From e5fd91f1ef340da553f7a79da9540c3db711c937 Mon Sep 17 00:00:00 2001 From: AndrĂ© Fabian Silva Delgado Date: Tue, 8 Sep 2015 01:01:14 -0300 Subject: Linux-libre 4.2-gnu --- drivers/staging/wilc1000/Kconfig | 59 + drivers/staging/wilc1000/Makefile | 34 + drivers/staging/wilc1000/TODO | 14 + drivers/staging/wilc1000/coreconfigsimulator.h | 17 + drivers/staging/wilc1000/coreconfigurator.c | 2156 ++++++ drivers/staging/wilc1000/coreconfigurator.h | 197 + drivers/staging/wilc1000/fifo_buffer.c | 133 + drivers/staging/wilc1000/fifo_buffer.h | 26 + drivers/staging/wilc1000/host_interface.c | 7963 +++++++++++++++++++++ drivers/staging/wilc1000/host_interface.h | 1281 ++++ drivers/staging/wilc1000/linux_mon.c | 598 ++ drivers/staging/wilc1000/linux_wlan.c | 2783 +++++++ drivers/staging/wilc1000/linux_wlan_common.h | 182 + drivers/staging/wilc1000/linux_wlan_sdio.c | 249 + drivers/staging/wilc1000/linux_wlan_sdio.h | 14 + drivers/staging/wilc1000/linux_wlan_spi.c | 479 ++ drivers/staging/wilc1000/linux_wlan_spi.h | 14 + drivers/staging/wilc1000/wilc_debugfs.c | 191 + drivers/staging/wilc1000/wilc_errorsupport.h | 67 + drivers/staging/wilc1000/wilc_exported_buf.c | 76 + drivers/staging/wilc1000/wilc_log.h | 47 + drivers/staging/wilc1000/wilc_memory.c | 58 + drivers/staging/wilc1000/wilc_memory.h | 239 + drivers/staging/wilc1000/wilc_msgqueue.c | 190 + drivers/staging/wilc1000/wilc_msgqueue.h | 108 + drivers/staging/wilc1000/wilc_osconfig.h | 9 + drivers/staging/wilc1000/wilc_oswrapper.h | 41 + drivers/staging/wilc1000/wilc_platform.h | 52 + drivers/staging/wilc1000/wilc_sdio.c | 1254 ++++ drivers/staging/wilc1000/wilc_sleep.c | 18 + drivers/staging/wilc1000/wilc_sleep.h | 20 + drivers/staging/wilc1000/wilc_spi.c | 1406 ++++ drivers/staging/wilc1000/wilc_strutils.c | 80 + drivers/staging/wilc1000/wilc_strutils.h | 134 + drivers/staging/wilc1000/wilc_timer.c | 45 + drivers/staging/wilc1000/wilc_timer.h | 129 + drivers/staging/wilc1000/wilc_type.h | 34 + drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 3957 ++++++++++ drivers/staging/wilc1000/wilc_wfi_cfgoperations.h | 129 + drivers/staging/wilc1000/wilc_wfi_netdevice.c | 951 +++ drivers/staging/wilc1000/wilc_wfi_netdevice.h | 254 + drivers/staging/wilc1000/wilc_wlan.c | 2332 ++++++ drivers/staging/wilc1000/wilc_wlan.h | 321 + drivers/staging/wilc1000/wilc_wlan_cfg.c | 617 ++ drivers/staging/wilc1000/wilc_wlan_cfg.h | 33 + drivers/staging/wilc1000/wilc_wlan_if.h | 969 +++ 46 files changed, 29960 insertions(+) create mode 100644 drivers/staging/wilc1000/Kconfig create mode 100644 drivers/staging/wilc1000/Makefile create mode 100644 drivers/staging/wilc1000/TODO create mode 100644 drivers/staging/wilc1000/coreconfigsimulator.h create mode 100644 drivers/staging/wilc1000/coreconfigurator.c create mode 100644 drivers/staging/wilc1000/coreconfigurator.h create mode 100644 drivers/staging/wilc1000/fifo_buffer.c create mode 100644 drivers/staging/wilc1000/fifo_buffer.h create mode 100644 drivers/staging/wilc1000/host_interface.c create mode 100644 drivers/staging/wilc1000/host_interface.h create mode 100644 drivers/staging/wilc1000/linux_mon.c create mode 100644 drivers/staging/wilc1000/linux_wlan.c create mode 100644 drivers/staging/wilc1000/linux_wlan_common.h create mode 100644 drivers/staging/wilc1000/linux_wlan_sdio.c create mode 100644 drivers/staging/wilc1000/linux_wlan_sdio.h create mode 100644 drivers/staging/wilc1000/linux_wlan_spi.c create mode 100644 drivers/staging/wilc1000/linux_wlan_spi.h create mode 100644 drivers/staging/wilc1000/wilc_debugfs.c create mode 100644 drivers/staging/wilc1000/wilc_errorsupport.h create mode 100644 drivers/staging/wilc1000/wilc_exported_buf.c create mode 100644 drivers/staging/wilc1000/wilc_log.h create mode 100644 drivers/staging/wilc1000/wilc_memory.c create mode 100644 drivers/staging/wilc1000/wilc_memory.h create mode 100644 drivers/staging/wilc1000/wilc_msgqueue.c create mode 100644 drivers/staging/wilc1000/wilc_msgqueue.h create mode 100644 drivers/staging/wilc1000/wilc_osconfig.h create mode 100644 drivers/staging/wilc1000/wilc_oswrapper.h create mode 100644 drivers/staging/wilc1000/wilc_platform.h create mode 100644 drivers/staging/wilc1000/wilc_sdio.c create mode 100644 drivers/staging/wilc1000/wilc_sleep.c create mode 100644 drivers/staging/wilc1000/wilc_sleep.h create mode 100644 drivers/staging/wilc1000/wilc_spi.c create mode 100644 drivers/staging/wilc1000/wilc_strutils.c create mode 100644 drivers/staging/wilc1000/wilc_strutils.h create mode 100644 drivers/staging/wilc1000/wilc_timer.c create mode 100644 drivers/staging/wilc1000/wilc_timer.h create mode 100644 drivers/staging/wilc1000/wilc_type.h create mode 100644 drivers/staging/wilc1000/wilc_wfi_cfgoperations.c create mode 100644 drivers/staging/wilc1000/wilc_wfi_cfgoperations.h create mode 100644 drivers/staging/wilc1000/wilc_wfi_netdevice.c create mode 100644 drivers/staging/wilc1000/wilc_wfi_netdevice.h create mode 100644 drivers/staging/wilc1000/wilc_wlan.c create mode 100644 drivers/staging/wilc1000/wilc_wlan.h create mode 100644 drivers/staging/wilc1000/wilc_wlan_cfg.c create mode 100644 drivers/staging/wilc1000/wilc_wlan_cfg.h create mode 100644 drivers/staging/wilc1000/wilc_wlan_if.h (limited to 'drivers/staging/wilc1000') diff --git a/drivers/staging/wilc1000/Kconfig b/drivers/staging/wilc1000/Kconfig new file mode 100644 index 000000000..062d9c5ca --- /dev/null +++ b/drivers/staging/wilc1000/Kconfig @@ -0,0 +1,59 @@ +config WILC1000 + tristate "WILC1000 support (WiFi only)" + depends on BROKEN + depends on !S390 + depends on CFG80211 && WEXT_CORE && INET + depends on MMC || SPI + ---help--- + This module only support IEEE 802.11n WiFi. + +choice + prompt "Memory Allocation" + depends on WILC1000 + default WILC1000_PREALLOCATE_AT_LOADING_DRIVER + +config WILC1000_PREALLOCATE_AT_LOADING_DRIVER + bool "Preallocate memory at loading driver" + ---help--- + This choice supports static allocation of the memory + for the receive buffer. The driver will allocate the RX buffer + during initial time. The driver will also free the buffer + by calling network device stop. + +config WILC1000_DYNAMICALLY_ALLOCATE_MEMROY + bool "Dynamically allocate memory in real time" + ---help--- + This choice supports dynamic allocation of the memory + for the receive buffer. The driver will allocate the RX buffer + when it is required. +endchoice + +choice + prompt "Bus Type" + depends on WILC1000 + default WILC1000_SDIO + + config WILC1000_SDIO + bool "SDIO support" + depends on MMC + ---help--- + This module adds support for the SDIO interface + of adapters using WILC chipset. Select this if + your platform is using the SDIO bus. + + config WILC1000_SPI + depends on SPI + bool "SPI support" + ---help--- + This module adds support for the SPI interface + of adapters using WILC chipset. Select this if + your platform is using the SPI bus. +endchoice + +config WILC1000_HW_OOB_INTR + bool "Use out of band interrupt" + depends on WILC1000 && WILC1000_SDIO + default n + ---help--- + If your platform don't recognize SDIO IRQ, connect chipset external IRQ pin + and check this option. Or, Use this to get all interrupts including SDIO interrupts. diff --git a/drivers/staging/wilc1000/Makefile b/drivers/staging/wilc1000/Makefile new file mode 100644 index 000000000..59b102074 --- /dev/null +++ b/drivers/staging/wilc1000/Makefile @@ -0,0 +1,34 @@ +obj-$(CONFIG_WILC1000) += wilc1000.o +obj-$(CONFIG_WILC1000_PREALLOCATE_DURING_SYSTEM_BOOT) += wilc_exported_buf.o + + +ccflags-$(CONFIG_WILC1000_SDIO) += -DWILC_SDIO -DCOMPLEMENT_BOOT +ccflags-$(CONFIG_WILC1000_HW_OOB_INTR) += -DWILC_SDIO_IRQ_GPIO +ccflags-$(CONFIG_WILC1000_SPI) += -DWILC_SPI + +ccflags-y += -DSTA_FIRMWARE="\"/*(DEBLOBBED)*/\"" \ + -DAP_FIRMWARE="\"/*(DEBLOBBED)*/\"" \ + -DP2P_CONCURRENCY_FIRMWARE="\"/*(DEBLOBBED)*/\"" + +ccflags-y += -I$(src)/ -D__CHECK_ENDIAN__ -DWILC_ASIC_A0 \ + -DPLL_WORKAROUND -DCONNECT_DIRECT -DAGING_ALG \ + -DWILC_PARSE_SCAN_IN_HOST -DDISABLE_PWRSAVE_AND_SCAN_DURING_IP \ + -Wno-unused-function -DUSE_WIRELESS -DWILC_DEBUGFS +#ccflags-y += -DTCP_ACK_FILTER + +ccflags-$(CONFIG_WILC1000_PREALLOCATE_DURING_SYSTEM_BOOT) += -DMEMORY_STATIC \ + -DWILC_PREALLOC_AT_BOOT + +ccflags-$(CONFIG_WILC1000_PREALLOCATE_AT_LOADING_DRIVER) += -DMEMORY_STATIC \ + -DWILC_PREALLOC_AT_INSMOD + +ccflags-$(CONFIG_WILC1000_DYNAMICALLY_ALLOCATE_MEMROY) += -DWILC_NORMAL_ALLOC + + +wilc1000-objs := wilc_wfi_netdevice.o wilc_wfi_cfgoperations.o linux_wlan.o linux_mon.o \ + wilc_memory.o wilc_msgqueue.o wilc_sleep.o wilc_strutils.o \ + wilc_timer.o coreconfigurator.o host_interface.o \ + fifo_buffer.o wilc_sdio.o wilc_spi.o wilc_wlan_cfg.o wilc_debugfs.o + +wilc1000-$(CONFIG_WILC1000_SDIO) += linux_wlan_sdio.o +wilc1000-$(CONFIG_WILC1000_SPI) += linux_wlan_spi.o diff --git a/drivers/staging/wilc1000/TODO b/drivers/staging/wilc1000/TODO new file mode 100644 index 000000000..95199d80a --- /dev/null +++ b/drivers/staging/wilc1000/TODO @@ -0,0 +1,14 @@ +TODO: +- remove the defined feature as kernel versions +- remove OS wrapper functions +- remove custom debug and tracing functions +- rework comments and function headers(also coding style) +- replace all semaphores with mutexes or completions +- make spi and sdio components coexist in one build +- turn compile-time platform configuration (BEAGLE_BOARD, + PANDA_BOARD, PLAT_WMS8304, PLAT_RKXXXX, CUSTOMER_PLATFORM, ...) + into run-time options that are read from DT +- support soft-ap and p2p mode +- support resume/suspend function +- replace SIOCDEVPRIVATE commands with generic API functions +- use wext-core handling instead of private SIOCSIWPRIV implementation diff --git a/drivers/staging/wilc1000/coreconfigsimulator.h b/drivers/staging/wilc1000/coreconfigsimulator.h new file mode 100644 index 000000000..5e01f8e4a --- /dev/null +++ b/drivers/staging/wilc1000/coreconfigsimulator.h @@ -0,0 +1,17 @@ + +/*! + * @file coreconfigsimulator.h + * @brief + * @author + * @sa coreconfigsimulator.c + * @date 1 Mar 2012 + * @version 1.0 + */ + +#ifndef CORECONFIGSIMULATOR_H +#define CORECONFIGSIMULATOR_H + +extern s32 CoreConfigSimulatorInit(void); +extern s32 CoreConfigSimulatorDeInit(void); + +#endif diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c new file mode 100644 index 000000000..ed6ac45c0 --- /dev/null +++ b/drivers/staging/wilc1000/coreconfigurator.c @@ -0,0 +1,2156 @@ + +/*! + * @file coreconfigurator.c + * @brief + * @author + * @sa coreconfigurator.h + * @date 1 Mar 2012 + * @version 1.0 + */ + + +/*****************************************************************************/ +/* File Includes */ +/*****************************************************************************/ +#include "coreconfigurator.h" +/*****************************************************************************/ +/* Constants */ +/*****************************************************************************/ +#define INLINE static __inline +#define PHY_802_11n +#define MAX_CFG_PKTLEN 1450 +#define MSG_HEADER_LEN 4 +#define QUERY_MSG_TYPE 'Q' +#define WRITE_MSG_TYPE 'W' +#define RESP_MSG_TYPE 'R' +#define WRITE_RESP_SUCCESS 1 +#define INVALID 255 +#define MAC_ADDR_LEN 6 +#define TAG_PARAM_OFFSET (MAC_HDR_LEN + TIME_STAMP_LEN + \ + BEACON_INTERVAL_LEN + CAP_INFO_LEN) + +/*****************************************************************************/ +/* Function Macros */ +/*****************************************************************************/ + + +/*****************************************************************************/ +/* Type Definitions */ +/*****************************************************************************/ + +/* Basic Frame Type Codes (2-bit) */ +typedef enum { + FRAME_TYPE_CONTROL = 0x04, + FRAME_TYPE_DATA = 0x08, + FRAME_TYPE_MANAGEMENT = 0x00, + FRAME_TYPE_RESERVED = 0x0C, + FRAME_TYPE_FORCE_32BIT = 0xFFFFFFFF +} tenuBasicFrmType; + +/* Frame Type and Subtype Codes (6-bit) */ +typedef enum { + ASSOC_REQ = 0x00, + ASSOC_RSP = 0x10, + REASSOC_REQ = 0x20, + REASSOC_RSP = 0x30, + PROBE_REQ = 0x40, + PROBE_RSP = 0x50, + BEACON = 0x80, + ATIM = 0x90, + DISASOC = 0xA0, + AUTH = 0xB0, + DEAUTH = 0xC0, + ACTION = 0xD0, + PS_POLL = 0xA4, + RTS = 0xB4, + CTS = 0xC4, + ACK = 0xD4, + CFEND = 0xE4, + CFEND_ACK = 0xF4, + DATA = 0x08, + DATA_ACK = 0x18, + DATA_POLL = 0x28, + DATA_POLL_ACK = 0x38, + NULL_FRAME = 0x48, + CFACK = 0x58, + CFPOLL = 0x68, + CFPOLL_ACK = 0x78, + QOS_DATA = 0x88, + QOS_DATA_ACK = 0x98, + QOS_DATA_POLL = 0xA8, + QOS_DATA_POLL_ACK = 0xB8, + QOS_NULL_FRAME = 0xC8, + QOS_CFPOLL = 0xE8, + QOS_CFPOLL_ACK = 0xF8, + BLOCKACK_REQ = 0x84, + BLOCKACK = 0x94, + FRAME_SUBTYPE_FORCE_32BIT = 0xFFFFFFFF +} tenuFrmSubtype; + +/* Basic Frame Classes */ +typedef enum { + CLASS1_FRAME_TYPE = 0x00, + CLASS2_FRAME_TYPE = 0x01, + CLASS3_FRAME_TYPE = 0x02, + FRAME_CLASS_FORCE_32BIT = 0xFFFFFFFF +} tenuFrameClass; + +/* Element ID of various Information Elements */ +typedef enum { + ISSID = 0, /* Service Set Identifier */ + ISUPRATES = 1, /* Supported Rates */ + IFHPARMS = 2, /* FH parameter set */ + IDSPARMS = 3, /* DS parameter set */ + ICFPARMS = 4, /* CF parameter set */ + ITIM = 5, /* Traffic Information Map */ + IIBPARMS = 6, /* IBSS parameter set */ + ICOUNTRY = 7, /* Country element */ + IEDCAPARAMS = 12, /* EDCA parameter set */ + ITSPEC = 13, /* Traffic Specification */ + ITCLAS = 14, /* Traffic Classification */ + ISCHED = 15, /* Schedule */ + ICTEXT = 16, /* Challenge Text */ + IPOWERCONSTRAINT = 32, /* Power Constraint */ + IPOWERCAPABILITY = 33, /* Power Capability */ + ITPCREQUEST = 34, /* TPC Request */ + ITPCREPORT = 35, /* TPC Report */ + ISUPCHANNEL = 36, /* Supported channel list */ + ICHSWANNOUNC = 37, /* Channel Switch Announcement */ + IMEASUREMENTREQUEST = 38, /* Measurement request */ + IMEASUREMENTREPORT = 39, /* Measurement report */ + IQUIET = 40, /* Quiet element Info */ + IIBSSDFS = 41, /* IBSS DFS */ + IERPINFO = 42, /* ERP Information */ + ITSDELAY = 43, /* TS Delay */ + ITCLASPROCESS = 44, /* TCLAS Processing */ + IHTCAP = 45, /* HT Capabilities */ + IQOSCAP = 46, /* QoS Capability */ + IRSNELEMENT = 48, /* RSN Information Element */ + IEXSUPRATES = 50, /* Extended Supported Rates */ + IEXCHSWANNOUNC = 60, /* Extended Ch Switch Announcement*/ + IHTOPERATION = 61, /* HT Information */ + ISECCHOFF = 62, /* Secondary Channel Offeset */ + I2040COEX = 72, /* 20/40 Coexistence IE */ + I2040INTOLCHREPORT = 73, /* 20/40 Intolerant channel report*/ + IOBSSSCAN = 74, /* OBSS Scan parameters */ + IEXTCAP = 127, /* Extended capability */ + IWMM = 221, /* WMM parameters */ + IWPAELEMENT = 221, /* WPA Information Element */ + INFOELEM_ID_FORCE_32BIT = 0xFFFFFFFF +} tenuInfoElemID; + + +typedef struct { + char *pcRespBuffer; + s32 s32MaxRespBuffLen; + s32 s32BytesRead; + bool bRespRequired; +} tstrConfigPktInfo; + + + +/*****************************************************************************/ +/* Extern Variable Declarations */ +/*****************************************************************************/ + + +/*****************************************************************************/ +/* Extern Function Declarations */ +/*****************************************************************************/ +extern s32 SendRawPacket(s8 *ps8Packet, s32 s32PacketLen); +extern void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length); +extern void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length); +extern void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length); +/*****************************************************************************/ +/* Global Variables */ +/*****************************************************************************/ +static struct semaphore SemHandleSendPkt; +static struct semaphore SemHandlePktResp; + +static s8 *gps8ConfigPacket; + +static tstrConfigPktInfo gstrConfigPktInfo; + +static u8 g_seqno; + +static s16 g_wid_num = -1; + +static u16 Res_Len; + +static u8 g_oper_mode = SET_CFG; + +/* WID Switches */ +static tstrWID gastrWIDs[] = { + {WID_FIRMWARE_VERSION, WID_STR}, + {WID_PHY_VERSION, WID_STR}, + {WID_HARDWARE_VERSION, WID_STR}, + {WID_BSS_TYPE, WID_CHAR}, + {WID_QOS_ENABLE, WID_CHAR}, + {WID_11I_MODE, WID_CHAR}, + {WID_CURRENT_TX_RATE, WID_CHAR}, + {WID_LINKSPEED, WID_CHAR}, + {WID_RTS_THRESHOLD, WID_SHORT}, + {WID_FRAG_THRESHOLD, WID_SHORT}, + {WID_SSID, WID_STR}, + {WID_BSSID, WID_ADR}, + {WID_BEACON_INTERVAL, WID_SHORT}, + {WID_POWER_MANAGEMENT, WID_CHAR}, + {WID_LISTEN_INTERVAL, WID_CHAR}, + {WID_DTIM_PERIOD, WID_CHAR}, + {WID_CURRENT_CHANNEL, WID_CHAR}, + {WID_TX_POWER_LEVEL_11A, WID_CHAR}, + {WID_TX_POWER_LEVEL_11B, WID_CHAR}, + {WID_PREAMBLE, WID_CHAR}, + {WID_11G_OPERATING_MODE, WID_CHAR}, + {WID_MAC_ADDR, WID_ADR}, + {WID_IP_ADDRESS, WID_ADR}, + {WID_ACK_POLICY, WID_CHAR}, + {WID_PHY_ACTIVE_REG, WID_CHAR}, + {WID_AUTH_TYPE, WID_CHAR}, + {WID_REKEY_POLICY, WID_CHAR}, + {WID_REKEY_PERIOD, WID_INT}, + {WID_REKEY_PACKET_COUNT, WID_INT}, + {WID_11I_PSK, WID_STR}, + {WID_1X_KEY, WID_STR}, + {WID_1X_SERV_ADDR, WID_IP}, + {WID_SUPP_USERNAME, WID_STR}, + {WID_SUPP_PASSWORD, WID_STR}, + {WID_USER_CONTROL_ON_TX_POWER, WID_CHAR}, + {WID_MEMORY_ADDRESS, WID_INT}, + {WID_MEMORY_ACCESS_32BIT, WID_INT}, + {WID_MEMORY_ACCESS_16BIT, WID_SHORT}, + {WID_MEMORY_ACCESS_8BIT, WID_CHAR}, + {WID_SITE_SURVEY_RESULTS, WID_STR}, + {WID_PMKID_INFO, WID_STR}, + {WID_ASSOC_RES_INFO, WID_STR}, + {WID_MANUFACTURER, WID_STR}, /* 4 Wids added for the CAPI tool*/ + {WID_MODEL_NAME, WID_STR}, + {WID_MODEL_NUM, WID_STR}, + {WID_DEVICE_NAME, WID_STR}, + {WID_SSID_PROBE_REQ, WID_STR}, + +#ifdef MAC_802_11N + {WID_11N_ENABLE, WID_CHAR}, + {WID_11N_CURRENT_TX_MCS, WID_CHAR}, + {WID_TX_POWER_LEVEL_11N, WID_CHAR}, + {WID_11N_OPERATING_MODE, WID_CHAR}, + {WID_11N_SMPS_MODE, WID_CHAR}, + {WID_11N_PROT_MECH, WID_CHAR}, + {WID_11N_ERP_PROT_TYPE, WID_CHAR}, + {WID_11N_HT_PROT_TYPE, WID_CHAR}, + {WID_11N_PHY_ACTIVE_REG_VAL, WID_INT}, + {WID_11N_PRINT_STATS, WID_CHAR}, + {WID_11N_AUTORATE_TABLE, WID_BIN_DATA}, + {WID_HOST_CONFIG_IF_TYPE, WID_CHAR}, + {WID_HOST_DATA_IF_TYPE, WID_CHAR}, + {WID_11N_SIG_QUAL_VAL, WID_SHORT}, + {WID_11N_IMMEDIATE_BA_ENABLED, WID_CHAR}, + {WID_11N_TXOP_PROT_DISABLE, WID_CHAR}, + {WID_11N_SHORT_GI_20MHZ_ENABLE, WID_CHAR}, + {WID_SHORT_SLOT_ALLOWED, WID_CHAR}, + {WID_11W_ENABLE, WID_CHAR}, + {WID_11W_MGMT_PROT_REQ, WID_CHAR}, + {WID_2040_ENABLE, WID_CHAR}, + {WID_2040_COEXISTENCE, WID_CHAR}, + {WID_USER_SEC_CHANNEL_OFFSET, WID_CHAR}, + {WID_2040_CURR_CHANNEL_OFFSET, WID_CHAR}, + {WID_2040_40MHZ_INTOLERANT, WID_CHAR}, + {WID_HUT_RESTART, WID_CHAR}, + {WID_HUT_NUM_TX_PKTS, WID_INT}, + {WID_HUT_FRAME_LEN, WID_SHORT}, + {WID_HUT_TX_FORMAT, WID_CHAR}, + {WID_HUT_BANDWIDTH, WID_CHAR}, + {WID_HUT_OP_BAND, WID_CHAR}, + {WID_HUT_STBC, WID_CHAR}, + {WID_HUT_ESS, WID_CHAR}, + {WID_HUT_ANTSET, WID_CHAR}, + {WID_HUT_HT_OP_MODE, WID_CHAR}, + {WID_HUT_RIFS_MODE, WID_CHAR}, + {WID_HUT_SMOOTHING_REC, WID_CHAR}, + {WID_HUT_SOUNDING_PKT, WID_CHAR}, + {WID_HUT_HT_CODING, WID_CHAR}, + {WID_HUT_TEST_DIR, WID_CHAR}, + {WID_HUT_TXOP_LIMIT, WID_SHORT}, + {WID_HUT_DEST_ADDR, WID_ADR}, + {WID_HUT_TX_PATTERN, WID_BIN_DATA}, + {WID_HUT_TX_TIME_TAKEN, WID_INT}, + {WID_HUT_PHY_TEST_MODE, WID_CHAR}, + {WID_HUT_PHY_TEST_RATE_HI, WID_CHAR}, + {WID_HUT_PHY_TEST_RATE_LO, WID_CHAR}, + {WID_HUT_TX_TEST_TIME, WID_INT}, + {WID_HUT_LOG_INTERVAL, WID_INT}, + {WID_HUT_DISABLE_RXQ_REPLENISH, WID_CHAR}, + {WID_HUT_TEST_ID, WID_STR}, + {WID_HUT_KEY_ORIGIN, WID_CHAR}, + {WID_HUT_BCST_PERCENT, WID_CHAR}, + {WID_HUT_GROUP_CIPHER_TYPE, WID_CHAR}, + {WID_HUT_STATS, WID_BIN_DATA}, + {WID_HUT_TSF_TEST_MODE, WID_CHAR}, + {WID_HUT_SIG_QUAL_AVG, WID_SHORT}, + {WID_HUT_SIG_QUAL_AVG_CNT, WID_SHORT}, + {WID_HUT_TSSI_VALUE, WID_CHAR}, + {WID_HUT_MGMT_PERCENT, WID_CHAR}, + {WID_HUT_MGMT_BCST_PERCENT, WID_CHAR}, + {WID_HUT_MGMT_ALLOW_HT, WID_CHAR}, + {WID_HUT_UC_MGMT_TYPE, WID_CHAR}, + {WID_HUT_BC_MGMT_TYPE, WID_CHAR}, + {WID_HUT_UC_MGMT_FRAME_LEN, WID_SHORT}, + {WID_HUT_BC_MGMT_FRAME_LEN, WID_SHORT}, + {WID_HUT_11W_MFP_REQUIRED_TX, WID_CHAR}, + {WID_HUT_11W_MFP_PEER_CAPABLE, WID_CHAR}, + {WID_HUT_11W_TX_IGTK_ID, WID_CHAR}, + {WID_HUT_FC_TXOP_MOD, WID_CHAR}, + {WID_HUT_FC_PROT_TYPE, WID_CHAR}, + {WID_HUT_SEC_CCA_ASSERT, WID_CHAR}, +#endif /* MAC_802_11N */ +}; + +u16 g_num_total_switches = (sizeof(gastrWIDs) / sizeof(tstrWID)); +/*****************************************************************************/ +/* Static Function Declarations */ +/*****************************************************************************/ + + + +/*****************************************************************************/ +/* Functions */ +/*****************************************************************************/ +INLINE u8 ascii_hex_to_dec(u8 num) +{ + if ((num >= '0') && (num <= '9')) + return (num - '0'); + else if ((num >= 'A') && (num <= 'F')) + return (10 + (num - 'A')); + else if ((num >= 'a') && (num <= 'f')) + return (10 + (num - 'a')); + + return INVALID; +} + +INLINE u8 get_hex_char(u8 inp) +{ + u8 *d2htab = "0123456789ABCDEF"; + + return d2htab[inp & 0xF]; +} + +/* This function extracts the MAC address held in a string in standard format */ +/* into another buffer as integers. */ +INLINE u16 extract_mac_addr(char *str, u8 *buff) +{ + *buff = 0; + while (*str != '\0') { + if ((*str == ':') || (*str == '-')) + *(++buff) = 0; + else + *buff = (*buff << 4) + ascii_hex_to_dec(*str); + + str++; + } + + return MAC_ADDR_LEN; +} + +/* This function creates MAC address in standard format from a buffer of */ +/* integers. */ +INLINE void create_mac_addr(u8 *str, u8 *buff) +{ + u32 i = 0; + u32 j = 0; + + for (i = 0; i < MAC_ADDR_LEN; i++) { + str[j++] = get_hex_char((u8)((buff[i] >> 4) & 0x0F)); + str[j++] = get_hex_char((u8)(buff[i] & 0x0F)); + str[j++] = ':'; + } + str[--j] = '\0'; +} + +/* This function converts the IP address string in dotted decimal format to */ +/* unsigned integer. This functionality is similar to the library function */ +/* inet_addr() but is reimplemented here since I could not confirm that */ +/* inet_addr is platform independent. */ +/* ips=>IP Address String in dotted decimal format */ +/* ipn=>Pointer to IP Address in integer format */ +INLINE u8 conv_ip_to_int(u8 *ips, u32 *ipn) +{ + u8 i = 0; + u8 ipb = 0; + *ipn = 0; + /* Integer to string for each component */ + while (ips[i] != '\0') { + if (ips[i] == '.') { + *ipn = ((*ipn) << 8) | ipb; + ipb = 0; + } else { + ipb = ipb * 10 + ascii_hex_to_dec(ips[i]); + } + + i++; + } + + /* The last byte of the IP address is read in here */ + *ipn = ((*ipn) << 8) | ipb; + + return 0; +} + +/* This function converts the IP address from integer format to dotted */ +/* decimal string format. Alternative to std library fn inet_ntoa(). */ +/* ips=>Buffer to hold IP Address String dotted decimal format (Min 17B) */ +/* ipn=>IP Address in integer format */ +INLINE u8 conv_int_to_ip(u8 *ips, u32 ipn) +{ + u8 i = 0; + u8 ipb = 0; + u8 cnt = 0; + u8 ipbsize = 0; + + for (cnt = 4; cnt > 0; cnt--) { + ipb = (ipn >> (8 * (cnt - 1))) & 0xFF; + + if (ipb >= 100) + ipbsize = 2; + else if (ipb >= 10) + ipbsize = 1; + else + ipbsize = 0; + + switch (ipbsize) { + case 2: + ips[i++] = get_hex_char(ipb / 100); + ipb %= 100; + + case 1: + ips[i++] = get_hex_char(ipb / 10); + ipb %= 10; + + default: + ips[i++] = get_hex_char(ipb); + } + + if (cnt > 1) + ips[i++] = '.'; + } + + ips[i] = '\0'; + + return i; +} + +INLINE tenuWIDtype get_wid_type(u32 wid_num) +{ + /* Check for iconfig specific WID types first */ + if ((wid_num == WID_BSSID) || + (wid_num == WID_MAC_ADDR) || + (wid_num == WID_IP_ADDRESS) || + (wid_num == WID_HUT_DEST_ADDR)) { + return WID_ADR; + } + + if ((WID_1X_SERV_ADDR == wid_num) || + (WID_STACK_IP_ADDR == wid_num) || + (WID_STACK_NETMASK_ADDR == wid_num)) { + return WID_IP; + } + + /* Next check for standard WID types */ + if (wid_num < 0x1000) + return WID_CHAR; + else if (wid_num < 0x2000) + return WID_SHORT; + else if (wid_num < 0x3000) + return WID_INT; + else if (wid_num < 0x4000) + return WID_STR; + else if (wid_num < 0x5000) + return WID_BIN_DATA; + + return WID_UNDEF; +} + + +/* This function extracts the beacon period field from the beacon or probe */ +/* response frame. */ +INLINE u16 get_beacon_period(u8 *data) +{ + u16 bcn_per = 0; + + bcn_per = data[0]; + bcn_per |= (data[1] << 8); + + return bcn_per; +} + +INLINE u32 get_beacon_timestamp_lo(u8 *data) +{ + u32 time_stamp = 0; + u32 index = MAC_HDR_LEN; + + time_stamp |= data[index++]; + time_stamp |= (data[index++] << 8); + time_stamp |= (data[index++] << 16); + time_stamp |= (data[index] << 24); + + return time_stamp; +} + +INLINE u32 get_beacon_timestamp_hi(u8 *data) +{ + u32 time_stamp = 0; + u32 index = (MAC_HDR_LEN + 4); + + time_stamp |= data[index++]; + time_stamp |= (data[index++] << 8); + time_stamp |= (data[index++] << 16); + time_stamp |= (data[index] << 24); + + return time_stamp; +} + +/* This function extracts the 'frame type' bits from the MAC header of the */ +/* input frame. */ +/* Returns the value in the LSB of the returned value. */ +INLINE tenuBasicFrmType get_type(u8 *header) +{ + return ((tenuBasicFrmType)(header[0] & 0x0C)); +} + +/* This function extracts the 'frame type and sub type' bits from the MAC */ +/* header of the input frame. */ +/* Returns the value in the LSB of the returned value. */ +INLINE tenuFrmSubtype get_sub_type(u8 *header) +{ + return ((tenuFrmSubtype)(header[0] & 0xFC)); +} + +/* This function extracts the 'to ds' bit from the MAC header of the input */ +/* frame. */ +/* Returns the value in the LSB of the returned value. */ +INLINE u8 get_to_ds(u8 *header) +{ + return (header[1] & 0x01); +} + +/* This function extracts the 'from ds' bit from the MAC header of the input */ +/* frame. */ +/* Returns the value in the LSB of the returned value. */ +INLINE u8 get_from_ds(u8 *header) +{ + return ((header[1] & 0x02) >> 1); +} + +/* This function extracts the MAC Address in 'address1' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +INLINE void get_address1(u8 *pu8msa, u8 *addr) +{ + WILC_memcpy(addr, pu8msa + 4, 6); +} + +/* This function extracts the MAC Address in 'address2' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +INLINE void get_address2(u8 *pu8msa, u8 *addr) +{ + WILC_memcpy(addr, pu8msa + 10, 6); +} + +/* This function extracts the MAC Address in 'address3' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +INLINE void get_address3(u8 *pu8msa, u8 *addr) +{ + WILC_memcpy(addr, pu8msa + 16, 6); +} + +/* This function extracts the BSSID from the incoming WLAN packet based on */ +/* the 'from ds' bit, and updates the MAC Address in the allocated 'addr' */ +/* variable. */ +INLINE void get_BSSID(u8 *data, u8 *bssid) +{ + if (get_from_ds(data) == 1) + get_address2(data, bssid); + else if (get_to_ds(data) == 1) + get_address1(data, bssid); + else + get_address3(data, bssid); +} + +/* This function extracts the SSID from a beacon/probe response frame */ +INLINE void get_ssid(u8 *data, u8 *ssid, u8 *p_ssid_len) +{ + u8 len = 0; + u8 i = 0; + u8 j = 0; + + len = data[MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + + CAP_INFO_LEN + 1]; + j = MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + + CAP_INFO_LEN + 2; + + /* If the SSID length field is set wrongly to a value greater than the */ + /* allowed maximum SSID length limit, reset the length to 0 */ + if (len >= MAX_SSID_LEN) + len = 0; + + for (i = 0; i < len; i++, j++) + ssid[i] = data[j]; + + ssid[len] = '\0'; + + *p_ssid_len = len; +} + +/* This function extracts the capability info field from the beacon or probe */ +/* response frame. */ +INLINE u16 get_cap_info(u8 *data) +{ + u16 cap_info = 0; + u16 index = MAC_HDR_LEN; + tenuFrmSubtype st = BEACON; + + st = get_sub_type(data); + + /* Location of the Capability field is different for Beacon and */ + /* Association frames. */ + if ((st == BEACON) || (st == PROBE_RSP)) + index += TIME_STAMP_LEN + BEACON_INTERVAL_LEN; + + cap_info = data[index]; + cap_info |= (data[index + 1] << 8); + + return cap_info; +} + +/* This function extracts the capability info field from the Association */ +/* response frame. */ +INLINE u16 get_assoc_resp_cap_info(u8 *data) +{ + u16 cap_info = 0; + + cap_info = data[0]; + cap_info |= (data[1] << 8); + + return cap_info; +} + +/* This funcion extracts the association status code from the incoming */ +/* association response frame and returns association status code */ +INLINE u16 get_asoc_status(u8 *data) +{ + u16 asoc_status = 0; + + asoc_status = data[3]; + asoc_status = (asoc_status << 8) | data[2]; + + return asoc_status; +} + +/* This function extracts association ID from the incoming association */ +/* response frame */ +INLINE u16 get_asoc_id(u8 *data) +{ + u16 asoc_id = 0; + + asoc_id = data[4]; + asoc_id |= (data[5] << 8); + + return asoc_id; +} + +/** + * @brief initializes the Core Configurator + * @details + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 1 Mar 2012 + * @version 1.0 + */ + +s32 CoreConfiguratorInit(void) +{ + s32 s32Error = WILC_SUCCESS; + PRINT_D(CORECONFIG_DBG, "CoreConfiguratorInit()\n"); + + sema_init(&SemHandleSendPkt, 1); + sema_init(&SemHandlePktResp, 0); + + gps8ConfigPacket = (s8 *)WILC_MALLOC(MAX_PACKET_BUFF_SIZE); + if (gps8ConfigPacket == NULL) { + PRINT_ER("failed in gps8ConfigPacket allocation\n"); + s32Error = WILC_NO_MEM; + goto _fail_; + } + + WILC_memset((void *)gps8ConfigPacket, 0, MAX_PACKET_BUFF_SIZE); + + WILC_memset((void *)(&gstrConfigPktInfo), 0, sizeof(tstrConfigPktInfo)); +_fail_: + return s32Error; +} + +u8 *get_tim_elm(u8 *pu8msa, u16 u16RxLen, u16 u16TagParamOffset) +{ + u16 u16index = 0; + + /*************************************************************************/ + /* Beacon Frame - Frame Body */ + /* --------------------------------------------------------------------- */ + /* |Timestamp |BeaconInt |CapInfo |SSID |SupRates |DSParSet |TIM elm | */ + /* --------------------------------------------------------------------- */ + /* |8 |2 |2 |2-34 |3-10 |3 |4-256 | */ + /* --------------------------------------------------------------------- */ + /* */ + /*************************************************************************/ + + u16index = u16TagParamOffset; + + /* Search for the TIM Element Field and return if the element is found */ + while (u16index < (u16RxLen - FCS_LEN)) { + if (pu8msa[u16index] == ITIM) { + return &pu8msa[u16index]; + } else { + u16index += (IE_HDR_LEN + pu8msa[u16index + 1]); + } + } + + return 0; +} + +/* This function gets the current channel information from + * the 802.11n beacon/probe response frame */ +u8 get_current_channel_802_11n(u8 *pu8msa, u16 u16RxLen) +{ + u16 index; + + index = TAG_PARAM_OFFSET; + while (index < (u16RxLen - FCS_LEN)) { + if (pu8msa[index] == IDSPARMS) + return pu8msa[index + 2]; + else + /* Increment index by length information and header */ + index += pu8msa[index + 1] + IE_HDR_LEN; + } + + /* Return current channel information from the MIB, if beacon/probe */ + /* response frame does not contain the DS parameter set IE */ + /* return (mget_CurrentChannel() + 1); */ + return 0; /* no MIB here */ +} + +u8 get_current_channel(u8 *pu8msa, u16 u16RxLen) +{ +#ifdef PHY_802_11n +#ifdef FIVE_GHZ_BAND + /* Get the current channel as its not set in */ + /* 802.11a beacons/probe response */ + return (get_rf_channel() + 1); +#else /* FIVE_GHZ_BAND */ + /* Extract current channel information from */ + /* the beacon/probe response frame */ + return get_current_channel_802_11n(pu8msa, u16RxLen); +#endif /* FIVE_GHZ_BAND */ +#else + return 0; +#endif /* PHY_802_11n */ +} + +/** + * @brief parses the received 'N' message + * @details + * @param[in] pu8MsgBuffer The message to be parsed + * @param[out] ppstrNetworkInfo pointer to pointer to the structure containing the parsed Network Info + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 1 Mar 2012 + * @version 1.0 + */ +s32 ParseNetworkInfo(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo) +{ + s32 s32Error = WILC_SUCCESS; + tstrNetworkInfo *pstrNetworkInfo = NULL; + u8 u8MsgType = 0; + u8 u8MsgID = 0; + u16 u16MsgLen = 0; + + u16 u16WidID = (u16)WID_NIL; + u16 u16WidLen = 0; + u8 *pu8WidVal = 0; + + u8MsgType = pu8MsgBuffer[0]; + + /* Check whether the received message type is 'N' */ + if ('N' != u8MsgType) { + PRINT_ER("Received Message format incorrect.\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + /* Extract message ID */ + u8MsgID = pu8MsgBuffer[1]; + + /* Extract message Length */ + u16MsgLen = MAKE_WORD16(pu8MsgBuffer[2], pu8MsgBuffer[3]); + + /* Extract WID ID */ + u16WidID = MAKE_WORD16(pu8MsgBuffer[4], pu8MsgBuffer[5]); + + /* Extract WID Length */ + u16WidLen = MAKE_WORD16(pu8MsgBuffer[6], pu8MsgBuffer[7]); + + /* Assign a pointer to the WID value */ + pu8WidVal = &pu8MsgBuffer[8]; + + /* parse the WID value of the WID "WID_NEWORK_INFO" */ + { + u8 *pu8msa = 0; + u16 u16RxLen = 0; + u8 *pu8TimElm = 0; + u8 *pu8IEs = 0; + u16 u16IEsLen = 0; + u8 u8index = 0; + u32 u32Tsf_Lo; + u32 u32Tsf_Hi; + + pstrNetworkInfo = (tstrNetworkInfo *)WILC_MALLOC(sizeof(tstrNetworkInfo)); + WILC_memset((void *)(pstrNetworkInfo), 0, sizeof(tstrNetworkInfo)); + + pstrNetworkInfo->s8rssi = pu8WidVal[0]; + + /* Assign a pointer to msa "Mac Header Start Address" */ + pu8msa = &pu8WidVal[1]; + + u16RxLen = u16WidLen - 1; + + /* parse msa*/ + + /* Get the cap_info */ + pstrNetworkInfo->u16CapInfo = get_cap_info(pu8msa); + #ifdef WILC_P2P + /* Get time-stamp [Low only 32 bit] */ + pstrNetworkInfo->u32Tsf = get_beacon_timestamp_lo(pu8msa); + PRINT_D(CORECONFIG_DBG, "TSF :%x\n", pstrNetworkInfo->u32Tsf); + #endif + + /* Get full time-stamp [Low and High 64 bit] */ + u32Tsf_Lo = get_beacon_timestamp_lo(pu8msa); + u32Tsf_Hi = get_beacon_timestamp_hi(pu8msa); + + pstrNetworkInfo->u64Tsf = u32Tsf_Lo | ((u64)u32Tsf_Hi << 32); + + /* Get SSID */ + get_ssid(pu8msa, pstrNetworkInfo->au8ssid, &(pstrNetworkInfo->u8SsidLen)); + + /* Get BSSID */ + get_BSSID(pu8msa, pstrNetworkInfo->au8bssid); + + /* Get the current channel */ + pstrNetworkInfo->u8channel = get_current_channel(pu8msa, (u16RxLen + FCS_LEN)); + + /* Get beacon period */ + u8index = (MAC_HDR_LEN + TIME_STAMP_LEN); + + pstrNetworkInfo->u16BeaconPeriod = get_beacon_period(pu8msa + u8index); + + u8index += BEACON_INTERVAL_LEN + CAP_INFO_LEN; + + /* Get DTIM Period */ + pu8TimElm = get_tim_elm(pu8msa, (u16RxLen + FCS_LEN), u8index); + if (pu8TimElm != 0) { + pstrNetworkInfo->u8DtimPeriod = pu8TimElm[3]; + } + pu8IEs = &pu8msa[MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + CAP_INFO_LEN]; + u16IEsLen = u16RxLen - (MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + CAP_INFO_LEN); + + if (u16IEsLen > 0) { + pstrNetworkInfo->pu8IEs = (u8 *)WILC_MALLOC(u16IEsLen); + WILC_memset((void *)(pstrNetworkInfo->pu8IEs), 0, u16IEsLen); + + WILC_memcpy(pstrNetworkInfo->pu8IEs, pu8IEs, u16IEsLen); + } + pstrNetworkInfo->u16IEsLen = u16IEsLen; + + } + + *ppstrNetworkInfo = pstrNetworkInfo; + +ERRORHANDLER: + return s32Error; +} + +/** + * @brief Deallocates the parsed Network Info + * @details + * @param[in] pstrNetworkInfo Network Info to be deallocated + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 1 Mar 2012 + * @version 1.0 + */ +s32 DeallocateNetworkInfo(tstrNetworkInfo *pstrNetworkInfo) +{ + s32 s32Error = WILC_SUCCESS; + + if (pstrNetworkInfo != NULL) { + if (pstrNetworkInfo->pu8IEs != NULL) { + WILC_FREE(pstrNetworkInfo->pu8IEs); + pstrNetworkInfo->pu8IEs = NULL; + } else { + s32Error = WILC_FAIL; + } + + WILC_FREE(pstrNetworkInfo); + pstrNetworkInfo = NULL; + + } else { + s32Error = WILC_FAIL; + } + + return s32Error; +} + +/** + * @brief parses the received Association Response frame + * @details + * @param[in] pu8Buffer The Association Response frame to be parsed + * @param[out] ppstrConnectRespInfo pointer to pointer to the structure containing the parsed Association Response Info + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 2 Apr 2012 + * @version 1.0 + */ +s32 ParseAssocRespInfo(u8 *pu8Buffer, u32 u32BufferLen, + tstrConnectRespInfo **ppstrConnectRespInfo) +{ + s32 s32Error = WILC_SUCCESS; + tstrConnectRespInfo *pstrConnectRespInfo = NULL; + u16 u16AssocRespLen = 0; + u8 *pu8IEs = 0; + u16 u16IEsLen = 0; + + pstrConnectRespInfo = (tstrConnectRespInfo *)WILC_MALLOC(sizeof(tstrConnectRespInfo)); + WILC_memset((void *)(pstrConnectRespInfo), 0, sizeof(tstrConnectRespInfo)); + + /* u16AssocRespLen = pu8Buffer[0]; */ + u16AssocRespLen = (u16)u32BufferLen; + + /* get the status code */ + pstrConnectRespInfo->u16ConnectStatus = get_asoc_status(pu8Buffer); + if (pstrConnectRespInfo->u16ConnectStatus == SUCCESSFUL_STATUSCODE) { + + /* get the capability */ + pstrConnectRespInfo->u16capability = get_assoc_resp_cap_info(pu8Buffer); + + /* get the Association ID */ + pstrConnectRespInfo->u16AssocID = get_asoc_id(pu8Buffer); + + /* get the Information Elements */ + pu8IEs = &pu8Buffer[CAP_INFO_LEN + STATUS_CODE_LEN + AID_LEN]; + u16IEsLen = u16AssocRespLen - (CAP_INFO_LEN + STATUS_CODE_LEN + AID_LEN); + + pstrConnectRespInfo->pu8RespIEs = (u8 *)WILC_MALLOC(u16IEsLen); + WILC_memset((void *)(pstrConnectRespInfo->pu8RespIEs), 0, u16IEsLen); + + WILC_memcpy(pstrConnectRespInfo->pu8RespIEs, pu8IEs, u16IEsLen); + pstrConnectRespInfo->u16RespIEsLen = u16IEsLen; + } + + *ppstrConnectRespInfo = pstrConnectRespInfo; + + + return s32Error; +} + +/** + * @brief Deallocates the parsed Association Response Info + * @details + * @param[in] pstrNetworkInfo Network Info to be deallocated + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 2 Apr 2012 + * @version 1.0 + */ +s32 DeallocateAssocRespInfo(tstrConnectRespInfo *pstrConnectRespInfo) +{ + s32 s32Error = WILC_SUCCESS; + + if (pstrConnectRespInfo != NULL) { + if (pstrConnectRespInfo->pu8RespIEs != NULL) { + WILC_FREE(pstrConnectRespInfo->pu8RespIEs); + pstrConnectRespInfo->pu8RespIEs = NULL; + } else { + s32Error = WILC_FAIL; + } + + WILC_FREE(pstrConnectRespInfo); + pstrConnectRespInfo = NULL; + + } else { + s32Error = WILC_FAIL; + } + + return s32Error; +} + +#ifndef CONNECT_DIRECT +s32 ParseSurveyResults(u8 ppu8RcvdSiteSurveyResults[][MAX_SURVEY_RESULT_FRAG_SIZE], + wid_site_survey_reslts_s **ppstrSurveyResults, + u32 *pu32SurveyResultsCount) +{ + s32 s32Error = WILC_SUCCESS; + wid_site_survey_reslts_s *pstrSurveyResults = NULL; + u32 u32SurveyResultsCount = 0; + u32 u32SurveyBytesLength = 0; + u8 *pu8BufferPtr; + u32 u32RcvdSurveyResultsNum = 2; + u8 u8ReadSurveyResFragNum; + u32 i; + u32 j; + + for (i = 0; i < u32RcvdSurveyResultsNum; i++) { + u32SurveyBytesLength = ppu8RcvdSiteSurveyResults[i][0]; + + + for (j = 0; j < u32SurveyBytesLength; j += SURVEY_RESULT_LENGTH) { + u32SurveyResultsCount++; + } + } + + pstrSurveyResults = (wid_site_survey_reslts_s *)WILC_MALLOC(u32SurveyResultsCount * sizeof(wid_site_survey_reslts_s)); + if (pstrSurveyResults == NULL) { + u32SurveyResultsCount = 0; + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + WILC_memset((void *)(pstrSurveyResults), 0, u32SurveyResultsCount * sizeof(wid_site_survey_reslts_s)); + + u32SurveyResultsCount = 0; + + for (i = 0; i < u32RcvdSurveyResultsNum; i++) { + pu8BufferPtr = ppu8RcvdSiteSurveyResults[i]; + + u32SurveyBytesLength = pu8BufferPtr[0]; + + /* TODO: mostafa: pu8BufferPtr[1] contains the fragment num */ + u8ReadSurveyResFragNum = pu8BufferPtr[1]; + + pu8BufferPtr += 2; + + for (j = 0; j < u32SurveyBytesLength; j += SURVEY_RESULT_LENGTH) { + WILC_memcpy(&pstrSurveyResults[u32SurveyResultsCount], pu8BufferPtr, SURVEY_RESULT_LENGTH); + pu8BufferPtr += SURVEY_RESULT_LENGTH; + u32SurveyResultsCount++; + } + } + +ERRORHANDLER: + *ppstrSurveyResults = pstrSurveyResults; + *pu32SurveyResultsCount = u32SurveyResultsCount; + + return s32Error; +} + + +s32 DeallocateSurveyResults(wid_site_survey_reslts_s *pstrSurveyResults) +{ + s32 s32Error = WILC_SUCCESS; + + if (pstrSurveyResults != NULL) { + WILC_FREE(pstrSurveyResults); + } + + return s32Error; +} +#endif + +/*****************************************************************************/ +/* */ +/* Function Name : ProcessCharWid */ +/* */ +/* Description : This function processes a WID of type WID_CHAR and */ +/* updates the cfg packet with the supplied value. */ +/* */ +/* Inputs : 1) Pointer to WID cfg structure */ +/* 2) Value to set */ +/* */ +/* Globals : */ +/* */ +/* Processing : */ +/* */ +/* Outputs : None */ +/* */ +/* Returns : None */ +/* */ +/* Issues : None */ +/* */ +/* Revision History: */ +/* */ +/* DD MM YYYY Author(s) Changes (Describe the changes made) */ +/* 08 01 2008 Ittiam Draft */ +/* */ +/*****************************************************************************/ + +void ProcessCharWid(char *pcPacket, s32 *ps32PktLen, + tstrWID *pstrWID, s8 *ps8WidVal) +{ + u8 *pu8val = (u8 *)ps8WidVal; + u8 u8val = 0; + s32 s32PktLen = *ps32PktLen; + if (pstrWID == NULL) { + PRINT_WRN(CORECONFIG_DBG, "Can't set CHAR val 0x%x ,NULL structure\n", u8val); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid >> 8) & 0xFF; + if (g_oper_mode == SET_CFG) { + u8val = *pu8val; + + /* Length */ + pcPacket[s32PktLen++] = sizeof(u8); + + + /* Value */ + pcPacket[s32PktLen++] = u8val; + } + *ps32PktLen = s32PktLen; +} + +/*****************************************************************************/ +/* */ +/* Function Name : ProcessShortWid */ +/* */ +/* Description : This function processes a WID of type WID_SHORT and */ +/* updates the cfg packet with the supplied value. */ +/* */ +/* Inputs : 1) Pointer to WID cfg structure */ +/* 2) Value to set */ +/* */ +/* Globals : */ +/* */ +/* Processing : */ +/* */ +/* Outputs : None */ +/* */ +/* Returns : None */ +/* */ +/* Issues : None */ +/* */ +/* Revision History: */ +/* */ +/* DD MM YYYY Author(s) Changes (Describe the changes made) */ +/* 08 01 2008 Ittiam Draft */ +/* */ +/*****************************************************************************/ + +void ProcessShortWid(char *pcPacket, s32 *ps32PktLen, + tstrWID *pstrWID, s8 *ps8WidVal) +{ + u16 *pu16val = (u16 *)ps8WidVal; + u16 u16val = 0; + s32 s32PktLen = *ps32PktLen; + if (pstrWID == NULL) { + PRINT_WRN(CORECONFIG_DBG, "Can't set SHORT val 0x%x ,NULL structure\n", u16val); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + u16val = *pu16val; + + /* Length */ + pcPacket[s32PktLen++] = sizeof(u16); + + /* Value */ + pcPacket[s32PktLen++] = (u8)(u16val & 0xFF); + pcPacket[s32PktLen++] = (u8)((u16val >> 8) & 0xFF); + } + *ps32PktLen = s32PktLen; +} + +/*****************************************************************************/ +/* */ +/* Function Name : ProcessIntWid */ +/* */ +/* Description : This function processes a WID of type WID_INT and */ +/* updates the cfg packet with the supplied value. */ +/* */ +/* Inputs : 1) Pointer to WID cfg structure */ +/* 2) Value to set */ +/* */ +/* Globals : */ +/* */ +/* Processing : */ +/* */ +/* Outputs : None */ +/* */ +/* Returns : None */ +/* */ +/* Issues : None */ +/* */ +/* Revision History: */ +/* */ +/* DD MM YYYY Author(s) Changes (Describe the changes made) */ +/* 08 01 2008 Ittiam Draft */ +/* */ +/*****************************************************************************/ + +void ProcessIntWid(char *pcPacket, s32 *ps32PktLen, + tstrWID *pstrWID, s8 *ps8WidVal) +{ + u32 *pu32val = (u32 *)ps8WidVal; + u32 u32val = 0; + s32 s32PktLen = *ps32PktLen; + if (pstrWID == NULL) { + PRINT_WRN(CORECONFIG_DBG, "Can't set INT val 0x%x , NULL structure\n", u32val); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + u32val = *pu32val; + + /* Length */ + pcPacket[s32PktLen++] = sizeof(u32); + + /* Value */ + pcPacket[s32PktLen++] = (u8)(u32val & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 8) & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 16) & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 24) & 0xFF); + } + *ps32PktLen = s32PktLen; +} + +/*****************************************************************************/ +/* */ +/* Function Name : ProcessIPwid */ +/* */ +/* Description : This function processes a WID of type WID_IP and */ +/* updates the cfg packet with the supplied value. */ +/* */ +/* Inputs : 1) Pointer to WID cfg structure */ +/* 2) Value to set */ +/* */ +/* Globals : */ +/* */ +/* */ +/* Processing : */ +/* */ +/* Outputs : None */ +/* */ +/* Returns : None */ +/* */ +/* Issues : None */ +/* */ +/* Revision History: */ +/* */ +/* DD MM YYYY Author(s) Changes (Describe the changes made) */ +/* 08 01 2008 Ittiam Draft */ +/* */ +/*****************************************************************************/ + +void ProcessIPwid(char *pcPacket, s32 *ps32PktLen, + tstrWID *pstrWID, u8 *pu8ip) +{ + u32 u32val = 0; + s32 s32PktLen = *ps32PktLen; + + if (pstrWID == NULL) { + PRINT_WRN(CORECONFIG_DBG, "Can't set IP Addr , NULL structure\n"); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + /* Length */ + pcPacket[s32PktLen++] = sizeof(u32); + + /* Convert the IP Address String to Integer */ + conv_ip_to_int(pu8ip, &u32val); + + /* Value */ + pcPacket[s32PktLen++] = (u8)(u32val & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 8) & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 16) & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 24) & 0xFF); + } + *ps32PktLen = s32PktLen; +} + +/*****************************************************************************/ +/* */ +/* Function Name : ProcessStrWid */ +/* */ +/* Description : This function processes a WID of type WID_STR and */ +/* updates the cfg packet with the supplied value. */ +/* */ +/* Inputs : 1) Pointer to WID cfg structure */ +/* 2) Value to set */ +/* */ +/* Globals : */ +/* */ +/* Processing : */ +/* */ +/* Outputs : None */ +/* */ +/* Returns : None */ +/* */ +/* Issues : None */ +/* */ +/* Revision History: */ +/* */ +/* DD MM YYYY Author(s) Changes (Describe the changes made) */ +/* 08 01 2008 Ittiam Draft */ +/* */ +/*****************************************************************************/ + +void ProcessStrWid(char *pcPacket, s32 *ps32PktLen, + tstrWID *pstrWID, u8 *pu8val, s32 s32ValueSize) +{ + u16 u16MsgLen = 0; + u16 idx = 0; + s32 s32PktLen = *ps32PktLen; + if (pstrWID == NULL) { + PRINT_WRN(CORECONFIG_DBG, "Can't set STR val, NULL structure\n"); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + /* Message Length */ + /* u16MsgLen = WILC_strlen(pu8val); */ + u16MsgLen = (u16)s32ValueSize; + + /* Length */ + pcPacket[s32PktLen++] = (u8)u16MsgLen; + + /* Value */ + for (idx = 0; idx < u16MsgLen; idx++) + pcPacket[s32PktLen++] = pu8val[idx]; + } + *ps32PktLen = s32PktLen; +} + +/*****************************************************************************/ +/* */ +/* Function Name : ProcessAdrWid */ +/* */ +/* Description : This function processes a WID of type WID_ADR and */ +/* updates the cfg packet with the supplied value. */ +/* */ +/* Inputs : 1) Pointer to WID cfg structure */ +/* 2) Value to set */ +/* */ +/* Globals : */ +/* */ +/* Processing : */ +/* */ +/* Outputs : None */ +/* */ +/* Returns : None */ +/* */ +/* Issues : None */ +/* */ +/* Revision History: */ +/* */ +/* DD MM YYYY Author(s) Changes (Describe the changes made) */ +/* 08 01 2008 Ittiam Draft */ +/* */ +/*****************************************************************************/ + +void ProcessAdrWid(char *pcPacket, s32 *ps32PktLen, + tstrWID *pstrWID, u8 *pu8val) +{ + u16 u16MsgLen = 0; + s32 s32PktLen = *ps32PktLen; + + if (pstrWID == NULL) { + PRINT_WRN(CORECONFIG_DBG, "Can't set Addr WID, NULL structure\n"); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + /* Message Length */ + u16MsgLen = MAC_ADDR_LEN; + + /* Length */ + pcPacket[s32PktLen++] = (u8)u16MsgLen; + + /* Value */ + extract_mac_addr(pu8val, pcPacket + s32PktLen); + s32PktLen += u16MsgLen; + } + *ps32PktLen = s32PktLen; +} + +/*****************************************************************************/ +/* */ +/* Function Name : ProcessBinWid */ +/* */ +/* Description : This function processes a WID of type WID_BIN_DATA and */ +/* updates the cfg packet with the supplied value. */ +/* */ +/* Inputs : 1) Pointer to WID cfg structure */ +/* 2) Name of file containing the binary data in text mode */ +/* */ +/* Globals : */ +/* */ +/* Processing : The binary data is expected to be supplied through a */ +/* file in text mode. This file is expected to be in the */ +/* finject format. It is parsed, converted to binary format */ +/* and copied into g_cfg_pkt for further processing. This */ +/* is obviously a round-about way of processing involving */ +/* multiple (re)conversions between bin & ascii formats. */ +/* But it is done nevertheless to retain uniformity and for */ +/* ease of debugging. */ +/* */ +/* Outputs : None */ +/* */ +/* Returns : None */ +/* */ + +/* Issues : None */ +/* */ +/* Revision History: */ +/* */ +/* DD MM YYYY Author(s) Changes (Describe the changes made) */ +/* 08 01 2008 Ittiam Draft */ +/* */ +/*****************************************************************************/ + +void ProcessBinWid(char *pcPacket, s32 *ps32PktLen, + tstrWID *pstrWID, u8 *pu8val, s32 s32ValueSize) +{ + /* WILC_ERROR("processing Binary WIDs is not supported\n"); */ + + u16 u16MsgLen = 0; + u16 idx = 0; + s32 s32PktLen = *ps32PktLen; + u8 u8checksum = 0; + + if (pstrWID == NULL) { + PRINT_WRN(CORECONFIG_DBG, "Can't set BIN val, NULL structure\n"); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + /* Message Length */ + u16MsgLen = (u16)s32ValueSize; + + /* Length */ + /* pcPacket[s32PktLen++] = (u8)u16MsgLen; */ + pcPacket[s32PktLen++] = (u8)(u16MsgLen & 0xFF); + pcPacket[s32PktLen++] = (u8)((u16MsgLen >> 8) & 0xFF); + + /* Value */ + for (idx = 0; idx < u16MsgLen; idx++) + pcPacket[s32PktLen++] = pu8val[idx]; + + /* checksum */ + for (idx = 0; idx < u16MsgLen; idx++) + u8checksum += pcPacket[MSG_HEADER_LEN + idx + 4]; + + pcPacket[s32PktLen++] = u8checksum; + } + *ps32PktLen = s32PktLen; +} + + +/*****************************************************************************/ +/* */ +/* Function Name : further_process_response */ +/* */ +/* Description : This function parses the response frame got from the */ +/* device. */ +/* */ +/* Inputs : 1) The received response frame */ +/* 2) WID */ +/* 3) WID Length */ +/* 4) Output file handle */ +/* 5) Process Wid Number(i.e wid from --widn switch) */ +/* 6) Index the array in the Global Wid Structure. */ +/* */ +/* Globals : g_wid_num, gastrWIDs */ +/* */ +/* Processing : This function parses the response of the device depending*/ +/* WID type and writes it to the output file in Hex or */ +/* decimal notation depending on the --getx or --get switch.*/ +/* */ +/* Outputs : None */ +/* */ +/* Returns : 0 on Success & -2 on Failure */ +/* */ +/* Issues : None */ +/* */ +/* Revision History: */ +/* */ +/* DD MM YYYY Author(s) Changes (Describe the changes made) */ +/* 08 01 2009 Ittiam Draft */ +/* */ +/*****************************************************************************/ + +s32 further_process_response(u8 *resp, + u16 u16WIDid, + u16 cfg_len, + bool process_wid_num, + u32 cnt, + tstrWID *pstrWIDresult) +{ + u32 retval = 0; + u32 idx = 0; + u8 cfg_chr = 0; + u16 cfg_sht = 0; + u32 cfg_int = 0; + u8 cfg_str[256] = {0}; + tenuWIDtype enuWIDtype = WID_UNDEF; + + if (process_wid_num) { + enuWIDtype = get_wid_type(g_wid_num); + } else { + enuWIDtype = gastrWIDs[cnt].enuWIDtype; + } + + + switch (enuWIDtype) { + case WID_CHAR: + cfg_chr = resp[idx]; + /*Set local copy of WID*/ + *(pstrWIDresult->ps8WidVal) = cfg_chr; + break; + + case WID_SHORT: + { + u16 *pu16val = (u16 *)(pstrWIDresult->ps8WidVal); + cfg_sht = MAKE_WORD16(resp[idx], resp[idx + 1]); + /*Set local copy of WID*/ + /* pstrWIDresult->ps8WidVal = (s8*)(s32)cfg_sht; */ + *pu16val = cfg_sht; + break; + } + + case WID_INT: + { + u32 *pu32val = (u32 *)(pstrWIDresult->ps8WidVal); + cfg_int = MAKE_WORD32( + MAKE_WORD16(resp[idx], resp[idx + 1]), + MAKE_WORD16(resp[idx + 2], resp[idx + 3]) + ); + /*Set local copy of WID*/ + /* pstrWIDresult->ps8WidVal = (s8*)cfg_int; */ + *pu32val = cfg_int; + break; + } + + case WID_STR: + WILC_memcpy(cfg_str, resp + idx, cfg_len); + /* cfg_str[cfg_len] = '\0'; //mostafa: no need currently for NULL termination */ + if (process_wid_num) { + /*fprintf(out_file,"0x%4.4x = %s\n",g_wid_num, + * cfg_str);*/ + } else { + /*fprintf(out_file,"%s = %s\n",gastrWIDs[cnt].cfg_switch, + * cfg_str);*/ + } + + if (pstrWIDresult->s32ValueSize >= cfg_len) { + WILC_memcpy(pstrWIDresult->ps8WidVal, cfg_str, cfg_len); /* mostafa: no need currently for the extra NULL byte */ + pstrWIDresult->s32ValueSize = cfg_len; + } else { + PRINT_ER("allocated WID buffer length is smaller than the received WID Length\n"); + retval = -2; + } + + break; + + case WID_ADR: + create_mac_addr(cfg_str, resp + idx); + + WILC_strncpy(pstrWIDresult->ps8WidVal, cfg_str, WILC_strlen(cfg_str)); + pstrWIDresult->ps8WidVal[WILC_strlen(cfg_str)] = '\0'; + if (process_wid_num) { + /*fprintf(out_file,"0x%4.4x = %s\n",g_wid_num, + * cfg_str);*/ + } else { + /*fprintf(out_file,"%s = %s\n",gastrWIDs[cnt].cfg_switch, + * cfg_str);*/ + } + break; + + case WID_IP: + cfg_int = MAKE_WORD32( + MAKE_WORD16(resp[idx], resp[idx + 1]), + MAKE_WORD16(resp[idx + 2], resp[idx + 3]) + ); + conv_int_to_ip(cfg_str, cfg_int); + if (process_wid_num) { + /*fprintf(out_file,"0x%4.4x = %s\n",g_wid_num, + * cfg_str);*/ + } else { + /*fprintf(out_file,"%s = %s\n",gastrWIDs[cnt].cfg_switch, + * cfg_str);*/ + } + break; + + case WID_BIN_DATA: + if (pstrWIDresult->s32ValueSize >= cfg_len) { + WILC_memcpy(pstrWIDresult->ps8WidVal, resp + idx, cfg_len); + pstrWIDresult->s32ValueSize = cfg_len; + } else { + PRINT_ER("Allocated WID buffer length is smaller than the received WID Length Err(%d)\n", retval); + retval = -2; + } + break; + + default: + PRINT_ER("ERROR: Check config database: Error(%d)\n", retval); + retval = -2; + break; + } + + return retval; +} + +/*****************************************************************************/ +/* */ +/* Function Name : ParseResponse */ +/* */ +/* Description : This function parses the command-line options and */ +/* creates the config packets which can be sent to the WLAN */ +/* station. */ +/* */ +/* Inputs : 1) The received response frame */ +/* */ +/* Globals : g_opt_list, gastrWIDs */ +/* */ +/* Processing : This function parses the options and creates different */ +/* types of packets depending upon the WID-type */ +/* corresponding to the option. */ +/* */ +/* Outputs : None */ +/* */ +/* Returns : 0 on Success & -1 on Failure */ +/* */ +/* Issues : None */ +/* */ +/* Revision History: */ +/* */ +/* DD MM YYYY Author(s) Changes (Describe the changes made) */ +/* 08 01 2008 Ittiam Draft */ +/* */ +/*****************************************************************************/ + +s32 ParseResponse(u8 *resp, tstrWID *pstrWIDcfgResult) +{ + u16 u16RespLen = 0; + u16 u16WIDid = 0; + u16 cfg_len = 0; + tenuWIDtype enuWIDtype = WID_UNDEF; + bool num_wid_processed = false; + u32 cnt = 0; + u32 idx = 0; + u32 ResCnt = 0; + /* Check whether the received frame is a valid response */ + if (RESP_MSG_TYPE != resp[0]) { + PRINT_INFO(CORECONFIG_DBG, "Received Message format incorrect.\n"); + return -1; + } + + /* Extract Response Length */ + u16RespLen = MAKE_WORD16(resp[2], resp[3]); + Res_Len = u16RespLen; + + for (idx = MSG_HEADER_LEN; idx < u16RespLen; ) { + u16WIDid = MAKE_WORD16(resp[idx], resp[idx + 1]); + cfg_len = resp[idx + 2]; + /* Incase of Bin Type Wid, the length is given by two byte field */ + enuWIDtype = get_wid_type(u16WIDid); + if (WID_BIN_DATA == enuWIDtype) { + cfg_len |= ((u16)resp[idx + 3] << 8) & 0xFF00; + idx++; + } + idx += 3; + if ((u16WIDid == g_wid_num) && (!num_wid_processed)) { + num_wid_processed = true; + + if (-2 == further_process_response(&resp[idx], u16WIDid, cfg_len, true, 0, &pstrWIDcfgResult[ResCnt])) { + return -2; + } + ResCnt++; + } else { + for (cnt = 0; cnt < g_num_total_switches; cnt++) { + if (gastrWIDs[cnt].u16WIDid == u16WIDid) { + if (-2 == further_process_response(&resp[idx], u16WIDid, cfg_len, false, cnt, + &pstrWIDcfgResult[ResCnt])) { + return -2; + } + ResCnt++; + } + } + } + idx += cfg_len; + /* In case if BIN type Wid, The last byte of the Cfg packet is the */ + /* Checksum. The WID Length field does not accounts for the checksum. */ + /* The Checksum is discarded. */ + if (WID_BIN_DATA == enuWIDtype) { + idx++; + } + } + + return 0; +} + +/** + * @brief parses the write response [just detects its status: success or failure] + * @details + * @param[in] pu8RespBuffer The Response to be parsed + * @return Error code indicating Write Operation status: + * WRITE_RESP_SUCCESS (1) => Write Success. + * WILC_FAIL (-100) => Write Failure. + * @note + * @author Ittiam + * @date 11 Aug 2009 + * @version 1.0 + */ + +s32 ParseWriteResponse(u8 *pu8RespBuffer) +{ + s32 s32Error = WILC_FAIL; + u16 u16RespLen = 0; + u16 u16WIDtype = (u16)WID_NIL; + + /* Check whether the received frame is a valid response */ + if (RESP_MSG_TYPE != pu8RespBuffer[0]) { + PRINT_ER("Received Message format incorrect.\n"); + return WILC_FAIL; + } + + /* Extract Response Length */ + u16RespLen = MAKE_WORD16(pu8RespBuffer[2], pu8RespBuffer[3]); + + u16WIDtype = MAKE_WORD16(pu8RespBuffer[4], pu8RespBuffer[5]); + + /* Check for WID_STATUS ID and then check the length and status value */ + if ((u16WIDtype == WID_STATUS) && + (pu8RespBuffer[6] == 1) && + (pu8RespBuffer[7] == WRITE_RESP_SUCCESS)) { + s32Error = WRITE_RESP_SUCCESS; + return s32Error; + } + + /* If the length or status are not as expected return failure */ + s32Error = WILC_FAIL; + return s32Error; + +} + +/** + * @brief creates the header of the Configuration Packet + * @details + * @param[in,out] pcpacket The Configuration Packet + * @param[in,out] ps32PacketLength Length of the Configuration Packet + * @return Error code indicating success/failure + * @note + * @author aismail + * @date 18 Feb 2012 + * @version 1.0 + */ + +s32 CreatePacketHeader(char *pcpacket, s32 *ps32PacketLength) +{ + s32 s32Error = WILC_SUCCESS; + u16 u16MsgLen = (u16)(*ps32PacketLength); + u16 u16MsgInd = 0; + + /* The format of the message is: */ + /* +-------------------------------------------------------------------+ */ + /* | Message Type | Message ID | Message Length |Message body | */ + /* +-------------------------------------------------------------------+ */ + /* | 1 Byte | 1 Byte | 2 Bytes | Message Length - 4 | */ + /* +-------------------------------------------------------------------+ */ + + /* The format of a message body of a message type 'W' is: */ + /* +-------------------------------------------------------------------+ */ + /* | WID0 | WID0 Length | WID0 Value | ......................... | */ + /* +-------------------------------------------------------------------+ */ + /* | 2 Bytes | 1 Byte | WID0 Length | ......................... | */ + /* +-------------------------------------------------------------------+ */ + + + + /* Message Type */ + if (g_oper_mode == SET_CFG) + pcpacket[u16MsgInd++] = WRITE_MSG_TYPE; + else + pcpacket[u16MsgInd++] = QUERY_MSG_TYPE; + + /* Sequence Number */ + pcpacket[u16MsgInd++] = g_seqno++; + + /* Message Length */ + pcpacket[u16MsgInd++] = (u8)(u16MsgLen & 0xFF); + pcpacket[u16MsgInd++] = (u8)((u16MsgLen >> 8) & 0xFF); + + *ps32PacketLength = u16MsgLen; + + return s32Error; +} + +/** + * @brief creates Configuration packet based on the Input WIDs + * @details + * @param[in] pstrWIDs WIDs to be sent in the configuration packet + * @param[in] u32WIDsCount number of WIDs to be sent in the configuration packet + * @param[out] ps8packet The created Configuration Packet + * @param[out] ps32PacketLength Length of the created Configuration Packet + * @return Error code indicating success/failure + * @note + * @author + * @date 1 Mar 2012 + * @version 1.0 + */ + +s32 CreateConfigPacket(s8 *ps8packet, s32 *ps32PacketLength, + tstrWID *pstrWIDs, u32 u32WIDsCount) +{ + s32 s32Error = WILC_SUCCESS; + u32 u32idx = 0; + *ps32PacketLength = MSG_HEADER_LEN; + for (u32idx = 0; u32idx < u32WIDsCount; u32idx++) { + switch (pstrWIDs[u32idx].enuWIDtype) { + case WID_CHAR: + ProcessCharWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal); + break; + + case WID_SHORT: + ProcessShortWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal); + break; + + case WID_INT: + ProcessIntWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal); + break; + + case WID_STR: + ProcessStrWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal, pstrWIDs[u32idx].s32ValueSize); + break; + + case WID_IP: + ProcessIPwid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal); + break; + + case WID_BIN_DATA: + ProcessBinWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal, pstrWIDs[u32idx].s32ValueSize); + break; + + default: + PRINT_ER("ERROR: Check Config database\n"); + } + } + + CreatePacketHeader(ps8packet, ps32PacketLength); + + return s32Error; +} + +s32 ConfigWaitResponse(char *pcRespBuffer, s32 s32MaxRespBuffLen, s32 *ps32BytesRead, + bool bRespRequired) +{ + s32 s32Error = WILC_SUCCESS; + /*bug 3878*/ + /*removed to caller function*/ + /*gstrConfigPktInfo.pcRespBuffer = pcRespBuffer; + * gstrConfigPktInfo.s32MaxRespBuffLen = s32MaxRespBuffLen; + * gstrConfigPktInfo.bRespRequired = bRespRequired;*/ + + + if (gstrConfigPktInfo.bRespRequired) { + down(&SemHandlePktResp); + + *ps32BytesRead = gstrConfigPktInfo.s32BytesRead; + } + + WILC_memset((void *)(&gstrConfigPktInfo), 0, sizeof(tstrConfigPktInfo)); + + return s32Error; +} + +/** + * @brief sends certain Configuration Packet based on the input WIDs pstrWIDs + * and retrieves the packet response pu8RxResp + * @details + * @param[in] pstrWIDs WIDs to be sent in the configuration packet + * @param[in] u32WIDsCount number of WIDs to be sent in the configuration packet + * @param[out] pu8RxResp The received Packet Response + * @param[out] ps32RxRespLen Length of the received Packet Response + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 1 Mar 2012 + * @version 1.0 + */ +#ifdef SIMULATION +s32 SendConfigPkt(u8 u8Mode, tstrWID *pstrWIDs, + u32 u32WIDsCount, bool bRespRequired, u32 drvHandler) +{ + s32 s32Error = WILC_SUCCESS; + s32 err = WILC_SUCCESS; + s32 s32ConfigPacketLen = 0; + s32 s32RcvdRespLen = 0; + + down(&SemHandleSendPkt); + + /*set the packet mode*/ + g_oper_mode = u8Mode; + + WILC_memset((void *)gps8ConfigPacket, 0, MAX_PACKET_BUFF_SIZE); + + if (CreateConfigPacket(gps8ConfigPacket, &s32ConfigPacketLen, pstrWIDs, u32WIDsCount) != WILC_SUCCESS) { + s32Error = WILC_FAIL; + goto End_ConfigPkt; + } + /*bug 3878*/ + gstrConfigPktInfo.pcRespBuffer = gps8ConfigPacket; + gstrConfigPktInfo.s32MaxRespBuffLen = MAX_PACKET_BUFF_SIZE; + PRINT_INFO(CORECONFIG_DBG, "GLOBAL =bRespRequired =%d\n", bRespRequired); + gstrConfigPktInfo.bRespRequired = bRespRequired; + + s32Error = SendRawPacket(gps8ConfigPacket, s32ConfigPacketLen); + if (s32Error != WILC_SUCCESS) { + goto End_ConfigPkt; + } + + WILC_memset((void *)gps8ConfigPacket, 0, MAX_PACKET_BUFF_SIZE); + + ConfigWaitResponse(gps8ConfigPacket, MAX_PACKET_BUFF_SIZE, &s32RcvdRespLen, bRespRequired); + + + if (bRespRequired) { + /* If the operating Mode is GET, then we expect a response frame from */ + /* the driver. Hence start listening to the port for response */ + if (g_oper_mode == GET_CFG) { + #if 1 + err = ParseResponse(gps8ConfigPacket, pstrWIDs); + if (err != 0) { + s32Error = WILC_FAIL; + goto End_ConfigPkt; + } else { + s32Error = WILC_SUCCESS; + } + #endif + } else { + err = ParseWriteResponse(gps8ConfigPacket); + if (err != WRITE_RESP_SUCCESS) { + s32Error = WILC_FAIL; + goto End_ConfigPkt; + } else { + s32Error = WILC_SUCCESS; + } + } + + + } + + +End_ConfigPkt: + up(&SemHandleSendPkt); + + return s32Error; +} +#endif +s32 ConfigProvideResponse(char *pcRespBuffer, s32 s32RespLen) +{ + s32 s32Error = WILC_SUCCESS; + + if (gstrConfigPktInfo.bRespRequired) { + if (s32RespLen <= gstrConfigPktInfo.s32MaxRespBuffLen) { + WILC_memcpy(gstrConfigPktInfo.pcRespBuffer, pcRespBuffer, s32RespLen); + gstrConfigPktInfo.s32BytesRead = s32RespLen; + } else { + WILC_memcpy(gstrConfigPktInfo.pcRespBuffer, pcRespBuffer, gstrConfigPktInfo.s32MaxRespBuffLen); + gstrConfigPktInfo.s32BytesRead = gstrConfigPktInfo.s32MaxRespBuffLen; + PRINT_ER("BusProvideResponse() Response greater than the prepared Buffer Size\n"); + } + + up(&SemHandlePktResp); + } + + return s32Error; +} + +/** + * @brief writes the received packet pu8RxPacket in the global Rx FIFO buffer + * @details + * @param[in] pu8RxPacket The received packet + * @param[in] s32RxPacketLen Length of the received packet + * @return Error code indicating success/failure + * @note + * + * @author mabubakr + * @date 1 Mar 2012 + * @version 1.0 + */ + +s32 ConfigPktReceived(u8 *pu8RxPacket, s32 s32RxPacketLen) +{ + s32 s32Error = WILC_SUCCESS; + u8 u8MsgType = 0; + + u8MsgType = pu8RxPacket[0]; + + switch (u8MsgType) { + case 'R': + ConfigProvideResponse(pu8RxPacket, s32RxPacketLen); + + break; + + case 'N': + PRINT_INFO(CORECONFIG_DBG, "NetworkInfo packet received\n"); + NetworkInfoReceived(pu8RxPacket, s32RxPacketLen); + break; + + case 'I': + GnrlAsyncInfoReceived(pu8RxPacket, s32RxPacketLen); + break; + + case 'S': + host_int_ScanCompleteReceived(pu8RxPacket, s32RxPacketLen); + break; + + default: + PRINT_ER("ConfigPktReceived(): invalid received msg type at the Core Configurator\n"); + break; + } + + return s32Error; +} + +/** + * @brief Deinitializes the Core Configurator + * @details + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 1 Mar 2012 + * @version 1.0 + */ + +s32 CoreConfiguratorDeInit(void) +{ + s32 s32Error = WILC_SUCCESS; + + PRINT_D(CORECONFIG_DBG, "CoreConfiguratorDeInit()\n"); + + if (gps8ConfigPacket != NULL) { + + WILC_FREE(gps8ConfigPacket); + gps8ConfigPacket = NULL; + } + + return s32Error; +} + + +#ifndef SIMULATION +/*Using the global handle of the driver*/ +extern wilc_wlan_oup_t *gpstrWlanOps; +/** + * @brief sends certain Configuration Packet based on the input WIDs pstrWIDs + * using driver config layer + * + * @details + * @param[in] pstrWIDs WIDs to be sent in the configuration packet + * @param[in] u32WIDsCount number of WIDs to be sent in the configuration packet + * @param[out] pu8RxResp The received Packet Response + * @param[out] ps32RxRespLen Length of the received Packet Response + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 1 Mar 2012 + * @version 1.0 + */ +s32 SendConfigPkt(u8 u8Mode, tstrWID *pstrWIDs, + u32 u32WIDsCount, bool bRespRequired, u32 drvHandler) +{ + s32 counter = 0, ret = 0; + if (gpstrWlanOps == NULL) { + PRINT_D(CORECONFIG_DBG, "Net Dev is still not initialized\n"); + return 1; + } else { + PRINT_D(CORECONFIG_DBG, "Net Dev is initialized\n"); + } + if (gpstrWlanOps->wlan_cfg_set == NULL || + gpstrWlanOps->wlan_cfg_get == NULL) { + PRINT_D(CORECONFIG_DBG, "Set and Get is still not initialized\n"); + return 1; + } else { + PRINT_D(CORECONFIG_DBG, "SET is initialized\n"); + } + if (u8Mode == GET_CFG) { + for (counter = 0; counter < u32WIDsCount; counter++) { + PRINT_INFO(CORECONFIG_DBG, "Sending CFG packet [%d][%d]\n", !counter, + (counter == u32WIDsCount - 1)); + if (!gpstrWlanOps->wlan_cfg_get(!counter, + pstrWIDs[counter].u16WIDid, + (counter == u32WIDsCount - 1), drvHandler)) { + ret = -1; + printk("[Sendconfigpkt]Get Timed out\n"); + break; + } + } + /** + * get the value + **/ + /* WILC_Sleep(1000); */ + counter = 0; + for (counter = 0; counter < u32WIDsCount; counter++) { + pstrWIDs[counter].s32ValueSize = gpstrWlanOps->wlan_cfg_get_value( + pstrWIDs[counter].u16WIDid, + pstrWIDs[counter].ps8WidVal, pstrWIDs[counter].s32ValueSize); + + } + } else if (u8Mode == SET_CFG) { + for (counter = 0; counter < u32WIDsCount; counter++) { + PRINT_D(CORECONFIG_DBG, "Sending config SET PACKET WID:%x\n", pstrWIDs[counter].u16WIDid); + if (!gpstrWlanOps->wlan_cfg_set(!counter, + pstrWIDs[counter].u16WIDid, pstrWIDs[counter].ps8WidVal, + pstrWIDs[counter].s32ValueSize, + (counter == u32WIDsCount - 1), drvHandler)) { + ret = -1; + printk("[Sendconfigpkt]Set Timed out\n"); + break; + } + } + } + + return ret; +} +#endif diff --git a/drivers/staging/wilc1000/coreconfigurator.h b/drivers/staging/wilc1000/coreconfigurator.h new file mode 100644 index 000000000..9059c8df7 --- /dev/null +++ b/drivers/staging/wilc1000/coreconfigurator.h @@ -0,0 +1,197 @@ + +/*! + * @file coreconfigurator.h + * @brief + * @author + * @sa coreconfigurator.c + * @date 1 Mar 2012 + * @version 1.0 + */ + + +#ifndef CORECONFIGURATOR_H +#define CORECONFIGURATOR_H + +#include "wilc_wlan_if.h" +/*****************************************************************************/ +/* Constants */ +/*****************************************************************************/ +/* Number of WID Options Supported */ +#define NUM_BASIC_SWITCHES 45 +#define NUM_FHSS_SWITCHES 0 + +#define NUM_RSSI 5 + +#ifdef MAC_802_11N +#define NUM_11N_BASIC_SWITCHES 25 +#define NUM_11N_HUT_SWITCHES 47 +#else /* MAC_802_11N */ +#define NUM_11N_BASIC_SWITCHES 0 +#define NUM_11N_HUT_SWITCHES 0 +#endif /* MAC_802_11N */ + +extern u16 g_num_total_switches; + +#define MAC_HDR_LEN 24 /* No Address4 - non-ESS */ +#define MAX_SSID_LEN 33 +#define FCS_LEN 4 +#define TIME_STAMP_LEN 8 +#define BEACON_INTERVAL_LEN 2 +#define CAP_INFO_LEN 2 +#define STATUS_CODE_LEN 2 +#define AID_LEN 2 +#define IE_HDR_LEN 2 + + +/* Operating Mode: SET */ +#define SET_CFG 0 +/* Operating Mode: GET */ +#define GET_CFG 1 + +#define MAX_PACKET_BUFF_SIZE 1596 + +#define MAX_STRING_LEN 256 +#define MAX_SURVEY_RESULT_FRAG_SIZE MAX_STRING_LEN +#define SURVEY_RESULT_LENGTH 44 +#define MAX_ASSOC_RESP_FRAME_SIZE MAX_STRING_LEN + +#define STATUS_MSG_LEN 12 +#define MAC_CONNECTED 1 +#define MAC_DISCONNECTED 0 + + + +/*****************************************************************************/ +/* Function Macros */ +/*****************************************************************************/ +#define MAKE_WORD16(lsb, msb) ((((u16)(msb) << 8) & 0xFF00) | (lsb)) +#define MAKE_WORD32(lsw, msw) ((((u32)(msw) << 16) & 0xFFFF0000) | (lsw)) + + +/*****************************************************************************/ +/* Type Definitions */ +/*****************************************************************************/ +/* Status Codes for Authentication and Association Frames */ +typedef enum { + SUCCESSFUL_STATUSCODE = 0, + UNSPEC_FAIL = 1, + UNSUP_CAP = 10, + REASOC_NO_ASOC = 11, + FAIL_OTHER = 12, + UNSUPT_ALG = 13, + AUTH_SEQ_FAIL = 14, + CHLNG_FAIL = 15, + AUTH_TIMEOUT = 16, + AP_FULL = 17, + UNSUP_RATE = 18, + SHORT_PREAMBLE_UNSUP = 19, + PBCC_UNSUP = 20, + CHANNEL_AGIL_UNSUP = 21, + SHORT_SLOT_UNSUP = 25, + OFDM_DSSS_UNSUP = 26, + CONNECT_STS_FORCE_16_BIT = 0xFFFF +} tenuConnectSts; + +typedef struct { + u16 u16WIDid; + tenuWIDtype enuWIDtype; + s32 s32ValueSize; + s8 *ps8WidVal; + +} tstrWID; + +typedef struct { + u8 u8Full; + u8 u8Index; + s8 as8RSSI[NUM_RSSI]; +} tstrRSSI; +/* This structure is used to support parsing of the received 'N' message */ +typedef struct { + s8 s8rssi; + u16 u16CapInfo; + u8 au8ssid[MAX_SSID_LEN]; + u8 u8SsidLen; + u8 au8bssid[6]; + u16 u16BeaconPeriod; + u8 u8DtimPeriod; + u8 u8channel; + unsigned long u32TimeRcvdInScanCached; /* of type unsigned long to be accepted by the linux kernel macro time_after() */ + unsigned long u32TimeRcvdInScan; + bool bNewNetwork; +#ifdef AGING_ALG + u8 u8Found; +#endif +#ifdef WILC_P2P + u32 u32Tsf; /* time-stamp [Low only 32 bit] */ +#endif + u8 *pu8IEs; + u16 u16IEsLen; + void *pJoinParams; + tstrRSSI strRssi; + u64 u64Tsf; /* time-stamp [Low and High 64 bit] */ +} tstrNetworkInfo; + +/* This structure is used to support parsing of the received Association Response frame */ +typedef struct { + u16 u16capability; + u16 u16ConnectStatus; + u16 u16AssocID; + u8 *pu8RespIEs; + u16 u16RespIEsLen; +} tstrConnectRespInfo; + + +typedef struct { + u8 au8bssid[6]; + u8 *pu8ReqIEs; + size_t ReqIEsLen; + u8 *pu8RespIEs; + u16 u16RespIEsLen; + u16 u16ConnectStatus; +} tstrConnectInfo; + + + +typedef struct { + u16 u16reason; + u8 *ie; + size_t ie_len; +} tstrDisconnectNotifInfo; + +#ifndef CONNECT_DIRECT +typedef struct wid_site_survey_reslts { + char SSID[MAX_SSID_LEN]; + u8 BssType; + u8 Channel; + u8 SecurityStatus; + u8 BSSID[6]; + char RxPower; + u8 Reserved; + +} wid_site_survey_reslts_s; +#endif + +extern s32 CoreConfiguratorInit(void); +extern s32 CoreConfiguratorDeInit(void); + +extern s32 SendConfigPkt(u8 u8Mode, tstrWID *pstrWIDs, + u32 u32WIDsCount, bool bRespRequired, u32 drvHandler); +extern s32 ParseNetworkInfo(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo); +extern s32 DeallocateNetworkInfo(tstrNetworkInfo *pstrNetworkInfo); + +extern s32 ParseAssocRespInfo(u8 *pu8Buffer, u32 u32BufferLen, + tstrConnectRespInfo **ppstrConnectRespInfo); +extern s32 DeallocateAssocRespInfo(tstrConnectRespInfo *pstrConnectRespInfo); + +#ifndef CONNECT_DIRECT +extern s32 ParseSurveyResults(u8 ppu8RcvdSiteSurveyResults[][MAX_SURVEY_RESULT_FRAG_SIZE], + wid_site_survey_reslts_s **ppstrSurveyResults, u32 *pu32SurveyResultsCount); +extern s32 DeallocateSurveyResults(wid_site_survey_reslts_s *pstrSurveyResults); +#endif + +extern s32 SendRawPacket(s8 *pspacket, s32 s32PacketLen); +extern void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length); +void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length); +void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length); + +#endif diff --git a/drivers/staging/wilc1000/fifo_buffer.c b/drivers/staging/wilc1000/fifo_buffer.c new file mode 100644 index 000000000..b6c07cfc4 --- /dev/null +++ b/drivers/staging/wilc1000/fifo_buffer.c @@ -0,0 +1,133 @@ + + +#include "fifo_buffer.h" + + + +u32 FIFO_InitBuffer(tHANDLE *hBuffer, u32 u32BufferLength) +{ + u32 u32Error = 0; + tstrFifoHandler *pstrFifoHandler = WILC_MALLOC (sizeof (tstrFifoHandler)); + if (pstrFifoHandler) { + WILC_memset (pstrFifoHandler, 0, sizeof (tstrFifoHandler)); + pstrFifoHandler->pu8Buffer = WILC_MALLOC (u32BufferLength); + if (pstrFifoHandler->pu8Buffer) { + pstrFifoHandler->u32BufferLength = u32BufferLength; + WILC_memset (pstrFifoHandler->pu8Buffer, 0, u32BufferLength); + /* create semaphore */ + sema_init(&pstrFifoHandler->SemBuffer, 1); + *hBuffer = pstrFifoHandler; + } else { + *hBuffer = NULL; + u32Error = 1; + } + } else { + u32Error = 1; + } + return u32Error; +} +u32 FIFO_DeInit(tHANDLE hFifo) +{ + u32 u32Error = 0; + tstrFifoHandler *pstrFifoHandler = (tstrFifoHandler *) hFifo; + if (pstrFifoHandler) { + if (pstrFifoHandler->pu8Buffer) { + WILC_FREE (pstrFifoHandler->pu8Buffer); + } else { + u32Error = 1; + } + + WILC_FREE (pstrFifoHandler); + } else { + u32Error = 1; + } + return u32Error; +} + +u32 FIFO_ReadBytes(tHANDLE hFifo, u8 *pu8Buffer, u32 u32BytesToRead, u32 *pu32BytesRead) +{ + u32 u32Error = 0; + tstrFifoHandler *pstrFifoHandler = (tstrFifoHandler *) hFifo; + if (pstrFifoHandler && pu32BytesRead) { + if (pstrFifoHandler->u32TotalBytes) { + down(&pstrFifoHandler->SemBuffer); + + if (u32BytesToRead > pstrFifoHandler->u32TotalBytes) { + *pu32BytesRead = pstrFifoHandler->u32TotalBytes; + } else { + *pu32BytesRead = u32BytesToRead; + } + if ((pstrFifoHandler->u32ReadOffset + u32BytesToRead) <= pstrFifoHandler->u32BufferLength) { + WILC_memcpy(pu8Buffer, pstrFifoHandler->pu8Buffer + pstrFifoHandler->u32ReadOffset, + *pu32BytesRead); + /* update read offset and total bytes */ + pstrFifoHandler->u32ReadOffset += u32BytesToRead; + pstrFifoHandler->u32TotalBytes -= u32BytesToRead; + + } else { + u32 u32FirstPart = + pstrFifoHandler->u32BufferLength - pstrFifoHandler->u32ReadOffset; + WILC_memcpy(pu8Buffer, pstrFifoHandler->pu8Buffer + pstrFifoHandler->u32ReadOffset, + u32FirstPart); + WILC_memcpy(pu8Buffer + u32FirstPart, pstrFifoHandler->pu8Buffer, + u32BytesToRead - u32FirstPart); + /* update read offset and total bytes */ + pstrFifoHandler->u32ReadOffset = u32BytesToRead - u32FirstPart; + pstrFifoHandler->u32TotalBytes -= u32BytesToRead; + } + up(&pstrFifoHandler->SemBuffer); + } else { + u32Error = 1; + } + } else { + u32Error = 1; + } + return u32Error; +} + +u32 FIFO_WriteBytes(tHANDLE hFifo, u8 *pu8Buffer, u32 u32BytesToWrite, bool bForceOverWrite) +{ + u32 u32Error = 0; + tstrFifoHandler *pstrFifoHandler = (tstrFifoHandler *) hFifo; + if (pstrFifoHandler) { + if (u32BytesToWrite < pstrFifoHandler->u32BufferLength) { + if ((pstrFifoHandler->u32TotalBytes + u32BytesToWrite) <= pstrFifoHandler->u32BufferLength || + bForceOverWrite) { + down(&pstrFifoHandler->SemBuffer); + if ((pstrFifoHandler->u32WriteOffset + u32BytesToWrite) <= pstrFifoHandler->u32BufferLength) { + WILC_memcpy(pstrFifoHandler->pu8Buffer + pstrFifoHandler->u32WriteOffset, pu8Buffer, + u32BytesToWrite); + /* update read offset and total bytes */ + pstrFifoHandler->u32WriteOffset += u32BytesToWrite; + pstrFifoHandler->u32TotalBytes += u32BytesToWrite; + + } else { + u32 u32FirstPart = + pstrFifoHandler->u32BufferLength - pstrFifoHandler->u32WriteOffset; + WILC_memcpy(pstrFifoHandler->pu8Buffer + pstrFifoHandler->u32WriteOffset, pu8Buffer, + u32FirstPart); + WILC_memcpy(pstrFifoHandler->pu8Buffer, pu8Buffer + u32FirstPart, + u32BytesToWrite - u32FirstPart); + /* update read offset and total bytes */ + pstrFifoHandler->u32WriteOffset = u32BytesToWrite - u32FirstPart; + pstrFifoHandler->u32TotalBytes += u32BytesToWrite; + } + /* if data overwriten */ + if (pstrFifoHandler->u32TotalBytes > pstrFifoHandler->u32BufferLength) { + /* adjust read offset to the oldest data available */ + pstrFifoHandler->u32ReadOffset = pstrFifoHandler->u32WriteOffset; + /* data availabe is the buffer length */ + pstrFifoHandler->u32TotalBytes = pstrFifoHandler->u32BufferLength; + } + up(&pstrFifoHandler->SemBuffer); + } else { + u32Error = 1; + } + } else { + u32Error = 1; + } + } else { + u32Error = 1; + } + return u32Error; +} diff --git a/drivers/staging/wilc1000/fifo_buffer.h b/drivers/staging/wilc1000/fifo_buffer.h new file mode 100644 index 000000000..7b76998e4 --- /dev/null +++ b/drivers/staging/wilc1000/fifo_buffer.h @@ -0,0 +1,26 @@ + +#include +#include +#include "wilc_memory.h" +#include "wilc_strutils.h" + + +#define tHANDLE void * + +typedef struct { + u8 *pu8Buffer; + u32 u32BufferLength; + u32 u32WriteOffset; + u32 u32ReadOffset; + u32 u32TotalBytes; + struct semaphore SemBuffer; +} tstrFifoHandler; + + +extern u32 FIFO_InitBuffer(tHANDLE *hBuffer, + u32 u32BufferLength); +extern u32 FIFO_DeInit(tHANDLE hFifo); +extern u32 FIFO_ReadBytes(tHANDLE hFifo, u8 *pu8Buffer, + u32 u32BytesToRead, u32 *pu32BytesRead); +extern u32 FIFO_WriteBytes(tHANDLE hFifo, u8 *pu8Buffer, + u32 u32BytesToWrite, bool bForceOverWrite); diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c new file mode 100644 index 000000000..6b10bbbe6 --- /dev/null +++ b/drivers/staging/wilc1000/host_interface.c @@ -0,0 +1,7963 @@ +#include "host_interface.h" +#include "coreconfigurator.h" + +extern s32 TransportInit(void); +extern s32 TransportDeInit(void); +extern u8 connecting; + +#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP +extern WILC_TimerHandle hDuringIpTimer; +#endif + +extern bool bEnablePS; +/*BugID_5137*/ +extern u8 g_wilc_initialized; +/*****************************************************************************/ +/* Macros */ +/*****************************************************************************/ + +/* Message types of the Host IF Message Queue*/ +#define HOST_IF_MSG_SCAN 0 +#define HOST_IF_MSG_CONNECT 1 +#define HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO 2 +#define HOST_IF_MSG_KEY 3 +#define HOST_IF_MSG_RCVD_NTWRK_INFO 4 +#define HOST_IF_MSG_RCVD_SCAN_COMPLETE 5 +#define HOST_IF_MSG_CFG_PARAMS 6 +#define HOST_IF_MSG_SET_CHANNEL 7 +#define HOST_IF_MSG_DISCONNECT 8 +#define HOST_IF_MSG_GET_RSSI 9 +#define HOST_IF_MSG_GET_CHNL 10 +#define HOST_IF_MSG_ADD_BEACON 11 +#define HOST_IF_MSG_DEL_BEACON 12 +#define HOST_IF_MSG_ADD_STATION 13 +#define HOST_IF_MSG_DEL_STATION 14 +#define HOST_IF_MSG_EDIT_STATION 15 +#define HOST_IF_MSG_SCAN_TIMER_FIRED 16 +#define HOST_IF_MSG_CONNECT_TIMER_FIRED 17 +#define HOST_IF_MSG_POWER_MGMT 18 +#define HOST_IF_MSG_GET_INACTIVETIME 19 +#define HOST_IF_MSG_REMAIN_ON_CHAN 20 +#define HOST_IF_MSG_REGISTER_FRAME 21 +#define HOST_IF_MSG_LISTEN_TIMER_FIRED 22 +#define HOST_IF_MSG_GET_LINKSPEED 23 +#define HOST_IF_MSG_SET_WFIDRV_HANDLER 24 +#define HOST_IF_MSG_SET_MAC_ADDRESS 25 +#define HOST_IF_MSG_GET_MAC_ADDRESS 26 +#define HOST_IF_MSG_SET_OPERATION_MODE 27 +#define HOST_IF_MSG_SET_IPADDRESS 28 +#define HOST_IF_MSG_GET_IPADDRESS 29 +#define HOST_IF_MSG_FLUSH_CONNECT 30 +#define HOST_IF_MSG_GET_STATISTICS 31 +#define HOST_IF_MSG_SET_MULTICAST_FILTER 32 +#define HOST_IF_MSG_ADD_BA_SESSION 33 +#define HOST_IF_MSG_DEL_BA_SESSION 34 +#define HOST_IF_MSG_Q_IDLE 35 +#define HOST_IF_MSG_DEL_ALL_STA 36 +#define HOST_IF_MSG_DEL_ALL_RX_BA_SESSIONS 34 +#define HOST_IF_MSG_EXIT 100 + +#define HOST_IF_SCAN_TIMEOUT 4000 +#define HOST_IF_CONNECT_TIMEOUT 9500 + +#define BA_SESSION_DEFAULT_BUFFER_SIZE 16 +#define BA_SESSION_DEFAULT_TIMEOUT 1000 +#define BLOCK_ACK_REQ_SIZE 0x14 +/*****************************************************************************/ +/* Type Definitions */ +/*****************************************************************************/ + +/*! + * @struct tstrHostIFCfgParamAttr + * @brief Structure to hold Host IF CFG Params Attributes + * @details + * @todo + * @sa + * @author Mai Daftedar + * @date 02 April 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFCfgParamAttr { + tstrCfgParamVal pstrCfgParamVal; + +} tstrHostIFCfgParamAttr; + +/*! + * @struct tstrHostIFwpaAttr + * @brief Structure to hold Host IF Scan Attributes + * @details + * @todo + * @sa + * @author Mai Daftedar + * @date 25 March 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFwpaAttr { + u8 *pu8key; + const u8 *pu8macaddr; + u8 *pu8seq; + u8 u8seqlen; + u8 u8keyidx; + u8 u8Keylen; + u8 u8Ciphermode; +} tstrHostIFwpaAttr; + + +/*! + * @struct tstrHostIFwepAttr + * @brief Structure to hold Host IF Scan Attributes + * @details + * @todo + * @sa + * @author Mai Daftedar + * @date 25 March 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFwepAttr { + u8 *pu8WepKey; + u8 u8WepKeylen; + u8 u8Wepidx; + u8 u8mode; + AUTHTYPE_T tenuAuth_type; + +} tstrHostIFwepAttr; + +/*! + * @struct tuniHostIFkeyAttr + * @brief Structure to hold Host IF Scan Attributes + * @details + * @todo + * @sa + * @author Mai Daftedar + * @date 25 March 2012 + * @version 1.0 + */ +typedef union _tuniHostIFkeyAttr { + tstrHostIFwepAttr strHostIFwepAttr; + tstrHostIFwpaAttr strHostIFwpaAttr; + tstrHostIFpmkidAttr strHostIFpmkidAttr; +} tuniHostIFkeyAttr; + +/*! + * @struct tstrHostIFkeyAttr + * @brief Structure to hold Host IF Scan Attributes + * @details + * @todo + * @sa + * @author Mai Daftedar + * @date 25 March 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFkeyAttr { + tenuKeyType enuKeyType; + u8 u8KeyAction; + tuniHostIFkeyAttr uniHostIFkeyAttr; +} tstrHostIFkeyAttr; + + + + +/*! + * @struct tstrHostIFscanAttr + * @brief Structure to hold Host IF Scan Attributes + * @details + * @todo + * @sa + * @author Mostafa Abu Bakr + * @date 25 March 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFscanAttr { + u8 u8ScanSource; + u8 u8ScanType; + u8 *pu8ChnlFreqList; + u8 u8ChnlListLen; + u8 *pu8IEs; + size_t IEsLen; + tWILCpfScanResult pfScanResult; + void *pvUserArg; + /*BugID_4189*/ + tstrHiddenNetwork strHiddenNetwork; + +} tstrHostIFscanAttr; + +/*! + * @struct tstrHostIFconnectAttr + * @brief Structure to hold Host IF Connect Attributes + * @details + * @todo + * @sa + * @author Mostafa Abu Bakr + * @date 25 March 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFconnectAttr { + u8 *pu8bssid; + u8 *pu8ssid; + size_t ssidLen; + u8 *pu8IEs; + size_t IEsLen; + u8 u8security; + tWILCpfConnectResult pfConnectResult; + void *pvUserArg; + AUTHTYPE_T tenuAuth_type; + u8 u8channel; + void *pJoinParams; +} tstrHostIFconnectAttr; + +/*! + * @struct tstrRcvdGnrlAsyncInfo + * @brief Structure to hold Received General Asynchronous info + * @details + * @todo + * @sa + * @author Mostafa Abu Bakr + * @date 25 March 2012 + * @version 1.0 + */ +typedef struct _tstrRcvdGnrlAsyncInfo { + u8 *pu8Buffer; + u32 u32Length; +} tstrRcvdGnrlAsyncInfo; + +/*! + * @struct tstrHostIFSetChan + * @brief Set Channel message body + * @details + * @todo + * @sa + * @author Mai Daftedar + * @date 25 March 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFSetChan { + u8 u8SetChan; +} tstrHostIFSetChan; + +/*! + * @struct tstrHostIFSetChan + * @brief Get Channel message body + * @details + * @todo + * @sa + * @author Mai Daftedar + * @date 01 Jule 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFGetChan { + u8 u8GetChan; +} tstrHostIFGetChan; + +/*bug3819: Add Scan acomplete notification to host*/ +/*! + * @struct tstrScanComplete + * @brief hold received Async. Scan Complete message body + * @details + * @todo + * @sa + * @author zsalah + * @date 25 March 2012 + * @version 1.0 + */ +/*typedef struct _tstrScanComplete + * { + * u8* pu8Buffer; + * u32 u32Length; + * } tstrScanComplete;*/ + +/*! + * @struct tstrHostIFSetBeacon + * @brief Set Beacon message body + * @details + * @todo + * @sa + * @author Adham Abozaeid + * @date 10 July 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFSetBeacon { + u32 u32Interval; /*!< Beacon Interval. Period between two successive beacons on air */ + u32 u32DTIMPeriod; /*!< DTIM Period. Indicates how many Beacon frames + * (including the current frame) appear before the next DTIM */ + u32 u32HeadLen; /*!< Length of the head buffer in bytes */ + u8 *pu8Head; /*!< Pointer to the beacon's head buffer. Beacon's head is the part + * from the beacon's start till the TIM element, NOT including the TIM */ + u32 u32TailLen; /*!< Length of the tail buffer in bytes */ + u8 *pu8Tail; /*!< Pointer to the beacon's tail buffer. Beacon's tail starts just + * after the TIM inormation element */ +} tstrHostIFSetBeacon; + + + +/*! + * @struct tstrHostIFDelBeacon + * @brief Del Beacon message body + * @details + * @todo + * @sa + * @author Adham Abozaeid + * @date 15 July 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFDelBeacon { + u8 u8dummy; +} tstrHostIFDelBeacon; + +/*! + * @struct tstrHostIFSetMulti + * @brief set Multicast filter Address + * @details + * @todo + * @sa + * @author Abdelrahman Sobhy + * @date 30 August 2013 + * @version 1.0 Description + */ + +typedef struct { + bool bIsEnabled; + u32 u32count; +} tstrHostIFSetMulti; + +/*! + * @struct tstrHostIFDelAllSta + * @brief Deauth station message body + * @details + * @todo + * @sa + * @author Mai Daftedar + * @date 09 April 2014 + * @version 1.0 Description + */ + +typedef struct { + u8 au8Sta_DelAllSta[MAX_NUM_STA][ETH_ALEN]; + u8 u8Num_AssocSta; +} tstrHostIFDelAllSta; + +/*! + * @struct tstrHostIFDelSta + * @brief Delete station message body + * @details + * @todo + * @sa + * @author Adham Abozaeid + * @date 15 July 2012 + * @version 1.0 Description + */ + +typedef struct { + u8 au8MacAddr[ETH_ALEN]; +} tstrHostIFDelSta; + +/*! + * @struct tstrTimerCb + * @brief Timer callback message body + * @details + * @todo + * @sa + * @author Mostafa Abu Bakr + * @date 25 March 2012 + * @version 1.0 + */ +typedef struct _tstrTimerCb { + void *pvUsrArg; /*!< Private data passed at timer start */ +} tstrTimerCb; + +/*! + * @struct tstrHostIfPowerMgmtParam + * @brief Power management message body + * @details + * @todo + * @sa + * @author Adham Abozaeid + * @date 24 November 2012 + * @version 1.0 + */ +typedef struct { + + bool bIsEnabled; + u32 u32Timeout; +} tstrHostIfPowerMgmtParam; + +/*! + * @struct tstrHostIFSetIPAddr + * @brief set IP Address message body + * @details + * @todo + * @sa + * @author Abdelrahman Sobhy + * @date 30 August 2013 + * @version 1.0 Description + */ + +typedef struct { + u8 *au8IPAddr; + u8 idx; +} tstrHostIFSetIPAddr; + +/*! + * @struct tstrHostIfStaInactiveT + * @brief Get station message body + * @details + * @todo + * @sa + * @author Mai Daftedar + * @date 16 April 2013 + * @version 1.0 + */ +typedef struct { + u8 mac[6]; + +} tstrHostIfStaInactiveT; +/**/ +/*! + * @union tuniHostIFmsgBody + * @brief Message body for the Host Interface message_q + * @details + * @todo + * @sa + * @author Mostafa Abu Bakr + * @date 25 March 2012 + * @version 1.0 + */ +typedef union _tuniHostIFmsgBody { + tstrHostIFscanAttr strHostIFscanAttr; /*!< Host IF Scan Request Attributes message body */ + tstrHostIFconnectAttr strHostIFconnectAttr; /*!< Host IF Connect Request Attributes message body */ + tstrRcvdNetworkInfo strRcvdNetworkInfo; /*!< Received Asynchronous Network Info message body */ + tstrRcvdGnrlAsyncInfo strRcvdGnrlAsyncInfo; /*!< Received General Asynchronous Info message body */ + tstrHostIFkeyAttr strHostIFkeyAttr; /*!<>*/ + tstrHostIFCfgParamAttr strHostIFCfgParamAttr; /*! */ + tstrHostIFSetChan strHostIFSetChan; + tstrHostIFGetChan strHostIFGetChan; + tstrHostIFSetBeacon strHostIFSetBeacon; /*!< Set beacon message body */ + tstrHostIFDelBeacon strHostIFDelBeacon; /*!< Del beacon message body */ + tstrWILC_AddStaParam strAddStaParam; /*!< Add station message body */ + tstrHostIFDelSta strDelStaParam; /*!< Del Station message body */ + tstrWILC_AddStaParam strEditStaParam; /*!< Edit station message body */ + /* tstrScanComplete strScanComplete; / *Received Async. Scan Complete message body* / */ + tstrTimerCb strTimerCb; /*!< Timer callback message body */ + tstrHostIfPowerMgmtParam strPowerMgmtparam; /*!< Power Management message body */ + tstrHostIfStaInactiveT strHostIfStaInactiveT; + tstrHostIFSetIPAddr strHostIfSetIP; + tstrHostIfSetDrvHandler strHostIfSetDrvHandler; + tstrHostIFSetMulti strHostIfSetMulti; + tstrHostIfSetOperationMode strHostIfSetOperationMode; + tstrHostIfSetMacAddress strHostIfSetMacAddress; + tstrHostIfGetMacAddress strHostIfGetMacAddress; + tstrHostIfBASessionInfo strHostIfBASessionInfo; + #ifdef WILC_P2P + tstrHostIfRemainOnChan strHostIfRemainOnChan; + tstrHostIfRegisterFrame strHostIfRegisterFrame; + #endif + char *pUserData; + tstrHostIFDelAllSta strHostIFDelAllSta; +} tuniHostIFmsgBody; + +/*! + * @struct tstrHostIFmsg + * @brief Host Interface message + * @details + * @todo + * @sa + * @author Mostafa Abu Bakr + * @date 25 March 2012 + * @version 1.0 + */ +typedef struct _tstrHostIFmsg { + u16 u16MsgId; /*!< Message ID */ + tuniHostIFmsgBody uniHostIFmsgBody; /*!< Message body */ + void *drvHandler; +} tstrHostIFmsg; + +#ifdef CONNECT_DIRECT +typedef struct _tstrWidJoinReqExt { + char SSID[MAX_SSID_LEN]; + u8 u8channel; + u8 BSSID[6]; +} tstrWidJoinReqExt; +#endif + +/*Bug4218: Parsing Join Param*/ +#ifdef WILC_PARSE_SCAN_IN_HOST +/*Struct containg joinParam of each AP*/ +typedef struct _tstrJoinBssParam { + BSSTYPE_T bss_type; + u8 dtim_period; + u16 beacon_period; + u16 cap_info; + u8 au8bssid[6]; + char ssid[MAX_SSID_LEN]; + u8 ssidLen; + u8 supp_rates[MAX_RATES_SUPPORTED + 1]; + u8 ht_capable; + u8 wmm_cap; + u8 uapsd_cap; + bool rsn_found; + u8 rsn_grp_policy; + u8 mode_802_11i; + u8 rsn_pcip_policy[3]; + u8 rsn_auth_policy[3]; + u8 rsn_cap[2]; + struct _tstrJoinParam *nextJoinBss; + #ifdef WILC_P2P + u32 tsf; + u8 u8NoaEnbaled; + u8 u8OppEnable; + u8 u8CtWindow; + u8 u8Count; + u8 u8Index; + u8 au8Duration[4]; + u8 au8Interval[4]; + u8 au8StartTime[4]; + #endif +} tstrJoinBssParam; +/*Bug4218: Parsing Join Param*/ +/*a linked list table containing needed join parameters entries for each AP found in most recent scan*/ +typedef struct _tstrBssTable { + u8 u8noBssEntries; + tstrJoinBssParam *head; + tstrJoinBssParam *tail; +} tstrBssTable; +#endif /*WILC_PARSE_SCAN_IN_HOST*/ + +typedef enum { + SCAN_TIMER = 0, + CONNECT_TIMER = 1, + SCAN_CONNECT_TIMER_FORCE_32BIT = 0xFFFFFFFF +} tenuScanConnTimer; + +/*****************************************************************************/ +/* */ +/* Global Variabls */ +/* */ +/*****************************************************************************/ + + +tstrWILC_WFIDrv *terminated_handle = NULL; +tstrWILC_WFIDrv *gWFiDrvHandle = NULL; +#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP +bool g_obtainingIP = false; +#endif +u8 P2P_LISTEN_STATE; +static struct task_struct *HostIFthreadHandler; +static WILC_MsgQueueHandle gMsgQHostIF; +static struct semaphore hSemHostIFthrdEnd; + +struct semaphore hSemDeinitDrvHandle; +static struct semaphore hWaitResponse; +struct semaphore hSemHostIntDeinit; +WILC_TimerHandle g_hPeriodicRSSI; + + + +u8 gau8MulticastMacAddrList[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN]; + +#ifndef CONNECT_DIRECT +static u8 gapu8RcvdSurveyResults[2][MAX_SURVEY_RESULT_FRAG_SIZE]; +#endif + +static u8 gapu8RcvdAssocResp[MAX_ASSOC_RESP_FRAME_SIZE]; + +bool gbScanWhileConnected = false; + +static s8 gs8Rssi; +static s8 gs8lnkspd; +static u8 gu8Chnl; +static u8 gs8SetIP[2][4]; +static u8 gs8GetIP[2][4]; +#ifdef WILC_AP_EXTERNAL_MLME +static u32 gu32InactiveTime; +static u8 gu8DelBcn; +#endif +#ifndef SIMULATION +static u32 gu32WidConnRstHack; +#endif + +/*BugID_5137*/ +u8 *gu8FlushedJoinReq; +u8 *gu8FlushedInfoElemAsoc; +u8 gu8Flushed11iMode; +u8 gu8FlushedAuthType; +u32 gu32FlushedJoinReqSize; +u32 gu32FlushedInfoElemAsocSize; +u32 gu8FlushedJoinReqDrvHandler; +#define REAL_JOIN_REQ 0 +#define FLUSHED_JOIN_REQ 1 +#define FLUSHED_BYTE_POS 79 /* Position the byte indicating flushing in the flushed request */ + +/*Bug4218: Parsing Join Param*/ +#ifdef WILC_PARSE_SCAN_IN_HOST +/*Bug4218: Parsing Join Param*/ +static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo); +#endif /*WILC_PARSE_SCAN_IN_HOST*/ + +extern void chip_sleep_manually(u32 u32SleepTime); +extern int linux_wlan_get_num_conn_ifcs(void); + +/** + * @brief Handle_SetChannel + * @details Sending config packet to firmware to set channel + * @param[in] tstrHostIFSetChan* pstrHostIFSetChan + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static s32 Handle_SetChannel(void *drvHandler, tstrHostIFSetChan *pstrHostIFSetChan) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + /*prepare configuration packet*/ + strWID.u16WIDid = (u16)WID_CURRENT_CHANNEL; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = (char *)&(pstrHostIFSetChan->u8SetChan); + strWID.s32ValueSize = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Setting channel\n"); + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Failed to set channel\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} +/** + * @brief Handle_SetWfiDrvHandler + * @details Sending config packet to firmware to set driver handler + * @param[in] void * drvHandler,tstrHostIfSetDrvHandler* pstrHostIfSetDrvHandler + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static s32 Handle_SetWfiDrvHandler(tstrHostIfSetDrvHandler *pstrHostIfSetDrvHandler) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)((pstrHostIfSetDrvHandler->u32Address)); + + + /*prepare configuration packet*/ + strWID.u16WIDid = (u16)WID_SET_DRV_HANDLER; + strWID.enuWIDtype = WID_INT; + strWID.ps8WidVal = (s8 *)&(pstrHostIfSetDrvHandler->u32Address); + strWID.s32ValueSize = sizeof(u32); + + /*Sending Cfg*/ + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + + + if ((pstrHostIfSetDrvHandler->u32Address) == (u32)NULL) { + up(&hSemDeinitDrvHandle); + } + + + if (s32Error) { + PRINT_ER("Failed to set driver handler\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief Handle_SetWfiAPDrvHandler + * @details Sending config packet to firmware to set driver handler + * @param[in] void * drvHandler,tstrHostIfSetDrvHandler* pstrHostIfSetDrvHandler + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static s32 Handle_SetOperationMode(void *drvHandler, tstrHostIfSetOperationMode *pstrHostIfSetOperationMode) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + + /*prepare configuration packet*/ + strWID.u16WIDid = (u16)WID_SET_OPERATION_MODE; + strWID.enuWIDtype = WID_INT; + strWID.ps8WidVal = (s8 *)&(pstrHostIfSetOperationMode->u32Mode); + strWID.s32ValueSize = sizeof(u32); + + /*Sending Cfg*/ + PRINT_INFO(HOSTINF_DBG, "pstrWFIDrv= %p \n", pstrWFIDrv); + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + + + if ((pstrHostIfSetOperationMode->u32Mode) == (u32)NULL) { + up(&hSemDeinitDrvHandle); + } + + + if (s32Error) { + PRINT_ER("Failed to set driver handler\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief host_int_set_IPAddress + * @details Setting IP address params in message queue + * @param[in] WILC_WFIDrvHandle hWFIDrv, u8* pu8IPAddr + * @return Error code. + * @author + * @date + * @version 1.0 + */ +s32 Handle_set_IPAddress(void *drvHandler, u8 *pu8IPAddr, u8 idx) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + char firmwareIPAddress[4] = {0}; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + if (pu8IPAddr[0] < 192) + pu8IPAddr[0] = 0; + + PRINT_INFO(HOSTINF_DBG, "Indx = %d, Handling set IP = %d.%d.%d.%d \n", idx, pu8IPAddr[0], pu8IPAddr[1], pu8IPAddr[2], pu8IPAddr[3]); + + WILC_memcpy(gs8SetIP[idx], pu8IPAddr, IP_ALEN); + + /*prepare configuration packet*/ + strWID.u16WIDid = (u16)WID_IP_ADDRESS; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = (u8 *)pu8IPAddr; + strWID.s32ValueSize = IP_ALEN; + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + + + + host_int_get_ipaddress((WILC_WFIDrvHandle)drvHandler, firmwareIPAddress, idx); + + if (s32Error) { + PRINT_D(HOSTINF_DBG, "Failed to set IP address\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } else { + PRINT_INFO(HOSTINF_DBG, "IP address set\n"); + } + + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + + +/** + * @brief Handle_get_IPAddress + * @details Setting IP address params in message queue + * @param[in] WILC_WFIDrvHandle hWFIDrv, u8* pu8IPAddr + * @return Error code. + * @author + * @date + * @version 1.0 + */ +s32 Handle_get_IPAddress(void *drvHandler, u8 *pu8IPAddr, u8 idx) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + /*prepare configuration packet*/ + strWID.u16WIDid = (u16)WID_IP_ADDRESS; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = (u8 *)WILC_MALLOC(IP_ALEN); + strWID.s32ValueSize = IP_ALEN; + + s32Error = SendConfigPkt(GET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + + PRINT_INFO(HOSTINF_DBG, "%d.%d.%d.%d\n", (u8)(strWID.ps8WidVal[0]), (u8)(strWID.ps8WidVal[1]), (u8)(strWID.ps8WidVal[2]), (u8)(strWID.ps8WidVal[3])); + + WILC_memcpy(gs8GetIP[idx], strWID.ps8WidVal, IP_ALEN); + + /*get the value by searching the local copy*/ + WILC_FREE(strWID.ps8WidVal); + + if (WILC_memcmp(gs8GetIP[idx], gs8SetIP[idx], IP_ALEN) != 0) + host_int_setup_ipaddress((WILC_WFIDrvHandle)pstrWFIDrv, gs8SetIP[idx], idx); + + if (s32Error != WILC_SUCCESS) { + PRINT_ER("Failed to get IP address\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } else { + PRINT_INFO(HOSTINF_DBG, "IP address retrieved:: u8IfIdx = %d \n", idx); + PRINT_INFO(HOSTINF_DBG, "%d.%d.%d.%d\n", gs8GetIP[idx][0], gs8GetIP[idx][1], gs8GetIP[idx][2], gs8GetIP[idx][3]); + PRINT_INFO(HOSTINF_DBG, "\n"); + } + + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + + +/*BugId_5077*/ +/** + * @brief Handle_SetMacAddress + * @details Setting mac address + * @param[in] void * drvHandler,tstrHostIfSetDrvHandler* pstrHostIfSetDrvHandler + * @return Error code. + * @author Amr Abdel-Moghny + * @date November 2013 + * @version 7.0 + */ +static s32 Handle_SetMacAddress(void *drvHandler, tstrHostIfSetMacAddress *pstrHostIfSetMacAddress) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + u8 *mac_buf = (u8 *)WILC_MALLOC(ETH_ALEN); + if (mac_buf == NULL) { + PRINT_ER("No buffer to send mac address\n"); + return WILC_FAIL; + } + WILC_memcpy(mac_buf, pstrHostIfSetMacAddress->u8MacAddress, ETH_ALEN); + + /*prepare configuration packet*/ + strWID.u16WIDid = (u16)WID_MAC_ADDR; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = mac_buf; + strWID.s32ValueSize = ETH_ALEN; + PRINT_D(GENERIC_DBG, "mac addr = :%x:%x:%x:%x:%x:%x\n", strWID.ps8WidVal[0], strWID.ps8WidVal[1], strWID.ps8WidVal[2], strWID.ps8WidVal[3], strWID.ps8WidVal[4], strWID.ps8WidVal[5]); + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Failed to set mac address\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + + } + WILC_FREE(mac_buf); + return s32Error; +} + + +/*BugID_5213*/ +/** + * @brief Handle_GetMacAddress + * @details Getting mac address + * @param[in] void * drvHandler,tstrHostIfSetDrvHandler* pstrHostIfSetDrvHandler + * @return Error code. + * @author Amr Abdel-Moghny + * @date JAN 2013 + * @version 8.0 + */ +static s32 Handle_GetMacAddress(void *drvHandler, tstrHostIfGetMacAddress *pstrHostIfGetMacAddress) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + + /*prepare configuration packet*/ + strWID.u16WIDid = (u16)WID_MAC_ADDR; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = pstrHostIfGetMacAddress->u8MacAddress; + strWID.s32ValueSize = ETH_ALEN; + + /*Sending Cfg*/ + s32Error = SendConfigPkt(GET_CFG, &strWID, 1, false, (u32)drvHandler); + if (s32Error) { + PRINT_ER("Failed to get mac address\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + WILC_CATCH(s32Error) + { + + } + up(&hWaitResponse); + + return s32Error; +} + + +/** + * @brief Handle_CfgParam + * @details Sending config packet to firmware to set CFG params + * @param[in] tstrHostIFCfgParamAttr* strHostIFCfgParamAttr + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static s32 Handle_CfgParam(void *drvHandler, tstrHostIFCfgParamAttr *strHostIFCfgParamAttr) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWIDList[32]; + u8 u8WidCnt = 0; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + + down(&(pstrWFIDrv->gtOsCfgValuesSem)); + + + PRINT_D(HOSTINF_DBG, "Setting CFG params\n"); + + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & BSS_TYPE) { + /*----------------------------------------------------------*/ + /*Input Value: INFRASTRUCTURE = 1, */ + /* INDEPENDENT= 2, */ + /* ANY_BSS= 3 */ + /*----------------------------------------------------------*/ + /* validate input then copy>> need to check value 4 and 5 */ + if (strHostIFCfgParamAttr->pstrCfgParamVal.bss_type < 6) { + strWIDList[u8WidCnt].u16WIDid = WID_BSS_TYPE; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.bss_type; + strWIDList[u8WidCnt].enuWIDtype = WID_CHAR; + strWIDList[u8WidCnt].s32ValueSize = sizeof(char); + pstrWFIDrv->strCfgValues.bss_type = (u8)strHostIFCfgParamAttr->pstrCfgParamVal.bss_type; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & AUTH_TYPE) { + /*------------------------------------------------------*/ + /*Input Values: OPEN_SYSTEM = 0, */ + /* SHARED_KEY = 1, */ + /* ANY = 2 */ + /*------------------------------------------------------*/ + /*validate Possible values*/ + if ((strHostIFCfgParamAttr->pstrCfgParamVal.auth_type) == 1 || (strHostIFCfgParamAttr->pstrCfgParamVal.auth_type) == 2 || (strHostIFCfgParamAttr->pstrCfgParamVal.auth_type) == 5) { + strWIDList[u8WidCnt].u16WIDid = WID_AUTH_TYPE; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.auth_type; + strWIDList[u8WidCnt].enuWIDtype = WID_CHAR; + strWIDList[u8WidCnt].s32ValueSize = sizeof(char); + pstrWFIDrv->strCfgValues.auth_type = (u8)strHostIFCfgParamAttr->pstrCfgParamVal.auth_type; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & AUTHEN_TIMEOUT) { + /* range is 1 to 65535. */ + if (strHostIFCfgParamAttr->pstrCfgParamVal.auth_timeout > 0 && strHostIFCfgParamAttr->pstrCfgParamVal.auth_timeout < 65536) { + strWIDList[u8WidCnt].u16WIDid = WID_AUTH_TIMEOUT; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.auth_timeout; + strWIDList[u8WidCnt].enuWIDtype = WID_SHORT; + strWIDList[u8WidCnt].s32ValueSize = sizeof(u16); + pstrWFIDrv->strCfgValues.auth_timeout = strHostIFCfgParamAttr->pstrCfgParamVal.auth_timeout; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & POWER_MANAGEMENT) { + /*-----------------------------------------------------------*/ + /*Input Values: NO_POWERSAVE = 0, */ + /* MIN_FAST_PS = 1, */ + /* MAX_FAST_PS = 2, */ + /* MIN_PSPOLL_PS = 3, */ + /* MAX_PSPOLL_PS = 4 */ + /*----------------------------------------------------------*/ + if (strHostIFCfgParamAttr->pstrCfgParamVal.power_mgmt_mode < 5) { + strWIDList[u8WidCnt].u16WIDid = WID_POWER_MANAGEMENT; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.power_mgmt_mode; + strWIDList[u8WidCnt].enuWIDtype = WID_CHAR; + strWIDList[u8WidCnt].s32ValueSize = sizeof(char); + pstrWFIDrv->strCfgValues.power_mgmt_mode = (u8)strHostIFCfgParamAttr->pstrCfgParamVal.power_mgmt_mode; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & RETRY_SHORT) { + /* range from 1 to 256 */ + if ((strHostIFCfgParamAttr->pstrCfgParamVal.short_retry_limit > 0) && (strHostIFCfgParamAttr->pstrCfgParamVal.short_retry_limit < 256)) { + strWIDList[u8WidCnt].u16WIDid = WID_SHORT_RETRY_LIMIT; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.short_retry_limit; + strWIDList[u8WidCnt].enuWIDtype = WID_SHORT; + strWIDList[u8WidCnt].s32ValueSize = sizeof(u16); + pstrWFIDrv->strCfgValues.short_retry_limit = strHostIFCfgParamAttr->pstrCfgParamVal.short_retry_limit; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & RETRY_LONG) { + /* range from 1 to 256 */ + if ((strHostIFCfgParamAttr->pstrCfgParamVal.long_retry_limit > 0) && (strHostIFCfgParamAttr->pstrCfgParamVal.long_retry_limit < 256)) { + strWIDList[u8WidCnt].u16WIDid = WID_LONG_RETRY_LIMIT; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.long_retry_limit; + + strWIDList[u8WidCnt].enuWIDtype = WID_SHORT; + strWIDList[u8WidCnt].s32ValueSize = sizeof(u16); + pstrWFIDrv->strCfgValues.long_retry_limit = strHostIFCfgParamAttr->pstrCfgParamVal.long_retry_limit; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & FRAG_THRESHOLD) { + + if (strHostIFCfgParamAttr->pstrCfgParamVal.frag_threshold > 255 && strHostIFCfgParamAttr->pstrCfgParamVal.frag_threshold < 7937) { + strWIDList[u8WidCnt].u16WIDid = WID_FRAG_THRESHOLD; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.frag_threshold; + strWIDList[u8WidCnt].enuWIDtype = WID_SHORT; + strWIDList[u8WidCnt].s32ValueSize = sizeof(u16); + pstrWFIDrv->strCfgValues.frag_threshold = strHostIFCfgParamAttr->pstrCfgParamVal.frag_threshold; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & RTS_THRESHOLD) { + /* range 256 to 65535 */ + if (strHostIFCfgParamAttr->pstrCfgParamVal.rts_threshold > 255 && strHostIFCfgParamAttr->pstrCfgParamVal.rts_threshold < 65536) { + strWIDList[u8WidCnt].u16WIDid = WID_RTS_THRESHOLD; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.rts_threshold; + strWIDList[u8WidCnt].enuWIDtype = WID_SHORT; + strWIDList[u8WidCnt].s32ValueSize = sizeof(u16); + pstrWFIDrv->strCfgValues.rts_threshold = strHostIFCfgParamAttr->pstrCfgParamVal.rts_threshold; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & PREAMBLE) { + /*-----------------------------------------------------*/ + /*Input Values: Short= 0, */ + /* Long= 1, */ + /* Auto= 2 */ + /*------------------------------------------------------*/ + if (strHostIFCfgParamAttr->pstrCfgParamVal.preamble_type < 3) { + strWIDList[u8WidCnt].u16WIDid = WID_PREAMBLE; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.preamble_type; + strWIDList[u8WidCnt].enuWIDtype = WID_CHAR; + strWIDList[u8WidCnt].s32ValueSize = sizeof(char); + pstrWFIDrv->strCfgValues.preamble_type = strHostIFCfgParamAttr->pstrCfgParamVal.preamble_type; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & SHORT_SLOT_ALLOWED) { + if (strHostIFCfgParamAttr->pstrCfgParamVal.short_slot_allowed < 2) { + strWIDList[u8WidCnt].u16WIDid = WID_SHORT_SLOT_ALLOWED; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.short_slot_allowed; + strWIDList[u8WidCnt].enuWIDtype = WID_CHAR; + strWIDList[u8WidCnt].s32ValueSize = sizeof(char); + pstrWFIDrv->strCfgValues.short_slot_allowed = (u8)strHostIFCfgParamAttr->pstrCfgParamVal.short_slot_allowed; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & TXOP_PROT_DISABLE) { + /*Description: used to Disable RTS-CTS protection for TXOP burst*/ + /*transmission when the acknowledgement policy is No-Ack or Block-Ack */ + /* this information is useful for external supplicant */ + /*Input Values: 1 for enable and 0 for disable. */ + if (strHostIFCfgParamAttr->pstrCfgParamVal.txop_prot_disabled < 2) { + strWIDList[u8WidCnt].u16WIDid = WID_11N_TXOP_PROT_DISABLE; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.txop_prot_disabled; + strWIDList[u8WidCnt].enuWIDtype = WID_CHAR; + strWIDList[u8WidCnt].s32ValueSize = sizeof(char); + pstrWFIDrv->strCfgValues.txop_prot_disabled = (u8)strHostIFCfgParamAttr->pstrCfgParamVal.txop_prot_disabled; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & BEACON_INTERVAL) { + /* range is 1 to 65535. */ + if (strHostIFCfgParamAttr->pstrCfgParamVal.beacon_interval > 0 && strHostIFCfgParamAttr->pstrCfgParamVal.beacon_interval < 65536) { + strWIDList[u8WidCnt].u16WIDid = WID_BEACON_INTERVAL; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.beacon_interval; + strWIDList[u8WidCnt].enuWIDtype = WID_SHORT; + strWIDList[u8WidCnt].s32ValueSize = sizeof(u16); + pstrWFIDrv->strCfgValues.beacon_interval = strHostIFCfgParamAttr->pstrCfgParamVal.beacon_interval; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & DTIM_PERIOD) { + /* range is 1 to 255. */ + if (strHostIFCfgParamAttr->pstrCfgParamVal.dtim_period > 0 && strHostIFCfgParamAttr->pstrCfgParamVal.dtim_period < 256) { + strWIDList[u8WidCnt].u16WIDid = WID_DTIM_PERIOD; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.dtim_period; + strWIDList[u8WidCnt].enuWIDtype = WID_CHAR; + strWIDList[u8WidCnt].s32ValueSize = sizeof(char); + pstrWFIDrv->strCfgValues.dtim_period = strHostIFCfgParamAttr->pstrCfgParamVal.dtim_period; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & SITE_SURVEY) { + /*----------------------------------------------------------------------*/ + /*Input Values: SITE_SURVEY_1CH = 0, i.e.: currently set channel */ + /* SITE_SURVEY_ALL_CH = 1, */ + /* SITE_SURVEY_OFF = 2 */ + /*----------------------------------------------------------------------*/ + if (strHostIFCfgParamAttr->pstrCfgParamVal.site_survey_enabled < 3) { + strWIDList[u8WidCnt].u16WIDid = WID_SITE_SURVEY; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.site_survey_enabled; + strWIDList[u8WidCnt].enuWIDtype = WID_CHAR; + strWIDList[u8WidCnt].s32ValueSize = sizeof(char); + pstrWFIDrv->strCfgValues.site_survey_enabled = (u8)strHostIFCfgParamAttr->pstrCfgParamVal.site_survey_enabled; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & SITE_SURVEY_SCAN_TIME) { + /* range is 1 to 65535. */ + if (strHostIFCfgParamAttr->pstrCfgParamVal.site_survey_scan_time > 0 && strHostIFCfgParamAttr->pstrCfgParamVal.site_survey_scan_time < 65536) { + strWIDList[u8WidCnt].u16WIDid = WID_SITE_SURVEY_SCAN_TIME; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.site_survey_scan_time; + strWIDList[u8WidCnt].enuWIDtype = WID_SHORT; + strWIDList[u8WidCnt].s32ValueSize = sizeof(u16); + pstrWFIDrv->strCfgValues.site_survey_scan_time = strHostIFCfgParamAttr->pstrCfgParamVal.site_survey_scan_time; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & ACTIVE_SCANTIME) { + /* range is 1 to 65535. */ + if (strHostIFCfgParamAttr->pstrCfgParamVal.active_scan_time > 0 && strHostIFCfgParamAttr->pstrCfgParamVal.active_scan_time < 65536) { + strWIDList[u8WidCnt].u16WIDid = WID_ACTIVE_SCAN_TIME; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.active_scan_time; + strWIDList[u8WidCnt].enuWIDtype = WID_SHORT; + strWIDList[u8WidCnt].s32ValueSize = sizeof(u16); + pstrWFIDrv->strCfgValues.active_scan_time = strHostIFCfgParamAttr->pstrCfgParamVal.active_scan_time; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & PASSIVE_SCANTIME) { + /* range is 1 to 65535. */ + if (strHostIFCfgParamAttr->pstrCfgParamVal.passive_scan_time > 0 && strHostIFCfgParamAttr->pstrCfgParamVal.passive_scan_time < 65536) { + strWIDList[u8WidCnt].u16WIDid = WID_PASSIVE_SCAN_TIME; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&strHostIFCfgParamAttr->pstrCfgParamVal.passive_scan_time; + strWIDList[u8WidCnt].enuWIDtype = WID_SHORT; + strWIDList[u8WidCnt].s32ValueSize = sizeof(u16); + pstrWFIDrv->strCfgValues.passive_scan_time = strHostIFCfgParamAttr->pstrCfgParamVal.passive_scan_time; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->pstrCfgParamVal.u32SetCfgFlag & CURRENT_TX_RATE) { + CURRENT_TX_RATE_T curr_tx_rate = strHostIFCfgParamAttr->pstrCfgParamVal.curr_tx_rate; + /*----------------------------------------------------------------------*/ + /*Rates: 1 2 5.5 11 6 9 12 18 24 36 48 54 Auto */ + /*InputValues: 1 2 3 4 5 6 7 8 9 10 11 12 0 */ + /*----------------------------------------------------------------------*/ + /* validate rate */ + if (curr_tx_rate == AUTORATE || curr_tx_rate == MBPS_1 + || curr_tx_rate == MBPS_2 || curr_tx_rate == MBPS_5_5 + || curr_tx_rate == MBPS_11 || curr_tx_rate == MBPS_6 + || curr_tx_rate == MBPS_9 || curr_tx_rate == MBPS_12 + || curr_tx_rate == MBPS_18 || curr_tx_rate == MBPS_24 + || curr_tx_rate == MBPS_36 || curr_tx_rate == MBPS_48 || curr_tx_rate == MBPS_54) { + strWIDList[u8WidCnt].u16WIDid = WID_CURRENT_TX_RATE; + strWIDList[u8WidCnt].ps8WidVal = (s8 *)&curr_tx_rate; + strWIDList[u8WidCnt].enuWIDtype = WID_SHORT; + strWIDList[u8WidCnt].s32ValueSize = sizeof(u16); + pstrWFIDrv->strCfgValues.curr_tx_rate = (u8)curr_tx_rate; + } else { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + u8WidCnt++; + } + s32Error = SendConfigPkt(SET_CFG, strWIDList, u8WidCnt, false, (u32)pstrWFIDrv); + + if (s32Error) { + PRINT_ER("Error in setting CFG params\n"); + + } + WILC_CATCH(s32Error) + { + } + up(&(pstrWFIDrv->gtOsCfgValuesSem)); + return s32Error; +} + + +/** + * @brief Handle_wait_msg_q_empty + * @details this should be the last msg and then the msg Q becomes idle + * @param[in] tstrHostIFscanAttr* pstrHostIFscanAttr + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static s32 Handle_wait_msg_q_empty(void) +{ + s32 s32Error = WILC_SUCCESS; + g_wilc_initialized = 0; + up(&hWaitResponse); + return s32Error; +} + +/** + * @brief Handle_Scan + * @details Sending config packet to firmware to set the scan params + * @param[in] tstrHostIFscanAttr* pstrHostIFscanAttr + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static s32 Handle_Scan(void *drvHandler, tstrHostIFscanAttr *pstrHostIFscanAttr) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWIDList[5]; + u32 u32WidsCount = 0; + u32 i; + u8 *pu8Buffer; + u8 valuesize = 0; + u8 *pu8HdnNtwrksWidVal = NULL; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *) drvHandler; + + PRINT_D(HOSTINF_DBG, "Setting SCAN params\n"); + PRINT_D(HOSTINF_DBG, "Scanning: In [%d] state \n", pstrWFIDrv->enuHostIFstate); + + pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult = pstrHostIFscanAttr->pfScanResult; + pstrWFIDrv->strWILC_UsrScanReq.u32UserScanPvoid = pstrHostIFscanAttr->pvUserArg; + + #ifdef WILC_P2P + #endif + + if ((pstrWFIDrv->enuHostIFstate >= HOST_IF_SCANNING) && (pstrWFIDrv->enuHostIFstate < HOST_IF_CONNECTED)) { + /* here we either in HOST_IF_SCANNING, HOST_IF_WAITING_CONN_REQ or HOST_IF_WAITING_CONN_RESP */ + PRINT_D(GENERIC_DBG, "Don't scan we are already in [%d] state\n", pstrWFIDrv->enuHostIFstate); + WILC_ERRORREPORT(s32Error, WILC_BUSY); + } + + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + if (g_obtainingIP || connecting) { + PRINT_D(GENERIC_DBG, "[handle_scan]: Don't do obss scan until IP adresss is obtained\n"); + WILC_ERRORREPORT(s32Error, WILC_BUSY); + } + #endif + + PRINT_D(HOSTINF_DBG, "Setting SCAN params\n"); + + + pstrWFIDrv->strWILC_UsrScanReq.u32RcvdChCount = 0; + + /*BugID_4189*/ + strWIDList[u32WidsCount].u16WIDid = (u16)WID_SSID_PROBE_REQ; + strWIDList[u32WidsCount].enuWIDtype = WID_STR; + + for (i = 0; i < pstrHostIFscanAttr->strHiddenNetwork.u8ssidnum; i++) { + valuesize += ((pstrHostIFscanAttr->strHiddenNetwork.pstrHiddenNetworkInfo[i].u8ssidlen) + 1); + } + pu8HdnNtwrksWidVal = WILC_MALLOC(valuesize + 1); + strWIDList[u32WidsCount].ps8WidVal = pu8HdnNtwrksWidVal; + if (strWIDList[u32WidsCount].ps8WidVal != NULL) { + pu8Buffer = strWIDList[u32WidsCount].ps8WidVal; + + *pu8Buffer++ = pstrHostIFscanAttr->strHiddenNetwork.u8ssidnum; + + PRINT_D(HOSTINF_DBG, "In Handle_ProbeRequest number of ssid %d\n", pstrHostIFscanAttr->strHiddenNetwork.u8ssidnum); + + for (i = 0; i < pstrHostIFscanAttr->strHiddenNetwork.u8ssidnum; i++) { + *pu8Buffer++ = pstrHostIFscanAttr->strHiddenNetwork.pstrHiddenNetworkInfo[i].u8ssidlen; + WILC_memcpy(pu8Buffer, pstrHostIFscanAttr->strHiddenNetwork.pstrHiddenNetworkInfo[i].pu8ssid, pstrHostIFscanAttr->strHiddenNetwork.pstrHiddenNetworkInfo[i].u8ssidlen); + pu8Buffer += pstrHostIFscanAttr->strHiddenNetwork.pstrHiddenNetworkInfo[i].u8ssidlen; + } + + + + strWIDList[u32WidsCount].s32ValueSize = (s32)(valuesize + 1); + u32WidsCount++; + } + + /*filling cfg param array*/ + + /* if((pstrHostIFscanAttr->pu8IEs != NULL) && (pstrHostIFscanAttr->IEsLen != 0)) */ + { + /* IEs to be inserted in Probe Request */ + strWIDList[u32WidsCount].u16WIDid = WID_INFO_ELEMENT_PROBE; + strWIDList[u32WidsCount].enuWIDtype = WID_BIN_DATA; + strWIDList[u32WidsCount].ps8WidVal = pstrHostIFscanAttr->pu8IEs; + strWIDList[u32WidsCount].s32ValueSize = pstrHostIFscanAttr->IEsLen; + u32WidsCount++; + } + + /*Scan Type*/ + strWIDList[u32WidsCount].u16WIDid = WID_SCAN_TYPE; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(pstrHostIFscanAttr->u8ScanType)); + u32WidsCount++; + + /*list of channels to be scanned*/ + strWIDList[u32WidsCount].u16WIDid = WID_SCAN_CHANNEL_LIST; + strWIDList[u32WidsCount].enuWIDtype = WID_BIN_DATA; + + /* Bug 4648: Convert channel numbers to start from 0 not 1. */ + if (pstrHostIFscanAttr->pu8ChnlFreqList != NULL && pstrHostIFscanAttr->u8ChnlListLen > 0) { + int i; + + for (i = 0; i < pstrHostIFscanAttr->u8ChnlListLen; i++) { + if (pstrHostIFscanAttr->pu8ChnlFreqList[i] > 0) { + pstrHostIFscanAttr->pu8ChnlFreqList[i] = pstrHostIFscanAttr->pu8ChnlFreqList[i] - 1; + } + } + } + + strWIDList[u32WidsCount].ps8WidVal = pstrHostIFscanAttr->pu8ChnlFreqList; + strWIDList[u32WidsCount].s32ValueSize = pstrHostIFscanAttr->u8ChnlListLen; + u32WidsCount++; + + /*Scan Request*/ + strWIDList[u32WidsCount].u16WIDid = WID_START_SCAN_REQ; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(pstrHostIFscanAttr->u8ScanSource)); + u32WidsCount++; + + /*keep the state as is , no need to change it*/ + /* gWFiDrvHandle->enuHostIFstate = HOST_IF_SCANNING; */ + + if (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTED) { + gbScanWhileConnected = true; + } else if (pstrWFIDrv->enuHostIFstate == HOST_IF_IDLE) { + gbScanWhileConnected = false; + } + + s32Error = SendConfigPkt(SET_CFG, strWIDList, u32WidsCount, false, (u32)pstrWFIDrv); + + if (s32Error) { + PRINT_ER("Failed to send scan paramters config packet\n"); + WILC_ERRORREPORT(s32Error, s32Error); + } else { + PRINT_D(HOSTINF_DBG, "Successfully sent SCAN params config packet\n"); + } + + WILC_CATCH(s32Error) + { + WILC_TimerStop(&(pstrWFIDrv->hScanTimer), NULL); + /*if there is an ongoing scan request*/ + Handle_ScanDone(drvHandler, SCAN_EVENT_ABORTED); + } + + /* Deallocate pstrHostIFscanAttr->u8ChnlListLen which was prevoisuly allocated by the sending thread */ + if (pstrHostIFscanAttr->pu8ChnlFreqList != NULL) { + WILC_FREE(pstrHostIFscanAttr->pu8ChnlFreqList); + pstrHostIFscanAttr->pu8ChnlFreqList = NULL; + } + + /* Deallocate pstrHostIFscanAttr->pu8IEs which was previously allocated by the sending thread */ + if (pstrHostIFscanAttr->pu8IEs != NULL) { + WILC_FREE(pstrHostIFscanAttr->pu8IEs); + pstrHostIFscanAttr->pu8IEs = NULL; + } + if (pstrHostIFscanAttr->strHiddenNetwork.pstrHiddenNetworkInfo != NULL) { + WILC_FREE(pstrHostIFscanAttr->strHiddenNetwork.pstrHiddenNetworkInfo); + pstrHostIFscanAttr->strHiddenNetwork.pstrHiddenNetworkInfo = NULL; + } + + /* Deallocate pstrHostIFscanAttr->u8ChnlListLen which was prevoisuly allocated by the sending thread */ + if (pstrHostIFscanAttr->pu8ChnlFreqList != NULL) { + WILC_FREE(pstrHostIFscanAttr->pu8ChnlFreqList); + pstrHostIFscanAttr->pu8ChnlFreqList = NULL; + } + + if (pu8HdnNtwrksWidVal != NULL) { + WILC_FREE(pu8HdnNtwrksWidVal); + } + + return s32Error; +} + +/** + * @brief Handle_ScanDone + * @details Call scan notification callback function + * @param[in] NONE + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static s32 Handle_ScanDone(void *drvHandler, tenuScanEvent enuEvent) +{ + s32 s32Error = WILC_SUCCESS; + + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + + u8 u8abort_running_scan; + tstrWID strWID; + + + PRINT_D(HOSTINF_DBG, "in Handle_ScanDone()\n"); + + /*BugID_4978*/ + /*Ask FW to abort the running scan, if any*/ + if (enuEvent == SCAN_EVENT_ABORTED) { + PRINT_D(GENERIC_DBG, "Abort running scan\n"); + u8abort_running_scan = 1; + strWID.u16WIDid = (u16)WID_ABORT_RUNNING_SCAN; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = (s8 *)&u8abort_running_scan; + strWID.s32ValueSize = sizeof(char); + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error != WILC_SUCCESS) { + PRINT_ER("Failed to set abort running scan\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + WILC_CATCH(s32Error) + { + } + } + + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver handler is NULL\n"); + return s32Error; + } + + /*if there is an ongoing scan request*/ + if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { + pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult(enuEvent, NULL, + pstrWFIDrv->strWILC_UsrScanReq.u32UserScanPvoid, NULL); + /*delete current scan request*/ + pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult = NULL; + } + + return s32Error; +} + +/** + * @brief Handle_Connect + * @details Sending config packet to firmware to starting connection + * @param[in] tstrHostIFconnectAttr* pstrHostIFconnectAttr + * @return Error code. + * @author + * @date + * @version 1.0 + */ +u8 u8ConnectedSSID[6] = {0}; +static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFconnectAttr) +{ + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *) drvHandler; + s32 s32Error = WILC_SUCCESS; + tstrWID strWIDList[8]; + u32 u32WidsCount = 0, dummyval = 0; + /* char passphrase[] = "12345678"; */ + #ifndef CONNECT_DIRECT + s32 s32Err = WILC_SUCCESS; + u32 i; + u8 u8bssDscListIndex; + wid_site_survey_reslts_s *pstrSurveyResults = NULL; + #else + u8 *pu8CurrByte = NULL; + /*Bug4218: Parsing Join Param*/ + #ifdef WILC_PARSE_SCAN_IN_HOST + tstrJoinBssParam *ptstrJoinBssParam; + #endif /*WILC_PARSE_SCAN_IN_HOST*/ + + #endif + + PRINT_D(GENERIC_DBG, "Handling connect request\n"); + + #ifndef CONNECT_DIRECT + WILC_memset(gapu8RcvdSurveyResults[0], 0, MAX_SURVEY_RESULT_FRAG_SIZE); + WILC_memset(gapu8RcvdSurveyResults[1], 0, MAX_SURVEY_RESULT_FRAG_SIZE); + + + PRINT_D(HOSTINF_DBG, "Getting site survey results\n"); + s32Err = host_int_get_site_survey_results((WILC_WFIDrvHandle)pstrWFIDrv, + gapu8RcvdSurveyResults, + MAX_SURVEY_RESULT_FRAG_SIZE); + if (s32Err) { + PRINT_ER("Failed to get site survey results\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + + } + s32Err = ParseSurveyResults(gapu8RcvdSurveyResults, &pstrSurveyResults, + &pstrWFIDrv->u32SurveyResultsCount); + + + if (s32Err == WILC_SUCCESS) { + /* use the parsed info in pstrSurveyResults, then deallocate it */ + PRINT_D(HOSTINF_DBG, "Copying site survey results in global structure, then deallocate\n"); + for (i = 0; i < pstrWFIDrv->u32SurveyResultsCount; i++) { + WILC_memcpy(&pstrWFIDrv->astrSurveyResults[i], &pstrSurveyResults[i], + sizeof(wid_site_survey_reslts_s)); + } + + DeallocateSurveyResults(pstrSurveyResults); + } else { + WILC_ERRORREPORT(s32Error, WILC_FAIL); + PRINT_ER("ParseSurveyResults() Error(%d) \n", s32Err); + } + + + for (i = 0; i < pstrWFIDrv->u32SurveyResultsCount; i++) { + if (WILC_memcmp(pstrWFIDrv->astrSurveyResults[i].SSID, + pstrHostIFconnectAttr->pu8ssid, + pstrHostIFconnectAttr->ssidLen) == 0) { + PRINT_INFO(HOSTINF_DBG, "Network with required SSID is found %s\n", pstrHostIFconnectAttr->pu8ssid); + if (pstrHostIFconnectAttr->pu8bssid == NULL) { + /* BSSID is not passed from the user, so decision of matching + * is done by SSID only */ + PRINT_INFO(HOSTINF_DBG, "BSSID is not passed from the user\n"); + break; + } else { + /* BSSID is also passed from the user, so decision of matching + * should consider also this passed BSSID */ + + if (WILC_memcmp(pstrWFIDrv->astrSurveyResults[i].BSSID, + pstrHostIFconnectAttr->pu8bssid, + 6) == 0) { + PRINT_INFO(HOSTINF_DBG, "BSSID is passed from the user and matched\n"); + break; + } + } + } + } + + if (i < pstrWFIDrv->u32SurveyResultsCount) { + u8bssDscListIndex = i; + + PRINT_INFO(HOSTINF_DBG, "Connecting to network of Bss Idx %d and SSID %s and channel %d \n", + u8bssDscListIndex, pstrWFIDrv->astrSurveyResults[u8bssDscListIndex].SSID, + pstrWFIDrv->astrSurveyResults[u8bssDscListIndex].Channel); + + PRINT_INFO(HOSTINF_DBG, "Saving connection parameters in global structure\n"); + + if (pstrHostIFconnectAttr->pu8bssid != NULL) { + pstrWFIDrv->strWILC_UsrConnReq.pu8bssid = (u8 *)WILC_MALLOC(6); + WILC_memcpy(pstrWFIDrv->strWILC_UsrConnReq.pu8bssid, pstrHostIFconnectAttr->pu8bssid, 6); + } + + pstrWFIDrv->strWILC_UsrConnReq.ssidLen = pstrHostIFconnectAttr->ssidLen; + if (pstrHostIFconnectAttr->pu8ssid != NULL) { + pstrWFIDrv->strWILC_UsrConnReq.pu8ssid = (u8 *)WILC_MALLOC(pstrHostIFconnectAttr->ssidLen + 1); + WILC_memcpy(pstrWFIDrv->strWILC_UsrConnReq.pu8ssid, pstrHostIFconnectAttr->pu8ssid, + pstrHostIFconnectAttr->ssidLen); + pstrWFIDrv->strWILC_UsrConnReq.pu8ssid[pstrHostIFconnectAttr->ssidLen] = '\0'; + } + + pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen = pstrHostIFconnectAttr->IEsLen; + if (pstrHostIFconnectAttr->pu8IEs != NULL) { + pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs = (u8 *)WILC_MALLOC(pstrHostIFconnectAttr->IEsLen); + WILC_memcpy(pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs, pstrHostIFconnectAttr->pu8IEs, + pstrHostIFconnectAttr->IEsLen); + } + + pstrWFIDrv->strWILC_UsrConnReq.u8security = pstrHostIFconnectAttr->u8security; + pstrWFIDrv->strWILC_UsrConnReq.tenuAuth_type = pstrHostIFconnectAttr->tenuAuth_type; + pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult = pstrHostIFconnectAttr->pfConnectResult; + pstrWFIDrv->strWILC_UsrConnReq.u32UserConnectPvoid = pstrHostIFconnectAttr->pvUserArg; + + + /* if((gWFiDrvHandle->strWILC_UsrConnReq.pu8ConnReqIEs != NULL) && */ + /* (gWFiDrvHandle->strWILC_UsrConnReq.ConnReqIEsLen != 0)) */ + { + /* IEs to be inserted in Association Request */ + strWIDList[u32WidsCount].u16WIDid = WID_INFO_ELEMENT_ASSOCIATE; + strWIDList[u32WidsCount].enuWIDtype = WID_BIN_DATA; + strWIDList[u32WidsCount].ps8WidVal = pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs; + strWIDList[u32WidsCount].s32ValueSize = pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen; + u32WidsCount++; + } + strWIDList[u32WidsCount].u16WIDid = (u16)WID_11I_MODE; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(pstrWFIDrv->strWILC_UsrConnReq.u8security)); + u32WidsCount++; + + PRINT_INFO(HOSTINF_DBG, "Encrypt Mode = %x\n", pstrWFIDrv->strWILC_UsrConnReq.u8security); + + strWIDList[u32WidsCount].u16WIDid = (u16)WID_AUTH_TYPE; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&pstrWFIDrv->strWILC_UsrConnReq.tenuAuth_type); + u32WidsCount++; + + PRINT_INFO(HOSTINF_DBG, "Authentication Type = %x\n", pstrWFIDrv->strWILC_UsrConnReq.tenuAuth_type); + /* + * strWIDList[u32WidsCount].u16WIDid = (u16)WID_11I_PSK; + * strWIDList[u32WidsCount].enuWIDtype = WID_STR; + * strWIDList[u32WidsCount].s32ValueSize = sizeof(passphrase); + * strWIDList[u32WidsCount].ps8WidVal = (s8*)(passphrase); + * u32WidsCount++; + */ + + strWIDList[u32WidsCount].u16WIDid = (u16)WID_JOIN_REQ; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)&u8bssDscListIndex; + u32WidsCount++; + + #ifndef SIMULATION + /* A temporary workaround to avoid handling the misleading MAC_DISCONNECTED raised from the + * firmware at chip reset when processing the WIDs of the Connect Request. + * (This workaround should be removed in the future when the Chip reset of the Connect WIDs is disabled) */ + /* ////////////////////// */ + gu32WidConnRstHack = 0; + /* ////////////////////// */ + #endif + + s32Error = SendConfigPkt(SET_CFG, strWIDList, u32WidsCount, false, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Handle_Connect()] failed to send config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } else { + pstrWFIDrv->enuHostIFstate = HOST_IF_WAITING_CONN_RESP; + } + + } else { + PRINT_ER("Required BSSID not found\n"); + WILC_ERRORREPORT(s32Error, WILC_NOT_FOUND); + } + + #else + + /* if we try to connect to an already connected AP then discard the request */ + + if (WILC_memcmp(pstrHostIFconnectAttr->pu8bssid, u8ConnectedSSID, ETH_ALEN) == 0) { + + s32Error = WILC_SUCCESS; + PRINT_ER("Trying to connect to an already connected AP, Discard connect request\n"); + return s32Error; + } + + PRINT_INFO(HOSTINF_DBG, "Saving connection parameters in global structure\n"); + + /*Bug4218: Parsing Join Param*/ + #ifdef WILC_PARSE_SCAN_IN_HOST + ptstrJoinBssParam = (tstrJoinBssParam *)pstrHostIFconnectAttr->pJoinParams; + if (ptstrJoinBssParam == NULL) { + PRINT_ER("Required BSSID not found\n"); + WILC_ERRORREPORT(s32Error, WILC_NOT_FOUND); + } + #endif /*WILC_PARSE_SCAN_IN_HOST*/ + + if (pstrHostIFconnectAttr->pu8bssid != NULL) { + pstrWFIDrv->strWILC_UsrConnReq.pu8bssid = (u8 *)WILC_MALLOC(6); + WILC_memcpy(pstrWFIDrv->strWILC_UsrConnReq.pu8bssid, pstrHostIFconnectAttr->pu8bssid, 6); + } + + pstrWFIDrv->strWILC_UsrConnReq.ssidLen = pstrHostIFconnectAttr->ssidLen; + if (pstrHostIFconnectAttr->pu8ssid != NULL) { + pstrWFIDrv->strWILC_UsrConnReq.pu8ssid = (u8 *)WILC_MALLOC(pstrHostIFconnectAttr->ssidLen + 1); + WILC_memcpy(pstrWFIDrv->strWILC_UsrConnReq.pu8ssid, pstrHostIFconnectAttr->pu8ssid, + pstrHostIFconnectAttr->ssidLen); + pstrWFIDrv->strWILC_UsrConnReq.pu8ssid[pstrHostIFconnectAttr->ssidLen] = '\0'; + } + + pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen = pstrHostIFconnectAttr->IEsLen; + if (pstrHostIFconnectAttr->pu8IEs != NULL) { + pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs = (u8 *)WILC_MALLOC(pstrHostIFconnectAttr->IEsLen); + WILC_memcpy(pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs, pstrHostIFconnectAttr->pu8IEs, + pstrHostIFconnectAttr->IEsLen); + } + + pstrWFIDrv->strWILC_UsrConnReq.u8security = pstrHostIFconnectAttr->u8security; + pstrWFIDrv->strWILC_UsrConnReq.tenuAuth_type = pstrHostIFconnectAttr->tenuAuth_type; + pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult = pstrHostIFconnectAttr->pfConnectResult; + pstrWFIDrv->strWILC_UsrConnReq.u32UserConnectPvoid = pstrHostIFconnectAttr->pvUserArg; + + strWIDList[u32WidsCount].u16WIDid = WID_SUCCESS_FRAME_COUNT; + strWIDList[u32WidsCount].enuWIDtype = WID_INT; + strWIDList[u32WidsCount].s32ValueSize = sizeof(u32); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(dummyval)); + u32WidsCount++; + + strWIDList[u32WidsCount].u16WIDid = WID_RECEIVED_FRAGMENT_COUNT; + strWIDList[u32WidsCount].enuWIDtype = WID_INT; + strWIDList[u32WidsCount].s32ValueSize = sizeof(u32); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(dummyval)); + u32WidsCount++; + + strWIDList[u32WidsCount].u16WIDid = WID_FAILED_COUNT; + strWIDList[u32WidsCount].enuWIDtype = WID_INT; + strWIDList[u32WidsCount].s32ValueSize = sizeof(u32); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(dummyval)); + u32WidsCount++; + + /* if((gWFiDrvHandle->strWILC_UsrConnReq.pu8ConnReqIEs != NULL) && */ + /* (gWFiDrvHandle->strWILC_UsrConnReq.ConnReqIEsLen != 0)) */ + { + /* IEs to be inserted in Association Request */ + strWIDList[u32WidsCount].u16WIDid = WID_INFO_ELEMENT_ASSOCIATE; + strWIDList[u32WidsCount].enuWIDtype = WID_BIN_DATA; + strWIDList[u32WidsCount].ps8WidVal = pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs; + strWIDList[u32WidsCount].s32ValueSize = pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen; + u32WidsCount++; + + /*BugID_5137*/ + if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) { + + gu32FlushedInfoElemAsocSize = pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen; + gu8FlushedInfoElemAsoc = WILC_MALLOC(gu32FlushedInfoElemAsocSize); + memcpy(gu8FlushedInfoElemAsoc, pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs, + gu32FlushedInfoElemAsocSize); + } + } + strWIDList[u32WidsCount].u16WIDid = (u16)WID_11I_MODE; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(pstrWFIDrv->strWILC_UsrConnReq.u8security)); + u32WidsCount++; + + /*BugID_5137*/ + if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) + gu8Flushed11iMode = pstrWFIDrv->strWILC_UsrConnReq.u8security; + + PRINT_INFO(HOSTINF_DBG, "Encrypt Mode = %x\n", pstrWFIDrv->strWILC_UsrConnReq.u8security); + + + strWIDList[u32WidsCount].u16WIDid = (u16)WID_AUTH_TYPE; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&pstrWFIDrv->strWILC_UsrConnReq.tenuAuth_type); + u32WidsCount++; + + /*BugID_5137*/ + if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) + gu8FlushedAuthType = (u8)pstrWFIDrv->strWILC_UsrConnReq.tenuAuth_type; + + PRINT_INFO(HOSTINF_DBG, "Authentication Type = %x\n", pstrWFIDrv->strWILC_UsrConnReq.tenuAuth_type); + /* + * strWIDList[u32WidsCount].u16WIDid = (u16)WID_11I_PSK; + * strWIDList[u32WidsCount].enuWIDtype = WID_STR; + * strWIDList[u32WidsCount].s32ValueSize = sizeof(passphrase); + * strWIDList[u32WidsCount].ps8WidVal = (s8*)(passphrase); + * u32WidsCount++; + */ + + PRINT_D(HOSTINF_DBG, "Connecting to network of SSID %s on channel %d\n", + pstrWFIDrv->strWILC_UsrConnReq.pu8ssid, pstrHostIFconnectAttr->u8channel); + + +#ifndef WILC_PARSE_SCAN_IN_HOST + strWIDList[u32WidsCount].u16WIDid = (u16)WID_JOIN_REQ_EXTENDED; + strWIDList[u32WidsCount].enuWIDtype = WID_STR; + strWIDList[u32WidsCount].s32ValueSize = MAX_SSID_LEN + 7; + strWIDList[u32WidsCount].ps8WidVal = WILC_MALLOC(strWIDList[u32WidsCount].s32ValueSize); + + if (strWIDList[u32WidsCount].ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + pu8CurrByte = strWIDList[u32WidsCount].ps8WidVal; + + if (pstrHostIFconnectAttr->pu8ssid != NULL) { + WILC_memcpy(pu8CurrByte, pstrHostIFconnectAttr->pu8ssid, pstrHostIFconnectAttr->ssidLen); + pu8CurrByte[pstrHostIFconnectAttr->ssidLen] = '\0'; + } + pu8CurrByte += MAX_SSID_LEN; + if ((pstrHostIFconnectAttr->u8channel >= 1) && (pstrHostIFconnectAttr->u8channel <= 14)) { + *(pu8CurrByte++) = pstrHostIFconnectAttr->u8channel; + } else { + PRINT_ER("Channel out of range\n"); + *(pu8CurrByte++) = 0xFF; + } + if (pstrHostIFconnectAttr->pu8bssid != NULL) { + WILC_memcpy(pu8CurrByte, pstrHostIFconnectAttr->pu8bssid, 6); + } + pu8CurrByte += 6; + + /* keep the buffer at the start of the allocated pointer to use it with the free*/ + pu8CurrByte = strWIDList[u32WidsCount].ps8WidVal; + + #else + + strWIDList[u32WidsCount].u16WIDid = (u16)WID_JOIN_REQ_EXTENDED; + strWIDList[u32WidsCount].enuWIDtype = WID_STR; + + /*Sending NoA attributes during connection*/ + strWIDList[u32WidsCount].s32ValueSize = 112; /* 79; */ + strWIDList[u32WidsCount].ps8WidVal = WILC_MALLOC(strWIDList[u32WidsCount].s32ValueSize); + + /*BugID_5137*/ + if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) { + gu32FlushedJoinReqSize = strWIDList[u32WidsCount].s32ValueSize; + gu8FlushedJoinReq = WILC_MALLOC(gu32FlushedJoinReqSize); + } + if (strWIDList[u32WidsCount].ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + pu8CurrByte = strWIDList[u32WidsCount].ps8WidVal; + + + if (pstrHostIFconnectAttr->pu8ssid != NULL) { + WILC_memcpy(pu8CurrByte, pstrHostIFconnectAttr->pu8ssid, pstrHostIFconnectAttr->ssidLen); + pu8CurrByte[pstrHostIFconnectAttr->ssidLen] = '\0'; + } + pu8CurrByte += MAX_SSID_LEN; + + /* BSS type*/ + *(pu8CurrByte++) = INFRASTRUCTURE; + /* Channel*/ + if ((pstrHostIFconnectAttr->u8channel >= 1) && (pstrHostIFconnectAttr->u8channel <= 14)) { + *(pu8CurrByte++) = pstrHostIFconnectAttr->u8channel; + } else { + PRINT_ER("Channel out of range\n"); + *(pu8CurrByte++) = 0xFF; + } + /* Cap Info*/ + *(pu8CurrByte++) = (ptstrJoinBssParam->cap_info) & 0xFF; + *(pu8CurrByte++) = ((ptstrJoinBssParam->cap_info) >> 8) & 0xFF; + PRINT_D(HOSTINF_DBG, "* Cap Info %0x*\n", (*(pu8CurrByte - 2) | ((*(pu8CurrByte - 1)) << 8))); + + /* sa*/ + if (pstrHostIFconnectAttr->pu8bssid != NULL) { + WILC_memcpy(pu8CurrByte, pstrHostIFconnectAttr->pu8bssid, 6); + } + pu8CurrByte += 6; + + /* bssid*/ + if (pstrHostIFconnectAttr->pu8bssid != NULL) { + WILC_memcpy(pu8CurrByte, pstrHostIFconnectAttr->pu8bssid, 6); + } + pu8CurrByte += 6; + + /* Beacon Period*/ + *(pu8CurrByte++) = (ptstrJoinBssParam->beacon_period) & 0xFF; + *(pu8CurrByte++) = ((ptstrJoinBssParam->beacon_period) >> 8) & 0xFF; + PRINT_D(HOSTINF_DBG, "* Beacon Period %d*\n", (*(pu8CurrByte - 2) | ((*(pu8CurrByte - 1)) << 8))); + /* DTIM Period*/ + *(pu8CurrByte++) = ptstrJoinBssParam->dtim_period; + PRINT_D(HOSTINF_DBG, "* DTIM Period %d*\n", (*(pu8CurrByte - 1))); + /* Supported rates*/ + WILC_memcpy(pu8CurrByte, ptstrJoinBssParam->supp_rates, MAX_RATES_SUPPORTED + 1); + pu8CurrByte += (MAX_RATES_SUPPORTED + 1); + + /* wmm cap*/ + *(pu8CurrByte++) = ptstrJoinBssParam->wmm_cap; + PRINT_D(HOSTINF_DBG, "* wmm cap%d*\n", (*(pu8CurrByte - 1))); + /* uapsd cap*/ + *(pu8CurrByte++) = ptstrJoinBssParam->uapsd_cap; + + /* ht cap*/ + *(pu8CurrByte++) = ptstrJoinBssParam->ht_capable; + /* copy this information to the user request */ + pstrWFIDrv->strWILC_UsrConnReq.IsHTCapable = ptstrJoinBssParam->ht_capable; + + /* rsn found*/ + *(pu8CurrByte++) = ptstrJoinBssParam->rsn_found; + PRINT_D(HOSTINF_DBG, "* rsn found %d*\n", *(pu8CurrByte - 1)); + /* rsn group policy*/ + *(pu8CurrByte++) = ptstrJoinBssParam->rsn_grp_policy; + PRINT_D(HOSTINF_DBG, "* rsn group policy %0x*\n", (*(pu8CurrByte - 1))); + /* mode_802_11i*/ + *(pu8CurrByte++) = ptstrJoinBssParam->mode_802_11i; + PRINT_D(HOSTINF_DBG, "* mode_802_11i %d*\n", (*(pu8CurrByte - 1))); + /* rsn pcip policy*/ + WILC_memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_pcip_policy, sizeof(ptstrJoinBssParam->rsn_pcip_policy)); + pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_pcip_policy); + + /* rsn auth policy*/ + WILC_memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_auth_policy, sizeof(ptstrJoinBssParam->rsn_auth_policy)); + pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_auth_policy); + + /* rsn auth policy*/ + WILC_memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_cap, sizeof(ptstrJoinBssParam->rsn_cap)); + pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_cap); + + /*BugID_5137*/ + *(pu8CurrByte++) = REAL_JOIN_REQ; + + #ifdef WILC_P2P + *(pu8CurrByte++) = ptstrJoinBssParam->u8NoaEnbaled; + if (ptstrJoinBssParam->u8NoaEnbaled) { + PRINT_D(HOSTINF_DBG, "NOA present\n"); + + *(pu8CurrByte++) = (ptstrJoinBssParam->tsf) & 0xFF; + *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 8) & 0xFF; + *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 16) & 0xFF; + *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 24) & 0xFF; + + *(pu8CurrByte++) = ptstrJoinBssParam->u8Index; + + *(pu8CurrByte++) = ptstrJoinBssParam->u8OppEnable; + + if (ptstrJoinBssParam->u8OppEnable) + *(pu8CurrByte++) = ptstrJoinBssParam->u8CtWindow; + + *(pu8CurrByte++) = ptstrJoinBssParam->u8Count; + + WILC_memcpy(pu8CurrByte, ptstrJoinBssParam->au8Duration, sizeof(ptstrJoinBssParam->au8Duration)); + + pu8CurrByte += sizeof(ptstrJoinBssParam->au8Duration); + + WILC_memcpy(pu8CurrByte, ptstrJoinBssParam->au8Interval, sizeof(ptstrJoinBssParam->au8Interval)); + + pu8CurrByte += sizeof(ptstrJoinBssParam->au8Interval); + + WILC_memcpy(pu8CurrByte, ptstrJoinBssParam->au8StartTime, sizeof(ptstrJoinBssParam->au8StartTime)); + + pu8CurrByte += sizeof(ptstrJoinBssParam->au8StartTime); + + } else + PRINT_D(HOSTINF_DBG, "NOA not present\n"); + #endif + + + /* keep the buffer at the start of the allocated pointer to use it with the free*/ + pu8CurrByte = strWIDList[u32WidsCount].ps8WidVal; + + + #endif /* #ifdef WILC_PARSE_SCAN_IN_HOST*/ + u32WidsCount++; + + #ifndef SIMULATION + /* A temporary workaround to avoid handling the misleading MAC_DISCONNECTED raised from the + * firmware at chip reset when processing the WIDs of the Connect Request. + * (This workaround should be removed in the future when the Chip reset of the Connect WIDs is disabled) */ + /* ////////////////////// */ + gu32WidConnRstHack = 0; + /* ////////////////////// */ + #endif + + /*BugID_5137*/ + if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) { + memcpy(gu8FlushedJoinReq, pu8CurrByte, gu32FlushedJoinReqSize); + gu8FlushedJoinReqDrvHandler = (u32)pstrWFIDrv; + } + + PRINT_D(GENERIC_DBG, "send HOST_IF_WAITING_CONN_RESP\n"); + + if (pstrHostIFconnectAttr->pu8bssid != NULL) { + WILC_memcpy(u8ConnectedSSID, pstrHostIFconnectAttr->pu8bssid, ETH_ALEN); + + PRINT_D(GENERIC_DBG, "save Bssid = %x:%x:%x:%x:%x:%x\n", (pstrHostIFconnectAttr->pu8bssid[0]), (pstrHostIFconnectAttr->pu8bssid[1]), (pstrHostIFconnectAttr->pu8bssid[2]), (pstrHostIFconnectAttr->pu8bssid[3]), (pstrHostIFconnectAttr->pu8bssid[4]), (pstrHostIFconnectAttr->pu8bssid[5])); + PRINT_D(GENERIC_DBG, "save bssid = %x:%x:%x:%x:%x:%x\n", (u8ConnectedSSID[0]), (u8ConnectedSSID[1]), (u8ConnectedSSID[2]), (u8ConnectedSSID[3]), (u8ConnectedSSID[4]), (u8ConnectedSSID[5])); + } + + s32Error = SendConfigPkt(SET_CFG, strWIDList, u32WidsCount, false, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Handle_Connect()] failed to send config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } else { + PRINT_D(GENERIC_DBG, "set HOST_IF_WAITING_CONN_RESP\n"); + pstrWFIDrv->enuHostIFstate = HOST_IF_WAITING_CONN_RESP; + } + #endif + + WILC_CATCH(s32Error) + { + tstrConnectInfo strConnectInfo; + + WILC_TimerStop(&(pstrWFIDrv->hConnectTimer), NULL); + + PRINT_D(HOSTINF_DBG, "could not start connecting to the required network\n"); + + WILC_memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); + + if (pstrHostIFconnectAttr->pfConnectResult != NULL) { + if (pstrHostIFconnectAttr->pu8bssid != NULL) { + WILC_memcpy(strConnectInfo.au8bssid, pstrHostIFconnectAttr->pu8bssid, 6); + } + + if (pstrHostIFconnectAttr->pu8IEs != NULL) { + strConnectInfo.ReqIEsLen = pstrHostIFconnectAttr->IEsLen; + strConnectInfo.pu8ReqIEs = (u8 *)WILC_MALLOC(pstrHostIFconnectAttr->IEsLen); + WILC_memcpy(strConnectInfo.pu8ReqIEs, + pstrHostIFconnectAttr->pu8IEs, + pstrHostIFconnectAttr->IEsLen); + } + + pstrHostIFconnectAttr->pfConnectResult(CONN_DISCONN_EVENT_CONN_RESP, + &strConnectInfo, + MAC_DISCONNECTED, + NULL, + pstrHostIFconnectAttr->pvUserArg); + /*Change state to idle*/ + pstrWFIDrv->enuHostIFstate = HOST_IF_IDLE; + /* Deallocation */ + if (strConnectInfo.pu8ReqIEs != NULL) { + WILC_FREE(strConnectInfo.pu8ReqIEs); + strConnectInfo.pu8ReqIEs = NULL; + } + + } else { + PRINT_ER("Connect callback function pointer is NULL \n"); + } + } + + PRINT_D(HOSTINF_DBG, "Deallocating connection parameters\n"); + /* Deallocate pstrHostIFconnectAttr->pu8bssid which was prevoisuly allocated by the sending thread */ + if (pstrHostIFconnectAttr->pu8bssid != NULL) { + WILC_FREE(pstrHostIFconnectAttr->pu8bssid); + pstrHostIFconnectAttr->pu8bssid = NULL; + } + + /* Deallocate pstrHostIFconnectAttr->pu8ssid which was prevoisuly allocated by the sending thread */ + if (pstrHostIFconnectAttr->pu8ssid != NULL) { + WILC_FREE(pstrHostIFconnectAttr->pu8ssid); + pstrHostIFconnectAttr->pu8ssid = NULL; + } + + /* Deallocate pstrHostIFconnectAttr->pu8IEs which was prevoisuly allocated by the sending thread */ + if (pstrHostIFconnectAttr->pu8IEs != NULL) { + WILC_FREE(pstrHostIFconnectAttr->pu8IEs); + pstrHostIFconnectAttr->pu8IEs = NULL; + } + + if (pu8CurrByte != NULL) { + WILC_FREE(pu8CurrByte); + } + return s32Error; +} + +/** + * @brief Handle_FlushConnect + * @details Sending config packet to firmware to flush an old connection + * after switching FW from station one to hybrid one + * @param[in] void * drvHandler + * @return Error code. + * @author Amr Abdel-Moghny + * @date 19 DEC 2013 + * @version 8.0 + */ + +static s32 Handle_FlushConnect(void *drvHandler) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWIDList[5]; + u32 u32WidsCount = 0; + u8 *pu8CurrByte = NULL; + + + /* IEs to be inserted in Association Request */ + strWIDList[u32WidsCount].u16WIDid = WID_INFO_ELEMENT_ASSOCIATE; + strWIDList[u32WidsCount].enuWIDtype = WID_BIN_DATA; + strWIDList[u32WidsCount].ps8WidVal = gu8FlushedInfoElemAsoc; + strWIDList[u32WidsCount].s32ValueSize = gu32FlushedInfoElemAsocSize; + u32WidsCount++; + + strWIDList[u32WidsCount].u16WIDid = (u16)WID_11I_MODE; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(gu8Flushed11iMode)); + u32WidsCount++; + + + + strWIDList[u32WidsCount].u16WIDid = (u16)WID_AUTH_TYPE; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&gu8FlushedAuthType); + u32WidsCount++; + + + #ifdef WILC_PARSE_SCAN_IN_HOST + strWIDList[u32WidsCount].u16WIDid = (u16)WID_JOIN_REQ_EXTENDED; + strWIDList[u32WidsCount].enuWIDtype = WID_STR; + strWIDList[u32WidsCount].s32ValueSize = gu32FlushedJoinReqSize; + strWIDList[u32WidsCount].ps8WidVal = (s8 *)gu8FlushedJoinReq; + pu8CurrByte = strWIDList[u32WidsCount].ps8WidVal; + + pu8CurrByte += FLUSHED_BYTE_POS; + *(pu8CurrByte) = FLUSHED_JOIN_REQ; + + u32WidsCount++; + + #endif + + s32Error = SendConfigPkt(SET_CFG, strWIDList, u32WidsCount, false, gu8FlushedJoinReqDrvHandler); + if (s32Error) { + PRINT_ER("Handle_Flush_Connect()] failed to send config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } + + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief Handle_ConnectTimeout + * @details Call connect notification callback function indicating connection failure + * @param[in] NONE + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static s32 Handle_ConnectTimeout(void *drvHandler) +{ + s32 s32Error = WILC_SUCCESS; + tstrConnectInfo strConnectInfo; + tstrWID strWID; + u16 u16DummyReasonCode = 0; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *) drvHandler; + + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver handler is NULL\n"); + return s32Error; + } + + pstrWFIDrv->enuHostIFstate = HOST_IF_IDLE; + + gbScanWhileConnected = false; + + + WILC_memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); + + + /* First, we will notify the upper layer with the Connection failure {through the Connect Callback function}, + * then we will notify our firmware also with the Connection failure {through sending to it Cfg packet carrying + * WID_DISCONNECT} */ + if (pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult != NULL) { + if (pstrWFIDrv->strWILC_UsrConnReq.pu8bssid != NULL) { + WILC_memcpy(strConnectInfo.au8bssid, + pstrWFIDrv->strWILC_UsrConnReq.pu8bssid, 6); + } + + if (pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs != NULL) { + strConnectInfo.ReqIEsLen = pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen; + strConnectInfo.pu8ReqIEs = (u8 *)WILC_MALLOC(pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen); + WILC_memcpy(strConnectInfo.pu8ReqIEs, + pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs, + pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen); + } + + pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult(CONN_DISCONN_EVENT_CONN_RESP, + &strConnectInfo, + MAC_DISCONNECTED, + NULL, + pstrWFIDrv->strWILC_UsrConnReq.u32UserConnectPvoid); + + /* Deallocation of strConnectInfo.pu8ReqIEs */ + if (strConnectInfo.pu8ReqIEs != NULL) { + WILC_FREE(strConnectInfo.pu8ReqIEs); + strConnectInfo.pu8ReqIEs = NULL; + } + } else { + PRINT_ER("Connect callback function pointer is NULL \n"); + } + + /* Here we will notify our firmware also with the Connection failure {through sending to it Cfg packet carrying + * WID_DISCONNECT} */ + strWID.u16WIDid = (u16)WID_DISCONNECT; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = (s8 *)&u16DummyReasonCode; + strWID.s32ValueSize = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Sending disconnect request\n"); + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Failed to send dissconect config packet\n"); + } + + /* Deallocation of the Saved Connect Request in the global Handle */ + pstrWFIDrv->strWILC_UsrConnReq.ssidLen = 0; + if (pstrWFIDrv->strWILC_UsrConnReq.pu8ssid != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8ssid); + pstrWFIDrv->strWILC_UsrConnReq.pu8ssid = NULL; + } + + if (pstrWFIDrv->strWILC_UsrConnReq.pu8bssid != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8bssid); + pstrWFIDrv->strWILC_UsrConnReq.pu8bssid = NULL; + } + + pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen = 0; + if (pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs); + pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs = NULL; + } + + WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + /*BugID_5213*/ + /*Freeing flushed join request params on connect timeout*/ + if (gu8FlushedJoinReq != NULL && gu8FlushedJoinReqDrvHandler == (u32)drvHandler) { + WILC_FREE(gu8FlushedJoinReq); + gu8FlushedJoinReq = NULL; + } + if (gu8FlushedInfoElemAsoc != NULL && gu8FlushedJoinReqDrvHandler == (u32)drvHandler) { + WILC_FREE(gu8FlushedInfoElemAsoc); + gu8FlushedInfoElemAsoc = NULL; + } + + return s32Error; +} + +/** + * @brief Handle_RcvdNtwrkInfo + * @details Handling received network information + * @param[in] tstrRcvdNetworkInfo* pstrRcvdNetworkInfo + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static s32 Handle_RcvdNtwrkInfo(void *drvHandler, tstrRcvdNetworkInfo *pstrRcvdNetworkInfo) +{ + u32 i; + bool bNewNtwrkFound; + + + + s32 s32Error = WILC_SUCCESS; + tstrNetworkInfo *pstrNetworkInfo = NULL; + void *pJoinParams = NULL; + + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + + + bNewNtwrkFound = true; + PRINT_INFO(HOSTINF_DBG, "Handling received network info\n"); + + /*if there is a an ongoing scan request*/ + if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { + PRINT_D(HOSTINF_DBG, "State: Scanning, parsing network information received\n"); + ParseNetworkInfo(pstrRcvdNetworkInfo->pu8Buffer, &pstrNetworkInfo); + if ((pstrNetworkInfo == NULL) + || (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult == NULL)) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + /* check whether this network is discovered before */ + for (i = 0; i < pstrWFIDrv->strWILC_UsrScanReq.u32RcvdChCount; i++) { + + if ((pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[i].au8bssid != NULL) && + (pstrNetworkInfo->au8bssid != NULL)) { + if (WILC_memcmp(pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[i].au8bssid, + pstrNetworkInfo->au8bssid, 6) == 0) { + if (pstrNetworkInfo->s8rssi <= pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[i].s8rssi) { + /*we have already found this network with better rssi, so keep the old cached one and don't + * send anything to the upper layer */ + PRINT_D(HOSTINF_DBG, "Network previously discovered\n"); + goto done; + } else { + /* here the same already found network is found again but with a better rssi, so just update + * the rssi for this cached network and send this updated network to the upper layer but + * don't add a new record for it */ + pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[i].s8rssi = pstrNetworkInfo->s8rssi; + bNewNtwrkFound = false; + break; + } + } + } + } + + if (bNewNtwrkFound == true) { + /* here it is confirmed that it is a new discovered network, + * so add its record then call the User CallBack function */ + + PRINT_D(HOSTINF_DBG, "New network found\n"); + + if (pstrWFIDrv->strWILC_UsrScanReq.u32RcvdChCount < MAX_NUM_SCANNED_NETWORKS) { + pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[pstrWFIDrv->strWILC_UsrScanReq.u32RcvdChCount].s8rssi = pstrNetworkInfo->s8rssi; + + if ((pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[pstrWFIDrv->strWILC_UsrScanReq.u32RcvdChCount].au8bssid != NULL) + && (pstrNetworkInfo->au8bssid != NULL)) { + WILC_memcpy(pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[pstrWFIDrv->strWILC_UsrScanReq.u32RcvdChCount].au8bssid, + pstrNetworkInfo->au8bssid, 6); + + pstrWFIDrv->strWILC_UsrScanReq.u32RcvdChCount++; + + pstrNetworkInfo->bNewNetwork = true; + /*Bug4218: Parsing Join Param*/ + /* add new BSS to JoinBssTable */ + #ifdef WILC_PARSE_SCAN_IN_HOST + pJoinParams = host_int_ParseJoinBssParam(pstrNetworkInfo); + #endif /*WILC_PARSE_SCAN_IN_HOST*/ + + pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo, + pstrWFIDrv->strWILC_UsrScanReq.u32UserScanPvoid, + pJoinParams); + + + } + } else { + PRINT_WRN(HOSTINF_DBG, "Discovered networks exceeded max. limit \n"); + } + } else { + pstrNetworkInfo->bNewNetwork = false; + /* just call the User CallBack function to send the same discovered network with its updated RSSI */ + pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo, + pstrWFIDrv->strWILC_UsrScanReq.u32UserScanPvoid, NULL); + } + } + + + WILC_CATCH(s32Error) + { + + } + +done: + /* Deallocate pstrRcvdNetworkInfo->pu8Buffer which was prevoisuly allocated by the sending thread */ + if (pstrRcvdNetworkInfo->pu8Buffer != NULL) { + WILC_FREE(pstrRcvdNetworkInfo->pu8Buffer); + pstrRcvdNetworkInfo->pu8Buffer = NULL; + } + + /*free structure allocated*/ + if (pstrNetworkInfo != NULL) { + DeallocateNetworkInfo(pstrNetworkInfo); + pstrNetworkInfo = NULL; + } + + return s32Error; +} + +/** + * @brief Handle_RcvdGnrlAsyncInfo + * @details Handling received asynchrous general network information + * @param[in] tstrRcvdGnrlAsyncInfo* pstrRcvdGnrlAsyncInfo + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pstrRcvdGnrlAsyncInfo) +{ + /* TODO: mostafa: till now, this function just handles only the received mac status msg, */ + /* which carries only 1 WID which have WID ID = WID_STATUS */ + s32 s32Error = WILC_SUCCESS; + u8 u8MsgType = 0; + u8 u8MsgID = 0; + u16 u16MsgLen = 0; + u16 u16WidID = (u16)WID_NIL; + u8 u8WidLen = 0; + u8 u8MacStatus; + u8 u8MacStatusReasonCode; + u8 u8MacStatusAdditionalInfo; + tstrConnectInfo strConnectInfo; + tstrDisconnectNotifInfo strDisconnectNotifInfo; + s32 s32Err = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *) drvHandler; + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver handler is NULL\n"); + } + PRINT_D(GENERIC_DBG, "Current State = %d,Received state = %d\n", pstrWFIDrv->enuHostIFstate, + pstrRcvdGnrlAsyncInfo->pu8Buffer[7]); + + if ((pstrWFIDrv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) || + (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTED) || + pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { + if ((pstrRcvdGnrlAsyncInfo->pu8Buffer == NULL) || + (pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult == NULL)) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + u8MsgType = pstrRcvdGnrlAsyncInfo->pu8Buffer[0]; + + /* Check whether the received message type is 'I' */ + if ('I' != u8MsgType) { + PRINT_ER("Received Message format incorrect.\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + /* Extract message ID */ + u8MsgID = pstrRcvdGnrlAsyncInfo->pu8Buffer[1]; + + /* Extract message Length */ + u16MsgLen = MAKE_WORD16(pstrRcvdGnrlAsyncInfo->pu8Buffer[2], pstrRcvdGnrlAsyncInfo->pu8Buffer[3]); + + /* Extract WID ID [expected to be = WID_STATUS] */ + u16WidID = MAKE_WORD16(pstrRcvdGnrlAsyncInfo->pu8Buffer[4], pstrRcvdGnrlAsyncInfo->pu8Buffer[5]); + + /* Extract WID Length [expected to be = 1] */ + u8WidLen = pstrRcvdGnrlAsyncInfo->pu8Buffer[6]; + + /* get the WID value [expected to be one of two values: either MAC_CONNECTED = (1) or MAC_DISCONNECTED = (0)] */ + u8MacStatus = pstrRcvdGnrlAsyncInfo->pu8Buffer[7]; + u8MacStatusReasonCode = pstrRcvdGnrlAsyncInfo->pu8Buffer[8]; + u8MacStatusAdditionalInfo = pstrRcvdGnrlAsyncInfo->pu8Buffer[9]; + PRINT_INFO(HOSTINF_DBG, "Recieved MAC status = %d with Reason = %d , Info = %d\n", u8MacStatus, u8MacStatusReasonCode, u8MacStatusAdditionalInfo); + if (pstrWFIDrv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) { + /* our station had sent Association Request frame, so here it will get the Association Response frame then parse it */ + u32 u32RcvdAssocRespInfoLen; + tstrConnectRespInfo *pstrConnectRespInfo = NULL; + + PRINT_D(HOSTINF_DBG, "Recieved MAC status = %d with Reason = %d , Code = %d\n", u8MacStatus, u8MacStatusReasonCode, u8MacStatusAdditionalInfo); + + WILC_memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); + + if (u8MacStatus == MAC_CONNECTED) { + WILC_memset(gapu8RcvdAssocResp, 0, MAX_ASSOC_RESP_FRAME_SIZE); + + host_int_get_assoc_res_info((WILC_WFIDrvHandle)pstrWFIDrv, + gapu8RcvdAssocResp, + MAX_ASSOC_RESP_FRAME_SIZE, + &u32RcvdAssocRespInfoLen); + + PRINT_INFO(HOSTINF_DBG, "Received association response with length = %d\n", u32RcvdAssocRespInfoLen); + + if (u32RcvdAssocRespInfoLen != 0) { + + PRINT_D(HOSTINF_DBG, "Parsing association response\n"); + s32Err = ParseAssocRespInfo(gapu8RcvdAssocResp, u32RcvdAssocRespInfoLen, + &pstrConnectRespInfo); + if (s32Err) { + PRINT_ER("ParseAssocRespInfo() returned error %d \n", s32Err); + } else { + /* use the necessary parsed Info from the Received Association Response */ + strConnectInfo.u16ConnectStatus = pstrConnectRespInfo->u16ConnectStatus; + + if (strConnectInfo.u16ConnectStatus == SUCCESSFUL_STATUSCODE) { + PRINT_INFO(HOSTINF_DBG, "Association response received : Successful connection status\n"); + if (pstrConnectRespInfo->pu8RespIEs != NULL) { + strConnectInfo.u16RespIEsLen = pstrConnectRespInfo->u16RespIEsLen; + + + strConnectInfo.pu8RespIEs = (u8 *)WILC_MALLOC(pstrConnectRespInfo->u16RespIEsLen); + WILC_memcpy(strConnectInfo.pu8RespIEs, pstrConnectRespInfo->pu8RespIEs, + pstrConnectRespInfo->u16RespIEsLen); + } + } + + /* deallocate the Assoc. Resp. parsed structure as it is not needed anymore */ + if (pstrConnectRespInfo != NULL) { + DeallocateAssocRespInfo(pstrConnectRespInfo); + pstrConnectRespInfo = NULL; + } + } + } + } + + /* The station has just received mac status and it also received assoc. response which + * it was waiting for. + * So check first the matching between the received mac status and the received status code in Asoc Resp */ + if ((u8MacStatus == MAC_CONNECTED) && + (strConnectInfo.u16ConnectStatus != SUCCESSFUL_STATUSCODE)) { + PRINT_ER("Received MAC status is MAC_CONNECTED while the received status code in Asoc Resp is not SUCCESSFUL_STATUSCODE \n"); + WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + + } else if (u8MacStatus == MAC_DISCONNECTED) { + PRINT_ER("Received MAC status is MAC_DISCONNECTED\n"); + WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + } + + /* TODO: mostafa: correct BSSID should be retrieved from actual BSSID received from AP */ + /* through a structure of type tstrConnectRespInfo */ + if (pstrWFIDrv->strWILC_UsrConnReq.pu8bssid != NULL) { + PRINT_D(HOSTINF_DBG, "Retrieving actual BSSID from AP\n"); + WILC_memcpy(strConnectInfo.au8bssid, pstrWFIDrv->strWILC_UsrConnReq.pu8bssid, 6); + + if ((u8MacStatus == MAC_CONNECTED) && + (strConnectInfo.u16ConnectStatus == SUCCESSFUL_STATUSCODE)) { + WILC_memcpy(pstrWFIDrv->au8AssociatedBSSID, + pstrWFIDrv->strWILC_UsrConnReq.pu8bssid, ETH_ALEN); + } + } + + + if (pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs != NULL) { + strConnectInfo.ReqIEsLen = pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen; + strConnectInfo.pu8ReqIEs = (u8 *)WILC_MALLOC(pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen); + WILC_memcpy(strConnectInfo.pu8ReqIEs, + pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs, + pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen); + } + + + WILC_TimerStop(&(pstrWFIDrv->hConnectTimer), NULL); + pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult(CONN_DISCONN_EVENT_CONN_RESP, + &strConnectInfo, + u8MacStatus, + NULL, + pstrWFIDrv->strWILC_UsrConnReq.u32UserConnectPvoid); + + + /* if received mac status is MAC_CONNECTED and + * received status code in Asoc Resp is SUCCESSFUL_STATUSCODE, change state to CONNECTED + * else change state to IDLE */ + if ((u8MacStatus == MAC_CONNECTED) && + (strConnectInfo.u16ConnectStatus == SUCCESSFUL_STATUSCODE)) { + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + + host_int_set_power_mgmt((WILC_WFIDrvHandle)pstrWFIDrv, 0, 0); + #endif + + PRINT_D(HOSTINF_DBG, "MAC status : CONNECTED and Connect Status : Successful\n"); + pstrWFIDrv->enuHostIFstate = HOST_IF_CONNECTED; + + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + PRINT_D(GENERIC_DBG, "Obtaining an IP, Disable Scan\n"); + g_obtainingIP = true; + WILC_TimerStart(&hDuringIpTimer, 10000, NULL, NULL); + #endif + + #ifdef WILC_PARSE_SCAN_IN_HOST + /* open a BA session if possible */ + /* if(pstrWFIDrv->strWILC_UsrConnReq.IsHTCapable) */ + + #endif + + /* host_int_addBASession(pstrWFIDrv->strWILC_UsrConnReq.pu8bssid,0, */ + /* BA_SESSION_DEFAULT_BUFFER_SIZE,BA_SESSION_DEFAULT_TIMEOUT); */ + } else { + PRINT_D(HOSTINF_DBG, "MAC status : %d and Connect Status : %d\n", u8MacStatus, strConnectInfo.u16ConnectStatus); + pstrWFIDrv->enuHostIFstate = HOST_IF_IDLE; + gbScanWhileConnected = false; + } + + /* Deallocation */ + if (strConnectInfo.pu8RespIEs != NULL) { + WILC_FREE(strConnectInfo.pu8RespIEs); + strConnectInfo.pu8RespIEs = NULL; + } + + if (strConnectInfo.pu8ReqIEs != NULL) { + WILC_FREE(strConnectInfo.pu8ReqIEs); + strConnectInfo.pu8ReqIEs = NULL; + } + + + pstrWFIDrv->strWILC_UsrConnReq.ssidLen = 0; + if (pstrWFIDrv->strWILC_UsrConnReq.pu8ssid != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8ssid); + pstrWFIDrv->strWILC_UsrConnReq.pu8ssid = NULL; + } + + if (pstrWFIDrv->strWILC_UsrConnReq.pu8bssid != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8bssid); + pstrWFIDrv->strWILC_UsrConnReq.pu8bssid = NULL; + } + + pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen = 0; + if (pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs); + pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs = NULL; + } + + } else if ((u8MacStatus == MAC_DISCONNECTED) && + (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTED)) { + /* Disassociation or Deauthentication frame has been received */ + PRINT_D(HOSTINF_DBG, "Received MAC_DISCONNECTED from the FW\n"); + + WILC_memset(&strDisconnectNotifInfo, 0, sizeof(tstrDisconnectNotifInfo)); + + if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { + PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running OBSS Scan >> \n\n"); + WILC_TimerStop(&(pstrWFIDrv->hScanTimer), NULL); + Handle_ScanDone((void *)pstrWFIDrv, SCAN_EVENT_ABORTED); + } + + strDisconnectNotifInfo.u16reason = 0; + strDisconnectNotifInfo.ie = NULL; + strDisconnectNotifInfo.ie_len = 0; + + if (pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult != NULL) { + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + + g_obtainingIP = false; + host_int_set_power_mgmt((WILC_WFIDrvHandle)pstrWFIDrv, 0, 0); + #endif + + pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult(CONN_DISCONN_EVENT_DISCONN_NOTIF, + NULL, + 0, + &strDisconnectNotifInfo, + pstrWFIDrv->strWILC_UsrConnReq.u32UserConnectPvoid); + + } else { + PRINT_ER("Connect result callback function is NULL \n"); + } + + WILC_memset(pstrWFIDrv->au8AssociatedBSSID, 0, ETH_ALEN); + + + /* Deallocation */ + + /* if Information Elements were retrieved from the Received deauth/disassoc frame, then they + * should be deallocated here */ + /* + * if(strDisconnectNotifInfo.ie != NULL) + * { + * WILC_FREE(strDisconnectNotifInfo.ie); + * strDisconnectNotifInfo.ie = NULL; + * } + */ + + pstrWFIDrv->strWILC_UsrConnReq.ssidLen = 0; + if (pstrWFIDrv->strWILC_UsrConnReq.pu8ssid != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8ssid); + pstrWFIDrv->strWILC_UsrConnReq.pu8ssid = NULL; + } + + if (pstrWFIDrv->strWILC_UsrConnReq.pu8bssid != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8bssid); + pstrWFIDrv->strWILC_UsrConnReq.pu8bssid = NULL; + } + + pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen = 0; + if (pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs); + pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs = NULL; + } + + /*BugID_5213*/ + /*Freeing flushed join request params on receiving*/ + /*MAC_DISCONNECTED while connected*/ + if (gu8FlushedJoinReq != NULL && gu8FlushedJoinReqDrvHandler == (u32)drvHandler) { + WILC_FREE(gu8FlushedJoinReq); + gu8FlushedJoinReq = NULL; + } + if (gu8FlushedInfoElemAsoc != NULL && gu8FlushedJoinReqDrvHandler == (u32)drvHandler) { + WILC_FREE(gu8FlushedInfoElemAsoc); + gu8FlushedInfoElemAsoc = NULL; + } + + pstrWFIDrv->enuHostIFstate = HOST_IF_IDLE; + gbScanWhileConnected = false; + + } else if ((u8MacStatus == MAC_DISCONNECTED) && + (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult != NULL)) { + PRINT_D(HOSTINF_DBG, "Received MAC_DISCONNECTED from the FW while scanning\n"); + PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running Scan >> \n\n"); + /*Abort the running scan*/ + WILC_TimerStop(&(pstrWFIDrv->hScanTimer), NULL); + if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { + Handle_ScanDone((void *)pstrWFIDrv, SCAN_EVENT_ABORTED); + + } + } + + } + + WILC_CATCH(s32Error) + { + + } + + /* Deallocate pstrRcvdGnrlAsyncInfo->pu8Buffer which was prevoisuly allocated by the sending thread */ + if (pstrRcvdGnrlAsyncInfo->pu8Buffer != NULL) { + WILC_FREE(pstrRcvdGnrlAsyncInfo->pu8Buffer); + pstrRcvdGnrlAsyncInfo->pu8Buffer = NULL; + } + + return s32Error; +} + +/** + * @brief Handle_Key + * @details Sending config packet to firmware to set key + * @param[in] tstrHostIFkeyAttr* pstrHostIFkeyAttr + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static int Handle_Key(void *drvHandler, tstrHostIFkeyAttr *pstrHostIFkeyAttr) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + #ifdef WILC_AP_EXTERNAL_MLME + tstrWID strWIDList[5]; + #endif + u8 i; + u8 *pu8keybuf; + s8 s8idxarray[1]; + s8 ret = 0; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + + switch (pstrHostIFkeyAttr->enuKeyType) { + + + case WEP: + +#ifdef WILC_AP_EXTERNAL_MLME + if (pstrHostIFkeyAttr->u8KeyAction & ADDKEY_AP) { + + PRINT_D(HOSTINF_DBG, "Handling WEP key\n"); + PRINT_D(GENERIC_DBG, "ID Hostint is %d\n", (pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8Wepidx)); + strWIDList[0].u16WIDid = (u16)WID_11I_MODE; + strWIDList[0].enuWIDtype = WID_CHAR; + strWIDList[0].s32ValueSize = sizeof(char); + strWIDList[0].ps8WidVal = (s8 *)(&(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8mode)); + + strWIDList[1].u16WIDid = WID_AUTH_TYPE; + strWIDList[1].enuWIDtype = WID_CHAR; + strWIDList[1].s32ValueSize = sizeof(char); + strWIDList[1].ps8WidVal = (s8 *)(&(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.tenuAuth_type)); + + strWIDList[2].u16WIDid = (u16)WID_KEY_ID; + strWIDList[2].enuWIDtype = WID_CHAR; + + strWIDList[2].ps8WidVal = (s8 *)(&(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8Wepidx)); + strWIDList[2].s32ValueSize = sizeof(char); + + + pu8keybuf = (u8 *)WILC_MALLOC(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8WepKeylen); + + + if (pu8keybuf == NULL) { + PRINT_ER("No buffer to send Key\n"); + return -1; + } + + WILC_memcpy(pu8keybuf, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.pu8WepKey, + pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8WepKeylen); + + + WILC_FREE(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.pu8WepKey); + + strWIDList[3].u16WIDid = (u16)WID_WEP_KEY_VALUE; + strWIDList[3].enuWIDtype = WID_STR; + strWIDList[3].s32ValueSize = pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8WepKeylen; + strWIDList[3].ps8WidVal = (s8 *)pu8keybuf; + + + s32Error = SendConfigPkt(SET_CFG, strWIDList, 4, true, (u32)pstrWFIDrv); + WILC_FREE(pu8keybuf); + + + } +#endif + + if (pstrHostIFkeyAttr->u8KeyAction & ADDKEY) { + PRINT_D(HOSTINF_DBG, "Handling WEP key\n"); + pu8keybuf = (u8 *)WILC_MALLOC(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8WepKeylen + 2); + if (pu8keybuf == NULL) { + PRINT_ER("No buffer to send Key\n"); + return -1; + } + pu8keybuf[0] = pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8Wepidx; + + WILC_memcpy(pu8keybuf + 1, &pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8WepKeylen, 1); + + WILC_memcpy(pu8keybuf + 2, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.pu8WepKey, + pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8WepKeylen); + + WILC_FREE(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.pu8WepKey); + + strWID.u16WIDid = (u16)WID_ADD_WEP_KEY; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = (s8 *)pu8keybuf; + strWID.s32ValueSize = pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8WepKeylen + 2; + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + WILC_FREE(pu8keybuf); + } else if (pstrHostIFkeyAttr->u8KeyAction & REMOVEKEY) { + + PRINT_D(HOSTINF_DBG, "Removing key\n"); + strWID.u16WIDid = (u16)WID_REMOVE_WEP_KEY; + strWID.enuWIDtype = WID_STR; + + s8idxarray[0] = (s8)pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8Wepidx; + strWID.ps8WidVal = s8idxarray; + strWID.s32ValueSize = 1; + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + } else { + strWID.u16WIDid = (u16)WID_KEY_ID; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = (s8 *)(&(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwepAttr.u8Wepidx)); + strWID.s32ValueSize = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Setting default key index\n"); + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + } + up(&(pstrWFIDrv->hSemTestKeyBlock)); + break; + + case WPARxGtk: + #ifdef WILC_AP_EXTERNAL_MLME + if (pstrHostIFkeyAttr->u8KeyAction & ADDKEY_AP) { + pu8keybuf = (u8 *)WILC_MALLOC(RX_MIC_KEY_MSG_LEN); + if (pu8keybuf == NULL) { + PRINT_ER("No buffer to send RxGTK Key\n"); + ret = -1; + goto _WPARxGtk_end_case_; + } + + WILC_memset(pu8keybuf, 0, RX_MIC_KEY_MSG_LEN); + + + /*|----------------------------------------------------------------------------| + * |Sta Address | Key RSC | KeyID | Key Length | Temporal Key | Rx Michael Key | + * |------------|---------|-------|------------|---------------|----------------| + | 6 bytes | 8 byte |1 byte | 1 byte | 16 bytes | 8 bytes |*/ + + + + if (pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8seq != NULL) + WILC_memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8seq, 8); + + + WILC_memcpy(pu8keybuf + 14, &pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8keyidx, 1); + + WILC_memcpy(pu8keybuf + 15, &pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Keylen, 1); + + WILC_memcpy(pu8keybuf + 16, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8key, + pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Keylen); + /* pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Ciphermode = 0X51; */ + strWIDList[0].u16WIDid = (u16)WID_11I_MODE; + strWIDList[0].enuWIDtype = WID_CHAR; + strWIDList[0].s32ValueSize = sizeof(char); + strWIDList[0].ps8WidVal = (s8 *)(&(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Ciphermode)); + + strWIDList[1].u16WIDid = (u16)WID_ADD_RX_GTK; + strWIDList[1].enuWIDtype = WID_STR; + strWIDList[1].ps8WidVal = (s8 *)pu8keybuf; + strWIDList[1].s32ValueSize = RX_MIC_KEY_MSG_LEN; + + s32Error = SendConfigPkt(SET_CFG, strWIDList, 2, true, (u32)pstrWFIDrv); + + WILC_FREE(pu8keybuf); + + /* ////////////////////////// */ + up(&(pstrWFIDrv->hSemTestKeyBlock)); + /* ///////////////////////// */ + } + + #endif + if (pstrHostIFkeyAttr->u8KeyAction & ADDKEY) { + PRINT_D(HOSTINF_DBG, "Handling group key(Rx) function\n"); + + pu8keybuf = (u8 *)WILC_MALLOC(RX_MIC_KEY_MSG_LEN); + if (pu8keybuf == NULL) { + PRINT_ER("No buffer to send RxGTK Key\n"); + ret = -1; + goto _WPARxGtk_end_case_; + } + + WILC_memset(pu8keybuf, 0, RX_MIC_KEY_MSG_LEN); + + + /*|----------------------------------------------------------------------------| + * |Sta Address | Key RSC | KeyID | Key Length | Temporal Key | Rx Michael Key | + * |------------|---------|-------|------------|---------------|----------------| + | 6 bytes | 8 byte |1 byte | 1 byte | 16 bytes | 8 bytes |*/ + + if (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTED) { + WILC_memcpy(pu8keybuf, pstrWFIDrv->au8AssociatedBSSID, ETH_ALEN); + } else { + PRINT_ER("Couldn't handle WPARxGtk while enuHostIFstate is not HOST_IF_CONNECTED \n"); + } + + WILC_memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8seq, 8); + + WILC_memcpy(pu8keybuf + 14, &pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8keyidx, 1); + + WILC_memcpy(pu8keybuf + 15, &pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Keylen, 1); + WILC_memcpy(pu8keybuf + 16, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8key, + pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Keylen); + + strWID.u16WIDid = (u16)WID_ADD_RX_GTK; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = (s8 *)pu8keybuf; + strWID.s32ValueSize = RX_MIC_KEY_MSG_LEN; + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + + WILC_FREE(pu8keybuf); + + /* ////////////////////////// */ + up(&(pstrWFIDrv->hSemTestKeyBlock)); + /* ///////////////////////// */ + } +_WPARxGtk_end_case_: + WILC_FREE(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8key); + WILC_FREE(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8seq); + if (ret == -1) + return ret; + + break; + + case WPAPtk: + #ifdef WILC_AP_EXTERNAL_MLME + if (pstrHostIFkeyAttr->u8KeyAction & ADDKEY_AP) { + + + pu8keybuf = (u8 *)WILC_MALLOC(PTK_KEY_MSG_LEN + 1); + + + + if (pu8keybuf == NULL) { + PRINT_ER("No buffer to send PTK Key\n"); + ret = -1; + goto _WPAPtk_end_case_; + + } + + /*|-----------------------------------------------------------------------------| + * |Station address | keyidx |Key Length |Temporal Key | Rx Michael Key |Tx Michael Key | + * |----------------|------------ |--------------|----------------|---------------| + | 6 bytes | 1 byte | 1byte | 16 bytes | 8 bytes | 8 bytes | + |-----------------------------------------------------------------------------|*/ + + WILC_memcpy(pu8keybuf, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8macaddr, 6); /*1 bytes Key Length */ + + WILC_memcpy(pu8keybuf + 6, &pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8keyidx, 1); + WILC_memcpy(pu8keybuf + 7, &pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Keylen, 1); + /*16 byte TK*/ + WILC_memcpy(pu8keybuf + 8, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8key, + pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Keylen); + + + strWIDList[0].u16WIDid = (u16)WID_11I_MODE; + strWIDList[0].enuWIDtype = WID_CHAR; + strWIDList[0].s32ValueSize = sizeof(char); + strWIDList[0].ps8WidVal = (s8 *)(&(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Ciphermode)); + + strWIDList[1].u16WIDid = (u16)WID_ADD_PTK; + strWIDList[1].enuWIDtype = WID_STR; + strWIDList[1].ps8WidVal = (s8 *)pu8keybuf; + strWIDList[1].s32ValueSize = PTK_KEY_MSG_LEN + 1; + + s32Error = SendConfigPkt(SET_CFG, strWIDList, 2, true, (u32)pstrWFIDrv); + WILC_FREE(pu8keybuf); + + /* ////////////////////////// */ + up(&(pstrWFIDrv->hSemTestKeyBlock)); + /* ///////////////////////// */ + } + #endif + if (pstrHostIFkeyAttr->u8KeyAction & ADDKEY) { + + + pu8keybuf = (u8 *)WILC_MALLOC(PTK_KEY_MSG_LEN); + + + + if (pu8keybuf == NULL) { + PRINT_ER("No buffer to send PTK Key\n"); + ret = -1; + goto _WPAPtk_end_case_; + + } + + /*|-----------------------------------------------------------------------------| + * |Station address | Key Length | Temporal Key | Rx Michael Key |Tx Michael Key | + * |----------------|------------|--------------|----------------|---------------| + | 6 bytes | 1byte | 16 bytes | 8 bytes | 8 bytes | + |-----------------------------------------------------------------------------|*/ + + WILC_memcpy(pu8keybuf, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8macaddr, 6); /*1 bytes Key Length */ + + WILC_memcpy(pu8keybuf + 6, &pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Keylen, 1); + /*16 byte TK*/ + WILC_memcpy(pu8keybuf + 7, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8key, + pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.u8Keylen); + + + strWID.u16WIDid = (u16)WID_ADD_PTK; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = (s8 *)pu8keybuf; + strWID.s32ValueSize = PTK_KEY_MSG_LEN; + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + WILC_FREE(pu8keybuf); + + /* ////////////////////////// */ + up(&(pstrWFIDrv->hSemTestKeyBlock)); + /* ///////////////////////// */ + } + +_WPAPtk_end_case_: + WILC_FREE(pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8key); + if (ret == -1) + return ret; + + break; + + + case PMKSA: + + PRINT_D(HOSTINF_DBG, "Handling PMKSA key\n"); + + pu8keybuf = (u8 *)WILC_MALLOC((pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFpmkidAttr.numpmkid * PMKSA_KEY_LEN) + 1); + if (pu8keybuf == NULL) { + PRINT_ER("No buffer to send PMKSA Key\n"); + return -1; + } + + pu8keybuf[0] = pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFpmkidAttr.numpmkid; + + for (i = 0; i < pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFpmkidAttr.numpmkid; i++) { + + WILC_memcpy(pu8keybuf + ((PMKSA_KEY_LEN * i) + 1), pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFpmkidAttr.pmkidlist[i].bssid, ETH_ALEN); + WILC_memcpy(pu8keybuf + ((PMKSA_KEY_LEN * i) + ETH_ALEN + 1), pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFpmkidAttr.pmkidlist[i].pmkid, PMKID_LEN); + } + + strWID.u16WIDid = (u16)WID_PMKID_INFO; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = (s8 *)pu8keybuf; + strWID.s32ValueSize = (pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFpmkidAttr.numpmkid * PMKSA_KEY_LEN) + 1; + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + + WILC_FREE(pu8keybuf); + break; + } + + if (s32Error) + PRINT_ER("Failed to send key config packet\n"); + + + return s32Error; +} + + +/** + * @brief Handle_Disconnect + * @details Sending config packet to firmware to disconnect + * @param[in] NONE + * @return NONE + * @author + * @date + * @version 1.0 + */ +static void Handle_Disconnect(void *drvHandler) +{ + tstrWID strWID; + + s32 s32Error = WILC_SUCCESS; + u16 u16DummyReasonCode = 0; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + + strWID.u16WIDid = (u16)WID_DISCONNECT; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = (s8 *)&u16DummyReasonCode; + strWID.s32ValueSize = sizeof(char); + + + + PRINT_D(HOSTINF_DBG, "Sending disconnect request\n"); + + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + + g_obtainingIP = false; + host_int_set_power_mgmt((WILC_WFIDrvHandle)pstrWFIDrv, 0, 0); + #endif + + WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)pstrWFIDrv); + + if (s32Error) { + PRINT_ER("Failed to send dissconect config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } else { + tstrDisconnectNotifInfo strDisconnectNotifInfo; + + WILC_memset(&strDisconnectNotifInfo, 0, sizeof(tstrDisconnectNotifInfo)); + + strDisconnectNotifInfo.u16reason = 0; + strDisconnectNotifInfo.ie = NULL; + strDisconnectNotifInfo.ie_len = 0; + + if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { + WILC_TimerStop(&(pstrWFIDrv->hScanTimer), NULL); + pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult(SCAN_EVENT_ABORTED, NULL, + pstrWFIDrv->strWILC_UsrScanReq.u32UserScanPvoid, NULL); + + pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult = NULL; + } + + if (pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult != NULL) { + + /*BugID_5193*/ + /*Stop connect timer, if connection in progress*/ + if (pstrWFIDrv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) { + PRINT_D(HOSTINF_DBG, "Upper layer requested termination of connection\n"); + WILC_TimerStop(&(pstrWFIDrv->hConnectTimer), NULL); + } + + pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL, + 0, &strDisconnectNotifInfo, pstrWFIDrv->strWILC_UsrConnReq.u32UserConnectPvoid); + } else { + PRINT_ER("strWILC_UsrConnReq.pfUserConnectResult = NULL \n"); + } + + gbScanWhileConnected = false; + + pstrWFIDrv->enuHostIFstate = HOST_IF_IDLE; + + WILC_memset(pstrWFIDrv->au8AssociatedBSSID, 0, ETH_ALEN); + + + /* Deallocation */ + pstrWFIDrv->strWILC_UsrConnReq.ssidLen = 0; + if (pstrWFIDrv->strWILC_UsrConnReq.pu8ssid != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8ssid); + pstrWFIDrv->strWILC_UsrConnReq.pu8ssid = NULL; + } + + if (pstrWFIDrv->strWILC_UsrConnReq.pu8bssid != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8bssid); + pstrWFIDrv->strWILC_UsrConnReq.pu8bssid = NULL; + } + + pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen = 0; + if (pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs != NULL) { + WILC_FREE(pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs); + pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs = NULL; + } + + + /*BugID_5137*/ + if (gu8FlushedJoinReq != NULL && gu8FlushedJoinReqDrvHandler == (u32)drvHandler) { + WILC_FREE(gu8FlushedJoinReq); + gu8FlushedJoinReq = NULL; + } + if (gu8FlushedInfoElemAsoc != NULL && gu8FlushedJoinReqDrvHandler == (u32)drvHandler) { + WILC_FREE(gu8FlushedInfoElemAsoc); + gu8FlushedInfoElemAsoc = NULL; + } + + } + + WILC_CATCH(s32Error) + { + + } + + /* ////////////////////////// */ + up(&(pstrWFIDrv->hSemTestDisconnectBlock)); + /* ///////////////////////// */ + +} + + +void resolve_disconnect_aberration(void *drvHandler) +{ + tstrWILC_WFIDrv *pstrWFIDrv; + + pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + if (pstrWFIDrv == NULL) + return; + if ((pstrWFIDrv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) || (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTING)) { + PRINT_D(HOSTINF_DBG, "\n\n<< correcting Supplicant state machine >>\n\n"); + host_int_disconnect((WILC_WFIDrvHandle)pstrWFIDrv, 1); + } +} +static s32 Switch_Log_Terminal(void *drvHandler) +{ + + + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + static char dummy = 9; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + strWID.u16WIDid = (u16)WID_LOGTerminal_Switch; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = &dummy; + strWID.s32ValueSize = sizeof(char); + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + + + if (s32Error) { + PRINT_D(HOSTINF_DBG, "Failed to switch log terminal\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } else { + PRINT_INFO(HOSTINF_DBG, "MAC address set :: \n"); + + + } + + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief Handle_GetChnl + * @details Sending config packet to get channel + * @param[in] NONE + * @return NONE + * + * @author + * @date + * @version 1.0 + */ +static s32 Handle_GetChnl(void *drvHandler) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + strWID.u16WIDid = (u16)WID_CURRENT_CHANNEL; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = (s8 *)&gu8Chnl; + strWID.s32ValueSize = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Getting channel value\n"); + + s32Error = SendConfigPkt(GET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + /*get the value by searching the local copy*/ + if (s32Error) { + PRINT_ER("Failed to get channel number\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + + WILC_CATCH(s32Error) + { + + } + up(&(pstrWFIDrv->hSemGetCHNL)); + + return s32Error; + + + +} + + +/** + * @brief Handle_GetRssi + * @details Sending config packet to get RSSI + * @param[in] NONE + * @return NONE + * @author + * @date + * @version 1.0 + */ +static void Handle_GetRssi(void *drvHandler) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + strWID.u16WIDid = (u16)WID_RSSI; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = &gs8Rssi; + strWID.s32ValueSize = sizeof(char); + + /*Sending Cfg*/ + PRINT_D(HOSTINF_DBG, "Getting RSSI value\n"); + + s32Error = SendConfigPkt(GET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Failed to get RSSI value\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + + } + up(&(pstrWFIDrv->hSemGetRSSI)); + + +} + + +static void Handle_GetLinkspeed(void *drvHandler) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + gs8lnkspd = 0; + + strWID.u16WIDid = (u16)WID_LINKSPEED; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = &gs8lnkspd; + strWID.s32ValueSize = sizeof(char); + /*Sending Cfg*/ + PRINT_D(HOSTINF_DBG, "Getting LINKSPEED value\n"); + + s32Error = SendConfigPkt(GET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Failed to get LINKSPEED value\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + + } + up(&(pstrWFIDrv->hSemGetLINKSPEED)); + + +} + +s32 Handle_GetStatistics(void *drvHandler, tstrStatistics *pstrStatistics) +{ + tstrWID strWIDList[5]; + uint32_t u32WidsCount = 0, s32Error = 0; + + strWIDList[u32WidsCount].u16WIDid = WID_LINKSPEED; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(pstrStatistics->u8LinkSpeed)); + u32WidsCount++; + + strWIDList[u32WidsCount].u16WIDid = WID_RSSI; + strWIDList[u32WidsCount].enuWIDtype = WID_CHAR; + strWIDList[u32WidsCount].s32ValueSize = sizeof(char); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(pstrStatistics->s8RSSI)); + u32WidsCount++; + + strWIDList[u32WidsCount].u16WIDid = WID_SUCCESS_FRAME_COUNT; + strWIDList[u32WidsCount].enuWIDtype = WID_INT; + strWIDList[u32WidsCount].s32ValueSize = sizeof(u32); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(pstrStatistics->u32TxCount)); + u32WidsCount++; + + strWIDList[u32WidsCount].u16WIDid = WID_RECEIVED_FRAGMENT_COUNT; + strWIDList[u32WidsCount].enuWIDtype = WID_INT; + strWIDList[u32WidsCount].s32ValueSize = sizeof(u32); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(pstrStatistics->u32RxCount)); + u32WidsCount++; + + strWIDList[u32WidsCount].u16WIDid = WID_FAILED_COUNT; + strWIDList[u32WidsCount].enuWIDtype = WID_INT; + strWIDList[u32WidsCount].s32ValueSize = sizeof(u32); + strWIDList[u32WidsCount].ps8WidVal = (s8 *)(&(pstrStatistics->u32TxFailureCount)); + u32WidsCount++; + + s32Error = SendConfigPkt(GET_CFG, strWIDList, u32WidsCount, false, (u32)drvHandler); + + if (s32Error) { + PRINT_ER("Failed to send scan paramters config packet\n"); + /* WILC_ERRORREPORT(s32Error, s32Error); */ + } + up(&hWaitResponse); + return 0; + +} + + +#ifdef WILC_AP_EXTERNAL_MLME + + +/** + * @brief Handle_Get_InActiveTime + * @details Sending config packet to set mac adddress for station and + * get inactive time + * @param[in] NONE + * @return NONE + * + * @author + * @date + * @version 1.0 + */ +static s32 Handle_Get_InActiveTime(void *drvHandler, tstrHostIfStaInactiveT *strHostIfStaInactiveT) +{ + + s32 s32Error = WILC_SUCCESS; + u8 *stamac; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + + strWID.u16WIDid = (u16)WID_SET_STA_MAC_INACTIVE_TIME; + strWID.enuWIDtype = WID_STR; + strWID.s32ValueSize = ETH_ALEN; + strWID.ps8WidVal = (u8 *)WILC_MALLOC(strWID.s32ValueSize); + + + stamac = strWID.ps8WidVal; + WILC_memcpy(stamac, strHostIfStaInactiveT->mac, ETH_ALEN); + + + PRINT_D(CFG80211_DBG, "SETING STA inactive time\n"); + + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + /*get the value by searching the local copy*/ + if (s32Error) { + PRINT_ER("Failed to SET incative time\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + + strWID.u16WIDid = (u16)WID_GET_INACTIVE_TIME; + strWID.enuWIDtype = WID_INT; + strWID.ps8WidVal = (s8 *)&gu32InactiveTime; + strWID.s32ValueSize = sizeof(u32); + + + s32Error = SendConfigPkt(GET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + /*get the value by searching the local copy*/ + if (s32Error) { + PRINT_ER("Failed to get incative time\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + + PRINT_D(CFG80211_DBG, "Getting inactive time : %d\n", gu32InactiveTime); + + up(&(pstrWFIDrv->hSemInactiveTime)); + WILC_CATCH(s32Error) + { + + } + + + return s32Error; + + + +} + + +/** + * @brief Handle_AddBeacon + * @details Sending config packet to add beacon + * @param[in] tstrHostIFSetBeacon* pstrSetBeaconParam + * @return NONE + * @author + * @date + * @version 1.0 + */ +static void Handle_AddBeacon(void *drvHandler, tstrHostIFSetBeacon *pstrSetBeaconParam) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + u8 *pu8CurrByte; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + PRINT_D(HOSTINF_DBG, "Adding BEACON\n"); + + strWID.u16WIDid = (u16)WID_ADD_BEACON; + strWID.enuWIDtype = WID_BIN; + strWID.s32ValueSize = pstrSetBeaconParam->u32HeadLen + pstrSetBeaconParam->u32TailLen + 16; + strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); + if (strWID.ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + pu8CurrByte = strWID.ps8WidVal; + *pu8CurrByte++ = (pstrSetBeaconParam->u32Interval & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32Interval >> 8) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32Interval >> 16) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32Interval >> 24) & 0xFF); + + *pu8CurrByte++ = (pstrSetBeaconParam->u32DTIMPeriod & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32DTIMPeriod >> 8) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32DTIMPeriod >> 16) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32DTIMPeriod >> 24) & 0xFF); + + *pu8CurrByte++ = (pstrSetBeaconParam->u32HeadLen & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32HeadLen >> 8) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32HeadLen >> 16) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32HeadLen >> 24) & 0xFF); + + memcpy(pu8CurrByte, pstrSetBeaconParam->pu8Head, pstrSetBeaconParam->u32HeadLen); + pu8CurrByte += pstrSetBeaconParam->u32HeadLen; + + *pu8CurrByte++ = (pstrSetBeaconParam->u32TailLen & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32TailLen >> 8) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32TailLen >> 16) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->u32TailLen >> 24) & 0xFF); + + /* Bug 4599 : if tail length = 0 skip copying */ + if (pstrSetBeaconParam->pu8Tail > 0) + memcpy(pu8CurrByte, pstrSetBeaconParam->pu8Tail, pstrSetBeaconParam->u32TailLen); + pu8CurrByte += pstrSetBeaconParam->u32TailLen; + + + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Failed to send add beacon config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + } + WILC_FREE_IF_TRUE(strWID.ps8WidVal); + WILC_FREE_IF_TRUE(pstrSetBeaconParam->pu8Head); + WILC_FREE_IF_TRUE(pstrSetBeaconParam->pu8Tail); +} + + +/** + * @brief Handle_AddBeacon + * @details Sending config packet to delete beacon + * @param[in] tstrHostIFDelBeacon* pstrDelBeacon + * @return NONE + * @author + * @date + * @version 1.0 + */ +static void Handle_DelBeacon(void *drvHandler, tstrHostIFDelBeacon *pstrDelBeacon) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + u8 *pu8CurrByte; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + strWID.u16WIDid = (u16)WID_DEL_BEACON; + strWID.enuWIDtype = WID_CHAR; + strWID.s32ValueSize = sizeof(char); + strWID.ps8WidVal = &gu8DelBcn; + + if (strWID.ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + pu8CurrByte = strWID.ps8WidVal; + + PRINT_D(HOSTINF_DBG, "Deleting BEACON\n"); + /* TODO: build del beacon message*/ + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)pstrWFIDrv); + if (s32Error) { + + PRINT_ER("Failed to send delete beacon config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + } +} + + +/** + * @brief WILC_HostIf_PackStaParam + * @details Handling packing of the station params in a buffer + * @param[in] u8* pu8Buffer, tstrWILC_AddStaParam* pstrStationParam + * @return NONE + * @author + * @date + * @version 1.0 + */ +static u32 WILC_HostIf_PackStaParam(u8 *pu8Buffer, tstrWILC_AddStaParam *pstrStationParam) +{ + u8 *pu8CurrByte; + + pu8CurrByte = pu8Buffer; + + PRINT_D(HOSTINF_DBG, "Packing STA params\n"); + WILC_memcpy(pu8CurrByte, pstrStationParam->au8BSSID, ETH_ALEN); + pu8CurrByte += ETH_ALEN; + + *pu8CurrByte++ = pstrStationParam->u16AssocID & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u16AssocID >> 8) & 0xFF; + + *pu8CurrByte++ = pstrStationParam->u8NumRates; + if (pstrStationParam->u8NumRates > 0) { + WILC_memcpy(pu8CurrByte, pstrStationParam->pu8Rates, pstrStationParam->u8NumRates); + } + pu8CurrByte += pstrStationParam->u8NumRates; + + *pu8CurrByte++ = pstrStationParam->bIsHTSupported; + *pu8CurrByte++ = pstrStationParam->u16HTCapInfo & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u16HTCapInfo >> 8) & 0xFF; + + *pu8CurrByte++ = pstrStationParam->u8AmpduParams; + WILC_memcpy(pu8CurrByte, pstrStationParam->au8SuppMCsSet, WILC_SUPP_MCS_SET_SIZE); + pu8CurrByte += WILC_SUPP_MCS_SET_SIZE; + + *pu8CurrByte++ = pstrStationParam->u16HTExtParams & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u16HTExtParams >> 8) & 0xFF; + + *pu8CurrByte++ = pstrStationParam->u32TxBeamformingCap & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u32TxBeamformingCap >> 8) & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u32TxBeamformingCap >> 16) & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u32TxBeamformingCap >> 24) & 0xFF; + + *pu8CurrByte++ = pstrStationParam->u8ASELCap; + + *pu8CurrByte++ = pstrStationParam->u16FlagsMask & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u16FlagsMask >> 8) & 0xFF; + + *pu8CurrByte++ = pstrStationParam->u16FlagsSet & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u16FlagsSet >> 8) & 0xFF; + + return pu8CurrByte - pu8Buffer; +} + +/** + * @brief Handle_AddStation + * @details Sending config packet to add station + * @param[in] tstrWILC_AddStaParam* pstrStationParam + * @return NONE + * @author + * @date + * @version 1.0 + */ +static void Handle_AddStation(void *drvHandler, tstrWILC_AddStaParam *pstrStationParam) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + u8 *pu8CurrByte; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + PRINT_D(HOSTINF_DBG, "Handling add station\n"); + strWID.u16WIDid = (u16)WID_ADD_STA; + strWID.enuWIDtype = WID_BIN; + strWID.s32ValueSize = WILC_ADD_STA_LENGTH + pstrStationParam->u8NumRates; + + strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); + if (strWID.ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + pu8CurrByte = strWID.ps8WidVal; + pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam); + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)pstrWFIDrv); + if (s32Error != WILC_SUCCESS) { + + PRINT_ER("Failed to send add station config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + } + WILC_FREE_IF_TRUE(pstrStationParam->pu8Rates); + WILC_FREE_IF_TRUE(strWID.ps8WidVal); +} + +/** + * @brief Handle_DelAllSta + * @details Sending config packet to delete station + * @param[in] tstrHostIFDelSta* pstrDelStaParam + * @return NONE + * @author + * @date + * @version 1.0 + */ +static void Handle_DelAllSta(void *drvHandler, tstrHostIFDelAllSta *pstrDelAllStaParam) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + u8 *pu8CurrByte; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + u8 i; + u8 au8Zero_Buff[6] = {0}; + strWID.u16WIDid = (u16)WID_DEL_ALL_STA; + strWID.enuWIDtype = WID_STR; + strWID.s32ValueSize = (pstrDelAllStaParam->u8Num_AssocSta * ETH_ALEN) + 1; + + PRINT_D(HOSTINF_DBG, "Handling delete station \n"); + + strWID.ps8WidVal = WILC_MALLOC((pstrDelAllStaParam->u8Num_AssocSta * ETH_ALEN) + 1); + if (strWID.ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + pu8CurrByte = strWID.ps8WidVal; + + *(pu8CurrByte++) = pstrDelAllStaParam->u8Num_AssocSta; + + for (i = 0; i < MAX_NUM_STA; i++) { + if (memcmp(pstrDelAllStaParam->au8Sta_DelAllSta[i], au8Zero_Buff, ETH_ALEN)) + WILC_memcpy(pu8CurrByte, pstrDelAllStaParam->au8Sta_DelAllSta[i], ETH_ALEN); + else + continue; + + pu8CurrByte += ETH_ALEN; + } + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) { + + PRINT_ER("Failed to send add station config packe\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + } + WILC_FREE_IF_TRUE(strWID.ps8WidVal); + + up(&hWaitResponse); +} + + +/** + * @brief Handle_DelStation + * @details Sending config packet to delete station + * @param[in] tstrHostIFDelSta* pstrDelStaParam + * @return NONE + * @author + * @date + * @version 1.0 + */ +static void Handle_DelStation(void *drvHandler, tstrHostIFDelSta *pstrDelStaParam) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + u8 *pu8CurrByte; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + strWID.u16WIDid = (u16)WID_REMOVE_STA; + strWID.enuWIDtype = WID_BIN; + strWID.s32ValueSize = ETH_ALEN; + + PRINT_D(HOSTINF_DBG, "Handling delete station \n"); + + strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); + if (strWID.ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + pu8CurrByte = strWID.ps8WidVal; + + WILC_memcpy(pu8CurrByte, pstrDelStaParam->au8MacAddr, ETH_ALEN); + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)pstrWFIDrv); + if (s32Error) { + + PRINT_ER("Failed to send add station config packe\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + } + WILC_FREE_IF_TRUE(strWID.ps8WidVal); +} + + +/** + * @brief Handle_EditStation + * @details Sending config packet to edit station + * @param[in] tstrWILC_AddStaParam* pstrStationParam + * @return NONE + * @author + * @date + * @version 1.0 + */ +static void Handle_EditStation(void *drvHandler, tstrWILC_AddStaParam *pstrStationParam) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + u8 *pu8CurrByte; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + strWID.u16WIDid = (u16)WID_EDIT_STA; + strWID.enuWIDtype = WID_BIN; + strWID.s32ValueSize = WILC_ADD_STA_LENGTH + pstrStationParam->u8NumRates; + + PRINT_D(HOSTINF_DBG, "Handling edit station\n"); + strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); + if (strWID.ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + pu8CurrByte = strWID.ps8WidVal; + pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam); + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)pstrWFIDrv); + if (s32Error) { + + PRINT_ER("Failed to send edit station config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + } + WILC_FREE_IF_TRUE(pstrStationParam->pu8Rates); + WILC_FREE_IF_TRUE(strWID.ps8WidVal); +} +#endif /*WILC_AP_EXTERNAL_MLME*/ + +#ifdef WILC_P2P +/** + * @brief Handle_RemainOnChan + * @details Sending config packet to edit station + * @param[in] tstrWILC_AddStaParam* pstrStationParam + * @return NONE + * @author + * @date + * @version 1.0 + */ +static int Handle_RemainOnChan(void *drvHandler, tstrHostIfRemainOnChan *pstrHostIfRemainOnChan) +{ + s32 s32Error = WILC_SUCCESS; + u8 u8remain_on_chan_flag; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *) drvHandler; + + /*If it's a pendig remain-on-channel, don't overwrite gWFiDrvHandle values (since incoming msg is garbbage)*/ + if (!pstrWFIDrv->u8RemainOnChan_pendingreq) { + pstrWFIDrv->strHostIfRemainOnChan.pVoid = pstrHostIfRemainOnChan->pVoid; + pstrWFIDrv->strHostIfRemainOnChan.pRemainOnChanExpired = pstrHostIfRemainOnChan->pRemainOnChanExpired; + pstrWFIDrv->strHostIfRemainOnChan.pRemainOnChanReady = pstrHostIfRemainOnChan->pRemainOnChanReady; + pstrWFIDrv->strHostIfRemainOnChan.u16Channel = pstrHostIfRemainOnChan->u16Channel; + pstrWFIDrv->strHostIfRemainOnChan.u32ListenSessionID = pstrHostIfRemainOnChan->u32ListenSessionID; + } else { + /*Set the channel to use it as a wid val*/ + pstrHostIfRemainOnChan->u16Channel = pstrWFIDrv->strHostIfRemainOnChan.u16Channel; + } + + if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult != NULL) { + PRINT_INFO(GENERIC_DBG, "Required to remain on chan while scanning return\n"); + pstrWFIDrv->u8RemainOnChan_pendingreq = 1; + WILC_ERRORREPORT(s32Error, WILC_BUSY); + } + if (pstrWFIDrv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) { + PRINT_INFO(GENERIC_DBG, "Required to remain on chan while connecting return\n"); + WILC_ERRORREPORT(s32Error, WILC_BUSY); + } + + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + if (g_obtainingIP || connecting) { + PRINT_D(GENERIC_DBG, "[handle_scan]: Don't do obss scan until IP adresss is obtained\n"); + WILC_ERRORREPORT(s32Error, WILC_BUSY); + } + #endif + + PRINT_D(HOSTINF_DBG, "Setting channel :%d\n", pstrHostIfRemainOnChan->u16Channel); + + u8remain_on_chan_flag = true; + strWID.u16WIDid = (u16)WID_REMAIN_ON_CHAN; + strWID.enuWIDtype = WID_STR; + strWID.s32ValueSize = 2; + strWID.ps8WidVal = (s8 *)WILC_MALLOC(strWID.s32ValueSize); + + if (strWID.ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + strWID.ps8WidVal[0] = u8remain_on_chan_flag; + strWID.ps8WidVal[1] = (s8)pstrHostIfRemainOnChan->u16Channel; + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error != WILC_SUCCESS) { + PRINT_ER("Failed to set remain on channel\n"); + } + + WILC_CATCH(-1) + { + P2P_LISTEN_STATE = 1; + WILC_TimerStart(&(pstrWFIDrv->hRemainOnChannel), pstrHostIfRemainOnChan->u32duration, (void *)pstrWFIDrv, NULL); + + /*Calling CFG ready_on_channel*/ + if (pstrWFIDrv->strHostIfRemainOnChan.pRemainOnChanReady) { + pstrWFIDrv->strHostIfRemainOnChan.pRemainOnChanReady(pstrWFIDrv->strHostIfRemainOnChan.pVoid); + } + + if (pstrWFIDrv->u8RemainOnChan_pendingreq) + pstrWFIDrv->u8RemainOnChan_pendingreq = 0; + } + return s32Error; +} + +/** + * @brief Handle_RegisterFrame + * @details + * @param[in] + * @return NONE + * @author + * @date + * @version 1.0 + */ +static int Handle_RegisterFrame(void *drvHandler, tstrHostIfRegisterFrame *pstrHostIfRegisterFrame) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + u8 *pu8CurrByte; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + PRINT_D(HOSTINF_DBG, "Handling frame register Flag : %d FrameType: %d\n", pstrHostIfRegisterFrame->bReg, pstrHostIfRegisterFrame->u16FrameType); + + /*prepare configuration packet*/ + strWID.u16WIDid = (u16)WID_REGISTER_FRAME; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = WILC_MALLOC(sizeof(u16) + 2); + if (strWID.ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + pu8CurrByte = strWID.ps8WidVal; + + *pu8CurrByte++ = pstrHostIfRegisterFrame->bReg; + *pu8CurrByte++ = pstrHostIfRegisterFrame->u8Regid; + WILC_memcpy(pu8CurrByte, &(pstrHostIfRegisterFrame->u16FrameType), sizeof(u16)); + + + strWID.s32ValueSize = sizeof(u16) + 2; + + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Failed to frame register config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } + + + WILC_CATCH(s32Error) + { + } + + return s32Error; + +} + +/** + * @brief Handle_ListenStateExpired + * @details Handle of listen state expiration + * @param[in] NONE + * @return Error code. + * @author + * @date + * @version 1.0 + */ +#define FALSE_FRMWR_CHANNEL 100 +static u32 Handle_ListenStateExpired(void *drvHandler, tstrHostIfRemainOnChan *pstrHostIfRemainOnChan) +{ + u8 u8remain_on_chan_flag; + tstrWID strWID; + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *) drvHandler; + + PRINT_D(HOSTINF_DBG, "CANCEL REMAIN ON CHAN\n"); + + /*BugID_5477*/ + /*Make sure we are already in listen state*/ + /*This is to handle duplicate expiry messages (listen timer fired and supplicant called cancel_remain_on_channel())*/ + if (P2P_LISTEN_STATE) { + u8remain_on_chan_flag = false; + strWID.u16WIDid = (u16)WID_REMAIN_ON_CHAN; + strWID.enuWIDtype = WID_STR; + strWID.s32ValueSize = 2; + strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); + + if (strWID.ps8WidVal == NULL) { + PRINT_ER("Failed to allocate memory\n"); + } + + strWID.ps8WidVal[0] = u8remain_on_chan_flag; + strWID.ps8WidVal[1] = FALSE_FRMWR_CHANNEL; + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error != WILC_SUCCESS) { + PRINT_ER("Failed to set remain on channel\n"); + goto _done_; + } + + if (pstrWFIDrv->strHostIfRemainOnChan.pRemainOnChanExpired) { + pstrWFIDrv->strHostIfRemainOnChan.pRemainOnChanExpired(pstrWFIDrv->strHostIfRemainOnChan.pVoid + , pstrHostIfRemainOnChan->u32ListenSessionID); + } + P2P_LISTEN_STATE = 0; + } else { + PRINT_D(GENERIC_DBG, "Not in listen state\n"); + s32Error = WILC_FAIL; + } + +_done_: + return s32Error; +} + + +/** + * @brief ListenTimerCB + * @details Callback function of remain-on-channel timer + * @param[in] NONE + * @return Error code. + * @author + * @date + * @version 1.0 + */ +static void ListenTimerCB(void *pvArg) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)pvArg; + /*Stopping remain-on-channel timer*/ + WILC_TimerStop(&(pstrWFIDrv->hRemainOnChannel), NULL); + + /* prepare the Timer Callback message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + strHostIFmsg.u16MsgId = HOST_IF_MSG_LISTEN_TIMER_FIRED; + strHostIFmsg.drvHandler = pstrWFIDrv; + strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.u32ListenSessionID = pstrWFIDrv->strHostIfRemainOnChan.u32ListenSessionID; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } +} +#endif + + +/** + * @brief Handle_EditStation + * @details Sending config packet to edit station + * @param[in] tstrWILC_AddStaParam* pstrStationParam + * @return NONE + * @author + * @date + * @version 1.0 + */ +static void Handle_PowerManagement(void *drvHandler, tstrHostIfPowerMgmtParam *strPowerMgmtParam) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + s8 s8PowerMode; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + strWID.u16WIDid = (u16)WID_POWER_MANAGEMENT; + + if (strPowerMgmtParam->bIsEnabled == true) { + s8PowerMode = MIN_FAST_PS; + } else { + s8PowerMode = NO_POWERSAVE; + } + PRINT_D(HOSTINF_DBG, "Handling power mgmt to %d\n", s8PowerMode); + strWID.ps8WidVal = &s8PowerMode; + strWID.s32ValueSize = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Handling Power Management\n"); + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Failed to send power management config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } + + WILC_CATCH(s32Error) + { + + } +} + +/** + * @brief Handle_SetMulticastFilter + * @details Set Multicast filter in firmware + * @param[in] tstrHostIFSetMulti* strHostIfSetMulti + * @return NONE + * @author asobhy + * @date + * @version 1.0 + */ +static void Handle_SetMulticastFilter(void *drvHandler, tstrHostIFSetMulti *strHostIfSetMulti) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + u8 *pu8CurrByte; + + PRINT_D(HOSTINF_DBG, "Setup Multicast Filter\n"); + + strWID.u16WIDid = (u16)WID_SETUP_MULTICAST_FILTER; + strWID.enuWIDtype = WID_BIN; + strWID.s32ValueSize = sizeof(tstrHostIFSetMulti) + ((strHostIfSetMulti->u32count) * ETH_ALEN); + strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); + if (strWID.ps8WidVal == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + + pu8CurrByte = strWID.ps8WidVal; + *pu8CurrByte++ = (strHostIfSetMulti->bIsEnabled & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->bIsEnabled >> 8) & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->bIsEnabled >> 16) & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->bIsEnabled >> 24) & 0xFF); + + *pu8CurrByte++ = (strHostIfSetMulti->u32count & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->u32count >> 8) & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->u32count >> 16) & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->u32count >> 24) & 0xFF); + + if ((strHostIfSetMulti->u32count) > 0) + memcpy(pu8CurrByte, gau8MulticastMacAddrList, ((strHostIfSetMulti->u32count) * ETH_ALEN)); + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)drvHandler); + if (s32Error) { + PRINT_ER("Failed to send setup multicast config packet\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + } + WILC_FREE_IF_TRUE(strWID.ps8WidVal); + +} + + +/*BugID_5222*/ +/** + * @brief Handle_AddBASession + * @details Add block ack session + * @param[in] tstrHostIFSetMulti* strHostIfSetMulti + * @return NONE + * @author Amr Abdel-Moghny + * @date Feb. 2014 + * @version 9.0 + */ +static s32 Handle_AddBASession(void *drvHandler, tstrHostIfBASessionInfo *strHostIfBASessionInfo) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + int AddbaTimeout = 100; + char *ptr = NULL; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + PRINT_D(HOSTINF_DBG, "Opening Block Ack session with\nBSSID = %.2x:%.2x:%.2x \nTID=%d \nBufferSize == %d \nSessionTimeOut = %d\n", + strHostIfBASessionInfo->au8Bssid[0], + strHostIfBASessionInfo->au8Bssid[1], + strHostIfBASessionInfo->au8Bssid[2], + strHostIfBASessionInfo->u16BufferSize, + strHostIfBASessionInfo->u16SessionTimeout, + strHostIfBASessionInfo->u8Ted); + + strWID.u16WIDid = (u16)WID_11E_P_ACTION_REQ; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = (u8 *)WILC_MALLOC(BLOCK_ACK_REQ_SIZE); + strWID.s32ValueSize = BLOCK_ACK_REQ_SIZE; + ptr = strWID.ps8WidVal; + /* *ptr++ = 0x14; */ + *ptr++ = 0x14; + *ptr++ = 0x3; + *ptr++ = 0x0; + WILC_memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN); + ptr += ETH_ALEN; + *ptr++ = strHostIfBASessionInfo->u8Ted; + /* BA Policy*/ + *ptr++ = 1; + /* Buffer size*/ + *ptr++ = (strHostIfBASessionInfo->u16BufferSize & 0xFF); + *ptr++ = ((strHostIfBASessionInfo->u16BufferSize >> 16) & 0xFF); + /* BA timeout*/ + *ptr++ = (strHostIfBASessionInfo->u16SessionTimeout & 0xFF); + *ptr++ = ((strHostIfBASessionInfo->u16SessionTimeout >> 16) & 0xFF); + /* ADDBA timeout*/ + *ptr++ = (AddbaTimeout & 0xFF); + *ptr++ = ((AddbaTimeout >> 16) & 0xFF); + /* Group Buffer Max Frames*/ + *ptr++ = 8; + /* Group Buffer Timeout */ + *ptr++ = 0; + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) + PRINT_D(HOSTINF_DBG, "Couldn't open BA Session\n"); + + + strWID.u16WIDid = (u16)WID_11E_P_ACTION_REQ; + strWID.enuWIDtype = WID_STR; + strWID.s32ValueSize = 15; + ptr = strWID.ps8WidVal; + /* *ptr++ = 0x14; */ + *ptr++ = 15; + *ptr++ = 7; + *ptr++ = 0x2; + WILC_memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN); + ptr += ETH_ALEN; + /* TID*/ + *ptr++ = strHostIfBASessionInfo->u8Ted; + /* Max Num MSDU */ + *ptr++ = 8; + /* BA timeout*/ + *ptr++ = (strHostIfBASessionInfo->u16BufferSize & 0xFF); + *ptr++ = ((strHostIfBASessionInfo->u16SessionTimeout >> 16) & 0xFF); + /*Ack-Policy */ + *ptr++ = 3; + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + + if (strWID.ps8WidVal != NULL) + WILC_FREE(strWID.ps8WidVal); + + return s32Error; + +} + + +/*BugID_5222*/ +/** + * @brief Handle_DelBASession + * @details Delete block ack session + * @param[in] tstrHostIFSetMulti* strHostIfSetMulti + * @return NONE + * @author Amr Abdel-Moghny + * @date Feb. 2013 + * @version 9.0 + */ +static s32 Handle_DelBASession(void *drvHandler, tstrHostIfBASessionInfo *strHostIfBASessionInfo) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + char *ptr = NULL; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + PRINT_D(GENERIC_DBG, "Delete Block Ack session with\nBSSID = %.2x:%.2x:%.2x \nTID=%d\n", + strHostIfBASessionInfo->au8Bssid[0], + strHostIfBASessionInfo->au8Bssid[1], + strHostIfBASessionInfo->au8Bssid[2], + strHostIfBASessionInfo->u8Ted); + + strWID.u16WIDid = (u16)WID_11E_P_ACTION_REQ; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = (u8 *)WILC_MALLOC(BLOCK_ACK_REQ_SIZE); + strWID.s32ValueSize = BLOCK_ACK_REQ_SIZE; + ptr = strWID.ps8WidVal; + /* *ptr++ = 0x14; */ + *ptr++ = 0x14; + *ptr++ = 0x3; + *ptr++ = 0x2; + WILC_memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN); + ptr += ETH_ALEN; + *ptr++ = strHostIfBASessionInfo->u8Ted; + /* BA direction = recipent*/ + *ptr++ = 0; + /* Delba Reason */ + *ptr++ = 32; /* Unspecific QOS reason */ + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) + PRINT_D(HOSTINF_DBG, "Couldn't delete BA Session\n"); + + + strWID.u16WIDid = (u16)WID_11E_P_ACTION_REQ; + strWID.enuWIDtype = WID_STR; + strWID.s32ValueSize = 15; + ptr = strWID.ps8WidVal; + /* *ptr++ = 0x14; */ + *ptr++ = 15; + *ptr++ = 7; + *ptr++ = 0x3; + WILC_memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN); + ptr += ETH_ALEN; + /* TID*/ + *ptr++ = strHostIfBASessionInfo->u8Ted; + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + + if (strWID.ps8WidVal != NULL) + WILC_FREE(strWID.ps8WidVal); + + /*BugID_5222*/ + up(&hWaitResponse); + + return s32Error; + +} + + +/** + * @brief Handle_DelAllRxBASessions + * @details Delete all Rx BA sessions + * @param[in] tstrHostIFSetMulti* strHostIfSetMulti + * @return NONE + * @author Abdelrahman Sobhy + * @date Feb. 2013 + * @version 9.0 + */ +static s32 Handle_DelAllRxBASessions(void *drvHandler, tstrHostIfBASessionInfo *strHostIfBASessionInfo) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + char *ptr = NULL; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + PRINT_D(GENERIC_DBG, "Delete Block Ack session with\nBSSID = %.2x:%.2x:%.2x \nTID=%d\n", + strHostIfBASessionInfo->au8Bssid[0], + strHostIfBASessionInfo->au8Bssid[1], + strHostIfBASessionInfo->au8Bssid[2], + strHostIfBASessionInfo->u8Ted); + + strWID.u16WIDid = (u16)WID_DEL_ALL_RX_BA; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = (u8 *)WILC_MALLOC(BLOCK_ACK_REQ_SIZE); + strWID.s32ValueSize = BLOCK_ACK_REQ_SIZE; + ptr = strWID.ps8WidVal; + *ptr++ = 0x14; + *ptr++ = 0x3; + *ptr++ = 0x2; + WILC_memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN); + ptr += ETH_ALEN; + *ptr++ = strHostIfBASessionInfo->u8Ted; + /* BA direction = recipent*/ + *ptr++ = 0; + /* Delba Reason */ + *ptr++ = 32; /* Unspecific QOS reason */ + + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) + PRINT_D(HOSTINF_DBG, "Couldn't delete BA Session\n"); + + + if (strWID.ps8WidVal != NULL) + WILC_FREE(strWID.ps8WidVal); + + /*BugID_5222*/ + up(&hWaitResponse); + + return s32Error; + +} + +/** + * @brief hostIFthread + * @details Main thread to handle message queue requests + * @param[in] void* pvArg + * @return NONE + * @author + * @date + * @version 1.0 + */ +static int hostIFthread(void *pvArg) +{ + u32 u32Ret; + tstrHostIFmsg strHostIFmsg; + tstrWILC_WFIDrv *pstrWFIDrv; + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + while (1) { + WILC_MsgQueueRecv(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), &u32Ret, NULL); + pstrWFIDrv = (tstrWILC_WFIDrv *)strHostIFmsg.drvHandler; + if (strHostIFmsg.u16MsgId == HOST_IF_MSG_EXIT) { + PRINT_D(GENERIC_DBG, "THREAD: Exiting HostIfThread\n"); + break; + } + + + /*Re-Queue HIF message*/ + if ((!g_wilc_initialized)) { + PRINT_D(GENERIC_DBG, "--WAIT--"); + WILC_Sleep(200); + WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + continue; + } + + if (strHostIFmsg.u16MsgId == HOST_IF_MSG_CONNECT && pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult != NULL) { + PRINT_D(HOSTINF_DBG, "Requeue connect request till scan done received\n"); + WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + WILC_Sleep(2); + continue; + } + + switch (strHostIFmsg.u16MsgId) { + case HOST_IF_MSG_Q_IDLE: + Handle_wait_msg_q_empty(); + break; + + case HOST_IF_MSG_SCAN: + Handle_Scan(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr); + break; + + case HOST_IF_MSG_CONNECT: + Handle_Connect(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr); + break; + + /*BugID_5137*/ + case HOST_IF_MSG_FLUSH_CONNECT: + Handle_FlushConnect(strHostIFmsg.drvHandler); + break; + + case HOST_IF_MSG_RCVD_NTWRK_INFO: + Handle_RcvdNtwrkInfo(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strRcvdNetworkInfo); + break; + + case HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO: + Handle_RcvdGnrlAsyncInfo(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strRcvdGnrlAsyncInfo); + break; + + case HOST_IF_MSG_KEY: + Handle_Key(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr); + break; + + case HOST_IF_MSG_CFG_PARAMS: + + Handle_CfgParam(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIFCfgParamAttr); + break; + + case HOST_IF_MSG_SET_CHANNEL: + Handle_SetChannel(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIFSetChan); + break; + + case HOST_IF_MSG_DISCONNECT: + Handle_Disconnect(strHostIFmsg.drvHandler); + break; + + case HOST_IF_MSG_RCVD_SCAN_COMPLETE: + WILC_TimerStop(&(pstrWFIDrv->hScanTimer), NULL); + PRINT_D(HOSTINF_DBG, "scan completed successfully\n"); + + /*BugID_5213*/ + /*Allow chip sleep, only if both interfaces are not connected*/ + if (!linux_wlan_get_num_conn_ifcs()) { + chip_sleep_manually(INFINITE_SLEEP_TIME); + } + + Handle_ScanDone(strHostIFmsg.drvHandler, SCAN_EVENT_DONE); + + #ifdef WILC_P2P + if (pstrWFIDrv->u8RemainOnChan_pendingreq) + Handle_RemainOnChan(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan); + #endif + + break; + + case HOST_IF_MSG_GET_RSSI: + Handle_GetRssi(strHostIFmsg.drvHandler); + break; + + case HOST_IF_MSG_GET_LINKSPEED: + Handle_GetLinkspeed(strHostIFmsg.drvHandler); + break; + + case HOST_IF_MSG_GET_STATISTICS: + Handle_GetStatistics(strHostIFmsg.drvHandler, (tstrStatistics *)strHostIFmsg.uniHostIFmsgBody.pUserData); + break; + + case HOST_IF_MSG_GET_CHNL: + Handle_GetChnl(strHostIFmsg.drvHandler); + break; + +#ifdef WILC_AP_EXTERNAL_MLME + case HOST_IF_MSG_ADD_BEACON: + Handle_AddBeacon(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIFSetBeacon); + break; + + case HOST_IF_MSG_DEL_BEACON: + Handle_DelBeacon(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIFDelBeacon); + break; + + case HOST_IF_MSG_ADD_STATION: + Handle_AddStation(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strAddStaParam); + break; + + case HOST_IF_MSG_DEL_STATION: + Handle_DelStation(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strDelStaParam); + break; + + case HOST_IF_MSG_EDIT_STATION: + Handle_EditStation(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strEditStaParam); + break; + + case HOST_IF_MSG_GET_INACTIVETIME: + Handle_Get_InActiveTime(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfStaInactiveT); + break; + +#endif /*WILC_AP_EXTERNAL_MLME*/ + case HOST_IF_MSG_SCAN_TIMER_FIRED: + PRINT_D(HOSTINF_DBG, "Scan Timeout\n"); + + Handle_ScanDone(strHostIFmsg.drvHandler, SCAN_EVENT_ABORTED); + break; + + case HOST_IF_MSG_CONNECT_TIMER_FIRED: + PRINT_D(HOSTINF_DBG, "Connect Timeout \n"); + Handle_ConnectTimeout(strHostIFmsg.drvHandler); + break; + + case HOST_IF_MSG_POWER_MGMT: + Handle_PowerManagement(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strPowerMgmtparam); + break; + + case HOST_IF_MSG_SET_WFIDRV_HANDLER: + Handle_SetWfiDrvHandler(&strHostIFmsg.uniHostIFmsgBody.strHostIfSetDrvHandler); + break; + + case HOST_IF_MSG_SET_OPERATION_MODE: + Handle_SetOperationMode(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfSetOperationMode); + break; + + case HOST_IF_MSG_SET_IPADDRESS: + PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_SET_IPADDRESS\n"); + Handle_set_IPAddress(strHostIFmsg.drvHandler, strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.au8IPAddr, strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.idx); + break; + + case HOST_IF_MSG_GET_IPADDRESS: + PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_SET_IPADDRESS\n"); + Handle_get_IPAddress(strHostIFmsg.drvHandler, strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.au8IPAddr, strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.idx); + break; + + /*BugID_5077*/ + case HOST_IF_MSG_SET_MAC_ADDRESS: + Handle_SetMacAddress(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfSetMacAddress); + break; + + /*BugID_5213*/ + case HOST_IF_MSG_GET_MAC_ADDRESS: + Handle_GetMacAddress(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfGetMacAddress); + break; + +#ifdef WILC_P2P + case HOST_IF_MSG_REMAIN_ON_CHAN: + PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_REMAIN_ON_CHAN\n"); + Handle_RemainOnChan(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan); + break; + + case HOST_IF_MSG_REGISTER_FRAME: + PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_REGISTER_FRAME\n"); + Handle_RegisterFrame(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfRegisterFrame); + break; + + case HOST_IF_MSG_LISTEN_TIMER_FIRED: + Handle_ListenStateExpired(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan); + break; + + #endif + case HOST_IF_MSG_SET_MULTICAST_FILTER: + PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_SET_MULTICAST_FILTER\n"); + Handle_SetMulticastFilter(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfSetMulti); + break; + + /*BugID_5222*/ + case HOST_IF_MSG_ADD_BA_SESSION: + Handle_AddBASession(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfBASessionInfo); + break; + + case HOST_IF_MSG_DEL_ALL_RX_BA_SESSIONS: + Handle_DelAllRxBASessions(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIfBASessionInfo); + break; + + case HOST_IF_MSG_DEL_ALL_STA: + Handle_DelAllSta(strHostIFmsg.drvHandler, &strHostIFmsg.uniHostIFmsgBody.strHostIFDelAllSta); + break; + + default: + PRINT_ER("[Host Interface] undefined Received Msg ID \n"); + break; + } + } + + PRINT_D(HOSTINF_DBG, "Releasing thread exit semaphore\n"); + up(&hSemHostIFthrdEnd); + return 0; +} + +static void TimerCB_Scan(void *pvArg) +{ + tstrHostIFmsg strHostIFmsg; + + /* prepare the Timer Callback message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + strHostIFmsg.drvHandler = pvArg; + strHostIFmsg.u16MsgId = HOST_IF_MSG_SCAN_TIMER_FIRED; + + /* send the message */ + WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); +} + +static void TimerCB_Connect(void *pvArg) +{ + tstrHostIFmsg strHostIFmsg; + + /* prepare the Timer Callback message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + strHostIFmsg.drvHandler = pvArg; + strHostIFmsg.u16MsgId = HOST_IF_MSG_CONNECT_TIMER_FIRED; + + /* send the message */ + WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); +} + + +/** + * @brief removes wpa/wpa2 keys + * @details only in BSS STA mode if External Supplicant support is enabled. + * removes all WPA/WPA2 station key entries from MAC hardware. + * @param[in,out] handle to the wifi driver + * @param[in] 6 bytes of Station Adress in the station entry table + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +/* Check implementation in core adding 9 bytes to the input! */ +s32 host_int_remove_key(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8StaAddress) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ + + strWID.u16WIDid = (u16)WID_REMOVE_KEY; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = (s8 *)pu8StaAddress; + strWID.s32ValueSize = 6; + + return s32Error; + +} + +/** + * @brief removes WEP key + * @details valid only in BSS STA mode if External Supplicant support is enabled. + * remove a WEP key entry from MAC HW. + * The BSS Station automatically finds the index of the entry using its + * BSS ID and removes that entry from the MAC hardware. + * @param[in,out] handle to the wifi driver + * @param[in] 6 bytes of Station Adress in the station entry table + * @return Error code indicating success/failure + * @note NO need for the STA add since it is not used for processing + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_remove_wep_key(WILC_WFIDrvHandle hWFIDrv, u8 u8keyIdx) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + /* prepare the Remove Wep Key Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + + strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.enuKeyType = WEP; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.u8KeyAction = REMOVEKEY; + strHostIFmsg.drvHandler = hWFIDrv; + + + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwepAttr.u8Wepidx = u8keyIdx; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) + PRINT_ER("Error in sending message queue : Request to remove WEP key \n"); + down(&(pstrWFIDrv->hSemTestKeyBlock)); + + WILC_CATCH(s32Error) + { + + } + return s32Error; +} + +/** + * @brief sets WEP default key + * @details Sets the index of the WEP encryption key in use, + * in the key table + * @param[in,out] handle to the wifi driver + * @param[in] key index ( 0, 1, 2, 3) + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_set_WEPDefaultKeyID(WILC_WFIDrvHandle hWFIDrv, u8 u8Index) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + /* prepare the Key Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + + strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.enuKeyType = WEP; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.u8KeyAction = DEFAULTKEY; + strHostIFmsg.drvHandler = hWFIDrv; + + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwepAttr.u8Wepidx = u8Index; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) + PRINT_ER("Error in sending message queue : Default key index\n"); + down(&(pstrWFIDrv->hSemTestKeyBlock)); + + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief sets WEP deafault key + * @details valid only in BSS STA mode if External Supplicant support is enabled. + * sets WEP key entry into MAC hardware when it receives the + * corresponding request from NDIS. + * @param[in,out] handle to the wifi driver + * @param[in] message containing WEP Key in the following format + *|---------------------------------------| + *|Key ID Value | Key Length | Key | + *|-------------|------------|------------| + | 1byte | 1byte | Key Length | + ||---------------------------------------| + | + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_add_wep_key_bss_sta(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8WepKey, u8 u8WepKeylen, u8 u8Keyidx) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + + } + + /* prepare the Key Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + + strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.enuKeyType = WEP; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.u8KeyAction = ADDKEY; + strHostIFmsg.drvHandler = hWFIDrv; + + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwepAttr.pu8WepKey = (u8 *)WILC_MALLOC(u8WepKeylen); + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFwepAttr.pu8WepKey, + pu8WepKey, u8WepKeylen); + + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwepAttr.u8WepKeylen = (u8WepKeylen); + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwepAttr.u8Wepidx = u8Keyidx; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) + PRINT_ER("Error in sending message queue :WEP Key\n"); + down(&(pstrWFIDrv->hSemTestKeyBlock)); + + WILC_CATCH(s32Error) + { + + } + return s32Error; + +} + +#ifdef WILC_AP_EXTERNAL_MLME +/** + * + * @brief host_int_add_wep_key_bss_ap + * @details valid only in BSS AP mode if External Supplicant support is enabled. + * sets WEP key entry into MAC hardware when it receives the + * + * corresponding request from NDIS. + * @param[in,out] handle to the wifi driver + * + * + * @return Error code indicating success/failure + * @note + * @author mdaftedar + * @date 28 FEB 2013 + * @version 1.0 + */ +s32 host_int_add_wep_key_bss_ap(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8WepKey, u8 u8WepKeylen, u8 u8Keyidx, u8 u8mode, AUTHTYPE_T tenuAuth_type) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + u8 i; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + + } + + /* prepare the Key Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + if (INFO) { + for (i = 0; i < u8WepKeylen; i++) + PRINT_INFO(HOSTAPD_DBG, "KEY is %x\n", pu8WepKey[i]); + } + strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.enuKeyType = WEP; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.u8KeyAction = ADDKEY_AP; + strHostIFmsg.drvHandler = hWFIDrv; + + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwepAttr.pu8WepKey = (u8 *)WILC_MALLOC((u8WepKeylen)); + + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFwepAttr.pu8WepKey, + pu8WepKey, (u8WepKeylen)); + + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwepAttr.u8WepKeylen = (u8WepKeylen); + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwepAttr.u8Wepidx = u8Keyidx; + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwepAttr.u8mode = u8mode; + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwepAttr.tenuAuth_type = tenuAuth_type; + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + + if (s32Error) + PRINT_ER("Error in sending message queue :WEP Key\n"); + down(&(pstrWFIDrv->hSemTestKeyBlock)); + + WILC_CATCH(s32Error) + { + + } + return s32Error; + +} +#endif +/** + * @brief adds ptk Key + * @details + * @param[in,out] handle to the wifi driver + * @param[in] message containing PTK Key in the following format + *|-----------------------------------------------------------------------------| + *|Station address | Key Length | Temporal Key | Rx Michael Key |Tx Michael Key | + *|----------------|------------|--------------|----------------|---------------| + | 6 bytes | 1byte | 16 bytes | 8 bytes | 8 bytes | + ||-----------------------------------------------------------------------------| + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_add_ptk(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8Ptk, u8 u8PtkKeylen, + const u8 *mac_addr, const u8 *pu8RxMic, const u8 *pu8TxMic, u8 mode, u8 u8Ciphermode, u8 u8Idx) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + u8 u8KeyLen = u8PtkKeylen; + u32 i; + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + if (pu8RxMic != NULL) { + u8KeyLen += RX_MIC_KEY_LEN; + } + if (pu8TxMic != NULL) { + u8KeyLen += TX_MIC_KEY_LEN; + } + + /* prepare the Key Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + + strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.enuKeyType = WPAPtk; + #ifdef WILC_AP_EXTERNAL_MLME + if (mode == AP_MODE) { + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.u8KeyAction = ADDKEY_AP; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwpaAttr.u8keyidx = u8Idx; + } + #endif + if (mode == STATION_MODE) + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.u8KeyAction = ADDKEY; + + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwpaAttr.pu8key = (u8 *)WILC_MALLOC(u8PtkKeylen); + + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFwpaAttr.pu8key, + pu8Ptk, u8PtkKeylen); + + if (pu8RxMic != NULL) { + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFwpaAttr.pu8key + 16, + pu8RxMic, RX_MIC_KEY_LEN); + if (INFO) { + for (i = 0; i < RX_MIC_KEY_LEN; i++) + PRINT_INFO(CFG80211_DBG, "PairwiseRx[%d] = %x\n", i, pu8RxMic[i]); + } + } + if (pu8TxMic != NULL) { + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFwpaAttr.pu8key + 24, + pu8TxMic, TX_MIC_KEY_LEN); + if (INFO) { + for (i = 0; i < TX_MIC_KEY_LEN; i++) + PRINT_INFO(CFG80211_DBG, "PairwiseTx[%d] = %x\n", i, pu8TxMic[i]); + } + } + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwpaAttr.u8Keylen = u8KeyLen; + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwpaAttr.u8Ciphermode = u8Ciphermode; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwpaAttr.pu8macaddr = mac_addr; + strHostIFmsg.drvHandler = hWFIDrv; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + + if (s32Error) + PRINT_ER("Error in sending message queue: PTK Key\n"); + + /* ////////////// */ + down(&(pstrWFIDrv->hSemTestKeyBlock)); + /* WILC_Sleep(100); */ + /* /////// */ + + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief adds Rx GTk Key + * @details + * @param[in,out] handle to the wifi driver + * @param[in] pu8RxGtk : contains temporal key | Rx Mic | Tx Mic + * u8GtkKeylen :The total key length + * + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_add_rx_gtk(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8RxGtk, u8 u8GtkKeylen, + u8 u8KeyIdx, u32 u32KeyRSClen, const u8 *KeyRSC, + const u8 *pu8RxMic, const u8 *pu8TxMic, u8 mode, u8 u8Ciphermode) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + u8 u8KeyLen = u8GtkKeylen; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + /* prepare the Key Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + + if (pu8RxMic != NULL) { + u8KeyLen += RX_MIC_KEY_LEN; + } + if (pu8TxMic != NULL) { + u8KeyLen += TX_MIC_KEY_LEN; + } + if (KeyRSC != NULL) { + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwpaAttr.pu8seq = (u8 *)WILC_MALLOC(u32KeyRSClen); + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFwpaAttr.pu8seq, + KeyRSC, u32KeyRSClen); + } + + + strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.enuKeyType = WPARxGtk; + strHostIFmsg.drvHandler = hWFIDrv; + + #ifdef WILC_AP_EXTERNAL_MLME + if (mode == AP_MODE) { + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.u8KeyAction = ADDKEY_AP; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFwpaAttr.u8Ciphermode = u8Ciphermode; + } + #endif + if (mode == STATION_MODE) + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.u8KeyAction = ADDKEY; + + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwpaAttr.pu8key = (u8 *)WILC_MALLOC(u8KeyLen); + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFwpaAttr.pu8key, + pu8RxGtk, u8GtkKeylen); + + if (pu8RxMic != NULL) { + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFwpaAttr.pu8key + 16, + pu8RxMic, RX_MIC_KEY_LEN); + + } + if (pu8TxMic != NULL) { + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFwpaAttr.pu8key + 24, + pu8TxMic, TX_MIC_KEY_LEN); + + } + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwpaAttr.u8keyidx = u8KeyIdx; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwpaAttr.u8Keylen = u8KeyLen; + + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. + uniHostIFkeyAttr.strHostIFwpaAttr.u8seqlen = u32KeyRSClen; + + + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) + PRINT_ER("Error in sending message queue: RX GTK\n"); + /* ////////////// */ + down(&(pstrWFIDrv->hSemTestKeyBlock)); + /* WILC_Sleep(100); */ + /* /////// */ + + WILC_CATCH(s32Error) + { + + } + return s32Error; +} + +/** + * @brief host_int_set_pmkid_info + * @details caches the pmkid valid only in BSS STA mode if External Supplicant + * support is enabled. This Function sets the PMKID in firmware + * when host drivr receives the corresponding request from NDIS. + * The firmware then includes theset PMKID in the appropriate + * management frames + * @param[in,out] handle to the wifi driver + * @param[in] message containing PMKID Info in the following format + *|-----------------------------------------------------------------| + *|NumEntries | BSSID[1] | PMKID[1] | ... | BSSID[K] | PMKID[K] | + *|-----------|------------|----------|-------|----------|----------| + | 1 | 6 | 16 | ... | 6 | 16 | + ||-----------------------------------------------------------------| + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_set_pmkid_info(WILC_WFIDrvHandle hWFIDrv, tstrHostIFpmkidAttr *pu8PmkidInfoArray) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + u32 i; + + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + /* prepare the Key Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.enuKeyType = PMKSA; + strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.u8KeyAction = ADDKEY; + strHostIFmsg.drvHandler = hWFIDrv; + + for (i = 0; i < pu8PmkidInfoArray->numpmkid; i++) { + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFpmkidAttr.pmkidlist[i].bssid, &pu8PmkidInfoArray->pmkidlist[i].bssid, + ETH_ALEN); + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.uniHostIFkeyAttr.strHostIFpmkidAttr.pmkidlist[i].pmkid, &pu8PmkidInfoArray->pmkidlist[i].pmkid, + PMKID_LEN); + } + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) + PRINT_ER(" Error in sending messagequeue: PMKID Info\n"); + + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief gets the cached the pmkid info + * @details valid only in BSS STA mode if External Supplicant + * support is enabled. This Function sets the PMKID in firmware + * when host drivr receives the corresponding request from NDIS. + * The firmware then includes theset PMKID in the appropriate + * management frames + * @param[in,out] handle to the wifi driver, + * message containing PMKID Info in the following format + *|-----------------------------------------------------------------| + *|NumEntries | BSSID[1] | PMKID[1] | ... | BSSID[K] | PMKID[K] | + *|-----------|------------|----------|-------|----------|----------| + | 1 | 6 | 16 | ... | 6 | 16 | + ||-----------------------------------------------------------------| + * @param[in] + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_get_pmkid_info(WILC_WFIDrvHandle hWFIDrv, u8 *pu8PmkidInfoArray, + u32 u32PmkidInfoLen) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ + + strWID.u16WIDid = (u16)WID_PMKID_INFO; + strWID.enuWIDtype = WID_STR; + strWID.s32ValueSize = u32PmkidInfoLen; + strWID.ps8WidVal = pu8PmkidInfoArray; + + return s32Error; +} + +/** + * @brief sets the pass phrase + * @details AP/STA mode. This function gives the pass phrase used to + * generate the Pre-Shared Key when WPA/WPA2 is enabled + * The length of the field can vary from 8 to 64 bytes, + * the lower layer should get the + * @param[in,out] handle to the wifi driver, + * @param[in] String containing PSK + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_set_RSNAConfigPSKPassPhrase(WILC_WFIDrvHandle hWFIDrv, u8 *pu8PassPhrase, + u8 u8Psklength) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ + + /* u8 u8Psklength = WILC_strlen(pu8PassPhrase); */ + /*validating psk length*/ + if ((u8Psklength > 7) && (u8Psklength < 65)) { + strWID.u16WIDid = (u16)WID_11I_PSK; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = pu8PassPhrase; + strWID.s32ValueSize = u8Psklength; + } + + return s32Error; +} +/** + * @brief host_int_get_MacAddress + * @details gets mac address + * @param[in,out] handle to the wifi driver, + * + * @return Error code indicating success/failure + * @note + * @author mdaftedar + * @date 19 April 2012 + * @version 1.0 + */ +s32 host_int_get_MacAddress(WILC_WFIDrvHandle hWFIDrv, u8 *pu8MacAddress) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + + + /* prepare the Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_MAC_ADDRESS; + strHostIFmsg.uniHostIFmsgBody.strHostIfGetMacAddress.u8MacAddress = pu8MacAddress; + strHostIFmsg.drvHandler = hWFIDrv; + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Failed to send get mac address\n"); + return WILC_FAIL; + } + + down(&hWaitResponse); + return s32Error; +} + +/** + * @brief host_int_set_MacAddress + * @details sets mac address + * @param[in,out] handle to the wifi driver, + * + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 16 July 2012 + * @version 1.0 + */ +s32 host_int_set_MacAddress(WILC_WFIDrvHandle hWFIDrv, u8 *pu8MacAddress) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + + PRINT_D(GENERIC_DBG, "mac addr = %x:%x:%x\n", pu8MacAddress[0], pu8MacAddress[1], pu8MacAddress[2]); + + /* prepare setting mac address message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_MAC_ADDRESS; + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIfSetMacAddress.u8MacAddress, pu8MacAddress, ETH_ALEN); + strHostIFmsg.drvHandler = hWFIDrv; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Failed to send message queue: Set mac address\n"); + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; + +} + +/** + * @brief host_int_get_RSNAConfigPSKPassPhrase + * @details gets the pass phrase:AP/STA mode. This function gets the pass phrase used to + * generate the Pre-Shared Key when WPA/WPA2 is enabled + * The length of the field can vary from 8 to 64 bytes, + * the lower layer should get the + * @param[in,out] handle to the wifi driver, + * String containing PSK + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_get_RSNAConfigPSKPassPhrase(WILC_WFIDrvHandle hWFIDrv, + u8 *pu8PassPhrase, u8 u8Psklength) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ + + strWID.u16WIDid = (u16)WID_11I_PSK; + strWID.enuWIDtype = WID_STR; + strWID.s32ValueSize = u8Psklength; + strWID.ps8WidVal = pu8PassPhrase; + + return s32Error; +} + +/** + * @brief host_int_get_site_survey_results + * @details gets the site survey results + * @param[in,out] handle to the wifi driver, + * Message containing site survey results in the + * following format + *|---------------------------------------------------| + | MsgLength | fragNo. | MsgBodyLength | MsgBody | + ||-----------|-----------|---------------|-----------| + | 1 | 1 | 1 | 1 | + | ----------------------------------------- | ---------------- + | + ||---------------------------------------| + | Network1 | Netweork2 | ... | Network5 | + ||---------------------------------------| + | 44 | 44 | ... | 44 | + | -------------------------- | --------------------------------------- + | + ||---------------------------------------------------------------------| + | SSID | BSS Type | Channel | Security Status| BSSID | RSSI |Reserved | + | + | + ||------|----------|---------|----------------|-------|------|---------| + | 33 | 1 | 1 | 1 | 6 | 1 | 1 | + ||---------------------------------------------------------------------| + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +#ifndef CONNECT_DIRECT +s32 host_int_get_site_survey_results(WILC_WFIDrvHandle hWFIDrv, + u8 ppu8RcvdSiteSurveyResults[][MAX_SURVEY_RESULT_FRAG_SIZE], + u32 u32MaxSiteSrvyFragLen) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID astrWIDList[2]; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + + astrWIDList[0].u16WIDid = (u16)WID_SITE_SURVEY_RESULTS; + astrWIDList[0].enuWIDtype = WID_STR; + astrWIDList[0].ps8WidVal = ppu8RcvdSiteSurveyResults[0]; + astrWIDList[0].s32ValueSize = u32MaxSiteSrvyFragLen; + + astrWIDList[1].u16WIDid = (u16)WID_SITE_SURVEY_RESULTS; + astrWIDList[1].enuWIDtype = WID_STR; + astrWIDList[1].ps8WidVal = ppu8RcvdSiteSurveyResults[1]; + astrWIDList[1].s32ValueSize = u32MaxSiteSrvyFragLen; + + s32Error = SendConfigPkt(GET_CFG, astrWIDList, 2, true, (u32)pstrWFIDrv); + + /*get the value by searching the local copy*/ + if (s32Error) { + PRINT_ER("Failed to send config packet to get survey results\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } + + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} +#endif + +/** + * @brief sets a start scan request + * @details + * @param[in,out] handle to the wifi driver, + * @param[in] Scan Source one of the following values + * DEFAULT_SCAN 0 + * USER_SCAN BIT0 + * OBSS_PERIODIC_SCAN BIT1 + * OBSS_ONETIME_SCAN BIT2 + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_set_start_scan_req(WILC_WFIDrvHandle hWFIDrv, u8 scanSource) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ + + strWID.u16WIDid = (u16)WID_START_SCAN_REQ; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = (s8 *)&scanSource; + strWID.s32ValueSize = sizeof(char); + + return s32Error; +} + +/** + * @brief host_int_get_start_scan_req + * @details gets a start scan request + * @param[in,out] handle to the wifi driver, + * @param[in] Scan Source one of the following values + * DEFAULT_SCAN 0 + * USER_SCAN BIT0 + * OBSS_PERIODIC_SCAN BIT1 + * OBSS_ONETIME_SCAN BIT2 + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ + +s32 host_int_get_start_scan_req(WILC_WFIDrvHandle hWFIDrv, u8 *pu8ScanSource) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ + + strWID.u16WIDid = (u16)WID_START_SCAN_REQ; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = (s8 *)pu8ScanSource; + strWID.s32ValueSize = sizeof(char); + + return s32Error; +} + +/** + * @brief host_int_set_join_req + * @details sets a join request + * @param[in,out] handle to the wifi driver, + * @param[in] Index of the bss descriptor + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_set_join_req(WILC_WFIDrvHandle hWFIDrv, u8 *pu8bssid, + const u8 *pu8ssid, size_t ssidLen, + const u8 *pu8IEs, size_t IEsLen, + tWILCpfConnectResult pfConnectResult, void *pvUserArg, + u8 u8security, AUTHTYPE_T tenuAuth_type, + u8 u8channel, + void *pJoinParams) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tenuScanConnTimer enuScanConnTimer; + + if (pstrWFIDrv == NULL || pfConnectResult == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + if (hWFIDrv == NULL) { + PRINT_ER("Driver not initialized: gWFiDrvHandle = NULL\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + if (pJoinParams == NULL) { + PRINT_ER("Unable to Join - JoinParams is NULL\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + + } +/* + * if(gWFiDrvHandle->strWILC_UsrScanReq.u32RcvdChCount == 0) + * { + * PRINT_ER("No scan results exist: Scanning should be done\n"); + * WILC_ERRORREPORT(s32Error, WILC_FAIL); + * } + */ + /* prepare the Connect Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_CONNECT; + + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.u8security = u8security; + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.tenuAuth_type = tenuAuth_type; + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.u8channel = u8channel; + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.pfConnectResult = pfConnectResult; + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.pvUserArg = pvUserArg; + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.pJoinParams = pJoinParams; + strHostIFmsg.drvHandler = hWFIDrv; + + if (pu8bssid != NULL) { + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.pu8bssid = (u8 *)WILC_MALLOC(6); /* will be deallocated by the receiving thread */ + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.pu8bssid, + pu8bssid, 6); + } + + if (pu8ssid != NULL) { + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.ssidLen = ssidLen; + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.pu8ssid = (u8 *)WILC_MALLOC(ssidLen); /* will be deallocated by the receiving thread */ + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.pu8ssid, + + pu8ssid, ssidLen); + } + + if (pu8IEs != NULL) { + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.IEsLen = IEsLen; + strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.pu8IEs = (u8 *)WILC_MALLOC(IEsLen); /* will be deallocated by the receiving thread */ + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.pu8IEs, + pu8IEs, IEsLen); + } + if (pstrWFIDrv->enuHostIFstate < HOST_IF_CONNECTING) { + pstrWFIDrv->enuHostIFstate = HOST_IF_CONNECTING; + } else + PRINT_D(GENERIC_DBG, "Don't set state to 'connecting' as state is %d\n", pstrWFIDrv->enuHostIFstate); + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Failed to send message queue: Set join request\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + enuScanConnTimer = CONNECT_TIMER; + WILC_TimerStart(&(pstrWFIDrv->hConnectTimer), HOST_IF_CONNECT_TIMEOUT, (void *) hWFIDrv, NULL); + + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief Flush a join request parameters to FW, but actual connection + * @details The function is called in situation where WILC is connected to AP and + * required to switch to hybrid FW for P2P connection + * @param[in] handle to the wifi driver, + * @return Error code indicating success/failure + * @note + * @author Amr Abdel-Moghny + * @date 19 DEC 2013 + * @version 8.0 + */ + +s32 host_int_flush_join_req(WILC_WFIDrvHandle hWFIDrv) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + + if (!gu8FlushedJoinReq) { + s32Error = WILC_FAIL; + return s32Error; + } + + + if (hWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + + strHostIFmsg.u16MsgId = HOST_IF_MSG_FLUSH_CONNECT; + strHostIFmsg.drvHandler = hWFIDrv; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Failed to send message queue: Flush join request\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + WILC_CATCH(s32Error) + { + + } + return s32Error; +} + +/** + * @brief host_int_disconnect + * @details disconnects from the currently associated network + * @param[in,out] handle to the wifi driver, + * @param[in] Reason Code of the Disconnection + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_disconnect(WILC_WFIDrvHandle hWFIDrv, u16 u16ReasonCode) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + if (pstrWFIDrv == NULL) { + PRINT_ER("gWFiDrvHandle = NULL\n"); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + /* prepare the Disconnect Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_DISCONNECT; + strHostIFmsg.drvHandler = hWFIDrv; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) + PRINT_ER("Failed to send message queue: disconnect\n"); + /* ////////////// */ + down(&(pstrWFIDrv->hSemTestDisconnectBlock)); + /* /////// */ + + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief host_int_disconnect_station + * @details disconnects a sta + * @param[in,out] handle to the wifi driver, + * @param[in] Association Id of the station to be disconnected + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_disconnect_station(WILC_WFIDrvHandle hWFIDrv, u8 assoc_id) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ + + strWID.u16WIDid = (u16)WID_DISCONNECT; + strWID.enuWIDtype = WID_CHAR; + strWID.ps8WidVal = (s8 *)&assoc_id; + strWID.s32ValueSize = sizeof(char); + + return s32Error; +} + +/** + * @brief host_int_get_assoc_req_info + * @details gets a Association request info + * @param[in,out] handle to the wifi driver, + * Message containg assoc. req info in the following format + * ------------------------------------------------------------------------ + | Management Frame Format | + ||-------------------------------------------------------------------| + ||Frame Control|Duration|DA|SA|BSSID|Sequence Control|Frame Body|FCS | + ||-------------|--------|--|--|-----|----------------|----------|----| + | 2 |2 |6 |6 |6 | 2 |0 - 2312 | 4 | + ||-------------------------------------------------------------------| + | | + | Association Request Frame - Frame Body | + ||-------------------------------------------------------------------| + | Capability Information | Listen Interval | SSID | Supported Rates | + ||------------------------|-----------------|------|-----------------| + | 2 | 2 | 2-34 | 3-10 | + | --------------------------------------------------------------------- + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ + +s32 host_int_get_assoc_req_info(WILC_WFIDrvHandle hWFIDrv, u8 *pu8AssocReqInfo, + u32 u32AssocReqInfoLen) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ + + strWID.u16WIDid = (u16)WID_ASSOC_REQ_INFO; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = pu8AssocReqInfo; + strWID.s32ValueSize = u32AssocReqInfoLen; + + + return s32Error; +} + +/** + * @brief gets a Association Response info + * @details + * @param[in,out] handle to the wifi driver, + * Message containg assoc. resp info + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_get_assoc_res_info(WILC_WFIDrvHandle hWFIDrv, u8 *pu8AssocRespInfo, + u32 u32MaxAssocRespInfoLen, u32 *pu32RcvdAssocRespInfoLen) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + strWID.u16WIDid = (u16)WID_ASSOC_RES_INFO; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = pu8AssocRespInfo; + strWID.s32ValueSize = u32MaxAssocRespInfoLen; + + + /* Sending Configuration packet */ + s32Error = SendConfigPkt(GET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Failed to send association response config packet\n"); + *pu32RcvdAssocRespInfoLen = 0; + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } else { + *pu32RcvdAssocRespInfoLen = strWID.s32ValueSize; + } + + WILC_CATCH(s32Error) + { + + } + return s32Error; +} + +/** + * @brief gets a Association Response info + * @details Valid only in STA mode. This function gives the RSSI + * values observed in all the channels at the time of scanning. + * The length of the field is 1 greater that the total number of + * channels supported. Byte 0 contains the number of channels while + * each of Byte N contains the observed RSSI value for the channel index N. + * @param[in,out] handle to the wifi driver, + * array of scanned channels' RSSI + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_get_rx_power_level(WILC_WFIDrvHandle hWFIDrv, u8 *pu8RxPowerLevel, + u32 u32RxPowerLevelLen) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ + + strWID.u16WIDid = (u16)WID_RX_POWER_LEVEL; + strWID.enuWIDtype = WID_STR; + strWID.ps8WidVal = pu8RxPowerLevel; + strWID.s32ValueSize = u32RxPowerLevelLen; + + + return s32Error; +} + +/** + * @brief sets a channel + * @details + * @param[in,out] handle to the wifi driver, + * @param[in] Index of the channel to be set + *|-------------------------------------------------------------------| + | CHANNEL1 CHANNEL2 .... CHANNEL14 | + | Input: 1 2 14 | + ||-------------------------------------------------------------------| + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_set_mac_chnl_num(WILC_WFIDrvHandle hWFIDrv, u8 u8ChNum) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + /* prepare the set channel message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_CHANNEL; + strHostIFmsg.uniHostIFmsgBody.strHostIFSetChan.u8SetChan = u8ChNum; + strHostIFmsg.drvHandler = hWFIDrv; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + + +s32 host_int_wait_msg_queue_idle(void) +{ + s32 s32Error = WILC_SUCCESS; + + tstrHostIFmsg strHostIFmsg; + + /* prepare the set driver handler message */ + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + strHostIFmsg.u16MsgId = HOST_IF_MSG_Q_IDLE; + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + /* wait untill MSG Q is empty */ + down(&hWaitResponse); + + return s32Error; + +} + +s32 host_int_set_wfi_drv_handler(u32 u32address) +{ + s32 s32Error = WILC_SUCCESS; + + tstrHostIFmsg strHostIFmsg; + + + /* prepare the set driver handler message */ + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_WFIDRV_HANDLER; + strHostIFmsg.uniHostIFmsgBody.strHostIfSetDrvHandler.u32Address = u32address; + /* strHostIFmsg.drvHandler=hWFIDrv; */ + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + + + +s32 host_int_set_operation_mode(WILC_WFIDrvHandle hWFIDrv, u32 u32mode) +{ + s32 s32Error = WILC_SUCCESS; + + tstrHostIFmsg strHostIFmsg; + + + /* prepare the set driver handler message */ + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_OPERATION_MODE; + strHostIFmsg.uniHostIFmsgBody.strHostIfSetOperationMode.u32Mode = u32mode; + strHostIFmsg.drvHandler = hWFIDrv; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief gets the current channel index + * @details + * @param[in,out] handle to the wifi driver, + * current channel index + *|-----------------------------------------------------------------------| + | CHANNEL1 CHANNEL2 .... CHANNEL14 | + | Input: 1 2 14 | + ||-----------------------------------------------------------------------| + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_get_host_chnl_num(WILC_WFIDrvHandle hWFIDrv, u8 *pu8ChNo) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + /* prepare the Get Channel Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_CHNL; + strHostIFmsg.drvHandler = hWFIDrv; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) + PRINT_ER("Failed to send get host channel param's message queue "); + down(&(pstrWFIDrv->hSemGetCHNL)); + /* gu8Chnl = 11; */ + + *pu8ChNo = gu8Chnl; + + WILC_CATCH(s32Error) + { + } + + return s32Error; + + +} + + +/** + * @brief host_int_test_set_int_wid + * @details Test function for setting wids + * @param[in,out] WILC_WFIDrvHandle hWFIDrv, u32 u32TestMemAddr + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_test_set_int_wid(WILC_WFIDrvHandle hWFIDrv, u32 u32TestMemAddr) +{ + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + + + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + /*prepare configuration packet*/ + strWID.u16WIDid = (u16)WID_MEMORY_ADDRESS; + strWID.enuWIDtype = WID_INT; + strWID.ps8WidVal = (char *)&u32TestMemAddr; + strWID.s32ValueSize = sizeof(u32); + + /*Sending Cfg*/ + s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + if (s32Error) { + PRINT_ER("Test Function: Failed to set wid value\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } else { + PRINT_D(HOSTINF_DBG, "Successfully set wid value\n"); + + } + + WILC_CATCH(s32Error) + { + + } + return s32Error; +} + +#ifdef WILC_AP_EXTERNAL_MLME +/** + * @brief host_int_get_inactive_time + * @details + * @param[in,out] handle to the wifi driver, + * current sta macaddress, inactive_time + * @return + * @note + * @author + * @date + * @version 1.0 + */ +s32 host_int_get_inactive_time(WILC_WFIDrvHandle hWFIDrv, const u8 *mac, u32 *pu32InactiveTime) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIfStaInactiveT.mac, + mac, ETH_ALEN); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_INACTIVETIME; + strHostIFmsg.drvHandler = hWFIDrv; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) + PRINT_ER("Failed to send get host channel param's message queue "); + + down(&(pstrWFIDrv->hSemInactiveTime)); + + *pu32InactiveTime = gu32InactiveTime; + + WILC_CATCH(s32Error) + { + } + + return s32Error; +} +#endif +/** + * @brief host_int_test_get_int_wid + * @details Test function for getting wids + * @param[in,out] WILC_WFIDrvHandle hWFIDrv, u32* pu32TestMemAddr + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_test_get_int_wid(WILC_WFIDrvHandle hWFIDrv, u32 *pu32TestMemAddr) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWID strWID; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + + + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + strWID.u16WIDid = (u16)WID_MEMORY_ADDRESS; + strWID.enuWIDtype = WID_INT; + strWID.ps8WidVal = (s8 *)pu32TestMemAddr; + strWID.s32ValueSize = sizeof(u32); + + s32Error = SendConfigPkt(GET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); + /*get the value by searching the local copy*/ + if (s32Error) { + PRINT_ER("Test Function: Failed to get wid value\n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); + } else { + PRINT_D(HOSTINF_DBG, "Successfully got wid value\n"); + + } + + WILC_CATCH(s32Error) + { + + } + return s32Error; +} + + +/** + * @brief host_int_get_rssi + * @details gets the currently maintained RSSI value for the station. + * The received signal strength value in dB. + * The range of valid values is -128 to 0. + * @param[in,out] handle to the wifi driver, + * rssi value in dB + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_get_rssi(WILC_WFIDrvHandle hWFIDrv, s8 *ps8Rssi) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + + + /* prepare the Get RSSI Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_RSSI; + strHostIFmsg.drvHandler = hWFIDrv; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Failed to send get host channel param's message queue "); + return WILC_FAIL; + } + + down(&(pstrWFIDrv->hSemGetRSSI)); + + + if (ps8Rssi == NULL) { + PRINT_ER("RSS pointer value is null"); + return WILC_FAIL; + } + + + *ps8Rssi = gs8Rssi; + + + return s32Error; +} + +s32 host_int_get_link_speed(WILC_WFIDrvHandle hWFIDrv, s8 *ps8lnkspd) +{ + tstrHostIFmsg strHostIFmsg; + s32 s32Error = WILC_SUCCESS; + + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + + + + /* prepare the Get LINKSPEED Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_LINKSPEED; + strHostIFmsg.drvHandler = hWFIDrv; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Failed to send GET_LINKSPEED to message queue "); + return WILC_FAIL; + } + + down(&(pstrWFIDrv->hSemGetLINKSPEED)); + + + if (ps8lnkspd == NULL) { + PRINT_ER("LINKSPEED pointer value is null"); + return WILC_FAIL; + } + + + *ps8lnkspd = gs8lnkspd; + + + return s32Error; +} + +s32 host_int_get_statistics(WILC_WFIDrvHandle hWFIDrv, tstrStatistics *pstrStatistics) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + + + /* prepare the Get RSSI Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_STATISTICS; + strHostIFmsg.uniHostIFmsgBody.pUserData = (char *)pstrStatistics; + strHostIFmsg.drvHandler = hWFIDrv; + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Failed to send get host channel param's message queue "); + return WILC_FAIL; + } + + down(&hWaitResponse); + return s32Error; +} + + +/** + * @brief host_int_scan + * @details scans a set of channels + * @param[in,out] handle to the wifi driver, + * @param[in] Scan source + * Scan Type PASSIVE_SCAN = 0, + * ACTIVE_SCAN = 1 + * Channels Array + * Channels Array length + * Scan Callback function + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 host_int_scan(WILC_WFIDrvHandle hWFIDrv, u8 u8ScanSource, + u8 u8ScanType, u8 *pu8ChnlFreqList, + u8 u8ChnlListLen, const u8 *pu8IEs, + size_t IEsLen, tWILCpfScanResult ScanResult, + void *pvUserArg, tstrHiddenNetwork *pstrHiddenNetwork) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tenuScanConnTimer enuScanConnTimer; + + if (pstrWFIDrv == NULL || ScanResult == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + + /* prepare the Scan Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_SCAN; + + if (pstrHiddenNetwork != NULL) { + strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.strHiddenNetwork.pstrHiddenNetworkInfo = pstrHiddenNetwork->pstrHiddenNetworkInfo; + strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.strHiddenNetwork.u8ssidnum = pstrHiddenNetwork->u8ssidnum; + + } else + PRINT_D(HOSTINF_DBG, "pstrHiddenNetwork IS EQUAL TO NULL\n"); + + strHostIFmsg.drvHandler = hWFIDrv; + strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.u8ScanSource = u8ScanSource; + strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.u8ScanType = u8ScanType; + strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.pfScanResult = ScanResult; + strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.pvUserArg = pvUserArg; + + strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.u8ChnlListLen = u8ChnlListLen; + strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.pu8ChnlFreqList = (u8 *)WILC_MALLOC(u8ChnlListLen); /* will be deallocated by the receiving thread */ + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.pu8ChnlFreqList, + pu8ChnlFreqList, u8ChnlListLen); + + strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.IEsLen = IEsLen; + strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.pu8IEs = (u8 *)WILC_MALLOC(IEsLen); /* will be deallocated by the receiving thread */ + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFscanAttr.pu8IEs, + pu8IEs, IEsLen); + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Error in sending message queue scanning parameters: Error(%d)\n", s32Error); + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + enuScanConnTimer = SCAN_TIMER; + PRINT_D(HOSTINF_DBG, ">> Starting the SCAN timer\n"); + WILC_TimerStart(&(pstrWFIDrv->hScanTimer), HOST_IF_SCAN_TIMEOUT, (void *) hWFIDrv, NULL); + + + WILC_CATCH(s32Error) + { + + } + return s32Error; + +} +/** + * @brief hif_set_cfg + * @details sets configuration wids values + * @param[in,out] handle to the wifi driver, + * @param[in] WID, WID value + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +s32 hif_set_cfg(WILC_WFIDrvHandle hWFIDrv, tstrCfgParamVal *pstrCfgParamVal) +{ + + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + + tstrHostIFmsg strHostIFmsg; + + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + /* prepare the WiphyParams Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + strHostIFmsg.u16MsgId = HOST_IF_MSG_CFG_PARAMS; + strHostIFmsg.uniHostIFmsgBody.strHostIFCfgParamAttr.pstrCfgParamVal = *pstrCfgParamVal; + strHostIFmsg.drvHandler = hWFIDrv; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + + WILC_CATCH(s32Error) + { + } + + return s32Error; + +} + + +/** + * @brief hif_get_cfg + * @details gets configuration wids values + * @param[in,out] handle to the wifi driver, + * WID value + * @param[in] WID, + * @return Error code indicating success/failure + * @note + * @author zsalah + * + * @date 8 March 2012 + * @version 1.0 + */ +s32 hif_get_cfg(WILC_WFIDrvHandle hWFIDrv, u16 u16WID, u16 *pu16WID_Value) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + + down(&(pstrWFIDrv->gtOsCfgValuesSem)); + + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + PRINT_D(HOSTINF_DBG, "Getting configuration parameters\n"); + switch (u16WID) { + + case WID_BSS_TYPE: + *pu16WID_Value = (u16)pstrWFIDrv->strCfgValues.bss_type; + break; + + case WID_AUTH_TYPE: + *pu16WID_Value = (u16)pstrWFIDrv->strCfgValues.auth_type; + break; + + case WID_AUTH_TIMEOUT: + *pu16WID_Value = pstrWFIDrv->strCfgValues.auth_timeout; + break; + + case WID_POWER_MANAGEMENT: + *pu16WID_Value = (u16)pstrWFIDrv->strCfgValues.power_mgmt_mode; + break; + + case WID_SHORT_RETRY_LIMIT: + *pu16WID_Value = pstrWFIDrv->strCfgValues.short_retry_limit; + break; + + case WID_LONG_RETRY_LIMIT: + *pu16WID_Value = pstrWFIDrv->strCfgValues.long_retry_limit; + break; + + case WID_FRAG_THRESHOLD: + *pu16WID_Value = pstrWFIDrv->strCfgValues.frag_threshold; + break; + + case WID_RTS_THRESHOLD: + *pu16WID_Value = pstrWFIDrv->strCfgValues.rts_threshold; + break; + + case WID_PREAMBLE: + *pu16WID_Value = (u16)pstrWFIDrv->strCfgValues.preamble_type; + break; + + case WID_SHORT_SLOT_ALLOWED: + *pu16WID_Value = (u16) pstrWFIDrv->strCfgValues.short_slot_allowed; + break; + + case WID_11N_TXOP_PROT_DISABLE: + *pu16WID_Value = (u16)pstrWFIDrv->strCfgValues.txop_prot_disabled; + break; + + case WID_BEACON_INTERVAL: + *pu16WID_Value = pstrWFIDrv->strCfgValues.beacon_interval; + break; + + case WID_DTIM_PERIOD: + *pu16WID_Value = (u16)pstrWFIDrv->strCfgValues.dtim_period; + break; + + case WID_SITE_SURVEY: + *pu16WID_Value = (u16)pstrWFIDrv->strCfgValues.site_survey_enabled; + break; + + case WID_SITE_SURVEY_SCAN_TIME: + *pu16WID_Value = pstrWFIDrv->strCfgValues.site_survey_scan_time; + break; + + case WID_ACTIVE_SCAN_TIME: + *pu16WID_Value = pstrWFIDrv->strCfgValues.active_scan_time; + break; + + case WID_PASSIVE_SCAN_TIME: + *pu16WID_Value = pstrWFIDrv->strCfgValues.passive_scan_time; + break; + + case WID_CURRENT_TX_RATE: + *pu16WID_Value = pstrWFIDrv->strCfgValues.curr_tx_rate; + break; + + default: + break; + } + + up(&(pstrWFIDrv->gtOsCfgValuesSem)); + + WILC_CATCH(s32Error) + { + } + return s32Error; + +} + +/*****************************************************************************/ +/* Notification Functions */ +/*****************************************************************************/ +/** + * @brief notifies host with join and leave requests + * @details This function prepares an Information frame having the + * information about a joining/leaving station. + * @param[in,out] handle to the wifi driver, + * @param[in] 6 byte Sta Adress + * Join or leave flag: + * Join = 1, + * Leave =0 + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +void host_int_send_join_leave_info_to_host + (u16 assocId, u8 *stationAddr, bool joining) +{ +} +/** + * @brief notifies host with stations found in scan + * @details sends the beacon/probe response from scan + * @param[in,out] handle to the wifi driver, + * @param[in] Sta Address, + * Frame length, + * Rssi of the Station found + * @return Error code indicating success/failure + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ + +void GetPeriodicRSSI(void *pvArg) +{ + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)pvArg; + if (pstrWFIDrv == NULL) { + PRINT_ER("Driver handler is NULL\n"); + return; + } + + if (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTED) { + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + + /* prepare the Get RSSI Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_RSSI; + strHostIFmsg.drvHandler = pstrWFIDrv; + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Failed to send get host channel param's message queue "); + return; + } + } + WILC_TimerStart(&(g_hPeriodicRSSI), 5000, (void *)pstrWFIDrv, NULL); +} + + +void host_int_send_network_info_to_host + (u8 *macStartAddress, u16 u16RxFrameLen, s8 s8Rssi) +{ +} +/** + * @brief host_int_init + * @details host interface initialization function + * @param[in,out] handle to the wifi driver, + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ +static u32 u32Intialized; +static u32 msgQ_created; +static u32 clients_count; + +s32 host_int_init(WILC_WFIDrvHandle *phWFIDrv) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv; + + /*if(u32Intialized == 1) + * { + * PRINT_D(HOSTINF_DBG,"Host interface is previously initialized\n"); + * *phWFIDrv = (WILC_WFIDrvHandle)gWFiDrvHandle; //Will be adjusted later for P2P + * return 0; + * } */ + PRINT_D(HOSTINF_DBG, "Initializing host interface for client %d\n", clients_count + 1); + + gbScanWhileConnected = false; + + sema_init(&hWaitResponse, 0); + + + + /*Allocate host interface private structure*/ + pstrWFIDrv = (tstrWILC_WFIDrv *)WILC_MALLOC(sizeof(tstrWILC_WFIDrv)); + if (pstrWFIDrv == NULL) { + /* WILC_ERRORREPORT(s32Error,WILC_NO_MEM); */ + s32Error = WILC_NO_MEM; + PRINT_ER("Failed to allocate memory\n"); + goto _fail_timer_2; + } + WILC_memset(pstrWFIDrv, 0, sizeof(tstrWILC_WFIDrv)); + /*return driver handle to user*/ + *phWFIDrv = (WILC_WFIDrvHandle)pstrWFIDrv; + /*save into globl handle*/ + + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + + g_obtainingIP = false; + #endif + + PRINT_D(HOSTINF_DBG, "Global handle pointer value=%p\n", pstrWFIDrv); + /* /////////////////////////////////////// */ + if (clients_count == 0) { + sema_init(&hSemHostIFthrdEnd, 0); + sema_init(&hSemDeinitDrvHandle, 0); + /*BugID_5348*/ + sema_init(&hSemHostIntDeinit, 1); + } + + sema_init(&(pstrWFIDrv->hSemTestKeyBlock), 0); + sema_init(&(pstrWFIDrv->hSemTestDisconnectBlock), 0); + sema_init(&(pstrWFIDrv->hSemGetRSSI), 0); + sema_init(&(pstrWFIDrv->hSemGetLINKSPEED), 0); + sema_init(&(pstrWFIDrv->hSemGetCHNL), 0); + sema_init(&(pstrWFIDrv->hSemInactiveTime), 0); + + /* /////////////////////////////////////// */ + + + + PRINT_D(HOSTINF_DBG, "INIT: CLIENT COUNT %d\n", clients_count); + + if (clients_count == 0) { + + s32Error = WILC_MsgQueueCreate(&gMsgQHostIF, NULL); + + + if (s32Error < 0) { + PRINT_ER("Failed to creat MQ\n"); + goto _fail_; + } + msgQ_created = 1; + HostIFthreadHandler = kthread_run(hostIFthread, NULL, "WILC_kthread"); + if (IS_ERR(HostIFthreadHandler)) { + PRINT_ER("Failed to creat Thread\n"); + s32Error = WILC_FAIL; + goto _fail_mq_; + } + s32Error = WILC_TimerCreate(&(g_hPeriodicRSSI), GetPeriodicRSSI, NULL); + if (s32Error < 0) { + PRINT_ER("Failed to creat Timer\n"); + goto _fail_timer_1; + } + WILC_TimerStart(&(g_hPeriodicRSSI), 5000, (void *)pstrWFIDrv, NULL); + + } + + + s32Error = WILC_TimerCreate(&(pstrWFIDrv->hScanTimer), TimerCB_Scan, NULL); + if (s32Error < 0) { + PRINT_ER("Failed to creat Timer\n"); + goto _fail_thread_; + } + + s32Error = WILC_TimerCreate(&(pstrWFIDrv->hConnectTimer), TimerCB_Connect, NULL); + if (s32Error < 0) { + PRINT_ER("Failed to creat Timer\n"); + goto _fail_timer_1; + } + + + #ifdef WILC_P2P + /*Remain on channel timer*/ + s32Error = WILC_TimerCreate(&(pstrWFIDrv->hRemainOnChannel), ListenTimerCB, NULL); + if (s32Error < 0) { + PRINT_ER("Failed to creat Remain-on-channel Timer\n"); + goto _fail_timer_3; + } + #endif + + sema_init(&(pstrWFIDrv->gtOsCfgValuesSem), 1); + down(&(pstrWFIDrv->gtOsCfgValuesSem)); + + + +#ifdef SIMULATION + TransportInit(); +#endif + + pstrWFIDrv->enuHostIFstate = HOST_IF_IDLE; + /* gWFiDrvHandle->bPendingConnRequest = false; */ + + /*Initialize CFG WIDS Defualt Values*/ + + pstrWFIDrv->strCfgValues.site_survey_enabled = SITE_SURVEY_OFF; + pstrWFIDrv->strCfgValues.scan_source = DEFAULT_SCAN; + pstrWFIDrv->strCfgValues.active_scan_time = ACTIVE_SCAN_TIME; + pstrWFIDrv->strCfgValues.passive_scan_time = PASSIVE_SCAN_TIME; + pstrWFIDrv->strCfgValues.curr_tx_rate = AUTORATE; + + + #ifdef WILC_P2P + + pstrWFIDrv->u64P2p_MgmtTimeout = 0; + + #endif + + PRINT_INFO(HOSTINF_DBG, "Initialization values, Site survey value: %d\n Scan source: %d\n Active scan time: %d\n Passive scan time: %d\nCurrent tx Rate = %d\n", + + pstrWFIDrv->strCfgValues.site_survey_enabled, pstrWFIDrv->strCfgValues.scan_source, + pstrWFIDrv->strCfgValues.active_scan_time, pstrWFIDrv->strCfgValues.passive_scan_time, + pstrWFIDrv->strCfgValues.curr_tx_rate); + + + up(&(pstrWFIDrv->gtOsCfgValuesSem)); + + /*TODO Code to setup simulation to be removed later*/ + /*Intialize configurator module*/ + s32Error = CoreConfiguratorInit(); + if (s32Error < 0) { + PRINT_ER("Failed to initialize core configurator\n"); + goto _fail_mem_; + } + +#ifdef SIMULATION + /*Initialize Simulaor*/ + CoreConfigSimulatorInit(); +#endif + + u32Intialized = 1; + clients_count++; /* increase number of created entities */ + + return s32Error; + + +_fail_mem_: + if (pstrWFIDrv != NULL) + WILC_FREE(pstrWFIDrv); +#ifdef WILC_P2P +_fail_timer_3: + WILC_TimerDestroy(&(pstrWFIDrv->hRemainOnChannel), NULL); +#endif +_fail_timer_2: + up(&(pstrWFIDrv->gtOsCfgValuesSem)); + WILC_TimerDestroy(&(pstrWFIDrv->hConnectTimer), NULL); +_fail_timer_1: + WILC_TimerDestroy(&(pstrWFIDrv->hScanTimer), NULL); +_fail_thread_: + kthread_stop(HostIFthreadHandler); +_fail_mq_: + WILC_MsgQueueDestroy(&gMsgQHostIF, NULL); +_fail_: + return s32Error; + + +} +/** + * @brief host_int_deinit + * @details host interface initialization function + * @param[in,out] handle to the wifi driver, + * @note + * @author zsalah + * @date 8 March 2012 + * @version 1.0 + */ + +s32 host_int_deinit(WILC_WFIDrvHandle hWFIDrv) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + + + /*obtain driver handle*/ + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + /*if(u32Intialized == 0) + * { + * PRINT_ER("Host Interface is not initialized\n"); + * return 0; + * }*/ + + /*BugID_5348*/ + + if (pstrWFIDrv == NULL) { + PRINT_ER("pstrWFIDrv = NULL\n"); + return 0; + } + + down(&hSemHostIntDeinit); + + terminated_handle = pstrWFIDrv; + PRINT_D(HOSTINF_DBG, "De-initializing host interface for client %d\n", clients_count); + + /*BugID_5348*/ + /*Destroy all timers before acquiring hSemDeinitDrvHandle*/ + /*to guarantee handling all messages befor proceeding*/ + if (WILC_TimerDestroy(&(pstrWFIDrv->hScanTimer), NULL)) { + PRINT_D(HOSTINF_DBG, ">> Scan timer is active \n"); + /* msleep(HOST_IF_SCAN_TIMEOUT+1000); */ + } + + if (WILC_TimerDestroy(&(pstrWFIDrv->hConnectTimer), NULL)) { + PRINT_D(HOSTINF_DBG, ">> Connect timer is active \n"); + /* msleep(HOST_IF_CONNECT_TIMEOUT+1000); */ + } + + + if (WILC_TimerDestroy(&(g_hPeriodicRSSI), NULL)) { + PRINT_D(HOSTINF_DBG, ">> Connect timer is active \n"); + /* msleep(HOST_IF_CONNECT_TIMEOUT+1000); */ + } + + #ifdef WILC_P2P + /*Destroy Remain-onchannel Timer*/ + WILC_TimerDestroy(&(pstrWFIDrv->hRemainOnChannel), NULL); + #endif + + host_int_set_wfi_drv_handler((u32)NULL); + down(&hSemDeinitDrvHandle); + + + /*Calling the CFG80211 scan done function with the abort flag set to true*/ + if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { + pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult(SCAN_EVENT_ABORTED, NULL, + pstrWFIDrv->strWILC_UsrScanReq.u32UserScanPvoid, NULL); + + pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult = NULL; + } + /*deinit configurator and simulator*/ +#ifdef SIMULATION + CoreConfigSimulatorDeInit(); +#endif + CoreConfiguratorDeInit(); +#ifdef SIMULATION + TransportDeInit(); +#endif + + pstrWFIDrv->enuHostIFstate = HOST_IF_IDLE; + + gbScanWhileConnected = false; + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + if (clients_count == 1) { + if (WILC_TimerDestroy(&g_hPeriodicRSSI, NULL)) { + PRINT_D(HOSTINF_DBG, ">> Connect timer is active \n"); + /* msleep(HOST_IF_CONNECT_TIMEOUT+1000); */ + } + strHostIFmsg.u16MsgId = HOST_IF_MSG_EXIT; + strHostIFmsg.drvHandler = hWFIDrv; + + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error != WILC_SUCCESS) { + PRINT_ER("Error in sending deinit's message queue message function: Error(%d)\n", s32Error); + } + + down(&hSemHostIFthrdEnd); + + + + WILC_MsgQueueDestroy(&gMsgQHostIF, NULL); + msgQ_created = 0; + } + + down(&(pstrWFIDrv->gtOsCfgValuesSem)); + + /*Setting the gloabl driver handler with NULL*/ + u32Intialized = 0; + /* gWFiDrvHandle = NULL; */ + if (pstrWFIDrv != NULL) { + WILC_FREE(pstrWFIDrv); + /* pstrWFIDrv=NULL; */ + + } + + clients_count--; /* Decrease number of created entities */ + terminated_handle = NULL; + up(&hSemHostIntDeinit); + return s32Error; +} + + +/** + * @brief NetworkInfoReceived + * @details function to to be called when network info packet is received + * @param[in] pu8Buffer the received packet + * @param[in] u32Length length of the received packet + * @return none + * @note + * @author + * @date 1 Mar 2012 + * @version 1.0 + */ +void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + u32 drvHandler; + tstrWILC_WFIDrv *pstrWFIDrv = NULL; + + drvHandler = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24)); + pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + + + + if (pstrWFIDrv == NULL || pstrWFIDrv == terminated_handle) { + PRINT_ER("NetworkInfo received but driver not init[%p]\n", pstrWFIDrv); + return; + } + + /* prepare the Asynchronous Network Info message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_RCVD_NTWRK_INFO; + strHostIFmsg.drvHandler = pstrWFIDrv; + + strHostIFmsg.uniHostIFmsgBody.strRcvdNetworkInfo.u32Length = u32Length; + strHostIFmsg.uniHostIFmsgBody.strRcvdNetworkInfo.pu8Buffer = (u8 *)WILC_MALLOC(u32Length); /* will be deallocated by the receiving thread */ + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strRcvdNetworkInfo.pu8Buffer, + pu8Buffer, u32Length); + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Error in sending network info message queue message parameters: Error(%d)\n", s32Error); + } + + + return; +} + +/** + * @brief GnrlAsyncInfoReceived + * @details function to be called when general Asynchronous info packet is received + * @param[in] pu8Buffer the received packet + * @param[in] u32Length length of the received packet + * @return none + * @note + * @author + * @date 15 Mar 2012 + * @version 1.0 + */ +void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + u32 drvHandler; + tstrWILC_WFIDrv *pstrWFIDrv = NULL; + + /*BugID_5348*/ + down(&hSemHostIntDeinit); + + drvHandler = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24)); + pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + PRINT_D(HOSTINF_DBG, "General asynchronous info packet received \n"); + + + if (pstrWFIDrv == NULL || pstrWFIDrv == terminated_handle) { + PRINT_D(HOSTINF_DBG, "Wifi driver handler is equal to NULL\n"); + /*BugID_5348*/ + up(&hSemHostIntDeinit); + return; + } + + if (pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult == NULL) { + /* received mac status is not needed when there is no current Connect Request */ + PRINT_ER("Received mac status is not needed when there is no current Connect Reques\n"); + /*BugID_5348*/ + up(&hSemHostIntDeinit); + return; + } + + /* prepare the General Asynchronous Info message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + + strHostIFmsg.u16MsgId = HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO; + strHostIFmsg.drvHandler = pstrWFIDrv; + + + strHostIFmsg.uniHostIFmsgBody.strRcvdGnrlAsyncInfo.u32Length = u32Length; + strHostIFmsg.uniHostIFmsgBody.strRcvdGnrlAsyncInfo.pu8Buffer = (u8 *)WILC_MALLOC(u32Length); /* will be deallocated by the receiving thread */ + WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strRcvdGnrlAsyncInfo.pu8Buffer, + pu8Buffer, u32Length); + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Error in sending message queue asynchronous message info: Error(%d)\n", s32Error); + } + + /*BugID_5348*/ + up(&hSemHostIntDeinit); + return; +} + +/** + * @brief host_int_ScanCompleteReceived + * @details Setting scan complete received notifcation in message queue + * @param[in] u8* pu8Buffer, u32 u32Length + * @return Error code. + * @author + * @date + * @version 1.0 + */ +void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length) +{ + s32 s32Error = WILC_SUCCESS; + tstrHostIFmsg strHostIFmsg; + u32 drvHandler; + tstrWILC_WFIDrv *pstrWFIDrv = NULL; + drvHandler = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24)); + pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + + + PRINT_D(GENERIC_DBG, "Scan notification received %p\n", pstrWFIDrv); + + if (pstrWFIDrv == NULL || pstrWFIDrv == terminated_handle) { + return; + } + + /*if there is an ongoing scan request*/ + if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { + /* prepare theScan Done message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + strHostIFmsg.u16MsgId = HOST_IF_MSG_RCVD_SCAN_COMPLETE; + strHostIFmsg.drvHandler = pstrWFIDrv; + + + /* will be deallocated by the receiving thread */ + /*no need to send message body*/ + + /*strHostIFmsg.uniHostIFmsgBody.strScanComplete.u32Length = u32Length; + * strHostIFmsg.uniHostIFmsgBody.strScanComplete.pu8Buffer = (u8*)WILC_MALLOC(u32Length); + * WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strScanComplete.pu8Buffer, + * pu8Buffer, u32Length); */ + + /* send the message */ + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + PRINT_ER("Error in sending message queue scan complete parameters: Error(%d)\n", s32Error); + } + } + + + return; + +} + +#ifdef WILC_P2P +/** + * @brief host_int_remain_on_channel + * @details + * @param[in] Handle to wifi driver + * Duration to remain on channel + * Channel to remain on + * Pointer to fn to be called on receive frames in listen state + * Pointer to remain-on-channel expired fn + * Priv + * @return Error code. + * @author + * @date + * @version 1.0 + */ +s32 host_int_remain_on_channel(WILC_WFIDrvHandle hWFIDrv, u32 u32SessionID, u32 u32duration, u16 chan, tWILCpfRemainOnChanExpired RemainOnChanExpired, tWILCpfRemainOnChanReady RemainOnChanReady, void *pvUserArg) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + /* prepare the remainonchan Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_REMAIN_ON_CHAN; + strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.u16Channel = chan; + strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.pRemainOnChanExpired = RemainOnChanExpired; + strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.pRemainOnChanReady = RemainOnChanReady; + strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.pVoid = pvUserArg; + strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.u32duration = u32duration; + strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.u32ListenSessionID = u32SessionID; + strHostIFmsg.drvHandler = hWFIDrv; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + +/** + * @brief host_int_ListenStateExpired + * @details + * @param[in] Handle to wifi driver + * Duration to remain on channel + * Channel to remain on + * Pointer to fn to be called on receive frames in listen state + * Pointer to remain-on-channel expired fn + * Priv + * @return Error code. + * @author + * @date + * @version 1.0 + */ +s32 host_int_ListenStateExpired(WILC_WFIDrvHandle hWFIDrv, u32 u32SessionID) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + /*Stopping remain-on-channel timer*/ + WILC_TimerStop(&(pstrWFIDrv->hRemainOnChannel), NULL); + + /* prepare the timer fire Message */ + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + strHostIFmsg.u16MsgId = HOST_IF_MSG_LISTEN_TIMER_FIRED; + strHostIFmsg.drvHandler = hWFIDrv; + strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.u32ListenSessionID = u32SessionID; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + return s32Error; +} + +/** + * @brief host_int_frame_register + * @details + * @param[in] Handle to wifi driver + * @return Error code. + * @author + * @date + * @version 1.0*/ +s32 host_int_frame_register(WILC_WFIDrvHandle hWFIDrv, u16 u16FrameType, bool bReg) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_REGISTER_FRAME; + switch (u16FrameType) { + case ACTION: + PRINT_D(HOSTINF_DBG, "ACTION\n"); + strHostIFmsg.uniHostIFmsgBody.strHostIfRegisterFrame.u8Regid = ACTION_FRM_IDX; + break; + + case PROBE_REQ: + PRINT_D(HOSTINF_DBG, "PROBE REQ\n"); + strHostIFmsg.uniHostIFmsgBody.strHostIfRegisterFrame.u8Regid = PROBE_REQ_IDX; + break; + + default: + PRINT_D(HOSTINF_DBG, "Not valid frame type\n"); + break; + } + strHostIFmsg.uniHostIFmsgBody.strHostIfRegisterFrame.u16FrameType = u16FrameType; + strHostIFmsg.uniHostIFmsgBody.strHostIfRegisterFrame.bReg = bReg; + strHostIFmsg.drvHandler = hWFIDrv; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; + + +} +#endif + +#ifdef WILC_AP_EXTERNAL_MLME +/** + * @brief host_int_add_beacon + * @details Setting add beacon params in message queue + * @param[in] WILC_WFIDrvHandle hWFIDrv, u32 u32Interval, + * u32 u32DTIMPeriod,u32 u32HeadLen, u8* pu8Head, + * u32 u32TailLen, u8* pu8Tail + * @return Error code. + * @author + * @date + * @version 1.0 + */ +s32 host_int_add_beacon(WILC_WFIDrvHandle hWFIDrv, u32 u32Interval, + u32 u32DTIMPeriod, + u32 u32HeadLen, u8 *pu8Head, + u32 u32TailLen, u8 *pu8Tail) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tstrHostIFSetBeacon *pstrSetBeaconParam = &strHostIFmsg.uniHostIFmsgBody.strHostIFSetBeacon; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + PRINT_D(HOSTINF_DBG, "Setting adding beacon message queue params\n"); + + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_ADD_BEACON; + strHostIFmsg.drvHandler = hWFIDrv; + pstrSetBeaconParam->u32Interval = u32Interval; + pstrSetBeaconParam->u32DTIMPeriod = u32DTIMPeriod; + pstrSetBeaconParam->u32HeadLen = u32HeadLen; + pstrSetBeaconParam->pu8Head = (u8 *)WILC_MALLOC(u32HeadLen); + if (pstrSetBeaconParam->pu8Head == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + WILC_memcpy(pstrSetBeaconParam->pu8Head, pu8Head, u32HeadLen); + pstrSetBeaconParam->u32TailLen = u32TailLen; + + /* Bug 4599 : if tail length = 0 skip allocating & copying */ + if (u32TailLen > 0) { + pstrSetBeaconParam->pu8Tail = (u8 *)WILC_MALLOC(u32TailLen); + if (pstrSetBeaconParam->pu8Tail == NULL) { + WILC_ERRORREPORT(s32Error, WILC_NO_MEM); + } + WILC_memcpy(pstrSetBeaconParam->pu8Tail, pu8Tail, u32TailLen); + } else { + pstrSetBeaconParam->pu8Tail = NULL; + } + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + + WILC_CATCH(s32Error) + { + if (pstrSetBeaconParam->pu8Head != NULL) { + WILC_FREE(pstrSetBeaconParam->pu8Head); + } + + if (pstrSetBeaconParam->pu8Tail != NULL) { + WILC_FREE(pstrSetBeaconParam->pu8Tail); + } + } + + return s32Error; + +} + + +/** + * @brief host_int_del_beacon + * @details Setting add beacon params in message queue + * @param[in] WILC_WFIDrvHandle hWFIDrv + * @return Error code. + * @author + * @date + * @version 1.0 + */ +s32 host_int_del_beacon(WILC_WFIDrvHandle hWFIDrv) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_DEL_BEACON; + strHostIFmsg.drvHandler = hWFIDrv; + PRINT_D(HOSTINF_DBG, "Setting deleting beacon message queue params\n"); + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + WILC_ERRORCHECK(s32Error); + + WILC_CATCH(s32Error) + { + } + return s32Error; +} + + +/** + * @brief host_int_add_station + * @details Setting add station params in message queue + * @param[in] WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam* pstrStaParams + * @return Error code. + * @author + * @date + * @version 1.0 + */ +s32 host_int_add_station(WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam *pstrStaParams) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tstrWILC_AddStaParam *pstrAddStationMsg = &strHostIFmsg.uniHostIFmsgBody.strAddStaParam; + + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + PRINT_D(HOSTINF_DBG, "Setting adding station message queue params\n"); + + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_ADD_STATION; + strHostIFmsg.drvHandler = hWFIDrv; + + WILC_memcpy(pstrAddStationMsg, pstrStaParams, sizeof(tstrWILC_AddStaParam)); + if (pstrAddStationMsg->u8NumRates > 0) { + u8 *rates = WILC_MALLOC(pstrAddStationMsg->u8NumRates); + WILC_NULLCHECK(s32Error, rates); + + WILC_memcpy(rates, pstrStaParams->pu8Rates, pstrAddStationMsg->u8NumRates); + pstrAddStationMsg->pu8Rates = rates; + } + + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + + WILC_CATCH(s32Error) + { + } + return s32Error; +} + +/** + * @brief host_int_del_station + * @details Setting delete station params in message queue + * @param[in] WILC_WFIDrvHandle hWFIDrv, u8* pu8MacAddr + * @return Error code. + * @author + * @date + * @version 1.0 + */ +s32 host_int_del_station(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8MacAddr) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tstrHostIFDelSta *pstrDelStationMsg = &strHostIFmsg.uniHostIFmsgBody.strDelStaParam; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + PRINT_D(HOSTINF_DBG, "Setting deleting station message queue params\n"); + + + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_DEL_STATION; + strHostIFmsg.drvHandler = hWFIDrv; + + /*BugID_4795: Handling situation of deleting all stations*/ + if (pu8MacAddr == NULL) + WILC_memset(pstrDelStationMsg->au8MacAddr, 255, ETH_ALEN); + else + WILC_memcpy(pstrDelStationMsg->au8MacAddr, pu8MacAddr, ETH_ALEN); + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + + WILC_CATCH(s32Error) + { + } + return s32Error; +} +/** + * @brief host_int_del_allstation + * @details Setting del station params in message queue + * @param[in] WILC_WFIDrvHandle hWFIDrv, u8 pu8MacAddr[][ETH_ALEN]s + * @return Error code. + * @author + * @date + * @version 1.0 + */ +s32 host_int_del_allstation(WILC_WFIDrvHandle hWFIDrv, u8 pu8MacAddr[][ETH_ALEN]) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tstrHostIFDelAllSta *pstrDelAllStationMsg = &strHostIFmsg.uniHostIFmsgBody.strHostIFDelAllSta; + u8 au8Zero_Buff[ETH_ALEN] = {0}; + u32 i; + u8 u8AssocNumb = 0; + + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + PRINT_D(HOSTINF_DBG, "Setting deauthenticating station message queue params\n"); + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_DEL_ALL_STA; + strHostIFmsg.drvHandler = hWFIDrv; + + /* Handling situation of deauthenticing all associated stations*/ + for (i = 0; i < MAX_NUM_STA; i++) { + if (memcmp(pu8MacAddr[i], au8Zero_Buff, ETH_ALEN)) { + WILC_memcpy(pstrDelAllStationMsg->au8Sta_DelAllSta[i], pu8MacAddr[i], ETH_ALEN); + PRINT_D(CFG80211_DBG, "BSSID = %x%x%x%x%x%x\n", pstrDelAllStationMsg->au8Sta_DelAllSta[i][0], pstrDelAllStationMsg->au8Sta_DelAllSta[i][1], pstrDelAllStationMsg->au8Sta_DelAllSta[i][2], pstrDelAllStationMsg->au8Sta_DelAllSta[i][3], pstrDelAllStationMsg->au8Sta_DelAllSta[i][4], + pstrDelAllStationMsg->au8Sta_DelAllSta[i][5]); + u8AssocNumb++; + } + } + if (!u8AssocNumb) { + PRINT_D(CFG80211_DBG, "NO ASSOCIATED STAS\n"); + return s32Error; + } + + pstrDelAllStationMsg->u8Num_AssocSta = u8AssocNumb; + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + + + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + + } + WILC_CATCH(s32Error) + { + + } + down(&hWaitResponse); + + return s32Error; + +} + +/** + * @brief host_int_edit_station + * @details Setting edit station params in message queue + * @param[in] WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam* pstrStaParams + * @return Error code. + * @author + * @date + * @version 1.0 + */ +s32 host_int_edit_station(WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam *pstrStaParams) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tstrWILC_AddStaParam *pstrAddStationMsg = &strHostIFmsg.uniHostIFmsgBody.strAddStaParam; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + PRINT_D(HOSTINF_DBG, "Setting editing station message queue params\n"); + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_EDIT_STATION; + strHostIFmsg.drvHandler = hWFIDrv; + + WILC_memcpy(pstrAddStationMsg, pstrStaParams, sizeof(tstrWILC_AddStaParam)); + if (pstrAddStationMsg->u8NumRates > 0) { + u8 *rates = WILC_MALLOC(pstrAddStationMsg->u8NumRates); + WILC_NULLCHECK(s32Error, rates); + WILC_memcpy(rates, pstrStaParams->pu8Rates, pstrAddStationMsg->u8NumRates); + pstrAddStationMsg->pu8Rates = rates; + } + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + } + return s32Error; +} +#endif /*WILC_AP_EXTERNAL_MLME*/ +uint32_t wilc_get_chipid(uint8_t); + +s32 host_int_set_power_mgmt(WILC_WFIDrvHandle hWFIDrv, bool bIsEnabled, u32 u32Timeout) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tstrHostIfPowerMgmtParam *pstrPowerMgmtParam = &strHostIFmsg.uniHostIFmsgBody.strPowerMgmtparam; + + PRINT_INFO(HOSTINF_DBG, "\n\n>> Setting PS to %d << \n\n", bIsEnabled); + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + PRINT_D(HOSTINF_DBG, "Setting Power management message queue params\n"); + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_POWER_MGMT; + strHostIFmsg.drvHandler = hWFIDrv; + + pstrPowerMgmtParam->bIsEnabled = bIsEnabled; + pstrPowerMgmtParam->u32Timeout = u32Timeout; + + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + } + return s32Error; +} + +s32 host_int_setup_multicast_filter(WILC_WFIDrvHandle hWFIDrv, bool bIsEnabled, u32 u32count) +{ + s32 s32Error = WILC_SUCCESS; + + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tstrHostIFSetMulti *pstrMulticastFilterParam = &strHostIFmsg.uniHostIFmsgBody.strHostIfSetMulti; + + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + PRINT_D(HOSTINF_DBG, "Setting Multicast Filter params\n"); + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_MULTICAST_FILTER; + strHostIFmsg.drvHandler = hWFIDrv; + + pstrMulticastFilterParam->bIsEnabled = bIsEnabled; + pstrMulticastFilterParam->u32count = u32count; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + } + return s32Error; +} + + + +/*Bug4218: Parsing Join Param*/ +#ifdef WILC_PARSE_SCAN_IN_HOST + +/*Bug4218: Parsing Join Param*/ +/** + * @brief host_int_ParseJoinBssParam + * @details Parse Needed Join Parameters and save it in a new JoinBssParam entry + * @param[in] tstrNetworkInfo* ptstrNetworkInfo + * @return + * @author zsalah + * @date + * @version 1.0**/ +static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo) +{ + tstrJoinBssParam *pNewJoinBssParam = NULL; + u8 *pu8IEs; + u16 u16IEsLen; + u16 index = 0; + u8 suppRatesNo = 0; + u8 extSuppRatesNo; + u16 jumpOffset; + u8 pcipherCount; + u8 authCount; + u8 pcipherTotalCount = 0; + u8 authTotalCount = 0; + u8 i, j; + + pu8IEs = ptstrNetworkInfo->pu8IEs; + u16IEsLen = ptstrNetworkInfo->u16IEsLen; + + pNewJoinBssParam = WILC_MALLOC(sizeof(tstrJoinBssParam)); + if (pNewJoinBssParam != NULL) { + WILC_memset(pNewJoinBssParam, 0, sizeof(tstrJoinBssParam)); + pNewJoinBssParam->dtim_period = ptstrNetworkInfo->u8DtimPeriod; + pNewJoinBssParam->beacon_period = ptstrNetworkInfo->u16BeaconPeriod; + pNewJoinBssParam->cap_info = ptstrNetworkInfo->u16CapInfo; + WILC_memcpy(pNewJoinBssParam->au8bssid, ptstrNetworkInfo->au8bssid, 6); + /*for(i=0; i<6;i++) + * PRINT_D(HOSTINF_DBG,"%c",pNewJoinBssParam->au8bssid[i]);*/ + WILC_memcpy((u8 *)pNewJoinBssParam->ssid, ptstrNetworkInfo->au8ssid, ptstrNetworkInfo->u8SsidLen + 1); + pNewJoinBssParam->ssidLen = ptstrNetworkInfo->u8SsidLen; + WILC_memset(pNewJoinBssParam->rsn_pcip_policy, 0xFF, 3); + WILC_memset(pNewJoinBssParam->rsn_auth_policy, 0xFF, 3); + /*for(i=0; issidLen;i++) + * PRINT_D(HOSTINF_DBG,"%c",pNewJoinBssParam->ssid[i]);*/ + + /* parse supported rates: */ + while (index < u16IEsLen) { + /* supportedRates IE */ + if (pu8IEs[index] == SUPP_RATES_IE) { + /* PRINT_D(HOSTINF_DBG, "Supported Rates\n"); */ + suppRatesNo = pu8IEs[index + 1]; + pNewJoinBssParam->supp_rates[0] = suppRatesNo; + index += 2; /* skipping ID and length bytes; */ + + for (i = 0; i < suppRatesNo; i++) { + pNewJoinBssParam->supp_rates[i + 1] = pu8IEs[index + i]; + /* PRINT_D(HOSTINF_DBG,"%0x ",pNewJoinBssParam->supp_rates[i+1]); */ + } + index += suppRatesNo; + continue; + } + /* Ext SupportedRates IE */ + else if (pu8IEs[index] == EXT_SUPP_RATES_IE) { + /* PRINT_D(HOSTINF_DBG, "Extended Supported Rates\n"); */ + /* checking if no of ext. supp and supp rates < max limit */ + extSuppRatesNo = pu8IEs[index + 1]; + if (extSuppRatesNo > (MAX_RATES_SUPPORTED - suppRatesNo)) + pNewJoinBssParam->supp_rates[0] = MAX_RATES_SUPPORTED; + else + pNewJoinBssParam->supp_rates[0] += extSuppRatesNo; + index += 2; + /* pNewJoinBssParam.supp_rates[0] contains now old number not the ext. no */ + for (i = 0; i < (pNewJoinBssParam->supp_rates[0] - suppRatesNo); i++) { + pNewJoinBssParam->supp_rates[suppRatesNo + i + 1] = pu8IEs[index + i]; + /* PRINT_D(HOSTINF_DBG,"%0x ",pNewJoinBssParam->supp_rates[suppRatesNo+i+1]); */ + } + index += extSuppRatesNo; + continue; + } + /* HT Cap. IE */ + else if (pu8IEs[index] == HT_CAPABILITY_IE) { + /* if IE found set the flag */ + pNewJoinBssParam->ht_capable = true; + index += pu8IEs[index + 1] + 2; /* ID,Length bytes and IE body */ + /* PRINT_D(HOSTINF_DBG,"HT_CAPABALE\n"); */ + continue; + } else if ((pu8IEs[index] == WMM_IE) && /* WMM Element ID */ + (pu8IEs[index + 2] == 0x00) && (pu8IEs[index + 3] == 0x50) && + (pu8IEs[index + 4] == 0xF2) && /* OUI */ + (pu8IEs[index + 5] == 0x02) && /* OUI Type */ + ((pu8IEs[index + 6] == 0x00) || (pu8IEs[index + 6] == 0x01)) && /* OUI Sub Type */ + (pu8IEs[index + 7] == 0x01)) { + /* Presence of WMM Info/Param element indicates WMM capability */ + pNewJoinBssParam->wmm_cap = true; + + /* Check if Bit 7 is set indicating U-APSD capability */ + if (pu8IEs[index + 8] & (1 << 7)) { + pNewJoinBssParam->uapsd_cap = true; + } + index += pu8IEs[index + 1] + 2; + continue; + } + #ifdef WILC_P2P + else if ((pu8IEs[index] == P2P_IE) && /* P2P Element ID */ + (pu8IEs[index + 2] == 0x50) && (pu8IEs[index + 3] == 0x6f) && + (pu8IEs[index + 4] == 0x9a) && /* OUI */ + (pu8IEs[index + 5] == 0x09) && (pu8IEs[index + 6] == 0x0c)) { /* OUI Type */ + u16 u16P2P_count; + pNewJoinBssParam->tsf = ptstrNetworkInfo->u32Tsf; + pNewJoinBssParam->u8NoaEnbaled = 1; + pNewJoinBssParam->u8Index = pu8IEs[index + 9]; + + /* Check if Bit 7 is set indicating Opss capability */ + if (pu8IEs[index + 10] & (1 << 7)) { + pNewJoinBssParam->u8OppEnable = 1; + pNewJoinBssParam->u8CtWindow = pu8IEs[index + 10]; + } else + pNewJoinBssParam->u8OppEnable = 0; + /* HOSTINF_DBG */ + PRINT_D(GENERIC_DBG, "P2P Dump \n"); + for (i = 0; i < pu8IEs[index + 7]; i++) + PRINT_D(GENERIC_DBG, " %x \n", pu8IEs[index + 9 + i]); + + pNewJoinBssParam->u8Count = pu8IEs[index + 11]; + u16P2P_count = index + 12; + + WILC_memcpy(pNewJoinBssParam->au8Duration, pu8IEs + u16P2P_count, 4); + u16P2P_count += 4; + + WILC_memcpy(pNewJoinBssParam->au8Interval, pu8IEs + u16P2P_count, 4); + u16P2P_count += 4; + + WILC_memcpy(pNewJoinBssParam->au8StartTime, pu8IEs + u16P2P_count, 4); + + index += pu8IEs[index + 1] + 2; + continue; + + } + #endif + else if ((pu8IEs[index] == RSN_IE) || + ((pu8IEs[index] == WPA_IE) && (pu8IEs[index + 2] == 0x00) && + (pu8IEs[index + 3] == 0x50) && (pu8IEs[index + 4] == 0xF2) && + (pu8IEs[index + 5] == 0x01))) { + u16 rsnIndex = index; + /*PRINT_D(HOSTINF_DBG,"RSN IE Length:%d\n",pu8IEs[rsnIndex+1]); + * for(i=0; imode_802_11i = 2; + /* PRINT_D(HOSTINF_DBG,"\nRSN_IE\n"); */ + } else { /* check if rsn was previously parsed */ + if (pNewJoinBssParam->mode_802_11i == 0) + pNewJoinBssParam->mode_802_11i = 1; + /* PRINT_D(HOSTINF_DBG,"\nWPA_IE\n"); */ + rsnIndex += 4; + } + rsnIndex += 7; /* skipping id, length, version(2B) and first 3 bytes of gcipher */ + pNewJoinBssParam->rsn_grp_policy = pu8IEs[rsnIndex]; + rsnIndex++; + /* PRINT_D(HOSTINF_DBG,"Group Policy: %0x \n",pNewJoinBssParam->rsn_grp_policy); */ + /* initialize policies with invalid values */ + + jumpOffset = pu8IEs[rsnIndex] * 4; /* total no.of bytes of pcipher field (count*4) */ + + /*parsing pairwise cipher*/ + + /* saving 3 pcipher max. */ + pcipherCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex]; + rsnIndex += 2; /* jump 2 bytes of pcipher count */ + + /* PRINT_D(HOSTINF_DBG,"\npcipher:%d \n",pcipherCount); */ + for (i = pcipherTotalCount, j = 0; i < pcipherCount + pcipherTotalCount && i < 3; i++, j++) { + /* each count corresponds to 4 bytes, only last byte is saved */ + pNewJoinBssParam->rsn_pcip_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1]; + /* PRINT_D(HOSTINF_DBG,"PAIR policy = [%0x,%0x]\n",pNewJoinBssParam->rsn_pcip_policy[i],i); */ + } + pcipherTotalCount += pcipherCount; + rsnIndex += jumpOffset; + + jumpOffset = pu8IEs[rsnIndex] * 4; + + /*parsing AKM suite (auth_policy)*/ + /* saving 3 auth policies max. */ + authCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex]; + rsnIndex += 2; /* jump 2 bytes of pcipher count */ + + for (i = authTotalCount, j = 0; i < authTotalCount + authCount; i++, j++) { + /* each count corresponds to 4 bytes, only last byte is saved */ + pNewJoinBssParam->rsn_auth_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1]; + } + authTotalCount += authCount; + rsnIndex += jumpOffset; + /*pasring rsn cap. only if rsn IE*/ + if (pu8IEs[index] == RSN_IE) { + pNewJoinBssParam->rsn_cap[0] = pu8IEs[rsnIndex]; + pNewJoinBssParam->rsn_cap[1] = pu8IEs[rsnIndex + 1]; + rsnIndex += 2; + } + pNewJoinBssParam->rsn_found = true; + index += pu8IEs[index + 1] + 2; /* ID,Length bytes and IE body */ + continue; + } else + index += pu8IEs[index + 1] + 2; /* ID,Length bytes and IE body */ + + } + + + } + + return (void *)pNewJoinBssParam; + +} + +void host_int_freeJoinParams(void *pJoinParams) +{ + if ((tstrJoinBssParam *)pJoinParams != NULL) + WILC_FREE((tstrJoinBssParam *)pJoinParams); + else + PRINT_ER("Unable to FREE null pointer\n"); +} +#endif /*WILC_PARSE_SCAN_IN_HOST*/ + + +/** + * @brief host_int_addBASession + * @details Open a block Ack session with the given parameters + * @param[in] tstrNetworkInfo* ptstrNetworkInfo + * @return + * @author anoureldin + * @date + * @version 1.0**/ + +static int host_int_addBASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char TID, short int BufferSize, + short int SessionTimeout, void *drvHandler) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tstrHostIfBASessionInfo *pBASessionInfo = &strHostIFmsg.uniHostIFmsgBody.strHostIfBASessionInfo; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_ADD_BA_SESSION; + + memcpy(pBASessionInfo->au8Bssid, pBSSID, ETH_ALEN); + pBASessionInfo->u8Ted = TID; + pBASessionInfo->u16BufferSize = BufferSize; + pBASessionInfo->u16SessionTimeout = SessionTimeout; + strHostIFmsg.drvHandler = hWFIDrv; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; +} + + +s32 host_int_delBASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char TID) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tstrHostIfBASessionInfo *pBASessionInfo = &strHostIFmsg.uniHostIFmsgBody.strHostIfBASessionInfo; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_DEL_BA_SESSION; + + memcpy(pBASessionInfo->au8Bssid, pBSSID, ETH_ALEN); + pBASessionInfo->u8Ted = TID; + strHostIFmsg.drvHandler = hWFIDrv; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + /*BugID_5222*/ + down(&hWaitResponse); + + return s32Error; +} + +s32 host_int_del_All_Rx_BASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char TID) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + tstrHostIfBASessionInfo *pBASessionInfo = &strHostIFmsg.uniHostIFmsgBody.strHostIfBASessionInfo; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_DEL_ALL_RX_BA_SESSIONS; + + memcpy(pBASessionInfo->au8Bssid, pBSSID, ETH_ALEN); + pBASessionInfo->u8Ted = TID; + strHostIFmsg.drvHandler = hWFIDrv; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + /*BugID_5222*/ + down(&hWaitResponse); + + return s32Error; +} + +/** + * @brief host_int_setup_ipaddress + * @details setup IP in firmware + * @param[in] Handle to wifi driver + * @return Error code. + * @author Abdelrahman Sobhy + * @date + * @version 1.0*/ +s32 host_int_setup_ipaddress(WILC_WFIDrvHandle hWFIDrv, u8 *u16ipadd, u8 idx) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + /* TODO: Enable This feature on softap firmware */ + return 0; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_IPADDRESS; + + strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.au8IPAddr = u16ipadd; + strHostIFmsg.drvHandler = hWFIDrv; + strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.idx = idx; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; + + +} + +/** + * @brief host_int_get_ipaddress + * @details Get IP from firmware + * @param[in] Handle to wifi driver + * @return Error code. + * @author Abdelrahman Sobhy + * @date + * @version 1.0*/ +s32 host_int_get_ipaddress(WILC_WFIDrvHandle hWFIDrv, u8 *u16ipadd, u8 idx) +{ + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; + tstrHostIFmsg strHostIFmsg; + + if (pstrWFIDrv == NULL) { + WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); + } + + WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + + /* prepare the WiphyParams Message */ + strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_IPADDRESS; + + strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.au8IPAddr = u16ipadd; + strHostIFmsg.drvHandler=hWFIDrv; + strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.idx= idx; + + s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); + if (s32Error) { + WILC_ERRORREPORT(s32Error, s32Error); + } + WILC_CATCH(s32Error) + { + + } + + return s32Error; + + +} diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h new file mode 100644 index 000000000..38db74074 --- /dev/null +++ b/drivers/staging/wilc1000/host_interface.h @@ -0,0 +1,1281 @@ +/*! + * @file host_interface.h + * @brief File containg host interface APIs + * @author zsalah + * @sa host_interface.c + * @date 8 March 2012 + * @version 1.0 + */ + +#ifndef HOST_INT_H +#define HOST_INT_H + +#include "coreconfigurator.h" +#include "coreconfigsimulator.h" +/*****************************************************************************/ +/* Macros */ +/*****************************************************************************/ +#define FAIL 0x0000 +#define SUCCESS 0x0001 + +#define IP_ALEN 4 + +#define BIT2 ((u32)(1 << 2)) +#define BIT1 ((u32)(1 << 1)) +#define BIT0 ((u32)(1 << 0)) + +#define AP_MODE 0x01 +#define STATION_MODE 0x02 +#define GO_MODE 0x03 +#define CLIENT_MODE 0x04 + + +#define MAX_NUM_STA 9 +#define ACTIVE_SCAN_TIME 10 +#define PASSIVE_SCAN_TIME 1200 +#define MIN_SCAN_TIME 10 +#define MAX_SCAN_TIME 1200 +#define DEFAULT_SCAN 0 +#define USER_SCAN BIT0 +#define OBSS_PERIODIC_SCAN BIT1 +#define OBSS_ONETIME_SCAN BIT2 +#define GTK_RX_KEY_BUFF_LEN 24 +#define ADDKEY 0x1 +#define REMOVEKEY 0x2 +#define DEFAULTKEY 0x4 +#define ADDKEY_AP 0x8 +#define MAX_NUM_SCANNED_NETWORKS 100 /* 30 // rachel */ +#define MAX_NUM_SCANNED_NETWORKS_SHADOW 130 +#define MAX_NUM_PROBED_SSID 10 /*One more than the number of scanned ssids*/ +#define CHANNEL_SCAN_TIME 250 /* 250 */ + +#define TX_MIC_KEY_LEN 8 +#define RX_MIC_KEY_LEN 8 +#define PTK_KEY_LEN 16 + +#define TX_MIC_KEY_MSG_LEN 26 +#define RX_MIC_KEY_MSG_LEN 48 +#define PTK_KEY_MSG_LEN 39 + +#define PMKSA_KEY_LEN 22 +#define ETH_ALEN 6 +#define PMKID_LEN 16 +#define WILC_MAX_NUM_PMKIDS 16 +#define WILC_SUPP_MCS_SET_SIZE 16 +#define WILC_ADD_STA_LENGTH 40 /* Not including the rates field cause it has variable length*/ +#define SCAN_EVENT_DONE_ABORTED +/*****************************************************************************/ +/* Data Types */ +/*****************************************************************************/ +/* typedef unsigned char uint8; */ +/* typedef signed char int8; */ +/* typedef unsigned short uint16; */ +/* typedef unsigned long uint32; */ +/* typedef uint32 Bool; */ + +typedef struct { + u16 cfg_wid; + WID_TYPE_T cfg_type; + s8 *pu8Para; +} cfg_param_t; + +typedef struct _tstrStatistics { + u8 u8LinkSpeed; + s8 s8RSSI; + u32 u32TxCount; + u32 u32RxCount; + u32 u32TxFailureCount; + +} tstrStatistics; + + +typedef enum { + HOST_IF_IDLE = 0, + HOST_IF_SCANNING = 1, + HOST_IF_CONNECTING = 2, + HOST_IF_WAITING_CONN_RESP = 3, + HOST_IF_CONNECTED = 4, + HOST_IF_P2P_LISTEN = 5, + HOST_IF_FORCE_32BIT = 0xFFFFFFFF +} tenuHostIFstate; + +typedef struct _tstrHostIFpmkid { + u8 bssid[ETH_ALEN]; + u8 pmkid[PMKID_LEN]; +} tstrHostIFpmkid; + +typedef struct _tstrHostIFpmkidAttr { + u8 numpmkid; + tstrHostIFpmkid pmkidlist[WILC_MAX_NUM_PMKIDS]; +} tstrHostIFpmkidAttr; + +typedef enum { + AUTORATE = 0, + MBPS_1 = 1, + MBPS_2 = 2, + MBPS_5_5 = 5, + MBPS_11 = 11, + MBPS_6 = 6, + MBPS_9 = 9, + MBPS_12 = 12, + MBPS_18 = 18, + MBPS_24 = 24, + MBPS_36 = 36, + MBPS_48 = 48, + MBPS_54 = 54 +} CURRENT_TX_RATE_T; + +typedef struct { + u32 u32SetCfgFlag; + u8 ht_enable; + u8 bss_type; + u8 auth_type; + u16 auth_timeout; + u8 power_mgmt_mode; + u16 short_retry_limit; + u16 long_retry_limit; + u16 frag_threshold; + u16 rts_threshold; + u16 preamble_type; + u8 short_slot_allowed; + u8 txop_prot_disabled; + u16 beacon_interval; + u16 dtim_period; + SITE_SURVEY_T site_survey_enabled; + u16 site_survey_scan_time; + u8 scan_source; + u16 active_scan_time; + u16 passive_scan_time; + CURRENT_TX_RATE_T curr_tx_rate; + +} tstrCfgParamVal; + +typedef enum { + RETRY_SHORT = 1 << 0, + RETRY_LONG = 1 << 1, + FRAG_THRESHOLD = 1 << 2, + RTS_THRESHOLD = 1 << 3, + BSS_TYPE = 1 << 4, + AUTH_TYPE = 1 << 5, + AUTHEN_TIMEOUT = 1 << 6, + POWER_MANAGEMENT = 1 << 7, + PREAMBLE = 1 << 8, + SHORT_SLOT_ALLOWED = 1 << 9, + TXOP_PROT_DISABLE = 1 << 10, + BEACON_INTERVAL = 1 << 11, + DTIM_PERIOD = 1 << 12, + SITE_SURVEY = 1 << 13, + SITE_SURVEY_SCAN_TIME = 1 << 14, + ACTIVE_SCANTIME = 1 << 15, + PASSIVE_SCANTIME = 1 << 16, + CURRENT_TX_RATE = 1 << 17, + HT_ENABLE = 1 << 18, +} tenuCfgParam; + +typedef struct { + u8 au8bssid[6]; + s8 s8rssi; +} tstrFoundNetworkInfo; + +typedef enum {SCAN_EVENT_NETWORK_FOUND = 0, + SCAN_EVENT_DONE = 1, + SCAN_EVENT_ABORTED = 2, + SCAN_EVENT_FORCE_32BIT = 0xFFFFFFFF} tenuScanEvent; + +typedef enum { + CONN_DISCONN_EVENT_CONN_RESP = 0, + CONN_DISCONN_EVENT_DISCONN_NOTIF = 1, + CONN_DISCONN_EVENT_FORCE_32BIT = 0xFFFFFFFF +} tenuConnDisconnEvent; + +typedef enum { + WEP, + WPARxGtk, + /* WPATxGtk, */ + WPAPtk, + PMKSA, +} tenuKeyType; + + +/*Scan callBack function definition*/ +typedef void (*tWILCpfScanResult)(tenuScanEvent, tstrNetworkInfo *, void *, void *); + +/*Connect callBack function definition*/ +typedef void (*tWILCpfConnectResult)(tenuConnDisconnEvent, + tstrConnectInfo *, + u8, + tstrDisconnectNotifInfo *, + void *); + +#ifdef WILC_P2P +typedef void (*tWILCpfRemainOnChanExpired)(void *, u32); /*Remain on channel expiration callback function*/ +typedef void (*tWILCpfRemainOnChanReady)(void *); /*Remain on channel callback function*/ +#endif + +/* typedef u32 WILC_WFIDrvHandle; */ +typedef struct { + s32 s32Dummy; +} *WILC_WFIDrvHandle; + +/*! + * @struct tstrRcvdNetworkInfo + * @brief Structure to hold Received Asynchronous Network info + * @details + * @todo + * @sa + * @author Mostafa Abu Bakr + * @date 25 March 2012 + * @version 1.0 + */ +typedef struct _tstrRcvdNetworkInfo { + u8 *pu8Buffer; + u32 u32Length; +} tstrRcvdNetworkInfo; + +/*BugID_4156*/ +typedef struct _tstrHiddenNetworkInfo { + u8 *pu8ssid; + u8 u8ssidlen; + +} tstrHiddenNetworkInfo; + +typedef struct _tstrHiddenNetwork { + /* MAX_SSID_LEN */ + tstrHiddenNetworkInfo *pstrHiddenNetworkInfo; + u8 u8ssidnum; + +} tstrHiddenNetwork; + +typedef struct { + /* Scan user call back function */ + tWILCpfScanResult pfUserScanResult; + + /* User specific parameter to be delivered through the Scan User Callback function */ + void *u32UserScanPvoid; + + u32 u32RcvdChCount; + tstrFoundNetworkInfo astrFoundNetworkInfo[MAX_NUM_SCANNED_NETWORKS]; +} tstrWILC_UsrScanReq; + +typedef struct { + u8 *pu8bssid; + u8 *pu8ssid; + u8 u8security; + AUTHTYPE_T tenuAuth_type; + size_t ssidLen; + u8 *pu8ConnReqIEs; + size_t ConnReqIEsLen; + /* Connect user call back function */ + tWILCpfConnectResult pfUserConnectResult; + bool IsHTCapable; + /* User specific parameter to be delivered through the Connect User Callback function */ + void *u32UserConnectPvoid; +} tstrWILC_UsrConnReq; + +typedef struct { + u32 u32Address; +} tstrHostIfSetDrvHandler; + +typedef struct { + u32 u32Mode; +} tstrHostIfSetOperationMode; + +/*BugID_5077*/ +typedef struct { + u8 u8MacAddress[ETH_ALEN]; +} tstrHostIfSetMacAddress; + +/*BugID_5213*/ +typedef struct { + u8 *u8MacAddress; +} tstrHostIfGetMacAddress; + +/*BugID_5222*/ +typedef struct { + u8 au8Bssid[ETH_ALEN]; + u8 u8Ted; + u16 u16BufferSize; + u16 u16SessionTimeout; +} tstrHostIfBASessionInfo; + +#ifdef WILC_P2P +typedef struct { + u16 u16Channel; + u32 u32duration; + tWILCpfRemainOnChanExpired pRemainOnChanExpired; + tWILCpfRemainOnChanReady pRemainOnChanReady; + void *pVoid; + u32 u32ListenSessionID; +} tstrHostIfRemainOnChan; + +typedef struct { + + bool bReg; + u16 u16FrameType; + u8 u8Regid; + + +} tstrHostIfRegisterFrame; + + +#define ACTION 0xD0 +#define PROBE_REQ 0x40 +#define PROBE_RESP 0x50 +#define ACTION_FRM_IDX 0 +#define PROBE_REQ_IDX 1 + + +enum p2p_listen_state { + P2P_IDLE, + P2P_LISTEN, + P2P_GRP_FORMATION +}; + +#endif +typedef struct { + /* Scan user structure */ + tstrWILC_UsrScanReq strWILC_UsrScanReq; + + /* Connect User structure */ + tstrWILC_UsrConnReq strWILC_UsrConnReq; + + #ifdef WILC_P2P + /*Remain on channel struvture*/ + tstrHostIfRemainOnChan strHostIfRemainOnChan; + u8 u8RemainOnChan_pendingreq; + u64 u64P2p_MgmtTimeout; + u8 u8P2PConnect; + #endif + + tenuHostIFstate enuHostIFstate; + + /* bool bPendingConnRequest; */ + + #ifndef CONNECT_DIRECT + u32 u32SurveyResultsCount; + wid_site_survey_reslts_s astrSurveyResults[MAX_NUM_SCANNED_NETWORKS]; + #endif + + u8 au8AssociatedBSSID[ETH_ALEN]; + tstrCfgParamVal strCfgValues; +/* semaphores */ + struct semaphore gtOsCfgValuesSem; + struct semaphore hSemTestKeyBlock; + + struct semaphore hSemTestDisconnectBlock; + struct semaphore hSemGetRSSI; + struct semaphore hSemGetLINKSPEED; + struct semaphore hSemGetCHNL; + struct semaphore hSemInactiveTime; +/* timer handlers */ + WILC_TimerHandle hScanTimer; + WILC_TimerHandle hConnectTimer; + #ifdef WILC_P2P + WILC_TimerHandle hRemainOnChannel; + #endif + + bool IFC_UP; +} tstrWILC_WFIDrv; + +/*! + * @enum tenuWILC_StaFlag + * @brief Used to decode the station flag set and mask in tstrWILC_AddStaParam + * @details + * @todo + * @sa tstrWILC_AddStaParam, enum nl80211_sta_flags + * @author Enumeraion's creator + * @date 12 July 2012 + * @version 1.0 Description + */ + +typedef enum { + WILC_STA_FLAG_INVALID = 0, + WILC_STA_FLAG_AUTHORIZED, /*!< station is authorized (802.1X)*/ + WILC_STA_FLAG_SHORT_PREAMBLE, /*!< station is capable of receiving frames with short barker preamble*/ + WILC_STA_FLAG_WME, /*!< station is WME/QoS capable*/ + WILC_STA_FLAG_MFP, /*!< station uses management frame protection*/ + WILC_STA_FLAG_AUTHENTICATED /*!< station is authenticated*/ +} tenuWILC_StaFlag; + +typedef struct { + u8 au8BSSID[ETH_ALEN]; + u16 u16AssocID; + u8 u8NumRates; + const u8 *pu8Rates; + bool bIsHTSupported; + u16 u16HTCapInfo; + u8 u8AmpduParams; + u8 au8SuppMCsSet[16]; + u16 u16HTExtParams; + u32 u32TxBeamformingCap; + u8 u8ASELCap; + u16 u16FlagsMask; /**/ + u16 u16FlagsSet; /*> 22) & 0x1ff) + +void WILC_WFI_monitor_rx(uint8_t *buff, uint32_t size) +{ + uint32_t header, pkt_offset; + struct sk_buff *skb = NULL; + struct wilc_wfi_radiotap_hdr *hdr; + struct wilc_wfi_radiotap_cb_hdr *cb_hdr; + + PRINT_INFO(HOSTAPD_DBG, "In monitor interface receive function\n"); + + /* struct WILC_WFI_priv *priv = netdev_priv(dev); */ + + /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */ + + /* Bug 4601 */ + if (wilc_wfi_mon == NULL) + return; + + if (!netif_running(wilc_wfi_mon)) { + PRINT_INFO(HOSTAPD_DBG, "Monitor interface already RUNNING\n"); + return; + } + + /* Get WILC header */ + memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET); + + /* The packet offset field conain info about what type of managment frame */ + /* we are dealing with and ack status */ + pkt_offset = GET_PKT_OFFSET(header); + + if (pkt_offset & IS_MANAGMEMENT_CALLBACK) { + + /* hostapd callback mgmt frame */ + + skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_cb_hdr)); + if (skb == NULL) { + PRINT_INFO(HOSTAPD_DBG, "Monitor if : No memory to allocate skb"); + return; + } + + memcpy(skb_put(skb, size), buff, size); + + cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb, sizeof(*cb_hdr)); + memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ + + cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_present = cpu_to_le32( + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_TX_FLAGS)); + + cb_hdr->rate = 5; /* txrate->bitrate / 5; */ + + if (pkt_offset & IS_MGMT_STATUS_SUCCES) { + /* success */ + cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS; + } else { + cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL; + } + + } else { + + skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_hdr)); + + if (skb == NULL) { + PRINT_INFO(HOSTAPD_DBG, "Monitor if : No memory to allocate skb"); + return; + } + + /* skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); */ + /* if (skb == NULL) */ + /* return; */ + + memcpy(skb_put(skb, size), buff, size); + hdr = (struct wilc_wfi_radiotap_hdr *) skb_push(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(struct wilc_wfi_radiotap_hdr)); + hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ + /* hdr->hdr.it_pad = 0; */ + hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_hdr)); + PRINT_INFO(HOSTAPD_DBG, "Radiotap len %d\n", hdr->hdr.it_len); + hdr->hdr.it_present = cpu_to_le32 + (1 << IEEE80211_RADIOTAP_RATE); /* | */ + /* (1 << IEEE80211_RADIOTAP_CHANNEL)); */ + PRINT_INFO(HOSTAPD_DBG, "Presentflags %d\n", hdr->hdr.it_present); + hdr->rate = 5; /* txrate->bitrate / 5; */ + + } + +/* if(INFO || if(skb->data[9] == 0x00 || skb->data[9] == 0xb0)) + * { + * for(i=0;ilen;i++) + * PRINT_INFO(HOSTAPD_DBG,"Mon RxData[%d] = %02x\n",i,skb->data[i]); + * }*/ + + + skb->dev = wilc_wfi_mon; + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + + netif_rx(skb); + + +} + +struct tx_complete_mon_data { + int size; + void *buff; +}; + +static void mgmt_tx_complete(void *priv, int status) +{ + + /* struct sk_buff *skb2; */ + /* struct wilc_wfi_radiotap_cb_hdr *cb_hdr; */ + + struct tx_complete_mon_data *pv_data = (struct tx_complete_mon_data *)priv; + u8 *buf = pv_data->buff; + + + + if (status == 1) { + if (INFO || buf[0] == 0x10 || buf[0] == 0xb0) + PRINT_INFO(HOSTAPD_DBG, "Packet sent successfully - Size = %d - Address = %p.\n", pv_data->size, pv_data->buff); + } else { + PRINT_INFO(HOSTAPD_DBG, "Couldn't send packet - Size = %d - Address = %p.\n", pv_data->size, pv_data->buff); + } + + +/* //(skb->data[9] == 0x00 || skb->data[9] == 0xb0 || skb->data[9] == 0x40 || skb->data[9] == 0xd0 ) + * { + * skb2 = dev_alloc_skb(pv_data->size+sizeof(struct wilc_wfi_radiotap_cb_hdr)); + * + * memcpy(skb_put(skb2,pv_data->size),pv_data->buff, pv_data->size); + * + * cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb2, sizeof(*cb_hdr)); + * memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); + * + * cb_hdr->hdr.it_version = 0;//PKTHDR_RADIOTAP_VERSION; + * + * cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr)); + * + * cb_hdr->hdr.it_present = cpu_to_le32( + * (1 << IEEE80211_RADIOTAP_RATE) | + * (1 << IEEE80211_RADIOTAP_TX_FLAGS)); + * + * cb_hdr->rate = 5;//txrate->bitrate / 5; + * cb_hdr->tx_flags = 0x0004; + * + * skb2->dev = wilc_wfi_mon; + * skb_set_mac_header(skb2, 0); + * skb2->ip_summed = CHECKSUM_UNNECESSARY; + * skb2->pkt_type = PACKET_OTHERHOST; + * skb2->protocol = htons(ETH_P_802_2); + * memset(skb2->cb, 0, sizeof(skb2->cb)); + * + * netif_rx(skb2); + * }*/ + + /* incase of fully hosting mode, the freeing will be done in response to the cfg packet */ + #ifndef WILC_FULLY_HOSTING_AP + kfree(pv_data->buff); + + kfree(pv_data); + #endif +} +static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len) +{ + linux_wlan_t *nic; + struct tx_complete_mon_data *mgmt_tx = NULL; + + if (dev == NULL) { + PRINT_D(HOSTAPD_DBG, "ERROR: dev == NULL\n"); + return WILC_FAIL; + } + nic = netdev_priv(dev); + + netif_stop_queue(dev); + mgmt_tx = kmalloc(sizeof(struct tx_complete_mon_data), GFP_ATOMIC); + if (mgmt_tx == NULL) { + PRINT_ER("Failed to allocate memory for mgmt_tx structure\n"); + return WILC_FAIL; + } + + #ifdef WILC_FULLY_HOSTING_AP + /* add space for the pointer to tx_complete_mon_data */ + len += sizeof(struct tx_complete_mon_data *); + #endif + + mgmt_tx->buff = kmalloc(len, GFP_ATOMIC); + if (mgmt_tx->buff == NULL) { + PRINT_ER("Failed to allocate memory for mgmt_tx buff\n"); + return WILC_FAIL; + + } + + mgmt_tx->size = len; + + #ifndef WILC_FULLY_HOSTING_AP + memcpy(mgmt_tx->buff, buf, len); + #else + memcpy(mgmt_tx->buff, buf, len - sizeof(struct tx_complete_mon_data *)); + memcpy((mgmt_tx->buff) + (len - sizeof(struct tx_complete_mon_data *)), &mgmt_tx, sizeof(struct tx_complete_mon_data *)); + + /* filter data frames to handle it's PS */ + if (filter_monitor_data_frames((mgmt_tx->buff), len) == true) { + return; + } + + #endif /* WILC_FULLY_HOSTING_AP */ + + g_linux_wlan->oup.wlan_add_mgmt_to_tx_que(mgmt_tx, mgmt_tx->buff, mgmt_tx->size, mgmt_tx_complete); + + netif_wake_queue(dev); + return 0; +} + +/** + * @brief WILC_WFI_mon_xmit + * @details + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 12 JUL 2012 + * @version 1.0 + */ +static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_radiotap_header *rtap_hdr; + u32 rtap_len, i, ret = 0; + struct WILC_WFI_mon_priv *mon_priv; + + struct sk_buff *skb2; + struct wilc_wfi_radiotap_cb_hdr *cb_hdr; + + /* Bug 4601 */ + if (wilc_wfi_mon == NULL) + return WILC_FAIL; + + /* if(skb->data[3] == 0x10 || skb->data[3] == 0xb0) */ + + mon_priv = netdev_priv(wilc_wfi_mon); + + if (mon_priv == NULL) { + PRINT_ER("Monitor interface private structure is NULL\n"); + return WILC_FAIL; + } + + rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; + + rtap_len = ieee80211_get_radiotap_len(skb->data); + if (skb->len < rtap_len) { + PRINT_ER("Error in radiotap header\n"); + return -1; + } + /* skip the radiotap header */ + PRINT_INFO(HOSTAPD_DBG, "Radiotap len: %d\n", rtap_len); + + if (INFO) { + for (i = 0; i < rtap_len; i++) + PRINT_INFO(HOSTAPD_DBG, "Radiotap_hdr[%d] %02x\n", i, skb->data[i]); + } + /* Skip the ratio tap header */ + skb_pull(skb, rtap_len); + + if (skb->data[0] == 0xc0) + PRINT_INFO(HOSTAPD_DBG, "%x:%x:%x:%x:%x%x\n", skb->data[4], skb->data[5], skb->data[6], skb->data[7], skb->data[8], skb->data[9]); + + if (skb->data[0] == 0xc0 && (!(memcmp(broadcast, &skb->data[4], 6)))) { + skb2 = dev_alloc_skb(skb->len + sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + memcpy(skb_put(skb2, skb->len), skb->data, skb->len); + + cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb2, sizeof(*cb_hdr)); + memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ + + cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_present = cpu_to_le32( + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_TX_FLAGS)); + + cb_hdr->rate = 5; /* txrate->bitrate / 5; */ + cb_hdr->tx_flags = 0x0004; + + skb2->dev = wilc_wfi_mon; + skb_set_mac_header(skb2, 0); + skb2->ip_summed = CHECKSUM_UNNECESSARY; + skb2->pkt_type = PACKET_OTHERHOST; + skb2->protocol = htons(ETH_P_802_2); + memset(skb2->cb, 0, sizeof(skb2->cb)); + + netif_rx(skb2); + + return 0; + } + skb->dev = mon_priv->real_ndev; + + PRINT_INFO(HOSTAPD_DBG, "Skipping the radiotap header\n"); + + + + /* actual deliver of data is device-specific, and not shown here */ + PRINT_INFO(HOSTAPD_DBG, "SKB netdevice name = %s\n", skb->dev->name); + PRINT_INFO(HOSTAPD_DBG, "MONITOR real dev name = %s\n", mon_priv->real_ndev->name); + + #ifdef SIMULATION + ret = WILC_WFI_Tx(skb, mon_priv->real_ndev); + #elif USE_WIRELESS + /* Identify if Ethernet or MAC header (data or mgmt) */ + memcpy(srcAdd, &skb->data[10], 6); + memcpy(bssid, &skb->data[16], 6); + /* if source address and bssid fields are equal>>Mac header */ + /*send it to mgmt frames handler */ + if (!(memcmp(srcAdd, bssid, 6))) { + mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len); + dev_kfree_skb(skb); + } else + ret = mac_xmit(skb, mon_priv->real_ndev); + #endif + + /* return NETDEV_TX_OK; */ + return ret; +} + +static const struct net_device_ops wilc_wfi_netdev_ops = { + .ndo_start_xmit = WILC_WFI_mon_xmit, + +}; + +#ifdef WILC_FULLY_HOSTING_AP +/* + * @brief WILC_mgm_HOSTAPD_ACK + * @details report the status of transmitted mgmt frames to HOSTAPD + * @param[in] priv : pointer to tx_complete_mon_data struct + * bStatus : status of transmission + * @author Abd Al-Rahman Diab + * @date 9 May 2013 + * @version 1.0 + */ +void WILC_mgm_HOSTAPD_ACK(void *priv, bool bStatus) +{ + struct sk_buff *skb; + struct wilc_wfi_radiotap_cb_hdr *cb_hdr; + + struct tx_complete_mon_data *pv_data = (struct tx_complete_mon_data *)priv; + u8 *buf = pv_data->buff; + + /* len of the original frame without the added pointer at the tail */ + u16 u16len = (pv_data->size) - sizeof(struct tx_complete_mon_data *); + + + /*if(bStatus == 1){ + * if(INFO || buf[0] == 0x10 || buf[0] == 0xb0) + * PRINT_D(HOSTAPD_DBG,"Packet sent successfully - Size = %d - Address = %p.\n",u16len,pv_data->buff); + * }else{ + * PRINT_D(HOSTAPD_DBG,"Couldn't send packet - Size = %d - Address = %p.\n",u16len,pv_data->buff); + * } + */ + + /* (skb->data[9] == 0x00 || skb->data[9] == 0xb0 || skb->data[9] == 0x40 || skb->data[9] == 0xd0 ) */ + { + skb = dev_alloc_skb(u16len + sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + memcpy(skb_put(skb, u16len), pv_data->buff, u16len); + + cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb, sizeof(*cb_hdr)); + memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ + + cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_present = cpu_to_le32( + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_TX_FLAGS)); + + cb_hdr->rate = 5; /* txrate->bitrate / 5; */ + + + if (bStatus) { + /* success */ + cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS; + } else { + cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL; + } + + skb->dev = wilc_wfi_mon; + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + + netif_rx(skb); + } + + /* incase of fully hosting mode, the freeing will be done in response to the cfg packet */ + kfree(pv_data->buff); + + kfree(pv_data); + +} +#endif /* WILC_FULLY_HOSTING_AP */ + +/** + * @brief WILC_WFI_mon_setup + * @details + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 12 JUL 2012 + * @version 1.0 + */ +static void WILC_WFI_mon_setup(struct net_device *dev) +{ + + dev->netdev_ops = &wilc_wfi_netdev_ops; + /* dev->destructor = free_netdev; */ + PRINT_INFO(CORECONFIG_DBG, "In Ethernet setup function\n"); + ether_setup(dev); + dev->tx_queue_len = 0; + dev->type = ARPHRD_IEEE80211_RADIOTAP; + memset(dev->dev_addr, 0, ETH_ALEN); + + #ifdef USE_WIRELESS + { + /* u8 * mac_add; */ + unsigned char mac_add[] = {0x00, 0x50, 0xc2, 0x5e, 0x10, 0x8f}; + /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */ + /* mac_add = (u8*)WILC_MALLOC(ETH_ALEN); */ + /* status = host_int_get_MacAddress(priv->hWILCWFIDrv,mac_add); */ + /* mac_add[ETH_ALEN-1]+=1; */ + memcpy(dev->dev_addr, mac_add, ETH_ALEN); + } + #else + dev->dev_addr[0] = 0x12; + #endif + +} + +/** + * @brief WILC_WFI_init_mon_interface + * @details + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 12 JUL 2012 + * @version 1.0 + */ +struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_device *real_dev) +{ + + + u32 ret = WILC_SUCCESS; + struct WILC_WFI_mon_priv *priv; + + /*If monitor interface is already initialized, return it*/ + if (wilc_wfi_mon) { + return wilc_wfi_mon; + } + + wilc_wfi_mon = alloc_etherdev(sizeof(struct WILC_WFI_mon_priv)); + if (!wilc_wfi_mon) { + PRINT_ER("failed to allocate memory\n"); + return NULL; + + } + + wilc_wfi_mon->type = ARPHRD_IEEE80211_RADIOTAP; + strncpy(wilc_wfi_mon->name, name, IFNAMSIZ); + wilc_wfi_mon->name[IFNAMSIZ - 1] = 0; + wilc_wfi_mon->netdev_ops = &wilc_wfi_netdev_ops; + + ret = register_netdevice(wilc_wfi_mon); + if (ret) { + PRINT_ER(" register_netdevice failed (%d)\n", ret); + return NULL; + } + priv = netdev_priv(wilc_wfi_mon); + if (priv == NULL) { + PRINT_ER("private structure is NULL\n"); + return NULL; + } + + priv->real_ndev = real_dev; + + return wilc_wfi_mon; +} + +/** + * @brief WILC_WFI_deinit_mon_interface + * @details + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 12 JUL 2012 + * @version 1.0 + */ +int WILC_WFI_deinit_mon_interface() +{ + bool rollback_lock = false; + + if (wilc_wfi_mon != NULL) { + PRINT_D(HOSTAPD_DBG, "In Deinit monitor interface\n"); + PRINT_D(HOSTAPD_DBG, "RTNL is being locked\n"); + if (rtnl_is_locked()) { + rtnl_unlock(); + rollback_lock = true; + } + PRINT_D(HOSTAPD_DBG, "Unregister netdev\n"); + unregister_netdev(wilc_wfi_mon); + /* free_netdev(wilc_wfi_mon); */ + + if (rollback_lock) { + rtnl_lock(); + rollback_lock = false; + } + wilc_wfi_mon = NULL; + } + return WILC_SUCCESS; + +} +#endif /* WILC_AP_EXTERNAL_MLME */ diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c new file mode 100644 index 000000000..e52534ce1 --- /dev/null +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -0,0 +1,2783 @@ +#ifndef SIMULATION +#include "wilc_wfi_cfgoperations.h" +#include "linux_wlan_common.h" +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" +#ifdef USE_WIRELESS +#include "wilc_wfi_cfgoperations.h" +#endif + +#include "linux_wlan_common.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP +#include +#endif +#include +#include +#include +#include + +#include +#include + +#ifdef WILC_SDIO +#include "linux_wlan_sdio.h" +#else +#include "linux_wlan_spi.h" +#endif + +#ifdef WILC_FULLY_HOSTING_AP +#include "wilc_host_ap.h" +#endif + +#ifdef STATIC_MACADDRESS /* brandy_0724 [[ */ +#include +#include +struct task_struct *wilc_mac_thread; +unsigned char mac_add[] = {0x00, 0x80, 0xC2, 0x5E, 0xa2, 0xb2}; +#endif /* brandy_0724 ]] */ + +#if defined(CUSTOMER_PLATFORM) +/* + TODO : Write power control functions as customer platform. + */ +#else + + #define _linux_wlan_device_power_on() {} + #define _linux_wlan_device_power_off() {} + + #define _linux_wlan_device_detection() {} + #define _linux_wlan_device_removal() {} +#endif + +#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP +extern bool g_obtainingIP; +#endif +extern u16 Set_machw_change_vir_if(bool bValue); +extern void resolve_disconnect_aberration(void *drvHandler); +extern u8 gau8MulticastMacAddrList[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN]; +void wilc1000_wlan_deinit(linux_wlan_t *nic); +#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP +extern WILC_TimerHandle hDuringIpTimer; +#endif + +static int linux_wlan_device_power(int on_off) +{ + PRINT_D(INIT_DBG, "linux_wlan_device_power.. (%d)\n", on_off); + + if (on_off) { + _linux_wlan_device_power_on(); + } else { + _linux_wlan_device_power_off(); + } + + return 0; +} + +static int linux_wlan_device_detection(int on_off) +{ + PRINT_D(INIT_DBG, "linux_wlan_device_detection.. (%d)\n", on_off); + +#ifdef WILC_SDIO + if (on_off) { + _linux_wlan_device_detection(); + } else { + _linux_wlan_device_removal(); + } +#endif + + return 0; +} + + +#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP +static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr); + +static struct notifier_block g_dev_notifier = { + .notifier_call = dev_state_ev_handler +}; +#endif + +#define wilc_wlan_deinit(nic) { if (&g_linux_wlan->oup != NULL) \ + if (g_linux_wlan->oup.wlan_cleanup != NULL) \ + g_linux_wlan->oup.wlan_cleanup(); } + + +#ifndef STA_FIRMWARE +#define STA_FIRMWARE "/*(DEBLOBBED)*/" +#endif + +#ifndef AP_FIRMWARE +#define AP_FIRMWARE "/*(DEBLOBBED)*/" +#endif + +#ifndef P2P_CONCURRENCY_FIRMWARE +#define P2P_CONCURRENCY_FIRMWARE "/*(DEBLOBBED)*/" +#endif + + + +typedef struct android_wifi_priv_cmd { + char *buf; + int used_len; + int total_len; +} android_wifi_priv_cmd; + + +#define IRQ_WAIT 1 +#define IRQ_NO_WAIT 0 +/* + * to sync between mac_close and module exit. + * don't initialize or de-initialize from init/deinitlocks + * to be initialized from module wilc_netdev_init and + * deinitialized from mdoule_exit + */ +static struct semaphore close_exit_sync; +unsigned int int_rcvdU; +unsigned int int_rcvdB; +unsigned int int_clrd; + +static int wlan_deinit_locks(linux_wlan_t *nic); +static void wlan_deinitialize_threads(linux_wlan_t *nic); +static void linux_wlan_lock(void *vp); +void linux_wlan_unlock(void *vp); +extern void WILC_WFI_monitor_rx(uint8_t *buff, uint32_t size); +extern void WILC_WFI_p2p_rx(struct net_device *dev, uint8_t *buff, uint32_t size); + + +static void *internal_alloc(uint32_t size, uint32_t flag); +static void linux_wlan_tx_complete(void *priv, int status); +void frmw_to_linux(uint8_t *buff, uint32_t size, uint32_t pkt_offset); +static int mac_init_fn(struct net_device *ndev); +int mac_xmit(struct sk_buff *skb, struct net_device *dev); +int mac_open(struct net_device *ndev); +int mac_close(struct net_device *ndev); +static struct net_device_stats *mac_stats(struct net_device *dev); +static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd); +static void wilc_set_multicast_list(struct net_device *dev); + + + +/* + * for now - in frmw_to_linux there should be private data to be passed to it + * and this data should be pointer to net device + */ +linux_wlan_t *g_linux_wlan; +wilc_wlan_oup_t *gpstrWlanOps; +bool bEnablePS = true; + +static const struct net_device_ops wilc_netdev_ops = { + .ndo_init = mac_init_fn, + .ndo_open = mac_open, + .ndo_stop = mac_close, + .ndo_start_xmit = mac_xmit, + .ndo_do_ioctl = mac_ioctl, + .ndo_get_stats = mac_stats, + .ndo_set_rx_mode = wilc_set_multicast_list, + +}; + +#ifdef DEBUG_MODE + +extern volatile int timeNo; + +#define DEGUG_BUFFER_LENGTH 1000 +volatile int WatchDogdebuggerCounter; +char DebugBuffer[DEGUG_BUFFER_LENGTH + 20] = {0}; +static char *ps8current = DebugBuffer; + + + +void printk_later(const char *format, ...) +{ + va_list args; + va_start (args, format); + ps8current += vsprintf (ps8current, format, args); + va_end (args); + if ((ps8current - DebugBuffer) > DEGUG_BUFFER_LENGTH) { + ps8current = DebugBuffer; + } + +} + + +void dump_logs() +{ + if (DebugBuffer[0]) { + DebugBuffer[DEGUG_BUFFER_LENGTH] = 0; + PRINT_INFO(GENERIC_DBG, "early printed\n"); + PRINT_D(GENERIC_DBG, ps8current + 1); + ps8current[1] = 0; + PRINT_INFO(GENERIC_DBG, "latest printed\n"); + PRINT_D(GENERIC_DBG, DebugBuffer); + DebugBuffer[0] = 0; + ps8current = DebugBuffer; + } +} + +void Reset_WatchDogdebugger() +{ + WatchDogdebuggerCounter = 0; +} + +static int DebuggingThreadTask(void *vp) +{ + while (1) { + while (!WatchDogdebuggerCounter) { + PRINT_D(GENERIC_DBG, "Debug Thread Running %d\n", timeNo); + WatchDogdebuggerCounter = 1; + msleep(10000); + } + dump_logs(); + WatchDogdebuggerCounter = 0; + } +} + + +#endif + + +#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP +static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct in_ifaddr *dev_iface = (struct in_ifaddr *)ptr; + struct WILC_WFI_priv *priv; + tstrWILC_WFIDrv *pstrWFIDrv; + struct net_device *dev; + u8 *pIP_Add_buff; + perInterface_wlan_t *nic; + u8 null_ip[4] = {0}; + char wlan_dev_name[5] = "wlan0"; + + if (dev_iface == NULL || dev_iface->ifa_dev == NULL || dev_iface->ifa_dev->dev == NULL) { + PRINT_D(GENERIC_DBG, "dev_iface = NULL\n"); + return NOTIFY_DONE; + } + + if ((memcmp(dev_iface->ifa_label, "wlan0", 5)) && (memcmp(dev_iface->ifa_label, "p2p0", 4))) { + PRINT_D(GENERIC_DBG, "Interface is neither WLAN0 nor P2P0\n"); + return NOTIFY_DONE; + } + + dev = (struct net_device *)dev_iface->ifa_dev->dev; + if (dev->ieee80211_ptr == NULL || dev->ieee80211_ptr->wiphy == NULL) { + PRINT_D(GENERIC_DBG, "No Wireless registerd\n"); + return NOTIFY_DONE; + } + priv = wiphy_priv(dev->ieee80211_ptr->wiphy); + if (priv == NULL) { + PRINT_D(GENERIC_DBG, "No Wireless Priv\n"); + return NOTIFY_DONE; + } + pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; + nic = netdev_priv(dev); + if (nic == NULL || pstrWFIDrv == NULL) { + PRINT_D(GENERIC_DBG, "No Wireless Priv\n"); + return NOTIFY_DONE; + } + + PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler +++\n"); /* tony */ + + switch (event) { + case NETDEV_UP: + PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_UP %p\n", dev); /* tony */ + + PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Obtained ===============\n\n"); + + + /*If we are in station mode or client mode*/ + if (nic->iftype == STATION_MODE || nic->iftype == CLIENT_MODE) { + pstrWFIDrv->IFC_UP = 1; + g_obtainingIP = false; + WILC_TimerStop(&hDuringIpTimer, NULL); + PRINT_D(GENERIC_DBG, "IP obtained , enable scan\n"); + } + + + + if (bEnablePS) + host_int_set_power_mgmt((WILC_WFIDrvHandle)pstrWFIDrv, 1, 0); + + PRINT_D(GENERIC_DBG, "[%s] Up IP\n", dev_iface->ifa_label); + + pIP_Add_buff = (char *) (&(dev_iface->ifa_address)); + PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d \n", pIP_Add_buff[0], pIP_Add_buff[1], pIP_Add_buff[2], pIP_Add_buff[3]); + host_int_setup_ipaddress((WILC_WFIDrvHandle)pstrWFIDrv, pIP_Add_buff, nic->u8IfIdx); + + break; + + case NETDEV_DOWN: + PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_DOWN %p\n", dev); /* tony */ + + PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Released ===============\n\n"); + if (nic->iftype == STATION_MODE || nic->iftype == CLIENT_MODE) { + pstrWFIDrv->IFC_UP = 0; + g_obtainingIP = false; + } + + if (memcmp(dev_iface->ifa_label, wlan_dev_name, 5) == 0) + host_int_set_power_mgmt((WILC_WFIDrvHandle)pstrWFIDrv, 0, 0); + + resolve_disconnect_aberration(pstrWFIDrv); + + + PRINT_D(GENERIC_DBG, "[%s] Down IP\n", dev_iface->ifa_label); + + pIP_Add_buff = null_ip; + PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d \n", pIP_Add_buff[0], pIP_Add_buff[1], pIP_Add_buff[2], pIP_Add_buff[3]); + + host_int_setup_ipaddress((WILC_WFIDrvHandle)pstrWFIDrv, pIP_Add_buff, nic->u8IfIdx); + + break; + + default: + PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler event=default\n"); /* tony */ + PRINT_INFO(GENERIC_DBG, "[%s] unknown dev event: %lu\n", dev_iface->ifa_label, event); + + break; + } + + return NOTIFY_DONE; + +} +#endif + +/* + * Interrupt initialization and handling functions + */ + +void linux_wlan_enable_irq(void) +{ + +#if (RX_BH_TYPE != RX_BH_THREADED_IRQ) +#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO) + PRINT_D(INT_DBG, "Enabling IRQ ...\n"); + enable_irq(g_linux_wlan->dev_irq_num); +#endif +#endif +} + +void linux_wlan_disable_irq(int wait) +{ +#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO) + if (wait) { + PRINT_D(INT_DBG, "Disabling IRQ ...\n"); + disable_irq(g_linux_wlan->dev_irq_num); + } else { + PRINT_D(INT_DBG, "Disabling IRQ ...\n"); + disable_irq_nosync(g_linux_wlan->dev_irq_num); + } +#endif +} + +#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO) +static irqreturn_t isr_uh_routine(int irq, void *user_data) +{ + + + int_rcvdU++; +#if (RX_BH_TYPE != RX_BH_THREADED_IRQ) + linux_wlan_disable_irq(IRQ_NO_WAIT); +#endif + PRINT_D(INT_DBG, "Interrupt received UH\n"); + + /*While mac is closing cacncel the handling of any interrupts received*/ + if (g_linux_wlan->close) { + PRINT_ER("Driver is CLOSING: Can't handle UH interrupt\n"); + #if (RX_BH_TYPE == RX_BH_THREADED_IRQ) + return IRQ_HANDLED; + #else + return IRQ_NONE; + #endif + + } +#if (RX_BH_TYPE == RX_BH_WORK_QUEUE) + schedule_work(&g_linux_wlan->rx_work_queue); + return IRQ_HANDLED; +#elif (RX_BH_TYPE == RX_BH_KTHREAD) + linux_wlan_unlock(&g_linux_wlan->rx_sem); + return IRQ_HANDLED; +#elif (RX_BH_TYPE == RX_BH_THREADED_IRQ) + return IRQ_WAKE_THREAD; +#endif + +} +#endif + +#if (RX_BH_TYPE == RX_BH_WORK_QUEUE || RX_BH_TYPE == RX_BH_THREADED_IRQ) + +#if (RX_BH_TYPE == RX_BH_THREADED_IRQ) +irqreturn_t isr_bh_routine(int irq, void *userdata) +{ + linux_wlan_t *nic; + nic = (linux_wlan_t *)userdata; +#else +static void isr_bh_routine(struct work_struct *work) +{ + perInterface_wlan_t *nic; + nic = (perInterface_wlan_t *)container_of(work, linux_wlan_t, rx_work_queue); +#endif + + /*While mac is closing cacncel the handling of any interrupts received*/ + if (g_linux_wlan->close) { + PRINT_ER("Driver is CLOSING: Can't handle BH interrupt\n"); + #if (RX_BH_TYPE == RX_BH_THREADED_IRQ) + return IRQ_HANDLED; + #else + return; + #endif + + + + } + + int_rcvdB++; + PRINT_D(INT_DBG, "Interrupt received BH\n"); + if (g_linux_wlan->oup.wlan_handle_rx_isr != 0) { + g_linux_wlan->oup.wlan_handle_rx_isr(); + } else { + PRINT_ER("wlan_handle_rx_isr() hasn't been initialized\n"); + } + + +#if (RX_BH_TYPE == RX_BH_THREADED_IRQ) + return IRQ_HANDLED; +#endif +} +#elif (RX_BH_TYPE == RX_BH_KTHREAD) +static int isr_bh_routine(void *vp) +{ + linux_wlan_t *nic; + + nic = (linux_wlan_t *)vp; + + while (1) { + linux_wlan_lock(&nic->rx_sem); + if (g_linux_wlan->close) { + + while (!kthread_should_stop()) + schedule(); + + break; + } + int_rcvdB++; + PRINT_D(INT_DBG, "Interrupt received BH\n"); + if (g_linux_wlan->oup.wlan_handle_rx_isr != 0) { + g_linux_wlan->oup.wlan_handle_rx_isr(); + } else { + PRINT_ER("wlan_handle_rx_isr() hasn't been initialized\n"); + } + } + + return 0; +} +#endif + + +#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO) +static int init_irq(linux_wlan_t *p_nic) +{ + int ret = 0; + linux_wlan_t *nic = p_nic; + + /*initialize GPIO and register IRQ num*/ + /*GPIO request*/ + if ((gpio_request(GPIO_NUM, "WILC_INTR") == 0) && + (gpio_direction_input(GPIO_NUM) == 0)) { +#if defined(CUSTOMER_PLATFORM) +/* + TODO : save the registerd irq number to the private wilc context in kernel. + * + * ex) nic->dev_irq_num = gpio_to_irq(GPIO_NUM); + */ +#elif defined (NM73131_0_BOARD) + nic->dev_irq_num = IRQ_WILC1000; +#elif defined (PANDA_BOARD) + gpio_export(GPIO_NUM, 1); + nic->dev_irq_num = OMAP_GPIO_IRQ(GPIO_NUM); + irq_set_irq_type(nic->dev_irq_num, IRQ_TYPE_LEVEL_LOW); +#else + nic->dev_irq_num = gpio_to_irq(GPIO_NUM); +#endif + } else { + ret = -1; + PRINT_ER("could not obtain gpio for WILC_INTR\n"); + } + + +#if (RX_BH_TYPE == RX_BH_THREADED_IRQ) + if ((ret != -1) && (request_threaded_irq(nic->dev_irq_num, isr_uh_routine, isr_bh_routine, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, /*Without IRQF_ONESHOT the uh will remain kicked in and dont gave a chance to bh*/ + "WILC_IRQ", nic)) < 0) { + +#else + /*Request IRQ*/ + if ((ret != -1) && (request_irq(nic->dev_irq_num, isr_uh_routine, + IRQF_TRIGGER_LOW, "WILC_IRQ", nic) < 0)) { + +#endif + PRINT_ER("Failed to request IRQ for GPIO: %d\n", GPIO_NUM); + ret = -1; + } else { + + PRINT_D(INIT_DBG, "IRQ request succeeded IRQ-NUM= %d on GPIO: %d\n", + nic->dev_irq_num, GPIO_NUM); + } + + return ret; +} +#endif + +static void deinit_irq(linux_wlan_t *nic) +{ +#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO) + /* Deintialize IRQ */ + if (&nic->dev_irq_num != 0) { + free_irq(nic->dev_irq_num, g_linux_wlan); + + gpio_free(GPIO_NUM); + } +#endif +} + + +/* + * OS functions + */ +static void linux_wlan_msleep(uint32_t msc) +{ + if (msc <= 4000000) { + u32 u32Temp = msc * 1000; + usleep_range(u32Temp, u32Temp); + } else { + msleep(msc); + } +} + +static void linux_wlan_atomic_msleep(uint32_t msc) +{ + mdelay(msc); +} +static void linux_wlan_dbg(uint8_t *buff) +{ + PRINT_D(INIT_DBG, "%d\n", *buff); +} + +static void *linux_wlan_malloc_atomic(uint32_t sz) +{ + char *pntr = NULL; + pntr = kmalloc(sz, GFP_ATOMIC); + PRINT_D(MEM_DBG, "Allocating %d bytes at address %p\n", sz, pntr); + return (void *)pntr; + +} +static void *linux_wlan_malloc(uint32_t sz) +{ + char *pntr = NULL; + pntr = kmalloc(sz, GFP_KERNEL); + PRINT_D(MEM_DBG, "Allocating %d bytes at address %p\n", sz, pntr); + return (void *)pntr; +} + +void linux_wlan_free(void *vp) +{ + if (vp != NULL) { + PRINT_D(MEM_DBG, "Freeing %p\n", vp); + kfree(vp); + } +} + + +static void *internal_alloc(uint32_t size, uint32_t flag) +{ + char *pntr = NULL; + pntr = kmalloc(size, flag); + PRINT_D(MEM_DBG, "Allocating %d bytes at address %p\n", size, pntr); + return (void *)pntr; +} + + +static void linux_wlan_init_lock(char *lockName, void *plock, int count) +{ + sema_init((struct semaphore *)plock, count); + PRINT_D(LOCK_DBG, "Initializing [%s][%p]\n", lockName, plock); + +} + +static void linux_wlan_deinit_lock(void *plock) +{ + /* mutex_destroy((struct mutex*)plock); */ +} + +static void linux_wlan_lock(void *vp) +{ + PRINT_D(LOCK_DBG, "Locking %p\n", vp); + if (vp != NULL) { + while (down_interruptible((struct semaphore *) vp)) + ; + } else { + PRINT_ER("Failed, mutex is NULL\n"); + } +} + +static int linux_wlan_lock_timeout(void *vp, u32 timeout) +{ + int error = -1; + PRINT_D(LOCK_DBG, "Locking %p\n", vp); + if (vp != NULL) { + error = down_timeout((struct semaphore *)vp, msecs_to_jiffies(timeout)); + } else { + PRINT_ER("Failed, mutex is NULL\n"); + } + return error; +} + +void linux_wlan_unlock(void *vp) +{ + PRINT_D(LOCK_DBG, "Unlocking %p\n", vp); + if (vp != NULL) { + up((struct semaphore *)vp); + } else { + PRINT_ER("Failed, mutex is NULL\n"); + } +} + + +static void linux_wlan_init_mutex(char *lockName, void *plock, int count) +{ + mutex_init((struct mutex *)plock); + PRINT_D(LOCK_DBG, "Initializing mutex [%s][%p]\n", lockName, plock); + +} + +static void linux_wlan_deinit_mutex(void *plock) +{ + mutex_destroy((struct mutex *)plock); +} + +static void linux_wlan_lock_mutex(void *vp) +{ + PRINT_D(LOCK_DBG, "Locking mutex %p\n", vp); + if (vp != NULL) { + /* + * if(mutex_is_locked((struct mutex*)vp)) + * { + * //PRINT_ER("Mutex already locked - %p \n",vp); + * } + */ + mutex_lock((struct mutex *)vp); + + } else { + PRINT_ER("Failed, mutex is NULL\n"); + } +} + +static void linux_wlan_unlock_mutex(void *vp) +{ + PRINT_D(LOCK_DBG, "Unlocking mutex %p\n", vp); + if (vp != NULL) { + + if (mutex_is_locked((struct mutex *)vp)) { + mutex_unlock((struct mutex *)vp); + } else { + /* PRINT_ER("Mutex already unlocked - %p\n",vp); */ + } + + } else { + PRINT_ER("Failed, mutex is NULL\n"); + } +} + + +/*Added by Amr - BugID_4720*/ +static void linux_wlan_init_spin_lock(char *lockName, void *plock, int count) +{ + spin_lock_init((spinlock_t *)plock); + PRINT_D(SPIN_DEBUG, "Initializing mutex [%s][%p]\n", lockName, plock); + +} + +static void linux_wlan_deinit_spin_lock(void *plock) +{ + +} +static void linux_wlan_spin_lock(void *vp, unsigned long *flags) +{ + unsigned long lflags; + PRINT_D(SPIN_DEBUG, "Lock spin %p\n", vp); + if (vp != NULL) { + spin_lock_irqsave((spinlock_t *)vp, lflags); + *flags = lflags; + } else { + PRINT_ER("Failed, spin lock is NULL\n"); + } +} +static void linux_wlan_spin_unlock(void *vp, unsigned long *flags) +{ + unsigned long lflags = *flags; + PRINT_D(SPIN_DEBUG, "Unlock spin %p\n", vp); + if (vp != NULL) { + spin_unlock_irqrestore((spinlock_t *)vp, lflags); + *flags = lflags; + } else { + PRINT_ER("Failed, spin lock is NULL\n"); + } +} + +static void linux_wlan_mac_indicate(int flag) +{ + /*I have to do it that way becuase there is no mean to encapsulate device pointer + * as a parameter + */ + linux_wlan_t *pd = g_linux_wlan; + int status; + + if (flag == WILC_MAC_INDICATE_STATUS) { + pd->oup.wlan_cfg_get_value(WID_STATUS, (unsigned char *)&status, 4); + if (pd->mac_status == WILC_MAC_STATUS_INIT) { + pd->mac_status = status; + linux_wlan_unlock(&pd->sync_event); + } else { + pd->mac_status = status; + } + + if (pd->mac_status == WILC_MAC_STATUS_CONNECT) { /* Connect */ + } + + } else if (flag == WILC_MAC_INDICATE_SCAN) { + PRINT_D(GENERIC_DBG, "Scanning ...\n"); + + } + +} + +struct net_device *GetIfHandler(uint8_t *pMacHeader) +{ + uint8_t *Bssid, *Bssid1; + int i = 0; + + Bssid = pMacHeader + 10; + Bssid1 = pMacHeader + 4; + + for (i = 0; i < g_linux_wlan->u8NoIfcs; i++) { + if (!memcmp(Bssid1, g_linux_wlan->strInterfaceInfo[i].aBSSID, ETH_ALEN) || + !memcmp(Bssid, g_linux_wlan->strInterfaceInfo[i].aBSSID, ETH_ALEN)) { + return g_linux_wlan->strInterfaceInfo[i].wilc_netdev; + } + } + PRINT_INFO(INIT_DBG, "Invalide handle\n"); + for (i = 0; i < 25; i++) { + PRINT_D(INIT_DBG, "%02x ", pMacHeader[i]); + } + Bssid = pMacHeader + 18; + Bssid1 = pMacHeader + 12; + for (i = 0; i < g_linux_wlan->u8NoIfcs; i++) { + if (!memcmp(Bssid1, g_linux_wlan->strInterfaceInfo[i].aBSSID, ETH_ALEN) || + !memcmp(Bssid, g_linux_wlan->strInterfaceInfo[i].aBSSID, ETH_ALEN)) { + PRINT_D(INIT_DBG, "Ctx [%p]\n", g_linux_wlan->strInterfaceInfo[i].wilc_netdev); + return g_linux_wlan->strInterfaceInfo[i].wilc_netdev; + } + } + PRINT_INFO(INIT_DBG, "\n"); + return NULL; +} + +int linux_wlan_set_bssid(struct net_device *wilc_netdev, uint8_t *pBSSID) +{ + int i = 0; + int ret = -1; + + PRINT_D(INIT_DBG, "set bssid on[%p]\n", wilc_netdev); + for (i = 0; i < g_linux_wlan->u8NoIfcs; i++) { + if (g_linux_wlan->strInterfaceInfo[i].wilc_netdev == wilc_netdev) { + PRINT_D(INIT_DBG, "set bssid [%x][%x][%x]\n", pBSSID[0], pBSSID[1], pBSSID[2]); + memcpy(g_linux_wlan->strInterfaceInfo[i].aBSSID, pBSSID, 6); + ret = 0; + break; + } + } + return ret; +} + +/*BugID_5213*/ +/*Function to get number of connected interfaces*/ +int linux_wlan_get_num_conn_ifcs(void) +{ + uint8_t i = 0; + uint8_t null_bssid[6] = {0}; + uint8_t ret_val = 0; + + for (i = 0; i < g_linux_wlan->u8NoIfcs; i++) { + if (memcmp(g_linux_wlan->strInterfaceInfo[i].aBSSID, null_bssid, 6)) { + ret_val++; + } + } + return ret_val; +} + +static int linux_wlan_rxq_task(void *vp) +{ + + /* inform wilc1000_wlan_init that RXQ task is started. */ + linux_wlan_unlock(&g_linux_wlan->rxq_thread_started); + while (1) { + linux_wlan_lock(&g_linux_wlan->rxq_event); + /* wait_for_completion(&g_linux_wlan->rxq_event); */ + + if (g_linux_wlan->close) { + /*Unlock the mutex in the mac_close function to indicate the exiting of the RX thread */ + linux_wlan_unlock(&g_linux_wlan->rxq_thread_started); + + while (!kthread_should_stop()) + schedule(); + + PRINT_D(RX_DBG, " RX thread stopped\n"); + break; + } + PRINT_D(RX_DBG, "Calling wlan_handle_rx_que()\n"); + + g_linux_wlan->oup.wlan_handle_rx_que(); + } + return 0; +} + +#define USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS + +static int linux_wlan_txq_task(void *vp) +{ + int ret, txq_count; + +#if defined USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS +#define TX_BACKOFF_WEIGHT_INCR_STEP (1) +#define TX_BACKOFF_WEIGHT_DECR_STEP (1) +#define TX_BACKOFF_WEIGHT_MAX (7) +#define TX_BACKOFF_WEIGHT_MIN (0) +#define TX_BACKOFF_WEIGHT_UNIT_MS (10) + int backoff_weight = TX_BACKOFF_WEIGHT_MIN; + signed long timeout; +#endif + + /* inform wilc1000_wlan_init that TXQ task is started. */ + linux_wlan_unlock(&g_linux_wlan->txq_thread_started); + while (1) { + + PRINT_D(TX_DBG, "txq_task Taking a nap :)\n"); + linux_wlan_lock(&g_linux_wlan->txq_event); + /* wait_for_completion(&pd->txq_event); */ + PRINT_D(TX_DBG, "txq_task Who waked me up :$\n"); + + if (g_linux_wlan->close) { + /*Unlock the mutex in the mac_close function to indicate the exiting of the TX thread */ + linux_wlan_unlock(&g_linux_wlan->txq_thread_started); + + while (!kthread_should_stop()) + schedule(); + + PRINT_D(TX_DBG, "TX thread stopped\n"); + break; + } + PRINT_D(TX_DBG, "txq_task handle the sending packet and let me go to sleep.\n"); +#if !defined USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS + g_linux_wlan->oup.wlan_handle_tx_que(); +#else + do { + ret = g_linux_wlan->oup.wlan_handle_tx_que(&txq_count); + if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD /* && netif_queue_stopped(pd->wilc_netdev)*/) { + PRINT_D(TX_DBG, "Waking up queue\n"); + /* netif_wake_queue(pd->wilc_netdev); */ + if (netif_queue_stopped(g_linux_wlan->strInterfaceInfo[0].wilc_netdev)) + netif_wake_queue(g_linux_wlan->strInterfaceInfo[0].wilc_netdev); + if (netif_queue_stopped(g_linux_wlan->strInterfaceInfo[1].wilc_netdev)) + netif_wake_queue(g_linux_wlan->strInterfaceInfo[1].wilc_netdev); + } + + if (ret == WILC_TX_ERR_NO_BUF) { /* failed to allocate buffers in chip. */ + timeout = msecs_to_jiffies(TX_BACKOFF_WEIGHT_UNIT_MS << backoff_weight); + do { + /* Back off from sending packets for some time. */ + /* schedule_timeout will allow RX task to run and free buffers.*/ + /* set_current_state(TASK_UNINTERRUPTIBLE); */ + /* timeout = schedule_timeout(timeout); */ + msleep(TX_BACKOFF_WEIGHT_UNIT_MS << backoff_weight); + } while (/*timeout*/ 0); + backoff_weight += TX_BACKOFF_WEIGHT_INCR_STEP; + if (backoff_weight > TX_BACKOFF_WEIGHT_MAX) { + backoff_weight = TX_BACKOFF_WEIGHT_MAX; + } + } else { + if (backoff_weight > TX_BACKOFF_WEIGHT_MIN) { + backoff_weight -= TX_BACKOFF_WEIGHT_DECR_STEP; + if (backoff_weight < TX_BACKOFF_WEIGHT_MIN) { + backoff_weight = TX_BACKOFF_WEIGHT_MIN; + } + } + } + /*TODO: drop packets after a certain time/number of retry count. */ + } while (ret == WILC_TX_ERR_NO_BUF && !g_linux_wlan->close); /* retry sending packets if no more buffers in chip. */ +#endif + } + return 0; +} + +static void linux_wlan_rx_complete(void) +{ + PRINT_D(RX_DBG, "RX completed\n"); +} + +int linux_wlan_get_firmware(perInterface_wlan_t *p_nic) +{ + + perInterface_wlan_t *nic = p_nic; + int ret = 0; + const struct firmware *wilc_firmware; + char *firmware; + + + if (nic->iftype == AP_MODE) + firmware = AP_FIRMWARE; + else if (nic->iftype == STATION_MODE) + firmware = STA_FIRMWARE; + + /*BugID_5137*/ + else { + PRINT_D(INIT_DBG, "Get P2P_CONCURRENCY_FIRMWARE\n"); + firmware = P2P_CONCURRENCY_FIRMWARE; + } + + + + if (nic == NULL) { + PRINT_ER("NIC is NULL\n"); + goto _fail_; + } + + if (&nic->wilc_netdev->dev == NULL) { + PRINT_ER("&nic->wilc_netdev->dev is NULL\n"); + goto _fail_; + } + + + /* the firmare should be located in /lib/firmware in + * root file system with the name specified above */ + +#ifdef WILC_SDIO + if (reject_firmware(&wilc_firmware, firmware, &g_linux_wlan->wilc_sdio_func->dev) != 0) { + PRINT_ER("%s - firmare not available\n", firmware); + ret = -1; + goto _fail_; + } +#else + if (reject_firmware(&wilc_firmware, firmware, &g_linux_wlan->wilc_spidev->dev) != 0) { + PRINT_ER("%s - firmare not available\n", firmware); + ret = -1; + goto _fail_; + } +#endif + g_linux_wlan->wilc_firmware = wilc_firmware; /* Bug 4703 */ + +_fail_: + + return ret; + +} + +#ifdef COMPLEMENT_BOOT +int repeat_power_cycle(perInterface_wlan_t *nic); +#endif + +static int linux_wlan_start_firmware(perInterface_wlan_t *nic) +{ + + int ret = 0; + /* start firmware */ + PRINT_D(INIT_DBG, "Starting Firmware ...\n"); + ret = g_linux_wlan->oup.wlan_start(); + if (ret < 0) { + PRINT_ER("Failed to start Firmware\n"); + goto _fail_; + } + + /* wait for mac ready */ + PRINT_D(INIT_DBG, "Waiting for Firmware to get ready ...\n"); + ret = linux_wlan_lock_timeout(&g_linux_wlan->sync_event, 5000); + if (ret) { +#ifdef COMPLEMENT_BOOT + static int timeout = 5; + + if (timeout--) { + PRINT_D(INIT_DBG, "repeat power cycle[%d]", timeout); + ret = repeat_power_cycle(nic); + } else { + timeout = 5; + ret = -1; + goto _fail_; + } +#endif + PRINT_D(INIT_DBG, "Firmware start timed out"); + goto _fail_; + } + /* + * TODO: Driver shouoldn't wait forever for firmware to get started - + * in case of timeout this should be handled properly + */ + PRINT_D(INIT_DBG, "Firmware successfully started\n"); + +_fail_: + return ret; +} +static int linux_wlan_firmware_download(linux_wlan_t *p_nic) +{ + + int ret = 0; + + if (g_linux_wlan->wilc_firmware == NULL) { + PRINT_ER("Firmware buffer is NULL\n"); + ret = -ENOBUFS; + goto _FAIL_; + } + /** + * do the firmware download + **/ + PRINT_D(INIT_DBG, "Downloading Firmware ...\n"); + ret = g_linux_wlan->oup.wlan_firmware_download(g_linux_wlan->wilc_firmware->data, g_linux_wlan->wilc_firmware->size); + if (ret < 0) { + goto _FAIL_; + } + + /* Freeing FW buffer */ + PRINT_D(INIT_DBG, "Freeing FW buffer ...\n"); + PRINT_D(INIT_DBG, "Releasing firmware\n"); + release_firmware(g_linux_wlan->wilc_firmware); + g_linux_wlan->wilc_firmware = NULL; + + PRINT_D(INIT_DBG, "Download Succeeded \n"); + +_FAIL_: + return ret; +} + + +/* startup configuration - could be changed later using iconfig*/ +static int linux_wlan_init_test_config(struct net_device *dev, linux_wlan_t *p_nic) +{ + + unsigned char c_val[64]; + #ifndef STATIC_MACADDRESS + unsigned char mac_add[] = {0x00, 0x80, 0xC2, 0x5E, 0xa2, 0xff}; + #endif + + /*BugID_5077*/ + struct WILC_WFI_priv *priv; + tstrWILC_WFIDrv *pstrWFIDrv; + + PRINT_D(TX_DBG, "Start configuring Firmware\n"); + #ifndef STATIC_MACADDRESS + get_random_bytes(&mac_add[5], 1); + get_random_bytes(&mac_add[4], 1); + #endif + priv = wiphy_priv(dev->ieee80211_ptr->wiphy); + pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; + PRINT_D(INIT_DBG, "Host = %p\n", pstrWFIDrv); + + PRINT_D(INIT_DBG, "MAC address is : %02x-%02x-%02x-%02x-%02x-%02x\n", mac_add[0], mac_add[1], mac_add[2], mac_add[3], mac_add[4], mac_add[5]); + wilc_get_chipid(0); + + + if (g_linux_wlan->oup.wlan_cfg_set == NULL) { + PRINT_D(INIT_DBG, "Null p[ointer\n"); + goto _fail_; + } + + *(int *)c_val = (u32)pstrWFIDrv; + + if (!g_linux_wlan->oup.wlan_cfg_set(1, WID_SET_DRV_HANDLER, c_val, 4, 0, 0)) + goto _fail_; + + /*to tell fw that we are going to use PC test - WILC specific*/ + c_val[0] = 0; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_PC_TEST_MODE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = INFRASTRUCTURE; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_BSS_TYPE, c_val, 1, 0, 0)) + goto _fail_; + + + /* c_val[0] = RATE_AUTO; / * bug 4275: Enable autorate and limit it to 24Mbps * / */ + c_val[0] = RATE_AUTO; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = G_MIXED_11B_2_MODE; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11G_OPERATING_MODE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 1; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_CURRENT_CHANNEL, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = G_SHORT_PREAMBLE; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_PREAMBLE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = AUTO_PROT; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_PROT_MECH, c_val, 1, 0, 0)) + goto _fail_; + +#ifdef SWITCH_LOG_TERMINAL + c_val[0] = AUTO_PROT; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_LOGTerminal_Switch, c_val, 1, 0, 0)) + goto _fail_; +#endif + + c_val[0] = ACTIVE_SCAN; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_SCAN_TYPE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = SITE_SURVEY_OFF; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_SITE_SURVEY, c_val, 1, 0, 0)) + goto _fail_; + + *((int *)c_val) = 0xffff; /* Never use RTS-CTS */ + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_RTS_THRESHOLD, c_val, 2, 0, 0)) + goto _fail_; + + *((int *)c_val) = 2346; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_FRAG_THRESHOLD, c_val, 2, 0, 0)) + goto _fail_; + + /* SSID */ + /* -------------------------------------------------------------- */ + /* Configuration : String with length less than 32 bytes */ + /* Values to set : Any string with length less than 32 bytes */ + /* ( In BSS Station Set SSID to "" (null string) */ + /* to enable Broadcast SSID suppport ) */ + /* -------------------------------------------------------------- */ +#ifndef USE_WIRELESS + strcpy(c_val, "nwifi"); + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_SSID, c_val, (strlen(c_val) + 1), 0, 0)) + goto _fail_; +#endif + + c_val[0] = 0; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_BCAST_SSID, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 1; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_QOS_ENABLE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = NO_POWERSAVE; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_POWER_MANAGEMENT, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = NO_ENCRYPT; /* NO_ENCRYPT, 0x79 */ + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11I_MODE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = OPEN_SYSTEM; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_AUTH_TYPE, c_val, 1, 0, 0)) + goto _fail_; + + /* WEP/802 11I Configuration */ + /* ------------------------------------------------------------------ */ + /* Configuration : WEP Key */ + /* Values (0x) : 5 byte for WEP40 and 13 bytes for WEP104 */ + /* In case more than 5 bytes are passed on for WEP 40 */ + /* only first 5 bytes will be used as the key */ + /* ------------------------------------------------------------------ */ + + strcpy(c_val, "123456790abcdef1234567890"); + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_WEP_KEY_VALUE, c_val, (strlen(c_val) + 1), 0, 0)) + goto _fail_; + + /* WEP/802 11I Configuration */ + /* ------------------------------------------------------------------ */ + /* Configuration : AES/TKIP WPA/RSNA Pre-Shared Key */ + /* Values to set : Any string with length greater than equal to 8 bytes */ + /* and less than 64 bytes */ + /* ------------------------------------------------------------------ */ + strcpy(c_val, "12345678"); + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11I_PSK, c_val, (strlen(c_val)), 0, 0)) + goto _fail_; + + /* IEEE802.1X Key Configuration */ + /* ------------------------------------------------------------------ */ + /* Configuration : Radius Server Access Secret Key */ + /* Values to set : Any string with length greater than equal to 8 bytes */ + /* and less than 65 bytes */ + /* ------------------------------------------------------------------ */ + strcpy(c_val, "password"); + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_1X_KEY, c_val, (strlen(c_val) + 1), 0, 0)) + goto _fail_; + + /* IEEE802.1X Server Address Configuration */ + /* ------------------------------------------------------------------ */ + /* Configuration : Radius Server IP Address */ + /* Values to set : Any valid IP Address */ + /* ------------------------------------------------------------------ */ + c_val[0] = 192; + c_val[1] = 168; + c_val[2] = 1; + c_val[3] = 112; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_1X_SERV_ADDR, c_val, 4, 0, 0)) + goto _fail_; + + c_val[0] = 3; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_LISTEN_INTERVAL, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 3; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_DTIM_PERIOD, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = NORMAL_ACK; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_ACK_POLICY, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 0; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_USER_CONTROL_ON_TX_POWER, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 48; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_TX_POWER_LEVEL_11A, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 28; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_TX_POWER_LEVEL_11B, c_val, 1, 0, 0)) + goto _fail_; + + /* Beacon Interval */ + /* -------------------------------------------------------------------- */ + /* Configuration : Sets the beacon interval value */ + /* Values to set : Any 16-bit value */ + /* -------------------------------------------------------------------- */ + + *((int *)c_val) = 100; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_BEACON_INTERVAL, c_val, 2, 0, 0)) + goto _fail_; + + c_val[0] = REKEY_DISABLE; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_REKEY_POLICY, c_val, 1, 0, 0)) + goto _fail_; + + /* Rekey Time (s) (Used only when the Rekey policy is 2 or 4) */ + /* -------------------------------------------------------------------- */ + /* Configuration : Sets the Rekey Time (s) */ + /* Values to set : 32-bit value */ + /* -------------------------------------------------------------------- */ + *((int *)c_val) = 84600; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_REKEY_PERIOD, c_val, 4, 0, 0)) + goto _fail_; + + /* Rekey Packet Count (in 1000s; used when Rekey Policy is 3) */ + /* -------------------------------------------------------------------- */ + /* Configuration : Sets Rekey Group Packet count */ + /* Values to set : 32-bit Value */ + /* -------------------------------------------------------------------- */ + *((int *)c_val) = 500; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_REKEY_PACKET_COUNT, c_val, 4, 0, 0)) + goto _fail_; + + c_val[0] = 1; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_SHORT_SLOT_ALLOWED, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = G_SELF_CTS_PROT; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_ERP_PROT_TYPE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 1; /* Enable N */ + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_ENABLE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = HT_MIXED_MODE; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_OPERATING_MODE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 1; /* TXOP Prot disable in N mode: No RTS-CTS on TX A-MPDUs to save air-time. */ + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_TXOP_PROT_DISABLE, c_val, 1, 0, 0)) + goto _fail_; + + memcpy(c_val, mac_add, 6); + + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_MAC_ADDR, c_val, 6, 0, 0)) + goto _fail_; + + /** + * AP only + **/ + c_val[0] = DETECT_PROTECT_REPORT; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_OBSS_NONHT_DETECTION, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = RTS_CTS_NONHT_PROT; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_HT_PROT_TYPE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 0; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_RIFS_PROT_ENABLE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = MIMO_MODE; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_SMPS_MODE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 7; + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_CURRENT_TX_MCS, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 1; /* Enable N with immediate block ack. */ + if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_11N_IMMEDIATE_BA_ENABLED, c_val, 1, 1, (u32)pstrWFIDrv)) + goto _fail_; + + return 0; + +_fail_: + return -1; +} + + +/**************************/ +void wilc1000_wlan_deinit(linux_wlan_t *nic) +{ + + if (g_linux_wlan->wilc1000_initialized) { + + printk("Deinitializing wilc1000 ...\n"); + + if (nic == NULL) { + PRINT_ER("nic is NULL\n"); + return; + } + +#if defined(PLAT_ALLWINNER_A20) || defined(PLAT_ALLWINNER_A23) || defined(PLAT_ALLWINNER_A31) + /* johnny : remove */ + PRINT_D(INIT_DBG, "skip wilc_bus_set_default_speed\n"); +#else + wilc_bus_set_default_speed(); +#endif + + PRINT_D(INIT_DBG, "Disabling IRQ\n"); + #if (!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO) + linux_wlan_disable_irq(IRQ_WAIT); + #else + #if defined(PLAT_ALLWINNER_A20) || defined(PLAT_ALLWINNER_A23) || defined(PLAT_ALLWINNER_A31) + + #else + linux_wlan_lock_mutex((void *)&g_linux_wlan->hif_cs); + disable_sdio_interrupt(); + linux_wlan_unlock_mutex((void *)&g_linux_wlan->hif_cs); + #endif + #endif + + + /* not sure if the following unlocks are needed or not*/ + if (&g_linux_wlan->rxq_event != NULL) { + linux_wlan_unlock(&g_linux_wlan->rxq_event); + } + + if (&g_linux_wlan->txq_event != NULL) { + linux_wlan_unlock(&g_linux_wlan->txq_event); + } + + + #if (RX_BH_TYPE == RX_BH_WORK_QUEUE) + /*Removing the work struct from the linux kernel workqueue*/ + if (&g_linux_wlan->rx_work_queue != NULL) + flush_work(&g_linux_wlan->rx_work_queue); + + #elif (RX_BH_TYPE == RX_BH_KTHREAD) + /* if(&nic->rx_sem != NULL) */ + /* linux_wlan_unlock(&nic->rx_sem); */ + #endif + + PRINT_D(INIT_DBG, "Deinitializing Threads\n"); + wlan_deinitialize_threads(nic); + + PRINT_D(INIT_DBG, "Deinitializing IRQ\n"); + deinit_irq(g_linux_wlan); + + + if (&g_linux_wlan->oup != NULL) { + if (g_linux_wlan->oup.wlan_stop != NULL) + g_linux_wlan->oup.wlan_stop(); + } + + PRINT_D(INIT_DBG, "Deinitializing WILC Wlan\n"); + wilc_wlan_deinit(nic); +#if (defined WILC_SDIO) && (!defined WILC_SDIO_IRQ_GPIO) + #if defined(PLAT_ALLWINNER_A20) || defined(PLAT_ALLWINNER_A23) || defined(PLAT_ALLWINNER_A31) + PRINT_D(INIT_DBG, "Disabling IRQ 2\n"); + + linux_wlan_lock_mutex((void *)&g_linux_wlan->hif_cs); + disable_sdio_interrupt(); + linux_wlan_unlock_mutex((void *)&g_linux_wlan->hif_cs); + #endif +#endif + + /*De-Initialize locks*/ + PRINT_D(INIT_DBG, "Deinitializing Locks\n"); + wlan_deinit_locks(g_linux_wlan); + + /* announce that wilc1000 is not initialized */ + g_linux_wlan->wilc1000_initialized = 0; + + PRINT_D(INIT_DBG, "wilc1000 deinitialization Done\n"); + + } else { + PRINT_D(INIT_DBG, "wilc1000 is not initialized\n"); + } + return; +} + +int wlan_init_locks(linux_wlan_t *p_nic) +{ + + PRINT_D(INIT_DBG, "Initializing Locks ...\n"); + + /*initialize mutexes*/ + linux_wlan_init_mutex("hif_lock/hif_cs", &g_linux_wlan->hif_cs, 1); + linux_wlan_init_mutex("rxq_lock/rxq_cs", &g_linux_wlan->rxq_cs, 1); + linux_wlan_init_mutex("txq_lock/txq_cs", &g_linux_wlan->txq_cs, 1); + + /*Added by Amr - BugID_4720*/ + linux_wlan_init_spin_lock("txq_spin_lock/txq_cs", &g_linux_wlan->txq_spinlock, 1); + + /*Added by Amr - BugID_4720*/ + linux_wlan_init_lock("txq_add_to_head_lock/txq_cs", &g_linux_wlan->txq_add_to_head_cs, 1); + + linux_wlan_init_lock("txq_wait/txq_event", &g_linux_wlan->txq_event, 0); + linux_wlan_init_lock("rxq_wait/rxq_event", &g_linux_wlan->rxq_event, 0); + + linux_wlan_init_lock("cfg_wait/cfg_event", &g_linux_wlan->cfg_event, 0); + linux_wlan_init_lock("sync_event", &g_linux_wlan->sync_event, 0); + + linux_wlan_init_lock("rxq_lock/rxq_started", &g_linux_wlan->rxq_thread_started, 0); + linux_wlan_init_lock("rxq_lock/txq_started", &g_linux_wlan->txq_thread_started, 0); + + #if (RX_BH_TYPE == RX_BH_KTHREAD) + linux_wlan_init_lock("BH_SEM", &g_linux_wlan->rx_sem, 0); + #endif + + return 0; +} + +static int wlan_deinit_locks(linux_wlan_t *nic) +{ + PRINT_D(INIT_DBG, "De-Initializing Locks\n"); + + if (&g_linux_wlan->hif_cs != NULL) + linux_wlan_deinit_mutex(&g_linux_wlan->hif_cs); + + if (&g_linux_wlan->rxq_cs != NULL) + linux_wlan_deinit_mutex(&g_linux_wlan->rxq_cs); + + if (&g_linux_wlan->txq_cs != NULL) + linux_wlan_deinit_mutex(&g_linux_wlan->txq_cs); + + /*Added by Amr - BugID_4720*/ + if (&g_linux_wlan->txq_spinlock != NULL) + linux_wlan_deinit_spin_lock(&g_linux_wlan->txq_spinlock); + + if (&g_linux_wlan->rxq_event != NULL) + linux_wlan_deinit_lock(&g_linux_wlan->rxq_event); + + if (&g_linux_wlan->txq_event != NULL) + linux_wlan_deinit_lock(&g_linux_wlan->txq_event); + + /*Added by Amr - BugID_4720*/ + if (&g_linux_wlan->txq_add_to_head_cs != NULL) + linux_wlan_deinit_lock(&g_linux_wlan->txq_add_to_head_cs); + + if (&g_linux_wlan->rxq_thread_started != NULL) + linux_wlan_deinit_lock(&g_linux_wlan->rxq_thread_started); + + if (&g_linux_wlan->txq_thread_started != NULL) + linux_wlan_deinit_lock(&g_linux_wlan->txq_thread_started); + + if (&g_linux_wlan->cfg_event != NULL) + linux_wlan_deinit_lock(&g_linux_wlan->cfg_event); + + if (&g_linux_wlan->sync_event != NULL) + linux_wlan_deinit_lock(&g_linux_wlan->sync_event); + + return 0; +} +void linux_to_wlan(wilc_wlan_inp_t *nwi, linux_wlan_t *nic) +{ + + PRINT_D(INIT_DBG, "Linux to Wlan services ...\n"); + + nwi->os_context.hif_critical_section = (void *)&g_linux_wlan->hif_cs; + nwi->os_context.os_private = (void *)nic; + nwi->os_context.tx_buffer_size = LINUX_TX_SIZE; + nwi->os_context.txq_critical_section = (void *)&g_linux_wlan->txq_cs; + + /*Added by Amr - BugID_4720*/ + nwi->os_context.txq_add_to_head_critical_section = (void *)&g_linux_wlan->txq_add_to_head_cs; + + /*Added by Amr - BugID_4720*/ + nwi->os_context.txq_spin_lock = (void *)&g_linux_wlan->txq_spinlock; + + nwi->os_context.txq_wait_event = (void *)&g_linux_wlan->txq_event; + +#if defined (MEMORY_STATIC) + nwi->os_context.rx_buffer_size = LINUX_RX_SIZE; +#endif + nwi->os_context.rxq_critical_section = (void *)&g_linux_wlan->rxq_cs; + nwi->os_context.rxq_wait_event = (void *)&g_linux_wlan->rxq_event; + nwi->os_context.cfg_wait_event = (void *)&g_linux_wlan->cfg_event; + + nwi->os_func.os_sleep = linux_wlan_msleep; + nwi->os_func.os_atomic_sleep = linux_wlan_atomic_msleep; + nwi->os_func.os_debug = linux_wlan_dbg; + nwi->os_func.os_malloc = linux_wlan_malloc; + nwi->os_func.os_malloc_atomic = linux_wlan_malloc_atomic; + nwi->os_func.os_free = linux_wlan_free; + nwi->os_func.os_lock = linux_wlan_lock; + nwi->os_func.os_unlock = linux_wlan_unlock; + nwi->os_func.os_wait = linux_wlan_lock_timeout; + nwi->os_func.os_signal = linux_wlan_unlock; + nwi->os_func.os_enter_cs = linux_wlan_lock_mutex; + nwi->os_func.os_leave_cs = linux_wlan_unlock_mutex; + + /*Added by Amr - BugID_4720*/ + nwi->os_func.os_spin_lock = linux_wlan_spin_lock; + nwi->os_func.os_spin_unlock = linux_wlan_spin_unlock; + +#ifdef WILC_SDIO + nwi->io_func.io_type = HIF_SDIO; + nwi->io_func.io_init = linux_sdio_init; + nwi->io_func.io_deinit = linux_sdio_deinit; + nwi->io_func.u.sdio.sdio_cmd52 = linux_sdio_cmd52; + nwi->io_func.u.sdio.sdio_cmd53 = linux_sdio_cmd53; + nwi->io_func.u.sdio.sdio_set_max_speed = linux_sdio_set_max_speed; + nwi->io_func.u.sdio.sdio_set_default_speed = linux_sdio_set_default_speed; +#else + nwi->io_func.io_type = HIF_SPI; + nwi->io_func.io_init = linux_spi_init; + nwi->io_func.io_deinit = linux_spi_deinit; + nwi->io_func.u.spi.spi_tx = linux_spi_write; + nwi->io_func.u.spi.spi_rx = linux_spi_read; + nwi->io_func.u.spi.spi_trx = linux_spi_write_read; + nwi->io_func.u.spi.spi_max_speed = linux_spi_set_max_speed; +#endif + + /*for now - to be revised*/ + #ifdef WILC_FULLY_HOSTING_AP + /* incase of Fully hosted AP, all non cfg pkts are processed here*/ + nwi->net_func.rx_indicate = WILC_Process_rx_frame; + #else + nwi->net_func.rx_indicate = frmw_to_linux; + #endif + nwi->net_func.rx_complete = linux_wlan_rx_complete; + nwi->indicate_func.mac_indicate = linux_wlan_mac_indicate; +} + +int wlan_initialize_threads(perInterface_wlan_t *nic) +{ + + int ret = 0; + PRINT_D(INIT_DBG, "Initializing Threads ...\n"); + +#if (RX_BH_TYPE == RX_BH_WORK_QUEUE) + /*Initialize rx work queue task*/ + INIT_WORK(&g_linux_wlan->rx_work_queue, isr_bh_routine); +#elif (RX_BH_TYPE == RX_BH_KTHREAD) + PRINT_D(INIT_DBG, "Creating kthread for Rxq BH\n"); + g_linux_wlan->rx_bh_thread = kthread_run(isr_bh_routine, (void *)g_linux_wlan, "K_RXQ_BH"); + if (g_linux_wlan->rx_bh_thread == 0) { + PRINT_ER("couldn't create RX BH thread\n"); + ret = -ENOBUFS; + goto _fail_; + } +#endif + +#ifndef TCP_ENHANCEMENTS + /* create rx task */ + PRINT_D(INIT_DBG, "Creating kthread for reception\n"); + g_linux_wlan->rxq_thread = kthread_run(linux_wlan_rxq_task, (void *)g_linux_wlan, "K_RXQ_TASK"); + if (g_linux_wlan->rxq_thread == 0) { + PRINT_ER("couldn't create RXQ thread\n"); + ret = -ENOBUFS; + goto _fail_1; + } + + /* wait for RXQ task to start. */ + linux_wlan_lock(&g_linux_wlan->rxq_thread_started); + +#endif + + /* create tx task */ + PRINT_D(INIT_DBG, "Creating kthread for transmission\n"); + g_linux_wlan->txq_thread = kthread_run(linux_wlan_txq_task, (void *)g_linux_wlan, "K_TXQ_TASK"); + if (g_linux_wlan->txq_thread == 0) { + PRINT_ER("couldn't create TXQ thread\n"); + ret = -ENOBUFS; + goto _fail_2; + } +#ifdef DEBUG_MODE + PRINT_D(INIT_DBG, "Creating kthread for Debugging\n"); + g_linux_wlan->txq_thread = kthread_run(DebuggingThreadTask, (void *)g_linux_wlan, "DebugThread"); + if (g_linux_wlan->txq_thread == 0) { + PRINT_ER("couldn't create TXQ thread\n"); + ret = -ENOBUFS; + goto _fail_2; + } +#endif + /* wait for TXQ task to start. */ + linux_wlan_lock(&g_linux_wlan->txq_thread_started); + + return 0; + +_fail_2: + /*De-Initialize 2nd thread*/ + g_linux_wlan->close = 1; + linux_wlan_unlock(&g_linux_wlan->rxq_event); + kthread_stop(g_linux_wlan->rxq_thread); + +#ifndef TCP_ENHANCEMENTS +_fail_1: +#endif + #if (RX_BH_TYPE == RX_BH_KTHREAD) + /*De-Initialize 1st thread*/ + g_linux_wlan->close = 1; + linux_wlan_unlock(&g_linux_wlan->rx_sem); + kthread_stop(g_linux_wlan->rx_bh_thread); +_fail_: + #endif + g_linux_wlan->close = 0; + return ret; +} + +static void wlan_deinitialize_threads(linux_wlan_t *nic) +{ + + g_linux_wlan->close = 1; + PRINT_D(INIT_DBG, "Deinitializing Threads\n"); + if (&g_linux_wlan->rxq_event != NULL) + linux_wlan_unlock(&g_linux_wlan->rxq_event); + + + if (g_linux_wlan->rxq_thread != NULL) { + kthread_stop(g_linux_wlan->rxq_thread); + g_linux_wlan->rxq_thread = NULL; + } + + + if (&g_linux_wlan->txq_event != NULL) + linux_wlan_unlock(&g_linux_wlan->txq_event); + + + if (g_linux_wlan->txq_thread != NULL) { + kthread_stop(g_linux_wlan->txq_thread); + g_linux_wlan->txq_thread = NULL; + } + + #if (RX_BH_TYPE == RX_BH_KTHREAD) + if (&g_linux_wlan->rx_sem != NULL) + linux_wlan_unlock(&g_linux_wlan->rx_sem); + + if (g_linux_wlan->rx_bh_thread != NULL) { + kthread_stop(g_linux_wlan->rx_bh_thread); + g_linux_wlan->rx_bh_thread = NULL; + } + #endif +} + +#ifdef STATIC_MACADDRESS +const char *path_string[] = { + "/etc/wlan", + "/data/wlan", +}; + +static int linux_wlan_read_mac_addr(void *vp) +{ + int ret = 0; + struct file *fp = (struct file *)-ENOENT; + mm_segment_t old_fs; + loff_t pos = 0; + int index; + int array_size = ARRAY_SIZE(path_string); + + /* change to KERNEL_DS address limit */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + + for (index = 0; index < array_size; index++) { + fp = filp_open(path_string[index], O_WRONLY, 0640); + if (!fp) { + ret = -1; + goto exit; + } + + /*No such file or directory */ + if (IS_ERR(fp) || !fp->f_op) { + get_random_bytes(&mac_add[3], 3); + /* open file to write */ + fp = filp_open(path_string[index], O_WRONLY | O_CREAT, 0640); + + if (!fp || IS_ERR(fp)) { + ret = -1; + continue; + } else { + /* write buf to file */ + fp->f_op->write(fp, mac_add, 6, &pos); + break; + } + } else { + /* read file to buf */ + fp->f_op->read(fp, mac_add, 6, &pos); + break; + } + } + + if (index == array_size) { + PRINT_ER("random MAC\n"); + } + +exit: + if (fp && !IS_ERR(fp)) { + filp_close(fp, NULL); + } + + set_fs(old_fs); + + return ret; +} +#endif + +#ifdef COMPLEMENT_BOOT + +extern volatile int probe; +extern uint8_t core_11b_ready(void); + +#define READY_CHECK_THRESHOLD 30 +extern void wilc_wlan_global_reset(void); +uint8_t wilc1000_prepare_11b_core(wilc_wlan_inp_t *nwi, wilc_wlan_oup_t *nwo, linux_wlan_t *nic) +{ + uint8_t trials = 0; + while ((core_11b_ready() && (READY_CHECK_THRESHOLD > (trials++)))) { + PRINT_D(INIT_DBG, "11b core not ready yet: %u\n", trials); + wilc_wlan_deinit(nic); + wilc_wlan_global_reset(); + sdio_unregister_driver(&wilc_bus); + + linux_wlan_device_detection(0); + + mdelay(100); + + linux_wlan_device_detection(1); + + sdio_register_driver(&wilc_bus); + + while (!probe) { + msleep(100); + } + probe = 0; + g_linux_wlan->wilc_sdio_func = local_sdio_func; + linux_to_wlan(nwi, nic); + wilc_wlan_init(nwi, nwo); + } + + if (READY_CHECK_THRESHOLD <= trials) + return 1; + else + return 0; + +} + +int repeat_power_cycle(perInterface_wlan_t *nic) +{ + int ret = 0; + wilc_wlan_inp_t nwi; + wilc_wlan_oup_t nwo; + sdio_unregister_driver(&wilc_bus); + + linux_wlan_device_detection(0); + linux_wlan_device_power(0); + msleep(100); + linux_wlan_device_power(1); + msleep(80); + linux_wlan_device_detection(1); + msleep(20); + + sdio_register_driver(&wilc_bus); + + /* msleep(1000); */ + while (!probe) { + msleep(100); + } + probe = 0; + g_linux_wlan->wilc_sdio_func = local_sdio_func; + linux_to_wlan(&nwi, g_linux_wlan); + ret = wilc_wlan_init(&nwi, &nwo); + + g_linux_wlan->mac_status = WILC_MAC_STATUS_INIT; + #if (defined WILC_SDIO) && (!defined WILC_SDIO_IRQ_GPIO) + enable_sdio_interrupt(); + #endif + + if (linux_wlan_get_firmware(nic)) { + PRINT_ER("Can't get firmware \n"); + ret = -1; + goto __fail__; + } + + /*Download firmware*/ + ret = linux_wlan_firmware_download(g_linux_wlan); + if (ret < 0) { + PRINT_ER("Failed to download firmware\n"); + goto __fail__; + } + /* Start firmware*/ + ret = linux_wlan_start_firmware(nic); + if (ret < 0) { + PRINT_ER("Failed to start firmware\n"); + } +__fail__: + return ret; +} +#endif + +int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic) +{ + wilc_wlan_inp_t nwi; + wilc_wlan_oup_t nwo; + perInterface_wlan_t *nic = p_nic; + int ret = 0; + + if (!g_linux_wlan->wilc1000_initialized) { + g_linux_wlan->mac_status = WILC_MAC_STATUS_INIT; + g_linux_wlan->close = 0; + g_linux_wlan->wilc1000_initialized = 0; + + wlan_init_locks(g_linux_wlan); + +#ifdef STATIC_MACADDRESS + wilc_mac_thread = kthread_run(linux_wlan_read_mac_addr, NULL, "wilc_mac_thread"); + if (wilc_mac_thread < 0) { + PRINT_ER("couldn't create Mac addr thread\n"); + } +#endif + + linux_to_wlan(&nwi, g_linux_wlan); + + ret = wilc_wlan_init(&nwi, &nwo); + if (ret < 0) { + PRINT_ER("Initializing WILC_Wlan FAILED\n"); + ret = -EIO; + goto _fail_locks_; + } + memcpy(&g_linux_wlan->oup, &nwo, sizeof(wilc_wlan_oup_t)); + + /*Save the oup structre into global pointer*/ + gpstrWlanOps = &g_linux_wlan->oup; + + + ret = wlan_initialize_threads(nic); + if (ret < 0) { + PRINT_ER("Initializing Threads FAILED\n"); + ret = -EIO; + goto _fail_wilc_wlan_; + } + +#if (defined WILC_SDIO) && (defined COMPLEMENT_BOOT) + if (wilc1000_prepare_11b_core(&nwi, &nwo, g_linux_wlan)) { + PRINT_ER("11b Core is not ready\n"); + ret = -EIO; + goto _fail_threads_; + } +#endif + +#if (!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO) + if (init_irq(g_linux_wlan)) { + PRINT_ER("couldn't initialize IRQ\n"); + ret = -EIO; + goto _fail_threads_; + } +#endif + +#if (defined WILC_SDIO) && (!defined WILC_SDIO_IRQ_GPIO) + if (enable_sdio_interrupt()) { + PRINT_ER("couldn't initialize IRQ\n"); + ret = -EIO; + goto _fail_irq_init_; + } +#endif + + if (linux_wlan_get_firmware(nic)) { + PRINT_ER("Can't get firmware \n"); + ret = -EIO; + goto _fail_irq_enable_; + } + + + /*Download firmware*/ + ret = linux_wlan_firmware_download(g_linux_wlan); + if (ret < 0) { + PRINT_ER("Failed to download firmware\n"); + ret = -EIO; + goto _fail_irq_enable_; + } + + /* Start firmware*/ + ret = linux_wlan_start_firmware(nic); + if (ret < 0) { + PRINT_ER("Failed to start firmware\n"); + ret = -EIO; + goto _fail_irq_enable_; + } + + wilc_bus_set_max_speed(); + + if (g_linux_wlan->oup.wlan_cfg_get(1, WID_FIRMWARE_VERSION, 1, 0)) { + int size; + char Firmware_ver[20]; + size = g_linux_wlan->oup.wlan_cfg_get_value( + WID_FIRMWARE_VERSION, + Firmware_ver, sizeof(Firmware_ver)); + Firmware_ver[size] = '\0'; + PRINT_D(INIT_DBG, "***** Firmware Ver = %s *******\n", Firmware_ver); + } + /* Initialize firmware with default configuration */ + ret = linux_wlan_init_test_config(dev, g_linux_wlan); + + if (ret < 0) { + PRINT_ER("Failed to configure firmware\n"); + ret = -EIO; + goto _fail_fw_start_; + } + + g_linux_wlan->wilc1000_initialized = 1; + return 0; /*success*/ + + +_fail_fw_start_: + if (&g_linux_wlan->oup != NULL) { + if (g_linux_wlan->oup.wlan_stop != NULL) + g_linux_wlan->oup.wlan_stop(); + } + +_fail_irq_enable_: +#if (defined WILC_SDIO) && (!defined WILC_SDIO_IRQ_GPIO) + disable_sdio_interrupt(); +_fail_irq_init_: +#endif +#if (!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO) + deinit_irq(g_linux_wlan); + +#endif +_fail_threads_: + wlan_deinitialize_threads(g_linux_wlan); +_fail_wilc_wlan_: + wilc_wlan_deinit(g_linux_wlan); +_fail_locks_: + wlan_deinit_locks(g_linux_wlan); + PRINT_ER("WLAN Iinitialization FAILED\n"); + } else { + PRINT_D(INIT_DBG, "wilc1000 already initialized\n"); + } + return ret; +} + + +/* + * - this function will be called automatically by OS when module inserted. + */ + +#if !defined (NM73131_0_BOARD) +int mac_init_fn(struct net_device *ndev) +{ + + /*Why we do this !!!*/ + netif_start_queue(ndev); /* ma */ + netif_stop_queue(ndev); /* ma */ + + return 0; +} +#else +int mac_init_fn(struct net_device *ndev) +{ + + unsigned char mac_add[] = {0x00, 0x50, 0xc2, 0x5e, 0x10, 0x00}; + /* TODO: get MAC address whenever the source is EPROM - hardcoded and copy it to ndev*/ + memcpy(ndev->dev_addr, mac_add, 6); + + if (!is_valid_ether_addr(ndev->dev_addr)) { + PRINT_ER("Error: Wrong MAC address\n"); + return -EINVAL; + } + + return 0; +} +#endif + + +void WILC_WFI_frame_register(struct wiphy *wiphy, struct net_device *dev, + u16 frame_type, bool reg); + +/* This fn is called, when this device is setup using ifconfig */ +#if !defined (NM73131_0_BOARD) +int mac_open(struct net_device *ndev) +{ + perInterface_wlan_t *nic; + + /*BugID_5213*/ + /*No need for setting mac address here anymore,*/ + /*Just set it in init_test_config()*/ + unsigned char mac_add[ETH_ALEN] = {0}; + int ret = 0; + int i = 0; + struct WILC_WFI_priv *priv; + + nic = netdev_priv(ndev); + priv = wiphy_priv(nic->wilc_netdev->ieee80211_ptr->wiphy); + PRINT_D(INIT_DBG, "MAC OPEN[%p]\n", ndev); + + #ifdef USE_WIRELESS + ret = WILC_WFI_InitHostInt(ndev); + if (ret < 0) { + PRINT_ER("Failed to initialize host interface\n"); + + return ret; + } + #endif + + /*initialize platform*/ + PRINT_D(INIT_DBG, "*** re-init ***\n"); + ret = wilc1000_wlan_init(ndev, nic); + if (ret < 0) { + PRINT_ER("Failed to initialize wilc1000\n"); + WILC_WFI_DeInitHostInt(ndev); + return ret; + } + + Set_machw_change_vir_if(false); + + host_int_get_MacAddress(priv->hWILCWFIDrv, mac_add); + PRINT_D(INIT_DBG, "Mac address: %x:%x:%x:%x:%x:%x\n", mac_add[0], mac_add[1], mac_add[2], + mac_add[3], mac_add[4], mac_add[5]); + + /* loop through the NUM of supported devices and set the MAC address */ + for (i = 0; i < g_linux_wlan->u8NoIfcs; i++) { + if (ndev == g_linux_wlan->strInterfaceInfo[i].wilc_netdev) { + memcpy(g_linux_wlan->strInterfaceInfo[i].aSrcAddress, mac_add, ETH_ALEN); + g_linux_wlan->strInterfaceInfo[i].drvHandler = (u32)priv->hWILCWFIDrv; + break; + } + } + + /* TODO: get MAC address whenever the source is EPROM - hardcoded and copy it to ndev*/ + memcpy(ndev->dev_addr, g_linux_wlan->strInterfaceInfo[i].aSrcAddress, ETH_ALEN); + + if (!is_valid_ether_addr(ndev->dev_addr)) { + PRINT_ER("Error: Wrong MAC address\n"); + ret = -EINVAL; + goto _err_; + } + + + WILC_WFI_frame_register(nic->wilc_netdev->ieee80211_ptr->wiphy, nic->wilc_netdev, + nic->g_struct_frame_reg[0].frame_type, nic->g_struct_frame_reg[0].reg); + WILC_WFI_frame_register(nic->wilc_netdev->ieee80211_ptr->wiphy, nic->wilc_netdev, + nic->g_struct_frame_reg[1].frame_type, nic->g_struct_frame_reg[1].reg); + netif_wake_queue(ndev); + g_linux_wlan->open_ifcs++; + nic->mac_opened = 1; + return 0; + +_err_: + WILC_WFI_DeInitHostInt(ndev); + wilc1000_wlan_deinit(g_linux_wlan); + return ret; +} +#else +int mac_open(struct net_device *ndev) +{ + + linux_wlan_t *nic; + nic = netdev_priv(ndev); + + /*initialize platform*/ + if (wilc1000_wlan_init(nic)) { + PRINT_ER("Failed to initialize platform\n"); + return 1; + } + /* Start the network interface queue for this device */ + PRINT_D(INIT_DBG, "Starting netifQ\n"); + netif_start_queue(ndev); +/* linux_wlan_lock(&close_exit_sync); */ + return 0; +} +#endif + +struct net_device_stats *mac_stats(struct net_device *dev) +{ + perInterface_wlan_t *nic = netdev_priv(dev); + + + return &nic->netstats; +} + +/* Setup the multicast filter */ +static void wilc_set_multicast_list(struct net_device *dev) +{ + + struct netdev_hw_addr *ha; + struct WILC_WFI_priv *priv; + tstrWILC_WFIDrv *pstrWFIDrv; + int i = 0; + priv = wiphy_priv(dev->ieee80211_ptr->wiphy); + pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; + + + if (!dev) + return; + + PRINT_D(INIT_DBG, "Setting Multicast List with count = %d. \n", dev->mc.count); + + if (dev->flags & IFF_PROMISC) { + /* Normally, we should configure the chip to retrive all packets + * but we don't wanna support this right now */ + /* TODO: add promiscuous mode support */ + PRINT_D(INIT_DBG, "Set promiscuous mode ON, retrive all packets \n"); + return; + } + + /* If there's more addresses than we handle, get all multicast + * packets and sort them out in software. */ + if ((dev->flags & IFF_ALLMULTI) || (dev->mc.count) > WILC_MULTICAST_TABLE_SIZE) { + PRINT_D(INIT_DBG, "Disable multicast filter, retrive all multicast packets\n"); + /* get all multicast packets */ + host_int_setup_multicast_filter((WILC_WFIDrvHandle)pstrWFIDrv, false, 0); + return; + } + + /* No multicast? Just get our own stuff */ + if ((dev->mc.count) == 0) { + PRINT_D(INIT_DBG, "Enable multicast filter, retrive directed packets only.\n"); + host_int_setup_multicast_filter((WILC_WFIDrvHandle)pstrWFIDrv, true, 0); + return; + } + + /* Store all of the multicast addresses in the hardware filter */ + netdev_for_each_mc_addr(ha, dev) + { + WILC_memcpy(gau8MulticastMacAddrList[i], ha->addr, ETH_ALEN); + PRINT_D(INIT_DBG, "Entry[%d]: %x:%x:%x:%x:%x:%x\n", i, + gau8MulticastMacAddrList[i][0], gau8MulticastMacAddrList[i][1], gau8MulticastMacAddrList[i][2], gau8MulticastMacAddrList[i][3], gau8MulticastMacAddrList[i][4], gau8MulticastMacAddrList[i][5]); + i++; + } + + host_int_setup_multicast_filter((WILC_WFIDrvHandle)pstrWFIDrv, true, (dev->mc.count)); + + return; + +} + +static void linux_wlan_tx_complete(void *priv, int status) +{ + + struct tx_complete_data *pv_data = (struct tx_complete_data *)priv; + if (status == 1) { + PRINT_D(TX_DBG, "Packet sent successfully - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb); + } else { + PRINT_D(TX_DBG, "Couldn't send packet - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb); + } + /* Free the SK Buffer, its work is done */ + dev_kfree_skb(pv_data->skb); + linux_wlan_free(pv_data); +} + +int mac_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + perInterface_wlan_t *nic; + struct tx_complete_data *tx_data = NULL; + int QueueCount; + char *pu8UdpBuffer; + struct iphdr *ih; + struct ethhdr *eth_h; + nic = netdev_priv(ndev); + + PRINT_D(INT_DBG, "\n========\n IntUH: %d - IntBH: %d - IntCld: %d \n========\n", int_rcvdU, int_rcvdB, int_clrd); + PRINT_D(TX_DBG, "Sending packet just received from TCP/IP\n"); + + /* Stop the network interface queue */ + if (skb->dev != ndev) { + PRINT_ER("Packet not destined to this device\n"); + return 0; + } + + tx_data = (struct tx_complete_data *)internal_alloc(sizeof(struct tx_complete_data), GFP_ATOMIC); + if (tx_data == NULL) { + PRINT_ER("Failed to allocate memory for tx_data structure\n"); + dev_kfree_skb(skb); + netif_wake_queue(ndev); + return 0; + } + + tx_data->buff = skb->data; + tx_data->size = skb->len; + tx_data->skb = skb; + + eth_h = (struct ethhdr *)(skb->data); + if (eth_h->h_proto == 0x8e88) { + PRINT_D(INIT_DBG, "EAPOL transmitted\n"); + } + + /*get source and dest ip addresses*/ + ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr)); + + pu8UdpBuffer = (char *)ih + sizeof(struct iphdr); + if ((pu8UdpBuffer[1] == 68 && pu8UdpBuffer[3] == 67) || (pu8UdpBuffer[1] == 67 && pu8UdpBuffer[3] == 68)) { + PRINT_D(GENERIC_DBG, "DHCP Message transmitted, type:%x %x %x\n", pu8UdpBuffer[248], pu8UdpBuffer[249], pu8UdpBuffer[250]); + + } + PRINT_D(TX_DBG, "Sending packet - Size = %d - Address = %p - SKB = %p\n", tx_data->size, tx_data->buff, tx_data->skb); + + /* Send packet to MAC HW - for now the tx_complete function will be just status + * indicator. still not sure if I need to suspend host transmission till the tx_complete + * function called or not? + * allocated buffer will be freed in tx_complete function. + */ + PRINT_D(TX_DBG, "Adding tx packet to TX Queue\n"); + nic->netstats.tx_packets++; + nic->netstats.tx_bytes += tx_data->size; + tx_data->pBssid = g_linux_wlan->strInterfaceInfo[nic->u8IfIdx].aBSSID; + #ifndef WILC_FULLY_HOSTING_AP + QueueCount = g_linux_wlan->oup.wlan_add_to_tx_que((void *)tx_data, + tx_data->buff, + tx_data->size, + linux_wlan_tx_complete); + #else + QueueCount = WILC_Xmit_data((void *)tx_data, HOST_TO_WLAN); + #endif /* WILC_FULLY_HOSTING_AP */ + + + if (QueueCount > FLOW_CONTROL_UPPER_THRESHOLD) { + netif_stop_queue(g_linux_wlan->strInterfaceInfo[0].wilc_netdev); + netif_stop_queue(g_linux_wlan->strInterfaceInfo[1].wilc_netdev); + } + + return 0; +} + + +int mac_close(struct net_device *ndev) +{ + struct WILC_WFI_priv *priv; + perInterface_wlan_t *nic; + tstrWILC_WFIDrv *pstrWFIDrv; + + nic = netdev_priv(ndev); + + if ((nic == NULL) || (nic->wilc_netdev == NULL) || (nic->wilc_netdev->ieee80211_ptr == NULL) || (nic->wilc_netdev->ieee80211_ptr->wiphy == NULL)) { + PRINT_ER("nic = NULL\n"); + return 0; + } + + priv = wiphy_priv(nic->wilc_netdev->ieee80211_ptr->wiphy); + + if (priv == NULL) { + PRINT_ER("priv = NULL\n"); + return 0; + } + + pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; + + + + PRINT_D(GENERIC_DBG, "Mac close\n"); + + if (g_linux_wlan == NULL) { + PRINT_ER("g_linux_wlan = NULL\n"); + return 0; + } + + if (pstrWFIDrv == NULL) { + PRINT_ER("pstrWFIDrv = NULL\n"); + return 0; + } + + if ((g_linux_wlan->open_ifcs) > 0) { + g_linux_wlan->open_ifcs--; + } else { + PRINT_ER("ERROR: MAC close called while number of opened interfaces is zero\n"); + return 0; + } + + if (nic->wilc_netdev != NULL) { + /* Stop the network interface queue */ + netif_stop_queue(nic->wilc_netdev); + + #ifdef USE_WIRELESS + WILC_WFI_DeInitHostInt(nic->wilc_netdev); + #endif + } + + if (g_linux_wlan->open_ifcs == 0) { + PRINT_D(GENERIC_DBG, "Deinitializing wilc1000\n"); + g_linux_wlan->close = 1; + wilc1000_wlan_deinit(g_linux_wlan); + #ifdef USE_WIRELESS + #ifdef WILC_AP_EXTERNAL_MLME + WILC_WFI_deinit_mon_interface(); + #endif + #endif + } + + linux_wlan_unlock(&close_exit_sync); + nic->mac_opened = 0; + + return 0; +} + + +int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd) +{ + + u8 *buff = NULL; + s8 rssi; + u32 size = 0, length = 0; + perInterface_wlan_t *nic; + struct WILC_WFI_priv *priv; + s32 s32Error = WILC_SUCCESS; + + + + /* struct iwreq *wrq = (struct iwreq *) req; // tony moved to case SIOCSIWPRIV */ + #ifdef USE_WIRELESS + nic = netdev_priv(ndev); + + if (!g_linux_wlan->wilc1000_initialized) + return 0; + + #endif + + switch (cmd) { + + /* ]] 2013-06-24 */ + case SIOCSIWPRIV: + { + struct iwreq *wrq = (struct iwreq *) req; /* added by tony */ + + size = wrq->u.data.length; + + if (size && wrq->u.data.pointer) { + + buff = memdup_user(wrq->u.data.pointer, wrq->u.data.length); + if (IS_ERR(buff)) { + s32Error = PTR_ERR(buff); + goto done; + } + + if (strncasecmp(buff, "RSSI", length) == 0) { + + #ifdef USE_WIRELESS + priv = wiphy_priv(nic->wilc_netdev->ieee80211_ptr->wiphy); + s32Error = host_int_get_rssi(priv->hWILCWFIDrv, &(rssi)); + if (s32Error) + PRINT_ER("Failed to send get rssi param's message queue "); + #endif + PRINT_INFO(GENERIC_DBG, "RSSI :%d\n", rssi); + + /*Rounding up the rssi negative value*/ + rssi += 5; + + snprintf(buff, size, "rssi %d", rssi); + + if (copy_to_user(wrq->u.data.pointer, buff, size)) { + PRINT_ER("%s: failed to copy data to user buffer\n", __func__); + s32Error = -EFAULT; + goto done; + } + } + } + } + break; + + default: + { + PRINT_INFO(GENERIC_DBG, "Command - %d - has been received\n", cmd); + s32Error = -EOPNOTSUPP; + goto done; + } + } + +done: + + if (buff != NULL) { + kfree(buff); + } + + return s32Error; +} + +void frmw_to_linux(uint8_t *buff, uint32_t size, uint32_t pkt_offset) +{ + + unsigned int frame_len = 0; + int stats; + unsigned char *buff_to_send = NULL; + struct sk_buff *skb; +#ifndef TCP_ENHANCEMENTS + char *pu8UdpBuffer; + struct iphdr *ih; +#endif + struct net_device *wilc_netdev; + perInterface_wlan_t *nic; + + wilc_netdev = GetIfHandler(buff); + if (wilc_netdev == NULL) + return; + + buff += pkt_offset; + nic = netdev_priv(wilc_netdev); + + if (size > 0) { + + frame_len = size; + buff_to_send = buff; + + + /* Need to send the packet up to the host, allocate a skb buffer */ + skb = dev_alloc_skb(frame_len); + if (skb == NULL) { + PRINT_ER("Low memory - packet droped\n"); + return; + } + + skb_reserve(skb, (unsigned int)skb->data & 0x3); + + if (g_linux_wlan == NULL || wilc_netdev == NULL) { + PRINT_ER("wilc_netdev in g_linux_wlan is NULL"); + } + skb->dev = wilc_netdev; + + if (skb->dev == NULL) { + PRINT_ER("skb->dev is NULL\n"); + } + + /* + * for(i=0;i<40;i++) + * { + * if(imonitor_flag) + * { + * WILC_WFI_monitor_rx(nic->wilc_netdev,skb); + * return; + * }*/ +#endif + skb->protocol = eth_type_trans(skb, wilc_netdev); + #ifndef TCP_ENHANCEMENTS + /*get source and dest ip addresses*/ + ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr)); + + pu8UdpBuffer = (char *)ih + sizeof(struct iphdr); + if (buff_to_send[35] == 67 && buff_to_send[37] == 68) { + PRINT_D(RX_DBG, "DHCP Message received\n"); + } + if (buff_to_send[12] == 0x88 && buff_to_send[13] == 0x8e) + PRINT_D(GENERIC_DBG, "eapol received\n"); + #endif + /* Send the packet to the stack by giving it to the bridge */ + nic->netstats.rx_packets++; + nic->netstats.rx_bytes += frame_len; + skb->ip_summed = CHECKSUM_UNNECESSARY; + stats = netif_rx(skb); + PRINT_D(RX_DBG, "netif_rx ret value is: %d\n", stats); + } + #ifndef TCP_ENHANCEMENTS + else { + PRINT_ER("Discard sending packet with len = %d\n", size); + } + #endif +} + +void WILC_WFI_mgmt_rx(uint8_t *buff, uint32_t size) +{ + int i = 0; + perInterface_wlan_t *nic; + + /*BugID_5450*/ + /*Pass the frame on the monitor interface, if any.*/ + /*Otherwise, pass it on p2p0 netdev, if registered on it*/ + for (i = 0; i < g_linux_wlan->u8NoIfcs; i++) { + nic = netdev_priv(g_linux_wlan->strInterfaceInfo[i].wilc_netdev); + if (nic->monitor_flag) { + WILC_WFI_monitor_rx(buff, size); + return; + } + } + + #ifdef WILC_P2P + nic = netdev_priv(g_linux_wlan->strInterfaceInfo[1].wilc_netdev); /* p2p0 */ + if ((buff[0] == nic->g_struct_frame_reg[0].frame_type && nic->g_struct_frame_reg[0].reg) || + (buff[0] == nic->g_struct_frame_reg[1].frame_type && nic->g_struct_frame_reg[1].reg)) { + WILC_WFI_p2p_rx(g_linux_wlan->strInterfaceInfo[1].wilc_netdev, buff, size); + } + #endif +} + +int wilc_netdev_init(void) +{ + + int i; + perInterface_wlan_t *nic; + struct net_device *ndev; + + linux_wlan_init_lock("close_exit_sync", &close_exit_sync, 0); + + /*create the common structure*/ + g_linux_wlan = (linux_wlan_t *)WILC_MALLOC(sizeof(linux_wlan_t)); + memset(g_linux_wlan, 0, sizeof(linux_wlan_t)); + + /*Reset interrupt count debug*/ + int_rcvdU = 0; + int_rcvdB = 0; + int_clrd = 0; + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + register_inetaddr_notifier(&g_dev_notifier); + #endif + + for (i = 0; i < NUM_CONCURRENT_IFC; i++) { + /*allocate first ethernet device with perinterface_wlan_t as its private data*/ + ndev = alloc_etherdev(sizeof(perInterface_wlan_t)); + if (!ndev) { + PRINT_ER("Failed to allocate ethernet dev\n"); + return -1; + } + + nic = netdev_priv(ndev); + memset(nic, 0, sizeof(perInterface_wlan_t)); + + /*Name the Devices*/ + if (i == 0) { + #if defined(NM73131) /* tony, 2012-09-20 */ + strcpy(ndev->name, "wilc_eth%d"); + #elif defined(PLAT_CLM9722) /* rachel */ + strcpy(ndev->name, "eth%d"); + #else /* PANDA_BOARD, PLAT_ALLWINNER_A10, PLAT_ALLWINNER_A20, PLAT_ALLWINNER_A31, PLAT_AML8726_M3 or PLAT_WMS8304 */ + strcpy(ndev->name, "wlan%d"); + #endif + } else + strcpy(ndev->name, "p2p%d"); + + nic->u8IfIdx = g_linux_wlan->u8NoIfcs; + nic->wilc_netdev = ndev; + g_linux_wlan->strInterfaceInfo[g_linux_wlan->u8NoIfcs].wilc_netdev = ndev; + g_linux_wlan->u8NoIfcs++; + ndev->netdev_ops = &wilc_netdev_ops; + + #ifdef USE_WIRELESS + { + struct wireless_dev *wdev; + /*Register WiFi*/ + wdev = WILC_WFI_WiphyRegister(ndev); + + #ifdef WILC_SDIO + /* set netdev, tony */ + SET_NETDEV_DEV(ndev, &local_sdio_func->dev); + #endif + + if (wdev == NULL) { + PRINT_ER("Can't register WILC Wiphy\n"); + return -1; + } + + /*linking the wireless_dev structure with the netdevice*/ + nic->wilc_netdev->ieee80211_ptr = wdev; + nic->wilc_netdev->ml_priv = nic; + wdev->netdev = nic->wilc_netdev; + nic->netstats.rx_packets = 0; + nic->netstats.tx_packets = 0; + nic->netstats.rx_bytes = 0; + nic->netstats.tx_bytes = 0; + + } + #endif + + + if (register_netdev(ndev)) { + PRINT_ER("Device couldn't be registered - %s\n", ndev->name); + return -1; /* ERROR */ + } + + nic->iftype = STATION_MODE; + nic->mac_opened = 0; + + } + + #ifndef WILC_SDIO + if (!linux_spi_init(&g_linux_wlan->wilc_spidev)) { + PRINT_ER("Can't initialize SPI \n"); + return -1; /* ERROR */ + } + g_linux_wlan->wilc_spidev = wilc_spi_dev; + #else + g_linux_wlan->wilc_sdio_func = local_sdio_func; + #endif + + return 0; +} + + +/*The 1st function called after module inserted*/ +static int __init init_wilc_driver(void) +{ + + +#if defined (WILC_DEBUGFS) + if (wilc_debugfs_init() < 0) { + PRINT_D(GENERIC_DBG, "fail to create debugfs for wilc driver\n"); + return -1; + } +#endif + + printk("IN INIT FUNCTION\n"); + printk("*** WILC1000 driver VERSION=[10.2] FW_VER=[10.2] ***\n"); + + linux_wlan_device_power(1); + msleep(100); + linux_wlan_device_detection(1); + +#ifdef WILC_SDIO + { + int ret; + + ret = sdio_register_driver(&wilc_bus); + if (ret < 0) { + PRINT_D(INIT_DBG, "init_wilc_driver: Failed register sdio driver\n"); + } + + return ret; + } +#else + PRINT_D(INIT_DBG, "Initializing netdev\n"); + if (wilc_netdev_init()) { + PRINT_ER("Couldn't initialize netdev\n"); + } + return 0; +#endif +} +late_initcall(init_wilc_driver); + +static void __exit exit_wilc_driver(void) +{ + int i = 0; + perInterface_wlan_t *nic[NUM_CONCURRENT_IFC] = {NULL,}; + #define CLOSE_TIMEOUT (12 * 1000) + + if ((g_linux_wlan != NULL) && (((g_linux_wlan->strInterfaceInfo[0].wilc_netdev) != NULL) + || ((g_linux_wlan->strInterfaceInfo[1].wilc_netdev) != NULL))) { + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + unregister_inetaddr_notifier(&g_dev_notifier); + #endif + + for (i = 0; i < NUM_CONCURRENT_IFC; i++) { + nic[i] = netdev_priv(g_linux_wlan->strInterfaceInfo[i].wilc_netdev); + } + } + + + if ((g_linux_wlan != NULL) && g_linux_wlan->wilc_firmware != NULL) { + release_firmware(g_linux_wlan->wilc_firmware); + g_linux_wlan->wilc_firmware = NULL; + } + + + if ((g_linux_wlan != NULL) && (((g_linux_wlan->strInterfaceInfo[0].wilc_netdev) != NULL) + || ((g_linux_wlan->strInterfaceInfo[1].wilc_netdev) != NULL))) { + PRINT_D(INIT_DBG, "Waiting for mac_close ....\n"); + + if (linux_wlan_lock_timeout(&close_exit_sync, CLOSE_TIMEOUT) < 0) + PRINT_D(INIT_DBG, "Closed TimedOUT\n"); + else + PRINT_D(INIT_DBG, "mac_closed\n"); + + + for (i = 0; i < NUM_CONCURRENT_IFC; i++) { + /* close all opened interfaces */ + if (g_linux_wlan->strInterfaceInfo[i].wilc_netdev != NULL) { + if (nic[i]->mac_opened) { + mac_close(g_linux_wlan->strInterfaceInfo[i].wilc_netdev); + } + } + } + for (i = 0; i < NUM_CONCURRENT_IFC; i++) { + PRINT_D(INIT_DBG, "Unregistering netdev %p \n", g_linux_wlan->strInterfaceInfo[i].wilc_netdev); + unregister_netdev(g_linux_wlan->strInterfaceInfo[i].wilc_netdev); + #ifdef USE_WIRELESS + PRINT_D(INIT_DBG, "Freeing Wiphy...\n"); + WILC_WFI_WiphyFree(g_linux_wlan->strInterfaceInfo[i].wilc_netdev); + #endif + PRINT_D(INIT_DBG, "Freeing netdev...\n"); + free_netdev(g_linux_wlan->strInterfaceInfo[i].wilc_netdev); + } + } + + +#ifdef USE_WIRELESS +#ifdef WILC_AP_EXTERNAL_MLME + /* Bug 4600 : WILC_WFI_deinit_mon_interface was already called at mac_close */ + /* WILC_WFI_deinit_mon_interface(); */ +#endif +#endif + + /* if(g_linux_wlan->open_ifcs==0) */ + { + #ifndef WILC_SDIO + PRINT_D(INIT_DBG, "SPI unregsiter...\n"); + spi_unregister_driver(&wilc_bus); + #else + PRINT_D(INIT_DBG, "SDIO unregsiter...\n"); + sdio_unregister_driver(&wilc_bus); + #endif + + linux_wlan_deinit_lock(&close_exit_sync); + if (g_linux_wlan != NULL) { + WILC_FREE(g_linux_wlan); + g_linux_wlan = NULL; + } + printk("Module_exit Done.\n"); + +#if defined (WILC_DEBUGFS) + wilc_debugfs_remove(); +#endif + + linux_wlan_device_detection(0); + linux_wlan_device_power(0); + } +} +module_exit(exit_wilc_driver); + +MODULE_LICENSE("GPL"); +#endif diff --git a/drivers/staging/wilc1000/linux_wlan_common.h b/drivers/staging/wilc1000/linux_wlan_common.h new file mode 100644 index 000000000..2476bfda1 --- /dev/null +++ b/drivers/staging/wilc1000/linux_wlan_common.h @@ -0,0 +1,182 @@ +#ifndef LINUX_WLAN_COMMON_H +#define LINUX_WLAN_COMMON_H + +enum debug_region { + Generic_debug = 0, + Hostapd_debug, + Hostinf_debug, + CFG80211_debug, + Coreconfig_debug, + Interrupt_debug, + TX_debug, + RX_debug, + Lock_debug, + Tcp_enhance, + /*Added by amr - BugID_4720*/ + Spin_debug, + + Init_debug, + Bus_debug, + Mem_debug, + Firmware_debug, + COMP = 0xFFFFFFFF, +}; + +#define GENERIC_DBG (1 << Generic_debug) +#define HOSTAPD_DBG (1 << Hostapd_debug) +#define HOSTINF_DBG (1 << Hostinf_debug) +#define CORECONFIG_DBG (1 << Coreconfig_debug) +#define CFG80211_DBG (1 << CFG80211_debug) +#define INT_DBG (1 << Interrupt_debug) +#define TX_DBG (1 << TX_debug) +#define RX_DBG (1 << RX_debug) +#define LOCK_DBG (1 << Lock_debug) +#define TCP_ENH (1 << Tcp_enhance) +#define SPIN_DEBUG (1 << Spin_debug) +#define INIT_DBG (1 << Init_debug) +#define BUS_DBG (1 << Bus_debug) +#define MEM_DBG (1 << Mem_debug) +#define FIRM_DBG (1 << Firmware_debug) + +#if defined (WILC_DEBUGFS) +extern int wilc_debugfs_init(void); +extern void wilc_debugfs_remove(void); + +extern atomic_t REGION; +extern atomic_t DEBUG_LEVEL; + +#define DEBUG (1 << 0) +#define INFO (1 << 1) +#define WRN (1 << 2) +#define ERR (1 << 3) + +#define PRINT_D(region, ...) \ + do { \ + if ((atomic_read(&DEBUG_LEVEL) & DEBUG) && \ + ((atomic_read(®ION)) & (region))) { \ + printk("DBG [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_INFO(region, ...) \ + do { \ + if ((atomic_read(&DEBUG_LEVEL) & INFO) && \ + ((atomic_read(®ION)) & (region))) { \ + printk("INFO [%s]", __func__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_WRN(region, ...) \ + do { \ + if ((atomic_read(&DEBUG_LEVEL) & WRN) && \ + ((atomic_read(®ION)) & (region))) { \ + printk("WRN [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_ER(...) \ + do { \ + if ((atomic_read(&DEBUG_LEVEL) & ERR)) { \ + printk("ERR [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#else + +#define REGION (INIT_DBG | GENERIC_DBG | CFG80211_DBG | FIRM_DBG | HOSTAPD_DBG) + +#define DEBUG 1 +#define INFO 0 +#define WRN 0 + +#define PRINT_D(region, ...) \ + do { \ + if (DEBUG == 1 && ((REGION)&(region))) { \ + printk("DBG [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_INFO(region, ...) \ + do { \ + if (INFO == 1 && ((REGION)&(region))) { \ + printk("INFO [%s]", __func__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_WRN(region, ...) \ + do { \ + if (WRN == 1 && ((REGION)&(region))) { \ + printk("WRN [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_ER(...) \ + do { \ + printk("ERR [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } while (0) +#endif + +#define FN_IN /* PRINT_D(">>> \n") */ +#define FN_OUT /* PRINT_D("<<<\n") */ + +#ifdef MEMORY_STATIC +#define LINUX_RX_SIZE (96 * 1024) +#endif +#define LINUX_TX_SIZE (64 * 1024) + + +#define WILC_MULTICAST_TABLE_SIZE 8 + +#if defined (NM73131_0_BOARD) + +#define MODALIAS "wilc_spi" +#define GPIO_NUM IRQ_WILC1000_GPIO + +#elif defined (BEAGLE_BOARD) + #define SPI_CHANNEL 4 + + #if SPI_CHANNEL == 4 + #define MODALIAS "wilc_spi4" + #define GPIO_NUM 162 + #else + #define MODALIAS "wilc_spi3" + #define GPIO_NUM 133 + #endif +#elif defined(PANDA_BOARD) + #define MODALIAS "WILC_SPI" + #define GPIO_NUM 139 +#elif defined(PLAT_WMS8304) /* rachel */ + #define MODALIAS "wilc_spi" + #define GPIO_NUM 139 +#elif defined (PLAT_RKXXXX) + #define MODALIAS "WILC_IRQ" + #define GPIO_NUM RK30_PIN3_PD2 /* RK30_PIN3_PA1 */ +/* RK30_PIN3_PD2 */ +/* RK2928_PIN1_PA7 */ + +#elif defined(CUSTOMER_PLATFORM) +/* + TODO : specify MODALIAS name and GPIO number. This is certainly necessary for SPI interface. + * + * ex) + * #define MODALIAS "WILC_SPI" + * #define GPIO_NUM 139 + */ + +#else +/* base on SAMA5D3_Xplained Board */ + #define MODALIAS "WILC_SPI" + #define GPIO_NUM 0x44 +#endif + + +void linux_wlan_enable_irq(void); +#endif diff --git a/drivers/staging/wilc1000/linux_wlan_sdio.c b/drivers/staging/wilc1000/linux_wlan_sdio.c new file mode 100644 index 000000000..858e3a191 --- /dev/null +++ b/drivers/staging/wilc1000/linux_wlan_sdio.c @@ -0,0 +1,249 @@ +#include "wilc_wfi_netdevice.h" + +#include +#include +#include +#include +#include + + + +#if defined (NM73131_0_BOARD) +#define SDIO_MODALIAS "wilc_sdio" +#else +#define SDIO_MODALIAS "wilc1000_sdio" +#endif + +#if defined (NM73131_0_BOARD) + #define MAX_SPEED 50000000 +#elif defined(CUSTOMER_PLATFORM) +/* TODO : User have to stable bus clock as user's environment. */ + #ifdef MAX_BUS_SPEED + #define MAX_SPEED MAX_BUS_SPEED + #else + #define MAX_SPEED 50000000 + #endif +#else + #define MAX_SPEED (6 * 1000000) /* Max 50M */ +#endif + + +struct sdio_func *local_sdio_func; +extern linux_wlan_t *g_linux_wlan; +extern int wilc_netdev_init(void); +extern int sdio_clear_int(void); +extern void wilc_handle_isr(void); + +static unsigned int sdio_default_speed; + +#define SDIO_VENDOR_ID_WILC 0x0296 +#define SDIO_DEVICE_ID_WILC 0x5347 + +static const struct sdio_device_id wilc_sdio_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) }, +}; + + +static void wilc_sdio_interrupt(struct sdio_func *func) +{ +#ifndef WILC_SDIO_IRQ_GPIO + sdio_release_host(func); + wilc_handle_isr(); + sdio_claim_host(func); +#endif +} + + +int linux_sdio_cmd52(sdio_cmd52_t *cmd) +{ + struct sdio_func *func = g_linux_wlan->wilc_sdio_func; + int ret; + u8 data; + + sdio_claim_host(func); + + func->num = cmd->function; + if (cmd->read_write) { /* write */ + if (cmd->raw) { + sdio_writeb(func, cmd->data, cmd->address, &ret); + data = sdio_readb(func, cmd->address, &ret); + cmd->data = data; + } else { + sdio_writeb(func, cmd->data, cmd->address, &ret); + } + } else { /* read */ + data = sdio_readb(func, cmd->address, &ret); + cmd->data = data; + } + + sdio_release_host(func); + + if (ret < 0) { + PRINT_ER("wilc_sdio_cmd52..failed, err(%d)\n", ret); + return 0; + } + return 1; +} + + +int linux_sdio_cmd53(sdio_cmd53_t *cmd) +{ + struct sdio_func *func = g_linux_wlan->wilc_sdio_func; + int size, ret; + + sdio_claim_host(func); + + func->num = cmd->function; + func->cur_blksize = cmd->block_size; + if (cmd->block_mode) + size = cmd->count * cmd->block_size; + else + size = cmd->count; + + if (cmd->read_write) { /* write */ + ret = sdio_memcpy_toio(func, cmd->address, (void *)cmd->buffer, size); + } else { /* read */ + ret = sdio_memcpy_fromio(func, (void *)cmd->buffer, cmd->address, size); + } + + sdio_release_host(func); + + + if (ret < 0) { + PRINT_ER("wilc_sdio_cmd53..failed, err(%d)\n", ret); + return 0; + } + + return 1; +} + +volatile int probe; /* COMPLEMENT_BOOT */ +static int linux_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + PRINT_D(INIT_DBG, "probe function\n"); + +#ifdef COMPLEMENT_BOOT + if (local_sdio_func != NULL) { + local_sdio_func = func; + probe = 1; + PRINT_D(INIT_DBG, "local_sdio_func isn't NULL\n"); + return 0; + } +#endif + PRINT_D(INIT_DBG, "Initializing netdev\n"); + local_sdio_func = func; + if (wilc_netdev_init()) { + PRINT_ER("Couldn't initialize netdev\n"); + return -1; + } + + printk("Driver Initializing success\n"); + return 0; +} + +static void linux_sdio_remove(struct sdio_func *func) +{ + /** + * TODO + **/ + +} + +struct sdio_driver wilc_bus = { + .name = SDIO_MODALIAS, + .id_table = wilc_sdio_ids, + .probe = linux_sdio_probe, + .remove = linux_sdio_remove, +}; + +int enable_sdio_interrupt(void) +{ + int ret = 0; +#ifndef WILC_SDIO_IRQ_GPIO + + sdio_claim_host(local_sdio_func); + ret = sdio_claim_irq(local_sdio_func, wilc_sdio_interrupt); + sdio_release_host(local_sdio_func); + + if (ret < 0) { + PRINT_ER("can't claim sdio_irq, err(%d)\n", ret); + ret = -EIO; + } +#endif + return ret; +} + +void disable_sdio_interrupt(void) +{ + +#ifndef WILC_SDIO_IRQ_GPIO + int ret; + + PRINT_D(INIT_DBG, "disable_sdio_interrupt IN\n"); + + sdio_claim_host(local_sdio_func); + ret = sdio_release_irq(local_sdio_func); + if (ret < 0) { + PRINT_ER("can't release sdio_irq, err(%d)\n", ret); + } + sdio_release_host(local_sdio_func); + + PRINT_D(INIT_DBG, "disable_sdio_interrupt OUT\n"); +#endif +} + +static int linux_sdio_set_speed(int speed) +{ + struct mmc_ios ios; + sdio_claim_host(local_sdio_func); + + memcpy((void *)&ios, (void *)&local_sdio_func->card->host->ios, sizeof(struct mmc_ios)); + local_sdio_func->card->host->ios.clock = speed; + ios.clock = speed; + local_sdio_func->card->host->ops->set_ios(local_sdio_func->card->host, &ios); + sdio_release_host(local_sdio_func); + PRINT_INFO(INIT_DBG, "@@@@@@@@@@@@ change SDIO speed to %d @@@@@@@@@\n", speed); + + return 1; +} + +static int linux_sdio_get_speed(void) +{ + return local_sdio_func->card->host->ios.clock; +} + +int linux_sdio_init(void *pv) +{ + + /** + * TODO : + **/ + + + sdio_default_speed = linux_sdio_get_speed(); + return 1; +} + +void linux_sdio_deinit(void *pv) +{ + + /** + * TODO : + **/ + + + sdio_unregister_driver(&wilc_bus); +} + +int linux_sdio_set_max_speed(void) +{ + return linux_sdio_set_speed(MAX_SPEED); +} + +int linux_sdio_set_default_speed(void) +{ + return linux_sdio_set_speed(sdio_default_speed); +} + + + diff --git a/drivers/staging/wilc1000/linux_wlan_sdio.h b/drivers/staging/wilc1000/linux_wlan_sdio.h new file mode 100644 index 000000000..4b515f510 --- /dev/null +++ b/drivers/staging/wilc1000/linux_wlan_sdio.h @@ -0,0 +1,14 @@ +extern struct sdio_func *local_sdio_func; +extern struct sdio_driver wilc_bus; + +#include + +int linux_sdio_init(void *); +void linux_sdio_deinit(void *); +int linux_sdio_cmd52(sdio_cmd52_t *cmd); +int linux_sdio_cmd53(sdio_cmd53_t *cmd); +int enable_sdio_interrupt(void); +void disable_sdio_interrupt(void); +int linux_sdio_set_max_speed(void); +int linux_sdio_set_default_speed(void); + diff --git a/drivers/staging/wilc1000/linux_wlan_spi.c b/drivers/staging/wilc1000/linux_wlan_spi.c new file mode 100644 index 000000000..236669cfc --- /dev/null +++ b/drivers/staging/wilc1000/linux_wlan_spi.c @@ -0,0 +1,479 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linux_wlan_common.h" + +#define USE_SPI_DMA 0 /* johnny add */ + +#ifdef WILC_ASIC_A0 + #if defined(PLAT_PANDA_ES_OMAP4460) + #define MIN_SPEED 12000000 + #define MAX_SPEED 24000000 + #elif defined(PLAT_WMS8304) + #define MIN_SPEED 12000000 + #define MAX_SPEED 24000000 /* 4000000 */ + #elif defined(CUSTOMER_PLATFORM) +/* + TODO : define Clock speed under 48M. + * + * ex) + * #define MIN_SPEED 24000000 + * #define MAX_SPEED 48000000 + */ + #else + #define MIN_SPEED 24000000 + #define MAX_SPEED 48000000 + #endif +#else /* WILC_ASIC_A0 */ +/* Limit clk to 6MHz on FPGA. */ + #define MIN_SPEED 6000000 + #define MAX_SPEED 6000000 +#endif /* WILC_ASIC_A0 */ + +static uint32_t SPEED = MIN_SPEED; + +struct spi_device *wilc_spi_dev; +void linux_spi_deinit(void *vp); + +static int __init wilc_bus_probe(struct spi_device *spi) +{ + + PRINT_D(BUS_DBG, "spiModalias: %s\n", spi->modalias); + PRINT_D(BUS_DBG, "spiMax-Speed: %d\n", spi->max_speed_hz); + wilc_spi_dev = spi; + + printk("Driver Initializing success\n"); + return 0; +} + +static int __exit wilc_bus_remove(struct spi_device *spi) +{ + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id wilc1000_of_match[] = { + { .compatible = "atmel,wilc_spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, wilc1000_of_match); +#endif + +struct spi_driver wilc_bus __refdata = { + .driver = { + .name = MODALIAS, +#ifdef CONFIG_OF + .of_match_table = wilc1000_of_match, +#endif + }, + .probe = wilc_bus_probe, + .remove = __exit_p(wilc_bus_remove), +}; + + +void linux_spi_deinit(void *vp) +{ + + spi_unregister_driver(&wilc_bus); + + SPEED = MIN_SPEED; + PRINT_ER("@@@@@@@@@@@@ restore SPI speed to %d @@@@@@@@@\n", SPEED); + +} + + + +int linux_spi_init(void *vp) +{ + int ret = 1; + static int called; + + + if (called == 0) { + called++; + ret = spi_register_driver(&wilc_bus); + } + + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +#if defined(PLAT_WMS8304) +#define TXRX_PHASE_SIZE (4096) +#endif + +#if defined (NM73131_0_BOARD) + +int linux_spi_write(uint8_t *b, uint32_t len) +{ + + int ret; + + if (len > 0 && b != NULL) { + struct spi_message msg; + PRINT_D(BUS_DBG, "Request writing %d bytes\n", len); + struct spi_transfer tr = { + .tx_buf = b, + .len = len, + .speed_hz = SPEED, + .delay_usecs = 0, + }; + + spi_message_init(&msg); + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + + } else { + PRINT_ER("can't write data with the following length: %d\n", len); + PRINT_ER("FAILED due to NULL buffer or ZERO length check the following length: %d\n", len); + ret = -1; + } + + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + + return ret; +} + +#elif defined(TXRX_PHASE_SIZE) + +int linux_spi_write(uint8_t *b, uint32_t len) +{ + int ret; + if (len > 0 && b != NULL) { + int i = 0; + int blk = len / TXRX_PHASE_SIZE; + int remainder = len % TXRX_PHASE_SIZE; + + char *r_buffer = kzalloc(TXRX_PHASE_SIZE, GFP_KERNEL); + if (!r_buffer) { + PRINT_ER("Failed to allocate memory for r_buffer\n"); + } + + if (blk) { + while (i < blk) { + struct spi_message msg; + struct spi_transfer tr = { + .tx_buf = b + (i * TXRX_PHASE_SIZE), + .len = TXRX_PHASE_SIZE, + .speed_hz = SPEED, + .bits_per_word = 8, + .delay_usecs = 0, + }; + + tr.rx_buf = r_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + i++; + + } + } + if (remainder) { + struct spi_message msg; + struct spi_transfer tr = { + .tx_buf = b + (blk * TXRX_PHASE_SIZE), + .len = remainder, + .speed_hz = SPEED, + .bits_per_word = 8, + .delay_usecs = 0, + }; + tr.rx_buf = r_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; /* rachel */ + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + } + kfree(r_buffer); + } else { + PRINT_ER("can't write data with the following length: %d\n", len); + PRINT_ER("FAILED due to NULL buffer or ZERO length check the following length: %d\n", len); + ret = -1; + } + + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; + +} + +#else +int linux_spi_write(uint8_t *b, uint32_t len) +{ + + int ret; + struct spi_message msg; + + if (len > 0 && b != NULL) { + struct spi_transfer tr = { + .tx_buf = b, + .len = len, + .speed_hz = SPEED, + .delay_usecs = 0, + }; + char *r_buffer = kzalloc(len, GFP_KERNEL); + if (!r_buffer) { + PRINT_ER("Failed to allocate memory for r_buffer\n"); + } + tr.rx_buf = r_buffer; + PRINT_D(BUS_DBG, "Request writing %d bytes\n", len); + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); +/* [[johnny add */ + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; +/* ]] */ + spi_message_add_tail(&tr, &msg); + + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + + kfree(r_buffer); + } else { + PRINT_ER("can't write data with the following length: %d\n", len); + PRINT_ER("FAILED due to NULL buffer or ZERO length check the following length: %d\n", len); + ret = -1; + } + + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + + return ret; +} + +#endif + +#if defined (NM73131_0_BOARD) + +int linux_spi_read(unsigned char *rb, unsigned long rlen) +{ + + int ret; + + if (rlen > 0) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb, + .len = rlen, + .speed_hz = SPEED, + .delay_usecs = 0, + + }; + + spi_message_init(&msg); + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + } else { + PRINT_ER("can't read data with the following length: %ld\n", rlen); + ret = -1; + } + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +#elif defined(TXRX_PHASE_SIZE) + +int linux_spi_read(unsigned char *rb, unsigned long rlen) +{ + int ret; + + if (rlen > 0) { + int i = 0; + + int blk = rlen / TXRX_PHASE_SIZE; + int remainder = rlen % TXRX_PHASE_SIZE; + + char *t_buffer = kzalloc(TXRX_PHASE_SIZE, GFP_KERNEL); + if (!t_buffer) { + PRINT_ER("Failed to allocate memory for t_buffer\n"); + } + + if (blk) { + while (i < blk) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb + (i * TXRX_PHASE_SIZE), + .len = TXRX_PHASE_SIZE, + .speed_hz = SPEED, + .bits_per_word = 8, + .delay_usecs = 0, + }; + tr.tx_buf = t_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + i++; + } + } + if (remainder) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb + (blk * TXRX_PHASE_SIZE), + .len = remainder, + .speed_hz = SPEED, + .bits_per_word = 8, + .delay_usecs = 0, + }; + tr.tx_buf = t_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; /* rachel */ + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + } + + kfree(t_buffer); + } else { + PRINT_ER("can't read data with the following length: %ld\n", rlen); + ret = -1; + } + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +#else +int linux_spi_read(unsigned char *rb, unsigned long rlen) +{ + + int ret; + + if (rlen > 0) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb, + .len = rlen, + .speed_hz = SPEED, + .delay_usecs = 0, + + }; + char *t_buffer = kzalloc(rlen, GFP_KERNEL); + if (!t_buffer) { + PRINT_ER("Failed to allocate memory for t_buffer\n"); + } + tr.tx_buf = t_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); +/* [[ johnny add */ + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; +/* ]] */ + spi_message_add_tail(&tr, &msg); + + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + kfree(t_buffer); + } else { + PRINT_ER("can't read data with the following length: %ld\n", rlen); + ret = -1; + } + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +#endif + +int linux_spi_write_read(unsigned char *wb, unsigned char *rb, unsigned int rlen) +{ + + int ret; + + if (rlen > 0) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb, + .tx_buf = wb, + .len = rlen, + .speed_hz = SPEED, + .bits_per_word = 8, + .delay_usecs = 0, + + }; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + } else { + PRINT_ER("can't read data with the following length: %d\n", rlen); + ret = -1; + } + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +int linux_spi_set_max_speed(void) +{ + SPEED = MAX_SPEED; + + PRINT_INFO(BUS_DBG, "@@@@@@@@@@@@ change SPI speed to %d @@@@@@@@@\n", SPEED); + return 1; +} diff --git a/drivers/staging/wilc1000/linux_wlan_spi.h b/drivers/staging/wilc1000/linux_wlan_spi.h new file mode 100644 index 000000000..0ecad477d --- /dev/null +++ b/drivers/staging/wilc1000/linux_wlan_spi.h @@ -0,0 +1,14 @@ +#ifndef LINUX_WLAN_SPI_H +#define LINUX_WLAN_SPI_H + +#include +extern struct spi_device *wilc_spi_dev; +extern struct spi_driver wilc_bus; + +int linux_spi_init(void *vp); +void linux_spi_deinit(void *vp); +int linux_spi_write(uint8_t *b, uint32_t len); +int linux_spi_read(uint8_t *rb, uint32_t rlen); +int linux_spi_write_read(unsigned char *wb, unsigned char *rb, unsigned int rlen); +int linux_spi_set_max_speed(void); +#endif diff --git a/drivers/staging/wilc1000/wilc_debugfs.c b/drivers/staging/wilc1000/wilc_debugfs.c new file mode 100644 index 000000000..c328208cd --- /dev/null +++ b/drivers/staging/wilc1000/wilc_debugfs.c @@ -0,0 +1,191 @@ +/* + * NewportMedia WiFi chipset driver test tools - wilc-debug + * Copyright (c) 2012 NewportMedia Inc. + * Author: SSW + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#if defined(WILC_DEBUGFS) +#include +#include +#include +#include + +#include "wilc_wlan_if.h" + + +static struct dentry *wilc_dir; + +/* + * -------------------------------------------------------------------------------- + */ + +#define DBG_REGION_ALL (GENERIC_DBG | HOSTAPD_DBG | HOSTINF_DBG | CORECONFIG_DBG | CFG80211_DBG | INT_DBG | TX_DBG | RX_DBG | LOCK_DBG | INIT_DBG | BUS_DBG | MEM_DBG) +#define DBG_LEVEL_ALL (DEBUG | INFO | WRN | ERR) +atomic_t REGION = ATOMIC_INIT(INIT_DBG | GENERIC_DBG | CFG80211_DBG | FIRM_DBG | HOSTAPD_DBG); +atomic_t DEBUG_LEVEL = ATOMIC_INIT(ERR); + +/* + * -------------------------------------------------------------------------------- + */ + + +static ssize_t wilc_debug_level_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) +{ + char buf[128]; + int res = 0; + + /* only allow read from start */ + if (*ppos > 0) + return 0; + + res = scnprintf(buf, sizeof(buf), "Debug Level: %x\n", atomic_read(&DEBUG_LEVEL)); + + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static ssize_t wilc_debug_level_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) +{ + char buffer[128] = {}; + int flag = 0; + + if (count > sizeof(buffer)) + return -EINVAL; + + if (copy_from_user(buffer, buf, count)) { + return -EFAULT; + } + + flag = buffer[0] - '0'; + + if (flag > 0) { + flag = DEBUG | ERR; + } else if (flag < 0) { + flag = 100; + } + + if (flag > DBG_LEVEL_ALL) { + printk("%s, value (0x%08x) is out of range, stay previous flag (0x%08x)\n", __func__, flag, atomic_read(&DEBUG_LEVEL)); + return -EFAULT; + } + + atomic_set(&DEBUG_LEVEL, (int)flag); + + if (flag == 0) { + printk("Debug-level disabled\n"); + } else { + printk("Debug-level enabled\n"); + } + return count; +} + +static ssize_t wilc_debug_region_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) +{ + char buf[128]; + int res = 0; + + /* only allow read from start */ + if (*ppos > 0) + return 0; + + res = scnprintf(buf, sizeof(buf), "Debug region: %x\n", atomic_read(®ION)); + + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static ssize_t wilc_debug_region_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) +{ + char buffer[128] = {}; + int flag; + + if (count > sizeof(buffer)) + return -EINVAL; + + if (copy_from_user(buffer, buf, count)) { + return -EFAULT; + } + + flag = buffer[0] - '0'; + + if (flag > DBG_REGION_ALL) { + printk("%s, value (0x%08x) is out of range, stay previous flag (0x%08x)\n", __func__, flag, atomic_read(®ION)); + return -EFAULT; + } + + atomic_set(®ION, (int)flag); + printk("new debug-region is %x\n", atomic_read(®ION)); + + return count; +} + +/* + * -------------------------------------------------------------------------------- + */ + +#define FOPS(_open, _read, _write, _poll) { \ + .owner = THIS_MODULE, \ + .open = (_open), \ + .read = (_read), \ + .write = (_write), \ + .poll = (_poll), \ +} + +struct wilc_debugfs_info_t { + const char *name; + int perm; + unsigned int data; + struct file_operations fops; +}; + +static struct wilc_debugfs_info_t debugfs_info[] = { + { "wilc_debug_level", 0666, (DEBUG | ERR), FOPS(NULL, wilc_debug_level_read, wilc_debug_level_write, NULL), }, + { "wilc_debug_region", 0666, (INIT_DBG | GENERIC_DBG | CFG80211_DBG), FOPS(NULL, wilc_debug_region_read, wilc_debug_region_write, NULL), }, +}; + +int wilc_debugfs_init(void) +{ + int i; + + struct dentry *debugfs_files; + struct wilc_debugfs_info_t *info; + + wilc_dir = debugfs_create_dir("wilc_wifi", NULL); + if (wilc_dir == ERR_PTR(-ENODEV)) { + /* it's not error. the debugfs is just not being enabled. */ + printk("ERR, kernel has built without debugfs support\n"); + return 0; + } + + if (!wilc_dir) { + printk("ERR, debugfs create dir\n"); + return -1; + } + + for (i = 0; i < ARRAY_SIZE(debugfs_info); i++) { + info = &debugfs_info[i]; + debugfs_files = debugfs_create_file(info->name, + info->perm, + wilc_dir, + &info->data, + &info->fops); + + if (!debugfs_files) { + printk("ERR fail to create the debugfs file, %s\n", info->name); + debugfs_remove_recursive(wilc_dir); + return -1; + } + } + return 0; +} + +void wilc_debugfs_remove(void) +{ + debugfs_remove_recursive(wilc_dir); +} + +#endif + diff --git a/drivers/staging/wilc1000/wilc_errorsupport.h b/drivers/staging/wilc1000/wilc_errorsupport.h new file mode 100644 index 000000000..b9517dc7f --- /dev/null +++ b/drivers/staging/wilc1000/wilc_errorsupport.h @@ -0,0 +1,67 @@ +#ifndef __WILC_ERRORSUPPORT_H__ +#define __WILC_ERRORSUPPORT_H__ + +/*! + * @file wilc_errorsupport.h + * @brief Error reporting and handling support + * @author syounan + * @sa wilc_oswrapper.h top level OS wrapper file + * @date 10 Aug 2010 + * @version 1.0 + */ + +#include "linux_wlan_common.h" + +/* Psitive Numbers to indicate sucess with special status */ +#define WILC_ALREADY_EXSIT (+100) /** The requested object already exists */ + +/* Generic success will return 0 */ +#define WILC_SUCCESS 0 /** Generic success */ + +/* Negative numbers to indicate failures */ +#define WILC_FAIL -100 /** Generic Fail */ +#define WILC_BUSY -101 /** Busy with another operation*/ +#define WILC_INVALID_ARGUMENT -102 /** A given argument is invalid*/ +#define WILC_INVALID_STATE -103 /** An API request would violate the Driver state machine (i.e. to start PID while not camped)*/ +#define WILC_BUFFER_OVERFLOW -104 /** In copy operations if the copied data is larger than the allocated buffer*/ +#define WILC_NULL_PTR -105 /** null pointer is passed or used */ +#define WILC_EMPTY -107 +#define WILC_FULL -108 +#define WILC_TIMEOUT -109 +#define WILC_CANCELED -110 /** The required operation have been canceled by the user*/ +#define WILC_INVALID_FILE -112 /** The Loaded file is corruped or having an invalid format */ +#define WILC_NOT_FOUND -113 /** Cant find the file to load */ +#define WILC_NO_MEM -114 +#define WILC_UNSUPPORTED_VERSION -115 +#define WILC_FILE_EOF -116 + + +/* Error type */ +typedef s32 WILC_ErrNo; + +#define WILC_IS_ERR(__status__) (__status__ < WILC_SUCCESS) + +#define WILC_ERRORCHECK(__status__) do { \ + if (WILC_IS_ERR(__status__)) { \ + PRINT_ER("PRINT_ER(%d)\n", __status__); \ + goto ERRORHANDLER; \ + } \ +} while (0) + +#define WILC_ERRORREPORT(__status__, __err__) do { \ + PRINT_ER("PRINT_ER(%d)\n", __err__); \ + __status__ = __err__; \ + goto ERRORHANDLER; \ +} while (0) + +#define WILC_NULLCHECK(__status__, __ptr__) do { \ + if (__ptr__ == NULL) { \ + WILC_ERRORREPORT(__status__, WILC_NULL_PTR); \ + } \ +} while (0) + +#define WILC_CATCH(__status__) \ +ERRORHANDLER: \ + if (WILC_IS_ERR(__status__)) \ + +#endif diff --git a/drivers/staging/wilc1000/wilc_exported_buf.c b/drivers/staging/wilc1000/wilc_exported_buf.c new file mode 100644 index 000000000..529457816 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_exported_buf.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include + +#define LINUX_RX_SIZE (96 * 1024) +#define LINUX_TX_SIZE (64 * 1024) +#define WILC1000_FW_SIZE (4 * 1024) + +#define DECLARE_WILC_BUFFER(name) \ + void *exported_ ## name = NULL; + +#define MALLOC_WILC_BUFFER(name, size) \ + exported_ ## name = kmalloc(size, GFP_KERNEL); \ + if (!exported_ ## name) { \ + printk("fail to alloc: %s memory\n", exported_ ## name); \ + return -ENOBUFS; \ + } + +#define FREE_WILC_BUFFER(name) \ + kfree(exported_ ## name); + +/* + * Add necessary buffer pointers + */ +DECLARE_WILC_BUFFER(g_tx_buf) +DECLARE_WILC_BUFFER(g_rx_buf) +DECLARE_WILC_BUFFER(g_fw_buf) + +void *get_tx_buffer(void) +{ + return exported_g_tx_buf; +} +EXPORT_SYMBOL(get_tx_buffer); + +void *get_rx_buffer(void) +{ + return exported_g_rx_buf; +} +EXPORT_SYMBOL(get_rx_buffer); + +void *get_fw_buffer(void) +{ + return exported_g_fw_buf; +} +EXPORT_SYMBOL(get_fw_buffer); + +static int __init wilc_module_init(void) +{ + printk("wilc_module_init\n"); + /* + * alloc necessary memory + */ + MALLOC_WILC_BUFFER(g_tx_buf, LINUX_TX_SIZE) + MALLOC_WILC_BUFFER(g_rx_buf, LINUX_RX_SIZE) + MALLOC_WILC_BUFFER(g_fw_buf, WILC1000_FW_SIZE) + + return 0; +} + +static void __exit wilc_module_deinit(void) +{ + printk("wilc_module_deinit\n"); + FREE_WILC_BUFFER(g_tx_buf) + FREE_WILC_BUFFER(g_rx_buf) + FREE_WILC_BUFFER(g_fw_buf) + + return; +} + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Tony Cho"); +MODULE_DESCRIPTION("WILC1xxx Memory Manager"); +pure_initcall(wilc_module_init); +module_exit(wilc_module_deinit); \ No newline at end of file diff --git a/drivers/staging/wilc1000/wilc_log.h b/drivers/staging/wilc1000/wilc_log.h new file mode 100644 index 000000000..2269ebdec --- /dev/null +++ b/drivers/staging/wilc1000/wilc_log.h @@ -0,0 +1,47 @@ +#ifndef __WILC_LOG_H__ +#define __WILC_LOG_H__ + +/* Errors will always get printed */ +#define WILC_ERROR(...) do { WILC_PRINTF("(ERR)(%s:%d) ", __WILC_FUNCTION__, __WILC_LINE__); \ + WILC_PRINTF(__VA_ARGS__); \ + } while (0) + +/* Wraning only printed if verbosity is 1 or more */ +#if (WILC_LOG_VERBOSITY_LEVEL > 0) +#define WILC_WARN(...) do { WILC_PRINTF("(WRN)"); \ + WILC_PRINTF(__VA_ARGS__); \ + } while (0) +#else +#define WILC_WARN(...) (0) +#endif + +/* Info only printed if verbosity is 2 or more */ +#if (WILC_LOG_VERBOSITY_LEVEL > 1) +#define WILC_INFO(...) do { WILC_PRINTF("(INF)"); \ + WILC_PRINTF(__VA_ARGS__); \ + } while (0) +#else +#define WILC_INFO(...) (0) +#endif + +/* Debug is only printed if verbosity is 3 or more */ +#if (WILC_LOG_VERBOSITY_LEVEL > 2) +#define WILC_DBG(...) do { WILC_PRINTF("(DBG)(%s:%d) ", __WILC_FUNCTION__, __WILC_LINE__); \ + WILC_PRINTF(__VA_ARGS__); \ + } while (0) + +#else +#define WILC_DBG(...) (0) +#endif + +/* Function In/Out is only printed if verbosity is 4 or more */ +#if (WILC_LOG_VERBOSITY_LEVEL > 3) +#define WILC_FN_IN do { WILC_PRINTF("(FIN) (%s:%d) \n", __WILC_FUNCTION__, __WILC_LINE__); } while (0) +#define WILC_FN_OUT(ret) do { WILC_PRINTF("(FOUT) (%s:%d) %d.\n", __WILC_FUNCTION__, __WILC_LINE__, (ret)); } while (0) +#else +#define WILC_FN_IN (0) +#define WILC_FN_OUT(ret) (0) +#endif + + +#endif \ No newline at end of file diff --git a/drivers/staging/wilc1000/wilc_memory.c b/drivers/staging/wilc1000/wilc_memory.c new file mode 100644 index 000000000..c70707fef --- /dev/null +++ b/drivers/staging/wilc1000/wilc_memory.c @@ -0,0 +1,58 @@ + +#include "wilc_memory.h" + +/*! + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +void *WILC_MemoryAlloc(u32 u32Size, tstrWILC_MemoryAttrs *strAttrs, + char *pcFileName, u32 u32LineNo) +{ + if (u32Size > 0) { + return kmalloc(u32Size, GFP_ATOMIC); + } else { + return NULL; + } +} + +/*! + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +void *WILC_MemoryCalloc(u32 u32Size, tstrWILC_MemoryAttrs *strAttrs, + char *pcFileName, u32 u32LineNo) +{ + return kcalloc(u32Size, 1, GFP_KERNEL); +} + +/*! + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +void *WILC_MemoryRealloc(void *pvOldBlock, u32 u32NewSize, + tstrWILC_MemoryAttrs *strAttrs, char *pcFileName, u32 u32LineNo) +{ + if (u32NewSize == 0) { + kfree(pvOldBlock); + return NULL; + } else if (pvOldBlock == NULL) { + return kmalloc(u32NewSize, GFP_KERNEL); + } else { + return krealloc(pvOldBlock, u32NewSize, GFP_KERNEL); + } + +} + +/*! + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +void WILC_MemoryFree(const void *pvBlock, tstrWILC_MemoryAttrs *strAttrs, + char *pcFileName, u32 u32LineNo) +{ + kfree(pvBlock); +} diff --git a/drivers/staging/wilc1000/wilc_memory.h b/drivers/staging/wilc1000/wilc_memory.h new file mode 100644 index 000000000..372d7053e --- /dev/null +++ b/drivers/staging/wilc1000/wilc_memory.h @@ -0,0 +1,239 @@ +#ifndef __WILC_MEMORY_H__ +#define __WILC_MEMORY_H__ + +/*! + * @file wilc_memory.h + * @brief Memory OS wrapper functionality + * @author syounan + * @sa wilc_oswrapper.h top level OS wrapper file + * @date 16 Aug 2010 + * @version 1.0 + */ + +#include +#include + +/*! + * @struct tstrWILC_MemoryAttrs + * @brief Memory API options + * @author syounan + * @date 16 Aug 2010 + * @version 1.0 + */ +typedef struct { +} tstrWILC_MemoryAttrs; + +/*! + * @brief Allocates a given size of bytes + * @param[in] u32Size size of memory in bytes to be allocated + * @param[in] strAttrs Optional attributes, NULL for default + * if not NULL, pAllocationPool should point to the pool to use for + * this allocation. if NULL memory will be allocated directly from + * the system + * @param[in] pcFileName file name of the calling code for debugging + * @param[in] u32LineNo line number of the calling code for debugging + * @return The new allocated block, NULL if allocation fails + * @note It is recommended to use of of the wrapper macros instead of + * calling this function directly + * @sa sttrWILC_MemoryAttrs + * @sa WILC_MALLOC + * @sa WILC_MALLOC_EX + * @sa WILC_NEW + * @sa WILC_NEW_EX + * @author syounan + * @date 16 Aug 2010 + * @version 1.0 + */ +void *WILC_MemoryAlloc(u32 u32Size, tstrWILC_MemoryAttrs *strAttrs, + char *pcFileName, u32 u32LineNo); + +/*! + * @brief Allocates a given size of bytes and zero filling it + * @param[in] u32Size size of memory in bytes to be allocated + * @param[in] strAttrs Optional attributes, NULL for default + * if not NULL, pAllocationPool should point to the pool to use for + * this allocation. if NULL memory will be allocated directly from + * the system + * @param[in] pcFileName file name of the calling code for debugging + * @param[in] u32LineNo line number of the calling code for debugging + * @return The new allocated block, NULL if allocation fails + * @note It is recommended to use of of the wrapper macros instead of + * calling this function directly + * @sa sttrWILC_MemoryAttrs + * @sa WILC_CALLOC + * @sa WILC_CALLOC_EX + * @sa WILC_NEW_0 + * @sa WILC_NEW_0_EX + * @author syounan + * @date 16 Aug 2010 + * @version 1.0 + */ +void *WILC_MemoryCalloc(u32 u32Size, tstrWILC_MemoryAttrs *strAttrs, + char *pcFileName, u32 u32LineNo); + +/*! + * @brief Reallocates a given block to a new size + * @param[in] pvOldBlock the old memory block, if NULL then this function + * behaves as a new allocation function + * @param[in] u32NewSize size of the new memory block in bytes, if zero then + * this function behaves as a free function + * @param[in] strAttrs Optional attributes, NULL for default + * if pAllocationPool!=NULL and pvOldBlock==NULL, pAllocationPool + * should point to the pool to use for this allocation. + * if pAllocationPool==NULL and pvOldBlock==NULL memory will be + * allocated directly from the system + * if and pvOldBlock!=NULL, pAllocationPool will not be inspected + * and reallocation is done from the same pool as the original block + * @param[in] pcFileName file name of the calling code for debugging + * @param[in] u32LineNo line number of the calling code for debugging + * @return The new allocated block, possibly same as pvOldBlock + * @note It is recommended to use of of the wrapper macros instead of + * calling this function directly + * @sa sttrWILC_MemoryAttrs + * @sa WILC_REALLOC + * @sa WILC_REALLOC_EX + * @author syounan + * @date 16 Aug 2010 + * @version 1.0 + */ +void *WILC_MemoryRealloc(void *pvOldBlock, u32 u32NewSize, + tstrWILC_MemoryAttrs *strAttrs, char *pcFileName, u32 u32LineNo); + +/*! + * @brief Frees given block + * @param[in] pvBlock the memory block to be freed + * @param[in] strAttrs Optional attributes, NULL for default + * @param[in] pcFileName file name of the calling code for debugging + * @param[in] u32LineNo line number of the calling code for debugging + * @note It is recommended to use of of the wrapper macros instead of + * calling this function directly + * @sa sttrWILC_MemoryAttrs + * @sa WILC_FREE + * @sa WILC_FREE_EX + * @sa WILC_FREE_SET_NULL + * @sa WILC_FREE_IF_TRUE + * @author syounan + * @date 16 Aug 2010 + * @version 1.0 + */ +void WILC_MemoryFree(const void *pvBlock, tstrWILC_MemoryAttrs *strAttrs, + char *pcFileName, u32 u32LineNo); + +/*! + * @brief standrad malloc wrapper with custom attributes + */ + #define WILC_MALLOC_EX(__size__, __attrs__) \ + (WILC_MemoryAlloc( \ + (__size__), __attrs__, NULL, 0)) + +/*! + * @brief standrad calloc wrapper with custom attributes + */ + #define WILC_CALLOC_EX(__size__, __attrs__) \ + (WILC_MemoryCalloc( \ + (__size__), __attrs__, NULL, 0)) + +/*! + * @brief standrad realloc wrapper with custom attributes + */ + #define WILC_REALLOC_EX(__ptr__, __new_size__, __attrs__) \ + (WILC_MemoryRealloc( \ + (__ptr__), (__new_size__), __attrs__, NULL, 0)) +/*! + * @brief standrad free wrapper with custom attributes + */ + #define WILC_FREE_EX(__ptr__, __attrs__) \ + (WILC_MemoryFree( \ + (__ptr__), __attrs__, NULL, 0)) + +/*! + * @brief Allocates a block (with custom attributes) of given type and number of + * elements + */ +#define WILC_NEW_EX(__struct_type__, __n_structs__, __attrs__) \ + ((__struct_type__ *)WILC_MALLOC_EX( \ + sizeof(__struct_type__) * (u32)(__n_structs__), __attrs__)) + +/*! + * @brief Allocates a block (with custom attributes) of given type and number of + * elements and Zero-fills it + */ +#define WILC_NEW_0_EX(__struct_type__, __n_structs__, __attrs__) \ + ((__struct_type__ *)WILC_CALLOC_EX( \ + sizeof(__struct_type__) * (u32)(__n_structs__), __attrs__)) + +/*! + * @brief Frees a block (with custom attributes), also setting the original pointer + * to NULL + */ +#define WILC_FREE_SET_NULL_EX(__ptr__, __attrs__) do { \ + if (__ptr__ != NULL) { \ + WILC_FREE_EX(__ptr__, __attrs__); \ + __ptr__ = NULL; \ + } \ +} while (0) + +/*! + * @brief Frees a block (with custom attributes) if the pointer expression evaluates + * to true + */ +#define WILC_FREE_IF_TRUE_EX(__ptr__, __attrs__) do { \ + if (__ptr__ != NULL) { \ + WILC_FREE_EX(__ptr__, __attrs__); \ + } \ +} while (0) + +/*! + * @brief standrad malloc wrapper with default attributes + */ +#define WILC_MALLOC(__size__) \ + WILC_MALLOC_EX(__size__, NULL) + +/*! + * @brief standrad calloc wrapper with default attributes + */ +#define WILC_CALLOC(__size__) \ + WILC_CALLOC_EX(__size__, NULL) + +/*! + * @brief standrad realloc wrapper with default attributes + */ +#define WILC_REALLOC(__ptr__, __new_size__) \ + WILC_REALLOC_EX(__ptr__, __new_size__, NULL) + +/*! + * @brief standrad free wrapper with default attributes + */ +#define WILC_FREE(__ptr__) \ + WILC_FREE_EX(__ptr__, NULL) + +/*! + * @brief Allocates a block (with default attributes) of given type and number of + * elements + */ +#define WILC_NEW(__struct_type__, __n_structs__) \ + WILC_NEW_EX(__struct_type__, __n_structs__, NULL) + +/*! + * @brief Allocates a block (with default attributes) of given type and number of + * elements and Zero-fills it + */ +#define WILC_NEW_0(__struct_type__, __n_structs__) \ + WILC_NEW_O_EX(__struct_type__, __n_structs__, NULL) + +/*! + * @brief Frees a block (with default attributes), also setting the original pointer + * to NULL + */ +#define WILC_FREE_SET_NULL(__ptr__) \ + WILC_FREE_SET_NULL_EX(__ptr__, NULL) + +/*! + * @brief Frees a block (with default attributes) if the pointer expression evaluates + * to true + */ +#define WILC_FREE_IF_TRUE(__ptr__) \ + WILC_FREE_IF_TRUE_EX(__ptr__, NULL) + + +#endif diff --git a/drivers/staging/wilc1000/wilc_msgqueue.c b/drivers/staging/wilc1000/wilc_msgqueue.c new file mode 100644 index 000000000..16bcef4b5 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_msgqueue.c @@ -0,0 +1,190 @@ + +#include "wilc_msgqueue.h" +#include + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +WILC_ErrNo WILC_MsgQueueCreate(WILC_MsgQueueHandle *pHandle, + tstrWILC_MsgQueueAttrs *pstrAttrs) +{ + spin_lock_init(&pHandle->strCriticalSection); + sema_init(&pHandle->hSem, 0); + pHandle->pstrMessageList = NULL; + pHandle->u32ReceiversCount = 0; + pHandle->bExiting = false; + return WILC_SUCCESS; +} + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +WILC_ErrNo WILC_MsgQueueDestroy(WILC_MsgQueueHandle *pHandle, + tstrWILC_MsgQueueAttrs *pstrAttrs) +{ + + pHandle->bExiting = true; + + /* Release any waiting receiver thread. */ + while (pHandle->u32ReceiversCount > 0) { + up(&(pHandle->hSem)); + pHandle->u32ReceiversCount--; + } + + while (pHandle->pstrMessageList != NULL) { + Message *pstrMessge = pHandle->pstrMessageList->pstrNext; + WILC_FREE(pHandle->pstrMessageList); + pHandle->pstrMessageList = pstrMessge; + } + + return WILC_SUCCESS; +} + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +WILC_ErrNo WILC_MsgQueueSend(WILC_MsgQueueHandle *pHandle, + const void *pvSendBuffer, u32 u32SendBufferSize, + tstrWILC_MsgQueueAttrs *pstrAttrs) +{ + WILC_ErrNo s32RetStatus = WILC_SUCCESS; + unsigned long flags; + Message *pstrMessage = NULL; + + if ((pHandle == NULL) || (u32SendBufferSize == 0) || (pvSendBuffer == NULL)) { + WILC_ERRORREPORT(s32RetStatus, WILC_INVALID_ARGUMENT); + } + + if (pHandle->bExiting == true) { + WILC_ERRORREPORT(s32RetStatus, WILC_FAIL); + } + + spin_lock_irqsave(&pHandle->strCriticalSection, flags); + + /* construct a new message */ + pstrMessage = WILC_NEW(Message, 1); + WILC_NULLCHECK(s32RetStatus, pstrMessage); + pstrMessage->u32Length = u32SendBufferSize; + pstrMessage->pstrNext = NULL; + pstrMessage->pvBuffer = WILC_MALLOC(u32SendBufferSize); + WILC_NULLCHECK(s32RetStatus, pstrMessage->pvBuffer); + WILC_memcpy(pstrMessage->pvBuffer, pvSendBuffer, u32SendBufferSize); + + + /* add it to the message queue */ + if (pHandle->pstrMessageList == NULL) { + pHandle->pstrMessageList = pstrMessage; + } else { + Message *pstrTailMsg = pHandle->pstrMessageList; + while (pstrTailMsg->pstrNext != NULL) { + pstrTailMsg = pstrTailMsg->pstrNext; + } + pstrTailMsg->pstrNext = pstrMessage; + } + + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + + up(&pHandle->hSem); + + WILC_CATCH(s32RetStatus) + { + /* error occured, free any allocations */ + if (pstrMessage != NULL) { + if (pstrMessage->pvBuffer != NULL) { + WILC_FREE(pstrMessage->pvBuffer); + } + WILC_FREE(pstrMessage); + } + } + + return s32RetStatus; +} + + + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +WILC_ErrNo WILC_MsgQueueRecv(WILC_MsgQueueHandle *pHandle, + void *pvRecvBuffer, u32 u32RecvBufferSize, + u32 *pu32ReceivedLength, + tstrWILC_MsgQueueAttrs *pstrAttrs) +{ + + Message *pstrMessage; + WILC_ErrNo s32RetStatus = WILC_SUCCESS; + unsigned long flags; + if ((pHandle == NULL) || (u32RecvBufferSize == 0) + || (pvRecvBuffer == NULL) || (pu32ReceivedLength == NULL)) { + WILC_ERRORREPORT(s32RetStatus, WILC_INVALID_ARGUMENT); + } + + if (pHandle->bExiting == true) { + WILC_ERRORREPORT(s32RetStatus, WILC_FAIL); + } + + spin_lock_irqsave(&pHandle->strCriticalSection, flags); + pHandle->u32ReceiversCount++; + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + + down(&(pHandle->hSem)); + + if (s32RetStatus == WILC_TIMEOUT) { + /* timed out, just exit without consumeing the message */ + spin_lock_irqsave(&pHandle->strCriticalSection, flags); + pHandle->u32ReceiversCount--; + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + } else { + /* other non-timeout scenarios */ + WILC_ERRORCHECK(s32RetStatus); + + if (pHandle->bExiting) { + WILC_ERRORREPORT(s32RetStatus, WILC_FAIL); + } + + spin_lock_irqsave(&pHandle->strCriticalSection, flags); + + pstrMessage = pHandle->pstrMessageList; + if (pstrMessage == NULL) { + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + WILC_ERRORREPORT(s32RetStatus, WILC_FAIL); + } + /* check buffer size */ + if (u32RecvBufferSize < pstrMessage->u32Length) { + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + up(&pHandle->hSem); + WILC_ERRORREPORT(s32RetStatus, WILC_BUFFER_OVERFLOW); + } + + /* consume the message */ + pHandle->u32ReceiversCount--; + WILC_memcpy(pvRecvBuffer, pstrMessage->pvBuffer, pstrMessage->u32Length); + *pu32ReceivedLength = pstrMessage->u32Length; + + pHandle->pstrMessageList = pstrMessage->pstrNext; + + WILC_FREE(pstrMessage->pvBuffer); + WILC_FREE(pstrMessage); + + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + + } + + WILC_CATCH(s32RetStatus) + { + } + + return s32RetStatus; +} diff --git a/drivers/staging/wilc1000/wilc_msgqueue.h b/drivers/staging/wilc1000/wilc_msgqueue.h new file mode 100644 index 000000000..35b10019e --- /dev/null +++ b/drivers/staging/wilc1000/wilc_msgqueue.h @@ -0,0 +1,108 @@ +#ifndef __WILC_MSG_QUEUE_H__ +#define __WILC_MSG_QUEUE_H__ + +/*! + * @file wilc_msgqueue.h + * @brief Message Queue OS wrapper functionality + * @author syounan + * @sa wilc_oswrapper.h top level OS wrapper file + * @date 30 Aug 2010 + * @version 1.0 + */ + +#include "wilc_platform.h" +#include "wilc_errorsupport.h" +#include "wilc_memory.h" +#include "wilc_strutils.h" + +/*! + * @struct tstrWILC_MsgQueueAttrs + * @brief Message Queue API options + * @author syounan + * @date 30 Aug 2010 + * @version 1.0 + */ +typedef struct { + /* a dummy member to avoid compiler errors*/ + u8 dummy; + +} tstrWILC_MsgQueueAttrs; + +/*! + * @brief Creates a new Message queue + * @details Creates a new Message queue, if the feature + * CONFIG_WILC_MSG_QUEUE_IPC_NAME is enabled and pstrAttrs->pcName + * is not Null, then this message queue can be used for IPC with + * any other message queue having the same name in the system + * @param[in,out] pHandle handle to the message queue object + * @param[in] pstrAttrs Optional attributes, NULL for default + * @return Error code indicating sucess/failure + * @sa tstrWILC_MsgQueueAttrs + * @author syounan + * @date 30 Aug 2010 + * @version 1.0 + */ +WILC_ErrNo WILC_MsgQueueCreate(WILC_MsgQueueHandle *pHandle, + tstrWILC_MsgQueueAttrs *pstrAttrs); + + +/*! + * @brief Sends a message + * @details Sends a message, this API will block unil the message is + * actually sent or until it is timedout (as long as the feature + * CONFIG_WILC_MSG_QUEUE_TIMEOUT is enabled and pstrAttrs->u32Timeout + * is not set to WILC_OS_INFINITY), zero timeout is a valid value + * @param[in] pHandle handle to the message queue object + * @param[in] pvSendBuffer pointer to the data to send + * @param[in] u32SendBufferSize the size of the data to send + * @param[in] pstrAttrs Optional attributes, NULL for default + * @return Error code indicating sucess/failure + * @sa tstrWILC_MsgQueueAttrs + * @author syounan + * @date 30 Aug 2010 + * @version 1.0 + */ +WILC_ErrNo WILC_MsgQueueSend(WILC_MsgQueueHandle *pHandle, + const void *pvSendBuffer, u32 u32SendBufferSize, + tstrWILC_MsgQueueAttrs *pstrAttrs); + + +/*! + * @brief Receives a message + * @details Receives a message, this API will block unil a message is + * received or until it is timedout (as long as the feature + * CONFIG_WILC_MSG_QUEUE_TIMEOUT is enabled and pstrAttrs->u32Timeout + * is not set to WILC_OS_INFINITY), zero timeout is a valid value + * @param[in] pHandle handle to the message queue object + * @param[out] pvRecvBuffer pointer to a buffer to fill with the received message + * @param[in] u32RecvBufferSize the size of the receive buffer + * @param[out] pu32ReceivedLength the length of received data + * @param[in] pstrAttrs Optional attributes, NULL for default + * @return Error code indicating sucess/failure + * @sa tstrWILC_MsgQueueAttrs + * @author syounan + * @date 30 Aug 2010 + * @version 1.0 + */ +WILC_ErrNo WILC_MsgQueueRecv(WILC_MsgQueueHandle *pHandle, + void *pvRecvBuffer, u32 u32RecvBufferSize, + u32 *pu32ReceivedLength, + tstrWILC_MsgQueueAttrs *pstrAttrs); + + +/*! + * @brief Destroys an existing Message queue + * @param[in] pHandle handle to the message queue object + * @param[in] pstrAttrs Optional attributes, NULL for default + * @return Error code indicating sucess/failure + * @sa tstrWILC_MsgQueueAttrs + * @author syounan + * @date 30 Aug 2010 + * @version 1.0 + */ +WILC_ErrNo WILC_MsgQueueDestroy(WILC_MsgQueueHandle *pHandle, + tstrWILC_MsgQueueAttrs *pstrAttrs); + + + +#endif diff --git a/drivers/staging/wilc1000/wilc_osconfig.h b/drivers/staging/wilc1000/wilc_osconfig.h new file mode 100644 index 000000000..f9c251403 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_osconfig.h @@ -0,0 +1,9 @@ +/* Logs options */ +#define WILC_LOGS_NOTHING 0 +#define WILC_LOGS_WARN 1 +#define WILC_LOGS_WARN_INFO 2 +#define WILC_LOGS_WARN_INFO_DBG 3 +#define WILC_LOGS_WARN_INFO_DBG_FN 4 +#define WILC_LOGS_ALL 5 + +#define WILC_LOG_VERBOSITY_LEVEL WILC_LOGS_ALL diff --git a/drivers/staging/wilc1000/wilc_oswrapper.h b/drivers/staging/wilc1000/wilc_oswrapper.h new file mode 100644 index 000000000..e97aa9600 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_oswrapper.h @@ -0,0 +1,41 @@ +#ifndef __WILC_OSWRAPPER_H__ +#define __WILC_OSWRAPPER_H__ + +/*! + * @file wilc_oswrapper.h + * @brief Top level OS Wrapper, include this file and it will include all + * other files as necessary + * @author syounan + * @date 10 Aug 2010 + * @version 1.0 + */ + +/* OS Wrapper interface version */ +#define WILC_OSW_INTERFACE_VER 2 + +/* Os Configuration File */ +#include "wilc_osconfig.h" +#include "wilc_platform.h" + +/* Logging Functions */ +#include "wilc_log.h" + +/* Error reporting and handling support */ +#include "wilc_errorsupport.h" + +/* Sleep support */ +#include "wilc_sleep.h" + +/* Timer support */ +#include "wilc_timer.h" + +/* Memory support */ +#include "wilc_memory.h" + +/* String Utilities */ +#include "wilc_strutils.h" + +/* Message Queue */ +#include "wilc_msgqueue.h" + +#endif diff --git a/drivers/staging/wilc1000/wilc_platform.h b/drivers/staging/wilc1000/wilc_platform.h new file mode 100644 index 000000000..d03532cc3 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_platform.h @@ -0,0 +1,52 @@ +#ifndef __WILC_platfrom_H__ +#define __WILC_platfrom_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux/string.h" +/****************************************************************** + * OS specific types + *******************************************************************/ + +typedef struct timer_list WILC_TimerHandle; + + + +/* Message Queue type is a structure */ +typedef struct __Message_struct { + void *pvBuffer; + u32 u32Length; + struct __Message_struct *pstrNext; +} Message; + +typedef struct __MessageQueue_struct { + struct semaphore hSem; + spinlock_t strCriticalSection; + bool bExiting; + u32 u32ReceiversCount; + Message *pstrMessageList; +} WILC_MsgQueueHandle; + + + +/*Time represented in 64 bit format*/ +typedef time_t WILC_Time; + + +/******************************************************************* + * others + ********************************************************************/ + +/* Generic printf function */ +#define __WILC_FILE__ __FILE__ +#define __WILC_FUNCTION__ __func__ +#define __WILC_LINE__ __LINE__ +#endif diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c new file mode 100644 index 000000000..897e47e31 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_sdio.c @@ -0,0 +1,1254 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_sdio.c */ +/* */ +/* */ +/* //////////////////////////////////////////////////////////////////////////// */ + +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" + + +#ifdef WILC1000_SINGLE_TRANSFER +#define WILC_SDIO_BLOCK_SIZE 256 +#else + #if defined(PLAT_AML8726_M3) /* johnny */ + #define WILC_SDIO_BLOCK_SIZE 512 + #define MAX_SEG_SIZE (1 << 12) /* 4096 */ + #else + #define WILC_SDIO_BLOCK_SIZE 512 + #endif +#endif + +typedef struct { + void *os_context; + wilc_wlan_os_func_t os_func; + uint32_t block_size; + int (*sdio_cmd52)(sdio_cmd52_t *); + int (*sdio_cmd53)(sdio_cmd53_t *); + int (*sdio_set_max_speed)(void); + int (*sdio_set_default_speed)(void); + wilc_debug_func dPrint; + int nint; +#define MAX_NUN_INT_THRPT_ENH2 (5) /* Max num interrupts allowed in registers 0xf7, 0xf8 */ + int has_thrpt_enh3; +} wilc_sdio_t; + +static wilc_sdio_t g_sdio; + +#ifdef WILC_SDIO_IRQ_GPIO +static int sdio_write_reg(uint32_t addr, uint32_t data); +static int sdio_read_reg(uint32_t addr, uint32_t *data); +#endif +extern unsigned int int_clrd; + +/******************************************** + * + * Function 0 + * + ********************************************/ + +static int sdio_set_func0_csa_address(uint32_t adr) +{ + sdio_cmd52_t cmd; + + /** + * Review: BIG ENDIAN + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x10c; + cmd.data = (uint8_t)adr; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10c data...\n"); + goto _fail_; + } + + cmd.address = 0x10d; + cmd.data = (uint8_t)(adr >> 8); + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10d data...\n"); + goto _fail_; + } + + cmd.address = 0x10e; + cmd.data = (uint8_t)(adr >> 16); + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10e data...\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +static int sdio_set_func0_csa_address_byte0(uint32_t adr) +{ + sdio_cmd52_t cmd; + + + /** + * Review: BIG ENDIAN + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x10c; + cmd.data = (uint8_t)adr; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10c data...\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} +static int sdio_set_func0_block_size(uint32_t block_size) +{ + sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x10; + cmd.data = (uint8_t)block_size; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10 data...\n"); + goto _fail_; + } + + cmd.address = 0x11; + cmd.data = (uint8_t)(block_size >> 8); + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x11 data...\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +/******************************************** + * + * Function 1 + * + ********************************************/ + +static int sdio_set_func1_block_size(uint32_t block_size) +{ + sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x110; + cmd.data = (uint8_t)block_size; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x110 data...\n"); + goto _fail_; + } + cmd.address = 0x111; + cmd.data = (uint8_t)(block_size >> 8); + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x111 data...\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +static int sdio_clear_int(void) +{ +#ifndef WILC_SDIO_IRQ_GPIO + /* uint32_t sts; */ + sdio_cmd52_t cmd; + cmd.read_write = 0; + cmd.function = 1; + cmd.raw = 0; + cmd.address = 0x4; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + int_clrd++; + + return cmd.data; +#else + uint32_t reg; + if (!sdio_read_reg(WILC_HOST_RX_CTRL_0, ®)) { + g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_HOST_RX_CTRL_0); + return 0; + } + reg &= ~0x1; + sdio_write_reg(WILC_HOST_RX_CTRL_0, reg); + int_clrd++; + return 1; +#endif + +} + +uint32_t sdio_xfer_cnt(void) +{ + uint32_t cnt = 0; + sdio_cmd52_t cmd; + cmd.read_write = 0; + cmd.function = 1; + cmd.raw = 0; + cmd.address = 0x1C; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + cnt = cmd.data; + + cmd.read_write = 0; + cmd.function = 1; + cmd.raw = 0; + cmd.address = 0x1D; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + cnt |= (cmd.data << 8); + + cmd.read_write = 0; + cmd.function = 1; + cmd.raw = 0; + cmd.address = 0x1E; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + cnt |= (cmd.data << 16); + + return cnt; + + +} + +/******************************************** + * + * Sdio interfaces + * + ********************************************/ +int sdio_check_bs(void) +{ + sdio_cmd52_t cmd; + + /** + * poll until BS is 0 + **/ + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xc; + cmd.data = 0; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, get BS register...\n"); + goto _fail_; + } + + return 1; + +_fail_: + + return 0; +} + +static int sdio_write_reg(uint32_t addr, uint32_t data) +{ +#ifdef BIG_ENDIAN + data = BYTE_SWAP(data); +#endif + + if ((addr >= 0xf0) && (addr <= 0xff)) { + sdio_cmd52_t cmd; + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = addr; + cmd.data = data; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd 52, read reg (%08x) ...\n", addr); + goto _fail_; + } + } else { + sdio_cmd53_t cmd; + + /** + * set the AHB address + **/ + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + + cmd.read_write = 1; + cmd.function = 0; + cmd.address = 0x10f; + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = 4; + cmd.buffer = (uint8_t *)&data; + cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */ + + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53, write reg (%08x)...\n", addr); + goto _fail_; + } + } + + return 1; + +_fail_: + + return 0; +} + +static int sdio_write(uint32_t addr, uint8_t *buf, uint32_t size) +{ + uint32_t block_size = g_sdio.block_size; + sdio_cmd53_t cmd; + int nblk, nleft; + + cmd.read_write = 1; + if (addr > 0) { + /** + * has to be word aligned... + **/ + if (size & 0x3) { + size += 4; + size &= ~0x3; + } + + /** + * func 0 access + **/ + cmd.function = 0; + cmd.address = 0x10f; + } else { +#ifdef WILC1000_SINGLE_TRANSFER + /** + * has to be block aligned... + **/ + nleft = size % block_size; + if (nleft > 0) { + size += block_size; + size &= ~(block_size - 1); + } +#else + /** + * has to be word aligned... + **/ + if (size & 0x3) { + size += 4; + size &= ~0x3; + } +#endif + + /** + * func 1 access + **/ + cmd.function = 1; + cmd.address = 0; + } + + nblk = size / block_size; + nleft = size % block_size; + + if (nblk > 0) { + +#if defined(PLAT_AML8726_M3_BACKUP) /* johnny */ + int i; + + for (i = 0; i < nblk; i++) { + cmd.block_mode = 0; /* 1; */ + cmd.increment = 1; + cmd.count = block_size; /* nblk; */ + cmd.buffer = buf; + cmd.block_size = block_size; + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block send...\n", addr); + goto _fail_; + } + + if (addr > 0) + addr += block_size; /* addr += nblk*block_size; */ + + buf += block_size; /* buf += nblk*block_size; */ + } + +#elif defined(PLAT_AML8726_M3) /* johnny */ + + int i; + int rest; + int seg_cnt; + + seg_cnt = (nblk * block_size) / MAX_SEG_SIZE; + rest = (nblk * block_size) & (MAX_SEG_SIZE - 1); + + for (i = 0; i < seg_cnt; i++) { + cmd.block_mode = 1; + cmd.increment = 1; + cmd.count = MAX_SEG_SIZE / block_size; + cmd.buffer = buf; + cmd.block_size = block_size; + + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block send...\n", addr); + goto _fail_; + } + + if (addr > 0) + addr += MAX_SEG_SIZE; + + buf += MAX_SEG_SIZE; + + } + + + if (rest > 0) { + cmd.block_mode = 1; + cmd.increment = 1; + cmd.count = rest / block_size; + cmd.buffer = buf; + cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ + + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes send...\n", addr); + goto _fail_; + } + + if (addr > 0) + addr += rest; + + buf += rest; + + } + +#else + + cmd.block_mode = 1; + cmd.increment = 1; + cmd.count = nblk; + cmd.buffer = buf; + cmd.block_size = block_size; + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block send...\n", addr); + goto _fail_; + } + if (addr > 0) + addr += nblk * block_size; + buf += nblk * block_size; + +#endif /* platform */ + } + + + if (nleft > 0) { + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = nleft; + cmd.buffer = buf; + + cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ + + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes send...\n", addr); + goto _fail_; + } + } + + return 1; + +_fail_: + + return 0; +} + +static int sdio_read_reg(uint32_t addr, uint32_t *data) +{ + if ((addr >= 0xf0) && (addr <= 0xff)) { + sdio_cmd52_t cmd; + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = addr; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd 52, read reg (%08x) ...\n", addr); + goto _fail_; + } + *data = cmd.data; + } else { + sdio_cmd53_t cmd; + + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + + cmd.read_write = 0; + cmd.function = 0; + cmd.address = 0x10f; + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = 4; + cmd.buffer = (uint8_t *)data; + + cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */ + + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53, read reg (%08x)...\n", addr); + goto _fail_; + } + } + +#ifdef BIG_ENDIAN + *data = BYTE_SWAP(*data); +#endif + + return 1; + +_fail_: + + return 0; +} + +static int sdio_read(uint32_t addr, uint8_t *buf, uint32_t size) +{ + uint32_t block_size = g_sdio.block_size; + sdio_cmd53_t cmd; + int nblk, nleft; + + cmd.read_write = 0; + if (addr > 0) { + /** + * has to be word aligned... + **/ + if (size & 0x3) { + size += 4; + size &= ~0x3; + } + + /** + * func 0 access + **/ + cmd.function = 0; + cmd.address = 0x10f; + } else { +#ifdef WILC1000_SINGLE_TRANSFER + /** + * has to be block aligned... + **/ + nleft = size % block_size; + if (nleft > 0) { + size += block_size; + size &= ~(block_size - 1); + } +#else + /** + * has to be word aligned... + **/ + if (size & 0x3) { + size += 4; + size &= ~0x3; + } +#endif + + /** + * func 1 access + **/ + cmd.function = 1; + cmd.address = 0; + } + + nblk = size / block_size; + nleft = size % block_size; + + if (nblk > 0) { + +#if defined(PLAT_AML8726_M3_BACKUP) /* johnny */ + + int i; + + for (i = 0; i < nblk; i++) { + cmd.block_mode = 0; /* 1; */ + cmd.increment = 1; + cmd.count = block_size; /* nblk; */ + cmd.buffer = buf; + cmd.block_size = block_size; + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr); + goto _fail_; + } + if (addr > 0) + addr += block_size; /* addr += nblk*block_size; */ + buf += block_size; /* buf += nblk*block_size; */ + } + +#elif defined(PLAT_AML8726_M3) /* johnny */ + + int i; + int rest; + int seg_cnt; + + seg_cnt = (nblk * block_size) / MAX_SEG_SIZE; + rest = (nblk * block_size) & (MAX_SEG_SIZE - 1); + + for (i = 0; i < seg_cnt; i++) { + cmd.block_mode = 1; + cmd.increment = 1; + cmd.count = MAX_SEG_SIZE / block_size; + cmd.buffer = buf; + cmd.block_size = block_size; + + + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr); + goto _fail_; + } + + if (addr > 0) + addr += MAX_SEG_SIZE; + + buf += MAX_SEG_SIZE; + + } + + + if (rest > 0) { + cmd.block_mode = 1; + cmd.increment = 1; + cmd.count = rest / block_size; + cmd.buffer = buf; + cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ + + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr); + goto _fail_; + } + + if (addr > 0) + addr += rest; + + buf += rest; + + } + +#else + + cmd.block_mode = 1; + cmd.increment = 1; + cmd.count = nblk; + cmd.buffer = buf; + cmd.block_size = block_size; + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr); + goto _fail_; + } + if (addr > 0) + addr += nblk * block_size; + buf += nblk * block_size; + +#endif /* platform */ + } /* if (nblk > 0) */ + + if (nleft > 0) { + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = nleft; + cmd.buffer = buf; + + cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ + + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes read...\n", addr); + goto _fail_; + } + } + + return 1; + +_fail_: + + return 0; +} + +/******************************************** + * + * Bus interfaces + * + ********************************************/ + +static int sdio_deinit(void *pv) +{ + return 1; +} + +static int sdio_sync(void) +{ + uint32_t reg; + + /** + * Disable power sequencer + **/ + if (!sdio_read_reg(WILC_MISC, ®)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read misc reg...\n"); + return 0; + } + + reg &= ~(1 << 8); + if (!sdio_write_reg(WILC_MISC, reg)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write misc reg...\n"); + return 0; + } + +#ifdef WILC_SDIO_IRQ_GPIO + { + uint32_t reg; + int ret; + + /** + * interrupt pin mux select + **/ + ret = sdio_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + reg |= (1 << 8); + ret = sdio_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + + /** + * interrupt enable + **/ + ret = sdio_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + reg |= (1 << 16); + ret = sdio_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + } +#endif + + return 1; +} + +static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func) +{ + sdio_cmd52_t cmd; + int loop; + uint32_t chipid; + memset(&g_sdio, 0, sizeof(wilc_sdio_t)); + + g_sdio.dPrint = func; + g_sdio.os_context = inp->os_context.os_private; + memcpy((void *)&g_sdio.os_func, (void *)&inp->os_func, sizeof(wilc_wlan_os_func_t)); + + if (inp->io_func.io_init) { + if (!inp->io_func.io_init(g_sdio.os_context)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed io init bus...\n"); + return 0; + } + } else { + return 0; + } + + g_sdio.sdio_cmd52 = inp->io_func.u.sdio.sdio_cmd52; + g_sdio.sdio_cmd53 = inp->io_func.u.sdio.sdio_cmd53; + g_sdio.sdio_set_max_speed = inp->io_func.u.sdio.sdio_set_max_speed; + g_sdio.sdio_set_default_speed = inp->io_func.u.sdio.sdio_set_default_speed; + + /** + * function 0 csa enable + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + cmd.address = 0x100; + cmd.data = 0x80; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, enable csa...\n"); + goto _fail_; + } + + /** + * function 0 block size + **/ + if (!sdio_set_func0_block_size(WILC_SDIO_BLOCK_SIZE)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, set func 0 block size...\n"); + goto _fail_; + } + g_sdio.block_size = WILC_SDIO_BLOCK_SIZE; + + /** + * enable func1 IO + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + cmd.address = 0x2; + cmd.data = 0x2; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio] Fail cmd 52, set IOE register...\n"); + goto _fail_; + } + + /** + * make sure func 1 is up + **/ + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x3; + loop = 3; + do { + cmd.data = 0; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, get IOR register...\n"); + goto _fail_; + } + if (cmd.data == 0x2) + break; + } while (loop--); + + if (loop <= 0) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail func 1 is not ready...\n"); + goto _fail_; + } + + /** + * func 1 is ready, set func 1 block size + **/ + if (!sdio_set_func1_block_size(WILC_SDIO_BLOCK_SIZE)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail set func 1 block size...\n"); + goto _fail_; + } + + /** + * func 1 interrupt enable + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + cmd.address = 0x4; + cmd.data = 0x3; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, set IEN register...\n"); + goto _fail_; + } + + /** + * make sure can read back chip id correctly + **/ + if (!sdio_read_reg(0x1000, &chipid)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd read chip id...\n"); + goto _fail_; + } + g_sdio.dPrint(N_ERR, "[wilc sdio]: chipid (%08x)\n", chipid); + if ((chipid & 0xfff) > 0x2a0) { + g_sdio.has_thrpt_enh3 = 1; + } else { + g_sdio.has_thrpt_enh3 = 0; + } + g_sdio.dPrint(N_ERR, "[wilc sdio]: has_thrpt_enh3 = %d...\n", g_sdio.has_thrpt_enh3); + + + return 1; + +_fail_: + + return 0; +} + +static void sdio_set_max_speed(void) +{ + g_sdio.sdio_set_max_speed(); +} + +static void sdio_set_default_speed(void) +{ + g_sdio.sdio_set_default_speed(); +} + +static int sdio_read_size(uint32_t *size) +{ + + uint32_t tmp; + sdio_cmd52_t cmd; + + /** + * Read DMA count in words + **/ + { + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf2; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + tmp = cmd.data; + + /* cmd.read_write = 0; */ + /* cmd.function = 0; */ + /* cmd.raw = 0; */ + cmd.address = 0xf3; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + tmp |= (cmd.data << 8); + } + + *size = tmp; + return 1; +} + +static int sdio_read_int(uint32_t *int_status) +{ + + uint32_t tmp; + sdio_cmd52_t cmd; + + sdio_read_size(&tmp); + + /** + * Read IRQ flags + **/ +#ifndef WILC_SDIO_IRQ_GPIO + /* cmd.read_write = 0; */ + cmd.function = 1; + /* cmd.raw = 0; */ + cmd.address = 0x04; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + + if (cmd.data & (1 << 0)) { + tmp |= INT_0; + } + if (cmd.data & (1 << 2)) { + tmp |= INT_1; + } + if (cmd.data & (1 << 3)) { + tmp |= INT_2; + } + if (cmd.data & (1 << 4)) { + tmp |= INT_3; + } + if (cmd.data & (1 << 5)) { + tmp |= INT_4; + } + if (cmd.data & (1 << 6)) { + tmp |= INT_5; + } + { + int i; + for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { + if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt (1) : tmp=%x, data=%x\n", tmp, cmd.data); + break; + } + } + } +#else + { + uint32_t irq_flags; + + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf7; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + irq_flags = cmd.data & 0x1f; + tmp |= ((irq_flags >> 0) << IRG_FLAGS_OFFSET); + } + +#endif + + *int_status = tmp; + + return 1; +} + +static int sdio_clear_int_ext(uint32_t val) +{ + int ret; + + if (g_sdio.has_thrpt_enh3) { + uint32_t reg; + +#ifdef WILC_SDIO_IRQ_GPIO + { + uint32_t flags; + flags = val & ((1 << MAX_NUN_INT_THRPT_ENH2) - 1); + reg = flags; + } +#else + reg = 0; +#endif + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + reg |= (1 << 5); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + reg |= (1 << 6); + /* enable VMM */ + if ((val & EN_VMM) == EN_VMM) + reg |= (1 << 7); + if (reg) { + sdio_cmd52_t cmd; + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf8; + cmd.data = reg; + + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf8 data (%d) ...\n", __LINE__); + goto _fail_; + } + + } + } else { +#ifdef WILC_SDIO_IRQ_GPIO + { + /* see below. has_thrpt_enh2 uses register 0xf8 to clear interrupts. */ + /* Cannot clear multiple interrupts. Must clear each interrupt individually */ + uint32_t flags; + flags = val & ((1 << MAX_NUM_INT) - 1); + if (flags) { + int i; + + ret = 1; + for (i = 0; i < g_sdio.nint; i++) { + if (flags & 1) { + sdio_cmd52_t cmd; + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf8; + cmd.data = (1 << i); + + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf8 data (%d) ...\n", __LINE__); + goto _fail_; + } + + } + if (!ret) + break; + flags >>= 1; + } + if (!ret) { + goto _fail_; + } + for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { + if (flags & 1) + g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt cleared %d...\n", i); + flags >>= 1; + } + } + } +#endif /* WILC_SDIO_IRQ_GPIO */ + + + { + uint32_t vmm_ctl; + + vmm_ctl = 0; + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + vmm_ctl |= (1 << 0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + vmm_ctl |= (1 << 1); + /* enable VMM */ + if ((val & EN_VMM) == EN_VMM) + vmm_ctl |= (1 << 2); + + if (vmm_ctl) { + sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf6; + cmd.data = vmm_ctl; + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf6 data (%d) ...\n", __LINE__); + goto _fail_; + } + } + } + } + + return 1; +_fail_: + return 0; +} + +static int sdio_sync_ext(int nint /* how mant interrupts to enable. */) +{ + uint32_t reg; + + + if (nint > MAX_NUM_INT) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Too many interupts (%d)...\n", nint); + return 0; + } + if (nint > MAX_NUN_INT_THRPT_ENH2) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Error: Cannot support more than 5 interrupts when has_thrpt_enh2=1.\n"); + return 0; + } + + + g_sdio.nint = nint; + + /** + * Disable power sequencer + **/ + if (!sdio_read_reg(WILC_MISC, ®)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read misc reg...\n"); + return 0; + } + + reg &= ~(1 << 8); + if (!sdio_write_reg(WILC_MISC, reg)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write misc reg...\n"); + return 0; + } + +#ifdef WILC_SDIO_IRQ_GPIO + { + uint32_t reg; + int ret, i; + + + /** + * interrupt pin mux select + **/ + ret = sdio_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + reg |= (1 << 8); + ret = sdio_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + + /** + * interrupt enable + **/ + ret = sdio_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + + for (i = 0; (i < 5) && (nint > 0); i++, nint--) { + reg |= (1 << (27 + i)); + } + ret = sdio_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + if (nint) { + ret = sdio_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_INTR2_ENABLE); + return 0; + } + + for (i = 0; (i < 3) && (nint > 0); i++, nint--) { + reg |= (1 << i); + } + + ret = sdio_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR2_ENABLE); + return 0; + } + } + } +#endif /* WILC_SDIO_IRQ_GPIO */ + return 1; +} + + +/******************************************** + * + * Global sdio HIF function table + * + ********************************************/ + +wilc_hif_func_t hif_sdio = { + sdio_init, + sdio_deinit, + sdio_read_reg, + sdio_write_reg, + sdio_read, + sdio_write, + sdio_sync, + sdio_clear_int, + sdio_read_int, + sdio_clear_int_ext, + sdio_read_size, + sdio_write, + sdio_read, + sdio_sync_ext, + + sdio_set_max_speed, + sdio_set_default_speed, +}; + diff --git a/drivers/staging/wilc1000/wilc_sleep.c b/drivers/staging/wilc1000/wilc_sleep.c new file mode 100644 index 000000000..adab3cac6 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_sleep.c @@ -0,0 +1,18 @@ + +#include "wilc_sleep.h" + +/* + * @author mdaftedar + * @date 10 Aug 2010 + * @version 1.0 + */ +void WILC_Sleep(u32 u32TimeMilliSec) +{ + if (u32TimeMilliSec <= 4000000) { + u32 u32Temp = u32TimeMilliSec * 1000; + usleep_range(u32Temp, u32Temp); + } else { + msleep(u32TimeMilliSec); + } + +} diff --git a/drivers/staging/wilc1000/wilc_sleep.h b/drivers/staging/wilc1000/wilc_sleep.h new file mode 100644 index 000000000..cf9047f70 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_sleep.h @@ -0,0 +1,20 @@ +#ifndef __WILC_SLEEP_H__ +#define __WILC_SLEEP_H__ + +#include +#include + +/*! + * @brief forces the current thread to sleep until the given time has elapsed + * @param[in] u32TimeMilliSec Time to sleep in Milli seconds + * @sa WILC_SleepMicrosec + * @author syounan + * @date 10 Aug 2010 + * @version 1.0 + * @note This function offers a relatively innacurate and low resolution + * sleep, for accurate high resolution sleep use u32TimeMicoSec + */ +/* TODO: remove and open-code in callers */ +void WILC_Sleep(u32 u32TimeMilliSec); + +#endif diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/wilc_spi.c new file mode 100644 index 000000000..abea5df65 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_spi.c @@ -0,0 +1,1406 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_spi.c */ +/* */ +/* */ +/* //////////////////////////////////////////////////////////////////////////// */ + +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" + +extern unsigned int int_clrd; + +/* + * #include + * #include + */ +typedef struct { + void *os_context; + int (*spi_tx)(uint8_t *, uint32_t); + int (*spi_rx)(uint8_t *, uint32_t); + int (*spi_trx)(uint8_t *, uint8_t *, uint32_t); + int (*spi_max_speed)(void); + wilc_debug_func dPrint; + int crc_off; + int nint; + int has_thrpt_enh; +} wilc_spi_t; + +static wilc_spi_t g_spi; + +static int spi_read(uint32_t, uint8_t *, uint32_t); +static int spi_write(uint32_t, uint8_t *, uint32_t); + +/******************************************** + * + * Crc7 + * + ********************************************/ + +static const uint8_t crc7_syndrome_table[256] = { + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, + 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, + 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, + 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e, + 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, + 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45, + 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, + 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c, + 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, + 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13, + 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, + 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a, + 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, + 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21, + 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, + 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, + 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, + 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36, + 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, + 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f, + 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, + 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, + 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d, + 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, + 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52, + 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, + 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b, + 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, + 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60, + 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, + 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79 +}; + +static uint8_t crc7_byte(uint8_t crc, uint8_t data) +{ + return crc7_syndrome_table[(crc << 1) ^ data]; +} + +static uint8_t crc7(uint8_t crc, const uint8_t *buffer, uint32_t len) +{ + while (len--) + crc = crc7_byte(crc, *buffer++); + return crc; +} + +/******************************************** + * + * Spi protocol Function + * + ********************************************/ + +#define CMD_DMA_WRITE 0xc1 +#define CMD_DMA_READ 0xc2 +#define CMD_INTERNAL_WRITE 0xc3 +#define CMD_INTERNAL_READ 0xc4 +#define CMD_TERMINATE 0xc5 +#define CMD_REPEAT 0xc6 +#define CMD_DMA_EXT_WRITE 0xc7 +#define CMD_DMA_EXT_READ 0xc8 +#define CMD_SINGLE_WRITE 0xc9 +#define CMD_SINGLE_READ 0xca +#define CMD_RESET 0xcf + +#define N_OK 1 +#define N_FAIL 0 +#define N_RESET -1 +#define N_RETRY -2 + +#define DATA_PKT_SZ_256 256 +#define DATA_PKT_SZ_512 512 +#define DATA_PKT_SZ_1K 1024 +#define DATA_PKT_SZ_4K (4 * 1024) +#define DATA_PKT_SZ_8K (8 * 1024) +#define DATA_PKT_SZ DATA_PKT_SZ_8K + +static int spi_cmd(uint8_t cmd, uint32_t adr, uint32_t data, uint32_t sz, uint8_t clockless) +{ + uint8_t bc[9]; + int len = 5; + int result = N_OK; + + bc[0] = cmd; + switch (cmd) { + case CMD_SINGLE_READ: /* single word (4 bytes) read */ + bc[1] = (uint8_t)(adr >> 16); + bc[2] = (uint8_t)(adr >> 8); + bc[3] = (uint8_t)adr; + len = 5; + break; + + case CMD_INTERNAL_READ: /* internal register read */ + bc[1] = (uint8_t)(adr >> 8); + if (clockless) + bc[1] |= (1 << 7); + bc[2] = (uint8_t)adr; + bc[3] = 0x00; + len = 5; + break; + + case CMD_TERMINATE: /* termination */ + bc[1] = 0x00; + bc[2] = 0x00; + bc[3] = 0x00; + len = 5; + break; + + case CMD_REPEAT: /* repeat */ + bc[1] = 0x00; + bc[2] = 0x00; + bc[3] = 0x00; + len = 5; + break; + + case CMD_RESET: /* reset */ + bc[1] = 0xff; + bc[2] = 0xff; + bc[3] = 0xff; + len = 5; + break; + + case CMD_DMA_WRITE: /* dma write */ + case CMD_DMA_READ: /* dma read */ + bc[1] = (uint8_t)(adr >> 16); + bc[2] = (uint8_t)(adr >> 8); + bc[3] = (uint8_t)adr; + bc[4] = (uint8_t)(sz >> 8); + bc[5] = (uint8_t)(sz); + len = 7; + break; + + case CMD_DMA_EXT_WRITE: /* dma extended write */ + case CMD_DMA_EXT_READ: /* dma extended read */ + bc[1] = (uint8_t)(adr >> 16); + bc[2] = (uint8_t)(adr >> 8); + bc[3] = (uint8_t)adr; + bc[4] = (uint8_t)(sz >> 16); + bc[5] = (uint8_t)(sz >> 8); + bc[6] = (uint8_t)(sz); + len = 8; + break; + + case CMD_INTERNAL_WRITE: /* internal register write */ + bc[1] = (uint8_t)(adr >> 8); + if (clockless) + bc[1] |= (1 << 7); + bc[2] = (uint8_t)(adr); + bc[3] = (uint8_t)(data >> 24); + bc[4] = (uint8_t)(data >> 16); + bc[5] = (uint8_t)(data >> 8); + bc[6] = (uint8_t)(data); + len = 8; + break; + + case CMD_SINGLE_WRITE: /* single word write */ + bc[1] = (uint8_t)(adr >> 16); + bc[2] = (uint8_t)(adr >> 8); + bc[3] = (uint8_t)(adr); + bc[4] = (uint8_t)(data >> 24); + bc[5] = (uint8_t)(data >> 16); + bc[6] = (uint8_t)(data >> 8); + bc[7] = (uint8_t)(data); + len = 9; + break; + + default: + result = N_FAIL; + break; + } + + if (result) { + if (!g_spi.crc_off) + bc[len - 1] = (crc7(0x7f, (const uint8_t *)&bc[0], len - 1)) << 1; + else + len -= 1; + + if (!g_spi.spi_tx(bc, len)) { + PRINT_ER("[wilc spi]: Failed cmd write, bus error...\n"); + result = N_FAIL; + } + } + + return result; +} + +static int spi_cmd_rsp(uint8_t cmd) +{ + uint8_t rsp; + int result = N_OK; + + /** + * Command/Control response + **/ + if ((cmd == CMD_RESET) || + (cmd == CMD_TERMINATE) || + (cmd == CMD_REPEAT)) { + if (!g_spi.spi_rx(&rsp, 1)) { + result = N_FAIL; + goto _fail_; + } + } + + if (!g_spi.spi_rx(&rsp, 1)) { + PRINT_ER("[wilc spi]: Failed cmd response read, bus error...\n"); + result = N_FAIL; + goto _fail_; + } + + if (rsp != cmd) { + PRINT_ER("[wilc spi]: Failed cmd response, cmd (%02x), resp (%02x)\n", cmd, rsp); + result = N_FAIL; + goto _fail_; + } + + /** + * State response + **/ + if (!g_spi.spi_rx(&rsp, 1)) { + PRINT_ER("[wilc spi]: Failed cmd state read, bus error...\n"); + result = N_FAIL; + goto _fail_; + } + + if (rsp != 0x00) { + PRINT_ER("[wilc spi]: Failed cmd state response state (%02x)\n", rsp); + result = N_FAIL; + } + +_fail_: + + return result; +} + +static int spi_cmd_complete(uint8_t cmd, uint32_t adr, uint8_t *b, uint32_t sz, uint8_t clockless) +{ + uint8_t wb[32], rb[32]; + uint8_t wix, rix; + uint32_t len2; + uint8_t rsp; + int len = 0; + int result = N_OK; + + wb[0] = cmd; + switch (cmd) { + case CMD_SINGLE_READ: /* single word (4 bytes) read */ + wb[1] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)adr; + len = 5; + break; + + case CMD_INTERNAL_READ: /* internal register read */ + wb[1] = (uint8_t)(adr >> 8); + if (clockless == 1) + wb[1] |= (1 << 7); + wb[2] = (uint8_t)adr; + wb[3] = 0x00; + len = 5; + break; + + case CMD_TERMINATE: /* termination */ + wb[1] = 0x00; + wb[2] = 0x00; + wb[3] = 0x00; + len = 5; + break; + + case CMD_REPEAT: /* repeat */ + wb[1] = 0x00; + wb[2] = 0x00; + wb[3] = 0x00; + len = 5; + break; + + case CMD_RESET: /* reset */ + wb[1] = 0xff; + wb[2] = 0xff; + wb[3] = 0xff; + len = 5; + break; + + case CMD_DMA_WRITE: /* dma write */ + case CMD_DMA_READ: /* dma read */ + wb[1] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)adr; + wb[4] = (uint8_t)(sz >> 8); + wb[5] = (uint8_t)(sz); + len = 7; + break; + + case CMD_DMA_EXT_WRITE: /* dma extended write */ + case CMD_DMA_EXT_READ: /* dma extended read */ + wb[1] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)adr; + wb[4] = (uint8_t)(sz >> 16); + wb[5] = (uint8_t)(sz >> 8); + wb[6] = (uint8_t)(sz); + len = 8; + break; + + case CMD_INTERNAL_WRITE: /* internal register write */ + wb[1] = (uint8_t)(adr >> 8); + if (clockless == 1) + wb[1] |= (1 << 7); + wb[2] = (uint8_t)(adr); + wb[3] = b[3]; + wb[4] = b[2]; + wb[5] = b[1]; + wb[6] = b[0]; + len = 8; + break; + + case CMD_SINGLE_WRITE: /* single word write */ + wb[1] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)(adr); + wb[4] = b[3]; + wb[5] = b[2]; + wb[6] = b[1]; + wb[7] = b[0]; + len = 9; + break; + + default: + result = N_FAIL; + break; + } + + if (result != N_OK) { + return result; + } + + if (!g_spi.crc_off) { + wb[len - 1] = (crc7(0x7f, (const uint8_t *)&wb[0], len - 1)) << 1; + } else { + len -= 1; + } + +#define NUM_SKIP_BYTES (1) +#define NUM_RSP_BYTES (2) +#define NUM_DATA_HDR_BYTES (1) +#define NUM_DATA_BYTES (4) +#define NUM_CRC_BYTES (2) +#define NUM_DUMMY_BYTES (3) + if ((cmd == CMD_RESET) || + (cmd == CMD_TERMINATE) || + (cmd == CMD_REPEAT)) { + len2 = len + (NUM_SKIP_BYTES + NUM_RSP_BYTES + NUM_DUMMY_BYTES); + } else if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ)) { + if (!g_spi.crc_off) { + len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES + + NUM_CRC_BYTES + NUM_DUMMY_BYTES); + } else { + len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES + + NUM_DUMMY_BYTES); + } + } else { + len2 = len + (NUM_RSP_BYTES + NUM_DUMMY_BYTES); + } +#undef NUM_DUMMY_BYTES + + if (len2 > (sizeof(wb) / sizeof(wb[0]))) { + PRINT_ER("[wilc spi]: spi buffer size too small (%d) (%zu)\n", + len2, (sizeof(wb) / sizeof(wb[0]))); + result = N_FAIL; + return result; + } + /* zero spi write buffers. */ + for (wix = len; wix < len2; wix++) { + wb[wix] = 0; + } + rix = len; + + if (!g_spi.spi_trx(wb, rb, len2)) { + PRINT_ER("[wilc spi]: Failed cmd write, bus error...\n"); + result = N_FAIL; + return result; + } + + /** + * Command/Control response + **/ + if ((cmd == CMD_RESET) || + (cmd == CMD_TERMINATE) || + (cmd == CMD_REPEAT)) { + rix++; /* skip 1 byte */ + } + + /* do { */ + rsp = rb[rix++]; + /* if(rsp == cmd) break; */ + /* } while(&rptr[1] <= &rb[len2]); */ + + if (rsp != cmd) { + PRINT_ER("[wilc spi]: Failed cmd response, cmd (%02x)" + ", resp (%02x)\n", cmd, rsp); + result = N_FAIL; + return result; + } + + /** + * State response + **/ + rsp = rb[rix++]; + if (rsp != 0x00) { + PRINT_ER("[wilc spi]: Failed cmd state response " + "state (%02x)\n", rsp); + result = N_FAIL; + return result; + } + + if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ) + || (cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) { + int retry; + /* uint16_t crc1, crc2; */ + uint8_t crc[2]; + /** + * Data Respnose header + **/ + retry = 100; + do { + /* ensure there is room in buffer later to read data and crc */ + if (rix < len2) { + rsp = rb[rix++]; + } else { + retry = 0; + break; + } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); + + if (retry <= 0) { + PRINT_ER("[wilc spi]: Error, data read " + "response (%02x)\n", rsp); + result = N_RESET; + return result; + } + + if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ)) { + /** + * Read bytes + **/ + if ((rix + 3) < len2) { + b[0] = rb[rix++]; + b[1] = rb[rix++]; + b[2] = rb[rix++]; + b[3] = rb[rix++]; + } else { + PRINT_ER("[wilc spi]: buffer overrun when reading data.\n"); + result = N_FAIL; + return result; + } + + if (!g_spi.crc_off) { + /** + * Read Crc + **/ + if ((rix + 1) < len2) { + crc[0] = rb[rix++]; + crc[1] = rb[rix++]; + } else { + PRINT_ER("[wilc spi]: buffer overrun when reading crc.\n"); + result = N_FAIL; + return result; + } + } + } else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) { + int ix; + + /* some data may be read in response to dummy bytes. */ + for (ix = 0; (rix < len2) && (ix < sz); ) { + b[ix++] = rb[rix++]; + } + + sz -= ix; + + if (sz > 0) { + int nbytes; + + if (sz <= (DATA_PKT_SZ - ix)) { + nbytes = sz; + } else { + nbytes = DATA_PKT_SZ - ix; + } + + /** + * Read bytes + **/ + if (!g_spi.spi_rx(&b[ix], nbytes)) { + PRINT_ER("[wilc spi]: Failed data block read, bus error...\n"); + result = N_FAIL; + goto _error_; + } + + /** + * Read Crc + **/ + if (!g_spi.crc_off) { + if (!g_spi.spi_rx(crc, 2)) { + PRINT_ER("[wilc spi]: Failed data block crc read, bus error...\n"); + result = N_FAIL; + goto _error_; + } + } + + + ix += nbytes; + sz -= nbytes; + } + + /* if any data in left unread, then read the rest using normal DMA code.*/ + while (sz > 0) { + int nbytes; + + if (sz <= DATA_PKT_SZ) { + nbytes = sz; + } else { + nbytes = DATA_PKT_SZ; + } + + /** + * read data response only on the next DMA cycles not + * the first DMA since data response header is already + * handled above for the first DMA. + **/ + /** + * Data Respnose header + **/ + retry = 10; + do { + if (!g_spi.spi_rx(&rsp, 1)) { + PRINT_ER("[wilc spi]: Failed data response read, bus error...\n"); + result = N_FAIL; + break; + } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); + + if (result == N_FAIL) + break; + + + /** + * Read bytes + **/ + if (!g_spi.spi_rx(&b[ix], nbytes)) { + PRINT_ER("[wilc spi]: Failed data block read, bus error...\n"); + result = N_FAIL; + break; + } + + /** + * Read Crc + **/ + if (!g_spi.crc_off) { + if (!g_spi.spi_rx(crc, 2)) { + PRINT_ER("[wilc spi]: Failed data block crc read, bus error...\n"); + result = N_FAIL; + break; + } + } + + ix += nbytes; + sz -= nbytes; + } + } + } +_error_: + return result; +} + +static int spi_data_read(uint8_t *b, uint32_t sz) +{ + int retry, ix, nbytes; + int result = N_OK; + uint8_t crc[2]; + uint8_t rsp; + + /** + * Data + **/ + ix = 0; + do { + if (sz <= DATA_PKT_SZ) + nbytes = sz; + else + nbytes = DATA_PKT_SZ; + + /** + * Data Respnose header + **/ + retry = 10; + do { + if (!g_spi.spi_rx(&rsp, 1)) { + PRINT_ER("[wilc spi]: Failed data response read, bus error...\n"); + result = N_FAIL; + break; + } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); + + if (result == N_FAIL) + break; + + if (retry <= 0) { + PRINT_ER("[wilc spi]: Failed data response read...(%02x)\n", rsp); + result = N_FAIL; + break; + } + + /** + * Read bytes + **/ + if (!g_spi.spi_rx(&b[ix], nbytes)) { + PRINT_ER("[wilc spi]: Failed data block read, bus error...\n"); + result = N_FAIL; + break; + } + + /** + * Read Crc + **/ + if (!g_spi.crc_off) { + if (!g_spi.spi_rx(crc, 2)) { + PRINT_ER("[wilc spi]: Failed data block crc read, bus error...\n"); + result = N_FAIL; + break; + } + } + + ix += nbytes; + sz -= nbytes; + + } while (sz); + + return result; +} + +static int spi_data_write(uint8_t *b, uint32_t sz) +{ + int ix, nbytes; + int result = 1; + uint8_t cmd, order, crc[2] = {0}; + /* uint8_t rsp; */ + + /** + * Data + **/ + ix = 0; + do { + if (sz <= DATA_PKT_SZ) + nbytes = sz; + else + nbytes = DATA_PKT_SZ; + + /** + * Write command + **/ + cmd = 0xf0; + if (ix == 0) { + if (sz <= DATA_PKT_SZ) + + order = 0x3; + else + order = 0x1; + } else { + if (sz <= DATA_PKT_SZ) + order = 0x3; + else + order = 0x2; + } + cmd |= order; + if (!g_spi.spi_tx(&cmd, 1)) { + PRINT_ER("[wilc spi]: Failed data block cmd write, bus error...\n"); + result = N_FAIL; + break; + } + + /** + * Write data + **/ + if (!g_spi.spi_tx(&b[ix], nbytes)) { + PRINT_ER("[wilc spi]: Failed data block write, bus error...\n"); + result = N_FAIL; + break; + } + + /** + * Write Crc + **/ + if (!g_spi.crc_off) { + if (!g_spi.spi_tx(crc, 2)) { + PRINT_ER("[wilc spi]: Failed data block crc write, bus error...\n"); + result = N_FAIL; + break; + } + } + + /** + * No need to wait for response + **/ + ix += nbytes; + sz -= nbytes; + } while (sz); + + + return result; +} + +/******************************************** + * + * Spi Internal Read/Write Function + * + ********************************************/ + +static int spi_internal_write(uint32_t adr, uint32_t dat) +{ + int result; + +#if defined USE_OLD_SPI_SW + /** + * Command + **/ + result = spi_cmd(CMD_INTERNAL_WRITE, adr, dat, 4, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed internal write cmd...\n"); + return 0; + } + + result = spi_cmd_rsp(CMD_INTERNAL_WRITE, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed internal write cmd response...\n"); + } +#else + +#ifdef BIG_ENDIAN + dat = BYTE_SWAP(dat); +#endif + result = spi_cmd_complete(CMD_INTERNAL_WRITE, adr, (uint8_t *)&dat, 4, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed internal write cmd...\n"); + } + +#endif + return result; +} + +static int spi_internal_read(uint32_t adr, uint32_t *data) +{ + int result; + +#if defined USE_OLD_SPI_SW + result = spi_cmd(CMD_INTERNAL_READ, adr, 0, 4, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed internal read cmd...\n"); + return 0; + } + + result = spi_cmd_rsp(CMD_INTERNAL_READ, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed internal read cmd response...\n"); + return 0; + } + + /** + * Data + **/ + result = spi_data_read((uint8_t *)data, 4); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed internal read data...\n"); + return 0; + } +#else + result = spi_cmd_complete(CMD_INTERNAL_READ, adr, (uint8_t *)data, 4, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed internal read cmd...\n"); + return 0; + } +#endif + + +#ifdef BIG_ENDIAN + *data = BYTE_SWAP(*data); +#endif + + return 1; +} + +/******************************************** + * + * Spi interfaces + * + ********************************************/ + +static int spi_write_reg(uint32_t addr, uint32_t data) +{ + int result = N_OK; + uint8_t cmd = CMD_SINGLE_WRITE; + uint8_t clockless = 0; + + +#if defined USE_OLD_SPI_SW + { + result = spi_cmd(cmd, addr, data, 4, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, write reg (%08x)...\n", addr); + return 0; + } + + result = spi_cmd_rsp(cmd, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd response, write reg (%08x)...\n", addr); + return 0; + } + + return 1; + } +#else +#ifdef BIG_ENDIAN + data = BYTE_SWAP(data); +#endif + if (addr < 0x30) { + /* Clockless register*/ + cmd = CMD_INTERNAL_WRITE; + clockless = 1; + } + + result = spi_cmd_complete(cmd, addr, (uint8_t *)&data, 4, clockless); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, write reg (%08x)...\n", addr); + } + + return result; +#endif + +} + +static int spi_write(uint32_t addr, uint8_t *buf, uint32_t size) +{ + int result; + uint8_t cmd = CMD_DMA_EXT_WRITE; + + /** + * has to be greated than 4 + **/ + if (size <= 4) + return 0; + +#if defined USE_OLD_SPI_SW + /** + * Command + **/ + result = spi_cmd(cmd, addr, 0, size, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, write block (%08x)...\n", addr); + return 0; + } + + result = spi_cmd_rsp(cmd, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi ]: Failed cmd response, write block (%08x)...\n", addr); + return 0; + } +#else + result = spi_cmd_complete(cmd, addr, NULL, size, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, write block (%08x)...\n", addr); + return 0; + } +#endif + + /** + * Data + **/ + result = spi_data_write(buf, size); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed block data write...\n"); + } + + return 1; +} + +static int spi_read_reg(uint32_t addr, uint32_t *data) +{ + int result = N_OK; + uint8_t cmd = CMD_SINGLE_READ; + uint8_t clockless = 0; + +#if defined USE_OLD_SPI_SW + result = spi_cmd(cmd, addr, 0, 4, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, read reg (%08x)...\n", addr); + return 0; + } + result = spi_cmd_rsp(cmd, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd response, read reg (%08x)...\n", addr); + return 0; + } + + result = spi_data_read((uint8_t *)data, 4); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed data read...\n"); + return 0; + } +#else + if (addr < 0x30) { + /* PRINT_ER("***** read addr %d\n\n", addr); */ + /* Clockless register*/ + cmd = CMD_INTERNAL_READ; + clockless = 1; + } + + result = spi_cmd_complete(cmd, addr, (uint8_t *)data, 4, clockless); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, read reg (%08x)...\n", addr); + return 0; + } +#endif + + +#ifdef BIG_ENDIAN + *data = BYTE_SWAP(*data); +#endif + + return 1; +} + +static int spi_read(uint32_t addr, uint8_t *buf, uint32_t size) +{ + uint8_t cmd = CMD_DMA_EXT_READ; + int result; + + if (size <= 4) + return 0; + +#if defined USE_OLD_SPI_SW + /** + * Command + **/ + result = spi_cmd(cmd, addr, 0, size, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, read block (%08x)...\n", addr); + return 0; + } + + result = spi_cmd_rsp(cmd, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd response, read block (%08x)...\n", addr); + return 0; + } + + /** + * Data + **/ + result = spi_data_read(buf, size); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed block data read...\n"); + return 0; + } +#else + result = spi_cmd_complete(cmd, addr, buf, size, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, read block (%08x)...\n", addr); + return 0; + } +#endif + + + return 1; +} + +/******************************************** + * + * Bus interfaces + * + ********************************************/ + +static int spi_clear_int(void) +{ + uint32_t reg; + if (!spi_read_reg(WILC_HOST_RX_CTRL_0, ®)) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_HOST_RX_CTRL_0); + return 0; + } + reg &= ~0x1; + spi_write_reg(WILC_HOST_RX_CTRL_0, reg); + int_clrd++; + return 1; +} + +static int spi_deinit(void *pv) +{ + /** + * TODO: + **/ + return 1; +} + +static int spi_sync(void) +{ + uint32_t reg; + int ret; + + /** + * interrupt pin mux select + **/ + ret = spi_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + reg |= (1 << 8); + ret = spi_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + + /** + * interrupt enable + **/ + ret = spi_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + reg |= (1 << 16); + ret = spi_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + + return 1; +} + +static int spi_init(wilc_wlan_inp_t *inp, wilc_debug_func func) +{ + uint32_t reg; + uint32_t chipid; + + static int isinit; + + if (isinit) { + + if (!spi_read_reg(0x1000, &chipid)) { + PRINT_ER("[wilc spi]: Fail cmd read chip id...\n"); + return 0; + } + return 1; + } + + memset(&g_spi, 0, sizeof(wilc_spi_t)); + + g_spi.dPrint = func; + g_spi.os_context = inp->os_context.os_private; + if (inp->io_func.io_init) { + if (!inp->io_func.io_init(g_spi.os_context)) { + PRINT_ER("[wilc spi]: Failed io init bus...\n"); + return 0; + } + } else { + return 0; + } + g_spi.spi_tx = inp->io_func.u.spi.spi_tx; + g_spi.spi_rx = inp->io_func.u.spi.spi_rx; + g_spi.spi_trx = inp->io_func.u.spi.spi_trx; + g_spi.spi_max_speed = inp->io_func.u.spi.spi_max_speed; + + /** + * configure protocol + **/ + g_spi.crc_off = 0; + + /* TODO: We can remove the CRC trials if there is a definite way to reset */ + /* the SPI to it's initial value. */ + if (!spi_internal_read(WILC_SPI_PROTOCOL_OFFSET, ®)) { + /* Read failed. Try with CRC off. This might happen when module + * is removed but chip isn't reset*/ + g_spi.crc_off = 1; + PRINT_ER("[wilc spi]: Failed internal read protocol with CRC on, retyring with CRC off...\n"); + if (!spi_internal_read(WILC_SPI_PROTOCOL_OFFSET, ®)) { + /* Reaad failed with both CRC on and off, something went bad */ + PRINT_ER("[wilc spi]: Failed internal read protocol...\n"); + return 0; + } + } + if (g_spi.crc_off == 0) { + reg &= ~0xc; /* disable crc checking */ + reg &= ~0x70; + reg |= (0x5 << 4); + if (!spi_internal_write(WILC_SPI_PROTOCOL_OFFSET, reg)) { + PRINT_ER("[wilc spi %d]: Failed internal write protocol reg...\n", __LINE__); + return 0; + } + g_spi.crc_off = 1; + } + + + /** + * make sure can read back chip id correctly + **/ + if (!spi_read_reg(0x1000, &chipid)) { + PRINT_ER("[wilc spi]: Fail cmd read chip id...\n"); + return 0; + } + /* PRINT_ER("[wilc spi]: chipid (%08x)\n", chipid); */ + + g_spi.has_thrpt_enh = 1; + + isinit = 1; + + return 1; +} + +static void spi_max_bus_speed(void) +{ + g_spi.spi_max_speed(); +} + +static void spi_default_bus_speed(void) +{ +} + +static int spi_read_size(uint32_t *size) +{ + int ret; + if (g_spi.has_thrpt_enh) { + ret = spi_internal_read(0xe840 - WILC_SPI_REG_BASE, size); + *size = *size & IRQ_DMA_WD_CNT_MASK; + } else { + uint32_t tmp; + uint32_t byte_cnt; + + ret = spi_read_reg(WILC_VMM_TO_HOST_SIZE, &byte_cnt); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read WILC_VMM_TO_HOST_SIZE ...\n"); + goto _fail_; + } + tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK; + *size = tmp; + } + + + +_fail_: + return ret; +} + + + +static int spi_read_int(uint32_t *int_status) +{ + int ret; + if (g_spi.has_thrpt_enh) { + ret = spi_internal_read(0xe840 - WILC_SPI_REG_BASE, int_status); + } else { + uint32_t tmp; + uint32_t byte_cnt; + + ret = spi_read_reg(WILC_VMM_TO_HOST_SIZE, &byte_cnt); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read WILC_VMM_TO_HOST_SIZE ...\n"); + goto _fail_; + } + tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK; + + { + int happended, j; + + j = 0; + do { + uint32_t irq_flags; + + happended = 0; + + spi_read_reg(0x1a90, &irq_flags); + tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET); + + if (g_spi.nint > 5) { + spi_read_reg(0x1a94, &irq_flags); + tmp |= (((irq_flags >> 0) & 0x7) << (IRG_FLAGS_OFFSET + 5)); + } + + { + uint32_t unkmown_mask; + + unkmown_mask = ~((1ul << g_spi.nint) - 1); + + if ((tmp >> IRG_FLAGS_OFFSET) & unkmown_mask) { + PRINT_ER("[wilc spi]: Unexpected interrupt (2): j=%d, tmp=%x, mask=%x\n", j, tmp, unkmown_mask); + happended = 1; + } + } + j++; + } while (happended); + } + + *int_status = tmp; + + } + +_fail_: + return ret; +} + +static int spi_clear_int_ext(uint32_t val) +{ + int ret; + + if (g_spi.has_thrpt_enh) { + ret = spi_internal_write(0xe844 - WILC_SPI_REG_BASE, val); + } else { + uint32_t flags; + flags = val & ((1 << MAX_NUM_INT) - 1); + if (flags) { + int i; + + ret = 1; + for (i = 0; i < g_spi.nint; i++) { + /* No matter what you write 1 or 0, it will clear interrupt. */ + if (flags & 1) + ret = spi_write_reg(0x10c8 + i * 4, 1); + if (!ret) + break; + flags >>= 1; + } + if (!ret) { + PRINT_ER("[wilc spi]: Failed spi_write_reg, set reg %x ...\n", 0x10c8 + i * 4); + goto _fail_; + } + for (i = g_spi.nint; i < MAX_NUM_INT; i++) { + if (flags & 1) + PRINT_ER("[wilc spi]: Unexpected interrupt cleared %d...\n", i); + flags >>= 1; + } + } + + { + uint32_t tbl_ctl; + + tbl_ctl = 0; + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + tbl_ctl |= (1 << 0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + tbl_ctl |= (1 << 1); + + ret = spi_write_reg(WILC_VMM_TBL_CTL, tbl_ctl); + if (!ret) { + PRINT_ER("[wilc spi]: fail write reg vmm_tbl_ctl...\n"); + goto _fail_; + } + + if ((val & EN_VMM) == EN_VMM) { + /** + * enable vmm transfer. + **/ + ret = spi_write_reg(WILC_VMM_CORE_CTL, 1); + if (!ret) { + PRINT_ER("[wilc spi]: fail write reg vmm_core_ctl...\n"); + goto _fail_; + } + } + } + } +_fail_: + return ret; +} + +static int spi_sync_ext(int nint /* how mant interrupts to enable. */) +{ + uint32_t reg; + int ret, i; + + if (nint > MAX_NUM_INT) { + PRINT_ER("[wilc spi]: Too many interupts (%d)...\n", nint); + return 0; + } + + g_spi.nint = nint; + + /** + * interrupt pin mux select + **/ + ret = spi_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + reg |= (1 << 8); + ret = spi_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + + /** + * interrupt enable + **/ + ret = spi_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + + for (i = 0; (i < 5) && (nint > 0); i++, nint--) { + reg |= (1 << (27 + i)); + } + ret = spi_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + if (nint) { + ret = spi_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR2_ENABLE); + return 0; + } + + for (i = 0; (i < 3) && (nint > 0); i++, nint--) { + reg |= (1 << i); + } + + ret = spi_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR2_ENABLE); + return 0; + } + } + + return 1; +} +/******************************************** + * + * Global spi HIF function table + * + ********************************************/ +wilc_hif_func_t hif_spi = { + spi_init, + spi_deinit, + spi_read_reg, + spi_write_reg, + spi_read, + spi_write, + spi_sync, + spi_clear_int, + spi_read_int, + spi_clear_int_ext, + spi_read_size, + spi_write, + spi_read, + spi_sync_ext, + spi_max_bus_speed, + spi_default_bus_speed, +}; diff --git a/drivers/staging/wilc1000/wilc_strutils.c b/drivers/staging/wilc1000/wilc_strutils.c new file mode 100644 index 000000000..e0145953c --- /dev/null +++ b/drivers/staging/wilc1000/wilc_strutils.c @@ -0,0 +1,80 @@ + +#define _CRT_SECURE_NO_DEPRECATE + +#include "wilc_strutils.h" + + +/*! + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +s32 WILC_memcmp(const void *pvArg1, const void *pvArg2, u32 u32Count) +{ + return memcmp(pvArg1, pvArg2, u32Count); +} + + +/*! + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +void WILC_memcpy_INTERNAL(void *pvTarget, const void *pvSource, u32 u32Count) +{ + memcpy(pvTarget, pvSource, u32Count); +} + +/*! + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +void *WILC_memset(void *pvTarget, u8 u8SetValue, u32 u32Count) +{ + return memset(pvTarget, u8SetValue, u32Count); +} + +/*! + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +char *WILC_strncpy(char *pcTarget, const char *pcSource, + u32 u32Count) +{ + return strncpy(pcTarget, pcSource, u32Count); +} + +s32 WILC_strncmp(const char *pcStr1, const char *pcStr2, + u32 u32Count) +{ + s32 s32Result; + + if (pcStr1 == NULL && pcStr2 == NULL) { + s32Result = 0; + } else if (pcStr1 == NULL) { + s32Result = -1; + } else if (pcStr2 == NULL) { + s32Result = 1; + } else { + s32Result = strncmp(pcStr1, pcStr2, u32Count); + if (s32Result < 0) { + s32Result = -1; + } else if (s32Result > 0) { + s32Result = 1; + } + } + + return s32Result; +} + +/*! + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +u32 WILC_strlen(const char *pcStr) +{ + return (u32)strlen(pcStr); +} diff --git a/drivers/staging/wilc1000/wilc_strutils.h b/drivers/staging/wilc1000/wilc_strutils.h new file mode 100644 index 000000000..d1445575a --- /dev/null +++ b/drivers/staging/wilc1000/wilc_strutils.h @@ -0,0 +1,134 @@ +#ifndef __WILC_STRUTILS_H__ +#define __WILC_STRUTILS_H__ + +/*! + * @file wilc_strutils.h + * @brief Basic string utilities + * @author syounan + * @sa wilc_oswrapper.h top level OS wrapper file + * @date 16 Aug 2010 + * @version 1.0 + */ + +#include +#include +#include "wilc_errorsupport.h" + +/*! + * @brief Compares two memory buffers + * @param[in] pvArg1 pointer to the first memory location + * @param[in] pvArg2 pointer to the second memory location + * @param[in] u32Count the size of the memory buffers + * @return 0 if the 2 buffers are equal, 1 if pvArg1 is bigger than pvArg2, + * -1 if pvArg1 smaller than pvArg2 + * @note this function repeats the functionality of standard memcmp + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +s32 WILC_memcmp(const void *pvArg1, const void *pvArg2, u32 u32Count); + +/*! + * @brief Internal implementation for memory copy + * @param[in] pvTarget the target buffer to which the data is copied into + * @param[in] pvSource pointer to the second memory location + * @param[in] u32Count the size of the data to copy + * @note this function should not be used directly, use WILC_memcpy instead + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +void WILC_memcpy_INTERNAL(void *pvTarget, const void *pvSource, u32 u32Count); + +/*! + * @brief Copies the contents of a memory buffer into another + * @param[in] pvTarget the target buffer to which the data is copied into + * @param[in] pvSource pointer to the second memory location + * @param[in] u32Count the size of the data to copy + * @return WILC_SUCCESS if copy is successfully handeled + * WILC_FAIL if copy failed + * @note this function repeats the functionality of standard memcpy, + * however memcpy is undefined if the two buffers overlap but this + * implementation will check for overlap and report error + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +static WILC_ErrNo WILC_memcpy(void *pvTarget, const void *pvSource, u32 u32Count) +{ + if ( + (((u8 *)pvTarget <= (u8 *)pvSource) + && (((u8 *)pvTarget + u32Count) > (u8 *)pvSource)) + + || (((u8 *)pvSource <= (u8 *)pvTarget) + && (((u8 *)pvSource + u32Count) > (u8 *)pvTarget)) + ) { + /* ovelapped memory, return Error */ + return WILC_FAIL; + } else { + WILC_memcpy_INTERNAL(pvTarget, pvSource, u32Count); + return WILC_SUCCESS; + } +} + +/*! + * @brief Sets the contents of a memory buffer with the given value + * @param[in] pvTarget the target buffer which contsnts will be set + * @param[in] u8SetValue the value to be used + * @param[in] u32Count the size of the memory buffer + * @return value of pvTarget + * @note this function repeats the functionality of standard memset + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +void *WILC_memset(void *pvTarget, u8 u8SetValue, u32 u32Count); + +/*! + * @brief copies the contents of source string into the target string + * @param[in] pcTarget the target string buffer + * @param[in] pcSource the source string the will be copied + * @param[in] u32Count copying will proceed until a null character in pcSource + * is encountered or u32Count of bytes copied + * @return value of pcTarget + * @note this function repeats the functionality of standard strncpy + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +char *WILC_strncpy(char *pcTarget, const char *pcSource, + u32 u32Count); + +/*! + * @brief Compares two strings up to u32Count characters + * @details Compares 2 strings reporting which is bigger, NULL is considered + * the smallest string, then a zero length string then all other + * strings depending on thier ascii characters order with small case + * converted to uppder case + * @param[in] pcStr1 the first string, NULL is valid and considered smaller + * than any other non-NULL string (incliding zero lenght strings) + * @param[in] pcStr2 the second string, NULL is valid and considered smaller + * than any other non-NULL string (incliding zero lenght strings) + * @param[in] u32Count copying will proceed until a null character in pcStr1 or + * pcStr2 is encountered or u32Count of bytes copied + * @return 0 if the 2 strings are equal, 1 if pcStr1 is bigger than pcStr2, + * -1 if pcStr1 smaller than pcStr2 + * @author aabozaeid + * @date 7 Dec 2010 + * @version 1.0 + */ +s32 WILC_strncmp(const char *pcStr1, const char *pcStr2, + u32 u32Count); + +/*! + * @brief gets the length of a string + * @param[in] pcStr the string + * @return the length + * @note this function repeats the functionality of standard strlen + * @author syounan + * @date 18 Aug 2010 + * @version 1.0 + */ +u32 WILC_strlen(const char *pcStr); + +#endif diff --git a/drivers/staging/wilc1000/wilc_timer.c b/drivers/staging/wilc1000/wilc_timer.c new file mode 100644 index 000000000..dc71157f9 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_timer.c @@ -0,0 +1,45 @@ + +#include "wilc_timer.h" + +WILC_ErrNo WILC_TimerCreate(WILC_TimerHandle *pHandle, + tpfWILC_TimerFunction pfCallback, tstrWILC_TimerAttrs *pstrAttrs) +{ + WILC_ErrNo s32RetStatus = WILC_SUCCESS; + setup_timer(pHandle, (void(*)(unsigned long))pfCallback, 0); + + return s32RetStatus; +} + +WILC_ErrNo WILC_TimerDestroy(WILC_TimerHandle *pHandle, + tstrWILC_TimerAttrs *pstrAttrs) +{ + WILC_ErrNo s32RetStatus = WILC_FAIL; + if (pHandle != NULL) { + s32RetStatus = del_timer_sync(pHandle); + pHandle = NULL; + } + + return s32RetStatus; +} + + +WILC_ErrNo WILC_TimerStart(WILC_TimerHandle *pHandle, u32 u32Timeout, + void *pvArg, tstrWILC_TimerAttrs *pstrAttrs) +{ + WILC_ErrNo s32RetStatus = WILC_FAIL; + if (pHandle != NULL) { + pHandle->data = (unsigned long)pvArg; + s32RetStatus = mod_timer(pHandle, (jiffies + msecs_to_jiffies(u32Timeout))); + } + return s32RetStatus; +} + +WILC_ErrNo WILC_TimerStop(WILC_TimerHandle *pHandle, + tstrWILC_TimerAttrs *pstrAttrs) +{ + WILC_ErrNo s32RetStatus = WILC_FAIL; + if (pHandle != NULL) + s32RetStatus = del_timer(pHandle); + + return s32RetStatus; +} diff --git a/drivers/staging/wilc1000/wilc_timer.h b/drivers/staging/wilc1000/wilc_timer.h new file mode 100644 index 000000000..931269db3 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_timer.h @@ -0,0 +1,129 @@ +#ifndef __WILC_TIMER_H__ +#define __WILC_TIMER_H__ + +/*! + * @file wilc_timer.h + * @brief Timer (One Shot and Periodic) OS wrapper functionality + * @author syounan + * @sa wilc_oswrapper.h top level OS wrapper file + * @date 16 Aug 2010 + * @version 1.0 + */ + +#include "wilc_platform.h" +#include "wilc_errorsupport.h" + +typedef void (*tpfWILC_TimerFunction)(void *); + +/*! + * @struct tstrWILC_TimerAttrs + * @brief Timer API options + * @author syounan + * @date 16 Aug 2010 + * @version 1.0 + */ +typedef struct { + /* a dummy member to avoid compiler errors*/ + u8 dummy; +} tstrWILC_TimerAttrs; + +/*! + * @brief Creates a new timer + * @details Timers are a useful utility to execute some callback function + * in the future. + * A timer object has 3 states : IDLE, PENDING and EXECUTING + * IDLE : initial timer state after creation, no execution for the + * callback function is planned + * PENDING : a request to execute the callback function is made + * using WILC_TimerStart. + * EXECUTING : the timer has expired and its callback is now + * executing, when execution is done the timer returns to PENDING + * if the feature CONFIG_WILC_TIMER_PERIODIC is enabled and + * the flag tstrWILC_TimerAttrs.bPeriodicTimer is set. otherwise the + * timer will return to IDLE + * @param[out] pHandle handle to the newly created timer object + * @param[in] pfEntry pointer to the callback function to be called when the + * timer expires + * the underlaying OS may put many restrictions on what can be + * called inside a timer's callback, as a general rule no blocking + * operations (IO or semaphore Acquision) should be perfomred + * It is recommended that the callback will be as short as possible + * and only flags other threads to do the actual work + * also it should be noted that the underlaying OS maynot give any + * guarentees on which contect this callback will execute in + * @param[in] pstrAttrs Optional attributes, NULL for default + * @return Error code indicating sucess/failure + * @sa WILC_TimerAttrs + * @author syounan + * @date 16 Aug 2010 + * @version 1.0 + */ +WILC_ErrNo WILC_TimerCreate(WILC_TimerHandle *pHandle, + tpfWILC_TimerFunction pfCallback, tstrWILC_TimerAttrs *pstrAttrs); + + +/*! + * @brief Destroys a given timer + * @details This will destroy a given timer freeing any resources used by it + * if the timer was PENDING Then must be cancelled as well(i.e. + * goes to IDLE, same effect as calling WILC_TimerCancel first) + * if the timer was EXECUTING then the callback will be allowed to + * finish first then all resources are freed + * @param[in] pHandle handle to the timer object + * @param[in] pstrAttrs Optional attributes, NULL for default + * @return Error code indicating sucess/failure + * @sa WILC_TimerAttrs + * @author syounan + * @date 16 Aug 2010 + * @version 1.0 + */ +WILC_ErrNo WILC_TimerDestroy(WILC_TimerHandle *pHandle, + tstrWILC_TimerAttrs *pstrAttrs); + +/*! + * @brief Starts a given timer + * @details This function will move the timer to the PENDING state until the + * given time expires (in msec) then the callback function will be + * executed (timer in EXECUTING state) after execution is dene the + * timer either goes to IDLE (if bPeriodicTimer==false) or + * PENDING with same timeout value (if bPeriodicTimer==true) + * @param[in] pHandle handle to the timer object + * @param[in] u32Timeout timeout value in msec after witch the callback + * function will be executed. Timeout value of 0 is not allowed for + * periodic timers + * @param[in] pstrAttrs Optional attributes, NULL for default, + * set bPeriodicTimer to run this timer as a periodic timer + * @return Error code indicating sucess/failure + * @sa WILC_TimerAttrs + * @author syounan + * @date 16 Aug 2010 + * @version 1.0 + */ +WILC_ErrNo WILC_TimerStart(WILC_TimerHandle *pHandle, u32 u32Timeout, void *pvArg, + tstrWILC_TimerAttrs *pstrAttrs); + + +/*! + * @brief Stops a given timer + * @details This function will move the timer to the IDLE state cancelling + * any sheduled callback execution. + * if this function is called on a timer already in the IDLE state + * it will have no effect. + * if this function is called on a timer in EXECUTING state + * (callback has already started) it will wait until executing is + * done then move the timer to the IDLE state (which is trivial + * work if the timer is non periodic) + * @param[in] pHandle handle to the timer object + * @param[in] pstrAttrs Optional attributes, NULL for default, + * @return Error code indicating sucess/failure + * @sa WILC_TimerAttrs + * @author syounan + * @date 16 Aug 2010 + * @version 1.0 + */ +WILC_ErrNo WILC_TimerStop(WILC_TimerHandle *pHandle, + tstrWILC_TimerAttrs *pstrAttrs); + + + +#endif diff --git a/drivers/staging/wilc1000/wilc_type.h b/drivers/staging/wilc1000/wilc_type.h new file mode 100644 index 000000000..5f36e7f92 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_type.h @@ -0,0 +1,34 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_type.h */ +/* */ +/* */ +/* //////////////////////////////////////////////////////////////////////////// */ +#ifndef WILC_TYPE_H +#define WILC_TYPE_H + +/******************************************** + * + * Type Defines + * + ********************************************/ +#ifdef WIN32 +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +#else +#ifdef _linux_ +/*typedef unsigned char uint8_t; + * typedef unsigned short uint16_t; + * typedef unsigned long uint32_t;*/ +#include +#else +#include "wilc_oswrapper.h" +#endif +#endif +#endif diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c new file mode 100644 index 000000000..92064db9e --- /dev/null +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -0,0 +1,3957 @@ +/*! + * @file wilc_wfi_cfgopertaions.c + * @brief CFG80211 Function Implementation functionality + * @author aabouzaeid + * mabubakr + * mdaftedar + * zsalah + * @sa wilc_wfi_cfgopertaions.h top level OS wrapper file + * @date 31 Aug 2010 + * @version 1.0 + */ + +#include "wilc_wfi_cfgoperations.h" +#include "wilc_wlan.c" +#ifdef WILC_SDIO +#include "linux_wlan_sdio.h" /* tony : for set_wiphy_dev() */ +#endif + + +#define IS_MANAGMEMENT 0x100 +#define IS_MANAGMEMENT_CALLBACK 0x080 +#define IS_MGMT_STATUS_SUCCES 0x040 +#define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff) + +extern void linux_wlan_free(void *vp); +extern int linux_wlan_get_firmware(perInterface_wlan_t *p_nic); +extern void linux_wlan_unlock(void *vp); +extern u16 Set_machw_change_vir_if(bool bValue); + +extern int mac_open(struct net_device *ndev); +extern int mac_close(struct net_device *ndev); + +tstrNetworkInfo astrLastScannedNtwrksShadow[MAX_NUM_SCANNED_NETWORKS_SHADOW]; +u32 u32LastScannedNtwrksCountShadow; +#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP +WILC_TimerHandle hDuringIpTimer; +#endif +WILC_TimerHandle hAgingTimer; +static u8 op_ifcs; +extern u8 u8ConnectedSSID[6]; + +/*BugID_5137*/ +u8 g_wilc_initialized = 1; +extern linux_wlan_t *g_linux_wlan; +#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP +extern bool g_obtainingIP; +#endif + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +/*Frequency range for channels*/ +static struct ieee80211_channel WILC_WFI_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +#define RATETAB_ENT(_rate, _hw_value, _flags) { \ + .bitrate = (_rate), \ + .hw_value = (_hw_value), \ + .flags = (_flags), \ +} + + +/* Table 6 in section 3.2.1.1 */ +static struct ieee80211_rate WILC_WFI_rates[] = { + RATETAB_ENT(10, 0, 0), + RATETAB_ENT(20, 1, 0), + RATETAB_ENT(55, 2, 0), + RATETAB_ENT(110, 3, 0), + RATETAB_ENT(60, 9, 0), + RATETAB_ENT(90, 6, 0), + RATETAB_ENT(120, 7, 0), + RATETAB_ENT(180, 8, 0), + RATETAB_ENT(240, 9, 0), + RATETAB_ENT(360, 10, 0), + RATETAB_ENT(480, 11, 0), + RATETAB_ENT(540, 12, 0), +}; + +#ifdef WILC_P2P +struct p2p_mgmt_data { + int size; + u8 *buff; +}; + +/*Global variable used to state the current connected STA channel*/ +u8 u8WLANChannel = INVALID_CHANNEL; + +/*BugID_5442*/ +u8 u8CurrChannel; + +u8 u8P2P_oui[] = {0x50, 0x6f, 0x9A, 0x09}; +u8 u8P2Plocalrandom = 0x01; +u8 u8P2Precvrandom = 0x00; +u8 u8P2P_vendorspec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03}; +bool bWilc_ie = false; +#endif + +static struct ieee80211_supported_band WILC_WFI_band_2ghz = { + .channels = WILC_WFI_2ghz_channels, + .n_channels = ARRAY_SIZE(WILC_WFI_2ghz_channels), + .bitrates = WILC_WFI_rates, + .n_bitrates = ARRAY_SIZE(WILC_WFI_rates), +}; + + +/*BugID_5137*/ +struct add_key_params { + u8 key_idx; + bool pairwise; + u8 *mac_addr; +}; +struct add_key_params g_add_gtk_key_params; +struct wilc_wfi_key g_key_gtk_params; +struct add_key_params g_add_ptk_key_params; +struct wilc_wfi_key g_key_ptk_params; +struct wilc_wfi_wep_key g_key_wep_params; +u8 g_flushing_in_progress; +bool g_ptk_keys_saved = false; +bool g_gtk_keys_saved = false; +bool g_wep_keys_saved = false; + +#define AGING_TIME (9 * 1000) +#define duringIP_TIME 15000 + +void clear_shadow_scan(void *pUserVoid) +{ + struct WILC_WFI_priv *priv; + int i; + priv = (struct WILC_WFI_priv *)pUserVoid; + if (op_ifcs == 0) { + WILC_TimerDestroy(&hAgingTimer, NULL); + PRINT_INFO(CORECONFIG_DBG, "destroy aging timer\n"); + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + if (astrLastScannedNtwrksShadow[u32LastScannedNtwrksCountShadow].pu8IEs != NULL) { + WILC_FREE(astrLastScannedNtwrksShadow[i].pu8IEs); + astrLastScannedNtwrksShadow[u32LastScannedNtwrksCountShadow].pu8IEs = NULL; + } + + host_int_freeJoinParams(astrLastScannedNtwrksShadow[i].pJoinParams); + astrLastScannedNtwrksShadow[i].pJoinParams = NULL; + } + u32LastScannedNtwrksCountShadow = 0; + } + +} + +uint32_t get_rssi_avg(tstrNetworkInfo *pstrNetworkInfo) +{ + uint8_t i; + int rssi_v = 0; + uint8_t num_rssi = (pstrNetworkInfo->strRssi.u8Full) ? NUM_RSSI : (pstrNetworkInfo->strRssi.u8Index); + + for (i = 0; i < num_rssi; i++) + rssi_v += pstrNetworkInfo->strRssi.as8RSSI[i]; + + rssi_v /= num_rssi; + return rssi_v; +} + +void refresh_scan(void *pUserVoid, uint8_t all, bool bDirectScan) +{ + struct WILC_WFI_priv *priv; + struct wiphy *wiphy; + struct cfg80211_bss *bss = NULL; + int i; + int rssi = 0; + + priv = (struct WILC_WFI_priv *)pUserVoid; + wiphy = priv->dev->ieee80211_ptr->wiphy; + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + tstrNetworkInfo *pstrNetworkInfo; + pstrNetworkInfo = &(astrLastScannedNtwrksShadow[i]); + + + if ((!pstrNetworkInfo->u8Found) || all) { + s32 s32Freq; + struct ieee80211_channel *channel; + + if (pstrNetworkInfo != NULL) { + + s32Freq = ieee80211_channel_to_frequency((s32)pstrNetworkInfo->u8channel, IEEE80211_BAND_2GHZ); + channel = ieee80211_get_channel(wiphy, s32Freq); + + rssi = get_rssi_avg(pstrNetworkInfo); + if (WILC_memcmp("DIRECT-", pstrNetworkInfo->au8ssid, 7) || bDirectScan) { + bss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, pstrNetworkInfo->au8bssid, pstrNetworkInfo->u64Tsf, pstrNetworkInfo->u16CapInfo, + pstrNetworkInfo->u16BeaconPeriod, (const u8 *)pstrNetworkInfo->pu8IEs, + (size_t)pstrNetworkInfo->u16IEsLen, (((s32)rssi) * 100), GFP_KERNEL); + cfg80211_put_bss(wiphy, bss); + } + } + + } + } + +} + +void reset_shadow_found(void *pUserVoid) +{ + struct WILC_WFI_priv *priv; + int i; + priv = (struct WILC_WFI_priv *)pUserVoid; + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + astrLastScannedNtwrksShadow[i].u8Found = 0; + + } +} + +void update_scan_time(void *pUserVoid) +{ + struct WILC_WFI_priv *priv; + int i; + priv = (struct WILC_WFI_priv *)pUserVoid; + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan = jiffies; + } +} + +void remove_network_from_shadow(void *pUserVoid) +{ + struct WILC_WFI_priv *priv; + unsigned long now = jiffies; + int i, j; + + priv = (struct WILC_WFI_priv *)pUserVoid; + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + if (time_after(now, astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan + (unsigned long)(SCAN_RESULT_EXPIRE))) { + PRINT_D(CFG80211_DBG, "Network expired in ScanShadow: %s \n", astrLastScannedNtwrksShadow[i].au8ssid); + + if (astrLastScannedNtwrksShadow[i].pu8IEs != NULL) { + WILC_FREE(astrLastScannedNtwrksShadow[i].pu8IEs); + astrLastScannedNtwrksShadow[i].pu8IEs = NULL; + } + + host_int_freeJoinParams(astrLastScannedNtwrksShadow[i].pJoinParams); + + for (j = i; (j < u32LastScannedNtwrksCountShadow - 1); j++) { + astrLastScannedNtwrksShadow[j] = astrLastScannedNtwrksShadow[j + 1]; + } + u32LastScannedNtwrksCountShadow--; + } + } + + PRINT_D(CFG80211_DBG, "Number of cached networks: %d\n", u32LastScannedNtwrksCountShadow); + if (u32LastScannedNtwrksCountShadow != 0) + WILC_TimerStart(&(hAgingTimer), AGING_TIME, pUserVoid, NULL); + else + PRINT_D(CFG80211_DBG, "No need to restart Aging timer\n"); +} + +#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP +void clear_duringIP(void *pUserVoid) +{ + PRINT_D(GENERIC_DBG, "GO:IP Obtained , enable scan\n"); + g_obtainingIP = false; +} +#endif + +int8_t is_network_in_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid) +{ + struct WILC_WFI_priv *priv; + int8_t state = -1; + int i; + + priv = (struct WILC_WFI_priv *)pUserVoid; + if (u32LastScannedNtwrksCountShadow == 0) { + PRINT_D(CFG80211_DBG, "Starting Aging timer\n"); + WILC_TimerStart(&(hAgingTimer), AGING_TIME, pUserVoid, NULL); + state = -1; + } else { + /* Linear search for now */ + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + if (WILC_memcmp(astrLastScannedNtwrksShadow[i].au8bssid, + pstrNetworkInfo->au8bssid, 6) == 0) { + state = i; + break; + } + } + } + return state; +} + +void add_network_to_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid, void *pJoinParams) +{ + struct WILC_WFI_priv *priv; + int8_t ap_found = is_network_in_shadow(pstrNetworkInfo, pUserVoid); + uint32_t ap_index = 0; + uint8_t rssi_index = 0; + priv = (struct WILC_WFI_priv *)pUserVoid; + + if (u32LastScannedNtwrksCountShadow >= MAX_NUM_SCANNED_NETWORKS_SHADOW) { + PRINT_D(CFG80211_DBG, "Shadow network reached its maximum limit\n"); + return; + } + if (ap_found == -1) { + ap_index = u32LastScannedNtwrksCountShadow; + u32LastScannedNtwrksCountShadow++; + + } else { + ap_index = ap_found; + } + rssi_index = astrLastScannedNtwrksShadow[ap_index].strRssi.u8Index; + astrLastScannedNtwrksShadow[ap_index].strRssi.as8RSSI[rssi_index++] = pstrNetworkInfo->s8rssi; + if (rssi_index == NUM_RSSI) { + rssi_index = 0; + astrLastScannedNtwrksShadow[ap_index].strRssi.u8Full = 1; + } + astrLastScannedNtwrksShadow[ap_index].strRssi.u8Index = rssi_index; + + astrLastScannedNtwrksShadow[ap_index].s8rssi = pstrNetworkInfo->s8rssi; + astrLastScannedNtwrksShadow[ap_index].u16CapInfo = pstrNetworkInfo->u16CapInfo; + + astrLastScannedNtwrksShadow[ap_index].u8SsidLen = pstrNetworkInfo->u8SsidLen; + WILC_memcpy(astrLastScannedNtwrksShadow[ap_index].au8ssid, + pstrNetworkInfo->au8ssid, pstrNetworkInfo->u8SsidLen); + + WILC_memcpy(astrLastScannedNtwrksShadow[ap_index].au8bssid, + pstrNetworkInfo->au8bssid, ETH_ALEN); + + astrLastScannedNtwrksShadow[ap_index].u16BeaconPeriod = pstrNetworkInfo->u16BeaconPeriod; + astrLastScannedNtwrksShadow[ap_index].u8DtimPeriod = pstrNetworkInfo->u8DtimPeriod; + astrLastScannedNtwrksShadow[ap_index].u8channel = pstrNetworkInfo->u8channel; + + astrLastScannedNtwrksShadow[ap_index].u16IEsLen = pstrNetworkInfo->u16IEsLen; + astrLastScannedNtwrksShadow[ap_index].u64Tsf = pstrNetworkInfo->u64Tsf; + if (ap_found != -1) + WILC_FREE(astrLastScannedNtwrksShadow[ap_index].pu8IEs); + astrLastScannedNtwrksShadow[ap_index].pu8IEs = + (u8 *)WILC_MALLOC(pstrNetworkInfo->u16IEsLen); /* will be deallocated by the WILC_WFI_CfgScan() function */ + WILC_memcpy(astrLastScannedNtwrksShadow[ap_index].pu8IEs, + pstrNetworkInfo->pu8IEs, pstrNetworkInfo->u16IEsLen); + + astrLastScannedNtwrksShadow[ap_index].u32TimeRcvdInScan = jiffies; + astrLastScannedNtwrksShadow[ap_index].u32TimeRcvdInScanCached = jiffies; + astrLastScannedNtwrksShadow[ap_index].u8Found = 1; + if (ap_found != -1) + host_int_freeJoinParams(astrLastScannedNtwrksShadow[ap_index].pJoinParams); + astrLastScannedNtwrksShadow[ap_index].pJoinParams = pJoinParams; + +} + + +/** + * @brief CfgScanResult + * @details Callback function which returns the scan results found + * + * @param[in] tenuScanEvent enuScanEvent: enum, indicating the scan event triggered, whether that is + * SCAN_EVENT_NETWORK_FOUND or SCAN_EVENT_DONE + * tstrNetworkInfo* pstrNetworkInfo: structure holding the scan results information + * void* pUserVoid: Private structure associated with the wireless interface + * @return NONE + * @author mabubakr + * @date + * @version 1.0 + */ +static void CfgScanResult(tenuScanEvent enuScanEvent, tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid, void *pJoinParams) +{ + struct WILC_WFI_priv *priv; + struct wiphy *wiphy; + s32 s32Freq; + struct ieee80211_channel *channel; + s32 s32Error = WILC_SUCCESS; + struct cfg80211_bss *bss = NULL; + + priv = (struct WILC_WFI_priv *)pUserVoid; + if (priv->bCfgScanning == true) { + if (enuScanEvent == SCAN_EVENT_NETWORK_FOUND) { + wiphy = priv->dev->ieee80211_ptr->wiphy; + WILC_NULLCHECK(s32Error, wiphy); + if (wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC + && + ((((s32)pstrNetworkInfo->s8rssi) * 100) < 0 + || + (((s32)pstrNetworkInfo->s8rssi) * 100) > 100) + ) { + WILC_ERRORREPORT(s32Error, WILC_FAIL); + } + + if (pstrNetworkInfo != NULL) { + s32Freq = ieee80211_channel_to_frequency((s32)pstrNetworkInfo->u8channel, IEEE80211_BAND_2GHZ); + channel = ieee80211_get_channel(wiphy, s32Freq); + + WILC_NULLCHECK(s32Error, channel); + + PRINT_INFO(CFG80211_DBG, "Network Info:: CHANNEL Frequency: %d, RSSI: %d, CapabilityInfo: %d," + "BeaconPeriod: %d \n", channel->center_freq, (((s32)pstrNetworkInfo->s8rssi) * 100), + pstrNetworkInfo->u16CapInfo, pstrNetworkInfo->u16BeaconPeriod); + + if (pstrNetworkInfo->bNewNetwork == true) { + if (priv->u32RcvdChCount < MAX_NUM_SCANNED_NETWORKS) { /* TODO: mostafa: to be replaced by */ + /* max_scan_ssids */ + PRINT_D(CFG80211_DBG, "Network %s found\n", pstrNetworkInfo->au8ssid); + + + priv->u32RcvdChCount++; + + + + if (pJoinParams == NULL) { + PRINT_INFO(CORECONFIG_DBG, ">> Something really bad happened\n"); + } + add_network_to_shadow(pstrNetworkInfo, priv, pJoinParams); + + /*P2P peers are sent to WPA supplicant and added to shadow table*/ + + if (!(WILC_memcmp("DIRECT-", pstrNetworkInfo->au8ssid, 7))) { + bss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, pstrNetworkInfo->au8bssid, pstrNetworkInfo->u64Tsf, pstrNetworkInfo->u16CapInfo, + pstrNetworkInfo->u16BeaconPeriod, (const u8 *)pstrNetworkInfo->pu8IEs, + (size_t)pstrNetworkInfo->u16IEsLen, (((s32)pstrNetworkInfo->s8rssi) * 100), GFP_KERNEL); + cfg80211_put_bss(wiphy, bss); + } + + + } else { + PRINT_ER("Discovered networks exceeded the max limit\n"); + } + } else { + u32 i; + /* So this network is discovered before, we'll just update its RSSI */ + for (i = 0; i < priv->u32RcvdChCount; i++) { + if (WILC_memcmp(astrLastScannedNtwrksShadow[i].au8bssid, pstrNetworkInfo->au8bssid, 6) == 0) { + PRINT_D(CFG80211_DBG, "Update RSSI of %s \n", astrLastScannedNtwrksShadow[i].au8ssid); + + astrLastScannedNtwrksShadow[i].s8rssi = pstrNetworkInfo->s8rssi; + astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan = jiffies; + break; + } + } + } + } + } else if (enuScanEvent == SCAN_EVENT_DONE) { + PRINT_D(CFG80211_DBG, "Scan Done[%p] \n", priv->dev); + PRINT_D(CFG80211_DBG, "Refreshing Scan ... \n"); + refresh_scan(priv, 1, false); + + if (priv->u32RcvdChCount > 0) { + PRINT_D(CFG80211_DBG, "%d Network(s) found \n", priv->u32RcvdChCount); + } else { + PRINT_D(CFG80211_DBG, "No networks found \n"); + } + + down(&(priv->hSemScanReq)); + + if (priv->pstrScanReq != NULL) { + cfg80211_scan_done(priv->pstrScanReq, false); + priv->u32RcvdChCount = 0; + priv->bCfgScanning = false; + priv->pstrScanReq = NULL; + } + up(&(priv->hSemScanReq)); + + } + /*Aborting any scan operation during mac close*/ + else if (enuScanEvent == SCAN_EVENT_ABORTED) { + down(&(priv->hSemScanReq)); + + PRINT_D(CFG80211_DBG, "Scan Aborted \n"); + if (priv->pstrScanReq != NULL) { + + update_scan_time(priv); + refresh_scan(priv, 1, false); + + cfg80211_scan_done(priv->pstrScanReq, false); + priv->bCfgScanning = false; + priv->pstrScanReq = NULL; + } + up(&(priv->hSemScanReq)); + } + } + + + WILC_CATCH(s32Error) + { + } +} + + +/** + * @brief WILC_WFI_Set_PMKSA + * @details Check if pmksa is cached and set it. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_Set_PMKSA(u8 *bssid, struct WILC_WFI_priv *priv) +{ + u32 i; + s32 s32Error = WILC_SUCCESS; + + + for (i = 0; i < priv->pmkid_list.numpmkid; i++) { + + if (!WILC_memcmp(bssid, priv->pmkid_list.pmkidlist[i].bssid, + ETH_ALEN)) { + PRINT_D(CFG80211_DBG, "PMKID successful comparison"); + + /*If bssid is found, set the values*/ + s32Error = host_int_set_pmkid_info(priv->hWILCWFIDrv, &priv->pmkid_list); + + if (s32Error != WILC_SUCCESS) + PRINT_ER("Error in pmkid\n"); + + break; + } + } + + return s32Error; + + +} +int linux_wlan_set_bssid(struct net_device *wilc_netdev, uint8_t *pBSSID); + + +/** + * @brief CfgConnectResult + * @details + * @param[in] tenuConnDisconnEvent enuConnDisconnEvent: Type of connection response either + * connection response or disconnection notification. + * tstrConnectInfo* pstrConnectInfo: COnnection information. + * u8 u8MacStatus: Mac Status from firmware + * tstrDisconnectNotifInfo* pstrDisconnectNotifInfo: Disconnection Notification + * void* pUserVoid: Private data associated with wireless interface + * @return NONE + * @author mabubakr + * @date 01 MAR 2012 + * @version 1.0 + */ +int connecting; + +static void CfgConnectResult(tenuConnDisconnEvent enuConnDisconnEvent, + tstrConnectInfo *pstrConnectInfo, + u8 u8MacStatus, + tstrDisconnectNotifInfo *pstrDisconnectNotifInfo, + void *pUserVoid) +{ + struct WILC_WFI_priv *priv; + struct net_device *dev; + #ifdef WILC_P2P + tstrWILC_WFIDrv *pstrWFIDrv; + #endif + u8 NullBssid[ETH_ALEN] = {0}; + connecting = 0; + + priv = (struct WILC_WFI_priv *)pUserVoid; + dev = priv->dev; + #ifdef WILC_P2P + pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; + #endif + + if (enuConnDisconnEvent == CONN_DISCONN_EVENT_CONN_RESP) { + /*Initialization*/ + u16 u16ConnectStatus = WLAN_STATUS_SUCCESS; + + u16ConnectStatus = pstrConnectInfo->u16ConnectStatus; + + PRINT_D(CFG80211_DBG, " Connection response received = %d\n", u8MacStatus); + + if ((u8MacStatus == MAC_DISCONNECTED) && + (pstrConnectInfo->u16ConnectStatus == SUCCESSFUL_STATUSCODE)) { + /* The case here is that our station was waiting for association response frame and has just received it containing status code + * = SUCCESSFUL_STATUSCODE, while mac status is MAC_DISCONNECTED (which means something wrong happened) */ + u16ConnectStatus = WLAN_STATUS_UNSPECIFIED_FAILURE; + linux_wlan_set_bssid(priv->dev, NullBssid); + WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + + /*BugID_5457*/ + /*Invalidate u8WLANChannel value on wlan0 disconnect*/ + #ifdef WILC_P2P + if (!pstrWFIDrv->u8P2PConnect) + u8WLANChannel = INVALID_CHANNEL; + #endif + + PRINT_ER("Unspecified failure: Connection status %d : MAC status = %d \n", u16ConnectStatus, u8MacStatus); + } + + if (u16ConnectStatus == WLAN_STATUS_SUCCESS) { + bool bNeedScanRefresh = false; + u32 i; + + PRINT_INFO(CFG80211_DBG, "Connection Successful:: BSSID: %x%x%x%x%x%x\n", pstrConnectInfo->au8bssid[0], + pstrConnectInfo->au8bssid[1], pstrConnectInfo->au8bssid[2], pstrConnectInfo->au8bssid[3], pstrConnectInfo->au8bssid[4], pstrConnectInfo->au8bssid[5]); + WILC_memcpy(priv->au8AssociatedBss, pstrConnectInfo->au8bssid, ETH_ALEN); + + /* BugID_4209: if this network has expired in the scan results in the above nl80211 layer, refresh them here by calling + * cfg80211_inform_bss() with the last Scan results before calling cfg80211_connect_result() to avoid + * Linux kernel warning generated at the nl80211 layer */ + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + if (WILC_memcmp(astrLastScannedNtwrksShadow[i].au8bssid, + pstrConnectInfo->au8bssid, ETH_ALEN) == 0) { + unsigned long now = jiffies; + + if (time_after(now, + astrLastScannedNtwrksShadow[i].u32TimeRcvdInScanCached + (unsigned long)(nl80211_SCAN_RESULT_EXPIRE - (1 * HZ)))) { + bNeedScanRefresh = true; + } + + break; + } + } + + if (bNeedScanRefresh) { + /*BugID_5418*/ + /*Also, refrsh DIRECT- results if */ + refresh_scan(priv, 1, true); + + } + + } + + + PRINT_D(CFG80211_DBG, "Association request info elements length = %zu\n", pstrConnectInfo->ReqIEsLen); + + PRINT_D(CFG80211_DBG, "Association response info elements length = %d\n", pstrConnectInfo->u16RespIEsLen); + + cfg80211_connect_result(dev, pstrConnectInfo->au8bssid, + pstrConnectInfo->pu8ReqIEs, pstrConnectInfo->ReqIEsLen, + pstrConnectInfo->pu8RespIEs, pstrConnectInfo->u16RespIEsLen, + u16ConnectStatus, GFP_KERNEL); /* TODO: mostafa: u16ConnectStatus to */ + /* be replaced by pstrConnectInfo->u16ConnectStatus */ + } else if (enuConnDisconnEvent == CONN_DISCONN_EVENT_DISCONN_NOTIF) { + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + g_obtainingIP = false; + #endif + PRINT_ER("Received MAC_DISCONNECTED from firmware with reason %d on dev [%p]\n", + pstrDisconnectNotifInfo->u16reason, priv->dev); + u8P2Plocalrandom = 0x01; + u8P2Precvrandom = 0x00; + bWilc_ie = false; + WILC_memset(priv->au8AssociatedBss, 0, ETH_ALEN); + linux_wlan_set_bssid(priv->dev, NullBssid); + WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + + /*BugID_5457*/ + /*Invalidate u8WLANChannel value on wlan0 disconnect*/ + #ifdef WILC_P2P + if (!pstrWFIDrv->u8P2PConnect) + u8WLANChannel = INVALID_CHANNEL; + #endif + /*BugID_5315*/ + /*Incase "P2P CLIENT Connected" send deauthentication reason by 3 to force the WPA_SUPPLICANT to directly change + * virtual interface to station*/ + if ((pstrWFIDrv->IFC_UP) && (dev == g_linux_wlan->strInterfaceInfo[1].wilc_netdev)) { + pstrDisconnectNotifInfo->u16reason = 3; + } + /*BugID_5315*/ + /*Incase "P2P CLIENT during connection(not connected)" send deauthentication reason by 1 to force the WPA_SUPPLICANT + * to scan again and retry the connection*/ + else if ((!pstrWFIDrv->IFC_UP) && (dev == g_linux_wlan->strInterfaceInfo[1].wilc_netdev)) { + pstrDisconnectNotifInfo->u16reason = 1; + } + cfg80211_disconnected(dev, pstrDisconnectNotifInfo->u16reason, pstrDisconnectNotifInfo->ie, + pstrDisconnectNotifInfo->ie_len, GFP_KERNEL); + + } + +} + + +/** + * @brief WILC_WFI_CfgSetChannel + * @details Set channel for a given wireless interface. Some devices + * may support multi-channel operation (by channel hopping) so cfg80211 + * doesn't verify much. Note, however, that the passed netdev may be + * %NULL as well if the user requested changing the channel for the + * device itself, or for a monitor interface. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_CfgSetChannel(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + + u32 channelnum = 0; + struct WILC_WFI_priv *priv; + s32 s32Error = WILC_SUCCESS; + priv = wiphy_priv(wiphy); + + channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq); + PRINT_D(CFG80211_DBG, "Setting channel %d with frequency %d\n", channelnum, chandef->chan->center_freq); + + u8CurrChannel = channelnum; + s32Error = host_int_set_mac_chnl_num(priv->hWILCWFIDrv, channelnum); + + if (s32Error != WILC_SUCCESS) + PRINT_ER("Error in setting channel %d\n", channelnum); + + return s32Error; +} + +/** + * @brief WILC_WFI_CfgScan + * @details Request to do a scan. If returning zero, the scan request is given + * the driver, and will be valid until passed to cfg80211_scan_done(). + * For scan results, call cfg80211_inform_bss(); you can call this outside + * the scan/scan_done bracket too. + * @param[in] + * @return int : Return 0 on Success + * @author mabubakr + * @date 01 MAR 2012 + * @version 1.0 + */ + +/* + * kernel version 3.8.8 supported + * tony, sswd, WILC-KR, 2013-10-29 + */ +static int WILC_WFI_CfgScan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +{ + struct WILC_WFI_priv *priv; + u32 i; + s32 s32Error = WILC_SUCCESS; + u8 au8ScanChanList[MAX_NUM_SCANNED_NETWORKS]; + tstrHiddenNetwork strHiddenNetwork; + + priv = wiphy_priv(wiphy); + + priv->pstrScanReq = request; + + priv->u32RcvdChCount = 0; + + host_int_set_wfi_drv_handler((u32)priv->hWILCWFIDrv); + + + reset_shadow_found(priv); + + priv->bCfgScanning = true; + if (request->n_channels <= MAX_NUM_SCANNED_NETWORKS) { /* TODO: mostafa: to be replaced by */ + /* max_scan_ssids */ + for (i = 0; i < request->n_channels; i++) { + au8ScanChanList[i] = (u8)ieee80211_frequency_to_channel(request->channels[i]->center_freq); + PRINT_INFO(CFG80211_DBG, "ScanChannel List[%d] = %d,", i, au8ScanChanList[i]); + } + + PRINT_D(CFG80211_DBG, "Requested num of scan channel %d\n", request->n_channels); + PRINT_D(CFG80211_DBG, "Scan Request IE len = %zu\n", request->ie_len); + + PRINT_D(CFG80211_DBG, "Number of SSIDs %d\n", request->n_ssids); + + if (request->n_ssids >= 1) { + + + strHiddenNetwork.pstrHiddenNetworkInfo = WILC_MALLOC(request->n_ssids * sizeof(tstrHiddenNetwork)); + strHiddenNetwork.u8ssidnum = request->n_ssids; + + + /*BugID_4156*/ + for (i = 0; i < request->n_ssids; i++) { + + if (request->ssids[i].ssid != NULL && request->ssids[i].ssid_len != 0) { + strHiddenNetwork.pstrHiddenNetworkInfo[i].pu8ssid = WILC_MALLOC(request->ssids[i].ssid_len); + WILC_memcpy(strHiddenNetwork.pstrHiddenNetworkInfo[i].pu8ssid, request->ssids[i].ssid, request->ssids[i].ssid_len); + strHiddenNetwork.pstrHiddenNetworkInfo[i].u8ssidlen = request->ssids[i].ssid_len; + } else { + PRINT_D(CFG80211_DBG, "Received one NULL SSID \n"); + strHiddenNetwork.u8ssidnum -= 1; + } + } + PRINT_D(CFG80211_DBG, "Trigger Scan Request \n"); + s32Error = host_int_scan(priv->hWILCWFIDrv, USER_SCAN, ACTIVE_SCAN, + au8ScanChanList, request->n_channels, + (const u8 *)request->ie, request->ie_len, + CfgScanResult, (void *)priv, &strHiddenNetwork); + } else { + PRINT_D(CFG80211_DBG, "Trigger Scan Request \n"); + s32Error = host_int_scan(priv->hWILCWFIDrv, USER_SCAN, ACTIVE_SCAN, + au8ScanChanList, request->n_channels, + (const u8 *)request->ie, request->ie_len, + CfgScanResult, (void *)priv, NULL); + } + + } else { + PRINT_ER("Requested num of scanned channels is greater than the max, supported" + " channels \n"); + } + + if (s32Error != WILC_SUCCESS) { + s32Error = -EBUSY; + PRINT_WRN(CFG80211_DBG, "Device is busy: Error(%d)\n", s32Error); + } + + return s32Error; +} + +/** + * @brief WILC_WFI_CfgConnect + * @details Connect to the ESS with the specified parameters. When connected, + * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. + * If the connection fails for some reason, call cfg80211_connect_result() + * with the status from the AP. + * @param[in] + * @return int : Return 0 on Success + * @author mabubakr + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_CfgConnect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + s32 s32Error = WILC_SUCCESS; + u32 i; + u8 u8security = NO_ENCRYPT; + AUTHTYPE_T tenuAuth_type = ANY; + char *pcgroup_encrypt_val = NULL; + char *pccipher_group = NULL; + char *pcwpa_version = NULL; + + struct WILC_WFI_priv *priv; + tstrWILC_WFIDrv *pstrWFIDrv; + tstrNetworkInfo *pstrNetworkInfo = NULL; + + + connecting = 1; + priv = wiphy_priv(wiphy); + pstrWFIDrv = (tstrWILC_WFIDrv *)(priv->hWILCWFIDrv); + + host_int_set_wfi_drv_handler((u32)priv->hWILCWFIDrv); + + PRINT_D(CFG80211_DBG, "Connecting to SSID [%s] on netdev [%p] host if [%p]\n", sme->ssid, dev, priv->hWILCWFIDrv); + #ifdef WILC_P2P + if (!(WILC_strncmp(sme->ssid, "DIRECT-", 7))) { + PRINT_D(CFG80211_DBG, "Connected to Direct network,OBSS disabled\n"); + pstrWFIDrv->u8P2PConnect = 1; + } else + pstrWFIDrv->u8P2PConnect = 0; + #endif + PRINT_INFO(CFG80211_DBG, "Required SSID = %s\n , AuthType = %d \n", sme->ssid, sme->auth_type); + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + if ((sme->ssid_len == astrLastScannedNtwrksShadow[i].u8SsidLen) && + WILC_memcmp(astrLastScannedNtwrksShadow[i].au8ssid, + sme->ssid, + sme->ssid_len) == 0) { + PRINT_INFO(CFG80211_DBG, "Network with required SSID is found %s\n", sme->ssid); + if (sme->bssid == NULL) { + /* BSSID is not passed from the user, so decision of matching + * is done by SSID only */ + PRINT_INFO(CFG80211_DBG, "BSSID is not passed from the user\n"); + break; + } else { + /* BSSID is also passed from the user, so decision of matching + * should consider also this passed BSSID */ + if (WILC_memcmp(astrLastScannedNtwrksShadow[i].au8bssid, + sme->bssid, + ETH_ALEN) == 0) { + PRINT_INFO(CFG80211_DBG, "BSSID is passed from the user and matched\n"); + break; + } + } + } + } + + if (i < u32LastScannedNtwrksCountShadow) { + PRINT_D(CFG80211_DBG, "Required bss is in scan results\n"); + + pstrNetworkInfo = &(astrLastScannedNtwrksShadow[i]); + + PRINT_INFO(CFG80211_DBG, "network BSSID to be associated: %x%x%x%x%x%x\n", + pstrNetworkInfo->au8bssid[0], pstrNetworkInfo->au8bssid[1], + pstrNetworkInfo->au8bssid[2], pstrNetworkInfo->au8bssid[3], + pstrNetworkInfo->au8bssid[4], pstrNetworkInfo->au8bssid[5]); + } else { + s32Error = -ENOENT; + if (u32LastScannedNtwrksCountShadow == 0) + PRINT_D(CFG80211_DBG, "No Scan results yet\n"); + else + PRINT_D(CFG80211_DBG, "Required bss not in scan results: Error(%d)\n", s32Error); + + goto done; + } + + priv->WILC_WFI_wep_default = 0; + WILC_memset(priv->WILC_WFI_wep_key, 0, sizeof(priv->WILC_WFI_wep_key)); + WILC_memset(priv->WILC_WFI_wep_key_len, 0, sizeof(priv->WILC_WFI_wep_key_len)); + + PRINT_INFO(CFG80211_DBG, "sme->crypto.wpa_versions=%x\n", sme->crypto.wpa_versions); + PRINT_INFO(CFG80211_DBG, "sme->crypto.cipher_group=%x\n", sme->crypto.cipher_group); + + PRINT_INFO(CFG80211_DBG, "sme->crypto.n_ciphers_pairwise=%d\n", sme->crypto.n_ciphers_pairwise); + + if (INFO) { + for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) + PRINT_D(CORECONFIG_DBG, "sme->crypto.ciphers_pairwise[%d]=%x\n", i, sme->crypto.ciphers_pairwise[i]); + } + + if (sme->crypto.cipher_group != NO_ENCRYPT) { + /* To determine the u8security value, first we check the group cipher suite then {in case of WPA or WPA2} + * we will add to it the pairwise cipher suite(s) */ + pcwpa_version = "Default"; + PRINT_D(CORECONFIG_DBG, ">> sme->crypto.wpa_versions: %x\n", sme->crypto.wpa_versions); + if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) { + u8security = ENCRYPT_ENABLED | WEP; + pcgroup_encrypt_val = "WEP40"; + pccipher_group = "WLAN_CIPHER_SUITE_WEP40"; + PRINT_INFO(CFG80211_DBG, "WEP Default Key Idx = %d\n", sme->key_idx); + + if (INFO) { + for (i = 0; i < sme->key_len; i++) + PRINT_D(CORECONFIG_DBG, "WEP Key Value[%d] = %d\n", i, sme->key[i]); + } + priv->WILC_WFI_wep_default = sme->key_idx; + priv->WILC_WFI_wep_key_len[sme->key_idx] = sme->key_len; + WILC_memcpy(priv->WILC_WFI_wep_key[sme->key_idx], sme->key, sme->key_len); + + /*BugID_5137*/ + g_key_wep_params.key_len = sme->key_len; + g_key_wep_params.key = WILC_MALLOC(sme->key_len); + memcpy(g_key_wep_params.key, sme->key, sme->key_len); + g_key_wep_params.key_idx = sme->key_idx; + g_wep_keys_saved = true; + + host_int_set_WEPDefaultKeyID(priv->hWILCWFIDrv, sme->key_idx); + host_int_add_wep_key_bss_sta(priv->hWILCWFIDrv, sme->key, sme->key_len, sme->key_idx); + } else if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104) { + u8security = ENCRYPT_ENABLED | WEP | WEP_EXTENDED; + pcgroup_encrypt_val = "WEP104"; + pccipher_group = "WLAN_CIPHER_SUITE_WEP104"; + + priv->WILC_WFI_wep_default = sme->key_idx; + priv->WILC_WFI_wep_key_len[sme->key_idx] = sme->key_len; + WILC_memcpy(priv->WILC_WFI_wep_key[sme->key_idx], sme->key, sme->key_len); + + /*BugID_5137*/ + g_key_wep_params.key_len = sme->key_len; + g_key_wep_params.key = WILC_MALLOC(sme->key_len); + memcpy(g_key_wep_params.key, sme->key, sme->key_len); + g_key_wep_params.key_idx = sme->key_idx; + g_wep_keys_saved = true; + + host_int_set_WEPDefaultKeyID(priv->hWILCWFIDrv, sme->key_idx); + host_int_add_wep_key_bss_sta(priv->hWILCWFIDrv, sme->key, sme->key_len, sme->key_idx); + } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) { + if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_TKIP) { + u8security = ENCRYPT_ENABLED | WPA2 | TKIP; + pcgroup_encrypt_val = "WPA2_TKIP"; + pccipher_group = "TKIP"; + } else { /* TODO: mostafa: here we assume that any other encryption type is AES */ + /* tenuSecurity_t = WPA2_AES; */ + u8security = ENCRYPT_ENABLED | WPA2 | AES; + pcgroup_encrypt_val = "WPA2_AES"; + pccipher_group = "AES"; + } + pcwpa_version = "WPA_VERSION_2"; + } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) { + if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_TKIP) { + u8security = ENCRYPT_ENABLED | WPA | TKIP; + pcgroup_encrypt_val = "WPA_TKIP"; + pccipher_group = "TKIP"; + } else { /* TODO: mostafa: here we assume that any other encryption type is AES */ + /* tenuSecurity_t = WPA_AES; */ + u8security = ENCRYPT_ENABLED | WPA | AES; + pcgroup_encrypt_val = "WPA_AES"; + pccipher_group = "AES"; + + } + pcwpa_version = "WPA_VERSION_1"; + + } else { + s32Error = -ENOTSUPP; + PRINT_ER("Not supported cipher: Error(%d)\n", s32Error); + + goto done; + } + + } + + /* After we set the u8security value from checking the group cipher suite, {in case of WPA or WPA2} we will + * add to it the pairwise cipher suite(s) */ + if ((sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) + || (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) { + for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) { + if (sme->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP) { + u8security = u8security | TKIP; + } else { /* TODO: mostafa: here we assume that any other encryption type is AES */ + u8security = u8security | AES; + } + } + } + + PRINT_D(CFG80211_DBG, "Adding key with cipher group = %x\n", sme->crypto.cipher_group); + + PRINT_D(CFG80211_DBG, "Authentication Type = %d\n", sme->auth_type); + switch (sme->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + PRINT_D(CFG80211_DBG, "In OPEN SYSTEM\n"); + tenuAuth_type = OPEN_SYSTEM; + break; + + case NL80211_AUTHTYPE_SHARED_KEY: + tenuAuth_type = SHARED_KEY; + PRINT_D(CFG80211_DBG, "In SHARED KEY\n"); + break; + + default: + PRINT_D(CFG80211_DBG, "Automatic Authentation type = %d\n", sme->auth_type); + } + + + /* ai: key_mgmt: enterprise case */ + if (sme->crypto.n_akm_suites) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + tenuAuth_type = IEEE8021; + break; + + default: + break; + } + } + + + PRINT_INFO(CFG80211_DBG, "Required Channel = %d\n", pstrNetworkInfo->u8channel); + + PRINT_INFO(CFG80211_DBG, "Group encryption value = %s\n Cipher Group = %s\n WPA version = %s\n", + pcgroup_encrypt_val, pccipher_group, pcwpa_version); + + /*BugID_5442*/ + u8CurrChannel = pstrNetworkInfo->u8channel; + + if (!pstrWFIDrv->u8P2PConnect) { + u8WLANChannel = pstrNetworkInfo->u8channel; + } + + linux_wlan_set_bssid(dev, pstrNetworkInfo->au8bssid); + + s32Error = host_int_set_join_req(priv->hWILCWFIDrv, pstrNetworkInfo->au8bssid, sme->ssid, + sme->ssid_len, sme->ie, sme->ie_len, + CfgConnectResult, (void *)priv, u8security, + tenuAuth_type, pstrNetworkInfo->u8channel, + pstrNetworkInfo->pJoinParams); + if (s32Error != WILC_SUCCESS) { + PRINT_ER("host_int_set_join_req(): Error(%d) \n", s32Error); + s32Error = -ENOENT; + goto done; + } + +done: + + return s32Error; +} + + +/** + * @brief WILC_WFI_disconnect + * @details Disconnect from the BSS/ESS. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) +{ + s32 s32Error = WILC_SUCCESS; + struct WILC_WFI_priv *priv; + #ifdef WILC_P2P + tstrWILC_WFIDrv *pstrWFIDrv; + #endif + uint8_t NullBssid[ETH_ALEN] = {0}; + connecting = 0; + priv = wiphy_priv(wiphy); + + /*BugID_5457*/ + /*Invalidate u8WLANChannel value on wlan0 disconnect*/ + #ifdef WILC_P2P + pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; + if (!pstrWFIDrv->u8P2PConnect) + u8WLANChannel = INVALID_CHANNEL; + #endif + linux_wlan_set_bssid(priv->dev, NullBssid); + + PRINT_D(CFG80211_DBG, "Disconnecting with reason code(%d)\n", reason_code); + + u8P2Plocalrandom = 0x01; + u8P2Precvrandom = 0x00; + bWilc_ie = false; + #ifdef WILC_P2P + pstrWFIDrv->u64P2p_MgmtTimeout = 0; + #endif + + s32Error = host_int_disconnect(priv->hWILCWFIDrv, reason_code); + if (s32Error != WILC_SUCCESS) { + PRINT_ER("Error in disconnecting: Error(%d)\n", s32Error); + s32Error = -EINVAL; + } + + return s32Error; +} + +/** + * @brief WILC_WFI_add_key + * @details Add a key with the given parameters. @mac_addr will be %NULL + * when adding a group key. + * @param[in] key : key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, 8-byte Rx Mic Key + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool pairwise, + const u8 *mac_addr, struct key_params *params) + +{ + s32 s32Error = WILC_SUCCESS, KeyLen = params->key_len; + u32 i; + struct WILC_WFI_priv *priv; + const u8 *pu8RxMic = NULL; + const u8 *pu8TxMic = NULL; + u8 u8mode = NO_ENCRYPT; + #ifdef WILC_AP_EXTERNAL_MLME + u8 u8gmode = NO_ENCRYPT; + u8 u8pmode = NO_ENCRYPT; + AUTHTYPE_T tenuAuth_type = ANY; + #endif + + priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Adding key with cipher suite = %x\n", params->cipher); + + /*BugID_5137*/ + PRINT_D(CFG80211_DBG, "%p %p %d\n", wiphy, netdev, key_index); + + PRINT_D(CFG80211_DBG, "key %x %x %x\n", params->key[0], + params->key[1], + params->key[2]); + + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + #ifdef WILC_AP_EXTERNAL_MLME + if (priv->wdev->iftype == NL80211_IFTYPE_AP) { + + priv->WILC_WFI_wep_default = key_index; + priv->WILC_WFI_wep_key_len[key_index] = params->key_len; + WILC_memcpy(priv->WILC_WFI_wep_key[key_index], params->key, params->key_len); + + PRINT_D(CFG80211_DBG, "Adding AP WEP Default key Idx = %d\n", key_index); + PRINT_D(CFG80211_DBG, "Adding AP WEP Key len= %d\n", params->key_len); + + for (i = 0; i < params->key_len; i++) + PRINT_D(CFG80211_DBG, "WEP AP key val[%d] = %x\n", i, params->key[i]); + + tenuAuth_type = OPEN_SYSTEM; + + if (params->cipher == WLAN_CIPHER_SUITE_WEP40) + u8mode = ENCRYPT_ENABLED | WEP; + else + u8mode = ENCRYPT_ENABLED | WEP | WEP_EXTENDED; + + host_int_add_wep_key_bss_ap(priv->hWILCWFIDrv, params->key, params->key_len, key_index, u8mode, tenuAuth_type); + break; + } + #endif + if (WILC_memcmp(params->key, priv->WILC_WFI_wep_key[key_index], params->key_len)) { + priv->WILC_WFI_wep_default = key_index; + priv->WILC_WFI_wep_key_len[key_index] = params->key_len; + WILC_memcpy(priv->WILC_WFI_wep_key[key_index], params->key, params->key_len); + + PRINT_D(CFG80211_DBG, "Adding WEP Default key Idx = %d\n", key_index); + PRINT_D(CFG80211_DBG, "Adding WEP Key length = %d\n", params->key_len); + if (INFO) { + for (i = 0; i < params->key_len; i++) + PRINT_INFO(CFG80211_DBG, "WEP key value[%d] = %d\n", i, params->key[i]); + } + host_int_add_wep_key_bss_sta(priv->hWILCWFIDrv, params->key, params->key_len, key_index); + } + + break; + + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + #ifdef WILC_AP_EXTERNAL_MLME + if (priv->wdev->iftype == NL80211_IFTYPE_AP || priv->wdev->iftype == NL80211_IFTYPE_P2P_GO) { + + if (priv->wilc_gtk[key_index] == NULL) { + priv->wilc_gtk[key_index] = (struct wilc_wfi_key *)WILC_MALLOC(sizeof(struct wilc_wfi_key)); + priv->wilc_gtk[key_index]->key = NULL; + priv->wilc_gtk[key_index]->seq = NULL; + + } + if (priv->wilc_ptk[key_index] == NULL) { + priv->wilc_ptk[key_index] = (struct wilc_wfi_key *)WILC_MALLOC(sizeof(struct wilc_wfi_key)); + priv->wilc_ptk[key_index]->key = NULL; + priv->wilc_ptk[key_index]->seq = NULL; + } + + + + if (!pairwise) + { + if (params->cipher == WLAN_CIPHER_SUITE_TKIP) + u8gmode = ENCRYPT_ENABLED | WPA | TKIP; + else + u8gmode = ENCRYPT_ENABLED | WPA2 | AES; + + priv->wilc_groupkey = u8gmode; + + if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) { + + pu8TxMic = params->key + 24; + pu8RxMic = params->key + 16; + KeyLen = params->key_len - 16; + } + /* if there has been previous allocation for the same index through its key, free that memory and allocate again*/ + if (priv->wilc_gtk[key_index]->key) + WILC_FREE(priv->wilc_gtk[key_index]->key); + + priv->wilc_gtk[key_index]->key = (u8 *)WILC_MALLOC(params->key_len); + WILC_memcpy(priv->wilc_gtk[key_index]->key, params->key, params->key_len); + + /* if there has been previous allocation for the same index through its seq, free that memory and allocate again*/ + if (priv->wilc_gtk[key_index]->seq) + WILC_FREE(priv->wilc_gtk[key_index]->seq); + + if ((params->seq_len) > 0) { + priv->wilc_gtk[key_index]->seq = (u8 *)WILC_MALLOC(params->seq_len); + WILC_memcpy(priv->wilc_gtk[key_index]->seq, params->seq, params->seq_len); + } + + priv->wilc_gtk[key_index]->cipher = params->cipher; + priv->wilc_gtk[key_index]->key_len = params->key_len; + priv->wilc_gtk[key_index]->seq_len = params->seq_len; + + if (INFO) { + for (i = 0; i < params->key_len; i++) + PRINT_INFO(CFG80211_DBG, "Adding group key value[%d] = %x\n", i, params->key[i]); + for (i = 0; i < params->seq_len; i++) + PRINT_INFO(CFG80211_DBG, "Adding group seq value[%d] = %x\n", i, params->seq[i]); + } + + + host_int_add_rx_gtk(priv->hWILCWFIDrv, params->key, KeyLen, + key_index, params->seq_len, params->seq, pu8RxMic, pu8TxMic, AP_MODE, u8gmode); + + } else { + PRINT_INFO(CFG80211_DBG, "STA Address: %x%x%x%x%x\n", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4]); + + if (params->cipher == WLAN_CIPHER_SUITE_TKIP) + u8pmode = ENCRYPT_ENABLED | WPA | TKIP; + else + u8pmode = priv->wilc_groupkey | AES; + + + if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) { + + pu8TxMic = params->key + 24; + pu8RxMic = params->key + 16; + KeyLen = params->key_len - 16; + } + + if (priv->wilc_ptk[key_index]->key) + WILC_FREE(priv->wilc_ptk[key_index]->key); + + priv->wilc_ptk[key_index]->key = (u8 *)WILC_MALLOC(params->key_len); + + if (priv->wilc_ptk[key_index]->seq) + WILC_FREE(priv->wilc_ptk[key_index]->seq); + + if ((params->seq_len) > 0) + priv->wilc_ptk[key_index]->seq = (u8 *)WILC_MALLOC(params->seq_len); + + if (INFO) { + for (i = 0; i < params->key_len; i++) + PRINT_INFO(CFG80211_DBG, "Adding pairwise key value[%d] = %x\n", i, params->key[i]); + + for (i = 0; i < params->seq_len; i++) + PRINT_INFO(CFG80211_DBG, "Adding group seq value[%d] = %x\n", i, params->seq[i]); + } + + WILC_memcpy(priv->wilc_ptk[key_index]->key, params->key, params->key_len); + + if ((params->seq_len) > 0) + WILC_memcpy(priv->wilc_ptk[key_index]->seq, params->seq, params->seq_len); + + priv->wilc_ptk[key_index]->cipher = params->cipher; + priv->wilc_ptk[key_index]->key_len = params->key_len; + priv->wilc_ptk[key_index]->seq_len = params->seq_len; + + host_int_add_ptk(priv->hWILCWFIDrv, params->key, KeyLen, mac_addr, + pu8RxMic, pu8TxMic, AP_MODE, u8pmode, key_index); + } + break; + } + #endif + + { + u8mode = 0; + if (!pairwise) + { + if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) { + /* swap the tx mic by rx mic */ + pu8RxMic = params->key + 24; + pu8TxMic = params->key + 16; + KeyLen = params->key_len - 16; + } + + /*BugID_5137*/ + /*save keys only on interface 0 (wifi interface)*/ + if (!g_gtk_keys_saved && netdev == g_linux_wlan->strInterfaceInfo[0].wilc_netdev) { + g_add_gtk_key_params.key_idx = key_index; + g_add_gtk_key_params.pairwise = pairwise; + if (!mac_addr) { + g_add_gtk_key_params.mac_addr = NULL; + } else { + g_add_gtk_key_params.mac_addr = WILC_MALLOC(ETH_ALEN); + memcpy(g_add_gtk_key_params.mac_addr, mac_addr, ETH_ALEN); + } + g_key_gtk_params.key_len = params->key_len; + g_key_gtk_params.seq_len = params->seq_len; + g_key_gtk_params.key = WILC_MALLOC(params->key_len); + memcpy(g_key_gtk_params.key, params->key, params->key_len); + if (params->seq_len > 0) { + g_key_gtk_params.seq = WILC_MALLOC(params->seq_len); + memcpy(g_key_gtk_params.seq, params->seq, params->seq_len); + } + g_key_gtk_params.cipher = params->cipher; + + PRINT_D(CFG80211_DBG, "key %x %x %x\n", g_key_gtk_params.key[0], + g_key_gtk_params.key[1], + g_key_gtk_params.key[2]); + g_gtk_keys_saved = true; + } + + host_int_add_rx_gtk(priv->hWILCWFIDrv, params->key, KeyLen, + key_index, params->seq_len, params->seq, pu8RxMic, pu8TxMic, STATION_MODE, u8mode); + } else { + if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) { + /* swap the tx mic by rx mic */ + pu8RxMic = params->key + 24; + pu8TxMic = params->key + 16; + KeyLen = params->key_len - 16; + } + + /*BugID_5137*/ + /*save keys only on interface 0 (wifi interface)*/ + if (!g_ptk_keys_saved && netdev == g_linux_wlan->strInterfaceInfo[0].wilc_netdev) { + g_add_ptk_key_params.key_idx = key_index; + g_add_ptk_key_params.pairwise = pairwise; + if (!mac_addr) { + g_add_ptk_key_params.mac_addr = NULL; + } else { + g_add_ptk_key_params.mac_addr = WILC_MALLOC(ETH_ALEN); + memcpy(g_add_ptk_key_params.mac_addr, mac_addr, ETH_ALEN); + } + g_key_ptk_params.key_len = params->key_len; + g_key_ptk_params.seq_len = params->seq_len; + g_key_ptk_params.key = WILC_MALLOC(params->key_len); + memcpy(g_key_ptk_params.key, params->key, params->key_len); + if (params->seq_len > 0) { + g_key_ptk_params.seq = WILC_MALLOC(params->seq_len); + memcpy(g_key_ptk_params.seq, params->seq, params->seq_len); + } + g_key_ptk_params.cipher = params->cipher; + + PRINT_D(CFG80211_DBG, "key %x %x %x\n", g_key_ptk_params.key[0], + g_key_ptk_params.key[1], + g_key_ptk_params.key[2]); + g_ptk_keys_saved = true; + } + + host_int_add_ptk(priv->hWILCWFIDrv, params->key, KeyLen, mac_addr, + pu8RxMic, pu8TxMic, STATION_MODE, u8mode, key_index); + PRINT_D(CFG80211_DBG, "Adding pairwise key\n"); + if (INFO) { + for (i = 0; i < params->key_len; i++) + PRINT_INFO(CFG80211_DBG, "Adding pairwise key value[%d] = %d\n", i, params->key[i]); + } + } + } + break; + + default: + PRINT_ER("Not supported cipher: Error(%d)\n", s32Error); + s32Error = -ENOTSUPP; + + } + + return s32Error; +} + +/** + * @brief WILC_WFI_del_key + * @details Remove a key given the @mac_addr (%NULL for a group key) + * and @key_index, return -ENOENT if the key doesn't exist. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_del_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, + bool pairwise, + const u8 *mac_addr) +{ + struct WILC_WFI_priv *priv; + s32 s32Error = WILC_SUCCESS; + + priv = wiphy_priv(wiphy); + + /*BugID_5137*/ + /*delete saved keys, if any*/ + if (netdev == g_linux_wlan->strInterfaceInfo[0].wilc_netdev) { + g_ptk_keys_saved = false; + g_gtk_keys_saved = false; + g_wep_keys_saved = false; + + /*Delete saved WEP keys params, if any*/ + if (g_key_wep_params.key != NULL) { + WILC_FREE(g_key_wep_params.key); + g_key_wep_params.key = NULL; + } + + /*freeing memory allocated by "wilc_gtk" and "wilc_ptk" in "WILC_WIFI_ADD_KEY"*/ + + #ifdef WILC_AP_EXTERNAL_MLME + if ((priv->wilc_gtk[key_index]) != NULL) { + + if (priv->wilc_gtk[key_index]->key != NULL) { + + WILC_FREE(priv->wilc_gtk[key_index]->key); + priv->wilc_gtk[key_index]->key = NULL; + } + if (priv->wilc_gtk[key_index]->seq) { + + WILC_FREE(priv->wilc_gtk[key_index]->seq); + priv->wilc_gtk[key_index]->seq = NULL; + } + + WILC_FREE(priv->wilc_gtk[key_index]); + priv->wilc_gtk[key_index] = NULL; + + } + + if ((priv->wilc_ptk[key_index]) != NULL) { + + if (priv->wilc_ptk[key_index]->key) { + + WILC_FREE(priv->wilc_ptk[key_index]->key); + priv->wilc_ptk[key_index]->key = NULL; + } + if (priv->wilc_ptk[key_index]->seq) { + + WILC_FREE(priv->wilc_ptk[key_index]->seq); + priv->wilc_ptk[key_index]->seq = NULL; + } + WILC_FREE(priv->wilc_ptk[key_index]); + priv->wilc_ptk[key_index] = NULL; + } + #endif + + /*Delete saved PTK and GTK keys params, if any*/ + if (g_key_ptk_params.key != NULL) { + WILC_FREE(g_key_ptk_params.key); + g_key_ptk_params.key = NULL; + } + if (g_key_ptk_params.seq != NULL) { + WILC_FREE(g_key_ptk_params.seq); + g_key_ptk_params.seq = NULL; + } + + if (g_key_gtk_params.key != NULL) { + WILC_FREE(g_key_gtk_params.key); + g_key_gtk_params.key = NULL; + } + if (g_key_gtk_params.seq != NULL) { + WILC_FREE(g_key_gtk_params.seq); + g_key_gtk_params.seq = NULL; + } + + /*Reset WILC_CHANGING_VIR_IF register to allow adding futrue keys to CE H/W*/ + Set_machw_change_vir_if(false); + } + + if (key_index >= 0 && key_index <= 3) { + WILC_memset(priv->WILC_WFI_wep_key[key_index], 0, priv->WILC_WFI_wep_key_len[key_index]); + priv->WILC_WFI_wep_key_len[key_index] = 0; + + PRINT_D(CFG80211_DBG, "Removing WEP key with index = %d\n", key_index); + host_int_remove_wep_key(priv->hWILCWFIDrv, key_index); + } else { + PRINT_D(CFG80211_DBG, "Removing all installed keys\n"); + host_int_remove_key(priv->hWILCWFIDrv, mac_addr); + } + + return s32Error; +} + +/** + * @brief WILC_WFI_get_key + * @details Get information about the key with the given parameters. + * @mac_addr will be %NULL when requesting information for a group + * key. All pointers given to the @callback function need not be valid + * after it returns. This function should return an error if it is + * not possible to retrieve the key, -ENOENT if it doesn't exist. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool pairwise, + const u8 *mac_addr, void *cookie, void (*callback)(void *cookie, struct key_params *)) +{ + + s32 s32Error = WILC_SUCCESS; + + struct WILC_WFI_priv *priv; + struct key_params key_params; + u32 i; + priv = wiphy_priv(wiphy); + + + if (!pairwise) + { + PRINT_D(CFG80211_DBG, "Getting group key idx: %x\n", key_index); + + key_params.key = priv->wilc_gtk[key_index]->key; + key_params.cipher = priv->wilc_gtk[key_index]->cipher; + key_params.key_len = priv->wilc_gtk[key_index]->key_len; + key_params.seq = priv->wilc_gtk[key_index]->seq; + key_params.seq_len = priv->wilc_gtk[key_index]->seq_len; + if (INFO) { + for (i = 0; i < key_params.key_len; i++) + PRINT_INFO(CFG80211_DBG, "Retrieved key value %x\n", key_params.key[i]); + } + } else { + PRINT_D(CFG80211_DBG, "Getting pairwise key\n"); + + key_params.key = priv->wilc_ptk[key_index]->key; + key_params.cipher = priv->wilc_ptk[key_index]->cipher; + key_params.key_len = priv->wilc_ptk[key_index]->key_len; + key_params.seq = priv->wilc_ptk[key_index]->seq; + key_params.seq_len = priv->wilc_ptk[key_index]->seq_len; + } + + callback(cookie, &key_params); + + return s32Error; /* priv->wilc_gtk->key_len ?0 : -ENOENT; */ +} + +/** + * @brief WILC_WFI_set_default_key + * @details Set the default management frame key on an interface + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_set_default_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool unicast, bool multicast) +{ + s32 s32Error = WILC_SUCCESS; + struct WILC_WFI_priv *priv; + + + priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Setting default key with idx = %d \n", key_index); + + if (key_index != priv->WILC_WFI_wep_default) { + + host_int_set_WEPDefaultKeyID(priv->hWILCWFIDrv, key_index); + } + + return s32Error; +} + +/** + * @brief WILC_WFI_dump_survey + * @details Get site survey information + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_dump_survey(struct wiphy *wiphy, struct net_device *netdev, + int idx, struct survey_info *info) +{ + s32 s32Error = WILC_SUCCESS; + + + if (idx != 0) { + s32Error = -ENOENT; + PRINT_ER("Error Idx value doesn't equal zero: Error(%d)\n", s32Error); + + } + + return s32Error; +} + + +/** + * @brief WILC_WFI_get_station + * @details Get station information for the station identified by @mac + * @param[in] NONE + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ + +extern uint32_t Statisitcs_totalAcks, Statisitcs_DroppedAcks; +static int WILC_WFI_get_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_info *sinfo) +{ + s32 s32Error = WILC_SUCCESS; + struct WILC_WFI_priv *priv; + perInterface_wlan_t *nic; + #ifdef WILC_AP_EXTERNAL_MLME + u32 i = 0; + u32 associatedsta = 0; + u32 inactive_time = 0; + #endif + priv = wiphy_priv(wiphy); + nic = netdev_priv(dev); + + #ifdef WILC_AP_EXTERNAL_MLME + if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) { + PRINT_D(HOSTAPD_DBG, "Getting station parameters\n"); + + PRINT_INFO(HOSTAPD_DBG, ": %x%x%x%x%x\n", mac[0], mac[1], mac[2], mac[3], mac[4]); + + for (i = 0; i < NUM_STA_ASSOCIATED; i++) { + + if (!(memcmp(mac, priv->assoc_stainfo.au8Sta_AssociatedBss[i], ETH_ALEN))) { + associatedsta = i; + break; + } + + } + + if (associatedsta == -1) { + s32Error = -ENOENT; + PRINT_ER("Station required is not associated : Error(%d)\n", s32Error); + + return s32Error; + } + + sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME); + + host_int_get_inactive_time(priv->hWILCWFIDrv, mac, &(inactive_time)); + sinfo->inactive_time = 1000 * inactive_time; + PRINT_D(CFG80211_DBG, "Inactive time %d\n", sinfo->inactive_time); + + } + #endif + + if (nic->iftype == STATION_MODE) { + tstrStatistics strStatistics; + host_int_get_statistics(priv->hWILCWFIDrv, &strStatistics); + + /* + * tony: 2013-11-13 + * tx_failed introduced more than + * kernel version 3.0.0 + */ + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) | + BIT( NL80211_STA_INFO_RX_PACKETS) | + BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_TX_FAILED) | + BIT(NL80211_STA_INFO_TX_BITRATE); + + sinfo->signal = strStatistics.s8RSSI; + sinfo->rx_packets = strStatistics.u32RxCount; + sinfo->tx_packets = strStatistics.u32TxCount + strStatistics.u32TxFailureCount; + sinfo->tx_failed = strStatistics.u32TxFailureCount; + sinfo->txrate.legacy = strStatistics.u8LinkSpeed * 10; + +#ifdef TCP_ENHANCEMENTS + if ((strStatistics.u8LinkSpeed > TCP_ACK_FILTER_LINK_SPEED_THRESH) && (strStatistics.u8LinkSpeed != DEFAULT_LINK_SPEED)) { + Enable_TCP_ACK_Filter(true); + } else if (strStatistics.u8LinkSpeed != DEFAULT_LINK_SPEED) { + Enable_TCP_ACK_Filter(false); + } +#endif + + PRINT_D(CORECONFIG_DBG, "*** stats[%d][%d][%d][%d][%d]\n", sinfo->signal, sinfo->rx_packets, sinfo->tx_packets, + sinfo->tx_failed, sinfo->txrate.legacy); + } + return s32Error; +} + + +/** + * @brief WILC_WFI_change_bss + * @details Modify parameters for a given BSS. + * @param[in] + * -use_cts_prot: Whether to use CTS protection + * (0 = no, 1 = yes, -1 = do not change) + * -use_short_preamble: Whether the use of short preambles is allowed + * (0 = no, 1 = yes, -1 = do not change) + * -use_short_slot_time: Whether the use of short slot time is allowed + * (0 = no, 1 = yes, -1 = do not change) + * -basic_rates: basic rates in IEEE 802.11 format + * (or NULL for no change) + * -basic_rates_len: number of basic rates + * -ap_isolate: do not forward packets between connected stations + * -ht_opmode: HT Operation mode + * (u16 = opmode, -1 = do not change) + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_change_bss(struct wiphy *wiphy, struct net_device *dev, + struct bss_parameters *params) +{ + PRINT_D(CFG80211_DBG, "Changing Bss parametrs\n"); + return 0; +} + +/** + * @brief WILC_WFI_auth + * @details Request to authenticate with the specified peer + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_auth(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_auth_request *req) +{ + PRINT_D(CFG80211_DBG, "In Authentication Function\n"); + return 0; +} + +/** + * @brief WILC_WFI_assoc + * @details Request to (re)associate with the specified peer + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_assoc(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_assoc_request *req) +{ + PRINT_D(CFG80211_DBG, "In Association Function\n"); + return 0; +} + +/** + * @brief WILC_WFI_deauth + * @details Request to deauthenticate from the specified peer + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_deauth(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_deauth_request *req, void *cookie) +{ + PRINT_D(CFG80211_DBG, "In De-authentication Function\n"); + return 0; +} + +/** + * @brief WILC_WFI_disassoc + * @details Request to disassociate from the specified peer + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_disassoc(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_disassoc_request *req, void *cookie) +{ + PRINT_D(CFG80211_DBG, "In Disassociation Function\n"); + return 0; +} + +/** + * @brief WILC_WFI_set_wiphy_params + * @details Notify that wiphy parameters have changed; + * @param[in] Changed bitfield (see &enum wiphy_params_flags) describes which values + * have changed. + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + s32 s32Error = WILC_SUCCESS; + tstrCfgParamVal pstrCfgParamVal; + struct WILC_WFI_priv *priv; + + priv = wiphy_priv(wiphy); + + pstrCfgParamVal.u32SetCfgFlag = 0; + PRINT_D(CFG80211_DBG, "Setting Wiphy params \n"); + + if (changed & WIPHY_PARAM_RETRY_SHORT) { + PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_RETRY_SHORT %d\n", + priv->dev->ieee80211_ptr->wiphy->retry_short); + pstrCfgParamVal.u32SetCfgFlag |= RETRY_SHORT; + pstrCfgParamVal.short_retry_limit = priv->dev->ieee80211_ptr->wiphy->retry_short; + } + if (changed & WIPHY_PARAM_RETRY_LONG) { + + PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_RETRY_LONG %d\n", priv->dev->ieee80211_ptr->wiphy->retry_long); + pstrCfgParamVal.u32SetCfgFlag |= RETRY_LONG; + pstrCfgParamVal.long_retry_limit = priv->dev->ieee80211_ptr->wiphy->retry_long; + + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_FRAG_THRESHOLD %d\n", priv->dev->ieee80211_ptr->wiphy->frag_threshold); + pstrCfgParamVal.u32SetCfgFlag |= FRAG_THRESHOLD; + pstrCfgParamVal.frag_threshold = priv->dev->ieee80211_ptr->wiphy->frag_threshold; + + } + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_RTS_THRESHOLD %d\n", priv->dev->ieee80211_ptr->wiphy->rts_threshold); + + pstrCfgParamVal.u32SetCfgFlag |= RTS_THRESHOLD; + pstrCfgParamVal.rts_threshold = priv->dev->ieee80211_ptr->wiphy->rts_threshold; + + } + + PRINT_D(CFG80211_DBG, "Setting CFG params in the host interface\n"); + s32Error = hif_set_cfg(priv->hWILCWFIDrv, &pstrCfgParamVal); + if (s32Error) + PRINT_ER("Error in setting WIPHY PARAMS\n"); + + + return s32Error; +} + +/** + * @brief WILC_WFI_set_bitrate_mask + * @details set the bitrate mask configuration + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, const u8 *peer, + const struct cfg80211_bitrate_mask *mask) +{ + s32 s32Error = WILC_SUCCESS; + + PRINT_D(CFG80211_DBG, "Setting Bitrate mask function\n"); + return s32Error; + +} + +/** + * @brief WILC_WFI_set_pmksa + * @details Cache a PMKID for a BSSID. This is mostly useful for fullmac + * devices running firmwares capable of generating the (re) association + * RSN IE. It allows for faster roaming between WPA2 BSSIDs. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + u32 i; + s32 s32Error = WILC_SUCCESS; + u8 flag = 0; + + struct WILC_WFI_priv *priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Setting PMKSA\n"); + + + for (i = 0; i < priv->pmkid_list.numpmkid; i++) { + if (!WILC_memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid, + ETH_ALEN)) { + /*If bssid already exists and pmkid value needs to reset*/ + flag = PMKID_FOUND; + PRINT_D(CFG80211_DBG, "PMKID already exists\n"); + break; + } + } + if (i < WILC_MAX_NUM_PMKIDS) { + PRINT_D(CFG80211_DBG, "Setting PMKID in private structure\n"); + WILC_memcpy(priv->pmkid_list.pmkidlist[i].bssid, pmksa->bssid, + ETH_ALEN); + WILC_memcpy(priv->pmkid_list.pmkidlist[i].pmkid, pmksa->pmkid, + PMKID_LEN); + if (!(flag == PMKID_FOUND)) + priv->pmkid_list.numpmkid++; + } else { + PRINT_ER("Invalid PMKID index\n"); + s32Error = -EINVAL; + } + + if (!s32Error) { + PRINT_D(CFG80211_DBG, "Setting pmkid in the host interface\n"); + s32Error = host_int_set_pmkid_info(priv->hWILCWFIDrv, &priv->pmkid_list); + } + return s32Error; +} + +/** + * @brief WILC_WFI_del_pmksa + * @details Delete a cached PMKID. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + + u32 i; + u8 flag = 0; + s32 s32Error = WILC_SUCCESS; + + struct WILC_WFI_priv *priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Deleting PMKSA keys\n"); + + for (i = 0; i < priv->pmkid_list.numpmkid; i++) { + if (!WILC_memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid, + ETH_ALEN)) { + /*If bssid is found, reset the values*/ + PRINT_D(CFG80211_DBG, "Reseting PMKID values\n"); + WILC_memset(&priv->pmkid_list.pmkidlist[i], 0, sizeof(tstrHostIFpmkid)); + flag = PMKID_FOUND; + break; + } + } + + if (i < priv->pmkid_list.numpmkid && priv->pmkid_list.numpmkid > 0) { + for (; i < (priv->pmkid_list.numpmkid - 1); i++) { + WILC_memcpy(priv->pmkid_list.pmkidlist[i].bssid, + priv->pmkid_list.pmkidlist[i + 1].bssid, + ETH_ALEN); + WILC_memcpy(priv->pmkid_list.pmkidlist[i].pmkid, + priv->pmkid_list.pmkidlist[i].pmkid, + PMKID_LEN); + } + priv->pmkid_list.numpmkid--; + } else { + s32Error = -EINVAL; + } + + return s32Error; +} + +/** + * @brief WILC_WFI_flush_pmksa + * @details Flush all cached PMKIDs. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) +{ + struct WILC_WFI_priv *priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Flushing PMKID key values\n"); + + /*Get cashed Pmkids and set all with zeros*/ + WILC_memset(&priv->pmkid_list, 0, sizeof(tstrHostIFpmkidAttr)); + + return 0; +} + +#ifdef WILC_P2P + +/** + * @brief WILC_WFI_CfgParseRxAction + * @details Function parses the received frames and modifies the following attributes: + * -GO Intent + * -Channel list + * -Operating Channel + * + * @param[in] u8* Buffer, u32 length + * @return NONE. + * @author mdaftedar + * @date 12 DEC 2012 + * @version + */ + +void WILC_WFI_CfgParseRxAction(u8 *buf, u32 len) +{ + u32 index = 0; + u32 i = 0, j = 0; + + /*BugID_5460*/ + #ifdef USE_SUPPLICANT_GO_INTENT + u8 intent; + u8 tie_breaker; + bool is_wilc_go = true; + #endif + u8 op_channel_attr_index = 0; + u8 channel_list_attr_index = 0; + + while (index < len) { + if (buf[index] == GO_INTENT_ATTR_ID) { + #ifdef USE_SUPPLICANT_GO_INTENT + /*BugID_5460*/ + /*Case 1: If we are going to be p2p client, no need to modify channels attributes*/ + /*In negotiation frames, go intent attr value determines who will be GO*/ + intent = GET_GO_INTENT(buf[index + 3]); + tie_breaker = GET_TIE_BREAKER(buf[index + 3]); + if (intent > SUPPLICANT_GO_INTENT + || (intent == SUPPLICANT_GO_INTENT && tie_breaker == 1)) { + PRINT_D(GENERIC_DBG, "WILC will be client (intent %d tie breaker %d)\n", intent, tie_breaker); + is_wilc_go = false; + } else { + PRINT_D(GENERIC_DBG, "WILC will be GO (intent %d tie breaker %d)\n", intent, tie_breaker); + is_wilc_go = true; + } + + #else /* USE_SUPPLICANT_GO_INTENT */ + #ifdef FORCE_P2P_CLIENT + buf[index + 3] = (buf[index + 3] & 0x01) | (0x0f << 1); + #else + buf[index + 3] = (buf[index + 3] & 0x01) | (0x00 << 1); + #endif + #endif /* USE_SUPPLICANT_GO_INTENT */ + } + + #ifdef USE_SUPPLICANT_GO_INTENT + /*Case 2: If group bssid attribute is present, no need to modify channels attributes*/ + /*In invitation req and rsp, group bssid attr presence determines who will be GO*/ + if (buf[index] == GROUP_BSSID_ATTR_ID) { + PRINT_D(GENERIC_DBG, "Group BSSID: %2x:%2x:%2x\n", buf[index + 3] + , buf[index + 4] + , buf[index + 5]); + is_wilc_go = false; + } + #endif /* USE_SUPPLICANT_GO_INTENT */ + + if (buf[index] == CHANLIST_ATTR_ID) { + channel_list_attr_index = index; + } else if (buf[index] == OPERCHAN_ATTR_ID) { + op_channel_attr_index = index; + } + index += buf[index + 1] + 3; /* ID,Length byte */ + } + + #ifdef USE_SUPPLICANT_GO_INTENT + if (u8WLANChannel != INVALID_CHANNEL && is_wilc_go) + #else + if (u8WLANChannel != INVALID_CHANNEL) + #endif + { + /*Modify channel list attribute*/ + if (channel_list_attr_index) { + PRINT_D(GENERIC_DBG, "Modify channel list attribute\n"); + for (i = channel_list_attr_index + 3; i < ((channel_list_attr_index + 3) + buf[channel_list_attr_index + 1]); i++) { + if (buf[i] == 0x51) { + for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++) { + buf[j] = u8WLANChannel; + } + break; + } + } + } + /*Modify operating channel attribute*/ + if (op_channel_attr_index) { + PRINT_D(GENERIC_DBG, "Modify operating channel attribute\n"); + buf[op_channel_attr_index + 6] = 0x51; + buf[op_channel_attr_index + 7] = u8WLANChannel; + } + } +} + +/** + * @brief WILC_WFI_CfgParseTxAction + * @details Function parses the transmitted action frames and modifies the + * GO Intent attribute + * @param[in] u8* Buffer, u32 length, bool bOperChan, u8 iftype + * @return NONE. + * @author mdaftedar + * @date 12 DEC 2012 + * @version + */ +void WILC_WFI_CfgParseTxAction(u8 *buf, u32 len, bool bOperChan, u8 iftype) +{ + u32 index = 0; + u32 i = 0, j = 0; + + u8 op_channel_attr_index = 0; + u8 channel_list_attr_index = 0; + #ifdef USE_SUPPLICANT_GO_INTENT + bool is_wilc_go = false; + + /*BugID_5460*/ + /*Case 1: If we are already p2p client, no need to modify channels attributes*/ + /*This to handle the case of inviting a p2p peer to join an existing group which we are a member in*/ + if (iftype == CLIENT_MODE) + return; + #endif + + while (index < len) { + #ifdef USE_SUPPLICANT_GO_INTENT + /*Case 2: If group bssid attribute is present, no need to modify channels attributes*/ + /*In invitation req and rsp, group bssid attr presence determines who will be GO*/ + /*Note: If we are already p2p client, group bssid attr may also be present (handled in Case 1)*/ + if (buf[index] == GROUP_BSSID_ATTR_ID) { + PRINT_D(GENERIC_DBG, "Group BSSID: %2x:%2x:%2x\n", buf[index + 3] + , buf[index + 4] + , buf[index + 5]); + is_wilc_go = true; + } + + #else /* USE_SUPPLICANT_GO_INTENT */ + if (buf[index] == GO_INTENT_ATTR_ID) { + #ifdef FORCE_P2P_CLIENT + buf[index + 3] = (buf[index + 3] & 0x01) | (0x00 << 1); + #else + buf[index + 3] = (buf[index + 3] & 0x01) | (0x0f << 1); + #endif + + break; + } + #endif + + if (buf[index] == CHANLIST_ATTR_ID) { + channel_list_attr_index = index; + } else if (buf[index] == OPERCHAN_ATTR_ID) { + op_channel_attr_index = index; + } + index += buf[index + 1] + 3; /* ID,Length byte */ + } + + #ifdef USE_SUPPLICANT_GO_INTENT + /*No need to check bOperChan since only transmitted invitation frames are parsed*/ + if (u8WLANChannel != INVALID_CHANNEL && is_wilc_go) + #else + if (u8WLANChannel != INVALID_CHANNEL && bOperChan) + #endif + { + /*Modify channel list attribute*/ + if (channel_list_attr_index) { + PRINT_D(GENERIC_DBG, "Modify channel list attribute\n"); + for (i = channel_list_attr_index + 3; i < ((channel_list_attr_index + 3) + buf[channel_list_attr_index + 1]); i++) { + if (buf[i] == 0x51) { + for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++) { + buf[j] = u8WLANChannel; + } + break; + } + } + } + /*Modify operating channel attribute*/ + if (op_channel_attr_index) { + PRINT_D(GENERIC_DBG, "Modify operating channel attribute\n"); + buf[op_channel_attr_index + 6] = 0x51; + buf[op_channel_attr_index + 7] = u8WLANChannel; + } + } +} + +/* @brief WILC_WFI_p2p_rx + * @details + * @param[in] + * + * @return None + * @author Mai Daftedar + * @date 2 JUN 2013 + * @version 1.0 + */ + +void WILC_WFI_p2p_rx (struct net_device *dev, uint8_t *buff, uint32_t size) +{ + + struct WILC_WFI_priv *priv; + u32 header, pkt_offset; + tstrWILC_WFIDrv *pstrWFIDrv; + u32 i = 0; + s32 s32Freq; + priv = wiphy_priv(dev->ieee80211_ptr->wiphy); + pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; + + /* Get WILC header */ + WILC_memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET); + + /* The packet offset field conain info about what type of managment frame */ + /* we are dealing with and ack status */ + pkt_offset = GET_PKT_OFFSET(header); + + if (pkt_offset & IS_MANAGMEMENT_CALLBACK) { + if (buff[FRAME_TYPE_ID] == IEEE80211_STYPE_PROBE_RESP) { + PRINT_D(GENERIC_DBG, "Probe response ACK\n"); + cfg80211_mgmt_tx_status(priv->wdev, priv->u64tx_cookie, buff, size, true, GFP_KERNEL); + return; + } else { + if (pkt_offset & IS_MGMT_STATUS_SUCCES) { + PRINT_D(GENERIC_DBG, "Success Ack - Action frame category: %x Action Subtype: %d Dialog T: %x OR %x\n", buff[ACTION_CAT_ID], buff[ACTION_SUBTYPE_ID], + buff[ACTION_SUBTYPE_ID + 1], buff[P2P_PUB_ACTION_SUBTYPE + 1]); + cfg80211_mgmt_tx_status(priv->wdev, priv->u64tx_cookie, buff, size, true, GFP_KERNEL); + } else { + PRINT_D(GENERIC_DBG, "Fail Ack - Action frame category: %x Action Subtype: %d Dialog T: %x OR %x\n", buff[ACTION_CAT_ID], buff[ACTION_SUBTYPE_ID], + buff[ACTION_SUBTYPE_ID + 1], buff[P2P_PUB_ACTION_SUBTYPE + 1]); + cfg80211_mgmt_tx_status(priv->wdev, priv->u64tx_cookie, buff, size, false, GFP_KERNEL); + } + return; + } + } else { + + PRINT_D(GENERIC_DBG, "Rx Frame Type:%x\n", buff[FRAME_TYPE_ID]); + + /*BugID_5442*/ + /*Upper layer is informed that the frame is received on this freq*/ + s32Freq = ieee80211_channel_to_frequency(u8CurrChannel, IEEE80211_BAND_2GHZ); + + if (ieee80211_is_action(buff[FRAME_TYPE_ID])) { + PRINT_D(GENERIC_DBG, "Rx Action Frame Type: %x %x\n", buff[ACTION_SUBTYPE_ID], buff[P2P_PUB_ACTION_SUBTYPE]); + + if (priv->bCfgScanning == true && time_after_eq(jiffies, (unsigned long)pstrWFIDrv->u64P2p_MgmtTimeout)) { + PRINT_D(GENERIC_DBG, "Receiving action frames from wrong channels\n"); + return; + } + if (buff[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) { + + switch (buff[ACTION_SUBTYPE_ID]) { + case GAS_INTIAL_REQ: + PRINT_D(GENERIC_DBG, "GAS INITIAL REQ %x\n", buff[ACTION_SUBTYPE_ID]); + break; + + case GAS_INTIAL_RSP: + PRINT_D(GENERIC_DBG, "GAS INITIAL RSP %x\n", buff[ACTION_SUBTYPE_ID]); + break; + + case PUBLIC_ACT_VENDORSPEC: + /*Now we have a public action vendor specific action frame, check if its a p2p public action frame + * based on the standard its should have the p2p_oui attribute with the following values 50 6f 9A 09*/ + if (!WILC_memcmp(u8P2P_oui, &buff[ACTION_SUBTYPE_ID + 1], 4)) { + if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP)) { + if (!bWilc_ie) { + for (i = P2P_PUB_ACTION_SUBTYPE; i < size; i++) { + if (!WILC_memcmp(u8P2P_vendorspec, &buff[i], 6)) { + u8P2Precvrandom = buff[i + 6]; + bWilc_ie = true; + PRINT_D(GENERIC_DBG, "WILC Vendor specific IE:%02x\n", u8P2Precvrandom); + break; + } + } + } + } + if (u8P2Plocalrandom > u8P2Precvrandom) { + if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP + || buff[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP)) { + for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < size; i++) { + if (buff[i] == P2PELEM_ATTR_ID && !(WILC_memcmp(u8P2P_oui, &buff[i + 2], 4))) { + WILC_WFI_CfgParseRxAction(&buff[i + 6], size - (i + 6)); + break; + } + } + } + } else + PRINT_D(GENERIC_DBG, "PEER WILL BE GO LocaRand=%02x RecvRand %02x\n", u8P2Plocalrandom, u8P2Precvrandom); + } + + + if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP) && (bWilc_ie)) { + PRINT_D(GENERIC_DBG, "Sending P2P to host without extra elemnt\n"); + /* extra attribute for sig_dbm: signal strength in mBm, or 0 if unknown */ + cfg80211_rx_mgmt(priv->wdev, s32Freq, 0, buff, size - 7, 0); + return; + } + break; + + default: + PRINT_D(GENERIC_DBG, "NOT HANDLED PUBLIC ACTION FRAME TYPE:%x\n", buff[ACTION_SUBTYPE_ID]); + break; + } + } + } + + cfg80211_rx_mgmt(priv->wdev, s32Freq, 0, buff, size - 7, 0); + } +} + +/** + * @brief WILC_WFI_mgmt_tx_complete + * @details Returns result of writing mgmt frame to VMM (Tx buffers are freed here) + * @param[in] priv + * transmitting status + * @return None + * @author Amr Abdelmoghny + * @date 20 MAY 2013 + * @version 1.0 + */ +static void WILC_WFI_mgmt_tx_complete(void *priv, int status) +{ + struct p2p_mgmt_data *pv_data = (struct p2p_mgmt_data *)priv; + + + kfree(pv_data->buff); + kfree(pv_data); +} + +/** + * @brief WILC_WFI_RemainOnChannelReady + * @details Callback function, called from handle_remain_on_channel on being ready on channel + * @param + * @return none + * @author Amr abdelmoghny + * @date 9 JUNE 2013 + * @version + */ + +static void WILC_WFI_RemainOnChannelReady(void *pUserVoid) +{ + struct WILC_WFI_priv *priv; + priv = (struct WILC_WFI_priv *)pUserVoid; + + PRINT_D(HOSTINF_DBG, "Remain on channel ready \n"); + + priv->bInP2PlistenState = true; + + cfg80211_ready_on_channel(priv->wdev, + priv->strRemainOnChanParams.u64ListenCookie, + priv->strRemainOnChanParams.pstrListenChan, + priv->strRemainOnChanParams.u32ListenDuration, + GFP_KERNEL); +} + +/** + * @brief WILC_WFI_RemainOnChannelExpired + * @details Callback function, called on expiration of remain-on-channel duration + * @param + * @return none + * @author Amr abdelmoghny + * @date 15 MAY 2013 + * @version + */ + +static void WILC_WFI_RemainOnChannelExpired(void *pUserVoid, u32 u32SessionID) +{ + struct WILC_WFI_priv *priv; + priv = (struct WILC_WFI_priv *)pUserVoid; + + /*BugID_5477*/ + if (u32SessionID == priv->strRemainOnChanParams.u32ListenSessionID) { + PRINT_D(GENERIC_DBG, "Remain on channel expired \n"); + + priv->bInP2PlistenState = false; + + /*Inform wpas of remain-on-channel expiration*/ + cfg80211_remain_on_channel_expired(priv->wdev, + priv->strRemainOnChanParams.u64ListenCookie, + priv->strRemainOnChanParams.pstrListenChan, + GFP_KERNEL); + } else { + PRINT_D(GENERIC_DBG, "Received ID 0x%x Expected ID 0x%x (No match)\n", u32SessionID + , priv->strRemainOnChanParams.u32ListenSessionID); + } +} + + +/** + * @brief WILC_WFI_remain_on_channel + * @details Request the driver to remain awake on the specified + * channel for the specified duration to complete an off-channel + * operation (e.g., public action frame exchange). When the driver is + * ready on the requested channel, it must indicate this with an event + * notification by calling cfg80211_ready_on_channel(). + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + s32 s32Error = WILC_SUCCESS; + struct WILC_WFI_priv *priv; + priv = wiphy_priv(wiphy); + + PRINT_D(GENERIC_DBG, "Remaining on channel %d\n", chan->hw_value); + + /*BugID_4800: if in AP mode, return.*/ + /*This check is to handle the situation when user*/ + /*requests "create group" during a running scan*/ + + if (wdev->iftype == NL80211_IFTYPE_AP) { + PRINT_D(GENERIC_DBG, "Required remain-on-channel while in AP mode"); + return s32Error; + } + + u8CurrChannel = chan->hw_value; + + /*Setting params needed by WILC_WFI_RemainOnChannelExpired()*/ + priv->strRemainOnChanParams.pstrListenChan = chan; + priv->strRemainOnChanParams.u64ListenCookie = *cookie; + priv->strRemainOnChanParams.u32ListenDuration = duration; + priv->strRemainOnChanParams.u32ListenSessionID++; + + s32Error = host_int_remain_on_channel(priv->hWILCWFIDrv + , priv->strRemainOnChanParams.u32ListenSessionID + , duration + , chan->hw_value + , WILC_WFI_RemainOnChannelExpired + , WILC_WFI_RemainOnChannelReady + , (void *)priv); + + return s32Error; +} + +/** + * @brief WILC_WFI_cancel_remain_on_channel + * @details Cancel an on-going remain-on-channel operation. + * This allows the operation to be terminated prior to timeout based on + * the duration value. + * @param[in] struct wiphy *wiphy, + * @param[in] struct net_device *dev + * @param[in] u64 cookie, + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + s32 s32Error = WILC_SUCCESS; + struct WILC_WFI_priv *priv; + priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Cancel remain on channel\n"); + + s32Error = host_int_ListenStateExpired(priv->hWILCWFIDrv, priv->strRemainOnChanParams.u32ListenSessionID); + return s32Error; +} +/** + * @brief WILC_WFI_add_wilcvendorspec + * @details Adding WILC information elemet to allow two WILC devices to + * identify each other and connect + * @param[in] u8 * buf + * @return void + * @author mdaftedar + * @date 01 JAN 2014 + * @version 1.0 + */ +void WILC_WFI_add_wilcvendorspec(u8 *buff) +{ + WILC_memcpy(buff, u8P2P_vendorspec, sizeof(u8P2P_vendorspec)); +} +/** + * @brief WILC_WFI_mgmt_tx_frame + * @details + * + * @param[in] + * @return NONE. + * @author mdaftedar + * @date 01 JUL 2012 + * @version + */ +extern linux_wlan_t *g_linux_wlan; +extern bool bEnablePS; +int WILC_WFI_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) +{ + struct ieee80211_channel *chan = params->chan; + unsigned int wait = params->wait; + const u8 *buf = params->buf; + size_t len = params->len; + const struct ieee80211_mgmt *mgmt; + struct p2p_mgmt_data *mgmt_tx; + struct WILC_WFI_priv *priv; + s32 s32Error = WILC_SUCCESS; + tstrWILC_WFIDrv *pstrWFIDrv; + u32 i; + perInterface_wlan_t *nic; + u32 buf_len = len + sizeof(u8P2P_vendorspec) + sizeof(u8P2Plocalrandom); + + nic = netdev_priv(wdev->netdev); + priv = wiphy_priv(wiphy); + pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; + + *cookie = (unsigned long)buf; + priv->u64tx_cookie = *cookie; + mgmt = (const struct ieee80211_mgmt *) buf; + + if (ieee80211_is_mgmt(mgmt->frame_control)) { + + /*mgmt frame allocation*/ + mgmt_tx = (struct p2p_mgmt_data *)WILC_MALLOC(sizeof(struct p2p_mgmt_data)); + if (mgmt_tx == NULL) { + PRINT_ER("Failed to allocate memory for mgmt_tx structure\n"); + return WILC_FAIL; + } + mgmt_tx->buff = (char *)WILC_MALLOC(buf_len); + if (mgmt_tx->buff == NULL) { + PRINT_ER("Failed to allocate memory for mgmt_tx buff\n"); + return WILC_FAIL; + } + WILC_memcpy(mgmt_tx->buff, buf, len); + mgmt_tx->size = len; + + + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + PRINT_D(GENERIC_DBG, "TX: Probe Response\n"); + PRINT_D(GENERIC_DBG, "Setting channel: %d\n", chan->hw_value); + host_int_set_mac_chnl_num(priv->hWILCWFIDrv, chan->hw_value); + /*Save the current channel after we tune to it*/ + u8CurrChannel = chan->hw_value; + } else if (ieee80211_is_action(mgmt->frame_control)) { + PRINT_D(GENERIC_DBG, "ACTION FRAME:%x\n", (u16)mgmt->frame_control); + + + /*BugID_4847*/ + if (buf[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) { + /*BugID_4847*/ + /*Only set the channel, if not a negotiation confirmation frame + * (If Negotiation confirmation frame, force it + * to be transmitted on the same negotiation channel)*/ + + if (buf[ACTION_SUBTYPE_ID] != PUBLIC_ACT_VENDORSPEC || + buf[P2P_PUB_ACTION_SUBTYPE] != GO_NEG_CONF) { + PRINT_D(GENERIC_DBG, "Setting channel: %d\n", chan->hw_value); + host_int_set_mac_chnl_num(priv->hWILCWFIDrv, chan->hw_value); + /*Save the current channel after we tune to it*/ + u8CurrChannel = chan->hw_value; + } + switch (buf[ACTION_SUBTYPE_ID]) { + case GAS_INTIAL_REQ: + { + PRINT_D(GENERIC_DBG, "GAS INITIAL REQ %x\n", buf[ACTION_SUBTYPE_ID]); + break; + } + + case GAS_INTIAL_RSP: + { + PRINT_D(GENERIC_DBG, "GAS INITIAL RSP %x\n", buf[ACTION_SUBTYPE_ID]); + break; + } + + case PUBLIC_ACT_VENDORSPEC: + { + /*Now we have a public action vendor specific action frame, check if its a p2p public action frame + * based on the standard its should have the p2p_oui attribute with the following values 50 6f 9A 09*/ + if (!WILC_memcmp(u8P2P_oui, &buf[ACTION_SUBTYPE_ID + 1], 4)) { + /*For the connection of two WILC's connection generate a rand number to determine who will be a GO*/ + if ((buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP)) { + if (u8P2Plocalrandom == 1 && u8P2Precvrandom < u8P2Plocalrandom) { + get_random_bytes(&u8P2Plocalrandom, 1); + /*Increment the number to prevent if its 0*/ + u8P2Plocalrandom++; + } + } + + if ((buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP + || buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP)) { + if (u8P2Plocalrandom > u8P2Precvrandom) { + PRINT_D(GENERIC_DBG, "LOCAL WILL BE GO LocaRand=%02x RecvRand %02x\n", u8P2Plocalrandom, u8P2Precvrandom); + + /*Search for the p2p information information element , after the Public action subtype theres a byte for teh dialog token, skip that*/ + for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < len; i++) { + if (buf[i] == P2PELEM_ATTR_ID && !(WILC_memcmp(u8P2P_oui, &buf[i + 2], 4))) { + if (buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP) + WILC_WFI_CfgParseTxAction(&mgmt_tx->buff[i + 6], len - (i + 6), true, nic->iftype); + + /*BugID_5460*/ + /*If using supplicant go intent, no need at all*/ + /*to parse transmitted negotiation frames*/ + #ifndef USE_SUPPLICANT_GO_INTENT + else + WILC_WFI_CfgParseTxAction(&mgmt_tx->buff[i + 6], len - (i + 6), false, nic->iftype); + #endif + break; + } + } + + if (buf[P2P_PUB_ACTION_SUBTYPE] != P2P_INV_REQ && buf[P2P_PUB_ACTION_SUBTYPE] != P2P_INV_RSP) { + WILC_WFI_add_wilcvendorspec(&mgmt_tx->buff[len]); + mgmt_tx->buff[len + sizeof(u8P2P_vendorspec)] = u8P2Plocalrandom; + mgmt_tx->size = buf_len; + } + } else + PRINT_D(GENERIC_DBG, "PEER WILL BE GO LocaRand=%02x RecvRand %02x\n", u8P2Plocalrandom, u8P2Precvrandom); + } + + } else { + PRINT_D(GENERIC_DBG, "Not a P2P public action frame\n"); + } + + break; + } + + default: + { + PRINT_D(GENERIC_DBG, "NOT HANDLED PUBLIC ACTION FRAME TYPE:%x\n", buf[ACTION_SUBTYPE_ID]); + break; + } + } + + } + + PRINT_D(GENERIC_DBG, "TX: ACTION FRAME Type:%x : Chan:%d\n", buf[ACTION_SUBTYPE_ID], chan->hw_value); + pstrWFIDrv->u64P2p_MgmtTimeout = (jiffies + msecs_to_jiffies(wait)); + + PRINT_D(GENERIC_DBG, "Current Jiffies: %lu Timeout:%llu\n", jiffies, pstrWFIDrv->u64P2p_MgmtTimeout); + + } + + g_linux_wlan->oup.wlan_add_mgmt_to_tx_que(mgmt_tx, mgmt_tx->buff, mgmt_tx->size, WILC_WFI_mgmt_tx_complete); + } else { + PRINT_D(GENERIC_DBG, "This function transmits only management frames\n"); + } + return s32Error; +} + +int WILC_WFI_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + struct WILC_WFI_priv *priv; + tstrWILC_WFIDrv *pstrWFIDrv; + priv = wiphy_priv(wiphy); + pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; + + + PRINT_D(GENERIC_DBG, "Tx Cancel wait :%lu\n", jiffies); + pstrWFIDrv->u64P2p_MgmtTimeout = jiffies; + + if (priv->bInP2PlistenState == false) { + /* Bug 5504: This is just to avoid connection failure when getting stuck when the supplicant + * considers the driver falsely that it is in Listen state */ + cfg80211_remain_on_channel_expired(priv->wdev, + priv->strRemainOnChanParams.u64ListenCookie, + priv->strRemainOnChanParams.pstrListenChan, + GFP_KERNEL); + } + + return 0; +} + +/** + * @brief WILC_WFI_frame_register + * @details Notify driver that a management frame type was + * registered. Note that this callback may not sleep, and cannot run + * concurrently with itself. + * @param[in] + * @return NONE. + * @author mdaftedar + * @date 01 JUL 2012 + * @version + */ +void WILC_WFI_frame_register(struct wiphy *wiphy, + struct wireless_dev *wdev, + u16 frame_type, bool reg) +{ + + struct WILC_WFI_priv *priv; + perInterface_wlan_t *nic; + + + priv = wiphy_priv(wiphy); + nic = netdev_priv(priv->wdev->netdev); + + + + /*BugID_5137*/ + if (!frame_type) + return; + + PRINT_D(GENERIC_DBG, "Frame registering Frame Type: %x: Boolean: %d\n", frame_type, reg); + switch (frame_type) { + case PROBE_REQ: + { + nic->g_struct_frame_reg[0].frame_type = frame_type; + nic->g_struct_frame_reg[0].reg = reg; + } + break; + + case ACTION: + { + nic->g_struct_frame_reg[1].frame_type = frame_type; + nic->g_struct_frame_reg[1].reg = reg; + } + break; + + default: + { + break; + } + + } + /*If mac is closed, then return*/ + if (!g_linux_wlan->wilc1000_initialized) { + PRINT_D(GENERIC_DBG, "Return since mac is closed\n"); + return; + } + host_int_frame_register(priv->hWILCWFIDrv, frame_type, reg); + + +} +#endif /*WILC_P2P*/ + +/** + * @brief WILC_WFI_set_cqm_rssi_config + * @details Configure connection quality monitor RSSI threshold. + * @param[in] struct wiphy *wiphy: + * @param[in] struct net_device *dev: + * @param[in] s32 rssi_thold: + * @param[in] u32 rssi_hyst: + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_set_cqm_rssi_config(struct wiphy *wiphy, + struct net_device *dev, s32 rssi_thold, u32 rssi_hyst) +{ + PRINT_D(CFG80211_DBG, "Setting CQM RSSi Function\n"); + return 0; + +} +/** + * @brief WILC_WFI_dump_station + * @details Configure connection quality monitor RSSI threshold. + * @param[in] struct wiphy *wiphy: + * @param[in] struct net_device *dev + * @param[in] int idx + * @param[in] u8 *mac + * @param[in] struct station_info *sinfo + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct WILC_WFI_priv *priv; + PRINT_D(CFG80211_DBG, "Dumping station information\n"); + + if (idx != 0) + return -ENOENT; + + priv = wiphy_priv(wiphy); + + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + + host_int_get_rssi(priv->hWILCWFIDrv, &(sinfo->signal)); + + return 0; + +} + + +/** + * @brief WILC_WFI_set_power_mgmt + * @details + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 JUL 2012 + * @version 1.0WILC_WFI_set_cqmWILC_WFI_set_cqm_rssi_configWILC_WFI_set_cqm_rssi_configWILC_WFI_set_cqm_rssi_configWILC_WFI_set_cqm_rssi_config_rssi_config + */ +int WILC_WFI_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout) +{ + struct WILC_WFI_priv *priv; + PRINT_D(CFG80211_DBG, " Power save Enabled= %d , TimeOut = %d\n", enabled, timeout); + + if (wiphy == NULL) + return -ENOENT; + + priv = wiphy_priv(wiphy); + if (priv->hWILCWFIDrv == NULL) { + PRINT_ER("Driver is NULL\n"); + return -EIO; + } + + if (bEnablePS) + host_int_set_power_mgmt(priv->hWILCWFIDrv, enabled, timeout); + + + return WILC_SUCCESS; + +} +#ifdef WILC_AP_EXTERNAL_MLME +/** + * @brief WILC_WFI_change_virt_intf + * @details Change type/configuration of virtual interface, + * keep the struct wireless_dev's iftype updated. + * @param[in] NONE + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void wilc1000_wlan_deinit(linux_wlan_t *nic); +int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic); + +static int WILC_WFI_change_virt_intf(struct wiphy *wiphy, struct net_device *dev, + enum nl80211_iftype type, u32 *flags, struct vif_params *params) +{ + s32 s32Error = WILC_SUCCESS; + struct WILC_WFI_priv *priv; + perInterface_wlan_t *nic; + u8 interface_type; + u16 TID = 0; + #ifdef WILC_P2P + u8 i; + #endif + + nic = netdev_priv(dev); + priv = wiphy_priv(wiphy); + + PRINT_D(HOSTAPD_DBG, "In Change virtual interface function\n"); + PRINT_D(HOSTAPD_DBG, "Wireless interface name =%s\n", dev->name); + u8P2Plocalrandom = 0x01; + u8P2Precvrandom = 0x00; + + bWilc_ie = false; + + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + g_obtainingIP = false; + WILC_TimerStop(&hDuringIpTimer, NULL); + PRINT_D(GENERIC_DBG, "Changing virtual interface, enable scan\n"); + #endif + /*BugID_5137*/ + /*Set WILC_CHANGING_VIR_IF register to disallow adding futrue keys to CE H/W*/ + if (g_ptk_keys_saved && g_gtk_keys_saved) { + Set_machw_change_vir_if(true); + } + + switch (type) { + case NL80211_IFTYPE_STATION: + connecting = 0; + PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_STATION\n"); + + /* send delba over wlan interface */ + + + dev->ieee80211_ptr->iftype = type; + priv->wdev->iftype = type; + nic->monitor_flag = 0; + nic->iftype = STATION_MODE; + + /*Remove the enteries of the previously connected clients*/ + memset(priv->assoc_stainfo.au8Sta_AssociatedBss, 0, MAX_NUM_STA * ETH_ALEN); + #ifndef SIMULATION + #ifdef WILC_P2P + interface_type = nic->iftype; + nic->iftype = STATION_MODE; + + if (g_linux_wlan->wilc1000_initialized) { + host_int_del_All_Rx_BASession(priv->hWILCWFIDrv, g_linux_wlan->strInterfaceInfo[0].aBSSID, TID); + /* ensure that the message Q is empty */ + host_int_wait_msg_queue_idle(); + + /*BugID_5213*/ + /*Eliminate host interface blocking state*/ + linux_wlan_unlock((void *)&g_linux_wlan->cfg_event); + + wilc1000_wlan_deinit(g_linux_wlan); + wilc1000_wlan_init(dev, nic); + g_wilc_initialized = 1; + nic->iftype = interface_type; + + /*Setting interface 1 drv handler and mac address in newly downloaded FW*/ + host_int_set_wfi_drv_handler(g_linux_wlan->strInterfaceInfo[0].drvHandler); + host_int_set_MacAddress((WILC_WFIDrvHandle)(g_linux_wlan->strInterfaceInfo[0].drvHandler), + g_linux_wlan->strInterfaceInfo[0].aSrcAddress); + host_int_set_operation_mode(priv->hWILCWFIDrv, STATION_MODE); + + /*Add saved WEP keys, if any*/ + if (g_wep_keys_saved) { + host_int_set_WEPDefaultKeyID((WILC_WFIDrvHandle)(g_linux_wlan->strInterfaceInfo[0].drvHandler), + g_key_wep_params.key_idx); + host_int_add_wep_key_bss_sta((WILC_WFIDrvHandle)(g_linux_wlan->strInterfaceInfo[0].drvHandler), + g_key_wep_params.key, + g_key_wep_params.key_len, + g_key_wep_params.key_idx); + } + + /*No matter the driver handler passed here, it will be overwriiten*/ + /*in Handle_FlushConnect() with gu8FlushedJoinReqDrvHandler*/ + host_int_flush_join_req(priv->hWILCWFIDrv); + + /*Add saved PTK and GTK keys, if any*/ + if (g_ptk_keys_saved && g_gtk_keys_saved) { + PRINT_D(CFG80211_DBG, "ptk %x %x %x\n", g_key_ptk_params.key[0], + g_key_ptk_params.key[1], + g_key_ptk_params.key[2]); + PRINT_D(CFG80211_DBG, "gtk %x %x %x\n", g_key_gtk_params.key[0], + g_key_gtk_params.key[1], + g_key_gtk_params.key[2]); + WILC_WFI_add_key(g_linux_wlan->strInterfaceInfo[0].wilc_netdev->ieee80211_ptr->wiphy, + g_linux_wlan->strInterfaceInfo[0].wilc_netdev, + g_add_ptk_key_params.key_idx, + g_add_ptk_key_params.pairwise, + g_add_ptk_key_params.mac_addr, + (struct key_params *)(&g_key_ptk_params)); + + WILC_WFI_add_key(g_linux_wlan->strInterfaceInfo[0].wilc_netdev->ieee80211_ptr->wiphy, + g_linux_wlan->strInterfaceInfo[0].wilc_netdev, + g_add_gtk_key_params.key_idx, + g_add_gtk_key_params.pairwise, + g_add_gtk_key_params.mac_addr, + (struct key_params *)(&g_key_gtk_params)); + } + + /*BugID_4847: registered frames in firmware are now*/ + /*lost due to mac close. So re-register those frames*/ + if (g_linux_wlan->wilc1000_initialized) { + for (i = 0; i < num_reg_frame; i++) { + PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + host_int_frame_register(priv->hWILCWFIDrv, + nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + } + } + + bEnablePS = true; + host_int_set_power_mgmt(priv->hWILCWFIDrv, 1, 0); + } + #endif + #endif + break; + + case NL80211_IFTYPE_P2P_CLIENT: + bEnablePS = false; + host_int_set_power_mgmt(priv->hWILCWFIDrv, 0, 0); + connecting = 0; + PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_P2P_CLIENT\n"); + + host_int_del_All_Rx_BASession(priv->hWILCWFIDrv, g_linux_wlan->strInterfaceInfo[0].aBSSID, TID); + + dev->ieee80211_ptr->iftype = type; + priv->wdev->iftype = type; + nic->monitor_flag = 0; + + #ifndef SIMULATION + #ifdef WILC_P2P + + PRINT_D(HOSTAPD_DBG, "Downloading P2P_CONCURRENCY_FIRMWARE\n"); + nic->iftype = CLIENT_MODE; + + + if (g_linux_wlan->wilc1000_initialized) { + /* ensure that the message Q is empty */ + host_int_wait_msg_queue_idle(); + + wilc1000_wlan_deinit(g_linux_wlan); + wilc1000_wlan_init(dev, nic); + g_wilc_initialized = 1; + + host_int_set_wfi_drv_handler(g_linux_wlan->strInterfaceInfo[0].drvHandler); + host_int_set_MacAddress((WILC_WFIDrvHandle)(g_linux_wlan->strInterfaceInfo[0].drvHandler), + g_linux_wlan->strInterfaceInfo[0].aSrcAddress); + host_int_set_operation_mode(priv->hWILCWFIDrv, STATION_MODE); + + /*Add saved WEP keys, if any*/ + if (g_wep_keys_saved) { + host_int_set_WEPDefaultKeyID((WILC_WFIDrvHandle)(g_linux_wlan->strInterfaceInfo[0].drvHandler), + g_key_wep_params.key_idx); + host_int_add_wep_key_bss_sta((WILC_WFIDrvHandle)(g_linux_wlan->strInterfaceInfo[0].drvHandler), + g_key_wep_params.key, + g_key_wep_params.key_len, + g_key_wep_params.key_idx); + } + + /*No matter the driver handler passed here, it will be overwriiten*/ + /*in Handle_FlushConnect() with gu8FlushedJoinReqDrvHandler*/ + host_int_flush_join_req(priv->hWILCWFIDrv); + + /*Add saved PTK and GTK keys, if any*/ + if (g_ptk_keys_saved && g_gtk_keys_saved) { + PRINT_D(CFG80211_DBG, "ptk %x %x %x\n", g_key_ptk_params.key[0], + g_key_ptk_params.key[1], + g_key_ptk_params.key[2]); + PRINT_D(CFG80211_DBG, "gtk %x %x %x\n", g_key_gtk_params.key[0], + g_key_gtk_params.key[1], + g_key_gtk_params.key[2]); + WILC_WFI_add_key(g_linux_wlan->strInterfaceInfo[0].wilc_netdev->ieee80211_ptr->wiphy, + g_linux_wlan->strInterfaceInfo[0].wilc_netdev, + g_add_ptk_key_params.key_idx, + g_add_ptk_key_params.pairwise, + g_add_ptk_key_params.mac_addr, + (struct key_params *)(&g_key_ptk_params)); + + WILC_WFI_add_key(g_linux_wlan->strInterfaceInfo[0].wilc_netdev->ieee80211_ptr->wiphy, + g_linux_wlan->strInterfaceInfo[0].wilc_netdev, + g_add_gtk_key_params.key_idx, + g_add_gtk_key_params.pairwise, + g_add_gtk_key_params.mac_addr, + (struct key_params *)(&g_key_gtk_params)); + } + + /*Refresh scan, to refresh the scan results to the wpa_supplicant. Set MachHw to false to enable further key installments*/ + refresh_scan(priv, 1, true); + Set_machw_change_vir_if(false); + + /*BugID_4847: registered frames in firmware are now lost + * due to mac close. So re-register those frames */ + if (g_linux_wlan->wilc1000_initialized) { + for (i = 0; i < num_reg_frame; i++) { + PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + host_int_frame_register(priv->hWILCWFIDrv, + nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + } + } + } + #endif + #endif + break; + + case NL80211_IFTYPE_AP: + bEnablePS = false; + PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_AP %d\n", type); + dev->ieee80211_ptr->iftype = type; + priv->wdev->iftype = type; + nic->iftype = AP_MODE; + PRINT_D(CORECONFIG_DBG, "priv->hWILCWFIDrv[%p]\n", priv->hWILCWFIDrv); + + #ifndef SIMULATION + PRINT_D(HOSTAPD_DBG, "Downloading AP firmware\n"); + linux_wlan_get_firmware(nic); + #ifdef WILC_P2P + /*If wilc is running, then close-open to actually get new firmware running (serves P2P)*/ + if (g_linux_wlan->wilc1000_initialized) { + nic->iftype = AP_MODE; + g_linux_wlan->wilc1000_initialized = 1; + mac_close(dev); + mac_open(dev); + + /*BugID_4847: registered frames in firmware are now lost + * due to mac close. So re-register those frames */ + for (i = 0; i < num_reg_frame; i++) { + PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + host_int_frame_register(priv->hWILCWFIDrv, + nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + } + } + #endif + #endif + break; + + case NL80211_IFTYPE_P2P_GO: + PRINT_D(GENERIC_DBG, "start duringIP timer\n"); + + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + g_obtainingIP = true; + WILC_TimerStart(&hDuringIpTimer, duringIP_TIME, NULL, NULL); + #endif + host_int_set_power_mgmt(priv->hWILCWFIDrv, 0, 0); + /*BugID_5222*/ + /*Delete block ack has to be the latest config packet*/ + /*sent before downloading new FW. This is because it blocks on*/ + /*hWaitResponse semaphore, which allows previous config*/ + /*packets to actually take action on old FW*/ + host_int_del_All_Rx_BASession(priv->hWILCWFIDrv, g_linux_wlan->strInterfaceInfo[0].aBSSID, TID); + bEnablePS = false; + PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_GO\n"); + dev->ieee80211_ptr->iftype = type; + priv->wdev->iftype = type; + + PRINT_D(CORECONFIG_DBG, "priv->hWILCWFIDrv[%p]\n", priv->hWILCWFIDrv); + + #ifndef SIMULATION + #ifdef WILC_P2P + PRINT_D(HOSTAPD_DBG, "Downloading P2P_CONCURRENCY_FIRMWARE\n"); + + + #if 1 + nic->iftype = GO_MODE; + + /* ensure that the message Q is empty */ + host_int_wait_msg_queue_idle(); + wilc1000_wlan_deinit(g_linux_wlan); + wilc1000_wlan_init(dev, nic); + g_wilc_initialized = 1; + + + /*Setting interface 1 drv handler and mac address in newly downloaded FW*/ + host_int_set_wfi_drv_handler(g_linux_wlan->strInterfaceInfo[0].drvHandler); + host_int_set_MacAddress((WILC_WFIDrvHandle)(g_linux_wlan->strInterfaceInfo[0].drvHandler), + g_linux_wlan->strInterfaceInfo[0].aSrcAddress); + host_int_set_operation_mode(priv->hWILCWFIDrv, AP_MODE); + + /*Add saved WEP keys, if any*/ + if (g_wep_keys_saved) { + host_int_set_WEPDefaultKeyID((WILC_WFIDrvHandle)(g_linux_wlan->strInterfaceInfo[0].drvHandler), + g_key_wep_params.key_idx); + host_int_add_wep_key_bss_sta((WILC_WFIDrvHandle)(g_linux_wlan->strInterfaceInfo[0].drvHandler), + g_key_wep_params.key, + g_key_wep_params.key_len, + g_key_wep_params.key_idx); + } + + /*No matter the driver handler passed here, it will be overwriiten*/ + /*in Handle_FlushConnect() with gu8FlushedJoinReqDrvHandler*/ + host_int_flush_join_req(priv->hWILCWFIDrv); + + /*Add saved PTK and GTK keys, if any*/ + if (g_ptk_keys_saved && g_gtk_keys_saved) { + PRINT_D(CFG80211_DBG, "ptk %x %x %x cipher %x\n", g_key_ptk_params.key[0], + g_key_ptk_params.key[1], + g_key_ptk_params.key[2], + g_key_ptk_params.cipher); + PRINT_D(CFG80211_DBG, "gtk %x %x %x cipher %x\n", g_key_gtk_params.key[0], + g_key_gtk_params.key[1], + g_key_gtk_params.key[2], + g_key_gtk_params.cipher); + #if 1 + WILC_WFI_add_key(g_linux_wlan->strInterfaceInfo[0].wilc_netdev->ieee80211_ptr->wiphy, + g_linux_wlan->strInterfaceInfo[0].wilc_netdev, + g_add_ptk_key_params.key_idx, + g_add_ptk_key_params.pairwise, + g_add_ptk_key_params.mac_addr, + (struct key_params *)(&g_key_ptk_params)); + + WILC_WFI_add_key(g_linux_wlan->strInterfaceInfo[0].wilc_netdev->ieee80211_ptr->wiphy, + g_linux_wlan->strInterfaceInfo[0].wilc_netdev, + g_add_gtk_key_params.key_idx, + g_add_gtk_key_params.pairwise, + g_add_gtk_key_params.mac_addr, + (struct key_params *)(&g_key_gtk_params)); + #endif + } + #endif + + /*BugID_4847: registered frames in firmware are now*/ + /*lost due to mac close. So re-register those frames*/ + if (g_linux_wlan->wilc1000_initialized) { + for (i = 0; i < num_reg_frame; i++) { + PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + host_int_frame_register(priv->hWILCWFIDrv, + nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + } + } + #endif + #endif + break; + + default: + PRINT_ER("Unknown interface type= %d\n", type); + s32Error = -EINVAL; + return s32Error; + break; + } + + return s32Error; +} + +/* (austin.2013-07-23) + * + * To support revised cfg80211_ops + * + * add_beacon --> start_ap + * set_beacon --> change_beacon + * del_beacon --> stop_ap + * + * beacon_parameters --> cfg80211_ap_settings + * cfg80211_beacon_data + * + * applicable for linux kernel 3.4+ + */ + +/** + * @brief WILC_WFI_start_ap + * @details Add a beacon with given parameters, @head, @interval + * and @dtim_period will be valid, @tail is optional. + * @param[in] wiphy + * @param[in] dev The net device structure + * @param[in] settings cfg80211_ap_settings parameters for the beacon to be added + * @return int : Return 0 on Success. + * @author austin + * @date 23 JUL 2013 + * @version 1.0 + */ +static int WILC_WFI_start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *settings) +{ + struct cfg80211_beacon_data *beacon = &(settings->beacon); + struct WILC_WFI_priv *priv; + s32 s32Error = WILC_SUCCESS; + + priv = wiphy_priv(wiphy); + PRINT_D(HOSTAPD_DBG, "Starting ap\n"); + + PRINT_D(HOSTAPD_DBG, "Interval = %d \n DTIM period = %d\n Head length = %zu Tail length = %zu\n", + settings->beacon_interval, settings->dtim_period, beacon->head_len, beacon->tail_len); + + s32Error = WILC_WFI_CfgSetChannel(wiphy, &settings->chandef); + + if (s32Error != WILC_SUCCESS) + PRINT_ER("Error in setting channel\n"); + + linux_wlan_set_bssid(dev, g_linux_wlan->strInterfaceInfo[0].aSrcAddress); + + #ifndef WILC_FULLY_HOSTING_AP + s32Error = host_int_add_beacon(priv->hWILCWFIDrv, + settings->beacon_interval, + settings->dtim_period, + beacon->head_len, (u8 *)beacon->head, + beacon->tail_len, (u8 *)beacon->tail); + #else + s32Error = host_add_beacon(priv->hWILCWFIDrv, + settings->beacon_interval, + settings->dtim_period, + beacon->head_len, (u8 *)beacon->head, + beacon->tail_len, (u8 *)beacon->tail); + #endif + + return s32Error; +} + +/** + * @brief WILC_WFI_change_beacon + * @details Add a beacon with given parameters, @head, @interval + * and @dtim_period will be valid, @tail is optional. + * @param[in] wiphy + * @param[in] dev The net device structure + * @param[in] beacon cfg80211_beacon_data for the beacon to be changed + * @return int : Return 0 on Success. + * @author austin + * @date 23 JUL 2013 + * @version 1.0 + */ +static int WILC_WFI_change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *beacon) +{ + struct WILC_WFI_priv *priv; + s32 s32Error = WILC_SUCCESS; + + priv = wiphy_priv(wiphy); + PRINT_D(HOSTAPD_DBG, "Setting beacon\n"); + + +#ifndef WILC_FULLY_HOSTING_AP + s32Error = host_int_add_beacon(priv->hWILCWFIDrv, + 0, + 0, + beacon->head_len, (u8 *)beacon->head, + beacon->tail_len, (u8 *)beacon->tail); +#else + s32Error = host_add_beacon(priv->hWILCWFIDrv, + 0, + 0, + beacon->head_len, (u8 *)beacon->head, + beacon->tail_len, (u8 *)beacon->tail); +#endif + + return s32Error; +} + +/** + * @brief WILC_WFI_stop_ap + * @details Remove beacon configuration and stop sending the beacon. + * @param[in] + * @return int : Return 0 on Success. + * @author austin + * @date 23 JUL 2013 + * @version 1.0 + */ +static int WILC_WFI_stop_ap(struct wiphy *wiphy, struct net_device *dev) +{ + s32 s32Error = WILC_SUCCESS; + struct WILC_WFI_priv *priv; + u8 NullBssid[ETH_ALEN] = {0}; + + + WILC_NULLCHECK(s32Error, wiphy); + + priv = wiphy_priv(wiphy); + + PRINT_D(HOSTAPD_DBG, "Deleting beacon\n"); + + /*BugID_5188*/ + linux_wlan_set_bssid(dev, NullBssid); + + #ifndef WILC_FULLY_HOSTING_AP + s32Error = host_int_del_beacon(priv->hWILCWFIDrv); + #else + s32Error = host_del_beacon(priv->hWILCWFIDrv); + #endif + + WILC_ERRORCHECK(s32Error); + + WILC_CATCH(s32Error) + { + } + return s32Error; +} + +/** + * @brief WILC_WFI_add_station + * @details Add a new station. + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_add_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_parameters *params) +{ + s32 s32Error = WILC_SUCCESS; + struct WILC_WFI_priv *priv; + tstrWILC_AddStaParam strStaParams = {{0}}; + perInterface_wlan_t *nic; + + + WILC_NULLCHECK(s32Error, wiphy); + + priv = wiphy_priv(wiphy); + nic = netdev_priv(dev); + + if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) { + #ifndef WILC_FULLY_HOSTING_AP + + WILC_memcpy(strStaParams.au8BSSID, mac, ETH_ALEN); + WILC_memcpy(priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid], mac, ETH_ALEN); + strStaParams.u16AssocID = params->aid; + strStaParams.u8NumRates = params->supported_rates_len; + strStaParams.pu8Rates = params->supported_rates; + + PRINT_D(CFG80211_DBG, "Adding station parameters %d\n", params->aid); + + PRINT_D(CFG80211_DBG, "BSSID = %x%x%x%x%x%x\n", priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][0], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][1], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][2], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][3], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][4], + priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][5]); + PRINT_D(HOSTAPD_DBG, "ASSOC ID = %d\n", strStaParams.u16AssocID); + PRINT_D(HOSTAPD_DBG, "Number of supported rates = %d\n", strStaParams.u8NumRates); + + if (params->ht_capa == NULL) { + strStaParams.bIsHTSupported = false; + } else { + strStaParams.bIsHTSupported = true; + strStaParams.u16HTCapInfo = params->ht_capa->cap_info; + strStaParams.u8AmpduParams = params->ht_capa->ampdu_params_info; + WILC_memcpy(strStaParams.au8SuppMCsSet, ¶ms->ht_capa->mcs, WILC_SUPP_MCS_SET_SIZE); + strStaParams.u16HTExtParams = params->ht_capa->extended_ht_cap_info; + strStaParams.u32TxBeamformingCap = params->ht_capa->tx_BF_cap_info; + strStaParams.u8ASELCap = params->ht_capa->antenna_selection_info; + } + + strStaParams.u16FlagsMask = params->sta_flags_mask; + strStaParams.u16FlagsSet = params->sta_flags_set; + + PRINT_D(HOSTAPD_DBG, "IS HT supported = %d\n", strStaParams.bIsHTSupported); + PRINT_D(HOSTAPD_DBG, "Capability Info = %d\n", strStaParams.u16HTCapInfo); + PRINT_D(HOSTAPD_DBG, "AMPDU Params = %d\n", strStaParams.u8AmpduParams); + PRINT_D(HOSTAPD_DBG, "HT Extended params = %d\n", strStaParams.u16HTExtParams); + PRINT_D(HOSTAPD_DBG, "Tx Beamforming Cap = %d\n", strStaParams.u32TxBeamformingCap); + PRINT_D(HOSTAPD_DBG, "Antenna selection info = %d\n", strStaParams.u8ASELCap); + PRINT_D(HOSTAPD_DBG, "Flag Mask = %d\n", strStaParams.u16FlagsMask); + PRINT_D(HOSTAPD_DBG, "Flag Set = %d\n", strStaParams.u16FlagsSet); + + s32Error = host_int_add_station(priv->hWILCWFIDrv, &strStaParams); + WILC_ERRORCHECK(s32Error); + + #else + PRINT_D(CFG80211_DBG, "Adding station parameters %d\n", params->aid); + WILC_memcpy(priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid], mac, ETH_ALEN); + + PRINT_D(CFG80211_DBG, "BSSID = %x%x%x%x%x%x\n", priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][0], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][1], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][2], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][3], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][4], + priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][5]); + + WILC_AP_AddSta(mac, params); + WILC_ERRORCHECK(s32Error); + #endif /* WILC_FULLY_HOSTING_AP */ + + } + + WILC_CATCH(s32Error) + { + } + return s32Error; +} + +/** + * @brief WILC_WFI_del_station + * @details Remove a station; @mac may be NULL to remove all stations. + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_del_station(struct wiphy *wiphy, struct net_device *dev, + struct station_del_parameters *params) +{ + const u8 *mac = params->mac; + s32 s32Error = WILC_SUCCESS; + struct WILC_WFI_priv *priv; + perInterface_wlan_t *nic; + WILC_NULLCHECK(s32Error, wiphy); + + priv = wiphy_priv(wiphy); + nic = netdev_priv(dev); + + if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) { + PRINT_D(HOSTAPD_DBG, "Deleting station\n"); + + + if (mac == NULL) { + PRINT_D(HOSTAPD_DBG, "All associated stations \n"); + s32Error = host_int_del_allstation(priv->hWILCWFIDrv, priv->assoc_stainfo.au8Sta_AssociatedBss); + } else { + PRINT_D(HOSTAPD_DBG, "With mac address: %x%x%x%x%x%x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + + #ifndef WILC_FULLY_HOSTING_AP + s32Error = host_int_del_station(priv->hWILCWFIDrv, mac); + #else + WILC_AP_RemoveSta(mac); + #endif /* WILC_FULLY_HOSTING_AP */ + + WILC_ERRORCHECK(s32Error); + } + WILC_CATCH(s32Error) + { + } + return s32Error; +} + +/** + * @brief WILC_WFI_change_station + * @details Modify a given station. + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_change_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_parameters *params) +{ + s32 s32Error = WILC_SUCCESS; + struct WILC_WFI_priv *priv; + tstrWILC_AddStaParam strStaParams = {{0}}; + perInterface_wlan_t *nic; + + + PRINT_D(HOSTAPD_DBG, "Change station paramters\n"); + + WILC_NULLCHECK(s32Error, wiphy); + + priv = wiphy_priv(wiphy); + nic = netdev_priv(dev); + + if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) { + #ifndef WILC_FULLY_HOSTING_AP + + WILC_memcpy(strStaParams.au8BSSID, mac, ETH_ALEN); + strStaParams.u16AssocID = params->aid; + strStaParams.u8NumRates = params->supported_rates_len; + strStaParams.pu8Rates = params->supported_rates; + + PRINT_D(HOSTAPD_DBG, "BSSID = %x%x%x%x%x%x\n", strStaParams.au8BSSID[0], strStaParams.au8BSSID[1], strStaParams.au8BSSID[2], strStaParams.au8BSSID[3], strStaParams.au8BSSID[4], + strStaParams.au8BSSID[5]); + PRINT_D(HOSTAPD_DBG, "ASSOC ID = %d\n", strStaParams.u16AssocID); + PRINT_D(HOSTAPD_DBG, "Number of supported rates = %d\n", strStaParams.u8NumRates); + + if (params->ht_capa == NULL) { + strStaParams.bIsHTSupported = false; + } else { + strStaParams.bIsHTSupported = true; + strStaParams.u16HTCapInfo = params->ht_capa->cap_info; + strStaParams.u8AmpduParams = params->ht_capa->ampdu_params_info; + WILC_memcpy(strStaParams.au8SuppMCsSet, ¶ms->ht_capa->mcs, WILC_SUPP_MCS_SET_SIZE); + strStaParams.u16HTExtParams = params->ht_capa->extended_ht_cap_info; + strStaParams.u32TxBeamformingCap = params->ht_capa->tx_BF_cap_info; + strStaParams.u8ASELCap = params->ht_capa->antenna_selection_info; + + } + + strStaParams.u16FlagsMask = params->sta_flags_mask; + strStaParams.u16FlagsSet = params->sta_flags_set; + + PRINT_D(HOSTAPD_DBG, "IS HT supported = %d\n", strStaParams.bIsHTSupported); + PRINT_D(HOSTAPD_DBG, "Capability Info = %d\n", strStaParams.u16HTCapInfo); + PRINT_D(HOSTAPD_DBG, "AMPDU Params = %d\n", strStaParams.u8AmpduParams); + PRINT_D(HOSTAPD_DBG, "HT Extended params = %d\n", strStaParams.u16HTExtParams); + PRINT_D(HOSTAPD_DBG, "Tx Beamforming Cap = %d\n", strStaParams.u32TxBeamformingCap); + PRINT_D(HOSTAPD_DBG, "Antenna selection info = %d\n", strStaParams.u8ASELCap); + PRINT_D(HOSTAPD_DBG, "Flag Mask = %d\n", strStaParams.u16FlagsMask); + PRINT_D(HOSTAPD_DBG, "Flag Set = %d\n", strStaParams.u16FlagsSet); + + s32Error = host_int_edit_station(priv->hWILCWFIDrv, &strStaParams); + WILC_ERRORCHECK(s32Error); + + #else + WILC_AP_EditSta(mac, params); + WILC_ERRORCHECK(s32Error); + #endif /* WILC_FULLY_HOSTING_AP */ + + } + WILC_CATCH(s32Error) + { + } + return s32Error; +} + + +/** + * @brief WILC_WFI_add_virt_intf + * @details + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 JUL 2012 + * @version 1.0 + */ +struct wireless_dev *WILC_WFI_add_virt_intf(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + perInterface_wlan_t *nic; + struct WILC_WFI_priv *priv; + struct net_device *new_ifc = NULL; + priv = wiphy_priv(wiphy); + + + + PRINT_D(HOSTAPD_DBG, "Adding monitor interface[%p]\n", priv->wdev->netdev); + + nic = netdev_priv(priv->wdev->netdev); + + + if (type == NL80211_IFTYPE_MONITOR) { + PRINT_D(HOSTAPD_DBG, "Monitor interface mode: Initializing mon interface virtual device driver\n"); + PRINT_D(HOSTAPD_DBG, "Adding monitor interface[%p]\n", nic->wilc_netdev); + new_ifc = WILC_WFI_init_mon_interface(name, nic->wilc_netdev); + if (new_ifc != NULL) { + PRINT_D(HOSTAPD_DBG, "Setting monitor flag in private structure\n"); + #ifdef SIMULATION + priv = netdev_priv(priv->wdev->netdev); + priv->monitor_flag = 1; + #else + nic = netdev_priv(priv->wdev->netdev); + nic->monitor_flag = 1; + #endif + } else + PRINT_ER("Error in initializing monitor interface\n "); + } + return priv->wdev; +} + +/** + * @brief WILC_WFI_del_virt_intf + * @details + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 JUL 2012 + * @version 1.0 + */ +int WILC_WFI_del_virt_intf(struct wiphy *wiphy, struct wireless_dev *wdev) /* tony for v3.8 support */ +{ + PRINT_D(HOSTAPD_DBG, "Deleting virtual interface\n"); + return WILC_SUCCESS; +} + + + +#endif /*WILC_AP_EXTERNAL_MLME*/ +static struct cfg80211_ops WILC_WFI_cfg80211_ops = { + + .set_monitor_channel = WILC_WFI_CfgSetChannel, + .scan = WILC_WFI_CfgScan, + .connect = WILC_WFI_CfgConnect, + .disconnect = WILC_WFI_disconnect, + .add_key = WILC_WFI_add_key, + .del_key = WILC_WFI_del_key, + .get_key = WILC_WFI_get_key, + .set_default_key = WILC_WFI_set_default_key, + #ifdef WILC_AP_EXTERNAL_MLME + .add_virtual_intf = WILC_WFI_add_virt_intf, + .del_virtual_intf = WILC_WFI_del_virt_intf, + .change_virtual_intf = WILC_WFI_change_virt_intf, + + .start_ap = WILC_WFI_start_ap, + .change_beacon = WILC_WFI_change_beacon, + .stop_ap = WILC_WFI_stop_ap, + .add_station = WILC_WFI_add_station, + .del_station = WILC_WFI_del_station, + .change_station = WILC_WFI_change_station, + #endif /* WILC_AP_EXTERNAL_MLME*/ + #ifndef WILC_FULLY_HOSTING_AP + .get_station = WILC_WFI_get_station, + #endif + .dump_station = WILC_WFI_dump_station, + .change_bss = WILC_WFI_change_bss, + .set_wiphy_params = WILC_WFI_set_wiphy_params, + + .set_pmksa = WILC_WFI_set_pmksa, + .del_pmksa = WILC_WFI_del_pmksa, + .flush_pmksa = WILC_WFI_flush_pmksa, +#ifdef WILC_P2P + .remain_on_channel = WILC_WFI_remain_on_channel, + .cancel_remain_on_channel = WILC_WFI_cancel_remain_on_channel, + .mgmt_tx_cancel_wait = WILC_WFI_mgmt_tx_cancel_wait, + .mgmt_tx = WILC_WFI_mgmt_tx, + .mgmt_frame_register = WILC_WFI_frame_register, + .set_power_mgmt = WILC_WFI_set_power_mgmt, + .set_cqm_rssi_config = WILC_WFI_set_cqm_rssi_config, +#endif + +}; + + + + + +/** + * @brief WILC_WFI_update_stats + * @details Modify parameters for a given BSS. + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0WILC_WFI_set_cqmWILC_WFI_set_cqm_rssi_configWILC_WFI_set_cqm_rssi_configWILC_WFI_set_cqm_rssi_configWILC_WFI_set_cqm_rssi_config_rssi_config + */ +int WILC_WFI_update_stats(struct wiphy *wiphy, u32 pktlen, u8 changed) +{ + + struct WILC_WFI_priv *priv; + + priv = wiphy_priv(wiphy); +#if 1 + switch (changed) { + + case WILC_WFI_RX_PKT: + { + priv->netstats.rx_packets++; + priv->netstats.rx_bytes += pktlen; + priv->netstats.rx_time = get_jiffies_64(); + } + break; + + case WILC_WFI_TX_PKT: + { + priv->netstats.tx_packets++; + priv->netstats.tx_bytes += pktlen; + priv->netstats.tx_time = get_jiffies_64(); + + } + break; + + default: + break; + } +#endif + return 0; +} + +/** + * @brief WILC_WFI_CfgAlloc + * @details Allocation of the wireless device structure and assigning it + * to the cfg80211 operations structure. + * @param[in] NONE + * @return wireless_dev : Returns pointer to wireless_dev structure. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +struct wireless_dev *WILC_WFI_CfgAlloc(void) +{ + + struct wireless_dev *wdev; + + + PRINT_D(CFG80211_DBG, "Allocating wireless device\n"); + /*Allocating the wireless device structure*/ + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + PRINT_ER("Cannot allocate wireless device\n"); + goto _fail_; + } + + /*Creating a new wiphy, linking wireless structure with the wiphy structure*/ + wdev->wiphy = wiphy_new(&WILC_WFI_cfg80211_ops, sizeof(struct WILC_WFI_priv)); + if (!wdev->wiphy) { + PRINT_ER("Cannot allocate wiphy\n"); + goto _fail_mem_; + + } + + #ifdef WILC_AP_EXTERNAL_MLME + /* enable 802.11n HT */ + WILC_WFI_band_2ghz.ht_cap.ht_supported = 1; + WILC_WFI_band_2ghz.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + WILC_WFI_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; + WILC_WFI_band_2ghz.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K; + WILC_WFI_band_2ghz.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; + #endif + + /*wiphy bands*/ + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &WILC_WFI_band_2ghz; + + return wdev; + +_fail_mem_: + kfree(wdev); +_fail_: + return NULL; + +} +/** + * @brief WILC_WFI_WiphyRegister + * @details Registering of the wiphy structure and interface modes + * @param[in] NONE + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +struct wireless_dev *WILC_WFI_WiphyRegister(struct net_device *net) +{ + struct WILC_WFI_priv *priv; + struct wireless_dev *wdev; + s32 s32Error = WILC_SUCCESS; + + PRINT_D(CFG80211_DBG, "Registering wifi device\n"); + + wdev = WILC_WFI_CfgAlloc(); + if (wdev == NULL) { + PRINT_ER("CfgAlloc Failed\n"); + return NULL; + } + + + /*Return hardware description structure (wiphy)'s priv*/ + priv = wdev_priv(wdev); + sema_init(&(priv->SemHandleUpdateStats), 1); + + /*Link the wiphy with wireless structure*/ + priv->wdev = wdev; + + /*Maximum number of probed ssid to be added by user for the scan request*/ + wdev->wiphy->max_scan_ssids = MAX_NUM_PROBED_SSID; + /*Maximum number of pmkids to be cashed*/ + wdev->wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS; + PRINT_INFO(CFG80211_DBG, "Max number of PMKIDs = %d\n", wdev->wiphy->max_num_pmkids); + + wdev->wiphy->max_scan_ie_len = 1000; + + /*signal strength in mBm (100*dBm) */ + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + /*Set the availaible cipher suites*/ + wdev->wiphy->cipher_suites = cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + /*Setting default managment types: for register action frame: */ + wdev->wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types; + +#ifdef WILC_P2P + wdev->wiphy->max_remain_on_channel_duration = 500; + /*Setting the wiphy interfcae mode and type before registering the wiphy*/ + wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR) | BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT); + wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; +#else + wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR); +#endif + wdev->iftype = NL80211_IFTYPE_STATION; + + + + PRINT_INFO(CFG80211_DBG, "Max scan ids = %d,Max scan IE len = %d,Signal Type = %d,Interface Modes = %d,Interface Type = %d\n", + wdev->wiphy->max_scan_ssids, wdev->wiphy->max_scan_ie_len, wdev->wiphy->signal_type, + wdev->wiphy->interface_modes, wdev->iftype); + + #ifdef WILC_SDIO + set_wiphy_dev(wdev->wiphy, &local_sdio_func->dev); /* tony */ + #endif + + /*Register wiphy structure*/ + s32Error = wiphy_register(wdev->wiphy); + if (s32Error) { + PRINT_ER("Cannot register wiphy device\n"); + /*should define what action to be taken in such failure*/ + } else { + PRINT_D(CFG80211_DBG, "Successful Registering\n"); + } + + priv->dev = net; + return wdev; + + +} +/** + * @brief WILC_WFI_WiphyFree + * @details Freeing allocation of the wireless device structure + * @param[in] NONE + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_InitHostInt(struct net_device *net) +{ + + s32 s32Error = WILC_SUCCESS; + + struct WILC_WFI_priv *priv; + + PRINT_D(INIT_DBG, "Host[%p][%p]\n", net, net->ieee80211_ptr); + priv = wdev_priv(net->ieee80211_ptr); + if (op_ifcs == 0) { + s32Error = WILC_TimerCreate(&(hAgingTimer), remove_network_from_shadow, NULL); + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + s32Error = WILC_TimerCreate(&(hDuringIpTimer), clear_duringIP, NULL); + #endif + } + op_ifcs++; + if (s32Error < 0) { + PRINT_ER("Failed to creat refresh Timer\n"); + return s32Error; + } + + priv->gbAutoRateAdjusted = false; + + priv->bInP2PlistenState = false; + + sema_init(&(priv->hSemScanReq), 1); + s32Error = host_int_init(&priv->hWILCWFIDrv); + if (s32Error) { + PRINT_ER("Error while initializing hostinterface\n"); + } + return s32Error; +} + +/** + * @brief WILC_WFI_WiphyFree + * @details Freeing allocation of the wireless device structure + * @param[in] NONE + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_DeInitHostInt(struct net_device *net) +{ + s32 s32Error = WILC_SUCCESS; + + struct WILC_WFI_priv *priv; + priv = wdev_priv(net->ieee80211_ptr); + + priv->gbAutoRateAdjusted = false; + + priv->bInP2PlistenState = false; + + op_ifcs--; + + s32Error = host_int_deinit(priv->hWILCWFIDrv); + + /* Clear the Shadow scan */ + clear_shadow_scan(priv); + #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP + if (op_ifcs == 0) { + PRINT_D(CORECONFIG_DBG, "destroy during ip\n"); + WILC_TimerDestroy(&hDuringIpTimer, NULL); + } + #endif + + if (s32Error) { + PRINT_ER("Error while deintializing host interface\n"); + } + return s32Error; +} + + +/** + * @brief WILC_WFI_WiphyFree + * @details Freeing allocation of the wireless device structure + * @param[in] NONE + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void WILC_WFI_WiphyFree(struct net_device *net) +{ + + PRINT_D(CFG80211_DBG, "Unregistering wiphy\n"); + + if (net == NULL) { + PRINT_D(INIT_DBG, "net_device is NULL\n"); + return; + } + + if (net->ieee80211_ptr == NULL) { + PRINT_D(INIT_DBG, "ieee80211_ptr is NULL\n"); + return; + } + + if (net->ieee80211_ptr->wiphy == NULL) { + PRINT_D(INIT_DBG, "wiphy is NULL\n"); + return; + } + + wiphy_unregister(net->ieee80211_ptr->wiphy); + + PRINT_D(INIT_DBG, "Freeing wiphy\n"); + wiphy_free(net->ieee80211_ptr->wiphy); + kfree(net->ieee80211_ptr); + +} diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h new file mode 100644 index 000000000..c25350cb5 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h @@ -0,0 +1,129 @@ +/*! + * @file wilc_wfi_cfgoperations.h + * @brief Definitions for the network module + * @author syounan + * @sa wilc_oswrapper.h top level OS wrapper file + * @date 31 Aug 2010 + * @version 1.0 + */ +#ifndef NM_WFI_CFGOPERATIONS +#define NM_WFI_CFGOPERATIONS +#include "wilc_wfi_netdevice.h" + +#ifdef WILC_FULLY_HOSTING_AP +#include "wilc_host_ap.h" +#endif + + +/* The following macros describe the bitfield map used by the firmware to determine its 11i mode */ +#define NO_ENCRYPT 0 +#define ENCRYPT_ENABLED (1 << 0) +#define WEP (1 << 1) +#define WEP_EXTENDED (1 << 2) +#define WPA (1 << 3) +#define WPA2 (1 << 4) +#define AES (1 << 5) +#define TKIP (1 << 6) + +#ifdef WILC_P2P +/* #define USE_SUPPLICANT_GO_INTENT */ + +/*Public action frame index IDs*/ +#define FRAME_TYPE_ID 0 +#define ACTION_CAT_ID 24 +#define ACTION_SUBTYPE_ID 25 +#define P2P_PUB_ACTION_SUBTYPE 30 + +/*Public action frame Attribute IDs*/ +#define ACTION_FRAME 0xd0 +#define GO_INTENT_ATTR_ID 0x04 +#define CHANLIST_ATTR_ID 0x0b +#define OPERCHAN_ATTR_ID 0x11 +#ifdef USE_SUPPLICANT_GO_INTENT +#define GROUP_BSSID_ATTR_ID 0x07 +#endif +#define PUB_ACTION_ATTR_ID 0x04 +#define P2PELEM_ATTR_ID 0xdd + +/*Public action subtype values*/ +#define GO_NEG_REQ 0x00 +#define GO_NEG_RSP 0x01 +#define GO_NEG_CONF 0x02 +#define P2P_INV_REQ 0x03 +#define P2P_INV_RSP 0x04 +#define PUBLIC_ACT_VENDORSPEC 0x09 +#define GAS_INTIAL_REQ 0x0a +#define GAS_INTIAL_RSP 0x0b + +#define INVALID_CHANNEL 0 +#ifdef USE_SUPPLICANT_GO_INTENT +#define SUPPLICANT_GO_INTENT 6 +#define GET_GO_INTENT(a) (((a) >> 1) & 0x0f) +#define GET_TIE_BREAKER(a) (((a)) & 0x01) +#else +/* #define FORCE_P2P_CLIENT */ +#endif +#endif + +#define nl80211_SCAN_RESULT_EXPIRE (3 * HZ) +#define SCAN_RESULT_EXPIRE (40 * HZ) + +static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, +}; + +static const struct ieee80211_txrx_stypes + wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) + } +}; + +/* Time to stay on the channel */ +#define WILC_WFI_DWELL_PASSIVE 100 +#define WILC_WFI_DWELL_ACTIVE 40 + +struct wireless_dev *WILC_WFI_CfgAlloc(void); +struct wireless_dev *WILC_WFI_WiphyRegister(struct net_device *net); +void WILC_WFI_WiphyFree(struct net_device *net); +int WILC_WFI_update_stats(struct wiphy *wiphy, u32 pktlen, u8 changed); +int WILC_WFI_DeInitHostInt(struct net_device *net); +int WILC_WFI_InitHostInt(struct net_device *net); +void WILC_WFI_monitor_rx(uint8_t *buff, uint32_t size); +int WILC_WFI_deinit_mon_interface(void); +struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_device *real_dev); + +#ifdef TCP_ENHANCEMENTS +#define TCP_ACK_FILTER_LINK_SPEED_THRESH 54 +#define DEFAULT_LINK_SPEED 72 +extern void Enable_TCP_ACK_Filter(bool value); +#endif + +#endif diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c new file mode 100644 index 000000000..ab66ce4bd --- /dev/null +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.c @@ -0,0 +1,951 @@ +/*! + * @file wilc_wfi_netdevice.c + * @brief File Operations OS wrapper functionality + * @author mdaftedar + * @sa wilc_wfi_netdevice.h + * @date 01 MAR 2012 + * @version 1.0 + */ + +#ifdef SIMULATION + +#include "wilc_wfi_cfgoperations.h" +#include "host_interface.h" + + +MODULE_AUTHOR("Mai Daftedar"); +MODULE_LICENSE("Dual BSD/GPL"); + + +struct net_device *WILC_WFI_devs[2]; + +/* + * Transmitter lockup simulation, normally disabled. + */ +static int lockup; +module_param(lockup, int, 0); + +static int timeout = WILC_WFI_TIMEOUT; +module_param(timeout, int, 0); + +/* + * Do we run in NAPI mode? + */ +static int use_napi ; +module_param(use_napi, int, 0); + + +/* + * A structure representing an in-flight packet. + */ +struct WILC_WFI_packet { + struct WILC_WFI_packet *next; + struct net_device *dev; + int datalen; + u8 data[ETH_DATA_LEN]; +}; + + + +int pool_size = 8; +module_param(pool_size, int, 0); + + +static void WILC_WFI_TxTimeout(struct net_device *dev); +static void (*WILC_WFI_Interrupt)(int, void *, struct pt_regs *); + +/** + * @brief WILC_WFI_SetupPool + * @details Set up a device's packet pool. + * @param[in] struct net_device *dev : Network Device Pointer + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void WILC_WFI_SetupPool(struct net_device *dev) +{ + struct WILC_WFI_priv *priv = netdev_priv(dev); + int i; + struct WILC_WFI_packet *pkt; + + priv->ppool = NULL; + for (i = 0; i < pool_size; i++) { + pkt = kmalloc (sizeof (struct WILC_WFI_packet), GFP_KERNEL); + if (pkt == NULL) { + PRINT_D(RX_DBG, "Ran out of memory allocating packet pool\n"); + return; + } + pkt->dev = dev; + pkt->next = priv->ppool; + priv->ppool = pkt; + } +} + +/** + * @brief WILC_WFI_TearDownPool + * @details Internal cleanup function that's called after the network device + * driver is unregistered + * @param[in] struct net_device *dev : Network Device Driver + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void WILC_WFI_TearDownPool(struct net_device *dev) +{ + struct WILC_WFI_priv *priv = netdev_priv(dev); + struct WILC_WFI_packet *pkt; + + while ((pkt = priv->ppool)) { + priv->ppool = pkt->next; + kfree (pkt); + /* FIXME - in-flight packets ? */ + } +} + +/** + * @brief WILC_WFI_GetTxBuffer + * @details Buffer/pool management + * @param[in] net_device *dev : Network Device Driver Structure + * @return struct WILC_WFI_packet + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +struct WILC_WFI_packet *WILC_WFI_GetTxBuffer(struct net_device *dev) +{ + struct WILC_WFI_priv *priv = netdev_priv(dev); + unsigned long flags; + struct WILC_WFI_packet *pkt; + + spin_lock_irqsave(&priv->lock, flags); + pkt = priv->ppool; + priv->ppool = pkt->next; + if (priv->ppool == NULL) { + PRINT_INFO(RX_DBG, "Pool empty\n"); + netif_stop_queue(dev); + } + spin_unlock_irqrestore(&priv->lock, flags); + return pkt; +} +/** + * @brief WILC_WFI_ReleaseBuffer + * @details Buffer/pool management + * @param[in] WILC_WFI_packet *pkt : Structure holding in-flight packet + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void WILC_WFI_ReleaseBuffer(struct WILC_WFI_packet *pkt) +{ + unsigned long flags; + struct WILC_WFI_priv *priv = netdev_priv(pkt->dev); + + spin_lock_irqsave(&priv->lock, flags); + pkt->next = priv->ppool; + priv->ppool = pkt; + spin_unlock_irqrestore(&priv->lock, flags); + if (netif_queue_stopped(pkt->dev) && pkt->next == NULL) + netif_wake_queue(pkt->dev); +} + +/** + * @brief WILC_WFI_EnqueueBuf + * @details Enqueuing packets in an RX buffer queue + * @param[in] WILC_WFI_packet *pkt : Structure holding in-flight packet + * @param[in] net_device *dev : Network Device Driver Structure + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void WILC_WFI_EnqueueBuf(struct net_device *dev, struct WILC_WFI_packet *pkt) +{ + unsigned long flags; + struct WILC_WFI_priv *priv = netdev_priv(dev); + + spin_lock_irqsave(&priv->lock, flags); + pkt->next = priv->rx_queue; /* FIXME - misorders packets */ + priv->rx_queue = pkt; + spin_unlock_irqrestore(&priv->lock, flags); +} + +/** + * @brief WILC_WFI_DequeueBuf + * @details Dequeuing packets from the RX buffer queue + * @param[in] net_device *dev : Network Device Driver Structure + * @return WILC_WFI_packet *pkt : Structure holding in-flight pac + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +struct WILC_WFI_packet *WILC_WFI_DequeueBuf(struct net_device *dev) +{ + struct WILC_WFI_priv *priv = netdev_priv(dev); + struct WILC_WFI_packet *pkt; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + pkt = priv->rx_queue; + if (pkt != NULL) + priv->rx_queue = pkt->next; + spin_unlock_irqrestore(&priv->lock, flags); + return pkt; +} +/** + * @brief WILC_WFI_RxInts + * @details Enable and disable receive interrupts. + * @param[in] net_device *dev : Network Device Driver Structure + * @param[in] enable : Enable/Disable flag + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static void WILC_WFI_RxInts(struct net_device *dev, int enable) +{ + struct WILC_WFI_priv *priv = netdev_priv(dev); + priv->rx_int_enabled = enable; +} + +/** + * @brief WILC_WFI_Open + * @details Open Network Device Driver, called when the network + * interface is opened. It starts the interface's transmit queue. + * @param[in] net_device *dev : Network Device Driver Structure + * @param[in] enable : Enable/Disable flag + * @return int : Returns 0 upon success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_Open(struct net_device *dev) +{ + /* request_region(), request_irq(), .... (like fops->open) */ + /* + * Assign the hardware address of the board: use "\0SNULx", where + * x is 0 or 1. The first byte is '\0' to avoid being a multicast + * address (the first byte of multicast addrs is odd). + */ + memcpy(dev->dev_addr, "\0WLAN0", ETH_ALEN); + if (dev == WILC_WFI_devs[1]) + dev->dev_addr[ETH_ALEN - 1]++; /* \0SNUL1 */ + + WILC_WFI_InitHostInt(dev); + netif_start_queue(dev); + return 0; +} +/** + * @brief WILC_WFI_Release + * @details Release Network Device Driver, called when the network + * interface is stopped or brought down. This function marks + * the network driver as not being able to transmit + * @param[in] net_device *dev : Network Device Driver Structure + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_Release(struct net_device *dev) +{ + /* release ports, irq and such -- like fops->close */ + + netif_stop_queue(dev); /* can't transmit any more */ + + return 0; +} +/** + * @brief WILC_WFI_Config + * @details Configuration changes (passed on by ifconfig) + * @param[in] net_device *dev : Network Device Driver Structure + * @param[in] struct ifmap *map : Contains the ioctl implementation for the + * network driver. + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_Config(struct net_device *dev, struct ifmap *map) +{ + if (dev->flags & IFF_UP) /* can't act on a running interface */ + return -EBUSY; + + /* Don't allow changing the I/O address */ + if (map->base_addr != dev->base_addr) { + PRINT_D(RX_DBG, KERN_WARNING "WILC_WFI: Can't change I/O address\n"); + return -EOPNOTSUPP; + } + + /* Allow changing the IRQ */ + if (map->irq != dev->irq) { + dev->irq = map->irq; + /* request_irq() is delayed to open-time */ + } + + /* ignore other fields */ + return 0; +} +/** + * @brief WILC_WFI_Rx + * @details Receive a packet: retrieve, encapsulate and pass over to upper + * levels + * @param[in] net_device *dev : Network Device Driver Structure + * @param[in] WILC_WFI_packet : + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void WILC_WFI_Rx(struct net_device *dev, struct WILC_WFI_packet *pkt) +{ + int i; + struct sk_buff *skb; + struct WILC_WFI_priv *priv = netdev_priv(dev); + s8 rssi; + /* + * The packet has been retrieved from the transmission + * medium. Build an skb around it, so upper layers can handle it + */ + + + skb = dev_alloc_skb(pkt->datalen + 2); + if (!skb) { + if (printk_ratelimit()) + PRINT_D(RX_DBG, "WILC_WFI rx: low on mem - packet dropped\n"); + priv->stats.rx_dropped++; + goto out; + } + skb_reserve(skb, 2); /* align IP on 16B boundary */ + memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); + + if (priv->monitor_flag) { + PRINT_INFO(RX_DBG, "In monitor device name %s\n", dev->name); + priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); + PRINT_D(RX_DBG, "VALUE PASSED IN OF HRWD %p\n", priv->hWILCWFIDrv); + /* host_int_get_rssi(priv->hWILCWFIDrv, &(rssi)); */ + if (INFO) { + for (i = 14; i < skb->len; i++) + PRINT_INFO(RX_DBG, "RXdata[%d] %02x\n", i, skb->data[i]); + } + WILC_WFI_monitor_rx(dev, skb); + return; + } +out: + return; +} + +/** + * @brief WILC_WFI_Poll + * @details The poll implementation + * @param[in] struct napi_struct *napi : + * @param[in] int budget : + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int WILC_WFI_Poll(struct napi_struct *napi, int budget) +{ + int npackets = 0; + struct sk_buff *skb; + struct WILC_WFI_priv *priv = container_of(napi, struct WILC_WFI_priv, napi); + struct net_device *dev = priv->dev; + struct WILC_WFI_packet *pkt; + + while (npackets < budget && priv->rx_queue) { + pkt = WILC_WFI_DequeueBuf(dev); + skb = dev_alloc_skb(pkt->datalen + 2); + if (!skb) { + if (printk_ratelimit()) + PRINT_D(RX_DBG, "WILC_WFI: packet dropped\n"); + priv->stats.rx_dropped++; + WILC_WFI_ReleaseBuffer(pkt); + continue; + } + skb_reserve(skb, 2); /* align IP on 16B boundary */ + memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + netif_receive_skb(skb); + /* Maintain stats */ + npackets++; + WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, pkt->datalen, WILC_WFI_RX_PKT); + WILC_WFI_ReleaseBuffer(pkt); + } + /* If we processed all packets, we're done; tell the kernel and re-enable ints */ + if (npackets < budget) { + napi_complete(napi); + WILC_WFI_RxInts(dev, 1); + } + return npackets; +} + +/** + * @brief WILC_WFI_Poll + * @details The typical interrupt entry point + * @param[in] struct napi_struct *napi : + * @param[in] int budget : + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static void WILC_WFI_RegularInterrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int statusword; + struct WILC_WFI_priv *priv; + struct WILC_WFI_packet *pkt = NULL; + /* + * As usual, check the "device" pointer to be sure it is + * really interrupting. + * Then assign "struct device *dev" + */ + struct net_device *dev = (struct net_device *)dev_id; + /* ... and check with hw if it's really ours */ + + /* paranoid */ + if (!dev) + return; + + /* Lock the device */ + priv = netdev_priv(dev); + spin_lock(&priv->lock); + + /* retrieve statusword: real netdevices use I/O instructions */ + statusword = priv->status; + priv->status = 0; + if (statusword & WILC_WFI_RX_INTR) { + /* send it to WILC_WFI_rx for handling */ + pkt = priv->rx_queue; + if (pkt) { + priv->rx_queue = pkt->next; + WILC_WFI_Rx(dev, pkt); + } + } + if (statusword & WILC_WFI_TX_INTR) { + /* a transmission is over: free the skb */ + WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, priv->tx_packetlen, WILC_WFI_TX_PKT); + dev_kfree_skb(priv->skb); + } + + /* Unlock the device and we are done */ + spin_unlock(&priv->lock); + if (pkt) + WILC_WFI_ReleaseBuffer(pkt); /* Do this outside the lock! */ + return; +} +/** + * @brief WILC_WFI_NapiInterrupt + * @details A NAPI interrupt handler + * @param[in] irq: + * @param[in] dev_id: + * @param[in] pt_regs: + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static void WILC_WFI_NapiInterrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int statusword; + struct WILC_WFI_priv *priv; + + /* + * As usual, check the "device" pointer for shared handlers. + * Then assign "struct device *dev" + */ + struct net_device *dev = (struct net_device *)dev_id; + /* ... and check with hw if it's really ours */ + + /* paranoid */ + if (!dev) + return; + + /* Lock the device */ + priv = netdev_priv(dev); + spin_lock(&priv->lock); + + /* retrieve statusword: real netdevices use I/O instructions */ + statusword = priv->status; + priv->status = 0; + if (statusword & WILC_WFI_RX_INTR) { + WILC_WFI_RxInts(dev, 0); /* Disable further interrupts */ + napi_schedule(&priv->napi); + } + if (statusword & WILC_WFI_TX_INTR) { + /* a transmission is over: free the skb */ + + WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, priv->tx_packetlen, WILC_WFI_TX_PKT); + dev_kfree_skb(priv->skb); + } + + /* Unlock the device and we are done */ + spin_unlock(&priv->lock); + return; +} + +/** + * @brief MI_WFI_HwTx + * @details Transmit a packet (low level interface) + * @param[in] buf: + * @param[in] len: + * @param[in] net_device *dev: + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void WILC_WFI_HwTx(char *buf, int len, struct net_device *dev) +{ + /* + * This function deals with hw details. This interface loops + * back the packet to the other WILC_WFI interface (if any). + * In other words, this function implements the WILC_WFI behaviour, + * while all other procedures are rather device-independent + */ + struct iphdr *ih; + struct net_device *dest; + struct WILC_WFI_priv *priv; + u32 *saddr, *daddr; + struct WILC_WFI_packet *tx_buffer; + + + /* I am paranoid. Ain't I? */ + if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { + PRINT_D(RX_DBG, "WILC_WFI: Hmm... packet too short (%i octets)\n", + len); + return; + } + + if (0) { /* enable this conditional to look at the data */ + int i; + PRINT_D(RX_DBG, "len is %i", len); + for (i = 14; i < len; i++) + PRINT_D(RX_DBG, "TXdata[%d] %02x\n", i, buf[i] & 0xff); + /* PRINT_D(RX_DBG, "\n"); */ + } + /* + * Ethhdr is 14 bytes, but the kernel arranges for iphdr + * to be aligned (i.e., ethhdr is unaligned) + */ + ih = (struct iphdr *)(buf + sizeof(struct ethhdr)); + saddr = &ih->saddr; + daddr = &ih->daddr; + + ((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */ + ((u8 *)daddr)[2] ^= 1; + + ih->check = 0; /* and rebuild the checksum (ip needs it) */ + ih->check = ip_fast_csum((unsigned char *)ih, ih->ihl); + + + if (dev == WILC_WFI_devs[0]) + PRINT_D(RX_DBG, "%08x:%05i --> %08x:%05i\n", + ntohl(ih->saddr), ntohs(((struct tcphdr *)(ih + 1))->source), + ntohl(ih->daddr), ntohs(((struct tcphdr *)(ih + 1))->dest)); + else + PRINT_D(RX_DBG, "%08x:%05i <-- %08x:%05i\n", + ntohl(ih->daddr), ntohs(((struct tcphdr *)(ih + 1))->dest), + ntohl(ih->saddr), ntohs(((struct tcphdr *)(ih + 1))->source)); + + /* + * Ok, now the packet is ready for transmission: first simulate a + * receive interrupt on the twin device, then a + * transmission-done on the transmitting device + */ + dest = WILC_WFI_devs[dev == WILC_WFI_devs[0] ? 1 : 0]; + priv = netdev_priv(dest); + + tx_buffer = WILC_WFI_GetTxBuffer(dev); + tx_buffer->datalen = len; + memcpy(tx_buffer->data, buf, len); + WILC_WFI_EnqueueBuf(dest, tx_buffer); + if (priv->rx_int_enabled) { + priv->status |= WILC_WFI_RX_INTR; + WILC_WFI_Interrupt(0, dest, NULL); + } + + priv = netdev_priv(dev); + priv->tx_packetlen = len; + priv->tx_packetdata = buf; + priv->status |= WILC_WFI_TX_INTR; + if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0) { + /* Simulate a dropped transmit interrupt */ + netif_stop_queue(dev); + PRINT_D(RX_DBG, "Simulate lockup at %ld, txp %ld\n", jiffies, + (unsigned long) priv->stats.tx_packets); + } else + WILC_WFI_Interrupt(0, dev, NULL); + +} + +/** + * @brief WILC_WFI_Tx + * @details Transmit a packet (called by the kernel) + * @param[in] sk_buff *skb: + * @param[in] net_device *dev: + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_Tx(struct sk_buff *skb, struct net_device *dev) +{ + int len; + char *data, shortpkt[ETH_ZLEN]; + struct WILC_WFI_priv *priv = netdev_priv(dev); + + /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */ + + /* if(priv->monitor_flag) */ + /* mac80211_hwsim_monitor_rx(skb); */ + + + data = skb->data; + len = skb->len; + + if (len < ETH_ZLEN) { + memset(shortpkt, 0, ETH_ZLEN); + memcpy(shortpkt, skb->data, skb->len); + len = ETH_ZLEN; + data = shortpkt; + } + dev->trans_start = jiffies; /* save the timestamp */ + + /* Remember the skb, so we can free it at interrupt time */ + priv->skb = skb; + + /* actual deliver of data is device-specific, and not shown here */ + WILC_WFI_HwTx(data, len, dev); + + return 0; /* Our simple device can not fail */ +} + +/** + * @brief WILC_WFI_TxTimeout + * @details Deal with a transmit timeout. + * @param[in] net_device *dev: + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void WILC_WFI_TxTimeout(struct net_device *dev) +{ + struct WILC_WFI_priv *priv = netdev_priv(dev); + + PRINT_D(RX_DBG, "Transmit timeout at %ld, latency %ld\n", jiffies, + jiffies - dev->trans_start); + /* Simulate a transmission interrupt to get things moving */ + priv->status = WILC_WFI_TX_INTR; + WILC_WFI_Interrupt(0, dev, NULL); + priv->stats.tx_errors++; + netif_wake_queue(dev); + return; +} + +/** + * @brief WILC_WFI_Ioctl + * @details Ioctl commands + * @param[in] net_device *dev: + * @param[in] ifreq *rq + * @param[in] cmd: + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_Ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + PRINT_D(RX_DBG, "ioctl\n"); + return 0; +} + +/** + * @brief WILC_WFI_Stat + * @details Return statistics to the caller + * @param[in] net_device *dev: + * @return WILC_WFI_Stats : Return net_device_stats stucture with the + * network device driver private data contents. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +struct net_device_stats *WILC_WFI_Stats(struct net_device *dev) +{ + struct WILC_WFI_priv *priv = netdev_priv(dev); + return &priv->stats; +} + +/** + * @brief WILC_WFI_RebuildHeader + * @details This function is called to fill up an eth header, since arp is not + * available on the interface + * @param[in] sk_buff *skb: + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_RebuildHeader(struct sk_buff *skb) +{ + struct ethhdr *eth = (struct ethhdr *) skb->data; + struct net_device *dev = skb->dev; + + memcpy(eth->h_source, dev->dev_addr, dev->addr_len); + memcpy(eth->h_dest, dev->dev_addr, dev->addr_len); + eth->h_dest[ETH_ALEN - 1] ^= 0x01; /* dest is us xor 1 */ + return 0; +} +/** + * @brief WILC_WFI_RebuildHeader + * @details This function is called to fill up an eth header, since arp is not + * available on the interface + * @param[in] sk_buff *skb: + * @param[in] struct net_device *dev: + * @param[in] unsigned short type: + * @param[in] const void *saddr, + * @param[in] const void *daddr: + * @param[in] unsigned int len + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_Header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, const void *saddr, + unsigned int len) +{ + struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); + + eth->h_proto = htons(type); + memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len); + memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len); + eth->h_dest[ETH_ALEN - 1] ^= 0x01; /* dest is us xor 1 */ + return dev->hard_header_len; +} + +/** + * @brief WILC_WFI_ChangeMtu + * @details The "change_mtu" method is usually not needed. + * If you need it, it must be like this. + * @param[in] net_device *dev : Network Device Driver Structure + * @param[in] new_mtu : + * @return int : Returns 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_ChangeMtu(struct net_device *dev, int new_mtu) +{ + unsigned long flags; + struct WILC_WFI_priv *priv = netdev_priv(dev); + spinlock_t *lock = &priv->lock; + + /* check ranges */ + if ((new_mtu < 68) || (new_mtu > 1500)) + return -EINVAL; + /* + * Do anything you need, and the accept the value + */ + spin_lock_irqsave(lock, flags); + dev->mtu = new_mtu; + spin_unlock_irqrestore(lock, flags); + return 0; /* success */ +} + +static const struct header_ops WILC_WFI_header_ops = { + .create = WILC_WFI_Header, + .rebuild = WILC_WFI_RebuildHeader, + .cache = NULL, /* disable caching */ +}; + + +static const struct net_device_ops WILC_WFI_netdev_ops = { + .ndo_open = WILC_WFI_Open, + .ndo_stop = WILC_WFI_Release, + .ndo_set_config = WILC_WFI_Config, + .ndo_start_xmit = WILC_WFI_Tx, + .ndo_do_ioctl = WILC_WFI_Ioctl, + .ndo_get_stats = WILC_WFI_Stats, + .ndo_change_mtu = WILC_WFI_ChangeMtu, + .ndo_tx_timeout = WILC_WFI_TxTimeout, +}; + +/** + * @brief WILC_WFI_Init + * @details The init function (sometimes called probe). + * It is invoked by register_netdev() + * @param[in] net_device *dev: + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void WILC_WFI_Init(struct net_device *dev) +{ + struct WILC_WFI_priv *priv; + + + /* + * Then, assign other fields in dev, using ether_setup() and some + * hand assignments + */ + ether_setup(dev); /* assign some of the fields */ + /* 1- Allocate space */ + + dev->netdev_ops = &WILC_WFI_netdev_ops; + dev->header_ops = &WILC_WFI_header_ops; + dev->watchdog_timeo = timeout; + /* keep the default flags, just add NOARP */ + dev->flags |= IFF_NOARP; + dev->features |= NETIF_F_NO_CSUM; + /* + * Then, initialize the priv field. This encloses the statistics + * and a few private fields. + */ + priv = netdev_priv(dev); + memset(priv, 0, sizeof(struct WILC_WFI_priv)); + priv->dev = dev; + netif_napi_add(dev, &priv->napi, WILC_WFI_Poll, 2); + /* The last parameter above is the NAPI "weight". */ + spin_lock_init(&priv->lock); + WILC_WFI_RxInts(dev, 1); /* enable receive interrupts */ + WILC_WFI_SetupPool(dev); +} + +/** + * @brief WILC_WFI_Stat + * @details Return statistics to the caller + * @param[in] net_device *dev: + * @return WILC_WFI_Stats : Return net_device_stats stucture with the + * network device driver private data contents. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ + +void WILC_WFI_Cleanup(void) +{ + int i; + struct WILC_WFI_priv *priv[2]; + + /*if(hwsim_mon!=NULL) + * { + * PRINT_D(RX_DBG, "Freeing monitor interface\n"); + * unregister_netdev(hwsim_mon); + * free_netdev(hwsim_mon); + * }*/ + for (i = 0; i < 2; i++) { + priv[i] = netdev_priv(WILC_WFI_devs[i]); + + if (WILC_WFI_devs[i]) { + PRINT_D(RX_DBG, "Unregistering\n"); + unregister_netdev(WILC_WFI_devs[i]); + WILC_WFI_TearDownPool(WILC_WFI_devs[i]); + free_netdev(WILC_WFI_devs[i]); + PRINT_D(RX_DBG, "[NETDEV]Stopping interface\n"); + WILC_WFI_DeInitHostInt(WILC_WFI_devs[i]); + WILC_WFI_WiphyFree(WILC_WFI_devs[i]); + } + + } + /* unregister_netdev(hwsim_mon); */ + WILC_WFI_deinit_mon_interface(); + return; +} + + +void StartConfigSim(void); + + + + + + + +/** + * @brief WILC_WFI_Stat + * @details Return statistics to the caller + * @param[in] net_device *dev: + * @return WILC_WFI_Stats : Return net_device_stats stucture with the + * network device driver private data contents. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_InitModule(void) +{ + + int result, i, ret = -ENOMEM; + struct WILC_WFI_priv *priv[2], *netpriv; + struct wireless_dev *wdev; + WILC_WFI_Interrupt = use_napi ? WILC_WFI_NapiInterrupt : WILC_WFI_RegularInterrupt; + char buf[IFNAMSIZ]; + + for (i = 0; i < 2; i++) { + + /* Allocate the net devices */ + WILC_WFI_devs[i] = alloc_netdev(sizeof(struct WILC_WFI_priv), "wlan%d", + WILC_WFI_Init); + if (WILC_WFI_devs[i] == NULL) + goto out; + /* priv[i] = netdev_priv(WILC_WFI_devs[i]); */ + + wdev = WILC_WFI_WiphyRegister(WILC_WFI_devs[i]); + WILC_WFI_devs[i]->ieee80211_ptr = wdev; + netpriv = netdev_priv(WILC_WFI_devs[i]); + netpriv->dev->ieee80211_ptr = wdev; + netpriv->dev->ml_priv = netpriv; + wdev->netdev = netpriv->dev; + + /*Registering the net device*/ + result = register_netdev(WILC_WFI_devs[i]); + if (result) + PRINT_D(RX_DBG, "WILC_WFI: error %i registering device \"%s\"\n", + result, WILC_WFI_devs[i]->name); + else + ret = 0; + } + + + /*init atmel driver */ + priv[0] = netdev_priv(WILC_WFI_devs[0]); + priv[1] = netdev_priv(WILC_WFI_devs[1]); + + if (priv[1]->dev->ieee80211_ptr->wiphy->interface_modes && BIT(NL80211_IFTYPE_MONITOR)) { + /* snprintf(buf, IFNAMSIZ, "mon.%s", priv[1]->dev->name); */ + /* WILC_WFI_init_mon_interface(); */ + /* priv[1]->monitor_flag = 1; */ + + } + priv[0]->bCfgScanning = false; + priv[0]->u32RcvdChCount = 0; + + WILC_memset(priv[0]->au8AssociatedBss, 0xFF, ETH_ALEN); + + + /* ret = host_int_init(&priv[0]->hWILCWFIDrv); */ + /*copy handle to the other driver*/ + /* priv[1]->hWILCWFIDrv = priv[0]->hWILCWFIDrv; */ + if (ret) { + PRINT_ER("Error Init Driver\n"); + } + + +out: + if (ret) + WILC_WFI_Cleanup(); + return ret; + + +} + + +module_init(WILC_WFI_InitModule); +module_exit(WILC_WFI_Cleanup); + +#endif diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h new file mode 100644 index 000000000..d413fa386 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -0,0 +1,254 @@ +/*! + * @file wilc_wfi_netdevice.h + * @brief Definitions for the network module + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +#ifndef WILC_WFI_NETDEVICE +#define WILC_WFI_NETDEVICE + +/* These are the flags in the statusword */ +#define WILC_WFI_RX_INTR 0x0001 +#define WILC_WFI_TX_INTR 0x0002 + +/* Default timeout period */ +#define WILC_WFI_TIMEOUT 5 /* In jiffies */ +#define WILC_MAX_NUM_PMKIDS 16 +#define PMKID_LEN 16 +#define PMKID_FOUND 1 + #define NUM_STA_ASSOCIATED 8 + +#include +#include +#include +#include +#include +#include /* kmalloc() */ +#include /* error codes */ +#include /* size_t */ +#include /* mark_bh */ +#include +#include +#include /* struct device, and other headers */ +#include /* eth_type_trans */ +#include /* struct iphdr */ +#include /* struct tcphdr */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "host_interface.h" +#include "wilc_wlan.h" +#include /* tony, 2013-06-12 */ + +#define FLOW_CONTROL_LOWER_THRESHOLD 128 +#define FLOW_CONTROL_UPPER_THRESHOLD 256 + +/*iftype*/ +enum stats_flags { + WILC_WFI_RX_PKT = 1 << 0, + WILC_WFI_TX_PKT = 1 << 1, +}; + +struct WILC_WFI_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + u64 rx_time; + u64 tx_time; + +}; + +/* + * This structure is private to each device. It is used to pass + * packets in and out, so there is place for a packet + */ + +#define RX_BH_KTHREAD 0 +#define RX_BH_WORK_QUEUE 1 +#define RX_BH_THREADED_IRQ 2 +#define num_reg_frame 2 +/* + * If you use RX_BH_WORK_QUEUE on LPC3131: You may lose the first interrupt on + * LPC3131 which is important to get the MAC start status when you are blocked inside + * linux_wlan_firmware_download() which blocks mac_open(). + */ +#if defined (NM73131_0_BOARD) + #define RX_BH_TYPE RX_BH_KTHREAD +#elif defined (PANDA_BOARD) + #define RX_BH_TYPE RX_BH_THREADED_IRQ +#else + #define RX_BH_TYPE RX_BH_KTHREAD +#endif + +struct wilc_wfi_key { + u8 *key; + u8 *seq; + int key_len; + int seq_len; + u32 cipher; +}; +struct wilc_wfi_wep_key { + u8 *key; + u8 key_len; + u8 key_idx; +}; + +struct sta_info { + u8 au8Sta_AssociatedBss[MAX_NUM_STA][ETH_ALEN]; +}; + +#ifdef WILC_P2P +/*Parameters needed for host interface for remaining on channel*/ +struct wilc_wfi_p2pListenParams { + struct ieee80211_channel *pstrListenChan; + enum nl80211_channel_type tenuChannelType; + u32 u32ListenDuration; + u64 u64ListenCookie; + u32 u32ListenSessionID; +}; + +#endif /*WILC_P2P*/ + +struct WILC_WFI_priv { + struct wireless_dev *wdev; + struct cfg80211_scan_request *pstrScanReq; + + #ifdef WILC_P2P + struct wilc_wfi_p2pListenParams strRemainOnChanParams; + u64 u64tx_cookie; + #endif + + bool bCfgScanning; + u32 u32RcvdChCount; + + u8 au8AssociatedBss[ETH_ALEN]; + struct sta_info assoc_stainfo; + struct net_device_stats stats; + u8 monitor_flag; + int status; + struct WILC_WFI_packet *ppool; + struct WILC_WFI_packet *rx_queue; /* List of incoming packets */ + int rx_int_enabled; + int tx_packetlen; + u8 *tx_packetdata; + struct sk_buff *skb; + spinlock_t lock; + struct net_device *dev; + struct napi_struct napi; + WILC_WFIDrvHandle hWILCWFIDrv; + WILC_WFIDrvHandle hWILCWFIDrv_2; + tstrHostIFpmkidAttr pmkid_list; + struct WILC_WFI_stats netstats; + u8 WILC_WFI_wep_default; + u8 WILC_WFI_wep_key[4][WLAN_KEY_LEN_WEP104]; + u8 WILC_WFI_wep_key_len[4]; + struct net_device *real_ndev; /* The real interface that the monitor is on */ + struct wilc_wfi_key *wilc_gtk[MAX_NUM_STA]; + struct wilc_wfi_key *wilc_ptk[MAX_NUM_STA]; + u8 wilc_groupkey; + /* semaphores */ + struct semaphore SemHandleUpdateStats; + struct semaphore hSemScanReq; + /* */ + bool gbAutoRateAdjusted; + + bool bInP2PlistenState; + +}; + +typedef struct { + u16 frame_type; + bool reg; + +} struct_frame_reg; + +#define NUM_CONCURRENT_IFC 2 +typedef struct { + uint8_t aSrcAddress[ETH_ALEN]; + uint8_t aBSSID[ETH_ALEN]; + uint32_t drvHandler; + struct net_device *wilc_netdev; +} tstrInterfaceInfo; +typedef struct { + int mac_status; + int wilc1000_initialized; + #if (!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO) + unsigned short dev_irq_num; + #endif + wilc_wlan_oup_t oup; + int close; + uint8_t u8NoIfcs; + tstrInterfaceInfo strInterfaceInfo[NUM_CONCURRENT_IFC]; + uint8_t open_ifcs; + struct mutex txq_cs; + + /*Added by Amr - BugID_4720*/ + struct mutex txq_add_to_head_cs; + spinlock_t txq_spinlock; + + struct mutex rxq_cs; + struct mutex hif_cs; + + /* struct mutex txq_event; */ + struct semaphore rxq_event; + struct semaphore cfg_event; + struct semaphore sync_event; + + struct semaphore txq_event; + /* struct completion txq_event; */ + +#if (RX_BH_TYPE == RX_BH_WORK_QUEUE) + struct work_struct rx_work_queue; +#elif (RX_BH_TYPE == RX_BH_KTHREAD) + struct task_struct *rx_bh_thread; + struct semaphore rx_sem; +#endif + struct semaphore rxq_thread_started; + struct semaphore txq_thread_started; + + struct task_struct *rxq_thread; + struct task_struct *txq_thread; + + unsigned char eth_src_address[NUM_CONCURRENT_IFC][6]; + /* unsigned char eth_dst_address[6]; */ + + const struct firmware *wilc_firmware; /* Bug 4703 */ + + struct net_device *real_ndev; +#ifdef WILC_SDIO + int already_claim; + struct sdio_func *wilc_sdio_func; +#else + struct spi_device *wilc_spidev; +#endif + +} linux_wlan_t; + +typedef struct { + uint8_t u8IfIdx; + u8 iftype; + int monitor_flag; + int mac_opened; + #ifdef WILC_P2P + struct_frame_reg g_struct_frame_reg[num_reg_frame]; + #endif + struct net_device *wilc_netdev; + struct net_device_stats netstats; + +} perInterface_wlan_t; + +struct WILC_WFI_mon_priv { + struct net_device *real_ndev; +}; + +extern struct net_device *WILC_WFI_devs[]; + +#endif diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c new file mode 100644 index 000000000..3af91f770 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -0,0 +1,2332 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_wlan.c */ +/* */ +/* */ +/* //////////////////////////////////////////////////////////////////////////// */ + +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" +#define INLINE static __inline + +/******************************************** + * + * Global + * + ********************************************/ +extern unsigned int int_clrd; +extern wilc_hif_func_t hif_sdio; +extern wilc_hif_func_t hif_spi; +extern wilc_cfg_func_t mac_cfg; +#if defined(PLAT_RK3026_TCHIP) +extern u8 g_wilc_initialized; /* AMR : 0422 RK3026 Crash issue */ +#endif +extern void WILC_WFI_mgmt_rx(uint8_t *buff, uint32_t size); +extern void frmw_to_linux(uint8_t *buff, uint32_t size); +int sdio_xfer_cnt(void); +uint32_t wilc_get_chipid(uint8_t update); +u16 Set_machw_change_vir_if(bool bValue); + + + +typedef struct { + int quit; + + /** + * input interface functions + **/ + wilc_wlan_os_func_t os_func; + wilc_wlan_io_func_t io_func; + wilc_wlan_net_func_t net_func; + wilc_wlan_indicate_func_t indicate_func; + + /** + * host interface functions + **/ + wilc_hif_func_t hif_func; + void *hif_lock; + + /** + * configuration interface functions + **/ + wilc_cfg_func_t cif_func; + int cfg_frame_in_use; + wilc_cfg_frame_t cfg_frame; + uint32_t cfg_frame_offset; + int cfg_seq_no; + void *cfg_wait; + + /** + * RX buffer + **/ + #ifdef MEMORY_STATIC + uint32_t rx_buffer_size; + uint8_t *rx_buffer; + uint32_t rx_buffer_offset; + #endif + /** + * TX buffer + **/ + uint32_t tx_buffer_size; + uint8_t *tx_buffer; + uint32_t tx_buffer_offset; + + /** + * TX queue + **/ + void *txq_lock; + + /*Added by Amr - BugID_4720*/ + void *txq_add_to_head_lock; + void *txq_spinlock; + unsigned long txq_spinlock_flags; + + struct txq_entry_t *txq_head; + struct txq_entry_t *txq_tail; + int txq_entries; + void *txq_wait; + int txq_exit; + + /** + * RX queue + **/ + void *rxq_lock; + struct rxq_entry_t *rxq_head; + struct rxq_entry_t *rxq_tail; + int rxq_entries; + void *rxq_wait; + int rxq_exit; + + +} wilc_wlan_dev_t; + +static wilc_wlan_dev_t g_wlan; + +INLINE void chip_allow_sleep(void); +INLINE void chip_wakeup(void); +/******************************************** + * + * Debug + * + ********************************************/ + +static uint32_t dbgflag = N_INIT | N_ERR | N_INTR | N_TXQ | N_RXQ; + +static void wilc_debug(uint32_t flag, char *fmt, ...) +{ + char buf[256]; + va_list args; + int len; + + if (flag & dbgflag) { + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + if (g_wlan.os_func.os_debug) + g_wlan.os_func.os_debug(buf); + } + + return; +} + +static CHIP_PS_STATE_T genuChipPSstate = CHIP_WAKEDUP; + +/*BugID_5213*/ +/*acquire_bus() and release_bus() are made INLINE functions*/ +/*as a temporary workaround to fix a problem of receiving*/ +/*unknown interrupt from FW*/ +INLINE void acquire_bus(BUS_ACQUIRE_T acquire) +{ + + g_wlan.os_func.os_enter_cs(g_wlan.hif_lock); + #ifndef WILC_OPTIMIZE_SLEEP_INT + if (genuChipPSstate != CHIP_WAKEDUP) + #endif + { + if (acquire == ACQUIRE_AND_WAKEUP) + chip_wakeup(); + } + +} +INLINE void release_bus(BUS_RELEASE_T release) +{ + #ifdef WILC_OPTIMIZE_SLEEP_INT + if (release == RELEASE_ALLOW_SLEEP) + chip_allow_sleep(); + #endif + g_wlan.os_func.os_leave_cs(g_wlan.hif_lock); +} +/******************************************** + * + * Queue + * + ********************************************/ + +static void wilc_wlan_txq_remove(struct txq_entry_t *tqe) +{ + + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + /* unsigned long flags; */ + if (tqe == p->txq_head) { + + p->txq_head = tqe->next; + if (p->txq_head) + p->txq_head->prev = NULL; + + + } else if (tqe == p->txq_tail) { + p->txq_tail = (tqe->prev); + if (p->txq_tail) + p->txq_tail->next = NULL; + } else { + tqe->prev->next = tqe->next; + tqe->next->prev = tqe->prev; + } + p->txq_entries -= 1; + +} + +static struct txq_entry_t *wilc_wlan_txq_remove_from_head(void) +{ + struct txq_entry_t *tqe; + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + unsigned long flags; + p->os_func.os_spin_lock(p->txq_spinlock, &flags); + if (p->txq_head) { + tqe = p->txq_head; + p->txq_head = tqe->next; + if (p->txq_head) { + p->txq_head->prev = NULL; + } + p->txq_entries -= 1; + + /*Added by Amr - BugID_4720*/ + + + + } else { + tqe = NULL; + } + p->os_func.os_spin_unlock(p->txq_spinlock, &flags); + return tqe; +} + +static void wilc_wlan_txq_add_to_tail(struct txq_entry_t *tqe) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + unsigned long flags; + /*Added by Amr - BugID_4720*/ + p->os_func.os_spin_lock(p->txq_spinlock, &flags); + + if (p->txq_head == NULL) { + tqe->next = NULL; + tqe->prev = NULL; + p->txq_head = tqe; + p->txq_tail = tqe; + } else { + tqe->next = NULL; + tqe->prev = p->txq_tail; + p->txq_tail->next = tqe; + p->txq_tail = tqe; + } + p->txq_entries += 1; + PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries); + + /*Added by Amr - BugID_4720*/ + p->os_func.os_spin_unlock(p->txq_spinlock, &flags); + + /** + * wake up TX queue + **/ + PRINT_D(TX_DBG, "Wake the txq_handling\n"); + + p->os_func.os_signal(p->txq_wait); + + +} + +static int wilc_wlan_txq_add_to_head(struct txq_entry_t *tqe) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + unsigned long flags; + /*Added by Amr - BugID_4720*/ + if (p->os_func.os_wait(p->txq_add_to_head_lock, CFG_PKTS_TIMEOUT)) + return -1; + + p->os_func.os_spin_lock(p->txq_spinlock, &flags); + + if (p->txq_head == NULL) { + tqe->next = NULL; + tqe->prev = NULL; + p->txq_head = tqe; + p->txq_tail = tqe; + } else { + tqe->next = p->txq_head; + tqe->prev = NULL; + p->txq_head->prev = tqe; + p->txq_head = tqe; + } + p->txq_entries += 1; + PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries); + + /*Added by Amr - BugID_4720*/ + p->os_func.os_spin_unlock(p->txq_spinlock, &flags); + p->os_func.os_signal(p->txq_add_to_head_lock); + + + /** + * wake up TX queue + **/ + p->os_func.os_signal(p->txq_wait); + PRINT_D(TX_DBG, "Wake up the txq_handler\n"); + + /*Added by Amr - BugID_4720*/ + return 0; + +} + +uint32_t Statisitcs_totalAcks = 0, Statisitcs_DroppedAcks = 0; + +#ifdef TCP_ACK_FILTER +struct Ack_session_info; +typedef struct Ack_session_info { + uint32_t Ack_seq_num; + uint32_t Bigger_Ack_num; + uint16_t src_port; + uint16_t dst_port; + uint16_t status; +} Ack_session_info_t; + +typedef struct { + uint32_t ack_num; + uint32_t Session_index; + struct txq_entry_t *txqe; +} Pending_Acks_info_t /*Ack_info_t*/; + + + + +struct Ack_session_info *Free_head; +struct Ack_session_info *Alloc_head; + +#define TCP_FIN_MASK (1 << 0) +#define TCP_SYN_MASK (1 << 1) +#define TCP_Ack_MASK (1 << 4) +#define NOT_TCP_ACK (-1) + +#define MAX_TCP_SESSION 25 +#define MAX_PENDING_ACKS 256 +Ack_session_info_t Acks_keep_track_info[2 * MAX_TCP_SESSION]; +Pending_Acks_info_t Pending_Acks_info[MAX_PENDING_ACKS]; + +uint32_t PendingAcks_arrBase; +uint32_t Opened_TCP_session; +uint32_t Pending_Acks; + + + +static __inline int Init_TCP_tracking(void) +{ + + return 0; + +} +static __inline int add_TCP_track_session(uint32_t src_prt, uint32_t dst_prt, uint32_t seq) +{ + Acks_keep_track_info[Opened_TCP_session].Ack_seq_num = seq; + Acks_keep_track_info[Opened_TCP_session].Bigger_Ack_num = 0; + Acks_keep_track_info[Opened_TCP_session].src_port = src_prt; + Acks_keep_track_info[Opened_TCP_session].dst_port = dst_prt; + Opened_TCP_session++; + + PRINT_D(TCP_ENH, "TCP Session %d to Ack %d\n", Opened_TCP_session, seq); + return 0; +} + +static __inline int Update_TCP_track_session(uint32_t index, uint32_t Ack) +{ + + if (Ack > Acks_keep_track_info[index].Bigger_Ack_num) { + Acks_keep_track_info[index].Bigger_Ack_num = Ack; + } + return 0; + +} +static __inline int add_TCP_Pending_Ack(uint32_t Ack, uint32_t Session_index, struct txq_entry_t *txqe) +{ + Statisitcs_totalAcks++; + if (Pending_Acks < MAX_PENDING_ACKS) { + Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].ack_num = Ack; + Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].txqe = txqe; + Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].Session_index = Session_index; + txqe->tcp_PendingAck_index = PendingAcks_arrBase + Pending_Acks; + Pending_Acks++; + + } else { + + } + return 0; +} +static __inline int remove_TCP_related(void) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + unsigned long flags; + p->os_func.os_spin_lock(p->txq_spinlock, &flags); + + p->os_func.os_spin_unlock(p->txq_spinlock, &flags); + return 0; +} + +static __inline int tcp_process(struct txq_entry_t *tqe) +{ + int ret; + uint8_t *eth_hdr_ptr; + uint8_t *buffer = tqe->buffer; + unsigned short h_proto; + int i; + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + unsigned long flags; + p->os_func.os_spin_lock(p->txq_spinlock, &flags); + + eth_hdr_ptr = &buffer[0]; + h_proto = ntohs(*((unsigned short *)ð_hdr_ptr[12])); + if (h_proto == 0x0800) { /* IP */ + uint8_t *ip_hdr_ptr; + uint8_t protocol; + + ip_hdr_ptr = &buffer[ETHERNET_HDR_LEN]; + protocol = ip_hdr_ptr[9]; + + + if (protocol == 0x06) { + uint8_t *tcp_hdr_ptr; + uint32_t IHL, Total_Length, Data_offset; + tcp_hdr_ptr = &ip_hdr_ptr[IP_HDR_LEN]; + IHL = (ip_hdr_ptr[0] & 0xf) << 2; + Total_Length = (((uint32_t)ip_hdr_ptr[2]) << 8) + ((uint32_t)ip_hdr_ptr[3]); + Data_offset = (((uint32_t)tcp_hdr_ptr[12] & 0xf0) >> 2); + if (Total_Length == (IHL + Data_offset)) { /*we want to recognize the clear Acks(packet only carry Ack infos not with data) so data size must be equal zero*/ + uint32_t seq_no, Ack_no; + seq_no = (((uint32_t)tcp_hdr_ptr[4]) << 24) + (((uint32_t)tcp_hdr_ptr[5]) << 16) + (((uint32_t)tcp_hdr_ptr[6]) << 8) + ((uint32_t)tcp_hdr_ptr[7]); + + Ack_no = (((uint32_t)tcp_hdr_ptr[8]) << 24) + (((uint32_t)tcp_hdr_ptr[9]) << 16) + (((uint32_t)tcp_hdr_ptr[10]) << 8) + ((uint32_t)tcp_hdr_ptr[11]); + + + for (i = 0; i < Opened_TCP_session; i++) { + if (Acks_keep_track_info[i].Ack_seq_num == seq_no) { + Update_TCP_track_session(i, Ack_no); + break; + } + } + if (i == Opened_TCP_session) { + add_TCP_track_session(0, 0, seq_no); + } + add_TCP_Pending_Ack(Ack_no, i, tqe); + + + } + + } else { + ret = 0; + } + } else { + ret = 0; + } + p->os_func.os_spin_unlock(p->txq_spinlock, &flags); + return ret; +} + + +static int wilc_wlan_txq_filter_dup_tcp_ack(void) +{ + + uint32_t i = 0; + uint32_t Dropped = 0; + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + + p->os_func.os_spin_lock(p->txq_spinlock, &p->txq_spinlock_flags); + for (i = PendingAcks_arrBase; i < (PendingAcks_arrBase + Pending_Acks); i++) { + if (Pending_Acks_info[i].ack_num < Acks_keep_track_info[Pending_Acks_info[i].Session_index].Bigger_Ack_num) { + struct txq_entry_t *tqe; + PRINT_D(TCP_ENH, "DROP ACK: %u \n", Pending_Acks_info[i].ack_num); + tqe = Pending_Acks_info[i].txqe; + if (tqe) { + wilc_wlan_txq_remove(tqe); + Statisitcs_DroppedAcks++; + tqe->status = 1; /* mark the packet send */ + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, tqe->status); + p->os_func.os_free(tqe); + Dropped++; + } + } + } + Pending_Acks = 0; + Opened_TCP_session = 0; + + if (PendingAcks_arrBase == 0) { + PendingAcks_arrBase = MAX_TCP_SESSION; + } else { + PendingAcks_arrBase = 0; + } + + + p->os_func.os_spin_unlock(p->txq_spinlock, &p->txq_spinlock_flags); + + while (Dropped > 0) { + /*consume the semaphore count of the removed packet*/ + p->os_func.os_wait(p->txq_wait, 1); + Dropped--; + } + + return 1; +} +#endif + +#ifdef TCP_ENHANCEMENTS +bool EnableTCPAckFilter = false; + +void Enable_TCP_ACK_Filter(bool value) +{ + EnableTCPAckFilter = value; +} + +bool is_TCP_ACK_Filter_Enabled(void) +{ + return EnableTCPAckFilter; +} +#endif + +static int wilc_wlan_txq_add_cfg_pkt(uint8_t *buffer, uint32_t buffer_size) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + struct txq_entry_t *tqe; + + PRINT_D(TX_DBG, "Adding config packet ...\n"); + if (p->quit) { + PRINT_D(TX_DBG, "Return due to clear function\n"); + p->os_func.os_signal(p->cfg_wait); + return 0; + } + + tqe = (struct txq_entry_t *)p->os_func.os_malloc_atomic(sizeof(struct txq_entry_t)); + if (tqe == NULL) { + PRINT_ER("Failed to allocate memory\n"); + return 0; + } + + tqe->type = WILC_CFG_PKT; + tqe->buffer = buffer; + tqe->buffer_size = buffer_size; + tqe->tx_complete_func = NULL; + tqe->priv = NULL; +#ifdef TCP_ACK_FILTER + tqe->tcp_PendingAck_index = NOT_TCP_ACK; +#endif + /** + * Configuration packet always at the front + **/ + PRINT_D(TX_DBG, "Adding the config packet at the Queue tail\n"); + + /*Edited by Amr - BugID_4720*/ + if (wilc_wlan_txq_add_to_head(tqe)) + return 0; + return 1; +} + +static int wilc_wlan_txq_add_net_pkt(void *priv, uint8_t *buffer, uint32_t buffer_size, wilc_tx_complete_func_t func) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + struct txq_entry_t *tqe; + + if (p->quit) + return 0; + + tqe = (struct txq_entry_t *)p->os_func.os_malloc_atomic(sizeof(struct txq_entry_t)); + + if (tqe == NULL) + return 0; + tqe->type = WILC_NET_PKT; + tqe->buffer = buffer; + tqe->buffer_size = buffer_size; + tqe->tx_complete_func = func; + tqe->priv = priv; + + PRINT_D(TX_DBG, "Adding mgmt packet at the Queue tail\n"); +#ifdef TCP_ACK_FILTER + tqe->tcp_PendingAck_index = NOT_TCP_ACK; +#ifdef TCP_ENHANCEMENTS + if (is_TCP_ACK_Filter_Enabled()) +#endif + tcp_process(tqe); +#endif + wilc_wlan_txq_add_to_tail(tqe); + /*return number of itemes in the queue*/ + return p->txq_entries; +} +/*Bug3959: transmitting mgmt frames received from host*/ +#if defined(WILC_AP_EXTERNAL_MLME) || defined(WILC_P2P) +int wilc_wlan_txq_add_mgmt_pkt(void *priv, uint8_t *buffer, uint32_t buffer_size, wilc_tx_complete_func_t func) +{ + + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + struct txq_entry_t *tqe; + + if (p->quit) + return 0; + + tqe = (struct txq_entry_t *)p->os_func.os_malloc_atomic(sizeof(struct txq_entry_t)); + + if (tqe == NULL) + return 0; + tqe->type = WILC_MGMT_PKT; + tqe->buffer = buffer; + tqe->buffer_size = buffer_size; + tqe->tx_complete_func = func; + tqe->priv = priv; +#ifdef TCP_ACK_FILTER + tqe->tcp_PendingAck_index = NOT_TCP_ACK; +#endif + PRINT_D(TX_DBG, "Adding Network packet at the Queue tail\n"); + wilc_wlan_txq_add_to_tail(tqe); + return 1; +} + +#ifdef WILC_FULLY_HOSTING_AP +int wilc_FH_wlan_txq_add_net_pkt(void *priv, uint8_t *buffer, uint32_t buffer_size, wilc_tx_complete_func_t func) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + struct txq_entry_t *tqe; + + if (p->quit) + return 0; + + tqe = (struct txq_entry_t *)p->os_func.os_malloc_atomic(sizeof(struct txq_entry_t)); + + if (tqe == NULL) + return 0; + tqe->type = WILC_FH_DATA_PKT; + tqe->buffer = buffer; + tqe->buffer_size = buffer_size; + tqe->tx_complete_func = func; + tqe->priv = priv; + PRINT_D(TX_DBG, "Adding mgmt packet at the Queue tail\n"); + wilc_wlan_txq_add_to_tail(tqe); + /*return number of itemes in the queue*/ + return p->txq_entries; +} +#endif /* WILC_FULLY_HOSTING_AP*/ +#endif /*WILC_AP_EXTERNAL_MLME*/ +static struct txq_entry_t *wilc_wlan_txq_get_first(void) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + struct txq_entry_t *tqe; + unsigned long flags; + + /*Added by Amr - BugID_4720*/ + p->os_func.os_spin_lock(p->txq_spinlock, &flags); + + tqe = p->txq_head; + + /*Added by Amr - BugID_4720*/ + p->os_func.os_spin_unlock(p->txq_spinlock, &flags); + + + return tqe; +} + +static struct txq_entry_t *wilc_wlan_txq_get_next(struct txq_entry_t *tqe) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + unsigned long flags; + /*Added by Amr - BugID_4720*/ + p->os_func.os_spin_lock(p->txq_spinlock, &flags); + + tqe = tqe->next; + /*Added by Amr - BugID_4720*/ + p->os_func.os_spin_unlock(p->txq_spinlock, &flags); + + + return tqe; +} + +static int wilc_wlan_rxq_add(struct rxq_entry_t *rqe) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + + if (p->quit) + return 0; + + p->os_func.os_enter_cs(p->rxq_lock); + if (p->rxq_head == NULL) { + PRINT_D(RX_DBG, "Add to Queue head\n"); + rqe->next = NULL; + p->rxq_head = rqe; + p->rxq_tail = rqe; + } else { + PRINT_D(RX_DBG, "Add to Queue tail\n"); + p->rxq_tail->next = rqe; + rqe->next = NULL; + p->rxq_tail = rqe; + } + p->rxq_entries += 1; + PRINT_D(RX_DBG, "Number of queue entries: %d\n", p->rxq_entries); + p->os_func.os_leave_cs(p->rxq_lock); + return p->rxq_entries; +} + +static struct rxq_entry_t *wilc_wlan_rxq_remove(void) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + + PRINT_D(RX_DBG, "Getting rxQ element\n"); + if (p->rxq_head) { + struct rxq_entry_t *rqe; + + p->os_func.os_enter_cs(p->rxq_lock); + rqe = p->rxq_head; + p->rxq_head = p->rxq_head->next; + p->rxq_entries -= 1; + PRINT_D(RX_DBG, "RXQ entries decreased\n"); + p->os_func.os_leave_cs(p->rxq_lock); + return rqe; + } + PRINT_D(RX_DBG, "Nothing to get from Q\n"); + return NULL; +} + + +/******************************************** + * + * Power Save handle functions + * + ********************************************/ + + + +#ifdef WILC_OPTIMIZE_SLEEP_INT + +INLINE void chip_allow_sleep(void) +{ + uint32_t reg = 0; + + /* Clear bit 1 */ + g_wlan.hif_func.hif_read_reg(0xf0, ®); + + g_wlan.hif_func.hif_write_reg(0xf0, reg & ~(1 << 0)); +} + +INLINE void chip_wakeup(void) +{ + uint32_t reg, clk_status_reg, trials = 0; + uint32_t sleep_time; + + if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) { + do { + g_wlan.hif_func.hif_read_reg(1, ®); + /* Set bit 1 */ + g_wlan.hif_func.hif_write_reg(1, reg | (1 << 1)); + + /* Clear bit 1*/ + g_wlan.hif_func.hif_write_reg(1, reg & ~(1 << 1)); + + do { + /* Wait for the chip to stabilize*/ + WILC_Sleep(2); + /* Make sure chip is awake. This is an extra step that can be removed */ + /* later to avoid the bus access overhead */ + if ((wilc_get_chipid(true) == 0)) { + wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n"); + } + } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0)); + + } while (wilc_get_chipid(true) == 0); + } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) { + g_wlan.hif_func.hif_read_reg(0xf0, ®); + do { + /* Set bit 1 */ + g_wlan.hif_func.hif_write_reg(0xf0, reg | (1 << 0)); + + /* Check the clock status */ + g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg); + + /* in case of clocks off, wait 2ms, and check it again. */ + /* if still off, wait for another 2ms, for a total wait of 6ms. */ + /* If still off, redo the wake up sequence */ + while (((clk_status_reg & 0x1) == 0) && (((++trials) % 3) == 0)) { + /* Wait for the chip to stabilize*/ + WILC_Sleep(2); + + /* Make sure chip is awake. This is an extra step that can be removed */ + /* later to avoid the bus access overhead */ + g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg); + + if ((clk_status_reg & 0x1) == 0) { + wilc_debug(N_ERR, "clocks still OFF. Wake up failed\n"); + } + } + /* in case of failure, Reset the wakeup bit to introduce a new edge on the next loop */ + if ((clk_status_reg & 0x1) == 0) { + /* Reset bit 0 */ + g_wlan.hif_func.hif_write_reg(0xf0, reg & (~(1 << 0))); + } + } while ((clk_status_reg & 0x1) == 0); + } + + + if (genuChipPSstate == CHIP_SLEEPING_MANUAL) { + g_wlan.hif_func.hif_read_reg(0x1C0C, ®); + reg &= ~(1 << 0); + g_wlan.hif_func.hif_write_reg(0x1C0C, reg); + + if (wilc_get_chipid(false) >= 0x1002b0) { + /* Enable PALDO back right after wakeup */ + uint32_t val32; + g_wlan.hif_func.hif_read_reg(0x1e1c, &val32); + val32 |= (1 << 6); + g_wlan.hif_func.hif_write_reg(0x1e1c, val32); + + g_wlan.hif_func.hif_read_reg(0x1e9c, &val32); + val32 |= (1 << 6); + g_wlan.hif_func.hif_write_reg(0x1e9c, val32); + } + } + genuChipPSstate = CHIP_WAKEDUP; +} +#else +INLINE void chip_wakeup(void) +{ + uint32_t reg, trials = 0; + do { + if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) { + g_wlan.hif_func.hif_read_reg(1, ®); + /* Make sure bit 1 is 0 before we start. */ + g_wlan.hif_func.hif_write_reg(1, reg & ~(1 << 1)); + /* Set bit 1 */ + g_wlan.hif_func.hif_write_reg(1, reg | (1 << 1)); + /* Clear bit 1*/ + g_wlan.hif_func.hif_write_reg(1, reg & ~(1 << 1)); + } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) { + /* Make sure bit 0 is 0 before we start. */ + g_wlan.hif_func.hif_read_reg(0xf0, ®); + g_wlan.hif_func.hif_write_reg(0xf0, reg & ~(1 << 0)); + /* Set bit 1 */ + g_wlan.hif_func.hif_write_reg(0xf0, reg | (1 << 0)); + /* Clear bit 1 */ + g_wlan.hif_func.hif_write_reg(0xf0, reg & ~(1 << 0)); + } + + do { + /* Wait for the chip to stabilize*/ + mdelay(3); + + /* Make sure chip is awake. This is an extra step that can be removed */ + /* later to avoid the bus access overhead */ + if ((wilc_get_chipid(true) == 0)) { + wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n"); + } + } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0)); + + } while (wilc_get_chipid(true) == 0); + + if (genuChipPSstate == CHIP_SLEEPING_MANUAL) { + g_wlan.hif_func.hif_read_reg(0x1C0C, ®); + reg &= ~(1 << 0); + g_wlan.hif_func.hif_write_reg(0x1C0C, reg); + + if (wilc_get_chipid(false) >= 0x1002b0) { + /* Enable PALDO back right after wakeup */ + uint32_t val32; + g_wlan.hif_func.hif_read_reg(0x1e1c, &val32); + val32 |= (1 << 6); + g_wlan.hif_func.hif_write_reg(0x1e1c, val32); + + g_wlan.hif_func.hif_read_reg(0x1e9c, &val32); + val32 |= (1 << 6); + g_wlan.hif_func.hif_write_reg(0x1e9c, val32); + } + } + genuChipPSstate = CHIP_WAKEDUP; +} +#endif +void chip_sleep_manually(u32 u32SleepTime) +{ + if (genuChipPSstate != CHIP_WAKEDUP) { + /* chip is already sleeping. Do nothing */ + return; + } + acquire_bus(ACQUIRE_ONLY); + +#ifdef WILC_OPTIMIZE_SLEEP_INT + chip_allow_sleep(); +#endif + + /* Trigger the manual sleep interrupt */ + g_wlan.hif_func.hif_write_reg(0x10a8, 1); + + genuChipPSstate = CHIP_SLEEPING_MANUAL; + release_bus(RELEASE_ONLY); + +} + + +/******************************************** + * + * Tx, Rx queue handle functions + * + ********************************************/ +static int wilc_wlan_handle_txq(uint32_t *pu32TxqCount) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + int i, entries = 0; + uint32_t sum; + uint32_t reg; + uint8_t *txb = p->tx_buffer; + uint32_t offset = 0; + int vmm_sz = 0; + struct txq_entry_t *tqe; + int ret = 0; + int counter; + int timeout; + uint32_t vmm_table[WILC_VMM_TBL_SIZE]; + p->txq_exit = 0; + do { + if (p->quit) + break; + + /*Added by Amr - BugID_4720*/ + p->os_func.os_wait(p->txq_add_to_head_lock, CFG_PKTS_TIMEOUT); +#ifdef TCP_ACK_FILTER + wilc_wlan_txq_filter_dup_tcp_ack(); +#endif + /** + * build the vmm list + **/ + PRINT_D(TX_DBG, "Getting the head of the TxQ\n"); + tqe = wilc_wlan_txq_get_first(); + i = 0; + sum = 0; + do { + /* if ((tqe != NULL) && (i < (8)) && */ + /* if ((tqe != NULL) && (i < (WILC_VMM_TBL_SIZE-1)) && */ + if ((tqe != NULL) && (i < (WILC_VMM_TBL_SIZE - 1)) /* reserve last entry to 0 */) { + + if (tqe->type == WILC_CFG_PKT) { + vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET; + } + /*Bug3959: transmitting mgmt frames received from host*/ + /*vmm_sz will only be equal to tqe->buffer_size + 4 bytes (HOST_HDR_OFFSET)*/ + /* in other cases WILC_MGMT_PKT and WILC_DATA_PKT_MAC_HDR*/ + else if (tqe->type == WILC_NET_PKT) { + vmm_sz = ETH_ETHERNET_HDR_OFFSET; + } +#ifdef WILC_FULLY_HOSTING_AP + else if (tqe->type == WILC_FH_DATA_PKT) { + vmm_sz = FH_TX_HOST_HDR_OFFSET; + } +#endif +#ifdef WILC_AP_EXTERNAL_MLME + else { + vmm_sz = HOST_HDR_OFFSET; + } +#endif + vmm_sz += tqe->buffer_size; + PRINT_D(TX_DBG, "VMM Size before alignment = %d\n", vmm_sz); + if (vmm_sz & 0x3) { /* has to be word aligned */ + vmm_sz = (vmm_sz + 4) & ~0x3; + } + if ((sum + vmm_sz) > p->tx_buffer_size) { + break; + } + PRINT_D(TX_DBG, "VMM Size AFTER alignment = %d\n", vmm_sz); + vmm_table[i] = vmm_sz / 4; /* table take the word size */ + PRINT_D(TX_DBG, "VMMTable entry size = %d\n", vmm_table[i]); + + if (tqe->type == WILC_CFG_PKT) { + vmm_table[i] |= (1 << 10); + PRINT_D(TX_DBG, "VMMTable entry changed for CFG packet = %d\n", vmm_table[i]); + } +#ifdef BIG_ENDIAN + vmm_table[i] = BYTE_SWAP(vmm_table[i]); +#endif + + i++; + sum += vmm_sz; + PRINT_D(TX_DBG, "sum = %d\n", sum); + tqe = wilc_wlan_txq_get_next(tqe); + } else { + break; + } + } while (1); + + if (i == 0) { /* nothing in the queue */ + PRINT_D(TX_DBG, "Nothing in TX-Q\n"); + break; + } else { + PRINT_D(TX_DBG, "Mark the last entry in VMM table - number of previous entries = %d\n", i); + vmm_table[i] = 0x0; /* mark the last element to 0 */ + } + acquire_bus(ACQUIRE_AND_WAKEUP); + counter = 0; + do { + + ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, ®); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't read reg vmm_tbl_entry..\n"); + break; + } + + if ((reg & 0x1) == 0) { + /** + * write to vmm table + **/ + PRINT_D(TX_DBG, "Writing VMM table ... with Size = %d\n", ((i + 1) * 4)); + break; + } else { + counter++; + if (counter > 200) { + counter = 0; + PRINT_D(TX_DBG, "Looping in tx ctrl , forcce quit\n"); + ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, 0); + break; + } + /** + * wait for vmm table is ready + **/ + PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait... \n"); + release_bus(RELEASE_ALLOW_SLEEP); + p->os_func.os_sleep(3); /* wait 3 ms */ + acquire_bus(ACQUIRE_AND_WAKEUP); + } + } while (!p->quit); + + if (!ret) { + goto _end_; + } + + timeout = 200; + do { + + /** + * write to vmm table + **/ + ret = p->hif_func.hif_block_tx(WILC_VMM_TBL_RX_SHADOW_BASE, (uint8_t *)vmm_table, ((i + 1) * 4)); /* Bug 4477 fix */ + if (!ret) { + wilc_debug(N_ERR, "ERR block TX of VMM table.\n"); + break; + } + + + /** + * interrupt firmware + **/ + ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x2); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't write reg host_vmm_ctl..\n"); + break; + } + + /** + * wait for confirm... + **/ + + do { + ret = p->hif_func.hif_read_reg(WILC_HOST_VMM_CTL, ®); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't read reg host_vmm_ctl..\n"); + break; + } + if ((reg >> 2) & 0x1) { + /** + * Get the entries + **/ + entries = ((reg >> 3) & 0x3f); + /* entries = ((reg>>3)&0x2f); */ + break; + } else { + release_bus(RELEASE_ALLOW_SLEEP); + p->os_func.os_sleep(3); /* wait 3 ms */ + acquire_bus(ACQUIRE_AND_WAKEUP); + PRINT_WRN(GENERIC_DBG, "Can't get VMM entery - reg = %2x\n", reg); + } + } while (--timeout); + if (timeout <= 0) { + ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x0); + break; + } + + if (!ret) { + break; + } + + if (entries == 0) { + PRINT_WRN(GENERIC_DBG, "[wilc txq]: no more buffer in the chip (reg: %08x), retry later [[ %d, %x ]] \n", reg, i, vmm_table[i - 1]); + + /* undo the transaction. */ + ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, ®); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't read reg WILC_HOST_TX_CTRL..\n"); + break; + } + reg &= ~(1ul << 0); + ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, reg); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't write reg WILC_HOST_TX_CTRL..\n"); + break; + } + break; + } else { + break; + } + } while (1); + + if (!ret) { + goto _end_; + } + if (entries == 0) { + ret = WILC_TX_ERR_NO_BUF; + goto _end_; + } + + /* since copying data into txb takes some time, then + * allow the bus lock to be released let the RX task go. */ + release_bus(RELEASE_ALLOW_SLEEP); + + /** + * Copy data to the TX buffer + **/ + offset = 0; + i = 0; + do { + tqe = wilc_wlan_txq_remove_from_head(); + if (tqe != NULL && (vmm_table[i] != 0)) { + uint32_t header, buffer_offset; + +#ifdef BIG_ENDIAN + vmm_table[i] = BYTE_SWAP(vmm_table[i]); +#endif + vmm_sz = (vmm_table[i] & 0x3ff); /* in word unit */ + vmm_sz *= 4; + header = (tqe->type << 31) | (tqe->buffer_size << 15) | vmm_sz; + /*Bug3959: transmitting mgmt frames received from host*/ + /*setting bit 30 in the host header to indicate mgmt frame*/ +#ifdef WILC_AP_EXTERNAL_MLME + if (tqe->type == WILC_MGMT_PKT) { + header |= (1 << 30); + } else { + header &= ~(1 << 30); + } +#endif + +#ifdef BIG_ENDIAN + header = BYTE_SWAP(header); +#endif + memcpy(&txb[offset], &header, 4); + if (tqe->type == WILC_CFG_PKT) { + buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET; + } + /*Bug3959: transmitting mgmt frames received from host*/ + /*buffer offset = HOST_HDR_OFFSET in other cases: WILC_MGMT_PKT*/ + /* and WILC_DATA_PKT_MAC_HDR*/ + else if (tqe->type == WILC_NET_PKT) { + char *pBSSID = ((struct tx_complete_data *)(tqe->priv))->pBssid; + buffer_offset = ETH_ETHERNET_HDR_OFFSET; + /* copy the bssid at the sart of the buffer */ + memcpy(&txb[offset + 4], pBSSID, 6); + } +#ifdef WILC_FULLY_HOSTING_AP + else if (tqe->type == WILC_FH_DATA_PKT) { + buffer_offset = FH_TX_HOST_HDR_OFFSET; + } +#endif + else { + buffer_offset = HOST_HDR_OFFSET; + } + + memcpy(&txb[offset + buffer_offset], tqe->buffer, tqe->buffer_size); + offset += vmm_sz; + i++; + tqe->status = 1; /* mark the packet send */ + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, tqe->status); + #ifdef TCP_ACK_FILTER + if (tqe->tcp_PendingAck_index != NOT_TCP_ACK) { + Pending_Acks_info[tqe->tcp_PendingAck_index].txqe = NULL; + } + #endif + p->os_func.os_free(tqe); + } else { + break; + } + } while (--entries); + + /** + * lock the bus + **/ + acquire_bus(ACQUIRE_AND_WAKEUP); + + ret = p->hif_func.hif_clear_int_ext(ENABLE_TX_VMM); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't start tx VMM ...\n"); + goto _end_; + } + + /** + * transfer + **/ + ret = p->hif_func.hif_block_tx_ext(0, txb, offset); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't block tx ext...\n"); + goto _end_; + } + +_end_: + + release_bus(RELEASE_ALLOW_SLEEP); + if (ret != 1) + break; + } while (0); + /*Added by Amr - BugID_4720*/ + p->os_func.os_signal(p->txq_add_to_head_lock); + + p->txq_exit = 1; + PRINT_D(TX_DBG, "THREAD: Exiting txq\n"); + /* return tx[]q count */ + *pu32TxqCount = p->txq_entries; + return ret; +} + +static void wilc_wlan_handle_rxq(void) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + int offset = 0, size, has_packet = 0; + uint8_t *buffer; + struct rxq_entry_t *rqe; + + p->rxq_exit = 0; + + + + + do { + if (p->quit) { + PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function \n"); + p->os_func.os_signal(p->cfg_wait); + break; + } + rqe = wilc_wlan_rxq_remove(); + if (rqe == NULL) { + PRINT_D(RX_DBG, "nothing in the queue - exit 1st do-while\n"); + break; + } + buffer = rqe->buffer; + size = rqe->buffer_size; + PRINT_D(RX_DBG, "rxQ entery Size = %d - Address = %p\n", size, buffer); + offset = 0; + + + + do { + uint32_t header; + uint32_t pkt_len, pkt_offset, tp_len; + int is_cfg_packet; + PRINT_D(RX_DBG, "In the 2nd do-while\n"); + memcpy(&header, &buffer[offset], 4); +#ifdef BIG_ENDIAN + header = BYTE_SWAP(header); +#endif + PRINT_D(RX_DBG, "Header = %04x - Offset = %d\n", header, offset); + + + + is_cfg_packet = (header >> 31) & 0x1; + pkt_offset = (header >> 22) & 0x1ff; + tp_len = (header >> 11) & 0x7ff; + pkt_len = header & 0x7ff; + + if (pkt_len == 0 || tp_len == 0) { + wilc_debug(N_RXQ, "[wilc rxq]: data corrupt, packet len or tp_len is 0 [%d][%d]\n", pkt_len, tp_len); + break; + } + +/*bug 3887: [AP] Allow Management frames to be passed to the host*/ + #if defined(WILC_AP_EXTERNAL_MLME) || defined(WILC_P2P) + #define IS_MANAGMEMENT 0x100 + #define IS_MANAGMEMENT_CALLBACK 0x080 + #define IS_MGMT_STATUS_SUCCES 0x040 + + + if (pkt_offset & IS_MANAGMEMENT) { + /* reset mgmt indicator bit, to use pkt_offeset in furthur calculations */ + pkt_offset &= ~(IS_MANAGMEMENT | IS_MANAGMEMENT_CALLBACK | IS_MGMT_STATUS_SUCCES); + +#ifdef USE_WIRELESS + WILC_WFI_mgmt_rx(&buffer[offset + HOST_HDR_OFFSET], pkt_len); + +#endif + + } + /* BUG4530 fix */ + else + #endif + { + + if (!is_cfg_packet) { + + if (p->net_func.rx_indicate) { + if (pkt_len > 0) { + p->net_func.rx_indicate(&buffer[offset], pkt_len, pkt_offset); + has_packet = 1; + } + } + } else { + wilc_cfg_rsp_t rsp; + + + + p->cif_func.rx_indicate(&buffer[pkt_offset + offset], pkt_len, &rsp); + if (rsp.type == WILC_CFG_RSP) { + /** + * wake up the waiting task... + **/ + PRINT_D(RX_DBG, "p->cfg_seq_no = %d - rsp.seq_no = %d\n", p->cfg_seq_no, rsp.seq_no); + if (p->cfg_seq_no == rsp.seq_no) { + p->os_func.os_signal(p->cfg_wait); + } + } else if (rsp.type == WILC_CFG_RSP_STATUS) { + /** + * Call back to indicate status... + **/ + if (p->indicate_func.mac_indicate) { + p->indicate_func.mac_indicate(WILC_MAC_INDICATE_STATUS); + } + + } else if (rsp.type == WILC_CFG_RSP_SCAN) { + if (p->indicate_func.mac_indicate) + p->indicate_func.mac_indicate(WILC_MAC_INDICATE_SCAN); + } + } + } + offset += tp_len; + if (offset >= size) + break; + } while (1); + + +#ifndef MEMORY_STATIC + if (buffer != NULL) + p->os_func.os_free((void *)buffer); +#endif + if (rqe != NULL) + p->os_func.os_free((void *)rqe); + + if (has_packet) { + if (p->net_func.rx_complete) + p->net_func.rx_complete(); + } + } while (1); + + p->rxq_exit = 1; + PRINT_D(RX_DBG, "THREAD: Exiting RX thread \n"); + return; +} + +/******************************************** + * + * Fast DMA Isr + * + ********************************************/ +static void wilc_unknown_isr_ext(void) +{ + g_wlan.hif_func.hif_clear_int_ext(0); +} +static void wilc_pllupdate_isr_ext(uint32_t int_stats) +{ + + int trials = 10; + + g_wlan.hif_func.hif_clear_int_ext(PLL_INT_CLR); + + /* Waiting for PLL */ + g_wlan.os_func.os_atomic_sleep(WILC_PLL_TO); + + /* poll till read a valid data */ + while (!(ISWILC1000(wilc_get_chipid(true)) && --trials)) { + PRINT_D(TX_DBG, "PLL update retrying\n"); + g_wlan.os_func.os_atomic_sleep(1); + } +} + +static void wilc_sleeptimer_isr_ext(uint32_t int_stats1) +{ + g_wlan.hif_func.hif_clear_int_ext(SLEEP_INT_CLR); +#ifndef WILC_OPTIMIZE_SLEEP_INT + genuChipPSstate = CHIP_SLEEPING_AUTO; +#endif +} + +static void wilc_wlan_handle_isr_ext(uint32_t int_status) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; +#ifdef MEMORY_STATIC + uint32_t offset = p->rx_buffer_offset; +#endif + uint8_t *buffer = NULL; + uint32_t size; + uint32_t retries = 0; + int ret = 0; + struct rxq_entry_t *rqe; + + + /** + * Get the rx size + **/ + + size = ((int_status & 0x7fff) << 2); + + while (!size && retries < 10) { + uint32_t time = 0; + /*looping more secure*/ + /*zero size make a crashe because the dma will not happen and that will block the firmware*/ + wilc_debug(N_ERR, "RX Size equal zero ... Trying to read it again for %d time\n", time++); + p->hif_func.hif_read_size(&size); + size = ((size & 0x7fff) << 2); + retries++; + + } + + if (size > 0) { +#ifdef MEMORY_STATIC + if (p->rx_buffer_size - offset < size) + offset = 0; + + if (p->rx_buffer) + buffer = &p->rx_buffer[offset]; + else { + wilc_debug(N_ERR, "[wilc isr]: fail Rx Buffer is NULL...drop the packets (%d)\n", size); + goto _end_; + } + +#else + buffer = p->os_func.os_malloc(size); + if (buffer == NULL) { + wilc_debug(N_ERR, "[wilc isr]: fail alloc host memory...drop the packets (%d)\n", size); + WILC_Sleep(100); + goto _end_; + } +#endif + + /** + * clear the chip's interrupt after getting size some register getting corrupted after clear the interrupt + **/ + p->hif_func.hif_clear_int_ext(DATA_INT_CLR | ENABLE_RX_VMM); + + + /** + * start transfer + **/ + ret = p->hif_func.hif_block_rx_ext(0, buffer, size); + + if (!ret) { + wilc_debug(N_ERR, "[wilc isr]: fail block rx...\n"); + goto _end_; + } +_end_: + + + if (ret) { +#ifdef MEMORY_STATIC + offset += size; + p->rx_buffer_offset = offset; +#endif + /** + * add to rx queue + **/ + rqe = (struct rxq_entry_t *)p->os_func.os_malloc(sizeof(struct rxq_entry_t)); + if (rqe != NULL) { + rqe->buffer = buffer; + rqe->buffer_size = size; + PRINT_D(RX_DBG, "rxq entery Size= %d - Address = %p\n", rqe->buffer_size, rqe->buffer); + wilc_wlan_rxq_add(rqe); + p->os_func.os_signal(p->rxq_wait); + } + } else { +#ifndef MEMORY_STATIC + if (buffer != NULL) + p->os_func.os_free(buffer); +#endif + } + } +#ifdef TCP_ENHANCEMENTS + wilc_wlan_handle_rxq(); +#endif +} + +void wilc_handle_isr(void) +{ + uint32_t int_status; + + acquire_bus(ACQUIRE_AND_WAKEUP); + g_wlan.hif_func.hif_read_int(&int_status); + + if (int_status & PLL_INT_EXT) { + wilc_pllupdate_isr_ext(int_status); + } + if (int_status & DATA_INT_EXT) { + wilc_wlan_handle_isr_ext(int_status); + #ifndef WILC_OPTIMIZE_SLEEP_INT + /* Chip is up and talking*/ + genuChipPSstate = CHIP_WAKEDUP; + #endif + } + if (int_status & SLEEP_INT_EXT) { + wilc_sleeptimer_isr_ext(int_status); + } + + if (!(int_status & (ALL_INT_EXT))) { +#ifdef WILC_SDIO + PRINT_D(TX_DBG, ">> UNKNOWN_INTERRUPT - 0x%08x\n", int_status); +#endif + wilc_unknown_isr_ext(); + } +#if ((!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO)) + linux_wlan_enable_irq(); +#endif + release_bus(RELEASE_ALLOW_SLEEP); +} + +/******************************************** + * + * Firmware download + * + ********************************************/ +static int wilc_wlan_firmware_download(const uint8_t *buffer, uint32_t buffer_size) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + uint32_t offset; + uint32_t addr, size, size2, blksz; + uint8_t *dma_buffer; + int ret = 0; + + blksz = (1ul << 12); /* Bug 4703: 4KB Good enough size for most platforms = PAGE_SIZE. */ + /* Allocate a DMA coherent buffer. */ + +#if (defined WILC_PREALLOC_AT_BOOT) + { + extern void *get_fw_buffer(void); + dma_buffer = (uint8_t *)get_fw_buffer(); + PRINT_D(TX_DBG, "fw_buffer = 0x%x\n", dma_buffer); + } +#else + dma_buffer = (uint8_t *)g_wlan.os_func.os_malloc(blksz); +#endif + if (dma_buffer == NULL) { + /*EIO 5*/ + ret = -5; + PRINT_ER("Can't allocate buffer for firmware download IO error\n "); + goto _fail_1; + } + + PRINT_D(INIT_DBG, "Downloading firmware size = %d ...\n", buffer_size); + /** + * load the firmware + **/ + offset = 0; + do { + memcpy(&addr, &buffer[offset], 4); + memcpy(&size, &buffer[offset + 4], 4); +#ifdef BIG_ENDIAN + addr = BYTE_SWAP(addr); + size = BYTE_SWAP(size); +#endif + acquire_bus(ACQUIRE_ONLY); + offset += 8; + while (((int)size) && (offset < buffer_size)) { + if (size <= blksz) { + size2 = size; + } else { + size2 = blksz; + } + /* Copy firmware into a DMA coherent buffer */ + memcpy(dma_buffer, &buffer[offset], size2); + ret = p->hif_func.hif_block_tx(addr, dma_buffer, size2); + if (!ret) + break; + + addr += size2; + offset += size2; + size -= size2; + } + release_bus(RELEASE_ONLY); + + if (!ret) { + /*EIO 5*/ + ret = -5; + PRINT_ER("Can't download firmware IO error\n "); + goto _fail_; + } + PRINT_D(INIT_DBG, "Offset = %d\n", offset); + } while (offset < buffer_size); + +_fail_: + +#if (defined WILC_PREALLOC_AT_BOOT) + +#else + if (dma_buffer) + g_wlan.os_func.os_free(dma_buffer); +#endif + +_fail_1: + + return (ret < 0) ? ret : 0; +} + +/******************************************** + * + * Common + * + ********************************************/ +static int wilc_wlan_start(void) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + uint32_t reg = 0; + int ret; + uint32_t chipid; + + /** + * Set the host interface + **/ +#ifdef OLD_FPGA_BITFILE + acquire_bus(ACQUIRE_ONLY); + ret = p->hif_func.hif_read_reg(WILC_VMM_CORE_CTL, ®); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail read reg vmm_core_ctl...\n"); + release_bus(RELEASE_ALLOW_SLEEP); + return ret; + } + reg |= (p->io_func.io_type << 2); + ret = p->hif_func.hif_write_reg(WILC_VMM_CORE_CTL, reg); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_ctl...\n"); + release_bus(RELEASE_ONLY); + return ret; + } +#else + if (p->io_func.io_type == HIF_SDIO) { + reg = 0; + reg |= (1 << 3); /* bug 4456 and 4557 */ + } else if (p->io_func.io_type == HIF_SPI) { + reg = 1; + } + acquire_bus(ACQUIRE_ONLY); + ret = p->hif_func.hif_write_reg(WILC_VMM_CORE_CFG, reg); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_cfg...\n"); + release_bus(RELEASE_ONLY); + /* EIO 5*/ + ret = -5; + return ret; + } + reg = 0; +#ifdef WILC_SDIO_IRQ_GPIO + reg |= WILC_HAVE_SDIO_IRQ_GPIO; +#endif + +#ifdef WILC_DISABLE_PMU +#else + reg |= WILC_HAVE_USE_PMU; +#endif + +#ifdef WILC_SLEEP_CLK_SRC_XO + reg |= WILC_HAVE_SLEEP_CLK_SRC_XO; +#elif defined WILC_SLEEP_CLK_SRC_RTC + reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC; +#endif + +#ifdef WILC_EXT_PA_INV_TX_RX + reg |= WILC_HAVE_EXT_PA_INV_TX_RX; +#endif + + reg |= WILC_HAVE_LEGACY_RF_SETTINGS; + + +/*BugID_5257*/ +/*Set oscillator frequency*/ +#ifdef XTAL_24 + reg |= WILC_HAVE_XTAL_24; +#endif + +/*BugID_5271*/ +/*Enable/Disable GPIO configuration for FW logs*/ +#ifdef DISABLE_WILC_UART + reg |= WILC_HAVE_DISABLE_WILC_UART; +#endif + + ret = p->hif_func.hif_write_reg(WILC_GP_REG_1, reg); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail write WILC_GP_REG_1 ...\n"); + release_bus(RELEASE_ONLY); + /* EIO 5*/ + ret = -5; + return ret; + } +#endif + + + /** + * Bus related + **/ + p->hif_func.hif_sync_ext(NUM_INT_EXT); + + ret = p->hif_func.hif_read_reg(0x1000, &chipid); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1000 ...\n"); + release_bus(RELEASE_ONLY); + /* EIO 5*/ + ret = -5; + return ret; + } + + /** + * Go... + **/ + + + p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + if ((reg & (1ul << 10)) == (1ul << 10)) { + reg &= ~(1ul << 10); + p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); + p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + } + + reg |= (1ul << 10); + ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); + p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + release_bus(RELEASE_ONLY); + + return (ret < 0) ? ret : 0; +} + +void wilc_wlan_global_reset(void) +{ + + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + acquire_bus(ACQUIRE_AND_WAKEUP); + p->hif_func.hif_write_reg(WILC_GLB_RESET_0, 0x0); + release_bus(RELEASE_ONLY); +} +static int wilc_wlan_stop(void) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + uint32_t reg = 0; + int ret; + uint8_t timeout = 10; + /** + * TODO: stop the firmware, need a re-download + **/ + acquire_bus(ACQUIRE_AND_WAKEUP); + + ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + if (!ret) { + PRINT_ER("Error while reading reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + return ret; + } + + reg &= ~(1 << 10); + + + ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); + if (!ret) { + PRINT_ER("Error while writing reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + return ret; + } + + + + do { + ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + if (!ret) { + PRINT_ER("Error while reading reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + return ret; + } + PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout); + /*Workaround to ensure that the chip is actually reset*/ + if ((reg & (1 << 10))) { + PRINT_D(GENERIC_DBG, "Bit 10 not reset : Retry %d\n", timeout); + reg &= ~(1 << 10); + ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); + timeout--; + } else { + PRINT_D(GENERIC_DBG, "Bit 10 reset after : Retry %d\n", timeout); + ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + if (!ret) { + PRINT_ER("Error while reading reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + return ret; + } + PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout); + break; + } + + } while (timeout); +#if 1 +/******************************************************************************/ +/* This was add at Bug 4595 to reset the chip while maintaining the bus state */ +/******************************************************************************/ + reg = ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 8) | (1 << 9) | (1 << 26) | (1 << 29) | (1 << 30) | (1 << 31)); /**/ + /**/ + ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); /**/ + reg = ~(1 << 10); /**/ + /**/ + ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); /**/ +/******************************************************************************/ +#endif + + release_bus(RELEASE_ALLOW_SLEEP); + + return ret; +} + +static void wilc_wlan_cleanup(void) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + struct txq_entry_t *tqe; + struct rxq_entry_t *rqe; + uint32_t reg = 0; + int ret; + + p->quit = 1; + do { + tqe = wilc_wlan_txq_remove_from_head(); + if (tqe == NULL) + break; + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, 0); + p->os_func.os_free((void *)tqe); + } while (1); + + do { + rqe = wilc_wlan_rxq_remove(); + if (rqe == NULL) + break; +#ifdef MEMORY_DYNAMIC + p->os_func.os_free((void *)tqe->buffer); +#endif + p->os_func.os_free((void *)rqe); + } while (1); + + /** + * clean up buffer + **/ + +#if (defined WILC_PREALLOC_AT_BOOT) + +#else + #ifdef MEMORY_STATIC + if (p->rx_buffer) { + p->os_func.os_free(p->rx_buffer); + p->rx_buffer = NULL; + } + #endif + if (p->tx_buffer) { + p->os_func.os_free(p->tx_buffer); + p->tx_buffer = NULL; + } +#endif + + acquire_bus(ACQUIRE_AND_WAKEUP); + + + ret = p->hif_func.hif_read_reg(WILC_GP_REG_0, ®); + if (!ret) { + PRINT_ER("Error while reading reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + } + PRINT_ER("Writing ABORT reg\n"); + ret = p->hif_func.hif_write_reg(WILC_GP_REG_0, (reg | ABORT_INT)); + if (!ret) { + PRINT_ER("Error while writing reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + } + release_bus(RELEASE_ALLOW_SLEEP); + /** + * io clean up + **/ + p->hif_func.hif_deinit(NULL); + +} + +static int wilc_wlan_cfg_commit(int type, uint32_t drvHandler) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + wilc_cfg_frame_t *cfg = &p->cfg_frame; + int total_len = p->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE; + int seq_no = p->cfg_seq_no % 256; + int driver_handler = (u32)drvHandler; + + + /** + * Set up header + **/ + if (type == WILC_CFG_SET) { /* Set */ + cfg->wid_header[0] = 'W'; + } else { /* Query */ + cfg->wid_header[0] = 'Q'; + } + cfg->wid_header[1] = seq_no; /* sequence number */ + cfg->wid_header[2] = (uint8_t)total_len; + cfg->wid_header[3] = (uint8_t)(total_len >> 8); + cfg->wid_header[4] = (uint8_t)driver_handler; + cfg->wid_header[5] = (uint8_t)(driver_handler >> 8); + cfg->wid_header[6] = (uint8_t)(driver_handler >> 16); + cfg->wid_header[7] = (uint8_t)(driver_handler >> 24); + p->cfg_seq_no = seq_no; + + /** + * Add to TX queue + **/ + + /*Edited by Amr - BugID_4720*/ + if (!wilc_wlan_txq_add_cfg_pkt(&cfg->wid_header[0], total_len)) + return -1; + + return 0; +} + +static int wilc_wlan_cfg_set(int start, uint32_t wid, uint8_t *buffer, uint32_t buffer_size, int commit, uint32_t drvHandler) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + uint32_t offset; + int ret_size; + + + if (p->cfg_frame_in_use) + return 0; + + if (start) + p->cfg_frame_offset = 0; + + offset = p->cfg_frame_offset; + ret_size = p->cif_func.cfg_wid_set(p->cfg_frame.frame, offset, (uint16_t)wid, buffer, buffer_size); + offset += ret_size; + p->cfg_frame_offset = offset; + + if (commit) { + PRINT_D(TX_DBG, "[WILC]PACKET Commit with sequence number %d\n", p->cfg_seq_no); + PRINT_D(RX_DBG, "Processing cfg_set()\n"); + p->cfg_frame_in_use = 1; + + /*Edited by Amr - BugID_4720*/ + if (wilc_wlan_cfg_commit(WILC_CFG_SET, drvHandler)) + ret_size = 0; /* BugID_5213 */ + + if (p->os_func.os_wait(p->cfg_wait, CFG_PKTS_TIMEOUT)) { + PRINT_D(TX_DBG, "Set Timed Out\n"); + ret_size = 0; + } + p->cfg_frame_in_use = 0; + p->cfg_frame_offset = 0; + p->cfg_seq_no += 1; + + } + + return ret_size; +} +static int wilc_wlan_cfg_get(int start, uint32_t wid, int commit, uint32_t drvHandler) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + uint32_t offset; + int ret_size; + + + if (p->cfg_frame_in_use) + return 0; + + if (start) + p->cfg_frame_offset = 0; + + offset = p->cfg_frame_offset; + ret_size = p->cif_func.cfg_wid_get(p->cfg_frame.frame, offset, (uint16_t)wid); + offset += ret_size; + p->cfg_frame_offset = offset; + + if (commit) { + p->cfg_frame_in_use = 1; + + /*Edited by Amr - BugID_4720*/ + if (wilc_wlan_cfg_commit(WILC_CFG_QUERY, drvHandler)) + ret_size = 0; /* BugID_5213 */ + + + if (p->os_func.os_wait(p->cfg_wait, CFG_PKTS_TIMEOUT)) { + PRINT_D(TX_DBG, "Get Timed Out\n"); + ret_size = 0; + } + PRINT_D(GENERIC_DBG, "[WILC]Get Response received\n"); + p->cfg_frame_in_use = 0; + p->cfg_frame_offset = 0; + p->cfg_seq_no += 1; + } + + return ret_size; +} + +static int wilc_wlan_cfg_get_val(uint32_t wid, uint8_t *buffer, uint32_t buffer_size) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + int ret; + + ret = p->cif_func.cfg_wid_get_val((uint16_t)wid, buffer, buffer_size); + + return ret; +} + +void wilc_bus_set_max_speed(void) +{ + + /* Increase bus speed to max possible. */ + g_wlan.hif_func.hif_set_max_bus_speed(); +} + +void wilc_bus_set_default_speed(void) +{ + + /* Restore bus speed to default. */ + g_wlan.hif_func.hif_set_default_bus_speed(); +} +uint32_t init_chip(void) +{ + uint32_t chipid; + uint32_t reg, ret = 0; + +#if defined(PLAT_RK3026_TCHIP) + acquire_bus(ACQUIRE_AND_WAKEUP); /* AMR : 0422 RK3026 Crash issue */ +#else + acquire_bus(ACQUIRE_ONLY); +#endif + + chipid = wilc_get_chipid(true); + + + + if ((chipid & 0xfff) != 0xa0) { + /** + * Avoid booting from boot ROM. Make sure that Drive IRQN [SDIO platform] + * or SD_DAT3 [SPI platform] to ?1? + **/ + /* Set cortus reset register to register control. */ + ret = g_wlan.hif_func.hif_read_reg(0x1118, ®); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1118 ...\n"); + return ret; + } + reg |= (1 << 0); + ret = g_wlan.hif_func.hif_write_reg(0x1118, reg); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail write reg 0x1118 ...\n"); + return ret; + } + /** + * Write branch intruction to IRAM (0x71 trap) at location 0xFFFF0000 + * (Cortus map) or C0000 (AHB map). + **/ + ret = g_wlan.hif_func.hif_write_reg(0xc0000, 0x71); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail write reg 0xc0000 ...\n"); + return ret; + } + } + + release_bus(RELEASE_ONLY); + + return ret; + +} + +uint32_t wilc_get_chipid(uint8_t update) +{ + static uint32_t chipid; + /* SDIO can't read into global variables */ + /* Use this variable as a temp, then copy to the global */ + uint32_t tempchipid = 0; + uint32_t rfrevid; + + if (chipid == 0 || update != 0) { + g_wlan.hif_func.hif_read_reg(0x1000, &tempchipid); + g_wlan.hif_func.hif_read_reg(0x13f4, &rfrevid); + if (!ISWILC1000(tempchipid)) { + chipid = 0; + goto _fail_; + } + if (tempchipid == 0x1002a0) { + if (rfrevid == 0x1) { /* 1002A0 */ + } else { /* if (rfrevid == 0x2) */ /* 1002A1 */ + tempchipid = 0x1002a1; + } + } else if (tempchipid == 0x1002b0) { + if (rfrevid == 3) { /* 1002B0 */ + } else if (rfrevid == 4) { /* 1002B1 */ + tempchipid = 0x1002b1; + } else { /* if(rfrevid == 5) */ /* 1002B2 */ + tempchipid = 0x1002b2; + } + } else { + } + + chipid = tempchipid; + } +_fail_: + return chipid; +} + +#ifdef COMPLEMENT_BOOT +uint8_t core_11b_ready(void) +{ + uint32_t reg_val; + + acquire_bus(ACQUIRE_ONLY); + g_wlan.hif_func.hif_write_reg(0x16082c, 1); + g_wlan.hif_func.hif_write_reg(0x161600, 0x90); + g_wlan.hif_func.hif_read_reg(0x161600, ®_val); + release_bus(RELEASE_ONLY); + + if (reg_val == 0x90) + return 0; + else + return 1; +} +#endif + +int wilc_wlan_init(wilc_wlan_inp_t *inp, wilc_wlan_oup_t *oup) +{ + + int ret = 0; + + PRINT_D(INIT_DBG, "Initializing WILC_Wlan ...\n"); + + memset((void *)&g_wlan, 0, sizeof(wilc_wlan_dev_t)); + + /** + * store the input + **/ + memcpy((void *)&g_wlan.os_func, (void *)&inp->os_func, sizeof(wilc_wlan_os_func_t)); + memcpy((void *)&g_wlan.io_func, (void *)&inp->io_func, sizeof(wilc_wlan_io_func_t)); + memcpy((void *)&g_wlan.net_func, (void *)&inp->net_func, sizeof(wilc_wlan_net_func_t)); + memcpy((void *)&g_wlan.indicate_func, (void *)&inp->indicate_func, sizeof(wilc_wlan_net_func_t)); + g_wlan.hif_lock = inp->os_context.hif_critical_section; + g_wlan.txq_lock = inp->os_context.txq_critical_section; + + /*Added by Amr - BugID_4720*/ + g_wlan.txq_add_to_head_lock = inp->os_context.txq_add_to_head_critical_section; + + /*Added by Amr - BugID_4720*/ + g_wlan.txq_spinlock = inp->os_context.txq_spin_lock; + + g_wlan.rxq_lock = inp->os_context.rxq_critical_section; + g_wlan.txq_wait = inp->os_context.txq_wait_event; + g_wlan.rxq_wait = inp->os_context.rxq_wait_event; + g_wlan.cfg_wait = inp->os_context.cfg_wait_event; + g_wlan.tx_buffer_size = inp->os_context.tx_buffer_size; +#if defined (MEMORY_STATIC) + g_wlan.rx_buffer_size = inp->os_context.rx_buffer_size; +#endif + /*** + * host interface init + **/ +#if defined(PLAT_RK3026_TCHIP) /* AMR : 0422 RK3026 Crash issue */ + if (!g_wilc_initialized) { + custom_lock_bus(g_mac_open); + custom_wakeup(g_mac_open); + } +#endif + + if ((inp->io_func.io_type & 0x1) == HIF_SDIO) { + if (!hif_sdio.hif_init(inp, wilc_debug)) { + /* EIO 5 */ + ret = -5; + goto _fail_; + } + memcpy((void *)&g_wlan.hif_func, &hif_sdio, sizeof(wilc_hif_func_t)); + } else { + if ((inp->io_func.io_type & 0x1) == HIF_SPI) { + /** + * TODO: + **/ + if (!hif_spi.hif_init(inp, wilc_debug)) { + /* EIO 5 */ + ret = -5; + goto _fail_; + } + memcpy((void *)&g_wlan.hif_func, &hif_spi, sizeof(wilc_hif_func_t)); + } else { + /* EIO 5 */ + ret = -5; + goto _fail_; + } + } + + /*** + * mac interface init + **/ + if (!mac_cfg.cfg_init(wilc_debug)) { + /* ENOBUFS 105 */ + ret = -105; + goto _fail_; + } + memcpy((void *)&g_wlan.cif_func, &mac_cfg, sizeof(wilc_cfg_func_t)); + + + /** + * alloc tx, rx buffer + **/ +#if (defined WILC_PREALLOC_AT_BOOT) + extern void *get_tx_buffer(void); + extern void *get_rx_buffer(void); + + PRINT_D(TX_DBG, "malloc before, g_wlan.tx_buffer = 0x%x, g_wlan.rx_buffer = 0x%x\n", g_wlan.tx_buffer, g_wlan.rx_buffer); +#endif + + + + if (g_wlan.tx_buffer == NULL) +#if (defined WILC_PREALLOC_AT_BOOT) + g_wlan.tx_buffer = (uint8_t *)get_tx_buffer(); +#else + g_wlan.tx_buffer = (uint8_t *)g_wlan.os_func.os_malloc(g_wlan.tx_buffer_size); +#endif + PRINT_D(TX_DBG, "g_wlan.tx_buffer = %p\n", g_wlan.tx_buffer); + + if (g_wlan.tx_buffer == NULL) { + /* ENOBUFS 105 */ + ret = -105; + PRINT_ER("Can't allocate Tx Buffer"); + goto _fail_; + } + +/* rx_buffer is not used unless we activate USE_MEM STATIC which is not applicable, allocating such memory is useless*/ +#if defined (MEMORY_STATIC) + if (g_wlan.rx_buffer == NULL) + #if (defined WILC_PREALLOC_AT_BOOT) + g_wlan.rx_buffer = (uint8_t *)get_rx_buffer(); + #else + g_wlan.rx_buffer = (uint8_t *)g_wlan.os_func.os_malloc(g_wlan.rx_buffer_size); + #endif + PRINT_D(TX_DBG, "g_wlan.rx_buffer =%p\n", g_wlan.rx_buffer); + if (g_wlan.rx_buffer == NULL) { + /* ENOBUFS 105 */ + ret = -105; + PRINT_ER("Can't allocate Rx Buffer"); + goto _fail_; + } +#endif + + /** + * export functions + **/ + oup->wlan_firmware_download = wilc_wlan_firmware_download; + oup->wlan_start = wilc_wlan_start; + oup->wlan_stop = wilc_wlan_stop; + oup->wlan_add_to_tx_que = wilc_wlan_txq_add_net_pkt; + oup->wlan_handle_tx_que = wilc_wlan_handle_txq; + oup->wlan_handle_rx_que = wilc_wlan_handle_rxq; + oup->wlan_handle_rx_isr = wilc_handle_isr; + oup->wlan_cleanup = wilc_wlan_cleanup; + oup->wlan_cfg_set = wilc_wlan_cfg_set; + oup->wlan_cfg_get = wilc_wlan_cfg_get; + oup->wlan_cfg_get_value = wilc_wlan_cfg_get_val; + + /*Bug3959: transmitting mgmt frames received from host*/ + #if defined(WILC_AP_EXTERNAL_MLME) || defined(WILC_P2P) + oup->wlan_add_mgmt_to_tx_que = wilc_wlan_txq_add_mgmt_pkt; + + #ifdef WILC_FULLY_HOSTING_AP + oup->wlan_add_data_to_tx_que = wilc_FH_wlan_txq_add_net_pkt; + #endif + #endif + + if (!init_chip()) { + /* EIO 5 */ + ret = -5; + goto _fail_; + } +#ifdef TCP_ACK_FILTER + Init_TCP_tracking(); +#endif + +#if defined(PLAT_RK3026_TCHIP) /* AMR : 0422 RK3026 Crash issue */ + if (!g_wilc_initialized) + custom_unlock_bus(g_mac_open); +#endif + + return 1; + +_fail_: + +#if (defined WILC_PREALLOC_AT_BOOT) + +#else + #ifdef MEMORY_STATIC + if (g_wlan.rx_buffer) { + g_wlan.os_func.os_free(g_wlan.rx_buffer); + g_wlan.rx_buffer = NULL; + } + #endif + if (g_wlan.tx_buffer) { + g_wlan.os_func.os_free(g_wlan.tx_buffer); + g_wlan.tx_buffer = NULL; + } +#endif + +#if defined(PLAT_RK3026_TCHIP) /* AMR : 0422 RK3026 Crash issue */ + if (!g_wilc_initialized) + custom_unlock_bus(g_mac_open); +#endif + + return ret; + +} + +#define BIT31 (1 << 31) +u16 Set_machw_change_vir_if(bool bValue) +{ + u16 ret; + u32 reg; + + /*Reset WILC_CHANGING_VIR_IF register to allow adding futrue keys to CE H/W*/ + (&g_wlan)->os_func.os_enter_cs((&g_wlan)->hif_lock); + ret = (&g_wlan)->hif_func.hif_read_reg(WILC_CHANGING_VIR_IF, ®); + if (!ret) { + PRINT_ER("Error while Reading reg WILC_CHANGING_VIR_IF\n"); + } + + if (bValue) { + reg |= (BIT31); + } else { + reg &= ~(BIT31); + } + + ret = (&g_wlan)->hif_func.hif_write_reg(WILC_CHANGING_VIR_IF, reg); + + if (!ret) { + PRINT_ER("Error while writing reg WILC_CHANGING_VIR_IF\n"); + } + (&g_wlan)->os_func.os_leave_cs((&g_wlan)->hif_lock); + + return ret; +} + +#ifdef WILC_FULLY_HOSTING_AP +wilc_wlan_dev_t *Get_wlan_context(u16 *pu16size) +{ + *pu16size = sizeof(wilc_wlan_dev_t); + return &g_wlan; +} +#endif + diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wilc_wlan.h new file mode 100644 index 000000000..0ba7ec69e --- /dev/null +++ b/drivers/staging/wilc1000/wilc_wlan.h @@ -0,0 +1,321 @@ +#ifndef WILC_WLAN_H +#define WILC_WLAN_H + +#include "wilc_type.h" + + +#define ISWILC1000(id) (((id & 0xfffff000) == 0x100000) ? 1 : 0) + + +/******************************************** + * + * Mac eth header length + * + ********************************************/ +#define DRIVER_HANDLER_SIZE 4 +#define MAX_MAC_HDR_LEN 26 /* QOS_MAC_HDR_LEN */ +#define SUB_MSDU_HEADER_LENGTH 14 +#define SNAP_HDR_LEN 8 +#define ETHERNET_HDR_LEN 14 +#define WORD_ALIGNMENT_PAD 0 + +#define ETH_ETHERNET_HDR_OFFSET (MAX_MAC_HDR_LEN + SUB_MSDU_HEADER_LENGTH + \ + SNAP_HDR_LEN - ETHERNET_HDR_LEN + WORD_ALIGNMENT_PAD) + +/*Bug3959: transmitting mgmt frames received from host*/ +#define HOST_HDR_OFFSET 4 +#define ETHERNET_HDR_LEN 14 +#define IP_HDR_LEN 20 +#define IP_HDR_OFFSET ETHERNET_HDR_LEN +#define UDP_HDR_OFFSET (IP_HDR_LEN + IP_HDR_OFFSET) +#define UDP_HDR_LEN 8 +#define UDP_DATA_OFFSET (UDP_HDR_OFFSET + UDP_HDR_LEN) +#define ETH_CONFIG_PKT_HDR_LEN UDP_DATA_OFFSET + +#define ETH_CONFIG_PKT_HDR_OFFSET (ETH_ETHERNET_HDR_OFFSET + \ + ETH_CONFIG_PKT_HDR_LEN) +#define ACTION 0xD0 +#define PROBE_REQ 0x40 +#ifdef WILC_FULLY_HOSTING_AP +#define FH_TX_HOST_HDR_OFFSET 24 +#endif + +/******************************************** + * + * Endian Conversion + * + ********************************************/ + +#define BYTE_SWAP(val) ((((val) & 0x000000FF) << 24) + \ + (((val) & 0x0000FF00) << 8) + \ + (((val) & 0x00FF0000) >> 8) + \ + (((val) & 0xFF000000) >> 24)) + +/******************************************** + * + * Register Defines + * + ********************************************/ +#define WILC_PERIPH_REG_BASE 0x1000 +/*BugID_5137*/ +#define WILC_CHANGING_VIR_IF (0x108c) +#define WILC_CHIPID (WILC_PERIPH_REG_BASE) +#define WILC_GLB_RESET_0 (WILC_PERIPH_REG_BASE + 0x400) +#define WILC_PIN_MUX_0 (WILC_PERIPH_REG_BASE + 0x408) +#define WILC_HOST_TX_CTRL (WILC_PERIPH_REG_BASE + 0x6c) +#define WILC_HOST_RX_CTRL_0 (WILC_PERIPH_REG_BASE + 0x70) +#define WILC_HOST_RX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x74) +#define WILC_HOST_VMM_CTL (WILC_PERIPH_REG_BASE + 0x78) +#define WILC_HOST_RX_CTRL (WILC_PERIPH_REG_BASE + 0x80) +#define WILC_HOST_RX_EXTRA_SIZE (WILC_PERIPH_REG_BASE + 0x84) +#define WILC_HOST_TX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x88) +#define WILC_MISC (WILC_PERIPH_REG_BASE + 0x428) +#define WILC_INTR_REG_BASE (WILC_PERIPH_REG_BASE + 0xa00) +#define WILC_INTR_ENABLE (WILC_INTR_REG_BASE) +#define WILC_INTR2_ENABLE (WILC_INTR_REG_BASE + 4) + +#define WILC_INTR_POLARITY (WILC_INTR_REG_BASE + 0x10) +#define WILC_INTR_TYPE (WILC_INTR_REG_BASE + 0x20) +#define WILC_INTR_CLEAR (WILC_INTR_REG_BASE + 0x30) +#define WILC_INTR_STATUS (WILC_INTR_REG_BASE + 0x40) + +#define WILC_VMM_TBL_SIZE 64 +#define WILC_VMM_TX_TBL_BASE (0x150400) +#define WILC_VMM_RX_TBL_BASE (0x150500) + +#define WILC_VMM_BASE 0x150000 +#define WILC_VMM_CORE_CTL (WILC_VMM_BASE) +#define WILC_VMM_TBL_CTL (WILC_VMM_BASE + 0x4) +#define WILC_VMM_TBL_ENTRY (WILC_VMM_BASE + 0x8) +#define WILC_VMM_TBL0_SIZE (WILC_VMM_BASE + 0xc) +#define WILC_VMM_TO_HOST_SIZE (WILC_VMM_BASE + 0x10) +#define WILC_VMM_CORE_CFG (WILC_VMM_BASE + 0x14) +#define WILC_VMM_TBL_ACTIVE (WILC_VMM_BASE + 040) +#define WILC_VMM_TBL_STATUS (WILC_VMM_BASE + 0x44) + +#define WILC_SPI_REG_BASE 0xe800 +#define WILC_SPI_CTL (WILC_SPI_REG_BASE) +#define WILC_SPI_MASTER_DMA_ADDR (WILC_SPI_REG_BASE + 0x4) +#define WILC_SPI_MASTER_DMA_COUNT (WILC_SPI_REG_BASE + 0x8) +#define WILC_SPI_SLAVE_DMA_ADDR (WILC_SPI_REG_BASE + 0xc) +#define WILC_SPI_SLAVE_DMA_COUNT (WILC_SPI_REG_BASE + 0x10) +#define WILC_SPI_TX_MODE (WILC_SPI_REG_BASE + 0x20) +#define WILC_SPI_PROTOCOL_CONFIG (WILC_SPI_REG_BASE + 0x24) +#define WILC_SPI_INTR_CTL (WILC_SPI_REG_BASE + 0x2c) + +#define WILC_SPI_PROTOCOL_OFFSET (WILC_SPI_PROTOCOL_CONFIG - WILC_SPI_REG_BASE) + +#define WILC_AHB_DATA_MEM_BASE 0x30000 +#define WILC_AHB_SHARE_MEM_BASE 0xd0000 + +#define WILC_VMM_TBL_RX_SHADOW_BASE WILC_AHB_SHARE_MEM_BASE /* Bug 4477 fix */ +#define WILC_VMM_TBL_RX_SHADOW_SIZE (256) /* Bug 4477 fix */ + +#define WILC_GP_REG_0 0x149c +#define WILC_GP_REG_1 0x14a0 + +#define rHAVE_SDIO_IRQ_GPIO_BIT (0) +#define rHAVE_USE_PMU_BIT (1) +#define rHAVE_SLEEP_CLK_SRC_RTC_BIT (2) +#define rHAVE_SLEEP_CLK_SRC_XO_BIT (3) +#define rHAVE_EXT_PA_INV_TX_RX_BIT (4) +#define rHAVE_LEGACY_RF_SETTINGS_BIT (5) +#define rHAVE_XTAL_24_BIT (6) +#define rHAVE_DISABLE_WILC_UART_BIT (7) + + +#define WILC_HAVE_SDIO_IRQ_GPIO (1 << rHAVE_SDIO_IRQ_GPIO_BIT) +#define WILC_HAVE_USE_PMU (1 << rHAVE_USE_PMU_BIT) +#define WILC_HAVE_SLEEP_CLK_SRC_RTC (1 << rHAVE_SLEEP_CLK_SRC_RTC_BIT) +#define WILC_HAVE_SLEEP_CLK_SRC_XO (1 << rHAVE_SLEEP_CLK_SRC_XO_BIT) +#define WILC_HAVE_EXT_PA_INV_TX_RX (1 << rHAVE_EXT_PA_INV_TX_RX_BIT) +#define WILC_HAVE_LEGACY_RF_SETTINGS (1 << rHAVE_LEGACY_RF_SETTINGS_BIT) +#define WILC_HAVE_XTAL_24 (1 << rHAVE_XTAL_24_BIT) +#define WILC_HAVE_DISABLE_WILC_UART (1 << rHAVE_DISABLE_WILC_UART_BIT) + + +/******************************************** + * + * Wlan Defines + * + ********************************************/ +#define WILC_CFG_PKT 1 +#define WILC_NET_PKT 0 +/*Bug3959: transmitting mgmt frames received from host*/ +#ifdef WILC_AP_EXTERNAL_MLME +#define WILC_MGMT_PKT 2 + +#ifdef WILC_FULLY_HOSTING_AP +#define WILC_FH_DATA_PKT 4 +#endif + +#endif /*WILC_AP_EXTERNAL_MLME*/ +#define WILC_CFG_SET 1 +#define WILC_CFG_QUERY 0 + +#define WILC_CFG_RSP 1 +#define WILC_CFG_RSP_STATUS 2 +#define WILC_CFG_RSP_SCAN 3 + +#ifdef WILC_SDIO +#define WILC_PLL_TO 4 +#else +#define WILC_PLL_TO 2 +#endif + + +#define ABORT_INT (1 << 31) + +/*******************************************/ +/* E0 and later Interrupt flags. */ +/*******************************************/ +/*******************************************/ +/* E0 and later Interrupt flags. */ +/* IRQ Status word */ +/* 15:0 = DMA count in words. */ +/* 16: INT0 flag */ +/* 17: INT1 flag */ +/* 18: INT2 flag */ +/* 19: INT3 flag */ +/* 20: INT4 flag */ +/* 21: INT5 flag */ +/*******************************************/ +#define IRG_FLAGS_OFFSET 16 +#define IRQ_DMA_WD_CNT_MASK ((1ul << IRG_FLAGS_OFFSET) - 1) +#define INT_0 (1 << (IRG_FLAGS_OFFSET)) +#define INT_1 (1 << (IRG_FLAGS_OFFSET + 1)) +#define INT_2 (1 << (IRG_FLAGS_OFFSET + 2)) +#define INT_3 (1 << (IRG_FLAGS_OFFSET + 3)) +#define INT_4 (1 << (IRG_FLAGS_OFFSET + 4)) +#define INT_5 (1 << (IRG_FLAGS_OFFSET + 5)) +#define MAX_NUM_INT (6) + +/*******************************************/ +/* E0 and later Interrupt flags. */ +/* IRQ Clear word */ +/* 0: Clear INT0 */ +/* 1: Clear INT1 */ +/* 2: Clear INT2 */ +/* 3: Clear INT3 */ +/* 4: Clear INT4 */ +/* 5: Clear INT5 */ +/* 6: Select VMM table 1 */ +/* 7: Select VMM table 2 */ +/* 8: Enable VMM */ +/*******************************************/ +#define CLR_INT0 (1 << 0) +#define CLR_INT1 (1 << 1) +#define CLR_INT2 (1 << 2) +#define CLR_INT3 (1 << 3) +#define CLR_INT4 (1 << 4) +#define CLR_INT5 (1 << 5) +#define SEL_VMM_TBL0 (1 << 6) +#define SEL_VMM_TBL1 (1 << 7) +#define EN_VMM (1 << 8) + +#define DATA_INT_EXT INT_0 +#define PLL_INT_EXT INT_1 +#define SLEEP_INT_EXT INT_2 +#define ALL_INT_EXT (DATA_INT_EXT | PLL_INT_EXT | SLEEP_INT_EXT) +#define NUM_INT_EXT (3) + +#define DATA_INT_CLR CLR_INT0 +#define PLL_INT_CLR CLR_INT1 +#define SLEEP_INT_CLR CLR_INT2 + +#define ENABLE_RX_VMM (SEL_VMM_TBL1 | EN_VMM) +#define ENABLE_TX_VMM (SEL_VMM_TBL0 | EN_VMM) + + +/*time for expiring the semaphores of cfg packets*/ +#define CFG_PKTS_TIMEOUT 2000 +/******************************************** + * + * Debug Type + * + ********************************************/ +typedef void (*wilc_debug_func)(uint32_t, char *, ...); + +/******************************************** + * + * Tx/Rx Queue Structure + * + ********************************************/ + +struct txq_entry_t { + struct txq_entry_t *next; + struct txq_entry_t *prev; + int type; + int tcp_PendingAck_index; + uint8_t *buffer; + int buffer_size; + void *priv; + int status; + void (*tx_complete_func)(void *, int); +}; + +struct rxq_entry_t { + struct rxq_entry_t *next; + uint8_t *buffer; + int buffer_size; +}; + +/******************************************** + * + * Host IF Structure + * + ********************************************/ + +typedef struct { + int (*hif_init)(wilc_wlan_inp_t *, wilc_debug_func); + int (*hif_deinit)(void *); + int (*hif_read_reg)(uint32_t, uint32_t *); + int (*hif_write_reg)(uint32_t, uint32_t); + int (*hif_block_rx)(uint32_t, uint8_t *, uint32_t); + int (*hif_block_tx)(uint32_t, uint8_t *, uint32_t); + int (*hif_sync)(void); + int (*hif_clear_int)(void); + int (*hif_read_int)(uint32_t *); + int (*hif_clear_int_ext)(uint32_t); + int (*hif_read_size)(uint32_t *); + int (*hif_block_tx_ext)(uint32_t, uint8_t *, uint32_t); + int (*hif_block_rx_ext)(uint32_t, uint8_t *, uint32_t); + int (*hif_sync_ext)(int); + void (*hif_set_max_bus_speed)(void); + void (*hif_set_default_bus_speed)(void); +} wilc_hif_func_t; + +/******************************************** + * + * Configuration Structure + * + ********************************************/ + +#define MAX_CFG_FRAME_SIZE 1468 + +typedef struct { + uint8_t ether_header[14]; + uint8_t ip_header[20]; + uint8_t udp_header[8]; + uint8_t wid_header[8]; + uint8_t frame[MAX_CFG_FRAME_SIZE]; +} wilc_cfg_frame_t; + +typedef struct { + int (*wlan_tx)(uint8_t *, uint32_t, wilc_tx_complete_func_t); +} wilc_wlan_cfg_func_t; + +typedef struct { + int type; + uint32_t seq_no; +} wilc_cfg_rsp_t; + +typedef struct { + int (*cfg_wid_set)(uint8_t *, uint32_t, uint16_t, uint8_t *, int); + int (*cfg_wid_get)(uint8_t *, uint32_t, uint16_t); + int (*cfg_wid_get_val)(uint16_t, uint8_t *, uint32_t); + int (*rx_indicate)(uint8_t *, int, wilc_cfg_rsp_t *); + int (*cfg_init)(wilc_debug_func); +} wilc_cfg_func_t; + +#endif diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wilc_wlan_cfg.c new file mode 100644 index 000000000..3cffe55b3 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_wlan_cfg.c @@ -0,0 +1,617 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_wlan_cfg.c */ +/* */ +/* */ +/* ///////////////////////////////////////////////////////////////////////// */ + +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" +#include "wilc_wlan_cfg.h" +#include "coreconfigurator.h" + +#ifdef WILC_FULLY_HOSTING_AP +#include "wilc_host_ap.h" +void WILC_mgm_HOSTAPD_ACK(void *priv, bool bStatus); +#endif + +/******************************************** + * + * Global Data + * + ********************************************/ + +typedef struct { + wilc_debug_func dPrint; + + int mac_status; + uint8_t mac_address[7]; + uint8_t ip_address[5]; + uint8_t bssid[7]; + uint8_t ssid[34]; + uint8_t firmware_version[129]; + uint8_t supp_rate[24]; + uint8_t wep_key[28]; + uint8_t i_psk[66]; + uint8_t hardwareProductVersion[33]; + uint8_t phyversion[17]; + uint8_t supp_username[21]; + uint8_t supp_password[64]; + uint8_t assoc_req[256]; + uint8_t assoc_rsp[256]; + uint8_t firmware_info[8]; + uint8_t scan_result[256]; + uint8_t scan_result1[256]; +} wilc_mac_cfg_t; + +static wilc_mac_cfg_t g_mac; + +static wilc_cfg_byte_t g_cfg_byte[] = { + {WID_BSS_TYPE, 0}, + {WID_CURRENT_TX_RATE, 0}, + {WID_CURRENT_CHANNEL, 0}, + {WID_PREAMBLE, 0}, + {WID_11G_OPERATING_MODE, 0}, + {WID_STATUS, 0}, + {WID_SCAN_TYPE, 0}, + {WID_KEY_ID, 0}, + {WID_QOS_ENABLE, 0}, + {WID_POWER_MANAGEMENT, 0}, + {WID_11I_MODE, 0}, + {WID_AUTH_TYPE, 0}, + {WID_SITE_SURVEY, 0}, + {WID_LISTEN_INTERVAL, 0}, + {WID_DTIM_PERIOD, 0}, + {WID_ACK_POLICY, 0}, + {WID_BCAST_SSID, 0}, + {WID_REKEY_POLICY, 0}, + {WID_SHORT_SLOT_ALLOWED, 0}, + {WID_START_SCAN_REQ, 0}, + {WID_RSSI, 0}, + {WID_LINKSPEED, 0}, + {WID_AUTO_RX_SENSITIVITY, 0}, + {WID_DATAFLOW_CONTROL, 0}, + {WID_SCAN_FILTER, 0}, + {WID_11N_PROT_MECH, 0}, + {WID_11N_ERP_PROT_TYPE, 0}, + {WID_11N_ENABLE, 0}, + {WID_11N_OPERATING_MODE, 0}, + {WID_11N_OBSS_NONHT_DETECTION, 0}, + {WID_11N_HT_PROT_TYPE, 0}, + {WID_11N_RIFS_PROT_ENABLE, 0}, + {WID_11N_SMPS_MODE, 0}, + {WID_11N_CURRENT_TX_MCS, 0}, + {WID_11N_SHORT_GI_ENABLE, 0}, + {WID_RIFS_MODE, 0}, + {WID_TX_ABORT_CONFIG, 0}, + {WID_11N_IMMEDIATE_BA_ENABLED, 0}, + {WID_11N_TXOP_PROT_DISABLE, 0}, + {WID_NIL, 0} +}; + +static wilc_cfg_hword_t g_cfg_hword[] = { + {WID_LINK_LOSS_THRESHOLD, 0}, + {WID_RTS_THRESHOLD, 0}, + {WID_FRAG_THRESHOLD, 0}, + {WID_SHORT_RETRY_LIMIT, 0}, + {WID_LONG_RETRY_LIMIT, 0}, + {WID_BEACON_INTERVAL, 0}, + {WID_RX_SENSE, 0}, + {WID_ACTIVE_SCAN_TIME, 0}, + {WID_PASSIVE_SCAN_TIME, 0}, + {WID_SITE_SURVEY_SCAN_TIME, 0}, + {WID_JOIN_START_TIMEOUT, 0}, + {WID_AUTH_TIMEOUT, 0}, + {WID_ASOC_TIMEOUT, 0}, + {WID_11I_PROTOCOL_TIMEOUT, 0}, + {WID_EAPOL_RESPONSE_TIMEOUT, 0}, + {WID_11N_SIG_QUAL_VAL, 0}, + {WID_CCA_THRESHOLD, 0}, + {WID_NIL, 0} +}; + +static wilc_cfg_word_t g_cfg_word[] = { + {WID_FAILED_COUNT, 0}, + {WID_RETRY_COUNT, 0}, + {WID_MULTIPLE_RETRY_COUNT, 0}, + {WID_FRAME_DUPLICATE_COUNT, 0}, + {WID_ACK_FAILURE_COUNT, 0}, + {WID_RECEIVED_FRAGMENT_COUNT, 0}, + {WID_MCAST_RECEIVED_FRAME_COUNT, 0}, + {WID_FCS_ERROR_COUNT, 0}, + {WID_SUCCESS_FRAME_COUNT, 0}, + {WID_TX_FRAGMENT_COUNT, 0}, + {WID_TX_MULTICAST_FRAME_COUNT, 0}, + {WID_RTS_SUCCESS_COUNT, 0}, + {WID_RTS_FAILURE_COUNT, 0}, + {WID_WEP_UNDECRYPTABLE_COUNT, 0}, + {WID_REKEY_PERIOD, 0}, + {WID_REKEY_PACKET_COUNT, 0}, + {WID_HW_RX_COUNT, 0}, + {WID_GET_INACTIVE_TIME, 0}, + {WID_NIL, 0} + +}; + +static wilc_cfg_str_t g_cfg_str[] = { + {WID_SSID, g_mac.ssid}, /* 33 + 1 bytes */ + {WID_FIRMWARE_VERSION, g_mac.firmware_version}, + {WID_OPERATIONAL_RATE_SET, g_mac.supp_rate}, + {WID_BSSID, g_mac.bssid}, /* 6 bytes */ + {WID_WEP_KEY_VALUE, g_mac.wep_key}, /* 27 bytes */ + {WID_11I_PSK, g_mac.i_psk}, /* 65 bytes */ + /* {WID_11E_P_ACTION_REQ, g_mac.action_req}, */ + {WID_HARDWARE_VERSION, g_mac.hardwareProductVersion}, + {WID_MAC_ADDR, g_mac.mac_address}, + {WID_PHY_VERSION, g_mac.phyversion}, + {WID_SUPP_USERNAME, g_mac.supp_username}, + {WID_SUPP_PASSWORD, g_mac.supp_password}, + {WID_SITE_SURVEY_RESULTS, g_mac.scan_result}, + {WID_SITE_SURVEY_RESULTS, g_mac.scan_result1}, + /* {WID_RX_POWER_LEVEL, g_mac.channel_rssi}, */ + {WID_ASSOC_REQ_INFO, g_mac.assoc_req}, + {WID_ASSOC_RES_INFO, g_mac.assoc_rsp}, + /* {WID_11N_P_ACTION_REQ, g_mac.action_req}, */ + {WID_FIRMWARE_INFO, g_mac.firmware_version}, + {WID_IP_ADDRESS, g_mac.ip_address}, + {WID_NIL, NULL} +}; + +/******************************************** + * + * Configuration Functions + * + ********************************************/ + +static int wilc_wlan_cfg_set_byte(uint8_t *frame, uint32_t offset, uint16_t id, uint8_t val8) +{ + uint8_t *buf; + + if ((offset + 4) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + + buf[0] = (uint8_t)id; + buf[1] = (uint8_t)(id >> 8); + buf[2] = 1; + buf[3] = val8; + return 4; +} + +static int wilc_wlan_cfg_set_hword(uint8_t *frame, uint32_t offset, uint16_t id, uint16_t val16) +{ + uint8_t *buf; + + if ((offset + 5) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + + buf[0] = (uint8_t)id; + buf[1] = (uint8_t)(id >> 8); + buf[2] = 2; + buf[3] = (uint8_t)val16; + buf[4] = (uint8_t)(val16 >> 8); + + return 5; +} + +static int wilc_wlan_cfg_set_word(uint8_t *frame, uint32_t offset, uint16_t id, uint32_t val32) +{ + uint8_t *buf; + + if ((offset + 7) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + + buf[0] = (uint8_t)id; + buf[1] = (uint8_t)(id >> 8); + buf[2] = 4; + buf[3] = (uint8_t)val32; + buf[4] = (uint8_t)(val32 >> 8); + buf[5] = (uint8_t)(val32 >> 16); + buf[6] = (uint8_t)(val32 >> 24); + + return 7; +} + +static int wilc_wlan_cfg_set_str(uint8_t *frame, uint32_t offset, uint16_t id, uint8_t *str, uint32_t size) +{ + uint8_t *buf; + + if ((offset + size + 3) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + + buf[0] = (uint8_t)id; + buf[1] = (uint8_t)(id >> 8); + buf[2] = (uint8_t)size; + + if ((str != NULL) && (size != 0)) + memcpy(&buf[3], str, size); + + return (size + 3); +} + +static int wilc_wlan_cfg_set_bin(uint8_t *frame, uint32_t offset, uint16_t id, uint8_t *b, uint32_t size) +{ + uint8_t *buf; + uint32_t i; + uint8_t checksum = 0; + + if ((offset + size + 5) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + buf[0] = (uint8_t)id; + buf[1] = (uint8_t)(id >> 8); + buf[2] = (uint8_t)size; + buf[3] = (uint8_t)(size >> 8); + + if ((b != NULL) && (size != 0)) { + memcpy(&buf[4], b, size); + for (i = 0; i < size; i++) { + checksum += buf[i + 4]; + } + } + + buf[size + 4] = checksum; + + return (size + 5); +} + +/******************************************** + * + * Configuration Response Functions + * + ********************************************/ + +static void wilc_wlan_parse_response_frame(uint8_t *info, int size) +{ + uint32_t wid, len = 0, i = 0; + static int seq; + + while (size > 0) { + i = 0; + wid = info[0] | (info[1] << 8); +#ifdef BIG_ENDIAN + wid = BYTE_SWAP(wid); +#endif + PRINT_INFO(GENERIC_DBG, "Processing response for %d seq %d\n", wid, seq++); + switch ((wid >> 12) & 0x7) { + case WID_CHAR: + do { + if (g_cfg_byte[i].id == WID_NIL) + break; + + if (g_cfg_byte[i].id == wid) { + g_cfg_byte[i].val = info[3]; + break; + } + i++; + } while (1); + len = 2; + break; + + case WID_SHORT: + do { + if (g_cfg_hword[i].id == WID_NIL) + break; + + if (g_cfg_hword[i].id == wid) { +#ifdef BIG_ENDIAN + g_cfg_hword[i].val = (info[3] << 8) | (info[4]); +#else + g_cfg_hword[i].val = info[3] | (info[4] << 8); +#endif + break; + } + i++; + } while (1); + len = 3; + break; + + case WID_INT: + do { + if (g_cfg_word[i].id == WID_NIL) + break; + + if (g_cfg_word[i].id == wid) { +#ifdef BIG_ENDIAN + g_cfg_word[i].val = (info[3] << 24) | (info[4] << 16) | (info[5] << 8) | (info[6]); +#else + g_cfg_word[i].val = info[3] | (info[4] << 8) | (info[5] << 16) | (info[6] << 24); +#endif + break; + } + i++; + } while (1); + len = 5; + break; + + case WID_STR: + do { + if (g_cfg_str[i].id == WID_NIL) + break; + + if (g_cfg_str[i].id == wid) { + if (wid == WID_SITE_SURVEY_RESULTS) { + static int toggle; + PRINT_INFO(GENERIC_DBG, "Site survey results received[%d]\n", + size); + + PRINT_INFO(GENERIC_DBG, "Site survey results value[%d]toggle[%d]\n", size, toggle); + i += toggle; + toggle ^= 1; + } + memcpy(g_cfg_str[i].str, &info[2], (info[2] + 1)); + break; + } + i++; + } while (1); + len = 1 + info[2]; + break; + + default: + break; + } + size -= (2 + len); + info += (2 + len); + } + + return; +} + +static int wilc_wlan_parse_info_frame(uint8_t *info, int size) +{ + wilc_mac_cfg_t *pd = (wilc_mac_cfg_t *)&g_mac; + uint32_t wid, len; + int type = WILC_CFG_RSP_STATUS; + + wid = info[0] | (info[1] << 8); + + len = info[2]; + PRINT_INFO(GENERIC_DBG, "Status Len = %d Id= %d\n", len, wid); + if ((len == 1) && (wid == WID_STATUS)) { + pd->mac_status = info[3]; + type = WILC_CFG_RSP_STATUS; + } + + return type; +} + +/******************************************** + * + * Configuration Exported Functions + * + ********************************************/ + +static int wilc_wlan_cfg_set_wid(uint8_t *frame, uint32_t offset, uint16_t id, uint8_t *buf, int size) +{ + uint8_t type = (id >> 12) & 0xf; + int ret = 0; + + if (type == 0) { /* byte command */ + if (size >= 1) + ret = wilc_wlan_cfg_set_byte(frame, offset, id, *buf); + } else if (type == 1) { /* half word command */ + if (size >= 2) + ret = wilc_wlan_cfg_set_hword(frame, offset, id, *((uint16_t *)buf)); + } else if (type == 2) { /* word command */ + if (size >= 4) + ret = wilc_wlan_cfg_set_word(frame, offset, id, *((uint32_t *)buf)); + } else if (type == 3) { /* string command */ + ret = wilc_wlan_cfg_set_str(frame, offset, id, buf, size); + } else if (type == 4) { /* binary command */ + ret = wilc_wlan_cfg_set_bin(frame, offset, id, buf, size); + } else { + g_mac.dPrint(N_ERR, "illegal id\n"); + } + + return ret; +} + +static int wilc_wlan_cfg_get_wid(uint8_t *frame, uint32_t offset, uint16_t id) +{ + uint8_t *buf; + + if ((offset + 2) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + + buf[0] = (uint8_t)id; + buf[1] = (uint8_t)(id >> 8); + + return 2; +} + +static int wilc_wlan_cfg_get_wid_value(uint16_t wid, uint8_t *buffer, uint32_t buffer_size) +{ + uint32_t type = (wid >> 12) & 0xf; + int i, ret = 0; + + if (wid == WID_STATUS) { + *((uint32_t *)buffer) = g_mac.mac_status; + return 4; + } + + i = 0; + if (type == 0) { /* byte command */ + do { + if (g_cfg_byte[i].id == WID_NIL) + break; + + if (g_cfg_byte[i].id == wid) { + memcpy(buffer, &g_cfg_byte[i].val, 1); + ret = 1; + break; + } + i++; + } while (1); + } else if (type == 1) { /* half word command */ + do { + if (g_cfg_hword[i].id == WID_NIL) + break; + + if (g_cfg_hword[i].id == wid) { + memcpy(buffer, &g_cfg_hword[i].val, 2); + ret = 2; + break; + } + i++; + } while (1); + } else if (type == 2) { /* word command */ + do { + if (g_cfg_word[i].id == WID_NIL) + break; + + if (g_cfg_word[i].id == wid) { + memcpy(buffer, &g_cfg_word[i].val, 4); + ret = 4; + break; + } + i++; + } while (1); + } else if (type == 3) { /* string command */ + do { + if (g_cfg_str[i].id == WID_NIL) + break; + + if (g_cfg_str[i].id == wid) { + uint32_t size = g_cfg_str[i].str[0]; + if (buffer_size >= size) { + if (g_cfg_str[i].id == WID_SITE_SURVEY_RESULTS) { + static int toggle; + PRINT_INFO(GENERIC_DBG, "Site survey results value[%d]\n", + size); + i += toggle; + toggle ^= 1; + + } + memcpy(buffer, &g_cfg_str[i].str[1], size); + ret = size; + } + break; + } + i++; + } while (1); + } else { + g_mac.dPrint(N_ERR, "[CFG]: illegal type (%08x)\n", wid); + } + + return ret; +} + +static int wilc_wlan_cfg_indicate_rx(uint8_t *frame, int size, wilc_cfg_rsp_t *rsp) +{ + int ret = 1; + uint8_t msg_type; + uint8_t msg_id; + uint16_t msg_len; + #ifdef WILC_FULLY_HOSTING_AP + u32 *ptru32Frame; + bool bStatus = frame[2]; + + #ifdef BIG_ENDIAN + ptru32Frame = (frame[4] << 24) | (frame[5] << 16) | (frame[6] << 8) | frame[7]; + #else + ptru32Frame = (frame[7] << 24) | (frame[6] << 16) | (frame[5] << 8) | frame[4]; + #endif /* BIG_ENDIAN */ + + #endif /* WILC_FULLY_HOSTING_AP */ + + msg_type = frame[0]; + msg_id = frame[1]; /* seq no */ +#ifdef BIG_ENDIAN + msg_len = (frame[2] << 8) | frame[3]; +#else + msg_len = (frame[3] << 8) | frame[2]; +#endif + frame += 4; + size -= 4; + + /** + * The valid types of response messages are 'R' (Response), 'I' (Information), and 'N' (Network Information) + **/ + + switch (msg_type) { + case 'R': + wilc_wlan_parse_response_frame(frame, size); + rsp->type = WILC_CFG_RSP; + rsp->seq_no = msg_id; + break; + + case 'I': + rsp->type = wilc_wlan_parse_info_frame(frame, size); + rsp->seq_no = msg_id; + /*call host interface info parse as well*/ + PRINT_INFO(RX_DBG, "Info message received\n"); + GnrlAsyncInfoReceived(frame - 4, size + 4); + break; + + case 'L': +#ifndef SWITCH_LOG_TERMINAL + PRINT_ER("Unexpected firmware log message received \n"); +#else + PRINT_D(FIRM_DBG, "\nFIRMWARE LOGS :\n<<\n%s\n>>\n", frame); + break; + +#endif +#if 1 + case 'N': + NetworkInfoReceived(frame - 4, size + 4); + rsp->type = 0; + break; + +#endif +/*bug3819:*/ + case 'S': + PRINT_INFO(RX_DBG, "Scan Notification Received \n"); + host_int_ScanCompleteReceived(frame - 4, size + 4); + break; + +#ifdef WILC_FULLY_HOSTING_AP + case 'T': + PRINT_INFO(RX_DBG, "TBTT Notification Received \n"); + process_tbtt_isr(); + break; + + case 'A': + PRINT_INFO(RX_DBG, "HOSTAPD ACK Notification Received \n"); + WILC_mgm_HOSTAPD_ACK(ptru32Frame, bStatus); + break; +#endif + + default: + PRINT_INFO(RX_DBG, "Receive unknown message type[%d-%d-%d-%d-%d-%d-%d-%d]\n", + frame[0], frame[1], frame[2], frame[3], frame[4], + frame[5], frame[6], frame[7]); + rsp->type = 0; + rsp->seq_no = msg_id; + ret = 0; + break; + } + + return ret; +} + +static int wilc_wlan_cfg_init(wilc_debug_func func) +{ + memset((void *)&g_mac, 0, sizeof(wilc_mac_cfg_t)); + g_mac.dPrint = func; + return 1; +} + +wilc_cfg_func_t mac_cfg = { + wilc_wlan_cfg_set_wid, + wilc_wlan_cfg_get_wid, + wilc_wlan_cfg_get_wid_value, + wilc_wlan_cfg_indicate_rx, + wilc_wlan_cfg_init, +}; diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.h b/drivers/staging/wilc1000/wilc_wlan_cfg.h new file mode 100644 index 000000000..8906611b2 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_wlan_cfg.h @@ -0,0 +1,33 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_wlan_cfg.h */ +/* */ +/* */ +/* ///////////////////////////////////////////////////////////////////////// */ + +#ifndef WILC_WLAN_CFG_H +#define WILC_WLAN_CFG_H + +typedef struct { + uint16_t id; + uint16_t val; +} wilc_cfg_byte_t; + +typedef struct { + uint16_t id; + uint16_t val; +} wilc_cfg_hword_t; + +typedef struct { + uint32_t id; + uint32_t val; +} wilc_cfg_word_t; + +typedef struct { + uint32_t id; + uint8_t *str; +} wilc_cfg_str_t; + +#endif diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wilc_wlan_if.h new file mode 100644 index 000000000..8ed51e385 --- /dev/null +++ b/drivers/staging/wilc1000/wilc_wlan_if.h @@ -0,0 +1,969 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_wlan_if.h */ +/* */ +/* */ +/* ///////////////////////////////////////////////////////////////////////// */ + + +#ifndef WILC_WLAN_IF_H +#define WILC_WLAN_IF_H + +/*bug 3887: [AP] Allow Management frames to be passed to the host*/ +#define WILC_AP_EXTERNAL_MLME +#define WILC_P2P +#define TCP_ENHANCEMENTS +/* #define MEMORY_STATIC */ +/* #define WILC_FULLY_HOSTING_AP */ +/* #define USE_OLD_SPI_SW */ + + +#include "wilc_type.h" +#include "linux_wlan_common.h" + + +/******************************************** + * + * Debug Flags + * + ********************************************/ + +#define N_INIT 0x00000001 +#define N_ERR 0x00000002 +#define N_TXQ 0x00000004 +#define N_INTR 0x00000008 +#define N_RXQ 0x00000010 + +/******************************************** + * + * Host Interface Defines + * + ********************************************/ + +#define HIF_SDIO (0) +#define HIF_SPI (1 << 0) +#define HIF_SDIO_GPIO_IRQ (1 << 2) + + +/******************************************** + * + * Tx/Rx Buffer Size Defines + * + ********************************************/ + +#define CE_TX_BUFFER_SIZE (64 * 1024) +#define CE_RX_BUFFER_SIZE (384 * 1024) + +/******************************************** + * + * Wlan Interface Defines + * + ********************************************/ + +typedef struct { + uint32_t read_write: 1; + uint32_t function: 3; + uint32_t raw: 1; + uint32_t address: 17; + uint32_t data: 8; +} sdio_cmd52_t; + +typedef struct { + /* struct { */ + uint32_t read_write: 1; + uint32_t function: 3; + uint32_t block_mode: 1; + uint32_t increment: 1; + uint32_t address: 17; + uint32_t count: 9; + /* } bit; */ + uint8_t *buffer; + uint32_t block_size; +} sdio_cmd53_t; + +typedef struct { + void (*os_sleep)(uint32_t); + void (*os_atomic_sleep)(uint32_t); + void (*os_debug)(uint8_t *); + void *(*os_malloc)(uint32_t); + void *(*os_malloc_atomic)(uint32_t); + void (*os_free)(void *); + void (*os_lock)(void *); + void (*os_unlock)(void *); + int (*os_wait)(void *, u32); + void (*os_signal)(void *); + void (*os_enter_cs)(void *); + void (*os_leave_cs)(void *); + + /*Added by Amr - BugID_4720*/ + void (*os_spin_lock)(void *, unsigned long *); + void (*os_spin_unlock)(void *, unsigned long *); + +} wilc_wlan_os_func_t; + +typedef struct { + int io_type; + int (*io_init)(void *); + void (*io_deinit)(void *); + union { + struct { + int (*sdio_cmd52)(sdio_cmd52_t *); + int (*sdio_cmd53)(sdio_cmd53_t *); + int (*sdio_set_max_speed)(void); + int (*sdio_set_default_speed)(void); + } sdio; + struct { + int (*spi_max_speed)(void); + int (*spi_tx)(uint8_t *, uint32_t); + int (*spi_rx)(uint8_t *, uint32_t); + int (*spi_trx)(uint8_t *, uint8_t *, uint32_t); + } spi; + } u; +} wilc_wlan_io_func_t; + +typedef struct { + void (*rx_indicate)(uint8_t *, uint32_t, uint32_t); + void (*rx_complete)(void); +} wilc_wlan_net_func_t; + +typedef struct { + void (*mac_indicate)(int); +} wilc_wlan_indicate_func_t; +#define WILC_MAC_INDICATE_STATUS 0x1 +#define WILC_MAC_STATUS_INIT -1 +#define WILC_MAC_STATUS_READY 0 +#define WILC_MAC_STATUS_CONNECT 1 + +#define WILC_MAC_INDICATE_SCAN 0x2 + +typedef struct { + void *os_private; + + void *hif_critical_section; + + uint32_t tx_buffer_size; + void *txq_critical_section; + + /*Added by Amr - BugID_4720*/ + void *txq_add_to_head_critical_section; + void *txq_spin_lock; + + void *txq_wait_event; + +#if defined(MEMORY_STATIC) + uint32_t rx_buffer_size; +#endif + void *rxq_critical_section; + void *rxq_wait_event; + + void *cfg_wait_event; +} wilc_wlan_os_context_t; + +typedef struct { + wilc_wlan_os_context_t os_context; + wilc_wlan_os_func_t os_func; + wilc_wlan_io_func_t io_func; + wilc_wlan_net_func_t net_func; + wilc_wlan_indicate_func_t indicate_func; +} wilc_wlan_inp_t; + +struct tx_complete_data { + #ifdef WILC_FULLY_HOSTING_AP + struct tx_complete_data *next; + #endif + int size; + void *buff; + uint8_t *pBssid; + struct sk_buff *skb; +}; + + +typedef void (*wilc_tx_complete_func_t)(void *, int); + +#define WILC_TX_ERR_NO_BUF (-2) + +typedef struct { + int (*wlan_firmware_download)(const uint8_t *, uint32_t); + int (*wlan_start)(void); + int (*wlan_stop)(void); + int (*wlan_add_to_tx_que)(void *, uint8_t *, uint32_t, wilc_tx_complete_func_t); + int (*wlan_handle_tx_que)(uint32_t *); + void (*wlan_handle_rx_que)(void); + void (*wlan_handle_rx_isr)(void); + void (*wlan_cleanup)(void); + int (*wlan_cfg_set)(int, uint32_t, uint8_t *, uint32_t, int, uint32_t); + int (*wlan_cfg_get)(int, uint32_t, int, uint32_t); + int (*wlan_cfg_get_value)(uint32_t, uint8_t *, uint32_t); + /*Bug3959: transmitting mgmt frames received from host*/ + #if defined(WILC_AP_EXTERNAL_MLME) || defined(WILC_P2P) + int (*wlan_add_mgmt_to_tx_que)(void *, uint8_t *, uint32_t, wilc_tx_complete_func_t); + + #ifdef WILC_FULLY_HOSTING_AP + int (*wlan_add_data_to_tx_que)(void *, uint8_t *, uint32_t, wilc_tx_complete_func_t); + #endif + + #endif +} wilc_wlan_oup_t; + +/******************************************** + * + * Wlan Configuration ID + * + ********************************************/ + +#define MAX_SSID_LEN 33 +#define MAX_RATES_SUPPORTED 12 + +#define INFINITE_SLEEP_TIME ((u32)0xFFFFFFFF) + +#ifdef WILC_PARSE_SCAN_IN_HOST +typedef enum { + SUPP_RATES_IE = 1, + EXT_SUPP_RATES_IE = 50, + HT_CAPABILITY_IE = 45, + RSN_IE = 48, + WPA_IE = 221, + WMM_IE = 221, + #ifdef WILC_P2P + P2P_IE = 221, + #endif +} BEACON_IE; +#endif +typedef enum { + INFRASTRUCTURE = 0, + INDEPENDENT, + AP, +} BSSTYPE_T; + +typedef enum { + RATE_AUTO = 0, + RATE_1MB = 1, + RATE_2MB = 2, + RATE_5MB = 5, + RATE_6MB = 6, + RATE_9MB = 9, + RATE_11MB = 11, + RATE_12MB = 12, + RATE_18MB = 18, + RATE_24MB = 24, + RATE_26MB = 36, + RATE_48MB = 48, + RATE_54MB = 54 +} TX_RATE_T; + +typedef enum { + B_ONLY_MODE = 0, /* basic rate: 1, 2 Mbps, otherwise: 5, 11 Mbps */ + G_ONLY_MODE, /* basic rate: 6, 12, 24 Mbps, otherwise: 9, 18, 36, 48, 54 Mbps */ + G_MIXED_11B_1_MODE, /* basic rate: 1, 2, 5.5, 11 Mbps, otherwise: all on */ + G_MIXED_11B_2_MODE, /* basic rate: 1, 2, 5, 11, 6, 12, 24 Mbps, otherwise: all on */ +} G_OPERATING_MODE_T; + +typedef enum { + G_SHORT_PREAMBLE = 0, /* Short Preamble */ + G_LONG_PREAMBLE = 1, /* Long Preamble */ + G_AUTO_PREAMBLE = 2, /* Auto Preamble Selection */ +} G_PREAMBLE_T; + +#define MAC_CONNECTED 1 +#define MAC_DISCONNECTED 0 + +/*bug3819: */ +#define SCAN_DONE TRUE +typedef enum { + PASSIVE_SCAN = 0, + ACTIVE_SCAN = 1, +} SCANTYPE_T; + +typedef enum { + NO_POWERSAVE = 0, + MIN_FAST_PS = 1, + MAX_FAST_PS = 2, + MIN_PSPOLL_PS = 3, + MAX_PSPOLL_PS = 4 +} USER_PS_MODE_T; + +typedef enum { + CHIP_WAKEDUP = 0, + CHIP_SLEEPING_AUTO = 1, + CHIP_SLEEPING_MANUAL = 2 +} CHIP_PS_STATE_T; + +typedef enum { + ACQUIRE_ONLY = 0, + ACQUIRE_AND_WAKEUP = 1, +} BUS_ACQUIRE_T; + +typedef enum { + RELEASE_ONLY = 0, + RELEASE_ALLOW_SLEEP = 1, +} BUS_RELEASE_T; + +typedef enum { + NO_SECURITY = 0, + WEP_40 = 0x3, + WEP_104 = 0x7, + WPA_AES = 0x29, + WPA_TKIP = 0x49, + WPA_AES_TKIP = 0x69, /* Aes or Tkip */ + WPA2_AES = 0x31, + WPA2_TKIP = 0x51, + WPA2_AES_TKIP = 0x71, /* Aes or Tkip */ +} SECURITY_T; + +typedef enum { + OPEN_SYSTEM = 1, + SHARED_KEY = 2, + ANY = 3, + IEEE8021 = 5 +} AUTHTYPE_T; + +typedef enum { + SITE_SURVEY_1CH = 0, + SITE_SURVEY_ALL_CH = 1, + SITE_SURVEY_OFF = 2 +} SITE_SURVEY_T; + +typedef enum { + NORMAL_ACK = 0, + NO_ACK, +} ACK_POLICY_T; + +typedef enum { + DONT_RESET = 0, + DO_RESET = 1, + NO_REQUEST = 2, +} RESET_REQ_T; + +typedef enum { + REKEY_DISABLE = 1, + REKEY_TIME_BASE, + REKEY_PKT_BASE, + REKEY_TIME_PKT_BASE +} RSNA_REKEY_POLICY_T; + +typedef enum { + FILTER_NO = 0x00, + FILTER_AP_ONLY = 0x01, + FILTER_STA_ONLY = 0x02 +} SCAN_CLASS_FITLER_T; + +typedef enum { + PRI_HIGH_RSSI = 0x00, + PRI_LOW_RSSI = 0x04, + PRI_DETECT = 0x08 +} SCAN_PRI_T; + +typedef enum { + CH_FILTER_OFF = 0x00, + CH_FILTER_ON = 0x10 +} CH_FILTER_T; + +typedef enum { + AUTO_PROT = 0, /* Auto */ + NO_PROT, /* Do not use any protection */ + ERP_PROT, /* Protect all ERP frame exchanges */ + HT_PROT, /* Protect all HT frame exchanges */ + GF_PROT, /* Protect all GF frame exchanges */ +} N_PROTECTION_MODE_T; + +typedef enum { + G_SELF_CTS_PROT, + G_RTS_CTS_PROT, +} G_PROTECTION_MODE_T; + +typedef enum { + HT_MIXED_MODE = 1, + HT_ONLY_20MHZ_MODE, + HT_ONLY_20_40MHZ_MODE, +} N_OPERATING_MODE_T; + +typedef enum { + NO_DETECT = 0, + DETECT_ONLY = 1, + DETECT_PROTECT = 2, + DETECT_PROTECT_REPORT = 3, +} N_OBSS_DETECTION_T; + +typedef enum { + RTS_CTS_NONHT_PROT = 0, /* RTS-CTS at non-HT rate */ + FIRST_FRAME_NONHT_PROT, /* First frame at non-HT rate */ + LSIG_TXOP_PROT, /* LSIG TXOP Protection */ + FIRST_FRAME_MIXED_PROT, /* First frame at Mixed format */ +} N_PROTECTION_TYPE_T; + +typedef enum { + STATIC_MODE = 1, + DYNAMIC_MODE = 2, + MIMO_MODE = 3, /* power save disable */ +} N_SMPS_MODE_T; + +typedef enum { + DISABLE_SELF_CTS, + ENABLE_SELF_CTS, + DISABLE_TX_ABORT, + ENABLE_TX_ABORT, + HW_TRIGGER_ABORT, + SW_TRIGGER_ABORT, +} TX_ABORT_OPTION_T; + +typedef enum { + WID_CHAR = 0, + WID_SHORT = 1, + WID_INT = 2, + WID_STR = 3, + WID_BIN_DATA = 4, + WID_BIN = 5, + WID_IP = 6, + WID_ADR = 7, + WID_UNDEF = 8, + WID_TYPE_FORCE_32BIT = 0xFFFFFFFF + +} WID_TYPE_T, tenuWIDtype; + +typedef enum { + WID_NIL = 0xffff, + + + /* BSS Type */ + /* -------------------------------------------------------------- */ + /* Configuration : Infrastructure Independent Access Point */ + /* Values to set : 0 1 2 */ + /* -------------------------------------------------------------- */ + WID_BSS_TYPE = 0x0000, + + /* Transmit Rate */ + /* -------------------------------------------------------------- */ + /* Configuration : 1 2 5.5 11 6 9 12 18 24 36 48 54 */ + /* Values to set : 1 2 5 11 6 9 12 18 24 36 48 54 */ + /* -------------------------------------------------------------- */ + WID_CURRENT_TX_RATE = 0x0001, + + /* Channel */ + /* ------------------------------------------------------------------- */ + /* Configuration(g) : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 */ + /* Values to set : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 */ + /* -------------------------------------------------------------------- */ + WID_CURRENT_CHANNEL = 0x0002, + + /* Preamble */ + /* -------------------------------------------------------------- */ + /* Configuration : short long Auto */ + /* Values to set : 0 1 2 */ + /* -------------------------------------------------------------- */ + WID_PREAMBLE = 0x0003, + + /* 11g operating mode (ignored if 11g not present) */ + /* -------------------------------------------------------------- */ + /* Configuration : HighPerf Compat(RSet #1) Compat(RSet #2) */ + /* Values to set : 1 2 3 */ + /* -------------------------------------------------------------- */ + WID_11G_OPERATING_MODE = 0x0004, + + /* Mac status (response only) */ + /* -------------------------------------------------------------- */ + /* Configuration : disconnect connect */ + /* Values to get : 0 1 */ + /* -------------------------------------------------------------- */ + WID_STATUS = 0x0005, + + /* Scan type */ + /* -------------------------------------------------------------- */ + /* Configuration : Passive Scanning Active Scanning */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------- */ + WID_SCAN_TYPE = 0x0007, + + /* Key Id (WEP default key Id) */ + /* -------------------------------------------------------------- */ + /* Configuration : Any value between 0 to 3 */ + /* Values to set : Same value. Default is 0 */ + /* -------------------------------------------------------------- */ + WID_KEY_ID = 0x0009, + + /* QoS Enable */ + /* -------------------------------------------------------------- */ + /* Configuration : QoS Disable WMM Enable */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------- */ + WID_QOS_ENABLE = 0x000A, + + /* Power Management */ + /* ------------------------------------------------------------------ */ + /* Configuration : NO_POWERSAVE MIN_POWERSAVE MAX_POWERSAVE */ + /* Values to set : 0 1 2 */ + /* ------------------------------------------------------------------ */ + WID_POWER_MANAGEMENT = 0x000B, + + /* WEP/802 11I Configuration */ + /* ------------------------------------------------------------------ */ + /* Configuration : Disable WP40 WP104 WPA-AES WPA-TKIP RSN-AES RSN-TKIP */ + /* Values (0x) : 00 03 07 29 49 31 51 */ + /* */ + /* Configuration : WPA-AES+TKIP RSN-AES+TKIP */ + /* Values (0x) : 69 71 */ + /* ------------------------------------------------------------------ */ + WID_11I_MODE = 0x000C, + + /* WEP Configuration: Used in BSS STA mode only when WEP is enabled */ + /* ------------------------------------------------------------------ */ + /* Configuration : Open System Shared Key Any Type | 802.1x Auth */ + /* Values (0x) : 01 02 03 | BIT2 */ + /* ------------------------------------------------------------------ */ + WID_AUTH_TYPE = 0x000D, + + /* Site Survey Type */ + /* -------------------------------------------------------------- */ + /* Configuration : Values to set */ + /* Survey 1 Channel : 0 */ + /* survey all Channels : 1 */ + /* Disable Site Survey : 2 */ + /* -------------------------------------------------------------- */ + WID_SITE_SURVEY = 0x000E, + + /* Listen Interval */ + /* -------------------------------------------------------------- */ + /* Configuration : Any value between 1 to 255 */ + /* Values to set : Same value. Default is 3 */ + /* -------------------------------------------------------------- */ + WID_LISTEN_INTERVAL = 0x000F, + + /* DTIM Period */ + /* -------------------------------------------------------------- */ + /* Configuration : Any value between 1 to 255 */ + /* Values to set : Same value. Default is 3 */ + /* -------------------------------------------------------------- */ + WID_DTIM_PERIOD = 0x0010, + + /* ACK Policy */ + /* -------------------------------------------------------------- */ + /* Configuration : Normal Ack No Ack */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------- */ + WID_ACK_POLICY = 0x0011, + + /* Reset MAC (Set only) */ + /* -------------------------------------------------------------- */ + /* Configuration : Don't Reset Reset No Request */ + /* Values to set : 0 1 2 */ + /* -------------------------------------------------------------- */ + WID_RESET = 0x0012, + + /* Broadcast SSID Option: Setting this will adhere to "" SSID element */ + /* ------------------------------------------------------------------ */ + /* Configuration : Enable Disable */ + /* Values to set : 1 0 */ + /* ------------------------------------------------------------------ */ + WID_BCAST_SSID = 0x0015, + + /* Disconnect (Station) */ + /* ------------------------------------------------------------------ */ + /* Configuration : Association ID */ + /* Values to set : Association ID */ + /* ------------------------------------------------------------------ */ + WID_DISCONNECT = 0x0016, + + /* 11a Tx Power Level */ + /* -------------------------------------------------------------------- */ + /* Configuration : Sets TX Power (Higher the value greater the power) */ + /* Values to set : Any value between 0 and 63 (inclusive; Default is 48)*/ + /* -------------------------------------------------------------------- */ + WID_TX_POWER_LEVEL_11A = 0x0018, + + /* Group Key Update Policy Selection */ + /* -------------------------------------------------------------------- */ + /* Configuration : Disabled timeBased packetBased timePacketBased */ + /* Values to set : 1 2 3 4 */ + /* -------------------------------------------------------------------- */ + WID_REKEY_POLICY = 0x0019, + + /* Allow Short Slot */ + /* -------------------------------------------------------------- */ + /* Configuration : Disallow Short Slot Allow Short Slot */ + /* (Enable Only Long Slot) (Enable Short Slot if applicable)*/ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------- */ + WID_SHORT_SLOT_ALLOWED = 0x001A, + + WID_PHY_ACTIVE_REG = 0x001B, + + /* 11b Tx Power Level */ + /* -------------------------------------------------------------------- */ + /* Configuration : Sets TX Power (Higher the value greater the power) */ + /* Values to set : Any value between 0 and 63 (inclusive; Default is 48)*/ + /* -------------------------------------------------------------------- */ + WID_TX_POWER_LEVEL_11B = 0x001D, + + /* Scan Request */ + /* -------------------------------------------------------------------- */ + /* Configuration : Request default scan */ + /* Values to set : 0 */ + /* -------------------------------------------------------------------- */ + WID_START_SCAN_REQ = 0x001E, + + /* Rssi (get only) */ + /* -------------------------------------------------------------------- */ + /* Configuration : */ + /* Values to get : Rssi value */ + /* -------------------------------------------------------------------- */ + WID_RSSI = 0x001F, + + /* Join Request */ + /* -------------------------------------------------------------------- */ + /* Configuration : Request to join */ + /* Values to set : index of scan result */ + /* -------------------------------------------------------------------- */ + WID_JOIN_REQ = 0x0020, + + WID_LINKSPEED = 0x0026, + + /* Enable User Control of TX Power */ + /* -------------------------------------------------------------------- */ + /* Configuration : Disable Enable */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------------- */ + WID_USER_CONTROL_ON_TX_POWER = 0x0027, + + WID_MEMORY_ACCESS_8BIT = 0x0029, + + /* Enable Auto RX Sensitivity feature */ + /* -------------------------------------------------------------------- */ + /* Configuration : Disable Enable */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------------- */ + WID_AUTO_RX_SENSITIVITY = 0x0032, + + /* Receive Buffer Based Ack */ + /* -------------------------------------------------------------------- */ + /* Configuration : Disable Enable */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------------- */ + WID_DATAFLOW_CONTROL = 0x0033, + + /* Scan Filter */ + /* -------------------------------------------------------------------- */ + /* Configuration : Class No filter AP only Station Only */ + /* Values to set : 0 1 2 */ + /* Configuration : Priority High Rssi Low Rssi Detect */ + /* Values to set : 0 0x4 0x08 */ + /* Configuration : Channel filter off filter on */ + /* Values to set : 0 0x10 */ + /* -------------------------------------------------------------------- */ + WID_SCAN_FILTER = 0x0036, + + /* Link Loss Threshold (measure in the beacon period) */ + /* -------------------------------------------------------------------- */ + /* Configuration : Any value between 10 and 254 (Set to 255 to disable it) */ + /* Values to set : Same value. Default is 10 */ + /* -------------------------------------------------------------------- */ + WID_LINK_LOSS_THRESHOLD = 0x0037, + + /*BugID_4978*/ + WID_ABORT_RUNNING_SCAN = 0x003E, + + /* NMAC Character WID list */ + WID_WPS_START = 0x0043, + + /* Protection mode for MAC */ + /* -------------------------------------------------------------- */ + /* Configuration : Auto No protection ERP HT GF */ + /* Values to set : 0 1 2 3 4 */ + /* -------------------------------------------------------------- */ + WID_11N_PROT_MECH = 0x0080, + + /* ERP Protection type for MAC */ + /* -------------------------------------------------------------- */ + /* Configuration : Self-CTS RTS-CTS */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------- */ + WID_11N_ERP_PROT_TYPE = 0x0081, + + /* HT Option Enable */ + /* -------------------------------------------------------------- */ + /* Configuration : HT Enable HT Disable */ + /* Values to set : 1 0 */ + /* -------------------------------------------------------------- */ + WID_11N_ENABLE = 0x0082, + + /* 11n Operating mode (Note that 11g operating mode will also be */ + /* used in addition to this, if this is set to HT Mixed mode) */ + /* -------------------------------------------------------------- */ + /* Configuration : HT Mixed HT Only-20MHz HT Only-20/40MHz */ + /* Values to set : 1 2 3 */ + /* -------------------------------------------------------------- */ + WID_11N_OPERATING_MODE = 0x0083, + + /* 11n OBSS non-HT STA Detection flag */ + /* -------------------------------------------------------------- */ + /* Configuration : Do not detect */ + /* Values to set : 0 */ + /* Configuration : Detect, do not protect or report */ + /* Values to set : 1 */ + /* Configuration : Detect, protect and do not report */ + /* Values to set : 2 */ + /* Configuration : Detect, protect and report to other BSS */ + /* Values to set : 3 */ + /* -------------------------------------------------------------- */ + WID_11N_OBSS_NONHT_DETECTION = 0x0084, + + /* 11n HT Protection Type */ + /* -------------------------------------------------------------- */ + /* Configuration : RTS-CTS First Frame Exchange at non-HT-rate */ + /* Values to set : 0 1 */ + /* Configuration : LSIG TXOP First Frame Exchange in Mixed Fmt */ + /* Values to set : 2 3 */ + /* -------------------------------------------------------------- */ + WID_11N_HT_PROT_TYPE = 0x0085, + + /* 11n RIFS Protection Enable Flag */ + /* -------------------------------------------------------------- */ + /* Configuration : Disable Enable */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------- */ + WID_11N_RIFS_PROT_ENABLE = 0x0086, + + /* SMPS Mode */ + /* -------------------------------------------------------------- */ + /* Configuration : Static Dynamic MIMO (Power Save Disabled) */ + /* Values to set : 1 2 3 */ + /* -------------------------------------------------------------- */ + WID_11N_SMPS_MODE = 0x0087, + + /* Current transmit MCS */ + /* -------------------------------------------------------------- */ + /* Configuration : MCS Index for data rate */ + /* Values to set : 0 to 7 */ + /* -------------------------------------------------------------- */ + WID_11N_CURRENT_TX_MCS = 0x0088, + + WID_11N_PRINT_STATS = 0x0089, + + /* 11n Short GI Enable Flag */ + /* -------------------------------------------------------------- */ + /* Configuration : Disable Enable */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------- */ + WID_11N_SHORT_GI_ENABLE = 0x008D, + + /* 11n RIFS Enable Flag */ + /* -------------------------------------------------------------- */ + /* Configuration : Disable Enable */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------- */ + WID_RIFS_MODE = 0x0094, + + /* TX Abort Feature */ + /* -------------------------------------------------------------- */ + /* Configuration : Disable Self CTS Enable Self CTS */ + /* Values to set : 0 1 */ + /* Configuration : Disable TX Abort Enable TX Abort */ + /* Values to set : 2 3 */ + /* Configuration : Enable HW TX Abort Enable SW TX Abort */ + /* Values to set : 4 5 */ + /* -------------------------------------------------------------- */ + WID_TX_ABORT_CONFIG = 0x00A1, + + WID_REG_TSSI_11B_VALUE = 0x00A6, + WID_REG_TSSI_11G_VALUE = 0x00A7, + WID_REG_TSSI_11N_VALUE = 0x00A8, + WID_TX_CALIBRATION = 0x00A9, + WID_DSCR_TSSI_11B_VALUE = 0x00AA, + WID_DSCR_TSSI_11G_VALUE = 0x00AB, + WID_DSCR_TSSI_11N_VALUE = 0x00AC, + + /* Immediate Block-Ack Support */ + /* -------------------------------------------------------------- */ + /* Configuration : Disable Enable */ + /* Values to set : 0 1 */ + /* -------------------------------------------------------------- */ + WID_11N_IMMEDIATE_BA_ENABLED = 0x00AF, + + /* TXOP Disable Flag */ + /* -------------------------------------------------------------- */ + /* Configuration : Disable Enable */ + /* Values to set : 1 0 */ + /* -------------------------------------------------------------- */ + WID_11N_TXOP_PROT_DISABLE = 0x00B0, + + + WID_TX_POWER_LEVEL_11N = 0x00B1, + + /* Custom Character WID list */ + WID_PC_TEST_MODE = 0x00C8, + /*bug3819: */ + /* SCAN Complete notification WID*/ + WID_SCAN_COMPLETE = 0x00C9, + +#ifdef WILC_AP_EXTERNAL_MLME + WID_DEL_BEACON = 0x00CA, +#endif + + WID_LOGTerminal_Switch = 0x00CD, + /* EMAC Short WID list */ + /* RTS Threshold */ + /* -------------------------------------------------------------- */ + /* Configuration : Any value between 256 to 2347 */ + /* Values to set : Same value. Default is 2347 */ + /* -------------------------------------------------------------- */ + WID_RTS_THRESHOLD = 0x1000, + + /* Fragmentation Threshold */ + /* -------------------------------------------------------------- */ + /* Configuration : Any value between 256 to 2346 */ + /* Values to set : Same value. Default is 2346 */ + /* -------------------------------------------------------------- */ + WID_FRAG_THRESHOLD = 0x1001, + + WID_SHORT_RETRY_LIMIT = 0x1002, + WID_LONG_RETRY_LIMIT = 0x1003, + WID_BEACON_INTERVAL = 0x1006, + WID_MEMORY_ACCESS_16BIT = 0x1008, + WID_RX_SENSE = 0x100B, + WID_ACTIVE_SCAN_TIME = 0x100C, + WID_PASSIVE_SCAN_TIME = 0x100D, + + WID_SITE_SURVEY_SCAN_TIME = 0x100E, + WID_JOIN_START_TIMEOUT = 0x100F, + WID_AUTH_TIMEOUT = 0x1010, + WID_ASOC_TIMEOUT = 0x1011, + WID_11I_PROTOCOL_TIMEOUT = 0x1012, + WID_EAPOL_RESPONSE_TIMEOUT = 0x1013, + + /* NMAC Short WID list */ + WID_11N_SIG_QUAL_VAL = 0x1085, + WID_CCA_THRESHOLD = 0x1087, + + /* Custom Short WID list */ + + /* EMAC Integer WID list */ + WID_FAILED_COUNT = 0x2000, + WID_RETRY_COUNT = 0x2001, + WID_MULTIPLE_RETRY_COUNT = 0x2002, + WID_FRAME_DUPLICATE_COUNT = 0x2003, + WID_ACK_FAILURE_COUNT = 0x2004, + WID_RECEIVED_FRAGMENT_COUNT = 0x2005, + WID_MCAST_RECEIVED_FRAME_COUNT = 0x2006, + WID_FCS_ERROR_COUNT = 0x2007, + WID_SUCCESS_FRAME_COUNT = 0x2008, + WID_HUT_TX_COUNT = 0x200A, + WID_TX_FRAGMENT_COUNT = 0x200B, + WID_TX_MULTICAST_FRAME_COUNT = 0x200C, + WID_RTS_SUCCESS_COUNT = 0x200D, + WID_RTS_FAILURE_COUNT = 0x200E, + WID_WEP_UNDECRYPTABLE_COUNT = 0x200F, + WID_REKEY_PERIOD = 0x2010, + WID_REKEY_PACKET_COUNT = 0x2011, + WID_1X_SERV_ADDR = 0x2012, + WID_STACK_IP_ADDR = 0x2013, + WID_STACK_NETMASK_ADDR = 0x2014, + WID_HW_RX_COUNT = 0x2015, + WID_MEMORY_ADDRESS = 0x201E, + WID_MEMORY_ACCESS_32BIT = 0x201F, + WID_RF_REG_VAL = 0x2021, + + + /* NMAC Integer WID list */ + WID_11N_PHY_ACTIVE_REG_VAL = 0x2080, + + /* Custom Integer WID list */ + WID_GET_INACTIVE_TIME = 0x2084, + WID_SET_DRV_HANDLER = 0X2085, + WID_SET_OPERATION_MODE = 0X2086, + /* EMAC String WID list */ + WID_SSID = 0x3000, + WID_FIRMWARE_VERSION = 0x3001, + WID_OPERATIONAL_RATE_SET = 0x3002, + WID_BSSID = 0x3003, + WID_WEP_KEY_VALUE = 0x3004, + WID_11I_PSK = 0x3008, + WID_11E_P_ACTION_REQ = 0x3009, + WID_1X_KEY = 0x300A, + WID_HARDWARE_VERSION = 0x300B, + WID_MAC_ADDR = 0x300C, + WID_HUT_DEST_ADDR = 0x300D, + WID_PHY_VERSION = 0x300F, + WID_SUPP_USERNAME = 0x3010, + WID_SUPP_PASSWORD = 0x3011, + WID_SITE_SURVEY_RESULTS = 0x3012, + WID_RX_POWER_LEVEL = 0x3013, + WID_DEL_ALL_RX_BA = 0x3014, + WID_SET_STA_MAC_INACTIVE_TIME = 0x3017, + WID_ADD_WEP_KEY = 0x3019, + WID_REMOVE_WEP_KEY = 0x301A, + WID_ADD_PTK = 0x301B, + WID_ADD_RX_GTK = 0x301C, + WID_ADD_TX_GTK = 0x301D, + WID_REMOVE_KEY = 0x301E, + WID_ASSOC_REQ_INFO = 0x301F, + WID_ASSOC_RES_INFO = 0x3020, + WID_MANUFACTURER = 0x3026, /*Added for CAPI tool */ + WID_MODEL_NAME = 0x3027, /*Added for CAPI tool */ + WID_MODEL_NUM = 0x3028, /*Added for CAPI tool */ + WID_DEVICE_NAME = 0x3029, /*Added for CAPI tool */ + + /* NMAC String WID list */ + WID_11N_P_ACTION_REQ = 0x3080, + WID_HUT_TEST_ID = 0x3081, + WID_PMKID_INFO = 0x3082, + WID_FIRMWARE_INFO = 0x3083, + #ifdef WILC_P2P + WID_REGISTER_FRAME = 0x3084, + #endif + WID_DEL_ALL_STA = 0x3085, + #ifdef WILC_P2P + WID_REMAIN_ON_CHAN = 0x3996, + #endif + /*BugID_4156*/ + WID_SSID_PROBE_REQ = 0x3997, + /*BugID_4124 WID to trigger modified Join Request using SSID and BSSID instead of bssListIdx (used by WID_JOIN_REQ)*/ + WID_JOIN_REQ_EXTENDED = 0x3998, + + /* BugID 4951: WID toset IP address in firmware */ + WID_IP_ADDRESS = 0x3999, + + + + /* Custom String WID list */ + + /* EMAC Binary WID list */ + WID_UAPSD_CONFIG = 0x4001, + WID_UAPSD_STATUS = 0x4002, + WID_WMM_AP_AC_PARAMS = 0x4003, + WID_WMM_STA_AC_PARAMS = 0x4004, + WID_NETWORK_INFO = 0x4005, + WID_STA_JOIN_INFO = 0x4006, + WID_CONNECTED_STA_LIST = 0x4007, + + /* NMAC Binary WID list */ + WID_11N_AUTORATE_TABLE = 0x4080, + + + /*Added here by Amr - BugID 4134*/ + WID_SCAN_CHANNEL_LIST = 0x4084, + + /*BugID_3746 WID to add IE to be added in next probe request*/ + WID_INFO_ELEMENT_PROBE = 0x4085, + /*BugID_3746 WID to add IE to be added in next associate request*/ + WID_INFO_ELEMENT_ASSOCIATE = 0x4086, + WID_ADD_STA = 0X4087, + WID_REMOVE_STA = 0X4088, + WID_EDIT_STA = 0X4089, + WID_ADD_BEACON = 0x408a, + + /* BugID 5108 */ + WID_SETUP_MULTICAST_FILTER = 0x408b, + + /* Miscellaneous WIDs */ + WID_ALL = 0x7FFE, + WID_MAX = 0xFFFF +} WID_T; + +int wilc_wlan_init(wilc_wlan_inp_t *inp, wilc_wlan_oup_t *oup); + +void wilc_bus_set_max_speed(void); +void wilc_bus_set_default_speed(void); +uint32_t wilc_get_chipid(uint8_t update); + + +#endif -- cgit v1.2.3-54-g00ecf