Project import generated by Copybara.
NOKEYCHECK=True
GitOrigin-RevId: d3c032d9650cd8d3d570f345069990c652057293
diff --git a/wl/components/shared/devctrl_if/phyioctl_defs.h b/wl/components/shared/devctrl_if/phyioctl_defs.h
new file mode 100644
index 0000000..01132ab
--- /dev/null
+++ b/wl/components/shared/devctrl_if/phyioctl_defs.h
@@ -0,0 +1,47 @@
+/*
+ * PHY firmware debug interface.
+ *
+ * Definitions subject to change without notice.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id$
+ */
+
+#ifndef _phyioctl_defs_h_
+#define _phyioctl_defs_h_
+
+/* Debug message levels */
+#define PHYHAL_ERROR 0x0001
+#define PHYHAL_TRACE 0x0002
+#define PHYHAL_INFORM 0x0004
+#define PHYHAL_TMP 0x0008
+#define PHYHAL_TXPWR 0x0010
+#define PHYHAL_CAL 0x0020
+#define PHYHAL_ACI 0x0040
+#define PHYHAL_RADAR 0x0080
+#define PHYHAL_THERMAL 0x0100
+#define PHYHAL_PAPD 0x0200
+#define PHYHAL_FCBS 0x0400
+#define PHYHAL_RXIQ 0x0800
+#define PHYHAL_WD 0x1000
+#define PHYHAL_CHANLOG 0x2000
+
+#define PHYHAL_TIMESTAMP 0x8000
+
+#endif /* _phyioctl_defs_h_ */
diff --git a/wl/components/shared/devctrl_if/wlioctl.h b/wl/components/shared/devctrl_if/wlioctl.h
new file mode 100644
index 0000000..c4a0203
--- /dev/null
+++ b/wl/components/shared/devctrl_if/wlioctl.h
@@ -0,0 +1,13014 @@
+/*
+ * Custom OID/ioctl definitions for
+ *
+ *
+ * Broadcom 802.11abg Networking Device Driver
+ *
+ * Definitions subject to change without notice.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wlioctl.h 663420 2017-01-04 06:58:04Z $
+ */
+
+#ifndef _wlioctl_h_
+#define _wlioctl_h_
+
+#include <typedefs.h>
+#include <proto/ethernet.h>
+#include <proto/bcmip.h>
+#include <proto/bcmeth.h>
+#include <proto/bcmip.h>
+#include <proto/bcmipv6.h>
+#include <proto/bcmevent.h>
+#include <proto/802.11.h>
+#ifdef WLMESH
+#include <proto/802.11s.h>
+#endif
+#include <proto/802.1d.h>
+#include <bcmwifi_channels.h>
+#include <bcmwifi_rates.h>
+#include <devctrl_if/wlioctl_defs.h>
+#include <proto/bcmipv6.h>
+
+#include <bcm_mpool_pub.h>
+#include <bcmcdc.h>
+
+
+typedef struct {
+ uint32 num;
+ chanspec_t list[1];
+} chanspec_list_t;
+
+#define RSN_KCK_LENGTH 16
+#define RSN_KEK_LENGTH 16
+#define TPK_FTM_LEN 16
+#ifndef INTF_NAME_SIZ
+#define INTF_NAME_SIZ 16
+#endif
+
+/**Used to send ioctls over the transport pipe */
+typedef struct remote_ioctl {
+ cdc_ioctl_t msg;
+ uint32 data_len;
+ char intf_name[INTF_NAME_SIZ];
+} rem_ioctl_t;
+#define REMOTE_SIZE sizeof(rem_ioctl_t)
+
+#define MAX_NUM_D11CORES 2
+
+/**DFS Forced param */
+typedef struct wl_dfs_forced_params {
+ chanspec_t chspec;
+ uint16 version;
+ chanspec_list_t chspec_list;
+} wl_dfs_forced_t;
+
+#define DFS_PREFCHANLIST_VER 0x01
+#define WL_CHSPEC_LIST_FIXED_SIZE OFFSETOF(chanspec_list_t, list)
+/* size of dfs forced param size given n channels are in the list */
+#define WL_DFS_FORCED_PARAMS_SIZE(n) \
+ (sizeof(wl_dfs_forced_t) + (((n) < 1) ? (0) : (((n) - 1)* sizeof(chanspec_t))))
+#define WL_DFS_FORCED_PARAMS_FIXED_SIZE \
+ (WL_CHSPEC_LIST_FIXED_SIZE + OFFSETOF(wl_dfs_forced_t, chspec_list))
+#define WL_DFS_FORCED_PARAMS_MAX_SIZE \
+ WL_DFS_FORCED_PARAMS_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(chanspec_t))
+
+/**association decision information */
+typedef struct {
+ uint8 assoc_approved; /**< (re)association approved */
+ uint8 pad;
+ uint16 reject_reason; /**< reason code for rejecting association */
+ struct ether_addr da;
+ uint8 pad1[6];
+#if 0 && (NDISVER >= 0x0620)
+ LARGE_INTEGER sys_time; /**< current system time */
+#else
+ int64 sys_time; /**< current system time */
+#endif
+} assoc_decision_t;
+
+#define DFS_SCAN_S_IDLE -1
+#define DFS_SCAN_S_RADAR_FREE 0
+#define DFS_SCAN_S_RADAR_FOUND 1
+#define DFS_SCAN_S_INPROGESS 2
+#define DFS_SCAN_S_SCAN_ABORTED 3
+#define DFS_SCAN_S_SCAN_MODESW_INPROGRESS 4
+#define DFS_SCAN_S_MAX 5
+
+
+#define ACTION_FRAME_SIZE 1800
+
+typedef struct wl_action_frame {
+ struct ether_addr da;
+ uint16 len;
+ uint32 packetId;
+ uint8 data[ACTION_FRAME_SIZE];
+} wl_action_frame_t;
+
+#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame)
+
+typedef struct ssid_info
+{
+ uint8 ssid_len; /**< the length of SSID */
+ uint8 ssid[32]; /**< SSID string */
+} ssid_info_t;
+
+typedef struct wl_af_params {
+ uint32 channel;
+ int32 dwell_time;
+ struct ether_addr BSSID;
+ wl_action_frame_t action_frame;
+} wl_af_params_t;
+
+#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params)
+
+#define MFP_TEST_FLAG_NORMAL 0
+#define MFP_TEST_FLAG_ANY_KEY 1
+typedef struct wl_sa_query {
+ uint32 flag;
+ uint8 action;
+ uint16 id;
+ struct ether_addr da;
+} wl_sa_query_t;
+
+/* EXT_STA */
+/**association information */
+typedef struct {
+ uint32 assoc_req; /**< offset to association request frame */
+ uint32 assoc_req_len; /**< association request frame length */
+ uint32 assoc_rsp; /**< offset to association response frame */
+ uint32 assoc_rsp_len; /**< association response frame length */
+ uint32 bcn; /**< offset to AP beacon */
+ uint32 bcn_len; /**< AP beacon length */
+ uint32 wsec; /**< ucast security algo */
+ uint32 wpaie; /**< offset to WPA ie */
+ uint8 auth_alg; /**< 802.11 authentication mode */
+ uint8 WPA_auth; /**< WPA: authenticated key management */
+ uint8 ewc_cap; /**< EWC (MIMO) capable */
+ uint8 ofdm; /**< OFDM */
+} assoc_info_t;
+/* defined(EXT_STA) */
+
+/* Flags for OBSS IOVAR Parameters */
+#define WL_OBSS_DYN_BWSW_FLAG_ACTIVITY_PERIOD (0x01)
+#define WL_OBSS_DYN_BWSW_FLAG_NOACTIVITY_PERIOD (0x02)
+#define WL_OBSS_DYN_BWSW_FLAG_NOACTIVITY_INCR_PERIOD (0x04)
+#define WL_OBSS_DYN_BWSW_FLAG_PSEUDO_SENSE_PERIOD (0x08)
+#define WL_OBSS_DYN_BWSW_FLAG_RX_CRS_PERIOD (0x10)
+#define WL_OBSS_DYN_BWSW_FLAG_DUR_THRESHOLD (0x20)
+#define WL_OBSS_DYN_BWSW_FLAG_TXOP_PERIOD (0x40)
+
+/* OBSS IOVAR Version information */
+#define WL_PROT_OBSS_CONFIG_PARAMS_VERSION 1
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint8 obss_bwsw_activity_cfm_count_cfg; /**< configurable count in
+ * seconds before we confirm that OBSS is present and
+ * dynamically activate dynamic bwswitch.
+ */
+ uint8 obss_bwsw_no_activity_cfm_count_cfg; /**< configurable count in
+ * seconds before we confirm that OBSS is GONE and
+ * dynamically start pseudo upgrade. If in pseudo sense time, we
+ * will see OBSS, [means that, we false detected that OBSS-is-gone
+ * in watchdog] this count will be incremented in steps of
+ * obss_bwsw_no_activity_cfm_count_incr_cfg for confirming OBSS
+ * detection again. Note that, at present, max 30seconds is
+ * allowed like this. [OBSS_BWSW_NO_ACTIVITY_MAX_INCR_DEFAULT]
+ */
+ uint8 obss_bwsw_no_activity_cfm_count_incr_cfg; /* see above
+ */
+ uint16 obss_bwsw_pseudo_sense_count_cfg; /**< number of msecs/cnt to be in
+ * pseudo state. This is used to sense/measure the stats from lq.
+ */
+ uint8 obss_bwsw_rx_crs_threshold_cfg; /**< RX CRS default threshold */
+ uint8 obss_bwsw_dur_thres; /**< OBSS dyn bwsw trigger/RX CRS Sec */
+ uint8 obss_bwsw_txop_threshold_cfg; /**< TXOP default threshold */
+} BWL_POST_PACKED_STRUCT wlc_obss_dynbwsw_config_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 version; /**< version field */
+ uint32 config_mask;
+ uint32 reset_mask;
+ wlc_obss_dynbwsw_config_t config_params;
+} BWL_POST_PACKED_STRUCT obss_config_params_t;
+#include <packed_section_end.h>
+
+/**bsscfg type */
+typedef enum bsscfg_type {
+ BSSCFG_TYPE_GENERIC = 0, /**< Generic AP/STA/IBSS BSS */
+ BSSCFG_TYPE_P2P = 1, /**< P2P BSS */
+ /* index 2 earlier used for BTAMP */
+ BSSCFG_TYPE_PSTA = 3,
+ BSSCFG_TYPE_TDLS = 4,
+ BSSCFG_TYPE_SLOTTED_BSS = 5,
+ BSSCFG_TYPE_PROXD = 6,
+ BSSCFG_TYPE_NAN = 7,
+ BSSCFG_TYPE_MESH = 8,
+ BSSCFG_TYPE_AIBSS = 9
+} bsscfg_type_t;
+
+/* bsscfg subtype */
+typedef enum bsscfg_subtype {
+ BSSCFG_SUBTYPE_NONE = 0,
+ BSSCFG_GENERIC_STA = 1, /* GENERIC */
+ BSSCFG_GENERIC_AP = 2,
+ BSSCFG_GENERIC_IBSS = 6,
+ BSSCFG_P2P_GC = 3, /* P2P */
+ BSSCFG_P2P_GO = 4,
+ BSSCFG_P2P_DISC = 5,
+ /* Index 7 & 8 earlier used for BTAMP */
+ BSSCFG_SUBTYPE_AWDL = 9, /* SLOTTED_BSS_TYPE */
+ BSSCFG_SUBTYPE_NAN_MGMT = 10,
+ BSSCFG_SUBTYPE_NAN_DATA = 11,
+ BSSCFG_SUBTYPE_NAN_MGMT_DATA = 12
+} bsscfg_subtype_t;
+
+typedef struct wlc_bsscfg_info {
+ uint32 type;
+ uint32 subtype;
+} wlc_bsscfg_info_t;
+
+/* ULP SHM Offsets info */
+typedef struct ulp_shm_info {
+ uint32 m_ulp_ctrl_sdio;
+ uint32 m_ulp_wakeevt_ind;
+ uint32 m_ulp_wakeind;
+} ulp_shm_info_t;
+
+
+/* Legacy structure to help keep backward compatible wl tool and tray app */
+
+#define LEGACY_WL_BSS_INFO_VERSION 107 /**< older version of wl_bss_info struct */
+
+typedef struct wl_bss_info_107 {
+ uint32 version; /**< version field */
+ uint32 length; /**< byte length of data in this record,
+ * starting at version and including IEs
+ */
+ struct ether_addr BSSID;
+ uint16 beacon_period; /**< units are Kusec */
+ uint16 capability; /**< Capability information */
+ uint8 SSID_len;
+ uint8 SSID[32];
+ struct {
+ uint32 count; /**< # rates in this set */
+ uint8 rates[16]; /**< rates in 500kbps units w/hi bit set if basic */
+ } rateset; /**< supported rates */
+ uint8 channel; /**< Channel no. */
+ uint16 atim_window; /**< units are Kusec */
+ uint8 dtim_period; /**< DTIM period */
+ int16 RSSI; /**< receive signal strength (in dBm) */
+ int8 phy_noise; /**< noise (in dBm) */
+ uint32 ie_length; /**< byte length of Information Elements */
+ /* variable length Information Elements */
+} wl_bss_info_107_t;
+
+/*
+ * Per-BSS information structure.
+ */
+
+#define LEGACY2_WL_BSS_INFO_VERSION 108 /**< old version of wl_bss_info struct */
+
+/**
+ * BSS info structure
+ * Applications MUST CHECK ie_offset field and length field to access IEs and
+ * next bss_info structure in a vector (in wl_scan_results_t)
+ */
+typedef struct wl_bss_info_108 {
+ uint32 version; /**< version field */
+ uint32 length; /**< byte length of data in this record,
+ * starting at version and including IEs
+ */
+ struct ether_addr BSSID;
+ uint16 beacon_period; /**< units are Kusec */
+ uint16 capability; /**< Capability information */
+ uint8 SSID_len;
+ uint8 SSID[32];
+ struct {
+ uint32 count; /**< # rates in this set */
+ uint8 rates[16]; /**< rates in 500kbps units w/hi bit set if basic */
+ } rateset; /**< supported rates */
+ chanspec_t chanspec; /**< chanspec for bss */
+ uint16 atim_window; /**< units are Kusec */
+ uint8 dtim_period; /**< DTIM period */
+ int16 RSSI; /**< receive signal strength (in dBm) */
+ int8 phy_noise; /**< noise (in dBm) */
+
+ uint8 n_cap; /**< BSS is 802.11N Capable */
+ uint32 nbss_cap; /**< 802.11N BSS Capabilities (based on HT_CAP_*) */
+ uint8 ctl_ch; /**< 802.11N BSS control channel number */
+ uint32 reserved32[1]; /**< Reserved for expansion of BSS properties */
+ uint8 flags; /**< flags */
+ uint8 reserved[3]; /**< Reserved for expansion of BSS properties */
+ uint8 basic_mcs[MCSSET_LEN]; /**< 802.11N BSS required MCS set */
+
+ uint16 ie_offset; /**< offset at which IEs start, from beginning */
+ uint32 ie_length; /**< byte length of Information Elements */
+ /* Add new fields here */
+ /* variable length Information Elements */
+} wl_bss_info_108_t;
+
+
+#define WL_BSS_INFO_VERSION 109 /**< current version of wl_bss_info struct */
+
+/**
+ * BSS info structure
+ * Applications MUST CHECK ie_offset field and length field to access IEs and
+ * next bss_info structure in a vector (in wl_scan_results_t)
+ */
+typedef struct wl_bss_info {
+ uint32 version; /**< version field */
+ uint32 length; /**< byte length of data in this record,
+ * starting at version and including IEs
+ */
+ struct ether_addr BSSID;
+ uint16 beacon_period; /**< units are Kusec */
+ uint16 capability; /**< Capability information */
+ uint8 SSID_len;
+ uint8 SSID[32];
+ uint8 bcnflags; /* additional flags w.r.t. beacon */
+ struct {
+ uint32 count; /**< # rates in this set */
+ uint8 rates[16]; /**< rates in 500kbps units w/hi bit set if basic */
+ } rateset; /**< supported rates */
+ chanspec_t chanspec; /**< chanspec for bss */
+ uint16 atim_window; /**< units are Kusec */
+ uint8 dtim_period; /**< DTIM period */
+ uint8 accessnet; /* from beacon interwork IE (if bcnflags) */
+ int16 RSSI; /**< receive signal strength (in dBm) */
+ int8 phy_noise; /**< noise (in dBm) */
+ uint8 n_cap; /**< BSS is 802.11N Capable */
+ uint16 freespace1; /* make implicit padding explicit */
+ uint32 nbss_cap; /**< 802.11N+AC BSS Capabilities */
+ uint8 ctl_ch; /**< 802.11N BSS control channel number */
+ uint8 padding1[3]; /**< explicit struct alignment padding */
+ uint16 vht_rxmcsmap; /**< VHT rx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */
+ uint16 vht_txmcsmap; /**< VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */
+ uint8 flags; /**< flags */
+ uint8 vht_cap; /**< BSS is vht capable */
+ uint8 reserved[2]; /**< Reserved for expansion of BSS properties */
+ uint8 basic_mcs[MCSSET_LEN]; /**< 802.11N BSS required MCS set */
+
+ uint16 ie_offset; /**< offset at which IEs start, from beginning */
+ uint16 freespace2; /* making implicit padding explicit */
+ uint32 ie_length; /**< byte length of Information Elements */
+ int16 SNR; /**< average SNR of during frame reception */
+ uint16 vht_mcsmap; /**< STA's Associated vhtmcsmap */
+ uint16 vht_mcsmap_prop; /**< STA's Associated prop vhtmcsmap */
+ uint16 vht_txmcsmap_prop; /**< prop VHT tx mcs prop */
+ /* Add new fields here */
+ /* variable length Information Elements */
+} wl_bss_info_t;
+
+#define WL_GSCAN_FULL_RESULT_VERSION 2 /* current version of wl_gscan_result_t struct */
+#define WL_GSCAN_INFO_FIXED_FIELD_SIZE (sizeof(wl_gscan_bss_info_t) - sizeof(wl_bss_info_t))
+
+typedef struct wl_gscan_bss_info {
+ uint32 timestamp[2];
+ wl_bss_info_t info;
+ /* Do not add any more members below, fixed */
+ /* and variable length Information Elements to follow */
+} wl_gscan_bss_info_t;
+
+
+typedef struct wl_bsscfg {
+ uint32 bsscfg_idx;
+ uint32 wsec;
+ uint32 WPA_auth;
+ uint32 wsec_index;
+ uint32 associated;
+ uint32 BSS;
+ uint32 phytest_on;
+ struct ether_addr prev_BSSID;
+ struct ether_addr BSSID;
+ uint32 targetbss_wpa2_flags;
+ uint32 assoc_type;
+ uint32 assoc_state;
+} wl_bsscfg_t;
+
+typedef struct wl_if_add {
+ uint32 bsscfg_flags;
+ uint32 if_flags;
+ uint32 ap;
+ struct ether_addr mac_addr;
+ uint32 wlc_index;
+} wl_if_add_t;
+
+typedef struct wl_bss_config {
+ uint32 atim_window;
+ uint32 beacon_period;
+ uint32 chanspec;
+} wl_bss_config_t;
+
+#define WL_BSS_USER_RADAR_CHAN_SELECT 0x1 /**< User application will randomly select
+ * radar channel.
+ */
+
+#define DLOAD_HANDLER_VER 1 /**< Downloader version */
+#define DLOAD_FLAG_VER_MASK 0xf000 /**< Downloader version mask */
+#define DLOAD_FLAG_VER_SHIFT 12 /**< Downloader version shift */
+
+#define DL_CRC_NOT_INUSE 0x0001
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define DL_BEGIN 0x0002
+#define DL_END 0x0004
+
+/* Flags for Major/Minor/Date number shift and mask */
+#define EPI_VER_SHIFT 16
+#define EPI_VER_MASK 0xFFFF
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/** generic download types & flags */
+enum {
+ DL_TYPE_UCODE = 1,
+ DL_TYPE_CLM = 2
+};
+
+/** ucode type values */
+enum {
+ UCODE_FW,
+ INIT_VALS,
+ BS_INIT_VALS
+};
+
+struct wl_dload_data {
+ uint16 flag;
+ uint16 dload_type;
+ uint32 len;
+ uint32 crc;
+ uint8 data[1];
+};
+typedef struct wl_dload_data wl_dload_data_t;
+
+struct wl_ucode_info {
+ uint32 ucode_type;
+ uint32 num_chunks;
+ uint32 chunk_len;
+ uint32 chunk_num;
+ uint8 data_chunk[1];
+};
+typedef struct wl_ucode_info wl_ucode_info_t;
+
+struct wl_clm_dload_info {
+ uint32 ds_id;
+ uint32 clm_total_len;
+ uint32 num_chunks;
+ uint32 chunk_len;
+ uint32 chunk_offset;
+ uint8 data_chunk[1];
+};
+typedef struct wl_clm_dload_info wl_clm_dload_info_t;
+
+
+typedef struct wlc_ssid {
+ uint32 SSID_len;
+ uint8 SSID[DOT11_MAX_SSID_LEN];
+} wlc_ssid_t;
+
+typedef struct wlc_ssid_ext {
+ uint8 hidden;
+ uint16 flags;
+ uint8 SSID_len;
+ int8 rssi_thresh;
+ uint8 SSID[DOT11_MAX_SSID_LEN];
+} wlc_ssid_ext_t;
+
+#define MAX_PREFERRED_AP_NUM 5
+typedef struct wlc_fastssidinfo {
+ uint32 SSID_channel[MAX_PREFERRED_AP_NUM];
+ wlc_ssid_t SSID_info[MAX_PREFERRED_AP_NUM];
+} wlc_fastssidinfo_t;
+
+typedef struct wnm_url {
+ uint8 len;
+ uint8 data[1];
+} wnm_url_t;
+
+typedef struct chan_scandata {
+ uint8 txpower;
+ uint8 pad;
+ chanspec_t channel; /**< Channel num, bw, ctrl_sb and band */
+ uint32 channel_mintime;
+ uint32 channel_maxtime;
+} chan_scandata_t;
+
+typedef enum wl_scan_type {
+ EXTDSCAN_FOREGROUND_SCAN,
+ EXTDSCAN_BACKGROUND_SCAN,
+ EXTDSCAN_FORCEDBACKGROUND_SCAN
+} wl_scan_type_t;
+
+#define WLC_EXTDSCAN_MAX_SSID 5
+
+typedef struct wl_extdscan_params {
+ int8 nprobes; /**< 0, passive, otherwise active */
+ int8 split_scan; /**< split scan */
+ int8 band; /**< band */
+ int8 pad;
+ wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /**< ssid list */
+ uint32 tx_rate; /**< in 500ksec units */
+ wl_scan_type_t scan_type; /**< enum */
+ int32 channel_num;
+ chan_scandata_t channel_list[1]; /**< list of chandata structs */
+} wl_extdscan_params_t;
+
+#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t))
+
+#define WL_SCAN_PARAMS_SSID_MAX 10
+
+typedef struct wl_scan_params {
+ wlc_ssid_t ssid; /**< default: {0, ""} */
+ struct ether_addr bssid; /**< default: bcast */
+ int8 bss_type; /**< default: any,
+ * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
+ */
+ uint8 scan_type; /**< flags, 0 use default */
+ int32 nprobes; /**< -1 use default, number of probes per channel */
+ int32 active_time; /**< -1 use default, dwell time per channel for
+ * active scanning
+ */
+ int32 passive_time; /**< -1 use default, dwell time per channel
+ * for passive scanning
+ */
+ int32 home_time; /**< -1 use default, dwell time for the home channel
+ * between channel scans
+ */
+ int32 channel_num; /**< count of channels and ssids that follow
+ *
+ * low half is count of channels in channel_list, 0
+ * means default (use all available channels)
+ *
+ * high half is entries in wlc_ssid_t array that
+ * follows channel_list, aligned for int32 (4 bytes)
+ * meaning an odd channel count implies a 2-byte pad
+ * between end of channel_list and first ssid
+ *
+ * if ssid count is zero, single ssid in the fixed
+ * parameter portion is assumed, otherwise ssid in
+ * the fixed portion is ignored
+ */
+ uint16 channel_list[1]; /**< list of chanspecs */
+} wl_scan_params_t;
+
+/** size of wl_scan_params not including variable length array */
+#define WL_SCAN_PARAMS_FIXED_SIZE 64
+#define WL_MAX_ROAMSCAN_DATSZ (WL_SCAN_PARAMS_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16)))
+
+#define ISCAN_REQ_VERSION 1
+
+/** incremental scan struct */
+typedef struct wl_iscan_params {
+ uint32 version;
+ uint16 action;
+ uint16 scan_duration;
+ wl_scan_params_t params;
+} wl_iscan_params_t;
+
+/** 3 fields + size of wl_scan_params, not including variable length array */
+#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t))
+
+typedef struct wl_scan_results {
+ uint32 buflen;
+ uint32 version;
+ uint32 count;
+ wl_bss_info_t bss_info[1];
+} wl_scan_results_t;
+
+/** size of wl_scan_results not including variable length array */
+#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t))
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#if defined(SIMPLE_ISCAN)
+/** the buf lengh can be WLC_IOCTL_MAXLEN (8K) to reduce iteration */
+#define WLC_IW_ISCAN_MAXLEN 2048
+typedef struct iscan_buf {
+ struct iscan_buf * next;
+ int8 iscan_buf[WLC_IW_ISCAN_MAXLEN];
+} iscan_buf_t;
+#endif /* SIMPLE_ISCAN */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#define ESCAN_REQ_VERSION 1
+
+/** event scan reduces amount of SOC memory needed to store scan results */
+typedef struct wl_escan_params {
+ uint32 version;
+ uint16 action;
+ uint16 sync_id;
+ wl_scan_params_t params;
+} wl_escan_params_t;
+
+#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t))
+
+/** event scan reduces amount of SOC memory needed to store scan results */
+typedef struct wl_escan_result {
+ uint32 buflen;
+ uint32 version;
+ uint16 sync_id;
+ uint16 bss_count;
+ wl_bss_info_t bss_info[1];
+} wl_escan_result_t;
+
+#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t))
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+typedef struct wl_gscan_result {
+ uint32 buflen;
+ uint32 version;
+ uint32 scan_ch_bucket;
+ wl_gscan_bss_info_t bss_info[1];
+} wl_gscan_result_t;
+
+#define WL_GSCAN_RESULTS_FIXED_SIZE (sizeof(wl_gscan_result_t) - sizeof(wl_gscan_bss_info_t))
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/** incremental scan results struct */
+typedef struct wl_iscan_results {
+ uint32 status;
+ wl_scan_results_t results;
+} wl_iscan_results_t;
+
+/** size of wl_iscan_results not including variable length array */
+#define WL_ISCAN_RESULTS_FIXED_SIZE \
+ (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results))
+
+typedef struct wl_probe_params {
+ wlc_ssid_t ssid;
+ struct ether_addr bssid;
+ struct ether_addr mac;
+} wl_probe_params_t;
+
+#define WL_MAXRATES_IN_SET 16 /**< max # of rates in a rateset */
+typedef struct wl_rateset {
+ uint32 count; /**< # rates in this set */
+ uint8 rates[WL_MAXRATES_IN_SET]; /**< rates in 500kbps units w/hi bit set if basic */
+} wl_rateset_t;
+
+typedef struct wl_rateset_args {
+ uint32 count; /**< # rates in this set */
+ uint8 rates[WL_MAXRATES_IN_SET]; /**< rates in 500kbps units w/hi bit set if basic */
+ uint8 mcs[MCSSET_LEN]; /**< supported mcs index bit map */
+ uint16 vht_mcs[VHT_CAP_MCS_MAP_NSS_MAX]; /**< supported mcs index bit map per nss */
+} wl_rateset_args_t;
+
+#define TXBF_RATE_MCS_ALL 4
+#define TXBF_RATE_VHT_ALL 4
+#define TXBF_RATE_OFDM_ALL 8
+
+typedef struct wl_txbf_rateset {
+ uint8 txbf_rate_mcs[TXBF_RATE_MCS_ALL]; /**< one for each stream */
+ uint8 txbf_rate_mcs_bcm[TXBF_RATE_MCS_ALL]; /**< one for each stream */
+ uint16 txbf_rate_vht[TXBF_RATE_VHT_ALL]; /**< one for each stream */
+ uint16 txbf_rate_vht_bcm[TXBF_RATE_VHT_ALL]; /**< one for each stream */
+ uint8 txbf_rate_ofdm[TXBF_RATE_OFDM_ALL]; /**< bitmap of ofdm rates that enables txbf */
+ uint8 txbf_rate_ofdm_bcm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */
+ uint8 txbf_rate_ofdm_cnt;
+ uint8 txbf_rate_ofdm_cnt_bcm;
+} wl_txbf_rateset_t;
+
+#define NUM_BFGAIN_ARRAY_1RX 2
+#define NUM_BFGAIN_ARRAY_2RX 3
+#define NUM_BFGAIN_ARRAY_3RX 4
+#define NUM_BFGAIN_ARRAY_4RX 5
+
+typedef struct wl_txbf_expgainset {
+ /* bitmap for each element: B[4:0]=>c0, B[9:5]=>c1, B[14:10]=>c2, B[19:15]=>c[3-7]
+ * B[24:20]=>c[8-9], B[29:25]=>c[10-11]
+ */
+ uint32 bfgain_2x1[NUM_BFGAIN_ARRAY_1RX]; /* exp 1ss, imp 1ss */
+ uint32 bfgain_2x2[NUM_BFGAIN_ARRAY_2RX]; /* exp [1-2]ss, imp 1ss */
+ uint32 bfgain_3x1[NUM_BFGAIN_ARRAY_1RX];
+ uint32 bfgain_3x2[NUM_BFGAIN_ARRAY_2RX];
+ uint32 bfgain_3x3[NUM_BFGAIN_ARRAY_3RX]; /* exp [1-3]ss, imp 1ss */
+ uint32 bfgain_4x1[NUM_BFGAIN_ARRAY_1RX];
+ uint32 bfgain_4x2[NUM_BFGAIN_ARRAY_2RX];
+ uint32 bfgain_4x3[NUM_BFGAIN_ARRAY_3RX];
+ uint32 bfgain_4x4[NUM_BFGAIN_ARRAY_4RX]; /* exp [1-4]ss, imp 1ss */
+} wl_txbf_expgainset_t;
+
+#define OFDM_RATE_MASK 0x0000007f
+typedef uint8 ofdm_rates_t;
+
+typedef struct wl_rates_info {
+ wl_rateset_t rs_tgt;
+ uint32 phy_type;
+ int32 bandtype;
+ uint8 cck_only;
+ uint8 rate_mask;
+ uint8 mcsallow;
+ uint8 bw;
+ uint8 txstreams;
+} wl_rates_info_t;
+
+/**uint32 list */
+typedef struct wl_uint32_list {
+ /** in - # of elements, out - # of entries */
+ uint32 count;
+ /** variable length uint32 list */
+ uint32 element[1];
+} wl_uint32_list_t;
+
+/* WLC_SET_ALLOW_MODE values */
+#define ALLOW_MODE_ANY_BSSID 0
+#define ALLOW_MODE_ONLY_DESIRED_BSSID 1
+#define ALLOW_MODE_NO_BSSID 2
+
+/** used for association with a specific BSSID and chanspec list */
+typedef struct wl_assoc_params {
+ struct ether_addr bssid; /**< 00:00:00:00:00:00: broadcast scan */
+ uint16 bssid_cnt; /**< 0: use chanspec_num, and the single bssid,
+ * otherwise count of chanspecs in chanspec_list
+ * AND paired bssids following chanspec_list
+ * also, chanspec_num has to be set to zero
+ * for bssid list to be used
+ */
+ int32 chanspec_num; /**< 0: all available channels,
+ * otherwise count of chanspecs in chanspec_list
+ */
+ chanspec_t chanspec_list[1]; /**< list of chanspecs */
+} wl_assoc_params_t;
+
+#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list)
+
+/** used for reassociation/roam to a specific BSSID and channel */
+typedef wl_assoc_params_t wl_reassoc_params_t;
+#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE
+
+/** used for association to a specific BSSID and channel */
+typedef wl_assoc_params_t wl_join_assoc_params_t;
+#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE
+
+/** used for join with or without a specific bssid and channel list */
+typedef struct wl_join_params {
+ wlc_ssid_t ssid;
+ wl_assoc_params_t params; /**< optional field, but it must include the fixed portion
+ * of the wl_assoc_params_t struct when it does present.
+ */
+} wl_join_params_t;
+
+#define WL_JOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_join_params_t, params) + \
+ WL_ASSOC_PARAMS_FIXED_SIZE)
+/** scan params for extended join */
+typedef struct wl_join_scan_params {
+ uint8 scan_type; /**< 0 use default, active or passive scan */
+ int32 nprobes; /**< -1 use default, number of probes per channel */
+ int32 active_time; /**< -1 use default, dwell time per channel for
+ * active scanning
+ */
+ int32 passive_time; /**< -1 use default, dwell time per channel
+ * for passive scanning
+ */
+ int32 home_time; /**< -1 use default, dwell time for the home channel
+ * between channel scans
+ */
+} wl_join_scan_params_t;
+
+/** extended join params */
+typedef struct wl_extjoin_params {
+ wlc_ssid_t ssid; /**< {0, ""}: wildcard scan */
+ wl_join_scan_params_t scan;
+ wl_join_assoc_params_t assoc; /**< optional field, but it must include the fixed portion
+ * of the wl_join_assoc_params_t struct when it does
+ * present.
+ */
+} wl_extjoin_params_t;
+#define WL_EXTJOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extjoin_params_t, assoc) + \
+ WL_JOIN_ASSOC_PARAMS_FIXED_SIZE)
+
+#define ANT_SELCFG_MAX 4 /**< max number of antenna configurations */
+#define MAX_STREAMS_SUPPORTED 4 /**< max number of streams supported */
+typedef struct {
+ uint8 ant_config[ANT_SELCFG_MAX]; /**< antenna configuration */
+ uint8 num_antcfg; /**< number of available antenna configurations */
+} wlc_antselcfg_t;
+
+typedef struct {
+ uint32 duration; /**< millisecs spent sampling this channel */
+ uint32 congest_ibss; /**< millisecs in our bss (presumably this traffic will */
+ /**< move if cur bss moves channels) */
+ uint32 congest_obss; /**< traffic not in our bss */
+ uint32 interference; /**< millisecs detecting a non 802.11 interferer. */
+ uint32 timestamp; /**< second timestamp */
+} cca_congest_t;
+
+typedef struct {
+ chanspec_t chanspec; /**< Which channel? */
+ uint16 num_secs; /**< How many secs worth of data */
+ cca_congest_t secs[1]; /**< Data */
+} cca_congest_channel_req_t;
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+typedef struct {
+ uint32 duration; /**< millisecs spent sampling this channel */
+ uint32 congest; /**< millisecs detecting busy CCA */
+ uint32 timestamp; /**< second timestamp */
+} cca_congest_simple_t;
+
+typedef struct {
+ uint16 status;
+ uint16 id;
+ chanspec_t chanspec; /**< Which channel? */
+ uint16 len;
+ union {
+ cca_congest_simple_t cca_busy; /**< CCA busy */
+ int32 noise; /**< noise floor */
+ };
+} cca_chan_qual_event_t;
+
+#if defined(BCMDBG) || defined(BCMDBG_DUMP)
+typedef struct {
+ uint32 msrmnt_time; /**< Time for Measurement (msec) */
+ uint32 msrmnt_done; /**< flag set when measurement complete */
+ char buf[1];
+} cca_stats_n_flags;
+
+typedef struct {
+ uint32 msrmnt_query; /* host to driver query for measurement done */
+ uint32 time_req; /* time required for measurement */
+ uint8 report_opt; /* option to print different stats in report */
+} cca_msrmnt_query;
+#endif
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* interference sources */
+enum interference_source {
+ ITFR_NONE = 0, /**< interference */
+ ITFR_PHONE, /**< wireless phone */
+ ITFR_VIDEO_CAMERA, /**< wireless video camera */
+ ITFR_MICROWAVE_OVEN, /**< microwave oven */
+ ITFR_BABY_MONITOR, /**< wireless baby monitor */
+ ITFR_BLUETOOTH, /**< bluetooth */
+ ITFR_VIDEO_CAMERA_OR_BABY_MONITOR, /**< wireless camera or baby monitor */
+ ITFR_BLUETOOTH_OR_BABY_MONITOR, /**< bluetooth or baby monitor */
+ ITFR_VIDEO_CAMERA_OR_PHONE, /**< video camera or phone */
+ ITFR_UNIDENTIFIED /**< interference from unidentified source */
+};
+
+/** structure for interference source report */
+typedef struct {
+ uint32 flags; /**< flags. bit definitions below */
+ uint32 source; /**< last detected interference source */
+ uint32 timestamp; /**< second timestamp on interferenced flag change */
+} interference_source_rep_t;
+
+#define WLC_CNTRY_BUF_SZ 4 /**< Country string is 3 bytes + NUL */
+
+typedef struct wl_country {
+ char country_abbrev[WLC_CNTRY_BUF_SZ]; /**< nul-terminated country code used in
+ * the Country IE
+ */
+ int32 rev; /**< revision specifier for ccode
+ * on set, -1 indicates unspecified.
+ * on get, rev >= 0
+ */
+ char ccode[WLC_CNTRY_BUF_SZ]; /**< nul-terminated built-in country code.
+ * variable length, but fixed size in
+ * struct allows simple allocation for
+ * expected country strings <= 3 chars.
+ */
+} wl_country_t;
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+
+#define CCODE_INFO_VERSION 1
+
+typedef enum wl_ccode_role {
+ WLC_CCODE_ROLE_ACTIVE = 0,
+ WLC_CCODE_ROLE_HOST,
+ WLC_CCODE_ROLE_80211D_ASSOC,
+ WLC_CCODE_ROLE_80211D_SCAN,
+ WLC_CCODE_ROLE_DEFAULT,
+ WLC_CCODE_LAST
+} wl_ccode_role_t;
+#define WLC_NUM_CCODE_INFO WLC_CCODE_LAST
+
+typedef struct wl_ccode_entry {
+ uint16 reserved;
+ uint8 band;
+ uint8 role;
+ char ccode[WLC_CNTRY_BUF_SZ];
+} wl_ccode_entry_t;
+
+typedef struct wl_ccode_info {
+ uint16 version;
+ uint16 count; /**< Number of ccodes entries in the set */
+ wl_ccode_entry_t ccodelist[1];
+} wl_ccode_info_t;
+#define WL_CCODE_INFO_FIXED_LEN OFFSETOF(wl_ccode_info_t, ccodelist)
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+typedef struct wl_channels_in_country {
+ uint32 buflen;
+ uint32 band;
+ char country_abbrev[WLC_CNTRY_BUF_SZ];
+ uint32 count;
+ uint32 channel[1];
+} wl_channels_in_country_t;
+
+typedef struct wl_country_list {
+ uint32 buflen;
+ uint32 band_set;
+ uint32 band;
+ uint32 count;
+ char country_abbrev[1];
+} wl_country_list_t;
+
+typedef struct wl_rm_req_elt {
+ int8 type;
+ int8 flags;
+ chanspec_t chanspec;
+ uint32 token; /**< token for this measurement */
+ uint32 tsf_h; /**< TSF high 32-bits of Measurement start time */
+ uint32 tsf_l; /**< TSF low 32-bits */
+ uint32 dur; /**< TUs */
+} wl_rm_req_elt_t;
+
+typedef struct wl_rm_req {
+ uint32 token; /**< overall measurement set token */
+ uint32 count; /**< number of measurement requests */
+ void *cb; /**< completion callback function: may be NULL */
+ void *cb_arg; /**< arg to completion callback function */
+ wl_rm_req_elt_t req[1]; /**< variable length block of requests */
+} wl_rm_req_t;
+#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req)
+
+typedef struct wl_rm_rep_elt {
+ int8 type;
+ int8 flags;
+ chanspec_t chanspec;
+ uint32 token; /**< token for this measurement */
+ uint32 tsf_h; /**< TSF high 32-bits of Measurement start time */
+ uint32 tsf_l; /**< TSF low 32-bits */
+ uint32 dur; /**< TUs */
+ uint32 len; /**< byte length of data block */
+ uint8 data[1]; /**< variable length data block */
+} wl_rm_rep_elt_t;
+#define WL_RM_REP_ELT_FIXED_LEN 24 /**< length excluding data block */
+
+#define WL_RPI_REP_BIN_NUM 8
+typedef struct wl_rm_rpi_rep {
+ uint8 rpi[WL_RPI_REP_BIN_NUM];
+ int8 rpi_max[WL_RPI_REP_BIN_NUM];
+} wl_rm_rpi_rep_t;
+
+typedef struct wl_rm_rep {
+ uint32 token; /**< overall measurement set token */
+ uint32 len; /**< length of measurement report block */
+ wl_rm_rep_elt_t rep[1]; /**< variable length block of reports */
+} wl_rm_rep_t;
+#define WL_RM_REP_FIXED_LEN 8
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#if defined(BCMSUP_PSK) || defined(BCMDONGLEHOST) || defined(GTKOE)
+typedef enum sup_auth_status {
+ /* Basic supplicant authentication states */
+ WLC_SUP_DISCONNECTED = 0,
+ WLC_SUP_CONNECTING,
+ WLC_SUP_IDREQUIRED,
+ WLC_SUP_AUTHENTICATING,
+ WLC_SUP_AUTHENTICATED,
+ WLC_SUP_KEYXCHANGE,
+ WLC_SUP_KEYED,
+ WLC_SUP_TIMEOUT,
+ WLC_SUP_LAST_BASIC_STATE,
+
+ /* Extended supplicant authentication states */
+ /** Waiting to receive handshake msg M1 */
+ WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED,
+ /** Preparing to send handshake msg M2 */
+ WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE,
+ /* Waiting to receive handshake msg M3 */
+ WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE,
+ WLC_SUP_KEYXCHANGE_PREP_M4, /**< Preparing to send handshake msg M4 */
+ WLC_SUP_KEYXCHANGE_WAIT_G1, /**< Waiting to receive handshake msg G1 */
+ WLC_SUP_KEYXCHANGE_PREP_G2 /**< Preparing to send handshake msg G2 */
+} sup_auth_status_t;
+#endif
+
+typedef struct wl_wsec_key {
+ uint32 index; /**< key index */
+ uint32 len; /**< key length */
+ uint8 data[DOT11_MAX_KEY_SIZE]; /**< key data */
+ uint32 pad_1[18];
+ uint32 algo; /**< CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
+ uint32 flags; /**< misc flags */
+ uint32 pad_2[2];
+ int32 pad_3;
+ int32 iv_initialized; /**< has IV been initialized already? */
+ int32 pad_4;
+ /* Rx IV */
+ struct {
+ uint32 hi; /**< upper 32 bits of IV */
+ uint16 lo; /**< lower 16 bits of IV */
+ } rxiv;
+ uint32 pad_5[2];
+ struct ether_addr ea; /**< per station */
+} wl_wsec_key_t;
+
+#define WSEC_MIN_PSK_LEN 8
+#define WSEC_MAX_PSK_LEN 64
+
+/** Flag for key material needing passhash'ing */
+#define WSEC_PASSPHRASE (1<<0)
+
+/**receptacle for WLC_SET_WSEC_PMK parameter */
+typedef struct wsec_pmk {
+ ushort key_len; /**< octets in key material */
+ ushort flags; /**< key handling qualification */
+ uint8 key[WSEC_MAX_PSK_LEN]; /**< PMK material */
+} wsec_pmk_t;
+
+typedef struct _pmkid {
+ struct ether_addr BSSID;
+ uint8 PMKID[WPA2_PMKID_LEN];
+} pmkid_t;
+
+typedef struct _pmkid_list {
+ uint32 npmkid;
+ pmkid_t pmkid[1];
+} pmkid_list_t;
+
+typedef struct _pmkid_cand {
+ struct ether_addr BSSID;
+ uint8 preauth;
+} pmkid_cand_t;
+
+typedef struct _pmkid_cand_list {
+ uint32 npmkid_cand;
+ pmkid_cand_t pmkid_cand[1];
+} pmkid_cand_list_t;
+
+#define WL_STA_ANT_MAX 4 /**< max possible rx antennas */
+
+typedef struct wl_assoc_info {
+ uint32 req_len;
+ uint32 resp_len;
+ uint32 flags;
+ struct dot11_assoc_req req;
+ struct ether_addr reassoc_bssid; /**< used in reassoc's */
+ struct dot11_assoc_resp resp;
+} wl_assoc_info_t;
+
+typedef struct wl_led_info {
+ uint32 index; /**< led index */
+ uint32 behavior;
+ uint8 activehi;
+} wl_led_info_t;
+
+
+/** srom read/write struct passed through ioctl */
+typedef struct {
+ uint32 byteoff; /**< byte offset */
+ uint32 nbytes; /**< number of bytes */
+ uint16 buf[1];
+} srom_rw_t;
+
+#define CISH_FLAG_PCIECIS (1 << 15) /**< write CIS format bit for PCIe CIS */
+
+/** similar cis (srom or otp) struct [iovar: may not be aligned] */
+typedef struct {
+ uint16 source; /**< cis source */
+ uint16 flags; /**< flags */
+ uint32 byteoff; /**< byte offset */
+ uint32 nbytes; /**< number of bytes */
+ /* data follows here */
+} cis_rw_t;
+
+/** R_REG and W_REG struct passed through ioctl */
+typedef struct {
+ uint32 byteoff; /**< byte offset of the field in d11regs_t */
+ uint32 val; /**< read/write value of the field */
+ uint32 size; /**< sizeof the field */
+ uint32 band; /**< band (optional) */
+} rw_reg_t;
+
+/**
+ * Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band
+ * PCL - Power Control Loop
+ */
+typedef struct {
+ uint16 auto_ctrl; /**< WL_ATTEN_XX */
+ uint16 bb; /**< Baseband attenuation */
+ uint16 radio; /**< Radio attenuation */
+ uint16 txctl1; /**< Radio TX_CTL1 value */
+} atten_t;
+
+/** Per-AC retry parameters */
+struct wme_tx_params_s {
+ uint8 short_retry;
+ uint8 short_fallback;
+ uint8 long_retry;
+ uint8 long_fallback;
+ uint16 max_rate; /**< In units of 512 Kbps */
+};
+
+typedef struct wme_tx_params_s wme_tx_params_t;
+
+#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT)
+
+/**Used to get specific link/ac parameters */
+typedef struct {
+ int32 ac;
+ uint8 val;
+ struct ether_addr ea;
+} link_val_t;
+
+
+#define WL_PM_MUTE_TX_VER 1
+
+typedef struct wl_pm_mute_tx {
+ uint16 version; /**< version */
+ uint16 len; /**< length */
+ uint16 deadline; /**< deadline timer (in milliseconds) */
+ uint8 enable; /**< set to 1 to enable mode; set to 0 to disable it */
+} wl_pm_mute_tx_t;
+
+
+/* sta_info_t version 4 */
+typedef struct {
+ uint16 ver; /**< version of this struct */
+ uint16 len; /**< length in bytes of this structure */
+ uint16 cap; /**< sta's advertised capabilities */
+ uint32 flags; /**< flags defined below */
+ uint32 idle; /**< time since data pkt rx'd from sta */
+ struct ether_addr ea; /**< Station address */
+ wl_rateset_t rateset; /**< rateset in use */
+ uint32 in; /**< seconds elapsed since associated */
+ uint32 listen_interval_inms; /**< Min Listen interval in ms for this STA */
+ uint32 tx_pkts; /**< # of user packets transmitted (unicast) */
+ uint32 tx_failures; /**< # of user packets failed */
+ uint32 rx_ucast_pkts; /**< # of unicast packets received */
+ uint32 rx_mcast_pkts; /**< # of multicast packets received */
+ uint32 tx_rate; /**< Rate used by last tx frame */
+ uint32 rx_rate; /**< Rate of last successful rx frame */
+ uint32 rx_decrypt_succeeds; /**< # of packet decrypted successfully */
+ uint32 rx_decrypt_failures; /**< # of packet decrypted unsuccessfully */
+ uint32 tx_tot_pkts; /**< # of user tx pkts (ucast + mcast) */
+ uint32 rx_tot_pkts; /**< # of data packets recvd (uni + mcast) */
+ uint32 tx_mcast_pkts; /**< # of mcast pkts txed */
+ uint64 tx_tot_bytes; /**< data bytes txed (ucast + mcast) */
+ uint64 rx_tot_bytes; /**< data bytes recvd (ucast + mcast) */
+ uint64 tx_ucast_bytes; /**< data bytes txed (ucast) */
+ uint64 tx_mcast_bytes; /**< # data bytes txed (mcast) */
+ uint64 rx_ucast_bytes; /**< data bytes recvd (ucast) */
+ uint64 rx_mcast_bytes; /**< data bytes recvd (mcast) */
+ int8 rssi[WL_STA_ANT_MAX]; /**< average rssi per antenna
+ * of data frames
+ */
+ int8 nf[WL_STA_ANT_MAX]; /**< per antenna noise floor */
+ uint16 aid; /**< association ID */
+ uint16 ht_capabilities; /**< advertised ht caps */
+ uint16 vht_flags; /**< converted vht flags */
+ uint32 tx_pkts_retried; /**< # of frames where a retry was
+ * necessary
+ */
+ uint32 tx_pkts_retry_exhausted; /**< # of user frames where a retry
+ * was exhausted
+ */
+ int8 rx_lastpkt_rssi[WL_STA_ANT_MAX]; /**< Per antenna RSSI of last
+ * received data frame.
+ */
+ /* TX WLAN retry/failure statistics:
+ * Separated for host requested frames and WLAN locally generated frames.
+ * Include unicast frame only where the retries/failures can be counted.
+ */
+ uint32 tx_pkts_total; /**< # user frames sent successfully */
+ uint32 tx_pkts_retries; /**< # user frames retries */
+ uint32 tx_pkts_fw_total; /**< # FW generated sent successfully */
+ uint32 tx_pkts_fw_retries; /**< # retries for FW generated frames */
+ uint32 tx_pkts_fw_retry_exhausted; /**< # FW generated where a retry
+ * was exhausted
+ */
+ uint32 rx_pkts_retried; /**< # rx with retry bit set */
+ uint32 tx_rate_fallback; /**< lowest fallback TX rate */
+ /* Fields above this line are common to sta_info_t versions 4 and 5 */
+
+ uint32 rx_dur_total; /* total user RX duration (estimated) */
+
+ chanspec_t chanspec; /** chanspec this sta is on */
+ wl_rateset_args_t rateset_adv; /* rateset along with mcs index bitmap */
+} sta_info_v4_t;
+
+/* Note: Version 4 is the latest version of sta_info_t. Version 5 is abandoned.
+ * Please add new fields to version 4, not version 5.
+ */
+/* sta_info_t version 5 */
+typedef struct {
+ uint16 ver; /**< version of this struct */
+ uint16 len; /**< length in bytes of this structure */
+ uint16 cap; /**< sta's advertised capabilities */
+ uint32 flags; /**< flags defined below */
+ uint32 idle; /**< time since data pkt rx'd from sta */
+ struct ether_addr ea; /**< Station address */
+ wl_rateset_t rateset; /**< rateset in use */
+ uint32 in; /**< seconds elapsed since associated */
+ uint32 listen_interval_inms; /**< Min Listen interval in ms for this STA */
+ uint32 tx_pkts; /**< # of user packets transmitted (unicast) */
+ uint32 tx_failures; /**< # of user packets failed */
+ uint32 rx_ucast_pkts; /**< # of unicast packets received */
+ uint32 rx_mcast_pkts; /**< # of multicast packets received */
+ uint32 tx_rate; /**< Rate used by last tx frame */
+ uint32 rx_rate; /**< Rate of last successful rx frame */
+ uint32 rx_decrypt_succeeds; /**< # of packet decrypted successfully */
+ uint32 rx_decrypt_failures; /**< # of packet decrypted unsuccessfully */
+ uint32 tx_tot_pkts; /**< # of user tx pkts (ucast + mcast) */
+ uint32 rx_tot_pkts; /**< # of data packets recvd (uni + mcast) */
+ uint32 tx_mcast_pkts; /**< # of mcast pkts txed */
+ uint64 tx_tot_bytes; /**< data bytes txed (ucast + mcast) */
+ uint64 rx_tot_bytes; /**< data bytes recvd (ucast + mcast) */
+ uint64 tx_ucast_bytes; /**< data bytes txed (ucast) */
+ uint64 tx_mcast_bytes; /**< # data bytes txed (mcast) */
+ uint64 rx_ucast_bytes; /**< data bytes recvd (ucast) */
+ uint64 rx_mcast_bytes; /**< data bytes recvd (mcast) */
+ int8 rssi[WL_STA_ANT_MAX]; /**< average rssi per antenna
+ * of data frames
+ */
+ int8 nf[WL_STA_ANT_MAX]; /**< per antenna noise floor */
+ uint16 aid; /**< association ID */
+ uint16 ht_capabilities; /**< advertised ht caps */
+ uint16 vht_flags; /**< converted vht flags */
+ uint32 tx_pkts_retried; /**< # of frames where a retry was
+ * necessary
+ */
+ uint32 tx_pkts_retry_exhausted; /**< # of user frames where a retry
+ * was exhausted
+ */
+ int8 rx_lastpkt_rssi[WL_STA_ANT_MAX]; /**< Per antenna RSSI of last
+ * received data frame.
+ */
+ /* TX WLAN retry/failure statistics:
+ * Separated for host requested frames and WLAN locally generated frames.
+ * Include unicast frame only where the retries/failures can be counted.
+ */
+ uint32 tx_pkts_total; /**< # user frames sent successfully */
+ uint32 tx_pkts_retries; /**< # user frames retries */
+ uint32 tx_pkts_fw_total; /**< # FW generated sent successfully */
+ uint32 tx_pkts_fw_retries; /**< # retries for FW generated frames */
+ uint32 tx_pkts_fw_retry_exhausted; /**< # FW generated where a retry
+ * was exhausted
+ */
+ uint32 rx_pkts_retried; /**< # rx with retry bit set */
+ uint32 tx_rate_fallback; /**< lowest fallback TX rate */
+ /* Fields above this line are common to sta_info_t versions 4 and 5 */
+
+ chanspec_t chanspec; /** chanspec this sta is on */
+ wl_rateset_args_t rateset_adv; /* rateset along with mcs index bitmap */
+} sta_info_v5_t;
+
+#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_tot_pkts)
+
+#define WL_STA_VER_4 4
+#define WL_STA_VER_5 5
+#define WL_STA_VER WL_STA_VER_4
+
+#define SWDIV_STATS_VERSION_2 2
+#define SWDIV_STATS_CURRENT_VERSION SWDIV_STATS_VERSION_2
+
+struct wlc_swdiv_stats_v1 {
+ uint32 auto_en;
+ uint32 active_ant;
+ uint32 rxcount;
+ int32 avg_snr_per_ant0;
+ int32 avg_snr_per_ant1;
+ int32 avg_snr_per_ant2;
+ uint32 swap_ge_rxcount0;
+ uint32 swap_ge_rxcount1;
+ uint32 swap_ge_snrthresh0;
+ uint32 swap_ge_snrthresh1;
+ uint32 swap_txfail0;
+ uint32 swap_txfail1;
+ uint32 swap_timer0;
+ uint32 swap_timer1;
+ uint32 swap_alivecheck0;
+ uint32 swap_alivecheck1;
+ uint32 rxcount_per_ant0;
+ uint32 rxcount_per_ant1;
+ uint32 acc_rxcount;
+ uint32 acc_rxcount_per_ant0;
+ uint32 acc_rxcount_per_ant1;
+ uint32 tx_auto_en;
+ uint32 tx_active_ant;
+ uint32 rx_policy;
+ uint32 tx_policy;
+ uint32 cell_policy;
+ uint32 swap_snrdrop0;
+ uint32 swap_snrdrop1;
+ uint32 mws_antsel_ovr_tx;
+ uint32 mws_antsel_ovr_rx;
+ uint8 swap_trig_event_id;
+};
+
+struct wlc_swdiv_stats_v2 {
+ uint16 version; /* version of the structure
+ * as defined by SWDIV_STATS_CURRENT_VERSION
+ */
+ uint16 length; /* length of the entire structure */
+ uint32 auto_en;
+ uint32 active_ant;
+ uint32 rxcount;
+ int32 avg_snr_per_ant0;
+ int32 avg_snr_per_ant1;
+ int32 avg_snr_per_ant2;
+ uint32 swap_ge_rxcount0;
+ uint32 swap_ge_rxcount1;
+ uint32 swap_ge_snrthresh0;
+ uint32 swap_ge_snrthresh1;
+ uint32 swap_txfail0;
+ uint32 swap_txfail1;
+ uint32 swap_timer0;
+ uint32 swap_timer1;
+ uint32 swap_alivecheck0;
+ uint32 swap_alivecheck1;
+ uint32 rxcount_per_ant0;
+ uint32 rxcount_per_ant1;
+ uint32 acc_rxcount;
+ uint32 acc_rxcount_per_ant0;
+ uint32 acc_rxcount_per_ant1;
+ uint32 tx_auto_en;
+ uint32 tx_active_ant;
+ uint32 rx_policy;
+ uint32 tx_policy;
+ uint32 cell_policy;
+ uint32 swap_snrdrop0;
+ uint32 swap_snrdrop1;
+ uint32 mws_antsel_ovr_tx;
+ uint32 mws_antsel_ovr_rx;
+ uint32 swap_trig_event_id;
+};
+
+#define WLC_NUMRATES 16 /**< max # of rates in a rateset */
+
+typedef struct wlc_rateset {
+ uint32 count; /**< number of rates in rates[] */
+ uint8 rates[WLC_NUMRATES]; /**< rates in 500kbps units w/hi bit set if basic */
+ uint8 htphy_membership; /**< HT PHY Membership */
+ uint8 mcs[MCSSET_LEN]; /**< supported mcs index bit map */
+ uint16 vht_mcsmap; /**< supported vht mcs nss bit map */
+ uint16 vht_mcsmap_prop; /**< supported prop vht mcs nss bit map */
+} wlc_rateset_t;
+
+/**Used to get specific STA parameters */
+typedef struct {
+ uint32 val;
+ struct ether_addr ea;
+} scb_val_t;
+
+/**Used by iovar versions of some ioctls, i.e. WLC_SCB_AUTHORIZE et al */
+typedef struct {
+ uint32 code;
+ scb_val_t ioctl_args;
+} authops_t;
+
+/** channel encoding */
+typedef struct channel_info {
+ int32 hw_channel;
+ int32 target_channel;
+ int32 scan_channel;
+} channel_info_t;
+
+/** For ioctls that take a list of MAC addresses */
+typedef struct maclist {
+ uint32 count; /**< number of MAC addresses */
+ struct ether_addr ea[1]; /**< variable length array of MAC addresses */
+} maclist_t;
+
+/**get pkt count struct passed through ioctl */
+typedef struct get_pktcnt {
+ uint32 rx_good_pkt;
+ uint32 rx_bad_pkt;
+ uint32 tx_good_pkt;
+ uint32 tx_bad_pkt;
+ uint32 rx_ocast_good_pkt; /**< unicast packets destined for others */
+} get_pktcnt_t;
+
+/* NINTENDO2 */
+#define LQ_IDX_MIN 0
+#define LQ_IDX_MAX 1
+#define LQ_IDX_AVG 2
+#define LQ_IDX_SUM 2
+#define LQ_IDX_LAST 3
+#define LQ_STOP_MONITOR 0
+#define LQ_START_MONITOR 1
+
+/** Get averages RSSI, Rx PHY rate and SNR values */
+typedef struct {
+ int32 rssi[LQ_IDX_LAST]; /**< Array to keep min, max, avg rssi */
+ int32 snr[LQ_IDX_LAST]; /**< Array to keep min, max, avg snr */
+ int32 isvalid; /**< Flag indicating whether above data is valid */
+} wl_lq_t; /* Link Quality */
+
+typedef enum wl_wakeup_reason_type {
+ LCD_ON = 1,
+ LCD_OFF,
+ DRC1_WAKE,
+ DRC2_WAKE,
+ REASON_LAST
+} wl_wr_type_t;
+
+typedef struct {
+ /** Unique filter id */
+ uint32 id;
+ /** stores the reason for the last wake up */
+ uint8 reason;
+} wl_wr_t;
+
+/** Get MAC specific rate histogram command */
+typedef struct {
+ struct ether_addr ea; /**< MAC Address */
+ uint8 ac_cat; /**< Access Category */
+ uint8 num_pkts; /**< Number of packet entries to be averaged */
+} wl_mac_ratehisto_cmd_t; /**< MAC Specific Rate Histogram command */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/** Get MAC rate histogram response */
+typedef struct {
+ uint32 rate[DOT11_RATE_MAX + 1]; /**< Rates */
+ uint32 mcs[WL_RATESET_SZ_HT_IOCTL * WL_TX_CHAINS_MAX]; /**< MCS counts */
+ uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /**< VHT counts */
+ uint32 tsf_timer[2][2]; /**< Start and End time for 8bytes value */
+ uint32 prop11n_mcs[WLC_11N_LAST_PROP_MCS - WLC_11N_FIRST_PROP_MCS + 1]; /** MCS counts */
+} wl_mac_ratehisto_res_t; /**< MAC Specific Rate Histogram Response */
+
+/* sta_info ecounters */
+typedef struct {
+ struct ether_addr ea; /* Station MAC addr */
+ struct ether_addr BSSID; /* BSSID of the BSS */
+ uint32 tx_pkts_fw_total; /* # FW generated sent successfully */
+ uint32 tx_pkts_fw_retries; /* # retries for FW generated frames */
+ uint32 tx_pkts_fw_retry_exhausted; /* # FW generated which
+ * failed after retry
+ */
+} sta_info_ecounters_t;
+
+#define STAMON_MODULE_VER 1
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/**Linux network driver ioctl encoding */
+typedef struct wl_ioctl {
+ uint32 cmd; /**< common ioctl definition */
+ void *buf; /**< pointer to user buffer */
+ uint32 len; /**< length of user buffer */
+ uint8 set; /**< 1=set IOCTL; 0=query IOCTL */
+ uint32 used; /**< bytes read or written (optional) */
+ uint32 needed; /**< bytes needed (optional) */
+} wl_ioctl_t;
+
+#ifdef CONFIG_COMPAT
+typedef struct compat_wl_ioctl {
+ uint32 cmd; /**< common ioctl definition */
+ uint32 buf; /**< pointer to user buffer */
+ uint32 len; /**< length of user buffer */
+ uint8 set; /**< 1=set IOCTL; 0=query IOCTL */
+ uint32 used; /**< bytes read or written (optional) */
+ uint32 needed; /**< bytes needed (optional) */
+} compat_wl_ioctl_t;
+#endif /* CONFIG_COMPAT */
+
+#define WL_NUM_RATES_CCK 4 /**< 1, 2, 5.5, 11 Mbps */
+#define WL_NUM_RATES_OFDM 8 /**< 6, 9, 12, 18, 24, 36, 48, 54 Mbps SISO/CDD */
+#define WL_NUM_RATES_MCS_1STREAM 8 /**< MCS 0-7 1-stream rates - SISO/CDD/STBC/MCS */
+#define WL_NUM_RATES_EXTRA_VHT 2 /**< Additional VHT 11AC rates */
+#define WL_NUM_RATES_VHT 10
+#define WL_NUM_RATES_MCS32 1
+
+
+/*
+ * Structure for passing hardware and software
+ * revision info up from the driver.
+ */
+typedef struct wlc_rev_info {
+ uint32 vendorid; /**< PCI vendor id */
+ uint32 deviceid; /**< device id of chip */
+ uint32 radiorev; /**< radio revision */
+ uint32 chiprev; /**< chip revision */
+ uint32 corerev; /**< core revision */
+ uint32 boardid; /**< board identifier (usu. PCI sub-device id) */
+ uint32 boardvendor; /**< board vendor (usu. PCI sub-vendor id) */
+ uint32 boardrev; /**< board revision */
+ uint32 driverrev; /**< driver version */
+ uint32 ucoderev; /**< microcode version */
+ uint32 bus; /**< bus type */
+ uint32 chipnum; /**< chip number */
+ uint32 phytype; /**< phy type */
+ uint32 phyrev; /**< phy revision */
+ uint32 anarev; /**< anacore rev */
+ uint32 chippkg; /**< chip package info */
+ uint32 nvramrev; /**< nvram revision number */
+ uint32 phyminorrev; /**< phy minor rev */
+ uint32 coreminorrev; /**< core minor rev */
+ uint32 drvrev_major; /**< driver version: major */
+ uint32 drvrev_minor; /**< driver version: minor */
+ uint32 drvrev_rc; /**< driver version: rc */
+ uint32 drvrev_rc_inc; /**< driver version: rc incremental */
+} wlc_rev_info_t;
+
+#define WL_REV_INFO_LEGACY_LENGTH 48
+
+#define WL_BRAND_MAX 10
+typedef struct wl_instance_info {
+ uint32 instance;
+ int8 brand[WL_BRAND_MAX];
+} wl_instance_info_t;
+
+/** structure to change size of tx fifo */
+typedef struct wl_txfifo_sz {
+ uint16 magic;
+ uint16 fifo;
+ uint16 size;
+} wl_txfifo_sz_t;
+
+/* Transfer info about an IOVar from the driver */
+/**Max supported IOV name size in bytes, + 1 for nul termination */
+#define WLC_IOV_NAME_LEN (32 + 1)
+
+typedef struct wlc_iov_trx_s {
+ uint8 module;
+ uint8 type;
+ char name[WLC_IOV_NAME_LEN];
+} wlc_iov_trx_t;
+
+/** bump this number if you change the ioctl interface */
+#define WLC_IOCTL_VERSION 2
+#define WLC_IOCTL_VERSION_LEGACY_IOTYPES 1
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#ifdef CONFIG_USBRNDIS_RETAIL
+/** struct passed in for WLC_NDCONFIG_ITEM */
+typedef struct {
+ char *name;
+ void *param;
+} ndconfig_item_t;
+#endif
+
+/* ifdef EXT_STA */
+typedef struct _wl_assoc_result {
+ ulong associated;
+ ulong NDIS_auth;
+ ulong NDIS_infra;
+} wl_assoc_result_t;
+/* EXT_STA */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+#define WL_PHY_PAVARS_LEN 32 /**< Phytype, Bandrange, chain, a[0], b[0], c[0], d[0] .. */
+
+
+#define WL_PHY_PAVAR_VER 1 /**< pavars version */
+#define WL_PHY_PAVARS2_NUM 3 /**< a1, b0, b1 */
+typedef struct wl_pavars2 {
+ uint16 ver; /**< version of this struct */
+ uint16 len; /**< len of this structure */
+ uint16 inuse; /**< driver return 1 for a1,b0,b1 in current band range */
+ uint16 phy_type; /**< phy type */
+ uint16 bandrange;
+ uint16 chain;
+ uint16 inpa[WL_PHY_PAVARS2_NUM]; /**< phy pavars for one band range */
+} wl_pavars2_t;
+
+typedef struct wl_po {
+ uint16 phy_type; /**< Phy type */
+ uint16 band;
+ uint16 cckpo;
+ uint32 ofdmpo;
+ uint16 mcspo[8];
+} wl_po_t;
+
+#define WL_NUM_RPCALVARS 5 /**< number of rpcal vars */
+
+typedef struct wl_rpcal {
+ uint16 value;
+ uint16 update;
+} wl_rpcal_t;
+
+#define WL_NUM_RPCALPHASEVARS 5 /* number of rpcal phase vars */
+
+typedef struct wl_rpcal_phase {
+ uint16 value;
+ uint16 update;
+} wl_rpcal_phase_t;
+
+typedef struct wl_aci_args {
+ int32 enter_aci_thresh; /* Trigger level to start detecting ACI */
+ int32 exit_aci_thresh; /* Trigger level to exit ACI mode */
+ int32 usec_spin; /* microsecs to delay between rssi samples */
+ int32 glitch_delay; /* interval between ACI scans when glitch count is consistently high */
+ uint16 nphy_adcpwr_enter_thresh; /**< ADC power to enter ACI mitigation mode */
+ uint16 nphy_adcpwr_exit_thresh; /**< ADC power to exit ACI mitigation mode */
+ uint16 nphy_repeat_ctr; /**< Number of tries per channel to compute power */
+ uint16 nphy_num_samples; /**< Number of samples to compute power on one channel */
+ uint16 nphy_undetect_window_sz; /**< num of undetects to exit ACI Mitigation mode */
+ uint16 nphy_b_energy_lo_aci; /**< low ACI power energy threshold for bphy */
+ uint16 nphy_b_energy_md_aci; /**< mid ACI power energy threshold for bphy */
+ uint16 nphy_b_energy_hi_aci; /**< high ACI power energy threshold for bphy */
+ uint16 nphy_noise_noassoc_glitch_th_up; /**< wl interference 4 */
+ uint16 nphy_noise_noassoc_glitch_th_dn;
+ uint16 nphy_noise_assoc_glitch_th_up;
+ uint16 nphy_noise_assoc_glitch_th_dn;
+ uint16 nphy_noise_assoc_aci_glitch_th_up;
+ uint16 nphy_noise_assoc_aci_glitch_th_dn;
+ uint16 nphy_noise_assoc_enter_th;
+ uint16 nphy_noise_noassoc_enter_th;
+ uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th;
+ uint16 nphy_noise_noassoc_crsidx_incr;
+ uint16 nphy_noise_assoc_crsidx_incr;
+ uint16 nphy_noise_crsidx_decr;
+} wl_aci_args_t;
+
+#define WL_ACI_ARGS_LEGACY_LENGTH 16 /**< bytes of pre NPHY aci args */
+#define WL_SAMPLECOLLECT_T_VERSION 2 /**< version of wl_samplecollect_args_t struct */
+typedef struct wl_samplecollect_args {
+ /* version 0 fields */
+ uint8 coll_us;
+ int32 cores;
+ /* add'l version 1 fields */
+ uint16 version; /**< see definition of WL_SAMPLECOLLECT_T_VERSION */
+ uint16 length; /**< length of entire structure */
+ int8 trigger;
+ uint16 timeout;
+ uint16 mode;
+ uint32 pre_dur;
+ uint32 post_dur;
+ uint8 gpio_sel;
+ uint8 downsamp;
+ uint8 be_deaf;
+ uint8 agc; /**< loop from init gain and going down */
+ uint8 filter; /**< override high pass corners to lowest */
+ /* add'l version 2 fields */
+ uint8 trigger_state;
+ uint8 module_sel1;
+ uint8 module_sel2;
+ uint16 nsamps;
+ int32 bitStart;
+ uint32 gpioCapMask;
+ uint8 gpio_collection;
+} wl_samplecollect_args_t;
+
+#define WL_SAMPLEDATA_T_VERSION 1 /**< version of wl_samplecollect_args_t struct */
+/* version for unpacked sample data, int16 {(I,Q),Core(0..N)} */
+#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2
+
+typedef struct wl_sampledata {
+ uint16 version; /**< structure version */
+ uint16 size; /**< size of structure */
+ uint16 tag; /**< Header/Data */
+ uint16 length; /**< data length */
+ uint32 flag; /**< bit def */
+} wl_sampledata_t;
+
+
+/* WL_OTA START */
+/* OTA Test Status */
+enum {
+ WL_OTA_TEST_IDLE = 0, /**< Default Idle state */
+ WL_OTA_TEST_ACTIVE = 1, /**< Test Running */
+ WL_OTA_TEST_SUCCESS = 2, /**< Successfully Finished Test */
+ WL_OTA_TEST_FAIL = 3 /**< Test Failed in the Middle */
+};
+
+/* OTA SYNC Status */
+enum {
+ WL_OTA_SYNC_IDLE = 0, /**< Idle state */
+ WL_OTA_SYNC_ACTIVE = 1, /**< Waiting for Sync */
+ WL_OTA_SYNC_FAIL = 2 /**< Sync pkt not recieved */
+};
+
+/* Various error states dut can get stuck during test */
+enum {
+ WL_OTA_SKIP_TEST_CAL_FAIL = 1, /**< Phy calibration failed */
+ WL_OTA_SKIP_TEST_SYNCH_FAIL = 2, /**< Sync Packet not recieved */
+ WL_OTA_SKIP_TEST_FILE_DWNLD_FAIL = 3, /**< Cmd flow file download failed */
+ WL_OTA_SKIP_TEST_NO_TEST_FOUND = 4, /**< No test found in Flow file */
+ WL_OTA_SKIP_TEST_WL_NOT_UP = 5, /**< WL UP failed */
+ WL_OTA_SKIP_TEST_UNKNOWN_CALL /**< Unintentional scheduling on ota test */
+};
+
+/* Differentiator for ota_tx and ota_rx */
+enum {
+ WL_OTA_TEST_TX = 0, /**< ota_tx */
+ WL_OTA_TEST_RX = 1, /**< ota_rx */
+};
+
+/* Catch 3 modes of operation: 20Mhz, 40Mhz, 20 in 40 Mhz */
+enum {
+ WL_OTA_TEST_BW_20_IN_40MHZ = 0, /**< 20 in 40 operation */
+ WL_OTA_TEST_BW_20MHZ = 1, /**< 20 Mhz operation */
+ WL_OTA_TEST_BW_40MHZ = 2, /**< full 40Mhz operation */
+ WL_OTA_TEST_BW_80MHZ = 3 /* full 80Mhz operation */
+};
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define HT_MCS_INUSE 0x00000080 /* HT MCS in use,indicates b0-6 holds an mcs */
+#define VHT_MCS_INUSE 0x00000100 /* VHT MCS in use,indicates b0-6 holds an mcs */
+#define OTA_RATE_MASK 0x0000007f /* rate/mcs value */
+#define OTA_STF_SISO 0
+#define OTA_STF_CDD 1
+#define OTA_STF_STBC 2
+#define OTA_STF_SDM 3
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+typedef struct ota_rate_info {
+ uint8 rate_cnt; /**< Total number of rates */
+ uint16 rate_val_mbps[WL_OTA_TEST_MAX_NUM_RATE]; /**< array of rates from 1mbps to 130mbps */
+ /**< for legacy rates : ratein mbps * 2 */
+ /**< for HT rates : mcs index */
+} ota_rate_info_t;
+
+typedef struct ota_power_info {
+ int8 pwr_ctrl_on; /**< power control on/off */
+ int8 start_pwr; /**< starting power/index */
+ int8 delta_pwr; /**< delta power/index */
+ int8 end_pwr; /**< end power/index */
+} ota_power_info_t;
+
+typedef struct ota_packetengine {
+ uint16 delay; /**< Inter-packet delay */
+ /**< for ota_tx, delay is tx ifs in micro seconds */
+ /* for ota_rx, delay is wait time in milliseconds */
+ uint16 nframes; /**< Number of frames */
+ uint16 length; /**< Packet length */
+} ota_packetengine_t;
+
+/*
+ * OTA txant/rxant parameter
+ * bit7-4: 4 bits swdiv_tx/rx_policy bitmask, specify antenna-policy for SW diversity
+ * bit3-0: 4 bits TxCore bitmask, specify cores used for transmit frames
+ * (maximum spatial expansion)
+ */
+#define WL_OTA_TEST_ANT_MASK 0xF0
+#define WL_OTA_TEST_CORE_MASK 0x0F
+
+/* OTA txant/rxant 'ant_mask' field; map to Tx/Rx antenna policy for SW diversity */
+enum {
+ WL_OTA_TEST_FORCE_ANT0 = 0x10, /* force antenna to Ant 0 */
+ WL_OTA_TEST_FORCE_ANT1 = 0x20, /* force antenna to Ant 1 */
+};
+
+/* antenna/core fields access */
+#define WL_OTA_TEST_GET_ANT(_txant) ((_txant) & WL_OTA_TEST_ANT_MASK)
+#define WL_OTA_TEST_GET_CORE(_txant) ((_txant) & WL_OTA_TEST_CORE_MASK)
+
+/** Test info vector */
+typedef struct wl_ota_test_args {
+ uint8 cur_test; /**< test phase */
+ uint8 chan; /**< channel */
+ uint8 bw; /**< bandwidth */
+ uint8 control_band; /**< control band */
+ uint8 stf_mode; /**< stf mode */
+ ota_rate_info_t rt_info; /**< Rate info */
+ ota_packetengine_t pkteng; /**< packeteng info */
+ uint8 txant; /**< tx antenna */
+ uint8 rxant; /**< rx antenna */
+ ota_power_info_t pwr_info; /**< power sweep info */
+ uint8 wait_for_sync; /**< wait for sync or not */
+ uint8 ldpc;
+ uint8 sgi;
+ /* Update WL_OTA_TESTVEC_T_VERSION for adding new members to this structure */
+} wl_ota_test_args_t;
+
+#define WL_OTA_TESTVEC_T_VERSION 1 /* version of wl_ota_test_vector_t struct */
+typedef struct wl_ota_test_vector {
+ uint16 version;
+ wl_ota_test_args_t test_arg[WL_OTA_TEST_MAX_NUM_SEQ]; /**< Test argument struct */
+ uint16 test_cnt; /**< Total no of test */
+ uint8 file_dwnld_valid; /**< File successfully downloaded */
+ uint8 sync_timeout; /**< sync packet timeout */
+ int8 sync_fail_action; /**< sync fail action */
+ struct ether_addr sync_mac; /**< macaddress for sync pkt */
+ struct ether_addr tx_mac; /**< macaddress for tx */
+ struct ether_addr rx_mac; /**< macaddress for rx */
+ int8 loop_test; /**< dbg feature to loop the test */
+ uint16 test_rxcnt;
+ /* Update WL_OTA_TESTVEC_T_VERSION for adding new members to this structure */
+} wl_ota_test_vector_t;
+
+
+/** struct copied back form dongle to host to query the status */
+typedef struct wl_ota_test_status {
+ int16 cur_test_cnt; /**< test phase */
+ int8 skip_test_reason; /**< skip test reasoin */
+ wl_ota_test_args_t test_arg; /**< cur test arg details */
+ uint16 test_cnt; /**< total no of test downloaded */
+ uint8 file_dwnld_valid; /**< file successfully downloaded ? */
+ uint8 sync_timeout; /**< sync timeout */
+ int8 sync_fail_action; /**< sync fail action */
+ struct ether_addr sync_mac; /**< macaddress for sync pkt */
+ struct ether_addr tx_mac; /**< tx mac address */
+ struct ether_addr rx_mac; /**< rx mac address */
+ uint8 test_stage; /**< check the test status */
+ int8 loop_test; /**< Debug feature to puts test enfine in a loop */
+ uint8 sync_status; /**< sync status */
+} wl_ota_test_status_t;
+
+/* FOR ioctl that take the sta monitor information */
+typedef struct stamon_data {
+ struct ether_addr ea;
+ int32 rssi;
+} stamon_data_t;
+
+typedef struct stamon_info {
+ int32 version;
+ uint32 count;
+ stamon_data_t sta_data[1];
+} stamon_info_t;
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+typedef struct wl_ota_rx_rssi {
+ uint16 pktcnt; /* Pkt count used for this rx test */
+ chanspec_t chanspec; /* Channel info on which the packets are received */
+ int16 rssi; /* Average RSSI of the first 50% packets received */
+} wl_ota_rx_rssi_t;
+
+#define WL_OTARSSI_T_VERSION 1 /* version of wl_ota_test_rssi_t struct */
+#define WL_OTA_TEST_RSSI_FIXED_SIZE OFFSETOF(wl_ota_test_rssi_t, rx_rssi)
+
+typedef struct wl_ota_test_rssi {
+ uint8 version;
+ uint8 testcnt; /* total measured RSSI values, valid on output only */
+ wl_ota_rx_rssi_t rx_rssi[1]; /* Variable length array of wl_ota_rx_rssi_t */
+} wl_ota_test_rssi_t;
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* WL_OTA END */
+
+/**wl_radar_args_t */
+typedef struct {
+ int32 npulses; /**< required number of pulses at n * t_int */
+ int32 ncontig; /**< required number of pulses at t_int */
+ int32 min_pw; /**< minimum pulse width (20 MHz clocks) */
+ int32 max_pw; /**< maximum pulse width (20 MHz clocks) */
+ uint16 thresh0; /**< Radar detection, thresh 0 */
+ uint16 thresh1; /**< Radar detection, thresh 1 */
+ uint16 blank; /**< Radar detection, blank control */
+ uint16 fmdemodcfg; /**< Radar detection, fmdemod config */
+ int32 npulses_lp; /**< Radar detection, minimum long pulses */
+ int32 min_pw_lp; /**< Minimum pulsewidth for long pulses */
+ int32 max_pw_lp; /**< Maximum pulsewidth for long pulses */
+ int32 min_fm_lp; /**< Minimum fm for long pulses */
+ int32 max_span_lp; /**< Maximum deltat for long pulses */
+ int32 min_deltat; /**< Minimum spacing between pulses */
+ int32 max_deltat; /**< Maximum spacing between pulses */
+ uint16 autocorr; /**< Radar detection, autocorr on or off */
+ uint16 st_level_time; /**< Radar detection, start_timing level */
+ uint16 t2_min; /**< minimum clocks needed to remain in state 2 */
+ uint32 version; /**< version */
+ uint32 fra_pulse_err; /**< sample error margin for detecting French radar pulsed */
+ int32 npulses_fra; /**< Radar detection, minimum French pulses set */
+ int32 npulses_stg2; /**< Radar detection, minimum staggered-2 pulses set */
+ int32 npulses_stg3; /**< Radar detection, minimum staggered-3 pulses set */
+ uint16 percal_mask; /**< defines which period cal is masked from radar detection */
+ int32 quant; /**< quantization resolution to pulse positions */
+ uint32 min_burst_intv_lp; /**< minimum burst to burst interval for bin3 radar */
+ uint32 max_burst_intv_lp; /**< maximum burst to burst interval for bin3 radar */
+ int32 nskip_rst_lp; /**< number of skipped pulses before resetting lp buffer */
+ int32 max_pw_tol; /* maximum tolerance allowd in detected pulse width for radar detection */
+ uint16 feature_mask; /**< 16-bit mask to specify enabled features */
+ uint16 thresh0_sc; /**< Radar detection, thresh 0 */
+ uint16 thresh1_sc; /**< Radar detection, thresh 1 */
+} wl_radar_args_t;
+
+#define WL_RADAR_ARGS_VERSION 2
+
+typedef struct {
+ uint32 version; /**< version */
+ uint16 thresh0_20_lo; /**< Radar detection, thresh 0 (range 5250-5350MHz) for BW 20MHz */
+ uint16 thresh1_20_lo; /**< Radar detection, thresh 1 (range 5250-5350MHz) for BW 20MHz */
+ uint16 thresh0_40_lo; /**< Radar detection, thresh 0 (range 5250-5350MHz) for BW 40MHz */
+ uint16 thresh1_40_lo; /**< Radar detection, thresh 1 (range 5250-5350MHz) for BW 40MHz */
+ uint16 thresh0_80_lo; /**< Radar detection, thresh 0 (range 5250-5350MHz) for BW 80MHz */
+ uint16 thresh1_80_lo; /**< Radar detection, thresh 1 (range 5250-5350MHz) for BW 80MHz */
+ uint16 thresh0_20_hi; /**< Radar detection, thresh 0 (range 5470-5725MHz) for BW 20MHz */
+ uint16 thresh1_20_hi; /**< Radar detection, thresh 1 (range 5470-5725MHz) for BW 20MHz */
+ uint16 thresh0_40_hi; /**< Radar detection, thresh 0 (range 5470-5725MHz) for BW 40MHz */
+ uint16 thresh1_40_hi; /**< Radar detection, thresh 1 (range 5470-5725MHz) for BW 40MHz */
+ uint16 thresh0_80_hi; /**< Radar detection, thresh 0 (range 5470-5725MHz) for BW 80MHz */
+ uint16 thresh1_80_hi; /**< Radar detection, thresh 1 (range 5470-5725MHz) for BW 80MHz */
+ uint16 thresh0_160_lo; /**< Radar detection, thresh 0 (range 5250-5350MHz) for BW 160MHz */
+ uint16 thresh1_160_lo; /**< Radar detection, thresh 1 (range 5250-5350MHz) for BW 160MHz */
+ uint16 thresh0_160_hi; /**< Radar detection, thresh 0 (range 5470-5725MHz) for BW 160MHz */
+ uint16 thresh1_160_hi; /**< Radar detection, thresh 1 (range 5470-5725MHz) for BW 160MHz */
+} wl_radar_thr_t;
+
+typedef struct {
+ uint32 version; /* version */
+ uint16 thresh0_sc_20_lo;
+ uint16 thresh1_sc_20_lo;
+ uint16 thresh0_sc_40_lo;
+ uint16 thresh1_sc_40_lo;
+ uint16 thresh0_sc_80_lo;
+ uint16 thresh1_sc_80_lo;
+ uint16 thresh0_sc_20_hi;
+ uint16 thresh1_sc_20_hi;
+ uint16 thresh0_sc_40_hi;
+ uint16 thresh1_sc_40_hi;
+ uint16 thresh0_sc_80_hi;
+ uint16 thresh1_sc_80_hi;
+ uint16 fc_varth_sb;
+ uint16 fc_varth_bin5_sb;
+ uint16 notradar_enb;
+ uint16 max_notradar_lp;
+ uint16 max_notradar;
+ uint16 max_notradar_lp_sc;
+ uint16 max_notradar_sc;
+ uint16 highpow_war_enb;
+ uint16 highpow_sp_ratio; //unit is 0.5
+
+} wl_radar_thr2_t;
+
+#define WL_RADAR_THR_VERSION 2
+
+typedef struct {
+ uint32 ver;
+ uint32 len;
+ int32 rssi_th[3];
+ uint8 rssi_gain_80[4];
+ uint8 rssi_gain_160[4];
+} wl_dyn_switch_th_t;
+
+#define WL_PHY_DYN_SWITCH_TH_VERSION 1
+
+/** RSSI per antenna */
+typedef struct {
+ uint32 version; /**< version field */
+ uint32 count; /**< number of valid antenna rssi */
+ int8 rssi_ant[WL_RSSI_ANT_MAX]; /**< rssi per antenna */
+} wl_rssi_ant_t;
+
+/* SNR per antenna */
+typedef struct {
+ uint32 version; /* version field */
+ uint32 count; /* number of valid antenna snr */
+ int8 snr_ant[WL_RSSI_ANT_MAX]; /* snr per antenna */
+} wl_snr_ant_t;
+
+
+/** data structure used in 'dfs_status' wl interface, which is used to query dfs status */
+typedef struct {
+ uint32 state; /**< noted by WL_DFS_CACSTATE_XX. */
+ uint32 duration; /**< time spent in ms in state. */
+ /**
+ * as dfs enters ISM state, it removes the operational channel from quiet channel
+ * list and notes the channel in channel_cleared. set to 0 if no channel is cleared
+ */
+ chanspec_t chanspec_cleared;
+ /** chanspec cleared used to be a uint32, add another to uint16 to maintain size */
+ uint16 pad;
+} wl_dfs_status_t;
+
+typedef struct {
+ uint32 state; /* noted by WL_DFS_CACSTATE_XX */
+ uint32 duration; /* time spent in ms in state */
+ chanspec_t chanspec; /* chanspec of this core */
+ chanspec_t chanspec_last_cleared; /* chanspec last cleared for operation by scanning */
+ uint16 sub_type; /* currently just the index of the core or the respective PLL */
+ uint16 pad;
+} wl_dfs_sub_status_t;
+
+#define WL_DFS_STATUS_ALL_VERSION (1)
+typedef struct {
+ uint16 version; /* version field; current max version 1 */
+ uint16 num_sub_status;
+ wl_dfs_sub_status_t dfs_sub_status[1]; /* struct array of length num_sub_status */
+} wl_dfs_status_all_t;
+
+#define WL_DFS_AP_MOVE_VERSION (1)
+
+struct wl_dfs_ap_move_status_v1 {
+ int16 dfs_status; /* DFS scan status */
+ chanspec_t chanspec; /* New AP Chanspec */
+ wl_dfs_status_t cac_status; /* CAC status */
+};
+
+struct wl_dfs_ap_move_status_v2 {
+ int8 version; /* version field; current max version 1 */
+ int8 move_status; /* DFS move status */
+ chanspec_t chanspec; /* New AP Chanspec */
+ wl_dfs_status_all_t scan_status; /* status; see dfs_status_all for wl_dfs_status_all_t */
+};
+
+#define WL_DFS_AP_MOVE_ABORT -1 /* Abort any dfs_ap_move in progress immediately */
+#define WL_DFS_AP_MOVE_STUNT -2 /* Stunt move but continue background CSA if in progress */
+
+
+/** data structure used in 'radar_status' wl interface, which is use to query radar det status */
+typedef struct {
+ uint8 detected;
+ int32 count;
+ uint8 pretended;
+ uint32 radartype;
+ uint32 timenow;
+ uint32 timefromL;
+ int32 lp_csect_single;
+ int32 detected_pulse_index;
+ int32 nconsecq_pulses;
+ chanspec_t ch;
+ int32 pw[10];
+ int32 intv[10];
+ int32 fm[10];
+} wl_radar_status_t;
+
+#define NUM_PWRCTRL_RATES 12
+
+typedef struct {
+ uint8 txpwr_band_max[NUM_PWRCTRL_RATES]; /**< User set target */
+ uint8 txpwr_limit[NUM_PWRCTRL_RATES]; /**< reg and local power limit */
+ uint8 txpwr_local_max; /**< local max according to the AP */
+ uint8 txpwr_local_constraint; /**< local constraint according to the AP */
+ uint8 txpwr_chan_reg_max; /**< Regulatory max for this channel */
+ uint8 txpwr_target[2][NUM_PWRCTRL_RATES]; /**< Latest target for 2.4 and 5 Ghz */
+ uint8 txpwr_est_Pout[2]; /**< Latest estimate for 2.4 and 5 Ghz */
+ uint8 txpwr_opo[NUM_PWRCTRL_RATES]; /**< On G phy, OFDM power offset */
+ uint8 txpwr_bphy_cck_max[NUM_PWRCTRL_RATES]; /**< Max CCK power for this band (SROM) */
+ uint8 txpwr_bphy_ofdm_max; /**< Max OFDM power for this band (SROM) */
+ uint8 txpwr_aphy_max[NUM_PWRCTRL_RATES]; /**< Max power for A band (SROM) */
+ int8 txpwr_antgain[2]; /**< Ant gain for each band - from SROM */
+ uint8 txpwr_est_Pout_gofdm; /**< Pwr estimate for 2.4 OFDM */
+} tx_power_legacy_t;
+
+#define WL_TX_POWER_RATES_LEGACY 45
+#define WL_TX_POWER_MCS20_FIRST 12
+#define WL_TX_POWER_MCS20_NUM 16
+#define WL_TX_POWER_MCS40_FIRST 28
+#define WL_TX_POWER_MCS40_NUM 17
+
+typedef struct {
+ uint32 flags;
+ chanspec_t chanspec; /**< txpwr report for this channel */
+ chanspec_t local_chanspec; /**< channel on which we are associated */
+ uint8 local_max; /**< local max according to the AP */
+ uint8 local_constraint; /**< local constraint according to the AP */
+ int8 antgain[2]; /**< Ant gain for each band - from SROM */
+ uint8 rf_cores; /**< count of RF Cores being reported */
+ uint8 est_Pout[4]; /**< Latest tx power out estimate per RF
+ * chain without adjustment
+ */
+ uint8 est_Pout_cck; /**< Latest CCK tx power out estimate */
+ uint8 user_limit[WL_TX_POWER_RATES_LEGACY]; /**< User limit */
+ uint8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /**< Regulatory power limit */
+ uint8 board_limit[WL_TX_POWER_RATES_LEGACY]; /**< Max power board can support (SROM) */
+ uint8 target[WL_TX_POWER_RATES_LEGACY]; /**< Latest target power */
+} tx_power_legacy2_t;
+
+#define WL_NUM_2x2_ELEMENTS 4
+#define WL_NUM_3x3_ELEMENTS 6
+#define WL_NUM_4x4_ELEMENTS 10
+
+typedef struct {
+ uint16 ver; /**< version of this struct */
+ uint16 len; /**< length in bytes of this structure */
+ uint32 flags;
+ chanspec_t chanspec; /**< txpwr report for this channel */
+ chanspec_t local_chanspec; /**< channel on which we are associated */
+ uint32 buflen; /**< ppr buffer length */
+ uint8 pprbuf[1]; /**< Latest target power buffer */
+} wl_txppr_t;
+
+#define WL_TXPPR_VERSION 1
+#define WL_TXPPR_LENGTH (sizeof(wl_txppr_t))
+#define TX_POWER_T_VERSION 45
+/** number of ppr serialization buffers, it should be reg, board and target */
+#define WL_TXPPR_SER_BUF_NUM (3)
+
+typedef struct chanspec_txpwr_max {
+ chanspec_t chanspec; /**< chanspec */
+ uint8 txpwr_max; /**< max txpwr in all the rates */
+ uint8 padding;
+} chanspec_txpwr_max_t;
+
+typedef struct wl_chanspec_txpwr_max {
+ uint16 ver; /**< version of this struct */
+ uint16 len; /**< length in bytes of this structure */
+ uint32 count; /**< number of elements of (chanspec, txpwr_max) pair */
+ chanspec_txpwr_max_t txpwr[1]; /**< array of (chanspec, max_txpwr) pair */
+} wl_chanspec_txpwr_max_t;
+
+#define WL_CHANSPEC_TXPWR_MAX_VER 1
+#define WL_CHANSPEC_TXPWR_MAX_LEN (sizeof(wl_chanspec_txpwr_max_t))
+
+typedef struct tx_inst_power {
+ uint8 txpwr_est_Pout[2]; /**< Latest estimate for 2.4 and 5 Ghz */
+ uint8 txpwr_est_Pout_gofdm; /**< Pwr estimate for 2.4 OFDM */
+} tx_inst_power_t;
+
+#define WL_NUM_TXCHAIN_MAX 4
+typedef struct wl_txchain_pwr_offsets {
+ int8 offset[WL_NUM_TXCHAIN_MAX]; /**< quarter dBm signed offset for each chain */
+} wl_txchain_pwr_offsets_t;
+
+/** maximum channels returned by the get valid channels iovar */
+#define WL_NUMCHANNELS 64
+#define WL_NUMCHANNELS_MANY_CHAN 10
+#define WL_ITER_LIMIT_MANY_CHAN 5
+
+#define WL_MIMO_PS_CFG_VERSION_1 1
+
+typedef struct wl_mimops_cfg {
+ uint8 version;
+ /* active_chains: 0 for all, 1 for 1 chain. */
+ uint8 active_chains;
+ /* static (0) or dynamic (1).or disabled (3) Mode applies only when active_chains = 0. */
+ uint8 mode;
+ /* bandwidth = Full (0), 20M (1), 40M (2), 80M (3). */
+ uint8 bandwidth;
+ uint8 applychangesafterlearning;
+ uint8 pad[3];
+} wl_mimops_cfg_t;
+
+/* This event is for tracing MIMO PS metrics snapshot calls.
+ * It is helpful to debug out-of-sync issue between
+ * ucode SHM values and FW snapshot calculation.
+ * It is part of the EVENT_LOG_TAG_MIMO_PS_TRACE.
+ */
+#define WL_MIMO_PS_METRICS_SNAPSHOT_TRACE_TYPE 0
+typedef struct wl_mimo_ps_metrics_snapshot_trace {
+ /* type field for this TLV: */
+ uint16 type;
+ /* length field for this TLV */
+ uint16 len;
+ uint32 idle_slotcnt_mimo; /* MIMO idle slotcnt raw SHM value */
+ uint32 last_idle_slotcnt_mimo; /* stored value snapshot */
+ uint32 idle_slotcnt_siso; /* SISO idle slotcnt raw SHM value */
+ uint32 last_idle_slotcnt_siso; /* stored value snapshot */
+ uint32 rx_time_mimo; /* Rx MIMO raw SHM value */
+ uint32 last_rx_time_mimo; /* stored value snapshot */
+ uint32 rx_time_siso; /* RX SISO raw SHM value */
+ uint32 last_rx_time_siso; /* stored value snapshot */
+ uint32 tx_time_1chain; /* Tx 1-chain raw SHM value */
+ uint32 last_tx_time_1chain; /* stored value snapshot */
+ uint32 tx_time_2chain; /* Tx 2-chain raw SHM value */
+ uint32 last_tx_time_2chain; /* stored value snapshot */
+ uint32 tx_time_3chain; /* Tx 3-chain raw SHM value */
+ uint32 last_tx_time_3chain; /* stored value snapshot */
+ uint16 reason; /* reason for snapshot call, see below */
+ /* Does the call reset last values after delta calculation */
+ uint16 reset_last;
+} wl_mimo_ps_metrics_snapshot_trace_t;
+/* reason codes for mimo ps metrics snapshot function calls */
+#define WL_MIMOPS_METRICS_SNAPSHOT_REPORT 1
+#define WL_MIMOPS_METRICS_SNAPSHOT_RXCHAIN_SET 2
+#define WL_MIMOPS_METRICS_SNAPSHOT_ARBI 3
+#define WL_MIMOPS_METRICS_SNAPSHOT_SLOTUPD 4
+#define WL_MIMOPS_METRICS_SNAPSHOT_PMBCNRX 5
+#define WL_MIMOPS_METRICS_SNAPSHOT_BMACINIT 6
+#define WL_MIMOPS_METRICS_SNAPSHOT_HT_COMPLETE 7
+#define WL_MIMOPS_METRICS_SNAPSHOT_OCL 8
+
+#define WL_MIMO_PS_STATUS_VERSION_2 2
+typedef struct wl_mimo_ps_status {
+ uint8 version;
+ uint8 ap_cap; /* The associated AP's capability (BW, MIMO/SISO). */
+ uint8 association_status; /* How we are associated to the AP (MIMO/SISO). */
+ uint8 mimo_ps_state; /* mimo_ps_cfg states: [0-5]. See below for values */
+ uint8 mrc_state; /* MRC state: NONE (0), ACTIVE(1) */
+ uint8 bss_rxchain; /* bss rxchain bitmask */
+ uint8 bss_txchain; /* bss txchain bitmask */
+ uint8 bss_bw; /* bandwidth: Full (0), 20M (1), 40M (2), 80M (3), etc */
+ uint16 hw_state; /* bitmask of hw state. See below for values */
+ uint8 hw_rxchain; /* actual HW rxchain bitmask */
+ uint8 hw_txchain; /* actual HW txchain bitmask */
+ uint8 hw_bw; /* bandwidth: Full (0), 20M (1), 40M (2), 80M (3), etc */
+ uint8 pm_bcnrx_state; /* actual state of ucode flag */
+ uint8 basic_rates_present; /* internal flag to trigger siso bcmc rx */
+ uint8 siso_bcmc_rx_state; /* actual state of ucode flag */
+} wl_mimo_ps_status_t;
+
+#define WL_MIMO_PS_STATUS_VERSION_1 1
+typedef struct wl_mimo_ps_status_v1 {
+ uint8 version;
+ uint8 ap_cap; /* The associated AP's capability (BW, MIMO/SISO). */
+ uint8 association_status; /* How we are associated to the AP (MIMO/SISO). */
+ uint8 mimo_ps_state; /* mimo_ps_cfg states: [0-5]. See below for values */
+ uint8 mrc_state; /* MRC state: NONE (0), ACTIVE(1) */
+ uint8 bss_rxchain; /* bss rxchain bitmask */
+ uint8 bss_txchain; /* bss txchain bitmask */
+ uint8 bss_bw; /* bandwidth: Full (0), 20M (1), 40M (2), 80M (3), etc */
+ uint16 hw_state; /* bitmask of hw state. See below for values */
+ uint8 hw_rxchain; /* actual HW rxchain bitmask */
+ uint8 hw_txchain; /* actual HW txchain bitmask */
+ uint8 hw_bw; /* bandwidth: Full (0), 20M (1), 40M (2), 80M (3), etc */
+ uint8 pad[3];
+} wl_mimo_ps_status_v1_t;
+
+#define WL_MIMO_PS_STATUS_AP_CAP(ap_cap) (ap_cap & 0x0F)
+#define WL_MIMO_PS_STATUS_AP_CAP_BW(ap_cap) (ap_cap >> 4)
+#define WL_MIMO_PS_STATUS_ASSOC_BW_SHIFT 4
+
+/* version 3: assoc status: low nibble is status enum, high other flags */
+#define WL_MIMO_PS_STATUS_VERSION_3 3
+#define WL_MIMO_PS_STATUS_ASSOC_STATUS_MASK 0x0F
+#define WL_MIMO_PS_STATUS_ASSOC_STATUS_VHT_WITHOUT_OMN 0x80
+
+/* mimo_ps_status: ap_cap/association status */
+enum {
+ WL_MIMO_PS_STATUS_ASSOC_NONE = 0,
+ WL_MIMO_PS_STATUS_ASSOC_SISO = 1,
+ WL_MIMO_PS_STATUS_ASSOC_MIMO = 2,
+ WL_MIMO_PS_STATUS_ASSOC_LEGACY = 3
+};
+
+/* mimo_ps_status: mimo_ps_cfg states */
+enum {
+ WL_MIMO_PS_CFG_STATE_NONE = 0,
+ WL_MIMO_PS_CFG_STATE_INFORM_AP_INPROGRESS = 1,
+ WL_MIMO_PS_CFG_STATE_INFORM_AP_DONE = 2,
+ WL_MIMO_PS_CFG_STATE_LEARNING = 3,
+ WL_MIMO_PS_CFG_STATE_HW_CONFIGURE = 4,
+ WL_MIMO_PS_CFG_STATE_INFORM_AP_PENDING = 5
+};
+
+/* mimo_ps_status: hw_state values */
+#define WL_MIMO_PS_STATUS_HW_STATE_NONE 0
+#define WL_MIMO_PS_STATUS_HW_STATE_LTECOEX (0x1 << 0)
+#define WL_MIMO_PS_STATUS_HW_STATE_MIMOPS_BSS (0x1 << 1)
+#define WL_MIMO_PS_STATUS_HW_STATE_AWDL_BSS (0x1 << 2)
+#define WL_MIMO_PS_STATUS_HW_STATE_SCAN (0x1 << 3)
+#define WL_MIMO_PS_STATUS_HW_STATE_TXPPR (0x1 << 4)
+#define WL_MIMO_PS_STATUS_HW_STATE_PWRTHOTTLE (0x1 << 5)
+#define WL_MIMO_PS_STATUS_HW_STATE_TMPSENSE (0x1 << 6)
+#define WL_MIMO_PS_STATUS_HW_STATE_IOVAR (0x1 << 7)
+#define WL_MIMO_PS_STATUS_HW_STATE_AP_BSS (0x1 << 8)
+
+/* mimo_ps_status: mrc states */
+#define WL_MIMO_PS_STATUS_MRC_NONE 0
+#define WL_MIMO_PS_STATUS_MRC_ACTIVE 1
+
+/* mimo_ps_status: core flag states for single-core beacon and siso-bcmc rx */
+#define WL_MIMO_PS_STATUS_MHF_FLAG_NONE 0
+#define WL_MIMO_PS_STATUS_MHF_FLAG_ACTIVE 1
+#define WL_MIMO_PS_STATUS_MHF_FLAG_COREDOWN 2
+#define WL_MIMO_PS_STATUS_MHF_FLAG_INVALID 3
+
+/* Type values for the REASON */
+#define WL_MIMO_PS_PS_LEARNING_ABORTED (1 << 0)
+#define WL_MIMO_PS_PS_LEARNING_COMPLETED (1 << 1)
+#define WL_MIMO_PS_PS_LEARNING_ONGOING (1 << 2)
+
+typedef struct wl_mimo_ps_learning_event_data {
+ uint32 startTimeStamp;
+ uint32 endTimeStamp;
+ uint16 reason;
+ struct ether_addr BSSID;
+ uint32 totalSISO_below_rssi_threshold;
+ uint32 totalMIMO_below_rssi_threshold;
+ uint32 totalSISO_above_rssi_threshold;
+ uint32 totalMIMO_above_rssi_threshold;
+} wl_mimo_ps_learning_event_data_t;
+
+#define WL_MIMO_PS_PS_LEARNING_CFG_ABORT (1 << 0)
+#define WL_MIMO_PS_PS_LEARNING_CFG_STATUS (1 << 1)
+#define WL_MIMO_PS_PS_LEARNING_CFG_CONFIG (1 << 2)
+
+#define WL_MIMO_PS_PS_LEARNING_CFG_V1 1
+
+typedef struct wl_mimops_learning_cfg {
+ /* flag: bit 0 for abort */
+ /* flag: bit 1 for status */
+ /* flag: bit 2 for configuring no of packets and rssi */
+ uint8 flag;
+ /* mimo ps learning version, compatible version is 0 */
+ uint8 version;
+ /* if version is 0 or rssi is 0, ignored */
+ int8 learning_rssi_threshold;
+ uint8 reserved;
+ uint32 no_of_packets_for_learning;
+ wl_mimo_ps_learning_event_data_t mimops_learning_data;
+} wl_mimops_learning_cfg_t;
+
+
+#define WL_OCL_STATUS_VERSION 1
+typedef struct ocl_status_info {
+ uint8 version;
+ uint8 len;
+ uint16 fw_status; /* Bits representing FW disable reasons */
+ uint8 hw_status; /* Bits for actual HW config and SISO/MIMO coremask */
+ uint8 coremask; /* The ocl core mask (indicating listening core) */
+} ocl_status_info_t;
+
+/* MWS OCL map */
+#define WL_MWS_OCL_OVERRIDE_VERSION 1
+typedef struct wl_mws_ocl_override {
+ uint16 version; /* Structure version */
+ uint16 bitmap_2g; /* bitmap for 2.4G channels bits 1-13 */
+ uint16 bitmap_5g_lo; /* bitmap for 5G low channels by 2:
+ *34-48, 52-56, 60-64, 100-102
+ */
+ uint16 bitmap_5g_mid; /* bitmap for 5G mid channels by 2:
+ * 104, 108-112, 116-120, 124-128,
+ * 132-136, 140, 149-151
+ */
+ uint16 bitmap_5g_high; /* bitmap for 5G high channels by 2
+ * 153, 157-161, 165
+ */
+} wl_mws_ocl_override_t;
+
+/* Bits for fw_status */
+#define OCL_DISABLED_HOST 0x01 /* Host has disabled through ocl_enable */
+#define OCL_DISABLED_RSSI 0x02 /* Disabled because of ocl_rssi_threshold */
+#define OCL_DISABLED_LTEC 0x04 /* Disabled due to LTE Coex activity */
+#define OCL_DISABLED_SISO 0x08 /* Disabled while in SISO mode */
+#define OCL_DISABLED_CAL 0x10 /* Disabled during active calibration */
+#define OCL_DISABLED_CHANSWITCH 0x20 /* Disabled during active channel switch */
+#define OCL_DISABLED_ASPEND 0x40 /* Disabled due to assoc pending */
+
+/* Bits for hw_status */
+#define OCL_HWCFG 0x01 /* State of OCL config bit in phy HW */
+#define OCL_HWMIMO 0x02 /* Set if current coremask is > 1 bit */
+#define OCL_COREDOWN 0x80 /* Set if core is currently down */
+
+
+/*
+ * Join preference iovar value is an array of tuples. Each tuple has a one-byte type,
+ * a one-byte length, and a variable length value. RSSI type tuple must be present
+ * in the array.
+ *
+ * Types are defined in "join preference types" section.
+ *
+ * Length is the value size in octets. It is reserved for WL_JOIN_PREF_WPA type tuple
+ * and must be set to zero.
+ *
+ * Values are defined below.
+ *
+ * 1. RSSI - 2 octets
+ * offset 0: reserved
+ * offset 1: reserved
+ *
+ * 2. WPA - 2 + 12 * n octets (n is # tuples defined below)
+ * offset 0: reserved
+ * offset 1: # of tuples
+ * offset 2: tuple 1
+ * offset 14: tuple 2
+ * ...
+ * offset 2 + 12 * (n - 1) octets: tuple n
+ *
+ * struct wpa_cfg_tuple {
+ * uint8 akm[DOT11_OUI_LEN+1]; akm suite
+ * uint8 ucipher[DOT11_OUI_LEN+1]; unicast cipher suite
+ * uint8 mcipher[DOT11_OUI_LEN+1]; multicast cipher suite
+ * };
+ *
+ * multicast cipher suite can be specified as a specific cipher suite or WL_WPA_ACP_MCS_ANY.
+ *
+ * 3. BAND - 2 octets
+ * offset 0: reserved
+ * offset 1: see "band preference" and "band types"
+ *
+ * 4. BAND RSSI - 2 octets
+ * offset 0: band types
+ * offset 1: +ve RSSI boost value in dB
+ */
+
+struct tsinfo_arg {
+ uint8 octets[3];
+};
+
+#define RATE_CCK_1MBPS 0
+#define RATE_CCK_2MBPS 1
+#define RATE_CCK_5_5MBPS 2
+#define RATE_CCK_11MBPS 3
+
+#define RATE_LEGACY_OFDM_6MBPS 0
+#define RATE_LEGACY_OFDM_9MBPS 1
+#define RATE_LEGACY_OFDM_12MBPS 2
+#define RATE_LEGACY_OFDM_18MBPS 3
+#define RATE_LEGACY_OFDM_24MBPS 4
+#define RATE_LEGACY_OFDM_36MBPS 5
+#define RATE_LEGACY_OFDM_48MBPS 6
+#define RATE_LEGACY_OFDM_54MBPS 7
+
+#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION 1
+
+typedef struct wl_bsstrans_rssi {
+ int8 rssi_2g; /**< RSSI in dbm for 2.4 G */
+ int8 rssi_5g; /**< RSSI in dbm for 5G, unused for cck */
+} wl_bsstrans_rssi_t;
+
+#define RSSI_RATE_MAP_MAX_STREAMS 4 /**< max streams supported */
+
+/** RSSI to rate mapping, all 20Mhz, no SGI */
+typedef struct wl_bsstrans_rssi_rate_map {
+ uint16 ver;
+ uint16 len; /**< length of entire structure */
+ wl_bsstrans_rssi_t cck[WL_NUM_RATES_CCK]; /**< 2.4G only */
+ wl_bsstrans_rssi_t ofdm[WL_NUM_RATES_OFDM]; /**< 6 to 54mbps */
+ wl_bsstrans_rssi_t phy_n[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_MCS_1STREAM]; /* MCS0-7 */
+ wl_bsstrans_rssi_t phy_ac[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_VHT]; /**< MCS0-9 */
+} wl_bsstrans_rssi_rate_map_t;
+
+#define WL_BSSTRANS_ROAMTHROTTLE_VERSION 1
+
+/** Configure number of scans allowed per throttle period */
+typedef struct wl_bsstrans_roamthrottle {
+ uint16 ver;
+ uint16 period;
+ uint16 scans_allowed;
+} wl_bsstrans_roamthrottle_t;
+
+#define NFIFO 6 /**< # tx/rx fifopairs */
+
+#if defined(BCM_DMA_CT) && !defined(BCM_DMA_CT_DISABLED)
+#define NFIFO_EXT 32 /* 6 traditional FIFOs + 2 rsvd + 24 MU FIFOs */
+#elif defined(WL11AX) && defined(WL11AX_TRIGGERQ_ENABLED)
+#define NFIFO_EXT 10
+#else
+#define NFIFO_EXT NFIFO
+#endif
+
+/* Reinit reason codes */
+enum {
+ WL_REINIT_RC_NONE = 0,
+ WL_REINIT_RC_PS_SYNC = 1,
+ WL_REINIT_RC_PSM_WD = 2,
+ WL_REINIT_RC_MAC_WAKE = 3,
+ WL_REINIT_RC_MAC_SUSPEND = 4,
+ WL_REINIT_RC_MAC_SPIN_WAIT = 5,
+ WL_REINIT_RC_AXI_BUS_ERROR = 6,
+ WL_REINIT_RC_DEVICE_REMOVED = 7,
+ WL_REINIT_RC_PCIE_FATAL_ERROR = 8,
+ WL_REINIT_RC_OL_FW_TRAP = 9,
+ WL_REINIT_RC_FIFO_ERR = 10,
+ WL_REINIT_RC_INV_TX_STATUS = 11,
+ WL_REINIT_RC_MQ_ERROR = 12,
+ WL_REINIT_RC_PHYTXERR_THRESH = 13,
+ WL_REINIT_RC_USER_FORCED = 14,
+ WL_REINIT_RC_FULL_RESET = 15,
+ WL_REINIT_RC_AP_BEACON = 16,
+ WL_REINIT_RC_PM_EXCESSED = 17,
+ WL_REINIT_RC_NO_CLK = 18,
+ WL_REINIT_RC_SW_ASSERT = 19,
+ WL_REINIT_RC_PSM_JMP0 = 20,
+ WL_REINIT_RC_PSM_RUN = 21,
+ WL_REINIT_RC_ENABLE_MAC = 22,
+ WL_REINIT_RC_SCAN_TIMEOUT = 23,
+ WL_REINIT_RC_JOIN_TIMEOUT = 24,
+ /* Below error codes are generated during D3 exit validation */
+ WL_REINIT_RC_LINK_NOT_ACTIVE = 25,
+ WL_REINIT_RC_PCI_CFG_RD_FAIL = 26,
+ WL_REINIT_RC_INV_VEN_ID = 27,
+ WL_REINIT_RC_INV_DEV_ID = 28,
+ WL_REINIT_RC_INV_BAR0 = 29,
+ WL_REINIT_RC_INV_BAR2 = 30,
+ WL_REINIT_RC_AER_UC_FATAL = 31,
+ WL_REINIT_RC_AER_UC_NON_FATAL = 32,
+ WL_REINIT_RC_AER_CORR = 33,
+ WL_REINIT_RC_AER_DEV_STS = 34,
+ WL_REINIT_RC_PCIe_STS = 35,
+ WL_REINIT_RC_MMIO_RD_FAIL = 36,
+ WL_REINIT_RC_MMIO_RD_INVAL = 37,
+ WL_REINIT_RC_MMIO_ARM_MEM_RD_FAIL = 38,
+ WL_REINIT_RC_MMIO_ARM_MEM_INVAL = 39,
+ WL_REINIT_RC_SROM_LOAD_FAILED = 40,
+ WL_REINIT_RC_PHY_CRASH = 41,
+ WL_REINIT_TX_STALL = 42,
+ WL_REINIT_RC_TX_FLOW_CONTROL_BLOCKED = 43,
+ WL_REINIT_RC_RX_HC_FAIL = 44,
+ WL_REINIT_RC_RX_DMA_STALL = 45,
+ WL_REINIT_UTRACE_BUF_OVERLAP_SR = 46,
+ WL_REINIT_UTRACE_TPL_OUT_BOUNDS = 47,
+ WL_REINIT_UTRACE_TPL_OSET_STRT0 = 48,
+ WL_REINIT_RC_PHYTXERR = 49,
+ WL_REINIT_RC_PSM_FATAL_SUSP = 50,
+ WL_REINIT_RC_TX_FIFO_SUSP = 51,
+ WL_REINIT_RC_MAC_ENABLE = 52,
+ WL_REINIT_RC_LAST /* This must be the last entry */
+};
+
+#define NREINITREASONCOUNT 8
+
+#define REINITRSNIDX(_x) (((_x) < WL_REINIT_RC_LAST) ? (_x) : 0)
+
+#define WL_CNT_T_VERSION 30 /**< current version of wl_cnt_t struct */
+#define WL_CNT_VERSION_6 6
+#define WL_CNT_VERSION_7 7
+/* version 7001 wl_cnt_t is same as version 7 with exception of phywatchdog is
+ * replaced with rxbcnlossmbss */
+#define WL_CNT_VERSION_7001 7001 /* version 7001 of wl_cnt_t struct */
+#define WL_CNT_VERSION_11 11
+#define WL_CNT_VERSION_XTLV 30
+
+#define WL_COUNTERS_IOV_VERSION_1 1
+#define WL_SUBCNTR_IOV_VER WL_COUNTERS_IOV_VERSION_1
+/* First two uint16 are version and lenght fields. So offset of the first counter will be 4 */
+#define FIRST_COUNTER_OFFSET 0x04
+
+#define WLC_WITH_XTLV_CNT
+
+/**
+ * tlv IDs uniquely identifies counter component
+ * packed into wl_cmd_t container
+ */
+enum wl_cnt_xtlv_id {
+ WL_CNT_XTLV_WLC = 0x100, /**< WLC layer counters */
+ WL_CNT_XTLV_WLC_RINIT_RSN = 0x101, /**< WLC layer reinitreason extension */
+ WL_CNT_XTLV_CNTV_LE10_UCODE = 0x200, /**< wl counter ver < 11 UCODE MACSTAT */
+ WL_CNT_XTLV_LT40_UCODE_V1 = 0x300, /**< corerev < 40 UCODE MACSTAT */
+ WL_CNT_XTLV_GE40_UCODE_V1 = 0x400, /**< corerev >= 40 UCODE MACSTAT */
+ WL_CNT_XTLV_GE64_UCODEX_V1 = 0x800 /* corerev >= 64 UCODEX MACSTAT */
+};
+
+/**
+ * The number of variables in wl macstat cnt struct.
+ * (wl_cnt_ge40mcst_v1_t, wl_cnt_lt40mcst_v1_t, wl_cnt_v_le10_mcst_t)
+ */
+#define WL_CNT_MCST_VAR_NUM 64
+/* sizeof(wl_cnt_ge40mcst_v1_t), sizeof(wl_cnt_lt40mcst_v1_t), and sizeof(wl_cnt_v_le10_mcst_t) */
+#define WL_CNT_MCST_STRUCT_SZ ((uint32)sizeof(uint32) * WL_CNT_MCST_VAR_NUM)
+
+#define WL_CNT_MCXST_STRUCT_SZ ((uint32)sizeof(wl_cnt_ge64mcxst_v1_t))
+#define INVALID_CNT_VAL (uint32)(-1)
+
+#define WL_XTLV_CNTBUF_MAX_SIZE ((uint32)(OFFSETOF(wl_cnt_info_t, data)) + \
+ (uint32)BCM_XTLV_HDR_SIZE + (uint32)sizeof(wl_cnt_wlc_t) + \
+ (uint32)BCM_XTLV_HDR_SIZE + WL_CNT_MCST_STRUCT_SZ + \
+ (uint32)BCM_XTLV_HDR_SIZE + WL_CNT_MCXST_STRUCT_SZ)
+
+#define WL_CNTBUF_MAX_SIZE MAX(WL_XTLV_CNTBUF_MAX_SIZE, (uint32)sizeof(wl_cnt_ver_11_t))
+
+
+/** Top structure of counters IOVar buffer */
+typedef struct {
+ uint16 version; /**< see definition of WL_CNT_T_VERSION */
+ uint16 datalen; /**< length of data including all paddings. */
+ uint8 data [1]; /**< variable length payload:
+ * 1 or more bcm_xtlv_t type of tuples.
+ * each tuple is padded to multiple of 4 bytes.
+ * 'datalen' field of this structure includes all paddings.
+ */
+} wl_cnt_info_t;
+
+/* Top structure of subcounters IOVar buffer
+ * Whenever we make any change in this structure
+ * WL_SUBCNTR_IOV_VER should be updated accordingly
+ * The structure definition should remain consistant b/w
+ * FW and wl/WLM app.
+ */
+typedef struct {
+ uint16 version; /* Version of IOVAR structure. Used for backward
+ * compatibility in future. Whenever we make any
+ * changes to this structure then value of WL_SUBCNTR_IOV_VER
+ * needs to be updated properly.
+ */
+ uint16 length; /* length in bytes of this structure */
+ uint16 counters_version; /* see definition of WL_CNT_T_VERSION
+ * wl app will send the version of counters
+ * which is used to calculate the offset of counters.
+ * It must match the version of counters FW is using
+ * else FW will return error with his version of counters
+ * set in this field.
+ */
+ uint16 num_subcounters; /* Number of counter offset passed by wl app to FW. */
+ uint32 data[1]; /* variable length payload:
+ * Offsets to the counters will be passed to FW
+ * throught this data field. FW will return the value of counters
+ * at the offsets passed by wl app in this fiels itself.
+ */
+} wl_subcnt_info_t;
+
+/** wlc layer counters */
+typedef struct {
+ /* transmit stat counters */
+ uint32 txframe; /**< tx data frames */
+ uint32 txbyte; /**< tx data bytes */
+ uint32 txretrans; /**< tx mac retransmits */
+ uint32 txerror; /**< tx data errors (derived: sum of others) */
+ uint32 txctl; /**< tx management frames */
+ uint32 txprshort; /**< tx short preamble frames */
+ uint32 txserr; /**< tx status errors */
+ uint32 txnobuf; /**< tx out of buffers errors */
+ uint32 txnoassoc; /**< tx discard because we're not associated */
+ uint32 txrunt; /**< tx runt frames */
+ uint32 txchit; /**< tx header cache hit (fastpath) */
+ uint32 txcmiss; /**< tx header cache miss (slowpath) */
+
+ /* transmit chip error counters */
+ uint32 txuflo; /**< tx fifo underflows */
+ uint32 txphyerr; /**< tx phy errors (indicated in tx status) */
+ uint32 txphycrs;
+
+ /* receive stat counters */
+ uint32 rxframe; /**< rx data frames */
+ uint32 rxbyte; /**< rx data bytes */
+ uint32 rxerror; /**< rx data errors (derived: sum of others) */
+ uint32 rxctl; /**< rx management frames */
+ uint32 rxnobuf; /**< rx out of buffers errors */
+ uint32 rxnondata; /**< rx non data frames in the data channel errors */
+ uint32 rxbadds; /**< rx bad DS errors */
+ uint32 rxbadcm; /**< rx bad control or management frames */
+ uint32 rxfragerr; /**< rx fragmentation errors */
+ uint32 rxrunt; /**< rx runt frames */
+ uint32 rxgiant; /**< rx giant frames */
+ uint32 rxnoscb; /**< rx no scb error */
+ uint32 rxbadproto; /**< rx invalid frames */
+ uint32 rxbadsrcmac; /**< rx frames with Invalid Src Mac */
+ uint32 rxbadda; /**< rx frames tossed for invalid da */
+ uint32 rxfilter; /**< rx frames filtered out */
+
+ /* receive chip error counters */
+ uint32 rxoflo; /**< rx fifo overflow errors */
+ uint32 rxuflo[NFIFO]; /**< rx dma descriptor underflow errors */
+
+ uint32 d11cnt_txrts_off; /**< d11cnt txrts value when reset d11cnt */
+ uint32 d11cnt_rxcrc_off; /**< d11cnt rxcrc value when reset d11cnt */
+ uint32 d11cnt_txnocts_off; /**< d11cnt txnocts value when reset d11cnt */
+
+ /* misc counters */
+ uint32 dmade; /**< tx/rx dma descriptor errors */
+ uint32 dmada; /**< tx/rx dma data errors */
+ uint32 dmape; /**< tx/rx dma descriptor protocol errors */
+ uint32 reset; /**< reset count */
+ uint32 tbtt; /**< cnts the TBTT int's */
+ uint32 txdmawar;
+ uint32 pkt_callback_reg_fail; /**< callbacks register failure */
+
+ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */
+ uint32 txfrag; /**< dot11TransmittedFragmentCount */
+ uint32 txmulti; /**< dot11MulticastTransmittedFrameCount */
+ uint32 txfail; /**< dot11FailedCount */
+ uint32 txretry; /**< dot11RetryCount */
+ uint32 txretrie; /**< dot11MultipleRetryCount */
+ uint32 rxdup; /**< dot11FrameduplicateCount */
+ uint32 txrts; /**< dot11RTSSuccessCount */
+ uint32 txnocts; /**< dot11RTSFailureCount */
+ uint32 txnoack; /**< dot11ACKFailureCount */
+ uint32 rxfrag; /**< dot11ReceivedFragmentCount */
+ uint32 rxmulti; /**< dot11MulticastReceivedFrameCount */
+ uint32 rxcrc; /**< dot11FCSErrorCount */
+ uint32 txfrmsnt; /**< dot11TransmittedFrameCount (bogus MIB?) */
+ uint32 rxundec; /**< dot11WEPUndecryptableCount */
+
+ /* WPA2 counters (see rxundec for DecryptFailureCount) */
+ uint32 tkipmicfaill; /**< TKIPLocalMICFailures */
+ uint32 tkipcntrmsr; /**< TKIPCounterMeasuresInvoked */
+ uint32 tkipreplay; /**< TKIPReplays */
+ uint32 ccmpfmterr; /**< CCMPFormatErrors */
+ uint32 ccmpreplay; /**< CCMPReplays */
+ uint32 ccmpundec; /**< CCMPDecryptErrors */
+ uint32 fourwayfail; /**< FourWayHandshakeFailures */
+ uint32 wepundec; /**< dot11WEPUndecryptableCount */
+ uint32 wepicverr; /**< dot11WEPICVErrorCount */
+ uint32 decsuccess; /**< DecryptSuccessCount */
+ uint32 tkipicverr; /**< TKIPICVErrorCount */
+ uint32 wepexcluded; /**< dot11WEPExcludedCount */
+
+ uint32 txchanrej; /**< Tx frames suppressed due to channel rejection */
+ uint32 psmwds; /**< Count PSM watchdogs */
+ uint32 phywatchdog; /**< Count Phy watchdogs (triggered by ucode) */
+
+ /* MBSS counters, AP only */
+ uint32 prq_entries_handled; /**< PRQ entries read in */
+ uint32 prq_undirected_entries; /**< which were bcast bss & ssid */
+ uint32 prq_bad_entries; /**< which could not be translated to info */
+ uint32 atim_suppress_count; /**< TX suppressions on ATIM fifo */
+ uint32 bcn_template_not_ready; /**< Template marked in use on send bcn ... */
+ uint32 bcn_template_not_ready_done; /**< ...but "DMA done" interrupt rcvd */
+ uint32 late_tbtt_dpc; /**< TBTT DPC did not happen in time */
+
+ /* per-rate receive stat counters */
+ uint32 rx1mbps; /**< packets rx at 1Mbps */
+ uint32 rx2mbps; /**< packets rx at 2Mbps */
+ uint32 rx5mbps5; /**< packets rx at 5.5Mbps */
+ uint32 rx6mbps; /**< packets rx at 6Mbps */
+ uint32 rx9mbps; /**< packets rx at 9Mbps */
+ uint32 rx11mbps; /**< packets rx at 11Mbps */
+ uint32 rx12mbps; /**< packets rx at 12Mbps */
+ uint32 rx18mbps; /**< packets rx at 18Mbps */
+ uint32 rx24mbps; /**< packets rx at 24Mbps */
+ uint32 rx36mbps; /**< packets rx at 36Mbps */
+ uint32 rx48mbps; /**< packets rx at 48Mbps */
+ uint32 rx54mbps; /**< packets rx at 54Mbps */
+ uint32 rx108mbps; /**< packets rx at 108mbps */
+ uint32 rx162mbps; /**< packets rx at 162mbps */
+ uint32 rx216mbps; /**< packets rx at 216 mbps */
+ uint32 rx270mbps; /**< packets rx at 270 mbps */
+ uint32 rx324mbps; /**< packets rx at 324 mbps */
+ uint32 rx378mbps; /**< packets rx at 378 mbps */
+ uint32 rx432mbps; /**< packets rx at 432 mbps */
+ uint32 rx486mbps; /**< packets rx at 486 mbps */
+ uint32 rx540mbps; /**< packets rx at 540 mbps */
+
+ uint32 rfdisable; /**< count of radio disables */
+
+ uint32 txexptime; /**< Tx frames suppressed due to timer expiration */
+
+ uint32 txmpdu_sgi; /**< count for sgi transmit */
+ uint32 rxmpdu_sgi; /**< count for sgi received */
+ uint32 txmpdu_stbc; /**< count for stbc transmit */
+ uint32 rxmpdu_stbc; /**< count for stbc received */
+
+ uint32 rxundec_mcst; /**< dot11WEPUndecryptableCount */
+
+ /* WPA2 counters (see rxundec for DecryptFailureCount) */
+ uint32 tkipmicfaill_mcst; /**< TKIPLocalMICFailures */
+ uint32 tkipcntrmsr_mcst; /**< TKIPCounterMeasuresInvoked */
+ uint32 tkipreplay_mcst; /**< TKIPReplays */
+ uint32 ccmpfmterr_mcst; /**< CCMPFormatErrors */
+ uint32 ccmpreplay_mcst; /**< CCMPReplays */
+ uint32 ccmpundec_mcst; /**< CCMPDecryptErrors */
+ uint32 fourwayfail_mcst; /**< FourWayHandshakeFailures */
+ uint32 wepundec_mcst; /**< dot11WEPUndecryptableCount */
+ uint32 wepicverr_mcst; /**< dot11WEPICVErrorCount */
+ uint32 decsuccess_mcst; /**< DecryptSuccessCount */
+ uint32 tkipicverr_mcst; /**< TKIPICVErrorCount */
+ uint32 wepexcluded_mcst; /**< dot11WEPExcludedCount */
+
+ uint32 dma_hang; /**< count for dma hang */
+ uint32 reinit; /**< count for reinit */
+
+ uint32 pstatxucast; /**< count of ucast frames xmitted on all psta assoc */
+ uint32 pstatxnoassoc; /**< count of txnoassoc frames xmitted on all psta assoc */
+ uint32 pstarxucast; /**< count of ucast frames received on all psta assoc */
+ uint32 pstarxbcmc; /**< count of bcmc frames received on all psta */
+ uint32 pstatxbcmc; /**< count of bcmc frames transmitted on all psta */
+
+ uint32 cso_passthrough; /**< hw cso required but passthrough */
+ uint32 cso_normal; /**< hw cso hdr for normal process */
+ uint32 chained; /**< number of frames chained */
+ uint32 chainedsz1; /**< number of chain size 1 frames */
+ uint32 unchained; /**< number of frames not chained */
+ uint32 maxchainsz; /**< max chain size so far */
+ uint32 currchainsz; /**< current chain size */
+ uint32 pciereset; /**< Secondary Bus Reset issued by driver */
+ uint32 cfgrestore; /**< configspace restore by driver */
+ uint32 reinitreason[NREINITREASONCOUNT]; /**< reinitreason counters; 0: Unknown reason */
+ uint32 rxrtry;
+ uint32 rxmpdu_mu; /**< Number of MU MPDUs received */
+
+ /* detailed control/management frames */
+ uint32 txbar; /**< Number of TX BAR */
+ uint32 rxbar; /**< Number of RX BAR */
+ uint32 txpspoll; /**< Number of TX PS-poll */
+ uint32 rxpspoll; /**< Number of RX PS-poll */
+ uint32 txnull; /**< Number of TX NULL_DATA */
+ uint32 rxnull; /**< Number of RX NULL_DATA */
+ uint32 txqosnull; /**< Number of TX NULL_QoSDATA */
+ uint32 rxqosnull; /**< Number of RX NULL_QoSDATA */
+ uint32 txassocreq; /**< Number of TX ASSOC request */
+ uint32 rxassocreq; /**< Number of RX ASSOC request */
+ uint32 txreassocreq; /**< Number of TX REASSOC request */
+ uint32 rxreassocreq; /**< Number of RX REASSOC request */
+ uint32 txdisassoc; /**< Number of TX DISASSOC */
+ uint32 rxdisassoc; /**< Number of RX DISASSOC */
+ uint32 txassocrsp; /**< Number of TX ASSOC response */
+ uint32 rxassocrsp; /**< Number of RX ASSOC response */
+ uint32 txreassocrsp; /**< Number of TX REASSOC response */
+ uint32 rxreassocrsp; /**< Number of RX REASSOC response */
+ uint32 txauth; /**< Number of TX AUTH */
+ uint32 rxauth; /**< Number of RX AUTH */
+ uint32 txdeauth; /**< Number of TX DEAUTH */
+ uint32 rxdeauth; /**< Number of RX DEAUTH */
+ uint32 txprobereq; /**< Number of TX probe request */
+ uint32 rxprobereq; /**< Number of RX probe request */
+ uint32 txprobersp; /**< Number of TX probe response */
+ uint32 rxprobersp; /**< Number of RX probe response */
+ uint32 txaction; /**< Number of TX action frame */
+ uint32 rxaction; /**< Number of RX action frame */
+ uint32 ampdu_wds; /**< Number of AMPDU watchdogs */
+ uint32 txlost; /**< Number of lost packets reported in txs */
+ uint32 txdatamcast; /**< Number of TX multicast data packets */
+ uint32 txdatabcast; /**< Number of TX broadcast data packets */
+ uint32 psmxwds; /**< Number of PSMx watchdogs */
+ uint32 rxback;
+ uint32 txback;
+ uint32 p2p_tbtt; /**< Number of P2P TBTT Events */
+ uint32 p2p_tbtt_miss; /**< Number of P2P TBTT Events Miss */
+ uint32 txqueue_start;
+ uint32 txqueue_end;
+} wl_cnt_wlc_t;
+
+/* Reinit reasons - do not put anything else other than reinit reasons here */
+typedef struct {
+ uint32 rsn[WL_REINIT_RC_LAST];
+} reinit_rsns_t;
+
+/* MACXSTAT counters for ucodex (corerev >= 64) */
+typedef struct {
+ uint32 macxsusp;
+ uint32 m2vmsg;
+ uint32 v2mmsg;
+ uint32 mboxout;
+ uint32 musnd;
+ uint32 sfb2v;
+} wl_cnt_ge64mcxst_v1_t;
+
+/** MACSTAT counters for ucode (corerev >= 40) */
+typedef struct {
+ /* MAC counters: 32-bit version of d11.h's macstat_t */
+ uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS,
+ * Control Management (includes retransmissions)
+ */
+ uint32 txrtsfrm; /**< number of RTS sent out by the MAC */
+ uint32 txctsfrm; /**< number of CTS sent out by the MAC */
+ uint32 txackfrm; /**< number of ACK frames sent out */
+ uint32 txdnlfrm; /**< number of Null-Data transmission generated from template */
+ uint32 txbcnfrm; /**< beacons transmitted */
+ uint32 txfunfl[6]; /**< per-fifo tx underflows */
+ uint32 txampdu; /**< number of AMPDUs transmitted */
+ uint32 txmpdu; /**< number of MPDUs transmitted */
+ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS
+ * or BCN)
+ */
+ uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for
+ * driver enqueued frames
+ */
+ uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */
+ uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */
+ uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */
+ uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */
+ uint32 rxanyerr; /**< Any RX error that is not counted by other counters. */
+ uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */
+ uint32 rxbadplcp; /**< parity check of the PLCP header failed */
+ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */
+ uint32 rxstrt; /**< Number of received frames with a good PLCP
+ * (i.e. passing parity check)
+ */
+ uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */
+ uint32 rxmgucastmbss; /**< number of received mgmt frames with good FCS and matching RA */
+ uint32 rxctlucast; /**< number of received CNTRL frames with good FCS and matching RA */
+ uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */
+ uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */
+ uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */
+ uint32 rxdtocast; /**< number of received DATA frames (good FCS and not matching RA) */
+ uint32 rxmgocast; /**< number of received MGMT frames (good FCS and not matching RA) */
+ uint32 rxctlocast; /**< number of received CNTRL frame (good FCS and not matching RA) */
+ uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */
+ uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */
+ uint32 rxdtmcast; /**< number of RX Data multicast frames received by the MAC */
+ uint32 rxmgmcast; /**< number of RX Management multicast frames received by the MAC */
+ uint32 rxctlmcast; /**< number of RX Control multicast frames received by the MAC
+ * (unlikely to see these)
+ */
+ uint32 rxbeaconmbss; /**< beacons received from member of BSS */
+ uint32 rxdtucastobss; /**< number of unicast frames addressed to the MAC from
+ * other BSS (WDS FRAME)
+ */
+ uint32 rxbeaconobss; /**< beacons received from other BSS */
+ uint32 rxrsptmout; /**< number of response timeouts for transmitted frames
+ * expecting a response
+ */
+ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */
+ uint32 rxnodelim; /**< number of no valid delimiter detected by ampdu parser */
+ uint32 rxf0ovfl; /**< number of receive fifo 0 overflows */
+ uint32 rxf1ovfl; /**< number of receive fifo 1 overflows */
+ uint32 rxhlovfl; /**< number of length / header fifo overflows */
+ uint32 missbcn_dbg; /**< number of beacon missed to receive */
+ uint32 pmqovfl; /**< number of PMQ overflows */
+ uint32 rxcgprqfrm; /**< number of received Probe requests that made it into
+ * the PRQ fifo
+ */
+ uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */
+ uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did
+ * not get ACK
+ */
+ uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */
+ uint32 prs_timeout; /**< number of probe requests that were dropped from the PRQ
+ * fifo because a probe response could not be sent out within
+ * the time limit defined in M_PRS_MAXTIME
+ */
+ uint32 txrtsfail; /**< number of rts transmission failure that reach retry limit */
+ uint32 txucast; /**< number of unicast tx expecting response other than cts/cwcts */
+ uint32 txinrtstxop; /**< number of data frame transmissions during rts txop */
+ uint32 rxback; /**< blockack rxcnt */
+ uint32 txback; /**< blockack txcnt */
+ uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */
+ uint32 rxdrop20s; /**< drop secondary cnt */
+ uint32 rxtoolate; /**< receive too late */
+ uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */
+} wl_cnt_ge40mcst_v1_t;
+
+/** MACSTAT counters for ucode (corerev < 40) */
+typedef struct {
+ /* MAC counters: 32-bit version of d11.h's macstat_t */
+ uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS,
+ * Control Management (includes retransmissions)
+ */
+ uint32 txrtsfrm; /**< number of RTS sent out by the MAC */
+ uint32 txctsfrm; /**< number of CTS sent out by the MAC */
+ uint32 txackfrm; /**< number of ACK frames sent out */
+ uint32 txdnlfrm; /**< number of Null-Data transmission generated from template */
+ uint32 txbcnfrm; /**< beacons transmitted */
+ uint32 txfunfl[6]; /**< per-fifo tx underflows */
+ uint32 txampdu; /**< number of AMPDUs transmitted */
+ uint32 txmpdu; /**< number of MPDUs transmitted */
+ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS
+ * or BCN)
+ */
+ uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for
+ * driver enqueued frames
+ */
+ uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */
+ uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */
+ uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */
+ uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */
+ uint32 rxanyerr; /**< Any RX error that is not counted by other counters. */
+ uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */
+ uint32 rxbadplcp; /**< parity check of the PLCP header failed */
+ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */
+ uint32 rxstrt; /**< Number of received frames with a good PLCP
+ * (i.e. passing parity check)
+ */
+ uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */
+ uint32 rxmgucastmbss; /**< number of received mgmt frames with good FCS and matching RA */
+ uint32 rxctlucast; /**< number of received CNTRL frames with good FCS and matching RA */
+ uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */
+ uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */
+ uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */
+ uint32 rxdtocast; /**< number of received DATA frames (good FCS and not matching RA) */
+ uint32 rxmgocast; /**< number of received MGMT frames (good FCS and not matching RA) */
+ uint32 rxctlocast; /**< number of received CNTRL frame (good FCS and not matching RA) */
+ uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */
+ uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */
+ uint32 rxdtmcast; /**< number of RX Data multicast frames received by the MAC */
+ uint32 rxmgmcast; /**< number of RX Management multicast frames received by the MAC */
+ uint32 rxctlmcast; /**< number of RX Control multicast frames received by the MAC
+ * (unlikely to see these)
+ */
+ uint32 rxbeaconmbss; /**< beacons received from member of BSS */
+ uint32 rxdtucastobss; /**< number of unicast frames addressed to the MAC from
+ * other BSS (WDS FRAME)
+ */
+ uint32 rxbeaconobss; /**< beacons received from other BSS */
+ uint32 rxrsptmout; /**< number of response timeouts for transmitted frames
+ * expecting a response
+ */
+ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */
+ uint32 rxnodelim; /**< number of no valid delimiter detected by ampdu parser */
+ uint32 rxf0ovfl; /**< number of receive fifo 0 overflows */
+ uint32 dbgoff46;
+ uint32 dbgoff47;
+ uint32 dbgoff48; /**< Used for counting txstatus queue overflow (corerev <= 4) */
+ uint32 pmqovfl; /**< number of PMQ overflows */
+ uint32 rxcgprqfrm; /**< number of received Probe requests that made it into
+ * the PRQ fifo
+ */
+ uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */
+ uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did
+ * not get ACK
+ */
+ uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */
+ uint32 prs_timeout; /**< number of probe requests that were dropped from the PRQ
+ * fifo because a probe response could not be sent out within
+ * the time limit defined in M_PRS_MAXTIME
+ */
+ uint32 txrtsfail; /**< number of rts transmission failure that reach retry limit */
+ uint32 txucast; /**< number of unicast tx expecting response other than cts/cwcts */
+ uint32 txinrtstxop; /**< number of data frame transmissions during rts txop */
+ uint32 rxback; /**< blockack rxcnt */
+ uint32 txback; /**< blockack txcnt */
+ uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */
+ uint32 phywatch;
+ uint32 rxtoolate; /**< receive too late */
+ uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */
+} wl_cnt_lt40mcst_v1_t;
+
+/** MACSTAT counters for "wl counter" version <= 10 */
+typedef struct {
+ /* MAC counters: 32-bit version of d11.h's macstat_t */
+ uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS,
+ * Control Management (includes retransmissions)
+ */
+ uint32 txrtsfrm; /**< number of RTS sent out by the MAC */
+ uint32 txctsfrm; /**< number of CTS sent out by the MAC */
+ uint32 txackfrm; /**< number of ACK frames sent out */
+ uint32 txdnlfrm; /**< number of Null-Data transmission generated from template */
+ uint32 txbcnfrm; /**< beacons transmitted */
+ uint32 txfunfl[6]; /**< per-fifo tx underflows */
+ uint32 txfbw; /**< transmit at fallback bw (dynamic bw) */
+ uint32 PAD0; /**< number of MPDUs transmitted */
+ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS
+ * or BCN)
+ */
+ uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for
+ * driver enqueued frames
+ */
+ uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */
+ uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */
+ uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */
+ uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */
+ uint32 rxinvmachdr; /**< Either the protocol version != 0 or frame type not
+ * data/control/management
+ */
+ uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */
+ uint32 rxbadplcp; /**< parity check of the PLCP header failed */
+ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */
+ uint32 rxstrt; /**< Number of received frames with a good PLCP
+ * (i.e. passing parity check)
+ */
+ uint32 rxdfrmucastmbss; /* number of received DATA frames with good FCS and matching RA */
+ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */
+ uint32 rxcfrmucast; /**< number of received CNTRL frames with good FCS and matching RA */
+ uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */
+ uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */
+ uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */
+ uint32 rxdfrmocast; /**< number of received DATA frames (good FCS and not matching RA) */
+ uint32 rxmfrmocast; /**< number of received MGMT frames (good FCS and not matching RA) */
+ uint32 rxcfrmocast; /**< number of received CNTRL frame (good FCS and not matching RA) */
+ uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */
+ uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */
+ uint32 rxdfrmmcast; /**< number of RX Data multicast frames received by the MAC */
+ uint32 rxmfrmmcast; /**< number of RX Management multicast frames received by the MAC */
+ uint32 rxcfrmmcast; /**< number of RX Control multicast frames received by the MAC
+ * (unlikely to see these)
+ */
+ uint32 rxbeaconmbss; /**< beacons received from member of BSS */
+ uint32 rxdfrmucastobss; /**< number of unicast frames addressed to the MAC from
+ * other BSS (WDS FRAME)
+ */
+ uint32 rxbeaconobss; /**< beacons received from other BSS */
+ uint32 rxrsptmout; /**< number of response timeouts for transmitted frames
+ * expecting a response
+ */
+ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */
+ uint32 PAD1;
+ uint32 rxf0ovfl; /**< number of receive fifo 0 overflows */
+ uint32 rxf1ovfl; /**< Number of receive fifo 1 overflows (obsolete) */
+ uint32 rxf2ovfl; /**< Number of receive fifo 2 overflows (obsolete) */
+ uint32 txsfovfl; /**< Number of transmit status fifo overflows (obsolete) */
+ uint32 pmqovfl; /**< number of PMQ overflows */
+ uint32 rxcgprqfrm; /**< number of received Probe requests that made it into
+ * the PRQ fifo
+ */
+ uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */
+ uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did
+ * not get ACK
+ */
+ uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */
+ uint32 prs_timeout; /**< number of probe requests that were dropped from the PRQ
+ * fifo because a probe response could not be sent out within
+ * the time limit defined in M_PRS_MAXTIME
+ */
+ uint32 rxnack; /**< obsolete */
+ uint32 frmscons; /**< obsolete */
+ uint32 txnack; /**< obsolete */
+ uint32 rxback; /**< blockack rxcnt */
+ uint32 txback; /**< blockack txcnt */
+ uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */
+ uint32 rxdrop20s; /**< drop secondary cnt */
+ uint32 rxtoolate; /**< receive too late */
+ uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */
+} wl_cnt_v_le10_mcst_t;
+
+#define MAX_RX_FIFO 3
+#define WL_RXFIFO_CNT_VERSION 1 /* current version of wl_rxfifo_cnt_t */
+typedef struct {
+ /* Counters for frames received from rx fifos */
+ uint16 version;
+ uint16 length; /* length of entire structure */
+ uint32 rxf_data[MAX_RX_FIFO]; /* data frames from rx fifo */
+ uint32 rxf_mgmtctl[MAX_RX_FIFO]; /* mgmt/ctl frames from rx fifo */
+} wl_rxfifo_cnt_t;
+
+typedef struct {
+ uint16 version; /**< see definition of WL_CNT_T_VERSION */
+ uint16 length; /**< length of entire structure */
+
+ /* transmit stat counters */
+ uint32 txframe; /**< tx data frames */
+ uint32 txbyte; /**< tx data bytes */
+ uint32 txretrans; /**< tx mac retransmits */
+ uint32 txerror; /**< tx data errors (derived: sum of others) */
+ uint32 txctl; /**< tx management frames */
+ uint32 txprshort; /**< tx short preamble frames */
+ uint32 txserr; /**< tx status errors */
+ uint32 txnobuf; /**< tx out of buffers errors */
+ uint32 txnoassoc; /**< tx discard because we're not associated */
+ uint32 txrunt; /**< tx runt frames */
+ uint32 txchit; /**< tx header cache hit (fastpath) */
+ uint32 txcmiss; /**< tx header cache miss (slowpath) */
+
+ /* transmit chip error counters */
+ uint32 txuflo; /**< tx fifo underflows */
+ uint32 txphyerr; /**< tx phy errors (indicated in tx status) */
+ uint32 txphycrs;
+
+ /* receive stat counters */
+ uint32 rxframe; /**< rx data frames */
+ uint32 rxbyte; /**< rx data bytes */
+ uint32 rxerror; /**< rx data errors (derived: sum of others) */
+ uint32 rxctl; /**< rx management frames */
+ uint32 rxnobuf; /**< rx out of buffers errors */
+ uint32 rxnondata; /**< rx non data frames in the data channel errors */
+ uint32 rxbadds; /**< rx bad DS errors */
+ uint32 rxbadcm; /**< rx bad control or management frames */
+ uint32 rxfragerr; /**< rx fragmentation errors */
+ uint32 rxrunt; /**< rx runt frames */
+ uint32 rxgiant; /**< rx giant frames */
+ uint32 rxnoscb; /**< rx no scb error */
+ uint32 rxbadproto; /**< rx invalid frames */
+ uint32 rxbadsrcmac; /**< rx frames with Invalid Src Mac */
+ uint32 rxbadda; /**< rx frames tossed for invalid da */
+ uint32 rxfilter; /**< rx frames filtered out */
+
+ /* receive chip error counters */
+ uint32 rxoflo; /**< rx fifo overflow errors */
+ uint32 rxuflo[NFIFO]; /**< rx dma descriptor underflow errors */
+
+ uint32 d11cnt_txrts_off; /**< d11cnt txrts value when reset d11cnt */
+ uint32 d11cnt_rxcrc_off; /**< d11cnt rxcrc value when reset d11cnt */
+ uint32 d11cnt_txnocts_off; /**< d11cnt txnocts value when reset d11cnt */
+
+ /* misc counters */
+ uint32 dmade; /**< tx/rx dma descriptor errors */
+ uint32 dmada; /**< tx/rx dma data errors */
+ uint32 dmape; /**< tx/rx dma descriptor protocol errors */
+ uint32 reset; /**< reset count */
+ uint32 tbtt; /**< cnts the TBTT int's */
+ uint32 txdmawar;
+ uint32 pkt_callback_reg_fail; /**< callbacks register failure */
+
+ /* MAC counters: 32-bit version of d11.h's macstat_t */
+ uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS,
+ * Control Management (includes retransmissions)
+ */
+ uint32 txrtsfrm; /**< number of RTS sent out by the MAC */
+ uint32 txctsfrm; /**< number of CTS sent out by the MAC */
+ uint32 txackfrm; /**< number of ACK frames sent out */
+ uint32 txdnlfrm; /**< Not used */
+ uint32 txbcnfrm; /**< beacons transmitted */
+ uint32 txfunfl[6]; /**< per-fifo tx underflows */
+ uint32 rxtoolate; /**< receive too late */
+ uint32 txfbw; /**< transmit at fallback bw (dynamic bw) */
+ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS
+ * or BCN)
+ */
+ uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for
+ * driver enqueued frames
+ */
+ uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */
+ uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */
+ uint32 rxinvmachdr; /**< Either the protocol version != 0 or frame type not
+ * data/control/management
+ */
+ uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */
+ uint32 rxbadplcp; /**< parity check of the PLCP header failed */
+ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */
+ uint32 rxstrt; /**< Number of received frames with a good PLCP
+ * (i.e. passing parity check)
+ */
+ uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */
+ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */
+ uint32 rxcfrmucast; /**< number of received CNTRL frames with good FCS and matching RA */
+ uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */
+ uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */
+ uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */
+ uint32 rxdfrmocast; /**< number of received DATA frames (good FCS and not matching RA) */
+ uint32 rxmfrmocast; /**< number of received MGMT frames (good FCS and not matching RA) */
+ uint32 rxcfrmocast; /**< number of received CNTRL frame (good FCS and not matching RA) */
+ uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */
+ uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */
+ uint32 rxdfrmmcast; /**< number of RX Data multicast frames received by the MAC */
+ uint32 rxmfrmmcast; /**< number of RX Management multicast frames received by the MAC */
+ uint32 rxcfrmmcast; /**< number of RX Control multicast frames received by the MAC
+ * (unlikely to see these)
+ */
+ uint32 rxbeaconmbss; /**< beacons received from member of BSS */
+ uint32 rxdfrmucastobss; /**< number of unicast frames addressed to the MAC from
+ * other BSS (WDS FRAME)
+ */
+ uint32 rxbeaconobss; /**< beacons received from other BSS */
+ uint32 rxrsptmout; /**< Number of response timeouts for transmitted frames
+ * expecting a response
+ */
+ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */
+ uint32 rxf0ovfl; /**< Number of receive fifo 0 overflows */
+ uint32 rxf1ovfl; /**< Number of receive fifo 1 overflows (obsolete) */
+ uint32 rxf2ovfl; /**< Number of receive fifo 2 overflows (obsolete) */
+ uint32 txsfovfl; /**< Number of transmit status fifo overflows (obsolete) */
+ uint32 pmqovfl; /**< Number of PMQ overflows */
+ uint32 rxcgprqfrm; /**< Number of received Probe requests that made it into
+ * the PRQ fifo
+ */
+ uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */
+ uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did
+ * not get ACK
+ */
+ uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */
+ uint32 prs_timeout; /**< Number of probe requests that were dropped from the PRQ
+ * fifo because a probe response could not be sent out within
+ * the time limit defined in M_PRS_MAXTIME
+ */
+ uint32 rxnack; /**< obsolete */
+ uint32 frmscons; /**< obsolete */
+ uint32 txnack; /**< obsolete */
+ uint32 rxback; /**< blockack rxcnt */
+ uint32 txback; /**< blockack txcnt */
+
+ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */
+ uint32 txfrag; /**< dot11TransmittedFragmentCount */
+ uint32 txmulti; /**< dot11MulticastTransmittedFrameCount */
+ uint32 txfail; /**< dot11FailedCount */
+ uint32 txretry; /**< dot11RetryCount */
+ uint32 txretrie; /**< dot11MultipleRetryCount */
+ uint32 rxdup; /**< dot11FrameduplicateCount */
+ uint32 txrts; /**< dot11RTSSuccessCount */
+ uint32 txnocts; /**< dot11RTSFailureCount */
+ uint32 txnoack; /**< dot11ACKFailureCount */
+ uint32 rxfrag; /**< dot11ReceivedFragmentCount */
+ uint32 rxmulti; /**< dot11MulticastReceivedFrameCount */
+ uint32 rxcrc; /**< dot11FCSErrorCount */
+ uint32 txfrmsnt; /**< dot11TransmittedFrameCount (bogus MIB?) */
+ uint32 rxundec; /**< dot11WEPUndecryptableCount */
+
+ /* WPA2 counters (see rxundec for DecryptFailureCount) */
+ uint32 tkipmicfaill; /**< TKIPLocalMICFailures */
+ uint32 tkipcntrmsr; /**< TKIPCounterMeasuresInvoked */
+ uint32 tkipreplay; /**< TKIPReplays */
+ uint32 ccmpfmterr; /**< CCMPFormatErrors */
+ uint32 ccmpreplay; /**< CCMPReplays */
+ uint32 ccmpundec; /**< CCMPDecryptErrors */
+ uint32 fourwayfail; /**< FourWayHandshakeFailures */
+ uint32 wepundec; /**< dot11WEPUndecryptableCount */
+ uint32 wepicverr; /**< dot11WEPICVErrorCount */
+ uint32 decsuccess; /**< DecryptSuccessCount */
+ uint32 tkipicverr; /**< TKIPICVErrorCount */
+ uint32 wepexcluded; /**< dot11WEPExcludedCount */
+
+ uint32 txchanrej; /**< Tx frames suppressed due to channel rejection */
+ uint32 psmwds; /**< Count PSM watchdogs */
+ uint32 phywatchdog; /**< Count Phy watchdogs (triggered by ucode) */
+
+ /* MBSS counters, AP only */
+ uint32 prq_entries_handled; /**< PRQ entries read in */
+ uint32 prq_undirected_entries; /**< which were bcast bss & ssid */
+ uint32 prq_bad_entries; /**< which could not be translated to info */
+ uint32 atim_suppress_count; /**< TX suppressions on ATIM fifo */
+ uint32 bcn_template_not_ready; /**< Template marked in use on send bcn ... */
+ uint32 bcn_template_not_ready_done; /**< ...but "DMA done" interrupt rcvd */
+ uint32 late_tbtt_dpc; /**< TBTT DPC did not happen in time */
+
+ /* per-rate receive stat counters */
+ uint32 rx1mbps; /**< packets rx at 1Mbps */
+ uint32 rx2mbps; /**< packets rx at 2Mbps */
+ uint32 rx5mbps5; /**< packets rx at 5.5Mbps */
+ uint32 rx6mbps; /**< packets rx at 6Mbps */
+ uint32 rx9mbps; /**< packets rx at 9Mbps */
+ uint32 rx11mbps; /**< packets rx at 11Mbps */
+ uint32 rx12mbps; /**< packets rx at 12Mbps */
+ uint32 rx18mbps; /**< packets rx at 18Mbps */
+ uint32 rx24mbps; /**< packets rx at 24Mbps */
+ uint32 rx36mbps; /**< packets rx at 36Mbps */
+ uint32 rx48mbps; /**< packets rx at 48Mbps */
+ uint32 rx54mbps; /**< packets rx at 54Mbps */
+ uint32 rx108mbps; /**< packets rx at 108mbps */
+ uint32 rx162mbps; /**< packets rx at 162mbps */
+ uint32 rx216mbps; /**< packets rx at 216 mbps */
+ uint32 rx270mbps; /**< packets rx at 270 mbps */
+ uint32 rx324mbps; /**< packets rx at 324 mbps */
+ uint32 rx378mbps; /**< packets rx at 378 mbps */
+ uint32 rx432mbps; /**< packets rx at 432 mbps */
+ uint32 rx486mbps; /**< packets rx at 486 mbps */
+ uint32 rx540mbps; /**< packets rx at 540 mbps */
+
+ /* pkteng rx frame stats */
+ uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */
+ uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */
+
+ uint32 rfdisable; /**< count of radio disables */
+ uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */
+ uint32 bphy_badplcp;
+
+ uint32 txexptime; /**< Tx frames suppressed due to timer expiration */
+
+ uint32 txmpdu_sgi; /**< count for sgi transmit */
+ uint32 rxmpdu_sgi; /**< count for sgi received */
+ uint32 txmpdu_stbc; /**< count for stbc transmit */
+ uint32 rxmpdu_stbc; /**< count for stbc received */
+
+ uint32 rxundec_mcst; /**< dot11WEPUndecryptableCount */
+
+ /* WPA2 counters (see rxundec for DecryptFailureCount) */
+ uint32 tkipmicfaill_mcst; /**< TKIPLocalMICFailures */
+ uint32 tkipcntrmsr_mcst; /**< TKIPCounterMeasuresInvoked */
+ uint32 tkipreplay_mcst; /**< TKIPReplays */
+ uint32 ccmpfmterr_mcst; /**< CCMPFormatErrors */
+ uint32 ccmpreplay_mcst; /**< CCMPReplays */
+ uint32 ccmpundec_mcst; /**< CCMPDecryptErrors */
+ uint32 fourwayfail_mcst; /**< FourWayHandshakeFailures */
+ uint32 wepundec_mcst; /**< dot11WEPUndecryptableCount */
+ uint32 wepicverr_mcst; /**< dot11WEPICVErrorCount */
+ uint32 decsuccess_mcst; /**< DecryptSuccessCount */
+ uint32 tkipicverr_mcst; /**< TKIPICVErrorCount */
+ uint32 wepexcluded_mcst; /**< dot11WEPExcludedCount */
+
+ uint32 dma_hang; /**< count for dma hang */
+ uint32 reinit; /**< count for reinit */
+
+ uint32 pstatxucast; /**< count of ucast frames xmitted on all psta assoc */
+ uint32 pstatxnoassoc; /**< count of txnoassoc frames xmitted on all psta assoc */
+ uint32 pstarxucast; /**< count of ucast frames received on all psta assoc */
+ uint32 pstarxbcmc; /**< count of bcmc frames received on all psta */
+ uint32 pstatxbcmc; /**< count of bcmc frames transmitted on all psta */
+
+ uint32 cso_passthrough; /**< hw cso required but passthrough */
+ uint32 cso_normal; /**< hw cso hdr for normal process */
+ uint32 chained; /**< number of frames chained */
+ uint32 chainedsz1; /**< number of chain size 1 frames */
+ uint32 unchained; /**< number of frames not chained */
+ uint32 maxchainsz; /**< max chain size so far */
+ uint32 currchainsz; /**< current chain size */
+ uint32 rxdrop20s; /**< drop secondary cnt */
+ uint32 pciereset; /**< Secondary Bus Reset issued by driver */
+ uint32 cfgrestore; /**< configspace restore by driver */
+ uint32 reinitreason[NREINITREASONCOUNT]; /**< reinitreason counters; 0: Unknown reason */
+ uint32 rxrtry; /**< num of received packets with retry bit on */
+ uint32 txmpdu; /**< macstat cnt only valid in ver 11. number of MPDUs txed. */
+ uint32 rxnodelim; /**< macstat cnt only valid in ver 11.
+ * number of occasions that no valid delimiter is detected
+ * by ampdu parser.
+ */
+ uint32 rxmpdu_mu; /**< Number of MU MPDUs received */
+
+ /* detailed control/management frames */
+ uint32 txbar; /**< Number of TX BAR */
+ uint32 rxbar; /**< Number of RX BAR */
+ uint32 txpspoll; /**< Number of TX PS-poll */
+ uint32 rxpspoll; /**< Number of RX PS-poll */
+ uint32 txnull; /**< Number of TX NULL_DATA */
+ uint32 rxnull; /**< Number of RX NULL_DATA */
+ uint32 txqosnull; /**< Number of TX NULL_QoSDATA */
+ uint32 rxqosnull; /**< Number of RX NULL_QoSDATA */
+ uint32 txassocreq; /**< Number of TX ASSOC request */
+ uint32 rxassocreq; /**< Number of RX ASSOC request */
+ uint32 txreassocreq; /**< Number of TX REASSOC request */
+ uint32 rxreassocreq; /**< Number of RX REASSOC request */
+ uint32 txdisassoc; /**< Number of TX DISASSOC */
+ uint32 rxdisassoc; /**< Number of RX DISASSOC */
+ uint32 txassocrsp; /**< Number of TX ASSOC response */
+ uint32 rxassocrsp; /**< Number of RX ASSOC response */
+ uint32 txreassocrsp; /**< Number of TX REASSOC response */
+ uint32 rxreassocrsp; /**< Number of RX REASSOC response */
+ uint32 txauth; /**< Number of TX AUTH */
+ uint32 rxauth; /**< Number of RX AUTH */
+ uint32 txdeauth; /**< Number of TX DEAUTH */
+ uint32 rxdeauth; /**< Number of RX DEAUTH */
+ uint32 txprobereq; /**< Number of TX probe request */
+ uint32 rxprobereq; /**< Number of RX probe request */
+ uint32 txprobersp; /**< Number of TX probe response */
+ uint32 rxprobersp; /**< Number of RX probe response */
+ uint32 txaction; /**< Number of TX action frame */
+ uint32 rxaction; /**< Number of RX action frame */
+ uint32 ampdu_wds; /**< Number of AMPDU watchdogs */
+ uint32 txlost; /**< Number of lost packets reported in txs */
+ uint32 txdatamcast; /**< Number of TX multicast data packets */
+ uint32 txdatabcast; /**< Number of TX broadcast data packets */
+
+} wl_cnt_ver_11_t;
+
+typedef struct {
+ uint16 version; /* see definition of WL_CNT_T_VERSION */
+ uint16 length; /* length of entire structure */
+
+ /* transmit stat counters */
+ uint32 txframe; /* tx data frames */
+ uint32 txbyte; /* tx data bytes */
+ uint32 txretrans; /* tx mac retransmits */
+ uint32 txerror; /* tx data errors (derived: sum of others) */
+ uint32 txctl; /* tx management frames */
+ uint32 txprshort; /* tx short preamble frames */
+ uint32 txserr; /* tx status errors */
+ uint32 txnobuf; /* tx out of buffers errors */
+ uint32 txnoassoc; /* tx discard because we're not associated */
+ uint32 txrunt; /* tx runt frames */
+ uint32 txchit; /* tx header cache hit (fastpath) */
+ uint32 txcmiss; /* tx header cache miss (slowpath) */
+
+ /* transmit chip error counters */
+ uint32 txuflo; /* tx fifo underflows */
+ uint32 txphyerr; /* tx phy errors (indicated in tx status) */
+ uint32 txphycrs;
+
+ /* receive stat counters */
+ uint32 rxframe; /* rx data frames */
+ uint32 rxbyte; /* rx data bytes */
+ uint32 rxerror; /* rx data errors (derived: sum of others) */
+ uint32 rxctl; /* rx management frames */
+ uint32 rxnobuf; /* rx out of buffers errors */
+ uint32 rxnondata; /* rx non data frames in the data channel errors */
+ uint32 rxbadds; /* rx bad DS errors */
+ uint32 rxbadcm; /* rx bad control or management frames */
+ uint32 rxfragerr; /* rx fragmentation errors */
+ uint32 rxrunt; /* rx runt frames */
+ uint32 rxgiant; /* rx giant frames */
+ uint32 rxnoscb; /* rx no scb error */
+ uint32 rxbadproto; /* rx invalid frames */
+ uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */
+ uint32 rxbadda; /* rx frames tossed for invalid da */
+ uint32 rxfilter; /* rx frames filtered out */
+
+ /* receive chip error counters */
+ uint32 rxoflo; /* rx fifo overflow errors */
+ uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */
+
+ uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */
+ uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */
+ uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */
+
+ /* misc counters */
+ uint32 dmade; /* tx/rx dma descriptor errors */
+ uint32 dmada; /* tx/rx dma data errors */
+ uint32 dmape; /* tx/rx dma descriptor protocol errors */
+ uint32 reset; /* reset count */
+ uint32 tbtt; /* cnts the TBTT int's */
+ uint32 txdmawar;
+ uint32 pkt_callback_reg_fail; /* callbacks register failure */
+
+ /* MAC counters: 32-bit version of d11.h's macstat_t */
+ uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS,
+ * Control Management (includes retransmissions)
+ */
+ uint32 txrtsfrm; /* number of RTS sent out by the MAC */
+ uint32 txctsfrm; /* number of CTS sent out by the MAC */
+ uint32 txackfrm; /* number of ACK frames sent out */
+ uint32 txdnlfrm; /* Not used */
+ uint32 txbcnfrm; /* beacons transmitted */
+ uint32 txfunfl[8]; /* per-fifo tx underflows */
+ uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS
+ * or BCN)
+ */
+ uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for
+ * driver enqueued frames
+ */
+ uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */
+ uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */
+ uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not
+ * data/control/management
+ */
+ uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */
+ uint32 rxbadplcp; /* parity check of the PLCP header failed */
+ uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */
+ uint32 rxstrt; /* Number of received frames with a good PLCP
+ * (i.e. passing parity check)
+ */
+ uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */
+ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */
+ uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */
+ uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */
+ uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */
+ uint32 rxackucast; /* number of ucast ACKS received (good FCS) */
+ uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */
+ uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */
+ uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */
+ uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */
+ uint32 rxctsocast; /* number of received CTS not addressed to the MAC */
+ uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */
+ uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */
+ uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC
+ * (unlikely to see these)
+ */
+ uint32 rxbeaconmbss; /* beacons received from member of BSS */
+ uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from
+ * other BSS (WDS FRAME)
+ */
+ uint32 rxbeaconobss; /* beacons received from other BSS */
+ uint32 rxrsptmout; /* Number of response timeouts for transmitted frames
+ * expecting a response
+ */
+ uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */
+ uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */
+ uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */
+ uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */
+ uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */
+ uint32 pmqovfl; /* Number of PMQ overflows */
+ uint32 rxcgprqfrm; /* Number of received Probe requests that made it into
+ * the PRQ fifo
+ */
+ uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */
+ uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did
+ * not get ACK
+ */
+ uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */
+ uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ
+ * fifo because a probe response could not be sent out within
+ * the time limit defined in M_PRS_MAXTIME
+ */
+ uint32 rxnack; /* obsolete */
+ uint32 frmscons; /* obsolete */
+ uint32 txnack; /* obsolete */
+ uint32 txglitch_nack; /* obsolete */
+ uint32 txburst; /* obsolete */
+
+ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */
+ uint32 txfrag; /* dot11TransmittedFragmentCount */
+ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */
+ uint32 txfail; /* dot11FailedCount */
+ uint32 txretry; /* dot11RetryCount */
+ uint32 txretrie; /* dot11MultipleRetryCount */
+ uint32 rxdup; /* dot11FrameduplicateCount */
+ uint32 txrts; /* dot11RTSSuccessCount */
+ uint32 txnocts; /* dot11RTSFailureCount */
+ uint32 txnoack; /* dot11ACKFailureCount */
+ uint32 rxfrag; /* dot11ReceivedFragmentCount */
+ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */
+ uint32 rxcrc; /* dot11FCSErrorCount */
+ uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */
+ uint32 rxundec; /* dot11WEPUndecryptableCount */
+
+ /* WPA2 counters (see rxundec for DecryptFailureCount) */
+ uint32 tkipmicfaill; /* TKIPLocalMICFailures */
+ uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */
+ uint32 tkipreplay; /* TKIPReplays */
+ uint32 ccmpfmterr; /* CCMPFormatErrors */
+ uint32 ccmpreplay; /* CCMPReplays */
+ uint32 ccmpundec; /* CCMPDecryptErrors */
+ uint32 fourwayfail; /* FourWayHandshakeFailures */
+ uint32 wepundec; /* dot11WEPUndecryptableCount */
+ uint32 wepicverr; /* dot11WEPICVErrorCount */
+ uint32 decsuccess; /* DecryptSuccessCount */
+ uint32 tkipicverr; /* TKIPICVErrorCount */
+ uint32 wepexcluded; /* dot11WEPExcludedCount */
+
+ uint32 txchanrej; /* Tx frames suppressed due to channel rejection */
+ uint32 psmwds; /* Count PSM watchdogs */
+ uint32 phywatchdog; /**< Count Phy watchdogs (triggered by ucode) */
+
+ /* MBSS counters, AP only */
+ uint32 prq_entries_handled; /* PRQ entries read in */
+ uint32 prq_undirected_entries; /* which were bcast bss & ssid */
+ uint32 prq_bad_entries; /* which could not be translated to info */
+ uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */
+ uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */
+ uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */
+ uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */
+
+ /* per-rate receive stat counters */
+ uint32 rx1mbps; /* packets rx at 1Mbps */
+ uint32 rx2mbps; /* packets rx at 2Mbps */
+ uint32 rx5mbps5; /* packets rx at 5.5Mbps */
+ uint32 rx6mbps; /* packets rx at 6Mbps */
+ uint32 rx9mbps; /* packets rx at 9Mbps */
+ uint32 rx11mbps; /* packets rx at 11Mbps */
+ uint32 rx12mbps; /* packets rx at 12Mbps */
+ uint32 rx18mbps; /* packets rx at 18Mbps */
+ uint32 rx24mbps; /* packets rx at 24Mbps */
+ uint32 rx36mbps; /* packets rx at 36Mbps */
+ uint32 rx48mbps; /* packets rx at 48Mbps */
+ uint32 rx54mbps; /* packets rx at 54Mbps */
+ uint32 rx108mbps; /* packets rx at 108mbps */
+ uint32 rx162mbps; /* packets rx at 162mbps */
+ uint32 rx216mbps; /* packets rx at 216 mbps */
+ uint32 rx270mbps; /* packets rx at 270 mbps */
+ uint32 rx324mbps; /* packets rx at 324 mbps */
+ uint32 rx378mbps; /* packets rx at 378 mbps */
+ uint32 rx432mbps; /* packets rx at 432 mbps */
+ uint32 rx486mbps; /* packets rx at 486 mbps */
+ uint32 rx540mbps; /* packets rx at 540 mbps */
+
+ /* pkteng rx frame stats */
+ uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */
+ uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */
+
+ uint32 rfdisable; /* count of radio disables */
+ uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */
+
+ uint32 txexptime; /* Tx frames suppressed due to timer expiration */
+
+ uint32 txmpdu_sgi; /* count for sgi transmit */
+ uint32 rxmpdu_sgi; /* count for sgi received */
+ uint32 txmpdu_stbc; /* count for stbc transmit */
+ uint32 rxmpdu_stbc; /* count for stbc received */
+
+ uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */
+
+ /* WPA2 counters (see rxundec for DecryptFailureCount) */
+ uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */
+ uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */
+ uint32 tkipreplay_mcst; /* TKIPReplays */
+ uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */
+ uint32 ccmpreplay_mcst; /* CCMPReplays */
+ uint32 ccmpundec_mcst; /* CCMPDecryptErrors */
+ uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */
+ uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */
+ uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */
+ uint32 decsuccess_mcst; /* DecryptSuccessCount */
+ uint32 tkipicverr_mcst; /* TKIPICVErrorCount */
+ uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */
+
+ uint32 dma_hang; /* count for stbc received */
+} wl_cnt_ver_7_t;
+
+typedef struct {
+ uint16 version; /**< see definition of WL_CNT_T_VERSION */
+ uint16 length; /**< length of entire structure */
+
+ /* transmit stat counters */
+ uint32 txframe; /**< tx data frames */
+ uint32 txbyte; /**< tx data bytes */
+ uint32 txretrans; /**< tx mac retransmits */
+ uint32 txerror; /**< tx data errors (derived: sum of others) */
+ uint32 txctl; /**< tx management frames */
+ uint32 txprshort; /**< tx short preamble frames */
+ uint32 txserr; /**< tx status errors */
+ uint32 txnobuf; /**< tx out of buffers errors */
+ uint32 txnoassoc; /**< tx discard because we're not associated */
+ uint32 txrunt; /**< tx runt frames */
+ uint32 txchit; /**< tx header cache hit (fastpath) */
+ uint32 txcmiss; /**< tx header cache miss (slowpath) */
+
+ /* transmit chip error counters */
+ uint32 txuflo; /**< tx fifo underflows */
+ uint32 txphyerr; /**< tx phy errors (indicated in tx status) */
+ uint32 txphycrs;
+
+ /* receive stat counters */
+ uint32 rxframe; /**< rx data frames */
+ uint32 rxbyte; /**< rx data bytes */
+ uint32 rxerror; /**< rx data errors (derived: sum of others) */
+ uint32 rxctl; /**< rx management frames */
+ uint32 rxnobuf; /**< rx out of buffers errors */
+ uint32 rxnondata; /**< rx non data frames in the data channel errors */
+ uint32 rxbadds; /**< rx bad DS errors */
+ uint32 rxbadcm; /**< rx bad control or management frames */
+ uint32 rxfragerr; /**< rx fragmentation errors */
+ uint32 rxrunt; /**< rx runt frames */
+ uint32 rxgiant; /**< rx giant frames */
+ uint32 rxnoscb; /**< rx no scb error */
+ uint32 rxbadproto; /**< rx invalid frames */
+ uint32 rxbadsrcmac; /**< rx frames with Invalid Src Mac */
+ uint32 rxbadda; /**< rx frames tossed for invalid da */
+ uint32 rxfilter; /**< rx frames filtered out */
+
+ /* receive chip error counters */
+ uint32 rxoflo; /**< rx fifo overflow errors */
+ uint32 rxuflo[NFIFO]; /**< rx dma descriptor underflow errors */
+
+ uint32 d11cnt_txrts_off; /**< d11cnt txrts value when reset d11cnt */
+ uint32 d11cnt_rxcrc_off; /**< d11cnt rxcrc value when reset d11cnt */
+ uint32 d11cnt_txnocts_off; /**< d11cnt txnocts value when reset d11cnt */
+
+ /* misc counters */
+ uint32 dmade; /**< tx/rx dma descriptor errors */
+ uint32 dmada; /**< tx/rx dma data errors */
+ uint32 dmape; /**< tx/rx dma descriptor protocol errors */
+ uint32 reset; /**< reset count */
+ uint32 tbtt; /**< cnts the TBTT int's */
+ uint32 txdmawar;
+ uint32 pkt_callback_reg_fail; /**< callbacks register failure */
+
+ /* MAC counters: 32-bit version of d11.h's macstat_t */
+ uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS,
+ * Control Management (includes retransmissions)
+ */
+ uint32 txrtsfrm; /**< number of RTS sent out by the MAC */
+ uint32 txctsfrm; /**< number of CTS sent out by the MAC */
+ uint32 txackfrm; /**< number of ACK frames sent out */
+ uint32 txdnlfrm; /**< Not used */
+ uint32 txbcnfrm; /**< beacons transmitted */
+ uint32 txfunfl[6]; /**< per-fifo tx underflows */
+ uint32 rxtoolate; /**< receive too late */
+ uint32 txfbw; /**< transmit at fallback bw (dynamic bw) */
+ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS
+ * or BCN)
+ */
+ uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for
+ * driver enqueued frames
+ */
+ uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */
+ uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */
+ uint32 rxinvmachdr; /**< Either the protocol version != 0 or frame type not
+ * data/control/management
+ */
+ uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */
+ uint32 rxbadplcp; /**< parity check of the PLCP header failed */
+ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */
+ uint32 rxstrt; /**< Number of received frames with a good PLCP
+ * (i.e. passing parity check)
+ */
+ uint32 rxdfrmucastmbss; /**< # of received DATA frames with good FCS and matching RA */
+ uint32 rxmfrmucastmbss; /**< # of received mgmt frames with good FCS and matching RA */
+ uint32 rxcfrmucast; /**< # of received CNTRL frames with good FCS and matching RA */
+ uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */
+ uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */
+ uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */
+ uint32 rxdfrmocast; /**< # of received DATA frames (good FCS and not matching RA) */
+ uint32 rxmfrmocast; /**< # of received MGMT frames (good FCS and not matching RA) */
+ uint32 rxcfrmocast; /**< # of received CNTRL frame (good FCS and not matching RA) */
+ uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */
+ uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */
+ uint32 rxdfrmmcast; /**< number of RX Data multicast frames received by the MAC */
+ uint32 rxmfrmmcast; /**< number of RX Management multicast frames received by the MAC */
+ uint32 rxcfrmmcast; /**< number of RX Control multicast frames received by the MAC
+ * (unlikely to see these)
+ */
+ uint32 rxbeaconmbss; /**< beacons received from member of BSS */
+ uint32 rxdfrmucastobss; /**< number of unicast frames addressed to the MAC from
+ * other BSS (WDS FRAME)
+ */
+ uint32 rxbeaconobss; /**< beacons received from other BSS */
+ uint32 rxrsptmout; /**< Number of response timeouts for transmitted frames
+ * expecting a response
+ */
+ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */
+ uint32 rxf0ovfl; /**< Number of receive fifo 0 overflows */
+ uint32 rxf1ovfl; /**< Number of receive fifo 1 overflows (obsolete) */
+ uint32 rxf2ovfl; /**< Number of receive fifo 2 overflows (obsolete) */
+ uint32 txsfovfl; /**< Number of transmit status fifo overflows (obsolete) */
+ uint32 pmqovfl; /**< Number of PMQ overflows */
+ uint32 rxcgprqfrm; /**< Number of received Probe requests that made it into
+ * the PRQ fifo
+ */
+ uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */
+ uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did
+ * not get ACK
+ */
+ uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */
+ uint32 prs_timeout; /**< Number of probe requests that were dropped from the PRQ
+ * fifo because a probe response could not be sent out within
+ * the time limit defined in M_PRS_MAXTIME
+ */
+ uint32 rxnack;
+ uint32 frmscons;
+ uint32 txnack; /**< obsolete */
+ uint32 rxback; /**< blockack rxcnt */
+ uint32 txback; /**< blockack txcnt */
+
+ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */
+ uint32 txfrag; /**< dot11TransmittedFragmentCount */
+ uint32 txmulti; /**< dot11MulticastTransmittedFrameCount */
+ uint32 txfail; /**< dot11FailedCount */
+ uint32 txretry; /**< dot11RetryCount */
+ uint32 txretrie; /**< dot11MultipleRetryCount */
+ uint32 rxdup; /**< dot11FrameduplicateCount */
+ uint32 txrts; /**< dot11RTSSuccessCount */
+ uint32 txnocts; /**< dot11RTSFailureCount */
+ uint32 txnoack; /**< dot11ACKFailureCount */
+ uint32 rxfrag; /**< dot11ReceivedFragmentCount */
+ uint32 rxmulti; /**< dot11MulticastReceivedFrameCount */
+ uint32 rxcrc; /**< dot11FCSErrorCount */
+ uint32 txfrmsnt; /**< dot11TransmittedFrameCount (bogus MIB?) */
+ uint32 rxundec; /**< dot11WEPUndecryptableCount */
+
+ /* WPA2 counters (see rxundec for DecryptFailureCount) */
+ uint32 tkipmicfaill; /**< TKIPLocalMICFailures */
+ uint32 tkipcntrmsr; /**< TKIPCounterMeasuresInvoked */
+ uint32 tkipreplay; /**< TKIPReplays */
+ uint32 ccmpfmterr; /**< CCMPFormatErrors */
+ uint32 ccmpreplay; /**< CCMPReplays */
+ uint32 ccmpundec; /**< CCMPDecryptErrors */
+ uint32 fourwayfail; /**< FourWayHandshakeFailures */
+ uint32 wepundec; /**< dot11WEPUndecryptableCount */
+ uint32 wepicverr; /**< dot11WEPICVErrorCount */
+ uint32 decsuccess; /**< DecryptSuccessCount */
+ uint32 tkipicverr; /**< TKIPICVErrorCount */
+ uint32 wepexcluded; /**< dot11WEPExcludedCount */
+
+ uint32 rxundec_mcst; /**< dot11WEPUndecryptableCount */
+
+ /* WPA2 counters (see rxundec for DecryptFailureCount) */
+ uint32 tkipmicfaill_mcst; /**< TKIPLocalMICFailures */
+ uint32 tkipcntrmsr_mcst; /**< TKIPCounterMeasuresInvoked */
+ uint32 tkipreplay_mcst; /**< TKIPReplays */
+ uint32 ccmpfmterr_mcst; /**< CCMPFormatErrors */
+ uint32 ccmpreplay_mcst; /**< CCMPReplays */
+ uint32 ccmpundec_mcst; /**< CCMPDecryptErrors */
+ uint32 fourwayfail_mcst; /**< FourWayHandshakeFailures */
+ uint32 wepundec_mcst; /**< dot11WEPUndecryptableCount */
+ uint32 wepicverr_mcst; /**< dot11WEPICVErrorCount */
+ uint32 decsuccess_mcst; /**< DecryptSuccessCount */
+ uint32 tkipicverr_mcst; /**< TKIPICVErrorCount */
+ uint32 wepexcluded_mcst; /**< dot11WEPExcludedCount */
+
+ uint32 txchanrej; /**< Tx frames suppressed due to channel rejection */
+ uint32 txexptime; /**< Tx frames suppressed due to timer expiration */
+ uint32 psmwds; /**< Count PSM watchdogs */
+ uint32 phywatchdog; /**< Count Phy watchdogs (triggered by ucode) */
+
+ /* MBSS counters, AP only */
+ uint32 prq_entries_handled; /**< PRQ entries read in */
+ uint32 prq_undirected_entries; /**< which were bcast bss & ssid */
+ uint32 prq_bad_entries; /**< which could not be translated to info */
+ uint32 atim_suppress_count; /**< TX suppressions on ATIM fifo */
+ uint32 bcn_template_not_ready; /**< Template marked in use on send bcn ... */
+ uint32 bcn_template_not_ready_done; /**< ...but "DMA done" interrupt rcvd */
+ uint32 late_tbtt_dpc; /**< TBTT DPC did not happen in time */
+
+ /* per-rate receive stat counters */
+ uint32 rx1mbps; /**< packets rx at 1Mbps */
+ uint32 rx2mbps; /**< packets rx at 2Mbps */
+ uint32 rx5mbps5; /**< packets rx at 5.5Mbps */
+ uint32 rx6mbps; /**< packets rx at 6Mbps */
+ uint32 rx9mbps; /**< packets rx at 9Mbps */
+ uint32 rx11mbps; /**< packets rx at 11Mbps */
+ uint32 rx12mbps; /**< packets rx at 12Mbps */
+ uint32 rx18mbps; /**< packets rx at 18Mbps */
+ uint32 rx24mbps; /**< packets rx at 24Mbps */
+ uint32 rx36mbps; /**< packets rx at 36Mbps */
+ uint32 rx48mbps; /**< packets rx at 48Mbps */
+ uint32 rx54mbps; /**< packets rx at 54Mbps */
+ uint32 rx108mbps; /**< packets rx at 108mbps */
+ uint32 rx162mbps; /**< packets rx at 162mbps */
+ uint32 rx216mbps; /**< packets rx at 216 mbps */
+ uint32 rx270mbps; /**< packets rx at 270 mbps */
+ uint32 rx324mbps; /**< packets rx at 324 mbps */
+ uint32 rx378mbps; /**< packets rx at 378 mbps */
+ uint32 rx432mbps; /**< packets rx at 432 mbps */
+ uint32 rx486mbps; /**< packets rx at 486 mbps */
+ uint32 rx540mbps; /**< packets rx at 540 mbps */
+
+ /* pkteng rx frame stats */
+ uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */
+ uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */
+
+ uint32 rfdisable; /**< count of radio disables */
+ uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */
+ uint32 bphy_badplcp;
+
+ uint32 txmpdu_sgi; /**< count for sgi transmit */
+ uint32 rxmpdu_sgi; /**< count for sgi received */
+ uint32 txmpdu_stbc; /**< count for stbc transmit */
+ uint32 rxmpdu_stbc; /**< count for stbc received */
+
+ uint32 rxdrop20s; /**< drop secondary cnt */
+} wl_cnt_ver_6_t;
+
+#define WL_DELTA_STATS_T_VERSION 2 /**< current version of wl_delta_stats_t struct */
+
+typedef struct {
+ uint16 version; /**< see definition of WL_DELTA_STATS_T_VERSION */
+ uint16 length; /**< length of entire structure */
+
+ /* transmit stat counters */
+ uint32 txframe; /**< tx data frames */
+ uint32 txbyte; /**< tx data bytes */
+ uint32 txretrans; /**< tx mac retransmits */
+ uint32 txfail; /**< tx failures */
+
+ /* receive stat counters */
+ uint32 rxframe; /**< rx data frames */
+ uint32 rxbyte; /**< rx data bytes */
+
+ /* per-rate receive stat counters */
+ uint32 rx1mbps; /**< packets rx at 1Mbps */
+ uint32 rx2mbps; /**< packets rx at 2Mbps */
+ uint32 rx5mbps5; /**< packets rx at 5.5Mbps */
+ uint32 rx6mbps; /**< packets rx at 6Mbps */
+ uint32 rx9mbps; /**< packets rx at 9Mbps */
+ uint32 rx11mbps; /**< packets rx at 11Mbps */
+ uint32 rx12mbps; /**< packets rx at 12Mbps */
+ uint32 rx18mbps; /**< packets rx at 18Mbps */
+ uint32 rx24mbps; /**< packets rx at 24Mbps */
+ uint32 rx36mbps; /**< packets rx at 36Mbps */
+ uint32 rx48mbps; /**< packets rx at 48Mbps */
+ uint32 rx54mbps; /**< packets rx at 54Mbps */
+ uint32 rx108mbps; /**< packets rx at 108mbps */
+ uint32 rx162mbps; /**< packets rx at 162mbps */
+ uint32 rx216mbps; /**< packets rx at 216 mbps */
+ uint32 rx270mbps; /**< packets rx at 270 mbps */
+ uint32 rx324mbps; /**< packets rx at 324 mbps */
+ uint32 rx378mbps; /**< packets rx at 378 mbps */
+ uint32 rx432mbps; /**< packets rx at 432 mbps */
+ uint32 rx486mbps; /**< packets rx at 486 mbps */
+ uint32 rx540mbps; /**< packets rx at 540 mbps */
+
+ /* phy stats */
+ uint32 rxbadplcp;
+ uint32 rxcrsglitch;
+ uint32 bphy_rxcrsglitch;
+ uint32 bphy_badplcp;
+
+} wl_delta_stats_t;
+
+/* Partial statistics counter report */
+#define WL_CNT_CTL_MGT_FRAMES 0
+
+typedef struct {
+ uint16 type;
+ uint16 len;
+
+ /* detailed control/management frames */
+ uint32 txnull;
+ uint32 rxnull;
+ uint32 txqosnull;
+ uint32 rxqosnull;
+ uint32 txassocreq;
+ uint32 rxassocreq;
+ uint32 txreassocreq;
+ uint32 rxreassocreq;
+ uint32 txdisassoc;
+ uint32 rxdisassoc;
+ uint32 txassocrsp;
+ uint32 rxassocrsp;
+ uint32 txreassocrsp;
+ uint32 rxreassocrsp;
+ uint32 txauth;
+ uint32 rxauth;
+ uint32 txdeauth;
+ uint32 rxdeauth;
+ uint32 txprobereq;
+ uint32 rxprobereq;
+ uint32 txprobersp;
+ uint32 rxprobersp;
+ uint32 txaction;
+ uint32 rxaction;
+ uint32 txrts;
+ uint32 rxrts;
+ uint32 txcts;
+ uint32 rxcts;
+ uint32 txack;
+ uint32 rxack;
+ uint32 txbar;
+ uint32 rxbar;
+ uint32 txback;
+ uint32 rxback;
+ uint32 txpspoll;
+ uint32 rxpspoll;
+} wl_ctl_mgt_cnt_t;
+
+typedef struct {
+ uint32 packets;
+ uint32 bytes;
+} wl_traffic_stats_t;
+
+typedef struct {
+ uint16 version; /**< see definition of WL_WME_CNT_VERSION */
+ uint16 length; /**< length of entire structure */
+
+ wl_traffic_stats_t tx[AC_COUNT]; /**< Packets transmitted */
+ wl_traffic_stats_t tx_failed[AC_COUNT]; /**< Packets dropped or failed to transmit */
+ wl_traffic_stats_t rx[AC_COUNT]; /**< Packets received */
+ wl_traffic_stats_t rx_failed[AC_COUNT]; /**< Packets failed to receive */
+
+ wl_traffic_stats_t forward[AC_COUNT]; /**< Packets forwarded by AP */
+
+ wl_traffic_stats_t tx_expired[AC_COUNT]; /**< packets dropped due to lifetime expiry */
+
+} wl_wme_cnt_t;
+
+struct wl_msglevel2 {
+ uint32 low;
+ uint32 high;
+};
+
+#define WL_ICMP_IPV6_CFG_VERSION 1
+#define WL_ICMP_IPV6_CLEAR_ALL (1 << 0)
+
+typedef struct wl_icmp_ipv6_cfg {
+ uint16 version;
+ uint16 length;
+ uint16 fixed_length;
+ uint16 flags;
+ uint32 num_ipv6;
+ /* num_ipv6 to follow */
+ struct ipv6_addr host_ipv6[];
+} wl_icmp_ipv6_cfg_t;
+
+#define WL_ICMP_CFG_IPV6_FIXED_LEN OFFSETOF(wl_icmp_ipv6_cfg_t, host_ipv6)
+#define WL_ICMP_CFG_IPV6_LEN(count) (WL_ICMP_CFG_IPV6_FIXED_LEN + \
+ ((count) * sizeof(struct ipv6_addr)))
+
+typedef struct wl_mkeep_alive_pkt {
+ uint16 version; /* Version for mkeep_alive */
+ uint16 length; /* length of fixed parameters in the structure */
+ uint32 period_msec; /* high bit on means immediate send */
+ uint16 len_bytes;
+ uint8 keep_alive_id; /* 0 - 3 for N = 4 */
+ uint8 data[1];
+} wl_mkeep_alive_pkt_t;
+
+#define WL_MKEEP_ALIVE_VERSION 1
+#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data)
+#define WL_MKEEP_ALIVE_PRECISION 500
+#define WL_MKEEP_ALIVE_PERIOD_MASK 0x7FFFFFFF
+#define WL_MKEEP_ALIVE_IMMEDIATE 0x80000000
+
+/** TCP Keep-Alive conn struct */
+typedef struct wl_mtcpkeep_alive_conn_pkt {
+ struct ether_addr saddr; /**< src mac address */
+ struct ether_addr daddr; /**< dst mac address */
+ struct ipv4_addr sipaddr; /**< source IP addr */
+ struct ipv4_addr dipaddr; /**< dest IP addr */
+ uint16 sport; /**< src port */
+ uint16 dport; /**< dest port */
+ uint32 seq; /**< seq number */
+ uint32 ack; /**< ACK number */
+ uint16 tcpwin; /**< TCP window */
+} wl_mtcpkeep_alive_conn_pkt_t;
+
+/** TCP Keep-Alive interval struct */
+typedef struct wl_mtcpkeep_alive_timers_pkt {
+ uint16 interval; /**< interval timer */
+ uint16 retry_interval; /**< retry_interval timer */
+ uint16 retry_count; /**< retry_count */
+} wl_mtcpkeep_alive_timers_pkt_t;
+
+typedef struct wake_info {
+ uint32 wake_reason;
+ uint32 wake_info_len; /**< size of packet */
+ uint8 packet[1];
+} wake_info_t;
+
+typedef struct wake_pkt {
+ uint32 wake_pkt_len; /**< size of packet */
+ uint8 packet[1];
+} wake_pkt_t;
+
+
+#define WL_MTCPKEEP_ALIVE_VERSION 1
+
+#ifdef WLBA
+
+#define WLC_BA_CNT_VERSION 1 /**< current version of wlc_ba_cnt_t */
+
+/** block ack related stats */
+typedef struct wlc_ba_cnt {
+ uint16 version; /**< WLC_BA_CNT_VERSION */
+ uint16 length; /**< length of entire structure */
+
+ /* transmit stat counters */
+ uint32 txpdu; /**< pdus sent */
+ uint32 txsdu; /**< sdus sent */
+ uint32 txfc; /**< tx side flow controlled packets */
+ uint32 txfci; /**< tx side flow control initiated */
+ uint32 txretrans; /**< retransmitted pdus */
+ uint32 txbatimer; /**< ba resend due to timer */
+ uint32 txdrop; /**< dropped packets */
+ uint32 txaddbareq; /**< addba req sent */
+ uint32 txaddbaresp; /**< addba resp sent */
+ uint32 txdelba; /**< delba sent */
+ uint32 txba; /**< ba sent */
+ uint32 txbar; /**< bar sent */
+ uint32 txpad[4]; /**< future */
+
+ /* receive side counters */
+ uint32 rxpdu; /**< pdus recd */
+ uint32 rxqed; /**< pdus buffered before sending up */
+ uint32 rxdup; /**< duplicate pdus */
+ uint32 rxnobuf; /**< pdus discarded due to no buf */
+ uint32 rxaddbareq; /**< addba req recd */
+ uint32 rxaddbaresp; /**< addba resp recd */
+ uint32 rxdelba; /**< delba recd */
+ uint32 rxba; /**< ba recd */
+ uint32 rxbar; /**< bar recd */
+ uint32 rxinvba; /**< invalid ba recd */
+ uint32 rxbaholes; /**< ba recd with holes */
+ uint32 rxunexp; /**< unexpected packets */
+ uint32 rxpad[4]; /**< future */
+} wlc_ba_cnt_t;
+#endif /* WLBA */
+
+/** structure for per-tid ampdu control */
+struct ampdu_tid_control {
+ uint8 tid; /* tid */
+ uint8 enable; /* enable/disable */
+};
+
+/** struct for ampdu tx/rx aggregation control */
+struct ampdu_aggr {
+ int8 aggr_override; /**< aggr overrided by dongle. Not to be set by host. */
+ uint16 conf_TID_bmap; /**< bitmap of TIDs to configure */
+ uint16 enab_TID_bmap; /**< enable/disable per TID */
+};
+
+/** structure for identifying ea/tid for sending addba/delba */
+struct ampdu_ea_tid {
+ struct ether_addr ea; /**< Station address */
+ uint8 tid; /**< tid */
+ uint8 initiator; /**< 0 is recipient, 1 is originator */
+};
+
+/** structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */
+struct ampdu_retry_tid {
+ uint8 tid; /**< tid */
+ uint8 retry; /**< retry value */
+};
+
+#define BDD_FNAME_LEN 32 /**< Max length of friendly name */
+typedef struct bdd_fname {
+ uint8 len; /**< length of friendly name */
+ uchar name[BDD_FNAME_LEN]; /**< friendly name */
+} bdd_fname_t;
+
+/* structure for addts arguments */
+/** For ioctls that take a list of TSPEC */
+struct tslist {
+ int32 count; /**< number of tspecs */
+ struct tsinfo_arg tsinfo[1]; /**< variable length array of tsinfo */
+};
+
+#ifdef WLTDLS
+/**structure for tdls iovars */
+typedef struct tdls_iovar {
+ struct ether_addr ea; /**< Station address */
+ uint8 mode; /**< mode: depends on iovar */
+ chanspec_t chanspec;
+ uint32 pad; /**< future */
+} tdls_iovar_t;
+
+#define TDLS_WFD_IE_SIZE 512
+/**structure for tdls wfd ie */
+typedef struct tdls_wfd_ie_iovar {
+ struct ether_addr ea; /**< Station address */
+ uint8 mode;
+ uint16 length;
+ uint8 data[TDLS_WFD_IE_SIZE];
+} tdls_wfd_ie_iovar_t;
+#endif /* WLTDLS */
+
+/** structure for addts/delts arguments */
+typedef struct tspec_arg {
+ uint16 version; /**< see definition of TSPEC_ARG_VERSION */
+ uint16 length; /**< length of entire structure */
+ uint32 flag; /**< bit field */
+ /* TSPEC Arguments */
+ struct tsinfo_arg tsinfo; /**< TS Info bit field */
+ uint16 nom_msdu_size; /**< (Nominal or fixed) MSDU Size (bytes) */
+ uint16 max_msdu_size; /**< Maximum MSDU Size (bytes) */
+ uint32 min_srv_interval; /**< Minimum Service Interval (us) */
+ uint32 max_srv_interval; /**< Maximum Service Interval (us) */
+ uint32 inactivity_interval; /**< Inactivity Interval (us) */
+ uint32 suspension_interval; /**< Suspension Interval (us) */
+ uint32 srv_start_time; /**< Service Start Time (us) */
+ uint32 min_data_rate; /**< Minimum Data Rate (bps) */
+ uint32 mean_data_rate; /**< Mean Data Rate (bps) */
+ uint32 peak_data_rate; /**< Peak Data Rate (bps) */
+ uint32 max_burst_size; /**< Maximum Burst Size (bytes) */
+ uint32 delay_bound; /**< Delay Bound (us) */
+ uint32 min_phy_rate; /**< Minimum PHY Rate (bps) */
+ uint16 surplus_bw; /**< Surplus Bandwidth Allowance (range 1.0 to 8.0) */
+ uint16 medium_time; /**< Medium Time (32 us/s periods) */
+ uint8 dialog_token; /**< dialog token */
+} tspec_arg_t;
+
+/** tspec arg for desired station */
+typedef struct tspec_per_sta_arg {
+ struct ether_addr ea;
+ struct tspec_arg ts;
+} tspec_per_sta_arg_t;
+
+/** structure for max bandwidth for each access category */
+typedef struct wme_max_bandwidth {
+ uint32 ac[AC_COUNT]; /**< max bandwidth for each access category */
+} wme_max_bandwidth_t;
+
+#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t))
+
+/* current version of wl_tspec_arg_t struct */
+#define TSPEC_ARG_VERSION 2 /**< current version of wl_tspec_arg_t struct */
+#define TSPEC_ARG_LENGTH 55 /**< argument length from tsinfo to medium_time */
+#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /**< default dialog token */
+#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /**< default surplus bw */
+
+
+#define WL_WOWL_KEEPALIVE_MAX_PACKET_SIZE 80
+#define WLC_WOWL_MAX_KEEPALIVE 2
+
+/** Packet lifetime configuration per ac */
+typedef struct wl_lifetime {
+ uint32 ac; /**< access class */
+ uint32 lifetime; /**< Packet lifetime value in ms */
+} wl_lifetime_t;
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/** Management time configuration */
+typedef struct wl_lifetime_mg {
+ uint32 mgmt_bitmap; /**< Mgmt subtype */
+ uint32 lifetime; /**< Packet lifetime value in us */
+} wl_lifetime_mg_t;
+
+#if defined(BCMDBG) || defined(BCMDBG_DUMP) || defined(BCMDBG_PHYDUMP) || \
+ defined(TDLS_TESTBED) || defined(BCMDBG_AMPDU) || defined(BCMDBG_TXBF) || \
+ defined(BCMDBG_DUMP_RSSI) || defined(MCHAN_MINIDUMP)
+/* MAC Sample Capture related */
+#define WL_MACCAPTR_DEFSTART_PTR 0xA00
+#define WL_MACCAPTR_DEFSTOP_PTR 0xA3F
+#define WL_MACCAPTR_DEFSZ 0x3F
+
+#define WL_MACCAPTR_DEF_MASK 0xFFFFFFFF
+
+typedef enum {
+ WL_MACCAPT_TRIG = 0,
+ WL_MACCAPT_STORE = 1,
+ WL_MACCAPT_TRANS = 2,
+ WL_MACCAPT_MATCH = 3
+} maccaptr_optn;
+
+typedef enum {
+ WL_MACCAPT_STRT = 1,
+ WL_MACCAPT_STOP = 2,
+ WL_MACCAPT_RST = 3
+} maccaptr_cmd_t;
+
+/* MAC Sample Capture Set-up Paramters */
+typedef struct wl_maccapture_params {
+ uint8 gpio_sel;
+ uint8 la_mode; /* TRUE: GPIO Out Enabled */
+ uint32 start_ptr; /* Start address to store */
+ uint32 stop_ptr; /* Stop address to store */
+ uint8 optn_bmp; /* Options */
+ uint32 tr_mask; /* Trigger Mask */
+ uint32 tr_val; /* Trigger Value */
+ uint32 s_mask; /* Store Mode Mask */
+ uint32 x_mask; /* Trans. Mode Mask */
+ uint32 m_mask; /* Match Mode Mask */
+ uint32 m_val; /* Match Value */
+ maccaptr_cmd_t cmd; /* Start / Stop */
+} wl_maccapture_params_t;
+#endif
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/** Channel Switch Announcement param */
+typedef struct wl_chan_switch {
+ uint8 mode; /**< value 0 or 1 */
+ uint8 count; /**< count # of beacons before switching */
+ chanspec_t chspec; /**< chanspec */
+ uint8 reg; /**< regulatory class */
+ uint8 frame_type; /**< csa frame type, unicast or broadcast */
+} wl_chan_switch_t;
+
+enum {
+ PFN_LIST_ORDER,
+ PFN_RSSI
+};
+
+enum {
+ DISABLE,
+ ENABLE
+};
+
+enum {
+ OFF_ADAPT,
+ SMART_ADAPT,
+ STRICT_ADAPT,
+ SLOW_ADAPT
+};
+
+#define SORT_CRITERIA_BIT 0
+#define AUTO_NET_SWITCH_BIT 1
+#define ENABLE_BKGRD_SCAN_BIT 2
+#define IMMEDIATE_SCAN_BIT 3
+#define AUTO_CONNECT_BIT 4
+#define ENABLE_BD_SCAN_BIT 5
+#define ENABLE_ADAPTSCAN_BIT 6
+#define IMMEDIATE_EVENT_BIT 8
+#define SUPPRESS_SSID_BIT 9
+#define ENABLE_NET_OFFLOAD_BIT 10
+/** report found/lost events for SSID and BSSID networks seperately */
+#define REPORT_SEPERATELY_BIT 11
+
+#define SORT_CRITERIA_MASK 0x0001
+#define AUTO_NET_SWITCH_MASK 0x0002
+#define ENABLE_BKGRD_SCAN_MASK 0x0004
+#define IMMEDIATE_SCAN_MASK 0x0008
+#define AUTO_CONNECT_MASK 0x0010
+
+#define ENABLE_BD_SCAN_MASK 0x0020
+#define ENABLE_ADAPTSCAN_MASK 0x00c0
+#define IMMEDIATE_EVENT_MASK 0x0100
+#define SUPPRESS_SSID_MASK 0x0200
+#define ENABLE_NET_OFFLOAD_MASK 0x0400
+/** report found/lost events for SSID and BSSID networks seperately */
+#define REPORT_SEPERATELY_MASK 0x0800
+
+#define PFN_VERSION 2
+
+#define PFN_COMPLETE 1
+#define PFN_INCOMPLETE 0
+
+#define DEFAULT_BESTN 2
+#define DEFAULT_MSCAN 0
+#define DEFAULT_REPEAT 10
+#define DEFAULT_EXP 2
+
+#define PFN_PARTIAL_SCAN_BIT 0
+#define PFN_PARTIAL_SCAN_MASK 1
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define PFN_SWC_RSSI_WINDOW_MAX 8
+#define PFN_SWC_MAX_NUM_APS 16
+#define PFN_HOTLIST_MAX_NUM_APS 64
+
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* Version 1 and 2 for various scan results structures defined below */
+#define PFN_SCANRESULTS_VERSION_V1 1
+#define PFN_SCANRESULTS_VERSION_V2 2
+
+/** PFN network info structure */
+typedef struct wl_pfn_subnet_info_v1 {
+ struct ether_addr BSSID;
+ uint8 channel; /**< channel number only */
+ uint8 SSID_len;
+ uint8 SSID[32];
+} wl_pfn_subnet_info_v1_t;
+
+typedef struct wl_pfn_subnet_info_v2 {
+ struct ether_addr BSSID;
+ uint8 channel; /**< channel number only */
+ uint8 SSID_len;
+ union {
+ uint8 SSID[32];
+ uint16 index;
+ } u;
+} wl_pfn_subnet_info_v2_t;
+
+typedef struct wl_pfn_net_info_v1 {
+ wl_pfn_subnet_info_v1_t pfnsubnet;
+ int16 RSSI; /**< receive signal strength (in dBm) */
+ uint16 timestamp; /**< age in seconds */
+} wl_pfn_net_info_v1_t;
+
+typedef struct wl_pfn_net_info_v2 {
+ wl_pfn_subnet_info_v2_t pfnsubnet;
+ int16 RSSI; /**< receive signal strength (in dBm) */
+ uint16 timestamp; /**< age in seconds */
+} wl_pfn_net_info_v2_t;
+
+/* Version 1 and 2 for various lbest scan results structures below */
+#define PFN_LBEST_SCAN_RESULT_VERSION_V1 1
+#define PFN_LBEST_SCAN_RESULT_VERSION_V2 2
+
+#define MAX_CHBKT_PER_RESULT 4
+
+typedef struct wl_pfn_lnet_info_v1 {
+ wl_pfn_subnet_info_v1_t pfnsubnet; /**< BSSID + channel + SSID len + SSID */
+ uint16 flags; /**< partial scan, etc */
+ int16 RSSI; /**< receive signal strength (in dBm) */
+ uint32 timestamp; /**< age in miliseconds */
+ uint16 rtt0; /**< estimated distance to this AP in centimeters */
+ uint16 rtt1; /**< standard deviation of the distance to this AP in centimeters */
+} wl_pfn_lnet_info_v1_t;
+
+typedef struct wl_pfn_lnet_info_v2 {
+ wl_pfn_subnet_info_v2_t pfnsubnet; /**< BSSID + channel + SSID len + SSID */
+ uint16 flags; /**< partial scan, etc */
+ int16 RSSI; /**< receive signal strength (in dBm) */
+ uint32 timestamp; /**< age in miliseconds */
+ uint16 rtt0; /**< estimated distance to this AP in centimeters */
+ uint16 rtt1; /**< standard deviation of the distance to this AP in centimeters */
+} wl_pfn_lnet_info_v2_t;
+
+typedef struct wl_pfn_lscanresults_v1 {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ wl_pfn_lnet_info_v1_t netinfo[1];
+} wl_pfn_lscanresults_v1_t;
+
+typedef struct wl_pfn_lscanresults_v2 {
+ uint32 version;
+ uint16 status;
+ uint16 count;
+ uint32 scan_ch_buckets[MAX_CHBKT_PER_RESULT];
+ wl_pfn_lnet_info_v2_t netinfo[1];
+} wl_pfn_lscanresults_v2_t;
+
+/**this is used to report on 1-* pfn scan results */
+typedef struct wl_pfn_scanresults_v1 {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ wl_pfn_net_info_v1_t netinfo[1];
+} wl_pfn_scanresults_v1_t;
+
+typedef struct wl_pfn_scanresults_v2 {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ uint32 scan_ch_bucket;
+ wl_pfn_net_info_v2_t netinfo[1];
+} wl_pfn_scanresults_v2_t;
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+typedef struct wl_pfn_significant_net {
+ uint16 flags;
+ uint16 channel;
+ struct ether_addr BSSID;
+ int8 rssi[PFN_SWC_RSSI_WINDOW_MAX];
+} wl_pfn_significant_net_t;
+
+#define PFN_SWC_SCANRESULT_VERSION 1
+
+typedef struct wl_pfn_swc_results {
+ uint32 version;
+ uint32 pkt_count; /**< No. of results in current frame */
+ uint32 total_count; /**< Total expected results */
+ wl_pfn_significant_net_t list[1];
+} wl_pfn_swc_results_t;
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+typedef struct wl_pfn_net_info_bssid {
+ struct ether_addr BSSID;
+ uint8 channel; /**< channel number only */
+ int8 RSSI; /**< receive signal strength (in dBm) */
+ uint16 flags; /**< (e.g. partial scan, off channel) */
+ uint16 timestamp; /**< age in seconds */
+} wl_pfn_net_info_bssid_t;
+
+typedef struct wl_pfn_scanhist_bssid {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ wl_pfn_net_info_bssid_t netinfo[1];
+} wl_pfn_scanhist_bssid_t;
+
+/* Version 1 and 2 for various single scan result */
+#define PFN_SCANRESULT_VERSION_V1 1
+#define PFN_SCANRESULT_VERSION_V2 2
+
+/* used to report exactly one scan result */
+/* plus reports detailed scan info in bss_info */
+typedef struct wl_pfn_scanresult_v1 {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ wl_pfn_net_info_v1_t netinfo;
+ wl_bss_info_t bss_info;
+} wl_pfn_scanresult_v1_t;
+
+typedef struct wl_pfn_scanresult_v2 {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ wl_pfn_net_info_v2_t netinfo;
+ wl_bss_info_t bss_info;
+} wl_pfn_scanresult_v2_t;
+
+/**PFN data structure */
+typedef struct wl_pfn_param {
+ int32 version; /**< PNO parameters version */
+ int32 scan_freq; /**< Scan frequency */
+ int32 lost_network_timeout; /**< Timeout in sec. to declare
+ * discovered network as lost
+ */
+ int16 flags; /**< Bit field to control features
+ * of PFN such as sort criteria auto
+ * enable switch and background scan
+ */
+ int16 rssi_margin; /**< Margin to avoid jitter for choosing a
+ * PFN based on RSSI sort criteria
+ */
+ uint8 bestn; /**< number of best networks in each scan */
+ uint8 mscan; /**< number of scans recorded */
+ uint8 repeat; /**< Minimum number of scan intervals
+ *before scan frequency changes in adaptive scan
+ */
+ uint8 exp; /**< Exponent of 2 for maximum scan interval */
+ int32 slow_freq; /**< slow scan period */
+} wl_pfn_param_t;
+
+typedef struct wl_pfn_bssid {
+ struct ether_addr macaddr;
+ /* Bit4: suppress_lost, Bit3: suppress_found */
+ uint16 flags;
+} wl_pfn_bssid_t;
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+typedef struct wl_pfn_significant_bssid {
+ struct ether_addr macaddr;
+ int8 rssi_low_threshold;
+ int8 rssi_high_threshold;
+} wl_pfn_significant_bssid_t;
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#define WL_PFN_SUPPRESSFOUND_MASK 0x08
+#define WL_PFN_SUPPRESSLOST_MASK 0x10
+#define WL_PFN_SSID_IMPRECISE_MATCH 0x80
+#define WL_PFN_SSID_SAME_NETWORK 0x10000
+#define WL_PFN_SUPPRESS_AGING_MASK 0x20000
+#define WL_PFN_FLUSH_ALL_SSIDS 0x40000
+
+#define WL_PFN_IOVAR_FLAG_MASK 0xFFFF00F
+#define WL_PFN_RSSI_MASK 0xff00
+#define WL_PFN_RSSI_SHIFT 8
+
+typedef struct wl_pfn_cfg {
+ uint32 reporttype;
+ int32 channel_num;
+ uint16 channel_list[WL_NUMCHANNELS];
+ uint32 flags;
+} wl_pfn_cfg_t;
+
+#define WL_PFN_SSID_CFG_VERSION 1
+#define WL_PFN_SSID_CFG_CLEAR 0x1
+
+typedef struct wl_ssid_ext_params {
+ int8 min5G_rssi; /* minimum 5GHz RSSI for a BSSID to be considered */
+ int8 min2G_rssi; /* minimum 2.4GHz RSSI for a BSSID to be considered */
+ int16 init_score_max; /* The maximum score that a network can have before bonuses */
+ int16 cur_bssid_bonus; /* Add to current bssid */
+ int16 same_ssid_bonus; /* score bonus for all networks with the same network flag */
+ int16 secure_bonus; /* score bonus for networks that are not open */
+ int16 band_5g_bonus;
+} wl_ssid_ext_params_t;
+
+typedef struct wl_pfn_ssid_cfg {
+ uint16 version;
+ uint16 flags;
+ wl_ssid_ext_params_t params;
+} wl_pfn_ssid_cfg_t;
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define CH_BUCKET_REPORT_NONE 0
+#define CH_BUCKET_REPORT_SCAN_COMPLETE_ONLY 1
+#define CH_BUCKET_REPORT_FULL_RESULT 2
+#define CH_BUCKET_REPORT_SCAN_COMPLETE (CH_BUCKET_REPORT_SCAN_COMPLETE_ONLY | \
+ CH_BUCKET_REPORT_FULL_RESULT)
+#define CH_BUCKET_REPORT_REGULAR 0
+#define CH_BUCKET_GSCAN 4
+
+typedef struct wl_pfn_gscan_ch_bucket_cfg {
+ uint8 bucket_end_index;
+ uint8 bucket_freq_multiple;
+ uint8 flag;
+ uint8 reserved;
+ uint16 repeat;
+ uint16 max_freq_multiple;
+} wl_pfn_gscan_ch_bucket_cfg_t;
+
+typedef struct wl_pfn_capabilities {
+ uint16 max_mscan;
+ uint16 max_bestn;
+ uint16 max_swc_bssid;
+ uint16 max_hotlist_bssid;
+} wl_pfn_capabilities_t;
+
+#define GSCAN_SEND_ALL_RESULTS_MASK (1 << 0)
+#define GSCAN_ALL_BUCKETS_IN_FIRST_SCAN_MASK (1 << 3)
+#define GSCAN_CFG_FLAGS_ONLY_MASK (1 << 7)
+#define WL_GSCAN_CFG_VERSION 1
+typedef struct wl_pfn_gscan_cfg {
+ uint16 version;
+ /**
+ * BIT0 1 = send probes/beacons to HOST
+ * BIT1 Reserved
+ * BIT2 Reserved
+ * Add any future flags here
+ * BIT7 1 = no other useful cfg sent
+ */
+ uint8 flags;
+ /** Buffer filled threshold in % to generate an event */
+ uint8 buffer_threshold;
+ /**
+ * No. of BSSIDs with "change" to generate an evt
+ * change - crosses rssi threshold/lost
+ */
+ uint8 swc_nbssid_threshold;
+ /* Max=8 (for now) Size of rssi cache buffer */
+ uint8 swc_rssi_window_size;
+ uint8 count_of_channel_buckets;
+ uint8 retry_threshold;
+ uint16 lost_ap_window;
+ wl_pfn_gscan_ch_bucket_cfg_t channel_bucket[1];
+} wl_pfn_gscan_cfg_t;
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+#define WL_PFN_REPORT_ALLNET 0
+#define WL_PFN_REPORT_SSIDNET 1
+#define WL_PFN_REPORT_BSSIDNET 2
+
+#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */
+#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /**< Remaining reserved for future use */
+
+typedef struct wl_pfn {
+ wlc_ssid_t ssid; /**< ssid name and its length */
+ int32 flags; /**< bit2: hidden */
+ int32 infra; /**< BSS Vs IBSS */
+ int32 auth; /**< Open Vs Closed */
+ int32 wpa_auth; /**< WPA type */
+ int32 wsec; /**< wsec value */
+} wl_pfn_t;
+
+typedef struct wl_pfn_list {
+ uint32 version;
+ uint32 enabled;
+ uint32 count;
+ wl_pfn_t pfn[1];
+} wl_pfn_list_t;
+
+#define WL_PFN_HIDDEN_BIT 2
+#define WL_PFN_HIDDEN_MASK 0x4
+
+#ifndef BESTN_MAX
+#define BESTN_MAX 10
+#endif
+
+#ifndef MSCAN_MAX
+#define MSCAN_MAX 90
+#endif
+
+/* Dynamic scan configuration for motion profiles */
+
+#define WL_PFN_MPF_VERSION 1
+
+/* Valid group IDs, may be expanded in the future */
+#define WL_PFN_MPF_GROUP_SSID 0
+#define WL_PFN_MPF_GROUP_BSSID 1
+#define WL_PFN_MPF_MAX_GROUPS 2
+
+/* Max number of MPF states supported in this time */
+#define WL_PFN_MPF_STATES_MAX 4
+
+/* Flags for the mpf-specific stuff */
+#define WL_PFN_MPF_ADAPT_ON_BIT 0
+#define WL_PFN_MPF_ADAPTSCAN_BIT 1
+
+#define WL_PFN_MPF_ADAPT_ON_MASK 0x0001
+#define WL_PFN_MPF_ADAPTSCAN_MASK 0x0006
+
+/* Per-state timing values */
+typedef struct wl_pfn_mpf_state_params {
+ int32 scan_freq; /* Scan frequency (secs) */
+ int32 lost_network_timeout; /* Timeout to declare net lost (secs) */
+ int16 flags; /* Space for flags: ADAPT etc */
+ uint8 exp; /* Exponent of 2 for max interval for SMART/STRICT_ADAPT */
+ uint8 repeat; /* Number of scans before changing adaptation level */
+ int32 slow_freq; /* Slow scan period for SLOW_ADAPT */
+} wl_pfn_mpf_state_params_t;
+
+typedef struct wl_pfn_mpf_param {
+ uint16 version; /* Structure version */
+ uint16 groupid; /* Group ID: 0 (SSID), 1 (BSSID), other: reserved */
+ wl_pfn_mpf_state_params_t state[WL_PFN_MPF_STATES_MAX];
+} wl_pfn_mpf_param_t;
+
+/* Structure for setting pfn_override iovar */
+typedef struct wl_pfn_override_param {
+ uint16 version; /* Structure version */
+ uint16 start_offset; /* Seconds from now to apply new params */
+ uint16 duration; /* Seconds to keep new params applied */
+ uint16 reserved;
+ wl_pfn_mpf_state_params_t override;
+} wl_pfn_override_param_t;
+#define WL_PFN_OVERRIDE_VERSION 1
+
+/*
+ * Definitions for base MPF configuration
+ */
+
+#define WL_MPF_VERSION 1
+#define WL_MPF_MAX_BITS 3
+#define WL_MPF_MAX_STATES (1 << WL_MPF_MAX_BITS)
+
+#define WL_MPF_STATE_NAME_MAX 12
+
+typedef struct wl_mpf_val {
+ uint16 val; /* Value of GPIO bits */
+ uint16 state; /* State identifier */
+ char name[WL_MPF_STATE_NAME_MAX]; /* Optional name */
+} wl_mpf_val_t;
+
+typedef struct wl_mpf_map {
+ uint16 version;
+ uint16 type;
+ uint16 mask; /* Which GPIO bits to use */
+ uint8 count; /* Count of state/value mappings */
+ uint8 PAD1;
+ wl_mpf_val_t vals[WL_MPF_MAX_STATES];
+} wl_mpf_map_t;
+
+#define WL_MPF_STATE_AUTO (0xFFFF) /* (uint16)-1) */
+
+typedef struct wl_mpf_state {
+ uint16 version;
+ uint16 type;
+ uint16 state; /* Get/Set */
+ uint8 force; /* 0 - auto (HW) state, 1 - forced state */
+ char name[WL_MPF_STATE_NAME_MAX]; /* Get/Set: Optional/actual name */
+} wl_mpf_state_t;
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/*
+ * WLFCTS definition
+ */
+typedef struct wl_txstatus_additional_info {
+ uint32 rspec;
+ uint32 enq_ts;
+ uint32 last_ts;
+ uint32 entry_ts;
+ uint16 seq;
+ uint8 rts_cnt;
+ uint8 tx_cnt;
+} wl_txstatus_additional_info_t;
+
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/** Service discovery */
+typedef struct {
+ uint8 transaction_id; /**< Transaction id */
+ uint8 protocol; /**< Service protocol type */
+ uint16 query_len; /**< Length of query */
+ uint16 response_len; /**< Length of response */
+ uint8 qrbuf[1];
+} wl_p2po_qr_t;
+
+typedef struct {
+ uint16 period; /**< extended listen period */
+ uint16 interval; /**< extended listen interval */
+ uint16 count; /* count to repeat */
+ uint16 pad; /* pad for 32bit align */
+} wl_p2po_listen_t;
+
+/** GAS state machine tunable parameters. Structure field values of 0 means use the default. */
+typedef struct wl_gas_config {
+ uint16 max_retransmit; /**< Max # of firmware/driver retransmits on no Ack
+ * from peer (on top of the ucode retries).
+ */
+ uint16 response_timeout; /**< Max time to wait for a GAS-level response
+ * after sending a packet.
+ */
+ uint16 max_comeback_delay; /**< Max GAS response comeback delay.
+ * Exceeding this fails the GAS exchange.
+ */
+ uint16 max_retries; /**< Max # of GAS state machine retries on failure
+ * of a GAS frame exchange.
+ */
+} wl_gas_config_t;
+
+/** P2P Find Offload parameters */
+typedef struct wl_p2po_find_config {
+ uint16 version; /**< Version of this struct */
+ uint16 length; /**< sizeof(wl_p2po_find_config_t) */
+ int32 search_home_time; /**< P2P search state home time when concurrent
+ * connection exists. -1 for default.
+ */
+ uint8 num_social_channels;
+ /**< Number of social channels up to WL_P2P_SOCIAL_CHANNELS_MAX.
+ * 0 means use default social channels.
+ */
+ uint8 flags;
+ uint16 social_channels[1]; /**< Variable length array of social channels */
+} wl_p2po_find_config_t;
+#define WL_P2PO_FIND_CONFIG_VERSION 2 /**< value for version field */
+
+/** wl_p2po_find_config_t flags */
+#define P2PO_FIND_FLAG_SCAN_ALL_APS 0x01 /**< Whether to scan for all APs in the p2po_find
+ * periodic scans of all channels.
+ * 0 means scan for only P2P devices.
+ * 1 means scan for P2P devices plus non-P2P APs.
+ */
+
+
+/** For adding a WFDS service to seek */
+typedef struct {
+ uint32 seek_hdl; /**< unique id chosen by host */
+ uint8 addr[6]; /**< Seek service from a specific device with this
+ * MAC address, all 1's for any device.
+ */
+ uint8 service_hash[P2P_WFDS_HASH_LEN];
+ uint8 service_name_len;
+ uint8 service_name[MAX_WFDS_SEEK_SVC_NAME_LEN];
+ /**< Service name to seek, not null terminated */
+ uint8 service_info_req_len;
+ uint8 service_info_req[1]; /**< Service info request, not null terminated.
+ * Variable length specified by service_info_req_len.
+ * Maximum length is MAX_WFDS_SEEK_SVC_INFO_LEN.
+ */
+} wl_p2po_wfds_seek_add_t;
+
+/** For deleting a WFDS service to seek */
+typedef struct {
+ uint32 seek_hdl; /**< delete service specified by id */
+} wl_p2po_wfds_seek_del_t;
+
+
+/** For adding a WFDS service to advertise */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 advertise_hdl; /**< unique id chosen by host */
+ uint8 service_hash[P2P_WFDS_HASH_LEN];
+ uint32 advertisement_id;
+ uint16 service_config_method;
+ uint8 service_name_len;
+ uint8 service_name[MAX_WFDS_SVC_NAME_LEN];
+ /**< Service name , not null terminated */
+ uint8 service_status;
+ uint16 service_info_len;
+ uint8 service_info[1]; /**< Service info, not null terminated.
+ * Variable length specified by service_info_len.
+ * Maximum length is MAX_WFDS_ADV_SVC_INFO_LEN.
+ */
+} BWL_POST_PACKED_STRUCT wl_p2po_wfds_advertise_add_t;
+#include <packed_section_end.h>
+
+/** For deleting a WFDS service to advertise */
+typedef struct {
+ uint32 advertise_hdl; /**< delete service specified by hdl */
+} wl_p2po_wfds_advertise_del_t;
+
+/** P2P Offload discovery mode for the p2po_state iovar */
+typedef enum {
+ WL_P2PO_DISC_STOP,
+ WL_P2PO_DISC_LISTEN,
+ WL_P2PO_DISC_DISCOVERY
+} disc_mode_t;
+
+/* ANQP offload */
+
+#define ANQPO_MAX_QUERY_SIZE 256
+typedef struct {
+ uint16 max_retransmit; /**< ~0 use default, max retransmit on no ACK from peer */
+ uint16 response_timeout; /**< ~0 use default, msec to wait for resp after tx packet */
+ uint16 max_comeback_delay; /**< ~0 use default, max comeback delay in resp else fail */
+ uint16 max_retries; /**< ~0 use default, max retries on failure */
+ uint16 query_len; /**< length of ANQP query */
+ uint8 query_data[1]; /**< ANQP encoded query (max ANQPO_MAX_QUERY_SIZE) */
+} wl_anqpo_set_t;
+
+typedef struct {
+ uint16 channel; /**< channel of the peer */
+ struct ether_addr addr; /**< addr of the peer */
+} wl_anqpo_peer_t;
+
+#define ANQPO_MAX_PEER_LIST 64
+typedef struct {
+ uint16 count; /**< number of peers in list */
+ wl_anqpo_peer_t peer[1]; /**< max ANQPO_MAX_PEER_LIST */
+} wl_anqpo_peer_list_t;
+
+#define ANQPO_MAX_IGNORE_SSID 64
+typedef struct {
+ uint8 is_clear; /**< set to clear list (not used on GET) */
+ uint16 count; /**< number of SSID in list */
+ wlc_ssid_t ssid[1]; /**< max ANQPO_MAX_IGNORE_SSID */
+} wl_anqpo_ignore_ssid_list_t;
+
+#define ANQPO_MAX_IGNORE_BSSID 64
+typedef struct {
+ uint8 is_clear; /**< set to clear list (not used on GET) */
+ uint16 count; /**< number of addr in list */
+ struct ether_addr bssid[1]; /**< max ANQPO_MAX_IGNORE_BSSID */
+} wl_anqpo_ignore_bssid_list_t;
+
+
+struct toe_ol_stats_t {
+ /** Num of tx packets that don't need to be checksummed */
+ uint32 tx_summed;
+
+ /* Num of tx packets where checksum is filled by offload engine */
+ uint32 tx_iph_fill;
+ uint32 tx_tcp_fill;
+ uint32 tx_udp_fill;
+ uint32 tx_icmp_fill;
+
+ /* Num of rx packets where toe finds out if checksum is good or bad */
+ uint32 rx_iph_good;
+ uint32 rx_iph_bad;
+ uint32 rx_tcp_good;
+ uint32 rx_tcp_bad;
+ uint32 rx_udp_good;
+ uint32 rx_udp_bad;
+ uint32 rx_icmp_good;
+ uint32 rx_icmp_bad;
+
+ /* Num of tx packets in which csum error is injected */
+ uint32 tx_tcp_errinj;
+ uint32 tx_udp_errinj;
+ uint32 tx_icmp_errinj;
+
+ /* Num of rx packets in which csum error is injected */
+ uint32 rx_tcp_errinj;
+ uint32 rx_udp_errinj;
+ uint32 rx_icmp_errinj;
+};
+
+/** Arp offload statistic counts */
+struct arp_ol_stats_t {
+ uint32 host_ip_entries; /**< Host IP table addresses (more than one if multihomed) */
+ uint32 host_ip_overflow; /**< Host IP table additions skipped due to overflow */
+
+ uint32 arp_table_entries; /**< ARP table entries */
+ uint32 arp_table_overflow; /**< ARP table additions skipped due to overflow */
+
+ uint32 host_request; /**< ARP requests from host */
+ uint32 host_reply; /**< ARP replies from host */
+ uint32 host_service; /**< ARP requests from host serviced by ARP Agent */
+
+ uint32 peer_request; /**< ARP requests received from network */
+ uint32 peer_request_drop; /**< ARP requests from network that were dropped */
+ uint32 peer_reply; /**< ARP replies received from network */
+ uint32 peer_reply_drop; /**< ARP replies from network that were dropped */
+ uint32 peer_service; /**< ARP request from host serviced by ARP Agent */
+};
+
+/** NS offload statistic counts */
+struct nd_ol_stats_t {
+ uint32 host_ip_entries; /**< Host IP table addresses (more than one if multihomed) */
+ uint32 host_ip_overflow; /**< Host IP table additions skipped due to overflow */
+ uint32 peer_request; /**< NS requests received from network */
+ uint32 peer_request_drop; /**< NS requests from network that were dropped */
+ uint32 peer_reply_drop; /**< NA replies from network that were dropped */
+ uint32 peer_service; /**< NS request from host serviced by firmware */
+};
+
+/*
+ * Neighbor Discovery Offloading
+ */
+enum {
+ WL_ND_IPV6_ADDR_TYPE_UNICAST = 0,
+ WL_ND_IPV6_ADDR_TYPE_ANYCAST
+};
+
+typedef struct wl_nd_host_ip_addr {
+ struct ipv6_addr ip_addr; /* host ip address */
+ uint8 type; /* type of address */
+ uint8 pad[3];
+} wl_nd_host_ip_addr_t;
+
+typedef struct wl_nd_host_ip_list {
+ uint32 count;
+ wl_nd_host_ip_addr_t host_ip[1];
+} wl_nd_host_ip_list_t;
+
+#define WL_ND_HOSTIP_IOV_VER 1
+
+enum {
+ WL_ND_HOSTIP_OP_VER = 0, /* get version */
+ WL_ND_HOSTIP_OP_ADD, /* add address */
+ WL_ND_HOSTIP_OP_DEL, /* delete specified address */
+ WL_ND_HOSTIP_OP_DEL_UC, /* delete all unicast address */
+ WL_ND_HOSTIP_OP_DEL_AC, /* delete all anycast address */
+ WL_ND_HOSTIP_OP_DEL_ALL, /* delete all addresses */
+ WL_ND_HOSTIP_OP_LIST, /* get list of host ip address */
+ WL_ND_HOSTIP_OP_MAX
+};
+
+typedef struct wl_nd_hostip {
+ uint16 version; /* version of iovar buf */
+ uint16 op_type; /* operation type */
+ uint32 length; /* length of entire structure */
+ union {
+ wl_nd_host_ip_addr_t host_ip; /* set param for add */
+ uint16 version; /* get return for ver */
+ } u;
+} wl_nd_hostip_t;
+
+#define WL_ND_HOSTIP_FIXED_LEN OFFSETOF(wl_nd_hostip_t, u)
+#define WL_ND_HOSTIP_WITH_ADDR_LEN (WL_ND_HOSTIP_FIXED_LEN + sizeof(wl_nd_host_ip_addr_t))
+
+/*
+ * Keep-alive packet offloading.
+ */
+
+/**
+ * NAT keep-alive packets format: specifies the re-transmission period, the packet
+ * length, and packet contents.
+ */
+typedef struct wl_keep_alive_pkt {
+ uint32 period_msec; /** Retransmission period (0 to disable packet re-transmits) */
+ uint16 len_bytes; /* Size of packet to transmit (0 to disable packet re-transmits) */
+ uint8 data[1]; /** Variable length packet to transmit. Contents should include
+ * entire ethernet packet (enet header, IP header, UDP header,
+ * and UDP payload) in network byte order.
+ */
+} wl_keep_alive_pkt_t;
+
+#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data)
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/*
+ * ptk_start: iovar to start 4-way handshake for secured ranging
+*/
+
+/* ptk negotiation security type - determines negotiation parameters */
+typedef enum {
+ WL_PTK_START_SEC_TYPE_PMK = 1
+} wl_ptk_start_sec_type_t;
+
+/* ptk negotiation role */
+enum {
+ ROLE_NONE = 0x0,
+ ROLE_AUTH = 0x1,
+ ROLE_SUP = 0x2,
+ ROLE_STATIC = 0x3,
+ ROLE_INVALID = 0xff
+};
+typedef int32 wl_ptk_start_role_t;
+
+typedef struct wl_ptk_start_tlv_v1 {
+ uint16 id;
+ uint16 len;
+ uint8 data[1];
+} wl_ptk_start_tlv_v1_t;
+
+typedef enum {
+ WL_PTK_START_TLV_PMK = 1 /* uint8[] */
+} wl_ptk_start_tlv_type;
+
+typedef enum {
+ WL_PTK_START_FLAG_NO_DATA_PROT = 1, /* data frame protection disabled */
+ WL_PTK_START_FLAG_GEN_FTM_TPK = 2 /* Generate FTM Toast/Seq Protection Key */
+} wl_ptk_start_flags_t;
+
+struct wl_ptk_start_iov_v1 {
+ uint16 version;
+ uint16 len; /* length of entire iov from version */
+ wl_ptk_start_flags_t flags;
+ wl_ptk_start_sec_type_t sec_type;
+ wl_ptk_start_role_t role;
+ struct ether_addr peer_addr;
+ uint16 pad; /* reserved/32 bit alignment */
+ wl_ptk_start_tlv_v1_t tlvs[1];
+};
+
+/*
+ * Dongle pattern matching filter.
+ */
+
+#define MAX_WAKE_PACKET_CACHE_BYTES 128 /**< Maximum cached wake packet */
+
+#define MAX_WAKE_PACKET_BYTES (DOT11_A3_HDR_LEN + \
+ DOT11_QOS_LEN + \
+ sizeof(struct dot11_llc_snap_header) + \
+ ETHER_MAX_DATA)
+
+typedef struct pm_wake_packet {
+ uint32 status; /**< Is the wake reason a packet (if all the other field's valid) */
+ uint32 pattern_id; /**< Pattern ID that matched */
+ uint32 original_packet_size;
+ uint32 saved_packet_size;
+ uint8 packet[MAX_WAKE_PACKET_CACHE_BYTES];
+} pm_wake_packet_t;
+
+/* Packet filter types. Currently, only pattern matching is supported. */
+typedef enum wl_pkt_filter_type {
+ WL_PKT_FILTER_TYPE_PATTERN_MATCH=0, /**< Pattern matching filter */
+ WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH=1, /**< Magic packet match */
+ WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH=2, /**< A pattern list (match all to match filter) */
+ WL_PKT_FILTER_TYPE_ENCRYPTED_PATTERN_MATCH=3, /**< SECURE WOWL magic / net pattern match */
+ WL_PKT_FILTER_TYPE_APF_MATCH=4, /* Android packet filter match */
+ WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT=5, /* Pattern matching filter with timeout event */
+ WL_PKT_FILTER_TYPE_IMMEDIATE_PATTERN_MATCH=6, /* Immediately pattern matching filter */
+} wl_pkt_filter_type_t;
+
+#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t
+
+/* String mapping for types that may be used by applications or debug */
+#define WL_PKT_FILTER_TYPE_NAMES \
+ { "PATTERN", WL_PKT_FILTER_TYPE_PATTERN_MATCH }, \
+ { "MAGIC", WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH }, \
+ { "PATLIST", WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH }, \
+ { "SECURE WOWL", WL_PKT_FILTER_TYPE_ENCRYPTED_PATTERN_MATCH }, \
+ { "APF", WL_PKT_FILTER_TYPE_APF_MATCH }, \
+ { "PATTERN TIMEOUT", WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT }, \
+ { "IMMEDIATE", WL_PKT_FILTER_TYPE_IMMEDIATE_PATTERN_MATCH }
+
+/** Secured WOWL packet was encrypted, need decrypted before check filter match */
+typedef struct wl_pkt_decrypter {
+ uint8* (*dec_cb)(void* dec_ctx, const void *sdu, int sending);
+ void* dec_ctx;
+} wl_pkt_decrypter_t;
+
+/**
+ * Pattern matching filter. Specifies an offset within received packets to
+ * start matching, the pattern to match, the size of the pattern, and a bitmask
+ * that indicates which bits within the pattern should be matched.
+ */
+typedef struct wl_pkt_filter_pattern {
+ uint32 offset; /**< Offset within received packet to start pattern matching.
+ * Offset '0' is the first byte of the ethernet header.
+ */
+ uint32 size_bytes; /**< Size of the pattern. Bitmask must be the same size. */
+ uint8 mask_and_pattern[1]; /**< Variable length mask and pattern data. mask starts
+ * at offset 0. Pattern immediately follows mask. for
+ * secured pattern, put the descrypter pointer to the
+ * beginning, mask and pattern postponed correspondingly
+ */
+} wl_pkt_filter_pattern_t;
+
+/** A pattern list is a numerically specified list of modified pattern structures. */
+typedef struct wl_pkt_filter_pattern_listel {
+ uint16 rel_offs; /**< Offset to begin match (relative to 'base' below) */
+ uint16 base_offs; /**< Base for offset (defined below) */
+ uint16 size_bytes; /**< Size of mask/pattern */
+ uint16 match_flags; /**< Addition flags controlling the match */
+ uint8 mask_and_data[1]; /**< Variable length mask followed by data, each size_bytes */
+} wl_pkt_filter_pattern_listel_t;
+
+typedef struct wl_pkt_filter_pattern_list {
+ uint8 list_cnt; /**< Number of elements in the list */
+ uint8 PAD1[1]; /**< Reserved (possible version: reserved) */
+ uint16 totsize; /**< Total size of this pattern list (includes this struct) */
+ wl_pkt_filter_pattern_listel_t patterns[1]; /**< Variable number of list elements */
+} wl_pkt_filter_pattern_list_t;
+
+typedef struct wl_apf_program {
+ uint16 version;
+ uint16 instr_len; /* number of instruction blocks */
+ uint32 inst_ts; /* program installation timestamp */
+ uint8 instrs[1]; /* variable length instructions */
+} wl_apf_program_t;
+
+typedef struct wl_pkt_filter_pattern_timeout {
+ uint32 offset; /* Offset within received packet to start pattern matching.
+ * Offset '0' is the first byte of the ethernet header.
+ */
+ uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */
+ uint32 timeout; /* Timeout(seconds) */
+ uint8 mask_and_pattern[1]; /* Variable length mask and pattern data.
+ * mask starts at offset 0. Pattern
+ * immediately follows mask.
+ */
+} wl_pkt_filter_pattern_timeout_t;
+
+/** IOVAR "pkt_filter_add" parameter. Used to install packet filters. */
+typedef struct wl_pkt_filter {
+ uint32 id; /**< Unique filter id, specified by app. */
+ uint32 type; /**< Filter type (WL_PKT_FILTER_TYPE_xxx). */
+ uint32 negate_match; /**< Negate the result of filter matches */
+ union { /* Filter definitions */
+ wl_pkt_filter_pattern_t pattern; /**< Pattern matching filter */
+ wl_pkt_filter_pattern_list_t patlist; /**< List of patterns to match */
+ wl_apf_program_t apf_program; /* apf program */
+ wl_pkt_filter_pattern_timeout_t pattern_timeout; /* Pattern timeout event filter */
+ } u;
+} wl_pkt_filter_t;
+
+/** IOVAR "tcp_keep_set" parameter. Used to install tcp keep_alive stuff. */
+typedef struct wl_tcp_keep_set {
+ uint32 val1;
+ uint32 val2;
+} wl_tcp_keep_set_t;
+
+#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u)
+#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern)
+#define WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_list_t, patterns)
+#define WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN \
+ OFFSETOF(wl_pkt_filter_pattern_listel_t, mask_and_data)
+#define WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN \
+ OFFSETOF(wl_pkt_filter_pattern_timeout_t, mask_and_pattern)
+
+#define WL_APF_INTERNAL_VERSION 1
+#define WL_APF_PROGRAM_FIXED_LEN OFFSETOF(wl_apf_program_t, instrs)
+#define WL_APF_PROGRAM_LEN(apf_program) \
+ ((apf_program)->instr_len * sizeof((apf_program)->instrs[0]))
+#define WL_APF_PROGRAM_TOTAL_LEN(apf_program) \
+ (WL_APF_PROGRAM_FIXED_LEN + WL_APF_PROGRAM_LEN(apf_program))
+
+/** IOVAR "pkt_filter_enable" parameter. */
+typedef struct wl_pkt_filter_enable {
+ uint32 id; /**< Unique filter id */
+ uint32 enable; /**< Enable/disable bool */
+} wl_pkt_filter_enable_t;
+
+/** IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */
+typedef struct wl_pkt_filter_list {
+ uint32 num; /**< Number of installed packet filters */
+ wl_pkt_filter_t filter[1]; /**< Variable array of packet filters. */
+} wl_pkt_filter_list_t;
+
+#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter)
+
+/** IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */
+typedef struct wl_pkt_filter_stats {
+ uint32 num_pkts_matched; /**< # filter matches for specified filter id */
+ uint32 num_pkts_forwarded; /**< # packets fwded from dongle to host for all filters */
+ uint32 num_pkts_discarded; /**< # packets discarded by dongle for all filters */
+} wl_pkt_filter_stats_t;
+
+/** IOVAR "pkt_filter_ports" parameter. Configure TCP/UDP port filters. */
+typedef struct wl_pkt_filter_ports {
+ uint8 version; /**< Be proper */
+ uint8 reserved; /**< Be really proper */
+ uint16 count; /**< Number of ports following */
+ /* End of fixed data */
+ uint16 ports[1]; /**< Placeholder for ports[<count>] */
+} wl_pkt_filter_ports_t;
+
+#define WL_PKT_FILTER_PORTS_FIXED_LEN OFFSETOF(wl_pkt_filter_ports_t, ports)
+
+#define WL_PKT_FILTER_PORTS_VERSION 0
+#define WL_PKT_FILTER_PORTS_MAX 128
+
+#define RSN_REPLAY_LEN 8
+typedef struct _gtkrefresh {
+ uint8 KCK[RSN_KCK_LENGTH];
+ uint8 KEK[RSN_KEK_LENGTH];
+ uint8 ReplayCounter[RSN_REPLAY_LEN];
+} gtk_keyinfo_t, *pgtk_keyinfo_t;
+
+/** Sequential Commands ioctl */
+typedef struct wl_seq_cmd_ioctl {
+ uint32 cmd; /**< common ioctl definition */
+ uint32 len; /**< length of user buffer */
+} wl_seq_cmd_ioctl_t;
+
+#define WL_SEQ_CMD_ALIGN_BYTES 4
+
+/**
+ * These are the set of get IOCTLs that should be allowed when using
+ * IOCTL sequence commands. These are issued implicitly by wl.exe each time
+ * it is invoked. We never want to buffer these, or else wl.exe will stop working.
+ */
+#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \
+ (((cmd) == WLC_GET_MAGIC) || \
+ ((cmd) == WLC_GET_VERSION) || \
+ ((cmd) == WLC_GET_AP) || \
+ ((cmd) == WLC_GET_INSTANCE))
+
+typedef struct wl_pkteng {
+ uint32 flags;
+ uint32 delay; /**< Inter-packet delay */
+ uint32 nframes; /**< Number of frames */
+ uint32 length; /**< Packet length */
+ uint8 seqno; /**< Enable/disable sequence no. */
+ struct ether_addr dest; /**< Destination address */
+ struct ether_addr src; /**< Source address */
+} wl_pkteng_t;
+
+typedef struct wl_pkteng_stats {
+ uint32 lostfrmcnt; /**< RX PER test: no of frames lost (skip seqno) */
+ int32 rssi; /**< RSSI */
+ int32 snr; /**< signal to noise ratio */
+ uint16 rxpktcnt[NUM_80211_RATES+1];
+ uint8 rssi_qdb; /**< qdB portion of the computed rssi */
+} wl_pkteng_stats_t;
+
+typedef struct wl_txcal_params {
+ wl_pkteng_t pkteng;
+ uint8 gidx_start;
+ int8 gidx_step;
+ uint8 gidx_stop;
+} wl_txcal_params_t;
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#if !defined(BCMDONGLEHOST)
+typedef struct wl_sslpnphy_papd_debug_data {
+ uint8 psat_pwr;
+ uint8 psat_indx;
+ uint8 final_idx;
+ uint8 start_idx;
+ int32 min_phase;
+ int32 voltage;
+ int8 temperature;
+} wl_sslpnphy_papd_debug_data_t;
+typedef struct wl_sslpnphy_debug_data {
+ int16 papdcompRe [64];
+ int16 papdcompIm [64];
+} wl_sslpnphy_debug_data_t;
+typedef struct wl_sslpnphy_spbdump_data {
+ uint16 tbl_length;
+ int16 spbreal[256];
+ int16 spbimg[256];
+} wl_sslpnphy_spbdump_data_t;
+typedef struct wl_sslpnphy_percal_debug_data {
+ uint32 cur_idx;
+ uint32 tx_drift;
+ uint8 prev_cal_idx;
+ uint32 percal_ctr;
+ int32 nxt_cal_idx;
+ uint32 force_1idxcal;
+ uint32 onedxacl_req;
+ int32 last_cal_volt;
+ int8 last_cal_temp;
+ uint32 vbat_ripple;
+ uint32 exit_route;
+ int32 volt_winner;
+} wl_sslpnphy_percal_debug_data_t;
+#endif
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+typedef enum {
+ wowl_pattern_type_bitmap = 0,
+ wowl_pattern_type_arp,
+ wowl_pattern_type_na
+} wowl_pattern_type_t;
+
+typedef struct wl_wowl_pattern {
+ uint32 masksize; /**< Size of the mask in #of bytes */
+ uint32 offset; /**< Pattern byte offset in packet */
+ uint32 patternoffset; /**< Offset of start of pattern in the structure */
+ uint32 patternsize; /**< Size of the pattern itself in #of bytes */
+ uint32 id; /**< id */
+ uint32 reasonsize; /**< Size of the wakeup reason code */
+ wowl_pattern_type_t type; /**< Type of pattern */
+ /* Mask follows the structure above */
+ /* Pattern follows the mask is at 'patternoffset' from the start */
+} wl_wowl_pattern_t;
+
+typedef struct wl_wowl_pattern_list {
+ uint32 count;
+ wl_wowl_pattern_t pattern[1];
+} wl_wowl_pattern_list_t;
+
+typedef struct wl_wowl_wakeind {
+ uint8 pci_wakeind; /**< Whether PCI PMECSR PMEStatus bit was set */
+ uint32 ucode_wakeind; /**< What wakeup-event indication was set by ucode */
+} wl_wowl_wakeind_t;
+
+typedef struct {
+ uint32 pktlen; /**< size of packet */
+ void *sdu;
+} tcp_keepalive_wake_pkt_infop_t;
+
+/** per AC rate control related data structure */
+typedef struct wl_txrate_class {
+ uint8 init_rate;
+ uint8 min_rate;
+ uint8 max_rate;
+} wl_txrate_class_t;
+
+/** structure for Overlap BSS scan arguments */
+typedef struct wl_obss_scan_arg {
+ int16 passive_dwell;
+ int16 active_dwell;
+ int16 bss_widthscan_interval;
+ int16 passive_total;
+ int16 active_total;
+ int16 chanwidth_transition_delay;
+ int16 activity_threshold;
+} wl_obss_scan_arg_t;
+
+#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t)
+
+/** RSSI event notification configuration. */
+typedef struct wl_rssi_event {
+ uint32 rate_limit_msec; /**< # of events posted to application will be limited to
+ * one per specified period (0 to disable rate limit).
+ */
+ uint8 num_rssi_levels; /**< Number of entries in rssi_levels[] below */
+ int8 rssi_levels[MAX_RSSI_LEVELS]; /**< Variable number of RSSI levels. An event
+ * will be posted each time the RSSI of received
+ * beacons/packets crosses a level.
+ */
+ int8 pad[3];
+} wl_rssi_event_t;
+
+#define RSSI_MONITOR_VERSION 1
+#define RSSI_MONITOR_STOP (1 << 0)
+typedef struct wl_rssi_monitor_cfg {
+ uint8 version;
+ uint8 flags;
+ int8 max_rssi;
+ int8 min_rssi;
+} wl_rssi_monitor_cfg_t;
+
+typedef struct wl_rssi_monitor_evt {
+ uint8 version;
+ int8 cur_rssi;
+ uint16 pad;
+} wl_rssi_monitor_evt_t;
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/* CCA based channel quality event configuration */
+#define WL_CHAN_QUAL_CCA 0
+#define WL_CHAN_QUAL_NF 1
+#define WL_CHAN_QUAL_NF_LTE 2
+#define WL_CHAN_QUAL_TOTAL 3
+
+#define MAX_CHAN_QUAL_LEVELS 8
+
+typedef struct wl_chan_qual_metric {
+ uint8 id; /**< metric ID */
+ uint8 num_levels; /**< Number of entries in rssi_levels[] below */
+ uint16 flags;
+ int16 htol[MAX_CHAN_QUAL_LEVELS]; /**< threshold level array: hi-to-lo */
+ int16 ltoh[MAX_CHAN_QUAL_LEVELS]; /**< threshold level array: lo-to-hi */
+} wl_chan_qual_metric_t;
+
+typedef struct wl_chan_qual_event {
+ uint32 rate_limit_msec; /**< # of events posted to application will be limited to
+ * one per specified period (0 to disable rate limit).
+ */
+ uint16 flags;
+ uint16 num_metrics;
+ wl_chan_qual_metric_t metric[WL_CHAN_QUAL_TOTAL]; /**< metric array */
+} wl_chan_qual_event_t;
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+typedef struct wl_action_obss_coex_req {
+ uint8 info;
+ uint8 num;
+ uint8 ch_list[1];
+} wl_action_obss_coex_req_t;
+
+
+/** IOVar parameter block for small MAC address array with type indicator */
+#define WL_IOV_MAC_PARAM_LEN 4
+
+#define WL_IOV_PKTQ_LOG_PRECS 16
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 num_addrs;
+ uint8 addr_type[WL_IOV_MAC_PARAM_LEN];
+ struct ether_addr ea[WL_IOV_MAC_PARAM_LEN];
+} BWL_POST_PACKED_STRUCT wl_iov_mac_params_t;
+#include <packed_section_end.h>
+
+/** This is extra info that follows wl_iov_mac_params_t */
+typedef struct {
+ uint32 addr_info[WL_IOV_MAC_PARAM_LEN];
+} wl_iov_mac_extra_params_t;
+
+/** Combined structure */
+typedef struct {
+ wl_iov_mac_params_t params;
+ wl_iov_mac_extra_params_t extra_params;
+} wl_iov_mac_full_params_t;
+
+/** Parameter block for PKTQ_LOG statistics */
+#define PKTQ_LOG_COUNTERS_V4 \
+ /* packets requested to be stored */ \
+ uint32 requested; \
+ /* packets stored */ \
+ uint32 stored; \
+ /* packets saved, because a lowest priority queue has given away one packet */ \
+ uint32 saved; \
+ /* packets saved, because an older packet from the same queue has been dropped */ \
+ uint32 selfsaved; \
+ /* packets dropped, because pktq is full with higher precedence packets */ \
+ uint32 full_dropped; \
+ /* packets dropped because pktq per that precedence is full */ \
+ uint32 dropped; \
+ /* packets dropped, in order to save one from a queue of a highest priority */ \
+ uint32 sacrificed; \
+ /* packets droped because of hardware/transmission error */ \
+ uint32 busy; \
+ /* packets re-sent because they were not received */ \
+ uint32 retry; \
+ /* packets retried again (ps pretend) prior to moving power save mode */ \
+ uint32 ps_retry; \
+ /* suppressed packet count */ \
+ uint32 suppress; \
+ /* packets finally dropped after retry limit */ \
+ uint32 retry_drop; \
+ /* the high-water mark of the queue capacity for packets - goes to zero as queue fills */ \
+ uint32 max_avail; \
+ /* the high-water mark of the queue utilisation for packets - ('inverse' of max_avail) */ \
+ uint32 max_used; \
+ /* the maximum capacity of the queue */ \
+ uint32 queue_capacity; \
+ /* count of rts attempts that failed to receive cts */ \
+ uint32 rtsfail; \
+ /* count of packets sent (acked) successfully */ \
+ uint32 acked; \
+ /* running total of phy rate of packets sent successfully */ \
+ uint32 txrate_succ; \
+ /* running total of phy 'main' rate */ \
+ uint32 txrate_main; \
+ /* actual data transferred successfully */ \
+ uint32 throughput; \
+ /* time difference since last pktq_stats */ \
+ uint32 time_delta;
+
+typedef struct {
+ PKTQ_LOG_COUNTERS_V4
+} pktq_log_counters_v04_t;
+
+/** v5 is the same as V4 with extra parameter */
+typedef struct {
+ PKTQ_LOG_COUNTERS_V4
+ /** cumulative time to transmit */
+ uint32 airtime;
+} pktq_log_counters_v05_t;
+
+typedef struct {
+ uint8 num_prec[WL_IOV_MAC_PARAM_LEN];
+ pktq_log_counters_v04_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS];
+ uint32 counter_info[WL_IOV_MAC_PARAM_LEN];
+ uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN];
+ char headings[1];
+} pktq_log_format_v04_t;
+
+typedef struct {
+ uint8 num_prec[WL_IOV_MAC_PARAM_LEN];
+ pktq_log_counters_v05_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS];
+ uint32 counter_info[WL_IOV_MAC_PARAM_LEN];
+ uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN];
+ char headings[1];
+} pktq_log_format_v05_t;
+
+
+typedef struct {
+ uint32 version;
+ wl_iov_mac_params_t params;
+ union {
+ pktq_log_format_v04_t v04;
+ pktq_log_format_v05_t v05;
+ } pktq_log;
+} wl_iov_pktq_log_t;
+
+/* PKTQ_LOG_AUTO, PKTQ_LOG_DEF_PREC flags introduced in v05, they are ignored by v04 */
+#define PKTQ_LOG_AUTO (1 << 31)
+#define PKTQ_LOG_DEF_PREC (1 << 30)
+
+typedef struct wl_pfn_macaddr_cfg_0 {
+ uint8 version;
+ uint8 reserved;
+ struct ether_addr macaddr;
+} wl_pfn_macaddr_cfg_0_t;
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define LEGACY1_WL_PFN_MACADDR_CFG_VER 0
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#define WL_PFN_MAC_OUI_ONLY_MASK 1
+#define WL_PFN_SET_MAC_UNASSOC_MASK 2
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_PFN_RESTRICT_LA_MAC_MASK 4
+#define WL_PFN_MACADDR_FLAG_MASK 0x7
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/** To configure pfn_macaddr */
+typedef struct wl_pfn_macaddr_cfg {
+ uint8 version;
+ uint8 flags;
+ struct ether_addr macaddr;
+} wl_pfn_macaddr_cfg_t;
+#define WL_PFN_MACADDR_CFG_VER 1
+
+/*
+ * SCB_BS_DATA iovar definitions start.
+ */
+#define SCB_BS_DATA_STRUCT_VERSION 1
+
+/** The actual counters maintained for each station */
+typedef struct {
+ /* The following counters are a subset of what pktq_stats provides per precedence. */
+ uint32 retry; /**< packets re-sent because they were not received */
+ uint32 retry_drop; /**< packets finally dropped after retry limit */
+ uint32 rtsfail; /**< count of rts attempts that failed to receive cts */
+ uint32 acked; /**< count of packets sent (acked) successfully */
+ uint32 txrate_succ; /**< running total of phy rate of packets sent successfully */
+ uint32 txrate_main; /**< running total of phy 'main' rate */
+ uint32 throughput; /**< actual data transferred successfully */
+ uint32 time_delta; /**< time difference since last pktq_stats */
+ uint32 airtime; /**< cumulative total medium access delay in useconds */
+} iov_bs_data_counters_t;
+
+/** The structure for individual station information. */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ struct ether_addr station_address; /**< The station MAC address */
+ uint16 station_flags; /**< Bit mask of flags, for future use. */
+ iov_bs_data_counters_t station_counters; /**< The actual counter values */
+} BWL_POST_PACKED_STRUCT iov_bs_data_record_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint16 structure_version; /**< Structure version number (for wl/wlu matching) */
+ uint16 structure_count; /**< Number of iov_bs_data_record_t records following */
+ iov_bs_data_record_t structure_record[1]; /**< 0 - structure_count records */
+} BWL_POST_PACKED_STRUCT iov_bs_data_struct_t;
+#include <packed_section_end.h>
+
+/* Bitmask of options that can be passed in to the iovar. */
+enum {
+ SCB_BS_DATA_FLAG_NO_RESET = (1<<0) /**< Do not clear the counters after reading */
+};
+/*
+ * SCB_BS_DATA iovar definitions end.
+ */
+
+typedef struct wlc_extlog_cfg {
+ int32 max_number;
+ uint16 module; /**< bitmap */
+ uint8 level;
+ uint8 flag;
+ uint16 version;
+} wlc_extlog_cfg_t;
+
+typedef struct log_record {
+ uint32 time;
+ uint16 module;
+ uint16 id;
+ uint8 level;
+ uint8 sub_unit;
+ uint8 seq_num;
+ uint8 pad;
+ int32 arg;
+ char str[MAX_ARGSTR_LEN];
+} log_record_t;
+
+typedef struct wlc_extlog_req {
+ uint32 from_last;
+ uint32 num;
+} wlc_extlog_req_t;
+
+typedef struct wlc_extlog_results {
+ uint16 version;
+ uint16 record_len;
+ uint32 num;
+ log_record_t logs[1];
+} wlc_extlog_results_t;
+
+typedef struct log_idstr {
+ uint16 id;
+ uint16 flag;
+ uint8 arg_type;
+ const char *fmt_str;
+} log_idstr_t;
+
+#define FMTSTRF_USER 1
+
+/* flat ID definitions
+ * New definitions HAVE TO BE ADDED at the end of the table. Otherwise, it will
+ * affect backward compatibility with pre-existing apps
+ */
+typedef enum {
+ FMTSTR_DRIVER_UP_ID = 0,
+ FMTSTR_DRIVER_DOWN_ID = 1,
+ FMTSTR_SUSPEND_MAC_FAIL_ID = 2,
+ FMTSTR_NO_PROGRESS_ID = 3,
+ FMTSTR_RFDISABLE_ID = 4,
+ FMTSTR_REG_PRINT_ID = 5,
+ FMTSTR_EXPTIME_ID = 6,
+ FMTSTR_JOIN_START_ID = 7,
+ FMTSTR_JOIN_COMPLETE_ID = 8,
+ FMTSTR_NO_NETWORKS_ID = 9,
+ FMTSTR_SECURITY_MISMATCH_ID = 10,
+ FMTSTR_RATE_MISMATCH_ID = 11,
+ FMTSTR_AP_PRUNED_ID = 12,
+ FMTSTR_KEY_INSERTED_ID = 13,
+ FMTSTR_DEAUTH_ID = 14,
+ FMTSTR_DISASSOC_ID = 15,
+ FMTSTR_LINK_UP_ID = 16,
+ FMTSTR_LINK_DOWN_ID = 17,
+ FMTSTR_RADIO_HW_OFF_ID = 18,
+ FMTSTR_RADIO_HW_ON_ID = 19,
+ FMTSTR_EVENT_DESC_ID = 20,
+ FMTSTR_PNP_SET_POWER_ID = 21,
+ FMTSTR_RADIO_SW_OFF_ID = 22,
+ FMTSTR_RADIO_SW_ON_ID = 23,
+ FMTSTR_PWD_MISMATCH_ID = 24,
+ FMTSTR_FATAL_ERROR_ID = 25,
+ FMTSTR_AUTH_FAIL_ID = 26,
+ FMTSTR_ASSOC_FAIL_ID = 27,
+ FMTSTR_IBSS_FAIL_ID = 28,
+ FMTSTR_EXTAP_FAIL_ID = 29,
+ FMTSTR_MAX_ID
+} log_fmtstr_id_t;
+
+/** 11k Neighbor Report element (unversioned, deprecated) */
+typedef struct nbr_element {
+ uint8 id;
+ uint8 len;
+ struct ether_addr bssid;
+ uint32 bssid_info;
+ uint8 reg;
+ uint8 channel;
+ uint8 phytype;
+ uint8 pad;
+} nbr_element_t;
+
+#define WL_RRM_NBR_RPT_VER 1
+/** 11k Neighbor Report element */
+typedef struct nbr_rpt_elem {
+ uint8 version;
+ uint8 id;
+ uint8 len;
+ uint8 pad;
+ struct ether_addr bssid;
+ uint8 pad_1[2];
+ uint32 bssid_info;
+ uint8 reg;
+ uint8 channel;
+ uint8 phytype;
+ uint8 pad_2;
+ wlc_ssid_t ssid;
+ chanspec_t chanspec;
+ uint8 bss_trans_preference;
+ uint8 flags;
+} nbr_rpt_elem_t;
+
+typedef enum event_msgs_ext_command {
+ EVENTMSGS_NONE = 0,
+ EVENTMSGS_SET_BIT = 1,
+ EVENTMSGS_RESET_BIT = 2,
+ EVENTMSGS_SET_MASK = 3
+} event_msgs_ext_command_t;
+
+#define EVENTMSGS_VER 1
+#define EVENTMSGS_EXT_STRUCT_SIZE OFFSETOF(eventmsgs_ext_t, mask[0])
+
+/* len- for SET it would be mask size from the application to the firmware */
+/* for GET it would be actual firmware mask size */
+/* maxgetsize - is only used for GET. indicate max mask size that the */
+/* application can read from the firmware */
+typedef struct eventmsgs_ext
+{
+ uint8 ver;
+ uint8 command;
+ uint8 len;
+ uint8 maxgetsize;
+ uint8 mask[1];
+} eventmsgs_ext_t;
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct pcie_bus_tput_params {
+ /** no of host dma descriptors programmed by the firmware before a commit */
+ uint16 max_dma_descriptors;
+
+ uint16 host_buf_len; /**< length of host buffer */
+ dmaaddr_t host_buf_addr; /**< physical address for bus_throughput_buf */
+} BWL_POST_PACKED_STRUCT pcie_bus_tput_params_t;
+#include <packed_section_end.h>
+
+typedef struct pcie_bus_tput_stats {
+ uint16 time_taken; /**< no of secs the test is run */
+ uint16 nbytes_per_descriptor; /**< no of bytes of data dma ed per descriptor */
+
+ /** no of desciptors for which dma is sucessfully completed within the test time */
+ uint32 count;
+} pcie_bus_tput_stats_t;
+
+typedef struct keepalives_max_idle {
+ uint16 keepalive_count; /**< nmbr of keepalives per bss_max_idle period */
+ uint8 mkeepalive_index; /**< mkeepalive_index for keepalive frame to be used */
+ uint8 PAD; /**< to align next field */
+ uint16 max_interval; /**< seconds */
+} keepalives_max_idle_t;
+
+#define PM_IGNORE_BCMC_PROXY_ARP (1 << 0)
+#define PM_IGNORE_BCMC_ALL_DMS_ACCEPTED (1 << 1)
+
+/* ##### Power Stats section ##### */
+
+#define WL_PWRSTATS_VERSION 2
+
+/** Input structure for pwrstats IOVAR */
+typedef struct wl_pwrstats_query {
+ uint16 length; /**< Number of entries in type array. */
+ uint16 type[1]; /**< Types (tags) to retrieve.
+ * Length 0 (no types) means get all.
+ */
+} wl_pwrstats_query_t;
+
+/** This structure is for version 2; version 1 will be deprecated in by FW */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_pwrstats {
+ uint16 version; /**< Version = 2 is TLV format */
+ uint16 length; /**< Length of entire structure */
+ uint8 data[1]; /**< TLV data, a series of structures,
+ * each starting with type and length.
+ *
+ * Padded as necessary so each section
+ * starts on a 4-byte boundary.
+ *
+ * Both type and len are uint16, but the
+ * upper nibble of length is reserved so
+ * valid len values are 0-4095.
+ */
+} BWL_POST_PACKED_STRUCT wl_pwrstats_t;
+#include <packed_section_end.h>
+#define WL_PWR_STATS_HDRLEN OFFSETOF(wl_pwrstats_t, data)
+
+/* Bits for wake reasons */
+#define WLC_PMD_WAKE_SET 0x1
+#define WLC_PMD_PM_AWAKE_BCN 0x2
+/* BIT:3 is no longer being used */
+#define WLC_PMD_SCAN_IN_PROGRESS 0x8
+#define WLC_PMD_RM_IN_PROGRESS 0x10
+#define WLC_PMD_AS_IN_PROGRESS 0x20
+#define WLC_PMD_PM_PEND 0x40
+#define WLC_PMD_PS_POLL 0x80
+#define WLC_PMD_CHK_UNALIGN_TBTT 0x100
+#define WLC_PMD_APSD_STA_UP 0x200
+#define WLC_PMD_TX_PEND_WAR 0x400 /* obsolete, can be reused */
+#define WLC_PMD_GPTIMER_STAY_AWAKE 0x800
+#define WLC_PMD_PM2_RADIO_SOFF_PEND 0x2000
+#define WLC_PMD_NON_PRIM_STA_UP 0x4000
+#define WLC_PMD_AP_UP 0x8000
+
+typedef struct wlc_pm_debug {
+ uint32 timestamp; /**< timestamp in millisecond */
+ uint32 reason; /**< reason(s) for staying awake */
+} wlc_pm_debug_t;
+
+/** WL_PWRSTATS_TYPE_PM_AWAKE1 structures (for 6.25 firmware) */
+#define WLC_STA_AWAKE_STATES_MAX_V1 30
+#define WLC_PMD_EVENT_MAX_V1 32
+/** Data sent as part of pwrstats IOVAR (and EXCESS_PM_WAKE event) */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct pm_awake_data_v1 {
+ uint32 curr_time; /**< ms */
+ uint32 hw_macc; /**< HW maccontrol */
+ uint32 sw_macc; /**< SW maccontrol */
+ uint32 pm_dur; /**< Total sleep time in PM, msecs */
+ uint32 mpc_dur; /**< Total sleep time in MPC, msecs */
+
+ /* int32 drifts = remote - local; +ve drift => local-clk slow */
+ int32 last_drift; /**< Most recent TSF drift from beacon */
+ int32 min_drift; /**< Min TSF drift from beacon in magnitude */
+ int32 max_drift; /**< Max TSF drift from beacon in magnitude */
+
+ uint32 avg_drift; /**< Avg TSF drift from beacon */
+
+ /* Wake history tracking */
+ uint8 pmwake_idx; /**< for stepping through pm_state */
+ wlc_pm_debug_t pm_state[WLC_STA_AWAKE_STATES_MAX_V1]; /**< timestamped wake bits */
+ uint32 pmd_event_wake_dur[WLC_PMD_EVENT_MAX_V1]; /**< cumulative usecs per wake reason */
+ uint32 drift_cnt; /**< Count of drift readings over which avg_drift was computed */
+} BWL_POST_PACKED_STRUCT pm_awake_data_v1_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_pm_awake_stats_v1 {
+ uint16 type; /**< WL_PWRSTATS_TYPE_PM_AWAKE */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+
+ pm_awake_data_v1_t awake_data;
+ uint32 frts_time; /**< Cumulative ms spent in frts since driver load */
+ uint32 frts_end_cnt; /**< No of times frts ended since driver load */
+} BWL_POST_PACKED_STRUCT wl_pwr_pm_awake_stats_v1_t;
+#include <packed_section_end.h>
+
+/** WL_PWRSTATS_TYPE_PM_AWAKE2 structures. Data sent as part of pwrstats IOVAR */
+typedef struct pm_awake_data_v2 {
+ uint32 curr_time; /**< ms */
+ uint32 hw_macc; /**< HW maccontrol */
+ uint32 sw_macc; /**< SW maccontrol */
+ uint32 pm_dur; /**< Total sleep time in PM, msecs */
+ uint32 mpc_dur; /**< Total sleep time in MPC, msecs */
+
+ /* int32 drifts = remote - local; +ve drift => local-clk slow */
+ int32 last_drift; /**< Most recent TSF drift from beacon */
+ int32 min_drift; /**< Min TSF drift from beacon in magnitude */
+ int32 max_drift; /**< Max TSF drift from beacon in magnitude */
+
+ uint32 avg_drift; /**< Avg TSF drift from beacon */
+
+ /* Wake history tracking */
+
+ /* pmstate array (type wlc_pm_debug_t) start offset */
+ uint16 pm_state_offset;
+ /** pmstate number of array entries */
+ uint16 pm_state_len;
+
+ /** array (type uint32) start offset */
+ uint16 pmd_event_wake_dur_offset;
+ /** pmd_event_wake_dur number of array entries */
+ uint16 pmd_event_wake_dur_len;
+
+ uint32 drift_cnt; /**< Count of drift readings over which avg_drift was computed */
+ uint8 pmwake_idx; /**< for stepping through pm_state */
+ uint8 flags; /**< bit0: 1-sleep, 0- wake. bit1: 0-bit0 invlid, 1-bit0 valid */
+ uint8 pad[2];
+ uint32 frts_time; /**< Cumulative ms spent in frts since driver load */
+ uint32 frts_end_cnt; /**< No of times frts ended since driver load */
+} pm_awake_data_v2_t;
+
+typedef struct wl_pwr_pm_awake_stats_v2 {
+ uint16 type; /**< WL_PWRSTATS_TYPE_PM_AWAKE */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+
+ pm_awake_data_v2_t awake_data;
+} wl_pwr_pm_awake_stats_v2_t;
+
+/* bit0: 1-sleep, 0- wake. bit1: 0-bit0 invlid, 1-bit0 valid */
+#define WL_PWR_PM_AWAKE_STATS_WAKE 0x02
+#define WL_PWR_PM_AWAKE_STATS_ASLEEP 0x03
+#define WL_PWR_PM_AWAKE_STATS_WAKE_MASK 0x03
+
+/* WL_PWRSTATS_TYPE_PM_AWAKE Version 2 structures taken from 4324/43342 */
+/* These structures are only to be used with 4324/43342 devices */
+
+#define WL_STA_AWAKE_STATES_MAX_V2 30
+#define WL_PMD_EVENT_MAX_V2 32
+#define MAX_P2P_BSS_DTIM_PRD 4
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct ucode_dbg_v2 {
+ uint32 macctrl;
+ uint16 m_p2p_hps;
+ uint16 m_p2p_bss_dtim_prd[MAX_P2P_BSS_DTIM_PRD];
+ uint32 psmdebug[20];
+ uint32 phydebug[20];
+ uint32 psm_brc;
+ uint32 ifsstat;
+} BWL_POST_PACKED_STRUCT ucode_dbg_v2_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct pmalert_awake_data_v2 {
+ uint32 curr_time; /* ms */
+ uint32 hw_macc; /* HW maccontrol */
+ uint32 sw_macc; /* SW maccontrol */
+ uint32 pm_dur; /* Total sleep time in PM, msecs */
+ uint32 mpc_dur; /* Total sleep time in MPC, msecs */
+
+ /* int32 drifts = remote - local; +ve drift => local-clk slow */
+ int32 last_drift; /* Most recent TSF drift from beacon */
+ int32 min_drift; /* Min TSF drift from beacon in magnitude */
+ int32 max_drift; /* Max TSF drift from beacon in magnitude */
+
+ uint32 avg_drift; /* Avg TSF drift from beacon */
+
+ /* Wake history tracking */
+ uint8 pmwake_idx; /* for stepping through pm_state */
+ wlc_pm_debug_t pm_state[WL_STA_AWAKE_STATES_MAX_V2]; /* timestamped wake bits */
+ uint32 pmd_event_wake_dur[WL_PMD_EVENT_MAX_V2]; /* cumulative usecs per wake reason */
+ uint32 drift_cnt; /* Count of drift readings over which avg_drift was computed */
+ uint32 start_event_dur[WL_PMD_EVENT_MAX_V2]; /* start event-duration */
+ ucode_dbg_v2_t ud;
+ uint32 frts_time; /* Cumulative ms spent in frts since driver load */
+ uint32 frts_end_cnt; /* No of times frts ended since driver load */
+} BWL_POST_PACKED_STRUCT pmalert_awake_data_v2_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct pm_alert_data_v2 {
+ uint32 version;
+ uint32 length; /* Length of entire structure */
+ uint32 reasons; /* reason(s) for pm_alert */
+ /* Following fields are present only for reasons
+ * PM_DUR_EXCEEDED, MPC_DUR_EXCEEDED & CONST_AWAKE_DUR_EXCEEDED
+ */
+ uint32 prev_stats_time; /* msecs */
+ uint32 prev_pm_dur; /* msecs */
+ uint32 prev_mpc_dur; /* msecs */
+ pmalert_awake_data_v2_t awake_data;
+} BWL_POST_PACKED_STRUCT pm_alert_data_v2_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_pm_awake_status_v2 {
+ uint16 type; /* WL_PWRSTATS_TYPE_PM_AWAKE */
+ uint16 len; /* Up to 4K-1, top 4 bits are reserved */
+
+ pmalert_awake_data_v2_t awake_data;
+ uint32 frts_time; /* Cumulative ms spent in frts since driver load */
+ uint32 frts_end_cnt; /* No of times frts ended since driver load */
+} BWL_POST_PACKED_STRUCT wl_pwr_pm_awake_status_v2_t;
+#include <packed_section_end.h>
+
+/* Below are latest definitions from PHO25178RC100_BRANCH_6_50 */
+/* wl_pwr_pm_awake_stats_v1_t is used for WL_PWRSTATS_TYPE_PM_AWAKE */
+/* (at least) the chip independent registers */
+typedef struct ucode_dbg_ext {
+ uint32 x120;
+ uint32 x124;
+ uint32 x154;
+ uint32 x158;
+ uint32 x15c;
+ uint32 x180;
+ uint32 x184;
+ uint32 x188;
+ uint32 x18c;
+ uint32 x1a0;
+ uint32 x1a8;
+ uint32 x1e0;
+ uint32 scr_x14;
+ uint32 scr_x2b;
+ uint32 scr_x2c;
+ uint32 scr_x2d;
+ uint32 scr_x2e;
+
+ uint16 x40a;
+ uint16 x480;
+ uint16 x490;
+ uint16 x492;
+ uint16 x4d8;
+ uint16 x4b8;
+ uint16 x4ba;
+ uint16 x4bc;
+ uint16 x4be;
+ uint16 x500;
+ uint16 x50e;
+ uint16 x522;
+ uint16 x546;
+ uint16 x578;
+ uint16 x602;
+ uint16 x646;
+ uint16 x648;
+ uint16 x666;
+ uint16 x670;
+ uint16 x690;
+ uint16 x692;
+ uint16 x6a0;
+ uint16 x6a2;
+ uint16 x6a4;
+ uint16 x6b2;
+ uint16 x7c0;
+
+ uint16 shm_x20;
+ uint16 shm_x4a;
+ uint16 shm_x5e;
+ uint16 shm_x5f;
+ uint16 shm_xaab;
+ uint16 shm_x74a;
+ uint16 shm_x74b;
+ uint16 shm_x74c;
+ uint16 shm_x74e;
+ uint16 shm_x756;
+ uint16 shm_x75b;
+ uint16 shm_x7b9;
+ uint16 shm_x7d4;
+
+ uint16 shm_P2P_HPS;
+ uint16 shm_P2P_intr[16];
+ uint16 shm_P2P_perbss[48];
+} ucode_dbg_ext_t;
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct pm_alert_data_v1 {
+ uint32 version;
+ uint32 length; /**< Length of entire structure */
+ uint32 reasons; /**< reason(s) for pm_alert */
+ /* Following fields are present only for reasons
+ * PM_DUR_EXCEEDED, MPC_DUR_EXCEEDED & CONST_AWAKE_DUR_EXCEEDED
+ */
+ uint32 prev_stats_time; /**< msecs */
+ uint32 prev_pm_dur; /**< msecs */
+ uint32 prev_mpc_dur; /**< msecs */
+ pm_awake_data_v1_t awake_data;
+ uint32 start_event_dur[WLC_PMD_EVENT_MAX_V1]; /**< start event-duration */
+ ucode_dbg_v2_t ud;
+ uint32 frts_time; /**< Cumulative ms spent in frts since driver load */
+ uint32 frts_end_cnt; /**< No of times frts ended since driver load */
+ ucode_dbg_ext_t ud_ext;
+ uint32 prev_frts_dur; /**< ms */
+} BWL_POST_PACKED_STRUCT pm_alert_data_v1_t;
+#include <packed_section_end.h>
+
+/* End of 43342/4324 v2 structure definitions */
+
+/* Original bus structure is for HSIC */
+
+typedef struct bus_metrics {
+ uint32 suspend_ct; /**< suspend count */
+ uint32 resume_ct; /**< resume count */
+ uint32 disconnect_ct; /**< disconnect count */
+ uint32 reconnect_ct; /**< reconnect count */
+ uint32 active_dur; /**< msecs in bus, usecs for user */
+ uint32 suspend_dur; /**< msecs in bus, usecs for user */
+ uint32 disconnect_dur; /**< msecs in bus, usecs for user */
+} bus_metrics_t;
+
+/** Bus interface info for USB/HSIC */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_usb_hsic_stats {
+ uint16 type; /**< WL_PWRSTATS_TYPE_USB_HSIC */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+
+ bus_metrics_t hsic; /**< stats from hsic bus driver */
+} BWL_POST_PACKED_STRUCT wl_pwr_usb_hsic_stats_t;
+#include <packed_section_end.h>
+
+typedef struct pcie_bus_metrics {
+ uint32 d3_suspend_ct; /**< suspend count */
+ uint32 d0_resume_ct; /**< resume count */
+ uint32 perst_assrt_ct; /**< PERST# assert count */
+ uint32 perst_deassrt_ct; /**< PERST# de-assert count */
+ uint32 active_dur; /**< msecs */
+ uint32 d3_suspend_dur; /**< msecs */
+ uint32 perst_dur; /**< msecs */
+ uint32 l0_cnt; /**< L0 entry count */
+ uint32 l0_usecs; /**< L0 duration in usecs */
+ uint32 l1_cnt; /**< L1 entry count */
+ uint32 l1_usecs; /**< L1 duration in usecs */
+ uint32 l1_1_cnt; /**< L1_1ss entry count */
+ uint32 l1_1_usecs; /**< L1_1ss duration in usecs */
+ uint32 l1_2_cnt; /**< L1_2ss entry count */
+ uint32 l1_2_usecs; /**< L1_2ss duration in usecs */
+ uint32 l2_cnt; /**< L2 entry count */
+ uint32 l2_usecs; /**< L2 duration in usecs */
+ uint32 timestamp; /**< Timestamp on when stats are collected */
+ uint32 num_h2d_doorbell; /**< # of doorbell interrupts - h2d */
+ uint32 num_d2h_doorbell; /**< # of doorbell interrupts - d2h */
+ uint32 num_submissions; /**< # of submissions */
+ uint32 num_completions; /**< # of completions */
+ uint32 num_rxcmplt; /**< # of rx completions */
+ uint32 num_rxcmplt_drbl; /**< of drbl interrupts for rx complt. */
+ uint32 num_txstatus; /**< # of tx completions */
+ uint32 num_txstatus_drbl; /**< of drbl interrupts for tx complt. */
+ uint32 deepsleep_count; /**< # of times chip went to deepsleep */
+ uint32 deepsleep_dur; /**< # of msecs chip was in deepsleep */
+ uint32 ltr_active_ct; /**< # of times chip went to LTR ACTIVE */
+ uint32 ltr_active_dur; /**< # of msecs chip was in LTR ACTIVE */
+ uint32 ltr_sleep_ct; /**< # of times chip went to LTR SLEEP */
+ uint32 ltr_sleep_dur; /**< # of msecs chip was in LTR SLEEP */
+} pcie_bus_metrics_t;
+
+/** Bus interface info for PCIE */
+typedef struct wl_pwr_pcie_stats {
+ uint16 type; /**< WL_PWRSTATS_TYPE_PCIE */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+ pcie_bus_metrics_t pcie; /**< stats from pcie bus driver */
+} wl_pwr_pcie_stats_t;
+
+/** Scan information history per category */
+typedef struct scan_data {
+ uint32 count; /**< Number of scans performed */
+ uint32 dur; /**< Total time (in us) used */
+} scan_data_t;
+
+typedef struct wl_pwr_scan_stats {
+ uint16 type; /**< WL_PWRSTATS_TYPE_SCAN */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+
+ /* Scan history */
+ scan_data_t user_scans; /**< User-requested scans: (i/e/p)scan */
+ scan_data_t assoc_scans; /**< Scans initiated by association requests */
+ scan_data_t roam_scans; /**< Scans initiated by the roam engine */
+ scan_data_t pno_scans[8]; /**< For future PNO bucketing (BSSID, SSID, etc) */
+ scan_data_t other_scans; /**< Scan engine usage not assigned to the above */
+} wl_pwr_scan_stats_t;
+
+typedef struct wl_pwr_connect_stats {
+ uint16 type; /**< WL_PWRSTATS_TYPE_SCAN */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+
+ /* Connection (Association + Key exchange) data */
+ uint32 count; /**< Number of connections performed */
+ uint32 dur; /**< Total time (in ms) used */
+} wl_pwr_connect_stats_t;
+
+typedef struct wl_pwr_phy_stats {
+ uint16 type; /**< WL_PWRSTATS_TYPE_PHY */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+ uint32 tx_dur; /**< TX Active duration in us */
+ uint32 rx_dur; /**< RX Active duration in us */
+} wl_pwr_phy_stats_t;
+
+
+typedef struct wl_mimo_meas_metrics_v1 {
+ uint16 type;
+ uint16 len;
+ /* Total time(us) idle in MIMO RX chain configuration */
+ uint32 total_idle_time_mimo;
+ /* Total time(us) idle in SISO RX chain configuration */
+ uint32 total_idle_time_siso;
+ /* Total receive time (us) in SISO RX chain configuration */
+ uint32 total_rx_time_siso;
+ /* Total receive time (us) in MIMO RX chain configuration */
+ uint32 total_rx_time_mimo;
+ /* Total 1-chain transmit time(us) */
+ uint32 total_tx_time_1chain;
+ /* Total 2-chain transmit time(us) */
+ uint32 total_tx_time_2chain;
+ /* Total 3-chain transmit time(us) */
+ uint32 total_tx_time_3chain;
+} wl_mimo_meas_metrics_v1_t;
+
+typedef struct wl_mimo_meas_metrics {
+ uint16 type;
+ uint16 len;
+ /* Total time(us) idle in MIMO RX chain configuration */
+ uint32 total_idle_time_mimo;
+ /* Total time(us) idle in SISO RX chain configuration */
+ uint32 total_idle_time_siso;
+ /* Total receive time (us) in SISO RX chain configuration */
+ uint32 total_rx_time_siso;
+ /* Total receive time (us) in MIMO RX chain configuration */
+ uint32 total_rx_time_mimo;
+ /* Total 1-chain transmit time(us) */
+ uint32 total_tx_time_1chain;
+ /* Total 2-chain transmit time(us) */
+ uint32 total_tx_time_2chain;
+ /* Total 3-chain transmit time(us) */
+ uint32 total_tx_time_3chain;
+ /* End of original, OCL fields start here */
+ /* Total time(us) idle in ocl mode */
+ uint32 total_idle_time_ocl;
+ /* Total receive time (us) in ocl mode */
+ uint32 total_rx_time_ocl;
+ /* End of OCL fields, internal adjustment fields here */
+ /* Total SIFS idle time in MIMO mode */
+ uint32 total_sifs_time_mimo;
+ /* Total SIFS idle time in SISO mode */
+ uint32 total_sifs_time_siso;
+} wl_mimo_meas_metrics_t;
+/* ##### End of Power Stats section ##### */
+
+/** IPV4 Arp offloads for ndis context */
+#include <packed_section_start.h>
+BWL_PRE_PACKED_STRUCT struct hostip_id {
+ struct ipv4_addr ipa;
+ uint8 id;
+} BWL_POST_PACKED_STRUCT;
+#include <packed_section_end.h>
+
+/* Return values */
+#define ND_REPLY_PEER 0x1 /**< Reply was sent to service NS request from peer */
+#define ND_REQ_SINK 0x2 /**< Input packet should be discarded */
+#define ND_FORCE_FORWARD 0X3 /**< For the dongle to forward req to HOST */
+
+/** Neighbor Solicitation Response Offload IOVAR param */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct nd_param {
+ struct ipv6_addr host_ip[2];
+ struct ipv6_addr solicit_ip;
+ struct ipv6_addr remote_ip;
+ uint8 host_mac[ETHER_ADDR_LEN];
+ uint32 offload_id;
+} BWL_POST_PACKED_STRUCT nd_param_t;
+#include <packed_section_end.h>
+
+typedef struct wl_pfn_roam_thresh {
+ uint32 pfn_alert_thresh; /**< time in ms */
+ uint32 roam_alert_thresh; /**< time in ms */
+} wl_pfn_roam_thresh_t;
+
+
+/* Reasons for wl_pmalert_t */
+#define PM_DUR_EXCEEDED (1<<0)
+#define MPC_DUR_EXCEEDED (1<<1)
+#define ROAM_ALERT_THRESH_EXCEEDED (1<<2)
+#define PFN_ALERT_THRESH_EXCEEDED (1<<3)
+#define CONST_AWAKE_DUR_ALERT (1<<4)
+#define CONST_AWAKE_DUR_RECOVERY (1<<5)
+
+#define MIN_PM_ALERT_LEN 9
+
+/** Data sent in EXCESS_PM_WAKE event */
+#define WL_PM_ALERT_VERSION 3
+
+/** This structure is for version 3; version 2 will be deprecated in by FW */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert {
+ uint16 version; /**< Version = 3 is TLV format */
+ uint16 length; /**< Length of entire structure */
+ uint32 reasons; /**< reason(s) for pm_alert */
+ uint8 data[1]; /**< TLV data, a series of structures,
+ * each starting with type and length.
+ *
+ * Padded as necessary so each section
+ * starts on a 4-byte boundary.
+ *
+ * Both type and len are uint16, but the
+ * upper nibble of length is reserved so
+ * valid len values are 0-4095.
+ */
+} BWL_POST_PACKED_STRUCT wl_pmalert_t;
+#include <packed_section_end.h>
+
+/* Type values for the data section */
+#define WL_PMALERT_FIXED 0 /**< struct wl_pmalert_fixed_t, fixed fields */
+#define WL_PMALERT_PMSTATE 1 /**< struct wl_pmalert_pmstate_t, variable */
+#define WL_PMALERT_EVENT_DUR 2 /**< struct wl_pmalert_event_dur_t, variable */
+#define WL_PMALERT_UCODE_DBG 3 /**< struct wl_pmalert_ucode_dbg_v1, variable */
+#define WL_PMALERT_PS_ALLOWED_HIST 4 /**< struct wl_pmalert_ps_allowed_history, variable */
+#define WL_PMALERT_EXT_UCODE_DBG 5 /**< struct wl_pmalert_ext_ucode_dbg_t, variable */
+#define WL_PMALERT_EPM_START_EVENT_DUR 6 /**< struct wl_pmalert_event_dur_t, variable */
+#define WL_PMALERT_UCODE_DBG_V2 7 /**< struct wl_pmalert_ucode_dbg_v2, variable */
+
+typedef struct wl_pmalert_fixed {
+ uint16 type; /**< WL_PMALERT_FIXED */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+ uint32 prev_stats_time; /**< msecs */
+ uint32 curr_time; /**< ms */
+ uint32 prev_pm_dur; /**< msecs */
+ uint32 pm_dur; /**< Total sleep time in PM, msecs */
+ uint32 prev_mpc_dur; /**< msecs */
+ uint32 mpc_dur; /**< Total sleep time in MPC, msecs */
+ uint32 hw_macc; /**< HW maccontrol */
+ uint32 sw_macc; /**< SW maccontrol */
+
+ /* int32 drifts = remote - local; +ve drift -> local-clk slow */
+ int32 last_drift; /**< Most recent TSF drift from beacon */
+ int32 min_drift; /**< Min TSF drift from beacon in magnitude */
+ int32 max_drift; /**< Max TSF drift from beacon in magnitude */
+
+ uint32 avg_drift; /**< Avg TSF drift from beacon */
+ uint32 drift_cnt; /**< Count of drift readings over which avg_drift was computed */
+ uint32 frts_time; /**< Cumulative ms spent in data frts since driver load */
+ uint32 frts_end_cnt; /**< No of times frts ended since driver load */
+ uint32 prev_frts_dur; /**< Data frts duration at start of pm-period */
+ uint32 cal_dur; /**< Cumulative ms spent in calibration */
+ uint32 prev_cal_dur; /**< cal duration at start of pm-period */
+} wl_pmalert_fixed_t;
+
+typedef struct wl_pmalert_pmstate {
+ uint16 type; /**< WL_PMALERT_PMSTATE */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+
+ uint8 pmwake_idx; /**< for stepping through pm_state */
+ uint8 pad[3];
+ /* Array of pmstate; len of array is based on tlv len */
+ wlc_pm_debug_t pmstate[1];
+} wl_pmalert_pmstate_t;
+
+typedef struct wl_pmalert_event_dur {
+ uint16 type; /**< WL_PMALERT_EVENT_DUR */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+
+ /* Array of event_dur, len of array is based on tlv len */
+ uint32 event_dur[1];
+} wl_pmalert_event_dur_t;
+
+#include <packed_section_start.h>
+BWL_PRE_PACKED_STRUCT struct wl_pmalert_ucode_dbg_v1 {
+ uint16 type; /* WL_PMALERT_UCODE_DBG */
+ uint16 len; /* Up to 4K-1, top 4 bits are reserved */
+ uint32 macctrl;
+ uint16 m_p2p_hps;
+ uint32 psm_brc;
+ uint32 ifsstat;
+ uint16 m_p2p_bss_dtim_prd[MAX_P2P_BSS_DTIM_PRD];
+ uint32 psmdebug[20];
+ uint32 phydebug[20];
+ uint16 M_P2P_BSS[3][12];
+ uint16 M_P2P_PRE_TBTT[3];
+
+ /* Following is valid only for corerevs<40 */
+ uint16 xmtfifordy;
+
+ /* Following 3 are valid only for 11ac corerevs (>=40) */
+ uint16 psm_maccommand;
+ uint16 txe_status1;
+ uint16 AQMFifoReady;
+} BWL_POST_PACKED_STRUCT;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+BWL_PRE_PACKED_STRUCT struct wl_pmalert_ucode_dbg_v2 {
+ uint16 type; /**< WL_PMALERT_UCODE_DBG_V2 */
+ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */
+ uint32 macctrl;
+ uint16 m_p2p_hps;
+ uint32 psm_brc;
+ uint32 ifsstat;
+ uint16 m_p2p_bss_dtim_prd[MAX_P2P_BSS_DTIM_PRD];
+ uint32 psmdebug[20];
+ uint32 phydebug[20];
+ uint16 M_P2P_BSS[3][12];
+ uint16 M_P2P_PRE_TBTT[3];
+
+ /* Following is valid only for corerevs<40 */
+ uint16 xmtfifordy;
+
+ /* Following 3 are valid only for 11ac corerevs (>=40) */
+ uint16 psm_maccommand;
+ uint16 txe_status1;
+ uint32 AQMFifoReady;
+} BWL_POST_PACKED_STRUCT;
+#include <packed_section_end.h>
+
+
+/* Structures and constants used for "vndr_ie" IOVar interface */
+#define VNDR_IE_CMD_LEN 4 /**< length of the set command string:
+ * "add", "del" (+ NUL)
+ */
+
+#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32))
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 pktflag; /**< bitmask indicating which packet(s) contain this IE */
+ vndr_ie_t vndr_ie_data; /**< vendor IE data */
+} BWL_POST_PACKED_STRUCT vndr_ie_info_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ int32 iecount; /**< number of entries in the vndr_ie_list[] array */
+ vndr_ie_info_t vndr_ie_list[1]; /**< variable size list of vndr_ie_info_t structs */
+} BWL_POST_PACKED_STRUCT vndr_ie_buf_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ char cmd[VNDR_IE_CMD_LEN]; /**< vndr_ie IOVar set command : "add", "del" + NUL */
+ vndr_ie_buf_t vndr_ie_buffer; /**< buffer containing Vendor IE list information */
+} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t;
+#include <packed_section_end.h>
+
+/** tag_ID/length/value_buffer tuple */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint8 id;
+ uint8 len;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT tlv_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 pktflag; /**< bitmask indicating which packet(s) contain this IE */
+ tlv_t ie_data; /**< IE data */
+} BWL_POST_PACKED_STRUCT ie_info_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ int32 iecount; /**< number of entries in the ie_list[] array */
+ ie_info_t ie_list[1]; /**< variable size list of ie_info_t structs */
+} BWL_POST_PACKED_STRUCT ie_buf_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ char cmd[VNDR_IE_CMD_LEN]; /**< ie IOVar set command : "add" + NUL */
+ ie_buf_t ie_buffer; /**< buffer containing IE list information */
+} BWL_POST_PACKED_STRUCT ie_setbuf_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 pktflag; /**< bitmask indicating which packet(s) contain this IE */
+ uint8 id; /**< IE type */
+} BWL_POST_PACKED_STRUCT ie_getbuf_t;
+#include <packed_section_end.h>
+
+/* structures used to define format of wps ie data from probe requests */
+/* passed up to applications via iovar "prbreq_wpsie" */
+typedef struct sta_prbreq_wps_ie_hdr {
+ struct ether_addr staAddr;
+ uint16 ieLen;
+} sta_prbreq_wps_ie_hdr_t;
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data {
+ sta_prbreq_wps_ie_hdr_t hdr;
+ uint8 ieData[1];
+} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list {
+ uint32 totLen;
+ uint8 ieDataList[1];
+} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t;
+#include <packed_section_end.h>
+
+
+#ifdef WLMEDIA_TXFAILEVENT
+typedef struct {
+ uint8 dest[ETHER_ADDR_LEN]; /**< destination MAC */
+ uint8 prio; /**< Packet Priority */
+ uint8 flags; /**< Flags */
+ uint32 tsf_l; /**< TSF timer low */
+ uint32 tsf_h; /**< TSF timer high */
+ uint16 rates; /**< Main Rates */
+ uint16 txstatus; /**< TX Status */
+} txfailinfo_t;
+#endif /* WLMEDIA_TXFAILEVENT */
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 flags;
+ chanspec_t chanspec; /**< txpwr report for this channel */
+ chanspec_t local_chanspec; /**< channel on which we are associated */
+ uint8 local_max; /**< local max according to the AP */
+ uint8 local_constraint; /**< local constraint according to the AP */
+ int8 antgain[2]; /**< Ant gain for each band - from SROM */
+ uint8 rf_cores; /**< count of RF Cores being reported */
+ uint8 est_Pout[4]; /**< Latest tx power out estimate per RF chain */
+ uint8 est_Pout_act[4]; /**< Latest tx power out estimate per RF chain w/o adjustment */
+ uint8 est_Pout_cck; /**< Latest CCK tx power out estimate */
+ uint8 tx_power_max[4]; /**< Maximum target power among all rates */
+ uint32 tx_power_max_rate_ind[4]; /**< Index of the rate with the max target power */
+ int8 sar; /**< SAR limit for display by wl executable */
+ int8 channel_bandwidth; /**< 20, 40 or 80 MHz bandwidth? */
+ uint8 version; /**< Version of the data format wlu <--> driver */
+ uint8 display_core; /**< Displayed curpower core */
+ int8 target_offsets[4]; /**< Target power offsets for current rate per core */
+ uint32 last_tx_ratespec; /**< Ratespec for last transmition */
+ uint32 user_target; /**< user limit */
+ uint32 ppr_len; /**< length of each ppr serialization buffer */
+ int8 SARLIMIT[MAX_STREAMS_SUPPORTED];
+ uint8 pprdata[1]; /**< ppr serialization buffer */
+} BWL_POST_PACKED_STRUCT tx_pwr_rpt_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ struct ipv4_addr ipv4_addr;
+ struct ether_addr nexthop;
+} BWL_POST_PACKED_STRUCT ibss_route_entry_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 num_entry;
+ ibss_route_entry_t route_entry[1];
+} BWL_POST_PACKED_STRUCT ibss_route_tbl_t;
+#include <packed_section_end.h>
+
+#define MAX_IBSS_ROUTE_TBL_ENTRY 64
+
+#define TXPWR_TARGET_VERSION 0
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ int32 version; /**< version number */
+ chanspec_t chanspec; /**< txpwr report for this channel */
+ int8 txpwr[WL_STA_ANT_MAX]; /**< Max tx target power, in qdb */
+ uint8 rf_cores; /**< count of RF Cores being reported */
+} BWL_POST_PACKED_STRUCT txpwr_target_max_t;
+#include <packed_section_end.h>
+
+#define BSS_PEER_INFO_PARAM_CUR_VER 0
+/** Input structure for IOV_BSS_PEER_INFO */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint16 version;
+ struct ether_addr ea; /**< peer MAC address */
+} BWL_POST_PACKED_STRUCT bss_peer_info_param_t;
+#include <packed_section_end.h>
+
+#define BSS_PEER_INFO_CUR_VER 0
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint16 version;
+ struct ether_addr ea;
+ int32 rssi;
+ uint32 tx_rate; /**< current tx rate */
+ uint32 rx_rate; /**< current rx rate */
+ wl_rateset_t rateset; /**< rateset in use */
+ uint32 age; /**< age in seconds */
+} BWL_POST_PACKED_STRUCT bss_peer_info_t;
+#include <packed_section_end.h>
+
+#define BSS_PEER_LIST_INFO_CUR_VER 0
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint16 version;
+ uint16 bss_peer_info_len; /**< length of bss_peer_info_t */
+ uint32 count; /**< number of peer info */
+ bss_peer_info_t peer_info[1]; /**< peer info */
+} BWL_POST_PACKED_STRUCT bss_peer_list_info_t;
+#include <packed_section_end.h>
+
+#define BSS_PEER_LIST_INFO_FIXED_LEN OFFSETOF(bss_peer_list_info_t, peer_info)
+
+#define AIBSS_BCN_FORCE_CONFIG_VER_0 0
+
+/** structure used to configure AIBSS beacon force xmit */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint16 version;
+ uint16 len;
+ uint32 initial_min_bcn_dur; /**< dur in ms to check a bcn in bcn_flood period */
+ uint32 min_bcn_dur; /**< dur in ms to check a bcn after bcn_flood period */
+ uint32 bcn_flood_dur; /**< Initial bcn xmit period in ms */
+} BWL_POST_PACKED_STRUCT aibss_bcn_force_config_t;
+#include <packed_section_end.h>
+
+#define AIBSS_TXFAIL_CONFIG_VER_0 0
+#define AIBSS_TXFAIL_CONFIG_VER_1 1
+#define AIBSS_TXFAIL_CONFIG_CUR_VER AIBSS_TXFAIL_CONFIG_VER_1
+
+/** structure used to configure aibss tx fail event */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint16 version;
+ uint16 len;
+ uint32 bcn_timeout; /**< dur in seconds to receive 1 bcn */
+ uint32 max_tx_retry; /**< no of consecutive no acks to send txfail event */
+ uint32 max_atim_failure; /**< no of consecutive atim failure */
+} BWL_POST_PACKED_STRUCT aibss_txfail_config_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_aibss_if {
+ uint16 version;
+ uint16 len;
+ uint32 flags;
+ struct ether_addr addr;
+ chanspec_t chspec;
+} BWL_POST_PACKED_STRUCT wl_aibss_if_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wlc_ipfo_route_entry {
+ struct ipv4_addr ip_addr;
+ struct ether_addr nexthop;
+} BWL_POST_PACKED_STRUCT wlc_ipfo_route_entry_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wlc_ipfo_route_tbl {
+ uint32 num_entry;
+ wlc_ipfo_route_entry_t route_entry[1];
+} BWL_POST_PACKED_STRUCT wlc_ipfo_route_tbl_t;
+#include <packed_section_end.h>
+
+#define WL_IPFO_ROUTE_TBL_FIXED_LEN 4
+#define WL_MAX_IPFO_ROUTE_TBL_ENTRY 64
+
+ /* Global ASSERT Logging */
+#define ASSERTLOG_CUR_VER 0x0100
+#define MAX_ASSRTSTR_LEN 64
+
+ typedef struct assert_record {
+ uint32 time;
+ uint8 seq_num;
+ int8 str[MAX_ASSRTSTR_LEN];
+ } assert_record_t;
+
+ typedef struct assertlog_results {
+ uint16 version;
+ uint16 record_len;
+ uint32 num;
+ assert_record_t logs[1];
+ } assertlog_results_t;
+
+#define LOGRRC_FIX_LEN 8
+#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type))
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#ifdef BCMWAPI_WAI
+#define IV_LEN 16
+ struct wapi_sta_msg_t
+ {
+ uint16 msg_type;
+ uint16 datalen;
+ uint8 vap_mac[6];
+ uint8 reserve_data1[2];
+ uint8 sta_mac[6];
+ uint8 reserve_data2[2];
+ uint8 gsn[IV_LEN];
+ uint8 wie[256];
+ };
+#endif /* BCMWAPI_WAI */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+ /* chanim acs record */
+ typedef struct {
+ uint8 valid;
+ uint8 trigger;
+ chanspec_t selected_chspc;
+ int8 bgnoise;
+ uint32 glitch_cnt;
+ uint8 ccastats;
+ uint8 chan_idle;
+ uint32 timestamp;
+ } chanim_acs_record_t;
+
+ typedef struct {
+ chanim_acs_record_t acs_record[CHANIM_ACS_RECORD];
+ uint8 count;
+ uint32 timestamp;
+ } wl_acs_record_t;
+
+#define WL_CHANIM_STATS_V2 2
+#define CCASTATS_V2_MAX 9
+typedef struct chanim_stats_v2 {
+ uint32 glitchcnt; /**< normalized as per second count */
+ uint32 badplcp; /**< normalized as per second count */
+ uint8 ccastats[CCASTATS_V2_MAX]; /**< normalized as 0-255 */
+ int8 bgnoise; /**< background noise level (in dBm) */
+ chanspec_t chanspec; /**< ctrl chanspec of the interface */
+ uint32 timestamp; /**< time stamp at which the stats are collected */
+ uint32 bphy_glitchcnt; /**< normalized as per second count */
+ uint32 bphy_badplcp; /**< normalized as per second count */
+ uint8 chan_idle; /**< normalized as 0~255 */
+} chanim_stats_v2_t;
+
+typedef struct chanim_stats {
+ uint32 glitchcnt; /**< normalized as per second count */
+ uint32 badplcp; /**< normalized as per second count */
+ uint8 ccastats[CCASTATS_MAX]; /**< normalized as 0-255 */
+ int8 bgnoise; /**< background noise level (in dBm) */
+ uint8 pad_1;
+ chanspec_t chanspec; /**< ctrl chanspec of the interface */
+ uint8 pad_2[2];
+ uint32 timestamp; /**< time stamp at which the stats are collected */
+ uint32 bphy_glitchcnt; /**< normalized as per second count */
+ uint32 bphy_badplcp; /**< normalized as per second count */
+ uint8 chan_idle; /**< normalized as 0~255 */
+} chanim_stats_t;
+
+#define WL_CHANIM_STATS_VERSION 3
+typedef struct {
+ uint32 buflen;
+ uint32 version;
+ uint32 count;
+ chanim_stats_t stats[1];
+} wl_chanim_stats_t;
+
+#define WL_CHANIM_STATS_FIXED_LEN OFFSETOF(wl_chanim_stats_t, stats)
+
+/** Noise measurement metrics. */
+#define NOISE_MEASURE_KNOISE 0x1
+
+/** scb probe parameter */
+typedef struct {
+ uint32 scb_timeout;
+ uint32 scb_activity_time;
+ uint32 scb_max_probe;
+} wl_scb_probe_t;
+
+/* structure/defines for selective mgmt frame (smf) stats support */
+
+#define SMFS_VERSION 1
+/** selected mgmt frame (smf) stats element */
+typedef struct wl_smfs_elem {
+ uint32 count;
+ uint16 code; /**< SC or RC code */
+} wl_smfs_elem_t;
+
+typedef struct wl_smf_stats {
+ uint32 version;
+ uint16 length; /**< reserved for future usage */
+ uint8 type;
+ uint8 codetype;
+ uint32 ignored_cnt;
+ uint32 malformed_cnt;
+ uint32 count_total; /**< count included the interested group */
+ wl_smfs_elem_t elem[1];
+} wl_smf_stats_t;
+
+#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem);
+
+enum {
+ SMFS_CODETYPE_SC,
+ SMFS_CODETYPE_RC
+};
+
+typedef enum smfs_type {
+ SMFS_TYPE_AUTH,
+ SMFS_TYPE_ASSOC,
+ SMFS_TYPE_REASSOC,
+ SMFS_TYPE_DISASSOC_TX,
+ SMFS_TYPE_DISASSOC_RX,
+ SMFS_TYPE_DEAUTH_TX,
+ SMFS_TYPE_DEAUTH_RX,
+ SMFS_TYPE_MAX
+} smfs_type_t;
+
+#ifdef PHYMON
+
+#define PHYMON_VERSION 1
+
+typedef struct wl_phycal_core_state {
+ /* Tx IQ/LO calibration coeffs */
+ int16 tx_iqlocal_a;
+ int16 tx_iqlocal_b;
+ int8 tx_iqlocal_ci;
+ int8 tx_iqlocal_cq;
+ int8 tx_iqlocal_di;
+ int8 tx_iqlocal_dq;
+ int8 tx_iqlocal_ei;
+ int8 tx_iqlocal_eq;
+ int8 tx_iqlocal_fi;
+ int8 tx_iqlocal_fq;
+
+ /** Rx IQ calibration coeffs */
+ int16 rx_iqcal_a;
+ int16 rx_iqcal_b;
+
+ uint8 tx_iqlocal_pwridx; /**< Tx Power Index for Tx IQ/LO calibration */
+ uint32 papd_epsilon_table[64]; /**< PAPD epsilon table */
+ int16 papd_epsilon_offset; /**< PAPD epsilon offset */
+ uint8 curr_tx_pwrindex; /**< Tx power index */
+ int8 idle_tssi; /**< Idle TSSI */
+ int8 est_tx_pwr; /**< Estimated Tx Power (dB) */
+ int8 est_rx_pwr; /**< Estimated Rx Power (dB) from RSSI */
+ uint16 rx_gaininfo; /**< Rx gain applied on last Rx pkt */
+ uint16 init_gaincode; /**< initgain required for ACI */
+ int8 estirr_tx;
+ int8 estirr_rx;
+
+} wl_phycal_core_state_t;
+
+typedef struct wl_phycal_state {
+ int32 version;
+ int8 num_phy_cores; /**< number of cores */
+ int8 curr_temperature; /**< on-chip temperature sensor reading */
+ chanspec_t chspec; /**< channspec for this state */
+ uint8 aci_state; /**< ACI state: ON/OFF */
+ uint16 crsminpower; /**< crsminpower required for ACI */
+ uint16 crsminpowerl; /**< crsminpowerl required for ACI */
+ uint16 crsminpoweru; /**< crsminpoweru required for ACI */
+ wl_phycal_core_state_t phycal_core[1];
+} wl_phycal_state_t;
+
+#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core)
+#endif /* PHYMON */
+
+/** discovery state */
+typedef struct wl_p2p_disc_st {
+ uint8 state; /**< see state */
+ chanspec_t chspec; /**< valid in listen state */
+ uint16 dwell; /**< valid in listen state, in ms */
+} wl_p2p_disc_st_t;
+
+/** scan request */
+typedef struct wl_p2p_scan {
+ uint8 type; /**< 'S' for WLC_SCAN, 'E' for "escan" */
+ uint8 reserved[3];
+ /* scan or escan parms... */
+} wl_p2p_scan_t;
+
+/** i/f request */
+typedef struct wl_p2p_if {
+ struct ether_addr addr;
+ uint8 type; /**< see i/f type */
+ chanspec_t chspec; /**< for p2p_ifadd GO */
+} wl_p2p_if_t;
+
+/** i/f query */
+typedef struct wl_p2p_ifq {
+ uint32 bsscfgidx;
+ char ifname[BCM_MSG_IFNAME_MAX];
+} wl_p2p_ifq_t;
+
+/** OppPS & CTWindow */
+typedef struct wl_p2p_ops {
+ uint8 ops; /**< 0: disable 1: enable */
+ uint8 ctw; /**< >= 10 */
+} wl_p2p_ops_t;
+
+/** absence and presence request */
+typedef struct wl_p2p_sched_desc {
+ uint32 start;
+ uint32 interval;
+ uint32 duration;
+ uint32 count; /**< see count */
+} wl_p2p_sched_desc_t;
+
+typedef struct wl_p2p_sched {
+ uint8 type; /**< see schedule type */
+ uint8 action; /**< see schedule action */
+ uint8 option; /**< see schedule option */
+ wl_p2p_sched_desc_t desc[1];
+} wl_p2p_sched_t;
+
+typedef struct wl_p2p_wfds_hash {
+ uint32 advt_id;
+ uint16 nw_cfg_method;
+ uint8 wfds_hash[6];
+ uint8 name_len;
+ uint8 service_name[MAX_WFDS_SVC_NAME_LEN];
+} wl_p2p_wfds_hash_t;
+
+typedef struct wl_bcmdcs_data {
+ uint32 reason;
+ chanspec_t chspec;
+} wl_bcmdcs_data_t;
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/* ifdef EXT_STA */
+/**
+ * Format of IHV data passed to OID_DOT11_NIC_SPECIFIC_EXTENSION.
+ */
+typedef struct _IHV_NIC_SPECIFIC_EXTENSION {
+ uint8 oui[4]; /**< vendor specific OUI value */
+ uint32 event; /**< event code */
+ uint8 ihvData[1]; /**< ihv data */
+} IHV_NIC_SPECIFIC_EXTENSION, *PIHV_NIC_SPECIFIC_EXTENSION;
+#define IHV_NIC_SPECIFIC_EXTENTION_HEADER OFFSETOF(IHV_NIC_SPECIFIC_EXTENSION, ihvData[0])
+/* EXT_STA */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/** NAT configuration */
+typedef struct {
+ uint32 ipaddr; /**< interface ip address */
+ uint32 ipaddr_mask; /**< interface ip address mask */
+ uint32 ipaddr_gateway; /**< gateway ip address */
+ uint8 mac_gateway[6]; /**< gateway mac address */
+ uint32 ipaddr_dns; /**< DNS server ip address, valid only for public if */
+ uint8 mac_dns[6]; /**< DNS server mac address, valid only for public if */
+ uint8 GUID[38]; /**< interface GUID */
+} nat_if_info_t;
+
+typedef struct {
+ uint32 op; /**< operation code */
+ uint8 pub_if; /**< set for public if, clear for private if */
+ nat_if_info_t if_info; /**< interface info */
+} nat_cfg_t;
+
+typedef struct {
+ int32 state; /**< NAT state returned */
+} nat_state_t;
+
+typedef struct flush_txfifo {
+ uint32 txfifobmp;
+ uint32 hwtxfifoflush;
+ struct ether_addr ea;
+} flush_txfifo_t;
+
+enum {
+ SPATIAL_MODE_2G_IDX = 0,
+ SPATIAL_MODE_5G_LOW_IDX,
+ SPATIAL_MODE_5G_MID_IDX,
+ SPATIAL_MODE_5G_HIGH_IDX,
+ SPATIAL_MODE_5G_UPPER_IDX,
+ SPATIAL_MODE_MAX_IDX
+};
+
+#define WLC_TXCORE_MAX 4 /**< max number of txcore supports */
+#define WLC_TXCORE_MAX_OLD 2 /**< backward compatibilty for TXCAL */
+#define WLC_SUBBAND_MAX 4 /**< max number of sub-band supports */
+typedef struct {
+ uint8 band2g[WLC_TXCORE_MAX];
+ uint8 band5g[WLC_SUBBAND_MAX][WLC_TXCORE_MAX];
+} sar_limit_t;
+
+#define MAX_NUM_TXCAL_MEAS 128
+#define MAX_NUM_PWR_STEP 40
+#define TXCAL_IOVAR_VERSION 0x1
+typedef struct wl_txcal_meas_percore {
+ uint16 tssi[MAX_NUM_TXCAL_MEAS];
+ int16 pwr[MAX_NUM_TXCAL_MEAS];
+} wl_txcal_meas_percore_t;
+
+typedef struct wl_txcal_meas_ncore {
+ uint16 version;
+ uint8 valid_cnt;
+ uint8 num_core;
+ wl_txcal_meas_percore_t txcal_percore[1];
+} wl_txcal_meas_ncore_t;
+
+typedef struct wl_txcal_power_tssi_percore {
+ int16 tempsense;
+ int16 pwr_start;
+ uint8 pwr_start_idx;
+ uint8 num_entries;
+ uint16 pad;
+ uint8 tssi[MAX_NUM_PWR_STEP];
+} wl_txcal_power_tssi_percore_t;
+
+typedef struct wl_txcal_power_tssi_ncore {
+ uint16 version;
+ uint8 set_core;
+ uint8 channel;
+ uint8 num_core;
+ uint8 gen_tbl;
+ uint16 pad;
+ wl_txcal_power_tssi_percore_t tssi_percore[1];
+} wl_txcal_power_tssi_ncore_t;
+
+typedef struct wl_txcal_meas {
+ uint16 tssi[WLC_TXCORE_MAX][MAX_NUM_TXCAL_MEAS];
+ int16 pwr[WLC_TXCORE_MAX][MAX_NUM_TXCAL_MEAS];
+ uint8 valid_cnt;
+} wl_txcal_meas_t;
+
+typedef struct wl_txcal_meas_old {
+ uint16 tssi[WLC_TXCORE_MAX_OLD][MAX_NUM_TXCAL_MEAS];
+ int16 pwr[WLC_TXCORE_MAX_OLD][MAX_NUM_TXCAL_MEAS];
+ uint8 valid_cnt;
+} wl_txcal_meas_old_t;
+
+typedef struct wl_txcal_power_tssi {
+ uint8 set_core;
+ uint8 channel;
+ int16 tempsense[WLC_TXCORE_MAX];
+ int16 pwr_start[WLC_TXCORE_MAX];
+ uint8 pwr_start_idx[WLC_TXCORE_MAX];
+ uint8 num_entries[WLC_TXCORE_MAX];
+ uint8 tssi[WLC_TXCORE_MAX][MAX_NUM_PWR_STEP];
+ uint8 gen_tbl;
+} wl_txcal_power_tssi_t;
+
+typedef struct wl_txcal_power_tssi_old {
+ uint8 set_core;
+ uint8 channel;
+ int16 tempsense[WLC_TXCORE_MAX_OLD];
+ int16 pwr_start[WLC_TXCORE_MAX_OLD];
+ uint8 pwr_start_idx[WLC_TXCORE_MAX_OLD];
+ uint8 num_entries[WLC_TXCORE_MAX_OLD];
+ uint8 tssi[WLC_TXCORE_MAX_OLD][MAX_NUM_PWR_STEP];
+ uint8 gen_tbl;
+} wl_txcal_power_tssi_old_t;
+
+typedef struct wl_olpc_pwr {
+ uint16 version;
+ uint8 core;
+ uint8 channel;
+ int16 tempsense;
+ uint8 olpc_idx;
+ uint8 pad;
+} wl_olpc_pwr_t;
+
+/** IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */
+typedef struct wl_mempool_stats {
+ int32 num; /**< Number of memory pools */
+ bcm_mp_stats_t s[1]; /**< Variable array of memory pool stats. */
+} wl_mempool_stats_t;
+
+typedef struct {
+ uint32 ipaddr;
+ uint32 ipaddr_netmask;
+ uint32 ipaddr_gateway;
+} nwoe_ifconfig_t;
+
+/** Traffic management priority classes */
+typedef enum trf_mgmt_priority_class {
+ trf_mgmt_priority_low = 0, /**< Maps to 802.1p BK */
+ trf_mgmt_priority_medium = 1, /**< Maps to 802.1p BE */
+ trf_mgmt_priority_high = 2, /**< Maps to 802.1p VI */
+ trf_mgmt_priority_nochange = 3, /**< do not update the priority */
+ trf_mgmt_priority_invalid = (trf_mgmt_priority_nochange + 1)
+} trf_mgmt_priority_class_t;
+
+/** Traffic management configuration parameters */
+typedef struct trf_mgmt_config {
+ uint32 trf_mgmt_enabled; /**< 0 - disabled, 1 - enabled */
+ uint32 flags; /**< See TRF_MGMT_FLAG_xxx defines */
+ uint32 host_ip_addr; /**< My IP address to determine subnet */
+ uint32 host_subnet_mask; /**< My subnet mask */
+ uint32 downlink_bandwidth; /**< In units of kbps */
+ uint32 uplink_bandwidth; /**< In units of kbps */
+ uint32 min_tx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /**< Minimum guaranteed tx bandwidth */
+ uint32 min_rx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /**< Minimum guaranteed rx bandwidth */
+} trf_mgmt_config_t;
+
+/** Traffic management filter */
+typedef struct trf_mgmt_filter {
+ struct ether_addr dst_ether_addr; /**< His L2 address */
+ uint32 dst_ip_addr; /**< His IP address */
+ uint16 dst_port; /**< His L4 port */
+ uint16 src_port; /**< My L4 port */
+ uint16 prot; /**< L4 protocol (only TCP or UDP) */
+ uint16 flags; /**< TBD. For now, this must be zero. */
+ trf_mgmt_priority_class_t priority; /**< Priority for filtered packets */
+ uint32 dscp; /**< DSCP */
+} trf_mgmt_filter_t;
+
+/** Traffic management filter list (variable length) */
+typedef struct trf_mgmt_filter_list {
+ uint32 num_filters;
+ trf_mgmt_filter_t filter[1];
+} trf_mgmt_filter_list_t;
+
+/** Traffic management global info used for all queues */
+typedef struct trf_mgmt_global_info {
+ uint32 maximum_bytes_per_second;
+ uint32 maximum_bytes_per_sampling_period;
+ uint32 total_bytes_consumed_per_second;
+ uint32 total_bytes_consumed_per_sampling_period;
+ uint32 total_unused_bytes_per_sampling_period;
+} trf_mgmt_global_info_t;
+
+/** Traffic management shaping info per priority queue */
+typedef struct trf_mgmt_shaping_info {
+ uint32 gauranteed_bandwidth_percentage;
+ uint32 guaranteed_bytes_per_second;
+ uint32 guaranteed_bytes_per_sampling_period;
+ uint32 num_bytes_produced_per_second;
+ uint32 num_bytes_consumed_per_second;
+ uint32 num_queued_packets; /**< Number of packets in queue */
+ uint32 num_queued_bytes; /**< Number of bytes in queue */
+} trf_mgmt_shaping_info_t;
+
+/** Traffic management shaping info array */
+typedef struct trf_mgmt_shaping_info_array {
+ trf_mgmt_global_info_t tx_global_shaping_info;
+ trf_mgmt_shaping_info_t tx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES];
+ trf_mgmt_global_info_t rx_global_shaping_info;
+ trf_mgmt_shaping_info_t rx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES];
+} trf_mgmt_shaping_info_array_t;
+
+
+/** Traffic management statistical counters */
+typedef struct trf_mgmt_stats {
+ uint32 num_processed_packets; /**< Number of packets processed */
+ uint32 num_processed_bytes; /**< Number of bytes processed */
+ uint32 num_discarded_packets; /**< Number of packets discarded from queue */
+} trf_mgmt_stats_t;
+
+/** Traffic management statistics array */
+typedef struct trf_mgmt_stats_array {
+ trf_mgmt_stats_t tx_queue_stats[TRF_MGMT_MAX_PRIORITIES];
+ trf_mgmt_stats_t rx_queue_stats[TRF_MGMT_MAX_PRIORITIES];
+} trf_mgmt_stats_array_t;
+
+/* Both powersel_params and lpc_params are used by IOVAR lpc_params.
+ * The powersel_params is replaced by lpc_params in later WLC versions.
+ */
+typedef struct powersel_params {
+ /* LPC Params exposed via IOVAR */
+ int32 tp_ratio_thresh; /**< Throughput ratio threshold */
+ uint8 rate_stab_thresh; /**< Thresh for rate stability based on nupd */
+ uint8 pwr_stab_thresh; /**< Number of successes before power step down */
+ uint8 pwr_sel_exp_time; /**< Time lapse for expiry of database */
+} powersel_params_t;
+
+#define WL_LPC_PARAMS_VER_2 2
+#define WL_LPC_PARAMS_CURRENT_VERSION WL_LPC_PARAMS_VER_2
+
+typedef struct lpc_params {
+ uint16 version;
+ uint16 length;
+ /* LPC Params exposed via IOVAR */
+ uint8 rate_stab_thresh; /**< Thresh for rate stability based on nupd */
+ uint8 pwr_stab_thresh; /**< Number of successes before power step down */
+ uint8 lpc_exp_time; /**< Time lapse for expiry of database */
+ uint8 pwrup_slow_step; /**< Step size for slow step up */
+ uint8 pwrup_fast_step; /**< Step size for fast step up */
+ uint8 pwrdn_slow_step; /**< Step size for slow step down */
+} lpc_params_t;
+
+/* tx pkt delay statistics */
+#define SCB_RETRY_SHORT_DEF 7 /**< Default Short retry Limit */
+#define WLPKTDLY_HIST_NBINS 16 /**< number of bins used in the Delay histogram */
+
+/** structure to store per-AC delay statistics */
+typedef struct scb_delay_stats {
+ uint32 txmpdu_lost; /**< number of MPDUs lost */
+ uint32 txmpdu_cnt[SCB_RETRY_SHORT_DEF]; /**< retry times histogram */
+ uint32 delay_sum[SCB_RETRY_SHORT_DEF]; /**< cumulative packet latency */
+ uint32 delay_min; /**< minimum packet latency observed */
+ uint32 delay_max; /**< maximum packet latency observed */
+ uint32 delay_avg; /**< packet latency average */
+ uint32 delay_hist[WLPKTDLY_HIST_NBINS]; /**< delay histogram */
+ uint32 delay_count; /**< minimum number of time period units before
+ consequent packet delay events can be generated
+ */
+ uint32 prev_txmpdu_cnt; /**< Previous value of txmpdu_cnt[] during last iteration */
+ uint32 prev_delay_sum; /**< Previous value of delay_sum[] during last iteration */
+} scb_delay_stats_t;
+
+/** structure for txdelay event */
+typedef struct txdelay_event {
+ uint8 status;
+ int32 rssi;
+ chanim_stats_t chanim_stats;
+ scb_delay_stats_t delay_stats[AC_COUNT];
+} txdelay_event_t;
+
+/** structure for txdelay parameters */
+typedef struct txdelay_params {
+ uint16 ratio; /**< Avg Txdelay Delta */
+ uint8 cnt; /**< Sample cnt */
+ uint8 period; /**< Sample period */
+ uint8 tune; /**< Debug */
+} txdelay_params_t;
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define MAX_TXDELAY_STATS_SCBS 6
+#define TXDELAY_STATS_VERSION 1
+
+enum {
+ TXDELAY_STATS_PARTIAL_RESULT = 0,
+ TXDELAY_STATS_FULL_RESULT = 1
+};
+
+typedef struct scb_total_delay_stats {
+ struct ether_addr ea;
+ uint8 pad[2];
+ scb_delay_stats_t dlystats[AC_COUNT];
+} scb_total_delay_stats_t;
+
+typedef struct txdelay_stats {
+ uint32 version;
+ uint32 full_result; /* 0:Partial, 1:full */
+ uint32 scb_cnt; /* in:requested, out:returned */
+ scb_total_delay_stats_t scb_delay_stats[1];
+} txdelay_stats_t;
+
+#define WL_TXDELAY_STATS_FIXED_SIZE \
+ (sizeof(txdelay_stats_t)+(MAX_TXDELAY_STATS_SCBS-1)*sizeof(scb_total_delay_stats_t))
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+enum {
+ WNM_SERVICE_DMS = 1,
+ WNM_SERVICE_FMS = 2,
+ WNM_SERVICE_TFS = 3
+};
+
+/** Definitions for WNM/NPS TCLAS */
+typedef struct wl_tclas {
+ uint8 user_priority;
+ uint8 fc_len;
+ dot11_tclas_fc_t fc;
+} wl_tclas_t;
+
+#define WL_TCLAS_FIXED_SIZE OFFSETOF(wl_tclas_t, fc)
+
+typedef struct wl_tclas_list {
+ uint32 num;
+ wl_tclas_t tclas[1];
+} wl_tclas_list_t;
+
+/** Definitions for WNM/NPS Traffic Filter Service */
+typedef struct wl_tfs_req {
+ uint8 tfs_id;
+ uint8 tfs_actcode;
+ uint8 tfs_subelem_id;
+ uint8 send;
+} wl_tfs_req_t;
+
+typedef struct wl_tfs_filter {
+ uint8 status; /**< Status returned by the AP */
+ uint8 tclas_proc; /**< TCLAS processing value (0:and, 1:or) */
+ uint8 tclas_cnt; /**< count of all wl_tclas_t in tclas array */
+ uint8 tclas[1]; /**< VLA of wl_tclas_t */
+} wl_tfs_filter_t;
+#define WL_TFS_FILTER_FIXED_SIZE OFFSETOF(wl_tfs_filter_t, tclas)
+
+typedef struct wl_tfs_fset {
+ struct ether_addr ea; /**< Address of AP/STA involved with this filter set */
+ uint8 tfs_id; /**< TFS ID field chosen by STA host */
+ uint8 status; /**< Internal status TFS_STATUS_xxx */
+ uint8 actcode; /**< Action code DOT11_TFS_ACTCODE_xxx */
+ uint8 token; /**< Token used in last request frame */
+ uint8 notify; /**< Notify frame sent/received because of this set */
+ uint8 filter_cnt; /**< count of all wl_tfs_filter_t in filter array */
+ uint8 filter[1]; /**< VLA of wl_tfs_filter_t */
+} wl_tfs_fset_t;
+#define WL_TFS_FSET_FIXED_SIZE OFFSETOF(wl_tfs_fset_t, filter)
+
+enum {
+ TFS_STATUS_DISABLED = 0, /**< TFS filter set disabled by user */
+ TFS_STATUS_DISABLING = 1, /**< Empty request just sent to AP */
+ TFS_STATUS_VALIDATED = 2, /**< Filter set validated by AP (but maybe not enabled!) */
+ TFS_STATUS_VALIDATING = 3, /**< Filter set just sent to AP */
+ TFS_STATUS_NOT_ASSOC = 4, /**< STA not associated */
+ TFS_STATUS_NOT_SUPPORT = 5, /**< TFS not supported by AP */
+ TFS_STATUS_DENIED = 6, /**< Filter set refused by AP (=> all sets are disabled!) */
+};
+
+typedef struct wl_tfs_status {
+ uint8 fset_cnt; /**< count of all wl_tfs_fset_t in fset array */
+ wl_tfs_fset_t fset[1]; /**< VLA of wl_tfs_fset_t */
+} wl_tfs_status_t;
+
+typedef struct wl_tfs_set {
+ uint8 send; /**< Immediatly register registered sets on AP side */
+ uint8 tfs_id; /**< ID of a specific set (existing or new), or nul for all */
+ uint8 actcode; /**< Action code for this filter set */
+ uint8 tclas_proc; /**< TCLAS processing operator for this filter set */
+} wl_tfs_set_t;
+
+typedef struct wl_tfs_term {
+ uint8 del; /**< Delete internal set once confirmation received */
+ uint8 tfs_id; /**< ID of a specific set (existing), or nul for all */
+} wl_tfs_term_t;
+
+
+#define DMS_DEP_PROXY_ARP (1 << 0)
+
+/* Definitions for WNM/NPS Directed Multicast Service */
+enum {
+ DMS_STATUS_DISABLED = 0, /**< DMS desc disabled by user */
+ DMS_STATUS_ACCEPTED = 1, /**< Request accepted by AP */
+ DMS_STATUS_NOT_ASSOC = 2, /**< STA not associated */
+ DMS_STATUS_NOT_SUPPORT = 3, /**< DMS not supported by AP */
+ DMS_STATUS_DENIED = 4, /**< Request denied by AP */
+ DMS_STATUS_TERM = 5, /**< Request terminated by AP */
+ DMS_STATUS_REMOVING = 6, /**< Remove request just sent */
+ DMS_STATUS_ADDING = 7, /**< Add request just sent */
+ DMS_STATUS_ERROR = 8, /**< Non compliant AP behvior */
+ DMS_STATUS_IN_PROGRESS = 9, /**< Request just sent */
+ DMS_STATUS_REQ_MISMATCH = 10 /**< Conditions for sending DMS req not met */
+};
+
+typedef struct wl_dms_desc {
+ uint8 user_id;
+ uint8 status;
+ uint8 token;
+ uint8 dms_id;
+ uint8 tclas_proc;
+ uint8 mac_len; /**< length of all ether_addr in data array, 0 if STA */
+ uint8 tclas_len; /**< length of all wl_tclas_t in data array */
+ uint8 data[1]; /**< VLA of 'ether_addr' and 'wl_tclas_t' (in this order ) */
+} wl_dms_desc_t;
+
+#define WL_DMS_DESC_FIXED_SIZE OFFSETOF(wl_dms_desc_t, data)
+
+typedef struct wl_dms_status {
+ uint32 cnt;
+ wl_dms_desc_t desc[1];
+} wl_dms_status_t;
+
+typedef struct wl_dms_set {
+ uint8 send;
+ uint8 user_id;
+ uint8 tclas_proc;
+} wl_dms_set_t;
+
+typedef struct wl_dms_term {
+ uint8 del;
+ uint8 user_id;
+} wl_dms_term_t;
+
+typedef struct wl_service_term {
+ uint8 service;
+ union {
+ wl_dms_term_t dms;
+ } u;
+} wl_service_term_t;
+
+/** Definitions for WNM/NPS BSS Transistion */
+typedef struct wl_bsstrans_req {
+ uint16 tbtt; /**< time of BSS to end of life, in unit of TBTT */
+ uint16 dur; /**< time of BSS to keep off, in unit of minute */
+ uint8 reqmode; /**< request mode of BSS transition request */
+ uint8 unicast; /**< request by unicast or by broadcast */
+} wl_bsstrans_req_t;
+
+enum {
+ BSSTRANS_RESP_AUTO = 0, /**< Currently equivalent to ENABLE */
+ BSSTRANS_RESP_DISABLE = 1, /**< Never answer BSS Trans Req frames */
+ BSSTRANS_RESP_ENABLE = 2, /**< Always answer Req frames with preset data */
+ BSSTRANS_RESP_WAIT = 3, /**< Send ind, wait and/or send preset data (NOT IMPL) */
+ BSSTRANS_RESP_IMMEDIATE = 4 /**< After an ind, set data and send resp (NOT IMPL) */
+};
+
+typedef struct wl_bsstrans_resp {
+ uint8 policy;
+ uint8 status;
+ uint8 delay;
+ struct ether_addr target;
+} wl_bsstrans_resp_t;
+
+/* "wnm_bsstrans_policy" argument programs behavior after BSSTRANS Req reception.
+ * BSS-Transition feature is used by multiple programs such as NPS-PF, VE-PF,
+ * Band-steering, Hotspot 2.0 and customer requirements. Each PF and its test plan
+ * mandates different behavior on receiving BSS-transition request. To accomodate
+ * such divergent behaviors these policies have been created.
+ */
+typedef enum {
+ WL_BSSTRANS_POLICY_ROAM_ALWAYS = 0, /**< Roam (or disassociate) in all cases */
+ WL_BSSTRANS_POLICY_ROAM_IF_MODE = 1, /**< Roam only if requested by Request Mode field */
+ WL_BSSTRANS_POLICY_ROAM_IF_PREF = 2, /**< Roam only if Preferred BSS provided */
+ WL_BSSTRANS_POLICY_WAIT = 3, /**< Wait for deauth and send Accepted status */
+ WL_BSSTRANS_POLICY_PRODUCT = 4, /**< Policy for real product use cases (Olympic) */
+ WL_BSSTRANS_POLICY_PRODUCT_WBTEXT = 5, /**< Policy for real product use cases (SS) */
+ WL_BSSTRANS_POLICY_MAX = 6
+} wnm_bsstrans_policy_type_t;
+
+/** Definitions for WNM/NPS TIM Broadcast */
+typedef struct wl_timbc_offset {
+ int16 offset; /**< offset in us */
+ uint16 fix_intv; /**< override interval sent from STA */
+ uint16 rate_override; /**< use rate override to send high rate TIM broadcast frame */
+ uint8 tsf_present; /**< show timestamp in TIM broadcast frame */
+} wl_timbc_offset_t;
+
+typedef struct wl_timbc_set {
+ uint8 interval; /**< Interval in DTIM wished or required. */
+ uint8 flags; /**< Bitfield described below */
+ uint16 rate_min; /**< Minimum rate required for High/Low TIM frames. Optionnal */
+ uint16 rate_max; /**< Maximum rate required for High/Low TIM frames. Optionnal */
+} wl_timbc_set_t;
+
+enum {
+ WL_TIMBC_SET_TSF_REQUIRED = 1, /**< Enable TIMBC only if TSF in TIM frames */
+ WL_TIMBC_SET_NO_OVERRIDE = 2, /**< ... if AP does not override interval */
+ WL_TIMBC_SET_PROXY_ARP = 4, /**< ... if AP support Proxy ARP */
+ WL_TIMBC_SET_DMS_ACCEPTED = 8 /**< ... if all DMS desc have been accepted */
+};
+
+typedef struct wl_timbc_status {
+ uint8 status_sta; /**< Status from internal state machine (check below) */
+ uint8 status_ap; /**< From AP response frame (check 8.4.2.86 from 802.11) */
+ uint8 interval;
+ uint8 pad;
+ int32 offset;
+ uint16 rate_high;
+ uint16 rate_low;
+} wl_timbc_status_t;
+
+enum {
+ WL_TIMBC_STATUS_DISABLE = 0, /**< TIMBC disabled by user */
+ WL_TIMBC_STATUS_REQ_MISMATCH = 1, /**< AP settings do no match user requirements */
+ WL_TIMBC_STATUS_NOT_ASSOC = 2, /**< STA not associated */
+ WL_TIMBC_STATUS_NOT_SUPPORT = 3, /**< TIMBC not supported by AP */
+ WL_TIMBC_STATUS_DENIED = 4, /**< Req to disable TIMBC sent to AP */
+ WL_TIMBC_STATUS_ENABLE = 5 /**< TIMBC enabled */
+};
+
+/** Definitions for PM2 Dynamic Fast Return To Sleep */
+typedef struct wl_pm2_sleep_ret_ext {
+ uint8 logic; /**< DFRTS logic: see WL_DFRTS_LOGIC_* below */
+ uint16 low_ms; /**< Low FRTS timeout */
+ uint16 high_ms; /**< High FRTS timeout */
+ uint16 rx_pkts_threshold; /**< switching threshold: # rx pkts */
+ uint16 tx_pkts_threshold; /**< switching threshold: # tx pkts */
+ uint16 txrx_pkts_threshold; /**< switching threshold: # (tx+rx) pkts */
+ uint32 rx_bytes_threshold; /**< switching threshold: # rx bytes */
+ uint32 tx_bytes_threshold; /**< switching threshold: # tx bytes */
+ uint32 txrx_bytes_threshold; /**< switching threshold: # (tx+rx) bytes */
+} wl_pm2_sleep_ret_ext_t;
+
+#define WL_DFRTS_LOGIC_OFF 0 /**< Feature is disabled */
+#define WL_DFRTS_LOGIC_OR 1 /**< OR all non-zero threshold conditions */
+#define WL_DFRTS_LOGIC_AND 2 /**< AND all non-zero threshold conditions */
+
+/* Values for the passive_on_restricted_mode iovar. When set to non-zero, this iovar
+ * disables automatic conversions of a channel from passively scanned to
+ * actively scanned. These values only have an effect for country codes such
+ * as XZ where some 5 GHz channels are defined to be passively scanned.
+ */
+#define WL_PASSACTCONV_DISABLE_NONE 0 /**< Enable permanent and temporary conversions */
+#define WL_PASSACTCONV_DISABLE_ALL 1 /**< Disable permanent and temporary conversions */
+#define WL_PASSACTCONV_DISABLE_PERM 2 /**< Disable only permanent conversions */
+
+/* Definitions for Reliable Multicast */
+#define WL_RMC_CNT_VERSION 1
+#define WL_RMC_TR_VERSION 1
+#define WL_RMC_MAX_CLIENT 32
+#define WL_RMC_FLAG_INBLACKLIST 1
+#define WL_RMC_FLAG_ACTIVEACKER 2
+#define WL_RMC_FLAG_RELMCAST 4
+#define WL_RMC_MAX_TABLE_ENTRY 4
+
+#define WL_RMC_VER 1
+#define WL_RMC_INDEX_ACK_ALL 255
+#define WL_RMC_NUM_OF_MC_STREAMS 4
+#define WL_RMC_MAX_TRS_PER_GROUP 1
+#define WL_RMC_MAX_TRS_IN_ACKALL 1
+#define WL_RMC_ACK_MCAST0 0x02
+#define WL_RMC_ACK_MCAST_ALL 0x01
+#define WL_RMC_ACTF_TIME_MIN 300 /**< time in ms */
+#define WL_RMC_ACTF_TIME_MAX 20000 /**< time in ms */
+#define WL_RMC_MAX_NUM_TRS 32 /**< maximun transmitters allowed */
+#define WL_RMC_ARTMO_MIN 350 /**< time in ms */
+#define WL_RMC_ARTMO_MAX 40000 /**< time in ms */
+
+/* RMC events in action frames */
+enum rmc_opcodes {
+ RELMCAST_ENTRY_OP_DISABLE = 0, /**< Disable multi-cast group */
+ RELMCAST_ENTRY_OP_DELETE = 1, /**< Delete multi-cast group */
+ RELMCAST_ENTRY_OP_ENABLE = 2, /**< Enable multi-cast group */
+ RELMCAST_ENTRY_OP_ACK_ALL = 3 /**< Enable ACK ALL bit in AMT */
+};
+
+/* RMC operational modes */
+enum rmc_modes {
+ WL_RMC_MODE_RECEIVER = 0, /**< Receiver mode by default */
+ WL_RMC_MODE_TRANSMITTER = 1, /**< Transmitter mode using wl ackreq */
+ WL_RMC_MODE_INITIATOR = 2 /**< Initiator mode using wl ackreq */
+};
+
+/** Each RMC mcast client info */
+typedef struct wl_relmcast_client {
+ uint8 flag; /**< status of client such as AR, R, or blacklisted */
+ int16 rssi; /**< rssi value of RMC client */
+ struct ether_addr addr; /**< mac address of RMC client */
+} wl_relmcast_client_t;
+
+/** RMC Counters */
+typedef struct wl_rmc_cnts {
+ uint16 version; /**< see definition of WL_CNT_T_VERSION */
+ uint16 length; /**< length of entire structure */
+ uint16 dupcnt; /**< counter for duplicate rmc MPDU */
+ uint16 ackreq_err; /**< counter for wl ackreq error */
+ uint16 af_tx_err; /**< error count for action frame transmit */
+ uint16 null_tx_err; /**< error count for rmc null frame transmit */
+ uint16 af_unicast_tx_err; /**< error count for rmc unicast frame transmit */
+ uint16 mc_no_amt_slot; /**< No mcast AMT entry available */
+ /* Unused. Keep for rom compatibility */
+ uint16 mc_no_glb_slot; /**< No mcast entry available in global table */
+ uint16 mc_not_mirrored; /**< mcast group is not mirrored */
+ uint16 mc_existing_tr; /**< mcast group is already taken by transmitter */
+ uint16 mc_exist_in_amt; /**< mcast group is already programmed in amt */
+ /* Unused. Keep for rom compatibility */
+ uint16 mc_not_exist_in_gbl; /**< mcast group is not in global table */
+ uint16 mc_not_exist_in_amt; /**< mcast group is not in AMT table */
+ uint16 mc_utilized; /**< mcast addressed is already taken */
+ uint16 mc_taken_other_tr; /**< multi-cast addressed is already taken */
+ uint32 rmc_rx_frames_mac; /**< no of mc frames received from mac */
+ uint32 rmc_tx_frames_mac; /**< no of mc frames transmitted to mac */
+ uint32 mc_null_ar_cnt; /**< no. of times NULL AR is received */
+ uint32 mc_ar_role_selected; /**< no. of times took AR role */
+ uint32 mc_ar_role_deleted; /**< no. of times AR role cancelled */
+ uint32 mc_noacktimer_expired; /**< no. of times noack timer expired */
+ uint16 mc_no_wl_clk; /**< no wl clk detected when trying to access amt */
+ uint16 mc_tr_cnt_exceeded; /**< No of transmitters in the network exceeded */
+} wl_rmc_cnts_t;
+
+/** RMC Status */
+typedef struct wl_relmcast_st {
+ uint8 ver; /**< version of RMC */
+ uint8 num; /**< number of clients detected by transmitter */
+ wl_relmcast_client_t clients[WL_RMC_MAX_CLIENT];
+ uint16 err; /**< error status (used in infra) */
+ uint16 actf_time; /**< action frame time period */
+} wl_relmcast_status_t;
+
+/** Entry for each STA/node */
+typedef struct wl_rmc_entry {
+ /* operation on multi-cast entry such add,
+ * delete, ack-all
+ */
+ int8 flag;
+ struct ether_addr addr; /**< multi-cast group mac address */
+} wl_rmc_entry_t;
+
+/** RMC table */
+typedef struct wl_rmc_entry_table {
+ uint8 index; /**< index to a particular mac entry in table */
+ uint8 opcode; /**< opcodes or operation on entry */
+ wl_rmc_entry_t entry[WL_RMC_MAX_TABLE_ENTRY];
+} wl_rmc_entry_table_t;
+
+typedef struct wl_rmc_trans_elem {
+ struct ether_addr tr_mac; /**< transmitter mac */
+ struct ether_addr ar_mac; /**< ar mac */
+ uint16 artmo; /**< AR timeout */
+ uint8 amt_idx; /**< amt table entry */
+ uint16 flag; /**< entry will be acked, not acked, programmed, full etc */
+} wl_rmc_trans_elem_t;
+
+/** RMC transmitters */
+typedef struct wl_rmc_trans_in_network {
+ uint8 ver; /**< version of RMC */
+ uint8 num_tr; /**< number of transmitters in the network */
+ wl_rmc_trans_elem_t trs[WL_RMC_MAX_NUM_TRS];
+} wl_rmc_trans_in_network_t;
+
+/** To update vendor specific ie for RMC */
+typedef struct wl_rmc_vsie {
+ uint8 oui[DOT11_OUI_LEN];
+ uint16 payload; /**< IE Data Payload */
+} wl_rmc_vsie_t;
+
+
+/* structures & defines for proximity detection */
+enum proxd_method {
+ PROXD_UNDEFINED_METHOD = 0,
+ PROXD_RSSI_METHOD = 1,
+ PROXD_TOF_METHOD = 2
+};
+
+/* structures for proximity detection device role */
+#define WL_PROXD_MODE_DISABLE 0
+#define WL_PROXD_MODE_NEUTRAL 1
+#define WL_PROXD_MODE_INITIATOR 2
+#define WL_PROXD_MODE_TARGET 3
+
+#define WL_PROXD_ACTION_STOP 0
+#define WL_PROXD_ACTION_START 1
+
+#define WL_PROXD_FLAG_TARGET_REPORT 0x1
+#define WL_PROXD_FLAG_REPORT_FAILURE 0x2
+#define WL_PROXD_FLAG_INITIATOR_REPORT 0x4
+#define WL_PROXD_FLAG_NOCHANSWT 0x8
+#define WL_PROXD_FLAG_NETRUAL 0x10
+#define WL_PROXD_FLAG_INITIATOR_RPTRTT 0x20
+#define WL_PROXD_FLAG_ONEWAY 0x40
+#define WL_PROXD_FLAG_SEQ_EN 0x80
+
+#define WL_PROXD_SETFLAG_K 0x1
+#define WL_PROXD_SETFLAG_N 0x2
+#define WL_PROXD_SETFLAG_S 0x4
+
+#define WL_PROXD_SETFLAG_K 0x1
+#define WL_PROXD_SETFLAG_N 0x2
+#define WL_PROXD_SETFLAG_S 0x4
+
+#define WL_PROXD_RANDOM_WAKEUP 0x8000
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_PROXD_MAXREPORT 8
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+typedef struct wl_proxd_iovar {
+ uint16 method; /**< Proximity Detection method */
+ uint16 mode; /**< Mode (neutral, initiator, target) */
+} wl_proxd_iovar_t;
+
+/*
+ * structures for proximity detection parameters
+ * consists of two parts, common and method specific params
+ * common params should be placed at the beginning
+ */
+
+typedef struct wl_proxd_params_common {
+ chanspec_t chanspec; /**< channel spec */
+ int16 tx_power; /**< tx power of Proximity Detection(PD) frames (in dBm) */
+ uint16 tx_rate; /**< tx rate of PD rames (in 500kbps units) */
+ uint16 timeout; /**< timeout value */
+ uint16 interval; /**< interval between neighbor finding attempts (in TU) */
+ uint16 duration; /**< duration of neighbor finding attempts (in ms) */
+} wl_proxd_params_common_t;
+
+typedef struct wl_proxd_params_rssi_method {
+ chanspec_t chanspec; /**< chanspec for home channel */
+ int16 tx_power; /**< tx power of Proximity Detection frames (in dBm) */
+ uint16 tx_rate; /**< tx rate of PD frames, 500kbps units */
+ uint16 timeout; /**< state machine wait timeout of the frames (in ms) */
+ uint16 interval; /**< interval between neighbor finding attempts (in TU) */
+ uint16 duration; /**< duration of neighbor finding attempts (in ms) */
+ /* method specific ones go after this line */
+ int16 rssi_thresh; /**< RSSI threshold (in dBm) */
+ uint16 maxconvergtmo; /**< max wait converge timeout (in ms) */
+} wl_proxd_params_rssi_method_t;
+
+#define Q1_NS 25 /**< Q1 time units */
+
+#define TOF_BW_NUM 3 /**< number of bandwidth that the TOF can support */
+#define TOF_BW_SEQ_NUM (TOF_BW_NUM+2) /* number of total index */
+enum tof_bw_index {
+ TOF_BW_20MHZ_INDEX = 0,
+ TOF_BW_40MHZ_INDEX = 1,
+ TOF_BW_80MHZ_INDEX = 2,
+ TOF_BW_SEQTX_INDEX = 3,
+ TOF_BW_SEQRX_INDEX = 4
+};
+
+#define BANDWIDTH_BASE 20 /**< base value of bandwidth */
+#define TOF_BW_20MHZ (BANDWIDTH_BASE << TOF_BW_20MHZ_INDEX)
+#define TOF_BW_40MHZ (BANDWIDTH_BASE << TOF_BW_40MHZ_INDEX)
+#define TOF_BW_80MHZ (BANDWIDTH_BASE << TOF_BW_80MHZ_INDEX)
+#define TOF_BW_10MHZ 10
+
+#define NFFT_BASE 64 /**< base size of fft */
+#define TOF_NFFT_20MHZ (NFFT_BASE << TOF_BW_20MHZ_INDEX)
+#define TOF_NFFT_40MHZ (NFFT_BASE << TOF_BW_40MHZ_INDEX)
+#define TOF_NFFT_80MHZ (NFFT_BASE << TOF_BW_80MHZ_INDEX)
+
+typedef struct wl_proxd_params_tof_method {
+ chanspec_t chanspec; /**< chanspec for home channel */
+ int16 tx_power; /**< tx power of Proximity Detection(PD) frames (in dBm) */
+ uint16 tx_rate; /**< tx rate of PD rames (in 500kbps units) */
+ uint16 timeout; /**< state machine wait timeout of the frames (in ms) */
+ uint16 interval; /**< interval between neighbor finding attempts (in TU) */
+ uint16 duration; /**< duration of neighbor finding attempts (in ms) */
+ /* specific for the method go after this line */
+ struct ether_addr tgt_mac; /**< target mac addr for TOF method */
+ uint16 ftm_cnt; /**< number of the frames txed by initiator */
+ uint16 retry_cnt; /**< number of retransmit attampts for ftm frames */
+ int16 vht_rate; /**< ht or vht rate */
+ /* add more params required for other methods can be added here */
+} wl_proxd_params_tof_method_t;
+
+typedef struct wl_proxd_seq_config
+{
+ int16 N_tx_log2;
+ int16 N_rx_log2;
+ int16 N_tx_scale;
+ int16 N_rx_scale;
+ int16 w_len;
+ int16 w_offset;
+} wl_proxd_seq_config_t;
+
+#define WL_PROXD_TUNE_VERSION_1 1
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_tune {
+ uint32 version;
+ uint32 Ki; /**< h/w delay K factor for initiator */
+ uint32 Kt; /**< h/w delay K factor for target */
+ int16 vhtack; /**< enable/disable VHT ACK */
+ int16 N_log2[TOF_BW_SEQ_NUM]; /**< simple threshold crossing */
+ int16 w_offset[TOF_BW_NUM]; /**< offset of threshold crossing window(per BW) */
+ int16 w_len[TOF_BW_NUM]; /**< length of threshold crossing window(per BW) */
+ int32 maxDT; /**< max time difference of T4/T1 or T3/T2 */
+ int32 minDT; /**< min time difference of T4/T1 or T3/T2 */
+ uint8 totalfrmcnt; /**< total count of transfered measurement frames */
+ uint16 rsv_media; /**< reserve media value for TOF */
+ uint32 flags; /**< flags */
+ uint8 core; /**< core to use for tx */
+ uint8 setflags; /* set flags of K, N. S values */
+ int16 N_scale[TOF_BW_SEQ_NUM]; /**< simple threshold crossing */
+ uint8 sw_adj; /**< enable sw assisted timestamp adjustment */
+ uint8 hw_adj; /**< enable hw assisted timestamp adjustment */
+ uint8 seq_en; /**< enable ranging sequence */
+ uint8 ftm_cnt[TOF_BW_SEQ_NUM]; /**< number of ftm frames based on bandwidth */
+ int16 N_log2_2g; /**< simple threshold crossing for 2g channel */
+ int16 N_scale_2g; /**< simple threshold crossing for 2g channel */
+ wl_proxd_seq_config_t seq_5g20;
+ wl_proxd_seq_config_t seq_2g20; /* Thresh crossing params for 2G Sequence */
+ uint16 bitflip_thresh; /* bitflip threshold */
+ uint16 snr_thresh; /* SNR threshold */
+ int8 recv_2g_thresh; /* 2g recieve sensitivity threshold */
+ uint32 acs_gdv_thresh;
+ int8 acs_rssi_thresh;
+ uint8 smooth_win_en;
+ int32 acs_gdmm_thresh;
+} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_tune_t;
+#include <packed_section_end.h>
+
+typedef struct wl_proxd_params_iovar {
+ uint16 method; /**< Proximity Detection method */
+ union {
+ /* common params for pdsvc */
+ wl_proxd_params_common_t cmn_params; /**< common parameters */
+ /* method specific */
+ wl_proxd_params_rssi_method_t rssi_params; /**< RSSI method parameters */
+ wl_proxd_params_tof_method_t tof_params; /**< TOF method parameters */
+ /* tune parameters */
+ wl_proxd_params_tof_tune_t tof_tune; /**< TOF tune parameters */
+ } u; /**< Method specific optional parameters */
+} wl_proxd_params_iovar_t;
+
+#define PROXD_COLLECT_GET_STATUS 0
+#define PROXD_COLLECT_SET_STATUS 1
+#define PROXD_COLLECT_QUERY_HEADER 2
+#define PROXD_COLLECT_QUERY_DATA 3
+#define PROXD_COLLECT_QUERY_DEBUG 4
+#define PROXD_COLLECT_REMOTE_REQUEST 5
+#define PROXD_COLLECT_DONE 6
+
+typedef enum {
+ WL_PROXD_COLLECT_METHOD_TYPE_DISABLE = 0x0,
+ WL_PROXD_COLLECT_METHOD_TYPE_IOVAR = 0x1,
+ WL_PROXD_COLLECT_METHOD_TYPE_EVENT = 0x2,
+ WL_PROXD_COLLECT_METHOD_TYPE_EVENT_LOG = 0x4
+} wl_proxd_collect_method_type_t;
+
+typedef uint16 wl_proxd_collect_method_t; /* query status: method to send proxd collect */
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_query {
+ uint32 method; /**< method */
+ uint8 request; /**< Query request. */
+ uint8 status; /**< bitmask 0 -- disable, 0x1 -- enable collection, */
+ /* 0x2 -- Use generic event, 0x4 -- use event log */
+ uint16 index; /**< The current frame index [0 to total_frames - 1]. */
+ uint16 mode; /**< Initiator or Target */
+ uint8 busy; /**< tof sm is busy */
+ uint8 remote; /**< Remote collect data */
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_query_t;
+#include <packed_section_end.h>
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_header {
+ uint16 total_frames; /**< The total frames for this collect. */
+ uint16 nfft; /**< nfft value */
+ uint16 bandwidth; /**< bandwidth */
+ uint16 channel; /**< channel number */
+ uint32 chanspec; /**< channel spec */
+ uint32 fpfactor; /**< avb timer value factor */
+ uint16 fpfactor_shift; /**< avb timer value shift bits */
+ int32 distance; /**< distance calculated by fw */
+ uint32 meanrtt; /**< mean of RTTs */
+ uint32 modertt; /**< mode of RTTs */
+ uint32 medianrtt; /**< median of RTTs */
+ uint32 sdrtt; /**< standard deviation of RTTs */
+ uint32 clkdivisor; /**< clock divisor */
+ uint16 chipnum; /**< chip type */
+ uint8 chiprev; /**< chip revision */
+ uint8 phyver; /**< phy version */
+ struct ether_addr localMacAddr; /**< local mac address */
+ struct ether_addr remoteMacAddr; /**< remote mac address */
+ wl_proxd_params_tof_tune_t params;
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_header_t;
+#include <packed_section_end.h>
+
+
+#ifdef WL_NAN
+/* ********************** NAN wl interface struct types and defs ******************** */
+/*
+ * Uses new common IOVAR batch processing mechanism
+ */
+
+/*
+ * Common macros
+ */
+#define WL_NAN_IOCTL_VERSION 0x2
+/* < some sufficient ioc buff size for our module */
+#define WL_NAN_IOC_BUFSZ 256
+/* some sufficient ioc buff size for dump commands */
+#define WL_NAN_IOC_BUFSZ_EXT 1024
+#define WL_NAN_MAX_SIDS_IN_BEACONS 127 /* Max allowed SIDs */
+#define WL_NAN_MASTER_RANK_LEN 8
+#define WL_NAN_RANGE_LIMITED 0x0040 /* Publish/Subscribe flags */
+
+/** Event generation indicator (default is continuous) */
+#define WL_NAN_MATCH_ONCE 0x100000
+#define WL_NAN_MATCH_NEVER 0x200000
+
+/* Bits specific to Publish */
+#define WL_NAN_PUB_UNSOLICIT 0x1000 /** Unsolicited transmissions */
+#define WL_NAN_PUB_SOLICIT 0x2000 /** Solicited transmissions */
+#define WL_NAN_PUB_BOTH 0x3000
+
+/**
+ * Set for broadcast solicited transmission.
+ * Do not set for unicast solicited transmission
+ */
+#define WL_NAN_PUB_BCAST 0x4000
+#define WL_NAN_PUB_EVENT 0x8000 /** Generate event on each solicited tx */
+#define WL_NAN_PUB_SOLICIT_PENDING 0x10000 /** solicited publish tx */
+
+/** Follow-up frames */
+#define WL_NAN_FOLLOWUP 0x20000
+
+/** Bits specific to Subscribe */
+/** Active subscribe mode (Leave unset for passive) */
+#define WL_NAN_SUB_ACTIVE 0x1000
+/** Service info in publish required for Match event */
+#define WL_NAN_SUB_MATCH_IF_SVC_INFO 0x2000
+
+/** Special values for time to live (ttl) parameter */
+#define WL_NAN_TTL_UNTIL_CANCEL 0xFFFFFFFF
+/* Publish - runs until first transmission
+ * Subscribe - runs until first DiscoveryResult event
+ */
+#define WL_NAN_TTL_FIRST 0
+
+/** The service hash (service id) is exactly this many bytes. */
+#define WL_NAN_SVC_HASH_LEN 6
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_NAN_HASHES_PER_BLOOM 4 /** Number of hash functions per bloom filter */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* no. of max last disc results */
+#define WL_NAN_MAX_DISC_RESULTS 3
+
+/* Max len of Rx and Tx filters */
+#define WL_NAN_MAX_SVC_MATCH_FILTER_LEN 255
+
+/* Max service name len */
+#define WL_NAN_MAX_SVC_NAME_LEN 32
+
+/* Type of Data path connection */
+#define WL_NAN_DP_TYPE_UNICAST 0
+#define WL_NAN_DP_TYPE_MULTICAST 1
+
+/* Post disc attr ID type */
+typedef uint8 wl_nan_post_disc_attr_id_t;
+
+/*
+ * Component IDs
+ */
+typedef enum {
+ WL_NAN_COMPID_CONFIG = 1,
+ WL_NAN_COMPID_ELECTION = 2,
+ WL_NAN_COMPID_SD = 3,
+ WL_NAN_COMPID_TIMESYNC = 4,
+ WL_NAN_COMPID_DATA_PATH = 5,
+ WL_NAN_COMPID_DEBUG = 15 /* Keep this at the end */
+} wl_nan_comp_id_t;
+
+#define WL_NAN_COMP_SHIFT 8
+#define WL_NAN_COMP_MASK(_c) (0x0F & ((uint8)(_c)))
+#define WL_NAN_COMP_ID(_c) (WL_NAN_COMP_MASK(_c) << WL_NAN_COMP_SHIFT)
+
+/* NAN Events */
+
+#define WLC_E_NAN_CRITICAL 1
+#define WLC_E_NAN_NON_CRITICAL 2
+
+/** Instance ID type (unique identifier) */
+typedef uint8 wl_nan_instance_id_t;
+
+/* Publish sent for a subscribe */
+/* WL_NAN_EVENT_REPLIED */
+
+typedef struct wl_nan_ev_replied {
+ struct ether_addr sub_mac; /* Subscriber MAC */
+ wl_nan_instance_id_t pub_id; /* Publisher Instance ID */
+ uint8 sub_id; /* Subscriber ID */
+ int8 sub_rssi; /* Subscriber RSSI */
+ uint8 pad[3];
+} wl_nan_ev_replied_t;
+
+/* Subscribe or Publish instance Terminated */
+
+/* WL_NAN_EVENT_TERMINATED */
+
+#define NAN_SD_TERM_REASON_TIMEOUT 1
+#define NAN_SD_TERM_REASON_HOSTREQ 2
+#define NAN_SD_TERM_REASON_FWTERM 3
+#define NAN_SD_TERM_REASON_FAIL 4
+
+typedef struct wl_nan_ev_terminated {
+ uint8 instance_id; /* publish / subscribe instance id */
+ uint8 reason; /* 1=timeout, 2=Host/IOVAR, 3=FW Terminated 4=Failure */
+ uint8 svctype; /* 0 - Publish, 0x1 - Subscribe */
+ uint8 pad; /* Align */
+} wl_nan_ev_terminated_t;
+
+/* Follow up received against a pub / subscr */
+/* WL_NAN_EVENT_RECEIVE */
+
+typedef struct wl_nan_ev_receive {
+ struct ether_addr remote_addr; /* Peer NAN device MAC */
+ uint8 local_id; /* Local subscribe or publish ID */
+ uint8 remote_id; /* Remote subscribe or publish ID */
+ int8 fup_rssi;
+ uint8 pad[3];
+} wl_nan_ev_receive_t;
+
+/*
+ * TLV IDs
+ */
+enum wl_nan_cmd_xtlv_id {
+ WL_NAN_XTLV_MAC_ADDR = 0x120,
+ WL_NAN_XTLV_MATCH_RX = 0x121,
+ WL_NAN_XTLV_MATCH_TX = 0x122,
+ WL_NAN_XTLV_SVC_INFO = 0x123,
+ WL_NAN_XTLV_SVC_NAME = 0x124,
+ WL_NAN_XTLV_SR_FILTER = 0x125,
+ WL_NAN_XTLV_FOLLOWUP = 0x126,
+ WL_NAN_XTLV_SVC_LIFE_COUNT = 0x127,
+ WL_NAN_XTLV_AVAIL = 0x128,
+ WL_NAN_XTLV_SDF_RX = 0x129,
+ WL_NAN_XTLV_SDE_CONTROL = 0x130,
+ WL_NAN_XTLV_SDE_RANGE_LIMIT = 0x131,
+ WL_NAN_XTLV_NAN_AF = 0x132,
+ WL_NAN_XTLV_SD_TERMINATE = 0x133,
+ WL_NAN_XTLV_CLUSTER_ID = 0x134,
+ WL_NAN_XTLV_PEER_RSSI = 0x135,
+ WL_NAN_XTLV_BCN_RX = 0x136,
+ WL_NAN_XTLV_REPLIED = 0x137, /* Publish sent for a subscribe */
+ WL_NAN_XTLV_RECEIVED = 0x138 /* FUP Received */
+};
+
+#define WL_NAN_CMD_CFG_COMP_ID 0x01
+#define WL_NAN_CMD_ELECTION_COMP_ID 0x02
+#define WL_NAN_CMD_SD_COMP_ID 0x03
+#define WL_NAN_CMD_SYNC_COMP_ID 0x04
+#define WL_NAN_CMD_DATA_COMP_ID 0x05
+#define WL_NAN_CMD_DAM_COMP_ID 0x06
+#define WL_NAN_CMD_RANGE_COMP_ID 0x07
+#define WL_NAN_CMD_DBG_COMP_ID 0x0f
+
+#define WL_NAN_CMD_COMP_SHIFT 8
+#define NAN_CMD(x, y) (((x) << WL_NAN_CMD_COMP_SHIFT) | (y))
+
+enum wl_nan_sub_cmd_xtlv_id {
+ /* nan cfg sub-commands */
+ WL_NAN_CMD_CFG_ENABLE = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x01),
+ WL_NAN_CMD_CFG_STATE = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x02),
+ WL_NAN_CMD_CFG_HOP_CNT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x03),
+ WL_NAN_CMD_CFG_HOP_LIMIT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x04),
+ WL_NAN_CMD_CFG_WARMUP_TIME = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x05),
+ WL_NAN_CMD_CFG_RSSI_THRESHOLD = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x06),
+ WL_NAN_CMD_CFG_STATUS = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x07),
+ WL_NAN_CMD_CFG_OUI = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x08),
+ WL_NAN_CMD_CFG_COUNT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x09),
+ WL_NAN_CMD_CFG_CLEARCOUNT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0a),
+ WL_NAN_CMD_CFG_CHANNEL = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0b),
+ WL_NAN_CMD_CFG_BAND = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0c),
+ WL_NAN_CMD_CFG_CID = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0d),
+ WL_NAN_CMD_CFG_IF_ADDR = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0e),
+ WL_NAN_CMD_CFG_BCN_INTERVAL = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0f),
+ WL_NAN_CMD_CFG_SDF_TXTIME = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x10),
+ WL_NAN_CMD_CFG_STOP_BCN_TX = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x11),
+ WL_NAN_CMD_CFG_SID_BEACON = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x12),
+ WL_NAN_CMD_CFG_DW_LEN = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x13),
+ WL_NAN_CMD_CFG_AVAIL = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x14),
+ WL_NAN_CMD_CFG_AWAKE_DW = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x15),
+ WL_NAN_CMD_CFG_WFA_TM = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x16),
+ WL_NAN_CMD_CFG_MAX = WL_NAN_CMD_CFG_WFA_TM, /* Add new commands before and update */
+
+ /* nan election sub-commands */
+ WL_NAN_CMD_ELECTION_HOST_ENABLE = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x01),
+ WL_NAN_CMD_ELECTION_METRICS_CONFIG = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x02),
+ WL_NAN_CMD_ELECTION_METRICS_STATE = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x03),
+ WL_NAN_CMD_ELECTION_JOIN = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x04),
+ WL_NAN_CMD_ELECTION_LEAVE = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x05),
+ WL_NAN_CMD_ELECTION_MERGE = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x06),
+ WL_NAN_CMD_ELECTION_STOP = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x07),
+ WL_NAN_CMD_ELECTION_MAX = WL_NAN_CMD_ELECTION_STOP, /* New commands go before and update */
+
+ /* nan SD sub-commands */
+ WL_NAN_CMD_SD_PARAMS = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x01),
+ WL_NAN_CMD_SD_PUBLISH = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x02),
+ WL_NAN_CMD_SD_PUBLISH_LIST = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x03),
+ WL_NAN_CMD_SD_CANCEL_PUBLISH = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x04),
+ WL_NAN_CMD_SD_SUBSCRIBE = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x05),
+ WL_NAN_CMD_SD_SUBSCRIBE_LIST = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x06),
+ WL_NAN_CMD_SD_CANCEL_SUBSCRIBE = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x07),
+ WL_NAN_CMD_SD_VND_INFO = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x08),
+ WL_NAN_CMD_SD_STATS = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x09),
+ WL_NAN_CMD_SD_TRANSMIT = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x0a),
+ WL_NAN_CMD_SD_FUP_TRANSMIT = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x0b),
+ WL_NAN_CMD_SD_CONNECTION = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x0c),
+ WL_NAN_CMD_SD_SHOW = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x0d),
+ WL_NAN_CMD_SD_MAX = WL_NAN_CMD_SD_SHOW, /* New commands go before and update */
+
+ /* nan time sync sub-commands */
+ WL_NAN_CMD_SYNC_TSRESERVE = NAN_CMD(WL_NAN_CMD_SYNC_COMP_ID, 0x01),
+ WL_NAN_CMD_SYNC_TSSCHEDULE = NAN_CMD(WL_NAN_CMD_SYNC_COMP_ID, 0x01),
+ WL_NAN_CMD_SYNC_TSRELEASE = NAN_CMD(WL_NAN_CMD_SYNC_COMP_ID, 0x01),
+ WL_NAN_CMD_SYNC_MAX = WL_NAN_CMD_SYNC_TSRELEASE, /* New ones before and update */
+
+ /* nan2 commands */
+ WL_NAN_CMD_DATA_CONFIG = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x01),
+ WL_NAN_CMD_DATA_AUTOCONN = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x02),
+ WL_NAN_CMD_DATA_RSVD03 = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x03),
+ WL_NAN_CMD_DATA_DATAREQ = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x04),
+ WL_NAN_CMD_DATA_DATARESP = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x05),
+ WL_NAN_CMD_DATA_DATAEND = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x06),
+ WL_NAN_CMD_DATA_SCHEDUPD = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x07),
+ WL_NAN_CMD_DATA_RSVD08 = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x08),
+ WL_NAN_CMD_DATA_CAP = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x9),
+ WL_NAN_CMD_DATA_STATUS = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0a),
+ WL_NAN_CMD_DATA_STATS = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0b),
+ WL_NAN_CMD_DATA_RSVD0C = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0c),
+ WL_NAN_CMD_DATA_NDP_SHOW = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0d),
+ WL_NAN_CMD_DATA_DATACONF = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0e),
+ WL_NAN_CMD_DATA_PATH_MAX = WL_NAN_CMD_DATA_DATACONF, /* New ones before and update */
+
+ /* nan dam sub-commands */
+ WL_NAN_CMD_DAM_CFG = NAN_CMD(WL_NAN_CMD_DAM_COMP_ID, 0x01),
+ WL_NAN_CMD_DAM_MAX = WL_NAN_CMD_DAM_CFG, /* New ones before and update */
+
+ /* nan2.0 ranging commands */
+ WL_NAN_CMD_RANGE_REQUEST = NAN_CMD(WL_NAN_CMD_RANGE_COMP_ID, 0x01),
+ WL_NAN_CMD_RANGE_AUTO = NAN_CMD(WL_NAN_CMD_RANGE_COMP_ID, 0x02),
+ WL_NAN_CMD_RANGE_RESPONSE = NAN_CMD(WL_NAN_CMD_RANGE_COMP_ID, 0x03),
+ WL_NAN_CMD_RANGE_CANCEL = NAN_CMD(WL_NAN_CMD_RANGE_COMP_ID, 0x04),
+
+ /* nan debug sub-commands */
+ WL_NAN_CMD_DBG_SCAN_PARAMS = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x01),
+ WL_NAN_CMD_DBG_SCAN = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x02),
+ WL_NAN_CMD_DBG_SCAN_RESULTS = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x03),
+ WL_NAN_CMD_DBG_EVENT_MASK = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x04),
+ WL_NAN_CMD_DBG_EVENT_CHECK = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x05),
+ WL_NAN_CMD_DBG_DUMP = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x06),
+ WL_NAN_CMD_DBG_CLEAR = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x07),
+ WL_NAN_CMD_DBG_RSSI = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x08),
+ WL_NAN_CMD_DBG_DEBUG = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x09),
+ WL_NAN_CMD_DBG_TEST1 = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0a),
+ WL_NAN_CMD_DBG_TEST2 = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0b),
+ WL_NAN_CMD_DBG_TEST3 = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0c),
+ WL_NAN_CMD_DBG_DISC_RESULTS = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0d),
+ WL_NAN_CMD_DBG_STATS = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0e),
+ WL_NAN_CMD_DBG_LEVEL = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0f),
+ WL_NAN_CMD_DBG_MAX = WL_NAN_CMD_DBG_LEVEL /* New ones before and update */
+};
+
+/** status - TBD BCME_ vs NAN status - range reserved for BCME_ */
+enum {
+ /* add new status here... */
+
+ WL_NAN_E_INVALID_STARTOFFSET = -2061,
+ WL_NAN_E_BAD_NA_ENTRY_TYPE = -2060,
+ WL_NAN_E_INVALID_CHANBMP = -2059,
+ WL_NAN_E_INVALID_OP_CLASS = -2058,
+ WL_NAN_E_NO_IES = -2057,
+ WL_NAN_E_NO_PEER_ENTRY_AVAIL = -2056,
+ WL_NAN_E_INVALID_PEER = -2055,
+ WL_NAN_E_PEER_EXISTS = -2054,
+ WL_NAN_E_PEER_NOTFOUND = -2053,
+ WL_NAN_E_NO_MEM = -2052,
+ WL_NAN_E_INVALID_OPTION = -2051,
+ WL_NAN_E_INVALID_BAND = -2050,
+ WL_NAN_E_INVALID_MAC = -2049,
+ WL_NAN_E_BAD_INSTANCE = -2048,
+ WL_NAN_E_NDC_EXISTS = -2047,
+ WL_NAN_E_NO_NDC_ENTRY_AVAIL = -2046,
+ WL_NAN_E_INVALID_NDC_ENTRY = -2045,
+ WL_NAN_E_ERROR = -1,
+ WL_NAN_E_OK = 0
+};
+
+typedef int32 wl_nan_status_t;
+
+/** nan cmd list entry */
+enum wl_nan_sub_cmd_input_flags {
+ WL_NAN_SUB_CMD_FLAG_NONE = 0,
+ WL_NAN_SUB_CMD_FLAG_SKIP = 1, /* Skip to next sub-command on error */
+ WL_NAN_SUB_CMD_FLAG_TERMINATE = 2, /* Terminate processing and return */
+ WL_NAN_SUB_CMD_FLAG_LAST /* Keep this at the end */
+};
+
+/** container for nan events */
+typedef struct wl_nan_ioc {
+ uint16 version; /**< interface command or event version */
+ uint16 id; /**< nan ioctl cmd ID */
+ uint16 len; /**< total length of all tlv records in data[] */
+ uint16 pad; /**< pad to be 32 bit aligment */
+ uint8 data [1]; /**< var len payload of bcm_xtlv_t type */
+} wl_nan_ioc_t;
+
+/*
+ * NAN sub-command data structures
+ */
+
+/*
+ * Config component WL_NAN_CMD_CFG_XXXX sub-commands
+ * WL_NAN_CMD_CFG_ENABLE
+ */
+enum wl_nan_config_state {
+ WL_NAN_CONFIG_STATE_DISABLE = 0,
+ WL_NAN_CONFIG_STATE_ENABLE = 1
+};
+
+typedef int8 wl_nan_config_state_t;
+
+/*
+ * WL_NAN_CMD_CFG_BAND, WL_NAN_CMD_CFG_RSSI_THRESHOLD(Get only)
+ */
+typedef uint8 wl_nan_band_t;
+
+/*
+ * WL_NAN_CMD_CFG_STATE
+ */
+enum wl_nan_role {
+ WL_NAN_ROLE_AUTO = 0,
+ WL_NAN_ROLE_NON_MASTER_NON_SYNC = 1,
+ WL_NAN_ROLE_NON_MASTER_SYNC = 2,
+ WL_NAN_ROLE_MASTER = 3,
+ WL_NAN_ROLE_ANCHOR_MASTER = 4
+};
+
+typedef uint8 wl_nan_role_t;
+
+typedef struct wl_nan_device_state
+{
+ wl_nan_role_t role; /* Sync Master, Non-Sync Master */
+ uint8 state; /* TBD */
+ uint8 hopcount; /* Hops to the Anchor Master */
+ struct ether_addr immediate_master; /* Master MAC */
+ struct ether_addr anchor_master; /* Anchor Master MAC */
+ struct ether_addr cluster_id; /* Cluster ID to which this device belongs to */
+ uint32 tsf_high; /* NAN Cluster TSFs */
+ uint32 tsf_low;
+} wl_nan_device_state_t;
+
+/*
+ * WL_NAN_CMD_CFG_HOP_CNT, WL_NAN_CMD_CFG_HOP_LIMIT
+ */
+typedef uint8 wl_nan_hop_count_t;
+
+/*
+ * WL_NAN_CMD_CFG_WARMUP_TIME
+ */
+typedef uint32 wl_nan_warmup_time_ticks_t;
+
+/*
+ * WL_NAN_CMD_CFG_RSSI_THRESHOLD
+ * rssi_close and rssi_mid are used to transition master to non-master
+ * role by NAN state machine. rssi thresholds corresponding to the band
+ * will be updated.
+ */
+typedef struct wl_nan_rssi_threshold {
+ wl_nan_band_t band;
+ int8 rssi_close;
+ int8 rssi_mid;
+ uint8 pad;
+} wl_nan_rssi_threshold_t;
+
+/*
+ * WL_NAN_CMD_CFG_STATUS
+ */
+typedef struct wl_nan_cfg_status {
+ uint8 enabled;
+ uint8 inited;
+ uint8 joined;
+ uint8 merged;
+ uint8 role;
+ uint32 chspec[2];
+ uint8 mr[8]; /**< Master Rank */
+ uint8 amr[8]; /**< Anchor Master Rank */
+ uint32 cnt_pend_txfrm; /**< pending TX frames */
+ uint32 cnt_bcn_tx; /**< TX disc/sync beacon count */
+ uint32 cnt_bcn_rx; /**< RX disc/sync beacon count */
+ uint32 cnt_svc_disc_tx; /**< TX svc disc frame count */
+ uint32 cnt_svc_disc_rx; /**< RX svc disc frame count */
+ uint32 ambtt; /**< Anchor master beacon target time */
+ struct ether_addr cid; /**< Cluster id */
+ uint8 hop_count; /**< Hop count */
+} wl_nan_cfg_status_t;
+
+/*
+ * WL_NAN_CMD_CFG_OUI
+ */
+typedef struct wl_nan_oui_type {
+ uint8 nan_oui[DOT11_OUI_LEN];
+ uint8 type;
+} wl_nan_oui_type_t;
+
+/*
+ * WL_NAN_CMD_CFG_COUNT
+ */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+typedef struct wl_nan_count {
+ uint32 cnt_bcn_tx; /**< TX disc/sync beacon count */
+ uint32 cnt_bcn_rx; /**< RX disc/sync beacon count */
+ uint32 cnt_svc_disc_tx; /**< TX svc disc frame count */
+ uint32 cnt_svc_disc_rx; /**< RX svc disc frame count */
+} wl_nan_count_t;
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/*
+ * Election component WL_NAN_CMD_ELECTION_XXXX sub-commands
+ * WL_NAN_CMD_ELECTION_HOST_ENABLE
+ */
+enum wl_nan_enable_flags {
+ WL_NAN_DISABLE_FLAG_HOST_ELECTION = 0,
+ WL_NAN_ENABLE_FLAG_HOST_ELECTION = 1
+};
+
+/*
+ * 0 - disable host based election
+ * 1 - enable host based election
+ */
+typedef uint8 wl_nan_host_enable_t;
+
+/*
+ * WL_NAN_CMD_ELECTION_METRICS_CONFIG
+ */
+/* Set only */
+typedef struct wl_nan_election_metric_config {
+ uint8 random_factor; /* Configured random factor */
+ uint8 master_pref; /* configured master preference */
+ uint8 pad[2];
+} wl_nan_election_metric_config_t;
+
+/*
+ * WL_NAN_CMD_ELECTION_METRICS_STATE
+ */
+/* Get only */
+typedef struct wl_nan_election_metric_state {
+ uint8 random_factor; /* random factor used in MIs */
+ uint8 master_pref; /* Master advertised in MIs */
+ uint8 pad[2];
+} wl_nan_election_metric_state_t;
+
+/*
+ * WL_NAN_CMD_ELECTION_LEAVE
+ * WL_NAN_CMD_ELECTION_STOP
+ */
+typedef struct ether_addr wl_nan_cluster_id_t;
+
+/*
+ * WL_NAN_CMD_ELECTION_JOIN
+ */
+typedef struct wl_nan_join {
+ uint8 start_cluster; /* Start a cluster */
+ uint8 pad[3];
+ wl_nan_cluster_id_t cluster_id; /* Cluster ID to join */
+} wl_nan_join_t;
+
+/*
+ * WL_NAN_CMD_ELECTION_MERGE
+ * 0 - disable cluster merge
+ * 1 - enable cluster merge
+ */
+typedef uint8 wl_nan_merge_enable_t;
+
+/*
+ * WL_NAN_CMD_CFG_STATE
+ * role = 0 means configuration by firmware; otherwise by host
+ * when host configures role, also need target master address to sync to
+ */
+typedef struct wl_nan_role_config {
+ wl_nan_role_t role;
+ struct ether_addr target_master;
+ uint8 pad;
+} wl_nan_role_config_t;
+
+/*
+ * Service Discovery component WL_NAN_CMD_SD_XXXX sub-commands
+ * WL_NAN_CMD_SD_PUBLISH
+ * WL_NAN_CMD_SD_SUBSCRIBE
+ */
+#define WL_NAN_SD_PUB_UNSOLICIT 0x0001 /* Unsolicited transmissions */
+#define WL_NAN_SD_PUB_SOLICIT 0x0002 /* Solicited transmissions */
+#define WL_NAN_SD_PUB_BCAST 0x0004 /* for solicited 1= broadcast, 0=unicast */
+#define WL_NAN_SD_PUB_EVENT 0x0008 /* Generate event on solicited transmission */
+enum wl_nan_sd_optional_field_types
+{
+ NAN_SD_FIELD_MATCH_FILTER_SERVICE_INFO = 1,
+ NAN_SD_FIELD_MATCH_FILTER_TX = 2,
+ NAN_SD_FIELD_MATCH_FILTER_RX = 3,
+ NAN_SD_FIELD_MATCH_FILTER_SRF = 4
+};
+
+typedef int8 wl_nan_sd_optional_field_types_t;
+
+/*
+ * WL_NAN_CMD_SD_PARAMS
+ */
+typedef struct wl_nan_sd_params
+{
+ uint16 length; /* length including options */
+ uint16 flags; /* bitmap representing aforesaid optional flags */
+ uint8 svc_hash[WL_NAN_SVC_HASH_LEN]; /* Hash for the service name */
+ uint8 instance_id; /* Instance of the current service */
+ int8 proximity_rssi; /* RSSI limit to Rx subscribe or pub SDF 0 no effect */
+ uint8 period; /* period of the unsolicited SDF xmission in DWs */
+ int32 ttl; /* TTL for this instance id, -1 will run till cancelled */
+ tlv_t optional[1]; /* optional fields in the SDF as appropriate */
+} wl_nan_sd_params_t;
+
+/*
+ * WL_NAN_CMD_SD_PUBLISH_LIST
+ * WL_NAN_CMD_SD_SUBSCRIBE_LIST
+ */
+typedef struct wl_nan_service_info
+{
+ uint8 instance_id; /* Publish instance ID */
+ uint8 service_hash[WL_NAN_SVC_HASH_LEN]; /* Hash for service name */
+} wl_nan_service_info_t;
+
+typedef struct wl_nan_service_list
+{
+ uint16 id_count; /* Number of registered publish/subscribe services */
+ wl_nan_service_info_t list[1]; /* service info defined by nan_service instance */
+} wl_nan_service_list_t;
+
+/*
+ * WL_NAN_CMD_CFG_BCN_INTERVAL
+ */
+typedef uint16 wl_nan_disc_bcn_interval_t;
+
+/*
+ * WL_NAN_CMD_CFG_SDF_TXTIME
+ */
+typedef uint16 wl_nan_svc_disc_txtime_t;
+
+/*
+ * WL_NAN_CMD_CFG_STOP_BCN_TX
+ */
+typedef uint16 wl_nan_stop_bcn_tx_t;
+
+/*
+ * WL_NAN_CMD_CFG_SID_BEACON
+ */
+typedef struct wl_nan_sid_beacon_control {
+ uint8 sid_enable; /* Flag to indicate the inclusion of Service IDs in Beacons */
+ uint8 sid_count; /* Limit for number of SIDs to be included in Beacons */
+ uint8 pad[2];
+} wl_nan_sid_beacon_control_t;
+
+/*
+ * WL_NAN_CMD_CFG_DW_LEN
+ */
+typedef uint16 wl_nan_dw_len_t;
+
+/*
+ * WL_NAN_CMD_CFG_AWAKE_DW
+ */
+typedef struct wl_nan_awake_dw {
+ wl_nan_band_t band; /* 0 - b mode 1- a mode */;
+ uint8 interval; /* 1 or 2 or 4 or 8 or 16 */
+ uint16 pad;
+} wl_nan_awake_dw_t;
+
+/*
+ * WL_NAN_CMD_SD_CANCEL_PUBLISH
+ * WL_NAN_CMD_SD_CANCEL_SUBSCRIBE
+ */
+typedef uint8 wl_nan_instance_id; /* Instance ID of an active publish instance */
+
+/*
+ * WL_NAN_CMD_SD_VND_INFO
+ */
+typedef struct wl_nan_sd_vendor_info
+{
+ uint16 length; /* Size in bytes of the payload following this field */
+ uint8 data[1]; /* Vendor Information */
+} wl_nan_sd_vendor_info_t;
+
+/*
+ * WL_NAN_CMD_SD_STATS
+ */
+typedef struct wl_nan_sd_stats {
+ uint32 sdftx;
+ uint32 sdfrx;
+ uint32 sdsrffail;
+ uint32 sdrejrssi;
+ uint32 sdfollowuprx;
+ uint32 sdsubmatch;
+ uint32 sdpubreplied;
+ uint32 sdmftfail1;
+ uint32 sdmftfail2;
+ uint32 sdmftfail3;
+ uint32 sdmftfail4;
+} wl_nan_sd_stats_t;
+
+/*
+ * WL_NAN_CMD_SD_TRANSMIT
+ * WL_NAN_CMD_SD_FUP_TRANSMIT
+ */
+typedef struct wl_nan_sd_transmit {
+ uint8 local_service_id; /* Sender Service ID */
+ uint8 requestor_service_id; /* Destination Service ID */
+ struct ether_addr destination_addr; /* Destination MAC */
+ uint16 token; /* follow_up_token when a follow-up msg is queued successfully */
+ uint8 priority; /* requested relative prio */
+ uint8 service_info_len; /* size in bytes of the service info payload */
+ wl_nan_service_info_t service_info[1]; /* Service Info payload */
+} wl_nan_sd_transmit_t;
+
+/*
+ * WL_NAN_CMD_SYNC_TSRESERVE
+ */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/** time slot */
+#define NAN_MAX_TIMESLOT 32
+typedef struct wl_nan_timeslot {
+ uint32 abitmap; /**< available bitmap */
+ uint32 chanlist[NAN_MAX_TIMESLOT];
+} wl_nan_timeslot_t;
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/*
+ * WL_NAN_CMD_SYNC_TSRELEASE
+ */
+typedef uint32 wl_nan_ts_bitmap_t;
+
+/* nan passive scan params */
+#define NAN_SCAN_MAX_CHCNT 8
+typedef struct wl_nan_scan_params {
+ uint16 scan_time;
+ uint16 home_time;
+ uint16 ms_intvl; /**< interval between merge scan */
+ uint16 ms_dur; /**< duration of merge scan */
+ uint16 chspec_num;
+ uint8 pad[2];
+ chanspec_t chspec_list[NAN_SCAN_MAX_CHCNT]; /**< act. used 3, 5 rfu */
+} wl_nan_scan_params_t;
+
+/*
+ * WL_NAN_CMD_DBG_SCAN
+ */
+typedef struct wl_nan_dbg_scan {
+ struct ether_addr cid;
+ uint8 pad[2];
+} wl_nan_dbg_scan_t;
+
+/* NAN_DBG_LEVEL */
+typedef struct wl_nan_dbg_level {
+ uint32 nan_err_level; /* for Error levels */
+ uint32 nan_dbg_level; /* for bebug logs and trace */
+ uint32 nan_info_level; /* for dumps like prhex */
+} wl_nan_dbg_level_t;
+
+/*
+ * WL_NAN_CMD_DBG_EVENT_MASK
+ */
+typedef uint32 wl_nan_event_mask_t;
+
+/*
+ * WL_NAN_CMD_DBG_EVENT_CHECK
+ */
+typedef uint8 wl_nan_dbg_ifname[BCM_MSG_IFNAME_MAX];
+
+/*
+ * WL_NAN_CMD_DBG_DUMP
+ * WL_NAN_CMD_DBG_CLEAR
+ */
+enum wl_nan_dbg_dump_type {
+ WL_NAN_DBG_DT_RSSI_DATA = 1,
+ WL_NAN_DBG_DT_STATS_DATA = 2,
+ /*
+ * Additional enums before this line
+ */
+ WL_NAN_DBG_DT_INVALID
+};
+typedef int8 wl_nan_dbg_dump_type_t;
+
+/** various params and ctl swithce for nan_debug instance */
+/*
+ * WL_NAN_CMD_DBG_DEBUG
+ */
+typedef struct wl_nan_debug_params {
+ uint16 cmd; /**< debug cmd to perform a debug action */
+ uint16 status;
+ uint32 msglevel; /**< msg level if enabled */
+ uint8 enabled; /**< runtime debuging enabled */
+ uint8 collect;
+} wl_nan_debug_params_t;
+
+
+typedef struct wl_nan_sched_svc_timeslot_s {
+ uint32 abitmap; /* availability bitmap */
+ uint32 chanlist[NAN_MAX_TIMESLOT];
+ uint8 res; /* resolution: 0 = 16ms, 1 = 32ms, 2 = 64ms 3 = reserved. REfer NAN spec */
+ uint8 mapid; /* mapid from NAN spec. Used to differentiate 2G Vs 5G band */
+} wl_nan_sched_svc_timeslot_t;
+
+
+/* nan passive scan params */
+#define NAN_SCAN_MAX_CHCNT 8
+typedef struct nan_scan_params {
+ uint16 scan_time;
+ uint16 home_time;
+ uint16 ms_intvl; /**< interval between merge scan */
+ uint16 ms_dur; /**< duration of merge scan */
+ uint16 chspec_num;
+ uint8 pad[2];
+ chanspec_t chspec_list[NAN_SCAN_MAX_CHCNT]; /**< act. used 3, 5 rfu */
+} nan_scan_params_t;
+
+#define NAN_MASTER_RANK_LEN 8
+/* nan cmd IDs */
+enum wl_nan_cmds {
+ /* nan cfg /disc & dbg ioctls */
+ WL_NAN_CMD_ENABLE = 1,
+ WL_NAN_CMD_ATTR = 2,
+ WL_NAN_CMD_NAN_JOIN = 3,
+ WL_NAN_CMD_LEAVE = 4,
+ WL_NAN_CMD_MERGE = 5,
+ WL_NAN_CMD_STATUS = 6,
+ WL_NAN_CMD_TSRESERVE = 7,
+ WL_NAN_CMD_TSSCHEDULE = 8,
+ WL_NAN_CMD_TSRELEASE = 9,
+ WL_NAN_CMD_OUI = 10,
+ WL_NAN_CMD_OOB_AF = 11,
+
+ WL_NAN_CMD_COUNT = 15,
+ WL_NAN_CMD_CLEARCOUNT = 16,
+
+ /* discovery engine commands */
+ WL_NAN_CMD_PUBLISH = 20,
+ WL_NAN_CMD_SUBSCRIBE = 21,
+ WL_NAN_CMD_CANCEL_PUBLISH = 22,
+ WL_NAN_CMD_CANCEL_SUBSCRIBE = 23,
+ WL_NAN_CMD_TRANSMIT = 24,
+ WL_NAN_CMD_CONNECTION = 25,
+ WL_NAN_CMD_SHOW = 26,
+ WL_NAN_CMD_STOP = 27, /* stop nan for a given cluster ID */
+ /* nan debug iovars & cmds */
+ WL_NAN_CMD_SCAN_PARAMS = 46,
+ WL_NAN_CMD_SCAN = 47,
+ WL_NAN_CMD_SCAN_RESULTS = 48,
+ WL_NAN_CMD_EVENT_MASK = 49,
+ WL_NAN_CMD_EVENT_CHECK = 50,
+ WL_NAN_CMD_DUMP = 51,
+ WL_NAN_CMD_CLEAR = 52,
+ WL_NAN_CMD_RSSI = 53,
+
+ WL_NAN_CMD_DEBUG = 60,
+ WL_NAN_CMD_TEST1 = 61,
+ WL_NAN_CMD_TEST2 = 62,
+ WL_NAN_CMD_TEST3 = 63,
+ WL_NAN_CMD_DISC_RESULTS = 64,
+ /* nan 2.0 data path commands */
+ WL_NAN_CMD_DATAPATH = 65
+};
+
+/* NAN DP interface commands */
+enum wl_nan_dp_cmds {
+ /* nan 2.0 ioctls */
+ WL_NAN_CMD_DP_CAP = 1000,
+ WL_NAN_CMD_DP_CONFIG = 1001,
+ WL_NAN_CMD_DP_CREATE = 1002,
+ WL_NAN_CMD_DP_AUTO_CONNECT = 1003,
+ WL_NAN_CMD_DP_DATA_REQ = 1004,
+ WL_NAN_CMD_DP_DATA_RESP = 1005,
+ WL_NAN_CMD_DP_SCHED_UPD = 1006,
+ WL_NAN_CMD_DP_END = 1007,
+ WL_NAN_CMD_DP_CONNECT = 1008,
+ WL_NAN_CMD_DP_STATUS = 1009
+};
+
+/* TODO Should remove this fixed length */
+#define WL_NAN_DATA_SVC_SPEC_INFO_LEN 32 /* arbitrary */
+#define WL_NAN_DP_MAX_SVC_INFO 0xFF
+#define WL_NAN_DATA_NDP_INST_SUPPORT 16
+
+/* Nan flags */
+#define WL_NAN_DP_FLAG_SVC_INFO (1 << 0)
+#define WL_NAN_DP_FLAG_CONFIRM (1 << 1)
+#define WL_NAN_DP_FLAG_EXPLICIT_CFM (1 << 2)
+
+/* to be done */
+typedef struct wl_nan_dp_cap {
+ uint8 tbd;
+} wl_nan_dp_cap_t;
+
+/** Flag bits for Publish and Subscribe (wl_nan_disc_params_t flags) */
+#define WL_NAN_RANGE_LIMITED 0x0040
+/** Event generation indicator (default is continuous) */
+#define WL_NAN_MATCH_ONCE 0x100000
+#define WL_NAN_MATCH_NEVER 0x200000
+/* Bits specific to Publish */
+/** Unsolicited transmissions */
+#define WL_NAN_PUB_UNSOLICIT 0x1000
+/** Solicited transmissions */
+#define WL_NAN_PUB_SOLICIT 0x2000
+#define WL_NAN_PUB_BOTH 0x3000
+/** Set for broadcast solicited transmission. Do not set for unicast solicited transmission */
+#define WL_NAN_PUB_BCAST 0x4000
+/** Generate event on each solicited transmission */
+#define WL_NAN_PUB_EVENT 0x8000
+/** Used for one-time solicited Publish functions to indicate transmision occurred */
+#define WL_NAN_PUB_SOLICIT_PENDING 0x10000
+/** Follow-up frames */
+#define WL_NAN_FOLLOWUP 0x20000
+/** Bits specific to Subscribe */
+/** Active subscribe mode (Leave unset for passive) */
+#define WL_NAN_SUB_ACTIVE 0x1000
+/** Service info in publish required for Match event */
+#define WL_NAN_SUB_MATCH_IF_SVC_INFO 0x2000
+
+/** Special values for time to live (ttl) parameter */
+#define WL_NAN_TTL_UNTIL_CANCEL 0xFFFFFFFF
+/* Publish - runs until first transmission
+ * Subscribe - runs until first DiscoveryResult event
+ */
+#define WL_NAN_TTL_FIRST 0
+
+/** The service hash (service id) is exactly this many bytes. */
+#define WL_NAN_SVC_HASH_LEN 6
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/** Number of hash functions per bloom filter */
+#define WL_NAN_HASHES_PER_BLOOM 4
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/* no. of max last disc results */
+#define WL_NAN_MAX_DISC_RESULTS 3
+
+/** Mandatory parameters for publish/subscribe iovars - NAN_TLV_SVC_PARAMS */
+typedef struct wl_nan_disc_params_s {
+ /** Periodicity of unsolicited/query transmissions, in DWs */
+ uint32 period;
+ /** Time to live in DWs */
+ uint32 ttl;
+ /** Flag bits */
+ uint32 flags;
+ /** Publish or subscribe service id, i.e. hash of the service name */
+ uint8 svc_hash[WL_NAN_SVC_HASH_LEN];
+ /** pad to make 4 byte alignment, can be used for something else in the future */
+ uint8 pad;
+ /** Publish or subscribe id */
+ wl_nan_instance_id_t instance_id;
+} wl_nan_disc_params_t;
+
+/* recent discovery results */
+typedef struct wl_nan_disc_result_s
+{
+ wl_nan_instance_id_t instance_id; /* instance id of pub/sub req */
+ wl_nan_instance_id_t peer_instance_id; /* peer instance id of pub/sub req/resp */
+ uint8 svc_hash[WL_NAN_SVC_HASH_LEN]; /* service descp string */
+ struct ether_addr peer_mac; /* peer mac address */
+} wl_nan_disc_result_t;
+
+/* list of recent discovery results */
+typedef struct wl_nan_disc_results_s
+{
+ wl_nan_disc_result_t disc_result[WL_NAN_MAX_DISC_RESULTS];
+} wl_nan_disc_results_list_t;
+
+/* nan 1.0 events */
+typedef struct wl_nan_ev_disc_result {
+ wl_nan_instance_id_t pub_id;
+ wl_nan_instance_id_t sub_id;
+ struct ether_addr pub_mac;
+ uint8 opt_tlvs[0];
+} wl_nan_ev_disc_result_t;
+
+typedef struct wl_nan_ev_p2p_avail {
+ struct ether_addr sender;
+ struct ether_addr p2p_dev_addr;
+ uint8 dev_role;
+ uint8 resolution;
+ uint8 repeat;
+ uint8 pad[3];
+ chanspec_t chanspec;
+ uint32 avail_bmap;
+} wl_nan_ev_p2p_avail_t;
+
+/*
+* discovery interface event structures *
+*/
+
+/* mandatory parameters for OOB action frame */
+/* single-shot when bitmap and offset are set to 0; periodic otherwise */
+typedef struct wl_nan_oob_af_params_s
+{
+ /* bitmap for the 32 timeslots in 512TU dw interval */
+ uint32 ts_map;
+ /* offset from start of dw, in us */
+ uint32 tx_offset;
+ struct ether_addr bssid;
+ struct ether_addr dest;
+ uint32 pkt_lifetime;
+ uint16 payload_len;
+ uint8 payload[1];
+} wl_nan_oob_af_params_t;
+
+/* NAN Ranging */
+
+/* Bit defines for global flags */
+#define WL_NAN_RANGING_ENABLE 1 /**< enable RTT */
+#define WL_NAN_RANGING_RANGED 2 /**< Report to host if ranged as target */
+typedef struct nan_ranging_config {
+ uint32 chanspec; /**< Ranging chanspec */
+ uint16 timeslot; /**< NAN RTT start time slot 1-511 */
+ uint16 duration; /**< NAN RTT duration in ms */
+ struct ether_addr allow_mac; /**< peer initiated ranging: the allowed peer mac
+ * address, a unicast (for one peer) or
+ * a broadcast for all. Setting it to all zeros
+ * means responding to none,same as not setting
+ * the flag bit NAN_RANGING_RESPOND
+ */
+ uint16 flags;
+} wl_nan_ranging_config_t;
+
+/** list of peers for self initiated ranging */
+/** Bit defines for per peer flags */
+#define WL_NAN_RANGING_REPORT (1<<0) /**< Enable reporting range to target */
+typedef struct nan_ranging_peer {
+ uint32 chanspec; /**< desired chanspec for this peer */
+ uint32 abitmap; /**< available bitmap */
+ struct ether_addr ea; /**< peer MAC address */
+ uint8 frmcnt; /**< frame count */
+ uint8 retrycnt; /**< retry count */
+ uint16 flags; /**< per peer flags, report or not */
+} wl_nan_ranging_peer_t;
+typedef struct nan_ranging_list {
+ uint8 count; /**< number of MAC addresses */
+ uint8 num_peers_done; /**< host set to 0, when read, shows number of peers
+ * completed, success or fail
+ */
+ uint8 num_dws; /**< time period to do the ranging, specified in dws */
+ uint8 reserve; /**< reserved field */
+ wl_nan_ranging_peer_t rp[1]; /**< variable length array of peers */
+} wl_nan_ranging_list_t;
+
+/* ranging results, a list for self initiated ranging and one for peer initiated ranging */
+/* There will be one structure for each peer */
+#define WL_NAN_RANGING_STATUS_SUCCESS 1
+#define WL_NAN_RANGING_STATUS_FAIL 2
+#define WL_NAN_RANGING_STATUS_TIMEOUT 3
+#define WL_NAN_RANGING_STATUS_ABORT 4 /**< with partial results if sounding count > 0 */
+typedef struct nan_ranging_result {
+ uint8 status; /**< 1: Success, 2: Fail 3: Timeout 4: Aborted */
+ uint8 sounding_count; /**< number of measurements completed (0 = failure) */
+ struct ether_addr ea; /**< initiator MAC address */
+ uint32 chanspec; /**< Chanspec where the ranging was done */
+ uint32 timestamp; /**< 32bits of the TSF timestamp ranging was completed at */
+ uint32 distance; /**< mean distance in meters expressed as Q4 number.
+ * Only valid when sounding_count > 0. Examples:
+ * 0x08 = 0.5m
+ * 0x10 = 1m
+ * 0x18 = 1.5m
+ * set to 0xffffffff to indicate invalid number
+ */
+ int32 rtt_var; /**< standard deviation in 10th of ns of RTTs measured.
+ * Only valid when sounding_count > 0
+ */
+ struct ether_addr tgtea; /**< target MAC address */
+} wl_nan_ranging_result_t;
+typedef struct nan_ranging_event_data {
+ uint8 mode; /**< 1: Result of host initiated ranging */
+ /* 2: Result of peer initiated ranging */
+ uint8 reserved;
+ uint8 success_count; /**< number of peers completed successfully */
+ uint8 count; /**< number of peers in the list */
+ wl_nan_ranging_result_t rr[1]; /**< variable array of ranging peers */
+} wl_nan_ranging_event_data_t;
+
+enum {
+ WL_NAN_STATS_RSSI = 1,
+ WL_NAN_STATS_DATA = 2,
+ WL_NAN_STATS_DP = 3,
+/*
+ * ***** ADD before this line ****
+ */
+ WL_NAN_STATS_INVALID
+};
+typedef struct wl_nan_dp_stats {
+ uint32 tbd; /* TBD */
+} wl_nan_dp_stats_t;
+
+typedef struct wl_nan_stats {
+ /* general */
+ uint32 cnt_dw; /* DW slots */
+ uint32 cnt_disc_bcn_sch; /* disc beacon slots */
+ uint32 cnt_amr_exp; /* count of ambtt expiries resetting roles */
+ uint32 cnt_bcn_upd; /* count of beacon template updates */
+ uint32 cnt_bcn_tx; /* count of sync & disc bcn tx */
+ uint32 cnt_bcn_rx; /* count of sync & disc bcn rx */
+ uint32 cnt_sync_bcn_tx; /* count of sync bcn tx within DW */
+ uint32 cnt_disc_bcn_tx; /* count of disc bcn tx */
+ uint32 cnt_sdftx_bcmc; /* count of bcast/mcast sdf tx */
+ uint32 cnt_sdftx_uc; /* count of unicast sdf tx */
+ uint32 cnt_sdftx_fail; /* count of unicast sdf tx fails */
+ uint32 cnt_sdf_rx; /* count of sdf rx */
+ /* NAN roles */
+ uint32 cnt_am; /* anchor master */
+ uint32 cnt_master; /* master */
+ uint32 cnt_nms; /* non master sync */
+ uint32 cnt_nmns; /* non master non sync */
+ /* TX */
+ uint32 cnt_err_txtime; /* txtime in sync bcn frame not a multiple of dw intv */
+ uint32 cnt_err_unsch_tx; /* tx while not in DW/ disc bcn slot */
+ uint32 cnt_err_bcn_tx; /* beacon tx error */
+ uint32 cnt_sync_bcn_tx_miss; /* no. of times time delta between 2 cosequetive
+ * sync beacons is more than expected
+ */
+ /* MSCH */
+ uint32 cnt_err_msch_reg; /* error is Dw/disc reg with msch */
+ uint32 cnt_err_wrong_ch_cb; /* count of msch calbacks in wrong channel */
+ uint32 cnt_dw_skip; /* count of DW rejected */
+ uint32 cnt_disc_skip; /* count of disc bcn rejected */
+ uint32 cnt_dw_start_early; /* msch cb not at registered time */
+ uint32 cnt_dw_start_late; /* no. of delays in slot start */
+ /* SCANS */
+ uint32 cnt_mrg_scan; /* count of merge scans completed */
+ uint32 cnt_err_ms_rej; /* number of merge scan failed */
+ uint32 cnt_scan_results; /* no. of nan beacons scanned */
+ uint32 cnt_join_scan_rej; /* no. of join scans rejected */
+ uint32 cnt_nan_scan_abort; /* no. of join scans rejected */
+ /* enable/disable */
+ uint32 cnt_nan_enab; /* no. of times nan feature got enabled */
+ uint32 cnt_nan_disab; /* no. of times nan feature got disabled */
+ uint32 cnt_sync_bcn_rx; /* count of sync bcn rx within DW */
+} wl_nan_stats_t;
+
+#define WL_NAN_MAC_MAX_NAN_PEERS 6
+#define WL_NAN_MAC_MAX_RSSI_DATA_PER_PEER 10
+
+typedef struct wl_nan_nbr_rssi {
+ uint8 rx_chan; /* channel number on which bcn rcvd */
+ int32 rssi_raw; /* received rssi value */
+ int32 rssi_avg; /* normalized rssi value */
+} wl_nan_peer_rssi_t;
+
+typedef struct wl_nan_peer_rssi_entry {
+ struct ether_addr mac; /* peer mac address */
+ uint8 flags; /* TODO:rssi data order: latest first, oldest first etc */
+ uint8 rssi_cnt; /* rssi data sample present */
+ wl_nan_peer_rssi_t rssi[WL_NAN_MAC_MAX_RSSI_DATA_PER_PEER]; /* RSSI data frm peer */
+} wl_nan_peer_rssi_entry_t;
+
+#define WL_NAN_PEER_RSSI 0x1
+#define WL_NAN_PEER_RSSI_LIST 0x2
+
+typedef struct wl_nan_nbr_rssi_data {
+ uint8 flags; /* this is a list or single rssi data */
+ uint8 peer_cnt; /* number of peers */
+ uint16 pad; /* padding */
+ wl_nan_peer_rssi_entry_t peers[1]; /* peers data list */
+} wl_nan_peer_rssi_data_t;
+
+/* WL_NAN_CMD_DBG_DUMP, GET Resp */
+typedef struct wl_nan_dbg_dump_rsp {
+ wl_nan_dbg_dump_type_t dump_type; /* dump data type */
+ uint8 pad[3];
+ union {
+ wl_nan_peer_rssi_data_t peer_rssi;
+ wl_nan_stats_t nan_stats;
+ } u;
+} wl_nan_dbg_dump_rsp_t;
+
+enum nan_termination_status {
+ NAN_TERM_REASON_INVALID = 1,
+ NAN_TERM_REASON_TIMEOUT = 2,
+ NAN_TERM_REASON_USER_REQ = 3,
+ NAN_TERM_REASON_FAILURE = 4,
+ NAN_TERM_REASON_COUNT_REACHED = 5,
+ NAN_TERM_REASON_DE_SHUTDOWN = 6,
+ NAN_TERM_REASON_DISABLE_IN_PROGRESS = 7
+};
+
+/* nan2 data iovar */
+/* nan2 qos */
+typedef struct wl_nan_dp_qos
+{
+ uint8 tid;
+ uint8 pad;
+ uint16 pkt_size;
+ uint16 mean_rate;
+ uint16 svc_interval;
+} wl_nan_dp_qos_t;
+/* ndp config */
+typedef struct wl_nan_ndp_config
+{
+ uint8 ndp_id;
+ uint8 pub_id;
+ struct ether_addr pub_addr;
+ struct ether_addr data_addr; /* configure local data addr */
+ struct ether_addr init_data_addr; /* initiator data addr */
+ uint8 svc_spec_info[WL_NAN_DATA_SVC_SPEC_INFO_LEN];
+ wl_nan_dp_qos_t qos;
+ uint16 avail_len;
+ uint8 pad[3];
+ uint8 data[1];
+} wl_nan_ndp_config_t;
+
+/* nan2 device capabilities */
+typedef struct wl_nan_ndp_oper_cfg {
+ uint8 awake_dw_2g;
+ uint8 awake_dw_5g;
+ uint8 bands_supported;
+ uint8 op_mode;
+} wl_nan_ndp_oper_cfg_t;
+
+typedef uint8 wl_nan_ndp_ndpid_t;
+typedef uint8 wl_nan_ndp_conn_t;
+
+#define WL_NAN_AUTO_DPRESP 1
+#define WL_NAN_AUTO_DPCONF 2
+
+typedef uint8 wl_nan_dp_autoconn_t;
+typedef uint8 wl_nan_dp_schedupd_t;
+
+typedef struct wl_nan_dp_req {
+ uint8 type; /* 0- unicast 1 - multicast */
+ uint8 pub_id; /* Publisher ID */
+ uint8 security; /* 0- open security 1-CSID 2-MKID */
+ uint8 flag;
+ struct ether_addr peer_mac; /* Peer's NMI addr */
+ struct ether_addr mcast_mac; /* Multicast addr */
+ wl_nan_dp_qos_t qos;
+ uint8 svc_spec_info[];
+} wl_nan_dp_req_t;
+
+/* TODO Need to replace ndp_id with lndp_id */
+/* Return structure to data req IOVAR */
+typedef struct wl_nan_dp_req_ret {
+ struct ether_addr indi; /* Initiators data mac addr */
+ uint8 ndp_id; /* Initiators ndpid */
+ uint8 pad;
+} wl_nan_dp_req_ret_t;
+
+typedef struct wl_nan_dp_resp {
+ uint8 type; /* 0- unicast 1 - multicast */
+ uint8 status; /* Accepted or Rejected */
+ uint8 reason_code;
+ /* Local NDP ID for unicast, mc_id for multicast, 0 for implicit NMSG */
+ uint8 ndp_id;
+ wl_nan_dp_qos_t qos;
+ /* Initiator data address for unicast or multicast address for multicast */
+ struct ether_addr mac_addr;
+ uint8 security; /* 0- open security 1-CSID 2-MKID */
+ uint8 flag;
+ uint8 svc_spec_info[]; /* NDP service specific info */
+} wl_nan_dp_resp_t;
+
+/* Return structure to data resp IOVAR */
+typedef struct wl_nan_dp_resp_ret {
+ uint8 nmsgid; /* NMSG ID or for multicast else 0 */
+ uint8 pad[3];
+} wl_nan_dp_resp_ret_t;
+
+typedef struct wl_nan_dp_conf {
+ uint8 lndp_id;
+ uint8 status; /* Accepted or Rejected */
+ uint8 pad[2];
+} wl_nan_dp_conf_t;
+
+typedef struct wl_nan_dp_end
+{
+ uint8 lndp_id;
+ uint8 status;
+ uint8 pad[2];
+} wl_nan_dp_end_t;
+
+/* list ndp ids */
+typedef struct wl_nan_ndp_id_list {
+ uint16 ndp_count;
+ uint8 lndp_id[];
+} wl_nan_ndp_id_list_t;
+
+/* nan2 status */
+typedef struct ndp_session {
+ uint8 lndp_id;
+ uint8 state;
+ uint8 pub_id;
+ uint8 pad;
+} ndp_session_t;
+
+typedef struct wl_nan_ndp_status {
+ struct ether_addr peer_nmi;
+ struct ether_addr peer_ndi;
+ ndp_session_t session;
+ uint8 pad;
+} wl_nan_ndp_status_t;
+
+/* events */
+#define NAN_DP_SESSION_UNICAST 0
+#define NAN_DP_SESSION_MULTICAST 1
+#define NAN_DP_SECURITY_NONE 0
+#define NAN_DP_SECURITY_CSID 1
+#define NAN_DP_SECURITY_MK 2
+
+/* Following datastructure will be removed once source code is committed */
+typedef struct wl_nan_ev_data_conf {
+ uint8 ndp_id;
+ uint8 status;
+ struct ether_addr peer_data_addr;
+ struct ether_addr local_data_addr;
+ uint8 svc_spec_info[WL_NAN_DATA_SVC_SPEC_INFO_LEN];
+ uint8 pad[2];
+} wl_nan_ev_data_conf_t;
+
+/* Following datastructure will be removed once source code is committed */
+typedef struct wl_nan_ev_data_ind {
+ uint8 ndp_id;
+ uint8 pub_id;
+ struct ether_addr peer_data_addr;
+ struct ether_addr local_data_addr;
+ uint8 svc_spec_info[WL_NAN_DATA_SVC_SPEC_INFO_LEN];
+ uint8 pad[2];
+} wl_nan_ev_data_ind_t;
+
+/* Following datastructure will be removed once source code is committed */
+typedef struct wl_nan_ev_data_conf_new {
+ /* Following three fields are valid only if type is unicast */
+ struct ether_addr initiator_ndi;
+ struct ether_addr responder_ndi;
+ uint8 ndp_id;
+ /* Following two fields are valid only if type is multicast */
+ uint8 mc_id;
+ uint8 nmsg_id;
+ uint8 type;
+ uint8 status;
+ uint8 pad[3];
+ uint8 svc_spec_info[];
+} wl_nan_ev_data_conf_new_t;
+
+/* Following datastructure will be removed once source code is committed */
+typedef struct wl_nan_ev_data_ind_new {
+ uint8 type;
+ uint8 ndp_id;
+ uint8 pub_id;
+ uint8 security;
+ struct ether_addr initiator_ndi;
+ struct ether_addr responder_ndi;
+ uint8 svc_spec_info[];
+} wl_nan_ev_data_ind_new_t;
+
+/* Following datastructure will be removed once source code is committed */
+typedef struct wl_nan_ev_data_end {
+ uint8 ndp_id;
+ uint8 status;
+ uint8 pad[2];
+} wl_nan_ev_data_end_t;
+
+#define WL_NAN_DATA_NMSGID_LEN 8 /* 8 bytes as per nan spec */
+
+typedef struct wl_nan_ev_datapath_cmn {
+ uint8 type;
+ /* ndp_id is valid only if type is unicast */
+ uint8 ndp_id;
+ uint8 pub_id;
+ uint8 security;
+ /* Following two fields are valid only if type is unicast */
+ struct ether_addr initiator_ndi;
+ struct ether_addr responder_ndi;
+ /* Following two fields are valid only if type is multicast */
+ uint8 nmsg_id[WL_NAN_DATA_NMSGID_LEN];
+ uint8 mc_id;
+ uint8 status;
+ uint8 pad[2];
+ uint8 opt_tlvs[];
+} wl_nan_ev_datapath_cmn_t;
+
+typedef struct wl_nan_ev_datapath_end {
+ uint8 ndp_id;
+ uint8 status;
+ uint8 pad[2];
+} wl_nan_ev_datapath_end_t;
+
+/* NAN2.0 Ranging definitions */
+
+/* result indication bit map */
+#define NAN_RANGE_INDICATION_CONT (1<<0)
+#define NAN_RANGE_INDICATION_INGRESS (1<<1)
+#define NAN_RANGE_INIDICATION_EGRESS (1<<2)
+
+/* responder flags */
+#define NAN_RANGE_FLAG_AUTO_ACCEPT (1 << 0)
+#define NAN_RANGE_FLAG_RESULT_REQUIRED (1 << 1)
+
+typedef struct wl_nan_range_req {
+ struct ether_addr peer;
+ uint8 publisher_id;
+ uint8 indication; /* bit map for result event */
+ uint32 resolution; /* default millimeters */
+ uint32 ingress; /* ingress limit in mm */
+ uint32 egress; /* egress limit in mm */
+ uint32 interval; /* max interval(in TU) b/w two ranging measurements */
+} wl_nan_range_req_t;
+
+#define NAN_RNG_REQ_IOV_LEN 24
+
+typedef uint8 wl_nan_range_id;
+
+typedef struct wl_nan_range_resp {
+ wl_nan_range_id range_id;
+ uint8 flags; /* auto response, range result required */
+ uint8 status; /* accept, reject */
+ uint8 indication; /* bit map for result event */
+ uint32 resolution; /* default millimeters */
+ uint32 ingress; /* ingress limit in mm */
+ uint32 egress; /* egress limit in mm */
+ uint32 interval; /* max interval(in TU) b/w two ranging measurements */
+} wl_nan_range_resp_t;
+
+#define NAN_RNG_RESP_IOV_LEN 20
+
+#define NAN_RNG_MAX_IOV_LEN 255
+
+typedef struct wl_nan_ev_rng_req_ind {
+ struct ether_addr peer_m_addr;
+ uint8 rng_id;
+ /* ftm parameters */
+ uint8 max_burst_dur;
+ uint8 min_ftm_delta;
+ uint8 max_num_ftm;
+ uint8 ftm_format_bw;
+ /* location info availability bit map */
+ uint8 lc_info_avail;
+ /* Last movement indication */
+ uint16 last_movement;
+ uint8 pad[2];
+} wl_nan_ev_rng_req_ind_t;
+
+#define NAN_RNG_REQ_IND_SIZE 14
+
+typedef struct wl_nan_ev_rng_rpt_ind {
+ uint32 dist_mm; /* in millimeter */
+ struct ether_addr peer_m_addr;
+ uint8 indication; /* indication definitions mentioned above */
+ uint8 pad;
+} wl_nan_ev_rng_rpt_ind_t;
+
+#define NAN_RNG_RPT_IND_SIZE 11
+
+typedef struct wl_nan_ev_rng_term_ind {
+ struct ether_addr peer_m_addr;
+ uint8 reason_code;
+ uint8 pad;
+} wl_nan_ev_rng_term_ind_t;
+
+#define NAN_RNG_TERM_IND_SIZE 7
+
+/* ********************* end of NAN section ******************************** */
+#endif /* WL_NAN */
+
+#define P2P_NAN_IOC_BUFSZ 512 /* some sufficient ioc buff size */
+#define WL_P2P_NAN_IOCTL_VERSION 0x1
+
+/* container for p2p nan iovtls & events */
+typedef struct wl_p2p_nan_ioc {
+ uint16 version; /* interface command or event version */
+ uint16 id; /* p2p nan ioctl cmd ID */
+ uint16 len; /* total length of data[] */
+ uint16 pad; /* padding */
+ uint8 data [1]; /* var len payload of bcm_xtlv_t type */
+} wl_p2p_nan_ioc_t;
+
+/* p2p nan cmd IDs */
+enum wl_p2p_nan_cmds {
+ /* p2p nan cfg ioctls */
+ WL_P2P_NAN_CMD_ENABLE = 1,
+ WL_P2P_NAN_CMD_CONFIG = 2,
+ WL_P2P_NAN_CMD_DEL_CONFIG = 3,
+ WL_P2P_NAN_CMD_GET_INSTS = 4
+};
+
+#define WL_P2P_NAN_CONFIG_VERSION 1
+
+#define WL_P2P_NAN_DEVICE_P2P 0x0
+#define WL_P2P_NAN_DEVICE_GO 0x1
+#define WL_P2P_NAN_DEVICE_GC 0x2
+#define WL_P2P_NAN_DEVICE_INVAL 0xFF
+
+/* NAN P2P operation */
+typedef struct p2p_nan_config {
+ uint16 version; /* wl_p2p_nan_config_t structure version */
+ uint16 len; /* total length including version and variable IE */
+ uint32 flags; /* 0x1 to NEW, 0x2 to ADD, 0x4 to DEL */
+ uint8 inst_id; /* publisher/subscriber id */
+ uint8 inst_type; /* publisher/subscriber */
+ uint8 dev_role; /* P2P device role: 'P2P','GO' or 'GC' */
+ uint8 pad1; /* padding */
+ uint8 resolution; /* Availability bitmap resolution */
+ uint8 repeat; /* Whether Availabilty repeat across DW */
+ uint16 ie_len; /* variable ie len */
+ struct ether_addr dev_mac; /* P2P device addres */
+ uint16 pad2; /* Padding */
+ uint32 avail_bmap; /* availability interval bitmap */
+ uint32 chanspec; /* Chanspec */
+ uint8 ie[1]; /* hex ie data */
+} wl_p2p_nan_config_t;
+
+#define WL_P2P_NAN_SERVICE_LIST_VERSION 1
+typedef enum wl_nan_service_type {
+ WL_NAN_SVC_INST_PUBLISHER = 1,
+ WL_NAN_SVC_INST_SUBSCRIBER = 2
+} wl_nan_service_type_t;
+
+#define WL_P2P_NAN_CONFIG_NEW 0x1
+#define WL_P2P_NAN_CONFIG_ADD 0x2
+#define WL_P2P_NAN_CONFIG_DEL 0x4
+
+typedef struct wl_nan_svc_inst {
+ uint8 inst_id; /* publisher/subscriber id */
+ uint8 inst_type; /* publisher/subscriber */
+} wl_nan_svc_inst_t;
+
+typedef struct wl_nan_svc_inst_list {
+ uint16 version; /* this structure version */
+ uint16 len; /* total length including version and variable svc list */
+ uint16 count; /* service instance count */
+ uint16 pad; /* padding */
+ wl_nan_svc_inst_t svc[1]; /* service instance list */
+} wl_nan_svc_inst_list_t;
+
+#define NAN_POST_DISC_P2P_DATA_VER 1
+/* This structure will be used send peer p2p data with
+ * NAN discovery result
+ */
+typedef struct nan_post_disc_p2p_data {
+ uint8 ver; /* this structure version */
+ uint8 dev_role; /* P2P Device role */
+ uint8 resolution; /* Availability bitmap resolution */
+ uint8 repeat; /* Whether Availabilty repeat across DW */
+ struct ether_addr dev_mac; /* P2P device addres */
+ uint16 pad1; /* Padding */
+ uint32 chanspec; /* Chanspec */
+ uint32 avl_bmp; /* availability interval bitmap */
+} nan_post_disc_p2p_data_t;
+
+/* timeslot etc for NAN */
+enum {
+ WL_TMU_TU = 0,
+ WL_TMU_SEC = 1,
+ WL_TMU_MILLI_SEC = 2,
+ WL_TMU_MICRO_SEC = 3,
+ WL_TMU_NANO_SEC = 4,
+ WL_TMU_PICO_SEC = 5
+};
+typedef int16 wl_tmu_t;
+
+typedef struct {
+ uint32 intvl; /* time interval */
+ wl_tmu_t tmu; /* time unit */
+ uint8 pad[2]; /* padding */
+} wl_time_interval_t;
+
+/* availabiloty slot flags */
+enum {
+ WL_AVAIL_SLOT_NONE = 0x0000,
+ WL_AVAIL_SLOT_COM = 0x0001, /* committed */
+ WL_AVAIL_SLOT_POT = 0x0002, /* potential */
+ WL_AVAIL_SLOT_PROP = 0x0004, /* proposed - note: not configurable */
+ WL_AVAIL_SLOT_PAGED = 0x0008 /* P-NDL */
+ /* 0x0030 - resrved for NDC index */
+ /* 0x00c0 - resrved for usage preference */
+};
+typedef int16 wl_avail_slot_flags_t;
+
+#define WL_AVAIL_SLOT_NDC_MASK 0x0030 /* up to 4 NDCs */
+#define WL_AVAIL_SLOT_NDC_SHIFT 4
+#define WL_AVAIL_SLOT_NDC(_flags) ((_flags) & WL_AVAIL_SLOT_NDC_MASK) \
+ >> WL_AVAIL_SLOT_NDC_SHIFT
+#define WL_AVAIL_SLOT_SET_NDC(_flags, _ndc_idx) (((_flags) & ~WL_AVAIL_SLOT_NDC_MASK) |\
+ ((_ndc_idx) << WL_AVAIL_SLOT_NDC_SHIFT))
+
+#define WL_AVAIL_SLOT_UPREF_MASK 0x00c0 /* up to 4 usage preferences */
+#define WL_AVAIL_SLOT_UPREF_SHIFT 6
+#define WL_AVAIL_SLOT_UPREF(_flags) ((_flags) & WL_AVAIL_SLOT_UPREF_MASK) \
+ >> WL_AVAIL_SLOT_UPREF_SHIFT
+#define WL_AVAIL_SLOT_SET_UPREF(_flags, _pref) (((_flags) & ~WL_AVAIL_SLOT_UPREF_MASK) |\
+ ((_pref) << WL_AVAIL_SLOT_UPREF_SHIFT))
+
+typedef struct wl_avail_slot {
+ wl_avail_slot_flags_t flags;
+ wl_time_interval_t start; /* from time ref */
+ wl_time_interval_t duration; /* from start */
+ uint32 chanspec; /* channel spec */
+} wl_avail_slot_t;
+
+/* time reference */
+enum {
+ WL_TIME_REF_NONE = 0,
+ WL_TIME_REF_DEV_TSF = 1,
+ WL_TIME_REF_NAN_DW = 2,
+ WL_TIME_REF_TBTT = 3,
+ WL_TIME_REF_NAN_DW0 = 4
+};
+typedef int16 wl_time_ref_t;
+
+enum {
+ WL_AVAIL_NONE = 0x0000,
+ WL_AVAIL_LOCAL = 0x0001,
+ WL_AVAIL_PEER = 0x0002,
+ WL_AVAIL_NDC = 0x0003,
+ WL_AVAIL_IMMUTABLE = 0x0004,
+ WL_AVAIL_RESPONSE = 0x0005,
+ WL_AVAIL_COUNTER = 0x0006,
+ WL_AVAIL_RANGING = 0x0007,
+ WL_AVAIL_TYPE_MAX = WL_AVAIL_RANGING /* New ones before and update */
+};
+typedef int16 wl_avail_flags_t;
+
+/* note: slots_off is offset to slots from beginning. It is
+ * initialized with sizeof(wl_avail_t), but processing should allow
+ * and ignore any extensions beyond (its) wl_avail_t size.
+ * slot_size is initialized with sizeof(wl_avail_slot_t), but processing
+ * should use the slot size from wl_avail_t so extensions to wl_avail_slot_t
+ * should be possible without changing wl_avail_t processing
+ */
+typedef struct wl_avail {
+ uint16 version;
+ uint16 length;
+ wl_avail_flags_t flags;
+ wl_time_ref_t time_ref;
+ wl_time_interval_t repeat;
+ uint16 slots_off;
+ uint8 slot_size;
+ uint8 num_slots;
+
+ /* add additional fields above this line */
+
+ wl_avail_slot_t slots[0]; /* nominal: at slots_off from start of struct */
+} wl_avail_t;
+
+/* get ptr to start of slot index in wl_avail */
+#define WL_AVAIL_SLOT(_avail, _slot_idx) (wl_avail_slot_t *) (\
+ (uint8 *)(_avail) + slots_off + ((_avail)->slot_size * (_slot_idx)))
+
+/* get ptr to first slot */
+#define WL_AVAIL_SLOTS(_avail) WL_AVAIL_SLOT(_avail, 0)
+
+/* determine allocation size for a given number slots */
+#define WL_AVAIL_ALLOC_SIZE(_num_slots) (sizeof(wl_avail_t) + \
+ sizeof(wl_avail_slot_t) * (_num_slots))
+
+/* availability entry flags */
+enum {
+ WL_AVAIL_ENTRY_NONE = 0x0000,
+ WL_AVAIL_ENTRY_COM = 0x0001, /* committed */
+ WL_AVAIL_ENTRY_POT = 0x0002, /* potential */
+ WL_AVAIL_ENTRY_COND = 0x0004, /* conditional */
+ WL_AVAIL_ENTRY_PAGED = 0x0008, /* P-NDL */
+ WL_AVAIL_ENTRY_USAGE = 0x0030, /* usage preference */
+ WL_AVAIL_ENTRY_BIT_DUR = 0x00c0, /* bit duration */
+ WL_AVAIL_ENTRY_BAND_PRESENT = 0x0100, /* band present */
+ WL_AVAIL_ENTRY_CHAN_PRESENT = 0x0200, /* channel information present */
+ WL_AVAIL_ENTRY_CHAN_ENTRY_PRESENT = 0x0400, /* channel entry (opclass+bitmap) */
+};
+
+/* bit duration */
+enum {
+ WL_AVAIL_BIT_DUR_16 = 0, /* 16TU */
+ WL_AVAIL_BIT_DUR_32 = 1, /* 32TU */
+ WL_AVAIL_BIT_DUR_64 = 2, /* 64TU */
+ WL_AVAIL_BIT_DUR_128 = 3, /* 128TU */
+};
+
+/* period */
+enum {
+ WL_AVAIL_PERIOD_0 = 0, /* 0TU */
+ WL_AVAIL_PERIOD_128 = 1, /* 128TU */
+ WL_AVAIL_PERIOD_256 = 2, /* 256TU */
+ WL_AVAIL_PERIOD_512 = 3, /* 512TU */
+ WL_AVAIL_PERIOD_1024 = 4, /* 1024TU */
+ WL_AVAIL_PERIOD_2048 = 5, /* 2048TU */
+ WL_AVAIL_PERIOD_4096 = 6, /* 4096TU */
+ WL_AVAIL_PERIOD_8192 = 7, /* 8192TU */
+};
+
+/* band */
+enum {
+ WL_AVAIL_BAND_NONE = 0, /* reserved */
+ WL_AVAIL_BAND_SUB1G = 1, /* sub-1 GHz */
+ WL_AVAIL_BAND_2G = 2, /* 2.4 GHz */
+ WL_AVAIL_BAND_3G = 3, /* reserved (for 3.6 GHz) */
+ WL_AVAIL_BAND_5G = 4, /* 4.9 and 5 GHz */
+ WL_AVAIL_BAND_60G = 5, /* reserved (for 60 GHz) */
+};
+
+#define WL_AVAIL_ENTRY_TYPE_MASK 0x0F
+#define WL_AVAIL_ENTRY_USAGE_MASK 0x0030 /* up to 4 usage preferences */
+#define WL_AVAIL_ENTRY_USAGE_SHIFT 4
+#define WL_AVAIL_ENTRY_USAGE_VAL(_flags) ((_flags) & WL_AVAIL_ENTRY_USAGE_MASK) \
+ >> WL_AVAIL_ENTRY_USAGE_SHIFT
+
+#define WL_AVAIL_ENTRY_BIT_DUR_MASK 0x00c0 /* 0:16TU, 1:32TU, 2:64TU, 3:128TU */
+#define WL_AVAIL_ENTRY_BIT_DUR_SHIFT 6
+#define WL_AVAIL_ENTRY_BIT_DUR_VAL(_flags) ((_flags) & WL_AVAIL_ENTRY_BIT_DUR_MASK) \
+ >> WL_AVAIL_ENTRY_BIT_DUR_SHIFT
+
+#define WL_AVAIL_ENTRY_BAND_MASK 0x0100 /* 0=band not present, 1=present */
+#define WL_AVAIL_ENTRY_BAND_SHIFT 8
+
+#define WL_AVAIL_ENTRY_CHAN_MASK 0x0200 /* 0=channel info not present, 1=present */
+#define WL_AVAIL_ENTRY_CHAN_SHIFT 9
+
+#define WL_AVAIL_ENTRY_CHAN_ENTRY_MASK 0x0400 /* 0=chanspec, 1=hex channel entry */
+#define WL_AVAIL_ENTRY_CHAN_ENTRY_SHIFT 10
+
+#define WL_AVAIL_ENTRY_OPCLASS_MASK 0xFF
+#define WL_AVAIL_ENTRY_CHAN_BITMAP_MASK 0xFF00
+#define WL_AVAIL_ENTRY_CHAN_BITMAP_SHIFT 8
+#define WL_AVAIL_ENTRY_CHAN_BITMAP_VAL(_info) ((_info) & WL_AVAIL_ENTRY_CHAN_BITMAP_MASK) \
+ >> WL_AVAIL_ENTRY_CHAN_BITMAP_SHIFT
+
+#define WL_AVAIL_TYPE_MASK 0x0F
+
+typedef struct wl_avail_entry {
+ uint16 length; /* total length */
+ uint16 start_offset; /* in TUs, multiply by 16 for total offset */
+ union {
+ uint32 channel_info; /* either chanspec or hex channel entry (opclass +
+ * bitmap per NAN spec), as indicated by setting
+ * WL_AVAIL_ENTRY_HEX_CHAN_ENTRY flag
+ */
+ uint32 band; /* defined by WL_BAND enum, 2=2.4GHz, 4=5GHz */
+ } u; /* band or channel value, 0=all band/channels */
+ uint8 period; /* in TUs, defined by WL_AVAIL_PERIOD enum
+ * 1:128, 2:256, 3:512, 4:1024, 5:2048, 6:4096,
+ * 7:8192
+ */
+ uint8 bitmap_len;
+ uint16 flags; /* defined by avail entry flags enum:
+ * type, usage pref, bit duration, band, channel
+ */
+ uint8 bitmap[]; /* time bitmap */
+} wl_avail_entry_t;
+
+/* Temporarily naming this to wl_avail_new until usage references
+ * to existing wl_avail are resolved.
+ */
+typedef struct wl_avail_new {
+ uint16 version;
+ uint16 length; /* total length */
+ uint16 flags; /* defined by WL_AVAIL enum
+ * 1=local, 2=peer, 3=ndc, 4=immutable,
+ * 5=response, 6=counter
+ */
+ uint16 time_ref; /* defined by WL_TIME_REF enum
+ * 1=TSF, 2=NANDW, 3=TBTT, 4=NANDW0
+ */
+ union {
+ uint8 id; /* local avail id */
+ struct ether_addr addr; /* peer mac address or ndc id */
+ } u;
+ uint8 num_entries;
+ uint8 entry_offset;
+ /* add additional fields above this line */
+ uint8 entry[];
+} wl_avail_new_t;
+
+#define WL_AVAIL_MIN_LEN(n) n ? OFFSETOF(wl_avail_new_t, entry) + \
+ (n * OFFSETOF(wl_avail_entry_t, bitmap)) : 0
+
+/* unaligned schedule - to be defined later */
+typedef struct wl_avail_ua {
+ uint16 version;
+ uint16 length;
+ uint8 data[0];
+} wl_avail_ua_t;
+
+/* nan wfa testmode operations */
+enum {
+ WL_NAN_WFA_TM_IGNORE_TERMINATE_NAF = 0x00000001,
+ WL_NAN_WFA_TM_IGNORE_RX_DATA_OUTSIDE_CRB = 0x00000002,
+ WL_NAN_WFA_TM_ALLOW_TX_DATA_OUTSIDE_CRB = 0x00000004,
+ WL_NAN_WFA_TM_ENFORCE_NDL_COUNTER = 0x00000008,
+ WL_NAN_WFA_TM_FLAG_MASK = 0x0000000f /* add above & update mask */
+};
+typedef uint32 wl_nan_wfa_testmode_t;
+
+#define RSSI_THRESHOLD_SIZE 16
+#define MAX_IMP_RESP_SIZE 256
+
+typedef struct wl_proxd_rssi_bias {
+ int32 version; /**< version */
+ int32 threshold[RSSI_THRESHOLD_SIZE]; /**< threshold */
+ int32 peak_offset; /**< peak offset */
+ int32 bias; /**< rssi bias */
+ int32 gd_delta; /**< GD - GD_ADJ */
+ int32 imp_resp[MAX_IMP_RESP_SIZE]; /**< (Hi*Hi)+(Hr*Hr) */
+} wl_proxd_rssi_bias_t;
+
+typedef struct wl_proxd_rssi_bias_avg {
+ int32 avg_threshold[RSSI_THRESHOLD_SIZE]; /**< avg threshold */
+ int32 avg_peak_offset; /**< avg peak offset */
+ int32 avg_rssi; /**< avg rssi */
+ int32 avg_bias; /**< avg bias */
+} wl_proxd_rssi_bias_avg_t;
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_info {
+ uint16 type; /**< type: 0 channel table, 1 channel smoothing table, 2 and 3 seq */
+ uint16 index; /**< The current frame index, from 1 to total_frames. */
+ uint16 tof_cmd; /**< M_TOF_CMD */
+ uint16 tof_rsp; /**< M_TOF_RSP */
+ uint16 tof_avb_rxl; /**< M_TOF_AVB_RX_L */
+ uint16 tof_avb_rxh; /**< M_TOF_AVB_RX_H */
+ uint16 tof_avb_txl; /**< M_TOF_AVB_TX_L */
+ uint16 tof_avb_txh; /**< M_TOF_AVB_TX_H */
+ uint16 tof_id; /**< M_TOF_ID */
+ uint8 tof_frame_type;
+ uint8 tof_frame_bw;
+ int8 tof_rssi;
+ int32 tof_cfo;
+ int32 gd_adj_ns; /**< gound delay */
+ int32 gd_h_adj_ns; /**< group delay + threshold crossing */
+ int16 nfft; /**< number of samples stored in H */
+ uint8 num_max_cores;
+
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_info_t;
+#include <packed_section_end.h>
+
+#define K_TOF_COLLECT_H_PAD 1
+#define K_TOF_COLLECT_SC_20MHZ (64)
+/* Maximum possible size of sample capture */
+#define K_TOF_COLLECT_SC_80MHZ (2*K_TOF_COLLECT_SC_20MHZ)
+/* Maximum possible size of channel dump */
+#define K_TOF_COLLECT_CHAN_SIZE (2*K_TOF_COLLECT_SC_80MHZ)
+
+/*
+A few extra samples are required to estimate frequency offset
+Right now 16 samples are being used. Can be changed in future.
+*/
+#define K_TOF_COLLECT_SAMP_SIZE_20MHZ (2*(K_TOF_COLLECT_SC_20MHZ)+16+K_TOF_COLLECT_H_PAD)
+#define K_TOF_COLLECT_RAW_SAMP_SIZE_20MHZ (2*K_TOF_COLLECT_SAMP_SIZE_20MHZ)
+#define K_TOF_COLLECT_H_SIZE_20MHZ (K_TOF_COLLECT_SAMP_SIZE_20MHZ)
+#define K_TOF_COLLECT_HRAW_SIZE_20MHZ (K_TOF_COLLECT_RAW_SAMP_SIZE_20MHZ)
+
+#define K_TOF_COLLECT_SAMP_SIZE_80MHZ (2*(K_TOF_COLLECT_SC_80MHZ)+16+K_TOF_COLLECT_H_PAD)
+#define K_TOF_COLLECT_RAW_SAMP_SIZE_80MHZ (2*K_TOF_COLLECT_SAMP_SIZE_80MHZ)
+#define K_TOF_COLLECT_H_SIZE_80MHZ (K_TOF_COLLECT_SAMP_SIZE_80MHZ)
+#define K_TOF_COLLECT_HRAW_SIZE_80MHZ (K_TOF_COLLECT_RAW_SAMP_SIZE_80MHZ)
+
+#define WL_PROXD_COLLECT_DATA_VERSION_1 1
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_data_v1 {
+ wl_proxd_collect_info_t info;
+ uint8 ri_rr[FTM_TPK_RI_RR_LEN];
+ /**< raw data read from phy used to adjust timestamps */
+ uint32 H[K_TOF_COLLECT_H_SIZE_20MHZ];
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_data_t_v1;
+#include <packed_section_end.h>
+
+#define WL_PROXD_COLLECT_DATA_VERSION_2 2
+typedef struct wl_proxd_collect_data_v2 {
+ uint16 version;
+ uint16 len;
+ wl_proxd_collect_info_t info;
+ uint8 ri_rr[FTM_TPK_RI_RR_LEN];
+ uint8 pad[3]; /* should be based on FTM_TPK_RI_RR_LEN */
+ /**< raw data read from phy used to adjust timestamps */
+ uint32 H[K_TOF_COLLECT_H_SIZE_20MHZ];
+ uint32 chan[4 * K_TOF_COLLECT_CHAN_SIZE];
+} wl_proxd_collect_data_t_v2;
+#define WL_PROXD_COLLECT_DATA_VERSION_MAX WL_PROXD_COLLECT_DATA_VERSION_2
+
+typedef struct wl_proxd_debug_data {
+ uint8 count; /**< number of packets */
+ uint8 stage; /**< state machone stage */
+ uint8 received; /**< received or txed */
+ uint8 paket_type; /**< packet type */
+ uint8 category; /**< category field */
+ uint8 action; /**< action field */
+ uint8 token; /**< token number */
+ uint8 follow_token; /**< following token number */
+ uint16 index; /**< index of the packet */
+ uint16 tof_cmd; /**< M_TOF_CMD */
+ uint16 tof_rsp; /**< M_TOF_RSP */
+ uint16 tof_avb_rxl; /**< M_TOF_AVB_RX_L */
+ uint16 tof_avb_rxh; /**< M_TOF_AVB_RX_H */
+ uint16 tof_avb_txl; /**< M_TOF_AVB_TX_L */
+ uint16 tof_avb_txh; /**< M_TOF_AVB_TX_H */
+ uint16 tof_id; /**< M_TOF_ID */
+ uint16 tof_status0; /**< M_TOF_STATUS_0 */
+ uint16 tof_status2; /**< M_TOF_STATUS_2 */
+ uint16 tof_chsm0; /**< M_TOF_CHNSM_0 */
+ uint16 tof_phyctl0; /**< M_TOF_PHYCTL0 */
+ uint16 tof_phyctl1; /**< M_TOF_PHYCTL1 */
+ uint16 tof_phyctl2; /**< M_TOF_PHYCTL2 */
+ uint16 tof_lsig; /**< M_TOF_LSIG */
+ uint16 tof_vhta0; /**< M_TOF_VHTA0 */
+ uint16 tof_vhta1; /**< M_TOF_VHTA1 */
+ uint16 tof_vhta2; /**< M_TOF_VHTA2 */
+ uint16 tof_vhtb0; /**< M_TOF_VHTB0 */
+ uint16 tof_vhtb1; /**< M_TOF_VHTB1 */
+ uint16 tof_apmductl; /**< M_TOF_AMPDU_CTL */
+ uint16 tof_apmdudlim; /**< M_TOF_AMPDU_DLIM */
+ uint16 tof_apmdulen; /**< M_TOF_AMPDU_LEN */
+} wl_proxd_debug_data_t;
+
+/** version of the wl_wsec_info structure */
+#define WL_WSEC_INFO_VERSION 0x01
+
+/** start enum value for BSS properties */
+#define WL_WSEC_INFO_BSS_BASE 0x0100
+
+/** size of len and type fields of wl_wsec_info_tlv_t struct */
+#define WL_WSEC_INFO_TLV_HDR_LEN OFFSETOF(wl_wsec_info_tlv_t, data)
+
+/** Allowed wl_wsec_info properties; not all of them may be supported. */
+typedef enum {
+ WL_WSEC_INFO_NONE = 0,
+ WL_WSEC_INFO_MAX_KEYS = 1,
+ WL_WSEC_INFO_NUM_KEYS = 2,
+ WL_WSEC_INFO_NUM_HW_KEYS = 3,
+ WL_WSEC_INFO_MAX_KEY_IDX = 4,
+ WL_WSEC_INFO_NUM_REPLAY_CNTRS = 5,
+ WL_WSEC_INFO_SUPPORTED_ALGOS = 6,
+ WL_WSEC_INFO_MAX_KEY_LEN = 7,
+ WL_WSEC_INFO_FLAGS = 8,
+ /* add global/per-wlc properties above */
+ WL_WSEC_INFO_BSS_FLAGS = (WL_WSEC_INFO_BSS_BASE + 1),
+ WL_WSEC_INFO_BSS_WSEC = (WL_WSEC_INFO_BSS_BASE + 2),
+ WL_WSEC_INFO_BSS_TX_KEY_ID = (WL_WSEC_INFO_BSS_BASE + 3),
+ WL_WSEC_INFO_BSS_ALGO = (WL_WSEC_INFO_BSS_BASE + 4),
+ WL_WSEC_INFO_BSS_KEY_LEN = (WL_WSEC_INFO_BSS_BASE + 5),
+ WL_WSEC_INFO_BSS_ALGOS = (WL_WSEC_INFO_BSS_BASE + 6),
+ /* add per-BSS properties above */
+ WL_WSEC_INFO_MAX = 0xffff
+} wl_wsec_info_type_t;
+
+typedef struct {
+ uint32 algos; /* set algos to be enabled/disabled */
+ uint32 mask; /* algos outside mask unaltered */
+} wl_wsec_info_algos_t;
+
+/** tlv used to return wl_wsec_info properties */
+typedef struct {
+ uint16 type;
+ uint16 len; /**< data length */
+ uint8 data[1]; /**< data follows */
+} wl_wsec_info_tlv_t;
+
+/** input/output data type for wsec_info iovar */
+typedef struct wl_wsec_info {
+ uint8 version; /**< structure version */
+ uint8 pad[2];
+ uint8 num_tlvs;
+ wl_wsec_info_tlv_t tlvs[1]; /**< tlv data follows */
+} wl_wsec_info_t;
+
+/*
+ * randmac definitions
+ */
+#define WL_RANDMAC_MODULE "randmac"
+#define WL_RANDMAC_API_VERSION 0x0100 /**< version 1.0 */
+#define WL_RANDMAC_API_MIN_VERSION 0x0100 /**< version 1.0 */
+
+/** subcommands that can apply to randmac */
+enum {
+ WL_RANDMAC_SUBCMD_NONE = 0,
+ WL_RANDMAC_SUBCMD_GET_VERSION = 1,
+ WL_RANDMAC_SUBCMD_ENABLE = 2,
+ WL_RANDMAC_SUBCMD_DISABLE = 3,
+ WL_RANDMAC_SUBCMD_CONFIG = 4,
+ WL_RANDMAC_SUBCMD_STATS = 5,
+ WL_RANDMAC_SUBCMD_CLEAR_STATS = 6,
+
+ WL_RANDMAC_SUBCMD_MAX
+};
+typedef int16 wl_randmac_subcmd_t;
+
+/* Common IOVAR struct */
+typedef struct wl_randmac {
+ uint16 version;
+ uint16 len; /* total length */
+ wl_randmac_subcmd_t subcmd_id; /* subcommand id */
+ uint8 data[0]; /* subcommand data */
+} wl_randmac_t;
+
+#define WL_RANDMAC_IOV_HDR_SIZE OFFSETOF(wl_randmac_t, data)
+
+/* randmac version subcommand */
+typedef struct wl_randmac_version {
+ uint16 version; /* Randmac method version info */
+ uint8 pad[2]; /* Align on 4 byte boundary */
+} wl_randmac_version_t;
+
+/*
+ * Bitmask for methods supporting MAC randomization feature
+ */
+#define WL_RANDMAC_USER_NONE 0x0000
+#define WL_RANDMAC_USER_FTM 0x0001
+#define WL_RANDMAC_USER_NAN 0x0002
+#define WL_RANDMAC_USER_SCAN 0x0004
+#define WL_RANDMAC_USER_ALL 0xFFFF
+typedef uint16 wl_randmac_method_t;
+
+enum {
+ WL_RANDMAC_FLAGS_NONE = 0x00,
+ WL_RANDMAC_FLAGS_ADDR = 0x01,
+ WL_RANDMAC_FLAGS_MASK = 0x02,
+ WL_RANDMAC_FLAGS_METHOD = 0x04,
+ WL_RANDMAC_FLAGS_ALL = 0xFF
+};
+typedef uint8 wl_randmac_flags_t;
+
+/* randmac statistics subcommand */
+typedef struct wl_randmac_stats {
+ uint32 set_ok; /* Set random addr success count */
+ uint32 set_fail; /* Set random addr failed count */
+ uint32 set_reqs; /* Set random addr count */
+ uint32 reset_reqs; /* Restore random addr count */
+ uint32 restore_ok; /* Restore random addr succes count */
+ uint32 restore_fail; /* Restore random addr failed count */
+ uint32 events_sent; /* randmac module events count */
+ uint32 events_rcvd; /* randmac events received count */
+} wl_randmac_stats_t;
+
+/* randmac config subcommand */
+typedef struct wl_randmac_config {
+ struct ether_addr addr; /* Randomized MAC address */
+ struct ether_addr addr_mask; /* bitmask for randomization */
+ wl_randmac_method_t method; /* Enabled methods */
+ wl_randmac_flags_t flags; /* What config info changed */
+} wl_randmac_config_t;
+
+enum {
+ WL_RANDMAC_EVENT_NONE = 0, /**< not an event, reserved */
+ WL_RANDMAC_EVENT_BSSCFG_ADDR_SET = 1, /* bsscfg addr randomized */
+ WL_RANDMAC_EVENT_BSSCFG_ADDR_RESTORE = 2, /* bsscfg addr restored */
+ WL_RANDMAC_EVENT_ENABLED = 3, /* randmac module enabled */
+ WL_RANDMAC_EVENT_DISABLE = 4, /* randmac module disabled */
+ WL_RANDMAC_EVENT_BSSCFG_STATUS = 5, /* bsscfg enable/disable */
+
+ WL_RANDMAC_EVENT_MAX
+};
+typedef int16 wl_randmac_event_type_t;
+typedef int32 wl_randmac_status_t;
+typedef uint32 wl_randmac_event_mask_t;
+
+#define WL_RANDMAC_EVENT_MASK_ALL 0xfffffffe
+#define WL_RANDMAC_EVENT_MASK_EVENT(_event_type) (1 << (_event_type))
+#define WL_RANDMAC_EVENT_ENABLED(_mask, _event_type) (\
+ ((_mask) & WL_RANDMAC_EVENT_MASK_EVENT(_event_type)) != 0)
+
+/** tlv IDs - data length 4 bytes unless overridden by type, alignment 32 bits */
+enum {
+ WL_RANDMAC_TLV_NONE = 0,
+ WL_RANDMAC_TLV_METHOD = 1,
+ WL_RANDMAC_TLV_ADDR = 2,
+ WL_RANDMAC_TLV_MASK = 3
+};
+typedef uint16 wl_randmac_tlv_id_t;
+
+typedef struct wl_randmac_tlv {
+ wl_randmac_tlv_id_t id;
+ uint16 len; /* Length of variable */
+ uint8 data[1];
+} wl_randmac_tlv_t;
+
+/** randmac event */
+typedef struct wl_randmac_event {
+ uint16 version;
+ uint16 len; /* Length of all variables */
+ wl_randmac_event_type_t type;
+ wl_randmac_method_t method;
+ uint8 pad[2];
+ wl_randmac_tlv_t tlvs[1]; /**< variable */
+} wl_randmac_event_t;
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/*
+ * scan MAC definitions
+ */
+
+/** common iovar struct */
+typedef struct wl_scanmac {
+ uint16 subcmd_id; /**< subcommand id */
+ uint16 len; /**< total length of data[] */
+ uint8 data[1]; /**< subcommand data */
+} wl_scanmac_t;
+
+/* subcommand ids */
+#define WL_SCANMAC_SUBCMD_ENABLE 0
+#define WL_SCANMAC_SUBCMD_BSSCFG 1 /**< only GET supported */
+#define WL_SCANMAC_SUBCMD_CONFIG 2
+
+/** scanmac enable data struct */
+typedef struct wl_scanmac_enable {
+ uint8 enable; /**< 1 - enable, 0 - disable */
+ uint8 pad[3]; /**< 4-byte struct alignment */
+} wl_scanmac_enable_t;
+
+/** scanmac bsscfg data struct */
+typedef struct wl_scanmac_bsscfg {
+ uint32 bsscfg; /**< bsscfg index */
+} wl_scanmac_bsscfg_t;
+
+/** scanmac config data struct */
+typedef struct wl_scanmac_config {
+ struct ether_addr mac; /**< 6 bytes of MAC address or MAC prefix (i.e. OUI) */
+ struct ether_addr random_mask; /**< randomized bits on each scan */
+ uint16 scan_bitmap; /**< scans to use this MAC address */
+ uint8 pad[2]; /**< 4-byte struct alignment */
+} wl_scanmac_config_t;
+
+/* scan bitmap */
+#define WL_SCANMAC_SCAN_UNASSOC (0x01 << 0) /**< unassociated scans */
+#define WL_SCANMAC_SCAN_ASSOC_ROAM (0x01 << 1) /**< associated roam scans */
+#define WL_SCANMAC_SCAN_ASSOC_PNO (0x01 << 2) /**< associated PNO scans */
+#define WL_SCANMAC_SCAN_ASSOC_HOST (0x01 << 3) /**< associated host scans */
+
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/*
+ * bonjour dongle offload definitions
+ */
+
+/* common iovar struct */
+typedef struct wl_bdo {
+ uint16 subcmd_id; /* subcommand id */
+ uint16 len; /* total length of data[] */
+ uint8 data[1]; /* subcommand data */
+} wl_bdo_t;
+
+/* subcommand ids */
+#define WL_BDO_SUBCMD_DOWNLOAD 0 /* Download flattened database */
+#define WL_BDO_SUBCMD_ENABLE 1 /* Start bonjour after download */
+#define WL_BDO_SUBCMD_MAX_DOWNLOAD 2 /* Get the max download size */
+
+/* maximum fragment size */
+#define BDO_MAX_FRAGMENT_SIZE 1024
+
+/* download flattened database
+ *
+ * BDO must be disabled before database download else fail.
+ *
+ * If database size is within BDO_MAX_FRAGMENT_SIZE then only a single fragment
+ * is required (i.e. frag_num = 0, total_size = frag_size).
+ * If database size exceeds BDO_MAX_FRAGMENT_SIZE then multiple fragments are required.
+ */
+typedef struct wl_bdo_download {
+ uint16 total_size; /* total database size */
+ uint16 frag_num; /* fragment number, 0 for first fragment, N-1 for last fragment */
+ uint16 frag_size; /* size of fragment (max BDO_MAX_FRAGMENT_SIZE) */
+ uint8 pad[2]; /* 4-byte struct alignment */
+ uint8 fragment[BDO_MAX_FRAGMENT_SIZE]; /* fragment data */
+} wl_bdo_download_t;
+
+/* enable
+ *
+ * Enable requires a downloaded database else fail.
+ */
+typedef struct wl_bdo_enable {
+ uint8 enable; /* 1 - enable, 0 - disable */
+ uint8 pad[3]; /* 4-byte struct alignment */
+} wl_bdo_enable_t;
+
+/*
+ * Get the max download size for Bonjour Offload.
+ */
+typedef struct wl_bdo_max_download {
+ uint16 size; /* Max download size in bytes */
+ uint8 pad[2]; /* 4-byte struct alignment */
+} wl_bdo_max_download_t;
+
+/*
+ * TCP keepalive offload definitions
+ */
+
+/* common iovar struct */
+typedef struct wl_tko {
+ uint16 subcmd_id; /* subcommand id */
+ uint16 len; /* total length of data[] */
+ uint8 data[1]; /* subcommand data */
+} wl_tko_t;
+
+/* subcommand ids */
+#define WL_TKO_SUBCMD_MAX_TCP 0 /* max TCP connections supported */
+#define WL_TKO_SUBCMD_PARAM 1 /* configure offload common parameters */
+#define WL_TKO_SUBCMD_CONNECT 2 /* TCP connection info */
+#define WL_TKO_SUBCMD_ENABLE 3 /* enable/disable */
+#define WL_TKO_SUBCMD_STATUS 4 /* TCP connection status */
+
+/* WL_TKO_SUBCMD_MAX_CONNECT subcommand data */
+typedef struct wl_tko_max_tcp {
+ uint8 max; /* max TCP connections supported */
+ uint8 pad[3]; /* 4-byte struct alignment */
+} wl_tko_max_tcp_t;
+
+/* WL_TKO_SUBCMD_PARAM subcommand data */
+typedef struct wl_tko_param {
+ uint16 interval; /* keepalive tx interval (secs) */
+ uint16 retry_interval; /* keepalive retry interval (secs) */
+ uint16 retry_count; /* retry_count */
+ uint8 pad[2]; /* 4-byte struct alignment */
+} wl_tko_param_t;
+
+/* WL_TKO_SUBCMD_CONNECT subcommand data
+ * invoke with unique 'index' for each TCP connection
+ */
+typedef struct wl_tko_connect {
+ uint8 index; /* TCP connection index, 0 to max-1 */
+ uint8 ip_addr_type; /* 0 - IPv4, 1 - IPv6 */
+ uint16 local_port; /* local port */
+ uint16 remote_port; /* remote port */
+ uint32 local_seq; /* local sequence number */
+ uint32 remote_seq; /* remote sequence number */
+ uint16 request_len; /* TCP keepalive request packet length */
+ uint16 response_len; /* TCP keepalive response packet length */
+ uint8 data[1]; /* variable length field containing local/remote IPv4/IPv6,
+ * TCP keepalive request packet, TCP keepalive response packet
+ * For IPv4, length is 4 * 2 + request_length + response_length
+ * offset 0 - local IPv4
+ * offset 4 - remote IPv4
+ * offset 8 - TCP keepalive request packet
+ * offset 8+request_length - TCP keepalive response packet
+ * For IPv6, length is 16 * 2 + request_length + response_length
+ * offset 0 - local IPv6
+ * offset 16 - remote IPv6
+ * offset 32 - TCP keepalive request packet
+ * offset 32+request_length - TCP keepalive response packet
+ */
+} wl_tko_connect_t;
+
+/* WL_TKO_SUBCMD_CONNECT subcommand data to GET configured info for specific index */
+typedef struct wl_tko_get_connect {
+ uint8 index; /* TCP connection index, 0 to max-1 */
+ uint8 pad[3]; /* 4-byte struct alignment */
+} wl_tko_get_connect_t;
+
+typedef struct wl_tko_enable {
+ uint8 enable; /* 1 - enable, 0 - disable */
+ uint8 pad[3]; /* 4-byte struct alignment */
+} wl_tko_enable_t;
+
+/* WL_TKO_SUBCMD_STATUS subcommand data */
+/* must be invoked before tko is disabled else status is unavailable */
+typedef struct wl_tko_status {
+ uint8 count; /* number of status entries (i.e. equals
+ * max TCP connections supported)
+ */
+ uint8 status[1]; /* variable length field contain status for
+ * each TCP connection index
+ */
+} wl_tko_status_t;
+
+typedef enum {
+ TKO_STATUS_NORMAL = 0, /* TCP connection normal, no error */
+ TKO_STATUS_NO_RESPONSE = 1, /* no response to TCP keepalive */
+ TKO_STATUS_NO_TCP_ACK_FLAG = 2, /* TCP ACK flag not set */
+ TKO_STATUS_UNEXPECT_TCP_FLAG = 3, /* unexpect TCP flags set other than ACK */
+ TKO_STATUS_SEQ_NUM_INVALID = 4, /* ACK != sequence number */
+ TKO_STATUS_REMOTE_SEQ_NUM_INVALID = 5, /* SEQ > remote sequence number */
+ TKO_STATUS_TCP_DATA = 6, /* TCP data available */
+ TKO_STATUS_UNAVAILABLE = 255, /* not used/configured */
+} tko_status_t;
+
+enum rssi_reason {
+ RSSI_REASON_UNKNOW = 0,
+ RSSI_REASON_LOWRSSI = 1,
+ RSSI_REASON_NSYC = 2,
+ RSSI_REASON_TIMEOUT = 3
+};
+
+enum tof_reason {
+ TOF_REASON_OK = 0,
+ TOF_REASON_REQEND = 1,
+ TOF_REASON_TIMEOUT = 2,
+ TOF_REASON_NOACK = 3,
+ TOF_REASON_INVALIDAVB = 4,
+ TOF_REASON_INITIAL = 5,
+ TOF_REASON_ABORT = 6
+};
+
+enum rssi_state {
+ RSSI_STATE_POLL = 0,
+ RSSI_STATE_TPAIRING = 1,
+ RSSI_STATE_IPAIRING = 2,
+ RSSI_STATE_THANDSHAKE = 3,
+ RSSI_STATE_IHANDSHAKE = 4,
+ RSSI_STATE_CONFIRMED = 5,
+ RSSI_STATE_PIPELINE = 6,
+ RSSI_STATE_NEGMODE = 7,
+ RSSI_STATE_MONITOR = 8,
+ RSSI_STATE_LAST = 9
+};
+
+enum tof_state {
+ TOF_STATE_IDLE = 0,
+ TOF_STATE_IWAITM = 1,
+ TOF_STATE_TWAITM = 2,
+ TOF_STATE_ILEGACY = 3,
+ TOF_STATE_IWAITCL = 4,
+ TOF_STATE_TWAITCL = 5,
+ TOF_STATE_ICONFIRM = 6,
+ TOF_STATE_IREPORT = 7
+};
+
+enum tof_mode_type {
+ TOF_LEGACY_UNKNOWN = 0,
+ TOF_LEGACY_AP = 1,
+ TOF_NONLEGACY_AP = 2
+};
+
+enum tof_way_type {
+ TOF_TYPE_ONE_WAY = 0,
+ TOF_TYPE_TWO_WAY = 1,
+ TOF_TYPE_REPORT = 2
+};
+
+enum tof_rate_type {
+ TOF_FRAME_RATE_VHT = 0,
+ TOF_FRAME_RATE_LEGACY = 1
+};
+
+#define TOF_ADJ_TYPE_NUM 4 /**< number of assisted timestamp adjustment */
+enum tof_adj_mode {
+ TOF_ADJ_SOFTWARE = 0,
+ TOF_ADJ_HARDWARE = 1,
+ TOF_ADJ_SEQ = 2,
+ TOF_ADJ_NONE = 3
+};
+
+#define FRAME_TYPE_NUM 4 /**< number of frame type */
+enum frame_type {
+ FRAME_TYPE_CCK = 0,
+ FRAME_TYPE_OFDM = 1,
+ FRAME_TYPE_11N = 2,
+ FRAME_TYPE_11AC = 3
+};
+
+typedef struct wl_proxd_status_iovar {
+ uint16 method; /**< method */
+ uint8 mode; /**< mode */
+ uint8 peermode; /**< peer mode */
+ uint8 state; /**< state */
+ uint8 reason; /**< reason code */
+ uint32 distance; /**< distance */
+ uint32 txcnt; /**< tx pkt counter */
+ uint32 rxcnt; /**< rx pkt counter */
+ struct ether_addr peer; /**< peer mac address */
+ int8 avg_rssi; /**< average rssi */
+ int8 hi_rssi; /**< highest rssi */
+ int8 low_rssi; /**< lowest rssi */
+ uint32 dbgstatus; /**< debug status */
+ uint16 frame_type_cnt[FRAME_TYPE_NUM]; /**< frame types */
+ uint8 adj_type_cnt[TOF_ADJ_TYPE_NUM]; /**< adj types HW/SW */
+} wl_proxd_status_iovar_t;
+
+#ifdef NET_DETECT
+typedef struct net_detect_adapter_features {
+ uint8 wowl_enabled;
+ uint8 net_detect_enabled;
+ uint8 nlo_enabled;
+} net_detect_adapter_features_t;
+
+typedef enum net_detect_bss_type {
+ nd_bss_any = 0,
+ nd_ibss,
+ nd_ess
+} net_detect_bss_type_t;
+
+typedef struct net_detect_profile {
+ wlc_ssid_t ssid;
+ net_detect_bss_type_t bss_type; /**< Ignore for now since Phase 1 is only for ESS */
+ uint32 cipher_type; /**< DOT11_CIPHER_ALGORITHM enumeration values */
+ uint32 auth_type; /**< DOT11_AUTH_ALGORITHM enumeration values */
+} net_detect_profile_t;
+
+typedef struct net_detect_profile_list {
+ uint32 num_nd_profiles;
+ net_detect_profile_t nd_profile[0];
+} net_detect_profile_list_t;
+
+typedef struct net_detect_config {
+ uint8 nd_enabled;
+ uint32 scan_interval;
+ uint32 wait_period;
+ uint8 wake_if_connected;
+ uint8 wake_if_disconnected;
+ net_detect_profile_list_t nd_profile_list;
+} net_detect_config_t;
+
+typedef enum net_detect_wake_reason {
+ nd_reason_unknown,
+ nd_net_detected,
+ nd_wowl_event,
+ nd_ucode_error
+} net_detect_wake_reason_t;
+
+typedef struct net_detect_wake_data {
+ net_detect_wake_reason_t nd_wake_reason;
+ uint32 nd_wake_date_length;
+ uint8 nd_wake_data[0]; /**< Wake data (currently unused) */
+} net_detect_wake_data_t;
+
+#endif /* NET_DETECT */
+
+
+/* (unversioned, deprecated) */
+typedef struct bcnreq {
+ uint8 bcn_mode;
+ int32 dur;
+ int32 channel;
+ struct ether_addr da;
+ uint16 random_int;
+ wlc_ssid_t ssid;
+ uint16 reps;
+} bcnreq_t;
+
+#define WL_RRM_BCN_REQ_VER 1
+typedef struct bcn_req {
+ uint8 version;
+ uint8 bcn_mode;
+ uint8 pad_1[2];
+ int32 dur;
+ int32 channel;
+ struct ether_addr da;
+ uint16 random_int;
+ wlc_ssid_t ssid;
+ uint16 reps;
+ uint8 req_elements;
+ uint8 pad_2;
+ chanspec_list_t chspec_list;
+} bcn_req_t;
+
+typedef struct rrmreq {
+ struct ether_addr da;
+ uint8 reg;
+ uint8 chan;
+ uint16 random_int;
+ uint16 dur;
+ uint16 reps;
+} rrmreq_t;
+
+typedef struct framereq {
+ struct ether_addr da;
+ uint8 reg;
+ uint8 chan;
+ uint16 random_int;
+ uint16 dur;
+ struct ether_addr ta;
+ uint16 reps;
+} framereq_t;
+
+typedef struct statreq {
+ struct ether_addr da;
+ struct ether_addr peer;
+ uint16 random_int;
+ uint16 dur;
+ uint8 group_id;
+ uint16 reps;
+} statreq_t;
+
+typedef struct wl_rrm_config_ioc {
+ uint16 version; /* command version */
+ uint16 id; /* subiovar cmd ID */
+ uint16 len; /* total length of all bytes in data[] */
+ uint16 pad; /* 4-byte boundary padding */
+ uint8 data[1]; /* payload */
+} wl_rrm_config_ioc_t;
+
+enum {
+ WL_RRM_CONFIG_NONE = 0, /* reserved */
+ WL_RRM_CONFIG_GET_LCI = 1, /* get LCI */
+ WL_RRM_CONFIG_SET_LCI = 2, /* set LCI */
+ WL_RRM_CONFIG_GET_CIVIC = 3, /* get civic location */
+ WL_RRM_CONFIG_SET_CIVIC = 4, /* set civic location */
+ WL_RRM_CONFIG_MAX = 5
+};
+
+#define WL_RRM_CONFIG_NAME "rrm_config"
+#define WL_RRM_CONFIG_MIN_LENGTH OFFSETOF(wl_rrm_config_ioc_t, data)
+
+enum {
+ WL_RRM_EVENT_NONE = 0, /* not an event, reserved */
+ WL_RRM_EVENT_FRNG_REQ = 1, /* Receipt of FRNG request frame */
+ WL_RRM_EVENT_FRNG_REP = 2, /* Receipt of FRNG report frame */
+
+ WL_RRM_EVENT_MAX
+};
+typedef int16 wl_rrm_event_type_t;
+
+typedef struct frngreq_target {
+ uint32 bssid_info;
+ uint8 channel;
+ uint8 phytype;
+ uint8 reg;
+ uint8 pad;
+ struct ether_addr bssid;
+ chanspec_t chanspec;
+ uint32 sid;
+} frngreq_target_t;
+
+typedef struct frngreq {
+ wl_rrm_event_type_t event; /* RRM event type */
+ struct ether_addr da;
+ uint16 max_init_delay; /* Upper bound of random delay, in TUs */
+ uint8 min_ap_count; /* Min FTM ranges requested (1-15) */
+ uint8 num_aps; /* Number of APs to range, at least min_ap_count */
+ uint16 max_age; /* Max elapsed time before FTM request, 0xFFFF = any */
+ uint16 reps; /* Number of repetitions of this measurement type */
+ frngreq_target_t targets[1]; /* Target BSSIDs to range */
+} frngreq_t;
+
+typedef struct frngrep_range {
+ uint32 start_tsf; /* 4 lsb of tsf */
+ struct ether_addr bssid;
+ uint8 pad[2];
+ uint32 range;
+ uint32 max_err;
+ uint8 rsvd;
+ uint8 pad2[3];
+} frngrep_range_t;
+
+typedef struct frngrep_error {
+ uint32 start_tsf; /* 4 lsb of tsf */
+ struct ether_addr bssid;
+ uint8 code;
+ uint8 pad[1];
+} frngrep_error_t;
+
+typedef struct frngrep {
+ wl_rrm_event_type_t event; /* RRM event type */
+ struct ether_addr da;
+ uint8 range_entry_count;
+ uint8 error_entry_count;
+ uint16 dialog_token; /* dialog token */
+ frngrep_range_t range_entries[DOT11_FTM_RANGE_ENTRY_MAX_COUNT];
+ frngrep_error_t error_entries[DOT11_FTM_RANGE_ERROR_ENTRY_MAX_COUNT];
+} frngrep_t;
+
+typedef struct wl_rrm_frng_ioc {
+ uint16 version; /* command version */
+ uint16 id; /* subiovar cmd ID */
+ uint16 len; /* total length of all bytes in data[] */
+ uint16 pad; /* 4-byte boundary padding */
+ uint8 data[1]; /* payload */
+} wl_rrm_frng_ioc_t;
+
+enum {
+ WL_RRM_FRNG_NONE = 0, /* reserved */
+ WL_RRM_FRNG_SET_REQ = 1, /* send ftm ranging request */
+ WL_RRM_FRNG_MAX = 2
+};
+
+#define WL_RRM_FRNG_NAME "rrm_frng"
+#define WL_RRM_FRNG_MIN_LENGTH OFFSETOF(wl_rrm_frng_ioc_t, data)
+
+#define WL_RRM_RPT_VER 0
+#define WL_RRM_RPT_MAX_PAYLOAD 256
+#define WL_RRM_RPT_MIN_PAYLOAD 7
+#define WL_RRM_RPT_FALG_ERR 0
+#define WL_RRM_RPT_FALG_GRP_ID_PROPR (1 << 0)
+#define WL_RRM_RPT_FALG_GRP_ID_0 (1 << 1)
+typedef struct {
+ uint16 ver; /**< version */
+ struct ether_addr addr; /**< STA MAC addr */
+ uint32 timestamp; /**< timestamp of the report */
+ uint16 flag; /**< flag */
+ uint16 len; /**< length of payload data */
+ uint8 data[WL_RRM_RPT_MAX_PAYLOAD];
+} statrpt_t;
+
+typedef struct wlc_dwds_config {
+ uint32 enable;
+ uint32 mode; /**< STA/AP interface */
+ struct ether_addr ea;
+} wlc_dwds_config_t;
+
+typedef struct wl_el_set_params_s {
+ uint8 set; /**< Set number */
+ uint32 size; /**< Size to make/expand */
+} wl_el_set_params_t;
+
+typedef struct wl_el_tag_params_s {
+ uint16 tag;
+ uint8 set;
+ uint8 flags;
+} wl_el_tag_params_t;
+
+/** Video Traffic Interference Monitor config */
+#define INTFER_VERSION 1
+typedef struct wl_intfer_params {
+ uint16 version; /**< version */
+ uint8 period; /**< sample period */
+ uint8 cnt; /**< sample cnt */
+ uint8 txfail_thresh; /**< non-TCP txfail threshold */
+ uint8 tcptxfail_thresh; /**< tcptxfail threshold */
+} wl_intfer_params_t;
+
+typedef struct wl_staprio_cfg {
+ struct ether_addr ea; /**< mac addr */
+ uint8 prio; /**< scb priority */
+} wl_staprio_cfg_t;
+
+typedef enum wl_stamon_cfg_cmd_type {
+ STAMON_CFG_CMD_DEL = 0,
+ STAMON_CFG_CMD_ADD = 1,
+ STAMON_CFG_CMD_ENB = 2,
+ STAMON_CFG_CMD_DSB = 3,
+ STAMON_CFG_CMD_CNT = 4,
+ STAMON_CFG_CMD_RSTCNT = 5,
+ STAMON_CFG_CMD_GET_STATS = 6
+} wl_stamon_cfg_cmd_type_t;
+
+typedef struct wlc_stamon_sta_config {
+ wl_stamon_cfg_cmd_type_t cmd; /**< 0 - delete, 1 - add */
+ struct ether_addr ea;
+} wlc_stamon_sta_config_t;
+
+#ifdef SR_DEBUG
+typedef struct /* pmu_reg */{
+ uint32 pmu_control;
+ uint32 pmu_capabilities;
+ uint32 pmu_status;
+ uint32 res_state;
+ uint32 res_pending;
+ uint32 pmu_timer1;
+ uint32 min_res_mask;
+ uint32 max_res_mask;
+ uint32 pmu_chipcontrol1[4];
+ uint32 pmu_regcontrol[5];
+ uint32 pmu_pllcontrol[5];
+ uint32 pmu_rsrc_up_down_timer[31];
+ uint32 rsrc_dep_mask[31];
+} pmu_reg_t;
+#endif /* pmu_reg */
+
+typedef struct wl_taf_define {
+ struct ether_addr ea; /**< STA MAC or 0xFF... */
+ uint16 version; /**< version */
+ uint32 sch; /**< method index */
+ uint32 prio; /**< priority */
+ uint32 misc; /**< used for return value */
+ uint8 text[1]; /**< used to pass and return ascii text */
+} wl_taf_define_t;
+
+/** Received Beacons lengths information */
+#define WL_LAST_BCNS_INFO_FIXED_LEN OFFSETOF(wlc_bcn_len_hist_t, bcnlen_ring)
+typedef struct wlc_bcn_len_hist {
+ uint16 ver; /**< version field */
+ uint16 cur_index; /**< current pointed index in ring buffer */
+ uint32 max_bcnlen; /**< Max beacon length received */
+ uint32 min_bcnlen; /**< Min beacon length received */
+ uint32 ringbuff_len; /**< Length of the ring buffer 'bcnlen_ring' */
+ uint32 bcnlen_ring[1]; /**< ring buffer storing received beacon lengths */
+} wlc_bcn_len_hist_t;
+
+/* WDS net interface types */
+#define WL_WDSIFTYPE_NONE 0x0 /**< The interface type is neither WDS nor DWDS. */
+#define WL_WDSIFTYPE_WDS 0x1 /**< The interface is WDS type. */
+#define WL_WDSIFTYPE_DWDS 0x2 /**< The interface is DWDS type. */
+
+typedef struct wl_bssload_static {
+ uint8 is_static;
+ uint16 sta_count;
+ uint8 chan_util;
+ uint16 aac;
+} wl_bssload_static_t;
+
+/* Buffer of size WLC_SAMPLECOLLECT_MAXLEN (=10240 for 4345a0 ACPHY)
+ * gets copied to this, multiple times
+ */
+typedef enum wl_gpaio_option {
+ GPAIO_PMU_AFELDO,
+ GPAIO_PMU_TXLDO,
+ GPAIO_PMU_VCOLDO,
+ GPAIO_PMU_LNALDO,
+ GPAIO_PMU_ADCLDO,
+ GPAIO_ICTAT_CAL,
+ GPAIO_PMU_CLEAR,
+ GPAIO_OFF,
+ GPAIO_PMU_LOGENLDO,
+ GPAIO_PMU_RXLDO2G,
+ GPAIO_PMU_RXLDO5G
+} wl_gpaio_option_t;
+
+/** IO Var Operations - the Value of iov_op In wlc_ap_doiovar */
+typedef enum wlc_ap_iov_bss_operation {
+ WLC_AP_IOV_OP_DELETE = -1,
+ WLC_AP_IOV_OP_DISABLE = 0,
+ WLC_AP_IOV_OP_ENABLE = 1,
+ WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE = 2,
+ WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE = 3,
+ WLC_AP_IOV_OP_MOVE = 4
+} wlc_ap_iov_bss_oper_t;
+
+/* LTE coex info */
+/* Analogue of HCI Set MWS Signaling cmd */
+typedef struct {
+ int16 mws_rx_assert_offset;
+ int16 mws_rx_assert_jitter;
+ int16 mws_rx_deassert_offset;
+ int16 mws_rx_deassert_jitter;
+ int16 mws_tx_assert_offset;
+ int16 mws_tx_assert_jitter;
+ int16 mws_tx_deassert_offset;
+ int16 mws_tx_deassert_jitter;
+ int16 mws_pattern_assert_offset;
+ int16 mws_pattern_assert_jitter;
+ int16 mws_inact_dur_assert_offset;
+ int16 mws_inact_dur_assert_jitter;
+ int16 mws_scan_freq_assert_offset;
+ int16 mws_scan_freq_assert_jitter;
+ int16 mws_prio_assert_offset_req;
+} wci2_config_t;
+
+/** Analogue of HCI MWS Channel Params */
+typedef struct {
+ uint16 mws_rx_center_freq; /**< MHz */
+ uint16 mws_tx_center_freq;
+ uint16 mws_rx_channel_bw; /**< KHz */
+ uint16 mws_tx_channel_bw;
+ uint8 mws_channel_en;
+ uint8 mws_channel_type; /**< Don't care for WLAN? */
+} mws_params_t;
+
+#define LTECX_MAX_NUM_PERIOD_TYPES 7
+
+/* LTE Frame params */
+typedef struct {
+ uint16 mws_frame_dur;
+ int16 mws_framesync_assert_offset;
+ uint16 mws_framesync_assert_jitter;
+ uint16 mws_period_dur[LTECX_MAX_NUM_PERIOD_TYPES];
+ uint8 mws_period_type[LTECX_MAX_NUM_PERIOD_TYPES];
+ uint8 mws_num_periods;
+} mws_frame_config_t;
+
+/** MWS wci2 message */
+typedef struct {
+ uint8 mws_wci2_data; /**< BT-SIG msg */
+ uint16 mws_wci2_interval; /**< Interval in us */
+ uint16 mws_wci2_repeat; /**< No of msgs to send */
+} mws_wci2_msg_t;
+/* MWS ANT map */
+typedef struct {
+ uint16 combo1; /* mws ant selection 1 */
+ uint16 combo2; /* mws ant selection 2 */
+ uint16 combo3; /* mws ant selection 3 */
+ uint16 combo4; /* mws ant selection 4 */
+} mws_ant_map_t;
+
+/* MWS SCAN_REQ Bitmap */
+typedef struct mws_scanreq_params {
+ uint16 idx;
+ uint16 bm_2g;
+ uint16 bm_5g_lo;
+ uint16 bm_5g_mid;
+ uint16 bm_5g_hi;
+} mws_scanreq_params_t;
+
+typedef struct {
+ uint32 config; /**< MODE: AUTO (-1), Disable (0), Enable (1) */
+ uint32 status; /**< Current state: Disabled (0), Enabled (1) */
+} wl_config_t;
+
+#define WLC_RSDB_MODE_AUTO_MASK 0x80
+#define WLC_RSDB_EXTRACT_MODE(val) ((int8)((val) & (~(WLC_RSDB_MODE_AUTO_MASK))))
+
+typedef struct {
+ uint16 request; /* type of sensor hub request */
+ uint16 enable; /* enable/disable response for specified request */
+ uint16 interval; /* interval between responses to the request */
+} shub_req_t;
+
+#define WL_IF_STATS_T_VERSION 1 /**< current version of wl_if_stats structure */
+
+/** per interface counters */
+typedef struct wl_if_stats {
+ uint16 version; /**< version of the structure */
+ uint16 length; /**< length of the entire structure */
+ uint32 PAD; /**< padding */
+
+ /* transmit stat counters */
+ uint64 txframe; /**< tx data frames */
+ uint64 txbyte; /**< tx data bytes */
+ uint64 txerror; /**< tx data errors (derived: sum of others) */
+ uint64 txnobuf; /**< tx out of buffer errors */
+ uint64 txrunt; /**< tx runt frames */
+ uint64 txfail; /**< tx failed frames */
+ uint64 txretry; /**< tx retry frames */
+ uint64 txretrie; /**< tx multiple retry frames */
+ uint64 txfrmsnt; /**< tx sent frames */
+ uint64 txmulti; /**< tx mulitcast sent frames */
+ uint64 txfrag; /**< tx fragments sent */
+
+ /* receive stat counters */
+ uint64 rxframe; /**< rx data frames */
+ uint64 rxbyte; /**< rx data bytes */
+ uint64 rxerror; /**< rx data errors (derived: sum of others) */
+ uint64 rxnobuf; /**< rx out of buffer errors */
+ uint64 rxrunt; /**< rx runt frames */
+ uint64 rxfragerr; /**< rx fragment errors */
+ uint64 rxmulti; /**< rx multicast frames */
+
+ uint64 txexptime; /* DATA Tx frames suppressed due to timer expiration */
+ uint64 txrts; /* RTS/CTS succeeeded count */
+ uint64 txnocts; /* RTS/CTS faled count */
+}
+wl_if_stats_t;
+
+typedef struct wl_band {
+ uint16 bandtype; /**< WL_BAND_2G, WL_BAND_5G */
+ uint16 bandunit; /**< bandstate[] index */
+ uint16 phytype; /**< phytype */
+ uint16 phyrev;
+}
+wl_band_t;
+
+#define WL_WLC_VERSION_T_VERSION 1 /**< current version of wlc_version structure */
+
+/** wlc interface version */
+typedef struct wl_wlc_version {
+ uint16 version; /**< version of the structure */
+ uint16 length; /**< length of the entire structure */
+
+ /* epi version numbers */
+ uint16 epi_ver_major; /**< epi major version number */
+ uint16 epi_ver_minor; /**< epi minor version number */
+ uint16 epi_rc_num; /**< epi RC number */
+ uint16 epi_incr_num; /**< epi increment number */
+
+ /* wlc interface version numbers */
+ uint16 wlc_ver_major; /**< wlc interface major version number */
+ uint16 wlc_ver_minor; /**< wlc interface minor version number */
+}
+wl_wlc_version_t;
+
+/* Version of WLC interface to be returned as a part of wl_wlc_version structure.
+ * For the discussion related to versions update policy refer to
+ * http://hwnbu-twiki.broadcom.com/bin/view/Mwgroup/WlShimAbstractionLayer
+ * For now the policy is to increment WLC_VERSION_MAJOR each time
+ * there is a change that involves both WLC layer and per-port layer.
+ * WLC_VERSION_MINOR is currently not in use.
+ */
+#define WLC_VERSION_MAJOR 8
+#define WLC_VERSION_MINOR 0
+
+/* begin proxd definitions */
+#include <packed_section_start.h>
+
+#define WL_PROXD_API_VERSION 0x0300 /**< version 3.0 */
+
+/** Minimum supported API version */
+#define WL_PROXD_API_MIN_VERSION 0x0300
+
+/** proximity detection methods */
+enum {
+ WL_PROXD_METHOD_NONE = 0,
+ WL_PROXD_METHOD_RSVD1 = 1, /**< backward compatibility - RSSI, not supported */
+ WL_PROXD_METHOD_TOF = 2,
+ WL_PROXD_METHOD_RSVD2 = 3, /**< 11v only - if needed */
+ WL_PROXD_METHOD_FTM = 4, /**< IEEE rev mc/2014 */
+ WL_PROXD_METHOD_MAX
+};
+typedef int16 wl_proxd_method_t;
+
+/** global and method configuration flags */
+enum {
+ WL_PROXD_FLAG_NONE = 0x00000000,
+ WL_PROXD_FLAG_RX_ENABLED = 0x00000001, /**< respond to requests, per bss */
+ WL_PROXD_FLAG_RX_RANGE_REQ = 0x00000002, /**< 11mc range requests enabled */
+ WL_PROXD_FLAG_TX_LCI = 0x00000004, /**< tx lci, if known */
+ WL_PROXD_FLAG_TX_CIVIC = 0x00000008, /**< tx civic, if known */
+ WL_PROXD_FLAG_RX_AUTO_BURST = 0x00000010, /**< auto respond w/o host action */
+ WL_PROXD_FLAG_TX_AUTO_BURST = 0x00000020, /**< continue tx w/o host action */
+ WL_PROXD_FLAG_AVAIL_PUBLISH = 0x00000040, /**< publish availability */
+ WL_PROXD_FLAG_AVAIL_SCHEDULE = 0x00000080, /**< schedule using availability */
+ WL_PROXD_FLAG_ASAP_CAPABLE = 0x00000100, /* ASAP capable */
+ WL_PROXD_FLAG_MBURST_FOLLOWUP = 0x00000200, /* new multi-burst algorithm */
+ WL_PROXD_FLAG_SECURE = 0x00000400, /* per bsscfg option */
+ WL_PROXD_FLAG_NO_TSF_SYNC = 0x00000800, /* disable tsf sync */
+ WL_PROXD_FLAG_ALL = 0xffffffff
+};
+typedef uint32 wl_proxd_flags_t;
+
+#define WL_PROXD_FLAGS_AVAIL (WL_PROXD_FLAG_AVAIL_PUBLISH | \
+ WL_PROXD_FLAG_AVAIL_SCHEDULE)
+
+/** session flags */
+enum {
+ WL_PROXD_SESSION_FLAG_NONE = 0x00000000, /**< no flags */
+ WL_PROXD_SESSION_FLAG_INITIATOR = 0x00000001, /**< local device is initiator */
+ WL_PROXD_SESSION_FLAG_TARGET = 0x00000002, /**< local device is target */
+ WL_PROXD_SESSION_FLAG_ONE_WAY = 0x00000004, /**< (initiated) 1-way rtt */
+ WL_PROXD_SESSION_FLAG_AUTO_BURST = 0x00000008, /**< created w/ rx_auto_burst */
+ WL_PROXD_SESSION_FLAG_MBURST_NODELAY = 0x00000010, /**< good until cancelled */
+ WL_PROXD_SESSION_FLAG_RTT_DETAIL = 0x00000020, /**< rtt detail in results */
+ WL_PROXD_SESSION_FLAG_SECURE = 0x00000040, /**< sessionis secure */
+ WL_PROXD_SESSION_FLAG_AOA = 0x00000080, /**< AOA along w/ RTT */
+ WL_PROXD_SESSION_FLAG_RX_AUTO_BURST = 0x00000100, /**< Same as proxd flags above */
+ WL_PROXD_SESSION_FLAG_TX_AUTO_BURST = 0x00000200, /**< Same as proxd flags above */
+ WL_PROXD_SESSION_FLAG_NAN_BSS = 0x00000400, /**< Use NAN BSS, if applicable */
+ WL_PROXD_SESSION_FLAG_TS1 = 0x00000800, /**< e.g. FTM1 - ASAP-capable */
+ WL_PROXD_SESSION_FLAG_REPORT_FAILURE = 0x00002000, /**< report failure to target */
+ WL_PROXD_SESSION_FLAG_INITIATOR_RPT = 0x00004000, /**< report distance to target */
+ WL_PROXD_SESSION_FLAG_NOCHANSWT = 0x00008000,
+ WL_PROXD_SESSION_FLAG_NETRUAL = 0x00010000, /**< netrual mode */
+ WL_PROXD_SESSION_FLAG_SEQ_EN = 0x00020000, /**< Toast */
+ WL_PROXD_SESSION_FLAG_NO_PARAM_OVRD = 0x00040000, /**< no param override from target */
+ WL_PROXD_SESSION_FLAG_ASAP = 0x00080000, /**< ASAP session */
+ WL_PROXD_SESSION_FLAG_REQ_LCI = 0x00100000, /**< transmit LCI req */
+ WL_PROXD_SESSION_FLAG_REQ_CIV = 0x00200000, /**< transmit civic loc req */
+ WL_PROXD_SESSION_FLAG_PRE_SCAN = 0x00400000, /* enable pre-scan for asap=1 */
+ WL_PROXD_SESSION_FLAG_AUTO_VHTACK = 0x00800000, /* use vhtack based on brcm ie */
+ WL_PROXD_SESSION_FLAG_VHTACK = 0x01000000, /* vht ack is in use - output only */
+ WL_PROXD_SESSION_FLAG_BDUR_NOPREF = 0x02000000, /* burst-duration: no preference */
+ WL_PROXD_SESSION_FLAG_NUM_FTM_NOPREF = 0x04000000, /* num of FTM frames: no preference */
+ WL_PROXD_SESSION_FLAG_FTM_SEP_NOPREF = 0x08000000, /* time btw FTM frams: no pref */
+ WL_PROXD_SESSION_FLAG_NUM_BURST_NOPREF = 0x10000000, /* num of bursts: no pref */
+ WL_PROXD_SESSION_FLAG_BURST_PERIOD_NOPREF = 0x20000000, /* burst period: no pref */
+ WL_PROXD_SESSION_FLAG_MBURST_FOLLOWUP = 0x40000000, /* new mburst algo - reserved */
+ WL_PROXD_SESSION_FLAG_UNUSED_BIT31 = 0x80000000,
+ WL_PROXD_SESSION_FLAG_ALL = 0xffffffff
+};
+typedef uint32 wl_proxd_session_flags_t;
+
+/** time units - mc supports up to 0.1ns resolution */
+enum {
+ WL_PROXD_TMU_TU = 0, /**< 1024us */
+ WL_PROXD_TMU_SEC = 1,
+ WL_PROXD_TMU_MILLI_SEC = 2,
+ WL_PROXD_TMU_MICRO_SEC = 3,
+ WL_PROXD_TMU_NANO_SEC = 4,
+ WL_PROXD_TMU_PICO_SEC = 5
+};
+typedef int16 wl_proxd_tmu_t;
+
+/** time interval e.g. 10ns */
+typedef struct wl_proxd_intvl {
+ uint32 intvl;
+ wl_proxd_tmu_t tmu;
+ uint8 pad[2];
+} wl_proxd_intvl_t;
+
+/** commands that can apply to proxd, method or a session */
+enum {
+ WL_PROXD_CMD_NONE = 0,
+ WL_PROXD_CMD_GET_VERSION = 1,
+ WL_PROXD_CMD_ENABLE = 2,
+ WL_PROXD_CMD_DISABLE = 3,
+ WL_PROXD_CMD_CONFIG = 4,
+ WL_PROXD_CMD_START_SESSION = 5,
+ WL_PROXD_CMD_BURST_REQUEST = 6,
+ WL_PROXD_CMD_STOP_SESSION = 7,
+ WL_PROXD_CMD_DELETE_SESSION = 8,
+ WL_PROXD_CMD_GET_RESULT = 9,
+ WL_PROXD_CMD_GET_INFO = 10,
+ WL_PROXD_CMD_GET_STATUS = 11,
+ WL_PROXD_CMD_GET_SESSIONS = 12,
+ WL_PROXD_CMD_GET_COUNTERS = 13,
+ WL_PROXD_CMD_CLEAR_COUNTERS = 14,
+ WL_PROXD_CMD_COLLECT = 15, /* not supported, see 'wl proxd_collect' */
+ WL_PROXD_CMD_TUNE = 16, /* not supported, see 'wl proxd_tune' */
+ WL_PROXD_CMD_DUMP = 17,
+ WL_PROXD_CMD_START_RANGING = 18,
+ WL_PROXD_CMD_STOP_RANGING = 19,
+ WL_PROXD_CMD_GET_RANGING_INFO = 20,
+ WL_PROXD_CMD_IS_TLV_SUPPORTED = 21,
+
+ WL_PROXD_CMD_MAX
+};
+typedef int16 wl_proxd_cmd_t;
+
+/* session ids:
+ * id 0 is reserved
+ * ids 1..0x7fff - allocated by host/app
+ * 0x8000-0xffff - allocated by firmware, used for auto/rx
+ */
+enum {
+ WL_PROXD_SESSION_ID_GLOBAL = 0
+};
+
+/* Externally allocated sids */
+#define WL_PROXD_SID_EXT_MAX 0x7fff
+#define WL_PROXD_SID_EXT_ALLOC(_sid) ((_sid) > 0 && (_sid) <= WL_PROXD_SID_EXT_MAX)
+
+/* block size for reserved sid blocks */
+#define WL_PROXD_SID_EXT_BLKSZ 256
+#define WL_PROXD_SID_EXT_BLK_START(_i) (WL_PROXD_SID_EXT_MAX - (_i) * WL_PROXD_SID_EXT_BLKSZ + 1)
+#define WL_PROXD_SID_EXT_BLK_END(_start) ((_start) + WL_PROXD_SID_EXT_BLKSZ - 1)
+
+/* rrm block */
+#define WL_PROXD_SID_RRM_START WL_PROXD_SID_EXT_BLK_START(1)
+#define WL_PROXD_SID_RRM_END WL_PROXD_SID_EXT_BLK_END(WL_PROXD_SID_RRM_START)
+
+/* nan block */
+#define WL_PROXD_SID_NAN_START WL_PROXD_SID_EXT_BLK_START(2)
+#define WL_PROXD_SID_NAN_END WL_PROXD_SID_EXT_BLK_END(WL_PROXD_SID_NAN_START)
+
+/** maximum number sessions that can be allocated, may be less if tunable */
+#define WL_PROXD_MAX_SESSIONS 16
+
+typedef uint16 wl_proxd_session_id_t;
+
+/** status - TBD BCME_ vs proxd status - range reserved for BCME_ */
+enum {
+ WL_PROXD_E_NOAVAIL = -1056,
+ WL_PROXD_E_EXT_SCHED = -1055,
+ WL_PROXD_E_NOT_BCM = -1054,
+ WL_PROXD_E_FRAME_TYPE = -1053,
+ WL_PROXD_E_VERNOSUPPORT = -1052,
+ WL_PROXD_E_SEC_NOKEY = -1051,
+ WL_PROXD_E_SEC_POLICY = -1050,
+ WL_PROXD_E_SCAN_INPROCESS = -1049,
+ WL_PROXD_E_BAD_PARTIAL_TSF = -1048,
+ WL_PROXD_E_SCANFAIL = -1047,
+ WL_PROXD_E_NOTSF = -1046,
+ WL_PROXD_E_POLICY = -1045,
+ WL_PROXD_E_INCOMPLETE = -1044,
+ WL_PROXD_E_OVERRIDDEN = -1043,
+ WL_PROXD_E_ASAP_FAILED = -1042,
+ WL_PROXD_E_NOTSTARTED = -1041,
+ WL_PROXD_E_INVALIDMEAS = -1040,
+ WL_PROXD_E_INCAPABLE = -1039,
+ WL_PROXD_E_MISMATCH = -1038,
+ WL_PROXD_E_DUP_SESSION = -1037,
+ WL_PROXD_E_REMOTE_FAIL = -1036,
+ WL_PROXD_E_REMOTE_INCAPABLE = -1035,
+ WL_PROXD_E_SCHED_FAIL = -1034,
+ WL_PROXD_E_PROTO = -1033,
+ WL_PROXD_E_EXPIRED = -1032,
+ WL_PROXD_E_TIMEOUT = -1031,
+ WL_PROXD_E_NOACK = -1030,
+ WL_PROXD_E_DEFERRED = -1029,
+ WL_PROXD_E_INVALID_SID = -1028,
+ WL_PROXD_E_REMOTE_CANCEL = -1027,
+ WL_PROXD_E_CANCELED = -1026, /**< local */
+ WL_PROXD_E_INVALID_SESSION = -1025,
+ WL_PROXD_E_BAD_STATE = -1024,
+ WL_PROXD_E_ERROR = -1,
+ WL_PROXD_E_OK = 0
+};
+typedef int32 wl_proxd_status_t;
+
+/* proxd errors from phy */
+#define PROXD_TOF_INIT_ERR_BITS 16
+
+enum {
+ WL_PROXD_PHY_ERR_LB_CORR_THRESH = (1 << 0), /* Loopback Correlation threshold */
+ WL_PROXD_PHY_ERR_RX_CORR_THRESH = (1 << 1), /* Received Correlation threshold */
+ WL_PROXD_PHY_ERR_LB_PEAK_POWER = (1 << 2), /* Loopback Peak power */
+ WL_PROXD_PHY_ERR_RX_PEAK_POWER = (1 << 3), /* Received Peak power */
+ WL_PROXD_PHY_ERR_BITFLIP = (1 << 4), /* Bitflips */
+ WL_PROXD_PHY_ERR_SNR = (1 << 5), /* SNR */
+ WL_PROXD_PHY_RX_STRT_WIN_OFF = (1 << 6), /* Receive start window is off */
+ WL_PROXD_PHY_RX_END_WIN_OFF = (1 << 7), /* Receive End window is off */
+ WL_PROXD_PHY_ERR_LOW_CONFIDENCE = (1 << 15), /* Low confidence on meas distance */
+};
+typedef uint32 wl_proxd_phy_error_t;
+
+/** session states */
+enum {
+ WL_PROXD_SESSION_STATE_NONE = 0,
+ WL_PROXD_SESSION_STATE_CREATED = 1,
+ WL_PROXD_SESSION_STATE_CONFIGURED = 2,
+ WL_PROXD_SESSION_STATE_STARTED = 3,
+ WL_PROXD_SESSION_STATE_DELAY = 4,
+ WL_PROXD_SESSION_STATE_USER_WAIT = 5,
+ WL_PROXD_SESSION_STATE_SCHED_WAIT = 6,
+ WL_PROXD_SESSION_STATE_BURST = 7,
+ WL_PROXD_SESSION_STATE_STOPPING = 8,
+ WL_PROXD_SESSION_STATE_ENDED = 9,
+ WL_PROXD_SESSION_STATE_START_WAIT = 10,
+ WL_PROXD_SESSION_STATE_DESTROYING = -1
+};
+typedef int16 wl_proxd_session_state_t;
+
+/** RTT sample flags */
+enum {
+ WL_PROXD_RTT_SAMPLE_NONE = 0x00,
+ WL_PROXD_RTT_SAMPLE_DISCARD = 0x01
+};
+typedef uint8 wl_proxd_rtt_sample_flags_t;
+typedef int16 wl_proxd_rssi_t;
+typedef uint16 wl_proxd_snr_t;
+typedef uint16 wl_proxd_bitflips_t;
+
+typedef struct wl_proxd_rtt_sample {
+ uint8 id; /**< id for the sample - non-zero */
+ wl_proxd_rtt_sample_flags_t flags;
+ wl_proxd_rssi_t rssi;
+ wl_proxd_intvl_t rtt; /**< round trip time */
+ uint32 ratespec;
+ wl_proxd_snr_t snr;
+ wl_proxd_bitflips_t bitflips;
+ wl_proxd_status_t status;
+ int32 distance;
+ wl_proxd_phy_error_t tof_phy_error;
+ uint8 coreid;
+} wl_proxd_rtt_sample_t;
+
+/** result flags */
+enum {
+ WL_PRXOD_RESULT_FLAG_NONE = 0x0000,
+ WL_PROXD_RESULT_FLAG_NLOS = 0x0001, /**< LOS - if available */
+ WL_PROXD_RESULT_FLAG_LOS = 0x0002, /**< NLOS - if available */
+ WL_PROXD_RESULT_FLAG_FATAL = 0x0004, /**< Fatal error during burst */
+ WL_PROXD_RESULT_FLAG_VHTACK = 0x0008, /* VHTACK or Legacy ACK used */
+ WL_PROXD_REQUEST_SENT = 0x0010, /* FTM request was sent */
+ WL_PROXD_REQUEST_ACKED = 0x0020, /* FTM request was acked */
+ WL_PROXD_LTFSEQ_STARTED = 0x0040, /* LTF sequence started */
+ WL_PROXD_RESULT_FLAG_ALL = 0xffff
+};
+typedef int16 wl_proxd_result_flags_t;
+
+/** rtt measurement result */
+typedef struct wl_proxd_rtt_result {
+ wl_proxd_session_id_t sid;
+ wl_proxd_result_flags_t flags;
+ wl_proxd_status_t status;
+ struct ether_addr peer;
+ wl_proxd_session_state_t state; /**< current state */
+ union {
+ wl_proxd_intvl_t retry_after; /* hint for errors */
+ wl_proxd_intvl_t burst_duration; /* burst duration */
+ } u;
+ wl_proxd_rtt_sample_t avg_rtt;
+ uint32 avg_dist; /* 1/256m units */
+ uint16 sd_rtt; /* RTT standard deviation */
+ uint8 num_valid_rtt; /* valid rtt cnt */
+ uint8 num_ftm; /* actual num of ftm cnt (Configured) */
+ uint16 burst_num; /* in a session */
+ uint16 num_rtt; /* 0 if no detail */
+ uint16 num_meas; /* number of ftm frames seen OTA */
+ uint8 pad[2];
+ wl_proxd_rtt_sample_t rtt[1]; /* variable */
+} wl_proxd_rtt_result_t;
+
+/** aoa measurement result */
+typedef struct wl_proxd_aoa_result {
+ wl_proxd_session_id_t sid;
+ wl_proxd_result_flags_t flags;
+ wl_proxd_status_t status;
+ struct ether_addr peer;
+ wl_proxd_session_state_t state;
+ uint16 burst_num;
+ uint8 pad[2];
+ /* wl_proxd_aoa_sample_t sample_avg; TBD */
+} BWL_POST_PACKED_STRUCT wl_proxd_aoa_result_t;
+#include <packed_section_end.h>
+
+/** global stats */
+typedef struct wl_proxd_counters {
+ uint32 tx; /**< tx frame count */
+ uint32 rx; /**< rx frame count */
+ uint32 burst; /**< total number of burst */
+ uint32 sessions; /**< total number of sessions */
+ uint32 max_sessions; /**< max concurrency */
+ uint32 sched_fail; /**< scheduling failures */
+ uint32 timeouts; /**< timeouts */
+ uint32 protoerr; /**< protocol errors */
+ uint32 noack; /**< tx w/o ack */
+ uint32 txfail; /**< any tx falure */
+ uint32 lci_req_tx; /**< tx LCI requests */
+ uint32 lci_req_rx; /**< rx LCI requests */
+ uint32 lci_rep_tx; /**< tx LCI reports */
+ uint32 lci_rep_rx; /**< rx LCI reports */
+ uint32 civic_req_tx; /**< tx civic requests */
+ uint32 civic_req_rx; /**< rx civic requests */
+ uint32 civic_rep_tx; /**< tx civic reports */
+ uint32 civic_rep_rx; /**< rx civic reports */
+ uint32 rctx; /**< ranging contexts created */
+ uint32 rctx_done; /**< count of ranging done */
+ uint32 publish_err; /**< availability publishing errors */
+ uint32 on_chan; /**< count of scheduler onchan */
+ uint32 off_chan; /**< count of scheduler offchan */
+ uint32 tsf_lo; /* local tsf or session tsf */
+ uint32 tsf_hi;
+ uint32 num_meas;
+} wl_proxd_counters_t;
+
+typedef struct wl_proxd_counters wl_proxd_session_counters_t;
+
+enum {
+ WL_PROXD_CAP_NONE = 0x0000,
+ WL_PROXD_CAP_ALL = 0xffff
+};
+typedef int16 wl_proxd_caps_t;
+
+/** method capabilities */
+enum {
+ WL_PROXD_FTM_CAP_NONE = 0x0000,
+ WL_PROXD_FTM_CAP_FTM1 = 0x0001
+};
+typedef uint16 wl_proxd_ftm_caps_t;
+
+typedef struct wl_proxd_tlv_id_list {
+ uint16 num_ids;
+ uint16 ids[1];
+} wl_proxd_tlv_id_list_t;
+
+typedef struct wl_proxd_session_id_list {
+ uint16 num_ids;
+ wl_proxd_session_id_t ids[1];
+} wl_proxd_session_id_list_t;
+
+typedef struct wl_proxd_tpk {
+ struct ether_addr peer;
+ uint8 tpk[TPK_FTM_LEN];
+} wl_proxd_tpk_t;
+
+/* tlvs returned for get_info on ftm method
+ * configuration:
+ * proxd flags
+ * event mask
+ * debug mask
+ * session defaults (session tlvs)
+ * status tlv - not supported for ftm method
+ * info tlv
+ */
+typedef struct wl_proxd_ftm_info {
+ wl_proxd_ftm_caps_t caps;
+ uint16 max_sessions;
+ uint16 num_sessions;
+ uint16 rx_max_burst;
+} wl_proxd_ftm_info_t;
+
+enum {
+ WL_PROXD_WAIT_NONE = 0x0000,
+ WL_PROXD_WAIT_KEY = 0x0001,
+ WL_PROXD_WAIT_SCHED = 0x0002,
+ WL_PROXD_WAIT_TSF = 0x0004
+};
+typedef int16 wl_proxd_wait_reason_t;
+
+/* tlvs returned for get_info on session
+ * session config (tlvs)
+ * session info tlv
+ */
+typedef struct wl_proxd_ftm_session_info {
+ uint16 sid;
+ uint8 bss_index;
+ uint8 pad;
+ struct ether_addr bssid;
+ wl_proxd_session_state_t state;
+ wl_proxd_status_t status;
+ uint16 burst_num;
+ wl_proxd_wait_reason_t wait_reason;
+ uint32 meas_start_lo; /* sn tsf of 1st meas for cur/prev burst */
+ uint32 meas_start_hi;
+} wl_proxd_ftm_session_info_t;
+
+typedef struct wl_proxd_ftm_session_status {
+ uint16 sid;
+ wl_proxd_session_state_t state;
+ wl_proxd_status_t status;
+ uint16 burst_num;
+ uint16 pad;
+} wl_proxd_ftm_session_status_t;
+
+/** rrm range request */
+typedef struct wl_proxd_range_req {
+ uint16 num_repeat;
+ uint16 init_delay_range; /**< in TUs */
+ uint8 pad;
+ uint8 num_nbr; /**< number of (possible) neighbors */
+ nbr_element_t nbr[1];
+} wl_proxd_range_req_t;
+
+#define WL_PROXD_LCI_LAT_OFF 0
+#define WL_PROXD_LCI_LONG_OFF 5
+#define WL_PROXD_LCI_ALT_OFF 10
+
+#define WL_PROXD_LCI_GET_LAT(_lci, _lat, _lat_err) { \
+ unsigned _off = WL_PROXD_LCI_LAT_OFF; \
+ _lat_err = (_lci)->data[(_off)] & 0x3f; \
+ _lat = (_lci)->data[(_off)+1]; \
+ _lat |= (_lci)->data[(_off)+2] << 8; \
+ _lat |= (_lci)->data[_(_off)+3] << 16; \
+ _lat |= (_lci)->data[(_off)+4] << 24; \
+ _lat <<= 2; \
+ _lat |= (_lci)->data[(_off)] >> 6; \
+}
+
+#define WL_PROXD_LCI_GET_LONG(_lci, _lcilong, _long_err) { \
+ unsigned _off = WL_PROXD_LCI_LONG_OFF; \
+ _long_err = (_lci)->data[(_off)] & 0x3f; \
+ _lcilong = (_lci)->data[(_off)+1]; \
+ _lcilong |= (_lci)->data[(_off)+2] << 8; \
+ _lcilong |= (_lci)->data[_(_off)+3] << 16; \
+ _lcilong |= (_lci)->data[(_off)+4] << 24; \
+ __lcilong <<= 2; \
+ _lcilong |= (_lci)->data[(_off)] >> 6; \
+}
+
+#define WL_PROXD_LCI_GET_ALT(_lci, _alt_type, _alt, _alt_err) { \
+ unsigned _off = WL_PROXD_LCI_ALT_OFF; \
+ _alt_type = (_lci)->data[_off] & 0x0f; \
+ _alt_err = (_lci)->data[(_off)] >> 4; \
+ _alt_err |= ((_lci)->data[(_off)+1] & 0x03) << 4; \
+ _alt = (_lci)->data[(_off)+2]; \
+ _alt |= (_lci)->data[(_off)+3] << 8; \
+ _alt |= (_lci)->data[_(_off)+4] << 16; \
+ _alt <<= 6; \
+ _alt |= (_lci)->data[(_off) + 1] >> 2; \
+}
+
+#define WL_PROXD_LCI_VERSION(_lci) ((_lci)->data[15] >> 6)
+
+/* availability. advertising mechanism bss specific */
+/** availablity flags */
+enum {
+ WL_PROXD_AVAIL_NONE = 0,
+ WL_PROXD_AVAIL_NAN_PUBLISHED = 0x0001,
+ WL_PROXD_AVAIL_SCHEDULED = 0x0002 /**< scheduled by proxd */
+};
+typedef int16 wl_proxd_avail_flags_t;
+
+/** time reference */
+enum {
+ WL_PROXD_TREF_NONE = 0,
+ WL_PROXD_TREF_DEV_TSF = 1,
+ WL_PROXD_TREF_NAN_DW = 2,
+ WL_PROXD_TREF_TBTT = 3,
+ WL_PROXD_TREF_MAX /* last entry */
+};
+typedef int16 wl_proxd_time_ref_t;
+
+/** proxd channel-time slot */
+typedef struct {
+ wl_proxd_intvl_t start; /**< from ref */
+ wl_proxd_intvl_t duration; /**< from start */
+ uint32 chanspec;
+} wl_proxd_time_slot_t;
+
+typedef struct wl_proxd_avail24 {
+ wl_proxd_avail_flags_t flags; /**< for query only */
+ wl_proxd_time_ref_t time_ref;
+ uint16 max_slots; /**< for query only */
+ uint16 num_slots;
+ wl_proxd_time_slot_t slots[1]; /**< ROM compat - not used */
+ wl_proxd_intvl_t repeat;
+ wl_proxd_time_slot_t ts0[1];
+} wl_proxd_avail24_t;
+#define WL_PROXD_AVAIL24_TIMESLOT(_avail24, _i) (&(_avail24)->ts0[(_i)])
+#define WL_PROXD_AVAIL24_TIMESLOT_OFFSET(_avail24) OFFSETOF(wl_proxd_avail24_t, ts0)
+#define WL_PROXD_AVAIL24_TIMESLOTS(_avail24) WL_PROXD_AVAIL24_TIMESLOT(_avail24, 0)
+#define WL_PROXD_AVAIL24_SIZE(_avail24, _num_slots) (\
+ WL_PROXD_AVAIL24_TIMESLOT_OFFSET(_avail24) + \
+ (_num_slots) * sizeof(*WL_PROXD_AVAIL24_TIMESLOT(_avail24, 0)))
+
+typedef struct wl_proxd_avail {
+ wl_proxd_avail_flags_t flags; /**< for query only */
+ wl_proxd_time_ref_t time_ref;
+ uint16 max_slots; /**< for query only */
+ uint16 num_slots;
+ wl_proxd_intvl_t repeat;
+ wl_proxd_time_slot_t slots[1];
+} wl_proxd_avail_t;
+#define WL_PROXD_AVAIL_TIMESLOT(_avail, _i) (&(_avail)->slots[(_i)])
+#define WL_PROXD_AVAIL_TIMESLOT_OFFSET(_avail) OFFSETOF(wl_proxd_avail_t, slots)
+
+#define WL_PROXD_AVAIL_TIMESLOTS(_avail) WL_PROXD_AVAIL_TIMESLOT(_avail, 0)
+#define WL_PROXD_AVAIL_SIZE(_avail, _num_slots) (\
+ WL_PROXD_AVAIL_TIMESLOT_OFFSET(_avail) + \
+ (_num_slots) * sizeof(*WL_PROXD_AVAIL_TIMESLOT(_avail, 0)))
+
+/* collect support TBD */
+
+/** debugging */
+enum {
+ WL_PROXD_DEBUG_NONE = 0x00000000,
+ WL_PROXD_DEBUG_LOG = 0x00000001,
+ WL_PROXD_DEBUG_IOV = 0x00000002,
+ WL_PROXD_DEBUG_EVENT = 0x00000004,
+ WL_PROXD_DEBUG_SESSION = 0x00000008,
+ WL_PROXD_DEBUG_PROTO = 0x00000010,
+ WL_PROXD_DEBUG_SCHED = 0x00000020,
+ WL_PROXD_DEBUG_RANGING = 0x00000040,
+ WL_PROXD_DEBUG_NAN = 0x00000080,
+ WL_PROXD_DEBUG_PKT = 0x00000100,
+ WL_PROXD_DEBUG_SEC = 0x00000200,
+ WL_PROXD_DEBUG_EVENTLOG = 0x80000000, /* map/enable EVNET_LOG_TAG_PROXD_INFO */
+ WL_PROXD_DEBUG_ALL = 0xffffffff
+};
+typedef uint32 wl_proxd_debug_mask_t;
+
+/** tlv IDs - data length 4 bytes unless overridden by type, alignment 32 bits */
+enum {
+ WL_PROXD_TLV_ID_NONE = 0,
+ WL_PROXD_TLV_ID_METHOD = 1,
+ WL_PROXD_TLV_ID_FLAGS = 2,
+ WL_PROXD_TLV_ID_CHANSPEC = 3, /**< note: uint32 */
+ WL_PROXD_TLV_ID_TX_POWER = 4,
+ WL_PROXD_TLV_ID_RATESPEC = 5,
+ WL_PROXD_TLV_ID_BURST_DURATION = 6, /**< intvl - length of burst */
+ WL_PROXD_TLV_ID_BURST_PERIOD = 7, /**< intvl - between bursts */
+ WL_PROXD_TLV_ID_BURST_FTM_SEP = 8, /**< intvl - between FTMs */
+ WL_PROXD_TLV_ID_BURST_NUM_FTM = 9, /**< uint16 - per burst */
+ WL_PROXD_TLV_ID_NUM_BURST = 10, /**< uint16 */
+ WL_PROXD_TLV_ID_FTM_RETRIES = 11, /**< uint16 at FTM level */
+ WL_PROXD_TLV_ID_BSS_INDEX = 12, /**< uint8 */
+ WL_PROXD_TLV_ID_BSSID = 13,
+ WL_PROXD_TLV_ID_INIT_DELAY = 14, /**< intvl - optional,non-standalone only */
+ WL_PROXD_TLV_ID_BURST_TIMEOUT = 15, /**< expect response within - intvl */
+ WL_PROXD_TLV_ID_EVENT_MASK = 16, /**< interested events - in/out */
+ WL_PROXD_TLV_ID_FLAGS_MASK = 17, /**< interested flags - in only */
+ WL_PROXD_TLV_ID_PEER_MAC = 18, /**< mac address of peer */
+ WL_PROXD_TLV_ID_FTM_REQ = 19, /**< dot11_ftm_req */
+ WL_PROXD_TLV_ID_LCI_REQ = 20,
+ WL_PROXD_TLV_ID_LCI = 21,
+ WL_PROXD_TLV_ID_CIVIC_REQ = 22,
+ WL_PROXD_TLV_ID_CIVIC = 23,
+ WL_PROXD_TLV_ID_AVAIL24 = 24, /**< ROM compatibility */
+ WL_PROXD_TLV_ID_SESSION_FLAGS = 25,
+ WL_PROXD_TLV_ID_SESSION_FLAGS_MASK = 26, /**< in only */
+ WL_PROXD_TLV_ID_RX_MAX_BURST = 27, /**< uint16 - limit bursts per session */
+ WL_PROXD_TLV_ID_RANGING_INFO = 28, /**< ranging info */
+ WL_PROXD_TLV_ID_RANGING_FLAGS = 29, /**< uint16 */
+ WL_PROXD_TLV_ID_RANGING_FLAGS_MASK = 30, /**< uint16, in only */
+ WL_PROXD_TLV_ID_NAN_MAP_ID = 31,
+ WL_PROXD_TLV_ID_DEV_ADDR = 32,
+ WL_PROXD_TLV_ID_AVAIL = 33, /**< wl_proxd_avail_t */
+ WL_PROXD_TLV_ID_TLV_ID = 34, /* uint16 tlv-id */
+ WL_PROXD_TLV_ID_FTM_REQ_RETRIES = 35, /* uint16 FTM request retries */
+ WL_PROXD_TLV_ID_TPK = 36, /* 32byte TPK */
+ WL_PROXD_TLV_ID_RI_RR = 36, /* RI_RR */
+ WL_PROXD_TLV_ID_TUNE = 37, /* wl_proxd_pararms_tof_tune_t */
+
+ /* output - 512 + x */
+ WL_PROXD_TLV_ID_STATUS = 512,
+ WL_PROXD_TLV_ID_COUNTERS = 513,
+ WL_PROXD_TLV_ID_INFO = 514,
+ WL_PROXD_TLV_ID_RTT_RESULT = 515,
+ WL_PROXD_TLV_ID_AOA_RESULT = 516,
+ WL_PROXD_TLV_ID_SESSION_INFO = 517,
+ WL_PROXD_TLV_ID_SESSION_STATUS = 518,
+ WL_PROXD_TLV_ID_SESSION_ID_LIST = 519,
+
+ /* debug tlvs can be added starting 1024 */
+ WL_PROXD_TLV_ID_DEBUG_MASK = 1024,
+ WL_PROXD_TLV_ID_COLLECT = 1025, /**< output only */
+ WL_PROXD_TLV_ID_STRBUF = 1026,
+
+ WL_PROXD_TLV_ID_COLLECT_HEADER = 1025, /* wl_proxd_collect_header_t */
+ WL_PROXD_TLV_ID_COLLECT_INFO = 1028, /* wl_proxd_collect_info_t */
+ WL_PROXD_TLV_ID_COLLECT_DATA = 1029, /* wl_proxd_collect_data_t */
+ WL_PROXD_TLV_ID_COLLECT_CHAN_DATA = 1030, /* wl_proxd_collect_data_t */
+
+ WL_PROXD_TLV_ID_MAX
+};
+
+typedef struct wl_proxd_tlv {
+ uint16 id;
+ uint16 len;
+ uint8 data[1];
+} wl_proxd_tlv_t;
+
+/** proxd iovar - applies to proxd, method or session */
+typedef struct wl_proxd_iov {
+ uint16 version;
+ uint16 len;
+ wl_proxd_cmd_t cmd;
+ wl_proxd_method_t method;
+ wl_proxd_session_id_t sid;
+ uint8 pad[2];
+ wl_proxd_tlv_t tlvs[1]; /**< variable */
+} wl_proxd_iov_t;
+
+#define WL_PROXD_IOV_HDR_SIZE OFFSETOF(wl_proxd_iov_t, tlvs)
+
+/* The following event definitions may move to bcmevent.h, but sharing proxd types
+ * across needs more invasive changes unrelated to proxd
+ */
+enum {
+ WL_PROXD_EVENT_NONE = 0, /**< not an event, reserved */
+ WL_PROXD_EVENT_SESSION_CREATE = 1,
+ WL_PROXD_EVENT_SESSION_START = 2,
+ WL_PROXD_EVENT_FTM_REQ = 3,
+ WL_PROXD_EVENT_BURST_START = 4,
+ WL_PROXD_EVENT_BURST_END = 5,
+ WL_PROXD_EVENT_SESSION_END = 6,
+ WL_PROXD_EVENT_SESSION_RESTART = 7,
+ WL_PROXD_EVENT_BURST_RESCHED = 8, /**< burst rescheduled-e.g. partial TSF */
+ WL_PROXD_EVENT_SESSION_DESTROY = 9,
+ WL_PROXD_EVENT_RANGE_REQ = 10,
+ WL_PROXD_EVENT_FTM_FRAME = 11,
+ WL_PROXD_EVENT_DELAY = 12,
+ WL_PROXD_EVENT_VS_INITIATOR_RPT = 13, /**< (target) rx initiator-report */
+ WL_PROXD_EVENT_RANGING = 14,
+ WL_PROXD_EVENT_LCI_MEAS_REP = 15, /* LCI measurement report */
+ WL_PROXD_EVENT_CIVIC_MEAS_REP = 16, /* civic measurement report */
+ WL_PROXD_EVENT_COLLECT = 17,
+ WL_PROXD_EVENT_START_WAIT = 18, /* waiting to start */
+
+ WL_PROXD_EVENT_MAX
+};
+typedef int16 wl_proxd_event_type_t;
+
+/** proxd event mask - upto 32 events for now */
+typedef uint32 wl_proxd_event_mask_t;
+
+#define WL_PROXD_EVENT_MASK_ALL 0xfffffffe
+#define WL_PROXD_EVENT_MASK_EVENT(_event_type) (1 << (_event_type))
+#define WL_PROXD_EVENT_ENABLED(_mask, _event_type) (\
+ ((_mask) & WL_PROXD_EVENT_MASK_EVENT(_event_type)) != 0)
+
+/** proxd event - applies to proxd, method or session */
+typedef struct wl_proxd_event {
+ uint16 version;
+ uint16 len;
+ wl_proxd_event_type_t type;
+ wl_proxd_method_t method;
+ wl_proxd_session_id_t sid;
+ uint8 pad[2];
+ wl_proxd_tlv_t tlvs[1]; /**< variable */
+} wl_proxd_event_t;
+
+enum {
+ WL_PROXD_RANGING_STATE_NONE = 0,
+ WL_PROXD_RANGING_STATE_NOTSTARTED = 1,
+ WL_PROXD_RANGING_STATE_INPROGRESS = 2,
+ WL_PROXD_RANGING_STATE_DONE = 3
+};
+typedef int16 wl_proxd_ranging_state_t;
+
+/** proxd ranging flags */
+enum {
+ WL_PROXD_RANGING_FLAG_NONE = 0x0000, /**< no flags */
+ WL_PROXD_RANGING_FLAG_DEL_SESSIONS_ON_STOP = 0x0001,
+ WL_PROXD_RANGING_FLAG_ALL = 0xffff
+};
+typedef uint16 wl_proxd_ranging_flags_t;
+
+struct wl_proxd_ranging_info {
+ wl_proxd_status_t status;
+ wl_proxd_ranging_state_t state;
+ wl_proxd_ranging_flags_t flags;
+ uint16 num_sids;
+ uint16 num_done;
+};
+typedef struct wl_proxd_ranging_info wl_proxd_ranging_info_t;
+
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_event_data {
+ uint32 H_LB[K_TOF_COLLECT_H_SIZE_20MHZ];
+ uint32 H_RX[K_TOF_COLLECT_H_SIZE_20MHZ];
+ uint8 ri_rr[FTM_TPK_LEN];
+ wl_proxd_phy_error_t phy_err_mask;
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_event_data_t;
+#include <packed_section_end.h>
+
+/** Data returned by the bssload_report iovar. This is also the WLC_E_BSS_LOAD event data */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct wl_bssload {
+ uint16 sta_count; /**< station count */
+ uint16 aac; /**< available admission capacity */
+ uint8 chan_util; /**< channel utilization */
+} BWL_POST_PACKED_STRUCT wl_bssload_t;
+#include <packed_section_end.h>
+
+/**
+ * Maximum number of configurable BSS Load levels. The number of BSS Load
+ * ranges is always 1 more than the number of configured levels. eg. if
+ * 3 levels of 10, 20, 30 are configured then this defines 4 load ranges:
+ * 0-10, 11-20, 21-30, 31-255. A WLC_E_BSS_LOAD event is generated each time
+ * the utilization level crosses into another range, subject to the rate limit.
+ */
+#define MAX_BSSLOAD_LEVELS 8
+#define MAX_BSSLOAD_RANGES (MAX_BSSLOAD_LEVELS + 1)
+
+/** BSS Load event notification configuration. */
+typedef struct wl_bssload_cfg {
+ uint32 rate_limit_msec; /**< # of events posted to application will be limited to
+ * one per specified period (0 to disable rate limit).
+ */
+ uint8 num_util_levels; /**< Number of entries in util_levels[] below */
+ uint8 util_levels[MAX_BSSLOAD_LEVELS];
+ /**< Variable number of BSS Load utilization levels in
+ * low to high order. An event will be posted each time
+ * a received beacon's BSS Load IE channel utilization
+ * value crosses a level.
+ */
+} wl_bssload_cfg_t;
+
+/** Multiple roaming profile suport */
+#define WL_MAX_ROAM_PROF_BRACKETS 4
+
+#define WL_ROAM_PROF_VER_0 0
+#define WL_ROAM_PROF_VER_1 1
+#define WL_MAX_ROAM_PROF_VER WL_ROAM_PROF_VER_1
+
+#define WL_ROAM_PROF_NONE (0 << 0)
+#define WL_ROAM_PROF_LAZY (1 << 0)
+#define WL_ROAM_PROF_NO_CI (1 << 1)
+#define WL_ROAM_PROF_SUSPEND (1 << 2)
+#define WL_ROAM_PROF_SYNC_DTIM (1 << 6)
+#define WL_ROAM_PROF_DEFAULT (1 << 7) /**< backward compatible single default profile */
+
+#define WL_FACTOR_TABLE_MAX_LIMIT 5
+
+#define WL_CU_2G_ROAM_TRIGGER (-60)
+#define WL_CU_5G_ROAM_TRIGGER (-70)
+
+#define WL_CU_SCORE_DELTA_DEFAULT 20
+
+#define WL_MAX_CHANNEL_USAGE 0x0FF
+#define WL_CU_PERCENTAGE_DISABLE 0
+#define WL_CU_PERCENTAGE_DEFAULT 70
+#define WL_CU_PERCENTAGE_MAX 100
+#define WL_CU_CALC_DURATION_DEFAULT 10 /* seconds */
+#define WL_CU_CALC_DURATION_MAX 60 /* seconds */
+
+typedef struct wl_roam_prof_v2 {
+ int8 roam_flags; /**< bit flags */
+ int8 roam_trigger; /**< RSSI trigger level per profile/RSSI bracket */
+ int8 rssi_lower;
+ int8 roam_delta;
+
+ /* if channel_usage if zero, roam_delta is rssi delta required for new AP */
+ /* if channel_usage if non-zero, roam_delta is score delta(%) required for new AP */
+ int8 rssi_boost_thresh; /**< Min RSSI to qualify for RSSI boost */
+ int8 rssi_boost_delta; /**< RSSI boost for AP in the other band */
+ uint16 nfscan; /**< number of full scan to start with */
+ uint16 fullscan_period;
+ uint16 init_scan_period;
+ uint16 backoff_multiplier;
+ uint16 max_scan_period;
+ uint8 channel_usage;
+ uint8 cu_avg_calc_dur;
+ uint8 pad[2];
+} wl_roam_prof_v2_t;
+
+typedef struct wl_roam_prof_v1 {
+ int8 roam_flags; /**< bit flags */
+ int8 roam_trigger; /**< RSSI trigger level per profile/RSSI bracket */
+ int8 rssi_lower;
+ int8 roam_delta;
+
+ /* if channel_usage if zero, roam_delta is rssi delta required for new AP */
+ /* if channel_usage if non-zero, roam_delta is score delta(%) required for new AP */
+ int8 rssi_boost_thresh; /**< Min RSSI to qualify for RSSI boost */
+ int8 rssi_boost_delta; /**< RSSI boost for AP in the other band */
+ uint16 nfscan; /**< number of full scan to start with */
+ uint16 fullscan_period;
+ uint16 init_scan_period;
+ uint16 backoff_multiplier;
+ uint16 max_scan_period;
+} wl_roam_prof_v1_t;
+
+typedef struct wl_roam_prof_band_v2 {
+ uint32 band; /**< Must be just one band */
+ uint16 ver; /**< version of this struct */
+ uint16 len; /**< length in bytes of this structure */
+ wl_roam_prof_v2_t roam_prof[WL_MAX_ROAM_PROF_BRACKETS];
+} wl_roam_prof_band_v2_t;
+
+typedef struct wl_roam_prof_band_v1 {
+ uint32 band; /**< Must be just one band */
+ uint16 ver; /**< version of this struct */
+ uint16 len; /**< length in bytes of this structure */
+ wl_roam_prof_v1_t roam_prof[WL_MAX_ROAM_PROF_BRACKETS];
+} wl_roam_prof_band_v1_t;
+
+#define BSS_MAXTABLE_SIZE 10
+#define WNM_BSS_SELECT_FACTOR_VERSION 1
+typedef struct wnm_bss_select_factor_params {
+ uint8 low;
+ uint8 high;
+ uint8 factor;
+ uint8 pad;
+} wnm_bss_select_factor_params_t;
+
+#define WNM_BSS_SELECT_FIXED_SIZE OFFSETOF(wnm_bss_select_factor_cfg_t, params)
+typedef struct wnm_bss_select_factor_cfg {
+ uint8 version;
+ uint8 band;
+ uint16 type;
+ uint16 pad;
+ uint16 count;
+ wnm_bss_select_factor_params_t params[1];
+} wnm_bss_select_factor_cfg_t;
+
+#define WNM_BSS_SELECT_WEIGHT_VERSION 1
+typedef struct wnm_bss_select_weight_cfg {
+ uint8 version;
+ uint8 band;
+ uint16 type;
+ uint16 weight; /* weightage for each type between 0 to 100 */
+} wnm_bss_select_weight_cfg_t;
+
+#define WNM_BSS_SELECT_TYPE_RSSI 0
+#define WNM_BSS_SELECT_TYPE_CU 1
+
+#define WNM_BSSLOAD_MONITOR_VERSION 1
+typedef struct wnm_bssload_monitor_cfg {
+ uint8 version;
+ uint8 band;
+ uint8 duration; /* duration between 1 to 20sec */
+} wnm_bssload_monitor_cfg_t;
+
+#define WNM_ROAM_TRIGGER_VERSION 1
+typedef struct wnm_roam_trigger_cfg {
+ uint8 version;
+ uint8 band;
+ uint16 type;
+ int16 trigger; /* trigger for each type in new roam algorithm */
+} wnm_roam_trigger_cfg_t;
+
+/* Data structures for Interface Create/Remove */
+
+#define WL_INTERFACE_CREATE_VER (2)
+
+/*
+ * The flags filed of the wl_interface_create is designed to be
+ * a Bit Mask. As of now only Bit 0 and Bit 1 are used as mentioned below.
+ * The rest of the bits can be used, incase we have to provide
+ * more information to the dongle
+ */
+
+/*
+ * Bit 0 of flags field is used to inform whether the interface requested to
+ * be created is STA or AP.
+ * 0 - Create a STA interface
+ * 1 - Create an AP interface
+ * NOTE: This Bit 0 is applicable for the WL_INTERFACE_CREATE_VER < 2
+ */
+#define WL_INTERFACE_CREATE_STA (0 << 0)
+#define WL_INTERFACE_CREATE_AP (1 << 0)
+
+/*
+ * From revision >= 2 Bit 0 of flags field will not used be for STA or AP interface creation.
+ * "iftype" field shall be used for identifying the interface type.
+ */
+typedef enum wl_interface_type {
+ WL_INTERFACE_TYPE_STA = 0,
+ WL_INTERFACE_TYPE_AP = 1,
+ WL_INTERFACE_TYPE_AWDL = 2,
+ WL_INTERFACE_TYPE_MAX
+} wl_interface_type_t;
+
+/*
+ * Bit 1 of flags field is used to inform whether MAC is present in the
+ * data structure or not.
+ * 0 - Ignore mac_addr field
+ * 1 - Use the mac_addr field
+ */
+#define WL_INTERFACE_MAC_DONT_USE (0 << 1)
+#define WL_INTERFACE_MAC_USE (1 << 1)
+
+/*
+ * Bit 2 of flags field is used to inform whether core or wlc index
+ * is present in the data structure or not.
+ * 0 - Ignore wlc_index field
+ * 1 - Use the wlc_index field
+ */
+#define WL_INTERFACE_WLC_INDEX_DONT_USE (0 << 2)
+#define WL_INTERFACE_WLC_INDEX_USE (1 << 2)
+
+typedef struct wl_interface_create {
+ uint16 ver; /**< version of this struct */
+ uint8 pad1[2]; /**< Padding bytes */
+ uint32 flags; /**< flags that defines the operation */
+ struct ether_addr mac_addr; /**< Optional Mac address */
+ uint8 iftype; /**< Type of interface created */
+ uint8 pad2; /**< Padding bytes */
+ uint32 wlc_index; /**< Optional wlc index */
+} wl_interface_create_t;
+
+typedef struct wl_interface_info {
+ uint16 ver; /**< version of this struct */
+ struct ether_addr mac_addr; /**< MAC address of the interface */
+ char ifname[BCM_MSG_IFNAME_MAX]; /**< name of interface */
+ uint8 bsscfgidx; /**< source bsscfg index */
+} wl_interface_info_t;
+
+#define PHY_RXIQEST_AVERAGING_DELAY 10
+
+typedef struct wl_iqest_params {
+ uint32 rxiq;
+ uint8 niter;
+ uint8 delay;
+} wl_iqest_params_t;
+
+typedef struct wl_iqest_sweep_params {
+ wl_iqest_params_t params;
+ uint8 nchannels;
+ uint8 channel[1];
+} wl_iqest_sweep_params_t;
+
+typedef struct wl_iqest_value {
+ uint8 channel;
+ uint32 rxiq;
+} wl_iqest_value_t;
+
+typedef struct wl_iqest_result {
+ uint8 nvalues;
+ wl_iqest_value_t value[1];
+} wl_iqest_result_t;
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/* BTCX AIBSS (Oxygen) Status */
+typedef struct wlc_btc_aibss_info {
+ uint32 prev_tsf_l; // Lower 32 bits of last read of TSF
+ uint32 prev_tsf_h; // Higher 32 bits of last read of TSF
+ uint32 last_btinfo; // Last read of BT info
+ uint32 local_btinfo; // Local BT INFO BitMap
+ uint8 bt_out_of_sync_cnt; // BT not in sync with strobe
+ uint8 esco_off_cnt; // Count incremented when ESCO is off
+ uint8 strobe_enabled; // Set only in AIBSS mode
+ uint8 strobe_on; // strobe to BT is on for Oxygen
+ uint8 local_bt_in_sync; // Sync status of local BT when strobe is on
+ uint8 other_bt_in_sync; // Sync state of BT in other devices in AIBSS
+ uint8 local_bt_is_master; // Local BT is master
+ uint8 sco_prot_on; // eSCO Protection on in local device
+ uint8 other_esco_present; // eSCO status in other devices in AIBSS
+ uint8 rx_agg_change; // Indicates Rx Agg size needs to change
+ uint8 rx_agg_modified; // Rx Agg size modified
+ uint8 acl_grant_set; // ACL grants on for speeding up sync
+ uint8 write_ie_err_cnt; // BTCX Ie write error cnt
+ uint8 parse_ie_err_cnt; // BTCX IE parse error cnt
+ uint8 wci2_fail_cnt; // WCI2 init failure cnt
+ uint8 strobe_enable_err_cnt; // Strobe enable err cnt
+ uint8 strobe_init_err_cnt; // Strobe init err cnt
+ uint8 tsf_jump_cnt; // TSF jump cnt
+ uint8 acl_grant_cnt; // ALC grant cnt
+ uint8 pad1;
+ uint16 ibss_tsf_shm; // SHM address of strobe TSF
+ uint16 pad2;
+} wlc_btc_aibss_info_t;
+
+#define WLC_BTC_AIBSS_STATUS_VER 1
+#define WLC_BTC_AIBSS_STATUS_LEN (sizeof(wlc_btc_aibss_status_t) - 2 * (sizeof(uint16)))
+
+typedef struct wlc_btc_aibss_status {
+ uint16 version; // Version #
+ uint16 len; // Length of the structure(excluding len & version)
+ int32 mode; // Current value of btc_mode
+ uint16 bth_period; // bt coex period. read from shm.
+ uint16 agg_off_bm; // AGG OFF BM read from SHM
+ uint8 bth_active; // bt active session
+ uint8 pad[3];
+ wlc_btc_aibss_info_t aibss_info; // Structure definition above
+} wlc_btc_aibss_status_t;
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+typedef enum {
+ STATE_NONE = 0,
+
+ /* WLAN -> BT */
+ W2B_DATA_SET = 21,
+ B2W_ACK_SET = 22,
+ W2B_DATA_CLEAR = 23,
+ B2W_ACK_CLEAR = 24,
+
+ /* BT -> WLAN */
+ B2W_DATA_SET = 31,
+ W2B_ACK_SET = 32,
+ B2W_DATA_CLEAR = 33,
+ W2B_ACK_CLEAR = 34
+} bwte_gci_intstate_t;
+
+#define WL_BWTE_STATS_VERSION 1 /* version of bwte_stats_t */
+typedef struct {
+ uint32 version;
+
+ bwte_gci_intstate_t inttobt;
+ bwte_gci_intstate_t intfrombt;
+
+ uint32 bt2wl_intrcnt; /* bt->wlan interrrupt count */
+ uint32 wl2bt_intrcnt; /* wlan->bt interrupt count */
+
+ uint32 wl2bt_dset_cnt;
+ uint32 wl2bt_dclear_cnt;
+ uint32 wl2bt_aset_cnt;
+ uint32 wl2bt_aclear_cnt;
+
+ uint32 bt2wl_dset_cnt;
+ uint32 bt2wl_dclear_cnt;
+ uint32 bt2wl_aset_cnt;
+ uint32 bt2wl_aclear_cnt;
+
+ uint32 state_error_1;
+ uint32 state_error_2;
+ uint32 state_error_3;
+ uint32 state_error_4;
+} bwte_stats_t;
+
+#define TBOW_MAX_SSID_LEN 32
+#define TBOW_MAX_PASSPHRASE_LEN 63
+
+#define WL_TBOW_SETUPINFO_T_VERSION 1 /* version of tbow_setup_netinfo_t */
+typedef struct tbow_setup_netinfo {
+ uint32 version;
+ uint8 opmode;
+ uint8 pad;
+ uint8 macaddr[ETHER_ADDR_LEN];
+ uint32 ssid_len;
+ uint8 ssid[TBOW_MAX_SSID_LEN];
+ uint8 passphrase_len;
+ uint8 passphrase[TBOW_MAX_PASSPHRASE_LEN];
+ chanspec_t chanspec;
+ uint32 channel;
+} tbow_setup_netinfo_t;
+
+typedef enum tbow_ho_opmode {
+ TBOW_HO_MODE_START_GO = 0,
+ TBOW_HO_MODE_START_STA,
+ TBOW_HO_MODE_START_GC,
+ TBOW_HO_MODE_TEST_GO,
+ TBOW_HO_MODE_STOP_GO = 0x10,
+ TBOW_HO_MODE_STOP_STA,
+ TBOW_HO_MODE_STOP_GC,
+ TBOW_HO_MODE_TEARDOWN
+} tbow_ho_opmode_t;
+
+/* Beacon trim feature statistics */
+/* configuration */
+#define BCNTRIMST_PER 0 /**< Number of beacons to trim (0: disable) */
+#define BCNTRIMST_TIMEND 1 /**< Number of bytes till TIM IE */
+#define BCNTRIMST_TSFLMT 2 /**< TSF tolerance value (usecs) */
+/* internal use */
+#define BCNTRIMST_CUR 3 /**< PSM's local beacon trim counter */
+#define BCNTRIMST_PREVLEN 4 /**< Beacon length excluding the TIM IE */
+#define BCNTRIMST_TIMLEN 5 /**< TIM IE Length */
+#define BCNTRIMST_RSSI 6 /**< Partial beacon RSSI */
+#define BCNTRIMST_CHAN 7 /**< Partial beacon channel */
+/* debug stat (off by default) */
+#define BCNTRIMST_DUR 8 /**< RX duration until beacon trimmed */
+#define BCNTRIMST_RXMBSS 9 /**< MYBSSID beacon received */
+#define BCNTRIMST_CANTRIM 10 /**< # beacons which were trimmed */
+#define BCNTRIMST_LENCHG 11 /**< # beacons not trimmed due to length change */
+#define BCNTRIMST_TSFDRF 12 /**< # beacons not trimmed due to large TSF delta */
+#define BCNTRIMST_NOTIM 13 /**< # beacons not trimmed due to TIM missing */
+
+#define BCNTRIMST_NUM 14
+
+/* -------------- TX Power Cap --------------- */
+#define TXPWRCAP_MAX_NUM_CORES 8
+#define TXPWRCAP_MAX_NUM_ANTENNAS (TXPWRCAP_MAX_NUM_CORES * 2)
+
+#define TXPWRCAP_NUM_SUBBANDS 5
+
+/* IOVAR txcapconfig enum's */
+#define TXPWRCAPCONFIG_WCI2 0
+#define TXPWRCAPCONFIG_HOST 1
+#define TXPWRCAPCONFIG_WCI2_AND_HOST 2
+
+/* IOVAR txcapstate enum's */
+#define TXPWRCAPSTATE_LOW_CAP 0
+#define TXPWRCAPSTATE_HIGH_CAP 1
+#define TXPWRCAPSTATE_HOST_LOW_WCI2_LOW_CAP 0
+#define TXPWRCAPSTATE_HOST_LOW_WCI2_HIGH_CAP 1
+#define TXPWRCAPSTATE_HOST_HIGH_WCI2_LOW_CAP 2
+#define TXPWRCAPSTATE_HOST_HIGH_WCI2_HIGH_CAP 3
+
+/* IOVAR txcapconfig and txcapstate structure is shared: SET and GET */
+#define TXPWRCAPCTL_VERSION 2
+typedef struct wl_txpwrcap_ctl {
+ uint8 version;
+ uint8 ctl[TXPWRCAP_NUM_SUBBANDS];
+} wl_txpwrcap_ctl_t;
+
+/* IOVAR txcapdump structure: GET only */
+#define TXPWRCAP_DUMP_VERSION 2
+typedef struct wl_txpwrcap_dump {
+ uint8 version;
+ uint8 pad0;
+ uint8 current_country[2];
+ uint32 current_channel;
+ uint8 config[TXPWRCAP_NUM_SUBBANDS];
+ uint8 state[TXPWRCAP_NUM_SUBBANDS];
+ uint8 high_cap_state_enabled;
+ uint8 wci2_cell_status_last;
+ uint8 download_present;
+ uint8 num_subbands;
+ uint8 num_antennas;
+ uint8 num_antennas_per_core[TXPWRCAP_MAX_NUM_CORES];
+ uint8 num_cc_groups;
+ uint8 current_country_cc_group_info_index;
+ int8 low_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS];
+ int8 high_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS];
+} wl_txpwrcap_dump_t;
+
+typedef struct wl_txpwrcap_dump_v3 {
+ uint8 version;
+ uint8 pad0;
+ uint8 current_country[2];
+ uint32 current_channel;
+ uint8 config[TXPWRCAP_NUM_SUBBANDS];
+ uint8 state[TXPWRCAP_NUM_SUBBANDS];
+ uint8 high_cap_state_enabled;
+ uint8 wci2_cell_status_last;
+ uint8 download_present;
+ uint8 num_subbands;
+ uint8 num_antennas;
+ uint8 num_antennas_per_core[TXPWRCAP_MAX_NUM_CORES];
+ uint8 num_cc_groups;
+ uint8 current_country_cc_group_info_index;
+ uint8 cap_states_per_cc_group;
+ int8 host_low_wci2_low_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS];
+ int8 host_low_wci2_high_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS];
+ int8 host_high_wci2_low_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS];
+ int8 host_high_wci2_high_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS];
+} wl_txpwrcap_dump_v3_t;
+
+typedef struct wl_txpwrcap_tbl {
+ uint8 num_antennas_per_core[TXPWRCAP_MAX_NUM_CORES];
+ /* Stores values for valid antennas */
+ int8 pwrcap_cell_on[TXPWRCAP_MAX_NUM_ANTENNAS]; /* qdBm units */
+ int8 pwrcap_cell_off[TXPWRCAP_MAX_NUM_ANTENNAS]; /* qdBm units */
+} wl_txpwrcap_tbl_t;
+
+/* ##### Ecounters section ##### */
+#define ECOUNTERS_VERSION_1 1
+
+/* Input structure for ecounters IOVAR */
+typedef struct ecounters_config_request {
+ uint16 version; /* config version */
+ uint16 set; /* Set where data will go. */
+ uint16 size; /* Size of the set. */
+ uint16 timeout; /* timeout in seconds. */
+ uint16 num_events; /* Number of events to report. */
+ uint16 ntypes; /* Number of entries in type array. */
+ uint16 type[1]; /* Statistics Types (tags) to retrieve. */
+} ecounters_config_request_t;
+
+#define ECOUNTERS_EVENTMSGS_VERSION_1 1
+#define ECOUNTERS_TRIGGER_CONFIG_VERSION_1 1
+
+#define ECOUNTERS_EVENTMSGS_EXT_MASK_OFFSET \
+ OFFSETOF(ecounters_eventmsgs_ext_t, mask[0])
+
+#define ECOUNTERS_TRIG_CONFIG_TYPE_OFFSET \
+ OFFSETOF(ecounters_trigger_config_t, type[0])
+
+typedef struct ecounters_eventmsgs_ext {
+ uint8 version;
+ uint8 len;
+ uint8 mask[1];
+} ecounters_eventmsgs_ext_t;
+
+typedef struct ecounters_trigger_config {
+ uint16 version; /* version */
+ uint16 set; /* set where data should go */
+ uint16 rsvd; /* reserved */
+ uint16 pad; /* pad/reserved */
+ uint16 ntypes; /* number of types/tags */
+ uint16 type[1]; /* list of types */
+} ecounters_trigger_config_t;
+
+#define ECOUNTERS_TRIGGER_REASON_VERSION_1 1
+/* Triggered due to timer based ecounters */
+#define ECOUNTERS_TRIGGER_REASON_TIMER 0
+/* Triggered due to event based configuration */
+#define ECOUNTERS_TRIGGER_REASON_EVENTS 1
+#define ECOUNTERS_TRIGGER_REASON_MAX 1
+
+typedef struct ecounters_trigger_reason {
+ uint16 version; /* version */
+ uint16 trigger_reason; /* trigger reason */
+ uint32 sub_reason_code; /* sub reason code */
+ uint32 trigger_time_now; /* time in ms at trigger */
+ uint32 host_ref_time; /* host ref time */
+} ecounters_trigger_reason_t;
+
+/* -------------- dynamic BTCOEX --------------- */
+#define DCTL_TROWS 2 /**< currently practical number of rows */
+#define DCTL_TROWS_MAX 4 /**< 2 extra rows RFU */
+/* DYNCTL profile flags */
+#define DCTL_FLAGS_DISABLED 0 /**< default value: all features disabled */
+#define DCTL_FLAGS_DYNCTL (1 << 0) /**< 1 - enabled, 0 - legacy only */
+#define DCTL_FLAGS_DESENSE (1 << 1) /**< auto desense is enabled */
+#define DCTL_FLAGS_MSWITCH (1 << 2) /**< mode switching is enabled */
+/* for now AGG on/off is handled separately */
+#define DCTL_FLAGS_TX_AGG_OFF (1 << 3) /**< TBD: allow TX agg Off */
+#define DCTL_FLAGS_RX_AGG_OFF (1 << 4) /**< TBD: allow RX agg Off */
+/* used for dry run testing only */
+#define DCTL_FLAGS_DRYRUN (1 << 7) /**< Enables dynctl dry run mode */
+#define IS_DYNCTL_ON(prof) ((prof->flags & DCTL_FLAGS_DYNCTL) != 0)
+#define IS_DESENSE_ON(prof) ((prof->flags & DCTL_FLAGS_DESENSE) != 0)
+#define IS_MSWITCH_ON(prof) ((prof->flags & DCTL_FLAGS_MSWITCH) != 0)
+/* desense level currently in use */
+#define DESENSE_OFF 0
+#define DFLT_DESENSE_MID 12
+#define DFLT_DESENSE_HIGH 2
+
+/**
+ * dynctl data points(a set of btpwr & wlrssi thresholds)
+ * for mode & desense switching
+ */
+typedef struct btc_thr_data {
+ int8 mode; /**< used by desense sw */
+ int8 bt_pwr; /**< BT tx power threshold */
+ int8 bt_rssi; /**< BT rssi threshold */
+ /* wl rssi range when mode or desense change may be needed */
+ int8 wl_rssi_high;
+ int8 wl_rssi_low;
+} btc_thr_data_t;
+
+/* dynctl. profile data structure */
+#define DCTL_PROFILE_VER 0x01
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct dctl_prof {
+ uint8 version; /**< dynctl profile version */
+ /* dynctl profile flags bit:0 - dynctl On, bit:1 dsns On, bit:2 mode sw On, */
+ uint8 flags; /**< bit[6:3] reserved, bit7 - Dryrun (sim) - On */
+ /** wl desense levels to apply */
+ uint8 dflt_dsns_level;
+ uint8 low_dsns_level;
+ uint8 mid_dsns_level;
+ uint8 high_dsns_level;
+ /** mode switching hysteresis in dBm */
+ int8 msw_btrssi_hyster;
+ /** default btcoex mode */
+ uint8 default_btc_mode;
+ /** num of active rows in mode switching table */
+ uint8 msw_rows;
+ /** num of rows in desense table */
+ uint8 dsns_rows;
+ /** dynctl mode switching data table */
+ btc_thr_data_t msw_data[DCTL_TROWS_MAX];
+ /** dynctl desense switching data table */
+ btc_thr_data_t dsns_data[DCTL_TROWS_MAX];
+} BWL_POST_PACKED_STRUCT dctl_prof_t;
+#include <packed_section_end.h>
+
+/** dynctl status info */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct dynctl_status {
+ uint8 sim_on; /**< true if simulation is On */
+ uint16 bt_pwr_shm; /**< BT per/task power as read from ucode */
+ int8 bt_pwr; /**< BT pwr extracted & converted to dBm */
+ int8 bt_rssi; /**< BT rssi in dBm */
+ int8 wl_rssi; /**< last wl rssi reading used by btcoex */
+ uint8 dsns_level; /**< current desense level */
+ uint8 btc_mode; /**< current btcoex mode */
+ /* add more status items if needed, pad to 4 BB if needed */
+} BWL_POST_PACKED_STRUCT dynctl_status_t;
+#include <packed_section_end.h>
+
+/** dynctl simulation (dryrun data) */
+#include <packed_section_start.h>
+typedef BWL_PRE_PACKED_STRUCT struct dynctl_sim {
+ uint8 sim_on; /**< simulation mode on/off */
+ int8 btpwr; /**< simulated BT power in dBm */
+ int8 btrssi; /**< simulated BT rssi in dBm */
+ int8 wlrssi; /**< simulated WL rssi in dBm */
+} BWL_POST_PACKED_STRUCT dynctl_sim_t;
+/* no default structure packing */
+#include <packed_section_end.h>
+
+/** PTK key maintained per SCB */
+#define RSN_TEMP_ENCR_KEY_LEN 16
+typedef struct wpa_ptk {
+ uint8 kck[RSN_KCK_LENGTH]; /**< EAPOL-Key Key Confirmation Key (KCK) */
+ uint8 kek[RSN_KEK_LENGTH]; /**< EAPOL-Key Key Encryption Key (KEK) */
+ uint8 tk1[RSN_TEMP_ENCR_KEY_LEN]; /**< Temporal Key 1 (TK1) */
+ uint8 tk2[RSN_TEMP_ENCR_KEY_LEN]; /**< Temporal Key 2 (TK2) */
+} wpa_ptk_t;
+
+/** GTK key maintained per SCB */
+typedef struct wpa_gtk {
+ uint32 idx;
+ uint32 key_len;
+ uint8 key[DOT11_MAX_KEY_SIZE];
+} wpa_gtk_t;
+
+/** FBT Auth Response Data structure */
+typedef struct wlc_fbt_auth_resp {
+ uint8 macaddr[ETHER_ADDR_LEN]; /**< station mac address */
+ uint8 pad[2];
+ uint8 pmk_r1_name[WPA2_PMKID_LEN];
+ wpa_ptk_t ptk; /**< pairwise key */
+ wpa_gtk_t gtk; /**< group key */
+ uint32 ie_len;
+ uint8 status; /**< Status of parsing FBT authentication
+ Request in application
+ */
+ uint8 ies[1]; /**< IEs contains MDIE, RSNIE,
+ FBTIE (ANonce, SNonce,R0KH-ID, R1KH-ID)
+ */
+} wlc_fbt_auth_resp_t;
+
+/** FBT Action Response frame */
+typedef struct wlc_fbt_action_resp {
+ uint16 version; /**< structure version */
+ uint16 length; /**< length of structure */
+ uint8 macaddr[ETHER_ADDR_LEN]; /**< station mac address */
+ uint8 data_len; /**< len of ie from Category */
+ uint8 data[1]; /**< data contains category, action, sta address, target ap,
+ status code,fbt response frame body
+ */
+} wlc_fbt_action_resp_t;
+
+#define MACDBG_PMAC_ADDR_INPUT_MAXNUM 16
+#define MACDBG_PMAC_OBJ_TYPE_LEN 8
+
+typedef struct _wl_macdbg_pmac_param_t {
+ char type[MACDBG_PMAC_OBJ_TYPE_LEN];
+ uint8 step;
+ uint8 w_en;
+ uint16 num;
+ uint32 bitmap;
+ uint8 addr_raw;
+ uint8 addr_num;
+ uint16 addr[MACDBG_PMAC_ADDR_INPUT_MAXNUM];
+ uint8 pad0[2];
+ uint32 w_val;
+} wl_macdbg_pmac_param_t;
+
+/** IOVAR 'svmp_sampcol' parameter. Used to set and read SVMP_SAMPLE_COLLECT's setting */
+typedef struct wl_svmp_sampcol_param {
+ uint32 version; /* version */
+ uint8 enable;
+ uint8 trigger_mode; /* SVMP_SAMPCOL_TRIGGER */
+ uint8 trigger_mode_s[2]; /* SVMP_SAMPCOL_PKTPROC */
+ uint8 data_samplerate; /* SVMP_SAMPCOL_SAMPLERATE */
+ uint8 data_sel_phy1; /* SVMP_SAMPCOL_PHY1MUX */
+ uint8 data_sel_rx1; /* SVMP_SAMPCOL_RX1MUX without iqCompOut */
+ uint8 data_sel_dualcap; /* SVMP_SAMPCOL_RX1MUX */
+ uint8 pack_mode; /* SVMP_SAMPCOL_PACK */
+ uint8 pack_order;
+ uint8 pack_cfix_fmt;
+ uint8 pack_1core_sel;
+ uint16 waitcnt;
+ uint16 caplen;
+ uint32 buff_addr_start; /* in word-size (2-bytes) */
+ uint32 buff_addr_end; /* note: Tcl in byte-size, HW in vector-size (8-bytes) */
+ uint8 int2vasip;
+ uint16 status;
+} wl_svmp_sampcol_t;
+
+#define WL_SVMP_SAMPCOL_PARAMS_VERSION 1
+
+enum {
+ SVMP_SAMPCOL_TRIGGER_PKTPROC_TRANSITION = 0,
+ SVMP_SAMPCOL_TRIGGER_FORCE_IMMEDIATE,
+ SVMP_SAMPCOL_TRIGGER_RADAR_DET
+};
+
+enum {
+ SVMP_SAMPCOL_PHY1MUX_GPIOOUT = 0,
+ SVMP_SAMPCOL_PHY1MUX_FFT,
+ SVMP_SAMPCOL_PHY1MUX_DBGHX,
+ SVMP_SAMPCOL_PHY1MUX_RX1MUX
+};
+
+enum {
+ SVMP_SAMPCOL_RX1MUX_FARROWOUT = 4,
+ SVMP_SAMPCOL_RX1MUX_IQCOMPOUT,
+ SVMP_SAMPCOL_RX1MUX_DCFILTEROUT,
+ SVMP_SAMPCOL_RX1MUX_RXFILTEROUT,
+ SVMP_SAMPCOL_RX1MUX_ACIFILTEROUT
+};
+
+enum {
+ SVMP_SAMPCOL_SAMPLERATE_1XBW = 0,
+ SVMP_SAMPCOL_SAMPLERATE_2XBW
+};
+
+enum {
+ SVMP_SAMPCOL_PACK_DUALCAP = 0,
+ SVMP_SAMPCOL_PACK_4CORE,
+ SVMP_SAMPCOL_PACK_2CORE,
+ SVMP_SAMPCOL_PACK_1CORE
+};
+
+enum {
+ SVMP_SAMPCOL_PKTPROC_RESET = 0,
+ SVMP_SAMPCOL_PKTPROC_CARRIER_SEARCH,
+ SVMP_SAMPCOL_PKTPROC_WAIT_FOR_NB_PWR,
+ SVMP_SAMPCOL_PKTPROC_WAIT_FOR_W1_PWR,
+ SVMP_SAMPCOL_PKTPROC_WAIT_FOR_W2_PWR,
+ SVMP_SAMPCOL_PKTPROC_OFDM_PHY,
+ SVMP_SAMPCOL_PKTPROC_TIMING_SEARCH,
+ SVMP_SAMPCOL_PKTPROC_CHAN_EST_1,
+ SVMP_SAMPCOL_PKTPROC_LEG_SIG_DEC,
+ SVMP_SAMPCOL_PKTPROC_SIG_DECODE_1,
+ SVMP_SAMPCOL_PKTPROC_SIG_DECODE_2,
+ SVMP_SAMPCOL_PKTPROC_HT_AGC,
+ SVMP_SAMPCOL_PKTPROC_CHAN_EST_2,
+ SVMP_SAMPCOL_PKTPROC_PAY_DECODE,
+ SVMP_SAMPCOL_PKTPROC_DSSS_CCK_PHY,
+ SVMP_SAMPCOL_PKTPROC_WAIT_ENERGY_DROP,
+ SVMP_SAMPCOL_PKTPROC_WAIT_NCLKS,
+ SVMP_SAMPCOL_PKTPROC_PAY_DEC_EXT,
+ SVMP_SAMPCOL_PKTPROC_SIG_FAIL_DELAY,
+ SVMP_SAMPCOL_PKTPROC_RIFS_SEARCH,
+ SVMP_SAMPCOL_PKTPROC_BOARD_SWITCH_DIV_SEARCH,
+ SVMP_SAMPCOL_PKTPROC_DSSS_CCK_BOARD_SWITCH_DIV_SEARCH,
+ SVMP_SAMPCOL_PKTPROC_CHAN_EST_3,
+ SVMP_SAMPCOL_PKTPROC_CHAN_EST_4,
+ SVMP_SAMPCOL_PKTPROC_FINE_TIMING_SEARCH,
+ SVMP_SAMPCOL_PKTPROC_SET_CLIP_GAIN,
+ SVMP_SAMPCOL_PKTPROC_NAP,
+ SVMP_SAMPCOL_PKTPROC_VHT_SIGA_DEC,
+ SVMP_SAMPCOL_PKTPROC_VHT_SIGB_DEC,
+ SVMP_SAMPCOL_PKTPROC_PKT_ABORT,
+ SVMP_SAMPCOL_PKTPROC_DCCAL
+};
+
+/** IOVAR 'svmp_mem' parameter. Used to read/clear svmp memory */
+typedef struct svmp_mem {
+ uint32 addr; /**< offset to read svmp memory from vasip base address */
+ uint16 len; /**< length in count of uint16's */
+ uint16 val; /**< set the range of addr/len with a value */
+} svmp_mem_t;
+
+/** IOVAR 'mu_rate' parameter. read/set mu rate for upto four users */
+#define MU_RATE_CFG_VERSION 1
+typedef struct mu_rate {
+ uint16 version; /**< version of the structure as defined by MU_RATE_CFG_VERSION */
+ uint16 length; /**< length of entire structure */
+ uint8 auto_rate; /**< enable/disable auto rate */
+ uint16 rate_user[4]; /**< rate per each of four users, set to -1 for no change */
+} mu_rate_t;
+
+/** IOVAR 'mu_group' parameter. Used to set and read MU group recommendation setting */
+#define WL_MU_GROUP_AUTO_COMMAND -1
+#define WL_MU_GROUP_PARAMS_VERSION 3
+#define WL_MU_GROUP_METHOD_NAMELEN 64
+#define WL_MU_GROUP_NGROUP_MAX 15
+#define WL_MU_GROUP_NUSER_MAX 4
+#define WL_MU_GROUP_METHOD_MIN 0
+#define WL_MU_GROUP_NUMBER_AUTO_MIN 1
+#define WL_MU_GROUP_NUMBER_AUTO_MAX 15
+#define WL_MU_GROUP_NUMBER_FORCED_MAX 8
+#define WL_MU_GROUP_METHOD_OLD 0
+#define WL_MU_GROUP_MODE_AUTO 0
+#define WL_MU_GROUP_MODE_FORCED 1
+#define WL_MU_GROUP_FORCED_1GROUP 1
+#define WL_MU_GROUP_ENTRY_EMPTY -1
+typedef struct mu_group {
+ uint32 version; /* version */
+ int16 forced; /* forced group recommendation */
+ int16 forced_group_mcs; /* forced group with mcs */
+ int16 forced_group_num; /* forced group number */
+ int16 group_option[WL_MU_GROUP_NGROUP_MAX][WL_MU_GROUP_NUSER_MAX];
+ /* set mode for forced grouping and read mode for auto grouping */
+ int16 group_GID[WL_MU_GROUP_NGROUP_MAX];
+ int16 group_method; /* methof for VASIP group recommendation */
+ int16 group_number; /* requested number for VASIP group recommendation */
+ int16 auto_group_num; /* exact number from VASIP group recommendation */
+ int8 group_method_name[WL_MU_GROUP_METHOD_NAMELEN];
+} mu_group_t;
+
+typedef struct mupkteng_sta {
+ struct ether_addr ea;
+ int32 nrxchain;
+ int32 idx;
+} mupkteng_sta_t;
+
+typedef struct mupkteng_client {
+ int32 rspec;
+ int32 idx;
+ int32 flen;
+ int32 nframes;
+} mupkteng_client_t;
+
+typedef struct mupkteng_tx {
+ mupkteng_client_t client[8];
+ int32 nclients;
+ int32 ntx;
+} mupkteng_tx_t;
+
+/*
+ * MU Packet engine interface.
+ * The following two definitions will go into
+ * components/shared/devctrl_if/wlioctl_defs.h
+ * when wl utility changes are merged to EAGLE TOB & Trunk
+ */
+
+#define WL_MUPKTENG_PER_TX_START 0x10
+#define WL_MUPKTENG_PER_TX_STOP 0x20
+
+/** IOVAR 'mu_policy' parameter. Used to configure MU admission control policies */
+#define WL_MU_POLICY_PARAMS_VERSION 1
+#define WL_MU_POLICY_SCHED_DEFAULT 60
+#define WL_MU_POLICY_DISABLED 0
+#define WL_MU_POLICY_ENABLED 1
+#define WL_MU_POLICY_NRX_MIN 1
+#define WL_MU_POLICY_NRX_MAX 2
+typedef struct mu_policy {
+ uint16 version;
+ uint16 length;
+ uint32 sched_timer;
+ uint32 pfmon;
+ uint32 pfmon_gpos;
+ uint32 samebw;
+ uint32 nrx;
+ uint32 max_muclients;
+} mu_policy_t;
+
+#define WL_NAN_BAND_STR_SIZE 5 /* sizeof ("auto") */
+
+/** Definitions of different NAN Bands */
+/* do not change the order */
+enum {
+ NAN_BAND_B = 0,
+ NAN_BAND_A,
+ NAN_BAND_AUTO,
+ NAN_BAND_INVALID = 0xFF
+};
+
+#ifdef WL11ULB
+/* ULB Mode configured via "ulb_mode" IOVAR */
+enum {
+ ULB_MODE_DISABLED = 0,
+ ULB_MODE_STD_ALONE_MODE = 1, /* Standalone ULB Mode */
+ ULB_MODE_DYN_MODE = 2, /* Dynamic ULB Mode */
+ /* Add all other enums before this */
+ MAX_SUPP_ULB_MODES
+};
+
+/* ULB BWs configured via "ulb_bw" IOVAR during Standalone Mode Only.
+ * Values of this enumeration are also used to specify 'Current Operational Bandwidth'
+ * and 'Primary Operational Bandwidth' sub-fields in 'ULB Operations' field (used in
+ * 'ULB Operations' Attribute or 'ULB Mode Switch' Attribute)
+ */
+typedef enum {
+ ULB_BW_DISABLED = 0,
+ ULB_BW_10MHZ = 1, /* Standalone ULB BW in 10 MHz BW */
+ ULB_BW_5MHZ = 2, /* Standalone ULB BW in 5 MHz BW */
+ ULB_BW_2P5MHZ = 3, /* Standalone ULB BW in 2.5 MHz BW */
+ /* Add all other enums before this */
+ MAX_SUPP_ULB_BW
+} ulb_bw_type_t;
+#endif /* WL11ULB */
+
+#ifdef WLMESH
+
+#define WL_MESH_IOCTL_VERSION 1
+#define MESH_IOC_BUFSZ 512 /* sufficient ioc buff size for mesh */
+
+typedef struct mesh_peer_info_ext {
+ mesh_peer_info_t peer_info;
+ uint8 pad1;
+ uint16 local_aid; /* AID generated by *local* to peer */
+ uint32 entry_state; /* see MESH_PEER_ENTRY_STATE_ACTIVE etc; valid
+ * ONLY for internal peering requests
+ */
+ int8 rssi;
+ uint8 pad2;
+ struct ether_addr ea; /* peer ea */
+} mesh_peer_info_ext_t;
+
+typedef struct mesh_peer_info_dump {
+ uint32 buflen;
+ uint32 version;
+ uint16 count; /* number of results */
+ uint16 remaining; /* remaining rsults */
+ mesh_peer_info_ext_t mpi_ext[1];
+} mesh_peer_info_dump_t;
+
+#define WL_MESH_PEER_RES_FIXED_SIZE (sizeof(mesh_peer_info_dump_t) - sizeof(mesh_peer_info_ext_t))
+
+/* container for mesh iovtls & events */
+typedef struct wl_mesh_ioc {
+ uint16 version; /* interface command or event version */
+ uint16 id; /* mesh ioctl cmd ID */
+ uint16 len; /* total length of all tlv records in data[] */
+ uint16 pad; /* pad to be 32 bit aligment */
+ uint8 data[1]; /* var len payload of bcm_xtlv_t type */
+} wl_mesh_ioc_t;
+
+enum wl_mesh_cmds {
+ WL_MESH_CMD_ENABLE = 1,
+ WL_MESH_CMD_JOIN = 2,
+ WL_MESH_CMD_PEER_STATUS = 3,
+ WL_MESH_CMD_ADD_ROUTE = 4,
+ WL_MESH_CMD_DEL_ROUTE = 5,
+ WL_MESH_CMD_ADD_FILTER = 6,
+ WL_MESH_CMD_ENAB_AL_METRIC = 7
+};
+
+enum wl_mesh_cmd_xtlv_id {
+ WL_MESH_XTLV_ENABLE = 1,
+ WL_MESH_XTLV_JOIN = 2,
+ WL_MESH_XTLV_STATUS = 3,
+ WL_MESH_XTLV_ADD_ROUTE = 4,
+ WL_MESH_XTLV_DEL_ROUTE = 5,
+ WL_MESH_XTLV_ADD_FILTER = 6,
+ WL_MESH_XTLV_ENAB_AIRLINK = 7
+};
+
+#endif /* WLMESH */
+
+/* Fast BSS Transition parameter configuration */
+#define FBT_PARAM_CURRENT_VERSION 0
+
+typedef struct _wl_fbt_params {
+ uint16 version; /* version of the structure
+ * as defined by FBT_PARAM_CURRENT_VERSION
+ */
+ uint16 length; /* length of the entire structure */
+
+ uint16 param_type; /* type of parameter defined below */
+ uint16 param_len; /* length of the param_value */
+ uint8 param_value[1]; /* variable length */
+} wl_fbt_params_t;
+
+#define WL_FBT_PARAM_TYPE_RSNIE 0
+#define WL_FBT_PARAM_TYPE_FTIE 0x1
+#define WL_FBT_PARAM_TYPE_SNONCE 0x2
+#define WL_FBT_PARAM_TYPE_MDE 0x3
+#define WL_FBT_PARAM_TYPE_PMK_R0_NAME 0x4
+#define WL_FBT_PARAM_TYPE_R0_KHID 0x5
+#define WL_FBT_PARAM_TYPE_R1_KHID 0x6
+#define WL_FBT_PARAM_TYPE_FIRST_INVALID 0x7
+
+/* Assoc Mgr commands for fine control of assoc */
+#define WL_ASSOC_MGR_CURRENT_VERSION 0x0
+
+typedef struct {
+ uint16 version; /* version of the structure as
+ * defined by WL_ASSOC_MGR_CURRENT_VERSION
+ */
+ uint16 length; /* length of the entire structure */
+
+ uint16 cmd;
+ uint16 params;
+} wl_assoc_mgr_cmd_t;
+
+#define WL_ASSOC_MGR_CMD_PAUSE_ON_EVT 0 /* have assoc pause on certain events */
+#define WL_ASSOC_MGR_CMD_ABORT_ASSOC 1
+
+#define WL_ASSOC_MGR_PARAMS_EVENT_NONE 0 /* use this to resume as well as clear */
+#define WL_ASSOC_MGR_PARAMS_PAUSE_EVENT_AUTH_RESP 1
+
+#define WL_WINVER_STRUCT_VER_1 (1)
+
+typedef struct wl_winver {
+
+ /* Version and length of this structure. Length includes all fields in wl_winver_t */
+ uint16 struct_version;
+ uint16 struct_length;
+
+ /* Windows operating system version info (Microsoft provided) */
+ struct {
+ uint32 major_ver;
+ uint32 minor_ver;
+ uint32 build;
+ } os_runtime;
+
+ /* NDIS runtime version (Microsoft provided) */
+ struct {
+ uint16 major_ver;
+ uint16 minor_ver;
+ } ndis_runtime;
+
+ /* NDIS Driver version (Broadcom provided) */
+ struct {
+ uint16 major_ver;
+ uint16 minor_ver;
+ } ndis_driver;
+
+ /* WDI Upper Edge (UE) Driver version (Microsoft provided) */
+ struct {
+ uint8 major_ver;
+ uint8 minor_ver;
+ uint8 suffix;
+ } wdi_ue;
+
+ /* WDI Lower Edge (LE) Driver version (Broadcom provided) */
+ struct {
+ uint8 major_ver;
+ uint8 minor_ver;
+ uint8 suffix;
+ } wdi_le;
+
+} wl_winver_t;
+
+#if defined(WLRCC) || defined(ROAM_CHANNEL_CACHE)
+#define MAX_ROAM_CHANNEL 20
+typedef struct {
+ int32 n;
+ chanspec_t channels[MAX_ROAM_CHANNEL];
+} wl_roam_channel_list_t;
+#endif /* RCC || ROAM_CHANNEL_CACHE */
+
+#ifdef MFP
+/* values for IOV_MFP arg */
+enum {
+ WL_MFP_NONE = 0,
+ WL_MFP_CAPABLE,
+ WL_MFP_REQUIRED
+};
+#endif /* MFP */
+
+typedef enum {
+ CHANSW_UNKNOWN = 0, /* channel switch due to unknown reason */
+ CHANSW_SCAN = 1, /* channel switch due to scan */
+ CHANSW_PHYCAL = 2, /* channel switch due to phy calibration */
+ CHANSW_INIT = 3, /* channel set at WLC up time */
+ CHANSW_ASSOC = 4, /* channel switch due to association */
+ CHANSW_ROAM = 5, /* channel switch due to roam */
+ CHANSW_MCHAN = 6, /* channel switch triggered by mchan module */
+ CHANSW_IOVAR = 7, /* channel switch due to IOVAR */
+ CHANSW_CSA_DFS = 8, /* channel switch due to chan switch announcement from AP */
+ CHANSW_APCS = 9, /* Channel switch from AP channel select module */
+ CHANSW_AWDL = 10, /* channel switch due to AWDL */
+ CHANSW_FBT = 11, /* Channel switch from FBT module for action frame response */
+ CHANSW_UPDBW = 12, /* channel switch at update bandwidth */
+ CHANSW_ULB = 13, /* channel switch at ULB */
+ CHANSW_LAST = 14 /* last channel switch reason */
+} chansw_reason_t;
+
+/*
+ * WOWL unassociated mode power svae pattern.
+ */
+typedef struct wowl_radio_duty_cycle {
+ uint16 wake_interval;
+ uint16 sleep_interval;
+} wowl_radio_duty_cycle_t;
+
+typedef struct nd_ra_ol_limits {
+ uint16 version; /* version of the iovar buffer */
+ uint16 type; /* type of data provided */
+ uint16 length; /* length of the entire structure */
+ uint16 pad1; /* pad union to 4 byte boundary */
+ union {
+ struct {
+ uint16 min_time; /* seconds, min time for RA offload hold */
+ uint16 lifetime_percent;
+ /* percent, lifetime percentage for offload hold time */
+ } lifetime_relative;
+ struct {
+ uint16 hold_time; /* seconds, RA offload hold time */
+ uint16 pad2; /* unused */
+ } fixed;
+ } limits;
+} nd_ra_ol_limits_t;
+
+#define ND_RA_OL_LIMITS_VER 1
+
+/* nd_ra_ol_limits sub-types */
+#define ND_RA_OL_LIMITS_REL_TYPE 0 /* relative, percent of RA lifetime */
+#define ND_RA_OL_LIMITS_FIXED_TYPE 1 /* fixed time */
+
+/* buffer lengths for the different nd_ra_ol_limits types */
+#define ND_RA_OL_LIMITS_REL_TYPE_LEN 12
+#define ND_RA_OL_LIMITS_FIXED_TYPE_LEN 10
+
+/*
+ * Temperature Throttling control mode
+ */
+typedef struct wl_temp_control {
+ uint8 enable;
+ uint16 control_bit;
+} wl_temp_control_t;
+
+
+/* Data structures for rsdb caps */
+
+#define WL_RSDB_CAPS_VER 2
+
+/*
+ * The flags field of the rsdb_caps_response is designed to be
+ * a Bit Mask. As of now only Bit 0 is used as mentioned below.
+ */
+
+/* Bit-0 in flags is used to indicate if the cores can operate synchronously
+* i.e either as 2x2 MIMO or 2(1x1 SISO). This is true only for 4349 variants
+* 0 - device can operate only in rsdb mode (eg: 4364)
+* 1 - device can operate in both rsdb and mimo (eg : 4359 variants)
+*/
+
+#define SYNCHRONOUS_OPERATION_TRUE (1 << 0)
+#define WL_RSDB_CAPS_FIXED_LEN OFFSETOF(rsdb_caps_response_t, num_chains)
+
+typedef struct rsdb_caps_response {
+ uint8 ver; /* Version */
+ uint8 len; /* length of this structure excluding ver and len */
+ uint8 rsdb; /* TRUE for rsdb chip */
+ uint8 num_of_cores; /* no of d11 cores */
+ uint16 flags; /* Flags to indicate various capabilities */
+ uint8 num_chains[1]; /* Tx/Rx chains for each core */
+} rsdb_caps_response_t;
+
+/* Data structures for rsdb bands */
+#define WL_RSDB_BANDS_VER 2
+#define WL_RSDB_BANDS_FIXED_LEN OFFSETOF(rsdb_bands_t, band)
+
+typedef struct rsdb_bands
+{
+ uint8 ver; /* Version of the iovar */
+ uint8 len; /* Length of this structure excluding ver and len */
+ uint16 num_cores; /* num of band-core map information */
+ int16 band[1]; /* The band operating on each of the d11 cores */
+} rsdb_bands_t;
+
+
+typedef struct sim_pm_params {
+ uint32 enabled;
+ uint16 cycle;
+ uint16 up;
+} sim_pm_params_t;
+
+/* Bits for fw_status */
+#define NAP_DISABLED_HOST 0x01 /* Host has disabled through nap_enable */
+#define NAP_DISABLED_RSSI 0x02 /* Disabled because of nap_rssi_threshold */
+
+/* Bits for hw_status */
+#define NAP_HWCFG 0x01 /* State of NAP config bit in phy HW */
+
+#ifdef WL_NATOE
+
+#define WL_NATOE_IOCTL_VERSION 1
+#define WL_NATOE_IOC_BUFSZ 512 /* sufficient ioc buff size for natoe */
+#define WL_NATOE_DBG_STATS_BUFSZ 2048
+
+/* config natoe STA and AP IP's structure */
+typedef struct {
+ uint32 sta_ip;
+ uint32 sta_netmask;
+ uint32 sta_router_ip;
+ uint32 sta_dnsip;
+ uint32 ap_ip;
+ uint32 ap_netmask;
+} wl_natoe_config_ips_t;
+
+/* natoe ports config structure */
+typedef struct {
+ uint16 start_port_num;
+ uint16 no_of_ports;
+} wl_natoe_ports_config_t;
+
+/* natoe ports exception info */
+typedef struct {
+ uint16 sta_port_num;
+ uint16 dst_port_num; /* for SIP type protocol, dst_port_num info can be ignored by FW */
+ uint32 ip; /* for SIP ip is APcli_ip and for port clash it is dst_ip */
+ uint8 entry_type; /* Create/Destroy */
+ uint8 pad;
+} wl_natoe_exception_port_t;
+
+/* container for natoe ioctls & events */
+typedef struct wl_natoe_ioc {
+ uint16 version; /* interface command or event version */
+ uint16 id; /* natoe ioctl cmd ID */
+ uint16 len; /* total length of all tlv records in data[] */
+ uint16 pad; /* pad to be 32 bit aligment */
+ uint8 data[1]; /* var len payload of bcm_xtlv_t type */
+} wl_natoe_ioc_t;
+
+enum wl_natoe_cmds {
+ WL_NATOE_CMD_ENABLE = 1,
+ WL_NATOE_CMD_CONFIG_IPS = 2,
+ WL_NATOE_CMD_CONFIG_PORTS = 3,
+ WL_NATOE_CMD_DBG_STATS = 4,
+ WL_NATOE_CMD_EXCEPTION_PORT = 5,
+ WL_NATOE_CMD_SKIP_PORT = 6,
+ WL_NATOE_CMD_TBL_CNT = 7
+};
+
+enum wl_natoe_cmd_xtlv_id {
+ WL_NATOE_XTLV_ENABLE = 1,
+ WL_NATOE_XTLV_CONFIG_IPS = 2,
+ WL_NATOE_XTLV_CONFIG_PORTS = 3,
+ WL_NATOE_XTLV_DBG_STATS = 4,
+ WL_NATOE_XTLV_EXCEPTION_PORT = 5,
+ WL_NATOE_XTLV_SKIP_PORT = 6,
+ WL_NATOE_XTLV_TBL_CNT = 7
+};
+
+#endif /* WL_NATOE */
+
+/* rsdb */
+#define ALLOW_SIB_PARALLEL_SCAN (1 << 0)
+#define WL_RSDB_CONFIG_VER 3
+#define MAX_BANDS 2
+#define WL_RSDB_CONFIG_LEN sizeof(rsdb_config_t)
+
+typedef uint8 rsdb_opmode_t;
+typedef uint32 rsdb_flags_t;
+
+typedef enum rsdb_modes {
+ WLC_SDB_MODE_NOSDB_MAIN = 1, /* 2X2 or MIMO mode (applicable only for 4355) */
+ WLC_SDB_MODE_NOSDB_AUX = 2,
+ WLC_SDB_MODE_SDB_MAIN = 3, /* This is RSDB mode(default) applicable only for 4364 */
+ WLC_SDB_MODE_SDB_AUX = 4,
+ WLC_SDB_MODE_SDB_AUTO = 5, /* Same as WLC_RSDB_MODE_RSDB(1+1) mode above */
+} rsdb_modes_t;
+
+typedef struct {
+ uint8 ver;
+ uint8 len; /* length of this structure excluding ver and len */
+ uint16 reserved;
+ rsdb_opmode_t non_infra_mode;
+ rsdb_opmode_t infra_mode[MAX_BANDS];
+ rsdb_flags_t flags[MAX_BANDS];
+ rsdb_opmode_t current_mode; /* Valid only in GET, returns the current mode */
+ uint8 pad[3];
+} rsdb_config_t;
+
+enum wl_idauth_cmd_ids {
+ WL_IDAUTH_CMD_CONFIG = 1,
+ WL_IDAUTH_CMD_PEER_INFO = 2,
+ WL_IDAUTH_CMD_COUNTERS = 3,
+ WL_IDAUTH_CMD_LAST
+};
+enum wl_idauth_xtlv_id {
+ WL_IDAUTH_XTLV_AUTH_ENAB = 0x1,
+ WL_IDAUTH_XTLV_GTK_ROTATION = 0x2,
+ WL_IDAUTH_XTLV_EAPOL_COUNT = 0x3,
+ WL_IDAUTH_XTLV_EAPOL_INTRVL = 0x4,
+ WL_IDAUTH_XTLV_BLKLIST_COUNT = 0x5,
+ WL_IDAUTH_XTLV_BLKLIST_AGE = 0x6,
+ WL_IDAUTH_XTLV_PEERS_INFO = 0x7,
+ WL_IDAUTH_XTLV_COUNTERS = 0x8
+};
+enum wl_idauth_stats {
+ WL_AUTH_PEER_STATE_AUTHORISED = 0x01,
+ WL_AUTH_PEER_STATE_BLACKLISTED = 0x02,
+ WL_AUTH_PEER_STATE_4WAY_HS_ONGOING = 0x03,
+ WL_AUTH_PEER_STATE_LAST
+};
+typedef struct {
+ uint16 state; /* Peer State: Authorised or Blacklisted */
+ struct ether_addr peer_addr; /* peer Address */
+ uint32 blklist_end_time; /* Time of blacklist end */
+} auth_peer_t;
+typedef struct wl_idauth_counters {
+ uint32 auth_reqs; /* No of auth req recvd */
+ uint32 mic_fail; /* No of mic fails */
+ uint32 four_way_hs_fail; /* No of 4-way handshake fails */
+} wl_idauth_counters_t;
+
+#define WLC_UTRACE_LEN 512
+#define WLC_UTRACE_READ_END 0
+#define WLC_UTRACE_MORE_DATA 1
+typedef struct wl_utrace_capture_args_v1 {
+ uint32 length;
+ uint32 flag;
+} wl_utrace_capture_args_v1_t;
+
+#define UTRACE_CAPTURE_VER_2 2
+typedef struct wl_utrace_capture_args_v2 {
+ /* structure control */
+ uint16 version; /**< structure version */
+ uint16 length; /**< length of the response */
+ uint32 flag; /* Indicates if there is more data or not */
+} wl_utrace_capture_args_v2_t;
+
+/* XTLV IDs for the Health Check "hc" iovar top level container */
+enum {
+ WL_HC_XTLV_ID_CAT_HC = 1,
+ WL_HC_XTLV_ID_CAT_DATAPATH_TX = 2, /* Datapath Tx */
+ WL_HC_XTLV_ID_CAT_DATAPATH_RX = 3, /* Datapath Rx */
+};
+
+/* Health Check: Common XTLV IDs for sub-elements in the top level container
+ * Number starts at 0x8000 to be out of the way for category specific IDs.
+ */
+enum {
+ WL_HC_XTLV_ID_ERR = 0x8000, /* for sub-command err return */
+ WL_HC_XTLV_ID_IDLIST = 0x8001, /* container for uint16 IDs */
+};
+
+/* Health Check: Datapath TX IDs */
+enum {
+ WL_HC_TX_XTLV_ID_VAL_STALL_THRESHOLD = 1, /* stall_threshold */
+ WL_HC_TX_XTLV_ID_VAL_STALL_SAMPLE_SIZE = 2, /* stall_sample_size */
+ WL_HC_TX_XTLV_ID_VAL_STALL_TIMEOUT = 3, /* stall_timeout */
+ WL_HC_TX_XTLV_ID_VAL_STALL_FORCE = 4, /* stall_force */
+ WL_HC_TX_XTLV_ID_VAL_STALL_EXCLUDE = 5, /* stall_exclude */
+ WL_HC_TX_XTLV_ID_VAL_FC_TIMEOUT = 6, /* flow ctl timeout */
+ WL_HC_TX_XTLV_ID_VAL_FC_FORCE = 7, /* flow ctl force failure */
+};
+
+/* Health Check: Datapath RX IDs */
+enum {
+ WL_HC_RX_XTLV_ID_VAL_DMA_STALL_TIMEOUT = 1, /* dma_stall_timeout */
+ WL_HC_RX_XTLV_ID_VAL_DMA_STALL_FORCE = 2, /* dma_stall test trigger */
+ WL_HC_RX_XTLV_ID_VAL_STALL_THRESHOLD = 3, /* stall_threshold */
+ WL_HC_RX_XTLV_ID_VAL_STALL_SAMPLE_SIZE = 4, /* stall_sample_size */
+ WL_HC_RX_XTLV_ID_VAL_STALL_FORCE = 5, /* stall test trigger */
+};
+
+/* IDs of Health Check report structures for sub types of health checks within WL */
+enum {
+ WL_HC_DD_UNDEFINED = 0, /* Undefined */
+ WL_HC_DD_RX_DMA_STALL = 1, /* RX DMA stall check */
+ WL_HC_DD_RX_STALL = 2, /* RX stall check */
+ WL_HC_DD_TX_STALL = 3, /* TX stall check */
+ WL_HC_DD_MAX
+};
+
+/*
+ * Health Check report structures for sub types of health checks within WL
+ */
+
+/* Health Check report structure for Rx DMA Stall check */
+typedef struct {
+ uint16 type;
+ uint16 length;
+ uint16 timeout;
+ uint16 stalled_dma_bitmap;
+} wl_rx_dma_hc_info_t;
+
+/* Health Check report structure for Tx packet failure check */
+typedef struct {
+ uint16 type;
+ uint16 length;
+ uint32 stall_bitmap;
+ uint32 stall_bitmap1;
+ uint32 failure_ac;
+ uint32 threshold;
+ uint32 tx_all;
+ uint32 tx_failure_all;
+} wl_tx_hc_info_t;
+
+/* Health Check report structure for Rx dropped packet failure check */
+typedef struct {
+ uint16 type;
+ uint16 length;
+ uint32 bsscfg_idx;
+ uint32 rx_hc_pkts;
+ uint32 rx_hc_dropped_all;
+ uint32 rx_hc_alert_th;
+} wl_rx_hc_info_t;
+
+/* HE top level command IDs */
+enum {
+ WL_HE_CMD_ENAB = 0,
+ WL_HE_CMD_FEATURES = 1,
+ WL_HE_CMD_TWT_SETUP = 2,
+ WL_HE_CMD_TWT_TEARDOWN = 3,
+ WL_HE_CMD_TWT_INFO = 4,
+ WL_HE_CMD_BSSCOLOR = 5,
+ WL_HE_CMD_LAST
+};
+
+
+/* TWT Setup descriptor */
+typedef struct {
+ /* Setup Command. */
+ uint8 setup_cmd; /* See TWT_SETUP_CMD_XXXX in 802.11ah.h,
+ * valid when bcast_twt is FALSE.
+ */
+ /* Flow attributes */
+ uint8 flow_flags; /* See WL_TWT_FLOW_FLAG_XXXX below */
+ uint8 flow_id; /* must be between 0 and 7 */
+ /* Target Wake Time */
+ uint8 wake_type; /* See WL_TWT_TIME_TYPE_XXXX below */
+ uint32 wake_time_h; /* target wake time - BSS TSF (us) */
+ uint32 wake_time_l;
+ uint32 wake_dur; /* target wake duration in us units */
+ uint32 wake_int; /* target wake interval */
+} wl_twt_sdesc_t;
+
+/* Flow flags */
+#define WL_TWT_FLOW_FLAG_BROADCAST (1<<0)
+#define WL_TWT_FLOW_FLAG_IMPLICIT (1<<1)
+#define WL_TWT_FLOW_FLAG_UNANNOUNCED (1<<2)
+#define WL_TWT_FLOW_FLAG_TRIGGER (1<<3)
+
+/* Flow id */
+#define WL_TWT_FLOW_ID_FID 0x07 /* flow id */
+#define WL_TWT_FLOW_ID_GID_MASK 0x70 /* group id - broadcast TWT only */
+#define WL_TWT_FLOW_ID_GID_SHIFT 4
+
+/* Wake type */
+/* TODO: not yet finalized */
+#define WL_TWT_TIME_TYPE_BSS 0 /* The time specified in wake_time_h/l is
+ * the BSS TSF time.
+ */
+#define WL_TWT_TIME_TYPE_OFFSET 1 /* The time specified in wake_time_h/l is an offset
+ * of the TSF time when the iovar is processed.
+ */
+
+#define WL_TWT_SETUP_VER 0
+
+/* HE TWT Setup command */
+typedef struct {
+ /* structure control */
+ uint16 version; /* structure version */
+ uint16 length; /* data length (starting after this field) */
+ /* peer address */
+ struct ether_addr peer; /* leave it all 0s' for AP */
+ /* session id */
+ uint8 dialog; /* an arbitrary number to identify the seesion */
+ uint8 pad;
+ /* setup descriptor */
+ wl_twt_sdesc_t desc;
+} wl_twt_setup_t;
+
+#define WL_TWT_TEARDOWN_VER 0
+
+/* HE TWT Teardown command */
+typedef struct {
+ /* structure control */
+ uint16 version; /* structure version */
+ uint16 length; /* data length (starting after this field) */
+ /* peer address */
+ struct ether_addr peer; /* leave it all 0s' for AP */
+ /* flow attributes */
+ uint8 flow_flags; /* See WL_TWT_FLOW_FLAG_XXXX above.
+ * (only BORADCAST) is applicable)
+ */
+ uint8 flow_id; /* must be between 0 and 7 */
+} wl_twt_teardown_t;
+
+/* twt information descriptor */
+typedef struct {
+ uint8 flow_flags; /* See WL_TWT_INFO_FLAG_XXX below */
+ uint8 flow_id;
+ uint8 pad[2];
+ uint32 next_twt_h;
+ uint32 next_twt_l;
+} wl_twt_idesc_t;
+
+/* Flow flags */
+#define WL_TWT_INFO_FLAG_RESP_REQ (1<<0) /* Request response */
+
+#define WL_TWT_INFO_VER 0
+
+/* HE TWT Information command */
+typedef struct {
+ /* structure control */
+ uint16 version; /* structure version */
+ uint16 length; /* data length (starting after this field) */
+ /* peer address */
+ struct ether_addr peer; /* leave it all 0s' for AP */
+ uint8 pad[2];
+ /* information descriptor */
+ wl_twt_idesc_t desc;
+} wl_twt_info_t;
+
+/* Current version for wlc_clm_power_limits_req_t structure and flags */
+#define WLC_CLM_POWER_LIMITS_REQ_VERSION 1
+/* "clm_power_limits" iovar request structure */
+typedef struct wlc_clm_power_limits_req {
+ /* Input. Structure and flags version */
+ uint32 version;
+ /* Full length of buffer (includes this structure and space for TLV-encoded PPR) */
+ uint32 buflen;
+ /* Input. Flags (see WLC_CLM_POWER_LIMITS_INPUT_FLAG_... below) */
+ uint32 input_flags;
+ /* Input. CC of region whose data is being requested */
+ char cc[WLC_CNTRY_BUF_SZ];
+ /* Input. Channel/subchannel in chanspec_t format */
+ uint32 chanspec;
+ /* Subchannel encoded as clm_limits_type_t */
+ uint32 clm_subchannel;
+ /* Input. 0-based antenna index */
+ uint32 antenna_idx;
+ /* Output. General flags (see WLC_CLM_POWER_LIMITS_OUTPUT_FLAG_... below) */
+ uint32 output_flags;
+ /* Output. 2.4G country flags, encoded as clm_flags_t enum */
+ uint32 clm_country_flags_2g;
+ /* Output. 5G country flags, encoded as clm_flags_t enum */
+ uint32 clm_country_flags_5g;
+ /* Output. Length of TLV-encoded PPR data that follows this structure */
+ uint32 ppr_tlv_size;
+ /* Output. Beginning of buffer for TLV-encoded PPR data */
+ uint8 ppr_tlv[1];
+} wlc_clm_power_limits_req_t;
+
+/* Input. Do not apply SAR limits */
+#define WLC_CLM_POWER_LIMITS_INPUT_FLAG_NO_SAR 0x00000001
+/* Input. Do not apply board limits */
+#define WLC_CLM_POWER_LIMITS_INPUT_FLAG_NO_BOARD 0x00000002
+/* Output. Limits taken from product-specific country data */
+#define WLC_CLM_POWER_LIMITS_OUTPUT_FLAG_PRODUCT_LIMITS 0x00000001
+/* Output. Limits taken from product-specific worldwide data */
+#define WLC_CLM_POWER_LIMITS_OUTPUT_FLAG_WORLDWIDE_LIMITS 0x00000002
+/* Output. Limits taken from country-default (all-product) data */
+#define WLC_CLM_POWER_LIMITS_OUTPUT_FLAG_DEFAULT_COUNTRY_LIMITS 0x00000004
+
+/*
+ * WOG (Wake On Googlecast)
+ */
+
+#define MAX_GCAST_APPID_CNT_LIMIT 50
+#define MAX_DNS_LABEL 63
+
+typedef struct wog_appid {
+ uint8 appID[MAX_DNS_LABEL+1];
+} wog_appid_t;
+
+enum {
+ WOG_APPID_ADD,
+ WOG_APPID_DEL,
+ WOG_APPID_CLEAR,
+ WOG_APPID_LIST,
+ WOG_MAX_APPID_CNT
+};
+
+#define WOG_APPID_IOV_VER 1
+typedef struct wog_appid_iov {
+ /* version for iovar */
+ uint32 ver;
+ /* add/del/clear/list operation */
+ uint32 operation;
+ /* for adding or deleting multiple items */
+ /* for WOG_MAX_APPID_CNT, this value is used for max count for AppID */
+ uint32 cnt;
+ /* Application IDs */
+ /* If FW found an AppID from this list, FW will respond to discovery */
+ /* without wake up the host */
+ wog_appid_t appids[1];
+} wog_appid_iov_t;
+
+/* dns service record */
+/* service name : _googlecast */
+typedef struct wog_srv_record {
+ uint32 ttl;
+ uint16 port; /* tcp 8008 or 8009 */
+ uint8 PAD[2];
+} wog_srv_record_t;
+
+#define GCAST_MAX_MODEL_NAME_LEN 16
+#define GCAST_MAX_FNAME_LEN 64
+#define GCAST_MAX_RS_LEN 60
+
+#define GCAST_UUID_LEN 32
+#define GCAST_PUBLICKEY_ID_LEN 64
+#define GCAST_VER_LEN 2
+typedef struct wog_txt_record {
+ uint32 ttl;
+ /* id : UUID for the receiver */
+ char id[GCAST_UUID_LEN+1];
+
+ /* Cast protocol version supported. Begins at 2 */
+ /* and is incremented by 1 with each version */
+ char ver[GCAST_VER_LEN+1];
+
+ /* 256bit receiver Subject Public Key Identifier from the SSL cert */
+ char public_key[GCAST_PUBLICKEY_ID_LEN+1];
+
+ /* A bitfield of device capabilities. */
+ /* bit 0 : video_out (1:has video out, 0:no video) */
+ /* bit 1 : video_in */
+ /* bit 2 : audio_out */
+ /* bit 3 : audio_in */
+ /* bit 4 : dev_mode */
+ /* (1:dev mode enabled, 0: not enabled) */
+ char capability;
+
+ /* Receiver status flag 0:IDLE, 1(BUSY/JOIN) */
+ /* IDLE : The receiver is idle */
+ /* and doesn't need to be connected now. */
+ /* BUSY/JOIN : The receiver is hosting an activity */
+ /* and invites the sender to join */
+ char receiver_status_flag;
+
+ uint8 PAD0[1];
+
+ char friendly_name[GCAST_MAX_FNAME_LEN+1];
+ uint8 PAD1[3];
+
+ char model_name[GCAST_MAX_MODEL_NAME_LEN+1];
+ uint8 PAD2[3];
+
+ /* Receiver Status text for Cast Protocol v2 */
+ /* Spec says that if the status text exceeds 60 characters in length, */
+ /* it is truncated at 60 caracters and */
+ /* a UTF-8 ellipsis character is appended to indicate trucation. */
+ /* But our dongle won't use UTF-8 ellipsis. It's not a big deal. */
+ char receiver_status[GCAST_MAX_RS_LEN+1];
+ uint8 PAD3[3];
+} wog_txt_record_t;
+
+/* ip will be taken from the ip of wog_info_t */
+typedef struct wog_a_record {
+ uint32 ttl;
+} wog_a_record_t;
+
+/* Google Cast protocl uses mDNS SD for its discovery */
+#define WOG_SD_RESP_VER 1
+typedef struct wog_sd_resp {
+ /* version for iovar */
+ int32 ver;
+ /* device name of Google Cast receiver */
+ char device_name[MAX_DNS_LABEL+1];
+ /* IP address of Google Cast receiver */
+ uint8 ip[4];
+ /* ttl of PTR response */
+ uint32 ptr_ttl;
+ /* DNS TXT record */
+ wog_txt_record_t txt;
+ /* DNS SRV record */
+ wog_srv_record_t srv;
+ /* DNS A record */
+ wog_a_record_t a;
+} wog_sd_resp_t;
+
+enum wl_mbo_cmd_ids {
+ WL_MBO_CMD_ADD_CHAN_PREF = 1,
+ WL_MBO_CMD_DEL_CHAN_PREF = 2,
+ WL_MBO_CMD_LIST_CHAN_PREF = 3,
+ WL_MBO_CMD_CELLULAR_DATA_CAP = 4,
+ WL_MBO_CMD_DUMP_COUNTERS = 5,
+ WL_MBO_CMD_CLEAR_COUNTERS = 6,
+ WL_MBO_CMD_FORCE_ASSOC = 7,
+ WL_MBO_CMD_BSSTRANS_REJECT = 8,
+ /* Add before this !! */
+ WL_MBO_CMD_LAST
+};
+
+enum wl_mbo_xtlv_id {
+ WL_MBO_XTLV_OPCLASS = 0x1,
+ WL_MBO_XTLV_CHAN = 0x2,
+ WL_MBO_XTLV_PREFERENCE = 0x3,
+ WL_MBO_XTLV_REASON_CODE = 0x4,
+ WL_MBO_XTLV_CELL_DATA_CAP = 0x5,
+ WL_MBO_XTLV_COUNTERS = 0x6,
+ WL_MBO_XTLV_ENABLE = 0x7
+};
+
+typedef struct wl_mbo_counters {
+ /* No of transition req recvd */
+ uint16 trans_req_rcvd;
+ /* No of transition req with disassoc imminent */
+ uint16 trans_req_disassoc;
+ /* No of transition req with BSS Termination */
+ uint16 trans_req_bss_term;
+ /* No of trans req w/ unspecified reason */
+ uint16 trans_resn_unspec;
+ /* No of trans req w/ reason frame loss */
+ uint16 trans_resn_frm_loss;
+ /* No of trans req w/ reason traffic delay */
+ uint16 trans_resn_traffic_delay;
+ /* No of trans req w/ reason insufficient buffer */
+ uint16 trans_resn_insuff_bw;
+ /* No of trans req w/ reason load balance */
+ uint16 trans_resn_load_bal;
+ /* No of trans req w/ reason low rssi */
+ uint16 trans_resn_low_rssi;
+ /* No of trans req w/ reason excessive retransmission */
+ uint16 trans_resn_xcess_retransmn;
+ /* No of trans req w/ reason gray zone */
+ uint16 trans_resn_gray_zone;
+ /* No of trans req w/ reason switch to premium AP */
+ uint16 trans_resn_prem_ap_sw;
+ /* No of transition rejection sent */
+ uint16 trans_rejn_sent;
+ /* No of trans rejn reason excessive frame loss */
+ uint16 trans_rejn_xcess_frm_loss;
+ /* No of trans rejn reason excessive traffic delay */
+ uint16 trans_rejn_xcess_traffic_delay;
+ /* No of trans rejn reason insufficient QoS capability */
+ uint16 trans_rejn_insuffic_qos_cap;
+ /* No of trans rejn reason low RSSI */
+ uint16 trans_rejn_low_rssi;
+ /* No of trans rejn reason high interference */
+ uint16 trans_rejn_high_interference;
+ /* No of trans rejn reason service unavilable */
+ uint16 trans_rejn_service_unavail;
+ /* No of beacon request rcvd */
+ uint16 bcn_req_rcvd;
+ /* No of beacon report sent */
+ uint16 bcn_rep_sent;
+ /* No of null beacon report sent */
+ uint16 null_bcn_rep_sent;
+ /* No of wifi to cell switch */
+ uint16 wifi_to_cell;
+} wl_mbo_counters_t;
+
+/* otpread command */
+#define WL_OTPREAD_VER 1
+
+typedef struct {
+ uint16 version; /* cmd structure version */
+ uint16 cmd_len; /* cmd struct len */
+ uint32 rdmode; /* otp read mode */
+ uint32 rdoffset; /* byte offset into otp to start read */
+ uint32 rdsize; /* number of bytes to read */
+} wl_otpread_cmd_t;
+
+#define WL_LEAKY_AP_STATS_GT_TYPE 0
+#define WL_LEAKY_AP_STATS_PKT_TYPE 1
+typedef struct wlc_leaked_infra_guard_marker {
+ /* type field for this TLV: WL_LEAKY_AP_STATS_GT_TYPE */
+ uint16 type;
+ /* length field for this TLV */
+ uint16 len;
+ /* guard sample sequence number; Updated by 1 on every guard sample */
+ uint32 seq_number;
+ /* Guard time start time (tsf; PS indicated and acked) */
+ uint32 start_time;
+ /* tsf timestamp for the GT end event */
+ uint32 gt_tsf_l;
+ /* Guard time period in ms */
+ uint16 guard_duration;
+ /* Number PPDUs in the notification */
+ uint16 num_pkts;
+ /* Flags to indicate some states see below */
+ uint8 flag;
+ /* pad for 32-bit alignment */
+ uint8 reserved[3];
+} wlc_leaked_infra_guard_marker_t;
+
+/* Flag information */
+#define WL_LEAKED_GUARD_TIME_NONE 0 /* Not in any guard time */
+#define WL_LEAKED_GUARD_TIME_FRTS (0x01 << 0) /* Normal FRTS power save */
+#define WL_LEAKED_GUARD_TIME_SCAN (0x01 << 1) /* Channel switch due to scanning */
+#define WL_LEAKED_GUARD_TIME_AWDL_PSF (0x01 << 2) /* Channel switch due to AWDL PSF */
+#define WL_LEAKED_GUARD_TIME_AWDL_AW (0x01 << 3) /* Channel switch due to AWDL AW */
+#define WL_LEAKED_GUARD_TIME_TERMINATED (0x01 << 7) /* indicate a GT is terminated early */
+
+typedef struct wlc_leaked_infra_packet_stat {
+ uint16 type; /* type field for this TLV: WL_LEAKY_AP_STATS_PKT_TYPE */
+ uint16 len; /* length field for this TLV */
+ uint16 ppdu_len_bytes; /* PPDU packet length in bytes */
+ uint16 num_mpdus; /* number of the MPDUs in the PPDU */
+ uint32 ppdu_time; /* PPDU arrival time at the begining of the guard time */
+ uint32 rate; /* PPDU packet rate; Received packet's data rate */
+ uint16 seq_number; /* sequence number */
+ int8 rssi; /* RSSI */
+ uint8 tid; /* tid */
+} wlc_leaked_infra_packet_stat_t;
+
+/* Wake timer structure definition */
+#define WAKE_TIMER_VERSION 1
+#define WAKE_TIMER_NOLIMIT 0xFFFF
+
+typedef struct wake_timer {
+ uint16 ver;
+ uint16 len;
+ uint16 limit; /* number of events to deliver
+ * 0-disable, 0xffff-indefinite, num_events otherwise
+ */
+ uint16 count; /* number of events delivered since enable (get only) */
+ uint16 period; /* timeout/period in milliseconds */
+} wake_timer_t;
+
+typedef struct wl_desense_restage_gain {
+ uint16 version;
+ uint16 length;
+ uint band;
+ uint8 num_cores;
+ uint8 desense_array[WL_TX_CHAINS_MAX];
+} wl_desense_restage_gain_t;
+
+#define MAX_UCM_CHAINS 5
+#define MAX_UCM_PROFILES 4
+#define UCM_PROFILE_VERSION_1 1
+
+/* UCM per chain attribute struct */
+typedef struct wlc_btcx_chain_attr {
+ uint16 length; /* chain attr length, version is same as profile version */
+ int8 desense_level; /* per chain desense level */
+ int8 ack_pwr_strong_rssi; /* per chain ack power at strong rssi */
+ int8 ack_pwr_weak_rssi; /* per chain ack power at weak rssi */
+ int8 tx_pwr_strong_rssi; /* per chain tx power at strong rssi */
+ int8 tx_pwr_weak_rssi; /* per chain tx power at weak rssi */
+ uint8 PAD[1]; /* additional bytes for alignment */
+} wlc_btcx_chain_attr_t;
+
+typedef struct wlc_btcx_profile_v1 {
+ uint16 version; /* UCM profile version */
+ uint16 length; /* profile size */
+ uint16 fixed_length; /* size of the fixed portion of the profile */
+ uint8 init; /* profile initialized or not */
+ uint8 chain_attr_count; /* Number of elements in chain_attr array */
+ uint8 profile_index; /* profile index */
+ uint8 mode_strong_wl_bt; /* Mode under strong WLAN and BT RSSI */
+ uint8 mode_weak_wl; /* Mode under weak WLAN RSSI */
+ uint8 mode_weak_bt; /* Mode under weak BT RSSI */
+ uint8 mode_weak_wl_bt; /* Mode under weak BT and WLAN RSSI */
+ int8 mode_wl_hi_lo_rssi_thresh; /* Strong to weak WLAN RSSI threshold for mode selection */
+ int8 mode_wl_lo_hi_rssi_thresh; /* Weak to strong WLAN RSSI threshold for mode selection */
+ int8 mode_bt_hi_lo_rssi_thresh; /* Strong to weak BT RSSI threshold for mode selection */
+ int8 mode_bt_lo_hi_rssi_thresh; /* Weak to strong BT RSSI threshold for mode selection */
+ int8 desense_wl_hi_lo_rssi_thresh; /* Strong to weak RSSI threshold for desense */
+ int8 desense_wl_lo_hi_rssi_thresh; /* Weak to strong RSSI threshold for desense */
+ int8 ack_pwr_wl_hi_lo_rssi_thresh; /* Strong to weak RSSI threshold for ACK power */
+ int8 ack_pwr_wl_lo_hi_rssi_thresh; /* Weak to strong RSSI threshold for ACK power */
+ int8 tx_pwr_wl_hi_lo_rssi_thresh; /* Strong to weak RSSI threshold for Tx power */
+ int8 tx_pwr_wl_lo_hi_rssi_thresh; /* Weak to strong RSSI threshold for Tx power */
+ uint8 PAD[1]; /* additional bytes for 4 byte alignment */
+ wlc_btcx_chain_attr_t chain_attr[]; /* variable length array with chain attributes */
+} wlc_btcx_profile_v1_t;
+
+typedef struct {
+ uint8 ipaddr[IPV4_ADDR_LEN];
+ uint8 ipaddr_netmask[IPV4_ADDR_LEN];
+ uint8 ipaddr_gateway[IPV4_ADDR_LEN];
+} netx_ifconfig_t;
+
+#ifdef TBTT_OFFSET_STAT
+/* XXX: tbtt offset stat is only for primary STA and non-p2p link */
+typedef struct {
+ uint32 tbtt_offset_avg;
+ uint32 tbtt_offset_min;
+ uint32 tbtt_offset_max;
+} tbtt_offset_stat_t;
+#endif /* TBTT_OFFSET_STAT */
+
+#endif /* _wlioctl_h_ */
diff --git a/wl/components/shared/devctrl_if/wlioctl_defs.h b/wl/components/shared/devctrl_if/wlioctl_defs.h
new file mode 100644
index 0000000..510c3fe
--- /dev/null
+++ b/wl/components/shared/devctrl_if/wlioctl_defs.h
@@ -0,0 +1,2278 @@
+/*
+ * Custom OID/ioctl definitions for
+ * Broadcom 802.11abg Networking Device Driver
+ *
+ * Definitions subject to change without notice.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wlioctl_defs.h 660256 2016-09-19 22:24:03Z $
+ */
+
+
+#ifndef wlioctl_defs_h
+#define wlioctl_defs_h
+
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+
+
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/* All builds use the new 11ac ratespec/chanspec */
+#undef D11AC_IOTYPES
+#define D11AC_IOTYPES
+
+/* WL_RSPEC defines for rate information */
+#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */
+#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /* VHT MCS value */
+#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /* VHT Nss value */
+#define WL_RSPEC_VHT_NSS_SHIFT 4 /* VHT Nss value shift */
+#define WL_RSPEC_TXEXP_MASK 0x00000300
+#define WL_RSPEC_TXEXP_SHIFT 8
+#define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */
+#define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */
+#define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */
+#define WL_RSPEC_TXBF 0x00200000 /* bit indicates TXBF mode */
+#define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */
+#define WL_RSPEC_SGI 0x00800000 /* Short GI mode */
+#define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */
+#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /* bit indicate to override mcs only */
+#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /* bit indicates override both rate & mode */
+
+/* WL_RSPEC_ENCODING field defs */
+#define WL_RSPEC_ENCODE_RATE 0x00000000 /* Legacy rate is stored in RSPEC_RATE_MASK */
+#define WL_RSPEC_ENCODE_HT 0x01000000 /* HT MCS is stored in RSPEC_RATE_MASK */
+#define WL_RSPEC_ENCODE_VHT 0x02000000 /* VHT MCS and Nss is stored in RSPEC_RATE_MASK */
+
+/* WL_RSPEC_BW field defs */
+#define WL_RSPEC_BW_UNSPECIFIED 0
+#define WL_RSPEC_BW_20MHZ 0x00010000
+#define WL_RSPEC_BW_40MHZ 0x00020000
+#define WL_RSPEC_BW_80MHZ 0x00030000
+#define WL_RSPEC_BW_160MHZ 0x00040000
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_RSPEC_BW_10MHZ 0x00050000
+#define WL_RSPEC_BW_5MHZ 0x00060000
+#define WL_RSPEC_BW_2P5MHZ 0x00070000
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* Legacy defines for the nrate iovar */
+#define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */
+#define OLD_NRATE_RATE_MASK 0x0000007f /* rate/mcs value */
+#define OLD_NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */
+#define OLD_NRATE_STF_SHIFT 8 /* stf mode shift */
+#define OLD_NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */
+#define OLD_NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */
+#define OLD_NRATE_SGI 0x00800000 /* sgi mode */
+#define OLD_NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */
+
+#define OLD_NRATE_STF_SISO 0 /* stf mode SISO */
+#define OLD_NRATE_STF_CDD 1 /* stf mode CDD */
+#define OLD_NRATE_STF_STBC 2 /* stf mode STBC */
+#define OLD_NRATE_STF_SDM 3 /* stf mode SDM */
+
+#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WLC_11N_N_PROP_MCS 6
+#define WLC_11N_FIRST_PROP_MCS 87
+#define WLC_11N_LAST_PROP_MCS 102
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#ifndef OEM_ANDROID
+/* given a proprietary MCS, get number of spatial streams */
+#define GET_PROPRIETARY_11N_MCS_NSS(mcs) (1 + ((mcs) - 85) / 8)
+
+#define GET_11N_MCS_NSS(mcs) ((mcs) < 32 ? (1 + ((mcs) / 8)) \
+ : ((mcs) == 32 ? 1 : GET_PROPRIETARY_11N_MCS_NSS(mcs)))
+#endif /* !OEM_ANDROID */
+
+#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */
+#ifdef DONGLEBUILD
+#define MAX_CCA_SECS 1 /* CCA keeps this many seconds history - trimmed for dongle */
+#else
+#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */
+#endif
+
+#define IBSS_MED 15 /* Mediom in-bss congestion percentage */
+#define IBSS_HI 25 /* Hi in-bss congestion percentage */
+#define OBSS_MED 12
+#define OBSS_HI 25
+#define INTERFER_MED 5
+#define INTERFER_HI 10
+
+#define CCA_FLAG_2G_ONLY 0x01 /* Return a channel from 2.4 Ghz band */
+#define CCA_FLAG_5G_ONLY 0x02 /* Return a channel from 2.4 Ghz band */
+#define CCA_FLAG_IGNORE_DURATION 0x04 /* Ignore dwell time for each channel */
+#define CCA_FLAGS_PREFER_1_6_11 0x10
+#define CCA_FLAG_IGNORE_INTERFER 0x20 /* do not exlude channel based on interfer level */
+
+#define CCA_ERRNO_BAND 1 /* After filtering for band pref, no choices left */
+#define CCA_ERRNO_DURATION 2 /* After filtering for duration, no choices left */
+#define CCA_ERRNO_PREF_CHAN 3 /* After filtering for chan pref, no choices left */
+#define CCA_ERRNO_INTERFER 4 /* After filtering for interference, no choices left */
+#define CCA_ERRNO_TOO_FEW 5 /* Only 1 channel was input */
+
+#define WL_STA_AID(a) ((a) &~ 0xc000)
+
+/* Flags for sta_info_t indicating properties of STA */
+#define WL_STA_BRCM 0x00000001 /* Running a Broadcom driver */
+#define WL_STA_WME 0x00000002 /* WMM association */
+#define WL_STA_NONERP 0x00000004 /* No ERP */
+#define WL_STA_AUTHE 0x00000008 /* Authenticated */
+#define WL_STA_ASSOC 0x00000010 /* Associated */
+#define WL_STA_AUTHO 0x00000020 /* Authorized */
+#define WL_STA_WDS 0x00000040 /* Wireless Distribution System */
+#define WL_STA_WDS_LINKUP 0x00000080 /* WDS traffic/probes flowing properly */
+#define WL_STA_PS 0x00000100 /* STA is in power save mode from AP's viewpoint */
+#define WL_STA_APSD_BE 0x00000200 /* APSD delv/trigger for AC_BE is default enabled */
+#define WL_STA_APSD_BK 0x00000400 /* APSD delv/trigger for AC_BK is default enabled */
+#define WL_STA_APSD_VI 0x00000800 /* APSD delv/trigger for AC_VI is default enabled */
+#define WL_STA_APSD_VO 0x00001000 /* APSD delv/trigger for AC_VO is default enabled */
+#define WL_STA_N_CAP 0x00002000 /* STA 802.11n capable */
+#define WL_STA_SCBSTATS 0x00004000 /* Per STA debug stats */
+#define WL_STA_AMPDU_CAP 0x00008000 /* STA AMPDU capable */
+#define WL_STA_AMSDU_CAP 0x00010000 /* STA AMSDU capable */
+#define WL_STA_MIMO_PS 0x00020000 /* mimo ps mode is enabled */
+#define WL_STA_MIMO_RTS 0x00040000 /* send rts in mimo ps mode */
+#define WL_STA_RIFS_CAP 0x00080000 /* rifs enabled */
+#define WL_STA_VHT_CAP 0x00100000 /* STA VHT(11ac) capable */
+#define WL_STA_WPS 0x00200000 /* WPS state */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_STA_DWDS_CAP 0x01000000 /* DWDS CAP */
+#define WL_STA_DWDS 0x02000000 /* DWDS active */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */
+
+/* STA HT cap fields */
+#define WL_STA_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */
+#define WL_STA_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */
+#define WL_STA_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */
+#define WL_STA_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */
+#define WL_STA_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */
+#define WL_STA_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */
+#define WL_STA_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */
+#define WL_STA_CAP_GF 0x0010 /* Greenfield preamble support */
+#define WL_STA_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */
+#define WL_STA_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */
+#define WL_STA_CAP_TX_STBC 0x0080 /* Tx STBC support */
+#define WL_STA_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */
+#define WL_STA_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */
+#define WL_STA_CAP_DELAYED_BA 0x0400 /* delayed BA support */
+#define WL_STA_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */
+#define WL_STA_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */
+#define WL_STA_CAP_PSMP 0x2000 /* Power Save Multi Poll support */
+#define WL_STA_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */
+#define WL_STA_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */
+
+#define WL_STA_CAP_RX_STBC_NO 0x0 /* no rx STBC support */
+#define WL_STA_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */
+#define WL_STA_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */
+#define WL_STA_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */
+
+/* scb vht flags */
+#define WL_STA_VHT_LDPCCAP 0x0001
+#define WL_STA_SGI80 0x0002
+#define WL_STA_SGI160 0x0004
+#define WL_STA_VHT_TX_STBCCAP 0x0008
+#define WL_STA_VHT_RX_STBCCAP 0x0010
+#define WL_STA_SU_BEAMFORMER 0x0020
+#define WL_STA_SU_BEAMFORMEE 0x0040
+#define WL_STA_MU_BEAMFORMER 0x0080
+#define WL_STA_MU_BEAMFORMEE 0x0100
+#define WL_STA_VHT_TXOP_PS 0x0200
+#define WL_STA_HTC_VHT_CAP 0x0400
+
+/* Values for TX Filter override mode */
+#define WLC_TXFILTER_OVERRIDE_DISABLED 0
+#define WLC_TXFILTER_OVERRIDE_ENABLED 1
+
+#define WL_IOCTL_ACTION_GET 0x0
+#define WL_IOCTL_ACTION_SET 0x1
+#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e
+#define WL_IOCTL_ACTION_OVL_RSV 0x20
+#define WL_IOCTL_ACTION_OVL 0x40
+#define WL_IOCTL_ACTION_MASK 0x7e
+#define WL_IOCTL_ACTION_OVL_SHIFT 1
+
+/* For WLC_SET_INFRA ioctl & infra_configuration iovar SET/GET operations */
+#define WL_BSSTYPE_INDEP 0
+#define WL_BSSTYPE_INFRA 1
+#define WL_BSSTYPE_ANY 2 /* deprecated */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_BSSTYPE_MESH 3
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/* Bitmask for scan_type */
+#define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */
+#define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */
+#define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */
+#define WL_SCANFLAGS_OFFCHAN 0x08 /* allow scanning/reporting off-channel APs */
+#define WL_SCANFLAGS_HOTSPOT 0x10 /* automatic ANQP to hotspot APs */
+#define WL_SCANFLAGS_SWTCHAN 0x20 /* Force channel switch for differerent bandwidth */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_SCANFLAGS_FORCE_PARALLEL 0x40 /* Force parallel scan even when actcb_fn_t is on.
+ * by default parallel scan will be disabled if actcb_fn_t
+ * is provided.
+ */
+#define WL_SCANFLAGS_SISO 0x40 /* Use 1 RX chain for scanning */
+#define WL_SCANFLAGS_MIMO 0x80 /* Force MIMO scanning */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* wl_iscan_results status values */
+#define WL_SCAN_RESULTS_SUCCESS 0
+#define WL_SCAN_RESULTS_PARTIAL 1
+#define WL_SCAN_RESULTS_PENDING 2
+#define WL_SCAN_RESULTS_ABORTED 3
+#define WL_SCAN_RESULTS_NO_MEM 4
+
+#define SCANOL_ENABLED (1 << 0)
+#define SCANOL_BCAST_SSID (1 << 1)
+#define SCANOL_NOTIFY_BCAST_SSID (1 << 2)
+#define SCANOL_RESULTS_PER_CYCLE (1 << 3)
+
+/* scan times in milliseconds */
+#define SCANOL_HOME_TIME 45 /* for home channel processing */
+#define SCANOL_ASSOC_TIME 20 /* dwell on a channel while associated */
+#define SCANOL_UNASSOC_TIME 40 /* dwell on a channel while unassociated */
+#define SCANOL_PASSIVE_TIME 110 /* listen on a channelfor passive scan */
+#define SCANOL_AWAY_LIMIT 100 /* max time to be away from home channel */
+#define SCANOL_IDLE_REST_TIME 40
+#define SCANOL_IDLE_REST_MULTIPLIER 0
+#define SCANOL_ACTIVE_REST_TIME 20
+#define SCANOL_ACTIVE_REST_MULTIPLIER 0
+#define SCANOL_CYCLE_IDLE_REST_TIME 300000 /* Idle Rest Time between Scan Cycle (msec) */
+#define SCANOL_CYCLE_IDLE_REST_MULTIPLIER 0 /* Idle Rest Time Multiplier */
+#define SCANOL_CYCLE_ACTIVE_REST_TIME 200
+#define SCANOL_CYCLE_ACTIVE_REST_MULTIPLIER 0
+#define SCANOL_MAX_REST_TIME 3600000 /* max rest time between scan cycle (msec) */
+#define SCANOL_CYCLE_DEFAULT 0 /* default for Max Scan Cycle, 0 = forever */
+#define SCANOL_CYCLE_MAX 864000 /* Max Scan Cycle */
+ /* 10 sec/scan cycle => 100 days */
+#define SCANOL_NPROBES 2 /* for Active scan; send n probes on each channel */
+#define SCANOL_NPROBES_MAX 5 /* for Active scan; send n probes on each channel */
+#define SCANOL_SCAN_START_DLY 10 /* delay start of offload scan (sec) */
+#define SCANOL_SCAN_START_DLY_MAX 240 /* delay start of offload scan (sec) */
+#define SCANOL_MULTIPLIER_MAX 10 /* Max Multiplier */
+#define SCANOL_UNASSOC_TIME_MAX 100 /* max dwell on a channel while unassociated */
+#define SCANOL_PASSIVE_TIME_MAX 500 /* max listen on a channel for passive scan */
+#define SCANOL_SSID_MAX 16 /* max supported preferred SSID */
+
+/* masks for channel and ssid count */
+#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff
+#define WL_SCAN_PARAMS_NSSID_SHIFT 16
+
+#define WL_SCAN_ACTION_START 1
+#define WL_SCAN_ACTION_CONTINUE 2
+#define WL_SCAN_ACTION_ABORT 3
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#if defined(SIMPLE_ISCAN)
+#define ISCAN_RETRY_CNT 5
+#define ISCAN_STATE_IDLE 0
+#define ISCAN_STATE_SCANING 1
+#define ISCAN_STATE_PENDING 2
+#endif /* SIMPLE_ISCAN */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+#define ANTENNA_NUM_1 1 /* total number of antennas to be used */
+#define ANTENNA_NUM_2 2
+#define ANTENNA_NUM_3 3
+#define ANTENNA_NUM_4 4
+
+#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */
+#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */
+#define ANT_SELCFG_TX_UNICAST 0 /* unicast tx antenna configuration */
+#define ANT_SELCFG_RX_UNICAST 1 /* unicast rx antenna configuration */
+#define ANT_SELCFG_TX_DEF 2 /* default tx antenna configuration */
+#define ANT_SELCFG_RX_DEF 3 /* default rx antenna configuration */
+
+/* interference source detection and identification mode */
+#define ITFR_MODE_DISABLE 0 /* disable feature */
+#define ITFR_MODE_MANUAL_ENABLE 1 /* enable manual detection */
+#define ITFR_MODE_AUTO_ENABLE 2 /* enable auto detection */
+
+/* bit definitions for flags in interference source report */
+#define ITFR_INTERFERENCED 1 /* interference detected */
+#define ITFR_HOME_CHANNEL 2 /* home channel has interference */
+#define ITFR_NOISY_ENVIRONMENT 4 /* noisy environemnt so feature stopped */
+
+#define WL_NUM_RPI_BINS 8
+#define WL_RM_TYPE_BASIC 1
+#define WL_RM_TYPE_CCA 2
+#define WL_RM_TYPE_RPI 3
+#define WL_RM_TYPE_ABORT -1 /* ABORT any in-progress RM request */
+
+#define WL_RM_FLAG_PARALLEL (1<<0)
+
+#define WL_RM_FLAG_LATE (1<<1)
+#define WL_RM_FLAG_INCAPABLE (1<<2)
+#define WL_RM_FLAG_REFUSED (1<<3)
+
+/* flags */
+#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */
+
+#define WLC_CIS_DEFAULT 0 /* built-in default */
+#define WLC_CIS_SROM 1 /* source is sprom */
+#define WLC_CIS_OTP 2 /* source is otp */
+
+/* PCL - Power Control Loop */
+/* current gain setting is replaced by user input */
+#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */
+#define WL_ATTEN_PCL_ON 1 /* turn on PCL */
+/* current gain setting is maintained */
+#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */
+
+/* defines used by poweridx iovar - it controls power in a-band */
+/* current gain setting is maintained */
+#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */
+#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */
+#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */
+#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */
+/* value >= 0 causes
+ * - input to be set to that value
+ * - PCL to be off
+ */
+
+#define BCM_MAC_STATUS_INDICATION (0x40010200L)
+
+/* Values for TX Filter override mode */
+#define WLC_TXFILTER_OVERRIDE_DISABLED 0
+#define WLC_TXFILTER_OVERRIDE_ENABLED 1
+
+/* magic pattern used for mismatch driver and wl */
+#define WL_TXFIFO_SZ_MAGIC 0xa5a5
+
+/* check this magic number */
+#define WLC_IOCTL_MAGIC 0x14e46c77
+
+
+/* bss_info_cap_t flags */
+#define WL_BSS_FLAGS_FROM_BEACON 0x01 /* bss_info derived from beacon */
+#define WL_BSS_FLAGS_FROM_CACHE 0x02 /* bss_info collected from cache */
+#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 /* rssi info received on channel (vs offchannel) */
+#define WL_BSS_FLAGS_HS20 0x08 /* hotspot 2.0 capable */
+#define WL_BSS_FLAGS_RSSI_INVALID 0x10 /* BSS contains invalid RSSI */
+#define WL_BSS_FLAGS_RSSI_INACCURATE 0x20 /* BSS contains inaccurate RSSI */
+#define WL_BSS_FLAGS_SNR_INVALID 0x40 /* BSS contains invalid SNR */
+#define WL_BSS_FLAGS_NF_INVALID 0x80 /* BSS contains invalid noise floor */
+
+/* bit definitions for bcnflags in wl_bss_info */
+#define WL_BSS_BCNFLAGS_INTERWORK_PRESENT 0x01 /* beacon had IE, accessnet valid */
+#define WL_BSS_BCNFLAGS_INTERWORK_PRESENT_VALID 0x02 /* on indicates support for this API */
+
+/* bssinfo flag for nbss_cap */
+#define VHT_BI_SGI_80MHZ 0x00000100
+#define VHT_BI_80MHZ 0x00000200
+#define VHT_BI_160MHZ 0x00000400
+#define VHT_BI_8080MHZ 0x00000800
+
+/* reference to wl_ioctl_t struct used by usermode driver */
+#define ioctl_subtype set /* subtype param */
+#define ioctl_pid used /* pid param */
+#define ioctl_status needed /* status param */
+
+
+/* Enumerate crypto algorithms */
+#define CRYPTO_ALGO_OFF 0
+#define CRYPTO_ALGO_WEP1 1
+#define CRYPTO_ALGO_TKIP 2
+#define CRYPTO_ALGO_WEP128 3
+#define CRYPTO_ALGO_AES_CCM 4
+#define CRYPTO_ALGO_AES_OCB_MSDU 5
+#define CRYPTO_ALGO_AES_OCB_MPDU 6
+#define CRYPTO_ALGO_NALG 7
+
+#define CRYPTO_ALGO_SMS4 11
+#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */
+#define CRYPTO_ALGO_BIP 13 /* 802.11w BIP (aes cmac) */
+
+#define CRYPTO_ALGO_AES_GCM 14 /* 128 bit GCM */
+#define CRYPTO_ALGO_AES_CCM256 15 /* 256 bit CCM */
+#define CRYPTO_ALGO_AES_GCM256 16 /* 256 bit GCM */
+#define CRYPTO_ALGO_BIP_CMAC256 17 /* 256 bit BIP CMAC */
+#define CRYPTO_ALGO_BIP_GMAC 18 /* 128 bit BIP GMAC */
+#define CRYPTO_ALGO_BIP_GMAC256 19 /* 256 bit BIP GMAC */
+
+#define CRYPTO_ALGO_NONE CRYPTO_ALGO_OFF
+
+/* algo bit vector */
+#define KEY_ALGO_MASK(_algo) (1 << _algo)
+
+
+#define KEY_ALGO_MASK_WEP (KEY_ALGO_MASK(CRYPTO_ALGO_WEP1) | \
+ KEY_ALGO_MASK(CRYPTO_ALGO_WEP128) | \
+ KEY_ALGO_MASK(CRYPTO_ALGO_NALG))
+
+#define KEY_ALGO_MASK_AES (KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM) | \
+ KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM256) | \
+ KEY_ALGO_MASK(CRYPTO_ALGO_AES_GCM) | \
+ KEY_ALGO_MASK(CRYPTO_ALGO_AES_GCM256))
+#define KEY_ALGO_MASK_TKIP (KEY_ALGO_MASK(CRYPTO_ALGO_TKIP))
+#define KEY_ALGO_MASK_WAPI (KEY_ALGO_MASK(CRYPTO_ALGO_SMS4))
+
+#define WSEC_GEN_MIC_ERROR 0x0001
+#define WSEC_GEN_REPLAY 0x0002
+#define WSEC_GEN_ICV_ERROR 0x0004
+#define WSEC_GEN_MFP_ACT_ERROR 0x0008
+#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010
+#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020
+
+#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */
+#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */
+#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */
+#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */
+#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */
+
+/* wireless security bitvec */
+#define WEP_ENABLED 0x0001
+#define TKIP_ENABLED 0x0002
+#define AES_ENABLED 0x0004
+#define WSEC_SWFLAG 0x0008
+#define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */
+#ifdef WLFIPS
+#define FIPS_ENABLED 0x0080
+#endif /* WLFIPS */
+
+#ifdef DONGLEBUILD
+/* wsec macros for operating on the above definitions */
+#ifdef WLWSEC
+#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED)
+#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED)
+#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED)
+#else
+#define WSEC_WEP_ENABLED(wsec) NULL
+#define WSEC_TKIP_ENABLED(wsec) NULL
+#define WSEC_AES_ENABLED(wsec) NULL
+#endif /* WLWSEC */
+#else
+#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED)
+#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED)
+#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED)
+#endif /* DONGLEBUILD */
+
+#ifdef DONGLEBUILD
+#ifdef WLWSEC
+#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
+#else
+#define WSEC_ENABLED(wsec) 0
+#endif /* WLWSEC */
+#else
+#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
+#endif /* DONGLEBUILD */
+
+#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED)
+#ifdef BCMWAPI_WAI
+#define WSEC_SMS4_ENABLED(wsec) ((wsec) & SMS4_ENABLED)
+#endif /* BCMWAPI_WAI */
+
+
+/* Following macros are not used any more. Just kept here to
+ * avoid build issue in BISON/CARIBOU branch
+ */
+#define MFP_CAPABLE 0x0200
+#define MFP_REQUIRED 0x0400
+#define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */
+
+/* WPA authentication mode bitvec */
+#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */
+#define WPA_AUTH_NONE 0x0001 /* none (IBSS) */
+#define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */
+#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */
+/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */
+#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */
+#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */
+#define BRCM_AUTH_PSK 0x0100 /* BRCM specific PSK */
+#define BRCM_AUTH_DPT 0x0200 /* DPT PSK without group keys */
+#if defined(BCMWAPI_WAI)
+#define WPA_AUTH_WAPI 0x0400
+#define WAPI_AUTH_NONE WPA_AUTH_NONE /* none (IBSS) */
+#define WAPI_AUTH_UNSPECIFIED 0x0400 /* over AS */
+#define WAPI_AUTH_PSK 0x0800 /* Pre-shared key */
+#endif
+#define WPA2_AUTH_1X_SHA256 0x1000 /* 1X with SHA256 key derivation */
+#define WPA2_AUTH_TPK 0x2000 /* TDLS Peer Key */
+#define WPA2_AUTH_FT 0x4000 /* Fast Transition. */
+#define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */
+/* WPA2_AUTH_SHA256 not used anymore. Just kept here to avoid build issue in DINGO */
+#define WPA2_AUTH_SHA256 0x8000
+#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */
+
+/* pmkid */
+#define MAXPMKID 16
+
+/* SROM12 changes */
+#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */
+
+
+#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */
+#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */
+#if defined(LCNCONF) || defined(LCN40CONF) || defined(LCN20CONF)
+#define WLC_SAMPLECOLLECT_MAXLEN 8192 /* Max Sample Collect buffer */
+#else
+#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */
+#endif
+#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192
+
+/* common ioctl definitions */
+#define WLC_GET_MAGIC 0
+#define WLC_GET_VERSION 1
+#define WLC_UP 2
+#define WLC_DOWN 3
+#define WLC_GET_LOOP 4
+#define WLC_SET_LOOP 5
+#define WLC_DUMP 6
+#define WLC_GET_MSGLEVEL 7
+#define WLC_SET_MSGLEVEL 8
+#define WLC_GET_PROMISC 9
+#define WLC_SET_PROMISC 10
+/* #define WLC_OVERLAY_IOCTL 11 */ /* not supported */
+#define WLC_GET_RATE 12
+#define WLC_GET_MAX_RATE 13
+#define WLC_GET_INSTANCE 14
+/* #define WLC_GET_FRAG 15 */ /* no longer supported */
+/* #define WLC_SET_FRAG 16 */ /* no longer supported */
+/* #define WLC_GET_RTS 17 */ /* no longer supported */
+/* #define WLC_SET_RTS 18 */ /* no longer supported */
+#define WLC_GET_INFRA 19
+#define WLC_SET_INFRA 20
+#define WLC_GET_AUTH 21
+#define WLC_SET_AUTH 22
+#define WLC_GET_BSSID 23
+#define WLC_SET_BSSID 24
+#define WLC_GET_SSID 25
+#define WLC_SET_SSID 26
+#define WLC_RESTART 27
+#define WLC_TERMINATED 28
+/* #define WLC_DUMP_SCB 28 */ /* no longer supported */
+#define WLC_GET_CHANNEL 29
+#define WLC_SET_CHANNEL 30
+#define WLC_GET_SRL 31
+#define WLC_SET_SRL 32
+#define WLC_GET_LRL 33
+#define WLC_SET_LRL 34
+#define WLC_GET_PLCPHDR 35
+#define WLC_SET_PLCPHDR 36
+#define WLC_GET_RADIO 37
+#define WLC_SET_RADIO 38
+#define WLC_GET_PHYTYPE 39
+#define WLC_DUMP_RATE 40
+#define WLC_SET_RATE_PARAMS 41
+#define WLC_GET_FIXRATE 42
+#define WLC_SET_FIXRATE 43
+/* #define WLC_GET_WEP 42 */ /* no longer supported */
+/* #define WLC_SET_WEP 43 */ /* no longer supported */
+#define WLC_GET_KEY 44
+#define WLC_SET_KEY 45
+#define WLC_GET_REGULATORY 46
+#define WLC_SET_REGULATORY 47
+#define WLC_GET_PASSIVE_SCAN 48
+#define WLC_SET_PASSIVE_SCAN 49
+#define WLC_SCAN 50
+#define WLC_SCAN_RESULTS 51
+#define WLC_DISASSOC 52
+#define WLC_REASSOC 53
+#define WLC_GET_ROAM_TRIGGER 54
+#define WLC_SET_ROAM_TRIGGER 55
+#define WLC_GET_ROAM_DELTA 56
+#define WLC_SET_ROAM_DELTA 57
+#define WLC_GET_ROAM_SCAN_PERIOD 58
+#define WLC_SET_ROAM_SCAN_PERIOD 59
+#define WLC_EVM 60 /* diag */
+#define WLC_GET_TXANT 61
+#define WLC_SET_TXANT 62
+#define WLC_GET_ANTDIV 63
+#define WLC_SET_ANTDIV 64
+/* #define WLC_GET_TXPWR 65 */ /* no longer supported */
+/* #define WLC_SET_TXPWR 66 */ /* no longer supported */
+#define WLC_GET_CLOSED 67
+#define WLC_SET_CLOSED 68
+#define WLC_GET_MACLIST 69
+#define WLC_SET_MACLIST 70
+#define WLC_GET_RATESET 71
+#define WLC_SET_RATESET 72
+/* #define WLC_GET_LOCALE 73 */ /* no longer supported */
+#define WLC_LONGTRAIN 74
+#define WLC_GET_BCNPRD 75
+#define WLC_SET_BCNPRD 76
+#define WLC_GET_DTIMPRD 77
+#define WLC_SET_DTIMPRD 78
+#define WLC_GET_SROM 79
+#define WLC_SET_SROM 80
+#define WLC_GET_WEP_RESTRICT 81
+#define WLC_SET_WEP_RESTRICT 82
+#define WLC_GET_COUNTRY 83
+#define WLC_SET_COUNTRY 84
+#define WLC_GET_PM 85
+#define WLC_SET_PM 86
+#define WLC_GET_WAKE 87
+#define WLC_SET_WAKE 88
+/* #define WLC_GET_D11CNTS 89 */ /* -> "counters" iovar */
+#define WLC_GET_FORCELINK 90 /* ndis only */
+#define WLC_SET_FORCELINK 91 /* ndis only */
+#define WLC_FREQ_ACCURACY 92 /* diag */
+#define WLC_CARRIER_SUPPRESS 93 /* diag */
+#define WLC_GET_PHYREG 94
+#define WLC_SET_PHYREG 95
+#define WLC_GET_RADIOREG 96
+#define WLC_SET_RADIOREG 97
+#define WLC_GET_REVINFO 98
+#define WLC_GET_UCANTDIV 99
+#define WLC_SET_UCANTDIV 100
+#define WLC_R_REG 101
+#define WLC_W_REG 102
+/* #define WLC_DIAG_LOOPBACK 103 old tray diag */
+/* #define WLC_RESET_D11CNTS 104 */ /* -> "reset_d11cnts" iovar */
+#define WLC_GET_MACMODE 105
+#define WLC_SET_MACMODE 106
+#define WLC_GET_MONITOR 107
+#define WLC_SET_MONITOR 108
+#define WLC_GET_GMODE 109
+#define WLC_SET_GMODE 110
+#define WLC_GET_LEGACY_ERP 111
+#define WLC_SET_LEGACY_ERP 112
+#define WLC_GET_RX_ANT 113
+#define WLC_GET_CURR_RATESET 114 /* current rateset */
+#define WLC_GET_SCANSUPPRESS 115
+#define WLC_SET_SCANSUPPRESS 116
+#define WLC_GET_AP 117
+#define WLC_SET_AP 118
+#define WLC_GET_EAP_RESTRICT 119
+#define WLC_SET_EAP_RESTRICT 120
+#define WLC_SCB_AUTHORIZE 121
+#define WLC_SCB_DEAUTHORIZE 122
+#define WLC_GET_WDSLIST 123
+#define WLC_SET_WDSLIST 124
+#define WLC_GET_ATIM 125
+#define WLC_SET_ATIM 126
+#define WLC_GET_RSSI 127
+#define WLC_GET_PHYANTDIV 128
+#define WLC_SET_PHYANTDIV 129
+#define WLC_AP_RX_ONLY 130
+#define WLC_GET_TX_PATH_PWR 131
+#define WLC_SET_TX_PATH_PWR 132
+#define WLC_GET_WSEC 133
+#define WLC_SET_WSEC 134
+#define WLC_GET_PHY_NOISE 135
+#define WLC_GET_BSS_INFO 136
+#define WLC_GET_PKTCNTS 137
+#define WLC_GET_LAZYWDS 138
+#define WLC_SET_LAZYWDS 139
+#define WLC_GET_BANDLIST 140
+
+#define WLC_GET_BAND 141
+#define WLC_SET_BAND 142
+#define WLC_SCB_DEAUTHENTICATE 143
+#define WLC_GET_SHORTSLOT 144
+#define WLC_GET_SHORTSLOT_OVERRIDE 145
+#define WLC_SET_SHORTSLOT_OVERRIDE 146
+#define WLC_GET_SHORTSLOT_RESTRICT 147
+#define WLC_SET_SHORTSLOT_RESTRICT 148
+#define WLC_GET_GMODE_PROTECTION 149
+#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150
+#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151
+#define WLC_UPGRADE 152
+/* #define WLC_GET_MRATE 153 */ /* no longer supported */
+/* #define WLC_SET_MRATE 154 */ /* no longer supported */
+#define WLC_GET_IGNORE_BCNS 155
+#define WLC_SET_IGNORE_BCNS 156
+#define WLC_GET_SCB_TIMEOUT 157
+#define WLC_SET_SCB_TIMEOUT 158
+#define WLC_GET_ASSOCLIST 159
+#define WLC_GET_CLK 160
+#define WLC_SET_CLK 161
+#define WLC_GET_UP 162
+#define WLC_OUT 163
+#define WLC_GET_WPA_AUTH 164
+#define WLC_SET_WPA_AUTH 165
+#define WLC_GET_UCFLAGS 166
+#define WLC_SET_UCFLAGS 167
+#define WLC_GET_PWRIDX 168
+#define WLC_SET_PWRIDX 169
+#define WLC_GET_TSSI 170
+#define WLC_GET_SUP_RATESET_OVERRIDE 171
+#define WLC_SET_SUP_RATESET_OVERRIDE 172
+/* #define WLC_SET_FAST_TIMER 173 */ /* no longer supported */
+/* #define WLC_GET_FAST_TIMER 174 */ /* no longer supported */
+/* #define WLC_SET_SLOW_TIMER 175 */ /* no longer supported */
+/* #define WLC_GET_SLOW_TIMER 176 */ /* no longer supported */
+/* #define WLC_DUMP_PHYREGS 177 */ /* no longer supported */
+#define WLC_GET_PROTECTION_CONTROL 178
+#define WLC_SET_PROTECTION_CONTROL 179
+#define WLC_GET_PHYLIST 180
+#define WLC_ENCRYPT_STRENGTH 181 /* ndis only */
+#define WLC_DECRYPT_STATUS 182 /* ndis only */
+#define WLC_GET_KEY_SEQ 183
+#define WLC_GET_SCAN_CHANNEL_TIME 184
+#define WLC_SET_SCAN_CHANNEL_TIME 185
+#define WLC_GET_SCAN_UNASSOC_TIME 186
+#define WLC_SET_SCAN_UNASSOC_TIME 187
+#define WLC_GET_SCAN_HOME_TIME 188
+#define WLC_SET_SCAN_HOME_TIME 189
+#define WLC_GET_SCAN_NPROBES 190
+#define WLC_SET_SCAN_NPROBES 191
+#define WLC_GET_PRB_RESP_TIMEOUT 192
+#define WLC_SET_PRB_RESP_TIMEOUT 193
+#define WLC_GET_ATTEN 194
+#define WLC_SET_ATTEN 195
+#define WLC_GET_SHMEM 196 /* diag */
+#define WLC_SET_SHMEM 197 /* diag */
+/* #define WLC_GET_GMODE_PROTECTION_CTS 198 */ /* no longer supported */
+/* #define WLC_SET_GMODE_PROTECTION_CTS 199 */ /* no longer supported */
+#define WLC_SET_WSEC_TEST 200
+#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201
+#define WLC_TKIP_COUNTERMEASURES 202
+#define WLC_GET_PIOMODE 203
+#define WLC_SET_PIOMODE 204
+#define WLC_SET_ASSOC_PREFER 205
+#define WLC_GET_ASSOC_PREFER 206
+#define WLC_SET_ROAM_PREFER 207
+#define WLC_GET_ROAM_PREFER 208
+#define WLC_SET_LED 209
+#define WLC_GET_LED 210
+#define WLC_GET_INTERFERENCE_MODE 211
+#define WLC_SET_INTERFERENCE_MODE 212
+#define WLC_GET_CHANNEL_QA 213
+#define WLC_START_CHANNEL_QA 214
+#define WLC_GET_CHANNEL_SEL 215
+#define WLC_START_CHANNEL_SEL 216
+#define WLC_GET_VALID_CHANNELS 217
+#define WLC_GET_FAKEFRAG 218
+#define WLC_SET_FAKEFRAG 219
+#define WLC_GET_PWROUT_PERCENTAGE 220
+#define WLC_SET_PWROUT_PERCENTAGE 221
+#define WLC_SET_BAD_FRAME_PREEMPT 222
+#define WLC_GET_BAD_FRAME_PREEMPT 223
+#define WLC_SET_LEAP_LIST 224
+#define WLC_GET_LEAP_LIST 225
+#define WLC_GET_CWMIN 226
+#define WLC_SET_CWMIN 227
+#define WLC_GET_CWMAX 228
+#define WLC_SET_CWMAX 229
+#define WLC_GET_WET 230
+#define WLC_SET_WET 231
+#define WLC_GET_PUB 232
+/* #define WLC_SET_GLACIAL_TIMER 233 */ /* no longer supported */
+/* #define WLC_GET_GLACIAL_TIMER 234 */ /* no longer supported */
+#define WLC_GET_KEY_PRIMARY 235
+#define WLC_SET_KEY_PRIMARY 236
+
+
+/* #define WLC_DUMP_RADIOREGS 237 */ /* no longer supported */
+#define WLC_GET_ACI_ARGS 238
+#define WLC_SET_ACI_ARGS 239
+#define WLC_UNSET_CALLBACK 240
+#define WLC_SET_CALLBACK 241
+#define WLC_GET_RADAR 242
+#define WLC_SET_RADAR 243
+#define WLC_SET_SPECT_MANAGMENT 244
+#define WLC_GET_SPECT_MANAGMENT 245
+#define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */
+#define WLC_WDS_GET_WPA_SUP 247
+#define WLC_SET_CS_SCAN_TIMER 248
+#define WLC_GET_CS_SCAN_TIMER 249
+#define WLC_MEASURE_REQUEST 250
+#define WLC_INIT 251
+#define WLC_SEND_QUIET 252
+#define WLC_KEEPALIVE 253
+#define WLC_SEND_PWR_CONSTRAINT 254
+#define WLC_UPGRADE_STATUS 255
+#define WLC_CURRENT_PWR 256
+#define WLC_GET_SCAN_PASSIVE_TIME 257
+#define WLC_SET_SCAN_PASSIVE_TIME 258
+#define WLC_LEGACY_LINK_BEHAVIOR 259
+#define WLC_GET_CHANNELS_IN_COUNTRY 260
+#define WLC_GET_COUNTRY_LIST 261
+#define WLC_GET_VAR 262 /* get value of named variable */
+#define WLC_SET_VAR 263 /* set named variable to value */
+#define WLC_NVRAM_GET 264 /* deprecated */
+#define WLC_NVRAM_SET 265
+#define WLC_NVRAM_DUMP 266
+#define WLC_REBOOT 267
+#define WLC_SET_WSEC_PMK 268
+#define WLC_GET_AUTH_MODE 269
+#define WLC_SET_AUTH_MODE 270
+#define WLC_GET_WAKEENTRY 271
+#define WLC_SET_WAKEENTRY 272
+#define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */
+#define WLC_NVOTPW 274
+#define WLC_OTPW 275
+#define WLC_IOV_BLOCK_GET 276
+#define WLC_IOV_MODULES_GET 277
+#define WLC_SOFT_RESET 278
+#define WLC_GET_ALLOW_MODE 279
+#define WLC_SET_ALLOW_MODE 280
+#define WLC_GET_DESIRED_BSSID 281
+#define WLC_SET_DESIRED_BSSID 282
+#define WLC_DISASSOC_MYAP 283
+#define WLC_GET_NBANDS 284 /* for Dongle EXT_STA support */
+#define WLC_GET_BANDSTATES 285 /* for Dongle EXT_STA support */
+#define WLC_GET_WLC_BSS_INFO 286 /* for Dongle EXT_STA support */
+#define WLC_GET_ASSOC_INFO 287 /* for Dongle EXT_STA support */
+#define WLC_GET_OID_PHY 288 /* for Dongle EXT_STA support */
+#define WLC_SET_OID_PHY 289 /* for Dongle EXT_STA support */
+#define WLC_SET_ASSOC_TIME 290 /* for Dongle EXT_STA support */
+#define WLC_GET_DESIRED_SSID 291 /* for Dongle EXT_STA support */
+#define WLC_GET_CHANSPEC 292 /* for Dongle EXT_STA support */
+#define WLC_GET_ASSOC_STATE 293 /* for Dongle EXT_STA support */
+#define WLC_SET_PHY_STATE 294 /* for Dongle EXT_STA support */
+#define WLC_GET_SCAN_PENDING 295 /* for Dongle EXT_STA support */
+#define WLC_GET_SCANREQ_PENDING 296 /* for Dongle EXT_STA support */
+#define WLC_GET_PREV_ROAM_REASON 297 /* for Dongle EXT_STA support */
+#define WLC_SET_PREV_ROAM_REASON 298 /* for Dongle EXT_STA support */
+#define WLC_GET_BANDSTATES_PI 299 /* for Dongle EXT_STA support */
+#define WLC_GET_PHY_STATE 300 /* for Dongle EXT_STA support */
+#define WLC_GET_BSS_WPA_RSN 301 /* for Dongle EXT_STA support */
+#define WLC_GET_BSS_WPA2_RSN 302 /* for Dongle EXT_STA support */
+#define WLC_GET_BSS_BCN_TS 303 /* for Dongle EXT_STA support */
+#define WLC_GET_INT_DISASSOC 304 /* for Dongle EXT_STA support */
+#define WLC_SET_NUM_PEERS 305 /* for Dongle EXT_STA support */
+#define WLC_GET_NUM_BSS 306 /* for Dongle EXT_STA support */
+#define WLC_PHY_SAMPLE_COLLECT 307 /* phy sample collect mode */
+/* #define WLC_UM_PRIV 308 */ /* Deprecated: usermode driver */
+#define WLC_GET_CMD 309
+/* #define WLC_LAST 310 */ /* Never used - can be reused */
+#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 /* set inter mode override */
+#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 /* get inter mode override */
+/* #define WLC_GET_WAI_RESTRICT 313 */
+/* #define WLC_SET_WAI_RESTRICT 314 */
+/* #define WLC_SET_WAI_REKEY 315 */
+#define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */
+#define WLC_GET_NAT_STATE 317
+#define WLC_GET_TXBF_RATESET 318
+#define WLC_SET_TXBF_RATESET 319
+#define WLC_SCAN_CQ 320
+#define WLC_GET_RSSI_QDB 321 /* qdB portion of the RSSI */
+#define WLC_DUMP_RATESET 322
+#define WLC_ECHO 323
+#define WLC_LAST 324
+#ifndef EPICTRL_COOKIE
+#define EPICTRL_COOKIE 0xABADCEDE
+#endif
+
+/* vx wlc ioctl's offset */
+#define CMN_IOCTL_OFF 0x180
+
+/*
+ * custom OID support
+ *
+ * 0xFF - implementation specific OID
+ * 0xE4 - first byte of Broadcom PCI vendor ID
+ * 0x14 - second byte of Broadcom PCI vendor ID
+ * 0xXX - the custom OID number
+ */
+
+/* begin 0x1f values beyond the start of the ET driver range. */
+#define WL_OID_BASE 0xFFE41420
+
+/* NDIS overrides */
+#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE)
+#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK)
+#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK)
+#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH)
+#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS)
+#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR)
+#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM)
+
+/* EXT_STA Dongle suuport */
+#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC)
+#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS)
+#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY)
+#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY)
+#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME)
+#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID)
+#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE)
+#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING)
+#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING)
+#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON)
+#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON)
+#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE)
+#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC)
+#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS)
+#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS)
+
+/* NAT filter driver support */
+#define OID_NAT_SET_CONFIG (WL_OID_BASE + WLC_SET_NAT_CONFIG)
+#define OID_NAT_GET_STATE (WL_OID_BASE + WLC_GET_NAT_STATE)
+
+#define WL_DECRYPT_STATUS_SUCCESS 1
+#define WL_DECRYPT_STATUS_FAILURE 2
+#define WL_DECRYPT_STATUS_UNKNOWN 3
+
+/* allows user-mode app to poll the status of USB image upgrade */
+#define WLC_UPGRADE_SUCCESS 0
+#define WLC_UPGRADE_PENDING 1
+
+/* WLC_GET_AUTH, WLC_SET_AUTH values */
+#define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */
+#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */
+#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */
+
+/* a large TX Power as an init value to factor out of MIN() calculations,
+ * keep low enough to fit in an int8, units are .25 dBm
+ */
+#define WLC_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */
+
+/* "diag" iovar argument and error code */
+#define WL_DIAG_INTERRUPT 1 /* d11 loopback interrupt test */
+#define WL_DIAG_LOOPBACK 2 /* d11 loopback data test */
+#define WL_DIAG_MEMORY 3 /* d11 memory test */
+#define WL_DIAG_LED 4 /* LED test */
+#define WL_DIAG_REG 5 /* d11/phy register test */
+#define WL_DIAG_SROM 6 /* srom read/crc test */
+#define WL_DIAG_DMA 7 /* DMA test */
+#define WL_DIAG_LOOPBACK_EXT 8 /* enhenced d11 loopback data test */
+
+#define WL_DIAGERR_SUCCESS 0
+#define WL_DIAGERR_FAIL_TO_RUN 1 /* unable to run requested diag */
+#define WL_DIAGERR_NOT_SUPPORTED 2 /* diag requested is not supported */
+#define WL_DIAGERR_INTERRUPT_FAIL 3 /* loopback interrupt test failed */
+#define WL_DIAGERR_LOOPBACK_FAIL 4 /* loopback data test failed */
+#define WL_DIAGERR_SROM_FAIL 5 /* srom read failed */
+#define WL_DIAGERR_SROM_BADCRC 6 /* srom crc failed */
+#define WL_DIAGERR_REG_FAIL 7 /* d11/phy register test failed */
+#define WL_DIAGERR_MEMORY_FAIL 8 /* d11 memory test failed */
+#define WL_DIAGERR_NOMEM 9 /* diag test failed due to no memory */
+#define WL_DIAGERR_DMA_FAIL 10 /* DMA test failed */
+
+#define WL_DIAGERR_MEMORY_TIMEOUT 11 /* d11 memory test didn't finish in time */
+#define WL_DIAGERR_MEMORY_BADPATTERN 12 /* d11 memory test result in bad pattern */
+
+/* band types */
+#define WLC_BAND_AUTO 0 /* auto-select */
+#define WLC_BAND_5G 1 /* 5 Ghz */
+#define WLC_BAND_2G 2 /* 2.4 Ghz */
+#define WLC_BAND_ALL 3 /* all bands */
+#define WLC_BAND_INVALID -1 /* Invalid band */
+
+/* band range returned by band_range iovar */
+#define WL_CHAN_FREQ_RANGE_2G 0
+#define WL_CHAN_FREQ_RANGE_5GL 1
+#define WL_CHAN_FREQ_RANGE_5GM 2
+#define WL_CHAN_FREQ_RANGE_5GH 3
+
+#define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4
+#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5
+#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6
+#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7
+#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8
+
+#define WL_CHAN_FREQ_RANGE_5G_BAND0 1
+#define WL_CHAN_FREQ_RANGE_5G_BAND1 2
+#define WL_CHAN_FREQ_RANGE_5G_BAND2 3
+#define WL_CHAN_FREQ_RANGE_5G_BAND3 4
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_CHAN_FREQ_RANGE_5G_4BAND 5
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* SROM12 */
+#define WL_CHAN_FREQ_RANGE_5G_BAND4 5
+#define WL_CHAN_FREQ_RANGE_2G_40 6
+#define WL_CHAN_FREQ_RANGE_5G_BAND0_40 7
+#define WL_CHAN_FREQ_RANGE_5G_BAND1_40 8
+#define WL_CHAN_FREQ_RANGE_5G_BAND2_40 9
+#define WL_CHAN_FREQ_RANGE_5G_BAND3_40 10
+#define WL_CHAN_FREQ_RANGE_5G_BAND4_40 11
+#define WL_CHAN_FREQ_RANGE_5G_BAND0_80 12
+#define WL_CHAN_FREQ_RANGE_5G_BAND1_80 13
+#define WL_CHAN_FREQ_RANGE_5G_BAND2_80 14
+#define WL_CHAN_FREQ_RANGE_5G_BAND3_80 15
+#define WL_CHAN_FREQ_RANGE_5G_BAND4_80 16
+
+#define WL_CHAN_FREQ_RANGE_5G_5BAND 18
+#define WL_CHAN_FREQ_RANGE_5G_5BAND_40 19
+#define WL_CHAN_FREQ_RANGE_5G_5BAND_80 20
+
+#define WLC_MACMODE_DISABLED 0 /* MAC list disabled */
+#define WLC_MACMODE_DENY 1 /* Deny specified (i.e. allow unspecified) */
+#define WLC_MACMODE_ALLOW 2 /* Allow specified (i.e. deny unspecified) */
+
+/*
+ * 54g modes (basic bits may still be overridden)
+ *
+ * GMODE_LEGACY_B Rateset: 1b, 2b, 5.5, 11
+ * Preamble: Long
+ * Shortslot: Off
+ * GMODE_AUTO Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54
+ * Extended Rateset: 6, 9, 12, 48
+ * Preamble: Long
+ * Shortslot: Auto
+ * GMODE_ONLY Rateset: 1b, 2b, 5.5b, 11b, 18, 24b, 36, 54
+ * Extended Rateset: 6b, 9, 12b, 48
+ * Preamble: Short required
+ * Shortslot: Auto
+ * GMODE_B_DEFERRED Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54
+ * Extended Rateset: 6, 9, 12, 48
+ * Preamble: Long
+ * Shortslot: On
+ * GMODE_PERFORMANCE Rateset: 1b, 2b, 5.5b, 6b, 9, 11b, 12b, 18, 24b, 36, 48, 54
+ * Preamble: Short required
+ * Shortslot: On and required
+ * GMODE_LRS Rateset: 1b, 2b, 5.5b, 11b
+ * Extended Rateset: 6, 9, 12, 18, 24, 36, 48, 54
+ * Preamble: Long
+ * Shortslot: Auto
+ */
+#define GMODE_LEGACY_B 0
+#define GMODE_AUTO 1
+#define GMODE_ONLY 2
+#define GMODE_B_DEFERRED 3
+#define GMODE_PERFORMANCE 4
+#define GMODE_LRS 5
+#define GMODE_MAX 6
+
+/* values for PLCPHdr_override */
+#define WLC_PLCP_AUTO -1
+#define WLC_PLCP_SHORT 0
+#define WLC_PLCP_LONG 1
+
+/* values for g_protection_override and n_protection_override */
+#define WLC_PROTECTION_AUTO -1
+#define WLC_PROTECTION_OFF 0
+#define WLC_PROTECTION_ON 1
+#define WLC_PROTECTION_MMHDR_ONLY 2
+#define WLC_PROTECTION_CTS_ONLY 3
+
+/* values for g_protection_control and n_protection_control */
+#define WLC_PROTECTION_CTL_OFF 0
+#define WLC_PROTECTION_CTL_LOCAL 1
+#define WLC_PROTECTION_CTL_OVERLAP 2
+
+/* values for n_protection */
+#define WLC_N_PROTECTION_OFF 0
+#define WLC_N_PROTECTION_OPTIONAL 1
+#define WLC_N_PROTECTION_20IN40 2
+#define WLC_N_PROTECTION_MIXEDMODE 3
+
+/* values for n_preamble_type */
+#define WLC_N_PREAMBLE_MIXEDMODE 0
+#define WLC_N_PREAMBLE_GF 1
+#define WLC_N_PREAMBLE_GF_BRCM 2
+
+/* values for band specific 40MHz capabilities (deprecated) */
+#define WLC_N_BW_20ALL 0
+#define WLC_N_BW_40ALL 1
+#define WLC_N_BW_20IN2G_40IN5G 2
+
+#define WLC_BW_20MHZ_BIT (1<<0)
+#define WLC_BW_40MHZ_BIT (1<<1)
+#define WLC_BW_80MHZ_BIT (1<<2)
+#define WLC_BW_160MHZ_BIT (1<<3)
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WLC_BW_10MHZ_BIT (1<<4)
+#define WLC_BW_5MHZ_BIT (1<<5)
+#define WLC_BW_2P5MHZ_BIT (1<<6)
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/* Bandwidth capabilities */
+#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_160MHZ (WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \
+ WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT)
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WLC_BW_CAP_2P5MHZ (WLC_BW_2P5MHZ_BIT)
+#define WLC_BW_CAP_5MHZ (WLC_BW_5MHZ_BIT)
+#define WLC_BW_CAP_10MHZ (WLC_BW_10MHZ_BIT)
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#define WLC_BW_CAP_UNRESTRICTED 0xFF
+
+#define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE)
+#define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE)
+#define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE)
+#define WL_BW_CAP_160MHZ(bw_cap)(((bw_cap) & WLC_BW_160MHZ_BIT) ? TRUE : FALSE)
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_BW_CAP_2P5MHZ(bw_cap)(((bw_cap) & WLC_BW_2P5MHZ_BIT) ? TRUE : FALSE)
+#define WL_BW_CAP_5MHZ(bw_cap) (((bw_cap) & WLC_BW_5MHZ_BIT) ? TRUE : FALSE)
+#define WL_BW_CAP_10MHZ(bw_cap) (((bw_cap) & WLC_BW_10MHZ_BIT) ? TRUE : FALSE)
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/* values to force tx/rx chain */
+#define WLC_N_TXRX_CHAIN0 0
+#define WLC_N_TXRX_CHAIN1 1
+
+/* bitflags for SGI support (sgi_rx iovar) */
+#define WLC_N_SGI_20 0x01
+#define WLC_N_SGI_40 0x02
+#define WLC_VHT_SGI_80 0x04
+#define WLC_VHT_SGI_160 0x08
+
+/* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */
+#define WLC_SGI_ALL 0x02
+
+#define LISTEN_INTERVAL 10
+/* interference mitigation options */
+#define INTERFERE_OVRRIDE_OFF -1 /* interference override off */
+#define INTERFERE_NONE 0 /* off */
+#define NON_WLAN 1 /* foreign/non 802.11 interference, no auto detect */
+#define WLAN_MANUAL 2 /* ACI: no auto detection */
+#define WLAN_AUTO 3 /* ACI: auto detect */
+#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */
+#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */
+
+/* interfernece mode bit-masks (ACPHY) */
+#define ACPHY_ACI_GLITCHBASED_DESENSE 1 /* bit 0 */
+#define ACPHY_ACI_HWACI_PKTGAINLMT 2 /* bit 1 */
+#define ACPHY_ACI_W2NB_PKTGAINLMT 4 /* bit 2 */
+#define ACPHY_ACI_PREEMPTION 8 /* bit 3 */
+#define ACPHY_HWACI_MITIGATION 16 /* bit 4 */
+#define ACPHY_LPD_PREEMPTION 32 /* bit 5 */
+#define ACPHY_HWOBSS_MITIGATION 64 /* bit 6 */
+#define ACPHY_ACI_MAX_MODE 127
+
+/* AP environment */
+#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */
+#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */
+#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */
+#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */
+
+#define TRIGGER_NOW 0
+#define TRIGGER_CRS 0x01
+#define TRIGGER_CRSDEASSERT 0x02
+#define TRIGGER_GOODFCS 0x04
+#define TRIGGER_BADFCS 0x08
+#define TRIGGER_BADPLCP 0x10
+#define TRIGGER_CRSGLITCH 0x20
+
+#define WL_SAMPLEDATA_HEADER_TYPE 1
+#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */
+#define WL_SAMPLEDATA_TYPE 2
+#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */
+#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */
+
+/* WL_OTA START */
+#define WL_OTA_ARG_PARSE_BLK_SIZE 1200
+#define WL_OTA_TEST_MAX_NUM_RATE 30
+#define WL_OTA_TEST_MAX_NUM_SEQ 100
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_OTA_TEST_MAX_NUM_RSSI 85
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#define WL_THRESHOLD_LO_BAND 70 /* range from 5250MHz - 5350MHz */
+
+/* radar iovar SET defines */
+#define WL_RADAR_DETECTOR_OFF 0 /* radar detector off */
+#define WL_RADAR_DETECTOR_ON 1 /* radar detector on */
+#define WL_RADAR_SIMULATED 2 /* force radar detector to declare
+ * detection once
+ */
+#define WL_RADAR_SIMULATED_SC 3 /* force radar detector to declare
+ * detection once on scan core
+ * if available and active
+ */
+#define WL_RSSI_ANT_VERSION 1 /* current version of wl_rssi_ant_t */
+#define WL_ANT_RX_MAX 2 /* max 2 receive antennas */
+#define WL_ANT_HT_RX_MAX 4 /* max 4 receive antennas/cores */
+#define WL_ANT_IDX_1 0 /* antenna index 1 */
+#define WL_ANT_IDX_2 1 /* antenna index 2 */
+
+#ifndef WL_RSSI_ANT_MAX
+#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */
+#elif WL_RSSI_ANT_MAX != 4
+#error "WL_RSSI_ANT_MAX does not match"
+#endif
+
+/* dfs_status iovar-related defines */
+
+/* cac - channel availability check,
+ * ism - in-service monitoring
+ * csa - channel switching announcement
+ */
+
+/* cac state values */
+#define WL_DFS_CACSTATE_IDLE 0 /* state for operating in non-radar channel */
+#define WL_DFS_CACSTATE_PREISM_CAC 1 /* CAC in progress */
+#define WL_DFS_CACSTATE_ISM 2 /* ISM in progress */
+#define WL_DFS_CACSTATE_CSA 3 /* csa */
+#define WL_DFS_CACSTATE_POSTISM_CAC 4 /* ISM CAC */
+#define WL_DFS_CACSTATE_PREISM_OOC 5 /* PREISM OOC */
+#define WL_DFS_CACSTATE_POSTISM_OOC 6 /* POSTISM OOC */
+#define WL_DFS_CACSTATES 7 /* this many states exist */
+
+/* Defines used with channel_bandwidth for curpower */
+#define WL_BW_20MHZ 0
+#define WL_BW_40MHZ 1
+#define WL_BW_80MHZ 2
+#define WL_BW_160MHZ 3
+#define WL_BW_8080MHZ 4
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_BW_2P5MHZ 5
+#define WL_BW_5MHZ 6
+#define WL_BW_10MHZ 7
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* tx_power_t.flags bits */
+#define WL_TX_POWER_F_ENABLED 1
+#define WL_TX_POWER_F_HW 2
+#define WL_TX_POWER_F_MIMO 4
+#define WL_TX_POWER_F_SISO 8
+#define WL_TX_POWER_F_HT 0x10
+#define WL_TX_POWER_F_VHT 0x20
+#define WL_TX_POWER_F_OPENLOOP 0x40
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_TX_POWER_F_PROP11NRATES 0x80
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#define WL_TX_POWER_F_UNIT_QDBM 0x100
+/* Message levels */
+#define WL_ERROR_VAL 0x00000001
+#define WL_TRACE_VAL 0x00000002
+#define WL_PRHDRS_VAL 0x00000004
+#define WL_PRPKT_VAL 0x00000008
+#define WL_INFORM_VAL 0x00000010
+#define WL_TMP_VAL 0x00000020
+#define WL_OID_VAL 0x00000040
+#define WL_RATE_VAL 0x00000080
+#define WL_ASSOC_VAL 0x00000100
+#define WL_PRUSR_VAL 0x00000200
+#define WL_PS_VAL 0x00000400
+#define WL_TXPWR_VAL 0x00000000 /* retired in TOT on 6/10/2009 */
+#define WL_MODE_SWITCH_VAL 0x00000800 /* Using retired TXPWR val */
+#define WL_PORT_VAL 0x00001000
+#define WL_DUAL_VAL 0x00002000
+#define WL_WSEC_VAL 0x00004000
+#define WL_WSEC_DUMP_VAL 0x00008000
+#define WL_LOG_VAL 0x00010000
+#define WL_NRSSI_VAL 0x00000000 /* retired in TOT on 6/10/2009 */
+#define WL_BCNTRIM_VAL 0x00020000 /* Using retired NRSSI VAL */
+#define WL_LOFT_VAL 0x00000000 /* retired in TOT on 6/10/2009 */
+#define WL_PFN_VAL 0x00040000 /* Using retired LOFT_VAL */
+#define WL_REGULATORY_VAL 0x00080000
+#define WL_CSA_VAL 0x00080000 /* Reusing REGULATORY_VAL due to lackof bits */
+#define WL_TAF_VAL 0x00100000
+#define WL_RADAR_VAL 0x00000000 /* retired in TOT on 6/10/2009 */
+#define WL_WDI_VAL 0x00200000 /* Using retired WL_RADAR_VAL VAL */
+#define WL_MPC_VAL 0x00400000
+#define WL_APSTA_VAL 0x00800000
+#define WL_DFS_VAL 0x01000000
+#define WL_BA_VAL 0x00000000 /* retired in TOT on 6/14/2010 */
+#define WL_MUMIMO_VAL 0x02000000 /* Using retired WL_BA_VAL */
+#define WL_ACI_VAL 0x04000000
+#define WL_PRMAC_VAL 0x04000000
+#define WL_MBSS_VAL 0x04000000
+#define WL_CAC_VAL 0x08000000
+#define WL_AMSDU_VAL 0x10000000
+#define WL_AMPDU_VAL 0x20000000
+#define WL_FFPLD_VAL 0x40000000
+#define WL_ROAM_EXP_VAL 0x80000000
+
+/* wl_msg_level is full. For new bits take the next one and AND with
+ * wl_msg_level2 in wl_dbg.h
+ */
+#define WL_DPT_VAL 0x00000001
+/* re-using WL_DPT_VAL */
+/* re-using WL_MESH_VAL */
+#define WL_NATOE_VAL 0x00000001
+#define WL_MESH_VAL 0x00000001
+#define WL_SCAN_VAL 0x00000002
+#define WL_WOWL_VAL 0x00000004
+#define WL_COEX_VAL 0x00000008
+#define WL_RTDC_VAL 0x00000010
+#define WL_PROTO_VAL 0x00000020
+#define WL_CHANINT_VAL 0x00000080
+#define WL_WMF_VAL 0x00000100
+#define WL_P2P_VAL 0x00000200
+#define WL_ITFR_VAL 0x00000400
+#define WL_MCHAN_VAL 0x00000800
+#define WL_TDLS_VAL 0x00001000
+#define WL_MCNX_VAL 0x00002000
+#define WL_PROT_VAL 0x00004000
+#define WL_PSTA_VAL 0x00008000
+#define WL_TSO_VAL 0x00010000
+#define WL_TRF_MGMT_VAL 0x00020000
+#define WL_LPC_VAL 0x00040000
+#define WL_L2FILTER_VAL 0x00080000
+#define WL_TXBF_VAL 0x00100000
+#define WL_P2PO_VAL 0x00200000
+#define WL_TBTT_VAL 0x00400000
+#define WL_FBT_VAL 0x00800000
+#define WL_RRM_VAL 0x00800000 /* reuse */
+#define WL_MQ_VAL 0x01000000
+
+/* This level is currently used in Phoenix2 only */
+#define WL_SRSCAN_VAL 0x02000000
+
+#define WL_WNM_VAL 0x04000000
+/* re-using WL_WNM_VAL for MBO */
+#define WL_MBO_VAL 0x04000000
+#define WL_PWRSEL_VAL 0x10000000
+#define WL_NET_DETECT_VAL 0x20000000
+#define WL_PCIE_VAL 0x40000000
+#define WL_PMDUR_VAL 0x80000000
+
+
+/* use top-bit for WL_TIME_STAMP_VAL because this is a modifier
+ * rather than a message-type of its own
+ */
+#define WL_TIMESTAMP_VAL 0x80000000
+
+/* max # of leds supported by GPIO (gpio pin# == led index#) */
+#define WL_LED_NUMGPIO 32 /* gpio 0-31 */
+
+/* led per-pin behaviors */
+#define WL_LED_OFF 0 /* always off */
+#define WL_LED_ON 1 /* always on */
+#define WL_LED_ACTIVITY 2 /* activity */
+#define WL_LED_RADIO 3 /* radio enabled */
+#define WL_LED_ARADIO 4 /* 5 Ghz radio enabled */
+#define WL_LED_BRADIO 5 /* 2.4Ghz radio enabled */
+#define WL_LED_BGMODE 6 /* on if gmode, off if bmode */
+#define WL_LED_WI1 7
+#define WL_LED_WI2 8
+#define WL_LED_WI3 9
+#define WL_LED_ASSOC 10 /* associated state indicator */
+#define WL_LED_INACTIVE 11 /* null behavior (clears default behavior) */
+#define WL_LED_ASSOCACT 12 /* on when associated; blink fast for activity */
+#define WL_LED_WI4 13
+#define WL_LED_WI5 14
+#define WL_LED_BLINKSLOW 15 /* blink slow */
+#define WL_LED_BLINKMED 16 /* blink med */
+#define WL_LED_BLINKFAST 17 /* blink fast */
+#define WL_LED_BLINKCUSTOM 18 /* blink custom */
+#define WL_LED_BLINKPERIODIC 19 /* blink periodic (custom 1000ms / off 400ms) */
+#define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */
+ /* keep on for 300 sec */
+#define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */
+#define WL_LED_WI6 22
+#define WL_LED_WI7 23
+#define WL_LED_WI8 24
+#define WL_LED_NUMBEHAVIOR 25
+
+/* led behavior numeric value format */
+#define WL_LED_BEH_MASK 0x3f /* behavior mask */
+#define WL_LED_PMU_OVERRIDE 0x40 /* need to set PMU Override bit for the GPIO */
+#define WL_LED_AL_MASK 0x80 /* activelow (polarity) bit */
+
+/* number of bytes needed to define a proper bit mask for MAC event reporting */
+#define BCMIO_ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+#define BCMIO_NBBY 8
+#define WL_EVENTING_MASK_LEN 16
+
+#define WL_EVENTING_MASK_EXT_LEN \
+ MAX(WL_EVENTING_MASK_LEN, (ROUNDUP(WLC_E_LAST, NBBY)/NBBY))
+
+/* join preference types */
+#define WL_JOIN_PREF_RSSI 1 /* by RSSI */
+#define WL_JOIN_PREF_WPA 2 /* by akm and ciphers */
+#define WL_JOIN_PREF_BAND 3 /* by 802.11 band */
+#define WL_JOIN_PREF_RSSI_DELTA 4 /* by 802.11 band only if RSSI delta condition matches */
+#define WL_JOIN_PREF_TRANS_PREF 5 /* defined by requesting AP */
+
+/* band preference */
+#define WLJP_BAND_ASSOC_PREF 255 /* use what WLC_SET_ASSOC_PREFER ioctl specifies */
+
+/* any multicast cipher suite */
+#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00"
+
+/* 802.11h measurement types */
+#define WLC_MEASURE_TPC 1
+#define WLC_MEASURE_CHANNEL_BASIC 2
+#define WLC_MEASURE_CHANNEL_CCA 3
+#define WLC_MEASURE_CHANNEL_RPI 4
+
+/* regulatory enforcement levels */
+#define SPECT_MNGMT_OFF 0 /* both 11h and 11d disabled */
+#define SPECT_MNGMT_LOOSE_11H 1 /* allow non-11h APs in scan lists */
+#define SPECT_MNGMT_STRICT_11H 2 /* prune out non-11h APs from scan list */
+#define SPECT_MNGMT_STRICT_11D 3 /* switch to 802.11D mode */
+/* SPECT_MNGMT_LOOSE_11H_D - same as SPECT_MNGMT_LOOSE with the exception that Country IE
+ * adoption is done regardless of capability spectrum_management
+ */
+#define SPECT_MNGMT_LOOSE_11H_D 4 /* operation defined above */
+
+/* bit position in per_chan_info; these depend on current country/regulatory domain */
+#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */
+#define WL_CHAN_VALID_SW (1 << 1) /* valid with current country setting */
+#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */
+#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */
+#define WL_CHAN_INACTIVE (1 << 4) /* temporarily inactive due to radar */
+#define WL_CHAN_PASSIVE (1 << 5) /* channel is in passive mode */
+#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_CHAN_RADAR_EU_WEATHER (1 << 7) /* EU Radar weather channel. Implies an
+ * EU Radar channel.
+ */
+/* following definition is for precommit; will be removed once wl, acsd switch to the new def */
+#define WL_CHAN_WEATHER_RADAR WL_CHAN_RADAR_EU_WEATHER
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* BTC mode used by "btc_mode" iovar */
+#define WL_BTC_DISABLE 0 /* disable BT coexistence */
+#define WL_BTC_FULLTDM 1 /* full TDM COEX */
+#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */
+#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */
+#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */
+#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */
+#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */
+#define WL_BTC_DEFAULT 8 /* set the default mode for the device */
+#define WL_INF_BTC_DISABLE 0
+#define WL_INF_BTC_ENABLE 1
+#define WL_INF_BTC_AUTO 3
+
+/* BTC wire used by "btc_wire" iovar */
+#define WL_BTC_DEFWIRE 0 /* use default wire setting */
+#define WL_BTC_2WIRE 2 /* use 2-wire BTC */
+#define WL_BTC_3WIRE 3 /* use 3-wire BTC */
+#define WL_BTC_4WIRE 4 /* use 4-wire BTC */
+
+/* BTC flags: BTC configuration that can be set by host */
+#define WL_BTC_FLAG_PREMPT (1 << 0)
+#define WL_BTC_FLAG_BT_DEF (1 << 1)
+#define WL_BTC_FLAG_ACTIVE_PROT (1 << 2)
+#define WL_BTC_FLAG_SIM_RSP (1 << 3)
+#define WL_BTC_FLAG_PS_PROTECT (1 << 4)
+#define WL_BTC_FLAG_SIM_TX_LP (1 << 5)
+#define WL_BTC_FLAG_ECI (1 << 6)
+#define WL_BTC_FLAG_LIGHT (1 << 7)
+#define WL_BTC_FLAG_PARALLEL (1 << 8)
+
+/* maximum channels returned by the get valid channels iovar */
+#define WL_NUMCHANNELS 64
+
+/* max number of chanspecs (used by the iovar to calc. buf space) */
+#ifdef WL11AC_80P80
+#define WL_NUMCHANSPECS 206
+#else
+#define WL_NUMCHANSPECS 110
+#endif
+
+/* WDS link local endpoint WPA role */
+#define WL_WDS_WPA_ROLE_AUTH 0 /* authenticator */
+#define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */
+#define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */
+
+/* Base offset values */
+#define WL_PKT_FILTER_BASE_PKT 0
+#define WL_PKT_FILTER_BASE_END 1
+#define WL_PKT_FILTER_BASE_D11_H 2 /* May be removed */
+#define WL_PKT_FILTER_BASE_D11_D 3 /* May be removed */
+#define WL_PKT_FILTER_BASE_ETH_H 4
+#define WL_PKT_FILTER_BASE_ETH_D 5
+#define WL_PKT_FILTER_BASE_ARP_H 6
+#define WL_PKT_FILTER_BASE_ARP_D 7 /* May be removed */
+#define WL_PKT_FILTER_BASE_IP4_H 8
+#define WL_PKT_FILTER_BASE_IP4_D 9
+#define WL_PKT_FILTER_BASE_IP6_H 10
+#define WL_PKT_FILTER_BASE_IP6_D 11
+#define WL_PKT_FILTER_BASE_TCP_H 12
+#define WL_PKT_FILTER_BASE_TCP_D 13 /* May be removed */
+#define WL_PKT_FILTER_BASE_UDP_H 14
+#define WL_PKT_FILTER_BASE_UDP_D 15
+#define WL_PKT_FILTER_BASE_IP6_P 16
+#define WL_PKT_FILTER_BASE_COUNT 17 /* May be removed */
+
+/* String mapping for bases that may be used by applications or debug */
+#define WL_PKT_FILTER_BASE_NAMES \
+ { "START", WL_PKT_FILTER_BASE_PKT }, \
+ { "END", WL_PKT_FILTER_BASE_END }, \
+ { "ETH_H", WL_PKT_FILTER_BASE_ETH_H }, \
+ { "ETH_D", WL_PKT_FILTER_BASE_ETH_D }, \
+ { "D11_H", WL_PKT_FILTER_BASE_D11_H }, \
+ { "D11_D", WL_PKT_FILTER_BASE_D11_D }, \
+ { "ARP_H", WL_PKT_FILTER_BASE_ARP_H }, \
+ { "IP4_H", WL_PKT_FILTER_BASE_IP4_H }, \
+ { "IP4_D", WL_PKT_FILTER_BASE_IP4_D }, \
+ { "IP6_H", WL_PKT_FILTER_BASE_IP6_H }, \
+ { "IP6_D", WL_PKT_FILTER_BASE_IP6_D }, \
+ { "IP6_P", WL_PKT_FILTER_BASE_IP6_P }, \
+ { "TCP_H", WL_PKT_FILTER_BASE_TCP_H }, \
+ { "TCP_D", WL_PKT_FILTER_BASE_TCP_D }, \
+ { "UDP_H", WL_PKT_FILTER_BASE_UDP_H }, \
+ { "UDP_D", WL_PKT_FILTER_BASE_UDP_D }
+
+/* Flags for a pattern list element */
+#define WL_PKT_FILTER_MFLAG_NEG 0x0001
+
+/*
+ * Packet engine interface
+ */
+
+#define WL_PKTENG_PER_TX_START 0x01
+#define WL_PKTENG_PER_TX_STOP 0x02
+#define WL_PKTENG_PER_RX_START 0x04
+#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05
+#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06
+#define WL_PKTENG_PER_RX_STOP 0x08
+#define WL_PKTENG_PER_MASK 0xff
+
+#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */
+#define WL_PKTENG_SYNCHRONOUS_UNBLK 0x200 /* synchronous unblock flag */
+#ifdef PKTENG_LONGPKTSZ
+/* max pktsz limit for pkteng */
+#define WL_PKTENG_MAXPKTSZ PKTENG_LONGPKTSZ
+#else
+#define WL_PKTENG_MAXPKTSZ 16384
+#endif
+
+#define NUM_80211b_RATES 4
+#define NUM_80211ag_RATES 8
+#define NUM_80211n_RATES 32
+#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES)
+
+/*
+ * WOWL capability/override settings
+ */
+#define WL_WOWL_MAGIC (1 << 0) /* Wakeup on Magic packet */
+#define WL_WOWL_NET (1 << 1) /* Wakeup on Netpattern */
+#define WL_WOWL_DIS (1 << 2) /* Wakeup on loss-of-link due to Disassoc/Deauth */
+#define WL_WOWL_RETR (1 << 3) /* Wakeup on retrograde TSF */
+#define WL_WOWL_BCN (1 << 4) /* Wakeup on loss of beacon */
+#define WL_WOWL_TST (1 << 5) /* Wakeup after test */
+#define WL_WOWL_M1 (1 << 6) /* Wakeup after PTK refresh */
+#define WL_WOWL_EAPID (1 << 7) /* Wakeup after receipt of EAP-Identity Req */
+#define WL_WOWL_PME_GPIO (1 << 8) /* Wakeind via PME(0) or GPIO(1) */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_WOWL_ULP_BAILOUT (1 << 8) /* wakeind via unknown pkt by basic ULP-offloads -
+ * WL_WOWL_ULP_BAILOUT - same as WL_WOWL_PME_GPIO used only for DONGLE BUILDS
+ */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#define WL_WOWL_NEEDTKIP1 (1 << 9) /* need tkip phase 1 key to be updated by the driver */
+#define WL_WOWL_GTK_FAILURE (1 << 10) /* enable wakeup if GTK fails */
+#define WL_WOWL_EXTMAGPAT (1 << 11) /* support extended magic packets */
+#define WL_WOWL_ARPOFFLOAD (1 << 12) /* support ARP/NS/keepalive offloading */
+#define WL_WOWL_WPA2 (1 << 13) /* read protocol version for EAPOL frames */
+#define WL_WOWL_KEYROT (1 << 14) /* If the bit is set, use key rotaton */
+#define WL_WOWL_BCAST (1 << 15) /* If the bit is set, frm received was bcast frame */
+#define WL_WOWL_SCANOL (1 << 16) /* If the bit is set, scan offload is enabled */
+#define WL_WOWL_TCPKEEP_TIME (1 << 17) /* Wakeup on tcpkeep alive timeout */
+#define WL_WOWL_MDNS_CONFLICT (1 << 18) /* Wakeup on mDNS Conflict Resolution */
+#define WL_WOWL_MDNS_SERVICE (1 << 19) /* Wakeup on mDNS Service Connect */
+#define WL_WOWL_TCPKEEP_DATA (1 << 20) /* tcp keepalive got data */
+#define WL_WOWL_FW_HALT (1 << 21) /* Firmware died in wowl mode */
+#define WL_WOWL_ENAB_HWRADIO (1 << 22) /* Enable detection of radio button changes */
+#define WL_WOWL_MIC_FAIL (1 << 23) /* Offloads detected MIC failure(s) */
+#define WL_WOWL_UNASSOC (1 << 24) /* Wakeup in Unassociated state (Net/Magic Pattern) */
+#define WL_WOWL_SECURE (1 << 25) /* Wakeup if received matched secured pattern */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_WOWL_EXCESS_WAKE (1 << 26) /* Excess wake */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#define WL_WOWL_LINKDOWN (1 << 31) /* Link Down indication in WoWL mode */
+
+#define WL_WOWL_TCPKEEP (1 << 20) /* temp copy to satisfy automerger */
+#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */
+
+#define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */
+#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */
+
+#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */
+#define MAGIC_PKT_NUM_MAC_ADDRS 16
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#if defined(DSLCPE_DELAY)
+#define WL_DELAYMODE_DEFER 0 /* defer by scheduler's choice, make this driver default */
+#define WL_DELAYMODE_FORCE 1 /* force, this is driver default */
+#define WL_DELAYMODE_AUTO 2 /* defer if no sta associated, force if sta associated */
+#endif
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* Overlap BSS Scan parameters default, minimum, maximum */
+#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 /* unit TU */
+#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 /* unit TU */
+#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 /* unit TU */
+#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 /* unit TU */
+#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 /* unit TU */
+#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 /* unit TU */
+#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 /* unit Sec */
+#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 /* unit Sec */
+#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 /* unit Sec */
+#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5
+#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5
+#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100
+#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 /* unit TU */
+#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 /* unit TU */
+#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */
+#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 /* unit TU */
+#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 /* unit TU */
+#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */
+#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 /* unit percent */
+#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 /* unit percent */
+#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 /* unit percent */
+
+#define WL_MIN_NUM_OBSS_SCAN_ARG 7 /* minimum number of arguments required for OBSS Scan */
+
+#define WL_COEX_INFO_MASK 0x07
+#define WL_COEX_INFO_REQ 0x01
+#define WL_COEX_40MHZ_INTOLERANT 0x02
+#define WL_COEX_WIDTH20 0x04
+
+#define WLC_RSSI_INVALID 0 /* invalid RSSI value */
+
+#define MAX_RSSI_LEVELS 8
+
+/* **** EXTLOG **** */
+#define EXTLOG_CUR_VER 0x0100
+
+#define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */
+
+/* log modules (bitmap) */
+#define LOG_MODULE_COMMON 0x0001
+#define LOG_MODULE_ASSOC 0x0002
+#define LOG_MODULE_EVENT 0x0004
+#define LOG_MODULE_MAX 3 /* Update when adding module */
+
+/* log levels */
+#define WL_LOG_LEVEL_DISABLE 0
+#define WL_LOG_LEVEL_ERR 1
+#define WL_LOG_LEVEL_WARN 2
+#define WL_LOG_LEVEL_INFO 3
+#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO /* Update when adding level */
+
+/* flag */
+#define LOG_FLAG_EVENT 1
+
+/* log arg_type */
+#define LOG_ARGTYPE_NULL 0
+#define LOG_ARGTYPE_STR 1 /* %s */
+#define LOG_ARGTYPE_INT 2 /* %d */
+#define LOG_ARGTYPE_INT_STR 3 /* %d...%s */
+#define LOG_ARGTYPE_STR_INT 4 /* %s...%d */
+
+/* 802.11 Mgmt Packet flags */
+#define VNDR_IE_BEACON_FLAG 0x1
+#define VNDR_IE_PRBRSP_FLAG 0x2
+#define VNDR_IE_ASSOCRSP_FLAG 0x4
+#define VNDR_IE_AUTHRSP_FLAG 0x8
+#define VNDR_IE_PRBREQ_FLAG 0x10
+#define VNDR_IE_ASSOCREQ_FLAG 0x20
+#define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */
+#define VNDR_IE_AUTHREQ_FLAG 0x80
+#define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */
+
+#if defined(WLP2P)
+/* P2P Action Frames flags (spec ordered) */
+#define VNDR_IE_GONREQ_FLAG 0x001000
+#define VNDR_IE_GONRSP_FLAG 0x002000
+#define VNDR_IE_GONCFM_FLAG 0x004000
+#define VNDR_IE_INVREQ_FLAG 0x008000
+#define VNDR_IE_INVRSP_FLAG 0x010000
+#define VNDR_IE_DISREQ_FLAG 0x020000
+#define VNDR_IE_DISRSP_FLAG 0x040000
+#define VNDR_IE_PRDREQ_FLAG 0x080000
+#define VNDR_IE_PRDRSP_FLAG 0x100000
+
+#define VNDR_IE_P2PAF_SHIFT 12
+#endif /* WLP2P */
+
+/* channel interference measurement (chanim) related defines */
+
+/* chanim mode */
+#define CHANIM_DISABLE 0 /* disabled */
+#define CHANIM_DETECT 1 /* detection only */
+#define CHANIM_EXT 2 /* external state machine */
+#define CHANIM_ACT 3 /* full internal state machine, detect + act */
+#define CHANIM_MODE_MAX 4
+
+/* define for apcs reason code */
+#define APCS_INIT 0
+#define APCS_IOCTL 1
+#define APCS_CHANIM 2
+#define APCS_CSTIMER 3
+#define APCS_TXDLY 5
+#define APCS_NONACSD 6
+#define APCS_DFS_REENTRY 7
+#define APCS_TXFAIL 8
+#define APCS_MAX 9
+
+/* number of ACS record entries */
+#define CHANIM_ACS_RECORD 10
+
+/* CHANIM */
+#define CCASTATS_TXDUR 0
+#define CCASTATS_INBSS 1
+#define CCASTATS_OBSS 2
+#define CCASTATS_NOCTG 3
+#define CCASTATS_NOPKT 4
+#define CCASTATS_DOZE 5
+#define CCASTATS_TXOP 6
+#define CCASTATS_GDTXDUR 7
+#define CCASTATS_BDTXDUR 8
+
+#ifndef WLCHANIM_V2
+#define CCASTATS_MAX 9
+#else /* WLCHANIM_V2 */
+#define CCASTATS_MYRX 9
+#define CCASTATS_MAX 10
+#endif /* WLCHANIM_V2 */
+
+#define WL_CHANIM_COUNT_ALL 0xff
+#define WL_CHANIM_COUNT_ONE 0x1
+
+/* ap tpc modes */
+#define AP_TPC_OFF 0
+#define AP_TPC_BSS_PWR 1 /* BSS power control */
+#define AP_TPC_AP_PWR 2 /* AP power control */
+#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */
+#define AP_TPC_MAX_LINK_MARGIN 127
+
+/* ap tpc modes */
+#define AP_TPC_OFF 0
+#define AP_TPC_BSS_PWR 1 /* BSS power control */
+#define AP_TPC_AP_PWR 2 /* AP power control */
+#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */
+#define AP_TPC_MAX_LINK_MARGIN 127
+
+/* state */
+#define WL_P2P_DISC_ST_SCAN 0
+#define WL_P2P_DISC_ST_LISTEN 1
+#define WL_P2P_DISC_ST_SEARCH 2
+
+/* i/f type */
+#define WL_P2P_IF_CLIENT 0
+#define WL_P2P_IF_GO 1
+#define WL_P2P_IF_DYNBCN_GO 2
+#define WL_P2P_IF_DEV 3
+
+/* count */
+#define WL_P2P_SCHED_RSVD 0
+#define WL_P2P_SCHED_REPEAT 255 /* anything > 255 will be treated as 255 */
+
+#define WL_P2P_SCHED_FIXED_LEN 3
+
+/* schedule type */
+#define WL_P2P_SCHED_TYPE_ABS 0 /* Scheduled Absence */
+#define WL_P2P_SCHED_TYPE_REQ_ABS 1 /* Requested Absence */
+
+/* schedule action during absence periods (for WL_P2P_SCHED_ABS type) */
+#define WL_P2P_SCHED_ACTION_NONE 0 /* no action */
+#define WL_P2P_SCHED_ACTION_DOZE 1 /* doze */
+/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */
+#define WL_P2P_SCHED_ACTION_GOOFF 2 /* turn off GO beacon/prbrsp functions */
+/* schedule option - WL_P2P_SCHED_TYPE_XXX */
+#define WL_P2P_SCHED_ACTION_RESET 255 /* reset */
+
+/* schedule option - WL_P2P_SCHED_TYPE_ABS */
+#define WL_P2P_SCHED_OPTION_NORMAL 0 /* normal start/interval/duration/count */
+#define WL_P2P_SCHED_OPTION_BCNPCT 1 /* percentage of beacon interval */
+/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */
+#define WL_P2P_SCHED_OPTION_TSFOFS 2 /* normal start/internal/duration/count with
+ * start being an offset of the 'current' TSF
+ */
+
+/* feature flags */
+#define WL_P2P_FEAT_GO_CSA (1 << 0) /* GO moves with the STA using CSA method */
+#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) /* GO does not probe respond to non-p2p probe
+ * requests
+ */
+#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) /* Restrict p2p dev interface from responding */
+
+/* n-mode support capability */
+/* 2x2 includes both 1x1 & 2x2 devices
+ * reserved #define 2 for future when we want to separate 1x1 & 2x2 and
+ * control it independently
+ */
+#define WL_11N_2x2 1
+#define WL_11N_3x3 3
+#define WL_11N_4x4 4
+
+/* define 11n feature disable flags */
+#define WLFEATURE_DISABLE_11N 0x00000001
+#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002
+#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004
+#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008
+#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010
+#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020
+#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040
+#define WLFEATURE_DISABLE_11N_GF 0x00000080
+
+/* Proxy STA modes */
+#define PSTA_MODE_DISABLED 0
+#define PSTA_MODE_PROXY 1
+#define PSTA_MODE_REPEATER 2
+
+/* op code in nat_cfg */
+#define NAT_OP_ENABLE 1 /* enable NAT on given interface */
+#define NAT_OP_DISABLE 2 /* disable NAT on given interface */
+#define NAT_OP_DISABLE_ALL 3 /* disable NAT on all interfaces */
+
+/* NAT state */
+#define NAT_STATE_ENABLED 1 /* NAT is enabled */
+#define NAT_STATE_DISABLED 2 /* NAT is disabled */
+
+#define CHANNEL_5G_LOW_START 36 /* 5G low (36..48) CDD enable/disable bit mask */
+#define CHANNEL_5G_MID_START 52 /* 5G mid (52..64) CDD enable/disable bit mask */
+#define CHANNEL_5G_HIGH_START 100 /* 5G high (100..140) CDD enable/disable bit mask */
+#define CHANNEL_5G_UPPER_START 149 /* 5G upper (149..161) CDD enable/disable bit mask */
+
+/* D0 Coalescing */
+#define IPV4_ARP_FILTER 0x0001
+#define IPV4_NETBT_FILTER 0x0002
+#define IPV4_LLMNR_FILTER 0x0004
+#define IPV4_SSDP_FILTER 0x0008
+#define IPV4_WSD_FILTER 0x0010
+#define IPV6_NETBT_FILTER 0x0200
+#define IPV6_LLMNR_FILTER 0x0400
+#define IPV6_SSDP_FILTER 0x0800
+#define IPV6_WSD_FILTER 0x1000
+
+/* Network Offload Engine */
+#define NWOE_OL_ENABLE 0x00000001
+
+/*
+ * Traffic management structures/defines.
+ */
+
+/* Traffic management bandwidth parameters */
+#define TRF_MGMT_MAX_PRIORITIES 3
+
+#define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */
+#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Don't shape traffic */
+#define TRF_MGMT_FLAG_MANAGE_LOCAL_TRAFFIC 0x0008 /* Manage traffic over our local subnet */
+#define TRF_MGMT_FLAG_FILTER_ON_MACADDR 0x0010 /* filter on MAC address */
+#define TRF_MGMT_FLAG_NO_RX 0x0020 /* do not apply fiters to rx packets */
+
+#define TRF_FILTER_MAC_ADDR 0x0001 /* L2 filter use dst mac address for filtering */
+#define TRF_FILTER_IP_ADDR 0x0002 /* L3 filter use ip ddress for filtering */
+#define TRF_FILTER_L4 0x0004 /* L4 filter use tcp/udp for filtering */
+#define TRF_FILTER_DWM 0x0008 /* L3 filter use DSCP for filtering */
+#define TRF_FILTER_FAVORED 0x0010 /* Tag the packet FAVORED */
+
+/* WNM/NPS subfeatures mask */
+#define WL_WNM_BSSTRANS 0x00000001
+#define WL_WNM_PROXYARP 0x00000002
+#define WL_WNM_MAXIDLE 0x00000004
+#define WL_WNM_TIMBC 0x00000008
+#define WL_WNM_TFS 0x00000010
+#define WL_WNM_SLEEP 0x00000020
+#define WL_WNM_DMS 0x00000040
+#define WL_WNM_FMS 0x00000080
+#define WL_WNM_NOTIF 0x00000100
+#define WL_WNM_WBTEXT 0x00000200
+#define WL_WNM_MAX 0x00000400
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#ifdef WLWNM_BRCM
+#define BRCM_WNM_FEATURE_SET\
+ (WL_WNM_PROXYARP | \
+ WL_WNM_SLEEP | \
+ WL_WNM_FMS | \
+ WL_WNM_TFS | \
+ WL_WNM_TIMBC | \
+ WL_WNM_BSSTRANS | \
+ WL_WNM_DMS | \
+ WL_WNM_NOTIF | \
+ 0)
+#endif /* WLWNM_BRCM */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#ifndef ETHER_MAX_DATA
+#define ETHER_MAX_DATA 1500
+#endif /* ETHER_MAX_DATA */
+
+/* Different discovery modes for dpt */
+#define DPT_DISCOVERY_MANUAL 0x01 /* manual discovery mode */
+#define DPT_DISCOVERY_AUTO 0x02 /* auto discovery mode */
+#define DPT_DISCOVERY_SCAN 0x04 /* scan-based discovery mode */
+
+/* different path selection values */
+#define DPT_PATHSEL_AUTO 0 /* auto mode for path selection */
+#define DPT_PATHSEL_DIRECT 1 /* always use direct DPT path */
+#define DPT_PATHSEL_APPATH 2 /* always use AP path */
+
+/* different ops for deny list */
+#define DPT_DENY_LIST_ADD 1 /* add to dpt deny list */
+#define DPT_DENY_LIST_REMOVE 2 /* remove from dpt deny list */
+
+/* different ops for manual end point */
+#define DPT_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */
+#define DPT_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */
+#define DPT_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */
+
+/* flags to indicate DPT status */
+#define DPT_STATUS_ACTIVE 0x01 /* link active (though may be suspended) */
+#define DPT_STATUS_AES 0x02 /* link secured through AES encryption */
+#define DPT_STATUS_FAILED 0x04 /* DPT link failed */
+
+#ifdef WLTDLS
+/* different ops for manual end point */
+#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */
+#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */
+#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */
+#define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */
+#define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */
+#define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */
+#define TDLS_MANUAL_EP_CHSW 7 /* channel switch */
+#define TDLS_MANUAL_EP_WFD_TPQ 8 /* WiFi-Display Tunneled Probe reQuest */
+
+/* modes */
+#define TDLS_WFD_IE_TX 0
+#define TDLS_WFD_IE_RX 1
+#define TDLS_WFD_PROBE_IE_TX 2
+#define TDLS_WFD_PROBE_IE_RX 3
+#endif /* WLTDLS */
+
+/* define for flag */
+#define TSPEC_PENDING 0 /* TSPEC pending */
+#define TSPEC_ACCEPTED 1 /* TSPEC accepted */
+#define TSPEC_REJECTED 2 /* TSPEC rejected */
+#define TSPEC_UNKNOWN 3 /* TSPEC unknown */
+#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */
+
+
+/* Software feature flag defines used by wlfeatureflag */
+#ifdef WLAFTERBURNER
+#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */
+#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */
+#endif /* WLAFTERBURNER */
+#define WL_SWFL_NOHWRADIO 0x0004
+#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */
+#define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */
+
+#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */
+
+#define CSA_BROADCAST_ACTION_FRAME 0 /* csa broadcast action frame */
+#define CSA_UNICAST_ACTION_FRAME 1 /* csa unicast action frame */
+
+/* Roaming trigger definitions for WLC_SET_ROAM_TRIGGER.
+ *
+ * (-100 < value < 0) value is used directly as a roaming trigger in dBm
+ * (0 <= value) value specifies a logical roaming trigger level from
+ * the list below
+ *
+ * WLC_GET_ROAM_TRIGGER always returns roaming trigger value in dBm, never
+ * the logical roam trigger value.
+ */
+#define WLC_ROAM_TRIGGER_DEFAULT 0 /* default roaming trigger */
+#define WLC_ROAM_TRIGGER_BANDWIDTH 1 /* optimize for bandwidth roaming trigger */
+#define WLC_ROAM_TRIGGER_DISTANCE 2 /* optimize for distance roaming trigger */
+#define WLC_ROAM_TRIGGER_AUTO 3 /* auto-detect environment */
+#define WLC_ROAM_TRIGGER_MAX_VALUE 3 /* max. valid value */
+
+#define WLC_ROAM_NEVER_ROAM_TRIGGER (-100) /* Avoid Roaming by setting a large value */
+
+/* Preferred Network Offload (PNO, formerly PFN) defines */
+#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */
+
+#define SORT_CRITERIA_BIT 0
+#define AUTO_NET_SWITCH_BIT 1
+#define ENABLE_BKGRD_SCAN_BIT 2
+#define IMMEDIATE_SCAN_BIT 3
+#define AUTO_CONNECT_BIT 4
+#define ENABLE_BD_SCAN_BIT 5
+#define ENABLE_ADAPTSCAN_BIT 6
+#define IMMEDIATE_EVENT_BIT 8
+#define SUPPRESS_SSID_BIT 9
+#define ENABLE_NET_OFFLOAD_BIT 10
+/* report found/lost events for SSID and BSSID networks seperately */
+#define REPORT_SEPERATELY_BIT 11
+#define BESTN_BSSID_ONLY_BIT 12
+
+#define SORT_CRITERIA_MASK 0x0001
+#define AUTO_NET_SWITCH_MASK 0x0002
+#define ENABLE_BKGRD_SCAN_MASK 0x0004
+#define IMMEDIATE_SCAN_MASK 0x0008
+#define AUTO_CONNECT_MASK 0x0010
+
+#define ENABLE_BD_SCAN_MASK 0x0020
+#define ENABLE_ADAPTSCAN_MASK 0x00c0
+#define IMMEDIATE_EVENT_MASK 0x0100
+#define SUPPRESS_SSID_MASK 0x0200
+#define ENABLE_NET_OFFLOAD_MASK 0x0400
+/* report found/lost events for SSID and BSSID networks seperately */
+#define REPORT_SEPERATELY_MASK 0x0800
+#define BESTN_BSSID_ONLY_MASK 0x1000
+
+#define PFN_VERSION 2
+#ifdef PFN_SCANRESULT_2
+#define PFN_SCANRESULT_VERSION 2
+#else
+#define PFN_SCANRESULT_VERSION 1
+#endif /* PFN_SCANRESULT_2 */
+#ifndef MAX_PFN_LIST_COUNT
+#define MAX_PFN_LIST_COUNT 16
+#endif /* MAX_PFN_LIST_COUNT */
+
+#define PFN_COMPLETE 1
+#define PFN_INCOMPLETE 0
+
+#define DEFAULT_BESTN 2
+#define DEFAULT_MSCAN 0
+#define DEFAULT_REPEAT 10
+#define DEFAULT_EXP 2
+
+#define PFN_PARTIAL_SCAN_BIT 0
+#define PFN_PARTIAL_SCAN_MASK 1
+
+#define WL_PFN_SUPPRESSFOUND_MASK 0x08
+#define WL_PFN_SUPPRESSLOST_MASK 0x10
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WL_PFN_SSID_A_BAND_TRIG 0x20
+#define WL_PFN_SSID_BG_BAND_TRIG 0x40
+#define WL_PFN_SSID_IMPRECISE_MATCH 0x80
+#define WL_PFN_SSID_SAME_NETWORK 0x10000
+#define WL_PFN_SUPPRESS_AGING_MASK 0x20000
+#define WL_PFN_FLUSH_ALL_SSIDS 0x40000
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#define WL_PFN_RSSI_MASK 0xff00
+#define WL_PFN_RSSI_SHIFT 8
+
+#define WL_PFN_REPORT_ALLNET 0
+#define WL_PFN_REPORT_SSIDNET 1
+#define WL_PFN_REPORT_BSSIDNET 2
+
+#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */
+#define WL_PFN_CFG_FLAGS_HISTORY_OFF 0x00000002 /* Scan history suppressed */
+
+#define WL_PFN_HIDDEN_BIT 2
+#define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */
+#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */
+#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */
+#define WL_PFN_HIDDEN_MASK 0x4
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define MAX_SSID_WHITELIST_NUM 4
+#define MAX_BSSID_PREF_LIST_NUM 32
+#define MAX_BSSID_BLACKLIST_NUM 32
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+#ifndef BESTN_MAX
+#define BESTN_MAX 10
+#endif
+
+#ifndef MSCAN_MAX
+#define MSCAN_MAX 32
+#endif
+
+/* TCP Checksum Offload error injection for testing */
+#define TOE_ERRTEST_TX_CSUM 0x00000001
+#define TOE_ERRTEST_RX_CSUM 0x00000002
+#define TOE_ERRTEST_RX_CSUM2 0x00000004
+
+/* ARP Offload feature flags for arp_ol iovar */
+#define ARP_OL_AGENT 0x00000001
+#define ARP_OL_SNOOP 0x00000002
+#define ARP_OL_HOST_AUTO_REPLY 0x00000004
+#define ARP_OL_PEER_AUTO_REPLY 0x00000008
+
+/* ARP Offload error injection */
+#define ARP_ERRTEST_REPLY_PEER 0x1
+#define ARP_ERRTEST_REPLY_HOST 0x2
+
+#define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */
+#define ND_MULTIHOMING_MAX 10 /* Maximum local host IP addresses */
+#define ND_REQUEST_MAX 5 /* Max set of offload params */
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/* AOAC wake event flag */
+#define WAKE_EVENT_NLO_DISCOVERY_BIT 1
+#define WAKE_EVENT_AP_ASSOCIATION_LOST_BIT 2
+#define WAKE_EVENT_GTK_HANDSHAKE_ERROR_BIT 4
+#define WAKE_EVENT_4WAY_HANDSHAKE_REQUEST_BIT 8
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define WAKE_EVENT_NET_PACKET_BIT 0x10
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+#define MAX_NUM_WOL_PATTERN 22 /* LOGO requirements min 22 */
+
+
+/* Packet filter operation mode */
+/* True: 1; False: 0 */
+#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1
+/* Enable and disable pkt_filter as a whole */
+#define PKT_FILTER_MODE_DISABLE 2
+/* Cache first matched rx pkt(be queried by host later) */
+#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4
+/* If pkt_filter is enabled and no filter is set, don't forward anything */
+#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8
+
+#ifdef DONGLEOVERLAYS
+#define OVERLAY_IDX_MASK 0x000000ff
+#define OVERLAY_IDX_SHIFT 0
+#define OVERLAY_FLAGS_MASK 0xffffff00
+#define OVERLAY_FLAGS_SHIFT 8
+/* overlay written to device memory immediately after loading the base image */
+#define OVERLAY_FLAG_POSTLOAD 0x100
+/* defer overlay download until the device responds w/WLC_E_OVL_DOWNLOAD event */
+#define OVERLAY_FLAG_DEFER_DL 0x200
+/* overlay downloaded prior to the host going to sleep */
+#define OVERLAY_FLAG_PRESLEEP 0x400
+#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024
+#endif /* DONGLEOVERLAYS */
+
+/* reuse two number in the sc/rc space */
+#define SMFS_CODE_MALFORMED 0xFFFE
+#define SMFS_CODE_IGNORED 0xFFFD
+
+/* RFAWARE def */
+#define BCM_ACTION_RFAWARE 0x77
+#define BCM_ACTION_RFAWARE_DCS 0x01
+
+/* DCS reason code define */
+#define BCM_DCS_IOVAR 0x1
+#define BCM_DCS_UNKNOWN 0xFF
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#ifdef EXT_STA
+#define IHV_OID_BCM 0x00181000 /* based on BRCM_OUI value */
+/* ---------------------------------------------------------------------------
+* Event codes
+* ---------------------------------------------------------------------------
+*/
+
+#define IHV_DRIVER_EVENT_GEN_INDICATION 0x00000011L /* from driver */
+#endif /* EXT_STA */
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+#ifdef PROP_TXSTATUS
+/* Bit definitions for tlv iovar */
+/*
+ * enable RSSI signals:
+ * WLFC_CTL_TYPE_RSSI
+ */
+#define WLFC_FLAGS_RSSI_SIGNALS 0x0001
+
+/* enable (if/mac_open, if/mac_close,, mac_add, mac_del) signals:
+ *
+ * WLFC_CTL_TYPE_MAC_OPEN
+ * WLFC_CTL_TYPE_MAC_CLOSE
+ *
+ * WLFC_CTL_TYPE_INTERFACE_OPEN
+ * WLFC_CTL_TYPE_INTERFACE_CLOSE
+ *
+ * WLFC_CTL_TYPE_MACDESC_ADD
+ * WLFC_CTL_TYPE_MACDESC_DEL
+ *
+ */
+#define WLFC_FLAGS_XONXOFF_SIGNALS 0x0002
+
+/* enable (status, fifo_credit, mac_credit) signals
+ * WLFC_CTL_TYPE_MAC_REQUEST_CREDIT
+ * WLFC_CTL_TYPE_TXSTATUS
+ * WLFC_CTL_TYPE_FIFO_CREDITBACK
+ */
+#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 0x0004
+
+#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008
+#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010
+#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020
+#define WLFC_FLAGS_HOST_RXRERODER_ACTIVE 0x0040
+#define WLFC_FLAGS_PKT_STAMP_SIGNALS 0x0080
+
+#endif /* PROP_TXSTATUS */
+
+#define WL_TIMBC_STATUS_AP_UNKNOWN 255 /* AP status for internal use only */
+
+#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */
+#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */
+#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */
+
+/* Definitions for Reliable Multicast */
+#define WL_RELMCAST_MAX_CLIENT 32
+#define WL_RELMCAST_FLAG_INBLACKLIST 1
+#define WL_RELMCAST_FLAG_ACTIVEACKER 2
+#define WL_RELMCAST_FLAG_RELMCAST 4
+
+/* structures for proximity detection device role */
+#define WL_PROXD_MODE_DISABLE 0
+#define WL_PROXD_MODE_NEUTRAL 1
+#define WL_PROXD_MODE_INITIATOR 2
+#define WL_PROXD_MODE_TARGET 3
+#define WL_PROXD_RANDOM_WAKEUP 0x8000
+
+
+#ifdef NET_DETECT
+#define NET_DETECT_MAX_WAKE_DATA_SIZE 2048
+#define NET_DETECT_MAX_PROFILES 16
+#define NET_DETECT_MAX_CHANNELS 50
+#endif /* NET_DETECT */
+
+
+/* Bit masks for radio disabled status - returned by WL_GET_RADIO */
+#define WL_RADIO_SW_DISABLE (1<<0)
+#define WL_RADIO_HW_DISABLE (1<<1)
+#define WL_RADIO_MPC_DISABLE (1<<2)
+#define WL_RADIO_COUNTRY_DISABLE (1<<3) /* some countries don't support any channel */
+#define WL_RADIO_PERCORE_DISABLE (1<<4) /* Radio diable per core for DVT */
+
+#define WL_SPURAVOID_OFF 0
+#define WL_SPURAVOID_ON1 1
+#define WL_SPURAVOID_ON2 2
+
+
+#define WL_4335_SPURAVOID_ON1 1
+#define WL_4335_SPURAVOID_ON2 2
+#define WL_4335_SPURAVOID_ON3 3
+#define WL_4335_SPURAVOID_ON4 4
+#define WL_4335_SPURAVOID_ON5 5
+#define WL_4335_SPURAVOID_ON6 6
+#define WL_4335_SPURAVOID_ON7 7
+#define WL_4335_SPURAVOID_ON8 8
+#define WL_4335_SPURAVOID_ON9 9
+
+/* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */
+#define WL_TXPWR_OVERRIDE (1U<<31)
+#define WL_TXPWR_2G (1U<<30)
+#define WL_TXPWR_5G (1U<<29)
+#define WL_TXPWR_NEG (1U<<28)
+
+#define WL_TXPWR_MASK (~(0x7<<29))
+#define WL_TXPWR_CORE_MAX (3)
+#define WL_TXPWR_CORE0_MASK (0x000000FF)
+#define WL_TXPWR_CORE0_SHIFT (0)
+#define WL_TXPWR_CORE1_MASK (0x0000FF00)
+#define WL_TXPWR_CORE1_SHIFT (8)
+#define WL_TXPWR_CORE2_MASK (0x00FF0000)
+#define WL_TXPWR_CORE2_SHIFT (16)
+
+/* phy types (returned by WLC_GET_PHYTPE) */
+#define WLC_PHY_TYPE_A 0
+#define WLC_PHY_TYPE_B 1
+#define WLC_PHY_TYPE_G 2
+#define WLC_PHY_TYPE_N 4
+#define WLC_PHY_TYPE_LP 5
+#define WLC_PHY_TYPE_SSN 6
+#define WLC_PHY_TYPE_HT 7
+#define WLC_PHY_TYPE_LCN 8
+#define WLC_PHY_TYPE_LCN40 10
+#define WLC_PHY_TYPE_AC 11
+#define WLC_PHY_TYPE_LCN20 12
+#define WLC_PHY_TYPE_NULL 0xf
+
+/* Values for PM */
+#define PM_OFF 0
+#define PM_MAX 1
+#define PM_FAST 2
+#define PM_FORCE_OFF 3 /* use this bit to force PM off even bt is active */
+
+#define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */
+
+/* fbt_cap: FBT assoc / reassoc modes. */
+#define WLC_FBT_CAP_DRV_4WAY_AND_REASSOC 1 /* Driver 4-way handshake & reassoc (WLFBT). */
+
+/* monitor_promisc_level bits */
+#define WL_MONPROMISC_PROMISC 0x0001
+#define WL_MONPROMISC_CTRL 0x0002
+#define WL_MONPROMISC_FCS 0x0004
+
+/* TCP Checksum Offload defines */
+#define TOE_TX_CSUM_OL 0x00000001
+#define TOE_RX_CSUM_OL 0x00000002
+
+/* Wi-Fi Display Services (WFDS) */
+#define WL_P2P_SOCIAL_CHANNELS_MAX WL_NUMCHANNELS
+#define MAX_WFDS_SEEK_SVC 4 /* Max # of wfds services to seek */
+#define MAX_WFDS_ADVERT_SVC 4 /* Max # of wfds services to advertise */
+#define MAX_WFDS_SVC_NAME_LEN 200 /* maximum service_name length */
+#define MAX_WFDS_ADV_SVC_INFO_LEN 65000 /* maximum adv service_info length */
+#define P2P_WFDS_HASH_LEN 6 /* Length of a WFDS service hash */
+#define MAX_WFDS_SEEK_SVC_INFO_LEN 255 /* maximum seek service_info req length */
+#define MAX_WFDS_SEEK_SVC_NAME_LEN 200 /* maximum service_name length */
+
+/* ap_isolate bitmaps */
+#define AP_ISOLATE_DISABLED 0x0
+#define AP_ISOLATE_SENDUP_ALL 0x01
+#define AP_ISOLATE_SENDUP_MCAST 0x02
+
+/* Type values for the wl_pwrstats_t data field */
+#define WL_PWRSTATS_TYPE_PHY 0 /**< struct wl_pwr_phy_stats */
+#define WL_PWRSTATS_TYPE_SCAN 1 /**< struct wl_pwr_scan_stats */
+#define WL_PWRSTATS_TYPE_USB_HSIC 2 /**< struct wl_pwr_usb_hsic_stats */
+#define WL_PWRSTATS_TYPE_PM_AWAKE1 3 /**< struct wl_pwr_pm_awake_stats_v1 */
+#define WL_PWRSTATS_TYPE_CONNECTION 4 /* struct wl_pwr_connect_stats; assoc and key-exch time */
+#define WL_PWRSTATS_TYPE_PCIE 6 /**< struct wl_pwr_pcie_stats */
+#define WL_PWRSTATS_TYPE_PM_AWAKE2 7 /**< struct wl_pwr_pm_awake_stats_v2 */
+#define WL_PWRSTATS_TYPE_SDIO 8 /* struct wl_pwr_sdio_stats */
+#define WL_PWRSTATS_TYPE_MIMO_PS_METRICS 9 /* struct wl_mimo_meas_metrics_t */
+
+#endif /* wlioctl_defs_h */
diff --git a/wl/components/shared/proto/802.11.h b/wl/components/shared/proto/802.11.h
new file mode 100644
index 0000000..a5ec095
--- /dev/null
+++ b/wl/components/shared/proto/802.11.h
@@ -0,0 +1,4961 @@
+/*
+ * Fundamental types and constants relating to 802.11
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: 802.11.h 663798 2017-02-09 06:38:25Z $
+ */
+
+#ifndef _802_11_H_
+#define _802_11_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+#ifndef _NET_ETHERNET_H_
+#include <proto/ethernet.h>
+#endif
+
+#include <proto/wpa.h>
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+#define DOT11_TU_TO_US 1024 /* 802.11 Time Unit is 1024 microseconds */
+
+/* Generic 802.11 frame constants */
+#define DOT11_A3_HDR_LEN 24 /* d11 header length with A3 */
+#define DOT11_A4_HDR_LEN 30 /* d11 header length with A4 */
+#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN /* MAC header length */
+#define DOT11_FCS_LEN 4 /* d11 FCS length */
+#define DOT11_ICV_LEN 4 /* d11 ICV length */
+#define DOT11_ICV_AES_LEN 8 /* d11 ICV/AES length */
+#define DOT11_QOS_LEN 2 /* d11 QoS length */
+#define DOT11_HTC_LEN 4 /* d11 HT Control field length */
+
+#define DOT11_KEY_INDEX_SHIFT 6 /* d11 key index shift */
+#define DOT11_IV_LEN 4 /* d11 IV length */
+#define DOT11_IV_TKIP_LEN 8 /* d11 IV TKIP length */
+#define DOT11_IV_AES_OCB_LEN 4 /* d11 IV/AES/OCB length */
+#define DOT11_IV_AES_CCM_LEN 8 /* d11 IV/AES/CCM length */
+#define DOT11_IV_MAX_LEN 8 /* maximum iv len for any encryption */
+
+/* Includes MIC */
+#define DOT11_MAX_MPDU_BODY_LEN 2304 /* max MPDU body length */
+/* A4 header + QoS + CCMP + PDU + ICV + FCS = 2352 */
+#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \
+ DOT11_QOS_LEN + \
+ DOT11_IV_AES_CCM_LEN + \
+ DOT11_MAX_MPDU_BODY_LEN + \
+ DOT11_ICV_LEN + \
+ DOT11_FCS_LEN) /* d11 max MPDU length */
+
+#define DOT11_MAX_SSID_LEN 32 /* d11 max ssid length */
+
+/* dot11RTSThreshold */
+#define DOT11_DEFAULT_RTS_LEN 2347 /* d11 default RTS length */
+#define DOT11_MAX_RTS_LEN 2347 /* d11 max RTS length */
+
+/* dot11FragmentationThreshold */
+#define DOT11_MIN_FRAG_LEN 256 /* d11 min fragmentation length */
+#define DOT11_MAX_FRAG_LEN 2346 /* Max frag is also limited by aMPDUMaxLength
+ * of the attached PHY
+ */
+#define DOT11_DEFAULT_FRAG_LEN 2346 /* d11 default fragmentation length */
+
+/* dot11BeaconPeriod */
+#define DOT11_MIN_BEACON_PERIOD 1 /* d11 min beacon period */
+#define DOT11_MAX_BEACON_PERIOD 0xFFFF /* d11 max beacon period */
+
+/* dot11DTIMPeriod */
+#define DOT11_MIN_DTIM_PERIOD 1 /* d11 min DTIM period */
+#define DOT11_MAX_DTIM_PERIOD 0xFF /* d11 max DTIM period */
+
+/** 802.2 LLC/SNAP header used by 802.11 per 802.1H */
+#define DOT11_LLC_SNAP_HDR_LEN 8 /* d11 LLC/SNAP header length */
+/* minimum LLC header length; DSAP, SSAP, 8 bit Control (unnumbered) */
+#define DOT11_LLC_HDR_LEN_MIN 3
+#define DOT11_OUI_LEN 3 /* d11 OUI length */
+BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header {
+ uint8 dsap; /* always 0xAA */
+ uint8 ssap; /* always 0xAA */
+ uint8 ctl; /* always 0x03 */
+ uint8 oui[DOT11_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00
+ * Bridge-Tunnel: 0x00 0x00 0xF8
+ */
+ uint16 type; /* ethertype */
+} BWL_POST_PACKED_STRUCT;
+
+/* RFC1042 header used by 802.11 per 802.1H */
+#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) /* RCF1042 header length */
+
+/* Generic 802.11 MAC header */
+/**
+ * N.B.: This struct reflects the full 4 address 802.11 MAC header.
+ * The fields are defined such that the shorter 1, 2, and 3
+ * address headers just use the first k fields.
+ */
+BWL_PRE_PACKED_STRUCT struct dot11_header {
+ uint16 fc; /* frame control */
+ uint16 durid; /* duration/ID */
+ struct ether_addr a1; /* address 1 */
+ struct ether_addr a2; /* address 2 */
+ struct ether_addr a3; /* address 3 */
+ uint16 seq; /* sequence control */
+ struct ether_addr a4; /* address 4 */
+} BWL_POST_PACKED_STRUCT;
+
+/* Control frames */
+
+BWL_PRE_PACKED_STRUCT struct dot11_rts_frame {
+ uint16 fc; /* frame control */
+ uint16 durid; /* duration/ID */
+ struct ether_addr ra; /* receiver address */
+ struct ether_addr ta; /* transmitter address */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_RTS_LEN 16 /* d11 RTS frame length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_cts_frame {
+ uint16 fc; /* frame control */
+ uint16 durid; /* duration/ID */
+ struct ether_addr ra; /* receiver address */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_CTS_LEN 10 /* d11 CTS frame length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_ack_frame {
+ uint16 fc; /* frame control */
+ uint16 durid; /* duration/ID */
+ struct ether_addr ra; /* receiver address */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_ACK_LEN 10 /* d11 ACK frame length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame {
+ uint16 fc; /* frame control */
+ uint16 durid; /* AID */
+ struct ether_addr bssid; /* receiver address, STA in AP */
+ struct ether_addr ta; /* transmitter address */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_PS_POLL_LEN 16 /* d11 PS poll frame length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame {
+ uint16 fc; /* frame control */
+ uint16 durid; /* duration/ID */
+ struct ether_addr ra; /* receiver address */
+ struct ether_addr bssid; /* transmitter address, STA in AP */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_CS_END_LEN 16 /* d11 CF-END frame length */
+
+/**
+ * RWL wifi protocol: The Vendor Specific Action frame is defined for vendor-specific signaling
+ * category+OUI+vendor specific content ( this can be variable)
+ */
+BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific {
+ uint8 category;
+ uint8 OUI[3];
+ uint8 type;
+ uint8 subtype;
+ uint8 data[1040];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t;
+
+/** generic vendor specific action frame with variable length */
+BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr {
+ uint8 category;
+ uint8 OUI[3];
+ uint8 type;
+ uint8 subtype;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t;
+
+#define DOT11_ACTION_VS_HDR_LEN 6
+
+#define BCM_ACTION_OUI_BYTE0 0x00
+#define BCM_ACTION_OUI_BYTE1 0x90
+#define BCM_ACTION_OUI_BYTE2 0x4c
+
+/* BA/BAR Control parameters */
+#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 /* normal ack */
+#define DOT11_BA_CTL_POLICY_NOACK 0x0001 /* no ack */
+#define DOT11_BA_CTL_POLICY_MASK 0x0001 /* ack policy mask */
+
+#define DOT11_BA_CTL_MTID 0x0002 /* multi tid BA */
+#define DOT11_BA_CTL_COMPRESSED 0x0004 /* compressed bitmap */
+
+#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 /* num msdu in bitmap mask */
+#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 /* num msdu in bitmap shift */
+
+#define DOT11_BA_CTL_TID_MASK 0xF000 /* tid mask */
+#define DOT11_BA_CTL_TID_SHIFT 12 /* tid shift */
+
+/** control frame header (BA/BAR) */
+BWL_PRE_PACKED_STRUCT struct dot11_ctl_header {
+ uint16 fc; /* frame control */
+ uint16 durid; /* duration/ID */
+ struct ether_addr ra; /* receiver address */
+ struct ether_addr ta; /* transmitter address */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_CTL_HDR_LEN 16 /* control frame hdr len */
+
+/** BAR frame payload */
+BWL_PRE_PACKED_STRUCT struct dot11_bar {
+ uint16 bar_control; /* BAR Control */
+ uint16 seqnum; /* Starting Sequence control */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_BAR_LEN 4 /* BAR frame payload length */
+
+#define DOT11_BA_BITMAP_LEN 128 /* bitmap length */
+#define DOT11_BA_CMP_BITMAP_LEN 8 /* compressed bitmap length */
+/** BA frame payload */
+BWL_PRE_PACKED_STRUCT struct dot11_ba {
+ uint16 ba_control; /* BA Control */
+ uint16 seqnum; /* Starting Sequence control */
+ uint8 bitmap[DOT11_BA_BITMAP_LEN]; /* Block Ack Bitmap */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_BA_LEN 4 /* BA frame payload len (wo bitmap) */
+
+/** Management frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_management_header {
+ uint16 fc; /* frame control */
+ uint16 durid; /* duration/ID */
+ struct ether_addr da; /* receiver address */
+ struct ether_addr sa; /* transmitter address */
+ struct ether_addr bssid; /* BSS ID */
+ uint16 seq; /* sequence control */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_management_header dot11_management_header_t;
+#define DOT11_MGMT_HDR_LEN 24 /* d11 management header length */
+
+/* Management frame payloads */
+
+BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb {
+ uint32 timestamp[2];
+ uint16 beacon_interval;
+ uint16 capability;
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_BCN_PRB_LEN 12 /* 802.11 beacon/probe frame fixed length */
+#define DOT11_BCN_PRB_FIXED_LEN 12 /* 802.11 beacon/probe frame fixed length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_auth {
+ uint16 alg; /* algorithm */
+ uint16 seq; /* sequence control */
+ uint16 status; /* status code */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_AUTH_FIXED_LEN 6 /* length of auth frame without challenge IE */
+
+BWL_PRE_PACKED_STRUCT struct dot11_assoc_req {
+ uint16 capability; /* capability information */
+ uint16 listen; /* listen interval */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_ASSOC_REQ_FIXED_LEN 4 /* length of assoc frame without info elts */
+
+BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req {
+ uint16 capability; /* capability information */
+ uint16 listen; /* listen interval */
+ struct ether_addr ap; /* Current AP address */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_REASSOC_REQ_FIXED_LEN 10 /* length of assoc frame without info elts */
+
+BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp {
+ uint16 capability; /* capability information */
+ uint16 status; /* status code */
+ uint16 aid; /* association ID */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_ASSOC_RESP_FIXED_LEN 6 /* length of assoc resp frame without info elts */
+
+BWL_PRE_PACKED_STRUCT struct dot11_action_measure {
+ uint8 category;
+ uint8 action;
+ uint8 token;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_ACTION_MEASURE_LEN 3 /* d11 action measurement header length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width {
+ uint8 category;
+ uint8 action;
+ uint8 ch_width;
+} BWL_POST_PACKED_STRUCT;
+
+BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops {
+ uint8 category;
+ uint8 action;
+ uint8 control;
+} BWL_POST_PACKED_STRUCT;
+
+BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query {
+ uint8 category;
+ uint8 action;
+ uint16 id;
+} BWL_POST_PACKED_STRUCT;
+
+BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode {
+ uint8 category;
+ uint8 action;
+ uint8 mode;
+} BWL_POST_PACKED_STRUCT;
+
+/* These lengths assume 64 MU groups, as specified in 802.11ac-2013 */
+#define DOT11_ACTION_GID_MEMBERSHIP_LEN 8 /* bytes */
+#define DOT11_ACTION_GID_USER_POS_LEN 16 /* bytes */
+BWL_PRE_PACKED_STRUCT struct dot11_action_group_id {
+ uint8 category;
+ uint8 action;
+ uint8 membership_status[DOT11_ACTION_GID_MEMBERSHIP_LEN];
+ uint8 user_position[DOT11_ACTION_GID_USER_POS_LEN];
+} BWL_POST_PACKED_STRUCT;
+
+#define SM_PWRSAVE_ENABLE 1
+#define SM_PWRSAVE_MODE 2
+
+/* ************* 802.11h related definitions. ************* */
+BWL_PRE_PACKED_STRUCT struct dot11_power_cnst {
+ uint8 id;
+ uint8 len;
+ uint8 power;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_power_cnst dot11_power_cnst_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_power_cap {
+ int8 min;
+ int8 max;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_power_cap dot11_power_cap_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep {
+ uint8 id;
+ uint8 len;
+ uint8 tx_pwr;
+ uint8 margin;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tpc_rep dot11_tpc_rep_t;
+#define DOT11_MNG_IE_TPC_REPORT_LEN 2 /* length of IE data, not including 2 byte header */
+
+BWL_PRE_PACKED_STRUCT struct dot11_supp_channels {
+ uint8 id;
+ uint8 len;
+ uint8 first_channel;
+ uint8 num_channels;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_supp_channels dot11_supp_channels_t;
+
+/**
+ * Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband
+ * offset for 40MHz operation. The possible 3 values are:
+ * 1 = above control channel
+ * 3 = below control channel
+ * 0 = no extension channel
+ */
+BWL_PRE_PACKED_STRUCT struct dot11_extch {
+ uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */
+ uint8 len; /* IE length */
+ uint8 extch;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_extch dot11_extch_ie_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch {
+ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */
+ uint8 len; /* IE length */
+ uint8 oui[3];
+ uint8 type; /* type indicates what follows */
+ uint8 extch;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t;
+
+#define BRCM_EXTCH_IE_LEN 5
+#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */
+#define DOT11_EXTCH_IE_LEN 1
+#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */
+#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */
+#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */
+#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */
+
+BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr {
+ uint8 category;
+ uint8 action;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_action_frmhdr dot11_action_frmhdr_t;
+#define DOT11_ACTION_FRMHDR_LEN 2
+
+/** CSA IE data structure */
+BWL_PRE_PACKED_STRUCT struct dot11_channel_switch {
+ uint8 id; /* id DOT11_MNG_CHANNEL_SWITCH_ID */
+ uint8 len; /* length of IE */
+ uint8 mode; /* mode 0 or 1 */
+ uint8 channel; /* channel switch to */
+ uint8 count; /* number of beacons before switching */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_channel_switch dot11_chan_switch_ie_t;
+
+#define DOT11_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */
+/* CSA mode - 802.11h-2003 $7.3.2.20 */
+#define DOT11_CSA_MODE_ADVISORY 0 /* no DOT11_CSA_MODE_NO_TX restriction imposed */
+#define DOT11_CSA_MODE_NO_TX 1 /* no transmission upon receiving CSA frame. */
+
+BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel {
+ uint8 category;
+ uint8 action;
+ dot11_chan_switch_ie_t chan_switch_ie; /* for switch IE */
+ dot11_brcm_extch_ie_t extch_ie; /* extension channel offset */
+} BWL_POST_PACKED_STRUCT;
+
+BWL_PRE_PACKED_STRUCT struct dot11_csa_body {
+ uint8 mode; /* mode 0 or 1 */
+ uint8 reg; /* regulatory class */
+ uint8 channel; /* channel switch to */
+ uint8 count; /* number of beacons before switching */
+} BWL_POST_PACKED_STRUCT;
+
+/** 11n Extended Channel Switch IE data structure */
+BWL_PRE_PACKED_STRUCT struct dot11_ext_csa {
+ uint8 id; /* id DOT11_MNG_EXT_CHANNEL_SWITCH_ID */
+ uint8 len; /* length of IE */
+ struct dot11_csa_body b; /* body of the ie */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ext_csa dot11_ext_csa_ie_t;
+#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */
+
+BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa {
+ uint8 category;
+ uint8 action;
+ dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */
+} BWL_POST_PACKED_STRUCT;
+
+BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa {
+ uint8 category;
+ uint8 action;
+ struct dot11_csa_body b; /* body of the ie */
+} BWL_POST_PACKED_STRUCT;
+
+/** Wide Bandwidth Channel Switch IE data structure */
+BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch {
+ uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */
+ uint8 len; /* length of IE */
+ uint8 channel_width; /* new channel width */
+ uint8 center_frequency_segment_0; /* center frequency segment 0 */
+ uint8 center_frequency_segment_1; /* center frequency segment 1 */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t;
+
+#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */
+
+/** Channel Switch Wrapper IE data structure */
+BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper {
+ uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */
+ uint8 len; /* length of IE */
+ dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t;
+
+typedef enum wide_bw_chan_width {
+ WIDE_BW_CHAN_WIDTH_20 = 0,
+ WIDE_BW_CHAN_WIDTH_40 = 1,
+ WIDE_BW_CHAN_WIDTH_80 = 2,
+ WIDE_BW_CHAN_WIDTH_160 = 3,
+ WIDE_BW_CHAN_WIDTH_80_80 = 4
+} wide_bw_chan_width_t;
+
+/** Wide Bandwidth Channel IE data structure */
+BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel {
+ uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_ID */
+ uint8 len; /* length of IE */
+ uint8 channel_width; /* channel width */
+ uint8 center_frequency_segment_0; /* center frequency segment 0 */
+ uint8 center_frequency_segment_1; /* center frequency segment 1 */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_wide_bw_channel dot11_wide_bw_chan_ie_t;
+
+#define DOT11_WIDE_BW_IE_LEN 3 /* length of IE data, not including 2 byte header */
+/** VHT Transmit Power Envelope IE data structure */
+BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope {
+ uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */
+ uint8 len; /* length of IE */
+ uint8 transmit_power_info;
+ uint8 local_max_transmit_power_20;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t;
+
+/* vht transmit power envelope IE length depends on channel width */
+#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_40MHZ 1
+#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_80MHZ 2
+#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_160MHZ 3
+
+BWL_PRE_PACKED_STRUCT struct dot11_obss_coex {
+ uint8 id;
+ uint8 len;
+ uint8 info;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_obss_coex dot11_obss_coex_t;
+#define DOT11_OBSS_COEXINFO_LEN 1 /* length of OBSS Coexistence INFO IE */
+
+#define DOT11_OBSS_COEX_INFO_REQ 0x01
+#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02
+#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04
+
+BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist {
+ uint8 id;
+ uint8 len;
+ uint8 regclass;
+ uint8 chanlist[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_obss_chanlist dot11_obss_chanlist_t;
+#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 /* fixed length of regclass */
+
+BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie {
+ uint8 id;
+ uint8 len;
+ uint8 cap[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_extcap_ie dot11_extcap_ie_t;
+
+#define DOT11_EXTCAP_LEN_COEX 1
+#define DOT11_EXTCAP_LEN_BT 3
+#define DOT11_EXTCAP_LEN_IW 4
+#define DOT11_EXTCAP_LEN_SI 6
+
+#define DOT11_EXTCAP_LEN_TDLS 5
+#define DOT11_11AC_EXTCAP_LEN_TDLS 8
+
+#define DOT11_EXTCAP_LEN_FMS 2
+#define DOT11_EXTCAP_LEN_PROXY_ARP 2
+#define DOT11_EXTCAP_LEN_TFS 3
+#define DOT11_EXTCAP_LEN_WNM_SLEEP 3
+#define DOT11_EXTCAP_LEN_TIMBC 3
+#define DOT11_EXTCAP_LEN_BSSTRANS 3
+#define DOT11_EXTCAP_LEN_DMS 4
+#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6
+#define DOT11_EXTCAP_LEN_TDLS_WBW 8
+#define DOT11_EXTCAP_LEN_OPMODE_NOTIFICATION 8
+
+/* TDLS Capabilities */
+#define DOT11_TDLS_CAP_TDLS 37 /* TDLS support */
+#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */
+#define DOT11_TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */
+#define DOT11_TDLS_CAP_CH_SW 30 /* TDLS Channel switch */
+#define DOT11_TDLS_CAP_PROH 38 /* TDLS prohibited */
+#define DOT11_TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */
+#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 /* TDLS Wider Band-Width */
+
+#define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */
+
+/* 802.11h/802.11k Measurement Request/Report IEs */
+/* Measurement Type field */
+#define DOT11_MEASURE_TYPE_BASIC 0 /* d11 measurement basic type */
+#define DOT11_MEASURE_TYPE_CCA 1 /* d11 measurement CCA type */
+#define DOT11_MEASURE_TYPE_RPI 2 /* d11 measurement RPI type */
+#define DOT11_MEASURE_TYPE_CHLOAD 3 /* d11 measurement Channel Load type */
+#define DOT11_MEASURE_TYPE_NOISE 4 /* d11 measurement Noise Histogram type */
+#define DOT11_MEASURE_TYPE_BEACON 5 /* d11 measurement Beacon type */
+#define DOT11_MEASURE_TYPE_FRAME 6 /* d11 measurement Frame type */
+#define DOT11_MEASURE_TYPE_STAT 7 /* d11 measurement STA Statistics type */
+#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */
+#define DOT11_MEASURE_TYPE_TXSTREAM 9 /* d11 measurement TX Stream type */
+#define DOT11_MEASURE_TYPE_MCDIAGS 10 /* d11 measurement multicast diagnostics */
+#define DOT11_MEASURE_TYPE_CIVICLOC 11 /* d11 measurement location civic */
+#define DOT11_MEASURE_TYPE_LOC_ID 12 /* d11 measurement location identifier */
+#define DOT11_MEASURE_TYPE_DIRCHANQ 13 /* d11 measurement dir channel quality */
+#define DOT11_MEASURE_TYPE_DIRMEAS 14 /* d11 measurement directional */
+#define DOT11_MEASURE_TYPE_DIRSTATS 15 /* d11 measurement directional stats */
+#define DOT11_MEASURE_TYPE_FTMRANGE 16 /* d11 measurement Fine Timing */
+#define DOT11_MEASURE_TYPE_PAUSE 255 /* d11 measurement pause type */
+
+/* Measurement Request Modes */
+#define DOT11_MEASURE_MODE_PARALLEL (1<<0) /* d11 measurement parallel */
+#define DOT11_MEASURE_MODE_ENABLE (1<<1) /* d11 measurement enable */
+#define DOT11_MEASURE_MODE_REQUEST (1<<2) /* d11 measurement request */
+#define DOT11_MEASURE_MODE_REPORT (1<<3) /* d11 measurement report */
+#define DOT11_MEASURE_MODE_DUR (1<<4) /* d11 measurement dur mandatory */
+/* Measurement Report Modes */
+#define DOT11_MEASURE_MODE_LATE (1<<0) /* d11 measurement late */
+#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) /* d11 measurement incapable */
+#define DOT11_MEASURE_MODE_REFUSED (1<<2) /* d11 measurement refuse */
+/* Basic Measurement Map bits */
+#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) /* d11 measurement basic map BSS */
+#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) /* d11 measurement map OFDM */
+#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) /* d11 measurement map unknown */
+#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) /* d11 measurement map radar */
+#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) /* d11 measurement map unmeasuremnt */
+
+BWL_PRE_PACKED_STRUCT struct dot11_meas_req {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 channel;
+ uint8 start_time[8];
+ uint16 duration;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_meas_req dot11_meas_req_t;
+#define DOT11_MNG_IE_MREQ_LEN 14 /* d11 measurement request IE length */
+/* length of Measure Request IE data not including variable len */
+#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 /* d11 measurement request IE fixed length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_meas_req_loc {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ BWL_PRE_PACKED_STRUCT union
+ {
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 subject;
+ uint8 data[1];
+ } BWL_POST_PACKED_STRUCT lci;
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 subject;
+ uint8 type; /* type of civic location */
+ uint8 siu; /* service interval units */
+ uint16 si; /* service interval */
+ uint8 data[1];
+ } BWL_POST_PACKED_STRUCT civic;
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 subject;
+ uint8 siu; /* service interval units */
+ uint16 si; /* service interval */
+ uint8 data[1];
+ } BWL_POST_PACKED_STRUCT locid;
+ BWL_PRE_PACKED_STRUCT struct {
+ uint16 max_init_delay; /* maximum random initial delay */
+ uint8 min_ap_count;
+ uint8 data[1];
+ } BWL_POST_PACKED_STRUCT ftm_range;
+ } BWL_POST_PACKED_STRUCT req;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_meas_req_loc dot11_meas_req_loc_t;
+#define DOT11_MNG_IE_MREQ_MIN_LEN 4 /* d11 measurement report IE length */
+#define DOT11_MNG_IE_MREQ_LCI_FIXED_LEN 4 /* d11 measurement report IE length */
+#define DOT11_MNG_IE_MREQ_CIVIC_FIXED_LEN 8 /* d11 measurement report IE length */
+#define DOT11_MNG_IE_MREQ_FRNG_FIXED_LEN 6 /* d11 measurement report IE length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_lci_subelement {
+ uint8 subelement;
+ uint8 length;
+ uint8 lci_data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_lci_subelement dot11_lci_subelement_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_civic_subelement {
+ uint8 type; /* type of civic location */
+ uint8 subelement;
+ uint8 length;
+ uint8 civic_data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_civic_subelement dot11_civic_subelement_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_meas_rep {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ BWL_PRE_PACKED_STRUCT union
+ {
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 channel;
+ uint8 start_time[8];
+ uint16 duration;
+ uint8 map;
+ } BWL_POST_PACKED_STRUCT basic;
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 subelement;
+ uint8 length;
+ uint8 data[1];
+ } BWL_POST_PACKED_STRUCT lci;
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 type; /* type of civic location */
+ uint8 subelement;
+ uint8 length;
+ uint8 data[1];
+ } BWL_POST_PACKED_STRUCT civic;
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 exp_tsf[8];
+ uint8 subelement;
+ uint8 length;
+ uint8 data[1];
+ } BWL_POST_PACKED_STRUCT locid;
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 entry_count;
+ uint8 data[1];
+ } BWL_POST_PACKED_STRUCT ftm_range;
+ uint8 data[1];
+ } BWL_POST_PACKED_STRUCT rep;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_meas_rep dot11_meas_rep_t;
+#define DOT11_MNG_IE_MREP_MIN_LEN 5 /* d11 measurement report IE length */
+#define DOT11_MNG_IE_MREP_LCI_FIXED_LEN 5 /* d11 measurement report IE length */
+#define DOT11_MNG_IE_MREP_CIVIC_FIXED_LEN 6 /* d11 measurement report IE length */
+#define DOT11_MNG_IE_MREP_LOCID_FIXED_LEN 13 /* d11 measurement report IE length */
+#define DOT11_MNG_IE_MREP_BASIC_FIXED_LEN 15 /* d11 measurement report IE length */
+#define DOT11_MNG_IE_MREP_FRNG_FIXED_LEN 4
+
+/* length of Measure Report IE data not including variable len */
+#define DOT11_MNG_IE_MREP_FIXED_LEN 3 /* d11 measurement response IE fixed length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic {
+ uint8 channel;
+ uint8 start_time[8];
+ uint16 duration;
+ uint8 map;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t;
+#define DOT11_MEASURE_BASIC_REP_LEN 12 /* d11 measurement basic report length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_quiet {
+ uint8 id;
+ uint8 len;
+ uint8 count; /* TBTTs until beacon interval in quiet starts */
+ uint8 period; /* Beacon intervals between periodic quiet periods ? */
+ uint16 duration; /* Length of quiet period, in TU's */
+ uint16 offset; /* TU's offset from TBTT in Count field */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_quiet dot11_quiet_t;
+
+BWL_PRE_PACKED_STRUCT struct chan_map_tuple {
+ uint8 channel;
+ uint8 map;
+} BWL_POST_PACKED_STRUCT;
+typedef struct chan_map_tuple chan_map_tuple_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs {
+ uint8 id;
+ uint8 len;
+ uint8 eaddr[ETHER_ADDR_LEN];
+ uint8 interval;
+ chan_map_tuple_t map[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ibss_dfs dot11_ibss_dfs_t;
+
+/* WME Elements */
+#define WME_OUI "\x00\x50\xf2" /* WME OUI */
+#define WME_OUI_LEN 3
+#define WME_OUI_TYPE 2 /* WME type */
+#define WME_TYPE 2 /* WME type, deprecated */
+#define WME_SUBTYPE_IE 0 /* Information Element */
+#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */
+#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */
+#define WME_VER 1 /* WME version */
+
+/* WME Access Category Indices (ACIs) */
+#define AC_BE 0 /* Best Effort */
+#define AC_BK 1 /* Background */
+#define AC_VI 2 /* Video */
+#define AC_VO 3 /* Voice */
+#define AC_COUNT 4 /* number of ACs */
+
+typedef uint8 ac_bitmap_t; /* AC bitmap of (1 << AC_xx) */
+
+#define AC_BITMAP_NONE 0x0 /* No ACs */
+#define AC_BITMAP_ALL 0xf /* All ACs */
+#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0)
+#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac))))
+#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac))))
+
+/* Management PKT Lifetime indices */
+/* Removing flag checks 'BCMINTERNAL || WLTEST'
+ * while merging MERGE BIS120RC4 to DINGO2
+ */
+#define MGMT_ALL 0xffff
+#define MGMT_AUTH_LT FC_SUBTYPE_AUTH
+#define MGMT_ASSOC_LT FC_SUBTYPE_ASSOC_REQ
+
+/** WME Information Element (IE) */
+BWL_PRE_PACKED_STRUCT struct wme_ie {
+ uint8 oui[3];
+ uint8 type;
+ uint8 subtype;
+ uint8 version;
+ uint8 qosinfo;
+} BWL_POST_PACKED_STRUCT;
+typedef struct wme_ie wme_ie_t;
+#define WME_IE_LEN 7 /* WME IE length */
+
+BWL_PRE_PACKED_STRUCT struct edcf_acparam {
+ uint8 ACI;
+ uint8 ECW;
+ uint16 TXOP; /* stored in network order (ls octet first) */
+} BWL_POST_PACKED_STRUCT;
+typedef struct edcf_acparam edcf_acparam_t;
+
+/** WME Parameter Element (PE) */
+BWL_PRE_PACKED_STRUCT struct wme_param_ie {
+ uint8 oui[3];
+ uint8 type;
+ uint8 subtype;
+ uint8 version;
+ uint8 qosinfo;
+ uint8 rsvd;
+ edcf_acparam_t acparam[AC_COUNT];
+} BWL_POST_PACKED_STRUCT;
+typedef struct wme_param_ie wme_param_ie_t;
+#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */
+
+/* QoS Info field for IE as sent from AP */
+#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */
+#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */
+#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */
+#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */
+
+/* QoS Info field for IE as sent from STA */
+#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */
+#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */
+#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */
+#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */
+#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */
+#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */
+#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */
+#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */
+#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */
+#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */
+#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */
+#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */
+
+/* ACI */
+#define EDCF_AIFSN_MIN 1 /* AIFSN minimum value */
+#define EDCF_AIFSN_MAX 15 /* AIFSN maximum value */
+#define EDCF_AIFSN_MASK 0x0f /* AIFSN mask */
+#define EDCF_ACM_MASK 0x10 /* ACM mask */
+#define EDCF_ACI_MASK 0x60 /* ACI mask */
+#define EDCF_ACI_SHIFT 5 /* ACI shift */
+#define EDCF_AIFSN_SHIFT 12 /* 4 MSB(0xFFF) in ifs_ctl for AC idx */
+
+/* ECW */
+#define EDCF_ECW_MIN 0 /* cwmin/cwmax exponent minimum value */
+#define EDCF_ECW_MAX 15 /* cwmin/cwmax exponent maximum value */
+#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1)
+#define EDCF_ECWMIN_MASK 0x0f /* cwmin exponent form mask */
+#define EDCF_ECWMAX_MASK 0xf0 /* cwmax exponent form mask */
+#define EDCF_ECWMAX_SHIFT 4 /* cwmax exponent form shift */
+
+/* TXOP */
+#define EDCF_TXOP_MIN 0 /* TXOP minimum value */
+#define EDCF_TXOP_MAX 65535 /* TXOP maximum value */
+#define EDCF_TXOP2USEC(txop) ((txop) << 5)
+
+/* Default BE ACI value for non-WME connection STA */
+#define NON_EDCF_AC_BE_ACI_STA 0x02
+
+/* Default EDCF parameters that AP advertises for STA to use; WMM draft Table 12 */
+#define EDCF_AC_BE_ACI_STA 0x03 /* STA ACI value for best effort AC */
+#define EDCF_AC_BE_ECW_STA 0xA4 /* STA ECW value for best effort AC */
+#define EDCF_AC_BE_TXOP_STA 0x0000 /* STA TXOP value for best effort AC */
+#define EDCF_AC_BK_ACI_STA 0x27 /* STA ACI value for background AC */
+#define EDCF_AC_BK_ECW_STA 0xA4 /* STA ECW value for background AC */
+#define EDCF_AC_BK_TXOP_STA 0x0000 /* STA TXOP value for background AC */
+#define EDCF_AC_VI_ACI_STA 0x42 /* STA ACI value for video AC */
+#define EDCF_AC_VI_ECW_STA 0x43 /* STA ECW value for video AC */
+#define EDCF_AC_VI_TXOP_STA 0x005e /* STA TXOP value for video AC */
+#define EDCF_AC_VO_ACI_STA 0x62 /* STA ACI value for audio AC */
+#define EDCF_AC_VO_ECW_STA 0x32 /* STA ECW value for audio AC */
+#define EDCF_AC_VO_TXOP_STA 0x002f /* STA TXOP value for audio AC */
+
+/* Default EDCF parameters that AP uses; WMM draft Table 14 */
+#define EDCF_AC_BE_ACI_AP 0x03 /* AP ACI value for best effort AC */
+#define EDCF_AC_BE_ECW_AP 0x64 /* AP ECW value for best effort AC */
+#define EDCF_AC_BE_TXOP_AP 0x0000 /* AP TXOP value for best effort AC */
+#define EDCF_AC_BK_ACI_AP 0x27 /* AP ACI value for background AC */
+#define EDCF_AC_BK_ECW_AP 0xA4 /* AP ECW value for background AC */
+#define EDCF_AC_BK_TXOP_AP 0x0000 /* AP TXOP value for background AC */
+#define EDCF_AC_VI_ACI_AP 0x41 /* AP ACI value for video AC */
+#define EDCF_AC_VI_ECW_AP 0x43 /* AP ECW value for video AC */
+#define EDCF_AC_VI_TXOP_AP 0x005e /* AP TXOP value for video AC */
+#define EDCF_AC_VO_ACI_AP 0x61 /* AP ACI value for audio AC */
+#define EDCF_AC_VO_ECW_AP 0x32 /* AP ECW value for audio AC */
+#define EDCF_AC_VO_TXOP_AP 0x002f /* AP TXOP value for audio AC */
+
+/** EDCA Parameter IE */
+BWL_PRE_PACKED_STRUCT struct edca_param_ie {
+ uint8 qosinfo;
+ uint8 rsvd;
+ edcf_acparam_t acparam[AC_COUNT];
+} BWL_POST_PACKED_STRUCT;
+typedef struct edca_param_ie edca_param_ie_t;
+#define EDCA_PARAM_IE_LEN 18 /* EDCA Parameter IE length */
+
+/** QoS Capability IE */
+BWL_PRE_PACKED_STRUCT struct qos_cap_ie {
+ uint8 qosinfo;
+} BWL_POST_PACKED_STRUCT;
+typedef struct qos_cap_ie qos_cap_ie_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie {
+ uint8 id; /* 11, DOT11_MNG_QBSS_LOAD_ID */
+ uint8 length;
+ uint16 station_count; /* total number of STAs associated */
+ uint8 channel_utilization; /* % of time, normalized to 255, QAP sensed medium busy */
+ uint16 aac; /* available admission capacity */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t;
+#define BSS_LOAD_IE_SIZE 7 /* BSS load IE size */
+
+#define WLC_QBSS_LOAD_CHAN_FREE_MAX 0xff /* max for channel free score */
+
+/* nom_msdu_size */
+#define FIXED_MSDU_SIZE 0x8000 /* MSDU size is fixed */
+#define MSDU_SIZE_MASK 0x7fff /* (Nominal or fixed) MSDU size */
+
+/* surplus_bandwidth */
+/* Represented as 3 bits of integer, binary point, 13 bits fraction */
+#define INTEGER_SHIFT 13 /* integer shift */
+#define FRACTION_MASK 0x1FFF /* fraction mask */
+
+/** Management Notification Frame */
+BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
+ uint8 category; /* DOT11_ACTION_NOTIFICATION */
+ uint8 action;
+ uint8 token;
+ uint8 status;
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+#define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */
+
+/** Timeout Interval IE */
+BWL_PRE_PACKED_STRUCT struct ti_ie {
+ uint8 ti_type;
+ uint32 ti_val;
+} BWL_POST_PACKED_STRUCT;
+typedef struct ti_ie ti_ie_t;
+#define TI_TYPE_REASSOC_DEADLINE 1
+#define TI_TYPE_KEY_LIFETIME 2
+
+/* WME Action Codes */
+#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */
+#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */
+#define WME_DELTS_REQUEST 2 /* WME DELTS request */
+
+/* WME Setup Response Status Codes */
+#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */
+#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */
+#define WME_ADMISSION_REFUSED 3 /* WME admission refused */
+
+/* Macro to take a pointer to a beacon or probe response
+ * body and return the char* pointer to the SSID info element
+ */
+#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN)
+
+/* Authentication frame payload constants */
+#define DOT11_OPEN_SYSTEM 0 /* d11 open authentication */
+#define DOT11_SHARED_KEY 1 /* d11 shared authentication */
+#define DOT11_FAST_BSS 2 /* d11 fast bss authentication */
+#define DOT11_CHALLENGE_LEN 128 /* d11 challenge text length */
+
+/* Frame control macros */
+#define FC_PVER_MASK 0x3 /* PVER mask */
+#define FC_PVER_SHIFT 0 /* PVER shift */
+#define FC_TYPE_MASK 0xC /* type mask */
+#define FC_TYPE_SHIFT 2 /* type shift */
+#define FC_SUBTYPE_MASK 0xF0 /* subtype mask */
+#define FC_SUBTYPE_SHIFT 4 /* subtype shift */
+#define FC_TODS 0x100 /* to DS */
+#define FC_TODS_SHIFT 8 /* to DS shift */
+#define FC_FROMDS 0x200 /* from DS */
+#define FC_FROMDS_SHIFT 9 /* from DS shift */
+#define FC_MOREFRAG 0x400 /* more frag. */
+#define FC_MOREFRAG_SHIFT 10 /* more frag. shift */
+#define FC_RETRY 0x800 /* retry */
+#define FC_RETRY_SHIFT 11 /* retry shift */
+#define FC_PM 0x1000 /* PM */
+#define FC_PM_SHIFT 12 /* PM shift */
+#define FC_MOREDATA 0x2000 /* more data */
+#define FC_MOREDATA_SHIFT 13 /* more data shift */
+#define FC_WEP 0x4000 /* WEP */
+#define FC_WEP_SHIFT 14 /* WEP shift */
+#define FC_ORDER 0x8000 /* order */
+#define FC_ORDER_SHIFT 15 /* order shift */
+
+/* sequence control macros */
+#define SEQNUM_SHIFT 4 /* seq. number shift */
+#define SEQNUM_MAX 0x1000 /* max seqnum + 1 */
+#define FRAGNUM_MASK 0xF /* frag. number mask */
+
+/* Frame Control type/subtype defs */
+
+/* FC Types */
+#define FC_TYPE_MNG 0 /* management type */
+#define FC_TYPE_CTL 1 /* control type */
+#define FC_TYPE_DATA 2 /* data type */
+
+/* Management Subtypes */
+#define FC_SUBTYPE_ASSOC_REQ 0 /* assoc. request */
+#define FC_SUBTYPE_ASSOC_RESP 1 /* assoc. response */
+#define FC_SUBTYPE_REASSOC_REQ 2 /* reassoc. request */
+#define FC_SUBTYPE_REASSOC_RESP 3 /* reassoc. response */
+#define FC_SUBTYPE_PROBE_REQ 4 /* probe request */
+#define FC_SUBTYPE_PROBE_RESP 5 /* probe response */
+#define FC_SUBTYPE_BEACON 8 /* beacon */
+#define FC_SUBTYPE_ATIM 9 /* ATIM */
+#define FC_SUBTYPE_DISASSOC 10 /* disassoc. */
+#define FC_SUBTYPE_AUTH 11 /* authentication */
+#define FC_SUBTYPE_DEAUTH 12 /* de-authentication */
+#define FC_SUBTYPE_ACTION 13 /* action */
+#define FC_SUBTYPE_ACTION_NOACK 14 /* action no-ack */
+
+/* Control Subtypes */
+#define FC_SUBTYPE_CTL_WRAPPER 7 /* Control Wrapper */
+#define FC_SUBTYPE_BLOCKACK_REQ 8 /* Block Ack Req */
+#define FC_SUBTYPE_BLOCKACK 9 /* Block Ack */
+#define FC_SUBTYPE_PS_POLL 10 /* PS poll */
+#define FC_SUBTYPE_RTS 11 /* RTS */
+#define FC_SUBTYPE_CTS 12 /* CTS */
+#define FC_SUBTYPE_ACK 13 /* ACK */
+#define FC_SUBTYPE_CF_END 14 /* CF-END */
+#define FC_SUBTYPE_CF_END_ACK 15 /* CF-END ACK */
+
+/* Data Subtypes */
+#define FC_SUBTYPE_DATA 0 /* Data */
+#define FC_SUBTYPE_DATA_CF_ACK 1 /* Data + CF-ACK */
+#define FC_SUBTYPE_DATA_CF_POLL 2 /* Data + CF-Poll */
+#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 /* Data + CF-Ack + CF-Poll */
+#define FC_SUBTYPE_NULL 4 /* Null */
+#define FC_SUBTYPE_CF_ACK 5 /* CF-Ack */
+#define FC_SUBTYPE_CF_POLL 6 /* CF-Poll */
+#define FC_SUBTYPE_CF_ACK_POLL 7 /* CF-Ack + CF-Poll */
+#define FC_SUBTYPE_QOS_DATA 8 /* QoS Data */
+#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 /* QoS Data + CF-Ack */
+#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 /* QoS Data + CF-Poll */
+#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 /* QoS Data + CF-Ack + CF-Poll */
+#define FC_SUBTYPE_QOS_NULL 12 /* QoS Null */
+#define FC_SUBTYPE_QOS_CF_POLL 14 /* QoS CF-Poll */
+#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 /* QoS CF-Ack + CF-Poll */
+
+/* Data Subtype Groups */
+#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0)
+#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0)
+#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0)
+#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0)
+#define FC_SUBTYPE_ANY_PSPOLL(s) (((s) & 10) != 0)
+
+/* Type/Subtype Combos */
+#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) /* FC kind mask */
+
+#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) /* FC kind */
+
+#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) /* Subtype from FC */
+#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) /* Type from FC */
+
+#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) /* assoc. request */
+#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) /* assoc. response */
+#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) /* reassoc. request */
+#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) /* reassoc. response */
+#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) /* probe request */
+#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) /* probe response */
+#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) /* beacon */
+#define FC_ATIM FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ATIM) /* ATIM */
+#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) /* disassoc */
+#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) /* authentication */
+#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) /* deauthentication */
+#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) /* action */
+#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) /* action no-ack */
+
+#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) /* Control Wrapper */
+#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) /* Block Ack Req */
+#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) /* Block Ack */
+#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) /* PS poll */
+#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) /* RTS */
+#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) /* CTS */
+#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) /* ACK */
+#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) /* CF-END */
+#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) /* CF-END ACK */
+
+#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) /* data */
+#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) /* null data */
+#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) /* data CF ACK */
+#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) /* QoS data */
+#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) /* QoS null */
+
+/* QoS Control Field */
+
+/* 802.1D Priority */
+#define QOS_PRIO_SHIFT 0 /* QoS priority shift */
+#define QOS_PRIO_MASK 0x0007 /* QoS priority mask */
+#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) /* QoS priority */
+
+/* Traffic Identifier */
+#define QOS_TID_SHIFT 0 /* QoS TID shift */
+#define QOS_TID_MASK 0x000f /* QoS TID mask */
+#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) /* QoS TID */
+
+/* End of Service Period (U-APSD) */
+#define QOS_EOSP_SHIFT 4 /* QoS End of Service Period shift */
+#define QOS_EOSP_MASK 0x0010 /* QoS End of Service Period mask */
+#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) /* Qos EOSP */
+
+/* Ack Policy */
+#define QOS_ACK_NORMAL_ACK 0 /* Normal Ack */
+#define QOS_ACK_NO_ACK 1 /* No Ack (eg mcast) */
+#define QOS_ACK_NO_EXP_ACK 2 /* No Explicit Ack */
+#define QOS_ACK_BLOCK_ACK 3 /* Block Ack */
+#define QOS_ACK_SHIFT 5 /* QoS ACK shift */
+#define QOS_ACK_MASK 0x0060 /* QoS ACK mask */
+#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) /* QoS ACK */
+
+/* A-MSDU flag */
+#define QOS_AMSDU_SHIFT 7 /* AMSDU shift */
+#define QOS_AMSDU_MASK 0x0080 /* AMSDU mask */
+
+/* Management Frames */
+
+/* Management Frame Constants */
+
+/* Fixed fields */
+#define DOT11_MNG_AUTH_ALGO_LEN 2 /* d11 management auth. algo. length */
+#define DOT11_MNG_AUTH_SEQ_LEN 2 /* d11 management auth. seq. length */
+#define DOT11_MNG_BEACON_INT_LEN 2 /* d11 management beacon interval length */
+#define DOT11_MNG_CAP_LEN 2 /* d11 management cap. length */
+#define DOT11_MNG_AP_ADDR_LEN 6 /* d11 management AP address length */
+#define DOT11_MNG_LISTEN_INT_LEN 2 /* d11 management listen interval length */
+#define DOT11_MNG_REASON_LEN 2 /* d11 management reason length */
+#define DOT11_MNG_AID_LEN 2 /* d11 management AID length */
+#define DOT11_MNG_STATUS_LEN 2 /* d11 management status length */
+#define DOT11_MNG_TIMESTAMP_LEN 8 /* d11 management timestamp length */
+
+/* DUR/ID field in assoc resp is 0xc000 | AID */
+#define DOT11_AID_MASK 0x3fff /* d11 AID mask */
+
+/* Reason Codes */
+#define DOT11_RC_RESERVED 0 /* d11 RC reserved */
+#define DOT11_RC_UNSPECIFIED 1 /* Unspecified reason */
+#define DOT11_RC_AUTH_INVAL 2 /* Previous authentication no longer valid */
+#define DOT11_RC_DEAUTH_LEAVING 3 /* Deauthenticated because sending station
+ * is leaving (or has left) IBSS or ESS
+ */
+#define DOT11_RC_INACTIVITY 4 /* Disassociated due to inactivity */
+#define DOT11_RC_BUSY 5 /* Disassociated because AP is unable to handle
+ * all currently associated stations
+ */
+#define DOT11_RC_INVAL_CLASS_2 6 /* Class 2 frame received from
+ * nonauthenticated station
+ */
+#define DOT11_RC_INVAL_CLASS_3 7 /* Class 3 frame received from
+ * nonassociated station
+ */
+#define DOT11_RC_DISASSOC_LEAVING 8 /* Disassociated because sending station is
+ * leaving (or has left) BSS
+ */
+#define DOT11_RC_NOT_AUTH 9 /* Station requesting (re)association is not
+ * authenticated with responding station
+ */
+#define DOT11_RC_BAD_PC 10 /* Unacceptable power capability element */
+#define DOT11_RC_BAD_CHANNELS 11 /* Unacceptable supported channels element */
+
+/* 12 is unused by STA but could be used by AP/GO */
+#define DOT11_RC_DISASSOC_BTM 12 /* Disassociated due to BSS Transition Magmt */
+
+
+/* 32-39 are QSTA specific reasons added in 11e */
+#define DOT11_RC_UNSPECIFIED_QOS 32 /* unspecified QoS-related reason */
+#define DOT11_RC_INSUFFCIENT_BW 33 /* QAP lacks sufficient bandwidth */
+#define DOT11_RC_EXCESSIVE_FRAMES 34 /* excessive number of frames need ack */
+#define DOT11_RC_TX_OUTSIDE_TXOP 35 /* transmitting outside the limits of txop */
+#define DOT11_RC_LEAVING_QBSS 36 /* QSTA is leaving the QBSS (or restting) */
+#define DOT11_RC_BAD_MECHANISM 37 /* does not want to use the mechanism */
+#define DOT11_RC_SETUP_NEEDED 38 /* mechanism needs a setup */
+#define DOT11_RC_TIMEOUT 39 /* timeout */
+
+#define DOT11_RC_MESH_PEERING_CANCELLED 52
+#define DOT11_RC_MESH_MAX_PEERS 53
+#define DOT11_RC_MESH_CONFIG_POLICY_VIOLN 54
+#define DOT11_RC_MESH_CLOSE_RECVD 55
+#define DOT11_RC_MESH_MAX_RETRIES 56
+#define DOT11_RC_MESH_CONFIRM_TIMEOUT 57
+#define DOT11_RC_MESH_INVALID_GTK 58
+#define DOT11_RC_MESH_INCONSISTENT_PARAMS 59
+
+#define DOT11_RC_MESH_INVALID_SEC_CAP 60
+#define DOT11_RC_MESH_PATHERR_NOPROXYINFO 61
+#define DOT11_RC_MESH_PATHERR_NOFWINFO 62
+#define DOT11_RC_MESH_PATHERR_DSTUNREACH 63
+#define DOT11_RC_MESH_MBSSMAC_EXISTS 64
+#define DOT11_RC_MESH_CHANSWITCH_REGREQ 65
+#define DOT11_RC_MESH_CHANSWITCH_UNSPEC 66
+
+#define DOT11_RC_MAX 66 /* Reason codes > 66 are reserved */
+
+#define DOT11_RC_TDLS_PEER_UNREACH 25
+#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26
+
+/* Status Codes */
+#define DOT11_SC_SUCCESS 0 /* Successful */
+#define DOT11_SC_FAILURE 1 /* Unspecified failure */
+#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 /* TDLS wakeup schedule rejected but alternative */
+ /* schedule provided */
+#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 /* TDLS wakeup schedule rejected */
+#define DOT11_SC_TDLS_SEC_DISABLED 5 /* TDLS Security disabled */
+#define DOT11_SC_LIFETIME_REJ 6 /* Unacceptable lifetime */
+#define DOT11_SC_NOT_SAME_BSS 7 /* Not in same BSS */
+#define DOT11_SC_CAP_MISMATCH 10 /* Cannot support all requested
+ * capabilities in the Capability
+ * Information field
+ */
+#define DOT11_SC_REASSOC_FAIL 11 /* Reassociation denied due to inability
+ * to confirm that association exists
+ */
+#define DOT11_SC_ASSOC_FAIL 12 /* Association denied due to reason
+ * outside the scope of this standard
+ */
+#define DOT11_SC_AUTH_MISMATCH 13 /* Responding station does not support
+ * the specified authentication
+ * algorithm
+ */
+#define DOT11_SC_AUTH_SEQ 14 /* Received an Authentication frame
+ * with authentication transaction
+ * sequence number out of expected
+ * sequence
+ */
+#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 /* Authentication rejected because of
+ * challenge failure
+ */
+#define DOT11_SC_AUTH_TIMEOUT 16 /* Authentication rejected due to timeout
+ * waiting for next frame in sequence
+ */
+#define DOT11_SC_ASSOC_BUSY_FAIL 17 /* Association denied because AP is
+ * unable to handle additional
+ * associated stations
+ */
+#define DOT11_SC_ASSOC_RATE_MISMATCH 18 /* Association denied due to requesting
+ * station not supporting all of the
+ * data rates in the BSSBasicRateSet
+ * parameter
+ */
+#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 /* Association denied due to requesting
+ * station not supporting the Short
+ * Preamble option
+ */
+#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 /* Association denied due to requesting
+ * station not supporting the PBCC
+ * Modulation option
+ */
+#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 /* Association denied due to requesting
+ * station not supporting the Channel
+ * Agility option
+ */
+#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum
+ * Management capability is required.
+ */
+#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info
+ * in the Power Cap element is
+ * unacceptable.
+ */
+#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 /* Association denied because the info
+ * in the Supported Channel element is
+ * unacceptable
+ */
+#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting
+ * station not supporting the Short Slot
+ * Time option
+ */
+#define DOT11_SC_ASSOC_DSSSOFDM_REQUIRED 26 /* Association denied because requesting station
+ * does not support the DSSS-OFDM option
+ */
+#define DOT11_SC_ASSOC_HT_REQUIRED 27 /* Association denied because the requesting
+ * station does not support HT features
+ */
+#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 /* Association denied due to AP
+ * being unable to reach the R0 Key Holder
+ */
+#define DOT11_SC_ASSOC_TRY_LATER 30 /* Association denied temporarily, try again later
+ */
+#define DOT11_SC_ASSOC_MFP_VIOLATION 31 /* Association denied due to Robust Management
+ * frame policy violation
+ */
+
+#define DOT11_SC_DECLINED 37 /* request declined */
+#define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */
+#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 /* invalid pairwise cipher */
+#define DOT11_SC_INVALID_AKMP 43 /* Association denied due to invalid AKMP */
+#define DOT11_SC_UNSUP_RSNIE_VER 44 /* Unsupported RSN IE version */
+#define DOT11_SC_INVALID_RSNIE_CAP 45 /* invalid RSN IE capabilities */
+#define DOT11_SC_DLS_NOT_ALLOWED 48 /* DLS is not allowed in the BSS by policy */
+#define DOT11_SC_INVALID_PMKID 53 /* Association denied due to invalid PMKID */
+#define DOT11_SC_INVALID_MDID 54 /* Association denied due to invalid MDID */
+#define DOT11_SC_INVALID_FTIE 55 /* Association denied due to invalid FTIE */
+
+#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 /* ad proto not supported */
+#define DOT11_SC_NO_OUTSTAND_REQ 60 /* no outstanding req */
+#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 /* no response from server */
+#define DOT11_SC_TIMEOUT 62 /* timeout */
+#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 /* query rsp too large */
+#define DOT11_SC_SERVER_UNREACHABLE 65 /* server unreachable */
+
+#define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */
+#define DOT11_SC_INVALID_SNONCE 71 /* Invalid SNonce */
+#define DOT11_SC_INVALID_RSNIE 72 /* Invalid contents of RSNIE */
+
+#define DOT11_SC_ANTICLOG_TOCKEN_REQUIRED 76 /* Anti-clogging tocken required */
+#define DOT11_SC_INVALID_FINITE_CYCLIC_GRP 77 /* Invalid contents of RSNIE */
+
+#define DOT11_SC_ASSOC_VHT_REQUIRED 104 /* Association denied because the requesting
+ * station does not support VHT features.
+ */
+
+#define DOT11_SC_TRANSMIT_FAILURE 79 /* transmission failure */
+
+/* Info Elts, length of INFORMATION portion of Info Elts */
+#define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */
+#define DOT11_MNG_IBSS_PARAM_LEN 2 /* d11 management IBSS parameter length */
+
+/* TIM Info element has 3 bytes fixed info in INFORMATION field,
+ * followed by 1 to 251 bytes of Partial Virtual Bitmap
+ */
+#define DOT11_MNG_TIM_FIXED_LEN 3 /* d11 management TIM fixed length */
+#define DOT11_MNG_TIM_DTIM_COUNT 0 /* d11 management DTIM count */
+#define DOT11_MNG_TIM_DTIM_PERIOD 1 /* d11 management DTIM period */
+#define DOT11_MNG_TIM_BITMAP_CTL 2 /* d11 management TIM BITMAP control */
+#define DOT11_MNG_TIM_PVB 3 /* d11 management TIM PVB */
+
+/* TLV defines */
+#define TLV_TAG_OFF 0 /* tag offset */
+#define TLV_LEN_OFF 1 /* length offset */
+#define TLV_HDR_LEN 2 /* header length */
+#define TLV_BODY_OFF 2 /* body offset */
+#define TLV_BODY_LEN_MAX 255 /* max body length */
+
+/* Management Frame Information Element IDs */
+#define DOT11_MNG_SSID_ID 0 /* d11 management SSID id */
+#define DOT11_MNG_RATES_ID 1 /* d11 management rates id */
+#define DOT11_MNG_FH_PARMS_ID 2 /* d11 management FH parameter id */
+#define DOT11_MNG_DS_PARMS_ID 3 /* d11 management DS parameter id */
+#define DOT11_MNG_CF_PARMS_ID 4 /* d11 management CF parameter id */
+#define DOT11_MNG_TIM_ID 5 /* d11 management TIM id */
+#define DOT11_MNG_IBSS_PARMS_ID 6 /* d11 management IBSS parameter id */
+#define DOT11_MNG_COUNTRY_ID 7 /* d11 management country id */
+#define DOT11_MNG_HOPPING_PARMS_ID 8 /* d11 management hopping parameter id */
+#define DOT11_MNG_HOPPING_TABLE_ID 9 /* d11 management hopping table id */
+#define DOT11_MNG_FTM_SYNC_INFO_ID 9 /* 11mc D4.3 */
+#define DOT11_MNG_REQUEST_ID 10 /* d11 management request id */
+#define DOT11_MNG_QBSS_LOAD_ID 11 /* d11 management QBSS Load id */
+#define DOT11_MNG_EDCA_PARAM_ID 12 /* 11E EDCA Parameter id */
+#define DOT11_MNG_TSPEC_ID 13 /* d11 management TSPEC id */
+#define DOT11_MNG_TCLAS_ID 14 /* d11 management TCLAS id */
+#define DOT11_MNG_CHALLENGE_ID 16 /* d11 management chanllenge id */
+#define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */
+#define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */
+#define DOT11_MNG_TPC_REQUEST_ID 34 /* 11H TPC Request */
+#define DOT11_MNG_TPC_REPORT_ID 35 /* 11H TPC Report */
+#define DOT11_MNG_SUPP_CHANNELS_ID 36 /* 11H Supported Channels */
+#define DOT11_MNG_CHANNEL_SWITCH_ID 37 /* 11H ChannelSwitch Announcement */
+#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */
+#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementReport */
+#define DOT11_MNG_QUIET_ID 40 /* 11H Quiet */
+#define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */
+#define DOT11_MNG_ERP_ID 42 /* d11 management ERP id */
+#define DOT11_MNG_TS_DELAY_ID 43 /* d11 management TS Delay id */
+#define DOT11_MNG_TCLAS_PROC_ID 44 /* d11 management TCLAS processing id */
+#define DOT11_MNG_HT_CAP 45 /* d11 mgmt HT cap id */
+#define DOT11_MNG_QOS_CAP_ID 46 /* 11E QoS Capability id */
+#define DOT11_MNG_NONERP_ID 47 /* d11 management NON-ERP id */
+#define DOT11_MNG_RSN_ID 48 /* d11 management RSN id */
+#define DOT11_MNG_EXT_RATES_ID 50 /* d11 management ext. rates id */
+#define DOT11_MNG_AP_CHREP_ID 51 /* 11k AP Channel report id */
+#define DOT11_MNG_NEIGHBOR_REP_ID 52 /* 11k & 11v Neighbor report id */
+#define DOT11_MNG_RCPI_ID 53 /* 11k RCPI */
+#define DOT11_MNG_MDIE_ID 54 /* 11r Mobility domain id */
+#define DOT11_MNG_FTIE_ID 55 /* 11r Fast Bss Transition id */
+#define DOT11_MNG_FT_TI_ID 56 /* 11r Timeout Interval id */
+#define DOT11_MNG_RDE_ID 57 /* 11r RIC Data Element id */
+#define DOT11_MNG_REGCLASS_ID 59 /* d11 management regulatory class id */
+#define DOT11_MNG_EXT_CSA_ID 60 /* d11 Extended CSA */
+#define DOT11_MNG_HT_ADD 61 /* d11 mgmt additional HT info */
+#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 /* d11 mgmt ext channel offset */
+#define DOT11_MNG_BSS_AVR_ACCESS_DELAY_ID 63 /* 11k bss average access delay */
+#define DOT11_MNG_ANTENNA_ID 64 /* 11k antenna id */
+#define DOT11_MNG_RSNI_ID 65 /* 11k RSNI id */
+#define DOT11_MNG_MEASUREMENT_PILOT_TX_ID 66 /* 11k measurement pilot tx info id */
+#define DOT11_MNG_BSS_AVAL_ADMISSION_CAP_ID 67 /* 11k bss aval admission cap id */
+#define DOT11_MNG_BSS_AC_ACCESS_DELAY_ID 68 /* 11k bss AC access delay id */
+#define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */
+#define DOT11_MNG_TIME_ADVERTISE_ID 69 /* 11p time advertisement */
+#define DOT11_MNG_RRM_CAP_ID 70 /* 11k radio measurement capability */
+#define DOT11_MNG_MULTIPLE_BSSID_ID 71 /* 11k multiple BSSID id */
+#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 /* d11 mgmt OBSS Coexistence INFO */
+#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 /* d11 mgmt OBSS Intolerant Channel list */
+#define DOT11_MNG_HT_OBSS_ID 74 /* d11 mgmt OBSS HT info */
+#define DOT11_MNG_MMIE_ID 76 /* d11 mgmt MIC IE */
+#define DOT11_MNG_FMS_DESCR_ID 86 /* 11v FMS descriptor */
+#define DOT11_MNG_FMS_REQ_ID 87 /* 11v FMS request id */
+#define DOT11_MNG_FMS_RESP_ID 88 /* 11v FMS response id */
+#define DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID 90 /* 11v bss max idle id */
+#define DOT11_MNG_TFS_REQUEST_ID 91 /* 11v tfs request id */
+#define DOT11_MNG_TFS_RESPONSE_ID 92 /* 11v tfs response id */
+#define DOT11_MNG_WNM_SLEEP_MODE_ID 93 /* 11v wnm-sleep mode id */
+#define DOT11_MNG_TIMBC_REQ_ID 94 /* 11v TIM broadcast request id */
+#define DOT11_MNG_TIMBC_RESP_ID 95 /* 11v TIM broadcast response id */
+#define DOT11_MNG_CHANNEL_USAGE 97 /* 11v channel usage */
+#define DOT11_MNG_TIME_ZONE_ID 98 /* 11v time zone */
+#define DOT11_MNG_DMS_REQUEST_ID 99 /* 11v dms request id */
+#define DOT11_MNG_DMS_RESPONSE_ID 100 /* 11v dms response id */
+#define DOT11_MNG_LINK_IDENTIFIER_ID 101 /* 11z TDLS Link Identifier IE */
+#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 /* 11z TDLS Wakeup Schedule IE */
+#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 /* 11z TDLS Channel Switch Timing IE */
+#define DOT11_MNG_PTI_CONTROL_ID 105 /* 11z TDLS PTI Control IE */
+#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 /* 11z TDLS PU Buffer Status IE */
+#define DOT11_MNG_INTERWORKING_ID 107 /* 11u interworking */
+#define DOT11_MNG_ADVERTISEMENT_ID 108 /* 11u advertisement protocol */
+#define DOT11_MNG_EXP_BW_REQ_ID 109 /* 11u expedited bandwith request */
+#define DOT11_MNG_QOS_MAP_ID 110 /* 11u QoS map set */
+#define DOT11_MNG_ROAM_CONSORT_ID 111 /* 11u roaming consortium */
+#define DOT11_MNG_EMERGCY_ALERT_ID 112 /* 11u emergency alert identifier */
+#define DOT11_MNG_MESH_CONFIG 113 /* Mesh Configuration */
+#define DOT11_MNG_MESH_ID 114 /* Mesh ID */
+#define DOT11_MNG_MESH_PEER_MGMT_ID 117 /* Mesh PEER MGMT IE */
+#define DOT11_MNG_EXT_CAP_ID 127 /* d11 mgmt ext capability */
+#define DOT11_MNG_EXT_PREQ_ID 130 /* Mesh PREQ IE */
+#define DOT11_MNG_EXT_PREP_ID 131 /* Mesh PREP IE */
+#define DOT11_MNG_EXT_PERR_ID 132 /* Mesh PERR IE */
+#define DOT11_MNG_VHT_CAP_ID 191 /* d11 mgmt VHT cap id */
+#define DOT11_MNG_VHT_OPERATION_ID 192 /* d11 mgmt VHT op id */
+#define DOT11_MNG_EXT_BSSLOAD_ID 193 /* d11 mgmt VHT extended bss load id */
+#define DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID 194 /* Wide BW Channel Switch IE */
+#define DOT11_MNG_VHT_TRANSMIT_POWER_ENVELOPE_ID 195 /* VHT transmit Power Envelope IE */
+#define DOT11_MNG_CHANNEL_SWITCH_WRAPPER_ID 196 /* Channel Switch Wrapper IE */
+#define DOT11_MNG_AID_ID 197 /* Association ID IE */
+#define DOT11_MNG_OPER_MODE_NOTIF_ID 199 /* d11 mgmt VHT oper mode notif */
+#define DOT11_MNG_HE_CAP_ID 201
+#define DOT11_MNG_HE_OP_ID 202
+#define DOT11_MNG_FTM_PARAMS_ID 206
+#define DOT11_MNG_TWT_ID 216 /* 11ah D5.0 */
+#define DOT11_MNG_WPA_ID 221 /* d11 management WPA id */
+#define DOT11_MNG_PROPR_ID 221
+/* should start using this one instead of above two */
+#define DOT11_MNG_VS_ID 221 /* d11 management Vendor Specific IE */
+
+#define DOT11_MNG_ID_EXT_ID 255 /* Element ID Extension 11mc D4.3 */
+
+#define DOT11_MNG_IE_ID_EXT_MATCH(_ie, _id) (\
+ ((_ie)->id == DOT11_MNG_ID_EXT_ID) && \
+ ((_ie)->len > 0) && \
+ ((_id) == ((uint8 *)(_ie) + TLV_HDR_LEN)[0]))
+
+#define DOT11_MNG_IE_ID_EXT_INIT(_ie, _id, _len) do {\
+ (_ie)->id = DOT11_MNG_ID_EXT_ID; \
+ (_ie)->len = _len; \
+ (_ie)->id_ext = _id; \
+ } while (0)
+
+/* Rate Defines */
+
+/* Valid rates for the Supported Rates and Extended Supported Rates IEs.
+ * Encoding is the rate in 500kbps units, rouding up for fractional values.
+ * 802.11-2012, section 6.5.5.2, DATA_RATE parameter enumerates all the values.
+ * The rate values cover DSSS, HR/DSSS, ERP, and OFDM phy rates.
+ * The defines below do not cover the rates specific to 10MHz, {3, 4.5, 27},
+ * and 5MHz, {1.5, 2.25, 3, 4.5, 13.5}, which are not supported by Broadcom devices.
+ */
+
+#define DOT11_RATE_1M 2 /* 1 Mbps in 500kbps units */
+#define DOT11_RATE_2M 4 /* 2 Mbps in 500kbps units */
+#define DOT11_RATE_5M5 11 /* 5.5 Mbps in 500kbps units */
+#define DOT11_RATE_11M 22 /* 11 Mbps in 500kbps units */
+#define DOT11_RATE_6M 12 /* 6 Mbps in 500kbps units */
+#define DOT11_RATE_9M 18 /* 9 Mbps in 500kbps units */
+#define DOT11_RATE_12M 24 /* 12 Mbps in 500kbps units */
+#define DOT11_RATE_18M 36 /* 18 Mbps in 500kbps units */
+#define DOT11_RATE_24M 48 /* 24 Mbps in 500kbps units */
+#define DOT11_RATE_36M 72 /* 36 Mbps in 500kbps units */
+#define DOT11_RATE_48M 96 /* 48 Mbps in 500kbps units */
+#define DOT11_RATE_54M 108 /* 54 Mbps in 500kbps units */
+#define DOT11_RATE_MAX 108 /* highest rate (54 Mbps) in 500kbps units */
+
+/* Supported Rates and Extended Supported Rates IEs
+ * The supported rates octets are defined a the MSB indicatin a Basic Rate
+ * and bits 0-6 as the rate value
+ */
+#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */
+#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */
+
+/* BSS Membership Selector parameters
+ * 802.11-2012 and 802.11ac_D4.0 sec 8.4.2.3
+ * These selector values are advertised in Supported Rates and Extended Supported Rates IEs
+ * in the supported rates list with the Basic rate bit set.
+ * Constants below include the basic bit.
+ */
+#define DOT11_BSS_MEMBERSHIP_HT 0xFF /* Basic 0x80 + 127, HT Required to join */
+#define DOT11_BSS_MEMBERSHIP_VHT 0xFE /* Basic 0x80 + 126, VHT Required to join */
+
+/* ERP info element bit values */
+#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */
+#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present
+ *in the BSS
+ */
+#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for
+ *ERP-OFDM frames
+ */
+#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed,
+ * 1 == not allowed
+ */
+/* TS Delay element offset & size */
+#define DOT11_MGN_TS_DELAY_LEN 4 /* length of TS DELAY IE */
+#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */
+
+/* Capability Information Field */
+#define DOT11_CAP_ESS 0x0001 /* d11 cap. ESS */
+#define DOT11_CAP_IBSS 0x0002 /* d11 cap. IBSS */
+#define DOT11_CAP_POLLABLE 0x0004 /* d11 cap. pollable */
+#define DOT11_CAP_POLL_RQ 0x0008 /* d11 cap. poll request */
+#define DOT11_CAP_PRIVACY 0x0010 /* d11 cap. privacy */
+#define DOT11_CAP_SHORT 0x0020 /* d11 cap. short */
+#define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */
+#define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */
+#define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */
+#define DOT11_CAP_QOS 0x0200 /* d11 cap. qos */
+#define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */
+#define DOT11_CAP_APSD 0x0800 /* d11 cap. apsd */
+#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */
+#define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */
+#define DOT11_CAP_DELAY_BA 0x4000 /* d11 cap. delayed block ack */
+#define DOT11_CAP_IMMEDIATE_BA 0x8000 /* d11 cap. immediate block ack */
+
+/* Extended capabilities IE bitfields */
+/* 20/40 BSS Coexistence Management support bit position */
+#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0
+/* Extended Channel Switching support bit position */
+#define DOT11_EXT_CAP_EXT_CHAN_SWITCHING 2
+/* scheduled PSMP support bit position */
+#define DOT11_EXT_CAP_SPSMP 6
+/* Flexible Multicast Service */
+#define DOT11_EXT_CAP_FMS 11
+/* proxy ARP service support bit position */
+#define DOT11_EXT_CAP_PROXY_ARP 12
+/* Civic Location */
+#define DOT11_EXT_CAP_CIVIC_LOC 14
+/* Geospatial Location */
+#define DOT11_EXT_CAP_LCI 15
+/* Traffic Filter Service */
+#define DOT11_EXT_CAP_TFS 16
+/* WNM-Sleep Mode */
+#define DOT11_EXT_CAP_WNM_SLEEP 17
+/* TIM Broadcast service */
+#define DOT11_EXT_CAP_TIMBC 18
+/* BSS Transition Management support bit position */
+#define DOT11_EXT_CAP_BSSTRANS_MGMT 19
+/* Direct Multicast Service */
+#define DOT11_EXT_CAP_DMS 26
+/* Interworking support bit position */
+#define DOT11_EXT_CAP_IW 31
+/* QoS map support bit position */
+#define DOT11_EXT_CAP_QOS_MAP 32
+/* service Interval granularity bit position and mask */
+#define DOT11_EXT_CAP_SI 41
+#define DOT11_EXT_CAP_SI_MASK 0x0E
+/* Location Identifier service */
+#define DOT11_EXT_CAP_IDENT_LOC 44
+/* WNM notification */
+#define DOT11_EXT_CAP_WNM_NOTIF 46
+/* Operating mode notification - VHT (11ac D3.0 - 8.4.2.29) */
+#define DOT11_EXT_CAP_OPER_MODE_NOTIF 62
+/* Fine timing measurement - D3.0 */
+#define DOT11_EXT_CAP_FTM_RESPONDER 70
+#define DOT11_EXT_CAP_FTM_INITIATOR 71 /* tentative 11mcd3.0 */
+#ifdef WL_FTM
+#define DOT11_EXT_CAP_MAX_BIT_IDX 95 /* !!!update this please!!! */
+#else
+#define DOT11_EXT_CAP_MAX_BIT_IDX 62 /* !!!update this please!!! */
+#endif
+
+/* extended capability */
+#ifndef DOT11_EXTCAP_LEN_MAX
+#define DOT11_EXTCAP_LEN_MAX ((DOT11_EXT_CAP_MAX_BIT_IDX + 8) >> 3)
+#endif
+
+BWL_PRE_PACKED_STRUCT struct dot11_extcap {
+ uint8 extcap[DOT11_EXTCAP_LEN_MAX];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_extcap dot11_extcap_t;
+
+/* VHT Operating mode bit fields - (11ac D3.0 - 8.4.1.50) */
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3
+#define DOT11_OPER_MODE_RXNSS_SHIFT 4
+#define DOT11_OPER_MODE_RXNSS_MASK 0x70
+#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7
+#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80
+
+#define DOT11_OPER_MODE(type, nss, chanw) (\
+ ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\
+ DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\
+ (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\
+ ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\
+ DOT11_OPER_MODE_CHANNEL_WIDTH_MASK))
+
+#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \
+ (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\
+ >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT)
+#define DOT11_OPER_MODE_RXNSS(mode) \
+ ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \
+ >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1)
+#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \
+ (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\
+ >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT)
+
+#define DOT11_OPER_MODE_20MHZ 0
+#define DOT11_OPER_MODE_40MHZ 1
+#define DOT11_OPER_MODE_80MHZ 2
+#define DOT11_OPER_MODE_160MHZ 3
+#define DOT11_OPER_MODE_8080MHZ 3
+
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\
+ ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ)
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\
+ ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ)
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\
+ ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ)
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\
+ ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_160MHZ)
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\
+ ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_8080MHZ)
+
+/* Operating mode information element 802.11ac D3.0 - 8.4.2.168 */
+BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie {
+ uint8 mode;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t;
+
+#define DOT11_OPER_MODE_NOTIF_IE_LEN 1
+
+/* Extended Capability Information Field */
+#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 /* 20/40 BSS Coexistence Management support */
+
+/*
+ * Action Frame Constants
+ */
+#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action field */
+#define DOT11_ACTION_CAT_OFF 0 /* category offset */
+#define DOT11_ACTION_ACT_OFF 1 /* action offset */
+
+/* Action Category field (sec 8.4.1.11) */
+#define DOT11_ACTION_CAT_ERR_MASK 0x80 /* category error mask */
+#define DOT11_ACTION_CAT_MASK 0x7F /* category mask */
+#define DOT11_ACTION_CAT_SPECT_MNG 0 /* category spectrum management */
+#define DOT11_ACTION_CAT_QOS 1 /* category QoS */
+#define DOT11_ACTION_CAT_DLS 2 /* category DLS */
+#define DOT11_ACTION_CAT_BLOCKACK 3 /* category block ack */
+#define DOT11_ACTION_CAT_PUBLIC 4 /* category public */
+#define DOT11_ACTION_CAT_RRM 5 /* category radio measurements */
+#define DOT11_ACTION_CAT_FBT 6 /* category fast bss transition */
+#define DOT11_ACTION_CAT_HT 7 /* category for HT */
+#define DOT11_ACTION_CAT_SA_QUERY 8 /* security association query */
+#define DOT11_ACTION_CAT_PDPA 9 /* protected dual of public action */
+#define DOT11_ACTION_CAT_WNM 10 /* category for WNM */
+#define DOT11_ACTION_CAT_UWNM 11 /* category for Unprotected WNM */
+#define DOT11_ACTION_CAT_MESH 13 /* category for Mesh */
+#define DOT11_ACTION_CAT_SELFPROT 15 /* category for Mesh, self protected */
+#define DOT11_ACTION_NOTIFICATION 17
+#define DOT11_ACTION_CAT_VHT 21 /* VHT action */
+#define DOT11_ACTION_CAT_HE 26 /* HE action frame */
+#define DOT11_ACTION_CAT_VSP 126 /* protected vendor specific */
+#define DOT11_ACTION_CAT_VS 127 /* category Vendor Specific */
+
+/* Spectrum Management Action IDs (sec 7.4.1) */
+#define DOT11_SM_ACTION_M_REQ 0 /* d11 action measurement request */
+#define DOT11_SM_ACTION_M_REP 1 /* d11 action measurement response */
+#define DOT11_SM_ACTION_TPC_REQ 2 /* d11 action TPC request */
+#define DOT11_SM_ACTION_TPC_REP 3 /* d11 action TPC response */
+#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */
+#define DOT11_SM_ACTION_EXT_CSA 5 /* d11 extened CSA for 11n */
+
+/* QoS action ids */
+#define DOT11_QOS_ACTION_ADDTS_REQ 0 /* d11 action ADDTS request */
+#define DOT11_QOS_ACTION_ADDTS_RESP 1 /* d11 action ADDTS response */
+#define DOT11_QOS_ACTION_DELTS 2 /* d11 action DELTS */
+#define DOT11_QOS_ACTION_SCHEDULE 3 /* d11 action schedule */
+#define DOT11_QOS_ACTION_QOS_MAP 4 /* d11 action QOS map */
+
+/* HT action ids */
+#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */
+#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */
+
+/* Public action ids */
+#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 /* 20/40 Coexistence Management action id */
+#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */
+#define DOT11_PUB_ACTION_GAS_CB_REQ 12 /* GAS Comeback Request */
+#define DOT11_PUB_ACTION_FTM_REQ 32 /* FTM request */
+#define DOT11_PUB_ACTION_FTM 33 /* FTM measurement */
+
+/* Block Ack action types */
+#define DOT11_BA_ACTION_ADDBA_REQ 0 /* ADDBA Req action frame type */
+#define DOT11_BA_ACTION_ADDBA_RESP 1 /* ADDBA Resp action frame type */
+#define DOT11_BA_ACTION_DELBA 2 /* DELBA action frame type */
+
+/* ADDBA action parameters */
+#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 /* AMSDU supported under BA */
+#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 /* policy mask(ack vs delayed) */
+#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 /* policy shift */
+#define DOT11_ADDBA_PARAM_TID_MASK 0x003c /* tid mask */
+#define DOT11_ADDBA_PARAM_TID_SHIFT 2 /* tid shift */
+#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 /* buffer size mask */
+#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 /* buffer size shift */
+
+#define DOT11_ADDBA_POLICY_DELAYED 0 /* delayed BA policy */
+#define DOT11_ADDBA_POLICY_IMMEDIATE 1 /* immediate BA policy */
+
+/* Fast Transition action types */
+#define DOT11_FT_ACTION_FT_RESERVED 0
+#define DOT11_FT_ACTION_FT_REQ 1 /* FBT request - for over-the-DS FBT */
+#define DOT11_FT_ACTION_FT_RES 2 /* FBT response - for over-the-DS FBT */
+#define DOT11_FT_ACTION_FT_CON 3 /* FBT confirm - for OTDS with RRP */
+#define DOT11_FT_ACTION_FT_ACK 4 /* FBT ack */
+
+/* DLS action types */
+#define DOT11_DLS_ACTION_REQ 0 /* DLS Request */
+#define DOT11_DLS_ACTION_RESP 1 /* DLS Response */
+#define DOT11_DLS_ACTION_TD 2 /* DLS Teardown */
+
+/* Wireless Network Management (WNM) action types */
+#define DOT11_WNM_ACTION_EVENT_REQ 0
+#define DOT11_WNM_ACTION_EVENT_REP 1
+#define DOT11_WNM_ACTION_DIAG_REQ 2
+#define DOT11_WNM_ACTION_DIAG_REP 3
+#define DOT11_WNM_ACTION_LOC_CFG_REQ 4
+#define DOT11_WNM_ACTION_LOC_RFG_RESP 5
+#define DOT11_WNM_ACTION_BSSTRANS_QUERY 6
+#define DOT11_WNM_ACTION_BSSTRANS_REQ 7
+#define DOT11_WNM_ACTION_BSSTRANS_RESP 8
+#define DOT11_WNM_ACTION_FMS_REQ 9
+#define DOT11_WNM_ACTION_FMS_RESP 10
+#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11
+#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12
+#define DOT11_WNM_ACTION_TFS_REQ 13
+#define DOT11_WNM_ACTION_TFS_RESP 14
+#define DOT11_WNM_ACTION_TFS_NOTIFY_REQ 15
+#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16
+#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17
+#define DOT11_WNM_ACTION_TIMBC_REQ 18
+#define DOT11_WNM_ACTION_TIMBC_RESP 19
+#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20
+#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21
+#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22
+#define DOT11_WNM_ACTION_DMS_REQ 23
+#define DOT11_WNM_ACTION_DMS_RESP 24
+#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25
+#define DOT11_WNM_ACTION_NOTFCTN_REQ 26
+#define DOT11_WNM_ACTION_NOTFCTN_RESP 27
+#define DOT11_WNM_ACTION_TFS_NOTIFY_RESP 28
+
+/* Unprotected Wireless Network Management (WNM) action types */
+#define DOT11_UWNM_ACTION_TIM 0
+#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1
+
+#define DOT11_MNG_COUNTRY_ID_LEN 3
+
+/* VHT category action types - 802.11ac D3.0 - 8.5.23.1 */
+#define DOT11_VHT_ACTION_CBF 0 /* Compressed Beamforming */
+#define DOT11_VHT_ACTION_GID_MGMT 1 /* Group ID Management */
+#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 /* Operating mode notif'n */
+
+/** DLS Request frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_dls_req {
+ uint8 category; /* category of action frame (2) */
+ uint8 action; /* DLS action: req (0) */
+ struct ether_addr da; /* destination address */
+ struct ether_addr sa; /* source address */
+ uint16 cap; /* capability */
+ uint16 timeout; /* timeout value */
+ uint8 data[1]; /* IE:support rate, extend support rate, HT cap */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_dls_req dot11_dls_req_t;
+#define DOT11_DLS_REQ_LEN 18 /* Fixed length */
+
+/** DLS response frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_dls_resp {
+ uint8 category; /* category of action frame (2) */
+ uint8 action; /* DLS action: req (0) */
+ uint16 status; /* status code field */
+ struct ether_addr da; /* destination address */
+ struct ether_addr sa; /* source address */
+ uint8 data[1]; /* optional: capability, rate ... */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_dls_resp dot11_dls_resp_t;
+#define DOT11_DLS_RESP_LEN 16 /* Fixed length */
+
+
+/* ************* 802.11v related definitions. ************* */
+
+/** BSS Management Transition Query frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_query {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: trans_query (6) */
+ uint8 token; /* dialog token */
+ uint8 reason; /* transition query reason */
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_bsstrans_query dot11_bsstrans_query_t;
+#define DOT11_BSSTRANS_QUERY_LEN 4 /* Fixed length */
+
+/* BTM transition reason */
+#define DOT11_BSSTRANS_REASON_UNSPECIFIED 0
+#define DOT11_BSSTRANS_REASON_EXC_FRAME_LOSS 1
+#define DOT11_BSSTRANS_REASON_EXC_TRAFFIC_DELAY 2
+#define DOT11_BSSTRANS_REASON_INSUFF_QOS_CAPACITY 3
+#define DOT11_BSSTRANS_REASON_FIRST_ASSOC 4
+#define DOT11_BSSTRANS_REASON_LOAD_BALANCING 5
+#define DOT11_BSSTRANS_REASON_BETTER_AP_FOUND 6
+#define DOT11_BSSTRANS_REASON_DEAUTH_RX 7
+#define DOT11_BSSTRANS_REASON_8021X_EAP_AUTH_FAIL 8
+#define DOT11_BSSTRANS_REASON_4WAY_HANDSHK_FAIL 9
+#define DOT11_BSSTRANS_REASON_MANY_REPLAYCNT_FAIL 10
+#define DOT11_BSSTRANS_REASON_MANY_DATAMIC_FAIL 11
+#define DOT11_BSSTRANS_REASON_EXCEED_MAX_RETRANS 12
+#define DOT11_BSSTRANS_REASON_MANY_BCAST_DISASSOC_RX 13
+#define DOT11_BSSTRANS_REASON_MANY_BCAST_DEAUTH_RX 14
+#define DOT11_BSSTRANS_REASON_PREV_TRANSITION_FAIL 15
+#define DOT11_BSSTRANS_REASON_LOW_RSSI 16
+#define DOT11_BSSTRANS_REASON_ROAM_FROM_NON_80211 17
+#define DOT11_BSSTRANS_REASON_RX_BTM_REQ 18
+#define DOT11_BSSTRANS_REASON_PREF_LIST_INCLUDED 19
+#define DOT11_BSSTRANS_REASON_LEAVING_ESS 20
+
+/** BSS Management Transition Request frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_req {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: trans_req (7) */
+ uint8 token; /* dialog token */
+ uint8 reqmode; /* transition request mode */
+ uint16 disassoc_tmr; /* disassociation timer */
+ uint8 validity_intrvl; /* validity interval */
+ uint8 data[1]; /* optional: BSS term duration, ... */
+ /* ...session info URL, candidate list */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_bsstrans_req dot11_bsstrans_req_t;
+#define DOT11_BSSTRANS_REQ_LEN 7 /* Fixed length */
+
+/* BSS Mgmt Transition Request Mode Field - 802.11v */
+#define DOT11_BSSTRANS_REQMODE_PREF_LIST_INCL 0x01
+#define DOT11_BSSTRANS_REQMODE_ABRIDGED 0x02
+#define DOT11_BSSTRANS_REQMODE_DISASSOC_IMMINENT 0x04
+#define DOT11_BSSTRANS_REQMODE_BSS_TERM_INCL 0x08
+#define DOT11_BSSTRANS_REQMODE_ESS_DISASSOC_IMNT 0x10
+
+/** BSS Management transition response frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_resp {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: trans_resp (8) */
+ uint8 token; /* dialog token */
+ uint8 status; /* transition status */
+ uint8 term_delay; /* validity interval */
+ uint8 data[1]; /* optional: BSSID target, candidate list */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_bsstrans_resp dot11_bsstrans_resp_t;
+#define DOT11_BSSTRANS_RESP_LEN 5 /* Fixed length */
+
+/* BSS Mgmt Transition Response Status Field */
+#define DOT11_BSSTRANS_RESP_STATUS_ACCEPT 0
+#define DOT11_BSSTRANS_RESP_STATUS_REJECT 1
+#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_BCN 2
+#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_CAP 3
+#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_UNDESIRED 4
+#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_DELAY_REQ 5
+#define DOT11_BSSTRANS_RESP_STATUS_REJ_BSS_LIST_PROVIDED 6
+#define DOT11_BSSTRANS_RESP_STATUS_REJ_NO_SUITABLE_BSS 7
+#define DOT11_BSSTRANS_RESP_STATUS_REJ_LEAVING_ESS 8
+
+
+/** BSS Max Idle Period element */
+BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie {
+ uint8 id; /* 90, DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID */
+ uint8 len;
+ uint16 max_idle_period; /* in unit of 1000 TUs */
+ uint8 idle_opt;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t;
+#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 /* bss max idle period IE size */
+#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 /* BSS max idle option */
+
+/** TIM Broadcast request element */
+BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie {
+ uint8 id; /* 94, DOT11_MNG_TIMBC_REQ_ID */
+ uint8 len;
+ uint8 interval; /* in unit of beacon interval */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t;
+#define DOT11_TIMBC_REQ_IE_LEN 1 /* Fixed length */
+
+/** TIM Broadcast request frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_timbc_req {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: DOT11_WNM_ACTION_TIMBC_REQ(18) */
+ uint8 token; /* dialog token */
+ uint8 data[1]; /* TIM broadcast request element */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_timbc_req dot11_timbc_req_t;
+#define DOT11_TIMBC_REQ_LEN 3 /* Fixed length */
+
+/** TIM Broadcast response element */
+BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie {
+ uint8 id; /* 95, DOT11_MNG_TIM_BROADCAST_RESP_ID */
+ uint8 len;
+ uint8 status; /* status of add request */
+ uint8 interval; /* in unit of beacon interval */
+ int32 offset; /* in unit of ms */
+ uint16 high_rate; /* in unit of 0.5 Mb/s */
+ uint16 low_rate; /* in unit of 0.5 Mb/s */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t;
+#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 /* Deny. Fixed length */
+#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 /* Accept. Fixed length */
+
+#define DOT11_TIMBC_STATUS_ACCEPT 0
+#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1
+#define DOT11_TIMBC_STATUS_DENY 2
+#define DOT11_TIMBC_STATUS_OVERRIDDEN 3
+#define DOT11_TIMBC_STATUS_RESERVED 4
+
+/** TIM Broadcast request frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* action: DOT11_WNM_ACTION_TIMBC_RESP(19) */
+ uint8 token; /* dialog token */
+ uint8 data[1]; /* TIM broadcast response element */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_timbc_resp dot11_timbc_resp_t;
+#define DOT11_TIMBC_RESP_LEN 3 /* Fixed length */
+
+/** TIM element */
+BWL_PRE_PACKED_STRUCT struct dot11_tim_ie {
+ uint8 id; /* 5, DOT11_MNG_TIM_ID */
+ uint8 len; /* 4 - 255 */
+ uint8 dtim_count; /* DTIM decrementing counter */
+ uint8 dtim_period; /* DTIM period */
+ uint8 bitmap_control; /* AID 0 + bitmap offset */
+ uint8 pvb[1]; /* Partial Virtual Bitmap, variable length */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tim_ie dot11_tim_ie_t;
+#define DOT11_TIM_IE_FIXED_LEN 3 /* Fixed length, without id and len */
+#define DOT11_TIM_IE_FIXED_TOTAL_LEN 5 /* Fixed length, with id and len */
+
+/** TIM Broadcast frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_timbc {
+ uint8 category; /* category of action frame (11) */
+ uint8 action; /* action: TIM (0) */
+ uint8 check_beacon; /* need to check-beacon */
+ uint8 tsf[8]; /* Time Synchronization Function */
+ dot11_tim_ie_t tim_ie; /* TIM element */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_timbc dot11_timbc_t;
+#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t))
+#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) /* Fixed length */
+#define DOT11_TIMBC_LEN 11 /* Fixed length */
+
+/** TCLAS frame classifier type */
+BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr {
+ uint8 type;
+ uint8 mask;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t;
+#define DOT11_TCLAS_FC_HDR_LEN 2 /* Fixed length */
+
+#define DOT11_TCLAS_MASK_0 0x1
+#define DOT11_TCLAS_MASK_1 0x2
+#define DOT11_TCLAS_MASK_2 0x4
+#define DOT11_TCLAS_MASK_3 0x8
+#define DOT11_TCLAS_MASK_4 0x10
+#define DOT11_TCLAS_MASK_5 0x20
+#define DOT11_TCLAS_MASK_6 0x40
+#define DOT11_TCLAS_MASK_7 0x80
+
+#define DOT11_TCLAS_FC_0_ETH 0
+#define DOT11_TCLAS_FC_1_IP 1
+#define DOT11_TCLAS_FC_2_8021Q 2
+#define DOT11_TCLAS_FC_3_OFFSET 3
+#define DOT11_TCLAS_FC_4_IP_HIGHER 4
+#define DOT11_TCLAS_FC_5_8021D 5
+
+/** TCLAS frame classifier type 0 parameters for Ethernet */
+BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth {
+ uint8 type;
+ uint8 mask;
+ uint8 sa[ETHER_ADDR_LEN];
+ uint8 da[ETHER_ADDR_LEN];
+ uint16 eth_type;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t;
+#define DOT11_TCLAS_FC_0_ETH_LEN 16
+
+/** TCLAS frame classifier type 1 parameters for IPV4 */
+BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 {
+ uint8 type;
+ uint8 mask;
+ uint8 version;
+ uint32 src_ip;
+ uint32 dst_ip;
+ uint16 src_port;
+ uint16 dst_port;
+ uint8 dscp;
+ uint8 protocol;
+ uint8 reserved;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t;
+#define DOT11_TCLAS_FC_1_IPV4_LEN 18
+
+/** TCLAS frame classifier type 2 parameters for 802.1Q */
+BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q {
+ uint8 type;
+ uint8 mask;
+ uint16 tci;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t;
+#define DOT11_TCLAS_FC_2_8021Q_LEN 4
+
+/** TCLAS frame classifier type 3 parameters for filter offset */
+BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter {
+ uint8 type;
+ uint8 mask;
+ uint16 offset;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t;
+#define DOT11_TCLAS_FC_3_FILTER_LEN 4
+
+/** TCLAS frame classifier type 4 parameters for IPV4 is the same as TCLAS type 1 */
+typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t;
+#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN
+
+/** TCLAS frame classifier type 4 parameters for IPV6 */
+BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 {
+ uint8 type;
+ uint8 mask;
+ uint8 version;
+ uint8 saddr[16];
+ uint8 daddr[16];
+ uint16 src_port;
+ uint16 dst_port;
+ uint8 dscp;
+ uint8 nexthdr;
+ uint8 flow_lbl[3];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t;
+#define DOT11_TCLAS_FC_4_IPV6_LEN 44
+
+/** TCLAS frame classifier type 5 parameters for 802.1D */
+BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d {
+ uint8 type;
+ uint8 mask;
+ uint8 pcp;
+ uint8 cfi;
+ uint16 vid;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t;
+#define DOT11_TCLAS_FC_5_8021D_LEN 6
+
+/** TCLAS frame classifier type parameters */
+BWL_PRE_PACKED_STRUCT union dot11_tclas_fc {
+ uint8 data[1];
+ dot11_tclas_fc_hdr_t hdr;
+ dot11_tclas_fc_0_eth_t t0_eth;
+ dot11_tclas_fc_1_ipv4_t t1_ipv4;
+ dot11_tclas_fc_2_8021q_t t2_8021q;
+ dot11_tclas_fc_3_filter_t t3_filter;
+ dot11_tclas_fc_4_ipv4_t t4_ipv4;
+ dot11_tclas_fc_4_ipv6_t t4_ipv6;
+ dot11_tclas_fc_5_8021d_t t5_8021d;
+} BWL_POST_PACKED_STRUCT;
+typedef union dot11_tclas_fc dot11_tclas_fc_t;
+
+#define DOT11_TCLAS_FC_MIN_LEN 4 /* Classifier Type 2 has the min size */
+#define DOT11_TCLAS_FC_MAX_LEN 254
+
+/** TCLAS element */
+BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie {
+ uint8 id; /* 14, DOT11_MNG_TCLAS_ID */
+ uint8 len;
+ uint8 user_priority;
+ dot11_tclas_fc_t fc;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tclas_ie dot11_tclas_ie_t;
+#define DOT11_TCLAS_IE_LEN 3 /* Fixed length, include id and len */
+
+/** TCLAS processing element */
+BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie {
+ uint8 id; /* 44, DOT11_MNG_TCLAS_PROC_ID */
+ uint8 len;
+ uint8 process;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t;
+#define DOT11_TCLAS_PROC_IE_LEN 3 /* Fixed length, include id and len */
+
+#define DOT11_TCLAS_PROC_MATCHALL 0 /* All high level element need to match */
+#define DOT11_TCLAS_PROC_MATCHONE 1 /* One high level element need to match */
+#define DOT11_TCLAS_PROC_NONMATCH 2 /* Non match to any high level element */
+
+
+/* TSPEC element defined in 802.11 std section 8.4.2.32 - Not supported */
+#define DOT11_TSPEC_IE_LEN 57 /* Fixed length */
+
+/** TFS request element */
+BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie {
+ uint8 id; /* 91, DOT11_MNG_TFS_REQUEST_ID */
+ uint8 len;
+ uint8 tfs_id;
+ uint8 actcode;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t;
+#define DOT11_TFS_REQ_IE_LEN 2 /* Fixed length, without id and len */
+
+/** TFS request action codes (bitfield) */
+#define DOT11_TFS_ACTCODE_DELETE 1
+#define DOT11_TFS_ACTCODE_NOTIFY 2
+
+/** TFS request subelement IDs */
+#define DOT11_TFS_REQ_TFS_SE_ID 1
+#define DOT11_TFS_REQ_VENDOR_SE_ID 221
+
+/** TFS subelement */
+BWL_PRE_PACKED_STRUCT struct dot11_tfs_se {
+ uint8 sub_id;
+ uint8 len;
+ uint8 data[1]; /* TCLAS element(s) + optional TCLAS proc */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tfs_se dot11_tfs_se_t;
+
+
+/** TFS response element */
+BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie {
+ uint8 id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */
+ uint8 len;
+ uint8 tfs_id;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t;
+#define DOT11_TFS_RESP_IE_LEN 1 /* Fixed length, without id and len */
+
+/** TFS response subelement IDs (same subelments, but different IDs than in TFS request */
+#define DOT11_TFS_RESP_TFS_STATUS_SE_ID 1
+#define DOT11_TFS_RESP_TFS_SE_ID 2
+#define DOT11_TFS_RESP_VENDOR_SE_ID 221
+
+/** TFS status subelement */
+BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se {
+ uint8 sub_id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */
+ uint8 len;
+ uint8 resp_st;
+ uint8 data[1]; /* Potential dot11_tfs_se_t included */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tfs_status_se dot11_tfs_status_se_t;
+#define DOT11_TFS_STATUS_SE_LEN 1 /* Fixed length, without id and len */
+
+/* Following Definition should be merged to FMS_TFS macro below */
+/* TFS Response status code. Identical to FMS Element status, without N/A */
+#define DOT11_TFS_STATUS_ACCEPT 0
+#define DOT11_TFS_STATUS_DENY_FORMAT 1
+#define DOT11_TFS_STATUS_DENY_RESOURCE 2
+#define DOT11_TFS_STATUS_DENY_POLICY 4
+#define DOT11_TFS_STATUS_DENY_UNSPECIFIED 5
+#define DOT11_TFS_STATUS_ALTPREF_POLICY 7
+#define DOT11_TFS_STATUS_ALTPREF_TCLAS_UNSUPP 14
+
+/* FMS Element Status and TFS Response Status Definition */
+#define DOT11_FMS_TFS_STATUS_ACCEPT 0
+#define DOT11_FMS_TFS_STATUS_DENY_FORMAT 1
+#define DOT11_FMS_TFS_STATUS_DENY_RESOURCE 2
+#define DOT11_FMS_TFS_STATUS_DENY_MULTIPLE_DI 3
+#define DOT11_FMS_TFS_STATUS_DENY_POLICY 4
+#define DOT11_FMS_TFS_STATUS_DENY_UNSPECIFIED 5
+#define DOT11_FMS_TFS_STATUS_ALT_DIFF_DI 6
+#define DOT11_FMS_TFS_STATUS_ALT_POLICY 7
+#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_DI 8
+#define DOT11_FMS_TFS_STATUS_ALT_MCRATE 9
+#define DOT11_FMS_TFS_STATUS_TERM_POLICY 10
+#define DOT11_FMS_TFS_STATUS_TERM_RESOURCE 11
+#define DOT11_FMS_TFS_STATUS_TERM_HIGHER_PRIO 12
+#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_MDI 13
+#define DOT11_FMS_TFS_STATUS_ALT_TCLAS_UNSUPP 14
+
+/** TFS Management Request frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_tfs_req {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: TFS request (13) */
+ uint8 token; /* dialog token */
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tfs_req dot11_tfs_req_t;
+#define DOT11_TFS_REQ_LEN 3 /* Fixed length */
+
+/** TFS Management Response frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: TFS request (14) */
+ uint8 token; /* dialog token */
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tfs_resp dot11_tfs_resp_t;
+#define DOT11_TFS_RESP_LEN 3 /* Fixed length */
+
+/** TFS Management Notify frame request header */
+BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_req {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: TFS notify request (15) */
+ uint8 tfs_id_cnt; /* TFS IDs count */
+ uint8 tfs_id[1]; /* Array of TFS IDs */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tfs_notify_req dot11_tfs_notify_req_t;
+#define DOT11_TFS_NOTIFY_REQ_LEN 3 /* Fixed length */
+
+/** TFS Management Notify frame response header */
+BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_resp {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: TFS notify response (28) */
+ uint8 tfs_id_cnt; /* TFS IDs count */
+ uint8 tfs_id[1]; /* Array of TFS IDs */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tfs_notify_resp dot11_tfs_notify_resp_t;
+#define DOT11_TFS_NOTIFY_RESP_LEN 3 /* Fixed length */
+
+
+/** WNM-Sleep Management Request frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: wnm-sleep request (16) */
+ uint8 token; /* dialog token */
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t;
+#define DOT11_WNM_SLEEP_REQ_LEN 3 /* Fixed length */
+
+/** WNM-Sleep Management Response frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: wnm-sleep request (17) */
+ uint8 token; /* dialog token */
+ uint16 key_len; /* key data length */
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t;
+#define DOT11_WNM_SLEEP_RESP_LEN 5 /* Fixed length */
+
+#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0
+#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1
+
+BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk {
+ uint8 sub_id;
+ uint8 len;
+ uint16 key_info;
+ uint8 key_length;
+ uint8 rsc[8];
+ uint8 key[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t;
+#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 /* without sub_id, len, and key */
+#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 /* without sub_id and len */
+
+BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk {
+ uint8 sub_id;
+ uint8 len;
+ uint16 key_id;
+ uint8 pn[6];
+ uint8 key[16];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t;
+#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 /* Fixed length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie {
+ uint8 id; /* 93, DOT11_MNG_WNM_SLEEP_MODE_ID */
+ uint8 len;
+ uint8 act_type;
+ uint8 resp_status;
+ uint16 interval;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t;
+#define DOT11_WNM_SLEEP_IE_LEN 4 /* Fixed length */
+
+#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0
+#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1
+
+#define DOT11_WNM_SLEEP_RESP_ACCEPT 0
+#define DOT11_WNM_SLEEP_RESP_UPDATE 1
+#define DOT11_WNM_SLEEP_RESP_DENY 2
+#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3
+#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4
+#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5
+#define DOT11_WNM_SLEEP_RESP_LAST 6
+
+/** DMS Management Request frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_dms_req {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: dms request (23) */
+ uint8 token; /* dialog token */
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_dms_req dot11_dms_req_t;
+#define DOT11_DMS_REQ_LEN 3 /* Fixed length */
+
+/** DMS Management Response frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_dms_resp {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: dms request (24) */
+ uint8 token; /* dialog token */
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_dms_resp dot11_dms_resp_t;
+#define DOT11_DMS_RESP_LEN 3 /* Fixed length */
+
+/** DMS request element */
+BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie {
+ uint8 id; /* 99, DOT11_MNG_DMS_REQUEST_ID */
+ uint8 len;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_dms_req_ie dot11_dms_req_ie_t;
+#define DOT11_DMS_REQ_IE_LEN 2 /* Fixed length */
+
+/** DMS response element */
+BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie {
+ uint8 id; /* 100, DOT11_MNG_DMS_RESPONSE_ID */
+ uint8 len;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t;
+#define DOT11_DMS_RESP_IE_LEN 2 /* Fixed length */
+
+/** DMS request descriptor */
+BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc {
+ uint8 dms_id;
+ uint8 len;
+ uint8 type;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_dms_req_desc dot11_dms_req_desc_t;
+#define DOT11_DMS_REQ_DESC_LEN 3 /* Fixed length */
+
+#define DOT11_DMS_REQ_TYPE_ADD 0
+#define DOT11_DMS_REQ_TYPE_REMOVE 1
+#define DOT11_DMS_REQ_TYPE_CHANGE 2
+
+/** DMS response status */
+BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st {
+ uint8 dms_id;
+ uint8 len;
+ uint8 type;
+ uint16 lsc;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_dms_resp_st dot11_dms_resp_st_t;
+#define DOT11_DMS_RESP_STATUS_LEN 5 /* Fixed length */
+
+#define DOT11_DMS_RESP_TYPE_ACCEPT 0
+#define DOT11_DMS_RESP_TYPE_DENY 1
+#define DOT11_DMS_RESP_TYPE_TERM 2
+
+#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF
+
+/** WNM-Notification Request frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_wnm_notif_req {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: Notification request (26) */
+ uint8 token; /* dialog token */
+ uint8 type; /* type */
+ uint8 data[1]; /* Sub-elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_wnm_notif_req dot11_wnm_notif_req_t;
+#define DOT11_WNM_NOTIF_REQ_LEN 4 /* Fixed length */
+
+/** FMS Management Request frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_fms_req {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: fms request (9) */
+ uint8 token; /* dialog token */
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_fms_req dot11_fms_req_t;
+#define DOT11_FMS_REQ_LEN 3 /* Fixed length */
+
+/** FMS Management Response frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_fms_resp {
+ uint8 category; /* category of action frame (10) */
+ uint8 action; /* WNM action: fms request (10) */
+ uint8 token; /* dialog token */
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_fms_resp dot11_fms_resp_t;
+#define DOT11_FMS_RESP_LEN 3 /* Fixed length */
+
+/** FMS Descriptor element */
+BWL_PRE_PACKED_STRUCT struct dot11_fms_desc {
+ uint8 id;
+ uint8 len;
+ uint8 num_fms_cnt;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_fms_desc dot11_fms_desc_t;
+#define DOT11_FMS_DESC_LEN 1 /* Fixed length */
+
+#define DOT11_FMS_CNTR_MAX 0x8
+#define DOT11_FMS_CNTR_ID_MASK 0x7
+#define DOT11_FMS_CNTR_ID_SHIFT 0x0
+#define DOT11_FMS_CNTR_COUNT_MASK 0xf1
+#define DOT11_FMS_CNTR_SHIFT 0x3
+
+/** FMS request element */
+BWL_PRE_PACKED_STRUCT struct dot11_fms_req_ie {
+ uint8 id;
+ uint8 len;
+ uint8 fms_token; /* token used to identify fms stream set */
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_fms_req_ie dot11_fms_req_ie_t;
+#define DOT11_FMS_REQ_IE_FIX_LEN 1 /* Fixed length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_rate_id_field {
+ uint8 mask;
+ uint8 mcs_idx;
+ uint16 rate;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rate_id_field dot11_rate_id_field_t;
+#define DOT11_RATE_ID_FIELD_MCS_SEL_MASK 0x7
+#define DOT11_RATE_ID_FIELD_MCS_SEL_OFFSET 0
+#define DOT11_RATE_ID_FIELD_RATETYPE_MASK 0x18
+#define DOT11_RATE_ID_FIELD_RATETYPE_OFFSET 3
+#define DOT11_RATE_ID_FIELD_LEN sizeof(dot11_rate_id_field_t)
+
+/** FMS request subelements */
+BWL_PRE_PACKED_STRUCT struct dot11_fms_se {
+ uint8 sub_id;
+ uint8 len;
+ uint8 interval;
+ uint8 max_interval;
+ dot11_rate_id_field_t rate;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_fms_se dot11_fms_se_t;
+#define DOT11_FMS_REQ_SE_LEN 6 /* Fixed length */
+
+#define DOT11_FMS_REQ_SE_ID_FMS 1 /* FMS subelement */
+#define DOT11_FMS_REQ_SE_ID_VS 221 /* Vendor Specific subelement */
+
+/** FMS response element */
+BWL_PRE_PACKED_STRUCT struct dot11_fms_resp_ie {
+ uint8 id;
+ uint8 len;
+ uint8 fms_token;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_fms_resp_ie dot11_fms_resp_ie_t;
+#define DOT11_FMS_RESP_IE_FIX_LEN 1 /* Fixed length */
+
+/* FMS status subelements */
+#define DOT11_FMS_STATUS_SE_ID_FMS 1 /* FMS Status */
+#define DOT11_FMS_STATUS_SE_ID_TCLAS 2 /* TCLAS Status */
+#define DOT11_FMS_STATUS_SE_ID_VS 221 /* Vendor Specific subelement */
+
+/** FMS status subelement */
+BWL_PRE_PACKED_STRUCT struct dot11_fms_status_se {
+ uint8 sub_id;
+ uint8 len;
+ uint8 status;
+ uint8 interval;
+ uint8 max_interval;
+ uint8 fmsid;
+ uint8 counter;
+ dot11_rate_id_field_t rate;
+ uint8 mcast_addr[ETHER_ADDR_LEN];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_fms_status_se dot11_fms_status_se_t;
+#define DOT11_FMS_STATUS_SE_LEN 15 /* Fixed length */
+
+/** TCLAS status subelement */
+BWL_PRE_PACKED_STRUCT struct dot11_tclas_status_se {
+ uint8 sub_id;
+ uint8 len;
+ uint8 fmsid;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_tclas_status_se dot11_tclas_status_se_t;
+#define DOT11_TCLAS_STATUS_SE_LEN 1 /* Fixed length */
+
+BWL_PRE_PACKED_STRUCT struct dot11_addba_req {
+ uint8 category; /* category of action frame (3) */
+ uint8 action; /* action: addba req */
+ uint8 token; /* identifier */
+ uint16 addba_param_set; /* parameter set */
+ uint16 timeout; /* timeout in seconds */
+ uint16 start_seqnum; /* starting sequence number */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_addba_req dot11_addba_req_t;
+#define DOT11_ADDBA_REQ_LEN 9 /* length of addba req frame */
+
+BWL_PRE_PACKED_STRUCT struct dot11_addba_resp {
+ uint8 category; /* category of action frame (3) */
+ uint8 action; /* action: addba resp */
+ uint8 token; /* identifier */
+ uint16 status; /* status of add request */
+ uint16 addba_param_set; /* negotiated parameter set */
+ uint16 timeout; /* negotiated timeout in seconds */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_addba_resp dot11_addba_resp_t;
+#define DOT11_ADDBA_RESP_LEN 9 /* length of addba resp frame */
+
+/* DELBA action parameters */
+#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 /* initiator mask */
+#define DOT11_DELBA_PARAM_INIT_SHIFT 11 /* initiator shift */
+#define DOT11_DELBA_PARAM_TID_MASK 0xf000 /* tid mask */
+#define DOT11_DELBA_PARAM_TID_SHIFT 12 /* tid shift */
+
+BWL_PRE_PACKED_STRUCT struct dot11_delba {
+ uint8 category; /* category of action frame (3) */
+ uint8 action; /* action: addba req */
+ uint16 delba_param_set; /* paarmeter set */
+ uint16 reason; /* reason for dellba */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_delba dot11_delba_t;
+#define DOT11_DELBA_LEN 6 /* length of delba frame */
+
+/* SA Query action field value */
+#define SA_QUERY_REQUEST 0
+#define SA_QUERY_RESPONSE 1
+
+/* ************* 802.11r related definitions. ************* */
+
+/** Over-the-DS Fast Transition Request frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_ft_req {
+ uint8 category; /* category of action frame (6) */
+ uint8 action; /* action: ft req */
+ uint8 sta_addr[ETHER_ADDR_LEN];
+ uint8 tgt_ap_addr[ETHER_ADDR_LEN];
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ft_req dot11_ft_req_t;
+#define DOT11_FT_REQ_FIXED_LEN 14
+
+/** Over-the-DS Fast Transition Response frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_ft_res {
+ uint8 category; /* category of action frame (6) */
+ uint8 action; /* action: ft resp */
+ uint8 sta_addr[ETHER_ADDR_LEN];
+ uint8 tgt_ap_addr[ETHER_ADDR_LEN];
+ uint16 status; /* status code */
+ uint8 data[1]; /* Elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ft_res dot11_ft_res_t;
+#define DOT11_FT_RES_FIXED_LEN 16
+
+/** RDE RIC Data Element. */
+BWL_PRE_PACKED_STRUCT struct dot11_rde_ie {
+ uint8 id; /* 11r, DOT11_MNG_RDE_ID */
+ uint8 length;
+ uint8 rde_id; /* RDE identifier. */
+ uint8 rd_count; /* Resource Descriptor Count. */
+ uint16 status; /* Status Code. */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rde_ie dot11_rde_ie_t;
+
+/* 11r - Size of the RDE (RIC Data Element) IE, including TLV header. */
+#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t)
+
+
+/* ************* 802.11k related definitions. ************* */
+
+/* Radio measurements enabled capability ie */
+#define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */
+#define RCPI_IE_LEN 1
+#define RSNI_IE_LEN 1
+BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie {
+ uint8 cap[DOT11_RRM_CAP_LEN];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t;
+
+/* Bitmap definitions for cap ie */
+#define DOT11_RRM_CAP_LINK 0
+#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1
+#define DOT11_RRM_CAP_PARALLEL 2
+#define DOT11_RRM_CAP_REPEATED 3
+#define DOT11_RRM_CAP_BCN_PASSIVE 4
+#define DOT11_RRM_CAP_BCN_ACTIVE 5
+#define DOT11_RRM_CAP_BCN_TABLE 6
+#define DOT11_RRM_CAP_BCN_REP_COND 7
+#define DOT11_RRM_CAP_FM 8
+#define DOT11_RRM_CAP_CLM 9
+#define DOT11_RRM_CAP_NHM 10
+#define DOT11_RRM_CAP_SM 11
+#define DOT11_RRM_CAP_LCIM 12
+#define DOT11_RRM_CAP_LCIA 13
+#define DOT11_RRM_CAP_TSCM 14
+#define DOT11_RRM_CAP_TTSCM 15
+#define DOT11_RRM_CAP_AP_CHANREP 16
+#define DOT11_RRM_CAP_RMMIB 17
+/* bit18-bit23, not used for RRM_IOVAR */
+#define DOT11_RRM_CAP_MPC0 24
+#define DOT11_RRM_CAP_MPC1 25
+#define DOT11_RRM_CAP_MPC2 26
+#define DOT11_RRM_CAP_MPTI 27
+#define DOT11_RRM_CAP_NBRTSFO 28
+#define DOT11_RRM_CAP_RCPI 29
+#define DOT11_RRM_CAP_RSNI 30
+#define DOT11_RRM_CAP_BSSAAD 31
+#define DOT11_RRM_CAP_BSSAAC 32
+#define DOT11_RRM_CAP_AI 33
+#define DOT11_RRM_CAP_FTM_RANGE 34
+#define DOT11_RRM_CAP_CIVIC_LOC 35
+#define DOT11_RRM_CAP_IDENT_LOC 36
+#define DOT11_RRM_CAP_LAST 36
+
+#define DOT11_RRM_CAP_MPA_MASK 0x7
+/* Operating Class (formerly "Regulatory Class") definitions */
+#define DOT11_OP_CLASS_NONE 255
+
+BWL_PRE_PACKED_STRUCT struct do11_ap_chrep {
+ uint8 id;
+ uint8 len;
+ uint8 reg;
+ uint8 chanlist[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct do11_ap_chrep dot11_ap_chrep_t;
+
+/* Radio Measurements action ids */
+#define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */
+#define DOT11_RM_ACTION_RM_REP 1 /* Radio measurement report */
+#define DOT11_RM_ACTION_LM_REQ 2 /* Link measurement request */
+#define DOT11_RM_ACTION_LM_REP 3 /* Link measurement report */
+#define DOT11_RM_ACTION_NR_REQ 4 /* Neighbor report request */
+#define DOT11_RM_ACTION_NR_REP 5 /* Neighbor report response */
+#define DOT11_PUB_ACTION_MP 7 /* Measurement Pilot public action id */
+
+/** Generic radio measurement action frame header */
+BWL_PRE_PACKED_STRUCT struct dot11_rm_action {
+ uint8 category; /* category of action frame (5) */
+ uint8 action; /* radio measurement action */
+ uint8 token; /* dialog token */
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rm_action dot11_rm_action_t;
+#define DOT11_RM_ACTION_LEN 3
+
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq {
+ uint8 category; /* category of action frame (5) */
+ uint8 action; /* radio measurement action */
+ uint8 token; /* dialog token */
+ uint16 reps; /* no. of repetitions */
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq dot11_rmreq_t;
+#define DOT11_RMREQ_LEN 5
+
+BWL_PRE_PACKED_STRUCT struct dot11_rm_ie {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rm_ie dot11_rm_ie_t;
+#define DOT11_RM_IE_LEN 5
+
+/* Definitions for "mode" bits in rm req */
+#define DOT11_RMREQ_MODE_PARALLEL 1
+#define DOT11_RMREQ_MODE_ENABLE 2
+#define DOT11_RMREQ_MODE_REQUEST 4
+#define DOT11_RMREQ_MODE_REPORT 8
+#define DOT11_RMREQ_MODE_DURMAND 0x10 /* Duration Mandatory */
+
+/* Definitions for "mode" bits in rm rep */
+#define DOT11_RMREP_MODE_LATE 1
+#define DOT11_RMREP_MODE_INCAPABLE 2
+#define DOT11_RMREP_MODE_REFUSED 4
+
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 reg;
+ uint8 channel;
+ uint16 interval;
+ uint16 duration;
+ uint8 bcn_mode;
+ struct ether_addr bssid;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t;
+#define DOT11_RMREQ_BCN_LEN 18
+
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn {
+ uint8 reg;
+ uint8 channel;
+ uint32 starttime[2];
+ uint16 duration;
+ uint8 frame_info;
+ uint8 rcpi;
+ uint8 rsni;
+ struct ether_addr bssid;
+ uint8 antenna_id;
+ uint32 parent_tsf;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t;
+#define DOT11_RMREP_BCN_LEN 26
+
+/* Beacon request measurement mode */
+#define DOT11_RMREQ_BCN_PASSIVE 0
+#define DOT11_RMREQ_BCN_ACTIVE 1
+#define DOT11_RMREQ_BCN_TABLE 2
+
+/* Sub-element IDs for Beacon Request */
+#define DOT11_RMREQ_BCN_SSID_ID 0
+#define DOT11_RMREQ_BCN_REPINFO_ID 1
+#define DOT11_RMREQ_BCN_REPDET_ID 2
+#define DOT11_RMREQ_BCN_REQUEST_ID 10
+#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID
+
+/* Reporting Detail element definition */
+#define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */
+#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 /* + requested information elems */
+#define DOT11_RMREQ_BCN_REPDET_ALL 2 /* All fields */
+
+/* Reporting Information (reporting condition) element definition */
+#define DOT11_RMREQ_BCN_REPINFO_LEN 2 /* Beacon Reporting Information length */
+#define DOT11_RMREQ_BCN_REPCOND_DEFAULT 0 /* Report to be issued after each measurement */
+
+/* Sub-element IDs for Beacon Report */
+#define DOT11_RMREP_BCN_FRM_BODY 1
+#define DOT11_RMREP_BCN_FRM_BODY_LEN_MAX 224 /* 802.11k-2008 7.3.2.22.6 */
+
+/* Sub-element IDs for Frame Report */
+#define DOT11_RMREP_FRAME_COUNT_REPORT 1
+
+/* Channel load request */
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 reg;
+ uint8 channel;
+ uint16 interval;
+ uint16 duration;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t;
+#define DOT11_RMREQ_CHANLOAD_LEN 11
+
+/** Channel load report */
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload {
+ uint8 reg;
+ uint8 channel;
+ uint32 starttime[2];
+ uint16 duration;
+ uint8 channel_load;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t;
+#define DOT11_RMREP_CHANLOAD_LEN 13
+
+/** Noise histogram request */
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 reg;
+ uint8 channel;
+ uint16 interval;
+ uint16 duration;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_noise dot11_rmreq_noise_t;
+#define DOT11_RMREQ_NOISE_LEN 11
+
+/** Noise histogram report */
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise {
+ uint8 reg;
+ uint8 channel;
+ uint32 starttime[2];
+ uint16 duration;
+ uint8 antid;
+ uint8 anpi;
+ uint8 ipi0_dens;
+ uint8 ipi1_dens;
+ uint8 ipi2_dens;
+ uint8 ipi3_dens;
+ uint8 ipi4_dens;
+ uint8 ipi5_dens;
+ uint8 ipi6_dens;
+ uint8 ipi7_dens;
+ uint8 ipi8_dens;
+ uint8 ipi9_dens;
+ uint8 ipi10_dens;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_noise dot11_rmrep_noise_t;
+#define DOT11_RMREP_NOISE_LEN 25
+
+/** Frame request */
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 reg;
+ uint8 channel;
+ uint16 interval;
+ uint16 duration;
+ uint8 req_type;
+ struct ether_addr ta;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_frame dot11_rmreq_frame_t;
+#define DOT11_RMREQ_FRAME_LEN 18
+
+/** Frame report */
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame {
+ uint8 reg;
+ uint8 channel;
+ uint32 starttime[2];
+ uint16 duration;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_frame dot11_rmrep_frame_t;
+#define DOT11_RMREP_FRAME_LEN 12
+
+/** Frame report entry */
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry {
+ struct ether_addr ta;
+ struct ether_addr bssid;
+ uint8 phy_type;
+ uint8 avg_rcpi;
+ uint8 last_rsni;
+ uint8 last_rcpi;
+ uint8 ant_id;
+ uint16 frame_cnt;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t;
+#define DOT11_RMREP_FRMENTRY_LEN 19
+
+/** STA statistics request */
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ struct ether_addr peer;
+ uint16 interval;
+ uint16 duration;
+ uint8 group_id;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_stat dot11_rmreq_stat_t;
+#define DOT11_RMREQ_STAT_LEN 16
+
+/** STA statistics report */
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat {
+ uint16 duration;
+ uint8 group_id;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_stat dot11_rmrep_stat_t;
+
+/* Statistics Group Report: Group IDs */
+enum {
+ DOT11_RRM_STATS_GRP_ID_0 = 0,
+ DOT11_RRM_STATS_GRP_ID_1,
+ DOT11_RRM_STATS_GRP_ID_2,
+ DOT11_RRM_STATS_GRP_ID_3,
+ DOT11_RRM_STATS_GRP_ID_4,
+ DOT11_RRM_STATS_GRP_ID_5,
+ DOT11_RRM_STATS_GRP_ID_6,
+ DOT11_RRM_STATS_GRP_ID_7,
+ DOT11_RRM_STATS_GRP_ID_8,
+ DOT11_RRM_STATS_GRP_ID_9,
+ DOT11_RRM_STATS_GRP_ID_10,
+ DOT11_RRM_STATS_GRP_ID_11,
+ DOT11_RRM_STATS_GRP_ID_12,
+ DOT11_RRM_STATS_GRP_ID_13,
+ DOT11_RRM_STATS_GRP_ID_14,
+ DOT11_RRM_STATS_GRP_ID_15,
+ DOT11_RRM_STATS_GRP_ID_16
+};
+
+/* Statistics Group Report: Group Data length */
+#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_0 28
+typedef struct rrm_stat_group_0 {
+ uint32 txfrag;
+ uint32 txmulti;
+ uint32 txfail;
+ uint32 rxframe;
+ uint32 rxmulti;
+ uint32 rxbadfcs;
+ uint32 txframe;
+} rrm_stat_group_0_t;
+
+#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_1 24
+typedef struct rrm_stat_group_1 {
+ uint32 txretry;
+ uint32 txretries;
+ uint32 rxdup;
+ uint32 txrts;
+ uint32 rtsfail;
+ uint32 ackfail;
+} rrm_stat_group_1_t;
+
+/* group 2-9 use same qos data structure (tid 0-7), total 52 bytes */
+#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_2_9 52
+typedef struct rrm_stat_group_qos {
+ uint32 txfrag;
+ uint32 txfail;
+ uint32 txretry;
+ uint32 txretries;
+ uint32 rxdup;
+ uint32 txrts;
+ uint32 rtsfail;
+ uint32 ackfail;
+ uint32 rxfrag;
+ uint32 txframe;
+ uint32 txdrop;
+ uint32 rxmpdu;
+ uint32 rxretries;
+} rrm_stat_group_qos_t;
+
+/* dot11BSSAverageAccessDelay Group (only available at an AP): 8 byte */
+#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_10 8
+typedef BWL_PRE_PACKED_STRUCT struct rrm_stat_group_10 {
+ uint8 apavgdelay;
+ uint8 avgdelaybe;
+ uint8 avgdelaybg;
+ uint8 avgdelayvi;
+ uint8 avgdelayvo;
+ uint16 stacount;
+ uint8 chanutil;
+} BWL_POST_PACKED_STRUCT rrm_stat_group_10_t;
+
+/* AMSDU, 40 bytes */
+#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_11 40
+typedef struct rrm_stat_group_11 {
+ uint32 txamsdu;
+ uint32 amsdufail;
+ uint32 amsduretry;
+ uint32 amsduretries;
+ uint32 txamsdubyte_h;
+ uint32 txamsdubyte_l;
+ uint32 amsduackfail;
+ uint32 rxamsdu;
+ uint32 rxamsdubyte_h;
+ uint32 rxamsdubyte_l;
+} rrm_stat_group_11_t;
+
+/* AMPDU, 36 bytes */
+#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_12 36
+typedef struct rrm_stat_group_12 {
+ uint32 txampdu;
+ uint32 txmpdu;
+ uint32 txampdubyte_h;
+ uint32 txampdubyte_l;
+ uint32 rxampdu;
+ uint32 rxmpdu;
+ uint32 rxampdubyte_h;
+ uint32 rxampdubyte_l;
+ uint32 ampducrcfail;
+} rrm_stat_group_12_t;
+
+/* BACK etc, 36 bytes */
+#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_13 36
+typedef struct rrm_stat_group_13 {
+ uint32 rximpbarfail;
+ uint32 rxexpbarfail;
+ uint32 chanwidthsw;
+ uint32 txframe20mhz;
+ uint32 txframe40mhz;
+ uint32 rxframe20mhz;
+ uint32 rxframe40mhz;
+ uint32 psmpgrantdur;
+ uint32 psmpuseddur;
+} rrm_stat_group_13_t;
+
+/* RD Dual CTS etc, 36 bytes */
+#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_14 36
+typedef struct rrm_stat_group_14 {
+ uint32 grantrdgused;
+ uint32 grantrdgunused;
+ uint32 txframeingrantrdg;
+ uint32 txbyteingrantrdg_h;
+ uint32 txbyteingrantrdg_l;
+ uint32 dualcts;
+ uint32 dualctsfail;
+ uint32 rtslsi;
+ uint32 rtslsifail;
+} rrm_stat_group_14_t;
+
+/* bf and STBC etc, 20 bytes */
+#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_15 20
+typedef struct rrm_stat_group_15 {
+ uint32 bfframe;
+ uint32 stbccts;
+ uint32 stbcctsfail;
+ uint32 nonstbccts;
+ uint32 nonstbcctsfail;
+} rrm_stat_group_15_t;
+
+/* RSNA, 28 bytes */
+#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_16 28
+typedef struct rrm_stat_group_16 {
+ uint32 rsnacmacicverr;
+ uint32 rsnacmacreplay;
+ uint32 rsnarobustmgmtccmpreplay;
+ uint32 rsnatkipicverr;
+ uint32 rsnatkipicvreplay;
+ uint32 rsnaccmpdecrypterr;
+ uint32 rsnaccmpreplay;
+} rrm_stat_group_16_t;
+
+/* Transmit stream/category measurement request */
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint16 interval;
+ uint16 duration;
+ struct ether_addr peer;
+ uint8 traffic_id;
+ uint8 bin0_range;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t;
+#define DOT11_RMREQ_TXSTREAM_LEN 17
+
+/** Transmit stream/category measurement report */
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream {
+ uint32 starttime[2];
+ uint16 duration;
+ struct ether_addr peer;
+ uint8 traffic_id;
+ uint8 reason;
+ uint32 txmsdu_cnt;
+ uint32 msdu_discarded_cnt;
+ uint32 msdufailed_cnt;
+ uint32 msduretry_cnt;
+ uint32 cfpolls_lost_cnt;
+ uint32 avrqueue_delay;
+ uint32 avrtx_delay;
+ uint8 bin0_range;
+ uint32 bin0;
+ uint32 bin1;
+ uint32 bin2;
+ uint32 bin3;
+ uint32 bin4;
+ uint32 bin5;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t;
+#define DOT11_RMREP_TXSTREAM_LEN 71
+
+typedef struct rrm_tscm {
+ uint32 msdu_tx;
+ uint32 msdu_exp;
+ uint32 msdu_fail;
+ uint32 msdu_retries;
+ uint32 cfpolls_lost;
+ uint32 queue_delay;
+ uint32 tx_delay_sum;
+ uint32 tx_delay_cnt;
+ uint32 bin0_range_us;
+ uint32 bin0;
+ uint32 bin1;
+ uint32 bin2;
+ uint32 bin3;
+ uint32 bin4;
+ uint32 bin5;
+} rrm_tscm_t;
+enum {
+ DOT11_FTM_LOCATION_SUBJ_LOCAL = 0, /* Where am I? */
+ DOT11_FTM_LOCATION_SUBJ_REMOTE = 1, /* Where are you? */
+ DOT11_FTM_LOCATION_SUBJ_THIRDPARTY = 2 /* Where is he/she? */
+};
+
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_lci {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 subj;
+
+ /* Following 3 fields are unused. Keep for ROM compatibility. */
+ uint8 lat_res;
+ uint8 lon_res;
+ uint8 alt_res;
+
+ /* optional sub-elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_ftm_lci dot11_rmreq_ftm_lci_t;
+#define DOT11_RMREQ_LCI_LEN 9
+
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_lci {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 lci_sub_id;
+ uint8 lci_sub_len;
+ /* optional LCI field */
+ /* optional sub-elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_ftm_lci dot11_rmrep_ftm_lci_t;
+
+#define DOT11_FTM_LCI_SUBELEM_ID 0
+#define DOT11_FTM_LCI_SUBELEM_LEN 2
+#define DOT11_FTM_LCI_FIELD_LEN 16
+#define DOT11_FTM_LCI_UNKNOWN_LEN 2
+
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_civic {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 subj;
+ uint8 civloc_type;
+ uint8 siu; /* service interval units */
+ uint16 si; /* service interval */
+ /* optional sub-elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_ftm_civic dot11_rmreq_ftm_civic_t;
+#define DOT11_RMREQ_CIVIC_LEN 10
+
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_civic {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 civloc_type;
+ uint8 civloc_sub_id;
+ uint8 civloc_sub_len;
+ /* optional location civic field */
+ /* optional sub-elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_ftm_civic dot11_rmrep_ftm_civic_t;
+
+#define DOT11_FTM_CIVIC_LOC_TYPE_RFC4776 0
+#define DOT11_FTM_CIVIC_SUBELEM_ID 0
+#define DOT11_FTM_CIVIC_SUBELEM_LEN 2
+#define DOT11_FTM_CIVIC_LOC_SI_NONE 0
+#define DOT11_FTM_CIVIC_TYPE_LEN 1
+#define DOT11_FTM_CIVIC_UNKNOWN_LEN 3
+
+/* Location Identifier measurement request */
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_locid {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 subj;
+ uint8 siu;
+ uint16 si;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_locid dot11_rmreq_locid_t;
+#define DOT11_RMREQ_LOCID_LEN 9
+
+/* Location Identifier measurement report */
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_locid {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 exp_tsf[8];
+ uint8 locid_sub_id;
+ uint8 locid_sub_len;
+ /* optional location identifier field */
+ /* optional sub-elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_locid dot11_rmrep_locid_t;
+#define DOT11_LOCID_UNKNOWN_LEN 10
+#define DOT11_LOCID_SUBELEM_ID 0
+
+BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_subel {
+ uint8 id;
+ uint8 len;
+ uint16 max_age;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ftm_range_subel dot11_ftm_range_subel_t;
+#define DOT11_FTM_RANGE_SUBELEM_ID 4
+#define DOT11_FTM_RANGE_SUBELEM_LEN 2
+
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_range {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint16 max_init_delay; /* maximum random initial delay */
+ uint8 min_ap_count;
+ uint8 data[1];
+ /* neighbor report sub-elements */
+ /* optional sub-elements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_ftm_range dot11_rmreq_ftm_range_t;
+#define DOT11_RMREQ_FTM_RANGE_LEN 8
+
+#define DOT11_FTM_RANGE_LEN 3
+BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_entry {
+ uint32 start_tsf; /* 4 lsb of tsf */
+ struct ether_addr bssid;
+ uint8 range[DOT11_FTM_RANGE_LEN];
+ uint8 max_err[DOT11_FTM_RANGE_LEN];
+ uint8 rsvd;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ftm_range_entry dot11_ftm_range_entry_t;
+#define DOT11_FTM_RANGE_ENTRY_MAX_COUNT 15
+
+enum {
+ DOT11_FTM_RANGE_ERROR_AP_INCAPABLE = 2,
+ DOT11_FTM_RANGE_ERROR_AP_FAILED = 3,
+ DOT11_FTM_RANGE_ERROR_TX_FAILED = 8,
+ DOT11_FTM_RANGE_ERROR_MAX
+};
+
+BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_error_entry {
+ uint32 start_tsf; /* 4 lsb of tsf */
+ struct ether_addr bssid;
+ uint8 code;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ftm_range_error_entry dot11_ftm_range_error_entry_t;
+#define DOT11_FTM_RANGE_ERROR_ENTRY_MAX_COUNT 11
+
+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_range {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint8 entry_count;
+ uint8 data[2]; /* includes pad */
+ /*
+ dot11_ftm_range_entry_t entries[entry_count];
+ uint8 error_count;
+ dot11_ftm_error_entry_t errors[error_count];
+ */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmrep_ftm_range dot11_rmrep_ftm_range_t;
+
+#define DOT11_FTM_RANGE_REP_MIN_LEN 6 /* No extra byte for error_count */
+#define DOT11_FTM_RANGE_ENTRY_CNT_MAX 15
+#define DOT11_FTM_RANGE_ERROR_CNT_MAX 11
+#define DOT11_FTM_RANGE_REP_FIXED_LEN 1 /* No extra byte for error_count */
+/** Measurement pause request */
+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time {
+ uint8 id;
+ uint8 len;
+ uint8 token;
+ uint8 mode;
+ uint8 type;
+ uint16 pause_time;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t;
+#define DOT11_RMREQ_PAUSE_LEN 7
+
+
+/* Neighbor Report subelements ID (11k & 11v) */
+#define DOT11_NGBR_TSF_INFO_SE_ID 1
+#define DOT11_NGBR_CCS_SE_ID 2
+#define DOT11_NGBR_BSSTRANS_PREF_SE_ID 3
+#define DOT11_NGBR_BSS_TERM_DUR_SE_ID 4
+#define DOT11_NGBR_BEARING_SE_ID 5
+#define DOT11_NGBR_WIDE_BW_CHAN_SE_ID 6
+
+/** Neighbor Report, BSS Transition Candidate Preference subelement */
+BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bsstrans_pref_se {
+ uint8 sub_id;
+ uint8 len;
+ uint8 preference;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ngbr_bsstrans_pref_se dot11_ngbr_bsstrans_pref_se_t;
+#define DOT11_NGBR_BSSTRANS_PREF_SE_LEN 1
+
+/** Neighbor Report, BSS Termination Duration subelement */
+BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bss_term_dur_se {
+ uint8 sub_id;
+ uint8 len;
+ uint8 tsf[8];
+ uint16 duration;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ngbr_bss_term_dur_se dot11_ngbr_bss_term_dur_se_t;
+#define DOT11_NGBR_BSS_TERM_DUR_SE_LEN 10
+
+/* Neighbor Report BSSID Information Field */
+#define DOT11_NGBR_BI_REACHABILTY_UNKN 0x0002
+#define DOT11_NGBR_BI_REACHABILTY 0x0003
+#define DOT11_NGBR_BI_SEC 0x0004
+#define DOT11_NGBR_BI_KEY_SCOPE 0x0008
+#define DOT11_NGBR_BI_CAP 0x03f0
+#define DOT11_NGBR_BI_CAP_SPEC_MGMT 0x0010
+#define DOT11_NGBR_BI_CAP_QOS 0x0020
+#define DOT11_NGBR_BI_CAP_APSD 0x0040
+#define DOT11_NGBR_BI_CAP_RDIO_MSMT 0x0080
+#define DOT11_NGBR_BI_CAP_DEL_BA 0x0100
+#define DOT11_NGBR_BI_CAP_IMM_BA 0x0200
+#define DOT11_NGBR_BI_MOBILITY 0x0400
+#define DOT11_NGBR_BI_HT 0x0800
+#define DOT11_NGBR_BI_VHT 0x1000
+#define DOT11_NGBR_BI_FTM 0x2000
+
+/** Neighbor Report element (11k & 11v) */
+BWL_PRE_PACKED_STRUCT struct dot11_neighbor_rep_ie {
+ uint8 id;
+ uint8 len;
+ struct ether_addr bssid;
+ uint32 bssid_info;
+ uint8 reg; /* Operating class */
+ uint8 channel;
+ uint8 phytype;
+ uint8 data[1]; /* Variable size subelements */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t;
+#define DOT11_NEIGHBOR_REP_IE_FIXED_LEN 13
+
+
+/* MLME Enumerations */
+#define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */
+#define DOT11_BSSTYPE_INDEPENDENT 1 /* d11 independent */
+#define DOT11_BSSTYPE_ANY 2 /* d11 any BSS type */
+#define DOT11_BSSTYPE_MESH 3 /* d11 Mesh */
+#define DOT11_SCANTYPE_ACTIVE 0 /* d11 scan active */
+#define DOT11_SCANTYPE_PASSIVE 1 /* d11 scan passive */
+
+/** Link Measurement */
+BWL_PRE_PACKED_STRUCT struct dot11_lmreq {
+ uint8 category; /* category of action frame (5) */
+ uint8 action; /* radio measurement action */
+ uint8 token; /* dialog token */
+ uint8 txpwr; /* Transmit Power Used */
+ uint8 maxtxpwr; /* Max Transmit Power */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_lmreq dot11_lmreq_t;
+#define DOT11_LMREQ_LEN 5
+
+BWL_PRE_PACKED_STRUCT struct dot11_lmrep {
+ uint8 category; /* category of action frame (5) */
+ uint8 action; /* radio measurement action */
+ uint8 token; /* dialog token */
+ dot11_tpc_rep_t tpc; /* TPC element */
+ uint8 rxant; /* Receive Antenna ID */
+ uint8 txant; /* Transmit Antenna ID */
+ uint8 rcpi; /* RCPI */
+ uint8 rsni; /* RSNI */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_lmrep dot11_lmrep_t;
+#define DOT11_LMREP_LEN 11
+
+#define DOT11_MP_CAP_SPECTRUM 0x01 /* d11 cap. spectrum */
+#define DOT11_MP_CAP_SHORTSLOT 0x02 /* d11 cap. shortslot */
+/* Measurement Pilot */
+BWL_PRE_PACKED_STRUCT struct dot11_mprep {
+ uint8 cap_info; /* Condensed capability Info. */
+ uint8 country[2]; /* Condensed country string */
+ uint8 opclass; /* Op. Class */
+ uint8 channel; /* Channel */
+ uint8 mp_interval; /* Measurement Pilot Interval */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_mprep dot11_mprep_t;
+#define DOT11_MPREP_LEN 6
+
+/* 802.11 BRCM "Compromise" Pre N constants */
+#define PREN_PREAMBLE 24 /* green field preamble time */
+#define PREN_MM_EXT 12 /* extra mixed mode preamble time */
+#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */
+
+/* 802.11N PHY constants */
+#define RIFS_11N_TIME 2 /* NPHY RIFS time */
+
+/* 802.11 HT PLCP format 802.11n-2009, sec 20.3.9.4.3
+ * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2
+ */
+/* HT-SIG1 */
+#define HT_SIG1_MCS_MASK 0x00007F
+#define HT_SIG1_CBW 0x000080
+#define HT_SIG1_HT_LENGTH 0xFFFF00
+
+/* HT-SIG2 */
+#define HT_SIG2_SMOOTHING 0x000001
+#define HT_SIG2_NOT_SOUNDING 0x000002
+#define HT_SIG2_RESERVED 0x000004
+#define HT_SIG2_AGGREGATION 0x000008
+#define HT_SIG2_STBC_MASK 0x000030
+#define HT_SIG2_STBC_SHIFT 4
+#define HT_SIG2_FEC_CODING 0x000040
+#define HT_SIG2_SHORT_GI 0x000080
+#define HT_SIG2_ESS_MASK 0x000300
+#define HT_SIG2_ESS_SHIFT 8
+#define HT_SIG2_CRC 0x03FC00
+#define HT_SIG2_TAIL 0x1C0000
+
+/* HT Timing-related parameters (802.11-2012, sec 20.3.6) */
+#define HT_T_LEG_PREAMBLE 16
+#define HT_T_L_SIG 4
+#define HT_T_SIG 8
+#define HT_T_LTF1 4
+#define HT_T_GF_LTF1 8
+#define HT_T_LTFs 4
+#define HT_T_STF 4
+#define HT_T_GF_STF 8
+#define HT_T_SYML 4
+
+#define HT_N_SERVICE 16 /* bits in SERVICE field */
+#define HT_N_TAIL 6 /* tail bits per BCC encoder */
+
+/* 802.11 A PHY constants */
+#define APHY_SLOT_TIME 9 /* APHY slot time */
+#define APHY_SIFS_TIME 16 /* APHY SIFS time */
+#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */
+#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */
+#define APHY_SIGNAL_TIME 4 /* APHY signal time */
+#define APHY_SYMBOL_TIME 4 /* APHY symbol time */
+#define APHY_SERVICE_NBITS 16 /* APHY service nbits */
+#define APHY_TAIL_NBITS 6 /* APHY tail nbits */
+#define APHY_CWMIN 15 /* APHY cwmin */
+#define APHY_PHYHDR_DUR 20 /* APHY PHY Header Duration */
+
+/* 802.11 B PHY constants */
+#define BPHY_SLOT_TIME 20 /* BPHY slot time */
+#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */
+#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */
+#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */
+#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */
+#define BPHY_CWMIN 31 /* BPHY cwmin */
+#define BPHY_SHORT_PHYHDR_DUR 96 /* BPHY Short PHY Header Duration */
+#define BPHY_LONG_PHYHDR_DUR 192 /* BPHY Long PHY Header Duration */
+
+/* 802.11 G constants */
+#define DOT11_OFDM_SIGNAL_EXTENSION 6 /* d11 OFDM signal extension */
+
+#define PHY_CWMAX 1023 /* PHY cwmax */
+
+#define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */
+
+/* 802.11 VHT constants */
+
+typedef int vht_group_id_t;
+
+/* for VHT-A1 */
+/* SIG-A1 reserved bits */
+#define VHT_SIGA1_CONST_MASK 0x800004
+
+#define VHT_SIGA1_BW_MASK 0x000003
+#define VHT_SIGA1_20MHZ_VAL 0x000000
+#define VHT_SIGA1_40MHZ_VAL 0x000001
+#define VHT_SIGA1_80MHZ_VAL 0x000002
+#define VHT_SIGA1_160MHZ_VAL 0x000003
+
+#define VHT_SIGA1_STBC 0x000008
+
+#define VHT_SIGA1_GID_MASK 0x0003f0
+#define VHT_SIGA1_GID_SHIFT 4
+#define VHT_SIGA1_GID_TO_AP 0x00
+#define VHT_SIGA1_GID_NOT_TO_AP 0x3f
+#define VHT_SIGA1_GID_MAX_GID 0x3f
+
+#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00
+#define VHT_SIGA1_NSTS_SHIFT 10
+#define VHT_SIGA1_MAX_USERPOS 3
+
+#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000
+#define VHT_SIGA1_PARTIAL_AID_SHIFT 13
+
+#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000
+
+/* for VHT-A2 */
+#define VHT_SIGA2_GI_NONE 0x000000
+#define VHT_SIGA2_GI_SHORT 0x000001
+#define VHT_SIGA2_GI_W_MOD10 0x000002
+#define VHT_SIGA2_CODING_LDPC 0x000004
+#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008
+#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100
+#define VHT_SIGA2_MCS_SHIFT 4
+
+#define VHT_SIGA2_B9_RESERVED 0x000200
+#define VHT_SIGA2_TAIL_MASK 0xfc0000
+#define VHT_SIGA2_TAIL_VALUE 0x000000
+
+/* VHT Timing-related parameters (802.11ac D4.0, sec 22.3.6) */
+#define VHT_T_LEG_PREAMBLE 16
+#define VHT_T_L_SIG 4
+#define VHT_T_SIG_A 8
+#define VHT_T_LTF 4
+#define VHT_T_STF 4
+#define VHT_T_SIG_B 4
+#define VHT_T_SYML 4
+
+#define VHT_N_SERVICE 16 /* bits in SERVICE field */
+#define VHT_N_TAIL 6 /* tail bits per BCC encoder */
+
+#define HE_LTF_1_GI_1_6us (0)
+#define HE_LTF_2_GI_0_8us (1)
+#define HE_LTF_2_GI_1_6us (2)
+#define HE_LTF_4_GI_3_2us (3)
+
+/** dot11Counters Table - 802.11 spec., Annex D */
+typedef struct d11cnt {
+ uint32 txfrag; /* dot11TransmittedFragmentCount */
+ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */
+ uint32 txfail; /* dot11FailedCount */
+ uint32 txretry; /* dot11RetryCount */
+ uint32 txretrie; /* dot11MultipleRetryCount */
+ uint32 rxdup; /* dot11FrameduplicateCount */
+ uint32 txrts; /* dot11RTSSuccessCount */
+ uint32 txnocts; /* dot11RTSFailureCount */
+ uint32 txnoack; /* dot11ACKFailureCount */
+ uint32 rxfrag; /* dot11ReceivedFragmentCount */
+ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */
+ uint32 rxcrc; /* dot11FCSErrorCount */
+ uint32 txfrmsnt; /* dot11TransmittedFrameCount */
+ uint32 rxundec; /* dot11WEPUndecryptableCount */
+} d11cnt_t;
+
+#define BRCM_PROP_OUI "\x00\x90\x4C"
+
+
+#define BRCM_FTM_IE_TYPE 14
+
+/* #define HT_CAP_IE_TYPE 51
+ * #define HT_ADD_IE_TYPE 52
+ * #define BRCM_EXTCH_IE_TYPE 53
+ * #define MEMBER_OF_BRCM_PROP_IE_TYPE 54
+ * #define BRCM_RELMACST_IE_TYPE 55
+ * #define BRCM_EVT_WL_BSS_INFO 64
+ * #define RWL_ACTION_WIFI_FRAG_TYPE 85
+ * #define BTC_INFO_BRCM_PROP_IE_TYPE 90
+ * #define ULB_BRCM_PROP_IE_TYPE 91
+ */
+
+/* Action frame type for RWL */
+#define RWL_WIFI_DEFAULT 0
+#define RWL_WIFI_FIND_MY_PEER 9 /* Used while finding server */
+#define RWL_WIFI_FOUND_PEER 10 /* Server response to the client */
+#define RWL_ACTION_WIFI_FRAG_TYPE 85 /* Fragment indicator for receiver */
+
+#define PROXD_AF_TYPE 11 /* Wifi proximity action frame type */
+#define BRCM_RELMACST_AF_TYPE 12 /* RMC action frame type */
+
+/* Action frame type for FTM Initiator Report */
+#define BRCM_FTM_VS_AF_TYPE 14
+enum {
+ BRCM_FTM_VS_INITIATOR_RPT_SUBTYPE = 1, /* FTM Initiator Report */
+ BRCM_FTM_VS_COLLECT_SUBTYPE = 2, /* FTM Collect debug protocol */
+};
+
+
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/*
+ * This BRCM_PROP_OUI types is intended for use in events to embed additional
+ * data, and would not be expected to appear on the air -- but having an IE
+ * format allows IE frame data with extra data in events in that allows for
+ * more flexible parsing.
+ */
+#define BRCM_EVT_WL_BSS_INFO 64
+
+/**
+ * Following is the generic structure for brcm_prop_ie (uses BRCM_PROP_OUI).
+ * DPT uses this format with type set to DPT_IE_TYPE
+ */
+BWL_PRE_PACKED_STRUCT struct brcm_prop_ie_s {
+ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */
+ uint8 len; /* IE length */
+ uint8 oui[3];
+ uint8 type; /* type of this IE */
+ uint16 cap; /* DPT capabilities */
+} BWL_POST_PACKED_STRUCT;
+typedef struct brcm_prop_ie_s brcm_prop_ie_t;
+
+#define BRCM_PROP_IE_LEN 6 /* len of fixed part of brcm_prop ie */
+
+#define DPT_IE_TYPE 2
+
+
+#define BRCM_SYSCAP_IE_TYPE 3
+#define WET_TUNNEL_IE_TYPE 3
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* brcm syscap_ie cap */
+#define BRCM_SYSCAP_WET_TUNNEL 0x0100 /* Device with WET_TUNNEL support */
+
+#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */
+
+/** BRCM info element */
+BWL_PRE_PACKED_STRUCT struct brcm_ie {
+ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */
+ uint8 len; /* IE length */
+ uint8 oui[3];
+ uint8 ver; /* type/ver of this IE */
+ uint8 assoc; /* # of assoc STAs */
+ uint8 flags; /* misc flags */
+ uint8 flags1; /* misc flags */
+ uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */
+} BWL_POST_PACKED_STRUCT;
+typedef struct brcm_ie brcm_ie_t;
+#define BRCM_IE_LEN 11 /* BRCM IE length */
+#define BRCM_IE_VER 2 /* BRCM IE version */
+#define BRCM_IE_LEGACY_AES_VER 1 /* BRCM IE legacy AES version */
+
+/* brcm_ie flags */
+#define BRF_ABCAP 0x1 /* afterburner is obsolete, defined for backward compat */
+#define BRF_ABRQRD 0x2 /* afterburner is obsolete, defined for backward compat */
+#define BRF_LZWDS 0x4 /* lazy wds enabled */
+#define BRF_BLOCKACK 0x8 /* BlockACK capable */
+#define BRF_ABCOUNTER_MASK 0xf0 /* afterburner is obsolete, defined for backward compat */
+#define BRF_PROP_11N_MCS 0x10 /* re-use afterburner bit */
+#define BRF_MEDIA_CLIENT 0x20 /* re-use afterburner bit to indicate media client device */
+
+#define GET_BRF_PROP_11N_MCS(brcm_ie) \
+ (!((brcm_ie)->flags & BRF_ABCAP) && ((brcm_ie)->flags & BRF_PROP_11N_MCS))
+
+/* brcm_ie flags1 */
+#define BRF1_AMSDU 0x1 /* A-MSDU capable */
+#define BRF1_WNM 0x2 /* WNM capable */
+#define BRF1_WMEPS 0x4 /* AP is capable of handling WME + PS w/o APSD */
+#define BRF1_PSOFIX 0x8 /* AP has fixed PS mode out-of-order packets */
+#define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */
+#define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */
+#define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */
+#define BRF1_DWDS 0x80 /* DWDS capable */
+
+/** Vendor IE structure */
+BWL_PRE_PACKED_STRUCT struct vndr_ie {
+ uchar id;
+ uchar len;
+ uchar oui [3];
+ uchar data [1]; /* Variable size data */
+} BWL_POST_PACKED_STRUCT;
+typedef struct vndr_ie vndr_ie_t;
+
+#define VNDR_IE_HDR_LEN 2 /* id + len field */
+#define VNDR_IE_MIN_LEN 3 /* size of the oui field */
+#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN)
+
+#define VNDR_IE_MAX_LEN 255 /* vendor IE max length, without ID and len */
+
+/** BRCM PROP DEVICE PRIMARY MAC ADDRESS IE */
+BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie {
+ uchar id;
+ uchar len;
+ uchar oui[3];
+ uint8 type; /* type indicates what follows */
+ struct ether_addr ea; /* Device Primary MAC Adrress */
+} BWL_POST_PACKED_STRUCT;
+typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t;
+
+#define MEMBER_OF_BRCM_PROP_IE_LEN 10 /* IE max length */
+#define MEMBER_OF_BRCM_PROP_IE_HDRLEN (sizeof(member_of_brcm_prop_ie_t))
+#define MEMBER_OF_BRCM_PROP_IE_TYPE 54
+
+/** BRCM Reliable Multicast IE */
+BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie {
+ uint8 id;
+ uint8 len;
+ uint8 oui[3];
+ uint8 type; /* type indicates what follows */
+ struct ether_addr ea; /* The ack sender's MAC Adrress */
+ struct ether_addr mcast_ea; /* The multicast MAC address */
+ uint8 updtmo; /* time interval(second) for client to send null packet to report its rssi */
+} BWL_POST_PACKED_STRUCT;
+typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t;
+
+/* IE length */
+/* BRCM_PROP_IE_LEN = sizeof(relmcast_brcm_prop_ie_t)-((sizeof (id) + sizeof (len)))? */
+#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-(2*sizeof(uint8)))
+
+#define RELMCAST_BRCM_PROP_IE_TYPE 55
+
+/* BRCM BTC IE */
+BWL_PRE_PACKED_STRUCT struct btc_brcm_prop_ie {
+ uint8 id;
+ uint8 len;
+ uint8 oui[3];
+ uint8 type; /* type inidicates what follows */
+ uint32 info;
+} BWL_POST_PACKED_STRUCT;
+typedef struct btc_brcm_prop_ie btc_brcm_prop_ie_t;
+
+#define BTC_INFO_BRCM_PROP_IE_TYPE 90
+#define BRCM_BTC_INFO_TYPE_LEN (sizeof(btc_brcm_prop_ie_t) - (2 * sizeof(uint8)))
+
+/* ************* HT definitions. ************* */
+#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */
+#define MAX_MCS_NUM (128) /* max mcs number = 128 */
+
+BWL_PRE_PACKED_STRUCT struct ht_cap_ie {
+ uint16 cap;
+ uint8 params;
+ uint8 supp_mcs[MCSSET_LEN];
+ uint16 ext_htcap;
+ uint32 txbf_cap;
+ uint8 as_cap;
+} BWL_POST_PACKED_STRUCT;
+typedef struct ht_cap_ie ht_cap_ie_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie {
+ uint8 id;
+ uint8 len;
+ ht_cap_ie_t ht_cap;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t;
+
+/* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */
+/* the capability IE is primarily used to convey this nodes abilities */
+BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie {
+ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */
+ uint8 len; /* IE length */
+ uint8 oui[3];
+ uint8 type; /* type indicates what follows */
+ ht_cap_ie_t cap_ie;
+} BWL_POST_PACKED_STRUCT;
+typedef struct ht_prop_cap_ie ht_prop_cap_ie_t;
+
+#define HT_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */
+#define HT_CAP_IE_LEN 26 /* HT capability len (based on .11n d2.0) */
+#define HT_CAP_IE_TYPE 51
+
+#define HT_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */
+#define HT_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */
+#define HT_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */
+#define HT_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */
+#define HT_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */
+#define HT_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */
+#define HT_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */
+#define HT_CAP_GF 0x0010 /* Greenfield preamble support */
+#define HT_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */
+#define HT_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */
+#define HT_CAP_TX_STBC 0x0080 /* Tx STBC support */
+#define HT_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */
+#define HT_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */
+#define HT_CAP_DELAYED_BA 0x0400 /* delayed BA support */
+#define HT_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */
+
+#define HT_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */
+#define HT_CAP_PSMP 0x2000 /* Power Save Multi Poll support */
+#define HT_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */
+#define HT_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */
+
+#define HT_CAP_RX_STBC_NO 0x0 /* no rx STBC support */
+#define HT_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */
+#define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */
+#define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */
+
+
+#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1
+#define HT_CAP_TXBF_CAP_NDP_RX 0x8
+#define HT_CAP_TXBF_CAP_NDP_TX 0x10
+#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100
+#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200
+#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400
+#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800
+#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11
+#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000
+#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13
+#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000
+#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15
+#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19
+#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21
+#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23
+#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000
+
+#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27
+#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000
+
+#define HT_CAP_TXBF_FB_TYPE_NONE 0
+#define HT_CAP_TXBF_FB_TYPE_DELAYED 1
+#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2
+#define HT_CAP_TXBF_FB_TYPE_BOTH 3
+
+#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_MASK 0x400
+#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_SHIFT 10
+#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_MASK 0x18000
+#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_SHIFT 15
+
+#define HT_CAP_MCS_FLAGS_SUPP_BYTE 12 /* byte offset in HT Cap Supported MCS for various flags */
+#define HT_CAP_MCS_RX_8TO15_BYTE_OFFSET 1
+#define HT_CAP_MCS_FLAGS_TX_RX_UNEQUAL 0x02
+#define HT_CAP_MCS_FLAGS_MAX_SPATIAL_STREAM_MASK 0x0C
+
+#define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */
+#define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */
+/* Max AMSDU len - per spec */
+#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA)
+
+#define HT_MAX_AMSDU 7935 /* max amsdu size (bytes) per the HT spec */
+#define HT_MIN_AMSDU 3835 /* min amsdu size (bytes) per the HT spec */
+
+#define HT_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */
+#define HT_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */
+#define HT_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */
+
+/* HT/AMPDU specific define */
+#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/4 usec units */
+#define AMPDU_DENSITY_NONE 0 /* No density requirement */
+#define AMPDU_DENSITY_1over4_US 1 /* 1/4 us density */
+#define AMPDU_DENSITY_1over2_US 2 /* 1/2 us density */
+#define AMPDU_DENSITY_1_US 3 /* 1 us density */
+#define AMPDU_DENSITY_2_US 4 /* 2 us density */
+#define AMPDU_DENSITY_4_US 5 /* 4 us density */
+#define AMPDU_DENSITY_8_US 6 /* 8 us density */
+#define AMPDU_DENSITY_16_US 7 /* 16 us density */
+#define AMPDU_RX_FACTOR_8K 0 /* max rcv ampdu len (8kb) */
+#define AMPDU_RX_FACTOR_16K 1 /* max rcv ampdu len (16kb) */
+#define AMPDU_RX_FACTOR_32K 2 /* max rcv ampdu len (32kb) */
+#define AMPDU_RX_FACTOR_64K 3 /* max rcv ampdu len (64kb) */
+
+/* AMPDU RX factors for VHT rates */
+#define AMPDU_RX_FACTOR_128K 4 /* max rcv ampdu len (128kb) */
+#define AMPDU_RX_FACTOR_256K 5 /* max rcv ampdu len (256kb) */
+#define AMPDU_RX_FACTOR_512K 6 /* max rcv ampdu len (512kb) */
+#define AMPDU_RX_FACTOR_1024K 7 /* max rcv ampdu len (1024kb) */
+
+#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */
+#define AMPDU_RX_FACTOR_BASE_PWR 13 /* ampdu factor base for rx len in power of 2 */
+
+#define AMPDU_DELIMITER_LEN 4 /* length of ampdu delimiter */
+#define AMPDU_DELIMITER_LEN_MAX 63 /* max length of ampdu delimiter(enforced in HW) */
+
+#define HT_CAP_EXT_PCO 0x0001
+#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006
+#define HT_CAP_EXT_PCO_TTIME_SHIFT 1
+#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300
+#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8
+#define HT_CAP_EXT_HTC 0x0400
+#define HT_CAP_EXT_RD_RESP 0x0800
+
+/** 'ht_add' is called 'HT Operation' information element in the 802.11 standard */
+BWL_PRE_PACKED_STRUCT struct ht_add_ie {
+ uint8 ctl_ch; /* control channel number */
+ uint8 byte1; /* ext ch,rec. ch. width, RIFS support */
+ uint16 opmode; /* operation mode */
+ uint16 misc_bits; /* misc bits */
+ uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */
+} BWL_POST_PACKED_STRUCT;
+typedef struct ht_add_ie ht_add_ie_t;
+
+/* ADD IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */
+/* the additional IE is primarily used to convey the current BSS configuration */
+BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie {
+ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */
+ uint8 len; /* IE length */
+ uint8 oui[3];
+ uint8 type; /* indicates what follows */
+ ht_add_ie_t add_ie;
+} BWL_POST_PACKED_STRUCT;
+typedef struct ht_prop_add_ie ht_prop_add_ie_t;
+
+#define HT_ADD_IE_LEN 22
+#define HT_ADD_IE_TYPE 52
+
+/* byte1 defn's */
+#define HT_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */
+#define HT_RIFS_PERMITTED 0x08 /* RIFS allowed */
+
+/* opmode defn's */
+#define HT_OPMODE_MASK 0x0003 /* protection mode mask */
+#define HT_OPMODE_SHIFT 0 /* protection mode shift */
+#define HT_OPMODE_PURE 0x0000 /* protection mode PURE */
+#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */
+#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */
+#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */
+#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */
+#define DOT11N_TXBURST 0x0008 /* Tx burst limit */
+#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */
+
+/* misc_bites defn's */
+#define HT_BASIC_STBC_MCS 0x007f /* basic STBC MCS */
+#define HT_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */
+#define HT_SECOND_BCN 0x0100 /* Secondary beacon support */
+#define HT_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */
+#define HT_PCO_ACTIVE 0x0400 /* PCO active */
+#define HT_PCO_PHASE 0x0800 /* PCO phase */
+#define HT_DUALCTS_PROTECTION 0x0080 /* DUAL CTS protection needed */
+
+/* Tx Burst Limits */
+#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */
+#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */
+
+/* Macros for opmode */
+#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
+ >> HT_OPMODE_SHIFT)
+#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
+ == HT_OPMODE_MIXED) /* mixed mode present */
+#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
+ == HT_OPMODE_HT20IN40) /* 20MHz HT present */
+#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
+ == HT_OPMODE_OPTIONAL) /* Optional protection present */
+#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \
+ HT_MIXEDMODE_PRESENT((add_ie))) /* use protection */
+#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \
+ == HT_OPMODE_NONGF) /* non-GF present */
+#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \
+ == DOT11N_TXBURST) /* Tx Burst present */
+#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \
+ == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */
+/* Macros for HT MCS filed access */
+#define HT_CAP_MCS_BITMASK(supp_mcs) \
+ ((supp_mcs)[HT_CAP_MCS_RX_8TO15_BYTE_OFFSET])
+#define HT_CAP_MCS_TX_RX_UNEQUAL(supp_mcs) \
+ ((supp_mcs)[HT_CAP_MCS_FLAGS_SUPP_BYTE] & HT_CAP_MCS_FLAGS_TX_RX_UNEQUAL)
+#define HT_CAP_MCS_TX_STREAM_SUPPORT(supp_mcs) \
+ ((supp_mcs)[HT_CAP_MCS_FLAGS_SUPP_BYTE] & HT_CAP_MCS_FLAGS_MAX_SPATIAL_STREAM_MASK)
+
+BWL_PRE_PACKED_STRUCT struct obss_params {
+ uint16 passive_dwell;
+ uint16 active_dwell;
+ uint16 bss_widthscan_interval;
+ uint16 passive_total;
+ uint16 active_total;
+ uint16 chanwidth_transition_dly;
+ uint16 activity_threshold;
+} BWL_POST_PACKED_STRUCT;
+typedef struct obss_params obss_params_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_obss_ie {
+ uint8 id;
+ uint8 len;
+ obss_params_t obss_params;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_obss_ie dot11_obss_ie_t;
+#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) /* HT OBSS len (based on 802.11n d3.0) */
+
+/* HT control field */
+#define HT_CTRL_LA_TRQ 0x00000002 /* sounding request */
+#define HT_CTRL_LA_MAI 0x0000003C /* MCS request or antenna selection indication */
+#define HT_CTRL_LA_MAI_SHIFT 2
+#define HT_CTRL_LA_MAI_MRQ 0x00000004 /* MCS request */
+#define HT_CTRL_LA_MAI_MSI 0x00000038 /* MCS request sequence identifier */
+#define HT_CTRL_LA_MFSI 0x000001C0 /* MFB sequence identifier */
+#define HT_CTRL_LA_MFSI_SHIFT 6
+#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 /* MCS feedback, antenna selection command/data */
+#define HT_CTRL_LA_MFB_ASELC_SH 9
+#define HT_CTRL_LA_ASELC_CMD 0x00000C00 /* ASEL command */
+#define HT_CTRL_LA_ASELC_DATA 0x0000F000 /* ASEL data */
+#define HT_CTRL_CAL_POS 0x00030000 /* Calibration position */
+#define HT_CTRL_CAL_SEQ 0x000C0000 /* Calibration sequence */
+#define HT_CTRL_CSI_STEERING 0x00C00000 /* CSI/Steering */
+#define HT_CTRL_CSI_STEER_SHIFT 22
+#define HT_CTRL_CSI_STEER_NFB 0 /* no fedback required */
+#define HT_CTRL_CSI_STEER_CSI 1 /* CSI, H matrix */
+#define HT_CTRL_CSI_STEER_NCOM 2 /* non-compressed beamforming */
+#define HT_CTRL_CSI_STEER_COM 3 /* compressed beamforming */
+#define HT_CTRL_NDP_ANNOUNCE 0x01000000 /* NDP announcement */
+#define HT_CTRL_AC_CONSTRAINT 0x40000000 /* AC Constraint */
+#define HT_CTRL_RDG_MOREPPDU 0x80000000 /* RDG/More PPDU */
+
+/* ************* VHT definitions. ************* */
+
+/**
+ * VHT Capabilites IE (sec 8.4.2.160)
+ */
+
+BWL_PRE_PACKED_STRUCT struct vht_cap_ie {
+ uint32 vht_cap_info;
+ /* supported MCS set - 64 bit field */
+ uint16 rx_mcs_map;
+ uint16 rx_max_rate;
+ uint16 tx_mcs_map;
+ uint16 tx_max_rate;
+} BWL_POST_PACKED_STRUCT;
+typedef struct vht_cap_ie vht_cap_ie_t;
+
+/* 4B cap_info + 8B supp_mcs */
+#define VHT_CAP_IE_LEN 12
+
+/* VHT Capabilities Info field - 32bit - in VHT Cap IE */
+#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003
+#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c
+#define VHT_CAP_INFO_LDPC 0x00000010
+#define VHT_CAP_INFO_SGI_80MHZ 0x00000020
+#define VHT_CAP_INFO_SGI_160MHZ 0x00000040
+#define VHT_CAP_INFO_TX_STBC 0x00000080
+#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700
+#define VHT_CAP_INFO_RX_STBC_SHIFT 8
+#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800
+#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000
+#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000
+#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13
+#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000
+#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16
+#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000
+#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000
+#define VHT_CAP_INFO_TXOPPS 0x00200000
+#define VHT_CAP_INFO_HTCVHT 0x00400000
+#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000
+#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23
+#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000
+#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26
+
+/* VHT Supported MCS Set - 64-bit - in VHT Cap IE */
+#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff
+#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0
+#define VHT_CAP_SUPP_CHAN_WIDTH_SHIFT 5
+
+#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff
+#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0
+
+#define VHT_CAP_MCS_MAP_0_7 0
+#define VHT_CAP_MCS_MAP_0_8 1
+#define VHT_CAP_MCS_MAP_0_9 2
+#define VHT_CAP_MCS_MAP_NONE 3
+#define VHT_CAP_MCS_MAP_S 2 /* num bits for 1-stream */
+#define VHT_CAP_MCS_MAP_M 0x3 /* mask for 1-stream */
+/* assumes VHT_CAP_MCS_MAP_NONE is 3 and 2 bits are used for encoding */
+#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff
+
+/* VHT rates bitmap */
+#define VHT_CAP_MCS_0_7_RATEMAP 0x00ff
+#define VHT_CAP_MCS_0_8_RATEMAP 0x01ff
+#define VHT_CAP_MCS_0_9_RATEMAP 0x03ff
+#define VHT_CAP_MCS_FULL_RATEMAP VHT_CAP_MCS_0_9_RATEMAP
+
+#define VHT_PROP_MCS_MAP_10_11 0
+#define VHT_PROP_MCS_MAP_UNUSED1 1
+#define VHT_PROP_MCS_MAP_UNUSED2 2
+#define VHT_PROP_MCS_MAP_NONE 3
+#define VHT_PROP_MCS_MAP_NONE_ALL 0xffff
+
+/* VHT prop rates bitmap */
+#define VHT_PROP_MCS_10_11_RATEMAP 0x0c00
+#define VHT_PROP_MCS_FULL_RATEMAP VHT_PROP_MCS_10_11_RATEMAP
+
+#if !defined(VHT_CAP_MCS_MAP_0_9_NSS3)
+/* mcsmap with MCS0-9 for Nss = 3 */
+#define VHT_CAP_MCS_MAP_0_9_NSS3 \
+ ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \
+ (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \
+ (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3)))
+#endif /* !VHT_CAP_MCS_MAP_0_9_NSS3 */
+
+#define VHT_CAP_MCS_MAP_NSS_MAX 8
+
+/* get mcsmap with given mcs for given nss streams */
+#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \
+ do { \
+ int i; \
+ for (i = 1; i <= nss; i++) { \
+ VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \
+ } \
+ } while (0)
+
+/* Map the mcs code to mcs bit map */
+#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \
+ ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? VHT_CAP_MCS_0_7_RATEMAP : \
+ (mcs_code == VHT_CAP_MCS_MAP_0_8) ? VHT_CAP_MCS_0_8_RATEMAP : \
+ (mcs_code == VHT_CAP_MCS_MAP_0_9) ? VHT_CAP_MCS_0_9_RATEMAP : 0)
+
+#define VHT_PROP_MCS_CODE_TO_PROP_MCS_MAP(mcs_code) \
+ ((mcs_code == VHT_PROP_MCS_MAP_10_11) ? VHT_PROP_MCS_10_11_RATEMAP : 0)
+
+/* Map the mcs bit map to mcs code */
+#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \
+ ((mcs_map == VHT_CAP_MCS_0_7_RATEMAP) ? VHT_CAP_MCS_MAP_0_7 : \
+ (mcs_map == VHT_CAP_MCS_0_8_RATEMAP) ? VHT_CAP_MCS_MAP_0_8 : \
+ (mcs_map == VHT_CAP_MCS_0_9_RATEMAP) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE)
+
+#define VHT_PROP_MCS_MAP_TO_PROP_MCS_CODE(mcs_map) \
+ (((mcs_map & 0xc00) == 0xc00) ? VHT_PROP_MCS_MAP_10_11 : VHT_PROP_MCS_MAP_NONE)
+
+/** VHT Capabilities Supported Channel Width */
+typedef enum vht_cap_chan_width {
+ VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00,
+ VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04,
+ VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08
+} vht_cap_chan_width_t;
+
+/** VHT Capabilities Supported max MPDU LEN (sec 8.4.2.160.2) */
+typedef enum vht_cap_max_mpdu_len {
+ VHT_CAP_MPDU_MAX_4K = 0x00,
+ VHT_CAP_MPDU_MAX_8K = 0x01,
+ VHT_CAP_MPDU_MAX_11K = 0x02
+} vht_cap_max_mpdu_len_t;
+
+/* Maximum MPDU Length byte counts for the VHT Capabilities advertised limits */
+#define VHT_MPDU_LIMIT_4K 3895
+#define VHT_MPDU_LIMIT_8K 7991
+#define VHT_MPDU_LIMIT_11K 11454
+
+
+/**
+ * VHT Operation IE (sec 8.4.2.161)
+ */
+
+BWL_PRE_PACKED_STRUCT struct vht_op_ie {
+ uint8 chan_width;
+ uint8 chan1;
+ uint8 chan2;
+ uint16 supp_mcs; /* same def as above in vht cap */
+} BWL_POST_PACKED_STRUCT;
+typedef struct vht_op_ie vht_op_ie_t;
+
+/* 3B VHT Op info + 2B Basic MCS */
+#define VHT_OP_IE_LEN 5
+
+typedef enum vht_op_chan_width {
+ VHT_OP_CHAN_WIDTH_20_40 = 0,
+ VHT_OP_CHAN_WIDTH_80 = 1,
+ VHT_OP_CHAN_WIDTH_160 = 2,
+ VHT_OP_CHAN_WIDTH_80_80 = 3
+} vht_op_chan_width_t;
+
+/* AID length */
+#define AID_IE_LEN 2
+/**
+ * BRCM vht features IE header
+ * The header if the fixed part of the IE
+ * On the 5GHz band this is the entire IE,
+ * on 2.4GHz the VHT IEs as defined in the 802.11ac
+ * specification follows
+ *
+ *
+ * VHT features rates bitmap.
+ * Bit0: 5G MCS 0-9 BW 160MHz
+ * Bit1: 5G MCS 0-9 support BW 80MHz
+ * Bit2: 5G MCS 0-9 support BW 20MHz
+ * Bit3: 2.4G MCS 0-9 support BW 20MHz
+ * Bits:4-7 Reserved for future use
+ *
+ */
+#define VHT_FEATURES_IE_TYPE 0x4
+BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr {
+ uint8 oui[3];
+ uint8 type; /* type of this IE = 4 */
+ uint8 rate_mask; /* VHT rate mask */
+} BWL_POST_PACKED_STRUCT;
+typedef struct vht_features_ie_hdr vht_features_ie_hdr_t;
+
+/* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */
+#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S)
+#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \
+ (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M)
+#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \
+ do { \
+ (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \
+ (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \
+ } while (0)
+#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \
+ (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE)
+
+/* Get the max ss supported from the mcs map */
+#define VHT_MAX_SS_SUPPORTED(mcsMap) \
+ VHT_MCS_SS_SUPPORTED(8, mcsMap) ? 8 : \
+ VHT_MCS_SS_SUPPORTED(7, mcsMap) ? 7 : \
+ VHT_MCS_SS_SUPPORTED(6, mcsMap) ? 6 : \
+ VHT_MCS_SS_SUPPORTED(5, mcsMap) ? 5 : \
+ VHT_MCS_SS_SUPPORTED(4, mcsMap) ? 4 : \
+ VHT_MCS_SS_SUPPORTED(3, mcsMap) ? 3 : \
+ VHT_MCS_SS_SUPPORTED(2, mcsMap) ? 2 : \
+ VHT_MCS_SS_SUPPORTED(1, mcsMap) ? 1 : 0
+
+/* ************* WPA definitions. ************* */
+#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
+#define WPA_OUI_LEN 3 /* WPA OUI length */
+#define WPA_OUI_TYPE 1
+#define WPA_VERSION 1 /* WPA version */
+#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */
+#define WPA2_OUI_LEN 3 /* WPA2 OUI length */
+#define WPA2_VERSION 1 /* WPA2 version */
+#define WPA2_VERSION_LEN 2 /* WAP2 version length */
+
+/* ************* WPS definitions. ************* */
+#define WPS_OUI "\x00\x50\xF2" /* WPS OUI */
+#define WPS_OUI_LEN 3 /* WPS OUI length */
+#define WPS_OUI_TYPE 4
+
+/* ************* WFA definitions. ************* */
+
+#ifdef P2P_IE_OVRD
+#define WFA_OUI MAC_OUI
+#else
+#define WFA_OUI "\x50\x6F\x9A" /* WFA OUI */
+#endif /* P2P_IE_OVRD */
+#define WFA_OUI_LEN 3 /* WFA OUI length */
+#ifdef P2P_IE_OVRD
+#define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P
+#else
+#define WFA_OUI_TYPE_TPC 8
+#define WFA_OUI_TYPE_P2P 9
+#endif
+
+#define WFA_OUI_TYPE_TPC 8
+#ifdef WLTDLS
+#define WFA_OUI_TYPE_TPQ 4 /* WFD Tunneled Probe ReQuest */
+#define WFA_OUI_TYPE_TPS 5 /* WFD Tunneled Probe ReSponse */
+#define WFA_OUI_TYPE_WFD 10
+#endif /* WTDLS */
+#define WFA_OUI_TYPE_HS20 0x10
+#define WFA_OUI_TYPE_OSEN 0x12
+#define WFA_OUI_TYPE_NAN 0x13
+#define WFA_OUI_TYPE_MBO 0x16
+#define WFA_OUI_TYPE_MBO_OCE 0x16
+
+/* RSN authenticated key managment suite */
+#define RSN_AKM_NONE 0 /* None (IBSS) */
+#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
+#define RSN_AKM_PSK 2 /* Pre-shared Key */
+#define RSN_AKM_FBT_1X 3 /* Fast Bss transition using 802.1X */
+#define RSN_AKM_FBT_PSK 4 /* Fast Bss transition using Pre-shared Key */
+/* RSN_AKM_MFP_1X and RSN_AKM_MFP_PSK are not used any more
+ * Just kept here to avoid build issue in BISON/CARIBOU branch
+ */
+#define RSN_AKM_MFP_1X 5 /* SHA256 key derivation, using 802.1X */
+#define RSN_AKM_MFP_PSK 6 /* SHA256 key derivation, using Pre-shared Key */
+#define RSN_AKM_SHA256_1X 5 /* SHA256 key derivation, using 802.1X */
+#define RSN_AKM_SHA256_PSK 6 /* SHA256 key derivation, using Pre-shared Key */
+#define RSN_AKM_TPK 7 /* TPK(TDLS Peer Key) handshake */
+
+/* OSEN authenticated key managment suite */
+#define OSEN_AKM_UNSPECIFIED RSN_AKM_UNSPECIFIED /* Over 802.1x */
+
+/* Key related defines */
+#define DOT11_MAX_DEFAULT_KEYS 4 /* number of default keys */
+#define DOT11_MAX_IGTK_KEYS 2
+#define DOT11_MAX_KEY_SIZE 32 /* max size of any key */
+#define DOT11_MAX_IV_SIZE 16 /* max size of any IV */
+#define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */
+#define DOT11_WPA_KEY_RSC_LEN 8 /* WPA RSC key len */
+
+#define WEP1_KEY_SIZE 5 /* max size of any WEP key */
+#define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */
+#define WEP128_KEY_SIZE 13 /* max size of any WEP key */
+#define WEP128_KEY_HEX_SIZE 26 /* size of WEP key in hex. */
+#define TKIP_MIC_SIZE 8 /* size of TKIP MIC */
+#define TKIP_EOM_SIZE 7 /* max size of TKIP EOM */
+#define TKIP_EOM_FLAG 0x5a /* TKIP EOM flag byte */
+#define TKIP_KEY_SIZE 32 /* size of any TKIP key, includs MIC keys */
+#define TKIP_TK_SIZE 16
+#define TKIP_MIC_KEY_SIZE 8
+#define TKIP_MIC_AUTH_TX 16 /* offset to Authenticator MIC TX key */
+#define TKIP_MIC_AUTH_RX 24 /* offset to Authenticator MIC RX key */
+#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX /* offset to Supplicant MIC RX key */
+#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX /* offset to Supplicant MIC TX key */
+#define AES_KEY_SIZE 16 /* size of AES key */
+#define AES_MIC_SIZE 8 /* size of AES MIC */
+#define BIP_KEY_SIZE 16 /* size of BIP key */
+#define BIP_MIC_SIZE 8 /* sizeof BIP MIC */
+
+#define AES_GCM_MIC_SIZE 16 /* size of MIC for 128-bit GCM - .11adD9 */
+
+#define AES256_KEY_SIZE 32 /* size of AES 256 key - .11acD5 */
+#define AES256_MIC_SIZE 16 /* size of MIC for 256 bit keys, incl BIP */
+
+/* WCN */
+#define WCN_OUI "\x00\x50\xf2" /* WCN OUI */
+#define WCN_TYPE 4 /* WCN type */
+
+
+/* 802.11r protocol definitions */
+
+/** Mobility Domain IE */
+BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie {
+ uint8 id;
+ uint8 len;
+ uint16 mdid; /* Mobility Domain Id */
+ uint8 cap;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_mdid_ie dot11_mdid_ie_t;
+
+#define FBT_MDID_CAP_OVERDS 0x01 /* Fast Bss transition over the DS support */
+#define FBT_MDID_CAP_RRP 0x02 /* Resource request protocol support */
+
+/** Fast Bss Transition IE */
+BWL_PRE_PACKED_STRUCT struct dot11_ft_ie {
+ uint8 id;
+ uint8 len;
+ uint16 mic_control; /* Mic Control */
+ uint8 mic[16];
+ uint8 anonce[32];
+ uint8 snonce[32];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ft_ie dot11_ft_ie_t;
+
+#define TIE_TYPE_RESERVED 0
+#define TIE_TYPE_REASSOC_DEADLINE 1
+#define TIE_TYPE_KEY_LIEFTIME 2
+#define TIE_TYPE_ASSOC_COMEBACK 3
+BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie {
+ uint8 id;
+ uint8 len;
+ uint8 type; /* timeout interval type */
+ uint32 value; /* timeout interval value */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_timeout_ie dot11_timeout_ie_t;
+
+/** GTK ie */
+BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie {
+ uint8 id;
+ uint8 len;
+ uint16 key_info;
+ uint8 key_len;
+ uint8 rsc[8];
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_gtk_ie dot11_gtk_ie_t;
+
+/** Management MIC ie */
+BWL_PRE_PACKED_STRUCT struct mmic_ie {
+ uint8 id; /* IE ID: DOT11_MNG_MMIE_ID */
+ uint8 len; /* IE length */
+ uint16 key_id; /* key id */
+ uint8 ipn[6]; /* ipn */
+ uint8 mic[16]; /* mic */
+} BWL_POST_PACKED_STRUCT;
+typedef struct mmic_ie mmic_ie_t;
+
+/* 802.11r-2008, 11A.10.3 - RRB frame format */
+BWL_PRE_PACKED_STRUCT struct dot11_ft_rrb_frame {
+ uint8 frame_type; /* 1 for RRB */
+ uint8 packet_type; /* 0 for Request 1 for Response */
+ uint16 len;
+ uint8 cur_ap_addr[ETHER_ADDR_LEN];
+ uint8 data[1]; /* IEs Received/Sent in FT Action Req/Resp Frame */
+} BWL_POST_PACKED_STRUCT;
+
+typedef struct dot11_ft_rrb_frame dot11_ft_rrb_frame_t;
+
+#define DOT11_FT_RRB_FIXED_LEN 10
+#define DOT11_FT_REMOTE_FRAME_TYPE 1
+#define DOT11_FT_PACKET_REQ 0
+#define DOT11_FT_PACKET_RESP 1
+
+#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00"
+#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF"
+
+#ifdef BCMWAPI_WAI
+#define WAPI_IE_MIN_LEN 20 /* WAPI IE min length */
+#define WAPI_VERSION 1 /* WAPI version */
+#define WAPI_VERSION_LEN 2 /* WAPI version length */
+#define WAPI_OUI "\x00\x14\x72" /* WAPI OUI */
+#define WAPI_OUI_LEN DOT11_OUI_LEN /* WAPI OUI length */
+#endif /* BCMWAPI_WAI */
+
+/* ************* WMM Parameter definitions. ************* */
+#define WMM_OUI "\x00\x50\xF2" /* WNN OUI */
+#define WMM_OUI_LEN 3 /* WMM OUI length */
+#define WMM_OUI_TYPE 2 /* WMM OUT type */
+#define WMM_VERSION 1
+#define WMM_VERSION_LEN 1
+
+/* WMM OUI subtype */
+#define WMM_OUI_SUBTYPE_PARAMETER 1
+#define WMM_PARAMETER_IE_LEN 24
+
+/** Link Identifier Element */
+BWL_PRE_PACKED_STRUCT struct link_id_ie {
+ uint8 id;
+ uint8 len;
+ struct ether_addr bssid;
+ struct ether_addr tdls_init_mac;
+ struct ether_addr tdls_resp_mac;
+} BWL_POST_PACKED_STRUCT;
+typedef struct link_id_ie link_id_ie_t;
+#define TDLS_LINK_ID_IE_LEN 18
+
+/** Link Wakeup Schedule Element */
+BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie {
+ uint8 id;
+ uint8 len;
+ uint32 offset; /* in ms between TSF0 and start of 1st Awake Window */
+ uint32 interval; /* in ms bwtween the start of 2 Awake Windows */
+ uint32 awake_win_slots; /* in backof slots, duration of Awake Window */
+ uint32 max_wake_win; /* in ms, max duration of Awake Window */
+ uint16 idle_cnt; /* number of consecutive Awake Windows */
+} BWL_POST_PACKED_STRUCT;
+typedef struct wakeup_sch_ie wakeup_sch_ie_t;
+#define TDLS_WAKEUP_SCH_IE_LEN 18
+
+/** Channel Switch Timing Element */
+BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie {
+ uint8 id;
+ uint8 len;
+ uint16 switch_time; /* in ms, time to switch channels */
+ uint16 switch_timeout; /* in ms */
+} BWL_POST_PACKED_STRUCT;
+typedef struct channel_switch_timing_ie channel_switch_timing_ie_t;
+#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4
+
+/** PTI Control Element */
+BWL_PRE_PACKED_STRUCT struct pti_control_ie {
+ uint8 id;
+ uint8 len;
+ uint8 tid;
+ uint16 seq_control;
+} BWL_POST_PACKED_STRUCT;
+typedef struct pti_control_ie pti_control_ie_t;
+#define TDLS_PTI_CONTROL_IE_LEN 3
+
+/** PU Buffer Status Element */
+BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie {
+ uint8 id;
+ uint8 len;
+ uint8 status;
+} BWL_POST_PACKED_STRUCT;
+typedef struct pu_buffer_status_ie pu_buffer_status_ie_t;
+#define TDLS_PU_BUFFER_STATUS_IE_LEN 1
+#define TDLS_PU_BUFFER_STATUS_AC_BK 1
+#define TDLS_PU_BUFFER_STATUS_AC_BE 2
+#define TDLS_PU_BUFFER_STATUS_AC_VI 4
+#define TDLS_PU_BUFFER_STATUS_AC_VO 8
+
+/* TDLS Action Field Values */
+#define TDLS_SETUP_REQ 0
+#define TDLS_SETUP_RESP 1
+#define TDLS_SETUP_CONFIRM 2
+#define TDLS_TEARDOWN 3
+#define TDLS_PEER_TRAFFIC_IND 4
+#define TDLS_CHANNEL_SWITCH_REQ 5
+#define TDLS_CHANNEL_SWITCH_RESP 6
+#define TDLS_PEER_PSM_REQ 7
+#define TDLS_PEER_PSM_RESP 8
+#define TDLS_PEER_TRAFFIC_RESP 9
+#define TDLS_DISCOVERY_REQ 10
+
+/* 802.11z TDLS Public Action Frame action field */
+#define TDLS_DISCOVERY_RESP 14
+
+/* 802.11u GAS action frames */
+#define GAS_REQUEST_ACTION_FRAME 10
+#define GAS_RESPONSE_ACTION_FRAME 11
+#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12
+#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13
+
+/* FTM - fine timing measurement public action frames */
+BWL_PRE_PACKED_STRUCT struct dot11_ftm_req {
+ uint8 category; /* category of action frame (4) */
+ uint8 action; /* public action (32) */
+ uint8 trigger; /* trigger/continue? */
+ /* optional lci, civic loc, ftm params */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ftm_req dot11_ftm_req_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_ftm {
+ uint8 category; /* category of action frame (4) */
+ uint8 action; /* public action (33) */
+ uint8 dialog; /* dialog token */
+ uint8 follow_up; /* follow up dialog token */
+ uint8 tod[6]; /* t1 - last depart timestamp */
+ uint8 toa[6]; /* t4 - last ack arrival timestamp */
+ uint8 tod_err[2]; /* t1 error */
+ uint8 toa_err[2]; /* t4 error */
+ /* optional lci report, civic loc report, ftm params */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ftm dot11_ftm_t;
+
+
+#define DOT11_FTM_ERR_NOT_CONT_OFFSET 1
+#define DOT11_FTM_ERR_NOT_CONT_MASK 0x80
+#define DOT11_FTM_ERR_NOT_CONT_SHIFT 7
+#define DOT11_FTM_ERR_NOT_CONT(_err) (((_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] & \
+ DOT11_FTM_ERR_NOT_CONT_MASK) >> DOT11_FTM_ERR_NOT_CONT_SHIFT)
+#define DOT11_FTM_ERR_SET_NOT_CONT(_err, _val) do {\
+ uint8 _err2 = (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET]; \
+ _err2 &= ~DOT11_FTM_ERR_NOT_CONT_MASK; \
+ _err2 |= ((_val) << DOT11_FTM_ERR_NOT_CONT_SHIFT) & DOT11_FTM_ERR_NOT_CONT_MASK; \
+ (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] = _err2; \
+} while (0)
+
+#define DOT11_FTM_ERR_MAX_ERR_OFFSET 0
+#define DOT11_FTM_ERR_MAX_ERR_MASK 0x7fff
+#define DOT11_FTM_ERR_MAX_ERR_SHIFT 0
+#define DOT11_FTM_ERR_MAX_ERR(_err) (((((_err)[1] & 0x7f) << 8) | (_err)[0]))
+#define DOT11_FTM_ERR_SET_MAX_ERR(_err, _val) do {\
+ uint16 _val2; \
+ uint16 _not_cont; \
+ _val2 = (((_val) & DOT11_FTM_ERR_MAX_ERR_MASK) << DOT11_FTM_ERR_MAX_ERR_SHIFT); \
+ _val2 = (_val2 > 0x3fff) ? 0 : _val2; /* not expecting > 16ns error */ \
+ _not_cont = DOT11_FTM_ERR_NOT_CONT(_err); \
+ (_err)[0] = _val2 & 0xff; \
+ (_err)[1] = (_val2 >> 8) & 0xff; \
+ DOT11_FTM_ERR_SET_NOT_CONT(_err, _not_cont); \
+} while (0)
+
+#if defined(DOT11_FTM_ERR_ROM_COMPAT)
+/* incorrect defs - here for ROM compatibiity */
+#undef DOT11_FTM_ERR_NOT_CONT_OFFSET
+#undef DOT11_FTM_ERR_NOT_CONT_MASK
+#undef DOT11_FTM_ERR_NOT_CONT_SHIFT
+#undef DOT11_FTM_ERR_NOT_CONT
+#undef DOT11_FTM_ERR_SET_NOT_CONT
+
+#define DOT11_FTM_ERR_NOT_CONT_OFFSET 0
+#define DOT11_FTM_ERR_NOT_CONT_MASK 0x0001
+#define DOT11_FTM_ERR_NOT_CONT_SHIFT 0
+#define DOT11_FTM_ERR_NOT_CONT(_err) (((_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] & \
+ DOT11_FTM_ERR_NOT_CONT_MASK) >> DOT11_FTM_ERR_NOT_CONT_SHIFT)
+#define DOT11_FTM_ERR_SET_NOT_CONT(_err, _val) do {\
+ uint8 _err2 = (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET]; \
+ _err2 &= ~DOT11_FTM_ERR_NOT_CONT_MASK; \
+ _err2 |= ((_val) << DOT11_FTM_ERR_NOT_CONT_SHIFT) & DOT11_FTM_ERR_NOT_CONT_MASK; \
+ (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] = _err2; \
+} while (0)
+
+#undef DOT11_FTM_ERR_MAX_ERR_OFFSET
+#undef DOT11_FTM_ERR_MAX_ERR_MASK
+#undef DOT11_FTM_ERR_MAX_ERR_SHIFT
+#undef DOT11_FTM_ERR_MAX_ERR
+#undef DOT11_FTM_ERR_SET_MAX_ERR
+
+#define DOT11_FTM_ERR_MAX_ERR_OFFSET 0
+#define DOT11_FTM_ERR_MAX_ERR_MASK 0xfff7
+#define DOT11_FTM_ERR_MAX_ERR_SHIFT 1
+#define DOT11_FTM_ERR_MAX_ERR(_err) ((((_err)[1] << 7) | (_err)[0]) >> 1)
+#define DOT11_FTM_ERR_SET_MAX_ERR(_err, _val) do {\
+ uint16 _val2; \
+ _val2 = (((_val) << DOT11_FTM_ERR_MAX_ERR_SHIFT) |\
+ ((_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] & DOT11_FTM_ERR_NOT_CONT_MASK)); \
+ (_err)[0] = _val2 & 0xff; \
+ (_err)[1] = _val2 >> 8 & 0xff; \
+} while (0)
+#endif /* DOT11_FTM_ERR_ROM_COMPAT */
+
+BWL_PRE_PACKED_STRUCT struct dot11_ftm_params {
+ uint8 id; /* DOT11_MNG_FTM_PARAM_ID 8.4.2.166 11mcd2.6/2014 - revisit */
+ uint8 len;
+ uint8 info[9];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ftm_params dot11_ftm_params_t;
+#define DOT11_FTM_PARAMS_IE_LEN (sizeof(dot11_ftm_params_t) - 2)
+
+#define FTM_PARAMS_FIELD(_p, _off, _mask, _shift) (((_p)->info[(_off)] & (_mask)) >> (_shift))
+#define FTM_PARAMS_SET_FIELD(_p, _off, _mask, _shift, _val) do {\
+ uint8 _ptmp = (_p)->info[_off] & ~(_mask); \
+ (_p)->info[(_off)] = _ptmp | (((_val) << (_shift)) & (_mask)); \
+} while (0)
+
+#define FTM_PARAMS_STATUS_OFFSET 0
+#define FTM_PARAMS_STATUS_MASK 0x03
+#define FTM_PARAMS_STATUS_SHIFT 0
+#define FTM_PARAMS_STATUS(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_STATUS_OFFSET, \
+ FTM_PARAMS_STATUS_MASK, FTM_PARAMS_STATUS_SHIFT)
+#define FTM_PARAMS_SET_STATUS(_p, _status) FTM_PARAMS_SET_FIELD(_p, \
+ FTM_PARAMS_STATUS_OFFSET, FTM_PARAMS_STATUS_MASK, FTM_PARAMS_STATUS_SHIFT, _status)
+
+#define FTM_PARAMS_VALUE_OFFSET 0
+#define FTM_PARAMS_VALUE_MASK 0x7c
+#define FTM_PARAMS_VALUE_SHIFT 2
+#define FTM_PARAMS_VALUE(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_VALUE_OFFSET, \
+ FTM_PARAMS_VALUE_MASK, FTM_PARAMS_VALUE_SHIFT)
+#define FTM_PARAMS_SET_VALUE(_p, _value) FTM_PARAMS_SET_FIELD(_p, \
+ FTM_PARAMS_VALUE_OFFSET, FTM_PARAMS_VALUE_MASK, FTM_PARAMS_VALUE_SHIFT, _value)
+#define FTM_PARAMS_MAX_VALUE 32
+
+#define FTM_PARAMS_NBURSTEXP_OFFSET 1
+#define FTM_PARAMS_NBURSTEXP_MASK 0x0f
+#define FTM_PARAMS_NBURSTEXP_SHIFT 0
+#define FTM_PARAMS_NBURSTEXP(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_NBURSTEXP_OFFSET, \
+ FTM_PARAMS_NBURSTEXP_MASK, FTM_PARAMS_NBURSTEXP_SHIFT)
+#define FTM_PARAMS_SET_NBURSTEXP(_p, _bexp) FTM_PARAMS_SET_FIELD(_p, \
+ FTM_PARAMS_NBURSTEXP_OFFSET, FTM_PARAMS_NBURSTEXP_MASK, FTM_PARAMS_NBURSTEXP_SHIFT, \
+ _bexp)
+
+#define FTM_PARAMS_NBURST(_p) (1 << FTM_PARAMS_NBURSTEXP(_p))
+
+enum {
+ FTM_PARAMS_NBURSTEXP_NOPREF = 15
+};
+
+enum {
+ FTM_PARAMS_BURSTTMO_NOPREF = 15
+};
+
+#define FTM_PARAMS_BURSTTMO_OFFSET 1
+#define FTM_PARAMS_BURSTTMO_MASK 0xf0
+#define FTM_PARAMS_BURSTTMO_SHIFT 4
+#define FTM_PARAMS_BURSTTMO(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_BURSTTMO_OFFSET, \
+ FTM_PARAMS_BURSTTMO_MASK, FTM_PARAMS_BURSTTMO_SHIFT)
+/* set timeout in params using _tmo where timeout = 2^(_tmo) * 250us */
+#define FTM_PARAMS_SET_BURSTTMO(_p, _tmo) FTM_PARAMS_SET_FIELD(_p, \
+ FTM_PARAMS_BURSTTMO_OFFSET, FTM_PARAMS_BURSTTMO_MASK, FTM_PARAMS_BURSTTMO_SHIFT, (_tmo)+2)
+
+#define FTM_PARAMS_BURSTTMO_USEC(_val) ((1 << ((_val)-2)) * 250)
+#define FTM_PARAMS_BURSTTMO_VALID(_val) ((((_val) < 12 && (_val) > 1)) || \
+ (_val) == FTM_PARAMS_BURSTTMO_NOPREF)
+#define FTM_PARAMS_BURSTTMO_MAX_MSEC 128 /* 2^9 * 250us */
+#define FTM_PARAMS_BURSTTMO_MAX_USEC 128000 /* 2^9 * 250us */
+
+#define FTM_PARAMS_MINDELTA_OFFSET 2
+#define FTM_PARAMS_MINDELTA_USEC(_p) ((_p)->info[FTM_PARAMS_MINDELTA_OFFSET] * 100)
+#define FTM_PARAMS_SET_MINDELTA_USEC(_p, _delta) do { \
+ (_p)->info[FTM_PARAMS_MINDELTA_OFFSET] = (_delta) / 100; \
+} while (0)
+
+enum {
+ FTM_PARAMS_MINDELTA_NOPREF = 0
+};
+
+#define FTM_PARAMS_PARTIAL_TSF(_p) ((_p)->info[4] << 8 | (_p)->info[3])
+#define FTM_PARAMS_SET_PARTIAL_TSF(_p, _partial_tsf) do { \
+ (_p)->info[3] = (_partial_tsf) & 0xff; \
+ (_p)->info[4] = ((_partial_tsf) >> 8) & 0xff; \
+} while (0)
+
+#define FTM_PARAMS_PARTIAL_TSF_MASK 0x0000000003fffc00ULL
+#define FTM_PARAMS_PARTIAL_TSF_SHIFT 10
+#define FTM_PARAMS_PARTIAL_TSF_BIT_LEN 16
+#define FTM_PARAMS_PARTIAL_TSF_MAX 0xffff
+
+/* FTM can indicate upto 62k TUs forward and 1k TU backward */
+#define FTM_PARAMS_TSF_FW_HI (63487 << 10) /* in micro sec */
+#define FTM_PARAMS_TSF_BW_LOW (64512 << 10) /* in micro sec */
+#define FTM_PARAMS_TSF_BW_HI (65535 << 10) /* in micro sec */
+#define FTM_PARAMS_TSF_FW_MAX FTM_PARAMS_TSF_FW_HI
+#define FTM_PARAMS_TSF_BW_MAX (FTM_PARAMS_TSF_BW_HI - FTM_PARAMS_TSF_BW_LOW)
+
+#define FTM_PARAMS_PTSFNOPREF_OFFSET 5
+#define FTM_PARAMS_PTSFNOPREF_MASK 0x1
+#define FTM_PARAMS_PTSFNOPREF_SHIFT 0
+#define FTM_PARAMS_PTSFNOPREF(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_PTSFNOPREF_OFFSET, \
+ FTM_PARAMS_PTSFNOPREF_MASK, FTM_PARAMS_PTSFNOPREF_SHIFT)
+#define FTM_PARAMS_SET_PTSFNOPREF(_p, _nopref) FTM_PARAMS_SET_FIELD(_p, \
+ FTM_PARAMS_PTSFNOPREF_OFFSET, FTM_PARAMS_PTSFNOPREF_MASK, \
+ FTM_PARAMS_PTSFNOPREF_SHIFT, _nopref)
+
+#define FTM_PARAMS_ASAP_OFFSET 5
+#define FTM_PARAMS_ASAP_MASK 0x4
+#define FTM_PARAMS_ASAP_SHIFT 2
+#define FTM_PARAMS_ASAP(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_ASAP_OFFSET, \
+ FTM_PARAMS_ASAP_MASK, FTM_PARAMS_ASAP_SHIFT)
+#define FTM_PARAMS_SET_ASAP(_p, _asap) FTM_PARAMS_SET_FIELD(_p, \
+ FTM_PARAMS_ASAP_OFFSET, FTM_PARAMS_ASAP_MASK, FTM_PARAMS_ASAP_SHIFT, _asap)
+
+/* FTM1 - AKA ASAP Capable */
+#define FTM_PARAMS_FTM1_OFFSET 5
+#define FTM_PARAMS_FTM1_MASK 0x02
+#define FTM_PARAMS_FTM1_SHIFT 1
+#define FTM_PARAMS_FTM1(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_FTM1_OFFSET, \
+ FTM_PARAMS_FTM1_MASK, FTM_PARAMS_FTM1_SHIFT)
+#define FTM_PARAMS_SET_FTM1(_p, _ftm1) FTM_PARAMS_SET_FIELD(_p, \
+ FTM_PARAMS_FTM1_OFFSET, FTM_PARAMS_FTM1_MASK, FTM_PARAMS_FTM1_SHIFT, _ftm1)
+
+#define FTM_PARAMS_FTMS_PER_BURST_OFFSET 5
+#define FTM_PARAMS_FTMS_PER_BURST_MASK 0xf8
+#define FTM_PARAMS_FTMS_PER_BURST_SHIFT 3
+#define FTM_PARAMS_FTMS_PER_BURST(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_FTMS_PER_BURST_OFFSET, \
+ FTM_PARAMS_FTMS_PER_BURST_MASK, FTM_PARAMS_FTMS_PER_BURST_SHIFT)
+#define FTM_PARAMS_SET_FTMS_PER_BURST(_p, _nftms) FTM_PARAMS_SET_FIELD(_p, \
+ FTM_PARAMS_FTMS_PER_BURST_OFFSET, FTM_PARAMS_FTMS_PER_BURST_MASK, \
+ FTM_PARAMS_FTMS_PER_BURST_SHIFT, _nftms)
+
+enum {
+ FTM_PARAMS_FTMS_PER_BURST_NOPREF = 0
+};
+
+#define FTM_PARAMS_CHAN_INFO_OFFSET 6
+#define FTM_PARAMS_CHAN_INFO_MASK 0xfc
+#define FTM_PARAMS_CHAN_INFO_SHIFT 2
+#define FTM_PARAMS_CHAN_INFO(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_CHAN_INFO_OFFSET, \
+ FTM_PARAMS_CHAN_INFO_MASK, FTM_PARAMS_CHAN_INFO_SHIFT)
+#define FTM_PARAMS_SET_CHAN_INFO(_p, _ci) FTM_PARAMS_SET_FIELD(_p, \
+ FTM_PARAMS_CHAN_INFO_OFFSET, FTM_PARAMS_CHAN_INFO_MASK, FTM_PARAMS_CHAN_INFO_SHIFT, _ci)
+
+/* burst period - units of 100ms */
+#define FTM_PARAMS_BURST_PERIOD(_p) (((_p)->info[8] << 8) | (_p)->info[7])
+#define FTM_PARAMS_SET_BURST_PERIOD(_p, _bp) do {\
+ (_p)->info[7] = (_bp) & 0xff; \
+ (_p)->info[8] = ((_bp) >> 8) & 0xff; \
+} while (0)
+
+#define FTM_PARAMS_BURST_PERIOD_MS(_p) (FTM_PARAMS_BURST_PERIOD(_p) * 100)
+
+enum {
+ FTM_PARAMS_BURST_PERIOD_NOPREF = 0
+};
+
+/* FTM status values - last updated from 11mcD4.0 */
+enum {
+ FTM_PARAMS_STATUS_RESERVED = 0,
+ FTM_PARAMS_STATUS_SUCCESSFUL = 1,
+ FTM_PARAMS_STATUS_INCAPABLE = 2,
+ FTM_PARAMS_STATUS_FAILED = 3,
+ /* Below are obsolte */
+ FTM_PARAMS_STATUS_OVERRIDDEN = 4,
+ FTM_PARAMS_STATUS_ASAP_INCAPABLE = 5,
+ FTM_PARAMS_STATUS_ASAP_FAILED = 6,
+ /* rest are reserved */
+};
+
+enum {
+ FTM_PARAMS_CHAN_INFO_NO_PREF = 0,
+ FTM_PARAMS_CHAN_INFO_RESERVE1 = 1,
+ FTM_PARAMS_CHAN_INFO_RESERVE2 = 2,
+ FTM_PARAMS_CHAN_INFO_RESERVE3 = 3,
+ FTM_PARAMS_CHAN_INFO_NON_HT_5 = 4,
+ FTM_PARAMS_CHAN_INFO_RESERVE5 = 5,
+ FTM_PARAMS_CHAN_INFO_NON_HT_10 = 6,
+ FTM_PARAMS_CHAN_INFO_RESERVE7 = 7,
+ FTM_PARAMS_CHAN_INFO_NON_HT_20 = 8, /* excludes 2.4G, and High rate DSSS */
+ FTM_PARAMS_CHAN_INFO_HT_MF_20 = 9,
+ FTM_PARAMS_CHAN_INFO_VHT_20 = 10,
+ FTM_PARAMS_CHAN_INFO_HT_MF_40 = 11,
+ FTM_PARAMS_CHAN_INFO_VHT_40 = 12,
+ FTM_PARAMS_CHAN_INFO_VHT_80 = 13,
+ FTM_PARAMS_CHAN_INFO_VHT_80_80 = 14,
+ FTM_PARAMS_CHAN_INFO_VHT_160_2_RFLOS = 15,
+ FTM_PARAMS_CHAN_INFO_VHT_160 = 16,
+ /* Reserved from 17 - 30 */
+ FTM_PARAMS_CHAN_INFO_DMG_2160 = 31,
+ /* Reserved from 32 - 63 */
+ FTM_PARAMS_CHAN_INFO_MAX = 63
+};
+
+/* tag_ID/length/value_buffer tuple */
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint8 id;
+ uint8 len;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT ftm_vs_tlv_t;
+
+BWL_PRE_PACKED_STRUCT struct dot11_ftm_vs_ie {
+ uint8 id; /* DOT11_MNG_VS_ID */
+ uint8 len; /* length following */
+ uint8 oui[3]; /* BRCM_PROP_OUI (or Customer) */
+ uint8 sub_type; /* BRCM_FTM_IE_TYPE (or Customer) */
+ uint8 version;
+ ftm_vs_tlv_t tlvs[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ftm_vs_ie dot11_ftm_vs_ie_t;
+
+/* ftm vs api version */
+#define BCM_FTM_VS_PARAMS_VERSION 0x01
+
+/* ftm vendor specific information tlv types */
+enum {
+ FTM_VS_TLV_NONE = 0,
+ FTM_VS_TLV_REQ_PARAMS = 1, /* additional request params (in FTM_REQ) */
+ FTM_VS_TLV_MEAS_INFO = 2, /* measurement information (in FTM_MEAS) */
+ FTM_VS_TLV_SEC_PARAMS = 3, /* security parameters (in either) */
+ FTM_VS_TLV_SEQ_PARAMS = 4, /* toast parameters (FTM_REQ, BRCM proprietary) */
+ FTM_VS_TLV_MF_BUF = 5, /* multi frame buffer - may span ftm vs ie's */
+ /* add additional types above */
+};
+
+/* the following definitions are *DEPRECATED* and moved to implemenetion files. They
+ * are retained here because previous (May 2016) some branches use them
+ */
+#define FTM_TPK_LEN 16
+#define FTM_RI_RR_BUF_LEN 32
+#define FTM_TPK_RI_RR_LEN 13
+#define FTM_TPK_DIGEST_LEN 32
+#define FTM_TPK_BUFFER_LEN 128
+#define FTM_TPK_RI_PHY_LEN 7
+#define FTM_TPK_RR_PHY_LEN 7
+#define FTM_TPK_DATA_BUFFER_LEN 88
+
+BWL_PRE_PACKED_STRUCT struct dot11_ftm_vs_params {
+ uint8 id; /* DOT11_MNG_VS_ID */
+ uint8 len;
+ uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */
+ uint8 bcm_vs_id;
+ ftm_vs_tlv_t ftm_tpk_ri_rr[1]; /* ftm_TPK_ri_rr place holder */
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ftm_vs_params dot11_ftm_vs_tpk_ri_rr_params_t;
+#define DOT11_FTM_VS_LEN (sizeof(dot11_ftm_vs_tpk_ri_rr_params_t) - TLV_HDR_LEN)
+/* end *DEPRECATED* ftm definitions */
+
+BWL_PRE_PACKED_STRUCT struct dot11_ftm_sync_info {
+ uint8 id; /* Extended - 255 11mc D4.3 */
+ uint8 len;
+ uint8 id_ext;
+ uint8 tsf_sync_info[4];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_ftm_sync_info dot11_ftm_sync_info_t;
+
+/* ftm tsf sync info ie len - includes id ext */
+#define DOT11_FTM_SYNC_INFO_IE_LEN (sizeof(dot11_ftm_sync_info_t) - TLV_HDR_LEN)
+
+#define DOT11_FTM_IS_SYNC_INFO_IE(_ie) (\
+ DOT11_MNG_IE_ID_EXT_MATCH(_ie, DOT11_MNG_FTM_SYNC_INFO) && \
+ (_ie)->len == DOT11_FTM_SYNC_INFO_IE_LEN)
+
+/* 802.11u interworking access network options */
+#define IW_ANT_MASK 0x0f
+#define IW_INTERNET_MASK 0x10
+#define IW_ASRA_MASK 0x20
+#define IW_ESR_MASK 0x40
+#define IW_UESA_MASK 0x80
+
+/* 802.11u interworking access network type */
+#define IW_ANT_PRIVATE_NETWORK 0
+#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1
+#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2
+#define IW_ANT_FREE_PUBLIC_NETWORK 3
+#define IW_ANT_PERSONAL_DEVICE_NETWORK 4
+#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5
+#define IW_ANT_TEST_NETWORK 14
+#define IW_ANT_WILDCARD_NETWORK 15
+
+#define IW_ANT_LEN 1
+#define IW_VENUE_LEN 2
+#define IW_HESSID_LEN 6
+#define IW_HESSID_OFF (IW_ANT_LEN + IW_VENUE_LEN)
+#define IW_MAX_LEN (IW_ANT_LEN + IW_VENUE_LEN + IW_HESSID_LEN)
+
+/* 802.11u advertisement protocol */
+#define ADVP_ANQP_PROTOCOL_ID 0
+#define ADVP_MIH_PROTOCOL_ID 1
+
+/* 802.11u advertisement protocol masks */
+#define ADVP_QRL_MASK 0x7f
+#define ADVP_PAME_BI_MASK 0x80
+
+/* 802.11u advertisement protocol values */
+#define ADVP_QRL_REQUEST 0x00
+#define ADVP_QRL_RESPONSE 0x7f
+#define ADVP_PAME_BI_DEPENDENT 0x00
+#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK
+
+/* 802.11u ANQP information ID */
+#define ANQP_ID_QUERY_LIST 256
+#define ANQP_ID_CAPABILITY_LIST 257
+#define ANQP_ID_VENUE_NAME_INFO 258
+#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259
+#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260
+#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261
+#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262
+#define ANQP_ID_NAI_REALM_LIST 263
+#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264
+#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265
+#define ANQP_ID_AP_CIVIC_LOCATION 266
+#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267
+#define ANQP_ID_DOMAIN_NAME_LIST 268
+#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269
+#define ANQP_ID_EMERGENCY_NAI 271
+#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797
+
+/* 802.11u ANQP OUI */
+#define ANQP_OUI_SUBTYPE 9
+
+/* 802.11u venue name */
+#define VENUE_LANGUAGE_CODE_SIZE 3
+#define VENUE_NAME_SIZE 255
+
+/* 802.11u venue groups */
+#define VENUE_UNSPECIFIED 0
+#define VENUE_ASSEMBLY 1
+#define VENUE_BUSINESS 2
+#define VENUE_EDUCATIONAL 3
+#define VENUE_FACTORY 4
+#define VENUE_INSTITUTIONAL 5
+#define VENUE_MERCANTILE 6
+#define VENUE_RESIDENTIAL 7
+#define VENUE_STORAGE 8
+#define VENUE_UTILITY 9
+#define VENUE_VEHICULAR 10
+#define VENUE_OUTDOOR 11
+
+/* 802.11u network authentication type indicator */
+#define NATI_UNSPECIFIED -1
+#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0
+#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1
+#define NATI_HTTP_HTTPS_REDIRECTION 2
+#define NATI_DNS_REDIRECTION 3
+
+/* 802.11u IP address type availability - IPv6 */
+#define IPA_IPV6_SHIFT 0
+#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT)
+#define IPA_IPV6_NOT_AVAILABLE 0x00
+#define IPA_IPV6_AVAILABLE 0x01
+#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02
+
+/* 802.11u IP address type availability - IPv4 */
+#define IPA_IPV4_SHIFT 2
+#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT)
+#define IPA_IPV4_NOT_AVAILABLE 0x00
+#define IPA_IPV4_PUBLIC 0x01
+#define IPA_IPV4_PORT_RESTRICT 0x02
+#define IPA_IPV4_SINGLE_NAT 0x03
+#define IPA_IPV4_DOUBLE_NAT 0x04
+#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05
+#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06
+#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07
+
+/* 802.11u NAI realm encoding */
+#define REALM_ENCODING_RFC4282 0
+#define REALM_ENCODING_UTF8 1
+
+/* 802.11u IANA EAP method type numbers */
+#define REALM_EAP_TLS 13
+#define REALM_EAP_LEAP 17
+#define REALM_EAP_SIM 18
+#define REALM_EAP_TTLS 21
+#define REALM_EAP_AKA 23
+#define REALM_EAP_PEAP 25
+#define REALM_EAP_FAST 43
+#define REALM_EAP_PSK 47
+#define REALM_EAP_AKAP 50
+#define REALM_EAP_EXPANDED 254
+
+/* 802.11u authentication ID */
+#define REALM_EXPANDED_EAP 1
+#define REALM_NON_EAP_INNER_AUTHENTICATION 2
+#define REALM_INNER_AUTHENTICATION_EAP 3
+#define REALM_EXPANDED_INNER_EAP 4
+#define REALM_CREDENTIAL 5
+#define REALM_TUNNELED_EAP_CREDENTIAL 6
+#define REALM_VENDOR_SPECIFIC_EAP 221
+
+/* 802.11u non-EAP inner authentication type */
+#define REALM_RESERVED_AUTH 0
+#define REALM_PAP 1
+#define REALM_CHAP 2
+#define REALM_MSCHAP 3
+#define REALM_MSCHAPV2 4
+
+/* 802.11u credential type */
+#define REALM_SIM 1
+#define REALM_USIM 2
+#define REALM_NFC 3
+#define REALM_HARDWARE_TOKEN 4
+#define REALM_SOFTOKEN 5
+#define REALM_CERTIFICATE 6
+#define REALM_USERNAME_PASSWORD 7
+#define REALM_SERVER_SIDE 8
+#define REALM_RESERVED_CRED 9
+#define REALM_VENDOR_SPECIFIC_CRED 10
+
+/* 802.11u 3GPP PLMN */
+#define G3PP_GUD_VERSION 0
+#define G3PP_PLMN_LIST_IE 0
+
+/** hotspot2.0 indication element (vendor specific) */
+BWL_PRE_PACKED_STRUCT struct hs20_ie {
+ uint8 oui[3];
+ uint8 type;
+ uint8 config;
+} BWL_POST_PACKED_STRUCT;
+typedef struct hs20_ie hs20_ie_t;
+#define HS20_IE_LEN 5 /* HS20 IE length */
+
+/** IEEE 802.11 Annex E */
+typedef enum {
+ DOT11_2GHZ_20MHZ_CLASS_12 = 81, /* Ch 1-11 */
+ DOT11_5GHZ_20MHZ_CLASS_1 = 115, /* Ch 36-48 */
+ DOT11_5GHZ_20MHZ_CLASS_2_DFS = 118, /* Ch 52-64 */
+ DOT11_5GHZ_20MHZ_CLASS_3 = 124, /* Ch 149-161 */
+ DOT11_5GHZ_20MHZ_CLASS_4_DFS = 121, /* Ch 100-140 */
+ DOT11_5GHZ_20MHZ_CLASS_5 = 125, /* Ch 149-165 */
+ DOT11_5GHZ_40MHZ_CLASS_22 = 116, /* Ch 36-44, lower */
+ DOT11_5GHZ_40MHZ_CLASS_23_DFS = 119, /* Ch 52-60, lower */
+ DOT11_5GHZ_40MHZ_CLASS_24_DFS = 122, /* Ch 100-132, lower */
+ DOT11_5GHZ_40MHZ_CLASS_25 = 126, /* Ch 149-157, lower */
+ DOT11_5GHZ_40MHZ_CLASS_27 = 117, /* Ch 40-48, upper */
+ DOT11_5GHZ_40MHZ_CLASS_28_DFS = 120, /* Ch 56-64, upper */
+ DOT11_5GHZ_40MHZ_CLASS_29_DFS = 123, /* Ch 104-136, upper */
+ DOT11_5GHZ_40MHZ_CLASS_30 = 127, /* Ch 153-161, upper */
+ DOT11_2GHZ_40MHZ_CLASS_32 = 83, /* Ch 1-7, lower */
+ DOT11_2GHZ_40MHZ_CLASS_33 = 84, /* Ch 5-11, upper */
+} dot11_op_class_t;
+
+/* QoS map */
+#define QOS_MAP_FIXED_LENGTH (8 * 2) /* DSCP ranges fixed with 8 entries */
+
+#define BCM_AIBSS_IE_TYPE 56
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _802_11_H_ */
diff --git a/wl/components/shared/proto/802.11ah.h b/wl/components/shared/proto/802.11ah.h
new file mode 100644
index 0000000..1637d31
--- /dev/null
+++ b/wl/components/shared/proto/802.11ah.h
@@ -0,0 +1,175 @@
+/*
+ * Basic types and constants relating to 802.11ah standard.
+ * This is a portion of 802.11ah definition. The rest are in 802.11.h.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: 802.11ah.h 627195 2016-03-24 00:57:47Z $
+ */
+
+#ifndef _802_11ah_h_
+#define _802_11ah_h_
+
+#include <typedefs.h>
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/**
+ * TWT IE (sec 8.4.2.196)
+ */
+
+/* TWT element - top */
+BWL_PRE_PACKED_STRUCT struct twt_ie_top {
+ uint8 id;
+ uint8 len;
+ uint8 ctrl; /* Control */
+ uint16 req_type; /* Request Type */
+} BWL_POST_PACKED_STRUCT;
+
+typedef struct twt_ie_top twt_ie_top_t;
+
+/* Control field (figure 8-557ax) */
+#define TWT_CTRL_NDP_PAGING_IND 0x01 /* NDP Paging Indication */
+#define TWT_CTRL_RESP_PM_MODE 0x02 /* Respondor PM Mode */
+#define TWT_CTRL_BCAST 0x04 /* Broadcast */
+
+/* Requestor Type field (figure 8-557ay) */
+#define TWT_REQ_TYPE_REQUEST 0x0001 /* Request */
+#define TWT_REQ_TYPE_SETUP_CMD_MASK 0x000e /* Setup Command */
+#define TWT_REQ_TYPE_SETUP_CMD_SHIFT 1
+#define TWT_REQ_TYPE_TRIGGER 0x0010 /* Trigger */
+#define TWT_REQ_TYPE_IMPLICIT 0x0020 /* Implicit */
+#define TWT_REQ_TYPE_FLOW_TYPE 0x0040 /* Flow Type */
+#define TWT_REQ_TYPE_FLOW_ID_MASK 0x0380 /* Flow Identifier */
+#define TWT_REQ_TYPE_FLOW_ID_SHIFT 7
+#define TWT_REQ_TYPE_WAKE_EXP_MASK 0x7c00 /* Wake Interval Exponent */
+#define TWT_REQ_TYPE_WAKE_EXP_SHIFT 10
+#define TWT_REQ_TYPE_PROTECTION 0x8000 /* Protection */
+
+/* Setup Command field (table 8-248I) */
+#define TWT_SETUP_CMD_REQUEST_TWT 0 /* Request TWT */
+#define TWT_SETUP_CMD_SUGGEST_TWT 1 /* Suggest TWT */
+#define TWT_SETUP_CMD_DEMAND_TWT 2 /* Demand TWT */
+#define TWT_SETUP_CMD_GRPING_TWT 3 /* Grouping TWT */
+#define TWT_SETUP_CMD_ACCEPT_TWT 4 /* Accept TWT */
+#define TWT_SETUP_CMD_ALTER_TWT 5 /* Alternate TWT */
+#define TWT_SETUP_CMD_DICTATE_TWT 6 /* Dictate TWT */
+#define TWT_SETUP_CMD_REJECT_TWT 7 /* Reject TWT */
+
+/* Flow Identifier field (table 8-248I1) */
+#define TWT_BCAST_FLOW_ID_NO_CONSTRAINS 0 /* No constrains on the frame transmitted during
+ * a broadcast TWT SP.
+ */
+#define TWT_BCAST_FLOW_ID_NO_RAND_RU 1 /* Do not contain RUs for random access */
+#define TWT_BCAST_FLOW_ID_RAND_RU 2 /* Contain RUs for random access */
+
+/* Target Wake Time - 8 octets or 0 octet */
+typedef uint64 twt_target_wake_time_t; /* 64 bit TSF time of TWT Responding STA */
+
+/* TWT Group Assignment Info - 9 octets (long format) or 3 octets (short format) or 0 octet */
+/* Group Assignment Info field - short format - Zero Offset Preset field is 0 */
+BWL_PRE_PACKED_STRUCT struct twt_grp_short {
+ uint8 grpid_n_0off; /* Group ID and Zero Offset Present */
+ uint16 unit_n_off; /* TWT Unit and TWT Offset */
+} BWL_POST_PACKED_STRUCT;
+
+typedef struct twt_grp_short twt_grp_short_t;
+
+/* Group Assignment Info field - long format - Zero Offset Preset field is 1 */
+#define TWT_ZERO_OFF_GRP_LEN 6
+BWL_PRE_PACKED_STRUCT struct twt_grp_long {
+ uint8 grpid_n_0off; /* Group ID and Zero Offset Present */
+ uint8 grp_0off[TWT_ZERO_OFF_GRP_LEN]; /* Zero Offset of Group */
+ uint16 unit_n_off; /* Unit and Offset */
+} BWL_POST_PACKED_STRUCT;
+
+typedef struct twt_grp_long twt_grp_long_t;
+
+/* TWT Unit and TWT Offset field */
+#define TWT_UNIT_MASK 0x000f /* TWT Unit */
+#define TWT_OFFSET_MASK 0xfff0 /* TWT Offset */
+#define TWT_OFFSET_SHIFT 4
+
+/* TWT Unit field (table 8-248m) */
+#define TWT_UNIT_32us 0
+#define TWT_UNIT_256us 1
+#define TWT_UNIT_1024us 2
+#define TWT_UNIT_8ms192us 3
+#define TWT_UNIT_32ms768us 4
+#define TWT_UNIT_262ms144us 5
+#define TWT_UNIT_1s048576us 6
+#define TWT_UNIT_8s388608us 7
+#define TWT_UNIT_33s554432us 8
+#define TWT_UNIT_268s435456us 9
+#define TWT_UNIT_1073s741824us 10
+#define TWT_UNIT_8589s934592us 11
+
+/* TWT element - bottom */
+BWL_PRE_PACKED_STRUCT struct twt_ie_bottom {
+ uint8 nom_wake_dur; /* Nominal Minimum Wake Duration */
+ uint16 wake_int_mant; /* TWT Wake Interval Mantissa */
+ uint8 channel; /* TWT Channel */
+ /* NDP Paging field */
+} BWL_POST_PACKED_STRUCT;
+
+typedef struct twt_ie_bottom twt_ie_bottom_t;
+
+/* Nominal Minimum Wake Duration */
+#define TWT_NOM_WAKE_DUR_UNIT 256 /* Nominal Minimum Wake Duration is in 256us units */
+
+/* NDP Paging field - 4 octets or 0 octet */
+typedef uint32 twt_ndp_paging_t;
+
+#define TWT_NDP_PAGING_PID 0x000001ff /* P-ID */
+#define TWT_NDP_PAGING_MAX_PERIOD 0x0001fe00 /* Max NDP Paging Period */
+#define TWT_NDP_PAGING_PART_TSF_OFF 0x001e0000 /* Partial TSF Offset */
+#define TWT_NDP_PAGING_ACTION 0x00e00000 /* Action */
+#define TWT_NDP_PAGING_MIN_SLEEP 0x3f000000 /* Min Sleep Duration */
+
+/* Action field (table 8-248n) */
+#define TWT_ACTION_SEND_PSP_TRIG 0 /* Send a PS-Poll or uplink trigger frame */
+#define TWT_ACTION_WAKE_MIN_SLEEP 1 /* Wake up at the time indicated by
+ * Min Sleep Duration
+ */
+#define TWT_ACTION_WAKE_RCV_BCN 2 /* Wake up to receive the Beacon */
+#define TWT_ACTION_WAKE_RCV_DTIM 3 /* Wake up to receive the DTIM Beacon */
+#define TWT_ACTION_WAKE_IND_TIME 4 /* Wakeup at the time indicated by the sum of
+ * the Min Sleep Duration field and the ASD subfield
+ * in the APDI field of the NDP Paging frame
+ */
+
+/* TWT Teardown Flow field */
+#define TWT_TEARDOWN_FLOW_ID_MASK 0x07
+
+/* TWT Information field byte 0 */
+#define TWT_INFO_FLOW_ID_MASK 0x07
+#define TWT_INFO_RESP_REQ 0x08
+#define TWT_INFO_NEXT_TWT_REQ 0x10
+#define TWT_INFO_NEXT_TWT_SIZE_MASK 0x60
+#define TWT_INFO_NEXT_TWT_SIZE_SHIFT 0x5
+
+/* Next TWT Subfield Size field */
+#define TWT_INFO_NEXT_TWT_SIZE_0 0 /* 0 byte */
+#define TWT_INFO_NEXT_TWT_SIZE_32 1 /* 4 bytes */
+#define TWT_INFO_NEXT_TWT_SIZE_48 2 /* 6 bytes */
+#define TWT_INFO_NEXT_TWT_SIZE_64 3 /* 8 bytes */
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _802_11ah_h_ */
diff --git a/wl/components/shared/proto/802.11e.h b/wl/components/shared/proto/802.11e.h
new file mode 100644
index 0000000..ff479be
--- /dev/null
+++ b/wl/components/shared/proto/802.11e.h
@@ -0,0 +1,128 @@
+/*
+ * 802.11e protocol header file
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: 802.11e.h 572688 2015-07-20 17:49:21Z $
+ */
+
+#ifndef _802_11e_H_
+#define _802_11e_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* WME Traffic Specification (TSPEC) element */
+#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */
+#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */
+
+#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */
+#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */
+#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */
+#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */
+
+BWL_PRE_PACKED_STRUCT struct tsinfo {
+ uint8 octets[3];
+} BWL_POST_PACKED_STRUCT;
+
+typedef struct tsinfo tsinfo_t;
+
+/* 802.11e TSPEC IE */
+typedef BWL_PRE_PACKED_STRUCT struct tspec {
+ uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */
+ uint8 type; /* WME_TYPE */
+ uint8 subtype; /* WME_SUBTYPE_TSPEC */
+ uint8 version; /* WME_VERSION */
+ tsinfo_t tsinfo; /* TS Info bit field */
+ uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */
+ uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */
+ uint32 min_srv_interval; /* Minimum Service Interval (us) */
+ uint32 max_srv_interval; /* Maximum Service Interval (us) */
+ uint32 inactivity_interval; /* Inactivity Interval (us) */
+ uint32 suspension_interval; /* Suspension Interval (us) */
+ uint32 srv_start_time; /* Service Start Time (us) */
+ uint32 min_data_rate; /* Minimum Data Rate (bps) */
+ uint32 mean_data_rate; /* Mean Data Rate (bps) */
+ uint32 peak_data_rate; /* Peak Data Rate (bps) */
+ uint32 max_burst_size; /* Maximum Burst Size (bytes) */
+ uint32 delay_bound; /* Delay Bound (us) */
+ uint32 min_phy_rate; /* Minimum PHY Rate (bps) */
+ uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */
+ uint16 medium_time; /* Medium Time (32 us/s periods) */
+} BWL_POST_PACKED_STRUCT tspec_t;
+
+#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */
+
+/* ts_info */
+/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */
+#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */
+#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */
+#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */
+#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */
+#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */
+#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */
+#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */
+#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */
+#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */
+#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */
+#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */
+#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */
+/* TS info. user priority mask */
+#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT)
+
+/* Macro to get/set bit(s) field in TSINFO */
+#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT)
+#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \
+ TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT)
+#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT)
+#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \
+ TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT)
+
+#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \
+ ((id) << TS_INFO_TID_SHIFT))
+#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \
+ ((prio) << TS_INFO_USER_PRIO_SHIFT))
+
+/* 802.11e QBSS Load IE */
+#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */
+#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */
+
+#define CAC_ADDTS_RESP_TIMEOUT 1000 /* default ADDTS response timeout in ms */
+ /* DEFVAL dot11ADDTSResponseTimeout = 1s */
+
+/* 802.11e ADDTS status code */
+#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */
+#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */
+#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */
+#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */
+
+/* 802.11e DELTS status code */
+#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */
+#define DOT11E_STATUS_END_TS 37 /* END TS */
+#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */
+#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */
+
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _802_11e_CAC_H_ */
diff --git a/wl/components/shared/proto/802.1d.h b/wl/components/shared/proto/802.1d.h
new file mode 100644
index 0000000..559dcff
--- /dev/null
+++ b/wl/components/shared/proto/802.1d.h
@@ -0,0 +1,47 @@
+/*
+ * Fundamental types and constants relating to 802.1D
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: 802.1d.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _802_1_D_
+#define _802_1_D_
+
+/* 802.1D priority defines */
+#define PRIO_8021D_NONE 2 /* None = - */
+#define PRIO_8021D_BK 1 /* BK - Background */
+#define PRIO_8021D_BE 0 /* BE - Best-effort */
+#define PRIO_8021D_EE 3 /* EE - Excellent-effort */
+#define PRIO_8021D_CL 4 /* CL - Controlled Load */
+#define PRIO_8021D_VI 5 /* Vi - Video */
+#define PRIO_8021D_VO 6 /* Vo - Voice */
+#define PRIO_8021D_NC 7 /* NC - Network Control */
+#define MAXPRIO 7 /* 0-7 */
+#define NUMPRIO (MAXPRIO + 1)
+
+#define ALLPRIO -1 /* All prioirty */
+
+/* Converts prio to precedence since the numerical value of
+ * PRIO_8021D_BE and PRIO_8021D_NONE are swapped.
+ */
+#define PRIO2PREC(prio) \
+ (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio))
+
+#endif /* _802_1_D__ */
diff --git a/wl/components/shared/proto/802.3.h b/wl/components/shared/proto/802.3.h
new file mode 100644
index 0000000..c759d2b
--- /dev/null
+++ b/wl/components/shared/proto/802.3.h
@@ -0,0 +1,49 @@
+/*
+ * Fundamental constants relating to 802.3
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: 802.3.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _802_3_h_
+#define _802_3_h_
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#define SNAP_HDR_LEN 6 /* 802.3 SNAP header length */
+#define DOT3_OUI_LEN 3 /* 802.3 oui length */
+
+BWL_PRE_PACKED_STRUCT struct dot3_mac_llc_snap_header {
+ uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */
+ uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */
+ uint16 length; /* frame length incl header */
+ uint8 dsap; /* always 0xAA */
+ uint8 ssap; /* always 0xAA */
+ uint8 ctl; /* always 0x03 */
+ uint8 oui[DOT3_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00
+ * Bridge-Tunnel: 0x00 0x00 0xF8
+ */
+ uint16 type; /* ethertype */
+} BWL_POST_PACKED_STRUCT;
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* #ifndef _802_3_h_ */
diff --git a/wl/components/shared/proto/bcmeth.h b/wl/components/shared/proto/bcmeth.h
new file mode 100644
index 0000000..4488807
--- /dev/null
+++ b/wl/components/shared/proto/bcmeth.h
@@ -0,0 +1,110 @@
+/*
+ * Broadcom Ethernettype protocol definitions
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmeth.h 565501 2015-06-22 14:29:02Z $
+ */
+
+/*
+ * Broadcom Ethernet protocol defines
+ */
+
+#ifndef _BCMETH_H_
+#define _BCMETH_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* ETHER_TYPE_BRCM is defined in ethernet.h */
+
+/*
+ * Following the 2byte BRCM ether_type is a 16bit BRCM subtype field
+ * in one of two formats: (only subtypes 32768-65535 are in use now)
+ *
+ * subtypes 0-32767:
+ * 8 bit subtype (0-127)
+ * 8 bit length in bytes (0-255)
+ *
+ * subtypes 32768-65535:
+ * 16 bit big-endian subtype
+ * 16 bit big-endian length in bytes (0-65535)
+ *
+ * length is the number of additional bytes beyond the 4 or 6 byte header
+ *
+ * Reserved values:
+ * 0 reserved
+ * 5-15 reserved for iLine protocol assignments
+ * 17-126 reserved, assignable
+ * 127 reserved
+ * 32768 reserved
+ * 32769-65534 reserved, assignable
+ * 65535 reserved
+ */
+
+/*
+ * While adding the subtypes and their specific processing code make sure
+ * bcmeth_bcm_hdr_t is the first data structure in the user specific data structure definition
+ */
+
+#define BCMILCP_SUBTYPE_RATE 1
+#define BCMILCP_SUBTYPE_LINK 2
+#define BCMILCP_SUBTYPE_CSA 3
+#define BCMILCP_SUBTYPE_LARQ 4
+#define BCMILCP_SUBTYPE_VENDOR 5
+#define BCMILCP_SUBTYPE_FLH 17
+
+#define BCMILCP_SUBTYPE_VENDOR_LONG 32769
+#define BCMILCP_SUBTYPE_CERT 32770
+#define BCMILCP_SUBTYPE_SES 32771
+
+
+#define BCMILCP_BCM_SUBTYPE_RESERVED 0
+#define BCMILCP_BCM_SUBTYPE_EVENT 1
+#define BCMILCP_BCM_SUBTYPE_SES 2
+/*
+ * The EAPOL type is not used anymore. Instead EAPOL messages are now embedded
+ * within BCMILCP_BCM_SUBTYPE_EVENT type messages
+ */
+/* #define BCMILCP_BCM_SUBTYPE_EAPOL 3 */
+#define BCMILCP_BCM_SUBTYPE_DPT 4
+#define BCMILCP_BCM_SUBTYPE_DNGLEVENT 5
+
+#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8
+#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0
+
+/* These fields are stored in network order */
+typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr
+{
+ uint16 subtype; /* Vendor specific..32769 */
+ uint16 length;
+ uint8 version; /* Version is 0 */
+ uint8 oui[3]; /* Broadcom OUI */
+ /* user specific Data */
+ uint16 usr_subtype;
+} BWL_POST_PACKED_STRUCT bcmeth_hdr_t;
+
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _BCMETH_H_ */
diff --git a/wl/components/shared/proto/bcmevent.h b/wl/components/shared/proto/bcmevent.h
new file mode 100644
index 0000000..8fe52d1
--- /dev/null
+++ b/wl/components/shared/proto/bcmevent.h
@@ -0,0 +1,845 @@
+/*
+ * Broadcom Event protocol definitions
+ *
+ * Dependencies: proto/bcmeth.h
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmevent.h 663597 2017-01-18 18:10:05Z $
+ *
+ */
+
+/*
+ * Broadcom Ethernet Events protocol defines
+ *
+ */
+
+#ifndef _BCMEVENT_H_
+#define _BCMEVENT_H_
+
+#include <typedefs.h>
+/* #include <ethernet.h> -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */
+#include <proto/bcmeth.h>
+#if defined(HEALTH_CHECK) || defined(DNGL_EVENT_SUPPORT)
+#include <proto/dnglevent.h>
+#endif /* HEALTH_CHECK || DNGL_EVENT_SUPPORT */
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#define BCM_EVENT_MSG_VERSION 2 /* wl_event_msg_t struct version */
+#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */
+
+/* flags */
+#define WLC_EVENT_MSG_LINK 0x01 /* link is up */
+#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */
+#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */
+#define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */
+#define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */
+
+/* these fields are stored in network order */
+
+/* version 1 */
+typedef BWL_PRE_PACKED_STRUCT struct
+{
+ uint16 version;
+ uint16 flags; /* see flags below */
+ uint32 event_type; /* Message (see below) */
+ uint32 status; /* Status code (see below) */
+ uint32 reason; /* Reason code (if applicable) */
+ uint32 auth_type; /* WLC_E_AUTH */
+ uint32 datalen; /* data buf */
+ struct ether_addr addr; /* Station address (if applicable) */
+ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */
+} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t;
+
+/* the current version */
+typedef BWL_PRE_PACKED_STRUCT struct
+{
+ uint16 version;
+ uint16 flags; /* see flags below */
+ uint32 event_type; /* Message (see below) */
+ uint32 status; /* Status code (see below) */
+ uint32 reason; /* Reason code (if applicable) */
+ uint32 auth_type; /* WLC_E_AUTH */
+ uint32 datalen; /* data buf */
+ struct ether_addr addr; /* Station address (if applicable) */
+ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */
+ uint8 ifidx; /* destination OS i/f index */
+ uint8 bsscfgidx; /* source bsscfg index */
+} BWL_POST_PACKED_STRUCT wl_event_msg_t;
+
+/* used by driver msgs */
+typedef BWL_PRE_PACKED_STRUCT struct bcm_event {
+ struct ether_header eth;
+ bcmeth_hdr_t bcm_hdr;
+ wl_event_msg_t event;
+ /* data portion follows */
+} BWL_POST_PACKED_STRUCT bcm_event_t;
+
+/*
+ * used by host event
+ * note: if additional event types are added, it should go with is_wlc_event_frame() as well.
+ */
+typedef union bcm_event_msg_u {
+ wl_event_msg_t event;
+#if defined(HEALTH_CHECK) || defined(DNGL_EVENT_SUPPORT)
+ bcm_dngl_event_msg_t dngl_event;
+#endif /* HEALTH_CHECK || DNGL_EVENT_SUPPORT */
+
+ /* add new event here */
+} bcm_event_msg_u_t;
+
+#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header))
+
+/* Event messages */
+#define WLC_E_SET_SSID 0 /* indicates status of set SSID */
+#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */
+#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */
+#define WLC_E_AUTH 3 /* 802.11 AUTH request */
+#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */
+#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */
+#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */
+#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */
+#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */
+#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */
+#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */
+#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */
+#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */
+#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */
+#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */
+#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */
+#define WLC_E_LINK 16 /* generic link indication */
+#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */
+#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */
+#define WLC_E_ROAM 19 /* roam complete: indicate status & reason */
+#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */
+#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */
+#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */
+#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */
+#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */
+#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */
+#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */
+#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */
+#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */
+#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */
+#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */
+#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */
+#define WLC_E_ROAM_PREP 32 /* before attempting to roam association */
+#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */
+#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */
+#define WLC_E_RESET_COMPLETE 35
+#define WLC_E_JOIN_START 36
+#define WLC_E_ROAM_START 37 /* roam attempt started: indicate reason */
+#define WLC_E_ASSOC_START 38
+#define WLC_E_IBSS_ASSOC 39
+#define WLC_E_RADIO 40
+#define WLC_E_PSM_WATCHDOG 41 /* PSM microcode watchdog fired */
+#define WLC_E_PROBREQ_MSG 44 /* probe request received */
+#define WLC_E_SCAN_CONFIRM_IND 45
+#define WLC_E_PSK_SUP 46 /* WPA Handshake fail */
+#define WLC_E_COUNTRY_CODE_CHANGED 47
+#define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */
+#define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */
+#define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */
+#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */
+#define WLC_E_TRACE 52
+#define WLC_E_IF 54 /* I/F change (for dongle host notification) */
+#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */
+#define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */
+#define WLC_E_PFN_BEST_BATCHING 57 /* PFN best network batching event */
+#define WLC_E_EXTLOG_MSG 58
+#define WLC_E_ACTION_FRAME 59 /* Action frame Rx */
+#define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */
+#define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */
+#define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */
+#define WLC_E_CHANNEL_ADOPTED 63
+#define WLC_E_AP_STARTED 64 /* AP started */
+#define WLC_E_DFS_AP_STOP 65 /* AP stopped due to DFS */
+#define WLC_E_DFS_AP_RESUME 66 /* AP resumed due to DFS */
+#define WLC_E_WAI_STA_EVENT 67 /* WAI stations event */
+#define WLC_E_WAI_MSG 68 /* event encapsulating an WAI message */
+#define WLC_E_ESCAN_RESULT 69 /* escan result event */
+#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 /* action frame off channel complete */
+#define WLC_E_PROBRESP_MSG 71 /* probe response received */
+#define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */
+#define WLC_E_DCS_REQUEST 73
+#define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */
+#define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH
+ * wl_event_rx_frame_data_t header
+ */
+#define WLC_E_WAKE_EVENT 76 /* Wake Event timer fired, used for wake WLAN test mode */
+#define WLC_E_RM_COMPLETE 77 /* Radio measurement complete */
+#define WLC_E_HTSFSYNC 78 /* Synchronize TSF with the host */
+#define WLC_E_OVERLAY_REQ 79 /* request an overlay IOCTL/iovar from the host */
+#define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */
+#define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */
+#define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */
+/* PFN BSSID network found event, conflict/share with WLC_E_PFN_SCAN_NONE */
+#define WLC_E_PFN_BSSID_NET_FOUND 82
+#define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */
+/* PFN BSSID network lost event, conflict/share with WLC_E_PFN_SCAN_ALLGONE */
+#define WLC_E_PFN_BSSID_NET_LOST 83
+#define WLC_E_GTK_PLUMBED 84
+#define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */
+#define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */
+#define WLC_E_ASSOC_REQ_IE 87
+#define WLC_E_ASSOC_RESP_IE 88
+#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */
+#define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */
+#define WLC_E_AUTH_REQ 91 /* authentication request received */
+#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected/disconnected peer */
+#define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */
+#define WLC_E_NATIVE 94 /* port-specific event and payload (e.g. NDIS) */
+#define WLC_E_PKTDELAY_IND 95 /* event for tx pkt delay suddently jump */
+#define WLC_E_PSTA_PRIMARY_INTF_IND 99 /* psta primary interface indication */
+#define WLC_E_NAN 100 /* NAN event */
+#define WLC_E_BEACON_FRAME_RX 101
+#define WLC_E_SERVICE_FOUND 102 /* desired service found */
+#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */
+#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */
+#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */
+#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */
+#define WLC_E_WNM_STA_SLEEP 107 /* WNM event to notify STA enter sleep mode */
+#define WLC_E_TXFAIL_THRESH 108 /* Indication of MAC tx failures (exhaustion of
+ * 802.11 retries) exceeding threshold(s)
+ */
+#define WLC_E_PROXD 109 /* Proximity Detection event */
+#define WLC_E_IBSS_COALESCE 110 /* IBSS Coalescing */
+#define WLC_E_AIBSS_TXFAIL 110 /* TXFAIL event for AIBSS, re using event 110 */
+#define WLC_E_BSS_LOAD 114 /* Inform host of beacon bss load */
+#define WLC_E_MIMO_PWR_SAVE 115 /* Inform host MIMO PWR SAVE learning events */
+#define WLC_E_LEAKY_AP_STATS 116 /* Inform host leaky Ap stats events */
+#define WLC_E_ALLOW_CREDIT_BORROW 117 /* Allow or disallow wlfc credit borrowing in DHD */
+#define WLC_E_MSCH 120 /* Multiple channel scheduler event */
+#define WLC_E_CSA_START_IND 121
+#define WLC_E_CSA_DONE_IND 122
+#define WLC_E_CSA_FAILURE_IND 123
+#define WLC_E_CCA_CHAN_QUAL 124 /* CCA based channel quality report */
+#define WLC_E_BSSID 125 /* to report change in BSSID while roaming */
+#define WLC_E_TX_STAT_ERROR 126 /* tx error indication */
+#define WLC_E_BCMC_CREDIT_SUPPORT 127 /* credit check for BCMC supported */
+#define WLC_E_PEER_TIMEOUT 128 /* silently drop a STA because of inactivity */
+#define WLC_E_BT_WIFI_HANDOVER_REQ 130 /* Handover Request Initiated */
+#define WLC_E_SPW_TXINHIBIT 131 /* Southpaw TxInhibit notification */
+#define WLC_E_FBT_AUTH_REQ_IND 132 /* FBT Authentication Request Indication */
+#define WLC_E_RSSI_LQM 133 /* Enhancement addition for WLC_E_RSSI */
+#define WLC_E_PFN_GSCAN_FULL_RESULT 134 /* Full probe/beacon (IEs etc) results */
+#define WLC_E_PFN_SWC 135 /* Significant change in rssi of bssids being tracked */
+#define WLC_E_AUTHORIZED 136 /* a STA been authroized for traffic */
+#define WLC_E_PROBREQ_MSG_RX 137 /* probe req with wl_event_rx_frame_data_t header */
+#define WLC_E_PFN_SCAN_COMPLETE 138 /* PFN completed scan of network list */
+#define WLC_E_RMC_EVENT 139 /* RMC Event */
+#define WLC_E_DPSTA_INTF_IND 140 /* DPSTA interface indication */
+#define WLC_E_RRM 141 /* RRM Event */
+#define WLC_E_PFN_SSID_EXT 142 /* SSID EXT event */
+#define WLC_E_ROAM_EXP_EVENT 143 /* Expanded roam event */
+#define WLC_E_ULP 146 /* ULP entered indication */
+#define WLC_E_MACDBG 147 /* Ucode debugging event */
+#define WLC_E_RESERVED 148 /* reserved */
+#define WLC_E_PRE_ASSOC_RSEP_IND 149 /* assoc resp received */
+#define WLC_E_PSK_AUTH 150 /* PSK AUTH WPA2-PSK 4 WAY Handshake failure */
+#define WLC_E_TKO 151 /* TCP keepalive offload */
+#define WLC_E_SDB_TRANSITION 152 /* SDB mode-switch event */
+#define WLC_E_NATOE_NFCT 153 /* natoe event */
+#define WLC_E_TEMP_THROTTLE 154 /* Temperature throttling control event */
+#define WLC_E_LINK_QUALITY 155 /* Link quality measurement complete */
+#define WLC_E_BSSTRANS_RESP 156 /* BSS Transition Response received */
+#define WLC_E_HE_TWT_SETUP 157 /* HE TWT Setup Complete event */
+#define WLC_E_NAN_DATA_IND 158 /* NAN 2.0 data indication */
+#define WLC_E_NAN_DATA_CONF 159 /* NAN 2.0 data confirmation */
+#define WLC_E_RADAR_DETECTED 160 /* Radar Detected event */
+#define WLC_E_RANGING_EVENT 161 /* Ranging event */
+#define WLC_E_INVALID_IE 162 /* Received invalid IE */
+#define WLC_E_MODE_SWITCH 163 /* Mode switch event */
+#define WLC_E_PKT_FILTER 164 /* Packet filter event */
+#define WLC_E_DMA_TXFLUSH_COMPLETE 165 /* TxFlush done before changing
+ * tx/rxchain
+ */
+#define WLC_E_LAST 166 /* highest val + 1 for range checking */
+#if (WLC_E_LAST > 166)
+#error "WLC_E_LAST: Invalid value for last event; must be <= 165."
+#endif /* WLC_E_LAST */
+
+/* define an API for getting the string name of an event */
+extern const char *bcmevent_get_name(uint event_type);
+extern void wl_event_to_host_order(wl_event_msg_t * evt);
+extern void wl_event_to_network_order(wl_event_msg_t * evt);
+
+/* validate if the event is proper and if valid copy event header to event */
+extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
+ bcm_event_msg_u_t *out_event);
+
+/* conversion between host and network order for events */
+void wl_event_to_host_order(wl_event_msg_t * evt);
+void wl_event_to_network_order(wl_event_msg_t * evt);
+
+
+/* Event status codes */
+#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */
+#define WLC_E_STATUS_FAIL 1 /* operation failed */
+#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */
+#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */
+#define WLC_E_STATUS_ABORT 4 /* operation was aborted */
+#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */
+#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */
+#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */
+#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */
+#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */
+#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */
+#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */
+#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */
+#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */
+#define WLC_E_STATUS_CS_ABORT 15 /* abort channel select */
+#define WLC_E_STATUS_ERROR 16 /* request failed due to error */
+#define WLC_E_STATUS_INVALID 0xff /* Invalid status code to init variables. */
+
+/* 4-way handshake event type */
+#define WLC_E_PSK_AUTH_SUB_EAPOL_START 1 /* EAPOL start */
+#define WLC_E_PSK_AUTH_SUB_EAPOL_DONE 2 /* EAPOL end */
+/* GTK event type */
+#define WLC_E_PSK_AUTH_SUB_GTK_DONE 3 /* GTK end */
+
+/* 4-way handshake event status code */
+#define WLC_E_STATUS_PSK_AUTH_WPA_TIMOUT 1 /* operation timed out */
+#define WLC_E_STATUS_PSK_AUTH_MIC_WPA_ERR 2 /* MIC error */
+#define WLC_E_STATUS_PSK_AUTH_IE_MISMATCH_ERR 3 /* IE Missmatch error */
+#define WLC_E_STATUS_PSK_AUTH_REPLAY_COUNT_ERR 4
+#define WLC_E_STATUS_PSK_AUTH_PEER_BLACKISTED 5 /* Blaclisted peer */
+#define WLC_E_STATUS_PSK_AUTH_GTK_REKEY_FAIL 6 /* GTK event status code */
+
+/* SDB transition status code */
+#define WLC_E_STATUS_SDB_START 1
+#define WLC_E_STATUS_SDB_COMPLETE 2
+
+/* SDB transition reason code */
+#define WLC_E_REASON_HOST_DIRECT 0
+#define WLC_E_REASON_INFRA_ASSOC 1
+#define WLC_E_REASON_INFRA_ROAM 2
+#define WLC_E_REASON_INFRA_DISASSOC 3
+#define WLC_E_REASON_NO_MODE_CHANGE_NEEDED 4
+
+/* WLC_E_SDB_TRANSITION event data */
+#define WL_MAX_BSSCFG 4
+#define WL_EVENT_SDB_TRANSITION_VER 1
+typedef struct wl_event_sdb_data {
+ uint8 wlunit; /* Core index */
+ uint8 is_iftype; /* Interface Type(Station, SoftAP, P2P_GO, P2P_GC */
+ uint16 chanspec; /* Interface Channel/Chanspec */
+ char ssidbuf[(4 * 32) + 1]; /* SSID_FMT_BUF_LEN: ((4 * DOT11_MAX_SSID_LEN) + 1) */
+} wl_event_sdb_data_t;
+
+typedef struct wl_event_sdb_trans {
+ uint8 version; /* Event Data Version */
+ uint8 rsdb_mode;
+ uint8 enable_bsscfg;
+ uint8 reserved;
+ struct wl_event_sdb_data values[WL_MAX_BSSCFG];
+} wl_event_sdb_trans_t;
+
+/* roam reason codes */
+#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */
+#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */
+#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */
+#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */
+#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */
+
+#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */
+#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */
+#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */
+#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */
+#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */
+#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */
+/* retained for precommit auto-merging errors; remove once all branches are synced */
+#define WLC_E_REASON_REQUESTED_ROAM 11
+#define WLC_E_REASON_BSSTRANS_REQ 11 /* roamed due to BSS Transition request by AP */
+#define WLC_E_REASON_LOW_RSSI_CU 12 /* roamed due to low RSSI and Channel Usage */
+#define WLC_E_REASON_RADAR_DETECTED 13 /* roamed due to radar detection by STA */
+
+/* prune reason codes */
+#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */
+#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */
+#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */
+#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */
+#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */
+#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */
+#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */
+#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */
+#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */
+#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */
+#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */
+#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */
+#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */
+#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */
+#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */
+#define WLC_E_PRUNE_AUTH_RESP_MAC 20 /* suppress auth resp by MAC filter */
+
+/* WPA failure reason codes carried in the WLC_E_PSK_SUP event */
+#define WLC_E_SUP_OTHER 0 /* Other reason */
+#define WLC_E_SUP_DECRYPT_KEY_DATA 1 /* Decryption of key data failed */
+#define WLC_E_SUP_BAD_UCAST_WEP128 2 /* Illegal use of ucast WEP128 */
+#define WLC_E_SUP_BAD_UCAST_WEP40 3 /* Illegal use of ucast WEP40 */
+#define WLC_E_SUP_UNSUP_KEY_LEN 4 /* Unsupported key length */
+#define WLC_E_SUP_PW_KEY_CIPHER 5 /* Unicast cipher mismatch in pairwise key */
+#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 /* WPA IE contains > 1 RSN IE in key msg 3 */
+#define WLC_E_SUP_MSG3_IE_MISMATCH 7 /* WPA IE mismatch in key message 3 */
+#define WLC_E_SUP_NO_INSTALL_FLAG 8 /* INSTALL flag unset in 4-way msg */
+#define WLC_E_SUP_MSG3_NO_GTK 9 /* encapsulated GTK missing from msg 3 */
+#define WLC_E_SUP_GRP_KEY_CIPHER 10 /* Multicast cipher mismatch in group key */
+#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 /* encapsulated GTK missing from group msg 1 */
+#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 /* GTK decrypt failure */
+#define WLC_E_SUP_SEND_FAIL 13 /* message send failure */
+#define WLC_E_SUP_DEAUTH 14 /* received FC_DEAUTH */
+#define WLC_E_SUP_WPA_PSK_TMO 15 /* WPA PSK 4-way handshake timeout */
+#define WLC_E_SUP_WPA_PSK_M1_TMO 16 /* WPA PSK 4-way handshake M1 timeout */
+#define WLC_E_SUP_WPA_PSK_M3_TMO 17 /* WPA PSK 4-way handshake M3 timeout */
+
+
+/* Ucode reason codes carried in the WLC_E_MACDBG event */
+#define WLC_E_MACDBG_LIST_PSM 0 /* Dump list update for PSM registers */
+#define WLC_E_MACDBG_LIST_PSMX 1 /* Dump list update for PSMx registers */
+#define WLC_E_MACDBG_REGALL 2 /* Dump all registers */
+
+/* reason codes for WLC_E_LINK_QUALITY event */
+#define WLC_E_LINK_QUALITY_NONE 0
+#define WLC_E_LINK_QUALITY_NO_ACK 1
+#define WLC_E_LINK_QUALITY_NO_RESULT 2
+
+/* Event data for events that include frames received over the air */
+/* WLC_E_PROBRESP_MSG
+ * WLC_E_P2P_PROBREQ_MSG
+ * WLC_E_ACTION_FRAME_RX
+ */
+typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data {
+ uint16 version;
+ uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */
+ int32 rssi;
+ uint32 mactime;
+ uint32 rate;
+} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t;
+
+#define BCM_RX_FRAME_DATA_VERSION 1
+
+/* WLC_E_IF event data */
+typedef struct wl_event_data_if {
+ uint8 ifidx; /* RTE virtual device index (for dongle) */
+ uint8 opcode; /* see I/F opcode */
+ uint8 reserved; /* bit mask (WLC_E_IF_FLAGS_XXX ) */
+ uint8 bssidx; /* bsscfg index */
+ uint8 role; /* see I/F role */
+} wl_event_data_if_t;
+
+/* WLC_E_NATOE event data */
+typedef struct wl_event_data_natoe {
+ uint32 natoe_active;
+ uint32 sta_ip;
+ uint16 start_port;
+ uint16 end_port;
+} wl_event_data_natoe_t;
+
+/* opcode in WLC_E_IF event */
+#define WLC_E_IF_ADD 1 /* bsscfg add */
+#define WLC_E_IF_DEL 2 /* bsscfg delete */
+#define WLC_E_IF_CHANGE 3 /* bsscfg role change */
+
+/* I/F role code in WLC_E_IF event */
+#define WLC_E_IF_ROLE_STA 0 /* Infra STA */
+#define WLC_E_IF_ROLE_AP 1 /* Access Point */
+#define WLC_E_IF_ROLE_WDS 2 /* WDS link */
+#define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */
+#define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */
+#define WLC_E_IF_ROLE_IBSS 8 /* IBSS */
+#define WLC_E_IF_ROLE_NAN 9 /* NAN */
+
+/* WLC_E_RSSI event data */
+typedef struct wl_event_data_rssi {
+ int32 rssi;
+ int32 snr;
+ int32 noise;
+} wl_event_data_rssi_t;
+
+/* WLC_E_IF flag */
+#define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 /* no host I/F creation needed */
+
+/* Reason codes for LINK */
+#define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */
+#define WLC_E_LINK_DISASSOC 2 /* Link down because of disassoc */
+#define WLC_E_LINK_ASSOC_REC 3 /* Link down because assoc recreate failed */
+#define WLC_E_LINK_BSSCFG_DIS 4 /* Link down due to bsscfg down */
+
+
+/* WLC_E_NDIS_LINK event data */
+typedef BWL_PRE_PACKED_STRUCT struct ndis_link_parms {
+ struct ether_addr peer_mac; /* 6 bytes */
+ uint16 chanspec; /* 2 bytes */
+ uint32 link_speed; /* current datarate in units of 500 Kbit/s */
+ uint32 max_link_speed; /* max possible datarate for link in units of 500 Kbit/s */
+ int32 rssi; /* average rssi */
+} BWL_POST_PACKED_STRUCT ndis_link_parms_t;
+
+/* reason codes for WLC_E_OVERLAY_REQ event */
+#define WLC_E_OVL_DOWNLOAD 0 /* overlay download request */
+#define WLC_E_OVL_UPDATE_IND 1 /* device indication of host overlay update */
+
+/* reason codes for WLC_E_TDLS_PEER_EVENT event */
+#define WLC_E_TDLS_PEER_DISCOVERED 0 /* peer is ready to establish TDLS */
+#define WLC_E_TDLS_PEER_CONNECTED 1
+#define WLC_E_TDLS_PEER_DISCONNECTED 2
+
+/* reason codes for WLC_E_RMC_EVENT event */
+#define WLC_E_REASON_RMC_NONE 0
+#define WLC_E_REASON_RMC_AR_LOST 1
+#define WLC_E_REASON_RMC_AR_NO_ACK 2
+
+#ifdef WLTDLS
+/* TDLS Action Category code */
+#define TDLS_AF_CATEGORY 12
+/* Wi-Fi Display (WFD) Vendor Specific Category */
+/* used for WFD Tunneled Probe Request and Response */
+#define TDLS_VENDOR_SPECIFIC 127
+/* TDLS Action Field Values */
+#define TDLS_ACTION_SETUP_REQ 0
+#define TDLS_ACTION_SETUP_RESP 1
+#define TDLS_ACTION_SETUP_CONFIRM 2
+#define TDLS_ACTION_TEARDOWN 3
+#define WLAN_TDLS_SET_PROBE_WFD_IE 11
+#define WLAN_TDLS_SET_SETUP_WFD_IE 12
+#define WLAN_TDLS_SET_WFD_ENABLED 13
+#define WLAN_TDLS_SET_WFD_DISABLED 14
+#endif
+
+/* WLC_E_RANGING_EVENT subtypes */
+#define WLC_E_RANGING_RESULTS 0
+
+
+/* GAS event data */
+typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas {
+ uint16 channel; /* channel of GAS protocol */
+ uint8 dialog_token; /* GAS dialog token */
+ uint8 fragment_id; /* fragment id */
+ uint16 status_code; /* status code on GAS completion */
+ uint16 data_len; /* length of data to follow */
+ uint8 data[1]; /* variable length specified by data_len */
+} BWL_POST_PACKED_STRUCT wl_event_gas_t;
+
+/* service discovery TLV */
+typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv {
+ uint16 length; /* length of response_data */
+ uint8 protocol; /* service protocol type */
+ uint8 transaction_id; /* service transaction id */
+ uint8 status_code; /* status code */
+ uint8 data[1]; /* response data */
+} BWL_POST_PACKED_STRUCT wl_sd_tlv_t;
+
+/* service discovery event data */
+typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd {
+ uint16 channel; /* channel */
+ uint8 count; /* number of tlvs */
+ wl_sd_tlv_t tlv[1]; /* service discovery TLV */
+} BWL_POST_PACKED_STRUCT wl_event_sd_t;
+
+/* WLC_E_PKT_FILTER event sub-classification codes */
+#define WLC_E_PKT_FILTER_TIMEOUT 1 /* Matching packet not received in last timeout seconds */
+
+/* Note: proxd has a new API (ver 3.0) deprecates the following */
+
+/* Reason codes for WLC_E_PROXD */
+#define WLC_E_PROXD_FOUND 1 /* Found a proximity device */
+#define WLC_E_PROXD_GONE 2 /* Lost a proximity device */
+#define WLC_E_PROXD_START 3 /* used by: target */
+#define WLC_E_PROXD_STOP 4 /* used by: target */
+#define WLC_E_PROXD_COMPLETED 5 /* used by: initiator completed */
+#define WLC_E_PROXD_ERROR 6 /* used by both initiator and target */
+#define WLC_E_PROXD_COLLECT_START 7 /* used by: target & initiator */
+#define WLC_E_PROXD_COLLECT_STOP 8 /* used by: target */
+#define WLC_E_PROXD_COLLECT_COMPLETED 9 /* used by: initiator completed */
+#define WLC_E_PROXD_COLLECT_ERROR 10 /* used by both initiator and target */
+#define WLC_E_PROXD_NAN_EVENT 11 /* used by both initiator and target */
+#define WLC_E_PROXD_TS_RESULTS 12 /* used by: initiator completed */
+
+/* proxd_event data */
+typedef struct ftm_sample {
+ uint32 value; /* RTT in ns */
+ int8 rssi; /* RSSI */
+} ftm_sample_t;
+
+typedef struct ts_sample {
+ uint32 t1;
+ uint32 t2;
+ uint32 t3;
+ uint32 t4;
+} ts_sample_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct proxd_event_data {
+ uint16 ver; /* version */
+ uint16 mode; /* mode: target/initiator */
+ uint16 method; /* method: rssi/TOF/AOA */
+ uint8 err_code; /* error classification */
+ uint8 TOF_type; /* one way or two way TOF */
+ uint8 OFDM_frame_type; /* legacy or VHT */
+ uint8 bandwidth; /* Bandwidth is 20, 40,80, MHZ */
+ struct ether_addr peer_mac; /* (e.g for tgt:initiator's */
+ uint32 distance; /* dst to tgt, units meter */
+ uint32 meanrtt; /* mean delta */
+ uint32 modertt; /* Mode delta */
+ uint32 medianrtt; /* median RTT */
+ uint32 sdrtt; /* Standard deviation of RTT */
+ int32 gdcalcresult; /* Software or Hardware Kind of redundant, but if */
+ /* frame type is VHT, then we should do it by hardware */
+ int16 avg_rssi; /* avg rssi accroos the ftm frames */
+ int16 validfrmcnt; /* Firmware's valid frame counts */
+ int32 peer_router_info; /* Peer router information if available in TLV, */
+ /* We will add this field later */
+ int32 var1; /* average of group delay */
+ int32 var2; /* average of threshold crossing */
+ int32 var3; /* difference between group delay and threshold crossing */
+ /* raw Fine Time Measurements (ftm) data */
+ uint16 ftm_unit; /* ftm cnt resolution in picoseconds , 6250ps - default */
+ uint16 ftm_cnt; /* num of rtd measurments/length in the ftm buffer */
+ ftm_sample_t ftm_buff[1]; /* 1 ... ftm_cnt */
+} BWL_POST_PACKED_STRUCT wl_proxd_event_data_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct proxd_event_ts_results {
+ uint16 ver; /* version */
+ uint16 mode; /* mode: target/initiator */
+ uint16 method; /* method: rssi/TOF/AOA */
+ uint8 err_code; /* error classification */
+ uint8 TOF_type; /* one way or two way TOF */
+ uint16 ts_cnt; /* number of timestamp measurements */
+ ts_sample_t ts_buff[1]; /* Timestamps */
+} BWL_POST_PACKED_STRUCT wl_proxd_event_ts_results_t;
+
+
+/* Video Traffic Interference Monitor Event */
+#define INTFER_EVENT_VERSION 1
+#define INTFER_STREAM_TYPE_NONTCP 1
+#define INTFER_STREAM_TYPE_TCP 2
+#define WLINTFER_STATS_NSMPLS 4
+typedef struct wl_intfer_event {
+ uint16 version; /* version */
+ uint16 status; /* status */
+ uint8 txfail_histo[WLINTFER_STATS_NSMPLS]; /* txfail histo */
+} wl_intfer_event_t;
+
+#define RRM_EVENT_VERSION 0
+typedef struct wl_rrm_event {
+ int16 version;
+ int16 len;
+ int16 cat; /* Category */
+ int16 subevent;
+ char payload[1]; /* Measurement payload */
+} wl_rrm_event_t;
+
+
+/* WLC_E_PSTA_PRIMARY_INTF_IND event data */
+typedef struct wl_psta_primary_intf_event {
+ struct ether_addr prim_ea; /* primary intf ether addr */
+} wl_psta_primary_intf_event_t;
+
+/* WLC_E_DPSTA_INTF_IND event data */
+typedef enum {
+ WL_INTF_PSTA = 1,
+ WL_INTF_DWDS = 2
+} wl_dpsta_intf_type;
+
+typedef struct wl_dpsta_intf_event {
+ wl_dpsta_intf_type intf_type; /* dwds/psta intf register */
+} wl_dpsta_intf_event_t;
+
+/* ********** NAN protocol events/subevents ********** */
+#define NAN_EVENT_BUFFER_SIZE 512 /* max size */
+/* NAN Events sent by firmware */
+typedef enum wl_nan_events {
+ WL_NAN_EVENT_START = 1, /* NAN cluster started */
+ WL_NAN_EVENT_JOIN = 2, /* Joined to a NAN cluster */
+ WL_NAN_EVENT_ROLE = 3, /* Role changed */
+ WL_NAN_EVENT_SCAN_COMPLETE = 4,
+ WL_NAN_EVENT_DISCOVERY_RESULT = 5,
+ WL_NAN_EVENT_REPLIED = 6,
+ WL_NAN_EVENT_TERMINATED = 7, /* the instance ID will be present in the ev data */
+ WL_NAN_EVENT_RECEIVE = 8,
+ WL_NAN_EVENT_STATUS_CHG = 9, /* generated on any change in nan_mac status */
+ WL_NAN_EVENT_MERGE = 10, /* Merged to a NAN cluster */
+ WL_NAN_EVENT_STOP = 11, /* NAN stopped */
+ WL_NAN_EVENT_P2P = 12, /* NAN P2P EVENT */
+ WL_NAN_EVENT_WINDOW_BEGIN_P2P = 13, /* Event for begin of P2P further availability window */
+ WL_NAN_EVENT_WINDOW_BEGIN_MESH = 14,
+ WL_NAN_EVENT_WINDOW_BEGIN_IBSS = 15,
+ WL_NAN_EVENT_WINDOW_BEGIN_RANGING = 16,
+ WL_NAN_EVENT_POST_DISC = 17, /* Event for post discovery data */
+ WL_NAN_EVENT_DATA_IF_ADD = 18, /* Event for Data IF add */
+ WL_NAN_EVENT_DATA_PEER_ADD = 19, /* Event for peer add */
+ /* nan 2.0 */
+ WL_NAN_EVENT_DATA_IND = 20, /* Will be removed after source code is committed. */
+ WL_NAN_EVENT_PEER_DATAPATH_IND = 20, /* Peer's Datapath request Indication to Host */
+ WL_NAN_EVENT_DATA_CONF = 21, /* Will be removed after source code is committed. */
+ WL_NAN_EVENT_DATAPATH_ESTB = 21, /* Datapath Established to Host */
+ WL_NAN_EVENT_SDF_RX = 22, /* entire service discovery frame */
+ WL_NAN_EVENT_DATA_END = 23, /* Will be removed after source code is committed. */
+ WL_NAN_EVENT_DATAPATH_END = 23, /* Data End to Host */
+ WL_NAN_EVENT_BCN_RX = 24, /* received beacon payload */
+ WL_NAN_EVENT_PEER_DATAPATH_RESP = 25, /* Peer's Data Response indication to Host */
+ WL_NAN_EVENT_PEER_DATAPATH_CONF = 26, /* Peer's Data Confirm indication to Host */
+ WL_NAN_EVENT_RNG_REQ_IND = 27, /* Range Request Indication to Host */
+ WL_NAN_EVENT_RNG_RPT_IND = 28, /* Range Report Indication to Host */
+ WL_NAN_EVENT_RNG_TERM_IND = 29, /* Range Termination Indication to Host */
+ WL_NAN_EVENT_INVALID /* delimiter for max value */
+} nan_app_events_e;
+
+#define IS_NAN_EVT_ON(var, evt) ((var & (1 << (evt-1))) != 0)
+/* ******************* end of NAN section *************** */
+
+/* WLC_E_ULP event data */
+#define WL_ULP_EVENT_VERSION 1
+#define WL_ULP_DISABLE_CONSOLE 1 /* Disable console message on ULP entry */
+#define WL_ULP_UCODE_DOWNLOAD 2 /* Download ULP ucode file */
+#define WL_ULP_ENTRY 3 /* inform ulp entry to Host during warmboot */
+
+typedef struct wl_ulp_event {
+ uint16 version;
+ uint16 ulp_dongle_action;
+} wl_ulp_event_t;
+
+/* TCP keepalive event data */
+typedef BWL_PRE_PACKED_STRUCT struct wl_event_tko {
+ uint8 index; /* TCP connection index, 0 to max-1 */
+ uint8 pad[3]; /* 4-byte struct alignment */
+} BWL_POST_PACKED_STRUCT wl_event_tko_t;
+
+typedef struct {
+ uint8 radar_type; /* one of RADAR_TYPE_XXX */
+ uint16 min_pw; /* minimum pulse-width (usec * 20) */
+ uint16 max_pw; /* maximum pulse-width (usec * 20) */
+ uint16 min_pri; /* minimum pulse repetition interval (usec) */
+ uint16 max_pri; /* maximum pulse repetition interval (usec) */
+ uint16 subband; /* subband/frequency */
+} radar_detected_event_info_t;
+typedef struct wl_event_radar_detect_data {
+
+ uint32 version;
+ uint16 current_chanspec; /* chanspec on which the radar is recieved */
+ uint16 target_chanspec; /* Target chanspec after detection of radar on current_chanspec */
+ radar_detected_event_info_t radar_info[2];
+} wl_event_radar_detect_data_t;
+
+
+#define WL_EVENT_MODESW_VER_1 1
+#define WL_EVENT_MODESW_VER_CURRENT WL_EVENT_MODESW_VER_1
+
+#define WL_E_MODESW_FLAG_MASK_DEVICE 0x01u /* mask of device: belongs to local or peer */
+#define WL_E_MODESW_FLAG_MASK_FROM 0x02u /* mask of origin: firmware or user */
+#define WL_E_MODESW_FLAG_MASK_STATE 0x0Cu /* mask of state: modesw progress state */
+
+#define WL_E_MODESW_FLAG_DEVICE_LOCAL 0x00u /* flag - device: info is about self/local */
+#define WL_E_MODESW_FLAG_DEVICE_PEER 0x01u /* flag - device: info is about peer */
+
+#define WL_E_MODESW_FLAG_FROM_FIRMWARE 0x00u /* flag - from: request is from firmware */
+#define WL_E_MODESW_FLAG_FROM_USER 0x02u /* flag - from: request is from user/iov */
+
+#define WL_E_MODESW_FLAG_STATE_REQUESTED 0x00u /* flag - state: mode switch request */
+#define WL_E_MODESW_FLAG_STATE_INITIATED 0x04u /* flag - state: switch initiated */
+#define WL_E_MODESW_FLAG_STATE_COMPLETE 0x08u /* flag - state: switch completed/success */
+#define WL_E_MODESW_FLAG_STATE_FAILURE 0x0Cu /* flag - state: failed to switch */
+
+/* Get sizeof *X including variable data's length where X is pointer to wl_event_mode_switch_t */
+#define WL_E_MODESW_SIZE(X) (sizeof(*(X)) + (X)->length)
+
+/* Get variable data's length where X is pointer to wl_event_mode_switch_t */
+#define WL_E_MODESW_DATA_SIZE(X) (((X)->length > sizeof(*(X))) ? ((X)->length - sizeof(*(X))) : 0)
+
+#define WL_E_MODESW_REASON_UNKNOWN 0u /* reason: UNKNOWN */
+#define WL_E_MODESW_REASON_ACSD 1u /* reason: ACSD (based on events from FW */
+#define WL_E_MODESW_REASON_OBSS_DBS 2u /* reason: OBSS DBS (eg. on interference) */
+#define WL_E_MODESW_REASON_DFS 3u /* reason: DFS (eg. on subband radar) */
+#define WL_E_MODESW_REASON_DYN160 4u /* reason: DYN160 (160/2x2 - 80/4x4) */
+
+/* event structure for WLC_E_MODE_SWITCH */
+typedef struct {
+ uint16 version;
+ uint16 length; /* size including 'data' field */
+ uint16 opmode_from;
+ uint16 opmode_to;
+ uint32 flags; /* bit 0: peer(/local==0);
+ * bit 1: user(/firmware==0);
+ * bits 3,2: 00==requested, 01==initiated,
+ * 10==complete, 11==failure;
+ * rest: reserved
+ */
+ uint16 reason; /* value 0: unknown, 1: ACSD, 2: OBSS_DBS,
+ * 3: DFS, 4: DYN160, rest: reserved
+ */
+ uint16 data_offset; /* offset to 'data' from beginning of this struct.
+ * fields may be added between data_offset and data
+ */
+ /* ADD NEW FIELDS HERE */
+ uint8 data[]; /* reason specific data; could be empty */
+} wl_event_mode_switch_t;
+
+/* when reason in WLC_E_MODE_SWITCH is DYN160, data will carry the following structure */
+typedef struct {
+ uint16 trigger; /* value 0: MU to SU, 1: SU to MU, 2: metric_dyn160, 3:re-/assoc,
+ * 4: disassoc, 5: rssi, 6: traffic, 7: interference,
+ * 8: chanim_stats
+ */
+ struct ether_addr sta_addr; /* causal STA's MAC address when known */
+ uint16 metric_160_80; /* latest dyn160 metric */
+ uint8 nss; /* NSS of the STA */
+ uint8 bw; /* BW of the STA */
+ int8 rssi; /* RSSI of the STA */
+ uint8 traffic; /* internal metric of traffic */
+} wl_event_mode_switch_dyn160;
+
+/* TWT Setup Completion is designed to notify the user of TWT Setup process
+ * status. When 'status' field is value of BCME_OK, the user must check the
+ * 'setup_cmd' field value in 'wl_twt_sdesc_t' structure that at the end of
+ * the event data to see the response from the TWT Responding STA; when
+ * 'status' field is value of BCME_ERROR or non BCME_OK, user must not use
+ * anything from 'wl_twt_sdesc_t' structure as it is the TWT Requesting STA's
+ * own TWT parameter.
+ */
+
+#define WL_TWT_SETUP_CPLT_VER 0
+
+/* TWT Setup Completion event data */
+typedef struct wl_twt_setup_cplt {
+ uint16 version;
+ uint16 length; /* the byte count of fields from 'dialog' onwards */
+ uint8 dialog; /* the dialog token user supplied to the TWT setup API */
+ uint8 pad[3];
+ int32 status;
+ /* wl_twt_sdesc_t desc; - defined in wlioctl.h */
+} wl_twt_setup_cplt_t;
+
+#define WL_INVALID_IE_EVENT_VERSION 0
+
+/* Invalid IE Event data */
+typedef struct wl_invalid_ie_event {
+ uint16 version;
+ uint16 len; /* Length of the invalid IE copy */
+ uint16 type; /* Type/subtype of the frame which contains the invalid IE */
+ uint16 error; /* error code of the wrong IE, defined in ie_error_code_t */
+ uint8 ie[]; /* Variable length buffer for the invalid IE copy */
+} wl_invalid_ie_event_t;
+
+typedef enum ie_error_code {
+ IE_ERROR_OUT_OF_RANGE = 0x01
+} ie_error_code_t;
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _BCMEVENT_H_ */
diff --git a/wl/components/shared/proto/bcmip.h b/wl/components/shared/proto/bcmip.h
new file mode 100644
index 0000000..fce188f
--- /dev/null
+++ b/wl/components/shared/proto/bcmip.h
@@ -0,0 +1,243 @@
+/*
+ * Fundamental constants relating to IP Protocol
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmip.h 594480 2015-10-22 03:14:33Z $
+ */
+
+#ifndef _bcmip_h_
+#define _bcmip_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+/* IPV4 and IPV6 common */
+#define IP_VER_OFFSET 0x0 /* offset to version field */
+#define IP_VER_MASK 0xf0 /* version mask */
+#define IP_VER_SHIFT 4 /* version shift */
+#define IP_VER_4 4 /* version number for IPV4 */
+#define IP_VER_6 6 /* version number for IPV6 */
+
+#define IP_VER(ip_body) \
+ ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT)
+
+#define IP_PROT_ICMP 0x1 /* ICMP protocol */
+#define IP_PROT_IGMP 0x2 /* IGMP protocol */
+#define IP_PROT_TCP 0x6 /* TCP protocol */
+#define IP_PROT_UDP 0x11 /* UDP protocol type */
+#define IP_PROT_GRE 0x2f /* GRE protocol type */
+#define IP_PROT_ICMP6 0x3a /* ICMPv6 protocol type */
+
+/* IPV4 field offsets */
+#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */
+#define IPV4_TOS_OFFSET 1 /* type of service offset */
+#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */
+#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */
+#define IPV4_PROT_OFFSET 9 /* protocol type offset */
+#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */
+#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */
+#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */
+#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */
+#define IPV4_MIN_HEADER_LEN 20 /* Minimum size for an IP header (no options) */
+
+/* IPV4 field decodes */
+#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */
+#define IPV4_VER_SHIFT 4 /* IPV4 version shift */
+
+#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */
+#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK))
+
+#define IPV4_ADDR_LEN 4 /* IPV4 address length */
+
+#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \
+ ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0)
+
+#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \
+ ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff)
+
+#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */
+#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */
+
+#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET])
+
+#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */
+#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */
+
+#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */
+#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */
+#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */
+
+#define IPV4_TOS_ROUTINE 0
+#define IPV4_TOS_PRIORITY 1
+#define IPV4_TOS_IMMEDIATE 2
+#define IPV4_TOS_FLASH 3
+#define IPV4_TOS_FLASHOVERRIDE 4
+#define IPV4_TOS_CRITICAL 5
+#define IPV4_TOS_INETWORK_CTRL 6
+#define IPV4_TOS_NETWORK_CTRL 7
+
+#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET])
+
+#define IPV4_FRAG_RESV 0x8000 /* Reserved */
+#define IPV4_FRAG_DONT 0x4000 /* Don't fragment */
+#define IPV4_FRAG_MORE 0x2000 /* More fragments */
+#define IPV4_FRAG_OFFSET_MASK 0x1fff /* Fragment offset */
+
+#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */
+
+/* IPV4 packet formats */
+BWL_PRE_PACKED_STRUCT struct ipv4_addr {
+ uint8 addr[IPV4_ADDR_LEN];
+} BWL_POST_PACKED_STRUCT;
+
+BWL_PRE_PACKED_STRUCT struct ipv4_hdr {
+ uint8 version_ihl; /* Version and Internet Header Length */
+ uint8 tos; /* Type Of Service */
+ uint16 tot_len; /* Number of bytes in packet (max 65535) */
+ uint16 id;
+ uint16 frag; /* 3 flag bits and fragment offset */
+ uint8 ttl; /* Time To Live */
+ uint8 prot; /* Protocol */
+ uint16 hdr_chksum; /* IP header checksum */
+ uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */
+ uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */
+} BWL_POST_PACKED_STRUCT;
+
+/* IPV6 field offsets */
+#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */
+#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */
+#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */
+#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */
+#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */
+
+/* IPV6 field decodes */
+#define IPV6_TRAFFIC_CLASS(ipv6_body) \
+ (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \
+ ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4))
+
+#define IPV6_FLOW_LABEL(ipv6_body) \
+ (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \
+ (((uint8 *)(ipv6_body))[2] << 8) | \
+ (((uint8 *)(ipv6_body))[3]))
+
+#define IPV6_PAYLOAD_LEN(ipv6_body) \
+ ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \
+ ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1])
+
+#define IPV6_NEXT_HDR(ipv6_body) \
+ (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET])
+
+#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body)
+
+#define IPV6_ADDR_LEN 16 /* IPV6 address length */
+
+/* IPV4 TOS or IPV6 Traffic Classifier or 0 */
+#define IP_TOS46(ip_body) \
+ (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \
+ IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0)
+
+#define IP_DSCP46(ip_body) (IP_TOS46(ip_body) >> IPV4_TOS_DSCP_SHIFT);
+
+/* IPV4 or IPV6 Protocol Classifier or 0 */
+#define IP_PROT46(ip_body) \
+ (IP_VER(ip_body) == IP_VER_4 ? IPV4_PROT(ip_body) : \
+ IP_VER(ip_body) == IP_VER_6 ? IPV6_PROT(ip_body) : 0)
+
+/* IPV6 extension headers (options) */
+#define IPV6_EXTHDR_HOP 0
+#define IPV6_EXTHDR_ROUTING 43
+#define IPV6_EXTHDR_FRAGMENT 44
+#define IPV6_EXTHDR_AUTH 51
+#define IPV6_EXTHDR_NONE 59
+#define IPV6_EXTHDR_DEST 60
+
+#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \
+ ((prot) == IPV6_EXTHDR_ROUTING) || \
+ ((prot) == IPV6_EXTHDR_FRAGMENT) || \
+ ((prot) == IPV6_EXTHDR_AUTH) || \
+ ((prot) == IPV6_EXTHDR_NONE) || \
+ ((prot) == IPV6_EXTHDR_DEST))
+
+#define IPV6_MIN_HLEN 40
+
+#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3)
+
+BWL_PRE_PACKED_STRUCT struct ipv6_exthdr {
+ uint8 nexthdr;
+ uint8 hdrlen;
+} BWL_POST_PACKED_STRUCT;
+
+BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag {
+ uint8 nexthdr;
+ uint8 rsvd;
+ uint16 frag_off;
+ uint32 ident;
+} BWL_POST_PACKED_STRUCT;
+
+static INLINE int32
+ipv6_exthdr_len(uint8 *h, uint8 *proto)
+{
+ uint16 len = 0, hlen;
+ struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h;
+
+ while (IPV6_EXTHDR(eh->nexthdr)) {
+ if (eh->nexthdr == IPV6_EXTHDR_NONE)
+ return -1;
+ else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT)
+ hlen = 8;
+ else if (eh->nexthdr == IPV6_EXTHDR_AUTH)
+ hlen = (eh->hdrlen + 2) << 2;
+ else
+ hlen = IPV6_EXTHDR_LEN(eh);
+
+ len += hlen;
+ eh = (struct ipv6_exthdr *)(h + len);
+ }
+
+ *proto = eh->nexthdr;
+ return len;
+}
+
+#define IPV4_ISMULTI(a) (((a) & 0xf0000000) == 0xe0000000)
+
+#define IPV4_MCAST_TO_ETHER_MCAST(ipv4, ether) \
+{ \
+ ether[0] = 0x01; \
+ ether[1] = 0x00; \
+ ether[2] = 0x5E; \
+ ether[3] = (ipv4 & 0x7f0000) >> 16; \
+ ether[4] = (ipv4 & 0xff00) >> 8; \
+ ether[5] = (ipv4 & 0xff); \
+}
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#define IPV4_ADDR_STR "%d.%d.%d.%d"
+#define IPV4_ADDR_TO_STR(addr) ((uint32)addr & 0xff000000) >> 24, \
+ ((uint32)addr & 0x00ff0000) >> 16, \
+ ((uint32)addr & 0x0000ff00) >> 8, \
+ ((uint32)addr & 0x000000ff)
+
+#endif /* _bcmip_h_ */
diff --git a/wl/components/shared/proto/bcmipv6.h b/wl/components/shared/proto/bcmipv6.h
new file mode 100644
index 0000000..27e18d4
--- /dev/null
+++ b/wl/components/shared/proto/bcmipv6.h
@@ -0,0 +1,168 @@
+/*
+ * Fundamental constants relating to Neighbor Discovery Protocol
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmipv6.h 665042 2017-05-15 03:46:00Z $
+ */
+
+#ifndef _bcmipv6_h_
+#define _bcmipv6_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* Extension headers */
+#define IPV6_EXT_HOP 0
+#define IPV6_EXT_ROUTE 43
+#define IPV6_EXT_FRAG 44
+#define IPV6_EXT_DEST 60
+#define IPV6_EXT_ESEC 50
+#define IPV6_EXT_AUTH 51
+
+/* Minimum size (extension header "word" length) */
+#define IPV6_EXT_WORD 8
+
+/* Offsets for most extension headers */
+#define IPV6_EXT_NEXTHDR 0
+#define IPV6_EXT_HDRLEN 1
+
+/* Constants specific to fragmentation header */
+#define IPV6_FRAG_MORE_MASK 0x0001
+#define IPV6_FRAG_MORE_SHIFT 0
+#define IPV6_FRAG_OFFS_MASK 0xfff8
+#define IPV6_FRAG_OFFS_SHIFT 3
+
+/* For icmpv6 */
+#define ICMPV6_HEADER_TYPE 0x3A
+#define ICMPV6_PKT_TYPE_RA 134
+#define ICMPV6_PKT_TYPE_NS 135
+#define ICMPV6_PKT_TYPE_NA 136
+
+#define ICMPV6_ND_OPT_TYPE_TARGET_MAC 2
+#define ICMPV6_ND_OPT_TYPE_SRC_MAC 1
+
+#define ICMPV6_ND_OPT_LEN_LINKADDR 1
+
+#define ICMPV6_ND_OPT_LEN_LINKADDR 1
+
+#define IPV6_VERSION 6
+#define IPV6_HOP_LIMIT 255
+
+#define IPV6_ADDR_NULL(a) ((a[0] | a[1] | a[2] | a[3] | a[4] | \
+ a[5] | a[6] | a[7] | a[8] | a[9] | \
+ a[10] | a[11] | a[12] | a[13] | \
+ a[14] | a[15]) == 0)
+
+#define IPV6_ADDR_LOCAL(a) (((a[0] == 0xfe) && (a[1] & 0x80))? TRUE: FALSE)
+
+/* IPV6 address */
+BWL_PRE_PACKED_STRUCT struct ipv6_addr {
+ uint8 addr[16];
+} BWL_POST_PACKED_STRUCT;
+
+/* ICMPV6 Header */
+BWL_PRE_PACKED_STRUCT struct icmp6_hdr {
+ uint8 icmp6_type;
+ uint8 icmp6_code;
+ uint16 icmp6_cksum;
+ BWL_PRE_PACKED_STRUCT union {
+ uint32 reserved;
+ BWL_PRE_PACKED_STRUCT struct nd_advt {
+#ifndef IL_BIGENDIAN
+ uint32 reserved1:5,
+ override:1,
+ solicited:1,
+ router:1,
+ reserved2:24;
+#else
+ uint32 router:1,
+ solicited:1,
+ override:1,
+ reserved:29;
+#endif /* IL_BIGENDIAN */
+ } BWL_POST_PACKED_STRUCT nd_advt;
+ } BWL_POST_PACKED_STRUCT opt;
+} BWL_POST_PACKED_STRUCT;
+
+/* Ipv6 Header Format */
+BWL_PRE_PACKED_STRUCT struct ipv6_hdr {
+#ifndef IL_BIGENDIAN
+ uint8 priority:4,
+ version:4;
+#else
+ uint8 version:4,
+ priority:4;
+#endif /* IL_BIGENDIAN */
+ uint8 flow_lbl[3];
+ uint16 payload_len;
+ uint8 nexthdr;
+ uint8 hop_limit;
+ struct ipv6_addr saddr;
+ struct ipv6_addr daddr;
+} BWL_POST_PACKED_STRUCT;
+
+/* Neighbor Advertisement/Solicitation Packet Structure */
+BWL_PRE_PACKED_STRUCT struct bcm_nd_msg {
+ struct icmp6_hdr icmph;
+ struct ipv6_addr target;
+} BWL_POST_PACKED_STRUCT;
+
+
+/* Neighibor Solicitation/Advertisement Optional Structure */
+BWL_PRE_PACKED_STRUCT struct nd_msg_opt {
+ uint8 type;
+ uint8 len;
+ uint8 mac_addr[ETHER_ADDR_LEN];
+} BWL_POST_PACKED_STRUCT;
+
+/* Ipv6 Fragmentation Header */
+BWL_PRE_PACKED_STRUCT struct ipv6_frag {
+ uint8 nexthdr;
+ uint8 reserved;
+ uint16 frag_offset;
+ uint32 ident;
+} BWL_POST_PACKED_STRUCT;
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+static const struct ipv6_addr all_node_ipv6_maddr = {
+ { 0xff, 0x2, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 1
+ }};
+
+#define IPV6_ISMULTI(a) (a[0] == 0xff)
+
+#define IPV6_MCAST_TO_ETHER_MCAST(ipv6, ether) \
+{ \
+ ether[0] = 0x33; \
+ ether[1] = 0x33; \
+ ether[2] = ipv6[12]; \
+ ether[3] = ipv6[13]; \
+ ether[4] = ipv6[14]; \
+ ether[5] = ipv6[15]; \
+}
+
+#endif /* !defined(_bcmipv6_h_) */
diff --git a/wl/components/shared/proto/bcmtcp.h b/wl/components/shared/proto/bcmtcp.h
new file mode 100644
index 0000000..435e1ae
--- /dev/null
+++ b/wl/components/shared/proto/bcmtcp.h
@@ -0,0 +1,87 @@
+/*
+ * Fundamental constants relating to TCP Protocol
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmtcp.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _bcmtcp_h_
+#define _bcmtcp_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+#define TCP_SRC_PORT_OFFSET 0 /* TCP source port offset */
+#define TCP_DEST_PORT_OFFSET 2 /* TCP dest port offset */
+#define TCP_SEQ_NUM_OFFSET 4 /* TCP sequence number offset */
+#define TCP_ACK_NUM_OFFSET 8 /* TCP acknowledgement number offset */
+#define TCP_HLEN_OFFSET 12 /* HLEN and reserved bits offset */
+#define TCP_FLAGS_OFFSET 13 /* FLAGS and reserved bits offset */
+#define TCP_CHKSUM_OFFSET 16 /* TCP body checksum offset */
+
+#define TCP_PORT_LEN 2 /* TCP port field length */
+
+/* 8bit TCP flag field */
+#define TCP_FLAG_URG 0x20
+#define TCP_FLAG_ACK 0x10
+#define TCP_FLAG_PSH 0x08
+#define TCP_FLAG_RST 0x04
+#define TCP_FLAG_SYN 0x02
+#define TCP_FLAG_FIN 0x01
+
+#define TCP_HLEN_MASK 0xf000
+#define TCP_HLEN_SHIFT 12
+
+/* These fields are stored in network order */
+BWL_PRE_PACKED_STRUCT struct bcmtcp_hdr
+{
+ uint16 src_port; /* Source Port Address */
+ uint16 dst_port; /* Destination Port Address */
+ uint32 seq_num; /* TCP Sequence Number */
+ uint32 ack_num; /* TCP Sequence Number */
+ uint16 hdrlen_rsvd_flags; /* Header length, reserved bits and flags */
+ uint16 tcpwin; /* TCP window */
+ uint16 chksum; /* Segment checksum with pseudoheader */
+ uint16 urg_ptr; /* Points to seq-num of byte following urg data */
+} BWL_POST_PACKED_STRUCT;
+
+#define TCP_MIN_HEADER_LEN 20
+
+#define TCP_HDRLEN_MASK 0xf0
+#define TCP_HDRLEN_SHIFT 4
+#define TCP_HDRLEN(hdrlen) (((hdrlen) & TCP_HDRLEN_MASK) >> TCP_HDRLEN_SHIFT)
+
+#define TCP_FLAGS_MASK 0x1f
+#define TCP_FLAGS(hdrlen) ((hdrlen) & TCP_FLAGS_MASK)
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+/* To address round up by 32bit. */
+#define IS_TCPSEQ_GE(a, b) ((a - b) < NBITVAL(31)) /* a >= b */
+#define IS_TCPSEQ_LE(a, b) ((b - a) < NBITVAL(31)) /* a =< b */
+#define IS_TCPSEQ_GT(a, b) !IS_TCPSEQ_LE(a, b) /* a > b */
+#define IS_TCPSEQ_LT(a, b) !IS_TCPSEQ_GE(a, b) /* a < b */
+
+#endif /* #ifndef _bcmtcp_h_ */
diff --git a/wl/components/shared/proto/ethernet.h b/wl/components/shared/proto/ethernet.h
new file mode 100644
index 0000000..756eff2
--- /dev/null
+++ b/wl/components/shared/proto/ethernet.h
@@ -0,0 +1,247 @@
+/*
+ * From FreeBSD 2.2.7: Fundamental constants relating to ethernet.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: ethernet.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */
+#define _NET_ETHERNET_H_
+
+#ifndef _TYPEDEFS_H_
+#include "typedefs.h"
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+/*
+ * The number of bytes in an ethernet (MAC) address.
+ */
+#define ETHER_ADDR_LEN 6
+
+/*
+ * The number of bytes in the type field.
+ */
+#define ETHER_TYPE_LEN 2
+
+/*
+ * The number of bytes in the trailing CRC field.
+ */
+#define ETHER_CRC_LEN 4
+
+/*
+ * The length of the combined header.
+ */
+#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
+
+/*
+ * The minimum packet length.
+ */
+#define ETHER_MIN_LEN 64
+
+/*
+ * The minimum packet user data length.
+ */
+#define ETHER_MIN_DATA 46
+
+/*
+ * The maximum packet length.
+ */
+#define ETHER_MAX_LEN 1518
+
+/*
+ * The maximum packet user data length.
+ */
+#define ETHER_MAX_DATA 1500
+
+/* ether types */
+#define ETHER_TYPE_MIN 0x0600 /* Anything less than MIN is a length */
+#define ETHER_TYPE_IP 0x0800 /* IP */
+#define ETHER_TYPE_ARP 0x0806 /* ARP */
+#define ETHER_TYPE_8021Q 0x8100 /* 802.1Q */
+#define ETHER_TYPE_IPV6 0x86dd /* IPv6 */
+#define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */
+#define ETHER_TYPE_802_1X 0x888e /* 802.1x */
+#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 /* 802.1x preauthentication */
+#define ETHER_TYPE_WAI 0x88b4 /* WAI */
+#define ETHER_TYPE_89_0D 0x890d /* 89-0d frame for TDLS */
+#define ETHER_TYPE_RRB ETHER_TYPE_89_0D /* RRB 802.11r 2008 */
+
+#define ETHER_TYPE_PPP_SES 0x8864 /* PPPoE Session */
+
+#define ETHER_TYPE_IAPP_L2_UPDATE 0x6 /* IAPP L2 update frame */
+
+/* Broadcom subtype follows ethertype; First 2 bytes are reserved; Next 2 are subtype; */
+#define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4 byte subtype */
+
+/* ether header */
+#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) /* dest address offset */
+#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) /* src address offset */
+#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) /* ether type offset */
+
+/*
+ * A macro to validate a length with
+ */
+#define ETHER_IS_VALID_LEN(foo) \
+ ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN)
+
+#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \
+ ((uint8 *)ea)[0] = 0x01; \
+ ((uint8 *)ea)[1] = 0x00; \
+ ((uint8 *)ea)[2] = 0x5e; \
+ ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \
+ ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \
+ ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \
+}
+
+#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */
+/*
+ * Structure of a 10Mb/s Ethernet header.
+ */
+BWL_PRE_PACKED_STRUCT struct ether_header {
+ uint8 ether_dhost[ETHER_ADDR_LEN];
+ uint8 ether_shost[ETHER_ADDR_LEN];
+ uint16 ether_type;
+} BWL_POST_PACKED_STRUCT;
+
+/*
+ * Structure of a 48-bit Ethernet address.
+ */
+BWL_PRE_PACKED_STRUCT struct ether_addr {
+ uint8 octet[ETHER_ADDR_LEN];
+} BWL_POST_PACKED_STRUCT;
+#elif defined(VX_BSD4_3) && VX_BSD4_3
+/*
+ * Structure of a 48-bit Ethernet address.
+ */
+BWL_PRE_PACKED_STRUCT struct ether_addr {
+ uint8 octet[ETHER_ADDR_LEN];
+} BWL_POST_PACKED_STRUCT;
+#endif /* !__INCif_etherh Quick and ugly hack for VxWorks */
+
+/*
+ * Takes a pointer, set, test, clear, toggle locally admininistered
+ * address bit in the 48-bit Ethernet address.
+ */
+#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2))
+#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2)
+#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd))
+#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2))
+
+/* Takes a pointer, marks unicast address bit in the MAC address */
+#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1))
+
+/*
+ * Takes a pointer, returns true if a 48-bit multicast address
+ * (including broadcast, since it is all ones)
+ */
+#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1)
+
+
+/* compare two ethernet addresses - assumes the pointers can be referenced as shorts */
+#define eacmp(a, b) ((((const uint16 *)(a))[0] ^ ((const uint16 *)(b))[0]) | \
+ (((const uint16 *)(a))[1] ^ ((const uint16 *)(b))[1]) | \
+ (((const uint16 *)(a))[2] ^ ((const uint16 *)(b))[2]))
+
+#define ether_cmp(a, b) eacmp(a, b)
+
+/* copy an ethernet address - assumes the pointers can be referenced as shorts */
+#define eacopy(s, d) \
+do { \
+ ((uint16 *)(d))[0] = ((const uint16 *)(s))[0]; \
+ ((uint16 *)(d))[1] = ((const uint16 *)(s))[1]; \
+ ((uint16 *)(d))[2] = ((const uint16 *)(s))[2]; \
+} while (0)
+
+#define ether_copy(s, d) eacopy(s, d)
+
+/* Copy an ethernet address in reverse order */
+#define ether_rcopy(s, d) \
+do { \
+ ((uint16 *)(d))[2] = ((uint16 *)(s))[2]; \
+ ((uint16 *)(d))[1] = ((uint16 *)(s))[1]; \
+ ((uint16 *)(d))[0] = ((uint16 *)(s))[0]; \
+} while (0)
+
+/* Copy 14B ethernet header: 32bit aligned source and destination. */
+#define ehcopy32(s, d) \
+do { \
+ ((uint32 *)(d))[0] = ((const uint32 *)(s))[0]; \
+ ((uint32 *)(d))[1] = ((const uint32 *)(s))[1]; \
+ ((uint32 *)(d))[2] = ((const uint32 *)(s))[2]; \
+ ((uint16 *)(d))[6] = ((const uint16 *)(s))[6]; \
+} while (0)
+
+#ifdef DONGLEBUILD
+
+/* Dongles use bcmutils functions instead of macros.
+ * Possibly slower but saves over 800 bytes off THUMB dongle image.
+ */
+
+extern const struct ether_addr ether_bcast;
+extern const struct ether_addr ether_null;
+extern const struct ether_addr ether_ipv6_mcast;
+
+extern int ether_isbcast(const void *ea);
+extern int ether_isnulladdr(const void *ea);
+
+#define ETHER_ISBCAST(ea) ether_isbcast(ea)
+#define ETHER_ISNULLADDR(ea) ether_isnulladdr(ea)
+
+#else /* !DONGLEBUILD */
+
+static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}};
+static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}};
+static const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}};
+
+#define ETHER_ISBCAST(ea) ((((const uint8 *)(ea))[0] & \
+ ((const uint8 *)(ea))[1] & \
+ ((const uint8 *)(ea))[2] & \
+ ((const uint8 *)(ea))[3] & \
+ ((const uint8 *)(ea))[4] & \
+ ((const uint8 *)(ea))[5]) == 0xff)
+#define ETHER_ISNULLADDR(ea) ((((const uint8 *)(ea))[0] | \
+ ((const uint8 *)(ea))[1] | \
+ ((const uint8 *)(ea))[2] | \
+ ((const uint8 *)(ea))[3] | \
+ ((const uint8 *)(ea))[4] | \
+ ((const uint8 *)(ea))[5]) == 0)
+
+#endif /* !DONGLEBUILD */
+
+#define ETHER_ISNULLDEST(da) ((((const uint16 *)(da))[0] | \
+ ((const uint16 *)(da))[1] | \
+ ((const uint16 *)(da))[2]) == 0)
+#define ETHER_ISNULLSRC(sa) ETHER_ISNULLDEST(sa)
+
+#define ETHER_MOVE_HDR(d, s) \
+do { \
+ struct ether_header t; \
+ t = *(struct ether_header *)(s); \
+ *(struct ether_header *)(d) = t; \
+} while (0)
+
+#define ETHER_ISUCAST(ea) ((((uint8 *)(ea))[0] & 0x01) == 0)
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _NET_ETHERNET_H_ */
diff --git a/wl/components/shared/proto/event_log_payload.h b/wl/components/shared/proto/event_log_payload.h
new file mode 100644
index 0000000..aa1f9e6
--- /dev/null
+++ b/wl/components/shared/proto/event_log_payload.h
@@ -0,0 +1,668 @@
+/*
+ * EVENT_LOG System Definitions
+ *
+ * This file describes the payloads of event log entries that are data buffers
+ * rather than formatted string entries. The contents are generally XTLVs.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: event_log_payload.h 658172 2016-09-06 20:47:02Z $
+ */
+
+#ifndef _EVENT_LOG_PAYLOAD_H_
+#define _EVENT_LOG_PAYLOAD_H_
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <proto/ethernet.h>
+#include <proto/event_log_tag.h>
+
+#define EVENT_LOG_XTLV_ID_STR 0 /**< XTLV ID for a string */
+#define EVENT_LOG_XTLV_ID_TXQ_SUM 1 /**< XTLV ID for txq_summary_t */
+#define EVENT_LOG_XTLV_ID_SCBDATA_SUM 2 /**< XTLV ID for cb_subq_summary_t */
+#define EVENT_LOG_XTLV_ID_SCBDATA_AMPDU_TX_SUM 3 /**< XTLV ID for scb_ampdu_tx_summary_t */
+#define EVENT_LOG_XTLV_ID_BSSCFGDATA_SUM 4 /**< XTLV ID for bsscfg_q_summary_t */
+#define EVENT_LOG_XTLV_ID_UCTXSTATUS 5 /**< XTLV ID for ucode TxStatus array */
+#define EVENT_LOG_XTLV_ID_TXQ_SUM_V2 6 /**< XTLV ID for txq_summary_v2_t */
+
+/**
+ * An XTLV holding a string
+ * String is not null terminated, length is the XTLV len.
+ */
+typedef struct xtlv_string {
+ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_STR */
+ uint16 len; /* XTLV Len (String length) */
+ char str[1]; /* var len array characters */
+} xtlv_string_t;
+
+#define XTLV_STRING_FULL_LEN(str_len) (BCM_XTLV_HDR_SIZE + (str_len) * sizeof(char))
+
+/**
+ * Summary for a single TxQ context
+ * Two of these will be used per TxQ context---one for the high TxQ, and one for
+ * the low txq that contains DMA prepared pkts. The high TxQ is a full multi-precidence
+ * queue and also has a BSSCFG map to identify the BSSCFGS associated with the queue context.
+ * The low txq counterpart does not populate the BSSCFG map.
+ * The excursion queue will have no bsscfgs associated and is the first queue dumped.
+ */
+typedef struct txq_summary {
+ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_TXQ_SUM */
+ uint16 len; /* XTLV Len */
+ uint32 bsscfg_map; /* bitmap of bsscfg indexes associated with this queue */
+ uint32 stopped; /* flow control bitmap */
+ uint8 prec_count; /* count of precedences/fifos and len of following array */
+ uint8 pad;
+ uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */
+} txq_summary_t;
+
+#define TXQ_SUMMARY_LEN (OFFSETOF(txq_summary_t, plen))
+#define TXQ_SUMMARY_FULL_LEN(num_q) (TXQ_SUMMARY_LEN + (num_q) * sizeof(uint16))
+
+typedef struct txq_summary_v2 {
+ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_TXQ_SUM_V2 */
+ uint16 len; /* XTLV Len */
+ uint32 bsscfg_map; /* bitmap of bsscfg indexes associated with this queue */
+ uint32 stopped; /* flow control bitmap */
+ uint32 hw_stopped; /* flow control bitmap */
+ uint8 prec_count; /* count of precedences/fifos and len of following array */
+ uint8 pad;
+ uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */
+} txq_summary_v2_t;
+
+#define TXQ_SUMMARY_V2_LEN (OFFSETOF(txq_summary_v2_t, plen))
+#define TXQ_SUMMARY_V2_FULL_LEN(num_q) (TXQ_SUMMARY_V2_LEN + (num_q) * sizeof(uint16))
+
+/**
+ * Summary for tx datapath of an SCB cubby
+ * This is a generic summary structure (one size fits all) with
+ * a cubby ID and sub-ID to differentiate SCB cubby types and possible sub-queues.
+ */
+typedef struct scb_subq_summary {
+ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_SCBDATA_SUM */
+ uint16 len; /* XTLV Len */
+ uint32 flags; /* cubby specficic flags */
+ uint8 cubby_id; /* ID registered for cubby */
+ uint8 sub_id; /* sub ID if a cubby has more than one queue */
+ uint8 prec_count; /* count of precedences/fifos and len of following array */
+ uint8 pad;
+ uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */
+} scb_subq_summary_t;
+
+#define SCB_SUBQ_SUMMARY_LEN (OFFSETOF(scb_subq_summary_t, plen))
+#define SCB_SUBQ_SUMMARY_FULL_LEN(num_q) (SCB_SUBQ_SUMMARY_LEN + (num_q) * sizeof(uint16))
+
+/* scb_subq_summary_t.flags for APPS */
+#define SCBDATA_APPS_F_PS 0x00000001
+#define SCBDATA_APPS_F_PSPEND 0x00000002
+#define SCBDATA_APPS_F_INPVB 0x00000004
+#define SCBDATA_APPS_F_APSD_USP 0x00000008
+#define SCBDATA_APPS_F_TXBLOCK 0x00000010
+#define SCBDATA_APPS_F_APSD_HPKT_TMR 0x00000020
+#define SCBDATA_APPS_F_APSD_TX_PEND 0x00000040
+#define SCBDATA_APPS_F_INTRANS 0x00000080
+#define SCBDATA_APPS_F_OFF_PEND 0x00000100
+#define SCBDATA_APPS_F_OFF_BLOCKED 0x00000200
+#define SCBDATA_APPS_F_OFF_IN_PROG 0x00000400
+
+
+/**
+ * Summary for tx datapath AMPDU SCB cubby
+ * This is a specific data structure to describe the AMPDU datapath state for an SCB
+ * used instead of scb_subq_summary_t.
+ * Info is for one TID, so one will be dumped per BA TID active for an SCB.
+ */
+typedef struct scb_ampdu_tx_summary {
+ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_SCBDATA_AMPDU_TX_SUM */
+ uint16 len; /* XTLV Len */
+ uint32 flags; /* misc flags */
+ uint8 tid; /* initiator TID (priority) */
+ uint8 ba_state; /* internal BA state */
+ uint8 bar_cnt; /* number of bars sent with no progress */
+ uint8 retry_bar; /* reason code if bar to be retried at watchdog */
+ uint16 barpending_seq; /* seqnum for bar */
+ uint16 bar_ackpending_seq; /* seqnum of bar for which ack is pending */
+ uint16 start_seq; /* seqnum of the first unacknowledged packet */
+ uint16 max_seq; /* max unacknowledged seqnum sent */
+ uint32 released_bytes_inflight; /* Number of bytes pending in bytes */
+ uint32 released_bytes_target;
+} scb_ampdu_tx_summary_t;
+
+/* scb_ampdu_tx_summary.flags defs */
+#define SCBDATA_AMPDU_TX_F_BAR_ACKPEND 0x00000001 /* bar_ackpending */
+
+/** XTLV stuct to summarize a BSSCFG's packet queue */
+typedef struct bsscfg_q_summary {
+ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_BSSCFGDATA_SUM */
+ uint16 len; /* XTLV Len */
+ struct ether_addr BSSID; /* BSSID */
+ uint8 bsscfg_idx; /* bsscfg index */
+ uint8 type; /* bsscfg type enumeration: BSSCFG_TYPE_XXX */
+ uint8 subtype; /* bsscfg subtype enumeration: BSSCFG_SUBTYPE_XXX */
+ uint8 prec_count; /* count of precedences/fifos and len of following array */
+ uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */
+} bsscfg_q_summary_t;
+
+#define BSSCFG_Q_SUMMARY_LEN (OFFSETOF(bsscfg_q_summary_t, plen))
+#define BSSCFG_Q_SUMMARY_FULL_LEN(num_q) (BSSCFG_Q_SUMMARY_LEN + (num_q) * sizeof(uint16))
+
+/**
+ * An XTLV holding a TxStats array
+ * TxStatus entries are 8 or 16 bytes, size in words (2 or 4) givent in
+ * entry_size field.
+ * Array is uint32 words
+ */
+typedef struct xtlv_uc_txs {
+ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_UCTXSTATUS */
+ uint16 len; /* XTLV Len */
+ uint8 entry_size; /* num uint32 words per entry */
+ uint8 pad[3]; /* reserved, zero */
+ uint32 w[1]; /* var len array of words */
+} xtlv_uc_txs_t;
+
+#define XTLV_UCTXSTATUS_LEN (OFFSETOF(xtlv_uc_txs_t, w))
+#define XTLV_UCTXSTATUS_FULL_LEN(words) (XTLV_UCTXSTATUS_LEN + (words) * sizeof(uint32))
+
+#define SCAN_SUMMARY_VERSION 1
+/* Scan flags */
+#define SCAN_SUM_CHAN_INFO 0x1
+/* Scan_sum flags */
+#define BAND5G_SIB_ENAB 0x2
+#define BAND2G_SIB_ENAB 0x4
+#define PARALLEL_SCAN 0x8
+#define SCAN_ABORT 0x10
+
+/* scan_channel_info flags */
+#define ACTIVE_SCAN_SCN_SUM 0x2
+#define SCAN_SUM_WLC_CORE0 0x4
+#define SCAN_SUM_WLC_CORE1 0x8
+#define HOME_CHAN 0x10
+
+typedef struct wl_scan_ssid_info
+{
+ uint8 ssid_len; /* the length of SSID */
+ uint8 ssid[32]; /* SSID string */
+} wl_scan_ssid_info_t;
+
+typedef struct wl_scan_channel_info {
+ uint16 chanspec; /* chanspec scanned */
+ uint16 reserv;
+ uint32 start_time; /* Scan start time in
+ * milliseconds for the chanspec
+ * or home_dwell time start
+ */
+ uint32 end_time; /* Scan end time in
+ * milliseconds for the chanspec
+ * or home_dwell time end
+ */
+ uint16 probe_count; /* No of probes sent out. For future use
+ */
+ uint16 scn_res_count; /* Count of scan_results found per
+ * channel. For future use
+ */
+} wl_scan_channel_info_t;
+
+typedef struct wl_scan_summary_info {
+ uint32 total_chan_num; /* Total number of channels scanned */
+ uint32 scan_start_time; /* Scan start time in milliseconds */
+ uint32 scan_end_time; /* Scan end time in milliseconds */
+ wl_scan_ssid_info_t ssid[1]; /* SSID being scanned in current
+ * channel. For future use
+ */
+} wl_scan_summary_info_t;
+
+struct wl_scan_summary {
+ uint8 version; /* Version */
+ uint8 reserved;
+ uint16 len; /* Length of the data buffer including SSID
+ * list.
+ */
+ uint16 sync_id; /* Scan Sync ID */
+ uint16 scan_flags; /* flags [0] or SCAN_SUM_CHAN_INFO = */
+ /* channel_info, if not set */
+ /* it is scan_summary_info */
+ /* when channel_info is used, */
+ /* the following flag bits are overridden: */
+ /* flags[1] or ACTIVE_SCAN_SCN_SUM = active channel if set */
+ /* passive if not set */
+ /* flags[2] or WLC_CORE0 = if set, represents wlc_core0 */
+ /* flags[3] or WLC_CORE1 = if set, represents wlc_core1 */
+ /* flags[4] or HOME_CHAN = if set, represents home-channel */
+ /* flags[5:15] = reserved */
+ /* when scan_summary_info is used, */
+ /* the following flag bits are used: */
+ /* flags[1] or BAND5G_SIB_ENAB = */
+ /* allowSIBParallelPassiveScan on 5G band */
+ /* flags[2] or BAND2G_SIB_ENAB = */
+ /* allowSIBParallelPassiveScan on 2G band */
+ /* flags[3] or PARALLEL_SCAN = Parallel scan enabled or not */
+ /* flags[4] or SCAN_ABORT = SCAN_ABORTED scenario */
+ /* flags[5:15] = reserved */
+ union {
+ wl_scan_channel_info_t scan_chan_info; /* scan related information
+ * for each channel scanned
+ */
+ wl_scan_summary_info_t scan_sum_info; /* Cumulative scan related
+ * information.
+ */
+ } u;
+};
+
+/* Channel switch log record structure
+ * Host may map the following structure on channel switch event log record
+ * received from dongle. Note that all payload entries in event log record are
+ * uint32/int32.
+ * THIS IS HTE SAME AS wl_chansw_event_log (as in src/include/wlioctl.h)!!!
+ */
+typedef struct wl_chansw_event_log {
+ uint32 time; /* Time in us */
+ uint32 old_chanspec; /* Old channel spec */
+ uint32 new_chanspec; /* New channel spec */
+ uint32 chansw_reason; /* Reason for channel change */
+ int32 dwell_time;
+} wl_chansw_event_log_t;
+
+/* Sub-block type for EVENT_LOG_TAG_AMPDU_DUMP */
+#define WL_AMPDU_STATS_CNT_RXMCSx1 0 /* RX MCS rate (Nss = 1) */
+#define WL_AMPDU_STATS_CNT_RXMCSx2 1
+#define WL_AMPDU_STATS_CNT_RXMCSx3 2
+#define WL_AMPDU_STATS_CNT_RXMCSx4 3
+#define WL_AMPDU_STATS_CNT_RXVHTx1 4 /* RX VHT rate (Nss = 1) */
+#define WL_AMPDU_STATS_CNT_RXVHTx2 5
+#define WL_AMPDU_STATS_CNT_RXVHTx3 6
+#define WL_AMPDU_STATS_CNT_RXVHTx4 7
+#define WL_AMPDU_STATS_CNT_TXMCSx1 8 /* TX MCS rate (Nss = 1) */
+#define WL_AMPDU_STATS_CNT_TXMCSx2 9
+#define WL_AMPDU_STATS_CNT_TXMCSx3 10
+#define WL_AMPDU_STATS_CNT_TXMCSx4 11
+#define WL_AMPDU_STATS_CNT_TXVHTx1 12 /* TX VHT rate (Nss = 1) */
+#define WL_AMPDU_STATS_CNT_TXVHTx2 13
+#define WL_AMPDU_STATS_CNT_TXVHTx3 14
+#define WL_AMPDU_STATS_CNT_TXVHTx4 15
+#define WL_AMPDU_STATS_CNT_RXMCSSGI 16 /* RX SGI usage (for all MCS rates) */
+#define WL_AMPDU_STATS_CNT_TXMCSSGI 17 /* TX SGI usage (for all MCS rates) */
+#define WL_AMPDU_STATS_CNT_RXVHTSGI 18 /* RX SGI usage (for all VHT rates) */
+#define WL_AMPDU_STATS_CNT_TXVHTSGI 19 /* TX SGI usage (for all VHT rates) */
+#define WL_AMPDU_STATS_CNT_RXMCSPER 20 /* RX PER (for all MCS rates) */
+#define WL_AMPDU_STATS_CNT_TXMCSPER 21 /* TX PER (for all MCS rates) */
+#define WL_AMPDU_STATS_CNT_RXVHTPER 22 /* RX PER (for all VHT rates) */
+#define WL_AMPDU_STATS_CNT_TXVHTPER 23 /* TX PER (for all VHT rates) */
+#define WL_AMPDU_STATS_CNT_RXDENS 24 /* RX AMPDU density */
+#define WL_AMPDU_STATS_CNT_TXDENS 25 /* TX AMPDU density */
+#define WL_AMPDU_STATS_CNT_RXMCSOK 26 /* RX all MCS rates */
+#define WL_AMPDU_STATS_CNT_RXVHTOK 27 /* RX all VHT rates */
+#define WL_AMPDU_STATS_CNT_TXMCSALL 28 /* TX all MCS rates */
+#define WL_AMPDU_STATS_CNT_TXVHTALL 29 /* TX all VHT rates */
+#define WL_AMPDU_STATS_CNT_TXMCSOK 30 /* TX all MCS rates */
+#define WL_AMPDU_STATS_CNT_TXVHTOK 31 /* TX all VHT rates */
+
+#define WL_AMPDU_STATS_CNT_MAX 64
+
+typedef struct {
+ uint16 type; /* AMPDU statistics sub-type */
+ uint16 len; /* Number of 32-bit counters */
+ uint32 counters[WL_AMPDU_STATS_CNT_MAX];
+} wl_ampdu_stats_cnt_generic_t;
+
+typedef struct {
+ uint16 type; /* AMPDU statistics sub-type */
+ uint16 len; /* Number of 32-bit counters + 2 */
+ uint32 total_ampdu;
+ uint32 total_mpdu;
+ uint32 aggr_dist[WL_AMPDU_STATS_CNT_MAX + 1];
+} wl_ampdu_stats_cnt_aggrsz_t;
+
+/* Sub-block type for EVENT_LOG_TAG_MSCHPROFILE */
+#define WL_MSCH_PROFILER_START 0 /* start event check */
+#define WL_MSCH_PROFILER_EXIT 1 /* exit event check */
+#define WL_MSCH_PROFILER_REQ 2 /* request event */
+#define WL_MSCH_PROFILER_CALLBACK 3 /* call back event */
+#define WL_MSCH_PROFILER_MESSAGE 4 /* message event */
+#define WL_MSCH_PROFILER_PROFILE_START 5
+#define WL_MSCH_PROFILER_PROFILE_END 6
+#define WL_MSCH_PROFILER_REQ_HANDLE 7
+#define WL_MSCH_PROFILER_REQ_ENTITY 8
+#define WL_MSCH_PROFILER_CHAN_CTXT 9
+#define WL_MSCH_PROFILER_EVENT_LOG 10
+#define WL_MSCH_PROFILER_REQ_TIMING 11
+#define WL_MSCH_PROFILER_TYPE_MASK 0x00ff
+#define WL_MSCH_PROFILER_WLINDEX_SHIFT 8
+#define WL_MSCH_PROFILER_WLINDEX_MASK 0x0f00
+#define WL_MSCH_PROFILER_VER_SHIFT 12
+#define WL_MSCH_PROFILER_VER_MASK 0xf000
+
+/* MSCH Event data current verion */
+#define WL_MSCH_PROFILER_VER 2
+
+/* msch version history */
+#define WL_MSCH_PROFILER_RSDB_VER 1
+#define WL_MSCH_PROFILER_REPORT_VER 2
+
+/* msch collect header size */
+#define WL_MSCH_PROFILE_HEAD_SIZE OFFSETOF(msch_collect_tlv_t, value)
+
+/* msch event log header size */
+#define WL_MSCH_EVENT_LOG_HEAD_SIZE OFFSETOF(msch_event_log_profiler_event_data_t, data)
+
+/* MSCH data buffer size */
+#define WL_MSCH_PROFILER_BUFFER_SIZE 512
+
+/* request type used in wlc_msch_req_param_t struct */
+#define WL_MSCH_RT_BOTH_FIXED 0 /* both start and end time is fixed */
+#define WL_MSCH_RT_START_FLEX 1 /* start time is flexible and duration is fixed */
+#define WL_MSCH_RT_DUR_FLEX 2 /* start time is fixed and end time is flexible */
+#define WL_MSCH_RT_BOTH_FLEX 3 /* Both start and duration is flexible */
+
+/* Flags used in wlc_msch_req_param_t struct */
+#define WL_MSCH_REQ_FLAGS_CHAN_CONTIGUOUS (1 << 0) /* Don't break up channels in chanspec_list */
+#define WL_MSCH_REQ_FLAGS_MERGE_CONT_SLOTS (1 << 1) /* No slot end if slots are continous */
+#define WL_MSCH_REQ_FLAGS_PREMTABLE (1 << 2) /* Req can be pre-empted by PREMT_CURTS req */
+#define WL_MSCH_REQ_FLAGS_PREMT_CURTS (1 << 3) /* Pre-empt request at the end of curts */
+#define WL_MSCH_REQ_FLAGS_PREMT_IMMEDIATE (1 << 4) /* Pre-empt cur_ts immediately */
+
+/* Requested slot Callback states
+ * req->pend_slot/cur_slot->flags
+ */
+#define WL_MSCH_RC_FLAGS_ONCHAN_FIRE (1 << 0)
+#define WL_MSCH_RC_FLAGS_START_FIRE_DONE (1 << 1)
+#define WL_MSCH_RC_FLAGS_END_FIRE_DONE (1 << 2)
+#define WL_MSCH_RC_FLAGS_ONFIRE_DONE (1 << 3)
+#define WL_MSCH_RC_FLAGS_SPLIT_SLOT_START (1 << 4)
+#define WL_MSCH_RC_FLAGS_SPLIT_SLOT_END (1 << 5)
+#define WL_MSCH_RC_FLAGS_PRE_ONFIRE_DONE (1 << 6)
+
+/* Request entity flags */
+#define WL_MSCH_ENTITY_FLAG_MULTI_INSTANCE (1 << 0)
+
+/* Request Handle flags */
+#define WL_MSCH_REQ_HDL_FLAGS_NEW_REQ (1 << 0) /* req_start callback */
+
+/* MSCH state flags (msch_info->flags) */
+#define WL_MSCH_STATE_IN_TIEMR_CTXT 0x1
+#define WL_MSCH_STATE_SCHD_PENDING 0x2
+
+/* MSCH callback type */
+#define WL_MSCH_CT_REQ_START 0x1
+#define WL_MSCH_CT_ON_CHAN 0x2
+#define WL_MSCH_CT_SLOT_START 0x4
+#define WL_MSCH_CT_SLOT_END 0x8
+#define WL_MSCH_CT_SLOT_SKIP 0x10
+#define WL_MSCH_CT_OFF_CHAN 0x20
+#define WL_MSCH_CT_OFF_CHAN_DONE 0x40
+#define WL_MSCH_CT_REQ_END 0x80
+#define WL_MSCH_CT_PARTIAL 0x100
+#define WL_MSCH_CT_PRE_ONCHAN 0x200
+#define WL_MSCH_CT_PRE_REQ_START 0x400
+
+/* MSCH command bits */
+#define WL_MSCH_CMD_ENABLE_BIT 0x01
+#define WL_MSCH_CMD_PROFILE_BIT 0x02
+#define WL_MSCH_CMD_CALLBACK_BIT 0x04
+#define WL_MSCH_CMD_REGISTER_BIT 0x08
+#define WL_MSCH_CMD_ERROR_BIT 0x10
+#define WL_MSCH_CMD_DEBUG_BIT 0x20
+#define WL_MSCH_CMD_INFOM_BIT 0x40
+#define WL_MSCH_CMD_TRACE_BIT 0x80
+#define WL_MSCH_CMD_ALL_BITS 0xfe
+#define WL_MSCH_CMD_SIZE_MASK 0x00ff0000
+#define WL_MSCH_CMD_SIZE_SHIFT 16
+#define WL_MSCH_CMD_VER_MASK 0xff000000
+#define WL_MSCH_CMD_VER_SHIFT 24
+
+/* maximum channels returned by the get valid channels iovar */
+#define WL_MSCH_NUMCHANNELS 64
+
+typedef struct msch_collect_tlv {
+ uint16 type;
+ uint16 size;
+ char value[1];
+} msch_collect_tlv_t;
+
+typedef struct msch_profiler_event_data {
+ uint32 time_lo; /* Request time */
+ uint32 time_hi;
+} msch_profiler_event_data_t;
+
+typedef struct msch_start_profiler_event_data {
+ uint32 time_lo; /* Request time */
+ uint32 time_hi;
+ uint32 status;
+} msch_start_profiler_event_data_t;
+
+typedef struct msch_message_profiler_event_data {
+ uint32 time_lo; /* Request time */
+ uint32 time_hi;
+ char message[1]; /* message */
+} msch_message_profiler_event_data_t;
+
+typedef struct msch_event_log_profiler_event_data {
+ uint32 time_lo; /* Request time */
+ uint32 time_hi;
+ event_log_hdr_t hdr; /* event log header */
+ uint32 data[9]; /* event data */
+} msch_event_log_profiler_event_data_t;
+
+typedef struct msch_req_param_profiler_event_data {
+ uint16 flags; /* Describe various request properties */
+ uint8 req_type; /* Describe start and end time flexiblilty */
+ uint8 priority; /* Define the request priority */
+ uint32 start_time_l; /* Requested start time offset in us unit */
+ uint32 start_time_h;
+ uint32 duration; /* Requested duration in us unit */
+ uint32 interval; /* Requested periodic interval in us unit,
+ * 0 means non-periodic
+ */
+ union {
+ uint32 dur_flex; /* MSCH_REG_DUR_FLEX, min_dur = duration - dur_flex */
+ struct {
+ uint32 min_dur; /* min duration for traffic, maps to home_time */
+ uint32 max_away_dur; /* max acceptable away dur, maps to home_away_time */
+ uint32 hi_prio_time_l;
+ uint32 hi_prio_time_h;
+ uint32 hi_prio_interval; /* repeated high priority interval */
+ } bf;
+ } flex;
+} msch_req_param_profiler_event_data_t;
+
+typedef struct msch_req_timing_profiler_event_data {
+ uint32 p_req_timing;
+ uint32 p_prev;
+ uint32 p_next;
+ uint16 flags;
+ uint16 timeslot_ptr;
+ uint32 fire_time_l;
+ uint32 fire_time_h;
+ uint32 pre_start_time_l;
+ uint32 pre_start_time_h;
+ uint32 start_time_l;
+ uint32 start_time_h;
+ uint32 end_time_l;
+ uint32 end_time_h;
+ uint32 p_timeslot;
+} msch_req_timing_profiler_event_data_t;
+
+typedef struct msch_chan_ctxt_profiler_event_data {
+ uint32 p_chan_ctxt;
+ uint32 p_prev;
+ uint32 p_next;
+ uint16 chanspec;
+ uint16 bf_sch_pending;
+ uint32 bf_link_prev;
+ uint32 bf_link_next;
+ uint32 onchan_time_l;
+ uint32 onchan_time_h;
+ uint32 actual_onchan_dur_l;
+ uint32 actual_onchan_dur_h;
+ uint32 pend_onchan_dur_l;
+ uint32 pend_onchan_dur_h;
+ uint16 req_entity_list_cnt;
+ uint16 req_entity_list_ptr;
+ uint16 bf_entity_list_cnt;
+ uint16 bf_entity_list_ptr;
+ uint32 bf_skipped_count;
+} msch_chan_ctxt_profiler_event_data_t;
+
+typedef struct msch_req_entity_profiler_event_data {
+ uint32 p_req_entity;
+ uint32 req_hdl_link_prev;
+ uint32 req_hdl_link_next;
+ uint32 chan_ctxt_link_prev;
+ uint32 chan_ctxt_link_next;
+ uint32 rt_specific_link_prev;
+ uint32 rt_specific_link_next;
+ uint32 start_fixed_link_prev;
+ uint32 start_fixed_link_next;
+ uint32 both_flex_list_prev;
+ uint32 both_flex_list_next;
+ uint16 chanspec;
+ uint16 priority;
+ uint16 cur_slot_ptr;
+ uint16 pend_slot_ptr;
+ uint16 pad;
+ uint16 chan_ctxt_ptr;
+ uint32 p_chan_ctxt;
+ uint32 p_req_hdl;
+ uint32 bf_last_serv_time_l;
+ uint32 bf_last_serv_time_h;
+ uint16 onchan_chn_idx;
+ uint16 cur_chn_idx;
+ uint32 flags;
+ uint32 actual_start_time_l;
+ uint32 actual_start_time_h;
+ uint32 curts_fire_time_l;
+ uint32 curts_fire_time_h;
+} msch_req_entity_profiler_event_data_t;
+
+typedef struct msch_req_handle_profiler_event_data {
+ uint32 p_req_handle;
+ uint32 p_prev;
+ uint32 p_next;
+ uint32 cb_func;
+ uint32 cb_ctxt;
+ uint16 req_param_ptr;
+ uint16 req_entity_list_cnt;
+ uint16 req_entity_list_ptr;
+ uint16 chan_cnt;
+ uint32 flags;
+ uint16 chanspec_list;
+ uint16 chanspec_cnt;
+ uint16 chan_idx;
+ uint16 last_chan_idx;
+ uint32 req_time_l;
+ uint32 req_time_h;
+} msch_req_handle_profiler_event_data_t;
+
+typedef struct msch_profiler_profiler_event_data {
+ uint32 time_lo; /* Request time */
+ uint32 time_hi;
+ uint32 free_req_hdl_list;
+ uint32 free_req_entity_list;
+ uint32 free_chan_ctxt_list;
+ uint32 free_chanspec_list;
+ uint16 cur_msch_timeslot_ptr;
+ uint16 next_timeslot_ptr;
+ uint32 p_cur_msch_timeslot;
+ uint32 p_next_timeslot;
+ uint32 cur_armed_timeslot;
+ uint32 flags;
+ uint32 ts_id;
+ uint32 service_interval;
+ uint32 max_lo_prio_interval;
+ uint16 flex_list_cnt;
+ uint16 msch_chanspec_alloc_cnt;
+ uint16 msch_req_entity_alloc_cnt;
+ uint16 msch_req_hdl_alloc_cnt;
+ uint16 msch_chan_ctxt_alloc_cnt;
+ uint16 msch_timeslot_alloc_cnt;
+ uint16 msch_req_hdl_list_cnt;
+ uint16 msch_req_hdl_list_ptr;
+ uint16 msch_chan_ctxt_list_cnt;
+ uint16 msch_chan_ctxt_list_ptr;
+ uint16 msch_req_timing_list_cnt;
+ uint16 msch_req_timing_list_ptr;
+ uint16 msch_start_fixed_list_cnt;
+ uint16 msch_start_fixed_list_ptr;
+ uint16 msch_both_flex_req_entity_list_cnt;
+ uint16 msch_both_flex_req_entity_list_ptr;
+ uint16 msch_start_flex_list_cnt;
+ uint16 msch_start_flex_list_ptr;
+ uint16 msch_both_flex_list_cnt;
+ uint16 msch_both_flex_list_ptr;
+ uint32 slotskip_flag;
+} msch_profiler_profiler_event_data_t;
+
+typedef struct msch_req_profiler_event_data {
+ uint32 time_lo; /* Request time */
+ uint32 time_hi;
+ uint16 chanspec_cnt;
+ uint16 chanspec_ptr;
+ uint16 req_param_ptr;
+ uint16 pad;
+} msch_req_profiler_event_data_t;
+
+typedef struct msch_callback_profiler_event_data {
+ uint32 time_lo; /* Request time */
+ uint32 time_hi;
+ uint16 type; /* callback type */
+ uint16 chanspec; /* actual chanspec, may different with requested one */
+ uint32 start_time_l; /* time slot start time low 32bit */
+ uint32 start_time_h; /* time slot start time high 32bit */
+ uint32 end_time_l; /* time slot end time low 32 bit */
+ uint32 end_time_h; /* time slot end time high 32 bit */
+ uint32 timeslot_id; /* unique time slot id */
+ uint32 p_req_hdl;
+ uint32 onchan_idx; /* Current channel index */
+ uint32 cur_chan_seq_start_time_l; /* start time of current sequence */
+ uint32 cur_chan_seq_start_time_h;
+} msch_callback_profiler_event_data_t;
+
+typedef struct msch_timeslot_profiler_event_data {
+ uint32 p_timeslot;
+ uint32 timeslot_id;
+ uint32 pre_start_time_l;
+ uint32 pre_start_time_h;
+ uint32 end_time_l;
+ uint32 end_time_h;
+ uint32 sch_dur_l;
+ uint32 sch_dur_h;
+ uint32 p_chan_ctxt;
+ uint32 fire_time_l;
+ uint32 fire_time_h;
+ uint32 state;
+} msch_timeslot_profiler_event_data_t;
+
+typedef struct msch_register_params {
+ uint16 wlc_index; /* Optional wlc index */
+ uint16 flags; /* Describe various request properties */
+ uint32 req_type; /* Describe start and end time flexiblilty */
+ uint16 id; /* register id */
+ uint16 priority; /* Define the request priority */
+ uint32 start_time; /* Requested start time offset in ms unit */
+ uint32 duration; /* Requested duration in ms unit */
+ uint32 interval; /* Requested periodic interval in ms unit,
+ * 0 means non-periodic
+ */
+ uint32 dur_flex; /* MSCH_REG_DUR_FLEX, min_dur = duration - dur_flex */
+ uint32 min_dur; /* min duration for traffic, maps to home_time */
+ uint32 max_away_dur; /* max acceptable away dur, maps to home_away_time */
+ uint32 hi_prio_time;
+ uint32 hi_prio_interval; /* repeated high priority interval */
+ uint32 chanspec_cnt;
+ uint16 chanspec_list[WL_MSCH_NUMCHANNELS];
+} msch_register_params_t;
+
+#endif /* _EVENT_LOG_PAYLOAD_H_ */
diff --git a/wl/components/shared/proto/event_log_set.h b/wl/components/shared/proto/event_log_set.h
new file mode 100644
index 0000000..fc9cc0d
--- /dev/null
+++ b/wl/components/shared/proto/event_log_set.h
@@ -0,0 +1,40 @@
+/*
+ * EVENT_LOG system definitions
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: event_log_set.h 585396 2015-09-10 09:04:56Z $
+ */
+
+#ifndef _EVENT_LOG_SET_H_
+#define _EVENT_LOG_SET_H_
+
+/* Set a maximum number of sets here. It is not dynamic for
+ * efficiency of the EVENT_LOG calls.
+ */
+#define NUM_EVENT_LOG_SETS 8
+
+/* Define new event log sets here */
+#define EVENT_LOG_SET_BUS 0
+#define EVENT_LOG_SET_WL 1
+#define EVENT_LOG_SET_PSM 2
+#define EVENT_LOG_SET_ERROR 3
+#define EVENT_LOG_SET_MEM_API 4
+#define EVENT_LOG_SET_ECOUNTERS 5 /* Host to instantiate this for ecounters. */
+
+#endif /* _EVENT_LOG_SET_H_ */
diff --git a/wl/components/shared/proto/event_log_tag.h b/wl/components/shared/proto/event_log_tag.h
new file mode 100644
index 0000000..187d174
--- /dev/null
+++ b/wl/components/shared/proto/event_log_tag.h
@@ -0,0 +1,196 @@
+/*
+ * EVENT_LOG system definitions
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: event_log_tag.h 660406 2016-09-20 11:21:19Z $
+ */
+
+#ifndef _EVENT_LOG_TAG_H_
+#define _EVENT_LOG_TAG_H_
+
+#include <typedefs.h>
+
+/* Define new event log tags here */
+#define EVENT_LOG_TAG_NULL 0 /* Special null tag */
+#define EVENT_LOG_TAG_TS 1 /* Special timestamp tag */
+#define EVENT_LOG_TAG_BUS_OOB 2
+#define EVENT_LOG_TAG_BUS_STATE 3
+#define EVENT_LOG_TAG_BUS_PROTO 4
+#define EVENT_LOG_TAG_BUS_CTL 5
+#define EVENT_LOG_TAG_BUS_EVENT 6
+#define EVENT_LOG_TAG_BUS_PKT 7
+#define EVENT_LOG_TAG_BUS_FRAME 8
+#define EVENT_LOG_TAG_BUS_DESC 9
+#define EVENT_LOG_TAG_BUS_SETUP 10
+#define EVENT_LOG_TAG_BUS_MISC 11
+#define EVENT_LOG_TAG_SRSCAN 22
+#define EVENT_LOG_TAG_PWRSTATS_INFO 23
+#define EVENT_LOG_TAG_UCODE_WATCHDOG 26
+#define EVENT_LOG_TAG_UCODE_FIFO 27
+#define EVENT_LOG_TAG_SCAN_TRACE_LOW 28
+#define EVENT_LOG_TAG_SCAN_TRACE_HIGH 29
+#define EVENT_LOG_TAG_SCAN_ERROR 30
+#define EVENT_LOG_TAG_SCAN_WARN 31
+#define EVENT_LOG_TAG_MPF_ERR 32
+#define EVENT_LOG_TAG_MPF_WARN 33
+#define EVENT_LOG_TAG_MPF_INFO 34
+#define EVENT_LOG_TAG_MPF_DEBUG 35
+#define EVENT_LOG_TAG_EVENT_INFO 36
+#define EVENT_LOG_TAG_EVENT_ERR 37
+#define EVENT_LOG_TAG_PWRSTATS_ERROR 38
+#define EVENT_LOG_TAG_EXCESS_PM_ERROR 39
+#define EVENT_LOG_TAG_IOCTL_LOG 40
+#define EVENT_LOG_TAG_PFN_ERR 41
+#define EVENT_LOG_TAG_PFN_WARN 42
+#define EVENT_LOG_TAG_PFN_INFO 43
+#define EVENT_LOG_TAG_PFN_DEBUG 44
+#define EVENT_LOG_TAG_BEACON_LOG 45
+#define EVENT_LOG_TAG_WNM_BSSTRANS_INFO 46
+#define EVENT_LOG_TAG_TRACE_CHANSW 47
+#define EVENT_LOG_TAG_PCI_ERROR 48
+#define EVENT_LOG_TAG_PCI_TRACE 49
+#define EVENT_LOG_TAG_PCI_WARN 50
+#define EVENT_LOG_TAG_PCI_INFO 51
+#define EVENT_LOG_TAG_PCI_DBG 52
+#define EVENT_LOG_TAG_PCI_DATA 53
+#define EVENT_LOG_TAG_PCI_RING 54
+/* EVENT_LOG_TAG_AWDL_TRACE_RANGING will be removed after wlc_ranging merge from IGUANA
+ * keeping it here to avoid compilation error on trunk
+ */
+#define EVENT_LOG_TAG_AWDL_TRACE_RANGING 55
+#define EVENT_LOG_TAG_RANGING_TRACE 55
+#define EVENT_LOG_TAG_WL_ERROR 56
+#define EVENT_LOG_TAG_PHY_ERROR 57
+#define EVENT_LOG_TAG_OTP_ERROR 58
+#define EVENT_LOG_TAG_NOTIF_ERROR 59
+#define EVENT_LOG_TAG_MPOOL_ERROR 60
+#define EVENT_LOG_TAG_OBJR_ERROR 61
+#define EVENT_LOG_TAG_DMA_ERROR 62
+#define EVENT_LOG_TAG_PMU_ERROR 63
+#define EVENT_LOG_TAG_BSROM_ERROR 64
+#define EVENT_LOG_TAG_SI_ERROR 65
+#define EVENT_LOG_TAG_ROM_PRINTF 66
+#define EVENT_LOG_TAG_RATE_CNT 67
+#define EVENT_LOG_TAG_CTL_MGT_CNT 68
+#define EVENT_LOG_TAG_AMPDU_DUMP 69
+#define EVENT_LOG_TAG_MEM_ALLOC_SUCC 70
+#define EVENT_LOG_TAG_MEM_ALLOC_FAIL 71
+#define EVENT_LOG_TAG_MEM_FREE 72
+#define EVENT_LOG_TAG_WL_ASSOC_LOG 73
+#define EVENT_LOG_TAG_WL_PS_LOG 74
+#define EVENT_LOG_TAG_WL_ROAM_LOG 75
+#define EVENT_LOG_TAG_WL_MPC_LOG 76
+#define EVENT_LOG_TAG_WL_WSEC_LOG 77
+#define EVENT_LOG_TAG_WL_WSEC_DUMP 78
+#define EVENT_LOG_TAG_WL_MCNX_LOG 79
+#define EVENT_LOG_TAG_HEALTH_CHECK_ERROR 80
+#define EVENT_LOG_TAG_HNDRTE_EVENT_ERROR 81
+#define EVENT_LOG_TAG_ECOUNTERS_ERROR 82
+#define EVENT_LOG_TAG_WL_COUNTERS 83
+#define EVENT_LOG_TAG_ECOUNTERS_IPCSTATS 84
+#define EVENT_LOG_TAG_WL_P2P_LOG 85
+#define EVENT_LOG_TAG_SDIO_ERROR 86
+#define EVENT_LOG_TAG_SDIO_TRACE 87
+#define EVENT_LOG_TAG_SDIO_DBG 88
+#define EVENT_LOG_TAG_SDIO_PRHDRS 89
+#define EVENT_LOG_TAG_SDIO_PRPKT 90
+#define EVENT_LOG_TAG_SDIO_INFORM 91
+#define EVENT_LOG_TAG_MIMO_PS_ERROR 92
+#define EVENT_LOG_TAG_MIMO_PS_TRACE 93
+#define EVENT_LOG_TAG_MIMO_PS_INFO 94
+#define EVENT_LOG_TAG_BTCX_STATS 95
+#define EVENT_LOG_TAG_LEAKY_AP_STATS 96
+#define EVENT_LOG_TAG_AWDL_TRACE_ELECTION 97
+#define EVENT_LOG_TAG_MIMO_PS_STATS 98
+#define EVENT_LOG_TAG_PWRSTATS_PHY 99
+#define EVENT_LOG_TAG_PWRSTATS_SCAN 100
+#define EVENT_LOG_TAG_PWRSTATS_AWDL 101
+#define EVENT_LOG_TAG_PWRSTATS_WAKE_V2 102
+#define EVENT_LOG_TAG_LQM 103
+#define EVENT_LOG_TAG_TRACE_WL_INFO 104
+#define EVENT_LOG_TAG_TRACE_BTCOEX_INFO 105
+#define EVENT_LOG_TAG_ECOUNTERS_TIME_DATA 106
+#define EVENT_LOG_TAG_NAN_ERROR 107
+#define EVENT_LOG_TAG_NAN_INFO 108
+#define EVENT_LOG_TAG_NAN_DBG 109
+#define EVENT_LOG_TAG_STF_ARBITRATOR_ERROR 110
+#define EVENT_LOG_TAG_STF_ARBITRATOR_TRACE 111
+#define EVENT_LOG_TAG_STF_ARBITRATOR_WARN 112
+#define EVENT_LOG_TAG_SCAN_SUMMARY 113
+#define EVENT_LOG_TAG_PROXD_SAMPLE_COLLECT 114
+#define EVENT_LOG_TAG_OCL_INFO 115
+#define EVENT_LOG_TAG_RSDB_PMGR_DEBUG 116
+#define EVENT_LOG_TAG_RSDB_PMGR_ERR 117
+#define EVENT_LOG_TAG_NAT_ERR 118
+#define EVENT_LOG_TAG_NAT_WARN 119
+#define EVENT_LOG_TAG_NAT_INFO 120
+#define EVENT_LOG_TAG_NAT_DEBUG 121
+#define EVENT_LOG_TAG_STA_INFO 122
+#define EVENT_LOG_TAG_PROXD_ERROR 123
+#define EVENT_LOG_TAG_PROXD_TRACE 124
+#define EVENT_LOG_TAG_PROXD_INFO 125
+#define EVENT_LOG_TAG_IE_ERROR 126
+#define EVENT_LOG_TAG_ASSOC_ERROR 127
+#define EVENT_LOG_TAG_SCAN_ERR 128
+#define EVENT_LOG_TAG_AMSDU_ERROR 129
+#define EVENT_LOG_TAG_AMPDU_ERROR 130
+#define EVENT_LOG_TAG_KM_ERROR 131
+#define EVENT_LOG_TAG_DFS 132
+#define EVENT_LOG_TAG_REGULATORY 133
+#define EVENT_LOG_TAG_CSA 134
+#define EVENT_LOG_TAG_WNM_BSSTRANS_ERR 135
+#define EVENT_LOG_TAG_SUP_INFO 136
+#define EVENT_LOG_TAG_SUP_ERROR 137
+#define EVENT_LOG_TAG_CHANCTXT_TRACE 138
+#define EVENT_LOG_TAG_CHANCTXT_INFO 139
+#define EVENT_LOG_TAG_CHANCTXT_ERROR 140
+#define EVENT_LOG_TAG_CHANCTXT_WARN 141
+#define EVENT_LOG_TAG_MSCHPROFILE 142
+#define EVENT_LOG_TAG_4WAYHANDSHAKE 143
+#define EVENT_LOG_TAG_MSCHPROFILE_TLV 144
+
+/* EVENT_LOG_TAG_MAX = Set to the same value of last tag, not last tag + 1 */
+#define EVENT_LOG_TAG_MAX 144
+/* Note: New event should be added/reserved in trunk before adding it to branches */
+
+
+#define SD_PRHDRS(i, s, h, p, n, l)
+#define SD_PRPKT(m, b, n)
+#define SD_INFORM(args)
+
+/* Flags for tag control */
+#define EVENT_LOG_TAG_FLAG_NONE 0
+#define EVENT_LOG_TAG_FLAG_LOG 0x80
+#define EVENT_LOG_TAG_FLAG_PRINT 0x40
+#define EVENT_LOG_TAG_FLAG_SET_MASK 0x3f
+
+/* Each event log entry has a type. The type is the LAST word of the
+ * event log. The printing code walks the event entries in reverse
+ * order to find the first entry.
+ */
+typedef union event_log_hdr {
+ struct {
+ uint8 tag; /* Event_log entry tag */
+ uint8 count; /* Count of 4-byte entries */
+ uint16 fmt_num; /* Format number */
+ };
+ uint32 t; /* Type cheat */
+} event_log_hdr_t;
+
+#endif /* _EVENT_LOG_TAG_H_ */
diff --git a/wl/components/shared/proto/mbo.h b/wl/components/shared/proto/mbo.h
new file mode 100644
index 0000000..5fa8e07
--- /dev/null
+++ b/wl/components/shared/proto/mbo.h
@@ -0,0 +1,272 @@
+/*
+ * Fundamental types and constants relating to WFA MBO
+ * (Multiband Operation)
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id$
+ */
+
+#ifndef _MBO_H_
+#define _MBO_H_
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* WiFi MBO OUI values */
+#define MBO_OUI WFA_OUI /* WiFi OUI 50:6F:9A */
+/* oui_type field identifying the type and version of the MBO IE. */
+#define MBO_OUI_TYPE WFA_OUI_TYPE_MBO /* OUI Type/Version */
+/* IEEE 802.11 vendor specific information element. */
+#define MBO_IE_ID 0xdd
+
+/* MBO ATTR related macros */
+#define MBO_ATTR_ID_OFF 0
+#define MBO_ATTR_LEN_OFF 1
+#define MBO_ATTR_DATA_OFF 2
+
+#define MBO_ATTR_ID_LEN 1 /* Attr ID field length */
+#define MBO_ATTR_LEN_LEN 1 /* Attr Length field length */
+#define MBO_ATTR_HDR_LEN 2 /* ID + 1-byte length field */
+
+/* MBO subelemts related */
+#define MBO_SUBELEM_ID 0xdd
+#define MBO_SUBELEM_OUI WFA_OUI
+
+#define MBO_SUBELEM_ID_LEN 1 /* SubElement ID field length */
+#define MBO_SUBELEM_LEN_LEN 1 /* SubElement length field length */
+#define MBO_SUBELEM_HDR_LEN 6 /* ID + length + OUI + OUY TYPE */
+
+#define MBO_NON_PREF_CHAN_SUBELEM_LEN_LEN(L) (7 + (L)) /* value of length field */
+#define MBO_NON_PREF_CHAN_SUBELEM_TOT_LEN(L) \
+ (MBO_SUBELEM_ID_LEN + MBO_SUBELEM_LEN_LEN + MBO_NON_PREF_CHAN_SUBELEM_LEN_LEN(L))
+/* MBO attributes as defined in the mbo spec */
+enum {
+ MBO_ATTR_MBO_AP_CAPABILITY = 1,
+ MBO_ATTR_NON_PREF_CHAN_REPORT = 2,
+ MBO_ATTR_CELL_DATA_CAP = 3,
+ MBO_ATTR_ASSOC_DISALLOWED = 4,
+ MBO_ATTR_CELL_DATA_CONN_PREF = 5,
+ MBO_ATTR_TRANS_REASON_CODE = 6,
+ MBO_ATTR_TRANS_REJ_REASON_CODE = 7,
+ MBO_ATTR_ASSOC_RETRY_DELAY = 8
+};
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_ie_s {
+ uint8 id; /* IE ID: MBO_IE_ID 0xDD */
+ uint8 len; /* IE length */
+ uint8 oui[WFA_OUI_LEN]; /* MBO_OUI 50:6F:9A */
+ uint8 oui_type; /* MBO_OUI_TYPE 0x16 */
+ uint8 attr[1]; /* var len attributes */
+} BWL_POST_PACKED_STRUCT wifi_mbo_ie_t;
+
+#define MBO_IE_HDR_SIZE (OFFSETOF(wifi_mbo_ie_t, attr))
+/* oui:3 bytes + oui type:1 byte */
+#define MBO_IE_NO_ATTR_LEN 4
+
+/* MBO AP Capability Attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_ap_cap_ind_attr_s {
+ /* Attribute ID - 0x01. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint8 len;
+ /* AP capability bitmap */
+ uint8 cap_ind;
+} BWL_POST_PACKED_STRUCT wifi_mbo_ap_cap_ind_attr_t;
+
+/* MBO AP Capability Indication Field Values */
+#define MBO_AP_CAP_IND_CELLULAR_AWARE 0x40
+
+/* Non-preferred Channel Report Attribute */
+#define MBO_NON_PREF_CHAN_ATTR_OPCALSS_OFF 2
+#define MBO_NON_PREF_CHAN_ATTR_CHANLIST_OFF 3
+#define MBO_NON_PREF_CHAN_ATTR_PREF_OFF(L) \
+ (MBO_NON_PREF_CHAN_ATTR_CHANLIST_OFF + (L))
+
+#define MBO_NON_PREF_CHAN_ATTR_OPCALSS_LEN 1
+#define MBO_NON_PREF_CHAN_ATTR_PREF_LEN 1
+#define MBO_NON_PREF_CHAN_ATTR_REASON_LEN 1
+
+#define MBO_NON_PREF_CHAN_ATTR_LEN(L) ((L) + 3)
+#define MBO_NON_PREF_CHAN_ATTR_TOT_LEN(L) (MBO_ATTR_HDR_LEN + (L) + 3)
+
+/* attribute len - (opclass + Pref + Reason) */
+#define MBO_NON_PREF_CHAN_ATTR_CHANLIST_LEN(L) ((L) - 3)
+
+/* MBO Non-preferred Channel Report: "Preference" field value */
+enum {
+ MBO_STA_NON_OPERABLE_BAND_CHAN = 0,
+ MBO_STA_NON_PREFERRED_BAND_CHAN = 1,
+ MBO_STA_PREFERRED_BAND_CHAN = 255
+};
+
+/* MBO Non-preferred Channel Report: "Reason Code" field value */
+enum {
+ MBO_NON_PREF_CHAN_RC_UNSPECIFIED = 0,
+ MBO_NON_PREF_CHAN_RC_BCN_STRENGTH = 1,
+ MBO_NON_PREF_CHAN_RC_CO_LOC_INTERFERENCE = 2,
+ MBO_NON_PREF_CHAN_RC_IN_DEV_INTERFERENCE = 3
+};
+
+/* Cellular Data Capability Attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_cell_data_cap_attr_s {
+ /* Attribute ID - 0x03. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint8 len;
+ /* MBO STA's cellular capability */
+ uint8 cell_conn;
+} BWL_POST_PACKED_STRUCT wifi_mbo_cell_data_cap_attr_t;
+
+/* MBO Cellular Data Capability: "Cellular Connectivity" field value */
+enum {
+ MBO_CELL_DATA_CONN_AVAILABLE = 1,
+ MBO_CELL_DATA_CONN_NOT_AVAILABLE = 2,
+ MBO_CELL_DATA_CONN_NOT_CAPABLE = 3
+};
+
+/* Association Disallowed attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_assoc_disallowed_attr_s {
+ /* Attribute ID - 0x04. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint8 len;
+ /* Reason of not accepting new association */
+ uint8 reason_code;
+} BWL_POST_PACKED_STRUCT wifi_mbo_assoc_disallowed_attr_t;
+
+/* Association Disallowed attr Reason code field values */
+enum {
+ MBO_ASSOC_DISALLOWED_RC_UNSPECIFIED = 1,
+ MBO_ASSOC_DISALLOWED_RC_MAX_STA_REACHED = 2,
+ MBO_ASSOC_DISALLOWED_RC_AIR_IFACE_OVERLOADED = 3,
+ MBO_ASSOC_DISALLOWED_RC_AUTH_SRVR_OVERLOADED = 4,
+ MBO_ASSOC_DISALLOWED_RC_INSUFFIC_RSSI = 5
+};
+
+/* Cellular Data Conn Pref attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_cell_data_conn_pref_attr_s {
+ /* Attribute ID - 0x05. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint8 len;
+ /* Preference value of cellular connection */
+ uint8 cell_pref;
+} BWL_POST_PACKED_STRUCT wifi_mbo_cell_data_conn_pref_attr_t;
+
+/* Cellular Data Conn Pref attr: Cellular Pref field values */
+enum {
+ MBO_CELLULAR_DATA_CONN_EXCLUDED = 1,
+ MBO_CELLULAR_DATA_CONN_NOT_PREFERRED = 2,
+ MBO_CELLULAR_DATA_CONN_PREFERRED = 255
+};
+
+/* Transition Reason Code Attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_trans_reason_code_attr_s {
+ /* Attribute ID - 0x06. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint8 len;
+ /* Reason of transition recommendation */
+ uint8 trans_reason_code;
+} BWL_POST_PACKED_STRUCT wifi_mbo_trans_reason_code_attr_t;
+
+/* Transition Reason Code Attr: trans reason code field values */
+enum {
+ MBO_TRANS_REASON_UNSPECIFIED = 0,
+ MBO_TRANS_REASON_EXCESSV_FRM_LOSS_RATE = 1,
+ MBO_TRANS_REASON_EXCESSV_TRAFFIC_DELAY = 2,
+ MBO_TRANS_REASON_INSUFF_BW = 3,
+ MBO_TRANS_REASON_LOAD_BALANCING = 4,
+ MBO_TRANS_REASON_LOW_RSSI = 5,
+ MBO_TRANS_REASON_EXCESSV_RETRANS_RCVD = 6,
+ MBO_TRANS_REASON_HIGH_INTERFERENCE = 7,
+ MBO_TRANS_REASON_GRAY_ZONE = 8,
+ MBO_TRANS_REASON_PREMIUM_AP_TRANS = 9
+};
+
+/* Transition Rejection Reason Code Attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_trans_rej_reason_code_attr_s {
+ /* Attribute ID - 0x07. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint8 len;
+ /* Reason of transition rejection */
+ uint8 trans_rej_reason_code;
+} BWL_POST_PACKED_STRUCT wifi_mbo_trans_rej_reason_code_attr_t;
+
+/* Transition Rej Reason Code Attr: trans rej reason code field values */
+enum {
+ MBO_TRANS_REJ_REASON_UNSPECIFIED = 0,
+ MBO_TRANS_REJ_REASON_EXSSIV_FRM_LOSS_RATE = 1,
+ MBO_TRANS_REJ_REASON_EXSSIV_TRAFFIC_DELAY = 2,
+ MBO_TRANS_REJ_REASON_INSUFF_QOS_CAPACITY = 3,
+ MBO_TRANS_REJ_REASON_LOW_RSSI = 4,
+ MBO_TRANS_REJ_REASON_HIGH_INTERFERENCE = 5,
+ MBO_TRANS_REJ_REASON_SERVICE_UNAVAIL = 6
+};
+
+/* Assoc Retry Delay Attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_assoc_retry_delay_attr_s {
+ /* Attribute ID - 0x08. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint8 len;
+ /* No of Seconds before next assoc attempt */
+ uint16 reassoc_delay;
+} BWL_POST_PACKED_STRUCT wifi_mbo_assoc_retry_delay_attr_t;
+
+#define MBO_ANQP_OUI_TYPE 0x12 /* OUTI Type/Version */
+
+/* MBO ANQP Element */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_anqp_elem_s {
+ /* ID - 56797 */
+ uint16 info_id;
+ /* Length of the OUI + Vendor Specific content */
+ uint16 len;
+ /* WFA_OUI 50:6F:9A */
+ uint8 oui[WFA_OUI_LEN];
+ /* MBO_ANQP_OUI_TYPE 0x12 */
+ uint8 oui_type;
+ /* MBO ANQP element type */
+ uint8 sub_type;
+ /* variable len payload */
+ uint8 payload[1];
+} BWL_POST_PACKED_STRUCT wifi_mbo_anqp_elem_t;
+
+/* MBO ANQP Subtype Values */
+enum {
+ MBO_ANQP_ELEM_CELL_DATA_CONN_PREF = 1
+};
+
+/* MBO sub-elements */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_mbo_cell_cap_subelem_s {
+ /* 0xDD */
+ uint8 sub_elem_id;
+ /* Length of the following fields in sub-element */
+ uint8 len;
+ /* WFA_OUI 50:6F:9A */
+ uint8 oui[WFA_OUI_LEN];
+ /* OUI_TYPE 0x03 */
+ uint8 oui_type;
+ /* STA cellular capability */
+ uint8 cell_conn;
+} BWL_POST_PACKED_STRUCT wifi_mbo_cell_cap_subelem_t;
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* __MBO_H__ */
diff --git a/wl/components/shared/proto/nan.h b/wl/components/shared/proto/nan.h
new file mode 100644
index 0000000..63ca306
--- /dev/null
+++ b/wl/components/shared/proto/nan.h
@@ -0,0 +1,1223 @@
+/*
+ * Fundamental types and constants relating to WFA NAN
+ * (Neighbor Awareness Networking)
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: nan.h 660905 2016-09-22 10:38:41Z $
+ */
+#ifndef _NAN_H_
+#define _NAN_H_
+
+#include <typedefs.h>
+#include <proto/802.11.h>
+
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* WiFi NAN OUI values */
+#define NAN_OUI WFA_OUI /* WiFi OUI */
+/* For oui_type field identifying the type and version of the NAN IE. */
+#define NAN_OUI_TYPE 0x13 /* Type/Version */
+#define NAN_AF_OUI_TYPE 0x18 /* Type/Version */
+/* IEEE 802.11 vendor specific information element. (Same as P2P_IE_ID.) */
+#define NAN_IE_ID 0xdd
+
+/* Same as P2P_PUB_AF_CATEGORY and DOT11_ACTION_CAT_PUBLIC */
+#define NAN_PUB_AF_CATEGORY 0x04
+/* IEEE 802.11 Public Action Frame Vendor Specific. (Same as P2P_PUB_AF_ACTION.) */
+#define NAN_PUB_AF_ACTION 0x09
+/* Number of octents in hash of service name. (Same as P2P_WFDS_HASH_LEN.) */
+#define NAN_SVC_HASH_LEN 6
+/* Size of fixed length part of nan_pub_act_frame_t before attributes. */
+#define NAN_PUB_ACT_FRAME_FIXED_LEN 6
+/* Number of octents in master rank value. */
+#define NAN_MASTER_RANK_LEN 8
+/* NAN public action frame header size */
+#define NAN_PUB_ACT_FRAME_HDR_SIZE (OFFSETOF(nan_pub_act_frame_t, data))
+/* NAN network ID */
+#define NAN_NETWORK_ID "\x51\x6F\x9A\x01\x00\x00"
+/* Service Control Type length */
+#define NAN_SVC_CONTROL_TYPE_LEN 2
+/* Binding Bitmap length */
+#define NAN_BINDING_BITMAP_LEN 2
+/* Service Response Filter (SRF) control field masks */
+#define NAN_SRF_BLOOM_MASK 0x01
+#define NAN_SRF_INCLUDE_MASK 0x02
+#define NAN_SRF_INDEX_MASK 0x0C
+/* SRF Bloom Filter index shift */
+#define NAN_SRF_BLOOM_SHIFT 2
+#define NAN_SRF_INCLUDE_SHIFT 1
+/* Mask for CRC32 output, used in hash function for NAN bloom filter */
+#define NAN_BLOOM_CRC32_MASK 0xFFFF
+
+/* Attribute TLV header size */
+#define NAN_ATTR_ID_OFF 0
+#define NAN_ATTR_LEN_OFF 1
+#define NAN_ATTR_DATA_OFF 3
+
+#define NAN_ATTR_ID_LEN 1 /* ID field length */
+#define NAN_ATTR_LEN_LEN 2 /* Length field length */
+#define NAN_ATTR_HDR_LEN (NAN_ATTR_ID_LEN + NAN_ATTR_LEN_LEN)
+#define NAN_ENTRY_CTRL_LEN 1 /* Entry control field length from FAM attribute */
+#define NAN_MAP_ID_LEN 1 /* MAP ID length to signify band */
+#define NAN_OPERATING_CLASS_LEN 1 /* operating class field length from NAN FAM */
+#define NAN_CHANNEL_NUM_LEN 1 /* channel number field length 1 byte */
+
+#define NAN_MAP_ID_2G 2 /* NAN Further Avail Map ID for band 2.4G */
+#define NAN_MAP_ID_5G 5 /* NAN Further Avail Map ID for band 5G */
+#define NAN_MAP_NUM_IDS 2 /* Max number of NAN Further Avail Map IDs supported */
+
+/* map id is 4 bits */
+#define NAN_CMN_MAP_ID_LEN_BITS 4
+/* siz eof ndc id */
+#define NAN_DATA_NDC_ID_SIZE 6
+
+#define NAN_AVAIL_ENTRY_LEN_RES0 7 /* Avail entry len in FAM attribute for resolution 16TU */
+#define NAN_AVAIL_ENTRY_LEN_RES1 5 /* Avail entry len in FAM attribute for resolution 32TU */
+#define NAN_AVAIL_ENTRY_LEN_RES2 4 /* Avail entry len in FAM attribute for resolution 64TU */
+
+/* Vendor-specific public action frame for NAN */
+typedef BWL_PRE_PACKED_STRUCT struct nan_pub_act_frame_s {
+ /* NAN_PUB_AF_CATEGORY 0x04 */
+ uint8 category_id;
+ /* NAN_PUB_AF_ACTION 0x09 */
+ uint8 action_field;
+ /* NAN_OUI 0x50-6F-9A */
+ uint8 oui[DOT11_OUI_LEN];
+ /* NAN_OUI_TYPE 0x13 */
+ uint8 oui_type;
+ /* One or more NAN Attributes follow */
+ uint8 data[];
+} BWL_POST_PACKED_STRUCT nan_pub_act_frame_t;
+
+/* NAN attributes as defined in the nan spec */
+enum {
+ NAN_ATTR_MASTER_IND = 0,
+ NAN_ATTR_CLUSTER = 1,
+ NAN_ATTR_SVC_ID_LIST = 2,
+ NAN_ATTR_SVC_DESCRIPTOR = 3,
+ NAN_ATTR_CONN_CAP = 4,
+ NAN_ATTR_INFRA = 5,
+ NAN_ATTR_P2P = 6,
+ NAN_ATTR_IBSS = 7,
+ NAN_ATTR_MESH = 8,
+ NAN_ATTR_FURTHER_NAN_SD = 9,
+ NAN_ATTR_FURTHER_AVAIL = 10,
+ NAN_ATTR_COUNTRY_CODE = 11,
+ NAN_ATTR_RANGING = 12,
+ NAN_ATTR_CLUSTER_DISC = 13,
+ /* nan 2.0 */
+ NAN_ATTR_SVC_DESC_EXTENSION = 14,
+ NAN_ATTR_NAN_DEV_CAP = 15,
+ NAN_ATTR_NAN_NDP = 16,
+ NAN_ATTR_NAN_NMSG = 17,
+ NAN_ATTR_NAN_AVAIL = 18,
+ NAN_ATTR_NAN_NDC = 19,
+ NAN_ATTR_NAN_NDL = 20,
+ NAN_ATTR_NAN_NDL_QOS = 21,
+ NAN_ATTR_MCAST_SCHED = 22,
+ NAN_ATTR_UNALIGN_SCHED = 23,
+ NAN_ATTR_PAGING_UCAST = 24,
+ NAN_ATTR_PAGING_MCAST = 25,
+ NAN_ATTR_RANGING_INFO = 26,
+ NAN_ATTR_RANGING_SETUP = 27,
+ NAN_ATTR_FTM_RANGE_REPORT = 28,
+ NAN_ATTR_ELEMENT_CONTAINER = 29,
+ NAN_ATTR_WLAN_INFRA_EXT = 30,
+ NAN_ATTR_EXT_P2P_OPER = 31,
+ NAN_ATTR_EXT_IBSS = 32,
+ NAN_ATTR_EXT_MESH = 33,
+
+ NAN_ATTR_VENDOR_SPECIFIC = 221,
+ NAN_ATTR_NAN_MGMT = 222 /* NAN Mgmt Attr (TBD; not in spec yet) */
+};
+
+enum wifi_nan_avail_resolution {
+ NAN_AVAIL_RES_16_TU = 0,
+ NAN_AVAIL_RES_32_TU = 1,
+ NAN_AVAIL_RES_64_TU = 2,
+ NAN_AVAIL_RES_INVALID = 255
+};
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ie_s {
+ uint8 id; /* IE ID: NAN_IE_ID 0xDD */
+ uint8 len; /* IE length */
+ uint8 oui[DOT11_OUI_LEN]; /* NAN_OUI 50:6F:9A */
+ uint8 oui_type; /* NAN_OUI_TYPE 0x13 */
+ uint8 attr[]; /* var len attributes */
+} BWL_POST_PACKED_STRUCT wifi_nan_ie_t;
+
+#define NAN_IE_HDR_SIZE (OFFSETOF(wifi_nan_ie_t, attr))
+
+/* master indication record */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_master_ind_attr_s {
+ uint8 id;
+ uint16 len;
+ uint8 master_preference;
+ uint8 random_factor;
+} BWL_POST_PACKED_STRUCT wifi_nan_master_ind_attr_t;
+
+/* cluster attr record */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_cluster_attr_s {
+ uint8 id;
+ uint16 len;
+ uint8 amr[NAN_MASTER_RANK_LEN];
+ uint8 hop_count;
+ /* Anchor Master Beacon Transmission Time */
+ uint32 ambtt;
+} BWL_POST_PACKED_STRUCT wifi_nan_cluster_attr_t;
+
+/* container for service ID records */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_id_attr_s {
+ uint8 id;
+ uint16 len;
+ uint8 svcid[0]; /* 6*len of srvc IDs */
+} BWL_POST_PACKED_STRUCT wifi_nan_svc_id_attr_t;
+
+/* service_control bitmap for wifi_nan_svc_descriptor_attr_t below */
+#define NAN_SC_PUBLISH 0x0
+#define NAN_SC_SUBSCRIBE 0x1
+#define NAN_SC_FOLLOWUP 0x2
+/* Set to 1 if a Matching Filter field is included in descriptors. */
+#define NAN_SC_MATCHING_FILTER_PRESENT 0x4
+/* Set to 1 if a Service Response Filter field is included in descriptors. */
+#define NAN_SC_SR_FILTER_PRESENT 0x8
+/* Set to 1 if a Service Info field is included in descriptors. */
+#define NAN_SC_SVC_INFO_PRESENT 0x10
+/* range is close proximity only */
+#define NAN_SC_RANGE_LIMITED 0x20
+/* Set to 1 if binding bitamp is present in descriptors */
+#define NAN_SC_BINDING_BITMAP_PRESENT 0x40
+
+/* Service descriptor */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_descriptor_attr_s {
+ /* Attribute ID - 0x03. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint16 len;
+ /* Hash of the Service Name */
+ uint8 svc_hash[NAN_SVC_HASH_LEN];
+ /* Publish or subscribe instance id */
+ uint8 instance_id;
+ /* Requestor Instance ID */
+ uint8 requestor_id;
+ /* Service Control Bitmask. Also determines what data follows. */
+ uint8 svc_control;
+ /* Optional fields follow */
+} BWL_POST_PACKED_STRUCT wifi_nan_svc_descriptor_attr_t;
+
+/* IBSS attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ibss_attr_s {
+ /* Attribute ID - 0x07. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint16 len;
+ /* BSSID of the ibss */
+ struct ether_addr bssid;
+ /*
+ map control:, bits:
+ [0-3]: Id for associated further avail map attribute
+ [4-5]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; 3:reserved
+ [6] : repeat : 0 - applies to next DW, 1: 16 intervals max? wtf?
+ [7] : reserved
+ */
+ uint8 map_ctrl;
+ /* avail. intervals bitmap, var len */
+ uint8 avail_bmp[1];
+} BWL_POST_PACKED_STRUCT wifi_nan_ibss_attr_t;
+
+/* Further Availability MAP attr */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_favail_attr_s {
+ /* Attribute ID - 0x0A. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint16 len;
+ /* MAP id: val [0..15], values[16-255] reserved */
+ uint8 map_id;
+ /* availibility entry, var len */
+ uint8 avil_entry[1];
+} BWL_POST_PACKED_STRUCT wifi_nan_favail_attr_t;
+
+/* Further Availability MAP attr */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_entry_s {
+ /*
+ entry control
+ [0-1]: avail interval duration: 0:16ms; 1:32ms; 2:64ms;
+ [2:7] reserved
+ */
+ uint8 entry_ctrl;
+ /* operating class: freq band etc IEEE 802.11 */
+ uint8 opclass;
+ /* channel number */
+ uint8 chan;
+ /* avail bmp, var len */
+ uint8 avail_bmp[1];
+} BWL_POST_PACKED_STRUCT wifi_nan_avail_entry_t;
+
+/* Map control Field */
+#define NAN_MAPCTRL_IDMASK 0x7
+#define NAN_MAPCTRL_DURSHIFT 4
+#define NAN_MAPCTRL_DURMASK 0x30
+#define NAN_MAPCTRL_REPEAT 0x40
+#define NAN_MAPCTRL_REPEATSHIFT 6
+
+#define NAN_VENDOR_TYPE_RTT 0
+#define NAN_VENDOR_TYPE_P2P 1
+
+/* Vendor Specific Attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_vendor_attr_s {
+ uint8 id; /* 0xDD */
+ uint16 len; /* IE length */
+ uint8 oui[DOT11_OUI_LEN]; /* 00-90-4C */
+ uint8 type; /* attribute type */
+ uint8 attr[1]; /* var len attributes */
+} BWL_POST_PACKED_STRUCT wifi_nan_vendor_attr_t;
+
+#define NAN_VENDOR_HDR_SIZE (OFFSETOF(wifi_nan_vendor_attr_t, attr))
+
+/* p2p operation attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_p2p_op_attr_s {
+ /* Attribute ID - 0x06. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint16 len;
+ /* P2P device role */
+ uint8 dev_role;
+ /* BSSID of the ibss */
+ struct ether_addr p2p_dev_addr;
+ /*
+ map control:, bits:
+ [0-3]: Id for associated further avail map attribute
+ [4-5]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; 3:reserved
+ [6] : repeat : 0 - applies to next DW, 1: 16 intervals max? wtf?
+ [7] : reserved
+ */
+ uint8 map_ctrl;
+ /* avail. intervals bitmap */
+ uint8 avail_bmp[1];
+} BWL_POST_PACKED_STRUCT wifi_nan_p2p_op_attr_t;
+
+/* ranging attribute */
+#define NAN_RANGING_MAP_CTRL_ID_SHIFT 0
+#define NAN_RANGING_MAP_CTRL_ID_MASK 0x0F
+#define NAN_RANGING_MAP_CTRL_DUR_SHIFT 4
+#define NAN_RANGING_MAP_CTRL_DUR_MASK 0x30
+#define NAN_RANGING_MAP_CTRL_REPEAT_SHIFT 6
+#define NAN_RANGING_MAP_CTRL_REPEAT_MASK 0x40
+#define NAN_RANGING_MAP_CTRL_REPEAT_DW(_ctrl) (((_ctrl) & \
+ NAN_RANGING_MAP_CTRL_DUR_MASK) ? 16 : 1)
+#define NAN_RANGING_MAP_CTRL(_id, _dur, _repeat) (\
+ (((_id) << NAN_RANGING_MAP_CTRL_ID_SHIFT) & \
+ NAN_RANGING_MAP_CTRL_ID_MASK) | \
+ (((_dur) << NAN_RANGING_MAP_CTRL_DUR_SHIFT) & \
+ NAN_RANGING_MAP_CTRL_DUR_MASK) | \
+ (((_repeat) << NAN_RANGING_MAP_CTRL_REPEAT_SHIFT) & \
+ NAN_RANGING_MAP_CTRL_REPEAT_MASK))
+
+enum {
+ NAN_RANGING_PROTO_FTM = 0
+};
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_attr_s {
+ uint8 id; /* 0x0C */
+ uint16 len; /* length that follows */
+ struct ether_addr dev_addr; /* device mac address */
+
+ /*
+ map control:, bits:
+ [0-3]: Id for associated further avail map attribute
+ [4-5]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; 3:reserved
+ [6] : repeat : 0 - applies to next DW, 1: 16 intervals max? wtf?
+ [7] : reserved
+ */
+ uint8 map_ctrl;
+
+ uint8 protocol; /* FTM = 0 */
+ uint32 avail_bmp; /* avail interval bitmap */
+} BWL_POST_PACKED_STRUCT wifi_nan_ranging_attr_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_info_attr_s {
+ uint8 id; /* 0x1A */
+ uint16 len; /* length that follows */
+ /*
+ location info availability bit map
+ 0: LCI Local Coordinates
+ 1: Geospatial LCI WGS84
+ 2: Civi Location
+ 3: Last Movement Indication
+ [4-7]: reserved
+ */
+ uint8 lc_info_avail;
+ /*
+ Last movement indication
+ present if bit 3 is set in lc_info_avail
+ cluster TSF[29:14] at the last detected platform movement
+ */
+ uint16 last_movement;
+
+} BWL_POST_PACKED_STRUCT wifi_nan_ranging_info_attr_t;
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_setup_attr_hdr_s {
+ uint8 id; /* 0x1B */
+ uint16 len; /* length that follows */
+ uint8 dialog_token; /* Identify req and resp */
+ uint8 type_status; /* bits 0-3 type, 4-7 status */
+ /* reason code
+ i. when frm type = response & status = reject
+ ii. frm type = termination
+ */
+ uint8 reason;
+} BWL_POST_PACKED_STRUCT wifi_nan_ranging_setup_attr_hdr_t;
+
+/* Common time structure used in NAN Availability, NDC, Immutable schedules */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_time_bitmap_s {
+ uint16 ctrl; /* Time bitmap control */
+ uint8 len; /* Time bitmap length */
+ uint8 bitmap[1]; /* Time bitmap */
+} BWL_POST_PACKED_STRUCT wifi_nan_time_bitmap_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_time_bitmap_s {
+ uint8 map_id; /* Map ID to which this bit map corresponds */
+ wifi_nan_time_bitmap_t time_bmp;
+} BWL_POST_PACKED_STRUCT wifi_nan_ranging_time_bitmap_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_setup_attr_s {
+
+ wifi_nan_ranging_setup_attr_hdr_t setup_attr_hdr;
+ /* Below fields not required when frm type = termination */
+ uint8 ranging_ctrl; /* Bit 0: ranging report required or not */
+ uint8 ftm_params[3];
+ wifi_nan_ranging_time_bitmap_t range_tbm; /* Ranging timebit map info */
+} BWL_POST_PACKED_STRUCT wifi_nan_ranging_setup_attr_t;
+#define NAN_RANGE_SETUP_ATTR_OFFSET_TBM_INFO (OFFSETOF(wifi_nan_ranging_setup_attr_t, range_tbm))
+
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_report_attr_s {
+ uint8 id; /* 0x1C */
+ uint16 len; /* length that follows */
+ /* FTM report format in spec.
+ See definition in 9.4.2.22.18 in 802.11mc D5.0
+ */
+ uint8 entry_count;
+ uint8 data[2]; /* includes pad */
+ /*
+ dot11_ftm_range_entry_t entries[entry_count];
+ uint8 error_count;
+ dot11_ftm_error_entry_t errors[error_count];
+ */
+} BWL_POST_PACKED_STRUCT wifi_nan_ranging_report_attr_t;
+
+/* Ranging control flags */
+#define NAN_RNG_REPORT_REQUIRED 0x01
+/* Location info flags */
+#define NAN_RNG_LOCATION_FLAGS_LOCAL_CORD 0x1
+#define NAN_RNG_LOCATION_FLAGS_GEO_SPATIAL 0x2
+#define NAN_RNG_LOCATION_FLAGS_CIVIC 0x4
+#define NAN_RNG_LOCATION_FLAGS_LAST_MVMT 0x8
+/* Last movement mask and shift value */
+#define NAN_RNG_LOCATION_MASK_LAST_MVT_TSF 0x3FFFC000
+#define NAN_RNG_LOCATION_SHIFT_LAST_MVT_TSF 14
+
+/* FTM params shift values */
+#define NAN_RNG_FTM_MAX_BURST_DUR_S 0
+#define NAN_RNG_FTM_MIN_FTM_DELTA_S 4
+#define NAN_RNG_FTM_NUM_FTM_S 10
+#define NAN_RNG_FTM_FORMAT_BW_S 15
+
+/* FTM params mask */
+#define NAN_RNG_FTM_MAX_BURST_DUR 0x00000F
+#define NAN_RNG_FTM_MIN_FTM_DELTA 0x00003F
+#define NAN_RNG_FTM_NUM_FTM 0x00001F
+#define NAN_RNG_FTM_FORMAT_BW 0x00003F
+
+#define NAN_CONN_CAPABILITY_WFD 0x0001
+#define NAN_CONN_CAPABILITY_WFDS 0x0002
+#define NAN_CONN_CAPABILITY_TDLS 0x0004
+#define NAN_CONN_CAPABILITY_INFRA 0x0008
+#define NAN_CONN_CAPABILITY_IBSS 0x0010
+#define NAN_CONN_CAPABILITY_MESH 0x0020
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_conn_cap_attr_s {
+ /* Attribute ID - 0x04. */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint16 len;
+ uint16 conn_cap_bmp; /* Connection capability bitmap */
+} BWL_POST_PACKED_STRUCT wifi_nan_conn_cap_attr_t;
+
+#define NAN_SLOT_RES_16TU 16
+#define NAN_SLOT_RES_32TU 32
+#define NAN_SLOT_RES_64TU 64
+#define NAN_SLOT_RES_128TU 128
+
+/* Attribute Control field */
+#define NAN_ATTR_CNTRL_MAP_ID_MASK 0x0F /* Map Id */
+#define NAN_ATTR_CNTRL_RSVD_MASK 0xF0 /* Reserved */
+#define NAN_ATTR_CNTRL_SEQ_ID_MASK 0xFF /* Seq Id */
+
+/* NAN Element container Attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_container_attr_s {
+ uint8 id; /* id - 0x20 */
+ uint16 len; /* Total length of following IEs */
+ uint8 data[1]; /* Data pointing to one or more IEs */
+} BWL_POST_PACKED_STRUCT wifi_nan_container_attr_t;
+
+/* NAN 2.0 NAN avail attribute */
+
+/* Availability Attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_attr_s {
+ uint8 id; /* id - 0x12 */
+ uint16 len; /* total length */
+ uint16 ctrl; /* attribute control */
+ uint8 entry[1]; /* availability entry list */
+} BWL_POST_PACKED_STRUCT wifi_nan_avail_attr_t;
+
+/* Availability Entry format */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_entry_attr_s {
+ uint16 len; /* Length */
+ uint16 entry_cntrl; /* Entry Control */
+ uint8 var[1]; /* Time bitmap fields and channel entry list */
+} BWL_POST_PACKED_STRUCT wifi_nan_avail_entry_attr_t;
+
+/* FAC Channel Entry (section 10.7.19.1.5) */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_chan_entry_s {
+ uint8 oper_class; /* Operating Class */
+ uint16 chan_bitmap; /* Channel Bitmap */
+ uint8 primary_chan_bmp; /* Primary Channel Bitmap */
+ uint8 aux_chan[0]; /* Auxiliary Channel bitmap */
+} BWL_POST_PACKED_STRUCT wifi_nan_chan_entry_t;
+
+#define NAN_AVAIL_CTRL_SEQ_ID_SHIFT 8
+
+#define NAN_AVAIL_ENTRY_CTRL_AVAIL_TYPE_MASK 0x07
+#define NAN_AVAIL_ENTRY_CTRL_AVAIL_TYPE(_flags) ((_flags) & NAN_AVAIL_ENTRY_CTRL_AVAIL_TYPE_MASK)
+#define NAN_AVAIL_ENTRY_CTRL_USAGE_MASK 0x18
+#define NAN_AVAIL_ENTRY_CTRL_USAGE_SHIFT 3
+#define NAN_AVAIL_ENTRY_CTRL_USAGE(_flags) ((_flags) & NAN_AVAIL_ENTRY_CTRL_USAGE_MASK) \
+ >> NAN_AVAIL_ENTRY_CTRL_USAGE_SHIFT
+#define NAN_AVAIL_ENTRY_CTRL_RX_NSS_MASK 0xF00
+#define NAN_AVAIL_ENTRY_CTRL_RX_NSS_SHIFT 8
+#define NAN_AVAIL_ENTRY_CTRL_RX_NSS(_flags) (((_flags) & NAN_AVAIL_ENTRY_CTRL_RX_NSS_MASK) \
+ >> NAN_AVAIL_ENTRY_CTRL_RX_NSS_SHIFT)
+#define NAN_AVAIL_ENTRY_CTRL_PAGING_MASK 0x1000
+#define NAN_AVAIL_ENTRY_CTRL_PAGING_SHIFT 12
+#define NAN_AVAIL_ENTRY_CTRL_PAGING(_flags) (((_flags) & NAN_AVAIL_ENTRY_CTRL_PAGING_MASK) \
+ >> NAN_AVAIL_ENTRY_CTRL_PAGING_SHIFT)
+#define NAN_AVAIL_ENTRY_CTRL_BITMAP_PRESENT_MASK 0x2000
+#define NAN_AVAIL_ENTRY_CTRL_BITMAP_PRESENT_SHIFT 13
+#define NAN_AVAIL_ENTRY_CTRL_BITMAP_PRESENT(_flags) ((_flags) & \
+ NAN_AVAIL_ENTRY_CTRL_BITMAP_PRESENT_MASK) >> NAN_AVAIL_ENTRY_CTRL_BITMAP_PRESENT_SHIFT
+
+#define NAN_TIME_BMAP_CTRL_BITDUR_MASK 0x07
+#define NAN_TIME_BMAP_CTRL_BITDUR(_flags) ((_flags) & NAN_TIME_BMAP_CTRL_BITDUR_MASK)
+#define NAN_TIME_BMAP_CTRL_PERIOD_MASK 0x38
+#define NAN_TIME_BMAP_CTRL_PERIOD_SHIFT 3
+#define NAN_TIME_BMAP_CTRL_PERIOD(_flags) ((_flags) & NAN_TIME_BMAP_CTRL_PERIOD_MASK) \
+ >> NAN_TIME_BMAP_CTRL_PERIOD_SHIFT
+#define NAN_TIME_BMAP_CTRL_OFFSET_MASK 0x7FC0
+#define NAN_TIME_BMAP_CTRL_OFFSET_SHIFT 6
+#define NAN_TIME_BMAP_CTRL_OFFSET(_flags) ((_flags) & NAN_TIME_BMAP_CTRL_OFFSET_MASK) \
+ >> NAN_TIME_BMAP_CTRL_OFFSET_SHIFT
+#define NAN_TIME_BMAP_LEN(avail_entry) \
+ (*(uint8 *)(((wifi_nan_avail_entry_attr_t *)avail_entry)->var + 2))
+
+#define NAN_AVAIL_CHAN_LIST_HDR_LEN 1
+#define NAN_AVAIL_CHAN_LIST_TYPE_CHANNEL 0x01
+#define NAN_AVAIL_CHAN_LIST_NON_CONTIG_BW 0x02
+#define NAN_AVAIL_CHAN_LIST_NUM_ENTRIES_MASK 0xF0
+#define NAN_AVAIL_CHAN_LIST_NUM_ENTRIES_SHIFT 4
+#define NAN_AVAIL_CHAN_LIST_NUM_ENTRIES(_ctrl) (((_ctrl) & NAN_AVAIL_CHAN_LIST_NUM_ENTRIES_MASK) \
+ >> NAN_AVAIL_CHAN_LIST_NUM_ENTRIES_SHIFT)
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_channel_entry_list_s {
+ uint8 chan_info;
+ uint8 var[0];
+} BWL_POST_PACKED_STRUCT wifi_nan_channel_entry_list_t;
+
+/* define for chan_info */
+#define NAN_CHAN_OP_CLASS_MASK 0x01
+#define NAN_CHAN_NON_CONT_BW_MASK 0x02
+#define NAN_CHAN_RSVD_MASK 0x03
+#define NAN_CHAN_NUM_ENTRIES_MASK 0xF0
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_band_entry_s {
+ uint8 band[0];
+} BWL_POST_PACKED_STRUCT wifi_nan_band_entry_t;
+
+/* Type of Availability: committed */
+#define NAN_ENTRY_CNTRL_TYPE_COMM_AVAIL 0x1
+/* Type of Availability: potential */
+#define NAN_ENTRY_CNTRL_TYPE_POTEN_AVAIL 0x2
+/* Type of Availability: conditional */
+#define NAN_ENTRY_CNTRL_TYPE_COND_AVAIL 0x4
+
+/* Type of Availability */
+#define NAN_ENTRY_CNTRL_TYPE_OF_AVAIL_MASK 0x07
+#define NAN_ENTRY_CNTRL_TYPE_OF_AVAIL_SHIFT 0
+/* Usage Preference */
+#define NAN_ENTRY_CNTRL_USAGE_PREF_MASK 0x18
+#define NAN_ENTRY_CNTRL_USAGE_PREF_SHIFT 3
+/* Utilization */
+#define NAN_ENTRY_CNTRL_UTIL_MASK 0x1E0
+#define NAN_ENTRY_CNTRL_UTIL_SHIFT 5
+
+/* Time Bitmap Control field (section 5.7.18.2.3) */
+
+/* Reserved */
+#define NAN_TIME_BMP_CNTRL_RSVD_MASK 0x01
+#define NAN_TIME_BMP_CNTRL_RSVD_SHIFT 0
+/* Bitmap Len */
+#define NAN_TIME_BMP_CNTRL_BMP_LEN_MASK 0x7E
+#define NAN_TIME_BMP_CNTRL_BMP_LEN_SHIFT 1
+/* Bit Duration */
+#define NAN_TIME_BMP_CNTRL_BIT_DUR_MASK 0x380
+#define NAN_TIME_BMP_CNTRL_BIT_DUR_SHIFT 7
+/* Bitmap Len */
+#define NAN_TIME_BMP_CNTRL_PERIOD_MASK 0x1C00
+#define NAN_TIME_BMP_CNTRL_PERIOD_SHIFT 10
+/* Start Offset */
+#define NAN_TIME_BMP_CNTRL_START_OFFSET_MASK 0x3FE000
+#define NAN_TIME_BMP_CNTRL_START_OFFSET_SHIFT 13
+/* Reserved */
+#define NAN_TIME_BMP_CNTRL_RESERVED_MASK 0xC00000
+#define NAN_TIME_BMP_CNTRL_RESERVED_SHIFT 22
+
+/* Time Bitmap Control field: Period */
+typedef enum
+{
+ NAN_TIME_BMP_CTRL_PERIOD_128TU = 1,
+ NAN_TIME_BMP_CTRL_PERIOD_256TU = 2,
+ NAN_TIME_BMP_CTRL_PERIOD_512TU = 3,
+ NAN_TIME_BMP_CTRL_PERIOD_1024TU = 4,
+ NAN_TIME_BMP_CTRL_PERIOD_2048U = 5,
+ NAN_TIME_BMP_CTRL_PERIOD_4096U = 6,
+ NAN_TIME_BMP_CTRL_PERIOD_8192U = 7
+} nan_time_bmp_ctrl_repeat_interval_t;
+
+enum
+{
+ NAN_TIME_BMP_BIT_DUR_16TU_IDX = 0,
+ NAN_TIME_BMP_BIT_DUR_32TU_IDX = 1,
+ NAN_TIME_BMP_BIT_DUR_64TU_IDX = 2,
+ NAN_TIME_BMP_BIT_DUR_128TU_IDX = 3
+};
+
+enum
+{
+ NAN_TIME_BMP_BIT_DUR_IDX_0 = 16,
+ NAN_TIME_BMP_BIT_DUR_IDX_1 = 32,
+ NAN_TIME_BMP_BIT_DUR_IDX_2 = 64,
+ NAN_TIME_BMP_BIT_DUR_IDX_3 = 128
+};
+
+enum
+{
+ NAN_TIME_BMP_CTRL_PERIOD_IDX_1 = 128,
+ NAN_TIME_BMP_CTRL_PERIOD_IDX_2 = 256,
+ NAN_TIME_BMP_CTRL_PERIOD_IDX_3 = 512,
+ NAN_TIME_BMP_CTRL_PERIOD_IDX_4 = 1024,
+ NAN_TIME_BMP_CTRL_PERIOD_IDX_5 = 2048,
+ NAN_TIME_BMP_CTRL_PERIOD_IDX_6 = 4096,
+ NAN_TIME_BMP_CTRL_PERIOD_IDX_7 = 8192
+};
+
+/* Channel Entries List field */
+
+/* Type */
+#define NAN_CHAN_ENTRY_TYPE_MASK 0x01
+#define NAN_CHAN_ENTRY_TYPE_SHIFT 0
+/* Channel Entry Length Indication */
+#define NAN_CHAN_ENTRY_LEN_IND_MASK 0x02
+#define NAN_CHAN_ENTRY_LEN_IND_SHIFT 1
+/* Reserved */
+#define NAN_CHAN_ENTRY_RESERVED_MASK 0x0C
+#define NAN_CHAN_ENTRY_RESERVED_SHIFT 2
+/* Number of FAC Band or Channel Entries */
+#define NAN_CHAN_ENTRY_NO_OF_CHAN_ENTRY_MASK 0xF0
+#define NAN_CHAN_ENTRY_NO_OF_CHAN_ENTRY_SHIFT 4
+
+#define NAN_CHAN_ENTRY_TYPE_BANDS 0
+#define NAN_CHAN_ENTRY_TYPE_OPCLASS_CHANS 1
+
+#define NAN_CHAN_ENTRY_BW_LT_80MHZ 0
+#define NAN_CHAN_ENTRY_BW_EQ_160MHZ 1
+
+/*
+ * NDL Attribute WFA Tech. Spec ver 1.0.r12 (section 10.7.19.2)
+ */
+#define NDL_ATTR_IM_MAP_ID_LEN 1
+#define NDL_ATTR_IM_TIME_BMP_CTRL_LEN 2
+#define NDL_ATTR_IM_TIME_BMP_LEN_LEN 1
+
+/* immutable schedule - as per r21 */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndl_im_sched_field_s {
+ uint8 no_of_im_entries;
+ uint8 var[];
+} BWL_POST_PACKED_STRUCT wifi_nan_ndl_im_sched_field_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndl_im_sched_entry_s {
+ uint8 map_id; /* map id */
+ uint16 tbmp_ctrl; /* time bitmap control */
+ uint8 tbmp_len; /* time bitmap len */
+ uint8 tbmp[]; /* time bitmap - Optional */
+} BWL_POST_PACKED_STRUCT wifi_nan_ndl_im_sched_entry_t;
+
+/*
+ * NDL Control field - Table xx
+ */
+#define NDL_ATTR_CTRL_PEER_ID_PRESENT_MASK 0x01
+#define NDL_ATTR_CTRL_PEER_ID_PRESENT_SHIFT 0
+#define NDL_ATTR_CTRL_IM_SCHED_PRESENT_MASK 0x02
+#define NDL_ATTR_CTRL_IM_SCHED_PRESENT_SHIFT 1
+#define NDL_ATTR_CTRL_NDC_ATTR_PRESENT_MASK 0x04
+#define NDL_ATTR_CTRL_NDC_ATTR_PRESENT_SHIFT 2
+#define NDL_ATTR_CTRL_QOS_ATTR_PRESENT_MASK 0x08
+#define NDL_ATTR_CTRL_QOS_ATTR_PRESENT_SHIFT 3
+
+#define NAN_NDL_TYPE_MASK 0x0F
+#define NDL_ATTR_TYPE_STATUS_REQUEST 0x00
+#define NDL_ATTR_TYPE_STATUS_RESPONSE 0x01
+#define NDL_ATTR_TYPE_STATUS_CONFIRM 0x02
+#define NDL_ATTR_TYPE_STATUS_CONTINUED 0x00
+#define NDL_ATTR_TYPE_STATUS_ACCEPTED 0x10
+#define NDL_ATTR_TYPE_STATUS_REJECTED 0x20
+
+#define NAN_NDL_TYPE_CHECK(_ndl, x) (((_ndl)->type_status & NAN_NDL_TYPE_MASK) == (x))
+#define NAN_NDL_REQUEST(_ndl) (((_ndl)->type_status & NAN_NDL_TYPE_MASK) == \
+ NDL_ATTR_TYPE_STATUS_REQUEST)
+#define NAN_NDL_RESPONSE(_ndl) (((_ndl)->type_status & NAN_NDL_TYPE_MASK) == \
+ NDL_ATTR_TYPE_STATUS_RESPONSE)
+#define NAN_NDL_CONFIRM(_ndl) (((_ndl)->type_status & NAN_NDL_TYPE_MASK) == \
+ NDL_ATTR_TYPE_STATUS_CONFIRM)
+
+#define NAN_NDL_STATUS_SHIFT 4
+#define NAN_NDL_STATUS_MASK 0xF0
+#define NAN_NDL_CONT(_ndl) (((_ndl)->type_status & NAN_NDL_STATUS_MASK) == \
+ NDL_ATTR_TYPE_STATUS_CONTINUED)
+#define NAN_NDL_ACCEPT(_ndl) (((_ndl)->type_status & NAN_NDL_STATUS_MASK) == \
+ NDL_ATTR_TYPE_STATUS_ACCEPTED)
+#define NAN_NDL_REJECT(_ndl) (((_ndl)->type_status & NAN_NDL_STATUS_MASK) == \
+ NDL_ATTR_TYPE_STATUS_REJECTED)
+
+#define NDL_ATTR_CTRL_NONE 0
+#define NDL_ATTR_CTRL_PEER_ID_PRESENT (1 << NDL_ATTR_CTRL_PEER_ID_PRESENT_SHIFT)
+#define NDL_ATTR_CTRL_IMSCHED_PRESENT (1 << NDL_ATTR_CTRL_IM_SCHED_PRESENT_SHIFT)
+#define NDL_ATTR_CTRL_NDC_PRESENT (1 << NDL_ATTR_CTRL_NDC_ATTR_PRESENT_SHIFT)
+#define NDL_ATTR_CTRL_NDL_QOS_PRESENT (1 << NDL_ATTR_CTRL_QOS_ATTR_PRESENT_SHIFT)
+
+#define NDL_ATTR_PEERID_LEN 1
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndl_attr_s {
+ uint8 id; /* NAN_ATTR_NAN_NDL = 0x17 */
+ uint16 len; /* Length of the fields in the attribute */
+ uint8 dialog_token; /* Identify req and resp */
+ uint8 type_status; /* Bits[3-0] type subfield, Bits[7-4] status subfield */
+ uint8 reason; /* Identifies reject reason */
+ uint8 ndl_ctrl; /* NDL control field */
+ uint8 var[]; /* Optional fields follow */
+} BWL_POST_PACKED_STRUCT wifi_nan_ndl_attr_t;
+
+/*
+ * NDL QoS Attribute WFA Tech. Spec ver 1.0.r12 (section 10.7.19.4)
+ */
+#define NDL_QOS_ATTR_MAX_LATENCY_LEN 3
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndl_qos_attr_s {
+ uint8 id; /* NAN_ATTR_NAN_NDL_QOS = 24 */
+ uint16 len; /* Length of the attribute field following */
+ uint8 min_slots; /* Min. number of FAW slots needed per DW interval */
+ uint8 max_latency[NDL_QOS_ATTR_MAX_LATENCY_LEN]; /* Max interval between non-cont FAW */
+} BWL_POST_PACKED_STRUCT wifi_nan_ndl_qos_attr_t;
+
+/* Device Capability Attribute */
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_dev_cap_s {
+ uint8 id; /* 0x0F */
+ uint16 len; /* Length */
+ uint16 commit_dw_info; /* Committed DW Info */
+ uint8 bands_supported; /* Supported Bands */
+ uint8 op_mode; /* Operation Mode */
+ uint8 num_antennas; /* Bit 0-3 tx, 4-7 rx */
+ uint16 chan_switch_time; /* Max channel switch time in us */
+} BWL_POST_PACKED_STRUCT wifi_nan_dev_cap_t;
+
+/* Awake DW Info field format */
+
+/* 2.4GHz DW */
+#define NAN_DEV_CAP_AWAKE_DW_2G_MASK 0x07
+/* 5GHz DW */
+#define NAN_DEV_CAP_AWAKE_DW_5G_MASK 0x38
+/* Reserved */
+#define NAN_DEV_CAP_AWAKE_DW_RSVD_MASK 0xC0
+
+/* bit shift for dev cap */
+#define NAN_DEV_CAP_AWAKE_DW_2G_SHIFT 0
+#define NAN_DEV_CAP_AWAKE_DW_5G_SHIFT 3
+
+/* Device Capability Attribute Format */
+
+/* Operation Mode: HT */
+#define NAN_DEV_CAP_HT_OPER_MODE_MASK 0x01
+/* Operation Mode: VHT */
+#define NAN_DEV_CAP_VHT_OPER_MODE_MASK 0x02
+
+/* Committed DW Info field format */
+/* 2.4GHz DW */
+#define NAN_DEV_CAP_COMMIT_DW_2G_MASK 0x07
+#define NAN_DEV_CAP_COMMIT_DW_2G_OVERWRITE_MASK 0x3C0
+/* 5GHz DW */
+#define NAN_DEV_CAP_COMMIT_DW_5G_MASK 0x38
+#define NAN_DEV_CAP_COMMIT_DW_5G_OVERWRITE_MASK 0x3C00
+/* Reserved */
+#define NAN_DEV_CAP_COMMIT_DW_RSVD_MASK 0xC000
+/* Committed DW bit shift for dev cap */
+#define NAN_DEV_CAP_COMMIT_DW_2G_SHIFT 0
+#define NAN_DEV_CAP_COMMIT_DW_5G_SHIFT 3
+#define NAN_DEV_CAP_COMMIT_DW_2G_OVERWRITE_SHIFT 6
+#define NAN_DEV_CAP_COMMIT_DW_5G_OVERWRITE_SHIFT 10
+/* Operation Mode */
+#define NAN_DEV_CAP_OP_PHY_MODE_HT_ONLY 0x00
+#define NAN_DEV_CAP_OP_PHY_MODE_VHT 0x01
+#define NAN_DEV_CAP_OP_PHY_MODE_VHT_8080 0x02
+#define NAN_DEV_CAP_OP_PHY_MODE_VHT_160 0x04
+#define NAN_DEV_CAP_OP_PAGING_NDL 0x08
+
+#define NAN_DEV_CAP_OP_MODE_VHT_MASK 0x01
+#define NAN_DEV_CAP_OP_MODE_VHT8080_MASK 0x03
+#define NAN_DEV_CAP_OP_MODE_VHT160_MASK 0x05
+#define NAN_DEV_CAP_OP_MODE_PAGING_NDL_MASK 0x08
+
+#define NAN_DEV_CAP_RX_ANT_SHIFT 4
+#define NAN_DEV_CAP_TX_ANT_MASK 0x0F
+#define NAN_DEV_CAP_RX_ANT_MASK 0xF0
+
+/* Band IDs */
+enum {
+ NAN_BAND_ID_TVWS = 0,
+ NAN_BAND_ID_SIG = 1,
+ NAN_BAND_ID_2G = 2,
+ NAN_BAND_ID_5G = 4,
+ NAN_BAND_ID_60G = 5
+};
+typedef uint8 nan_band_id_t;
+
+/*
+ * Unaligned schedule attribute section 10.7.19.6 spec. ver r15
+ */
+#define NAN_UAW_ATTR_CTRL_SCHED_ID_MASK 0x000F
+#define NAN_UAW_ATTR_CTRL_SCHED_ID_SHIFT 0
+#define NAN_UAW_ATTR_CTRL_SEQ_ID_MASK 0xFF00
+#define NAN_UAW_ATTR_CTRL_SEQ_ID_SHIFT 8
+
+#define NAN_UAW_OVWR_ALL_MASK 0x01
+#define NAN_UAW_OVWR_ALL_SHIFT 0
+#define NAN_UAW_OVWR_MAP_ID_MASK 0x1E
+#define NAN_UAW_OVWR_MAP_ID_SHIFT 1
+
+#define NAN_UAW_CTRL_TYPE_MASK 0x03
+#define NAN_UAW_CTRL_TYPE_SHIFT 0
+#define NAN_UAW_CTRL_CHAN_AVAIL_MASK 0x04
+#define NAN_UAW_CTRL_CHAN_AVAIL_SHIFT 2
+#define NAN_UAW_CTRL_RX_NSS_MASK 0x78
+#define NAN_UAW_CTRL_RX_NSS_SHIFT 3
+
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_uaw_attr_s {
+ uint8 id;
+ uint16 len;
+ uint16 ctrl;
+ uint32 start; /* low 32 bits of tsf */
+ uint32 dur;
+ uint32 period;
+ uint8 count_down;
+ uint8 overwrite;
+ /*
+ * uaw[0] == optional field UAW control when present.
+ * band ID or channel follows
+ */
+ uint8 uaw_entry[];
+} BWL_POST_PACKED_STRUCT wifi_nan_uaw_attr_t;
+
+/* NAN2 Management Frame (section 5.6) */
+
+/* Public action frame for NAN2 */
+typedef BWL_PRE_PACKED_STRUCT struct nan2_pub_act_frame_s {
+ /* NAN_PUB_AF_CATEGORY 0x04 */
+ uint8 category_id;
+ /* NAN_PUB_AF_ACTION 0x09 */
+ uint8 action_field;
+ /* NAN_OUI 0x50-6F-9A */
+ uint8 oui[DOT11_OUI_LEN];
+ /* NAN_OUI_TYPE TBD */
+ uint8 oui_type;
+ /* NAN_OUI_SUB_TYPE TBD */
+ uint8 oui_sub_type;
+ /* One or more NAN Attributes follow */
+ uint8 data[];
+} BWL_POST_PACKED_STRUCT nan2_pub_act_frame_t;
+
+#define NAN2_PUB_ACT_FRM_SIZE (OFFSETOF(nan2_pub_act_frame_t, data))
+
+/* NAN Action Frame Subtypes */
+/* Subtype-0 is Reserved */
+#define NAN_MGMT_FRM_SUBTYPE_RESERVED 0
+/* NAN Ranging Request */
+#define NAN_MGMT_FRM_SUBTYPE_RANGING_REQ 1
+/* NAN Ranging Response */
+#define NAN_MGMT_FRM_SUBTYPE_RANGING_RESP 2
+/* NAN Ranging Termination */
+#define NAN_MGMT_FRM_SUBTYPE_RANGING_TERM 3
+/* NAN Ranging Report */
+#define NAN_MGMT_FRM_SUBTYPE_RANGING_RPT 4
+/* NDP Request */
+#define NAN_MGMT_FRM_SUBTYPE_NDP_REQ 5
+/* NDP Response */
+#define NAN_MGMT_FRM_SUBTYPE_NDP_RESP 6
+/* NDP Confirm */
+#define NAN_MGMT_FRM_SUBTYPE_NDP_CONFIRM 7
+/* NDP Key Installment */
+#define NAN_MGMT_FRM_SUBTYPE_NDP_KEY_INST 8
+/* NDP Termination */
+#define NAN_MGMT_FRM_SUBTYPE_NDP_END 9
+/* Schedule Request */
+#define NAN_MGMT_FRM_SUBTYPE_SCHED_REQ 10
+/* Schedule Response */
+#define NAN_MGMT_FRM_SUBTYPE_SCHED_RESP 11
+/* Schedule Confirm */
+#define NAN_MGMT_FRM_SUBTYPE_SCHED_CONF 12
+/* Schedule Update */
+#define NAN_MGMT_FRM_SUBTYPE_SCHED_UPD 13
+
+/* Reason code defines */
+#define NAN_REASON_RESERVED 0x0
+#define NAN_REASON_UNSPECIFIED 0x1
+#define NAN_REASON_RESOURCE_LIMIT 0x2
+#define NAN_REASON_INVALID_PARAMS 0x3
+#define NAN_REASON_FTM_PARAM_INCAP 0x4
+#define NAN_REASON_NO_MOVEMENT 0x5
+#define NAN_REASON_INVALID_AVAIL 0x6
+
+/* nan 2.0 qos (not attribute) */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndp_qos_s {
+ uint8 tid; /* traffic identifier */
+ uint16 pkt_size; /* service data pkt size */
+ uint8 data_rate; /* mean data rate */
+ uint8 svc_interval; /* max service interval */
+} BWL_POST_PACKED_STRUCT wifi_nan_ndp_qos_t;
+
+/* NDP control bitmap defines */
+#define NAN_NDP_CTRL_CONFIRM_REQUIRED 0x01
+#define NAN_NDP_CTRL_EXPLICIT_CONFIRM 0x02
+#define NAN_NDP_CTRL_SECURTIY_PRESENT 0x04
+#define NAN_NDP_CTRL_PUB_ID_PRESENT 0x08
+#define NAN_NDP_CTRL_RESP_NDI_PRESENT 0x10
+#define NAN_NDP_CTRL_SPEC_INFO_PRESENT 0x20
+#define NAN_NDP_CTRL_RESERVED 0xA0
+
+/* NDP Attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndp_attr_s {
+ uint8 id; /* 0x10 */
+ uint16 len; /* length */
+ uint8 dialog_token; /* dialog token */
+ uint8 type_status; /* bits 0-3 type, 4-7 status */
+ uint8 reason; /* reason code */
+ struct ether_addr init_ndi; /* ndp initiator's data interface address */
+ uint8 ndp_id; /* ndp identifier (created by initiator */
+ uint8 control; /* ndp control field */
+ uint8 var[]; /* Optional fields follow */
+} BWL_POST_PACKED_STRUCT wifi_nan_ndp_attr_t;
+/* NDP attribute type and status macros */
+#define NAN_NDP_TYPE_MASK 0x0F
+#define NAN_NDP_TYPE_REQUEST 0x0
+#define NAN_NDP_TYPE_RESPONSE 0x1
+#define NAN_NDP_TYPE_CONFIRM 0x2
+#define NAN_NDP_TYPE_SECURITY 0x3
+#define NAN_NDP_TYPE_TERMINATE 0x4
+#define NAN_NDP_REQUEST(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == NAN_NDP_TYPE_REQUEST)
+#define NAN_NDP_RESPONSE(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == NAN_NDP_TYPE_RESPONSE)
+#define NAN_NDP_CONFIRM(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == NAN_NDP_TYPE_CONFIRM)
+#define NAN_NDP_SECURITY_INST(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == \
+ NAN_NDP_TYPE_SECURITY)
+#define NAN_NDP_TERMINATE(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == \
+ NAN_NDP_TYPE_TERMINATE)
+#define NAN_NDP_STATUS_SHIFT 4
+#define NAN_NDP_STATUS_MASK 0xF0
+#define NAN_NDP_STATUS_CONT (0 << NAN_NDP_STATUS_SHIFT)
+#define NAN_NDP_STATUS_ACCEPT (1 << NAN_NDP_STATUS_SHIFT)
+#define NAN_NDP_STATUS_REJECT (2 << NAN_NDP_STATUS_SHIFT)
+#define NAN_NDP_CONT(_ndp) (((_ndp)->type_status & NAN_NDP_STATUS_MASK) == NAN_NDP_STATUS_CONT)
+#define NAN_NDP_ACCEPT(_ndp) (((_ndp)->type_status & NAN_NDP_STATUS_MASK) == \
+ NAN_NDP_STATUS_ACCEPT)
+#define NAN_NDP_REJECT(_ndp) (((_ndp)->type_status & NAN_NDP_STATUS_MASK) == \
+ NAN_NDP_STATUS_REJECT)
+/* NDP Setup Status */
+#define NAN_NDP_SETUP_STATUS_OK 1
+#define NAN_NDP_SETUP_STATUS_FAIL 0
+#define NAN_NDP_SETUP_STATUS_REJECT 2
+
+/* Rng setup attribute type and status macros */
+#define NAN_RNG_TYPE_MASK 0x0F
+#define NAN_RNG_TYPE_REQUEST 0x0
+#define NAN_RNG_TYPE_RESPONSE 0x1
+#define NAN_RNG_TYPE_TERMINATE 0x2
+
+#define NAN_RNG_STATUS_SHIFT 4
+#define NAN_RNG_STATUS_MASK 0xF0
+#define NAN_RNG_STATUS_ACCEPT (0 << NAN_RNG_STATUS_SHIFT)
+#define NAN_RNG_STATUS_REJECT (1 << NAN_RNG_STATUS_SHIFT)
+
+#define NAN_RNG_ACCEPT(_rsua) (((_rsua)->type_status & NAN_RNG_STATUS_MASK) == \
+ NAN_RNG_STATUS_ACCEPT)
+#define NAN_RNG_REJECT(_rsua) (((_rsua)->type_status & NAN_RNG_STATUS_MASK) == \
+ NAN_RNG_STATUS_REJECT)
+
+/* nan2 ndc ie */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndc_attr_s {
+ uint8 id;
+ uint16 len;
+ uint8 ndc_id[NAN_DATA_NDC_ID_SIZE];
+ uint8 sched_cntrl;
+ uint8 var[];
+} BWL_POST_PACKED_STRUCT wifi_nan_ndc_attr_t;
+
+/* Schedule Indication */
+#define NAN_NDC_ATTR_SCHED_IND_MASK 0x1E
+#define NAN_NDC_ATTR_SCHED_IND_SHIFT 1
+/* Time Bitmap Present */
+#define NAN_NDC_ATTR_TBMP_PRESENT_MASK 0x20
+#define NAN_NDC_ATTR_TBMP_PRESENT_SHIFT 5
+
+#define NAN_NDC_ATTR_TBMP_CTRL_OFFSET 0
+#define NAN_NDC_ATTR_TBMP_LEN_OFFSET 2
+#define NAN_NDC_ATTR_TBMP_OFFSET 3
+
+/* Proposed NDC */
+#define NAN_NDC_ATTR_PROPOSED_NDC_MASK 0x40
+#define NAN_NDC_ATTR_PROPOSED_NDC_SHIFT 6
+#define NAN_NDC_CTRL_BITMAP_PRESENT(_flags) ((_flags) & \
+ NAN_NDC_ATTR_TBMP_PRESENT_MASK) >> NAN_NDC_ATTR_TBMP_PRESENT_SHIFT
+
+/* Service descriptor extension attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_descriptor_ext_attr_t {
+ /* Attribute ID - 0x11 */
+ uint8 id;
+ /* Length of the following fields in the attribute */
+ uint16 len;
+ /* Instance id of associated service descriptor attribute */
+ uint8 instance_id;
+ /* SDE control field */
+ uint16 control;
+ /* Range limit - ingress */
+ uint16 range_ingress;
+ /* Range limit - egress */
+ uint16 range_egress;
+} BWL_POST_PACKED_STRUCT wifi_nan_svc_descriptor_ext_attr_t;
+#define NAN_SDE_ATTR_LEN (sizeof(wifi_nan_svc_descriptor_ext_attr_t))
+/* SDEA control field bit definitions and access macros */
+#define NAN_SDE_CF_FSD_REQUIRED (1 << 0)
+#define NAN_SDE_CF_FSD_GAS (1 << 1)
+#define NAN_SDE_CF_DP_REQUIRED (1 << 2)
+#define NAN_SDE_CF_DP_TYPE (1 << 3)
+#define NAN_SDE_CF_MULTICAST_TYPE (1 << 4)
+#define NAN_SDE_CF_QOS_REQUIRED (1 << 5)
+#define NAN_SDE_CF_SECURITY_REQUIRED (1 << 6)
+#define NAN_SDE_CF_RANGING_REQUIRED (1 << 7)
+#define NAN_SDE_CF_RANGE_PRESENT (1 << 8)
+#define NAN_SDE_FSD_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_FSD_REQUIRED)
+#define NAN_SDE_FSD_GAS(_sde) ((_sde)->control & NAN_SDE_CF_FSD_GAS)
+#define NAN_SDE_DP_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_DP_REQUIRED)
+#define NAN_SDE_DP_MULTICAST(_sde) ((_sde)->control & NAN_SDE_CF_DP_TYPE)
+#define NAN_SDE_MULTICAST_M_TO_M(_sde) ((_sde)->control & NAN_SDE_CF_MULTICAST_TYPE)
+#define NAN_SDE_QOS_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_QOS_REQUIRED)
+#define NAN_SDE_SECURITY_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_SECURITY_REQUIRED)
+#define NAN_SDE_RANGING_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_RANGING_REQUIRED)
+#define NAN_SDE_RANGE_PRESENT(_sde) ((_sde)->control & NAN_SDE_CF_RANGE_PRESENT)
+
+/* ********************************************
+* OBSOLETE/DUPLICATES - DO NOT USE BELOW
+**********************************************
+*/
+/* Time Bitmap Control field: Bit Duration - Incorrect. */
+typedef enum
+{
+ NAN_TIME_BMP_CTRL_BIT_DUR_DUR_16TU = 0,
+ NAN_TIME_BMP_CTRL_BIT_DUR_DUR_32TU = 1,
+ NAN_TIME_BMP_CTRL_BIT_DUR_DUR_48TU = 2,
+ NAN_TIME_BMP_CTRL_BIT_DUR_DUR_64TU = 3,
+ NAN_TIME_BMP_CTRL_BIT_DUR_DUR_80TU = 4,
+ NAN_TIME_BMP_CTRL_BIT_DUR_DUR_96TU = 5,
+ NAN_TIME_BMP_CTRL_BIT_DUR_DUR_112TU = 6,
+ NAN_TIME_BMP_CTRL_BIT_DUR_DUR_128TU = 7
+} nan_time_bmp_ctrl_bit_dur_t;
+
+/* FAC Channel Entry (section 10.7.19.1.5) */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_fac_chan_entry_s {
+ uint8 oper_class; /* Operating Class */
+ uint16 chan_bitmap; /* Channel Bitmap */
+ uint8 primary_chan_bmp; /* Primary Channel Bitmap */
+ uint16 aux_chan; /* Auxiliary Channel bitmap */
+} BWL_POST_PACKED_STRUCT wifi_nan_fac_chan_entry_t;
+
+/* Channel Entry List Present bit in Entry Control Filed is obsolete (WFA NAN Spec 1.0 r21) */
+#define NAN_AVAIL_ENTRY_CTRL_LIST_PRESENT_MASK 0x4000
+#define NAN_AVAIL_ENTRY_CTRL_LIST_PRESENT_SHIFT 14
+#define NAN_AVAIL_ENTRY_CTRL_LIST_PRESENT(_flags) ((_flags) & \
+ NAN_AVAIL_ENTRY_CTRL_LIST_PRESENT_MASK) >> NAN_AVAIL_ENTRY_CTRL_LIST_PRESENT_SHIFT
+
+/* NDP Information Element (internal) */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndp_setup_s {
+ uint8 id; /* 221 */
+ uint8 len; /* Length */
+ uint8 oui[DOT11_OUI_LEN]; /* "\x00\x10\x18" BRCM OUI */
+ uint8 type; /* NAN_OUI_TYPE 0x13 */
+ uint8 subtype; /* NAN_DATA_NDP_SETUP */
+ uint8 msg_type; /* NDP Req, NDP Resp etc. */
+ uint8 pub_inst_id; /* publish instance id */
+ struct ether_addr peer_mac_addr; /* publisher mac addr (aka peer mgmt address) */
+ struct ether_addr data_if_addr; /* local data i/f address */
+ uint8 msg_status;
+ uint8 ndp_ctrl;
+ uint8 security;
+ wifi_nan_ndp_qos_t qos; /* qos info */
+ uint8 var[1]; /* NDP specific info */
+} BWL_POST_PACKED_STRUCT wifi_nan_ndp_setup_t;
+
+/* NAN mgmt information element */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_mgmt_setup_s {
+ uint8 id; /* 221 */
+ uint8 len; /* Length */
+ uint8 oui[DOT11_OUI_LEN]; /* "\x00\x10\x18" BRCM OUI */
+ uint8 type; /* NAN_OUI_TYPE 0x13 */
+ uint8 subtype; /* NAN_DATA_MGMT_SETUP */
+ uint8 msg_type; /* Mgmt Req, Mgmt Resp etc. */
+ uint8 msg_status;
+} BWL_POST_PACKED_STRUCT wifi_nan_mgmt_setup_t;
+
+/* NAN Mgmt Request */
+#define NAN_MGMT_SETUP_MSG_REQ 1 /* don't use 0 */
+/* NAN Mgmt Response */
+#define NAN_MGMT_SETUP_MSG_RESP 2
+
+/* NAN Mgmt Setup Status */
+#define NAN_MGMT_SETUP_STATUS_OK 0
+#define NAN_MGMT_SETUP_STATUS_FAIL 1
+#define NAN_MGMT_SETUP_STATUS_REJECT 2
+
+/* NDL Schedule request */
+#define NAN_MGMT_FRM_SUBTYPE_NDL_UPDATE_REQ 17 /* Not part of spec. ver 1.0.r12 */
+/* NDL Schedule response */
+#define NAN_MGMT_FRM_SUBTYPE_NDL_UPDATE_RESP 18 /* Not part of spec. ver 1.0.r12 */
+
+/* NAN2 Management */
+/* TODO: Remove this once nan_mgmt module is removed */
+#define NAN_MGMT_FRM_SUBTYPE_MGMT 0
+
+/* NAN 2.0 NDP Setup */
+#define NAN_DATA_NDP_SETUP 0 /* arbitrary value */
+/* NAN 2.0 Mgmt Setup */
+#define NAN_DATA_MGMT_SETUP 1 /* arbitrary value */
+/* NAN 2.0 NDL Setup */
+#define NAN_DATA_NDL_SETUP 2 /* arbitrary value */
+
+/*
+ * Period
+ * Indicate the repeat interval of the following bitmap.
+ * when set to 0, the indicated bitmap is not repeated.
+ * When set to non-zero, the repeat interval is:
+ * 1:128 TU, 2: 256 TU, 3: 512 TU, 4: 1024 TU, 5: 2048 TU, 6: 4096 TU, 7: 8192 TU
+*/
+#define NAN_DATA_MAX_AVAIL_INTRVL 7 /* no. of period intervals supported */
+
+/* no. of peer devices supported TODO make it tunable */
+#define NAN_DATA_PEER_DEV_SUPPORT 8
+/* no. of instaces supported (ndp, mgmt) */
+#define NAN_DATA_NDP_INST_SUPPORT 16
+/* instaces supported (same as ndp) */
+#define NAN_DATA_MGMT_INST_SUPPORT NAN_DATA_NDP_INST_SUPPORT
+#define NAN_DATA_NDL_INST_SUPPORT NAN_DATA_PEER_DEV_SUPPORT
+/* ndc base schedule cannot be more than ndl instances */
+#define NAN_DATA_NDC_INST_SUPPORT NAN_DATA_PEER_DEV_SUPPORT
+
+/* NAN 2.0 (section 5.7.18.2): NAN availability attribute */
+
+/* NAN Availability Attribute */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_availability_attr_s {
+ uint8 id; /* TBD */
+ uint16 len; /* length that follows */
+ uint8 attr_cntrl[3]; /* attribute control */
+ uint8 avail_entry_list[1]; /* availability entry list */
+} BWL_POST_PACKED_STRUCT wifi_nan_availability_attr_t;
+
+/* Channel entry */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_channel_entry_s {
+ uint8 opclass; /* Operating class */
+ uint16 chan_bitmap; /* Channel bitmap */
+ uint8 prim_bitmap; /* Primary channel bitmap */
+ uint16 aux_bitmap; /* Time bitmap length */
+} BWL_POST_PACKED_STRUCT wifi_nan_channel_entry_t;
+
+/* GAS Sechdule Request */
+#define NAN_MGMT_FRM_SUBTYPE_GAS_SCHED_REQ 14 /* Not part of spec. ver 1.0.r12 */
+/* GAS Sechdule Response */
+#define NAN_MGMT_FRM_SUBTYPE_GAS_SCHED_RESP 15 /* Not part of spec. ver 1.0.r12 */
+
+/* DUPLICATES */
+/* Type of Availability: committed */
+#define NAN_ENTRY_CNTRL_TYPE_COMM_AVAIL_MASK 0x1
+/* Type of Availability: potential */
+#define NAN_ENTRY_CNTRL_TYPE_POTEN_AVAIL_MASK 0x2
+/* Type of Availability: conditional */
+#define NAN_ENTRY_CNTRL_TYPE_COND_AVAIL_MASK 0x4
+
+/* Rx Nss */
+#define NAN_ENTRY_CNTRL_RX_NSS_MASK 0x1E00
+#define NAN_ENTRY_CNTRL_RX_NSS_SHIFT 9
+/* Paged Resource block */
+#define NAN_ENTRY_CNTRL_PAGED_RSC_BLK_MASK 0x2000
+#define NAN_ENTRY_CNTRL_PAGED_RSC_BLK_SHIFT 13
+/* Time Bitmap Present */
+#define NAN_ENTRY_CNTRL_TIME_BMP_PRSNT_MASK 0x4000
+#define NAN_ENTRY_CNTRL_TIME_BMP_PRSNT_SHIFT 14
+/* Channel Entry Present */
+#define NAN_ENTRY_CNTRL_CHAN_ENTRY_PRSNT_MASK 0x8000
+#define NAN_ENTRY_CNTRL_CHAN_ENTRY_PRSNT_SHIFT 15
+/* Reserved */
+#define NAN_ENTRY_CNTRL_RESERVED_MASK 0xFF0000
+#define NAN_ENTRY_CNTRL_RESERVED_SHIFT 16
+
+#define NAN_ALL_NAN_MGMT_FRAMES (NAN_FRM_MGMT_AF | \
+ NAN_FRM_NDP_AF | NAN_FRM_NDL_AF | \
+ NAN_FRM_DISC_BCN | NAN_FRM_SYNC_BCN | \
+ NAN_FRM_SVC_DISC)
+
+/* obsoleted by spec r21 */
+typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndl_im_sched_ctrl_s {
+ uint8 sched_ctrl; /* Schedule control */
+ uint16 bitmap_ctrl; /* Optional field */
+ uint8 time_bitmap_len; /* Optional field */
+ uint8 time_bitmap[]; /* Optional field */
+} BWL_POST_PACKED_STRUCT wifi_nan_ndl_im_sched_ctrl_t;
+
+#define NDL_ATTR_IM_SCHED_CTRL_LEN 1
+#define NDL_ATTR_IM_SCHED_CTRL_SCHED_IND_MASK 0x1E
+#define NDL_ATTR_IM_SCHED_CTRL_SCHED_IND_SHIFT 1
+#define NDL_ATTR_IM_SCHED_CTRL_TIME_BMP_PRSNT_MASK 0x20
+#define NDL_ATTR_IM_SCHED_CTRL_TIME_BMP_PRSNT_SHIFT 5
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _NAN_H_ */
diff --git a/wl/components/shared/proto/vlan.h b/wl/components/shared/proto/vlan.h
new file mode 100644
index 0000000..eb85151
--- /dev/null
+++ b/wl/components/shared/proto/vlan.h
@@ -0,0 +1,92 @@
+/*
+ * 802.1Q VLAN protocol definitions
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: vlan.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _vlan_h_
+#define _vlan_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#ifndef VLAN_VID_MASK
+#define VLAN_VID_MASK 0xfff /* low 12 bits are vlan id */
+#endif
+
+#define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */
+#define VLAN_PRI_SHIFT 13 /* user priority */
+
+#define VLAN_PRI_MASK 7 /* 3 bits of priority */
+
+#define VLAN_TPID_OFFSET 12 /* offset of tag protocol id field */
+#define VLAN_TCI_OFFSET 14 /* offset of tag ctrl info field */
+
+#define VLAN_TAG_LEN 4
+#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) /* offset in Ethernet II packet only */
+
+#define VLAN_TPID 0x8100 /* VLAN ethertype/Tag Protocol ID */
+
+struct vlan_header {
+ uint16 vlan_type; /* 0x8100 */
+ uint16 vlan_tag; /* priority, cfi and vid */
+};
+
+struct ethervlan_header {
+ uint8 ether_dhost[ETHER_ADDR_LEN];
+ uint8 ether_shost[ETHER_ADDR_LEN];
+ uint16 vlan_type; /* 0x8100 */
+ uint16 vlan_tag; /* priority, cfi and vid */
+ uint16 ether_type;
+};
+
+struct dot3_mac_llc_snapvlan_header {
+ uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */
+ uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */
+ uint16 length; /* frame length incl header */
+ uint8 dsap; /* always 0xAA */
+ uint8 ssap; /* always 0xAA */
+ uint8 ctl; /* always 0x03 */
+ uint8 oui[3]; /* RFC1042: 0x00 0x00 0x00
+ * Bridge-Tunnel: 0x00 0x00 0xF8
+ */
+ uint16 vlan_type; /* 0x8100 */
+ uint16 vlan_tag; /* priority, cfi and vid */
+ uint16 ether_type; /* ethertype */
+};
+
+#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN)
+
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#define ETHERVLAN_MOVE_HDR(d, s) \
+do { \
+ struct ethervlan_header t; \
+ t = *(struct ethervlan_header *)(s); \
+ *(struct ethervlan_header *)(d) = t; \
+} while (0)
+
+#endif /* _vlan_h_ */
diff --git a/wl/components/shared/proto/wpa.h b/wl/components/shared/proto/wpa.h
new file mode 100644
index 0000000..68ac03c
--- /dev/null
+++ b/wl/components/shared/proto/wpa.h
@@ -0,0 +1,206 @@
+/*
+ * Fundamental types and constants relating to WPA
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wpa.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _proto_wpa_h_
+#define _proto_wpa_h_
+
+#include <typedefs.h>
+#include <proto/ethernet.h>
+
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* Reason Codes */
+
+/* 13 through 23 taken from IEEE Std 802.11i-2004 */
+#define DOT11_RC_INVALID_WPA_IE 13 /* Invalid info. element */
+#define DOT11_RC_MIC_FAILURE 14 /* Michael failure */
+#define DOT11_RC_4WH_TIMEOUT 15 /* 4-way handshake timeout */
+#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 /* Group key update timeout */
+#define DOT11_RC_WPA_IE_MISMATCH 17 /* WPA IE in 4-way handshake differs from
+ * (re-)assoc. request/probe response
+ */
+#define DOT11_RC_INVALID_MC_CIPHER 18 /* Invalid multicast cipher */
+#define DOT11_RC_INVALID_UC_CIPHER 19 /* Invalid unicast cipher */
+#define DOT11_RC_INVALID_AKMP 20 /* Invalid authenticated key management protocol */
+#define DOT11_RC_BAD_WPA_VERSION 21 /* Unsupported WPA version */
+#define DOT11_RC_INVALID_WPA_CAP 22 /* Invalid WPA IE capabilities */
+#define DOT11_RC_8021X_AUTH_FAIL 23 /* 802.1X authentication failure */
+
+#define WPA2_PMKID_LEN 16
+
+/* WPA IE fixed portion */
+typedef BWL_PRE_PACKED_STRUCT struct
+{
+ uint8 tag; /* TAG */
+ uint8 length; /* TAG length */
+ uint8 oui[3]; /* IE OUI */
+ uint8 oui_type; /* OUI type */
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 low;
+ uint8 high;
+ } BWL_POST_PACKED_STRUCT version; /* IE version */
+} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t;
+#define WPA_IE_OUITYPE_LEN 4
+#define WPA_IE_FIXED_LEN 8
+#define WPA_IE_TAG_FIXED_LEN 6
+
+#define BIP_OUI_TYPE WPA2_OUI "\x06"
+
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint8 tag; /* TAG */
+ uint8 length; /* TAG length */
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 low;
+ uint8 high;
+ } BWL_POST_PACKED_STRUCT version; /* IE version */
+} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t;
+#define WPA_RSN_IE_FIXED_LEN 4
+#define WPA_RSN_IE_TAG_FIXED_LEN 2
+typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN];
+
+#define WFA_OSEN_IE_FIXED_LEN 6
+
+/* WPA suite/multicast suite */
+typedef BWL_PRE_PACKED_STRUCT struct
+{
+ uint8 oui[3];
+ uint8 type;
+} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t;
+#define WPA_SUITE_LEN 4
+
+/* WPA unicast suite list/key management suite list */
+typedef BWL_PRE_PACKED_STRUCT struct
+{
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 low;
+ uint8 high;
+ } BWL_POST_PACKED_STRUCT count;
+ wpa_suite_t list[1];
+} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t;
+#define WPA_IE_SUITE_COUNT_LEN 2
+typedef BWL_PRE_PACKED_STRUCT struct
+{
+ BWL_PRE_PACKED_STRUCT struct {
+ uint8 low;
+ uint8 high;
+ } BWL_POST_PACKED_STRUCT count;
+ wpa_pmkid_t list[1];
+} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t;
+
+/* WPA cipher suites */
+#define WPA_CIPHER_NONE 0 /* None */
+#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
+#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
+#define WPA_CIPHER_AES_OCB 3 /* AES (OCB) */
+#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
+#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
+#define WPA_CIPHER_BIP 6 /* WEP (104-bit) */
+#define WPA_CIPHER_TPK 7 /* Group addressed traffic not allowed */
+
+#ifdef BCMWAPI_WAI
+#define WAPI_CIPHER_NONE WPA_CIPHER_NONE
+#define WAPI_CIPHER_SMS4 11
+
+#define WAPI_CSE_WPI_SMS4 1
+#endif /* BCMWAPI_WAI */
+
+#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \
+ (cipher) == WPA_CIPHER_WEP_40 || \
+ (cipher) == WPA_CIPHER_WEP_104 || \
+ (cipher) == WPA_CIPHER_TKIP || \
+ (cipher) == WPA_CIPHER_AES_OCB || \
+ (cipher) == WPA_CIPHER_AES_CCM || \
+ (cipher) == WPA_CIPHER_TPK)
+
+#ifdef BCMWAPI_WAI
+#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \
+ (cipher) == WAPI_CSE_WPI_SMS4)
+
+/* convert WAPI_CSE_WPI_XXX to WAPI_CIPHER_XXX */
+#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \
+ WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE)
+
+#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \
+ WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE)
+#endif /* BCMWAPI_WAI */
+
+/* WPA TKIP countermeasures parameters */
+#define WPA_TKIP_CM_DETECT 60 /* multiple MIC failure window (seconds) */
+#define WPA_TKIP_CM_BLOCK 60 /* countermeasures active window (seconds) */
+
+/* RSN IE defines */
+#define RSN_CAP_LEN 2 /* Length of RSN capabilities field (2 octets) */
+
+/* RSN Capabilities defined in 802.11i */
+#define RSN_CAP_PREAUTH 0x0001
+#define RSN_CAP_NOPAIRWISE 0x0002
+#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
+#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2
+#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030
+#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4
+#define RSN_CAP_1_REPLAY_CNTR 0
+#define RSN_CAP_2_REPLAY_CNTRS 1
+#define RSN_CAP_4_REPLAY_CNTRS 2
+#define RSN_CAP_16_REPLAY_CNTRS 3
+#define RSN_CAP_MFPR 0x0040
+#define RSN_CAP_MFPC 0x0080
+#define RSN_CAP_SPPC 0x0400
+#define RSN_CAP_SPPR 0x0800
+
+/* WPA capabilities defined in 802.11i */
+#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS
+#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS
+#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT
+#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK
+
+/* WPA capabilities defined in 802.11zD9.0 */
+#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) /* bit 9 */
+
+/* WPA Specific defines */
+#define WPA_CAP_LEN RSN_CAP_LEN /* Length of RSN capabilities in RSN IE (2 octets) */
+#define WPA_PMKID_CNT_LEN 2 /* Length of RSN PMKID count (2 octests) */
+
+#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH
+
+#define WPA2_PMKID_COUNT_LEN 2
+
+#ifdef BCMWAPI_WAI
+#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH
+
+/* Other WAI definition */
+#define WAPI_WAI_REQUEST 0x00F1
+#define WAPI_UNICAST_REKEY 0x00F2
+#define WAPI_STA_AGING 0x00F3
+#define WAPI_MUTIL_REKEY 0x00F4
+#define WAPI_STA_STATS 0x00F5
+
+#define WAPI_USK_REKEY_COUNT 0x4000000 /* 0xA00000 */
+#define WAPI_MSK_REKEY_COUNT 0x4000000 /* 0xA00000 */
+#endif /* BCMWAPI_WAI */
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _proto_wpa_h_ */
diff --git a/wl/components/shared/proto/wps.h b/wl/components/shared/proto/wps.h
new file mode 100644
index 0000000..4569a84
--- /dev/null
+++ b/wl/components/shared/proto/wps.h
@@ -0,0 +1,383 @@
+/*
+ * WPS IE definitions
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id$
+ */
+
+#ifndef _WPS_
+#define _WPS_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Data Element Definitions */
+#define WPS_ID_AP_CHANNEL 0x1001
+#define WPS_ID_ASSOC_STATE 0x1002
+#define WPS_ID_AUTH_TYPE 0x1003
+#define WPS_ID_AUTH_TYPE_FLAGS 0x1004
+#define WPS_ID_AUTHENTICATOR 0x1005
+#define WPS_ID_CONFIG_METHODS 0x1008
+#define WPS_ID_CONFIG_ERROR 0x1009
+#define WPS_ID_CONF_URL4 0x100A
+#define WPS_ID_CONF_URL6 0x100B
+#define WPS_ID_CONN_TYPE 0x100C
+#define WPS_ID_CONN_TYPE_FLAGS 0x100D
+#define WPS_ID_CREDENTIAL 0x100E
+#define WPS_ID_DEVICE_NAME 0x1011
+#define WPS_ID_DEVICE_PWD_ID 0x1012
+#define WPS_ID_E_HASH1 0x1014
+#define WPS_ID_E_HASH2 0x1015
+#define WPS_ID_E_SNONCE1 0x1016
+#define WPS_ID_E_SNONCE2 0x1017
+#define WPS_ID_ENCR_SETTINGS 0x1018
+#define WPS_ID_ENCR_TYPE 0x100F
+#define WPS_ID_ENCR_TYPE_FLAGS 0x1010
+#define WPS_ID_ENROLLEE_NONCE 0x101A
+#define WPS_ID_FEATURE_ID 0x101B
+#define WPS_ID_IDENTITY 0x101C
+#define WPS_ID_IDENTITY_PROOF 0x101D
+#define WPS_ID_KEY_WRAP_AUTH 0x101E
+#define WPS_ID_KEY_IDENTIFIER 0x101F
+#define WPS_ID_MAC_ADDR 0x1020
+#define WPS_ID_MANUFACTURER 0x1021
+#define WPS_ID_MSG_TYPE 0x1022
+#define WPS_ID_MODEL_NAME 0x1023
+#define WPS_ID_MODEL_NUMBER 0x1024
+#define WPS_ID_NW_INDEX 0x1026
+#define WPS_ID_NW_KEY 0x1027
+#define WPS_ID_NW_KEY_INDEX 0x1028
+#define WPS_ID_NEW_DEVICE_NAME 0x1029
+#define WPS_ID_NEW_PWD 0x102A
+#define WPS_ID_OOB_DEV_PWD 0x102C
+#define WPS_ID_OS_VERSION 0x102D
+#define WPS_ID_POWER_LEVEL 0x102F
+#define WPS_ID_PSK_CURRENT 0x1030
+#define WPS_ID_PSK_MAX 0x1031
+#define WPS_ID_PUBLIC_KEY 0x1032
+#define WPS_ID_RADIO_ENABLED 0x1033
+#define WPS_ID_REBOOT 0x1034
+#define WPS_ID_REGISTRAR_CURRENT 0x1035
+#define WPS_ID_REGISTRAR_ESTBLSHD 0x1036
+#define WPS_ID_REGISTRAR_LIST 0x1037
+#define WPS_ID_REGISTRAR_MAX 0x1038
+#define WPS_ID_REGISTRAR_NONCE 0x1039
+#define WPS_ID_REQ_TYPE 0x103A
+#define WPS_ID_RESP_TYPE 0x103B
+#define WPS_ID_RF_BAND 0x103C
+#define WPS_ID_R_HASH1 0x103D
+#define WPS_ID_R_HASH2 0x103E
+#define WPS_ID_R_SNONCE1 0x103F
+#define WPS_ID_R_SNONCE2 0x1040
+#define WPS_ID_SEL_REGISTRAR 0x1041
+#define WPS_ID_SERIAL_NUM 0x1042
+#define WPS_ID_SC_STATE 0x1044
+#define WPS_ID_SSID 0x1045
+#define WPS_ID_TOT_NETWORKS 0x1046
+#define WPS_ID_UUID_E 0x1047
+#define WPS_ID_UUID_R 0x1048
+#define WPS_ID_VENDOR_EXT 0x1049
+#define WPS_ID_VERSION 0x104A
+#define WPS_ID_X509_CERT_REQ 0x104B
+#define WPS_ID_X509_CERT 0x104C
+#define WPS_ID_EAP_IDENTITY 0x104D
+#define WPS_ID_MSG_COUNTER 0x104E
+#define WPS_ID_PUBKEY_HASH 0x104F
+#define WPS_ID_REKEY_KEY 0x1050
+#define WPS_ID_KEY_LIFETIME 0x1051
+#define WPS_ID_PERM_CFG_METHODS 0x1052
+#define WPS_ID_SEL_REG_CFG_METHODS 0x1053
+#define WPS_ID_PRIM_DEV_TYPE 0x1054
+#define WPS_ID_SEC_DEV_TYPE_LIST 0x1055
+#define WPS_ID_PORTABLE_DEVICE 0x1056
+#define WPS_ID_AP_SETUP_LOCKED 0x1057
+#define WPS_ID_APP_LIST 0x1058
+#define WPS_ID_EAP_TYPE 0x1059
+#define WPS_ID_INIT_VECTOR 0x1060
+#define WPS_ID_KEY_PROVIDED_AUTO 0x1061
+#define WPS_ID_8021X_ENABLED 0x1062
+#define WPS_ID_WEP_TRANSMIT_KEY 0x1064
+#define WPS_ID_REQ_DEV_TYPE 0x106A
+
+/* WSC 2.0, WFA Vendor Extension Subelements */
+#define WFA_VENDOR_EXT_ID "\x00\x37\x2A"
+#define WPS_WFA_SUBID_VERSION2 0x00
+#define WPS_WFA_SUBID_AUTHORIZED_MACS 0x01
+#define WPS_WFA_SUBID_NW_KEY_SHAREABLE 0x02
+#define WPS_WFA_SUBID_REQ_TO_ENROLL 0x03
+#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME 0x04
+#define WPS_WFA_SUBID_REG_CFG_METHODS 0x05
+
+
+/* WCN-NET Windows Rally Vertical Pairing Vendor Extensions */
+#define MS_VENDOR_EXT_ID "\x00\x01\x37"
+#define WPS_MS_ID_VPI 0x1001 /* Vertical Pairing Identifier TLV */
+#define WPS_MS_ID_TRANSPORT_UUID 0x1002 /* Transport UUID TLV */
+
+/* Vertical Pairing Identifier TLV Definitions */
+#define WPS_MS_VPI_TRANSPORT_NONE 0x00 /* None */
+#define WPS_MS_VPI_TRANSPORT_DPWS 0x01 /* Devices Profile for Web Services */
+#define WPS_MS_VPI_TRANSPORT_UPNP 0x02 /* uPnP */
+#define WPS_MS_VPI_TRANSPORT_SDNWS 0x03 /* Secure Devices Profile for Web Services */
+#define WPS_MS_VPI_NO_PROFILE_REQ 0x00 /* Wi-Fi profile not requested.
+ * Not supported in Windows 7
+ */
+#define WPS_MS_VPI_PROFILE_REQ 0x01 /* Wi-Fi profile requested. */
+
+/* sizes of the fixed size elements */
+#define WPS_ID_AP_CHANNEL_S 2
+#define WPS_ID_ASSOC_STATE_S 2
+#define WPS_ID_AUTH_TYPE_S 2
+#define WPS_ID_AUTH_TYPE_FLAGS_S 2
+#define WPS_ID_AUTHENTICATOR_S 8
+#define WPS_ID_CONFIG_METHODS_S 2
+#define WPS_ID_CONFIG_ERROR_S 2
+#define WPS_ID_CONN_TYPE_S 1
+#define WPS_ID_CONN_TYPE_FLAGS_S 1
+#define WPS_ID_DEVICE_PWD_ID_S 2
+#define WPS_ID_ENCR_TYPE_S 2
+#define WPS_ID_ENCR_TYPE_FLAGS_S 2
+#define WPS_ID_FEATURE_ID_S 4
+#define WPS_ID_MAC_ADDR_S 6
+#define WPS_ID_MSG_TYPE_S 1
+#define WPS_ID_SC_STATE_S 1
+#define WPS_ID_RF_BAND_S 1
+#define WPS_ID_OS_VERSION_S 4
+#define WPS_ID_VERSION_S 1
+#define WPS_ID_SEL_REGISTRAR_S 1
+#define WPS_ID_SEL_REG_CFG_METHODS_S 2
+#define WPS_ID_REQ_TYPE_S 1
+#define WPS_ID_RESP_TYPE_S 1
+#define WPS_ID_AP_SETUP_LOCKED_S 1
+
+/* WSC 2.0, WFA Vendor Extension Subelements */
+#define WPS_WFA_SUBID_VERSION2_S 1
+#define WPS_WFA_SUBID_NW_KEY_SHAREABLE_S 1
+#define WPS_WFA_SUBID_REQ_TO_ENROLL_S 1
+#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME_S 1
+#define WPS_WFA_SUBID_REG_CFG_METHODS_S 2
+
+/* Association states */
+#define WPS_ASSOC_NOT_ASSOCIATED 0
+#define WPS_ASSOC_CONN_SUCCESS 1
+#define WPS_ASSOC_CONFIG_FAIL 2
+#define WPS_ASSOC_ASSOC_FAIL 3
+#define WPS_ASSOC_IP_FAIL 4
+
+/* Authentication types */
+#define WPS_AUTHTYPE_OPEN 0x0001
+#define WPS_AUTHTYPE_WPAPSK 0x0002 /* Deprecated in WSC 2.0 */
+#define WPS_AUTHTYPE_SHARED 0x0004 /* Deprecated in WSC 2.0 */
+#define WPS_AUTHTYPE_WPA 0x0008 /* Deprecated in WSC 2.0 */
+#define WPS_AUTHTYPE_WPA2 0x0010
+#define WPS_AUTHTYPE_WPA2PSK 0x0020
+
+/* Config methods */
+#define WPS_CONFMET_USBA 0x0001 /* Deprecated in WSC 2.0 */
+#define WPS_CONFMET_ETHERNET 0x0002 /* Deprecated in WSC 2.0 */
+#define WPS_CONFMET_LABEL 0x0004
+#define WPS_CONFMET_DISPLAY 0x0008
+#define WPS_CONFMET_EXT_NFC_TOK 0x0010
+#define WPS_CONFMET_INT_NFC_TOK 0x0020
+#define WPS_CONFMET_NFC_INTF 0x0040
+#define WPS_CONFMET_PBC 0x0080
+#define WPS_CONFMET_KEYPAD 0x0100
+/* WSC 2.0 */
+#define WPS_CONFMET_VIRT_PBC 0x0280
+#define WPS_CONFMET_PHY_PBC 0x0480
+#define WPS_CONFMET_VIRT_DISPLAY 0x2008
+#define WPS_CONFMET_PHY_DISPLAY 0x4008
+
+/* WPS error messages */
+#define WPS_ERROR_NO_ERROR 0
+#define WPS_ERROR_OOB_INT_READ_ERR 1
+#define WPS_ERROR_DECRYPT_CRC_FAIL 2
+#define WPS_ERROR_CHAN24_NOT_SUPP 3
+#define WPS_ERROR_CHAN50_NOT_SUPP 4
+#define WPS_ERROR_SIGNAL_WEAK 5 /* Deprecated in WSC 2.0 */
+#define WPS_ERROR_NW_AUTH_FAIL 6 /* Deprecated in WSC 2.0 */
+#define WPS_ERROR_NW_ASSOC_FAIL 7 /* Deprecated in WSC 2.0 */
+#define WPS_ERROR_NO_DHCP_RESP 8 /* Deprecated in WSC 2.0 */
+#define WPS_ERROR_FAILED_DHCP_CONF 9 /* Deprecated in WSC 2.0 */
+#define WPS_ERROR_IP_ADDR_CONFLICT 10 /* Deprecated in WSC 2.0 */
+#define WPS_ERROR_FAIL_CONN_REGISTRAR 11
+#define WPS_ERROR_MULTI_PBC_DETECTED 12
+#define WPS_ERROR_ROGUE_SUSPECTED 13
+#define WPS_ERROR_DEVICE_BUSY 14
+#define WPS_ERROR_SETUP_LOCKED 15
+#define WPS_ERROR_MSG_TIMEOUT 16 /* Deprecated in WSC 2.0 */
+#define WPS_ERROR_REG_SESSION_TIMEOUT 17 /* Deprecated in WSC 2.0 */
+#define WPS_ERROR_DEV_PWD_AUTH_FAIL 18
+#define WPS_ERROR_60GHZ_NOT_SUPPORT 19
+#define WPS_ERROR_PKH_MISMATCH 20 /* Public Key Hash Mismatch */
+
+/* Connection types */
+#define WPS_CONNTYPE_ESS 0x01
+#define WPS_CONNTYPE_IBSS 0x02
+
+/* Device password ID */
+#define WPS_DEVICEPWDID_DEFAULT 0x0000
+#define WPS_DEVICEPWDID_USER_SPEC 0x0001
+#define WPS_DEVICEPWDID_MACHINE_SPEC 0x0002
+#define WPS_DEVICEPWDID_REKEY 0x0003
+#define WPS_DEVICEPWDID_PUSH_BTN 0x0004
+#define WPS_DEVICEPWDID_REG_SPEC 0x0005
+#define WPS_DEVICEPWDID_IBSS 0x0006
+#define WPS_DEVICEPWDID_NFC_CHO 0x0007 /* NFC-Connection-Handover */
+#define WPS_DEVICEPWDID_WFDS 0x0008 /* Wi-Fi Direct Services Specification */
+
+/* Encryption type */
+#define WPS_ENCRTYPE_NONE 0x0001
+#define WPS_ENCRTYPE_WEP 0x0002 /* Deprecated in WSC 2.0 */
+#define WPS_ENCRTYPE_TKIP 0x0004 /* Deprecated in version 2.0. TKIP can only
+ * be advertised on the AP when Mixed Mode
+ * is enabled (Encryption Type is 0x000c).
+ */
+#define WPS_ENCRTYPE_AES 0x0008
+
+
+/* WPS Message Types */
+#define WPS_ID_BEACON 0x01
+#define WPS_ID_PROBE_REQ 0x02
+#define WPS_ID_PROBE_RESP 0x03
+#define WPS_ID_MESSAGE_M1 0x04
+#define WPS_ID_MESSAGE_M2 0x05
+#define WPS_ID_MESSAGE_M2D 0x06
+#define WPS_ID_MESSAGE_M3 0x07
+#define WPS_ID_MESSAGE_M4 0x08
+#define WPS_ID_MESSAGE_M5 0x09
+#define WPS_ID_MESSAGE_M6 0x0A
+#define WPS_ID_MESSAGE_M7 0x0B
+#define WPS_ID_MESSAGE_M8 0x0C
+#define WPS_ID_MESSAGE_ACK 0x0D
+#define WPS_ID_MESSAGE_NACK 0x0E
+#define WPS_ID_MESSAGE_DONE 0x0F
+
+/* WSP private ID for local use */
+#define WPS_PRIVATE_ID_IDENTITY (WPS_ID_MESSAGE_DONE + 1)
+#define WPS_PRIVATE_ID_WPS_START (WPS_ID_MESSAGE_DONE + 2)
+#define WPS_PRIVATE_ID_FAILURE (WPS_ID_MESSAGE_DONE + 3)
+#define WPS_PRIVATE_ID_FRAG (WPS_ID_MESSAGE_DONE + 4)
+#define WPS_PRIVATE_ID_FRAG_ACK (WPS_ID_MESSAGE_DONE + 5)
+#define WPS_PRIVATE_ID_EAPOL_START (WPS_ID_MESSAGE_DONE + 6)
+
+
+/* Device Type categories for primary and secondary device types */
+#define WPS_DEVICE_TYPE_CAT_COMPUTER 1
+#define WPS_DEVICE_TYPE_CAT_INPUT_DEVICE 2
+#define WPS_DEVICE_TYPE_CAT_PRINTER 3
+#define WPS_DEVICE_TYPE_CAT_CAMERA 4
+#define WPS_DEVICE_TYPE_CAT_STORAGE 5
+#define WPS_DEVICE_TYPE_CAT_NW_INFRA 6
+#define WPS_DEVICE_TYPE_CAT_DISPLAYS 7
+#define WPS_DEVICE_TYPE_CAT_MM_DEVICES 8
+#define WPS_DEVICE_TYPE_CAT_GAME_DEVICES 9
+#define WPS_DEVICE_TYPE_CAT_TELEPHONE 10
+#define WPS_DEVICE_TYPE_CAT_AUDIO_DEVICES 11 /* WSC 2.0 */
+
+/* Device Type sub categories for primary and secondary device types */
+#define WPS_DEVICE_TYPE_SUB_CAT_COMP_PC 1
+#define WPS_DEVICE_TYPE_SUB_CAT_COMP_SERVER 2
+#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MEDIA_CTR 3
+#define WPS_DEVICE_TYPE_SUB_CAT_COMP_UM_PC 4 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NOTEBOOK 5 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_COMP_DESKTOP 6 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MID 7 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NETBOOK 8 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_INP_Keyboard 1 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_INP_MOUSE 2 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_INP_JOYSTICK 3 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_INP_TRACKBALL 4 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_INP_GAM_CTRL 5 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_INP_REMOTE 6 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_INP_TOUCHSCREEN 7 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_INP_BIO_READER 8 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_INP_BAR_READER 9 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_PRINTER 1
+#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_SCANNER 2
+#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_FAX 3 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_COPIER 4 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_ALLINONE 5 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_CAM_DGTL_STILL 1
+#define WPS_DEVICE_TYPE_SUB_CAT_CAM_VIDEO_CAM 2 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_CAM_WEB_CAM 3 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_CAM_SECU_CAM 4 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_STOR_NAS 1
+#define WPS_DEVICE_TYPE_SUB_CAT_NW_AP 1
+#define WPS_DEVICE_TYPE_SUB_CAT_NW_ROUTER 2
+#define WPS_DEVICE_TYPE_SUB_CAT_NW_SWITCH 3
+#define WPS_DEVICE_TYPE_SUB_CAT_NW_GATEWAY 4 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_NW_BRIDGE 5 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_DISP_TV 1
+#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PIC_FRAME 2
+#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PROJECTOR 3
+#define WPS_DEVICE_TYPE_SUB_CAT_DISP_MONITOR 4 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_MM_DAR 1
+#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVR 2
+#define WPS_DEVICE_TYPE_SUB_CAT_MM_MCX 3
+#define WPS_DEVICE_TYPE_SUB_CAT_MM_STB 4 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_MM_MS_ME 5 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVP 6 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX 1
+#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX_360 2
+#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PS 3
+#define WPS_DEVICE_TYPE_SUB_CAT_GAM_GC 4 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PGD 5 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_WM 1
+#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PSM 2 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PDM 3 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SSM 4 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SDM 5 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_TUNER 1 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_SPEAKERS 2 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_PMP 3 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HEADSET 4 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HPHONE 5 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_MPHONE 6 /* WSC 2.0 */
+#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HTS 7 /* WSC 2.0 */
+
+
+/* Device request/response type */
+#define WPS_MSGTYPE_ENROLLEE_INFO_ONLY 0x00
+#define WPS_MSGTYPE_ENROLLEE_OPEN_8021X 0x01
+#define WPS_MSGTYPE_REGISTRAR 0x02
+#define WPS_MSGTYPE_AP_WLAN_MGR 0x03
+
+/* RF Band */
+#define WPS_RFBAND_24GHZ 0x01
+#define WPS_RFBAND_50GHZ 0x02
+
+/* Simple Config state */
+#define WPS_SCSTATE_UNCONFIGURED 0x01
+#define WPS_SCSTATE_CONFIGURED 0x02
+#define WPS_SCSTATE_OFF 11
+
+/* WPS Vendor extension key */
+#define WPS_OUI_HEADER_LEN 2
+#define WPS_OUI_HEADER_SIZE 4
+#define WPS_OUI_FIXED_HEADER_OFF 16
+#define WPS_WFA_SUBID_V2_OFF 3
+#define WPS_WFA_V2_OFF 5
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WPS_ */
diff --git a/wl/src/Makerules b/wl/src/Makerules
new file mode 100644
index 0000000..e576370
--- /dev/null
+++ b/wl/src/Makerules
@@ -0,0 +1,639 @@
+
+
+#
+# Top level Makerules
+# it uses Makerules.env for build env vars and optional branding.inc
+#
+# Copyright (C) 2017, Broadcom. All Rights Reserved.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+#
+# <<Broadcom-WL-IPTag/Open:>>
+#
+# $Id: Makerules 646625 2016-06-30 02:57:52Z $
+
+# This is the TOP level makefile rules, which is used by many makefiles.
+# Please be cautious on changes, especially compatibilities.
+# e.g. new gcc compile option should be protected with version check
+# or "check_gcc" trick
+
+# first rule (default)
+all:
+
+APPLY_PREFIX ?= true
+
+WLAN_ComponentsInUse ?= bcmwifi
+include $(dir $(lastword $(MAKEFILE_LIST)))makefiles/WLAN_Common.mk
+
+# Set up the build environment variables
+include ${SRCBASE}/Makerules.env
+
+ifeq ($(HOSTOS), Windows_NT)
+
+# force use of bash, otherwise you will get the broken sh.exe.
+SHELL=bash
+
+endif
+
+#
+# Setup make variables depending on target
+#
+
+ifeq ($(TARGETOS), unix)
+
+ # The environment for native unix builds
+
+ EXEEXT =
+ OBJEXT = .o
+ GCINCS = $(strip -I$(SRCBASE)/include $(WLAN_ComponentIncPath)) $(WLAN_StdIncPathA)
+ GCDEFS = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) -DTARGETARCH_$(TARGETARCH)
+
+ ifeq ($(TARGETARCH), x86_mmx)
+ GCDEFS := $(GCDEFS) -D_X86_ -D_MMX_
+ endif
+ ifeq ($(TARGETARCH), x86)
+ GCDEFS := $(GCDEFS) -D_X86_
+ endif
+ ifeq ($(TARGETARCH), x86_android_ndk_r6b)
+ GCDEFS := $(GCDEFS) -D_X86_
+ endif
+ ifeq ($(TARGETARCH), mips)
+ GCDEFS := $(GCDEFS) -D_MIPS_
+ endif
+ ifeq ($(TARGETARCH), mips_be)
+ GCDEFS := $(GCDEFS) -D_MIPS_ -DIL_BIGENDIAN
+ endif
+ ifeq ($(TARGETARCH), arm)
+ GCDEFS := $(GCDEFS) -D_ARM_ -DIL_BIGENDIAN
+ endif
+ ifeq ($(TARGETARCH), arm_le)
+ GCDEFS := $(GCDEFS) -D_ARM_
+ endif
+ ifeq ($(TARGETARCH), arm_android)
+ GCDEFS := $(GCDEFS) -D_ARM_
+ endif
+ ifeq ($(TARGETARCH), arm64_android)
+ GCDEFS := $(GCDEFS) -D_ARM_
+ endif
+ ifeq ($(TARGETARCH), arm_android_ndk_r6b)
+ GCDEFS := $(GCDEFS) -D_ARM_
+ endif
+
+# ifeq ($(TARGETENV), freebsd)
+# ifeq ($(HOSTENV), freebsd)
+# GCINCS := $(GCINCS) -I/usr/include
+# endif
+# endif
+ ifeq ($(TARGETENV), sun4)
+ GCDEFS := $(GCDEFS) -D_SPARC_
+ endif
+ ifeq ($(TARGETENV), macos)
+ MACOS_VER := $(shell sw_vers -productVersion)
+
+ # Default dev dir
+ dev_dir := /Applications/Xcode.app/Contents/Developer
+
+ # SDKs dir in the default Developer dir
+ sdk_dir := $(dev_dir)/Platforms/MacOSX.platform/Developer/SDKs
+
+ # Set default SDKROOT based on the host machine MacOS version
+ # If command line SDKROOT is provided, it will take precedence
+
+ ifneq (,$(findstring 10.11,$(MACOS_VER)))
+ export SDKROOT := $(sdk_dir)/MacOSX10.11.sdk
+
+ else ifneq (,$(findstring 10.10,$(MACOS_VER)))
+ export SDKROOT := $(sdk_dir)/MacOSX10.10.sdk
+
+ else ifneq (,$(findstring 10.9,$(MACOS_VER)))
+ export SDKROOT := $(sdk_dir)/MacOSX10.9.sdk
+
+ else ifneq (,$(findstring 10.8,$(MACOS_VER)))
+ export SDKROOT := $(sdk_dir)/MacOSX10.8.sdk
+
+ else ifneq (,$(findstring 10.7,$(MACOS_VER)))
+ SDK=/Developer/SDKs/MacOSX10.7.sdk
+ GCDEFS += -isysroot $(SDK)
+
+ else ifneq (,$(findstring 10.6,$(MACOS_VER)))
+ SDK=/Developer/SDKs/MacOSX10.6.sdk
+ GCDEFS += -isysroot $(SDK)
+ endif
+
+ GCDEFS := $(GCDEFS) -DMACOSX
+
+ ifeq ($(TARGETARCH), PPC)
+ GCDEFS := $(GCDEFS) -arch ppc -mtune=G4
+ GLDFLAGS = -arch ppc -Wl,-syslibroot,$(SDK)
+ endif
+ ifeq ($(TARGETARCH), x86)
+ GCDEFS := $(GCDEFS) -arch x86_64
+ GLDFLAGS = -arch x86_64
+ endif
+ endif
+
+ GCOPTS =
+ GCFLAGS = -g -Wall
+
+ CC_TARGET =-o $@
+ LINK_TARGET =-o $@
+
+ ifeq ($(TARGETENV), linuxmips)
+ TARGET_PREFIX = mipsel-linux-
+ else
+ ifeq ($(TARGETENV), linuxmips_be)
+ TARGET_PREFIX = mips-linux-
+ else
+ ifeq ($(TARGETENV), linuxarm)
+ TARGET_PREFIX = armeb-linux-
+ else
+ ifeq ($(TARGETENV), linuxarm_le)
+ TARGET_PREFIX ?= arm-linux-
+ ifneq ($(LINUXDIR),)
+ GCFLAGS += -I$(LINUXDIR)/include
+ endif
+ else
+ ifeq ($(TARGETENV), android)
+ TARGET_PREFIX ?= arm-eabi-
+ GCFLAGS += -Dlinux -DTARGETENV_android
+ else
+ ifeq ($(TARGETENV), android_ndk_r6b)
+ #TARGET_PREFIX = arm-linux-androideabi-
+
+ ifeq ($(TARGET_PREFIX),)
+$(warning : TARGET_PREFIX is not set!)
+ endif
+ ifeq ($(TARGET_NDK),)
+$(warning : TARGET_NDK is not set!)
+ endif
+ ifeq ($(LINUXDIR),)
+$(warning : LINUXDIR is not set!)
+ endif
+ GCDEFS := $(GCDEFS) -fno-short-enums
+
+ GCFLAGS += -Dlinux -DTARGETENV_android
+ ifeq ($(TARGETARCH), arm_android_ndk_r6b)
+ GCFLAGS += -DTARGETARCH_arm_android
+ GCFLAGS += -I$(TARGET_NDK)/platforms/android-9/arch-arm/usr/include/
+ GCFLAGS += -march=armv5te -mtune=xscale -msoft-float
+ GCFLAGS += -mthumb-interwork
+ else
+ ifeq ($(TARGETARCH), x86_android_ndk_r6b)
+ GCFLAGS += -DTARGETARCH_x86_android
+ GCFLAGS += -I$(TARGET_NDK)/platforms/android-9/arch-x86/usr/include/
+ GCFLAGS += -march=i686
+ endif
+ endif
+ GCFLAGS += -fpic -fno-exceptions
+ GCFLAGS += -ffunction-sections -funwind-tables
+ GCFLAGS += -fstack-protector -fmessage-length=0
+ GCFLAGS += -I$(LINUXDIR)/include/uapi/
+ GCFLAGS += -I$(LINUXDIR)/include/
+ else
+ TARGET_PREFIX =
+ endif
+ endif
+ endif
+ endif
+ endif
+ endif
+
+ ifeq ($(APPLY_PREFIX),true)
+ CC = $(TARGET_PREFIX)gcc
+ AS = $(TARGET_PREFIX)as
+ LD = $(TARGET_PREFIX)ld
+ AR = $(TARGET_PREFIX)ar
+ endif
+
+ INSTALL = install -c
+
+ TCFLAGS =
+
+ ifeq ($(TARGETENV), freebsd)
+ GLDFLAGS = -static
+ endif
+ ifeq ($(TARGETENV), freebsd_be)
+ GLDFLAGS = -static
+ endif
+ ifeq ($(TARGETENV), linuxarm)
+ GLDFLAGS = -static
+ endif
+ ifeq ($(TARGETENV), linuxarm_le)
+ GLDFLAGS ?= -static
+ endif
+ ifeq ($(TARGETENV), android)
+ GLDFLAGS = -static
+ endif
+ ifeq ($(TARGETENV), android_ndk_r6b)
+ GLDFLAGS = -Bdynamic -Wl,-dynamic-linker,/system/bin/linker
+ GLDFLAGS += -lm -lc -ldl
+ GLDFLAGS += -nostdlib
+ GLDFLAGS += -Wl,--gc-sections -Wl,-z,nocopyreloc
+ GLDFLAGS += -Wl,--no-undefined
+ ifeq ($(TARGETARCH), arm_android_ndk_r6b)
+ GLDFLAGS += -ldl
+ GLDFLAGS += -Wl,-T,$(TARGET_NDK)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/arm-linux-androideabi/lib/ldscripts/armelf_linux_eabi.x
+ GLDFLAGS += -Wl,-rpath-link=$(TARGET_NDK)/platforms/android-9/arch-arm
+ GLDFLAGS += -L$(TARGET_NDK)/platforms/android-9/arch-arm/usr/lib
+ GLDFLAGS += $(TARGET_NDK)/platforms/android-9/arch-arm/usr/lib/crtend_android.o
+ GLDFLAGS += $(TARGET_NDK)/platforms/android-9/arch-arm/usr/lib/crtbegin_dynamic.o
+ GLDFLAGS += $(TARGET_NDK)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a
+ else
+ ifeq ($(TARGETARCH), x86_android_ndk_r6b)
+ GLDFLAGS += -m32 -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
+ GLDFLAGS += -Wl,-z,relro,-z,now -fPIE -pie
+ GLDFLAGS += -L$(TARGET_NDK)/platforms/android-9/arch-x86/usr/lib
+ GLDFLAGS += -Wl,-rpath-link=$(TARGET_NDK)/platforms/android-9/arch-x86
+ GLDFLAGS += -lstdc++
+ GLDFLAGS += $(TARGET_NDK)/platforms/android-9/arch-x86/usr/lib/crtbegin_dynamic.o
+ GLDFLAGS += -Wl,--whole-archive -Wl,--no-whole-archive
+ GLDFLAGS += $(TARGET_NDK)/toolchains/x86-4.4.3/prebuilt/linux-x86/lib/gcc/i686-android-linux/4.4.3/libgcc.a
+ GLDFLAGS += $(TARGET_NDK)/platforms/android-9/arch-x86/usr/lib/crtend_android.o
+ endif
+ endif
+ endif
+
+ GLDLIBS = -lgcc
+
+endif # $(TARGETOS) == unix
+
+ifeq ($(TARGETOS), Windows_NT)
+
+ # The environment for windows builds
+
+ EXEEXT = .exe
+
+ ifeq ($(TARGETENV), win32)
+ # standard win32 using MS compiler
+ OBJEXT = .obj
+ GCINCS = $(strip /I$(SRCBASE)/include $(patsubst -I%,/I%,$(WLAN_StdIncPathA)) $(patsubst -I%,/I%,$(WLAN_ComponentIncPath)))
+ GCDEFS = /DTARGETENV_$(TARGETENV) /DTARGETOS_$(TARGETOS) \
+ /DTARGETARCH_$(TARGETARCH) /D_X86_
+ ifeq ($(TARGETARCH), x86_mmx)
+ GCDEFS += /D_MMX_
+ endif
+ GCOPTS = /nologo
+ GCFLAGS = /GM /W3 /Z7
+
+ CC_TARGET =-Fo$@
+ LINK_TARGET =-out:$@
+
+ CC = cl
+ AS = cl
+ LD = cl
+
+ TCFLAGS =
+ GLDFLAGS = /nologo /link /nologo /INCREMENTAL:NO
+
+ GLDLIBS =
+ else
+ # cygwin32 based environment
+ OBJEXT = .o
+ GCINCS = $(strip -I$(SRCBASE)/include $(WLAN_StdIncPathA) $(WLAN_ComponentIncPath))
+ GCDEFS = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) \
+ -DTARGETARCH_$(TARGETARCH) -D_X86_
+ ifeq ($(TARGETARCH), x86_mmx)
+ GCDEFS += -D_MMX_
+ endif
+ GCOPTS =
+ GCFLAGS = -g -Wall
+
+ CC_TARGET =-o $@
+ LINK_TARGET =-o $@
+
+ CC = gcc
+ AS = gcc
+ LD = gcc
+ INSTALL = install -c
+
+ TCFLAGS =
+ GLDFLAGS =
+
+ GLDLIBS = -liberty -lgcc
+ endif
+
+ # Tools common to cygwin/win32
+
+ INSTALL = install -c
+ BUILD = build -ceZ
+
+ # RELEASE_TARGET is a the directory under RELEASE_DIR where
+ # target dependant files go. It is composed of the OS and
+ # the CPU, some examples are: winnt40/i386, win98 ...
+ #
+ # NEEDSWORK: For now only NT 4.0 stuff uses it.
+ ifneq ($(findstring $(TARGETPLATFORM), "Wdm wdm"), )
+ RELEASE_TARGET = wdm/i386
+ else
+ RELEASE_TARGET = winnt40/i386
+ endif
+
+ # RELEASE_TOOLS_DIR is a the directory under RELEASE_DIR where
+ # common tools go.
+ # For compatability with previous installs &test scripts, old
+ # tools still go in "yosemite".
+ RELEASE_YOS_DIR = yosemite
+ RELEASE_TOOLS_DIR = tools
+
+endif # $(TARGETOS) == Windows_NT
+
+ifeq ($(TARGETOS), vxWorks)
+ WIND_REGISTRY = sol
+ ifndef WIND_BASE
+ ifeq ($(HOSTOS), unix)
+ WIND_BASE = /dfs/tools/vxWorks
+ else
+ WIND_BASE = $(WLAN_WINPFX)/tools/vxWorks
+ endif
+ endif
+ include $(WIND_BASE)/target/h/make/defs.default
+
+ ifeq ($(HOSTENV), Windows_NT)
+ WIND_HOST_TYPE = x86-win32
+ else
+ ifeq ($(HOSTENV), sun4)
+ WIND_HOST_TYPE = sun4-solaris2
+ else
+ WIND_HOST_TYPE = i386-freebsd
+ endif
+ endif
+
+ ifeq ($(TARGETENV), vxsim)
+ CPU = SIMSPARCSOLARIS
+ else
+ ifeq ($(TARGETENV), vx386)
+ CPU = i386
+ else
+ CPU = R4650
+ VXFLAGS = -DCPU_VAR=$(CPU)
+ endif
+ endif
+
+ include $(WIND_BASE)/target/h/make/make.$(CPU)$(TOOL)
+ include $(WIND_BASE)/target/h/make/defs.$(WIND_HOST_TYPE)
+
+ GCINCS = -I$(WIND_BASE)/target/h -I$(SRCBASE)/include $(WLAN_StdIncPathA)
+ GCDEFS = $(DEFINE_CC) -DCPU=$(CPU) -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) -DTARGETARCH_$(TARGETARCH)
+ GCOPTS = -g -O2
+ GCFLAGS = -Wall $(CC_ARCH_SPEC)
+ LDFLAGS = $(GLDFLAGS) $(LLDFLAGS)
+ GLDLIBS = $(LIBS)
+
+ WIND_BIN = $(WIND_BASE)/host/$(WIND_HOST_TYPE)/bin
+
+ AR := $(WIND_BIN)/$(AR)
+ AS := $(WIND_BIN)/$(AS)
+ BINHEX := $(WIND_BIN)/$(BINHEX)
+ CC := $(WIND_BIN)/$(CC)
+ CF := $(WIND_BIN)/$(CF)
+ LD := $(CC)
+ NM := $(WIND_BIN)/$(NM)
+ RANLIB := $(WIND_BIN)/$(RANLIB)
+ BINXSYM_NAME := $(WIND_BIN)/$(BINXSYM)
+
+endif # $(TARGETOS) == vxWorks
+
+ifeq ($(TARGETENV), nucleusarm)
+
+ # The environment for nucleus builds
+ ifeq ($(BSP_BASE_DIR),)
+ BSP_BASE_DIR := $(SRCBASE)/../bsp
+ endif
+
+ ifeq ($(NUCLEUS_INC_DIR),)
+ NUCLEUS_INC_DIR := $(BSP_BASE_DIR)/rtos/nucleus/inc
+ endif
+
+ EXEEXT :=
+ OBJEXT := .o
+ GCINCS := $(strip -I$(SRCBASE)/include $(WLAN_StdIncPathA) -I$(NUCLEUS_INC_DIR) $(WLAN_ComponentIncPath))
+ GCDEFS := -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) -DTARGETARCH_$(TARGETARCH)
+ GCOPTS :=
+
+ ifeq ($(OBJDIR),)
+ OBJDIR := $(TARGETENV)/
+ endif
+
+ # --md: This option compiles the source and writes make file dependency lines
+ # to a file. The output file is suitable for use by a make utility.
+ # -c: Compiles but does not perform the link phase.
+ # -O2: High optimization.
+ # ---memaccess -UL41: This option tells the compiler that the memory in the
+ # target system has slightly restricted or expanded capabilities.
+ # Disables unaligned mode for code that uses pre-ARMv6 unaligned
+ # access behavior.
+ # "/adsabi" is added to "--apcs /interwork/$(SWST)" so that objects created
+ # under ADS 1.2 can be linked with objects compiled under RVCT 2.2.
+ # --diag_suppress 2084,1658 = blocks the diagnostic warning "Warning: C2084W: support for --apcs /adsabi is deprecated"
+ # 1293: Suppress "assignment in condition" warning.
+ # 550: Suppress "variable set but never used" warning.
+ GCFLAGS := --md \
+ -c \
+ -O2 \
+ --memaccess -UL41 \
+ --apcs /adsabi/interwork/NOSWST \
+ --diag_suppress 2084,1658,1293,550 \
+ --li
+
+ # --cpu 'name': This option generates code for a specific ARM processor or architecture.
+ ifeq ($(TARGETCPU),2153)
+ GCFLAGS += --cpu ARM1136J-S
+ else
+ $(error "Unknown target CPU type!")
+ endif
+
+ #CPPFLAGS := -embeddedcplusplus
+
+ CC_TARGET =-o $@
+ CPP_TARGET =-o $@
+ LINK_TARGET =-o $@
+
+ CC := tcc
+ CPP := tcpp
+ AS := armasm
+ LD := armlink
+ AR := armar -c -r --create
+
+ INSTALL := install -c
+
+ TCFLAGS :=
+
+ GLDFLAGS :=
+ GLDLIBS := --ELF --symbols --debug --map --info sizes,totals --errors link.err --list link.map --verbose
+
+ # Convert windows style directories to cygwin style.
+ # It should be used in situations where the host environment is cygwin, and
+ # the host compiler is a native Win32 app (non-cygwin). It will convert the
+ # Windows style directories in the dependencies list to cygwin style. This is
+ # necessary for the dependency files to be included by cygwin make.
+ ifeq ($(HOSTOS),Windows_NT)
+ FILTER_DEPENDS_IN_C_TO_OBJ_RULE := 1
+ endif
+
+endif # $(TARGETENV) == nucleusarm
+
+ifeq ($(TARGETENV), bcmmips)
+
+ OBJEXT = .o
+ GCINCS = $(strip -I$(SRCBASE)/include $(WLAN_StdIncPathA) $(WLAN_ComponentIncPath))
+ GCDEFS = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) \
+ -DTARGETARCH_$(TARGETARCH) -D__mips__
+ GCOPTS = -g -O2
+ GCFLAGS = -Wall
+ GLDFLAGS = -Wl,-tidt.dld
+
+ AS = bcmas
+ CC = bcmgcc
+ LD = $(CC)
+ NM = bcmnm
+ RANLIB = bcmranlib
+
+endif # $(TARGETENV) == bcmmips
+
+ifeq ($(TARGETENV), klsi)
+
+ OBJEXT = .obj
+ GCINCS = $(strip -I$(SRCBASE)/include $(WLAN_StdIncPathA) $(WLAN_ComponentIncPath))
+ GCDEFS = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) \
+ -DTARGETARCH_$(TARGETARCH) -D__klsi__
+
+ AS = qtasm
+ GASFLAGS = -m20
+ CC = qtcc
+ TCFLAGS = -w asm=$(GASFLAGS) +c -Vcdv -w cc=+reginfo
+
+endif # $(TARGETENV) == klsi
+
+CFLAGS = $(LCINCS) $(GCINCS) $(GCDEFS) $(GCOPTS) $(GCFLAGS) $(TCFLAGS) $(HCFLAGS) \
+$(LCDEFS) $(LCOPTS) $(LCFLAGS) $(CENV)
+
+ASFLAGS = $(GASFLAGS) $(LASFLAGS) $(ASENV)
+LDFLAGS = $(GLDFLAGS) $(LLDFLAGS) $(LDENV)
+LDLIBS = $(LLDLIBS) $(GLDLIBS)
+
+# dependency files including the .d file itself.
+# note the example in GNU documentation seems to have a bug:
+# two backslashes where one is correct.
+%.d: %.c
+ifeq ($(findstring s, $(MAKEFLAGS) ),)
+ @ echo making $@
+endif
+ @ $(SHELL) -ec '$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< \
+ | sed '\''s/$*\.o[ :]*/$@ &/g'\'' >$@'
+
+ifeq ($(TARGETENV), win32)
+
+# win32 needs different command line args
+
+%.s: %.c
+ $(CC) /FAs $(CFLAGS) $(CPPFLAGS) /Fa$@ /c $<
+
+%.i: %.c
+ $(CC) /E $(CFLAGS) $(CPPFLAGS) $< > $@
+
+else # !win32
+
+%.s: %.c
+ $(CC) -S $(CFLAGS) $(CPPFLAGS) -o $@ $<
+
+%.i: %.c
+ $(CC) -o $@ -E -dD $(CFLAGS) $(CPPFLAGS) $<
+
+endif # win32
+
+ifeq ($(TARGETENV), klsi)
+
+%$(OBJEXT): %.c
+ $(CC) $(CFLAGS) $*.c
+
+%$(OBJEXT): %.asm
+ $(AS) $(ASFLAGS) $*.asm
+
+%.asm: %.c
+ $(CC) $(CFLAGS) -asm $*.c
+
+%.i: %.c
+ $(CC) $(CFLAGS) -cc -peep -asm $*.c
+ mv $*.pp $*.i
+
+else
+
+
+# This command sequence will:
+# - Convert back-slashes to foward-slashes
+# - Convert long filenames to 8.3 format (e.g. Program Files --> PROGRA~1)
+# - Convert windows-style drive letters to cygwin style.
+#
+# It should be used in situations where the host environment is cygwin, and
+# the host compiler is a native Win32 app (non-cygwin). It will convert the
+# Windows style directories in the dependencies list to cygwin style. This is
+# necessary for the dependency files to be included by cygwin make.
+define FILTER_DEPENDS
+ sed -e 's/\\/\//g' \
+ -e 's/Program Files/PROGRA~1/g' \
+ -e 's/\([A-Za-z]\):\//\/cygdrive\/\1\//' < $(notdir $(@:.o=.d)) > $(@:.o=.d) && \
+ rm -f $(notdir $(@:.o=.d))
+endef
+
+
+$(OBJDIR)%$(OBJEXT): %.c
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) $(CC_TARGET) $<
+ifeq ($(FILTER_DEPENDS_IN_C_TO_OBJ_RULE),1)
+ ${FILTER_DEPENDS}
+endif
+
+$(OBJDIR)%$(OBJEXT): %.cpp
+ $(CPP) -c $(CFLAGS) $(CPPFLAGS) $(CPP_TARGET) $<
+ifeq ($(FILTER_DEPENDS_IN_C_TO_OBJ_RULE),1)
+ ${FILTER_DEPENDS}
+endif
+
+
+endif # klsi
+
+%.h: %.x
+ rpcgen -C -h $< > $@
+
+%_xdr.c: %.x
+ @ (if [ ! -f `basename $<` ] ; then ln -s $< . ; fi; true)
+ rpcgen -C -c -i 0 `basename $<` > $@
+
+# Makefile debugging rule
+env:
+ printenv
+
+# if the user mistakenly specified RELEASE_DIR in unix-style notation,
+# convert it to Win32 notation for them.
+#
+# RELEASE_DIR is assumed to be in windows-style notation if it has both
+# backslashes ('\') and colons (':').
+#
+
+ifneq ("$(subst \,,$(RELEASE_DIR))", "$(RELEASE_DIR)")
+ifneq ("$(subst :,,$(RELEASE_DIR))", "$(RELEASE_DIR)")
+RELEASE_DIR := $(subst :,,$(RELEASE_DIR))
+RELEASE_DIR := $(subst \,/,$(RELEASE_DIR))
+RELEASE_DIR := //$(RELEASE_DIR)
+endif
+endif
+
+# all release rules depend on a valid RELEASE_DIR
+release: check_release_dir
+check_release_dir:
+ @if [ "x$(RELEASE_DIR)" = "x" ]; then \
+ echo "RELEASE_DIR is not set!"; \
+ exit 1; \
+ fi;
+
+include ${SRCBASE}/branding.inc
diff --git a/wl/src/Makerules.env b/wl/src/Makerules.env
new file mode 100644
index 0000000..22f9888
--- /dev/null
+++ b/wl/src/Makerules.env
@@ -0,0 +1,151 @@
+#*******************************************************************************
+#
+# Broadcom Proprietary and Confidential. Copyright (C) 2017,
+# All Rights Reserved.
+#
+# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+# the contents of this file may not be disclosed to third parties, copied
+# or duplicated in any form, in whole or in part, without the prior
+# written permission of Broadcom.
+#
+#
+# <<Broadcom-WL-IPTag/Proprietary:>>
+#
+# $Id: Makerules.env 514727 2014-11-12 03:02:48Z $
+# Top-level Makerules for defining environment variables
+# can be included by anyone doing software at Epigram
+#*******************************************************************************
+
+# HOSTOS is either unix or Windows_NT.
+# HOSTENV differentiates HOSTOS and is either freebsd, sun4, or Windows_NT.
+# This refers to the *BUILD* environment. All environments use "GNU C"
+# except Windows_NT which may use "GNU C" or "Microsoft C".
+
+ifndef HOSTENV
+ # Figure what type of host we are in.
+ UNAME = $(shell uname)
+
+ ifneq ($(findstring "$(UNAME)", "FreeBSD" "NetBSD"), )
+ HOSTENV = freebsd
+ HOSTOS = unix
+ else
+ ifneq ($(findstring "$(UNAME)", "sun4" "SunOS"), )
+ HOSTENV = sun4
+ HOSTOS = unix
+ else
+ ifeq ($(UNAME), Linux)
+ HOSTENV = linux
+ HOSTOS = unix
+ else
+ ifneq ($(findstring CYGWIN,$(UNAME)),)
+ HOSTENV = Windows_NT
+ HOSTOS = Windows_NT
+ else
+ ifeq ($(UNAME), Darwin)
+ HOSTENV = macos
+ HOSTOS = unix
+ else
+ HOSTENV = unknown
+ HOSTOS = unknown
+ endif
+ endif
+ endif
+ endif
+ endif
+endif
+# In case we just defined them, make sure they are known
+export HOSTENV
+export HOSTOS
+
+# TARGETENV is one of freebsd, sun4, linux, linuxarm, android, android_ndk_r6b, linuxmips, linuxmips_be, cygwin32, win32, or macos
+# TARGETENV defaults to HOSTENV unless HOSTENV is Windows_NT, in
+# which case it defaults to win32.
+
+ifndef TARGETENV
+ ifeq ($(HOSTENV), Windows_NT)
+ TARGETENV = win32
+ else
+ TARGETENV = $(HOSTENV)
+ endif
+endif
+export TARGETENV
+
+# TARGETOS defaults to HOSTOS in most cases
+ifneq ($(findstring "$(TARGETENV)", "freebsd" "freebsd_be" "linux" "linuxarm" "linuxarm_le" "android" "android_ndk_r6b" "linuxmips" "linuxmips_be" "sun4" "cygwin32" "win32" "macos"), )
+ TARGETOS = $(HOSTOS)
+endif
+ifeq ($(TARGETENV), bcmmips)
+ TARGETOS = bcmmips
+endif
+ifeq ($(TARGETENV), klsi)
+ TARGETOS = klsi
+endif
+ifeq ($(TARGETENV), nucleusarm)
+ TARGETOS = nucleus
+endif
+ifndef TARGETOS
+ TARGETOS = unknown
+endif
+export TARGETOS
+
+# TARGETARCH is the target processor architecture
+# Currently valid values are: x86, x86_mmx, sparc, unknown, or a list of any
+# of the valid values.
+# For the x86* family, a generic x86 is assuemd if not otherwise specified
+# Order is important since "linux" matches both linuxmips and linux.
+ifndef TARGETARCH
+ ifneq ($(findstring "$(TARGETENV)", "android"), )
+ TARGETARCH = arm_android
+ endif
+
+ ifneq ($(findstring "$(TARGETENV)", "android_ndk_r6b"), )
+ TARGETARCH = arm_android_ndk_r6b
+ endif
+
+ ifneq ($(findstring "$(TARGETENV)", "linuxarm_le"), )
+ TARGETARCH = arm_le
+ endif
+ ifneq ($(findstring "$(TARGETENV)", "linuxarm nucleusarm"), )
+ TARGETARCH = arm
+ endif
+ ifneq ($(findstring "$(TARGETENV)", "bcmmips" "linuxmips" "linuxmips_be"), )
+ TARGETARCH = mips
+ endif
+ ifneq ($(findstring "$(TARGETENV)", "sun4"), )
+ TARGETARCH = sparc
+ endif
+ ifneq ($(findstring "$(TARGETENV)", "freebsd" "linux" "cygwin32" "win32"), )
+ TARGETCPU = $(shell uname -m)
+ ifneq ($(findstring "$(TARGETCPU)", "sparc" "sparc64"), )
+ TARGETARCH = $(TARGETCPU)
+ else
+ TARGETARCH = x86_mmx
+ endif
+ endif
+ ifeq ($(TARGETENV), macos)
+ TARGETCPU = $(shell uname -p)
+ ifneq ($(findstring "$(TARGETCPU)", "powerpc"), )
+ TARGETARCH = PPC
+ else
+ TARGETARCH = x86
+ endif
+ endif
+ ifeq ($(TARGETENV), klsi)
+ TARGETARCH = klsi
+ endif
+ ifndef TARGETARCH
+ TARGETARCH = unknown
+ endif
+endif
+export TARGETARCH
+
+# TARGET_TYPE is either "all" or one or more of: float64, float32, int16
+# default is int16. "all" will get expanded into a list of all possible types
+ifndef TARGET_TYPE
+ TARGET_TYPE = int16
+endif
+
+ifeq ($(TARGET_TYPE), all)
+ TARGET_TYPE = int16 float32 float64
+endif
+export TARGET_TYPE
diff --git a/wl/src/bcmcrypto/sha256.c b/wl/src/bcmcrypto/sha256.c
new file mode 100644
index 0000000..c8024f5
--- /dev/null
+++ b/wl/src/bcmcrypto/sha256.c
@@ -0,0 +1,450 @@
+/* crypto/sha/sha256.c
+ * Code copied from openssl distribution and
+ * Modified just enough so that compiles and runs standalone
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sha256.c 523198 2014-12-29 04:39:42Z $
+ */
+/* ====================================================================
+ * Copyright (c) 2004 The OpenSSL Project. All rights reserved
+ * according to the OpenSSL license [found in ../../LICENSE].
+ * ====================================================================
+ */
+#ifndef BCMDRIVER
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include <typedefs.h>
+#ifdef BCMDRIVER
+#include <osl.h>
+#else
+#include <string.h>
+#endif /* BCMDRIVER */
+
+#include <bcmcrypto/sha256.h>
+
+const char *SHA256_version = "SHA-256";
+
+int SHA224_Init(SHA256_CTX *c)
+{
+ c->h[0] = 0xc1059ed8UL; c->h[1] = 0x367cd507UL;
+ c->h[2] = 0x3070dd17UL; c->h[3] = 0xf70e5939UL;
+ c->h[4] = 0xffc00b31UL; c->h[5] = 0x68581511UL;
+ c->h[6] = 0x64f98fa7UL; c->h[7] = 0xbefa4fa4UL;
+ c->Nl = 0;
+ c->Nh = 0;
+ c->num = 0;
+ c->md_len = SHA224_DIGEST_LENGTH;
+ return 1;
+}
+
+int
+SHA256_Init(SHA256_CTX *c)
+{
+ c->h[0] = 0x6a09e667UL; c->h[1] = 0xbb67ae85UL;
+ c->h[2] = 0x3c6ef372UL; c->h[3] = 0xa54ff53aUL;
+ c->h[4] = 0x510e527fUL; c->h[5] = 0x9b05688cUL;
+ c->h[6] = 0x1f83d9abUL; c->h[7] = 0x5be0cd19UL;
+ c->Nl = 0;
+ c->Nh = 0;
+ c->num = 0;
+ c->md_len = SHA256_DIGEST_LENGTH;
+ return 1;
+}
+
+unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md)
+{
+ SHA256_CTX c;
+ static unsigned char m[SHA224_DIGEST_LENGTH];
+
+ if (md == NULL)
+ md = m;
+
+ SHA224_Init(&c);
+ SHA256_Update(&c, d, n);
+ SHA256_Final(md, &c);
+
+ return (md);
+}
+
+unsigned char *SHA256(const unsigned char *key, size_t n, unsigned char *md)
+{
+ SHA256_CTX c;
+ static unsigned char m[SHA256_DIGEST_LENGTH];
+
+ if (md == NULL)
+ md = m;
+
+ SHA256_Init(&c);
+ SHA256_Update(&c, key, n);
+ SHA256_Final(md, &c);
+
+ return (md);
+}
+
+#ifndef SHA_LONG_LOG2
+#define SHA_LONG_LOG2 2 /* default to 32 bits */
+#endif
+
+#define DATA_ORDER_IS_BIG_ENDIAN
+
+#define HASH_LONG SHA_LONG
+#define HASH_LONG_LOG2 SHA_LONG_LOG2
+#define HASH_CTX SHA256_CTX
+#define HASH_CBLOCK SHA_CBLOCK
+#define HASH_LBLOCK SHA_LBLOCK
+
+/*
+ * Note that FIPS180-2 discusses "Truncation of the Hash Function Output."
+ * default: case below covers for it. It's not clear however if it's
+ * permitted to truncate to amount of bytes not divisible by 4. I bet not,
+ * but if it is, then default: case shall be extended. For reference.
+ * Idea behind separate cases for pre-defined lenghts is to let the
+ * compiler decide if it's appropriate to unroll small loops.
+ */
+#define HASH_MAKE_STRING(c, s) do { \
+ unsigned long ll; \
+ unsigned int n; \
+ switch ((c)->md_len) \
+ { case SHA224_DIGEST_LENGTH: \
+ for (n = 0; n < SHA224_DIGEST_LENGTH/4; n++) \
+ { ll = (c)->h[n]; HOST_l2c(ll, (s)); } \
+ break; \
+ case SHA256_DIGEST_LENGTH: \
+ for (n = 0; n < SHA256_DIGEST_LENGTH/4; n++) \
+ { ll = (c)->h[n]; HOST_l2c(ll, (s)); } \
+ break; \
+ default: \
+ if ((c)->md_len > SHA256_DIGEST_LENGTH) \
+ return 0; \
+ for (n = 0; n < (c)->md_len/4; n++) \
+ { ll = (c)->h[n]; HOST_l2c(ll, (s)); } \
+ break; \
+ } \
+ } while (0)
+
+#define HASH_UPDATE SHA256_Update
+#define HASH_TRANSFORM SHA256_Transform
+#define HASH_FINAL SHA256_Final
+#define HASH_BLOCK_HOST_ORDER sha256_block_host_order
+#define HASH_BLOCK_DATA_ORDER sha256_block_data_order
+
+void sha256_block_host_order(SHA256_CTX *ctx, const void *in, size_t num);
+void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num);
+
+#include <bcmcrypto/md32_common.h>
+
+#ifdef SHA256_ASM
+void sha256_block(SHA256_CTX *ctx, const void *in, size_t num, int host);
+#else
+static const SHA_LONG K256[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+ 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+ 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL };
+
+/*
+ * FIPS specification refers to right rotations, while our ROTATE macro
+ * is left one. This is why you might notice that rotation coefficients
+ * differ from those observed in FIPS document by 32-N...
+ */
+#define Sigma0(x) (ROTATE((x), 30) ^ ROTATE((x), 19) ^ ROTATE((x), 10))
+#define Sigma1(x) (ROTATE((x), 26) ^ ROTATE((x), 21) ^ ROTATE((x), 7))
+#define sigma0(x) (ROTATE((x), 25) ^ ROTATE((x), 14) ^ ((x)>>3))
+#define sigma1(x) (ROTATE((x), 15) ^ ROTATE((x), 13) ^ ((x)>>10))
+
+#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+#ifdef OPENSSL_SMALL_FOOTPRINT
+
+static void
+sha256_block(SHA256_CTX *ctx, const void *in, size_t num, int host)
+{
+ unsigned MD32_REG_T a, b, c, d, e, f, g, h, s0, s1, T1, T2;
+ SHA_LONG X[16];
+ int i;
+ const unsigned char *data = in;
+
+ while (num--) {
+
+ a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3];
+ e = ctx->h[4]; f = ctx->h[5]; g = ctx->h[6]; h = ctx->h[7];
+
+ if (host) {
+ const SHA_LONG *W = (const SHA_LONG *)data;
+
+ for (i = 0; i < 16; i++)
+ {
+ T1 = X[i] = W[i];
+ T1 += h + Sigma1(e) + Ch(e, f, g) + K256[i];
+ T2 = Sigma0(a) + Maj(a, b, c);
+ h = g; g = f; f = e; e = d + T1;
+ d = c; c = b; b = a; a = T1 + T2;
+ }
+
+ data += SHA256_CBLOCK;
+ } else {
+ SHA_LONG l;
+
+ for (i = 0; i < 16; i++) {
+ HOST_c2l(data, l); T1 = X[i] = l;
+ T1 += h + Sigma1(e) + Ch(e, f, g) + K256[i];
+ T2 = Sigma0(a) + Maj(a, b, c);
+ h = g; g = f; f = e; e = d + T1;
+ d = c; c = b; b = a; a = T1 + T2;
+ }
+ }
+
+ for (; i < 64; i++) {
+ s0 = X[(i+1)&0x0f]; s0 = sigma0(s0);
+ s1 = X[(i+14)&0x0f]; s1 = sigma1(s1);
+
+ T1 = X[i&0xf] += s0 + s1 + X[(i+9)&0xf];
+ T1 += h + Sigma1(e) + Ch(e, f, g) + K256[i];
+ T2 = Sigma0(a) + Maj(a, b, c);
+ h = g; g = f; f = e; e = d + T1;
+ d = c; c = b; b = a; a = T1 + T2;
+ }
+
+ ctx->h[0] += a; ctx->h[1] += b; ctx->h[2] += c; ctx->h[3] += d;
+ ctx->h[4] += e; ctx->h[5] += f; ctx->h[6] += g; ctx->h[7] += h;
+
+ }
+}
+
+#else
+
+#define ROUND_00_15(i, a, b, c, d, e, f, g, h) do { \
+ T1 += h + Sigma1(e) + Ch(e, f, g) + K256[i]; \
+ h = Sigma0(a) + Maj(a, b, c); \
+ d += T1; h += T1; } while (0)
+
+#define ROUND_16_63(i, a, b, c, d, e, f, g, h, X) do { \
+ s0 = X[(i+1)&0x0f]; s0 = sigma0(s0); \
+ s1 = X[(i+14)&0x0f]; s1 = sigma1(s1); \
+ T1 = X[(i)&0x0f] += s0 + s1 + X[(i+9)&0x0f]; \
+ ROUND_00_15(i, a, b, c, d, e, f, g, h); } while (0)
+
+static void
+sha256_block(SHA256_CTX *ctx, const void *in, size_t num, int host)
+{
+ unsigned MD32_REG_T a, b, c, d, e, f, g, h, s0, s1, T1;
+ SHA_LONG X[16];
+ int i;
+ const unsigned char *data = in;
+
+ while (num--) {
+
+ a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3];
+ e = ctx->h[4]; f = ctx->h[5]; g = ctx->h[6]; h = ctx->h[7];
+
+ if (host) {
+ const SHA_LONG *W = (const SHA_LONG *)data;
+
+ T1 = X[0] = W[0]; ROUND_00_15(0, a, b, c, d, e, f, g, h);
+ T1 = X[1] = W[1]; ROUND_00_15(1, h, a, b, c, d, e, f, g);
+ T1 = X[2] = W[2]; ROUND_00_15(2, g, h, a, b, c, d, e, f);
+ T1 = X[3] = W[3]; ROUND_00_15(3, f, g, h, a, b, c, d, e);
+ T1 = X[4] = W[4]; ROUND_00_15(4, e, f, g, h, a, b, c, d);
+ T1 = X[5] = W[5]; ROUND_00_15(5, d, e, f, g, h, a, b, c);
+ T1 = X[6] = W[6]; ROUND_00_15(6, c, d, e, f, g, h, a, b);
+ T1 = X[7] = W[7]; ROUND_00_15(7, b, c, d, e, f, g, h, a);
+ T1 = X[8] = W[8]; ROUND_00_15(8, a, b, c, d, e, f, g, h);
+ T1 = X[9] = W[9]; ROUND_00_15(9, h, a, b, c, d, e, f, g);
+ T1 = X[10] = W[10]; ROUND_00_15(10, g, h, a, b, c, d, e, f);
+ T1 = X[11] = W[11]; ROUND_00_15(11, f, g, h, a, b, c, d, e);
+ T1 = X[12] = W[12]; ROUND_00_15(12, e, f, g, h, a, b, c, d);
+ T1 = X[13] = W[13]; ROUND_00_15(13, d, e, f, g, h, a, b, c);
+ T1 = X[14] = W[14]; ROUND_00_15(14, c, d, e, f, g, h, a, b);
+ T1 = X[15] = W[15]; ROUND_00_15(15, b, c, d, e, f, g, h, a);
+
+ data += SHA256_CBLOCK;
+ } else {
+ SHA_LONG l;
+
+ HOST_c2l(data, l); T1 = X[0] = l; ROUND_00_15(0, a, b, c, d, e, f, g, h);
+ HOST_c2l(data, l); T1 = X[1] = l; ROUND_00_15(1, h, a, b, c, d, e, f, g);
+ HOST_c2l(data, l); T1 = X[2] = l; ROUND_00_15(2, g, h, a, b, c, d, e, f);
+ HOST_c2l(data, l); T1 = X[3] = l; ROUND_00_15(3, f, g, h, a, b, c, d, e);
+ HOST_c2l(data, l); T1 = X[4] = l; ROUND_00_15(4, e, f, g, h, a, b, c, d);
+ HOST_c2l(data, l); T1 = X[5] = l; ROUND_00_15(5, d, e, f, g, h, a, b, c);
+ HOST_c2l(data, l); T1 = X[6] = l; ROUND_00_15(6, c, d, e, f, g, h, a, b);
+ HOST_c2l(data, l); T1 = X[7] = l; ROUND_00_15(7, b, c, d, e, f, g, h, a);
+ HOST_c2l(data, l); T1 = X[8] = l; ROUND_00_15(8, a, b, c, d, e, f, g, h);
+ HOST_c2l(data, l); T1 = X[9] = l; ROUND_00_15(9, h, a, b, c, d, e, f, g);
+ HOST_c2l(data, l); T1 = X[10] = l; ROUND_00_15(10, g, h, a, b, c, d, e, f);
+ HOST_c2l(data, l); T1 = X[11] = l; ROUND_00_15(11, f, g, h, a, b, c, d, e);
+ HOST_c2l(data, l); T1 = X[12] = l; ROUND_00_15(12, e, f, g, h, a, b, c, d);
+ HOST_c2l(data, l); T1 = X[13] = l; ROUND_00_15(13, d, e, f, g, h, a, b, c);
+ HOST_c2l(data, l); T1 = X[14] = l; ROUND_00_15(14, c, d, e, f, g, h, a, b);
+ HOST_c2l(data, l); T1 = X[15] = l; ROUND_00_15(15, b, c, d, e, f, g, h, a);
+ }
+
+ for (i = 16; i < 64; i += 8) {
+ ROUND_16_63(i+0, a, b, c, d, e, f, g, h, X);
+ ROUND_16_63(i+1, h, a, b, c, d, e, f, g, X);
+ ROUND_16_63(i+2, g, h, a, b, c, d, e, f, X);
+ ROUND_16_63(i+3, f, g, h, a, b, c, d, e, X);
+ ROUND_16_63(i+4, e, f, g, h, a, b, c, d, X);
+ ROUND_16_63(i+5, d, e, f, g, h, a, b, c, X);
+ ROUND_16_63(i+6, c, d, e, f, g, h, a, b, X);
+ ROUND_16_63(i+7, b, c, d, e, f, g, h, a, X);
+ }
+
+ ctx->h[0] += a; ctx->h[1] += b; ctx->h[2] += c; ctx->h[3] += d;
+ ctx->h[4] += e; ctx->h[5] += f; ctx->h[6] += g; ctx->h[7] += h;
+ }
+}
+
+#endif /* OPENSSL_SMALL_FOOTPRINT */
+#endif /* SHA256_ASM */
+
+/*
+ * Idea is to trade couple of cycles for some space. On IA-32 we save
+ * about 4K in "big footprint" case. In "small footprint" case any gain
+ * is appreciated:-)
+ */
+void
+HASH_BLOCK_HOST_ORDER(SHA256_CTX *ctx, const void *in, size_t num)
+{
+ sha256_block(ctx, in, num, 1);
+}
+
+void
+HASH_BLOCK_DATA_ORDER(SHA256_CTX *ctx, const void *in, size_t num)
+{
+ sha256_block(ctx, in, num, 0);
+}
+
+
+#ifdef BCMSHA256_TEST
+/*
+ * sha1test.c
+ *
+ * Description:
+ * This file will exercise the SHA-256 code performing the three
+ * tests documented in FIPS PUB 180-2 plus one which calls
+ * SHA1Input with an exact multiple of 512 bits, plus a few
+ * error test checks.
+ *
+ * Portability Issues:
+ * None.
+ *
+ */
+
+#include <stdio.h>
+
+/*
+ * Define patterns for testing
+ */
+#define TEST1 "abc"
+#define TEST2a "abcdbcdecdefdefgefghfghighijhi"
+#define TEST2b "jkijkljklmklmnlmnomnopnopq"
+#define TEST2 TEST2a TEST2b
+#define TEST3 "a"
+
+char *testarray[3] = {
+ TEST1,
+ TEST2,
+ TEST3
+};
+
+
+int repeatcount[3] = { 1, 1, 1000000};
+unsigned char resultarray[3][32] =
+{
+ {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad},
+
+ {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
+ 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
+ 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1},
+
+ {0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92,
+ 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67,
+ 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e,
+ 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}
+};
+
+int
+main()
+{
+ SHA256_CTX sha;
+ int i, j, err, fail = 0;
+ unsigned char Message_Digest[32];
+
+ /*
+ * Perform SHA-1 tests
+ */
+ for (j = 0; j < 3; ++j) {
+ printf("\nTest %d: %d, '%s'\n", j + 1, repeatcount[j], testarray[j]);
+
+ err = SHA256_Init(&sha);
+
+ for (i = 0; i < repeatcount[j]; ++i) {
+ err = SHA256_Update(&sha,
+ (const unsigned char *) testarray[j],
+ strlen(testarray[j]));
+ }
+
+ err = SHA256_Final(Message_Digest, &sha);
+ printf("\t");
+ for (i = 0; i < 32; ++i) {
+ printf("%02X ", Message_Digest[i]);
+ }
+ printf("\n");
+ printf("Should match:\n");
+ printf("\t");
+ for (i = 0; i < 32; ++i) {
+ printf("%02X ", resultarray[j][i]);
+ }
+ printf("\n");
+ if (memcmp(Message_Digest, resultarray[j], 32)) fail++;
+ }
+#ifdef EXTRA_SHA256_TEST
+ /* Test some error returns */
+ err = SHA1Input(&sha, (const unsigned char *) testarray[1], 1);
+ printf("\nError %d. Should be %d.\n", err, shaStateError);
+ if (err != shaStateError) fail++;
+
+ err = SHA1Reset(0);
+ printf("\nError %d. Should be %d.\n", err, shaNull);
+ if (err != shaNull) fail++;
+#endif
+ printf("SHA1 test %s\n", fail? "FAILED" : "PASSED");
+ return fail;
+}
+#endif /* BCMSHA1_TEST */
diff --git a/wl/src/branding.inc b/wl/src/branding.inc
new file mode 100644
index 0000000..021c204
--- /dev/null
+++ b/wl/src/branding.inc
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2017, Broadcom. All Rights Reserved.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+#
+# <<Broadcom-WL-IPTag/Open:>>
+#
+BRAND=
+
+export RELAY_FILE_BASE=bcm42rly
diff --git a/wl/src/include/bcm_cfg.h b/wl/src/include/bcm_cfg.h
new file mode 100644
index 0000000..8969980
--- /dev/null
+++ b/wl/src/include/bcm_cfg.h
@@ -0,0 +1,26 @@
+/*
+ * BCM common config options
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcm_cfg.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#ifndef _bcm_cfg_h_
+#define _bcm_cfg_h_
+#endif /* _bcm_cfg_h_ */
diff --git a/wl/src/include/bcm_mpool_pub.h b/wl/src/include/bcm_mpool_pub.h
new file mode 100644
index 0000000..76f087b
--- /dev/null
+++ b/wl/src/include/bcm_mpool_pub.h
@@ -0,0 +1,358 @@
+/*
+ * Memory pools library, Public interface
+ *
+ * API Overview
+ *
+ * This package provides a memory allocation subsystem based on pools of
+ * homogenous objects.
+ *
+ * Instrumentation is available for reporting memory utilization both
+ * on a per-data-structure basis and system wide.
+ *
+ * There are two main types defined in this API.
+ *
+ * pool manager: A singleton object that acts as a factory for
+ * pool allocators. It also is used for global
+ * instrumentation, such as reporting all blocks
+ * in use across all data structures. The pool manager
+ * creates and provides individual memory pools
+ * upon request to application code.
+ *
+ * memory pool: An object for allocating homogenous memory blocks.
+ *
+ * Global identifiers in this module use the following prefixes:
+ * bcm_mpm_* Memory pool manager
+ * bcm_mp_* Memory pool
+ *
+ * There are two main types of memory pools:
+ *
+ * prealloc: The contiguous memory block of objects can either be supplied
+ * by the client or malloc'ed by the memory manager. The objects are
+ * allocated out of a block of memory and freed back to the block.
+ *
+ * heap: The memory pool allocator uses the heap (malloc/free) for memory.
+ * In this case, the pool allocator is just providing statistics
+ * and instrumentation on top of the heap, without modifying the heap
+ * allocation implementation.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcm_mpool_pub.h 535090 2015-02-17 04:49:01Z $
+ */
+
+#ifndef _BCM_MPOOL_PUB_H
+#define _BCM_MPOOL_PUB_H 1
+
+#include <typedefs.h> /* needed for uint16 */
+
+
+/*
+**************************************************************************
+*
+* Type definitions, handles
+*
+**************************************************************************
+*/
+
+/* Forward declaration of OSL handle. */
+struct osl_info;
+
+/* Forward declaration of string buffer. */
+struct bcmstrbuf;
+
+/*
+ * Opaque type definition for the pool manager handle. This object is used for global
+ * memory pool operations such as obtaining a new pool, deleting a pool, iterating and
+ * instrumentation/debugging.
+ */
+struct bcm_mpm_mgr;
+typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h;
+
+/*
+ * Opaque type definition for an instance of a pool. This handle is used for allocating
+ * and freeing memory through the pool, as well as management/instrumentation on this
+ * specific pool.
+ */
+struct bcm_mp_pool;
+typedef struct bcm_mp_pool *bcm_mp_pool_h;
+
+
+/*
+ * To make instrumentation more readable, every memory
+ * pool must have a readable name. Pool names are up to
+ * 8 bytes including '\0' termination. (7 printable characters.)
+ */
+#define BCM_MP_NAMELEN 8
+
+
+/*
+ * Type definition for pool statistics.
+ */
+typedef struct bcm_mp_stats {
+ char name[BCM_MP_NAMELEN]; /* Name of this pool. */
+ unsigned int objsz; /* Object size allocated in this pool */
+ uint16 nobj; /* Total number of objects in this pool */
+ uint16 num_alloc; /* Number of objects currently allocated */
+ uint16 high_water; /* Max number of allocated objects. */
+ uint16 failed_alloc; /* Failed allocations. */
+} bcm_mp_stats_t;
+
+
+/*
+**************************************************************************
+*
+* API Routines on the pool manager.
+*
+**************************************************************************
+*/
+
+/*
+ * bcm_mpm_init() - initialize the whole memory pool system.
+ *
+ * Parameters:
+ * osh: INPUT Operating system handle. Needed for heap memory allocation.
+ * max_pools: INPUT Maximum number of mempools supported.
+ * mgr: OUTPUT The handle is written with the new pools manager object/handle.
+ *
+ * Returns:
+ * BCME_OK Object initialized successfully. May be used.
+ * BCME_NOMEM Initialization failed due to no memory. Object must not be used.
+ */
+int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp);
+
+
+/*
+ * bcm_mpm_deinit() - de-initialize the whole memory pool system.
+ *
+ * Parameters:
+ * mgr: INPUT Pointer to pool manager handle.
+ *
+ * Returns:
+ * BCME_OK Memory pool manager successfully de-initialized.
+ * other Indicated error occured during de-initialization.
+ */
+int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp);
+
+/*
+ * bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The
+ * pool uses a contiguous block of pre-alloced
+ * memory. The memory block may either be provided
+ * by the client or dynamically allocated by the
+ * pool manager.
+ *
+ * Parameters:
+ * mgr: INPUT The handle to the pool manager
+ * obj_sz: INPUT Size of objects that will be allocated by the new pool
+ * Must be >= sizeof(void *).
+ * nobj: INPUT Maximum number of concurrently existing objects to support
+ * memstart INPUT Pointer to the memory to use, or NULL to malloc()
+ * memsize INPUT Number of bytes referenced from memstart (for error checking).
+ * Must be 0 if 'memstart' is NULL.
+ * poolname INPUT For instrumentation, the name of the pool
+ * newp: OUTPUT The handle for the new pool, if creation is successful
+ *
+ * Returns:
+ * BCME_OK Pool created ok.
+ * other Pool not created due to indicated error. newpoolp set to NULL.
+ *
+ *
+ */
+int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr,
+ unsigned int obj_sz,
+ int nobj,
+ void *memstart,
+ unsigned int memsize,
+ const char poolname[BCM_MP_NAMELEN],
+ bcm_mp_pool_h *newp);
+
+
+/*
+ * bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after
+ * all memory objects have been freed back to the pool.
+ *
+ * Parameters:
+ * mgr: INPUT The handle to the pools manager
+ * pool: INPUT The handle of the pool to delete
+ *
+ * Returns:
+ * BCME_OK Pool deleted ok.
+ * other Pool not deleted due to indicated error.
+ *
+ */
+int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp);
+
+/*
+ * bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory
+ * pool allocator uses the heap (malloc/free) for memory.
+ * In this case, the pool allocator is just providing
+ * statistics and instrumentation on top of the heap,
+ * without modifying the heap allocation implementation.
+ *
+ * Parameters:
+ * mgr: INPUT The handle to the pool manager
+ * obj_sz: INPUT Size of objects that will be allocated by the new pool
+ * poolname INPUT For instrumentation, the name of the pool
+ * newp: OUTPUT The handle for the new pool, if creation is successful
+ *
+ * Returns:
+ * BCME_OK Pool created ok.
+ * other Pool not created due to indicated error. newpoolp set to NULL.
+ *
+ *
+ */
+int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz,
+ const char poolname[BCM_MP_NAMELEN],
+ bcm_mp_pool_h *newp);
+
+
+/*
+ * bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after
+ * all memory objects have been freed back to the pool.
+ *
+ * Parameters:
+ * mgr: INPUT The handle to the pools manager
+ * pool: INPUT The handle of the pool to delete
+ *
+ * Returns:
+ * BCME_OK Pool deleted ok.
+ * other Pool not deleted due to indicated error.
+ *
+ */
+int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp);
+
+
+/*
+ * bcm_mpm_stats() - Return stats for all pools
+ *
+ * Parameters:
+ * mgr: INPUT The handle to the pools manager
+ * stats: OUTPUT Array of pool statistics.
+ * nentries: MOD Max elements in 'stats' array on INPUT. Actual number
+ * of array elements copied to 'stats' on OUTPUT.
+ *
+ * Returns:
+ * BCME_OK Ok
+ * other Error getting stats.
+ *
+ */
+int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries);
+
+
+/*
+ * bcm_mpm_dump() - Display statistics on all pools
+ *
+ * Parameters:
+ * mgr: INPUT The handle to the pools manager
+ * b: OUTPUT Output buffer.
+ *
+ * Returns:
+ * BCME_OK Ok
+ * other Error during dump.
+ *
+ */
+int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b);
+
+
+/*
+ * bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to
+ * compensate for alignment requirements of the objects.
+ * This function provides the padded object size. If clients
+ * pre-allocate a memory slab for a memory pool, the
+ * padded object size should be used by the client to allocate
+ * the memory slab (in order to provide sufficent space for
+ * the maximum number of objects).
+ *
+ * Parameters:
+ * mgr: INPUT The handle to the pools manager.
+ * obj_sz: INPUT Input object size.
+ * padded_obj_sz: OUTPUT Padded object size.
+ *
+ * Returns:
+ * BCME_OK Ok
+ * BCME_BADARG Bad arguments.
+ *
+ */
+int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz);
+
+
+/*
+***************************************************************************
+*
+* API Routines on a specific pool.
+*
+***************************************************************************
+*/
+
+
+/*
+ * bcm_mp_alloc() - Allocate a memory pool object.
+ *
+ * Parameters:
+ * pool: INPUT The handle to the pool.
+ *
+ * Returns:
+ * A pointer to the new object. NULL on error.
+ *
+ */
+void* bcm_mp_alloc(bcm_mp_pool_h pool);
+
+/*
+ * bcm_mp_free() - Free a memory pool object.
+ *
+ * Parameters:
+ * pool: INPUT The handle to the pool.
+ * objp: INPUT A pointer to the object to free.
+ *
+ * Returns:
+ * BCME_OK Ok
+ * other Error during free.
+ *
+ */
+int bcm_mp_free(bcm_mp_pool_h pool, void *objp);
+
+/*
+ * bcm_mp_stats() - Return stats for this pool
+ *
+ * Parameters:
+ * pool: INPUT The handle to the pool
+ * stats: OUTPUT Pool statistics
+ *
+ * Returns:
+ * BCME_OK Ok
+ * other Error getting statistics.
+ *
+ */
+void bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats);
+
+
+/*
+ * bcm_mp_dump() - Dump a pool
+ *
+ * Parameters:
+ * pool: INPUT The handle to the pool
+ * b OUTPUT Output buffer
+ *
+ * Returns:
+ * BCME_OK Ok
+ * other Error during dump.
+ *
+ */
+int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b);
+
+
+#endif /* _BCM_MPOOL_PUB_H */
diff --git a/wl/src/include/bcmbloom.h b/wl/src/include/bcmbloom.h
new file mode 100644
index 0000000..59c6273
--- /dev/null
+++ b/wl/src/include/bcmbloom.h
@@ -0,0 +1,66 @@
+/*
+ * Bloom filter support
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: bcmbloom.h 525587 2015-01-10 05:24:58Z $
+ */
+
+#ifndef _bcmbloom_h_
+#define _bcmbloom_h_
+
+#include <typedefs.h>
+#ifdef BCMDRIVER
+#include <osl.h>
+#else
+#include <stddef.h> /* For size_t */
+#endif
+
+struct bcm_bloom_filter;
+typedef struct bcm_bloom_filter bcm_bloom_filter_t;
+
+typedef void* (*bcm_bloom_alloc_t)(void *ctx, uint size);
+typedef void (*bcm_bloom_free_t)(void *ctx, void *buf, uint size);
+typedef uint (*bcm_bloom_hash_t)(void* ctx, uint idx, const uint8 *tag, uint len);
+
+/* create/allocate a bloom filter. filter size can be 0 for validate only filters */
+int bcm_bloom_create(bcm_bloom_alloc_t alloc_cb,
+ bcm_bloom_free_t free_cb, void *callback_ctx, uint max_hash,
+ uint filter_size /* bytes */, bcm_bloom_filter_t **bloom);
+
+/* destroy bloom filter */
+int bcm_bloom_destroy(bcm_bloom_filter_t **bloom, bcm_bloom_free_t free_cb);
+
+/* add a hash function to filter, return an index */
+int bcm_bloom_add_hash(bcm_bloom_filter_t *filter, bcm_bloom_hash_t hash, uint *idx);
+
+/* remove the hash function at index from filter */
+int bcm_bloom_remove_hash(bcm_bloom_filter_t *filter, uint idx);
+
+/* check if given tag is member of the filter. If buf is NULL and/or buf_len is 0
+ * then use the internal state. BCME_OK if member, BCME_NOTFOUND if not,
+ * or other error (e.g. BADARG)
+ */
+bool bcm_bloom_is_member(bcm_bloom_filter_t *filter,
+ const uint8 *tag, uint tag_len, const uint8 *buf, uint buf_len);
+
+/* add a member to the filter. invalid for validate_only filters */
+int bcm_bloom_add_member(bcm_bloom_filter_t *filter, const uint8 *tag, uint tag_len);
+
+/* no support for remove member */
+
+/* get the filter data from state. BCME_BUFTOOSHORT w/ required length in buf_len
+ * if supplied size is insufficient
+ */
+int bcm_bloom_get_filter_data(bcm_bloom_filter_t *filter,
+ uint buf_size, uint8 *buf, uint *buf_len);
+
+#endif /* _bcmbloom_h_ */
diff --git a/wl/src/include/bcmcdc.h b/wl/src/include/bcmcdc.h
new file mode 100644
index 0000000..7343726
--- /dev/null
+++ b/wl/src/include/bcmcdc.h
@@ -0,0 +1,130 @@
+/*
+ * CDC network driver ioctl/indication encoding
+ * Broadcom 802.11abg Networking Device Driver
+ *
+ * Definitions subject to change without notice.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmcdc.h 633551 2016-04-22 22:51:06Z $
+ */
+#ifndef _bcmcdc_h_
+#define _bcmcdc_h_
+#include <proto/ethernet.h>
+
+typedef struct cdc_ioctl {
+ uint32 cmd; /* ioctl command value */
+ uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */
+ uint32 flags; /* flag defns given below */
+ uint32 status; /* status code returned from the device */
+} cdc_ioctl_t;
+
+/* Max valid buffer size that can be sent to the dongle */
+#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN
+
+/* len field is divided into input and output buffer lengths */
+#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */
+ /* excluding IOCTL header */
+#define CDCL_IOC_OUTLEN_SHIFT 0
+#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */
+#define CDCL_IOC_INLEN_SHIFT 16
+
+/* CDC flag definitions */
+#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */
+#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */
+#define CDCF_IOC_OVL_IDX_MASK 0x3c /* overlay region index mask */
+#define CDCF_IOC_OVL_RSV 0x40 /* 1=reserve this overlay region */
+#define CDCF_IOC_OVL 0x80 /* 1=this ioctl corresponds to an overlay */
+#define CDCF_IOC_ACTION_MASK 0xfe /* SET/GET, OVL_IDX, OVL_RSV, OVL mask */
+#define CDCF_IOC_ACTION_SHIFT 1 /* SET/GET, OVL_IDX, OVL_RSV, OVL shift */
+#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */
+#define CDCF_IOC_IF_SHIFT 12
+#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */
+#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */
+
+#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)
+#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT)
+
+#define CDC_GET_IF_IDX(hdr) \
+ ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT))
+#define CDC_SET_IF_IDX(hdr, idx) \
+ ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT)))
+
+/*
+ * BDC header
+ *
+ * The BDC header is used on data packets to convey priority across USB.
+ */
+
+struct bdc_header {
+ uint8 flags; /* Flags */
+ uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 USB flow control info */
+ uint8 flags2;
+ uint8 dataOffset; /* Offset from end of BDC header to packet data, in
+ * 4-byte words. Leaves room for optional headers.
+ */
+};
+
+#define BDC_HEADER_LEN 4
+
+/* flags field bitmap */
+#define BDC_FLAG_EXEMPT 0x03 /* EXT_STA: encryption exemption (host -> dongle?) */
+#define BDC_FLAG_80211_PKT 0x01 /* Packet is in 802.11 format (dongle -> host) */
+#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */
+#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums: host->device */
+#define BDC_FLAG_EVENT_MSG 0x08 /* Payload contains an event msg: device->host */
+#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */
+#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */
+
+/* priority field bitmap */
+#define BDC_PRIORITY_MASK 0x07
+#define BDC_PRIORITY_FC_MASK 0xf0 /* flow control info mask */
+#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */
+
+/* flags2 field bitmap */
+#define BDC_FLAG2_IF_MASK 0x0f /* interface index (host <-> dongle) */
+#define BDC_FLAG2_IF_SHIFT 0
+#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */
+ /* FLOW CONTROL info only */
+
+/* version numbers */
+#define BDC_PROTO_VER_1 1 /* Old Protocol version */
+#define BDC_PROTO_VER 2 /* Protocol version */
+
+/* flags2.if field access macros */
+#define BDC_GET_IF_IDX(hdr) \
+ ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))
+#define BDC_SET_IF_IDX(hdr, idx) \
+ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | ((idx) << BDC_FLAG2_IF_SHIFT)))
+
+#define BDC_FLAG2_PAD_MASK 0xf0
+#define BDC_FLAG_PAD_MASK 0x03
+#define BDC_FLAG2_PAD_SHIFT 2
+#define BDC_FLAG_PAD_SHIFT 0
+#define BDC_FLAG2_PAD_IDX 0x3c
+#define BDC_FLAG_PAD_IDX 0x03
+#define BDC_GET_PAD_LEN(hdr) \
+ ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \
+ ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT)))
+#define BDC_SET_PAD_LEN(hdr, idx) \
+ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \
+ (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \
+ ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \
+ (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT)))
+
+#endif /* _bcmcdc_h_ */
diff --git a/wl/src/include/bcmcrypto/md32_common.h b/wl/src/include/bcmcrypto/md32_common.h
new file mode 100644
index 0000000..d31aae8
--- /dev/null
+++ b/wl/src/include/bcmcrypto/md32_common.h
@@ -0,0 +1,527 @@
+/* crypto/md32_common.h */
+/* ====================================================================
+ * Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ */
+
+/*
+ * This is a generic 32 bit "collector" for message digest algorithms.
+ * Whenever needed it collects input character stream into chunks of
+ * 32 bit values and invokes a block function that performs actual hash
+ * calculations.
+ *
+ * Porting guide.
+ *
+ * Obligatory macros:
+ *
+ * DATA_ORDER_IS_BIG_ENDIAN or DATA_ORDER_IS_LITTLE_ENDIAN
+ * this macro defines byte order of input stream.
+ * HASH_CBLOCK
+ * size of a unit chunk HASH_BLOCK operates on.
+ * HASH_LONG
+ * has to be at lest 32 bit wide, if it's wider, then
+ * HASH_LONG_LOG2 *has to* be defined along
+ * HASH_CTX
+ * context structure that at least contains following
+ * members:
+ * typedef struct {
+ * ...
+ * HASH_LONG Nl,Nh;
+ * HASH_LONG data[HASH_LBLOCK];
+ * unsigned int num;
+ * ...
+ * } HASH_CTX;
+ * HASH_UPDATE
+ * name of "Update" function, implemented here.
+ * HASH_TRANSFORM
+ * name of "Transform" function, implemented here.
+ * HASH_FINAL
+ * name of "Final" function, implemented here.
+ * HASH_BLOCK_HOST_ORDER
+ * name of "block" function treating *aligned* input message
+ * in host byte order, implemented externally.
+ * HASH_BLOCK_DATA_ORDER
+ * name of "block" function treating *unaligned* input message
+ * in original (data) byte order, implemented externally (it
+ * actually is optional if data and host are of the same
+ * "endianess").
+ * HASH_MAKE_STRING
+ * macro convering context variables to an ASCII hash string.
+ *
+ * Optional macros:
+ *
+ * B_ENDIAN or L_ENDIAN
+ * defines host byte-order.
+ * HASH_LONG_LOG2
+ * defaults to 2 if not states otherwise.
+ * HASH_LBLOCK
+ * assumed to be HASH_CBLOCK/4 if not stated otherwise.
+ * HASH_BLOCK_DATA_ORDER_ALIGNED
+ * alternative "block" function capable of treating
+ * aligned input message in original (data) order,
+ * implemented externally.
+ *
+ * MD5 example:
+ *
+ * #define DATA_ORDER_IS_LITTLE_ENDIAN
+ *
+ * #define HASH_LONG MD5_LONG
+ * #define HASH_LONG_LOG2 MD5_LONG_LOG2
+ * #define HASH_CTX MD5_CTX
+ * #define HASH_CBLOCK MD5_CBLOCK
+ * #define HASH_LBLOCK MD5_LBLOCK
+ * #define HASH_UPDATE MD5_Update
+ * #define HASH_TRANSFORM MD5_Transform
+ * #define HASH_FINAL MD5_Final
+ * #define HASH_BLOCK_HOST_ORDER md5_block_host_order
+ * #define HASH_BLOCK_DATA_ORDER md5_block_data_order
+ *
+ * <appro@fy.chalmers.se>
+ */
+
+/* FILE-CSTYLED */
+
+#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+#error "DATA_ORDER must be defined!"
+#endif
+
+#ifndef HASH_CBLOCK
+#error "HASH_CBLOCK must be defined!"
+#endif
+#ifndef HASH_LONG
+#error "HASH_LONG must be defined!"
+#endif
+#ifndef HASH_CTX
+#error "HASH_CTX must be defined!"
+#endif
+
+#ifndef HASH_UPDATE
+#error "HASH_UPDATE must be defined!"
+#endif
+#ifndef HASH_TRANSFORM
+#error "HASH_TRANSFORM must be defined!"
+#endif
+#ifndef HASH_FINAL
+#error "HASH_FINAL must be defined!"
+#endif
+
+#ifndef HASH_BLOCK_HOST_ORDER
+#error "HASH_BLOCK_HOST_ORDER must be defined!"
+#endif
+
+
+#ifndef HASH_LBLOCK
+#define HASH_LBLOCK (HASH_CBLOCK/4)
+#endif
+
+#ifndef HASH_LONG_LOG2
+#define HASH_LONG_LOG2 2
+#endif
+
+#ifndef ROTATE
+#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+/*
+ * Make some obvious choices. E.g., HASH_BLOCK_DATA_ORDER_ALIGNED
+ * and HASH_BLOCK_HOST_ORDER ought to be the same if input data
+ * and host are of the same "endianess". It's possible to mask
+ * this with blank #define HASH_BLOCK_DATA_ORDER though...
+ *
+ * <appro@fy.chalmers.se>
+ */
+#if defined(B_ENDIAN)
+# if defined(DATA_ORDER_IS_BIG_ENDIAN)
+# if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED) && HASH_LONG_LOG2==2
+# define HASH_BLOCK_DATA_ORDER_ALIGNED HASH_BLOCK_HOST_ORDER
+# endif
+# endif
+#elif defined(L_ENDIAN)
+# if defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+# if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED) && HASH_LONG_LOG2==2
+# define HASH_BLOCK_DATA_ORDER_ALIGNED HASH_BLOCK_HOST_ORDER
+# endif
+# endif
+#endif
+
+#if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+#ifndef HASH_BLOCK_DATA_ORDER
+#error "HASH_BLOCK_DATA_ORDER must be defined!"
+#endif
+#endif
+
+#if defined(DATA_ORDER_IS_BIG_ENDIAN)
+
+#ifndef PEDANTIC
+# if defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && \
+ !defined(OPENSSL_NO_INLINE_ASM)
+# if ((defined(__i386) || defined(__i386__)) && !defined(I386_ONLY)) || \
+ (defined(__x86_64) || defined(__x86_64__))
+ /*
+ * This gives ~30-40% performance improvement in SHA-256 compiled
+ * with gcc [on P4]. Well, first macro to be frank. We can pull
+ * this trick on x86* platforms only, because these CPUs can fetch
+ * unaligned data without raising an exception.
+ */
+# define HOST_c2l(c,l) ({ unsigned int r=*((const unsigned int *)(c)); \
+ asm ("bswapl %0":"=r"(r):"0"(r)); \
+ (c)+=4; (l)=r; })
+# define HOST_l2c(l,c) ({ unsigned int r=(l); \
+ asm ("bswapl %0":"=r"(r):"0"(r)); \
+ *((unsigned int *)(c))=r; (c)+=4; r; })
+# endif
+# endif
+#endif
+
+#ifndef HOST_c2l
+#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++)))<<24), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++))) ), \
+ l)
+#endif
+#define HOST_p_c2l(c,l,n) { \
+ switch (n) { \
+ case 0: l =((unsigned long)(*((c)++)))<<24; \
+ case 1: l|=((unsigned long)(*((c)++)))<<16; \
+ case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+ case 3: l|=((unsigned long)(*((c)++))); \
+ } }
+#define HOST_p_c2l_p(c,l,sc,len) { \
+ switch (sc) { \
+ case 0: l =((unsigned long)(*((c)++)))<<24; \
+ if (--len == 0) break; \
+ case 1: l|=((unsigned long)(*((c)++)))<<16; \
+ if (--len == 0) break; \
+ case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+ } }
+/* NOTE the pointer is not incremented at the end of this */
+#define HOST_c2l_p(c,l,n) { \
+ l=0; (c)+=n; \
+ switch (n) { \
+ case 3: l =((unsigned long)(*(--(c))))<< 8; \
+ case 2: l|=((unsigned long)(*(--(c))))<<16; \
+ case 1: l|=((unsigned long)(*(--(c))))<<24; \
+ } }
+#ifndef HOST_l2c
+#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff), \
+ l)
+#endif
+
+#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+
+#if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
+# ifndef B_ENDIAN
+ /* See comment in DATA_ORDER_IS_BIG_ENDIAN section. */
+# define HOST_c2l(c,l) ((l)=*((const unsigned int *)(c)), (c)+=4, l)
+# define HOST_l2c(l,c) (*((unsigned int *)(c))=(l), (c)+=4, l)
+# endif
+#endif
+
+#ifndef HOST_c2l
+#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<<24), \
+ l)
+#endif
+#define HOST_p_c2l(c,l,n) { \
+ switch (n) { \
+ case 0: l =((unsigned long)(*((c)++))); \
+ case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ case 3: l|=((unsigned long)(*((c)++)))<<24; \
+ } }
+#define HOST_p_c2l_p(c,l,sc,len) { \
+ switch (sc) { \
+ case 0: l =((unsigned long)(*((c)++))); \
+ if (--len == 0) break; \
+ case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ if (--len == 0) break; \
+ case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ } }
+/* NOTE the pointer is not incremented at the end of this */
+#define HOST_c2l_p(c,l,n) { \
+ l=0; (c)+=n; \
+ switch (n) { \
+ case 3: l =((unsigned long)(*(--(c))))<<16; \
+ case 2: l|=((unsigned long)(*(--(c))))<< 8; \
+ case 1: l|=((unsigned long)(*(--(c)))); \
+ } }
+#ifndef HOST_l2c
+#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ l)
+#endif
+
+#endif
+
+/*
+ * Time for some action:-)
+ */
+
+int HASH_UPDATE (HASH_CTX *c, const void *data_, size_t len)
+ {
+ const unsigned char *data=data_;
+ register HASH_LONG * p;
+ register HASH_LONG l;
+ size_t sw,sc,ew,ec;
+
+ if (len==0) return 1;
+
+ l=(c->Nl+(((HASH_LONG)len)<<3))&0xffffffffUL;
+ /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to
+ * Wei Dai <weidai@eskimo.com> for pointing it out. */
+ if (l < c->Nl) /* overflow */
+ c->Nh++;
+ c->Nh+=(unsigned int)(len>>29); /* might cause compiler warning on 16-bit */
+ c->Nl=l;
+
+ if (c->num != 0)
+ {
+ p=c->data;
+ sw=c->num>>2;
+ sc=c->num&0x03;
+
+ if ((c->num+len) >= HASH_CBLOCK)
+ {
+ l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
+ for (; sw<HASH_LBLOCK; sw++)
+ {
+ HOST_c2l(data,l); p[sw]=l;
+ }
+ HASH_BLOCK_HOST_ORDER (c,p,1);
+ len-=(HASH_CBLOCK-c->num);
+ c->num=0;
+ /* drop through and do the rest */
+ }
+ else
+ {
+ c->num+=(unsigned int)len;
+ if ((sc+len) < 4) /* ugly, add char's to a word */
+ {
+ l=p[sw]; HOST_p_c2l_p(data,l,sc,len); p[sw]=l;
+ }
+ else
+ {
+ ew=(c->num>>2);
+ ec=(c->num&0x03);
+ if (sc)
+ l=p[sw];
+ HOST_p_c2l(data,l,sc);
+ p[sw++]=l;
+ for (; sw < ew; sw++)
+ {
+ HOST_c2l(data,l); p[sw]=l;
+ }
+ if (ec)
+ {
+ HOST_c2l_p(data,l,ec); p[sw]=l;
+ }
+ }
+ return 1;
+ }
+ }
+
+ sw=len/HASH_CBLOCK;
+ if (sw > 0)
+ {
+#if defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+ /*
+ * Note that HASH_BLOCK_DATA_ORDER_ALIGNED gets defined
+ * only if sizeof(HASH_LONG)==4.
+ */
+ if ((((size_t)data)%4) == 0)
+ {
+ /* data is properly aligned so that we can cast it: */
+ HASH_BLOCK_DATA_ORDER_ALIGNED (c,(const HASH_LONG *)data,sw);
+ sw*=HASH_CBLOCK;
+ data+=sw;
+ len-=sw;
+ }
+ else
+#if !defined(HASH_BLOCK_DATA_ORDER)
+ while (sw--)
+ {
+ memcpy (p=c->data,data,HASH_CBLOCK);
+ HASH_BLOCK_DATA_ORDER_ALIGNED(c,p,1);
+ data+=HASH_CBLOCK;
+ len-=HASH_CBLOCK;
+ }
+#endif
+#endif
+#if defined(HASH_BLOCK_DATA_ORDER)
+ {
+ HASH_BLOCK_DATA_ORDER(c,data,sw);
+ sw*=HASH_CBLOCK;
+ data+=sw;
+ len-=sw;
+ }
+#endif
+ }
+
+ if (len!=0)
+ {
+ p = c->data;
+ c->num = (unsigned int)len;
+ ew=len>>2; /* words to copy */
+ ec=len&0x03;
+ for (; ew; ew--,p++)
+ {
+ HOST_c2l(data,l); *p=l;
+ }
+ HOST_c2l_p(data,l,ec);
+ *p=l;
+ }
+ return 1;
+ }
+
+
+void HASH_TRANSFORM (HASH_CTX *c, const unsigned char *data)
+ {
+#if defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+ if ((((size_t)data)%4) == 0)
+ /* data is properly aligned so that we can cast it: */
+ HASH_BLOCK_DATA_ORDER_ALIGNED (c,(const HASH_LONG *)data,1);
+ else
+#if !defined(HASH_BLOCK_DATA_ORDER)
+ {
+ memcpy (c->data,data,HASH_CBLOCK);
+ HASH_BLOCK_DATA_ORDER_ALIGNED (c,c->data,1);
+ }
+#endif
+#endif
+#if defined(HASH_BLOCK_DATA_ORDER)
+ HASH_BLOCK_DATA_ORDER (c,data,1);
+#endif
+ }
+
+
+int HASH_FINAL (unsigned char *md, HASH_CTX *c)
+ {
+ register HASH_LONG *p;
+ register unsigned long l;
+ register int i,j;
+ static const unsigned char end[4]={0x80,0x00,0x00,0x00};
+ const unsigned char *cp=end;
+
+ /* c->num should definitly have room for at least one more byte. */
+ p=c->data;
+ i=c->num>>2;
+ j=c->num&0x03;
+
+ l = (j==0) ? 0 : p[i];
+ HOST_p_c2l(cp,l,j); p[i++]=l; /* i is the next 'undefined word' */
+
+ if (i>(HASH_LBLOCK-2)) /* save room for Nl and Nh */
+ {
+ if (i<HASH_LBLOCK) p[i]=0;
+ HASH_BLOCK_HOST_ORDER (c,p,1);
+ i=0;
+ }
+ for (; i<(HASH_LBLOCK-2); i++)
+ p[i]=0;
+
+#if defined(DATA_ORDER_IS_BIG_ENDIAN)
+ p[HASH_LBLOCK-2]=c->Nh;
+ p[HASH_LBLOCK-1]=c->Nl;
+#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+ p[HASH_LBLOCK-2]=c->Nl;
+ p[HASH_LBLOCK-1]=c->Nh;
+#endif
+ HASH_BLOCK_HOST_ORDER (c,p,1);
+
+#ifndef HASH_MAKE_STRING
+#error "HASH_MAKE_STRING must be defined!"
+#else
+ HASH_MAKE_STRING(c,md);
+#endif
+
+ c->num=0;
+ /* clear stuff, HASH_BLOCK may be leaving some stuff on the stack
+ * but I'm not worried :-)
+ OPENSSL_cleanse((void *)c,sizeof(HASH_CTX));
+ */
+ return 1;
+ }
+
+#ifndef MD32_REG_T
+#define MD32_REG_T long
+/*
+ * This comment was originaly written for MD5, which is why it
+ * discusses A-D. But it basically applies to all 32-bit digests,
+ * which is why it was moved to common header file.
+ *
+ * In case you wonder why A-D are declared as long and not
+ * as MD5_LONG. Doing so results in slight performance
+ * boost on LP64 architectures. The catch is we don't
+ * really care if 32 MSBs of a 64-bit register get polluted
+ * with eventual overflows as we *save* only 32 LSBs in
+ * *either* case. Now declaring 'em long excuses the compiler
+ * from keeping 32 MSBs zeroed resulting in 13% performance
+ * improvement under SPARC Solaris7/64 and 5% under AlphaLinux.
+ * Well, to be honest it should say that this *prevents*
+ * performance degradation.
+ * <appro@fy.chalmers.se>
+ * Apparently there're LP64 compilers that generate better
+ * code if A-D are declared int. Most notably GCC-x86_64
+ * generates better code.
+ * <appro@fy.chalmers.se>
+ */
+#endif
diff --git a/wl/src/include/bcmcrypto/sha256.h b/wl/src/include/bcmcrypto/sha256.h
new file mode 100644
index 0000000..c7b9e9b
--- /dev/null
+++ b/wl/src/include/bcmcrypto/sha256.h
@@ -0,0 +1,141 @@
+/* sha256.h
+ * Code copied from openssl distribution and
+ * Modified just enough so that compiles and runs standalone
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sha256.h 523133 2014-12-27 05:50:30Z $
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_SHA_H
+#define HEADER_SHA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * ! SHA_LONG has to be at least 32 bits wide. If it's wider, then !
+ * ! SHA_LONG_LOG2 has to be defined along. !
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__)
+#define SHA_LONG unsigned long
+#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
+#define SHA_LONG unsigned long
+#define SHA_LONG_LOG2 3
+#else
+#define SHA_LONG unsigned int
+#endif
+
+#define SHA_LBLOCK 16
+#define SHA_CBLOCK (SHA_LBLOCK*4) /* SHA treats input data as a
+ * contiguous array of 32 bit
+ * wide big-endian values.
+ */
+#define SHA_LAST_BLOCK (SHA_CBLOCK-8)
+#define SHA_DIGEST_LENGTH 20
+
+#define SHA256_CBLOCK (SHA_LBLOCK*4) /* SHA-256 treats input data as a
+ * contiguous array of 32 bit
+ * wide big-endian values.
+ */
+#define SHA224_DIGEST_LENGTH 28
+#define SHA256_DIGEST_LENGTH 32
+
+typedef struct SHA256state_st
+ {
+ SHA_LONG h[8];
+ SHA_LONG Nl, Nh;
+ SHA_LONG data[SHA_LBLOCK];
+ unsigned int num, md_len;
+ } SHA256_CTX;
+
+int SHA224_Init(SHA256_CTX *c);
+int SHA224_Update(SHA256_CTX *c, const void *data, size_t len);
+int SHA224_Final(unsigned char *md, SHA256_CTX *c);
+unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md);
+int SHA256_Init(SHA256_CTX *c);
+int SHA256_Update(SHA256_CTX *c, const void *data, size_t len);
+int SHA256_Final(unsigned char *md, SHA256_CTX *c);
+unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md);
+void SHA256_Transform(SHA256_CTX *c, const unsigned char *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HEADER_SHA_H */
diff --git a/wl/src/include/bcmdefs.h b/wl/src/include/bcmdefs.h
new file mode 100644
index 0000000..4caa55f
--- /dev/null
+++ b/wl/src/include/bcmdefs.h
@@ -0,0 +1,605 @@
+/*
+ * Misc system wide definitions
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmdefs.h 659962 2016-09-16 18:46:17Z $
+ */
+
+#ifndef _bcmdefs_h_
+#define _bcmdefs_h_
+
+/*
+ * One doesn't need to include this file explicitly, gets included automatically if
+ * typedefs.h is included.
+ */
+
+/* Use BCM_REFERENCE to suppress warnings about intentionally-unused function
+ * arguments or local variables.
+ */
+#define BCM_REFERENCE(data) ((void)(data))
+
+/* Allow for suppressing unused variable warnings. */
+#ifdef __GNUC__
+#define UNUSED_VAR __attribute__ ((unused))
+#else
+#define UNUSED_VAR
+#endif
+
+/* Compile-time assert can be used in place of ASSERT if the expression evaluates
+ * to a constant at compile time.
+ */
+#define STATIC_ASSERT(expr) { \
+ /* Make sure the expression is constant. */ \
+ typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e UNUSED_VAR; \
+ /* Make sure the expression is true. */ \
+ typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] UNUSED_VAR; \
+}
+
+/* Reclaiming text and data :
+ * The following macros specify special linker sections that can be reclaimed
+ * after a system is considered 'up'.
+ * BCMATTACHFN is also used for detach functions (it's not worth having a BCMDETACHFN,
+ * as in most cases, the attach function calls the detach function to clean up on error).
+ */
+#if defined(BCM_RECLAIM)
+
+extern bool bcm_reclaimed;
+extern bool bcm_attach_part_reclaimed;
+extern bool bcm_preattach_part_reclaimed;
+extern bool bcm_postattach_part_reclaimed;
+
+#define RECLAIMED() (bcm_reclaimed)
+#define ATTACH_PART_RECLAIMED() (bcm_attach_part_reclaimed)
+#define PREATTACH_PART_RECLAIMED() (bcm_preattach_part_reclaimed)
+#define POSTATTACH_PART_RECLAIMED() (bcm_postattach_part_reclaimed)
+
+#if defined(BCM_RECLAIM_ATTACH_FN_DATA)
+#define BCMATTACHDATA(_data) __attribute__ ((__section__ (".dataini2." #_data))) _data
+#define BCMATTACHFN(_fn) __attribute__ ((__section__ (".textini2." #_fn), noinline)) _fn
+
+/* Relocate attach symbols to save-restore region to increase pre-reclaim heap size. */
+#define BCM_SRM_ATTACH_DATA(_data) __attribute__ ((__section__ (".datasrm." #_data))) _data
+#define BCM_SRM_ATTACH_FN(_fn) __attribute__ ((__section__ (".textsrm." #_fn), noinline)) _fn
+
+#ifndef PREATTACH_NORECLAIM
+#define BCMPREATTACHDATA(_data) __attribute__ ((__section__ (".dataini3." #_data))) _data
+#define BCMPREATTACHFN(_fn) __attribute__ ((__section__ (".textini3." #_fn), noinline)) _fn
+#else
+#define BCMPREATTACHDATA(_data) __attribute__ ((__section__ (".dataini2." #_data))) _data
+#define BCMPREATTACHFN(_fn) __attribute__ ((__section__ (".textini2." #_fn), noinline)) _fn
+#endif /* PREATTACH_NORECLAIM */
+#define BCMPOSTATTACHDATA(_data) __attribute__ ((__section__ (".dataini5." #_data))) _data
+#define BCMPOSTATTACHFN(_fn) __attribute__ ((__section__ (".textini5." #_fn), noinline)) _fn
+#else /* BCM_RECLAIM_ATTACH_FN_DATA */
+#define BCMATTACHDATA(_data) _data
+#define BCMATTACHFN(_fn) _fn
+#define BCMPREATTACHDATA(_data) _data
+#define BCMPREATTACHFN(_fn) _fn
+#define BCMPOSTATTACHDATA(_data) _data
+#define BCMPOSTATTACHFN(_fn) _fn
+#endif /* BCM_RECLAIM_ATTACH_FN_DATA */
+
+#ifdef BCMDBG_SR
+/*
+ * Don't reclaim so we can compare SR ASM
+ */
+#define BCMPREATTACHDATASR(_data) _data
+#define BCMPREATTACHFNSR(_fn) _fn
+#define BCMATTACHDATASR(_data) _data
+#define BCMATTACHFNSR(_fn) _fn
+#else
+#define BCMPREATTACHDATASR(_data) BCMPREATTACHDATA(_data)
+#define BCMPREATTACHFNSR(_fn) BCMPREATTACHFN(_fn)
+#define BCMATTACHDATASR(_data) BCMATTACHDATA(_data)
+#define BCMATTACHFNSR(_fn) BCMATTACHFN(_fn)
+#endif
+
+#if defined(BCM_RECLAIM_INIT_FN_DATA)
+#define BCMINITDATA(_data) __attribute__ ((__section__ (".dataini1." #_data))) _data
+#define BCMINITFN(_fn) __attribute__ ((__section__ (".textini1." #_fn), noinline)) _fn
+#define CONST
+#else /* BCM_RECLAIM_INIT_FN_DATA */
+#define BCMINITDATA(_data) _data
+#define BCMINITFN(_fn) _fn
+#ifndef CONST
+#define CONST const
+#endif
+#endif /* BCM_RECLAIM_INIT_FN_DATA */
+
+/* Non-manufacture or internal attach function/dat */
+#define BCMNMIATTACHFN(_fn) BCMATTACHFN(_fn)
+#define BCMNMIATTACHDATA(_data) BCMATTACHDATA(_data)
+
+/* SROM with OTP support */
+#if defined(BCMOTPSROM)
+#define BCMSROMATTACHFN(_fn) _fn
+#define BCMSROMATTACHDATA(_data) _data
+#else
+#define BCMSROMATTACHFN(_fn) BCMNMIATTACHFN(_fn)
+#define BCMSROMATTACHDATA(_data) BCMNMIATTACHFN(_data)
+#endif /* BCMOTPSROM */
+
+#ifdef BCMNODOWN
+#define BCMUNINITFN(_fn) BCMINITFN(_fn)
+#else
+#define BCMUNINITFN(_fn) _fn
+#endif
+
+#else /* BCM_RECLAIM */
+
+#define bcm_reclaimed (1)
+#define bcm_attach_part_reclaimed (1)
+#define bcm_preattach_part_reclaimed (1)
+#define bcm_postattach_part_reclaimed (1)
+#define BCMATTACHDATA(_data) _data
+#define BCMATTACHFN(_fn) _fn
+#define BCM_SRM_ATTACH_DATA(_data) _data
+#define BCM_SRM_ATTACH_FN(_fn) _fn
+#define BCMPREATTACHDATA(_data) _data
+#define BCMPREATTACHFN(_fn) _fn
+#define BCMPOSTATTACHDATA(_data) _data
+#define BCMPOSTATTACHFN(_fn) _fn
+#define BCMINITDATA(_data) _data
+#define BCMINITFN(_fn) _fn
+#define BCMUNINITFN(_fn) _fn
+#define BCMNMIATTACHFN(_fn) _fn
+#define BCMNMIATTACHDATA(_data) _data
+#define BCMSROMATTACHFN(_fn) _fn
+#define BCMSROMATTACHDATA(_data) _data
+#define BCMPREATTACHFNSR(_fn) _fn
+#define BCMPREATTACHDATASR(_data) _data
+#define BCMATTACHFNSR(_fn) _fn
+#define BCMATTACHDATASR(_data) _data
+#define CONST const
+
+#define RECLAIMED() (bcm_reclaimed)
+#define ATTACH_PART_RECLAIMED() (bcm_attach_part_reclaimed)
+#define PREATTACH_PART_RECLAIMED() (bcm_preattach_part_reclaimed)
+#define POSTATTACH_PART_RECLAIMED() (bcm_postattach_part_reclaimed)
+
+#endif /* BCM_RECLAIM */
+
+#define BCMUCODEDATA(_data) BCMINITDATA(_data)
+
+#if defined(BCM_DMA_CT) && !defined(BCM_DMA_CT_DISABLED)
+#define BCMUCODEFN(_fn) BCMINITFN(_fn)
+#else
+#define BCMUCODEFN(_fn) BCMATTACHFN(_fn)
+#endif /* BCM_DMA_CT */
+
+#if !defined STB
+#if defined(BCM47XX) && defined(__ARM_ARCH_7A__) && !defined(OEM_ANDROID)
+#define BCM47XX_CA9
+#else
+#undef BCM47XX_CA9
+#endif /* BCM47XX && __ARM_ARCH_7A__ && !OEM_ANDROID */
+#endif /* STB */
+
+/* BCMFASTPATH Related Macro defines
+*/
+#ifndef BCMFASTPATH
+#if defined(mips) || defined(BCM47XX_CA9) || defined(STB)
+#define BCMFASTPATH __attribute__ ((__section__ (".text.fastpath")))
+#define BCMFASTPATH_HOST __attribute__ ((__section__ (".text.fastpath_host")))
+#else /* mips || BCM47XX_CA9 || STB */
+#define BCMFASTPATH
+#define BCMFASTPATH_HOST
+#endif /* mips || BCM47XX_CA9 || STB */
+#endif /* BCMFASTPATH */
+
+/* Use the BCMRAMFN() macro to tag functions in source that must be included in RAM (excluded from
+ * ROM). This should eliminate the need to manually specify these functions in the ROM config file.
+ * It should only be used in special cases where the function must be in RAM for *all* ROM-based
+ * chips.
+ */
+#if defined(BCMROMBUILD)
+ #define BCMRAMFN(_fn) __attribute__ ((__section__ (".text_ram." #_fn), noinline)) _fn
+#else
+ #define BCMRAMFN(_fn) _fn
+#endif
+
+#define STATIC static
+
+/* Bus types */
+#define SI_BUS 0 /* SOC Interconnect */
+#define PCI_BUS 1 /* PCI target */
+#define PCMCIA_BUS 2 /* PCMCIA target */
+#define SDIO_BUS 3 /* SDIO target */
+#define JTAG_BUS 4 /* JTAG */
+#define USB_BUS 5 /* USB (does not support R/W REG) */
+#define SPI_BUS 6 /* gSPI target */
+#define RPC_BUS 7 /* RPC target */
+
+/* Allows size optimization for single-bus image */
+#ifdef BCMBUSTYPE
+#define BUSTYPE(bus) (BCMBUSTYPE)
+#else
+#define BUSTYPE(bus) (bus)
+#endif
+
+#ifdef BCMBUSCORETYPE
+#define BUSCORETYPE(ct) (BCMBUSCORETYPE)
+#else
+#define BUSCORETYPE(ct) (ct)
+#endif
+
+/* Allows size optimization for single-backplane image */
+#ifdef BCMCHIPTYPE
+#define CHIPTYPE(bus) (BCMCHIPTYPE)
+#else
+#define CHIPTYPE(bus) (bus)
+#endif
+
+
+/* Allows size optimization for SPROM support */
+#if defined(BCMSPROMBUS)
+#define SPROMBUS (BCMSPROMBUS)
+#elif defined(SI_PCMCIA_SROM)
+#define SPROMBUS (PCMCIA_BUS)
+#else
+#define SPROMBUS (PCI_BUS)
+#endif
+
+/* Allows size optimization for single-chip image */
+#ifdef BCMCHIPID
+#define CHIPID(chip) (BCMCHIPID)
+#else
+#define CHIPID(chip) (chip)
+#endif
+
+#ifdef BCMCHIPREV
+#define CHIPREV(rev) (BCMCHIPREV)
+#else
+#define CHIPREV(rev) (rev)
+#endif
+
+#ifdef BCMPCIEREV
+#define PCIECOREREV(rev) (BCMPCIEREV)
+#else
+#define PCIECOREREV(rev) (rev)
+#endif
+
+#ifdef BCMPMUREV
+#define PMUREV(rev) (BCMPMUREV)
+#else
+#define PMUREV(rev) (rev)
+#endif
+
+#ifdef BCMCCREV
+#define CCREV(rev) (BCMCCREV)
+#else
+#define CCREV(rev) (rev)
+#endif
+
+#ifdef BCMGCIREV
+#define GCIREV(rev) (BCMGCIREV)
+#else
+#define GCIREV(rev) (rev)
+#endif
+
+/* Defines for DMA Address Width - Shared between OSL and HNDDMA */
+#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */
+#define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */
+#define DMADDR_MASK_26 0xFC000000 /* Address maks for 26-bits */
+#define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */
+
+#define DMADDRWIDTH_26 26 /* 26-bit addressing capability */
+#define DMADDRWIDTH_30 30 /* 30-bit addressing capability */
+#define DMADDRWIDTH_32 32 /* 32-bit addressing capability */
+#define DMADDRWIDTH_63 63 /* 64-bit addressing capability */
+#define DMADDRWIDTH_64 64 /* 64-bit addressing capability */
+
+typedef struct {
+ uint32 loaddr;
+ uint32 hiaddr;
+} dma64addr_t;
+
+#define PHYSADDR64HI(_pa) ((_pa).hiaddr)
+#define PHYSADDR64HISET(_pa, _val) \
+ do { \
+ (_pa).hiaddr = (_val); \
+ } while (0)
+#define PHYSADDR64LO(_pa) ((_pa).loaddr)
+#define PHYSADDR64LOSET(_pa, _val) \
+ do { \
+ (_pa).loaddr = (_val); \
+ } while (0)
+
+#ifdef BCMDMA64OSL
+typedef dma64addr_t dmaaddr_t;
+#define PHYSADDRHI(_pa) PHYSADDR64HI(_pa)
+#define PHYSADDRHISET(_pa, _val) PHYSADDR64HISET(_pa, _val)
+#define PHYSADDRLO(_pa) PHYSADDR64LO(_pa)
+#define PHYSADDRLOSET(_pa, _val) PHYSADDR64LOSET(_pa, _val)
+#define PHYSADDRTOULONG(_pa, _ulong) \
+ do { \
+ _ulong = ((unsigned long long)(_pa).hiaddr << 32) | ((_pa).loaddr); \
+ } while (0)
+
+#else
+typedef unsigned long dmaaddr_t;
+#define PHYSADDRHI(_pa) (0)
+#define PHYSADDRHISET(_pa, _val)
+#define PHYSADDRLO(_pa) ((_pa))
+#define PHYSADDRLOSET(_pa, _val) \
+ do { \
+ (_pa) = (_val); \
+ } while (0)
+#endif /* BCMDMA64OSL */
+#define PHYSADDRISZERO(_pa) (PHYSADDRLO(_pa) == 0 && PHYSADDRHI(_pa) == 0)
+
+/* One physical DMA segment */
+typedef struct {
+ dmaaddr_t addr;
+ uint32 length;
+} hnddma_seg_t;
+
+#if defined(linux)
+#define MAX_DMA_SEGS 8
+#else
+#define MAX_DMA_SEGS 4
+#endif
+
+
+typedef struct {
+ void *oshdmah; /* Opaque handle for OSL to store its information */
+ uint origsize; /* Size of the virtual packet */
+ uint nsegs;
+ hnddma_seg_t segs[MAX_DMA_SEGS];
+} hnddma_seg_map_t;
+
+
+/* packet headroom necessary to accommodate the largest header in the system, (i.e TXOFF).
+ * By doing, we avoid the need to allocate an extra buffer for the header when bridging to WL.
+ * There is a compile time check in wlc.c which ensure that this value is at least as big
+ * as TXOFF. This value is used in dma_rxfill (hnddma.c).
+ */
+
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY)
+/* add 40 bytes to allow for extra RPC header and info */
+#define BCMEXTRAHDROOM 260
+#else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */
+#if defined(linux) && (defined(BCM47XX_CA9) || defined(STB))
+#if defined(BCM_GMAC3)
+#define BCMEXTRAHDROOM 32 /* For FullDongle, no D11 headroom space required. */
+#define BCMEXTRAHDROOM_NIC 224
+#else
+#define BCMEXTRAHDROOM 224
+#endif /* ! BCM_GMAC3 */
+#else
+#ifdef CTFMAP
+#define BCMEXTRAHDROOM 208
+#else /* CTFMAP */
+#define BCMEXTRAHDROOM 204
+#endif /* CTFMAP */
+#endif /* linux && BCM47XX_CA9 */
+#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */
+
+/* Packet alignment for most efficient SDIO (can change based on platform) */
+#ifndef SDALIGN
+#define SDALIGN 32
+#endif
+
+/* Headroom required for dongle-to-host communication. Packets allocated
+ * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should
+ * leave this much room in front for low-level message headers which may
+ * be needed to get across the dongle bus to the host. (These messages
+ * don't go over the network, so room for the full WL header above would
+ * be a waste.).
+*/
+#define BCMDONGLEHDRSZ 12
+#define BCMDONGLEPADSZ 16
+
+#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ)
+
+#ifdef BCMDBG
+
+#ifndef BCMDBG_ERR
+#define BCMDBG_ERR
+#endif /* BCMDBG_ERR */
+
+#ifndef BCMDBG_ASSERT
+#define BCMDBG_ASSERT
+#endif /* BCMDBG_ASSERT */
+
+#endif /* BCMDBG */
+
+#if defined(NO_BCMDBG_ASSERT)
+# undef BCMDBG_ASSERT
+# undef BCMASSERT_LOG
+#endif
+
+#if defined(BCMDBG_ASSERT) || defined(BCMASSERT_LOG)
+#define BCMASSERT_SUPPORT
+#endif /* BCMDBG_ASSERT || BCMASSERT_LOG */
+
+/* Macros for doing definition and get/set of bitfields
+ * Usage example, e.g. a three-bit field (bits 4-6):
+ * #define <NAME>_M BITFIELD_MASK(3)
+ * #define <NAME>_S 4
+ * ...
+ * regval = R_REG(osh, ®s->regfoo);
+ * field = GFIELD(regval, <NAME>);
+ * regval = SFIELD(regval, <NAME>, 1);
+ * W_REG(osh, ®s->regfoo, regval);
+ */
+#define BITFIELD_MASK(width) \
+ (((unsigned)1 << (width)) - 1)
+#define GFIELD(val, field) \
+ (((val) >> field ## _S) & field ## _M)
+#define SFIELD(val, field, bits) \
+ (((val) & (~(field ## _M << field ## _S))) | \
+ ((unsigned)(bits) << field ## _S))
+
+/* define BCMSMALL to remove misc features for memory-constrained environments */
+#ifdef BCMSMALL
+#undef BCMSPACE
+#define bcmspace FALSE /* if (bcmspace) code is discarded */
+#else
+#define BCMSPACE
+#define bcmspace TRUE /* if (bcmspace) code is retained */
+#endif
+
+/* Max. nvram variable table size */
+#ifndef MAXSZ_NVRAM_VARS
+#ifdef LARGE_NVRAM_MAXSZ
+#define MAXSZ_NVRAM_VARS (LARGE_NVRAM_MAXSZ * 2)
+#else
+#if defined(BCMROMBUILD) || defined(DONGLEBUILD)
+/* SROM12 changes */
+#define MAXSZ_NVRAM_VARS 6144
+#else
+#define LARGE_NVRAM_MAXSZ 8192
+#define MAXSZ_NVRAM_VARS (LARGE_NVRAM_MAXSZ * 2)
+#endif /* BCMROMBUILD || DONGLEBUILD */
+#endif /* LARGE_NVRAM_MAXSZ */
+#endif /* !MAXSZ_NVRAM_VARS */
+
+#ifdef ATE_BUILD
+#ifndef ATE_NVRAM_MAXSIZE
+#define ATE_NVRAM_MAXSIZE 32000
+#endif /* ATE_NVRAM_MAXSIZE */
+#endif /* ATE_BUILD */
+
+
+/* WL_ENAB_RUNTIME_CHECK may be set based upon the #define below (for ROM builds). It may also
+ * be defined via makefiles (e.g. ROM auto abandon unoptimized compiles).
+ */
+#if defined(BCMROMBUILD)
+ #ifndef WL_ENAB_RUNTIME_CHECK
+ #define WL_ENAB_RUNTIME_CHECK
+ #endif
+#endif /* BCMROMBUILD */
+
+#ifdef BCMLFRAG /* BCMLFRAG support enab macros */
+ extern bool _bcmlfrag;
+ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
+ #define BCMLFRAG_ENAB() (_bcmlfrag)
+ #elif defined(BCMLFRAG_DISABLED)
+ #define BCMLFRAG_ENAB() (0)
+ #else
+ #define BCMLFRAG_ENAB() (1)
+ #endif
+#else
+ #define BCMLFRAG_ENAB() (0)
+#endif /* BCMLFRAG_ENAB */
+
+#ifdef BCMPCIEDEV /* BCMPCIEDEV support enab macros */
+extern bool _pciedevenab;
+ #if defined(WL_ENAB_RUNTIME_CHECK)
+ #define BCMPCIEDEV_ENAB() (_pciedevenab)
+ #elif defined(BCMPCIEDEV_ENABLED)
+ #define BCMPCIEDEV_ENAB() 1
+ #else
+ #define BCMPCIEDEV_ENAB() 0
+ #endif
+#else
+ #define BCMPCIEDEV_ENAB() 0
+#endif /* BCMPCIEDEV */
+
+#ifdef BCMRESVFRAGPOOL /* BCMRESVFRAGPOOL support enab macros */
+extern bool _resvfragpool_enab;
+ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
+ #define BCMRESVFRAGPOOL_ENAB() (_resvfragpool_enab)
+ #elif defined(BCMRESVFRAGPOOL_ENABLED)
+ #define BCMRESVFRAGPOOL_ENAB() 1
+ #else
+ #define BCMRESVFRAGPOOL_ENAB() 0
+ #endif
+#else
+ #define BCMRESVFRAGPOOL_ENAB() 0
+#endif /* BCMPCIEDEV */
+
+#ifdef BCMSDIODEV /* BCMSDIODEV support enab macros */
+extern bool _sdiodevenab;
+ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
+ #define BCMSDIODEV_ENAB() (_sdiodevenab)
+ #elif defined(BCMSDIODEV_ENABLED)
+ #define BCMSDIODEV_ENAB() 1
+ #else
+ #define BCMSDIODEV_ENAB() 0
+ #endif
+#else
+ #define BCMSDIODEV_ENAB() 0
+#endif /* BCMSDIODEV */
+
+/* Max size for reclaimable NVRAM array */
+#ifndef ATE_BUILD
+#ifdef DL_NVRAM
+#define NVRAM_ARRAY_MAXSIZE DL_NVRAM
+#else
+#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS
+#endif /* DL_NVRAM */
+#else
+#define NVRAM_ARRAY_MAXSIZE ATE_NVRAM_MAXSIZE
+#endif /* ATE_BUILD */
+
+extern uint32 gFWID;
+
+#ifdef BCMFRWDPOOLREORG /* BCMFRWDPOOLREORG support enab macros */
+ extern bool _bcmfrwdpoolreorg;
+ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
+ #define BCMFRWDPOOLREORG_ENAB() (_bcmfrwdpoolreorg)
+ #elif defined(BCMFRWDPOOLREORG_DISABLED)
+ #define BCMFRWDPOOLREORG_ENAB() (0)
+ #else
+ #define BCMFRWDPOOLREORG_ENAB() (1)
+ #endif
+#else
+ #define BCMFRWDPOOLREORG_ENAB() (0)
+#endif /* BCMFRWDPOOLREORG */
+
+#ifdef BCMPOOLRECLAIM /* BCMPOOLRECLAIM support enab macros */
+ extern bool _bcmpoolreclaim;
+ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
+ #define BCMPOOLRECLAIM_ENAB() (_bcmpoolreclaim)
+ #elif defined(BCMPOOLRECLAIM_DISABLED)
+ #define BCMPOOLRECLAIM_ENAB() (0)
+ #else
+ #define BCMPOOLRECLAIM_ENAB() (1)
+ #endif
+#else
+ #define BCMPOOLRECLAIM_ENAB() (0)
+#endif /* BCMPOOLRECLAIM */
+
+/* Chip related low power flags (lpflags) */
+
+#ifndef PAD
+#define _PADLINE(line) pad ## line
+#define _XSTR(line) _PADLINE(line)
+#define PAD _XSTR(__LINE__)
+#endif
+
+#ifndef FRAG_HEADROOM
+#define FRAG_HEADROOM 224 /* In absence of SFD, use default headroom of 224 */
+#endif
+
+#ifdef DONGLEBUILD
+#define MODULE_DETACH(var, detach_func)
+#define MODULE_DETACH_TYPECASTED(var, detach_func)
+#else
+#define MODULE_DETACH(var, detach_func)\
+ if (var) { \
+ detach_func(var); \
+ (var) = NULL; \
+ }
+#define MODULE_DETACH_TYPECASTED(var, detach_func) detach_func(var)
+#endif /* DONGLEBUILD */
+
+#endif /* _bcmdefs_h_ */
diff --git a/wl/src/include/bcmdevs.h b/wl/src/include/bcmdevs.h
new file mode 100644
index 0000000..4cb41c2
--- /dev/null
+++ b/wl/src/include/bcmdevs.h
@@ -0,0 +1,1342 @@
+/*
+ * Broadcom device-specific manifest constants.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmdevs.h 663905 2017-02-16 07:49:38Z $
+ */
+
+#ifndef _BCMDEVS_H
+#define _BCMDEVS_H
+
+/* PCI vendor IDs */
+#define VENDOR_EPIGRAM 0xfeda
+#define VENDOR_BROADCOM 0x14e4
+#define VENDOR_3COM 0x10b7
+#define VENDOR_NETGEAR 0x1385
+#define VENDOR_DIAMOND 0x1092
+#define VENDOR_INTEL 0x8086
+#define VENDOR_DELL 0x1028
+#define VENDOR_HP 0x103c
+#define VENDOR_HP_COMPAQ 0x0e11
+#define VENDOR_APPLE 0x106b
+#define VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */
+#define VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */
+#define VENDOR_TI 0x104c /* Texas Instruments */
+#define VENDOR_RICOH 0x1180 /* Ricoh */
+#define VENDOR_JMICRON 0x197b
+
+
+/* PCMCIA vendor IDs */
+#define VENDOR_BROADCOM_PCMCIA 0x02d0
+
+/* SDIO vendor IDs */
+#define VENDOR_BROADCOM_SDIO 0x00BF
+
+/* DONGLE VID/PIDs */
+#define CY_DNGL_VID 0x04b4
+#define BCM_DNGL_VID 0x0a5c
+#define BCM_DNGL_BL_PID_4328 0xbd12
+#define BCM_DNGL_BL_PID_4322 0xbd13
+#define BCM_DNGL_BL_PID_4319 0xbd16
+#define BCM_DNGL_BL_PID_43236 0xbd17
+#define BCM_DNGL_BL_PID_4332 0xbd18
+#define BCM_DNGL_BL_PID_4330 0xbd19
+#define BCM_DNGL_BL_PID_4334 0xbd1a
+#define BCM_DNGL_BL_PID_43239 0xbd1b
+#define BCM_DNGL_BL_PID_4324 0xbd1c
+#define BCM_DNGL_BL_PID_4360 0xbd1d
+#define BCM_DNGL_BL_PID_43143 0xbd1e
+#define BCM_DNGL_BL_PID_43242 0xbd1f
+#define BCM_DNGL_BL_PID_43342 0xbd21
+#define BCM_DNGL_BL_PID_4335 0xbd20
+#define BCM_DNGL_BL_PID_43341 0xbd22
+#define BCM_DNGL_BL_PID_4350 0xbd23
+#define BCM_DNGL_BL_PID_4345 0xbd24
+#define BCM_DNGL_BL_PID_4349 0xbd25
+#define BCM_DNGL_BL_PID_4354 0xbd26
+#define BCM_DNGL_BL_PID_43569 0xbd27
+#define BCM_DNGL_BL_PID_43909 0xbd28
+#define BCM_DNGL_BL_PID_4373 0xbd29
+
+#define BCM_DNGL_BDC_PID 0x0bdc
+#define BCM_DNGL_JTAG_PID 0x4a44
+
+/* HW USB BLOCK [CPULESS USB] PIDs */
+#define BCM_HWUSB_PID_43239 43239
+
+/* PCI Device IDs */
+#ifdef DEPRECATED /* These products have been deprecated */
+#define BCM4210_DEVICE_ID 0x1072 /* never used */
+#define BCM4230_DEVICE_ID 0x1086 /* never used */
+#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */
+#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */
+#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */
+#define BCM4211_DEVICE_ID 0x4211
+#define BCM4231_DEVICE_ID 0x4231
+#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */
+#define BCM4311_D11G_ID 0x4311 /* 4311 802.11b/g id */
+#define BCM4311_D11DUAL_ID 0x4312 /* 4311 802.11a/b/g id */
+#define BCM4311_D11A_ID 0x4313 /* 4311 802.11a id */
+#define BCM4328_D11DUAL_ID 0x4314 /* 4328/4312 802.11a/g id */
+#define BCM4328_D11G_ID 0x4315 /* 4328/4312 802.11g id */
+#define BCM4328_D11A_ID 0x4316 /* 4328/4312 802.11a id */
+#define BCM4318_D11A_ID 0x431a /* 4318 802.11a id */
+#define BCM4325_D11DUAL_ID 0x431b /* 4325 802.11a/g id */
+#define BCM4325_D11G_ID 0x431c /* 4325 802.11g id */
+#define BCM4325_D11A_ID 0x431d /* 4325 802.11a id */
+#define BCM4306_UART_ID 0x4322 /* 4306 uart */
+#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */
+#define BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G_ID; INF w/loose binding war */
+#define BCM4321_D11N_ID 0x4328 /* 4321 802.11n dualband id */
+#define BCM4321_D11N2G_ID 0x4329 /* 4321 802.11n 2.4Ghz band id */
+#define BCM4321_D11N5G_ID 0x432a /* 4321 802.11n 5Ghz band id */
+#define BCM4322_D11N_ID 0x432b /* 4322 802.11n dualband device */
+#define BCM4322_D11N2G_ID 0x432c /* 4322 802.11n 2.4GHz device */
+#define BCM4322_D11N5G_ID 0x432d /* 4322 802.11n 5GHz device */
+#define BCM4329_D11N_ID 0x432e /* 4329 802.11n dualband device */
+#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */
+#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */
+#define BCM4315_D11DUAL_ID 0x4334 /* 4315 802.11a/g id */
+#define BCM4315_D11G_ID 0x4335 /* 4315 802.11g id */
+#define BCM4315_D11A_ID 0x4336 /* 4315 802.11a id */
+#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */
+#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */
+#define BCM4319_D11N5G_ID 0x4339 /* 4319 802.11n 5G device */
+#define BCM43231_D11N2G_ID 0x4340 /* 43231 802.11n 2.4GHz device */
+#define BCM43221_D11N2G_ID 0x4341 /* 43221 802.11n 2.4GHz device */
+#define BCM43222_D11N_ID 0x4350 /* 43222 802.11n dualband device */
+#define BCM43222_D11N2G_ID 0x4351 /* 43222 802.11n 2.4GHz device */
+#define BCM43222_D11N5G_ID 0x4352 /* 43222 802.11n 5GHz device */
+#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband device */
+#endif /* DEPRECATED */
+/* DEPRECATED but used */
+#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */
+#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */
+#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */
+#define BCM4318_D11G_ID 0x4318 /* 4318 802.11b/g id */
+#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g id */
+/* DEPRECATED */
+
+#define BCM53572_D11N2G_ID 0x4329 /* 53572 802.11n 2.4Ghz band id (same as BCM4321) */
+#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */
+#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */
+#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */
+#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */
+#define BCM43236_D11N5G_ID 0x4348 /* 43236 802.11n 5GHz device */
+#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */
+#define BCM43421_D11N_ID 0xA99D /* 43421 802.11n dualband device */
+#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
+#define BCM4330_D11N_ID 0x4360 /* 4330 802.11n dualband device */
+#define BCM4330_D11N2G_ID 0x4361 /* 4330 802.11n 2.4G device */
+#define BCM4330_D11N5G_ID 0x4362 /* 4330 802.11n 5G device */
+#define BCM4336_D11N_ID 0x4343 /* 4336 802.11n 2.4GHz device */
+#define BCM6362_D11N_ID 0x435f /* 6362 802.11n dualband device */
+#define BCM6362_D11N2G_ID 0x433f /* 6362 802.11n 2.4Ghz band id */
+#define BCM6362_D11N5G_ID 0x434f /* 6362 802.11n 5Ghz band id */
+#define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */
+#define BCM4331_D11N2G_ID 0x4332 /* 4331 802.11n 2.4Ghz band id */
+#define BCM4331_D11N5G_ID 0x4333 /* 4331 802.11n 5Ghz band id */
+#define BCM43237_D11N_ID 0x4355 /* 43237 802.11n dualband device */
+#define BCM43237_D11N5G_ID 0x4356 /* 43237 802.11n 5GHz device */
+#define BCM43227_D11N2G_ID 0x4358 /* 43228 802.11n 2.4GHz device */
+#define BCM43228_D11N_ID 0x4359 /* 43228 802.11n DualBand device */
+#define BCM43228_D11N5G_ID 0x435a /* 43228 802.11n 5GHz device */
+#define BCM43362_D11N_ID 0x4363 /* 43362 802.11n 2.4GHz device */
+#define BCM43239_D11N_ID 0x4370 /* 43239 802.11n dualband device */
+#define BCM4324_D11N_ID 0x4374 /* 4324 802.11n dualband device */
+#define BCM43217_D11N2G_ID 0x43a9 /* 43217 802.11n 2.4GHz device */
+#define BCM43131_D11N2G_ID 0x43aa /* 43131 802.11n 2.4GHz device */
+#define BCM4314_D11N2G_ID 0x4364 /* 4314 802.11n 2.4G device */
+#define BCM43142_D11N2G_ID 0x4365 /* 43142 802.11n 2.4G device */
+#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */
+#define BCM4334_D11N_ID 0x4380 /* 4334 802.11n dualband device */
+#define BCM4334_D11N2G_ID 0x4381 /* 4334 802.11n 2.4G device */
+#define BCM4334_D11N5G_ID 0x4382 /* 4334 802.11n 5G device */
+#define BCM43342_D11N_ID 0x4383 /* 43342 802.11n dualband device */
+#define BCM43342_D11N2G_ID 0x4384 /* 43342 802.11n 2.4G device */
+#define BCM43342_D11N5G_ID 0x4385 /* 43342 802.11n 5G device */
+#define BCM43341_D11N_ID 0x4386 /* 43341 802.11n dualband device */
+#define BCM43341_D11N2G_ID 0x4387 /* 43341 802.11n 2.4G device */
+#define BCM43341_D11N5G_ID 0x4388 /* 43341 802.11n 5G device */
+#define BCM4360_D11AC_ID 0x43a0
+#define BCM4360_D11AC2G_ID 0x43a1
+#define BCM4360_D11AC5G_ID 0x43a2
+#define BCM4345_D11AC_ID 0x43ab /* 4345 802.11ac dualband device */
+#define BCM4345_D11AC2G_ID 0x43ac /* 4345 802.11ac 2.4G device */
+#define BCM4345_D11AC5G_ID 0x43ad /* 4345 802.11ac 5G device */
+#define BCM43455_D11AC_ID 0x43e3 /* 43455 802.11ac dualband device */
+#define BCM43455_D11AC2G_ID 0x43e4 /* 43455 802.11ac 2.4G device */
+#define BCM43455_D11AC5G_ID 0x43e5 /* 43455 802.11ac 5G device */
+#define BCM4335_D11AC_ID 0x43ae
+#define BCM4335_D11AC2G_ID 0x43af
+#define BCM4335_D11AC5G_ID 0x43b0
+#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */
+#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */
+#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */
+#define BCM43602_D11AC_ID 0x43ba /* ac dualband PCI devid SPROM programmed */
+#define BCM43602_D11AC2G_ID 0x43bb /* 43602 802.11ac 2.4G device */
+#define BCM43602_D11AC5G_ID 0x43bc /* 43602 802.11ac 5G device */
+#define BCM4349_D11AC_ID 0x4349 /* 4349 802.11ac dualband device */
+#define BCM4349_D11AC2G_ID 0x43dd /* 4349 802.11ac 2.4G device */
+#define BCM4349_D11AC5G_ID 0x43de /* 4349 802.11ac 5G device */
+#define BCM53573_D11AC_ID 0x43b4 /* 53573 802.11ac dualband device */
+#define BCM53573_D11AC2G_ID 0x43b5 /* 53573 802.11ac 2.4G device */
+#define BCM53573_D11AC5G_ID 0x43b6 /* 53573 802.11ac 5G device */
+#define BCM47189_D11AC_ID 0x43c6 /* 47189 802.11ac dualband device */
+#define BCM47189_D11AC2G_ID 0x43c7 /* 47189 802.11ac 2.4G device */
+#define BCM47189_D11AC5G_ID 0x43c8 /* 47189 802.11ac 5G device */
+#define BCM4355_D11AC_ID 0x43dc /* 4355 802.11ac dualband device */
+#define BCM4355_D11AC2G_ID 0x43fc /* 4355 802.11ac 2.4G device */
+#define BCM4355_D11AC5G_ID 0x43fd /* 4355 802.11ac 5G device */
+#define BCM4359_D11AC_ID 0x43ef /* 4359 802.11ac dualband device */
+#define BCM4359_D11AC2G_ID 0x43fe /* 4359 802.11ac 2.4G device */
+#define BCM4359_D11AC5G_ID 0x43ff /* 4359 802.11ac 5G device */
+#define BCM43596_D11AC_ID 0x4415 /* 43596 802.11ac dualband device */
+#define BCM43596_D11AC2G_ID 0x4416 /* 43596 802.11ac 2.4G device */
+#define BCM43596_D11AC5G_ID 0x4417 /* 43596 802.11ac 5G device */
+#define BCM43597_D11AC_ID 0x441c /* 43597 802.11ac dualband device */
+#define BCM43597_D11AC2G_ID 0x441d /* 43597 802.11ac 2.4G device */
+#define BCM43597_D11AC5G_ID 0x441e /* 43597 802.11ac 5G device */
+#define BCM43909_D11AC_ID 0x43d0 /* 43909 802.11ac dualband device */
+#define BCM43909_D11AC2G_ID 0x43d1 /* 43909 802.11ac 2.4G device */
+#define BCM43909_D11AC5G_ID 0x43d2 /* 43909 802.11ac 5G device */
+#define BCM43012_D11N_ID 0xA804 /* 43012 802.11n dualband device */
+#define BCM43012_D11N2G_ID 0xA805 /* 43012 802.11n 2.4G device */
+#define BCM43012_D11N5G_ID 0xA806 /* 43012 802.11n 5G device */
+
+/* PCI Subsystem ID */
+#define BCM943228HMB_SSID_VEN1 0x0607
+#define BCM94313HMGBL_SSID_VEN1 0x0608
+#define BCM94313HMG_SSID_VEN1 0x0609
+#define BCM943142HM_SSID_VEN1 0x0611
+
+#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */
+
+#define BCM43242_D11N_ID 0x4367 /* 43242 802.11n dualband device */
+#define BCM43242_D11N2G_ID 0x4368 /* 43242 802.11n 2.4G device */
+#define BCM43242_D11N5G_ID 0x4369 /* 43242 802.11n 5G device */
+
+#define BCM4350_D11AC_ID 0x43a3
+#define BCM4350_D11AC2G_ID 0x43a4
+#define BCM4350_D11AC5G_ID 0x43a5
+
+#define BCM43556_D11AC_ID 0x43b7
+#define BCM43556_D11AC2G_ID 0x43b8
+#define BCM43556_D11AC5G_ID 0x43b9
+
+#define BCM43558_D11AC_ID 0x43c0
+#define BCM43558_D11AC2G_ID 0x43c1
+#define BCM43558_D11AC5G_ID 0x43c2
+
+#define BCM43566_D11AC_ID 0x43d3
+#define BCM43566_D11AC2G_ID 0x43d4
+#define BCM43566_D11AC5G_ID 0x43d5
+
+#define BCM43568_D11AC_ID 0x43d6
+#define BCM43568_D11AC2G_ID 0x43d7
+#define BCM43568_D11AC5G_ID 0x43d8
+
+#define BCM43569_D11AC_ID 0x43d9
+#define BCM43569_D11AC2G_ID 0x43da
+#define BCM43569_D11AC5G_ID 0x43db
+
+#define BCM43570_D11AC_ID 0x43d9
+#define BCM43570_D11AC2G_ID 0x43da
+#define BCM43570_D11AC5G_ID 0x43db
+
+#define BCM4354_D11AC_ID 0x43df /* 4354 802.11ac dualband device */
+#define BCM4354_D11AC2G_ID 0x43e0 /* 4354 802.11ac 2.4G device */
+#define BCM4354_D11AC5G_ID 0x43e1 /* 4354 802.11ac 5G device */
+#define BCM43430_D11N2G_ID 0x43e2 /* 43430 802.11n 2.4G device */
+#define BCM43018_D11N2G_ID 0x441b /* 43018 802.11n 2.4G device */
+
+
+#define BCM4347_D11AC_ID 0x440a /* 4347 802.11ac dualband device */
+#define BCM4347_D11AC2G_ID 0x440b /* 4347 802.11ac 2.4G device */
+#define BCM4347_D11AC5G_ID 0x440c /* 4347 802.11ac 5G device */
+
+#define BCM4361_D11AC_ID 0x441f /* 4361 802.11ac dualband device */
+#define BCM4361_D11AC2G_ID 0x4420 /* 4361 802.11ac 2.4G device */
+#define BCM4361_D11AC5G_ID 0x4421 /* 4361 802.11ac 5G device */
+
+#define BCM4364_D11AC_ID 0x4464 /* 4364 802.11ac dualband device */
+#define BCM4364_D11AC2G_ID 0x446a /* 4364 802.11ac 2.4G device */
+#define BCM4364_D11AC5G_ID 0x446b /* 4364 802.11ac 5G device */
+
+
+#define BCM4365_D11AC_ID 0x43ca
+#define BCM4365_D11AC2G_ID 0x43cb
+#define BCM4365_D11AC5G_ID 0x43cc
+
+#define BCM4366_D11AC_ID 0x43c3
+#define BCM4366_D11AC2G_ID 0x43c4
+#define BCM4366_D11AC5G_ID 0x43c5
+
+/* TBD change below values */
+#define BCM4369_D11AC_ID 0x4470 /* 4369 802.11ac dualband device */
+#define BCM4369_D11AC2G_ID 0x4471 /* 4369 802.11ac 2.4G device */
+#define BCM4369_D11AC5G_ID 0x4472 /* 4369 802.11ac 5G device */
+
+
+#define BCM43349_D11N_ID 0x43e6 /* 43349 802.11n dualband id */
+#define BCM43349_D11N2G_ID 0x43e7 /* 43349 802.11n 2.4Ghz band id */
+#define BCM43349_D11N5G_ID 0x43e8 /* 43349 802.11n 5Ghz band id */
+
+#define BCM4358_D11AC_ID 0x43e9 /* 4358 802.11ac dualband device */
+#define BCM4358_D11AC2G_ID 0x43ea /* 4358 802.11ac 2.4G device */
+#define BCM4358_D11AC5G_ID 0x43eb /* 4358 802.11ac 5G device */
+
+#define BCM4356_D11AC_ID 0x43ec /* 4356 802.11ac dualband device */
+#define BCM4356_D11AC2G_ID 0x43ed /* 4356 802.11ac 2.4G device */
+#define BCM4356_D11AC5G_ID 0x43ee /* 4356 802.11ac 5G device */
+
+#define BCM4371_D11AC_ID 0x440d /* 4371 802.11ac dualband device */
+#define BCM4371_D11AC2G_ID 0x440e /* 4371 802.11ac 2.4G device */
+#define BCM4371_D11AC5G_ID 0x440f /* 4371 802.11ac 5G device */
+#define BCM7271_D11AC_ID 0x4410 /* 7271 802.11ac dualband device */
+#define BCM7271_D11AC2G_ID 0x4411 /* 7271 802.11ac 2.4G device */
+#define BCM7271_D11AC5G_ID 0x4412 /* 7271 802.11ac 5G device */
+
+#define BCM4373_D11AC_ID 0x4418 /* 4373 802.11ac dualband device */
+#define BCM4373_D11AC2G_ID 0x4419 /* 4373 802.11ac 2.4G device */
+#define BCM4373_D11AC5G_ID 0x441a /* 4373 802.11ac 5G device */
+
+#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */
+#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */
+#define FPGA_JTAGM_ID 0x43f0 /* FPGA jtagm device id */
+#define BCM_JTAGM_ID 0x43f1 /* BCM jtagm device id */
+#define SDIOH_FPGA_ID 0x43f2 /* sdio host fpga */
+#define BCM_SDIOH_ID 0x43f3 /* BCM sdio host id */
+#define SDIOD_FPGA_ID 0x43f4 /* sdio device fpga */
+#define SPIH_FPGA_ID 0x43f5 /* PCI SPI Host Controller FPGA */
+#define BCM_SPIH_ID 0x43f6 /* Synopsis SPI Host Controller */
+#define MIMO_FPGA_ID 0x43f8 /* FPGA mimo minimacphy device id */
+#define BCM_JTAGM2_ID 0x43f9 /* BCM alternate jtagm device id */
+#define SDHCI_FPGA_ID 0x43fa /* Standard SDIO Host Controller FPGA */
+#define BCM4402_ENET_ID 0x4402 /* 4402 enet */
+#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */
+#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */
+#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */
+#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */
+#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */
+#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */
+#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */
+#define BCM47XX_AUDIO_ID 0x4711 /* 47xx audio codec */
+#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */
+#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */
+#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */
+#define BCM47XX_GMAC_ID 0x4715 /* 47xx Unimac based GbE */
+#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */
+#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */
+#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */
+#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */
+#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */
+#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */
+#define BCM47XX_ATA100_ID 0x471d /* 47xx parallel ATA */
+#define BCM47XX_SATAXOR_ID 0x471e /* 47xx serial ATA & XOR DMA */
+#define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */
+#ifdef DEPRECATED /* These products have been deprecated */
+#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */
+#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */
+#endif /* DEPRECATED */
+#define BCM47XX_USB30H_ID 0x472a /* 47xx usb 3.0 host */
+#define BCM47XX_USB30D_ID 0x472b /* 47xx usb 3.0 device */
+#define BCM47XX_USBHUB_ID 0x472c /* 47xx usb hub */
+#define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */
+#define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */
+#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */
+#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */
+#define JINVANI_SDIOH_ID 0x4743 /* Jinvani SDIO Gold Host */
+#define BCM27XX_SDIOH_ID 0x2702 /* BCM27xx Standard SDIO Host */
+#define PCIXX21_FLASHMEDIA_ID 0x803b /* TI PCI xx21 Standard Host Controller */
+#define PCIXX21_SDIOH_ID 0x803c /* TI PCI xx21 Standard Host Controller */
+#define R5C822_SDIOH_ID 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */
+#define JMICRON_SDIOH_ID 0x2381 /* JMicron Standard SDIO Host Controller */
+
+#define BCM43452_D11AC_ID 0x47ab /* 43452 802.11ac dualband device */
+#define BCM43452_D11AC2G_ID 0x47ac /* 43452 802.11ac 2.4G device */
+#define BCM43452_D11AC5G_ID 0x47ad /* 43452 802.11ac 5G device */
+
+/* Chip IDs */
+#ifdef DEPRECATED /* These products have been deprecated */
+#define BCM4306_CHIP_ID 0x4306 /* 4306 chipcommon chipid */
+#define BCM4311_CHIP_ID 0x4311 /* 4311 PCIe 802.11a/b/g */
+#define BCM43111_CHIP_ID 43111 /* 43111 chipcommon chipid (OTP chipid) */
+#define BCM43112_CHIP_ID 43112 /* 43112 chipcommon chipid (OTP chipid) */
+#define BCM4312_CHIP_ID 0x4312 /* 4312 chipcommon chipid */
+#define BCM4315_CHIP_ID 0x4315 /* 4315 chip id */
+#define BCM4318_CHIP_ID 0x4318 /* 4318 chipcommon chipid */
+#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */
+#define BCM4320_CHIP_ID 0x4320 /* 4320 chipcommon chipid */
+#define BCM4321_CHIP_ID 0x4321 /* 4321 chipcommon chipid */
+#define BCM4322_CHIP_ID 0x4322 /* 4322 chipcommon chipid */
+#define BCM43221_CHIP_ID 43221 /* 43221 chipcommon chipid (OTP chipid) */
+#define BCM43222_CHIP_ID 43222 /* 43222 chipcommon chipid */
+#define BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */
+#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (OTP chipid) */
+#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */
+#define BCM4325_CHIP_ID 0x4325 /* 4325 chip id */
+#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */
+#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */
+#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */
+#endif /* DEPRECATED */
+
+/* DEPRECATED but still referenced in components - start */
+#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */
+#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */
+#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */
+#define BCM5354_CHIP_ID 0x5354 /* 5354 chipcommon chipid */
+/* DEPRECATED but still referenced in components - end */
+
+#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */
+#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */
+#define BCM43227_CHIP_ID 43227 /* 43227 chipcommon chipid */
+#define BCM43228_CHIP_ID 43228 /* 43228 chipcommon chipid */
+#define BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP chipid) */
+#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */
+#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP chipid) */
+#define BCM43234_CHIP_ID 43234 /* 43234 chipcommon chipid */
+#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */
+#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */
+#define BCM43237_CHIP_ID 43237 /* 43237 chipcommon chipid */
+#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */
+#define BCM43239_CHIP_ID 43239 /* 43239 chipcommon chipid */
+#define BCM43420_CHIP_ID 43420 /* 43222 chipcommon chipid (OTP, RBBU) */
+#define BCM43421_CHIP_ID 43421 /* 43224 chipcommon chipid (OTP, RBBU) */
+#define BCM43428_CHIP_ID 43428 /* 43228 chipcommon chipid (OTP, RBBU) */
+#define BCM43431_CHIP_ID 43431 /* 4331 chipcommon chipid (OTP, RBBU) */
+#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */
+#define BCM43465_CHIP_ID 43465 /* 4366 chipcommon chipid (OTP, RBBU) */
+#define BCM43525_CHIP_ID 43525 /* 4365 chipcommon chipid (OTP, RBBU) */
+#define BCM47452_CHIP_ID 47452 /* 53573 chipcommon chipid (OTP, RBBU) */
+#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */
+#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */
+#define BCM43362_CHIP_ID 43362 /* 43362 chipcommon chipid */
+#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */
+#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */
+#define BCM4314_CHIP_ID 0x4314 /* 4314 chipcommon chipid */
+#define BCM43142_CHIP_ID 43142 /* 43142 chipcommon chipid */
+#define BCM43143_CHIP_ID 43143 /* 43143 chipcommon chipid */
+#define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */
+#define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */
+#define BCM43243_CHIP_ID 43243 /* 43243 chipcommon chipid */
+#define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */
+#define BCM4335_CHIP_ID 0x4335 /* 4335 chipcommon chipid */
+#define BCM4339_CHIP_ID 0x4339 /* 4339 chipcommon chipid */
+#define BCM43349_CHIP_ID 43349 /* 43349(0xA955) chipcommon chipid */
+#define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */
+#define BCM4364_CHIP_ID 0x4364 /* 4364 chipcommon chipid */
+#define BCM4352_CHIP_ID 0x4352 /* 4352 chipcommon chipid */
+#define BCM43526_CHIP_ID 0xAA06
+#define BCM43340_CHIP_ID 43340 /* 43340 chipcommon chipid */
+#define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */
+#define BCM43342_CHIP_ID 43342 /* 43342 chipcommon chipid */
+#define BCM4350_CHIP_ID 0x4350 /* 4350 chipcommon chipid */
+#define BCM4354_CHIP_ID 0x4354 /* 4354 chipcommon chipid */
+#define BCM4356_CHIP_ID 0x4356 /* 4356 chipcommon chipid */
+#define BCM4371_CHIP_ID 0x4371 /* 4371 chipcommon chipid */
+#define BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */
+#define BCM43558_CHIP_ID 0xAA26 /* 43558 chipcommon chipid */
+#define BCM43562_CHIP_ID 0xAA2A /* 43562 chipcommon chipid */
+#define BCM43566_CHIP_ID 0xAA2E /* 43566 chipcommon chipid */
+#define BCM43567_CHIP_ID 0xAA2F /* 43567 chipcommon chipid */
+#define BCM43568_CHIP_ID 0xAA30 /* 43568 chipcommon chipid */
+#define BCM43569_CHIP_ID 0xAA31 /* 43569 chipcommon chipid */
+#define BCM43570_CHIP_ID 0xAA32 /* 43570 chipcommon chipid */
+#define BCM4358_CHIP_ID 0x4358 /* 4358 chipcommon chipid */
+#define BCM43012_CHIP_ID 0xA804 /* 43012 chipcommon chipid */
+#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4354_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43556_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43558_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43566_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43567_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43568_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43569_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43570_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4358_CHIP_ID)) /* 4350 variations */
+
+#define BCM4345_CHIP_ID 0x4345 /* 4345 chipcommon chipid */
+#define BCM43454_CHIP_ID 43454 /* 43454 chipcommon chipid */
+#define BCM43455_CHIP_ID 43455 /* 43455 chipcommon chipid */
+#define BCM43457_CHIP_ID 43457 /* 43457 chipcommon chipid */
+#define BCM43458_CHIP_ID 43458 /* 43458 chipcommon chipid */
+
+#define BCM4345_CHIP(chipid) (CHIPID(chipid) == BCM4345_CHIP_ID || \
+ CHIPID(chipid) == BCM43454_CHIP_ID || \
+ CHIPID(chipid) == BCM43455_CHIP_ID || \
+ CHIPID(chipid) == BCM43457_CHIP_ID || \
+ CHIPID(chipid) == BCM43458_CHIP_ID)
+
+#define CASE_BCM4345_CHIP case BCM4345_CHIP_ID: /* fallthrough */ \
+ case BCM43454_CHIP_ID: /* fallthrough */ \
+ case BCM43455_CHIP_ID: /* fallthrough */ \
+ case BCM43457_CHIP_ID: /* fallthrough */ \
+ case BCM43458_CHIP_ID
+
+#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */
+#define BCM43018_CHIP_ID 43018 /* 43018 chipcommon chipid */
+#define BCM4349_CHIP_ID 0x4349 /* 4349 chipcommon chipid */
+#define BCM4355_CHIP_ID 0x4355 /* 4355 chipcommon chipid */
+#define BCM4359_CHIP_ID 0x4359 /* 4359 chipcommon chipid */
+#define BCM4349_CHIP(chipid) ((CHIPID(chipid) == BCM4349_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4355_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4359_CHIP_ID))
+#define BCM4349_CHIP_GRPID BCM4349_CHIP_ID: \
+ case BCM4355_CHIP_ID: \
+ case BCM4359_CHIP_ID
+#define BCM43596_CHIP_ID 43596 /* 43596 chipcommon chipid */
+
+
+#define BCM4347_CHIP_ID 0x4347 /* 4347 chipcommon chipid */
+#define BCM4357_CHIP_ID 0x4357 /* 4357 chipcommon chipid */
+#define BCM4361_CHIP_ID 0x4361 /* 4361 chipcommon chipid */
+#define BCM4369_CHIP_ID 0x4369 /* 436/ chipcommon chipid */
+#define BCM4347_CHIP(chipid) ((CHIPID(chipid) == BCM4347_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4357_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4361_CHIP_ID))
+#define BCM4347_CHIP_GRPID BCM4347_CHIP_ID: \
+ case BCM4357_CHIP_ID: \
+ case BCM4361_CHIP_ID
+
+#define BCM4365_CHIP_ID 0x4365 /* 4365 chipcommon chipid */
+#define BCM4366_CHIP_ID 0x4366 /* 4366 chipcommon chipid */
+#define BCM43664_CHIP_ID 43664 /* 4366E chipcommon chipid */
+#define BCM43666_CHIP_ID 43666 /* 4365E chipcommon chipid */
+#define BCM4365_CHIP(chipid) ((CHIPID(chipid) == BCM4365_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4366_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43664_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43666_CHIP_ID))
+#define CASE_BCM4365_CHIP case BCM4365_CHIP_ID: /* fallthrough */ \
+ case BCM4366_CHIP_ID: /* fallthrough */ \
+ case BCM43664_CHIP_ID: /* fallthrough */ \
+ case BCM43666_CHIP_ID
+
+#define BCM43909_CHIP_ID 0xab85 /* 43909 chipcommon chipid */
+
+#define BCM43602_CHIP_ID 0xaa52 /* 43602 chipcommon chipid */
+#define BCM43462_CHIP_ID 0xa9c6 /* 43462 chipcommon chipid */
+#define BCM43522_CHIP_ID 0xaa02 /* 43522 chipcommon chipid */
+#define BCM43602_CHIP(chipid) ((CHIPID(chipid) == BCM43602_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43462_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43522_CHIP_ID)) /* 43602 variations */
+#define BCM43012_CHIP(chipid) (CHIPID(chipid) == BCM43012_CHIP_ID)
+#define CASE_BCM43602_CHIP case BCM43602_CHIP_ID: /* fallthrough */ \
+ case BCM43462_CHIP_ID: /* fallthrough */ \
+ case BCM43522_CHIP_ID
+
+#define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */
+#define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */
+#define BCM4706_CHIP_ID 0x5300 /* 4706 chipcommon chipid */
+#define BCM4707_CHIP_ID 53010 /* 4707 chipcommon chipid */
+#define BCM47094_CHIP_ID 53030 /* 47094 chipcommon chipid */
+#define BCM53018_CHIP_ID 53018 /* 53018 chipcommon chipid */
+#define BCM4707_CHIP(chipid) (((chipid) == BCM4707_CHIP_ID) || \
+ ((chipid) == BCM53018_CHIP_ID) || \
+ ((chipid) == BCM47094_CHIP_ID))
+#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */
+#define BCM4749_CHIP_ID 0x4749 /* 5357 chipcommon chipid (OTP, RBBU) */
+#define BCM4785_CHIP_ID 0x4785 /* 4785 chipcommon chipid */
+#define BCM5350_CHIP_ID 0x5350 /* 5350 chipcommon chipid */
+#define BCM5352_CHIP_ID 0x5352 /* 5352 chipcommon chipid */
+#define BCM5365_CHIP_ID 0x5365 /* 5365 chipcommon chipid */
+#define BCM5356_CHIP_ID 0x5356 /* 5356 chipcommon chipid */
+#define BCM5357_CHIP_ID 0x5357 /* 5357 chipcommon chipid */
+#define BCM53572_CHIP_ID 53572 /* 53572 chipcommon chipid */
+#define BCM53573_CHIP_ID 53573 /* 53573 chipcommon chipid */
+#define BCM53574_CHIP_ID 53574 /* 53574 chipcommon chipid */
+#define BCM53573_CHIP(chipid) ((CHIPID(chipid) == BCM53573_CHIP_ID) || \
+ (CHIPID(chipid) == BCM53574_CHIP_ID) || \
+ (CHIPID(chipid) == BCM47452_CHIP_ID))
+#define BCM53573_CHIP_GRPID BCM53573_CHIP_ID : \
+ case BCM53574_CHIP_ID : \
+ case BCM47452_CHIP_ID
+#define BCM53573_DEVICE(devid) (((devid) == BCM53573_D11AC_ID) || \
+ ((devid) == BCM53573_D11AC2G_ID) || \
+ ((devid) == BCM53573_D11AC5G_ID) || \
+ ((devid) == BCM47189_D11AC_ID) || \
+ ((devid) == BCM47189_D11AC2G_ID) || \
+ ((devid) == BCM47189_D11AC5G_ID))
+
+#define BCM7271_CHIP_ID 0x05c9 /* 7271 chipcommon chipid */
+#define BCM7271_CHIP(chipid) ((CHIPID(chipid) == BCM7271_CHIP_ID))
+
+#define BCM4373_CHIP_ID 0x4373 /* 4373 chipcommon chipid */
+
+/* Package IDs */
+#ifdef DEPRECATED /* These products have been deprecated */
+#define BCM4303_PKG_ID 2 /* 4303 package id */
+#define BCM4309_PKG_ID 1 /* 4309 package id */
+#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */
+#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */
+#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */
+#define BCM4328USBD11G_PKG_ID 2 /* 4328 802.11g USB package id */
+#define BCM4328USBDUAL_PKG_ID 3 /* 4328 802.11a/g USB package id */
+#define BCM4328SDIOD11G_PKG_ID 4 /* 4328 802.11g SDIO package id */
+#define BCM4328SDIODUAL_PKG_ID 5 /* 4328 802.11a/g SDIO package id */
+#define BCM4329_289PIN_PKG_ID 0 /* 4329 289-pin package id */
+#define BCM4329_182PIN_PKG_ID 1 /* 4329N 182-pin package id */
+#define BCM5354E_PKG_ID 1 /* 5354E package id */
+#define BCM4716_PKG_ID 8 /* 4716 package id */
+#define BCM4717_PKG_ID 9 /* 4717 package id */
+#define BCM4718_PKG_ID 10 /* 4718 package id */
+#endif /* DEPRECATED */
+#define BCM5356_PKG_NONMODE 1 /* 5356 package without nmode suppport */
+#define BCM5358U_PKG_ID 8 /* 5358U package id */
+#define BCM5358_PKG_ID 9 /* 5358 package id */
+#define BCM47186_PKG_ID 10 /* 47186 package id */
+#define BCM5357_PKG_ID 11 /* 5357 package id */
+#define BCM5356U_PKG_ID 12 /* 5356U package id */
+#define BCM53572_PKG_ID 8 /* 53572 package id */
+#define BCM5357C0_PKG_ID 8 /* 5357c0 package id (the same as 53572) */
+#define BCM47188_PKG_ID 9 /* 47188 package id */
+#define BCM5358C0_PKG_ID 0xa /* 5358c0 package id */
+#define BCM5356C0_PKG_ID 0xb /* 5356c0 package id */
+#define BCM4331TT_PKG_ID 8 /* 4331 12x12 package id */
+#define BCM4331TN_PKG_ID 9 /* 4331 12x9 package id */
+#define BCM4331TNA0_PKG_ID 0xb /* 4331 12x9 package id */
+#define BCM47189_PKG_ID 1 /* 47189 package id */
+#define BCM53573_PKG_ID 0 /* 53573 package id */
+#define BCM4706L_PKG_ID 1 /* 4706L package id */
+
+#define HDLSIM5350_PKG_ID 1 /* HDL simulator package id for a 5350 */
+#define HDLSIM_PKG_ID 14 /* HDL simulator package id */
+#define HWSIM_PKG_ID 15 /* Hardware simulator package id */
+#define BCM43224_FAB_CSM 0x8 /* the chip is manufactured by CSM */
+#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */
+#define BCM4336_WLBGA_PKG_ID 0x8
+#define BCM4330_WLBGA_PKG_ID 0x0
+#define BCM4314PCIE_ARM_PKG_ID (8 | 0) /* 4314 QFN PCI package id, bit 3 tie high */
+#define BCM4314SDIO_PKG_ID (8 | 1) /* 4314 QFN SDIO package id */
+#define BCM4314PCIE_PKG_ID (8 | 2) /* 4314 QFN PCI (ARM-less) package id */
+#define BCM4314SDIO_ARM_PKG_ID (8 | 3) /* 4314 QFN SDIO (ARM-less) package id */
+#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) /* 4314 FpBGA SDIO package id */
+#define BCM4314DEV_PKG_ID (8 | 6) /* 4314 Developement package id */
+
+#define BCM4707_PKG_ID 1 /* 4707 package id */
+#define BCM4708_PKG_ID 2 /* 4708 package id */
+#define BCM4709_PKG_ID 0 /* 4709 package id */
+
+#define PCIXX21_FLASHMEDIA0_ID 0x8033 /* TI PCI xx21 Standard Host Controller */
+#define PCIXX21_SDIOH0_ID 0x8034 /* TI PCI xx21 Standard Host Controller */
+
+#define BCM4335_WLCSP_PKG_ID (0x0) /* WLCSP Module/Mobile SDIO/HSIC. */
+#define BCM4335_FCBGA_PKG_ID (0x1) /* FCBGA PC/Embeded/Media PCIE/SDIO */
+#define BCM4335_WLBGA_PKG_ID (0x2) /* WLBGA COB/Mobile SDIO/HSIC. */
+#define BCM4335_FCBGAD_PKG_ID (0x3) /* FCBGA Debug Debug/Dev All if's. */
+#define BCM4335_PKG_MASK (0x3)
+#define BCM43602_12x12_PKG_ID (0x1) /* 12x12 pins package, used for e.g. router designs */
+
+
+/* boardflags */
+#define BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */
+#define BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */
+#define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */
+#define BFL_AIRLINEMODE 0x00000004 /* Board implements gpio radio disable indication */
+#define BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */
+#define BFL_DIS_256QAM 0x00000008
+#define BFL_ENETROBO 0x00000010 /* Board has robo switch or core */
+#define BFL_TSSIAVG 0x00000010 /* TSSI averaging for ACPHY chips */
+#define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */
+#define BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */
+#define BFL_ENETADM 0x00000080 /* Board has ADMtek switch */
+#define BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */
+#define BFL_LTECOEX 0x00000200 /* LTE Coex enabled */
+#define BFL_NOPCI 0x00000400 /* Board leaves PCI floating */
+#define BFL_FEM 0x00000800 /* Board supports the Front End Module */
+#define BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */
+#define BFL_HGPA 0x00002000 /* Board has a high gain PA */
+#define BFL_BTC2WIRE_ALTGPIO 0x00004000 /* Board's BTC 2wire is in the alternate gpios */
+#define BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */
+#define BFL_NOPA 0x00010000 /* Board has no PA */
+#define BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */
+#define BFL_PAREF 0x00040000 /* Board uses the PARef LDO */
+#define BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */
+#define BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */
+#define BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */
+#define BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */
+#define BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */
+#define BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */
+#define BFL_PALDO 0x02000000 /* Power topology uses PALDO */
+#define BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */
+#define BFL_FASTPWR 0x08000000
+#define BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */
+#define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */
+#define BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */
+#define BFL_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */
+#define BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */
+#define BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field
+ * when this flag is set
+ */
+#define BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */
+
+/* boardflags2 */
+#define BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */
+#define BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */
+#define BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */
+#define BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */
+#define BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */
+#define BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */
+#define BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */
+#define BFL2_WLCX_ATLAS 0x00000040 /* Board flag to initialize ECI for WLCX on FL-ATLAS */
+#define BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */
+#define BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace
+ * BFL2_BTC3WIRE
+ */
+#define BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */
+#define BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */
+#define BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */
+#define BFL2_TRISTATE_LED 0x00000800 /* Tri-state the LED */
+#define BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */
+#define BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */
+#define BFL2_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */
+#define BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */
+#define BFL2_DAC_SPUR_IMPROVEMENT 0x00008000 /* Reducing DAC Spurs */
+#define BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */
+#define BFL2_REDUCED_PA_TURNONTIME 0x00010000 /* Flag to reduce PA turn on Time */
+#define BFL2_IPALVLSHIFT_3P3 0x00020000
+#define BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */
+#define BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio on */
+ /* Most drivers will turn it off without this flag */
+ /* to save power. */
+
+#define BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */
+#define BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */
+#define BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */
+#define BFL2_BT_SHARE_ANT0 0x00800000 /* share core0 antenna with BT */
+#define BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value
+ * than programmed. The exact delta is decided by
+ * driver per chip/boardtype. This can be used
+ * when tempsense qualification happens after shipment
+ */
+#define BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */
+#define BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */
+#define BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save */
+ /* ucode control of eLNA during Tx */
+#define BFL2_4313_RADIOREG 0x10000000
+ /* board rework */
+#define BFL2_DYNAMIC_VMID 0x10000000 /* enable dynamic Vmid in idle TSSI CAL for 4331 */
+
+#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */
+#define BFL2_DYNAMIC_VMID 0x10000000 /* boardflag to enable dynamic Vmid idle TSSI CAL */
+#define BFL2_LNA1BYPFORTR2G 0x40000000 /* acphy, enable lna1 bypass for clip gain, 2g */
+#define BFL2_LNA1BYPFORTR5G 0x80000000 /* acphy, enable lna1 bypass for clip gain, 5g */
+
+/* SROM 11 - 11ac boardflag definitions */
+#define BFL_SROM11_BTCOEX 0x00000001 /* Board supports BTCOEX */
+#define BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 /* bluetooth and wlan share same crystal */
+#define BFL_SROM11_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */
+#define BFL_SROM11_EPA_TURNON_TIME 0x00018000 /* 2 bits for different PA turn on times */
+#define BFL_SROM11_EPA_TURNON_TIME_SHIFT 15
+#define BFL_SROM11_PRECAL_TX_IDX 0x00040000 /* Dedicated TX IQLOCAL IDX values */
+ /* per subband, as derived from 43602A1 MCH5 */
+#define BFL_SROM11_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */
+#define BFL_SROM11_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */
+#define BFL2_SROM11_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */
+#define BFL2_SROM11_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are ctrl-ed by analog PA ctrl lines */
+#define BFL2_SROM11_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are ctrl-ed by analog PA ctrl lines */
+#define BFL2_SROM11_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */
+#define BFL2_SROM11_EPA_ON_DURING_TXIQLOCAL 0x00020000 /* Keep ext. PA's on in TX IQLO CAL */
+
+/* boardflags3 */
+#define BFL3_FEMCTRL_SUB 0x00000007 /* acphy, subrevs of femctrl on top of srom_femctrl */
+#define BFL3_RCAL_WAR 0x00000008 /* acphy, rcal war active on this board (4335a0) */
+#define BFL3_TXGAINTBLID 0x00000070 /* acphy, txgain table id */
+#define BFL3_TXGAINTBLID_SHIFT 0x4 /* acphy, txgain table id shift bit */
+#define BFL3_TSSI_DIV_WAR 0x00000080 /* acphy, Seperate paparam for 20/40/80 */
+#define BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Seperate paparam for 20/40/80 shift bit */
+#define BFL3_FEMTBL_FROM_NVRAM 0x00000100 /* acphy, femctrl table is read from nvram */
+#define BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 /* acphy, femctrl table is read from nvram */
+#define BFL3_AGC_CFG_2G 0x00000200 /* acphy, gain control configuration for 2G */
+#define BFL3_AGC_CFG_5G 0x00000400 /* acphy, gain control configuration for 5G */
+#define BFL3_PPR_BIT_EXT 0x00000800 /* acphy, bit position for 1bit extension for ppr */
+#define BFL3_PPR_BIT_EXT_SHIFT 11 /* acphy, bit shift for 1bit extension for ppr */
+#define BFL3_BBPLL_SPR_MODE_DIS 0x00001000 /* acphy, disables bbpll spur modes */
+#define BFL3_RCAL_OTP_VAL_EN 0x00002000 /* acphy, to read rcal_trim value from otp */
+#define BFL3_2GTXGAINTBL_BLANK 0x00004000 /* acphy, blank the first X ticks of 2g gaintbl */
+#define BFL3_2GTXGAINTBL_BLANK_SHIFT 14 /* acphy, blank the first X ticks of 2g gaintbl */
+#define BFL3_5GTXGAINTBL_BLANK 0x00008000 /* acphy, blank the first X ticks of 5g gaintbl */
+#define BFL3_5GTXGAINTBL_BLANK_SHIFT 15 /* acphy, blank the first X ticks of 5g gaintbl */
+#define BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 /* acphy, to max out alpha,beta to 511 */
+#define BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 /* acphy, to max out alpha,beta to 511 */
+/* acphy, to use backed off gaintbl for lte-coex */
+#define BFL3_LTECOEX_GAINTBL_EN 0x00060000
+/* acphy, to use backed off gaintbl for lte-coex */
+#define BFL3_LTECOEX_GAINTBL_EN_SHIFT 17
+#define BFL3_5G_SPUR_WAR 0x00080000 /* acphy, enable spur WAR in 5G band */
+#define BFL3_1X1_RSDB_ANT 0x01000000 /* to find if 2-ant RSDB board or 1-ant RSDB board */
+#define BFL3_1X1_RSDB_ANT_SHIFT 24
+
+/* acphy: lpmode2g and lpmode_5g related boardflags */
+#define BFL3_ACPHY_LPMODE_2G 0x00300000 /* bits 20:21 for lpmode_2g choice */
+#define BFL3_ACPHY_LPMODE_2G_SHIFT 20
+
+#define BFL3_ACPHY_LPMODE_5G 0x00C00000 /* bits 22:23 for lpmode_5g choice */
+#define BFL3_ACPHY_LPMODE_5G_SHIFT 22
+
+#define BFL3_EXT_LPO_ISCLOCK 0x02000000 /* External LPO is clock, not x-tal */
+#define BFL3_FORCE_INT_LPO_SEL 0x04000000 /* Force internal lpo */
+#define BFL3_FORCE_EXT_LPO_SEL 0x08000000 /* Force external lpo */
+
+#define BFL3_EN_BRCM_IMPBF 0x10000000 /* acphy, Allow BRCM Implicit TxBF */
+#define BFL3_AVVMID_FROM_NVRAM 0x40000000 /* Read Av Vmid from NVRAM */
+#define BFL3_VLIN_EN_FROM_NVRAM 0x80000000 /* Read Vlin En from NVRAM */
+
+#define BFL3_AVVMID_FROM_NVRAM_SHIFT 30 /* Read Av Vmid from NVRAM */
+#define BFL3_VLIN_EN_FROM_NVRAM_SHIFT 31 /* Enable Vlin from NVRAM */
+
+/* boardflags4 for SROM12/SROM13 */
+#define BFL4_SROM12_4dBPAD (1 << 0) /* To distinguigh between normal and 4dB pad board */
+#define BFL4_SROM12_2G_DETTYPE (1 << 1) /* Determine power detector type for 2G */
+#define BFL4_SROM12_5G_DETTYPE (1 << 2) /* Determine power detector type for 5G */
+#define BFL4_SROM13_DETTYPE_EN (1 << 3) /* using pa_dettype from SROM13 flags */
+#define BFL4_SROM13_CCK_SPUR_EN (1 << 4) /* using cck spur reduction setting in 4366 */
+#define BFL4_SROM13_1P5V_CBUCK (1 << 7) /* using 1.5V cbuck board in 4366 */
+#define BFL4_SROM13_EN_SW_TXRXCHAIN_MASK (1 << 8) /* Enable/disable bit for sw chain mask */
+
+#define BFL4_4364_HARPOON 0x0100 /* Harpoon module 4364 */
+#define BFL4_4364_GODZILLA 0x0200 /* Godzilla module 4364 */
+#define BFL4_BTCOEX_OVER_SECI 0x00000400 /* Enable btcoex over gci seci */
+
+/* papd params */
+#define PAPD_TX_ATTN_2G 0xFF
+#define PAPD_TX_ATTN_5G 0xFF00
+#define PAPD_TX_ATTN_5G_SHIFT 8
+#define PAPD_RX_ATTN_2G 0xFF
+#define PAPD_RX_ATTN_5G 0xFF00
+#define PAPD_RX_ATTN_5G_SHIFT 8
+#define PAPD_CAL_IDX_2G 0xFF
+#define PAPD_CAL_IDX_5G 0xFF00
+#define PAPD_CAL_IDX_5G_SHIFT 8
+#define PAPD_BBMULT_2G 0xFF
+#define PAPD_BBMULT_5G 0xFF00
+#define PAPD_BBMULT_5G_SHIFT 8
+#define TIA_GAIN_MODE_2G 0xFF
+#define TIA_GAIN_MODE_5G 0xFF00
+#define TIA_GAIN_MODE_5G_SHIFT 8
+#define PAPD_EPS_OFFSET_2G 0xFFFF
+#define PAPD_EPS_OFFSET_5G 0xFFFF0000
+#define PAPD_EPS_OFFSET_5G_SHIFT 16
+#define PAPD_CALREF_DB_2G 0xFF
+#define PAPD_CALREF_DB_5G 0xFF00
+#define PAPD_CALREF_DB_5G_SHIFT 8
+
+
+/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */
+#define BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */
+#define BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */
+#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */
+#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */
+#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */
+#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */
+#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */
+#define BOARD_GPIO_12 0x1000 /* gpio 12 */
+#define BOARD_GPIO_13 0x2000 /* gpio 13 */
+#define BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */
+#define BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */
+#define BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */
+#define BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */
+#define BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */
+#define BOARD_GPIO_2_WLAN_PWR 0x04 /* throttle WLAN power on X29C board */
+#define BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */
+#define BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */
+#define BOARD_GPIO_13_WLAN_PWR 0x2000 /* throttle WLAN power on X14 board */
+
+#define GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */
+#define GPIO_BTC4W_OUT_43224 0x020 /* bit 5 is BT_IODISABLE */
+#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 /* bit 5 is BT_IODISABLE */
+#define GPIO_BTC4W_OUT_43225 0x0e0 /* bit 5 BT_IODISABLE, bit 6 SW_BT, bit 7 SW_WL */
+#define GPIO_BTC4W_OUT_43421 0x020 /* bit 5 is BT_IODISABLE */
+#define GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */
+#define GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */
+
+#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */
+#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */
+#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal power-up */
+#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL power-down */
+
+/* power control defines */
+#define PLL_DELAY 150 /* us pll on delay */
+#define FREF_DELAY 200 /* us fref change delay */
+#define MIN_SLOW_CLK 32 /* us Slow clock period */
+#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/* Reference Board Types */
+#define BU4710_BOARD 0x0400
+#define VSIM4710_BOARD 0x0401
+#define QT4710_BOARD 0x0402
+
+#define BU4309_BOARD 0x040a
+#define BCM94309CB_BOARD 0x040b
+#define BCM94309MP_BOARD 0x040c
+#define BCM4309AP_BOARD 0x040d
+
+#define BCM94302MP_BOARD 0x040e
+
+#define BU4306_BOARD 0x0416
+#define BCM94306CB_BOARD 0x0417
+#define BCM94306MP_BOARD 0x0418
+
+#define BCM94710D_BOARD 0x041a
+#define BCM94710R1_BOARD 0x041b
+#define BCM94710R4_BOARD 0x041c
+#define BCM94710AP_BOARD 0x041d
+
+#define BU2050_BOARD 0x041f
+
+#define BCM94306P50_BOARD 0x0420
+
+#define BCM94309G_BOARD 0x0421
+
+#define BU4704_BOARD 0x0423
+#define BU4702_BOARD 0x0424
+
+#define BCM94306PC_BOARD 0x0425 /* pcmcia 3.3v 4306 card */
+
+#define MPSG4306_BOARD 0x0427
+
+#define BCM94702MN_BOARD 0x0428
+
+/* BCM4702 1U CompactPCI Board */
+#define BCM94702CPCI_BOARD 0x0429
+
+/* BCM4702 with BCM95380 VLAN Router */
+#define BCM95380RR_BOARD 0x042a
+
+/* cb4306 with SiGe PA */
+#define BCM94306CBSG_BOARD 0x042b
+
+/* cb4306 with SiGe PA */
+#define PCSG94306_BOARD 0x042d
+
+/* bu4704 with sdram */
+#define BU4704SD_BOARD 0x042e
+
+/* Dual 11a/11g Router */
+#define BCM94704AGR_BOARD 0x042f
+
+/* 11a-only minipci */
+#define BCM94308MP_BOARD 0x0430
+
+/* 4306/gprs combo */
+#define BCM94306GPRS_BOARD 0x0432
+
+/* BCM5365/BCM4704 FPGA Bringup Board */
+#define BU5365_FPGA_BOARD 0x0433
+
+#define BU4712_BOARD 0x0444
+#define BU4712SD_BOARD 0x045d
+#define BU4712L_BOARD 0x045f
+
+/* BCM4712 boards */
+#define BCM94712AP_BOARD 0x0445
+#define BCM94712P_BOARD 0x0446
+
+/* BCM4318 boards */
+#define BU4318_BOARD 0x0447
+#define CB4318_BOARD 0x0448
+#define MPG4318_BOARD 0x0449
+#define MP4318_BOARD 0x044a
+#define SD4318_BOARD 0x044b
+
+/* BCM4313 boards */
+#define BCM94313BU_BOARD 0x050f
+#define BCM94313HM_BOARD 0x0510
+#define BCM94313EPA_BOARD 0x0511
+#define BCM94313HMG_BOARD 0x051C
+
+/* BCM63XX boards */
+#define BCM96338_BOARD 0x6338
+#define BCM96348_BOARD 0x6348
+#define BCM96358_BOARD 0x6358
+#define BCM96368_BOARD 0x6368
+
+/* Another mp4306 with SiGe */
+#define BCM94306P_BOARD 0x044c
+
+/* mp4303 */
+#define BCM94303MP_BOARD 0x044e
+
+/* mpsgh4306 */
+#define BCM94306MPSGH_BOARD 0x044f
+
+/* BRCM 4306 w/ Front End Modules */
+#define BCM94306MPM 0x0450
+#define BCM94306MPL 0x0453
+
+/* 4712agr */
+#define BCM94712AGR_BOARD 0x0451
+
+/* pcmcia 4303 */
+#define PC4303_BOARD 0x0454
+
+/* 5350K */
+#define BCM95350K_BOARD 0x0455
+
+/* 5350R */
+#define BCM95350R_BOARD 0x0456
+
+/* 4306mplna */
+#define BCM94306MPLNA_BOARD 0x0457
+
+/* 4320 boards */
+#define BU4320_BOARD 0x0458
+#define BU4320S_BOARD 0x0459
+#define BCM94320PH_BOARD 0x045a
+
+/* 4306mph */
+#define BCM94306MPH_BOARD 0x045b
+
+/* 4306pciv */
+#define BCM94306PCIV_BOARD 0x045c
+
+#define BU4712SD_BOARD 0x045d
+
+#define BCM94320PFLSH_BOARD 0x045e
+
+#define BU4712L_BOARD 0x045f
+#define BCM94712LGR_BOARD 0x0460
+#define BCM94320R_BOARD 0x0461
+
+#define BU5352_BOARD 0x0462
+
+#define BCM94318MPGH_BOARD 0x0463
+
+#define BU4311_BOARD 0x0464
+#define BCM94311MC_BOARD 0x0465
+#define BCM94311MCAG_BOARD 0x0466
+
+#define BCM95352GR_BOARD 0x0467
+
+/* bcm95351agr */
+#define BCM95351AGR_BOARD 0x0470
+
+/* bcm94704mpcb */
+#define BCM94704MPCB_BOARD 0x0472
+
+/* 4785 boards */
+#define BU4785_BOARD 0x0478
+
+/* 4321 boards */
+#define BU4321_BOARD 0x046b
+#define BU4321E_BOARD 0x047c
+#define MP4321_BOARD 0x046c
+#define CB2_4321_BOARD 0x046d
+#define CB2_4321_AG_BOARD 0x0066
+#define MC4321_BOARD 0x046e
+
+/* 4328 boards */
+#define BU4328_BOARD 0x0481
+#define BCM4328SDG_BOARD 0x0482
+#define BCM4328SDAG_BOARD 0x0483
+#define BCM4328UG_BOARD 0x0484
+#define BCM4328UAG_BOARD 0x0485
+#define BCM4328PC_BOARD 0x0486
+#define BCM4328CF_BOARD 0x0487
+
+/* 4325 boards */
+#define BCM94325DEVBU_BOARD 0x0490
+#define BCM94325BGABU_BOARD 0x0491
+
+#define BCM94325SDGWB_BOARD 0x0492
+
+#define BCM94325SDGMDL_BOARD 0x04aa
+#define BCM94325SDGMDL2_BOARD 0x04c6
+#define BCM94325SDGMDL3_BOARD 0x04c9
+
+#define BCM94325SDABGWBA_BOARD 0x04e1
+
+#ifdef DEPRECATED
+/* 4322 boards */
+#define BCM94322MC_SSID 0x04a4
+#define BCM94322USB_SSID 0x04a8 /* dualband */
+#define BCM94322HM_SSID 0x04b0
+#define BCM94322USB2D_SSID 0x04bf /* single band discrete front end */
+
+/* 4312 boards */
+#define BCM4312MCGSG_BOARD 0x04b5
+
+/* 4315 boards */
+#define BCM94315DEVBU_SSID 0x04c2
+#define BCM94315USBGP_SSID 0x04c7
+#define BCM94315BGABU_SSID 0x04ca
+#define BCM94315USBGP41_SSID 0x04cb
+
+/* 4319 boards */
+#define BCM94319DEVBU_SSID 0X04e5
+#define BCM94319USB_SSID 0X04e6
+#define BCM94319SD_SSID 0X04e7
+
+/* 4716 boards */
+#define BCM94716NR2_SSID 0x04cd
+
+/* 4319 boards */
+#define BCM94319DEVBU_SSID 0X04e5
+#define BCM94319USBNP4L_SSID 0X04e6
+#define BCM94319WLUSBN4L_SSID 0X04e7
+#define BCM94319SDG_SSID 0X04ea
+#define BCM94319LCUSBSDN4L_SSID 0X04eb
+#define BCM94319USBB_SSID 0x04ee
+#define BCM94319LCSDN4L_SSID 0X0507
+#define BCM94319LSUSBN4L_SSID 0X0508
+#define BCM94319SDNA4L_SSID 0X0517
+#define BCM94319SDELNA4L_SSID 0X0518
+#define BCM94319SDELNA6L_SSID 0X0539
+#define BCM94319ARCADYAN_SSID 0X0546
+#define BCM94319WINDSOR_SSID 0x0561
+#define BCM94319MLAP_SSID 0x0562
+#define BCM94319SDNA_SSID 0x058b
+#define BCM94319BHEMU3_SSID 0x0563
+#define BCM94319SDHMB_SSID 0x058c
+#define BCM94319SDBREF_SSID 0x05a1
+#define BCM94319USBSDB_SSID 0x05a2
+
+
+/* 4329 boards */
+#define BCM94329AGB_SSID 0X04b9
+#define BCM94329TDKMDL1_SSID 0X04ba
+#define BCM94329TDKMDL11_SSID 0X04fc
+#define BCM94329OLYMPICN18_SSID 0X04fd
+#define BCM94329OLYMPICN90_SSID 0X04fe
+#define BCM94329OLYMPICN90U_SSID 0X050c
+#define BCM94329OLYMPICN90M_SSID 0X050b
+#define BCM94329AGBF_SSID 0X04ff
+#define BCM94329OLYMPICX17_SSID 0X0504
+#define BCM94329OLYMPICX17M_SSID 0X050a
+#define BCM94329OLYMPICX17U_SSID 0X0509
+#define BCM94329OLYMPICUNO_SSID 0X0564
+#define BCM94329MOTOROLA_SSID 0X0565
+#define BCM94329OLYMPICLOCO_SSID 0X0568
+#endif /* DEPRICATED */
+
+/* 4336 SDIO board types */
+#define BCM94336SD_WLBGABU_SSID 0x0511
+#define BCM94336SD_WLBGAREF_SSID 0x0519
+#define BCM94336SDGP_SSID 0x0538
+#define BCM94336SDG_SSID 0x0519
+#define BCM94336SDGN_SSID 0x0538
+#define BCM94336SDGFC_SSID 0x056B
+
+/* 4330 SDIO board types */
+#define BCM94330SDG_SSID 0x0528
+#define BCM94330SD_FCBGABU_SSID 0x052e
+#define BCM94330SD_WLBGABU_SSID 0x052f
+#define BCM94330SD_FCBGA_SSID 0x0530
+#define BCM94330FCSDAGB_SSID 0x0532
+#define BCM94330OLYMPICAMG_SSID 0x0549
+#define BCM94330OLYMPICAMGEPA_SSID 0x054F
+#define BCM94330OLYMPICUNO3_SSID 0x0551
+#define BCM94330WLSDAGB_SSID 0x0547
+#define BCM94330CSPSDAGBB_SSID 0x054A
+
+/* 43224 boards */
+#define BCM943224X21 0x056e
+#define BCM943224X21_FCC 0x00d1
+#define BCM943224X21B 0x00e9
+#define BCM943224M93 0x008b
+#define BCM943224M93A 0x0090
+#define BCM943224X16 0x0093
+#define BCM94322X9 0x008d
+#define BCM94322M35e 0x008e
+
+/* 43228 Boards */
+#define BCM943228BU8_SSID 0x0540
+#define BCM943228BU9_SSID 0x0541
+#define BCM943228BU_SSID 0x0542
+#define BCM943227HM4L_SSID 0x0543
+#define BCM943227HMB_SSID 0x0544
+#define BCM943228HM4L_SSID 0x0545
+#define BCM943228SD_SSID 0x0573
+
+/* 43239 Boards */
+#define BCM943239MOD_SSID 0x05ac
+#define BCM943239REF_SSID 0x05aa
+
+/* 4331 boards */
+#define BCM94331X19 0x00D6 /* X19B */
+#define BCM94331X28 0x00E4 /* X28 */
+#define BCM94331X28B 0x010E /* X28B */
+#define BCM94331PCIEBT3Ax_SSID BCM94331X28
+#define BCM94331X12_2G_SSID 0x00EC /* X12 2G */
+#define BCM94331X12_5G_SSID 0x00ED /* X12 5G */
+#define BCM94331X29B 0x00EF /* X29B */
+#define BCM94331X29D 0x010F /* X29D */
+#define BCM94331CSAX_SSID BCM94331X29B
+#define BCM94331X19C 0x00F5 /* X19C */
+#define BCM94331X33 0x00F4 /* X33 */
+#define BCM94331BU_SSID 0x0523
+#define BCM94331S9BU_SSID 0x0524
+#define BCM94331MC_SSID 0x0525
+#define BCM94331MCI_SSID 0x0526
+#define BCM94331PCIEBT4_SSID 0x0527
+#define BCM94331HM_SSID 0x0574
+#define BCM94331PCIEDUAL_SSID 0x059B
+#define BCM94331MCH5_SSID 0x05A9
+#define BCM94331CS_SSID 0x05C6
+#define BCM94331CD_SSID 0x05DA
+
+/* 4314 Boards */
+#define BCM94314BU_SSID 0x05b1
+
+/* 53572 Boards */
+#define BCM953572BU_SSID 0x058D
+#define BCM953572NR2_SSID 0x058E
+#define BCM947188NR2_SSID 0x058F
+#define BCM953572SDRNR2_SSID 0x0590
+
+/* 43236 boards */
+#define BCM943236OLYMPICSULLEY_SSID 0x594
+#define BCM943236PREPROTOBLU2O3_SSID 0x5b9
+#define BCM943236USBELNA_SSID 0x5f8
+
+/* 4314 Boards */
+#define BCM94314BUSDIO_SSID 0x05c8
+#define BCM94314BGABU_SSID 0x05c9
+#define BCM94314HMEPA_SSID 0x05ca
+#define BCM94314HMEPABK_SSID 0x05cb
+#define BCM94314SUHMEPA_SSID 0x05cc
+#define BCM94314SUHM_SSID 0x05cd
+#define BCM94314HM_SSID 0x05d1
+
+/* 4334 Boards */
+#define BCM94334FCAGBI_SSID 0x05df
+#define BCM94334WLAGBI_SSID 0x05dd
+
+/* 4335 Boards */
+#define BCM94335X52 0x0114
+
+/* 4345 Boards */
+#define BCM94345_SSID 0x0687
+
+/* 4360 Boards */
+#define BCM94360X52C 0X0117
+#define BCM94360X52D 0X0137
+#define BCM94360X29C 0X0112
+#define BCM94360X29CP2 0X0134
+#define BCM94360X29CP3 0X013B
+#define BCM94360X51 0x0111
+#define BCM94360X51P2 0x0129
+#define BCM94360X51P3 0x0142
+#define BCM94360X51A 0x0135
+#define BCM94360X51B 0x0136
+#define BCM94360CS 0x061B
+#define BCM94360J28_D11AC2G 0x0c00
+#define BCM94360J28_D11AC5G 0x0c01
+#define BCM94360USBH5_D11AC5G 0x06aa
+#define BCM94360MCM5 0x06d8
+
+/* 4350 Boards */
+#define BCM94350X52B 0X0116
+#define BCM94350X14 0X0131
+#define BCM94350X14P2 0X0158
+#define BCM94350X14P3 0X0159
+
+/* 43217 Boards */
+#define BCM943217BU_SSID 0x05d5
+#define BCM943217HM2L_SSID 0x05d6
+#define BCM943217HMITR2L_SSID 0x05d7
+
+/* 43142 Boards */
+#define BCM943142HM_SSID 0x05e0
+
+/* 4357 Boards */
+#define BCM94361SSMOD_TYPE8_ALLEPA 0x080f
+#define BCM94361FCPAGBSS 0x0817
+#define BCM94361WLPAGBI 0x081a
+#define BCM94357FCPAGBE 0x07ec
+#define BCM94361FCPAGBI 0x07eb
+
+/* 4364 Boards */
+#define BCM94364FCPAGB 0x07A2
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
+/* 43341 Boards */
+#define BCM943341WLABGS_SSID 0x062d
+
+/* 43342 Boards */
+#define BCM943342FCAGBI_SSID 0x0641
+
+/* 43012 wlbga Board */
+#define BCM943012WLREF_SSID 0x07d7
+
+/* 43012 fcbga Board */
+#define BCM943012FCREF_SSID 0x07d4
+
+/* 43602 Boards, unclear yet what boards will be created. */
+#define BCM943602RSVD1_SSID 0x06a5
+#define BCM943602RSVD2_SSID 0x06a6
+#define BCM943602X87 0X0133
+#define BCM943602X87P2 0X0152
+#define BCM943602X87P3 0X0153
+#define BCM943602X238 0X0132
+#define BCM943602X238D 0X014A
+#define BCM943602X238DP2 0X0155
+#define BCM943602X238DP3 0X0156
+#define BCM943602X100 0x0761
+#define BCM943602X100GS 0x0157
+#define BCM943602X100P2 0x015A
+
+/* # of GPIO pins */
+#define GPIO_NUMPINS 32
+
+/* These values are used by dhd host driver. */
+#define RDL_RAM_BASE_4319 0x60000000
+#define RDL_RAM_BASE_4329 0x60000000
+#define RDL_RAM_SIZE_4319 0x48000
+#define RDL_RAM_SIZE_4329 0x48000
+#define RDL_RAM_SIZE_43236 0x70000
+#define RDL_RAM_BASE_43236 0x60000000
+#define RDL_RAM_SIZE_4328 0x60000
+#define RDL_RAM_BASE_4328 0x80000000
+#define RDL_RAM_SIZE_4322 0x60000
+#define RDL_RAM_BASE_4322 0x60000000
+#define RDL_RAM_SIZE_4360 0xA0000
+#define RDL_RAM_BASE_4360 0x60000000
+#define RDL_RAM_SIZE_43242 0x90000
+#define RDL_RAM_BASE_43242 0x60000000
+#define RDL_RAM_SIZE_43143 0x70000
+#define RDL_RAM_BASE_43143 0x60000000
+#define RDL_RAM_SIZE_4350 0xC0000
+#define RDL_RAM_BASE_4350 0x180800
+
+/* generic defs for nvram "muxenab" bits
+* Note: these differ for 4335a0. refer bcmchipc.h for specific mux options.
+*/
+#define MUXENAB_UART 0x00000001
+#define MUXENAB_GPIO 0x00000002
+#define MUXENAB_ERCX 0x00000004 /* External Radio BT coex */
+#define MUXENAB_JTAG 0x00000008
+#define MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */
+#define MUXENAB_I2S_EN 0x00000020
+#define MUXENAB_I2S_MASTER 0x00000040
+#define MUXENAB_I2S_FULL 0x00000080
+#define MUXENAB_SFLASH 0x00000100
+#define MUXENAB_RFSWCTRL0 0x00000200
+#define MUXENAB_RFSWCTRL1 0x00000400
+#define MUXENAB_RFSWCTRL2 0x00000800
+#define MUXENAB_SECI 0x00001000
+#define MUXENAB_BT_LEGACY 0x00002000
+#define MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */
+
+/* Boot flags */
+#define FLASH_KERNEL_NFLASH 0x00000001
+#define FLASH_BOOT_NFLASH 0x00000002
+
+#endif /* _BCMDEVS_H */
diff --git a/wl/src/include/bcmendian.h b/wl/src/include/bcmendian.h
new file mode 100644
index 0000000..40678e8
--- /dev/null
+++ b/wl/src/include/bcmendian.h
@@ -0,0 +1,450 @@
+/*
+ * Byte order utilities
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmendian.h 633810 2016-04-25 16:46:55Z $
+ *
+ * This file by default provides proper behavior on little-endian architectures.
+ * On big-endian architectures, IL_BIGENDIAN should be defined.
+ */
+
+#ifndef _BCMENDIAN_H_
+#define _BCMENDIAN_H_
+
+#include <typedefs.h>
+
+/* Reverse the bytes in a 16-bit value */
+#define BCMSWAP16(val) \
+ ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \
+ (((uint16)(val) & (uint16)0xff00U) >> 8)))
+
+/* Reverse the bytes in a 32-bit value */
+#define BCMSWAP32(val) \
+ ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \
+ (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \
+ (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \
+ (((uint32)(val) & (uint32)0xff000000U) >> 24)))
+
+/* Reverse the two 16-bit halves of a 32-bit value */
+#define BCMSWAP32BY16(val) \
+ ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \
+ (((uint32)(val) & (uint32)0xffff0000U) >> 16)))
+
+/* Reverse the bytes in a 64-bit value */
+#define BCMSWAP64(val) \
+ ((uint64)((((uint64)(val) & 0x00000000000000ffULL) << 56) | \
+ (((uint64)(val) & 0x000000000000ff00ULL) << 40) | \
+ (((uint64)(val) & 0x0000000000ff0000ULL) << 24) | \
+ (((uint64)(val) & 0x00000000ff000000ULL) << 8) | \
+ (((uint64)(val) & 0x000000ff00000000ULL) >> 8) | \
+ (((uint64)(val) & 0x0000ff0000000000ULL) >> 24) | \
+ (((uint64)(val) & 0x00ff000000000000ULL) >> 40) | \
+ (((uint64)(val) & 0xff00000000000000ULL) >> 56)))
+
+/* Reverse the two 32-bit halves of a 64-bit value */
+#define BCMSWAP64BY32(val) \
+ ((uint64)((((uint64)(val) & 0x00000000ffffffffULL) << 32) | \
+ (((uint64)(val) & 0xffffffff00000000ULL) >> 32)))
+
+
+/* Byte swapping macros
+ * Host <=> Network (Big Endian) for 16- and 32-bit values
+ * Host <=> Little-Endian for 16- and 32-bit values
+ */
+#ifndef hton16
+#ifndef IL_BIGENDIAN
+#define HTON16(i) BCMSWAP16(i)
+#define hton16(i) bcmswap16(i)
+#define HTON32(i) BCMSWAP32(i)
+#define hton32(i) bcmswap32(i)
+#define NTOH16(i) BCMSWAP16(i)
+#define ntoh16(i) bcmswap16(i)
+#define NTOH32(i) BCMSWAP32(i)
+#define ntoh32(i) bcmswap32(i)
+#define LTOH16(i) (i)
+#define ltoh16(i) (i)
+#define LTOH32(i) (i)
+#define ltoh32(i) (i)
+#define HTOL16(i) (i)
+#define htol16(i) (i)
+#define HTOL32(i) (i)
+#define htol32(i) (i)
+#define HTOL64(i) (i)
+#define htol64(i) (i)
+#else /* IL_BIGENDIAN */
+#define HTON16(i) (i)
+#define hton16(i) (i)
+#define HTON32(i) (i)
+#define hton32(i) (i)
+#define NTOH16(i) (i)
+#define ntoh16(i) (i)
+#define NTOH32(i) (i)
+#define ntoh32(i) (i)
+#define LTOH16(i) BCMSWAP16(i)
+#define ltoh16(i) bcmswap16(i)
+#define LTOH32(i) BCMSWAP32(i)
+#define ltoh32(i) bcmswap32(i)
+#define HTOL16(i) BCMSWAP16(i)
+#define htol16(i) bcmswap16(i)
+#define HTOL32(i) BCMSWAP32(i)
+#define htol32(i) bcmswap32(i)
+#define HTOL64(i) BCMSWAP64(i)
+#define htol64(i) bcmswap64(i)
+#endif /* IL_BIGENDIAN */
+#endif /* hton16 */
+
+#ifndef IL_BIGENDIAN
+#define ltoh16_buf(buf, i)
+#define htol16_buf(buf, i)
+#define ltoh32_buf(buf, i)
+#define htol32_buf(buf, i)
+#define ltoh64_buf(buf, i)
+#define htol64_buf(buf, i)
+#else
+#define ltoh16_buf(buf, i) bcmswap16_buf((uint16 *)(buf), (i))
+#define htol16_buf(buf, i) bcmswap16_buf((uint16 *)(buf), (i))
+#define ltoh32_buf(buf, i) bcmswap32_buf((uint16 *)(buf), (i))
+#define htol32_buf(buf, i) bcmswap32_buf((uint16 *)(buf), (i))
+#define ltoh64_buf(buf, i) bcmswap64_buf((uint16 *)(buf), (i))
+#define htol64_buf(buf, i) bcmswap64_buf((uint16 *)(buf), (i))
+#endif /* IL_BIGENDIAN */
+
+/* Unaligned loads and stores in host byte order */
+#ifndef IL_BIGENDIAN
+#define load32_ua(a) ltoh32_ua(a)
+#define store32_ua(a, v) htol32_ua_store(v, a)
+#define load16_ua(a) ltoh16_ua(a)
+#define store16_ua(a, v) htol16_ua_store(v, a)
+#define load64_ua(a) ltoh64_ua(a)
+#define store64_ua(a, v) htol64_ua_store(v, a)
+#else
+#define load32_ua(a) ntoh32_ua(a)
+#define store32_ua(a, v) hton32_ua_store(v, a)
+#define load16_ua(a) ntoh16_ua(a)
+#define store16_ua(a, v) hton16_ua_store(v, a)
+#define load64_ua(a) ntoh64_ua(a)
+#define store64_ua(a, v) hton64_ua_store(v, a)
+#endif /* IL_BIGENDIAN */
+
+#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8))
+#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24))
+#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1])
+#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3])
+
+#define _LTOH64_UA(cp) ((uint64)(cp)[0] | ((uint64)(cp)[1] << 8) | \
+ ((uint64)(cp)[2] << 16) | ((uint64)(cp)[3] << 24) | \
+ ((uint64)(cp)[4] << 32) | ((uint64)(cp)[5] << 40) | \
+ ((uint64)(cp)[6] << 48) | ((uint64)(cp)[7] << 56))
+
+#define _NTOH64_UA(cp) ((uint64)(cp)[7] | ((uint64)(cp)[6] << 8) | \
+ ((uint64)(cp)[5] << 16) | ((uint64)(cp)[4] << 24) | \
+ ((uint64)(cp)[3] << 32) | ((uint64)(cp)[2] << 40) | \
+ ((uint64)(cp)[1] << 48) | ((uint64)(cp)[0] << 56))
+
+#define ltoh_ua(ptr) \
+ (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \
+ sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \
+ sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \
+ *(uint8 *)0)
+
+#define ntoh_ua(ptr) \
+ (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \
+ sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \
+ sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \
+ *(uint8 *)0)
+
+#ifdef __GNUC__
+
+/* GNU macro versions avoid referencing the argument multiple times, while also
+ * avoiding the -fno-inline used in ROM builds.
+ */
+
+#define bcmswap16(val) ({ \
+ uint16 _val = (val); \
+ BCMSWAP16(_val); \
+})
+
+#define bcmswap32(val) ({ \
+ uint32 _val = (val); \
+ BCMSWAP32(_val); \
+})
+
+#define bcmswap64(val) ({ \
+ uint64 _val = (val); \
+ BCMSWAP64(_val); \
+})
+
+#define bcmswap32by16(val) ({ \
+ uint32 _val = (val); \
+ BCMSWAP32BY16(_val); \
+})
+
+#define bcmswap16_buf(buf, len) ({ \
+ uint16 *_buf = (uint16 *)(buf); \
+ uint _wds = (len) / 2; \
+ while (_wds--) { \
+ *_buf = bcmswap16(*_buf); \
+ _buf++; \
+ } \
+})
+
+#define bcmswap32_buf(buf, len) ({ \
+ uint32 *_buf = (uint32 *)(buf); \
+ uint _wds = (len) / 4; \
+ while (_wds--) { \
+ *_buf = bcmswap32(*_buf); \
+ _buf++; \
+ } \
+})
+
+#define bcmswap64_buf(buf, len) ({ \
+ uint64 *_buf = (uint64 *)(buf); \
+ uint _wds = (len) / 8; \
+ while (_wds--) { \
+ *_buf = bcmswap64(*_buf); \
+ _buf++; \
+ } \
+})
+
+#define htol16_ua_store(val, bytes) ({ \
+ uint16 _val = (val); \
+ uint8 *_bytes = (uint8 *)(bytes); \
+ _bytes[0] = _val & 0xff; \
+ _bytes[1] = _val >> 8; \
+})
+
+#define htol32_ua_store(val, bytes) ({ \
+ uint32 _val = (val); \
+ uint8 *_bytes = (uint8 *)(bytes); \
+ _bytes[0] = _val & 0xff; \
+ _bytes[1] = (_val >> 8) & 0xff; \
+ _bytes[2] = (_val >> 16) & 0xff; \
+ _bytes[3] = _val >> 24; \
+})
+
+#define htol64_ua_store(val, bytes) ({ \
+ uint64 _val = (val); \
+ uint8 *_bytes = (uint8 *)(bytes); \
+ int i; \
+ for (i = 0; i < (int)sizeof(_val); ++i) { \
+ *_bytes++ = _val & 0xff; \
+ _val >>= 8; \
+ } \
+})
+
+#define hton16_ua_store(val, bytes) ({ \
+ uint16 _val = (val); \
+ uint8 *_bytes = (uint8 *)(bytes); \
+ _bytes[0] = _val >> 8; \
+ _bytes[1] = _val & 0xff; \
+})
+
+#define hton32_ua_store(val, bytes) ({ \
+ uint32 _val = (val); \
+ uint8 *_bytes = (uint8 *)(bytes); \
+ _bytes[0] = _val >> 24; \
+ _bytes[1] = (_val >> 16) & 0xff; \
+ _bytes[2] = (_val >> 8) & 0xff; \
+ _bytes[3] = _val & 0xff; \
+})
+
+#define ltoh16_ua(bytes) ({ \
+ const uint8 *_bytes = (const uint8 *)(bytes); \
+ _LTOH16_UA(_bytes); \
+})
+
+#define ltoh32_ua(bytes) ({ \
+ const uint8 *_bytes = (const uint8 *)(bytes); \
+ _LTOH32_UA(_bytes); \
+})
+
+#define ltoh64_ua(bytes) ({ \
+ const uint8 *_bytes = (const uint8 *)(bytes); \
+ _LTOH64_UA(_bytes); \
+})
+
+#define ntoh16_ua(bytes) ({ \
+ const uint8 *_bytes = (const uint8 *)(bytes); \
+ _NTOH16_UA(_bytes); \
+})
+
+#define ntoh32_ua(bytes) ({ \
+ const uint8 *_bytes = (const uint8 *)(bytes); \
+ _NTOH32_UA(_bytes); \
+})
+
+#define ntoh64_ua(bytes) ({ \
+ const uint8 *_bytes = (const uint8 *)(bytes); \
+ _NTOH64_UA(_bytes); \
+})
+
+#else /* !__GNUC__ */
+
+/* Inline versions avoid referencing the argument multiple times */
+static INLINE uint16
+bcmswap16(uint16 val)
+{
+ return BCMSWAP16(val);
+}
+
+static INLINE uint32
+bcmswap32(uint32 val)
+{
+ return BCMSWAP32(val);
+}
+
+static INLINE uint64
+bcmswap64(uint64 val)
+{
+ return BCMSWAP64(val);
+}
+
+static INLINE uint32
+bcmswap32by16(uint32 val)
+{
+ return BCMSWAP32BY16(val);
+}
+
+/* Reverse pairs of bytes in a buffer (not for high-performance use) */
+/* buf - start of buffer of shorts to swap */
+/* len - byte length of buffer */
+static INLINE void
+bcmswap16_buf(uint16 *buf, uint len)
+{
+ len = len / 2;
+
+ while (len--) {
+ *buf = bcmswap16(*buf);
+ buf++;
+ }
+}
+
+/*
+ * Store 16-bit value to unaligned little-endian byte array.
+ */
+static INLINE void
+htol16_ua_store(uint16 val, uint8 *bytes)
+{
+ bytes[0] = val & 0xff;
+ bytes[1] = val >> 8;
+}
+
+/*
+ * Store 32-bit value to unaligned little-endian byte array.
+ */
+static INLINE void
+htol32_ua_store(uint32 val, uint8 *bytes)
+{
+ bytes[0] = val & 0xff;
+ bytes[1] = (val >> 8) & 0xff;
+ bytes[2] = (val >> 16) & 0xff;
+ bytes[3] = val >> 24;
+}
+
+/*
+ * Store 64-bit value to unaligned little-endian byte array.
+ */
+static INLINE void
+htol64_ua_store(uint64 val, uint8 *bytes)
+{
+ int i;
+ for (i = 0; i < sizeof(val); ++i) {
+ *bytes++ = (uint8)(val & 0xff);
+ val >>= 8;
+ }
+}
+
+/*
+ * Store 16-bit value to unaligned network-(big-)endian byte array.
+ */
+static INLINE void
+hton16_ua_store(uint16 val, uint8 *bytes)
+{
+ bytes[0] = val >> 8;
+ bytes[1] = val & 0xff;
+}
+
+/*
+ * Store 32-bit value to unaligned network-(big-)endian byte array.
+ */
+static INLINE void
+hton32_ua_store(uint32 val, uint8 *bytes)
+{
+ bytes[0] = val >> 24;
+ bytes[1] = (val >> 16) & 0xff;
+ bytes[2] = (val >> 8) & 0xff;
+ bytes[3] = val & 0xff;
+}
+
+/*
+ * Load 16-bit value from unaligned little-endian byte array.
+ */
+static INLINE uint16
+ltoh16_ua(const void *bytes)
+{
+ return _LTOH16_UA((const uint8 *)bytes);
+}
+
+/*
+ * Load 32-bit value from unaligned little-endian byte array.
+ */
+static INLINE uint32
+ltoh32_ua(const void *bytes)
+{
+ return _LTOH32_UA((const uint8 *)bytes);
+}
+
+/*
+ * Load 64-bit value from unaligned little-endian byte array.
+ */
+static INLINE uint64
+ltoh64_ua(const void *bytes)
+{
+ return _LTOH64_UA((const uint8 *)bytes);
+}
+
+/*
+ * Load 16-bit value from unaligned big-(network-)endian byte array.
+ */
+static INLINE uint16
+ntoh16_ua(const void *bytes)
+{
+ return _NTOH16_UA((const uint8 *)bytes);
+}
+
+/*
+ * Load 32-bit value from unaligned big-(network-)endian byte array.
+ */
+static INLINE uint32
+ntoh32_ua(const void *bytes)
+{
+ return _NTOH32_UA((const uint8 *)bytes);
+}
+
+/*
+ * Load 64-bit value from unaligned big-(network-)endian byte array.
+ */
+static INLINE uint64
+ntoh64_ua(const void *bytes)
+{
+ return _NTOH64_UA((const uint8 *)bytes);
+}
+
+#endif /* !__GNUC__ */
+#endif /* !_BCMENDIAN_H_ */
diff --git a/wl/src/include/bcmiov.h b/wl/src/include/bcmiov.h
new file mode 100644
index 0000000..b6e77d5
--- /dev/null
+++ b/wl/src/include/bcmiov.h
@@ -0,0 +1,350 @@
+/*
+ * bcmiov.h
+ * Common iovar handling/parsing support - batching, parsing, sub-cmd dispatch etc.
+ * To be used in firmware and host apps or dhd - reducing code size,
+ * duplication, and maintenance overhead.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id$
+ */
+
+
+#ifndef _bcmiov_h_
+#define _bcmiov_h_
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <wlioctl.h>
+#ifdef BCMDRIVER
+#include <osl.h>
+#else
+#include <stddef.h> /* For size_t */
+#endif /* BCMDRIVER */
+
+/* Forward declarations */
+typedef uint16 bcm_iov_cmd_id_t;
+typedef uint16 bcm_iov_cmd_flags_t;
+typedef uint16 bcm_iov_cmd_iovf_t;
+typedef struct bcm_iov_cmd_info bcm_iov_cmd_info_t;
+typedef struct bcm_iov_cmd_digest bcm_iov_cmd_digest_t;
+typedef struct bcm_iov_cmd_tlv_info bcm_iov_cmd_tlv_info_t;
+typedef struct bcm_iov_buf bcm_iov_buf_t;
+typedef struct bcm_iov_batch_buf bcm_iov_batch_buf_t;
+typedef struct bcm_iov_parse_context bcm_iov_parse_context_t;
+typedef struct bcm_iov_sub_cmd_context bcm_iov_sub_cmd_context_t;
+
+typedef void* (*bcm_iov_malloc_t)(void* alloc_ctx, size_t len);
+typedef void (*bcm_iov_free_t)(void* alloc_ctx, void *buf, size_t len);
+
+typedef uint8 bcm_iov_tlp_data_type_t;
+typedef struct bcm_iov_tlp bcm_iov_tlp_t;
+typedef struct bcm_iov_tlp_node bcm_iov_tlp_node_t;
+typedef struct bcm_iov_batch_subcmd bcm_iov_batch_subcmd_t;
+
+/*
+ * iov validation handler - All the common checks that are required
+ * for processing of iovars for any given command.
+ */
+typedef int (*bcm_iov_cmd_validate_t)(const bcm_iov_cmd_digest_t *dig,
+ uint32 actionid, const uint8* ibuf, size_t ilen, uint8 *obuf, size_t *olen);
+
+/* iov get handler - process subcommand specific input and return output.
+ * input and output may overlap, so the callee needs to check if
+ * that is supported. For xtlv data a tlv digest is provided to make
+ * parsing simpler. Output tlvs may be packed into output buffer using
+ * bcm xtlv support. olen is input/output parameter. On input contains
+ * max available obuf length and callee must fill the correct length
+ * to represent the length of output returned.
+ */
+typedef int (*bcm_iov_cmd_get_t)(const bcm_iov_cmd_digest_t *dig,
+ const uint8* ibuf, size_t ilen, uint8 *obuf, size_t *olen);
+
+/* iov set handler - process subcommand specific input and return output
+ * input and output may overlap, so the callee needs to check if
+ * that is supported. olen is input/output parameter. On input contains
+ * max available obuf length and callee must fill the correct length
+ * to represent the length of output returned.
+ */
+typedef int (*bcm_iov_cmd_set_t)(const bcm_iov_cmd_digest_t *dig,
+ const uint8* ibuf, size_t ilen, uint8 *obuf, size_t *olen);
+
+/* iov (sub-cmd) batch - a vector of commands. count can be zero
+ * to support a version query. Each command is a tlv - whose data
+ * portion may have an optional return status, followed by a fixed
+ * length data header, optionally followed by tlvs.
+ * cmd = type|length|<status|options>[header][tlvs]
+ */
+
+/*
+ * Batch sub-commands have status length included in the
+ * response length packed in TLV.
+ */
+#define BCM_IOV_STATUS_LEN sizeof(uint32)
+
+/* batch version is indicated by setting high bit. */
+#define BCM_IOV_BATCH_MASK 0x8000
+
+/*
+ * Batched commands will have the following memory layout
+ * +--------+---------+-----+-------+
+ * |version |count | pad |sub-cmd|
+ * +--------+---------+-----+-------+
+ * version >= 0x8000
+ * count = number of sub-commands encoded in the iov buf
+ * sub-cmd one or more sub-commands for processing
+ * Where sub-cmd is padded byte buffer with memory layout as follows
+ * +--------+---------+-----------------------+-------------+------
+ * |cmd-id |length |IN(options) OUT(status)|command data |......
+ * +--------+---------+-----------------------+-------------+------
+ * cmd-id =sub-command ID
+ * length = length of this sub-command
+ * IN(options) = On input processing options/flags for this command
+ * OUT(status) on output processing status for this command
+ * command data = encapsulated IOVAR data as a single structure or packed TLVs for each
+ * individual sub-command.
+ */
+struct bcm_iov_batch_buf {
+ uint16 version;
+ uint8 count;
+ uint8 pad; /* Align sub-commands on 32 bit boundary */
+ bcm_xtlv_t cmds[1];
+};
+
+/* non-batched command version = major|minor w/ major <= 127 */
+struct bcm_iov_buf {
+ uint16 version;
+ uint16 len;
+ bcm_iov_cmd_id_t id;
+ uint16 data[1]; /* 32 bit alignment may be repurposed by the command */
+ /* command specific data follows */
+};
+
+struct bcm_iov_batch_subcmd {
+ uint16 id;
+ uint16 len;
+ union {
+ uint32 options;
+ uint32 status;
+ } u;
+ uint8 data[1];
+};
+
+/* iov options flags */
+enum {
+ BCM_IOV_CMD_OPT_ALIGN_NONE = 0x0000,
+ BCM_IOV_CMD_OPT_ALIGN32 = 0x0001,
+ BCM_IOV_CMD_OPT_TERMINATE_SUB_CMDS = 0x0002
+};
+
+/* iov command flags */
+enum {
+ BCM_IOV_CMD_FLAG_NONE = 0,
+ BCM_IOV_CMD_FLAG_STATUS_PRESENT = (1 << 0), /* status present at data start - output only */
+ BCM_IOV_CMD_FLAG_XTLV_DATA = (1 << 1), /* data is a set of xtlvs */
+ BCM_IOV_CMD_FLAG_HDR_IN_LEN = (1 << 2), /* length starts at version - non-bacthed only */
+ BCM_IOV_CMD_FLAG_NOPAD = (1 << 3) /* No padding needed after iov_buf */
+};
+
+/* information about the command, xtlv options and xtlvs_off are meaningful
+ * only if XTLV_DATA cmd flag is selected
+ */
+struct bcm_iov_cmd_info {
+ bcm_iov_cmd_id_t cmd; /* the (sub)command - module specific */
+ bcm_iov_cmd_flags_t flags;
+ bcm_iov_cmd_iovf_t iovf; /* IOV flags - same as for normal iovars */
+ bcm_xtlv_opts_t xtlv_opts;
+ bcm_iov_cmd_validate_t validate_h; /* command validation handler */
+ bcm_iov_cmd_get_t get_h;
+ bcm_iov_cmd_set_t set_h;
+ uint16 xtlvs_off; /* offset to beginning of xtlvs in cmd data */
+ uint16 min_len_set;
+ uint16 max_len_set;
+ uint16 min_len_get;
+ uint16 max_len_get;
+};
+
+/* tlv digest to support parsing of xtlvs for commands w/ tlv data; the tlv
+ * digest is available in the handler for the command. The count and order in
+ * which tlvs appear in the digest are exactly the same as the order of tlvs
+ * passed in the registration for the command. Unknown tlvs are ignored.
+ * If registered tlvs are missing datap will be NULL. common iov rocessing
+ * acquires an input digest to process input buffer. The handler is responsible
+ * for constructing an output digest and use packing functions to generate
+ * the output buffer. The handler may use the input digest as output digest once
+ * the tlv data is extracted and used. Multiple tlv support involves allocation of
+ * tlp nodes, except the first, as required,
+ */
+
+/* tlp data type indicates if the data is not used/invalid, input or output */
+enum {
+ BCM_IOV_TLP_NODE_INVALID = 0,
+ BCM_IOV_TLP_NODE_IN = 1,
+ BCM_IOV_TLP_NODE_OUT = 2
+};
+
+struct bcm_iov_tlp {
+ uint16 type;
+ uint16 len;
+ uint16 nodeix; /* node index */
+};
+
+/* tlp data for a given tlv - multiple tlvs of same type chained */
+struct bcm_iov_tlp_node {
+ uint8 *next; /* multiple tlv support */
+ bcm_iov_tlp_data_type_t type;
+ uint8 *data; /* pointer to data in buffer or state */
+};
+
+struct bcm_iov_cmd_digest {
+ uint32 version; /* Version */
+ void *cmd_ctx;
+ struct wlc_bsscfg *bsscfg;
+ const bcm_iov_cmd_info_t *cmd_info;
+ uint16 max_tlps; /* number of tlps allocated */
+ uint16 max_nodes; /* number of nods allocated */
+ uint16 num_tlps; /* number of tlps valid */
+ uint16 num_nodes; /* number of nods valid */
+ uint16 tlps_off; /* offset to tlps */
+ uint16 nodes_off; /* offset to nodes */
+ /*
+ * bcm_iov_tlp_t tlps[max_tlps];
+ * bcm_iov_tlp_node_t nodes[max_nodes]
+ */
+};
+
+/* get length callback - default length is min_len taken from digest */
+typedef size_t (*bcm_iov_xtlv_get_len_t)(const bcm_iov_cmd_digest_t *dig,
+ const bcm_iov_cmd_tlv_info_t *tlv_info);
+
+/* pack to buffer data callback. under some conditions it might
+ * not be a straight copy and can refer to context(ual) information and
+ * endian conversions...
+ */
+typedef void (*bcm_iov_xtlv_pack_t)(const bcm_iov_cmd_digest_t *dig,
+ const bcm_iov_cmd_tlv_info_t *tlv_info,
+ uint8 *out_buf, const uint8 *in_data, size_t len);
+
+struct bcm_iov_cmd_tlv_info {
+ uint16 id;
+ uint16 min_len; /* inclusive */
+ uint16 max_len; /* inclusive */
+ bcm_iov_xtlv_get_len_t get_len;
+ bcm_iov_xtlv_pack_t pack;
+};
+
+/*
+ * module private parse context. Default version type len is uint16
+ */
+enum {
+ BCM_IOV_PARSE_CMD_NONE = 0
+};
+typedef uint32 parse_context_opts_t;
+
+/* get digest callback */
+typedef int (*bcm_iov_get_digest_t)(void *cmd_ctx, bcm_iov_cmd_digest_t **dig);
+
+typedef struct bcm_iov_parse_config {
+ parse_context_opts_t options; /* to handle different ver lengths */
+ bcm_iov_malloc_t alloc_fn;
+ bcm_iov_free_t free_fn;
+ bcm_iov_get_digest_t dig_fn;
+ int max_regs;
+ void *alloc_ctx;
+} bcm_iov_parse_config_t;
+
+/* API */
+
+/* All calls return an integer status code BCME_* unless otherwise indicated */
+
+/* return length of allocation for 'num_cmds' commands. data_len
+ * includes length of data for all the commands excluding the headers
+ */
+size_t bcm_iov_get_alloc_len(int num_cmds, size_t data_len);
+
+/* create parsing context using allocator provided; max_regs provides
+ * the number of allowed registrations for commands using the context
+ * sub-components of a module may register their own commands indepdently
+ * using the parsing context. If digest callback is NULL or returns NULL,
+ * the (input) digest is allocated using the provided allocators and released on
+ * completion of processing.
+ */
+int bcm_iov_create_parse_context(const bcm_iov_parse_config_t *parse_cfg,
+ bcm_iov_parse_context_t **parse_ctx);
+
+/* free the parsing context; ctx is set to NULL on exit */
+int bcm_iov_free_parse_context(bcm_iov_parse_context_t **ctx, bcm_iov_free_t free_fn);
+
+/* Return the command context for the module */
+void *bcm_iov_get_cmd_ctx_info(bcm_iov_parse_context_t *parse_ctx);
+
+/* register a command info vector along with supported tlvs. Each command
+ * may support a subset of tlvs
+ */
+int bcm_iov_register_commands(bcm_iov_parse_context_t *parse_ctx, void *cmd_ctx,
+ const bcm_iov_cmd_info_t *info, size_t num_cmds,
+ const bcm_iov_cmd_tlv_info_t *tlv_info, size_t num_tlvs);
+
+/* pack the xtlvs provided in the digest. may returns BCME_BUFTOOSHORT, but the
+ * out_len is set to required length in that case.
+ */
+int bcm_iov_pack_xtlvs(const bcm_iov_cmd_digest_t *dig, bcm_xtlv_opts_t xtlv_opts,
+ uint8 *out_buf, size_t out_size, size_t *out_len);
+
+#ifdef BCMDRIVER
+/* wlc modules register their iovar(s) using the parsing context w/ wlc layer
+ * during attach.
+ */
+struct wlc_if;
+struct wlc_info;
+extern struct wlc_bsscfg *bcm_iov_bsscfg_find_from_wlcif(struct wlc_info *wlc,
+ struct wlc_if *wlcif);
+int bcm_iov_doiovar(void *parse_ctx, uint32 id, void *params, uint params_len,
+ void *arg, uint arg_len, uint vsize, struct wlc_if *intf);
+#endif /* BCMDRIVER */
+
+/* parsing context helpers */
+
+/* get the maximum number of tlvs - can be used to allocate digest for all
+ * commands. the digest can be shared. Negative values are BCM_*, >=0, the
+ * number of tlvs
+ */
+int bcm_iov_parse_get_max_tlvs(const bcm_iov_parse_context_t *ctx);
+
+/* common packing support */
+
+/* pack a buffer of uint8s - memcpy wrapper */
+int bcm_iov_pack_buf(const bcm_iov_cmd_digest_t *dig, uint8 *buf,
+ const uint8 *data, size_t len);
+
+#define bcm_iov_packv_u8 bcm_iov_pack_buf
+
+/*
+ * pack a buffer with uint16s - serialized in LE order, data points to uint16
+ * length is not checked.
+ */
+int bcm_iov_packv_u16(const bcm_iov_cmd_digest_t *dig, uint8 *buf,
+ const uint16 *data, int n);
+
+/*
+ * pack a buffer with uint32s - serialized in LE order - data points to uint32
+ * length is not checked.
+ */
+int bcm_iov_packv_u32(const bcm_iov_cmd_digest_t *dig, uint8 *buf,
+ const uint32 *data, int n);
+
+#endif /* _bcmiov_h_ */
diff --git a/wl/src/include/bcmnvram.h b/wl/src/include/bcmnvram.h
new file mode 100644
index 0000000..b6d0101
--- /dev/null
+++ b/wl/src/include/bcmnvram.h
@@ -0,0 +1,329 @@
+/*
+ * NVRAM variable manipulation
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmnvram.h 655606 2016-08-22 17:16:11Z $
+ */
+
+#ifndef _bcmnvram_h_
+#define _bcmnvram_h_
+
+#ifndef _LANGUAGE_ASSEMBLY
+
+#include <typedefs.h>
+#include <bcmdefs.h>
+
+struct nvram_header {
+ uint32 magic;
+ uint32 len;
+ uint32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+ uint32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */
+ uint32 config_ncdl; /* ncdl values for memc */
+};
+
+struct nvram_tuple {
+ char *name;
+ char *value;
+ struct nvram_tuple *next;
+};
+
+/*
+ * Get default value for an NVRAM variable
+ */
+extern char *nvram_default_get(const char *name);
+/*
+ * validate/restore all per-interface related variables
+ */
+extern void nvram_validate_all(char *prefix, bool restore);
+
+/*
+ * restore specific per-interface variable
+ */
+extern void nvram_restore_var(char *prefix, char *name);
+
+/*
+ * Initialize NVRAM access. May be unnecessary or undefined on certain
+ * platforms.
+ */
+extern int nvram_init(void *sih);
+extern int nvram_deinit(void *sih);
+
+
+extern int nvram_file_read(char **nvramp, int *nvraml);
+
+/*
+ * Append a chunk of nvram variables to the global list
+ */
+extern int nvram_append(void *si, char *vars, uint varsz);
+
+extern void nvram_get_global_vars(char **varlst, uint *varsz);
+
+
+/*
+ * Check for reset button press for restoring factory defaults.
+ */
+extern int nvram_reset(void *sih);
+
+/*
+ * Disable NVRAM access. May be unnecessary or undefined on certain
+ * platforms.
+ */
+extern void nvram_exit(void *sih);
+
+/*
+ * Get the value of an NVRAM variable. The pointer returned may be
+ * invalid after a set.
+ * @param name name of variable to get
+ * @return value of variable or NULL if undefined
+ */
+extern char * nvram_get(const char *name);
+
+/*
+ * Get the value of an NVRAM variable. The pointer returned may be
+ * invalid after a set.
+ * @param name name of variable to get
+ * @param bit bit value to get
+ * @return value of variable or NULL if undefined
+ */
+extern char * nvram_get_bitflag(const char *name, const int bit);
+
+/*
+ * Read the reset GPIO value from the nvram and set the GPIO
+ * as input
+ */
+extern int BCMINITFN(nvram_resetgpio_init)(void *sih);
+
+/*
+ * Get the value of an NVRAM variable.
+ * @param name name of variable to get
+ * @return value of variable or NUL if undefined
+ */
+static INLINE char *
+nvram_safe_get(const char *name)
+{
+ char *p = nvram_get(name);
+ return p ? p : "";
+}
+
+/*
+ * Match an NVRAM variable.
+ * @param name name of variable to match
+ * @param match value to compare against value of variable
+ * @return TRUE if variable is defined and its value is string equal
+ * to match or FALSE otherwise
+ */
+static INLINE int
+nvram_match(const char *name, const char *match)
+{
+ const char *value = nvram_get(name);
+
+ /* In nvramstubs.c builds, nvram_get() is defined as returning zero,
+ * so the return line below never executes the strcmp(),
+ * resulting in 'match' being an unused parameter.
+ * Make a ref to 'match' to quiet the compiler warning.
+ */
+
+ BCM_REFERENCE(match);
+
+ return (value && !strcmp(value, match));
+}
+
+/*
+ * Match an NVRAM variable.
+ * @param name name of variable to match
+ * @param bit bit value to get
+ * @param match value to compare against value of variable
+ * @return TRUE if variable is defined and its value is string equal
+ * to match or FALSE otherwise
+ */
+static INLINE int
+nvram_match_bitflag(const char *name, const int bit, const char *match)
+{
+ const char *value = nvram_get_bitflag(name, bit);
+ BCM_REFERENCE(match);
+ return (value && !strcmp(value, match));
+}
+
+/*
+ * Inversely match an NVRAM variable.
+ * @param name name of variable to match
+ * @param match value to compare against value of variable
+ * @return TRUE if variable is defined and its value is not string
+ * equal to invmatch or FALSE otherwise
+ */
+static INLINE int
+nvram_invmatch(const char *name, const char *invmatch)
+{
+ const char *value = nvram_get(name);
+
+ /* In nvramstubs.c builds, nvram_get() is defined as returning zero,
+ * so the return line below never executes the strcmp(),
+ * resulting in 'invmatch' being an unused parameter.
+ * Make a ref to 'invmatch' to quiet the compiler warning.
+ */
+
+ BCM_REFERENCE(invmatch);
+
+ return (value && strcmp(value, invmatch));
+}
+
+/*
+ * Set the value of an NVRAM variable. The name and value strings are
+ * copied into private storage. Pointers to previously set values
+ * may become invalid. The new value may be immediately
+ * retrieved but will not be permanently stored until a commit.
+ * @param name name of variable to set
+ * @param value value of variable
+ * @return 0 on success and errno on failure
+ */
+extern int nvram_set(const char *name, const char *value);
+
+/*
+ * Set the value of an NVRAM variable. The name and value strings are
+ * copied into private storage. Pointers to previously set values
+ * may become invalid. The new value may be immediately
+ * retrieved but will not be permanently stored until a commit.
+ * @param name name of variable to set
+ * @param bit bit value to set
+ * @param value value of variable
+ * @return 0 on success and errno on failure
+ */
+extern int nvram_set_bitflag(const char *name, const int bit, const int value);
+/*
+ * Unset an NVRAM variable. Pointers to previously set values
+ * remain valid until a set.
+ * @param name name of variable to unset
+ * @return 0 on success and errno on failure
+ * NOTE: use nvram_commit to commit this change to flash.
+ */
+extern int nvram_unset(const char *name);
+
+/*
+ * Commit NVRAM variables to permanent storage. All pointers to values
+ * may be invalid after a commit.
+ * NVRAM values are undefined after a commit.
+ * @param nvram_corrupt true to corrupt nvram, false otherwise.
+ * @return 0 on success and errno on failure
+ */
+extern int nvram_commit_internal(bool nvram_corrupt);
+
+/*
+ * Commit NVRAM variables to permanent storage. All pointers to values
+ * may be invalid after a commit.
+ * NVRAM values are undefined after a commit.
+ * @return 0 on success and errno on failure
+ */
+extern int nvram_commit(void);
+
+/*
+ * Get all NVRAM variables (format name=value\0 ... \0\0).
+ * @param buf buffer to store variables
+ * @param count size of buffer in bytes
+ * @return 0 on success and errno on failure
+ */
+extern int nvram_getall(char *nvram_buf, int count);
+
+/*
+ * returns the crc value of the nvram
+ * @param nvh nvram header pointer
+ */
+uint8 nvram_calc_crc(struct nvram_header * nvh);
+
+extern int nvram_space;
+#endif /* _LANGUAGE_ASSEMBLY */
+
+/* The NVRAM version number stored as an NVRAM variable */
+#define NVRAM_SOFTWARE_VERSION "1"
+
+#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */
+#define NVRAM_CLEAR_MAGIC 0x0
+#define NVRAM_INVALID_MAGIC 0xFFFFFFFF
+#define NVRAM_VERSION 1
+#define NVRAM_HEADER_SIZE 20
+/* This definition is for precommit staging, and will be removed */
+#define NVRAM_SPACE 0x8000
+/* For CFE builds this gets passed in thru the makefile */
+#ifndef MAX_NVRAM_SPACE
+#define MAX_NVRAM_SPACE 0x10000
+#endif
+#define DEF_NVRAM_SPACE 0x8000
+#define ROM_ENVRAM_SPACE 0x1000
+#define NVRAM_LZMA_MAGIC 0x4c5a4d41 /* 'LZMA' */
+
+#define NVRAM_MAX_VALUE_LEN 255
+#define NVRAM_MAX_PARAM_LEN 64
+
+#define NVRAM_CRC_START_POSITION 9 /* magic, len, crc8 to be skipped */
+#define NVRAM_CRC_VER_MASK 0xffffff00 /* for crc_ver_init */
+
+/* Offsets to embedded nvram area */
+#define NVRAM_START_COMPRESSED 0x400
+#define NVRAM_START 0x1000
+
+#define BCM_JUMBO_NVRAM_DELIMIT '\n'
+#define BCM_JUMBO_START "Broadcom Jumbo Nvram file"
+
+#if !defined(BCMDONGLEHOST) && defined(BCMTRXV2)
+extern char *_vars;
+extern uint _varsz;
+#endif /* !defined(BCMDONGLEHOST) && defined(BCMTRXV2) */
+
+#if (defined(FAILSAFE_UPGRADE) || defined(CONFIG_FAILSAFE_UPGRADE) || \
+ defined(__CONFIG_FAILSAFE_UPGRADE_SUPPORT__))
+#define IMAGE_SIZE "image_size"
+#define BOOTPARTITION "bootpartition"
+#define IMAGE_BOOT BOOTPARTITION
+#define PARTIALBOOTS "partialboots"
+#define MAXPARTIALBOOTS "maxpartialboots"
+#define IMAGE_1ST_FLASH_TRX "flash0.trx"
+#define IMAGE_1ST_FLASH_OS "flash0.os"
+#define IMAGE_2ND_FLASH_TRX "flash0.trx2"
+#define IMAGE_2ND_FLASH_OS "flash0.os2"
+#define IMAGE_FIRST_OFFSET "image_first_offset"
+#define IMAGE_SECOND_OFFSET "image_second_offset"
+#define LINUX_FIRST "linux"
+#define LINUX_SECOND "linux2"
+#endif
+
+#if (defined(DUAL_IMAGE) || defined(CONFIG_DUAL_IMAGE) || \
+ defined(__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__))
+/* Shared by all: CFE, Linux Kernel, and Ap */
+#define IMAGE_BOOT "image_boot"
+#define BOOTPARTITION IMAGE_BOOT
+/* CFE variables */
+#define IMAGE_1ST_FLASH_TRX "flash0.trx"
+#define IMAGE_1ST_FLASH_OS "flash0.os"
+#define IMAGE_2ND_FLASH_TRX "flash0.trx2"
+#define IMAGE_2ND_FLASH_OS "flash0.os2"
+#define IMAGE_SIZE "image_size"
+
+/* CFE and Linux Kernel shared variables */
+#define IMAGE_FIRST_OFFSET "image_first_offset"
+#define IMAGE_SECOND_OFFSET "image_second_offset"
+
+/* Linux application variables */
+#define LINUX_FIRST "linux"
+#define LINUX_SECOND "linux2"
+#define POLICY_TOGGLE "toggle"
+#define LINUX_PART_TO_FLASH "linux_to_flash"
+#define LINUX_FLASH_POLICY "linux_flash_policy"
+
+#endif /* defined(DUAL_IMAGE||CONFIG_DUAL_IMAGE)||__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__ */
+
+#endif /* _bcmnvram_h_ */
diff --git a/wl/src/include/bcmsrom_fmt.h b/wl/src/include/bcmsrom_fmt.h
new file mode 100644
index 0000000..47a5073
--- /dev/null
+++ b/wl/src/include/bcmsrom_fmt.h
@@ -0,0 +1,969 @@
+/*
+ * SROM format definition.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmsrom_fmt.h 657898 2016-09-03 00:25:48Z $
+ */
+
+#ifndef _bcmsrom_fmt_h_
+#define _bcmsrom_fmt_h_
+
+#define SROM_MAXREV 15 /* max revision supported by driver */
+
+/* Maximum srom: 16 Kilobits == 2048 bytes */
+
+#define SROM_MAX 2048
+#define SROM_MAXW 594
+
+#ifdef LARGE_NVRAM_MAXSZ
+#define VARS_MAX LARGE_NVRAM_MAXSZ
+#else
+#if defined(BCMROMBUILD) || defined(DONGLEBUILD)
+#define VARS_MAX 4096
+#else
+#define LARGE_NVRAM_MAXSZ 8192
+#define VARS_MAX LARGE_NVRAM_MAXSZ
+#endif /* BCMROMBUILD || DONGLEBUILD */
+#endif /* LARGE_NVRAM_MAXSZ */
+
+/* PCI fields */
+#define PCI_F0DEVID 48
+
+
+#define SROM_WORDS 64
+
+#define SROM3_SWRGN_OFF 28 /* s/w region offset in words */
+
+#define SROM_SSID 2
+#define SROM_SVID 3
+
+#define SROM_WL1LHMAXP 29
+
+#define SROM_WL1LPAB0 30
+#define SROM_WL1LPAB1 31
+#define SROM_WL1LPAB2 32
+
+#define SROM_WL1HPAB0 33
+#define SROM_WL1HPAB1 34
+#define SROM_WL1HPAB2 35
+
+#define SROM_MACHI_IL0 36
+#define SROM_MACMID_IL0 37
+#define SROM_MACLO_IL0 38
+#define SROM_MACHI_ET0 39
+#define SROM_MACMID_ET0 40
+#define SROM_MACLO_ET0 41
+#define SROM_MACHI_ET1 42
+#define SROM_MACMID_ET1 43
+#define SROM_MACLO_ET1 44
+#define SROM3_MACHI 37
+#define SROM3_MACMID 38
+#define SROM3_MACLO 39
+
+#define SROM_BXARSSI2G 40
+#define SROM_BXARSSI5G 41
+
+#define SROM_TRI52G 42
+#define SROM_TRI5GHL 43
+
+#define SROM_RXPO52G 45
+
+#define SROM2_ENETPHY 45
+
+#define SROM_AABREV 46
+/* Fields in AABREV */
+#define SROM_BR_MASK 0x00ff
+#define SROM_CC_MASK 0x0f00
+#define SROM_CC_SHIFT 8
+#define SROM_AA0_MASK 0x3000
+#define SROM_AA0_SHIFT 12
+#define SROM_AA1_MASK 0xc000
+#define SROM_AA1_SHIFT 14
+
+#define SROM_WL0PAB0 47
+#define SROM_WL0PAB1 48
+#define SROM_WL0PAB2 49
+
+#define SROM_LEDBH10 50
+#define SROM_LEDBH32 51
+
+#define SROM_WL10MAXP 52
+
+#define SROM_WL1PAB0 53
+#define SROM_WL1PAB1 54
+#define SROM_WL1PAB2 55
+
+#define SROM_ITT 56
+
+#define SROM_BFL 57
+#define SROM_BFL2 28
+#define SROM3_BFL2 61
+
+#define SROM_AG10 58
+
+#define SROM_CCODE 59
+
+#define SROM_OPO 60
+
+#define SROM3_LEDDC 62
+
+#define SROM_CRCREV 63
+
+/* SROM Rev 4: Reallocate the software part of the srom to accomodate
+ * MIMO features. It assumes up to two PCIE functions and 440 bytes
+ * of useable srom i.e. the useable storage in chips with OTP that
+ * implements hardware redundancy.
+ */
+
+#define SROM4_WORDS 220
+
+#define SROM4_SIGN 32
+#define SROM4_SIGNATURE 0x5372
+
+#define SROM4_BREV 33
+
+#define SROM4_BFL0 34
+#define SROM4_BFL1 35
+#define SROM4_BFL2 36
+#define SROM4_BFL3 37
+#define SROM5_BFL0 37
+#define SROM5_BFL1 38
+#define SROM5_BFL2 39
+#define SROM5_BFL3 40
+
+#define SROM4_MACHI 38
+#define SROM4_MACMID 39
+#define SROM4_MACLO 40
+#define SROM5_MACHI 41
+#define SROM5_MACMID 42
+#define SROM5_MACLO 43
+
+#define SROM4_CCODE 41
+#define SROM4_REGREV 42
+#define SROM5_CCODE 34
+#define SROM5_REGREV 35
+
+#define SROM4_LEDBH10 43
+#define SROM4_LEDBH32 44
+#define SROM5_LEDBH10 59
+#define SROM5_LEDBH32 60
+
+#define SROM4_LEDDC 45
+#define SROM5_LEDDC 45
+
+#define SROM4_AA 46
+#define SROM4_AA2G_MASK 0x00ff
+#define SROM4_AA2G_SHIFT 0
+#define SROM4_AA5G_MASK 0xff00
+#define SROM4_AA5G_SHIFT 8
+
+#define SROM4_AG10 47
+#define SROM4_AG32 48
+
+#define SROM4_TXPID2G 49
+#define SROM4_TXPID5G 51
+#define SROM4_TXPID5GL 53
+#define SROM4_TXPID5GH 55
+
+#define SROM4_TXRXC 61
+#define SROM4_TXCHAIN_MASK 0x000f
+#define SROM4_TXCHAIN_SHIFT 0
+#define SROM4_RXCHAIN_MASK 0x00f0
+#define SROM4_RXCHAIN_SHIFT 4
+#define SROM4_SWITCH_MASK 0xff00
+#define SROM4_SWITCH_SHIFT 8
+
+
+/* Per-path fields */
+#define MAX_PATH_SROM 4
+#define SROM4_PATH0 64
+#define SROM4_PATH1 87
+#define SROM4_PATH2 110
+#define SROM4_PATH3 133
+
+#define SROM4_2G_ITT_MAXP 0
+#define SROM4_2G_PA 1
+#define SROM4_5G_ITT_MAXP 5
+#define SROM4_5GLH_MAXP 6
+#define SROM4_5G_PA 7
+#define SROM4_5GL_PA 11
+#define SROM4_5GH_PA 15
+
+/* Fields in the ITT_MAXP and 5GLH_MAXP words */
+#define B2G_MAXP_MASK 0xff
+#define B2G_ITT_SHIFT 8
+#define B5G_MAXP_MASK 0xff
+#define B5G_ITT_SHIFT 8
+#define B5GH_MAXP_MASK 0xff
+#define B5GL_MAXP_SHIFT 8
+
+/* All the miriad power offsets */
+#define SROM4_2G_CCKPO 156
+#define SROM4_2G_OFDMPO 157
+#define SROM4_5G_OFDMPO 159
+#define SROM4_5GL_OFDMPO 161
+#define SROM4_5GH_OFDMPO 163
+#define SROM4_2G_MCSPO 165
+#define SROM4_5G_MCSPO 173
+#define SROM4_5GL_MCSPO 181
+#define SROM4_5GH_MCSPO 189
+#define SROM4_CDDPO 197
+#define SROM4_STBCPO 198
+#define SROM4_BW40PO 199
+#define SROM4_BWDUPPO 200
+
+#define SROM4_CRCREV 219
+
+
+/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6.
+ * This is acombined srom for both MIMO and SISO boards, usable in
+ * the .130 4Kilobit OTP with hardware redundancy.
+ */
+
+#define SROM8_SIGN 64
+
+#define SROM8_BREV 65
+
+#define SROM8_BFL0 66
+#define SROM8_BFL1 67
+#define SROM8_BFL2 68
+#define SROM8_BFL3 69
+
+#define SROM8_MACHI 70
+#define SROM8_MACMID 71
+#define SROM8_MACLO 72
+
+#define SROM8_CCODE 73
+#define SROM8_REGREV 74
+
+#define SROM8_LEDBH10 75
+#define SROM8_LEDBH32 76
+
+#define SROM8_LEDDC 77
+
+#define SROM8_AA 78
+
+#define SROM8_AG10 79
+#define SROM8_AG32 80
+
+#define SROM8_TXRXC 81
+
+#define SROM8_BXARSSI2G 82
+#define SROM8_BXARSSI5G 83
+#define SROM8_TRI52G 84
+#define SROM8_TRI5GHL 85
+#define SROM8_RXPO52G 86
+
+#define SROM8_FEM2G 87
+#define SROM8_FEM5G 88
+#define SROM8_FEM_ANTSWLUT_MASK 0xf800
+#define SROM8_FEM_ANTSWLUT_SHIFT 11
+#define SROM8_FEM_TR_ISO_MASK 0x0700
+#define SROM8_FEM_TR_ISO_SHIFT 8
+#define SROM8_FEM_PDET_RANGE_MASK 0x00f8
+#define SROM8_FEM_PDET_RANGE_SHIFT 3
+#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006
+#define SROM8_FEM_EXTPA_GAIN_SHIFT 1
+#define SROM8_FEM_TSSIPOS_MASK 0x0001
+#define SROM8_FEM_TSSIPOS_SHIFT 0
+
+#define SROM8_THERMAL 89
+
+/* Temp sense related entries */
+#define SROM8_MPWR_RAWTS 90
+#define SROM8_TS_SLP_OPT_CORRX 91
+/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, IQSWP: IQ CAL swap disable */
+#define SROM8_FOC_HWIQ_IQSWP 92
+
+#define SROM8_EXTLNAGAIN 93
+
+/* Temperature delta for PHY calibration */
+#define SROM8_PHYCAL_TEMPDELTA 94
+
+/* Measured power 1 & 2, 0-13 bits at offset 95, MSB 2 bits are unused for now. */
+#define SROM8_MPWR_1_AND_2 95
+
+
+/* Per-path offsets & fields */
+#define SROM8_PATH0 96
+#define SROM8_PATH1 112
+#define SROM8_PATH2 128
+#define SROM8_PATH3 144
+
+#define SROM8_2G_ITT_MAXP 0
+#define SROM8_2G_PA 1
+#define SROM8_5G_ITT_MAXP 4
+#define SROM8_5GLH_MAXP 5
+#define SROM8_5G_PA 6
+#define SROM8_5GL_PA 9
+#define SROM8_5GH_PA 12
+
+/* All the miriad power offsets */
+#define SROM8_2G_CCKPO 160
+
+#define SROM8_2G_OFDMPO 161
+#define SROM8_5G_OFDMPO 163
+#define SROM8_5GL_OFDMPO 165
+#define SROM8_5GH_OFDMPO 167
+
+#define SROM8_2G_MCSPO 169
+#define SROM8_5G_MCSPO 177
+#define SROM8_5GL_MCSPO 185
+#define SROM8_5GH_MCSPO 193
+
+#define SROM8_CDDPO 201
+#define SROM8_STBCPO 202
+#define SROM8_BW40PO 203
+#define SROM8_BWDUPPO 204
+
+/* SISO PA parameters are in the path0 spaces */
+#define SROM8_SISO 96
+
+/* Legacy names for SISO PA paramters */
+#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP)
+#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA)
+#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1)
+#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2)
+#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP)
+#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP)
+#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA)
+#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1)
+#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2)
+#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA)
+#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1)
+#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2)
+#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA)
+#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1)
+#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2)
+
+#define SROM8_CRCREV 219
+
+/* SROM REV 9 */
+#define SROM9_2GPO_CCKBW20 160
+#define SROM9_2GPO_CCKBW20UL 161
+#define SROM9_2GPO_LOFDMBW20 162
+#define SROM9_2GPO_LOFDMBW20UL 164
+
+#define SROM9_5GLPO_LOFDMBW20 166
+#define SROM9_5GLPO_LOFDMBW20UL 168
+#define SROM9_5GMPO_LOFDMBW20 170
+#define SROM9_5GMPO_LOFDMBW20UL 172
+#define SROM9_5GHPO_LOFDMBW20 174
+#define SROM9_5GHPO_LOFDMBW20UL 176
+
+#define SROM9_2GPO_MCSBW20 178
+#define SROM9_2GPO_MCSBW20UL 180
+#define SROM9_2GPO_MCSBW40 182
+
+#define SROM9_5GLPO_MCSBW20 184
+#define SROM9_5GLPO_MCSBW20UL 186
+#define SROM9_5GLPO_MCSBW40 188
+#define SROM9_5GMPO_MCSBW20 190
+#define SROM9_5GMPO_MCSBW20UL 192
+#define SROM9_5GMPO_MCSBW40 194
+#define SROM9_5GHPO_MCSBW20 196
+#define SROM9_5GHPO_MCSBW20UL 198
+#define SROM9_5GHPO_MCSBW40 200
+
+#define SROM9_PO_MCS32 202
+#define SROM9_PO_LOFDM40DUP 203
+#define SROM9_EU_EDCRSTH 204
+#define SROM10_EU_EDCRSTH 204
+#define SROM8_RXGAINERR_2G 205
+#define SROM8_RXGAINERR_5GL 206
+#define SROM8_RXGAINERR_5GM 207
+#define SROM8_RXGAINERR_5GH 208
+#define SROM8_RXGAINERR_5GU 209
+#define SROM8_SUBBAND_PPR 210
+#define SROM8_PCIEINGRESS_WAR 211
+#define SROM8_EU_EDCRSTH 212
+#define SROM9_SAR 212
+
+#define SROM8_NOISELVL_2G 213
+#define SROM8_NOISELVL_5GL 214
+#define SROM8_NOISELVL_5GM 215
+#define SROM8_NOISELVL_5GH 216
+#define SROM8_NOISELVL_5GU 217
+#define SROM8_NOISECALOFFSET 218
+
+#define SROM9_REV_CRC 219
+
+#define SROM10_CCKPWROFFSET 218
+#define SROM10_SIGN 219
+#define SROM10_SWCTRLMAP_2G 220
+#define SROM10_CRCREV 229
+
+#define SROM10_WORDS 230
+#define SROM10_SIGNATURE SROM4_SIGNATURE
+
+
+/* SROM REV 11 */
+#define SROM11_BREV 65
+
+#define SROM11_BFL0 66
+#define SROM11_BFL1 67
+#define SROM11_BFL2 68
+#define SROM11_BFL3 69
+#define SROM11_BFL4 70
+#define SROM11_BFL5 71
+
+#define SROM11_MACHI 72
+#define SROM11_MACMID 73
+#define SROM11_MACLO 74
+
+#define SROM11_CCODE 75
+#define SROM11_REGREV 76
+
+#define SROM11_LEDBH10 77
+#define SROM11_LEDBH32 78
+
+#define SROM11_LEDDC 79
+
+#define SROM11_AA 80
+
+#define SROM11_AGBG10 81
+#define SROM11_AGBG2A0 82
+#define SROM11_AGA21 83
+
+#define SROM11_TXRXC 84
+
+#define SROM11_FEM_CFG1 85
+#define SROM11_FEM_CFG2 86
+
+/* Masks and offsets for FEM_CFG */
+#define SROM11_FEMCTRL_MASK 0xf800
+#define SROM11_FEMCTRL_SHIFT 11
+#define SROM11_PAPDCAP_MASK 0x0400
+#define SROM11_PAPDCAP_SHIFT 10
+#define SROM11_TWORANGETSSI_MASK 0x0200
+#define SROM11_TWORANGETSSI_SHIFT 9
+#define SROM11_PDGAIN_MASK 0x01f0
+#define SROM11_PDGAIN_SHIFT 4
+#define SROM11_EPAGAIN_MASK 0x000e
+#define SROM11_EPAGAIN_SHIFT 1
+#define SROM11_TSSIPOSSLOPE_MASK 0x0001
+#define SROM11_TSSIPOSSLOPE_SHIFT 0
+#define SROM11_GAINCTRLSPH_MASK 0xf800
+#define SROM11_GAINCTRLSPH_SHIFT 11
+
+#define SROM11_THERMAL 87
+#define SROM11_MPWR_RAWTS 88
+#define SROM11_TS_SLP_OPT_CORRX 89
+#define SROM11_XTAL_FREQ 90
+#define SROM11_5GB0_4080_W0_A1 91
+#define SROM11_PHYCAL_TEMPDELTA 92
+#define SROM11_MPWR_1_AND_2 93
+#define SROM11_5GB0_4080_W1_A1 94
+#define SROM11_TSSIFLOOR_2G 95
+#define SROM11_TSSIFLOOR_5GL 96
+#define SROM11_TSSIFLOOR_5GM 97
+#define SROM11_TSSIFLOOR_5GH 98
+#define SROM11_TSSIFLOOR_5GU 99
+
+/* Masks and offsets for Thermal parameters */
+#define SROM11_TEMPS_PERIOD_MASK 0xf0
+#define SROM11_TEMPS_PERIOD_SHIFT 4
+#define SROM11_TEMPS_HYSTERESIS_MASK 0x0f
+#define SROM11_TEMPS_HYSTERESIS_SHIFT 0
+#define SROM11_TEMPCORRX_MASK 0xfc
+#define SROM11_TEMPCORRX_SHIFT 2
+#define SROM11_TEMPSENSE_OPTION_MASK 0x3
+#define SROM11_TEMPSENSE_OPTION_SHIFT 0
+
+#define SROM11_PDOFF_2G_40M_A0_MASK 0x000f
+#define SROM11_PDOFF_2G_40M_A0_SHIFT 0
+#define SROM11_PDOFF_2G_40M_A1_MASK 0x00f0
+#define SROM11_PDOFF_2G_40M_A1_SHIFT 4
+#define SROM11_PDOFF_2G_40M_A2_MASK 0x0f00
+#define SROM11_PDOFF_2G_40M_A2_SHIFT 8
+#define SROM11_PDOFF_2G_40M_VALID_MASK 0x8000
+#define SROM11_PDOFF_2G_40M_VALID_SHIFT 15
+
+#define SROM11_PDOFF_2G_40M 100
+#define SROM11_PDOFF_40M_A0 101
+#define SROM11_PDOFF_40M_A1 102
+#define SROM11_PDOFF_40M_A2 103
+#define SROM11_5GB0_4080_W2_A1 103
+#define SROM11_PDOFF_80M_A0 104
+#define SROM11_PDOFF_80M_A1 105
+#define SROM11_PDOFF_80M_A2 106
+#define SROM11_5GB1_4080_W0_A1 106
+
+#define SROM11_SUBBAND5GVER 107
+
+/* Per-path fields and offset */
+#define MAX_PATH_SROM_11 3
+#define SROM11_PATH0 108
+#define SROM11_PATH1 128
+#define SROM11_PATH2 148
+
+#define SROM11_2G_MAXP 0
+#define SROM11_5GB1_4080_PA 0
+#define SROM11_2G_PA 1
+#define SROM11_5GB2_4080_PA 2
+#define SROM11_RXGAINS1 4
+#define SROM11_RXGAINS 5
+#define SROM11_5GB3_4080_PA 5
+#define SROM11_5GB1B0_MAXP 6
+#define SROM11_5GB3B2_MAXP 7
+#define SROM11_5GB0_PA 8
+#define SROM11_5GB1_PA 11
+#define SROM11_5GB2_PA 14
+#define SROM11_5GB3_PA 17
+
+/* Masks and offsets for rxgains */
+#define SROM11_RXGAINS5GTRELNABYPA_MASK 0x8000
+#define SROM11_RXGAINS5GTRELNABYPA_SHIFT 15
+#define SROM11_RXGAINS5GTRISOA_MASK 0x7800
+#define SROM11_RXGAINS5GTRISOA_SHIFT 11
+#define SROM11_RXGAINS5GELNAGAINA_MASK 0x0700
+#define SROM11_RXGAINS5GELNAGAINA_SHIFT 8
+#define SROM11_RXGAINS2GTRELNABYPA_MASK 0x0080
+#define SROM11_RXGAINS2GTRELNABYPA_SHIFT 7
+#define SROM11_RXGAINS2GTRISOA_MASK 0x0078
+#define SROM11_RXGAINS2GTRISOA_SHIFT 3
+#define SROM11_RXGAINS2GELNAGAINA_MASK 0x0007
+#define SROM11_RXGAINS2GELNAGAINA_SHIFT 0
+#define SROM11_RXGAINS5GHTRELNABYPA_MASK 0x8000
+#define SROM11_RXGAINS5GHTRELNABYPA_SHIFT 15
+#define SROM11_RXGAINS5GHTRISOA_MASK 0x7800
+#define SROM11_RXGAINS5GHTRISOA_SHIFT 11
+#define SROM11_RXGAINS5GHELNAGAINA_MASK 0x0700
+#define SROM11_RXGAINS5GHELNAGAINA_SHIFT 8
+#define SROM11_RXGAINS5GMTRELNABYPA_MASK 0x0080
+#define SROM11_RXGAINS5GMTRELNABYPA_SHIFT 7
+#define SROM11_RXGAINS5GMTRISOA_MASK 0x0078
+#define SROM11_RXGAINS5GMTRISOA_SHIFT 3
+#define SROM11_RXGAINS5GMELNAGAINA_MASK 0x0007
+#define SROM11_RXGAINS5GMELNAGAINA_SHIFT 0
+
+/* Power per rate */
+#define SROM11_CCKBW202GPO 168
+#define SROM11_CCKBW20UL2GPO 169
+#define SROM11_MCSBW202GPO 170
+#define SROM11_MCSBW202GPO_1 171
+#define SROM11_MCSBW402GPO 172
+#define SROM11_MCSBW402GPO_1 173
+#define SROM11_DOT11AGOFDMHRBW202GPO 174
+#define SROM11_OFDMLRBW202GPO 175
+
+#define SROM11_MCSBW205GLPO 176
+#define SROM11_MCSBW205GLPO_1 177
+#define SROM11_MCSBW405GLPO 178
+#define SROM11_MCSBW405GLPO_1 179
+#define SROM11_MCSBW805GLPO 180
+#define SROM11_MCSBW805GLPO_1 181
+#define SROM11_RPCAL_2G 182
+#define SROM11_RPCAL_5GL 183
+#define SROM11_MCSBW205GMPO 184
+#define SROM11_MCSBW205GMPO_1 185
+#define SROM11_MCSBW405GMPO 186
+#define SROM11_MCSBW405GMPO_1 187
+#define SROM11_MCSBW805GMPO 188
+#define SROM11_MCSBW805GMPO_1 189
+#define SROM11_RPCAL_5GM 190
+#define SROM11_RPCAL_5GH 191
+#define SROM11_MCSBW205GHPO 192
+#define SROM11_MCSBW205GHPO_1 193
+#define SROM11_MCSBW405GHPO 194
+#define SROM11_MCSBW405GHPO_1 195
+#define SROM11_MCSBW805GHPO 196
+#define SROM11_MCSBW805GHPO_1 197
+#define SROM11_RPCAL_5GU 198
+#define SROM11_PDOFF_2G_CCK 199
+#define SROM11_MCSLR5GLPO 200
+#define SROM11_MCSLR5GMPO 201
+#define SROM11_MCSLR5GHPO 202
+
+#define SROM11_SB20IN40HRPO 203
+#define SROM11_SB20IN80AND160HR5GLPO 204
+#define SROM11_SB40AND80HR5GLPO 205
+#define SROM11_SB20IN80AND160HR5GMPO 206
+#define SROM11_SB40AND80HR5GMPO 207
+#define SROM11_SB20IN80AND160HR5GHPO 208
+#define SROM11_SB40AND80HR5GHPO 209
+#define SROM11_SB20IN40LRPO 210
+#define SROM11_SB20IN80AND160LR5GLPO 211
+#define SROM11_SB40AND80LR5GLPO 212
+#define SROM11_TXIDXCAP2G 212
+#define SROM11_SB20IN80AND160LR5GMPO 213
+#define SROM11_SB40AND80LR5GMPO 214
+#define SROM11_TXIDXCAP5G 214
+#define SROM11_SB20IN80AND160LR5GHPO 215
+#define SROM11_SB40AND80LR5GHPO 216
+
+#define SROM11_DOT11AGDUPHRPO 217
+#define SROM11_DOT11AGDUPLRPO 218
+
+/* MISC */
+#define SROM11_PCIEINGRESS_WAR 220
+#define SROM11_SAR 221
+
+#define SROM11_NOISELVL_2G 222
+#define SROM11_NOISELVL_5GL 223
+#define SROM11_NOISELVL_5GM 224
+#define SROM11_NOISELVL_5GH 225
+#define SROM11_NOISELVL_5GU 226
+
+#define SROM11_RXGAINERR_2G 227
+#define SROM11_RXGAINERR_5GL 228
+#define SROM11_RXGAINERR_5GM 229
+#define SROM11_RXGAINERR_5GH 230
+#define SROM11_RXGAINERR_5GU 231
+
+#define SROM11_EU_EDCRSTH 232
+#define SROM12_EU_EDCRSTH 232
+
+#define SROM11_SIGN 64
+#define SROM11_CRCREV 233
+
+#define SROM11_WORDS 234
+#define SROM11_SIGNATURE 0x0634
+
+
+/* SROM REV 12 */
+#define SROM12_SIGN 64
+#define SROM12_WORDS 512
+#define SROM12_SIGNATURE 0x8888
+#define SROM12_CRCREV 511
+
+#define SROM12_BFL6 486
+#define SROM12_BFL7 487
+
+#define SROM12_MCSBW205GX1PO 234
+#define SROM12_MCSBW205GX1PO_1 235
+#define SROM12_MCSBW405GX1PO 236
+#define SROM12_MCSBW405GX1PO_1 237
+#define SROM12_MCSBW805GX1PO 238
+#define SROM12_MCSBW805GX1PO_1 239
+#define SROM12_MCSLR5GX1PO 240
+#define SROM12_SB40AND80LR5GX1PO 241
+#define SROM12_SB20IN80AND160LR5GX1PO 242
+#define SROM12_SB20IN80AND160HR5GX1PO 243
+#define SROM12_SB40AND80HR5GX1PO 244
+
+#define SROM12_MCSBW205GX2PO 245
+#define SROM12_MCSBW205GX2PO_1 246
+#define SROM12_MCSBW405GX2PO 247
+#define SROM12_MCSBW405GX2PO_1 248
+#define SROM12_MCSBW805GX2PO 249
+#define SROM12_MCSBW805GX2PO_1 250
+#define SROM12_MCSLR5GX2PO 251
+#define SROM12_SB40AND80LR5GX2PO 252
+#define SROM12_SB20IN80AND160LR5GX2PO 253
+#define SROM12_SB20IN80AND160HR5GX2PO 254
+#define SROM12_SB40AND80HR5GX2PO 255
+
+/* MISC */
+#define SROM12_RXGAINS10 483
+#define SROM12_RXGAINS11 484
+#define SROM12_RXGAINS12 485
+
+/* Per-path fields and offset */
+#define MAX_PATH_SROM_12 3
+#define SROM12_PATH0 256
+#define SROM12_PATH1 328
+#define SROM12_PATH2 400
+
+#define SROM12_5GB42G_MAXP 0
+#define SROM12_2GB0_PA 1
+#define SROM12_2GB0_PA_W0 1
+#define SROM12_2GB0_PA_W1 2
+#define SROM12_2GB0_PA_W2 3
+#define SROM12_2GB0_PA_W3 4
+
+#define SROM12_RXGAINS 5
+#define SROM12_5GB1B0_MAXP 6
+#define SROM12_5GB3B2_MAXP 7
+
+#define SROM12_5GB0_PA 8
+#define SROM12_5GB0_PA_W0 8
+#define SROM12_5GB0_PA_W1 9
+#define SROM12_5GB0_PA_W2 10
+#define SROM12_5GB0_PA_W3 11
+
+#define SROM12_5GB1_PA 12
+#define SROM12_5GB1_PA_W0 12
+#define SROM12_5GB1_PA_W1 13
+#define SROM12_5GB1_PA_W2 14
+#define SROM12_5GB1_PA_W3 15
+
+#define SROM12_5GB2_PA 16
+#define SROM12_5GB2_PA_W0 16
+#define SROM12_5GB2_PA_W1 17
+#define SROM12_5GB2_PA_W2 18
+#define SROM12_5GB2_PA_W3 19
+
+#define SROM12_5GB3_PA 20
+#define SROM12_5GB3_PA_W0 20
+#define SROM12_5GB3_PA_W1 21
+#define SROM12_5GB3_PA_W2 22
+#define SROM12_5GB3_PA_W3 23
+
+#define SROM12_5GB4_PA 24
+#define SROM12_5GB4_PA_W0 24
+#define SROM12_5GB4_PA_W1 25
+#define SROM12_5GB4_PA_W2 26
+#define SROM12_5GB4_PA_W3 27
+
+#define SROM12_2G40B0_PA 28
+#define SROM12_2G40B0_PA_W0 28
+#define SROM12_2G40B0_PA_W1 29
+#define SROM12_2G40B0_PA_W2 30
+#define SROM12_2G40B0_PA_W3 31
+
+#define SROM12_5G40B0_PA 32
+#define SROM12_5G40B0_PA_W0 32
+#define SROM12_5G40B0_PA_W1 33
+#define SROM12_5G40B0_PA_W2 34
+#define SROM12_5G40B0_PA_W3 35
+
+#define SROM12_5G40B1_PA 36
+#define SROM12_5G40B1_PA_W0 36
+#define SROM12_5G40B1_PA_W1 37
+#define SROM12_5G40B1_PA_W2 38
+#define SROM12_5G40B1_PA_W3 39
+
+#define SROM12_5G40B2_PA 40
+#define SROM12_5G40B2_PA_W0 40
+#define SROM12_5G40B2_PA_W1 41
+#define SROM12_5G40B2_PA_W2 42
+#define SROM12_5G40B2_PA_W3 43
+
+#define SROM12_5G40B3_PA 44
+#define SROM12_5G40B3_PA_W0 44
+#define SROM12_5G40B3_PA_W1 45
+#define SROM12_5G40B3_PA_W2 46
+#define SROM12_5G40B3_PA_W3 47
+
+#define SROM12_5G40B4_PA 48
+#define SROM12_5G40B4_PA_W0 48
+#define SROM12_5G40B4_PA_W1 49
+#define SROM12_5G40B4_PA_W2 50
+#define SROM12_5G40B4_PA_W3 51
+
+#define SROM12_5G80B0_PA 52
+#define SROM12_5G80B0_PA_W0 52
+#define SROM12_5G80B0_PA_W1 53
+#define SROM12_5G80B0_PA_W2 54
+#define SROM12_5G80B0_PA_W3 55
+
+#define SROM12_5G80B1_PA 56
+#define SROM12_5G80B1_PA_W0 56
+#define SROM12_5G80B1_PA_W1 57
+#define SROM12_5G80B1_PA_W2 58
+#define SROM12_5G80B1_PA_W3 59
+
+#define SROM12_5G80B2_PA 60
+#define SROM12_5G80B2_PA_W0 60
+#define SROM12_5G80B2_PA_W1 61
+#define SROM12_5G80B2_PA_W2 62
+#define SROM12_5G80B2_PA_W3 63
+
+#define SROM12_5G80B3_PA 64
+#define SROM12_5G80B3_PA_W0 64
+#define SROM12_5G80B3_PA_W1 65
+#define SROM12_5G80B3_PA_W2 66
+#define SROM12_5G80B3_PA_W3 67
+
+#define SROM12_5G80B4_PA 68
+#define SROM12_5G80B4_PA_W0 68
+#define SROM12_5G80B4_PA_W1 69
+#define SROM12_5G80B4_PA_W2 70
+#define SROM12_5G80B4_PA_W3 71
+
+/* PD offset */
+#define SROM12_PDOFF_2G_CCK 472
+
+#define SROM12_PDOFF_20in40M_5G_B0 473
+#define SROM12_PDOFF_20in40M_5G_B1 474
+#define SROM12_PDOFF_20in40M_5G_B2 475
+#define SROM12_PDOFF_20in40M_5G_B3 476
+#define SROM12_PDOFF_20in40M_5G_B4 477
+
+#define SROM12_PDOFF_40in80M_5G_B0 478
+#define SROM12_PDOFF_40in80M_5G_B1 479
+#define SROM12_PDOFF_40in80M_5G_B2 480
+#define SROM12_PDOFF_40in80M_5G_B3 481
+#define SROM12_PDOFF_40in80M_5G_B4 482
+
+#define SROM12_PDOFF_20in80M_5G_B0 488
+#define SROM12_PDOFF_20in80M_5G_B1 489
+#define SROM12_PDOFF_20in80M_5G_B2 490
+#define SROM12_PDOFF_20in80M_5G_B3 491
+#define SROM12_PDOFF_20in80M_5G_B4 492
+
+#define SROM12_GPDN_L 91 /* GPIO pull down bits [15:0] */
+#define SROM12_GPDN_H 233 /* GPIO pull down bits [31:16] */
+
+#define SROM13_SIGN 64
+#define SROM13_WORDS 590
+#define SROM13_SIGNATURE 0x4d55
+#define SROM13_CRCREV 589
+
+
+/* Per-path fields and offset */
+#define MAX_PATH_SROM_13 4
+#define SROM13_PATH0 256
+#define SROM13_PATH1 328
+#define SROM13_PATH2 400
+#define SROM13_PATH3 512
+#define SROM13_RXGAINS 5
+
+#define SROM13_XTALFREQ 90
+
+#define SROM13_PDOFFSET20IN40M2G 94
+#define SROM13_PDOFFSET20IN40M2GCORE3 95
+#define SROM13_SB20IN40HRLRPOX 96
+
+#define SROM13_RXGAINS1CORE3 97
+
+#define SROM13_PDOFFSET20IN40M5GCORE3 98
+#define SROM13_PDOFFSET20IN40M5GCORE3_1 99
+
+#define SROM13_ANTGAIN_BANDBGA 100
+
+#define SROM13_PDOFFSET40IN80M5GCORE3 105
+#define SROM13_PDOFFSET40IN80M5GCORE3_1 106
+
+/* power per rate */
+#define SROM13_MCS1024QAM2GPO 108
+#define SROM13_MCS1024QAM5GLPO 109
+#define SROM13_MCS1024QAM5GLPO_1 110
+#define SROM13_MCS1024QAM5GMPO 111
+#define SROM13_MCS1024QAM5GMPO_1 112
+#define SROM13_MCS1024QAM5GHPO 113
+#define SROM13_MCS1024QAM5GHPO_1 114
+#define SROM13_MCS1024QAM5GX1PO 115
+#define SROM13_MCS1024QAM5GX1PO_1 116
+#define SROM13_MCS1024QAM5GX2PO 117
+#define SROM13_MCS1024QAM5GX2PO_1 118
+
+#define SROM13_MCSBW1605GLPO 119
+#define SROM13_MCSBW1605GLPO_1 120
+#define SROM13_MCSBW1605GMPO 121
+#define SROM13_MCSBW1605GMPO_1 122
+#define SROM13_MCSBW1605GHPO 123
+#define SROM13_MCSBW1605GHPO_1 124
+
+#define SROM13_MCSBW1605GX1PO 125
+#define SROM13_MCSBW1605GX1PO_1 126
+#define SROM13_MCSBW1605GX2PO 127
+#define SROM13_MCSBW1605GX2PO_1 128
+
+#define SROM13_ULBPPROFFS5GB0 129
+#define SROM13_ULBPPROFFS5GB1 130
+#define SROM13_ULBPPROFFS5GB2 131
+#define SROM13_ULBPPROFFS5GB3 132
+#define SROM13_ULBPPROFFS5GB4 133
+#define SROM13_ULBPPROFFS2G 134
+
+#define SROM13_MCS8POEXP 135
+#define SROM13_MCS8POEXP_1 136
+#define SROM13_MCS9POEXP 137
+#define SROM13_MCS9POEXP_1 138
+#define SROM13_MCS10POEXP 139
+#define SROM13_MCS10POEXP_1 140
+#define SROM13_MCS11POEXP 141
+#define SROM13_MCS11POEXP_1 142
+#define SROM13_ULBPDOFFS5GB0A0 143
+#define SROM13_ULBPDOFFS5GB0A1 144
+#define SROM13_ULBPDOFFS5GB0A2 145
+#define SROM13_ULBPDOFFS5GB0A3 146
+#define SROM13_ULBPDOFFS5GB1A0 147
+#define SROM13_ULBPDOFFS5GB1A1 148
+#define SROM13_ULBPDOFFS5GB1A2 149
+#define SROM13_ULBPDOFFS5GB1A3 150
+#define SROM13_ULBPDOFFS5GB2A0 151
+#define SROM13_ULBPDOFFS5GB2A1 152
+#define SROM13_ULBPDOFFS5GB2A2 153
+#define SROM13_ULBPDOFFS5GB2A3 154
+#define SROM13_ULBPDOFFS5GB3A0 155
+#define SROM13_ULBPDOFFS5GB3A1 156
+#define SROM13_ULBPDOFFS5GB3A2 157
+#define SROM13_ULBPDOFFS5GB3A3 158
+#define SROM13_ULBPDOFFS5GB4A0 159
+#define SROM13_ULBPDOFFS5GB4A1 160
+#define SROM13_ULBPDOFFS5GB4A2 161
+#define SROM13_ULBPDOFFS5GB4A3 162
+#define SROM13_ULBPDOFFS2GA0 163
+#define SROM13_ULBPDOFFS2GA1 164
+#define SROM13_ULBPDOFFS2GA2 165
+#define SROM13_ULBPDOFFS2GA3 166
+
+#define SROM13_RPCAL5GB4 199
+#define SROM13_RPCAL2GCORE3 101
+#define SROM13_RPCAL5GB01CORE3 102
+#define SROM13_RPCAL5GB23CORE3 103
+
+#define SROM13_SW_TXRX_MASK 104
+
+#define SROM13_EU_EDCRSTH 232
+
+#define SROM13_SWCTRLMAP4_CFG 493
+#define SROM13_SWCTRLMAP4_TX2G_FEM3TO0 494
+#define SROM13_SWCTRLMAP4_RX2G_FEM3TO0 495
+#define SROM13_SWCTRLMAP4_RXBYP2G_FEM3TO0 496
+#define SROM13_SWCTRLMAP4_MISC2G_FEM3TO0 497
+#define SROM13_SWCTRLMAP4_TX5G_FEM3TO0 498
+#define SROM13_SWCTRLMAP4_RX5G_FEM3TO0 499
+#define SROM13_SWCTRLMAP4_RXBYP5G_FEM3TO0 500
+#define SROM13_SWCTRLMAP4_MISC5G_FEM3TO0 501
+#define SROM13_SWCTRLMAP4_TX2G_FEM7TO4 502
+#define SROM13_SWCTRLMAP4_RX2G_FEM7TO4 503
+#define SROM13_SWCTRLMAP4_RXBYP2G_FEM7TO4 504
+#define SROM13_SWCTRLMAP4_MISC2G_FEM7TO4 505
+#define SROM13_SWCTRLMAP4_TX5G_FEM7TO4 506
+#define SROM13_SWCTRLMAP4_RX5G_FEM7TO4 507
+#define SROM13_SWCTRLMAP4_RXBYP5G_FEM7TO4 508
+#define SROM13_SWCTRLMAP4_MISC5G_FEM7TO4 509
+
+#define SROM13_PDOFFSET20IN80M5GCORE3 510
+#define SROM13_PDOFFSET20IN80M5GCORE3_1 511
+
+#define SROM13_NOISELVLCORE3 584
+#define SROM13_NOISELVLCORE3_1 585
+#define SROM13_RXGAINERRCORE3 586
+#define SROM13_RXGAINERRCORE3_1 587
+
+#define SROM13_PDOFF_2G_CCK_20M 167
+
+#define SROM15_CAL_OFFSET_LOC 68
+#define MAX_IOCTL_TXCHUNK_SIZE 1500
+#define SROM15_MAX_CAL_SIZE 1662
+#define SROM15_SIGNATURE 0x110c
+#define SROM15_WORDS 1024
+#define SROM15_MACHI 65
+
+#define SROM16_SIGN 128
+#define SROM16_WORDS 1024
+#define SROM16_SIGNATURE 0x4357
+#define SROM16_CRCREV 1023
+
+#define SROM16_CAL_DATA_OFFSET 288
+
+typedef struct {
+ uint8 tssipos; /* TSSI positive slope, 1: positive, 0: negative */
+ uint8 extpagain; /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */
+ uint8 pdetrange; /* support 32 combinations of different Pdet dynamic ranges */
+ uint8 triso; /* TR switch isolation */
+ uint8 antswctrllut; /* antswctrl lookup table configuration: 32 possible choices */
+} srom_fem_t;
+
+#endif /* _bcmsrom_fmt_h_ */
diff --git a/wl/src/include/bcmsrom_tbl.h b/wl/src/include/bcmsrom_tbl.h
new file mode 100644
index 0000000..df02f4c
--- /dev/null
+++ b/wl/src/include/bcmsrom_tbl.h
@@ -0,0 +1,1435 @@
+/*
+ * Table that encodes the srom formats for PCI/PCIe NICs.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmsrom_tbl.h 650789 2016-07-22 12:29:31Z $
+ */
+
+#ifndef _bcmsrom_tbl_h_
+#define _bcmsrom_tbl_h_
+
+#include "sbpcmcia.h"
+#include "wlioctl.h"
+#include <bcmsrom_fmt.h>
+
+typedef struct {
+ const char *name;
+ uint32 revmask;
+ uint32 flags;
+ uint16 off;
+ uint16 mask;
+} sromvar_t;
+
+#define SRFL_MORE 1 /* value continues as described by the next entry */
+#define SRFL_NOFFS 2 /* value bits can't be all one's */
+#define SRFL_PRHEX 4 /* value is in hexdecimal format */
+#define SRFL_PRSIGN 8 /* value is in signed decimal format */
+#define SRFL_CCODE 0x10 /* value is in country code format */
+#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */
+#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */
+#define SRFL_NOVAR 0x80 /* do not generate a nvram param, entry is for mfgc */
+#define SRFL_ARRAY 0x100 /* value is in an array. All elements EXCEPT FOR THE LAST
+ * ONE in the array should have this flag set.
+ */
+
+#if defined(DSLCPE) && defined(DSLCPE_WOMBO)
+#define SRFL_PCI 0x10000000 /* value is an PCI specific */
+#define SRFL_PCIE 0x20000000 /* value is an PCIE specific */
+
+#define SROM_DEVID_PCI 4
+#endif /* defined(DSLCPE) && defined(DSLCPE_WOMBO) */
+
+#define SROM_DEVID_PCIE 48
+
+/**
+ * Assumptions:
+ * - Ethernet address spans across 3 consecutive words
+ *
+ * Table rules:
+ * - Add multiple entries next to each other if a value spans across multiple words
+ * (even multiple fields in the same word) with each entry except the last having
+ * it's SRFL_MORE bit set.
+ * - Ethernet address entry does not follow above rule and must not have SRFL_MORE
+ * bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
+ * - The last entry's name field must be NULL to indicate the end of the table. Other
+ * entries must have non-NULL name.
+ */
+#if !defined(SROM15_MEMOPT)
+static const sromvar_t BCMATTACHDATA(pci_sromvars)[] = {
+/* name revmask flags off mask */
+#if defined(DSLCPE) && defined(DSLCPE_WOMBO)
+ {"devid", 0xfffffffe, SRFL_PRHEX|SRFL_PCI, SROM_DEVID_PCI, 0xffff},
+ {"devid", 0xffffff00, SRFL_PRHEX|SRFL_PCIE, SROM_DEVID_PCIE, 0xffff},
+#elif defined(CABLECPE)
+ {"devid", 0xffffff00, SRFL_PRHEX, PCI_F0DEVID, 0xffff},
+#elif defined(BCMPCIEDEV) && defined(BCMPCIEDEV_ENABLED)
+ {"devid", 0xffffff00, SRFL_PRHEX, SROM_DEVID_PCIE, 0xffff},
+#else
+ {"devid", 0xffffff00, SRFL_PRHEX|SRFL_NOVAR, PCI_F0DEVID, 0xffff},
+#endif /* defined(DSLCPE) && defined(DSLCPE_WOMBO) */
+ {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK},
+ {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff},
+ {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
+ {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff},
+ {"boardflags", 0x00000004, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff},
+ {"", 0, 0, SROM_BFL2, 0xffff},
+ {"boardflags", 0x00000008, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff},
+ {"", 0, 0, SROM3_BFL2, 0xffff},
+ {"boardflags", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL0, 0xffff},
+ {"", 0, 0, SROM4_BFL1, 0xffff},
+ {"boardflags", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL0, 0xffff},
+ {"", 0, 0, SROM5_BFL1, 0xffff},
+ {"boardflags", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL0, 0xffff},
+ {"", 0, 0, SROM8_BFL1, 0xffff},
+ {"boardflags2", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL2, 0xffff},
+ {"", 0, 0, SROM4_BFL3, 0xffff},
+ {"boardflags2", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL2, 0xffff},
+ {"", 0, 0, SROM5_BFL3, 0xffff},
+ {"boardflags2", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL2, 0xffff},
+ {"", 0, 0, SROM8_BFL3, 0xffff},
+ {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
+ {"subvid", 0xfffffffc, SRFL_PRHEX, SROM_SVID, 0xffff},
+ {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff},
+ {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff},
+ {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff},
+ {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff},
+ {"boardnum", 0x00000700, 0, SROM8_MACLO, 0xffff},
+ {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK},
+ {"regrev", 0x00000008, 0, SROM_OPO, 0xff00},
+ {"regrev", 0x00000010, 0, SROM4_REGREV, 0xffff},
+ {"regrev", 0x000000e0, 0, SROM5_REGREV, 0xffff},
+ {"regrev", 0x00000700, 0, SROM8_REGREV, 0xffff},
+ {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff},
+ {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
+ {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff},
+ {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
+ {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff},
+ {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
+ {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff},
+ {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
+ {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff},
+ {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
+ {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff},
+ {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
+ {"ledbh0", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
+ {"ledbh1", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
+ {"ledbh2", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
+ {"ledbh3", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
+ {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff},
+ {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff},
+ {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff},
+ {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0x00ff},
+ {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0x00ff},
+ {"pa0b0", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
+ {"pa0b1", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
+ {"pa0b2", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
+ {"pa0itssit", 0x00000700, 0, SROM8_W0_ITTMAXP, 0xff00},
+ {"pa0maxpwr", 0x00000700, 0, SROM8_W0_ITTMAXP, 0x00ff},
+ {"opo", 0x0000000c, 0, SROM_OPO, 0x00ff},
+ {"opo", 0x00000700, 0, SROM8_2G_OFDMPO, 0x00ff},
+ {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK},
+ {"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff},
+ {"aa2g", 0x00000700, 0, SROM8_AA, 0x00ff},
+ {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK},
+ {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00},
+ {"aa5g", 0x00000700, 0, SROM8_AA, 0xff00},
+ {"ag0", 0x0000000e, 0, SROM_AG10, 0x00ff},
+ {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00},
+ {"ag0", 0x000000f0, 0, SROM4_AG10, 0x00ff},
+ {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00},
+ {"ag2", 0x000000f0, 0, SROM4_AG32, 0x00ff},
+ {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00},
+ {"ag0", 0x00000700, 0, SROM8_AG10, 0x00ff},
+ {"ag1", 0x00000700, 0, SROM8_AG10, 0xff00},
+ {"ag2", 0x00000700, 0, SROM8_AG32, 0x00ff},
+ {"ag3", 0x00000700, 0, SROM8_AG32, 0xff00},
+ {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff},
+ {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff},
+ {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff},
+ {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff},
+ {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff},
+ {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff},
+ {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff},
+ {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff},
+ {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff},
+ {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00},
+ {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00},
+ {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00},
+ {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff},
+ {"pa1b0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
+ {"pa1b1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
+ {"pa1b2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
+ {"pa1lob0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
+ {"pa1lob1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
+ {"pa1lob2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
+ {"pa1hib0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
+ {"pa1hib1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
+ {"pa1hib2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
+ {"pa1itssit", 0x00000700, 0, SROM8_W1_ITTMAXP, 0xff00},
+ {"pa1maxpwr", 0x00000700, 0, SROM8_W1_ITTMAXP, 0x00ff},
+ {"pa1lomaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0xff00},
+ {"pa1himaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
+ {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800},
+ {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700},
+ {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0},
+ {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f},
+ {"bxa2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x1800},
+ {"rssisav2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x0700},
+ {"rssismc2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x00f0},
+ {"rssismf2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x000f},
+ {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800},
+ {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700},
+ {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0},
+ {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f},
+ {"bxa5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x1800},
+ {"rssisav5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x0700},
+ {"rssismc5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x00f0},
+ {"rssismf5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x000f},
+ {"tri2g", 0x00000008, 0, SROM_TRI52G, 0x00ff},
+ {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00},
+ {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0x00ff},
+ {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00},
+ {"tri2g", 0x00000700, 0, SROM8_TRI52G, 0x00ff},
+ {"tri5g", 0x00000700, 0, SROM8_TRI52G, 0xff00},
+ {"tri5gl", 0x00000700, 0, SROM8_TRI5GHL, 0x00ff},
+ {"tri5gh", 0x00000700, 0, SROM8_TRI5GHL, 0xff00},
+ {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff},
+ {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00},
+ {"rxpo2g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
+ {"rxpo5g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
+ {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK},
+ {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK},
+ {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK},
+ {"txchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK},
+ {"rxchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK},
+ {"antswitch", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK},
+ {"tssipos2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK},
+ {"extpagain2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK},
+ {"pdetrange2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK},
+ {"triso2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK},
+ {"antswctl2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK},
+ {"tssipos5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK},
+ {"extpagain5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK},
+ {"pdetrange5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK},
+ {"triso5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK},
+ {"antswctl5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK},
+ {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0x00ff},
+ {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00},
+ {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff},
+ {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00},
+ {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0x00ff},
+ {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00},
+ {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff},
+ {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00},
+ {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff},
+ {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00},
+ {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff},
+ {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00},
+ {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff},
+ {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00},
+ {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff},
+ {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00},
+
+ {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff},
+ {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff},
+ {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff},
+ {"ccode", 0x00000700, SRFL_CCODE, SROM8_CCODE, 0xffff},
+ {"macaddr", 0x00000700, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
+ {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff},
+ {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff},
+ {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff},
+ {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff},
+ {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff},
+ {"leddc", 0x00000700, SRFL_NOFFS|SRFL_LEDDC, SROM8_LEDDC, 0xffff},
+ {"leddc", 0x000000e0, SRFL_NOFFS|SRFL_LEDDC, SROM5_LEDDC, 0xffff},
+ {"leddc", 0x00000010, SRFL_NOFFS|SRFL_LEDDC, SROM4_LEDDC, 0xffff},
+ {"leddc", 0x00000008, SRFL_NOFFS|SRFL_LEDDC, SROM3_LEDDC, 0xffff},
+
+ {"tempthresh", 0x00000700, 0, SROM8_THERMAL, 0xff00},
+ {"tempoffset", 0x00000700, 0, SROM8_THERMAL, 0x00ff},
+ {"rawtempsense", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff},
+ {"measpower", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00},
+ {"tempsense_slope", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x00ff},
+ {"tempcorrx", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00},
+ {"tempsense_option", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x0300},
+ {"freqoffset_corr", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x000f},
+ {"iqcal_swp_dis", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010},
+ {"hw_iqcal_en", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020},
+ {"elna2g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0x00ff},
+ {"elna5g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0xff00},
+ {"phycal_tempdelta", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff},
+ {"temps_period", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x0f00},
+ {"temps_hysteresis", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0xf000},
+ {"measpower1", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x007f},
+ {"measpower2", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x3f80},
+
+ {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff},
+ {"cck2gpo", 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
+ {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff},
+ {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff},
+ {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff},
+ {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff},
+ {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff},
+ {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff},
+ {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff},
+ {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff},
+ {"ofdm2gpo", 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
+ {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
+ {"ofdm5gpo", 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
+ {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff},
+ {"ofdm5glpo", 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
+ {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
+ {"ofdm5ghpo", 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
+ {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
+ {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff},
+ {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff},
+ {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff},
+ {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff},
+ {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff},
+ {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff},
+ {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff},
+ {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff},
+ {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff},
+ {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff},
+ {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff},
+ {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff},
+ {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff},
+ {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff},
+ {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff},
+ {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff},
+ {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff},
+ {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff},
+ {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff},
+ {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff},
+ {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff},
+ {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff},
+ {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff},
+ {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff},
+ {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff},
+ {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff},
+ {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff},
+ {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff},
+ {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff},
+ {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff},
+ {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff},
+ {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff},
+ {"mcs2gpo0", 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
+ {"mcs2gpo1", 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
+ {"mcs2gpo2", 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
+ {"mcs2gpo3", 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff},
+ {"mcs2gpo4", 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff},
+ {"mcs2gpo5", 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff},
+ {"mcs2gpo6", 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff},
+ {"mcs2gpo7", 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff},
+ {"mcs5gpo0", 0x00000100, 0, SROM8_5G_MCSPO, 0xffff},
+ {"mcs5gpo1", 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff},
+ {"mcs5gpo2", 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff},
+ {"mcs5gpo3", 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff},
+ {"mcs5gpo4", 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff},
+ {"mcs5gpo5", 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff},
+ {"mcs5gpo6", 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff},
+ {"mcs5gpo7", 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff},
+ {"mcs5glpo0", 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff},
+ {"mcs5glpo1", 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff},
+ {"mcs5glpo2", 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff},
+ {"mcs5glpo3", 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff},
+ {"mcs5glpo4", 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff},
+ {"mcs5glpo5", 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff},
+ {"mcs5glpo6", 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff},
+ {"mcs5glpo7", 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff},
+ {"mcs5ghpo0", 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff},
+ {"mcs5ghpo1", 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff},
+ {"mcs5ghpo2", 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff},
+ {"mcs5ghpo3", 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff},
+ {"mcs5ghpo4", 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff},
+ {"mcs5ghpo5", 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
+ {"mcs5ghpo6", 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
+ {"mcs5ghpo7", 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
+ {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff},
+ {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff},
+ {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff},
+ {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff},
+ {"cddpo", 0x00000100, 0, SROM8_CDDPO, 0xffff},
+ {"stbcpo", 0x00000100, 0, SROM8_STBCPO, 0xffff},
+ {"bw40po", 0x00000100, 0, SROM8_BW40PO, 0xffff},
+ {"bwduppo", 0x00000100, 0, SROM8_BWDUPPO, 0xffff},
+
+ /* power per rate from sromrev 9 */
+ {"cckbw202gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20, 0xffff},
+ {"cckbw20ul2gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20UL, 0xffff},
+ {"legofdmbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20, 0xffff},
+ {"", 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff},
+ {"legofdmbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20UL, 0xffff},
+ {"", 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff},
+ {"legofdmbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20, 0xffff},
+ {"", 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff},
+ {"legofdmbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL, 0xffff},
+ {"", 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff},
+ {"legofdmbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20, 0xffff},
+ {"", 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff},
+ {"legofdmbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL, 0xffff},
+ {"", 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff},
+ {"legofdmbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20, 0xffff},
+ {"", 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff},
+ {"legofdmbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL, 0xffff},
+ {"", 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff},
+ {"mcsbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff},
+ {"", 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff},
+ {"mcsbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff},
+ {"", 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff},
+ {"mcsbw402gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff},
+ {"", 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff},
+ {"mcsbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff},
+ {"", 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff},
+ {"mcsbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20UL, 0xffff},
+ {"", 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff},
+ {"mcsbw405glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff},
+ {"", 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff},
+ {"mcsbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff},
+ {"", 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff},
+ {"mcsbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20UL, 0xffff},
+ {"", 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff},
+ {"mcsbw405gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff},
+ {"", 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff},
+ {"mcsbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff},
+ {"", 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff},
+ {"mcsbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20UL, 0xffff},
+ {"", 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff},
+ {"mcsbw405ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff},
+ {"", 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff},
+ {"mcs32po", 0x00000600, 0, SROM9_PO_MCS32, 0xffff},
+ {"legofdm40duppo", 0x00000600, 0, SROM9_PO_LOFDM40DUP, 0xffff},
+ {"pcieingress_war", 0x00000700, 0, SROM8_PCIEINGRESS_WAR, 0xf},
+ {"eu_edthresh2g", 0x00000100, 0, SROM8_EU_EDCRSTH, 0x00ff},
+ {"eu_edthresh5g", 0x00000100, 0, SROM8_EU_EDCRSTH, 0xff00},
+ {"eu_edthresh2g", 0x00000200, 0, SROM9_EU_EDCRSTH, 0x00ff},
+ {"eu_edthresh5g", 0x00000200, 0, SROM9_EU_EDCRSTH, 0xff00},
+ {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f},
+ {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f},
+ {"rxgainerr2ga1", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x07c0},
+ {"rxgainerr2ga2", 0x00000700, 0, SROM8_RXGAINERR_2G, 0xf800},
+ {"rxgainerr5gla0", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x003f},
+ {"rxgainerr5gla1", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x07c0},
+ {"rxgainerr5gla2", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0xf800},
+ {"rxgainerr5gma0", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x003f},
+ {"rxgainerr5gma1", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x07c0},
+ {"rxgainerr5gma2", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0xf800},
+ {"rxgainerr5gha0", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x003f},
+ {"rxgainerr5gha1", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x07c0},
+ {"rxgainerr5gha2", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0xf800},
+ {"rxgainerr5gua0", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x003f},
+ {"rxgainerr5gua1", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x07c0},
+ {"rxgainerr5gua2", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0xf800},
+ {"sar2g", 0x00000600, 0, SROM9_SAR, 0x00ff},
+ {"sar5g", 0x00000600, 0, SROM9_SAR, 0xff00},
+ {"noiselvl2ga0", 0x00000700, 0, SROM8_NOISELVL_2G, 0x001f},
+ {"noiselvl2ga1", 0x00000700, 0, SROM8_NOISELVL_2G, 0x03e0},
+ {"noiselvl2ga2", 0x00000700, 0, SROM8_NOISELVL_2G, 0x7c00},
+ {"noiselvl5gla0", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x001f},
+ {"noiselvl5gla1", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x03e0},
+ {"noiselvl5gla2", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x7c00},
+ {"noiselvl5gma0", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x001f},
+ {"noiselvl5gma1", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x03e0},
+ {"noiselvl5gma2", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x7c00},
+ {"noiselvl5gha0", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x001f},
+ {"noiselvl5gha1", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x03e0},
+ {"noiselvl5gha2", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x7c00},
+ {"noiselvl5gua0", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x001f},
+ {"noiselvl5gua1", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x03e0},
+ {"noiselvl5gua2", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x7c00},
+ {"noisecaloffset", 0x00000300, 0, SROM8_NOISECALOFFSET, 0x00ff},
+ {"noisecaloffset5g", 0x00000300, 0, SROM8_NOISECALOFFSET, 0xff00},
+ {"subband5gver", 0x00000700, 0, SROM8_SUBBAND_PPR, 0x7},
+
+ {"cckPwrOffset", 0x00000400, 0, SROM10_CCKPWROFFSET, 0xffff},
+ {"eu_edthresh2g", 0x00000400, 0, SROM10_EU_EDCRSTH, 0x00ff},
+ {"eu_edthresh5g", 0x00000400, 0, SROM10_EU_EDCRSTH, 0xff00},
+ /* swctrlmap_2g array, note that the last element doesn't have SRFL_ARRAY flag set */
+ {"swctrlmap_2g", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G, 0xffff},
+ {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 1, 0xffff},
+ {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 2, 0xffff},
+ {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 3, 0xffff},
+ {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 4, 0xffff},
+ {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 5, 0xffff},
+ {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 6, 0xffff},
+ {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 7, 0xffff},
+ {"", 0x00000400, SRFL_PRHEX, SROM10_SWCTRLMAP_2G + 8, 0xffff},
+
+ /* sromrev 11 */
+ {"boardflags3", 0xfffff800, SRFL_PRHEX|SRFL_MORE, SROM11_BFL4, 0xffff},
+ {"", 0, 0, SROM11_BFL5, 0xffff},
+ {"boardnum", 0xfffff800, 0, SROM11_MACLO, 0xffff},
+ {"macaddr", 0xfffff800, SRFL_ETHADDR, SROM11_MACHI, 0xffff},
+ {"ccode", 0xfffff800, SRFL_CCODE, SROM11_CCODE, 0xffff},
+ {"regrev", 0xfffff800, 0, SROM11_REGREV, 0xffff},
+ {"ledbh0", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0x00ff},
+ {"ledbh1", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0xff00},
+ {"ledbh2", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0x00ff},
+ {"ledbh3", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0xff00},
+ {"leddc", 0xfffff800, SRFL_NOFFS|SRFL_LEDDC, SROM11_LEDDC, 0xffff},
+ {"aa2g", 0xfffff800, 0, SROM11_AA, 0x00ff},
+ {"aa5g", 0xfffff800, 0, SROM11_AA, 0xff00},
+ {"agbg0", 0xfffff800, 0, SROM11_AGBG10, 0xff00},
+ {"agbg1", 0xfffff800, 0, SROM11_AGBG10, 0x00ff},
+ {"agbg2", 0xfffff800, 0, SROM11_AGBG2A0, 0xff00},
+ {"aga0", 0xfffff800, 0, SROM11_AGBG2A0, 0x00ff},
+ {"aga1", 0xfffff800, 0, SROM11_AGA21, 0xff00},
+ {"aga2", 0xfffff800, 0, SROM11_AGA21, 0x00ff},
+ {"txchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_TXCHAIN_MASK},
+ {"rxchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_RXCHAIN_MASK},
+ {"antswitch", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_SWITCH_MASK},
+
+ {"tssiposslope2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0001},
+ {"epagain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x000e},
+ {"pdgain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x01f0},
+ {"tworangetssi2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0200},
+ {"papdcap2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0400},
+ {"femctrl", 0xfffff800, 0, SROM11_FEM_CFG1, 0xf800},
+
+ {"tssiposslope5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0001},
+ {"epagain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x000e},
+ {"pdgain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x01f0},
+ {"tworangetssi5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0200},
+ {"papdcap5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0400},
+ {"gainctrlsph", 0xfffff800, 0, SROM11_FEM_CFG2, 0xf800},
+
+ {"tempthresh", 0xfffff800, 0, SROM11_THERMAL, 0xff00},
+ {"tempoffset", 0xfffff800, 0, SROM11_THERMAL, 0x00ff},
+ {"rawtempsense", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0x01ff},
+ {"measpower", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0xfe00},
+ {"tempsense_slope", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x00ff},
+ {"tempcorrx", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0xfc00},
+ {"tempsense_option", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x0300},
+ {"xtalfreq", 0xfffff800, 0, SROM11_XTAL_FREQ, 0xffff},
+ {"txpwrbckof", 0x00000800, SRFL_PRHEX, SROM11_PATH0 + SROM11_2G_MAXP, 0xff00},
+ /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #1 */
+ {"pa5gbw4080a1", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W0_A1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W1_A1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W2_A1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_4080_W0_A1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_4080_PA + 2, 0xffff},
+ {"phycal_tempdelta", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x00ff},
+ {"temps_period", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x0f00},
+ {"temps_hysteresis", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0xf000},
+ {"measpower1", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x007f},
+ {"measpower2", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x3f80},
+ {"tssifloor2g", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_2G, 0x03ff},
+ {"tssifloor5g", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GL, 0x03ff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GM, 0x03ff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GH, 0x03ff},
+ {"", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_5GU, 0x03ff},
+ {"pdoffset2g40ma0", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x000f},
+ {"pdoffset2g40ma1", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x00f0},
+ {"pdoffset2g40ma2", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x0f00},
+ {"pdoffset2g40mvalid", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x8000},
+ {"pdoffset40ma0", 0xfffff800, 0, SROM11_PDOFF_40M_A0, 0xffff},
+ {"pdoffset40ma1", 0xfffff800, 0, SROM11_PDOFF_40M_A1, 0xffff},
+ {"pdoffset40ma2", 0xfffff800, 0, SROM11_PDOFF_40M_A2, 0xffff},
+ {"pdoffset80ma0", 0xfffff800, 0, SROM11_PDOFF_80M_A0, 0xffff},
+ {"pdoffset80ma1", 0xfffff800, 0, SROM11_PDOFF_80M_A1, 0xffff},
+ {"pdoffset80ma2", 0xfffff800, 0, SROM11_PDOFF_80M_A2, 0xffff},
+
+ {"subband5gver", 0xfffff800, SRFL_PRHEX, SROM11_SUBBAND5GVER, 0xffff},
+ {"paparambwver", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0xf000},
+ {"rx5ggainwar", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0x2000},
+ /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #0 */
+ {"pa5gbw4080a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 +SROM11_5GB0_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff},
+ /* Special PA Params for 4335 5G Band, 40 MHz BW */
+ {"pa5gbw40a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_5GB3_PA + 2, 0xffff},
+ /* Special PA Params for 4335 5G Band, 80 MHz BW */
+ {"pa5gbw80a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff},
+ /* Special PA Params for 4335 2G Band, CCK */
+ {"pa2gccka0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_2G_PA + 2, 0xffff},
+
+ /* power per rate */
+ {"cckbw202gpo", 0xfffff800, 0, SROM11_CCKBW202GPO, 0xffff},
+ {"cckbw20ul2gpo", 0xfffff800, 0, SROM11_CCKBW20UL2GPO, 0xffff},
+ {"mcsbw202gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW202GPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW202GPO_1, 0xffff},
+ {"mcsbw402gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW402GPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW402GPO_1, 0xffff},
+ {"dot11agofdmhrbw202gpo", 0xfffff800, 0, SROM11_DOT11AGOFDMHRBW202GPO, 0xffff},
+ {"ofdmlrbw202gpo", 0xfffff800, 0, SROM11_OFDMLRBW202GPO, 0xffff},
+ {"mcsbw205glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GLPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW205GLPO_1, 0xffff},
+ {"mcsbw405glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GLPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW405GLPO_1, 0xffff},
+ {"mcsbw805glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GLPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW805GLPO_1, 0xffff},
+ {"mcsbw205gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GMPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW205GMPO_1, 0xffff},
+ {"mcsbw405gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GMPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW405GMPO_1, 0xffff},
+ {"mcsbw805gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GMPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW805GMPO_1, 0xffff},
+ {"mcsbw205ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GHPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW205GHPO_1, 0xffff},
+ {"mcsbw405ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GHPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW405GHPO_1, 0xffff},
+ {"mcsbw805ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GHPO, 0xffff},
+ {"", 0xfffff800, 0, SROM11_MCSBW805GHPO_1, 0xffff},
+ {"mcslr5glpo", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0x0fff},
+ {"mcslr5gmpo", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0xffff},
+ {"mcslr5ghpo", 0xfffff800, 0, SROM11_MCSLR5GHPO, 0xffff},
+ {"sb20in40hrpo", 0xfffff800, 0, SROM11_SB20IN40HRPO, 0xffff},
+ {"sb20in80and160hr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GLPO, 0xffff},
+ {"sb40and80hr5glpo", 0xfffff800, 0, SROM11_SB40AND80HR5GLPO, 0xffff},
+ {"sb20in80and160hr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GMPO, 0xffff},
+ {"sb40and80hr5gmpo", 0xfffff800, 0, SROM11_SB40AND80HR5GMPO, 0xffff},
+ {"sb20in80and160hr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GHPO, 0xffff},
+ {"sb40and80hr5ghpo", 0xfffff800, 0, SROM11_SB40AND80HR5GHPO, 0xffff},
+ {"sb20in40lrpo", 0xfffff800, 0, SROM11_SB20IN40LRPO, 0xffff},
+ {"sb20in80and160lr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GLPO, 0xffff},
+ {"sb40and80lr5glpo", 0xfffff800, 0, SROM11_SB40AND80LR5GLPO, 0xffff},
+ {"sb20in80and160lr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GMPO, 0xffff},
+ {"sb40and80lr5gmpo", 0xfffff800, 0, SROM11_SB40AND80LR5GMPO, 0xffff},
+ {"sb20in80and160lr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GHPO, 0xffff},
+ {"sb40and80lr5ghpo", 0xfffff800, 0, SROM11_SB40AND80LR5GHPO, 0xffff},
+ {"dot11agduphrpo", 0xfffff800, 0, SROM11_DOT11AGDUPHRPO, 0xffff},
+ {"dot11agduplrpo", 0xfffff800, 0, SROM11_DOT11AGDUPLRPO, 0xffff},
+
+ /* Misc */
+ {"sar2g", 0xfffff800, 0, SROM11_SAR, 0x00ff},
+ {"sar5g", 0xfffff800, 0, SROM11_SAR, 0xff00},
+
+ {"noiselvl2ga0", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x001f},
+ {"noiselvl2ga1", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x03e0},
+ {"noiselvl2ga2", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x7c00},
+ {"noiselvl5ga0", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x001f},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x001f},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x001f},
+ {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x001f},
+ {"noiselvl5ga1", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x03e0},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x03e0},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x03e0},
+ {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x03e0},
+ {"noiselvl5ga2", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x7c00},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x7c00},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x7c00},
+ {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x7c00},
+ {"eu_edthresh2g", 0x00000800, 0, SROM11_EU_EDCRSTH, 0x00ff},
+ {"eu_edthresh5g", 0x00000800, 0, SROM11_EU_EDCRSTH, 0xff00},
+
+ {"rxgainerr2ga0", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x003f},
+ {"rxgainerr2ga1", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x07c0},
+ {"rxgainerr2ga2", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0xf800},
+ {"rxgainerr5ga0", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x003f},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x003f},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x003f},
+ {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x003f},
+ {"rxgainerr5ga1", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x07c0},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x07c0},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x07c0},
+ {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x07c0},
+ {"rxgainerr5ga2", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0xf800},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0xf800},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0xf800},
+ {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0xf800},
+ {"rpcal2g", 0xfffff800, 0, SROM11_RPCAL_2G, 0xffff},
+ {"rpcal5gb0", 0xfffff800, 0, SROM11_RPCAL_5GL, 0xffff},
+ {"rpcal5gb1", 0xfffff800, 0, SROM11_RPCAL_5GM, 0xffff},
+ {"rpcal5gb2", 0xfffff800, 0, SROM11_RPCAL_5GH, 0xffff},
+ {"rpcal5gb3", 0xfffff800, 0, SROM11_RPCAL_5GU, 0xffff},
+ {"txidxcap2g", 0xfffff800, 0, SROM11_TXIDXCAP2G, 0x0ff0},
+ {"txidxcap5g", 0xfffff800, 0, SROM11_TXIDXCAP5G, 0x0ff0},
+ {"pdoffsetcckma0", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x000f},
+ {"pdoffsetcckma1", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x00f0},
+ {"pdoffsetcckma2", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x0f00},
+
+ /* sromrev 12 */
+ {"boardflags4", 0xfffff000, SRFL_PRHEX|SRFL_MORE, SROM12_BFL6, 0xffff},
+ {"", 0, 0, SROM12_BFL7, 0xffff},
+ {"pdoffsetcck", 0xfffff000, 0, SROM12_PDOFF_2G_CCK, 0xffff},
+ {"pdoffset20in40m5gb0", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B0, 0xffff},
+ {"pdoffset20in40m5gb1", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B1, 0xffff},
+ {"pdoffset20in40m5gb2", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B2, 0xffff},
+ {"pdoffset20in40m5gb3", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B3, 0xffff},
+ {"pdoffset20in40m5gb4", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B4, 0xffff},
+ {"pdoffset40in80m5gb0", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B0, 0xffff},
+ {"pdoffset40in80m5gb1", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B1, 0xffff},
+ {"pdoffset40in80m5gb2", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B2, 0xffff},
+ {"pdoffset40in80m5gb3", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B3, 0xffff},
+ {"pdoffset40in80m5gb4", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B4, 0xffff},
+ {"pdoffset20in80m5gb0", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B0, 0xffff},
+ {"pdoffset20in80m5gb1", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B1, 0xffff},
+ {"pdoffset20in80m5gb2", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B2, 0xffff},
+ {"pdoffset20in80m5gb3", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B3, 0xffff},
+ {"pdoffset20in80m5gb4", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B4, 0xffff},
+
+ /* power per rate */
+ {"mcsbw205gx1po", 0xfffff000, SRFL_MORE, SROM12_MCSBW205GX1PO, 0xffff},
+ {"", 0xfffff000, 0, SROM12_MCSBW205GX1PO_1, 0xffff},
+ {"mcsbw405gx1po", 0xfffff000, SRFL_MORE, SROM12_MCSBW405GX1PO, 0xffff},
+ {"", 0xfffff000, 0, SROM12_MCSBW405GX1PO_1, 0xffff},
+ {"mcsbw805gx1po", 0xfffff000, SRFL_MORE, SROM12_MCSBW805GX1PO, 0xffff},
+ {"", 0xfffff000, 0, SROM12_MCSBW805GX1PO_1, 0xffff},
+ {"mcsbw205gx2po", 0xfffff000, SRFL_MORE, SROM12_MCSBW205GX2PO, 0xffff},
+ {"", 0xfffff000, 0, SROM12_MCSBW205GX2PO_1, 0xffff},
+ {"mcsbw405gx2po", 0xfffff000, SRFL_MORE, SROM12_MCSBW405GX2PO, 0xffff},
+ {"", 0xfffff000, 0, SROM12_MCSBW405GX2PO_1, 0xffff},
+ {"mcsbw805gx2po", 0xfffff000, SRFL_MORE, SROM12_MCSBW805GX2PO, 0xffff},
+ {"", 0xfffff000, 0, SROM12_MCSBW805GX2PO_1, 0xffff},
+
+ {"sb20in80and160hr5gx1po", 0xfffff000, 0, SROM12_SB20IN80AND160HR5GX1PO, 0xffff},
+ {"sb40and80hr5gx1po", 0xfffff000, 0, SROM12_SB40AND80HR5GX1PO, 0xffff},
+ {"sb20in80and160lr5gx1po", 0xfffff000, 0, SROM12_SB20IN80AND160LR5GX1PO, 0xffff},
+ {"sb40and80hr5gx1po", 0xfffff000, 0, SROM12_SB40AND80HR5GX1PO, 0xffff},
+ {"sb20in80and160hr5gx2po", 0xfffff000, 0, SROM12_SB20IN80AND160HR5GX2PO, 0xffff},
+ {"sb40and80hr5gx2po", 0xfffff000, 0, SROM12_SB40AND80HR5GX2PO, 0xffff},
+ {"sb20in80and160lr5gx2po", 0xfffff000, 0, SROM12_SB20IN80AND160LR5GX2PO, 0xffff},
+ {"sb40and80hr5gx2po", 0xfffff000, 0, SROM12_SB40AND80HR5GX2PO, 0xffff},
+
+ {"rxgains5gmelnagaina0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0007},
+ {"rxgains5gmelnagaina1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0007},
+ {"rxgains5gmelnagaina2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0007},
+ {"rxgains5gmtrisoa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0078},
+ {"rxgains5gmtrisoa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0078},
+ {"rxgains5gmtrisoa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0078},
+ {"rxgains5gmtrelnabypa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0080},
+ {"rxgains5gmtrelnabypa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0080},
+ {"rxgains5gmtrelnabypa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0080},
+ {"rxgains5ghelnagaina0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0700},
+ {"rxgains5ghelnagaina1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0700},
+ {"rxgains5ghelnagaina2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0700},
+ {"rxgains5ghtrisoa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x7800},
+ {"rxgains5ghtrisoa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x7800},
+ {"rxgains5ghtrisoa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x7800},
+ {"rxgains5ghtrelnabypa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x8000},
+ {"rxgains5ghtrelnabypa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x8000},
+ {"rxgains5ghtrelnabypa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x8000},
+ {"eu_edthresh2g", 0x00001000, 0, SROM12_EU_EDCRSTH, 0x00ff},
+ {"eu_edthresh5g", 0x00001000, 0, SROM12_EU_EDCRSTH, 0xff00},
+
+ {"gpdn", 0xfffff000, SRFL_PRHEX|SRFL_MORE, SROM12_GPDN_L, 0xffff},
+ {"", 0, 0, SROM12_GPDN_H, 0xffff},
+
+ {"rpcal2gcore3", 0xffffe000, 0, SROM13_RPCAL2GCORE3, 0x00ff},
+ {"rpcal5gb0core3", 0xffffe000, 0, SROM13_RPCAL5GB01CORE3, 0x00ff},
+ {"rpcal5gb1core3", 0xffffe000, 0, SROM13_RPCAL5GB01CORE3, 0xff00},
+ {"rpcal5gb2core3", 0xffffe000, 0, SROM13_RPCAL5GB23CORE3, 0x00ff},
+ {"rpcal5gb3core3", 0xffffe000, 0, SROM13_RPCAL5GB23CORE3, 0xff00},
+
+ {"sw_txchain_mask", 0xffffe000, 0, SROM13_SW_TXRX_MASK, 0x000f},
+ {"sw_rxchain_mask", 0xffffe000, 0, SROM13_SW_TXRX_MASK, 0x00f0},
+
+ {"eu_edthresh2g", 0x00002000, 0, SROM13_EU_EDCRSTH, 0x00ff},
+ {"eu_edthresh5g", 0x00002000, 0, SROM13_EU_EDCRSTH, 0xff00},
+
+ {"agbg3", 0xffffe000, 0, SROM13_ANTGAIN_BANDBGA, 0xff00},
+ {"aga3", 0xffffe000, 0, SROM13_ANTGAIN_BANDBGA, 0x00ff},
+ {"noiselvl2ga3", 0xffffe000, 0, SROM13_NOISELVLCORE3, 0x001f},
+ {"noiselvl5ga3", 0xffffe000, SRFL_ARRAY, SROM13_NOISELVLCORE3, 0x03e0},
+ {"", 0xffffe000, SRFL_ARRAY, SROM13_NOISELVLCORE3, 0x7c00},
+ {"", 0xffffe000, SRFL_ARRAY, SROM13_NOISELVLCORE3_1, 0x001f},
+ {"", 0xffffe000, 0, SROM13_NOISELVLCORE3_1, 0x03e0},
+ {"rxgainerr2ga3", 0xffffe000, 0, SROM13_RXGAINERRCORE3, 0x001f},
+ {"rxgainerr5ga3", 0xffffe000, SRFL_ARRAY, SROM13_RXGAINERRCORE3, 0x03e0},
+ {"", 0xffffe000, SRFL_ARRAY, SROM13_RXGAINERRCORE3, 0x7c00},
+ {"", 0xffffe000, SRFL_ARRAY, SROM13_RXGAINERRCORE3_1, 0x001f},
+ {"", 0xffffe000, 0, SROM13_RXGAINERRCORE3_1, 0x03e0},
+ {"rxgains5gmelnagaina3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0007},
+ {"rxgains5gmtrisoa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0078},
+ {"rxgains5gmtrelnabypa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0080},
+ {"rxgains5ghelnagaina3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0700},
+ {"rxgains5ghtrisoa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x7800},
+ {"rxgains5ghtrelnabypa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x8000},
+
+ /* pdoffset */
+ {"pdoffset20in40m5gcore3", 0xffffe000, 0, SROM13_PDOFFSET20IN40M5GCORE3, 0xffff},
+ {"pdoffset20in40m5gcore3_1", 0xffffe000, 0, SROM13_PDOFFSET20IN40M5GCORE3_1, 0xffff},
+ {"pdoffset20in80m5gcore3", 0xffffe000, 0, SROM13_PDOFFSET20IN80M5GCORE3, 0xffff},
+ {"pdoffset20in80m5gcore3_1", 0xffffe000, 0, SROM13_PDOFFSET20IN80M5GCORE3_1, 0xffff},
+ {"pdoffset40in80m5gcore3", 0xffffe000, 0, SROM13_PDOFFSET40IN80M5GCORE3, 0xffff},
+ {"pdoffset40in80m5gcore3_1", 0xffffe000, 0, SROM13_PDOFFSET40IN80M5GCORE3_1, 0xffff},
+
+ {"pdoffset20in40m2g", 0xffffe000, 0, SROM13_PDOFFSET20IN40M2G, 0xffff},
+ {"pdoffset20in40m2gcore3", 0xffffe000, 0, SROM13_PDOFFSET20IN40M2GCORE3, 0xffff},
+ {"pdoffsetcck20m", 0xffffe000, 0, SROM13_PDOFF_2G_CCK_20M, 0xffff},
+
+ /* power per rate */
+ {"mcs1024qam2gpo", 0xffffe000, 0, SROM13_MCS1024QAM2GPO, 0xffff},
+ {"mcs1024qam5glpo", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GLPO, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCS1024QAM5GLPO_1, 0xffff},
+ {"mcs1024qam5gmpo", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GMPO, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCS1024QAM5GMPO_1, 0xffff},
+ {"mcs1024qam5ghpo", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GHPO, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCS1024QAM5GHPO_1, 0xffff},
+ {"mcs1024qam5gx1po", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GX1PO, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCS1024QAM5GX1PO_1, 0xffff},
+ {"mcs1024qam5gx2po", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GX2PO, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCS1024QAM5GX2PO_1, 0xffff},
+
+ {"mcsbw1605glpo", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GLPO, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCSBW1605GLPO_1, 0xffff},
+ {"mcsbw1605gmpo", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GMPO, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCSBW1605GMPO_1, 0xffff},
+ {"mcsbw1605ghpo", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GHPO, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCSBW1605GHPO_1, 0xffff},
+ {"mcsbw1605gx1po", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GX1PO, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCSBW1605GX1PO_1, 0xffff},
+ {"mcsbw1605gx2po", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GX2PO, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCSBW1605GX2PO_1, 0xffff},
+
+ {"ulbpproffs2g", 0xffffe000, 0, SROM13_ULBPPROFFS2G, 0xffff},
+
+ {"mcs8poexp", 0xffffe000, SRFL_MORE, SROM13_MCS8POEXP, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCS8POEXP_1, 0xffff},
+ {"mcs9poexp", 0xffffe000, SRFL_MORE, SROM13_MCS9POEXP, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCS9POEXP_1, 0xffff},
+ {"mcs10poexp", 0xffffe000, SRFL_MORE, SROM13_MCS10POEXP, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCS10POEXP_1, 0xffff},
+ {"mcs11poexp", 0xffffe000, SRFL_MORE, SROM13_MCS11POEXP, 0xffff},
+ {"", 0xffffe000, 0, SROM13_MCS11POEXP_1, 0xffff},
+
+ {"ulbpdoffs5gb0a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A0, 0xffff},
+ {"ulbpdoffs5gb0a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A1, 0xffff},
+ {"ulbpdoffs5gb0a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A2, 0xffff},
+ {"ulbpdoffs5gb0a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A3, 0xffff},
+ {"ulbpdoffs5gb1a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A0, 0xffff},
+ {"ulbpdoffs5gb1a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A1, 0xffff},
+ {"ulbpdoffs5gb1a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A2, 0xffff},
+ {"ulbpdoffs5gb1a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A3, 0xffff},
+ {"ulbpdoffs5gb2a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A0, 0xffff},
+ {"ulbpdoffs5gb2a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A1, 0xffff},
+ {"ulbpdoffs5gb2a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A2, 0xffff},
+ {"ulbpdoffs5gb2a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A3, 0xffff},
+ {"ulbpdoffs5gb3a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A0, 0xffff},
+ {"ulbpdoffs5gb3a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A1, 0xffff},
+ {"ulbpdoffs5gb3a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A2, 0xffff},
+ {"ulbpdoffs5gb3a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A3, 0xffff},
+ {"ulbpdoffs5gb4a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A0, 0xffff},
+ {"ulbpdoffs5gb4a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A1, 0xffff},
+ {"ulbpdoffs5gb4a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A2, 0xffff},
+ {"ulbpdoffs5gb4a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A3, 0xffff},
+ {"ulbpdoffs2ga0", 0xffffe000, 0, SROM13_ULBPDOFFS2GA0, 0xffff},
+ {"ulbpdoffs2ga1", 0xffffe000, 0, SROM13_ULBPDOFFS2GA1, 0xffff},
+ {"ulbpdoffs2ga2", 0xffffe000, 0, SROM13_ULBPDOFFS2GA2, 0xffff},
+ {"ulbpdoffs2ga3", 0xffffe000, 0, SROM13_ULBPDOFFS2GA3, 0xffff},
+
+ {"rpcal5gb4", 0xffffe000, 0, SROM13_RPCAL5GB4, 0xffff},
+
+ {"sb20in40hrlrpox", 0xffffe000, 0, SROM13_SB20IN40HRLRPOX, 0xffff},
+
+ {"swctrlmap4_cfg", 0xffffe000, 0, SROM13_SWCTRLMAP4_CFG, 0xffff},
+ {"swctrlmap4_TX2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX2G_FEM3TO0, 0xffff},
+ {"swctrlmap4_RX2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX2G_FEM3TO0, 0xffff},
+ {"swctrlmap4_RXByp2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP2G_FEM3TO0, 0xffff},
+ {"swctrlmap4_misc2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC2G_FEM3TO0, 0xffff},
+ {"swctrlmap4_TX5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX5G_FEM3TO0, 0xffff},
+ {"swctrlmap4_RX5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX5G_FEM3TO0, 0xffff},
+ {"swctrlmap4_RXByp5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP5G_FEM3TO0, 0xffff},
+ {"swctrlmap4_misc5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC5G_FEM3TO0, 0xffff},
+ {"swctrlmap4_TX2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX2G_FEM7TO4, 0xffff},
+ {"swctrlmap4_RX2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX2G_FEM7TO4, 0xffff},
+ {"swctrlmap4_RXByp2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP2G_FEM7TO4, 0xffff},
+ {"swctrlmap4_misc2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC2G_FEM7TO4, 0xffff},
+ {"swctrlmap4_TX5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX5G_FEM7TO4, 0xffff},
+ {"swctrlmap4_RX5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX5G_FEM7TO4, 0xffff},
+ {"swctrlmap4_RXByp5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP5G_FEM7TO4, 0xffff},
+ {"swctrlmap4_misc5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC5G_FEM7TO4, 0xffff},
+ {NULL, 0, 0, 0, 0}
+};
+#endif /* !defined(SROM15_MEMOPT) */
+
+static const sromvar_t BCMATTACHDATA(pci_srom15vars)[] = {
+ {"macaddr", 0x00008000, SRFL_ETHADDR, SROM15_MACHI, 0xffff},
+ {"caldata_offset", 0x00008000, 0, SROM15_CAL_OFFSET_LOC, 0xffff},
+ {NULL, 0, 0, 0, 0}
+};
+
+static const sromvar_t perpath_pci_sromvars[] = {
+ {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff},
+ {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00},
+ {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00},
+ {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff},
+ {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff},
+ {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff},
+ {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff},
+ {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff},
+ {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff},
+ {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00},
+ {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff},
+ {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff},
+ {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff},
+ {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff},
+ {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff},
+ {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff},
+ {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff},
+ {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff},
+ {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff},
+ {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff},
+ {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff},
+ {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff},
+ {"maxp2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0x00ff},
+ {"itt2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0xff00},
+ {"itt5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0xff00},
+ {"pa2gw0a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
+ {"pa2gw1a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff},
+ {"pa2gw2a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff},
+ {"maxp5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0x00ff},
+ {"maxp5gha", 0x00000700, 0, SROM8_5GLH_MAXP, 0x00ff},
+ {"maxp5gla", 0x00000700, 0, SROM8_5GLH_MAXP, 0xff00},
+ {"pa5gw0a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
+ {"pa5gw1a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff},
+ {"pa5gw2a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff},
+ {"pa5glw0a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
+ {"pa5glw1a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff},
+ {"pa5glw2a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff},
+ {"pa5ghw0a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
+ {"pa5ghw1a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff},
+ {"pa5ghw2a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff},
+
+ /* sromrev 11 */
+ {"maxp2ga", 0xfffff800, 0, SROM11_2G_MAXP, 0x00ff},
+ {"pa2ga", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA + 1, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX, SROM11_2G_PA + 2, 0xffff},
+ {"rxgains5gmelnagaina", 0x00000800, 0, SROM11_RXGAINS1, 0x0007},
+ {"rxgains5gmtrisoa", 0x00000800, 0, SROM11_RXGAINS1, 0x0078},
+ {"rxgains5gmtrelnabypa", 0x00000800, 0, SROM11_RXGAINS1, 0x0080},
+ {"rxgains5ghelnagaina", 0x00000800, 0, SROM11_RXGAINS1, 0x0700},
+ {"rxgains5ghtrisoa", 0x00000800, 0, SROM11_RXGAINS1, 0x7800},
+ {"rxgains5ghtrelnabypa", 0x00000800, 0, SROM11_RXGAINS1, 0x8000},
+ {"rxgains2gelnagaina", 0x00000800, 0, SROM11_RXGAINS, 0x0007},
+ {"rxgains2gtrisoa", 0x00000800, 0, SROM11_RXGAINS, 0x0078},
+ {"rxgains2gtrelnabypa", 0x00000800, 0, SROM11_RXGAINS, 0x0080},
+ {"rxgains5gelnagaina", 0x00000800, 0, SROM11_RXGAINS, 0x0700},
+ {"rxgains5gtrisoa", 0x00000800, 0, SROM11_RXGAINS, 0x7800},
+ {"rxgains5gtrelnabypa", 0x00000800, 0, SROM11_RXGAINS, 0x8000},
+ {"maxp5ga", 0x00000800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0x00ff},
+ {"", 0x00000800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0xff00},
+ {"", 0x00000800, SRFL_ARRAY, SROM11_5GB3B2_MAXP, 0x00ff},
+ {"", 0x00000800, 0, SROM11_5GB3B2_MAXP, 0xff00},
+ {"pa5ga", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 1, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 2, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 1, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 2, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 1, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 2, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA + 1, 0xffff},
+ {"", 0x00000800, SRFL_PRHEX, SROM11_5GB3_PA + 2, 0xffff},
+
+ /* sromrev 12 */
+ {"maxp5gb4a", 0xfffff000, 0, SROM12_5GB42G_MAXP, 0x00ff00},
+ {"pa2ga", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2GB0_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2GB0_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2GB0_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX, SROM12_2GB0_PA_W3, 0x00ffff},
+
+ {"pa2g40a", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2G40B0_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2G40B0_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2G40B0_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX, SROM12_2G40B0_PA_W3, 0x00ffff},
+ {"maxp5gb0a", 0xfffff000, 0, SROM12_5GB1B0_MAXP, 0x00ff},
+ {"maxp5gb1a", 0xfffff000, 0, SROM12_5GB1B0_MAXP, 0x00ff00},
+ {"maxp5gb2a", 0xfffff000, 0, SROM12_5GB3B2_MAXP, 0x00ff},
+ {"maxp5gb3a", 0xfffff000, 0, SROM12_5GB3B2_MAXP, 0x00ff00},
+
+ {"pa5ga", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB4_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB4_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB4_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX, SROM12_5GB4_PA_W3, 0x00ffff},
+
+ {"pa5g40a", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B4_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B4_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B4_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX, SROM12_5G40B4_PA_W3, 0x00ffff},
+
+ {"pa5g80a", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W3, 0x00ffff},
+
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B4_PA_W0, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B4_PA_W1, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B4_PA_W2, 0x00ffff},
+ {"", 0xfffff000, SRFL_PRHEX, SROM12_5G80B4_PA_W3, 0x00ffff},
+ /* sromrev 13 */
+ {"rxgains2gelnagaina", 0xffffe000, 0, SROM13_RXGAINS, 0x0007},
+ {"rxgains2gtrisoa", 0xffffe000, 0, SROM13_RXGAINS, 0x0078},
+ {"rxgains2gtrelnabypa", 0xffffe000, 0, SROM13_RXGAINS, 0x0080},
+ {"rxgains5gelnagaina", 0xffffe000, 0, SROM13_RXGAINS, 0x0700},
+ {"rxgains5gtrisoa", 0xffffe000, 0, SROM13_RXGAINS, 0x7800},
+ {"rxgains5gtrelnabypa", 0xffffe000, 0, SROM13_RXGAINS, 0x8000},
+ {NULL, 0, 0, 0, 0}
+};
+
+#if !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N))
+#define PHY_TYPE_HT 7 /* HT-Phy value */
+#define PHY_TYPE_N 4 /* N-Phy value */
+#endif /* !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N)) */
+#if !defined(PHY_TYPE_AC)
+#define PHY_TYPE_AC 11 /* AC-Phy value */
+#endif /* !defined(PHY_TYPE_AC) */
+#if !defined(PHY_TYPE_LCN20)
+#define PHY_TYPE_LCN20 12 /* LCN20-Phy value */
+#endif /* !defined(PHY_TYPE_LCN20) */
+#if !defined(PHY_TYPE_NULL)
+#define PHY_TYPE_NULL 0xf /* Invalid Phy value */
+#endif /* !defined(PHY_TYPE_NULL) */
+
+typedef struct {
+ uint16 phy_type;
+ uint16 bandrange;
+ uint16 chain;
+ const char *vars;
+} pavars_t;
+
+static const pavars_t pavars[] = {
+ /* HTPHY */
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 2, "pa2gw0a2 pa2gw1a2 pa2gw2a2"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 2, "pa5glw0a2 pa5glw1a2 pa5glw2a2"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 2, "pa5gw0a2 pa5gw1a2 pa5gw2a2"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 2, "pa5ghw0a2 pa5ghw1a2 pa5ghw2a2"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 0, "pa5gw0a3 pa5gw1a3 pa5gw2a3"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 1, "pa5glw0a3 pa5glw1a3 pa5glw2a3"},
+ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 2, "pa5ghw0a3 pa5ghw1a3 pa5ghw2a3"},
+ /* NPHY */
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"},
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"},
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"},
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"},
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"},
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"},
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"},
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"},
+ /* ACPHY */
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5ga2"},
+ /* LCN20PHY */
+ {PHY_TYPE_LCN20, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"},
+ {PHY_TYPE_NULL, 0, 0, ""}
+};
+
+
+static const pavars_t pavars_SROM12[] = {
+ /* ACPHY */
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 0, "pa2g40a0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 1, "pa2g40a1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 2, "pa2g40a2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 0, "pa5ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 1, "pa5ga1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 2, "pa5ga2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 0, "pa5g40a0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 1, "pa5g40a1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 2, "pa5g40a2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 0, "pa5g80a0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 1, "pa5g80a1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 2, "pa5g80a2"},
+ {PHY_TYPE_NULL, 0, 0, ""}
+};
+
+static const pavars_t pavars_SROM13[] = {
+ /* ACPHY */
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 3, "pa2ga3"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 0, "pa2g40a0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 1, "pa2g40a1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 2, "pa2g40a2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 3, "pa2g40a3"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 0, "pa5ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 1, "pa5ga1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 2, "pa5ga2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 3, "pa5ga3"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 0, "pa5g40a0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 1, "pa5g40a1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 2, "pa5g40a2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 3, "pa5g40a3"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 0, "pa5g80a0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 1, "pa5g80a1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 2, "pa5g80a2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 3, "pa5g80a3"},
+ {PHY_TYPE_NULL, 0, 0, ""}
+};
+
+/* pavars table when paparambwver is 1 */
+static const pavars_t pavars_bwver_1[] = {
+ /* ACPHY */
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gccka0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga2"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5gbw40a0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw80a0"},
+ {PHY_TYPE_NULL, 0, 0, ""}
+};
+
+/* pavars table when paparambwver is 2 */
+static const pavars_t pavars_bwver_2[] = {
+ /* ACPHY */
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw4080a0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 3, "pa5gbw4080a1"},
+ {PHY_TYPE_NULL, 0, 0, ""}
+};
+
+/* pavars table when paparambwver is 3 */
+static const pavars_t pavars_bwver_3[] = {
+ /* ACPHY */
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2gccka0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 3, "pa2gccka1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw4080a0"},
+ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 3, "pa5gbw4080a1"},
+ {PHY_TYPE_NULL, 0, 0, ""}
+};
+
+typedef struct {
+ uint16 phy_type;
+ uint16 bandrange;
+ const char *vars;
+} povars_t;
+
+static const povars_t povars[] = {
+ /* NPHY */
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, "mcs2gpo0 mcs2gpo1 mcs2gpo2 mcs2gpo3 "
+ "mcs2gpo4 mcs2gpo5 mcs2gpo6 mcs2gpo7"},
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, "mcs5glpo0 mcs5glpo1 mcs5glpo2 mcs5glpo3 "
+ "mcs5glpo4 mcs5glpo5 mcs5glpo6 mcs5glpo7"},
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, "mcs5gpo0 mcs5gpo1 mcs5gpo2 mcs5gpo3 "
+ "mcs5gpo4 mcs5gpo5 mcs5gpo6 mcs5gpo7"},
+ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, "mcs5ghpo0 mcs5ghpo1 mcs5ghpo2 mcs5ghpo3 "
+ "mcs5ghpo4 mcs5ghpo5 mcs5ghpo6 mcs5ghpo7"},
+ {PHY_TYPE_NULL, 0, ""}
+};
+
+typedef struct {
+ uint8 tag; /* Broadcom subtag name */
+ uint32 revmask; /* Supported cis_sromrev bitmask. Some of the parameters in
+ * different tuples have the same name. Therefore, the MFGc tool
+ * needs to know which tuple to generate when seeing these
+ * parameters (given that we know sromrev from user input, like the
+ * nvram file).
+ */
+ uint8 len; /* Length field of the tuple, note that it includes the
+ * subtag name (1 byte): 1 + tuple content length
+ */
+ const char *params;
+} cis_tuple_t;
+
+#define OTP_RAW (0xff - 1) /* Reserved tuple number for wrvar Raw input */
+#define OTP_VERS_1 (0xff - 2) /* CISTPL_VERS_1 */
+#define OTP_MANFID (0xff - 3) /* CISTPL_MANFID */
+#define OTP_RAW1 (0xff - 4) /* Like RAW, but comes first */
+
+/** this array is used by CIS creating/writing applications */
+static const cis_tuple_t cis_hnbuvars[] = {
+/* tag revmask len params */
+ {OTP_RAW1, 0xffffffff, 0, ""}, /* special case */
+ {OTP_VERS_1, 0xffffffff, 0, "smanf sproductname"}, /* special case (non BRCM tuple) */
+ {OTP_MANFID, 0xffffffff, 4, "2manfid 2prodid"}, /* special case (non BRCM tuple) */
+ /* Unified OTP: tupple to embed USB manfid inside SDIO CIS */
+ {HNBU_UMANFID, 0xffffffff, 8, "8usbmanfid"},
+ {HNBU_SROMREV, 0xffffffff, 2, "1sromrev"},
+ /* NOTE: subdevid is also written to boardtype.
+ * Need to write HNBU_BOARDTYPE to change it if it is different.
+ */
+ {HNBU_CHIPID, 0xffffffff, 11, "2vendid 2devid 2chiprev 2subvendid 2subdevid"},
+ {HNBU_BOARDREV, 0xffffffff, 3, "2boardrev"},
+ {HNBU_PAPARMS, 0xffffffff, 10, "2pa0b0 2pa0b1 2pa0b2 1pa0itssit 1pa0maxpwr 1opo"},
+ {HNBU_AA, 0xffffffff, 3, "1aa2g 1aa5g"},
+ {HNBU_AA, 0xffffffff, 3, "1aa0 1aa1"}, /* backward compatibility */
+ {HNBU_AG, 0xffffffff, 5, "1ag0 1ag1 1ag2 1ag3"},
+ {HNBU_BOARDFLAGS, 0xffffffff, 21, "4boardflags 4boardflags2 4boardflags3 "
+ "4boardflags4 4boardflags5 "},
+ {HNBU_LEDS, 0xffffffff, 17, "1ledbh0 1ledbh1 1ledbh2 1ledbh3 1ledbh4 1ledbh5 "
+ "1ledbh6 1ledbh7 1ledbh8 1ledbh9 1ledbh10 1ledbh11 1ledbh12 1ledbh13 1ledbh14 1ledbh15"},
+ {HNBU_CCODE, 0xffffffff, 4, "2ccode 1cctl"},
+ {HNBU_CCKPO, 0xffffffff, 3, "2cckpo"},
+ {HNBU_OFDMPO, 0xffffffff, 5, "4ofdmpo"},
+ {HNBU_PAPARMS5G, 0xffffffff, 23, "2pa1b0 2pa1b1 2pa1b2 2pa1lob0 2pa1lob1 2pa1lob2 "
+ "2pa1hib0 2pa1hib1 2pa1hib2 1pa1itssit "
+ "1pa1maxpwr 1pa1lomaxpwr 1pa1himaxpwr"},
+ {HNBU_RDLID, 0xffffffff, 3, "2rdlid"},
+ {HNBU_RSSISMBXA2G, 0xffffffff, 3, "0rssismf2g 0rssismc2g "
+ "0rssisav2g 0bxa2g"}, /* special case */
+ {HNBU_RSSISMBXA5G, 0xffffffff, 3, "0rssismf5g 0rssismc5g "
+ "0rssisav5g 0bxa5g"}, /* special case */
+ {HNBU_XTALFREQ, 0xffffffff, 5, "4xtalfreq"},
+ {HNBU_TRI2G, 0xffffffff, 2, "1tri2g"},
+ {HNBU_TRI5G, 0xffffffff, 4, "1tri5gl 1tri5g 1tri5gh"},
+ {HNBU_RXPO2G, 0xffffffff, 2, "1rxpo2g"},
+ {HNBU_RXPO5G, 0xffffffff, 2, "1rxpo5g"},
+ {HNBU_BOARDNUM, 0xffffffff, 3, "2boardnum"},
+ {HNBU_MACADDR, 0xffffffff, 7, "6macaddr"}, /* special case */
+ {HNBU_RDLSN, 0xffffffff, 3, "2rdlsn"},
+ {HNBU_BOARDTYPE, 0xffffffff, 3, "2boardtype"},
+ {HNBU_LEDDC, 0xffffffff, 3, "2leddc"},
+ {HNBU_RDLRNDIS, 0xffffffff, 2, "1rdlndis"},
+ {HNBU_CHAINSWITCH, 0xffffffff, 5, "1txchain 1rxchain 2antswitch"},
+ {HNBU_REGREV, 0xffffffff, 3, "2regrev"},
+ {HNBU_FEM, 0x000007fe, 5, "0antswctl2g 0triso2g 0pdetrange2g 0extpagain2g "
+ "0tssipos2g 0antswctl5g 0triso5g 0pdetrange5g 0extpagain5g 0tssipos5g"}, /* special case */
+ {HNBU_PAPARMS_C0, 0x000007fe, 31, "1maxp2ga0 1itt2ga0 2pa2gw0a0 2pa2gw1a0 "
+ "2pa2gw2a0 1maxp5ga0 1itt5ga0 1maxp5gha0 1maxp5gla0 2pa5gw0a0 2pa5gw1a0 2pa5gw2a0 "
+ "2pa5glw0a0 2pa5glw1a0 2pa5glw2a0 2pa5ghw0a0 2pa5ghw1a0 2pa5ghw2a0"},
+ {HNBU_PAPARMS_C1, 0x000007fe, 31, "1maxp2ga1 1itt2ga1 2pa2gw0a1 2pa2gw1a1 "
+ "2pa2gw2a1 1maxp5ga1 1itt5ga1 1maxp5gha1 1maxp5gla1 2pa5gw0a1 2pa5gw1a1 2pa5gw2a1 "
+ "2pa5glw0a1 2pa5glw1a1 2pa5glw2a1 2pa5ghw0a1 2pa5ghw1a1 2pa5ghw2a1"},
+ {HNBU_PO_CCKOFDM, 0xffffffff, 19, "2cck2gpo 4ofdm2gpo 4ofdm5gpo 4ofdm5glpo "
+ "4ofdm5ghpo"},
+ {HNBU_PO_MCS2G, 0xffffffff, 17, "2mcs2gpo0 2mcs2gpo1 2mcs2gpo2 2mcs2gpo3 "
+ "2mcs2gpo4 2mcs2gpo5 2mcs2gpo6 2mcs2gpo7"},
+ {HNBU_PO_MCS5GM, 0xffffffff, 17, "2mcs5gpo0 2mcs5gpo1 2mcs5gpo2 2mcs5gpo3 "
+ "2mcs5gpo4 2mcs5gpo5 2mcs5gpo6 2mcs5gpo7"},
+ {HNBU_PO_MCS5GLH, 0xffffffff, 33, "2mcs5glpo0 2mcs5glpo1 2mcs5glpo2 2mcs5glpo3 "
+ "2mcs5glpo4 2mcs5glpo5 2mcs5glpo6 2mcs5glpo7 "
+ "2mcs5ghpo0 2mcs5ghpo1 2mcs5ghpo2 2mcs5ghpo3 "
+ "2mcs5ghpo4 2mcs5ghpo5 2mcs5ghpo6 2mcs5ghpo7"},
+ {HNBU_CCKFILTTYPE, 0xffffffff, 2, "1cckdigfilttype"},
+ {HNBU_PO_CDD, 0xffffffff, 3, "2cddpo"},
+ {HNBU_PO_STBC, 0xffffffff, 3, "2stbcpo"},
+ {HNBU_PO_40M, 0xffffffff, 3, "2bw40po"},
+ {HNBU_PO_40MDUP, 0xffffffff, 3, "2bwduppo"},
+ {HNBU_RDLRWU, 0xffffffff, 2, "1rdlrwu"},
+ {HNBU_WPS, 0xffffffff, 3, "1wpsgpio 1wpsled"},
+ {HNBU_USBFS, 0xffffffff, 2, "1usbfs"},
+ {HNBU_ELNA2G, 0xffffffff, 2, "1elna2g"},
+ {HNBU_ELNA5G, 0xffffffff, 2, "1elna5g"},
+ {HNBU_CUSTOM1, 0xffffffff, 5, "4customvar1"},
+ {OTP_RAW, 0xffffffff, 0, ""}, /* special case */
+ {HNBU_OFDMPO5G, 0xffffffff, 13, "4ofdm5gpo 4ofdm5glpo 4ofdm5ghpo"},
+ {HNBU_USBEPNUM, 0xffffffff, 3, "2usbepnum"},
+ {HNBU_CCKBW202GPO, 0xffffffff, 7, "2cckbw202gpo 2cckbw20ul2gpo 2cckbw20in802gpo"},
+ {HNBU_LEGOFDMBW202GPO, 0xffffffff, 9, "4legofdmbw202gpo 4legofdmbw20ul2gpo"},
+ {HNBU_LEGOFDMBW205GPO, 0xffffffff, 25, "4legofdmbw205glpo 4legofdmbw20ul5glpo "
+ "4legofdmbw205gmpo 4legofdmbw20ul5gmpo 4legofdmbw205ghpo 4legofdmbw20ul5ghpo"},
+ {HNBU_MCS2GPO, 0xffffffff, 17, "4mcsbw202gpo 4mcsbw20ul2gpo 4mcsbw402gpo 4mcsbw802gpo"},
+ {HNBU_MCS5GLPO, 0xffffffff, 13, "4mcsbw205glpo 4mcsbw20ul5glpo 4mcsbw405glpo"},
+ {HNBU_MCS5GMPO, 0xffffffff, 13, "4mcsbw205gmpo 4mcsbw20ul5gmpo 4mcsbw405gmpo"},
+ {HNBU_MCS5GHPO, 0xffffffff, 13, "4mcsbw205ghpo 4mcsbw20ul5ghpo 4mcsbw405ghpo"},
+ {HNBU_MCS32PO, 0xffffffff, 3, "2mcs32po"},
+ {HNBU_LEG40DUPPO, 0xffffffff, 3, "2legofdm40duppo"},
+ {HNBU_TEMPTHRESH, 0xffffffff, 7, "1tempthresh 0temps_period 0temps_hysteresis "
+ "1tempoffset 1tempsense_slope 0tempcorrx 0tempsense_option "
+ "1phycal_tempdelta"}, /* special case */
+ {HNBU_MUXENAB, 0xffffffff, 2, "1muxenab"},
+ {HNBU_FEM_CFG, 0xfffff800, 5, "0femctrl 0papdcap2g 0tworangetssi2g 0pdgain2g "
+ "0epagain2g 0tssiposslope2g 0gainctrlsph 0papdcap5g 0tworangetssi5g 0pdgain5g 0epagain5g "
+ "0tssiposslope5g"}, /* special case */
+ {HNBU_ACPA_C0, 0x00001800, 39, "2subband5gver 2maxp2ga0 2*3pa2ga0 "
+ "1*4maxp5ga0 2*12pa5ga0"},
+ {HNBU_ACPA_C1, 0x00001800, 37, "2maxp2ga1 2*3pa2ga1 1*4maxp5ga1 2*12pa5ga1"},
+ {HNBU_ACPA_C2, 0x00001800, 37, "2maxp2ga2 2*3pa2ga2 1*4maxp5ga2 2*12pa5ga2"},
+ {HNBU_MEAS_PWR, 0xfffff800, 5, "1measpower 1measpower1 1measpower2 2rawtempsense"},
+ {HNBU_PDOFF, 0xfffff800, 13, "2pdoffset40ma0 2pdoffset40ma1 2pdoffset40ma2 "
+ "2pdoffset80ma0 2pdoffset80ma1 2pdoffset80ma2"},
+ {HNBU_ACPPR_2GPO, 0xfffff800, 13, "2dot11agofdmhrbw202gpo 2ofdmlrbw202gpo "
+ "2sb20in40dot11agofdm2gpo 2sb20in80dot11agofdm2gpo 2sb20in40ofdmlrbw202gpo "
+ "2sb20in80ofdmlrbw202gpo"},
+ {HNBU_ACPPR_5GPO, 0xfffff800, 59, "4mcsbw805glpo 4mcsbw1605glpo 4mcsbw805gmpo "
+ "4mcsbw1605gmpo 4mcsbw805ghpo 4mcsbw1605ghpo 2mcslr5glpo 2mcslr5gmpo 2mcslr5ghpo "
+ "4mcsbw80p805glpo 4mcsbw80p805gmpo 4mcsbw80p805ghpo 4mcsbw80p805gx1po 2mcslr5gx1po "
+ "2mcslr5g80p80po 4mcsbw805gx1po 4mcsbw1605gx1po"},
+ {HNBU_MCS5Gx1PO, 0xfffff800, 9, "4mcsbw205gx1po 4mcsbw405gx1po"},
+ {HNBU_ACPPR_SBPO, 0xfffff800, 49, "2sb20in40hrpo 2sb20in80and160hr5glpo "
+ "2sb40and80hr5glpo 2sb20in80and160hr5gmpo 2sb40and80hr5gmpo 2sb20in80and160hr5ghpo "
+ "2sb40and80hr5ghpo 2sb20in40lrpo 2sb20in80and160lr5glpo 2sb40and80lr5glpo "
+ "2sb20in80and160lr5gmpo 2sb40and80lr5gmpo 2sb20in80and160lr5ghpo 2sb40and80lr5ghpo "
+ "4dot11agduphrpo 4dot11agduplrpo 2sb20in40and80hrpo 2sb20in40and80lrpo "
+ "2sb20in80and160hr5gx1po 2sb20in80and160lr5gx1po 2sb40and80hr5gx1po 2sb40and80lr5gx1po "
+ },
+ {HNBU_ACPPR_SB8080_PO, 0xfffff800, 23, "2sb2040and80in80p80hr5glpo "
+ "2sb2040and80in80p80lr5glpo 2sb2040and80in80p80hr5gmpo "
+ "2sb2040and80in80p80lr5gmpo 2sb2040and80in80p80hr5ghpo 2sb2040and80in80p80lr5ghpo "
+ "2sb2040and80in80p80hr5gx1po 2sb2040and80in80p80lr5gx1po 2sb20in80p80hr5gpo "
+ "2sb20in80p80lr5gpo 2dot11agduppo"},
+ {HNBU_NOISELVL, 0xfffff800, 16, "1noiselvl2ga0 1noiselvl2ga1 1noiselvl2ga2 "
+ "1*4noiselvl5ga0 1*4noiselvl5ga1 1*4noiselvl5ga2"},
+ {HNBU_RXGAIN_ERR, 0xfffff800, 16, "1rxgainerr2ga0 1rxgainerr2ga1 1rxgainerr2ga2 "
+ "1*4rxgainerr5ga0 1*4rxgainerr5ga1 1*4rxgainerr5ga2"},
+ {HNBU_AGBGA, 0xfffff800, 7, "1agbg0 1agbg1 1agbg2 1aga0 1aga1 1aga2"},
+ {HNBU_USBDESC_COMPOSITE, 0xffffffff, 3, "2usbdesc_composite"},
+ {HNBU_UUID, 0xffffffff, 17, "16uuid"},
+ {HNBU_WOWLGPIO, 0xffffffff, 2, "1wowl_gpio"},
+ {HNBU_ACRXGAINS_C0, 0xfffff800, 5, "0rxgains5gtrelnabypa0 0rxgains5gtrisoa0 "
+ "0rxgains5gelnagaina0 0rxgains2gtrelnabypa0 0rxgains2gtrisoa0 0rxgains2gelnagaina0 "
+ "0rxgains5ghtrelnabypa0 0rxgains5ghtrisoa0 0rxgains5ghelnagaina0 0rxgains5gmtrelnabypa0 "
+ "0rxgains5gmtrisoa0 0rxgains5gmelnagaina0"}, /* special case */
+ {HNBU_ACRXGAINS_C1, 0xfffff800, 5, "0rxgains5gtrelnabypa1 0rxgains5gtrisoa1 "
+ "0rxgains5gelnagaina1 0rxgains2gtrelnabypa1 0rxgains2gtrisoa1 0rxgains2gelnagaina1 "
+ "0rxgains5ghtrelnabypa1 0rxgains5ghtrisoa1 0rxgains5ghelnagaina1 0rxgains5gmtrelnabypa1 "
+ "0rxgains5gmtrisoa1 0rxgains5gmelnagaina1"}, /* special case */
+ {HNBU_ACRXGAINS_C2, 0xfffff800, 5, "0rxgains5gtrelnabypa2 0rxgains5gtrisoa2 "
+ "0rxgains5gelnagaina2 0rxgains2gtrelnabypa2 0rxgains2gtrisoa2 0rxgains2gelnagaina2 "
+ "0rxgains5ghtrelnabypa2 0rxgains5ghtrisoa2 0rxgains5ghelnagaina2 0rxgains5gmtrelnabypa2 "
+ "0rxgains5gmtrisoa2 0rxgains5gmelnagaina2"}, /* special case */
+ {HNBU_TXDUTY, 0xfffff800, 9, "2tx_duty_cycle_ofdm_40_5g "
+ "2tx_duty_cycle_thresh_40_5g 2tx_duty_cycle_ofdm_80_5g 2tx_duty_cycle_thresh_80_5g"},
+ {HNBU_PDOFF_2G, 0xfffff800, 3, "0pdoffset2g40ma0 0pdoffset2g40ma1 "
+ "0pdoffset2g40ma2 0pdoffset2g40mvalid"},
+ {HNBU_ACPA_CCK_C0, 0xfffff800, 7, "2*3pa2gccka0"},
+ {HNBU_ACPA_CCK_C1, 0xfffff800, 7, "2*3pa2gccka1"},
+ {HNBU_ACPA_40, 0xfffff800, 25, "2*12pa5gbw40a0"},
+ {HNBU_ACPA_80, 0xfffff800, 25, "2*12pa5gbw80a0"},
+ {HNBU_ACPA_4080, 0xfffff800, 49, "2*12pa5gbw4080a0 2*12pa5gbw4080a1"},
+ {HNBU_ACPA_4X4C0, 0xffffe000, 23, "1maxp2ga0 2*4pa2ga0 2*4pa2g40a0 "
+ "1maxp5gb0a0 1maxp5gb1a0 1maxp5gb2a0 1maxp5gb3a0 1maxp5gb4a0"},
+ {HNBU_ACPA_4X4C1, 0xffffe000, 23, "1maxp2ga1 2*4pa2ga1 2*4pa2g40a1 "
+ "1maxp5gb0a1 1maxp5gb1a1 1maxp5gb2a1 1maxp5gb3a1 1maxp5gb4a1"},
+ {HNBU_ACPA_4X4C2, 0xffffe000, 23, "1maxp2ga2 2*4pa2ga2 2*4pa2g40a2 "
+ "1maxp5gb0a2 1maxp5gb1a2 1maxp5gb2a2 1maxp5gb3a2 1maxp5gb4a2"},
+ {HNBU_ACPA_4X4C3, 0xffffe000, 23, "1maxp2ga3 2*4pa2ga3 2*4pa2g40a3 "
+ "1maxp5gb0a3 1maxp5gb1a3 1maxp5gb2a3 1maxp5gb3a3 1maxp5gb4a3"},
+ {HNBU_ACPA_BW20_4X4C0, 0xffffe000, 41, "2*20pa5ga0"},
+ {HNBU_ACPA_BW40_4X4C0, 0xffffe000, 41, "2*20pa5g40a0"},
+ {HNBU_ACPA_BW80_4X4C0, 0xffffe000, 41, "2*20pa5g80a0"},
+ {HNBU_ACPA_BW20_4X4C1, 0xffffe000, 41, "2*20pa5ga1"},
+ {HNBU_ACPA_BW40_4X4C1, 0xffffe000, 41, "2*20pa5g40a1"},
+ {HNBU_ACPA_BW80_4X4C1, 0xffffe000, 41, "2*20pa5g80a1"},
+ {HNBU_ACPA_BW20_4X4C2, 0xffffe000, 41, "2*20pa5ga2"},
+ {HNBU_ACPA_BW40_4X4C2, 0xffffe000, 41, "2*20pa5g40a2"},
+ {HNBU_ACPA_BW80_4X4C2, 0xffffe000, 41, "2*20pa5g80a2"},
+ {HNBU_ACPA_BW20_4X4C3, 0xffffe000, 41, "2*20pa5ga3"},
+ {HNBU_ACPA_BW40_4X4C3, 0xffffe000, 41, "2*20pa5g40a3"},
+ {HNBU_ACPA_BW80_4X4C3, 0xffffe000, 41, "2*20pa5g80a3"},
+ {HNBU_SUBBAND5GVER, 0xfffff800, 3, "2subband5gver"},
+ {HNBU_PAPARAMBWVER, 0xfffff800, 2, "1paparambwver"},
+ {HNBU_TXBFRPCALS, 0xfffff800, 11,
+ "2rpcal2g 2rpcal5gb0 2rpcal5gb1 2rpcal5gb2 2rpcal5gb3"}, /* txbf rpcalvars */
+ {HNBU_GPIO_PULL_DOWN, 0xffffffff, 5, "4gpdn"},
+ {HNBU_MACADDR2, 0xffffffff, 7, "6macaddr2"}, /* special case */
+ {0xFF, 0xffffffff, 0, ""}
+};
+
+#endif /* _bcmsrom_tbl_h_ */
diff --git a/wl/src/include/bcmtlv.h b/wl/src/include/bcmtlv.h
new file mode 100644
index 0000000..ed586f0
--- /dev/null
+++ b/wl/src/include/bcmtlv.h
@@ -0,0 +1,286 @@
+/*
+ * TLV and XTLV support
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: $
+ */
+
+#ifndef _bcmtlv_h_
+#define _bcmtlv_h_
+
+#include <typedefs.h>
+#if defined(__FreeBSD__)
+#include <stdbool.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* begin tlvs - used in 802.11 IEs etc. */
+
+/* type(aka id)/length/value buffer triple */
+typedef struct bcm_tlv {
+ uint8 id;
+ uint8 len;
+ uint8 data[1];
+} bcm_tlv_t;
+
+/* size of tlv including data */
+#define BCM_TLV_SIZE(_tlv) ((_tlv) ? (OFFSETOF(bcm_tlv_t, data) + (_tlv)->len) : 0)
+
+/* get next tlv - no length checks */
+#define BCM_TLV_NEXT(_tlv) (bcm_tlv_t *)((uint8 *)(_tlv)+ BCM_TLV_SIZE(_tlv))
+
+/* tlv length is restricted to 1 byte */
+#define BCM_TLV_MAX_DATA_SIZE (255)
+
+/* tlv header - two bytes */
+#define BCM_TLV_HDR_SIZE (OFFSETOF(bcm_tlv_t, data))
+
+/* Check that bcm_tlv_t fits into the given buffer len */
+#define bcm_valid_tlv(elt, buflen) (\
+ ((int)(buflen) >= (int)BCM_TLV_HDR_SIZE) && \
+ ((int)(buflen) >= (int)(BCM_TLV_HDR_SIZE + (elt)->len)))
+
+/* find the next tlv */
+bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen);
+
+/* find the tlv for a given id */
+bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key);
+
+/*
+ * Traverse tlvs and return pointer to the first tlv that
+ * matches the key. Return NULL if not found or tlv len < min_bodylen
+ */
+bcm_tlv_t *bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen);
+
+/* parse tlvs for dot11 - same as parse_tlvs but supports 802.11 id extension */
+bcm_tlv_t *bcm_parse_tlvs_dot11(void *buf, int buflen, uint key, bool id_ext);
+
+/* same as parse_tlvs, but stops when found id > key */
+bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key);
+
+/* find a tlv with DOT11_MNG_PROPR_ID as id, and the given oui and type */
+bcm_tlv_t *bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type,
+ int type_len);
+
+/* write tlv at dst and return next tlv ptr */
+uint8 *bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst);
+
+/* write tlv at dst if space permits and return next tlv ptr */
+uint8 *bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst,
+ int dst_maxlen);
+
+/* copy a tlv and return next tlv ptr */
+uint8 *bcm_copy_tlv(const void *src, uint8 *dst);
+
+/* copy a tlv if space permits and return next tlv ptr */
+uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen);
+
+/* end tlvs */
+
+/* begin xtlv - used for iovars, nan attributes etc. */
+
+/* bcm type(id), length, value with w/16 bit id/len. The structure below
+ * is nominal, and is used to support variable length id and type. See
+ * xtlv options below.
+ */
+typedef struct bcm_xtlv {
+ uint16 id;
+ uint16 len;
+ uint8 data[1];
+} bcm_xtlv_t;
+
+/* xtlv options */
+#define BCM_XTLV_OPTION_NONE 0x0000
+#define BCM_XTLV_OPTION_ALIGN32 0x0001 /* 32bit alignment of type.len.data */
+#define BCM_XTLV_OPTION_IDU8 0x0002 /* shorter id */
+#define BCM_XTLV_OPTION_LENU8 0x0004 /* shorted length */
+typedef uint16 bcm_xtlv_opts_t;
+
+/* header size. depends on options. Macros names ending w/ _EX are where
+ * options are explcitly specified that may be less common. The ones
+ * without use default values that correspond to ...OPTION_NONE
+ */
+
+/* xtlv header size depends on options */
+#define BCM_XTLV_HDR_SIZE 4
+#define BCM_XTLV_HDR_SIZE_EX(_opts) bcm_xtlv_hdr_size(_opts)
+
+/* note: xtlv len only stores the value's length without padding */
+#define BCM_XTLV_LEN(_elt) ltoh16_ua(&(_elt)->len)
+#define BCM_XTLV_LEN_EX(_elt, _opts) bcm_xtlv_len(_elt, _opts)
+
+#define BCM_XTLV_ID(_elt) ltoh16_ua(&(_elt)->id)
+#define BCM_XTLV_ID_EX(_elt, _opts) bcm_xtlv_id(_elt, _opts)
+
+/* entire size of the XTLV including header, data, and optional padding */
+#define BCM_XTLV_SIZE(elt, opts) bcm_xtlv_size(elt, opts)
+#define BCM_XTLV_SIZE_EX(_elt, _opts) bcm_xtlv_size(_elt, _opts)
+
+/* max xtlv data size */
+#define BCM_XTLV_MAX_DATA_SIZE 65535
+#define BCM_XTLV_MAX_DATA_SIZE_EX(_opts) ((_opts & BCM_XTLV_OPTION_LENU8) ? \
+ 255 : 65535)
+
+/* descriptor of xtlv data, packing(src) and unpacking(dst) support */
+typedef struct {
+ uint16 type;
+ uint16 len;
+ void *ptr; /* ptr to memory location */
+} xtlv_desc_t;
+
+/* xtlv buffer - packing/unpacking support */
+struct bcm_xtlvbuf {
+ bcm_xtlv_opts_t opts;
+ uint16 size;
+ uint8 *head; /* point to head of buffer */
+ uint8 *buf; /* current position of buffer */
+ /* allocated buffer may follow, but not necessarily */
+};
+typedef struct bcm_xtlvbuf bcm_xtlvbuf_t;
+
+/* valid xtlv ? */
+bool bcm_valid_xtlv(const bcm_xtlv_t *elt, int buf_len, bcm_xtlv_opts_t opts);
+
+/* return the next xtlv element, and update buffer len (remaining). Buffer length
+ * updated includes padding as specified by options
+ */
+bcm_xtlv_t *bcm_next_xtlv(bcm_xtlv_t *elt, int *buf_len, bcm_xtlv_opts_t opts);
+
+/* initialize an xtlv buffer. Use options specified for packing/unpacking using
+ * the buffer. Caller is responsible for allocating both buffers.
+ */
+int bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len,
+ bcm_xtlv_opts_t opts);
+
+/* length of data in the xtlv buffer */
+uint16 bcm_xtlv_buf_len(struct bcm_xtlvbuf *tbuf);
+
+/* remaining space in the xtlv buffer */
+uint16 bcm_xtlv_buf_rlen(struct bcm_xtlvbuf *tbuf);
+
+/* write ptr */
+uint8 *bcm_xtlv_buf(struct bcm_xtlvbuf *tbuf);
+
+/* head */
+uint8 *bcm_xtlv_head(struct bcm_xtlvbuf *tbuf);
+
+/* put a data buffer into xtlv */
+int bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n);
+
+/* put one or more u16 elts into xtlv */
+int bcm_xtlv_put16(bcm_xtlvbuf_t *tbuf, uint16 type, const uint16 *data, int n);
+
+/* put one or more u32 elts into xtlv */
+int bcm_xtlv_put32(bcm_xtlvbuf_t *tbuf, uint16 type, const uint32 *data, int n);
+
+/* put one or more u64 elts into xtlv */
+int bcm_xtlv_put64(bcm_xtlvbuf_t *tbuf, uint16 type, const uint64 *data, int n);
+
+/* note: there are no get equivalent of integer unpacking, becasuse bcmendian.h
+ * can be used directly using pointers returned in the buffer being processed.
+ */
+
+/* unpack a single xtlv entry, advances buffer and copies data to dst_data on match
+ * type and length match must be exact
+ */
+int bcm_unpack_xtlv_entry(uint8 **buf, uint16 expected_type, uint16 expected_len,
+ uint8 *dst_data, bcm_xtlv_opts_t opts);
+
+/* packs an xtlv into buffer, and advances buffer, decreements buffer length.
+ * buffer length is checked and must be >= size of xtlv - otherwise BCME_BADLEN
+ */
+int bcm_pack_xtlv_entry(uint8 **buf, uint16 *buflen, uint16 type, uint16 len,
+ const uint8 *src_data, bcm_xtlv_opts_t opts);
+
+/* accessors and lengths for element given options */
+int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts);
+int bcm_xtlv_hdr_size(bcm_xtlv_opts_t opts);
+int bcm_xtlv_len(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts);
+int bcm_xtlv_id(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts);
+int bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts);
+
+/* compute size needed for number of tlvs whose total data len is given */
+#define BCM_XTLV_SIZE_FOR_TLVS(_data_len, _num_tlvs, _opts) (\
+ bcm_xtlv_size_for_data(_data_len, _opts) + (\
+ (_num_tlvs) * BCM_XTLV_HDR_SIZE_EX(_opts)))
+
+/* unsafe copy xtlv */
+#define BCM_XTLV_BCOPY(_src, _dst, _opts) \
+ bcm_xtlv_bcopy(_src, _dst, BCM_XTLV_MAX_DATA_SIZE_EX(_opts), \
+ BCM_XTLV_MAX_DATA_SIZE_EX(_opts), _opts)
+
+/* copy xtlv - note: src->dst bcopy order - to be compatible w/ tlv version */
+bcm_xtlv_t* bcm_xtlv_bcopy(const bcm_xtlv_t *src, bcm_xtlv_t *dst,
+ int src_buf_len, int dst_buf_len, bcm_xtlv_opts_t opts);
+
+/* callback for unpacking xtlv from a buffer into context. */
+typedef int (bcm_xtlv_unpack_cbfn_t)(void *ctx, const uint8 *buf,
+ uint16 type, uint16 len);
+
+/* unpack a tlv buffer using buffer, options, and callback */
+int bcm_unpack_xtlv_buf(void *ctx, const uint8 *buf, uint16 buflen,
+ bcm_xtlv_opts_t opts, bcm_xtlv_unpack_cbfn_t *cbfn);
+
+/* unpack a set of tlvs from the buffer using provided xtlv descriptors */
+int bcm_unpack_xtlv_buf_to_mem(uint8 *buf, int *buflen, xtlv_desc_t *items,
+ bcm_xtlv_opts_t opts);
+
+/* pack a set of tlvs into buffer using provided xtlv descriptors */
+int bcm_pack_xtlv_buf_from_mem(uint8 **buf, uint16 *buflen,
+ const xtlv_desc_t *items, bcm_xtlv_opts_t opts);
+
+/* return data pointer and data length of a given id from xtlv buffer
+ * data_len may be NULL
+ */
+const uint8* bcm_get_data_from_xtlv_buf(const uint8 *tlv_buf, uint16 buflen,
+ uint16 id, uint16 *datalen, bcm_xtlv_opts_t opts);
+
+/* callback to return next tlv id and len to pack, if there is more tlvs to come and
+ * options e.g. alignment
+ */
+typedef bool (*bcm_pack_xtlv_next_info_cbfn_t)(void *ctx, uint16 *tlv_id, uint16 *tlv_len);
+
+/* callback to pack the tlv into length validated buffer */
+typedef void (*bcm_pack_xtlv_pack_next_cbfn_t)(void *ctx,
+ uint16 tlv_id, uint16 tlv_len, uint8* buf);
+
+/* pack a set of tlvs into buffer using get_next to interate */
+int bcm_pack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen,
+ bcm_xtlv_opts_t opts, bcm_pack_xtlv_next_info_cbfn_t get_next,
+ bcm_pack_xtlv_pack_next_cbfn_t pack_next, int *outlen);
+
+/* pack an xtlv. does not do any error checking. if data is not NULL
+ * data of given length is copied to buffer (xtlv)
+ */
+void bcm_xtlv_pack_xtlv(bcm_xtlv_t *xtlv, uint16 type, uint16 len,
+ const uint8 *data, bcm_xtlv_opts_t opts);
+
+/* unpack an xtlv and return ptr to data, and data length */
+void bcm_xtlv_unpack_xtlv(const bcm_xtlv_t *xtlv, uint16 *type, uint16 *len,
+ const uint8 **data, bcm_xtlv_opts_t opts);
+
+/* end xtlvs */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _bcmtlv_h_ */
diff --git a/wl/src/include/bcmutils.h b/wl/src/include/bcmutils.h
new file mode 100644
index 0000000..a7bb049
--- /dev/null
+++ b/wl/src/include/bcmutils.h
@@ -0,0 +1,1330 @@
+/*
+ * Misc useful os-independent macros and functions.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmutils.h 661946 2016-09-27 21:47:25Z $
+ */
+
+#ifndef _bcmutils_h_
+#define _bcmutils_h_
+
+#include <bcmtlv.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__FreeBSD__)
+#include <stdbool.h>
+#endif
+
+#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count))
+#ifdef FREEBSD
+#define bcm_strncat_s(dst, noOfElements, src, count) strcat((dst), (src))
+#else
+#define bcm_strncat_s(dst, noOfElements, src, count) strncat((dst), (src), (count))
+#endif /* FREEBSD */
+#define bcm_snprintf_s snprintf
+#define bcm_sprintf_s snprintf
+
+/*
+ * #define bcm_strcpy_s(dst, count, src) strncpy((dst), (src), (count))
+ * Use bcm_strcpy_s instead as it is a safer option
+ * bcm_strcat_s: Use bcm_strncat_s as a safer option
+ *
+ */
+
+#define BCM_BIT(x) (1 << (x))
+
+/* ctype replacement */
+#define _BCM_U 0x01 /* upper */
+#define _BCM_L 0x02 /* lower */
+#define _BCM_D 0x04 /* digit */
+#define _BCM_C 0x08 /* cntrl */
+#define _BCM_P 0x10 /* punct */
+#define _BCM_S 0x20 /* white space (space/lf/tab) */
+#define _BCM_X 0x40 /* hex digit */
+#define _BCM_SP 0x80 /* hard space (0x20) */
+
+extern const unsigned char bcm_ctype[];
+#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)])
+
+#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0)
+#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0)
+#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0)
+#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0)
+#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0)
+#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0)
+#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0)
+#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0)
+#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0)
+#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0)
+#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0)
+#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
+#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c))
+
+#define CIRCULAR_ARRAY_FULL(rd_idx, wr_idx, max) ((wr_idx + 1)%max == rd_idx)
+
+#define KB(bytes) (((bytes) + 1023) / 1024)
+
+/* Buffer structure for collecting string-formatted data
+* using bcm_bprintf() API.
+* Use bcm_binit() to initialize before use
+*/
+
+struct bcmstrbuf {
+ char *buf; /* pointer to current position in origbuf */
+ unsigned int size; /* current (residual) size in bytes */
+ char *origbuf; /* unmodified pointer to orignal buffer */
+ unsigned int origsize; /* unmodified orignal buffer size in bytes */
+};
+
+#define BCMSTRBUF_LEN(b) (b->size)
+#define BCMSTRBUF_BUF(b) (b->buf)
+
+/* ** driver-only section ** */
+#ifdef BCMDRIVER
+#include <osl.h>
+#include <hnd_pktq.h>
+#include <hnd_pktpool.h>
+
+#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */
+
+/*
+ * Spin at most 'us' microseconds while 'exp' is true.
+ * Caller should explicitly test 'exp' when this completes
+ * and take appropriate error action if 'exp' is still true.
+ */
+#ifndef SPINWAIT_POLL_PERIOD
+#define SPINWAIT_POLL_PERIOD 10
+#endif
+
+#define SPINWAIT(exp, us) { \
+ uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1); \
+ while ((exp) && (countdown >= SPINWAIT_POLL_PERIOD)) { \
+ OSL_DELAY(SPINWAIT_POLL_PERIOD); \
+ countdown -= SPINWAIT_POLL_PERIOD; \
+ } \
+}
+
+/* forward definition of ether_addr structure used by some function prototypes */
+
+struct ether_addr;
+
+extern int ether_isbcast(const void *ea);
+extern int ether_isnulladdr(const void *ea);
+
+#define UP_TABLE_MAX ((IPV4_TOS_DSCP_MASK >> IPV4_TOS_DSCP_SHIFT) + 1) /* 64 max */
+#define CORE_SLAVE_PORT_0 0
+#define CORE_SLAVE_PORT_1 1
+#define CORE_BASE_ADDR_0 0
+#define CORE_BASE_ADDR_1 1
+
+#ifdef DONGLEBUILD
+/* TRIM Tail bytes from lfrag */
+extern void pktfrag_trim_tailbytes(osl_t * osh, void* p, uint16 len, uint8 type);
+#define PKTFRAG_TRIM_TAILBYTES(osh, p, len, type) \
+ pktfrag_trim_tailbytes(osh, p, len, type)
+#endif /* DONGLEBUILD */
+
+/* externs */
+/* packet */
+extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf);
+extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf);
+extern uint pkttotlen(osl_t *osh, void *p);
+extern void *pktlast(osl_t *osh, void *p);
+extern uint pktsegcnt(osl_t *osh, void *p);
+extern uint pktsegcnt_war(osl_t *osh, void *p);
+extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset);
+extern void *pktoffset(osl_t *osh, void *p, uint offset);
+
+/* Get priority from a packet and pass it back in scb (or equiv) */
+#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */
+#define PKTPRIO_VLAN 0x200 /* VLAN prio found */
+#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */
+#define PKTPRIO_DSCP 0x800 /* DSCP prio found */
+
+/* DSCP type definitions (RFC4594) */
+/* AF1x: High-Throughput Data (RFC2597) */
+#define DSCP_AF11 0x0A
+#define DSCP_AF12 0x0C
+#define DSCP_AF13 0x0E
+/* AF2x: Low-Latency Data (RFC2597) */
+#define DSCP_AF21 0x12
+#define DSCP_AF22 0x14
+#define DSCP_AF23 0x16
+/* AF3x: Multimedia Streaming (RFC2597) */
+#define DSCP_AF31 0x1A
+#define DSCP_AF32 0x1C
+#define DSCP_AF33 0x1E
+/* EF: Telephony (RFC3246) */
+#define DSCP_EF 0x2E
+
+extern uint pktsetprio(void *pkt, bool update_vtag);
+extern uint pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag);
+extern bool pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp);
+
+/* ethernet address */
+extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf);
+extern int bcm_ether_atoe(const char *p, struct ether_addr *ea);
+
+/* ip address */
+struct ipv4_addr;
+extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf);
+extern char *bcm_ipv6_ntoa(void *ipv6, char *buf);
+extern int bcm_atoipv4(const char *p, struct ipv4_addr *ip);
+
+/* delay */
+extern void bcm_mdelay(uint ms);
+/* variable access */
+#if defined(BCM_RECLAIM)
+extern bool _nvram_reclaim_enb;
+#define NVRAM_RECLAIM_ENAB() (_nvram_reclaim_enb)
+#ifdef BCMDBG
+#define NVRAM_RECLAIM_CHECK(name) \
+ if (NVRAM_RECLAIM_ENAB() && (bcm_attach_part_reclaimed == TRUE)) { \
+ printf("%s: NVRAM already reclaimed, %s\n", __FUNCTION__, (name)); \
+ *(char*) 0 = 0; /* TRAP */ \
+ return NULL; \
+ }
+#else /* BCMDBG */
+#define NVRAM_RECLAIM_CHECK(name) \
+ if (NVRAM_RECLAIM_ENAB() && (bcm_attach_part_reclaimed == TRUE)) { \
+ *(char*) 0 = 0; /* TRAP */ \
+ return NULL; \
+ }
+#endif /* BCMDBG */
+#else /* BCM_RECLAIM */
+#define NVRAM_RECLAIM_CHECK(name)
+#endif /* BCM_RECLAIM */
+
+extern char *getvar(char *vars, const char *name);
+extern int getintvar(char *vars, const char *name);
+extern int getintvararray(char *vars, const char *name, int index);
+extern int getintvararraysize(char *vars, const char *name);
+extern uint getgpiopin(char *vars, char *pin_name, uint def_pin);
+#ifdef BCMDBG
+extern void prpkt(const char *msg, osl_t *osh, void *p0);
+#endif /* BCMDBG */
+#ifdef BCMPERFSTATS
+extern void bcm_perf_enable(void);
+extern void bcmstats(char *fmt);
+extern void bcmlog(char *fmt, uint a1, uint a2);
+extern void bcmdumplog(char *buf, int size);
+extern int bcmdumplogent(char *buf, uint idx);
+#else
+#define bcm_perf_enable()
+#define bcmstats(fmt)
+#define bcmlog(fmt, a1, a2)
+#define bcmdumplog(buf, size) *buf = '\0'
+#define bcmdumplogent(buf, idx) -1
+#endif /* BCMPERFSTATS */
+
+#define TSF_TICKS_PER_MS 1000
+#define TS_ENTER 0xdeadbeef /* Timestamp profiling enter */
+#define TS_EXIT 0xbeefcafe /* Timestamp profiling exit */
+
+#if defined(BCMTSTAMPEDLOGS)
+/* Store a TSF timestamp and a log line in the log buffer */
+extern void bcmtslog(uint32 tstamp, const char *fmt, uint a1, uint a2);
+/* Print out the log buffer with timestamps */
+extern void bcmprinttslogs(void);
+/* Print out a microsecond timestamp as "sec.ms.us " */
+extern void bcmprinttstamp(uint32 us);
+/* Dump to buffer a microsecond timestamp as "sec.ms.us " */
+extern void bcmdumptslog(struct bcmstrbuf *b);
+#else
+#define bcmtslog(tstamp, fmt, a1, a2)
+#define bcmprinttslogs()
+#define bcmprinttstamp(us)
+#define bcmdumptslog(b)
+#endif /* BCMTSTAMPEDLOGS */
+
+extern char *bcm_nvram_vars(uint *length);
+extern int bcm_nvram_cache(void *sih);
+
+/* Support for sharing code across in-driver iovar implementations.
+ * The intent is that a driver use this structure to map iovar names
+ * to its (private) iovar identifiers, and the lookup function to
+ * find the entry. Macros are provided to map ids and get/set actions
+ * into a single number space for a switch statement.
+ */
+
+/* iovar structure */
+typedef struct bcm_iovar {
+ const char *name; /* name for lookup and display */
+ uint16 varid; /* id for switch */
+ uint16 flags; /* driver-specific flag bits */
+ uint8 flags2; /* driver-specific flag bits */
+ uint8 type; /* base type of argument */
+ uint16 minlen; /* min length for buffer vars */
+} bcm_iovar_t;
+
+/* varid definitions are per-driver, may use these get/set bits */
+
+/* IOVar action bits for id mapping */
+#define IOV_GET 0 /* Get an iovar */
+#define IOV_SET 1 /* Set an iovar */
+
+/* Varid to actionid mapping */
+#define IOV_GVAL(id) ((id) * 2)
+#define IOV_SVAL(id) ((id) * 2 + IOV_SET)
+#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET)
+#define IOV_ID(actionid) (actionid >> 1)
+
+/* flags are per-driver based on driver attributes */
+
+extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name);
+extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set);
+
+/* ioctl structure */
+typedef struct wlc_ioctl_cmd {
+ uint16 cmd; /**< IOCTL command */
+ uint16 flags; /**< IOCTL command flags */
+ int16 min_len; /**< IOCTL command minimum argument len (in bytes) */
+} wlc_ioctl_cmd_t;
+
+#if defined(WLTINYDUMP) || defined(BCMDBG) || defined(WLMSG_INFORM) || \
+ defined(WLMSG_ASSOC) || defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
+extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len);
+#endif /* WLTINYDUMP || BCMDBG || WLMSG_INFORM || WLMSG_ASSOC || WLMSG_PRPKT */
+#endif /* BCMDRIVER */
+
+/* string */
+extern int bcm_atoi(const char *s);
+extern ulong bcm_strtoul(const char *cp, char **endp, uint base);
+extern uint64 bcm_strtoull(const char *cp, char **endp, uint base);
+extern char *bcmstrstr(const char *haystack, const char *needle);
+extern char *bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len);
+extern char *bcmstrcat(char *dest, const char *src);
+extern char *bcmstrncat(char *dest, const char *src, uint size);
+extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen);
+char* bcmstrtok(char **string, const char *delimiters, char *tokdelim);
+int bcmstricmp(const char *s1, const char *s2);
+int bcmstrnicmp(const char* s1, const char* s2, int cnt);
+
+/* Base type definitions */
+#define IOVT_VOID 0 /* no value (implictly set only) */
+#define IOVT_BOOL 1 /* any value ok (zero/nonzero) */
+#define IOVT_INT8 2 /* integer values are range-checked */
+#define IOVT_UINT8 3 /* unsigned int 8 bits */
+#define IOVT_INT16 4 /* int 16 bits */
+#define IOVT_UINT16 5 /* unsigned int 16 bits */
+#define IOVT_INT32 6 /* int 32 bits */
+#define IOVT_UINT32 7 /* unsigned int 32 bits */
+#define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */
+#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER)
+
+/* Initializer for IOV type strings */
+#define BCM_IOV_TYPE_INIT { \
+ "void", \
+ "bool", \
+ "int8", \
+ "uint8", \
+ "int16", \
+ "uint16", \
+ "int32", \
+ "uint32", \
+ "buffer", \
+ "" }
+
+#define BCM_IOVT_IS_INT(type) (\
+ (type == IOVT_BOOL) || \
+ (type == IOVT_INT8) || \
+ (type == IOVT_UINT8) || \
+ (type == IOVT_INT16) || \
+ (type == IOVT_UINT16) || \
+ (type == IOVT_INT32) || \
+ (type == IOVT_UINT32))
+
+/* ** driver/apps-shared section ** */
+
+#define BCME_STRLEN 64 /* Max string length for BCM errors */
+#define VALID_BCMERROR(e) valid_bcmerror(e)
+
+
+/*
+ * error codes could be added but the defined ones shouldn't be changed/deleted
+ * these error codes are exposed to the user code
+ * when ever a new error code is added to this list
+ * please update errorstring table with the related error string and
+ * update osl files with os specific errorcode map
+*/
+
+#define BCME_OK 0 /* Success */
+#define BCME_ERROR -1 /* Error generic */
+#define BCME_BADARG -2 /* Bad Argument */
+#define BCME_BADOPTION -3 /* Bad option */
+#define BCME_NOTUP -4 /* Not up */
+#define BCME_NOTDOWN -5 /* Not down */
+#define BCME_NOTAP -6 /* Not AP */
+#define BCME_NOTSTA -7 /* Not STA */
+#define BCME_BADKEYIDX -8 /* BAD Key Index */
+#define BCME_RADIOOFF -9 /* Radio Off */
+#define BCME_NOTBANDLOCKED -10 /* Not band locked */
+#define BCME_NOCLK -11 /* No Clock */
+#define BCME_BADRATESET -12 /* BAD Rate valueset */
+#define BCME_BADBAND -13 /* BAD Band */
+#define BCME_BUFTOOSHORT -14 /* Buffer too short */
+#define BCME_BUFTOOLONG -15 /* Buffer too long */
+#define BCME_BUSY -16 /* Busy */
+#define BCME_NOTASSOCIATED -17 /* Not Associated */
+#define BCME_BADSSIDLEN -18 /* Bad SSID len */
+#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */
+#define BCME_BADCHAN -20 /* Bad Channel */
+#define BCME_BADADDR -21 /* Bad Address */
+#define BCME_NORESOURCE -22 /* Not Enough Resources */
+#define BCME_UNSUPPORTED -23 /* Unsupported */
+#define BCME_BADLEN -24 /* Bad length */
+#define BCME_NOTREADY -25 /* Not Ready */
+#define BCME_EPERM -26 /* Not Permitted */
+#define BCME_NOMEM -27 /* No Memory */
+#define BCME_ASSOCIATED -28 /* Associated */
+#define BCME_RANGE -29 /* Not In Range */
+#define BCME_NOTFOUND -30 /* Not Found */
+#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */
+#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */
+#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */
+#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */
+#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */
+#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */
+#define BCME_VERSION -37 /* Incorrect version */
+#define BCME_TXFAIL -38 /* TX failure */
+#define BCME_RXFAIL -39 /* RX failure */
+#define BCME_NODEVICE -40 /* Device not present */
+#define BCME_NMODE_DISABLED -41 /* NMODE disabled */
+#define BCME_HOFFLOAD_RESIDENT -42 /* offload resident */
+#define BCME_SCANREJECT -43 /* reject scan request */
+#define BCME_USAGE_ERROR -44 /* WLCMD usage error */
+#define BCME_IOCTL_ERROR -45 /* WLCMD ioctl error */
+#define BCME_SERIAL_PORT_ERR -46 /* RWL serial port error */
+#define BCME_DISABLED -47 /* Disabled in this build */
+#define BCME_DECERR -48 /* Decrypt error */
+#define BCME_ENCERR -49 /* Encrypt error */
+#define BCME_MICERR -50 /* Integrity/MIC error */
+#define BCME_REPLAY -51 /* Replay */
+#define BCME_IE_NOTFOUND -52 /* IE not found */
+#ifdef __FreeBSD__
+#define BCME_DATA_NOTFOUND -46 /* Complete data not found in buffer */
+#else
+#define BCME_DATA_NOTFOUND -53 /* Complete data not found in buffer */
+#endif /* FreeBSD last error */
+#define BCME_NOT_GC -54 /* expecting a group client */
+#define BCME_PRS_REQ_FAILED -55 /* GC presence req failed to sent */
+#define BCME_NO_P2P_SE -56 /* Could not find P2P-Subelement */
+#define BCME_NOA_PND -57 /* NoA pending, CB shuld be NULL */
+#define BCME_FRAG_Q_FAILED -58 /* queueing 80211 frag failedi */
+#define BCME_GET_AF_FAILED -59 /* Get p2p AF pkt failed */
+#define BCME_MSCH_NOTREADY -60 /* scheduler not ready */
+#define BCME_IOV_LAST_CMD -61 /* last batched iov sub-command */
+#define BCME_LAST BCME_IOV_LAST_CMD
+
+#define BCME_NOTENABLED BCME_DISABLED
+
+/* This error code is *internal* to the driver, and is not propogated to users. It should
+ * only be used by IOCTL patch handlers as an indication that it did not handle the IOCTL.
+ * (Since the error code is internal, an entry in 'BCMERRSTRINGTABLE' is not required,
+ * nor does it need to be part of any OSL driver-to-OS error code mapping).
+ */
+#define BCME_IOCTL_PATCH_UNSUPPORTED -9999
+#if (BCME_LAST <= BCME_IOCTL_PATCH_UNSUPPORTED)
+ #error "BCME_LAST <= BCME_IOCTL_PATCH_UNSUPPORTED"
+#endif
+
+/* These are collection of BCME Error strings */
+#define BCMERRSTRINGTABLE { \
+ "OK", \
+ "Undefined error", \
+ "Bad Argument", \
+ "Bad Option", \
+ "Not up", \
+ "Not down", \
+ "Not AP", \
+ "Not STA", \
+ "Bad Key Index", \
+ "Radio Off", \
+ "Not band locked", \
+ "No clock", \
+ "Bad Rate valueset", \
+ "Bad Band", \
+ "Buffer too short", \
+ "Buffer too long", \
+ "Busy", \
+ "Not Associated", \
+ "Bad SSID len", \
+ "Out of Range Channel", \
+ "Bad Channel", \
+ "Bad Address", \
+ "Not Enough Resources", \
+ "Unsupported", \
+ "Bad length", \
+ "Not Ready", \
+ "Not Permitted", \
+ "No Memory", \
+ "Associated", \
+ "Not In Range", \
+ "Not Found", \
+ "WME Not Enabled", \
+ "TSPEC Not Found", \
+ "ACM Not Supported", \
+ "Not WME Association", \
+ "SDIO Bus Error", \
+ "Dongle Not Accessible", \
+ "Incorrect version", \
+ "TX Failure", \
+ "RX Failure", \
+ "Device Not Present", \
+ "NMODE Disabled", \
+ "Host Offload in device", \
+ "Scan Rejected", \
+ "WLCMD usage error", \
+ "WLCMD ioctl error", \
+ "RWL serial port error", \
+ "Disabled", \
+ "Decrypt error", \
+ "Encrypt error", \
+ "MIC error", \
+ "Replay", \
+ "IE not found", \
+ "Data not found", \
+ "NOT GC", \
+ "PRS REQ FAILED", \
+ "NO P2P SubElement", \
+ "NOA Pending", \
+ "FRAG Q FAILED", \
+ "GET ActionFrame failed", \
+ "scheduler not ready", \
+ "Last IOV batched sub-cmd", \
+}
+
+#ifndef ABS
+#define ABS(a) (((a) < 0) ? -(a) : (a))
+#endif /* ABS */
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* MIN */
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif /* MAX */
+
+/* limit to [min, max] */
+#ifndef LIMIT_TO_RANGE
+#define LIMIT_TO_RANGE(x, min, max) \
+ ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
+#endif /* LIMIT_TO_RANGE */
+
+/* limit to max */
+#ifndef LIMIT_TO_MAX
+#define LIMIT_TO_MAX(x, max) \
+ (((x) > (max) ? (max) : (x)))
+#endif /* LIMIT_TO_MAX */
+
+/* limit to min */
+#ifndef LIMIT_TO_MIN
+#define LIMIT_TO_MIN(x, min) \
+ (((x) < (min) ? (min) : (x)))
+#endif /* LIMIT_TO_MIN */
+
+#define DELTA(curr, prev) ((curr) > (prev) ? ((curr) - (prev)) : \
+ (0xffffffff - (prev) + (curr) + 1))
+#define CEIL(x, y) (((x) + ((y) - 1)) / (y))
+#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+#define ROUNDDN(p, align) ((p) & ~((align) - 1))
+#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0)
+#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \
+ & ~((boundary) - 1))
+#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \
+ & ~((boundary) - 1))
+#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0)
+#define VALID_MASK(mask) !((mask) & ((mask) + 1))
+
+#ifndef OFFSETOF
+#ifdef __ARMCC_VERSION
+/*
+ * The ARM RVCT compiler complains when using OFFSETOF where a constant
+ * expression is expected, such as an initializer for a static object.
+ * offsetof from the runtime library doesn't have that problem.
+ */
+#include <stddef.h>
+#define OFFSETOF(type, member) offsetof(type, member)
+#else
+# if ((__GNUC__ >= 4) && (__GNUC_MINOR__ >= 8))
+/* GCC 4.8+ complains when using our OFFSETOF macro in array length declarations. */
+# define OFFSETOF(type, member) __builtin_offsetof(type, member)
+# else
+# define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member)
+# endif /* GCC 4.8 or newer */
+#endif /* __ARMCC_VERSION */
+#endif /* OFFSETOF */
+
+/* substruct size up to and including a member of the struct */
+#ifndef STRUCT_SIZE_THROUGH
+#define STRUCT_SIZE_THROUGH(sptr, fname) \
+ (((uint8*)&((sptr)->fname) - (uint8*)(sptr)) + sizeof((sptr)->fname))
+#endif
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0]))
+#endif
+
+#ifndef ARRAYLAST /* returns pointer to last array element */
+#define ARRAYLAST(a) (&a[ARRAYSIZE(a)-1])
+#endif
+
+/* Reference a function; used to prevent a static function from being optimized out */
+extern void *_bcmutils_dummy_fn;
+#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f))
+
+/* bit map related macros */
+#ifndef setbit
+#ifndef NBBY /* the BSD family defines NBBY */
+#define NBBY 8 /* 8 bits per byte */
+#endif /* #ifndef NBBY */
+#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
+extern void setbit(void *array, uint bit);
+extern void clrbit(void *array, uint bit);
+extern bool isset(const void *array, uint bit);
+extern bool isclr(const void *array, uint bit);
+#else
+#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY))
+#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY)))
+#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY)))
+#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0)
+#endif
+#endif /* setbit */
+extern void set_bitrange(void *array, uint start, uint end, uint maxbit);
+extern int bcm_find_fsb(uint32 num);
+
+#define isbitset(a, i) (((a) & (1 << (i))) != 0)
+
+#define NBITS(type) (sizeof(type) * 8)
+#define NBITVAL(nbits) (1 << (nbits))
+#define MAXBITVAL(nbits) ((1 << (nbits)) - 1)
+#define NBITMASK(nbits) MAXBITVAL(nbits)
+#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8)
+
+extern void bcm_bitprint32(const uint32 u32);
+
+/*
+ * ----------------------------------------------------------------------------
+ * Multiword map of 2bits, nibbles
+ * setbit2 setbit4 (void *ptr, uint32 ix, uint32 val)
+ * getbit2 getbit4 (void *ptr, uint32 ix)
+ * ----------------------------------------------------------------------------
+ */
+
+#define DECLARE_MAP_API(NB, RSH, LSH, OFF, MSK) \
+static INLINE void setbit##NB(void *ptr, uint32 ix, uint32 val) \
+{ \
+ uint32 *addr = (uint32 *)ptr; \
+ uint32 *a = addr + (ix >> RSH); /* (ix / 2^RSH) */ \
+ uint32 pos = (ix & OFF) << LSH; /* (ix % 2^RSH) * 2^LSH */ \
+ uint32 mask = (MSK << pos); \
+ uint32 tmp = *a & ~mask; \
+ *a = tmp | (val << pos); \
+} \
+static INLINE uint32 getbit##NB(void *ptr, uint32 ix) \
+{ \
+ uint32 *addr = (uint32 *)ptr; \
+ uint32 *a = addr + (ix >> RSH); \
+ uint32 pos = (ix & OFF) << LSH; \
+ return ((*a >> pos) & MSK); \
+}
+
+DECLARE_MAP_API(2, 4, 1, 15U, 0x0003) /* setbit2() and getbit2() */
+DECLARE_MAP_API(4, 3, 2, 7U, 0x000F) /* setbit4() and getbit4() */
+DECLARE_MAP_API(8, 2, 3, 3U, 0x00FF) /* setbit8() and getbit8() */
+
+/* basic mux operation - can be optimized on several architectures */
+#define MUX(pred, true, false) ((pred) ? (true) : (false))
+
+/* modulo inc/dec - assumes x E [0, bound - 1] */
+#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1)
+#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
+
+/* modulo inc/dec, bound = 2^k */
+#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
+#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
+
+/* modulo add/sub - assumes x, y E [0, bound - 1] */
+#define MODADD(x, y, bound) \
+ MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y))
+#define MODSUB(x, y, bound) \
+ MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y))
+
+/* module add/sub, bound = 2^k */
+#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
+#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
+
+/* crc defines */
+#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */
+#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */
+#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */
+#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */
+#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */
+#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */
+
+/* use for direct output of MAC address in printf etc */
+#define MACF "%02x:%02x:%02x:%02x:%02x:%02x"
+#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \
+ ((struct ether_addr *) (ea))->octet[1], \
+ ((struct ether_addr *) (ea))->octet[2], \
+ ((struct ether_addr *) (ea))->octet[3], \
+ ((struct ether_addr *) (ea))->octet[4], \
+ ((struct ether_addr *) (ea))->octet[5]
+
+#define CONST_ETHERP_TO_MACF(ea) ((const struct ether_addr *) (ea))->octet[0], \
+ ((const struct ether_addr *) (ea))->octet[1], \
+ ((const struct ether_addr *) (ea))->octet[2], \
+ ((const struct ether_addr *) (ea))->octet[3], \
+ ((const struct ether_addr *) (ea))->octet[4], \
+ ((const struct ether_addr *) (ea))->octet[5]
+#define ETHER_TO_MACF(ea) (ea).octet[0], \
+ (ea).octet[1], \
+ (ea).octet[2], \
+ (ea).octet[3], \
+ (ea).octet[4], \
+ (ea).octet[5]
+#if !defined(SIMPLE_MAC_PRINT)
+#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5]
+#else
+#define MACDBG "%02x:%02x:%02x"
+#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5]
+#endif /* SIMPLE_MAC_PRINT */
+
+/* bcm_format_flags() bit description structure */
+typedef struct bcm_bit_desc {
+ uint32 bit;
+ const char* name;
+} bcm_bit_desc_t;
+
+/* bcm_format_field */
+typedef struct bcm_bit_desc_ex {
+ uint32 mask;
+ const bcm_bit_desc_t *bitfield;
+} bcm_bit_desc_ex_t;
+
+/* buffer length for ethernet address from bcm_ether_ntoa() */
+#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */
+
+static INLINE uint32 /* 32bit word aligned xor-32 */
+bcm_compute_xor32(volatile uint32 *u32_val, int num_u32)
+{
+ int idx;
+ uint32 xor32 = 0;
+ for (idx = 0; idx < num_u32; idx++)
+ xor32 ^= *(u32_val + idx);
+ return xor32;
+}
+
+/* crypto utility function */
+/* 128-bit xor: *dst = *src1 xor *src2. dst1, src1 and src2 may have any alignment */
+static INLINE void
+xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst)
+{
+ if (
+#ifdef __i386__
+ 1 ||
+#endif
+ (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) {
+ /* ARM CM3 rel time: 1229 (727 if alignment check could be omitted) */
+ /* x86 supports unaligned. This version runs 6x-9x faster on x86. */
+ ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0];
+ ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1];
+ ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2];
+ ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3];
+ } else {
+ /* ARM CM3 rel time: 4668 (4191 if alignment check could be omitted) */
+ int k;
+ for (k = 0; k < 16; k++)
+ dst[k] = src1[k] ^ src2[k];
+ }
+}
+
+/* externs */
+/* crc */
+extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc);
+extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc);
+extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc);
+
+/* format/print */
+#if defined(BCMDBG) || defined(DHD_DEBUG) || defined(BCMDBG_ERR) || \
+ defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
+ defined(BCMDBG_DUMP)
+/* print out the value a field has: fields may have 1-32 bits and may hold any value */
+extern int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 field, char* buf, int len);
+/* print out which bits in flags are set */
+extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len);
+#endif
+
+extern int bcm_format_hex(char *str, const void *bytes, int len);
+
+#ifdef BCMDBG
+extern void deadbeef(void *p, uint len);
+#endif
+extern const char *bcm_crypto_algo_name(uint algo);
+extern char *bcm_chipname(uint chipid, char *buf, uint len);
+extern char *bcm_brev_str(uint32 brev, char *buf);
+extern void printbig(char *buf);
+extern void prhex(const char *msg, const uchar *buf, uint len);
+
+/* bcmerror */
+extern const char *bcmerrorstr(int bcmerror);
+
+extern int wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie);
+
+/* multi-bool data type: set of bools, mbool is true if any is set */
+typedef uint32 mbool;
+#define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */
+#define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */
+#define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* TRUE if one bool is set */
+#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val)))
+
+/* generic datastruct to help dump routines */
+struct fielddesc {
+ const char *nameandfmt;
+ uint32 offset;
+ uint32 len;
+};
+
+extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size);
+extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline,
+ const uint8 *buf, int len);
+
+extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount);
+extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes);
+extern void bcm_print_bytes(const char *name, const uchar *cdata, int len);
+
+typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset);
+extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str,
+ char *buf, uint32 bufsize);
+extern uint bcm_bitcount(uint8 *bitmap, uint bytelength);
+
+extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...);
+
+/* power conversion */
+extern uint16 bcm_qdbm_to_mw(uint8 qdbm);
+extern uint8 bcm_mw_to_qdbm(uint16 mw);
+extern uint bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint len);
+
+#ifdef BCMDBG_PKT /* pkt logging for debugging */
+#define PKTLIST_SIZE 3000
+
+#ifdef BCMDBG_PTRACE
+#define PKTTRACE_MAX_BYTES 12
+#define PKTTRACE_MAX_BITS (PKTTRACE_MAX_BYTES * NBBY)
+
+enum pkttrace_info {
+ PKTLIST_PRECQ, /* Pkt in Prec Q */
+ PKTLIST_FAIL_PRECQ, /* Pkt failed to Q in PRECQ */
+ PKTLIST_DMAQ, /* Pkt in DMA Q */
+ PKTLIST_MI_TFS_RCVD, /* Received TX status */
+ PKTLIST_TXDONE, /* Pkt TX done */
+ PKTLIST_TXFAIL, /* Pkt TX failed */
+ PKTLIST_PKTFREE, /* pkt is freed */
+ PKTLIST_PRECREQ, /* Pkt requeued in precq */
+ PKTLIST_TXFIFO /* To trace in wlc_fifo */
+};
+#endif /* BCMDBG_PTRACE */
+
+typedef struct pkt_dbginfo {
+ int line;
+ char *file;
+ void *pkt;
+#ifdef BCMDBG_PTRACE
+ char pkt_trace[PKTTRACE_MAX_BYTES];
+#endif /* BCMDBG_PTRACE */
+} pkt_dbginfo_t;
+
+typedef struct {
+ pkt_dbginfo_t list[PKTLIST_SIZE]; /* List of pointers to packets */
+ uint16 count; /* Total count of the packets */
+} pktlist_info_t;
+
+
+extern void pktlist_add(pktlist_info_t *pktlist, void *p, int len, char *file);
+extern void pktlist_remove(pktlist_info_t *pktlist, void *p);
+extern char* pktlist_dump(pktlist_info_t *pktlist, char *buf);
+#ifdef BCMDBG_PTRACE
+extern void pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit);
+#endif /* BCMDBG_PTRACE */
+#endif /* BCMDBG_PKT */
+unsigned int process_nvram_vars(char *varbuf, unsigned int len);
+
+/* trace any object allocation / free, with / without features (flags) set to the object */
+#if (defined(DONGLEBUILD) && defined(BCMDBG_MEM) && !defined(BCM_OBJECT_TRACE))
+#define BCM_OBJECT_TRACE
+#endif /* (defined(DONGLEBUILD) && defined(BCMDBG_MEM) && (!defined(BCM_OBJECT_TRACE))) */
+
+#define BCM_OBJDBG_ADD 1
+#define BCM_OBJDBG_REMOVE 2
+#define BCM_OBJDBG_ADD_PKT 3
+
+/* object feature: set or clear flags */
+#define BCM_OBJECT_FEATURE_FLAG 1
+#define BCM_OBJECT_FEATURE_PKT_STATE 2
+/* object feature: flag bits */
+#define BCM_OBJECT_FEATURE_0 (1 << 0)
+#define BCM_OBJECT_FEATURE_1 (1 << 1)
+#define BCM_OBJECT_FEATURE_2 (1 << 2)
+/* object feature: clear flag bits field set with this flag */
+#define BCM_OBJECT_FEATURE_CLEAR (1 << 31)
+#ifdef BCM_OBJECT_TRACE
+#define bcm_pkt_validate_chk(obj) do { \
+ void * pkttag; \
+ bcm_object_trace_chk(obj, 0, 0, \
+ __FUNCTION__, __LINE__); \
+ if ((pkttag = PKTTAG(obj))) { \
+ bcm_object_trace_chk(obj, 1, DHD_PKTTAG_SN(pkttag), \
+ __FUNCTION__, __LINE__); \
+ } \
+} while (0)
+extern void bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line);
+extern void bcm_object_trace_upd(void *obj, void *obj_new);
+extern void bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn,
+ const char *caller, int line);
+extern void bcm_object_feature_set(void *obj, uint32 type, uint32 value);
+extern int bcm_object_feature_get(void *obj, uint32 type, uint32 value);
+extern void bcm_object_trace_init(void);
+extern void bcm_object_trace_deinit(void);
+#else
+#define bcm_pkt_validate_chk(obj)
+#define bcm_object_trace_opr(a, b, c, d)
+#define bcm_object_trace_upd(a, b)
+#define bcm_object_trace_chk(a, b, c, d, e)
+#define bcm_object_feature_set(a, b, c)
+#define bcm_object_feature_get(a, b, c)
+#define bcm_object_trace_init()
+#define bcm_object_trace_deinit()
+#endif /* BCM_OBJECT_TRACE */
+
+/* calculate a * b + c */
+extern void bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c);
+/* calculate a / b */
+extern void bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b);
+/* calculate uint64 a / b (returns uint64) */
+extern uint64 bcm_uint64_div(uint32 a_high, uint32 a_low, uint32 b);
+
+
+/* Public domain bit twiddling hacks/utilities: Sean Eron Anderson */
+
+/* Table driven count set bits. */
+static const uint8 /* Table only for use by bcm_cntsetbits */
+_CSBTBL[256] =
+{
+# define B2(n) n, n + 1, n + 1, n + 2
+# define B4(n) B2(n), B2(n + 1), B2(n + 1), B2(n + 2)
+# define B6(n) B4(n), B4(n + 1), B4(n + 1), B4(n + 2)
+ B6(0), B6(0 + 1), B6(0 + 1), B6(0 + 2)
+};
+
+static INLINE uint32 /* Uses table _CSBTBL for fast counting of 1's in a u32 */
+bcm_cntsetbits(const uint32 u32arg)
+{
+ /* function local scope declaration of const _CSBTBL[] */
+ const uint8 * p = (const uint8 *)&u32arg;
+ return (_CSBTBL[p[0]] + _CSBTBL[p[1]] + _CSBTBL[p[2]] + _CSBTBL[p[3]]);
+}
+
+
+static INLINE int /* C equivalent count of leading 0's in a u32 */
+C_bcm_count_leading_zeros(uint32 u32arg)
+{
+ int shifts = 0;
+ while (u32arg) {
+ shifts++; u32arg >>= 1;
+ }
+ return (32U - shifts);
+}
+
+#ifdef BCMDRIVER
+/*
+ * Assembly instructions: Count Leading Zeros
+ * "clz" : MIPS, ARM
+ * "cntlzw" : PowerPC
+ * "BSF" : x86
+ * "lzcnt" : AMD, SPARC
+ */
+#if defined(__mips__)
+#define __USE_ASM_CLZ__
+#endif /* __mips__ */
+
+#if defined(__arm__)
+#if defined(__ARM_ARCH_7M__) /* Cortex M3 */
+#define __USE_ASM_CLZ__
+#endif /* __ARM_ARCH_7M__ */
+#if defined(__ARM_ARCH_7R__) /* Cortex R4 */
+#define __USE_ASM_CLZ__
+#endif /* __ARM_ARCH_7R__ */
+#endif /* __arm__ */
+
+static INLINE int
+bcm_count_leading_zeros(uint32 u32arg)
+{
+#if defined(__USE_ASM_CLZ__)
+ int zeros;
+ __asm__ volatile("clz %0, %1 \n" : "=r" (zeros) : "r" (u32arg));
+ return zeros;
+#else /* C equivalent */
+ return C_bcm_count_leading_zeros(u32arg);
+#endif /* C equivalent */
+}
+
+/*
+ * Macro to count leading zeroes
+ *
+ */
+#if defined(__GNUC__)
+#define CLZ(x) __builtin_clzl(x)
+#elif defined(__arm__)
+#define CLZ(x) __clz(x)
+#else
+#define CLZ(x) bcm_count_leading_zeros(x)
+#endif /* __GNUC__ */
+
+/* INTERFACE: Multiword bitmap based small id allocator. */
+struct bcm_mwbmap; /* forward declaration for use as an opaque mwbmap handle */
+
+#define BCM_MWBMAP_INVALID_HDL ((struct bcm_mwbmap *)NULL)
+#define BCM_MWBMAP_INVALID_IDX ((uint32)(~0U))
+
+/* Incarnate a multiword bitmap based small index allocator */
+extern struct bcm_mwbmap * bcm_mwbmap_init(osl_t * osh, uint32 items_max);
+
+/* Free up the multiword bitmap index allocator */
+extern void bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl);
+
+/* Allocate a unique small index using a multiword bitmap index allocator */
+extern uint32 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl);
+
+/* Force an index at a specified position to be in use */
+extern void bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix);
+
+/* Free a previously allocated index back into the multiword bitmap allocator */
+extern void bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix);
+
+/* Fetch the toal number of free indices in the multiword bitmap allocator */
+extern uint32 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl);
+
+/* Determine whether an index is inuse or free */
+extern bool bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix);
+
+/* Debug dump a multiword bitmap allocator */
+extern void bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl);
+
+extern void bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl);
+/* End - Multiword bitmap based small Id allocator. */
+
+
+/* INTERFACE: Simple unique 16bit Id Allocator using a stack implementation. */
+
+#define ID8_INVALID 0xFFu
+#define ID16_INVALID 0xFFFFu
+#define ID32_INVALID 0xFFFFFFFFu
+#define ID16_UNDEFINED ID16_INVALID
+
+/*
+ * Construct a 16bit id allocator, managing 16bit ids in the range:
+ * [start_val16 .. start_val16+total_ids)
+ * Note: start_val16 is inclusive.
+ * Returns an opaque handle to the 16bit id allocator.
+ */
+extern void * id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16);
+extern void * id16_map_fini(osl_t *osh, void * id16_map_hndl);
+extern void id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16);
+
+/* Allocate a unique 16bit id */
+extern uint16 id16_map_alloc(void * id16_map_hndl);
+
+/* Free a 16bit id value into the id16 allocator */
+extern void id16_map_free(void * id16_map_hndl, uint16 val16);
+
+/* Get the number of failures encountered during id allocation. */
+extern uint32 id16_map_failures(void * id16_map_hndl);
+
+/* Audit the 16bit id allocator state. */
+extern bool id16_map_audit(void * id16_map_hndl);
+/* End - Simple 16bit Id Allocator. */
+#endif /* BCMDRIVER */
+
+extern void bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b);
+
+void bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset);
+void bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset);
+
+uint64 fp_mult_64(uint64 val1, uint64 val2, uint8 nf1, uint8 nf2, uint8 nf_res);
+uint8 fp_div_64(uint64 num, uint32 den, uint8 nf_num, uint8 nf_den, uint32 *div_out);
+uint8 fp_calc_head_room_64(uint64 num);
+uint8 fp_calc_head_room_32(uint32 num);
+uint32 fp_round_64(uint64 num, uint8 rnd_pos);
+uint32 fp_round_32(uint32 num, uint8 rnd_pos);
+uint32 fp_floor_64(uint64 num, uint8 floor_pos);
+uint32 fp_floor_32(uint32 num, uint8 floor_pos);
+uint32 fp_ceil_64(uint64 num, uint8 ceil_pos);
+uint64 bcm_shl_64(uint64 input, uint8 shift_amt);
+uint64 bcm_shr_64(uint64 input, uint8 shift_amt);
+
+#define MASK_32_BITS (~0)
+#define MASK_8_BITS ((1 << 8) - 1)
+
+#define EXTRACT_LOW32(num) (uint32)(num & MASK_32BITS)
+#define EXTRACT_HIGH32(num) (uint32)(((uint64)num >> 32) & MASK_32BITS)
+
+#define MAXIMUM(a, b) ((a > b) ? a : b)
+#define MINIMUM(a, b) ((a < b) ? a : b)
+#define LIMIT(x, min, max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
+
+/* calculate checksum for ip header, tcp / udp header / data */
+uint16 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum);
+
+#ifndef _dll_t_
+#define _dll_t_
+/*
+ * -----------------------------------------------------------------------------
+ * Double Linked List Macros
+ * -----------------------------------------------------------------------------
+ *
+ * All dll operations must be performed on a pre-initialized node.
+ * Inserting an uninitialized node into a list effectively initialized it.
+ *
+ * When a node is deleted from a list, you may initialize it to avoid corruption
+ * incurred by double deletion. You may skip initialization if the node is
+ * immediately inserted into another list.
+ *
+ * By placing a dll_t element at the start of a struct, you may cast a dll_t *
+ * to the struct or vice versa.
+ *
+ * Example of declaring an initializing someList and inserting nodeA, nodeB
+ *
+ * typedef struct item {
+ * dll_t node;
+ * int someData;
+ * } Item_t;
+ * Item_t nodeA, nodeB, nodeC;
+ * nodeA.someData = 11111, nodeB.someData = 22222, nodeC.someData = 33333;
+ *
+ * dll_t someList;
+ * dll_init(&someList);
+ *
+ * dll_append(&someList, (dll_t *) &nodeA);
+ * dll_prepend(&someList, &nodeB.node);
+ * dll_insert((dll_t *)&nodeC, &nodeA.node);
+ *
+ * dll_delete((dll_t *) &nodeB);
+ *
+ * Example of a for loop to walk someList of node_p
+ *
+ * extern void mydisplay(Item_t * item_p);
+ *
+ * dll_t * item_p, * next_p;
+ * for (item_p = dll_head_p(&someList); ! dll_end(&someList, item_p);
+ * item_p = next_p)
+ * {
+ * next_p = dll_next_p(item_p);
+ * ... use item_p at will, including removing it from list ...
+ * mydisplay((PItem_t)item_p);
+ * }
+ *
+ * -----------------------------------------------------------------------------
+ */
+typedef struct dll {
+ struct dll * next_p;
+ struct dll * prev_p;
+} dll_t;
+
+static INLINE void
+dll_init(dll_t *node_p)
+{
+ node_p->next_p = node_p;
+ node_p->prev_p = node_p;
+}
+/* dll macros returing a pointer to dll_t */
+
+static INLINE dll_t *
+dll_head_p(dll_t *list_p)
+{
+ return list_p->next_p;
+}
+
+
+static INLINE dll_t *
+dll_tail_p(dll_t *list_p)
+{
+ return (list_p)->prev_p;
+}
+
+
+static INLINE dll_t *
+dll_next_p(dll_t *node_p)
+{
+ return (node_p)->next_p;
+}
+
+
+static INLINE dll_t *
+dll_prev_p(dll_t *node_p)
+{
+ return (node_p)->prev_p;
+}
+
+
+static INLINE bool
+dll_empty(dll_t *list_p)
+{
+ return ((list_p)->next_p == (list_p));
+}
+
+
+static INLINE bool
+dll_end(dll_t *list_p, dll_t * node_p)
+{
+ return (list_p == node_p);
+}
+
+
+/* inserts the node new_p "after" the node at_p */
+static INLINE void
+dll_insert(dll_t *new_p, dll_t * at_p)
+{
+ new_p->next_p = at_p->next_p;
+ new_p->prev_p = at_p;
+ at_p->next_p = new_p;
+ (new_p->next_p)->prev_p = new_p;
+}
+
+static INLINE void
+dll_append(dll_t *list_p, dll_t *node_p)
+{
+ dll_insert(node_p, dll_tail_p(list_p));
+}
+
+static INLINE void
+dll_prepend(dll_t *list_p, dll_t *node_p)
+{
+ dll_insert(node_p, list_p);
+}
+
+
+/* deletes a node from any list that it "may" be in, if at all. */
+static INLINE void
+dll_delete(dll_t *node_p)
+{
+ node_p->prev_p->next_p = node_p->next_p;
+ node_p->next_p->prev_p = node_p->prev_p;
+}
+#endif /* ! defined(_dll_t_) */
+
+/* Elements managed in a double linked list */
+
+typedef struct dll_pool {
+ dll_t free_list;
+ uint16 free_count;
+ uint16 elems_max;
+ uint16 elem_size;
+ dll_t elements[1];
+} dll_pool_t;
+
+dll_pool_t * dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size);
+void * dll_pool_alloc(dll_pool_t * dll_pool_p);
+void dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p);
+void dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p);
+typedef void (* dll_elem_dump)(void * elem_p);
+#ifdef BCMDBG
+void dll_pool_dump(dll_pool_t * dll_pool_p, dll_elem_dump dump);
+#endif
+void dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size);
+
+int valid_bcmerror(int e);
+
+/* calculate IPv4 header checksum
+ * - input ip points to IP header in network order
+ * - output cksum is in network order
+ */
+uint16 ipv4_hdr_cksum(uint8 *ip, int ip_len);
+
+/* calculate IPv4 TCP header checksum
+ * - input ip and tcp points to IP and TCP header in network order
+ * - output cksum is in network order
+ */
+uint16 ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len);
+
+/* calculate IPv6 TCP header checksum
+ * - input ipv6 and tcp points to IPv6 and TCP header in network order
+ * - output cksum is in network order
+ */
+uint16 ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len);
+
+#ifdef __cplusplus
+ }
+#endif
+
+/* #define DEBUG_COUNTER */
+#ifdef DEBUG_COUNTER
+#define CNTR_TBL_MAX 10
+typedef struct _counter_tbl_t {
+ char name[16]; /* name of this counter table */
+ uint32 prev_log_print; /* Internal use. Timestamp of the previous log print */
+ uint log_print_interval; /* Desired interval to print logs in ms */
+ uint needed_cnt; /* How many counters need to be used */
+ uint32 cnt[CNTR_TBL_MAX]; /* Counting entries to increase at desired places */
+ bool enabled; /* Whether to enable printing log */
+} counter_tbl_t;
+
+
+void counter_printlog(counter_tbl_t *ctr_tbl);
+#endif /* DEBUG_COUNTER */
+
+#if defined(__GNUC__)
+#define CALL_SITE __builtin_return_address(0)
+#else
+#define CALL_SITE ((void*) 0)
+#endif
+#ifdef SHOW_LOGTRACE
+#define TRACE_LOG_BUF_MAX_SIZE 1500
+#define BUF_NOT_AVAILABLE 0
+#define NEXT_BUF_NOT_AVAIL 1
+#define NEXT_BUF_AVAIL 2
+
+typedef struct trace_buf_info {
+ int availability;
+ int size;
+ char buf[TRACE_LOG_BUF_MAX_SIZE];
+} trace_buf_info_t;
+#endif /* SHOW_LOGTRACE */
+
+typedef int32 math_fixed; /* s15.16 fixed-point */
+
+typedef struct _cint32 {
+ math_fixed q;
+ math_fixed i;
+} math_cint32;
+
+typedef math_cint32 cint32;
+
+extern void mult_cint32_cfixed(const cint32* in1, const cint32* in2, const uint8 prec,
+ cint32* out, bool conj);
+extern void add_cint32(const cint32* in1, const cint32* in2, cint32* out);
+extern void power_cint32(const cint32* in1, uint32* pwr);
+extern void power_cint32_arr(const cint32* in1, const uint16* idx_arr, uint16 len, uint32* pwr);
+extern uint32 sqrt_int(uint32 value);
+
+#endif /* _bcmutils_h_ */
diff --git a/wl/src/include/brcm_nl80211.h b/wl/src/include/brcm_nl80211.h
new file mode 100644
index 0000000..47f5801
--- /dev/null
+++ b/wl/src/include/brcm_nl80211.h
@@ -0,0 +1,63 @@
+/*
+ * Definitions for nl80211 vendor command/event access to host driver
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: brcm_nl80211.h 601873 2015-11-24 11:04:28Z $
+ *
+ */
+
+#ifndef _brcm_nl80211_h_
+#define _brcm_nl80211_h_
+
+#define OUI_BRCM 0x001018
+#define OUI_GOOGLE 0x001A11
+
+enum wl_vendor_subcmd {
+ BRCM_VENDOR_SCMD_UNSPEC,
+ BRCM_VENDOR_SCMD_PRIV_STR,
+ BRCM_VENDOR_SCMD_BCM_STR
+};
+
+
+struct bcm_nlmsg_hdr {
+ uint cmd; /* common ioctl definition */
+ int len; /* expected return buffer length */
+ uint offset; /* user buffer offset */
+ uint set; /* get or set request optional */
+ uint magic; /* magic number for verification */
+};
+
+enum bcmnl_attrs {
+ BCM_NLATTR_UNSPEC,
+
+ BCM_NLATTR_LEN,
+ BCM_NLATTR_DATA,
+
+ __BCM_NLATTR_AFTER_LAST,
+ BCM_NLATTR_MAX = __BCM_NLATTR_AFTER_LAST - 1
+};
+
+struct nl_prv_data {
+ int err; /* return result */
+ void *data; /* ioctl return buffer pointer */
+ uint len; /* ioctl return buffer length */
+ struct bcm_nlmsg_hdr *nlioc; /* bcm_nlmsg_hdr header pointer */
+};
+
+#endif /* _brcm_nl80211_h_ */
diff --git a/wl/src/include/dhdioctl.h b/wl/src/include/dhdioctl.h
new file mode 100644
index 0000000..72bbd7e
--- /dev/null
+++ b/wl/src/include/dhdioctl.h
@@ -0,0 +1,151 @@
+/*
+ * Definitions for ioctls to access DHD iovars.
+ * Based on wlioctl.h (for Broadcom 802.11abg driver).
+ * (Moves towards generic ioctls for BCM drivers/iovars.)
+ *
+ * Definitions subject to change without notice.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhdioctl.h 660496 2016-09-20 19:28:50Z $
+ */
+
+#ifndef _dhdioctl_h_
+#define _dhdioctl_h_
+
+#include <typedefs.h>
+
+#if defined(__FreeBSD__)
+/* NetBSD 2.0 does not have SIOCDEVPRIVATE. This is NetBSD 2.0 specific */
+#define SIOCDEVPRIVATE _IOWR('i', 139, struct ifreq)
+#endif
+
+/* Linux network driver ioctl encoding */
+typedef struct dhd_ioctl {
+ uint32 cmd; /* common ioctl definition */
+ void *buf; /* pointer to user buffer */
+ uint32 len; /* length of user buffer */
+ uint32 set; /* get or set request boolean (optional) */
+ uint32 used; /* bytes read or written (optional) */
+ uint32 needed; /* bytes needed (optional) */
+ uint32 driver; /* to identify target driver */
+} dhd_ioctl_t;
+
+/* Underlying BUS definition */
+enum {
+ BUS_TYPE_USB = 0, /* for USB dongles */
+ BUS_TYPE_SDIO, /* for SDIO dongles */
+ BUS_TYPE_PCIE /* for PCIE dongles */
+};
+
+
+/* per-driver magic numbers */
+#define DHD_IOCTL_MAGIC 0x00444944
+
+/* bump this number if you change the ioctl interface */
+#define DHD_IOCTL_VERSION 1
+
+/*
+ * Increase the DHD_IOCTL_MAXLEN to 16K for supporting download of NVRAM files of size
+ * > 8K. In the existing implementation when NVRAM is to be downloaded via the "vars"
+ * DHD IOVAR, the NVRAM is copied to the DHD Driver memory. Later on when "dwnldstate" is
+ * invoked with FALSE option, the NVRAM gets copied from the DHD driver to the Dongle
+ * memory. The simple way to support this feature without modifying the DHD application,
+ * driver logic is to increase the DHD_IOCTL_MAXLEN size. This macro defines the "size"
+ * of the buffer in which data is exchanged between the DHD App and DHD driver.
+ */
+#define DHD_IOCTL_MAXLEN (16384) /* max length ioctl buffer required */
+#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */
+
+/* common ioctl definitions */
+#define DHD_GET_MAGIC 0
+#define DHD_GET_VERSION 1
+#define DHD_GET_VAR 2
+#define DHD_SET_VAR 3
+
+/* message levels */
+#define DHD_ERROR_VAL 0x0001
+#define DHD_TRACE_VAL 0x0002
+#define DHD_INFO_VAL 0x0004
+#define DHD_DATA_VAL 0x0008
+#define DHD_CTL_VAL 0x0010
+#define DHD_TIMER_VAL 0x0020
+#define DHD_HDRS_VAL 0x0040
+#define DHD_BYTES_VAL 0x0080
+#define DHD_INTR_VAL 0x0100
+#define DHD_LOG_VAL 0x0200
+#define DHD_GLOM_VAL 0x0400
+#define DHD_EVENT_VAL 0x0800
+#define DHD_BTA_VAL 0x1000
+#if 0 && (NDISVER >= 0x0630) && defined(BCMDONGLEHOST)
+#define DHD_SCAN_VAL 0x2000
+#else
+#define DHD_ISCAN_VAL 0x2000
+#endif
+#define DHD_ARPOE_VAL 0x4000
+#define DHD_REORDER_VAL 0x8000
+#define DHD_WL_VAL 0x10000
+#define DHD_NOCHECKDIED_VAL 0x20000 /* UTF WAR */
+#define DHD_WL_VAL2 0x40000
+#define DHD_PNO_VAL 0x80000
+#define DHD_RTT_VAL 0x100000
+#define DHD_MSGTRACE_VAL 0x200000
+#define DHD_FWLOG_VAL 0x400000
+#define DHD_DBGIF_VAL 0x800000
+#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
+#define DHD_RPM_VAL 0x1000000
+#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
+#define DHD_PKT_MON_VAL 0x2000000
+#define DHD_PKT_MON_DUMP_VAL 0x4000000
+
+#ifdef SDTEST
+/* For pktgen iovar */
+typedef struct dhd_pktgen {
+ uint32 version; /* To allow structure change tracking */
+ uint32 freq; /* Max ticks between tx/rx attempts */
+ uint32 count; /* Test packets to send/rcv each attempt */
+ uint32 print; /* Print counts every <print> attempts */
+ uint32 total; /* Total packets (or bursts) */
+ uint32 minlen; /* Minimum length of packets to send */
+ uint32 maxlen; /* Maximum length of packets to send */
+ uint32 numsent; /* Count of test packets sent */
+ uint32 numrcvd; /* Count of test packets received */
+ uint32 numfail; /* Count of test send failures */
+ uint32 mode; /* Test mode (type of test packets) */
+ uint32 stop; /* Stop after this many tx failures */
+} dhd_pktgen_t;
+
+/* Version in case structure changes */
+#define DHD_PKTGEN_VERSION 2
+
+/* Type of test packets to use */
+#define DHD_PKTGEN_ECHO 1 /* Send echo requests */
+#define DHD_PKTGEN_SEND 2 /* Send discard packets */
+#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */
+#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */
+#endif /* SDTEST */
+
+/* Enter idle immediately (no timeout) */
+#define DHD_IDLE_IMMEDIATE (-1)
+
+/* Values for idleclock iovar: other values are the sd_divisor to use when idle */
+#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */
+#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */
+
+
+#endif /* _dhdioctl_h_ */
diff --git a/wl/src/include/epivers.h b/wl/src/include/epivers.h
new file mode 100644
index 0000000..8a2d74a
--- /dev/null
+++ b/wl/src/include/epivers.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: epivers.h.in 596126 2015-10-29 19:53:48Z $
+ *
+*/
+
+#ifndef _epivers_h_
+#define _epivers_h_
+
+#define EPI_MAJOR_VERSION 2017
+
+#define EPI_MINOR_VERSION 5
+
+#define EPI_RC_NUMBER 14
+
+#define EPI_INCREMENTAL_NUMBER 0
+
+#define EPI_BUILD_NUMBER 0
+
+#define EPI_VERSION 2017, 5, 14, 0
+
+#define EPI_VERSION_NUM 0x7e1050e0
+
+#define EPI_VERSION_DEV 2017.5.14
+
+/* Driver Version String, ASCII, 32 chars max */
+#define EPI_VERSION_STR "2017.05.14 (r665031)"
+
+#endif /* _epivers_h_ */
diff --git a/wl/src/include/event_log.h b/wl/src/include/event_log.h
new file mode 100644
index 0000000..57dec6b
--- /dev/null
+++ b/wl/src/include/event_log.h
@@ -0,0 +1,388 @@
+/*
+ * EVENT_LOG system definitions
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: event_log.h 657831 2016-09-02 18:52:56Z $
+ */
+
+#ifndef _EVENT_LOG_H_
+#define _EVENT_LOG_H_
+
+#include <typedefs.h>
+#include <proto/event_log_set.h>
+#include <proto/event_log_tag.h>
+#include <proto/event_log_payload.h>
+#include <osl_decl.h>
+
+/* logstrs header */
+#define LOGSTRS_MAGIC 0x4C4F4753
+#define LOGSTRS_VERSION 0x1
+
+/* We make sure that the block size will fit in a single packet
+ * (allowing for a bit of overhead on each packet
+ */
+#if defined(BCMPCIEDEV)
+#define EVENT_LOG_MAX_BLOCK_SIZE 1648
+#else
+#define EVENT_LOG_MAX_BLOCK_SIZE 1400
+#endif
+#define EVENT_LOG_WL_BLOCK_SIZE 0x200
+#define EVENT_LOG_PSM_BLOCK_SIZE 0x200
+#define EVENT_LOG_BUS_BLOCK_SIZE 0x200
+#define EVENT_LOG_ERROR_BLOCK_SIZE 0x200
+/* Maximum event log record payload size = 1024 bytes or 256 words. */
+#define EVENT_LOG_MAX_RECORD_PAYLOAD_SIZE 256
+
+/*
+ * There are multiple levels of objects define here:
+ * event_log_set - a set of buffers
+ * event log groups - every event log call is part of just one. All
+ * event log calls in a group are handled the
+ * same way. Each event log group is associated
+ * with an event log set or is off.
+ */
+
+#ifndef __ASSEMBLER__
+
+/* On the external system where the dumper is we need to make sure
+ * that these types are the same size as they are on the ARM the
+ * produced them
+ */
+#ifdef EVENT_LOG_DUMPER
+#define _EL_BLOCK_PTR uint32
+#define _EL_TYPE_PTR uint32
+#define _EL_SET_PTR uint32
+#define _EL_TOP_PTR uint32
+#else
+#define _EL_BLOCK_PTR struct event_log_block *
+#define _EL_TYPE_PTR uint32 *
+#define _EL_SET_PTR struct event_log_set **
+#define _EL_TOP_PTR struct event_log_top *
+#endif /* EVENT_LOG_DUMPER */
+
+/* Event log sets (a logical circurlar buffer) consist of one or more
+ * event_log_blocks. The blocks themselves form a logical circular
+ * list. The log entries are placed in each event_log_block until it
+ * is full. Logging continues with the next event_log_block in the
+ * event_set until the last event_log_block is reached and then
+ * logging starts over with the first event_log_block in the
+ * event_set.
+ */
+typedef struct event_log_block {
+ _EL_BLOCK_PTR next_block;
+ _EL_BLOCK_PTR prev_block;
+ _EL_TYPE_PTR end_ptr;
+
+ /* Start of packet sent for log tracing */
+ uint16 pktlen; /* Size of rest of block */
+ uint16 count; /* Logtrace counter */
+ uint32 extra_hdr_info; /* LSB: 6 bits set id. MSB 24 bits reserved */
+ uint32 event_logs;
+} event_log_block_t;
+
+typedef enum {
+ SET_DESTINATION_INVALID = -1,
+ SET_DESTINATION_HOST = 0,
+ SET_DESTINATION_NONE = 1,
+ SET_DESTINATION_MAX
+} event_log_set_destination_t;
+
+/* There can be multiple event_sets with each logging a set of
+ * associated events (i.e, "fast" and "slow" events).
+ */
+typedef struct event_log_set {
+ _EL_BLOCK_PTR first_block; /* Pointer to first event_log block */
+ _EL_BLOCK_PTR last_block; /* Pointer to last event_log block */
+ _EL_BLOCK_PTR logtrace_block; /* next block traced */
+ _EL_BLOCK_PTR cur_block; /* Pointer to current event_log block */
+ _EL_TYPE_PTR cur_ptr; /* Current event_log pointer */
+ uint32 blockcount; /* Number of blocks */
+ uint16 logtrace_count; /* Last count for logtrace */
+ uint16 blockfill_count; /* Fill count for logtrace */
+ uint32 timestamp; /* Last timestamp event */
+ uint32 cyclecount; /* Cycles at last timestamp event */
+ event_log_set_destination_t destination;
+ uint16 size; /* same size for all buffers in one set */
+} event_log_set_t;
+
+/* Top data structure for access to everything else */
+typedef struct event_log_top {
+ uint32 magic;
+#define EVENT_LOG_TOP_MAGIC 0x474C8669 /* 'EVLG' */
+ uint32 version;
+#define EVENT_LOG_VERSION 1
+ uint32 num_sets;
+ uint32 logstrs_size; /* Size of lognums + logstrs area */
+ uint32 timestamp; /* Last timestamp event */
+ uint32 cyclecount; /* Cycles at last timestamp event */
+ _EL_SET_PTR sets; /* Ptr to array of <num_sets> set ptrs */
+} event_log_top_t;
+
+/* Data structure of Keeping the Header from logstrs.bin */
+typedef struct {
+ uint32 logstrs_size; /* Size of the file */
+ uint32 rom_lognums_offset; /* Offset to the ROM lognum */
+ uint32 ram_lognums_offset; /* Offset to the RAM lognum */
+ uint32 rom_logstrs_offset; /* Offset to the ROM logstr */
+ uint32 ram_logstrs_offset; /* Offset to the RAM logstr */
+ /* Keep version and magic last since "header" is appended to the end of logstrs file. */
+ uint32 version; /* Header version */
+ uint32 log_magic; /* MAGIC number for verification 'LOGS' */
+} logstr_header_t;
+
+/*
+ * Use the following macros for generating log events.
+ *
+ * The FAST versions check the enable of the tag before evaluating the arguments and calling the
+ * event_log function. This adds 5 instructions. The COMPACT versions evaluate the arguments
+ * and call the event_log function unconditionally. The event_log function will then skip logging
+ * if this tag is disabled.
+ *
+ * To support easy usage of existing debugging (e.g. msglevel) via macro re-definition there are
+ * two variants of these macros to help.
+ *
+ * First there are the CAST versions. The event_log function normally logs uint32 values or else
+ * they have to be cast to uint32. The CAST versions blindly cast for you so you don't have to edit
+ * any existing code.
+ *
+ * Second there are the PAREN_ARGS versions. These expect the logging format string and arguments
+ * to be enclosed in parentheses. This allows us to make the following mapping of an existing
+ * msglevel macro:
+ * #define WL_ERROR(args) EVENT_LOG_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_ERROR, args)
+ *
+ * The versions of the macros without FAST or COMPACT in their name are just synonyms for the
+ * COMPACT versions.
+ *
+ * You should use the COMPACT macro (or its synonym) in cases where there is some preceding logic
+ * that prevents the execution of the macro, e.g. WL_ERROR by definition rarely gets executed.
+ * Use the FAST macro in performance sensitive paths. The key concept here is that you should be
+ * assuming that your macro usage is compiled into ROM and can't be changed ... so choose wisely.
+ *
+ */
+
+#if !defined(EVENT_LOG_DUMPER) && !defined(DHD_EFI)
+
+#ifndef EVENT_LOG_COMPILE
+
+/* Null define if no tracing */
+#define EVENT_LOG(format, ...)
+#define EVENT_LOG_FAST(tag, fmt, ...)
+#define EVENT_LOG_COMPACT(tag, fmt, ...)
+
+#define EVENT_LOG_CAST(tag, fmt, ...)
+#define EVENT_LOG_FAST_CAST(tag, fmt, ...)
+#define EVENT_LOG_COMPACT_CAST(tag, fmt, ...)
+
+#define EVENT_LOG_CAST_PAREN_ARGS(tag, pargs)
+#define EVENT_LOG_FAST_CAST_PAREN_ARGS(tag, pargs)
+#define EVENT_LOG_COMPACT_CAST_PAREN_ARGS(tag, pargs)
+
+#define EVENT_LOG_IS_ON(tag) 0
+#define EVENT_LOG_IS_LOG_ON(tag) 0
+
+#define EVENT_LOG_BUFFER(tag, buf, size)
+
+#else /* EVENT_LOG_COMPILE */
+
+/* The first few are special because they can be done more efficiently
+ * this way and they are the common case. Once there are too many
+ * parameters the code size starts to be an issue and a loop is better
+ */
+#define _EVENT_LOG0(tag, fmt_num) \
+ event_log0(tag, fmt_num)
+#define _EVENT_LOG1(tag, fmt_num, t1) \
+ event_log1(tag, fmt_num, t1)
+#define _EVENT_LOG2(tag, fmt_num, t1, t2) \
+ event_log2(tag, fmt_num, t1, t2)
+#define _EVENT_LOG3(tag, fmt_num, t1, t2, t3) \
+ event_log3(tag, fmt_num, t1, t2, t3)
+#define _EVENT_LOG4(tag, fmt_num, t1, t2, t3, t4) \
+ event_log4(tag, fmt_num, t1, t2, t3, t4)
+
+/* The rest call the generic routine that takes a count */
+#define _EVENT_LOG5(tag, fmt_num, ...) event_logn(5, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG6(tag, fmt_num, ...) event_logn(6, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG7(tag, fmt_num, ...) event_logn(7, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG8(tag, fmt_num, ...) event_logn(8, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG9(tag, fmt_num, ...) event_logn(9, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGA(tag, fmt_num, ...) event_logn(10, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGB(tag, fmt_num, ...) event_logn(11, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGC(tag, fmt_num, ...) event_logn(12, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGD(tag, fmt_num, ...) event_logn(13, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGE(tag, fmt_num, ...) event_logn(14, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGF(tag, fmt_num, ...) event_logn(15, tag, fmt_num, __VA_ARGS__)
+
+
+/* Casting low level macros */
+#define _EVENT_LOG_CAST0(tag, fmt_num) \
+ event_log0(tag, fmt_num)
+#define _EVENT_LOG_CAST1(tag, fmt_num, t1) \
+ event_log1(tag, fmt_num, (uint32)(t1))
+#define _EVENT_LOG_CAST2(tag, fmt_num, t1, t2) \
+ event_log2(tag, fmt_num, (uint32)(t1), (uint32)(t2))
+#define _EVENT_LOG_CAST3(tag, fmt_num, t1, t2, t3) \
+ event_log3(tag, fmt_num, (uint32)(t1), (uint32)(t2), (uint32)(t3))
+#define _EVENT_LOG_CAST4(tag, fmt_num, t1, t2, t3, t4) \
+ event_log4(tag, fmt_num, (uint32)(t1), (uint32)(t2), (uint32)(t3), (uint32)(t4))
+
+/* The rest call the generic routine that takes a count */
+#define _EVENT_LOG_CAST5(tag, fmt_num, ...) _EVENT_LOG5(tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG_CAST6(tag, fmt_num, ...) _EVENT_LOG6(tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG_CAST7(tag, fmt_num, ...) _EVENT_LOG7(tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG_CAST8(tag, fmt_num, ...) _EVENT_LOG8(tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG_CAST9(tag, fmt_num, ...) _EVENT_LOG9(tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG_CASTA(tag, fmt_num, ...) _EVENT_LOGA(tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG_CASTB(tag, fmt_num, ...) _EVENT_LOGB(tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG_CASTC(tag, fmt_num, ...) _EVENT_LOGC(tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG_CASTD(tag, fmt_num, ...) _EVENT_LOGD(tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG_CASTE(tag, fmt_num, ...) _EVENT_LOGE(tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG_CASTF(tag, fmt_num, ...) _EVENT_LOGF(tag, fmt_num, __VA_ARGS__)
+
+/* Hack to make the proper routine call when variadic macros get
+ * passed. Note the max of 15 arguments. More than that can't be
+ * handled by the event_log entries anyways so best to catch it at compile
+ * time
+ */
+
+#define _EVENT_LOG_VA_NUM_ARGS(F, _1, _2, _3, _4, _5, _6, _7, _8, _9, \
+ _A, _B, _C, _D, _E, _F, N, ...) F ## N
+
+/* cast = _EVENT_LOG for no casting
+ * cast = _EVENT_LOG_CAST for casting of fmt arguments to uint32.
+ * Only first 4 arguments are casted to uint32. event_logn() is called
+ * if more than 4 arguments are present. This function internally assumes
+ * all arguments are uint32
+ */
+#define _EVENT_LOG(cast, tag, fmt, ...) \
+ static char logstr[] __attribute__ ((section(".logstrs"))) = fmt; \
+ static uint32 fmtnum __attribute__ ((section(".lognums"))) = (uint32) &logstr; \
+ _EVENT_LOG_VA_NUM_ARGS(cast, ##__VA_ARGS__, \
+ F, E, D, C, B, A, 9, 8, \
+ 7, 6, 5, 4, 3, 2, 1, 0) \
+ (tag, (int) &fmtnum , ## __VA_ARGS__)
+
+
+#define EVENT_LOG_FAST(tag, fmt, ...) \
+ do { \
+ if (event_log_tag_sets != NULL) { \
+ uint8 tag_flag = *(event_log_tag_sets + tag); \
+ if ((tag_flag & ~EVENT_LOG_TAG_FLAG_SET_MASK) != 0) { \
+ _EVENT_LOG(_EVENT_LOG, tag, fmt , ## __VA_ARGS__); \
+ } \
+ } \
+ } while (0)
+
+#define EVENT_LOG_COMPACT(tag, fmt, ...) \
+ do { \
+ _EVENT_LOG(_EVENT_LOG, tag, fmt , ## __VA_ARGS__); \
+ } while (0)
+
+/* Event log macro with casting to uint32 of arguments */
+#define EVENT_LOG_FAST_CAST(tag, fmt, ...) \
+ do { \
+ if (event_log_tag_sets != NULL) { \
+ uint8 tag_flag = *(event_log_tag_sets + tag); \
+ if ((tag_flag & ~EVENT_LOG_TAG_FLAG_SET_MASK) != 0) { \
+ _EVENT_LOG(_EVENT_LOG_CAST, tag, fmt , ## __VA_ARGS__); \
+ } \
+ } \
+ } while (0)
+
+#define EVENT_LOG_COMPACT_CAST(tag, fmt, ...) \
+ do { \
+ _EVENT_LOG(_EVENT_LOG_CAST, tag, fmt , ## __VA_ARGS__); \
+ } while (0)
+
+
+#define EVENT_LOG(tag, fmt, ...) EVENT_LOG_COMPACT(tag, fmt , ## __VA_ARGS__)
+
+#define EVENT_LOG_CAST(tag, fmt, ...) EVENT_LOG_COMPACT_CAST(tag, fmt , ## __VA_ARGS__)
+
+#define _EVENT_LOG_REMOVE_PAREN(...) __VA_ARGS__
+#define EVENT_LOG_REMOVE_PAREN(args) _EVENT_LOG_REMOVE_PAREN args
+
+#define EVENT_LOG_CAST_PAREN_ARGS(tag, pargs) \
+ EVENT_LOG_CAST(tag, EVENT_LOG_REMOVE_PAREN(pargs))
+
+#define EVENT_LOG_FAST_CAST_PAREN_ARGS(tag, pargs) \
+ EVENT_LOG_FAST_CAST(tag, EVENT_LOG_REMOVE_PAREN(pargs))
+
+#define EVENT_LOG_COMPACT_CAST_PAREN_ARGS(tag, pargs) \
+ EVENT_LOG_COMPACT_CAST(tag, EVENT_LOG_REMOVE_PAREN(pargs))
+
+/* Minimal event logging. Event log internally calls event_logx()
+ * log return address in caller.
+ * Note that the if(0){..} below is to avoid compiler warnings
+ * due to unused variables caused by this macro
+ */
+#define EVENT_LOG_RA(tag, args) \
+ do { \
+ if (0) { \
+ EVENT_LOG_COMPACT_CAST_PAREN_ARGS(tag, args); \
+ } \
+ event_log_caller_return_address(tag); \
+ } while (0)
+
+#define EVENT_LOG_IS_ON(tag) (*(event_log_tag_sets + (tag)) & ~EVENT_LOG_TAG_FLAG_SET_MASK)
+#define EVENT_LOG_IS_LOG_ON(tag) (*(event_log_tag_sets + (tag)) & EVENT_LOG_TAG_FLAG_LOG)
+
+#define EVENT_LOG_BUFFER(tag, buf, size) event_log_buffer(tag, buf, size)
+#define EVENT_DUMP event_log_buffer
+
+extern uint8 *event_log_tag_sets;
+
+extern int event_log_init(osl_t *osh);
+extern int event_log_set_init(osl_t *osh, int set_num, int size);
+extern int event_log_set_expand(osl_t *osh, int set_num, int size);
+extern int event_log_set_shrink(osl_t *osh, int set_num, int size);
+
+extern int event_log_tag_start(int tag, int set_num, int flags);
+extern int event_log_tag_stop(int tag);
+
+typedef void (*event_log_logtrace_trigger_fn_t)(void *ctx);
+void event_log_set_logtrace_trigger_fn(event_log_logtrace_trigger_fn_t fn, void *ctx);
+
+event_log_top_t *event_log_get_top(void);
+
+extern int event_log_get(int set_num, int buflen, void *buf);
+
+extern uint8 *event_log_next_logtrace(int set_num);
+
+extern void event_log0(int tag, int fmtNum);
+extern void event_log1(int tag, int fmtNum, uint32 t1);
+extern void event_log2(int tag, int fmtNum, uint32 t1, uint32 t2);
+extern void event_log3(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3);
+extern void event_log4(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3, uint32 t4);
+extern void event_logn(int num_args, int tag, int fmtNum, ...);
+
+extern void event_log_time_sync(uint32 ms);
+extern void event_log_buffer(int tag, uint8 *buf, int size);
+extern void event_log_caller_return_address(int tag);
+extern int event_log_set_destination_set(int set, event_log_set_destination_t dest);
+extern event_log_set_destination_t event_log_set_destination_get(int set);
+extern int event_log_flush_log_buffer(int set);
+extern bool event_log_is_ready(void);
+
+#endif /* EVENT_LOG_DUMPER */
+
+#endif /* EVENT_LOG_COMPILE */
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* _EVENT_LOG_H_ */
diff --git a/wl/src/include/miniopt.h b/wl/src/include/miniopt.h
new file mode 100644
index 0000000..80ab967
--- /dev/null
+++ b/wl/src/include/miniopt.h
@@ -0,0 +1,80 @@
+/*
+ * Command line options parser.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: miniopt.h 514727 2014-11-12 03:02:48Z $
+ */
+
+
+#ifndef MINI_OPT_H
+#define MINI_OPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#if defined(__FreeBSD__)
+#include <stdbool.h>
+#endif
+
+/* ---- Constants and Types ---------------------------------------------- */
+
+#define MINIOPT_MAXKEY 128 /* Max options */
+typedef struct miniopt {
+
+ /* These are persistent after miniopt_init() */
+ const char* name; /* name for prompt in error strings */
+ const char* flags; /* option chars that take no args */
+ bool longflags; /* long options may be flags */
+ bool opt_end; /* at end of options (passed a "--") */
+
+ /* These are per-call to miniopt() */
+
+ int consumed; /* number of argv entries cosumed in
+ * the most recent call to miniopt()
+ */
+ bool positional;
+ bool good_int; /* 'val' member is the result of a sucessful
+ * strtol conversion of the option value
+ */
+ char opt;
+ char key[MINIOPT_MAXKEY];
+ char* valstr; /* positional param, or value for the option,
+ * or null if the option had
+ * no accompanying value
+ */
+ uint uval; /* strtol translation of valstr */
+ int val; /* strtol translation of valstr */
+} miniopt_t;
+
+void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags);
+int miniopt(miniopt_t *t, char **argv);
+
+
+/* ---- Variable Externs ------------------------------------------------- */
+/* ---- Function Prototypes ---------------------------------------------- */
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* MINI_OPT_H */
diff --git a/wl/src/include/osl_decl.h b/wl/src/include/osl_decl.h
new file mode 100644
index 0000000..7ad7261
--- /dev/null
+++ b/wl/src/include/osl_decl.h
@@ -0,0 +1,31 @@
+/*
+ * osl forward declarations
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: osl_decl.h 596126 2015-10-29 19:53:48Z $
+ */
+
+#ifndef _osl_decl_h_
+#define _osl_decl_h_
+
+/* osl handle type forward declaration */
+typedef struct osl_info osl_t;
+typedef struct osl_dmainfo osldma_t;
+extern unsigned int lmtest; /* low memory test */
+#endif
diff --git a/wl/src/include/packed_section_end.h b/wl/src/include/packed_section_end.h
new file mode 100644
index 0000000..5c4e772
--- /dev/null
+++ b/wl/src/include/packed_section_end.h
@@ -0,0 +1,59 @@
+/*
+ * Declare directives for structure packing. No padding will be provided
+ * between the members of packed structures, and therefore, there is no
+ * guarantee that structure members will be aligned.
+ *
+ * Declaring packed structures is compiler specific. In order to handle all
+ * cases, packed structures should be delared as:
+ *
+ * #include <packed_section_start.h>
+ *
+ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t {
+ * some_struct_members;
+ * } BWL_POST_PACKED_STRUCT foobar_t;
+ *
+ * #include <packed_section_end.h>
+ *
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: packed_section_end.h 660496 2016-09-20 19:28:50Z $
+ */
+
+
+/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h
+ * and undefined in packed_section_end.h. If it is NOT defined at this
+ * point, then there is a missing include of packed_section_start.h.
+ */
+#ifdef BWL_PACKED_SECTION
+ #undef BWL_PACKED_SECTION
+#else
+ #error "BWL_PACKED_SECTION is NOT defined!"
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(disable:4103)
+#pragma pack(pop)
+#endif
+
+/* Compiler-specific directives for structure packing are declared in
+ * packed_section_start.h. This marks the end of the structure packing section,
+ * so, undef them here.
+ */
+#undef BWL_PRE_PACKED_STRUCT
+#undef BWL_POST_PACKED_STRUCT
diff --git a/wl/src/include/packed_section_start.h b/wl/src/include/packed_section_start.h
new file mode 100644
index 0000000..da805bd
--- /dev/null
+++ b/wl/src/include/packed_section_start.h
@@ -0,0 +1,109 @@
+/*
+ * Declare directives for structure packing. No padding will be provided
+ * between the members of packed structures, and therefore, there is no
+ * guarantee that structure members will be aligned.
+ *
+ * Declaring packed structures is compiler specific. In order to handle all
+ * cases, packed structures should be delared as:
+ *
+ * #include <packed_section_start.h>
+ *
+ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t {
+ * some_struct_members;
+ * } BWL_POST_PACKED_STRUCT foobar_t;
+ *
+ * #include <packed_section_end.h>
+ *
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: packed_section_start.h 660529 2016-09-20 23:01:03Z $
+ */
+
+
+#ifndef _alignment_test_
+#define _alignment_test_
+
+/* ASSERT default packing */
+typedef struct T4 {
+ uint8 a;
+ uint32 b;
+ uint16 c;
+ uint8 d;
+} T4_t;
+
+/* 4 byte alignment support */
+/*
+* a . . .
+* b b b b
+* c c d .
+*/
+
+/*
+ * Below function is meant to verify that this file is compiled with the default alignment of 4.
+ * Function will fail to compile if the condition is not met.
+ */
+#ifdef __GNUC__
+#define VARIABLE_IS_NOT_USED __attribute__ ((unused))
+#else
+#define VARIABLE_IS_NOT_USED
+#endif
+static void alignment_test(void);
+static void
+VARIABLE_IS_NOT_USED alignment_test(void)
+{
+ /* verify 4 byte alignment support */
+ STATIC_ASSERT(sizeof(T4_t) == 12);
+}
+#endif /* _alignment_test_ */
+
+
+/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h
+ * and undefined in packed_section_end.h. If it is already defined at this
+ * point, then there is a missing include of packed_section_end.h.
+ */
+#ifdef BWL_PACKED_SECTION
+ #error "BWL_PACKED_SECTION is already defined!"
+#else
+ #define BWL_PACKED_SECTION
+#endif
+
+#if defined(BWL_DEFAULT_PACKING)
+ /* generate an error if BWL_DEFAULT_PACKING is defined */
+ #error "BWL_DEFAULT_PACKING not supported any more."
+#endif /* BWL_PACKED_SECTION */
+
+#if defined(_MSC_VER)
+#pragma warning(disable:4103)
+#pragma pack(push)
+#pragma pack(1)
+#endif
+
+/* Declare compiler-specific directives for structure packing. */
+#if defined(_MSC_VER)
+ #define BWL_PRE_PACKED_STRUCT
+ #define BWL_POST_PACKED_STRUCT
+#elif defined(__GNUC__) || defined(__lint)
+ #define BWL_PRE_PACKED_STRUCT
+ #define BWL_POST_PACKED_STRUCT __attribute__ ((packed))
+#elif defined(__CC_ARM)
+ #define BWL_PRE_PACKED_STRUCT __packed
+ #define BWL_POST_PACKED_STRUCT
+#else
+ #error "Unknown compiler!"
+#endif
diff --git a/wl/src/include/rte_ioctl.h b/wl/src/include/rte_ioctl.h
new file mode 100644
index 0000000..bb9023e
--- /dev/null
+++ b/wl/src/include/rte_ioctl.h
@@ -0,0 +1,87 @@
+/*
+ * HND Run Time Environment ioctl.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: rte_ioctl.h 637908 2016-05-16 06:59:09Z $
+ */
+
+#ifndef _rte_ioctl_h_
+#define _rte_ioctl_h_
+
+/* RTE IOCTL definitions for generic ether devices */
+#define RTEGHWADDR 0x8901
+#define RTESHWADDR 0x8902
+#define RTEGMTU 0x8903
+#define RTEGSTATS 0x8904
+#define RTEGALLMULTI 0x8905
+#define RTESALLMULTI 0x8906
+#define RTEGPROMISC 0x8907
+#define RTESPROMISC 0x8908
+#define RTESMULTILIST 0x8909
+#define RTEGUP 0x890A
+#define RTEGPERMADDR 0x890B
+#define RTEDEVPWRSTCHG 0x890C /* Device pwr state change for PCIedev */
+#define RTEDEVPMETOGGLE 0x890D /* Toggle PME# to wake up the host */
+#define RTEDEVTIMESYNC 0x890E /* Device TimeSync */
+#define RTEDEVDSNOTIFY 0x890F /* Bus DS state notification */
+
+#define RTE_IOCTL_QUERY 0x00
+#define RTE_IOCTL_SET 0x01
+#define RTE_IOCTL_OVL_IDX_MASK 0x1e
+#define RTE_IOCTL_OVL_RSV 0x20
+#define RTE_IOCTL_OVL 0x40
+#define RTE_IOCTL_OVL_IDX_SHIFT 1
+
+enum hnd_ioctl_cmd {
+ HND_RTE_DNGL_IS_SS = 1, /* true if device connected at super speed */
+
+ /* PCIEDEV specific wl <--> bus ioctls */
+ BUS_GET_VAR = 2,
+ BUS_SET_VAR = 3,
+ BUS_FLUSH_RXREORDER_Q = 4,
+ BUS_SET_LTR_STATE = 5,
+ BUS_FLUSH_CHAINED_PKTS = 6,
+ BUS_SET_COPY_COUNT = 7,
+ BUS_UPDATE_FLOW_PKTS_MAX = 8,
+ BUS_UPDATE_EXTRA_TXLFRAGS = 9,
+ BUS_UPDATE_FRWD_RESRV_BUFCNT = 10
+};
+
+#define SDPCMDEV_SET_MAXTXPKTGLOM 1
+#define RTE_MEMUSEINFO_VER 0x00
+
+typedef struct memuse_info {
+ uint16 ver; /* version of this struct */
+ uint16 len; /* length in bytes of this structure */
+ uint32 tot; /* Total memory */
+ uint32 text_len; /* Size of Text segment memory */
+ uint32 data_len; /* Size of Data segment memory */
+ uint32 bss_len; /* Size of BSS segment memory */
+
+ uint32 arena_size; /* Total Heap size */
+ uint32 arena_free; /* Heap memory available or free */
+ uint32 inuse_size; /* Heap memory currently in use */
+ uint32 inuse_hwm; /* High watermark of memory - reclaimed memory */
+ uint32 inuse_overhead; /* tally of allocated mem_t blocks */
+ uint32 inuse_total; /* Heap in-use + Heap overhead memory */
+ uint32 free_lwm; /* Least free size since reclaim */
+ uint32 mf_count; /* Malloc failure count */
+} memuse_info_t;
+
+#endif /* _rte_ioctl_h_ */
diff --git a/wl/src/include/rwl_wifi.h b/wl/src/include/rwl_wifi.h
new file mode 100644
index 0000000..1e3f050
--- /dev/null
+++ b/wl/src/include/rwl_wifi.h
@@ -0,0 +1,98 @@
+/*
+ * RWL definitions of
+ * Broadcom 802.11bang Networking Device Driver
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: rwl_wifi.h 524641 2015-01-07 15:25:03Z $
+ *
+ */
+
+#ifndef _rwl_wifi_h_
+#define _rwl_wifi_h_
+
+#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR) || defined(RFAWARE)
+
+#define RWL_ACTION_WIFI_CATEGORY 127 /* Vendor-specific category value for WiFi */
+#define RWL_WIFI_OUI_BYTE0 0x00 /* BRCM-specific public OUI */
+#define RWL_WIFI_OUI_BYTE1 0x90
+#define RWL_WIFI_OUI_BYTE2 0x4c
+#define RWL_WIFI_ACTION_FRAME_SIZE sizeof(struct dot11_action_wifi_vendor_specific)
+
+/*
+ * Information about the action frame data fields in the dot11_action_wifi_vendor_specific
+ * cdc structure (1 to 16). This does not include the status flag. Since this
+ * is not directly visible to the driver code, we can't use sizeof(struct cdc_ioctl).
+ * Hence Ref MAC address offset starts from byte 17.
+ * REF MAC ADDR (6 bytes (MAC Address len) from byte 17 to 22)
+ * DUT MAC ADDR (6 bytes after the REF MAC Address byte 23 to 28)
+ * unused (byte 29 to 49)
+ * REF/Client Channel offset (50)
+ * DUT/Server channel offset (51)
+ * ---------------------------------------------------------------------------------------
+ * cdc struct|REF MAC ADDR|DUT_MAC_ADDR|un used|REF Channel|DUT channel|Action frame Data|
+ * 1---------17-----------23-------------------50----------51----------52----------------1040
+ * REF MAC addr after CDC struct without status flag (status flag not used by wifi)
+ */
+
+#define RWL_REF_MAC_ADDRESS_OFFSET 17
+#define RWL_DUT_MAC_ADDRESS_OFFSET 23
+#define RWL_WIFI_CLIENT_CHANNEL_OFFSET 50
+#define RWL_WIFI_SERVER_CHANNEL_OFFSET 51
+
+#ifdef WIFI_REFLECTOR
+#include <bcmcdc.h>
+#define REMOTE_FINDSERVER_CMD 16
+#define RWL_WIFI_ACTION_CMD "wifiaction"
+#define RWL_WIFI_ACTION_CMD_LEN 11 /* With the NULL terminator */
+#define REMOTE_SET_CMD 1
+#define REMOTE_GET_CMD 2
+#define REMOTE_REPLY 4
+#define RWL_WIFI_DEFAULT_TYPE 0x00
+#define RWL_WIFI_DEFAULT_SUBTYPE 0x00
+#define RWL_ACTION_FRAME_DATA_SIZE 1024 /* fixed size for the wifi frame data */
+#define RWL_WIFI_CDC_HEADER_OFFSET 0
+#define RWL_WIFI_FRAG_DATA_SIZE 960 /* max size of the frag data */
+#define RWL_DEFAULT_WIFI_FRAG_COUNT 127 /* maximum fragment count */
+#define RWL_WIFI_RETRY 5 /* CMD retry count for wifi */
+#define RWL_WIFI_SEND 5 /* WIFI frame sent count */
+#define RWL_WIFI_SEND_DELAY 100 /* delay between two frames */
+#define MICROSEC_CONVERTOR_VAL 1000
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+typedef struct rem_packet {
+ rem_ioctl_t rem_cdc;
+ uchar message [RWL_ACTION_FRAME_DATA_SIZE];
+} rem_packet_t;
+
+#include <packed_section_start.h>
+struct BWL_PRE_PACKED_STRUCT send_packet {
+ char command [RWL_WIFI_ACTION_CMD_LEN];
+ dot11_action_wifi_vendor_specific_t response;
+} BWL_POST_PACKED_STRUCT;
+#include <packed_section_end.h>
+
+typedef struct send_packet send_packet_t;
+
+#define REMOTE_SIZE sizeof(rem_ioctl_t)
+#endif /* WIFI_REFLECTOR */
+
+typedef struct rwl_request {
+ struct rwl_request* next_request;
+ struct dot11_action_wifi_vendor_specific action_frame;
+} rwl_request_t;
+
+
+#endif
+#endif /* _rwl_wifi_h_ */
diff --git a/wl/src/include/sbpcmcia.h b/wl/src/include/sbpcmcia.h
new file mode 100644
index 0000000..a9a6484
--- /dev/null
+++ b/wl/src/include/sbpcmcia.h
@@ -0,0 +1,417 @@
+/*
+ * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sbpcmcia.h 647676 2016-07-07 02:59:05Z $
+ */
+
+#ifndef _SBPCMCIA_H
+#define _SBPCMCIA_H
+
+/* All the addresses that are offsets in attribute space are divided
+ * by two to account for the fact that odd bytes are invalid in
+ * attribute space and our read/write routines make the space appear
+ * as if they didn't exist. Still we want to show the original numbers
+ * as documented in the hnd_pcmcia core manual.
+ */
+
+/* PCMCIA Function Configuration Registers */
+#define PCMCIA_FCR (0x700 / 2)
+
+#define FCR0_OFF 0
+#define FCR1_OFF (0x40 / 2)
+#define FCR2_OFF (0x80 / 2)
+#define FCR3_OFF (0xc0 / 2)
+
+#define PCMCIA_FCR0 (0x700 / 2)
+#define PCMCIA_FCR1 (0x740 / 2)
+#define PCMCIA_FCR2 (0x780 / 2)
+#define PCMCIA_FCR3 (0x7c0 / 2)
+
+/* Standard PCMCIA FCR registers */
+
+#define PCMCIA_COR 0
+
+#define COR_RST 0x80
+#define COR_LEV 0x40
+#define COR_IRQEN 0x04
+#define COR_BLREN 0x01
+#define COR_FUNEN 0x01
+
+
+#define PCICIA_FCSR (2 / 2)
+#define PCICIA_PRR (4 / 2)
+#define PCICIA_SCR (6 / 2)
+#define PCICIA_ESR (8 / 2)
+
+
+#define PCM_MEMOFF 0x0000
+#define F0_MEMOFF 0x1000
+#define F1_MEMOFF 0x2000
+#define F2_MEMOFF 0x3000
+#define F3_MEMOFF 0x4000
+
+/* Memory base in the function fcr's */
+#define MEM_ADDR0 (0x728 / 2)
+#define MEM_ADDR1 (0x72a / 2)
+#define MEM_ADDR2 (0x72c / 2)
+
+/* PCMCIA base plus Srom access in fcr0: */
+#define PCMCIA_ADDR0 (0x072e / 2)
+#define PCMCIA_ADDR1 (0x0730 / 2)
+#define PCMCIA_ADDR2 (0x0732 / 2)
+
+#define MEM_SEG (0x0734 / 2)
+#define SROM_CS (0x0736 / 2)
+#define SROM_DATAL (0x0738 / 2)
+#define SROM_DATAH (0x073a / 2)
+#define SROM_ADDRL (0x073c / 2)
+#define SROM_ADDRH (0x073e / 2)
+#define SROM_INFO2 (0x0772 / 2) /* Corerev >= 2 && <= 5 */
+#define SROM_INFO (0x07be / 2) /* Corerev >= 6 */
+
+/* Values for srom_cs: */
+#define SROM_IDLE 0
+#define SROM_WRITE 1
+#define SROM_READ 2
+#define SROM_WEN 4
+#define SROM_WDS 7
+#define SROM_DONE 8
+
+/* Fields in srom_info: */
+#define SRI_SZ_MASK 0x03
+#define SRI_BLANK 0x04
+#define SRI_OTP 0x80
+
+
+#define SROM16K_BANK_SEL_MASK (3 << 11)
+#define SROM16K_BANK_SHFT_MASK 11
+#define SROM16K_ADDR_SEL_MASK ((1 << SROM16K_BANK_SHFT_MASK) - 1)
+#define SROM_PRSNT_MASK 0x1
+#define SROM_SUPPORT_SHIFT_MASK 30
+#define SROM_SUPPORTED (0x1 << SROM_SUPPORT_SHIFT_MASK)
+#define SROM_SIZE_MASK 0x00000006
+#define SROM_SIZE_2K 2
+#define SROM_SIZE_512 1
+#define SROM_SIZE_128 0
+#define SROM_SIZE_SHFT_MASK 1
+
+#if !defined(LINUX_POSTMOGRIFY_REMOVAL)
+/* CIS stuff */
+
+/* The CIS stops where the FCRs start */
+#define CIS_SIZE PCMCIA_FCR
+#define CIS_SIZE_12K 1154 /* Maximum h/w + s/w sub region size for 12k OTP */
+
+/* CIS tuple length field max */
+#define CIS_TUPLE_LEN_MAX 0xff
+#endif /* !defined(LINUX_POSTMOGRIFY_REMOVAL) */
+
+/* Standard tuples we know about */
+
+#define CISTPL_NULL 0x00
+#define CISTPL_END 0xff /* End of the CIS tuple chain */
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define CISTPL_VERS_1 0x15 /* CIS ver, manf, dev & ver strings */
+#define CISTPL_MANFID 0x20 /* Manufacturer and device id */
+#define CISTPL_FUNCID 0x21 /* Function identification */
+#define CISTPL_FUNCE 0x22 /* Function extensions */
+#define CISTPL_CFTABLE 0x1b /* Config table entry */
+
+/* Function identifier provides context for the function extentions tuple */
+#define CISTPL_FID_SDIO 0x0c /* Extensions defined by SDIO spec */
+
+/* Function extensions for LANs (assumed for extensions other than SDIO) */
+#define LAN_TECH 1 /* Technology type */
+#define LAN_SPEED 2 /* Raw bit rate */
+#define LAN_MEDIA 3 /* Transmission media */
+#define LAN_NID 4 /* Node identification (aka MAC addr) */
+#define LAN_CONN 5 /* Connector standard */
+
+
+/* CFTable */
+#define CFTABLE_REGWIN_2K 0x08 /* 2k reg windows size */
+#define CFTABLE_REGWIN_4K 0x10 /* 4k reg windows size */
+#define CFTABLE_REGWIN_8K 0x20 /* 8k reg windows size */
+
+/* Vendor unique tuples are 0x80-0x8f. Within Broadcom we'll
+ * take one for HNBU, and use "extensions" (a la FUNCE) within it.
+ */
+#endif /* !defined(LINUX_POSTMOGRIFY_REMOVAL) */
+
+#define CISTPL_BRCM_HNBU 0x80
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+/* Subtypes of BRCM_HNBU: */
+
+#define HNBU_SROMREV 0x00 /* A byte with sromrev, 1 if not present */
+#define HNBU_CHIPID 0x01 /* Two 16bit values: PCI vendor & device id */
+#endif /* !defined(LINUX_POSTMOGRIFY_REMOVAL) */
+
+#define HNBU_BOARDREV 0x02 /* One byte board revision */
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define HNBU_PAPARMS 0x03 /* PA parameters: 8 (sromrev == 1)
+ * or 9 (sromrev > 1) bytes
+ */
+#define HNBU_OEM 0x04 /* Eight bytes OEM data (sromrev == 1) */
+#define HNBU_CC 0x05 /* Default country code (sromrev == 1) */
+#define HNBU_AA 0x06 /* Antennas available */
+#define HNBU_AG 0x07 /* Antenna gain */
+#define HNBU_BOARDFLAGS 0x08 /* board flags (2 or 4 bytes) */
+#define HNBU_LEDS 0x09 /* LED set */
+#define HNBU_CCODE 0x0a /* Country code (2 bytes ascii + 1 byte cctl)
+ * in rev 2
+ */
+#define HNBU_CCKPO 0x0b /* 2 byte cck power offsets in rev 3 */
+#define HNBU_OFDMPO 0x0c /* 4 byte 11g ofdm power offsets in rev 3 */
+#define HNBU_GPIOTIMER 0x0d /* 2 bytes with on/off values in rev 3 */
+#define HNBU_PAPARMS5G 0x0e /* 5G PA params */
+#define HNBU_ANT5G 0x0f /* 4328 5G antennas available/gain */
+#define HNBU_RDLID 0x10 /* 2 byte USB remote downloader (RDL) product Id */
+#define HNBU_RSSISMBXA2G 0x11 /* 4328 2G RSSI mid pt sel & board switch arch,
+ * 2 bytes, rev 3.
+ */
+#define HNBU_RSSISMBXA5G 0x12 /* 4328 5G RSSI mid pt sel & board switch arch,
+ * 2 bytes, rev 3.
+ */
+#define HNBU_XTALFREQ 0x13 /* 4 byte Crystal frequency in kilohertz */
+#define HNBU_TRI2G 0x14 /* 4328 2G TR isolation, 1 byte */
+#define HNBU_TRI5G 0x15 /* 4328 5G TR isolation, 3 bytes */
+#define HNBU_RXPO2G 0x16 /* 4328 2G RX power offset, 1 byte */
+#define HNBU_RXPO5G 0x17 /* 4328 5G RX power offset, 1 byte */
+#define HNBU_BOARDNUM 0x18 /* board serial number, independent of mac addr */
+#define HNBU_MACADDR 0x19 /* mac addr override for the standard CIS LAN_NID */
+#define HNBU_RDLSN 0x1a /* 2 bytes; serial # advertised in USB descriptor */
+#endif /* !defined(LINUX_POSTMOGRIFY_REMOVAL) */
+
+#define HNBU_BOARDTYPE 0x1b /* 2 bytes; boardtype */
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define HNBU_LEDDC 0x1c /* 2 bytes; LED duty cycle */
+#endif /* !defined(LINUX_POSTMOGRIFY_REMOVAL) */
+
+#define HNBU_HNBUCIS 0x1d /* what follows is proprietary HNBU CIS format */
+
+#ifndef LINUX_POSTMOGRIFY_REMOVAL
+#define HNBU_PAPARMS_SSLPNPHY 0x1e /* SSLPNPHY PA params */
+#define HNBU_RSSISMBXA2G_SSLPNPHY 0x1f /* SSLPNPHY RSSI mid pt sel & board switch arch */
+#define HNBU_RDLRNDIS 0x20 /* 1 byte; 1 = RDL advertises RNDIS config */
+#define HNBU_CHAINSWITCH 0x21 /* 2 byte; txchain, rxchain */
+#define HNBU_REGREV 0x22 /* 1 byte; */
+#define HNBU_FEM 0x23 /* 2 or 4 byte: 11n frontend specification */
+#define HNBU_PAPARMS_C0 0x24 /* 8 or 30 bytes: 11n pa paramater for chain 0 */
+#define HNBU_PAPARMS_C1 0x25 /* 8 or 30 bytes: 11n pa paramater for chain 1 */
+#define HNBU_PAPARMS_C2 0x26 /* 8 or 30 bytes: 11n pa paramater for chain 2 */
+#define HNBU_PAPARMS_C3 0x27 /* 8 or 30 bytes: 11n pa paramater for chain 3 */
+#define HNBU_PO_CCKOFDM 0x28 /* 6 or 18 bytes: cck2g/ofdm2g/ofdm5g power offset */
+#define HNBU_PO_MCS2G 0x29 /* 8 bytes: mcs2g power offset */
+#define HNBU_PO_MCS5GM 0x2a /* 8 bytes: mcs5g mid band power offset */
+#define HNBU_PO_MCS5GLH 0x2b /* 16 bytes: mcs5g low-high band power offset */
+#define HNBU_PO_CDD 0x2c /* 2 bytes: cdd2g/5g power offset */
+#define HNBU_PO_STBC 0x2d /* 2 bytes: stbc2g/5g power offset */
+#define HNBU_PO_40M 0x2e /* 2 bytes: 40Mhz channel 2g/5g power offset */
+#define HNBU_PO_40MDUP 0x2f /* 2 bytes: 40Mhz channel dup 2g/5g power offset */
+
+#define HNBU_RDLRWU 0x30 /* 1 byte; 1 = RDL advertises Remote Wake-up */
+#define HNBU_WPS 0x31 /* 1 byte; GPIO pin for WPS button */
+#define HNBU_USBFS 0x32 /* 1 byte; 1 = USB advertises FS mode only */
+#define HNBU_BRMIN 0x33 /* 4 byte bootloader min resource mask */
+#define HNBU_BRMAX 0x34 /* 4 byte bootloader max resource mask */
+#define HNBU_PATCH 0x35 /* bootloader patch addr(2b) & data(4b) pair */
+#define HNBU_CCKFILTTYPE 0x36 /* CCK digital filter selection options */
+#define HNBU_OFDMPO5G 0x37 /* 4 * 3 = 12 byte 11a ofdm power offsets in rev 3 */
+#define HNBU_ELNA2G 0x38
+#define HNBU_ELNA5G 0x39
+#define HNBU_TEMPTHRESH 0x3A /* 2 bytes
+ * byte1 tempthresh
+ * byte2 period(msb 4 bits) | hysterisis(lsb 4 bits)
+ */
+#define HNBU_UUID 0x3B /* 16 Bytes Hex */
+
+#define HNBU_USBEPNUM 0x40 /* USB endpoint numbers */
+
+/* POWER PER RATE for SROM V9 */
+#define HNBU_CCKBW202GPO 0x41 /* 2 bytes each
+ * CCK Power offsets for 20 MHz rates (11, 5.5, 2, 1Mbps)
+ * cckbw202gpo cckbw20ul2gpo
+ */
+
+#define HNBU_LEGOFDMBW202GPO 0x42 /* 4 bytes each
+ * OFDM power offsets for 20 MHz Legacy rates
+ * (54, 48, 36, 24, 18, 12, 9, 6 Mbps)
+ * legofdmbw202gpo legofdmbw20ul2gpo
+ */
+
+#define HNBU_LEGOFDMBW205GPO 0x43 /* 4 bytes each
+ * 5G band: OFDM power offsets for 20 MHz Legacy rates
+ * (54, 48, 36, 24, 18, 12, 9, 6 Mbps)
+ * low subband : legofdmbw205glpo legofdmbw20ul2glpo
+ * mid subband :legofdmbw205gmpo legofdmbw20ul2gmpo
+ * high subband :legofdmbw205ghpo legofdmbw20ul2ghpo
+ */
+
+#define HNBU_MCS2GPO 0x44 /* 4 bytes each
+ * mcs 0-7 power-offset. LSB nibble: m0, MSB nibble: m7
+ * mcsbw202gpo mcsbw20ul2gpo mcsbw402gpo
+ */
+#define HNBU_MCS5GLPO 0x45 /* 4 bytes each
+ * 5G low subband mcs 0-7 power-offset.
+ * LSB nibble: m0, MSB nibble: m7
+ * mcsbw205glpo mcsbw20ul5glpo mcsbw405glpo
+ */
+#define HNBU_MCS5GMPO 0x46 /* 4 bytes each
+ * 5G mid subband mcs 0-7 power-offset.
+ * LSB nibble: m0, MSB nibble: m7
+ * mcsbw205gmpo mcsbw20ul5gmpo mcsbw405gmpo
+ */
+#define HNBU_MCS5GHPO 0x47 /* 4 bytes each
+ * 5G high subband mcs 0-7 power-offset.
+ * LSB nibble: m0, MSB nibble: m7
+ * mcsbw205ghpo mcsbw20ul5ghpo mcsbw405ghpo
+ */
+#define HNBU_MCS32PO 0x48 /* 2 bytes total
+ * mcs-32 power offset for each band/subband.
+ * LSB nibble: 2G band, MSB nibble:
+ * mcs322ghpo, mcs325gmpo, mcs325glpo, mcs322gpo
+ */
+#define HNBU_LEG40DUPPO 0x49 /* 2 bytes total
+ * Additional power offset for Legacy Dup40 transmissions.
+ * Applied in addition to legofdmbw20ulXpo, X=2g, 5gl, 5gm, or 5gh.
+ * LSB nibble: 2G band, MSB nibble: 5G band high subband.
+ * leg40dup5ghpo, leg40dup5gmpo, leg40dup5glpo, leg40dup2gpo
+ */
+
+#define HNBU_PMUREGS 0x4a /* Variable length (5 bytes for each register)
+ * The setting of the ChipCtrl, PLL, RegulatorCtrl, Up/Down Timer and
+ * ResourceDependency Table registers.
+ */
+
+#define HNBU_PATCH2 0x4b /* bootloader TCAM patch addr(4b) & data(4b) pair .
+ * This is required for socram rev 15 onwards.
+ */
+
+#define HNBU_USBRDY 0x4c /* Variable length (upto 5 bytes)
+ * This is to indicate the USB/HSIC host controller
+ * that the device is ready for enumeration.
+ */
+
+#define HNBU_USBREGS 0x4d /* Variable length
+ * The setting of the devcontrol, HSICPhyCtrl1 and HSICPhyCtrl2
+ * registers during the USB initialization.
+ */
+
+#define HNBU_BLDR_TIMEOUT 0x4e /* 2 bytes used for HSIC bootloader to reset chip
+ * on connect timeout.
+ * The Delay after USBConnect for timeout till dongle receives
+ * get_descriptor request.
+ */
+#define HNBU_USBFLAGS 0x4f
+#define HNBU_PATCH_AUTOINC 0x50
+#define HNBU_MDIO_REGLIST 0x51
+#define HNBU_MDIOEX_REGLIST 0x52
+/* Unified OTP: tupple to embed USB manfid inside SDIO CIS */
+#define HNBU_UMANFID 0x53
+#define HNBU_PUBKEY 0x54 /* 128 byte; publick key to validate downloaded FW */
+#define HNBU_WOWLGPIO 0x55 /* 1 byte bit 7 initial polarity, bit 6..0 gpio pin */
+#define HNBU_MUXENAB 0x56 /* 1 byte to enable mux options */
+#define HNBU_GCI_CCR 0x57 /* GCI Chip control register */
+
+#define HNBU_FEM_CFG 0x58 /* FEM config */
+#define HNBU_ACPA_C0 0x59 /* ACPHY PA parameters: chain 0 */
+#define HNBU_ACPA_C1 0x5a /* ACPHY PA parameters: chain 1 */
+#define HNBU_ACPA_C2 0x5b /* ACPHY PA parameters: chain 2 */
+#define HNBU_MEAS_PWR 0x5c
+#define HNBU_PDOFF 0x5d
+#define HNBU_ACPPR_2GPO 0x5e /* ACPHY Power-per-rate 2gpo */
+#define HNBU_ACPPR_5GPO 0x5f /* ACPHY Power-per-rate 5gpo */
+#define HNBU_ACPPR_SBPO 0x60 /* ACPHY Power-per-rate sbpo */
+#define HNBU_NOISELVL 0x61
+#define HNBU_RXGAIN_ERR 0x62
+#define HNBU_AGBGA 0x63
+#define HNBU_USBDESC_COMPOSITE 0x64 /* USB WLAN/BT composite descriptor */
+#define HNBU_PATCH_AUTOINC8 0x65 /* Auto increment patch entry for 8 byte patching */
+#define HNBU_PATCH8 0x66 /* Patch entry for 8 byte patching */
+#define HNBU_ACRXGAINS_C0 0x67 /* ACPHY rxgains: chain 0 */
+#define HNBU_ACRXGAINS_C1 0x68 /* ACPHY rxgains: chain 1 */
+#define HNBU_ACRXGAINS_C2 0x69 /* ACPHY rxgains: chain 2 */
+#define HNBU_TXDUTY 0x6a /* Tx duty cycle for ACPHY 5g 40/80 Mhz */
+#define HNBU_USBUTMI_CTL 0x6b /* 2 byte USB UTMI/LDO Control */
+#define HNBU_PDOFF_2G 0x6c
+#define HNBU_USBSSPHY_UTMI_CTL0 0x6d /* 4 byte USB SSPHY UTMI Control */
+#define HNBU_USBSSPHY_UTMI_CTL1 0x6e /* 4 byte USB SSPHY UTMI Control */
+#define HNBU_USBSSPHY_UTMI_CTL2 0x6f /* 4 byte USB SSPHY UTMI Control */
+#define HNBU_USBSSPHY_SLEEP0 0x70 /* 2 byte USB SSPHY sleep */
+#define HNBU_USBSSPHY_SLEEP1 0x71 /* 2 byte USB SSPHY sleep */
+#define HNBU_USBSSPHY_SLEEP2 0x72 /* 2 byte USB SSPHY sleep */
+#define HNBU_USBSSPHY_SLEEP3 0x73 /* 2 byte USB SSPHY sleep */
+#define HNBU_USBSSPHY_MDIO 0x74 /* USB SSPHY INIT regs setting */
+#define HNBU_USB30PHY_NOSS 0x75 /* USB30 NO Super Speed */
+#define HNBU_USB30PHY_U1U2 0x76 /* USB30 PHY U1U2 Enable */
+#define HNBU_USB30PHY_REGS 0x77 /* USB30 PHY REGs update */
+#define HNBU_GPIO_PULL_DOWN 0x78 /* 4 byte GPIO pull down mask */
+
+#define HNBU_SROM3SWRGN 0x80 /* 78 bytes; srom rev 3 s/w region without crc8
+ * plus extra info appended.
+ */
+#define HNBU_RESERVED 0x81 /* Reserved for non-BRCM post-mfg additions */
+#define HNBU_CUSTOM1 0x82 /* 4 byte; For non-BRCM post-mfg additions */
+#define HNBU_CUSTOM2 0x83 /* Reserved; For non-BRCM post-mfg additions */
+#define HNBU_ACPAPARAM 0x84 /* ACPHY PAPARAM */
+#define HNBU_ACPA_CCK_C0 0x86 /* ACPHY PA trimming parameters: CCK */
+#define HNBU_ACPA_40 0x87 /* ACPHY PA trimming parameters: 40 */
+#define HNBU_ACPA_80 0x88 /* ACPHY PA trimming parameters: 80 */
+#define HNBU_ACPA_4080 0x89 /* ACPHY PA trimming parameters: 40/80 */
+#define HNBU_SUBBAND5GVER 0x8a /* subband5gver */
+#define HNBU_PAPARAMBWVER 0x8b /* paparambwver */
+
+#define HNBU_MCS5Gx1PO 0x8c
+#define HNBU_ACPPR_SB8080_PO 0x8d
+#define HNBU_TXBFRPCALS 0x8f /* phy txbf rpcalvars */
+#define HNBU_MACADDR2 0x90 /* (optional) 2nd mac-addr for RSDB chips */
+
+#define HNBU_ACPA_4X4C0 0x91
+#define HNBU_ACPA_4X4C1 0x92
+#define HNBU_ACPA_4X4C2 0x93
+#define HNBU_ACPA_4X4C3 0x94
+#define HNBU_ACPA_BW20_4X4C0 0x95
+#define HNBU_ACPA_BW40_4X4C0 0x96
+#define HNBU_ACPA_BW80_4X4C0 0x97
+#define HNBU_ACPA_BW20_4X4C1 0x98
+#define HNBU_ACPA_BW40_4X4C1 0x99
+#define HNBU_ACPA_BW80_4X4C1 0x9a
+#define HNBU_ACPA_BW20_4X4C2 0x9b
+#define HNBU_ACPA_BW40_4X4C2 0x9c
+#define HNBU_ACPA_BW80_4X4C2 0x9d
+#define HNBU_ACPA_BW20_4X4C3 0x9e
+#define HNBU_ACPA_BW40_4X4C3 0x9f
+#define HNBU_ACPA_BW80_4X4C3 0xa0
+#define HNBU_ACPA_CCK_C1 0xa1 /* ACPHY PA trimming parameters: CCK */
+
+
+#endif /* !defined(LINUX_POSTMOGRIFY_REMOVAL) */
+
+/* sbtmstatelow */
+#define SBTML_INT_ACK 0x40000 /* ack the sb interrupt */
+#define SBTML_INT_EN 0x20000 /* enable sb interrupt */
+
+/* sbtmstatehigh */
+#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */
+#endif /* _SBPCMCIA_H */
diff --git a/wl/src/include/sdiovar.h b/wl/src/include/sdiovar.h
new file mode 100644
index 0000000..3628ac0
--- /dev/null
+++ b/wl/src/include/sdiovar.h
@@ -0,0 +1,117 @@
+/*
+ * Structure used by apps whose drivers access SDIO drivers.
+ * Pulled out separately so dhdu and wlu can both use it.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sdiovar.h 660496 2016-09-20 19:28:50Z $
+ */
+
+#ifndef _sdiovar_h_
+#define _sdiovar_h_
+
+#include <typedefs.h>
+
+typedef struct sdreg {
+ int func;
+ int offset;
+ int value;
+} sdreg_t;
+
+/* Common msglevel constants */
+#define SDH_ERROR_VAL 0x0001 /* Error */
+#define SDH_TRACE_VAL 0x0002 /* Trace */
+#define SDH_INFO_VAL 0x0004 /* Info */
+#define SDH_DEBUG_VAL 0x0008 /* Debug */
+#define SDH_DATA_VAL 0x0010 /* Data */
+#define SDH_CTRL_VAL 0x0020 /* Control Regs */
+#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */
+#define SDH_DMA_VAL 0x0080 /* DMA */
+
+#define NUM_PREV_TRANSACTIONS 16
+
+#ifdef BCMSPI
+/* Error statistics for gSPI */
+struct spierrstats_t {
+ uint32 dna; /* The requested data is not available. */
+ uint32 rdunderflow; /* FIFO underflow happened due to current (F2, F3) rd command */
+ uint32 wroverflow; /* FIFO underflow happened due to current (F1, F2, F3) wr command */
+
+ uint32 f2interrupt; /* OR of all F2 related intr status bits. */
+ uint32 f3interrupt; /* OR of all F3 related intr status bits. */
+
+ uint32 f2rxnotready; /* F2 FIFO is not ready to receive data (FIFO empty) */
+ uint32 f3rxnotready; /* F3 FIFO is not ready to receive data (FIFO empty) */
+
+ uint32 hostcmddataerr; /* Error in command or host data, detected by CRC/checksum
+ * (optional)
+ */
+ uint32 f2pktavailable; /* Packet is available in F2 TX FIFO */
+ uint32 f3pktavailable; /* Packet is available in F2 TX FIFO */
+
+ uint32 dstatus[NUM_PREV_TRANSACTIONS]; /* dstatus bits of last 16 gSPI transactions */
+ uint32 spicmd[NUM_PREV_TRANSACTIONS];
+};
+#endif /* BCMSPI */
+
+typedef struct sdio_bus_metrics {
+ uint32 active_dur; /* msecs */
+
+ /* Generic */
+ uint32 data_intr_cnt; /* data interrupt counter */
+ uint32 mb_intr_cnt; /* mailbox interrupt counter */
+ uint32 error_intr_cnt; /* error interrupt counter */
+ uint32 wakehost_cnt; /* counter for OOB wakehost */
+
+ /* DS forcewake */
+ uint32 ds_wake_on_cnt; /* counter for (clock) ON */
+ uint32 ds_wake_on_dur; /* duration for (clock) ON) */
+ uint32 ds_wake_off_cnt; /* counter for (clock) OFF */
+ uint32 ds_wake_off_dur; /* duration for (clock) OFF */
+
+ /* DS_D0 state */
+ uint32 ds_d0_cnt; /* counter for DS_D0 state */
+ uint32 ds_d0_dur; /* duration for DS_D0 state */
+
+ /* DS_D3 state */
+ uint32 ds_d3_cnt; /* counter for DS_D3 state */
+ uint32 ds_d3_dur; /* duration for DS_D3 state */
+
+ /* DS DEV_WAKE */
+ uint32 ds_dw_assrt_cnt; /* counter for DW_ASSERT */
+ uint32 ds_dw_dassrt_cnt; /* counter for DW_DASSERT */
+
+ /* DS mailbox signals */
+ uint32 ds_tx_dsreq_cnt; /* counter for tx HMB_DATA_DSREQ */
+ uint32 ds_tx_dsexit_cnt; /* counter for tx HMB_DATA_DSEXIT */
+ uint32 ds_tx_d3ack_cnt; /* counter for tx HMB_DATA_D3ACK */
+ uint32 ds_tx_d3exit_cnt; /* counter for tx HMB_DATA_D3EXIT */
+ uint32 ds_rx_dsack_cnt; /* counter for rx SMB_DATA_DSACK */
+ uint32 ds_rx_dsnack_cnt; /* counter for rx SMB_DATA_DSNACK */
+ uint32 ds_rx_d3inform_cnt; /* counter for rx SMB_DATA_D3INFORM */
+} sdio_bus_metrics_t;
+
+/* Bus interface info for SDIO */
+typedef struct wl_pwr_sdio_stats {
+ uint16 type; /* WL_PWRSTATS_TYPE_SDIO */
+ uint16 len; /* Up to 4K-1, top 4 bits are reserved */
+
+ sdio_bus_metrics_t sdio; /* stats from SDIO bus driver */
+} wl_pwr_sdio_stats_t;
+
+#endif /* _sdiovar_h_ */
diff --git a/wl/src/include/trxhdr.h b/wl/src/include/trxhdr.h
new file mode 100644
index 0000000..e67e6c9
--- /dev/null
+++ b/wl/src/include/trxhdr.h
@@ -0,0 +1,93 @@
+/*
+ * TRX image file header format.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: trxhdr.h 520026 2014-12-10 01:29:40Z $
+ */
+
+#ifndef _TRX_HDR_H
+#define _TRX_HDR_H
+
+#include <typedefs.h>
+
+#define TRX_MAGIC 0x30524448 /* "HDR0" */
+#define TRX_MAX_LEN 0x3B0000 /* Max length */
+#define TRX_NO_HEADER 1 /* Do not write TRX header */
+#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
+#define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */
+#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */
+#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */
+#define TRX_BOOTLOADER 0x40 /* the image is a bootloader */
+
+#define TRX_V1 1
+#define TRX_V1_MAX_OFFSETS 3 /* V1: Max number of individual files */
+
+#ifndef BCMTRXV2
+#define TRX_VERSION TRX_V1 /* Version 1 */
+#define TRX_MAX_OFFSET TRX_V1_MAX_OFFSETS
+#endif
+
+/* BMAC Host driver/application like bcmdl need to support both Ver 1 as well as
+ * Ver 2 of trx header. To make it generic, trx_header is structure is modified
+ * as below where size of "offsets" field will vary as per the TRX version.
+ * Currently, BMAC host driver and bcmdl are modified to support TRXV2 as well.
+ * To make sure, other applications like "dhdl" which are yet to be enhanced to support
+ * TRXV2 are not broken, new macro and structure defintion take effect only when BCMTRXV2
+ * is defined.
+ */
+struct trx_header {
+ uint32 magic; /* "HDR0" */
+ uint32 len; /* Length of file including header */
+ uint32 crc32; /* 32-bit CRC from flag_version to end of file */
+ uint32 flag_version; /* 0:15 flags, 16:31 version */
+#ifndef BCMTRXV2
+ uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
+#else
+ uint32 offsets[1]; /* Offsets of partitions from start of header */
+#endif
+};
+
+#ifdef BCMTRXV2
+#define TRX_VERSION TRX_V2 /* Version 2 */
+#define TRX_MAX_OFFSET TRX_V2_MAX_OFFSETS
+
+#define TRX_V2 2
+/* V2: Max number of individual files
+ * To support SDR signature + Config data region
+ */
+#define TRX_V2_MAX_OFFSETS 5
+#define SIZEOF_TRXHDR_V1 (sizeof(struct trx_header)+(TRX_V1_MAX_OFFSETS-1)*sizeof(uint32))
+#define SIZEOF_TRXHDR_V2 (sizeof(struct trx_header)+(TRX_V2_MAX_OFFSETS-1)*sizeof(uint32))
+#ifdef IL_BIGENDIAN
+#define TRX_VER(trx) (ltoh32((trx)->flag_version>>16))
+#else
+#define TRX_VER(trx) ((trx)->flag_version>>16)
+#endif
+#define ISTRX_V1(trx) (TRX_VER(trx) == TRX_V1)
+#define ISTRX_V2(trx) (TRX_VER(trx) == TRX_V2)
+/* For V2, return size of V2 size: others, return V1 size */
+#define SIZEOF_TRX(trx) (ISTRX_V2(trx) ? SIZEOF_TRXHDR_V2: SIZEOF_TRXHDR_V1)
+#else
+#define SIZEOF_TRX(trx) (sizeof(struct trx_header))
+#endif /* BCMTRXV2 */
+
+/* Compatibility */
+typedef struct trx_header TRXHDR, *PTRXHDR;
+
+#endif /* _TRX_HDR_H */
diff --git a/wl/src/include/typedefs.h b/wl/src/include/typedefs.h
new file mode 100644
index 0000000..26d9e6a
--- /dev/null
+++ b/wl/src/include/typedefs.h
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: typedefs.h 657121 2016-08-31 05:26:32Z $
+ */
+
+#ifndef _TYPEDEFS_H_
+#define _TYPEDEFS_H_
+
+#if (!defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)) || \
+ !defined(BWL_NO_INTERNAL_STDLIB_SUPPORT)
+
+#ifdef SITE_TYPEDEFS
+
+/*
+ * Define SITE_TYPEDEFS in the compile to include a site-specific
+ * typedef file "site_typedefs.h".
+ *
+ * If SITE_TYPEDEFS is not defined, then the code section below makes
+ * inferences about the compile environment based on defined symbols and
+ * possibly compiler pragmas.
+ *
+ * Following these two sections is the Default Typedefs section.
+ * This section is only processed if USE_TYPEDEF_DEFAULTS is
+ * defined. This section has a default set of typedefs and a few
+ * preprocessor symbols (TRUE, FALSE, NULL, ...).
+ */
+
+#include "site_typedefs.h"
+
+#else
+
+/*
+ * Infer the compile environment based on preprocessor symbols and pragmas.
+ * Override type definitions as needed, and include configuration-dependent
+ * header files to define types.
+ */
+
+#ifdef __cplusplus
+
+#define TYPEDEF_BOOL
+#ifndef FALSE
+#define FALSE false
+#endif
+#ifndef TRUE
+#define TRUE true
+#endif
+
+#else /* ! __cplusplus */
+
+#if defined(_WIN32)
+
+#define TYPEDEF_BOOL
+typedef unsigned char bool; /* consistent w/BOOL */
+
+#endif /* _WIN32 */
+
+#endif /* ! __cplusplus */
+
+
+#if defined(_WIN64)
+/* use the Windows ULONG_PTR type when compiling for 64 bit */
+#include <basetsd.h>
+#define TYPEDEF_UINTPTR
+typedef ULONG_PTR uintptr;
+#elif defined(__LP64__)
+#define TYPEDEF_UINTPTR
+typedef unsigned long long int uintptr;
+#endif
+
+
+
+
+#if defined(TARGETOS_nucleus)
+/* for 'size_t' type */
+#include <stddef.h>
+#endif /* TARGETOS_nucleus */
+/* float_t types conflict with the same typedefs from the standard ANSI-C
+** math.h header file. Don't re-typedef them here.
+*/
+#if defined(TARGETOS_nucleus)
+#define TYPEDEF_FLOAT_T
+#endif
+
+#if defined(_NEED_SIZE_T_)
+typedef long unsigned int size_t;
+#endif
+
+#ifdef _MSC_VER /* Microsoft C */
+#define TYPEDEF_INT64
+#define TYPEDEF_UINT64
+typedef signed __int64 int64;
+typedef unsigned __int64 uint64;
+#endif
+
+
+
+#if defined(__FreeBSD__)
+#include <sys/param.h>
+#define TYPEDEF_BOOL
+#if !defined(__bool_true_false_are_defined)
+typedef int bool;
+#endif
+#endif /* (defined(__FreeBSD__)) */
+
+#if defined(__sparc__)
+#define TYPEDEF_ULONG
+#endif
+
+#if defined(linux)
+/*
+ * If this is either a Linux hybrid build or the per-port code of a hybrid build
+ * then use the Linux header files to get some of the typedefs. Otherwise, define
+ * them entirely in this file. We can't always define the types because we get
+ * a duplicate typedef error; there is no way to "undefine" a typedef.
+ * We know when it's per-port code because each file defines LINUX_PORT at the top.
+ */
+#define TYPEDEF_UINT
+#ifndef TARGETENV_android
+#define TYPEDEF_USHORT
+#define TYPEDEF_ULONG
+#endif /* TARGETENV_android */
+#ifdef __KERNEL__
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
+#define TYPEDEF_BOOL
+#endif /* >= 2.6.19 */
+/* special detection for 2.6.18-128.7.1.0.1.el5 */
+#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18))
+#include <linux/compiler.h>
+#ifdef noinline_for_stack
+#define TYPEDEF_BOOL
+#endif
+#endif /* == 2.6.18 */
+#endif /* __KERNEL__ */
+#endif
+
+#if !defined(linux) && !defined(_WIN32) && !defined(__DJGPP__) && !defined(__BOB__) && \
+ !defined(TARGETOS_nucleus) && !defined(__FreeBSD__)
+#define TYPEDEF_UINT
+#define TYPEDEF_USHORT
+#endif
+
+/* Do not support the (u)int64 types with strict ansi for GNU C */
+#if defined(__GNUC__) && defined(__STRICT_ANSI__)
+#if !defined(__FreeBSD__)
+#define TYPEDEF_INT64
+#define TYPEDEF_UINT64
+#endif /* !defined(__FreeBSD__) */
+#endif /* defined(__GNUC__) && defined(__STRICT_ANSI__) */
+
+/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode
+ * for signed or unsigned
+ */
+#if defined(__ICL)
+
+#define TYPEDEF_INT64
+
+#if defined(__STDC__)
+#define TYPEDEF_UINT64
+#endif
+
+#endif /* __ICL */
+
+#if !defined(_WIN32) && !defined(__DJGPP__) && !defined(__BOB__) && \
+ !defined(TARGETOS_nucleus)
+
+/* pick up ushort & uint from standard types.h */
+#if defined(linux) && defined(__KERNEL__)
+
+/* See note above */
+#ifdef USER_MODE
+#include <sys/types.h>
+#else
+#include <linux/types.h> /* sys/types.h and linux/types.h are oil and water */
+#endif /* USER_MODE */
+
+#else
+
+#include <sys/types.h>
+
+#endif /* linux && __KERNEL__ */
+
+#endif
+
+
+/* use the default typedefs in the next section of this file */
+#define USE_TYPEDEF_DEFAULTS
+
+#endif /* SITE_TYPEDEFS */
+
+
+/*
+ * Default Typedefs
+ */
+
+#ifdef USE_TYPEDEF_DEFAULTS
+#undef USE_TYPEDEF_DEFAULTS
+
+#ifndef TYPEDEF_BOOL
+typedef /* @abstract@ */ unsigned char bool;
+#endif /* endif TYPEDEF_BOOL */
+
+/* define uchar, ushort, uint, ulong */
+
+#ifndef TYPEDEF_UCHAR
+typedef unsigned char uchar;
+#endif
+
+#ifndef TYPEDEF_USHORT
+typedef unsigned short ushort;
+#endif
+
+#ifndef TYPEDEF_UINT
+typedef unsigned int uint;
+#endif
+
+#ifndef TYPEDEF_ULONG
+typedef unsigned long ulong;
+#endif
+
+/* define [u]int8/16/32/64, uintptr */
+
+#ifndef TYPEDEF_UINT8
+typedef unsigned char uint8;
+#endif
+
+#ifndef TYPEDEF_UINT16
+typedef unsigned short uint16;
+#endif
+
+#ifndef TYPEDEF_UINT32
+typedef unsigned int uint32;
+#endif
+
+#ifndef TYPEDEF_UINT64
+typedef unsigned long long uint64;
+#endif
+
+#ifndef TYPEDEF_UINTPTR
+typedef unsigned int uintptr;
+#endif
+
+#ifndef TYPEDEF_INT8
+typedef signed char int8;
+#endif
+
+#ifndef TYPEDEF_INT16
+typedef signed short int16;
+#endif
+
+#ifndef TYPEDEF_INT32
+typedef signed int int32;
+#endif
+
+#ifndef TYPEDEF_INT64
+typedef signed long long int64;
+#endif
+
+/* define float32/64, float_t */
+
+#ifndef TYPEDEF_FLOAT32
+typedef float float32;
+#endif
+
+#ifndef TYPEDEF_FLOAT64
+typedef double float64;
+#endif
+
+/*
+ * abstracted floating point type allows for compile time selection of
+ * single or double precision arithmetic. Compiling with -DFLOAT32
+ * selects single precision; the default is double precision.
+ */
+
+#ifndef TYPEDEF_FLOAT_T
+
+#if defined(FLOAT32)
+typedef float32 float_t;
+#else /* default to double precision floating point */
+typedef float64 float_t;
+#endif
+
+#endif /* TYPEDEF_FLOAT_T */
+
+/* define macro values */
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1 /* TRUE */
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef OFF
+#define OFF 0
+#endif
+
+#ifndef ON
+#define ON 1 /* ON = 1 */
+#endif
+
+#define AUTO (-1) /* Auto = -1 */
+
+/* define PTRSZ, INLINE */
+
+#ifndef PTRSZ
+#define PTRSZ sizeof(char*)
+#endif
+
+
+/* Detect compiler type. */
+#ifdef _MSC_VER
+ #define BWL_COMPILER_MICROSOFT
+#elif defined(__GNUC__) || defined(__lint)
+ #define BWL_COMPILER_GNU
+#elif defined(__CC_ARM) && __CC_ARM
+ #define BWL_COMPILER_ARMCC
+#else
+ #error "Unknown compiler!"
+#endif /* _MSC_VER */
+
+
+#ifndef INLINE
+ #if defined(BWL_COMPILER_MICROSOFT)
+ #define INLINE __inline
+ #elif defined(BWL_COMPILER_GNU)
+ #define INLINE __inline__
+ #elif defined(BWL_COMPILER_ARMCC)
+ #define INLINE __inline
+ #else
+ #define INLINE
+ #endif /* _MSC_VER */
+#endif /* INLINE */
+
+#undef TYPEDEF_BOOL
+#undef TYPEDEF_UCHAR
+#undef TYPEDEF_USHORT
+#undef TYPEDEF_UINT
+#undef TYPEDEF_ULONG
+#undef TYPEDEF_UINT8
+#undef TYPEDEF_UINT16
+#undef TYPEDEF_UINT32
+#undef TYPEDEF_UINT64
+#undef TYPEDEF_UINTPTR
+#undef TYPEDEF_INT8
+#undef TYPEDEF_INT16
+#undef TYPEDEF_INT32
+#undef TYPEDEF_INT64
+#undef TYPEDEF_FLOAT32
+#undef TYPEDEF_FLOAT64
+#undef TYPEDEF_FLOAT_T
+
+#endif /* USE_TYPEDEF_DEFAULTS */
+
+/* Suppress unused parameter warning */
+#define UNUSED_PARAMETER(x) (void)(x)
+
+/* Avoid warning for discarded const or volatile qualifier in special cases (-Wcast-qual) */
+#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr))
+
+#else /* !EDK_RELEASE_VERSION || (EDK_RELEASE_VERSION < 0x00020000) */
+
+#include <sys/types.h>
+#include <strings.h>
+#include <stdlib.h>
+
+#ifdef stderr
+#undef stderr
+#define stderr stdout
+#endif
+
+typedef UINT8 uint8;
+typedef UINT16 uint16;
+typedef UINT32 uint32;
+typedef UINT64 uint64;
+typedef INT8 int8;
+typedef INT16 int16;
+typedef INT32 int32;
+typedef INT64 int64;
+
+typedef BOOLEAN bool;
+typedef unsigned char uchar;
+typedef UINTN uintptr;
+
+#define UNUSED_PARAMETER(x) (void)(x)
+#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr))
+#define INLINE
+#define AUTO (-1) /* Auto = -1 */
+#define ON 1 /* ON = 1 */
+#define OFF 0
+
+#endif /* !EDK_RELEASE_VERSION || (EDK_RELEASE_VERSION < 0x00020000) */
+
+/*
+ * Including the bcmdefs.h here, to make sure everyone including typedefs.h
+ * gets this automatically
+*/
+#include <bcmdefs.h>
+#endif /* _TYPEDEFS_H_ */
diff --git a/wl/src/include/wlc_extlog_idstr.h b/wl/src/include/wlc_extlog_idstr.h
new file mode 100644
index 0000000..6a55e97
--- /dev/null
+++ b/wl/src/include/wlc_extlog_idstr.h
@@ -0,0 +1,120 @@
+/*
+ * EXTLOG Module log ID to log Format String mapping table
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlc_extlog_idstr.h 514727 2014-11-12 03:02:48Z $
+ */
+#ifndef _WLC_EXTLOG_IDSTR_H_
+#define _WLC_EXTLOG_IDSTR_H_
+
+#include "wlioctl.h"
+
+/* Strings corresponding to the IDs defined in wlioctl.h
+ * This file is only included by the apps and not included by the external driver
+ * Formats of pre-existing ids should NOT be changed
+ */
+log_idstr_t extlog_fmt_str[ ] = {
+ {FMTSTR_DRIVER_UP_ID, 0, LOG_ARGTYPE_NULL,
+ "Driver is Up\n"},
+
+ {FMTSTR_DRIVER_DOWN_ID, 0, LOG_ARGTYPE_NULL,
+ "Driver is Down\n"},
+
+ {FMTSTR_SUSPEND_MAC_FAIL_ID, 0, LOG_ARGTYPE_INT,
+ "wlc_suspend_mac_and_wait() failed with psmdebug 0x%08x\n"},
+
+ {FMTSTR_NO_PROGRESS_ID, 0, LOG_ARGTYPE_INT,
+ "No Progress on TX for %d seconds\n"},
+
+ {FMTSTR_RFDISABLE_ID, 0, LOG_ARGTYPE_INT,
+ "Detected a change in RF Disable Input 0x%x\n"},
+
+ {FMTSTR_REG_PRINT_ID, 0, LOG_ARGTYPE_STR_INT,
+ "Register %s = 0x%x\n"},
+
+ {FMTSTR_EXPTIME_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "Strong RF interference detected\n"},
+
+ {FMTSTR_JOIN_START_ID, FMTSTRF_USER, LOG_ARGTYPE_STR,
+ "Searching for networks with ssid %s\n"},
+
+ {FMTSTR_JOIN_COMPLETE_ID, FMTSTRF_USER, LOG_ARGTYPE_STR,
+ "Successfully joined network with BSSID %s\n"},
+
+ {FMTSTR_NO_NETWORKS_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "No networks found. Please check if the network exists and is in range\n"},
+
+ {FMTSTR_SECURITY_MISMATCH_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "AP rejected due to security mismatch. Change the security settings and try again...\n"},
+
+ {FMTSTR_RATE_MISMATCH_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "AP rejected due to rate mismatch\n"},
+
+ {FMTSTR_AP_PRUNED_ID, 0, LOG_ARGTYPE_INT,
+ "AP rejected due to reason %d\n"},
+
+ {FMTSTR_KEY_INSERTED_ID, 0, LOG_ARGTYPE_INT,
+ "Inserting keys for algorithm %d\n"},
+
+ {FMTSTR_DEAUTH_ID, FMTSTRF_USER, LOG_ARGTYPE_STR_INT,
+ "Received Deauth from %s with Reason %d\n"},
+
+ {FMTSTR_DISASSOC_ID, FMTSTRF_USER, LOG_ARGTYPE_STR_INT,
+ "Received Disassoc from %s with Reason %d\n"},
+
+ {FMTSTR_LINK_UP_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "Link Up\n"},
+
+ {FMTSTR_LINK_DOWN_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "Link Down\n"},
+
+ {FMTSTR_RADIO_HW_OFF_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "Radio button is turned OFF. Please turn it on...\n"},
+
+ {FMTSTR_RADIO_HW_ON_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "Hardware Radio button is turned ON\n"},
+
+ {FMTSTR_EVENT_DESC_ID, 0, LOG_ARGTYPE_INT_STR,
+ "Generated event id %d: (result status) is (%s)\n"},
+
+ {FMTSTR_PNP_SET_POWER_ID, 0, LOG_ARGTYPE_INT,
+ "Device going into power state %d\n"},
+
+ {FMTSTR_RADIO_SW_OFF_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "Software Radio is disabled. Please enable it through the UI...\n"},
+
+ {FMTSTR_RADIO_SW_ON_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "Software Radio is enabled\n"},
+
+ {FMTSTR_PWD_MISMATCH_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "Potential passphrase mismatch. Please try a different one...\n"},
+
+ {FMTSTR_FATAL_ERROR_ID, 0, LOG_ARGTYPE_INT,
+ "Fatal Error: intstatus 0x%x\n"},
+
+ {FMTSTR_AUTH_FAIL_ID, 0, LOG_ARGTYPE_STR_INT,
+ "Authentication to %s Failed with status %d\n"},
+
+ {FMTSTR_ASSOC_FAIL_ID, 0, LOG_ARGTYPE_STR_INT,
+ "Association to %s Failed with status %d\n"},
+
+ {FMTSTR_IBSS_FAIL_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "Unable to start IBSS since PeerNet is already active\n"},
+
+ {FMTSTR_EXTAP_FAIL_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL,
+ "Unable to start Ext-AP since PeerNet is already active\n"},
+
+ {FMTSTR_MAX_ID, 0, 0, "\0"}
+};
+
+#endif /* _WLC_EXTLOG_IDSTR_H_ */
diff --git a/wl/src/include/wlioctl.h b/wl/src/include/wlioctl.h
new file mode 100644
index 0000000..2200383
--- /dev/null
+++ b/wl/src/include/wlioctl.h
@@ -0,0 +1,28 @@
+/*
+ * Custom OID/ioctl definitions for
+ *
+ *
+ * Broadcom 802.11abg Networking Device Driver
+ *
+ * Definitions subject to change without notice.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wlioctl.h 661028 2016-09-23 00:14:48Z $
+ */
+
+/* wlioctl.h has been moved to components/shared/devctrl_if */
+#include <devctrl_if/wlioctl.h>
diff --git a/wl/src/include/wlioctl_utils.h b/wl/src/include/wlioctl_utils.h
new file mode 100644
index 0000000..498d78a
--- /dev/null
+++ b/wl/src/include/wlioctl_utils.h
@@ -0,0 +1,55 @@
+/*
+ * Custom OID/ioctl related helper functions.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wlioctl_utils.h 626207 2016-03-19 17:39:14Z $
+ */
+
+#ifndef _wlioctl_utils_h_
+#define _wlioctl_utils_h_
+
+#include <wlioctl.h>
+
+#ifndef BCMDRIVER
+#define CCA_THRESH_MILLI 14
+#define CCA_THRESH_INTERFERE 6
+
+extern cca_congest_channel_req_t * cca_per_chan_summary(cca_congest_channel_req_t *input,
+ cca_congest_channel_req_t *avg, bool percent);
+
+extern int cca_analyze(cca_congest_channel_req_t *input[], int num_chans,
+ uint flags, chanspec_t *answer);
+#endif /* BCMDRIVER */
+
+extern int wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf,
+ int buflen, uint32 corerev);
+
+extern const char * wl_get_reinit_rc_name(int rc);
+
+/* Get data pointer of wlc layer counters tuple from xtlv formatted counters IOVar buffer. */
+#define GET_WLCCNT_FROM_CNTBUF(cntbuf) (const wl_cnt_wlc_t*) \
+ bcm_get_data_from_xtlv_buf(((const wl_cnt_info_t *)cntbuf)->data, \
+ ((const wl_cnt_info_t *)cntbuf)->datalen, WL_CNT_XTLV_WLC, \
+ NULL, BCM_XTLV_OPTION_ALIGN32)
+
+#define CHK_CNTBUF_DATALEN(cntbuf, ioctl_buflen) do { \
+ if (((wl_cnt_info_t *)cntbuf)->datalen + \
+ OFFSETOF(wl_cnt_info_t, data) > ioctl_buflen) \
+ printf("%s: IOVAR buffer short!\n", __FUNCTION__); \
+} while (0)
+
+#endif /* _wlioctl_utils_h_ */
diff --git a/wl/src/makefiles/RelPath.mk b/wl/src/makefiles/RelPath.mk
new file mode 100644
index 0000000..d95a36b
--- /dev/null
+++ b/wl/src/makefiles/RelPath.mk
@@ -0,0 +1,103 @@
+# General-purpose GNU make include file
+#
+# Copyright (C) 2017, Broadcom. All Rights Reserved.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+#
+# <<Broadcom-WL-IPTag/Open:>>
+#
+# $Id: Makefile 506823 2014-10-07 12:59:32Z $
+#
+
+ifdef _RELPATH_MK_
+$(if $D,$(info =-= Avoiding redundant include ($(MAKEFILE_LIST))))
+else
+unexport _RELPATH_MK_ # in case of make -e
+_RELPATH_MK_ := 1
+
+# Protection against process recursion when this file is
+# included by setting MAKEFILES.
+ifneq (,$(filter %$(notdir $(lastword $(MAKEFILE_LIST))),$(MAKEFILES)))
+MAKEFILES := $(filter-out %$(notdir $(lastword $(MAKEFILE_LIST))),$(MAKEFILES))
+ifndef MAKEFILES
+unexport MAKEFILES
+endif
+endif
+
+# Usage: $(call relpath,[<from-dir>,]<to-dir>)
+# Returns the relative path from <from-dir> to <to-dir>; <from-dir>
+# may be elided in which case it defaults to $(CURDIR).
+
+_rp_space :=
+_rp_space +=
+_rp_uname_s := $(shell uname -s)
+
+# Utility functions.
+_rp_compose = $(subst ${_rp_space},$(strip $1),$(strip $2))
+_rp_endlist = $(wordlist $1,$(words $2),$2)
+_rp_canonpath = $(if $(findstring CYGWIN,$(_rp_uname_s)),$(shell cygpath -a -u $1),$(abspath $1))
+
+# ----relpath(): Self-recursive function which compares the first element
+# of two given paths, then calls itself with the next two
+# elements, and so on, until a difference is found. At each
+# step, if the first element of both paths matches, that
+# element is produced.
+----relpath = $(if $(filter $(firstword $1),$(firstword $2)), \
+ $(firstword $1) \
+ $(call $0,$(call _rp_endlist,2,$1),$(call _rp_endlist,2,$2)) \
+ )
+# ---relpath(): This function removes $1 from the front of both $2 and
+# $3 (removes common path prefix) and generates a relative
+# path between the locations given by $2 and $3, by replacing
+# each remaining element of $2 (after common prefix removal)
+# with '..', then appending the remainder of $3 (after common
+# prefix removal) to the string of '..'s
+---relpath = $(foreach e,$(subst /, ,$(patsubst $(if $1,/)$1/%,%,$2)),..) \
+ $(if $3,$(patsubst $(if $1,/)$1/%,%,$3))
+# --relpath(): This function runs the output of ----relpath() through
+# ---relpath(), and turns the result into an actual relative
+# path string, separated by '/'.
+--relpath = $(call _rp_compose,/, \
+ $(call -$0,$(call _rp_compose,/,$(call --$0,$3,$4)),$1,$2) \
+ )
+# -relpath(): This function makes a determination about the two given
+# paths -- does one strictly prefix the other? If so, this
+# function produces a relative path between the two inputs,
+# without calling --relpath() and taking the "long road".
+# If $1 prefixes $2, the result is the remainder of $2 after
+# removing $1. If $2 prefixes $1, the result is the remainder
+# of $1 after removing $2, but with each element in that
+# remainder converted to '..'.
+-relpath = $(if $(filter $1,$2),., \
+ $(if $(filter $1/%,$2), \
+ $(patsubst $1/%,%,$2), \
+ $(if $(filter $2/%,$1), \
+ $(call _rp_compose,/, \
+ $(foreach e,$(subst /, ,$(patsubst $2/%,%,$1)),..) \
+ ), \
+ $(call -$0,$1,$2,$(subst /, ,$1),$(subst /, ,$2)) \
+ ) \
+ ) \
+ )
+
+# relpath(): This function loops over each element in $2, calculating
+# the relative path from $1 to each element of $2.
+relpath = $(if $1,,$(error Error: missing first parameter to $0))$(strip \
+ $(if $2, \
+ $(foreach d,$2,$(call -$0,$(call _rp_canonpath,$1),$(call _rp_canonpath,$d))), \
+ $(foreach d,$1,$(call -$0,$(call _rp_canonpath,${CURDIR}),$(call _rp_canonpath,$d))) \
+ ) \
+ )
+
+endif #_RELPATH_MK_
diff --git a/wl/src/makefiles/WLAN_Common.mk b/wl/src/makefiles/WLAN_Common.mk
new file mode 100644
index 0000000..4affa3f
--- /dev/null
+++ b/wl/src/makefiles/WLAN_Common.mk
@@ -0,0 +1,511 @@
+# General-purpose GNU make include file
+#
+# Copyright (C) 2017, Broadcom. All Rights Reserved.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+#
+# <<Broadcom-WL-IPTag/Open:>>
+#
+# $Id: Makefile 506823 2014-10-07 12:59:32Z $
+#
+ifdef _WLAN_COMMON_MK
+ $(if $D,$(info Info: Avoiding redundant include ($(MAKEFILE_LIST))))
+else # _WLAN_COMMON_MK
+ _WLAN_COMMON_MK := 1
+unexport _WLAN_COMMON_MK # in case of make -e
+
+################################################################
+# Summary and Namespace Rules
+################################################################
+# This is a special makefile fragment intended for common use.
+# The most important design principle is that it defines variables
+# and functions only within a tightly controlled namespace.
+# If a make include file is used to set rules, pattern rules,
+# or well known variables like CFLAGS, it can have unexpected
+# effects on the including makefile with the result that people
+# either stop including it or stop changing it.
+# Therefore, the only way to keep this a file which can be
+# safely included by any GNU makefile and extended at will is
+# to allow it only to set variables and only in its own namespace.
+# The namespace is "WLAN_CamelCase" for normal variables,
+# "wlan_lowercase" for functions, and WLAN_UPPERCASE for boolean
+# "constants" (these are all really just make variables; only the
+# usage patterns differ).
+# Internal (logically file-scoped) variables are prefixed with "-"
+# and have no other namespace restrictions.
+# Every variable defined here should match one of these patterns.
+
+################################################################
+# Enforce required conditions
+################################################################
+
+ifneq (,$(filter 3.7% 3.80,$(MAKE_VERSION)))
+ $(error $(MAKE): Error: version $(MAKE_VERSION) too old, 3.81+ required)
+endif
+
+################################################################
+# Store this makefile's path before MAKEFILE_LIST gets changed.
+################################################################
+
+WLAN_Common := $(lastword $(MAKEFILE_LIST))
+
+################################################################
+# Derive including makefile since it's a little tricky.
+################################################################
+
+WLAN_Makefile := $(abspath $(lastword $(filter-out $(lastword $(MAKEFILE_LIST)),$(MAKEFILE_LIST))))
+
+################################################################
+# Shiny new ideas, can be enabled via environment for testing.
+################################################################
+
+ifdef WLAN_MakeBeta
+ $(info Info: BUILDING WITH "WLAN_MakeBeta" ENABLED!)
+ SHELL := /bin/bash
+ #.SUFFIXES:
+ #MAKEFLAGS += -r
+endif
+
+################################################################
+# Allow a makefile to force this file into all child makes.
+################################################################
+
+ifdef WLAN_StickyCommon
+ export MAKEFILES := $(MAKEFILES) $(abspath $(lastword $(MAKEFILE_LIST)))
+endif
+
+################################################################
+# Host type determination
+################################################################
+
+_common-uname-s := $(shell uname -s)
+
+# Typically this will not be tested explicitly; it's the default condition.
+WLAN_HOST_TYPE := unix
+
+ifneq (,$(filter Linux,$(_common-uname-s)))
+ WLAN_LINUX_HOST := 1
+else ifneq (,$(filter CYGWIN%,$(_common-uname-s)))
+ WLAN_CYGWIN_HOST := 1
+ WLAN_WINDOWS_HOST := 1
+else ifneq (,$(filter Darwin,$(_common-uname-s)))
+ WLAN_MACOS_HOST := 1
+ WLAN_BSD_HOST := 1
+else ifneq (,$(filter FreeBSD NetBSD,$(_common-uname-s)))
+ WLAN_BSD_HOST := 1
+else ifneq (,$(filter SunOS%,$(_common-uname-s)))
+ WLAN_SOLARIS_HOST := 1
+endif
+
+################################################################
+# Utility variables
+################################################################
+
+empty :=
+space := $(empty) $(empty)
+comma := ,
+
+################################################################
+# Utility functions
+################################################################
+
+# Provides enhanced-format messages from make logic.
+wlan_die = $(error Error: $1)
+wlan_warning = $(warning Warning: $1)
+wlan_info = $(info Info: $1)
+
+# Debug function to enable make verbosity.
+wlan_dbg = $(if $D,$(call wlan_info,$1))
+
+# Debug function to expose values of the listed variables.
+wlan_dbgv = $(foreach _,$1,$(call wlan_dbg,$_=$($_)))
+
+# Make-time assertion.
+define wlan_assert
+ ifeq (,$(findstring clean,$(MAKECMDGOALS)))
+ $(if $1,,$(call wlan_die,$2))
+ endif
+endef
+
+# Checks for the presence of an option in an option string
+# like "aaa-bbb-ccc-ddd".
+wlan_opt = $(if $(findstring -$1-,-$2-),1,0)
+
+# The purpose of this macro is to avoid the need for full directory
+# paths to be created via mkdir -p since mkdir -p has an inherent
+# race in parallel use cases. Interestingly, though it exists to
+# make -p unnecessary, it actually uses -p. Why is that? It's to
+# take advantage of a useful side effect of -p which is that it
+# doesn't complain if the directory already exists. In other words
+# it creates directories one at a time to avoid creating its own
+# race but still uses mkdir -p to protect itself against races with
+# unrelated make processes.
+# Usage: $(call wlan_target_needs_dir,<target>,<dir-path>)
+define wlan_target_needs_dir
+$(eval
+$$1: | $$2
+$$2: | $$(filter-out .,$$(patsubst %/,%,$$(dir $$2))); mkdir -p $$@
+ifneq (,$$(findstring /,$$2))
+ $$(call wlan_target_needs_dir,$$1,$$(patsubst %/,%,$$(dir $$2)))
+endif
+)
+endef
+
+# Compares two dotted numeric strings (e.g 2.3.16.1) for $1 >= $2
+define wlan_version_ge
+$(findstring TRUE,$(shell bash -c 'sort -cu -t. -k1,1nr -k2,2nr -k3,3nr -k4,4nr <(echo -e "$2\n$1") 2>&1 || echo TRUE'))
+endef
+
+# This is a useful macro to wrap around a compiler command line,
+# e.g. "$(call wlan_cc,<command-line>). It organizes flags in a
+# readable way while taking care not to change any ordering
+# which matters. It also provides a hook for externally
+# imposed C flags which can be passed in from the top level.
+# This would be the best place to add a check for
+# command line length. Requires a $(strlen) function;
+# GMSL has one.
+define wlan_cc
+$(filter-out -D% -I%,$1) $(filter -D%,$1) $(filter -I%,$1) $(WLAN_EXTERNAL_CFLAGS)
+endef
+
+# Applies the standard cygpath translation for a path on Cygwin.
+define wlan_cygpath
+$(if $(WLAN_CYGWIN_HOST),$(shell cygpath -m $1),$1)
+endef
+
+# Change case without requiring a shell.
+wlan_tolower = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,\
+$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,\
+$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,\
+$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
+
+wlan_toupper = $(subst a,A,$(subst b,B,$(subst c,C,$(subst d,D,$(subst e,E,$(subst f,F,$(subst g,G,\
+$(subst h,H,$(subst i,I,$(subst j,J,$(subst k,K,$(subst l,L,$(subst m,M,$(subst n,N,$(subst o,O,\
+$(subst p,P,$(subst q,Q,$(subst r,R,$(subst s,S,$(subst t,T,$(subst u,U,$(subst v,V,$(subst w,W,\
+$(subst x,X,$(subst y,Y,$(subst z,Z,$1))))))))))))))))))))))))))
+
+# This macro derives the base (aka root) of the entire "checkout tree" as well as the
+# current "build tree" and "component tree" (svn or git checkout).
+# Definitions:
+# - Checkout Tree: the root of the full tree of files retrieved from SCM. May comprise
+# any number of individual checkouts, potentially from different branches, repos,
+# or even SCM tools.
+# - Build Tree: the root of a coherent subtree within the checkout tree, sufficient to
+# build some subset of the required deliverables.
+# - Component Tree: the root of a single component within the build tree, generally a
+# single checkout from svn or git.
+# These could all have the same value but more often a component is a subdir of a build
+# tree which may be a subdir of a DEPS checkout. The only guaranteed relationship is that
+# each component tree is within a build tree which is within the unitary checkout tree.
+# Returns a list: [checkout-tree, build-tree, component-tree]
+# Notes:
+# 1. We've observed a bug, or at least a surprising behavior, in emake which causes
+# $(realpath ...) to fail. That's why a $(shell ...) fallback is used below.
+# 2. There may be no SCM metadata at all, particularly in the case of a source package
+# delivered to a customer. This is where guessing (as described below) comes in.
+# 3. This macro always trusts .wlbase if present. It looks next for a .gclient
+# file, then sparsefile_url.py. If none of these are found we have to guess starting
+# from the location of this file. If a ../../../main file exists from here, set the
+# base there. Otherwise set it at ../.. from here.
+define wlan_basedirs
+$(eval\
+ _refdir := $$(realpath $$(or $1,$$(dir $$(lastword $$(MAKEFILE_LIST)))))
+ _refdir ?= $$(shell cd $$(or $1,$$(dir $$(lastword $$(MAKEFILE_LIST)))) && pwd -P)
+ _parts := $$(strip $$(subst /,$$(space),$$(subst \,/,$$(_refdir))))
+ _paths := /
+ $$(foreach _i,$$(_parts),$$(eval _paths += $$(addsuffix /$$(_i),$$(lastword $$(_paths)))))
+ _paths := $$(patsubst //%,/%,$$(wordlist 2,$$(words $$(_paths)),$$(_paths)))
+ _wlb := $$(patsubst %/,%,$$(dir $$(lastword $$(wildcard $$(addsuffix /.wlbase,$$(_paths))))))
+ _dep := $$(patsubst %/,%,$$(dir $$(lastword $$(wildcard $$(addsuffix /.gclient,$$(_paths))))))
+ ifndef _dep
+ _sprs := $$(subst /.svn/sparsefile_url.py,,$$(lastword $$(wildcard $$(addsuffix /.svn/sparsefile_url.py,$$(_paths)))))
+ ifndef _sprs
+ _guess := $$(strip $$(if $$(wildcard $$(dir $$(abspath $$(WLAN_Common)))../../../main),\
+ $$(abspath $$(dir $$(WLAN_Common))../../..),\
+ $$(abspath $$(dir $$(WLAN_Common))../..)))
+ endif # _sprs
+ endif # _dep
+ _arg3 := $$(patsubst %/,%,$$(dir $$(lastword $$(wildcard $$(addsuffix /.svn,$$(_paths)) $$(addsuffix /.git,$$(_paths))))))
+ _arg2 := $$(abspath $$(_refdir)/../..)
+ _arg1 := $$(or $$(_wlb),$$(_dep),$$(_sprs),$$(_guess),$$(_arg3))
+)$(strip $(_arg1) $(_arg2) $(_arg3))
+endef
+
+################################################################
+# Standard make variables
+################################################################
+
+# The WLAN_CheckoutBaseA variable points to the root of the entire
+# checkout while WLAN_TreeBaseA points to the root of the current
+# build tree and WLAN_ComponentBaseA points to the root of the
+# component containing the including Makefile. They could have the
+# values values but in other cases such as DHDAP routers a single
+# DEPS checkout may contain multiple build trees (potentially from
+# different branches) with each build tree composed of multiple components.
+# These 'A' variables are absolute paths; each has an 'R' variant
+# which is relative.
+ifndef WLAN_TreeBaseA
+ _basedata := $(call wlan_basedirs)
+ WLAN_CheckoutBaseA := $(word 1,$(_basedata))
+ WLAN_TreeBaseA := $(word 2,$(_basedata))
+ WLAN_ComponentBaseA := $(word 3,$(_basedata))
+ ifdef WLAN_CYGWIN_HOST
+ WLAN_TreeBaseA := $(shell cygpath -m -a $(WLAN_TreeBaseA))
+ endif
+endif
+
+# Pick up the "relpath" make function from the same dir as this makefile.
+include $(dir $(lastword $(MAKEFILE_LIST)))RelPath.mk
+
+# The *R variables are relativized versions of the *A variables.
+WLAN_CheckoutBaseR = $(call relpath,$(WLAN_CheckoutBaseA))
+WLAN_TreeBaseR = $(call relpath,$(WLAN_TreeBaseA))
+WLAN_ComponentBaseR = $(call relpath,$(WLAN_ComponentBaseA))
+
+# For compatibility, due to the prevalence of $(SRCBASE)
+WLAN_SrcBaseA := $(WLAN_TreeBaseA)/src
+WLAN_SrcBaseR = $(patsubst %/,%,$(dir $(WLAN_TreeBaseR)))
+
+# Show makefile list before we start including things.
+$(call wlan_dbgv, CURDIR MAKEFILE_LIST)
+
+################################################################
+# Pick up the "universal settings file" containing
+# the list of all available software components.
+################################################################
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../tools/release/WLAN.usf
+
+################################################################
+# Calculate paths to requested components.
+################################################################
+
+# This uses pattern matching to pull component paths from
+# their basenames (e.g. src/wl/xyz => xyz).
+# It also strips out component paths which don't currently exist.
+# This may be required due to our "sparse tree" build styles
+# and the fact that linux mkdep throws an error when a directory
+# specified with -I doesn't exist.
+define _common-component-names-to-rel-paths
+$(strip \
+ $(patsubst $(WLAN_TreeBaseA)/%,%,$(wildcard $(addprefix $(WLAN_TreeBaseA)/,\
+ $(sort $(foreach name,$(if $1,$1,$(WLAN_COMPONENT_PATHS)),$(filter %/$(name),$(WLAN_COMPONENT_PATHS))))))))
+endef
+
+# It's also possible to request the full set with a literal '*'.
+ifeq (,$(WLAN_ComponentsInUse))
+ WLAN_ComponentsInUse := $(sort $(notdir $(WLAN_COMPONENT_PATHS)))
+ # $(call wlan_die,no SW component request)
+else ifeq (*,$(WLAN_ComponentsInUse))
+ WLAN_ComponentsInUse := $(sort $(notdir $(WLAN_COMPONENT_PATHS)))
+ # $(call wlan_info,all SW components requested ("$(WLAN_ComponentsInUse)"))
+else
+ WLAN_ComponentsInUse := $(sort $(WLAN_ComponentsInUse))
+endif
+
+# For backward compatibility we accept certain old component names from older
+# branches and convert them to their updated names here.
+WLAN_ComponentsInUse := $(sort $(subst phymods,phy,$(WLAN_ComponentsInUse)))
+
+# Translate the resulting list of components names to paths.
+WLAN_ComponentPathsInUse := $(call _common-component-names-to-rel-paths,$(WLAN_ComponentsInUse))
+
+# Loop through all components in use. If a cfg-xyz.mk file exists at the base of
+# component xyz's subtree, include it and use its contents to modify the list
+# of include and src dirs. Otherwise, use the defaults for that component.
+# Also generate a WLAN_ComponentBaseDir_xyz variable for each component "xyz".
+WLAN_ComponentIncPathsInUse :=
+WLAN_ComponentSrcPathsInUse :=
+$(foreach _path,$(WLAN_ComponentPathsInUse), \
+ $(if $(wildcard $(WLAN_TreeBaseA)/$(_path)/cfg-$(notdir $(_path)).mk),$(eval include $(WLAN_TreeBaseA)/$(_path)/cfg-$(notdir $(_path)).mk)) \
+ $(eval $(notdir $(_path))_IncDirs ?= include) \
+ $(eval $(notdir $(_path))_SrcDirs ?= src) \
+ $(eval WLAN_ComponentIncPathsInUse += $(addprefix $(_path)/,$($(notdir $(_path))_IncDirs))) \
+ $(eval WLAN_ComponentSrcPathsInUse += $(addprefix $(_path)/,$($(notdir $(_path))_SrcDirs))) \
+ $(eval WLAN_ComponentBaseDir_$$(notdir $(_path)) := $$(WLAN_TreeBaseA)/$(_path)) \
+)
+
+# Global include/source path
+WLAN_StdSrcDirs = src/shared src/wl/sys src/bcmcrypto
+WLAN_StdSrcDirs += components/clm-api/src
+WLAN_StdIncDirs = src/include components/shared
+WLAN_StdIncDirs += components/clm-api/include
+WLAN_SrcIncDirs = src/shared src/wl/sys src/bcmcrypto \
+ src/wl/keymgmt/src src/wl/iocv/src \
+ components/drivers/wl/shim/src src/wl/proxd/src src/wl/mesh/src \
+ src/wl/randmac/src
+
+WLAN_StdSrcDirsR = $(addprefix $(WLAN_TreeBaseR)/,$(WLAN_StdSrcDirs))
+WLAN_StdIncDirsR = $(addprefix $(WLAN_TreeBaseR)/,$(WLAN_StdIncDirs))
+WLAN_SrcIncDirsR = $(addprefix $(WLAN_TreeBaseR)/,$(WLAN_SrcIncDirs))
+WLAN_StdIncPathR = $(addprefix -I,$(wildcard $(WLAN_StdIncDirsR)))
+WLAN_IncDirsR = $(WLAN_StdIncDirsR) $(WLAN_SrcIncDirsR)
+WLAN_IncPathR = $(addprefix -I,$(wildcard $(WLAN_IncDirsR)))
+
+WLAN_StdSrcDirsA = $(addprefix $(WLAN_TreeBaseA)/,$(WLAN_StdSrcDirs))
+WLAN_StdIncDirsA = $(addprefix $(WLAN_TreeBaseA)/,$(WLAN_StdIncDirs))
+WLAN_SrcIncDirsA = $(addprefix $(WLAN_TreeBaseA)/,$(WLAN_SrcIncDirs))
+WLAN_StdIncPathA = $(addprefix -I,$(wildcard $(WLAN_StdIncDirsA)))
+WLAN_IncDirsA = $(WLAN_StdIncDirsA) $(WLAN_SrcIncDirsA)
+WLAN_IncPathA = $(addprefix -I,$(wildcard $(WLAN_IncDirsA)))
+
+# Public convenience macros based on WLAN_ComponentPathsInUse list.
+WLAN_ComponentSrcDirsR = $(addprefix $(WLAN_TreeBaseR)/,$(WLAN_ComponentSrcPathsInUse))
+WLAN_ComponentIncDirsR = $(addprefix $(WLAN_TreeBaseR)/,$(WLAN_ComponentIncPathsInUse))
+WLAN_ComponentIncPathR = $(addprefix -I,$(wildcard $(WLAN_ComponentIncDirsR)))
+
+WLAN_ComponentSrcDirsA = $(addprefix $(WLAN_TreeBaseA)/,$(WLAN_ComponentSrcPathsInUse))
+WLAN_ComponentIncDirsA = $(addprefix $(WLAN_TreeBaseA)/,$(WLAN_ComponentIncPathsInUse))
+WLAN_ComponentIncPathA = $(addprefix -I,$(wildcard $(WLAN_ComponentIncDirsA)))
+
+WLAN_ComponentSrcDirs = $(WLAN_ComponentSrcDirsA)
+WLAN_ComponentIncDirs = $(WLAN_ComponentIncDirsA)
+WLAN_ComponentIncPath = $(WLAN_ComponentIncPathA)
+
+# Dump a representative sample of derived variables in debug mode.
+$(call wlan_dbgv, WLAN_TreeBaseA WLAN_TreeBaseR WLAN_SrcBaseA WLAN_SrcBaseR \
+ WLAN_ComponentPathsInUse WLAN_ComponentIncPath WLAN_ComponentIncPathR \
+ WLAN_ComponentSrcDirs WLAN_ComponentSrcDirsR)
+
+# Special case for Windows to reflect CL in the build log if used.
+ifdef WLAN_WINDOWS_HOST
+ ifdef CL
+ $(info Info: CL=$(CL))
+ endif
+endif
+
+# A big hammer for debugging each shell invocation.
+# Warning: this can get lost if a sub-makefile sets SHELL explicitly, and
+# in that case the parent should add $(WLAN_ShellDebugSHELL) to the call.
+ifeq ($D,2)
+ WLAN_ShellDebug := 1
+endif
+ifdef WLAN_ShellDebug
+ ORIG_SHELL := $(SHELL)
+ SHELL = $(strip $(warning Shell: ORIG_SHELL=$(ORIG_SHELL) PATH=$(PATH))$(ORIG_SHELL)) -x
+ WLAN_ShellDebugSHELL := SHELL='$$(warning Shell: ORIG_SHELL=$$(ORIG_SHELL) PATH=$$(PATH))$(ORIG_SHELL) -x'
+endif
+
+# Variables of general utility.
+WLAN_Perl := perl
+WLAN_Python := python
+WLAN_WINPFX ?= Z:
+
+# These macros are used to stash an extra copy of generated source files,
+# such that when a source release is made those files can be reconstituted
+# from the stash during builds. Required if the generating tools or inputs
+# are not shipped.
+define wlan_copy_to_gen
+ $(if $(WLAN_COPY_GEN),&& mkdir -p $(subst $(abspath $2),$(abspath $2/$(WLAN_GEN_BASEDIR)),$(dir $(abspath $1))) && \
+ cp -pv $1 $(subst $(abspath $2),$(abspath $2/$(WLAN_GEN_BASEDIR)),$(abspath $1).GEN))
+endef
+
+############################################################################
+# CLM function; Generates a rule to run ClmCompiler iff the XML exists.
+# USAGE: $(call WLAN_GenClmCompilerRule,target-dir,src-base[,flags])
+# $1 is the directory where the generated .c file goes (it must exist)
+# $2 gives the base of the WL driver tree (SRCBASE).
+# $3 is an optional set of flags to pass to ClmCompiler.
+# The ClmCompiler options are concatenated from three places.
+# 1) The optional $3 argument
+# 2) The make variable CLMCOMPEXTFLAGS which is by default --obfuscate
+# but can be overridden AFTER the WLAN_GenClmCompilerRule usage
+# 3) --config $(CLM_TYPE) if ($CLM_TYPE) is defined. CLM_TYPE
+# represent the basename, without the .clm, of a ClmCompiler
+# config that is expected to be in src/wl/clm/types directory.
+# If $(CLM_TYPE) is defined, a dependency to that .clm will
+# be added.
+# The created ClmCompiler rule will use/depend on a xml file. This will be
+# src/wl/clm/private/wlc_clm_data_$CLM_TYPE).xml if it exists else
+# components/clm/clm-private/wlc_clm_data.xml will be used. This allows you
+# to use a xml file that corresponds to the .clm being used.
+# This macro uses GNU make's eval function to generate an
+# explicit rule to generate a particular CLM data file each time
+# it's called. Make variables which should be evaluated during eval
+# processing get one $, those which must defer till "runtime" get $$.
+# The "clm_compiled" phony target is provided for makefiles which need
+# to defer some other processing until CLM data is ready, and "clm_clean"
+# and "CLM_DATA_FILES" make it easier for internal client makefiles to
+# clean up CLM data (externally, this is treated as source and not removed).
+# The outermost conditional allows this rule to become a no-op
+# in external settings where there is no XML input file while allowing
+# it to turn back on automatically if an XML file is provided.
+# A vpath is used to find the XML input because this file is not allowed
+# to be present in external builds. Use of vpath allows it to be "poached"
+# from the internal build as necessary.
+# Note: the .c file is listed with and without a path due to the way the
+# Linux kernel Makefiles generate .depend data.
+CLMCOMPEXTFLAGS := --obfuscate
+define WLAN_GenClmCompilerRule
+$(eval\
+.PHONY: clm_compiled clm_clean
+
+# The "mkdir -p foo 2>/dev/null || test -d foo || mkdir -p foo" logic below is
+# intended to defeat potential race conditions. If the first mkdir fails we
+# check whether we just lost the race to create it; if it still doesn't exist
+# there must be some other problem so we run mkdir again to generate
+# the appropriate error message and die.
+$1: ; mkdir -p $$@ 2>/dev/null || test -d $$@ || mkdir -p $$@
+vpath wlc_clm_data.c $1 $$(abspath $1)
+ifneq (,$(or $(wildcard $(addsuffix /../components/clm-private/wlc_clm_data.xml,$2 $2/../../src $2/../../../src)),$(wildcard $(addsuffix /wl/clm/private/wlc_clm_data_$(CLM_TYPE).xml,$2 $2/../../src $2/../../../src))))
+ vpath wlc_clm_data.xml $(wildcard $(addsuffix /../components/clm-private,$2 $2/../../src $2/../../../src))
+ vpath wlc_clm_data_$(CLM_TYPE).xml $(addsuffix /wl/clm/private,$2 $2/../../src $2/../../../src)
+ vpath %.clm $(addsuffix /wl/clm/types,$2 $2/../../src $2/../../../src)
+ $1/wlc_clm_data.c: \
+ $$(if $$(wildcard $2/wl/clm/private/wlc_clm_data_$$(CLM_TYPE).xml),$2/wl/clm/private/wlc_clm_data_$$(CLM_TYPE).xml,wlc_clm_data.xml) \
+ $2/../components/clm-api/include/wlc_clm_data.h \
+ $$(wildcard $2/../components/clm-bin/ClmCompiler.py) \
+ $$(if $$(CLM_TYPE),$$(CLM_TYPE).clm) \
+ | $1; \
+ @echo wlc_clm_data.c rule -- $$@: $$+ ;\
+ $$(strip $$(firstword $$(wildcard $$(addsuffix /components/clm-bin/ClmCompiler.py, $2/.. $2/../.. $2/../../..))) \
+ --clmapi_include_dir $$(firstword $$(wildcard $$(addsuffix components/clm-api/include, $2/../ $2/../../ $2/../../../ ))) \
+ --print_options --bcmwifi_include_dir $$(firstword $$(wildcard $$(addsuffix shared/bcmwifi/include, $2/ $2/../../src/ $2/../../../src/ ))) \
+ $$(if $$(CLM_TYPE),--config_file $$(lastword $$^)) $3 $(CLMCOMPEXTFLAGS) $$< $$@ $$(call wlan_copy_to_gen,$$@,$2))
+else
+ vpath %.GEN $(subst $(abspath $2),$(abspath $2/$(WLAN_GEN_BASEDIR)),$1) $(sort $(patsubst %/,%,$(dir $(wildcard $(subst $(abspath $2),$(abspath $2/$(WLAN_GEN_BASEDIR)),$(dir $1))*/*.GEN))))
+ $1/%: %.GEN ; cp -pv $$< $$@
+endif
+ clm_compiled: $1/wlc_clm_data.c
+ clm_clean:: ; $$(RM) $1/wlc_clm_data.c
+ CLM_DATA_FILES += $1/wlc_clm_data.c
+)
+endef
+
+################################################################
+# Generates rule that generates wlc_sar_tbl.c file
+# USAGE: $(call WLAN_GenSarTblRule,target-dir,src-base,[sar-files])
+# Arguments:
+# target-dir -- Directory where generated wlc_sar_tbl.c shall be put.
+# src-base -- Top level 'src' directory. Strange manipulations with
+# it within macro expansion are due to some strange
+# peculiarities of Linux driver builds
+# sar_files -- Space-separated list of base names of .csv files that
+# contain SAR entries that shall be put to generated SAR
+# table. Empty means use all files in src/wl/sar directory
+define WLAN_GenSarTblRule
+$(eval\
+$1/wlc_sar_tbl.c: ; $$(firstword $$(wildcard \
+ $$(addsuffix /components/tools/bin/sar_conv.py, $2/.. $2/../.. $2/../../..))) create_c \
+ --driver_dir $$(addsuffix /../.., $$(firstword $$(wildcard \
+ $$(addsuffix /include, $2 $2/../../src $2/../../../src)))) \
+ $$(addprefix $$(firstword $$(wildcard \
+ $$(addsuffix /wl/sar, $2 $2/../../src $2/../../../src)))/, \
+ $$(if $3,$3,*.csv)) $$@
+)
+endef
+
+################################################################
+
+endif # _WLAN_COMMON_MK
diff --git a/wl/src/shared/bcm_app_utils.c b/wl/src/shared/bcm_app_utils.c
new file mode 100644
index 0000000..76e89b9
--- /dev/null
+++ b/wl/src/shared/bcm_app_utils.c
@@ -0,0 +1,1231 @@
+/*
+ * Misc utility routines used by kernel or app-level.
+ * Contents are wifi-specific, used by any kernel or app-level
+ * software that might want wifi things as it grows.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcm_app_utils.c 625864 2016-03-18 00:12:54Z $
+ */
+
+#include <typedefs.h>
+
+#ifdef BCMDRIVER
+#include <osl.h>
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
+#else /* BCMDRIVER */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifndef ASSERT
+#define ASSERT(exp)
+#endif
+#endif /* BCMDRIVER */
+#include <bcmwifi_channels.h>
+
+#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
+#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
+#endif
+
+#include <bcmutils.h>
+#include <wlioctl.h>
+#include <wlioctl_utils.h>
+
+#ifndef BCMDRIVER
+/* Take an array of measurments representing a single channel over time and return
+ a summary. Currently implemented as a simple average but could easily evolve
+ into more cpomplex alogrithms.
+*/
+cca_congest_channel_req_t *
+cca_per_chan_summary(cca_congest_channel_req_t *input, cca_congest_channel_req_t *avg, bool percent)
+{
+ int sec;
+ cca_congest_t totals;
+
+ totals.duration = 0;
+ totals.congest_ibss = 0;
+ totals.congest_obss = 0;
+ totals.interference = 0;
+ avg->num_secs = 0;
+
+ for (sec = 0; sec < input->num_secs; sec++) {
+ if (input->secs[sec].duration) {
+ totals.duration += input->secs[sec].duration;
+ totals.congest_ibss += input->secs[sec].congest_ibss;
+ totals.congest_obss += input->secs[sec].congest_obss;
+ totals.interference += input->secs[sec].interference;
+ avg->num_secs++;
+ }
+ }
+ avg->chanspec = input->chanspec;
+
+ if (!avg->num_secs || !totals.duration)
+ return (avg);
+
+ if (percent) {
+ avg->secs[0].duration = totals.duration / avg->num_secs;
+ avg->secs[0].congest_ibss = totals.congest_ibss * 100/totals.duration;
+ avg->secs[0].congest_obss = totals.congest_obss * 100/totals.duration;
+ avg->secs[0].interference = totals.interference * 100/totals.duration;
+ } else {
+ avg->secs[0].duration = totals.duration / avg->num_secs;
+ avg->secs[0].congest_ibss = totals.congest_ibss / avg->num_secs;
+ avg->secs[0].congest_obss = totals.congest_obss / avg->num_secs;
+ avg->secs[0].interference = totals.interference / avg->num_secs;
+ }
+
+ return (avg);
+}
+
+static void
+cca_info(uint8 *bitmap, int num_bits, int *left, int *bit_pos)
+{
+ int i;
+ for (*left = 0, i = 0; i < num_bits; i++) {
+ if (isset(bitmap, i)) {
+ (*left)++;
+ *bit_pos = i;
+ }
+ }
+}
+
+static uint8
+spec_to_chan(chanspec_t chspec)
+{
+ uint8 center_ch, edge, primary, sb;
+
+ center_ch = CHSPEC_CHANNEL(chspec);
+
+ if (CHSPEC_BW_LE20(chspec)) {
+ return center_ch;
+ } else {
+ /* the lower edge of the wide channel is half the bw from
+ * the center channel.
+ */
+ if (CHSPEC_IS40(chspec)) {
+ edge = center_ch - CH_20MHZ_APART;
+ } else {
+ /* must be 80MHz (until we support more) */
+ ASSERT(CHSPEC_IS80(chspec));
+ edge = center_ch - CH_40MHZ_APART;
+ }
+
+ /* find the channel number of the lowest 20MHz primary channel */
+ primary = edge + CH_10MHZ_APART;
+
+ /* select the actual subband */
+ sb = (chspec & WL_CHANSPEC_CTL_SB_MASK) >> WL_CHANSPEC_CTL_SB_SHIFT;
+ primary = primary + sb * CH_20MHZ_APART;
+
+ return primary;
+ }
+}
+
+/*
+ Take an array of measumrements representing summaries of different channels.
+ Return a recomended channel.
+ Interference is evil, get rid of that first.
+ Then hunt for lowest Other bss traffic.
+ Don't forget that channels with low duration times may not have accurate readings.
+ For the moment, do not overwrite input array.
+*/
+int
+cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer)
+{
+ uint8 *bitmap = NULL; /* 38 Max channels needs 5 bytes = 40 */
+ int i, left, winner, ret_val = 0;
+ uint32 min_obss = 1 << 30;
+ uint bitmap_sz;
+
+ bitmap_sz = CEIL(num_chans, NBBY);
+ bitmap = (uint8 *)malloc(bitmap_sz);
+ if (bitmap == NULL) {
+ printf("unable to allocate memory\n");
+ return BCME_NOMEM;
+ }
+
+ memset(bitmap, 0, bitmap_sz);
+ /* Initially, all channels are up for consideration */
+ for (i = 0; i < num_chans; i++) {
+ if (input[i]->chanspec)
+ setbit(bitmap, i);
+ }
+ cca_info(bitmap, num_chans, &left, &i);
+ if (!left) {
+ ret_val = CCA_ERRNO_TOO_FEW;
+ goto f_exit;
+ }
+
+ /* Filter for 2.4 GHz Band */
+ if (flags & CCA_FLAG_2G_ONLY) {
+ for (i = 0; i < num_chans; i++) {
+ if (!CHSPEC_IS2G(input[i]->chanspec))
+ clrbit(bitmap, i);
+ }
+ }
+ cca_info(bitmap, num_chans, &left, &i);
+ if (!left) {
+ ret_val = CCA_ERRNO_BAND;
+ goto f_exit;
+ }
+
+ /* Filter for 5 GHz Band */
+ if (flags & CCA_FLAG_5G_ONLY) {
+ for (i = 0; i < num_chans; i++) {
+ if (!CHSPEC_IS5G(input[i]->chanspec))
+ clrbit(bitmap, i);
+ }
+ }
+ cca_info(bitmap, num_chans, &left, &i);
+ if (!left) {
+ ret_val = CCA_ERRNO_BAND;
+ goto f_exit;
+ }
+
+ /* Filter for Duration */
+ if (!(flags & CCA_FLAG_IGNORE_DURATION)) {
+ for (i = 0; i < num_chans; i++) {
+ if (input[i]->secs[0].duration < CCA_THRESH_MILLI)
+ clrbit(bitmap, i);
+ }
+ }
+ cca_info(bitmap, num_chans, &left, &i);
+ if (!left) {
+ ret_val = CCA_ERRNO_DURATION;
+ goto f_exit;
+ }
+
+ /* Filter for 1 6 11 on 2.4 Band */
+ if (flags & CCA_FLAGS_PREFER_1_6_11) {
+ int tmp_channel = spec_to_chan(input[i]->chanspec);
+ int is2g = CHSPEC_IS2G(input[i]->chanspec);
+ for (i = 0; i < num_chans; i++) {
+ if (is2g && tmp_channel != 1 && tmp_channel != 6 && tmp_channel != 11)
+ clrbit(bitmap, i);
+ }
+ }
+ cca_info(bitmap, num_chans, &left, &i);
+ if (!left) {
+ ret_val = CCA_ERRNO_PREF_CHAN;
+ goto f_exit;
+ }
+
+ /* Toss high interference interference */
+ if (!(flags & CCA_FLAG_IGNORE_INTERFER)) {
+ for (i = 0; i < num_chans; i++) {
+ if (input[i]->secs[0].interference > CCA_THRESH_INTERFERE)
+ clrbit(bitmap, i);
+ }
+ cca_info(bitmap, num_chans, &left, &i);
+ if (!left) {
+ ret_val = CCA_ERRNO_INTERFER;
+ goto f_exit;
+ }
+ }
+
+ /* Now find lowest obss */
+ winner = 0;
+ for (i = 0; i < num_chans; i++) {
+ if (isset(bitmap, i) && input[i]->secs[0].congest_obss < min_obss) {
+ winner = i;
+ min_obss = input[i]->secs[0].congest_obss;
+ }
+ }
+ *answer = input[winner]->chanspec;
+ f_exit:
+ free(bitmap); /* free the allocated memory for bitmap */
+ return ret_val;
+}
+#endif /* !BCMDRIVER */
+
+/* offset of cntmember by sizeof(uint32) from the first cnt variable, txframe. */
+#define IDX_IN_WL_CNT_VER_6_T(cntmember) \
+ ((OFFSETOF(wl_cnt_ver_6_t, cntmember) - OFFSETOF(wl_cnt_ver_6_t, txframe)) / sizeof(uint32))
+
+#define IDX_IN_WL_CNT_VER_7_T(cntmember) \
+ ((OFFSETOF(wl_cnt_ver_7_t, cntmember) - OFFSETOF(wl_cnt_ver_7_t, txframe)) / sizeof(uint32))
+
+#define IDX_IN_WL_CNT_VER_11_T(cntmember) \
+ ((OFFSETOF(wl_cnt_ver_11_t, cntmember) - OFFSETOF(wl_cnt_ver_11_t, txframe)) \
+ / sizeof(uint32))
+
+/* Exclude version and length fields */
+#define NUM_OF_CNT_IN_WL_CNT_VER_6_T \
+ ((sizeof(wl_cnt_ver_6_t) - 2 * sizeof(uint16)) / sizeof(uint32))
+/* Exclude macstat cnt variables. wl_cnt_ver_6_t only has 62 macstat cnt variables. */
+#define NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T \
+ (NUM_OF_CNT_IN_WL_CNT_VER_6_T - (WL_CNT_MCST_VAR_NUM - 2))
+
+/* Exclude version and length fields */
+#define NUM_OF_CNT_IN_WL_CNT_VER_7_T \
+ ((sizeof(wl_cnt_ver_7_t) - 2 * sizeof(uint16)) / sizeof(uint32))
+/* Exclude macstat cnt variables. wl_cnt_ver_7_t only has 61 macstat cnt variables. */
+#define NUM_OF_WLCCNT_IN_WL_CNT_VER_7_T \
+ (NUM_OF_CNT_IN_WL_CNT_VER_7_T - (WL_CNT_MCST_VAR_NUM - 3))
+
+/* Exclude version and length fields */
+#define NUM_OF_CNT_IN_WL_CNT_VER_11_T \
+ ((sizeof(wl_cnt_ver_11_t) - 2 * sizeof(uint16)) / sizeof(uint32))
+/* Exclude 64 macstat cnt variables. */
+#define NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T \
+ (NUM_OF_CNT_IN_WL_CNT_VER_11_T - WL_CNT_MCST_VAR_NUM)
+
+/* Index conversion table from wl_cnt_ver_6_t to wl_cnt_wlc_t */
+static const uint8 wlcntver6t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T] = {
+ IDX_IN_WL_CNT_VER_6_T(txframe),
+ IDX_IN_WL_CNT_VER_6_T(txbyte),
+ IDX_IN_WL_CNT_VER_6_T(txretrans),
+ IDX_IN_WL_CNT_VER_6_T(txerror),
+ IDX_IN_WL_CNT_VER_6_T(txctl),
+ IDX_IN_WL_CNT_VER_6_T(txprshort),
+ IDX_IN_WL_CNT_VER_6_T(txserr),
+ IDX_IN_WL_CNT_VER_6_T(txnobuf),
+ IDX_IN_WL_CNT_VER_6_T(txnoassoc),
+ IDX_IN_WL_CNT_VER_6_T(txrunt),
+ IDX_IN_WL_CNT_VER_6_T(txchit),
+ IDX_IN_WL_CNT_VER_6_T(txcmiss),
+ IDX_IN_WL_CNT_VER_6_T(txuflo),
+ IDX_IN_WL_CNT_VER_6_T(txphyerr),
+ IDX_IN_WL_CNT_VER_6_T(txphycrs),
+ IDX_IN_WL_CNT_VER_6_T(rxframe),
+ IDX_IN_WL_CNT_VER_6_T(rxbyte),
+ IDX_IN_WL_CNT_VER_6_T(rxerror),
+ IDX_IN_WL_CNT_VER_6_T(rxctl),
+ IDX_IN_WL_CNT_VER_6_T(rxnobuf),
+ IDX_IN_WL_CNT_VER_6_T(rxnondata),
+ IDX_IN_WL_CNT_VER_6_T(rxbadds),
+ IDX_IN_WL_CNT_VER_6_T(rxbadcm),
+ IDX_IN_WL_CNT_VER_6_T(rxfragerr),
+ IDX_IN_WL_CNT_VER_6_T(rxrunt),
+ IDX_IN_WL_CNT_VER_6_T(rxgiant),
+ IDX_IN_WL_CNT_VER_6_T(rxnoscb),
+ IDX_IN_WL_CNT_VER_6_T(rxbadproto),
+ IDX_IN_WL_CNT_VER_6_T(rxbadsrcmac),
+ IDX_IN_WL_CNT_VER_6_T(rxbadda),
+ IDX_IN_WL_CNT_VER_6_T(rxfilter),
+ IDX_IN_WL_CNT_VER_6_T(rxoflo),
+ IDX_IN_WL_CNT_VER_6_T(rxuflo),
+ IDX_IN_WL_CNT_VER_6_T(rxuflo) + 1,
+ IDX_IN_WL_CNT_VER_6_T(rxuflo) + 2,
+ IDX_IN_WL_CNT_VER_6_T(rxuflo) + 3,
+ IDX_IN_WL_CNT_VER_6_T(rxuflo) + 4,
+ IDX_IN_WL_CNT_VER_6_T(rxuflo) + 5,
+ IDX_IN_WL_CNT_VER_6_T(d11cnt_txrts_off),
+ IDX_IN_WL_CNT_VER_6_T(d11cnt_rxcrc_off),
+ IDX_IN_WL_CNT_VER_6_T(d11cnt_txnocts_off),
+ IDX_IN_WL_CNT_VER_6_T(dmade),
+ IDX_IN_WL_CNT_VER_6_T(dmada),
+ IDX_IN_WL_CNT_VER_6_T(dmape),
+ IDX_IN_WL_CNT_VER_6_T(reset),
+ IDX_IN_WL_CNT_VER_6_T(tbtt),
+ IDX_IN_WL_CNT_VER_6_T(txdmawar),
+ IDX_IN_WL_CNT_VER_6_T(pkt_callback_reg_fail),
+ IDX_IN_WL_CNT_VER_6_T(txfrag),
+ IDX_IN_WL_CNT_VER_6_T(txmulti),
+ IDX_IN_WL_CNT_VER_6_T(txfail),
+ IDX_IN_WL_CNT_VER_6_T(txretry),
+ IDX_IN_WL_CNT_VER_6_T(txretrie),
+ IDX_IN_WL_CNT_VER_6_T(rxdup),
+ IDX_IN_WL_CNT_VER_6_T(txrts),
+ IDX_IN_WL_CNT_VER_6_T(txnocts),
+ IDX_IN_WL_CNT_VER_6_T(txnoack),
+ IDX_IN_WL_CNT_VER_6_T(rxfrag),
+ IDX_IN_WL_CNT_VER_6_T(rxmulti),
+ IDX_IN_WL_CNT_VER_6_T(rxcrc),
+ IDX_IN_WL_CNT_VER_6_T(txfrmsnt),
+ IDX_IN_WL_CNT_VER_6_T(rxundec),
+ IDX_IN_WL_CNT_VER_6_T(tkipmicfaill),
+ IDX_IN_WL_CNT_VER_6_T(tkipcntrmsr),
+ IDX_IN_WL_CNT_VER_6_T(tkipreplay),
+ IDX_IN_WL_CNT_VER_6_T(ccmpfmterr),
+ IDX_IN_WL_CNT_VER_6_T(ccmpreplay),
+ IDX_IN_WL_CNT_VER_6_T(ccmpundec),
+ IDX_IN_WL_CNT_VER_6_T(fourwayfail),
+ IDX_IN_WL_CNT_VER_6_T(wepundec),
+ IDX_IN_WL_CNT_VER_6_T(wepicverr),
+ IDX_IN_WL_CNT_VER_6_T(decsuccess),
+ IDX_IN_WL_CNT_VER_6_T(tkipicverr),
+ IDX_IN_WL_CNT_VER_6_T(wepexcluded),
+ IDX_IN_WL_CNT_VER_6_T(txchanrej),
+ IDX_IN_WL_CNT_VER_6_T(psmwds),
+ IDX_IN_WL_CNT_VER_6_T(phywatchdog),
+ IDX_IN_WL_CNT_VER_6_T(prq_entries_handled),
+ IDX_IN_WL_CNT_VER_6_T(prq_undirected_entries),
+ IDX_IN_WL_CNT_VER_6_T(prq_bad_entries),
+ IDX_IN_WL_CNT_VER_6_T(atim_suppress_count),
+ IDX_IN_WL_CNT_VER_6_T(bcn_template_not_ready),
+ IDX_IN_WL_CNT_VER_6_T(bcn_template_not_ready_done),
+ IDX_IN_WL_CNT_VER_6_T(late_tbtt_dpc),
+ IDX_IN_WL_CNT_VER_6_T(rx1mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx2mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx5mbps5),
+ IDX_IN_WL_CNT_VER_6_T(rx6mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx9mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx11mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx12mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx18mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx24mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx36mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx48mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx54mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx108mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx162mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx216mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx270mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx324mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx378mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx432mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx486mbps),
+ IDX_IN_WL_CNT_VER_6_T(rx540mbps),
+ IDX_IN_WL_CNT_VER_6_T(rfdisable),
+ IDX_IN_WL_CNT_VER_6_T(txexptime),
+ IDX_IN_WL_CNT_VER_6_T(txmpdu_sgi),
+ IDX_IN_WL_CNT_VER_6_T(rxmpdu_sgi),
+ IDX_IN_WL_CNT_VER_6_T(txmpdu_stbc),
+ IDX_IN_WL_CNT_VER_6_T(rxmpdu_stbc),
+ IDX_IN_WL_CNT_VER_6_T(rxundec_mcst),
+ IDX_IN_WL_CNT_VER_6_T(tkipmicfaill_mcst),
+ IDX_IN_WL_CNT_VER_6_T(tkipcntrmsr_mcst),
+ IDX_IN_WL_CNT_VER_6_T(tkipreplay_mcst),
+ IDX_IN_WL_CNT_VER_6_T(ccmpfmterr_mcst),
+ IDX_IN_WL_CNT_VER_6_T(ccmpreplay_mcst),
+ IDX_IN_WL_CNT_VER_6_T(ccmpundec_mcst),
+ IDX_IN_WL_CNT_VER_6_T(fourwayfail_mcst),
+ IDX_IN_WL_CNT_VER_6_T(wepundec_mcst),
+ IDX_IN_WL_CNT_VER_6_T(wepicverr_mcst),
+ IDX_IN_WL_CNT_VER_6_T(decsuccess_mcst),
+ IDX_IN_WL_CNT_VER_6_T(tkipicverr_mcst),
+ IDX_IN_WL_CNT_VER_6_T(wepexcluded_mcst)
+};
+
+static const uint8 wlcntver7t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_7_T] = {
+ IDX_IN_WL_CNT_VER_7_T(txframe),
+ IDX_IN_WL_CNT_VER_7_T(txbyte),
+ IDX_IN_WL_CNT_VER_7_T(txretrans),
+ IDX_IN_WL_CNT_VER_7_T(txerror),
+ IDX_IN_WL_CNT_VER_7_T(txctl),
+ IDX_IN_WL_CNT_VER_7_T(txprshort),
+ IDX_IN_WL_CNT_VER_7_T(txserr),
+ IDX_IN_WL_CNT_VER_7_T(txnobuf),
+ IDX_IN_WL_CNT_VER_7_T(txnoassoc),
+ IDX_IN_WL_CNT_VER_7_T(txrunt),
+ IDX_IN_WL_CNT_VER_7_T(txchit),
+ IDX_IN_WL_CNT_VER_7_T(txcmiss),
+ IDX_IN_WL_CNT_VER_7_T(txuflo),
+ IDX_IN_WL_CNT_VER_7_T(txphyerr),
+ IDX_IN_WL_CNT_VER_7_T(txphycrs),
+ IDX_IN_WL_CNT_VER_7_T(rxframe),
+ IDX_IN_WL_CNT_VER_7_T(rxbyte),
+ IDX_IN_WL_CNT_VER_7_T(rxerror),
+ IDX_IN_WL_CNT_VER_7_T(rxctl),
+ IDX_IN_WL_CNT_VER_7_T(rxnobuf),
+ IDX_IN_WL_CNT_VER_7_T(rxnondata),
+ IDX_IN_WL_CNT_VER_7_T(rxbadds),
+ IDX_IN_WL_CNT_VER_7_T(rxbadcm),
+ IDX_IN_WL_CNT_VER_7_T(rxfragerr),
+ IDX_IN_WL_CNT_VER_7_T(rxrunt),
+ IDX_IN_WL_CNT_VER_7_T(rxgiant),
+ IDX_IN_WL_CNT_VER_7_T(rxnoscb),
+ IDX_IN_WL_CNT_VER_7_T(rxbadproto),
+ IDX_IN_WL_CNT_VER_7_T(rxbadsrcmac),
+ IDX_IN_WL_CNT_VER_7_T(rxbadda),
+ IDX_IN_WL_CNT_VER_7_T(rxfilter),
+ IDX_IN_WL_CNT_VER_7_T(rxoflo),
+ IDX_IN_WL_CNT_VER_7_T(rxuflo),
+ IDX_IN_WL_CNT_VER_7_T(rxuflo) + 1,
+ IDX_IN_WL_CNT_VER_7_T(rxuflo) + 2,
+ IDX_IN_WL_CNT_VER_7_T(rxuflo) + 3,
+ IDX_IN_WL_CNT_VER_7_T(rxuflo) + 4,
+ IDX_IN_WL_CNT_VER_7_T(rxuflo) + 5,
+ IDX_IN_WL_CNT_VER_7_T(d11cnt_txrts_off),
+ IDX_IN_WL_CNT_VER_7_T(d11cnt_rxcrc_off),
+ IDX_IN_WL_CNT_VER_7_T(d11cnt_txnocts_off),
+ IDX_IN_WL_CNT_VER_7_T(dmade),
+ IDX_IN_WL_CNT_VER_7_T(dmada),
+ IDX_IN_WL_CNT_VER_7_T(dmape),
+ IDX_IN_WL_CNT_VER_7_T(reset),
+ IDX_IN_WL_CNT_VER_7_T(tbtt),
+ IDX_IN_WL_CNT_VER_7_T(txdmawar),
+ IDX_IN_WL_CNT_VER_7_T(pkt_callback_reg_fail),
+ IDX_IN_WL_CNT_VER_7_T(txfrag),
+ IDX_IN_WL_CNT_VER_7_T(txmulti),
+ IDX_IN_WL_CNT_VER_7_T(txfail),
+ IDX_IN_WL_CNT_VER_7_T(txretry),
+ IDX_IN_WL_CNT_VER_7_T(txretrie),
+ IDX_IN_WL_CNT_VER_7_T(rxdup),
+ IDX_IN_WL_CNT_VER_7_T(txrts),
+ IDX_IN_WL_CNT_VER_7_T(txnocts),
+ IDX_IN_WL_CNT_VER_7_T(txnoack),
+ IDX_IN_WL_CNT_VER_7_T(rxfrag),
+ IDX_IN_WL_CNT_VER_7_T(rxmulti),
+ IDX_IN_WL_CNT_VER_7_T(rxcrc),
+ IDX_IN_WL_CNT_VER_7_T(txfrmsnt),
+ IDX_IN_WL_CNT_VER_7_T(rxundec),
+ IDX_IN_WL_CNT_VER_7_T(tkipmicfaill),
+ IDX_IN_WL_CNT_VER_7_T(tkipcntrmsr),
+ IDX_IN_WL_CNT_VER_7_T(tkipreplay),
+ IDX_IN_WL_CNT_VER_7_T(ccmpfmterr),
+ IDX_IN_WL_CNT_VER_7_T(ccmpreplay),
+ IDX_IN_WL_CNT_VER_7_T(ccmpundec),
+ IDX_IN_WL_CNT_VER_7_T(fourwayfail),
+ IDX_IN_WL_CNT_VER_7_T(wepundec),
+ IDX_IN_WL_CNT_VER_7_T(wepicverr),
+ IDX_IN_WL_CNT_VER_7_T(decsuccess),
+ IDX_IN_WL_CNT_VER_7_T(tkipicverr),
+ IDX_IN_WL_CNT_VER_7_T(wepexcluded),
+ IDX_IN_WL_CNT_VER_7_T(txchanrej),
+ IDX_IN_WL_CNT_VER_7_T(psmwds),
+ IDX_IN_WL_CNT_VER_7_T(phywatchdog),
+ IDX_IN_WL_CNT_VER_7_T(prq_entries_handled),
+ IDX_IN_WL_CNT_VER_7_T(prq_undirected_entries),
+ IDX_IN_WL_CNT_VER_7_T(prq_bad_entries),
+ IDX_IN_WL_CNT_VER_7_T(atim_suppress_count),
+ IDX_IN_WL_CNT_VER_7_T(bcn_template_not_ready),
+ IDX_IN_WL_CNT_VER_7_T(bcn_template_not_ready_done),
+ IDX_IN_WL_CNT_VER_7_T(late_tbtt_dpc),
+ IDX_IN_WL_CNT_VER_7_T(rx1mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx2mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx5mbps5),
+ IDX_IN_WL_CNT_VER_7_T(rx6mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx9mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx11mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx12mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx18mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx24mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx36mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx48mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx54mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx108mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx162mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx216mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx270mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx324mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx378mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx432mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx486mbps),
+ IDX_IN_WL_CNT_VER_7_T(rx540mbps),
+ IDX_IN_WL_CNT_VER_7_T(rfdisable),
+ IDX_IN_WL_CNT_VER_7_T(txexptime),
+ IDX_IN_WL_CNT_VER_7_T(txmpdu_sgi),
+ IDX_IN_WL_CNT_VER_7_T(rxmpdu_sgi),
+ IDX_IN_WL_CNT_VER_7_T(txmpdu_stbc),
+ IDX_IN_WL_CNT_VER_7_T(rxmpdu_stbc),
+ IDX_IN_WL_CNT_VER_7_T(rxundec_mcst),
+ IDX_IN_WL_CNT_VER_7_T(tkipmicfaill_mcst),
+ IDX_IN_WL_CNT_VER_7_T(tkipcntrmsr_mcst),
+ IDX_IN_WL_CNT_VER_7_T(tkipreplay_mcst),
+ IDX_IN_WL_CNT_VER_7_T(ccmpfmterr_mcst),
+ IDX_IN_WL_CNT_VER_7_T(ccmpreplay_mcst),
+ IDX_IN_WL_CNT_VER_7_T(ccmpundec_mcst),
+ IDX_IN_WL_CNT_VER_7_T(fourwayfail_mcst),
+ IDX_IN_WL_CNT_VER_7_T(wepundec_mcst),
+ IDX_IN_WL_CNT_VER_7_T(wepicverr_mcst),
+ IDX_IN_WL_CNT_VER_7_T(decsuccess_mcst),
+ IDX_IN_WL_CNT_VER_7_T(tkipicverr_mcst),
+ IDX_IN_WL_CNT_VER_7_T(wepexcluded_mcst)
+};
+
+/* Index conversion table from wl_cnt_ver_11_t to wl_cnt_wlc_t */
+static const uint8 wlcntver11t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T] = {
+ IDX_IN_WL_CNT_VER_11_T(txframe),
+ IDX_IN_WL_CNT_VER_11_T(txbyte),
+ IDX_IN_WL_CNT_VER_11_T(txretrans),
+ IDX_IN_WL_CNT_VER_11_T(txerror),
+ IDX_IN_WL_CNT_VER_11_T(txctl),
+ IDX_IN_WL_CNT_VER_11_T(txprshort),
+ IDX_IN_WL_CNT_VER_11_T(txserr),
+ IDX_IN_WL_CNT_VER_11_T(txnobuf),
+ IDX_IN_WL_CNT_VER_11_T(txnoassoc),
+ IDX_IN_WL_CNT_VER_11_T(txrunt),
+ IDX_IN_WL_CNT_VER_11_T(txchit),
+ IDX_IN_WL_CNT_VER_11_T(txcmiss),
+ IDX_IN_WL_CNT_VER_11_T(txuflo),
+ IDX_IN_WL_CNT_VER_11_T(txphyerr),
+ IDX_IN_WL_CNT_VER_11_T(txphycrs),
+ IDX_IN_WL_CNT_VER_11_T(rxframe),
+ IDX_IN_WL_CNT_VER_11_T(rxbyte),
+ IDX_IN_WL_CNT_VER_11_T(rxerror),
+ IDX_IN_WL_CNT_VER_11_T(rxctl),
+ IDX_IN_WL_CNT_VER_11_T(rxnobuf),
+ IDX_IN_WL_CNT_VER_11_T(rxnondata),
+ IDX_IN_WL_CNT_VER_11_T(rxbadds),
+ IDX_IN_WL_CNT_VER_11_T(rxbadcm),
+ IDX_IN_WL_CNT_VER_11_T(rxfragerr),
+ IDX_IN_WL_CNT_VER_11_T(rxrunt),
+ IDX_IN_WL_CNT_VER_11_T(rxgiant),
+ IDX_IN_WL_CNT_VER_11_T(rxnoscb),
+ IDX_IN_WL_CNT_VER_11_T(rxbadproto),
+ IDX_IN_WL_CNT_VER_11_T(rxbadsrcmac),
+ IDX_IN_WL_CNT_VER_11_T(rxbadda),
+ IDX_IN_WL_CNT_VER_11_T(rxfilter),
+ IDX_IN_WL_CNT_VER_11_T(rxoflo),
+ IDX_IN_WL_CNT_VER_11_T(rxuflo),
+ IDX_IN_WL_CNT_VER_11_T(rxuflo) + 1,
+ IDX_IN_WL_CNT_VER_11_T(rxuflo) + 2,
+ IDX_IN_WL_CNT_VER_11_T(rxuflo) + 3,
+ IDX_IN_WL_CNT_VER_11_T(rxuflo) + 4,
+ IDX_IN_WL_CNT_VER_11_T(rxuflo) + 5,
+ IDX_IN_WL_CNT_VER_11_T(d11cnt_txrts_off),
+ IDX_IN_WL_CNT_VER_11_T(d11cnt_rxcrc_off),
+ IDX_IN_WL_CNT_VER_11_T(d11cnt_txnocts_off),
+ IDX_IN_WL_CNT_VER_11_T(dmade),
+ IDX_IN_WL_CNT_VER_11_T(dmada),
+ IDX_IN_WL_CNT_VER_11_T(dmape),
+ IDX_IN_WL_CNT_VER_11_T(reset),
+ IDX_IN_WL_CNT_VER_11_T(tbtt),
+ IDX_IN_WL_CNT_VER_11_T(txdmawar),
+ IDX_IN_WL_CNT_VER_11_T(pkt_callback_reg_fail),
+ IDX_IN_WL_CNT_VER_11_T(txfrag),
+ IDX_IN_WL_CNT_VER_11_T(txmulti),
+ IDX_IN_WL_CNT_VER_11_T(txfail),
+ IDX_IN_WL_CNT_VER_11_T(txretry),
+ IDX_IN_WL_CNT_VER_11_T(txretrie),
+ IDX_IN_WL_CNT_VER_11_T(rxdup),
+ IDX_IN_WL_CNT_VER_11_T(txrts),
+ IDX_IN_WL_CNT_VER_11_T(txnocts),
+ IDX_IN_WL_CNT_VER_11_T(txnoack),
+ IDX_IN_WL_CNT_VER_11_T(rxfrag),
+ IDX_IN_WL_CNT_VER_11_T(rxmulti),
+ IDX_IN_WL_CNT_VER_11_T(rxcrc),
+ IDX_IN_WL_CNT_VER_11_T(txfrmsnt),
+ IDX_IN_WL_CNT_VER_11_T(rxundec),
+ IDX_IN_WL_CNT_VER_11_T(tkipmicfaill),
+ IDX_IN_WL_CNT_VER_11_T(tkipcntrmsr),
+ IDX_IN_WL_CNT_VER_11_T(tkipreplay),
+ IDX_IN_WL_CNT_VER_11_T(ccmpfmterr),
+ IDX_IN_WL_CNT_VER_11_T(ccmpreplay),
+ IDX_IN_WL_CNT_VER_11_T(ccmpundec),
+ IDX_IN_WL_CNT_VER_11_T(fourwayfail),
+ IDX_IN_WL_CNT_VER_11_T(wepundec),
+ IDX_IN_WL_CNT_VER_11_T(wepicverr),
+ IDX_IN_WL_CNT_VER_11_T(decsuccess),
+ IDX_IN_WL_CNT_VER_11_T(tkipicverr),
+ IDX_IN_WL_CNT_VER_11_T(wepexcluded),
+ IDX_IN_WL_CNT_VER_11_T(txchanrej),
+ IDX_IN_WL_CNT_VER_11_T(psmwds),
+ IDX_IN_WL_CNT_VER_11_T(phywatchdog),
+ IDX_IN_WL_CNT_VER_11_T(prq_entries_handled),
+ IDX_IN_WL_CNT_VER_11_T(prq_undirected_entries),
+ IDX_IN_WL_CNT_VER_11_T(prq_bad_entries),
+ IDX_IN_WL_CNT_VER_11_T(atim_suppress_count),
+ IDX_IN_WL_CNT_VER_11_T(bcn_template_not_ready),
+ IDX_IN_WL_CNT_VER_11_T(bcn_template_not_ready_done),
+ IDX_IN_WL_CNT_VER_11_T(late_tbtt_dpc),
+ IDX_IN_WL_CNT_VER_11_T(rx1mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx2mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx5mbps5),
+ IDX_IN_WL_CNT_VER_11_T(rx6mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx9mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx11mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx12mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx18mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx24mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx36mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx48mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx54mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx108mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx162mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx216mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx270mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx324mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx378mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx432mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx486mbps),
+ IDX_IN_WL_CNT_VER_11_T(rx540mbps),
+ IDX_IN_WL_CNT_VER_11_T(rfdisable),
+ IDX_IN_WL_CNT_VER_11_T(txexptime),
+ IDX_IN_WL_CNT_VER_11_T(txmpdu_sgi),
+ IDX_IN_WL_CNT_VER_11_T(rxmpdu_sgi),
+ IDX_IN_WL_CNT_VER_11_T(txmpdu_stbc),
+ IDX_IN_WL_CNT_VER_11_T(rxmpdu_stbc),
+ IDX_IN_WL_CNT_VER_11_T(rxundec_mcst),
+ IDX_IN_WL_CNT_VER_11_T(tkipmicfaill_mcst),
+ IDX_IN_WL_CNT_VER_11_T(tkipcntrmsr_mcst),
+ IDX_IN_WL_CNT_VER_11_T(tkipreplay_mcst),
+ IDX_IN_WL_CNT_VER_11_T(ccmpfmterr_mcst),
+ IDX_IN_WL_CNT_VER_11_T(ccmpreplay_mcst),
+ IDX_IN_WL_CNT_VER_11_T(ccmpundec_mcst),
+ IDX_IN_WL_CNT_VER_11_T(fourwayfail_mcst),
+ IDX_IN_WL_CNT_VER_11_T(wepundec_mcst),
+ IDX_IN_WL_CNT_VER_11_T(wepicverr_mcst),
+ IDX_IN_WL_CNT_VER_11_T(decsuccess_mcst),
+ IDX_IN_WL_CNT_VER_11_T(tkipicverr_mcst),
+ IDX_IN_WL_CNT_VER_11_T(wepexcluded_mcst),
+ IDX_IN_WL_CNT_VER_11_T(dma_hang),
+ IDX_IN_WL_CNT_VER_11_T(reinit),
+ IDX_IN_WL_CNT_VER_11_T(pstatxucast),
+ IDX_IN_WL_CNT_VER_11_T(pstatxnoassoc),
+ IDX_IN_WL_CNT_VER_11_T(pstarxucast),
+ IDX_IN_WL_CNT_VER_11_T(pstarxbcmc),
+ IDX_IN_WL_CNT_VER_11_T(pstatxbcmc),
+ IDX_IN_WL_CNT_VER_11_T(cso_passthrough),
+ IDX_IN_WL_CNT_VER_11_T(cso_normal),
+ IDX_IN_WL_CNT_VER_11_T(chained),
+ IDX_IN_WL_CNT_VER_11_T(chainedsz1),
+ IDX_IN_WL_CNT_VER_11_T(unchained),
+ IDX_IN_WL_CNT_VER_11_T(maxchainsz),
+ IDX_IN_WL_CNT_VER_11_T(currchainsz),
+ IDX_IN_WL_CNT_VER_11_T(pciereset),
+ IDX_IN_WL_CNT_VER_11_T(cfgrestore),
+ IDX_IN_WL_CNT_VER_11_T(reinitreason),
+ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 1,
+ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 2,
+ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 3,
+ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 4,
+ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 5,
+ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 6,
+ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 7,
+ IDX_IN_WL_CNT_VER_11_T(rxrtry),
+ IDX_IN_WL_CNT_VER_11_T(rxmpdu_mu),
+ IDX_IN_WL_CNT_VER_11_T(txbar),
+ IDX_IN_WL_CNT_VER_11_T(rxbar),
+ IDX_IN_WL_CNT_VER_11_T(txpspoll),
+ IDX_IN_WL_CNT_VER_11_T(rxpspoll),
+ IDX_IN_WL_CNT_VER_11_T(txnull),
+ IDX_IN_WL_CNT_VER_11_T(rxnull),
+ IDX_IN_WL_CNT_VER_11_T(txqosnull),
+ IDX_IN_WL_CNT_VER_11_T(rxqosnull),
+ IDX_IN_WL_CNT_VER_11_T(txassocreq),
+ IDX_IN_WL_CNT_VER_11_T(rxassocreq),
+ IDX_IN_WL_CNT_VER_11_T(txreassocreq),
+ IDX_IN_WL_CNT_VER_11_T(rxreassocreq),
+ IDX_IN_WL_CNT_VER_11_T(txdisassoc),
+ IDX_IN_WL_CNT_VER_11_T(rxdisassoc),
+ IDX_IN_WL_CNT_VER_11_T(txassocrsp),
+ IDX_IN_WL_CNT_VER_11_T(rxassocrsp),
+ IDX_IN_WL_CNT_VER_11_T(txreassocrsp),
+ IDX_IN_WL_CNT_VER_11_T(rxreassocrsp),
+ IDX_IN_WL_CNT_VER_11_T(txauth),
+ IDX_IN_WL_CNT_VER_11_T(rxauth),
+ IDX_IN_WL_CNT_VER_11_T(txdeauth),
+ IDX_IN_WL_CNT_VER_11_T(rxdeauth),
+ IDX_IN_WL_CNT_VER_11_T(txprobereq),
+ IDX_IN_WL_CNT_VER_11_T(rxprobereq),
+ IDX_IN_WL_CNT_VER_11_T(txprobersp),
+ IDX_IN_WL_CNT_VER_11_T(rxprobersp),
+ IDX_IN_WL_CNT_VER_11_T(txaction),
+ IDX_IN_WL_CNT_VER_11_T(rxaction),
+ IDX_IN_WL_CNT_VER_11_T(ampdu_wds),
+ IDX_IN_WL_CNT_VER_11_T(txlost),
+ IDX_IN_WL_CNT_VER_11_T(txdatamcast),
+ IDX_IN_WL_CNT_VER_11_T(txdatabcast)
+};
+
+/* Index conversion table from wl_cnt_ver_11_t to
+ * either wl_cnt_ge40mcst_v1_t or wl_cnt_lt40mcst_v1_t
+ */
+static const uint8 wlcntver11t_to_wlcntXX40mcstv1t[WL_CNT_MCST_VAR_NUM] = {
+ IDX_IN_WL_CNT_VER_11_T(txallfrm),
+ IDX_IN_WL_CNT_VER_11_T(txrtsfrm),
+ IDX_IN_WL_CNT_VER_11_T(txctsfrm),
+ IDX_IN_WL_CNT_VER_11_T(txackfrm),
+ IDX_IN_WL_CNT_VER_11_T(txdnlfrm),
+ IDX_IN_WL_CNT_VER_11_T(txbcnfrm),
+ IDX_IN_WL_CNT_VER_11_T(txfunfl),
+ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 1,
+ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 2,
+ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 3,
+ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 4,
+ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 5,
+ IDX_IN_WL_CNT_VER_11_T(txfbw),
+ IDX_IN_WL_CNT_VER_11_T(txmpdu),
+ IDX_IN_WL_CNT_VER_11_T(txtplunfl),
+ IDX_IN_WL_CNT_VER_11_T(txphyerror),
+ IDX_IN_WL_CNT_VER_11_T(pktengrxducast),
+ IDX_IN_WL_CNT_VER_11_T(pktengrxdmcast),
+ IDX_IN_WL_CNT_VER_11_T(rxfrmtoolong),
+ IDX_IN_WL_CNT_VER_11_T(rxfrmtooshrt),
+ IDX_IN_WL_CNT_VER_11_T(rxinvmachdr),
+ IDX_IN_WL_CNT_VER_11_T(rxbadfcs),
+ IDX_IN_WL_CNT_VER_11_T(rxbadplcp),
+ IDX_IN_WL_CNT_VER_11_T(rxcrsglitch),
+ IDX_IN_WL_CNT_VER_11_T(rxstrt),
+ IDX_IN_WL_CNT_VER_11_T(rxdfrmucastmbss),
+ IDX_IN_WL_CNT_VER_11_T(rxmfrmucastmbss),
+ IDX_IN_WL_CNT_VER_11_T(rxcfrmucast),
+ IDX_IN_WL_CNT_VER_11_T(rxrtsucast),
+ IDX_IN_WL_CNT_VER_11_T(rxctsucast),
+ IDX_IN_WL_CNT_VER_11_T(rxackucast),
+ IDX_IN_WL_CNT_VER_11_T(rxdfrmocast),
+ IDX_IN_WL_CNT_VER_11_T(rxmfrmocast),
+ IDX_IN_WL_CNT_VER_11_T(rxcfrmocast),
+ IDX_IN_WL_CNT_VER_11_T(rxrtsocast),
+ IDX_IN_WL_CNT_VER_11_T(rxctsocast),
+ IDX_IN_WL_CNT_VER_11_T(rxdfrmmcast),
+ IDX_IN_WL_CNT_VER_11_T(rxmfrmmcast),
+ IDX_IN_WL_CNT_VER_11_T(rxcfrmmcast),
+ IDX_IN_WL_CNT_VER_11_T(rxbeaconmbss),
+ IDX_IN_WL_CNT_VER_11_T(rxdfrmucastobss),
+ IDX_IN_WL_CNT_VER_11_T(rxbeaconobss),
+ IDX_IN_WL_CNT_VER_11_T(rxrsptmout),
+ IDX_IN_WL_CNT_VER_11_T(bcntxcancl),
+ IDX_IN_WL_CNT_VER_11_T(rxnodelim),
+ IDX_IN_WL_CNT_VER_11_T(rxf0ovfl),
+ IDX_IN_WL_CNT_VER_11_T(rxf1ovfl),
+ IDX_IN_WL_CNT_VER_11_T(rxf2ovfl),
+ IDX_IN_WL_CNT_VER_11_T(txsfovfl),
+ IDX_IN_WL_CNT_VER_11_T(pmqovfl),
+ IDX_IN_WL_CNT_VER_11_T(rxcgprqfrm),
+ IDX_IN_WL_CNT_VER_11_T(rxcgprsqovfl),
+ IDX_IN_WL_CNT_VER_11_T(txcgprsfail),
+ IDX_IN_WL_CNT_VER_11_T(txcgprssuc),
+ IDX_IN_WL_CNT_VER_11_T(prs_timeout),
+ IDX_IN_WL_CNT_VER_11_T(rxnack),
+ IDX_IN_WL_CNT_VER_11_T(frmscons),
+ IDX_IN_WL_CNT_VER_11_T(txnack),
+ IDX_IN_WL_CNT_VER_11_T(rxback),
+ IDX_IN_WL_CNT_VER_11_T(txback),
+ IDX_IN_WL_CNT_VER_11_T(bphy_rxcrsglitch),
+ IDX_IN_WL_CNT_VER_11_T(rxdrop20s),
+ IDX_IN_WL_CNT_VER_11_T(rxtoolate),
+ IDX_IN_WL_CNT_VER_11_T(bphy_badplcp)
+};
+
+/* For mcst offsets that were not used. (2 Pads) */
+#define INVALID_MCST_IDX ((uint8)(-1))
+/* Index conversion table from wl_cnt_ver_11_t to wl_cnt_v_le10_mcst_t */
+static const uint8 wlcntver11t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = {
+ IDX_IN_WL_CNT_VER_11_T(txallfrm),
+ IDX_IN_WL_CNT_VER_11_T(txrtsfrm),
+ IDX_IN_WL_CNT_VER_11_T(txctsfrm),
+ IDX_IN_WL_CNT_VER_11_T(txackfrm),
+ IDX_IN_WL_CNT_VER_11_T(txdnlfrm),
+ IDX_IN_WL_CNT_VER_11_T(txbcnfrm),
+ IDX_IN_WL_CNT_VER_11_T(txfunfl),
+ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 1,
+ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 2,
+ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 3,
+ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 4,
+ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 5,
+ IDX_IN_WL_CNT_VER_11_T(txfbw),
+ INVALID_MCST_IDX,
+ IDX_IN_WL_CNT_VER_11_T(txtplunfl),
+ IDX_IN_WL_CNT_VER_11_T(txphyerror),
+ IDX_IN_WL_CNT_VER_11_T(pktengrxducast),
+ IDX_IN_WL_CNT_VER_11_T(pktengrxdmcast),
+ IDX_IN_WL_CNT_VER_11_T(rxfrmtoolong),
+ IDX_IN_WL_CNT_VER_11_T(rxfrmtooshrt),
+ IDX_IN_WL_CNT_VER_11_T(rxinvmachdr),
+ IDX_IN_WL_CNT_VER_11_T(rxbadfcs),
+ IDX_IN_WL_CNT_VER_11_T(rxbadplcp),
+ IDX_IN_WL_CNT_VER_11_T(rxcrsglitch),
+ IDX_IN_WL_CNT_VER_11_T(rxstrt),
+ IDX_IN_WL_CNT_VER_11_T(rxdfrmucastmbss),
+ IDX_IN_WL_CNT_VER_11_T(rxmfrmucastmbss),
+ IDX_IN_WL_CNT_VER_11_T(rxcfrmucast),
+ IDX_IN_WL_CNT_VER_11_T(rxrtsucast),
+ IDX_IN_WL_CNT_VER_11_T(rxctsucast),
+ IDX_IN_WL_CNT_VER_11_T(rxackucast),
+ IDX_IN_WL_CNT_VER_11_T(rxdfrmocast),
+ IDX_IN_WL_CNT_VER_11_T(rxmfrmocast),
+ IDX_IN_WL_CNT_VER_11_T(rxcfrmocast),
+ IDX_IN_WL_CNT_VER_11_T(rxrtsocast),
+ IDX_IN_WL_CNT_VER_11_T(rxctsocast),
+ IDX_IN_WL_CNT_VER_11_T(rxdfrmmcast),
+ IDX_IN_WL_CNT_VER_11_T(rxmfrmmcast),
+ IDX_IN_WL_CNT_VER_11_T(rxcfrmmcast),
+ IDX_IN_WL_CNT_VER_11_T(rxbeaconmbss),
+ IDX_IN_WL_CNT_VER_11_T(rxdfrmucastobss),
+ IDX_IN_WL_CNT_VER_11_T(rxbeaconobss),
+ IDX_IN_WL_CNT_VER_11_T(rxrsptmout),
+ IDX_IN_WL_CNT_VER_11_T(bcntxcancl),
+ INVALID_MCST_IDX,
+ IDX_IN_WL_CNT_VER_11_T(rxf0ovfl),
+ IDX_IN_WL_CNT_VER_11_T(rxf1ovfl),
+ IDX_IN_WL_CNT_VER_11_T(rxf2ovfl),
+ IDX_IN_WL_CNT_VER_11_T(txsfovfl),
+ IDX_IN_WL_CNT_VER_11_T(pmqovfl),
+ IDX_IN_WL_CNT_VER_11_T(rxcgprqfrm),
+ IDX_IN_WL_CNT_VER_11_T(rxcgprsqovfl),
+ IDX_IN_WL_CNT_VER_11_T(txcgprsfail),
+ IDX_IN_WL_CNT_VER_11_T(txcgprssuc),
+ IDX_IN_WL_CNT_VER_11_T(prs_timeout),
+ IDX_IN_WL_CNT_VER_11_T(rxnack),
+ IDX_IN_WL_CNT_VER_11_T(frmscons),
+ IDX_IN_WL_CNT_VER_11_T(txnack),
+ IDX_IN_WL_CNT_VER_11_T(rxback),
+ IDX_IN_WL_CNT_VER_11_T(txback),
+ IDX_IN_WL_CNT_VER_11_T(bphy_rxcrsglitch),
+ IDX_IN_WL_CNT_VER_11_T(rxdrop20s),
+ IDX_IN_WL_CNT_VER_11_T(rxtoolate),
+ IDX_IN_WL_CNT_VER_11_T(bphy_badplcp)
+};
+
+/* Index conversion table from wl_cnt_ver_7_t to wl_cnt_v_le10_mcst_t */
+static const uint8 wlcntver7t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = {
+ IDX_IN_WL_CNT_VER_7_T(txallfrm),
+ IDX_IN_WL_CNT_VER_7_T(txrtsfrm),
+ IDX_IN_WL_CNT_VER_7_T(txctsfrm),
+ IDX_IN_WL_CNT_VER_7_T(txackfrm),
+ IDX_IN_WL_CNT_VER_7_T(txdnlfrm),
+ IDX_IN_WL_CNT_VER_7_T(txbcnfrm),
+ IDX_IN_WL_CNT_VER_7_T(txfunfl),
+ IDX_IN_WL_CNT_VER_7_T(txfunfl) + 1,
+ IDX_IN_WL_CNT_VER_7_T(txfunfl) + 2,
+ IDX_IN_WL_CNT_VER_7_T(txfunfl) + 3,
+ IDX_IN_WL_CNT_VER_7_T(txfunfl) + 4,
+ IDX_IN_WL_CNT_VER_7_T(txfunfl) + 5,
+ INVALID_MCST_IDX,
+ INVALID_MCST_IDX,
+ IDX_IN_WL_CNT_VER_7_T(txtplunfl),
+ IDX_IN_WL_CNT_VER_7_T(txphyerror),
+ IDX_IN_WL_CNT_VER_7_T(pktengrxducast),
+ IDX_IN_WL_CNT_VER_7_T(pktengrxdmcast),
+ IDX_IN_WL_CNT_VER_7_T(rxfrmtoolong),
+ IDX_IN_WL_CNT_VER_7_T(rxfrmtooshrt),
+ IDX_IN_WL_CNT_VER_7_T(rxinvmachdr),
+ IDX_IN_WL_CNT_VER_7_T(rxbadfcs),
+ IDX_IN_WL_CNT_VER_7_T(rxbadplcp),
+ IDX_IN_WL_CNT_VER_7_T(rxcrsglitch),
+ IDX_IN_WL_CNT_VER_7_T(rxstrt),
+ IDX_IN_WL_CNT_VER_7_T(rxdfrmucastmbss),
+ IDX_IN_WL_CNT_VER_7_T(rxmfrmucastmbss),
+ IDX_IN_WL_CNT_VER_7_T(rxcfrmucast),
+ IDX_IN_WL_CNT_VER_7_T(rxrtsucast),
+ IDX_IN_WL_CNT_VER_7_T(rxctsucast),
+ IDX_IN_WL_CNT_VER_7_T(rxackucast),
+ IDX_IN_WL_CNT_VER_7_T(rxdfrmocast),
+ IDX_IN_WL_CNT_VER_7_T(rxmfrmocast),
+ IDX_IN_WL_CNT_VER_7_T(rxcfrmocast),
+ IDX_IN_WL_CNT_VER_7_T(rxrtsocast),
+ IDX_IN_WL_CNT_VER_7_T(rxctsocast),
+ IDX_IN_WL_CNT_VER_7_T(rxdfrmmcast),
+ IDX_IN_WL_CNT_VER_7_T(rxmfrmmcast),
+ IDX_IN_WL_CNT_VER_7_T(rxcfrmmcast),
+ IDX_IN_WL_CNT_VER_7_T(rxbeaconmbss),
+ IDX_IN_WL_CNT_VER_7_T(rxdfrmucastobss),
+ IDX_IN_WL_CNT_VER_7_T(rxbeaconobss),
+ IDX_IN_WL_CNT_VER_7_T(rxrsptmout),
+ IDX_IN_WL_CNT_VER_7_T(bcntxcancl),
+ INVALID_MCST_IDX,
+ IDX_IN_WL_CNT_VER_7_T(rxf0ovfl),
+ IDX_IN_WL_CNT_VER_7_T(rxf1ovfl),
+ IDX_IN_WL_CNT_VER_7_T(rxf2ovfl),
+ IDX_IN_WL_CNT_VER_7_T(txsfovfl),
+ IDX_IN_WL_CNT_VER_7_T(pmqovfl),
+ IDX_IN_WL_CNT_VER_7_T(rxcgprqfrm),
+ IDX_IN_WL_CNT_VER_7_T(rxcgprsqovfl),
+ IDX_IN_WL_CNT_VER_7_T(txcgprsfail),
+ IDX_IN_WL_CNT_VER_7_T(txcgprssuc),
+ IDX_IN_WL_CNT_VER_7_T(prs_timeout),
+ IDX_IN_WL_CNT_VER_7_T(rxnack),
+ IDX_IN_WL_CNT_VER_7_T(frmscons),
+ IDX_IN_WL_CNT_VER_7_T(txnack),
+ INVALID_MCST_IDX,
+ INVALID_MCST_IDX,
+ IDX_IN_WL_CNT_VER_7_T(bphy_rxcrsglitch),
+ INVALID_MCST_IDX,
+ INVALID_MCST_IDX,
+ INVALID_MCST_IDX
+};
+
+/* Index conversion table from wl_cnt_ver_6_t to wl_cnt_v_le10_mcst_t */
+static const uint8 wlcntver6t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = {
+ IDX_IN_WL_CNT_VER_6_T(txallfrm),
+ IDX_IN_WL_CNT_VER_6_T(txrtsfrm),
+ IDX_IN_WL_CNT_VER_6_T(txctsfrm),
+ IDX_IN_WL_CNT_VER_6_T(txackfrm),
+ IDX_IN_WL_CNT_VER_6_T(txdnlfrm),
+ IDX_IN_WL_CNT_VER_6_T(txbcnfrm),
+ IDX_IN_WL_CNT_VER_6_T(txfunfl),
+ IDX_IN_WL_CNT_VER_6_T(txfunfl) + 1,
+ IDX_IN_WL_CNT_VER_6_T(txfunfl) + 2,
+ IDX_IN_WL_CNT_VER_6_T(txfunfl) + 3,
+ IDX_IN_WL_CNT_VER_6_T(txfunfl) + 4,
+ IDX_IN_WL_CNT_VER_6_T(txfunfl) + 5,
+ IDX_IN_WL_CNT_VER_6_T(txfbw),
+ INVALID_MCST_IDX,
+ IDX_IN_WL_CNT_VER_6_T(txtplunfl),
+ IDX_IN_WL_CNT_VER_6_T(txphyerror),
+ IDX_IN_WL_CNT_VER_6_T(pktengrxducast),
+ IDX_IN_WL_CNT_VER_6_T(pktengrxdmcast),
+ IDX_IN_WL_CNT_VER_6_T(rxfrmtoolong),
+ IDX_IN_WL_CNT_VER_6_T(rxfrmtooshrt),
+ IDX_IN_WL_CNT_VER_6_T(rxinvmachdr),
+ IDX_IN_WL_CNT_VER_6_T(rxbadfcs),
+ IDX_IN_WL_CNT_VER_6_T(rxbadplcp),
+ IDX_IN_WL_CNT_VER_6_T(rxcrsglitch),
+ IDX_IN_WL_CNT_VER_6_T(rxstrt),
+ IDX_IN_WL_CNT_VER_6_T(rxdfrmucastmbss),
+ IDX_IN_WL_CNT_VER_6_T(rxmfrmucastmbss),
+ IDX_IN_WL_CNT_VER_6_T(rxcfrmucast),
+ IDX_IN_WL_CNT_VER_6_T(rxrtsucast),
+ IDX_IN_WL_CNT_VER_6_T(rxctsucast),
+ IDX_IN_WL_CNT_VER_6_T(rxackucast),
+ IDX_IN_WL_CNT_VER_6_T(rxdfrmocast),
+ IDX_IN_WL_CNT_VER_6_T(rxmfrmocast),
+ IDX_IN_WL_CNT_VER_6_T(rxcfrmocast),
+ IDX_IN_WL_CNT_VER_6_T(rxrtsocast),
+ IDX_IN_WL_CNT_VER_6_T(rxctsocast),
+ IDX_IN_WL_CNT_VER_6_T(rxdfrmmcast),
+ IDX_IN_WL_CNT_VER_6_T(rxmfrmmcast),
+ IDX_IN_WL_CNT_VER_6_T(rxcfrmmcast),
+ IDX_IN_WL_CNT_VER_6_T(rxbeaconmbss),
+ IDX_IN_WL_CNT_VER_6_T(rxdfrmucastobss),
+ IDX_IN_WL_CNT_VER_6_T(rxbeaconobss),
+ IDX_IN_WL_CNT_VER_6_T(rxrsptmout),
+ IDX_IN_WL_CNT_VER_6_T(bcntxcancl),
+ INVALID_MCST_IDX,
+ IDX_IN_WL_CNT_VER_6_T(rxf0ovfl),
+ IDX_IN_WL_CNT_VER_6_T(rxf1ovfl),
+ IDX_IN_WL_CNT_VER_6_T(rxf2ovfl),
+ IDX_IN_WL_CNT_VER_6_T(txsfovfl),
+ IDX_IN_WL_CNT_VER_6_T(pmqovfl),
+ IDX_IN_WL_CNT_VER_6_T(rxcgprqfrm),
+ IDX_IN_WL_CNT_VER_6_T(rxcgprsqovfl),
+ IDX_IN_WL_CNT_VER_6_T(txcgprsfail),
+ IDX_IN_WL_CNT_VER_6_T(txcgprssuc),
+ IDX_IN_WL_CNT_VER_6_T(prs_timeout),
+ IDX_IN_WL_CNT_VER_6_T(rxnack),
+ IDX_IN_WL_CNT_VER_6_T(frmscons),
+ IDX_IN_WL_CNT_VER_6_T(txnack),
+ IDX_IN_WL_CNT_VER_6_T(rxback),
+ IDX_IN_WL_CNT_VER_6_T(txback),
+ IDX_IN_WL_CNT_VER_6_T(bphy_rxcrsglitch),
+ IDX_IN_WL_CNT_VER_6_T(rxdrop20s),
+ IDX_IN_WL_CNT_VER_6_T(rxtoolate),
+ IDX_IN_WL_CNT_VER_6_T(bphy_badplcp)
+};
+
+/* copy wlc layer counters from old type cntbuf to wl_cnt_wlc_t type. */
+static int
+wl_copy_wlccnt(uint16 cntver, uint32 *dst, uint32 *src, uint8 src_max_idx)
+{
+ uint i;
+ if (dst == NULL || src == NULL) {
+ return BCME_ERROR;
+ }
+
+ /* Init wlccnt with invalid value. Unchanged value will not be printed out */
+ for (i = 0; i < (sizeof(wl_cnt_wlc_t) / sizeof(uint32)); i++) {
+ dst[i] = INVALID_CNT_VAL;
+ }
+
+ if (cntver == WL_CNT_VERSION_6) {
+ for (i = 0; i < NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T; i++) {
+ if (wlcntver6t_to_wlcntwlct[i] >= src_max_idx) {
+ /* src buffer does not have counters from here */
+ break;
+ }
+ dst[i] = src[wlcntver6t_to_wlcntwlct[i]];
+ }
+ } else if (cntver == WL_CNT_VERSION_7 || cntver == WL_CNT_VERSION_7001) {
+ for (i = 0; i < NUM_OF_WLCCNT_IN_WL_CNT_VER_7_T; i++) {
+ if (wlcntver7t_to_wlcntwlct[i] >= src_max_idx) {
+ /* src buffer does not have counters from here */
+ break;
+ }
+ dst[i] = src[wlcntver7t_to_wlcntwlct[i]];
+ }
+ } else {
+ for (i = 0; i < NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T; i++) {
+ if (wlcntver11t_to_wlcntwlct[i] >= src_max_idx) {
+ /* src buffer does not have counters from here */
+ break;
+ }
+ dst[i] = src[wlcntver11t_to_wlcntwlct[i]];
+ }
+ }
+ return BCME_OK;
+}
+
+/* copy macstat counters from old type cntbuf to wl_cnt_v_le10_mcst_t type. */
+static int
+wl_copy_macstat_upto_ver10(uint16 cntver, uint32 *dst, uint32 *src)
+{
+ uint i;
+
+ if (dst == NULL || src == NULL) {
+ return BCME_ERROR;
+ }
+
+ if (cntver == WL_CNT_VERSION_7 || cntver == WL_CNT_VERSION_7001) {
+ for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) {
+ if (wlcntver7t_to_wlcntvle10mcstt[i] == INVALID_MCST_IDX) {
+ /* This mcst counter does not exist in wl_cnt_ver_7_t */
+ dst[i] = INVALID_CNT_VAL;
+ } else {
+ dst[i] = src[wlcntver7t_to_wlcntvle10mcstt[i]];
+ }
+ }
+ } else if (cntver == WL_CNT_VERSION_6) {
+ for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) {
+ if (wlcntver6t_to_wlcntvle10mcstt[i] == INVALID_MCST_IDX) {
+ /* This mcst counter does not exist in wl_cnt_ver_6_t */
+ dst[i] = INVALID_CNT_VAL;
+ } else {
+ dst[i] = src[wlcntver6t_to_wlcntvle10mcstt[i]];
+ }
+ }
+ } else {
+ for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) {
+ if (wlcntver11t_to_wlcntvle10mcstt[i] == INVALID_MCST_IDX) {
+ /* This mcst counter does not exist in wl_cnt_ver_11_t */
+ dst[i] = INVALID_CNT_VAL;
+ } else {
+ dst[i] = src[wlcntver11t_to_wlcntvle10mcstt[i]];
+ }
+ }
+ }
+ return BCME_OK;
+}
+
+static int
+wl_copy_macstat_ver11(uint32 *dst, uint32 *src)
+{
+ uint i;
+
+ if (dst == NULL || src == NULL) {
+ return BCME_ERROR;
+ }
+
+ for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) {
+ dst[i] = src[wlcntver11t_to_wlcntXX40mcstv1t[i]];
+ }
+ return BCME_OK;
+}
+
+/**
+ * Translate non-xtlv 'wl counters' IOVar buffer received by old driver/FW to xtlv format.
+ * Parameters:
+ * cntbuf: pointer to non-xtlv 'wl counters' IOVar buffer received by old driver/FW.
+ * Newly translated xtlv format is written to this pointer.
+ * buflen: length of the "cntbuf" without any padding.
+ * corerev: chip core revision of the driver/FW.
+ */
+int
+wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf, int buflen, uint32 corerev)
+{
+ wl_cnt_wlc_t *wlccnt = NULL;
+ uint32 *macstat = NULL;
+ xtlv_desc_t xtlv_desc[3];
+ uint16 mcst_xtlv_id;
+ int res = BCME_OK;
+ wl_cnt_info_t *cntinfo = cntbuf;
+ uint8 *xtlvbuf_p = cntinfo->data;
+ uint16 ver = cntinfo->version;
+ uint16 xtlvbuflen = (uint16)buflen;
+ uint16 src_max_idx;
+#ifdef BCMDRIVER
+ osl_t *osh = ctx;
+#else
+ BCM_REFERENCE(ctx);
+#endif
+
+ if (ver >= WL_CNT_VERSION_XTLV && ver != WL_CNT_VERSION_7001) {
+ /* Already in xtlv format. */
+ goto exit;
+ }
+
+#ifdef BCMDRIVER
+ wlccnt = MALLOC(osh, sizeof(*wlccnt));
+ macstat = MALLOC(osh, WL_CNT_MCST_STRUCT_SZ);
+#else
+ wlccnt = (wl_cnt_wlc_t *)malloc(sizeof(*wlccnt));
+ macstat = (uint32 *)malloc(WL_CNT_MCST_STRUCT_SZ);
+#endif
+ if (!wlccnt || !macstat) {
+ printf("%s: malloc fail!\n", __FUNCTION__);
+ res = BCME_NOMEM;
+ goto exit;
+ }
+
+ /* Check if the max idx in the struct exceeds the boundary of uint8 */
+ if (NUM_OF_CNT_IN_WL_CNT_VER_6_T > ((uint8)(-1) + 1) ||
+ NUM_OF_CNT_IN_WL_CNT_VER_7_T > ((uint8)(-1) + 1) ||
+ NUM_OF_CNT_IN_WL_CNT_VER_11_T > ((uint8)(-1) + 1)) {
+ printf("wlcntverXXt_to_wlcntwlct and src_max_idx need"
+ " to be of uint16 instead of uint8\n");
+ res = BCME_ERROR;
+ goto exit;
+ }
+
+ /* Exclude version and length fields in either wlc_cnt_ver_6_t or wlc_cnt_ver_11_t */
+ src_max_idx = (cntinfo->datalen - OFFSETOF(wl_cnt_info_t, data)) / sizeof(uint32);
+ if (src_max_idx > (uint8)(-1)) {
+ printf("wlcntverXXt_to_wlcntwlct and src_max_idx need"
+ " to be of uint16 instead of uint8\n"
+ "Try updating wl utility to the latest.\n");
+ src_max_idx = (uint8)(-1);
+ }
+
+ /* Copy wlc layer counters to wl_cnt_wlc_t */
+ res = wl_copy_wlccnt(ver, (uint32 *)wlccnt, (uint32 *)cntinfo->data, (uint8)src_max_idx);
+ if (res != BCME_OK) {
+ printf("wl_copy_wlccnt fail!\n");
+ goto exit;
+ }
+
+ /* Copy macstat counters to wl_cnt_wlc_t */
+ if (ver == WL_CNT_VERSION_11) {
+ res = wl_copy_macstat_ver11(macstat, (uint32 *)cntinfo->data);
+ if (res != BCME_OK) {
+ printf("wl_copy_macstat_ver11 fail!\n");
+ goto exit;
+ }
+ if (corerev >= 40) {
+ mcst_xtlv_id = WL_CNT_XTLV_GE40_UCODE_V1;
+ } else {
+ mcst_xtlv_id = WL_CNT_XTLV_LT40_UCODE_V1;
+ }
+ } else {
+ res = wl_copy_macstat_upto_ver10(ver, macstat, (uint32 *)cntinfo->data);
+ if (res != BCME_OK) {
+ printf("wl_copy_macstat_upto_ver10 fail!\n");
+ goto exit;
+ }
+ mcst_xtlv_id = WL_CNT_XTLV_CNTV_LE10_UCODE;
+ }
+
+ xtlv_desc[0].type = WL_CNT_XTLV_WLC;
+ xtlv_desc[0].len = sizeof(*wlccnt);
+ xtlv_desc[0].ptr = wlccnt;
+
+ xtlv_desc[1].type = mcst_xtlv_id;
+ xtlv_desc[1].len = WL_CNT_MCST_STRUCT_SZ;
+ xtlv_desc[1].ptr = macstat;
+
+ xtlv_desc[2].type = 0;
+ xtlv_desc[2].len = 0;
+ xtlv_desc[2].ptr = NULL;
+
+ memset(cntbuf, 0, buflen);
+
+ res = bcm_pack_xtlv_buf_from_mem(&xtlvbuf_p, &xtlvbuflen,
+ xtlv_desc, BCM_XTLV_OPTION_ALIGN32);
+ cntinfo->datalen = (buflen - xtlvbuflen);
+exit:
+#ifdef BCMDRIVER
+ if (wlccnt) {
+ MFREE(osh, wlccnt, sizeof(*wlccnt));
+ }
+ if (macstat) {
+ MFREE(osh, macstat, WL_CNT_MCST_STRUCT_SZ);
+ }
+#else
+ if (wlccnt) {
+ free(wlccnt);
+ }
+ if (macstat) {
+ free(macstat);
+ }
+#endif
+ return res;
+}
diff --git a/wl/src/shared/bcmbloom.c b/wl/src/shared/bcmbloom.c
new file mode 100644
index 0000000..51425e1
--- /dev/null
+++ b/wl/src/shared/bcmbloom.c
@@ -0,0 +1,230 @@
+/*
+ * Bloom filter support
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: bcmbloom.c 525587 2015-01-10 05:24:58Z $
+ */
+
+
+#include <typedefs.h>
+#include <bcmdefs.h>
+
+#if defined(__FreeBSD__)
+#include <machine/stdarg.h>
+#else
+#include <stdarg.h>
+#endif /* __FreeBSD__ */
+
+#ifdef BCMDRIVER
+#include <osl.h>
+#include <bcmutils.h>
+#else /* !BCMDRIVER */
+#include <stdio.h>
+#include <string.h>
+#ifndef ASSERT
+#define ASSERT(exp)
+#endif
+#endif /* !BCMDRIVER */
+#include <bcmutils.h>
+
+#include <bcmbloom.h>
+
+#define BLOOM_BIT_LEN(_x) ((_x) << 3)
+
+struct bcm_bloom_filter {
+ void *cb_ctx;
+ uint max_hash;
+ bcm_bloom_hash_t *hash; /* array of hash functions */
+ uint filter_size; /* in bytes */
+ uint8 *filter; /* can be NULL for validate only */
+};
+
+/* public interface */
+int
+bcm_bloom_create(bcm_bloom_alloc_t alloc_cb,
+ bcm_bloom_free_t free_cb, void *cb_ctx, uint max_hash,
+ uint filter_size, bcm_bloom_filter_t **bloom)
+{
+ int err = BCME_OK;
+ bcm_bloom_filter_t *bp = NULL;
+
+ if (!bloom || !alloc_cb || (max_hash == 0)) {
+ err = BCME_BADARG;
+ goto done;
+ }
+
+ bp = (*alloc_cb)(cb_ctx, sizeof(*bp));
+ if (!bp) {
+ err = BCME_NOMEM;
+ goto done;
+ }
+
+ memset(bp, 0, sizeof(*bp));
+ bp->cb_ctx = cb_ctx;
+ bp->max_hash = max_hash;
+ bp->hash = (*alloc_cb)(cb_ctx, sizeof(*bp->hash) * max_hash);
+ if (!bp->hash) {
+ err = BCME_NOMEM;
+ goto done;
+ }
+
+ if (filter_size > 0) {
+ bp->filter = (*alloc_cb)(cb_ctx, filter_size);
+ if (!bp->filter) {
+ err = BCME_NOMEM;
+ goto done;
+ }
+ bp->filter_size = filter_size;
+ memset(bp->filter, 0, filter_size);
+ }
+
+ *bloom = bp;
+
+done:
+ if (err != BCME_OK)
+ bcm_bloom_destroy(&bp, free_cb);
+
+ return err;
+}
+
+int
+bcm_bloom_destroy(bcm_bloom_filter_t **bloom, bcm_bloom_free_t free_cb)
+{
+ int err = BCME_OK;
+ bcm_bloom_filter_t *bp;
+
+ if (!bloom || !*bloom || !free_cb)
+ goto done;
+
+ bp = *bloom;
+ *bloom = NULL;
+
+ if (bp->filter)
+ (*free_cb)(bp->cb_ctx, bp->filter, bp->filter_size);
+ if (bp->hash)
+ (*free_cb)(bp->cb_ctx, bp->hash,
+ sizeof(*bp->hash) * bp->max_hash);
+ (*free_cb)(bp->cb_ctx, bp, sizeof(*bp));
+
+done:
+ return err;
+}
+
+int
+bcm_bloom_add_hash(bcm_bloom_filter_t *bp, bcm_bloom_hash_t hash, uint *idx)
+{
+ uint i;
+
+ if (!bp || !hash || !idx)
+ return BCME_BADARG;
+
+ for (i = 0; i < bp->max_hash; ++i) {
+ if (bp->hash[i] == NULL)
+ break;
+ }
+
+ if (i >= bp->max_hash)
+ return BCME_NORESOURCE;
+
+ bp->hash[i] = hash;
+ *idx = i;
+ return BCME_OK;
+}
+
+int
+bcm_bloom_remove_hash(bcm_bloom_filter_t *bp, uint idx)
+{
+ if (!bp)
+ return BCME_BADARG;
+
+ if (idx >= bp->max_hash)
+ return BCME_NOTFOUND;
+
+ bp->hash[idx] = NULL;
+ return BCME_OK;
+}
+
+bool
+bcm_bloom_is_member(bcm_bloom_filter_t *bp,
+ const uint8 *tag, uint tag_len, const uint8 *buf, uint buf_len)
+{
+ uint i;
+ int err = BCME_OK;
+
+ if (!tag || (tag_len == 0)) /* empty tag is always a member */
+ goto done;
+
+ /* use internal buffer if none was specified */
+ if (!buf || (buf_len == 0)) {
+ if (!bp->filter) /* every one is a member of empty filter */
+ goto done;
+
+ buf = bp->filter;
+ buf_len = bp->filter_size;
+ }
+
+ for (i = 0; i < bp->max_hash; ++i) {
+ uint pos;
+ if (!bp->hash[i])
+ continue;
+ pos = (*bp->hash[i])(bp->cb_ctx, i, tag, tag_len);
+
+ /* all bits must be set for a match */
+ if (isclr(buf, pos % BLOOM_BIT_LEN(buf_len))) {
+ err = BCME_NOTFOUND;
+ break;
+ }
+ }
+
+done:
+ return err;
+}
+
+int
+bcm_bloom_add_member(bcm_bloom_filter_t *bp, const uint8 *tag, uint tag_len)
+{
+ uint i;
+
+ if (!bp || !tag || (tag_len == 0))
+ return BCME_BADARG;
+
+ if (!bp->filter) /* validate only */
+ return BCME_UNSUPPORTED;
+
+ for (i = 0; i < bp->max_hash; ++i) {
+ uint pos;
+ if (!bp->hash[i])
+ continue;
+ pos = (*bp->hash[i])(bp->cb_ctx, i, tag, tag_len);
+ setbit(bp->filter, pos % BLOOM_BIT_LEN(bp->filter_size));
+ }
+
+ return BCME_OK;
+}
+
+int bcm_bloom_get_filter_data(bcm_bloom_filter_t *bp,
+ uint buf_size, uint8 *buf, uint *buf_len)
+{
+ if (!bp)
+ return BCME_BADARG;
+
+ if (buf_len)
+ *buf_len = bp->filter_size;
+
+ if (buf_size < bp->filter_size)
+ return BCME_BUFTOOSHORT;
+
+ if (bp->filter && bp->filter_size)
+ memcpy(buf, bp->filter, bp->filter_size);
+
+ return BCME_OK;
+}
diff --git a/wl/src/shared/bcmutils.c b/wl/src/shared/bcmutils.c
new file mode 100644
index 0000000..ac05dd7
--- /dev/null
+++ b/wl/src/shared/bcmutils.c
@@ -0,0 +1,5217 @@
+/*
+ * Driver O/S-independent utility routines
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmutils.c 661946 2016-09-27 21:47:25Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#if defined(__FreeBSD__)
+#include <machine/stdarg.h>
+#include <stdbool.h>
+#else
+#include <stdarg.h>
+#endif
+#ifdef BCMDRIVER
+
+#include <osl.h>
+#include <bcmutils.h>
+#if !defined(BCMDONGLEHOST) || defined(BCMNVRAM)
+#include <siutils.h>
+#include <bcmnvram.h>
+#endif
+
+#else /* !BCMDRIVER */
+
+#include <stdio.h>
+#include <string.h>
+#include <bcmutils.h>
+
+#if defined(BCMEXTSUP)
+#include <bcm_osl.h>
+#endif
+
+#ifndef ASSERT
+#define ASSERT(exp)
+#endif
+
+#endif /* !BCMDRIVER */
+
+#if defined(_WIN32)
+/* Debatable */
+#include <bcmstdlib.h>
+#endif
+#include <bcmendian.h>
+#include <bcmdevs.h>
+#include <proto/ethernet.h>
+#include <proto/vlan.h>
+#include <proto/bcmip.h>
+#include <proto/802.1d.h>
+#include <proto/802.11.h>
+#include <proto/bcmip.h>
+#include <proto/bcmipv6.h>
+#include <proto/bcmtcp.h>
+#ifdef BCMPERFSTATS
+#include <bcmperf.h>
+#endif
+
+
+#ifdef CUSTOM_DSCP_TO_PRIO_MAPPING
+#define CUST_IPV4_TOS_PREC_MASK 0x3F
+#define DCSP_MAX_VALUE 64
+extern uint dhd_dscpmap_enable;
+/* 0:BE,1:BK,2:RESV(BK):,3:EE,:4:CL,5:VI,6:VO,7:NC */
+int dscp2priomap[DCSP_MAX_VALUE]=
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* BK->BE */
+ 2, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 0, 0, 0,
+ 6, 0, 0, 0, 0, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0
+};
+#endif /* CUSTOM_DSCP_TO_PRIO_MAPPING */
+
+
+#ifdef BCMDRIVER
+
+#if !defined(BCMDONGLEHOST)
+/* Forward declarations */
+char * getvar_internal(char *vars, const char *name);
+int getintvar_internal(char *vars, const char *name);
+int getintvararray_internal(char *vars, const char *name, int index);
+int getintvararraysize_internal(char *vars, const char *name);
+
+/* nvram vars cache */
+static char *nvram_vars = NULL;
+static int vars_len = -1;
+
+/*
+ * Search the name=value vars for a specific one and return its value.
+ * Returns NULL if not found.
+ */
+char *
+getvar(char *vars, const char *name)
+{
+ NVRAM_RECLAIM_CHECK(name);
+ return getvar_internal(vars, name);
+}
+
+char *
+getvar_internal(char *vars, const char *name)
+{
+ char *s;
+ int len;
+
+ if (!name)
+ return NULL;
+
+ len = strlen(name);
+ if (len == 0)
+ return NULL;
+
+ /* first look in vars[] */
+ for (s = vars; s && *s;) {
+ if ((bcmp(s, name, len) == 0) && (s[len] == '=')) {
+ return (&s[len+1]);
+ }
+ while (*s++)
+ ;
+ }
+
+ /* then query nvram */
+ return (nvram_get(name));
+}
+
+/*
+ * Search the vars for a specific one and return its value as
+ * an integer. Returns 0 if not found.
+ */
+int
+getintvar(char *vars, const char *name)
+{
+ NVRAM_RECLAIM_CHECK(name);
+ return getintvar_internal(vars, name);
+}
+
+int
+getintvar_internal(char *vars, const char *name)
+{
+ char *val;
+
+ if ((val = getvar_internal(vars, name)) == NULL)
+ return (0);
+
+ return (bcm_strtoul(val, NULL, 0));
+}
+
+int
+getintvararray(char *vars, const char *name, int index)
+{
+ NVRAM_RECLAIM_CHECK(name);
+ return getintvararray_internal(vars, name, index);
+}
+
+int
+getintvararray_internal(char *vars, const char *name, int index)
+{
+ char *buf, *endp;
+ int i = 0;
+ int val = 0;
+
+ if ((buf = getvar_internal(vars, name)) == NULL) {
+ return (0);
+ }
+
+ /* table values are always separated by "," or " " */
+ while (*buf != '\0') {
+ val = bcm_strtoul(buf, &endp, 0);
+ if (i == index) {
+ return val;
+ }
+ buf = endp;
+ /* delimiter is ',' */
+ if (*buf == ',')
+ buf++;
+ i++;
+ }
+ return (0);
+}
+
+int
+getintvararraysize(char *vars, const char *name)
+{
+ NVRAM_RECLAIM_CHECK(name);
+ return getintvararraysize_internal(vars, name);
+}
+
+int
+getintvararraysize_internal(char *vars, const char *name)
+{
+ char *buf, *endp;
+ int count = 0;
+ int val = 0;
+
+ if ((buf = getvar_internal(vars, name)) == NULL) {
+ return (0);
+ }
+
+ /* table values are always separated by "," or " " */
+ while (*buf != '\0') {
+ val = bcm_strtoul(buf, &endp, 0);
+ buf = endp;
+ /* delimiter is ',' */
+ if (*buf == ',')
+ buf++;
+ count++;
+ }
+ BCM_REFERENCE(val);
+ return count;
+}
+
+/* Search for token in comma separated token-string */
+static int
+findmatch(const char *string, const char *name)
+{
+ uint len;
+ char *c;
+
+ len = strlen(name);
+ while ((c = strchr(string, ',')) != NULL) {
+ if (len == (uint)(c - string) && !strncmp(string, name, len))
+ return 1;
+ string = c + 1;
+ }
+
+ return (!strcmp(string, name));
+}
+
+/* Return gpio pin number assigned to the named pin
+ *
+ * Variable should be in format:
+ *
+ * gpio<N>=pin_name,pin_name
+ *
+ * This format allows multiple features to share the gpio with mutual
+ * understanding.
+ *
+ * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
+ * and if def_pin is not used by others.
+ */
+uint
+getgpiopin(char *vars, char *pin_name, uint def_pin)
+{
+ char name[] = "gpioXXXX";
+ char *val;
+ uint pin;
+
+ /* Go thru all possibilities till a match in pin name */
+ for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
+ snprintf(name, sizeof(name), "gpio%d", pin);
+ val = getvar(vars, name);
+ if (val && findmatch(val, pin_name))
+ return pin;
+ }
+
+ if (def_pin != GPIO_PIN_NOTDEFINED) {
+ /* make sure the default pin is not used by someone else */
+ snprintf(name, sizeof(name), "gpio%d", def_pin);
+ if (getvar(vars, name)) {
+ def_pin = GPIO_PIN_NOTDEFINED;
+ }
+ }
+ return def_pin;
+}
+
+static void
+BCMATTACHFN(bcm_nvram_refresh)(char *flash)
+{
+ int i;
+ int ret = 0;
+
+ ASSERT(flash != NULL);
+
+ /* default "empty" vars cache */
+ bzero(flash, 2);
+
+ if ((ret = nvram_getall(flash, MAX_NVRAM_SPACE)))
+ return;
+
+ /* determine nvram length */
+ for (i = 0; i < MAX_NVRAM_SPACE; i++) {
+ if (flash[i] == '\0' && flash[i+1] == '\0')
+ break;
+ }
+
+ if (i > 1)
+ vars_len = i + 2;
+ else
+ vars_len = 0;
+}
+
+char *
+BCMATTACHFN(bcm_nvram_vars)(uint *length)
+{
+#ifndef BCMNVRAMR
+ /* cache may be stale if nvram is read/write */
+ if (nvram_vars) {
+ ASSERT(!bcm_reclaimed);
+ bcm_nvram_refresh(nvram_vars);
+ }
+#endif
+ if (length)
+ *length = vars_len;
+ return nvram_vars;
+}
+
+/* copy nvram vars into locally-allocated multi-string array */
+int
+BCMATTACHFN(bcm_nvram_cache)(void *sih)
+{
+ int ret = 0;
+ void *osh;
+ char *flash = NULL;
+
+ if (vars_len >= 0) {
+#ifndef BCMNVRAMR
+ bcm_nvram_refresh(nvram_vars);
+#endif
+ return 0;
+ }
+
+ osh = si_osh((si_t *)sih);
+
+ /* allocate memory and read in flash */
+ /* freed in same function */
+ if (!(flash = MALLOC_NOPERSIST(osh, MAX_NVRAM_SPACE))) {
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ bcm_nvram_refresh(flash);
+
+#ifdef BCMNVRAMR
+ if (vars_len > 3) {
+ /* freed on nvram_exit */
+ /* copy into a properly-sized buffer */
+ if (!(nvram_vars = MALLOC_NOPERSIST(osh, vars_len))) {
+ ret = BCME_NOMEM;
+ } else
+ bcopy(flash, nvram_vars, vars_len);
+ }
+ MFREE(osh, flash, MAX_NVRAM_SPACE);
+#else
+ /* cache must be full size of nvram if read/write */
+ nvram_vars = flash;
+#endif /* BCMNVRAMR */
+
+exit:
+ return ret;
+}
+#endif /* !BCMDONGLEHOST */
+
+
+/* return total length of buffer chain */
+uint BCMFASTPATH
+pkttotlen(osl_t *osh, void *p)
+{
+ uint total;
+ int len;
+
+ total = 0;
+ for (; p; p = PKTNEXT(osh, p)) {
+ len = PKTLEN(osh, p);
+ total += len;
+#ifdef BCMLFRAG
+ if (BCMLFRAG_ENAB()) {
+ if (PKTISFRAG(osh, p)) {
+ total += PKTFRAGTOTLEN(osh, p);
+ }
+ }
+#endif
+ }
+
+ return (total);
+}
+
+/* return the last buffer of chained pkt */
+void *
+pktlast(osl_t *osh, void *p)
+{
+ for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
+ ;
+
+ return (p);
+}
+
+/* count segments of a chained packet */
+uint BCMFASTPATH
+pktsegcnt(osl_t *osh, void *p)
+{
+ uint cnt;
+
+ for (cnt = 0; p; p = PKTNEXT(osh, p)) {
+ cnt++;
+#ifdef BCMLFRAG
+ if (BCMLFRAG_ENAB()) {
+ if (PKTISFRAG(osh, p)) {
+ cnt += PKTFRAGTOTNUM(osh, p);
+ }
+ }
+#endif
+ }
+
+ return cnt;
+}
+
+#ifdef DONGLEBUILD
+/**
+ * Takes in a lbuf/lfrag and no of bytes to be trimmed from tail.
+ * trim bytes could be spread out in below 3 formats
+ * 1. entirely in dongle
+ * 2. entirely in host
+ * 3. split between host-dongle
+ */
+void
+pktfrag_trim_tailbytes(osl_t * osh, void* p, uint16 trim_len, uint8 type)
+{
+ uint16 tcmseg_len = PKTLEN(osh, p); /* TCM segment length */
+ uint16 hostseg_len = PKTFRAGUSEDLEN(osh, p); /* HOST segment length */
+
+ /* return if zero trim length- Nothing to do */
+ if (trim_len == 0)
+ return;
+
+ /* if header conv is on, there is no fcs at the end */
+ if (PKTISHDRCONVTD(osh, p))
+ return;
+
+ /* if pktfetched, then its already trimmed */
+ if (PKTISPKTFETCHED(osh, p))
+ return;
+
+ if (PKTFRAGUSEDLEN(osh, p) >= trim_len) {
+ /* TRIM bytes entirely in host */
+ ASSERT(PKTISRXFRAG(osh, p));
+
+ PKTSETFRAGUSEDLEN(osh, p, (hostseg_len - trim_len));
+ } else {
+ /* trim bytes either in dongle or split between dongle-host */
+ PKTSETLEN(osh, p, (tcmseg_len - (trim_len - hostseg_len)));
+
+ /* No more contents in host; reset length to zero */
+ if (PKTFRAGUSEDLEN(osh, p))
+ PKTSETFRAGUSEDLEN(osh, p, 0);
+ }
+}
+#endif /* DONGLEBUILD */
+
+/* copy a pkt buffer chain into a buffer */
+uint
+pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
+{
+ uint n, ret = 0;
+
+ if (len < 0)
+ len = 4096; /* "infinite" */
+
+ /* skip 'offset' bytes */
+ for (; p && offset; p = PKTNEXT(osh, p)) {
+ if (offset < (uint)PKTLEN(osh, p))
+ break;
+ offset -= PKTLEN(osh, p);
+ }
+
+ if (!p)
+ return 0;
+
+ /* copy the data */
+ for (; p && len; p = PKTNEXT(osh, p)) {
+ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
+ bcopy(PKTDATA(osh, p) + offset, buf, n);
+ buf += n;
+ len -= n;
+ ret += n;
+ offset = 0;
+ }
+
+ return ret;
+}
+
+/* copy a buffer into a pkt buffer chain */
+uint
+pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
+{
+ uint n, ret = 0;
+
+
+ /* skip 'offset' bytes */
+ for (; p && offset; p = PKTNEXT(osh, p)) {
+ if (offset < (uint)PKTLEN(osh, p))
+ break;
+ offset -= PKTLEN(osh, p);
+ }
+
+ if (!p)
+ return 0;
+
+ /* copy the data */
+ for (; p && len; p = PKTNEXT(osh, p)) {
+ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
+ bcopy(buf, PKTDATA(osh, p) + offset, n);
+ buf += n;
+ len -= n;
+ ret += n;
+ offset = 0;
+ }
+
+ return ret;
+}
+
+#ifdef NOTYET
+/* copy data from one pkt buffer (chain) to another */
+uint
+pkt2pktcopy(osl_t *osh, void *p1, uint offs1, void *p2, uint offs2, int maxlen)
+{
+ uint8 *dp1, *dp2;
+ uint len1, len2, copylen, totallen;
+
+ for (; p1 && offs; p1 = PKTNEXT(osh, p1)) {
+ if (offs1 < (uint)PKTLEN(osh, p1))
+ break;
+ offs1 -= PKTLEN(osh, p1);
+ }
+ for (; p2 && offs; p2 = PKTNEXT(osh, p2)) {
+ if (offs2 < (uint)PKTLEN(osh, p2))
+ break;
+ offs2 -= PKTLEN(osh, p2);
+ }
+
+ /* Heck w/it, only need the above for now */
+}
+#endif /* NOTYET */
+
+/* count segments of a chained packet */
+uint BCMFASTPATH
+pktsegcnt_war(osl_t *osh, void *p)
+{
+ uint cnt;
+ uint8 *pktdata;
+ uint len, remain, align64;
+
+ for (cnt = 0; p; p = PKTNEXT(osh, p)) {
+ cnt++;
+ len = PKTLEN(osh, p);
+ if (len > 128) {
+ pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */
+ /* Check for page boundary straddle (2048B) */
+ if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff))
+ cnt++;
+
+ align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */
+ align64 = (64 - align64) & 0x3f;
+ len -= align64; /* bytes from aligned 64B to end */
+ /* if aligned to 128B, check for MOD 128 between 1 to 4B */
+ remain = len % 128;
+ if (remain > 0 && remain <= 4)
+ cnt++; /* add extra seg */
+ }
+ }
+
+ return cnt;
+}
+
+uint8 * BCMFASTPATH
+pktdataoffset(osl_t *osh, void *p, uint offset)
+{
+ uint total = pkttotlen(osh, p);
+ uint pkt_off = 0, len = 0;
+ uint8 *pdata = (uint8 *) PKTDATA(osh, p);
+
+ if (offset > total)
+ return NULL;
+
+ for (; p; p = PKTNEXT(osh, p)) {
+ pdata = (uint8 *) PKTDATA(osh, p);
+ pkt_off = offset - len;
+ len += PKTLEN(osh, p);
+ if (len > offset)
+ break;
+ }
+ return (uint8*) (pdata+pkt_off);
+}
+
+
+/* given a offset in pdata, find the pkt seg hdr */
+void *
+pktoffset(osl_t *osh, void *p, uint offset)
+{
+ uint total = pkttotlen(osh, p);
+ uint len = 0;
+
+ if (offset > total)
+ return NULL;
+
+ for (; p; p = PKTNEXT(osh, p)) {
+ len += PKTLEN(osh, p);
+ if (len > offset)
+ break;
+ }
+ return p;
+}
+
+void
+bcm_mdelay(uint ms)
+{
+ uint i;
+
+ for (i = 0; i < ms; i++) {
+ OSL_DELAY(1000);
+ }
+}
+
+#if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS)
+
+#if defined(__ARM_ARCH_7R__)
+#define BCMLOG_CYCLE_OVERHEAD 54 /* Number of CPU cycle overhead due to bcmlog().
+ * This is to compensate CPU cycle incurred by
+ * added bcmlog() function call for profiling.
+ */
+#else
+#define BCMLOG_CYCLE_OVERHEAD 0
+#endif
+
+#define LOGSIZE 256 /* should be power of 2 to avoid div below */
+static struct {
+ uint cycles;
+ const char *fmt;
+ uint a1;
+ uint a2;
+ uchar indent; /* track indent level for nice printing */
+} logtab[LOGSIZE];
+
+/* last entry logged */
+static uint logi = 0;
+/* next entry to read */
+static uint volatile readi = 0;
+#endif /* defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) */
+
+#ifdef BCMPERFSTATS
+/* TODO: make the utility configurable (choose between icache, dcache, hits, misses ...) */
+void
+bcm_perf_enable()
+{
+ BCMPERF_ENABLE_INSTRCOUNT();
+ BCMPERF_ENABLE_ICACHE_MISS();
+ BCMPERF_ENABLE_ICACHE_HIT();
+}
+
+/* WARNING: This routine uses OSL_GETCYCLES(), which can give unexpected results on
+ * modern speed stepping CPUs. Use bcmtslog() instead in combination with TSF counter.
+ */
+void
+bcmlog(char *fmt, uint a1, uint a2)
+{
+ static uint last = 0;
+ uint cycles, i, elapsed;
+ OSL_GETCYCLES(cycles);
+
+ i = logi;
+
+ elapsed = cycles - last;
+ if (elapsed > BCMLOG_CYCLE_OVERHEAD)
+ logtab[i].cycles = elapsed - BCMLOG_CYCLE_OVERHEAD;
+ else
+ logtab[i].cycles = 0;
+ logtab[i].fmt = fmt;
+ logtab[i].a1 = a1;
+ logtab[i].a2 = a2;
+
+ logi = (i + 1) % LOGSIZE;
+ last = cycles;
+
+ /* if log buffer is overflowing, readi should be advanced.
+ * Otherwise logi and readi will become out of sync.
+ */
+ if (logi == readi) {
+ readi = (readi + 1) % LOGSIZE;
+ } else {
+ /* This redundant else is to make CPU cycles of bcmlog() function to be uniform,
+ * so that the cycle compensation with BCMLOG_CYCLE_OVERHEAD is more accurate.
+ */
+ readi = readi % LOGSIZE;
+ }
+}
+
+/* Same as bcmlog but specializes the use of a1 and a2 to
+ * store icache misses and instruction count.
+ * TODO : make this use a configuration array to decide what counter to read.
+ * We are limited to 2 numbers but it seems it is the most we can get anyway
+ * since dcache and icache cannot be enabled at the same time. Recording
+ * both the hits and misses at the same time for a given cache is not that useful either.
+*/
+
+void
+bcmstats(char *fmt)
+{
+ static uint last = 0;
+ static uint32 ic_miss = 0;
+ static uint32 instr_count = 0;
+ uint32 ic_miss_cur;
+ uint32 instr_count_cur;
+ uint cycles, i;
+
+ OSL_GETCYCLES(cycles);
+ BCMPERF_GETICACHE_MISS(ic_miss_cur);
+ BCMPERF_GETINSTRCOUNT(instr_count_cur);
+
+ i = logi;
+
+ logtab[i].cycles = cycles - last;
+ logtab[i].a1 = ic_miss_cur - ic_miss;
+ logtab[i].a2 = instr_count_cur - instr_count;
+ logtab[i].fmt = fmt;
+
+ logi = (i + 1) % LOGSIZE;
+
+ last = cycles;
+ instr_count = instr_count_cur;
+ ic_miss = ic_miss_cur;
+
+ /* if log buffer is overflowing, readi should be advanced.
+ * Otherwise logi and readi will become out of sync.
+ */
+ if (logi == readi) {
+ readi = (readi + 1) % LOGSIZE;
+ } else {
+ /* This redundant else is to make CPU cycles of bcmstats() function to be uniform
+ */
+ readi = readi % LOGSIZE;
+ }
+}
+
+/*
+ * TODO (linux version): a "proc" version where the log would be dumped
+ * on the proc file directly.
+ */
+
+void
+bcmdumplog(char *buf, int size)
+{
+ char *limit;
+ int j = 0;
+ int num;
+
+ limit = buf + size - 80;
+ *buf = '\0';
+
+ num = logi - readi;
+
+ if (num < 0)
+ num += LOGSIZE;
+
+ /* print in chronological order */
+
+ for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
+ if (logtab[readi].fmt == NULL)
+ continue;
+ buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles);
+ buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1,
+ logtab[readi].a2);
+ buf += snprintf(buf, (limit - buf), "\n");
+ }
+
+}
+
+
+/*
+ * Dump one log entry at a time.
+ * Return index of next entry or -1 when no more .
+ */
+int
+bcmdumplogent(char *buf, uint i)
+{
+ bool hit;
+
+ /*
+ * If buf is NULL, return the starting index,
+ * interpreting i as the indicator of last 'i' entries to dump.
+ */
+ if (buf == NULL) {
+ i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
+ return ((logi - i) % LOGSIZE);
+ }
+
+ *buf = '\0';
+
+ ASSERT(i < LOGSIZE);
+
+ if (i == logi)
+ return (-1);
+
+ hit = FALSE;
+ for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) {
+ if (logtab[i].fmt == NULL)
+ continue;
+ buf += snprintf(buf, LOGSIZE, "%d: %d\t", i, logtab[i].cycles);
+ buf += snprintf(buf, LOGSIZE, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
+ buf += snprintf(buf, LOGSIZE, "\n");
+ hit = TRUE;
+ }
+
+ return (i);
+}
+
+#endif /* BCMPERFSTATS */
+
+#if defined(BCMTSTAMPEDLOGS)
+/* Store a TSF timestamp and a log line in the log buffer */
+/*
+ a1 is used to signify entering/exiting a routine. When entering
+ the indent level is increased. When exiting, the delta since entering
+ is printed and the indent level is bumped back out.
+ Nesting can go up to level MAX_TS_INDENTS deep.
+*/
+#define MAX_TS_INDENTS 20
+void
+bcmtslog(uint32 tstamp, const char *fmt, uint a1, uint a2)
+{
+ uint i = logi;
+ bool use_delta = TRUE;
+ static uint32 last = 0; /* used only when use_delta is true */
+ static uchar indent = 0;
+ static uint32 indents[MAX_TS_INDENTS];
+
+ logtab[i].cycles = tstamp;
+ if (use_delta)
+ logtab[i].cycles -= last;
+
+ logtab[i].a2 = a2;
+
+ if (a1 == TS_EXIT && indent) {
+ indent--;
+ logtab[i].a2 = tstamp - indents[indent];
+ }
+
+ logtab[i].fmt = fmt;
+ logtab[i].a1 = a1;
+ logtab[i].indent = indent;
+
+ if (a1 == TS_ENTER) {
+ indents[indent] = tstamp;
+ if (indent < MAX_TS_INDENTS - 1)
+ indent++;
+ }
+
+ if (use_delta)
+ last = tstamp;
+ logi = (i + 1) % LOGSIZE;
+}
+
+/* Print out a microsecond timestamp as "sec.ms.us " */
+void
+bcmprinttstamp(uint32 ticks)
+{
+ uint us, ms, sec;
+
+ us = (ticks % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
+ ms = ticks / TSF_TICKS_PER_MS;
+ sec = ms / 1000;
+ ms -= sec * 1000;
+ printf("%04u.%03u.%03u ", sec, ms, us);
+}
+
+/* Print out the log buffer with timestamps */
+void
+bcmprinttslogs(void)
+{
+ int j = 0;
+ int num;
+
+ num = logi - readi;
+ if (num < 0)
+ num += LOGSIZE;
+
+ /* Format and print the log entries directly in chronological order */
+ for (j = 0; j < num; readi = (readi + 1) % LOGSIZE, j++) {
+ if (logtab[readi].fmt == NULL)
+ continue;
+ bcmprinttstamp(logtab[readi].cycles);
+ printf(logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
+ printf("\n");
+ }
+}
+
+/*
+ Identical to bcmdumplog, but output is based on tsf instead of cycles.
+
+ a1 is used to signify entering/exiting a routine. When entering
+ the indent level is increased. When exiting, the delta since entering
+ is printed and the indent level is bumped back out.
+*/
+void
+bcmdumptslog(struct bcmstrbuf *b)
+{
+ char *limit;
+ int j = 0;
+ int num;
+ uint us, ms, sec;
+ int skip;
+ char *lines = "| | | | | | | | | | | | | | | | | | | |";
+
+ limit = BCMSTRBUF_BUF(b) + BCMSTRBUF_LEN(b) - 80;
+
+ num = logi - readi;
+
+ if (num < 0)
+ num += LOGSIZE;
+
+ /* print in chronological order */
+ for (j = 0; j < num && (BCMSTRBUF_BUF(b) < limit); readi = (readi + 1) % LOGSIZE, j++) {
+ char *last_buf = BCMSTRBUF_BUF(b);
+ if (logtab[readi].fmt == NULL)
+ continue;
+
+ us = (logtab[readi].cycles % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
+ ms = logtab[readi].cycles / TSF_TICKS_PER_MS;
+ sec = ms / 1000;
+ ms -= sec * 1000;
+
+ bcm_bprintf(b, "%04u.%03u.%03u ", sec, ms, us);
+
+ /* 2 spaces for each indent level */
+ bcm_bprintf(b, "%.*s", logtab[readi].indent * 2, lines);
+
+ /*
+ * The following call to snprintf generates a compiler warning
+ * due to -Wformat-security. However, the format string is coming
+ * from internal callers rather than external data input, and is a
+ * useful debugging tool serving a variety of diagnostics. Rather
+ * than expand code size by replicating multiple functions with different
+ * argument lists, or disabling the warning globally, let's consider
+ * if we can just disable the warning for this one instance.
+ */
+ bcm_bprintf(b, logtab[readi].fmt);
+
+ /* If a1 is ENTER or EXIT, print the + or - */
+ skip = 0;
+ if (logtab[readi].a1 == TS_ENTER) {
+ bcm_bprintf(b, " +");
+ skip++;
+ }
+ if (logtab[readi].a1 == TS_EXIT) {
+ bcm_bprintf(b, " -");
+ skip++;
+ }
+
+ /* else print the real a1 */
+ if (logtab[readi].a1 && !skip)
+ bcm_bprintf(b, " %d", logtab[readi].a1);
+
+ /*
+ If exiting routine, print a nicely formatted delta since entering.
+ Otherwise, just print a2 normally.
+ */
+ if (logtab[readi].a2) {
+ if (logtab[readi].a1 == TS_EXIT) {
+ int num_space = 75 - (BCMSTRBUF_BUF(b) - last_buf);
+ bcm_bprintf(b, "%*.s", num_space, "");
+ bcm_bprintf(b, "%5d usecs", logtab[readi].a2);
+ } else
+ bcm_bprintf(b, " %d", logtab[readi].a2);
+ }
+ bcm_bprintf(b, "\n");
+ last_buf = BCMSTRBUF_BUF(b);
+ }
+}
+
+#endif /* BCMTSTAMPEDLOGS */
+
+#if defined(BCMDBG) || defined(DHD_DEBUG)
+/* pretty hex print a pkt buffer chain */
+void
+prpkt(const char *msg, osl_t *osh, void *p0)
+{
+ void *p;
+
+ if (msg && (msg[0] != '\0'))
+ printf("%s:\n", msg);
+
+ for (p = p0; p; p = PKTNEXT(osh, p))
+ prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
+}
+#endif /* BCMDBG || DHD_DEBUG */
+
+/* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
+ * Also updates the inplace vlan tag if requested.
+ * For debugging, it returns an indication of what it did.
+ */
+uint BCMFASTPATH
+pktsetprio(void *pkt, bool update_vtag)
+{
+ struct ether_header *eh;
+ struct ethervlan_header *evh;
+ uint8 *pktdata;
+ int priority = 0;
+ int rc = 0;
+
+ pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
+ ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
+
+ eh = (struct ether_header *) pktdata;
+
+ if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
+ uint16 vlan_tag;
+ int vlan_prio, dscp_prio = 0;
+
+ evh = (struct ethervlan_header *)eh;
+
+ vlan_tag = ntoh16(evh->vlan_tag);
+ vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
+
+ if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
+ (evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
+ uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
+ uint8 tos_tc = IP_TOS46(ip_body);
+ dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
+ }
+
+ /* DSCP priority gets precedence over 802.1P (vlan tag) */
+ if (dscp_prio != 0) {
+ priority = dscp_prio;
+ rc |= PKTPRIO_VDSCP;
+ } else {
+ priority = vlan_prio;
+ rc |= PKTPRIO_VLAN;
+ }
+ /*
+ * If the DSCP priority is not the same as the VLAN priority,
+ * then overwrite the priority field in the vlan tag, with the
+ * DSCP priority value. This is required for Linux APs because
+ * the VLAN driver on Linux, overwrites the skb->priority field
+ * with the priority value in the vlan tag
+ */
+ if (update_vtag && (priority != vlan_prio)) {
+ vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
+ vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
+ evh->vlan_tag = hton16(vlan_tag);
+ rc |= PKTPRIO_UPD;
+ }
+#if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING)
+ } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
+ priority = PRIO_8021D_NC;
+ rc = PKTPRIO_DSCP;
+#endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */
+ } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
+ (eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
+ uint8 *ip_body = pktdata + sizeof(struct ether_header);
+ uint8 tos_tc = IP_TOS46(ip_body);
+ uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
+ switch (dscp) {
+ case DSCP_EF:
+ priority = PRIO_8021D_VO;
+ break;
+ case DSCP_AF31:
+ case DSCP_AF32:
+ case DSCP_AF33:
+ priority = PRIO_8021D_CL;
+ break;
+ case DSCP_AF21:
+ case DSCP_AF22:
+ case DSCP_AF23:
+ case DSCP_AF11:
+ case DSCP_AF12:
+ case DSCP_AF13:
+ priority = PRIO_8021D_EE;
+ break;
+ default:
+#ifndef CUSTOM_DSCP_TO_PRIO_MAPPING
+ priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
+#else
+ if (dhd_dscpmap_enable) {
+ priority = (int)dscp2priomap[((tos_tc >> IPV4_TOS_DSCP_SHIFT)
+ & CUST_IPV4_TOS_PREC_MASK)];
+ }
+ else {
+ priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
+ }
+#endif /* CUSTOM_DSCP_TO_PRIO_MAPPING */
+ break;
+ }
+
+ rc |= PKTPRIO_DSCP;
+ }
+
+ ASSERT(priority >= 0 && priority <= MAXPRIO);
+ PKTSETPRIO(pkt, priority);
+ return (rc | priority);
+}
+
+/* lookup user priority for specified DSCP */
+static uint8
+dscp2up(uint8 *up_table, uint8 dscp)
+{
+ uint8 user_priority = 255;
+
+ /* lookup up from table if parameters valid */
+ if (up_table != NULL && dscp < UP_TABLE_MAX) {
+ user_priority = up_table[dscp];
+ }
+
+ /* 255 is unused value so return up from dscp */
+ if (user_priority == 255) {
+ user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT);
+ }
+
+ return user_priority;
+}
+
+/* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
+uint BCMFASTPATH
+pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag)
+{
+ if (up_table) {
+ uint8 *pktdata;
+ uint pktlen;
+ uint8 dscp;
+ uint user_priority = 0;
+ uint rc = 0;
+
+ pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
+ pktlen = PKTLEN(OSH_NULL, pkt);
+
+ if (pktgetdscp(pktdata, pktlen, &dscp)) {
+ rc = PKTPRIO_DSCP;
+ user_priority = dscp2up(up_table, dscp);
+ PKTSETPRIO(pkt, user_priority);
+ }
+
+ return (rc | user_priority);
+ } else {
+ return pktsetprio(pkt, update_vtag);
+ }
+}
+
+/* Returns TRUE and DSCP if IP header found, FALSE otherwise.
+ */
+bool BCMFASTPATH
+pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
+{
+ struct ether_header *eh;
+ struct ethervlan_header *evh;
+ uint8 *ip_body;
+ bool rc = FALSE;
+
+ /* minimum length is ether header and IP header */
+ if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)
+ return FALSE;
+
+ eh = (struct ether_header *) pktdata;
+
+ if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
+ ip_body = pktdata + sizeof(struct ether_header);
+ *dscp = IP_DSCP46(ip_body);
+ rc = TRUE;
+ }
+ else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
+ evh = (struct ethervlan_header *)eh;
+
+ /* minimum length is ethervlan header and IP header */
+ if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
+ evh->ether_type == HTON16(ETHER_TYPE_IP)) {
+ ip_body = pktdata + sizeof(struct ethervlan_header);
+ *dscp = IP_DSCP46(ip_body);
+ rc = TRUE;
+ }
+ }
+
+ return rc;
+}
+
+/* usr_prio range from low to high with usr_prio value */
+static bool
+up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high)
+{
+ int i;
+
+ if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) {
+ return FALSE;
+ }
+
+ for (i = low; i <= high; i++) {
+ up_table[i] = usr_prio;
+ }
+
+ return TRUE;
+}
+
+/* set user priority table */
+int BCMFASTPATH
+wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie)
+{
+ uint8 len;
+
+ if (up_table == NULL || qos_map_ie == NULL) {
+ return BCME_ERROR;
+ }
+
+ /* clear table to check table was set or not */
+ memset(up_table, 0xff, UP_TABLE_MAX);
+
+ /* length of QoS Map IE must be 16+n*2, n is number of exceptions */
+ if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID &&
+ (len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH &&
+ (len % 2) == 0) {
+ uint8 *except_ptr = (uint8 *)qos_map_ie->data;
+ uint8 except_len = len - QOS_MAP_FIXED_LENGTH;
+ uint8 *range_ptr = except_ptr + except_len;
+ int i;
+
+ /* fill in ranges */
+ for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) {
+ uint8 low = range_ptr[i];
+ uint8 high = range_ptr[i + 1];
+ if (low == 255 && high == 255) {
+ continue;
+ }
+
+ if (!up_table_set(up_table, i / 2, low, high)) {
+ /* clear the table on failure */
+ memset(up_table, 0xff, UP_TABLE_MAX);
+ return BCME_ERROR;
+ }
+ }
+
+ /* update exceptions */
+ for (i = 0; i < except_len; i += 2) {
+ uint8 dscp = except_ptr[i];
+ uint8 usr_prio = except_ptr[i+1];
+
+ /* exceptions with invalid dscp/usr_prio are ignored */
+ up_table_set(up_table, usr_prio, dscp, dscp);
+ }
+ }
+
+ return BCME_OK;
+}
+
+#ifndef BCM_BOOTLOADER
+/* The 0.5KB string table is not removed by compiler even though it's unused */
+
+static char bcm_undeferrstr[32];
+static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
+
+/* Convert the error codes into related error strings */
+const char *
+BCMRAMFN(bcmerrorstr)(int bcmerror)
+{
+ /* check if someone added a bcmerror code but forgot to add errorstring */
+ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
+
+ if (bcmerror > 0 || bcmerror < BCME_LAST) {
+ snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
+ return bcm_undeferrstr;
+ }
+
+ ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
+
+ return bcmerrorstrtable[-bcmerror];
+}
+
+#endif /* !BCM_BOOTLOADER */
+
+#ifdef BCMDBG_PKT /* pkt logging for debugging */
+/* Add a packet to the pktlist */
+static void
+_pktlist_add(pktlist_info_t *pktlist, void *pkt, int line, char *file)
+{
+ uint16 i;
+ char *basename;
+#ifdef BCMDBG_PTRACE
+ uint16 *idx = PKTLIST_IDX(pkt);
+#endif /* BCMDBG_PTRACE */
+
+ ASSERT(pktlist->count < PKTLIST_SIZE);
+
+ /* Verify the packet is not already part of the list */
+ for (i = 0; i < pktlist->count; i++) {
+ if (pktlist->list[i].pkt == pkt)
+ ASSERT(0);
+ }
+ pktlist->list[pktlist->count].pkt = pkt;
+ pktlist->list[pktlist->count].line = line;
+
+ basename = strrchr(file, '/');
+ if (basename)
+ basename++;
+ else
+ basename = file;
+ pktlist->list[pktlist->count].file = basename;
+#ifdef BCMDBG_PTRACE
+ *idx = pktlist->count;
+ bzero(pktlist->list[pktlist->count].pkt_trace, PKTTRACE_MAX_BYTES);
+#endif /* BCMDBG_PTRACE */
+ pktlist->count++;
+
+ return;
+}
+
+void
+pktlist_add(pktlist_info_t *pktlist, void *pkt, int line, char *file)
+{
+ void *p;
+ for (p = pkt; p != NULL; p = PKTCLINK(p))
+ _pktlist_add(pktlist, p, line, file);
+}
+
+/* Remove a packet from the pktlist */
+static void
+_pktlist_remove(pktlist_info_t *pktlist, void *pkt)
+{
+ uint16 i;
+ uint16 num = pktlist->count;
+#ifdef BCMDBG_PTRACE
+ uint16 *idx = PKTLIST_IDX(pkt);
+
+ ASSERT((*idx) < pktlist->count);
+#endif /* BCMDBG_PTRACE */
+
+ /* find the index where pkt exists */
+ for (i = 0; i < num; i++) {
+ /* check for the existence of pkt in the list */
+ if (pktlist->list[i].pkt == pkt) {
+#ifdef BCMDBG_PTRACE
+ ASSERT((*idx) == i);
+#endif /* BCMDBG_PTRACE */
+ /* replace with the last element */
+ pktlist->list[i].pkt = pktlist->list[num-1].pkt;
+ pktlist->list[i].line = pktlist->list[num-1].line;
+ pktlist->list[i].file = pktlist->list[num-1].file;
+#ifdef BCMDBG_PTRACE
+ memcpy(pktlist->list[i].pkt_trace, pktlist->list[num-1].pkt_trace,
+ PKTTRACE_MAX_BYTES);
+ idx = PKTLIST_IDX(pktlist->list[i].pkt);
+ *idx = i;
+#endif /* BCMDBG_PTRACE */
+ pktlist->count--;
+ return;
+ }
+ }
+ ASSERT(0);
+}
+
+void
+pktlist_remove(pktlist_info_t *pktlist, void *pkt)
+{
+ void *p;
+ for (p = pkt; p != NULL; p = PKTCLINK(p))
+ _pktlist_remove(pktlist, p);
+}
+
+#ifdef BCMDBG_PTRACE
+static void
+_pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit)
+{
+ uint16 *idx = PKTLIST_IDX(pkt);
+
+ ASSERT(((*idx) < pktlist->count) && (bit < PKTTRACE_MAX_BITS));
+ ASSERT(pktlist->list[(*idx)].pkt == pkt);
+
+ pktlist->list[(*idx)].pkt_trace[bit/NBBY] |= (1 << ((bit)%NBBY));
+
+}
+void
+pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit)
+{
+ void *p;
+ for (p = pkt; p != NULL; p = PKTCLINK(p))
+ _pktlist_trace(pktlist, p, bit);
+}
+#endif /* BCMDBG_PTRACE */
+
+/* Dump the pktlist (and the contents of each packet if 'data'
+ * is set). 'buf' should be large enough
+ */
+
+char *
+pktlist_dump(pktlist_info_t *pktlist, char *buf)
+{
+ char *obuf = buf;
+ uint16 i;
+
+ if (buf != NULL)
+ buf += sprintf(buf, "Packet list dump:\n");
+ else
+ printf("Packet list dump:\n");
+
+ for (i = 0; i < (pktlist->count); i++) {
+ if (buf != NULL)
+ buf += sprintf(buf, "Pkt_addr: 0x%p Line: %d File: %s\t",
+ OSL_OBFUSCATE_BUF(pktlist->list[i].pkt), pktlist->list[i].line,
+ pktlist->list[i].file);
+ else
+ printf("Pkt_addr: 0x%p Line: %d File: %s\t",
+ OSL_OBFUSCATE_BUF(pktlist->list[i].pkt),
+ pktlist->list[i].line, pktlist->list[i].file);
+
+/* #ifdef NOTDEF Remove this ifdef to print pkttag and pktdata */
+ if (buf != NULL) {
+ if (PKTTAG(pktlist->list[i].pkt)) {
+ /* Print pkttag */
+ buf += sprintf(buf, "Pkttag(in hex): ");
+ buf += bcm_format_hex(buf, PKTTAG(pktlist->list[i].pkt),
+ OSL_PKTTAG_SZ);
+ }
+ buf += sprintf(buf, "Pktdata(in hex): ");
+ buf += bcm_format_hex(buf, PKTDATA(OSH_NULL, pktlist->list[i].pkt),
+ PKTLEN(OSH_NULL, pktlist->list[i].pkt));
+ } else {
+ void *pkt = pktlist->list[i].pkt, *npkt;
+
+ printf("Pkt[%d] Dump:\n", i);
+ while (pkt) {
+ int hroom, pktlen;
+ uchar *src;
+#ifdef BCMDBG_PTRACE
+ uint16 *idx = PKTLIST_IDX(pkt);
+
+ ASSERT((*idx) < pktlist->count);
+ prhex("Pkt Trace (in hex):", pktlist->list[(*idx)].pkt_trace,
+ PKTTRACE_MAX_BYTES);
+#endif /* BCMDBG_PTRACE */
+ npkt = (void *)PKTNEXT(OSH_NULL, pkt);
+ PKTSETNEXT(OSH_NULL, pkt, NULL);
+
+ src = (uchar *)(PKTTAG(pkt));
+ pktlen = PKTLEN(OSH_NULL, pkt);
+ hroom = PKTHEADROOM(OSH_NULL, pkt);
+
+ printf("Pkttag_addr: %p\n", OSL_OBFUSCATE_BUF(src));
+ if (src)
+ prhex("Pkttag(in hex): ", src, OSL_PKTTAG_SZ);
+ src = (uchar *) (PKTDATA(OSH_NULL, pkt));
+ printf("Pkthead_addr: %p len: %d\n",
+ OSL_OBFUSCATE_BUF(src - hroom), hroom);
+ prhex("Pkt headroom content(in hex): ", src - hroom, hroom);
+ printf("Pktdata_addr: %p len: %d\n",
+ OSL_OBFUSCATE_BUF(src), pktlen);
+ prhex("Pktdata(in hex): ", src, pktlen);
+
+ pkt = npkt;
+ }
+ }
+/* #endif NOTDEF */
+
+ if (buf != NULL)
+ buf += sprintf(buf, "\n");
+ else
+ printf("\n");
+ }
+ return obuf;
+}
+#endif /* BCMDBG_PKT */
+
+/* iovar table lookup */
+/* could mandate sorted tables and do a binary search */
+const bcm_iovar_t*
+bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
+{
+ const bcm_iovar_t *vi;
+ const char *lookup_name;
+
+ /* skip any ':' delimited option prefixes */
+ lookup_name = strrchr(name, ':');
+ if (lookup_name != NULL)
+ lookup_name++;
+ else
+ lookup_name = name;
+
+ ASSERT(table != NULL);
+
+ for (vi = table; vi->name; vi++) {
+ if (!strcmp(vi->name, lookup_name))
+ return vi;
+ }
+ /* ran to end of table */
+
+ return NULL; /* var name not found */
+}
+
+int
+bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
+{
+ int bcmerror = 0;
+ BCM_REFERENCE(arg);
+
+ /* length check on io buf */
+ switch (vi->type) {
+ case IOVT_BOOL:
+ case IOVT_INT8:
+ case IOVT_INT16:
+ case IOVT_INT32:
+ case IOVT_UINT8:
+ case IOVT_UINT16:
+ case IOVT_UINT32:
+ /* all integers are int32 sized args at the ioctl interface */
+ if (len < (int)sizeof(int)) {
+ bcmerror = BCME_BUFTOOSHORT;
+ }
+ break;
+
+ case IOVT_BUFFER:
+ /* buffer must meet minimum length requirement */
+ if (len < vi->minlen) {
+ bcmerror = BCME_BUFTOOSHORT;
+ }
+ break;
+
+ case IOVT_VOID:
+ if (!set) {
+ /* Cannot return nil... */
+ bcmerror = BCME_UNSUPPORTED;
+ } else if (len) {
+ /* Set is an action w/o parameters */
+ bcmerror = BCME_BUFTOOLONG;
+ }
+ break;
+
+ default:
+ /* unknown type for length check in iovar info */
+ ASSERT(0);
+ bcmerror = BCME_UNSUPPORTED;
+ }
+
+ return bcmerror;
+}
+
+#if !defined(_CFEZ_)
+/*
+ * Hierarchical Multiword bitmap based small id allocator.
+ *
+ * Multilevel hierarchy bitmap. (maximum 2 levels)
+ * First hierarchy uses a multiword bitmap to identify 32bit words in the
+ * second hierarchy that have at least a single bit set. Each bit in a word of
+ * the second hierarchy represents a unique ID that may be allocated.
+ *
+ * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
+ * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
+ * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
+ * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
+ * non-zero bitmap word carrying at least one free ID.
+ * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
+ * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
+ *
+ * Design Notes:
+ * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
+ * bits are computed each time on allocation and deallocation, requiring 4
+ * array indexed access and 3 arithmetic operations. When not defined, a runtime
+ * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
+ * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
+ * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
+ * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
+ *
+ * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
+ * size is fixed. No intention to support larger than 4K indice allocation. ID
+ * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
+ * with savings in not having to use an indirect access, had it been dynamically
+ * allocated.
+ */
+#if defined(DONGLEBUILD)
+#define BCM_MWBMAP_USE_CNTSETBITS /* runtime count set bits */
+#define BCM_MWBMAP_ITEMS_MAX (4 * 1024)
+#else /* ! DONGLEBUILD */
+#define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */
+#endif /* DONGLEBUILD */
+
+#define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
+#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
+#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
+#define BCM_MWBMAP_SHIFT_OP (5)
+#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
+#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
+#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
+
+/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
+#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
+#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
+
+#if defined(BCM_MWBMAP_DEBUG)
+#define BCM_MWBMAP_AUDIT(mwb) \
+ do { \
+ ASSERT((mwb != NULL) && \
+ (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
+ bcm_mwbmap_audit(mwb); \
+ } while (0)
+#define MWBMAP_ASSERT(exp) ASSERT(exp)
+#define MWBMAP_DBG(x) printf x
+#else /* !BCM_MWBMAP_DEBUG */
+#define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
+#define MWBMAP_ASSERT(exp) do {} while (0)
+#define MWBMAP_DBG(x)
+#endif /* !BCM_MWBMAP_DEBUG */
+
+
+typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */
+ uint16 wmaps; /* Total number of words in free wd bitmap */
+ uint16 imaps; /* Total number of words in free id bitmap */
+ int32 ifree; /* Count of free indices. Used only in audits */
+ uint16 total; /* Total indices managed by multiword bitmap */
+
+ void * magic; /* Audit handle parameter from user */
+
+ uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */
+#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
+ int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+
+ uint32 id_bitmap[0]; /* Second level bitmap */
+} bcm_mwbmap_t;
+
+/* Incarnate a hierarchical multiword bitmap based small index allocator. */
+struct bcm_mwbmap *
+BCMATTACHFN(bcm_mwbmap_init)(osl_t *osh, uint32 items_max)
+{
+ struct bcm_mwbmap * mwbmap_p;
+ uint32 wordix, size, words, extra;
+
+ /* Implementation Constraint: Uses 32bit word bitmap */
+ MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
+ MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
+ MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
+ MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
+
+ ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
+
+ /* Determine the number of words needed in the multiword bitmap */
+ extra = BCM_MWBMAP_MODOP(items_max);
+ words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
+
+ /* Allocate runtime state of multiword bitmap */
+ /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
+ size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
+ mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
+ if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
+ ASSERT(0);
+ goto error1;
+ }
+ memset(mwbmap_p, 0, size);
+
+ /* Initialize runtime multiword bitmap state */
+ mwbmap_p->imaps = (uint16)words;
+ mwbmap_p->ifree = (int32)items_max;
+ mwbmap_p->total = (uint16)items_max;
+
+ /* Setup magic, for use in audit of handle */
+ mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
+
+ /* Setup the second level bitmap of free indices */
+ /* Mark all indices as available */
+ for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
+ mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
+#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
+ mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ }
+
+ /* Ensure that extra indices are tagged as un-available */
+ if (extra) { /* fixup the free ids in last bitmap and wd_count */
+ uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
+ *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
+#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
+ mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ }
+
+ /* Setup the first level bitmap hierarchy */
+ extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
+ words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
+
+ mwbmap_p->wmaps = (uint16)words;
+
+ for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++)
+ mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
+ if (extra) {
+ uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
+ *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
+ }
+
+ return mwbmap_p;
+
+error1:
+ return BCM_MWBMAP_INVALID_HDL;
+}
+
+/* Release resources used by multiword bitmap based small index allocator. */
+void
+BCMATTACHFN(bcm_mwbmap_fini)(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
+{
+ bcm_mwbmap_t * mwbmap_p;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap)
+ + (sizeof(uint32) * mwbmap_p->imaps));
+ return;
+}
+
+/* Allocate a unique small index using a multiword bitmap index allocator. */
+uint32 BCMFASTPATH
+bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)
+{
+ bcm_mwbmap_t * mwbmap_p;
+ uint32 wordix, bitmap;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ /* Start with the first hierarchy */
+ for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
+
+ bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
+
+ if (bitmap != 0U) {
+
+ uint32 count, bitix, *bitmap_p;
+
+ bitmap_p = &mwbmap_p->wd_bitmap[wordix];
+
+ /* clear all except trailing 1 */
+ bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
+ MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
+ bcm_count_leading_zeros(bitmap));
+ bitix = (BCM_MWBMAP_BITS_WORD - 1)
+ - bcm_count_leading_zeros(bitmap); /* use asm clz */
+ wordix = BCM_MWBMAP_MULOP(wordix) + bitix;
+
+ /* Clear bit if wd count is 0, without conditional branch */
+#if defined(BCM_MWBMAP_USE_CNTSETBITS)
+ count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
+#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ mwbmap_p->wd_count[wordix]--;
+ count = mwbmap_p->wd_count[wordix];
+ MWBMAP_ASSERT(count ==
+ (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ MWBMAP_ASSERT(count >= 0);
+
+ /* clear wd_bitmap bit if id_map count is 0 */
+ bitmap = (count == 0) << bitix;
+
+ MWBMAP_DBG((
+ "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
+ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
+
+ *bitmap_p ^= bitmap;
+
+ /* Use bitix in the second hierarchy */
+ bitmap_p = &mwbmap_p->id_bitmap[wordix];
+
+ bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
+ MWBMAP_ASSERT(bitmap != 0U);
+
+ /* clear all except trailing 1 */
+ bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
+ MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
+ bcm_count_leading_zeros(bitmap));
+ bitix = BCM_MWBMAP_MULOP(wordix)
+ + (BCM_MWBMAP_BITS_WORD - 1)
+ - bcm_count_leading_zeros(bitmap); /* use asm clz */
+
+ mwbmap_p->ifree--; /* decrement system wide free count */
+ MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
+
+ MWBMAP_DBG((
+ "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
+ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
+ mwbmap_p->ifree));
+
+ *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
+
+ return bitix;
+ }
+ }
+
+ ASSERT(mwbmap_p->ifree == 0);
+
+ return BCM_MWBMAP_INVALID_IDX;
+}
+
+/* Force an index at a specified position to be in use */
+void
+bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
+{
+ bcm_mwbmap_t * mwbmap_p;
+ uint32 count, wordix, bitmap, *bitmap_p;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ ASSERT(bitix < mwbmap_p->total);
+
+ /* Start with second hierarchy */
+ wordix = BCM_MWBMAP_DIVOP(bitix);
+ bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
+ bitmap_p = &mwbmap_p->id_bitmap[wordix];
+
+ ASSERT((*bitmap_p & bitmap) == bitmap);
+
+ mwbmap_p->ifree--; /* update free count */
+ ASSERT(mwbmap_p->ifree >= 0);
+
+ MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
+ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
+ mwbmap_p->ifree));
+
+ *bitmap_p ^= bitmap; /* mark as in use */
+
+ /* Update first hierarchy */
+ bitix = wordix;
+
+ wordix = BCM_MWBMAP_DIVOP(bitix);
+ bitmap_p = &mwbmap_p->wd_bitmap[wordix];
+
+#if defined(BCM_MWBMAP_USE_CNTSETBITS)
+ count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
+#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ mwbmap_p->wd_count[bitix]--;
+ count = mwbmap_p->wd_count[bitix];
+ MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ MWBMAP_ASSERT(count >= 0);
+
+ bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix);
+
+ MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
+ BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
+ (*bitmap_p) ^ bitmap, count));
+
+ *bitmap_p ^= bitmap; /* mark as in use */
+
+ return;
+}
+
+/* Free a previously allocated index back into the multiword bitmap allocator */
+void BCMFASTPATH
+bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
+{
+ bcm_mwbmap_t * mwbmap_p;
+ uint32 wordix, bitmap, *bitmap_p;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ ASSERT(bitix < mwbmap_p->total);
+
+ /* Start with second level hierarchy */
+ wordix = BCM_MWBMAP_DIVOP(bitix);
+ bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
+ bitmap_p = &mwbmap_p->id_bitmap[wordix];
+
+ ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */
+
+ mwbmap_p->ifree++; /* update free count */
+ ASSERT(mwbmap_p->ifree <= mwbmap_p->total);
+
+ MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
+ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
+ mwbmap_p->ifree));
+
+ *bitmap_p |= bitmap; /* mark as available */
+
+ /* Now update first level hierarchy */
+
+ bitix = wordix;
+
+ wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
+ bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
+ bitmap_p = &mwbmap_p->wd_bitmap[wordix];
+
+#if !defined(BCM_MWBMAP_USE_CNTSETBITS)
+ mwbmap_p->wd_count[bitix]++;
+#endif
+
+#if defined(BCM_MWBMAP_DEBUG)
+ {
+ uint32 count;
+#if defined(BCM_MWBMAP_USE_CNTSETBITS)
+ count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
+#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ count = mwbmap_p->wd_count[bitix];
+ MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+
+ MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
+
+ MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
+ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
+ }
+#endif /* BCM_MWBMAP_DEBUG */
+
+ *bitmap_p |= bitmap;
+
+ return;
+}
+
+/* Fetch the toal number of free indices in the multiword bitmap allocator */
+uint32
+bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)
+{
+ bcm_mwbmap_t * mwbmap_p;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ ASSERT(mwbmap_p->ifree >= 0);
+
+ return mwbmap_p->ifree;
+}
+
+/* Determine whether an index is inuse or free */
+bool
+bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
+{
+ bcm_mwbmap_t * mwbmap_p;
+ uint32 wordix, bitmap;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ ASSERT(bitix < mwbmap_p->total);
+
+ wordix = BCM_MWBMAP_DIVOP(bitix);
+ bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
+
+ return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
+}
+
+/* Debug dump a multiword bitmap allocator */
+void
+bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)
+{
+ uint32 ix, count;
+ bcm_mwbmap_t * mwbmap_p;
+
+ BCM_MWBMAP_AUDIT(mwbmap_hdl);
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n",
+ OSL_OBFUSCATE_BUF((void *)mwbmap_p),
+ mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
+ for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
+ printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
+ bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
+ printf("\n");
+ }
+ for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
+#if defined(BCM_MWBMAP_USE_CNTSETBITS)
+ count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
+#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ count = mwbmap_p->wd_count[ix];
+ MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count);
+ bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
+ printf("\n");
+ }
+
+ return;
+}
+
+/* Audit a hierarchical multiword bitmap */
+void
+bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
+{
+ bcm_mwbmap_t * mwbmap_p;
+ uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
+
+ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
+
+ for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
+
+ bitmap_p = &mwbmap_p->wd_bitmap[wordix];
+
+ for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
+ if ((*bitmap_p) & (1 << bitix)) {
+ idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
+#if defined(BCM_MWBMAP_USE_CNTSETBITS)
+ count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
+#else /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ count = mwbmap_p->wd_count[idmap_ix];
+ ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
+#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
+ ASSERT(count != 0U);
+ free_cnt += count;
+ }
+ }
+ }
+
+ ASSERT((int)free_cnt == mwbmap_p->ifree);
+}
+/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
+
+/* Simple 16bit Id allocator using a stack implementation. */
+typedef struct id16_map {
+ uint32 failures; /* count of failures */
+ void *dbg; /* debug placeholder */
+ uint16 total; /* total number of ids managed by allocator */
+ uint16 start; /* start value of 16bit ids to be managed */
+ int stack_idx; /* index into stack of available ids */
+ uint16 stack[0]; /* stack of 16 bit ids */
+} id16_map_t;
+
+#define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \
+ (sizeof(uint16) * (items)))
+
+#if defined(BCM_DBG)
+
+/* Uncomment BCM_DBG_ID16 to debug double free */
+/* #define BCM_DBG_ID16 */
+
+typedef struct id16_map_dbg {
+ uint16 total;
+ bool avail[0];
+} id16_map_dbg_t;
+#define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \
+ (sizeof(bool) * (items)))
+#define ID16_MAP_MSG(x) print x
+#else
+#define ID16_MAP_MSG(x)
+#endif /* BCM_DBG */
+
+void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
+id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
+{
+ uint16 idx, val16;
+ id16_map_t * id16_map;
+
+ ASSERT(total_ids > 0);
+
+ /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
+ * with random values.
+ */
+ ASSERT((start_val16 == ID16_UNDEFINED) ||
+ (start_val16 + total_ids) < ID16_INVALID);
+
+ id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids));
+ if (id16_map == NULL) {
+ return NULL;
+ }
+
+ id16_map->total = total_ids;
+ id16_map->start = start_val16;
+ id16_map->failures = 0;
+ id16_map->dbg = NULL;
+
+ /*
+ * Populate stack with 16bit id values, commencing with start_val16.
+ * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
+ */
+ id16_map->stack_idx = -1;
+
+ if (id16_map->start != ID16_UNDEFINED) {
+ val16 = start_val16;
+
+ for (idx = 0; idx < total_ids; idx++, val16++) {
+ id16_map->stack_idx = idx;
+ id16_map->stack[id16_map->stack_idx] = val16;
+ }
+ }
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->start != ID16_UNDEFINED) {
+ id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
+
+ if (id16_map->dbg) {
+ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+ id16_map_dbg->total = total_ids;
+ for (idx = 0; idx < total_ids; idx++) {
+ id16_map_dbg->avail[idx] = TRUE;
+ }
+ }
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+ return (void *)id16_map;
+}
+
+void * /* Destruct an id16 allocator instance */
+id16_map_fini(osl_t *osh, void * id16_map_hndl)
+{
+ uint16 total_ids;
+ id16_map_t * id16_map;
+
+ if (id16_map_hndl == NULL)
+ return NULL;
+
+ id16_map = (id16_map_t *)id16_map_hndl;
+
+ total_ids = id16_map->total;
+ ASSERT(total_ids > 0);
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->dbg) {
+ MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
+ id16_map->dbg = NULL;
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+ id16_map->total = 0;
+ MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
+
+ return NULL;
+}
+
+void
+id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16)
+{
+ uint16 idx, val16;
+ id16_map_t * id16_map;
+
+ ASSERT(total_ids > 0);
+ /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
+ * with random values.
+ */
+ ASSERT((start_val16 == ID16_UNDEFINED) ||
+ (start_val16 + total_ids) < ID16_INVALID);
+
+ id16_map = (id16_map_t *)id16_map_hndl;
+ if (id16_map == NULL) {
+ return;
+ }
+
+ id16_map->total = total_ids;
+ id16_map->start = start_val16;
+ id16_map->failures = 0;
+
+ /* Populate stack with 16bit id values, commencing with start_val16 */
+ id16_map->stack_idx = -1;
+
+ if (id16_map->start != ID16_UNDEFINED) {
+ val16 = start_val16;
+
+ for (idx = 0; idx < total_ids; idx++, val16++) {
+ id16_map->stack_idx = idx;
+ id16_map->stack[id16_map->stack_idx] = val16;
+ }
+ }
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->start != ID16_UNDEFINED) {
+ if (id16_map->dbg) {
+ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+ id16_map_dbg->total = total_ids;
+ for (idx = 0; idx < total_ids; idx++) {
+ id16_map_dbg->avail[idx] = TRUE;
+ }
+ }
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+}
+
+uint16 BCMFASTPATH /* Allocate a unique 16bit id */
+id16_map_alloc(void * id16_map_hndl)
+{
+ uint16 val16;
+ id16_map_t * id16_map;
+
+ ASSERT(id16_map_hndl != NULL);
+
+ id16_map = (id16_map_t *)id16_map_hndl;
+
+ ASSERT(id16_map->total > 0);
+
+ if (id16_map->stack_idx < 0) {
+ id16_map->failures++;
+ return ID16_INVALID;
+ }
+
+ val16 = id16_map->stack[id16_map->stack_idx];
+ id16_map->stack_idx--;
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ ASSERT((id16_map->start == ID16_UNDEFINED) ||
+ (val16 < (id16_map->start + id16_map->total)));
+
+ if (id16_map->dbg) { /* Validate val16 */
+ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+ ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
+ id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+ return val16;
+}
+
+
+void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */
+id16_map_free(void * id16_map_hndl, uint16 val16)
+{
+ id16_map_t * id16_map;
+
+ ASSERT(id16_map_hndl != NULL);
+
+ id16_map = (id16_map_t *)id16_map_hndl;
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ ASSERT((id16_map->start == ID16_UNDEFINED) ||
+ (val16 < (id16_map->start + id16_map->total)));
+
+ if (id16_map->dbg) { /* Validate val16 */
+ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+ ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
+ id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+ id16_map->stack_idx++;
+ id16_map->stack[id16_map->stack_idx] = val16;
+}
+
+uint32 /* Returns number of failures to allocate an unique id16 */
+id16_map_failures(void * id16_map_hndl)
+{
+ ASSERT(id16_map_hndl != NULL);
+ return ((id16_map_t *)id16_map_hndl)->failures;
+}
+
+bool
+id16_map_audit(void * id16_map_hndl)
+{
+ int idx;
+ int insane = 0;
+ id16_map_t * id16_map;
+
+ ASSERT(id16_map_hndl != NULL);
+
+ id16_map = (id16_map_t *)id16_map_hndl;
+
+ ASSERT(id16_map->stack_idx >= -1);
+ ASSERT(id16_map->stack_idx < (int)id16_map->total);
+
+ if (id16_map->start == ID16_UNDEFINED)
+ goto done;
+
+ for (idx = 0; idx <= id16_map->stack_idx; idx++) {
+ ASSERT(id16_map->stack[idx] >= id16_map->start);
+ ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->dbg) {
+ uint16 val16 = id16_map->stack[idx];
+ if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
+ insane |= 1;
+ ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
+ OSL_OBFUSATE_BUF(id16_map_hndl), idx, val16));
+ }
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+ }
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->dbg) {
+ uint16 avail = 0; /* Audit available ids counts */
+ for (idx = 0; idx < id16_map_dbg->total; idx++) {
+ if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE)
+ avail++;
+ }
+ if (avail && (avail != (id16_map->stack_idx + 1))) {
+ insane |= 1;
+ ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
+ OSL_OBFUSCATE_BUF(id16_map_hndl),
+ avail, id16_map->stack_idx));
+ }
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+done:
+ /* invoke any other system audits */
+ return (!!insane);
+}
+/* END: Simple id16 allocator */
+
+void
+BCMATTACHFN(dll_pool_detach)(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size)
+{
+ uint32 mem_size;
+ mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
+ if (pool)
+ MFREE(osh, pool, mem_size);
+}
+dll_pool_t *
+BCMATTACHFN(dll_pool_init)(void * osh, uint16 elems_max, uint16 elem_size)
+{
+ uint32 mem_size, i;
+ dll_pool_t * dll_pool_p;
+ dll_t * elem_p;
+
+ ASSERT(elem_size > sizeof(dll_t));
+
+ mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
+
+ if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, mem_size)) == NULL) {
+ printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
+ elems_max, elem_size);
+ ASSERT(0);
+ return dll_pool_p;
+ }
+
+ dll_init(&dll_pool_p->free_list);
+ dll_pool_p->elems_max = elems_max;
+ dll_pool_p->elem_size = elem_size;
+
+ elem_p = dll_pool_p->elements;
+ for (i = 0; i < elems_max; i++) {
+ dll_append(&dll_pool_p->free_list, elem_p);
+ elem_p = (dll_t *)((uintptr)elem_p + elem_size);
+ }
+
+ dll_pool_p->free_count = elems_max;
+
+ return dll_pool_p;
+}
+
+
+void *
+dll_pool_alloc(dll_pool_t * dll_pool_p)
+{
+ dll_t * elem_p;
+
+ if (dll_pool_p->free_count == 0) {
+ ASSERT(dll_empty(&dll_pool_p->free_list));
+ return NULL;
+ }
+
+ elem_p = dll_head_p(&dll_pool_p->free_list);
+ dll_delete(elem_p);
+ dll_pool_p->free_count -= 1;
+
+ return (void *)elem_p;
+}
+
+void
+dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p)
+{
+ dll_t * node_p = (dll_t *)elem_p;
+ dll_prepend(&dll_pool_p->free_list, node_p);
+ dll_pool_p->free_count += 1;
+}
+
+
+void
+dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p)
+{
+ dll_t * node_p = (dll_t *)elem_p;
+ dll_append(&dll_pool_p->free_list, node_p);
+ dll_pool_p->free_count += 1;
+}
+
+#ifdef BCMDBG
+void
+dll_pool_dump(dll_pool_t * dll_pool_p, dll_elem_dump elem_dump)
+{
+ dll_t * elem_p;
+ dll_t * next_p;
+ printf("dll_pool<%p> free_count<%u> elems_max<%u> elem_size<%u>\n",
+ OSL_OBFUSCATE_BUF(dll_pool_p), dll_pool_p->free_count,
+ dll_pool_p->elems_max, dll_pool_p->elem_size);
+
+ for (elem_p = dll_head_p(&dll_pool_p->free_list);
+ !dll_end(&dll_pool_p->free_list, elem_p); elem_p = next_p) {
+
+ next_p = dll_next_p(elem_p);
+ printf("\telem<%p>\n", OSL_OBFUSCATE_BUF(elem_p));
+ if (elem_dump != NULL)
+ elem_dump((void *)elem_p);
+ }
+}
+#endif /* BCMDBG */
+
+#endif
+
+#endif /* BCMDRIVER */
+
+
+#if defined(BCMDRIVER) || defined(WL_UNITTEST)
+
+/* triggers bcm_bprintf to print to kernel log */
+bool bcm_bprintf_bypass = FALSE;
+
+/* Initialization of bcmstrbuf structure */
+void
+bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
+{
+ b->origsize = b->size = size;
+ b->origbuf = b->buf = buf;
+}
+
+/* Buffer sprintf wrapper to guard against buffer overflow */
+int
+bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+
+ r = vsnprintf(b->buf, b->size, fmt, ap);
+ if (bcm_bprintf_bypass == TRUE) {
+ printf(b->buf);
+ goto exit;
+ }
+
+ /* Non Ansi C99 compliant returns -1,
+ * Ansi compliant return r >= b->size,
+ * bcmstdlib returns 0, handle all
+ */
+ /* r == 0 is also the case when strlen(fmt) is zero.
+ * typically the case when "" is passed as argument.
+ */
+ if ((r == -1) || (r >= (int)b->size)) {
+ b->size = 0;
+ } else {
+ b->size -= r;
+ b->buf += r;
+ }
+
+exit:
+ va_end(ap);
+
+ return r;
+}
+
+void
+bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len)
+{
+ int i;
+
+ if (msg != NULL && msg[0] != '\0')
+ bcm_bprintf(b, "%s", msg);
+ for (i = 0; i < len; i ++)
+ bcm_bprintf(b, "%02X", buf[i]);
+ if (newline)
+ bcm_bprintf(b, "\n");
+}
+
+void
+bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
+{
+ int i;
+
+ for (i = 0; i < num_bytes; i++) {
+ num[i] += amount;
+ if (num[i] >= amount)
+ break;
+ amount = 1;
+ }
+}
+
+int
+bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
+{
+ int i;
+
+ for (i = nbytes - 1; i >= 0; i--) {
+ if (arg1[i] != arg2[i])
+ return (arg1[i] - arg2[i]);
+ }
+ return 0;
+}
+
+void
+bcm_print_bytes(const char *name, const uchar *data, int len)
+{
+ int i;
+ int per_line = 0;
+
+ printf("%s: %d \n", name ? name : "", len);
+ for (i = 0; i < len; i++) {
+ printf("%02x ", *data++);
+ per_line++;
+ if (per_line == 16) {
+ per_line = 0;
+ printf("\n");
+ }
+ }
+ printf("\n");
+}
+
+/* Look for vendor-specific IE with specified OUI and optional type */
+bcm_tlv_t *
+bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len)
+{
+ bcm_tlv_t *ie;
+ uint8 ie_len;
+
+ ie = (bcm_tlv_t*)tlvs;
+
+ /* make sure we are looking at a valid IE */
+ if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
+ return NULL;
+ }
+
+ /* Walk through the IEs looking for an OUI match */
+ do {
+ ie_len = ie->len;
+ if ((ie->id == DOT11_MNG_VS_ID) &&
+ (ie_len >= (DOT11_OUI_LEN + type_len)) &&
+ !bcmp(ie->data, voui, DOT11_OUI_LEN))
+ {
+ /* compare optional type */
+ if (type_len == 0 ||
+ !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
+ return (ie); /* a match */
+ }
+ }
+ } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
+
+ return NULL;
+}
+
+#if defined(WLTINYDUMP) || defined(BCMDBG) || defined(WLMSG_INFORM) || \
+ defined(WLMSG_ASSOC) || defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
+#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
+
+int
+bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
+{
+ uint i, c;
+ char *p = buf;
+ char *endp = buf + SSID_FMT_BUF_LEN;
+
+ if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
+
+ for (i = 0; i < ssid_len; i++) {
+ c = (uint)ssid[i];
+ if (c == '\\') {
+ *p++ = '\\';
+ *p++ = '\\';
+ } else if (bcm_isprint((uchar)c)) {
+ *p++ = (char)c;
+ } else {
+ p += snprintf(p, (endp - p), "\\x%02X", c);
+ }
+ }
+ *p = '\0';
+ ASSERT(p < endp);
+
+ return (int)(p - buf);
+}
+#endif /* WLTINYDUMP || BCMDBG || WLMSG_INFORM || WLMSG_ASSOC || WLMSG_PRPKT */
+
+#endif /* BCMDRIVER || WL_UNITTEST */
+
+char *
+bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
+{
+ static const char hex[] =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+ const uint8 *octet = ea->octet;
+ char *p = buf;
+ int i;
+
+ for (i = 0; i < 6; i++, octet++) {
+ *p++ = hex[(*octet >> 4) & 0xf];
+ *p++ = hex[*octet & 0xf];
+ *p++ = ':';
+ }
+
+ *(p-1) = '\0';
+
+ return (buf);
+}
+
+/* Find the position of first bit set
+ * in the given number.
+ */
+int
+bcm_find_fsb(uint32 num)
+{
+ uint8 pos = 0;
+ if (!num)
+ return pos;
+ while (!(num & 1)) {
+ num >>= 1;
+ pos++;
+ }
+ return (pos+1);
+}
+
+char *
+bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
+{
+ snprintf(buf, 16, "%d.%d.%d.%d",
+ ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
+ return (buf);
+}
+
+char *
+bcm_ipv6_ntoa(void *ipv6, char *buf)
+{
+ /* Implementing RFC 5952 Sections 4 + 5 */
+ /* Not thoroughly tested */
+ uint16 tmp[8];
+ uint16 *a = &tmp[0];
+ char *p = buf;
+ int i, i_max = -1, cnt = 0, cnt_max = 1;
+ uint8 *a4 = NULL;
+ memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
+
+ for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
+ if (a[i]) {
+ if (cnt > cnt_max) {
+ cnt_max = cnt;
+ i_max = i - cnt;
+ }
+ cnt = 0;
+ } else
+ cnt++;
+ }
+ if (cnt > cnt_max) {
+ cnt_max = cnt;
+ i_max = i - cnt;
+ }
+ if (i_max == 0 &&
+ /* IPv4-translated: ::ffff:0:a.b.c.d */
+ ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
+ /* IPv4-mapped: ::ffff:a.b.c.d */
+ (cnt_max == 5 && a[5] == 0xffff)))
+ a4 = (uint8*) (a + 6);
+
+ for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
+ if ((uint8*) (a + i) == a4) {
+ snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
+ break;
+ } else if (i == i_max) {
+ *p++ = ':';
+ i += cnt_max - 1;
+ p[0] = ':';
+ p[1] = '\0';
+ } else {
+ if (i)
+ *p++ = ':';
+ p += snprintf(p, 8, "%x", ntoh16(a[i]));
+ }
+ }
+
+ return buf;
+}
+
+#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
+const unsigned char bcm_ctype[] = {
+
+ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
+ _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
+ _BCM_C, /* 8-15 */
+ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
+ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
+ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
+ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
+ _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
+ _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
+ _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
+ _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
+ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
+ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
+ _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
+ _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
+ _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
+ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
+ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
+ _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
+ _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
+ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
+ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
+ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
+ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
+ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
+ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
+ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
+ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
+ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
+ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
+ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
+};
+
+uint64
+bcm_strtoull(const char *cp, char **endp, uint base)
+{
+ uint64 result, last_result = 0, value;
+ bool minus;
+
+ minus = FALSE;
+
+ while (bcm_isspace(*cp))
+ cp++;
+
+ if (cp[0] == '+')
+ cp++;
+ else if (cp[0] == '-') {
+ minus = TRUE;
+ cp++;
+ }
+
+ if (base == 0) {
+ if (cp[0] == '0') {
+ if ((cp[1] == 'x') || (cp[1] == 'X')) {
+ base = 16;
+ cp = &cp[2];
+ } else {
+ base = 8;
+ cp = &cp[1];
+ }
+ } else
+ base = 10;
+ } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
+ cp = &cp[2];
+ }
+
+ result = 0;
+
+ while (bcm_isxdigit(*cp) &&
+ (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
+ result = result*base + value;
+ /* Detected overflow */
+ if (result < last_result && !minus) {
+ if (endp) {
+ /* Go to the end of current number */
+ while (bcm_isxdigit(*cp)) {
+ cp++;
+ }
+ *endp = DISCARD_QUAL(cp, char);
+ }
+ return (ulong)-1;
+ }
+ last_result = result;
+ cp++;
+ }
+
+ if (minus)
+ result = (ulong)(-(long)result);
+
+ if (endp)
+ *endp = DISCARD_QUAL(cp, char);
+
+ return (result);
+}
+
+ulong
+bcm_strtoul(const char *cp, char **endp, uint base)
+{
+ return (ulong) bcm_strtoull(cp, endp, base);
+}
+
+int
+bcm_atoi(const char *s)
+{
+ return (int)bcm_strtoul(s, NULL, 10);
+}
+
+/* return pointer to location of substring 'needle' in 'haystack' */
+char *
+bcmstrstr(const char *haystack, const char *needle)
+{
+ int len, nlen;
+ int i;
+
+ if ((haystack == NULL) || (needle == NULL))
+ return DISCARD_QUAL(haystack, char);
+
+ nlen = (int)strlen(needle);
+ len = (int)strlen(haystack) - nlen + 1;
+
+ for (i = 0; i < len; i++)
+ if (memcmp(needle, &haystack[i], nlen) == 0)
+ return DISCARD_QUAL(&haystack[i], char);
+ return (NULL);
+}
+
+char *
+bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len)
+{
+ for (; s_len >= substr_len; s++, s_len--)
+ if (strncmp(s, substr, substr_len) == 0)
+ return DISCARD_QUAL(s, char);
+
+ return NULL;
+}
+
+char *
+bcmstrcat(char *dest, const char *src)
+{
+ char *p;
+
+ p = dest + strlen(dest);
+
+ while ((*p++ = *src++) != '\0')
+ ;
+
+ return (dest);
+}
+
+char *
+bcmstrncat(char *dest, const char *src, uint size)
+{
+ char *endp;
+ char *p;
+
+ p = dest + strlen(dest);
+ endp = p + size;
+
+ while (p != endp && (*p++ = *src++) != '\0')
+ ;
+
+ return (dest);
+}
+
+
+/****************************************************************************
+* Function: bcmstrtok
+*
+* Purpose:
+* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
+* but allows strToken() to be used by different strings or callers at the same
+* time. Each call modifies '*string' by substituting a NULL character for the
+* first delimiter that is encountered, and updates 'string' to point to the char
+* after the delimiter. Leading delimiters are skipped.
+*
+* Parameters:
+* string (mod) Ptr to string ptr, updated by token.
+* delimiters (in) Set of delimiter characters.
+* tokdelim (out) Character that delimits the returned token. (May
+* be set to NULL if token delimiter is not required).
+*
+* Returns: Pointer to the next token found. NULL when no more tokens are found.
+*****************************************************************************
+*/
+char *
+bcmstrtok(char **string, const char *delimiters, char *tokdelim)
+{
+ unsigned char *str;
+ unsigned long map[8];
+ int count;
+ char *nextoken;
+
+ if (tokdelim != NULL) {
+ /* Prime the token delimiter */
+ *tokdelim = '\0';
+ }
+
+ /* Clear control map */
+ for (count = 0; count < 8; count++) {
+ map[count] = 0;
+ }
+
+ /* Set bits in delimiter table */
+ do {
+ map[*delimiters >> 5] |= (1 << (*delimiters & 31));
+ }
+ while (*delimiters++);
+
+ str = (unsigned char*)*string;
+
+ /* Find beginning of token (skip over leading delimiters). Note that
+ * there is no token iff this loop sets str to point to the terminal
+ * null (*str == '\0')
+ */
+ while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
+ str++;
+ }
+
+ nextoken = (char*)str;
+
+ /* Find the end of the token. If it is not the end of the string,
+ * put a null there.
+ */
+ for (; *str; str++) {
+ if (map[*str >> 5] & (1 << (*str & 31))) {
+ if (tokdelim != NULL) {
+ *tokdelim = *str;
+ }
+
+ *str++ = '\0';
+ break;
+ }
+ }
+
+ *string = (char*)str;
+
+ /* Determine if a token has been found. */
+ if (nextoken == (char *) str) {
+ return NULL;
+ }
+ else {
+ return nextoken;
+ }
+}
+
+
+#define xToLower(C) \
+ ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
+
+
+/****************************************************************************
+* Function: bcmstricmp
+*
+* Purpose: Compare to strings case insensitively.
+*
+* Parameters: s1 (in) First string to compare.
+* s2 (in) Second string to compare.
+*
+* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
+* t1 > t2, when ignoring case sensitivity.
+*****************************************************************************
+*/
+int
+bcmstricmp(const char *s1, const char *s2)
+{
+ char dc, sc;
+
+ while (*s2 && *s1) {
+ dc = xToLower(*s1);
+ sc = xToLower(*s2);
+ if (dc < sc) return -1;
+ if (dc > sc) return 1;
+ s1++;
+ s2++;
+ }
+
+ if (*s1 && !*s2) return 1;
+ if (!*s1 && *s2) return -1;
+ return 0;
+}
+
+
+/****************************************************************************
+* Function: bcmstrnicmp
+*
+* Purpose: Compare to strings case insensitively, upto a max of 'cnt'
+* characters.
+*
+* Parameters: s1 (in) First string to compare.
+* s2 (in) Second string to compare.
+* cnt (in) Max characters to compare.
+*
+* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
+* t1 > t2, when ignoring case sensitivity.
+*****************************************************************************
+*/
+int
+bcmstrnicmp(const char* s1, const char* s2, int cnt)
+{
+ char dc, sc;
+
+ while (*s2 && *s1 && cnt) {
+ dc = xToLower(*s1);
+ sc = xToLower(*s2);
+ if (dc < sc) return -1;
+ if (dc > sc) return 1;
+ s1++;
+ s2++;
+ cnt--;
+ }
+
+ if (!cnt) return 0;
+ if (*s1 && !*s2) return 1;
+ if (!*s1 && *s2) return -1;
+ return 0;
+}
+
+/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
+int
+bcm_ether_atoe(const char *p, struct ether_addr *ea)
+{
+ int i = 0;
+ char *ep;
+
+ for (;;) {
+ ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
+ p = ep;
+ if (!*p++ || i == 6)
+ break;
+ }
+
+ return (i == 6);
+}
+
+int
+bcm_atoipv4(const char *p, struct ipv4_addr *ip)
+{
+
+ int i = 0;
+ char *c;
+ for (;;) {
+ ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0);
+ if (*c++ != '.' || i == IPV4_ADDR_LEN)
+ break;
+ p = c;
+ }
+ return (i == IPV4_ADDR_LEN);
+}
+#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
+
+#ifdef DONGLEBUILD
+
+const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}};
+const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}};
+const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}};
+
+int
+ether_isbcast(const void *ea)
+{
+ return (memcmp(ea, ðer_bcast, sizeof(struct ether_addr)) == 0);
+}
+
+int
+ether_isnulladdr(const void *ea)
+{
+ uint8 *u8 = (uint8*)ea;
+ return !(u8[5] || u8[4] || u8[3] || u8[2] || u8[1] || u8[0]);
+}
+
+#endif /* DONGLEBUILD */
+
+#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
+/* registry routine buffer preparation utility functions:
+ * parameter order is like strncpy, but returns count
+ * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
+ */
+ulong
+wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
+{
+ ulong copyct = 1;
+ ushort i;
+
+ if (abuflen == 0)
+ return 0;
+
+ /* wbuflen is in bytes */
+ wbuflen /= sizeof(ushort);
+
+ for (i = 0; i < wbuflen; ++i) {
+ if (--abuflen == 0)
+ break;
+ *abuf++ = (char) *wbuf++;
+ ++copyct;
+ }
+ *abuf = '\0';
+
+ return copyct;
+}
+#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
+
+#ifdef BCM_OBJECT_TRACE
+
+#define BCM_OBJECT_MERGE_SAME_OBJ 0
+
+/* some place may add / remove the object to trace list for Linux: */
+/* add: osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */
+/* remove: osl_pktfree dev_kfree_skb netif_rx */
+
+#if defined(linux)
+#define BCM_OBJDBG_COUNT (1024 * 100)
+static spinlock_t dbgobj_lock;
+#define BCM_OBJDBG_LOCK_INIT() spin_lock_init(&dbgobj_lock)
+#define BCM_OBJDBG_LOCK_DESTROY()
+#define BCM_OBJDBG_LOCK spin_lock_irqsave
+#define BCM_OBJDBG_UNLOCK spin_unlock_irqrestore
+#elif defined(__FreeBSD__)
+#define BCM_OBJDBG_COUNT (1024 * 100)
+struct mtx dbgobj_lock;
+#define BCM_OBJDBG_LOCK_INIT() MTX_INIT(&dbgobj_lock, "objdbg", NULL, MTX_DEF)
+#define BCM_OBJDBG_LOCK_DESTROY() MTX_DESTROY(&dbgobj_lock)
+#define BCM_OBJDBG_LOCK(x, y) MTX_LOCK(x)
+#define BCM_OBJDBG_UNLOCK(x, y) MTX_UNLOCK(x)
+#else
+#define BCM_OBJDBG_COUNT (256)
+#define BCM_OBJDBG_LOCK_INIT()
+#define BCM_OBJDBG_LOCK_DESTROY()
+#define BCM_OBJDBG_LOCK(x, y)
+#define BCM_OBJDBG_UNLOCK(x, y)
+#endif /* else OS */
+
+#define BCM_OBJDBG_ADDTOHEAD 0
+#define BCM_OBJDBG_ADDTOTAIL 1
+
+#define BCM_OBJDBG_CALLER_LEN 32
+struct bcm_dbgobj {
+ struct bcm_dbgobj *prior;
+ struct bcm_dbgobj *next;
+ uint32 flag;
+ void *obj;
+ uint32 obj_sn;
+ uint32 obj_state;
+ uint32 line;
+ char caller[BCM_OBJDBG_CALLER_LEN];
+};
+
+static struct bcm_dbgobj *dbgobj_freehead = NULL;
+static struct bcm_dbgobj *dbgobj_freetail = NULL;
+static struct bcm_dbgobj *dbgobj_objhead = NULL;
+static struct bcm_dbgobj *dbgobj_objtail = NULL;
+
+static uint32 dbgobj_sn = 0;
+static int dbgobj_count = 0;
+static struct bcm_dbgobj bcm_dbg_objs[BCM_OBJDBG_COUNT];
+
+void
+bcm_object_trace_init(void)
+{
+ int i = 0;
+ BCM_OBJDBG_LOCK_INIT();
+ memset(&bcm_dbg_objs, 0x00, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT);
+ dbgobj_freehead = &bcm_dbg_objs[0];
+ dbgobj_freetail = &bcm_dbg_objs[BCM_OBJDBG_COUNT - 1];
+
+ for (i = 0; i < BCM_OBJDBG_COUNT; ++i) {
+ bcm_dbg_objs[i].next = (i == (BCM_OBJDBG_COUNT - 1)) ?
+ dbgobj_freehead : &bcm_dbg_objs[i + 1];
+ bcm_dbg_objs[i].prior = (i == 0) ?
+ dbgobj_freetail : &bcm_dbg_objs[i - 1];
+ }
+}
+
+void
+bcm_object_trace_deinit(void)
+{
+ if (dbgobj_objhead || dbgobj_objtail) {
+ printf("%s: not all objects are released\n", __FUNCTION__);
+ ASSERT(0);
+ }
+ BCM_OBJDBG_LOCK_DESTROY();
+}
+
+static void
+bcm_object_rm_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
+ struct bcm_dbgobj *dbgobj)
+{
+ if ((dbgobj == *head) && (dbgobj == *tail)) {
+ *head = NULL;
+ *tail = NULL;
+ } else if (dbgobj == *head) {
+ *head = (*head)->next;
+ } else if (dbgobj == *tail) {
+ *tail = (*tail)->prior;
+ }
+ dbgobj->next->prior = dbgobj->prior;
+ dbgobj->prior->next = dbgobj->next;
+}
+
+static void
+bcm_object_add_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
+ struct bcm_dbgobj *dbgobj, int addtotail)
+{
+ if (!(*head) && !(*tail)) {
+ *head = dbgobj;
+ *tail = dbgobj;
+ dbgobj->next = dbgobj;
+ dbgobj->prior = dbgobj;
+ } else if ((*head) && (*tail)) {
+ (*tail)->next = dbgobj;
+ (*head)->prior = dbgobj;
+ dbgobj->next = *head;
+ dbgobj->prior = *tail;
+ if (addtotail == BCM_OBJDBG_ADDTOTAIL)
+ *tail = dbgobj;
+ else
+ *head = dbgobj;
+ } else {
+ ASSERT(0); /* can't be this case */
+ }
+}
+
+static INLINE void
+bcm_object_movetoend(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
+ struct bcm_dbgobj *dbgobj, int movetotail)
+{
+ if ((*head) && (*tail)) {
+ if (movetotail == BCM_OBJDBG_ADDTOTAIL) {
+ if (dbgobj != (*tail)) {
+ bcm_object_rm_list(head, tail, dbgobj);
+ bcm_object_add_list(head, tail, dbgobj, movetotail);
+ }
+ } else {
+ if (dbgobj != (*head)) {
+ bcm_object_rm_list(head, tail, dbgobj);
+ bcm_object_add_list(head, tail, dbgobj, movetotail);
+ }
+ }
+ } else {
+ ASSERT(0); /* can't be this case */
+ }
+}
+
+void
+bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line)
+{
+ struct bcm_dbgobj *dbgobj;
+ unsigned long flags;
+
+ BCM_REFERENCE(flags);
+ BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
+
+ if (opt == BCM_OBJDBG_ADD_PKT ||
+ opt == BCM_OBJDBG_ADD) {
+ dbgobj = dbgobj_objtail;
+ while (dbgobj) {
+ if (dbgobj->obj == obj) {
+ printf("%s: obj %p allocated from %s(%d),"
+ " allocate again from %s(%d)\n",
+ __FUNCTION__, dbgobj->obj,
+ dbgobj->caller, dbgobj->line,
+ caller, line);
+ ASSERT(0);
+ goto EXIT;
+ }
+ dbgobj = dbgobj->prior;
+ if (dbgobj == dbgobj_objtail)
+ break;
+ }
+
+#if BCM_OBJECT_MERGE_SAME_OBJ
+ dbgobj = dbgobj_freetail;
+ while (dbgobj) {
+ if (dbgobj->obj == obj) {
+ goto FREED_ENTRY_FOUND;
+ }
+ dbgobj = dbgobj->prior;
+ if (dbgobj == dbgobj_freetail)
+ break;
+ }
+#endif /* BCM_OBJECT_MERGE_SAME_OBJ */
+
+ dbgobj = dbgobj_freehead;
+#if BCM_OBJECT_MERGE_SAME_OBJ
+FREED_ENTRY_FOUND:
+#endif /* BCM_OBJECT_MERGE_SAME_OBJ */
+ if (!dbgobj) {
+ printf("%s: already got %d objects ?????????????????????\n",
+ __FUNCTION__, BCM_OBJDBG_COUNT);
+ ASSERT(0);
+ goto EXIT;
+ }
+
+ bcm_object_rm_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj);
+ dbgobj->obj = obj;
+ strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
+ dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0';
+ dbgobj->line = line;
+ dbgobj->flag = 0;
+ if (opt == BCM_OBJDBG_ADD_PKT) {
+ dbgobj->obj_sn = dbgobj_sn++;
+ dbgobj->obj_state = 0;
+ /* first 4 bytes is pkt sn */
+ if (((unsigned long)PKTTAG(obj)) & 0x3)
+ printf("pkt tag address not aligned by 4: %p\n", PKTTAG(obj));
+ *(uint32*)PKTTAG(obj) = dbgobj->obj_sn;
+ }
+ bcm_object_add_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
+ BCM_OBJDBG_ADDTOTAIL);
+
+ dbgobj_count++;
+
+ } else if (opt == BCM_OBJDBG_REMOVE) {
+ dbgobj = dbgobj_objtail;
+ while (dbgobj) {
+ if (dbgobj->obj == obj) {
+ if (dbgobj->flag) {
+ printf("%s: rm flagged obj %p flag 0x%08x from %s(%d)\n",
+ __FUNCTION__, obj, dbgobj->flag, caller, line);
+ }
+ bcm_object_rm_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj);
+ memset(dbgobj->caller, 0x00, BCM_OBJDBG_CALLER_LEN);
+ strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
+ dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0';
+ dbgobj->line = line;
+ bcm_object_add_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj,
+ BCM_OBJDBG_ADDTOTAIL);
+ dbgobj_count--;
+ goto EXIT;
+ }
+ dbgobj = dbgobj->prior;
+ if (dbgobj == dbgobj_objtail)
+ break;
+ }
+
+ dbgobj = dbgobj_freetail;
+ while (dbgobj && dbgobj->obj) {
+ if (dbgobj->obj == obj) {
+ printf("%s: obj %p already freed from from %s(%d),"
+ " try free again from %s(%d)\n",
+ __FUNCTION__, obj,
+ dbgobj->caller, dbgobj->line,
+ caller, line);
+ //ASSERT(0); /* release same obj more than one time? */
+ goto EXIT;
+ }
+ dbgobj = dbgobj->prior;
+ if (dbgobj == dbgobj_freetail)
+ break;
+ }
+
+ printf("%s: ################### release none-existing obj %p from %s(%d)\n",
+ __FUNCTION__, obj, caller, line);
+ //ASSERT(0); /* release same obj more than one time? */
+
+ }
+
+EXIT:
+ BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
+ return;
+}
+
+void
+bcm_object_trace_upd(void *obj, void *obj_new)
+{
+ struct bcm_dbgobj *dbgobj;
+ unsigned long flags;
+
+ BCM_REFERENCE(flags);
+ BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
+
+ dbgobj = dbgobj_objtail;
+ while (dbgobj) {
+ if (dbgobj->obj == obj) {
+ dbgobj->obj = obj_new;
+ if (dbgobj != dbgobj_objtail) {
+ bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
+ dbgobj, BCM_OBJDBG_ADDTOTAIL);
+ }
+ goto EXIT;
+ }
+ dbgobj = dbgobj->prior;
+ if (dbgobj == dbgobj_objtail)
+ break;
+ }
+
+EXIT:
+ BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
+ return;
+}
+
+void
+bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn,
+ const char *caller, int line)
+{
+ struct bcm_dbgobj *dbgobj;
+ unsigned long flags;
+
+ BCM_REFERENCE(flags);
+ BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
+
+ dbgobj = dbgobj_objtail;
+ while (dbgobj) {
+ if ((dbgobj->obj == obj) &&
+ ((!chksn) || (dbgobj->obj_sn == sn))) {
+ if (dbgobj != dbgobj_objtail) {
+ bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
+ dbgobj, BCM_OBJDBG_ADDTOTAIL);
+ }
+ goto EXIT;
+ }
+ dbgobj = dbgobj->prior;
+ if (dbgobj == dbgobj_objtail)
+ break;
+ }
+
+ dbgobj = dbgobj_freetail;
+ while (dbgobj) {
+ if ((dbgobj->obj == obj) &&
+ ((!chksn) || (dbgobj->obj_sn == sn))) {
+ printf("%s: (%s:%d) obj %p (sn %d state %d) was freed from %s(%d)\n",
+ __FUNCTION__, caller, line,
+ dbgobj->obj, dbgobj->obj_sn, dbgobj->obj_state,
+ dbgobj->caller, dbgobj->line);
+ goto EXIT;
+ }
+ else if (dbgobj->obj == NULL) {
+ break;
+ }
+ dbgobj = dbgobj->prior;
+ if (dbgobj == dbgobj_freetail)
+ break;
+ }
+
+ printf("%s: obj %p not found, check from %s(%d), chksn %s, sn %d\n",
+ __FUNCTION__, obj, caller, line, chksn ? "yes" : "no", sn);
+ dbgobj = dbgobj_objtail;
+ while (dbgobj) {
+ printf("%s: (%s:%d) obj %p sn %d was allocated from %s(%d)\n",
+ __FUNCTION__, caller, line,
+ dbgobj->obj, dbgobj->obj_sn, dbgobj->caller, dbgobj->line);
+ dbgobj = dbgobj->prior;
+ if (dbgobj == dbgobj_objtail)
+ break;
+ }
+
+EXIT:
+ BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
+ return;
+}
+
+void
+bcm_object_feature_set(void *obj, uint32 type, uint32 value)
+{
+ struct bcm_dbgobj *dbgobj;
+ unsigned long flags;
+
+ BCM_REFERENCE(flags);
+ BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
+
+ dbgobj = dbgobj_objtail;
+ while (dbgobj) {
+ if (dbgobj->obj == obj) {
+ if (type == BCM_OBJECT_FEATURE_FLAG) {
+ if (value & BCM_OBJECT_FEATURE_CLEAR)
+ dbgobj->flag &= ~(value);
+ else
+ dbgobj->flag |= (value);
+ } else if (type == BCM_OBJECT_FEATURE_PKT_STATE) {
+ dbgobj->obj_state = value;
+ }
+ if (dbgobj != dbgobj_objtail) {
+ bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
+ dbgobj, BCM_OBJDBG_ADDTOTAIL);
+ }
+ goto EXIT;
+ }
+ dbgobj = dbgobj->prior;
+ if (dbgobj == dbgobj_objtail)
+ break;
+ }
+
+ printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
+ ASSERT(0);
+
+EXIT:
+ BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
+ return;
+}
+
+int
+bcm_object_feature_get(void *obj, uint32 type, uint32 value)
+{
+ int rtn = 0;
+ struct bcm_dbgobj *dbgobj;
+ unsigned long flags;
+
+ BCM_REFERENCE(flags);
+ BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
+
+ dbgobj = dbgobj_objtail;
+ while (dbgobj) {
+ if (dbgobj->obj == obj) {
+ if (type == BCM_OBJECT_FEATURE_FLAG) {
+ rtn = (dbgobj->flag & value) & (~BCM_OBJECT_FEATURE_CLEAR);
+ }
+ if (dbgobj != dbgobj_objtail) {
+ bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
+ dbgobj, BCM_OBJDBG_ADDTOTAIL);
+ }
+ goto EXIT;
+ }
+ dbgobj = dbgobj->prior;
+ if (dbgobj == dbgobj_objtail)
+ break;
+ }
+
+ printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
+ ASSERT(0);
+
+EXIT:
+ BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
+ return rtn;
+}
+
+#endif /* BCM_OBJECT_TRACE */
+
+uint8 *
+bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst)
+{
+ uint8 *new_dst = dst;
+ bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst;
+
+ /* dst buffer should always be valid */
+ ASSERT(dst);
+
+ /* data len must be within valid range */
+ ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE));
+
+ /* source data buffer pointer should be valid, unless datalen is 0
+ * meaning no data with this TLV
+ */
+ ASSERT((data != NULL) || (datalen == 0));
+
+ /* only do work if the inputs are valid
+ * - must have a dst to write to AND
+ * - datalen must be within range AND
+ * - the source data pointer must be non-NULL if datalen is non-zero
+ * (this last condition detects datalen > 0 with a NULL data pointer)
+ */
+ if ((dst != NULL) &&
+ ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) &&
+ ((data != NULL) || (datalen == 0))) {
+
+ /* write type, len fields */
+ dst_tlv->id = (uint8)type;
+ dst_tlv->len = (uint8)datalen;
+
+ /* if data is present, copy to the output buffer and update
+ * pointer to output buffer
+ */
+ if (datalen > 0) {
+
+ memcpy(dst_tlv->data, data, datalen);
+ }
+
+ /* update the output destination poitner to point past
+ * the TLV written
+ */
+ new_dst = dst + BCM_TLV_HDR_SIZE + datalen;
+ }
+
+ return (new_dst);
+}
+
+uint8 *
+bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen)
+{
+ uint8 *new_dst = dst;
+
+ if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) {
+
+ /* if len + tlv hdr len is more than destlen, don't do anything
+ * just return the buffer untouched
+ */
+ if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) {
+
+ new_dst = bcm_write_tlv(type, data, datalen, dst);
+ }
+ }
+
+ return (new_dst);
+}
+
+uint8 *
+bcm_copy_tlv(const void *src, uint8 *dst)
+{
+ uint8 *new_dst = dst;
+ const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
+ uint totlen;
+
+ ASSERT(dst && src);
+ if (dst && src) {
+
+ totlen = BCM_TLV_HDR_SIZE + src_tlv->len;
+ memcpy(dst, src_tlv, totlen);
+ new_dst = dst + totlen;
+ }
+
+ return (new_dst);
+}
+
+
+uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen)
+{
+ uint8 *new_dst = dst;
+ const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
+
+ ASSERT(src);
+ if (src) {
+ if (bcm_valid_tlv(src_tlv, dst_maxlen)) {
+ new_dst = bcm_copy_tlv(src, dst);
+ }
+ }
+
+ return (new_dst);
+}
+
+
+#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
+/*******************************************************************************
+ * crc8
+ *
+ * Computes a crc8 over the input data using the polynomial:
+ *
+ * x^8 + x^7 +x^6 + x^4 + x^2 + 1
+ *
+ * The caller provides the initial value (either CRC8_INIT_VALUE
+ * or the previous returned value) to allow for processing of
+ * discontiguous blocks of data. When generating the CRC the
+ * caller is responsible for complementing the final return value
+ * and inserting it into the byte stream. When checking, a final
+ * return value of CRC8_GOOD_VALUE indicates a valid CRC.
+ *
+ * Reference: Dallas Semiconductor Application Note 27
+ * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
+ * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
+ * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
+ *
+ * ****************************************************************************
+ */
+
+static const uint8 crc8_table[256] = {
+ 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+ 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+ 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+ 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+ 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+ 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+ 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+ 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+ 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+ 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+ 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+ 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+ 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+ 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+ 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+ 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+ 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+ 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+ 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+ 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+ 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+ 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+ 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+ 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+ 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+ 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+ 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+ 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+ 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+ 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+ 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+ 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
+};
+
+#define CRC_INNER_LOOP(n, c, x) \
+ (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
+
+uint8
+hndcrc8(
+ uint8 *pdata, /* pointer to array of data to process */
+ uint nbytes, /* number of input data bytes to process */
+ uint8 crc /* either CRC8_INIT_VALUE or previous return value */
+)
+{
+ /* hard code the crc loop instead of using CRC_INNER_LOOP macro
+ * to avoid the undefined and unnecessary (uint8 >> 8) operation.
+ */
+ while (nbytes-- > 0)
+ crc = crc8_table[(crc ^ *pdata++) & 0xff];
+
+ return crc;
+}
+
+/*******************************************************************************
+ * crc16
+ *
+ * Computes a crc16 over the input data using the polynomial:
+ *
+ * x^16 + x^12 +x^5 + 1
+ *
+ * The caller provides the initial value (either CRC16_INIT_VALUE
+ * or the previous returned value) to allow for processing of
+ * discontiguous blocks of data. When generating the CRC the
+ * caller is responsible for complementing the final return value
+ * and inserting it into the byte stream. When checking, a final
+ * return value of CRC16_GOOD_VALUE indicates a valid CRC.
+ *
+ * Reference: Dallas Semiconductor Application Note 27
+ * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
+ * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
+ * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
+ *
+ * ****************************************************************************
+ */
+
+static const uint16 crc16_table[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
+ 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
+ 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
+ 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
+ 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
+ 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
+ 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
+ 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
+ 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
+ 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
+ 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
+ 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
+ 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
+ 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
+ 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
+ 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
+ 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
+ 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
+ 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
+ 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
+ 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
+ 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
+ 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
+ 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
+ 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
+ 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
+ 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
+ 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
+ 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
+ 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
+ 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
+ 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
+};
+
+uint16
+hndcrc16(
+ uint8 *pdata, /* pointer to array of data to process */
+ uint nbytes, /* number of input data bytes to process */
+ uint16 crc /* either CRC16_INIT_VALUE or previous return value */
+)
+{
+ while (nbytes-- > 0)
+ CRC_INNER_LOOP(16, crc, *pdata++);
+ return crc;
+}
+
+static const uint32 crc32_table[256] = {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
+ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
+ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
+ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
+ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
+ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
+ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
+ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
+ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
+ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
+ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
+ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
+ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
+ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
+ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
+ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
+ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
+ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+/*
+ * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
+ * accumulating over multiple pieces.
+ */
+uint32
+hndcrc32(uint8 *pdata, uint nbytes, uint32 crc)
+{
+ uint8 *pend;
+#ifdef __mips__
+ uint8 tmp[4];
+ ulong *tptr = (ulong *)tmp;
+
+ if (nbytes > 3) {
+ /* in case the beginning of the buffer isn't aligned */
+ pend = (uint8 *)((uint)(pdata + 3) & ~0x3);
+ nbytes -= (pend - pdata);
+ while (pdata < pend)
+ CRC_INNER_LOOP(32, crc, *pdata++);
+ }
+
+ if (nbytes > 3) {
+ /* handle bulk of data as 32-bit words */
+ pend = pdata + (nbytes & ~0x3);
+ while (pdata < pend) {
+ *tptr = *(ulong *)pdata;
+ pdata += sizeof(ulong *);
+ CRC_INNER_LOOP(32, crc, tmp[0]);
+ CRC_INNER_LOOP(32, crc, tmp[1]);
+ CRC_INNER_LOOP(32, crc, tmp[2]);
+ CRC_INNER_LOOP(32, crc, tmp[3]);
+ }
+ }
+
+ /* 1-3 bytes at end of buffer */
+ pend = pdata + (nbytes & 0x03);
+ while (pdata < pend)
+ CRC_INNER_LOOP(32, crc, *pdata++);
+#else
+ pend = pdata + nbytes;
+ while (pdata < pend)
+ CRC_INNER_LOOP(32, crc, *pdata++);
+#endif /* __mips__ */
+
+ return crc;
+}
+
+#ifdef notdef
+#define CLEN 1499 /* CRC Length */
+#define CBUFSIZ (CLEN+4)
+#define CNBUFS 5 /* # of bufs */
+
+void
+testcrc32(void)
+{
+ uint j, k, l;
+ uint8 *buf;
+ uint len[CNBUFS];
+ uint32 crcr;
+ uint32 crc32tv[CNBUFS] =
+ {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
+
+ ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
+
+ /* step through all possible alignments */
+ for (l = 0; l <= 4; l++) {
+ for (j = 0; j < CNBUFS; j++) {
+ len[j] = CLEN;
+ for (k = 0; k < len[j]; k++)
+ *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
+ }
+
+ for (j = 0; j < CNBUFS; j++) {
+ crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
+ ASSERT(crcr == crc32tv[j]);
+ }
+ }
+
+ MFREE(buf, CBUFSIZ*CNBUFS);
+ return;
+}
+#endif /* notdef */
+
+/*
+ * Advance from the current 1-byte tag/1-byte length/variable-length value
+ * triple, to the next, returning a pointer to the next.
+ * If the current or next TLV is invalid (does not fit in given buffer length),
+ * NULL is returned.
+ * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
+ * by the TLV parameter's length if it is valid.
+ */
+bcm_tlv_t *
+bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
+{
+ int len;
+
+ /* validate current elt */
+ if (!bcm_valid_tlv(elt, *buflen)) {
+ return NULL;
+ }
+
+ /* advance to next elt */
+ len = elt->len;
+ elt = (bcm_tlv_t*)(elt->data + len);
+ *buflen -= (TLV_HDR_LEN + len);
+
+ /* validate next elt */
+ if (!bcm_valid_tlv(elt, *buflen)) {
+ return NULL;
+ }
+
+ return elt;
+}
+
+/*
+ * Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
+ * matches tag
+ */
+bcm_tlv_t *
+bcm_parse_tlvs(void *buf, int buflen, uint key)
+{
+ bcm_tlv_t *elt;
+ int totlen;
+
+ if ((elt = (bcm_tlv_t*)buf) == NULL) {
+ return NULL;
+ }
+ totlen = buflen;
+
+ /* find tagged parameter */
+ while (totlen >= TLV_HDR_LEN) {
+ int len = elt->len;
+
+ /* validate remaining totlen */
+ if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
+
+ return (elt);
+ }
+
+ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
+ totlen -= (len + TLV_HDR_LEN);
+ }
+
+ return NULL;
+}
+
+bcm_tlv_t *
+bcm_parse_tlvs_dot11(void *buf, int buflen, uint key, bool id_ext)
+{
+ bcm_tlv_t *elt;
+ int totlen;
+
+ elt = (bcm_tlv_t*)buf;
+ totlen = buflen;
+
+ /* find tagged parameter */
+ while (totlen >= TLV_HDR_LEN) {
+ int len = elt->len;
+
+ do {
+ /* validate remaining totlen */
+ if (totlen < (int)(len + TLV_HDR_LEN))
+ break;
+
+ if (id_ext) {
+ if (!DOT11_MNG_IE_ID_EXT_MATCH(elt, key))
+ break;
+ } else if (elt->id != key) {
+ break;
+ }
+
+ return (elt);
+ } while (0);
+
+ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
+ totlen -= (len + TLV_HDR_LEN);
+ }
+
+ return NULL;
+}
+
+/*
+ * Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
+ * matches tag
+ * return NULL if not found or length field < min_varlen
+ */
+bcm_tlv_t *
+bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen)
+{
+ bcm_tlv_t * ret;
+ ret = bcm_parse_tlvs(buf, buflen, key);
+ if (ret == NULL || ret->len < min_bodylen) {
+ return NULL;
+ }
+ return ret;
+}
+
+/*
+ * Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
+ * matches tag. Stop parsing when we see an element whose ID is greater
+ * than the target key.
+ */
+bcm_tlv_t *
+bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
+{
+ bcm_tlv_t *elt;
+ int totlen;
+
+ elt = (bcm_tlv_t*)buf;
+ totlen = buflen;
+
+ /* find tagged parameter */
+ while (totlen >= TLV_HDR_LEN) {
+ uint id = elt->id;
+ int len = elt->len;
+
+ /* Punt if we start seeing IDs > than target key */
+ if (id > key) {
+ return (NULL);
+ }
+
+ /* validate remaining totlen */
+ if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
+ return (elt);
+ }
+
+ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
+ totlen -= (len + TLV_HDR_LEN);
+ }
+ return NULL;
+}
+#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
+
+#if defined(BCMDBG) || defined(BCMDBG_ERR) || defined(WLMSG_PRHDRS) || \
+ defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || defined(BCMDBG_DUMP) || \
+ defined(DHD_DEBUG)
+int
+bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len)
+{
+ int i, slen = 0;
+ uint32 bit, mask;
+ const char *name;
+ mask = bd->mask;
+ if (len < 2 || !buf)
+ return 0;
+
+ buf[0] = '\0';
+
+ for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) {
+ bit = bd->bitfield[i].bit;
+ if ((flags & mask) == bit) {
+ if (len > (int)strlen(name)) {
+ slen = strlen(name);
+ strncpy(buf, name, slen+1);
+ }
+ break;
+ }
+ }
+ return slen;
+}
+
+int
+bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
+{
+ int i;
+ char* p = buf;
+ char hexstr[16];
+ int slen = 0, nlen = 0;
+ uint32 bit;
+ const char* name;
+
+ if (len < 2 || !buf)
+ return 0;
+
+ buf[0] = '\0';
+
+ for (i = 0; flags != 0; i++) {
+ bit = bd[i].bit;
+ name = bd[i].name;
+ if (bit == 0 && flags != 0) {
+ /* print any unnamed bits */
+ snprintf(hexstr, 16, "0x%X", flags);
+ name = hexstr;
+ flags = 0; /* exit loop */
+ } else if ((flags & bit) == 0)
+ continue;
+ flags &= ~bit;
+ nlen = strlen(name);
+ slen += nlen;
+ /* count btwn flag space */
+ if (flags != 0)
+ slen += 1;
+ /* need NULL char as well */
+ if (len <= slen)
+ break;
+ /* copy NULL char but don't count it */
+ strncpy(p, name, nlen + 1);
+ p += nlen;
+ /* copy btwn flag space and NULL char */
+ if (flags != 0)
+ p += snprintf(p, 2, " ");
+ }
+
+ /* indicate the str was too short */
+ if (flags != 0) {
+ p += snprintf(p, 2, ">");
+ }
+
+ return (int)(p - buf);
+}
+#endif /* BCMDBG || WLMSG_PRHDRS || WLMSG_PRPKT || WLMSG_ASSOC || BCMDBG_DUMP || DHD_DEBUG */
+
+/* print bytes formatted as hex to a string. return the resulting string length */
+int
+bcm_format_hex(char *str, const void *bytes, int len)
+{
+ int i;
+ char *p = str;
+ const uint8 *src = (const uint8*)bytes;
+
+ for (i = 0; i < len; i++) {
+ p += snprintf(p, 3, "%02X", *src);
+ src++;
+ }
+ return (int)(p - str);
+}
+
+/* pretty hex print a contiguous buffer */
+void
+prhex(const char *msg, const uchar *buf, uint nbytes)
+{
+ char line[128], *p;
+ int len = sizeof(line);
+ int nchar;
+ uint i;
+
+ if (msg && (msg[0] != '\0'))
+ printf("%s:\n", msg);
+
+ p = line;
+ for (i = 0; i < nbytes; i++) {
+ if (i % 16 == 0) {
+ nchar = snprintf(p, len, " %04x: ", i); /* line prefix */
+ p += nchar;
+ len -= nchar;
+ }
+ if (len > 0) {
+ nchar = snprintf(p, len, "%02x ", buf[i]);
+ p += nchar;
+ len -= nchar;
+ }
+
+ if (i % 16 == 15) {
+ printf("%s\n", line); /* flush line */
+ p = line;
+ len = sizeof(line);
+ }
+ }
+
+ /* flush last partial line */
+ if (p != line)
+ printf("%s\n", line);
+}
+
+static const char *crypto_algo_names[] = {
+ "NONE",
+ "WEP1",
+ "TKIP",
+ "WEP128",
+ "AES_CCM",
+ "AES_OCB_MSDU",
+ "AES_OCB_MPDU",
+ "NALG",
+ "UNDEF",
+ "UNDEF",
+ "UNDEF",
+#ifdef BCMWAPI_WAI
+ "WAPI",
+#else
+ "UNDEF"
+#endif
+ "PMK",
+ "BIP",
+ "AES_GCM",
+ "AES_CCM256",
+ "AES_GCM256",
+ "BIP_CMAC256",
+ "BIP_GMAC",
+ "BIP_GMAC256",
+ "UNDEF"
+};
+
+const char *
+bcm_crypto_algo_name(uint algo)
+{
+ return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
+}
+
+#ifdef BCMDBG
+void
+deadbeef(void *p, uint len)
+{
+ static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
+
+ while (len-- > 0) {
+ *(uint8*)p = meat[((uintptr)p) & 3];
+ p = (uint8*)p + 1;
+ }
+}
+#endif /* BCMDBG */
+
+char *
+bcm_chipname(uint chipid, char *buf, uint len)
+{
+ const char *fmt;
+
+ fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
+ snprintf(buf, len, fmt, chipid);
+ return buf;
+}
+
+/* Produce a human-readable string for boardrev */
+char *
+bcm_brev_str(uint32 brev, char *buf)
+{
+ if (brev < 0x100)
+ snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
+ else
+ snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
+
+ return (buf);
+}
+
+#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
+
+/* dump large strings to console */
+void
+printbig(char *buf)
+{
+ uint len, max_len;
+ char c;
+
+ len = (uint)strlen(buf);
+
+ max_len = BUFSIZE_TODUMP_ATONCE;
+
+ while (len > max_len) {
+ c = buf[max_len];
+ buf[max_len] = '\0';
+ printf("%s", buf);
+ buf[max_len] = c;
+
+ buf += max_len;
+ len -= max_len;
+ }
+ /* print the remaining string */
+ printf("%s\n", buf);
+ return;
+}
+
+/* routine to dump fields in a fileddesc structure */
+uint
+bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
+ char *buf, uint32 bufsize)
+{
+ uint filled_len;
+ int len;
+ struct fielddesc *cur_ptr;
+
+ filled_len = 0;
+ cur_ptr = fielddesc_array;
+
+ while (bufsize > 1) {
+ if (cur_ptr->nameandfmt == NULL)
+ break;
+ len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
+ read_rtn(arg0, arg1, cur_ptr->offset));
+ /* check for snprintf overflow or error */
+ if (len < 0 || (uint32)len >= bufsize)
+ len = bufsize - 1;
+ buf += len;
+ bufsize -= len;
+ filled_len += len;
+ cur_ptr++;
+ }
+ return filled_len;
+}
+
+uint
+bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint buflen)
+{
+ uint len;
+
+ len = (uint)strlen(name) + 1;
+
+ if ((len + datalen) > buflen)
+ return 0;
+
+ strncpy(buf, name, buflen);
+
+ /* append data onto the end of the name string */
+ if (data) {
+ memcpy(&buf[len], data, datalen);
+ len += datalen;
+ }
+
+ return len;
+}
+
+/* Quarter dBm units to mW
+ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
+ * Table is offset so the last entry is largest mW value that fits in
+ * a uint16.
+ */
+
+#define QDBM_OFFSET 153 /* Offset for first entry */
+#define QDBM_TABLE_LEN 40 /* Table size */
+
+/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
+ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
+ */
+#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
+
+/* Largest mW value that will round down to the last table entry,
+ * QDBM_OFFSET + QDBM_TABLE_LEN-1.
+ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
+ */
+#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
+
+static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
+/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
+/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
+/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
+/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
+/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
+/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
+};
+
+uint16
+bcm_qdbm_to_mw(uint8 qdbm)
+{
+ uint factor = 1;
+ int idx = qdbm - QDBM_OFFSET;
+
+ if (idx >= QDBM_TABLE_LEN) {
+ /* clamp to max uint16 mW value */
+ return 0xFFFF;
+ }
+
+ /* scale the qdBm index up to the range of the table 0-40
+ * where an offset of 40 qdBm equals a factor of 10 mW.
+ */
+ while (idx < 0) {
+ idx += 40;
+ factor *= 10;
+ }
+
+ /* return the mW value scaled down to the correct factor of 10,
+ * adding in factor/2 to get proper rounding.
+ */
+ return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
+}
+
+uint8
+bcm_mw_to_qdbm(uint16 mw)
+{
+ uint8 qdbm;
+ int offset;
+ uint mw_uint = mw;
+ uint boundary;
+
+ /* handle boundary case */
+ if (mw_uint <= 1)
+ return 0;
+
+ offset = QDBM_OFFSET;
+
+ /* move mw into the range of the table */
+ while (mw_uint < QDBM_TABLE_LOW_BOUND) {
+ mw_uint *= 10;
+ offset -= 40;
+ }
+
+ for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
+ boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
+ nqdBm_to_mW_map[qdbm])/2;
+ if (mw_uint < boundary) break;
+ }
+
+ qdbm += (uint8)offset;
+
+ return (qdbm);
+}
+
+
+uint
+bcm_bitcount(uint8 *bitmap, uint length)
+{
+ uint bitcount = 0, i;
+ uint8 tmp;
+ for (i = 0; i < length; i++) {
+ tmp = bitmap[i];
+ while (tmp) {
+ bitcount++;
+ tmp &= (tmp - 1);
+ }
+ }
+ return bitcount;
+}
+
+/*
+ * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
+ * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
+ * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
+ * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
+*/
+
+unsigned int
+process_nvram_vars(char *varbuf, unsigned int len)
+{
+ char *dp;
+ bool findNewline;
+ int column;
+ unsigned int buf_len, n;
+ unsigned int pad = 0;
+
+ dp = varbuf;
+
+ findNewline = FALSE;
+ column = 0;
+
+ for (n = 0; n < len; n++) {
+ if (varbuf[n] == '\r')
+ continue;
+ if (findNewline && varbuf[n] != '\n')
+ continue;
+ findNewline = FALSE;
+ if (varbuf[n] == '#') {
+ findNewline = TRUE;
+ continue;
+ }
+ if (varbuf[n] == '\n') {
+ if (column == 0)
+ continue;
+ *dp++ = 0;
+ column = 0;
+ continue;
+ }
+ *dp++ = varbuf[n];
+ column++;
+ }
+ buf_len = (unsigned int)(dp - varbuf);
+ if (buf_len % 4) {
+ pad = 4 - buf_len % 4;
+ if (pad && (buf_len + pad <= len)) {
+ buf_len += pad;
+ }
+ }
+
+ while (dp < varbuf + n)
+ *dp++ = 0;
+
+ return buf_len;
+}
+
+/* calculate a * b + c */
+void
+bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
+{
+#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
+ uint32 r1, r0;
+ uint32 a1, a0, b1, b0, t, cc = 0;
+
+ a1 = a >> 16;
+ a0 = a & 0xffff;
+ b1 = b >> 16;
+ b0 = b & 0xffff;
+
+ r0 = a0 * b0;
+ FORMALIZE(r0);
+
+ t = (a1 * b0) << 16;
+ FORMALIZE(t);
+
+ r0 += t;
+ FORMALIZE(r0);
+
+ t = (a0 * b1) << 16;
+ FORMALIZE(t);
+
+ r0 += t;
+ FORMALIZE(r0);
+
+ FORMALIZE(c);
+
+ r0 += c;
+ FORMALIZE(r0);
+
+ r0 |= (cc % 2) ? 0x80000000 : 0;
+ r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2);
+
+ *r_high = r1;
+ *r_low = r0;
+}
+
+/* calculate a / b */
+void
+bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
+{
+ uint32 a1 = a_high, a0 = a_low, r0 = 0;
+
+ if (b < 2)
+ return;
+
+ while (a1 != 0) {
+ r0 += (0xffffffff / b) * a1;
+ bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0);
+ }
+
+ r0 += a0 / b;
+ *r = r0;
+}
+
+/* calculate uint64 a / b
+ * keeping bcm_uint64_divide (returns uint32 value) since many module
+ * uses it. Added new func bcm_unit64_div to take care of uint64 quotient
+ */
+uint64
+bcm_uint64_div(uint32 a_high, uint32 a_low, uint32 b)
+{
+ uint32 a1 = a_high, a0 = a_low;
+ uint64 r0 = 0;
+
+ if (!b) {
+ ASSERT(0);
+ return 0;
+ }
+
+ if (b == 1) {
+ return (((uint64)a1 << 32) | a0);
+ }
+ while (a1 != 0) {
+ r0 += (uint64)(0xffffffff / b) * a1;
+ bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0);
+ }
+
+ r0 += a0 / b;
+ return r0;
+}
+
+#ifndef setbit /* As in the header file */
+#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
+/* Set bit in byte array. */
+void
+setbit(void *array, uint bit)
+{
+ ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY);
+}
+
+/* Clear bit in byte array. */
+void
+clrbit(void *array, uint bit)
+{
+ ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY));
+}
+
+/* Test if bit is set in byte array. */
+bool
+isset(const void *array, uint bit)
+{
+ return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY)));
+}
+
+/* Test if bit is clear in byte array. */
+bool
+isclr(const void *array, uint bit)
+{
+ return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0);
+}
+#endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
+#endif /* setbit */
+
+void
+set_bitrange(void *array, uint start, uint end, uint maxbit)
+{
+ uint startbyte = start/NBBY;
+ uint endbyte = end/NBBY;
+ uint i, startbytelastbit, endbytestartbit;
+
+ if (end >= start) {
+ if (endbyte - startbyte > 1)
+ {
+ startbytelastbit = (startbyte+1)*NBBY - 1;
+ endbytestartbit = endbyte*NBBY;
+ for (i = startbyte+1; i < endbyte; i++)
+ ((uint8 *)array)[i] = 0xFF;
+ for (i = start; i <= startbytelastbit; i++)
+ setbit(array, i);
+ for (i = endbytestartbit; i <= end; i++)
+ setbit(array, i);
+ } else {
+ for (i = start; i <= end; i++)
+ setbit(array, i);
+ }
+ }
+ else {
+ set_bitrange(array, start, maxbit, maxbit);
+ set_bitrange(array, 0, end, maxbit);
+ }
+}
+
+void
+bcm_bitprint32(const uint32 u32arg)
+{
+ int i;
+ for (i = NBITS(uint32) - 1; i >= 0; i--) {
+ if (isbitset(u32arg, i)) {
+ printf("1");
+ } else {
+ printf("0");
+ }
+
+ if ((i % NBBY) == 0) printf(" ");
+ }
+ printf("\n");
+}
+
+/* calculate checksum for ip header, tcp / udp header / data */
+uint16
+bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum)
+{
+ while (len > 1) {
+ sum += (buf[0] << 8) | buf[1];
+ buf += 2;
+ len -= 2;
+ }
+
+ if (len > 0) {
+ sum += (*buf) << 8;
+ }
+
+ while (sum >> 16) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+
+ return ((uint16)~sum);
+}
+
+/* calculate a >> b; and returns only lower 32 bits */
+void
+bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
+{
+ uint32 a1 = a_high, a0 = a_low, r0 = 0;
+
+ if (b == 0) {
+ r0 = a_low;
+ *r = r0;
+ return;
+ }
+
+ if (b < 32) {
+ a0 = a0 >> b;
+ a1 = a1 & ((1 << b) - 1);
+ a1 = a1 << (32 - b);
+ r0 = a0 | a1;
+ *r = r0;
+ return;
+ } else {
+ r0 = a1 >> (b - 32);
+ *r = r0;
+ return;
+ }
+
+}
+
+/* calculate a + b where a is a 64 bit number and b is a 32 bit number */
+void
+bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset)
+{
+ uint32 r1_lo = *r_lo;
+ (*r_lo) += offset;
+ if (*r_lo < r1_lo)
+ (*r_hi) ++;
+}
+
+/* calculate a - b where a is a 64 bit number and b is a 32 bit number */
+void
+bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset)
+{
+ uint32 r1_lo = *r_lo;
+ (*r_lo) -= offset;
+ if (*r_lo > r1_lo)
+ (*r_hi) --;
+}
+
+int
+BCMRAMFN(valid_bcmerror)(int e)
+{
+ return ((e <= 0) && (e >= BCME_LAST));
+}
+
+/* Does unsigned 64 bit fixed point multiplication */
+uint64
+fp_mult_64(uint64 val1, uint64 val2, uint8 nf1, uint8 nf2, uint8 nf_res)
+{
+ uint64 mult_out_tmp, mult_out, rnd_val;
+ uint8 shift_amt;
+
+ shift_amt = nf1 + nf2 - nf_res;
+ /* 0.5 in 1.0.shift_amt */
+ rnd_val = bcm_shl_64(1, (shift_amt - 1));
+ rnd_val = (shift_amt == 0) ? 0 : rnd_val;
+ mult_out_tmp = (uint64)((uint64)val1 * (uint64)val2) + (uint64)rnd_val;
+ mult_out = bcm_shr_64(mult_out_tmp, shift_amt);
+
+ return mult_out;
+}
+
+
+/* Does unsigned 64 bit by 32 bit fixed point division */
+uint8
+fp_div_64(uint64 num, uint32 den, uint8 nf_num, uint8 nf_den, uint32 *div_out)
+{
+ uint8 shift_amt1, shift_amt2, shift_amt, nf_res, hd_rm_nr, hd_rm_dr;
+ uint32 num_hi, num_lo;
+ uint64 num_scale;
+
+ /* Worst case shift possible */
+ hd_rm_nr = fp_calc_head_room_64(num);
+ hd_rm_dr = fp_calc_head_room_32(den);
+
+ /* (Nr / Dr) <= 2^32 */
+ shift_amt1 = hd_rm_nr - hd_rm_dr - 1;
+ /* Shift <= 32 + N2 - N1 */
+ shift_amt2 = 31 + nf_den - nf_num;
+ shift_amt = MINIMUM(shift_amt1, shift_amt2);
+
+ /* Scale numerator */
+ num_scale = bcm_shl_64(num, shift_amt);
+
+ /* Do division */
+ num_hi = (uint32)((uint64)num_scale >> 32) & MASK_32_BITS;
+ num_lo = (uint32)(num_scale & MASK_32_BITS);
+ bcm_uint64_divide(div_out, num_hi, num_lo, den);
+
+ /* Result format */
+ nf_res = nf_num - nf_den + shift_amt;
+ return nf_res;
+}
+
+/* Look-up table to calculate head room present in a number */
+static const uint8 msb_table[] = {
+ 0, 1, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+/* Finds the number of bits available for shifting in unsigned 64 bit number */
+uint8
+fp_calc_head_room_64(uint64 num)
+{
+ uint8 n_room_bits = 0, msb_pos;
+ uint32 num_hi, num_lo, x;
+
+ num_hi = (uint32)((uint64)num >> 32) & MASK_32_BITS;
+ num_lo = (uint32)(num & MASK_32_BITS);
+
+ if (num_hi > 0) {
+ x = num_hi;
+ n_room_bits = 0;
+ } else {
+ x = num_lo;
+ n_room_bits = 32;
+ }
+
+ msb_pos = (x >> 16) ? ((x >> 24) ? (24 + msb_table[(x >> 24) & MASK_8_BITS])
+ : (16 + msb_table[(x >> 16) & MASK_8_BITS]))
+ : ((x >> 8) ? (8 + msb_table[(x >> 8) & MASK_8_BITS])
+ : msb_table[x & MASK_8_BITS]);
+
+ return (n_room_bits + 32 - msb_pos);
+}
+
+/* Finds the number of bits available for shifting in unsigned 32 bit number */
+uint8
+fp_calc_head_room_32(uint32 x)
+{
+ uint8 msb_pos;
+
+ msb_pos = (x >> 16) ? ((x >> 24) ? (24 + msb_table[(x >> 24) & MASK_8_BITS])
+ : (16 + msb_table[(x >> 16) & MASK_8_BITS]))
+ : ((x >> 8) ? (8 + msb_table[(x >> 8) & MASK_8_BITS])
+ : msb_table[x & MASK_8_BITS]);
+
+ return (32 - msb_pos);
+}
+
+/* Does unsigned 64 bit fixed point floor */
+uint32
+fp_floor_64(uint64 num, uint8 floor_pos)
+{
+ uint32 floor_out;
+
+ floor_out = (uint32)bcm_shr_64(num, floor_pos);
+
+ return floor_out;
+}
+
+/* Does unsigned 32 bit fixed point floor */
+uint32
+fp_floor_32(uint32 num, uint8 floor_pos)
+{
+ return num >> floor_pos;
+}
+
+/* Does unsigned 64 bit fixed point rounding */
+uint32
+fp_round_64(uint64 num, uint8 rnd_pos)
+{
+ uint64 rnd_val, rnd_out_tmp;
+ uint32 rnd_out;
+
+ /* 0.5 in 1.0.rnd_pos */
+ rnd_val = bcm_shl_64(1, (rnd_pos - 1));
+ rnd_val = (rnd_pos == 0) ? 0 : rnd_val;
+ rnd_out_tmp = num + rnd_val;
+ rnd_out = (uint32)bcm_shr_64(rnd_out_tmp, rnd_pos);
+
+ return rnd_out;
+}
+
+/* Does unsigned 32 bit fixed point rounding */
+uint32
+fp_round_32(uint32 num, uint8 rnd_pos)
+{
+ uint32 rnd_val, rnd_out_tmp;
+
+ /* 0.5 in 1.0.rnd_pos */
+ rnd_val = 1 << (rnd_pos - 1);
+ rnd_val = (rnd_pos == 0) ? 0 : rnd_val;
+ rnd_out_tmp = num + rnd_val;
+ return (rnd_out_tmp >> rnd_pos);
+}
+
+/* Does unsigned fixed point ceiling */
+uint32
+fp_ceil_64(uint64 num, uint8 ceil_pos)
+{
+ uint64 ceil_val, ceil_out_tmp;
+ uint32 ceil_out;
+
+ /* 0.999 in 1.0.rnd_pos */
+ ceil_val = bcm_shl_64(1, ceil_pos) - 1;
+ ceil_out_tmp = num + ceil_val;
+ ceil_out = (uint32)bcm_shr_64(ceil_out_tmp, ceil_pos);
+
+ return ceil_out;
+}
+
+/* Does left shift of unsigned 64 bit number */
+uint64
+bcm_shl_64(uint64 input, uint8 shift_amt)
+{
+ uint32 in_hi, in_lo;
+ uint32 masked_lo = 0;
+ uint32 mask;
+ uint64 shl_out;
+
+ if (shift_amt == 0) {
+ return input;
+ }
+
+ /* Get hi and lo part */
+ in_hi = (uint32)((uint64)input >> 32) & MASK_32_BITS;
+ in_lo = (uint32)(input & MASK_32_BITS);
+
+ if (shift_amt < 32) {
+ /* Extract bit which belongs to hi part after shifting */
+ mask = ((uint32)~0) << (32 - shift_amt);
+ masked_lo = (in_lo & mask) >> (32 - shift_amt);
+
+ /* Shift hi and lo and prepare output */
+ in_hi = (in_hi << shift_amt) | masked_lo;
+ in_lo = in_lo << shift_amt;
+ } else {
+ /* Extract bit which belongs to hi part after shifting */
+ shift_amt = shift_amt - 32;
+
+ /* Shift hi and lo and prepare output */
+ in_hi = in_lo << shift_amt;
+ in_lo = 0;
+ }
+
+ shl_out = (((uint64)in_hi << 32) | in_lo);
+ return shl_out;
+}
+
+/* Does right shift of unsigned 64 bit number */
+uint64
+bcm_shr_64(uint64 input, uint8 shift_amt)
+{
+ uint32 in_hi, in_lo;
+ uint32 masked_hi = 0;
+ uint32 mask;
+ uint64 shr_out;
+
+ if (shift_amt == 0) {
+ return input;
+ }
+
+ /* Get hi and lo part */
+ in_hi = (uint32)((uint64)input >> 32) & MASK_32_BITS;
+ in_lo = (uint32)(input & MASK_32_BITS);
+
+ if (shift_amt < 32) {
+ /* Extract bit which belongs to lo part after shifting */
+ mask = (1 << shift_amt) - 1;
+ masked_hi = in_hi & mask;
+
+ /* Shift hi and lo and prepare output */
+ in_hi = (uint32)in_hi >> shift_amt;
+ in_lo = ((uint32)in_lo >> shift_amt) | (masked_hi << (32 - shift_amt));
+ } else {
+ shift_amt = shift_amt - 32;
+ in_lo = in_hi >> shift_amt;
+ in_hi = 0;
+ }
+
+ shr_out = (((uint64)in_hi << 32) | in_lo);
+ return shr_out;
+}
+
+#ifdef DEBUG_COUNTER
+#if (OSL_SYSUPTIME_SUPPORT == TRUE)
+void counter_printlog(counter_tbl_t *ctr_tbl)
+{
+ uint32 now;
+
+ if (!ctr_tbl->enabled)
+ return;
+
+ now = OSL_SYSUPTIME();
+
+ if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) {
+ uint8 i = 0;
+ printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print);
+
+ for (i = 0; i < ctr_tbl->needed_cnt; i++) {
+ printf(" %u", ctr_tbl->cnt[i]);
+ }
+ printf("\n");
+
+ ctr_tbl->prev_log_print = now;
+ bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint));
+ }
+}
+#else
+/* OSL_SYSUPTIME is not supported so no way to get time */
+#define counter_printlog(a) do {} while (0)
+#endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
+#endif /* DEBUG_COUNTER */
+
+/* calculate partial checksum */
+static uint32
+ip_cksum_partial(uint32 sum, uint8 *val8, uint32 count)
+{
+ uint32 i;
+ uint16 *val16 = (uint16 *)val8;
+
+ ASSERT(val8 != NULL);
+ /* partial chksum calculated on 16-bit values */
+ ASSERT((count % 2) == 0);
+
+ count /= 2;
+
+ for (i = 0; i < count; i++) {
+ sum += *val16++;
+ }
+ return sum;
+}
+
+/* calculate IP checksum */
+static uint16
+ip_cksum(uint32 sum, uint8 *val8, uint32 count)
+{
+ uint16 *val16 = (uint16 *)val8;
+
+ ASSERT(val8 != NULL);
+
+ while (count > 1) {
+ sum += *val16++;
+ count -= 2;
+ }
+ /* add left-over byte, if any */
+ if (count > 0) {
+ sum += (*(uint8 *)val16);
+ }
+
+ /* fold 32-bit sum to 16 bits */
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ return ((uint16)~sum);
+}
+
+/* calculate IPv4 header checksum
+ * - input ip points to IP header in network order
+ * - output cksum is in network order
+ */
+uint16
+ipv4_hdr_cksum(uint8 *ip, int ip_len)
+{
+ uint32 sum = 0;
+ uint8 *ptr = ip;
+
+ ASSERT(ip != NULL);
+ ASSERT(ip_len >= IPV4_MIN_HEADER_LEN);
+
+ /* partial cksum skipping the hdr_chksum field */
+ sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct ipv4_hdr, hdr_chksum));
+ ptr += OFFSETOF(struct ipv4_hdr, hdr_chksum) + 2;
+
+ /* return calculated chksum */
+ return ip_cksum(sum, ptr, ip_len - OFFSETOF(struct ipv4_hdr, src_ip));
+}
+
+/* calculate TCP header checksum using partial sum */
+static uint16
+tcp_hdr_chksum(uint32 sum, uint8 *tcp_hdr, uint16 tcp_len)
+{
+ uint8 *ptr = tcp_hdr;
+
+ ASSERT(tcp_hdr != NULL);
+ ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
+
+ /* partial TCP cksum skipping the chksum field */
+ sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct bcmtcp_hdr, chksum));
+ ptr += OFFSETOF(struct bcmtcp_hdr, chksum) + 2;
+
+ /* return calculated chksum */
+ return ip_cksum(sum, ptr, tcp_len - OFFSETOF(struct bcmtcp_hdr, urg_ptr));
+}
+
+struct tcp_pseudo_hdr {
+ uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */
+ uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */
+ uint8 zero;
+ uint8 prot;
+ uint16 tcp_size;
+};
+
+/* calculate IPv4 TCP header checksum
+ * - input ip and tcp points to IP and TCP header in network order
+ * - output cksum is in network order
+ */
+uint16
+ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len)
+{
+ struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)ip;
+ struct tcp_pseudo_hdr tcp_ps;
+ uint32 sum = 0;
+
+ ASSERT(ip != NULL);
+ ASSERT(tcp != NULL);
+ ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
+
+ /* pseudo header cksum */
+ memset(&tcp_ps, 0, sizeof(tcp_ps));
+ memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN);
+ memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN);
+ tcp_ps.zero = 0;
+ tcp_ps.prot = ip_hdr->prot;
+ tcp_ps.tcp_size = hton16(tcp_len);
+ sum = ip_cksum_partial(sum, (uint8 *)&tcp_ps, sizeof(tcp_ps));
+
+ /* return calculated TCP header chksum */
+ return tcp_hdr_chksum(sum, tcp, tcp_len);
+}
+
+struct ipv6_pseudo_hdr {
+ uint8 saddr[IPV6_ADDR_LEN];
+ uint8 daddr[IPV6_ADDR_LEN];
+ uint16 payload_len;
+ uint8 zero;
+ uint8 next_hdr;
+};
+
+/* calculate IPv6 TCP header checksum
+ * - input ipv6 and tcp points to IPv6 and TCP header in network order
+ * - output cksum is in network order
+ */
+uint16
+ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len)
+{
+ struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)ipv6;
+ struct ipv6_pseudo_hdr ipv6_pseudo;
+ uint32 sum = 0;
+
+ ASSERT(ipv6 != NULL);
+ ASSERT(tcp != NULL);
+ ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
+
+ /* pseudo header cksum */
+ memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo));
+ memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr,
+ sizeof(ipv6_pseudo.saddr));
+ memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr,
+ sizeof(ipv6_pseudo.daddr));
+ ipv6_pseudo.payload_len = ipv6_hdr->payload_len;
+ ipv6_pseudo.next_hdr = ipv6_hdr->nexthdr;
+ sum = ip_cksum_partial(sum, (uint8 *)&ipv6_pseudo, sizeof(ipv6_pseudo));
+
+ /* return calculated TCP header chksum */
+ return tcp_hdr_chksum(sum, tcp, tcp_len);
+}
+
+void *_bcmutils_dummy_fn = NULL;
+
+/* GROUP 1 --- start
+ * These function under GROUP 1 are general purpose functions to do complex number
+ * calculations and square root calculation.
+ */
+void mult_cint32_cfixed(const cint32* in1, const cint32* in2, const uint8 prec,
+ cint32* out, bool conj) {
+ int32 i1 = in1->i, q1 = in1->q;
+ int32 i2 = in2->i, q2 = in2->q * (conj ? -1 : 1);
+ out->i = (i1*i2 - q1*q2) / (1 << prec);
+ out->q = (i1*q2 + i2*q1) / (1 << prec);
+}
+
+void add_cint32(const cint32* in1, const cint32* in2, cint32* out)
+{
+ out->i = in1->i + in2->i;
+ out->q = in1->q + in2->q;
+}
+
+void power_cint32(const cint32* in1, uint32* pwr)
+{
+ int32 re = in1->i;
+ int32 im = in1->q;
+ *(pwr) = (re*re + im*im);
+}
+
+void power_cint32_arr(const cint32* in1, const uint16* idx_arr, uint16 len, uint32* pwr)
+{
+ uint32 tmp_pwr = 0;
+ uint16 i = 0, idx;
+ *pwr = 0;
+ for (i = 0; i < len; i++) {
+ idx = *(idx_arr + i);
+ power_cint32((in1 + idx), &tmp_pwr);
+ *(pwr) += tmp_pwr;
+ }
+}
+
+uint32 sqrt_int(uint32 value)
+{
+ uint32 root = 0, shift = 0;
+
+ /* Compute integer nearest to square root of input integer value */
+ for (shift = 0; shift < 32; shift += 2) {
+ if (((0x40000000 >> shift) + root) <= value) {
+ value -= ((0x40000000 >> shift) + root);
+ root = (root >> 1) | (0x40000000 >> shift);
+ }
+ else {
+ root = root >> 1;
+ }
+ }
+
+ /* round to the nearest integer */
+ if (root < value) ++root;
+
+ return root;
+}
+/* GROUP 1 --- end */
diff --git a/wl/src/shared/bcmwifi/include/bcmwifi_channels.h b/wl/src/shared/bcmwifi/include/bcmwifi_channels.h
new file mode 100644
index 0000000..17ff789
--- /dev/null
+++ b/wl/src/shared/bcmwifi/include/bcmwifi_channels.h
@@ -0,0 +1,836 @@
+/*
+ * Misc utility routines for WL and Apps
+ * This header file housing the define and function prototype use by
+ * both the wl driver, tools & Apps.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmwifi_channels.h 655845 2016-08-24 01:05:41Z $
+ */
+
+#ifndef _bcmwifi_channels_h_
+#define _bcmwifi_channels_h_
+
+#if defined(__FreeBSD__)
+#include <stdbool.h>
+#endif
+
+/* A chanspec holds the channel number, band, bandwidth and control sideband */
+typedef uint16 chanspec_t;
+
+/* channel defines */
+#define CH_UPPER_SB 0x01
+#define CH_LOWER_SB 0x02
+#define CH_EWA_VALID 0x04
+#define CH_80MHZ_APART 16
+#define CH_40MHZ_APART 8
+#define CH_20MHZ_APART 4
+#define CH_10MHZ_APART 2
+#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */
+#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */
+
+/* maximum # channels the s/w supports */
+#define MAXCHANNEL 224 /* max # supported channels. The max channel no is above,
+ * this is that + 1 rounded up to a multiple of NBBY (8).
+ * DO NOT MAKE it > 255: channels are uint8's all over
+ */
+#define MAXCHANNEL_NUM (MAXCHANNEL - 1) /* max channel number */
+
+/* channel bitvec */
+typedef struct {
+ uint8 vec[MAXCHANNEL/8]; /* bitvec of channels */
+} chanvec_t;
+
+/* make sure channel num is within valid range */
+#define CH_NUM_VALID_RANGE(ch_num) ((ch_num) > 0 && (ch_num) <= MAXCHANNEL_NUM)
+
+#define CHSPEC_CTLOVLP(sp1, sp2, sep) \
+ (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep))
+
+/* All builds use the new 11ac ratespec/chanspec */
+#undef D11AC_IOTYPES
+#define D11AC_IOTYPES
+
+#define WL_CHANSPEC_CHAN_MASK 0x00ff
+#define WL_CHANSPEC_CHAN_SHIFT 0
+#define WL_CHANSPEC_CHAN1_MASK 0x000f
+#define WL_CHANSPEC_CHAN1_SHIFT 0
+#define WL_CHANSPEC_CHAN2_MASK 0x00f0
+#define WL_CHANSPEC_CHAN2_SHIFT 4
+
+#define WL_CHANSPEC_CTL_SB_MASK 0x0700
+#define WL_CHANSPEC_CTL_SB_SHIFT 8
+#define WL_CHANSPEC_CTL_SB_LLL 0x0000
+#define WL_CHANSPEC_CTL_SB_LLU 0x0100
+#define WL_CHANSPEC_CTL_SB_LUL 0x0200
+#define WL_CHANSPEC_CTL_SB_LUU 0x0300
+#define WL_CHANSPEC_CTL_SB_ULL 0x0400
+#define WL_CHANSPEC_CTL_SB_ULU 0x0500
+#define WL_CHANSPEC_CTL_SB_UUL 0x0600
+#define WL_CHANSPEC_CTL_SB_UUU 0x0700
+#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL
+#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU
+#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL
+#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU
+#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL
+#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU
+#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL
+#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU
+#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL
+
+#define WL_CHANSPEC_BW_MASK 0x3800
+#define WL_CHANSPEC_BW_SHIFT 11
+#define WL_CHANSPEC_BW_5 0x0000
+#define WL_CHANSPEC_BW_10 0x0800
+#define WL_CHANSPEC_BW_20 0x1000
+#define WL_CHANSPEC_BW_40 0x1800
+#define WL_CHANSPEC_BW_80 0x2000
+#define WL_CHANSPEC_BW_160 0x2800
+#define WL_CHANSPEC_BW_8080 0x3000
+#define WL_CHANSPEC_BW_2P5 0x3800
+
+#define WL_CHANSPEC_BAND_MASK 0xc000
+#define WL_CHANSPEC_BAND_SHIFT 14
+#define WL_CHANSPEC_BAND_2G 0x0000
+#define WL_CHANSPEC_BAND_3G 0x4000
+#define WL_CHANSPEC_BAND_4G 0x8000
+#define WL_CHANSPEC_BAND_5G 0xc000
+#define INVCHANSPEC 255
+#define MAX_CHANSPEC 0xFFFF
+
+#define WL_CHANNEL_BAND(ch) (((ch) <= CH_MAX_2G_CHANNEL) ? \
+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)
+
+/* channel defines */
+#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \
+ ((channel) - CH_10MHZ_APART) : 0)
+#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \
+ ((channel) + CH_10MHZ_APART) : 0)
+
+/* pass a 80MHz channel number (uint8) to get respective LL, UU, LU, UL */
+#define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0)
+#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \
+ ((channel) + 3 * CH_10MHZ_APART) : 0)
+#define LU_20_SB(channel) LOWER_20_SB(channel)
+#define UL_20_SB(channel) UPPER_20_SB(channel)
+
+#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART)
+#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART)
+#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX)
+#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \
+ (((channel) <= CH_MAX_2G_CHANNEL) ? \
+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
+#define CH2P5MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_2P5 | \
+ (((channel) <= CH_MAX_2G_CHANNEL) ? \
+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
+#define CH5MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_5 | \
+ (((channel) <= CH_MAX_2G_CHANNEL) ? \
+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
+#define CH10MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_10 | \
+ (((channel) <= CH_MAX_2G_CHANNEL) ? \
+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
+#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \
+ ((channel) + CH_20MHZ_APART) : 0)
+#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
+ ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \
+ ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \
+ WL_CHANSPEC_BAND_5G))
+#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
+ ((channel) | (ctlsb) | \
+ WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G)
+#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
+ ((channel) | (ctlsb) | \
+ WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G)
+#define CHBW_CHSPEC(bw, channel) (chanspec_t)((chanspec_t)(channel) | (bw) | \
+ (((channel) <= CH_MAX_2G_CHANNEL) ? \
+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
+
+/* simple MACROs to get different fields of chanspec */
+#ifdef WL11AC_80P80
+#define CHSPEC_CHANNEL(chspec) wf_chspec_channel(chspec)
+#else
+#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK))
+#endif
+#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT
+#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT
+#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)
+#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK)
+#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK)
+
+#ifdef WL11N_20MHZONLY
+#ifdef WL11ULB
+#define CHSPEC_IS2P5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_2P5)
+#define CHSPEC_IS5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_5)
+#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
+#else
+#define CHSPEC_IS2P5(chspec) 0
+#define CHSPEC_IS5(chspec) 0
+#define CHSPEC_IS10(chspec) 0
+#endif
+#define CHSPEC_IS20(chspec) 1
+#define CHSPEC_IS20_2G(chspec) ((((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) && \
+ CHSPEC_IS2G(chspec))
+#ifndef CHSPEC_IS40
+#define CHSPEC_IS40(chspec) 0
+#endif
+#ifndef CHSPEC_IS80
+#define CHSPEC_IS80(chspec) 0
+#endif
+#ifndef CHSPEC_IS160
+#define CHSPEC_IS160(chspec) 0
+#endif
+#ifndef CHSPEC_IS8080
+#define CHSPEC_IS8080(chspec) 0
+#endif
+#define BW_LE20(bw) TRUE
+#define CHSPEC_ISLE20(chspec) TRUE
+
+/* see FOREACH_20_SB in !WL11N_20MHZONLY section */
+#define FOREACH_20_SB(chspec, channel) \
+ for (channel = CHSPEC_CHANNEL(chspec); channel; channel = 0)
+
+/* see GET_ALL_SB in !WL11N_20MHZONLY section */
+#define GET_ALL_SB(chspec, psb) do { \
+ psb[0] = CHSPEC_CHANNEL(chspec); \
+} while (0)
+
+#else /* !WL11N_20MHZONLY */
+
+#define CHSPEC_IS2P5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_2P5)
+#define CHSPEC_IS5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_5)
+#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
+#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
+#define CHSPEC_IS20_5G(chspec) ((((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) && \
+ CHSPEC_IS5G(chspec))
+#ifndef CHSPEC_IS40
+#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
+#endif
+#ifndef CHSPEC_IS80
+#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80)
+#endif
+#ifndef CHSPEC_IS160
+#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160)
+#endif
+#ifndef CHSPEC_IS8080
+#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080)
+#endif
+
+/* pass a center channel and get channel offset from it by 10MHz */
+#define CH_OFF_10MHZ_MULTIPLES(channel, offset) ((uint8) (((offset) < 0) ? \
+ (((channel) > (WL_CHANSPEC_CHAN_MASK & ((uint16)((-(offset)) * CH_10MHZ_APART)))) ?\
+ ((channel) + (offset) * CH_10MHZ_APART) : 0) : \
+ (((channel) < (uint16)(MAXCHANNEL - (offset) * CH_10MHZ_APART)) ? \
+ ((channel) + (offset) * CH_10MHZ_APART) : 0)))
+
+#if defined(WL11AC_80P80) || defined(WL11AC_160)
+/* pass a 160MHz center channel to get 20MHz subband channel numbers */
+#define LLL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -7)
+#define LLU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -5)
+#define LUL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -3)
+#define LUU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -1)
+#define ULL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 1)
+#define ULU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 3)
+#define UUL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 5)
+#define UUU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 7)
+
+/* given an 80p80 channel, return the lower 80MHz sideband */
+#define LOWER_80_SB(chspec) (wf_chspec_primary80_channel(chspec) < \
+ wf_chspec_secondary80_channel(chspec) ? \
+ wf_chspec_primary80_channel(chspec) : wf_chspec_secondary80_channel(chspec))
+
+/* given an 80p80 channel, return the upper 80MHz sideband */
+#define UPPER_80_SB(chspec) (wf_chspec_primary80_channel(chspec) > \
+ wf_chspec_secondary80_channel(chspec) ? \
+ wf_chspec_primary80_channel(chspec) : wf_chspec_secondary80_channel(chspec))
+
+/* pass an 80P80 chanspec (not channel) to get 20MHz subnand channel numbers */
+#define LLL_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(LOWER_80_SB(chspec), -3)
+#define LLU_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(LOWER_80_SB(chspec), -1)
+#define LUL_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(LOWER_80_SB(chspec), 1)
+#define LUU_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(LOWER_80_SB(chspec), 3)
+#define ULL_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(UPPER_80_SB(chspec), -3)
+#define ULU_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(UPPER_80_SB(chspec), -1)
+#define UUL_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(UPPER_80_SB(chspec), 1)
+#define UUU_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(UPPER_80_SB(chspec), 3)
+
+/* get lowest 20MHz sideband of a given chspec
+ * (works with 20, 40, 80, 160, 80p80)
+ */
+#define CH_FIRST_20_SB(chspec) ((uint8) (\
+ CHSPEC_IS160(chspec) ? LLL_20_SB_160(CHSPEC_CHANNEL(chspec)) : (\
+ CHSPEC_IS8080(chspec) ? LLL_20_SB_8080(chspec) : (\
+ CHSPEC_IS80(chspec) ? LL_20_SB(CHSPEC_CHANNEL(chspec)) : (\
+ CHSPEC_IS40(chspec) ? LOWER_20_SB(CHSPEC_CHANNEL(chspec)) : \
+ CHSPEC_CHANNEL(chspec))))))
+
+/* get upper most 20MHz sideband of a given chspec
+ * (works with 20, 40, 80, 160, 80p80)
+ */
+#define CH_LAST_20_SB(chspec) ((uint8) (\
+ CHSPEC_IS160(chspec) ? UUU_20_SB_160(CHSPEC_CHANNEL(chspec)) : (\
+ CHSPEC_IS8080(chspec) ? UUU_20_SB_8080(chspec) : (\
+ CHSPEC_IS80(chspec) ? UU_20_SB(CHSPEC_CHANNEL(chspec)) : (\
+ CHSPEC_IS40(chspec) ? UPPER_20_SB(CHSPEC_CHANNEL(chspec)) : \
+ CHSPEC_CHANNEL(chspec))))))
+
+/* call this with chspec and a valid 20MHz sideband of this channel to get the next 20MHz sideband
+ * (works with 80p80 only)
+ * resolves to 0 if called with upper most channel
+ */
+#define CH_NEXT_20_SB_IN_8080(chspec, channel) ((uint8) (\
+ ((uint8) ((channel) + CH_20MHZ_APART) > CH_LAST_20_SB(chspec) ? 0 : \
+ ((channel) == LUU_20_SB_8080(chspec) ? ULL_20_SB_8080(chspec) : \
+ (channel) + CH_20MHZ_APART))))
+
+/* call this with chspec and a valid 20MHz sideband of this channel to get the next 20MHz sideband
+ * (works with 20, 40, 80, 160, 80p80)
+ * resolves to 0 if called with upper most channel
+ */
+#define CH_NEXT_20_SB(chspec, channel) ((uint8) (\
+ (CHSPEC_IS8080(chspec) ? CH_NEXT_20_SB_IN_8080((chspec), (channel)) : \
+ ((uint8) ((channel) + CH_20MHZ_APART) > CH_LAST_20_SB(chspec) ? 0 : \
+ ((channel) + CH_20MHZ_APART)))))
+
+#else /* WL11AC_80P80, WL11AC_160 */
+
+#define LLL_20_SB_160(channel) 0
+#define LLU_20_SB_160(channel) 0
+#define LUL_20_SB_160(channel) 0
+#define LUU_20_SB_160(channel) 0
+#define ULL_20_SB_160(channel) 0
+#define ULU_20_SB_160(channel) 0
+#define UUL_20_SB_160(channel) 0
+#define UUU_20_SB_160(channel) 0
+
+#define LOWER_80_SB(chspec) 0
+
+#define UPPER_80_SB(chspec) 0
+
+#define LLL_20_SB_8080(chspec) 0
+#define LLU_20_SB_8080(chspec) 0
+#define LUL_20_SB_8080(chspec) 0
+#define LUU_20_SB_8080(chspec) 0
+#define ULL_20_SB_8080(chspec) 0
+#define ULU_20_SB_8080(chspec) 0
+#define UUL_20_SB_8080(chspec) 0
+#define UUU_20_SB_8080(chspec) 0
+
+/* get lowest 20MHz sideband of a given chspec
+ * (works with 20, 40, 80)
+ */
+#define CH_FIRST_20_SB(chspec) ((uint8) (\
+ CHSPEC_IS80(chspec) ? LL_20_SB(CHSPEC_CHANNEL(chspec)) : (\
+ CHSPEC_IS40(chspec) ? LOWER_20_SB(CHSPEC_CHANNEL(chspec)) : \
+ CHSPEC_CHANNEL(chspec))))
+/* get upper most 20MHz sideband of a given chspec
+ * (works with 20, 40, 80, 160, 80p80)
+ */
+#define CH_LAST_20_SB(chspec) ((uint8) (\
+ CHSPEC_IS80(chspec) ? UU_20_SB(CHSPEC_CHANNEL(chspec)) : (\
+ CHSPEC_IS40(chspec) ? UPPER_20_SB(CHSPEC_CHANNEL(chspec)) : \
+ CHSPEC_CHANNEL(chspec))))
+
+/* call this with chspec and a valid 20MHz sideband of this channel to get the next 20MHz sideband
+ * (works with 20, 40, 80, 160, 80p80)
+ * resolves to 0 if called with upper most channel
+ */
+#define CH_NEXT_20_SB(chspec, channel) ((uint8) (\
+ ((uint8) ((channel) + CH_20MHZ_APART) > CH_LAST_20_SB(chspec) ? 0 : \
+ ((channel) + CH_20MHZ_APART))))
+
+#endif /* WL11AC_80P80, WL11AC_160 */
+
+/* Iterator for 20MHz side bands of a chanspec: (chanspec_t chspec, uint8 channel)
+ * 'chspec' chanspec_t of interest (used in loop, better to pass a resolved value than a macro)
+ * 'channel' must be a variable (not an expression).
+ */
+#define FOREACH_20_SB(chspec, channel) \
+ for (channel = CH_FIRST_20_SB(chspec); channel; \
+ channel = CH_NEXT_20_SB((chspec), channel))
+
+/* Uses iterator to populate array with all side bands involved (sorted lower to upper).
+ * 'chspec' chanspec_t of interest
+ * 'psb' pointer to uint8 array of enough size to hold all side bands for the given chspec
+ */
+#define GET_ALL_SB(chspec, psb) do { \
+ uint8 channel, idx = 0; \
+ chanspec_t chspec_local = chspec; \
+ FOREACH_20_SB(chspec_local, channel) \
+ (psb)[idx++] = channel; \
+} while (0)
+
+/* given a chanspec_t of any bw, returns if control SB is in lower 20, 40, 80 or not respectively */
+#define IS_CTL_IN_L20(chspec) !((chspec) & WL_CHANSPEC_CTL_SB_U) /* CTL SB is in low 20 of any 40 */
+#define IS_CTL_IN_L40(chspec) !((chspec) & WL_CHANSPEC_CTL_SB_UL) /* in low 40 of any 80 */
+#define IS_CTL_IN_L80(chspec) !((chspec) & WL_CHANSPEC_CTL_SB_ULL) /* in low 80 of 80p80/160 */
+
+
+#ifdef WL11ULB
+#define BW_LT20(bw) (((bw) == WL_CHANSPEC_BW_2P5) || \
+ ((bw) == WL_CHANSPEC_BW_5) || \
+ ((bw) == WL_CHANSPEC_BW_10))
+#define CHSPEC_BW_LT20(chspec) (BW_LT20(CHSPEC_BW(chspec)))
+/* This MACRO is strictly to avoid abandons in existing code with ULB feature and is in no way
+ * optimial to use. Should be replaced with CHSPEC_BW_LE() instead
+ */
+#define BW_LE20(bw) (((bw) == WL_CHANSPEC_BW_2P5) || \
+ ((bw) == WL_CHANSPEC_BW_5) || \
+ ((bw) == WL_CHANSPEC_BW_10) || \
+ ((bw) == WL_CHANSPEC_BW_20))
+#define CHSPEC_ISLE20(chspec) (BW_LE20(CHSPEC_BW(chspec)))
+
+#else /* WL11ULB */
+#define BW_LE20(bw) ((bw) == WL_CHANSPEC_BW_20)
+#define CHSPEC_ISLE20(chspec) (CHSPEC_IS20(chspec))
+#endif /* WL11ULB */
+#endif /* !WL11N_20MHZONLY */
+
+#define BW_LE40(bw) (BW_LE20(bw) || ((bw) == WL_CHANSPEC_BW_40))
+#define BW_LE80(bw) (BW_LE40(bw) || ((bw) == WL_CHANSPEC_BW_80))
+#define BW_LE160(bw) (BW_LE80(bw) || ((bw) == WL_CHANSPEC_BW_160))
+#define CHSPEC_BW_LE20(chspec) (BW_LE20(CHSPEC_BW(chspec)))
+#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
+#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
+#define CHSPEC_SB_UPPER(chspec) \
+ ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \
+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40))
+#define CHSPEC_SB_LOWER(chspec) \
+ ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \
+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40))
+#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G)
+
+/**
+ * Number of chars needed for wf_chspec_ntoa() destination character buffer.
+ */
+#define CHANSPEC_STR_LEN 20
+
+/*
+ * This function returns TRUE if both the chanspec can co-exist in PHY.
+ * Addition to control channel, the function checks for side band for 2g 40 channels
+ */
+extern bool wf_chspec_coexist(chanspec_t chspec1, chanspec_t chspec2);
+
+#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\
+ CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080)
+
+/* BW inequality comparisons, LE (<=), GE (>=), LT (<), GT (>), comparisons can be made
+* as simple numeric comparisons, with the exception that 160 is the same BW as 80+80,
+* but have different numeric values; (WL_CHANSPEC_BW_160 < WL_CHANSPEC_BW_8080).
+*
+* The LT/LE/GT/GE macros check first checks whether both chspec bandwidth and bw are 160 wide.
+* If both chspec bandwidth and bw is not 160 wide, then the comparison is made.
+*/
+#ifdef WL11ULB
+#define CHSPEC_BW_GE(chspec, bw) \
+ (((CHSPEC_IS_BW_160_WIDE(chspec) &&\
+ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\
+ (CHSPEC_BW(chspec) >= (bw))) && \
+ (!(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5 && (bw) != WL_CHANSPEC_BW_2P5)))
+#else /* WL11ULB */
+#define CHSPEC_BW_GE(chspec, bw) \
+ ((CHSPEC_IS_BW_160_WIDE(chspec) &&\
+ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\
+ (CHSPEC_BW(chspec) >= (bw)))
+#endif /* WL11ULB */
+
+#ifdef WL11ULB
+#define CHSPEC_BW_LE(chspec, bw) \
+ (((CHSPEC_IS_BW_160_WIDE(chspec) &&\
+ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\
+ (CHSPEC_BW(chspec) <= (bw))) || \
+ (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5))
+#else /* WL11ULB */
+#define CHSPEC_BW_LE(chspec, bw) \
+ ((CHSPEC_IS_BW_160_WIDE(chspec) &&\
+ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\
+ (CHSPEC_BW(chspec) <= (bw)))
+#endif /* WL11ULB */
+
+#ifdef WL11ULB
+#define CHSPEC_BW_GT(chspec, bw) \
+ ((!(CHSPEC_IS_BW_160_WIDE(chspec) &&\
+ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\
+ (CHSPEC_BW(chspec) > (bw))) && \
+ (CHSPEC_BW(chspec) != WL_CHANSPEC_BW_2P5))
+#else /* WL11ULB */
+#define CHSPEC_BW_GT(chspec, bw) \
+ (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\
+ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\
+ (CHSPEC_BW(chspec) > (bw)))
+#endif /* WL11ULB */
+
+#ifdef WL11ULB
+#define CHSPEC_BW_LT(chspec, bw) \
+ ((!(CHSPEC_IS_BW_160_WIDE(chspec) &&\
+ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\
+ (CHSPEC_BW(chspec) < (bw))) || \
+ ((CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5 && (bw) != WL_CHANSPEC_BW_2P5)))
+#else /* WL11ULB */
+#define CHSPEC_BW_LT(chspec, bw) \
+ (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\
+ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\
+ (CHSPEC_BW(chspec) < (bw)))
+#endif /* WL11ULB */
+
+/* Legacy Chanspec defines
+ * These are the defines for the previous format of the chanspec_t
+ */
+#define WL_LCHANSPEC_CHAN_MASK 0x00ff
+#define WL_LCHANSPEC_CHAN_SHIFT 0
+
+#define WL_LCHANSPEC_CTL_SB_MASK 0x0300
+#define WL_LCHANSPEC_CTL_SB_SHIFT 8
+#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100
+#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200
+#define WL_LCHANSPEC_CTL_SB_NONE 0x0300
+
+#define WL_LCHANSPEC_BW_MASK 0x0C00
+#define WL_LCHANSPEC_BW_SHIFT 10
+#define WL_LCHANSPEC_BW_10 0x0400
+#define WL_LCHANSPEC_BW_20 0x0800
+#define WL_LCHANSPEC_BW_40 0x0C00
+
+#define WL_LCHANSPEC_BAND_MASK 0xf000
+#define WL_LCHANSPEC_BAND_SHIFT 12
+#define WL_LCHANSPEC_BAND_5G 0x1000
+#define WL_LCHANSPEC_BAND_2G 0x2000
+
+#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK))
+#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK)
+#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK)
+#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK)
+#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10)
+#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20)
+#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)
+#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G)
+#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G)
+
+#define LCHSPEC_SB_UPPER(chspec) \
+ ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \
+ (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40))
+#define LCHSPEC_SB_LOWER(chspec) \
+ ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \
+ (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40))
+
+#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band)))
+
+#define CH20MHZ_LCHSPEC(channel) \
+ (chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \
+ WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \
+ WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G))
+
+#define GET_ALL_EXT wf_get_all_ext
+
+/*
+ * WF_CHAN_FACTOR_* constants are used to calculate channel frequency
+ * given a channel number.
+ * chan_freq = chan_factor * 500Mhz + chan_number * 5
+ */
+
+/**
+ * Channel Factor for the starting frequence of 2.4 GHz channels.
+ * The value corresponds to 2407 MHz.
+ */
+#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */
+
+/**
+ * Channel Factor for the starting frequence of 5 GHz channels.
+ * The value corresponds to 5000 MHz.
+ */
+#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */
+
+/**
+ * Channel Factor for the starting frequence of 4.9 GHz channels.
+ * The value corresponds to 4000 MHz.
+ */
+#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */
+
+#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */
+
+/**
+ * No of sub-band vlaue of the specified Mhz chanspec
+ */
+#define WF_NUM_SIDEBANDS_40MHZ 2
+#define WF_NUM_SIDEBANDS_80MHZ 4
+#define WF_NUM_SIDEBANDS_8080MHZ 4
+#define WF_NUM_SIDEBANDS_160MHZ 8
+
+/* Get bandwidth of chanspec in half MHz;
+ * works with 2.5MHz to 160MHz (including 80p80) chanspecs
+ *
+ * @param chspec chanspec_t format
+ *
+ * @return bandwidth of a chanspec in half MHz units
+ */
+extern uint16 wf_bw_chspec_to_half_mhz(chanspec_t chspec);
+
+/**
+ * Convert chanspec to ascii string
+ *
+ * @param chspec chanspec format
+ * @param buf ascii string of chanspec
+ *
+ * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes
+ * Original chanspec in case of error
+ *
+ * @see CHANSPEC_STR_LEN
+ */
+extern char * wf_chspec_ntoa_ex(chanspec_t chspec, char *buf);
+
+/**
+ * Convert chanspec to ascii string
+ *
+ * @param chspec chanspec format
+ * @param buf ascii string of chanspec
+ *
+ * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes
+ * NULL in case of error
+ *
+ * @see CHANSPEC_STR_LEN
+ */
+extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf);
+
+/**
+ * Convert ascii string to chanspec
+ *
+ * @param a pointer to input string
+ *
+ * @return >= 0 if successful or 0 otherwise
+ */
+extern chanspec_t wf_chspec_aton(const char *a);
+
+/**
+ * Verify the chanspec fields are valid.
+ *
+ * Verify the chanspec is using a legal set field values, i.e. that the chanspec
+ * specified a band, bw, ctl_sb and channel and that the combination could be
+ * legal given some set of circumstances.
+ *
+ * @param chanspec input chanspec to verify
+ *
+ * @return TRUE if the chanspec is malformed, FALSE if it looks good.
+ */
+extern bool wf_chspec_malformed(chanspec_t chanspec);
+
+/**
+ * Verify the chanspec specifies a valid channel according to 802.11.
+ *
+ * @param chanspec input chanspec to verify
+ *
+ * @return TRUE if the chanspec is a valid 802.11 channel
+ */
+extern bool wf_chspec_valid(chanspec_t chanspec);
+
+/**
+ * Return the primary (control) channel.
+ *
+ * This function returns the channel number of the primary 20MHz channel. For
+ * 20MHz channels this is just the channel number. For 40MHz or wider channels
+ * it is the primary 20MHz channel specified by the chanspec.
+ *
+ * @param chspec input chanspec
+ *
+ * @return Returns the channel number of the primary 20MHz channel
+ */
+extern uint8 wf_chspec_ctlchan(chanspec_t chspec);
+
+/*
+ * Return the bandwidth string.
+ *
+ * This function returns the bandwidth string for the passed chanspec.
+ *
+ * @param chspec input chanspec
+ *
+ * @return Returns the bandwidth string
+ */
+extern const char *wf_chspec_to_bw_str(chanspec_t chspec);
+
+/**
+ * Return the primary (control) chanspec.
+ *
+ * This function returns the chanspec of the primary 20MHz channel. For 20MHz
+ * channels this is just the chanspec. For 40MHz or wider channels it is the
+ * chanspec of the primary 20MHZ channel specified by the chanspec.
+ *
+ * @param chspec input chanspec
+ *
+ * @return Returns the chanspec of the primary 20MHz channel
+ */
+extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec);
+
+/**
+ * Return a channel number corresponding to a frequency.
+ *
+ * This function returns the chanspec for the primary 40MHz of an 80MHz channel.
+ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using
+ * as the primary 20MHz channel.
+ */
+extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec);
+
+/*
+ * Return the channel number for a given frequency and base frequency.
+ * The returned channel number is relative to the given base frequency.
+ * If the given base frequency is zero, a base frequency of 5 GHz is assumed for
+ * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz.
+ *
+ * Frequency is specified in MHz.
+ * The base frequency is specified as (start_factor * 500 kHz).
+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
+ * 2.4 GHz and 5 GHz bands.
+ *
+ * The returned channel will be in the range [1, 14] in the 2.4 GHz band
+ * and [0, 200] otherwise.
+ * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the
+ * frequency is not a 2.4 GHz channel, or if the frequency is not and even
+ * multiple of 5 MHz from the base frequency to the base plus 1 GHz.
+ *
+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
+ *
+ * @param freq frequency in MHz
+ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz
+ *
+ * @return Returns a channel number
+ *
+ * @see WF_CHAN_FACTOR_2_4_G
+ * @see WF_CHAN_FACTOR_5_G
+ */
+extern int wf_mhz2channel(uint freq, uint start_factor);
+
+/**
+ * Return the center frequency in MHz of the given channel and base frequency.
+ *
+ * Return the center frequency in MHz of the given channel and base frequency.
+ * The channel number is interpreted relative to the given base frequency.
+ *
+ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise.
+ * The base frequency is specified as (start_factor * 500 kHz).
+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
+ * 2.4 GHz and 5 GHz bands.
+ * The channel range of [1, 14] is only checked for a start_factor of
+ * WF_CHAN_FACTOR_2_4_G (4814).
+ * Odd start_factors produce channels on .5 MHz boundaries, in which case
+ * the answer is rounded down to an integral MHz.
+ * -1 is returned for an out of range channel.
+ *
+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
+ *
+ * @param channel input channel number
+ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz
+ *
+ * @return Returns a frequency in MHz
+ *
+ * @see WF_CHAN_FACTOR_2_4_G
+ * @see WF_CHAN_FACTOR_5_G
+ */
+extern int wf_channel2mhz(uint channel, uint start_factor);
+
+/**
+ * Returns the chanspec 80Mhz channel corresponding to the following input
+ * parameters
+ *
+ * primary_channel - primary 20Mhz channel
+ * center_channel - center frequecny of the 80Mhz channel
+ *
+ * The center_channel can be one of {42, 58, 106, 122, 138, 155}
+ *
+ * returns INVCHANSPEC in case of error
+ */
+extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel);
+
+/**
+ * Convert ctl chan and bw to chanspec
+ *
+ * @param ctl_ch channel
+ * @param bw bandwidth
+ *
+ * @return > 0 if successful or 0 otherwise
+ *
+ */
+extern uint16 wf_channel2chspec(uint ctl_ch, uint bw);
+
+extern uint wf_channel2freq(uint channel);
+extern uint wf_freq2channel(uint freq);
+
+/*
+ * Returns the 80+80 MHz chanspec corresponding to the following input parameters
+ *
+ * primary_20mhz - Primary 20 MHz channel
+ * chan0_80MHz - center channel number of one frequency segment
+ * chan1_80MHz - center channel number of the other frequency segment
+ *
+ * Parameters chan0_80MHz and chan1_80MHz are channel numbers in {42, 58, 106, 122, 138, 155}.
+ * The primary channel must be contained in one of the 80MHz channels. This routine
+ * will determine which frequency segment is the primary 80 MHz segment.
+ *
+ * Returns INVCHANSPEC in case of error.
+ *
+ * Refer to IEEE802.11ac section 22.3.14 "Channelization".
+ */
+extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz,
+ uint8 chan0_80Mhz, uint8 chan1_80Mhz);
+
+/*
+ * Returns the primary 80 Mhz channel for the provided chanspec
+ *
+ * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved
+ *
+ * returns -1 in case the provided channel is 20/40 Mhz chanspec
+ */
+extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec);
+
+/*
+ * Returns the secondary 80 Mhz channel for the provided chanspec
+ *
+ * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved
+ *
+ * returns -1 in case the provided channel is 20/40 Mhz chanspec
+ */
+extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec);
+
+/*
+ * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel.
+ */
+extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec);
+
+/*
+ * For 160MHz or 80P80 chanspec, set ch[0]/ch[1] to be the low/high 80 Mhz channels
+ *
+ * For 20/40/80MHz chanspec, set ch[0] to be the center freq, and chan[1]=-1
+ */
+extern void wf_chspec_get_80p80_channels(chanspec_t chspec, uint8 *ch);
+
+#ifdef WL11AC_80P80
+/*
+ * This function returns the centre chanel for the given chanspec.
+ * In case of 80+80 chanspec it returns the primary 80 Mhz centre channel
+ */
+extern uint8 wf_chspec_channel(chanspec_t chspec);
+#endif
+extern chanspec_t wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel);
+extern int wf_channel_create_opclass_frm_chspec(chanspec_t chspec);
+
+/* Populates array with all 20MHz side bands of a given chanspec_t in the following order:
+ * control, ext20, two ext40s, four ext80s.
+ * 'chspec' is the chanspec of interest
+ * 'pext' must point to an uint8 array of long enough to hold all side bands of the given chspec
+ *
+ * Works with 20, 40, 80, 80p80 and 160MHz chspec
+ */
+
+extern void wf_get_all_ext(chanspec_t chspec, uint8 *chan_ptr);
+#endif /* _bcmwifi_channels_h_ */
diff --git a/wl/src/shared/bcmwifi/include/bcmwifi_rates.h b/wl/src/shared/bcmwifi/include/bcmwifi_rates.h
new file mode 100644
index 0000000..70ed384
--- /dev/null
+++ b/wl/src/shared/bcmwifi/include/bcmwifi_rates.h
@@ -0,0 +1,787 @@
+/*
+ * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmwifi_rates.h 612483 2016-01-14 03:44:27Z $
+ */
+
+#ifndef _bcmwifi_rates_h_
+#define _bcmwifi_rates_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define WL_RATESET_SZ_DSSS 4
+#define WL_RATESET_SZ_OFDM 8
+#define WL_RATESET_SZ_VHT_MCS 10
+#define WL_RATESET_SZ_VHT_MCS_P 12
+
+#if defined(WLPROPRIETARY_11N_RATES)
+#define WL_RATESET_SZ_HT_MCS WL_RATESET_SZ_VHT_MCS
+#else
+#define WL_RATESET_SZ_HT_MCS 8
+#endif
+
+#define WL_RATESET_SZ_HT_IOCTL 8 /* MAC histogram, compatibility with wl utility */
+
+#define WL_TX_CHAINS_MAX 4
+
+#define WL_RATE_DISABLED (-128) /* Power value corresponding to unsupported rate */
+
+/* Transmit channel bandwidths */
+typedef enum wl_tx_bw {
+ WL_TX_BW_20,
+ WL_TX_BW_40,
+ WL_TX_BW_80,
+ WL_TX_BW_20IN40,
+ WL_TX_BW_20IN80,
+ WL_TX_BW_40IN80,
+ WL_TX_BW_160,
+ WL_TX_BW_20IN160,
+ WL_TX_BW_40IN160,
+ WL_TX_BW_80IN160,
+ WL_TX_BW_ALL,
+ WL_TX_BW_8080,
+ WL_TX_BW_8080CHAN2,
+ WL_TX_BW_20IN8080,
+ WL_TX_BW_40IN8080,
+ WL_TX_BW_80IN8080,
+ WL_TX_BW_2P5,
+ WL_TX_BW_5,
+ WL_TX_BW_10
+} wl_tx_bw_t;
+
+
+/*
+ * Transmit modes.
+ * Not all modes are listed here, only those required for disambiguation. e.g. SPEXP is not listed
+ */
+typedef enum wl_tx_mode {
+ WL_TX_MODE_NONE,
+ WL_TX_MODE_STBC,
+ WL_TX_MODE_CDD,
+ WL_TX_MODE_TXBF,
+ WL_NUM_TX_MODES
+} wl_tx_mode_t;
+
+
+/* Number of transmit chains */
+typedef enum wl_tx_chains {
+ WL_TX_CHAINS_1 = 1,
+ WL_TX_CHAINS_2,
+ WL_TX_CHAINS_3,
+ WL_TX_CHAINS_4
+} wl_tx_chains_t;
+
+
+/* Number of transmit streams */
+typedef enum wl_tx_nss {
+ WL_TX_NSS_1 = 1,
+ WL_TX_NSS_2,
+ WL_TX_NSS_3,
+ WL_TX_NSS_4
+} wl_tx_nss_t;
+
+
+/* This enum maps each rate to a CLM index */
+
+typedef enum clm_rates {
+ /************
+ * 1 chain *
+ ************
+ */
+
+ /* 1 Stream */
+ WL_RATE_1X1_DSSS_1 = 0,
+ WL_RATE_1X1_DSSS_2 = 1,
+ WL_RATE_1X1_DSSS_5_5 = 2,
+ WL_RATE_1X1_DSSS_11 = 3,
+
+ WL_RATE_1X1_OFDM_6 = 4,
+ WL_RATE_1X1_OFDM_9 = 5,
+ WL_RATE_1X1_OFDM_12 = 6,
+ WL_RATE_1X1_OFDM_18 = 7,
+ WL_RATE_1X1_OFDM_24 = 8,
+ WL_RATE_1X1_OFDM_36 = 9,
+ WL_RATE_1X1_OFDM_48 = 10,
+ WL_RATE_1X1_OFDM_54 = 11,
+
+ WL_RATE_1X1_MCS0 = 12,
+ WL_RATE_1X1_MCS1 = 13,
+ WL_RATE_1X1_MCS2 = 14,
+ WL_RATE_1X1_MCS3 = 15,
+ WL_RATE_1X1_MCS4 = 16,
+ WL_RATE_1X1_MCS5 = 17,
+ WL_RATE_1X1_MCS6 = 18,
+ WL_RATE_1X1_MCS7 = 19,
+ WL_RATE_P_1X1_MCS87 = 20,
+ WL_RATE_P_1X1_MCS88 = 21,
+
+ WL_RATE_1X1_VHT0SS1 = 12,
+ WL_RATE_1X1_VHT1SS1 = 13,
+ WL_RATE_1X1_VHT2SS1 = 14,
+ WL_RATE_1X1_VHT3SS1 = 15,
+ WL_RATE_1X1_VHT4SS1 = 16,
+ WL_RATE_1X1_VHT5SS1 = 17,
+ WL_RATE_1X1_VHT6SS1 = 18,
+ WL_RATE_1X1_VHT7SS1 = 19,
+ WL_RATE_1X1_VHT8SS1 = 20,
+ WL_RATE_1X1_VHT9SS1 = 21,
+ WL_RATE_P_1X1_VHT10SS1 = 22,
+ WL_RATE_P_1X1_VHT11SS1 = 23,
+
+
+ /************
+ * 2 chains *
+ ************
+ */
+
+ /* 1 Stream expanded + 1 */
+ WL_RATE_1X2_DSSS_1 = 24,
+ WL_RATE_1X2_DSSS_2 = 25,
+ WL_RATE_1X2_DSSS_5_5 = 26,
+ WL_RATE_1X2_DSSS_11 = 27,
+
+ WL_RATE_1X2_CDD_OFDM_6 = 28,
+ WL_RATE_1X2_CDD_OFDM_9 = 29,
+ WL_RATE_1X2_CDD_OFDM_12 = 30,
+ WL_RATE_1X2_CDD_OFDM_18 = 31,
+ WL_RATE_1X2_CDD_OFDM_24 = 32,
+ WL_RATE_1X2_CDD_OFDM_36 = 33,
+ WL_RATE_1X2_CDD_OFDM_48 = 34,
+ WL_RATE_1X2_CDD_OFDM_54 = 35,
+
+ WL_RATE_1X2_CDD_MCS0 = 36,
+ WL_RATE_1X2_CDD_MCS1 = 37,
+ WL_RATE_1X2_CDD_MCS2 = 38,
+ WL_RATE_1X2_CDD_MCS3 = 39,
+ WL_RATE_1X2_CDD_MCS4 = 40,
+ WL_RATE_1X2_CDD_MCS5 = 41,
+ WL_RATE_1X2_CDD_MCS6 = 42,
+ WL_RATE_1X2_CDD_MCS7 = 43,
+ WL_RATE_P_1X2_CDD_MCS87 = 44,
+ WL_RATE_P_1X2_CDD_MCS88 = 45,
+
+ WL_RATE_1X2_VHT0SS1 = 36,
+ WL_RATE_1X2_VHT1SS1 = 37,
+ WL_RATE_1X2_VHT2SS1 = 38,
+ WL_RATE_1X2_VHT3SS1 = 39,
+ WL_RATE_1X2_VHT4SS1 = 40,
+ WL_RATE_1X2_VHT5SS1 = 41,
+ WL_RATE_1X2_VHT6SS1 = 42,
+ WL_RATE_1X2_VHT7SS1 = 43,
+ WL_RATE_1X2_VHT8SS1 = 44,
+ WL_RATE_1X2_VHT9SS1 = 45,
+ WL_RATE_P_1X2_VHT10SS1 = 46,
+ WL_RATE_P_1X2_VHT11SS1 = 47,
+
+ /* 2 Streams */
+ WL_RATE_2X2_STBC_MCS0 = 48,
+ WL_RATE_2X2_STBC_MCS1 = 49,
+ WL_RATE_2X2_STBC_MCS2 = 50,
+ WL_RATE_2X2_STBC_MCS3 = 51,
+ WL_RATE_2X2_STBC_MCS4 = 52,
+ WL_RATE_2X2_STBC_MCS5 = 53,
+ WL_RATE_2X2_STBC_MCS6 = 54,
+ WL_RATE_2X2_STBC_MCS7 = 55,
+ WL_RATE_P_2X2_STBC_MCS87 = 56,
+ WL_RATE_P_2X2_STBC_MCS88 = 57,
+
+ WL_RATE_2X2_STBC_VHT0SS1 = 48,
+ WL_RATE_2X2_STBC_VHT1SS1 = 49,
+ WL_RATE_2X2_STBC_VHT2SS1 = 50,
+ WL_RATE_2X2_STBC_VHT3SS1 = 51,
+ WL_RATE_2X2_STBC_VHT4SS1 = 52,
+ WL_RATE_2X2_STBC_VHT5SS1 = 53,
+ WL_RATE_2X2_STBC_VHT6SS1 = 54,
+ WL_RATE_2X2_STBC_VHT7SS1 = 55,
+ WL_RATE_2X2_STBC_VHT8SS1 = 56,
+ WL_RATE_2X2_STBC_VHT9SS1 = 57,
+ WL_RATE_P_2X2_STBC_VHT10SS1 = 58,
+ WL_RATE_P_2X2_STBC_VHT11SS1 = 59,
+
+ WL_RATE_2X2_SDM_MCS8 = 60,
+ WL_RATE_2X2_SDM_MCS9 = 61,
+ WL_RATE_2X2_SDM_MCS10 = 62,
+ WL_RATE_2X2_SDM_MCS11 = 63,
+ WL_RATE_2X2_SDM_MCS12 = 64,
+ WL_RATE_2X2_SDM_MCS13 = 65,
+ WL_RATE_2X2_SDM_MCS14 = 66,
+ WL_RATE_2X2_SDM_MCS15 = 67,
+ WL_RATE_P_2X2_SDM_MCS99 = 68,
+ WL_RATE_P_2X2_SDM_MCS100 = 69,
+
+ WL_RATE_2X2_VHT0SS2 = 60,
+ WL_RATE_2X2_VHT1SS2 = 61,
+ WL_RATE_2X2_VHT2SS2 = 62,
+ WL_RATE_2X2_VHT3SS2 = 63,
+ WL_RATE_2X2_VHT4SS2 = 64,
+ WL_RATE_2X2_VHT5SS2 = 65,
+ WL_RATE_2X2_VHT6SS2 = 66,
+ WL_RATE_2X2_VHT7SS2 = 67,
+ WL_RATE_2X2_VHT8SS2 = 68,
+ WL_RATE_2X2_VHT9SS2 = 69,
+ WL_RATE_P_2X2_VHT10SS2 = 70,
+ WL_RATE_P_2X2_VHT11SS2 = 71,
+
+ /****************************
+ * TX Beamforming, 2 chains *
+ ****************************
+ */
+
+ /* 1 Stream expanded + 1 */
+ WL_RATE_1X2_TXBF_OFDM_6 = 72,
+ WL_RATE_1X2_TXBF_OFDM_9 = 73,
+ WL_RATE_1X2_TXBF_OFDM_12 = 74,
+ WL_RATE_1X2_TXBF_OFDM_18 = 75,
+ WL_RATE_1X2_TXBF_OFDM_24 = 76,
+ WL_RATE_1X2_TXBF_OFDM_36 = 77,
+ WL_RATE_1X2_TXBF_OFDM_48 = 78,
+ WL_RATE_1X2_TXBF_OFDM_54 = 79,
+
+ WL_RATE_1X2_TXBF_MCS0 = 80,
+ WL_RATE_1X2_TXBF_MCS1 = 81,
+ WL_RATE_1X2_TXBF_MCS2 = 82,
+ WL_RATE_1X2_TXBF_MCS3 = 83,
+ WL_RATE_1X2_TXBF_MCS4 = 84,
+ WL_RATE_1X2_TXBF_MCS5 = 85,
+ WL_RATE_1X2_TXBF_MCS6 = 86,
+ WL_RATE_1X2_TXBF_MCS7 = 87,
+ WL_RATE_P_1X2_TXBF_MCS87 = 88,
+ WL_RATE_P_1X2_TXBF_MCS88 = 89,
+
+ WL_RATE_1X2_TXBF_VHT0SS1 = 80,
+ WL_RATE_1X2_TXBF_VHT1SS1 = 81,
+ WL_RATE_1X2_TXBF_VHT2SS1 = 82,
+ WL_RATE_1X2_TXBF_VHT3SS1 = 83,
+ WL_RATE_1X2_TXBF_VHT4SS1 = 84,
+ WL_RATE_1X2_TXBF_VHT5SS1 = 85,
+ WL_RATE_1X2_TXBF_VHT6SS1 = 86,
+ WL_RATE_1X2_TXBF_VHT7SS1 = 87,
+ WL_RATE_1X2_TXBF_VHT8SS1 = 88,
+ WL_RATE_1X2_TXBF_VHT9SS1 = 89,
+ WL_RATE_P_1X2_TXBF_VHT10SS1 = 90,
+ WL_RATE_P_1X2_TXBF_VHT11SS1 = 91,
+
+ /* 2 Streams */
+ WL_RATE_2X2_TXBF_SDM_MCS8 = 92,
+ WL_RATE_2X2_TXBF_SDM_MCS9 = 93,
+ WL_RATE_2X2_TXBF_SDM_MCS10 = 94,
+ WL_RATE_2X2_TXBF_SDM_MCS11 = 95,
+ WL_RATE_2X2_TXBF_SDM_MCS12 = 96,
+ WL_RATE_2X2_TXBF_SDM_MCS13 = 97,
+ WL_RATE_2X2_TXBF_SDM_MCS14 = 98,
+ WL_RATE_2X2_TXBF_SDM_MCS15 = 99,
+ WL_RATE_P_2X2_TXBF_SDM_MCS99 = 100,
+ WL_RATE_P_2X2_TXBF_SDM_MCS100 = 101,
+
+ WL_RATE_2X2_TXBF_VHT0SS2 = 92,
+ WL_RATE_2X2_TXBF_VHT1SS2 = 93,
+ WL_RATE_2X2_TXBF_VHT2SS2 = 94,
+ WL_RATE_2X2_TXBF_VHT3SS2 = 95,
+ WL_RATE_2X2_TXBF_VHT4SS2 = 96,
+ WL_RATE_2X2_TXBF_VHT5SS2 = 97,
+ WL_RATE_2X2_TXBF_VHT6SS2 = 98,
+ WL_RATE_2X2_TXBF_VHT7SS2 = 99,
+ WL_RATE_2X2_TXBF_VHT8SS2 = 100,
+ WL_RATE_2X2_TXBF_VHT9SS2 = 101,
+ WL_RATE_P_2X2_TXBF_VHT10SS2 = 102,
+ WL_RATE_P_2X2_TXBF_VHT11SS2 = 103,
+
+
+ /************
+ * 3 chains *
+ ************
+ */
+
+ /* 1 Stream expanded + 2 */
+ WL_RATE_1X3_DSSS_1 = 104,
+ WL_RATE_1X3_DSSS_2 = 105,
+ WL_RATE_1X3_DSSS_5_5 = 106,
+ WL_RATE_1X3_DSSS_11 = 107,
+
+ WL_RATE_1X3_CDD_OFDM_6 = 108,
+ WL_RATE_1X3_CDD_OFDM_9 = 109,
+ WL_RATE_1X3_CDD_OFDM_12 = 110,
+ WL_RATE_1X3_CDD_OFDM_18 = 111,
+ WL_RATE_1X3_CDD_OFDM_24 = 112,
+ WL_RATE_1X3_CDD_OFDM_36 = 113,
+ WL_RATE_1X3_CDD_OFDM_48 = 114,
+ WL_RATE_1X3_CDD_OFDM_54 = 115,
+
+ WL_RATE_1X3_CDD_MCS0 = 116,
+ WL_RATE_1X3_CDD_MCS1 = 117,
+ WL_RATE_1X3_CDD_MCS2 = 118,
+ WL_RATE_1X3_CDD_MCS3 = 119,
+ WL_RATE_1X3_CDD_MCS4 = 120,
+ WL_RATE_1X3_CDD_MCS5 = 121,
+ WL_RATE_1X3_CDD_MCS6 = 122,
+ WL_RATE_1X3_CDD_MCS7 = 123,
+ WL_RATE_P_1X3_CDD_MCS87 = 124,
+ WL_RATE_P_1X3_CDD_MCS88 = 125,
+
+ WL_RATE_1X3_VHT0SS1 = 116,
+ WL_RATE_1X3_VHT1SS1 = 117,
+ WL_RATE_1X3_VHT2SS1 = 118,
+ WL_RATE_1X3_VHT3SS1 = 119,
+ WL_RATE_1X3_VHT4SS1 = 120,
+ WL_RATE_1X3_VHT5SS1 = 121,
+ WL_RATE_1X3_VHT6SS1 = 122,
+ WL_RATE_1X3_VHT7SS1 = 123,
+ WL_RATE_1X3_VHT8SS1 = 124,
+ WL_RATE_1X3_VHT9SS1 = 125,
+ WL_RATE_P_1X3_VHT10SS1 = 126,
+ WL_RATE_P_1X3_VHT11SS1 = 127,
+
+ /* 2 Streams expanded + 1 */
+ WL_RATE_2X3_STBC_MCS0 = 128,
+ WL_RATE_2X3_STBC_MCS1 = 129,
+ WL_RATE_2X3_STBC_MCS2 = 130,
+ WL_RATE_2X3_STBC_MCS3 = 131,
+ WL_RATE_2X3_STBC_MCS4 = 132,
+ WL_RATE_2X3_STBC_MCS5 = 133,
+ WL_RATE_2X3_STBC_MCS6 = 134,
+ WL_RATE_2X3_STBC_MCS7 = 135,
+ WL_RATE_P_2X3_STBC_MCS87 = 136,
+ WL_RATE_P_2X3_STBC_MCS88 = 137,
+
+ WL_RATE_2X3_STBC_VHT0SS1 = 128,
+ WL_RATE_2X3_STBC_VHT1SS1 = 129,
+ WL_RATE_2X3_STBC_VHT2SS1 = 130,
+ WL_RATE_2X3_STBC_VHT3SS1 = 131,
+ WL_RATE_2X3_STBC_VHT4SS1 = 132,
+ WL_RATE_2X3_STBC_VHT5SS1 = 133,
+ WL_RATE_2X3_STBC_VHT6SS1 = 134,
+ WL_RATE_2X3_STBC_VHT7SS1 = 135,
+ WL_RATE_2X3_STBC_VHT8SS1 = 136,
+ WL_RATE_2X3_STBC_VHT9SS1 = 137,
+ WL_RATE_P_2X3_STBC_VHT10SS1 = 138,
+ WL_RATE_P_2X3_STBC_VHT11SS1 = 139,
+
+ WL_RATE_2X3_SDM_MCS8 = 140,
+ WL_RATE_2X3_SDM_MCS9 = 141,
+ WL_RATE_2X3_SDM_MCS10 = 142,
+ WL_RATE_2X3_SDM_MCS11 = 143,
+ WL_RATE_2X3_SDM_MCS12 = 144,
+ WL_RATE_2X3_SDM_MCS13 = 145,
+ WL_RATE_2X3_SDM_MCS14 = 146,
+ WL_RATE_2X3_SDM_MCS15 = 147,
+ WL_RATE_P_2X3_SDM_MCS99 = 148,
+ WL_RATE_P_2X3_SDM_MCS100 = 149,
+
+ WL_RATE_2X3_VHT0SS2 = 140,
+ WL_RATE_2X3_VHT1SS2 = 141,
+ WL_RATE_2X3_VHT2SS2 = 142,
+ WL_RATE_2X3_VHT3SS2 = 143,
+ WL_RATE_2X3_VHT4SS2 = 144,
+ WL_RATE_2X3_VHT5SS2 = 145,
+ WL_RATE_2X3_VHT6SS2 = 146,
+ WL_RATE_2X3_VHT7SS2 = 147,
+ WL_RATE_2X3_VHT8SS2 = 148,
+ WL_RATE_2X3_VHT9SS2 = 149,
+ WL_RATE_P_2X3_VHT10SS2 = 150,
+ WL_RATE_P_2X3_VHT11SS2 = 151,
+
+ /* 3 Streams */
+ WL_RATE_3X3_SDM_MCS16 = 152,
+ WL_RATE_3X3_SDM_MCS17 = 153,
+ WL_RATE_3X3_SDM_MCS18 = 154,
+ WL_RATE_3X3_SDM_MCS19 = 155,
+ WL_RATE_3X3_SDM_MCS20 = 156,
+ WL_RATE_3X3_SDM_MCS21 = 157,
+ WL_RATE_3X3_SDM_MCS22 = 158,
+ WL_RATE_3X3_SDM_MCS23 = 159,
+ WL_RATE_P_3X3_SDM_MCS101 = 160,
+ WL_RATE_P_3X3_SDM_MCS102 = 161,
+
+ WL_RATE_3X3_VHT0SS3 = 152,
+ WL_RATE_3X3_VHT1SS3 = 153,
+ WL_RATE_3X3_VHT2SS3 = 154,
+ WL_RATE_3X3_VHT3SS3 = 155,
+ WL_RATE_3X3_VHT4SS3 = 156,
+ WL_RATE_3X3_VHT5SS3 = 157,
+ WL_RATE_3X3_VHT6SS3 = 158,
+ WL_RATE_3X3_VHT7SS3 = 159,
+ WL_RATE_3X3_VHT8SS3 = 160,
+ WL_RATE_3X3_VHT9SS3 = 161,
+ WL_RATE_P_3X3_VHT10SS3 = 162,
+ WL_RATE_P_3X3_VHT11SS3 = 163,
+
+
+ /****************************
+ * TX Beamforming, 3 chains *
+ ****************************
+ */
+
+ /* 1 Stream expanded + 2 */
+ WL_RATE_1X3_TXBF_OFDM_6 = 164,
+ WL_RATE_1X3_TXBF_OFDM_9 = 165,
+ WL_RATE_1X3_TXBF_OFDM_12 = 166,
+ WL_RATE_1X3_TXBF_OFDM_18 = 167,
+ WL_RATE_1X3_TXBF_OFDM_24 = 168,
+ WL_RATE_1X3_TXBF_OFDM_36 = 169,
+ WL_RATE_1X3_TXBF_OFDM_48 = 170,
+ WL_RATE_1X3_TXBF_OFDM_54 = 171,
+
+ WL_RATE_1X3_TXBF_MCS0 = 172,
+ WL_RATE_1X3_TXBF_MCS1 = 173,
+ WL_RATE_1X3_TXBF_MCS2 = 174,
+ WL_RATE_1X3_TXBF_MCS3 = 175,
+ WL_RATE_1X3_TXBF_MCS4 = 176,
+ WL_RATE_1X3_TXBF_MCS5 = 177,
+ WL_RATE_1X3_TXBF_MCS6 = 178,
+ WL_RATE_1X3_TXBF_MCS7 = 179,
+ WL_RATE_P_1X3_TXBF_MCS87 = 180,
+ WL_RATE_P_1X3_TXBF_MCS88 = 181,
+
+ WL_RATE_1X3_TXBF_VHT0SS1 = 172,
+ WL_RATE_1X3_TXBF_VHT1SS1 = 173,
+ WL_RATE_1X3_TXBF_VHT2SS1 = 174,
+ WL_RATE_1X3_TXBF_VHT3SS1 = 175,
+ WL_RATE_1X3_TXBF_VHT4SS1 = 176,
+ WL_RATE_1X3_TXBF_VHT5SS1 = 177,
+ WL_RATE_1X3_TXBF_VHT6SS1 = 178,
+ WL_RATE_1X3_TXBF_VHT7SS1 = 179,
+ WL_RATE_1X3_TXBF_VHT8SS1 = 180,
+ WL_RATE_1X3_TXBF_VHT9SS1 = 181,
+ WL_RATE_P_1X3_TXBF_VHT10SS1 = 182,
+ WL_RATE_P_1X3_TXBF_VHT11SS1 = 183,
+
+ /* 2 Streams expanded + 1 */
+ WL_RATE_2X3_TXBF_SDM_MCS8 = 184,
+ WL_RATE_2X3_TXBF_SDM_MCS9 = 185,
+ WL_RATE_2X3_TXBF_SDM_MCS10 = 186,
+ WL_RATE_2X3_TXBF_SDM_MCS11 = 187,
+ WL_RATE_2X3_TXBF_SDM_MCS12 = 188,
+ WL_RATE_2X3_TXBF_SDM_MCS13 = 189,
+ WL_RATE_2X3_TXBF_SDM_MCS14 = 190,
+ WL_RATE_2X3_TXBF_SDM_MCS15 = 191,
+ WL_RATE_P_2X3_TXBF_SDM_MCS99 = 192,
+ WL_RATE_P_2X3_TXBF_SDM_MCS100 = 193,
+
+ WL_RATE_2X3_TXBF_VHT0SS2 = 184,
+ WL_RATE_2X3_TXBF_VHT1SS2 = 185,
+ WL_RATE_2X3_TXBF_VHT2SS2 = 186,
+ WL_RATE_2X3_TXBF_VHT3SS2 = 187,
+ WL_RATE_2X3_TXBF_VHT4SS2 = 188,
+ WL_RATE_2X3_TXBF_VHT5SS2 = 189,
+ WL_RATE_2X3_TXBF_VHT6SS2 = 190,
+ WL_RATE_2X3_TXBF_VHT7SS2 = 191,
+ WL_RATE_2X3_TXBF_VHT8SS2 = 192,
+ WL_RATE_2X3_TXBF_VHT9SS2 = 193,
+ WL_RATE_P_2X3_TXBF_VHT10SS2 = 194,
+ WL_RATE_P_2X3_TXBF_VHT11SS2 = 195,
+
+ /* 3 Streams */
+ WL_RATE_3X3_TXBF_SDM_MCS16 = 196,
+ WL_RATE_3X3_TXBF_SDM_MCS17 = 197,
+ WL_RATE_3X3_TXBF_SDM_MCS18 = 198,
+ WL_RATE_3X3_TXBF_SDM_MCS19 = 199,
+ WL_RATE_3X3_TXBF_SDM_MCS20 = 200,
+ WL_RATE_3X3_TXBF_SDM_MCS21 = 201,
+ WL_RATE_3X3_TXBF_SDM_MCS22 = 202,
+ WL_RATE_3X3_TXBF_SDM_MCS23 = 203,
+ WL_RATE_P_3X3_TXBF_SDM_MCS101 = 204,
+ WL_RATE_P_3X3_TXBF_SDM_MCS102 = 205,
+
+ WL_RATE_3X3_TXBF_VHT0SS3 = 196,
+ WL_RATE_3X3_TXBF_VHT1SS3 = 197,
+ WL_RATE_3X3_TXBF_VHT2SS3 = 198,
+ WL_RATE_3X3_TXBF_VHT3SS3 = 199,
+ WL_RATE_3X3_TXBF_VHT4SS3 = 200,
+ WL_RATE_3X3_TXBF_VHT5SS3 = 201,
+ WL_RATE_3X3_TXBF_VHT6SS3 = 202,
+ WL_RATE_3X3_TXBF_VHT7SS3 = 203,
+ WL_RATE_3X3_TXBF_VHT8SS3 = 204,
+ WL_RATE_3X3_TXBF_VHT9SS3 = 205,
+ WL_RATE_P_3X3_TXBF_VHT10SS3 = 206,
+ WL_RATE_P_3X3_TXBF_VHT11SS3 = 207,
+
+
+ /************
+ * 4 chains *
+ ************
+ */
+
+ /* 1 Stream expanded + 3 */
+ WL_RATE_1X4_DSSS_1 = 208,
+ WL_RATE_1X4_DSSS_2 = 209,
+ WL_RATE_1X4_DSSS_5_5 = 210,
+ WL_RATE_1X4_DSSS_11 = 211,
+
+ WL_RATE_1X4_CDD_OFDM_6 = 212,
+ WL_RATE_1X4_CDD_OFDM_9 = 213,
+ WL_RATE_1X4_CDD_OFDM_12 = 214,
+ WL_RATE_1X4_CDD_OFDM_18 = 215,
+ WL_RATE_1X4_CDD_OFDM_24 = 216,
+ WL_RATE_1X4_CDD_OFDM_36 = 217,
+ WL_RATE_1X4_CDD_OFDM_48 = 218,
+ WL_RATE_1X4_CDD_OFDM_54 = 219,
+
+ WL_RATE_1X4_CDD_MCS0 = 220,
+ WL_RATE_1X4_CDD_MCS1 = 221,
+ WL_RATE_1X4_CDD_MCS2 = 222,
+ WL_RATE_1X4_CDD_MCS3 = 223,
+ WL_RATE_1X4_CDD_MCS4 = 224,
+ WL_RATE_1X4_CDD_MCS5 = 225,
+ WL_RATE_1X4_CDD_MCS6 = 226,
+ WL_RATE_1X4_CDD_MCS7 = 227,
+ WL_RATE_P_1X4_CDD_MCS87 = 228,
+ WL_RATE_P_1X4_CDD_MCS88 = 229,
+
+ WL_RATE_1X4_VHT0SS1 = 220,
+ WL_RATE_1X4_VHT1SS1 = 221,
+ WL_RATE_1X4_VHT2SS1 = 222,
+ WL_RATE_1X4_VHT3SS1 = 223,
+ WL_RATE_1X4_VHT4SS1 = 224,
+ WL_RATE_1X4_VHT5SS1 = 225,
+ WL_RATE_1X4_VHT6SS1 = 226,
+ WL_RATE_1X4_VHT7SS1 = 227,
+ WL_RATE_1X4_VHT8SS1 = 228,
+ WL_RATE_1X4_VHT9SS1 = 229,
+ WL_RATE_P_1X4_VHT10SS1 = 230,
+ WL_RATE_P_1X4_VHT11SS1 = 231,
+
+ /* 2 Streams expanded + 2 */
+ WL_RATE_2X4_STBC_MCS0 = 232,
+ WL_RATE_2X4_STBC_MCS1 = 233,
+ WL_RATE_2X4_STBC_MCS2 = 234,
+ WL_RATE_2X4_STBC_MCS3 = 235,
+ WL_RATE_2X4_STBC_MCS4 = 236,
+ WL_RATE_2X4_STBC_MCS5 = 237,
+ WL_RATE_2X4_STBC_MCS6 = 238,
+ WL_RATE_2X4_STBC_MCS7 = 239,
+ WL_RATE_P_2X4_STBC_MCS87 = 240,
+ WL_RATE_P_2X4_STBC_MCS88 = 241,
+
+ WL_RATE_2X4_STBC_VHT0SS1 = 232,
+ WL_RATE_2X4_STBC_VHT1SS1 = 233,
+ WL_RATE_2X4_STBC_VHT2SS1 = 234,
+ WL_RATE_2X4_STBC_VHT3SS1 = 235,
+ WL_RATE_2X4_STBC_VHT4SS1 = 236,
+ WL_RATE_2X4_STBC_VHT5SS1 = 237,
+ WL_RATE_2X4_STBC_VHT6SS1 = 238,
+ WL_RATE_2X4_STBC_VHT7SS1 = 239,
+ WL_RATE_2X4_STBC_VHT8SS1 = 240,
+ WL_RATE_2X4_STBC_VHT9SS1 = 241,
+ WL_RATE_P_2X4_STBC_VHT10SS1 = 242,
+ WL_RATE_P_2X4_STBC_VHT11SS1 = 243,
+
+ WL_RATE_2X4_SDM_MCS8 = 244,
+ WL_RATE_2X4_SDM_MCS9 = 245,
+ WL_RATE_2X4_SDM_MCS10 = 246,
+ WL_RATE_2X4_SDM_MCS11 = 247,
+ WL_RATE_2X4_SDM_MCS12 = 248,
+ WL_RATE_2X4_SDM_MCS13 = 249,
+ WL_RATE_2X4_SDM_MCS14 = 250,
+ WL_RATE_2X4_SDM_MCS15 = 251,
+ WL_RATE_P_2X4_SDM_MCS99 = 252,
+ WL_RATE_P_2X4_SDM_MCS100 = 253,
+
+ WL_RATE_2X4_VHT0SS2 = 244,
+ WL_RATE_2X4_VHT1SS2 = 245,
+ WL_RATE_2X4_VHT2SS2 = 246,
+ WL_RATE_2X4_VHT3SS2 = 247,
+ WL_RATE_2X4_VHT4SS2 = 248,
+ WL_RATE_2X4_VHT5SS2 = 249,
+ WL_RATE_2X4_VHT6SS2 = 250,
+ WL_RATE_2X4_VHT7SS2 = 251,
+ WL_RATE_2X4_VHT8SS2 = 252,
+ WL_RATE_2X4_VHT9SS2 = 253,
+ WL_RATE_P_2X4_VHT10SS2 = 254,
+ WL_RATE_P_2X4_VHT11SS2 = 255,
+
+ /* 3 Streams expanded + 1 */
+ WL_RATE_3X4_SDM_MCS16 = 256,
+ WL_RATE_3X4_SDM_MCS17 = 257,
+ WL_RATE_3X4_SDM_MCS18 = 258,
+ WL_RATE_3X4_SDM_MCS19 = 259,
+ WL_RATE_3X4_SDM_MCS20 = 260,
+ WL_RATE_3X4_SDM_MCS21 = 261,
+ WL_RATE_3X4_SDM_MCS22 = 262,
+ WL_RATE_3X4_SDM_MCS23 = 263,
+ WL_RATE_P_3X4_SDM_MCS101 = 264,
+ WL_RATE_P_3X4_SDM_MCS102 = 265,
+
+ WL_RATE_3X4_VHT0SS3 = 256,
+ WL_RATE_3X4_VHT1SS3 = 257,
+ WL_RATE_3X4_VHT2SS3 = 258,
+ WL_RATE_3X4_VHT3SS3 = 259,
+ WL_RATE_3X4_VHT4SS3 = 260,
+ WL_RATE_3X4_VHT5SS3 = 261,
+ WL_RATE_3X4_VHT6SS3 = 262,
+ WL_RATE_3X4_VHT7SS3 = 263,
+ WL_RATE_3X4_VHT8SS3 = 264,
+ WL_RATE_3X4_VHT9SS3 = 265,
+ WL_RATE_P_3X4_VHT10SS3 = 266,
+ WL_RATE_P_3X4_VHT11SS3 = 267,
+
+
+ /* 4 Streams */
+ WL_RATE_4X4_SDM_MCS24 = 268,
+ WL_RATE_4X4_SDM_MCS25 = 269,
+ WL_RATE_4X4_SDM_MCS26 = 270,
+ WL_RATE_4X4_SDM_MCS27 = 271,
+ WL_RATE_4X4_SDM_MCS28 = 272,
+ WL_RATE_4X4_SDM_MCS29 = 273,
+ WL_RATE_4X4_SDM_MCS30 = 274,
+ WL_RATE_4X4_SDM_MCS31 = 275,
+ WL_RATE_P_4X4_SDM_MCS103 = 276,
+ WL_RATE_P_4X4_SDM_MCS104 = 277,
+
+ WL_RATE_4X4_VHT0SS4 = 268,
+ WL_RATE_4X4_VHT1SS4 = 269,
+ WL_RATE_4X4_VHT2SS4 = 270,
+ WL_RATE_4X4_VHT3SS4 = 271,
+ WL_RATE_4X4_VHT4SS4 = 272,
+ WL_RATE_4X4_VHT5SS4 = 273,
+ WL_RATE_4X4_VHT6SS4 = 274,
+ WL_RATE_4X4_VHT7SS4 = 275,
+ WL_RATE_4X4_VHT8SS4 = 276,
+ WL_RATE_4X4_VHT9SS4 = 277,
+ WL_RATE_P_4X4_VHT10SS4 = 278,
+ WL_RATE_P_4X4_VHT11SS4 = 279,
+
+
+ /****************************
+ * TX Beamforming, 4 chains *
+ ****************************
+ */
+
+ /* 1 Stream expanded + 3 */
+ WL_RATE_1X4_TXBF_OFDM_6 = 280,
+ WL_RATE_1X4_TXBF_OFDM_9 = 281,
+ WL_RATE_1X4_TXBF_OFDM_12 = 282,
+ WL_RATE_1X4_TXBF_OFDM_18 = 283,
+ WL_RATE_1X4_TXBF_OFDM_24 = 284,
+ WL_RATE_1X4_TXBF_OFDM_36 = 285,
+ WL_RATE_1X4_TXBF_OFDM_48 = 286,
+ WL_RATE_1X4_TXBF_OFDM_54 = 287,
+
+ WL_RATE_1X4_TXBF_MCS0 = 288,
+ WL_RATE_1X4_TXBF_MCS1 = 289,
+ WL_RATE_1X4_TXBF_MCS2 = 290,
+ WL_RATE_1X4_TXBF_MCS3 = 291,
+ WL_RATE_1X4_TXBF_MCS4 = 292,
+ WL_RATE_1X4_TXBF_MCS5 = 293,
+ WL_RATE_1X4_TXBF_MCS6 = 294,
+ WL_RATE_1X4_TXBF_MCS7 = 295,
+ WL_RATE_P_1X4_TXBF_MCS87 = 296,
+ WL_RATE_P_1X4_TXBF_MCS88 = 297,
+
+ WL_RATE_1X4_TXBF_VHT0SS1 = 288,
+ WL_RATE_1X4_TXBF_VHT1SS1 = 289,
+ WL_RATE_1X4_TXBF_VHT2SS1 = 290,
+ WL_RATE_1X4_TXBF_VHT3SS1 = 291,
+ WL_RATE_1X4_TXBF_VHT4SS1 = 292,
+ WL_RATE_1X4_TXBF_VHT5SS1 = 293,
+ WL_RATE_1X4_TXBF_VHT6SS1 = 294,
+ WL_RATE_1X4_TXBF_VHT7SS1 = 295,
+ WL_RATE_1X4_TXBF_VHT8SS1 = 296,
+ WL_RATE_1X4_TXBF_VHT9SS1 = 297,
+ WL_RATE_P_1X4_TXBF_VHT10SS1 = 298,
+ WL_RATE_P_1X4_TXBF_VHT11SS1 = 299,
+
+ /* 2 Streams expanded + 2 */
+ WL_RATE_2X4_TXBF_SDM_MCS8 = 300,
+ WL_RATE_2X4_TXBF_SDM_MCS9 = 301,
+ WL_RATE_2X4_TXBF_SDM_MCS10 = 302,
+ WL_RATE_2X4_TXBF_SDM_MCS11 = 303,
+ WL_RATE_2X4_TXBF_SDM_MCS12 = 304,
+ WL_RATE_2X4_TXBF_SDM_MCS13 = 305,
+ WL_RATE_2X4_TXBF_SDM_MCS14 = 306,
+ WL_RATE_2X4_TXBF_SDM_MCS15 = 307,
+ WL_RATE_P_2X4_TXBF_SDM_MCS99 = 308,
+ WL_RATE_P_2X4_TXBF_SDM_MCS100 = 309,
+
+ WL_RATE_2X4_TXBF_VHT0SS2 = 300,
+ WL_RATE_2X4_TXBF_VHT1SS2 = 301,
+ WL_RATE_2X4_TXBF_VHT2SS2 = 302,
+ WL_RATE_2X4_TXBF_VHT3SS2 = 303,
+ WL_RATE_2X4_TXBF_VHT4SS2 = 304,
+ WL_RATE_2X4_TXBF_VHT5SS2 = 305,
+ WL_RATE_2X4_TXBF_VHT6SS2 = 306,
+ WL_RATE_2X4_TXBF_VHT7SS2 = 307,
+ WL_RATE_2X4_TXBF_VHT8SS2 = 308,
+ WL_RATE_2X4_TXBF_VHT9SS2 = 309,
+ WL_RATE_P_2X4_TXBF_VHT10SS2 = 310,
+ WL_RATE_P_2X4_TXBF_VHT11SS2 = 311,
+
+ /* 3 Streams expanded + 1 */
+ WL_RATE_3X4_TXBF_SDM_MCS16 = 312,
+ WL_RATE_3X4_TXBF_SDM_MCS17 = 313,
+ WL_RATE_3X4_TXBF_SDM_MCS18 = 314,
+ WL_RATE_3X4_TXBF_SDM_MCS19 = 315,
+ WL_RATE_3X4_TXBF_SDM_MCS20 = 316,
+ WL_RATE_3X4_TXBF_SDM_MCS21 = 317,
+ WL_RATE_3X4_TXBF_SDM_MCS22 = 318,
+ WL_RATE_3X4_TXBF_SDM_MCS23 = 319,
+ WL_RATE_P_3X4_TXBF_SDM_MCS101 = 320,
+ WL_RATE_P_3X4_TXBF_SDM_MCS102 = 321,
+
+ WL_RATE_3X4_TXBF_VHT0SS3 = 312,
+ WL_RATE_3X4_TXBF_VHT1SS3 = 313,
+ WL_RATE_3X4_TXBF_VHT2SS3 = 314,
+ WL_RATE_3X4_TXBF_VHT3SS3 = 315,
+ WL_RATE_3X4_TXBF_VHT4SS3 = 316,
+ WL_RATE_3X4_TXBF_VHT5SS3 = 317,
+ WL_RATE_3X4_TXBF_VHT6SS3 = 318,
+ WL_RATE_3X4_TXBF_VHT7SS3 = 319,
+ WL_RATE_P_3X4_TXBF_VHT8SS3 = 320,
+ WL_RATE_P_3X4_TXBF_VHT9SS3 = 321,
+ WL_RATE_P_3X4_TXBF_VHT10SS3 = 322,
+ WL_RATE_P_3X4_TXBF_VHT11SS3 = 323,
+
+ /* 4 Streams */
+ WL_RATE_4X4_TXBF_SDM_MCS24 = 324,
+ WL_RATE_4X4_TXBF_SDM_MCS25 = 325,
+ WL_RATE_4X4_TXBF_SDM_MCS26 = 326,
+ WL_RATE_4X4_TXBF_SDM_MCS27 = 327,
+ WL_RATE_4X4_TXBF_SDM_MCS28 = 328,
+ WL_RATE_4X4_TXBF_SDM_MCS29 = 329,
+ WL_RATE_4X4_TXBF_SDM_MCS30 = 330,
+ WL_RATE_4X4_TXBF_SDM_MCS31 = 331,
+ WL_RATE_P_4X4_TXBF_SDM_MCS103 = 332,
+ WL_RATE_P_4X4_TXBF_SDM_MCS104 = 333,
+
+ WL_RATE_4X4_TXBF_VHT0SS4 = 324,
+ WL_RATE_4X4_TXBF_VHT1SS4 = 325,
+ WL_RATE_4X4_TXBF_VHT2SS4 = 326,
+ WL_RATE_4X4_TXBF_VHT3SS4 = 327,
+ WL_RATE_4X4_TXBF_VHT4SS4 = 328,
+ WL_RATE_4X4_TXBF_VHT5SS4 = 329,
+ WL_RATE_4X4_TXBF_VHT6SS4 = 330,
+ WL_RATE_4X4_TXBF_VHT7SS4 = 331,
+ WL_RATE_P_4X4_TXBF_VHT8SS4 = 332,
+ WL_RATE_P_4X4_TXBF_VHT9SS4 = 333,
+ WL_RATE_P_4X4_TXBF_VHT10SS4 = 334,
+ WL_RATE_P_4X4_TXBF_VHT11SS4 = 335
+
+} clm_rates_t;
+
+/* Number of rate codes */
+#define WL_NUMRATES 336
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _bcmwifi_rates_h_ */
diff --git a/wl/src/shared/bcmwifi/src/bcmwifi_channels.c b/wl/src/shared/bcmwifi/src/bcmwifi_channels.c
new file mode 100644
index 0000000..c3738ed
--- /dev/null
+++ b/wl/src/shared/bcmwifi/src/bcmwifi_channels.c
@@ -0,0 +1,1452 @@
+/*
+ * Misc utility routines used by kernel or app-level.
+ * Contents are wifi-specific, used by any kernel or app-level
+ * software that might want wifi things as it grows.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmwifi_channels.c 655845 2016-08-24 01:05:41Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmutils.h>
+
+#ifdef BCMDRIVER
+#include <osl.h>
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifndef ASSERT
+#define ASSERT(exp)
+#endif
+#endif /* BCMDRIVER */
+
+#include <bcmwifi_channels.h>
+
+#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
+#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
+#endif
+
+/* Definitions for D11AC capable Chanspec type */
+
+/* Chanspec ASCII representation with 802.11ac capability:
+ * [<band> 'g'] <channel> ['/'<bandwidth> [<ctl-sideband>]['/'<1st80channel>'-'<2nd80channel>]]
+ *
+ * <band>:
+ * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively.
+ * Default value is 2g if channel <= 14, otherwise 5g.
+ * <channel>:
+ * channel number of the 5MHz, 10MHz, 20MHz channel,
+ * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel.
+ * <bandwidth>:
+ * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20.
+ * <primary-sideband>:
+ * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower.
+ *
+ * For 2.4GHz band 40MHz channels, the same primary channel may be the
+ * upper sideband for one 40MHz channel, and the lower sideband for an
+ * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel
+ * is being specified.
+ *
+ * For 40MHz in the 5GHz band and all channel bandwidths greater than
+ * 40MHz, the U/L specificaion is not allowed since the channels are
+ * non-overlapping and the primary sub-band is derived from its
+ * position in the wide bandwidth channel.
+ *
+ * <1st80Channel>:
+ * <2nd80Channel>:
+ * Required for 80+80, otherwise not allowed.
+ * Specifies the center channel of the first and second 80MHz band.
+ *
+ * In its simplest form, it is a 20MHz channel number, with the implied band
+ * of 2.4GHz if channel number <= 14, and 5GHz otherwise.
+ *
+ * To allow for backward compatibility with scripts, the old form for
+ * 40MHz channels is also allowed: <channel><ctl-sideband>
+ *
+ * <channel>:
+ * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz
+ * <ctl-sideband>:
+ * "U" for upper, "L" for lower (or lower case "u" "l")
+ *
+ * 5 GHz Examples:
+ * Chanspec BW Center Ch Channel Range Primary Ch
+ * 5g8 20MHz 8 - -
+ * 52 20MHz 52 - -
+ * 52/40 40MHz 54 52-56 52
+ * 56/40 40MHz 54 52-56 56
+ * 52/80 80MHz 58 52-64 52
+ * 56/80 80MHz 58 52-64 56
+ * 60/80 80MHz 58 52-64 60
+ * 64/80 80MHz 58 52-64 64
+ * 52/160 160MHz 50 36-64 52
+ * 36/160 160MGz 50 36-64 36
+ * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36
+ *
+ * 2 GHz Examples:
+ * Chanspec BW Center Ch Channel Range Primary Ch
+ * 2g8 20MHz 8 - -
+ * 8 20MHz 8 - -
+ * 6 20MHz 6 - -
+ * 6/40l 40MHz 8 6-10 6
+ * 6l 40MHz 8 6-10 6
+ * 6/40u 40MHz 4 2-6 6
+ * 6u 40MHz 4 2-6 6
+ */
+
+/* bandwidth ASCII string */
+static const char *wf_chspec_bw_str[] =
+{
+ "5",
+ "10",
+ "20",
+ "40",
+ "80",
+ "160",
+ "80+80",
+#ifdef WL11ULB
+ "2.5"
+#else /* WL11ULB */
+ "na"
+#endif /* WL11ULB */
+};
+
+static const uint16 wf_chspec_bw_half_mhz[] = {
+ 10, /* 5MHz (WL_CHANSPEC_BW_5) */
+ 20, /* 10MHz (WL_CHANSPEC_BW_10) */
+ 40, /* 20MHz (WL_CHANSPEC_BW_20) */
+ 80, /* 40MHz (WL_CHANSPEC_BW_40) */
+ 160, /* 80MHz (WL_CHANSPEC_BW_80) */
+ 320, /* 160MHz (WL_CHANSPEC_BW_160) */
+ 320, /* 160MHz (WL_CHANSPEC_BW_8080) */
+ 5 /* 2.5MHz (WL_CHANSPEC_BW_2P5) */
+};
+
+#define WF_NUM_BW_HALF_MHZ ARRAYSIZE(wf_chspec_bw_half_mhz)
+
+static const uint8 wf_chspec_bw_mhz[] =
+{5, 10, 20, 40, 80, 160, 160};
+
+#define WF_NUM_BW \
+ (sizeof(wf_chspec_bw_mhz)/sizeof(uint8))
+
+/* 40MHz channels in 5GHz band */
+static const uint8 wf_5g_40m_chans[] =
+{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159};
+#define WF_NUM_5G_40M_CHANS \
+ (sizeof(wf_5g_40m_chans)/sizeof(uint8))
+
+/* 80MHz channels in 5GHz band */
+static const uint8 wf_5g_80m_chans[] =
+{42, 58, 106, 122, 138, 155};
+#define WF_NUM_5G_80M_CHANS \
+ (sizeof(wf_5g_80m_chans)/sizeof(uint8))
+
+/* 160MHz channels in 5GHz band */
+static const uint8 wf_5g_160m_chans[] =
+{50, 114};
+#define WF_NUM_5G_160M_CHANS \
+ (sizeof(wf_5g_160m_chans)/sizeof(uint8))
+
+/* opclass and channel information for US. Table E-1 */
+static const uint16 opclass_data[] = {
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
+ 0,
+ 0,
+ 0,
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
+ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
+ (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
+ (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
+};
+
+/* Get bandwidth of chanspec in half MHz;
+ * works with 2.5MHz to 160MHz (including 80p80) chanspecs
+ *
+ * @param chspec chanspec_t format
+ *
+ * @return bandwidth of a chanspec in half MHz units
+ */
+uint16
+wf_bw_chspec_to_half_mhz(chanspec_t chspec)
+{
+ uint16 bw;
+
+ bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT;
+ return (bw >= WF_NUM_BW_HALF_MHZ ? 0 : wf_chspec_bw_half_mhz[bw]);
+}
+
+/* convert bandwidth from chanspec to MHz; works with 5MHz to 160MHz (including 80p80) */
+static uint
+bw_chspec_to_mhz(chanspec_t chspec)
+{
+ uint bw;
+
+ bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT;
+ return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]);
+}
+
+/* bw in MHz, return the channel count from the center channel to the
+ * the channel at the edge of the band
+ */
+static uint8
+center_chan_to_edge(uint bw)
+{
+ /* edge channels separated by BW - 10MHz on each side
+ * delta from cf to edge is half of that,
+ * MHz to channel num conversion is 5MHz/channel
+ */
+ return (uint8)(((bw - 20) / 2) / 5);
+}
+
+/* return channel number of the low edge of the band
+ * given the center channel and BW
+ */
+static uint8
+channel_low_edge(uint center_ch, uint bw)
+{
+ return (uint8)(center_ch - center_chan_to_edge(bw));
+}
+
+/* return side band number given center channel and control channel
+ * return -1 on error
+ */
+static int
+channel_to_sb(uint center_ch, uint ctl_ch, uint bw)
+{
+ uint lowest = channel_low_edge(center_ch, bw);
+ uint sb;
+
+ if ((ctl_ch - lowest) % 4) {
+ /* bad ctl channel, not mult 4 */
+ return -1;
+ }
+
+ sb = ((ctl_ch - lowest) / 4);
+
+ /* sb must be a index to a 20MHz channel in range */
+ if (sb >= (bw / 20)) {
+ /* ctl_ch must have been too high for the center_ch */
+ return -1;
+ }
+
+ return sb;
+}
+
+/* return control channel given center channel and side band */
+static uint8
+channel_to_ctl_chan(uint center_ch, uint bw, uint sb)
+{
+ return (uint8)(channel_low_edge(center_ch, bw) + sb * 4);
+}
+
+/* return index of 80MHz channel from channel number
+ * return -1 on error
+ */
+static int
+channel_80mhz_to_id(uint ch)
+{
+ uint i;
+ for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) {
+ if (ch == wf_5g_80m_chans[i])
+ return i;
+ }
+
+ return -1;
+}
+
+/* wrapper function for wf_chspec_ntoa. In case of an error it puts
+ * the original chanspec in the output buffer, prepended with "invalid".
+ * Can be directly used in print routines as it takes care of null
+ */
+char *
+wf_chspec_ntoa_ex(chanspec_t chspec, char *buf)
+{
+ if (wf_chspec_ntoa(chspec, buf) == NULL)
+ snprintf(buf, CHANSPEC_STR_LEN, "invalid 0x%04x", chspec);
+ return buf;
+}
+
+/* given a chanspec and a string buffer, format the chanspec as a
+ * string, and return the original pointer a.
+ * Min buffer length must be CHANSPEC_STR_LEN.
+ * On error return NULL
+ */
+char *
+wf_chspec_ntoa(chanspec_t chspec, char *buf)
+{
+ const char *band;
+ uint ctl_chan;
+
+ if (wf_chspec_malformed(chspec))
+ return NULL;
+
+ band = "";
+
+ /* check for non-default band spec */
+ if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) ||
+ (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL))
+ band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g";
+
+ /* ctl channel */
+ ctl_chan = wf_chspec_ctlchan(chspec);
+
+ /* bandwidth and ctl sideband */
+ if (CHSPEC_IS20(chspec)) {
+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan);
+ } else if (!CHSPEC_IS8080(chspec)) {
+ const char *bw;
+ const char *sb = "";
+
+ bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT];
+
+#ifdef CHANSPEC_NEW_40MHZ_FORMAT
+ /* ctl sideband string if needed for 2g 40MHz */
+ if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) {
+ sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l";
+ }
+
+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb);
+#else
+ /* ctl sideband string instead of BW for 40MHz */
+ if (CHSPEC_IS40(chspec)) {
+ sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l";
+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb);
+ } else {
+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw);
+ }
+#endif /* CHANSPEC_NEW_40MHZ_FORMAT */
+
+ } else {
+ /* 80+80 */
+ uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT;
+ uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT;
+
+ /* convert to channel number */
+ chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0;
+ chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0;
+
+ /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */
+ snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2);
+ }
+
+ return (buf);
+}
+
+static int
+read_uint(const char **p, unsigned int *num)
+{
+ unsigned long val;
+ char *endp = NULL;
+
+ val = strtoul(*p, &endp, 10);
+ /* if endp is the initial pointer value, then a number was not read */
+ if (endp == *p)
+ return 0;
+
+ /* advance the buffer pointer to the end of the integer string */
+ *p = endp;
+ /* return the parsed integer */
+ *num = (unsigned int)val;
+
+ return 1;
+}
+
+/* given a chanspec string, convert to a chanspec.
+ * On error return 0
+ */
+chanspec_t
+wf_chspec_aton(const char *a)
+{
+ chanspec_t chspec;
+ uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb;
+ uint num, ctl_ch;
+ uint ch1, ch2;
+ char c, sb_ul = '\0';
+ int i;
+
+ bw = 20;
+ chspec_sb = 0;
+ chspec_ch = ch1 = ch2 = 0;
+
+ /* parse channel num or band */
+ if (!read_uint(&a, &num))
+ return 0;
+ /* if we are looking at a 'g', then the first number was a band */
+ c = tolower((int)a[0]);
+ if (c == 'g') {
+ a++; /* consume the char */
+
+ /* band must be "2" or "5" */
+ if (num == 2)
+ chspec_band = WL_CHANSPEC_BAND_2G;
+ else if (num == 5)
+ chspec_band = WL_CHANSPEC_BAND_5G;
+ else
+ return 0;
+
+ /* read the channel number */
+ if (!read_uint(&a, &ctl_ch))
+ return 0;
+
+ c = tolower((int)a[0]);
+ }
+ else {
+ /* first number is channel, use default for band */
+ ctl_ch = num;
+ chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ?
+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
+ }
+
+ if (c == '\0') {
+ /* default BW of 20MHz */
+ chspec_bw = WL_CHANSPEC_BW_20;
+ goto done_read;
+ }
+
+ a ++; /* consume the 'u','l', or '/' */
+
+ /* check 'u'/'l' */
+ if (c == 'u' || c == 'l') {
+ sb_ul = c;
+ chspec_bw = WL_CHANSPEC_BW_40;
+ goto done_read;
+ }
+
+ /* next letter must be '/' */
+ if (c != '/')
+ return 0;
+
+ /* read bandwidth */
+ if (!read_uint(&a, &bw))
+ return 0;
+
+ /* convert to chspec value */
+ if (bw == 2) {
+ chspec_bw = WL_CHANSPEC_BW_2P5;
+ } else if (bw == 5) {
+ chspec_bw = WL_CHANSPEC_BW_5;
+ } else if (bw == 10) {
+ chspec_bw = WL_CHANSPEC_BW_10;
+ } else if (bw == 20) {
+ chspec_bw = WL_CHANSPEC_BW_20;
+ } else if (bw == 40) {
+ chspec_bw = WL_CHANSPEC_BW_40;
+ } else if (bw == 80) {
+ chspec_bw = WL_CHANSPEC_BW_80;
+ } else if (bw == 160) {
+ chspec_bw = WL_CHANSPEC_BW_160;
+ } else {
+ return 0;
+ }
+
+ /* So far we have <band>g<chan>/<bw>
+ * Can now be followed by u/l if bw = 40,
+ * or '+80' if bw = 80, to make '80+80' bw,
+ * or '.5' if bw = 2.5 to make '2.5' bw .
+ */
+
+ c = tolower((int)a[0]);
+
+ /* if we have a 2g/40 channel, we should have a l/u spec now */
+ if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) {
+ if (c == 'u' || c == 'l') {
+ a ++; /* consume the u/l char */
+ sb_ul = c;
+ goto done_read;
+ }
+ }
+
+ /* check for 80+80 */
+ if (c == '+') {
+ /* 80+80 */
+ const char plus80[] = "80/";
+
+ /* must be looking at '+80/'
+ * check and consume this string.
+ */
+ chspec_bw = WL_CHANSPEC_BW_8080;
+
+ a ++; /* consume the char '+' */
+
+ /* consume the '80/' string */
+ for (i = 0; i < 3; i++) {
+ if (*a++ != plus80[i]) {
+ return 0;
+ }
+ }
+
+ /* read primary 80MHz channel */
+ if (!read_uint(&a, &ch1))
+ return 0;
+
+ /* must followed by '-' */
+ if (a[0] != '-')
+ return 0;
+ a ++; /* consume the char */
+
+ /* read secondary 80MHz channel */
+ if (!read_uint(&a, &ch2))
+ return 0;
+ } else if (c == '.') {
+ /* 2.5 */
+ /* must be looking at '.5'
+ * check and consume this string.
+ */
+ chspec_bw = WL_CHANSPEC_BW_2P5;
+
+ a ++; /* consume the char '.' */
+
+ /* consume the '5' string */
+ if (*a++ != '5') {
+ return 0;
+ }
+ }
+
+done_read:
+ /* skip trailing white space */
+ while (a[0] == ' ') {
+ a ++;
+ }
+
+ /* must be end of string */
+ if (a[0] != '\0')
+ return 0;
+
+ /* Now have all the chanspec string parts read;
+ * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2.
+ * chspec_band and chspec_bw are chanspec values.
+ * Need to convert ctl_ch, sb_ul, and ch1,ch2 into
+ * a center channel (or two) and sideband.
+ */
+
+ /* if a sb u/l string was given, just use that,
+ * guaranteed to be bw = 40 by sting parse.
+ */
+ if (sb_ul != '\0') {
+ if (sb_ul == 'l') {
+ chspec_ch = UPPER_20_SB(ctl_ch);
+ chspec_sb = WL_CHANSPEC_CTL_SB_LLL;
+ } else if (sb_ul == 'u') {
+ chspec_ch = LOWER_20_SB(ctl_ch);
+ chspec_sb = WL_CHANSPEC_CTL_SB_LLU;
+ }
+ }
+ /* if the bw is 20, center and sideband are trivial */
+ else if (BW_LE20(chspec_bw)) {
+ chspec_ch = ctl_ch;
+ chspec_sb = WL_CHANSPEC_CTL_SB_NONE;
+ }
+ /* if the bw is 40/80/160, not 80+80, a single method
+ * can be used to to find the center and sideband
+ */
+ else if (chspec_bw != WL_CHANSPEC_BW_8080) {
+ /* figure out ctl sideband based on ctl channel and bandwidth */
+ const uint8 *center_ch = NULL;
+ int num_ch = 0;
+ int sb = -1;
+
+ if (chspec_bw == WL_CHANSPEC_BW_40) {
+ center_ch = wf_5g_40m_chans;
+ num_ch = WF_NUM_5G_40M_CHANS;
+ } else if (chspec_bw == WL_CHANSPEC_BW_80) {
+ center_ch = wf_5g_80m_chans;
+ num_ch = WF_NUM_5G_80M_CHANS;
+ } else if (chspec_bw == WL_CHANSPEC_BW_160) {
+ center_ch = wf_5g_160m_chans;
+ num_ch = WF_NUM_5G_160M_CHANS;
+ } else {
+ return 0;
+ }
+
+ for (i = 0; i < num_ch; i ++) {
+ sb = channel_to_sb(center_ch[i], ctl_ch, bw);
+ if (sb >= 0) {
+ chspec_ch = center_ch[i];
+ chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT;
+ break;
+ }
+ }
+
+ /* check for no matching sb/center */
+ if (sb < 0) {
+ return 0;
+ }
+ }
+ /* Otherwise, bw is 80+80. Figure out channel pair and sb */
+ else {
+ int ch1_id = 0, ch2_id = 0;
+ int sb;
+
+ /* look up the channel ID for the specified channel numbers */
+ ch1_id = channel_80mhz_to_id(ch1);
+ ch2_id = channel_80mhz_to_id(ch2);
+
+ /* validate channels */
+ if (ch1_id < 0 || ch2_id < 0)
+ return 0;
+
+ /* combine 2 channel IDs in channel field of chspec */
+ chspec_ch = (((uint)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) |
+ ((uint)ch2_id << WL_CHANSPEC_CHAN2_SHIFT));
+
+ /* figure out primary 20 MHz sideband */
+
+ /* is the primary channel contained in the 1st 80MHz channel? */
+ sb = channel_to_sb(ch1, ctl_ch, bw);
+ if (sb < 0) {
+ /* no match for primary channel 'ctl_ch' in segment0 80MHz channel */
+ return 0;
+ }
+
+ chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT;
+ }
+
+ chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb);
+
+ if (wf_chspec_malformed(chspec))
+ return 0;
+
+ return chspec;
+}
+
+/*
+ * Verify the chanspec is using a legal set of parameters, i.e. that the
+ * chanspec specified a band, bw, ctl_sb and channel and that the
+ * combination could be legal given any set of circumstances.
+ * RETURNS: TRUE is the chanspec is malformed, false if it looks good.
+ */
+bool
+wf_chspec_malformed(chanspec_t chanspec)
+{
+ uint chspec_bw = CHSPEC_BW(chanspec);
+ uint chspec_ch = CHSPEC_CHANNEL(chanspec);
+
+ /* must be 2G or 5G band */
+ if (CHSPEC_IS2G(chanspec)) {
+ /* must be valid bandwidth */
+ if (!BW_LE40(chspec_bw)) {
+ return TRUE;
+ }
+ } else if (CHSPEC_IS5G(chanspec)) {
+ if (chspec_bw == WL_CHANSPEC_BW_8080) {
+ uint ch1_id, ch2_id;
+
+ /* channel IDs in 80+80 must be in range */
+ ch1_id = CHSPEC_CHAN1(chanspec);
+ ch2_id = CHSPEC_CHAN2(chanspec);
+ if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS)
+ return TRUE;
+
+ } else if (BW_LE20(chspec_bw) || chspec_bw == WL_CHANSPEC_BW_40 ||
+ chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) {
+
+ if (chspec_ch > MAXCHANNEL) {
+ return TRUE;
+ }
+ } else {
+ /* invalid bandwidth */
+ return TRUE;
+ }
+ } else {
+ /* must be 2G or 5G band */
+ return TRUE;
+ }
+
+ /* side band needs to be consistent with bandwidth */
+ if (BW_LE20(chspec_bw)) {
+ if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL)
+ return TRUE;
+ } else if (chspec_bw == WL_CHANSPEC_BW_40) {
+ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU)
+ return TRUE;
+ } else if (chspec_bw == WL_CHANSPEC_BW_80) {
+ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU)
+ return TRUE;
+ }
+ else if (chspec_bw == WL_CHANSPEC_BW_160 ||
+ chspec_bw == WL_CHANSPEC_BW_8080) {
+ ASSERT(CHSPEC_CTL_SB(chanspec) <= WL_CHANSPEC_CTL_SB_UUU);
+ }
+ return FALSE;
+}
+
+/*
+ * Verify the chanspec specifies a valid channel according to 802.11.
+ * RETURNS: TRUE if the chanspec is a valid 802.11 channel
+ */
+bool
+wf_chspec_valid(chanspec_t chanspec)
+{
+ uint chspec_bw = CHSPEC_BW(chanspec);
+ uint chspec_ch = CHSPEC_CHANNEL(chanspec);
+
+ if (wf_chspec_malformed(chanspec))
+ return FALSE;
+
+ if (CHSPEC_IS2G(chanspec)) {
+ /* must be valid bandwidth and channel range */
+ if (BW_LE20(chspec_bw)) {
+ if (chspec_ch >= 1 && chspec_ch <= 14)
+ return TRUE;
+ } else if (chspec_bw == WL_CHANSPEC_BW_40) {
+ if (chspec_ch >= 3 && chspec_ch <= 11)
+ return TRUE;
+ }
+ } else if (CHSPEC_IS5G(chanspec)) {
+ if (chspec_bw == WL_CHANSPEC_BW_8080) {
+ uint16 ch1, ch2;
+
+ ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)];
+ ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)];
+
+ /* the two channels must be separated by more than 80MHz by VHT req */
+ if ((ch2 > ch1 + CH_80MHZ_APART) ||
+ (ch1 > ch2 + CH_80MHZ_APART))
+ return TRUE;
+ } else {
+ const uint8 *center_ch;
+ uint num_ch, i;
+
+ if (BW_LE40(chspec_bw)) {
+ center_ch = wf_5g_40m_chans;
+ num_ch = WF_NUM_5G_40M_CHANS;
+ } else if (chspec_bw == WL_CHANSPEC_BW_80) {
+ center_ch = wf_5g_80m_chans;
+ num_ch = WF_NUM_5G_80M_CHANS;
+ } else if (chspec_bw == WL_CHANSPEC_BW_160) {
+ center_ch = wf_5g_160m_chans;
+ num_ch = WF_NUM_5G_160M_CHANS;
+ } else {
+ /* invalid bandwidth */
+ return FALSE;
+ }
+
+ /* check for a valid center channel */
+ if (BW_LE20(chspec_bw)) {
+ /* We don't have an array of legal 20MHz 5G channels, but they are
+ * each side of the legal 40MHz channels. Check the chanspec
+ * channel against either side of the 40MHz channels.
+ */
+ for (i = 0; i < num_ch; i ++) {
+ if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) ||
+ chspec_ch == (uint)UPPER_20_SB(center_ch[i]))
+ break; /* match found */
+ }
+
+ if (i == num_ch) {
+ /* check for channel 165 which is not the side band
+ * of 40MHz 5G channel
+ */
+ if (chspec_ch == 165)
+ i = 0;
+
+ /* check for legacy JP channels on failure */
+ if (chspec_ch == 34 || chspec_ch == 38 ||
+ chspec_ch == 42 || chspec_ch == 46)
+ i = 0;
+ }
+ } else {
+ /* check the chanspec channel to each legal channel */
+ for (i = 0; i < num_ch; i ++) {
+ if (chspec_ch == center_ch[i])
+ break; /* match found */
+ }
+ }
+
+ if (i < num_ch) {
+ /* match found */
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * This function returns TRUE if both the chanspec can co-exist in PHY.
+ * Addition to control channel, the function checks for side band for 2g 40 channels
+ */
+bool
+wf_chspec_coexist(chanspec_t chspec1, chanspec_t chspec2)
+{
+ bool same_ctl = (wf_chspec_ctlchan(chspec1) == wf_chspec_ctlchan(chspec2));
+
+ if (same_ctl && CHSPEC_IS2G(chspec1)) {
+ if (CHSPEC_IS40(chspec1) && CHSPEC_IS40(chspec2)) {
+ return (CHSPEC_CTL_SB(chspec1) == CHSPEC_CTL_SB(chspec2));
+ }
+ }
+ return same_ctl;
+}
+
+/*
+ * This function returns the channel number that control traffic is being sent on, for 20MHz
+ * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ
+ * sideband depending on the chanspec selected
+ */
+uint8
+wf_chspec_ctlchan(chanspec_t chspec)
+{
+ uint center_chan;
+ uint bw_mhz;
+ uint sb;
+
+ ASSERT(!wf_chspec_malformed(chspec));
+
+ /* Is there a sideband ? */
+ if (CHSPEC_BW_LE20(chspec)) {
+ return CHSPEC_CHANNEL(chspec);
+ } else {
+ sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
+
+ if (CHSPEC_IS8080(chspec)) {
+ /* For an 80+80 MHz channel, the sideband 'sb' field is an 80 MHz sideband
+ * (LL, LU, UL, LU) for the 80 MHz frequency segment 0.
+ */
+ uint chan_id = CHSPEC_CHAN1(chspec);
+
+ bw_mhz = 80;
+
+ /* convert from channel index to channel number */
+ center_chan = wf_5g_80m_chans[chan_id];
+ }
+ else {
+ bw_mhz = bw_chspec_to_mhz(chspec);
+ center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT;
+ }
+
+ return (channel_to_ctl_chan(center_chan, bw_mhz, sb));
+ }
+}
+
+/* given a chanspec, return the bandwidth string */
+const char *
+wf_chspec_to_bw_str(chanspec_t chspec)
+{
+ return wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)];
+}
+
+/*
+ * This function returns the chanspec of the control channel of a given chanspec
+ */
+chanspec_t
+wf_chspec_ctlchspec(chanspec_t chspec)
+{
+ chanspec_t ctl_chspec = chspec;
+ uint8 ctl_chan;
+
+ ASSERT(!wf_chspec_malformed(chspec));
+
+ /* Is there a sideband ? */
+ if (!CHSPEC_BW_LE20(chspec)) {
+ ctl_chan = wf_chspec_ctlchan(chspec);
+ ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20;
+ ctl_chspec |= CHSPEC_BAND(chspec);
+ }
+ return ctl_chspec;
+}
+
+/* return chanspec given control channel and bandwidth
+ * return 0 on error
+ */
+uint16
+wf_channel2chspec(uint ctl_ch, uint bw)
+{
+ uint16 chspec;
+ const uint8 *center_ch = NULL;
+ int num_ch = 0;
+ int sb = -1;
+ int i = 0;
+
+ chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
+
+ chspec |= bw;
+
+ if (bw == WL_CHANSPEC_BW_40) {
+ center_ch = wf_5g_40m_chans;
+ num_ch = WF_NUM_5G_40M_CHANS;
+ bw = 40;
+ } else if (bw == WL_CHANSPEC_BW_80) {
+ center_ch = wf_5g_80m_chans;
+ num_ch = WF_NUM_5G_80M_CHANS;
+ bw = 80;
+ } else if (bw == WL_CHANSPEC_BW_160) {
+ center_ch = wf_5g_160m_chans;
+ num_ch = WF_NUM_5G_160M_CHANS;
+ bw = 160;
+ } else if (BW_LE20(bw)) {
+ chspec |= ctl_ch;
+ return chspec;
+ } else {
+ return 0;
+ }
+
+ for (i = 0; i < num_ch; i ++) {
+ sb = channel_to_sb(center_ch[i], ctl_ch, bw);
+ if (sb >= 0) {
+ chspec |= center_ch[i];
+ chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT);
+ break;
+ }
+ }
+
+ /* check for no matching sb/center */
+ if (sb < 0) {
+ return 0;
+ }
+
+ return chspec;
+}
+
+/*
+ * This function returns the chanspec for the primary 40MHz of an 80MHz channel.
+ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using
+ * as the primary 20MHz channel.
+ */
+extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec)
+{
+ chanspec_t chspec40 = chspec;
+ uint center_chan;
+ uint sb;
+
+ ASSERT(!wf_chspec_malformed(chspec));
+
+ /* if the chanspec is > 80MHz, use the helper routine to find the primary 80 MHz channel */
+ if (CHSPEC_IS8080(chspec) || CHSPEC_IS160(chspec)) {
+ chspec = wf_chspec_primary80_chspec(chspec);
+ }
+
+ /* determine primary 40 MHz sub-channel of an 80 MHz chanspec */
+ if (CHSPEC_IS80(chspec)) {
+ center_chan = CHSPEC_CHANNEL(chspec);
+ sb = CHSPEC_CTL_SB(chspec);
+
+ if (sb < WL_CHANSPEC_CTL_SB_UL) {
+ /* Primary 40MHz is on lower side */
+ center_chan -= CH_20MHZ_APART;
+ /* sideband bits are the same for LL/LU and L/U */
+ } else {
+ /* Primary 40MHz is on upper side */
+ center_chan += CH_20MHZ_APART;
+ /* sideband bits need to be adjusted by UL offset */
+ sb -= WL_CHANSPEC_CTL_SB_UL;
+ }
+
+ /* Create primary 40MHz chanspec */
+ chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 |
+ sb | center_chan);
+ }
+
+ return chspec40;
+}
+
+/*
+ * Return the channel number for a given frequency and base frequency.
+ * The returned channel number is relative to the given base frequency.
+ * If the given base frequency is zero, a base frequency of 5 GHz is assumed for
+ * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz.
+ *
+ * Frequency is specified in MHz.
+ * The base frequency is specified as (start_factor * 500 kHz).
+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
+ * 2.4 GHz and 5 GHz bands.
+ *
+ * The returned channel will be in the range [1, 14] in the 2.4 GHz band
+ * and [0, 200] otherwise.
+ * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the
+ * frequency is not a 2.4 GHz channel, or if the frequency is not and even
+ * multiple of 5 MHz from the base frequency to the base plus 1 GHz.
+ *
+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
+ */
+int
+wf_mhz2channel(uint freq, uint start_factor)
+{
+ int ch = -1;
+ uint base;
+ int offset;
+
+ /* take the default channel start frequency */
+ if (start_factor == 0) {
+ if (freq >= 2400 && freq <= 2500)
+ start_factor = WF_CHAN_FACTOR_2_4_G;
+ else if (freq >= 5000 && freq <= 6000)
+ start_factor = WF_CHAN_FACTOR_5_G;
+ }
+
+ if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G)
+ return 14;
+
+ base = start_factor / 2;
+
+ /* check that the frequency is in 1GHz range of the base */
+ if ((freq < base) || (freq > base + 1000))
+ return -1;
+
+ offset = freq - base;
+ ch = offset / 5;
+
+ /* check that frequency is a 5MHz multiple from the base */
+ if (offset != (ch * 5))
+ return -1;
+
+ /* restricted channel range check for 2.4G */
+ if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13))
+ return -1;
+
+ return ch;
+}
+
+/*
+ * Return the center frequency in MHz of the given channel and base frequency.
+ * The channel number is interpreted relative to the given base frequency.
+ *
+ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise.
+ * The base frequency is specified as (start_factor * 500 kHz).
+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G
+ * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands.
+ * The channel range of [1, 14] is only checked for a start_factor of
+ * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2).
+ * Odd start_factors produce channels on .5 MHz boundaries, in which case
+ * the answer is rounded down to an integral MHz.
+ * -1 is returned for an out of range channel.
+ *
+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
+ */
+int
+wf_channel2mhz(uint ch, uint start_factor)
+{
+ int freq;
+
+ if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) ||
+ (ch > 200))
+ freq = -1;
+ else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14))
+ freq = 2484;
+ else
+ freq = ch * 5 + start_factor / 2;
+
+ return freq;
+}
+
+static const uint16 sidebands[] = {
+ WL_CHANSPEC_CTL_SB_LLL, WL_CHANSPEC_CTL_SB_LLU,
+ WL_CHANSPEC_CTL_SB_LUL, WL_CHANSPEC_CTL_SB_LUU,
+ WL_CHANSPEC_CTL_SB_ULL, WL_CHANSPEC_CTL_SB_ULU,
+ WL_CHANSPEC_CTL_SB_UUL, WL_CHANSPEC_CTL_SB_UUU
+};
+
+/*
+ * Returns the chanspec 80Mhz channel corresponding to the following input
+ * parameters
+ *
+ * primary_channel - primary 20Mhz channel
+ * center_channel - center frequecny of the 80Mhz channel
+ *
+ * The center_channel can be one of {42, 58, 106, 122, 138, 155}
+ *
+ * returns INVCHANSPEC in case of error
+ */
+chanspec_t
+wf_chspec_80(uint8 center_channel, uint8 primary_channel)
+{
+
+ chanspec_t chanspec = INVCHANSPEC;
+ chanspec_t chanspec_cur;
+ uint i;
+
+ for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) {
+ chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]);
+ if (primary_channel == wf_chspec_ctlchan(chanspec_cur)) {
+ chanspec = chanspec_cur;
+ break;
+ }
+ }
+ /* If the loop ended early, we are good, otherwise we did not
+ * find a 80MHz chanspec with the given center_channel that had a primary channel
+ *matching the given primary_channel.
+ */
+ return chanspec;
+}
+
+/*
+ * Returns the 80+80 chanspec corresponding to the following input parameters
+ *
+ * primary_20mhz - Primary 20 MHz channel
+ * chan0 - center channel number of one frequency segment
+ * chan1 - center channel number of the other frequency segment
+ *
+ * Parameters chan0 and chan1 are channel numbers in {42, 58, 106, 122, 138, 155}.
+ * The primary channel must be contained in one of the 80MHz channels. This routine
+ * will determine which frequency segment is the primary 80 MHz segment.
+ *
+ * Returns INVCHANSPEC in case of error.
+ *
+ * Refer to IEEE802.11ac section 22.3.14 "Channelization".
+ */
+chanspec_t
+wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan0, uint8 chan1)
+{
+ int sb = 0;
+ uint16 chanspec = 0;
+ int chan0_id = 0, chan1_id = 0;
+ int seg0, seg1;
+
+ chan0_id = channel_80mhz_to_id(chan0);
+ chan1_id = channel_80mhz_to_id(chan1);
+
+ /* make sure the channel numbers were valid */
+ if (chan0_id == -1 || chan1_id == -1)
+ return INVCHANSPEC;
+
+ /* does the primary channel fit with the 1st 80MHz channel ? */
+ sb = channel_to_sb(chan0, primary_20mhz, 80);
+ if (sb >= 0) {
+ /* yes, so chan0 is frequency segment 0, and chan1 is seg 1 */
+ seg0 = chan0_id;
+ seg1 = chan1_id;
+ } else {
+ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
+ sb = channel_to_sb(chan1, primary_20mhz, 80);
+ if (sb < 0) {
+ /* no match for ctl_ch to either 80MHz center channel */
+ return INVCHANSPEC;
+ }
+ /* swapped, so chan1 is frequency segment 0, and chan0 is seg 1 */
+ seg0 = chan1_id;
+ seg1 = chan0_id;
+ }
+
+ chanspec = ((seg0 << WL_CHANSPEC_CHAN1_SHIFT) |
+ (seg1 << WL_CHANSPEC_CHAN2_SHIFT) |
+ (sb << WL_CHANSPEC_CTL_SB_SHIFT) |
+ WL_CHANSPEC_BW_8080 |
+ WL_CHANSPEC_BAND_5G);
+
+ return chanspec;
+}
+
+/*
+ * This function returns the 80Mhz channel for the given id.
+ */
+static uint8
+wf_chspec_get80Mhz_ch(uint8 chan_80Mhz_id)
+{
+ if (chan_80Mhz_id < WF_NUM_5G_80M_CHANS)
+ return wf_5g_80m_chans[chan_80Mhz_id];
+
+ return 0;
+}
+
+/*
+ * Returns the primary 80 Mhz channel for the provided chanspec
+ *
+ * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved
+ *
+ * returns -1 in case the provided channel is 20/40 Mhz chanspec
+ */
+
+uint8
+wf_chspec_primary80_channel(chanspec_t chanspec)
+{
+ uint8 primary80_chan;
+
+ if (CHSPEC_IS80(chanspec)) {
+ primary80_chan = CHSPEC_CHANNEL(chanspec);
+ }
+ else if (CHSPEC_IS8080(chanspec)) {
+ /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */
+ primary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec));
+ }
+ else if (CHSPEC_IS160(chanspec)) {
+ uint8 center_chan = CHSPEC_CHANNEL(chanspec);
+ uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
+
+ /* based on the sb value primary 80 channel can be retrieved
+ * if sb is in range 0 to 3 the lower band is the 80Mhz primary band
+ */
+ if (sb < 4) {
+ primary80_chan = center_chan - CH_40MHZ_APART;
+ }
+ /* if sb is in range 4 to 7 the upper band is the 80Mhz primary band */
+ else
+ {
+ primary80_chan = center_chan + CH_40MHZ_APART;
+ }
+ }
+ else {
+ /* for 20 and 40 Mhz */
+ primary80_chan = -1;
+ }
+ return primary80_chan;
+}
+
+/*
+ * Returns the secondary 80 Mhz channel for the provided chanspec
+ *
+ * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved
+ *
+ * returns -1 in case the provided channel is 20/40/80 Mhz chanspec
+ */
+uint8
+wf_chspec_secondary80_channel(chanspec_t chanspec)
+{
+ uint8 secondary80_chan;
+
+ if (CHSPEC_IS8080(chanspec)) {
+ secondary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec));
+ }
+ else if (CHSPEC_IS160(chanspec)) {
+ uint8 center_chan = CHSPEC_CHANNEL(chanspec);
+ uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
+
+ /* based on the sb value secondary 80 channel can be retrieved
+ * if sb is in range 0 to 3 upper band is the secondary 80Mhz band
+ */
+ if (sb < 4) {
+ secondary80_chan = center_chan + CH_40MHZ_APART;
+ }
+ /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */
+ else
+ {
+ secondary80_chan = center_chan - CH_40MHZ_APART;
+ }
+ }
+ else {
+ /* for 20, 40, and 80 Mhz */
+ secondary80_chan = -1;
+ }
+ return secondary80_chan;
+}
+
+/*
+ * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel.
+ *
+ * chanspec - Input chanspec for which the primary 80Mhz chanspec has to be retreived
+ *
+ * returns the input chanspec in case the provided chanspec is an 80 MHz chanspec
+ * returns INVCHANSPEC in case the provided channel is 20/40 MHz chanspec
+ */
+chanspec_t
+wf_chspec_primary80_chspec(chanspec_t chspec)
+{
+ chanspec_t chspec80;
+ uint center_chan;
+ uint sb;
+
+ ASSERT(!wf_chspec_malformed(chspec));
+ if (CHSPEC_IS80(chspec)) {
+ chspec80 = chspec;
+ }
+ else if (CHSPEC_IS8080(chspec)) {
+ sb = CHSPEC_CTL_SB(chspec);
+ if (sb < WL_CHANSPEC_CTL_SB_ULL) {
+ center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec));
+ } else {
+ center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec));
+ sb &= WL_CHANSPEC_CTL_SB_LUU; /* reduce to 80MHz side band */
+ }
+
+ /* Create primary 80MHz chanspec */
+ chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
+ }
+ else if (CHSPEC_IS160(chspec)) {
+ center_chan = CHSPEC_CHANNEL(chspec);
+ sb = CHSPEC_CTL_SB(chspec);
+
+ if (sb < WL_CHANSPEC_CTL_SB_ULL) {
+ /* Primary 80MHz is on lower side */
+ center_chan -= CH_40MHZ_APART;
+ }
+ else {
+ /* Primary 80MHz is on upper side */
+ center_chan += CH_40MHZ_APART;
+ sb -= WL_CHANSPEC_CTL_SB_ULL;
+ }
+ /* Create primary 80MHz chanspec */
+ chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
+ }
+ else {
+ chspec80 = INVCHANSPEC;
+ }
+
+ return chspec80;
+}
+
+/*
+ * For 160MHz or 80P80 chanspec, set ch[0]/ch[1] to be the low/high 80 Mhz channels
+ *
+ * For 20/40/80MHz chanspec, set ch[0] to be the center freq, and chan[1]=-1
+ */
+void
+wf_chspec_get_80p80_channels(chanspec_t chspec, uint8 *ch)
+{
+
+ if (CHSPEC_IS8080(chspec)) {
+ ch[0] = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec));
+ ch[1] = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec));
+ }
+ else if (CHSPEC_IS160(chspec)) {
+ uint8 center_chan = CHSPEC_CHANNEL(chspec);
+ ch[0] = center_chan - CH_40MHZ_APART;
+ ch[1] = center_chan + CH_40MHZ_APART;
+ }
+ else {
+ /* for 20, 40, and 80 Mhz */
+ ch[0] = CHSPEC_CHANNEL(chspec);
+ ch[1] = -1;
+ }
+ return;
+
+}
+
+#ifdef WL11AC_80P80
+uint8
+wf_chspec_channel(chanspec_t chspec)
+{
+ if (CHSPEC_IS8080(chspec)) {
+ return wf_chspec_primary80_channel(chspec);
+ }
+ else {
+ return ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK));
+ }
+}
+#endif /* WL11AC_80P80 */
+
+/* This routine returns the chanspec for a given operating class and
+ * channel number
+ */
+chanspec_t
+wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel)
+{
+ chanspec_t chanspec = 0;
+ uint16 opclass_info = 0;
+ uint16 lookupindex = 0;
+ switch (opclass) {
+ case 115:
+ lookupindex = 1;
+ break;
+ case 124:
+ lookupindex = 3;
+ break;
+ case 125:
+ lookupindex = 5;
+ break;
+ case 81:
+ lookupindex = 12;
+ break;
+ case 116:
+ lookupindex = 22;
+ break;
+ case 119:
+ lookupindex = 23;
+ break;
+ case 126:
+ lookupindex = 25;
+ break;
+ case 83:
+ lookupindex = 32;
+ break;
+ case 84:
+ lookupindex = 33;
+ break;
+ default:
+ lookupindex = 12;
+ }
+
+ if (lookupindex < 33) {
+ opclass_info = opclass_data[lookupindex-1];
+ }
+ else {
+ opclass_info = opclass_data[11];
+ }
+ chanspec = opclass_info | (uint16)channel;
+ return chanspec;
+}
+
+/* This routine returns the opclass for a given chanspec */
+int
+wf_channel_create_opclass_frm_chspec(chanspec_t chspec)
+{
+ BCM_REFERENCE(chspec);
+ /* TODO: Implement this function ! */
+ return 12; /* opclass 12 for basic 2G channels */
+}
+
+/* Populates array with all 20MHz side bands of a given chanspec_t in the following order:
+ * control, ext20, two ext40s, four ext80s.
+ * 'chspec' is the chanspec of interest
+ * 'pext' must point to an uint8 array of long enough to hold all side bands of the given chspec
+ *
+ * Works with 20, 40, 80, 80p80 and 160MHz chspec
+ */
+void
+wf_get_all_ext(chanspec_t chspec, uint8 *pext)
+{
+#ifdef WL11N_20MHZONLY
+ GET_ALL_SB(chspec, pext);
+#else /* !WL11N_20MHZONLY */
+ chanspec_t t = (CHSPEC_IS160(chspec) || CHSPEC_IS8080(chspec)) ? /* if bw > 80MHz */
+ wf_chspec_primary80_chspec(chspec) : (chspec); /* extract primary 80 */
+ /* control channel as first element */
+ uint8 ctl_ch = (pext)[0] = wf_chspec_ctlchan(t);
+ if (CHSPEC_ISLE20(chspec)) return; /* nothing more to do since 20MHz chspec */
+ /* 20MHz EXT */
+ (pext)[1] = ctl_ch + (IS_CTL_IN_L20(t) ? CH_20MHZ_APART : -CH_20MHZ_APART);
+ if (CHSPEC_IS40(chspec)) return; /* nothing more to do since 40MHz chspec */
+ /* center 40MHz EXT */
+ t = wf_channel2chspec(ctl_ch + (IS_CTL_IN_L40(chspec) ?
+ CH_40MHZ_APART : -CH_40MHZ_APART), WL_CHANSPEC_BW_40);
+ GET_ALL_SB(t, &((pext)[2])); /* get the 20MHz side bands in 40MHz EXT */
+ if (CHSPEC_IS80(chspec)) return; /* nothing more to do since 80MHz chspec */
+ t = CH80MHZ_CHSPEC(wf_chspec_secondary80_channel(chspec), WL_CHANSPEC_CTL_SB_LLL);
+ /* get the 20MHz side bands in 80MHz EXT (secondary) */
+ GET_ALL_SB(t, &((pext)[4]));
+#endif /* !WL11N_20MHZONLY */
+}
diff --git a/wl/src/shared/bcmxtlv.c b/wl/src/shared/bcmxtlv.c
new file mode 100644
index 0000000..9f6e91a
--- /dev/null
+++ b/wl/src/shared/bcmxtlv.c
@@ -0,0 +1,610 @@
+/*
+ * Driver O/S-independent utility routines
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmxtlv.c 635987 2016-05-06 01:49:37Z $
+ */
+
+#ifndef __FreeBSD__
+#include <bcm_cfg.h>
+#endif
+
+#include <typedefs.h>
+#include <bcmdefs.h>
+
+#if defined(__FreeBSD__)
+#include <machine/stdarg.h>
+#else
+#include <stdarg.h>
+#endif /* __FreeBSD__ */
+
+#ifdef BCMDRIVER
+#include <osl.h>
+#else /* !BCMDRIVER */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifndef ASSERT
+#define ASSERT(exp)
+#endif
+#endif /* !BCMDRIVER */
+
+#include <bcmtlv.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+
+int
+bcm_xtlv_hdr_size(bcm_xtlv_opts_t opts)
+{
+ int len = (int)OFFSETOF(bcm_xtlv_t, data); /* nominal */
+ if (opts & BCM_XTLV_OPTION_LENU8) --len;
+ if (opts & BCM_XTLV_OPTION_IDU8) --len;
+
+ return len;
+}
+
+bool
+bcm_valid_xtlv(const bcm_xtlv_t *elt, int buf_len, bcm_xtlv_opts_t opts)
+{
+ return elt != NULL &&
+ buf_len >= bcm_xtlv_hdr_size(opts) &&
+ buf_len >= bcm_xtlv_size(elt, opts);
+}
+
+int
+bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts)
+{
+ int hsz;
+
+ hsz = bcm_xtlv_hdr_size(opts);
+ return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + hsz, 4)
+ : (dlen + hsz));
+}
+
+int
+bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
+{
+ int size; /* size including header, data, and any pad */
+ int len; /* length wthout padding */
+
+ len = BCM_XTLV_LEN_EX(elt, opts);
+ size = bcm_xtlv_size_for_data(len, opts);
+ return size;
+}
+
+int
+bcm_xtlv_len(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
+{
+ const uint8 *lenp;
+ int len;
+
+ lenp = (const uint8 *)&elt->len; /* nominal */
+ if (opts & BCM_XTLV_OPTION_IDU8) --lenp;
+
+ if (opts & BCM_XTLV_OPTION_LENU8)
+ len = *lenp;
+ else
+ len = ltoh16_ua(lenp);
+
+ return len;
+}
+
+int
+bcm_xtlv_id(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
+{
+ int id = 0;
+ if (opts & BCM_XTLV_OPTION_IDU8)
+ id = *(const uint8 *)elt;
+ else
+ id = ltoh16_ua((const uint8 *)elt);
+
+ return id;
+}
+
+bcm_xtlv_t *
+bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts)
+{
+ int sz;
+#ifdef BCMDBG
+ /* validate current elt */
+ if (!bcm_valid_xtlv(elt, *buflen, opts))
+ return NULL;
+#endif
+ /* advance to next elt */
+ sz = BCM_XTLV_SIZE_EX(elt, opts);
+ elt = (bcm_xtlv_t*)((uint8 *)elt + sz);
+ *buflen -= sz;
+
+ /* validate next elt */
+ if (!bcm_valid_xtlv(elt, *buflen, opts))
+ return NULL;
+
+ return elt;
+}
+
+int
+bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, bcm_xtlv_opts_t opts)
+{
+ if (!tlv_buf || !buf || !len)
+ return BCME_BADARG;
+
+ tlv_buf->opts = opts;
+ tlv_buf->size = len;
+ tlv_buf->head = buf;
+ tlv_buf->buf = buf;
+ return BCME_OK;
+}
+
+uint16
+bcm_xtlv_buf_len(bcm_xtlvbuf_t *tbuf)
+{
+ uint16 len;
+
+ if (tbuf)
+ len = (uint16)(tbuf->buf - tbuf->head);
+ else
+ len = 0;
+
+ return len;
+}
+
+uint16
+bcm_xtlv_buf_rlen(bcm_xtlvbuf_t *tbuf)
+{
+ uint16 rlen;
+ if (tbuf)
+ rlen = tbuf->size - bcm_xtlv_buf_len(tbuf);
+ else
+ rlen = 0;
+
+ return rlen;
+}
+
+uint8 *
+bcm_xtlv_buf(bcm_xtlvbuf_t *tbuf)
+{
+ return tbuf ? tbuf->buf : NULL;
+}
+
+uint8 *
+bcm_xtlv_head(bcm_xtlvbuf_t *tbuf)
+{
+ return tbuf ? tbuf->head : NULL;
+}
+
+void
+bcm_xtlv_pack_xtlv(bcm_xtlv_t *xtlv, uint16 type, uint16 len, const uint8 *data,
+ bcm_xtlv_opts_t opts)
+{
+ uint8 *data_buf;
+ bcm_xtlv_opts_t mask = BCM_XTLV_OPTION_IDU8 | BCM_XTLV_OPTION_LENU8;
+
+ if (!(opts & mask)) { /* default */
+ uint8 *idp = (uint8 *)xtlv;
+ uint8 *lenp = idp + sizeof(xtlv->id);
+ htol16_ua_store(type, idp);
+ htol16_ua_store(len, lenp);
+ data_buf = lenp + sizeof(uint16);
+ } else if ((opts & mask) == mask) { /* u8 id and u8 len */
+ uint8 *idp = (uint8 *)xtlv;
+ uint8 *lenp = idp + 1;
+ *idp = (uint8)type;
+ *lenp = (uint8)len;
+ data_buf = lenp + sizeof(uint8);
+ } else if (opts & BCM_XTLV_OPTION_IDU8) { /* u8 id, u16 len */
+ uint8 *idp = (uint8 *)xtlv;
+ uint8 *lenp = idp + 1;
+ *idp = (uint8)type;
+ htol16_ua_store(len, lenp);
+ data_buf = lenp + sizeof(uint16);
+ } else if (opts & BCM_XTLV_OPTION_LENU8) { /* u16 id, u8 len */
+ uint8 *idp = (uint8 *)xtlv;
+ uint8 *lenp = idp + sizeof(uint16);
+ htol16_ua_store(type, idp);
+ *lenp = (uint8)len;
+ data_buf = lenp + sizeof(uint8);
+ } else {
+ ASSERT(!"Unexpected xtlv option");
+ return;
+ }
+
+ if (opts & BCM_XTLV_OPTION_LENU8) {
+ ASSERT(len <= 0x00ff);
+ len &= 0xff;
+ }
+
+ if (data != NULL)
+ memcpy(data_buf, data, len);
+}
+
+/* xtlv header is always packed in LE order */
+void
+bcm_xtlv_unpack_xtlv(const bcm_xtlv_t *xtlv, uint16 *type, uint16 *len,
+ const uint8 **data, bcm_xtlv_opts_t opts)
+{
+ if (type)
+ *type = (uint16)bcm_xtlv_id(xtlv, opts);
+ if (len)
+ *len = (uint16)bcm_xtlv_len(xtlv, opts);
+ if (data)
+ *data = (const uint8 *)xtlv + BCM_XTLV_HDR_SIZE_EX(opts);
+}
+
+int
+bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n)
+{
+ bcm_xtlv_t *xtlv;
+ int size;
+
+ if (tbuf == NULL)
+ return BCME_BADARG;
+
+ size = bcm_xtlv_size_for_data(n, tbuf->opts);
+ if (bcm_xtlv_buf_rlen(tbuf) < size)
+ return BCME_NOMEM;
+
+ xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf);
+ bcm_xtlv_pack_xtlv(xtlv, type, (uint16)n, data, tbuf->opts);
+ tbuf->buf += size; /* note: data may be NULL, reserves space */
+ return BCME_OK;
+}
+
+static int
+bcm_xtlv_put_int(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n, int int_sz)
+{
+ bcm_xtlv_t *xtlv;
+ int xtlv_len;
+ uint8 *xtlv_data;
+ int err = BCME_OK;
+
+ if (tbuf == NULL) {
+ err = BCME_BADARG;
+ goto done;
+ }
+
+ xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf);
+
+ /* put type and length in xtlv and reserve data space */
+ xtlv_len = n * int_sz;
+ err = bcm_xtlv_put_data(tbuf, type, NULL, xtlv_len);
+ if (err != BCME_OK)
+ goto done;
+
+ xtlv_data = (uint8 *)xtlv + bcm_xtlv_hdr_size(tbuf->opts);
+
+ /* write data w/ little-endianness into buffer - single loop, aligned access */
+ for (; n != 0; --n, xtlv_data += int_sz, data += int_sz) {
+ switch (int_sz) {
+ case sizeof(uint8):
+ break;
+ case sizeof(uint16):
+ {
+ uint16 v = load16_ua(data);
+ htol16_ua_store(v, xtlv_data);
+ break;
+ }
+ case sizeof(uint32):
+ {
+ uint32 v = load32_ua(data);
+ htol32_ua_store(v, xtlv_data);
+ break;
+ }
+ case sizeof(uint64):
+ {
+ uint64 v = load64_ua(data);
+ htol64_ua_store(v, xtlv_data);
+ break;
+ }
+ default:
+ err = BCME_UNSUPPORTED;
+ goto done;
+ }
+ }
+
+done:
+ return err;
+}
+
+int
+bcm_xtlv_put16(bcm_xtlvbuf_t *tbuf, uint16 type, const uint16 *data, int n)
+{
+ return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint16));
+}
+
+int
+bcm_xtlv_put32(bcm_xtlvbuf_t *tbuf, uint16 type, const uint32 *data, int n)
+{
+ return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint32));
+}
+
+int
+bcm_xtlv_put64(bcm_xtlvbuf_t *tbuf, uint16 type, const uint64 *data, int n)
+{
+ return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint64));
+}
+
+/*
+ * upacks xtlv record from buf checks the type
+ * copies data to callers buffer
+ * advances tlv pointer to next record
+ * caller's resposible for dst space check
+ */
+int
+bcm_unpack_xtlv_entry(uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len,
+ uint8 *dst_data, bcm_xtlv_opts_t opts)
+{
+ bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf;
+ uint16 len;
+ uint16 type;
+ const uint8 *data;
+
+ ASSERT(ptlv);
+
+ bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
+ if (len) {
+ if ((type != xpct_type) || (len > xpct_len))
+ return BCME_BADARG;
+ if (dst_data && data)
+ memcpy(dst_data, data, len); /* copy data to dst */
+ }
+
+ *tlv_buf += BCM_XTLV_SIZE_EX(ptlv, opts);
+ return BCME_OK;
+}
+
+/*
+ * packs user data into tlv record and advances tlv pointer to next xtlv slot
+ * buflen is used for tlv_buf space check
+ */
+int
+bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len,
+ const uint8 *src_data, bcm_xtlv_opts_t opts)
+{
+ bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf;
+ int size;
+
+ ASSERT(ptlv);
+
+ size = bcm_xtlv_size_for_data(len, opts);
+
+ /* copy data from tlv buffer to dst provided by user */
+ if (size > *buflen)
+ return BCME_BADLEN;
+
+ bcm_xtlv_pack_xtlv(ptlv, type, len, src_data, opts);
+
+ /* advance callers pointer to tlv buff */
+ *tlv_buf = (uint8*)(*tlv_buf) + size;
+ /* decrement the len */
+ *buflen -= (uint16)size;
+ return BCME_OK;
+}
+
+/*
+ * unpack all xtlv records from the issue a callback
+ * to set function one call per found tlv record
+ */
+int
+bcm_unpack_xtlv_buf(void *ctx, const uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
+ bcm_xtlv_unpack_cbfn_t *cbfn)
+{
+ uint16 len;
+ uint16 type;
+ int res = BCME_OK;
+ int size;
+ const bcm_xtlv_t *ptlv;
+ int sbuflen = buflen;
+ const uint8 *data;
+ int hdr_size;
+
+ ASSERT(!buflen || tlv_buf);
+ ASSERT(!buflen || cbfn);
+
+ hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
+ while (sbuflen >= hdr_size) {
+ ptlv = (const bcm_xtlv_t *)tlv_buf;
+
+ bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
+ size = bcm_xtlv_size_for_data(len, opts);
+
+ sbuflen -= size;
+ if (sbuflen < 0) /* check for buffer overrun */
+ break;
+
+ if ((res = cbfn(ctx, data, type, len)) != BCME_OK)
+ break;
+ tlv_buf += size;
+ }
+ return res;
+}
+
+int
+bcm_pack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
+ bcm_pack_xtlv_next_info_cbfn_t get_next, bcm_pack_xtlv_pack_next_cbfn_t pack_next,
+ int *outlen)
+{
+ int res = BCME_OK;
+ uint16 tlv_id;
+ uint16 tlv_len;
+ uint8 *startp;
+ uint8 *endp;
+ uint8 *buf;
+ bool more;
+ int size;
+ int hdr_size;
+
+ ASSERT(get_next && pack_next);
+
+ buf = tlv_buf;
+ startp = buf;
+ endp = (uint8 *)buf + buflen;
+ more = TRUE;
+ hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
+
+ while (more && (buf < endp)) {
+ more = get_next(ctx, &tlv_id, &tlv_len);
+ size = bcm_xtlv_size_for_data(tlv_len, opts);
+ if ((buf + size) > endp) {
+ res = BCME_BUFTOOSHORT;
+ goto done;
+ }
+
+ bcm_xtlv_pack_xtlv((bcm_xtlv_t *)buf, tlv_id, tlv_len, NULL, opts);
+ pack_next(ctx, tlv_id, tlv_len, buf + hdr_size);
+ buf += size;
+ }
+
+ if (more)
+ res = BCME_BUFTOOSHORT;
+
+done:
+ if (outlen) {
+ *outlen = (int)(buf - startp);
+ }
+ return res;
+}
+
+/*
+ * pack xtlv buffer from memory according to xtlv_desc_t
+ */
+int
+bcm_pack_xtlv_buf_from_mem(uint8 **tlv_buf, uint16 *buflen, const xtlv_desc_t *items,
+ bcm_xtlv_opts_t opts)
+{
+ int res = BCME_OK;
+ uint8 *ptlv = *tlv_buf;
+
+ while (items->type != 0) {
+ if (items->len && items->ptr) {
+ res = bcm_pack_xtlv_entry(&ptlv, buflen, items->type,
+ items->len, items->ptr, opts);
+ if (res != BCME_OK)
+ break;
+ }
+ items++;
+ }
+
+ *tlv_buf = ptlv; /* update the external pointer */
+ return res;
+}
+
+/*
+ * unpack xtlv buffer to memory according to xtlv_desc_t
+ *
+ */
+int
+bcm_unpack_xtlv_buf_to_mem(uint8 *tlv_buf, int *buflen, xtlv_desc_t *items,
+ bcm_xtlv_opts_t opts)
+{
+ int res = BCME_OK;
+ bcm_xtlv_t *elt;
+
+ elt = bcm_valid_xtlv((bcm_xtlv_t *)tlv_buf, *buflen, opts) ? (bcm_xtlv_t *)tlv_buf : NULL;
+ if (!elt || !items) {
+ res = BCME_BADARG;
+ return res;
+ }
+
+ for (; elt != NULL && res == BCME_OK; elt = bcm_next_xtlv(elt, buflen, opts)) {
+ /* find matches in desc_t items */
+ xtlv_desc_t *dst_desc = items;
+ uint16 len, type;
+ const uint8 *data;
+
+ bcm_xtlv_unpack_xtlv(elt, &type, &len, &data, opts);
+ while (dst_desc->type != 0) {
+ if (type == dst_desc->type) {
+ if (len != dst_desc->len) {
+ res = BCME_BADLEN;
+ } else {
+ memcpy(dst_desc->ptr, data, len);
+ }
+ break;
+ }
+ dst_desc++;
+ }
+ }
+
+ if (res == BCME_OK && *buflen != 0)
+ res = BCME_BUFTOOSHORT;
+
+ return res;
+}
+
+/*
+ * return data pointer of a given ID from xtlv buffer.
+ * If the specified xTLV ID is found, on return *datalen will contain
+ * the the data length of the xTLV ID.
+ */
+const uint8*
+bcm_get_data_from_xtlv_buf(const uint8 *tlv_buf, uint16 buflen, uint16 id,
+ uint16 *datalen, bcm_xtlv_opts_t opts)
+{
+ const uint8 *retptr = NULL;
+ uint16 type, len;
+ int size;
+ const bcm_xtlv_t *ptlv;
+ int sbuflen = buflen;
+ const uint8 *data;
+ int hdr_size;
+
+ hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
+ while (sbuflen >= hdr_size) {
+ ptlv = (const bcm_xtlv_t *)tlv_buf;
+ bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
+
+ size = bcm_xtlv_size_for_data(len, opts);
+ sbuflen -= size;
+ if (sbuflen < 0) /* buffer overrun? */
+ break;
+
+ if (id == type) {
+ retptr = data;
+ if (datalen)
+ *datalen = len;
+ break;
+ }
+
+ tlv_buf += size;
+ }
+
+ return retptr;
+}
+
+bcm_xtlv_t*
+bcm_xtlv_bcopy(const bcm_xtlv_t *src, bcm_xtlv_t *dst,
+ int src_buf_len, int dst_buf_len, bcm_xtlv_opts_t opts)
+{
+ bcm_xtlv_t *dst_next = NULL;
+ src = (src && bcm_valid_xtlv(src, src_buf_len, opts)) ? src : NULL;
+ if (src && dst) {
+ uint16 type;
+ uint16 len;
+ const uint8 *data;
+ int size;
+ bcm_xtlv_unpack_xtlv(src, &type, &len, &data, opts);
+ size = bcm_xtlv_size_for_data(len, opts);
+ if (size <= dst_buf_len) {
+ bcm_xtlv_pack_xtlv(dst, type, len, data, opts);
+ dst_next = (bcm_xtlv_t *)((uint8 *)dst + size);
+ }
+ }
+
+ return dst_next;
+}
diff --git a/wl/src/shared/miniopt.c b/wl/src/shared/miniopt.c
new file mode 100644
index 0000000..9a81751
--- /dev/null
+++ b/wl/src/shared/miniopt.c
@@ -0,0 +1,161 @@
+/*
+ * Description.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: miniopt.c 514727 2014-11-12 03:02:48Z $
+ */
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#include <typedefs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <miniopt.h>
+
+
+/* ---- Public Variables ------------------------------------------------- */
+/* ---- Private Constants and Types -------------------------------------- */
+
+
+
+/* ---- Private Variables ------------------------------------------------ */
+/* ---- Private Function Prototypes -------------------------------------- */
+/* ---- Functions -------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------- */
+void
+miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags)
+{
+ static const char *null_flags = "";
+
+ memset(t, 0, sizeof(miniopt_t));
+ t->name = name;
+ if (flags == NULL)
+ t->flags = null_flags;
+ else
+ t->flags = flags;
+ t->longflags = longflags;
+}
+
+
+/* ----------------------------------------------------------------------- */
+int
+miniopt(miniopt_t *t, char **argv)
+{
+ int keylen;
+ char *p, *eq, *valstr, *endptr = NULL;
+ int err = 0;
+
+ t->consumed = 0;
+ t->positional = FALSE;
+ memset(t->key, 0, MINIOPT_MAXKEY);
+ t->opt = '\0';
+ t->valstr = NULL;
+ t->good_int = FALSE;
+ valstr = NULL;
+
+ if (*argv == NULL) {
+ err = -1;
+ goto exit;
+ }
+
+ p = *argv++;
+ t->consumed++;
+
+ if (!t->opt_end && !strcmp(p, "--")) {
+ t->opt_end = TRUE;
+ if (*argv == NULL) {
+ err = -1;
+ goto exit;
+ }
+ p = *argv++;
+ t->consumed++;
+ }
+
+ if (t->opt_end) {
+ t->positional = TRUE;
+ valstr = p;
+ }
+ else if (!strncmp(p, "--", 2)) {
+ eq = strchr(p, '=');
+ if (eq == NULL && !t->longflags) {
+ fprintf(stderr,
+ "%s: missing \" = \" in long param \"%s\"\n", t->name, p);
+ err = 1;
+ goto exit;
+ }
+ keylen = eq ? (int)(eq - (p + 2)) : (int)strlen(p) - 2;
+ if (keylen > 63) keylen = 63;
+ memcpy(t->key, p + 2, keylen);
+
+ if (eq) {
+ valstr = eq + 1;
+ if (*valstr == '\0') {
+ fprintf(stderr,
+ "%s: missing value after \" = \" in long param \"%s\"\n",
+ t->name, p);
+ err = 1;
+ goto exit;
+ }
+ }
+ }
+ else if (!strncmp(p, "-", 1)) {
+ t->opt = p[1];
+ if (strlen(p) > 2) {
+ fprintf(stderr,
+ "%s: only single char options, error on param \"%s\"\n",
+ t->name, p);
+ err = 1;
+ goto exit;
+ }
+ if (strchr(t->flags, t->opt)) {
+ /* this is a flag option, no value expected */
+ valstr = NULL;
+ } else {
+ if (*argv == NULL) {
+ fprintf(stderr,
+ "%s: missing value parameter after \"%s\"\n", t->name, p);
+ err = 1;
+ goto exit;
+ }
+ valstr = *argv;
+ argv++;
+ t->consumed++;
+ }
+ } else {
+ t->positional = TRUE;
+ valstr = p;
+ }
+
+ /* parse valstr as int just in case */
+ if (valstr) {
+ t->uval = (uint)strtoul(valstr, &endptr, 0);
+ t->val = (int)t->uval;
+ t->good_int = (*endptr == '\0');
+ }
+
+ t->valstr = valstr;
+
+exit:
+ if (err == 1)
+ t->opt = '?';
+
+ return err;
+}
diff --git a/wl/src/tools/release/WLAN.usf b/wl/src/tools/release/WLAN.usf
new file mode 100644
index 0000000..681d66a
--- /dev/null
+++ b/wl/src/tools/release/WLAN.usf
@@ -0,0 +1,57 @@
+#
+# This is a common config file that is used mainly by modules
+# or brand makefiles. The ".usf" suffix stands for "universal
+# settings file". The important feature is that this file is
+# both legal makefile and shell syntax, and could be parsed as
+# a properties file by any language (Perl, Python, Java, ...)
+# which understands properties.
+#
+# Rules: Each line is either an assignment, a comment, or blank.
+# Assignments MUST be of the form "foo=bar" (no spaces) and
+# comments have a leading "#" character.
+#
+# It can be included by common templates like WLAN_Common.mk,
+# or by brand makefiles, or sourced by build scripts.
+#
+# Copyright (C) 2017, Broadcom. All Rights Reserved.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+#
+# <<Broadcom-WL-IPTag/Open:>>
+#
+# $Id: WLAN.usf 658442 2016-09-08 01:17:56Z $
+#
+
+# Current list of components
+# This list is used in module makefiles to set vpath search
+# paths and include paths
+
+WLAN_COMPONENT_PATHS=src/shared/bcmwifi components/clm-api src/wl/lwip src/wl/ppr \
+ src/wl/rel_mcast src/wl/gas src/wl/encode src/wl/olpc \
+ src/wl/keymgmt src/wl/iocv src/wl/dump \
+ components/ndis src/wl/proxd src/dongle src/rte \
+ components/nan src/wl/ate src/wl/mesh src/wl/randmac \
+ components/phy src/wl/natoe components/accel components/avs \
+ components/msch components/apf components/hml src/wl/chctx
+
+# This is a staging area for generated content that need to be shared
+# between build step and packaging step. E.g when CLM data files
+# need to be packaged, they are first staged to $(WLAN_GEN_BASEDIR)
+# and packaged from there.
+
+WLAN_GEN_BASEDIR=generated
+
+# This is the conventional Windows mount point for network files.
+
+WLAN_WINPFX=Z:
diff --git a/wl/src/wl/exe/GNUmakefile b/wl/src/wl/exe/GNUmakefile
new file mode 100644
index 0000000..4f04ce9
--- /dev/null
+++ b/wl/src/wl/exe/GNUmakefile
@@ -0,0 +1,814 @@
+#
+# GNUmakefile for wl/exe
+#
+# Broadcom Proprietary and Confidential. Copyright (C) 2017,
+# All Rights Reserved.
+#
+# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+# the contents of this file may not be disclosed to third parties, copied
+# or duplicated in any form, in whole or in part, without the prior
+# written permission of Broadcom.
+#
+#
+# <<Broadcom-WL-IPTag/Proprietary:>>
+#
+# $Id: GNUmakefile 663904 2017-02-16 07:26:50Z $
+
+WLAN_ComponentsInUse := bcmwifi ppr
+ifeq ($(CONFIG_WLEXE),y)
+ SRCBASE := $(WLAN_SrcBaseR)
+ export WLAN_TreeBaseA=$(abspath ../../..)
+endif
+include ../../makefiles/WLAN_Common.mk
+
+ifndef SRCBASE
+ SRCBASE := $(WLAN_SrcBaseR)
+endif
+
+UNAME = $(shell uname)
+
+ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
+
+#-----------------------------------------------------------------
+# Windows build, don't include Makerules due to all: conflict
+
+include ../../GNUmakefile.inc
+
+# MfgTest XP and WIN7 WLU DLL builds are built from other standalone Makefiles
+# from App and MfgTest teams
+# To build XP WLU DLL (output is in windows/winxp/obj/*/mfg_dll/{free,checked}/...)
+# $(MAKE) -C src/wl/exe -f GNUmakefile.wlu_dll
+# To build Win7/Vista WLU DLL (output is in windows/win7/obj/*/mfg_dll/{Release,Debug}/...)
+# $(MAKE) -C src/wl/exe/win7
+
+else # UNAME
+
+#-----------------------------------------------------------------
+# Linux build
+#
+
+# This should be one of values recognized in src/Makerules
+# 2) not windows, need to include first to pick up TARGETENV dependent vars
+include $(SRCBASE)/Makerules
+
+# GNU make function to do compilation and dependency generation
+# in one step.
+define CompileAndMakedep
+$(strip $1 -c -MMD -MF $(@D)/.$(@F).depend -MP $2)
+endef
+
+ifeq ($(CONFIG_WLEXE),y)
+ CFLAGS += -fno-strict-aliasing -O2 -s
+endif
+
+
+# Use newer 11ac ratespec for wl command line
+CFLAGS += -DD11AC_IOTYPES
+
+# Use opaque PPR structures
+CFLAGS += -DPPR_API
+
+#ifdef SR_DEBUG
+CFLAGS += -DSR_DEBUG
+#endif
+
+#ifdef WLCNT
+ CFLAGS += -DWLCNT
+#endif
+
+#ifdef WIFI_ACT_FRAME
+ CFLAGS += -DWIFI_ACT_FRAME
+#endif
+
+#ifdef WLEXTLOG
+ CFLAGS += -DWLEXTLOG
+#endif
+
+ifeq ($(WLTEST),1)
+ CFLAGS += -DSERDOWNLOAD
+ CFLAGS += -DWLTEST
+endif
+
+ifeq ($(PCIE_MFGTEST),1)
+ CFLAGS += -DPCIE_MFGTEST
+endif
+
+ifeq ($(OLYMPIC_RWL),1)
+ CFLAGS += -DOLYMPIC_RWL
+endif
+
+
+ifneq ($(findstring $(TARGETENV), "linux linuxmips linuxmips_be linuxarm linuxarm_le android android_ndk_r6b freebsd freebsd_be"),)
+
+#ifdef WLP2P
+ CFLAGS += -DWLP2P
+#endif
+
+#ifdef WLMCHAN
+ CFLAGS += -DWLMCHAN
+#endif
+
+#ifdef WLTDLS
+ CFLAGS += -DWLTDLS
+#endif
+
+#ifdef WLNDOE
+ CFLAGS += -DWLNDOE
+#endif
+
+#ifdef WLP2PO
+ CFLAGS += -DWLP2PO
+#endif
+
+#ifdef WLANQPO
+ CFLAGS += -DWLANQPO
+#endif
+
+#ifdef WLBDO
+ CFLAGS += -DWLBDO
+#endif
+
+#ifdef WLTKO
+ CFLAGS += -DWLTKO
+#endif
+
+#ifdef TRAFFIC_MGMT
+ CFLAGS += -DTRAFFIC_MGMT
+#endif
+
+#ifdef WL_PROXDETECT
+ CFLAGS += -DWL_PROXDETECT
+#endif
+
+#ifdef WL_RANDMAC
+ CFLAGS += -DWL_RANDMAC
+#endif
+
+#ifdef WL_MSCH
+ CFLAGS += -DWL_MSCH
+#endif
+
+#ifdef WL11ULB
+ CFLAGS += -DWL11ULB
+#endif
+
+# netlink driver interface
+ifeq ($(NL80211),1)
+ CFLAGS += -DNL80211
+endif
+
+#ifeq ($(tbow),1)
+ CFLAGS += -DBT_WIFI_HANDOVER
+#endif
+
+#ifdef WLWNM
+ CFLAGS += -DWLWNM
+#endif
+
+#if defined(WLBSSLOAD_REPORT)
+ CFLAGS += -DWLBSSLOAD_REPORT
+#endif
+
+#ifdef WL_NAN
+CFLAGS += -DWL_NAN
+#endif
+
+#ifdef WLRSDB
+CFLAGS += -DWLRSDB
+#endif
+
+#ifdef WL_NATOE
+CFLAGS += -DWL_NATOE
+#endif
+
+#ifdef WL_BTCDYN
+ CFLAGS += -DWL_BTCDYN
+#endif
+
+#ifdef WL_MPF
+CFLAGS += -DWL_MPF
+#endif
+
+#ifdef WLRCC
+CFLAGS += -DWLRCC
+#endif
+#ifdef WL_MBO
+CFLAGS += -DWL_MBO
+#endif
+#ifdef WL_MBO_WFA_CERT
+CFLAGS += -DWL_MBO_WFA_CERT
+#endif
+
+
+#ifdef ECOUNTERS
+ CFLAGS += -DECOUNTERS
+#endif
+
+CFLAGS += -DTBTT_OFFSET_STAT
+
+# extra warnings
+ifneq ($(filter mips_be arm_le arm_android arm_android_ndk_r6b arm64_android,$(TARGETARCH)),)
+CFLAGS += -Wextra -Wall
+else
+CFLAGS += -Wextra -Wall -Werror
+endif
+CFLAGS += -DWLPFN -DWLPFN_AUTO_CONNECT
+
+# Avoid compilation error of unused value warning in open source sha256
+ifneq ($(findstring WL_NAN, $(CFLAGS)),)
+CFLAGS += -Wno-error="unused-value"
+endif
+
+ifneq (,$(findstring freebsd, $(TARGETENV)))
+ # To do cross compilation on linux,
+ # - Define the env CROSS_COMPILE pointing to the cross compile tool dir
+ # - Define the env FREEBSD_DIR pointing to the FreeBSD source directory
+ # To do local compilation on a FreeBSD machine, do not set CROSS_COMPILE or FREEBSD_DIR
+ CC := $(CROSS_COMPILE)gcc
+ LD := $(CROSS_COMPILE)ld
+ NM := $(CROSS_COMPILE)nm
+ OBJCOPY := $(CROSS_COMPILE)objcopy
+ ifneq (,$(findstring freebsd_be, $(TARGETENV)))
+ CFLAGS += -DIL_BIGENDIAN
+ endif
+else
+ CFLAGS += -DLINUX
+endif
+CFLAGS += -I$(SRCBASE)/wl/sys
+CFLAGS += $(WLAN_ComponentIncPathR)
+
+# Discard any "MMX" or other qualifications on x86 so that
+# any TARGETARCH containing x86 is just "x86"
+ifeq ($(findstring x86_mmx,$(TARGETARCH)),x86_mmx)
+ TARGETARCH = x86
+endif
+
+ASD ?= 0
+ifneq ($(ASD),1)
+ override ASD:=
+endif
+ifneq ($(ASD),1)
+ NOASDDIR = _noasd
+endif
+
+RWL ?= 1
+ifeq ($(RWL),0)
+ override RWL:=
+endif
+
+ifeq (,$(findstring freebsd, $(TARGETENV)))
+RWL_DONGLE ?= 1
+RWL_SOCKET ?= 1
+RWL_WIFI ?= 1
+RWL_SERIAL ?= 1
+
+ifneq ($(RWL_DONGLE),0)
+RWL_SERVERS += $(SERVER_DONGLE)
+endif
+ifneq ($(RWL_SOCKET),0)
+RWL_SERVERS += $(SERVER_SOCKET)
+endif
+ifneq ($(RWL_WIFI),0)
+RWL_SERVERS += $(SERVER_WIFI)
+endif
+ifneq ($(RWL_SERIAL),0)
+RWL_SERVERS += $(SERVER_SERIAL)
+endif
+endif
+# $(TARGETARCH) is set based on TARGETENV in src/Makerules.* files
+ifneq (,$(findstring freebsd, $(TARGETENV)))
+WL_OBJS := wlu.o wlu_common.o wlu_bsd.o wlu_cmd.o wlu_iov.o wlu_rates_matrix.o miniopt.o bcmutils.o bcmwifi_channels.o bcm_app_utils.o wlc_ppr.o bcmxtlv.o bcmbloom.o wlu_subcounters.o
+else
+WL_OBJS := wlu.o wlu_common.o wlu_linux.o bcmutils.o bcmwifi_channels.o wlu_cmd.o wlu_iov.o wlu_client_shared.o wlu_pipe_linux.o wlu_pipe.o miniopt.o bcm_app_utils.o wlu_rates_matrix.o wlc_ppr.o bcmxtlv.o bcmbloom.o wlu_subcounters.o
+endif
+
+ifneq ($(findstring WL_NAN, $(CFLAGS)),)
+WL_OBJS += sha256.o
+endif
+
+SERVER_OBJS := wlu_server_linux.o wlu_pipe_linux.o wlu_pipe.o wlu_server_shared.o shellproc_linux.o
+WLM_OBJS := $(WL_OBJS) wlm.o
+WLHIGHSTUB_OBJS := wlhighstub.o bcm_rpc_char.o bcm_rpc.o linux_rpc_osl.o
+WLHIGHSTUB_OBJS += wlc_low_stubs.o bcm_xdr.o
+
+WL_OBJS += wluc_phy.o
+WL_OBJS += wluc_wnm.o
+WL_OBJS += wluc_cac.o
+WL_OBJS += wluc_relmcast.o
+WL_OBJS += wluc_rrm.o
+WL_OBJS += wluc_wowl.o
+WL_OBJS += wluc_pkt_filter.o
+WL_OBJS += wluc_mfp.o
+WL_OBJS += wluc_ota_test.o
+WL_OBJS += wluc_bssload.o
+WL_OBJS += wluc_stf.o
+WL_OBJS += wluc_offloads.o
+WL_OBJS += wluc_tpc.o
+WL_OBJS += wluc_toe.o
+WL_OBJS += wluc_arpoe.o
+WL_OBJS += wluc_keep_alive.o
+WL_OBJS += wluc_ap.o
+WL_OBJS += wluc_ampdu.o
+WL_OBJS += wluc_ampdu_cmn.o
+WL_OBJS += wluc_bmac.o
+WL_OBJS += wluc_ht.o
+WL_OBJS += wluc_wds.o
+WL_OBJS += wluc_keymgmt.o
+WL_OBJS += wluc_scan.o
+WL_OBJS += wluc_obss.o
+WL_OBJS += wluc_prot_obss.o
+WL_OBJS += wluc_lq.o
+WL_OBJS += wluc_seq_cmds.o
+WL_OBJS += wluc_btcx.o
+WL_OBJS += wluc_led.o
+WL_OBJS += wluc_interfere.o
+WL_OBJS += wluc_ltecx.o
+WL_OBJS += wlu_avail_utils.o
+
+ifneq ($(findstring WL_BTCDYN, $(CFLAGS)),)
+WL_OBJS += wluc_btcdyn.o
+endif
+
+ifneq ($(findstring WL_NAN, $(CFLAGS)),)
+WL_OBJS += wluc_nan.o
+endif
+
+ifneq ($(findstring WLRSDB, $(CFLAGS)),)
+WL_OBJS += wluc_rsdb.o
+endif
+
+ifneq ($(findstring WLEXTLOG, $(CFLAGS)),)
+WL_OBJS += wluc_extlog.o
+endif
+
+ifneq ($(findstring BCMSDIO, $(CFLAGS)),)
+WL_OBJS += wluc_sdio.o
+endif
+
+ifneq ($(findstring WLNDOE, $(CFLAGS)),)
+WL_OBJS += wluc_ndoe.o
+endif
+
+ifneq ($(filter -DWLP2PO, $(CFLAGS)),)
+WL_OBJS += wluc_p2po.o
+endif
+
+ifneq ($(findstring WLANQPO, $(CFLAGS)),)
+WL_OBJS += wluc_anqpo.o
+endif
+
+ifneq ($(findstring WLBDO, $(CFLAGS)),)
+WL_OBJS += wluc_bdo.o
+endif
+
+ifneq ($(findstring WLTKO, $(CFLAGS)),)
+WL_OBJS += wluc_tko.o
+endif
+
+ifneq ($(findstring WLPFN, $(CFLAGS)),)
+WL_OBJS += wluc_pfn.o
+endif
+
+ifneq ($(findstring BT_WIFI_HANDOVER, $(CFLAGS)),)
+WL_OBJS += wluc_tbow.o
+endif
+
+ifneq ($(filter -DWLP2P, $(CFLAGS)),)
+WL_OBJS += wluc_p2p.o
+endif
+
+ifneq ($(findstring WLTDLS, $(CFLAGS)),)
+WL_OBJS += wluc_tdls.o
+endif
+
+ifneq ($(findstring TRAFFIC_MGMT, $(CFLAGS)),)
+WL_OBJS += wluc_traffic_mgmt.o
+endif
+
+ifneq ($(findstring WL_PROXDETECT, $(CFLAGS)),)
+WL_OBJS += wluc_proxd.o
+endif
+
+ifneq ($(findstring WL_RANDMAC, $(CFLAGS)),)
+WL_OBJS += wluc_randmac.o
+endif
+
+ifneq ($(findstring WLMESH, $(CFLAGS)),)
+WL_OBJS += wluc_mesh.o
+endif
+
+ifneq ($(findstring WL_NATOE, $(CFLAGS)),)
+WL_OBJS += wluc_natoe.o
+endif
+
+ifneq ($(findstring WL_MSCH, $(CFLAGS)),)
+WL_OBJS += wluc_msch.o
+endif
+
+WL_OBJS += wluc_he.o
+
+
+ifneq ($(findstring WL_MBO, $(CFLAGS)),)
+WL_OBJS += wluc_mbo.o
+endif
+
+ifneq ($(findstring ECOUNTERS, $(CFLAGS)),)
+WL_OBJS += wluc_ecounters.o
+endif
+
+ifneq ($(wildcard ../../../components/hml),)
+CFLAGS += -DHOFFLOAD_MODULES
+CFLAGS += -I ../../../components/hml/include -I ../../pciedev
+WL_OBJS += wluc_hoffload.o
+endif
+
+# include build settings for nl80211 support
+ifeq ($(NL80211),1)
+include netlink.inc
+endif
+
+# Prefix obj/<type>/TARGETARCH to produced .obj files
+WL_OBJS := $(WL_OBJS:%.o=obj/wl$(NOASDDIR)/$(TARGETARCH)/%.o)
+DONGLE_OBJS := $(SERVER_OBJS:%.o=obj/dongle$(NOASDDIR)/$(TARGETARCH)/%.o)
+SOCKET_OBJS := $(SERVER_OBJS:%.o=obj/socket$(NOASDDIR)/$(TARGETARCH)/%.o)
+WIFI_OBJS := $(SERVER_OBJS:%.o=obj/wifi$(NOASDDIR)/$(TARGETARCH)/%.o)
+SERIAL_OBJS := $(SERVER_OBJS:%.o=obj/serial$(NOASDDIR)/$(TARGETARCH)/%.o)
+WLM_OBJS := $(WLM_OBJS:%.o=obj/wlm/$(TARGETARCH)/%.o)
+WLHIGHSTUB_OBJS := $(WLHIGHSTUB_OBJS:%.o=obj/wlhighstub/$(TARGETARCH)/%.o)
+
+# Derive a final list of all known objects.
+OBJS := $(WL_OBJS) $(DONGLE_OBJS) $(SOCKET_OBJS) $(WIFI_OBJS) $(SERIAL_OBJS) $(WLM_OBJS) $(WLHIGHSTUB_OBJS)
+
+# Make a list of dependency files, one per object file.
+DEPENDS := $(join $(dir $(OBJS)),$(addprefix .,$(addsuffix .depend,$(notdir $(OBJS)))))
+
+# Include any dependency files which currently exist.
+-include $(DEPENDS)
+
+# TODO: Move final built objects to respective TARGETARCH dirs as well
+# Final exe names
+ifneq ($(TARGETARCH),x86)
+ ARCH_SFX = $(TARGETARCH)
+endif
+WL_EXE := wl$(ARCH_SFX)
+SERVER_SOCKET = socket$(NOASDDIR)/$(TARGETARCH)/wl_server_socket$(ARCH_SFX)
+SERVER_DONGLE = dongle$(NOASDDIR)/$(TARGETARCH)/wl_server_dongle$(ARCH_SFX)
+SERVER_WIFI = wifi$(NOASDDIR)/$(TARGETARCH)/wl_server_wifi$(ARCH_SFX)
+SERVER_SERIAL = serial$(NOASDDIR)/$(TARGETARCH)/wl_server_serial$(ARCH_SFX)
+WLM_SO := wlm/$(TARGETARCH)/wlm$(ARCH_SFX).so
+WLHIGHSTUB := obj/wlhighstub/$(TARGETARCH)/wlhighstub$(ARCH_SFX)
+
+# excluding lbrt inclusion for android build
+ifeq (,$(findstring android,$(TARGETARCH)))
+LDFLAGS += -lrt
+endif
+
+# ASD specific flags
+ifeq ($(ASD),1)
+ ASD_CFLAGS := -DRWLASD
+ ASD_CFLAGS += -I../../tools/Wifi_ASD_test/inc
+ifneq ($(filter mips_be arm_android arm_android_ndk_r6b x86_android_ndk_r6b arm64_android,$(TARGETARCH)),)
+ ASD_LDFLAGS:= -L../../tools/Wifi_ASD_test/lib/$(TARGETARCH) -lwfa
+else
+ ASD_LDFLAGS:= -L../../tools/Wifi_ASD_test/lib/$(TARGETARCH) -lwfa -lpthread
+endif
+endif # ASD
+INSTALL_DIR ?= apps
+
+vpath %.c $(SRCBASE)/shared $(SRCBASE)/wl/sys $(WLAN_StdSrcDirsR) $(WLAN_ComponentSrcDirsR)
+
+all: build_deps
+
+# Build servers for all but mips_be
+ifeq ($(filter mips_be,$(TARGETARCH)),)
+all: $(WL_EXE) servers
+else
+all: $(WL_EXE)
+endif
+
+build_deps:
+ifeq ($(ASD),1)
+ $(MAKE) -C ../../tools/Wifi_ASD_test
+endif # ASD
+
+wlm: $(WLM_SO)
+
+servers: $(RWL_SERVERS)
+
+# Handle creation of directories for objects mentioned below.
+$(addprefix obj/,$(addsuffix $(NOASDDIR)/$(TARGETARCH),wl dongle socket wifi serial) $(addsuffix /$(TARGETARCH),wlm wlhighstub)):
+ @mkdir -pv $@
+
+# Compilation targets
+obj/wl$(NOASDDIR)/$(TARGETARCH)/%.o: %.c | obj/wl$(NOASDDIR)/$(TARGETARCH)
+ifneq ($(RWL),)
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_SOCKET -DRWL_DONGLE -DRWL_WIFI -DRWL_SERIAL -o $@ $<)
+else
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -o $@ $<)
+endif
+
+obj/dongle$(NOASDDIR)/$(TARGETARCH)/%.o: %.c | obj/dongle$(NOASDDIR)/$(TARGETARCH)
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_DONGLE -o $@ $<)
+
+obj/socket$(NOASDDIR)/$(TARGETARCH)/%.o: %.c | obj/socket$(NOASDDIR)/$(TARGETARCH)
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_SOCKET -o $@ $<)
+
+obj/wifi$(NOASDDIR)/$(TARGETARCH)/%.o: %.c | obj/wifi$(NOASDDIR)/$(TARGETARCH)
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_WIFI -o $@ $<)
+
+obj/serial$(NOASDDIR)/$(TARGETARCH)/%.o: %.c | obj/serial$(NOASDDIR)/$(TARGETARCH)
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_SERIAL -o $@ $<)
+
+obj/wlm/$(TARGETARCH)/%.o: %.c | obj/wlm/$(TARGETARCH)
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_DONGLE -DRWL_SOCKET -DRWL_WIFI -DRWL_SERIAL -DWLMSO -fPIC -o $@ $<)
+
+obj/wlhighstub/$(TARGETARCH)/%.o: %.c | obj/wlhighstub/$(TARGETARCH)
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) -o $@ $<)
+
+$(WLHIGHSTUB): $(WLHIGHSTUB_OBJS)
+ @mkdir -pv $(@D)
+
+# Final link targets
+$(WL_EXE): $(WL_OBJS)
+ $(strip $(CC) -o $@ $^ $(LDFLAGS) $(LIBS))
+ifneq ($(filter arm_android_ndk_r6b,$(TARGETARCH)),)
+ifneq ($(TARGET_PREFIX),)
+ $(TARGET_PREFIX)strip $(WL_EXE)
+endif
+endif
+
+# net_priv target is for building the dhd with NET_ADMIN privilege (i.e. to avoid running as root)
+# note: The 'setcap' command is availble from the libcap2-bin package
+# note: linux kernel < 2.6.33 doesn't support Security File Capabilities by default
+net_priv: $(WL_EXE)
+ sudo setcap CAP_NET_ADMIN=eip $^
+
+$(SERVER_DONGLE): $(DONGLE_OBJS)
+ @mkdir -pv $(@D)
+ $(strip $(CC) $(LDFLAGS) -o $@ $^ $(ASD_LDFLAGS))
+
+$(SERVER_SOCKET): $(SOCKET_OBJS)
+ @mkdir -pv $(@D)
+ $(strip $(CC) $(LDFLAGS) -o $@ $^ $(ASD_LDFLAGS))
+
+$(SERVER_WIFI): $(WIFI_OBJS)
+ @mkdir -pv $(@D)
+ $(strip $(CC) $(LDFLAGS) -o $@ $^ $(ASD_LDFLAGS))
+
+$(SERVER_SERIAL): $(SERIAL_OBJS)
+ @mkdir -pv $(@D)
+ $(strip $(CC) $(LDFLAGS) -o $@ $^ $(ASD_LDFLAGS))
+
+$(WLM_SO): $(WLM_OBJS)
+ @mkdir -pv $(@D)
+ $(strip $(CC) $(LDFLAGS) -shared -o $@ $^)
+
+wldefs: wlmain.o
+ $(CC) $(LDFLAGS) -o $@ $<
+
+.PHONY: all clean wlm release_bins net_priv
+
+release_bins:
+ @mkdir -p $(INSTALL_DIR)
+ install -pv $(WL_EXE) $(INSTALL_DIR)
+ifeq ($(filter mips_be,$(TARGETARCH)),)
+ install -pv $(SERVER_SOCKET) $(INSTALL_DIR)
+ install -pv $(SERVER_DONGLE) $(INSTALL_DIR)
+ install -pv $(SERVER_WIFI) $(INSTALL_DIR)
+ install -pv $(SERVER_SERIAL) $(INSTALL_DIR)
+endif
+ifeq ($(ASD),1)
+ $(MAKE) -C ../../tools/Wifi_ASD_test release_bins
+endif #ASD
+
+clean::
+ rm -fv $(WL_EXE) $(WL_OBJS) $(SERVER_SOCKET) $(SERVER_DONGLE) $(SERVER_WIFI) $(SERVER_SERIAL) $(SOCKET_OBJS) $(SERIAL_OBJS) $(WIFI_OBJS) $(DONGLE_OBJS) $(WLM_SO) $(WLM_OBJS) $(SERVER_SERIAL) $(DEPENDS)
+
+endif # TARGETENV linux
+
+#-----------------------------------------------------------------
+# MacOS build
+#
+
+ifeq ($(TARGETENV), macos)
+
+ifndef MACOS_VER
+ MACOS_VER := $(shell sw_vers -productVersion)
+endif
+
+include $(SRCBASE)/Makerules.env
+
+.PHONY: all everything clean wl wl_server_socket wl_server_wifi wl_dongle
+
+PROJTGT := wl
+BUILD := xcodebuild
+PROJECT := wl.xcodeproj
+OBJDIR := $(TARGETENV)/$(MACOS_VER)
+
+all: wl wl_server_socket
+
+everything: wl wl_server_socket wl_server_wifi wl_dongle
+
+clean::
+ rm -rf $(OBJDIR) build
+
+wl wl_server_socket wl_server_wifi: | $(OBJDIR)
+
+#
+# dongle wl is located at ./build/Debug/wl
+#
+wl_dongle:
+ $(BUILD) -project $(PROJECT) -target $(PROJTGT) -configuration Debug build
+
+WL_EXE := $(OBJDIR)/wl
+SERVER_SOCKET := $(OBJDIR)/socket/wl_server_socket
+SERVER_WIFI := $(OBJDIR)/wifi/wl_server_wifi
+
+WL_OBJS := $(addprefix $(OBJDIR)/,wlu.o wlu_common.o wlu_macos.o bcmutils.o bcmwifi_channels.o wlu_cmd.o wlu_iov.o miniopt.o bcm_app_utils.o wlu_rates_matrix.o wlc_ppr.o bcmxtlv.o wlu_subcounters.o)
+SERVER_OBJS := wlu_server_macos.o wlu_pipe_linux.o wlu_pipe.o wlu_server_shared.o shellproc_linux.o
+SOCKET_OBJS := $(SERVER_OBJS:%.o=$(OBJDIR)/socket/%.o)
+WIFI_OBJS := $(SERVER_OBJS:%.o=$(OBJDIR)/wifi/%.o)
+
+# Derive a final list of all known objects.
+OBJS := $(WL_OBJS) $(SOCKET_OBJS) $(WIFI_OBJS)
+
+# Create the sub-directories needed to hold object files.
+$(sort $(dir $(OBJS))):
+ @mkdir -pv $@
+
+# Make a list of dependency files, one per object file.
+DEPENDS := $(join $(dir $(OBJS)),$(addprefix .,$(addsuffix .depend,$(notdir $(OBJS)))))
+
+# Include any dependency files which currently exist.
+-include $(DEPENDS)
+
+vpath %.c .. $(SRCBASE)/shared $(SRCBASE)/wl/sys $(WLAN_StdSrcDirsR) $(WLAN_ComponentSrcDirsR)
+
+ifneq (,$(findstring 10.11,$(MACOS_VER)))
+ GCDEFS += -DWLP2P -DWLMCHAN -DPPR_API -DWLANQPO -DWLP2PO -DWL_DUMP_BUF_LEN=819200
+else
+ifneq (,$(findstring 10.10,$(MACOS_VER)))
+ GCDEFS += -DWLP2P -DWLMCHAN -DPPR_API -DWLANQPO -DWLP2PO -DWL_DUMP_BUF_LEN=819200
+else
+ifneq (,$(findstring 10.9,$(MACOS_VER)))
+ GCDEFS += -DWLP2P -DWLMCHAN -DPPR_API -DWLANQPO -DWLP2PO
+else
+ GCDEFS += -DWLP2P -DWLMCHAN -DPPR_API -DWLANQPO -DWLP2PO -DWL_DUMP_BUF_LEN=819200
+endif
+endif
+endif
+
+
+WL_OBJS += $(OBJDIR)/wluc_phy.o
+WL_OBJS += $(OBJDIR)/wluc_wnm.o
+WL_OBJS += $(OBJDIR)/wluc_cac.o
+WL_OBJS += $(OBJDIR)/wluc_relmcast.o
+WL_OBJS += $(OBJDIR)/wluc_rrm.o
+WL_OBJS += $(OBJDIR)/wluc_wowl.o
+WL_OBJS += $(OBJDIR)/wluc_pkt_filter.o
+WL_OBJS += $(OBJDIR)/wluc_mfp.o
+WL_OBJS += $(OBJDIR)/wluc_ota_test.o
+WL_OBJS += $(OBJDIR)/wluc_bssload.o
+WL_OBJS += $(OBJDIR)/wluc_stf.o
+WL_OBJS += $(OBJDIR)/wluc_offloads.o
+WL_OBJS += $(OBJDIR)/wluc_tpc.o
+WL_OBJS += $(OBJDIR)/wluc_toe.o
+WL_OBJS += $(OBJDIR)/wluc_arpoe.o
+WL_OBJS += $(OBJDIR)/wluc_keep_alive.o
+WL_OBJS += $(OBJDIR)/wluc_ap.o
+WL_OBJS += $(OBJDIR)/wluc_ampdu.o
+WL_OBJS += $(OBJDIR)/wluc_ampdu_cmn.o
+WL_OBJS += $(OBJDIR)/wluc_bmac.o
+WL_OBJS += $(OBJDIR)/wluc_ht.o
+WL_OBJS += $(OBJDIR)/wluc_wds.o
+WL_OBJS += $(OBJDIR)/wluc_keymgmt.o
+WL_OBJS += $(OBJDIR)/wluc_scan.o
+WL_OBJS += $(OBJDIR)/wluc_obss.o
+WL_OBJS += $(OBJDIR)/wluc_prot_obss.o
+WL_OBJS += $(OBJDIR)/wluc_lq.o
+WL_OBJS += $(OBJDIR)/wluc_seq_cmds.o
+WL_OBJS += $(OBJDIR)/wluc_btcx.o
+WL_OBJS += $(OBJDIR)/wluc_led.o
+WL_OBJS += $(OBJDIR)/wluc_interfere.o
+WL_OBJS += $(OBJDIR)/wluc_ltecx.o
+
+ifneq ($(or $(findstring WL_BTCDYN, $(GCDEFS)),\
+ $(findstring WL_BTCDYN, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_btcdyn.o
+endif
+
+ifneq ($(findstring WLMESH, $(CFLAGS)),)
+WL_OBJS += $(OBJDIR)/wluc_mesh.o
+endif
+
+ifneq ($(or $(findstring WL_NAN, $(GCDEFS)),\
+ $(findstring WL_NAN, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_nan.o
+endif
+
+ifneq ($(or $(findstring WLRSDB, $(GCDEFS)),\
+ $(findstring WLRSDB, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_rsdb.o
+endif
+
+ifneq ($(or $(findstring WL_NATOE, $(GCDEFS)),\
+ $(findstring WL_NATOE, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_natoe.o
+endif
+
+ifneq ($(or $(findstring WLEXTLOG, $(GCDEFS)),\
+ $(findstring WLEXTLOG, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_extlog.o
+endif
+
+ifneq ($(or $(findstring BCMSDIO, $(GCDEFS)),\
+ $(findstring BCMSDIO, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_sdio.o
+endif
+
+ifneq ($(or $(findstring WLNDOE, $(GCDEFS)),\
+ $(findstring WLNDOE, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_ndoe.o
+endif
+
+ifneq ($(or $(filter -DWLP2PO, $(GCDEFS)),\
+ $(filter -DWLP2PO, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_p2po.o
+endif
+
+ifneq ($(or $(findstring WLANQPO, $(GCDEFS)),\
+ $(findstring WLANQPO, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_anqpo.o
+endif
+
+ifneq ($(or $(findstring WLBDO, $(GCDEFS)),\
+ $(findstring WLBDO, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_bdo.o
+endif
+
+ifneq ($(or $(findstring WLTKO, $(GCDEFS)),\
+ $(findstring WLTKO, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_tko.o
+endif
+ifneq ($(or $(findstring WLPFN, $(GCDEFS)),\
+ $(findstring WLPFN, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_pfn.o
+endif
+
+ifneq ($(or $(filter -DWLP2P, $(GCDEFS)),\
+ $(filter -DWLP2P, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_p2p.o
+endif
+
+ifneq ($(or $(findstring WLTDLS, $(GCDEFS)),\
+ $(findstring WLTDLS, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_tdls.o
+endif
+
+ifneq ($(or $(findstring TRAFFIC_MGMT, $(GCDEFS)),\
+ $(findstring TRAFFIC_MGMT, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_traffic_mgmt.o
+endif
+
+ifneq ($(or $(findstring WL_PROXDETECT, $(GCDEFS)),\
+ $(findstring WL_PROXDETECT, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_proxd.o
+endif
+
+ifneq ($(or $(findstring WL_MSCH, $(GCDEFS)),\
+ $(findstring WL_MSCH, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_msch.o
+endif
+
+
+ifneq ($(or $(findstring ECOUNTERS, $(GCDEFS)),\
+ $(findstring ECOUNTERS, $(CFLAGS))),)
+WL_OBJS += $(OBJDIR)/wluc_ecounters.o
+endif
+
+WL_OBJS += $(OBJDIR)/wluc_he.o
+
+$(OBJDIR)/%.o: %.c | $(OBJDIR)
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) -o $@ $<)
+
+wl: $(OBJDIR)/wl
+$(OBJDIR)/wl: $(WL_OBJS)
+ $(CC) -L/usr/lib $(LDFLAGS) -o $@ $^
+
+wl_server_socket: $(SERVER_SOCKET)
+$(SERVER_SOCKET): $(SOCKET_OBJS)
+ $(strip $(CC) $(LDFLAGS) -o $@ $^)
+
+$(OBJDIR)/socket/%.o: %.c | $(OBJDIR)/socket
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) -DRWL_SOCKET -DREMOTE_WL -o $@ $<)
+
+wl_server_wifi: $(SERVER_WIFI)
+$(SERVER_WIFI): $(WIFI_OBJS)
+ $(strip $(CC) $(LDFLAGS) -o $@ $^)
+
+$(OBJDIR)/wifi/%.o: %.c | $(OBJDIR)/wifi
+ $(call CompileAndMakedep,$(CC),$(CFLAGS) -DRWL_WIFI -DREMOTE_WL -o $@ $<)
+
+endif # TARGETENV macos
+
+endif # UNAME
diff --git a/wl/src/wl/exe/netlink.inc b/wl/src/wl/exe/netlink.inc
new file mode 100644
index 0000000..d32b169
--- /dev/null
+++ b/wl/src/wl/exe/netlink.inc
@@ -0,0 +1,95 @@
+#
+# netlink.inc for wl/exe
+#
+# Broadcom Proprietary and Confidential. Copyright (C) 2017,
+# All Rights Reserved.
+#
+# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+# the contents of this file may not be disclosed to third parties, copied
+# or duplicated in any form, in whole or in part, without the prior
+# written permission of Broadcom.
+#
+#
+# <<Broadcom-WL-IPTag/Proprietary:>>
+#
+# $Id: netlink.inc 629114 2016-04-04 08:29:40Z $
+
+ifneq ($(findstring android,$(TARGETENV)),)
+
+include $(dir $(lastword $(MAKEFILE_LIST)))/../../makefiles/WLAN_Common.mk
+
+ifeq ($(NLHEADERS_PATH),)
+$(error libnl headers path must be specified)
+endif
+ifeq ($(NLSTATICLIB_PATH),)
+$(error libnl static library path must be specified)
+endif
+
+CFLAGS += -I$(NLHEADERS_PATH)
+LIBS += -Wl,--whole-archive -Wl,--no-whole-archive $(NLSTATICLIB_PATH)
+
+LIBNLVER = $(shell grep "LIBNL_VERSION" $(NLHEADERS_PATH)/netlink/version.h | cut -d " " -f 3 | sed "s/\"//g")
+
+ifeq ($(call wlan_version_ge,$(LIBNLVER),3.0),TRUE)
+CFLAGS += -DCONFIG_LIBNL30
+else ifeq ($(call wlan_version_ge,$(LIBNLVER),2.0),TRUE)
+CFLAGS += -DCONFIG_LIBNL20
+endif
+
+else #ifneq ($(findstring android,$(TARGETENV)),)
+
+PKG_CONFIG ?= pkg-config
+
+NL1FOUND := $(shell $(PKG_CONFIG) --atleast-version=1 libnl-1 && echo Y)
+NL2FOUND := $(shell $(PKG_CONFIG) --atleast-version=2 libnl-2.0 && echo Y)
+NL3FOUND := $(shell $(PKG_CONFIG) --atleast-version=3 libnl-3.0 && echo Y)
+NL31FOUND := $(shell $(PKG_CONFIG) --exact-version=3.1 libnl-3.1 && echo Y)
+NL3xFOUND := $(shell $(PKG_CONFIG) --atleast-version=3.2 libnl-3.0 && echo Y)
+
+ifeq ($(NL1FOUND),Y)
+NLLIBNAME = libnl-1
+endif
+
+ifeq ($(NL2FOUND),Y)
+CFLAGS += -DCONFIG_LIBNL20
+LIBS += -lnl-genl
+NLLIBNAME = libnl-2.0
+endif
+
+ifeq ($(NL3xFOUND),Y)
+# libnl 3.2 might be found as 3.2 and 3.0
+NL3FOUND = N
+CFLAGS += -DCONFIG_LIBNL30
+LIBS += -lnl-genl-3
+NLLIBNAME = libnl-3.0
+endif
+
+ifeq ($(NL3FOUND),Y)
+CFLAGS += -DCONFIG_LIBNL30
+LIBS += -lnl-genl
+NLLIBNAME = libnl-3.0
+endif
+
+# nl-3.1 has a broken libnl-gnl-3.1.pc file
+# as show by pkg-config --debug --libs --cflags --exact-version=3.1 libnl-genl-3.1;echo $?
+ifeq ($(NL31FOUND),Y)
+CFLAGS += -DCONFIG_LIBNL30
+LIBS += -lnl-genl
+NLLIBNAME = libnl-3.1
+endif
+
+ifeq ($(NLLIBNAME),)
+ifeq ($(and $(NLLIBS), $(NLCFLAGS)),)
+$(error Cannot find development files for any supported version of libnl)
+endif
+LIBS += $(NLLIBS)
+CFLAGS += $(NLCFLAGS)
+$(warning override $(LIBS))
+else
+LIBS += $(shell $(PKG_CONFIG) --libs $(NLLIBNAME))
+CFLAGS += $(shell $(PKG_CONFIG) --cflags $(NLLIBNAME))
+endif
+
+endif #ifneq ($(findstring android,$(TARGETENV)),)
+
+WL_OBJS += wlu_nl80211.o
diff --git a/wl/src/wl/exe/shellproc_linux.c b/wl/src/wl/exe/shellproc_linux.c
new file mode 100644
index 0000000..e2cc825
--- /dev/null
+++ b/wl/src/wl/exe/shellproc_linux.c
@@ -0,0 +1,700 @@
+/*
+ * Remote shell command execution (common for all transports) for linux
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: shellproc_linux.c 514727 2014-11-12 03:02:48Z $
+ */
+
+/* Linux remote shell command execution
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmcdc.h>
+#include "wlu_remote.h"
+#include <sys/poll.h>
+#include <malloc.h>
+#include <miniopt.h>
+#include <sys/utsname.h>
+#define ASYNC_RESP 0
+#define MAX_SHELL_ASYNC_RESP 128 /* Support for maximum 5 async process */
+#define MAX_ASYNC_FILE_LENGTH 50
+#define MAX_PID_CMD_LENGTH 20
+#define MAX_PID_RESP_LENTH 50
+#define MAX_SHELL_CMD_LENTH 256
+#define PID_TOKEN_SIZE 50
+#define PID_SEARCH_CMD_SIZE 100
+#define ASYNC_SHELL_CHAR "%" /* Async process identifier from the client */
+#define FILE_PERMISSION 777
+
+#define DEFAULT_SHELL_TIMEOUT 0 /* Default TimeOut Value for synchronous shell commands */
+#define SHELL_RETURNVALUE_SIZE 2 /* Size of Return Value of the shell command */
+#define SHELL_ASYNCCMD_ID 1 /* To identify if it is an async command */
+#define REBOOT_MSG "Rebooting AP ...\n"
+
+/* Function prototypes */
+
+static int rwl_get_file_size(char *file_name);
+static int remote_shell_async_exec(char *buf_ptr);
+static int remote_shell_sync_exec(char *cmd_buf_ptr, void *wl);
+
+
+/* Data structure to hold async shell information */
+typedef struct remote_shell_async {
+ pid_t PID;
+ char file_name[MAX_ASYNC_FILE_LENGTH];
+} remote_shell_async_t;
+
+remote_shell_async_t g_async_resp[MAX_SHELL_ASYNC_RESP];
+
+extern int g_shellsync_pid;
+
+extern unsigned char g_return_stat;
+extern void rwl_chld_handler(int num);
+extern int set_ctrlc;
+extern void handle_ctrlc(int unused);
+
+/* Global variable to store the timeout value for the shell commands */
+static int g_shellsync_timeout = DEFAULT_SHELL_TIMEOUT;
+char globalbuffer[MAX_SHELL_CMD_LENTH];
+
+/* Wait for process termination.
+ * This function returns immediately if the child has
+ * already exited (zombie process)
+ */
+static void
+sigchld_handler(int s)
+{
+ UNUSED_PARAMETER(s);
+
+ while (waitpid(-1, NULL, WNOHANG) > 0);
+}
+
+/* Create a main directory \tmp\RWL\ for the shell response files */
+int
+rwl_create_dir(void)
+{
+ if (mkdir(SHELL_RESP_PATH, FILE_PERMISSION) < 0) {
+ if (errno != EEXIST)
+ return BCME_ERROR;
+ }
+
+ return SUCCESS;
+}
+
+/* Main function for shell command execution */
+int
+remote_shell_execute(char* buf_ptr, void *wl)
+{
+ char *async_cmd_flag;
+ int msg_len;
+
+ /* Check for the "%" token in the buffer from client
+ * If "%" token is present, execute asynchronous process
+ * else, execute synchronous shell process
+ */
+ async_cmd_flag = strstr((char*)buf_ptr, ASYNC_SHELL_CHAR);
+
+ if ((async_cmd_flag != NULL) && (!strcmp(async_cmd_flag, ASYNC_SHELL_CHAR))) {
+ g_shellsync_pid = SHELL_ASYNCCMD_ID;
+ msg_len = remote_shell_async_exec(buf_ptr);
+ }
+ else {
+ msg_len = remote_shell_sync_exec(buf_ptr, wl);
+ strcpy(buf_ptr, globalbuffer);
+ }
+ return msg_len;
+}
+
+/* Function to get the shell response from the file */
+int
+remote_shell_async_get_resp(char* shell_fname, char* buf_ptr, int msg_len)
+{
+ int sts = 0;
+ FILE *shell_fpt;
+
+ shell_fpt = fopen(shell_fname, "rb");
+
+ if (shell_fpt == NULL) {
+ DPRINT_ERR(ERR, "\nShell Cmd:File open error\n");
+ return sts;
+ }
+
+ /* If there is any response from the shell, Read the file and
+ * update the buffer for the shell response
+ * else Just send the return value of the command executed
+ */
+ if (g_shellsync_pid != SHELL_ASYNCCMD_ID) {
+ if (msg_len)
+ sts = fread(buf_ptr, sizeof(char), msg_len, shell_fpt);
+ fscanf(shell_fpt, "%2x", &sts);
+ }
+ else
+ sts = fread(buf_ptr, sizeof(char), MAX_SHELL_CMD_LENTH, shell_fpt);
+
+ fclose(shell_fpt);
+
+ remove(shell_fname);
+
+ DPRINT_DBG(OUTPUT, "\n Resp buff from shell cmdis %s\n", buf_ptr);
+
+ return sts;
+}
+
+/*
+ * Function to get the shell response length
+ * by opening the file containing the shell response
+ * and get the total file size.
+ * For a given input file name it returns File size.
+ */
+static int
+rwl_get_file_size(char *file_name)
+{
+ FILE *shell_fpt;
+ int filesize = 0;
+
+ shell_fpt = fopen(file_name, "rb");
+
+ if (shell_fpt == NULL) {
+ DPRINT_DBG(OUTPUT, "\nShell Cmd:File open error\n");
+ return filesize;
+ }
+
+ /* obtain file size */
+ if (fseek(shell_fpt, 0, SEEK_END) < 0)
+ return filesize;
+
+ filesize = ftell(shell_fpt);
+ fclose(shell_fpt);
+
+ return filesize;
+}
+
+/*
+ * Function for executing asynchronous shell comamnd
+ * Stores the results in async temp file and returns the PID
+ */
+static int
+remote_shell_async_exec(char *buf_ptr)
+{
+ int PID_val = 0, val, msg_len, sts;
+ FILE *fpt;
+ int async_count = 0; /* counter needs to be initialized */
+ struct sigaction sa;
+ char pid_search_cmd[MAX_PID_CMD_LENGTH];
+ char pid_resp_buf[MAX_PID_RESP_LENTH];
+ char temp_async_file_name[MAX_ASYNC_FILE_LENGTH];
+ pid_t pid;
+ char *pid_token, next_pid[PID_TOKEN_SIZE][PID_TOKEN_SIZE];
+ struct utsname name;
+
+ /* Call the signal handler for reaping defunct or zombie process */
+ sa.sa_handler = sigchld_handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ if (sigaction(SIGCHLD, &sa, NULL) == -1) {
+ perror("sigaction:");
+ }
+
+ /* Store the async file name if that async process is not killed.
+ * Async file name: async_temp_0...5
+ */
+ for (val = 0; val < MAX_SHELL_ASYNC_RESP; val++) {
+ if (g_async_resp[val].PID > 0) {
+ async_count++;
+ } else {
+ sprintf(g_async_resp[val].file_name, "%s%d", "async_temp_", val);
+ break;
+ }
+ }
+ sprintf(temp_async_file_name, "%s%s", SHELL_RESP_PATH,
+ g_async_resp[val].file_name);
+
+ DPRINT_DBG(OUTPUT, "\nasync_count:%d\n", async_count);
+ if (async_count >= MAX_SHELL_ASYNC_RESP) {
+ sprintf(buf_ptr, "\n%s\n", "Exceeded max async process forking");
+ return BCME_ERROR;
+ }
+
+ /* Open a child process. The fork will return the PID of the child process
+ * (i.e) defunct process PID in parent's thread of execution. Zero is returned
+ * for child's thread of execution.
+ */
+ if ((pid = fork()) == 0) {
+ /* Redirect the async process output to the async file
+ * Then after the client executes the kill command for that
+ * async process, the file will give the status of async process
+ */
+ strtok(buf_ptr, ASYNC_SHELL_CHAR); /* Remove % character from the command buf */
+ uname(&name);
+ /*
+ * Checking for mips architecture
+ * different command for mips and x86
+ */
+ if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0) {
+ strcat(buf_ptr, "&> "); /* buf_ptr is now "ping 127.0.0.1&> " */
+ strcat(buf_ptr, temp_async_file_name); /* Add path \tmp\RWL\async_temp_* */
+ }
+ else {
+ strcat(buf_ptr, " > "); /* buf_ptr is now "ping 127.0.0.1> " */
+ strcat(buf_ptr, temp_async_file_name); /* Add path \tmp\RWL\async_temp_* */
+ strcat(buf_ptr, " 2>&1 &");
+ }
+ if ((sts = execl(SH_PATH, "sh", "-c", buf_ptr, NULL)) == -1) {
+ sprintf(buf_ptr, "%s\n", "Not able to execute shell cmd");
+ return BCME_ERROR;
+ }
+ exit(0);
+ } /* end of fork */
+
+ if (pid < 0) {
+ perror("\nFork error:");
+ sprintf(buf_ptr, "%s\n", "Forking async process failed");
+ return BCME_ERROR;
+ }
+
+ /* Find the PID of the running process (for ex: ping)
+ * pidof -s options returns latest PID of the command.
+ */
+ strtok(buf_ptr, " ");
+
+ uname(&name);
+ /* Checking for mips architecture */
+ if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0)
+ sprintf(pid_search_cmd, "pidof -s %s", buf_ptr);
+ else
+ sprintf(pid_search_cmd, "pidof %s", buf_ptr);
+
+ sleep(1);
+
+ /* Execute the command e.g "pidof ping" */
+ if ((fpt = popen(pid_search_cmd, "r")) == NULL) {
+ sprintf(buf_ptr, "%s\n", "Can't return PID");
+ return BCME_ERROR;
+ }
+
+ /* Get the PID and copy the PID in buf_ptr to send to the client */
+ fgets(pid_resp_buf, sizeof(pid_resp_buf), fpt);
+
+ /* Checking for mips architecture */
+ if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0) {
+ PID_val = atoi(pid_resp_buf);
+ }
+ else {
+ /* code to extract the correct PID */
+ pid_token = strtok_r(pid_resp_buf, " ", (char **)next_pid);
+ /* the pid buffer will terminate with a '\n' */
+ while (pid_token != NULL && *pid_token != '\n') {
+ PID_val = atoi(pid_token);
+ pid_token = strtok_r(NULL, " ", (char **)next_pid);
+ }
+ }
+ if (PID_val == 0) {
+ msg_len = rwl_get_file_size(temp_async_file_name);
+ remote_shell_async_get_resp(temp_async_file_name, buf_ptr, msg_len);
+
+ } else {
+ g_async_resp[val].PID = PID_val;
+ /* Update PID value in buffer to send it to client */
+ sprintf(buf_ptr, "%d", PID_val);
+ msg_len = strlen(buf_ptr);
+ }
+
+ pclose(fpt);
+ /* In async case, the PID value will be copied to the input buffer only
+ * and there is no need of getting the response from the file. So return
+ * value can be -1.
+ */
+ return msg_len;
+}
+
+/* Process for 'kill' command.
+ * Kill command can also be used from the client to get the
+ * result of asynchronous command and actually kill the mentioned process
+ */
+static int
+remote_kill_cmd_exec(char *cmd_buf_ptr)
+{
+ char file_name[MAX_ASYNC_FILE_LENGTH];
+ int PID_val = 0, val, msg_len;
+ FILE *fpt;
+ char *pid_token, next_pid[PID_TOKEN_SIZE][PID_TOKEN_SIZE];
+
+ system(cmd_buf_ptr);
+
+ /* Parse the PID val from the kill command.
+ */
+ pid_token = strtok_r(cmd_buf_ptr, " ", (char **)next_pid);
+ while (pid_token != NULL && *pid_token != '\n') {
+ /* to extract the PID from the kill command */
+ PID_val = atoi(pid_token);
+ pid_token = strtok_r(NULL, " ", (char **)next_pid);
+ }
+
+ /* Check for the matching PID from the async structure and
+ * give the last 256 bytes statistics of the async process
+ * that was running
+ */
+ for (val = 0; val < MAX_SHELL_ASYNC_RESP; ++val) {
+ if (g_async_resp[val].PID == PID_val) {
+ /* We found a match here. Hence get the response now from the
+ * corresponding async response file
+ */
+ sprintf(file_name, "%s%s", SHELL_RESP_PATH, g_async_resp[val].file_name);
+ msg_len = rwl_get_file_size(file_name);
+ if (msg_len > 0) {
+ if ((fpt = fopen(file_name, "rb")) == NULL) {
+ DPRINT_DBG(OUTPUT, "\nShell Cmd:File open error\n");
+ return BCME_ERROR;
+ }
+
+ if (fseek(fpt, 0, SEEK_SET) < 0) {
+ fclose(fpt);
+ return BCME_ERROR;
+ }
+
+ if (fread(cmd_buf_ptr, sizeof(char), MAX_SHELL_CMD_LENTH,
+ fpt) <= 0) {
+ sprintf(cmd_buf_ptr, "%s\n", "Shell Resp:Reading error");
+ fclose(fpt);
+ return BCME_ERROR;
+ }
+
+ fclose(fpt);
+ }
+ else
+ sprintf(cmd_buf_ptr, "ed %d: No Response\n", PID_val);
+ remove(g_async_resp[val].file_name);
+
+ g_async_resp[val].PID = 0;
+ break;
+ }
+ }
+ return MAX_SHELL_CMD_LENTH;
+}
+
+/* Handle --timeout command line option for linux servers */
+int
+shell_timeout_cmd(char *cmd_buf_ptr, char *sync_file_name)
+{
+ char *token1, *token2, *nexttoken;
+ FILE* fp;
+ int msg_len;
+
+ token1 = strtok_r(cmd_buf_ptr, "--timeout ", &nexttoken);
+ if (token1)
+ token2 = strtok_r(NULL, token1, &nexttoken);
+ if (token1 == NULL || atoi(token1) <= 0 || token2 == NULL) {
+ fp = fopen(sync_file_name, "w+");
+ fprintf(fp, "Usage: ./wl --<transport> <ip/mac> sh"
+ "--timeout <timeout value> <shell command>\n");
+ fprintf(fp, "Eg: ./wl --socket 172.22.65.226 sh --timeout 15 ls\n");
+ fflush(fp);
+ msg_len = rwl_get_file_size(sync_file_name);
+ strcpy(cmd_buf_ptr, sync_file_name);
+ fclose(fp);
+ strcpy(globalbuffer, sync_file_name);
+ printf("Fix timeout problem in socket!!!!!\n");
+ return msg_len;
+ }
+ else
+ g_shellsync_timeout = atoi(token1);
+ return BCME_OK;
+}
+
+/* Handle synchronous shell commands here */
+static int
+remote_shell_sync_exec(char *cmd_buf_ptr, void *wl)
+{
+ char *kill_cmd_token;
+ char sync_file_name[] = TEMPLATE;
+ int fd, msg_len;
+ char cmd[(strlen(cmd_buf_ptr) + 1)];
+ int pid, status, pid_final;
+ char buf[SHELL_RESP_SIZE], cmd_find_lastpid[PID_SEARCH_CMD_SIZE];
+ int nbytes = 0;
+ int child_status;
+ static int sent_once = 0;
+ struct utsname name;
+ FILE *fpt;
+
+ /* Default Size of Return Value of the shell command is 2bytes */
+
+ kill_cmd_token = strstr(cmd_buf_ptr, "kill");
+
+ /* Synchronous Kill command processing is handled separately */
+ if (kill_cmd_token != NULL) {
+ msg_len = remote_kill_cmd_exec(cmd_buf_ptr);
+ remote_tx_response(wl, cmd_buf_ptr, msg_len);
+ return 0;
+ }
+
+
+ /* Process synchronous command other than kill command */
+ if ((fd = mkstemp(sync_file_name)) < 0) {
+ perror("mkstemp failed");
+ DPRINT_ERR(ERR, "\n errno:%d\n", errno);
+ sprintf(cmd_buf_ptr, "%s\n", "mkstemp failed");
+ return BCME_ERROR;
+ }
+
+ close(fd);
+
+ strcpy(cmd, cmd_buf_ptr);
+ /* Synchronous timeout command processing is handled separately */
+ if (strstr(cmd_buf_ptr, "--timeout") != NULL) {
+ if ((msg_len = shell_timeout_cmd (cmd, sync_file_name) > 0)) {
+ /* Signal end of command output */
+ g_rem_ptr->msg.len = 0;
+ g_rem_ptr->msg.cmd = g_return_stat;
+ remote_tx_response(wl, NULL, 0);
+ return msg_len;
+ } else {
+ /* Parse out --timeout <val> since command is successful
+ * point buffer to the shell command
+ */
+ strcpy(cmd, cmd_buf_ptr);
+ strtok_r(cmd, " ", &cmd_buf_ptr);
+ strcpy(cmd, cmd_buf_ptr);
+ strtok_r(cmd, " ", &cmd_buf_ptr);
+ }
+ }
+
+ /* Schedule an ALARM in case of timeout value of SHELL_TIMEOUT seconds */
+ /* Defalut time out only in case of Non socket transport */
+ alarm(g_shellsync_timeout);
+ /* registering the relevant signals to handle end of child process,
+ * the ctrl+c event on the server side and the kill command on the
+ * server process
+ */
+ signal(SIGCHLD, rwl_chld_handler);
+ signal(SIGINT, handle_ctrlc);
+ signal(SIGTERM, handle_ctrlc);
+
+ /* Set g_sig_chld before forking */
+ g_sig_chld = 1;
+
+ if (strcmp("reboot", cmd_buf_ptr) == 0) { /* reboot command */
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, REBOOT_MSG, sizeof(REBOOT_MSG));
+ remote_tx_response(wl, buf, 0);
+
+ /* Signal end of command output */
+ g_rem_ptr->msg.len = 0;
+ g_rem_ptr->msg.cmd = 0;
+ remote_tx_response(wl, NULL, 0);
+ sleep(1);
+
+ /* Clean up the temp file */
+ remove(sync_file_name);
+ }
+
+ if ((pid = fork()) == 0) {
+ close(STDOUT_FILENO);
+ fd = open(sync_file_name, O_WRONLY|O_SYNC);
+ /* Redirect stdin to dev/null. This handles un usual commands like
+ * sh cat from the client side
+ */
+ close(STDIN_FILENO);
+ open("/dev/null", O_RDONLY);
+ close(STDERR_FILENO);
+ fcntl(fd, F_DUPFD, STDERR_FILENO);
+ if ((status = execl(SH_PATH, "sh", "-c", cmd_buf_ptr, NULL)) == -1) {
+ perror("Exec error");
+
+ }
+ } /* end of fork */
+
+ g_shellsync_pid = pid;
+ /* The g_return_stat is being set for short commands */
+ waitpid(g_shellsync_pid, &child_status, WNOHANG);
+ if (WIFEXITED(child_status))
+ g_return_stat = WEXITSTATUS(child_status);
+ else
+ g_return_stat = 1;
+
+ /* Read file in the interim from a temp file and send back the results */
+ fd = open(sync_file_name, O_RDONLY|O_SYNC);
+
+ while (1) {
+ /* read file in the interim and send back the results */
+ nbytes = read(fd, buf, SHELL_RESP_SIZE);
+ g_rem_ptr->msg.len = nbytes;
+ if (nbytes > 0) {
+ remote_tx_response(wl, buf, 0);
+#ifdef RWL_SERIAL
+ /* usleep introduced for flooding of data over serial port */
+ usleep(1);
+#endif
+ }
+ if (get_ctrlc_header(wl) >= 0) {
+ if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG) {
+ uname(&name);
+ /* Checking for mips architecture
+ * The mips machine responds differently to
+ * execl command. so the pid is incremented
+ * to kill the right command.
+ */
+ if (strncmp(name.machine, "mips", sizeof(name.machine)) == 0)
+ pid++;
+ if (strncmp(name.machine, "armv5tel", sizeof(name.machine)) == 0) {
+ snprintf(cmd_find_lastpid, sizeof(cmd_find_lastpid),
+ "ps | awk \'PRINT $1\' | tail -n 1");
+ if ((fpt = popen(cmd_find_lastpid, "r")) == NULL) {
+ sprintf(buf, "%s\n", "Can't return PID");
+ return BCME_ERROR;
+ }
+ fgets(cmd_find_lastpid, sizeof(cmd_find_lastpid), fpt);
+ pid_final = atoi(cmd_find_lastpid);
+ while (pid <= pid_final) {
+ kill(pid, SIGKILL);
+ pid++;
+ }
+ pclose(fpt);
+ }
+ else {
+ kill(pid, SIGKILL);
+ }
+ break;
+ }
+ }
+ if (get_ctrlc_header(wl) >= 0) {
+ if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG) {
+ uname(&name);
+ /* Checking for mips architecture
+ * The mips machine responds differently to
+ * execl command. so the pid is incremented
+ * to kill the right command.
+ */
+ if (strncmp(name.machine, "mips", sizeof(name.machine)) == 0) {
+ pid++;
+ kill(pid, SIGKILL);
+ }
+ /* Checking for arm architecture
+ * The multiple commands would not work
+ * for ctrl+C. So we kill the processes
+ * spawned after the parent. This method has
+ * its own limitations but the busybox in pxa
+ * doesnot have many options to implement it better
+ */
+ else {
+ if (strncmp(name.machine, "armv5tel",
+ sizeof(name.machine)) == 0) {
+ /* The command below is used to get the
+ * PIDs and they are killed
+ */
+ snprintf(cmd_find_lastpid,
+ sizeof(cmd_find_lastpid),
+ "ps | awk \'PRINT $1\' | tail -n 1");
+ if ((fpt = popen(cmd_find_lastpid, "r")) == NULL) {
+ sprintf(buf, "%s\n", "Can't return PID");
+ return BCME_ERROR;
+ }
+ fgets(cmd_find_lastpid, sizeof(cmd_find_lastpid),
+ fpt);
+ pid_final = atoi(cmd_find_lastpid);
+ while (pid <= pid_final) {
+ kill(pid, SIGKILL);
+ pid++;
+ }
+ pclose(fpt);
+ }
+ /* In the case of x86, on receiving ctrl+C
+ * the child PIDs are obtained by searching
+ * the parent PID to obtain the PIDs of the
+ * and kill them
+ */
+ else {
+ while (pid != 0) {
+ /* The commad below is used to get the
+ * child PIDs by using their parent PID
+ */
+ snprintf(cmd_find_lastpid,
+ sizeof(cmd_find_lastpid),
+ "ps al | awk \"{ if (\\$4 == %d)"
+ " {print \\$3}}\"| head -n 1",
+ g_shellsync_pid);
+ if ((fpt = popen(cmd_find_lastpid, "r"))
+ == NULL) {
+ sprintf(buf, "%s\n",
+ "Can't return PID");
+ return BCME_ERROR;
+ }
+ fgets(cmd_find_lastpid,
+ sizeof(cmd_find_lastpid),
+ fpt);
+ pid = atoi(cmd_find_lastpid);
+ if (pid == 0)
+ kill(g_shellsync_pid, SIGKILL);
+ else
+ kill(pid, SIGKILL);
+ pclose(fpt);
+ }
+ }
+ }
+ break;
+ }
+ }
+ if (set_ctrlc == 1) {
+ g_rem_ptr->msg.len = 0;
+ g_rem_ptr->msg.cmd = g_return_stat;
+ remote_tx_response(wl, NULL, g_return_stat);
+ unlink(sync_file_name);
+ kill(0, SIGKILL);
+ }
+ /* It is possible that the child would have exited
+ * However we did not get a chance to read the file
+ * In this case go once again and check the file
+ */
+ if (!sent_once && !g_sig_chld) {
+ sent_once = 1;
+ continue;
+ }
+
+ if (!(g_sig_chld || nbytes))
+ break;
+ }
+ wait(NULL);
+ close(fd);
+
+ /* Signal end of command output */
+ g_rem_ptr->msg.len = 0;
+ g_rem_ptr->msg.cmd = g_return_stat;
+
+ remote_tx_response(wl, NULL, g_return_stat);
+ /* Cancel the time out alarm if any */
+ alarm(0);
+ sent_once = 0;
+ /* Clean up the temp file */
+ unlink(sync_file_name);
+ g_shellsync_timeout = DEFAULT_SHELL_TIMEOUT;
+ signal(SIGINT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+
+ return BCME_OK;
+}
diff --git a/wl/src/wl/exe/wlu.c b/wl/src/wl/exe/wlu.c
new file mode 100644
index 0000000..a4970fd
--- /dev/null
+++ b/wl/src/wl/exe/wlu.c
@@ -0,0 +1,27474 @@
+/*
+ * Common code for wl command-line swiss-army-knife utility
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu.c 663042 2016-11-30 13:48:19Z $
+ */
+
+
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+#include <wlioctl.h>
+#include <wlioctl_utils.h>
+
+#if !defined(TARGETOS_nucleus)
+#define CLMDOWNLOAD
+#endif
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <typedefs.h>
+#include <epivers.h>
+#include <proto/ethernet.h>
+#include <proto/802.11.h>
+#include <proto/802.1d.h>
+#include <proto/802.11e.h>
+#include <proto/wpa.h>
+#include <proto/bcmip.h>
+#include <proto/wps.h>
+
+#include <bcmwifi_rates.h>
+#include "wlu_rates_matrix.h"
+#include <rte_ioctl.h>
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmwifi_channels.h>
+#include <bcmsrom_fmt.h>
+#include <bcmsrom_tbl.h>
+#include "wlu_common.h"
+#include "wlu.h"
+#include <bcmcdc.h>
+#if defined(linux)
+#ifndef TARGETENV_android
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#include <time.h>
+#include <sched.h>
+#define TIME_STR_SZ 100 /* string buffer size for timestamp formatting */
+#endif /* linux */
+#if defined(WLBSSLOAD_REPORT) && defined(linux)
+#include <sys/time.h>
+#endif /* defined(WLBSSLOAD_REPORT) && defined(linux) */
+
+#ifdef LINUX
+#include <inttypes.h>
+#endif
+#include <miniopt.h>
+#include <errno.h>
+
+#if defined SERDOWNLOAD || defined CLMDOWNLOAD
+#include <sys/stat.h>
+#include <trxhdr.h>
+#ifdef SERDOWNLOAD
+#include <usbrdl.h>
+#endif
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef WIN32
+#include <fcntl.h>
+#endif /* WIN32 */
+#endif /* SERDOWNLOAD || defined CLMDOWNLOAD */
+
+#if LCNCONF || SSLPNCONF
+#define MAX_CHUNK_LEN 1456 /* 8 * 7 * 26 */
+#else
+#define MAX_CHUNK_LEN 1408 /* 8 * 8 * 22 */
+#endif
+
+#include <bcm_mpool_pub.h>
+#include <proto/bcmipv6.h>
+
+#define EVENT_LOG_DUMPER
+#include <proto/event_log_tag.h>
+
+#include <sdiovar.h>
+
+#include "wlu_subcounters.h"
+
+/* For backwards compatibility, the absense of the define 'NO_FILESYSTEM_SUPPORT'
+ * implies that a filesystem is supported.
+ */
+#if !defined(BWL_NO_FILESYSTEM_SUPPORT)
+#define BWL_FILESYSTEM_SUPPORT
+#endif
+
+#if defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION >= 0x00020000)
+extern int wlu_efi_stat(char *filename, struct stat *filest);
+extern long wlu_efi_ftell(void *fp);
+extern int wlu_efi_fseek(void *fp, long offset, int whence);
+extern size_t wlu_efi_fwrite(void *buf, size_t size, size_t nmemb, void *fp);
+extern size_t wlu_efi_fread(void *buf, size_t size, size_t nmemb, void *fp);
+extern void wlu_efi_fclose(void *fp);
+extern void * wlu_efi_fopen(char *filename, char *mode);
+
+#define fopen(filename, mode) (FILE *)wlu_efi_fopen(filename, mode)
+#define fread(buf, size, nmemb, fp) wlu_efi_fread(buf, size, nmemb, fp)
+#define fwrite(buf, size, nmemb, fp) wlu_efi_fwrite(buf, size, nmemb, fp)
+#define fseek(fp, offset, origin) wlu_efi_fseek(fp, offset, origin)
+#define ftell(fp) wlu_efi_ftell(fp)
+#define stat(fname, filest) wlu_efi_stat(fname, (struct stat *)(filest))
+#define fclose(fp) wlu_efi_fclose(fp)
+#ifdef stderr
+#undef stderr
+#define stderr stdout
+#endif
+#endif /* defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION >= 0x00020000) */
+
+const char blob_magic_string[] = {'B', 'L', 'O', 'B'};
+
+cmd_func_t wl_int, wl_buf;
+
+const ofdm_rates_t ofdm_rates[] = { /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
+ 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c };
+
+/* ifdef protection since wlc_event_names[] only used under ifdef linux */
+#ifdef linux
+
+#define NAME_ENTRY(x) {x, #x}
+
+static const wlu_name_entry_t wlc_event_names[] = {
+ NAME_ENTRY(WLC_E_SET_SSID),
+ NAME_ENTRY(WLC_E_JOIN),
+ NAME_ENTRY(WLC_E_START),
+ NAME_ENTRY(WLC_E_AUTH),
+ NAME_ENTRY(WLC_E_AUTH_IND),
+ NAME_ENTRY(WLC_E_DEAUTH),
+ NAME_ENTRY(WLC_E_DEAUTH_IND),
+ NAME_ENTRY(WLC_E_ASSOC),
+ NAME_ENTRY(WLC_E_ASSOC_IND),
+ NAME_ENTRY(WLC_E_REASSOC),
+ NAME_ENTRY(WLC_E_REASSOC_IND),
+ NAME_ENTRY(WLC_E_DISASSOC),
+ NAME_ENTRY(WLC_E_DISASSOC_IND),
+ NAME_ENTRY(WLC_E_QUIET_START),
+ NAME_ENTRY(WLC_E_QUIET_END),
+ NAME_ENTRY(WLC_E_BEACON_RX),
+ NAME_ENTRY(WLC_E_LINK),
+ NAME_ENTRY(WLC_E_MIC_ERROR),
+ NAME_ENTRY(WLC_E_NDIS_LINK),
+ NAME_ENTRY(WLC_E_ROAM),
+ NAME_ENTRY(WLC_E_TXFAIL),
+ NAME_ENTRY(WLC_E_PMKID_CACHE),
+ NAME_ENTRY(WLC_E_RETROGRADE_TSF),
+ NAME_ENTRY(WLC_E_PRUNE),
+ NAME_ENTRY(WLC_E_AUTOAUTH),
+ NAME_ENTRY(WLC_E_EAPOL_MSG),
+ NAME_ENTRY(WLC_E_SCAN_COMPLETE),
+ NAME_ENTRY(WLC_E_ADDTS_IND),
+ NAME_ENTRY(WLC_E_DELTS_IND),
+ NAME_ENTRY(WLC_E_BCNSENT_IND),
+ NAME_ENTRY(WLC_E_BCNRX_MSG),
+ NAME_ENTRY(WLC_E_BCNLOST_MSG),
+ NAME_ENTRY(WLC_E_ROAM_PREP),
+ NAME_ENTRY(WLC_E_PFN_NET_FOUND),
+ NAME_ENTRY(WLC_E_PFN_NET_LOST),
+ NAME_ENTRY(WLC_E_RESET_COMPLETE),
+ NAME_ENTRY(WLC_E_JOIN_START),
+ NAME_ENTRY(WLC_E_ROAM_START),
+ NAME_ENTRY(WLC_E_ASSOC_START),
+ NAME_ENTRY(WLC_E_IBSS_ASSOC),
+ NAME_ENTRY(WLC_E_RADIO),
+ NAME_ENTRY(WLC_E_PSM_WATCHDOG),
+ NAME_ENTRY(WLC_E_PROBREQ_MSG),
+ NAME_ENTRY(WLC_E_SCAN_CONFIRM_IND),
+ NAME_ENTRY(WLC_E_PSK_SUP),
+ NAME_ENTRY(WLC_E_COUNTRY_CODE_CHANGED),
+ NAME_ENTRY(WLC_E_EXCEEDED_MEDIUM_TIME),
+ NAME_ENTRY(WLC_E_ICV_ERROR),
+ NAME_ENTRY(WLC_E_UNICAST_DECODE_ERROR),
+ NAME_ENTRY(WLC_E_MULTICAST_DECODE_ERROR),
+ NAME_ENTRY(WLC_E_TRACE),
+ NAME_ENTRY(WLC_E_IF),
+ NAME_ENTRY(WLC_E_P2P_DISC_LISTEN_COMPLETE),
+ NAME_ENTRY(WLC_E_RSSI),
+ NAME_ENTRY(WLC_E_PFN_SCAN_COMPLETE),
+ NAME_ENTRY(WLC_E_EXTLOG_MSG),
+ NAME_ENTRY(WLC_E_ACTION_FRAME),
+ NAME_ENTRY(WLC_E_ACTION_FRAME_COMPLETE),
+ NAME_ENTRY(WLC_E_PRE_ASSOC_IND),
+ NAME_ENTRY(WLC_E_PRE_REASSOC_IND),
+ NAME_ENTRY(WLC_E_CHANNEL_ADOPTED),
+ NAME_ENTRY(WLC_E_AP_STARTED),
+ NAME_ENTRY(WLC_E_DFS_AP_STOP),
+ NAME_ENTRY(WLC_E_DFS_AP_RESUME),
+ NAME_ENTRY(WLC_E_WAI_STA_EVENT),
+ NAME_ENTRY(WLC_E_WAI_MSG),
+ NAME_ENTRY(WLC_E_ESCAN_RESULT),
+ NAME_ENTRY(WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE),
+ NAME_ENTRY(WLC_E_PROBRESP_MSG),
+ NAME_ENTRY(WLC_E_P2P_PROBREQ_MSG),
+ NAME_ENTRY(WLC_E_DCS_REQUEST),
+ NAME_ENTRY(WLC_E_FIFO_CREDIT_MAP),
+ NAME_ENTRY(WLC_E_ACTION_FRAME_RX),
+ NAME_ENTRY(WLC_E_WAKE_EVENT),
+ NAME_ENTRY(WLC_E_RM_COMPLETE),
+ NAME_ENTRY(WLC_E_HTSFSYNC),
+ NAME_ENTRY(WLC_E_OVERLAY_REQ),
+ NAME_ENTRY(WLC_E_CSA_COMPLETE_IND),
+ NAME_ENTRY(WLC_E_EXCESS_PM_WAKE_EVENT),
+ NAME_ENTRY(WLC_E_PFN_SCAN_NONE),
+ NAME_ENTRY(WLC_E_PFN_SCAN_ALLGONE),
+ NAME_ENTRY(WLC_E_GTK_PLUMBED),
+ NAME_ENTRY(WLC_E_ASSOC_IND_NDIS),
+ NAME_ENTRY(WLC_E_REASSOC_IND_NDIS),
+ NAME_ENTRY(WLC_E_ASSOC_REQ_IE),
+ NAME_ENTRY(WLC_E_ASSOC_RESP_IE),
+ { 0, NULL}
+};
+#endif /* linux */
+
+static cmd_func_t wl_print_deprecate;
+static cmd_func_t wl_rssi, wl_gmode;
+static cmd_func_t wlu_dump, wlu_dump_clr, wlu_mempool, wlu_srdump, wlu_srvar;
+static cmd_func_t wlu_ciswrite, wlu_cisupdate, wlu_cisdump;
+static cmd_func_t wl_rate, wl_rate_mrate, wl_bss_max;
+static cmd_func_t wl_channel, wl_chanspec, wl_rclass, wl_dfs_ap_move, wl_sc_chan;
+static cmd_func_t wl_phy_vcore;
+static cmd_func_t wl_dfs_max_safe_tx;
+static cmd_func_t wl_radio, wl_version, wl_list, wl_band, wl_bandlist, wl_phylist;
+static cmd_func_t wl_join, wl_txpwr, wl_country;
+static cmd_func_t wl_out, wl_txpwr1, wl_country_ie_override, wl_echo;
+static cmd_func_t wl_radar_status, wl_clear_radar_status;
+static cmd_func_t wl_radar_sc_status;
+static cmd_func_t wl_get_pktcnt, wl_upgrade;
+static cmd_func_t wl_default_rateset;
+static cmd_func_t wl_rateset, wl_txbf_rateset;
+static cmd_func_t wl_dfs_status;
+static cmd_func_t wl_dfs_status_all;
+static cmd_func_t wl_get_txpwr_limit, wl_get_current_power;
+static cmd_func_t wl_get_txpwr_target_max, wl_get_chanspec_txpwr_max;
+static cmd_func_t wl_var_getint;
+static cmd_func_t wl_nvdump, wl_nvget, wl_nvset, wl_chan_info;
+static cmd_func_t wl_wme_ac_req, wl_add_ie, wl_del_ie, _wl_list_ie;
+static cmd_func_t wl_wme_apsd_sta, wl_wme_dp, wl_lifetime;
+static cmd_func_t wl_rand;
+static cmd_func_t wl_wlc_ver;
+static cmd_func_t wl_assoc_info, wl_wme_counters;
+static cmd_func_t wl_rxfifo_counters;
+static cmd_func_t wl_eventbitvec, wl_bitvecext;
+static cmd_func_t wl_auto_channel_sel;
+static cmd_func_t wl_msglevel, wl_plcphdr, wl_macreg, wl_band_elm;
+static cmd_func_t wl_rateparam, wl_status, wl_spect;
+static cmd_func_t wl_sup_rateset, wl_scan, wl_send_csa, wl_iscan, wl_escan;
+static cmd_func_t wl_roamparms, wl_roam_prof;
+#ifdef WLRCC
+static cmd_func_t wl_roamchannels;
+#endif /* WLRCC */
+static cmd_func_t wl_dump_chanlist, wl_measure_req, wl_send_quiet;
+static cmd_func_t wl_pm_mute_tx;
+static cmd_func_t wl_dump_chanspecs, wl_dump_chanspecs_defset;
+static cmd_func_t wl_wsec;
+static cmd_func_t wl_channels_in_country;
+static cmd_func_t wl_wpa_auth, wl_deauth_rc, wl_bssid, wl_smfstats;
+static cmd_func_t wl_set_pmk;
+static cmd_func_t wl_rm_request, wl_rm_report;
+static cmd_func_t wl_join_pref, wl_assoc_pref;
+static cmd_func_t wl_dump_networks, wl_revinfo, wl_iov_pktqlog_params;
+static cmd_func_t wl_varstr;
+static cmd_func_t wl_winver;
+
+#if defined(linux)
+static cmd_func_t wl_escan_event_check;
+static cmd_func_t wl_escanresults;
+static cmd_func_t wl_event_check;
+#endif /* linux */
+
+static cmd_func_t wl_hs20_ie;
+static cmd_func_t wl_reassoc;
+
+static cmd_func_t wl_overlay;
+static cmd_func_t wl_pmkid_info;
+
+
+static void wl_rate_histo_print(wl_mac_ratehisto_res_t *rate_histo_res);
+static cmd_func_t wl_rate_histo;
+static cmd_func_t wl_mac_rate_histo;
+static cmd_func_t wme_tx_params;
+static cmd_func_t wme_maxbw_params;
+
+static cmd_func_t wl_actframe;
+static cmd_func_t wl_antsel;
+static cmd_func_t wl_txfifo_sz;
+
+static cmd_func_t wl_mcast_ar;
+
+static cmd_func_t wl_pwrstats;
+static cmd_func_t wl_memuse;
+
+int wl_seq_batch_in_client(bool enable);
+
+static cmd_func_t wl_antgain;
+static cmd_func_t wl_srchmem;
+static cmd_func_t wl_ptk_start;
+
+#ifdef CLMDOWNLOAD
+static cmd_func_t wl_clmload;
+static cmd_func_t wl_txcapload;
+static cmd_func_t wl_txcapctl;
+static cmd_func_t wl_txcapdump;
+#endif /* CLMDOWNLOAD */
+static cmd_func_t wl_calload;
+static cmd_func_t wl_caldump;
+
+#ifdef RWL_WIFI
+/* Function added to support RWL_WIFI Transport */
+static cmd_func_t wl_wifiserver;
+#endif
+
+static cmd_func_t wl_cca_get_stats;
+static cmd_func_t wl_txdelay_params;
+static cmd_func_t wl_intfer_params;
+
+static cmd_func_t wl_rpmt;
+static cmd_func_t wl_sarlimit;
+static cmd_func_t wl_ie;
+static cmd_func_t wl_ccode_info;
+
+
+#ifdef SERDOWNLOAD
+static cmd_func_t dhd_upload;
+int debug = 0;
+#endif
+static cmd_func_t wl_wds_ap_ifname;
+
+static cmd_func_t wl_staprio;
+static cmd_func_t wl_stamon_sta_config;
+static cmd_func_t wl_monitor_promisc_level;
+static cmd_func_t wl_bcnlenhist;
+static cmd_func_t wl_aibss_bcn_force_config;
+
+#ifdef SR_DEBUG
+static cmd_func_t wl_dump_pmu;
+#endif /* SR_DEBUG */
+
+#ifdef TBTT_OFFSET_STAT
+static cmd_func_t wl_tbtt_offset_stat;
+#endif /* TBTT_OFFSET_STAT */
+
+static cmd_func_t wl_bss_peer_info;
+static cmd_func_t wl_aibss_txfail_config;
+static cmd_func_t wl_setiproute;
+static cmd_func_t wl_desired_bssid;
+static cmd_func_t wl_interface_create_action;
+static cmd_func_t wl_interface_remove_action;
+static cmd_func_t wl_macdbg_pmac;
+static cmd_func_t wl_svmp_mem;
+static cmd_func_t wl_mu_rate;
+static cmd_func_t wl_mu_group;
+static cmd_func_t wl_mu_policy;
+#if defined(BCMDBG) || defined(BCMDBG_DUMP)
+static cmd_func_t wl_svmp_sampcol;
+#endif
+static cmd_func_t wl_macregx;
+static cmd_func_t wl_scanmac;
+cmd_func_t wl_hostip;
+cmd_func_t wl_hostipv6_extended;
+static cmd_func_t wl_hc;
+static cmd_func_t wl_wake_timer;
+
+static cmd_func_t wl_idauth;
+static cmd_func_t wl_netx_ifconfig;
+
+static int wl_idauth_config_set(void *wl, uint16 category, char **argv);
+static int wl_idauth_config_get(void *wl, uint16 category, char **argv);
+static int wl_idauth_dump_counters(void *wl, uint16 category, char **argv);
+static int wl_idauth_dump_peer_info(void *wl, uint16 category, char **argv);
+
+static int wlu_dump_phytbls(void *wl, char *dump_buf);
+static int8 wl_ppr_get_pwr(ppr_t* pprptr, reg_rate_index_t rate_idx, wl_tx_bw_t bw);
+static void wl_txpwr_array_row_print(ppr_t* pprptr, int8 channel_bandwidth,
+ reg_rate_index_t rate_idx);
+static void wl_txpwr_array_print(ppr_t* pprptr, int8 channel_bandwidth, bool verbose, bool is5G);
+static void wl_txpwr_ppr_print(ppr_t* pprptr, int vb, ppr_rate_type_t type,
+ clm_rate_group_id_t gid, int8 bw, reg_rate_index_t *rate_index, bool is5G);
+void wl_txpwr_ppr_print_row(const char* label, int8 chains, int8 bw, bool vb,
+ int8** rates, uint rate_index);
+void wl_txpwr_ppr_get_rateset(ppr_t* pprptr, ppr_rate_type_t type,
+ clm_rate_group_id_t gid, wl_tx_bw_t bw, int8* rateset);
+static int wl_array_check_val(int8 *pwr, uint count, int8 val);
+static int wl_parse_rateset(void *wl, wl_rateset_args_t* rs, char **argv);
+static void wl_print_vhtmcsset(uint16 *mcsset);
+static void dump_networks(char *buf);
+static void wl_dump_wpa_rsn_ies(uint8* cp, uint len);
+static void wl_rsn_ie_dump(bcm_tlv_t *ie);
+static void wl_dump_ext_cap(uint8* cp, uint len);
+static void wl_ext_cap_ie_dump(bcm_tlv_t* ext_cap_ie);
+static void free_cca_array(cca_congest_channel_req_t **favg, int favg_chan_elts);
+static int wl_print_dfs_status(wl_dfs_status_t *dfs_status);
+static int wl_print_dfs_sub_status(wl_dfs_sub_status_t *sub);
+static int wl_print_dfs_status_all(wl_dfs_status_all_t *dfs_status_all);
+static int wl_parse_txbf_rateset(wl_txbf_rateset_t *rs, char **argv);
+static void wl_print_txbf_mcsset(char *mcsset, char *prefix);
+static void wl_print_txbf_vhtmcsset(uint16 *mcsset, char *prefix);
+
+static cmd_func_t wl_power_sel_params;
+#if defined(BCMDBG) || defined(BCMDBG_DUMP)
+static cmd_func_t wl_dump_modesw_dyn_bwsw;
+#endif
+
+int wlu_get(void *wl, int cmd, void *buf, int len);
+int wlu_set(void *wl, int cmd, void *buf, int len);
+
+static cmd_func_t wl_modesw_timecal;
+static cmd_func_t wl_bcntrim_stats;
+static int fsize(void *fp);
+
+typedef struct wl_config_iovar_s wl_config_iovar_t;
+typedef struct nv_s nv_t;
+
+/* 802.11i/WPA RSN IE parsing utilities */
+typedef struct {
+ uint16 version;
+ wpa_suite_mcast_t *mcast;
+ wpa_suite_ucast_t *ucast;
+ wpa_suite_auth_key_mgmt_t *akm;
+ uint8 *capabilities;
+} rsn_parse_info_t;
+
+static int wl_rsn_ie_parse_info(uint8* buf, uint len, rsn_parse_info_t *rsn);
+static uint wl_rsn_ie_decode_cntrs(uint cntr_field);
+typedef void (wl_config_print_func_t)(wl_config_iovar_t *config_iovar,
+ wl_config_t *config);
+static void wl_bcm_config_print(wl_config_iovar_t *cfg_iovar, wl_config_t *cfg);
+static int wl_parse_assoc_params(char **argv, wl_assoc_params_t *params, bool *prescanned);
+static int wl_join_prescanned(void *wl, wl_join_params_t *join_params, uint *join_params_size);
+#define wl_parse_reassoc_params(argv, params) wl_parse_assoc_params(argv, \
+ (wl_assoc_params_t *)(params), NULL)
+
+static uint16 wl_qdbm_to_mw(int8 qdbm);
+static int8 wl_mw_to_qdbm(uint16 mw);
+
+static void wl_printrate(int val);
+static int wl_get_iscan(void *wl, char *buf, uint buf_len);
+int wlu_var_setbuf(void *wl, const char *iovar, void *param, int param_len);
+int wlu_iovar_get(void *wl, const char *iovar, void *outbuf, int len);
+int wlu_iovar_set(void *wl, const char *iovar, void *param, int paramlen);
+int wlu_iovar_getint(void *wl, const char *iovar, int *pval);
+int wlu_iovar_setint(void *wl, const char *iovar, int val);
+static int wl_bssiovar_mkbuf(const char *iovar, int bssidx, void *param,
+ int paramlen, void *bufptr, int buflen, int *perr);
+int wlu_bssiovar_setbuf(void* wl, const char *iovar, int bssidx,
+ void *param, int paramlen, void *bufptr, int buflen);
+static int wl_bssiovar_getbuf(void* wl, const char *iovar, int bssidx,
+ void *param, int paramlen, void *bufptr, int buflen);
+static int wl_bssiovar_set(void *wl, const char *iovar, int bssidx, void *param, int paramlen);
+int wlu_bssiovar_get(void *wl, const char *iovar, int bssidx, void *outbuf, int len);
+static int wl_bssiovar_setint(void *wl, const char *iovar, int bssidx, int val);
+static int wl_bssiovar_getint(void *wl, const char *iovar, int bssidx, int *pval);
+static int wl_vndr_ie(void *wl, const char *command, uint32 pktflag_ok, char **argv);
+static void wl_dump_ie_buf(vndr_ie_buf_t *ie_getbuf);
+static void wl_join_pref_print_ie(bcm_tlv_t *ie);
+static void wl_join_pref_print_akm(uint8* suite);
+static void wl_join_pref_print_cipher_suite(uint8* suite);
+
+static int wl_assertlog(void *wl, cmd_t *cmd, char **argv);
+static int wl_tsf(void *wl, cmd_t *cmd, char **argv);
+
+static cmd_func_t wl_scb_bs_data;
+
+static int wl_dfs_channel_forced(void *wl, cmd_t *cmd, char **argv);
+static int wl_event_log_set_init(void *wl, cmd_t *cmd, char **argv);
+static int wl_event_log_set_expand(void *wl, cmd_t *cmd, char **argv);
+static int wl_event_log_set_shrink(void *wl, cmd_t *cmd, char **argv);
+static int wl_event_log_tag_control(void *wl, cmd_t *cmd, char **argv);
+static int wl_event_log_get(void *wl, cmd_t *cmd, char **argv);
+static int wl_sleep_ret_ext(void *wl, cmd_t *cmd, char **argv);
+
+static cmd_func_t wl_pcie_bus_throughput_params;
+
+static cmd_func_t wl_phy_txpwrcap_tbl;
+static cmd_func_t wl_sim_pm;
+static cmd_func_t wl_utrace_capture;
+
+#ifdef ATE_BUILD
+static cmd_func_t wl_gpaio;
+#endif
+
+
+static cmd_func_t wl_nd_ra_limit_intv;
+
+static void dlystat_dump(txdelay_stats_t *txdelay_stats);
+static int wl_dlystats(void *wl, cmd_t *cmd, char **argv);
+static int wl_dlystats_clear(void *wl, cmd_t *cmd, char **argv);
+
+static int wl_get_tcmstbl_entry(void *wl, cmd_t *cmd, char **argv);
+
+char *ver2str(unsigned int vms, unsigned int vls);
+
+#define BCM_CONFIG_ARRAY_SIZE 10
+
+#define OUI_STR_SIZE 8 /* OUI string size */
+#define MAX_OUI_SIZE 3 /* MAX OUI size */
+#define MAX_BYTE_CHARS 2 /* MAX num chars */
+#define MAX_DATA_COLS 16 /* MAX data cols */
+
+#define RADIO_CORE_SYN (0x0 << 12)
+#define RADIO_CORE_TX0 (0x2 << 12)
+#define RADIO_CORE_TX1 (0x3 << 12)
+#define RADIO_CORE_RX0 (0x6 << 12)
+#define RADIO_CORE_RX1 (0x7 << 12)
+#define RADIO_CORE_CR0 (0x0 << 10)
+#define RADIO_CORE_CR1 (0x1 << 10)
+#define RADIO_CORE_CR2 (0x2 << 10)
+#define RADIO_CORE_ALL (0x3 << 10)
+#define RADIO_2069_CORE_CR0 (0x0 << 9)
+#define RADIO_2069_CORE_CR1 (0x1 << 9)
+#define RADIO_2069_CORE_CR2 (0x2 << 9)
+#define RADIO_2069_CORE_ALL (0x3 << 9)
+#define RADIO_2069_CORE_PLL (0x4 << 9)
+#define RADIO_2069_CORE_PLL0 (0x4 << 9)
+#define RADIO_2069_CORE_PLL1 (0x5 << 9)
+
+#define NUM_CHANSPECS_LIST_SIZE 110 /* chanspecs list size passed to driver */
+
+/* IOCtl version read from targeted driver */
+static int ioctl_version;
+
+/* 64 bits aligned allocation */
+static union {
+ char bufdata[WLC_IOCTL_MAXLEN];
+ uint64 alignme;
+} bufstruct_wlu;
+static char *buf = (char*) &bufstruct_wlu.bufdata;
+
+/* integer output format, default to signed integer */
+static uint8 int_fmt;
+
+/*
+ * Country names and abbreviations from ISO 3166
+ */
+typedef struct {
+ const char *name; /* Long name */
+ const char *abbrev; /* Abbreviation */
+} cntry_name_t;
+cntry_name_t cntry_names[]; /* At end of this file */
+
+struct nv_s {
+ char *name;
+ uint32 value;
+};
+
+struct wl_config_iovar_s {
+ char *iovar_name;
+ wl_config_print_func_t *pfunc;
+ nv_t params[BCM_CONFIG_ARRAY_SIZE];
+};
+
+typedef struct {
+ uint value;
+ const char *string;
+} monitor_promisc_level_msg_t;
+
+
+#define WL_SCAN_PARAMS_SSID_MAX 10
+
+#define RATE_2G_USAGE \
+"\tEither \"auto\", or a simple CCK/DSSS/OFDM rate value:\n" \
+"\t1 2 5.5 11 6 9 12 18 24 36 48 54\n\n" \
+"\tOr options to specify legacy, HT, or VHT rate:\n" \
+"\t-r R, --rate=R : legacy rate (CCK, DSSS, OFDM)\n" \
+"\t-h M, --ht=M : HT MCS index [0-23]\n" \
+"\t-v M[xS], --vht=M[xS] : VHT MCS index M [0-9],\n" \
+"\t : and optionally Nss S [1-8], eg. 5x2 is MCS=5, Nss=2\n" \
+"\t-c cM[sS] : VHT (c notation) MCS index M [0-9],\n" \
+"\t : and optionally Nss S [1-8], eg. c5s2 is MCS=5, Nss=2\n" \
+"\t-s S, --ss=S : VHT Nss [1-8], number of spatial streams, default 1.\n" \
+"\t : Only used with -v/--vht when MxS format is not used\n" \
+"\t-x T, --exp=T : Tx Expansion, number of tx chains (NTx) beyond the minimum\n" \
+"\t : required for the space-time-streams, exp = NTx - Nsts\n" \
+"\t--stbc : Use STBC expansion, otherwise no STBC\n" \
+"\t-l, --ldpc : Use LDPC encoding, otherwise no LDPC\n" \
+"\t-g, --sgi : SGI, Short Guard Interval, otherwise standard GI\n" \
+"\t-b, --bandwidth : transmit bandwidth MHz; 2.5, 5, 10, 20, 40, 80, 160"
+
+#define RATE_5G_USAGE \
+"\tEither \"auto\", or a simple OFDM rate value:\n" \
+"\t6 9 12 18 24 36 48 54\n\n" \
+"\tOr options to specify legacy OFDM, HT, or VHT rate:\n" \
+"\t-r R, --rate=R : legacy OFDM rate\n" \
+"\t-h M, --ht=M : HT MCS index [0-23]\n" \
+"\t-v M[xS], --vht=M[xS] : VHT MCS index M [0-9],\n" \
+"\t : and optionally Nss S [1-8], eg. 5x2 is MCS=5, Nss=2\n" \
+"\t-c cM[sS] : VHT (c notation) MCS index M [0-9],\n" \
+"\t : and optionally Nss S [1-8], eg. c5s2 is MCS=5, Nss=2\n" \
+"\t-s S, --ss=S : VHT Nss [1-8], number of spatial streams, default 1.\n" \
+"\t : Only used with -v/--vht when MxS format is not used\n" \
+"\t-x T, --exp=T : Tx Expansion, number of tx chains (NTx) beyond the minimum\n" \
+"\t : required for the space-time-streams, exp = NTx - Nsts\n" \
+"\t--stbc : Use STBC expansion, otherwise no STBC\n" \
+"\t-l, --ldpc : Use LDPC encoding, otherwise no LDPC\n" \
+"\t-g, --sgi : SGI, Short Guard Interval, otherwise standard GI\n" \
+"\t-b, --bandwidth : transmit bandwidth MHz; 2.5, 5, 10, 20, 40, 80, 160"
+
+#define TXBF_RATESET_USAGE \
+"Get rateset consisting of OFDM, HT and VHT rates, and Broadcom-to-Broadcom\n" \
+"\tgroup of OFDM, HT and VHT rates by issuing command with no arguments.\n" \
+"\tOFDM rates printed are in Mbps, and each Basic rate in OFDM list is marked\n" \
+"\tby (b) behind it. Example: full list of OFDM rates:\n" \
+"\t\t6(b) 9 12(b) 18 24(b) 36 48 54\n" \
+"\twhere 6, 12 and 24 are Basic rates.\n" \
+"\n" \
+"\tSet synopsis:\n" \
+"\t\twl txbf_rateset < [ofdm_rate_list] [options ...] >\n" \
+"\tOFDM rate specification does not need to mark Basic rates because Basic\n" \
+"\trates are automatically recognized.\n" \
+"\tOptions are processed in order; thus redundant instances of an option will\n" \
+"\tresult in only the last instance taking effect for that option.\n" \
+"\tOptions:\n" \
+"\t-m <MCS_bitmask> ...\n" \
+"\t\tSet HT rates by bitmask bytes, each ranges from 00 through ff, where\n" \
+"\t\tthe least significant bit is MCS0.\n" \
+"\t\tExample: '-m 3f 01' specifies HT rates MCS0 - MCS5 and MCS8.\n" \
+"\n" \
+"\t-v <VHT_bitmask> ...\n" \
+"\t\tSet VHT rates for each supported count of spatial streams.\n" \
+"\t\tExample: '-v 3ff 1ff ff' specifies VHT rates: MCS0 - MCS9 for 1 stream,\n" \
+"\t\tMCS0 - MCS8 for 2 streams, and MCS0 - MCS7 for 3 streams.\n" \
+"\n" \
+"\t-b\n" \
+"\t\tSet for Broadcom-to-Broadcom group of rates. Otherwise without\n" \
+"\t\tthe -b option, the standard group of rates are set accordingly.\n"
+
+#define MONITOR_PROMISC_LEVEL_USAGE \
+"\tUsage: wl monitor_promisc_level [<bitmap> | <+|-name>]\n" \
+"\tbitmap values and corresponding name are the following:\n" \
+"\tArgs:\n" \
+"\t\tbit:0:promisc: " \
+"When set, address filter accepts all received frames." \
+"When cleared, the address filter accepts only those frames " \
+"that match the BSSID or local MAC address\n" \
+"\t\tbit:1:ctrl: " \
+"When set, the RX filter accepts all received control frames " \
+"that are accepted by the address filter. " \
+"When cleared, the RX filter rejects all control frames other " \
+"than PS poll frames." \
+"\t\tbit:3:fcs: " \
+"When set, the RX filter forwards received frames with FCS " \
+"errors to the driver." \
+"When cleared, frames with FCS errors are discarded.\n\n" \
+"\tExample: wl monitor_promisc_level +promisc\n" \
+"\tExample: wl monitor_promisc_level 0x2\n" \
+"\tExample: wl monitor_promisc_level 0"
+
+/* the default behavior is batching in driver,
+ * to indicate client batching, users should specify --interactive and --clientbatch
+ */
+static bool batch_in_client;
+
+/* The wl_config_iovar_list structure is used to define config iovars. Config iovars can be in
+ * either an auto mode or in an override mode. If it is in auto mode, the status of the iovar
+ * is determined automatically. In override mode, the status is passed as a parameter to the
+ * iovar. If a new config iovar is getting added, it can either reuse the last entry in the
+ * list if parameters match, or add a new entry. If you are adding a new entry, make sure it is
+ * added before the last entry.
+ * In each row, the last entry of name-value params must have NULL
+ */
+wl_config_iovar_t wl_config_iovar_list[] = {
+ { "rsdb_mode", wl_bcm_config_print, {{"auto", -1}, {"mimo", 0}, {"rsdb", 1}, {"80p80", 2},
+ {NULL, 0}}},
+ { NULL, wl_bcm_config_print, {{"auto", -1}, {"off", 0}, {"disable", 0}, {"on", 1},
+ {"enable", 1}, {NULL, 0}}},
+};
+
+/* If the new command needs to be part of 'wc.exe' tool used for WMM,
+ * be sure to modify wc_cmds[] array as well
+ *
+ * If you add a command, please update wlu_cmd.c cmd2cat to categorize the command.
+ */
+cmd_t wl_cmds[] = {
+ { "debug_crash", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR,
+ "debug crash - TYPE DELAYED"},
+ { "winver", wl_winver, -1, -1,
+ "get Windows OS and driver version information" },
+ { "ver", wl_version, -1, -1,
+ "get version information" },
+ { "cmds", wl_list, -1, -1,
+ "generate a short list of available commands"},
+ { "ioctl_echo", wl_echo, -1, WLC_ECHO,
+ "check ioctl functionality" },
+ { "up", wl_void, -1, WLC_UP,
+ "reinitialize and mark adapter up (operational)" },
+ { "down", wl_void, -1, WLC_DOWN,
+ "reset and mark adapter down (disabled)" },
+ { "out", wl_out, -1, WLC_OUT,
+ "mark adapter down but do not reset hardware(disabled)\n"
+ "\tOn dualband cards, cards must be bandlocked before use."},
+ { "clk", wl_int, WLC_GET_CLK, WLC_SET_CLK,
+ "set board clock state. return error for set_clk attempt if the driver is not down\n"
+ "\t0: clock off\n"
+ "\t1: clock on" },
+ { "reboot", wl_void, -1, WLC_REBOOT,
+ "Reboot platform"},
+ { "radio", wl_radio, WLC_GET_RADIO, WLC_SET_RADIO,
+ "Set the radio on or off.\n"
+ "\t\"on\" or \"off\"" },
+ { "dump", wlu_dump, WLC_GET_VAR, -1,
+ "Give suboption \"list\" to list various suboptions" },
+ { "dump_clear", wlu_dump_clr, -1, WLC_SET_VAR,
+ "Clear a specific category of counters/stats.\n"
+ "\tUsage: dump_clear <category-name>\n"},
+ { "srclear", wlu_srwrite, -1, WLC_SET_SROM,
+ "Clears first 'len' bytes of the srom, len in decimal or hex\n"
+ "\tUsage: srclear <len>" },
+ { "srdump", wlu_srdump, WLC_GET_SROM, -1,
+ "print contents of SPROM to stdout" },
+ { "srwrite", wlu_srwrite, -1, WLC_SET_SROM,
+ "Write the srom: srwrite byteoffset value" },
+ { "ciswrite", wlu_ciswrite, -1, WLC_SET_VAR,
+ "Write specified <file> to the SDIO/PCIe CIS source (either SROM or OTP)"
+ "\tUsage: ciswrite [-p|--pciecis] <file>\n"
+ "\t-p|--pciecis -- Write OTP for PCIe full-dongle"},
+ { "cisupdate", wlu_cisupdate, -1, WLC_SET_VAR,
+ "Write a hex byte stream to specified byte offset to the CIS source (either SROM or OTP)\n"
+ "--preview option allows you to review the update without committing it\n"
+ "\t<byte offset> <hex byte stream> [--preview]" },
+ { "cisdump", wlu_cisdump, WLC_GET_VAR, -1,
+ "Display the content of the SDIO CIS source\n"
+ "\t-b <file> -- also write raw bytes to <file>\n"
+ "\t<len> -- optional count of bytes to display (must be even)"},
+ { "cisconvert", wlu_srvar, -1, -1,
+ "Print CIS tuple for given name=value pair" },
+ { "rdvar", wlu_srvar, WLC_GET_SROM, -1,
+ "Read a named variable to the srom" },
+ { "wrvar", wlu_srvar, WLC_GET_SROM, WLC_SET_SROM,
+ "Write a named variable to the srom" },
+ { "nvram_dump", wl_nvdump, WLC_NVRAM_DUMP, -1,
+ "print nvram variables to stdout" },
+ { "nvset", wl_nvset, -1, WLC_NVRAM_SET,
+ "set an nvram variable\n"
+ "\tname=value (no spaces around \'=\')" },
+ { "nvget", wl_nvget, WLC_NVRAM_GET, -1,
+ "get the value of an nvram variable" },
+ { "nvram_get", wl_nvget, WLC_NVRAM_GET, -1,
+ "get the value of an nvram variable" },
+ { "revinfo", wl_revinfo, WLC_GET_REVINFO, -1,
+ "get hardware revision information" },
+ { "msglevel", wl_msglevel, WLC_GET_VAR, WLC_SET_VAR,
+ "set driver console debugging message bitvector\n"
+ "\ttype \'wl msglevel ?\' for values" },
+ { "PM", wl_int, WLC_GET_PM, WLC_SET_PM,
+ "set driver power management mode:\n"
+ "\t0: CAM (constantly awake)\n"
+ "\t1: PS (power-save)\n"
+ "\t2: FAST PS mode" },
+ { "wake", wl_int, WLC_GET_WAKE, WLC_SET_WAKE,
+ "set driver power-save mode sleep state:\n"
+ "\t0: core-managed\n"
+ "\t1: awake" },
+ { "promisc", wl_int, WLC_GET_PROMISC, WLC_SET_PROMISC,
+ "set promiscuous mode ethernet address reception\n"
+ "\t0 - disable\n"
+ "\t1 - enable" },
+ { "monitor", wl_int, WLC_GET_MONITOR, WLC_SET_MONITOR,
+ "set monitor mode\n"
+ "\t0 - disable\n"
+ "\t1 - enable active monitor mode (interface still operates)" },
+ { "frag", wl_print_deprecate, -1, -1, "Deprecated. Use fragthresh." },
+ { "rts", wl_print_deprecate, -1, -1, "Deprecated. Use rtsthresh." },
+ { "cwmin", wl_int, WLC_GET_CWMIN, WLC_SET_CWMIN,
+ "Set the cwmin. (integer [1, 255])" },
+ { "cwmax", wl_int, WLC_GET_CWMAX, WLC_SET_CWMAX,
+ "Set the cwmax. (integer [256, 2047])" },
+ { "srl", wl_int, WLC_GET_SRL, WLC_SET_SRL,
+ "Set the short retry limit. (integer [1, 255])" },
+ { "lrl", wl_int, WLC_GET_LRL, WLC_SET_LRL,
+ "Set the long retry limit. (integer [1, 255])" },
+ { "rate", wl_rate_mrate, WLC_GET_RATE, -1,
+ "force a fixed rate:\n"
+ "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n"
+ "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n"
+ "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n"
+ "\t-1 (default) means automatically determine the best rate" },
+ { "mrate", wl_rate_mrate, -1, -1, /* Deprecated. Use "bg_mrate" or "a_mrate" */
+ "force a fixed multicast rate:\n"
+ "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n"
+ "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n"
+ "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n"
+ "\t-1 (default) means automatically determine the best rate" },
+ { "a_rate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR,
+ "force a fixed rate for the A PHY:\n"
+ "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n"
+ "\t-1 (default) means automatically determine the best rate" },
+ { "a_mrate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR,
+ "force a fixed multicast rate for the A PHY:\n"
+ "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n"
+ "\t-1 (default) means automatically determine the best rate" },
+ { "bg_rate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR,
+ "force a fixed rate for the B/G PHY:\n"
+ "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n"
+ "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n"
+ "\t-1 (default) means automatically determine the best rate" },
+ { "bg_mrate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR,
+ "force a fixed multicast rate for the B/G PHY:\n"
+ "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n"
+ "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n"
+ "\t-1 (default) means automatically determine the best rate" },
+ { "2g_rate", wl_rate, WLC_GET_VAR, WLC_SET_VAR,
+ "Force a fixed rate for data frames in the 2.4G band:\n\n"
+ RATE_2G_USAGE
+ },
+ { "2g_mrate", wl_rate, WLC_GET_VAR, WLC_SET_VAR,
+ "Force a fixed rate for mulitcast/broadcast data frames in the 2.4G band:\n\n"
+ RATE_2G_USAGE
+ },
+ { "5g_rate", wl_rate, WLC_GET_VAR, WLC_SET_VAR,
+ "Force a fixed rate for data frames in the 5G band:\n\n"
+ RATE_5G_USAGE
+ },
+ { "5g_mrate", wl_rate, WLC_GET_VAR, WLC_SET_VAR,
+ "Force a fixed rate for mulitcast/broadcast data frames in the 5G band:\n\n"
+ RATE_5G_USAGE
+ },
+ { "infra", wl_int, WLC_GET_INFRA, WLC_SET_INFRA,
+ "Configure BSS type or query Infra mode.\n"
+ "Configure BSS type for next BSS Start or Join operation:\n"
+ "\t0 (IBSS)\n"
+ "\t1 (Infra BSS)\n"
+ "\t2 (Any BSS, for Join only)\n"
+ "\t3 (Mesh BSS)\n"
+ "Query the Infra mode of the current BSS:\n"
+ "\t0 (IBSS)\n"
+ "\t1 (Infra BSS)\n"
+ "Note: use \"wl infra_configuration\" to query the configuration.\n"},
+ { "bssid", wl_bssid, WLC_GET_BSSID, -1,
+ "Get the BSSID value, error if STA and not associated"},
+ { "bssmax", wl_bss_max, WLC_GET_VAR, -1,
+ "get number of BSSes " },
+ { "channel", wl_channel, WLC_GET_CHANNEL, WLC_SET_CHANNEL,
+ "Set the channel:\n"
+ "\tvalid channels for 802.11b/g (2.4GHz band) are 1 through 14\n"
+ "\tvalid channels for 802.11a (5 GHz band) are:\n"
+ "\t\t36, 40, 44, 48, 52, 56, 60, 64,\n"
+ "\t\t100, 104, 108, 112, 116,120, 124, 128, 132, 136, 140, 144,\n"
+ "\t\t149, 153, 157, 161,\n"
+ "\t\t184, 188, 192, 196, 200, 204, 208, 212, 216"},
+ { "clmver", wl_var_getandprintstr, WLC_GET_VAR, -1,
+ "Get version information for CLM data and tools"},
+ { "roam_channels_in_cache", wl_dump_chanspecs, WLC_GET_VAR, -1,
+ "Get a list of channels in roam cache" },
+ { "roam_channels_in_hotlist", wl_dump_chanspecs, WLC_GET_VAR, -1,
+ "Get a list of channels in roam hot channel list" },
+ { "chanspecs", wl_dump_chanspecs, WLC_GET_VAR, -1,
+ "Get all the valid chanspecs (default: all within current locale):\n"
+ "\t-b band (5(a) or 2(b/g))\n"
+ "\t-w bandwidth, 20, 40, 80, 160, or 80+80\n"
+ "\t[-c country_abbrev]"
+ },
+ { "chanspecs_defset", wl_dump_chanspecs_defset, WLC_GET_VAR, -1,
+ "Get default chanspecs for current driver settings (default: all within current locale)"
+ },
+ { "chanspec", wl_chanspec, WLC_GET_VAR, WLC_SET_VAR,
+ "Set current or configured channel:\n"
+ "\t20MHz : [2g|5g]<channel>[/20]\n"
+ "\t40MHz : [2g|5g]<channel>/40[u,l]\n"
+ "\t80MHz : [5g]<channel>/80\n"
+ "\t160MHz: [5g]<channel>/160\n"
+ "\t80+80MHz: [5g]<channel>/80+80/<1st80channel>-<2nd80channel>\n"
+ "\toptional band 2g or 5g, default to 2g if channel <= 14\n"
+ "\tchannel number (0-200)\n"
+ "\tbandwidth, 2.5, 5, 10, 20, 40, 80, 160, or 80+80 default 20\n"
+ "\tprimary sideband for 40MHz on 2g, l=lower, u=upper\n"
+ "\t<1st80Channel>, <2nd80Channel> Required for 80+80, otherwise not allowed. "
+ "These fields specify the center channel of the first and second 80MHz band.\n"
+ "OR Set channel with legacy format:\n"
+ "\t-c channel number (0-224)\n"
+ "\t-b band (5(a) or 2(b/g))\n"
+ "\t-w bandwidth 20 or 40\n"
+ "\t-s ctl sideband, -1=lower, 0=none, 1=upper"},
+ { "sc_chan", wl_sc_chan, WLC_GET_VAR, WLC_SET_VAR,
+ "Set current or configured channel:\n"
+ "\t20MHz : [2g|5g]<channel>[/20]\n"
+ "\t40MHz : [2g|5g]<channel>/40[u,l]\n"
+ "\t80MHz : [5g]<channel>/80\n"
+ "\toptional band 2g or 5g, default to 2g if channel <= 14\n"
+ "\tchannel number (0-200)\n"
+ "\tbandwidth, 2.5, 5, 10, 20, 40, or 80, default 20\n"
+ "\tprimary sideband for 40MHz on 2g, l=lower, u=upper\n"
+ "OR Set channel with legacy format:\n"
+ "\t-c channel number (0-224)\n"
+ "\t-b band (5(a) or 2(b/g))\n"
+ "\t-w bandwidth 20 or 40\n"
+ "\t-s ctl sideband, -1=lower, 0=none, 1=upper"},
+ { "phy_vcore", wl_phy_vcore, WLC_GET_VAR, -1,
+ "get virtual core related capabilities\n"},
+ { "rclass", wl_rclass, WLC_GET_VAR, -1,
+ "Get operation class:\n"
+ "\t chanspec \n"},
+ { "dfs_channel_forced", wl_dfs_channel_forced, WLC_GET_VAR, WLC_SET_VAR,
+ "Set <channel>[a,b][n][u,l]\n"
+ "\tchannel number (0-224)\n"
+ "\tband a=5G, b=2G, default to 2G if channel <= 14\n"
+ "\tbandwidth, n=10, non for 20 & 40\n"
+ "\tctl sideband, l=lower, u=upper\n"
+ "Set channel list using -l option \n"
+ "\twl dfs_channel_forced {-l <chanspec list> | 0}\n"
+ "\t20MHz : <channel>[/20]\n"
+ "\t40MHz : <channel>{{l|u}|/40}\n"
+ "\t80MHz : <channel>/80\n"
+ "\tChannels specified using '-l' option should be\n"
+ "seperated by ','/' ' and should be prefixed with '+'/'-'\n"
+ "Deletes existing configuration when '0' specified"},
+ { "txpwr", wl_txpwr, -1, -1, /* Deprecated. Use "txpwr1" */
+ "Set tx power in milliwatts. Range [1, 84]." },
+ { "txpwr1", wl_txpwr1, WLC_GET_VAR, WLC_SET_VAR,
+ "Set tx power in in various units. Choose one of (default: dBm): \n"
+ "\t-d dBm units (range: -32 - 31)\n"
+ "\t-q quarter dBm units (range: -128 - 127)\n"
+ "\t-m milliwatt units\n"
+ "Can be combined with:\n"
+ "\t-o turn on override to disable regulatory and other limitations\n"
+ "Use wl txpwr -1 to restore defaults"},
+ { "txpwrlimit", wl_get_txpwr_limit, WLC_CURRENT_PWR, -1,
+ "Return current tx power limit" },
+ { "ucflags", wl_reg, WLC_GET_UCFLAGS, WLC_SET_UCFLAGS,
+ "Get/Set ucode flags 1, 2, 3(16 bits each)\n"
+ "\toffset [ value ] [ band ]" },
+ { "shmem", wl_reg, WLC_GET_SHMEM, WLC_SET_SHMEM,
+ "Get/Set a shared memory location:\n"
+ "\toffset [ value ] [band ]" },
+ { "macreg", wl_macreg, WLC_R_REG, WLC_W_REG,
+ "Get/Set any mac registers(include IHR and SB):\n"
+ "\tmacreg offset size[2,4] [ value ] [ band ]" },
+ { "shmemx", wl_macregx, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set a shared memory location of PSMX:\n"
+ "\toffset [ value ] [band ]" },
+ { "macregx", wl_macregx, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set any mac registers(include IHR and SB) of PSMX:\n"
+ "\tmacreg offset size[2,4] [ value ] [ band ]" },
+ { "ucantdiv", wl_int, WLC_GET_UCANTDIV, WLC_SET_UCANTDIV,
+ "Enable/disable ucode antenna diversity (1/0 or on/off)" },
+ { "actframe", wl_actframe, -1, WLC_SET_VAR,
+ "Send a Vendor specific Action frame to a channel\n"
+ "\tusage: wl actframe <Dest Mac Addr> <data> channel dwell-time <BSSID>" },
+ { "antdiv", wl_int, WLC_GET_ANTDIV, WLC_SET_ANTDIV,
+ "Set antenna diversity for rx\n"
+ "\t0 - force use of antenna 0\n"
+ "\t1 - force use of antenna 1\n"
+ "\t3 - automatic selection of antenna diversity" },
+ { "txant", wl_int, WLC_GET_TXANT, WLC_SET_TXANT,
+ "Set the transmit antenna\n"
+ "\t0 - force use of antenna 0\n"
+ "\t1 - force use of antenna 1\n"
+ "\t3 - use the RX antenna selection that was in force during\n"
+ "\t the most recently received good PLCP header" },
+ { "plcphdr", wl_plcphdr, WLC_GET_PLCPHDR, WLC_SET_PLCPHDR,
+ "Set the plcp header.\n"
+ "\t\"long\" or \"auto\" or \"debug\"" },
+ { "phytype", wl_int, WLC_GET_PHYTYPE, -1,
+ "Get phy type" },
+ { "rateparam", wl_rateparam, -1, WLC_SET_RATE_PARAMS,
+ "set driver rate selection tunables\n"
+ "\targ 1: tunable id\n"
+ "\targ 2: tunable value" },
+ { "wsec_restrict", wl_bsscfg_int, WLC_GET_WEP_RESTRICT, WLC_SET_WEP_RESTRICT,
+ "Drop unencrypted packets if WSEC is enabled\n"
+ "\t0 - disable\n"
+ "\t1 - enable" },
+ { "eap", wl_int, WLC_GET_EAP_RESTRICT, WLC_SET_EAP_RESTRICT,
+ "restrict traffic to 802.1X packets until 802.1X authorization succeeds\n"
+ "\t0 - disable\n"
+ "\t1 - enable" },
+ { "cur_etheraddr", wl_iov_mac, -1, -1,
+ "Get/set the current hw address" },
+ { "perm_etheraddr", wl_iov_mac, -1, -1,
+ "Get the permanent address from NVRAM" },
+ { "authorize", wl_macaddr, -1, WLC_SCB_AUTHORIZE,
+ "restrict traffic to 802.1X packets until 802.1X authorization succeeds" },
+ { "deauthorize", wl_macaddr, -1, WLC_SCB_DEAUTHORIZE,
+ "do not restrict traffic to 802.1X packets until 802.1X authorization succeeds" },
+ { "deauthenticate", wl_deauth_rc, -1, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
+ "deauthenticate a STA from the AP with optional reason code (AP ONLY)" },
+ { "wsec", wl_wsec, WLC_GET_WSEC, WLC_SET_WSEC,
+ "wireless security bit vector\n"
+ "\t1 - WEP enabled\n"
+ "\t2 - TKIP enabled\n"
+ "\t4 - AES enabled\n"
+ "\t8 - WSEC in software\n"
+ "\t0x80 - FIPS enabled\n"
+ "\t0x100 - WAPI enabled"
+ },
+ { "auth", wl_bsscfg_int, WLC_GET_AUTH, WLC_SET_AUTH,
+ "set/get 802.11 authentication type. 0 = OpenSystem, 1= SharedKey, 3=Open/Shared" },
+ { "wpa_auth", wl_wpa_auth, WLC_GET_WPA_AUTH, WLC_SET_WPA_AUTH,
+ "Bitvector of WPA authorization modes:\n"
+ "\t1 WPA-NONE\n"
+ "\t2 WPA-802.1X/WPA-Professional\n"
+ "\t4 WPA-PSK/WPA-Personal\n"
+ "\t64 WPA2-802.1X/WPA2-Professional\n"
+ "\t128 WPA2-PSK/WPA2-Personal\n"
+ "\t0 disable WPA"
+ },
+ { "wpa_cap", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get 802.11i RSN capabilities" },
+ { "set_pmk", wl_set_pmk, -1, WLC_SET_WSEC_PMK,
+ "Set passphrase for PMK in driver-resident supplicant." },
+ { "scan", wl_scan, -1, WLC_SCAN,
+ "Initiate a scan.\n" SCAN_USAGE
+ },
+ { "roamscan_parms", wl_roamparms, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get roam scan parameters\n"
+ "Use standard scan params syntax below,"
+ "but only active/passive/home times, nprobes, type,"
+ "and channels are used.\n"
+ "All other values are silently discarded.\n"
+ SCAN_USAGE
+ },
+#ifdef WLRCC
+ { "roamscan_channels", wl_roamchannels, WLC_GET_VAR, -1,
+ "get roam channels\n"
+ },
+#endif /* WLRCC */
+ { "roam_prof", wl_roam_prof, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set roaming profiles (need to specify band)\n"
+ "\tUsage: wl roam_prof_2g a|b|2g|5g flags rssi_upper rssi_lower delta, boost_thresh "
+ "boot_delta nfscan fullperiod initperiod backoff maxperiod\n"
+ },
+ { "iscan_s", wl_iscan, -1, WLC_SET_VAR,
+ "Initiate an incremental scan.\n" SCAN_USAGE
+ },
+ { "iscan_c", wl_iscan, -1, WLC_SET_VAR,
+ "Continue an incremental scan.\n" SCAN_USAGE
+ },
+ { "escan", wl_escan, -1, WLC_SET_VAR,
+ "Start an escan.\n" SCAN_USAGE
+ },
+ { "escanabort", wl_escan, -1, WLC_SET_VAR,
+ "Abort an escan.\n" SCAN_USAGE
+ },
+ { "regulatory", wl_int, WLC_GET_REGULATORY, WLC_SET_REGULATORY,
+ "Get/Set regulatory domain mode (802.11d). Driver must be down." },
+ { "spect", wl_spect, WLC_GET_SPECT_MANAGMENT, WLC_SET_SPECT_MANAGMENT,
+ "Get/Set 802.11h Spectrum Management mode.\n"
+ "\t0 - Off\n"
+ "\t1 - Loose interpretation of 11h spec - may join non-11h APs\n"
+ "\t2 - Strict interpretation of 11h spec - may not join non-11h APs\n"
+ "\t3 - Disable 11h and enable 11d\n"
+ "\t4 - Loose interpretation of 11h+d spec - may join non-11h APs"
+ },
+ { "scanabort", wl_var_void, -1, WLC_SET_VAR,
+ "Abort a scan." },
+ { "scanresults", wl_dump_networks, WLC_SCAN_RESULTS, -1,
+ "Return results from last scan." },
+ { "iscanresults", wl_dump_networks, WLC_GET_VAR, -1,
+ "Return results from last iscan. Specify a buflen (max 8188)\n"
+ "\tto artificially limit the size of the results buffer.\n"
+ "\tiscanresults [buflen]"},
+ { "assoc", wl_status, -1, -1,
+ "Print information about current network association.\n"
+ "\t(also known as \"status\")" },
+ { "status", wl_status, -1, -1,
+ "Print information about current network association.\n"
+ "\t(also known as \"assoc\")" },
+ { "disassoc", wl_void, -1, WLC_DISASSOC,
+ "Disassociate from the current BSS/IBSS." },
+ { "chanlist", wl_print_deprecate, WLC_GET_VALID_CHANNELS, -1,
+ "Deprecated. Use channels." },
+ { "channels", wl_dump_chanlist, WLC_GET_VALID_CHANNELS, -1,
+ "Return valid channels for the current settings." },
+ { "channels_in_country", wl_channels_in_country, WLC_GET_CHANNELS_IN_COUNTRY, -1,
+ "Return valid channels for the country specified.\n"
+ "\tArg 1 is the country abbreviation\n"
+ "\tArg 2 is the band(a or b)"},
+ { "curpower", wl_get_current_power, WLC_CURRENT_PWR, -1,
+ "Return current tx power settings.\n"
+ "\t-v, --verbose: display the power settings for every "
+ "rate even when every rate in a rate group has the same power." },
+ { "txpwr_target_max", wl_get_txpwr_target_max, WLC_GET_VAR, -1,
+ "Return current max tx target power settings.\n" },
+ { "chanspec_txpwr_max", wl_get_chanspec_txpwr_max, WLC_GET_VAR, -1,
+ "Return valid chanspecs with max tx power settings.\n"
+ "\t-b band (5(a) or 2(b/g))\n"
+ "\t-w bandwidth, 20, 40, 80, 160 or 8080\n"
+ },
+ { "rateset", wl_rateset, WLC_GET_RATESET, WLC_SET_RATESET,
+ "Returns or sets the supported and basic rateset, (b) indicates basic\n"
+ "\tWith no args, returns the rateset. Args are\n"
+ "\trateset \"default\" | \"all\" | <arbitrary rateset> [-m|-v <list of mcs masks>]\n"
+ "\t\tdefault - driver defaults\n"
+ "\t\tall - all rates are basic rates\n"
+ "\t\tarbitrary rateset - list of rates\n"
+ "\tList of rates are in Mbps and each rate is optionally followed\n"
+ "\tby \"(b)\" or \"b\" for a Basic rate. Example: 1(b) 2b 5.5 11\n"
+ "\tAt least one rate must be Basic for a legal rateset.\n\n"
+ "\t-m sets HT rates (bitmasks, 00-ff). Least significant bit is MCS0.\n"
+ "\t example: 'rateset -m 0x3f 0x01' limits rates to MCS0-MCS5 and MCS8\n\n"
+ "\t-v sets VHT MCS values for each supported count of spatial streams.\n"
+ "\t example: 'rateset -v 3ff 1ff ff' limits vht rates to MCS 0-9 for 1 stream,\n"
+ "\t MCS 0-8 for 2 streams, and MCS 0-7 for 3 streams."
+ },
+ {"txbf_rateset", wl_txbf_rateset, WLC_GET_TXBF_RATESET, WLC_SET_TXBF_RATESET,
+ TXBF_RATESET_USAGE
+ },
+ { "default_rateset", wl_default_rateset, WLC_GET_VAR, -1,
+ "Returns supported rateset of given phy.\n"
+ "\tYou have to insert following Args\n"
+ "\t\tArg 1. Phy Type: have to be one of the following: "
+ "[a, b, g, n, lp, ssn, ht, lcn, lcn40, ac]\n"
+ "\t\tArg 2. Band Type: 2 for 2.4G or 5 for 5G\n"
+ "\t\tArg 3. CCK Only: 1 for CCK Only or 0 for CCK and OFDM rates\n"
+ "\t\tArg 4. Basic Rates: 1 for all rates WITH basic rates or "
+ "0 for all rates WITHOUT basic rates\n"
+ "\t\tArg 5. MCS Rates: 1 for all rates WITH MCS rates or "
+ "0 for all rates WITHOUT MCS rates\n"
+ "\t\tArg 6. Bandwidth: have to be one of the following: [10, 20, 40, 80, 160]\n"
+ "\t\tArg 7. TX/RX Stream: \"tx\" for TX streams or \"rx\" for RX streams\n"
+ "\t\tExample: PHY: AC, Band 2.4G, CCK rates only, With Basec rates, "
+ "WithOut MCS rates, BW: 40 and TX streams\n"
+ "\t\tInput: default_rateset ac 2 0 1 0 40 tx\n"
+ },
+ { "roam_trigger", wl_band_elm, WLC_GET_ROAM_TRIGGER, WLC_SET_ROAM_TRIGGER,
+ "Get or Set the roam trigger RSSI threshold:\n"
+ "\tGet: roam_trigger [a|b]\n"
+ "\tSet: roam_trigger <integer> [a|b|all]\n"
+ "\tinteger - 0: default\n"
+ "\t 1: optimize bandwidth\n"
+ "\t 2: optimize distance\n"
+ "\t [-1, -99]: dBm trigger value"},
+ { "roam_delta", wl_band_elm, WLC_GET_ROAM_DELTA, WLC_SET_ROAM_DELTA,
+ "Set the roam candidate qualification delta. roam_delta [integer [, a/b]]" },
+ { "roam_scan_period", wl_int, WLC_GET_ROAM_SCAN_PERIOD, WLC_SET_ROAM_SCAN_PERIOD,
+ "Set the roam candidate qualification delta. (integer)" },
+ { "suprates", wl_sup_rateset, WLC_GET_SUP_RATESET_OVERRIDE, WLC_SET_SUP_RATESET_OVERRIDE,
+ "Returns or sets the 11g override for the supported rateset\n"
+ "\tWith no args, returns the rateset. Args are a list of rates,\n"
+ "\tor 0 or -1 to specify an empty rateset to clear the override.\n"
+ "\tList of rates are in Mbps, example: 1 2 5.5 11"},
+ { "prb_resp_timeout", wl_int, WLC_GET_PRB_RESP_TIMEOUT, WLC_SET_PRB_RESP_TIMEOUT,
+ "Get/Set probe response timeout"},
+ { "channel_qa", wl_int, WLC_GET_CHANNEL_QA, -1,
+ "Get last channel quality measurment"},
+ { "channel_qa_start", wl_void, -1, WLC_START_CHANNEL_QA,
+ "Start a channel quality measurment"},
+ { "ccode_info", wl_ccode_info, WLC_GET_VAR, -1,
+ "Get Country Code Info"},
+ { "country", wl_country, WLC_GET_COUNTRY, WLC_SET_COUNTRY,
+ "Select Country Code for driver operational region\n"
+ "\tFor simple country setting: wl country <country>\n"
+ "\tWhere <country> is either a long name or country code from ISO 3166; "
+ "for example \"Germany\" or \"DE\"\n"
+ "\n\tFor a specific built-in country definition: "
+ "wl country <built-in> [<advertised-country>]\n"
+ "\tWhere <built-in> is a country country code followed by '/' and "
+ "regulatory revision number.\n"
+ "\tFor example, \"US/3\".\n"
+ "\tAnd where <advertised-country> is either a long name or country code from ISO 3166.\n"
+ "\tIf <advertised-country> is omitted, it will be the same as the built-in country code.\n"
+ "\n\tUse 'wl country list [band(a or b)]' for the list of supported countries"},
+ { "country_ie_override", wl_country_ie_override, WLC_GET_VAR, WLC_SET_VAR,
+ "To set/get country ie"},
+ { "autocountry_default", wl_varstr, WLC_GET_VAR, WLC_SET_VAR,
+ "Select Country Code for use with Auto Contry Discovery"},
+ { "join", wl_join, -1, -1,
+ "Join a specified network SSID.\n"
+ "\tUsage: join <ssid> [key <0-3>:xxxxx] [imode bss|ibss] "
+ "[amode open|shared|openshared|wpa|wpapsk|wpa2|wpa2psk|wpanone|ftpsk] [options]\n"
+ "\tOptions:\n"
+ "\t-b MAC, --bssid=MAC \tBSSID (xx:xx:xx:xx:xx:xx) to scan and join\n"
+ "\t-c CL, --chanspecs=CL \tchanspecs (comma or space separated list)\n"
+ "\tprescanned \tuses channel and bssid list from scanresults\n"
+ "\t-p, -passive: force passive assoc scan (useful for P2P)"},
+ { "ssid", wl_ssid, WLC_GET_SSID, WLC_SET_SSID,
+ "Set or get a configuration's SSID.\n"
+ "\twl ssid [-C num]|[--cfg=num] [<ssid>]\n"
+ "\tIf the configuration index 'num' is not given, configuraion #0 is assumed and\n"
+ "\tsetting will initiate an assoication attempt if in infrastructure mode,\n"
+ "\tor join/creation of an IBSS if in IBSS mode,\n"
+ "\tor creation of a BSS if in AP mode."},
+ { "mac", wl_maclist, WLC_GET_MACLIST, WLC_SET_MACLIST,
+ "Set or get the list of source MAC address matches.\n"
+ "\twl mac xx:xx:xx:xx:xx:xx [xx:xx:xx:xx:xx:xx ...]\n"
+ "\tTo Clear the list: wl mac none" },
+ { "macmode", wl_int, WLC_GET_MACMODE, WLC_SET_MACMODE,
+ "Set the mode of the MAC list.\n"
+ "\t0 - Disable MAC address matching.\n"
+ "\t1 - Deny association to stations on the MAC list.\n"
+ "\t2 - Allow association to stations on the MAC list."},
+ { "band", wl_band, WLC_GET_BAND, WLC_SET_BAND,
+ "Returns or sets the current band\n"
+ "\tauto - auto switch between available bands (default)\n"
+ "\ta - force use of 802.11a band\n"
+ "\tb - force use of 802.11b band" },
+ { "bands", wl_bandlist, WLC_GET_BANDLIST, -1,
+ "Return the list of available 802.11 bands" },
+ { "phylist", wl_phylist, WLC_GET_PHYLIST, -1,
+ "Return the list of available phytypes" },
+ { "shortslot", wl_int, WLC_GET_SHORTSLOT, -1,
+ "Get current 11g Short Slot Timing mode. (0=long, 1=short)" },
+ { "shortslot_override", wl_int, WLC_GET_SHORTSLOT_OVERRIDE, WLC_SET_SHORTSLOT_OVERRIDE,
+ "Get/Set 11g Short Slot Timing mode override. (-1=auto, 0=long, 1=short)" },
+ { "pktcnt", wl_get_pktcnt, WLC_GET_PKTCNTS, -1,
+ "Get the summary of good and bad packets." },
+ { "upgrade", wl_upgrade, -1, WLC_UPGRADE,
+ "Upgrade the firmware on an embedded device" },
+ { "gmode", wl_gmode, WLC_GET_GMODE, WLC_SET_GMODE,
+ "Set the 54g Mode (LegacyB|Auto||GOnly|BDeferred|Performance|LRS)" },
+ { "gmode_protection", wl_int, WLC_GET_GMODE_PROTECTION, -1,
+ "Get G protection mode. (0=disabled, 1=enabled)" },
+ { "gmode_protection_control", wl_int, WLC_GET_PROTECTION_CONTROL,
+ WLC_SET_PROTECTION_CONTROL,
+ "Get/Set 11g protection mode control alg."
+ "(0=always off, 1=monitor local association, 2=monitor overlapping BSS)" },
+ { "gmode_protection_override", wl_int, WLC_GET_GMODE_PROTECTION_OVERRIDE,
+ WLC_SET_GMODE_PROTECTION_OVERRIDE,
+ "Get/Set 11g protection mode override. (-1=auto, 0=disable, 1=enable)" },
+ { "protection_control", wl_int, WLC_GET_PROTECTION_CONTROL,
+ WLC_SET_PROTECTION_CONTROL,
+ "Get/Set protection mode control alg."
+ "(0=always off, 1=monitor local association, 2=monitor overlapping BSS)" },
+ { "legacy_erp", wl_int, WLC_GET_LEGACY_ERP, WLC_SET_LEGACY_ERP,
+ "Get/Set 11g legacy ERP inclusion (0=disable, 1=enable)" },
+ { "isup", wl_int, WLC_GET_UP, -1,
+ "Get driver operational state (0=down, 1=up)"},
+ { "rssi", wl_rssi, WLC_GET_RSSI, -1,
+ "Get the current RSSI val, for an AP you must specify the mac addr of the STA" },
+ { "fasttimer", wl_print_deprecate, -1, -1,
+ "Deprecated. Use fast_timer."},
+ { "slowtimer", wl_print_deprecate, -1, -1,
+ "Deprecated. Use slow_timer."},
+ { "glacialtimer", wl_print_deprecate, -1, -1,
+ "Deprecated. Use glacial_timer."},
+ { "dfs_status", wl_dfs_status, WLC_GET_VAR, -1,
+ "Get dfs status"},
+ { "dfs_status_all", wl_dfs_status_all, WLC_GET_VAR, -1,
+ "Get dfs status of multiple cores or parallel radar scans"},
+ { "radar_status", wl_radar_status, WLC_GET_VAR, -1,
+ "Get radar detection status"},
+ { "clear_radar_status", wl_clear_radar_status, -1, WLC_SET_VAR,
+ "Clear radar detection status"},
+ { "radar_sc_status", wl_radar_sc_status, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/clear sc radar detection status"},
+ { "pwr_percent", wl_int, WLC_GET_PWROUT_PERCENTAGE, WLC_SET_PWROUT_PERCENTAGE,
+ "Get/Set power output percentage"},
+ { "toe", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/Disable tcpip offload feature"},
+ { "arpoe", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/Disable arp agent offload feature"},
+ { "wet", wl_int, WLC_GET_WET, WLC_SET_WET,
+ "Get/Set wireless ethernet bridging mode"},
+ { "bi", wl_int, WLC_GET_BCNPRD, WLC_SET_BCNPRD,
+ "Get/Set the beacon period (bi=beacon interval)"},
+ { "dtim", wl_int, WLC_GET_DTIMPRD, WLC_SET_DTIMPRD,
+ "Get/Set DTIM"},
+ { "measure_req", wl_measure_req, -1, WLC_MEASURE_REQUEST,
+ "Send an 802.11h measurement request.\n"
+ "\tUsage: wl measure_req <type> <target MAC addr>\n"
+ "\tMeasurement types are: TPC, Basic, CCA, RPI\n"
+ "\tTarget MAC addr format is xx:xx:xx:xx:xx:xx"},
+ { "quiet", wl_send_quiet, -1, WLC_SEND_QUIET,
+ "Send an 802.11h quiet command.\n"
+ "\tUsage: wl quiet <TBTTs until start>, <duration (in TUs)>, <offset (in TUs)>"},
+ { "pm_mute_tx", wl_pm_mute_tx, -1, WLC_SET_VAR,
+ "Sets parameters for power save mode with muted transmission path. Usage:\n"
+ "\twl pm_mute_tx 1 <deadline>\t: attempts to enable mode as soon as\n"
+ "\t\t\t timer of <deadline> (milliseconds) expires.\n"
+ "\twl pm_mute_tx 0\t: disables mode\n" },
+ { "csa", wl_send_csa, -1, WLC_SET_VAR,
+ "Send an 802.11h channel switch anouncement with chanspec:\n"
+ "\t<mode> <count> <channel>[a,b][n][u,l][frame type]\n"
+ "\tmode (0 or 1)\n"
+ "\tcount (0-254)\n"
+ "\tchannel format:\n"
+ "\t20MHz : [2g|5g]<channel>[/20]\n"
+ "\t40MHz : [2g|5g]<channel>/40[u,l]\n"
+ "\t80MHz : [5g]<channel>/80\n"
+ "\toptional band 2g or 5g, default to 2g if channel <= 14\n"
+ "\tchannel number (0-200)\n"
+ "\tbandwidth, 20, 40, or 80, default 20\n"
+ "\tprimary sideband for 40MHz on 2g, l=lower, u=upper\n"
+ "\tcsa frame type(optional), default is broadcast if not specified, u=unicast"},
+ { "constraint", wl_int, -1, WLC_SEND_PWR_CONSTRAINT,
+ "Send an 802.11h Power Constraint IE\n"
+ "\tUsage: wl constraint 1-255 db"},
+ { "rm_req", wl_rm_request, -1, WLC_SET_VAR,
+ "Request a radio measurement of type basic, cca, or rpi\n"
+ "\tspecify a series of measurement types each followed by options.\n"
+ "\texample: wl rm_req cca -c 1 -d 50 cca -c 6 cca -c 11\n"
+ "\tOptions:\n"
+ "\t-t n numeric token id for measurement set or measurement\n"
+ "\t-c n channel\n"
+ "\t-d n duration in TUs (1024 us)\n"
+ "\t-p parallel flag, measurement starts at the same time as previous\n"
+ "\n"
+ "\tEach measurement specified uses the same channel and duration as the\n"
+ "\tprevious unless a new channel or duration is specified."},
+ { "rm_rep", wl_rm_report, WLC_GET_VAR, -1,
+ "Get current radio measurement report"},
+ { "join_pref", wl_join_pref, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get join target preferences."},
+ { "assoc_pref", wl_assoc_pref, WLC_GET_ASSOC_PREFER, WLC_SET_ASSOC_PREFER,
+ "Set/Get association preference.\n"
+ "Usage: wl assoc_pref [auto|a|b|g]"},
+ { "wme", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Set WME (Wireless Multimedia Extensions) mode (0=off, 1=on, -1=auto)"},
+ { "wme_ac", wl_wme_ac_req, WLC_GET_VAR, WLC_SET_VAR,
+ "wl wme_ac ap|sta [be|bk|vi|vo [ecwmax|ecwmin|txop|aifsn|acm <value>] ...]"},
+ { "wme_apsd", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Set APSD (Automatic Power Save Delivery) mode on AP (0=off, 1=on)" },
+ { "wme_apsd_sta", wl_wme_apsd_sta, WLC_GET_VAR, WLC_SET_VAR,
+ "Set APSD parameters on STA. Driver must be down.\n"
+ "Usage: wl wme_apsd_sta <max_sp_len> <be> <bk> <vi> <vo>\n"
+ " <max_sp_len>: number of frames per USP: 0 (all), 2, 4, or 6\n"
+ " <xx>: value 0 to disable, 1 to enable U-APSD per AC" },
+ { "wme_dp", wl_wme_dp, WLC_GET_VAR, WLC_SET_VAR,
+ "Set AC queue discard policy.\n"
+ "Usage: wl wme_dp <be> <bk> <vi> <vo>\n"
+ " <xx>: value 0 for newest-first, 1 for oldest-first" },
+ { "wme_counters", wl_wme_counters, WLC_GET_VAR, -1,
+ "print WMM stats" },
+ { "wme_clear_counters", wl_var_void, -1, WLC_SET_VAR,
+ "clear WMM counters"},
+ { "wme_tx_params", wme_tx_params, -1, -1,
+ "wl wme_tx_params [be|bk|vi|vo [short|sfb|long|lfb|max_rate <value>] ...]"},
+ { "wme_maxbw_params", wme_maxbw_params, WLC_GET_VAR, WLC_SET_VAR,
+ "wl wme_maxbw_params [be|bk|vi|vo <value> ....]"},
+ { "lifetime", wl_lifetime, WLC_GET_VAR, WLC_SET_VAR,
+ "Set Lifetime parameter (milliseconds) for each ac.\n"
+ "wl lifetime be|bk|vi|vo [<value>]"},
+ { "reinit", wl_void, -1, WLC_INIT,
+ "Reinitialize device"},
+ { "sta_info", wl_sta_info, WLC_GET_VAR, -1,
+ "wl sta_info <xx:xx:xx:xx:xx:xx>"},
+ { "staprio", wl_staprio, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get sta priority \n"
+ "Usage: wl staprio <xx:xx:xx:xx:xx:xx> <prio> \n"
+ "<prio>: 0~3"},
+ { "pktq_stats", wl_iov_pktqlog_params, WLC_GET_VAR, -1,
+ "Dumps packet queue log info for [C] common, [A] AMPDU, [N] NAR or [P] power save queues\n"
+ "A:, N: or P: are used to prefix a MAC address (a colon : separator is necessary),\n"
+ "or else C: is used alone. The '+' option after the colon gives more details.\n"
+ "Up to 4 parameters may be given, the common queue is default when no parameters\n"
+ "are supplied\n"
+ "Use '/<PREC>' as suffix to restrict to certain prec indices; multiple /<PREC>/<PREC>/..."
+ "can be used\n"
+ "Also, '//' as a suffix to the MAC address or 'C://' will enable automatic logging of\n"
+ "all prec as they are seen.\n"
+ "Full automatic operation is also possible with the shorthand\n"
+ "'A:' (or 'A://'), 'P:' (or 'P://') etc which scans through all known addresses for\n"
+ "those parameters that take a MAC address.\n"
+ "wl pktq_stats [C:[+]]|[A:[+]|P:[+]|N:[+]<xx:xx:xx:xx:xx:xx>][/<PREC>[/<PREC>]][//]..." },
+ { "bs_data", wl_scb_bs_data, WLC_GET_VAR, -1, "Display per station band steering data\n"
+ "usage: bs_data [options]\n"
+ " options are:\n"
+ " -comma Use commas to separate values rather than blanks.\n"
+ " -tab Use <TAB> to separate values rather than blanks.\n"
+ " -raw Display raw values as received from driver.\n"
+ " -noidle Do not display idle stations\n"
+ " -noreset Do not reset counters after reading" },
+ { "cap", wl_var_getandprintstr, WLC_GET_VAR, -1, "driver capabilities"},
+ { "malloc_dump", wl_print_deprecate, -1, -1, "Deprecated. Folded under 'wl dump malloc"},
+ { "chan_info", wl_chan_info, WLC_GET_VAR, -1, "channel info"},
+ { "add_ie", wl_add_ie, -1, WLC_SET_VAR,
+ "Add a vendor proprietary IE to 802.11 management packets\n"
+ "Usage: wl add_ie <pktflag> length OUI hexdata\n"
+ "<pktflag>: Bit 0 - Beacons\n"
+ " Bit 1 - Probe Rsp\n"
+ " Bit 2 - Assoc/Reassoc Rsp\n"
+ " Bit 3 - Auth Rsp\n"
+ " Bit 4 - Probe Req\n"
+ " Bit 5 - Assoc/Reassoc Req\n"
+ " Bit 7 - Auth Req\n"
+ "Example: wl add_ie 3 10 00:90:4C 0101050c121a03\n"
+ " to add this IE to beacons and probe responses" },
+ { "del_ie", wl_del_ie, -1, WLC_SET_VAR,
+ "Delete a vendor proprietary IE from 802.11 management packets\n"
+ "Usage: wl del_ie <pktflag> length OUI hexdata\n"
+ "<pktflag>: Bit 0 - Beacons\n"
+ " Bit 1 - Probe Rsp\n"
+ " Bit 2 - Assoc/Reassoc Rsp\n"
+ " Bit 3 - Auth Rsp\n"
+ " Bit 4 - Probe Req\n"
+ " Bit 5 - Assoc/Reassoc Req\n"
+ " Bit 7 - Auth Req\n"
+ "Example: wl del_ie 3 10 00:90:4C 0101050c121a03" },
+ { "list_ie", _wl_list_ie, WLC_GET_VAR, -1,
+ "Dump the list of vendor proprietary IEs" },
+ { "rand", wl_rand, WLC_GET_VAR, -1,
+ "Get a 2-byte Random Number from the MAC's PRNG\n"
+ "Usage: wl rand"},
+ { "bcmerrorstr", wl_var_getandprintstr, WLC_GET_VAR, -1, "errorstring"},
+ { "freqtrack", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Set Frequency Tracking Mode (0=Auto, 1=On, 2=OFF)"},
+ { "eventing", wl_eventbitvec, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get hex filter bitmask for MAC event reporting up to application layer"},
+ { "event_msgs_ext", wl_bitvecext, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get bit arbitrary size hex filter bitmask for MAC" },
+ { "event_msgs", wl_eventbitvec, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get hex filter bitmask for MAC event reporting via packet indications"},
+ { "counters", wl_counters, WLC_GET_VAR, -1,
+ "Return driver counter values. \n"
+ "\t wl counters [options]. Options:\n"
+ "\t --nz : only non zero counters\n"
+ "\t --err : only error/warning related counters\n"
+ "\t --rx : only rx specific counters\n"
+ "\t --tx\n"
+ "\t --ctrl : only ctrl/mgmt related counters\n"
+ "\t --ucode : only ucode generated counters\n"
+ "\t --ucast\n"
+ "\t --mcast : only mcast+bcast related counters\n"
+ "\t --sec : security: only tkip/aes/ related counters\n"
+ "\t --ampdu --rx : combine options to narrow down selection\n"
+ "\t --ampdu --invert : use --invert to invert the selection"},
+ { "subcounters", wl_subcounters, WLC_GET_VAR, WLC_SET_VAR,
+ "Return driver counter values of requested counters. \n"
+ "\t wl subcounters <version> <counters list> - To list requested counters\n"
+ "\t wl subcounters - To get the counters version FW is using\n"
+ "\t wl subcounters <version> - List supported counters in given version"},
+ { "if_counters", wl_if_counters, WLC_GET_VAR, -1,
+ "Return driver counter values for current interface." },
+ { "reset_cnts", wl_clear_counters, WLC_GET_VAR, -1,
+ "Clear driver counter values" },
+ { "wlc_ver", wl_wlc_ver, WLC_GET_VAR, -1,
+ "returns wlc interface version" },
+ { "delta_stats_interval", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get the delta statistics interval in seconds (0 to disable)"},
+ { "delta_stats", wl_delta_stats, WLC_GET_VAR, -1,
+ "get the delta statistics for the last interval" },
+ { "swdiv_stats", wl_swdiv_stats, WLC_GET_VAR, -1,
+ "Returns swdiv stats"},
+ { "rxfifo_counters", wl_rxfifo_counters, WLC_GET_VAR, -1,
+ "Returns rxfifo counters"},
+ { "assoc_info", wl_assoc_info, WLC_GET_VAR, -1,
+ "Returns the assoc req and resp information [STA only]" },
+ { "autochannel", wl_auto_channel_sel, WLC_GET_CHANNEL_SEL, WLC_START_CHANNEL_SEL,
+ "auto channel selection: \n"
+ "\t1 to issue a channel scanning;\n"
+ "\t2 to set chanspec based on the channel scan result;\n"
+ "\twithout argument to only show the chanspec selected; \n"
+ "\tssid must set to null before this process, RF must be up"},
+ { "csscantimer", wl_int, WLC_GET_CS_SCAN_TIMER, WLC_SET_CS_SCAN_TIMER,
+ "auto channel scan timer in minutes (0 to disable)" },
+ { "closed", wl_int, WLC_GET_CLOSED, WLC_SET_CLOSED,
+ "hides the network from active scans, 0 or 1.\n"
+ "\t0 is open, 1 is hide" },
+ { "pmkid_info", wl_pmkid_info, WLC_GET_VAR, WLC_SET_VAR,
+ "Returns the pmkid table" },
+ { "probresp_mac_filter", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get MAC filter based Probe response mode. \n"
+ "\t0 - Disable MAC filter based Probe response mode.\n"
+ "\t1 - Enable MAC filter based Probe response mode.\n"
+ "\tNo parameter - Returns the current setting."},
+ { "eap_restrict", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get EAP restriction"},
+ { "reset_d11cnts", wl_var_void, -1, WLC_SET_VAR,
+ "reset 802.11 MIB counters"},
+ { "staname", wl_varstr, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set station name: \n"
+ "\tMaximum name length is 15 bytes"},
+ { "apname", wl_varstr, WLC_GET_VAR, -1,
+ "get AP name"},
+ { "overlay", wl_overlay, WLC_GET_VAR, WLC_SET_VAR,
+ "overlay virt_addr phy_addr size"},
+ { "antgain", wl_antgain, WLC_GET_VAR, WLC_SET_VAR,
+ "Set temp ag0/1 value\n"
+ "usage: wl antgain ag0=0x1 ag1=0x2"
+ },
+ { "phy_antsel", wl_antsel, WLC_GET_VAR, -1,
+ "get/set antenna configuration \n"
+ "\tset: -1(AUTO), 0xAB(fixed antenna selection)\n"
+ "\t\twhere A and B is the antenna numbers used for RF chain 1 and 0 respectively\n"
+ "\tquery: <utx>[AUTO] <urx>[AUTO] <dtx>[AUTO] <drx>[AUTO]\n"
+ "\t\twhere utx = TX unicast antenna configuration\n"
+ "\t\t\turx = RX unicast antenna configuration\n"
+ "\t\t\tdtx = TX default (non-unicast) antenna configuration\n"
+ "\t\t\tdrx = RX default (non-unicast) antenna configuration"
+ },
+ { "txfifo_sz", wl_txfifo_sz, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get the txfifo size; usage: wl txfifo_sz <fifonum> <size_in_bytes>" },
+#if defined(linux)
+ { "escan_event_check", wl_escan_event_check, -1, -1,
+ "Listen and prints the escan events from the dongle\n"
+ "\tescan_event_check syntax is: escan_event_check ifname flag\n"
+ "\tflag 1 = sync_id info, 2 = bss info, 4 = state + bss info [default], "
+ "8 = TLV check for IEs"},
+ { "escanresults", wl_escanresults, -1, WLC_SET_VAR,
+ "Start escan and display results.\n" SCAN_USAGE
+ },
+ { "wl_event_check", wl_event_check, -1, -1,
+ "listen and display brcm events\n"
+ "\tusage:wl -i <ifname> wl_event_check"},
+#endif /* linux */
+
+ { "hs20_ie", wl_hs20_ie, -1, WLC_SET_VAR,
+ "set hotspot 2.0 indication IE\n"
+ "\tusage: wl hs20_ie <length> <hexdata>\n"
+ },
+ {"rate_histo", wl_rate_histo, -1, WLC_GET_VAR,
+ "Get rate hostrogram"
+ },
+ { "wme_apsd_trigger", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Set Periodic APSD Trigger Frame Timer timeout in ms (0=off)"},
+ { "wme_autotrigger", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/Disable sending of APSD Trigger frame when all ac are delivery enabled"},
+ { "reassoc", wl_reassoc, -1, WLC_REASSOC,
+ "Initiate a (re)association request.\n"
+ "\tUsage: wl reassoc <bssid> [options]\n"
+ "\tOptions:\n"
+ "\t-c CL, --chanspecs=CL \tchanspecs (comma or space separated list)"},
+ { "send_nulldata", wl_iov_mac, -1, -1,
+ "Sed a null frame to the specified hw address" },
+ { "srchmem", wl_srchmem, WLC_GET_VAR, WLC_SET_VAR,
+ "g/set ucode srch engine memory"},
+ {"ptk_start", wl_ptk_start, -1, WLC_SET_VAR,
+ "Send specified \"wl_ptk_start \" params .\n"
+ "\tUsage: wl ptk_start <sec type> <awdl peer_addr> <pmk> <role>\n"},
+#ifdef CLMDOWNLOAD
+ { "clmload", wl_clmload, -1, WLC_SET_VAR,
+ "Download CLM data into a driver. Driver must be down.\n"
+ "\tUsage: wl clmload <clm blob file name>\n"
+ "\t Note obsolete syntax 'wl clmload 0/1 <clm blob file name>' is still accepted\n"
+ "\t but the download type 0/1 is no longer applicable and is ignored. Incremental\n"
+ "\t CLM download is no longer supported. Also reverting to the original built-in\n"
+ "\t CLM is no longer supported. (This syntax was 'wl clmload 0/1')"},
+ { "txcapload", wl_txcapload, -1, WLC_SET_VAR,
+ "Download txcap data into a driver. Driver must be down.\n"
+ "\tUsage: wl txcapload <txcap file name>\n"},
+ { "txcapver", wl_var_getandprintstr, WLC_GET_VAR, -1,
+ "List curent txcap downloaded information"},
+ { "txcapconfig", wl_txcapctl, WLC_GET_VAR, WLC_SET_VAR,
+ "Set or get the txcap config setting for the low/high cap selection for each subband"},
+ { "txcapstate", wl_txcapctl, WLC_GET_VAR, WLC_SET_VAR,
+ "Set or get the txcap state setting for the low/high cap selection for each subband"},
+ { "txcapdump", wl_txcapdump, WLC_GET_VAR, -1,
+ "Get txcap dump information. Intended for design verification/debugging as opposed to\n"
+ "\tproduction usage and as such may change with little (or no) notice."},
+#endif /* CLMDOWNLOAD */
+ { "calload", wl_calload, -1, WLC_SET_VAR,
+ "Download CAL data into a driver. Driver must be down.\n"
+ "\tUsage: wl calload <cal file name> to download existing calibration data file\n"},
+ { "caldump", wl_caldump, WLC_GET_VAR, -1,
+ "Dump calibration data and save it with calibration storage format.\n"
+ "\tUsage: wl caldump <cal file name> to dump current calibration info to file\n"},
+ { "calload_chkver", wl_buf, -1, WLC_SET_VAR,
+ "Confirm TxCal load with provided version string"},
+ { "bmac_reboot", wl_var_void, -1, WLC_SET_VAR,
+ "Reboot BMAC"},
+#ifdef RWL_WIFI
+ { "findserver", wl_wifiserver, -1, -1,
+ "Used to find the remote server with proper mac address given by the user,this "
+ "cmd is specific to wifi protocol."},
+#endif
+ { "assertlog", wl_assertlog, WLC_GET_VAR, -1,
+ "get external assert logs\n"
+ "\tUsage: wl assertlog"},
+ { "assert_type", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get the asset_bypass flag; usage: wl assert_type <1/0> (On/Off)"
+ },
+#ifdef BCMWAPI_WAI
+ { "wai_restrict", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get WAI restriction"},
+ { "wai_rekey", wl_iov_mac, -1, -1,
+ "set rekey event"},
+#endif /* BCMWAPI_WAI */
+ {"cca_get_stats", wl_cca_get_stats, WLC_GET_VAR, -1,
+ "Usage: wl cca_stats [-c channel] [-s num seconds][-n]\n"
+ "\t -c channel: Optional. specify channel. 0 = All channels. Default = current channel \n"
+ "\t -n: no analysis of results\n"
+ "\t -s num_seconds: Optional. Default = 10, Max = 60\n"
+ "\t -i: list individual measurements in addition to the averages\n"
+ "\t -curband: Only recommend channels on current band"
+ },
+ { "smfstats", wl_smfstats, WLC_GET_VAR, WLC_SET_VAR,
+ "get/clear selected management frame (smf) stats"
+ "\twl smfstats [-C num]|[--cfg=num] [auth]|[assoc]|[reassoc]|[clear]\n"
+ "\tclear - to clear the stats" },
+#ifdef RWL_DONGLE
+ { "dongleset", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable uart driver"
+ },
+#endif
+ { "manfinfo", wl_var_getandprintstr, WLC_GET_VAR, -1,
+ "show chip package info in OTP"},
+ { "pm_dur", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Retrieve accumulated PM duration information (GET only)\n"
+ },
+ { "mpc_dur", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Retrieve accumulated MPC duration information in ms (GET) or clear accumulator (SET)\n"
+ "\tUsage: wl mpc_dur <any-number-to-clear>"},
+ {"txdelay_params", wl_txdelay_params, WLC_GET_VAR, -1,
+ "get chanim stats \n"
+ "\t Usage: wl txdelay_params ratio cnt period tune"
+ },
+ {"dlystats", wl_dlystats, WLC_GET_VAR, -1,
+ "dump delay statistics\n"
+ "\tUsage: wl dlystats [xx:xx:xx:xx:xx:xx] (optional mac address)\n"
+ "\tIf mac_addr is not specified, dump all of scbs"
+ },
+ {"dlystats_clear", wl_dlystats_clear, -1, WLC_SET_VAR,
+ "clear delay stats \n"
+ "\t Usage: wl dlystats_clear"
+ },
+ {"intfer_params", wl_intfer_params, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get intfer params \n"
+ "\tUsage: wl intfer_params period (in sec) cnt(0~4) txfail_thresh tcptxfail_thresh\n"
+ "\tperiod=0: disable Driver monitor txfail"
+ },
+ { "dngl_wd", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "enable or disable dongle keep alive watchdog timer\n"
+ "\tUsage: wl dngl_wd 0\\1 (to turn off\\on)"},
+ { "tsf", wl_tsf, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get tsf register\n"
+ "\tUsage: wl tsf [<high> <low>]"},
+ { "mac_rate_histo", wl_mac_rate_histo, WLC_GET_VAR, WLC_SET_VAR,
+ "Usage: wl mac_rate_histo <mac address> <access category> <num_pkts>\n"
+ "\t(MAC address e.g. 00:11:20:11:33:33)\n"
+ "\t(Access Category(AC) - 0x10:for entire MAC or 0x4:for video AC for this MAC)\n"
+ "\t(num_pkts (optional) - Number of packets to average - max 64 for AC 0x10,"
+ " max 32 for AC 0x4)"
+ },
+#ifdef SERDOWNLOAD
+ { "rwl_download", rwl_download, -1, WLC_SET_VAR,
+ "rwl_download <firmware> <nvram>\n"
+ "\trwl_download transfer firmware and nvram via remote interface\n"
+ },
+ { "init", dhd_init, WLC_GET_VAR, WLC_SET_VAR,
+ "init <chip_id>\n"
+ "\tInitialize the chip.\n"
+ "\tCurrently only 4325, 4329, 43291, 4330a1 and 4330 (b1) are supported"
+ },
+ { "download", dhd_download, WLC_GET_VAR, WLC_SET_VAR,
+ "download <binfile> <varsfile>\n"
+ "\tdownload file to dongle ram and start CPU\n"
+ "\tvars file will replace vars parsed from the CIS"
+ },
+ { "upload", dhd_upload, WLC_GET_VAR, WLC_SET_VAR,
+ "upload <file> \n"
+ "\tupload the entire memory and save it to the file"
+ },
+#endif /* SERDOWNLOAD */
+ { "rpmt", wl_rpmt, -1, WLC_SET_VAR, "rpmt <pm1-to> <pm0-to>"},
+ { "ie", wl_ie, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get IE\n"
+ "\tUsage: For set: wl ie type length hexdata\n"
+ "\t For get: wl ie type" },
+ { "mempool", wlu_mempool, WLC_GET_VAR, -1,
+ "Get memory pool statistics" },
+ { "leaky_ap_stats", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/disable leaky ap stats collection and reporting\n"
+ "\t0 - disable\n"
+ "\t1 - enable" },
+ { "leaky_ap_sep", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/disable leaky ap to suppress the early packet before guard start time\n"
+ "\t0 - disable\n"
+ "\t1 - enable" },
+#ifdef SR_DEBUG
+ { "sr_dump_pmu", wl_dump_pmu, WLC_GET_VAR, WLC_SET_VAR,
+ "Dump value of PMU registers"},
+ { "sr_pmu_keep_on", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Keep resource on"},
+ { "sr_power_island", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Keep power islands on/off.\n"
+ "Usage: For get:wl sr_power_island\n"
+ " For set:wl sr_power_island 0x????\n"
+ " where ?-> 0 power_island off\n"
+ " ?-> 1 power_island on\n"
+ " eg: wl sr_power_island 0x1101"},
+#endif /* SR_DEBUG */
+ { "antdiv_bcnloss", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "0 - Disable Rx antenna flip feature based on consecutive beacon loss\n"
+ "\tX - beacon loss count after which Rx ant will be flipped\n"
+ "\tUsage: wl antdiv_bcnloss <beaconloss_count>\n"
+ },
+ { "lpc_params", wl_power_sel_params, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get Link Power Control params\n"
+ "\tUsage: wl lpc_params <rate_stab_thresh> <pwr_stab_thresh>\n"
+ "\t\t<lpc_exp_time> <pwrup_slow_step>\n"
+ "\t\t<pwrup_fast_step> <pwrdn_slow_step>\n"},
+ { "nar_clear_dump", wl_var_void, -1, WLC_SET_VAR,
+ "Clear non-aggregated regulation counters"},
+ { "sar_limit", wl_sarlimit, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get sar_limit\n"
+ "\tusage: (set) sar_limit <2Gcore0 2Gcore1 2Gcore2 2Gcore3 5G[0]core0 5G[0]core1...>\n"
+ "\t (get) sar_limit, return sar limit table\n"
+ "\tunit: all input/output values are absolute and in unit of qdbm\n"
+ },
+ { "event_log_set_init", wl_event_log_set_init, -1, WLC_SET_VAR,
+ "Initialize an event log set\n"
+ "\tUsage: wl event_log_set_init <set> <size>\n"},
+ { "event_log_set_expand", wl_event_log_set_expand, -1, WLC_SET_VAR,
+ "Increase the size of an event log set\n"
+ "\tUsage: wl event_log_set_expand <set> <size>\n"},
+ { "event_log_set_shrink", wl_event_log_set_shrink, -1, WLC_SET_VAR,
+ "Decrease the size of an event log set\n"
+ "\tUsage: wl event_log_set_shrink <set> <[size]>\n"},
+ { "event_log_tag_control", wl_event_log_tag_control, -1, WLC_SET_VAR,
+ "Modify the state of an event log tag\n"
+ "\tUsage: wl event_log_tag_control <tag> <set> <flags>\n"},
+ { "event_log_get", wl_event_log_get, -1, WLC_SET_VAR,
+ "\t usage: wl event_log_get [-f <set_num>] [-g <set_num> -s <buf_size>]\n"
+ "\t -f: flush a log buffer of specified set being written to by trigerring logtrace\n"
+ "\t -g: get a log buffer of a specified set that is full but not delivered to host yet\n"
+ "\t Store the contents in a buffer of size specified with -s option\n"
+ "\t Note: Only -f option is currently supported\n"
+ },
+ { "rmc_ar", wl_mcast_ar, WLC_GET_VAR, WLC_SET_VAR,
+ "Set active receiver to the one that matches the provided mac address\n"
+ "If there is no match among current RMC receivers, it will return fail\n"
+ "If mac address is set to all 0 (00:00:00:00:00:00), auto selection mode is enabled\n"
+ "and the transmitter will choose the active receiver automatically by RSSI\n"
+ "\tusage: wl rmc_ar [mac address]\n"
+ "Get the device mac that is set to be the active receiver for this transmitter\n"
+ "\tusage: wl rmc_ar\n"
+ },
+
+ { "pm2_sleep_ret_ext", wl_sleep_ret_ext, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set Dynamic Fast Return To Sleep params"},
+ { "sta_monitor", wl_stamon_sta_config, WLC_GET_VAR, WLC_SET_VAR,
+ "wl sta_monitor [enable|disable|counters|reset_cnts] | [<add/del> <xx:xx:xx:xx:xx:xx>]"},
+ { "monitor_promisc_level", wl_monitor_promisc_level, WLC_GET_VAR, WLC_SET_VAR,
+ "Set a bitmap of different MAC promiscuous level of monitor mode.\n\n"
+ MONITOR_PROMISC_LEVEL_USAGE},
+ { "aibss_bcn_force_config", wl_aibss_bcn_force_config, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set AIBSS beacon force configuration \n"
+ "wl aibss_bcn_force_config <initial_min_bcn_dur,min_bcn_dur,initial_bcn_flood_dur>\n"},
+ {"bcnlenhist", wl_bcnlenhist, WLC_GET_VAR, -1,
+ "Usage: wl bcnlenhist [0]"},
+ { "bss_peer_info", wl_bss_peer_info, WLC_GET_VAR, -1,
+ "Get BSS peer info of all the peer's in the indivudual interface\n"
+ "\tIf a non-zero MAC address is specified, gets the peer info of the PEER alone\n"
+ "\tUsage: wl bss_peer_info [MAC address]"},
+#if defined(BCMDBG) || defined(BCMDBG_DUMP)
+ { "dump_modesw_dyn_bwsw", wl_dump_modesw_dyn_bwsw, WLC_GET_VAR, -1,
+ "Usage : wl dump_modesw_dyn_bwsw" },
+#endif
+ { "pwrstats", wl_pwrstats, WLC_GET_VAR, -1,
+ "Get power usage statistics\n"
+ "Usage: wl pwrstats [<type>] ..."},
+ { "memuse", wl_memuse, WLC_GET_VAR, -1,
+ "Get memory usage statistics\n"
+ "Usage: wl memuse"},
+ { "drift_stats_reset", wl_var_void, -1, WLC_SET_VAR,
+ "Reset drift statistics"},
+ { "aibss_txfail_config", wl_aibss_txfail_config, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get txfail configuration for bcn_timeout, max tx retries and max atim failures\n"
+ "\tUsage: wl aibss_txfail_config [bcn_timeout max_retry max_atim_failure]"},
+ { "ibss_route_tbl", wl_setiproute, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set ibss route table\n"
+ "\tUsage: wl ibss_route_tbl num_entries [{ip_addr1, mac_addr1}, ...]"},
+ { "ip_route_table", wl_setiproute, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set ip route table\n"
+ "\tUsage: wl ip_route_tbl num_entries [{ip_addr1, mac_addr1}, ...]"},
+ { "rsdb_mode", wl_bcm_config, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get the RSDB mode. Possible values auto(-1), mimo(0), rsdb(1), 80p80(2)"},
+ { "desired_bssid", wl_desired_bssid, WLC_GET_DESIRED_BSSID, WLC_SET_DESIRED_BSSID,
+ "Set or get the desired BSS ID value\n"
+ "\tUsage: wl desired_bssid [BSSID]"},
+ { "ht_features", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "disable/enable/force proprietary 11n rates support. Interface must be down." },
+ { "modesw_timecal", wl_modesw_timecal, WLC_GET_VAR, WLC_SET_VAR,
+ "Usage: \n\t wl modesw_timecal 0~1 for disable /enable \n"
+ "\t wl modesw_timecal to get Time statistics" },
+ { "atim", wl_int, WLC_GET_ATIM, WLC_SET_ATIM,
+ "Set/Get the current ATIM window size" },
+ { "pcie_bus_tput", wl_pcie_bus_throughput_params, WLC_GET_VAR, WLC_SET_VAR,
+ "Measure the pcie bus througput\n"
+ "Usage: wl pcie_bus_tput -n 64\n"},
+ { "interface_create", wl_interface_create_action, -1, WLC_GET_VAR,
+ "create an AP/STA interface on a WLC instance that receives the IOVAR\n"
+ "\tUsage: wl interface_create ap/sta [MAC-address]\n"
+ "MAC-address: xx:xx:xx:xx:xx:xx"
+ },
+ { "interface_remove", wl_interface_remove_action, -1, WLC_SET_VAR,
+ "Deletes the interface on which this command is received\n"
+ "\tUsage:\n\t wl interface_remove\n"
+ "\t wl -i <interface_name> interface_remove \n"
+ "\t wl interface_remove -C <bss_cfg_index> \n"
+ },
+ {"phy_txpwrcap_tbl", wl_phy_txpwrcap_tbl, WLC_GET_VAR, WLC_SET_VAR,
+ "Get the stored txpwr cap table:\n"
+ "\t\twl phy_txpwrcap_tbl\n"
+ "\tSet the txpwr cap table:\n"
+ "\t\twl phy_txpwrcap_tbl <Na0> <Na1> <Na2> <Na3> <Na4> <Na5> <Na6> <Na7>"
+ " <Cap_cell_ON> <Cap_cell_OFF>\n"
+ "\t\tNaX: Number of Antennas on Core X\n"
+ "\t\tCap_cell_ON: Pwr caps for valid antennas on all cores for Cell On status\n"
+ "\t\tCap_cell_OFF: Pwr caps for valid antennas on all cores for Cell Off status\n"
+ "\t\tPwr Caps are in qdBm, int8 format. Cap_cell_OFF values are optional.\n"},
+ { "bcntrim_stats", wl_bcntrim_stats, WLC_GET_VAR, -1,
+ "Get Beacon Trim Statistics\n"
+ "\tUsage: wl bcntrim_stats\n"},
+#ifdef ATE_BUILD
+ { "gpaio", wl_gpaio, NULL, WLC_SET_VAR,
+ "Configure the GPAIO using different options as follows:\n\n"
+ "\tgpaio pmu_afeldo\n\n"
+ "\tgpaio pmu_txldo\n\n"
+ "\tgpaio pmu_vcoldo\n\n"
+ "\tgpaio pmu_lnaldo\n\n"
+ "\tgpaio pmu_adcldo\n\n"
+ "\tgpaio clear\n\n"},
+#endif
+ { "dfs_ap_move", wl_dfs_ap_move, WLC_GET_VAR, WLC_SET_VAR,
+ "Move the AP interface to dfs channel specified:\n"
+ "\t Default: Get the dfs scan status\n"
+ "\t -1: Abort recent AP move request (if in progress)\n"
+ "\t -2: Stunt recent AP move request (if in progress)\n"
+ "\t20MHz : [5g]<channel>[/20]\n"
+ "\t40MHz : [5g]<channel>/40[u,l]\n"
+ "\t80MHz : [5g]<channel>/80\n"
+ "\tchannel number (36-200)\n"
+ "\tbandwidth, 20, 40, or 80, default 20\n"
+ "\tprimary sideband for 40MHz on 2g, l=lower, u=upper\n"
+ "OR Set channel with legacy format:\n"
+ "\t-c channel number (36-224)\n"
+ "\t-w bandwidth 20 or 40\n"
+ "\t-s ctl sideband, -1=lower, 0=none, 1=upper"},
+ {"pmac", wl_macdbg_pmac, WLC_GET_VAR, -1,
+ "Get mac obj values such as of SHM and IHR\n"
+ "\tusage: wl pmac <type> <addresses up to 16> -s <step size>"
+ " -n <num> -b <bitmap> -w <write val> -r\n"
+ "<addresses> : a single address, or multiple, upto 16 addresses, in Decimal or Hex\n"
+ "<step size> = 0 or 2 or 4\n"
+ "<num> : how many to print\n"
+ "<bitmap> : 32-bit value\n"
+ "<w_val> : write value to the registers\n"
+ "-r option is used to specify internal address:"},
+ { "vasip_counters_clear", wl_var_void, -1, WLC_SET_VAR,
+ "clear vasip counters"},
+ {"svmp_mem", wl_svmp_mem, WLC_GET_VAR, WLC_SET_VAR,
+ "Usage: wl svmp_mem <offset> <len> [ <val> ]\n"
+ "With 2 params, read svmp memory at offset for len of 16-bit width.\n"
+ "With 3rd param, set the same range to the given value\n"},
+ {"mu_rate", wl_mu_rate, WLC_GET_VAR, WLC_SET_VAR,
+ "Force the tranmission rate for each user, rate0 is for user0; rate1 is for user1...\n"
+ "Usage: wl mu_rate { [auto | -1] | [[rate0] [rate1] [rate2] [rate3]]\n"
+ "no input: read current MU-MIMO rate.\n"
+ "auto or -1: turn on auto rate.\n"},
+ {"mu_group", wl_mu_group, WLC_GET_VAR, WLC_SET_VAR,
+ "Force the group recommendation result or set parameters for VASIP group recomendation\n"
+ "\tUsage: no parameters means getting configs\n"
+ "\t 'wl mu_group [-g P0 [P01 P02 ... P04] [... -g Px [Px1 Px2 ... Px4]]] [-f F]'\n"
+ "\t 'wl mu_group [-g -1] [-m M] [-n N]'\n"
+ "\t Combination of '-g 0 XXX' with '-m M' or '-n N' is invalid\n"
+ "\t Example1: wl mu_group -g 0 0x016 0x209 0x309 -g 1 0x009 0x217 -g 2 0x115 0x308\n"
+ "\t Example2: wl mu_group -g 0 0x007 0x109 0x209 0x308 -f 0\n"
+ "\t Example3: wl mu_group -g -1\n"
+ "\t Example4: wl mu_group -g -1 -m 1 -n 4\n"
+ "\t Example5: wl mu_group -m 1 -n 4 (only valid under auto grouping)\n"
+ "\t -g: Force group recommendation (x<=7, up to 8 options)\n"
+ "\t P0=-1 means VASIP group recommendation (not-forced mode, default)\n"
+ "\t P0~Px are expected to be 0~x in forced mode\n"
+ "\t Pxy: three nibbles for (user_id<<8 + (user_nss-1)<<4 + user_mcs)\n"
+ "\t -f: Force MCS and only valid with '-g 0 XXX'\n"
+ "\t F=0: auto MCS from VASIP MCS recommendation\n"
+ "\t F=1: forced MCS according to '-g' argument (default when froced grouping)\n"
+ "\t -m: Method for VASIP group recommendation, M>=0\n"
+ "\t M=0: old method: 1 group for all admitted users with GID=9\n"
+ "\t M>0: new method: M=1 for N best THPT groups\n"
+ "\t -n: Number of groups reported to MAC for VASIP group recommendation, N=1~15"},
+ {"mu_policy", wl_mu_policy, WLC_GET_VAR, WLC_SET_VAR,
+ "Configure the MU admission control policies\n"
+ "\tUsage: no parameters means getting configs\n"
+ "\t 'wl mu_policy [-sched_timer T] [-pfmon P] [-pfmon_gpos G] [-samebw B]"
+ " [-nrx R] [-max_muclients C]'\n"
+ "\t Example1: wl mu_policy -sched_timer 60 -pfmon 1 -pfmon_gpos 0 -samebw 0 -nrx 1\n"
+ "\t Example2: wl mu_policy -sched_timer 0\n"
+ "\t Example3: wl mu_policy -pfmon 0\n"
+ "\t Example4: wl mu_policy -nrx 2\n"
+ "\t Example5: wl mu_policy -max_muclients 4\n"
+ "\t -sched_timer: Configure the timer interval for the score based MU client scheduler\n"
+ "\t T=0 means the scheduler is disabled\n"
+ "\t T>0 means the timer duration in seconds (default 60)\n"
+ "\t -pfmon: Configure the perfomance monitors (mutxcnt and gpos)'\n"
+ "\t P=0: Disable the perfomance monitors\n"
+ "\t P=1: Enable the perfomance monitors and black lists\n"
+ "\t -pfmon_gpos: Configure the gpos performance monitor\n"
+ "\t G=0: Disable the gpos performance monitor\n"
+ "\t G=1: Enable the gpos performance monitor\n"
+ "\t -samebw: Configure the BW check at admission control\n"
+ "\t B=0: Allow clients with different BW to be admitted\n"
+ "\t B=1: Only clients with the same BW can be admitted\n"
+ "\t -nrx: Configure the max nrx (number of RX streams) of the clients\n"
+ "\t R=1: Only 1x1 MU STAs can be admitted\n"
+ "\t R=2: Both 1x1 and 2x2 MU STAs can be admitted\n"
+ "\t -max_muclients: Configure the max number of clients\n"
+ "\t C: Can be a value between 2~8"},
+#if defined(BCMDBG) || defined(BCMDBG_DUMP)
+ { "svmp_sampcol", wl_svmp_sampcol, WLC_GET_VAR, WLC_SET_VAR,
+ "No parameters means getting configs\n"
+ "\tOptional parameters for BCM4365 are:\n"
+ "\t-e enable capture, 0: enable, 1: disable,"
+ "without this field means setting configs only\n"
+ "\t-t trigger mode, 0: pkt-proc transition trigger (need 2 additional states setting),"
+ "1: force immediate trigger, 2: radar-det trigger\n"
+ "\t-w waiting counter in sample (default: 0)\n"
+ "\t-l capture length in sample (default: 128)\n"
+ "\t-s source select, set phy1_mux and rx1_mux\n"
+ "\t\tphy1_mux, 0: gpioOut, 1: fftOut, 2: dbgHx, 3: rx1mux\n"
+ "\t\trx1_mux, 4: farrowOut, 6: dcFilterOut, 7: rxFilterOut, 8: aciFilterOut\n"
+ "\t-d dual capture mode, use ACPHY sample_collect HW (default: off)\n"
+ "\t\tdata_mux, 4: farrowOut, 5: iqCompOut, 6: dcFilterOut, 7: rxFilterOut\n"
+ "\t-r samplerate, 0: 1xBW, 1: 2xBW (only farrowOut supports 2xBW)\n"
+ "\t-p memory packing selection, set packing_mode, packing_order, packing_format,"
+ "single-core selection (default 1 0 0 0)\n"
+ "\t\tpacking_mode, 0: for dual capture, 1: 4-core, 2: first 2-core, 3: single-core\n"
+ "\t\tpacking_order, 0: big endian, 1: little endian\n"
+ "\t\tpacking_format, 0: IQswap of cfix, 1: VASIP cfix format,"
+ "4365A0/B0 only supports IQswap of cfix\n"
+ "\t\tsingle-core selection, 0~3 (4365A0/B0 only forces to core0)\n"
+ "\t-a SVMP buffer address in word size, set addr_start and addr_end"
+ "(default 0x25800 0x26800)\n"
+ "\t-i send interrupt to VASIP when capture done (default 1)\n"},
+#endif
+ { "scanmac", wl_scanmac, WLC_GET_VAR, WLC_SET_VAR,
+ "Configure scan MAC using subcommands:\n"
+ "\tscanmac enable <0|1>\n"
+ "\tscanmac bsscfg\n"
+ "\tscanmac config <mac> <random_mask> <scan_bitmap>\n"},
+ {"mkeep_alive", wl_mkeep_alive, WLC_GET_VAR, WLC_SET_VAR,
+ "Send specified \"mkeep-alive\" packet periodically.\n"
+ "Usage: wl mkeep_alive <index0-7> [[<immediate>] <period> <packet>]\n"
+ "\tindex: 0 - 7 (for set or get).\n"
+ "\timmediate: Send first packet immediately.\n"
+ "\tperiod: Re-transmission period in msecs, 0 to disable.\n"
+ "\tpacket: Hex packet contents to transmit. The packet contents should\n"
+ "\t include the entire ethernet packet (ethernet header, IP header, UDP\n"
+ "\t header, and UDP payload) specified in network byte order. If no\n"
+ "\t packet is specified, a nulldata frame will be sent instead.\n\n"
+ "E.g. Send keep alive packet every 30 seconds using id-1:\n"
+ "\twl mkeep_alive 1 30000 0x0014a54b164f000f66f45b7e08004500001e000040004011c"
+ "52a0a8830700a88302513c413c4000a00000a0d\n" },
+ { "tcmstbl", wl_get_tcmstbl_entry, WLC_GET_VAR, -1,
+ "Returns the total power in hdBm and the Tx core Mask for the combination: \n"
+ "\t-c core number (0-7) default 0\n"
+ "\t-s cell status (0 or 1) default 0\n"
+ "\t-a antenna map (each nibble holds one core, core0 LSB) default 0x0 \n"},
+ { "dfs_max_safe_tx", wl_dfs_max_safe_tx, WLC_GET_VAR, WLC_SET_VAR,
+ "Thresholds for tx traffic on main core. On crossing this threshold, scan core \n"
+ "background DFS scan results may be discarded depending on dfs_txblank_check_mode.\n"
+ "\t Default: Get the dfs max safe tx thresholds for non-adjacent (and adjacent) cases.\n"},
+ { "dfs_txblank_check_mode", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Control if tx on main core must be considered at end of background CAC on scan core.\n"
+ "\t Default: Get the dfs txblank check mode.\n"},
+ { "nd_ra_limit_intv", wl_nd_ra_limit_intv, WLC_GET_VAR, WLC_SET_VAR,
+ "Get / Set IPv6 RA rate limit interval\n"
+ "\tUsage(Set): nd_ra_limit_intv -t <type> -p <percentage(<100)> -m <fixed time>\n"
+ "\t : nd_ra_limit_intv -t 0 -p XX -m YYY\n"
+ "\t : nd_ra_limit_intv -t 1 -m ZZZ\n"
+ "\tUsage(Get): nd_ra_limit_intv\n"
+ "\t<type> 0: percentage of lifetime, 1: fixed time\n"},
+ {"sim_PM", wl_sim_pm, WLC_GET_VAR, WLC_SET_VAR,
+ "Set the fw into a simulated PM in idle associated mode\n"
+ "\t[0 / 1] - Disable / Enable\n\t-c - Cycle time in TUs (max 10,000)\n\t-u Up time in TUs "
+ "(max 1000)\n"},
+ { "wowl_arp_hostip", wl_hostip, WLC_GET_VAR, WLC_SET_VAR,
+ "Add a host-ip address or display them"},
+ { "arp_hostip_clear", wl_var_void, -1, WLC_SET_VAR,
+ "Clear all host-ip addresses"},
+ { "hc", wl_hc, WLC_GET_VAR, WLC_SET_VAR,
+ "Health Check command group\n"
+ "\tusage: wl hc tx <attribute> [value]\n"
+ "\tusage: wl hc rx <attribute> [value]\n"
+ "\tGet or Set tx/rx attribute values"},
+ {"fbt_r0kh_id", wl_varstr, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set R0 Key Holder Idenitifer for an interface\n"
+ "\tUsage: wl fbt_r0kh_id <string>\n"
+ "String: Maximum 48 byte R0 Key Holder ID\n"},
+ {"fbt_r1kh_id", wl_iov_mac, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set 802.11r R1 Key Holder Idenitifer for an interface\n"
+ "\tUsage: wl fbt_r1kh_id <mac-address>\n"
+ "MAC-address: xx:xx:xx:xx:xx:xx\n"},
+ {"fbt_auth_resp", wl_varstr, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set fbt auth response for an interface\n"
+ "\tUsage: wl fbt_auth_resp <string>\n"
+ "String: Maximum 48 byte FBT auth response\n"},
+ { "icmp_hostip", wl_hostip, WLC_GET_VAR, WLC_SET_VAR,
+ "Add a host-ip address or display current address set"},
+ { "icmp_hostipv6", wl_hostipv6_extended, WLC_GET_VAR, WLC_SET_VAR,
+ "Set host-ipv6 address or display current addresses set for icmp offloads\n"
+ "\tUse NULL ipv6 address - :: to flush all addresses\n"
+ "Usage:\n\tSET: wl icmp_hostipv6 <ipv6addr1> <ipv6addr2>\n"
+ "\tGET: wl icmp_hostipv6"},
+ {"wake_timer", wl_wake_timer, WLC_GET_VAR, WLC_SET_VAR,
+ "\tSend wake event to host periodically\n"
+ "\tUsage : wl wake_timer <period> <limit>\n"
+ "\t<period>: value in ms\n"
+ "\t<limit>: value to specify num of events\n"
+ "\t\t 0 : disable\n"
+ "\t\t 0xFFFF : Infinite\n"
+ "\t\t non-zero value: num of events\n"},
+ { "idauth", wl_idauth, WLC_GET_VAR, WLC_SET_VAR,
+ "IDAUTH command group\n"
+ "\tusage: wl idauth config -a 0/1 -b 1000 -c 3 -e 1000 -g 1000 -m 10\n"
+ "\t\t-a: authentication offload enable/disable \n"
+ "\t\t-c: EAPOL retry count\n"
+ "\t\t-e: EAPOL retry Interval\n"
+ "\t\t-g: GTK rotation interval\n"
+ "\t\t-m: MIC fail count for blacklist\n"
+ "\t\t-b: Blacklist age\n"
+ "\tusage: wl idauth peer_info\n"
+ "\tusage: wl idauth counters\n"},
+ { "utrace_capture", wl_utrace_capture, WLC_GET_VAR, -1,
+ "Read the template RAM for ucode trace data.\n"},
+ { "wds_ap_ifname", wl_wds_ap_ifname, WLC_GET_VAR, -1,
+ "Get associated AP interface name for WDS interface."},
+ { "netx_ping", wl_hostip, -1, WLC_SET_VAR,
+ "Add a host-ip address or display them"},
+ { "netx_ifconfig", wl_netx_ifconfig, WLC_GET_VAR, WLC_SET_VAR,
+ "Configure the Netx interface, or display current settings\n"
+ "\tUsage: wl netx_ifconfig [<ip> <netmask> <gateway>]\n"},
+#ifdef TBTT_OFFSET_STAT
+ { "tbtt_offset_stat", wl_tbtt_offset_stat, WLC_GET_VAR, -1,
+ "Get TBTT offset stat (only for STA mode)\n"
+ "\tUsage: wl tbtt_offset_stat\n"},
+#endif /* TBTT_OFFSET_STAT */
+ { NULL, NULL, 0, 0, NULL }
+};
+
+cmd_t wl_varcmd = {"var", wl_varint, -1, -1, "unrecognized name, type -h for help"};
+
+#ifdef WC_TOOL
+/* Include any commands for wc tool used for WMM
+ * These need to be only the command names from port_cmds and wl_cmds array
+ */
+static const char *wc_cmds[] = {
+ "ver", "cmds", "up", "down",
+ "gmode", "listen", "wme", "wme_ac", "wme_apsd",
+ "wme_apsd_sta", "wme_dp"
+};
+#else
+static const char **wc_cmds = NULL;
+#endif /* WC_TOOL */
+
+
+static const char *dfs_cacstate_str[WL_DFS_CACSTATES] = {
+ "IDLE",
+ "PRE-ISM Channel Availability Check(CAC)",
+ "In-Service Monitoring(ISM)",
+ "Channel Switching Announcement(CSA)",
+ "POST-ISM Channel Availability Check",
+ "PRE-ISM Ouf Of Channels(OOC)",
+ "POST-ISM Out Of Channels(OOC)"
+};
+
+#define MAX_MODULES 256
+static cmd_t* module_cmds[MAX_MODULES];
+static int module_count = 0;
+
+/* register commands for a module */
+void
+wl_module_cmds_register(cmd_t *cmds)
+{
+ if (cmds == NULL)
+ return;
+
+ if (module_count < MAX_MODULES) {
+ module_cmds[module_count] = cmds;
+ module_count++;
+ }
+ else
+ fprintf(stderr, "err - module count over %d\n", MAX_MODULES);
+}
+
+/* common function to find a command */
+cmd_t *
+wlu_find_cmd(char *name)
+{
+ int i;
+ cmd_t *cmd = NULL;
+
+ /* search cmd in modules */
+ for (i = 0; i < module_count; i++) {
+
+ /* search cmd in one cmd table */
+ for (cmd = module_cmds[i]; cmd->name; cmd++) {
+ /* stop if we find a matching name */
+ if (!strcmp(cmd->name, name)) {
+ break;
+ }
+ }
+
+ /* if a match was found, break out of module loop */
+ if (cmd->name != NULL) {
+ break;
+ }
+ }
+
+ return (cmd->name != NULL) ? cmd : NULL;
+}
+
+/* return global ioctl_version */
+int
+wl_get_ioctl_version(void)
+{
+ return ioctl_version;
+}
+
+/* return the address of bufstruct_wlu, global buf */
+char *
+wl_get_buf(void)
+{
+ return buf;
+}
+
+/* initialize stuff needed before processing the command */
+void
+wl_cmd_init(void)
+{
+ int_fmt = INT_FMT_DEC;
+ g_wlc_idx = -1;
+}
+
+void
+wlu_init(void)
+{
+ /* Init global variables at run-time, not as part of the declaration.
+ * This is required to support init/de-init of the driver. Initialization
+ * of globals as part of the declaration results in non-deterministic
+ * behaviour since the value of the globals may be different on the
+ * first time that the driver is initialized vs subsequent initializations.
+ */
+ int_fmt = INT_FMT_DEC;
+ g_wlc_idx = -1;
+ batch_in_client = FALSE;
+ init_cmd_batchingmode();
+
+ /* register general wl commands */
+ wl_module_cmds_register(wl_cmds);
+
+ /* add wluc module init here */
+ wluc_phy_module_init();
+ wluc_wnm_module_init();
+ wluc_cac_module_init();
+ wluc_rmc_module_init();
+ wluc_rrm_module_init();
+ wluc_wowl_module_init();
+ wluc_pkt_filter_module_init();
+ wluc_mfp_module_init();
+ wluc_ota_module_init();
+ wluc_bssload_module_init();
+ wluc_stf_module_init();
+ wluc_offloads_module_init();
+ wluc_tpc_module_init();
+ wluc_toe_module_init();
+ wluc_arpoe_module_init();
+ wluc_keep_alive_module_init();
+ wluc_ap_module_init();
+ wluc_ampdu_module_init();
+ wluc_ampdu_cmn_module_init();
+ wluc_bmac_module_init();
+ wluc_ht_module_init();
+ wluc_wds_module_init();
+ wluc_keymgmt_module_init();
+ wluc_scan_module_init();
+ wluc_obss_module_init();
+ wluc_prot_obss_module_init();
+ wluc_lq_module_init();
+ wluc_seq_cmds_module_init();
+ wluc_btcx_module_init();
+ wluc_led_module_init();
+ wluc_interfere_module_init();
+ wluc_ltecx_module_init();
+#ifdef WLEXTLOG
+ wluc_extlog_module_init();
+#endif /* WLEXTLOG */
+#ifdef WL_NAN
+ wluc_nan_module_init();
+#endif /* WL_NAN */
+#ifdef WLNDOE
+ wluc_ndoe_module_init();
+#endif /* WLNDOE */
+#ifdef WLPFN
+ wluc_pfn_module_init();
+#endif /* WLPFN */
+#ifdef BT_WIFI_HANDOVER
+ wluc_tbow_module_init();
+#endif /* BT_WIFI_HANDOVER */
+#ifdef WLP2P
+ wluc_p2p_module_init();
+#endif /* WLP2PO */
+#ifdef WLTDLS
+ wluc_tdls_module_init();
+#endif /* WLTDLS */
+#ifdef TRAFFIC_MGMT
+ wluc_trf_mgmt_module_init();
+#endif /* TRAFFIC_MGMT */
+#ifdef WL_PROXDETECT
+ wluc_proxd_module_init();
+#endif /* WL_PROXDETECT */
+#ifdef WLP2PO
+ wluc_p2po_module_init();
+#endif /* WLP2PO */
+#ifdef WLANQPO
+ wluc_anqpo_module_init();
+#endif /* WLANQPO */
+#ifdef WL_BTCDYN
+ wluc_btcdyn_module_init();
+#endif /* WL_BTCDYN */
+#ifdef WLMESH
+ wluc_mesh_module_init();
+#endif /* WLMESH */
+#ifdef WL_MSCH
+ wluc_msch_module_init();
+#endif /* WL_MSCH */
+#ifdef WLBDO
+ wluc_bdo_module_init();
+#endif /* WLBDO */
+#ifdef WL_RANDMAC
+ wluc_randmac_module_init();
+#endif /* WL_RANDMAC */
+#ifdef WLTKO
+ wluc_tko_module_init();
+#endif /* WLTKO */
+#ifdef WL_NATOE
+ wluc_natoe_module_init();
+#endif /* WL_NATOE */
+#ifdef WLRSDB
+ wluc_rsdb_module_init();
+#endif
+ wluc_he_module_init();
+#ifdef WL_MBO
+ wluc_mbo_module_init();
+#endif /* WL_MBO */
+#ifdef ECOUNTERS
+ wluc_ecounters_module_init();
+#endif
+#ifdef HOFFLOAD_MODULES
+ wluc_hoffload_module_init();
+#endif /* HOFFLOAD_MODULES */
+}
+
+int wlc_ver_major(void *wl)
+{
+ int err;
+ wl_wlc_version_t wlc_ver;
+
+ memset(&wlc_ver, 0, sizeof(wlc_ver));
+ err = wlu_iovar_get(wl, "wlc_ver", &wlc_ver, sizeof(wl_wlc_version_t));
+ if (err != BCME_OK) {
+ printf("Unable to get wlc_ver iovar %d\n", err);
+ /* old firmware may not support it */
+ return 0;
+ }
+ return wlc_ver.wlc_ver_major;
+}
+
+int
+wl_check(void *wl)
+{
+ int ret;
+ int val;
+
+ if ((ret = wlu_get(wl, WLC_GET_MAGIC, &val, sizeof(int))) < 0)
+ return ret;
+
+ /* Detect if IOCTL swapping is necessary */
+ if (val == (int)bcmswap32(WLC_IOCTL_MAGIC))
+ {
+ val = bcmswap32(val);
+ g_swap = TRUE;
+ }
+ if (val != WLC_IOCTL_MAGIC)
+ return -1;
+ if ((ret = wlu_get(wl, WLC_GET_VERSION, &val, sizeof(int))) < 0)
+ return ret;
+ ioctl_version = dtoh32(val);
+ if (ioctl_version != WLC_IOCTL_VERSION &&
+ ioctl_version != 1) {
+ fprintf(stderr, "Version mismatch, please upgrade. Got %d, expected %d or 1\n",
+ ioctl_version, WLC_IOCTL_VERSION);
+ return -1;
+ }
+ return 0;
+}
+
+int
+ARGCNT(char **argv)
+{
+ int i;
+
+ for (i = 0; argv[i] != NULL; i ++)
+ ;
+ return i;
+}
+
+/* parse/validate the command line arguments */
+/*
+ * pargv is updated upon return if the first argument is an option.
+ * It remains intact otherwise.
+ */
+int
+wl_option(char ***pargv, char **pifname, int *phelp)
+{
+ char *ifname = NULL;
+ int help = FALSE;
+ int status = CMD_OPT;
+ char **argv = *pargv;
+
+ while (*argv) {
+ /* select different adapter */
+ if (!strcmp(*argv, "-a") || !strcmp(*argv, "-i")) {
+ char *opt = *argv++;
+ ifname = *argv;
+ if (!ifname) {
+ fprintf(stderr,
+ "error: expected interface name after option %s\n", opt);
+ status = CMD_ERR;
+ break;
+ }
+ }
+ /* integer output format */
+ else if (!strcmp(*argv, "-d"))
+ int_fmt = INT_FMT_DEC;
+ else if (!strcmp(*argv, "-u"))
+ int_fmt = INT_FMT_UINT;
+ else if (!strcmp(*argv, "-x"))
+ int_fmt = INT_FMT_HEX;
+
+ /* command usage */
+ else if (!strcmp(*argv, "-h") || !strcmp(*argv, "--help"))
+ help = TRUE;
+
+ else if (!strcmp(*argv, "--clientbatch")) {
+ wl_seq_batch_in_client(TRUE);
+ }
+ /* To handle endian mis-matches between wl utility and wl driver */
+ else if (!strcmp(*argv, "--es")) {
+ g_swap = TRUE;
+ }
+ else if (!stricmp(*argv, "-W") || !strcmp(*argv, "--wlc")) {
+ char *opt = *argv++;
+ char *endptr = NULL;
+ if (*argv) {
+ g_wlc_idx = strtol(*argv, &endptr, 0);
+ }
+ if (endptr == *argv) {
+ fprintf(stderr,
+ "error: expected wlc integer index after option %s\n", opt);
+ status = CMD_ERR;
+ /* just to ensure that we trigger error */
+ argv--;
+ break;
+ }
+ }
+ /* start of non wl options */
+ else {
+ status = CMD_WL;
+ break;
+ }
+ /* consume the argument */
+ argv ++;
+ break;
+ }
+
+ *phelp = help;
+ *pifname = ifname;
+ *pargv = argv;
+
+ return status;
+}
+
+void
+wl_cmd_usage(FILE *fid, cmd_t *cmd)
+{
+ if (strlen(cmd->name) >= 8)
+ fprintf(fid, "%s\n\t%s\n\n", cmd->name, cmd->help);
+ else
+ fprintf(fid, "%s\t%s\n\n", cmd->name, cmd->help);
+}
+
+static int
+wl_print_deprecate(void *wl, cmd_t *cmd, char **argv)
+{
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(argv);
+
+ wl_cmd_usage(stderr, cmd); /* warning string is in command table */
+ return 0;
+}
+
+/* Dump out short list of commands */
+static int
+wl_list(void *wl, cmd_t *garb, char **argv)
+{
+ cmd_t *cmd;
+ int nrows, i, len;
+ char *list_buf;
+ int letter, col, row, pad;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(garb);
+ UNUSED_PARAMETER(argv);
+
+ nrows = 0;
+ for (i = 0; i < module_count; i++) {
+ for (cmd = module_cmds[i]; cmd->name; cmd++)
+ /* Check for wc_cmd */
+ if (wc_cmd_check(cmd->name))
+ nrows++;
+ }
+
+ nrows /= 4;
+ nrows++;
+
+ len = nrows * 80 + 2;
+ list_buf = malloc(len);
+ if (list_buf == NULL) {
+ fprintf(stderr, "Failed to allocate buffer of %d bytes\n", len);
+ return BCME_NOMEM;
+ }
+ for (i = 0; i < len; i++)
+ *(list_buf+i) = 0;
+
+ row = col = 0;
+ for (letter = 'a'; letter < 'z'; letter++) {
+ for (i = 0; i < module_count; i++) {
+ for (cmd = module_cmds[i]; cmd->name; cmd++) {
+ /* Check for wc_cmd */
+ if (!wc_cmd_check(cmd->name))
+ continue;
+ if (cmd->name[0] == letter || cmd->name[0] == letter - 0x20) {
+ strcat(list_buf+row*80, cmd->name);
+ pad = 18 * (col + 1) - strlen(list_buf+row*80);
+ if (pad < 1)
+ pad = 1;
+ for (; pad; pad--)
+ strcat(list_buf+row*80, " ");
+ row++;
+ if (row == nrows) {
+ col++; row = 0;
+ }
+ }
+ }
+ }
+ }
+ for (row = 0; row < nrows; row++)
+ printf("%s\n", list_buf+row*80);
+
+ printf("\n");
+
+ free(list_buf);
+ return (0);
+}
+
+void
+wl_cmds_usage(FILE *fid, cmd_t *port_cmds)
+{
+ cmd_t *port_cmd;
+ cmd_t *cmd;
+ int i;
+
+ /* print usage of port commands */
+ for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++)
+ /* Check for wc_cmd */
+ if (wc_cmd_check(port_cmd->name))
+ wl_cmd_usage(fid, port_cmd);
+
+ /* print usage of common commands without port counterparts */
+ for (i = 0; i < module_count; i++) {
+ for (cmd = module_cmds[i]; cmd->name; cmd++) {
+ /* search if port counterpart exists */
+ for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++)
+ if (!strcmp(port_cmd->name, cmd->name))
+ break;
+ /* Also, check for this being a wc_cmd */
+ if ((!port_cmd || !port_cmd->name) && (wc_cmd_check(cmd->name)))
+ wl_cmd_usage(fid, cmd);
+ }
+ }
+}
+
+void
+wl_usage(FILE *fid, cmd_t *port_cmds)
+{
+ fprintf(fid, "Usage: %s [-a|i <adapter>]"
+ " [-h] [-d|u|x] [-w|--wlc <index>] <command> [arguments]\n", wlu_av0);
+
+ fprintf(fid, "\n");
+ fprintf(fid, " -h this message and command descriptions\n");
+ fprintf(fid, " -h [cmd] command description for cmd\n");
+ fprintf(fid, " -a, -i adapter name or number\n");
+ fprintf(fid, " -d output format signed integer\n");
+ fprintf(fid, " -u output format unsigned integer\n");
+ fprintf(fid, " -x output format hexdecimal\n");
+ fprintf(fid, " -w <idx> index of WLC for RSDB only\n");
+ fprintf(fid, "\n");
+
+ wl_cmds_usage(fid, port_cmds);
+}
+
+void
+wl_printint(int val)
+{
+ switch (int_fmt) {
+ case INT_FMT_UINT:
+ printf("%u\n", val);
+ break;
+ case INT_FMT_HEX:
+ printf("0x%x\n", val);
+ break;
+ case INT_FMT_DEC:
+ default:
+ printf("%d\n", val);
+ break;
+ }
+}
+
+
+/* Common routine to check for an option arg specifying the configuration index.
+ * Takes the syntax -C num, --cfg=num, --config=num, or --configuration=num
+ * Returns BCME_BADARG if there is a command line parsing error.
+ * Returns 0 if no error, and sets *consumed to the number of argv strings
+ * used. Sets *bsscfg_idx to the index to use. Will set *bsscfg_idx to zero if there
+ * was no config arg.
+ */
+int
+wl_cfg_option(char **argv, const char *fn_name, int *bsscfg_idx, int *consumed)
+{
+ miniopt_t mo;
+ int opt_err;
+
+ *bsscfg_idx = 0;
+ *consumed = 0;
+
+ miniopt_init(&mo, fn_name, NULL, FALSE);
+
+ /* process the first option */
+ opt_err = miniopt(&mo, argv);
+
+ /* check for no args or end of options */
+ if (opt_err == -1)
+ return 0;
+
+ /* check for no options, just a positional arg encountered */
+ if (mo.positional)
+ return 0;
+
+ /* check for error parsing options */
+ if (opt_err == 1)
+ return BCME_USAGE_ERROR;
+
+ /* check for -C, --cfg=X, --config=X, --configuration=X */
+ if (mo.opt == 'C' ||
+ !strcmp(mo.key, "cfg") ||
+ !strcmp(mo.key, "config") ||
+ !strcmp(mo.key, "configuration")) {
+ if (!mo.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an integer for the configuartion index\n",
+ fn_name, mo.valstr);
+ return BCME_BADARG;
+ }
+ *bsscfg_idx = mo.val;
+ *consumed = mo.consumed;
+ }
+
+ return 0;
+}
+
+int
+wl_void(void *wl, cmd_t *cmd, char **argv)
+{
+ UNUSED_PARAMETER(argv);
+
+ if (cmd->set < 0)
+ return -1;
+ return wlu_set(wl, cmd->set, NULL, 0);
+}
+
+int
+wl_int(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int val;
+ char *endptr = NULL;
+
+ if (!*++argv) {
+ if (cmd->get == -1)
+ return -1;
+ if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0)
+ return ret;
+
+ val = dtoh32(val);
+ wl_printint(val);
+ } else {
+ if (cmd->set == -1)
+ return -1;
+ if (!stricmp(*argv, "on"))
+ val = 1;
+ else if (!stricmp(*argv, "off"))
+ val = 0;
+ else {
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ val = htod32(val);
+ ret = wlu_set(wl, cmd->set, &val, sizeof(int));
+ }
+
+ return ret;
+}
+
+int wl_buf(void *wl, cmd_t *cmd, char **argv)
+{
+ char* data;
+ int err;
+ int len;
+ int i;
+
+ strcpy(buf, cmd->name);
+
+ /* set */
+ if (argv[1]) {
+ len = strlen(buf);
+ data = argv[1];
+ for (i = len + 1, len += 1 + strlen(data) / 2;
+ (i < len) && (i < (int)WLC_IOCTL_SMLEN); i ++) {
+ char hex[] = "XX";
+ hex[0] = *data++;
+ hex[1] = *data++;
+ buf[i] = (uint8)strtoul(hex, NULL, 16);
+ }
+ err = wlu_set(wl, WLC_SET_VAR, buf, i);
+ }
+ /* get */
+ else if (!(err = wlu_get(wl, WLC_GET_VAR, buf, WLC_IOCTL_SMLEN))) {
+ len = dtoh32(*(int *)buf);
+ if (len > WLC_IOCTL_SMLEN) {
+ data = buf + sizeof(int);
+ for (i = 0; i < len; i ++)
+ printf("%02x", (uint8)(data[i]));
+ printf("\n");
+ } else {
+ err = BCME_BUFTOOLONG;
+ }
+ }
+
+ return err;
+}
+
+/* Return a new chanspec given a legacy chanspec
+ * Returns INVCHANSPEC on error
+ */
+static chanspec_t
+wl_chspec_from_legacy(chanspec_t legacy_chspec)
+{
+ chanspec_t chspec;
+
+ /* get the channel number */
+ chspec = LCHSPEC_CHANNEL(legacy_chspec);
+
+ /* convert the band */
+ if (LCHSPEC_IS2G(legacy_chspec)) {
+ chspec |= WL_CHANSPEC_BAND_2G;
+ } else {
+ chspec |= WL_CHANSPEC_BAND_5G;
+ }
+
+ /* convert the bw and sideband */
+ if (LCHSPEC_IS20(legacy_chspec)) {
+ chspec |= WL_CHANSPEC_BW_20;
+ } else {
+ chspec |= WL_CHANSPEC_BW_40;
+ if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
+ chspec |= WL_CHANSPEC_CTL_SB_L;
+ } else {
+ chspec |= WL_CHANSPEC_CTL_SB_U;
+ }
+ }
+
+ if (wf_chspec_malformed(chspec)) {
+ fprintf(stderr, "wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
+ chspec);
+ return INVCHANSPEC;
+ }
+
+ return chspec;
+}
+
+/* Return a legacy chanspec given a new chanspec
+ * Returns INVCHANSPEC on error
+ */
+chanspec_t
+wl_chspec_to_legacy(chanspec_t chspec)
+{
+ chanspec_t lchspec;
+
+ if (wf_chspec_malformed(chspec)) {
+ fprintf(stderr, "wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
+ chspec);
+ return INVCHANSPEC;
+ }
+
+ /* get the channel number */
+ lchspec = CHSPEC_CHANNEL(chspec);
+
+ /* convert the band */
+ if (CHSPEC_IS2G(chspec)) {
+ lchspec |= WL_LCHANSPEC_BAND_2G;
+ } else {
+ lchspec |= WL_LCHANSPEC_BAND_5G;
+ }
+
+ /* convert the bw and sideband */
+ if (CHSPEC_IS20(chspec)) {
+ lchspec |= WL_LCHANSPEC_BW_20;
+ lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
+ } else if (CHSPEC_IS40(chspec)) {
+ lchspec |= WL_LCHANSPEC_BW_40;
+ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
+ lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
+ } else {
+ lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
+ }
+ } else {
+ /* cannot express the bandwidth */
+ char chanbuf[CHANSPEC_STR_LEN];
+ fprintf(stderr,
+ "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
+ "to pre-11ac format\n",
+ wf_chspec_ntoa(chspec, chanbuf), chspec);
+ return INVCHANSPEC;
+ }
+
+ return lchspec;
+}
+
+/* given a chanspec value, do the endian and chanspec version conversion to
+ * a chanspec_t value
+ * Returns INVCHANSPEC on error
+ */
+chanspec_t
+wl_chspec_to_driver(chanspec_t chanspec)
+{
+ if (ioctl_version == 1) {
+ chanspec = wl_chspec_to_legacy(chanspec);
+ if (chanspec == INVCHANSPEC) {
+ return chanspec;
+ }
+ }
+ chanspec = htodchanspec(chanspec);
+
+ return chanspec;
+}
+
+/* given a chanspec value, do the endian and chanspec version conversion to
+ * a chanspec_t value in a 32 bit integer
+ * Returns INVCHANSPEC on error
+ */
+uint32
+wl_chspec32_to_driver(chanspec_t chanspec)
+{
+ uint32 val;
+
+ if (ioctl_version == 1) {
+ chanspec = wl_chspec_to_legacy(chanspec);
+ if (chanspec == INVCHANSPEC) {
+ return chanspec;
+ }
+ }
+ val = htod32((uint32)chanspec);
+
+ return val;
+}
+
+/* given a chanspec value from the driver, do the endian and chanspec version conversion to
+ * a chanspec_t value
+ * Returns INVCHANSPEC on error
+ */
+chanspec_t
+wl_chspec_from_driver(chanspec_t chanspec)
+{
+ chanspec = dtohchanspec(chanspec);
+ if (ioctl_version == 1) {
+ chanspec = wl_chspec_from_legacy(chanspec);
+ }
+ return chanspec;
+}
+
+/* given a chanspec value from the driver in a 32 bit integer, do the endian and
+ * chanspec version conversion to a chanspec_t value
+ * Returns INVCHANSPEC on error
+ */
+chanspec_t
+wl_chspec32_from_driver(uint32 chanspec32)
+{
+ chanspec_t chanspec;
+
+ chanspec = (chanspec_t)dtoh32(chanspec32);
+
+ if (ioctl_version == 1) {
+ chanspec = wl_chspec_from_legacy(chanspec);
+ }
+ return chanspec;
+}
+
+#ifdef CLMDOWNLOAD
+/*
+Generic interface for downloading required data onto the dongle
+*/
+int
+download2dongle(void *wl, char *iovar, uint16 flag, uint16 dload_type,
+ unsigned char *dload_buf, int len)
+{
+ struct wl_dload_data *dload_ptr = (struct wl_dload_data *)dload_buf;
+ int err = 0;
+ int dload_data_offset;
+
+ dload_data_offset = OFFSETOF(wl_dload_data_t, data);
+ dload_ptr->flag = (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT) | flag;
+ dload_ptr->dload_type = dload_type;
+ dload_ptr->len = htod32(len - dload_data_offset);
+ dload_ptr->crc = 0;
+ len = len + 8 - (len%8);
+
+ err = wlu_iovar_setbuf(wl, iovar,
+ dload_buf, len, buf, WLC_IOCTL_MEDLEN);
+ return err;
+}
+
+int
+dload_clm(void *wl, uint32 datalen, unsigned char *org_buf, int ds_id)
+{
+ int num_chunks, chunk_len, cumulative_len = 0;
+ int size2alloc;
+ unsigned char *new_buf;
+ wl_clm_dload_info_t *clm_info_ptr;
+ int err = 0, clm_info_offset, chunk_offset;
+
+ clm_info_offset = OFFSETOF(wl_dload_data_t, data);
+ chunk_offset = OFFSETOF(wl_clm_dload_info_t, data_chunk);
+
+ num_chunks = datalen/MAX_CHUNK_LEN;
+ if (datalen % MAX_CHUNK_LEN != 0)
+ num_chunks++;
+ size2alloc = clm_info_offset + chunk_offset + MAX_CHUNK_LEN;
+
+ if ((new_buf = (unsigned char *)malloc(size2alloc)) != NULL) {
+ memset(new_buf, 0, size2alloc);
+ clm_info_ptr = (wl_clm_dload_info_t*)((uint8 *)new_buf + clm_info_offset);
+ clm_info_ptr->num_chunks = num_chunks;
+ clm_info_ptr->clm_total_len = datalen;
+ clm_info_ptr->ds_id = ds_id;
+ do {
+ if (datalen >= MAX_CHUNK_LEN)
+ chunk_len = MAX_CHUNK_LEN;
+ else
+ chunk_len = datalen;
+ memset(new_buf + clm_info_offset + chunk_offset, 0,
+ size2alloc - clm_info_offset - chunk_offset);
+ clm_info_ptr->chunk_len = htod32(chunk_len);
+
+ memcpy(&clm_info_ptr->data_chunk[0], org_buf + cumulative_len, chunk_len);
+ clm_info_ptr->chunk_offset = cumulative_len;
+ cumulative_len += chunk_len;
+
+ err = download2dongle(wl, "generic_dload", 0, DL_TYPE_CLM, new_buf,
+ chunk_len + clm_info_offset + chunk_offset);
+
+ datalen = datalen - chunk_len;
+ } while ((datalen > 0) && (err == 0));
+ free(new_buf);
+ } else {
+ err = BCME_NOMEM;
+ }
+
+ return err;
+}
+
+int
+dload_blob(void *wl, char *iovar, unsigned char *org_buf, uint32 datalen)
+{
+ int chunk_len, cumulative_len = 0;
+ int size2alloc;
+ unsigned char *new_buf;
+ int err = 0, data_offset;
+ uint16 dl_flag = DL_BEGIN;
+
+ data_offset = OFFSETOF(wl_dload_data_t, data);
+ size2alloc = data_offset + MAX_CHUNK_LEN;
+
+ if ((new_buf = (unsigned char *)malloc(size2alloc)) != NULL) {
+ memset(new_buf, 0, size2alloc);
+
+ do {
+ if (datalen >= MAX_CHUNK_LEN)
+ chunk_len = MAX_CHUNK_LEN;
+ else
+ chunk_len = datalen;
+
+ memcpy(new_buf + data_offset, org_buf + cumulative_len, chunk_len);
+ cumulative_len += chunk_len;
+
+ if (datalen - chunk_len == 0)
+ dl_flag |= DL_END;
+
+ err = download2dongle(wl, iovar, dl_flag, DL_TYPE_CLM,
+ new_buf, data_offset + chunk_len);
+ dl_flag &= ~DL_BEGIN;
+
+ datalen = datalen - chunk_len;
+ } while ((datalen > 0) && (err == 0));
+
+ free(new_buf);
+ } else {
+ err = BCME_NOMEM;
+ }
+
+ return err;
+}
+
+int
+dload_clm_blob(void *wl, unsigned char *org_buf, uint32 datalen)
+{
+ int chunk_len, cumulative_len = 0;
+ int size2alloc;
+ unsigned char *new_buf;
+ int err = 0, data_offset;
+ uint16 dl_flag = DL_BEGIN;
+
+ data_offset = OFFSETOF(wl_dload_data_t, data);
+ size2alloc = data_offset + MAX_CHUNK_LEN;
+
+ if ((new_buf = (unsigned char *)malloc(size2alloc)) != NULL) {
+ memset(new_buf, 0, size2alloc);
+
+ do {
+ if (datalen >= MAX_CHUNK_LEN)
+ chunk_len = MAX_CHUNK_LEN;
+ else
+ chunk_len = datalen;
+
+ memcpy(new_buf + data_offset, org_buf + cumulative_len, chunk_len);
+ cumulative_len += chunk_len;
+
+ if (datalen - chunk_len == 0)
+ dl_flag |= DL_END;
+
+ err = download2dongle(wl, "clmload", dl_flag, DL_TYPE_CLM,
+ new_buf, data_offset + chunk_len);
+ dl_flag &= ~DL_BEGIN;
+
+ datalen = datalen - chunk_len;
+ } while ((datalen > 0) && (err == 0));
+
+ free(new_buf);
+ } else {
+ err = BCME_NOMEM;
+ }
+
+ return err;
+}
+
+#define CLM_INPUT_FILE_MIN_LEN 32
+int
+process_clm_data(void *wl, char *clmfn, int ds_id)
+{
+ int ret = 0;
+
+ FILE *fp = NULL;
+
+ unsigned int clm_filelen;
+ unsigned long status = 0;
+ unsigned char *new_buf = NULL;
+ uint32 clm_data_len;
+ unsigned char *new_ptr;
+ int filelen = 0;
+ const char clm_magic_string[] = {'C', 'L', 'M', ' ', 'D', 'A', 'T', 'A'};
+ const char blob_magic_string[] = {'B', 'L', 'O', 'B'};
+
+ /* Open the clm download file */
+ if (!(fp = fopen(clmfn, "rb"))) {
+ fprintf(stderr, "unable to open input file %s\n", clmfn);
+ ret = BCME_BADARG;
+ goto error;
+ }
+
+ /* fstat is a linux/unix, not a stdio function. This is replaced everywhere with function
+ * fsize() which calls fseek(fp, 0L, SEEK_END), ftell(fp), fseek(fp, 0L, SEEK_SET) sequence
+ * to determine the file size.
+ */
+
+ if ((filelen = fsize(fp)) < 0) {
+ fprintf(stderr, "fseek or ftell on input file %s return error %s\n",
+ clmfn, strerror(errno));
+ ret = BCME_ERROR;
+ goto error;
+ }
+ clm_filelen = (uint)filelen;
+
+ if (clm_filelen == 0) {
+ fprintf(stderr, "input file %s is empty (i.e. zero length)\n", clmfn);
+ ret = BCME_ERROR;
+ goto error;
+ }
+
+ if ((new_buf = malloc(clm_filelen)) == NULL) {
+ fprintf(stderr, "unable to allocate %u bytes based on input file size!\n",
+ clm_filelen);
+ ret = BCME_NOMEM;
+ goto error;
+ }
+
+ /* We can read a CLM binary file or CLM blob file. The CLM binary file has
+ * been obsoleted in favor of the "blob" format that allows additional data
+ * to included in a modular/independent way. The blob format is downloaded
+ * via the new 'clmload' iovar. The binary format uses the legacy and now obsolete
+ * 'generic_dload' iovar.
+ *
+ * Newer driver builds no longer support the generic_dload iovar but this wl
+ * command utility will support either format/iovar combination based on the
+ * download file's magic string for some transition time.
+ */
+
+ status = fread(new_buf, 1, clm_filelen, fp);
+
+ /* Basic sanity check on size. Make sure there is enough for any magic string plus
+ * a little more for good measure.
+ */
+ if (status < CLM_INPUT_FILE_MIN_LEN) {
+ fprintf(stderr, "size of input file %s is less than %d bytes."
+ " This can't be a CLM file!\n", clmfn, CLM_INPUT_FILE_MIN_LEN);
+ ret = BCME_ERROR;
+ goto error;
+ } else if (status != clm_filelen) {
+ fprintf(stderr, "read of input file %s wasn't good based on fstat size %u\n",
+ clmfn, clm_filelen);
+ ret = BCME_ERROR;
+ goto error;
+ }
+
+ /* CLM blob or binary format file? */
+ if (memcmp(new_buf, blob_magic_string, sizeof(blob_magic_string)) == 0) {
+ /* CLM blob file? They start with magic string 'BLOB' */
+ printf("Downloading CLM blob format file %s\n", clmfn);
+ ret = dload_clm_blob(wl, new_buf, clm_filelen);
+ } else if (memcmp(new_buf, clm_magic_string, sizeof(clm_magic_string)) == 0) {
+ /* pure CLM binary file? CLM binary files start with 'CLM DATA' */
+ clm_data_len = clm_filelen;
+ new_ptr = new_buf;
+ printf("Downloading legacy, obsolete CLM binary format file %s as a %s CLM\n",
+ clmfn, ds_id ? "incremental":"base");
+ ret = dload_clm(wl, clm_data_len, new_ptr, ds_id);
+ } else {
+ fprintf(stderr, "input file is missing CLM binary or CLM blob magic string\n");
+ ret = -1;
+ goto error;
+ }
+error:
+ if (new_buf)
+ free(new_buf);
+ if (fp)
+ fclose(fp);
+
+ return ret;
+}
+
+#define TXCAP_INPUT_FILE_MIN_LEN 32
+
+int
+process_txcap_data(void *wl, char *txcapfn)
+{
+ int ret = 0;
+
+ FILE *fp = NULL;
+
+ unsigned int txcap_filelen;
+ unsigned long status = 0;
+ unsigned char *new_buf = NULL;
+ int filelen = 0;
+
+ /* Open the txcap download file */
+ if (!(fp = fopen(txcapfn, "rb"))) {
+ fprintf(stderr, "unable to open input file %s\n", txcapfn);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* fstat is a linux/unix, not a stdio function. This is replaced everywhere with function
+ * fsize() which calls fseek(fp, 0L, SEEK_END), ftell(fp), fseek(fp, 0L, SEEK_SET) sequence
+ * to determine the file size.
+ */
+
+ if ((filelen = fsize(fp)) < 0) {
+ fprintf(stderr, "fseek or ftell on input file %s return error %s\n",
+ txcapfn, strerror(errno));
+ ret = -EINVAL;
+ goto error;
+ }
+ txcap_filelen = (uint)filelen;
+
+ if (txcap_filelen == 0) {
+ fprintf(stderr, "input file %s is empty (i.e. zero length)\n", txcapfn);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if ((new_buf = malloc(txcap_filelen)) == NULL) {
+ fprintf(stderr, "unable to allocate %u bytes based on input file size!\n",
+ txcap_filelen);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ status = fread(new_buf, 1, txcap_filelen, fp);
+
+ if (status != txcap_filelen) {
+ fprintf(stderr, "read of input file %s wasn't good based on fstat size %u\n",
+ txcapfn, txcap_filelen);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Basic sanity check on size. Make sure there is enough for any magic string plus
+ * a little more for good measure.
+ */
+ if (status < TXCAP_INPUT_FILE_MIN_LEN) {
+ fprintf(stderr, "size of input file %s is less than %d bytes."
+ " This can't be a txcap file!\n", txcapfn, TXCAP_INPUT_FILE_MIN_LEN);
+ ret = -EINVAL;
+ goto error;
+ } else if (status != txcap_filelen) {
+ fprintf(stderr, "read of input file %s wasn't good based on fstat size %u\n",
+ txcapfn, txcap_filelen);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* txcap package? */
+ if (memcmp(new_buf, blob_magic_string, sizeof(blob_magic_string)) == 0) {
+ /* MSF packaged file? They start with magic string 'BLOB' */
+ printf("Downloading txcap package format file %s\n", txcapfn);
+ ret = dload_blob(wl, "txcapload", new_buf, txcap_filelen);
+ } else {
+ fprintf(stderr, "input file is missing txcap package magic string\n");
+ ret = -1;
+ goto error;
+ }
+
+error:
+ if (new_buf)
+ free(new_buf);
+ if (fp)
+ fclose(fp);
+
+ return ret;
+}
+
+static int
+wl_clmload(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ char *arg1;
+ char *arg2;
+ char* fname;
+
+ BCM_REFERENCE(cmd);
+
+ /* argv is pointing at the clmload command name to start */
+ if ((arg1 = *++argv) == NULL) {
+ fprintf(stderr, "too few arguments (none)\n");
+ return BCME_USAGE_ERROR;
+ } else if ((arg2 = *++argv) == NULL) {
+ /* one argument - use it, arg1, as the file name */
+ fname = arg1;
+ } else if ((*++argv) == NULL) {
+ /* two arguments - use the last, arg2, as the filename
+ * while ignoring the first argument. We no longer
+ * support downloading anything but a base CLM,
+ */
+ fname = arg2;
+ } else {
+ fprintf(stderr, "too mang arguments (3 or more)\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ ret = process_clm_data(wl, fname, 0);
+
+ return ret;
+}
+static int
+wl_txcapload(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ char *arg1;
+ char* fname;
+
+ BCM_REFERENCE(cmd);
+
+ /* argv is pointing at the clmload command name to start */
+ if ((arg1 = *++argv) == NULL) {
+ /* too few arguments (none) */
+ return -1;
+ } else if (*++argv == NULL) {
+ /* one argument - use it, arg1, as the file name */
+ fname = arg1;
+ } else {
+ /* too mang arguments (2 or more) */
+ return -1;
+ }
+
+ ret = process_txcap_data(wl, fname);
+
+ return ret;
+}
+
+static int
+wl_txcapctl(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ void *ptr = NULL;
+ wl_txpwrcap_ctl_t *txcap_ctl_ptr;
+ wl_txpwrcap_ctl_t txcap_ctl;
+ int i;
+
+ if (!(argv[1])) { /* Get */
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return err;
+ txcap_ctl_ptr = ptr;
+ printf("%d %d %d %d %d\n",
+ txcap_ctl_ptr->ctl[0],
+ txcap_ctl_ptr->ctl[1],
+ txcap_ctl_ptr->ctl[2],
+ txcap_ctl_ptr->ctl[3],
+ txcap_ctl_ptr->ctl[4]);
+ } else { /* Set */
+ for (i = 0; i < 5; i++) {
+ if (*++argv) {
+ txcap_ctl.ctl[i] = strtol(*argv, NULL, 0);
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+ }
+ if (argv[1]) {
+ return BCME_USAGE_ERROR;
+ }
+ else {
+ (void)txcap_ctl;
+ txcap_ctl.version = TXPWRCAPCTL_VERSION;
+ if ((err = wlu_var_setbuf(wl, cmd->name, &txcap_ctl, sizeof(txcap_ctl)))
+ < 0)
+ return BCME_ERROR;
+ }
+ }
+ return err;
+}
+
+static int
+wl_txcapdump(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ void *ptr = NULL;
+ uint8 txcap_dump_version;
+ int i;
+
+ if (!(argv[1])) { /* Get */
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return err;
+ txcap_dump_version = *((uint8 *)ptr);
+ if (txcap_dump_version == 2) {
+ wl_txpwrcap_dump_t *txcap_dump_ptr = ptr;
+ printf("current country %c%c, channel(control) %d\n",
+ txcap_dump_ptr->current_country[0],
+ txcap_dump_ptr->current_country[1],
+ txcap_dump_ptr->current_channel);
+ printf("low/high cap config: ");
+ for (i = 0; i < TXPWRCAP_NUM_SUBBANDS; i++) {
+ printf(" %d", txcap_dump_ptr->config[i]);
+ }
+ printf("\n");
+ printf("low/high cap state: ");
+ for (i = 0; i < TXPWRCAP_NUM_SUBBANDS; i++) {
+ printf(" %d", txcap_dump_ptr->state[i]);
+ }
+ printf("\n");
+ printf("high cap state enabled %d\n",
+ txcap_dump_ptr->high_cap_state_enabled);
+ printf("wci2 cell status last %d\n",
+ txcap_dump_ptr->wci2_cell_status_last);
+ if (!txcap_dump_ptr->download_present) {
+ printf("txcap download not present\n");
+ } else {
+ printf("subbands %d, antennas %d, antennas per core",
+ txcap_dump_ptr->num_subbands, txcap_dump_ptr->num_antennas);
+ for (i = 0; i < TXPWRCAP_MAX_NUM_CORES; i++) {
+ printf(" %d", txcap_dump_ptr->num_antennas_per_core[i]);
+ }
+ printf(", cc groups %d\n", txcap_dump_ptr->num_cc_groups);
+ printf("current cc group info index %d\n",
+ txcap_dump_ptr->current_country_cc_group_info_index);
+ printf(" tx caps (decimal qdbm, per subband, per antenna,"
+ " e.g. sb0_a0, sb0_a1, sb1_a0, sb1_a1, ...)\n");
+ printf(" low cap: ");
+ for (i = 0;
+ i < txcap_dump_ptr->num_subbands *
+ txcap_dump_ptr->num_antennas;
+ i++) {
+ printf("%4d ", txcap_dump_ptr->low_cap[i]);
+ }
+ printf("\n");
+ printf(" high cap: ");
+ for (i = 0;
+ i < txcap_dump_ptr->num_subbands *
+ txcap_dump_ptr->num_antennas;
+ i++) {
+ printf("%4d ", txcap_dump_ptr->high_cap[i]);
+ }
+ printf("\n");
+ }
+ } else if (txcap_dump_version == 3) {
+ wl_txpwrcap_dump_v3_t *txcap_dump_ptr = ptr;
+ printf("current country %c%c, channel(control) %d\n",
+ txcap_dump_ptr->current_country[0],
+ txcap_dump_ptr->current_country[1],
+ txcap_dump_ptr->current_channel);
+ printf("low/high cap config: ");
+ for (i = 0; i < TXPWRCAP_NUM_SUBBANDS; i++) {
+ printf(" %d", txcap_dump_ptr->config[i]);
+ }
+ printf("\n");
+ printf("low/high cap state: ");
+ for (i = 0; i < TXPWRCAP_NUM_SUBBANDS; i++) {
+ printf(" %d", txcap_dump_ptr->state[i]);
+ }
+ printf("\n");
+ printf("high cap state enabled %d\n",
+ txcap_dump_ptr->high_cap_state_enabled);
+ printf("wci2 cell status last %d\n",
+ txcap_dump_ptr->wci2_cell_status_last);
+ if (!txcap_dump_ptr->download_present) {
+ printf("txcap download not present\n");
+ } else {
+ printf("subbands %d, antennas %d, antennas per core",
+ txcap_dump_ptr->num_subbands, txcap_dump_ptr->num_antennas);
+ for (i = 0; i < TXPWRCAP_MAX_NUM_CORES; i++) {
+ printf(" %d", txcap_dump_ptr->num_antennas_per_core[i]);
+ }
+ printf(", cc groups %d\n", txcap_dump_ptr->num_cc_groups);
+ printf("current cc group info index %d\n",
+ txcap_dump_ptr->current_country_cc_group_info_index);
+ printf(" tx caps (decimal qdbm, per subband, per antenna,"
+ " e.g. sb0_a0, sb0_a1, sb1_a0, sb1_a1, ...)\n");
+ if (txcap_dump_ptr->cap_states_per_cc_group == 2) {
+ printf(" low cap: ");
+ for (i = 0;
+ i < txcap_dump_ptr->num_subbands *
+ txcap_dump_ptr->num_antennas;
+ i++) {
+ printf("%4d ",
+ txcap_dump_ptr->host_low_wci2_low_cap[i]);
+ }
+ printf("\n");
+ printf(" high cap: ");
+ for (i = 0;
+ i < txcap_dump_ptr->num_subbands *
+ txcap_dump_ptr->num_antennas;
+ i++) {
+ printf("%4d ",
+ txcap_dump_ptr->host_low_wci2_high_cap[i]);
+ }
+ printf("\n");
+ } else {
+ printf(" host low wci2 low cap: ");
+ for (i = 0;
+ i < txcap_dump_ptr->num_subbands *
+ txcap_dump_ptr->num_antennas;
+ i++) {
+ printf("%4d ",
+ txcap_dump_ptr->host_low_wci2_low_cap[i]);
+ }
+ printf("\n");
+ printf(" host low wci2 high cap: ");
+ for (i = 0;
+ i < txcap_dump_ptr->num_subbands *
+ txcap_dump_ptr->num_antennas;
+ i++) {
+ printf("%4d ",
+ txcap_dump_ptr->host_low_wci2_high_cap[i]);
+ }
+ printf("\n");
+ printf(" host high wci2 low cap: ");
+ for (i = 0;
+ i < txcap_dump_ptr->num_subbands *
+ txcap_dump_ptr->num_antennas;
+ i++) {
+ printf("%4d ",
+ txcap_dump_ptr->host_high_wci2_low_cap[i]);
+ }
+ printf("\n");
+ printf(" host high wci2 high cap: ");
+ for (i = 0;
+ i < txcap_dump_ptr->num_subbands *
+ txcap_dump_ptr->num_antennas;
+ i++) {
+ printf("%4d ",
+ txcap_dump_ptr->host_high_wci2_high_cap[i]);
+ }
+ printf("\n");
+ }
+ }
+ } else {
+ err = BCME_USAGE_ERROR;
+ }
+ } else { /* Set */
+ err = BCME_USAGE_ERROR;
+ }
+ return err;
+}
+
+#endif /* CLMDOWNLOAD */
+
+#define CAL_INPUT_FILE_MIN_LEN 32
+
+int
+process_cal_data(void *wl, char *calfn)
+{
+ int ret = 0;
+ FILE *fp = NULL;
+ unsigned int cal_filelen;
+ unsigned long status = 0;
+ unsigned char *new_buf = NULL;
+ int filelen = 0;
+
+ /* Open the CAL download file */
+ if (!(fp = fopen(calfn, "rb"))) {
+ fprintf(stderr, "unable to open input file %s\n", calfn);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* fstat is a linux/unix, not a stdio function. This is replaced everywhere with function
+ * fsize() which calls fseek(fp, 0L, SEEK_END), ftell(fp), fseek(fp, 0L, SEEK_SET) sequence
+ * to determine the file size.
+ */
+
+ if ((filelen = fsize(fp)) < 0) {
+ fprintf(stderr, "fseek or ftell on input file %s return error %s\n",
+ calfn, strerror(errno));
+ ret = -EINVAL;
+ goto error;
+ }
+ cal_filelen = (uint)filelen;
+
+ if (cal_filelen == 0) {
+ fprintf(stderr, "input file %s is empty (i.e. zero length)\n", calfn);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if ((new_buf = malloc(cal_filelen)) == NULL) {
+ fprintf(stderr, "unable to allocate %u bytes based on input file size!\n",
+ cal_filelen);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ status = fread(new_buf, 1, cal_filelen, fp);
+
+ if (status != cal_filelen) {
+ fprintf(stderr, "read of input file %s wasn't good based on fstat size %u\n",
+ calfn, cal_filelen);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Basic sanity check on size. Make sure there is enough for any magic string plus
+ * a little more for good measure.
+ */
+ if (status < CAL_INPUT_FILE_MIN_LEN) {
+ fprintf(stderr, "size of input file %s is less than %d bytes."
+ " This can't be a cal file!\n", calfn, CAL_INPUT_FILE_MIN_LEN);
+ ret = -EINVAL;
+ goto error;
+ } else if (status != cal_filelen) {
+ fprintf(stderr, "read of input file %s wasn't good based on fstat size %u\n",
+ calfn, cal_filelen);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Calibration package? */
+ if (memcmp(new_buf, blob_magic_string, sizeof(blob_magic_string)) == 0) {
+ /* MSF packaged file? They start with magic string 'BLOB' */
+ printf("Downloading calibration package format file %s\n", calfn);
+ ret = dload_blob(wl, "calload", new_buf, cal_filelen);
+ } else {
+ fprintf(stderr, "input file is missing calibration package magic string\n");
+ ret = -1;
+ goto error;
+ }
+
+error:
+ if (new_buf)
+ free(new_buf);
+ if (fp)
+ fclose(fp);
+
+ return ret;
+}
+
+static int
+wl_calload(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ char* fname;
+
+ BCM_REFERENCE(cmd);
+
+ /* argv is pointing at the calload command name to start */
+ if ((fname = *++argv) == NULL) {
+ /* too few arguments (none) */
+ return -EINVAL;
+ }
+
+ ret = process_cal_data(wl, fname);
+
+ return ret;
+}
+
+int
+process_cal_dump(void *wl, char *fname_txcal, char *fname_rxcal)
+{
+ int ret = 0;
+ unsigned long status = 0;
+ FILE *fblobp = NULL;
+ void *ptr = NULL;
+ uint32 dump_sz_total;
+ uint16 dump_sz_txcal, dump_sz_rxcal;
+
+ /* Read back TX calibration information */
+ if ((ret = wlu_var_getbuf_med(wl, "caldump", NULL, 0, &ptr)) < 0)
+ goto error;
+
+ dump_sz_total = dtoh32(*(int *)ptr);
+ printf("caldump: total dump size %d bytes\n", dump_sz_total);
+ if (dump_sz_total > (WLC_IOCTL_MEDLEN - 4)) {
+ fprintf(stderr, "caldump: total dump size too large\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ ptr = (void *)((uint8 *)ptr + sizeof(dump_sz_total));
+
+ /* The TxCal data starts first. Its size is indicated in first two bytes
+ * (excluding size field itself - an uint16 field)
+ */
+ dump_sz_txcal = dtoh16(*(uint16 *)ptr) + sizeof(dump_sz_txcal);
+ printf("\tTxCal dump size %d bytes\n", dump_sz_txcal);
+ if (dump_sz_total < (uint32)dump_sz_txcal) {
+ fprintf(stderr, "caldump: total dump size too small for TxCal\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Open the txcal bin file */
+ if (!(fblobp = fopen(fname_txcal, "wb"))) {
+ fprintf(stderr, "unable to open TxCal output file %s\n", fname_txcal);
+ perror(fname_txcal);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ status = (unsigned long)fwrite((uint8 *)ptr, 1, dump_sz_txcal, fblobp);
+ if (status != dump_sz_txcal) {
+ fprintf(stderr, "unable to complete TxCal output (write %lu out of %u bytes)\n",
+ status, dump_sz_txcal);
+ ret = -EINVAL;
+ goto error;
+ }
+ ptr = (void *)((uint8 *)ptr + dump_sz_txcal);
+ fclose(fblobp);
+ fblobp = NULL;
+
+ /* The RxCal data starts after TxCal. Its size is indicated in first two bytes
+ * (but here, its size is derived from dump_sz_total and dump_sz_txcal))
+ */
+
+ /* For backward comatible where only TxCal file is given, we just dump TxCal
+ * and return. If the RXCal file name is "NULL", we just return without any error
+ */
+ if (fname_rxcal == NULL) {
+ fprintf(stderr, "can't find RxCal output file\n");
+ return ret;
+ }
+ dump_sz_rxcal = (uint16)(dump_sz_total - (uint32)dump_sz_txcal);
+ printf("\tRxCal dump size %d bytes\n", dump_sz_rxcal);
+ if (dump_sz_rxcal == 0) {
+ fprintf(stderr, "no RxCal data available\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Open the rxcal bin file */
+ if (!(fblobp = fopen(fname_rxcal, "wb"))) {
+ fprintf(stderr, "unable to open RxCal output file %s\n", fname_rxcal);
+ perror(fname_rxcal);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ status = (unsigned long)fwrite((uint8 *)ptr, 1, dump_sz_rxcal, fblobp);
+ if (status != dump_sz_rxcal) {
+ fprintf(stderr, "unable to complete RxCal output (write %lu out of %u bytes)\n",
+ status, dump_sz_rxcal);
+ ret = -EINVAL;
+ goto error;
+ }
+
+error:
+ if (fblobp)
+ fclose(fblobp);
+ return ret;
+}
+
+static int
+wl_caldump(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ char *fname_txcal, *fname_rxcal;
+
+ BCM_REFERENCE(cmd);
+
+ /* argv is pointing at the command name to start */
+ if ((fname_txcal = *++argv) == NULL) {
+ /* too few arguments (none) */
+ return -EINVAL;
+ }
+ printf("caldump: dump TxCal to file %s\n", fname_txcal);
+
+ if ((fname_rxcal = *++argv) != NULL)
+ printf("caldump: dump RxCal to file %s\n", fname_rxcal);
+
+ ret = process_cal_dump(wl, fname_txcal, fname_rxcal);
+
+ return ret;
+}
+
+int
+wl_bsscfg_int(void *wl, cmd_t *cmd, char **argv)
+{
+ char *endptr = NULL;
+ char *val_name;
+ int bsscfg_idx = 0;
+ int val = 0;
+ int consumed;
+ int ret;
+
+ val_name = *argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((ret = wl_cfg_option(argv, val_name, &bsscfg_idx, &consumed)) != 0)
+ return ret;
+
+ /* handle a bsscfg int with a legacy ioctl */
+ if (consumed == 0 && cmd->set != WLC_SET_VAR) {
+ /* back up to the orig command and run as an ioctl int */
+ argv--;
+ return wl_int(wl, cmd, argv);
+ }
+
+ argv += consumed;
+
+ if (!*argv) {
+ /* This is a GET */
+ if (cmd->get == -1)
+ return -1;
+
+ if (consumed == 0)
+ ret = wlu_iovar_getint(wl, val_name, &val);
+ else
+ ret = wl_bssiovar_getint(wl, val_name, bsscfg_idx, &val);
+
+ if (ret < 0)
+ return ret;
+
+ wl_printint(val);
+ } else {
+ /* This is a SET */
+ if (cmd->set == -1)
+ return -1;
+
+ if (!stricmp(*argv, "on"))
+ val = 1;
+ else if (!stricmp(*argv, "off"))
+ val = 0;
+ else {
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ if (consumed == 0)
+ ret = wlu_iovar_setint(wl, val_name, val);
+ else
+ ret = wl_bssiovar_setint(wl, val_name, bsscfg_idx, val);
+ }
+
+ return ret;
+}
+
+/* Get/Set the gmode config */
+static int
+wl_gmode(void *wl, cmd_t *cmd, char **argv)
+{
+ char *endptr = NULL;
+ int ret = 0, val;
+
+ if (!*++argv) {
+ const char *gconfig;
+
+ /* Get the current G mode */
+ if ((ret = wlu_get(wl, cmd->get, &val, sizeof(val))) < 0)
+ return ret;
+
+ val = dtoh32(val);
+ switch (val) {
+ case GMODE_LEGACY_B:
+ gconfig = "54g Legacy B";
+ break;
+ case GMODE_AUTO:
+ gconfig = "54g Auto";
+ break;
+ case GMODE_ONLY:
+ gconfig = "54g Only";
+ break;
+ case GMODE_PERFORMANCE:
+ gconfig = "54g Performance";
+ break;
+ case GMODE_LRS:
+ gconfig = "54g LRS";
+ break;
+ default:
+ gconfig = "unknown";
+ break;
+ }
+
+ printf("%s (%d)\n", gconfig, val);
+
+ } else {
+ /* Set the new G mode */
+
+ if (!strnicmp(*argv, "legacy", 6))
+ val = GMODE_LEGACY_B;
+ else if (!strnicmp(*argv, "auto", 4))
+ val = GMODE_AUTO;
+ else if (!strnicmp(*argv, "gonly", 5))
+ val = GMODE_ONLY;
+ else if (!strnicmp(*argv, "perf", 4))
+ val = GMODE_PERFORMANCE;
+ else if (!strnicmp(*argv, "lrs", 3))
+ val = GMODE_LRS;
+ else {
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ /* Set the gmode configration */
+ val = htod32(val);
+ if ((ret = wlu_set(wl, cmd->set, &val, sizeof(val))))
+ goto done;
+
+ }
+
+done:
+ return (ret);
+}
+
+static int
+wl_overlay(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int argc;
+ char *endptr = NULL;
+ void *ptr = NULL;
+ int param[3];
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+ argc--;
+
+ if (argc < 1 || argc > 3) {
+ printf("required args: virt_addr phy_addr size\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ param[0] = strtol(argv[1], &endptr, 0);
+ if (*endptr != '\0' || (param[0] & ~0x003FFE00) != 0) {
+ printf("Invaild virtual address: %s\n", argv[1]);
+ return BCME_BADARG;
+ }
+
+ if (argc == 1) {
+ if ((ret = wlu_var_getbuf(wl, cmd->name, param, sizeof(int), &ptr)) >= 0) {
+ wl_hexdump((uchar *)ptr, 512);
+ }
+ return (ret);
+ }
+
+ param[1] = strtol(argv[2], &endptr, 0);
+ if (*endptr != '\0' || (param[1] & ~0x003FFE00) != 0) {
+ printf("Invaild physical Address: %s\n", argv[2]);
+ return BCME_BADARG;
+ }
+
+ if (argc == 3) {
+ param[2] = strtol(argv[3], &endptr, 0);
+ if (*endptr != '\0' || param[2] < 0 || param[2] > 7) {
+ printf("Invaild size: %s\n", argv[3]);
+ return BCME_BADARG;
+ }
+ } else {
+ param[2] = 0;
+ }
+
+ printf("Setting virtual Address 0x%x to physical Address 0x%x, size is %d\n",
+ param[0], param[1], param[2]);
+ ret = wlu_var_setbuf(wl, cmd->name, param, sizeof(param));
+
+ return (ret);
+}
+
+int
+wl_reg(void *wl, cmd_t *cmd, char **argv)
+{
+ int reg;
+ int ret;
+ struct {
+ int val;
+ int band;
+ } x;
+ char *endptr = NULL;
+ uint argc;
+ bool core_cmd;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+
+ /* eat command name */
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* required arg: reg offset */
+ if (argc < 1)
+ return BCME_USAGE_ERROR;
+
+ reg = strtol(argv[0], &endptr, 0);
+
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ x.val = 0;
+ x.band = WLC_BAND_AUTO;
+ core_cmd = FALSE;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (ret) {
+ return ret;
+ }
+ phytype = dtoh32(revinfo.phytype);
+
+ /* Second arg: value or band or "radio core" */
+ if (argc >= 2) {
+ if (!stricmp(argv[1], "a"))
+ x.band = WLC_BAND_5G;
+ else if (!stricmp(argv[1], "b"))
+ x.band = WLC_BAND_2G;
+ else {
+ /* For NPHY Rev >= 3, the 2nd argument can be
+ the radio core
+ */
+ if (strcmp(cmd->name, "radioreg") == 0) {
+ if (strcmp(argv[1], "syn") == 0) {
+ reg |= RADIO_CORE_SYN;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "tx0") == 0) {
+ reg |= RADIO_CORE_TX0;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "tx1") == 0) {
+ reg |= RADIO_CORE_TX1;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "rx0") == 0) {
+ reg |= RADIO_CORE_RX0;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "rx1") == 0) {
+ reg |= RADIO_CORE_RX1;
+ core_cmd = TRUE;
+ }
+ }
+ /* For HTPHY/ACPHY, the 2nd argument can be
+ the radio core
+ */
+ if (strcmp(cmd->name, "radioreg") == 0) {
+ if (phytype == WLC_PHY_TYPE_AC) {
+ if (strcmp(argv[1], "cr0") == 0) {
+ reg |= RADIO_2069_CORE_CR0;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "cr1") == 0) {
+ reg |= RADIO_2069_CORE_CR1;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "cr2") == 0) {
+ reg |= RADIO_2069_CORE_CR2;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "pll") == 0) {
+ reg |= RADIO_2069_CORE_PLL;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "pll0") == 0) {
+ reg |= RADIO_2069_CORE_PLL0;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "pll1") == 0) {
+ reg |= RADIO_2069_CORE_PLL1;
+ core_cmd = TRUE;
+ }
+ } else {
+ if (strcmp(argv[1], "cr0") == 0) {
+ reg |= RADIO_CORE_CR0;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "cr1") == 0) {
+ reg |= RADIO_CORE_CR1;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[1], "cr2") == 0) {
+ reg |= RADIO_CORE_CR2;
+ core_cmd = TRUE;
+ }
+ }
+ }
+ /* If the second argument is a value */
+ if (!core_cmd) {
+ x.val = strtol(argv[1], &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+ }
+ }
+
+ /* Third arg: band OR "radio core" */
+ if (argc >= 3) {
+ if (!stricmp(argv[2], "a"))
+ x.band = WLC_BAND_5G;
+ else if (!stricmp(argv[2], "b"))
+ x.band = WLC_BAND_2G;
+ else {
+ /* For NPHY Rev >= 3, the 3rd argument can be
+ the radio core
+ */
+ core_cmd = FALSE;
+ if (strcmp(cmd->name, "radioreg") == 0) {
+ if (strcmp(argv[2], "syn") == 0) {
+ reg |= RADIO_CORE_SYN;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "tx0") == 0) {
+ reg |= RADIO_CORE_TX0;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "tx1") == 0) {
+ reg |= RADIO_CORE_TX1;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "rx0") == 0) {
+ reg |= RADIO_CORE_RX0;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "rx1") == 0) {
+ reg |= RADIO_CORE_RX1;
+ core_cmd = TRUE;
+ }
+ }
+ /* For HTPHY/ACPHY, the 3rd argument can be
+ the radio core
+ */
+ if (phytype == WLC_PHY_TYPE_AC) {
+ if (strcmp(argv[2], "cr0") == 0) {
+ reg |= RADIO_2069_CORE_CR0;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "cr1") == 0) {
+ reg |= RADIO_2069_CORE_CR1;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "cr2") == 0) {
+ reg |= RADIO_2069_CORE_CR2;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "pll") == 0) {
+ reg |= RADIO_2069_CORE_PLL;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "pll0") == 0) {
+ reg |= RADIO_2069_CORE_PLL0;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "pll1") == 0) {
+ reg |= RADIO_2069_CORE_PLL1;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "all") == 0) {
+ reg |= RADIO_2069_CORE_ALL;
+ core_cmd = TRUE;
+ }
+ } else {
+ if (strcmp(cmd->name, "radioreg") == 0) {
+ if (strcmp(argv[2], "cr0") == 0) {
+ reg |= RADIO_CORE_CR0;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "cr1") == 0) {
+ reg |= RADIO_CORE_CR1;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "cr2") == 0) {
+ reg |= RADIO_CORE_CR2;
+ core_cmd = TRUE;
+ } else if (strcmp(argv[2], "all") == 0) {
+ reg |= RADIO_CORE_ALL;
+ core_cmd = TRUE;
+ }
+ }
+ }
+
+ if (!core_cmd) {
+ return BCME_USAGE_ERROR;
+ }
+ }
+ }
+
+ x.val = (x.val << 16) | (reg & 0xffff);
+
+ /* issue the get or set ioctl */
+ if ((argc == 1) || ((argc == 2) && ((x.band != WLC_BAND_AUTO) || core_cmd))) {
+ x.band = htod32(x.band);
+ x.val = htod32(x.val);
+ if ((ret = wlu_get(wl, cmd->get, &x, sizeof(x))) < 0)
+ return (ret);
+ printf("0x%04x\n", (uint16)(dtoh32(x.val)));
+ } else {
+ x.band = htod32(x.band);
+ x.val = htod32(x.val);
+ ret = wlu_set(wl, cmd->set, &x, sizeof(x));
+ }
+
+ return (ret);
+}
+
+static int
+wl_macreg(void *wl, cmd_t *cmd, char **argv)
+{
+ int reg;
+ int size;
+ uint32 val;
+ int ret;
+ char *endptr = NULL;
+ rw_reg_t rwt;
+ uint argc;
+
+ val = 0;
+
+ /* eat command name */
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* required arg: reg offset */
+ if (argc < 1)
+ return BCME_USAGE_ERROR;
+
+ reg = strtol(argv[0], &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ /* required arg: reg size */
+ if (argc < 2)
+ return BCME_USAGE_ERROR;
+
+ size = strtol(argv[1], &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ rwt.band = WLC_BAND_AUTO;
+
+ /* Third arg: new value or band */
+ if (argc >= 3) {
+ if (!stricmp(argv[2], "a"))
+ rwt.band = WLC_BAND_5G;
+ else if (!stricmp(argv[2], "b"))
+ rwt.band = WLC_BAND_2G;
+ else {
+ val = strtoul(argv[2], &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+
+ }
+
+ /* Fourth arg: band */
+ if (argc >= 4) {
+ if (!stricmp(argv[3], "a"))
+ rwt.band = WLC_BAND_5G;
+ else if (!stricmp(argv[3], "b"))
+ rwt.band = WLC_BAND_2G;
+ else
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((argc == 2) || ((argc == 3) && (rwt.band != WLC_BAND_AUTO))) {
+ rwt.band = htod32(rwt.band);
+ rwt.byteoff = htod32(reg);
+ rwt.size = htod32(size);
+ if ((ret = wlu_get(wl, cmd->get, &rwt, sizeof(rw_reg_t))) < 0)
+ return (ret);
+ printf("0x%04x\n", dtoh32(rwt.val));
+ }
+ else {
+ rwt.band = htod32(rwt.band);
+ rwt.byteoff = htod32(reg);
+ rwt.size = htod32(size);
+ rwt.val = htod32(val);
+ ret = wlu_set(wl, cmd->set, &rwt, sizeof(rw_reg_t));
+ }
+
+ return (ret);
+}
+
+static int
+wl_macregx(void *wl, cmd_t *cmd, char **argv)
+{
+ int reg;
+ int size = 2;
+ int err;
+ char *p;
+ rw_reg_t rwt;
+
+ /* eat command name */
+ argv++;
+
+ /* required arg: reg offset */
+ if ((p = *argv) == NULL) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ reg = strtol(p, NULL, 0);
+ argv++;
+
+ if (strcmp(cmd->name, "macregx") == 0) {
+ /* required arg: size of the register */
+ if ((p = *argv) == NULL) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ size = strtol(p, NULL, 0);
+ argv++;
+ }
+
+ rwt.byteoff = htod32(reg);
+ rwt.size = htod32(size);
+ rwt.band = WLC_BAND_AUTO;
+
+ if ((p = *argv) == NULL) {
+ uint32 val;
+ /* GET cmd */
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, &rwt,
+ sizeof(rwt), buf, WLC_IOCTL_SMLEN) < 0)) {
+ goto exit;
+ }
+ val = *((uint32 *)buf);
+
+ if (size == 4) {
+ printf("0x%08x\n", dtoh32(val));
+ } else {
+ printf("0x%04x\n", (uint16)dtoh32(val));
+ }
+ } else {
+ /* SET cmd */
+ /* required arg: set value */
+ if ((p = *argv) == NULL) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ rwt.val = htod32(strtol(p, NULL, 0));
+ argv++;
+
+ if ((err = wlu_iovar_set(wl, cmd->name, &rwt, sizeof(rwt))) < 0) {
+ printf("Error setting variable %s\n", cmd->name);
+ return err;
+ }
+ }
+exit:
+ return (err);
+}
+
+/*
+ * get or get a band specific variable
+ * the band can be a/b/all or omitted. "all"(set only)
+ * means all supported bands. blank means current band
+ */
+static int
+wl_band_elm(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ struct {
+ int val;
+ int band;
+ } x;
+ char *endptr = NULL;
+ uint argc;
+
+ /* eat command name */
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ x.val = 0;
+ x.band = WLC_BAND_AUTO;
+
+ /* First arg: value or band */
+ if (argc >= 1) {
+ if (!stricmp(argv[0], "a"))
+ x.band = WLC_BAND_5G;
+ else if (!stricmp(argv[0], "b"))
+ x.band = WLC_BAND_2G;
+ else if (!stricmp(argv[0], "all"))
+ x.band = WLC_BAND_ALL;
+ else {
+ x.val = strtol(argv[0], &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ /* Second arg: band */
+ if (argc >= 2) {
+ if (!stricmp(argv[1], "a"))
+ x.band = WLC_BAND_5G;
+ else if (!stricmp(argv[1], "b"))
+ x.band = WLC_BAND_2G;
+ else if (!stricmp(argv[1], "all"))
+ x.band = WLC_BAND_ALL;
+ else
+ return BCME_USAGE_ERROR;
+ }
+
+ /* issue the get or set ioctl */
+ if ((argc == 0) || ((argc == 1) && (x.band != WLC_BAND_AUTO))) {
+ if (x.band == WLC_BAND_ALL) {
+ printf("band option \"all\" is for set only, not get\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ x.band = htod32(x.band);
+ if ((ret = wlu_get(wl, cmd->get, &x, sizeof(x))) < 0)
+ return (ret);
+
+ printf("%s is 0x%04x(%d)\n", cmd->name, (uint16)(dtoh32(x.val)), dtoh32(x.val));
+ } else {
+ x.band = htod32(x.band);
+ x.val = htod32(x.val);
+ ret = wlu_set(wl, cmd->set, &x, sizeof(x));
+ }
+
+ return (ret);
+}
+
+/* Command may or may not take a MAC address */
+static int
+wl_rssi(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ scb_val_t scb_val;
+ int32 rssi;
+
+ if (!*++argv) {
+ if ((ret = wlu_get(wl, cmd->get, &rssi, sizeof(rssi))) < 0)
+ return ret;
+ printf("%d\n", dtoh32(rssi));
+ return 0;
+ } else {
+ if (!wl_ether_atoe(*argv, &scb_val.ea))
+ return BCME_USAGE_ERROR;
+ if ((ret = wlu_get(wl, cmd->get, &scb_val, sizeof(scb_val))) < 0)
+ return ret;
+ printf("%d\n", dtoh32(scb_val.val));
+ return 0;
+ }
+}
+
+/* Commands that take a MAC address */
+int
+wl_macaddr(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ struct ether_addr ea;
+
+ if (!*++argv) {
+ if ((ret = wlu_get(wl, cmd->get, &ea, ETHER_ADDR_LEN)) < 0)
+ return ret;
+ printf("%s\n", wl_ether_etoa(&ea));
+ return 0;
+ } else {
+ if (!wl_ether_atoe(*argv, &ea))
+ return BCME_USAGE_ERROR;
+ return wlu_set(wl, cmd->set, &ea, ETHER_ADDR_LEN);
+ }
+}
+
+/* IO variables that take a MAC address */
+int
+wl_iov_mac(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ struct ether_addr ea = {{0, 0, 0, 0, 0, 0}};
+
+ if (argv[1]) { /* set */
+ if (!wl_ether_atoe(argv[1], &ea)) {
+ printf(" ERROR: no valid ether addr provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ if ((ret = wlu_iovar_set(wl, cmd->name, &ea, ETHER_ADDR_LEN)) < 0) {
+ printf("Error setting variable %s\n", argv[0]);
+ return ret;
+ }
+ return 0;
+ } else { /* get */
+ if ((ret = wlu_iovar_get(wl, cmd->name, &ea, ETHER_ADDR_LEN)) < 0) {
+ printf("Error getting variable %s\n", argv[0]);
+ return ret;
+ }
+ printf("%s %s\n", argv[0], wl_ether_etoa(&ea));
+ }
+
+ return 0;
+}
+
+static void
+wl_txq_prec_dump(wl_iov_pktq_log_t* iov_pktq_log, bool hide_unknown, bool is_aqm)
+{
+#define PREC_DUMPV(v4, v5) ((iov_pktq_log->version == 4) ? (v4) : (v5))
+
+#define v4hstubL "prec: rqstd, stored,selfsave, saved,fulldrop, dropped," \
+ "sacrficd, retried, rtsfail,rtrydrop, psretry,supprssd, " \
+ "acked,utlisatn,q length,Data Mbits/s,Phy Mbits/s,Rate Mbits/s"
+
+#define v4hstubS "prec: rqstd, stored, dropped, retried, rtsfail,rtrydrop, " \
+ "psretry, acked,utlisatn,q length,Data Mbits/s,Phy Mbits/s"
+
+#define v4fstubL " %02u: %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, " \
+ "%7u, %7u, %7u, %7u, %8.2f, %8.2f, %8.2f"
+
+#define v4fstubS " %02u: %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, " \
+ "%8.2f, %8.2f"
+
+#define v4fstubL_aqm " %02u: %7u, %7u, %7u, %7u, %7u, %7u, %7u, -, -, " \
+ "%7u, %7u, %7u, %7u, %7u, %7u, %8.2f, -, -"
+
+#define v4fstubS_aqm " %02u: %7u, %7u, %7u, -, -, %7u, %7u, %7u, %7u, " \
+ "%7u, %8.2f, -"
+
+ const char* v4headingsL = v4hstubL" (+v%d.)\n";
+ const char* v4headingsS = v4hstubS" (+v%d.)\n";
+ const char* v5headingsL = v4hstubL", %%air, %%effcy (v%d)\n";
+ const char* v5headingsS = v4hstubS", %%air, %%effcy (v%d)\n";
+
+ const char* v4formL = v4fstubL"\n";
+ const char* v4formS = v4fstubS"\n";
+ const char* v4formL_aqm = v4fstubL_aqm"\n";
+ const char* v4formS_aqm = v4fstubS_aqm"\n";
+
+ const char* v5formL = v4fstubL", %6.1f, %5.1f\n";
+ const char* v5formS = v4fstubS", %6.1f, %5.1f\n";
+ const char* v5formL_aqm = v4fstubL_aqm", -, -\n";
+ const char* v5formS_aqm = v4fstubS_aqm", -, -\n";
+
+ char* headings;
+ uint8 index;
+ uint8 prec;
+ uint32 prec_mask = 0;
+ char marker[4] = "[X]";
+ pktq_log_format_v05_t* logv05 = NULL;
+ pktq_log_format_v04_t* logv04 = NULL;
+
+ if (iov_pktq_log->version == 0x04) {
+ logv04 = &iov_pktq_log->pktq_log.v04;
+ }
+ else if (iov_pktq_log->version == 0x05) {
+ logv05 = &iov_pktq_log->pktq_log.v05;
+ }
+ else {
+ fprintf(stderr, "Unknown/unsupported binary format (%x)\n",
+ iov_pktq_log->version);
+ return;
+ }
+
+ headings = PREC_DUMPV(&logv04->headings[0], &logv05->headings[0]);
+
+ for (index = 0; index < (uint8)iov_pktq_log->params.num_addrs; index++) {
+
+ char* heading_start;
+ char* heading_end;
+ uint32 num_prec = 0;
+
+ prec_mask = PREC_DUMPV(logv04->counter_info[index],
+ logv05->counter_info[index]);
+ num_prec = PREC_DUMPV(logv04->num_prec[index],
+ logv05->num_prec[index]);
+
+ /* test for 'unknown' data; unknown means either that
+ * the queue is invalid or else that the logging
+ * is not active at all.
+ */
+ if (((prec_mask & 0xFFFF) == 0) && hide_unknown) {
+ continue;
+ }
+
+ if ((num_prec == 0) && hide_unknown) {
+ continue;
+ }
+
+ /* search for string marker - the marker is of the form
+ "[<index>]" where index is a single ascii numeral
+ */
+ marker[1] = '0' + index;
+ heading_start = strstr(headings, marker);
+
+ /* The driver may pass back an optional character
+ * string for additional info
+ */
+ if (heading_start != NULL) {
+
+ heading_start += strlen(marker);
+ heading_end = strstr(heading_start, marker);
+
+ if (heading_end == NULL) {
+ heading_end = heading_start + strlen(heading_start);
+ }
+ while (heading_start < heading_end) {
+ fputc(*heading_start++, stdout);
+ }
+ }
+
+ /* Note that this is zero if the data is invalid */
+ if (!num_prec) {
+ fprintf(stdout, "Parameter %c:%s not valid\n",
+ iov_pktq_log->params.addr_type[index] != 0 ?
+ iov_pktq_log->params.addr_type[index] & 0x7F : ' ',
+ wl_ether_etoa(&iov_pktq_log->params.ea[index]));
+ continue;
+ }
+
+ /* check for short form or long form (top bit set) */
+ fprintf(stdout,
+ iov_pktq_log->params.addr_type[index] & 0x80 ?
+ PREC_DUMPV(v4headingsL, v5headingsL) :
+ PREC_DUMPV(v4headingsS, v5headingsS),
+ iov_pktq_log->version);
+
+ for (prec = 0; prec < num_prec; prec++) {
+ float tput = 0.0;
+ float txrate_succ = 0.0;
+ float txrate_main = 0.0;
+ pktq_log_counters_v05_t counters;
+ uint32 try_count = 0;
+ float airuse = 0.0;
+ float efficiency = 0.0;
+
+ if (!(prec_mask & (1 << prec))) {
+ continue;
+ }
+
+ if (iov_pktq_log->version == 5) {
+ counters = logv05->counters[index][prec];
+ }
+ else {
+ /* the following is a trick - it is possible because
+ * V4 and V5 are both common except that V5 has extra fields
+ * at the end
+ */
+ memcpy(&counters, &logv04->counters[index][prec],
+ sizeof(pktq_log_counters_v04_t));
+ counters.airtime = 0;
+ }
+
+ txrate_succ = (float)((float)counters.txrate_succ * 0.5);
+
+ if (counters.time_delta != 0) {
+ /* convert bytes to bits */
+ tput = (float)counters.throughput;
+ tput *= 8.0;
+
+ if (counters.airtime) {
+ efficiency = (float)(100.0 * tput /
+ (float)counters.airtime);
+ }
+
+ /* converts to rate of bits per us,
+ because time_delta is in micro-seconds
+ */
+ tput /= (float)counters.time_delta;
+
+ /* Calculate % airtime */
+ airuse = (float)((float)counters.airtime * 100.0 /
+ (float)counters.time_delta);
+ }
+
+ if (!(is_aqm && (prec & 1))) {
+ uint32 acked = counters.acked;
+
+ try_count = counters.acked + counters.retry;
+
+ if (is_aqm && (prec_mask & (1 << (prec + 1)))) {
+ pktq_log_counters_v05_t hi;
+
+ if (iov_pktq_log->version == 5) {
+ hi = logv05->counters[index][prec + 1];
+ }
+ else {
+ /* the following is a trick - it is possible
+ * fields V4 and V5 are both common except
+ * that V5 has extra fields at the end
+ */
+ memcpy(&hi, &logv04->counters[index][prec + 1],
+ sizeof(pktq_log_counters_v04_t));
+ }
+
+ acked += hi.acked;
+ try_count += hi.acked + hi.retry;
+
+ if (counters.airtime) {
+ float t = (float)hi.throughput;
+ t /= (float)counters.airtime;
+ efficiency += (float)(100.0 * 8.0 * t);
+ }
+ }
+ if (acked) {
+ txrate_succ /= (float) acked;
+
+ if (counters.txrate_succ) {
+ efficiency /= txrate_succ;
+ }
+ else {
+ efficiency = 0;
+ }
+ }
+ else {
+ txrate_succ = 0;
+ efficiency = 0;
+ }
+ }
+
+ if (try_count) {
+ txrate_main = (float)((float)counters.txrate_main * 0.5);
+ txrate_main /= (float)try_count;
+ }
+
+ if (iov_pktq_log->params.addr_type[index] & 0x80) {
+ /* long form */
+ if (is_aqm && (prec & 1)) {
+ /* aqm format for hi-prec */
+ fprintf(stdout, PREC_DUMPV(v4formL_aqm, v5formL_aqm),
+ prec,
+ counters.requested,
+ counters.stored,
+ counters.selfsaved,
+ counters.saved,
+ counters.full_dropped,
+ counters.dropped,
+ counters.sacrificed,
+ counters.retry_drop,
+ counters.ps_retry,
+ counters.suppress,
+ counters.acked,
+ counters.max_used,
+ counters.queue_capacity,
+ tput);
+ }
+ else {
+ fprintf(stdout, PREC_DUMPV(v4formL, v5formL),
+ prec,
+ counters.requested,
+ counters.stored,
+ counters.selfsaved,
+ counters.saved,
+ counters.full_dropped,
+ counters.dropped,
+ counters.sacrificed,
+ counters.retry,
+ counters.rtsfail,
+ counters.retry_drop,
+ counters.ps_retry,
+ counters.suppress,
+ counters.acked,
+ counters.max_used,
+ counters.queue_capacity,
+ tput, txrate_succ,
+ txrate_main,
+ airuse, efficiency);
+ }
+ }
+ else {
+ /* short form */
+ if (is_aqm && (prec & 1)) {
+ /* aqm format for hi-prec */
+ fprintf(stdout, PREC_DUMPV(v4formS_aqm, v5formS_aqm),
+ prec,
+ counters.requested,
+ counters.stored,
+ counters.dropped,
+ counters.retry_drop,
+ counters.ps_retry,
+ counters.acked,
+ counters.max_used,
+ counters.queue_capacity,
+ tput);
+ }
+ else {
+ fprintf(stdout, PREC_DUMPV(v4formS, v5formS),
+ prec,
+ counters.requested,
+ counters.stored,
+ counters.dropped,
+ counters.retry,
+ counters.rtsfail,
+ counters.retry_drop,
+ counters.ps_retry,
+ counters.acked,
+ counters.max_used,
+ counters.queue_capacity,
+ tput, txrate_succ,
+ airuse, efficiency);
+ }
+ }
+ }
+ fputs("\n", stdout);
+
+ if (iov_pktq_log->version == 5 &&
+ (logv05->pspretend_time_delta[index] != (uint32)-1)) {
+
+ fprintf(stdout, "Total time in ps pretend state is %d milliseconds\n\n",
+ (logv05->pspretend_time_delta[index] + 500)/1000);
+ }
+ }
+}
+
+static int
+wl_scb_bs_data(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int32 flag_bits = 0;
+ int argn;
+ enum { DISPLAY_COOKED, DISPLAY_RAW } display_mode = DISPLAY_COOKED;
+ iov_bs_data_struct_t *data = (iov_bs_data_struct_t *)buf;
+ char sep = ' ';
+ bool skip_idle = FALSE;
+ float total_throughput = 0.0;
+
+ UNUSED_PARAMETER(cmd); /* cmd->name should match argv[0] ? */
+
+ if (!argv[0]) {
+ fprintf(stderr, "%s: argv[0] missing\n", __FUNCTION__);
+ return BCME_BADARG;
+ }
+
+ for (argn = 1; argv[argn]; ++argn) {
+ if (!strcmp(argv[argn], "-noreset")) { /* do not reset counters after reading */
+ flag_bits |= SCB_BS_DATA_FLAG_NO_RESET;
+ } else
+ if (!strcmp(argv[argn], "-raw")) { /* Display raw counters */
+ display_mode = DISPLAY_RAW;
+ } else
+ if (!strcmp(argv[argn], "-tab")) { /* Tab separator */
+ sep = '\t';
+ } else
+ if (!strcmp(argv[argn], "-comma")) { /* Comma separator */
+ sep = ',';
+ } else
+ if (!strcmp(argv[argn], "-noidle")) { /* Skip idle stations */
+ skip_idle = TRUE;
+ } else
+ if (!strcmp(argv[argn], "-help") || !strcmp(argv[argn], "-h")) {
+ /* Display usage, do not complain about unknown option. */
+ return BCME_USAGE_ERROR;
+ } else {
+ fprintf(stderr, "%s: unknown option: %s\n", argv[0], argv[argn]);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ flag_bits = htod32(flag_bits);
+ err = wlu_iovar_getbuf(wl, argv[0], &flag_bits, sizeof(flag_bits), buf, WLC_IOCTL_MAXLEN);
+ if (err) {
+ return (err);
+ }
+
+ data->structure_version = dtoh16(data->structure_version);
+ if (data->structure_version != SCB_BS_DATA_STRUCT_VERSION) {
+ fprintf(stderr, "wlu / wl driver mismatch, expect V%d format, got %d.\n",
+ SCB_BS_DATA_STRUCT_VERSION, data->structure_version);
+ return BCME_IOCTL_ERROR;
+ }
+
+ data->structure_count = dtoh16(data->structure_count);
+ if (data->structure_count == 0) {
+ printf("No stations are currently associated.\n");
+ return BCME_OK;
+ }
+
+ /* Display Column headers - mac address always, then, depending on display mode */
+
+ printf("%17s%c", "Station Address", sep);
+ switch (display_mode) {
+ case DISPLAY_RAW:
+ printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
+ "retry_drop", "rtsfail", "retry", "txrate_main",
+ "txrate_succ", "acked", "throughput", "time_delta", "airtime");
+ break;
+ case DISPLAY_COOKED:
+ printf("%10s%c%10s%c%10s%c%10s%c%10s\n", "PHY Mbps", sep, "Data Mbps", sep,
+ "Air Use", sep, "Data Use", sep, "Retries");
+ break;
+ }
+
+ /* Convert returned counters to host byte order, and sum up total throughput */
+
+ for (argn = 0; argn < data->structure_count; ++argn) {
+
+ iov_bs_data_record_t *rec;
+ iov_bs_data_counters_t *ctr;
+ float data_rate;
+
+ rec = &data->structure_record[argn];
+ ctr = &rec->station_counters;
+
+#define DEVICE_TO_HOST(xyzzy) ctr->xyzzy = dtoh32(ctr->xyzzy)
+ DEVICE_TO_HOST(retry_drop);
+ DEVICE_TO_HOST(rtsfail);
+ DEVICE_TO_HOST(retry);
+ DEVICE_TO_HOST(txrate_main);
+ DEVICE_TO_HOST(txrate_succ);
+ DEVICE_TO_HOST(acked);
+ DEVICE_TO_HOST(throughput);
+ DEVICE_TO_HOST(time_delta);
+ DEVICE_TO_HOST(airtime);
+#undef DEVICE_TO_HOST
+
+ /* Calculate data rate in bits per second, rather than bytes per second */
+ data_rate = (ctr->time_delta) ?
+ (float)((float)ctr->throughput * 8.0 / (float)ctr->time_delta) : 0.0;
+
+ total_throughput += data_rate;
+ }
+
+ for (argn = 0; argn < data->structure_count; ++argn) {
+ iov_bs_data_record_t *rec;
+ iov_bs_data_counters_t *ctr;
+ rec = &data->structure_record[argn];
+ ctr = &rec->station_counters;
+
+ if (skip_idle && (ctr->acked == 0)) continue;
+
+ printf("%17s%c", wl_ether_etoa(&rec->station_address), sep);
+ switch (display_mode) {
+ case DISPLAY_RAW:
+ printf("%9d %9d %9d %9d %9d %9d %9d %9d %9d\n",
+ ctr->retry_drop, ctr->rtsfail, ctr->retry,
+ ctr->txrate_main, ctr->txrate_succ, ctr->acked,
+ ctr->throughput, ctr->time_delta, ctr->airtime);
+ break;
+ case DISPLAY_COOKED:
+ {
+ float data_rate;
+ float phy_rate;
+ float use, air, rtr;
+
+ /* Calculate PHY rate */
+ phy_rate = (ctr->acked) ?
+ (float)((float)ctr->txrate_succ * 0.5 / (float)ctr->acked) : 0.0;
+
+ /* Calculate Data rate */
+ data_rate = (ctr->time_delta) ?
+ (float)((float)ctr->throughput * 8.0 / (float)ctr->time_delta) :
+ 0.0;
+
+ /* Calculate use percentage amongst throughput from all stations */
+ use = (total_throughput) ? (float)(data_rate / total_throughput * 100.0) :
+ 0.0;
+
+ /* Calculate % airtime */
+ air = (ctr->time_delta) ? (float)((float)ctr->airtime * 100.0 /
+ (float) ctr->time_delta) : 0.0;
+
+ /* Calculate retry percentage */
+ rtr = (ctr->acked) ? (float)((float)ctr->retry / (float)ctr->acked * 100) :
+ 0.0;
+
+ printf("%10.1f%c%10.1f%c%9.1f%%%c%9.1f%%%c%9.1f%%\n",
+ phy_rate, sep, data_rate, sep, air, sep, use, sep, rtr);
+ }
+ break;
+ }
+ }
+ return BCME_OK;
+}
+
+/* IO variables that take MAC addresses (with optional single letter prefix)
+ * and output a string buffer
+ */
+static int
+wl_iov_pktqlog_params(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ char** macaddrs = argv + 1;
+
+ wl_iov_mac_full_params_t* full_params = (wl_iov_mac_full_params_t*)buf;
+ wl_iov_mac_params_t* params = &full_params->params;
+ wl_iov_mac_extra_params_t* extra_params = &full_params->extra_params;
+
+ wl_iov_mac_params_t loop_params;
+ wl_iov_mac_extra_params_t loop_extra_params;
+ uint32 index;
+ bool loop_assoclist = FALSE;
+ struct maclist* maclist = NULL;
+ wlc_rev_info_t revinfo;
+ uint32 corerev;
+
+ if (cmd->get < 0)
+ return -1;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (ret) {
+ return ret;
+ }
+ corerev = dtoh32(revinfo.corerev);
+
+ memset(full_params, 0, sizeof(*full_params));
+ memset(&loop_params, 0, sizeof(loop_params));
+ memset(&loop_extra_params, 0, sizeof(loop_extra_params));
+
+ /* only pass up to WL_IOV_MAC_PARAM_LEN parameters */
+ while (params->num_addrs < WL_IOV_MAC_PARAM_LEN && *macaddrs) {
+ bool full_auto = FALSE;
+ char* ptr = *macaddrs;
+ uint32 bitmask;
+
+ /* is there a prefix character? */
+ if (ptr[1] == ':') {
+ params->addr_type[params->num_addrs] = toupper((int)(ptr[0]));
+
+ /* move ptr to skip over prefix */
+ ptr += 2;
+
+ /* is there the 'long form' option ? */
+ if (ptr[0] == '+') {
+ /* check for + additional info option, set top bit */
+ params->addr_type[params->num_addrs] |= 0x80;
+ ptr++;
+ }
+ if ((ptr[0] == 0) || (ptr[0] == '/' || ptr[0] == ',')) {
+ /* this is the fully automatic mode */
+ full_auto = TRUE;
+ }
+ }
+
+ /* the prefix C: denotes no given MAC address (to refer to "common") */
+ if ((params->addr_type[params->num_addrs] & 0x7F) == 'C') {
+ full_auto = FALSE;
+ }
+ else if (full_auto) {
+ loop_assoclist = TRUE;
+ loop_params.addr_type[loop_params.num_addrs] =
+ params->addr_type[params->num_addrs];
+ }
+ else if (wl_ether_atoe(ptr, ¶ms->ea[params->num_addrs])) {
+ /* length of MAC addr string excl end char */
+ ptr += (ETHER_ADDR_STR_LEN - 1);
+ }
+ else {
+ params->addr_type[params->num_addrs] = 0;
+ printf("Bad parameter '%s'\n", *macaddrs);
+ ++macaddrs;
+ continue;
+ }
+
+
+ bitmask = 0;
+
+ while (ptr && (ptr[0] == ',' || ptr[0] == '/') &&
+ ((ptr[1] >= '0' && ptr[1] <= '9') ||
+ ptr[1] == '/' || ptr[1] == ',')) {
+
+ uint8 prec;
+ char* endptr = 0;
+
+ if (ptr[1] == '/' || ptr[1] == ',') {
+ /* this is the 'auto' setting */
+ bitmask |= PKTQ_LOG_AUTO;
+ ptr += 2;
+ }
+ else {
+ ptr++;
+
+ prec = (uint8)strtoul(ptr, &endptr, 10);
+
+ if (prec <= 15) {
+ bitmask |= (1 << prec);
+ }
+ else {
+ printf("Bad precedence %d (will be ignored)\n",
+ prec);
+ }
+ ptr = endptr;
+ }
+
+ }
+
+ if (bitmask == 0) {
+ /* PKTQ_LOG_DEF_PREC is ignored in V4, it is used to indicate no prec was
+ * selected
+ */
+ bitmask = 0xFFFF | PKTQ_LOG_DEF_PREC;
+ }
+
+ if (full_auto) {
+ loop_extra_params.addr_info[loop_params.num_addrs] = bitmask;
+ loop_params.num_addrs++;
+ }
+ else {
+ extra_params->addr_info[params->num_addrs] = bitmask;
+ params->num_addrs ++;
+ }
+ ++macaddrs;
+ }
+
+ while (*macaddrs) {
+ printf("Ignoring excess parameter '%s' (maximum number of params is %d)\n",
+ *macaddrs, WL_IOV_MAC_PARAM_LEN);
+ ++macaddrs;
+ }
+
+ /* if no valid params found, pass default prefix 'C' with no mac address */
+ if (params->num_addrs == 0 && !loop_assoclist)
+ {
+ params->addr_type[0] = 'C';
+ extra_params->addr_info[0] = 0xFFFF;
+ params->num_addrs = 1;
+ }
+
+ if (params->num_addrs) {
+ /* set a "version" indication (ie extra_params present) */
+ params->num_addrs |= (4 << 8);
+
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, full_params,
+ sizeof(*full_params),
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ fprintf(stderr, "Error getting variable %s\n", argv[0]);
+ return ret;
+ }
+
+ wl_txq_prec_dump((wl_iov_pktq_log_t*)buf, FALSE, corerev >= 40);
+
+ }
+ if (!loop_assoclist) {
+ return 0;
+ }
+
+ maclist = malloc(WLC_IOCTL_MEDLEN);
+
+ if (!maclist) {
+ fprintf(stderr, "unable to allocate memory\n");
+ return -ENOMEM;
+ }
+ maclist->count = htod32((WLC_IOCTL_MEDLEN - sizeof(int)) / ETHER_ADDR_LEN);
+
+ if ((ret = wlu_get(wl, WLC_GET_ASSOCLIST, maclist, WLC_IOCTL_MEDLEN)) < 0) {
+ fprintf(stderr, "Cannot get assoclist\n");
+ free(maclist);
+ return ret;
+ }
+ maclist->count = dtoh32(maclist->count);
+
+ if (maclist->count == 0) {
+ fprintf(stderr, "No available addresses in assoclist for automatic operation\n");
+ free(maclist);
+ return 0;
+ }
+
+ for (index = 0; index < loop_params.num_addrs; index++) {
+ uint32 ea_index = 0;
+
+ while (ea_index < maclist->count) {
+
+ memset(full_params, 0, sizeof(*full_params));
+
+ while ((params->num_addrs < WL_IOV_MAC_PARAM_LEN) &&
+ (ea_index < maclist->count)) {
+
+ params->addr_type[params->num_addrs] = loop_params.addr_type[index];
+ params->ea[params->num_addrs] = maclist->ea[ea_index];
+ extra_params->addr_info[params->num_addrs] =
+ loop_extra_params.addr_info[index] | PKTQ_LOG_AUTO;
+
+ params->num_addrs++;
+ ea_index++;
+ }
+
+ /* set a "version" indication (ie extra_params present) */
+ params->num_addrs |= (4 << 8);
+
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, full_params,
+ sizeof(*full_params),
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ fprintf(stderr, "Error getting %s\n", argv[0]);
+ free(maclist);
+ return ret;
+ }
+
+ wl_txq_prec_dump((wl_iov_pktq_log_t*)buf, TRUE, corerev >= 40);
+ }
+ }
+ free(maclist);
+ return 0;
+}
+
+static int
+wlu_dump_phytbls(void *wl, char *dump_buf)
+{
+ /* The IOVAR's used in iteration */
+ const char str_phytbl[] = "phytbl";
+ const char str_phytbl_page[] = "phydump_page";
+ const char str_phytbl_entry[] = "phydump_entry";
+ int phytbl_page = 0;
+ int phytbl_entry = 0;
+ int ret;
+
+ /* Initialize page and entry */
+ ret = wlu_iovar_setint(wl, str_phytbl_page, phytbl_page);
+ if (ret != BCME_OK) {
+ fprintf(stderr, "IOVAR %s is not supported by firmware\n", str_phytbl_page);
+ } else {
+ ret = wlu_iovar_setint(wl, str_phytbl_entry, phytbl_entry);
+ if (ret != BCME_OK) {
+ fprintf(stderr, "IOVAR %s is not supported by firmware\n",
+ str_phytbl_entry);
+ }
+ else {
+ /* Dump the whole table by iterating str_phytbl IOVAR */
+ do {
+ strncpy(dump_buf, str_phytbl, sizeof(str_phytbl));
+ if ((ret = wlu_iovar_getbuf(wl, "dump",
+ dump_buf, (int)strlen(dump_buf),
+ dump_buf, WL_DUMP_BUF_LEN)) >= 0) {
+ fputs(dump_buf, stdout);
+ memset(dump_buf, 0, WL_DUMP_BUF_LEN);
+ if (((ret = wlu_iovar_getint(wl, str_phytbl_page,
+ &phytbl_page)) >= 0) &&
+ (phytbl_page == 0)) {
+ ret = wlu_iovar_getint(wl, str_phytbl_entry,
+ &phytbl_entry);
+ }
+ }
+ /* Iteration ends when both page and entry wrap around */
+ } while ((ret >= BCME_OK) && ((phytbl_page != 0) || (phytbl_entry != 0)));
+ }
+ }
+ return ret;
+}
+
+static int
+wlu_dump(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, err, bcmerr;
+ char *dump_buf;
+
+ /* This suboption is only known to wl, IOVAR list won't show it */
+ const char str_phytbls[] = "phytbls";
+
+ if (cmd->get < 0)
+ return -1;
+
+ dump_buf = malloc(WL_DUMP_BUF_LEN);
+ if (dump_buf == NULL) {
+ fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WL_DUMP_BUF_LEN);
+ return BCME_NOMEM;
+ }
+ memset(dump_buf, 0, WL_DUMP_BUF_LEN);
+
+ /* skip the command name */
+ argv++;
+
+ /* If no args given, get the subset of 'wl dump all'
+ * Otherwise, if args are given, they are the dump section names.
+ */
+ if (*argv == NULL) {
+ /* query for the 'dump' without any argument */
+ ret = wlu_iovar_getbuf(wl, "dump", NULL, 0, dump_buf, WL_DUMP_BUF_LEN);
+
+ /* if the query is successful, continue on and print the result. */
+
+ /* if the query fails, check for a legacy driver that does not support
+ * the "dump" iovar, and instead issue a WLC_DUMP ioctl.
+ */
+ if (ret) {
+ err = wlu_iovar_getint(wl, "bcmerror", &bcmerr);
+ if (!err && (bcmerr == BCME_UNSUPPORTED)) {
+ ret = wlu_get(wl, WLC_DUMP, dump_buf, WL_DUMP_BUF_LEN);
+ if (ret) {
+ fprintf(stderr, "dump: error on query of WLC_DUMP\n");
+ }
+ } else {
+ fprintf(stderr, "dump: error on query of dump list\n");
+ }
+ }
+ } else if (!strncmp(*argv, str_phytbls, sizeof(str_phytbls))) {
+ ret = wlu_dump_phytbls(wl, dump_buf);
+ } else {
+ /* create the dump section name list */
+ while (*argv) {
+ /* add space delimiter if this is not the first section name */
+ if (dump_buf[0] != '\0')
+ strcat(dump_buf, " ");
+
+ strcat(dump_buf, *argv);
+
+ argv++;
+ }
+
+ /* This is a "space" added at end of last argument */
+ strcat(dump_buf, " ");
+
+ ret = wlu_iovar_getbuf(wl, "dump", dump_buf, (int)strlen(dump_buf),
+ dump_buf, WL_DUMP_BUF_LEN);
+ }
+
+ if (ret >= BCME_OK) {
+ ret = BCME_OK;
+ fputs(dump_buf, stdout);
+ }
+
+ free(dump_buf);
+
+ return ret;
+}
+
+static int
+wlu_dump_clr(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+
+ /* skip the command name */
+ argv++;
+
+ /* call dump_clear for each category */
+ while (*argv != NULL) {
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+
+ ret = wlu_iovar_setbuf(wl, cmd->name, *argv, strlen(*argv),
+ buf, WLC_IOCTL_MAXLEN);
+ if (ret != BCME_OK) {
+ fprintf(stderr, "%s: error on %s\n", cmd->name, *argv);
+ return ret;
+ }
+ argv++;
+ }
+
+ return BCME_OK;
+}
+
+static int
+wl_staprio(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = BCME_USAGE_ERROR;
+ wl_staprio_cfg_t staprio_cfg;
+ char *endptr = NULL;
+
+ if (!*++argv) return -1;
+
+ /* get link mac address */
+ if (!wl_ether_atoe(*argv++, &staprio_cfg.ea))
+ goto error;
+
+ if (argv[0]) {
+ staprio_cfg.prio = (uint8)strtol(argv[0], &endptr, 0);
+ if (*endptr != '\0')
+ goto error;
+
+ if (staprio_cfg.prio > 3) {
+ printf("prio %d out of range [0, 3]\n", staprio_cfg.prio);
+ goto error;
+ }
+ else {
+ printf("Set SCB prio: 0x%x\n", staprio_cfg.prio);
+ ret = wlu_iovar_setbuf(wl, cmd->name, (void *) &staprio_cfg,
+ sizeof(wl_staprio_cfg_t), buf, WLC_IOCTL_MEDLEN);
+ }
+ }
+ else {
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, (void *) &staprio_cfg,
+ sizeof(wl_staprio_cfg_t), buf, WLC_IOCTL_MEDLEN)) >= 0) {
+ printf("SCB prio: 0x%x\n", ((wl_staprio_cfg_t *)buf)->prio);
+ }
+ }
+
+error:
+ return ret;
+}
+
+static int
+wl_aibss_bcn_force_config(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = BCME_USAGE_ERROR;
+ aibss_bcn_force_config_t bcn_config;
+
+ if (!*++argv) {
+ /* Get */
+ memset(&bcn_config, 0, sizeof(aibss_bcn_force_config_t));
+ /* get current rateset */
+ if ((ret = wlu_iovar_get(wl, cmd->name, &bcn_config,
+ sizeof(aibss_bcn_force_config_t))) < 0)
+ goto error;
+
+ printf("AIBSS Initial beacon check duration: %d \r\n"
+ "AIBSS beacon check duration:%d \r\n"
+ "AIBSS beacon flood duration:%d\r\n",
+ bcn_config.initial_min_bcn_dur, bcn_config.min_bcn_dur,
+ bcn_config.bcn_flood_dur);
+ }
+ else {
+ char *p = argv[0];
+ char *endptr = NULL;
+
+ /* Extract the content */
+ if (!p || *p == '\0')
+ goto error;
+
+ bcn_config.initial_min_bcn_dur = strtoul(p, &endptr, 0);
+
+ p = endptr;
+ /* check and skip , */
+ if (*p == '\0' || *++p == '\0')
+ goto error;
+
+ bcn_config.min_bcn_dur = strtoul(p, &endptr, 0);
+
+ p = endptr;
+ /* check and skip , */
+ if (*p == '\0' || *++p == '\0')
+ goto error;
+
+ bcn_config.bcn_flood_dur = strtoul(p, &endptr, 0);
+
+ if (*endptr != '\0')
+ goto error;
+ bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0;
+ bcn_config.len = sizeof(aibss_bcn_force_config_t);
+ ret = wlu_iovar_set(wl, cmd->name, (void *) &bcn_config,
+ sizeof(aibss_bcn_force_config_t));
+ }
+
+error:
+ return ret;
+}
+
+
+static int
+wlu_srdump(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, i, nw, nb = 0;
+ uint16 *words = (uint16 *)&buf[8];
+
+ srom_rw_t *srt;
+
+ /*
+ * Avoid wl utility to driver compatibility issues by reading a 'safe' amount of words from
+ * SPROM to determine the SPROM version that the driver supports, once the version is known
+ * the full SPROM contents can be read. At the moment sromrev12 is the largest.
+ */
+ nw = MAX(MAX(SROM10_SIGN, SROM11_SIGN), SROM11_SIGN) + 1;
+
+ srt = (srom_rw_t *)buf;
+ srt->byteoff = htod32(0);
+ srt->nbytes = htod32(2 * nw);
+
+ if (cmd->get < 0)
+ return -1;
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+
+ if (words[SROM11_SIGN] == SROM15_SIGNATURE) {
+ nw = SROM15_WORDS;
+ } else if (words[SROM11_SIGN] == SROM13_SIGNATURE) {
+ nw = SROM13_WORDS;
+ } else if (words[SROM11_SIGN] == SROM12_SIGNATURE) {
+ nw = SROM12_WORDS;
+ } else if (words[SROM11_SIGN] == SROM11_SIGNATURE) {
+ nw = SROM11_WORDS;
+ } else if (words[SROM10_SIGN] == SROM10_SIGNATURE) {
+ nw = SROM10_WORDS;
+ } else if (words[SROM16_SIGN] == SROM16_SIGNATURE) {
+ nw = SROM16_WORDS;
+ } else {
+ nw = SROM4_WORDS;
+ if ((words[SROM4_SIGN] != SROM4_SIGNATURE) &&
+ (words[SROM8_SIGN] != SROM4_SIGNATURE))
+ nw = SROM_WORDS;
+ }
+
+ /* allow reading a larger (or any other-size one) if specified */
+ if (*++argv != NULL) {
+ nb = (int)strtol(*argv, NULL, 0);
+ if (nb & 1) {
+ printf("Byte count %d is odd\n", nb);
+ return BCME_BADARG;
+ }
+ nw = nb / 2;
+ }
+
+ /* Since the SROM version known at this point, the entire SPROM contents can be read */
+ srt->nbytes = htod32(2 * nw);
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+
+ for (i = 0; i < nw; i++) {
+ if ((i % 8) == 0)
+ printf("\n srom[%03d]: ", i);
+ printf("0x%04x ", words[i]);
+ }
+ printf("\n");
+
+ return 0;
+}
+
+int
+wlu_srwrite(void *wl, cmd_t *cmd, char **argv)
+{
+#if !defined(BWL_FILESYSTEM_SUPPORT)
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
+ return (-1);
+#elif defined(DONGLEBUILD)
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
+ return 0;
+#else
+ char *arg;
+ char *endptr;
+ FILE *fp = NULL;
+ int ret = 0, erase, srcrc;
+ uint i, len;
+ srom_rw_t *srt = (srom_rw_t *)buf;
+ char *tempbuf = NULL;
+
+ erase = !strcmp(*argv, "srclear");
+ srcrc = !strcmp(*argv, "srcrc");
+
+ /* We need at least one arg */
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ arg = *argv++;
+
+ if (erase) {
+ if (*argv)
+ return BCME_USAGE_ERROR;
+ len = strtoul(arg, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "error parsing value \"%s\" as an integer for byte count\n",
+ arg);
+ return BCME_USAGE_ERROR;
+ }
+ srt->byteoff = 0x55aa;
+ } else if (!*argv) { /* srwrite or srcrc */
+ /* Only one arg, it better be a file name */
+ if (!(fp = fopen(arg, "rb"))) {
+ fprintf(stderr, "%s: No such file or directory\n", arg);
+ return BCME_BADARG;
+ }
+
+ len = fread(srt->buf, 1, SROM_MAX + 1, fp);
+ if ((ret = ferror(fp))) {
+ printf("\nerror %d reading %s\n", ret, arg);
+ ret = BCME_ERROR;
+ goto out;
+ }
+
+ if (!feof(fp)) {
+ printf("\nFile %s is too large\n", arg);
+ ret = BCME_ERROR;
+ goto out;
+ }
+
+ if (len == SROM4_WORDS * 2) {
+ if ((srt->buf[SROM4_SIGN] != SROM4_SIGNATURE) &&
+ (srt->buf[SROM8_SIGN] != SROM4_SIGNATURE)) {
+ printf("\nFile %s is %d bytes but lacks a REV4/ signature\n",
+ arg, SROM4_WORDS * 2);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ } else if (len == SROM11_WORDS * 2) {
+ if (srt->buf[SROM11_SIGN] != SROM11_SIGNATURE) {
+ printf("\nFile %s is %d bytes but lacks a REV11/ signature\n",
+ arg, SROM11_WORDS * 2);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ } else if (len == SROM12_WORDS * 2) {
+ if ((srt->buf[SROM11_SIGN] != SROM12_SIGNATURE) &&
+ (srt->buf[SROM16_SIGN] != SROM16_SIGNATURE)) {
+ printf("\nFile %s is %d bytes but lacks a REV12/REV16 signature\n",
+ arg, SROM12_WORDS * 2);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ } else if (len == SROM13_WORDS * 2) {
+ if (srt->buf[SROM11_SIGN] != SROM13_SIGNATURE) {
+ printf("\nFile %s is %d bytes but lacks a REV13/ signature\n",
+ arg, SROM13_WORDS * 2);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ } else if (len == SROM15_WORDS * 2) {
+ if ((srt->buf[SROM11_SIGN] != SROM15_SIGNATURE) &&
+ (srt->buf[SROM16_SIGN] != SROM16_SIGNATURE)) {
+ printf("\nFile %s is %d bytes but lacks a REV15/REV16 signature\n",
+ arg, SROM15_WORDS * 2);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ }
+ else if ((len != SROM_WORDS * 2) && (len != SROM10_WORDS * 2) &&
+ (len != SROM_MAX)) {
+ printf("\nFile %s is %d bytes, not %d or %d or %d or %d bytes\n", arg, len,
+ SROM_WORDS * 2, SROM4_WORDS * 2, SROM10_WORDS, SROM_MAX);
+ ret = BCME_ERROR;
+ goto out;
+ }
+
+ srt->byteoff = 0;
+ } else {
+ if (srcrc) {
+ printf("srcrc only takes one arg\n");
+ ret = BCME_USAGE_ERROR;
+ goto out;
+ }
+
+ /* More than 1 arg, first is offset, rest are data. */
+ srt->byteoff = strtoul(arg, &endptr, 0);
+ if (*endptr != '\0')
+ goto nout;
+
+ i = 0;
+ while ((arg = *argv++) != NULL) {
+ srt->buf[i++] = (uint16)strtoul(arg, &endptr, 0);
+ if (*endptr != '\0') {
+nout:
+ printf("\n%s is not an integer\n", arg);
+ ret = BCME_USAGE_ERROR;
+ goto out;
+ }
+ }
+
+ if (srt->byteoff & 1) {
+ printf("Byte offset (%d) is odd or negative\n", srt->byteoff);
+ ret = BCME_BADARG;
+ goto out;
+ }
+
+ len = 2 * i;
+ if ((srt->byteoff + len) > SROM_MAX) {
+ printf("Data extends past %d bytes\n", SROM_MAX);
+ ret = BCME_BUFTOOLONG;
+ goto out;
+ }
+ }
+ srt->nbytes = len;
+
+ if (srcrc) {
+ srt->byteoff = 0x55ab; /* Hack for srcrc */
+ if ((ret = wlu_get(wl, cmd->get, buf, len + 8)) == 0)
+ printf("0x%x\n", (uint8)buf[0]);
+ } else {
+ tempbuf = malloc(SROM_MAX);
+ if (tempbuf == NULL) {
+ ret = BCME_NOMEM;
+ goto out;
+ }
+ if ((arg != NULL) && (len > MAX_IOCTL_TXCHUNK_SIZE) && (srt->byteoff != 0x55aa)) {
+ if (!(fp = fopen(arg, "rb"))) {
+ fprintf(stderr, "%s: No such file or directory\n", arg);
+ ret = BCME_BADARG;
+ goto out;
+ }
+ len = fread(tempbuf, 1, SROM_MAX + 1, fp);
+ memcpy(srt->buf, tempbuf, MAX_IOCTL_TXCHUNK_SIZE);
+ srt->byteoff = htod32(0);
+ srt->nbytes = htod32(MAX_IOCTL_TXCHUNK_SIZE);
+ ret = wlu_set(wl, cmd->set, buf, MAX_IOCTL_TXCHUNK_SIZE + 8);
+ memcpy(srt->buf, tempbuf + MAX_IOCTL_TXCHUNK_SIZE,
+ len - MAX_IOCTL_TXCHUNK_SIZE);
+ srt->byteoff = htod32(MAX_IOCTL_TXCHUNK_SIZE);
+ srt->nbytes = htod32(len - MAX_IOCTL_TXCHUNK_SIZE);
+ ret = wlu_set(wl, cmd->set, buf, len - MAX_IOCTL_TXCHUNK_SIZE + 8);
+ }
+ else {
+ ret = wlu_set(wl, cmd->set, buf, len + 8);
+ }
+ }
+
+out:
+ fflush(stdout);
+ if (fp)
+ fclose(fp);
+ if (tempbuf)
+ free(tempbuf);
+ return ret;
+#endif /* BWL_FILESYSTEM_SUPPORT */
+}
+
+static int
+wlu_ciswrite(void *wl, cmd_t *cmd, char **argv)
+{
+#if !defined(BWL_FILESYSTEM_SUPPORT)
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
+ return (-1);
+#elif defined(DONGLEBUILD)
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
+ return 0;
+#else
+ char *arg, *bufp;
+ FILE *fp = NULL;
+ int ret = 0;
+ uint32 len;
+
+ cis_rw_t cish;
+ char *cisp, *cisdata;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* arg check -- error if no arg */
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ memset((char*)&cish, 0, sizeof(cish));
+ /* Grab and move past optional output file argument */
+ if ((strcmp(*argv, "--pciecis") == 0) || (strcmp(*argv, "-p") == 0)) {
+ printf("Writing in PCIe CIS format\n");
+
+ cish.flags |= CISH_FLAG_PCIECIS; /* write CIS format bit */
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ }
+
+ /* initialize buffer with iovar */
+ bufp = buf;
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(bufp, "ciswrite");
+ bufp += strlen("ciswrite") + 1;
+ cisp = bufp;
+ cisdata = cisp + sizeof(cish);
+
+ /* grab the filename arg */
+ arg = *argv;
+ if (!(fp = fopen(arg, "rb"))) {
+ fprintf(stderr, "%s: No such file or directory\n", arg);
+ return BCME_BADARG;
+ }
+
+ len = fread(cisdata, 1, SROM_MAX + 1, fp);
+ if ((ret = ferror(fp))) {
+ printf("\nerror %d reading %s\n", ret, arg);
+ ret = BCME_ERROR;
+ goto out;
+ }
+
+ if (!feof(fp)) {
+ printf("\nFile %s is too large\n", arg);
+ ret = BCME_ERROR;
+ goto out;
+ }
+
+ /* Convert the endianess for non-zero fields */
+ cish.flags = htod16(cish.flags);
+ cish.nbytes = htod32(len); /* fill in length (offset is 0) */
+ memcpy(cisp, (char*)&cish, sizeof(cish));
+
+ printf("len %d sizeof(cish) %d total %d\n", len, (int)sizeof(cish),
+ (int)(len + sizeof(cish)));
+ ret = wl_set(wl, WLC_SET_VAR, buf, (cisp - buf) + sizeof(cish) + len);
+ if (ret < 0) {
+ fprintf(stderr, "ciswrite failed: %d\n", ret);
+ }
+
+out:
+ if (fp)
+ fclose(fp);
+
+ return ret;
+#endif /* BWL_FILESYSTEM_SUPPORT */
+}
+
+static int
+wlu_cisupdate(void *wl, cmd_t *cmd, char **argv)
+{
+#if defined(DONGLEBUILD)
+ return 0;
+#else
+ char *bufp, *endptr;
+ int ret = 0;
+ int preview = 0;
+ uint32 off;
+ uint32 len;
+ uint32 updatelen;
+ uint32 i;
+ char hexstr[3];
+ char bytes[SROM_MAX];
+
+ cis_rw_t cish;
+ char *cisp;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* validate arg count */
+ if (!*++argv || !argv[1])
+ return BCME_USAGE_ERROR;
+
+ if (argv[2] && !strcmp(argv[2], "--preview"))
+ preview = 1;
+
+ /* grab byte offset */
+ off = (uint32)strtol(argv[0], &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+
+ bufp = argv[1];
+ updatelen = strlen(bufp);
+ if (updatelen % 2) {
+ fprintf(stderr, "cisupdate hex string must contain an even number of digits\n");
+ goto done;
+ }
+ updatelen /= 2;
+
+ /* convert and store hex byte values */
+ for (i = 0; i < updatelen; i++) {
+ hexstr[0] = *bufp;
+ hexstr[1] = *(bufp + 1);
+ if (!isxdigit((int)hexstr[0]) || !isxdigit((int)hexstr[1])) {
+ fprintf(stderr, "cisupdate invalid hex digit(s) in %s\n", argv[1]);
+ goto done;
+ }
+ hexstr[2] = '\0';
+ bytes[i] = (char) strtol(hexstr, NULL, 16);
+ bufp += 2;
+ }
+
+ /* Prepare the read info */
+ memset((char*)&cish, 0, sizeof(cish));
+
+ /* set up the buffer and do the get (+9 allows space for "ciswrite" string later) */
+ memset(buf + 9, 0, (WLC_IOCTL_MAXLEN - 9));
+ strcpy(buf + 9, "cisdump");
+ bufp = buf + strlen("cisdump") + 1 + 9;
+ memcpy(bufp, (char*)&cish, sizeof(cish));
+ bufp += sizeof(cish);
+ ret = wl_get(wl, WLC_GET_VAR, buf + 9, (bufp - (buf + 9)) + SROM_MAX);
+ if (ret < 0) {
+ fprintf(stderr, "cisupdate failed to read cis: %d\n", ret);
+ goto done;
+ }
+
+ /* pull off the cis_rw_t */
+ bufp = buf + 9;
+ memcpy((char*)&cish, bufp, sizeof(cish));
+ len = dtoh32(cish.nbytes);
+
+ if ((off + updatelen) > len) {
+ fprintf(stderr, "cisupdate offset %d plus update len %d exceeds CIS len %d\n",
+ off, updatelen, len);
+ goto done;
+ }
+
+ /* move past to the data */
+ bufp += sizeof(cish);
+
+ /* update the bytes */
+ if (dtoh16(cish.source) == WLC_CIS_SROM) {
+ for (i = 0; i < updatelen; ++i)
+ bufp[off + i] = bytes[i] & 0xff;
+ } else {
+ for (i = 0; i < updatelen; ++i) {
+ if (~bytes[i] & bufp[off + i]) {
+ fprintf(stderr, "cisupdate: OTP update incompatible:"
+ " update[%d](0x%02x)->cis[%d](0x%02x)\n",
+ i, bytes[i], off + i, bufp[off + i]);
+ goto done;
+ }
+ bufp[off + i] |= bytes[i];
+ }
+ }
+
+ /* initialize buffer with iovar */
+ bufp = buf;
+ strcpy(bufp, "ciswrite");
+ bufp += strlen("ciswrite") + 1;
+ cisp = bufp;
+
+ /* fill in cis_rw_t fields */
+ memset((char*)&cish, 0, sizeof(cish));
+ cish.nbytes = htod32(len);
+ memcpy(cisp, (char*)&cish, sizeof(cish));
+
+ /* write the data back to the device */
+ printf("offset %d data %s cislen %d\n", off, argv[1], len);
+ if (preview) {
+ bufp += sizeof(cish);
+ for (i = 0; i < len; i++) {
+ if ((i % 8) == 0)
+ printf("\nByte %3d: ", i);
+ printf("0x%02x ", (uint8)bufp[i]);
+ }
+ printf("\n");
+ } else {
+ ret = wl_set(wl, WLC_SET_VAR, buf, (cisp - buf) + sizeof(cish) + len);
+ if (ret < 0) {
+ fprintf(stderr, "cisupdate cis write failed: %d\n", ret);
+ }
+ }
+
+done:
+ return ret;
+#endif
+}
+
+static int
+wlu_cisdump(void *wl, cmd_t *cmd, char **argv)
+{
+ char *bufp;
+ int i, ret = 0;
+ cis_rw_t cish;
+ uint nbytes = 0;
+ char *fname = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* Grab and move past optional output file argument */
+ if ((argv[1] != NULL) && (strcmp(argv[1], "-b") == 0)) {
+ fname = argv[2];
+ argv += 2;
+ }
+
+ /* check for a length argument */
+ if (*++argv != NULL) {
+ nbytes = (int)strtol(*argv, NULL, 0);
+ if (nbytes & 1) {
+ printf("Invalid byte count %d, must be even\n", nbytes);
+ ret = BCME_BADARG;
+ goto done;
+ }
+ if (nbytes > SROM_MAX) {
+ printf("Count %d too large\n", nbytes);
+ ret = BCME_BUFTOOLONG;
+ goto done;
+ }
+ }
+
+ /* Prepare the read info */
+ memset((char*)&cish, 0, sizeof(cish));
+ cish.nbytes = htod32(nbytes);
+
+ /* set up the buffer and do the get */
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(buf, "cisdump");
+ bufp = buf + strlen("cisdump") + 1;
+ memcpy(bufp, (char*)&cish, sizeof(cish));
+ bufp += sizeof(cish);
+ ret = wl_get(wl, WLC_GET_VAR, buf, (bufp - buf) + (nbytes ? nbytes : SROM_MAX));
+ if (ret < 0) {
+ fprintf(stderr, "Failed cisdump request: %d\n", ret);
+ goto done;
+ }
+
+ /* pull off the cis_rw_t */
+ bufp = buf;
+ memcpy((char*)&cish, bufp, sizeof(cish));
+ cish.source = dtoh16(cish.source);
+ cish.flags = dtoh16(cish.flags);
+ cish.byteoff = dtoh32(cish.byteoff);
+ cish.nbytes = dtoh32(cish.nbytes);
+
+ /* move past to the data */
+ bufp += sizeof(cish);
+
+ printf("Source: %d (%s)", cish.source,
+ (cish.source == WLC_CIS_DEFAULT) ? "Built-in default" :
+ (cish.source == WLC_CIS_SROM) ? "External SPROM" :
+ (cish.source == WLC_CIS_OTP) ? "Internal OTP" : "Unknown?");
+ if (!nbytes)
+ printf("\nMaximum length: %d bytes", cish.nbytes);
+ for (i = 0; i < (int)cish.nbytes; i++) {
+ if ((i % 8) == 0)
+ printf("\nByte %3d: ", i);
+ printf("0x%02x ", (uint8)bufp[i]);
+ }
+ printf("\n");
+
+#if defined(BWL_FILESYSTEM_SUPPORT)
+#if !defined(DONGLEBUILD)
+ if (fname != NULL) {
+ FILE *fp;
+
+ if (!nbytes)
+ nbytes = cish.nbytes;
+
+ fp = fopen(fname, "wb");
+ if (fp != NULL) {
+ ret = fwrite(bufp, 1, nbytes, fp);
+ if (ret != (int)nbytes) {
+ fprintf(stderr, "Error writing %d bytes to file, rc %d!\n",
+ (int)nbytes, ret);
+ ret = BCME_ERROR;
+ } else {
+ printf("Wrote %d bytes to %s\n", ret, fname);
+ ret = 0;
+ }
+ fclose(fp);
+ } else {
+ fprintf(stderr, "Problem opening file %s\n", fname);
+ ret = BCME_BADARG;
+ }
+ }
+#endif /* !(CFE|DONGLEBUILD|IOPOS) -- has stdio filesystem */
+#endif /* BWL_FILESYSTEM_SUPPORT */
+
+done:
+ return ret;
+}
+
+#if defined(linux) || defined(DONGLEBUILD) || defined(__FreeBSD__) || \
+ defined(BWL_NO_INTERNAL_STDLIB_SUPPORT)
+/* linux, MacOS, NetBSD: ffs is in the standard C library */
+/* CFE, DONGLEBUILD & IOPOS: Not needed, the code below is ifdef out */
+#else
+static int
+ffs(int i)
+{
+ int j;
+
+ if (i != 0)
+ for (j = 0; j < 32; j++)
+ if (i & (1 << j))
+ return j + 1;
+ return 0;
+}
+#endif
+
+#if !defined(DONGLEBUILD)
+
+/* VX wants prototypes even for static functions. */
+static int newtuple(char *b, int *cnt, uint8 tag, const cis_tuple_t *srv);
+static int parsecis(char *b, char **argv, int sromrev);
+static const sromvar_t *srvlookup(const sromvar_t *tab, char *name, int nlen, int sromrev);
+
+/* Find an entry in argv[][] in this form
+ * name=value, could be pattern=(0x)1234 or pattern=ABC
+ *
+ * If *val is NULL, return the pointer to value.
+ * If *val is not NULL, fill the value into val, return the pointer to name if found,
+ * return NULL if no match found.
+ */
+char*
+find_pattern(char **argv, const char *pattern, uint *val)
+{
+ char *ret = NULL, *name = NULL, **pargv = argv;
+
+ /* clear val first */
+ if (val) *val = 0;
+
+ while ((name = *pargv++)) {
+ if ((ret = strstr(name, pattern))) {
+ char *p = ret, *q = NULL;
+
+ /* Extracting the content */
+ p += strlen(pattern);
+
+ /* var name could have same prefix */
+ if (*p++ != '=') {
+ ret = NULL;
+ continue;
+ }
+ if (!val)
+ return (ret+strlen(pattern)+1);
+
+ *val = strtoul(p, &q, 0);
+ if (p == q) {
+ printf("Bad value: %s\n", ret);
+ return NULL;
+ }
+
+ break;
+ }
+ }
+ return ret;
+}
+
+/* Find an entry in argv[][] in this form
+ * name=value1,value2,...,value(n)
+ * n is indicated by vnum
+ * could be pattern=(0x)1234,... or pattern=ABC,...
+ *
+ * If *val is NULL, return the pointer to value.
+ * If *val is not NULL, fill the value into val, return the pointer to name if found,
+ * return NULL if no match found.
+ */
+char*
+find_pattern2(char **argv, const char *pattern, uint *val, int vnum)
+{
+ char *ret = NULL, *name = NULL, **pargv = argv;
+ int i;
+
+ while ((name = *pargv++)) {
+ if ((ret = strstr(name, pattern))) {
+ char *p = ret, *q = NULL;
+
+ /* Extracting the content */
+ p += strlen(pattern);
+
+ /* var name could have same prefix */
+ if (*p++ != '=') {
+ ret = NULL;
+ continue;
+ }
+ if (!val)
+ return (ret+strlen(pattern)+1);
+
+ for (i = 0; i < vnum; i ++)
+ {
+ val[i] = strtoul(p, &q, 0);
+
+ if (p == q) {
+ printf("Bad value: %s\n", ret);
+ return NULL;
+ }
+ p = q + 1; /* skip ',' */
+ }
+ break;
+ }
+ }
+ return ret;
+}
+
+static int
+newtuple(char *b, int *cnt, uint8 tag, const cis_tuple_t *srv)
+{
+ memset(b, 0, srv->len + 2);
+
+ b[0] = tag;
+ b[1] = (char)srv->len;
+ b[2] = (char)srv->tag;
+
+ if (cnt)
+ *cnt += 3;
+ return 0;
+}
+
+/**
+ * When programming OTP or SROM, driver expects to receive a CIS from the wl utility.
+ * This function converts a caller supplied string (in **argv) containing nvram variables pairs into
+ * a CIS (in *b). Caller can dictate the binary CIS contents by using nvram string 'RAW=...' or
+ * 'RAW1=...'. Function will only create tuples for values in caller supplied nvram string.
+ */
+static int
+parsecis(char *b, char **argv, int sromrev)
+{
+ /* built-in list of known tuples and nvram var(s) associated with a specific tuple */
+ const cis_tuple_t *srv = cis_hnbuvars;
+ char *cpar = NULL, *p = NULL;
+ char *par;
+ char delimit[2] = " \0";
+ int cnt = 0, i = 0;
+ uint sromrev_mask = 0xffffffff;
+
+ if (sromrev > 0 && sromrev <= 31) {
+ sromrev_mask = 1 << sromrev;
+ } else {
+ printf("Invalid sromrev %d.\n", sromrev);
+ return BCME_BADARG;
+ }
+
+ /* Walk through built-in list of tuples, create append buffer */
+ while (srv->tag != 0xFF) {
+ uint val = 0;
+
+ /* Skip srv if not supported in sromrev */
+ if (!(sromrev_mask & srv->revmask)) {
+ srv++;
+ continue;
+ }
+
+ /* Special cases (Raw Data / macaddr / ccode / fem) */
+ if (srv->tag == OTP_RAW) {
+ if ((p = find_pattern(argv, "RAW", &val))) {
+ p += (strlen("RAW") + 1); /* RAW= */
+ for (;;) {
+ b[cnt++] = (unsigned char) strtoul(p, &p, 16);
+ if (!*p++)
+ break;
+ }
+ }
+ } else if (srv->tag == OTP_RAW1) {
+ if ((p = find_pattern(argv, "RAW1", NULL))) {
+ for (;;) {
+ b[cnt++] = (unsigned char) strtoul(p, &p, 16);
+ if (!*p++)
+ break;
+ }
+ }
+ } else if (srv->tag == OTP_VERS_1) {
+ uint l1 = 1, l2 = 1;
+ char *p2 = NULL;
+
+ if ((p = find_pattern(argv, "manf", NULL)))
+ l1 += strlen(p);
+
+ if ((p2 = find_pattern(argv, "productname", NULL)))
+ l2 += strlen(p2);
+
+ if ((p != NULL) | (p2 != NULL)) {
+ b[cnt++] = CISTPL_VERS_1;
+ b[cnt++] = 2 + l1 + l2;
+ b[cnt++] = 8;
+ b[cnt++] = 0;
+ if (p) {
+ char *q = p;
+ /* Replace '_' by space */
+ while ((q = strchr(q, '_')))
+ *q = ' ';
+ memcpy(&b[cnt], p, l1);
+ } else
+ b[cnt] = '\0';
+ cnt += l1;
+
+ if (p2) {
+ char *q = p2;
+ /* Replace '_' by space */
+ while ((q = strchr(q, '_')))
+ *q = ' ';
+ memcpy(&b[cnt], p2, l2);
+ } else
+ b[cnt] = '\0';
+ cnt += l2;
+ }
+ } else if (srv->tag == OTP_MANFID) {
+ bool found = FALSE;
+ uint manfid = 0, prodid = 0;
+
+ if ((p = find_pattern(argv, "manfid", &manfid)))
+ found = TRUE;
+
+ if ((p = find_pattern(argv, "prodid", &prodid)))
+ found = TRUE;
+
+ if (found) {
+ b[cnt++] = CISTPL_MANFID;
+ b[cnt++] = srv->len;
+ b[cnt++] = (uint8)(manfid & 0xff);
+ b[cnt++] = (uint8)((manfid >> 8) & 0xff);
+ b[cnt++] = (uint8)(prodid & 0xff);
+ b[cnt++] = (uint8)((prodid >> 8) & 0xff);
+ }
+ } else if (srv->tag == HNBU_MACADDR) {
+ if ((p = find_pattern(argv, "macaddr", NULL))) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ if (!wl_ether_atoe(p, (struct ether_addr*)&b[cnt]))
+ printf("Argument does not look like a MAC "
+ "address: %s\n", p);
+ cnt += sizeof(struct ether_addr);
+ }
+ } else if (srv->tag == HNBU_MACADDR2) {
+ if ((p = find_pattern(argv, "macaddr2", NULL))) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ if (!wl_ether_atoe(p, (struct ether_addr*)&b[cnt]))
+ printf("Argument does not look like a MAC "
+ "address: %s\n", p);
+ cnt += sizeof(struct ether_addr);
+ }
+ } else if (srv->tag == HNBU_CCODE) {
+ bool found = FALSE;
+ char tmp[3] = "\0\0\0";
+
+ if ((p = find_pattern(argv, "ccode", NULL))) {
+ found = TRUE;
+ tmp[0] = *p++;
+ tmp[1] = *p++;
+ }
+ if ((p = find_pattern(argv, "cctl", &val))) {
+ found = TRUE;
+ tmp[2] = (uint8)val;
+ }
+ if (found) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ memcpy(&b[cnt], tmp, 3);
+ cnt += 3; /* contents filled already */
+ }
+ } else if (srv->tag == HNBU_RSSISMBXA2G) {
+ bool found = FALSE;
+ char tmp[2] = "\0\0";
+
+ if ((p = find_pattern(argv, "rssismf2g", &val))) {
+ found = TRUE;
+ tmp[0] |= val & 0xf;
+ }
+ if ((p = find_pattern(argv, "rssismc2g", &val))) {
+ found = TRUE;
+ tmp[0] |= (val & 0xf) << 4;
+ }
+ if ((p = find_pattern(argv, "rssisav2g", &val))) {
+ found = TRUE;
+ tmp[1] |= val & 0x7;
+ }
+ if ((p = find_pattern(argv, "bxa2g", &val))) {
+ found = TRUE;
+ tmp[1] |= (val & 0x3) << 3;
+ }
+ if (found) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ memcpy(&b[cnt], tmp, 2);
+ cnt += 2; /* contents filled already */
+ }
+ } else if (srv->tag == HNBU_RSSISMBXA5G) {
+ bool found = FALSE;
+ char tmp[2] = "\0\0";
+
+ if ((p = find_pattern(argv, "rssismf5g", &val))) {
+ found = TRUE;
+ tmp[0] |= val & 0xf;
+ }
+ if ((p = find_pattern(argv, "rssismc5g", &val))) {
+ found = TRUE;
+ tmp[0] |= (val & 0xf) << 4;
+ }
+ if ((p = find_pattern(argv, "rssisav5g", &val))) {
+ found = TRUE;
+ tmp[1] |= val & 0x7;
+ }
+ if ((p = find_pattern(argv, "bxa5g", &val))) {
+ found = TRUE;
+ tmp[1] |= (val & 0x3) << 3;
+ }
+ if (found) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ memcpy(&b[cnt], tmp, 2);
+ cnt += 2; /* contents filled already */
+ }
+ } else if (srv->tag == HNBU_FEM) {
+ bool found = FALSE;
+ uint16 tmp2g = 0, tmp5g = 0;
+
+ if ((p = find_pattern(argv, "antswctl2g", &val))) {
+ found = TRUE;
+ tmp2g |= ((val << SROM8_FEM_ANTSWLUT_SHIFT) &
+ SROM8_FEM_ANTSWLUT_MASK);
+ }
+ if ((p = find_pattern(argv, "triso2g", &val))) {
+ found = TRUE;
+ tmp2g |= ((val << SROM8_FEM_TR_ISO_SHIFT) &
+ SROM8_FEM_TR_ISO_MASK);
+ }
+ if ((p = find_pattern(argv, "pdetrange2g", &val))) {
+ found = TRUE;
+ tmp2g |= ((val << SROM8_FEM_PDET_RANGE_SHIFT) &
+ SROM8_FEM_PDET_RANGE_MASK);
+ }
+ if ((p = find_pattern(argv, "extpagain2g", &val))) {
+ found = TRUE;
+ tmp2g |= ((val << SROM8_FEM_EXTPA_GAIN_SHIFT) &
+ SROM8_FEM_EXTPA_GAIN_MASK);
+ }
+ if ((p = find_pattern(argv, "tssipos2g", &val))) {
+ found = TRUE;
+ tmp2g |= ((val << SROM8_FEM_TSSIPOS_SHIFT) &
+ SROM8_FEM_TSSIPOS_MASK);
+ }
+ if ((p = find_pattern(argv, "antswctl5g", &val))) {
+ found = TRUE;
+ tmp5g |= ((val << SROM8_FEM_ANTSWLUT_SHIFT) &
+ SROM8_FEM_ANTSWLUT_MASK);
+ }
+ if ((p = find_pattern(argv, "triso5g", &val))) {
+ found = TRUE;
+ tmp5g |= ((val << SROM8_FEM_TR_ISO_SHIFT) &
+ SROM8_FEM_TR_ISO_MASK);
+ }
+ if ((p = find_pattern(argv, "pdetrange5g", &val))) {
+ found = TRUE;
+ tmp5g |= ((val << SROM8_FEM_PDET_RANGE_SHIFT) &
+ SROM8_FEM_PDET_RANGE_MASK);
+ }
+ if ((p = find_pattern(argv, "extpagain5g", &val))) {
+ found = TRUE;
+ tmp5g |= ((val << SROM8_FEM_EXTPA_GAIN_SHIFT) &
+ SROM8_FEM_EXTPA_GAIN_MASK);
+ }
+ if ((p = find_pattern(argv, "tssipos5g", &val))) {
+ found = TRUE;
+ tmp5g |= ((val << SROM8_FEM_TSSIPOS_SHIFT) &
+ SROM8_FEM_TSSIPOS_MASK);
+ }
+
+ if (found) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ b[cnt++] = (uint8)(tmp2g & 0xff);
+ b[cnt++] = (uint8)((tmp2g >> 8) & 0xff);
+ b[cnt++] = (uint8)(tmp5g & 0xff);
+ b[cnt++] = (uint8)((tmp5g >> 8) & 0xff);
+ }
+ } else if (srv->tag == HNBU_UUID) {
+
+ char *uuidstr = NULL;
+ char nibble[3] = {0, 0, 0};
+
+ if ((uuidstr = find_pattern(argv, "uuid", NULL)) != NULL) {
+
+ /* uuid format 12345678-1234-5678-1234-567812345678 */
+
+ if (strlen(uuidstr) == 36) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ while (*uuidstr != '\0') {
+ if (*uuidstr == '-') {
+ uuidstr++;
+ continue;
+ }
+ nibble[0] = *uuidstr++;
+ nibble[1] = *uuidstr++;
+ b[cnt ++] = (char)strtoul(nibble, NULL, 16);
+ }
+ }
+ }
+
+ } else if (srv->tag == HNBU_TEMPTHRESH) {
+ bool found = FALSE;
+ char tmp[6] = "\0\0\0\0\0\0";
+
+ if ((p = find_pattern(argv, "tempthresh", &val))) {
+ found = TRUE;
+ tmp[0] = val;
+ }
+ if ((p = find_pattern(argv, "temps_period", &val))) {
+ found = TRUE;
+ tmp[1] |= ((val << SROM11_TEMPS_PERIOD_SHIFT) &
+ SROM11_TEMPS_PERIOD_MASK);
+ }
+ if ((p = find_pattern(argv, "temps_hysteresis", &val))) {
+ found = TRUE;
+ tmp[1] |= ((val << SROM11_TEMPS_HYSTERESIS_SHIFT) &
+ SROM11_TEMPS_HYSTERESIS_MASK);
+ }
+ if ((p = find_pattern(argv, "tempoffset", &val))) {
+ found = TRUE;
+ tmp[2] = val;
+ }
+ if ((p = find_pattern(argv, "tempsense_slope", &val))) {
+ found = TRUE;
+ tmp[3] = val;
+ }
+ if ((p = find_pattern(argv, "tempcorrx", &val))) {
+ found = TRUE;
+ tmp[4] |= ((val << SROM11_TEMPCORRX_SHIFT) &
+ SROM11_TEMPCORRX_MASK);
+ }
+ if ((p = find_pattern(argv, "tempsense_option", &val))) {
+ found = TRUE;
+ tmp[4] |= ((val << SROM11_TEMPSENSE_OPTION_SHIFT) &
+ SROM11_TEMPSENSE_OPTION_MASK);
+ }
+ if ((p = find_pattern(argv, "phycal_tempdelta", &val))) {
+ found = TRUE;
+ tmp[5] = val;
+ }
+
+ if (found) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ memcpy(&b[cnt], tmp, 6);
+ cnt += 6; /* contents filled already */
+ }
+ } else if (srv->tag == HNBU_FEM_CFG) {
+ bool found = FALSE;
+ uint16 fem_cfg1 = 0, fem_cfg2 = 0;
+
+ if ((p = find_pattern(argv, "femctrl", &val))) {
+ found = TRUE;
+ fem_cfg1 |= ((val << SROM11_FEMCTRL_SHIFT) &
+ SROM11_FEMCTRL_MASK);
+ }
+ if ((p = find_pattern(argv, "papdcap2g", &val))) {
+ found = TRUE;
+ fem_cfg1 |= ((val << SROM11_PAPDCAP_SHIFT) &
+ SROM11_PAPDCAP_MASK);
+ }
+ if ((p = find_pattern(argv, "tworangetssi2g", &val))) {
+ found = TRUE;
+ fem_cfg1 |= ((val << SROM11_TWORANGETSSI_SHIFT) &
+ SROM11_TWORANGETSSI_MASK);
+ }
+ if ((p = find_pattern(argv, "pdgain2g", &val))) {
+ found = TRUE;
+ fem_cfg1 |= ((val << SROM11_PDGAIN_SHIFT) &
+ SROM11_PDGAIN_MASK);
+ }
+ if ((p = find_pattern(argv, "epagain2g", &val))) {
+ found = TRUE;
+ fem_cfg1 |= ((val << SROM11_EPAGAIN_SHIFT) &
+ SROM11_EPAGAIN_MASK);
+ }
+ if ((p = find_pattern(argv, "tssiposslope2g", &val))) {
+ found = TRUE;
+ fem_cfg1 |= ((val << SROM11_TSSIPOSSLOPE_SHIFT) &
+ SROM11_TSSIPOSSLOPE_MASK);
+ }
+ if ((p = find_pattern(argv, "gainctrlsph", &val))) {
+ found = TRUE;
+ fem_cfg2 |= ((val << SROM11_GAINCTRLSPH_SHIFT) &
+ SROM11_GAINCTRLSPH_MASK);
+ }
+ if ((p = find_pattern(argv, "papdcap5g", &val))) {
+ found = TRUE;
+ fem_cfg2 |= ((val << SROM11_PAPDCAP_SHIFT) &
+ SROM11_PAPDCAP_MASK);
+ }
+ if ((p = find_pattern(argv, "tworangetssi5g", &val))) {
+ found = TRUE;
+ fem_cfg2 |= ((val << SROM11_TWORANGETSSI_SHIFT) &
+ SROM11_TWORANGETSSI_MASK);
+ }
+ if ((p = find_pattern(argv, "pdgain5g", &val))) {
+ found = TRUE;
+ fem_cfg2 |= ((val << SROM11_PDGAIN_SHIFT) &
+ SROM11_PDGAIN_MASK);
+ }
+ if ((p = find_pattern(argv, "epagain5g", &val))) {
+ found = TRUE;
+ fem_cfg2 |= ((val << SROM11_EPAGAIN_SHIFT) &
+ SROM11_EPAGAIN_MASK);
+ }
+ if ((p = find_pattern(argv, "tssiposslope5g", &val))) {
+ found = TRUE;
+ fem_cfg2 |= ((val << SROM11_TSSIPOSSLOPE_SHIFT) &
+ SROM11_TSSIPOSSLOPE_MASK);
+ }
+
+ if (found) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ b[cnt++] = (uint8)(fem_cfg1 & 0xff);
+ b[cnt++] = (uint8)((fem_cfg1 >> 8) & 0xff);
+ b[cnt++] = (uint8)(fem_cfg2 & 0xff);
+ b[cnt++] = (uint8)((fem_cfg2 >> 8) & 0xff);
+ }
+ } else if (srv->tag == HNBU_ACRXGAINS_C0) {
+ bool found = FALSE;
+ uint16 rxgains = 0, rxgains1 = 0;
+
+ if ((p = find_pattern(argv, "rxgains5gtrelnabypa0", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS5GTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS5GTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gtrisoa0", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS5GTRISOA_SHIFT) &
+ SROM11_RXGAINS5GTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gelnagaina0", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS5GELNAGAINA_SHIFT) &
+ SROM11_RXGAINS5GELNAGAINA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains2gtrelnabypa0", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS2GTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS2GTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains2gtrisoa0", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS2GTRISOA_SHIFT) &
+ SROM11_RXGAINS2GTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains2gelnagaina0", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS2GELNAGAINA_SHIFT) &
+ SROM11_RXGAINS2GELNAGAINA_MASK);
+ }
+
+ if ((p = find_pattern(argv, "rxgains5ghtrelnabypa0", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GHTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS5GHTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5ghtrisoa0", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GHTRISOA_SHIFT) &
+ SROM11_RXGAINS5GHTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5ghelnagaina0", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GHELNAGAINA_SHIFT) &
+ SROM11_RXGAINS5GHELNAGAINA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gmtrelnabypa0", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GMTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS5GMTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gmtrisoa0", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GMTRISOA_SHIFT) &
+ SROM11_RXGAINS5GMTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gmelnagaina0", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GMELNAGAINA_SHIFT) &
+ SROM11_RXGAINS5GMELNAGAINA_MASK);
+ }
+
+ if (found) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ b[cnt++] = (uint8)(rxgains & 0xff);
+ b[cnt++] = (uint8)((rxgains >> 8) & 0xff);
+ b[cnt++] = (uint8)(rxgains1 & 0xff);
+ b[cnt++] = (uint8)((rxgains1 >> 8) & 0xff);
+ }
+ } else if (srv->tag == HNBU_ACRXGAINS_C1) {
+ bool found = FALSE;
+ uint16 rxgains = 0, rxgains1 = 0;
+
+ if ((p = find_pattern(argv, "rxgains5gtrelnabypa1", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS5GTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS5GTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gtrisoa1", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS5GTRISOA_SHIFT) &
+ SROM11_RXGAINS5GTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gelnagaina1", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS5GELNAGAINA_SHIFT) &
+ SROM11_RXGAINS5GELNAGAINA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains2gtrelnabypa1", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS2GTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS2GTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains2gtrisoa1", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS2GTRISOA_SHIFT) &
+ SROM11_RXGAINS2GTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains2gelnagaina1", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS2GELNAGAINA_SHIFT) &
+ SROM11_RXGAINS2GELNAGAINA_MASK);
+ }
+
+ if ((p = find_pattern(argv, "rxgains5ghtrelnabypa1", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GHTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS5GHTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5ghtrisoa1", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GHTRISOA_SHIFT) &
+ SROM11_RXGAINS5GHTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5ghelnagaina1", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GHELNAGAINA_SHIFT) &
+ SROM11_RXGAINS5GHELNAGAINA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gmtrelnabypa1", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GMTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS5GMTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gmtrisoa1", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GMTRISOA_SHIFT) &
+ SROM11_RXGAINS5GMTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gmelnagaina1", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GMELNAGAINA_SHIFT) &
+ SROM11_RXGAINS5GMELNAGAINA_MASK);
+ }
+
+ if (found) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ b[cnt++] = (uint8)(rxgains & 0xff);
+ b[cnt++] = (uint8)((rxgains >> 8) & 0xff);
+ b[cnt++] = (uint8)(rxgains1 & 0xff);
+ b[cnt++] = (uint8)((rxgains1 >> 8) & 0xff);
+ }
+ } else if (srv->tag == HNBU_ACRXGAINS_C2) {
+ bool found = FALSE;
+ uint16 rxgains = 0, rxgains1 = 0;
+
+ if ((p = find_pattern(argv, "rxgains5gtrelnabypa2", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS5GTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS5GTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gtrisoa2", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS5GTRISOA_SHIFT) &
+ SROM11_RXGAINS5GTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gelnagaina2", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS5GELNAGAINA_SHIFT) &
+ SROM11_RXGAINS5GELNAGAINA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains2gtrelnabypa2", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS2GTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS2GTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains2gtrisoa2", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS2GTRISOA_SHIFT) &
+ SROM11_RXGAINS2GTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains2gelnagaina2", &val))) {
+ found = TRUE;
+ rxgains |= ((val << SROM11_RXGAINS2GELNAGAINA_SHIFT) &
+ SROM11_RXGAINS2GELNAGAINA_MASK);
+ }
+
+ if ((p = find_pattern(argv, "rxgains5ghtrelnabypa2", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GHTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS5GHTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5ghtrisoa2", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GHTRISOA_SHIFT) &
+ SROM11_RXGAINS5GHTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5ghelnagaina2", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GHELNAGAINA_SHIFT) &
+ SROM11_RXGAINS5GHELNAGAINA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gmtrelnabypa2", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GMTRELNABYPA_SHIFT) &
+ SROM11_RXGAINS5GMTRELNABYPA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gmtrisoa2", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GMTRISOA_SHIFT) &
+ SROM11_RXGAINS5GMTRISOA_MASK);
+ }
+ if ((p = find_pattern(argv, "rxgains5gmelnagaina2", &val))) {
+ found = TRUE;
+ rxgains1 |= ((val << SROM11_RXGAINS5GMELNAGAINA_SHIFT) &
+ SROM11_RXGAINS5GMELNAGAINA_MASK);
+ }
+
+ if (found) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ b[cnt++] = (uint8)(rxgains & 0xff);
+ b[cnt++] = (uint8)((rxgains >> 8) & 0xff);
+ b[cnt++] = (uint8)(rxgains1 & 0xff);
+ b[cnt++] = (uint8)((rxgains1 >> 8) & 0xff);
+ }
+ } else if (srv->tag == HNBU_PDOFF_2G) {
+ bool found = FALSE;
+ uint16 tmppdoff2g = 0;
+
+ if ((p = find_pattern(argv, "pdoffset2g40ma0", &val))) {
+ found = TRUE;
+ tmppdoff2g |= ((val << SROM11_PDOFF_2G_40M_A0_SHIFT) &
+ SROM11_PDOFF_2G_40M_A0_MASK);
+ }
+
+ if ((p = find_pattern(argv, "pdoffset2g40ma1", &val))) {
+ found = TRUE;
+ tmppdoff2g |= ((val << SROM11_PDOFF_2G_40M_A1_SHIFT) &
+ SROM11_PDOFF_2G_40M_A1_MASK);
+ }
+
+ if ((p = find_pattern(argv, "pdoffset2g40ma2", &val))) {
+ found = TRUE;
+ tmppdoff2g |= ((val << SROM11_PDOFF_2G_40M_A2_SHIFT) &
+ SROM11_PDOFF_2G_40M_A2_MASK);
+ }
+
+ if ((p = find_pattern(argv, "pdoffset2g40mvalid", &val))) {
+ found = TRUE;
+ tmppdoff2g |= ((val << SROM11_PDOFF_2G_40M_VALID_SHIFT) &
+ SROM11_PDOFF_2G_40M_VALID_MASK);
+ }
+
+ if (found) {
+ newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
+ b[cnt++] = (uint8)(tmppdoff2g & 0xff);
+ b[cnt++] = (uint8)((tmppdoff2g >> 8) & 0xff);
+ }
+ } else { /* All other tuples */
+ int found = FALSE, varlen = 0;
+ char *cur = &b[cnt];
+ uint newtp = TRUE;
+
+ /* example srv->params contents: "1aa2g 1aa5g" */
+ par = malloc(strlen(srv->params)+1);
+ if (!par)
+ return BCME_NOMEM;
+
+ /* Walk through each parameters in one tuple */
+ strcpy(par, srv->params);
+
+ cpar = strtok (par, delimit); /* current param */
+ while (cpar) {
+ int array_sz = 1;
+ val = 0;
+
+ /* Fill the CIS tuple to b but don't commit cnt yet */
+ if (newtp) {
+ newtuple(cur, NULL, CISTPL_BRCM_HNBU, srv);
+ cur += 3;
+ newtp = FALSE;
+ }
+
+ /* the first byte of each parameter indicates its length */
+ varlen = (*cpar++) - '0';
+
+ /* parse array size if any */
+ if (*cpar == '*') {
+ array_sz = 0;
+ while (((*++cpar) >= '0') && (*cpar <= '9'))
+ array_sz = (array_sz * 10) + *cpar - '0';
+ }
+
+ /* Find the parameter in the input argument list */
+ if ((p = find_pattern(argv, cpar, &val)))
+ found = TRUE;
+ else
+ val = 0;
+
+ while (found && array_sz--) {
+ *cur++ = (uint8)(val & 0xff);
+ if (varlen >= 2)
+ *cur++ = (uint8)((val >> 8) & 0xff);
+ if (varlen >= 4) {
+ *cur++ = (uint8)((val >> 16) & 0xff);
+ *cur++ = (uint8)((val >> 24) & 0xff);
+ }
+
+ /* skip the "," if more array elements */
+ if (p && array_sz) {
+ char *q = NULL;
+
+ p = strstr (p, ","); /* current param */
+ if (p) {
+ p++;
+ val = strtoul(p, &q, strncmp(p, "0x", 2) ?
+ 10 : 16);
+ } else {
+ printf("Input array size error!");
+ free(par);
+ return BCME_BADARG;
+ }
+ }
+ }
+
+ /* move to the next parameter string */
+ cpar = strtok(NULL, delimit);
+ }
+ free(par);
+
+ /* commit the tuple if its valid */
+ if (found)
+ cnt += (cur - &b[cnt]);
+ }
+
+ srv++;
+ }
+
+ printf("sromrev %d buffer size %d bytes:\n", sromrev, cnt);
+ for (i = 0; i < cnt; i++) {
+ printf("0x%.02x ", b[i] & 0xff);
+ if (i%8 == 7) printf("\n");
+ }
+ printf("\n");
+
+ return cnt;
+}
+
+static const sromvar_t *
+srvlookup(const sromvar_t *tab, char *name, int nlen, int sromrev)
+{
+ uint32 srrmask;
+ const sromvar_t *srv = tab;
+
+ srrmask = 1 << sromrev;
+
+ while (srv->name) {
+ if ((strncmp(name, srv->name, nlen) == 0) &&
+ ((srrmask & srv->revmask) != 0))
+ break;
+ while (srv->flags & SRFL_MORE)
+ srv++;
+ srv++;
+ }
+
+ return srv;
+}
+#endif
+
+/** read/write caller supplied NVRAM variables in OTP or SROM */
+static int
+wlu_srvar(void *wl, cmd_t *cmd, char **argv)
+{
+#if defined(DONGLEBUILD)
+ return 0;
+#else
+ int ret, nw, nlen, ro, co, wr, sromrev, shift = 0;
+ bool otp = FALSE;
+ uint32 val32 = 0;
+ char *name, *p, *newval;
+ const sromvar_t *srv;
+ uint16 w, *words = (uint16 *)&buf[8];
+ srom_rw_t *srt;
+ struct ether_addr ea;
+
+ ro = !strcmp(*argv, "rdvar");
+ wr = !strcmp(*argv, "wrvar");
+ co = !strcmp(*argv, "cisconvert");
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ /* Query the driver on where the cis comes from: OTP or SROM */
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(buf, "cis_source");
+ ret = wl_get(wl, WLC_GET_VAR, buf, strlen(buf)+1);
+ if (ret < 0) {
+ ; /* printf("Error %x: cannot get cis_source\n", ret); */
+ }
+
+ if (buf[0] == WLC_CIS_OTP)
+ otp = TRUE;
+ if (otp && ro) {
+ /* read caller supplied nvram variable from driver */
+ wl_nvget(wl, cmd, --argv);
+ return ret;
+ }
+
+ /*
+ * Before OTP can be written, the caller supplied nvram string has to be converted into a
+ * list of CIS tuples. This CIS format is SROM rev dependent.
+ */
+ if ((otp && wr) || co) {
+ int cnt = 0, err = 0;
+ uint sromrev = 8;
+ void *p = NULL;
+
+ /* Read all nvram variables from driver and retrieve srom revision from that */
+ if ((err = wlu_var_getbuf(wl, "nvram_dump", NULL, 0, &p)) < 0) {
+ err = wlu_get(wl, WLC_NVRAM_DUMP, &buf[0], WLC_IOCTL_MAXLEN);
+ }
+
+ if (err) {
+ printf("Fail to get sromrev from nvram file!\n");
+ return err;
+ }
+
+ if ((p = strstr(p, "sromrev"))) {
+ char *q = NULL;
+
+ p = (void*)((char*)p + 8);
+ /* for OTP, its either srom rev 10 or 16 */
+ sromrev = strtoul(p, &q, strncmp(p, "0x", 2) ? 10 : 16);
+ } else {
+ printf("sromrev not defined in nvram file!\n");
+ return BCME_ERROR;
+ }
+
+ /* convert caller supplied nvram string (in argv) into a list of tuples (in buf) */
+ if ((cnt = parsecis(buf, argv, sromrev)) <= 0) {
+ printf("CIS parse failure!\n");
+ return BCME_ERROR;
+ }
+
+ /* leave an empty srom_rw_t at the front for backward
+ * compatibility
+ */
+ if (!co) {
+ /*
+ * Pass the CIS containing caller supplied nvram vars to driver so driver
+ * can write OTP. Driver decides which OTP region (hardware,software) will
+ * be written, depending on chip type and bus type.
+ */
+ ret = wlu_iovar_set(wl, "cisvar", buf, cnt); /* IOV_BMAC_CISVAR */
+ }
+ return ret;
+ }
+
+ /* First read the srom and find out the sromrev */
+ srt = (srom_rw_t *)buf;
+ srt->byteoff = htod32(0);
+ srt->nbytes = htod32(2 * SROM4_WORDS);
+
+ if (cmd->get < 0)
+ return -1;
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+
+ if (words[SROM11_SIGN] == SROM11_SIGNATURE) {
+ sromrev = 11;
+
+ srt->byteoff = htod32(0);
+ srt->nbytes = htod32(2 * SROM11_WORDS);
+
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+
+ } else if (words[SROM11_SIGN] == SROM12_SIGNATURE) {
+ sromrev = 12;
+
+ srt->byteoff = htod32(0);
+ srt->nbytes = htod32(2 * SROM12_WORDS);
+
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+ } else if (words[SROM11_SIGN] == SROM13_SIGNATURE) {
+ sromrev = 13;
+
+ srt->byteoff = htod32(0);
+ srt->nbytes = htod32(2 * SROM13_WORDS);
+
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+ } else if (words[SROM11_SIGN] == SROM15_SIGNATURE) {
+ sromrev = 15;
+ srt->byteoff = htod32(0);
+ srt->nbytes = htod32(2 * SROM15_WORDS);
+
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+ } else {
+ if ((words[SROM4_SIGN] != SROM4_SIGNATURE) &&
+ (words[SROM8_SIGN] != SROM4_SIGNATURE))
+ nw = SROM_CRCREV;
+ else
+ nw = SROM4_CRCREV;
+ sromrev = words[nw] & 0xff;
+ }
+
+ if ((sromrev < 2) || (sromrev > SROM_MAXREV)) {
+ return BCME_ERROR;
+ }
+
+ nw = 0;
+ while ((name = *argv++) != NULL) {
+ int off, off_base;
+
+ newval = strchr(name, '=');
+ if (newval)
+ *newval++ = '\0';
+ nlen = strlen(name);
+ if ((nlen == 0) || (nlen > 32)) {
+ printf("Bad variable name: %s\n", name);
+ continue;
+ }
+ off = 0;
+ if (sromrev == 15)
+ srv = srvlookup(pci_srom15vars, name, nlen + 1, sromrev);
+ else
+ srv = srvlookup(pci_sromvars, name, nlen + 1, sromrev);
+
+ if (srv->name == NULL) {
+ int path;
+ if (sromrev == 15) {
+ printf("Variable %s does not exist in sromrev %d\n", name, sromrev);
+ return BCME_ERROR;
+ }
+ srv = srvlookup(perpath_pci_sromvars, name, nlen - 1, sromrev);
+ path = name[nlen - 1] - '0';
+ if ((srv->name == NULL) || (path < 0) || (path >= MAX_PATH_SROM)) {
+ printf("Variable %s does not exist in sromrev %d\n",
+ name, sromrev);
+ continue;
+ }
+ if (sromrev == 13) {
+ if (path == 0) {
+ off = SROM13_PATH0;
+ } else if (path == 1) {
+ off = SROM13_PATH1;
+ } else if (path == 2) {
+ off = SROM13_PATH2;
+ } else if (path == 3) {
+ off = SROM13_PATH3;
+ }
+ } else if (sromrev == 12) {
+ if (path == 0) {
+ off = SROM12_PATH0;
+ } else if (path == 1) {
+ off = SROM12_PATH1;
+ } else if (path == 2) {
+ off = SROM12_PATH2;
+ }
+ } else if (sromrev == 11) {
+ if (path == 0) {
+ off = SROM11_PATH0;
+ } else if (path == 1) {
+ off = SROM11_PATH1;
+ } else if (path == 2) {
+ off = SROM11_PATH2;
+ }
+ } else if (sromrev >= 8) {
+ if (path == 0) {
+ off = SROM8_PATH0;
+ } else if (path == 1) {
+ off = SROM8_PATH1;
+ } else if (path == 2) {
+ off = SROM8_PATH2;
+ } else if (path == 3) {
+ off = SROM8_PATH3;
+ }
+ } else
+ off = (path == 0) ? SROM4_PATH0 : SROM4_PATH1;
+ }
+ off_base = off;
+ off += srv->off;
+
+ if (ro) {
+ /* This code is cheating a bit: it knows that SRFL_ETHADDR means three
+ * whole words, and SRFL_MORE means 2 whole words (i.e. the masks for
+ * them are all 0xffff).
+ */
+ if (srv->flags & SRFL_ETHADDR) {
+ w = words[off];
+ ea.octet[0] = w >> 8;
+ ea.octet[1] = w & 0xff;
+ w = words[off + 1];
+ ea.octet[2] = w >> 8;
+ ea.octet[3] = w & 0xff;
+ w = words[off + 2];
+ ea.octet[4] = w >> 8;
+ ea.octet[5] = w & 0xff;
+ } else if (srv->flags & SRFL_MORE) {
+ val32 = words[off];
+ val32 |= words[srv[1].off] << 16;
+ } else {
+ shift = ffs(srv->mask) - 1;
+ val32 = (words[off] & srv->mask) >> shift;
+ }
+
+ /* OK, print it */
+ if (srv->flags & SRFL_ETHADDR)
+ printf("%s=%s", name, wl_ether_etoa(&ea));
+ else if (srv->flags & SRFL_PRHEX)
+ printf("%s=0x%x", name, val32);
+ else if (srv->flags & SRFL_PRSIGN)
+ printf("%s=%d", name, val32);
+ else
+ printf("%s=%u", name, val32);
+
+ if (srv->flags & SRFL_ARRAY) {
+ do {
+ srv ++;
+ off = off_base + srv->off;
+
+ if (srv->name == NULL)
+ break;
+
+ shift = ffs(srv->mask) - 1;
+ val32 = (words[off] & srv->mask) >> shift;
+
+ if (srv->flags & SRFL_PRHEX)
+ printf(",0x%x", val32);
+ else if (srv->flags & SRFL_PRSIGN)
+ printf(",%d", val32);
+ else
+ printf(",%u", val32);
+ } while (srv->flags & SRFL_ARRAY);
+ }
+ printf("\n");
+
+ } else { /* wr */
+
+ /* Make the change in the image we read */
+ if (!newval) {
+ printf("wrvar missing value to write for variable %s\n", name);
+ ro = 1;
+ break;
+ }
+
+ /* Cheating again as above */
+ if (srv->flags & SRFL_ETHADDR) {
+ if (!wl_ether_atoe(newval, &ea)) {
+ printf("Argument does not look like a MAC address: %s\n",
+ newval);
+ ret = BCME_USAGE_ERROR;
+ ro = 1;
+ break;
+ }
+ words[off] = (ea.octet[0] << 8) | ea.octet[1];
+ words[off + 1] = (ea.octet[2] << 8) | ea.octet[3];
+ words[off + 2] = (ea.octet[4] << 8) | ea.octet[5];
+ off += 2;
+ } else {
+ val32 = strtoul(newval, &p, 0);
+ if (p == newval) {
+ printf("Bad value: %s for variable %s\n", newval, name);
+ ro = 1;
+ break;
+ }
+
+ if (srv->flags & SRFL_MORE) {
+ words[off] = val32 & 0xffff;
+ words[off + 1] = val32 >> 16;
+ off++;
+ } else {
+ shift = ffs(srv->mask) - 1;
+ words[off] = (((val32 << shift) & srv->mask) |
+ (words[off] & ~srv->mask));
+
+ if (srv->flags & SRFL_ARRAY) {
+ do {
+ srv ++;
+ off = off_base + srv->off;
+
+ if (srv->name == NULL)
+ break;
+
+ newval = p + 1;
+ val32 = strtoul(newval, &p, 0);
+ if (p == newval) {
+ printf(
+ "Bad value: %s for variable %s\n",
+ newval, name);
+ ro = 1;
+ break;
+ }
+
+ shift = ffs(srv->mask) - 1;
+ words[off] =
+ (((val32 << shift) & srv->mask) |
+ (words[off] & ~srv->mask));
+ } while (srv->flags & SRFL_ARRAY);
+ }
+ }
+ }
+
+ if (off > nw)
+ nw = off;
+ }
+ }
+
+ if (!ro) {
+ /* Now write all the changes */
+ nw++;
+ srt->byteoff = 0;
+ srt->nbytes = htod32(2 * nw);
+ ret = wlu_set(wl, cmd->set, buf, (2 * nw) + 8);
+ if (ret < 0)
+ printf("Error %d writing the srom\n", ret);
+ }
+
+ return ret;
+#endif
+}
+
+/* All 32bits are used. Please populate wl_msgs2[] with further entries */
+static dbg_msg_t wl_msgs[] = {
+ {WL_ERROR_VAL, "error"},
+ {WL_ERROR_VAL, "err"},
+ {WL_TRACE_VAL, "trace"},
+ {WL_PRHDRS_VAL, "prhdrs"},
+ {WL_PRPKT_VAL, "prpkt"},
+ {WL_INFORM_VAL, "inform"},
+ {WL_INFORM_VAL, "info"},
+ {WL_INFORM_VAL, "inf"},
+ {WL_TMP_VAL, "tmp"},
+ {WL_OID_VAL, "oid"},
+ {WL_RATE_VAL, "rate"},
+ {WL_ASSOC_VAL, "assoc"},
+ {WL_ASSOC_VAL, "as"},
+ {WL_PRUSR_VAL, "prusr"},
+ {WL_PS_VAL, "ps"},
+ {WL_MODE_SWITCH_VAL, "modesw"},
+ {WL_PORT_VAL, "port"},
+ {WL_DUAL_VAL, "dual"},
+ {WL_WSEC_VAL, "wsec"},
+ {WL_WSEC_DUMP_VAL, "wsec_dump"},
+ {WL_LOG_VAL, "log"},
+ {WL_BCNTRIM_VAL, "bcntrim"},
+ {WL_PFN_VAL, "pfn"},
+ {WL_REGULATORY_VAL, "regulatory"},
+ {WL_MPC_VAL, "mpc"},
+ {WL_APSTA_VAL, "apsta"},
+ {WL_DFS_VAL, "dfs"},
+ {WL_MUMIMO_VAL, "mumimo"},
+ {WL_MUMIMO_VAL, "mu"},
+ {WL_MBSS_VAL, "mbss"},
+ {WL_CAC_VAL, "cac"},
+ {WL_AMSDU_VAL, "amsdu"},
+ {WL_AMPDU_VAL, "ampdu"},
+ {WL_FFPLD_VAL, "ffpld"},
+ {0, NULL}
+};
+
+/* msglevels which use wl_msg_level2 should go here */
+static dbg_msg_t wl_msgs2[] = {
+ {WL_SCAN_VAL, "scan"},
+ {WL_WOWL_VAL, "wowl"},
+ {WL_COEX_VAL, "coex"},
+ {WL_RTDC_VAL, "rtdc"},
+ {WL_PROTO_VAL, "proto"},
+ {WL_CHANINT_VAL, "chanim"},
+ {WL_WMF_VAL, "wmf"},
+#ifdef WLP2P
+ {WL_P2P_VAL, "p2p"},
+#endif
+ {WL_ITFR_VAL, "itfr"},
+#ifdef WLMCHAN
+ {WL_MCHAN_VAL, "mchan"},
+#endif
+#ifdef WLTDLS
+ {WL_TDLS_VAL, "tdls"},
+#endif
+ {WL_PSTA_VAL, "psta"},
+ {WL_MCNX_VAL, "mcnx"},
+ {WL_PROT_VAL, "prot"},
+ {WL_TBTT_VAL, "tbtt"},
+ {WL_TIMESTAMP_VAL, "time"},
+ {WL_PWRSEL_VAL, "lpc"},
+ {WL_TSO_VAL, "tso"},
+ {WL_MQ_VAL, "mq"},
+ {WL_TIMESTAMP_VAL, "chanlog"},
+#ifdef WLP2PO
+ {WL_P2PO_VAL, "p2po"},
+#endif
+ {WL_WNM_VAL, "wnm"},
+ {WL_TXBF_VAL, "txbf"},
+ {WL_PCIE_VAL, "pcie"},
+ {WL_MESH_VAL, "mesh"},
+ {WL_NATOE_VAL, "natoe"},
+ {0, NULL}
+};
+
+static int
+wl_msglevel(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, i;
+ uint hval = 0, len, val = 0, found, last_val = 0, msglevel = 0, msglevel2_add = 0;
+ uint msglevel2_del = 0, msglevel_add = 0, msglevel_del = 0, supported = 1;
+ char *endptr = NULL;
+ dbg_msg_t *dbg_msg = wl_msgs, *dbg_msg2 = wl_msgs2;
+ void *ptr = NULL;
+ struct wl_msglevel2 msglevel64, *reply;
+ const char *cmdname = "msglevel";
+ char c[32] = "0x";
+
+ UNUSED_PARAMETER(cmd);
+
+ /* but preseve older IOCTL call for older drivers */
+ if ((ret = wlu_var_getbuf_sm(wl, cmdname, &msglevel64, sizeof(msglevel64), &ptr) < 0)) {
+ if ((ret = wlu_get(wl, WLC_GET_MSGLEVEL, &msglevel, sizeof(int))) < 0)
+ return (ret);
+ supported = 0;
+ msglevel = dtoh32(msglevel);
+ if (!*++argv) {
+ printf("0x%x ", msglevel);
+ for (i = 0; (val = dbg_msg[i].value); i++) {
+ if ((msglevel & val) && (val != last_val))
+ printf(" %s", dbg_msg[i].string);
+ last_val = val;
+ }
+ printf("\n");
+ return (0);
+ }
+ while (*argv) {
+ char *s = *argv;
+ if (*s == '+' || *s == '-')
+ s++;
+ else
+ msglevel_del = ~0; /* make the whole list absolute */
+ val = strtoul(s, &endptr, 0);
+ if (val == 0xFFFFFFFF) {
+ fprintf(stderr,
+ "Bits >32 are not supported on this driver version\n");
+ val = 1;
+ }
+ /* not an integer if not all the string was parsed by strtoul */
+ if (*endptr != '\0') {
+ for (i = 0; (val = dbg_msg[i].value); i++)
+ if (stricmp(dbg_msg[i].string, s) == 0)
+ break;
+ if (!val)
+ goto usage;
+ }
+ if (**argv == '-')
+ msglevel_del |= val;
+ else
+ msglevel_add |= val;
+ ++argv;
+ }
+ msglevel &= ~msglevel_del;
+ msglevel |= msglevel_add;
+ msglevel = htod32(msglevel);
+ return (wlu_set(wl, WLC_SET_MSGLEVEL, &msglevel, sizeof(int)));
+ } else { /* 64bit message level */
+ reply = (struct wl_msglevel2 *)ptr;
+ reply->low = dtoh32(reply->low);
+ reply->high = dtoh32(reply->high);
+ if (!*++argv) {
+ if (reply->high != 0)
+ printf("0x%x%08x", reply->high, reply->low);
+ else
+ printf("0x%x ", reply->low);
+ for (i = 0; (val = dbg_msg2[i].value); i++) {
+ if (((reply->high & val)) && (val != last_val))
+ printf(" %s", dbg_msg2[i].string);
+ last_val = val;
+ }
+ last_val = 0;
+ for (i = 0; (val = dbg_msg[i].value); i++) {
+ if (((reply->low & val)) && (val != last_val))
+ printf(" %s", dbg_msg[i].string);
+ last_val = val;
+ }
+ printf("\n");
+ return (0);
+ }
+ while (*argv) {
+ char* s = *argv;
+ char t[32];
+ found = 0;
+ if (*s == '+' || *s == '-')
+ s++;
+ else {
+ msglevel_del = ~0; /* make the whole list absolute */
+ msglevel2_del = ~0;
+ }
+ val = strtoul(s, &endptr, 0);
+ if (val == 0xFFFFFFFF){ /* Assume >32 bit hex passed in */
+ if (!(*s == '0' && *(s+1) == 'x')) {
+ fprintf(stderr,
+ "Msg bits >32 take only numerical input in hex\n");
+ val = 0;
+ } else {
+ len = strlen(s);
+ hval = strtoul(strncpy(t, s, len-8), &endptr, 0);
+ *endptr = 0;
+ s = s+strlen(t);
+ s = strcat(c, s);
+ val = strtoul(s, &endptr, 0);
+ if (hval == 0xFFFFFFFF) {
+ fprintf(stderr, "Invalid entry for msglevel\n");
+ hval = 0;
+ val = 0;
+ }
+ }
+ }
+ if (*endptr != '\0') {
+ for (i = 0; (val = dbg_msg[i].value); i++) {
+ if (stricmp(dbg_msg[i].string, s) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ for (i = 0; (hval = dbg_msg2[i].value); i++)
+ if (stricmp(dbg_msg2[i].string, s) == 0)
+ break;
+ }
+ if (!val && !hval)
+ goto usage;
+ }
+ if (**argv == '-') {
+ msglevel_del |= val;
+ if (!found)
+ msglevel2_del |= hval;
+ }
+ else {
+ msglevel_add |= val;
+ if (!found)
+ msglevel2_add |= hval;
+ }
+ ++argv;
+ }
+ reply->low &= ~msglevel_del;
+ reply->high &= ~msglevel2_del;
+ reply->low |= msglevel_add;
+ reply->high |= msglevel2_add;
+ reply->low = htod32(reply->low);
+ reply->high = htod32(reply->high);
+ msglevel64.low = reply->low;
+ msglevel64.high = reply->high;
+ return (wlu_var_setbuf(wl, cmdname, &msglevel64, sizeof(msglevel64)));
+ }
+
+usage:
+ fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");
+ fprintf(stderr, "Use a + or - prefix to make an incremental change.");
+
+ for (i = 0; (val = dbg_msg[i].value); i++) {
+ if (val != last_val)
+ fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string);
+ else
+ fprintf(stderr, ", %s", dbg_msg[i].string);
+ last_val = val;
+ }
+ if (supported) {
+ for (i = 0; (val = dbg_msg2[i].value); i++) {
+ if (val != last_val)
+ fprintf(stderr, "\n0x%x00000000 %s", val, dbg_msg2[i].string);
+ else
+ fprintf(stderr, ", %s", dbg_msg2[i].string);
+ last_val = val;
+ }
+ }
+ fprintf(stderr, "\n");
+ return 0;
+}
+
+struct d11_mcs_rate_info {
+ uint8 constellation_bits;
+ uint8 coding_q;
+ uint8 coding_d;
+};
+
+static const struct d11_mcs_rate_info wlu_mcs_info[] = {
+ { 1, 1, 2 }, /* MCS 0: MOD: BPSK, CR 1/2 */
+ { 2, 1, 2 }, /* MCS 1: MOD: QPSK, CR 1/2 */
+ { 2, 3, 4 }, /* MCS 2: MOD: QPSK, CR 3/4 */
+ { 4, 1, 2 }, /* MCS 3: MOD: 16QAM, CR 1/2 */
+ { 4, 3, 4 }, /* MCS 4: MOD: 16QAM, CR 3/4 */
+ { 6, 2, 3 }, /* MCS 5: MOD: 64QAM, CR 2/3 */
+ { 6, 3, 4 }, /* MCS 6: MOD: 64QAM, CR 3/4 */
+ { 6, 5, 6 }, /* MCS 7: MOD: 64QAM, CR 5/6 */
+ { 8, 3, 4 }, /* MCS 8: MOD: 256QAM, CR 3/4 */
+ { 8, 5, 6 } /* MCS 9: MOD: 256QAM, CR 5/6 */
+};
+
+static uint
+wl_mcs2rate(uint mcs, uint nss, uint bw, int sgi)
+{
+ const int ksps = 250; /* kilo symbols per sec, 4 us sym */
+ const int Nsd_20MHz = 52;
+ const int Nsd_40MHz = 108;
+ const int Nsd_80MHz = 234;
+ const int Nsd_160MHz = 468;
+ uint rate;
+
+ if (mcs == 32) {
+ /* just return fixed values for mcs32 instead of trying to parametrize */
+ rate = (sgi == 0) ? 6000 : 6700;
+ } else if (mcs <= 9) {
+ /* This calculation works for 11n HT and 11ac VHT if the HT mcs values
+ * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8.
+ * That is, HT MCS 23 is a base MCS = 7, Nss = 3
+ */
+
+ /* find the number of complex numbers per symbol */
+ if (bw == 20) {
+ rate = Nsd_20MHz;
+ } else if (bw == 40) {
+ rate = Nsd_40MHz;
+ } else if (bw == 80) {
+ rate = Nsd_80MHz;
+ } else if (bw == 160) {
+ rate = Nsd_160MHz;
+ } else {
+ rate = 1;
+ }
+
+ /* multiply by bits per number from the constellation in use */
+ rate = rate * wlu_mcs_info[mcs].constellation_bits;
+
+ /* adjust for the number of spatial streams */
+ rate = rate * nss;
+
+ /* adjust for the coding rate given as a quotient and divisor */
+ rate = (rate * wlu_mcs_info[mcs].coding_q) / wlu_mcs_info[mcs].coding_d;
+
+ /* multiply by Kilo symbols per sec to get Kbps */
+ rate = rate * ksps;
+
+ /* adjust the symbols per sec for SGI
+ * symbol duration is 4 us without SGI, and 3.6 us with SGI,
+ * so ratio is 10 / 9
+ */
+ if (sgi) {
+ /* add 4 for rounding of division by 9 */
+ rate = ((rate * 10) + 4) / 9;
+ }
+ } else {
+ rate = 0;
+ }
+
+ return rate;
+}
+
+/* take a wl_ratespec arg and return phy rate in 500Kbps units */
+static int
+wl_ratespec2rate(uint32 rspec)
+{
+ const char* fn_name = "wl_ratespec2rate";
+ int rate = -1;
+ int sgi = ((rspec & WL_RSPEC_SGI) != 0);
+
+ if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) {
+ rate = (rspec & WL_RSPEC_RATE_MASK);
+ } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) {
+ uint mcs = (rspec & WL_RSPEC_RATE_MASK);
+
+ if (mcs > 32) {
+ fprintf(stderr, "%s: MCS %u out of range (>32) in ratespec 0x%X\n",
+ fn_name, mcs, rspec);
+ } else if (mcs == 32) {
+ rate = wl_mcs2rate(mcs, 1, 40, sgi) / 500;
+ } else {
+ uint nss = 1 + (mcs / 8);
+ mcs = mcs % 8;
+
+ rate = wl_mcs2rate(mcs, nss, 20, sgi) / 500;
+ }
+ } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) {
+ uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK);
+ uint nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
+
+ rate = wl_mcs2rate(mcs, nss, 20, sgi) / 500;
+ } else {
+ fprintf(stderr, "%s: expected rate encoding in ratespec 0x%X\n",
+ fn_name, (uint)rspec);
+ }
+
+ return rate;
+}
+
+/* take rate arg in units of 500Kbits/s and print it in units of Mbit/s */
+static void
+wl_printrate(int val)
+{
+ char rate_buf[32];
+
+ printf("%s\n", rate_int2string(rate_buf, val));
+}
+
+/* convert rate string in Mbit/s format, like "11", "5.5", to internal 500 Kbit/s units */
+int
+rate_string2int(char *s)
+{
+ if (!stricmp(s, "-1"))
+ return (0);
+ if (!stricmp(s, "5.5"))
+ return (11);
+ return (atoi(s) * 2);
+}
+
+/* convert rate internal 500 Kbits/s units to string in Mbits/s format, like "11", "5.5" */
+char*
+rate_int2string(char *rate_buf, int val)
+{
+ if ((val == -1) || (val == 0))
+ sprintf(rate_buf, "auto");
+ else
+ sprintf(rate_buf, "%d%s Mbps", (val / 2), (val & 1) ? ".5" : "");
+ return (rate_buf);
+}
+
+/*
+ * Format a ratespec for output of any of the wl_rate() iovars
+ */
+char*
+wl_rate_print(char *rate_buf, uint32 rspec)
+{
+ uint encode, rate, txexp, bw_val;
+ const char* stbc;
+ const char* ldpc;
+ const char* sgi;
+ const char* bw;
+
+ encode = (rspec & WL_RSPEC_ENCODING_MASK);
+ rate = (rspec & WL_RSPEC_RATE_MASK);
+ txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
+ bw_val = (rspec & WL_RSPEC_BW_MASK);
+ stbc = ((rspec & WL_RSPEC_STBC) != 0) ? " stbc" : "";
+ ldpc = ((rspec & WL_RSPEC_LDPC) != 0) ? " ldpc" : "";
+ sgi = ((rspec & WL_RSPEC_SGI) != 0) ? " sgi" : "";
+
+ if (bw_val == WL_RSPEC_BW_UNSPECIFIED) {
+ bw = "auto";
+ } else if (bw_val == WL_RSPEC_BW_20MHZ) {
+ bw = "20";
+ } else if (bw_val == WL_RSPEC_BW_40MHZ) {
+ bw = "40";
+ } else if (bw_val == WL_RSPEC_BW_80MHZ) {
+ bw = "80";
+ } else if (bw_val == WL_RSPEC_BW_160MHZ) {
+ bw = "160";
+ } else if (bw_val == WL_RSPEC_BW_10MHZ) {
+ bw = "10";
+ } else if (bw_val == WL_RSPEC_BW_5MHZ) {
+ bw = "5";
+ } else if (bw_val == WL_RSPEC_BW_2P5MHZ) {
+ bw = "2.5";
+ } else {
+ bw = "???";
+ }
+
+ if ((rspec & ~WL_RSPEC_TXEXP_MASK) == 0) { /* Ignore TxExpansion for NULL rspec check */
+ sprintf(rate_buf, "auto");
+ } else if (encode == WL_RSPEC_ENCODE_RATE) {
+ sprintf(rate_buf, "rate %d%s Mbps Tx Exp %d",
+ rate/2, (rate % 2)?".5":"", txexp);
+ } else if (encode == WL_RSPEC_ENCODE_HT) {
+ sprintf(rate_buf, "ht mcs %d Tx Exp %d BW %s%s%s%s",
+ rate, txexp, bw, stbc, ldpc, sgi);
+ } else if (encode == WL_RSPEC_ENCODE_VHT) {
+ uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK);
+ uint Nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
+ sprintf(rate_buf, "vht mcs %d Nss %d Tx Exp %d BW %s%s%s%s",
+ mcs, Nss, txexp, bw, stbc, ldpc, sgi);
+ } else {
+ sprintf(rate_buf, "<unknown encoding for ratespec 0x%08X>", rspec);
+ }
+
+ return rate_buf;
+}
+
+/* handles both "rate" and "mrate", which makes the flow a bit complex */
+static int
+wl_rate_mrate(void *wl, cmd_t *cmd, char **argv)
+{
+ const char* fn_name = "wl_rate_mrate";
+ int error;
+ int val;
+ int band;
+ int list[3];
+ char aname[sizeof("5g_mrate") + 1];
+ char bgname[sizeof("2g_mrate") + 1];
+ char *name;
+
+ sprintf(aname, "5g_%s", cmd->name);
+ sprintf(bgname, "2g_%s", cmd->name);
+
+ if ((error = wlu_get(wl, WLC_GET_BAND, &band, sizeof(uint))) < 0)
+ return error;
+ band = dtoh32(band);
+
+ if ((error = wlu_get(wl, WLC_GET_BANDLIST, list, sizeof(list))) < 0)
+ return error;
+ list[0] = dtoh32(list[0]);
+ list[1] = dtoh32(list[1]);
+ list[2] = dtoh32(list[2]);
+
+ if (!list[0])
+ return BCME_ERROR;
+ else if (list[0] > 2)
+ list[0] = 2;
+
+ /* toss the command name from the args */
+ argv++;
+
+ if ((!strcmp(cmd->name, "rate"))) {
+ /* it is "rate" */
+ if (!*argv) {
+ /* it is "rate" get. handle it here */
+ /* WLC_GET_RATE processing */
+ if ((error = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0)
+ return error;
+
+ val = dtoh32(val);
+ wl_printrate(val);
+ return 0;
+ }
+ }
+
+ switch (band) {
+ case WLC_BAND_AUTO :
+ if (list[0] > 1) {
+ fprintf(stderr,
+ "%s: driver band must be locked to %s %s, use %s/%s instead\n",
+ fn_name, (*argv ? "set" : "get"), cmd->name,
+ bgname, aname);
+ return BCME_BADARG;
+ } else if (list[1] == WLC_BAND_5G)
+ name = (char *)aname;
+ else if (list[1] == WLC_BAND_2G)
+ name = (char *)bgname;
+ else
+ return BCME_ERROR;
+
+ break;
+
+ case WLC_BAND_5G :
+ name = (char *)aname;
+ break;
+
+ case WLC_BAND_2G :
+ name = (char *)bgname;
+ break;
+
+ default :
+ return BCME_ERROR;
+ }
+
+ if (!*argv) {
+ /* it is "mrate" get */
+ if ((error = wlu_iovar_getint(wl, name, &val) < 0))
+ return error;
+
+ val = dtoh32(val);
+
+ if (ioctl_version == 1) {
+ wl_printrate(val);
+ } else {
+ wl_printrate(wl_ratespec2rate((uint32)val));
+ }
+ } else {
+ /* create the ioctl value based on the major ioctl version */
+ if (ioctl_version == 1) {
+ /* for ver=1 ioctl interfaces, override values for 2g_(m)rate/5g_(m)rate
+ * are just given as 500 Kbps units
+ */
+ val = rate_string2int(*argv);
+ } else {
+ /* for ver>1 ioctl interfaces, override values for 2g_(m)rate/5g_(m)rate
+ * are a wl_ratespec of a legacy rate.
+ */
+ val = WL_RSPEC_ENCODE_RATE | rate_string2int(*argv);
+ }
+
+ val = htod32(val);
+
+ error = wlu_iovar_setint(wl, name, val);
+ }
+
+ return error;
+}
+
+/* parse the -v/--vht or -c argument for the wl_rate() command.
+ * return FALSE if the arg does not look like MxS or cMsS, where M and S are single digits
+ * return TRUE if the arg does look like MxS or cMsS, setting mcsp to M, and nssp to S
+ */
+static int
+wl_parse_vht_spec(const char* cp, int* mcsp, int* nssp)
+{
+ char *startp, *endp;
+ char c;
+ int mcs, nss;
+ char sx;
+
+ if (cp == NULL || cp[0] == '\0') {
+ return FALSE;
+ }
+
+ if (cp[0] == 'c') {
+ startp = (char*)cp + 1;
+ sx = 's';
+ }
+ else {
+ startp = (char*)cp;
+ sx = 'x';
+ }
+
+ mcs = (int)strtol(startp, &endp, 10);
+ /* verify MCS 0-11, and next char is 's' or 'x' */
+ /* std MCS 0-9 and prop MCS 10-11 */
+ if (mcs < 0 || mcs > 11 || endp[0] != sx) {
+ return FALSE;
+ }
+
+ /* grab the char after the 'x'/'s' and convert to value */
+ c = endp[1];
+ nss = 0;
+ if (isdigit((int)c)) {
+ nss = c - '0';
+ }
+
+ /* consume trailing space after digit */
+ cp = &endp[2];
+ while (isspace((int)(*cp))) {
+ cp++;
+ }
+
+ /* check for trailing garbage after digit */
+ if (cp[0] != '\0') {
+ return FALSE;
+ }
+
+ if (nss < 1 || nss > 8) {
+ return FALSE;
+ }
+
+ *mcsp = mcs;
+ *nssp = nss;
+
+ return TRUE;
+}
+
+static int
+wl_rate(void *wl, cmd_t *cmd, char **argv)
+{
+ miniopt_t mo;
+ char *option_name = NULL;
+ char* endp;
+ const int option_name_len = 64;
+ const char* iov_name;
+ const char* fn_name = "wl_rate";
+ bool options = FALSE;
+ bool auto_set = FALSE;
+ bool legacy_set = FALSE, ht_set = FALSE, vht_set = FALSE;
+ int rate, mcs, Nss, tx_exp, bw;
+ bool stbc, ldpc, sgi;
+ int err, opt_err;
+ uint32 rspec = 0;
+
+ /* set default values */
+ rate = 0;
+ mcs = 0;
+ Nss = 0;
+ tx_exp = 0;
+ stbc = FALSE;
+ ldpc = FALSE;
+ sgi = FALSE;
+ bw = 0;
+
+ /* save the command name */
+ iov_name = *argv++;
+
+ if (ioctl_version == 1) {
+ fprintf(stderr,
+ "cmd %s not supported in this version of the driver, ioctl version 1.\n",
+ iov_name);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* process a GET */
+ if (!*argv) {
+ uint32 val = 0;
+ char * rate_str;
+ const int rate_str_len = 64;
+
+ if (cmd->get < 0)
+ return -1;
+ if ((err = wlu_iovar_getint(wl, iov_name, (int*)&val)) < 0)
+ return err;
+
+ rate_str = malloc(rate_str_len);
+ if (rate_str == NULL) {
+ fprintf(stderr, "%s: malloc failure for rate string buffer.\n", fn_name);
+ return BCME_NOMEM;
+ }
+ memset(rate_str, 0, rate_str_len);
+
+ wl_rate_print(rate_str, val);
+
+ printf("%s\n", rate_str);
+
+ free(rate_str);
+
+ return 0;
+ }
+
+ /* process a SET */
+
+ /* initialze to common error for the miniopt processing */
+ err = BCME_USAGE_ERROR;
+
+ /* alloc option name for error messages */
+ option_name = malloc(option_name_len);
+ if (option_name == NULL) {
+ fprintf(stderr, "%s: malloc failure for option_name buffer.\n", fn_name);
+ return BCME_NOMEM;
+ }
+ memset(option_name, 0, option_name_len);
+
+ miniopt_init(&mo, fn_name, "lg", TRUE);
+ while ((opt_err = miniopt(&mo, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += mo.consumed;
+
+ /* track whether or not the command line is just a single positional
+ * parameter of "auto" or a legacy rate, or is using options
+ */
+ if (!mo.positional) {
+ options = TRUE; /* command line is using options */
+ }
+ if (mo.positional) {
+ /* command line is using a positional parameter,
+ * complain if options are also being used
+ */
+ if (options) {
+ fprintf(stderr,
+ "%s: cannot mix positional args and options. "
+ "Got positional arg \"%s\" after options.\n",
+ fn_name, mo.valstr);
+ goto exit;
+ }
+ /* complain if there are any more parameters since there should only
+ * be one positional param, "auto" or a legacy rate.
+ */
+ if (*argv != NULL) {
+ fprintf(stderr,
+ "%s: unexpected parameter \"%s\" after rate value.\n",
+ fn_name, *argv);
+ goto exit;
+ }
+ /* test for "auto" to clear the rate override */
+ if (!strcmp(mo.valstr, "auto")) {
+ auto_set = TRUE;
+ } else {
+ /* pretend there was a '-r' option */
+ mo.opt = 'r';
+ }
+ }
+
+ /* format the option name for error messages */
+ if (mo.key[0] != '\0') {
+ /* would like to do the following, but snprintf() is not availble in
+ * all target builds. Fails in win_mfgtest_wl build.
+ *
+ * snprintf(option_name, option_name_len, "--%s", mo.key);
+ * option_name[option_name_len - 1] = '\0';
+ */
+ size_t key_len;
+
+ key_len = strlen(mo.key);
+ /* limit key_len to space in str buffer minus the '--' and null */
+ key_len = MIN((uint)(option_name_len - 3), key_len);
+
+ memcpy(option_name, "--", 2);
+ memcpy(option_name + 2, mo.key, key_len);
+ option_name[2 + key_len] = '\0';
+ } else {
+ sprintf(option_name, "-%c", mo.opt);
+ }
+
+ /* Option: -r or --rate */
+ if (mo.opt == 'r' ||
+ !strcmp(mo.key, "rate")) {
+ if (mo.valstr == NULL) {
+ fprintf(stderr,
+ "%s: expected a value for %s option\n",
+ fn_name, option_name);
+ goto exit;
+ }
+
+ /* special case check for "-r 5.5" */
+ if (!strcmp(mo.valstr, "5.5")) {
+ rate = 11;
+ } else if (!mo.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a value for %s option\n",
+ fn_name, mo.valstr, option_name);
+ goto exit;
+ } else {
+ rate = mo.val*2;
+ }
+
+ legacy_set = TRUE;
+ }
+ /* Option: -h or --ht */
+ if (mo.opt == 'h' ||
+ !strcmp(mo.key, "ht")) {
+ if (mo.valstr == NULL) {
+ fprintf(stderr,
+ "%s: expected a value for %s option\n",
+ fn_name, option_name);
+ goto exit;
+ }
+
+ if (!mo.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a value for %s option\n",
+ fn_name, mo.valstr, option_name);
+ goto exit;
+ }
+
+ mcs = mo.val;
+ ht_set = TRUE;
+ }
+ /* Option: -v or --vht */
+ if (mo.opt == 'v' ||
+ !strcmp(mo.key, "vht")) {
+ if (mo.valstr == NULL || mo.valstr[0] == 'c') {
+ fprintf(stderr,
+ "%s: expected a value for %s option\n",
+ fn_name, option_name);
+ goto exit;
+ }
+
+ mcs = (int)strtol(mo.valstr, &endp, 10);
+ if (*endp == '\0') {
+ mcs = mo.val;
+ vht_set = TRUE;
+ } else if (wl_parse_vht_spec(mo.valstr, &mcs, &Nss)) {
+ vht_set = TRUE;
+ } else {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a value for %s option\n",
+ fn_name, mo.valstr, option_name);
+ goto exit;
+ }
+ }
+ /* Option: -c (system team's c notiation: c<MCS>s<Nss>) */
+ if (mo.opt == 'c') {
+ if (mo.valstr == NULL || mo.valstr[0] != 'c') {
+ fprintf(stderr,
+ "%s: expected a value start with c for %s option\n",
+ fn_name, option_name);
+ goto exit;
+ }
+
+ mcs = (int)strtol(mo.valstr + 1, &endp, 10);
+ if (*endp == '\0') {
+ vht_set = TRUE;
+ } else if (wl_parse_vht_spec(mo.valstr, &mcs, &Nss)) {
+ vht_set = TRUE;
+ } else {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a value for %s option\n",
+ fn_name, mo.valstr, option_name);
+ goto exit;
+ }
+ }
+ /* Option: -s or --ss */
+ if (mo.opt == 's' ||
+ !strcmp(mo.key, "ss")) {
+ if (mo.valstr == NULL) {
+ fprintf(stderr,
+ "%s: expected a value for %s option\n",
+ fn_name, option_name);
+ goto exit;
+ }
+
+ if (!mo.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a value for %s option\n",
+ fn_name, mo.valstr, option_name);
+ goto exit;
+ }
+ Nss = mo.val;
+ }
+ /* Option: -x or --exp */
+ if (mo.opt == 'x' ||
+ !strcmp(mo.key, "exp")) {
+ if (mo.valstr == NULL) {
+ fprintf(stderr,
+ "%s: expected a value for %s option\n",
+ fn_name, option_name);
+ goto exit;
+ }
+
+ if (!mo.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a value for %s option\n",
+ fn_name, mo.valstr, option_name);
+ goto exit;
+ }
+ tx_exp = mo.val;
+ if (tx_exp < 0 || tx_exp > 3) {
+ fprintf(stderr,
+ "%s: tx expansion %d out of range [0-3]\n",
+ fn_name, tx_exp);
+ err = BCME_RANGE;
+ goto exit;
+ }
+ }
+ /* Option: --stbc */
+ if (!strcmp(mo.key, "stbc")) {
+ if (mo.valstr != NULL) {
+ fprintf(stderr,
+ "%s: unexpected a value for %s option\n",
+ fn_name, option_name);
+ goto exit;
+ }
+ stbc = TRUE;
+ }
+ /* Option: -l or --ldpc */
+ if (mo.opt == 'l' ||
+ !strcmp(mo.key, "ldpc")) {
+ if (mo.valstr != NULL) {
+ fprintf(stderr,
+ "%s: unexpected a value for %s option\n",
+ fn_name, option_name);
+ goto exit;
+ }
+ ldpc = TRUE;
+ }
+ /* Option: -g or --sgi */
+ if (mo.opt == 'g' ||
+ !strcmp(mo.key, "sgi")) {
+ if (mo.valstr != NULL) {
+ fprintf(stderr,
+ "%s: unexpected a value for %s option\n",
+ fn_name, option_name);
+ goto exit;
+ }
+ sgi = TRUE;
+ }
+ /* Option: -b or --bandwidth */
+ if (mo.opt == 'b' ||
+ !strcmp(mo.key, "bandwidth")) {
+ if (mo.valstr == NULL) {
+ fprintf(stderr,
+ "%s: expected a value for %s option\n",
+ fn_name, option_name);
+ goto exit;
+ }
+
+ if (!mo.good_int && strcmp(mo.valstr, "2.5")) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a value for %s option\n",
+ fn_name, mo.valstr, option_name);
+ goto exit;
+ }
+
+ if (mo.val == 2) {
+ if (strcmp(mo.valstr, "2.5")) {
+ fprintf(stderr,
+ "%s: unexpected bandwidth specified \"%s\", "
+ "expected 2.5, 5, 10, 20, 40, 80, or 160\n",
+ fn_name, mo.valstr);
+ goto exit;
+ }
+ bw = WL_RSPEC_BW_2P5MHZ;
+ } else if (mo.val == 5) {
+ bw = WL_RSPEC_BW_5MHZ;
+ } else if (mo.val == 10) {
+ bw = WL_RSPEC_BW_10MHZ;
+ } else if (mo.val == 20) {
+ bw = WL_RSPEC_BW_20MHZ;
+ } else if (mo.val == 40) {
+ bw = WL_RSPEC_BW_40MHZ;
+ } else if (mo.val == 80) {
+ bw = WL_RSPEC_BW_80MHZ;
+ } else if (mo.val == 160) {
+ bw = WL_RSPEC_BW_160MHZ;
+ } else {
+ fprintf(stderr,
+ "%s: unexpected bandwidth specified \"%s\", "
+ "expected 2.5, 5, 10, 20, 40, 80, or 160\n",
+ fn_name, mo.valstr);
+ goto exit;
+ }
+ }
+ }
+
+ /*
+ * check for necessary use of one of -r/-h/-v or auto
+ */
+
+ if (!auto_set && !legacy_set && !ht_set && !vht_set) {
+ fprintf(stderr, "%s: must specify one of \"auto\", legacy rate -r/--rate, "
+ "HT (11n) rate -h/--ht, or VHT (11ac) rate -v/--vht\n",
+ fn_name);
+ goto exit;
+ }
+
+ /*
+ * check for incompatible use of -r/-h/-v
+ */
+
+ if (legacy_set && ht_set) {
+ fprintf(stderr, "%s: cannot use legacy rate -r/--rate and "
+ "HT rate -h/--ht at the same time\n",
+ fn_name);
+ goto exit;
+ }
+
+ if (legacy_set && vht_set) {
+ fprintf(stderr, "%s: cannot use legacy rate -r/--rate and "
+ "HT rate -v/--vht at the same time\n",
+ fn_name);
+ goto exit;
+ }
+
+ if (ht_set && vht_set) {
+ fprintf(stderr, "%s: cannot use HT rate -h/--ht and "
+ "HT rate -v/--vht at the same time\n",
+ fn_name);
+ goto exit;
+ }
+
+ /* Nss can only be used with VHT */
+ if (!vht_set && Nss != 0) {
+ fprintf(stderr, "%s: cannot use -s/--ss option with non VHT rate\n",
+ fn_name);
+ goto exit;
+ }
+
+ /* STBC, LDPC, SGI can only be used with HT/VHT rates */
+ if ((stbc || ldpc || sgi) && !(ht_set || vht_set)) {
+ fprintf(stderr, "%s: cannot use STBC/LDPC/SGI options with non HT/VHT rates\n",
+ fn_name);
+ goto exit;
+ }
+
+ /* set the ratespec encoding type and basic rate value */
+ if (auto_set) {
+ rspec = 0;
+ } else if (legacy_set) {
+ rspec = WL_RSPEC_ENCODE_RATE; /* 11abg */
+ rspec |= rate;
+ } else if (ht_set) {
+ rspec = WL_RSPEC_ENCODE_HT; /* 11n HT */
+ rspec |= mcs;
+ } else {
+ rspec = WL_RSPEC_ENCODE_VHT; /* 11ac VHT */
+ if (Nss == 0) {
+ Nss = 1; /* default Nss = 1 if --ss option not given */
+ }
+ rspec |= (Nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs;
+ }
+
+ /* set the other rspec fields */
+ rspec |= (tx_exp << WL_RSPEC_TXEXP_SHIFT);
+ rspec |= bw;
+ rspec |= (stbc ? WL_RSPEC_STBC : 0);
+ rspec |= (ldpc ? WL_RSPEC_LDPC : 0);
+ rspec |= (sgi ? WL_RSPEC_SGI : 0);
+
+ err = wlu_iovar_setint(wl, iov_name, (int)rspec);
+
+exit:
+ if (option_name != NULL) {
+ free(option_name);
+ }
+
+ return err;
+} /* wl_rate */
+
+static int
+wl_bss_max(void *wl, cmd_t *cmd, char **argv)
+{
+ int val = 1;
+ int error;
+
+ UNUSED_PARAMETER(argv);
+
+ /* Get the CAP variable; search for mbss4 or mbss16 */
+ strcpy(buf, "cap");
+ if ((error = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MEDLEN)) < 0)
+ return (error);
+
+ buf[WLC_IOCTL_MEDLEN] = '\0';
+ if (strstr(buf, "mbss16"))
+ val = 16;
+ else if (strstr(buf, "mbss4"))
+ val = 4;
+
+ printf("%d\n", val);
+ return (0);
+}
+
+int
+wl_phy_rate(void *wl, cmd_t *cmd, char **argv)
+{
+ int val, error;
+ const char *name = cmd->name;
+ static const struct {
+ const char* orig;
+ const char* new;
+ } aliases[] = {
+ {"bg_rate", "2g_rate"},
+ {"bg_mrate", "2g_mrate"},
+ {"a_rate", "5g_rate"},
+ {"a_mrate", "5g_mrate"},
+ };
+
+ /* toss the command name from the args */
+ argv++;
+
+ /* if we are not using the legacy ioctl driver, translate the
+ * bg_* prefix to 2g_* and a_* to 5g_* iovars
+ */
+ if (ioctl_version > 1) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ if (!strcmp(name, aliases[i].orig)) {
+ name = aliases[i].new;
+ break;
+ }
+ }
+ }
+
+ if (!*argv) {
+ error = wlu_iovar_getint(wl, name, &val);
+ if (error < 0)
+ return (error);
+
+ val = dtoh32(val);
+ if (ioctl_version > 1) {
+ wl_printrate(wl_ratespec2rate((uint32)val));
+ } else {
+ wl_printrate(val);
+ }
+ } else {
+ /* create the ioctl value based on the major ioctl version */
+ if (ioctl_version == 1) {
+ /* for ver=1 ioctl interfaces, override values for 2g_(m)rate/5g_(m)rate
+ * are just given as 500 Kbps units
+ */
+ val = rate_string2int(*argv);
+ } else {
+ /* for ver>1 ioctl interfaces, override values for 2g_(m)rate/5g_(m)rate
+ * are a wl_ratespec of a legacy rate.
+ */
+ val = WL_RSPEC_ENCODE_RATE | rate_string2int(*argv);
+ }
+
+
+ val = htod32(val);
+ error = wlu_iovar_setint(wl, name, val);
+ }
+
+ return error;
+}
+
+static int
+wl_assoc_info(void *wl, cmd_t *cmd, char **argv)
+{
+ uint i, req_ies_len = 0, resp_ies_len = 0;
+ wl_assoc_info_t assoc_info;
+ int ret;
+ uint8 *pbuf;
+
+ UNUSED_PARAMETER(argv);
+
+ /* get the generic association information */
+ strcpy(buf, cmd->name);
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0)
+ return ret;
+
+ memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t));
+ assoc_info.req_len = htod32(assoc_info.req_len);
+ assoc_info.resp_len = htod32(assoc_info.resp_len);
+ assoc_info.flags = htod32(assoc_info.flags);
+
+ printf("Assoc req:\n");
+ printf("\tlen 0x%x\n", assoc_info.req_len);
+ if (assoc_info.req_len) {
+ printf("\tcapab 0x%x\n", ltoh16(assoc_info.req.capability));
+ printf("\tlisten 0x%x\n", ltoh16(assoc_info.req.listen));
+ req_ies_len = assoc_info.req_len - sizeof(struct dot11_assoc_req);
+ if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
+ printf("\treassoc bssid %s\n",
+ wl_ether_etoa(&assoc_info.reassoc_bssid));
+ req_ies_len -= ETHER_ADDR_LEN;
+ }
+ }
+
+ /* get the association req IE's if there are any */
+ if (req_ies_len) {
+ strcpy(buf, "assoc_req_ies");
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0)
+ return ret;
+
+ printf("assoc req IEs:\n\t");
+ for (i = 1, pbuf = (uint8*)buf; i <= req_ies_len; i++) {
+ printf("0x%02x ", *pbuf++);
+ if (!(i%8))
+ printf("\n\t");
+ }
+ }
+
+ printf("\nAssoc resp:\n");
+ printf("\tlen 0x%x\n", assoc_info.resp_len);
+ if (assoc_info.resp_len) {
+ printf("\tcapab 0x%x\n", ltoh16(assoc_info.resp.capability));
+ printf("\tstatus 0x%x\n", ltoh16(assoc_info.resp.status));
+ printf("\taid 0x%x\n", ltoh16(assoc_info.resp.aid));
+ resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp);
+ }
+
+ /* get the association resp IE's if there are any */
+ if (resp_ies_len) {
+ strcpy(buf, "assoc_resp_ies");
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0)
+ return ret;
+
+ printf("assoc resp IEs:\n\t");
+ for (i = 1, pbuf = (uint8*)buf; i <= resp_ies_len; i++) {
+ printf(" 0x%02x ", *pbuf++);
+ if (!(i%8))
+ printf("\n\t");
+
+ }
+ }
+ printf("\n");
+
+ return 0;
+}
+
+static int
+wl_pmkid_info(void *wl, cmd_t *cmd, char**argv)
+{
+ int i, j, ret;
+ pmkid_list_t *pmkid_info;
+
+ if (!*++argv) {
+ strcpy(buf, cmd->name);
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0)
+ return ret;
+
+ pmkid_info = (pmkid_list_t *)buf;
+ pmkid_info->npmkid = dtoh32(pmkid_info->npmkid);
+ printf("\npmkid entries : %d\n", pmkid_info->npmkid);
+
+ for (i = 0; i < (int)pmkid_info->npmkid; i++) {
+ printf("\tPMKID[%d]: %s =",
+ i, wl_ether_etoa(&pmkid_info->pmkid[i].BSSID));
+ for (j = 0; j < WPA2_PMKID_LEN; j++)
+ printf("%02x ", pmkid_info->pmkid[i].PMKID[j]);
+ printf("\n");
+ }
+ }
+ else {
+#ifdef test_pmkid_info
+ char eaddr[6] = {0x0, 0x0, 0x1, 0x2, 0x3, 0x5};
+ char eaddr1[6] = {0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+ char id[WPA2_PMKID_LEN], id1[WPA2_PMKID_LEN];
+ int i, len = (sizeof(uint32) + 2*(sizeof(pmkid_t)));
+
+ /* check that the set uses to "test" cmd */
+ if (strcmp(*argv, "test")) {
+ printf("\t wl pmkid_info only supports `test` a test specific set\n");
+ return BCME_USAGE_ERROR;
+ }
+ if ((pmkid_info = (pmkid_list_t *)malloc(len)) == NULL) {
+ printf("\tfailed to allocate buffer\n");
+ return BCME_NOMEM;
+ }
+
+ printf("\toverwriting pmkid table with test pattern\n");
+ for (i = 0; i < (int)sizeof(id); i++) {
+ id[i] = i;
+ id1[i] = (i*2);
+ }
+
+ /* "test" - creates two PMKID entries and sets the table to that */
+ pmkid_info->npmkid = htod32(2);
+ memcpy(&pmkid_info->pmkid[0].BSSID.octet[0], &eaddr[0], ETHER_ADDR_LEN);
+ memcpy(&pmkid_info->pmkid[0].PMKID[0], &id[0], WPA2_PMKID_LEN);
+ memcpy(&pmkid_info->pmkid[1].BSSID.octet[0], &eaddr1[0], ETHER_ADDR_LEN);
+ memcpy(&pmkid_info->pmkid[1].PMKID[0], &id1[0], WPA2_PMKID_LEN);
+
+ ret = wlu_var_setbuf(wl, cmd->name, pmkid_info, len);
+
+ free(pmkid_info);
+
+ return ret;
+#else
+ printf("\tset cmd ignored\n");
+#endif /* test_pmkid_info */
+ }
+
+ return 0;
+}
+
+static int
+wl_rateset(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_rateset_args_t rs, defrs;
+ int error;
+ uint i;
+
+ UNUSED_PARAMETER(cmd);
+
+ error = 0;
+
+ argv++;
+
+ if (*argv == NULL) {
+ /* get current rateset */
+ if ((error = wlu_iovar_get(wl, "cur_rateset", &rs, sizeof(rs))) < 0)
+ return (error);
+
+ dump_rateset(rs.rates, dtoh32(rs.count));
+ printf("\n");
+ wl_print_mcsset((char *)rs.mcs);
+ wl_print_vhtmcsset((uint16 *)rs.vht_mcs);
+ } else {
+ /* get default rateset and mcsset */
+ if ((error = wlu_iovar_get(wl, "rateset", &defrs,
+ sizeof(wl_rateset_args_t))) < 0)
+ return (error);
+ defrs.count = dtoh32(defrs.count);
+
+ if (!stricmp(*argv, "all")) {
+ for (i = 0; i < defrs.count; i++)
+ defrs.rates[i] |= 0x80;
+ defrs.count = htod32(defrs.count);
+ error = wlu_iovar_set(wl, "rateset", &defrs,
+ sizeof(wl_rateset_args_t));
+ }
+ else if (!stricmp(*argv, "default")) {
+ defrs.count = htod32(defrs.count);
+ error = wlu_iovar_set(wl, "rateset", &defrs,
+ sizeof(wl_rateset_args_t));
+ }
+ else { /* arbitrary list */
+ error = wl_parse_rateset(wl, &defrs, argv);
+ if (!error) {
+
+ /* check for common error of no basic rates */
+ for (i = 0; i < defrs.count; i++) {
+ if (defrs.rates[i] & 0x80)
+ break;
+ }
+ if (i < defrs.count) {
+ defrs.count = htod32(defrs.count);
+ error = wlu_iovar_set(wl, "rateset", &defrs,
+ sizeof(wl_rateset_args_t));
+ } else {
+ error = BCME_BADARG;
+ fprintf(stderr,
+ "Bad Args: at least one rate must be marked Basic\n");
+ }
+ }
+ }
+
+ }
+ return (error);
+}
+
+static int
+wl_default_rateset(void *wl, cmd_t *cmd, char **argv)
+{
+ int error = 0;
+ wl_rates_info_t rates_info;
+
+ UNUSED_PARAMETER(cmd);
+
+ memset((char*)&rates_info.rs_tgt, 0, sizeof(wl_rateset_t));
+
+ argv++;
+ /* not enough params */
+ if (*argv == NULL) {
+ fprintf(stderr, "Can't parse phy type\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* phy_type */
+ if (!stricmp(*argv, "a"))
+ rates_info.phy_type = 0;
+ else if (!stricmp(*argv, "b"))
+ rates_info.phy_type = 2;
+ else if (!stricmp(*argv, "g"))
+ rates_info.phy_type = 2;
+ else if (!stricmp(*argv, "n"))
+ rates_info.phy_type = 4;
+ else if (!stricmp(*argv, "lp"))
+ rates_info.phy_type = 5;
+ else if (!stricmp(*argv, "ssn"))
+ rates_info.phy_type = 6;
+ else if (!stricmp(*argv, "ht"))
+ rates_info.phy_type = 7;
+ else if (!stricmp(*argv, "lcn"))
+ rates_info.phy_type = 8;
+ else if (!stricmp(*argv, "lcn40"))
+ rates_info.phy_type = 10;
+ else if (!stricmp(*argv, "ac"))
+ rates_info.phy_type = 11;
+ else {
+ fprintf(stderr, "Wrong phy type: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+ /* not enough params */
+ if (*argv == NULL) {
+ fprintf(stderr, "Can't parse band type\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* band type */
+ if (!stricmp(*argv, "5"))
+ rates_info.bandtype = WLC_BAND_5G;
+ else if (!stricmp(*argv, "2"))
+ rates_info.bandtype = WLC_BAND_2G;
+ else {
+ fprintf(stderr, "Wrong band type: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+ /* not enough params */
+ if (*argv == NULL) {
+ fprintf(stderr, "Can't parse cck\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* cck only */
+ if (!stricmp(*argv, "0"))
+ rates_info.cck_only = FALSE;
+ else if (!stricmp(*argv, "1"))
+ rates_info.cck_only = TRUE;
+ else {
+ fprintf(stderr, "Wrong cck: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+ /* not enough params */
+ if (*argv == NULL) {
+ fprintf(stderr, "Can't parse basic rates\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* rate_mask */
+ if (!stricmp(*argv, "0"))
+ rates_info.rate_mask = 0x7f;
+ else if (!stricmp(*argv, "1"))
+ rates_info.rate_mask = 0xff;
+ else {
+ fprintf(stderr, "Wrong basic rates: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+ /* not enough params */
+ if (*argv == NULL) {
+ fprintf(stderr, "Can't parse mcs\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* mcs */
+ if (!stricmp(*argv, "0"))
+ rates_info.mcsallow = FALSE;
+ else if (!stricmp(*argv, "1"))
+ rates_info.mcsallow = TRUE;
+ else {
+ fprintf(stderr, "Wrong mcs: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+ /* not enough params */
+ if (*argv == NULL) {
+ fprintf(stderr, "Can't parse bandwidth\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* channel bandwidth */
+ if (!stricmp(*argv, "10"))
+ rates_info.bw = 10;
+ else if (!stricmp(*argv, "20"))
+ rates_info.bw = 20;
+ else if (!stricmp(*argv, "40"))
+ rates_info.bw = 40;
+ else if (!stricmp(*argv, "80"))
+ rates_info.bw = 80;
+ else if (!stricmp(*argv, "160"))
+ rates_info.bw = 160;
+ else {
+ fprintf(stderr, "Wrong bandwidth: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+ /* not enough params */
+ if (*argv == NULL) {
+ fprintf(stderr, "Can't parse tx/rx streams\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* mcs */
+ if (!stricmp(*argv, "tx")) {
+ int txstreams;
+ if ((error = wlu_iovar_getint(wl, "txstreams", &txstreams)) < 0) {
+ fprintf(stderr, "Can't get tx streams\n");
+ return BCME_USAGE_ERROR;
+ }
+ rates_info.txstreams = txstreams;
+ }
+ else if (!stricmp(*argv, "rx")) {
+ int rxstreams;
+ if ((error = wlu_iovar_getint(wl, "rxstreams", &rxstreams)) < 0) {
+ fprintf(stderr, "Can't get rx streams\n");
+ return BCME_USAGE_ERROR;
+ }
+ rates_info.txstreams = rxstreams;
+ }
+ else {
+ fprintf(stderr, "Wrong tx/rx streams: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* get default rates */
+ if ((error = wlu_iovar_getbuf(wl, "default_rateset", NULL, 0, &rates_info,
+ sizeof(wl_rates_info_t)))) {
+ fprintf(stderr, "default_rateset failed\n");
+ return (error);
+ }
+
+ dump_rateset(rates_info.rs_tgt.rates, dtoh32(rates_info.rs_tgt.count));
+
+ return (error);
+}
+
+static int
+wl_txbf_rateset(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_txbf_rateset_t rs;
+ int error = 0;
+
+ argv++;
+
+ if ((error = wlu_iovar_get(wl, cmd->name, &rs, sizeof(rs))) < 0)
+ return (error);
+ /* Get txbf rateset */
+ if (*argv == NULL) {
+ printf(" OFDM: ");
+ dump_rateset(rs.txbf_rate_ofdm, dtoh32(rs.txbf_rate_ofdm_cnt));
+ printf("\n");
+ wl_print_txbf_mcsset((char *)rs.txbf_rate_mcs, " ");
+ wl_print_txbf_vhtmcsset((uint16 *)rs.txbf_rate_vht, " ");
+
+ printf("BCM OFDM: ");
+ dump_rateset(rs.txbf_rate_ofdm_bcm, dtoh32(rs.txbf_rate_ofdm_cnt_bcm));
+ printf("\n");
+ wl_print_txbf_mcsset((char *)rs.txbf_rate_mcs_bcm, "BCM");
+ wl_print_txbf_vhtmcsset((uint16 *)rs.txbf_rate_vht_bcm, "BCM");
+ } else { /* Set txbf rateset */
+ error = wl_parse_txbf_rateset(&rs, argv);
+ if (!error) {
+ rs.txbf_rate_ofdm_cnt = htod32(rs.txbf_rate_ofdm_cnt);
+ rs.txbf_rate_ofdm_cnt_bcm = htod32(rs.txbf_rate_ofdm_cnt_bcm);
+ error = wlu_iovar_set(wl, cmd->name, &rs, sizeof(rs));
+ }
+ }
+ return (error);
+}
+
+static int
+wl_sup_rateset(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_rateset_args_t rs;
+ bool got_basic;
+ int error;
+ uint i;
+
+ error = 0;
+ memset((char*)&rs, 0, sizeof(wl_rateset_args_t));
+
+ argv++;
+
+ if (*argv == NULL) {
+ /* get rateset */
+ if ((error = wlu_get(wl, cmd->get, &rs, sizeof(wl_rateset_t))) < 0)
+ return (error);
+
+ dump_rateset(rs.rates, dtoh32(rs.count));
+ printf("\n");
+ } else {
+ if (!stricmp(*argv, "-1") || !stricmp(*argv, "0")) {
+ /* set an empty rateset */
+ error = wlu_set(wl, cmd->set, &rs, sizeof(wl_rateset_t));
+ }
+ else { /* set the specified rateset */
+ wl_parse_rateset(wl, &rs, argv);
+ /* check for common error of including a basic rate */
+ got_basic = FALSE;
+ for (i = 0; i < rs.count; i++) {
+ if (rs.rates[i] & 0x80) {
+ rs.rates[i] &= 0x7F;
+ got_basic = TRUE;
+ }
+ }
+ if (got_basic) {
+ fprintf(stderr,
+ "Warning: Basic rate attribute ignored for \"%s\" command\n",
+ cmd->name);
+ }
+ rs.count = htod32(rs.count);
+ error = wlu_set(wl, cmd->set, &rs, sizeof(wl_rateset_t));
+ }
+
+ }
+ return (error);
+}
+
+/*
+ * Parse the rateset command arguments into the passed wl_rateset_args_t structure.
+ *
+ * Returns 0 on success, or an appropriate error code (BCME_USAGE_ERROR, BCME_BADARG).
+ *
+ */
+static int
+wl_parse_rateset(void *wl, wl_rateset_args_t* rs, char **argv)
+{
+ char* endp = NULL;
+ char* arg;
+ int r;
+ int mcs_index = 0;
+ uint32 mcs_mask;
+ int error = 0;
+ wl_rateset_args_t cur_rs;
+ bool mcs_args, vht_args;
+
+ mcs_args = vht_args = FALSE;
+
+ memset(rs, 0, sizeof(*rs));
+
+ while ((arg = *argv++) != NULL) {
+ /* mcs rates */
+ if (!stricmp(arg, "-m")) {
+ mcs_args = TRUE;
+ break;
+ }
+
+ /* vht rates */
+ if (!stricmp(arg, "-v")) {
+ vht_args = TRUE;
+ break;
+ }
+
+ /* Parse legacy rates */
+
+ if (rs->count >= WL_MAXRATES_IN_SET) {
+ fprintf(stderr,
+ "parsing \"%s\", too many rates specified, max is %d rates\n",
+ arg, WL_MAXRATES_IN_SET);
+ error = BCME_USAGE_ERROR;
+ break;
+ }
+
+ /* convert the rate number to a 500kbps rate by multiplying by 2 */
+ r = (int)(strtoul(arg, &endp, 0) * 2);
+ if (endp == arg) {
+ fprintf(stderr, "unable to convert the rate parameter \"%s\"\n", arg);
+ error = BCME_USAGE_ERROR;
+ break;
+ }
+
+ /* parse a .5 specially */
+ if (!strncmp(endp, ".5", 2)) {
+ r += 1;
+ endp += 2;
+ }
+
+ /* strip trailing space */
+ while (isspace((int)endp[0]))
+ endp++;
+
+ /* check for a basic rate specifier */
+ if (!stricmp(endp, "b") || !stricmp(endp, "(b)")) {
+ r |= 0x80;
+ } else if (endp[0] != '\0') {
+ fprintf(stderr,
+ "unable to convert trailing characters"
+ " \"%s\" in the rate parameter \"%s\"\n",
+ endp, arg);
+ error = BCME_USAGE_ERROR;
+ break;
+ }
+
+ /* no legacy rates specified */
+ if ((rs->count == 0) && (r == 0)) {
+ fprintf(stderr, "empty legacy rateset not supported\n");
+ error = BCME_USAGE_ERROR;
+ break;
+ }
+
+ rs->rates[rs->count++] = r;
+ }
+
+ if (error)
+ return error;
+
+ if (!mcs_args && !vht_args && !rs->count)
+ return BCME_USAGE_ERROR; /* Cannot happen, really */
+
+ /*
+ * If one of the rate sets was not specified, keep its current setting.
+ */
+
+ error = wlu_iovar_get(wl, "cur_rateset", &cur_rs, sizeof(cur_rs));
+ if (error)
+ return error;
+
+ if (!rs->count) { /* No legacy rates specified -- keep what we have */
+ rs->count = cur_rs.count;
+ memcpy(&rs->rates, &cur_rs.rates, rs->count);
+ }
+
+ if (!mcs_args) { /* No MCS rates specified */
+ memcpy(rs->mcs, cur_rs.mcs, MCSSET_LEN);
+ }
+
+ if (!vht_args) { /* No VHT rates specified, keep current values */
+ memcpy(rs->vht_mcs, cur_rs.vht_mcs,
+ VHT_CAP_MCS_MAP_NSS_MAX * sizeof(rs->vht_mcs[0]));
+ }
+
+ /* If no more args, return. */
+
+ if (!arg) {
+ return error;
+ }
+
+ /* Parse mcs or VHT rateset values */
+
+ while ((arg = *argv++) != NULL) {
+
+ if (mcs_args) {
+
+ if (mcs_index >= MCSSET_LEN) {
+ fprintf(stderr, "parsing \"%s\", too many mcs rates "
+ "specified, max is %d rates\n", arg, MCSSET_LEN);
+ error = BCME_USAGE_ERROR;
+ break;
+ }
+
+ mcs_mask = strtoul(arg, &endp, 16);
+
+ if (endp == arg) {
+ fprintf(stderr, "unable to convert the mcs parameter \"%s\"\n", arg);
+ error = BCME_BADARG;
+ break;
+ }
+
+ /* clear the mcs rates */
+ if (mcs_mask == 0) {
+ memset(rs->mcs, 0, MCSSET_LEN);
+ break;
+ }
+
+ /* copy the mcs rates bitmap octets */
+ rs->mcs[mcs_index++] = mcs_mask;
+
+ } else { /* vht_args */
+
+ /*
+ * Specified as rate masks for Nss=0, Nss=1, etc.
+ */
+ if (mcs_index >= VHT_CAP_MCS_MAP_NSS_MAX) {
+ fprintf(stderr,
+ "Error: Too many VHT rate masks specified, max %d\n",
+ VHT_CAP_MCS_MAP_NSS_MAX);
+ error = BCME_USAGE_ERROR;
+ break;
+ }
+
+ mcs_mask = strtoul( arg, &endp, 16 ); /* Base 16 for consistency with -m */
+
+ if ((*arg == '\0') || (*endp != '\0')) {
+ fprintf(stderr, "Error converting VHT rate mask value '%s'\n", arg);
+ error = BCME_USAGE_ERROR;
+ break;
+ }
+
+ /*
+ * Can only specify 0, 0xff, 0x1ff, 0x3ff because of the way the rates
+ * are encoded in the driver (0-3).
+ */
+ if ((mcs_mask != 0x0000) && /* vht disabled */
+ (mcs_mask != VHT_CAP_MCS_0_7_RATEMAP) && /* vht mcs0-7 */
+ (mcs_mask != VHT_CAP_MCS_0_8_RATEMAP) && /* vht mcs0-8 */
+ (mcs_mask != VHT_CAP_MCS_0_9_RATEMAP) && /* vht mcs0-9 */
+ (mcs_mask != (VHT_CAP_MCS_0_9_RATEMAP |
+ VHT_PROP_MCS_10_11_RATEMAP))) { /* vht mcs0-11 */
+ fprintf(stderr, "Error: VHT rate mask must be 0 (disabled),"
+ " 0xff (MCS0-7), 0x1ff (MCS0-8), 0x3ff (MCS0-9) or "
+ "0xfff (MCS0-11).\n");
+ error = BCME_BADARG;
+ break;
+ }
+
+ rs->vht_mcs[mcs_index++] = mcs_mask;
+ }
+ }
+
+ return error;
+}
+
+static int
+wl_parse_txbf_rateset(wl_txbf_rateset_t *rs, char **argv)
+{
+#define TXBF_RATE_OFDM 0
+#define TXBF_RATE_MCS 1
+#define TXBF_RATE_VHT 2
+ char* endp = NULL;
+ char* arg;
+ int i;
+ int error = 0;
+ int rate_type = TXBF_RATE_OFDM;
+ uint8 txbf_rate_mcs[TXBF_RATE_MCS_ALL];
+ uint8 txbf_rate_mcs_cnt = 0;
+ uint8 mcs_mask;
+ uint16 txbf_rate_vht[TXBF_RATE_VHT_ALL];
+ uint8 txbf_rate_vht_cnt = 0;
+ uint16 vht_mask;
+ uint8 txbf_rate_ofdm[TXBF_RATE_OFDM_ALL];
+ uint8 txbf_rate_ofdm_cnt;
+ int r;
+ bool specified_ofdm = FALSE;
+ bool specified_mcs = FALSE;
+ bool specified_vht = FALSE;
+ bool specified_bcm = FALSE;
+
+ /* First see if ofdm list */
+ arg = *argv;
+ if (stricmp(arg, "-m") != 0 && stricmp(arg, "-v") != 0) {
+ rate_type = TXBF_RATE_OFDM;
+ specified_ofdm = TRUE;
+ txbf_rate_ofdm_cnt = 0;
+ }
+
+ while ((arg = *argv++) != NULL) {
+ /* mcs rates */
+ if (!stricmp(arg, "-m")) {
+ rate_type = TXBF_RATE_MCS;
+ specified_mcs = TRUE;
+ txbf_rate_mcs_cnt = 0;
+ continue;
+ }
+ /* vht rates */
+ if (!stricmp(arg, "-v")) {
+ rate_type = TXBF_RATE_VHT;
+ specified_vht = TRUE;
+ txbf_rate_vht_cnt = 0;
+ continue;
+ }
+ /* Broadcom-to-Broadcom group */
+ if (!stricmp(arg, "-b")) {
+ specified_bcm = TRUE;
+ continue;
+ }
+
+ if (rate_type == TXBF_RATE_OFDM) {
+ /* Check if too many specified ofdm rates */
+ if (txbf_rate_ofdm_cnt >= TXBF_RATE_OFDM_ALL) {
+ fprintf(stderr, "ERR: more than max. of %d ofdm rates\n",
+ TXBF_RATE_OFDM_ALL);
+ return (BCME_USAGE_ERROR);
+ }
+ /* Convert user typed number to a 500kbps rate by multiplying by 2 */
+ r = (int)(strtoul(arg, &endp, 0) * 2);
+ if (endp == arg) {
+ fprintf(stderr, "ERR: failed to convert %s\n", arg);
+ return (BCME_USAGE_ERROR);
+ }
+ /* Check if valid ofdm rate */
+ for (i = 0; i < (int)sizeof(ofdm_rates); i++) {
+ /* match: it is a valid ofdm rate */
+ if (r == (ofdm_rates[i] & OFDM_RATE_MASK)) {
+ r = ofdm_rates[i]; /* will pick up basic rate bit too */
+ break;
+ }
+ }
+ if (i >= (int)sizeof(ofdm_rates)) {
+ fprintf(stderr, "ERR: %s is an invalid ofdm rate\n", arg);
+ return (BCME_USAGE_ERROR);
+ }
+
+ /* Strip trailing space */
+ while (isspace((int)endp[0]))
+ endp++;
+ /* No ofdm rate specified */
+ if ((rs->txbf_rate_ofdm_cnt == 0) && (r == 0)) {
+ fprintf(stderr, "ERR: no ofdm rate specified\n");
+ return (BCME_USAGE_ERROR);
+ }
+ txbf_rate_ofdm[txbf_rate_ofdm_cnt++] = r;
+ } else if (rate_type == TXBF_RATE_MCS) {
+ /* Check if exceeding max */
+ if (txbf_rate_mcs_cnt >= TXBF_RATE_MCS_ALL) {
+ fprintf(stderr, "ERR: exceed max. %d bitmask bytes; parsing %s\n",
+ TXBF_RATE_MCS_ALL, arg);
+ return (BCME_BADARG);
+ }
+ mcs_mask = (uint8)strtoul(arg, &endp, 16);
+ if (endp == arg) {
+ fprintf(stderr, "ERR: failed to convert %s\n", arg);
+ return (BCME_USAGE_ERROR);
+ }
+ txbf_rate_mcs[txbf_rate_mcs_cnt++] = mcs_mask;
+ } else if (rate_type == TXBF_RATE_VHT) {
+ /* Check if exceeding max */
+ if (txbf_rate_vht_cnt >= TXBF_RATE_VHT_ALL) {
+ fprintf(stderr, "ERR: exceed max. %d bitmasks; parsing %s\n",
+ TXBF_RATE_VHT_ALL, arg);
+ return (BCME_BADARG);
+ }
+ vht_mask = (uint16)strtoul(arg, &endp, 16);
+ if (endp == arg) {
+ fprintf(stderr, "ERR: failed to convert %s\n", arg);
+ return (BCME_USAGE_ERROR);
+ }
+
+ /* Validate bitmask value */
+ if (vht_mask > 0x0fff) {
+ fprintf(stderr, "ERR: vht bitmask must be 0 (disabled)"
+ " or up to a maximum of 0xfff (MCS0-11).\n");
+ return (BCME_BADARG);
+ }
+ txbf_rate_vht[txbf_rate_vht_cnt++] = vht_mask;
+ }
+
+ } /* while */
+
+ if (specified_mcs && !specified_bcm) {
+ for (i = 0; i < txbf_rate_mcs_cnt; i++)
+ rs->txbf_rate_mcs[i] = txbf_rate_mcs[i];
+ if (txbf_rate_mcs_cnt)
+ for (i = txbf_rate_mcs_cnt; i < TXBF_RATE_MCS_ALL; i++) /* clear trailer */
+ rs->txbf_rate_mcs[i] = 0;
+ }
+
+ if (specified_vht && !specified_bcm) {
+ for (i = 0; i < txbf_rate_vht_cnt; i++)
+ rs->txbf_rate_vht[i] = txbf_rate_vht[i];
+ if (txbf_rate_vht_cnt)
+ for (i = txbf_rate_vht_cnt; i < TXBF_RATE_VHT_ALL; i++) /* clear trailer */
+ rs->txbf_rate_vht[i] = 0;
+ }
+
+ if (specified_ofdm && !specified_bcm) {
+ for (i = 0; i < txbf_rate_ofdm_cnt; i++)
+ rs->txbf_rate_ofdm[i] = txbf_rate_ofdm[i];
+ rs->txbf_rate_ofdm_cnt = txbf_rate_ofdm_cnt;
+ }
+
+ if (specified_mcs && specified_bcm) {
+ for (i = 0; i < txbf_rate_mcs_cnt; i++)
+ rs->txbf_rate_mcs_bcm[i] = txbf_rate_mcs[i];
+ if (txbf_rate_mcs_cnt)
+ for (i = txbf_rate_mcs_cnt; i < TXBF_RATE_MCS_ALL; i++) /* clear trailer */
+ rs->txbf_rate_mcs_bcm[i] = 0;
+ }
+
+ if (specified_vht && specified_bcm) {
+ for (i = 0; i < txbf_rate_vht_cnt; i++)
+ rs->txbf_rate_vht_bcm[i] = txbf_rate_vht[i];
+ if (txbf_rate_vht_cnt)
+ for (i = txbf_rate_vht_cnt; i < TXBF_RATE_VHT_ALL; i++) /* clear trailer */
+ rs->txbf_rate_vht_bcm[i] = 0;
+ }
+
+ if (specified_ofdm && specified_bcm) {
+ for (i = 0; i < txbf_rate_ofdm_cnt; i++)
+ rs->txbf_rate_ofdm_bcm[i] = txbf_rate_ofdm[i];
+ rs->txbf_rate_ofdm_cnt_bcm = txbf_rate_ofdm_cnt;
+ }
+
+ return (error);
+}
+
+/*
+ * Get or Set LPC Params
+ * wl lpc_params \
+ * <rate_stab_thresh> <pwr_stab_thresh> <lpc_exp_time> <pwrup_slow_step>
+ * <pwrup_fast_step> <pwrdn_slow_step>
+ */
+static int
+wl_power_sel_params(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, argc;
+ bool lpc_params_use_powersel_params;
+ lpc_params_t lpc_params;
+
+ UNUSED_PARAMETER(cmd);
+
+ lpc_params_use_powersel_params = (wlc_ver_major(wl) <= 5);
+
+ /* handle old powersel_params_t format support */
+ if (lpc_params_use_powersel_params) {
+ powersel_params_t pwrsel_params;
+
+ argv++;
+
+ if (*argv == NULL) {
+ /* get current powersel params */
+ if ((err = wlu_iovar_get(wl, cmd->name, (void *) &pwrsel_params,
+ (sizeof(powersel_params_t)))) < 0)
+ return (err);
+
+ printf("- Link Power Control parameters -\n");
+ printf("tp_ratio_thresh\t\t= %d\nrate_stab_thresh\t= %d\n",
+ pwrsel_params.tp_ratio_thresh, pwrsel_params.rate_stab_thresh);
+ printf("pwr_stab_thresh\t\t= %d\npwr_sel_exp_time\t= %d\n",
+ pwrsel_params.pwr_stab_thresh, pwrsel_params.pwr_sel_exp_time);
+ } else {
+ char *endptr;
+ /* Validate num of entries */
+ for (argc = 0; argv[argc]; argc++);
+ if (argc != 4)
+ return BCME_USAGE_ERROR;
+
+ argc = 0;
+ pwrsel_params.tp_ratio_thresh = strtol(argv[argc], &endptr, 0);
+ argc++;
+ pwrsel_params.rate_stab_thresh = strtol(argv[argc], &endptr, 0);
+ argc++;
+ pwrsel_params.pwr_stab_thresh = strtol(argv[argc], &endptr, 0);
+ argc++;
+ pwrsel_params.pwr_sel_exp_time = strtol(argv[argc], &endptr, 0);
+
+ /* Set powersel params */
+ err = wlu_iovar_set(wl, cmd->name, (void *) &pwrsel_params,
+ (sizeof(powersel_params_t)));
+ }
+ return err;
+ }
+
+ /* handle new lpc_params_t format support */
+ argv++;
+
+ if (*argv == NULL) {
+ /* get current powersel params */
+ if ((err = wlu_iovar_get(wl, cmd->name, (void *) &lpc_params,
+ (sizeof(lpc_params_t)))) < 0)
+ return (err);
+
+ printf("- Link Power Control parameters (ver%d) -\n",
+ lpc_params.version);
+ printf("rate_stab_thresh\t= %d\npwr_stab_thresh\t\t= %d\n",
+ lpc_params.rate_stab_thresh, lpc_params.pwr_stab_thresh);
+ printf("lpc_exp_time\t\t= %d\npwrup_slow_step\t\t= %d\n",
+ lpc_params.lpc_exp_time, lpc_params.pwrup_slow_step);
+ printf("pwrup_fast_step\t\t= %d\npwrdn_slow_step\t\t= %d\n",
+ lpc_params.pwrup_fast_step, lpc_params.pwrdn_slow_step);
+ } else {
+ char *endptr;
+ /* Validate num of entries */
+ for (argc = 0; argv[argc]; argc++);
+ if (argc != 6)
+ return BCME_USAGE_ERROR;
+
+ lpc_params.version = WL_LPC_PARAMS_CURRENT_VERSION;
+ lpc_params.length = sizeof(lpc_params);
+
+ argc = 0;
+ lpc_params.rate_stab_thresh = strtol(argv[argc], &endptr, 0);
+ argc++;
+ lpc_params.pwr_stab_thresh = strtol(argv[argc], &endptr, 0);
+ argc++;
+ lpc_params.lpc_exp_time = strtol(argv[argc], &endptr, 0);
+ argc++;
+ lpc_params.pwrup_slow_step = strtol(argv[argc], &endptr, 0);
+ argc++;
+ lpc_params.pwrup_fast_step = strtol(argv[argc], &endptr, 0);
+ argc++;
+ lpc_params.pwrdn_slow_step = strtol(argv[argc], &endptr, 0);
+
+ /* Set powersel params */
+ err = wlu_iovar_set(wl, cmd->name, (void *) &lpc_params,
+ (sizeof(lpc_params_t)));
+ }
+
+ return err;
+}
+
+static int
+wl_channel(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ channel_info_t ci;
+
+ if (!*++argv) {
+ memset(&ci, 0, sizeof(ci));
+ if ((ret = wlu_get(wl, cmd->get, &ci, sizeof(channel_info_t))) < 0)
+ return ret;
+ ci.hw_channel = dtoh32(ci.hw_channel);
+ ci.scan_channel = dtoh32(ci.scan_channel);
+ ci.target_channel = dtoh32(ci.target_channel);
+ if (ci.scan_channel) {
+ printf("Scan in progress.\n");
+ printf("current scan channel\t%d\n", ci.scan_channel);
+ } else {
+ printf("No scan in progress.\n");
+ }
+ printf("current mac channel\t%d\n", ci.hw_channel);
+ printf("target channel\t%d\n", ci.target_channel);
+ return 0;
+ } else {
+ ci.target_channel = htod32(atoi(*argv));
+ ret = wlu_set(wl, cmd->set, &ci.target_channel, sizeof(int));
+ return ret;
+ }
+}
+
+static int
+wl_chanspec(void *wl, cmd_t *cmd, char **argv)
+{
+ miniopt_t to;
+ const char* fn_name = "wl_chanspec";
+ bool band_set = FALSE, ch_set = FALSE, bw_set = FALSE, ctl_sb_set = FALSE;
+ int err, opt_err;
+ uint32 val = 0;
+ chanspec_t chanspec = 0;
+
+ /* toss the command name */
+ argv++;
+
+ if (!*argv) {
+ if (cmd->get < 0)
+ return -1;
+ if ((err = wlu_iovar_getint(wl, cmd->name, (int*)&val)) < 0)
+ return err;
+
+ chanspec = wl_chspec32_from_driver(val);
+ wf_chspec_ntoa(chanspec, buf);
+ printf("%s (0x%x)\n", buf, chanspec);
+ return 0;
+ }
+
+
+ chanspec = wf_chspec_aton(*argv);
+ if (chanspec != 0) {
+ val = wl_chspec32_to_driver(chanspec);
+ if (val != INVCHANSPEC) {
+ err = wlu_iovar_setint(wl, cmd->name, val);
+ } else {
+ err = BCME_USAGE_ERROR;
+ }
+ } else {
+ miniopt_init(&to, fn_name, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 'c') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " the channel\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val > 224) {
+ fprintf(stderr, "%s: invalid channel %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ chanspec |= to.val;
+ ch_set = TRUE;
+ }
+ if (to.opt == 'b') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for band\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 5) && (to.val != 2)) {
+ fprintf(stderr,
+ "%s: invalid band %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == 5)
+ chanspec |= WL_CHANSPEC_BAND_5G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ band_set = TRUE;
+ }
+ if (to.opt == 'w') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " bandwidth\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 20) && (to.val != 40) && (to.val != 80) &&
+ (to.val != 160)) {
+ fprintf(stderr,
+ "%s: invalid bandwidth %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == 20)
+ chanspec |= WL_CHANSPEC_BW_20;
+ else if (to.val == 40)
+ chanspec |= WL_CHANSPEC_BW_40;
+ else if (to.val == 80)
+ chanspec |= WL_CHANSPEC_BW_80;
+ else
+ chanspec |= WL_CHANSPEC_BW_160;
+ bw_set = TRUE;
+ }
+ if (to.opt == 's') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " ctl sideband\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 1) && (to.val != 0) && (to.val != -1)) {
+ fprintf(stderr,
+ "%s: invalid ctl sideband %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == -1)
+ chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
+ else if (to.val == 1)
+ chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
+ ctl_sb_set = TRUE;
+ }
+ }
+
+ /* set ctl sb to 20 if not set and 20mhz is selected */
+ if (!ctl_sb_set && CHSPEC_IS20(chanspec)) {
+ ctl_sb_set = TRUE;
+ }
+
+ if (ch_set && band_set && bw_set && ctl_sb_set) {
+ val = wl_chspec32_to_driver(chanspec);
+ if (val != INVCHANSPEC) {
+ err = wlu_iovar_setint(wl, cmd->name, val);
+ } else {
+ err = BCME_USAGE_ERROR;
+ }
+ } else {
+ if (!ch_set)
+ fprintf(stderr, "%s: you need to set a channel,"
+ " '-c <ch>'\n", fn_name);
+ if (!band_set)
+ fprintf(stderr, "%s: you need to set a band,"
+ " '-b <5|2>'\n", fn_name);
+ if (!bw_set)
+ fprintf(stderr, "%s: you need to set a bandwidth,"
+ " '-w <20|40>'\n", fn_name);
+ if (!ctl_sb_set)
+ fprintf(stderr, "%s: you need to set a ctl sideband,"
+ " '-s <-1|0|1>'\n", fn_name);
+ err = BCME_USAGE_ERROR;
+ }
+ }
+
+ if (!err)
+ printf("Chanspec set to 0x%x\n", chanspec);
+
+exit:
+ return err;
+}
+
+static int
+wl_sc_chan(void *wl, cmd_t *cmd, char **argv)
+{
+ miniopt_t to;
+ const char* fn_name = "wl_sc_chan";
+ bool band_set = FALSE, ch_set = FALSE, bw_set = FALSE, ctl_sb_set = FALSE;
+ int err, opt_err;
+ uint32 val = 0;
+ chanspec_t chanspec = 0;
+
+ /* toss the command name */
+ argv++;
+
+ if (!*argv) {
+ if (cmd->get < 0)
+ return -1;
+ if ((err = wlu_iovar_getint(wl, cmd->name, (int*)&val)) < 0)
+ return err;
+
+ chanspec = wl_chspec32_from_driver(val);
+ wf_chspec_ntoa(chanspec, buf);
+ printf("%s (0x%x)\n", buf, chanspec);
+ return 0;
+ }
+
+ chanspec = wf_chspec_aton(*argv);
+ if (chanspec != 0) {
+ val = wl_chspec32_to_driver(chanspec);
+ if (val != INVCHANSPEC) {
+ err = wlu_iovar_setint(wl, cmd->name, val);
+ } else {
+ err = BCME_USAGE_ERROR;
+ }
+ } else {
+ miniopt_init(&to, fn_name, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 'c') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " the channel\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val > 224) {
+ fprintf(stderr, "%s: invalid channel %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ chanspec |= to.val;
+ ch_set = TRUE;
+ }
+ if (to.opt == 'b') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for band\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 5) && (to.val != 2)) {
+ fprintf(stderr,
+ "%s: invalid band %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == 5)
+ chanspec |= WL_CHANSPEC_BAND_5G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ band_set = TRUE;
+ }
+ if (to.opt == 'w') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " bandwidth\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 20) && (to.val != 40) && (to.val != 80)) {
+ fprintf(stderr,
+ "%s: invalid bandwidth %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == 20)
+ chanspec |= WL_CHANSPEC_BW_20;
+ else if (to.val == 40)
+ chanspec |= WL_CHANSPEC_BW_40;
+ else
+ chanspec |= WL_CHANSPEC_BW_80;
+ bw_set = TRUE;
+ }
+ if (to.opt == 's') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " ctl sideband\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 1) && (to.val != 0) && (to.val != -1)) {
+ fprintf(stderr,
+ "%s: invalid ctl sideband %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == -1)
+ chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
+ else if (to.val == 1)
+ chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
+ ctl_sb_set = TRUE;
+ }
+ }
+
+ /* set ctl sb to 20 if not set and 20mhz is selected */
+ if (!ctl_sb_set && CHSPEC_IS20(chanspec)) {
+ ctl_sb_set = TRUE;
+ }
+
+ if (ch_set && band_set && bw_set && ctl_sb_set) {
+ val = wl_chspec32_to_driver(chanspec);
+ if (val != INVCHANSPEC) {
+ err = wlu_iovar_setint(wl, cmd->name, val);
+ } else {
+ err = BCME_USAGE_ERROR;
+ }
+ } else {
+ if (!ch_set)
+ fprintf(stderr, "%s: you need to set a channel,"
+ " '-c <ch>'\n", fn_name);
+ if (!band_set)
+ fprintf(stderr, "%s: you need to set a band,"
+ " '-b <5|2>'\n", fn_name);
+ if (!bw_set)
+ fprintf(stderr, "%s: you need to set a bandwidth,"
+ " '-w <20|40>'\n", fn_name);
+ if (!ctl_sb_set)
+ fprintf(stderr, "%s: you need to set a ctl sideband,"
+ " '-s <-1|0|1>'\n", fn_name);
+ err = BCME_USAGE_ERROR;
+ }
+ }
+
+ if (!err)
+ printf("SC Chanspec set to 0x%x\n", chanspec);
+
+exit:
+ return err;
+}
+
+static int
+wl_phy_vcore(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ uint32 val = 0;
+ uint8 bw80p80_cap = 0;
+ uint8 ncore = 0;
+ uint8 hw_swmask_txchain = 0;
+ uint8 hw_swmask_rxchain = 0;
+ bool tx_80p80_valid = FALSE;
+ bool rx_80p80_valid = FALSE;
+
+ /* toss the command name */
+ argv++;
+
+ if (!*argv) {
+ if (cmd->get < 0)
+ return -1;
+ if ((err = wlu_iovar_getint(wl, cmd->name, (int*)&val)) < 0)
+ return err;
+ bw80p80_cap = (val >> 12) & 0x1;
+ /*
+ * assume maximum core number is 4
+ * bit extension is needed for future > 4-core design
+ */
+ ncore = (val >> 8) & 0xf;
+ hw_swmask_txchain = (val >> 4) & 0xf;
+ hw_swmask_rxchain = val & 0xf;
+ printf("REAL160:NO\n");
+
+ if (bw80p80_cap == 1) {
+ if (ncore == 4) {
+ /* 80p80 for 4-core, 4365 */
+ tx_80p80_valid |= hw_swmask_txchain == 0xf;
+ tx_80p80_valid |= hw_swmask_txchain == 0xa;
+ tx_80p80_valid |= hw_swmask_txchain == 0x5;
+ rx_80p80_valid |= hw_swmask_rxchain == 0xf;
+ rx_80p80_valid |= hw_swmask_rxchain == 0xa;
+ rx_80p80_valid |= hw_swmask_rxchain == 0x5;
+ if (!(tx_80p80_valid) || !(rx_80p80_valid)) {
+ printf("80p80:NO\n");
+ } else {
+ printf("80p80:YES\n");
+ if (hw_swmask_txchain == 0xf) {
+ printf("tx_vcore=%d txchain= %d\n", 1, 5);
+ printf("tx_vcore=%d txchain=%d\n", 2, 10);
+ printf("tx_vcore=%d txchain=%d\n", 3, 15);
+ } else if (hw_swmask_txchain == 0xa) {
+ printf("tx_vcore=%d txchain=%d\n", 2, 10);
+ } else {
+ printf("tx_vcore=%d txchain= %d\n", 1, 5);
+ }
+ if (hw_swmask_rxchain == 0xf) {
+ printf("rx_vcore=%d rxchain= %d\n", 1, 5);
+ printf("rx_vcore=%d rxchain=%d\n", 2, 10);
+ printf("rx_vcore=%d rxchain=%d\n", 3, 15);
+ } else if (hw_swmask_rxchain == 0xa) {
+ printf("rx_vcore=%d rxchain=%d\n", 2, 10);
+ } else {
+ printf("rx_vcore=%d rxchain= %d\n", 1, 5);
+ }
+ }
+ } else if (ncore == 2) {
+ /* 80p80 for 2-core, 4349 */
+ tx_80p80_valid |= hw_swmask_txchain == 0x3;
+ rx_80p80_valid |= hw_swmask_rxchain == 0x3;
+
+ if (!(tx_80p80_valid) || !(rx_80p80_valid)) {
+ printf("80p80:NO\n");
+ } else {
+ printf("80p80:YES\n");
+ printf("tx_vcore=%d txchain= %d\n", 1, 3);
+ printf("rx_vcore=%d rxchain= %d\n", 1, 3);
+ }
+ } else {
+ printf("!!!Number of cores should be 2 or 4!!!\n");
+ }
+ } else {
+ printf("80p80:NO\n");
+ }
+ return 0;
+ } else {
+ return BCME_UNSUPPORTED;
+ }
+}
+
+
+static int
+wl_dfs_ap_move(void *wl, cmd_t *cmd, char **argv)
+{
+ miniopt_t to;
+ void *ptr;
+ const char* fn_name = "wl_dfs_ap_move";
+ bool band_set = FALSE, ch_set = FALSE, bw_set = FALSE, ctl_sb_set = FALSE;
+ int err, opt_err;
+ uint32 val = 0;
+ chanspec_t chanspec = 0;
+ int arg1;
+ struct wl_dfs_ap_move_status_v1 *status_v1;
+ struct wl_dfs_ap_move_status_v2 *status_v2;
+
+ char chanbuf[CHANSPEC_STR_LEN];
+ const char *dfs_state_str[DFS_SCAN_S_MAX] = {
+ "Radar Free On Channel",
+ "Radar Found On Channel",
+ "Radar Scan In Progress",
+ "Radar Scan Aborted",
+ "RSDB Mode switch in Progress For Scan"
+ };
+
+ /* toss the command name */
+ argv++;
+
+ /* GET */
+ if (!*argv) {
+ if (cmd->get < 0)
+ return -1;
+
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, NULL, 0, &ptr))) {
+ printf("err=%d \n", err);
+ return err;
+ }
+
+ /* Check for firmware version */
+ if (wlc_ver_major(wl) <= 5) {
+
+ status_v1 = (struct wl_dfs_ap_move_status_v1*)ptr;
+
+ if (status_v1->dfs_status != DFS_SCAN_S_IDLE) {
+ chanspec = wl_chspec32_from_driver(status_v1->chanspec);
+ if (chanspec != 0 && chanspec != INVCHANSPEC) {
+ wf_chspec_ntoa(chanspec, chanbuf);
+ printf("AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec);
+ }
+ printf("%s\n", dfs_state_str[status_v1->dfs_status]);
+ err = wl_print_dfs_status(&status_v1->cac_status);
+
+ } else
+ printf("dfs AP move in IDLE state\n");
+
+ return err;
+ } else {
+ status_v2 = (struct wl_dfs_ap_move_status_v2*)ptr;
+
+ if (status_v2->version != WL_DFS_AP_MOVE_VERSION) {
+ err = BCME_UNSUPPORTED;
+ printf("err=%d version=%d\n", err, status_v2->version);
+ return err;
+ }
+
+ printf("version=%d, move status=%d\n", status_v2->version,
+ status_v2->move_status);
+
+ if (status_v2->move_status != (int8) DFS_SCAN_S_IDLE) {
+ chanspec = wl_chspec32_from_driver(status_v2->chanspec);
+ if (chanspec != 0 && chanspec != INVCHANSPEC) {
+ wf_chspec_ntoa(chanspec, chanbuf);
+ printf("AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec);
+ }
+ printf("%s\n", dfs_state_str[status_v2->move_status]);
+ err = wl_print_dfs_status_all(&status_v2->scan_status);
+
+ } else {
+ printf("dfs AP move in IDLE state\n");
+ err = wl_print_dfs_status_all(&status_v2->scan_status);
+ }
+
+ return err;
+ }
+ }
+
+
+ /* SET */
+ arg1 = atoi(*argv);
+ chanspec = wf_chspec_aton(*argv);
+
+ if (arg1 == WL_DFS_AP_MOVE_ABORT || arg1 == WL_DFS_AP_MOVE_STUNT) {
+ err = wlu_iovar_setint(wl, cmd->name, arg1);
+ } else if (chanspec != 0) {
+ val = wl_chspec32_to_driver(chanspec);
+ if (val != INVCHANSPEC) {
+ err = wlu_iovar_setint(wl, cmd->name, val);
+ } else {
+ err = BCME_USAGE_ERROR;
+ }
+ } else {
+ miniopt_init(&to, fn_name, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 'c') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " the channel\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val > 224) {
+ fprintf(stderr, "%s: invalid channel %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ chanspec |= to.val;
+ ch_set = TRUE;
+ }
+ if (to.opt == 'b') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for band\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val != 5) {
+ fprintf(stderr,
+ "%s: invalid band %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ chanspec |= WL_CHANSPEC_BAND_5G;
+ band_set = TRUE;
+ }
+ if (to.opt == 'w') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " bandwidth\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 20) && (to.val != 40) && (to.val != 80)) {
+ fprintf(stderr,
+ "%s: invalid bandwidth %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == 20)
+ chanspec |= WL_CHANSPEC_BW_20;
+ else if (to.val == 40)
+ chanspec |= WL_CHANSPEC_BW_40;
+ else
+ chanspec |= WL_CHANSPEC_BW_80;
+ bw_set = TRUE;
+ }
+ if (to.opt == 's') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " ctl sideband\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 1) && (to.val != 0) && (to.val != -1)) {
+ fprintf(stderr,
+ "%s: invalid ctl sideband %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == -1)
+ chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
+ else if (to.val == 1)
+ chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
+ ctl_sb_set = TRUE;
+ }
+ }
+
+ /* set ctl sb to 20 if not set and 20mhz is selected */
+ if (!ctl_sb_set && CHSPEC_IS20(chanspec)) {
+ ctl_sb_set = TRUE;
+ }
+
+ if (ch_set && band_set && bw_set && ctl_sb_set) {
+ val = wl_chspec32_to_driver(chanspec);
+ if (val != INVCHANSPEC) {
+ err = wlu_iovar_setint(wl, cmd->name, val);
+ } else {
+ err = BCME_USAGE_ERROR;
+ }
+ } else {
+ if (!ch_set)
+ fprintf(stderr, "%s: you need to set a channel,"
+ " '-c <ch>'\n", fn_name);
+ if (!band_set)
+ fprintf(stderr, "%s: you need to set a band,"
+ " '-b <5|2>'\n", fn_name);
+ if (!bw_set)
+ fprintf(stderr, "%s: you need to set a bandwidth,"
+ " '-w <20|40>'\n", fn_name);
+ if (!ctl_sb_set)
+ fprintf(stderr, "%s: you need to set a ctl sideband,"
+ " '-s <-1|0|1>'\n", fn_name);
+ err = BCME_USAGE_ERROR;
+ }
+ }
+
+exit:
+ return err;
+}
+
+static int
+wl_dfs_max_safe_tx(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ uint argc, num_vals = 0;
+ uint32 *pvals, vals[3];
+ char *endptr = NULL;
+
+ /* pop command name */
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argc < 4 && argv[argc]; argc++); /* empty loop */
+
+ /* get case */
+ if (argc < 1) {
+ if (cmd->get < 0) {
+ return -1;
+ }
+
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, NULL, 0, (void**)&pvals)) || !pvals) {
+ printf("err=%d \n", err);
+ return err;
+ }
+
+ pvals[0] = dtoh32(pvals[0]);
+ pvals[1] = dtoh32(pvals[1]);
+ pvals[2] = dtoh32(pvals[2]);
+ printf("non-adjacent=%u%%, adjacent=%u%%, eu-weather=%u%%\n",
+ pvals[0], pvals[1], pvals[2]);
+
+ return err;
+ }
+
+ /* set case */
+ if (cmd->get < 0) {
+ return -1;
+ }
+ vals[num_vals++] = htod32(strtol(argv[0], &endptr, 0));
+ if (argc > 1) {
+ vals[num_vals++] = htod32(strtol(argv[1], &endptr, 0));
+ }
+ if (argc > 2) {
+ vals[num_vals++] = htod32(strtol(argv[2], &endptr, 0));
+ }
+
+ if ((err = wlu_var_setbuf_sm(wl, cmd->name, vals, sizeof(*vals)*(num_vals))) != BCME_OK) {
+ printf("err=%d\n", err);
+ return err;
+ }
+
+ return err;
+}
+
+static int
+wl_rclass(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = BCME_USAGE_ERROR;
+ chanspec_t chanspec = 0;
+ void *ptr;
+
+ /* toss the command name */
+ argv++;
+
+ if (*argv) {
+ chanspec = wf_chspec_aton(*argv);
+ if (chanspec != 0) {
+ err = wlu_var_getbuf(wl, cmd->name, &chanspec, sizeof(chanspec_t), &ptr);
+
+ if (err)
+ printf("Read rclass fails: chanspec:0x%x\n", chanspec);
+ else
+ printf("rclass=0x%x\n", *((int *)ptr));
+ }
+ }
+
+ return err;
+}
+
+int
+wl_ether_atoe(const char *a, struct ether_addr *n)
+{
+ char *c = NULL;
+ int i = 0;
+
+ memset(n, 0, ETHER_ADDR_LEN);
+ for (;;) {
+ n->octet[i++] = (uint8)strtoul(a, &c, 16);
+ if (!*c++ || i == ETHER_ADDR_LEN)
+ break;
+ a = c;
+ }
+ return (i == ETHER_ADDR_LEN);
+}
+char *
+wl_ether_etoa(const struct ether_addr *n)
+{
+ static char etoa_buf[ETHER_ADDR_LEN * 3];
+ char *c = etoa_buf;
+ int i;
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ if (i)
+ *c++ = ':';
+ c += sprintf(c, "%02X", n->octet[i] & 0xff);
+ }
+ return etoa_buf;
+}
+
+int
+wl_atoip(const char *a, struct ipv4_addr *n)
+{
+ char *c = NULL;
+ int i = 0;
+
+ for (;;) {
+ n->addr[i++] = (uint8)strtoul(a, &c, 0);
+ if (*c++ != '.' || i == IPV4_ADDR_LEN)
+ break;
+ a = c;
+ }
+ return (i == IPV4_ADDR_LEN);
+}
+
+
+int wl_ipv6_colon(const char *a, char *x)
+{
+ int i;
+ const char *t;
+ int colons = 0;
+ int double_colons = 0;
+ int zero_req = 0;
+
+ if (*a == ':' && *(a+1) != ':')
+ return 1; /* Illegal */
+ t = a;
+ while ((t = strstr(t, "::")) != NULL) {
+ ++t;
+ ++double_colons;
+ }
+
+ if (double_colons == 0) {
+ strcpy(x, a); /* No double colon in the address */
+ return 0;
+ }
+
+ if (double_colons > 1) {
+ return 1; /* Illegal */
+ }
+ t = a;
+ while ((t = strchr(t, ':')) != NULL) {
+ ++t;
+ ++colons;
+ }
+ zero_req = 8 - colons;
+ if (zero_req) {
+ t = a;
+ while (*t) {
+ if (*t == ':' && *(t+1) == ':') {
+ if (t == a) {
+ *x++ = '0';
+ }
+ *x++ = *t++;
+ for (i = 0; i < zero_req; i++) {
+ *x++ = '0';
+ *x++ = ':';
+ }
+ t++;
+ } else {
+ *x++ = *t++;
+ }
+ }
+ } else {
+ strcpy(x, a);
+ }
+ return 0;
+}
+
+int
+wl_atoipv6(const char *a, struct ipv6_addr *n)
+{
+ char *c = NULL;
+ int i = 0;
+ uint16 *addr16;
+ char x[64];
+ char *t = x;
+
+ memset(x, 0, 64);
+
+ if (wl_ipv6_colon(a, x) == 1) {
+ return 0;
+ }
+
+ for (;;) {
+ addr16 = (uint16 *)&n->addr[i];
+ *addr16 = hton16((uint16)strtoul((char *)t, &c, 16));
+ i += 2;
+ if (*c++ != ':' || i == IPV6_ADDR_LEN)
+ break;
+ t = c;
+ }
+
+ return (i == IPV6_ADDR_LEN);
+}
+
+char *
+wl_ipv6toa(const void *ipv6)
+{
+ /* Implementing RFC 5952 Sections 4 + 5 */
+ /* Not thoroughly tested */
+ uint16 *a = (uint16 *)ipv6;
+
+ /* Returned buffer is from a static circular pool to permit several calls in a printf */
+#define IPV6_BUFFER_CNT 4
+ static char buffer[IPV6_BUFFER_CNT][IPV6_ADDR_LEN * 4];
+ static int idx = 0;
+
+ char *p = buffer[idx++ % IPV6_BUFFER_CNT];
+ int i, i_max = -1, cnt = 0, cnt_max = 1;
+ uint8 *a4 = NULL;
+
+ for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
+ if (a[i]) {
+ if (cnt > cnt_max) {
+ cnt_max = cnt;
+ i_max = i - cnt;
+ }
+ cnt = 0;
+ } else
+ cnt++;
+ }
+ if (cnt > cnt_max) {
+ cnt_max = cnt;
+ i_max = i - cnt;
+ }
+ if (i_max == 0 &&
+ /* IPv4-translated: ::ffff:0:a.b.c.d */
+ ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
+ /* IPv4-mapped: ::ffff:a.b.c.d */
+ (cnt_max == 5 && a[5] == 0xffff)))
+ a4 = (uint8*) (a + 6);
+
+ for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
+ if ((uint8*) (a + i) == a4) {
+ sprintf(p, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
+ break;
+ } else if (i == i_max) {
+ *p++ = ':';
+ i += cnt_max - 1;
+ p[0] = ':';
+ p[1] = '\0';
+ } else {
+ if (i)
+ *p++ = ':';
+ p += sprintf(p, "%x", ntoh16(a[i]));
+ }
+ }
+
+ /* Sub-buffer start is found back by rounding p with the sub-buffer size */
+ return buffer[(p - buffer[0]) / sizeof(buffer[0])];
+}
+
+char *
+wl_iptoa(const struct ipv4_addr *n)
+{
+ static char iptoa_buf[IPV4_ADDR_LEN * 4];
+
+ sprintf(iptoa_buf, "%u.%u.%u.%u",
+ n->addr[0], n->addr[1], n->addr[2], n->addr[3]);
+
+ return iptoa_buf;
+}
+
+int
+wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len)
+{
+ int i, c;
+ char *p = ssid_buf;
+
+ if (ssid_len > 32)
+ ssid_len = 32;
+
+ for (i = 0; i < ssid_len; i++) {
+ c = (int)ssid[i];
+ if (c == '\\') {
+ *p++ = '\\';
+ *p++ = '\\';
+ } else if (isprint((uchar)c)) {
+ *p++ = (char)c;
+ } else {
+ p += sprintf(p, "\\x%02X", c);
+ }
+ }
+ *p = '\0';
+
+ return p - ssid_buf;
+}
+
+/* pretty hex print a contiguous buffer */
+void
+wl_hexdump(uchar *dump_buf, uint nbytes)
+{
+ char line[256];
+ char* p;
+ uint i;
+
+ if (nbytes == 0) {
+ printf("\n");
+ return;
+ }
+
+ p = line;
+ for (i = 0; i < nbytes; i++) {
+ if (i % 16 == 0 && nbytes > 16) {
+ p += sprintf(p, "%04d: ", i); /* line prefix */
+ }
+ p += sprintf(p, "%02x ", dump_buf[i]);
+ if (i % 16 == 15) {
+ printf("%s\n", line); /* flush line */
+ p = line;
+ }
+ }
+
+ /* flush last partial line */
+ if (p != line)
+ printf("%s\n", line);
+}
+
+static int
+wl_plcphdr(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int val;
+
+ if (!*++argv) {
+ if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0)
+ return ret;
+ val = dtoh32(val);
+ if (val == WLC_PLCP_AUTO)
+ printf("long");
+ else if (val == WLC_PLCP_SHORT)
+ printf("auto");
+ else if (val == WLC_PLCP_LONG)
+ printf("debug");
+ else
+ printf("unknown");
+ printf("\n");
+ return 0;
+ } else {
+ if (!stricmp(*argv, "long"))
+ val = WLC_PLCP_AUTO;
+ else if (!stricmp(*argv, "auto"))
+ val = WLC_PLCP_SHORT;
+ else if (!stricmp(*argv, "debug"))
+ val = WLC_PLCP_LONG;
+ else
+ return BCME_USAGE_ERROR;
+ val = htod32(val);
+ return wlu_set(wl, cmd->set, &val, sizeof(int));
+ }
+}
+
+/* WLC_GET_RADIO and WLC_SET_RADIO in driver operate on radio_disabled which
+ * is opposite of "wl radio [1|0]". So invert for user.
+ * In addition, display WL_RADIO_SW_DISABLE and WL_RADIO_HW_DISABLE bits.
+ */
+static int
+wl_radio(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ uint val;
+ char *endptr = NULL;
+
+ if (!*++argv) {
+ if (cmd->get < 0)
+ return -1;
+ if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0)
+ return ret;
+ val = dtoh32(val);
+ printf("0x%04x\n", val);
+ return 0;
+ } else {
+ if (cmd->set < 0)
+ return -1;
+ if (!stricmp(*argv, "on"))
+ val = WL_RADIO_SW_DISABLE << 16;
+ else if (!stricmp(*argv, "off"))
+ val = WL_RADIO_SW_DISABLE << 16 | WL_RADIO_SW_DISABLE;
+ else {
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+
+ /* raw bits setting, add the mask if not provided */
+ if ((val >> 16) == 0) {
+ val |= val << 16;
+ }
+ }
+ val = htod32(val);
+ return wlu_set(wl, cmd->set, &val, sizeof(int));
+ }
+}
+
+char *
+ver2str(unsigned int vms, unsigned int vls)
+{
+ static char verstr[100];
+ unsigned int maj, year, month, day, build;
+
+ maj = (vms >> 16) & 0xFFFF;
+ if (maj > 1000) {
+ /* it is probably a date... */
+ year = (vms >> 16) & 0xFFFF;
+ month = vms & 0xFFFF;
+ day = (vls >> 16) & 0xFFFF;
+ build = vls & 0xFFFF;
+ sprintf(verstr, "%d/%d/%d build %d",
+ month, day, year, build);
+ } else {
+ /* it is a tagged release. */
+ sprintf(verstr, "%d.%d RC%d.%d",
+ (vms>>16)&0xFFFF, vms&0xFFFF,
+ (vls>>16)&0xFFFF, vls&0xFFFF);
+ }
+ return verstr;
+}
+
+
+static int
+wl_version(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int bcmerr = 0;
+ char *p = NULL;
+ char *dump_buf;
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ printf("%s\n",
+ ver2str(((EPI_MAJOR_VERSION) << 16) | EPI_MINOR_VERSION,
+ (EPI_RC_NUMBER << 16) | EPI_INCREMENTAL_NUMBER));
+ dump_buf = malloc(WLC_IOCTL_SMLEN);
+ if (dump_buf == NULL) {
+ fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WLC_IOCTL_SMLEN);
+ return BCME_NOMEM;
+ }
+ memset(dump_buf, 0, WLC_IOCTL_SMLEN);
+
+ /* query for 'ver' to get version info */
+ ret = wlu_iovar_get(wl, "ver", dump_buf, WLC_IOCTL_SMLEN);
+
+ /* if the query is successful, continue on and print the result. */
+
+ /* if the query fails, check for a legacy driver that does not support
+ * the "dump" iovar, and instead issue a WLC_DUMP ioctl.
+ */
+ if (ret) {
+ err = wlu_iovar_getint(wl, "bcmerror", &bcmerr);
+ if (!err && (bcmerr == BCME_UNSUPPORTED)) {
+ ret = wlu_get(wl, WLC_DUMP, dump_buf, WLC_IOCTL_SMLEN);
+ }
+ }
+
+ if (ret) {
+ fprintf(stderr, "Error %d on query of driver dump\n", (int)ret);
+ free(dump_buf);
+ return ret;
+ }
+
+ /* keep only the first line from the dump buf output */
+ p = strchr(dump_buf, '\n');
+ if (p)
+ *p = '\0';
+ printf("%s\n", dump_buf);
+
+ free(dump_buf);
+
+ return 0;
+}
+
+static int
+wl_rateparam(void *wl, cmd_t *cmd, char **argv)
+{
+ int val[2];
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ val[0] = htod32(atoi(*argv));
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ val[1] = htod32(atoi(*argv));
+ return wlu_set(wl, cmd->set, val, sizeof(val));
+}
+
+/* wl scan
+ * -s --ssid=ssid_list
+ * -t T --scan_type=T : [active|passive]
+ * --bss_type=T : [infra|bss|adhoc|ibss]
+ * -b --bssid=
+ * -n --nprobes=
+ * -a --active=
+ * -p --passive=
+ * -h --home=
+ * -c --channels=
+ * ssid_list
+ */
+
+/* Parse a comma-separated list from list_str into ssid array, starting
+ * at index idx. Max specifies size of the ssid array. Parses ssids
+ * and returns updated idx; if idx >= max not all fit, the excess have
+ * not been copied. Returns -1 on empty string, or on ssid too long.
+ */
+int
+wl_parse_ssid_list(char* list_str, wlc_ssid_t* ssid, int idx, int max)
+{
+ char *str, *ptr;
+
+ if (list_str == NULL)
+ return -1;
+
+ for (str = list_str; str != NULL; str = ptr) {
+ if ((ptr = strchr(str, ',')) != NULL)
+ *ptr++ = '\0';
+
+ if (strlen(str) > DOT11_MAX_SSID_LEN) {
+ fprintf(stderr, "ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN);
+ return -1;
+ }
+ if (strlen(str) == 0)
+ ssid[idx].SSID_len = 0;
+
+ if (idx < max) {
+ strcpy((char*)ssid[idx].SSID, str);
+ ssid[idx].SSID_len = strlen(str);
+ }
+ idx++;
+ }
+
+ return idx;
+}
+
+int
+wl_scan_prep(void *wl, cmd_t *cmd, char **argv, wl_scan_params_t *params, int *params_size)
+{
+ int val = 0;
+ char key[64];
+ int keylen;
+ char *p, *eq, *valstr, *endptr = NULL;
+ char opt;
+ bool positional_param;
+ bool good_int;
+ bool opt_end;
+ int err = 0;
+ int i;
+
+ int nchan = 0;
+ int nssid = 0;
+ wlc_ssid_t ssids[WL_SCAN_PARAMS_SSID_MAX];
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN);
+ params->bss_type = DOT11_BSSTYPE_ANY;
+ params->scan_type = 0;
+ params->nprobes = -1;
+ params->active_time = -1;
+ params->passive_time = -1;
+ params->home_time = -1;
+ params->channel_num = 0;
+ memset(ssids, 0, WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t));
+
+ /* skip the command name */
+ argv++;
+
+ opt_end = FALSE;
+ while ((p = *argv) != NULL) {
+ argv++;
+ positional_param = FALSE;
+ memset(key, 0, sizeof(key));
+ opt = '\0';
+ valstr = NULL;
+ good_int = FALSE;
+
+ if (opt_end) {
+ positional_param = TRUE;
+ valstr = p;
+ }
+ else if (!strcmp(p, "--")) {
+ opt_end = TRUE;
+ continue;
+ }
+ else if (!strncmp(p, "--", 2)) {
+ eq = strchr(p, '=');
+ if (eq == NULL) {
+ fprintf(stderr,
+ "wl_scan: missing \" = \" in long param \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ keylen = eq - (p + 2);
+ if (keylen > 63)
+ keylen = 63;
+ memcpy(key, p + 2, keylen);
+
+ valstr = eq + 1;
+ if (*valstr == '\0') {
+ fprintf(stderr,
+ "wl_scan: missing value after \" = \" in long param \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ else if (!strncmp(p, "-", 1)) {
+ opt = p[1];
+ if (strlen(p) > 2) {
+ fprintf(stderr,
+ "wl_scan: only single char options, error on param \"%s\"\n", p);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (*argv == NULL) {
+ fprintf(stderr,
+ "wl_scan: missing value parameter after \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ valstr = *argv;
+ argv++;
+ } else {
+ positional_param = TRUE;
+ valstr = p;
+ }
+
+ /* parse valstr as int just in case */
+ val = (int)strtol(valstr, &endptr, 0);
+ if (*endptr == '\0') {
+ /* not all the value string was parsed by strtol */
+ good_int = TRUE;
+ }
+
+ if (opt == 's' || !strcmp(key, "ssid") || positional_param) {
+ nssid = wl_parse_ssid_list(valstr, ssids, nssid, WL_SCAN_PARAMS_SSID_MAX);
+ if (nssid < 0) {
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+
+ /* scan_type is a bitmap value and can have multiple options */
+ if (opt == 't' || !strcmp(key, "scan_type")) {
+ if (!strcmp(valstr, "active")) {
+ /* do nothing - scan_type is initialized outside of while loop */
+ } else if (!strcmp(valstr, "passive")) {
+ params->scan_type |= WL_SCANFLAGS_PASSIVE;
+ } else if (!strcmp(valstr, "prohibit")) {
+ params->scan_type |= WL_SCANFLAGS_PROHIBITED;
+ } else if (!strcmp(valstr, "offchan")) {
+ params->scan_type |= WL_SCANFLAGS_OFFCHAN;
+ } else if (!strcmp(valstr, "hotspot")) {
+ params->scan_type |= WL_SCANFLAGS_HOTSPOT;
+ } else {
+ fprintf(stderr,
+ "scan_type value should be \"active\", "
+ "\"passive\", \"prohibit\", \"offchan\" "
+ "or \"hotspot\", but got \"%s\"\n", valstr);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ if (!strcmp(key, "bss_type")) {
+ if (!strcmp(valstr, "bss") || !strcmp(valstr, "infra")) {
+ params->bss_type = DOT11_BSSTYPE_INFRASTRUCTURE;
+ } else if (!strcmp(valstr, "ibss") || !strcmp(valstr, "adhoc")) {
+ params->bss_type = DOT11_BSSTYPE_INDEPENDENT;
+ } else if (!strcmp(valstr, "any")) {
+ params->bss_type = DOT11_BSSTYPE_ANY;
+ } else {
+ fprintf(stderr,
+ "bss_type value should be "
+ "\"bss\", \"ibss\", or \"any\", but got \"%s\"\n", valstr);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ if (opt == 'b' || !strcmp(key, "bssid")) {
+ if (!wl_ether_atoe(valstr, ¶ms->bssid)) {
+ fprintf(stderr,
+ "could not parse \"%s\" as an ethernet MAC address\n", valstr);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ if (opt == 'n' || !strcmp(key, "nprobes")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as an int for value nprobes\n", valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->nprobes = val;
+ }
+ if (opt == 'a' || !strcmp(key, "active")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as an int for active dwell time\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->active_time = val;
+ }
+ if (opt == 'p' || !strcmp(key, "passive")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as an int for passive dwell time\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->passive_time = val;
+ }
+ if (opt == 'h' || !strcmp(key, "home")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as an int for home channel dwell time\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->home_time = val;
+ }
+ if (opt == 'c' || !strcmp(key, "chanspecs")) {
+ nchan = wl_parse_chanspec_list(valstr, params->channel_list,
+ WL_NUMCHANNELS);
+ if (nchan == -1) {
+ fprintf(stderr, "error parsing chanspec list arg\n");
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+ }
+
+ if (nssid > WL_SCAN_PARAMS_SSID_MAX) {
+ fprintf(stderr, "ssid count %d exceeds max of %d\n",
+ nssid, WL_SCAN_PARAMS_SSID_MAX);
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ params->nprobes = htod32(params->nprobes);
+ params->active_time = htod32(params->active_time);
+ params->passive_time = htod32(params->passive_time);
+ params->home_time = htod32(params->home_time);
+
+ for (i = 0; i < nchan; i++) {
+ params->channel_list[i] = htodchanspec(params->channel_list[i]);
+ }
+
+ for (i = 0; i < nssid; i++) {
+ ssids[i].SSID_len = htod32(ssids[i].SSID_len);
+ }
+
+ /* For a single ssid, use the single fixed field */
+ if (nssid == 1) {
+ nssid = 0;
+ memcpy(¶ms->ssid, &ssids[0], sizeof(ssids[0]));
+ }
+
+ /* Copy ssid array if applicable */
+ if (nssid > 0) {
+ i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16);
+ i = ROUNDUP(i, sizeof(uint32));
+ if (i + nssid * sizeof(wlc_ssid_t) > (uint)*params_size) {
+ fprintf(stderr, "additional ssids exceed params_size\n");
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ p = (char*)params + i;
+ memcpy(p, ssids, nssid * sizeof(wlc_ssid_t));
+ p += nssid * sizeof(wlc_ssid_t);
+ } else {
+ p = (char*)params->channel_list + nchan * sizeof(uint16);
+ }
+
+ params->channel_num = htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) |
+ (nchan & WL_SCAN_PARAMS_COUNT_MASK));
+ *params_size = p - (char*)params + nssid * sizeof(wlc_ssid_t);
+exit:
+ return err;
+}
+
+
+static int
+wl_roamparms(void *wl, cmd_t *cmd, char **argv)
+{
+ int params_size;
+ wl_scan_params_t *params;
+ int err = 0;
+
+ params_size = WL_MAX_ROAMSCAN_DATSZ;
+ params = (wl_scan_params_t*)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
+ return BCME_NOMEM;
+ }
+ memset(params, 0, params_size);
+
+ if (!(argv[1])) {
+#ifdef BCMDBG
+ printf("GET roam scan params\n");
+#endif
+ /* no data to copy here for a get */
+ err = wlu_iovar_getbuf(wl, "roamscan_parms", params, 0,
+ buf, WLC_IOCTL_MEDLEN);
+ if (err) {
+ fprintf(stderr, "Error retrieving roamscan params: %d\n", err);
+ goto done;
+ }
+
+#ifdef BCMDBG
+ prhex(NULL, (void *)buf, 64);
+#endif
+ memset(params, 0, params_size);
+ memcpy(params, buf, params_size);
+
+ printf("Roam Scan Parameters:\n");
+ printf("scan_type: %d\n", dtoh32(params->scan_type));
+ printf("nprobes: %d\n", dtoh32(params->nprobes));
+ printf("active_time: %d\n", dtoh32(params->active_time));
+ printf("passive_time: %d\n", dtoh32(params->passive_time));
+ printf("home_time: %d\n", dtoh32(params->home_time));
+
+ /* print out the channels, if any */
+ if (params->channel_num) {
+ uint32 i;
+ uint32 chcount = dtoh32(params->channel_num);
+ printf("Channels:\n");
+ for (i = 0; i < chcount; i++)
+ printf("Channel number 0x%x\n", dtoh16(params->channel_list[i]));
+ }
+ /* No ssids to print out, ever */
+
+ goto done;
+ }
+
+
+ printf("Setting Roam Scan parameters \n");
+
+
+ err = wl_scan_prep(wl, cmd, argv, params, ¶ms_size);
+
+ if (err)
+ goto done;
+
+ printf("params_size %d\n", params_size);
+ err = wlu_iovar_setbuf(wl, "roamscan_parms", params, params_size, buf, WLC_IOCTL_MEDLEN);
+
+done:
+ free(params);
+ return err;
+}
+
+#ifdef WLRCC
+static int
+wl_roamchannels(void *wl, cmd_t *cmd, char **argv)
+{
+ int params_size;
+ wl_roam_channel_list_t *params;
+ int i, chcount, chspec;
+ int err = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ params_size = sizeof(*params);
+ params = (wl_roam_channel_list_t *)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for scan channels\n", params_size);
+ return BCME_NOMEM;
+ }
+ memset(params, 0, params_size);
+
+ if (!(argv[1])) {
+ /* no data to copy here for a get */
+ err = wlu_iovar_getbuf(wl, "roamscan_channels", params, 0,
+ buf, WLC_IOCTL_MEDLEN);
+ if (err) {
+ fprintf(stderr, "Error retrieving roamscan channels: %d\n", err);
+ goto done;
+ }
+
+ memcpy(params, buf, params_size);
+
+ chcount = dtoh32(params->n);
+ printf("Roam Scan Channels: %d\n", chcount);
+ for (i = 0; i < chcount; i++) {
+ chspec = dtoh16(params->channels[i]);
+ wf_chspec_ntoa(chspec, buf);
+ printf("Channel: %s (0x%x)\n", buf, chspec);
+ }
+ goto done;
+ }
+
+ printf("Setting Roam Scan channels not supported!!!\n");
+
+done:
+ free(params);
+ return err;
+}
+#endif /* WLRCC */
+
+static int
+wl_roam_prof(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ uint i;
+ void *ptr = NULL;
+ uint16 wl_rp_ver = WL_ROAM_PROF_VER_0;
+ uint wl_roam_prof_size = sizeof(wl_roam_prof_band_v1_t);
+ union {
+ wl_roam_prof_band_v1_t v1;
+ wl_roam_prof_band_v2_t v2;
+ } rp;
+
+ /* try to check wlc_ver first
+ * for older FW (WLC interface revision <= 5), wl_roam_prof ver 0 is used;
+ * for newer FW (WLC interface revision > 5), wl_roam_prof ver 1 is used;
+ */
+ if (wlc_ver_major(wl) > 5) {
+ wl_rp_ver = WL_ROAM_PROF_VER_1;
+ wl_roam_prof_size = sizeof(wl_roam_prof_band_v2_t);
+ }
+
+ /* fill in some common fields among all roam_prof verisions */
+ ++argv;
+ rp.v1.ver = wl_rp_ver;
+ if (*argv && (!strcmp(*argv, "b") || !strcmp(*argv, "2g"))) {
+ rp.v1.band = WLC_BAND_2G;
+ } else if (*argv && (!strcmp(*argv, "a") || !strcmp(*argv, "5g"))) {
+ rp.v1.band = WLC_BAND_5G;
+ } else
+ return -1; /* Missing band */
+
+ /* roam_prof version get */
+ rp.v1.len = 0;
+ if ((ret = wlu_var_getbuf(wl, cmd->name, &rp, 8, &ptr)) < 0)
+ return ret;
+
+ memcpy(&rp, ptr, sizeof(rp));
+
+ if (dtoh16(rp.v1.ver) > WL_ROAM_PROF_VER_1) {
+ printf("\tIncorrect version: expected up to %d; got %d\n",
+ WL_ROAM_PROF_VER_1, dtoh16(rp.v1.ver));
+ return BCME_VERSION;
+ }
+
+ if (!*++argv) {
+ /* roam_prof get is done above. */
+ if ((rp.v1.len % wl_roam_prof_size) != 0)
+ printf("bad length (=%d) in return data\n", rp.v1.len);
+
+ for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
+ if ((i * wl_roam_prof_size) > rp.v1.len) break;
+
+ if (rp.v1.ver > WL_ROAM_PROF_VER_0) {
+ /* The full scan period must be non-zero for valid roam profile */
+ if (rp.v2.roam_prof[i].fullscan_period == 0) break;
+
+ printf("flag:%02x RSSI[%d,%d] delta:%d(%s) boost:%d.by.%d "
+ "nfscan:%d period(full:%ds partial:%ds.x%d.%ds) "
+ "CU(trigger:%d%% duration:%ds)\n",
+ rp.v2.roam_prof[i].roam_flags,
+ rp.v2.roam_prof[i].roam_trigger,
+ rp.v2.roam_prof[i].rssi_lower,
+ rp.v2.roam_prof[i].roam_delta,
+ rp.v2.roam_prof[i].channel_usage ? "%" : "dBm",
+ rp.v2.roam_prof[i].rssi_boost_thresh,
+ rp.v2.roam_prof[i].rssi_boost_delta,
+ rp.v2.roam_prof[i].nfscan,
+ rp.v2.roam_prof[i].fullscan_period,
+ rp.v2.roam_prof[i].init_scan_period,
+ rp.v2.roam_prof[i].backoff_multiplier,
+ rp.v2.roam_prof[i].max_scan_period,
+ rp.v2.roam_prof[i].channel_usage,
+ rp.v2.roam_prof[i].cu_avg_calc_dur);
+ } else {
+ /* The full scan period must be non-zero for valid roam profile */
+ if (rp.v1.roam_prof[i].fullscan_period == 0) break;
+
+ printf("flag:%02x RSSI[%d,%d] delta:%d(dBm) boost:%d.by.%d "
+ "nfscan:%d period(full:%ds partial:%ds.x%d.%ds)\n",
+ rp.v1.roam_prof[i].roam_flags,
+ rp.v1.roam_prof[i].roam_trigger,
+ rp.v1.roam_prof[i].rssi_lower,
+ rp.v1.roam_prof[i].roam_delta,
+ rp.v1.roam_prof[i].rssi_boost_thresh,
+ rp.v1.roam_prof[i].rssi_boost_delta,
+ rp.v1.roam_prof[i].nfscan,
+ rp.v1.roam_prof[i].fullscan_period,
+ rp.v1.roam_prof[i].init_scan_period,
+ rp.v1.roam_prof[i].backoff_multiplier,
+ rp.v1.roam_prof[i].max_scan_period);
+ }
+ }
+ } else {
+ /* set */
+ memset(&rp.v1.roam_prof[0], 0, wl_roam_prof_size * WL_MAX_ROAM_PROF_BRACKETS);
+ for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
+ if (rp.v1.ver > WL_ROAM_PROF_VER_0) {
+ if (!*argv) break;
+ rp.v2.roam_prof[i].roam_flags = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].roam_trigger = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].rssi_lower = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].roam_delta = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].rssi_boost_thresh = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].rssi_boost_delta = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].nfscan = htod16(atoi(*argv++));
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].fullscan_period = htod16(atoi(*argv++));
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].init_scan_period = htod16(atoi(*argv++));
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].backoff_multiplier = htod16(atoi(*argv++));
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].max_scan_period = htod16(atoi(*argv++));
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].channel_usage = htod16(atoi(*argv++));
+
+ if (!*argv) return -1;
+ rp.v2.roam_prof[i].cu_avg_calc_dur = htod16(atoi(*argv++));
+ } else {
+ if (!*argv) break;
+ rp.v1.roam_prof[i].roam_flags = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v1.roam_prof[i].roam_trigger = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v1.roam_prof[i].rssi_lower = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v1.roam_prof[i].roam_delta = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v1.roam_prof[i].rssi_boost_thresh = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v1.roam_prof[i].rssi_boost_delta = atoi(*argv++);
+
+ if (!*argv) return -1;
+ rp.v1.roam_prof[i].nfscan = htod16(atoi(*argv++));
+
+ if (!*argv) return -1;
+ rp.v1.roam_prof[i].fullscan_period = htod16(atoi(*argv++));
+
+ if (!*argv) return -1;
+ rp.v1.roam_prof[i].init_scan_period = htod16(atoi(*argv++));
+
+ if (!*argv) return -1;
+ rp.v1.roam_prof[i].backoff_multiplier = htod16(atoi(*argv++));
+
+ if (!*argv) return -1;
+ rp.v1.roam_prof[i].max_scan_period = htod16(atoi(*argv++));
+ }
+ }
+
+ if (i == 0) {
+ return -1;
+ }
+
+ if (*argv) {
+ /* too many parameters */
+ return -1;
+ }
+
+ rp.v1.len = wl_roam_prof_size * i;
+ ret = wlu_var_setbuf(wl, cmd->name, &rp, 8 + rp.v1.len);
+ }
+ return ret;
+}
+
+static int
+wl_scan(void *wl, cmd_t *cmd, char **argv)
+{
+ int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
+ wl_scan_params_t *params;
+ int err = 0;
+
+ params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
+ params = (wl_scan_params_t*)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
+ return BCME_NOMEM;
+ }
+ memset(params, 0, params_size);
+
+ err = wl_scan_prep(wl, cmd, argv, params, ¶ms_size);
+
+ if (!err) {
+ err = wlu_set(wl, cmd->set, params, params_size);
+ }
+
+ free(params);
+ return err;
+}
+
+static int
+wl_escan(void *wl, cmd_t *cmd, char **argv)
+{
+ int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)) +
+ (WL_NUMCHANNELS * sizeof(uint16));
+ wl_escan_params_t *params;
+ int err = 0;
+ uint16 action = WL_SCAN_ACTION_START;
+
+ if (!stricmp(*argv, "escan"))
+ /* start an escan */
+ action = WL_SCAN_ACTION_START;
+ else if (!stricmp(*argv, "escanabort"))
+ /* abort an escan */
+ action = WL_SCAN_ACTION_ABORT;
+ else {
+ printf("unknown escan command: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
+ params = (wl_escan_params_t*)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
+ return BCME_NOMEM;
+ }
+ memset(params, 0, params_size);
+
+ err = wl_scan_prep(wl, cmd, argv, ¶ms->params, ¶ms_size);
+
+ if (!err) {
+ params->version = htod32(ESCAN_REQ_VERSION);
+ params->action = htod16(action);
+
+#if defined(linux)
+ srand((unsigned)time(NULL));
+ params->sync_id = htod16(rand() & 0xffff);
+#else
+ params->sync_id = htod16(4321);
+#endif /* #if defined(linux) */
+
+ params_size += OFFSETOF(wl_escan_params_t, params);
+ err = wlu_iovar_setbuf(wl, "escan", params, params_size, buf, WLC_IOCTL_MAXLEN);
+ }
+
+ free(params);
+ return err;
+}
+
+static int
+wl_iscan(void *wl, cmd_t *cmd, char **argv)
+{
+ int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) +
+ (WL_NUMCHANNELS * sizeof(uint16));
+ wl_iscan_params_t *params;
+ int err = 0;
+ uint16 action = WL_SCAN_ACTION_START;
+ char **p;
+ uint16 iscan_duration = 0;
+
+ if (!stricmp(*argv, "iscan_s"))
+ action = WL_SCAN_ACTION_START;
+ else if (!stricmp(*argv, "iscan_c"))
+ action = WL_SCAN_ACTION_CONTINUE;
+ else {
+ printf("unknown iscan command: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* look for iscan_duration parameter */
+ p = argv;
+ while (*p != NULL) {
+ if (!strcmp(*p, "-d") || !strncmp(*p, "--duration=", 11)) {
+ char *valptr;
+ int val;
+ char *endptr;
+ if (!strcmp(*p, "-d"))
+ valptr = *(++p);
+ else
+ valptr = *p + 11;
+ val = (int)strtol(valptr, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "could not parse \"%s\" as an int for duration\n",
+ valptr);
+ err = -1;
+ goto exit;
+ }
+ iscan_duration = (uint16) val;
+ break;
+ }
+ ++p;
+ }
+
+ params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
+ params = (wl_iscan_params_t*)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
+ return BCME_NOMEM;
+ }
+ memset(params, 0, params_size);
+
+ err = wl_scan_prep(wl, cmd, argv, ¶ms->params, ¶ms_size);
+
+ if (!err) {
+ params->version = htod32(ISCAN_REQ_VERSION);
+ params->action = htod16(action);
+ params->scan_duration = htod16(iscan_duration);
+ params_size += OFFSETOF(wl_iscan_params_t, params);
+ err = wlu_iovar_setbuf(wl, "iscan", params, params_size, buf, WLC_IOCTL_MAXLEN);
+ }
+
+ free(params);
+exit:
+ return err;
+}
+
+static int
+wl_parse_assoc_params(char **argv, wl_assoc_params_t *params, bool *prescanned)
+{
+ int err = BCME_OK;
+ char *p, *eq, *valstr;
+ char opt;
+ bool opt_end;
+ int keylen;
+ char key[64];
+ int i;
+ bool bssid_set = FALSE;
+ bool ch_set = FALSE;
+
+ opt_end = FALSE;
+
+ while ((p = *argv) != NULL) {
+ argv++;
+ memset(key, 0, sizeof(key));
+ opt = '\0';
+ valstr = NULL;
+
+ if (opt_end) {
+ valstr = p;
+ }
+ else if (!strcmp(p, "--")) {
+ opt_end = TRUE;
+ continue;
+ }
+ else if (!strcmp(p, "prescanned")) {
+ if (prescanned)
+ *prescanned = TRUE;
+ continue;
+ }
+ else if (!strncmp(p, "--", 2)) {
+ eq = strchr(p, '=');
+ if (eq == NULL) {
+ fprintf(stderr, "wl_parse_assoc_params: missing \" = \" in "
+ "long param \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ keylen = eq - (p + 2);
+ if (keylen > 63)
+ keylen = 63;
+ memcpy(key, p + 2, keylen);
+
+ valstr = eq + 1;
+ if (*valstr == '\0') {
+ fprintf(stderr, "wl_parse_assoc_params: missing value after "
+ "\" = \" in long param \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ else if (!strncmp(p, "-", 1)) {
+ opt = p[1];
+ if (strlen(p) > 2) {
+ fprintf(stderr, "wl_parse_assoc_params: only single char options, "
+ "error on param \"%s\"\n", p);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (*argv == NULL) {
+ fprintf(stderr, "wl_parse_assoc_params: missing value parameter "
+ "after \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ valstr = *argv++;
+ } else {
+ valstr = p;
+ }
+
+ /* handle -o v or --option=val */
+ if (opt == 'b' || !stricmp(key, "bssid")) {
+ if (!wl_ether_atoe(valstr, ¶ms->bssid)) {
+ fprintf(stderr, "could not parse as an ethernet MAC address\n");
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ bssid_set = TRUE;
+ }
+ else if (opt == 'c' || !strcmp(key, "chanspecs")) {
+ params->chanspec_num =
+ wl_parse_chanspec_list(valstr, params->chanspec_list, WL_NUMCHANNELS);
+ if (params->chanspec_num == -1) {
+ fprintf(stderr, "error parsing chanspec list arg\n");
+ err = BCME_BADARG;
+ goto exit;
+ }
+ ch_set = TRUE;
+ }
+ }
+
+ if (prescanned && *prescanned && (ch_set || bssid_set)) {
+ fprintf(stderr, "cannot use bssid/channel options with prescan option\n");
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ /* prepare the chanspec using the channel number and the user provided options */
+ for (i = 0; i < params->chanspec_num; i++) {
+ chanspec_t chanspec = wl_chspec_to_driver(params->chanspec_list[i]);
+ if (chanspec == INVCHANSPEC) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ params->chanspec_list[i] = chanspec;
+ }
+ params->chanspec_num = htod32(params->chanspec_num);
+
+exit:
+ return err;
+}
+
+/* wl reassoc <bssid>
+ * Options:
+ * -c CL, --chanspecs=CL, where CL is a comma or space separated list of chanspecs
+ */
+static int
+wl_reassoc(void *wl, cmd_t *cmd, char **argv)
+{
+ int params_size = WL_REASSOC_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(chanspec_t);
+ wl_reassoc_params_t *params;
+ int err = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv == NULL) {
+ fprintf(stderr, "no arguments to wl_reassoc\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ params = (wl_reassoc_params_t *)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
+ return BCME_NOMEM;
+ }
+ memset(params, 0, params_size);
+
+ if (!wl_ether_atoe(*argv, ¶ms->bssid)) {
+ fprintf(stderr, "could not parse %s as an Ethernet MAC address\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /* default to plain old ioctl */
+ params_size = ETHER_ADDR_LEN;
+
+ if (*++argv != NULL) {
+ if ((err = wl_parse_reassoc_params(argv, params)) != BCME_OK) {
+ fprintf(stderr, "could not parse reassociation parameters\n");
+ goto exit;
+ }
+ params_size = WL_REASSOC_PARAMS_FIXED_SIZE +
+ dtoh32(params->chanspec_num) * sizeof(chanspec_t);
+ }
+
+ err = wlu_set(wl, WLC_REASSOC, params, params_size);
+
+exit:
+ free(params);
+ return err;
+}
+
+int
+wl_parse_channel_list(char* list_str, uint16* channel_list, int channel_num)
+{
+ int num;
+ int val;
+ char* str;
+ char* endptr = NULL;
+
+ if (list_str == NULL)
+ return -1;
+
+ str = list_str;
+ num = 0;
+ while (*str != '\0') {
+ val = (int)strtol(str, &endptr, 0);
+ if (endptr == str) {
+ fprintf(stderr,
+ "could not parse channel number starting at"
+ " substring \"%s\" in list:\n%s\n",
+ str, list_str);
+ return -1;
+ }
+ str = endptr + strspn(endptr, " ,");
+
+ if (num == channel_num) {
+ fprintf(stderr, "too many channels (more than %d) in channel list:\n%s\n",
+ channel_num, list_str);
+ return -1;
+ }
+
+ channel_list[num++] = (uint16)val;
+ }
+
+ return num;
+}
+
+int
+wl_parse_chanspec_list(char *list_str, chanspec_t *chanspec_list, int chanspec_num)
+{
+ int num = 0;
+ chanspec_t chanspec;
+ char *next, str[8];
+ size_t len;
+
+ if ((next = list_str) == NULL)
+ return BCME_ERROR;
+
+ while ((len = strcspn(next, " ,")) > 0) {
+ if (len >= sizeof(str)) {
+ fprintf(stderr, "string \"%s\" before ',' or ' ' is too long\n", next);
+ return BCME_ERROR;
+ }
+ strncpy(str, next, len);
+ str[len] = 0;
+ chanspec = wf_chspec_aton(str);
+ if (chanspec == 0) {
+ fprintf(stderr, "could not parse chanspec starting at "
+ "\"%s\" in list:\n%s\n", str, list_str);
+ return BCME_ERROR;
+ }
+ if (num == chanspec_num) {
+ fprintf(stderr, "too many chanspecs (more than %d) in chanspec list:\n%s\n",
+ chanspec_num, list_str);
+ return BCME_ERROR;
+ }
+ chanspec_list[num++] = chanspec;
+ next += len;
+ next += strspn(next, " ,");
+ }
+
+ return num;
+}
+
+static void bcm_print_vs_ie(uint8 *parse, int len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
+ int len_tmp = 0;
+ printf("VS_IE:");
+ printf("%02x%02x", ie->id, ie->len);
+ while (len_tmp < ie->len) {
+ printf("%02x", ie->data[len_tmp]);
+ len_tmp++;
+ }
+ printf("\n");
+
+ if ((parse = (uint8 *)bcm_next_tlv(ie, &len)) == NULL)
+ break;
+ }
+}
+
+/* channel info structure */
+typedef struct {
+ uint chan; /* channel number */
+ uint freq; /* in Mhz */
+} chan_info_t;
+
+static chan_info_t chan_info[] = {
+ /* B channels */
+ { 1, 2412},
+ { 2, 2417},
+ { 3, 2422},
+ { 4, 2427},
+ { 5, 2432},
+ { 6, 2437},
+ { 7, 2442},
+ { 8, 2447},
+ { 9, 2452},
+ { 10, 2457},
+ { 11, 2462},
+ { 12, 2467},
+ { 13, 2472},
+ { 14, 2484},
+
+ /* A channels */
+ /* 11a usa low */
+ { 36, 5180},
+ { 40, 5200},
+ { 44, 5220},
+ { 48, 5240},
+ { 52, 5260},
+ { 56, 5280},
+ { 60, 5300},
+ { 64, 5320},
+
+ /* 11a Europe */
+ { 100, 5500},
+ { 104, 5520},
+ { 108, 5540},
+ { 112, 5560},
+ { 116, 5580},
+ { 120, 5600},
+ { 124, 5620},
+ { 128, 5640},
+ { 132, 5660},
+ { 136, 5680},
+ { 140, 5700},
+ { 144, 5720},
+
+ /* 11a usa high */
+ { 149, 5745},
+ { 153, 5765},
+ { 157, 5785},
+ { 161, 5805},
+
+ /* 11a japan */
+ { 184, 4920},
+ { 188, 4940},
+ { 192, 4960},
+ { 196, 4980},
+ { 200, 5000},
+ { 204, 5020},
+ { 208, 5040},
+ { 212, 5060},
+ { 216, 5080}
+};
+
+uint
+freq2channel(uint freq)
+{
+ int i;
+
+ for (i = 0; i < (int)ARRAYSIZE(chan_info); i++) {
+ if (chan_info[i].freq == freq)
+ return (chan_info[i].chan);
+ }
+ return (0);
+}
+
+void
+dump_rateset(uint8 *rates, uint count)
+{
+ uint i;
+ uint r;
+ bool b;
+
+ printf("[ ");
+ for (i = 0; i < count; i++) {
+ r = rates[i] & 0x7f;
+ b = rates[i] & 0x80;
+ if (r == 0)
+ break;
+ printf("%d%s%s ", (r / 2), (r % 2)?".5":"", b?"(b)":"");
+ }
+ printf("]");
+}
+
+/* Helper routine to print the infrastructure mode while pretty printing the BSS list */
+static const char *
+capmode2str(uint16 capability)
+{
+ capability &= (DOT11_CAP_ESS | DOT11_CAP_IBSS);
+
+ if (capability == DOT11_CAP_ESS)
+ return "Managed";
+ else if (capability == DOT11_CAP_IBSS)
+ return "Ad Hoc";
+ else
+ return "<unknown>";
+}
+
+/*
+ * Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
+ * matches tag
+ */
+static uint8 *
+wlu_parse_tlvs(uint8 *tlv_buf, int buflen, uint key)
+{
+ uint8 *cp;
+ int totlen;
+
+ cp = tlv_buf;
+ totlen = buflen;
+
+ /* find tagged parameter */
+ while (totlen >= 2) {
+ uint tag;
+ int len;
+
+ tag = *cp;
+ len = *(cp +1);
+
+ /* validate remaining totlen */
+ if ((tag == key) && (totlen >= (len + 2)))
+ return (cp);
+
+ cp += (len + 2);
+ totlen -= (len + 2);
+ }
+
+ return NULL;
+}
+
+static int
+wlu_bcmp(const void *b1, const void *b2, int len)
+{
+ return (memcmp(b1, b2, len));
+}
+
+/* Is this body of this tlvs entry a WPA entry? If */
+/* not update the tlvs buffer pointer/length */
+static bool
+wlu_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, uint *tlvs_len)
+{
+ uint8 *ie = *wpaie;
+
+ /* If the contents match the WPA_OUI and type=1 */
+ if ((ie[1] >= 6) && !wlu_bcmp(&ie[2], WPA_OUI "\x01", 4)) {
+ return TRUE;
+ }
+
+ /* point to the next ie */
+ ie += ie[1] + 2;
+ /* calculate the length of the rest of the buffer */
+ *tlvs_len -= (int)(ie - *tlvs);
+ /* update the pointer to the start of the buffer */
+ *tlvs = ie;
+
+ return FALSE;
+}
+
+static void
+wl_dump_wpa_rsn_ies(uint8* cp, uint len)
+{
+ uint8 *parse = cp;
+ uint parse_len = len;
+ uint8 *wpaie;
+ uint8 *rsnie;
+
+ while ((wpaie = wlu_parse_tlvs(parse, parse_len, DOT11_MNG_WPA_ID)))
+ if (wlu_is_wpa_ie(&wpaie, &parse, &parse_len))
+ break;
+ if (wpaie)
+ wl_rsn_ie_dump((bcm_tlv_t*)wpaie);
+
+ rsnie = wlu_parse_tlvs(cp, len, DOT11_MNG_RSN_ID);
+ if (rsnie)
+ wl_rsn_ie_dump((bcm_tlv_t*)rsnie);
+
+ return;
+}
+
+static void
+wl_rsn_ie_dump(bcm_tlv_t *ie)
+{
+ int i;
+ int rsn;
+ wpa_ie_fixed_t *wpa = NULL;
+ rsn_parse_info_t rsn_info;
+ wpa_suite_t *suite;
+ uint8 std_oui[3];
+ int unicast_count = 0;
+ int akm_count = 0;
+ uint16 capabilities;
+ uint cntrs;
+ int err;
+
+ if (ie->id == DOT11_MNG_RSN_ID) {
+ rsn = TRUE;
+ memcpy(std_oui, WPA2_OUI, WPA_OUI_LEN);
+ err = wl_rsn_ie_parse_info(ie->data, ie->len, &rsn_info);
+ } else {
+ rsn = FALSE;
+ memcpy(std_oui, WPA_OUI, WPA_OUI_LEN);
+ wpa = (wpa_ie_fixed_t*)ie;
+ err = wl_rsn_ie_parse_info((uint8*)&wpa->version, wpa->length - WPA_IE_OUITYPE_LEN,
+ &rsn_info);
+ }
+ if (err || rsn_info.version != WPA_VERSION)
+ return;
+
+ if (rsn)
+ printf("RSN (WPA2):\n");
+ else
+ printf("WPA:\n");
+
+ /* Check for multicast suite */
+ if (rsn_info.mcast) {
+ printf("\tmulticast cipher: ");
+ if (!wlu_bcmp(rsn_info.mcast->oui, std_oui, 3)) {
+ switch (rsn_info.mcast->type) {
+ case WPA_CIPHER_NONE:
+ printf("NONE\n");
+ break;
+ case WPA_CIPHER_WEP_40:
+ printf("WEP64\n");
+ break;
+ case WPA_CIPHER_WEP_104:
+ printf("WEP128\n");
+ break;
+ case WPA_CIPHER_TKIP:
+ printf("TKIP\n");
+ break;
+ case WPA_CIPHER_AES_OCB:
+ printf("AES-OCB\n");
+ break;
+ case WPA_CIPHER_AES_CCM:
+ printf("AES-CCMP\n");
+ break;
+ default:
+ printf("Unknown-%s(#%d)\n", rsn ? "RSN" : "WPA",
+ rsn_info.mcast->type);
+ break;
+ }
+ }
+ else {
+ printf("Unknown-%02X:%02X:%02X(#%d) ",
+ rsn_info.mcast->oui[0], rsn_info.mcast->oui[1],
+ rsn_info.mcast->oui[2], rsn_info.mcast->type);
+ }
+ }
+
+ /* Check for unicast suite(s) */
+ if (rsn_info.ucast) {
+ unicast_count = ltoh16_ua(&rsn_info.ucast->count);
+ printf("\tunicast ciphers(%d): ", unicast_count);
+ for (i = 0; i < unicast_count; i++) {
+ suite = &rsn_info.ucast->list[i];
+ if (!wlu_bcmp(suite->oui, std_oui, 3)) {
+ switch (suite->type) {
+ case WPA_CIPHER_NONE:
+ printf("NONE ");
+ break;
+ case WPA_CIPHER_WEP_40:
+ printf("WEP64 ");
+ break;
+ case WPA_CIPHER_WEP_104:
+ printf("WEP128 ");
+ break;
+ case WPA_CIPHER_TKIP:
+ printf("TKIP ");
+ break;
+ case WPA_CIPHER_AES_OCB:
+ printf("AES-OCB ");
+ break;
+ case WPA_CIPHER_AES_CCM:
+ printf("AES-CCMP ");
+ break;
+ default:
+ printf("WPA-Unknown-%s(#%d) ", rsn ? "RSN" : "WPA",
+ suite->type);
+ break;
+ }
+ }
+ else {
+ printf("Unknown-%02X:%02X:%02X(#%d) ",
+ suite->oui[0], suite->oui[1], suite->oui[2],
+ suite->type);
+ }
+ }
+ printf("\n");
+ }
+ /* Authentication Key Management */
+ if (rsn_info.akm) {
+ akm_count = ltoh16_ua(&rsn_info.akm->count);
+ printf("\tAKM Suites(%d): ", akm_count);
+ for (i = 0; i < akm_count; i++) {
+ suite = &rsn_info.akm->list[i];
+ if (!wlu_bcmp(suite->oui, std_oui, 3)) {
+ switch (suite->type) {
+ case RSN_AKM_NONE:
+ printf("None ");
+ break;
+ case RSN_AKM_UNSPECIFIED:
+ printf("%s ", rsn ? "WPA2" : "WPA");
+ break;
+ case RSN_AKM_PSK:
+ printf("%s ", rsn ? "WPA2-PSK" : "WPA-PSK");
+ break;
+ case RSN_AKM_FBT_1X:
+ printf("FT-802.1x ");
+ break;
+ case RSN_AKM_FBT_PSK:
+ printf("FT-PSK ");
+ break;
+ default:
+ printf("Unknown-%s(#%d) ",
+ rsn ? "RSN" : "WPA", suite->type);
+ break;
+ }
+ }
+ else {
+ printf("Unknown-%02X:%02X:%02X(#%d) ",
+ suite->oui[0], suite->oui[1], suite->oui[2],
+ suite->type);
+ }
+ }
+ printf("\n");
+ }
+
+ /* Capabilities */
+ if (rsn_info.capabilities) {
+ capabilities = ltoh16_ua(rsn_info.capabilities);
+ printf("\tCapabilities(0x%04x): ", capabilities);
+ if (rsn)
+ printf("%sPre-Auth, ", (capabilities & RSN_CAP_PREAUTH) ? "" : "No ");
+
+ printf("%sPairwise, ", (capabilities & RSN_CAP_NOPAIRWISE) ? "No " : "");
+
+ cntrs = wl_rsn_ie_decode_cntrs((capabilities & RSN_CAP_PTK_REPLAY_CNTR_MASK) >>
+ RSN_CAP_PTK_REPLAY_CNTR_SHIFT);
+
+ printf("%d PTK Replay Ctr%s", cntrs, (cntrs > 1)?"s":"");
+
+ if (rsn) {
+ cntrs = wl_rsn_ie_decode_cntrs(
+ (capabilities & RSN_CAP_GTK_REPLAY_CNTR_MASK) >>
+ RSN_CAP_GTK_REPLAY_CNTR_SHIFT);
+
+ printf("%d GTK Replay Ctr%s\n", cntrs, (cntrs > 1)?"s":"");
+ } else {
+ printf("\n");
+ }
+ } else {
+ printf("\tNo %s Capabilities advertised\n", rsn ? "RSN" : "WPA");
+ }
+
+}
+
+/* Validates and parses the RSN or WPA IE contents into a rsn_parse_info_t structure
+ * Returns 0 on success, or 1 if the information in the buffer is not consistant with
+ * an RSN IE or WPA IE.
+ * The buf pointer passed in should be pointing at the version field in either an RSN IE
+ * or WPA IE.
+ */
+static int
+wl_rsn_ie_parse_info(uint8* rsn_buf, uint len, rsn_parse_info_t *rsn)
+{
+ uint16 count;
+
+ memset(rsn, 0, sizeof(rsn_parse_info_t));
+
+ /* version */
+ if (len < sizeof(uint16))
+ return 1;
+
+ rsn->version = ltoh16_ua(rsn_buf);
+ len -= sizeof(uint16);
+ rsn_buf += sizeof(uint16);
+
+ /* Multicast Suite */
+ if (len < sizeof(wpa_suite_mcast_t))
+ return 0;
+
+ rsn->mcast = (wpa_suite_mcast_t*)rsn_buf;
+ len -= sizeof(wpa_suite_mcast_t);
+ rsn_buf += sizeof(wpa_suite_mcast_t);
+
+ /* Unicast Suite */
+ if (len < sizeof(uint16))
+ return 0;
+
+ count = ltoh16_ua(rsn_buf);
+
+ if (len < (sizeof(uint16) + count * sizeof(wpa_suite_t)))
+ return 1;
+
+ rsn->ucast = (wpa_suite_ucast_t*)rsn_buf;
+ len -= (sizeof(uint16) + count * sizeof(wpa_suite_t));
+ rsn_buf += (sizeof(uint16) + count * sizeof(wpa_suite_t));
+
+ /* AKM Suite */
+ if (len < sizeof(uint16))
+ return 0;
+
+ count = ltoh16_ua(rsn_buf);
+
+ if (len < (sizeof(uint16) + count * sizeof(wpa_suite_t)))
+ return 1;
+
+ rsn->akm = (wpa_suite_auth_key_mgmt_t*)rsn_buf;
+ len -= (sizeof(uint16) + count * sizeof(wpa_suite_t));
+ rsn_buf += (sizeof(uint16) + count * sizeof(wpa_suite_t));
+
+ /* Capabilites */
+ if (len < sizeof(uint16))
+ return 0;
+
+ rsn->capabilities = rsn_buf;
+
+ return 0;
+}
+
+static uint
+wl_rsn_ie_decode_cntrs(uint cntr_field)
+{
+ uint cntrs;
+
+ switch (cntr_field) {
+ case RSN_CAP_1_REPLAY_CNTR:
+ cntrs = 1;
+ break;
+ case RSN_CAP_2_REPLAY_CNTRS:
+ cntrs = 2;
+ break;
+ case RSN_CAP_4_REPLAY_CNTRS:
+ cntrs = 4;
+ break;
+ case RSN_CAP_16_REPLAY_CNTRS:
+ cntrs = 16;
+ break;
+ default:
+ cntrs = 0;
+ break;
+ }
+
+ return cntrs;
+}
+
+
+void
+wl_dump_raw_ie(bcm_tlv_t *ie, uint len)
+{
+ uint dump_len;
+
+ if (len == 0) {
+ return;
+ } else if (len == 1) {
+ printf("IE header truncated: ID: 0x%02X\n", ie->id);
+ return;
+ } else if (len < (uint)(ie->len + TLV_HDR_LEN)) {
+ printf("IE data truncated: ID: 0x%02X Len: %d\n", ie->id, ie->len);
+ dump_len = len - TLV_HDR_LEN;
+ } else {
+ printf("ID: 0x%02X Len: %d\n", ie->id, ie->len);
+ dump_len = ie->len;
+ }
+
+ /* choose how to format the data based on data len */
+ if (dump_len > 16)
+ printf("Data:\n");
+ else if (dump_len > 0)
+ printf("Data: ");
+
+ if (dump_len > 0)
+ wl_hexdump(ie->data, dump_len);
+
+ if (dump_len < ie->len)
+ printf("<missing %d bytes>\n", ie->len - dump_len);
+
+ return;
+}
+
+
+/* Pretty print the BSS list */
+static void
+dump_networks(char *network_buf)
+{
+ wl_scan_results_t *list = (wl_scan_results_t*)network_buf;
+ wl_bss_info_t *bi;
+ uint i;
+
+ if (list->count == 0)
+ return;
+ else if (list->version != WL_BSS_INFO_VERSION &&
+ list->version != LEGACY2_WL_BSS_INFO_VERSION &&
+ list->version != LEGACY_WL_BSS_INFO_VERSION) {
+ fprintf(stderr, "Sorry, your driver has bss_info_version %d "
+ "but this program supports only version %d.\n",
+ list->version, WL_BSS_INFO_VERSION);
+ return;
+ }
+
+ bi = list->bss_info;
+ for (i = 0; i < list->count; i++, bi = (wl_bss_info_t*)((int8*)bi + dtoh32(bi->length))) {
+ dump_bss_info(bi);
+ }
+}
+
+static void
+bcm_wps_version(uint8 *wps_ie)
+{
+ uint16 wps_len;
+ uint16 wps_off, wps_suboff;
+ uint16 wps_key;
+ uint8 wps_field_len;
+
+ wps_len = (uint16)*(wps_ie+TLV_LEN_OFF); /* Get the length of the WPS OUI header */
+ wps_off = WPS_OUI_FIXED_HEADER_OFF; /* Skip the fixed headers */
+ wps_field_len = 1;
+
+ /* Parsing the OUI header looking for version number */
+ while ((wps_len >= wps_off + 2) && (wps_field_len))
+ {
+ wps_key = (((uint8)wps_ie[wps_off]*256) + (uint8)wps_ie[wps_off+1]);
+ if (wps_key == WPS_ID_VENDOR_EXT) {
+ /* Key found */
+ wps_suboff = wps_off + WPS_OUI_HEADER_SIZE;
+
+ /* Looking for the Vendor extension code 0x00 0x37 0x2A
+ * and the Version 2 sudId 0x00
+ * if found then the next byte is the len of field which is always 1
+ * for version field the byte after is the version number
+ */
+ if (!wlu_bcmp(&wps_ie[wps_suboff], WFA_VENDOR_EXT_ID, WPS_OUI_LEN)&&
+ (wps_ie[wps_suboff+WPS_WFA_SUBID_V2_OFF] == WPS_WFA_SUBID_VERSION2))
+ {
+ printf("V%d.%d ", (wps_ie[wps_suboff+WPS_WFA_V2_OFF]>>4),
+ (wps_ie[wps_suboff+WPS_WFA_V2_OFF] & 0x0f));
+ return;
+ }
+ }
+ /* Jump to next field */
+ wps_field_len = wps_ie[wps_off+WPS_OUI_HEADER_LEN+1];
+ wps_off += WPS_OUI_HEADER_SIZE + wps_field_len;
+ }
+
+ /* If nothing found from the parser then this is the WPS version 1.0 */
+ printf("V1.0 ");
+}
+
+static void
+bcm_is_wps_configured(uint8 *wps_ie)
+{
+ /* Before calling this function the test of WPS_OUI type 4 should be already done
+ * If the contents match the WPS_OUI_SC_STATE
+ */
+ uint16 wps_key;
+ wps_key = (wps_ie[WPS_SCSTATE_OFF]*256) + wps_ie[WPS_SCSTATE_OFF+1];
+ if ((wps_ie[TLV_LEN_OFF] > (WPS_SCSTATE_OFF+5))&&
+ (wps_key == WPS_ID_SC_STATE))
+ {
+ switch (wps_ie[WPS_SCSTATE_OFF+WPS_OUI_HEADER_SIZE])
+ {
+ case WPS_SCSTATE_UNCONFIGURED:
+ printf("Unconfigured\n");
+ break;
+ case WPS_SCSTATE_CONFIGURED:
+ printf("Configured\n");
+ break;
+ default:
+ printf("Unknown State\n");
+ }
+ }
+}
+
+/* Looking for WPS OUI in the propriatary_ie */
+static bool
+bcm_is_wps_ie(uint8 *ie, uint8 **tlvs, uint32 *tlvs_len)
+{
+ bool retval = FALSE;
+ /* If the contents match the WPS_OUI and type=4 */
+ if ((ie[TLV_LEN_OFF] > (WPS_OUI_LEN+1)) &&
+ !wlu_bcmp(&ie[TLV_BODY_OFF], WPS_OUI "\x04", WPS_OUI_LEN + 1)) {
+ retval = TRUE;
+ }
+
+ /* point to the next ie */
+ ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
+ /* calculate the length of the rest of the buffer */
+ *tlvs_len -= (int)(ie - *tlvs);
+ /* update the pointer to the start of the buffer */
+ *tlvs = ie;
+
+ return retval;
+}
+
+static void
+wl_dump_wps(uint8* cp, uint len)
+{
+ uint8 *parse = cp;
+ uint32 parse_len = len;
+ uint8 *proprietary_ie;
+
+ while ((proprietary_ie = wlu_parse_tlvs(parse, parse_len, DOT11_MNG_WPA_ID))) {
+ if (bcm_is_wps_ie(proprietary_ie, &parse, &parse_len)) {
+ /* Print WPS status */
+ printf("WPS: ");
+ /* Print the version get from vendor extension field */
+ bcm_wps_version(proprietary_ie);
+ /* Print the WPS configure or Unconfigure option */
+ bcm_is_wps_configured(proprietary_ie);
+ break;
+ }
+ }
+}
+
+/* vendor specific TLV match */
+static bool bcm_vs_ie_match(uint8 *ie, uint8 *oui, int oui_len, uint8 type)
+{
+ /* If the contents match the OUI and the type */
+ if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
+ !wlu_bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
+ type == ie[TLV_BODY_OFF + oui_len]) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static bcm_tlv_t *bcm_find_vs_ie(uint8 *parse, int len,
+ uint8 *oui, uint8 oui_len, uint8 oui_type)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
+ if (bcm_vs_ie_match((uint8 *)ie, oui, oui_len, oui_type))
+ return ie;
+ if ((ie = bcm_next_tlv(ie, &len)) == NULL)
+ break;
+ }
+ return NULL;
+}
+
+static void
+wl_dump_ext_cap(uint8* cp, uint len)
+{
+ uint8 *parse = cp;
+ uint parse_len = len;
+ uint8 *ext_cap_ie;
+
+ if ((ext_cap_ie = wlu_parse_tlvs(parse, parse_len, DOT11_MNG_EXT_CAP_ID))) {
+ wl_ext_cap_ie_dump((bcm_tlv_t*)ext_cap_ie);
+ } else
+ printf("Extended Capabilities: Not_Available\n");
+
+}
+
+static void
+wl_ext_cap_ie_dump(bcm_tlv_t* ext_cap_ie)
+{
+
+ printf("Extended Capabilities: ");
+
+ if (ext_cap_ie->len >= CEIL(DOT11_EXT_CAP_IW, NBBY)) {
+ /* check IW bit */
+ if (isset(ext_cap_ie->data, DOT11_EXT_CAP_IW))
+ printf("IW ");
+ }
+
+ if (ext_cap_ie->len >= CEIL(DOT11_EXT_CAP_CIVIC_LOC, NBBY)) {
+ /* check Civic Location bit */
+ if (isset(ext_cap_ie->data, DOT11_EXT_CAP_CIVIC_LOC))
+ printf("Civic_Location ");
+ }
+
+ if (ext_cap_ie->len >= CEIL(DOT11_EXT_CAP_LCI, NBBY)) {
+ /* check Geospatial Location bit */
+ if (isset(ext_cap_ie->data, DOT11_EXT_CAP_LCI))
+ printf("Geospatial_Location ");
+ }
+
+ if (ext_cap_ie->len > 0) {
+ /* check 20/40 BSS Coexistence Management support bit */
+ if (isset(ext_cap_ie->data, DOT11_EXT_CAP_OBSS_COEX_MGMT))
+ printf("20/40_Bss_Coexist ");
+ }
+
+ if (ext_cap_ie->len >= CEIL(DOT11_EXT_CAP_BSSTRANS_MGMT, NBBY)) {
+ /* check BSS Transition Management support bit */
+ if (isset(ext_cap_ie->data, DOT11_EXT_CAP_BSSTRANS_MGMT))
+ printf("BSS_Transition");
+ }
+
+ printf("\n");
+}
+
+void
+dump_bss_info(wl_bss_info_t *bi)
+{
+ char ssidbuf[SSID_FMT_BUF_LEN];
+ char chspec_str[CHANSPEC_STR_LEN];
+ wl_bss_info_107_t *old_bi;
+ int mcs_idx = 0, start_idx = 0;
+ bool start_idx_valid = FALSE;
+ uint16 capability;
+
+ /* Convert version 107 to 109 */
+ if (dtoh32(bi->version) == LEGACY_WL_BSS_INFO_VERSION) {
+ old_bi = (wl_bss_info_107_t *)bi;
+ bi->chanspec = CH20MHZ_CHSPEC(old_bi->channel);
+ bi->ie_length = old_bi->ie_length;
+ bi->ie_offset = sizeof(wl_bss_info_107_t);
+ } else {
+ /* do endian swap and format conversion for chanspec if we have
+ * not created it from legacy bi above
+ */
+ bi->chanspec = wl_chspec_from_driver(bi->chanspec);
+ }
+
+ wl_format_ssid(ssidbuf, bi->SSID, bi->SSID_len);
+
+ printf("SSID: \"%s\"\n", ssidbuf);
+
+ printf("Mode: %s\t", capmode2str(dtoh16(bi->capability)));
+ printf("RSSI: %d dBm\t", (int16)(dtoh16(bi->RSSI)));
+
+ /*
+ * SNR has valid value in only 109 version.
+ * So print SNR for 109 version only.
+ */
+ if (dtoh32(bi->version) == WL_BSS_INFO_VERSION) {
+ printf("SNR: %d dB\t", (int16)(dtoh16(bi->SNR)));
+ }
+
+ printf("noise: %d dBm\t", bi->phy_noise);
+ if (bi->flags) {
+ uint16 flags = dtoh16(bi->flags);
+ printf("Flags: ");
+ if (flags & WL_BSS_FLAGS_FROM_BEACON)
+ printf("FromBcn ");
+ if (flags & WL_BSS_FLAGS_FROM_CACHE)
+ printf("Cached ");
+ if (flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)
+ printf("RSSI on-channel ");
+ printf("\t");
+ }
+ printf("Channel: %s\n", wf_chspec_ntoa(bi->chanspec, chspec_str));
+
+ printf("BSSID: %s\t", wl_ether_etoa(&bi->BSSID));
+
+ printf("Capability: ");
+ capability = dtoh16(bi->capability);
+ if (capability & DOT11_CAP_ESS)
+ printf("ESS ");
+ if (capability & DOT11_CAP_IBSS)
+ printf("IBSS ");
+ if (capability & DOT11_CAP_POLLABLE)
+ printf("Pollable ");
+ if (capability & DOT11_CAP_POLL_RQ)
+ printf("PollReq ");
+ if (capability & DOT11_CAP_PRIVACY)
+ printf("WEP ");
+ if (capability & DOT11_CAP_SHORT)
+ printf("ShortPre ");
+ if (capability & DOT11_CAP_PBCC)
+ printf("PBCC ");
+ if (capability & DOT11_CAP_AGILITY)
+ printf("Agility ");
+ if (capability & DOT11_CAP_SHORTSLOT)
+ printf("ShortSlot ");
+ if (capability & DOT11_CAP_RRM)
+ printf("RRM ");
+ if (capability & DOT11_CAP_CCK_OFDM)
+ printf("CCK-OFDM ");
+ printf("\n");
+
+ printf("Supported Rates: ");
+ dump_rateset(bi->rateset.rates, dtoh32(bi->rateset.count));
+ printf("\n");
+ if (dtoh32(bi->ie_length)) {
+ wl_dump_wpa_rsn_ies((uint8 *)(((uint8 *)bi) + dtoh16(bi->ie_offset)),
+ dtoh32(bi->ie_length));
+
+ wl_dump_ext_cap((uint8 *)(((uint8 *)bi) + dtoh16(bi->ie_offset)),
+ dtoh32(bi->ie_length));
+
+ }
+
+ if (dtoh32(bi->version) != LEGACY_WL_BSS_INFO_VERSION && bi->n_cap) {
+ if (bi->vht_cap)
+ printf("VHT Capable:\n");
+ else
+ printf("HT Capable:\n");
+ if (CHSPEC_IS8080(bi->chanspec)) {
+ printf("\tChanspec: 5GHz channel %d-%d 80+80MHz (0x%x)\n",
+ wf_chspec_primary80_channel(bi->chanspec),
+ wf_chspec_secondary80_channel(bi->chanspec),
+ bi->chanspec);
+ }
+ else {
+ printf("\tChanspec: %sGHz channel %d %dMHz (0x%x)\n",
+ CHSPEC_IS2G(bi->chanspec)?"2.4":"5", CHSPEC_CHANNEL(bi->chanspec),
+ (CHSPEC_IS160(bi->chanspec) ?
+ 160:(CHSPEC_IS80(bi->chanspec) ?
+ 80 : (CHSPEC_IS40(bi->chanspec) ?
+ 40 : (CHSPEC_IS20(bi->chanspec) ? 20 : 10)))),
+ bi->chanspec);
+ }
+ printf("\tPrimary channel: %d\n", bi->ctl_ch);
+ printf("\tHT Capabilities: ");
+ if (dtoh32(bi->nbss_cap) & HT_CAP_40MHZ)
+ printf("40Mhz ");
+ if (dtoh32(bi->nbss_cap) & HT_CAP_SHORT_GI_20)
+ printf("SGI20 ");
+ if (dtoh32(bi->nbss_cap) & HT_CAP_SHORT_GI_40)
+ printf("SGI40 ");
+ printf("\n\tSupported HT MCS :");
+ for (mcs_idx = 0; mcs_idx < (MCSSET_LEN * 8); mcs_idx++) {
+ if (isset(bi->basic_mcs, mcs_idx) && !start_idx_valid) {
+ printf(" %d", mcs_idx);
+ start_idx = mcs_idx;
+ start_idx_valid = TRUE;
+ }
+
+ if (!isset(bi->basic_mcs, mcs_idx) && start_idx_valid) {
+ if ((mcs_idx - start_idx) > 1)
+ printf("-%d", (mcs_idx - 1));
+ start_idx_valid = FALSE;
+
+ }
+ }
+ printf("\n");
+
+ if (bi->vht_cap) {
+ int i;
+ uint mcs, rx_mcs, prop_mcs = VHT_PROP_MCS_MAP_NONE;
+ char *mcs_str, *rx_mcs_str;
+
+ if (bi->vht_mcsmap) {
+ printf("\tNegotiated VHT MCS:\n");
+ for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
+ mcs = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_mcsmap));
+
+ /* roundup to be in sync with driver
+ * wlc_bss2wl_bss().
+ */
+ if (dtoh16(bi->length) >= (OFFSETOF(wl_bss_info_t,
+ vht_mcsmap_prop) +
+ ROUNDUP(dtoh32(bi->ie_length), 4) +
+ sizeof(uint16))) {
+ prop_mcs = VHT_MCS_MAP_GET_MCS_PER_SS(i,
+ dtoh16(bi->vht_mcsmap_prop));
+ }
+ mcs_str =
+ (mcs == VHT_CAP_MCS_MAP_0_9 ? "0-9 " :
+ (mcs == VHT_CAP_MCS_MAP_0_8 ? "0-8 " :
+ (mcs == VHT_CAP_MCS_MAP_0_7 ? "0-7 " :
+ " -- ")));
+ if (prop_mcs != VHT_PROP_MCS_MAP_NONE)
+ mcs_str =
+ (mcs == VHT_CAP_MCS_MAP_0_9 ? "0-11 " :
+ (mcs == VHT_CAP_MCS_MAP_0_8 ? "0-8, 10-11" :
+ (mcs == VHT_CAP_MCS_MAP_0_7 ? "0-7, 10-11" :
+ " -- ")));
+
+ if (mcs != VHT_CAP_MCS_MAP_NONE) {
+ printf("\t\tNSS%d : %s \n", i,
+ mcs_str);
+ }
+ }
+ } else {
+ printf("\tSupported VHT MCS:\n");
+ for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
+ mcs = VHT_MCS_MAP_GET_MCS_PER_SS(i,
+ dtoh16(bi->vht_txmcsmap));
+
+ rx_mcs = VHT_MCS_MAP_GET_MCS_PER_SS(i,
+ dtoh16(bi->vht_rxmcsmap));
+
+ /* roundup to be in sync with driver
+ * wlc_bss2wl_bss().
+ */
+ if (dtoh16(bi->length) >= (OFFSETOF(wl_bss_info_t,
+ vht_txmcsmap_prop) +
+ ROUNDUP(dtoh32(bi->ie_length), 4) +
+ sizeof(uint16))) {
+ prop_mcs = VHT_MCS_MAP_GET_MCS_PER_SS(i,
+ dtoh16(bi->vht_txmcsmap_prop));
+ }
+
+ mcs_str =
+ (mcs == VHT_CAP_MCS_MAP_0_9 ? "0-9 " :
+ (mcs == VHT_CAP_MCS_MAP_0_8 ? "0-8 " :
+ (mcs == VHT_CAP_MCS_MAP_0_7 ? "0-7 " : " -- ")));
+ if (prop_mcs != VHT_PROP_MCS_MAP_NONE)
+ mcs_str =
+ (mcs == VHT_CAP_MCS_MAP_0_9 ? "0-11 " :
+ (mcs == VHT_CAP_MCS_MAP_0_8 ? "0-8, 10-11" :
+ (mcs == VHT_CAP_MCS_MAP_0_7 ? "0-7, 10-11" :
+ " -- ")));
+
+ rx_mcs_str =
+ (rx_mcs == VHT_CAP_MCS_MAP_0_9 ? "0-9 " :
+ (rx_mcs == VHT_CAP_MCS_MAP_0_8 ? "0-8 " :
+ (rx_mcs == VHT_CAP_MCS_MAP_0_7 ? "0-7 " : " -- ")));
+ if (prop_mcs != VHT_PROP_MCS_MAP_NONE)
+ rx_mcs_str =
+ (rx_mcs == VHT_CAP_MCS_MAP_0_9 ? "0-11 " :
+ (rx_mcs == VHT_CAP_MCS_MAP_0_8 ? "0-8, 10-11" :
+ (rx_mcs == VHT_CAP_MCS_MAP_0_7 ? "0-7, 10-11" :
+ " -- ")));
+
+ if ((mcs != VHT_CAP_MCS_MAP_NONE) ||
+ (rx_mcs != VHT_CAP_MCS_MAP_NONE)) {
+ printf("\t\tNSS%d Tx: %s Rx: %s\n", i,
+ mcs_str, rx_mcs_str);
+ }
+ }
+ }
+ }
+ bi->chanspec = wl_chspec_to_driver(bi->chanspec);
+ }
+
+ if (dtoh32(bi->ie_length))
+ {
+ wl_dump_wps((uint8 *)(((uint8 *)bi) + dtoh16(bi->ie_offset)),
+ dtoh32(bi->ie_length));
+ }
+
+ if (dtoh16(bi->flags) & WL_BSS_FLAGS_HS20) {
+ printf("Hotspot 2.0 capable\n");
+ }
+
+ if (bcm_find_vs_ie((uint8 *)(((uint8 *)bi) + dtoh16(bi->ie_offset)),
+ dtoh32(bi->ie_length),
+ (uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_OSEN) != NULL) {
+ printf("OSEN supported\n");
+ }
+ bcm_print_vs_ie((uint8 *)(((uint8 *)bi) + dtoh16(bi->ie_offset)),
+ dtoh32(bi->ie_length));
+
+ printf("\n");
+}
+
+static int
+wl_bcnlenhist(void *wl, cmd_t *cmd, char **argv)
+{
+ wlc_bcn_len_hist_t *bcnlenhist = NULL;
+ uint32 *bcns_len = NULL;
+ char* dump_buf = NULL;
+ uint32 counter = 0;
+ int index = 0;
+ int err = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ dump_buf = malloc(WLC_IOCTL_SMLEN);
+ if (dump_buf == NULL) {
+ fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WLC_IOCTL_SMLEN);
+ return -1;
+ }
+ memset(dump_buf, 0, WLC_IOCTL_SMLEN);
+
+ if (argv[1])
+ err = wlu_iovar_getbuf(wl, "bcnlenhist", argv[1], 1, dump_buf, WLC_IOCTL_SMLEN);
+ else
+ err = wlu_iovar_getbuf(wl, "bcnlenhist", NULL, 0, dump_buf, WLC_IOCTL_SMLEN);
+
+ if (BCME_OK == err) {
+ bcnlenhist = (wlc_bcn_len_hist_t *)dump_buf;
+
+ index = bcnlenhist->cur_index;
+ counter = bcnlenhist->ringbuff_len;
+ bcns_len = bcnlenhist->bcnlen_ring;
+
+ index--;
+ printf("LAST %d BEACON LENGTH's: ", counter);
+ for (; counter--; index--) {
+ if (index < 0)
+ index = bcnlenhist->ringbuff_len - 1;
+ printf("%d ", bcns_len[index]);
+ }
+
+ printf("\nMAX BCNLEN: %d\n", bcnlenhist->max_bcnlen);
+
+ if (bcnlenhist->min_bcnlen == (int)0x7fffffff)
+ printf("MIN BCNLEN: 0\n\n");
+ else
+ printf("MIN BCNLEN: %d\n\n", bcnlenhist->min_bcnlen);
+ }
+
+ free(dump_buf);
+
+ return err;
+}
+
+static int
+wl_dump_networks(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ char *dump_buf, *dump_buf_orig;
+ uint32 status = 0;
+ bool iscan = FALSE;
+
+ dump_buf_orig = dump_buf = malloc(WL_DUMP_BUF_LEN);
+ if (dump_buf == NULL) {
+ fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WL_DUMP_BUF_LEN);
+ return BCME_NOMEM;
+ }
+
+ iscan = (cmd->get != WLC_SCAN_RESULTS);
+ if (iscan) {
+ int buflen = 1920; /* usually fits about 10 BSS infos */
+
+ if (*(++argv)) {
+ char *endptr = NULL;
+ buflen = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ ret = wl_get_iscan(wl, dump_buf, buflen);
+ } else
+ ret = wl_get_scan(wl, WLC_SCAN_RESULTS, dump_buf, WL_DUMP_BUF_LEN);
+
+ if (ret == 0) {
+ if (iscan) {
+ status = dtoh32(((wl_iscan_results_t *)dump_buf)->status);
+ dump_buf += OFFSETOF(wl_iscan_results_t, results);
+ }
+ dump_networks(dump_buf);
+ if (iscan) {
+ switch (status) {
+ case WL_SCAN_RESULTS_PARTIAL:
+ printf("iscanresults incomplete\n");
+ break;
+ case WL_SCAN_RESULTS_SUCCESS:
+ printf("iscanresults complete\n");
+ break;
+ case WL_SCAN_RESULTS_PENDING:
+ printf("iscanresults pending\n");
+ break;
+ case WL_SCAN_RESULTS_ABORTED:
+ printf("iscanresults aborted\n");
+ break;
+ default:
+ printf("iscanresults returned unknown status %d\n", status);
+ break;
+ }
+ }
+ }
+
+exit:
+ free(dump_buf_orig);
+ return ret;
+}
+
+static int
+wl_dump_chanlist(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 chan_buf[WL_NUMCHANNELS + 1];
+ wl_uint32_list_t *list;
+ int ret;
+ uint i;
+
+ UNUSED_PARAMETER(argv);
+
+ list = (wl_uint32_list_t *)(void *)chan_buf;
+ list->count = htod32(WL_NUMCHANNELS);
+ ret = wlu_get(wl, cmd->get, chan_buf, sizeof(chan_buf));
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < dtoh32(list->count); i++)
+ printf("%d ", dtoh32(list->element[i]));
+ printf("\n");
+ return ret;
+}
+
+/* Dump chanspecs based on the driver's current configuration of band, band-width & locale. */
+static int
+wl_dump_chanspecs_defset(void *wl, cmd_t *cmd, char **argv)
+{
+ const char* fn_name = "wl_dump_chanspecs_defset";
+ wl_uint32_list_t *list;
+ int ret, buflen;
+ chanspec_t c = 0;
+ uint i;
+ int err;
+ int num_chanspecs = 0;
+ char chspec_str[CHANSPEC_STR_LEN];
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+
+ strcpy(buf, "chanspecs_defset");
+ buflen = strlen(buf) + 1;
+
+ /* toss the command name */
+ argv++;
+
+ /* Validate arguments if any */
+ if (*argv) {
+ fprintf(stderr,
+ "%s: This IOVAR doesn't take any arguments.\n", fn_name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ num_chanspecs += NUM_CHANSPECS_LIST_SIZE;
+
+ /* Add list */
+ list = (wl_uint32_list_t *)(buf + buflen);
+ list->count = htod32(num_chanspecs);
+ buflen += sizeof(uint32)*(num_chanspecs + 1);
+
+ /* if buflen is greater then WLC_IOCTL_MAXLEN return error */
+ ret = BCME_IOCTL_ERROR;
+ while (buflen <= WLC_IOCTL_MAXLEN) {
+ int bcmerr;
+
+ ret = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen);
+ if (ret == 0)
+ break;
+
+ /* If the error is not buffer too short break */
+ ret = wlu_iovar_getint(wl, "bcmerror", &bcmerr);
+ if (ret < 0 || bcmerr != BCME_BUFTOOSHORT)
+ break;
+
+ /* If the error is buffer too short, increment the num_chanspecs */
+ num_chanspecs += NUM_CHANSPECS_LIST_SIZE;
+ list->count = htod32(num_chanspecs);
+ /* increase the buffer length by the space for the chanspecs added */
+ buflen += sizeof(uint32)*(NUM_CHANSPECS_LIST_SIZE);
+ }
+
+ /* Incase of error return */
+ if (ret) {
+ err = BCME_IOCTL_ERROR;
+ goto exit;
+ }
+
+ list = (wl_uint32_list_t *)buf;
+ for (i = 0; i < dtoh32(list->count); i++) {
+ c = (chanspec_t)dtoh32(list->element[i]);
+ wf_chspec_ntoa(c, chspec_str);
+ printf("%s (0x%04x)\n", chspec_str, c);
+ }
+ printf("\n");
+ return ret;
+
+ exit:
+ return err;
+}
+
+static int
+wl_dump_chanspecs(void *wl, cmd_t *cmd, char **argv)
+{
+ miniopt_t to;
+ const char* fn_name = "wl_dump_chanspecs";
+ wl_uint32_list_t *list;
+ chanspec_t c = 0, *chanspec;
+ int ret, buflen;
+ uint i;
+ int err, opt_err;
+ bool band_set = FALSE, bw_set = FALSE, is80p80 = FALSE;
+ char abbrev[WLC_CNTRY_BUF_SZ] = ""; /* default.. current locale */
+ char chspec_str[CHANSPEC_STR_LEN];
+ char *country_abbrev;
+ int num_chanspecs = 0;
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+
+ /* multiple commands are using this API to dump a channel list:
+ * chanspecs
+ * roam_channels_in_cache
+ * roam_channels_in_hotlist
+ */
+ strcpy(buf, cmd->name);
+ buflen = strlen(buf) + 1;
+
+ /* toss the command name */
+ argv++;
+
+ /* Validate arguments if any */
+ if (*argv) {
+ miniopt_init(&to, fn_name, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 'b') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for band\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 5) && (to.val != 2)) {
+ fprintf(stderr,
+ "%s: invalid band %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == 5)
+ c |= WL_CHANSPEC_BAND_5G;
+ else
+ c |= WL_CHANSPEC_BAND_2G;
+ band_set = TRUE;
+ }
+ if (to.opt == 'w') {
+ /* For 80+80 case, using flag is80p80 for it */
+ if (!strcmp(to.valstr, "80+80")) {
+ is80p80 = TRUE;
+ }
+ if ((!to.good_int) && (!is80p80)) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " bandwidth\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 20) && (to.val != 40) && (to.val != 80) &&
+ (to.val != 160) && (!is80p80)) {
+ fprintf(stderr,
+ "%s: invalid bandwidth %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == 20)
+ c |= WL_CHANSPEC_BW_20;
+ else if (to.val == 40)
+ c |= WL_CHANSPEC_BW_40;
+ else {
+ if (ioctl_version == 1) {
+ fprintf(stderr,
+ "%s: bandwidth 80 MHz is not supported by "
+ "this version driver.\n",
+ fn_name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+
+ }
+ if (is80p80)
+ c |= WL_CHANSPEC_BW_8080;
+ else if (to.val == 160)
+ c |= WL_CHANSPEC_BW_160;
+ else
+ c |= WL_CHANSPEC_BW_80;
+ }
+
+ bw_set = TRUE;
+ }
+ if (to.opt == 'c') {
+ if (!to.valstr) {
+ fprintf(stderr,
+ "%s: please provide country abbrev \n", fn_name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ strncpy(abbrev, to.valstr, WLC_CNTRY_BUF_SZ - 1);
+ abbrev[WLC_CNTRY_BUF_SZ - 1] = '\0';
+ }
+ }
+ if (!bw_set || !band_set) {
+ if (!band_set)
+ fprintf(stderr, "%s: you need to set a band, '-b <5|2>'\n",
+ fn_name);
+ if (!bw_set)
+ fprintf(stderr,
+ "%s: you need to set a bandwidth, "
+ "'-w <20|40|80|160|80+80>'\n",
+ fn_name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+
+ /* convert chanspec to legacy if needed */
+ if (c != 0) {
+ c = wl_chspec_to_driver(c);
+ if (c == INVCHANSPEC) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+
+ /* Add chanspec argument */
+ chanspec = (chanspec_t *) (buf + buflen);
+ *chanspec = c;
+ buflen += (sizeof(chanspec_t));
+
+ /* Add country abbrev */
+ country_abbrev = buf + buflen;
+ strncpy(country_abbrev, abbrev, WLC_CNTRY_BUF_SZ);
+ buflen += WLC_CNTRY_BUF_SZ;
+
+ num_chanspecs += NUM_CHANSPECS_LIST_SIZE;
+
+ /* Add list */
+ list = (wl_uint32_list_t *)(buf + buflen);
+ list->count = htod32(num_chanspecs);
+ buflen += sizeof(uint32)*(num_chanspecs + 1);
+
+ /* if buflen is greater then WLC_IOCTL_MAXLEN return error */
+ ret = BCME_IOCTL_ERROR;
+ while (buflen <= WLC_IOCTL_MAXLEN) {
+ int bcmerr;
+
+ ret = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen);
+ if (ret == 0)
+ break;
+
+ /* If the error is not buffer too short break */
+ ret = wlu_iovar_getint(wl, "bcmerror", &bcmerr);
+ if (ret < 0 || bcmerr != BCME_BUFTOOSHORT)
+ break;
+
+ /* reconstruct the argument */
+ strcpy(buf, cmd->name);
+
+ /* Add chanspec argument */
+ *chanspec = c;
+
+ /* Add country abbrev */
+ strncpy(country_abbrev, abbrev, WLC_CNTRY_BUF_SZ);
+
+ /* If the error is buffer too short, increment the num_chanspecs */
+ num_chanspecs += NUM_CHANSPECS_LIST_SIZE;
+ list->count = htod32(num_chanspecs);
+ /* increase the buffer length by the space for the chanspecs added */
+ buflen += sizeof(uint32)*(NUM_CHANSPECS_LIST_SIZE);
+ }
+
+ /* Incase of error return */
+ if (ret) {
+ err = BCME_IOCTL_ERROR;
+ goto exit;
+ }
+
+ list = (wl_uint32_list_t *)buf;
+ for (i = 0; i < dtoh32(list->count); i++) {
+ c = wl_chspec32_from_driver(list->element[i]);
+ wf_chspec_ntoa(c, chspec_str);
+ printf("%s (0x%04x)\n", chspec_str, c);
+ }
+ printf("\n");
+ return ret;
+
+exit:
+ return err;
+}
+
+static int
+wl_channels_in_country(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_channels_in_country_t *cic;
+ int ret;
+ uint i, len;
+
+ cic = (wl_channels_in_country_t *)buf;
+ cic->buflen = WLC_IOCTL_MAXLEN;
+ cic->count = 0;
+
+ /* country abbrev must follow */
+ if (!*++argv) {
+ fprintf(stderr, "missing country abbrev\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ len = strlen(*argv);
+ if ((len > 3) || (len < 2)) {
+ fprintf(stderr, "invalid country abbrev: %s\n", *argv);
+ return BCME_BADARG;
+ }
+
+ strcpy(cic->country_abbrev, *argv);
+
+ /* band must follow */
+ if (!*++argv) {
+ fprintf(stderr, "missing band\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!stricmp(*argv, "a"))
+ cic->band = WLC_BAND_5G;
+ else if (!stricmp(*argv, "b"))
+ cic->band = WLC_BAND_2G;
+ else {
+ fprintf(stderr, "unsupported band: %s\n", *argv);
+ return BCME_UNSUPPORTED;
+ }
+
+ cic->buflen = htod32(cic->buflen);
+ cic->band = htod32(cic->band);
+ cic->count = htod32(cic->count);
+ ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < dtoh32(cic->count); i++)
+ printf("%d ", dtoh32(cic->channel[i]));
+ printf("\n");
+
+ return ret;
+}
+
+int
+wl_get_scan(void *wl, int opc, char *scan_buf, uint buf_len)
+{
+ wl_scan_results_t *list = (wl_scan_results_t*)scan_buf;
+ int ret;
+
+ list->buflen = htod32(buf_len);
+ ret = wlu_get(wl, opc, scan_buf, buf_len);
+ if (ret < 0)
+ return ret;
+ ret = 0;
+
+ list->buflen = dtoh32(list->buflen);
+ list->version = dtoh32(list->version);
+ list->count = dtoh32(list->count);
+ if (list->buflen == 0) {
+ list->version = 0;
+ list->count = 0;
+ } else if (list->version != WL_BSS_INFO_VERSION &&
+ list->version != LEGACY2_WL_BSS_INFO_VERSION &&
+ list->version != LEGACY_WL_BSS_INFO_VERSION) {
+ fprintf(stderr, "Sorry, your driver has bss_info_version %d "
+ "but this program supports only version %d.\n",
+ list->version, WL_BSS_INFO_VERSION);
+ list->buflen = 0;
+ list->count = 0;
+ }
+
+ return ret;
+}
+
+static int
+wl_get_iscan(void *wl, char *scan_buf, uint buf_len)
+{
+ wl_iscan_results_t list;
+ wl_scan_results_t *results;
+ int ret;
+
+ memset(&list, '\0', sizeof(list));
+ list.results.buflen = htod32(buf_len);
+ ret = wlu_iovar_getbuf(wl, "iscanresults", &list, WL_ISCAN_RESULTS_FIXED_SIZE,
+ scan_buf, WLC_IOCTL_MAXLEN);
+
+ if (ret < 0)
+ return ret;
+
+ ret = 0;
+
+ results = &((wl_iscan_results_t*)scan_buf)->results;
+ results->buflen = dtoh32(results->buflen);
+ results->version = dtoh32(results->version);
+ results->count = dtoh32(results->count);
+ if (results->buflen == 0) {
+ printf("wl_get_iscan buflen 0\n");
+ results->version = 0;
+ results->count = 0;
+ } else if (results->version != WL_BSS_INFO_VERSION &&
+ results->version != LEGACY2_WL_BSS_INFO_VERSION &&
+ results->version != LEGACY_WL_BSS_INFO_VERSION) {
+ fprintf(stderr, "Sorry, your driver has bss_info_version %d "
+ "but this program supports only version %d.\n",
+ results->version, WL_BSS_INFO_VERSION);
+ results->buflen = 0;
+ results->count = 0;
+ }
+
+ return ret;
+}
+
+static int
+wl_spect(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, spect;
+ char *endptr = NULL;
+
+ if (!*++argv) {
+ if ((ret = wlu_get(wl, cmd->get, &spect, sizeof(spect))) < 0) {
+ return ret;
+ }
+
+ spect = dtoh32(spect);
+ switch (spect) {
+ case SPECT_MNGMT_OFF:
+ printf("Off\n");
+ break;
+
+ case SPECT_MNGMT_LOOSE_11H:
+ printf("Loose interpretation of 11h spec - may join non 11h AP.\n");
+ break;
+
+ case SPECT_MNGMT_STRICT_11H:
+ printf("Strict interpretation of 11h spec - may not join non 11h AP.\n");
+ break;
+
+ case SPECT_MNGMT_STRICT_11D:
+ printf("802.11d mode\n");
+ break;
+
+ case SPECT_MNGMT_LOOSE_11H_D:
+ printf("Loose interpretation of 11h+d spec - may join non-11h APs\n");
+ break;
+
+ default:
+ printf("invalid value 0x%x\n", spect);
+ return BCME_BADARG;
+ }
+ return (0);
+ } else {
+ spect = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ if (spect < SPECT_MNGMT_OFF || spect > SPECT_MNGMT_LOOSE_11H_D)
+ return BCME_BADARG;
+
+ spect = htod32(spect);
+ return wlu_set(wl, cmd->set, &spect, sizeof(spect));
+ }
+}
+
+static int
+wl_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ struct ether_addr bssid;
+ wlc_ssid_t ssid;
+ char ssidbuf[SSID_FMT_BUF_LEN];
+ wl_bss_info_t *bi;
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ if ((ret = wlu_get(wl, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) == 0) {
+ /* The adapter is associated. */
+ *(uint32*)buf = htod32(WLC_IOCTL_MAXLEN);
+ if ((ret = wlu_get(wl, WLC_GET_BSS_INFO, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+
+ bi = (wl_bss_info_t*)(buf + 4);
+ if (dtoh32(bi->version) == WL_BSS_INFO_VERSION ||
+ dtoh32(bi->version) == LEGACY2_WL_BSS_INFO_VERSION ||
+ dtoh32(bi->version) == LEGACY_WL_BSS_INFO_VERSION)
+ dump_bss_info(bi);
+ else
+ fprintf(stderr, "Sorry, your driver has bss_info_version %d "
+ "but this program supports only version %d.\n",
+ bi->version, WL_BSS_INFO_VERSION);
+ } else {
+ printf("Not associated. Last associated with ");
+
+ if ((ret = wlu_get(wl, WLC_GET_SSID, &ssid, sizeof(wlc_ssid_t))) < 0) {
+ printf("\n");
+ return ret;
+ }
+
+ wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len));
+ printf("SSID: \"%s\"\n", ssidbuf);
+ }
+
+ return 0;
+}
+
+static int
+wl_deauth_rc(void *wl, cmd_t *cmd, char **argv)
+{
+ scb_val_t scb_val;
+ int ret;
+
+ if (!*++argv) {
+ fprintf(stderr, "STA MAC not specified, deauth all\n");
+ ret = wlu_set(wl, WLC_SCB_DEAUTHENTICATE, (void *)ðer_bcast,
+ ETHER_ADDR_LEN);
+ return ret;
+
+ } else if (!wl_ether_atoe(*argv, &scb_val.ea)) {
+ fprintf(stderr, "Malformed STA MAC parameter\n");
+ ret = BCME_USAGE_ERROR;
+
+ } else if (!*++argv) {
+ /* No reason code furnished, so driver will use its default */
+ ret = wlu_set(wl, WLC_SCB_DEAUTHENTICATE, &scb_val.ea,
+ ETHER_ADDR_LEN);
+
+ } else {
+ scb_val.val = htod32((uint32)strtoul(*argv, NULL, 0));
+ ret = wlu_set(wl, cmd->set, &scb_val, sizeof(scb_val));
+ }
+ return ret;
+}
+
+static int
+wl_wpa_auth(void *wl, cmd_t *cmd, char **argv)
+{
+ int bsscfg_idx = 0;
+ int consumed;
+ int wpa_auth = 0;
+ int ret = 0;
+ int i;
+ static struct {
+ int val;
+ const char *name;
+ } auth_mode[] =
+ /* Keep the numeric values in the staticly initialized
+ * help string consistent. Unfortunately, there isn't
+ * an automatic way for that.
+ */
+ {{WPA_AUTH_NONE, "WPA-NONE"},
+ {WPA_AUTH_UNSPECIFIED, "WPA-802.1x"},
+ {WPA_AUTH_PSK, "WPA-PSK"},
+ {WPA2_AUTH_UNSPECIFIED, "WPA2-802.1x"},
+ {WPA2_AUTH_PSK, "WPA2-PSK"},
+#ifdef BCMWAPI_WAI
+ {WAPI_AUTH_UNSPECIFIED, "WAPI-AS"},
+ {WAPI_AUTH_PSK, "WAPI-PSK"},
+#endif /* BCMWAPI_WAI */
+ {WPA2_AUTH_1X_SHA256, "1X-SHA256"},
+ {WPA2_AUTH_FT, "FT"},
+ {WPA2_AUTH_PSK_SHA256, "PSK-SHA256"},
+ {WPA_AUTH_DISABLED, "disabled"}};
+
+ /* skip the command name */
+ argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((ret = wl_cfg_option(argv, cmd->name, &bsscfg_idx, &consumed)) != 0)
+ return ret;
+
+ argv += consumed;
+
+ if (!*argv) {
+ /* no arg, so this is a GET. */
+
+ if (!consumed)
+ ret = wlu_iovar_getint(wl, "wpa_auth", &wpa_auth);
+ else
+ ret = wl_bssiovar_getint(wl, "wpa_auth", bsscfg_idx, &wpa_auth);
+
+ if (ret < 0)
+ return ret;
+
+ /* Show all AKM suites enabled */
+ printf("0x%x", wpa_auth);
+
+ if (wpa_auth == WPA_AUTH_DISABLED)
+ printf(" Disabled");
+
+ for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) {
+ if (wpa_auth & auth_mode[i].val)
+ printf(" %s", auth_mode[i].name);
+ }
+
+ printf("\n");
+ return ret;
+
+
+ } else {
+ /* there's an arg, so this is a SET. */
+ ret = 1;
+
+ /* Validate the user input range */
+ if (isdigit((int)*argv[0])) {
+ unsigned int range = 0;
+
+ /* param is a number; look for value in the list */
+ wpa_auth = strtoul(*argv, NULL, 0);
+
+ /* Validate the user input range */
+
+ for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++)
+ range |= auth_mode[i].val;
+
+ range = (~range) & 0xFFFF;
+
+ if (range & wpa_auth) {
+ ret = 1;
+ goto usage;
+ } else {
+ ret = 0;
+ }
+
+ } else {
+
+ int arg_count = 0;
+ char** p_argv;
+ int j = 0;
+ unsigned int range = 0;
+
+ wpa_auth = 0;
+ p_argv = argv;
+
+ for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++)
+ range |= auth_mode[i].val;
+
+ range = (~range) & (0xFFFF);
+
+ while (*p_argv) {
+ arg_count++;
+ p_argv++;
+ }
+
+ p_argv = argv;
+
+ for (j = 0; j < arg_count; j++) {
+ bool found = FALSE;
+
+ argv = p_argv + j;
+
+ /* treat param as string to be matched in list */
+ for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) {
+ if (!stricmp(auth_mode[i].name, *argv)) {
+
+ found = TRUE;
+ wpa_auth |= auth_mode[i].val;
+ ret = 0;
+
+ /* traverse the list */
+ argv++;
+ if (!*argv)
+ break;
+ }
+ }
+
+ if ((found == FALSE) || (range & wpa_auth))
+ goto usage;
+ }
+
+ }
+ if (ret)
+ fprintf(stderr, "%s is not a valid WPA auth mode\n", *argv);
+ else {
+ if (!consumed)
+ ret = wlu_iovar_setint(wl, "wpa_auth", wpa_auth);
+ else
+ ret = wl_bssiovar_setint(wl, "wpa_auth", bsscfg_idx, wpa_auth);
+ }
+ }
+
+ return ret;
+
+usage:
+ fprintf(stderr, "Inavlid user argument.\n");
+ fprintf(stderr, "Values may be a bitvector or list of names from the set.\n");
+
+ for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) {
+ fprintf(stderr, "\n0x%04x %s", auth_mode[i].val, auth_mode[i].name);
+ }
+
+ printf("\n");
+ return ret;
+}
+
+static int
+wl_set_pmk(void *wl, cmd_t *cmd, char **argv)
+{
+ wsec_pmk_t psk;
+ size_t key_len;
+
+ if (!*++argv) {
+ return BCME_USAGE_ERROR;
+ }
+ key_len = strlen(*argv);
+ if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
+ fprintf(stderr, "passphrase must be between %d and %d characters long\n",
+ WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN);
+ return BCME_BADARG;
+ }
+ psk.key_len = htod16((ushort) key_len);
+ psk.flags = htod16(WSEC_PASSPHRASE);
+ memcpy(psk.key, *argv, key_len);
+ return wlu_set(wl, cmd->set, &psk, sizeof(psk));
+}
+
+static int
+wl_wsec(void *wl, cmd_t *cmd, char **argv)
+{
+ int wsec;
+ int bsscfg_idx = 0;
+ int consumed;
+ char *endptr = NULL;
+ int error;
+
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((error = wl_cfg_option(argv, "wsec", &bsscfg_idx, &consumed)) != 0)
+ return error;
+
+ argv += consumed;
+
+ if (!*argv) {
+ /* This is a GET */
+ if (consumed == 0) {
+ error = wlu_get(wl, WLC_GET_WSEC, &wsec, sizeof(uint32));
+ wsec = dtoh32(wsec);
+ }
+ else
+ error = wl_bssiovar_getint(wl, "wsec", bsscfg_idx, &wsec);
+
+ if (!error)
+ wl_printint(wsec);
+ } else {
+ /* This is a SET */
+ if (!stricmp(*argv, "off"))
+ wsec = 0;
+ else {
+ wsec = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ if (consumed == 0) {
+ wsec = htod32(wsec);
+ error = wlu_set(wl, WLC_SET_WSEC, &wsec, sizeof(uint32));
+ }
+ else
+ error = wl_bssiovar_setint(wl, "wsec", bsscfg_idx, wsec);
+ }
+
+ return error;
+}
+
+int
+parse_wep(char **argv, wl_wsec_key_t *key, bool options)
+{
+ char hex[] = "XX";
+ unsigned char *data = key->data;
+ char *keystr = *argv;
+
+ switch (strlen(keystr)) {
+ case 5:
+ case 13:
+ case 16:
+ key->len = strlen(keystr);
+ memcpy(data, keystr, key->len + 1);
+ break;
+ case 12:
+ case 28:
+ case 34:
+ case 66:
+ /* strip leading 0x */
+ if (!strnicmp(keystr, "0x", 2))
+ keystr += 2;
+ else
+ return -1;
+ /* fall through */
+ case 10:
+ case 26:
+ case 32:
+ case 64:
+ key->len = strlen(keystr) / 2;
+ while (*keystr) {
+ strncpy(hex, keystr, 2);
+ *data++ = (char) strtoul(hex, NULL, 16);
+ keystr += 2;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ switch (key->len) {
+ case 5:
+ key->algo = CRYPTO_ALGO_WEP1;
+ break;
+ case 13:
+ key->algo = CRYPTO_ALGO_WEP128;
+ break;
+ case 16:
+ /* default to AES-CCM */
+ key->algo = CRYPTO_ALGO_AES_CCM;
+ break;
+ case 32:
+ key->algo = CRYPTO_ALGO_TKIP;
+ break;
+ default:
+ return -1;
+ }
+
+ /* Set as primary key by default */
+ key->flags |= WL_PRIMARY_KEY;
+
+ if (options) {
+ /* Get options */
+ while (*++argv) {
+ if (!strnicmp("ccm", *argv, 3) && key->len == 16)
+ key->algo = CRYPTO_ALGO_AES_CCM;
+ else if (!strnicmp("ocb", *argv, 3) && key->len == 16)
+ key->algo = CRYPTO_ALGO_AES_OCB_MPDU;
+ else if (!strnicmp("notx", *argv, 4))
+ key->flags &= ~WL_PRIMARY_KEY;
+ else if (!wl_ether_atoe(*argv, &key->ea))
+ memset(&key->ea, 0, ETHER_ADDR_LEN);
+ }
+ }
+
+ return 0;
+}
+
+/* get a power value from the opaque ppr structure */
+static int8 wl_ppr_get_pwr(ppr_t* pprptr, reg_rate_index_t rate_idx, wl_tx_bw_t bw)
+{
+ clm_rate_group_id_t group_id = ppr_table[rate_idx].id;
+ int8 power = WL_RATE_DISABLED;
+ switch (ppr_group_table[group_id].rate_type) {
+ case PPR_RATE_DSSS:
+ {
+ ppr_dsss_rateset_t rateset;
+ ppr_get_dsss(pprptr, bw, ppr_group_table[group_id].chain, &rateset);
+ power = rateset.pwr[rate_idx-ppr_group_table[group_id].first_rate];
+ }
+ break;
+ case PPR_RATE_OFDM:
+ {
+ ppr_ofdm_rateset_t rateset;
+ ppr_get_ofdm(pprptr, bw, ppr_group_table[group_id].mode,
+ ppr_group_table[group_id].chain, &rateset);
+ power = rateset.pwr[rate_idx-ppr_group_table[group_id].first_rate];
+ }
+ break;
+ case PPR_RATE_HT:
+ {
+ ppr_ht_mcs_rateset_t rateset;
+ ppr_get_ht_mcs(pprptr, bw, ppr_group_table[group_id].nss,
+ ppr_group_table[group_id].mode,
+ ppr_group_table[group_id].chain, &rateset);
+ power = rateset.pwr[rate_idx-ppr_group_table[group_id].first_rate];
+ }
+ break;
+ case PPR_RATE_VHT:
+ {
+ ppr_vht_mcs_rateset_t rateset;
+ ppr_get_vht_mcs(pprptr, bw, ppr_group_table[group_id].nss,
+ ppr_group_table[group_id].mode,
+ ppr_group_table[group_id].chain, &rateset);
+ power = rateset.pwr[rate_idx-ppr_group_table[group_id].first_rate];
+ }
+ break;
+ default:
+ break;
+ }
+
+ return power;
+}
+
+static int
+wl_get_chanspec_txpwr_max(void *wl, cmd_t *cmd, char **argv)
+{
+ int i, err;
+ char chspec_str[CHANSPEC_STR_LEN];
+
+ wl_chanspec_txpwr_max_t *chanspec_txpwr;
+ wl_chanspec_txpwr_max_t params;
+
+ miniopt_t to;
+ chanspec_t chanspec = 0;
+ int opt_err;
+ bool band_set = FALSE, bw_set = FALSE;
+
+ /* toss the command name */
+ argv++;
+
+ /* Validate arguments if any */
+ if (*argv) {
+ miniopt_init(&to, __FUNCTION__, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 'b') {
+ if (!to.good_int) {
+ fprintf(stderr, "%s: could not parse [%s] as band\n",
+ __FUNCTION__, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 5) && (to.val != 2)) {
+ fprintf(stderr, "%s: invalid band %d\n",
+ __FUNCTION__, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == 5)
+ chanspec |= WL_CHANSPEC_BAND_5G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ band_set = TRUE;
+ }
+ if (to.opt == 'w') {
+ if (!to.good_int) {
+ fprintf(stderr, "%s: could not parse [%s] as bandwidth\n",
+ __FUNCTION__, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val == 20)
+ chanspec |= WL_CHANSPEC_BW_20;
+ else if (to.val == 40)
+ chanspec |= WL_CHANSPEC_BW_40;
+ else if (to.val == 80)
+ chanspec |= WL_CHANSPEC_BW_80;
+ else if (to.val == 160)
+ chanspec |= WL_CHANSPEC_BW_160;
+ else if (to.val == 8080)
+ chanspec |= WL_CHANSPEC_BW_8080;
+ else {
+ fprintf(stderr, "%s: invalid bandwidth %d\n",
+ __FUNCTION__, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ bw_set = TRUE;
+ }
+ }
+ if (!bw_set || !band_set) {
+ if (!band_set)
+ fprintf(stderr, "%s: you need to set a band, '-b <5|2>'\n",
+ __FUNCTION__);
+ if (!bw_set)
+ fprintf(stderr,
+ "%s: you need to set a bandwidth, '-w <20|40|80>'\n",
+ __FUNCTION__);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+
+ /* convert chanspec to legacy if needed */
+ if (chanspec != 0) {
+ chanspec = wl_chspec_to_driver(chanspec);
+ if (chanspec == INVCHANSPEC) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+
+ memset(¶ms, 0, WL_CHANSPEC_TXPWR_MAX_LEN);
+ params.ver = WL_CHANSPEC_TXPWR_MAX_VER;
+ params.len = WL_CHANSPEC_TXPWR_MAX_LEN;
+ params.count = 1;
+ params.txpwr[0].chanspec = chanspec;
+
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, ¶ms, sizeof(params),
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ return err;
+ }
+
+ chanspec_txpwr = (wl_chanspec_txpwr_max_t *)buf;
+
+ if (chanspec_txpwr->ver != WL_CHANSPEC_TXPWR_MAX_VER) {
+ fprintf(stderr, "Error: version [%d] mismatch Driver version:%d\n",
+ WL_CHANSPEC_TXPWR_MAX_VER, chanspec_txpwr->ver);
+ return err;
+ }
+
+ for (i = 0; i < (int)(dtoh32(chanspec_txpwr->count)); i++) {
+ chanspec = wl_chspec32_from_driver(chanspec_txpwr->txpwr[i].chanspec);
+ wf_chspec_ntoa(chanspec, chspec_str);
+
+ printf("%s\t(0x%04x)\t%2d.%02d(dbm)\n",
+ chspec_str, chanspec,
+ DIV_QUO(chanspec_txpwr->txpwr[i].txpwr_max, 4),
+ DIV_REM(chanspec_txpwr->txpwr[i].txpwr_max, 4));
+ }
+ printf("\n");
+
+exit:
+ return err;
+}
+
+/* This version number must be incremented for every
+ * modification to the curpower output format. Minor changes
+ * warrant a decimal point increment. Major (potential
+ * script-breaking) changes should be met with a major increment.
+ */
+#define CURPOWER_OUTPUT_FORMAT_VERSION "8"
+
+#define RATE_STR_LEN 64
+#define CURPOWER_VER_STR "cptlv-"
+#define WL_CAP_CMD "cap"
+
+static int
+wl_get_curpower_tlv_ver(void *wl)
+{
+ int error;
+ int ret = 0;
+
+ /* Get the CAP variable; search for curpower ver */
+ strncpy(buf, WL_CAP_CMD, WLC_IOCTL_MAXLEN);
+ if ((error = wlu_get(wl, WLC_GET_VAR, buf, WLC_IOCTL_MEDLEN)) >= 0) {
+ char seps[] = " ";
+ char *token;
+ buf[WLC_IOCTL_MEDLEN] = '\0';
+ token = strtok(buf, seps);
+ while (token != NULL) {
+ if (!memcmp(token, CURPOWER_VER_STR, strlen(CURPOWER_VER_STR))) {
+ char *ver = &token[strlen(CURPOWER_VER_STR)];
+ ret = atoi(ver);
+ }
+ token = strtok(NULL, seps);
+ }
+ }
+ return ret;
+}
+
+static int
+wl_get_current_power(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int mimo;
+ int i;
+ char chanspec_str[CHANSPEC_STR_LEN];
+ bool verbose = FALSE;
+ bool brief = FALSE;
+ int16 power_target;
+ char rate_str[RATE_STR_LEN];
+ int clk;
+ int val;
+ chanspec_t chanspec;
+ uint8 *ppr_ser;
+ uint32 pprsize;
+ uint32 txchain_bitmap = 0;
+ size_t ppr_rpt_size;
+ tx_pwr_rpt_t *ppr_wl = NULL;
+ ppr_t* ppr_board = NULL;
+ ppr_t* ppr_target = NULL;
+ ppr_t* ppr_reg = NULL;
+ uint8 ppr_dim = 0;
+
+ int tlv_ver = wl_get_curpower_tlv_ver(wl);
+ /* firmware will crash if clk = 0 while using curpower */
+ if ((err = wlu_get(wl, WLC_GET_CLK, &clk, sizeof(int))) < 0)
+ goto exit;
+
+ if (!clk) {
+ fprintf(stderr, "Error: clock not active, do wl up (if not done already) "
+ "and force mpc 0 to active clock\n");
+ err = BCME_ERROR;
+ goto exit;
+ }
+
+ if ((err = wlu_iovar_getint(wl, "chanspec", (int *)&val)) < 0) {
+ goto exit;
+ }
+ chanspec = wl_chspec32_from_driver(val);
+
+ if ((err = wlu_iovar_get(wl, "hw_txchain", &txchain_bitmap, sizeof(txchain_bitmap))) < 0)
+ goto exit;
+
+ /* Special cases for 4365 3x3 config: hw_txchain can take a value between [8-15];
+ * there are still 4 PHY cores but one or more cores are not used
+ */
+ if (txchain_bitmap > 8 && txchain_bitmap <= 15)
+ ppr_dim = 4;
+ else
+ ppr_dim = bcm_bitcount((uint8 *)&txchain_bitmap, sizeof(uint8));
+
+
+ if (tlv_ver) {
+ if ((ppr_board = ppr_create(NULL, ppr_chanspec_bw(chanspec))) == NULL) {
+ err = BCME_NOMEM;
+ goto exit;
+ }
+ if ((ppr_target = ppr_create(NULL, ppr_chanspec_bw(chanspec))) == NULL) {
+ err = BCME_NOMEM;
+ goto exit;
+ }
+ if ((ppr_reg = ppr_create(NULL, ppr_chanspec_bw(chanspec))) == NULL) {
+ err = BCME_NOMEM;
+ goto exit;
+ }
+ pprsize = ppr_get_tlv_size(ppr_target, ppr_chanspec_bw(chanspec), ppr_dim);
+ } else {
+ pprsize = ppr_ser_size_by_bw(ppr_get_max_bw());
+ }
+ ppr_rpt_size = sizeof(tx_pwr_rpt_t) + pprsize*WL_TXPPR_SER_BUF_NUM;
+ ppr_wl = (tx_pwr_rpt_t *)malloc(ppr_rpt_size);
+
+ if (!tlv_ver) {
+ for (i = 0; i < WL_TXPPR_SER_BUF_NUM; i++) {
+ ppr_ser = ppr_wl->pprdata + i*pprsize;
+ ppr_init_ser_mem_by_bw(ppr_ser, ppr_get_max_bw(), pprsize);
+ }
+ }
+
+ if (ppr_wl == NULL) {
+ fprintf(stderr, "Allocating mem failed for curpower\n");
+ err = BCME_NOMEM;
+ goto exit;
+ }
+
+ memset(ppr_wl, WL_RATE_DISABLED, ppr_rpt_size);
+
+ ppr_wl->ppr_len = pprsize;
+ ppr_wl->version = TX_POWER_T_VERSION;
+
+ if (argv[1] && (!strcmp(argv[1], "--verbose") || !strcmp(argv[1], "-v"))) {
+ verbose = TRUE;
+ argv++;
+ }
+ if (argv[1] && (!strcmp(argv[1], "--brief") || !strcmp(argv[1], "-b"))) {
+ brief = TRUE;
+ argv++;
+ }
+ argv++;
+ if (*argv)
+ fprintf(stderr, "Ignoring arguments for %s\n", cmd->name);
+
+ if ((err = wlu_get(wl, cmd->get, ppr_wl, ppr_rpt_size)) < 0) {
+ fprintf(stderr, "Error: Curpower failed. ");
+ fprintf(stderr, "Bring up interface and disable mpc if necessary (wl mpc 0)\n");
+ goto exit;
+ }
+
+ /* parse */
+ if (ppr_wl->version != TX_POWER_T_VERSION) {
+ printf("error: version mismatch - driver %d, wl executable was expecting %d\n",
+ ppr_wl->version, TX_POWER_T_VERSION);
+ err = BCME_ERROR;
+ } else {
+ int8 temp_val;
+ int divquo, divrem;
+ bool neg;
+
+ ppr_wl->flags = dtoh32(ppr_wl->flags);
+ ppr_wl->chanspec = wl_chspec_from_driver(ppr_wl->chanspec);
+ ppr_wl->local_chanspec = wl_chspec_from_driver(ppr_wl->local_chanspec);
+
+ mimo = (ppr_wl->flags & WL_TX_POWER_F_HT) |
+ (ppr_wl->flags & WL_TX_POWER_F_MIMO) |
+ (ppr_wl->flags & WL_TX_POWER_F_SISO);
+ ppr_ser = ppr_wl->pprdata;
+
+ if (tlv_ver) {
+ (void)ppr_convert_from_tlv(ppr_board, ppr_wl->pprdata, ppr_wl->ppr_len);
+ ppr_ser += ppr_wl->ppr_len;
+ (void)ppr_convert_from_tlv(ppr_target, ppr_ser, ppr_wl->ppr_len);
+ ppr_ser += ppr_wl->ppr_len;
+ (void)ppr_convert_from_tlv(ppr_reg, ppr_ser, ppr_wl->ppr_len);
+ } else {
+ /* Try non TLV decode */
+ if ((err = ppr_deserialize_create(NULL, ppr_wl->pprdata, ppr_wl->ppr_len,
+ &ppr_board)) != BCME_OK) {
+ fprintf(stderr, "Error: read ppr board limit failed\n");
+ goto exit;
+ }
+ ppr_ser += ppr_wl->ppr_len;
+ if ((err = ppr_deserialize_create(NULL, ppr_ser, ppr_wl->ppr_len,
+ &ppr_target)) != BCME_OK) {
+ fprintf(stderr, "Error: read ppr target power failed\n");
+ goto exit;
+ }
+ ppr_ser += ppr_wl->ppr_len;
+ if ((err = ppr_deserialize_create(NULL, ppr_ser, ppr_wl->ppr_len, &ppr_reg))
+ != BCME_OK) {
+ fprintf(stderr, "Error: read ppr regulatory limits failed\n");
+ goto exit;
+ }
+ }
+
+ /* dump */
+ if (verbose)
+ printf("%-23s%s\n", "Output Format Version:",
+ CURPOWER_OUTPUT_FORMAT_VERSION);
+
+ printf("%-23s%s, %s\n", "Power Control:",
+ (ppr_wl->flags & WL_TX_POWER_F_ENABLED) ? "On" : "Off",
+ (ppr_wl->flags & WL_TX_POWER_F_HW) ? "HW" : "SW");
+ printf("%-23s%s\n", "Current Channel:",
+ wf_chspec_ntoa(ppr_wl->chanspec, chanspec_str));
+ printf("%-23s%s\n", "BSS Channel:",
+ wf_chspec_ntoa(ppr_wl->local_chanspec, chanspec_str));
+ printf("%-23s%d.%d dBm\n", "BSS Local Max:",
+ DIV_QUO(ppr_wl->local_max, 4), DIV_REM(ppr_wl->local_max, 4));
+ printf("%-23s%d.%d dB\n", "BSS Local Constraint:",
+ DIV_QUO(ppr_wl->local_constraint, 4), DIV_REM(ppr_wl->local_constraint, 4));
+ printf("%-23s", "Channel Width:");
+ switch (ppr_wl->channel_bandwidth) {
+ case WL_BW_2P5MHZ:
+ printf("2.5MHz\n");
+ break;
+ case WL_BW_5MHZ:
+ printf("5MHz\n");
+ break;
+ case WL_BW_10MHZ:
+ printf("10MHz\n");
+ break;
+ case WL_BW_20MHZ:
+ printf("20MHz\n");
+ break;
+ case WL_BW_40MHZ:
+ printf("40MHz\n");
+ break;
+ case WL_BW_80MHZ:
+ printf("80MHz\n");
+ break;
+ case WL_BW_160MHZ:
+ printf("160MHz\n");
+ break;
+ case WL_BW_8080MHZ:
+ printf("80+80MHz\n");
+ break;
+ default:
+ fprintf(stderr, "Error: Unknown bandwidth %d\n",
+ ppr_wl->channel_bandwidth);
+ err = BCME_RANGE;
+ goto exit;
+ }
+
+ temp_val = (int8)(ppr_wl->user_target & 0xff);
+ divquo = DIV_QUO(temp_val, 4);
+ divrem = DIV_REM(temp_val, 4);
+ neg = (divrem < 0) || (divquo < 0);
+ divrem = ABS(divrem);
+ divquo = ABS(divquo);
+ divquo = neg ? -divquo : divquo;
+
+ printf("%-23s%d.%d dBm\n", "User Target:",
+ divquo, divrem);
+ printf("%-23s%d.%d dB\n", "SROM Antgain 2G:",
+ DIV_QUO(ppr_wl->antgain[0], 4), DIV_REM(ppr_wl->antgain[0], 4));
+ printf("%-23s%d.%d dB\n", "SROM Antgain 5G:",
+ DIV_QUO(ppr_wl->antgain[1], 4), DIV_REM(ppr_wl->antgain[1], 4));
+ printf("%-23s", "SAR:");
+ if (ppr_wl->sar != WLC_TXPWR_MAX)
+ printf("%d.%d dB\n", DIV_QUO(ppr_wl->sar, 4), DIV_REM(ppr_wl->sar, 4));
+ else
+ printf("-\n");
+ printf("%-23s", "Open loop:");
+ if (ppr_wl->flags & WL_TX_POWER_F_OPENLOOP)
+ printf("On\n");
+ else
+ printf("Off\n");
+ printf("%-23s", "Current rate:");
+ wl_rate_print(rate_str, ppr_wl->last_tx_ratespec);
+ printf("[%s] %s\n", get_reg_rate_string_from_ratespec(ppr_wl->last_tx_ratespec),
+ rate_str);
+ printf("\n");
+
+ printf("Regulatory Limits:\n");
+ if (brief)
+ {
+ wl_txpwr_array_row_print(ppr_reg, ppr_wl->channel_bandwidth,
+ get_reg_rate_index_from_ratespec(ppr_wl->last_tx_ratespec));
+ }
+ else
+ {
+ wl_txpwr_array_print(ppr_reg, ppr_wl->channel_bandwidth, verbose,
+ CHSPEC_IS5G(chanspec));
+ }
+ printf("\n");
+
+ printf("%-23s%d\n", "Core Index:", ppr_wl->display_core);
+ printf("Board Limits:\n");
+ if (brief)
+ {
+ wl_txpwr_array_row_print(ppr_board, ppr_wl->channel_bandwidth,
+ get_reg_rate_index_from_ratespec(ppr_wl->last_tx_ratespec));
+ }
+ else
+ {
+ wl_txpwr_array_print(ppr_board, ppr_wl->channel_bandwidth, verbose,
+ CHSPEC_IS5G(chanspec));
+ }
+ printf("\n");
+
+ printf("Power Targets:\n");
+ if (brief)
+ {
+ wl_txpwr_array_row_print(ppr_target, ppr_wl->channel_bandwidth,
+ get_reg_rate_index_from_ratespec(ppr_wl->last_tx_ratespec));
+ }
+ else
+ {
+ wl_txpwr_array_print(ppr_target, ppr_wl->channel_bandwidth, verbose,
+ CHSPEC_IS5G(chanspec));
+ }
+ printf("\n");
+
+ /* print the different power estimate combinations */
+ if (mimo) {
+ printf("Maximum Power Target among all rates:\t");
+ for (i = 0; i < ppr_wl->rf_cores; i++) {
+ power_target = (int8)ppr_wl->tx_power_max[i];
+ divquo = DIV_QUO(power_target, 4);
+ divrem = DIV_REM(power_target, 4);
+ neg = (divrem < 0) || (divquo < 0);
+ divrem = ABS(divrem);
+ divquo = ABS(divquo);
+ divquo = neg ? -divquo : divquo;
+ printf("%2d.%02d ", divquo, divrem);
+ }
+ printf("\n");
+
+ printf("Last est. power :\t");
+ for (i = 0; i < ppr_wl->rf_cores; i++)
+ printf("%2d.%02d ",
+ DIV_QUO((int8)ppr_wl->est_Pout[i], 4),
+ DIV_REM(ppr_wl->est_Pout[i], 4));
+ printf("\n");
+
+ printf("Power Target for the current rate :\t");
+ for (i = 0; i < ppr_wl->rf_cores; i++)
+ {
+ if (ppr_wl->target_offsets[i] != WL_RATE_DISABLED)
+ {
+ power_target = (int8)ppr_wl->tx_power_max[i] -
+ ppr_wl->target_offsets[i];
+ /* for ACPHY, clip the power_target if it
+ is larger than the SAR limit for the
+ current path. For non-ACPHY or
+ WLC_SARLIMIT disabled, this threshold is
+ set to be MAX pwr, ie. 127
+ */
+ if (power_target > ppr_wl->SARLIMIT[i])
+ power_target = ppr_wl->SARLIMIT[i];
+ divquo = DIV_QUO(power_target, 4);
+ divrem = DIV_REM(power_target, 4);
+ neg = (divrem < 0) || (divquo < 0);
+ divrem = ABS(divrem);
+ divquo = ABS(divquo);
+ divquo = neg ? -divquo : divquo;
+
+ printf("%2d.%02d ", divquo, divrem);
+
+ }
+ else
+ {
+ printf("- ");
+ }
+ }
+ printf("\n");
+
+ printf("Last adjusted est. power :\t");
+ for (i = 0; i < ppr_wl->rf_cores; i++)
+ printf("%2d.%02d ",
+ DIV_QUO((int8)ppr_wl->est_Pout[i], 4),
+ DIV_REM(ppr_wl->est_Pout[i], 4));
+ printf("\n");
+ } else {
+ printf("Last est. power:\t%2d.%02d dBm\n",
+ DIV_QUO((int8)ppr_wl->est_Pout[0], 4),
+ DIV_REM(ppr_wl->est_Pout[0], 4));
+ }
+
+ if (!mimo && CHSPEC_IS2G(chanspec)) {
+ printf("Last CCK est. power:\t%2d.%02d dBm\n",
+ DIV_QUO((int8)ppr_wl->est_Pout_cck, 4),
+ DIV_REM(ppr_wl->est_Pout_cck, 4));
+ }
+exit:
+ if (ppr_board != NULL) {
+ ppr_delete(NULL, ppr_board);
+ }
+ if (ppr_target != NULL) {
+ ppr_delete(NULL, ppr_target);
+ }
+ if (ppr_reg != NULL) {
+ ppr_delete(NULL, ppr_reg);
+ }
+ }
+ free(ppr_wl);
+ return err;
+}
+
+static int wl_get_txpwr_target_max(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ txpwr_target_max_t target_pwr;
+ int i;
+
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_iovar_get(wl, cmd->name, (void *)&target_pwr, sizeof(target_pwr))) < 0) {
+ fprintf(stderr, "Error: txpwr_target failed. Make sure interface is up.\n");
+ return err;
+ }
+
+ if (target_pwr.version != TXPWR_TARGET_VERSION) {
+ fprintf(stderr, "Error: version [%d] mismatch Driver version:%d\n",
+ TXPWR_TARGET_VERSION, target_pwr.version);
+ return err;
+ }
+
+ printf("Maximum Tx Power Target (chanspec:0x%x):\t", target_pwr.chanspec);
+ for (i = 0; i < target_pwr.rf_cores; i++)
+ printf("%2d.%02d ",
+ DIV_QUO(target_pwr.txpwr[i], 4),
+ DIV_REM(target_pwr.txpwr[i], 4));
+ printf("\n");
+
+ return err;
+}
+
+/* print a single row of the power data.
+ convert data from dB to qdB;
+ decide if the pwr data is 20 or 40MHz data;
+ print "-" in the other channels
+ */
+void
+wl_txpwr_print_row(const char *label, uint8 chains, txpwr_row_t powers,
+ int8 unsupported_rate, int8 channel_bandwidth, bool verbose)
+{
+ char tmp[] = "- ";
+ char rate2P5[] = "- ";
+ char rate5[] = "- ";
+ char rate10[] = "- ";
+ char rate20[] = "- ";
+ char rate20in40[] = "- ";
+ char rate40[] = "- ";
+ char rate80[] = "- ";
+ char rate20in80[] = "- ";
+ char rate40in80[] = "- ";
+ char rate160[] = "- ";
+ char rate20in160[] = "- ";
+ char rate40in160[] = "- ";
+ char rate80in160[] = "- ";
+ char rate8080[] = "- ";
+ char rate8080chan2[] = "- ";
+ char rate20in8080[] = "- ";
+ char rate40in8080[] = "- ";
+ char rate80in8080[] = "- ";
+
+ if (powers.pwr2p5 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr2p5/4);
+ strncpy(rate2P5, tmp, strlen(tmp));
+ }
+ if (powers.pwr5 != unsupported_rate) {
+ sprintf(tmp, "%2.2f ", (float)powers.pwr5/4);
+ strncpy(rate5, tmp, strlen(tmp));
+ }
+ if (powers.pwr10 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr10/4);
+ strncpy(rate10, tmp, strlen(tmp));
+ }
+ if (powers.pwr20 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr20/4);
+ strncpy(rate20, tmp, strlen(tmp));
+ }
+ if (powers.pwr20in40 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr20in40/4);
+ strncpy(rate20in40, tmp, strlen(tmp));
+ }
+ if (powers.pwr40 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr40/4);
+ strncpy(rate40, tmp, strlen(tmp));
+ }
+ if (powers.pwr80 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr80/4);
+ strncpy(rate80, tmp, strlen(tmp));
+ }
+ if (powers.pwr20in80 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr20in80/4);
+ strncpy(rate20in80, tmp, strlen(tmp));
+ }
+ if (powers.pwr40in80 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr40in80/4);
+ strncpy(rate40in80, tmp, strlen(tmp));
+ }
+ if (powers.pwr20 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr20/4);
+ strncpy(rate20, tmp, strlen(tmp));
+ }
+ if (powers.pwr160 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr160/4);
+ strncpy(rate160, tmp, strlen(tmp));
+ }
+ if (powers.pwr20in160 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr20in160/4);
+ strncpy(rate20in160, tmp, strlen(tmp));
+ }
+ if (powers.pwr40in160 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr40in160/4);
+ strncpy(rate40in160, tmp, strlen(tmp));
+ }
+ if (powers.pwr80in160 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr80in160/4);
+ strncpy(rate80in160, tmp, strlen(tmp));
+ }
+ if (powers.pwr8080 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr8080/4);
+ strncpy(rate8080, tmp, strlen(tmp));
+ }
+ if (powers.pwr8080chan2 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr8080chan2/4);
+ strncpy(rate8080chan2, tmp, strlen(tmp));
+ }
+ if (powers.pwr20in8080 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr20in8080/4);
+ strncpy(rate20in8080, tmp, strlen(tmp));
+ }
+ if (powers.pwr40in8080 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr40in8080/4);
+ strncpy(rate40in8080, tmp, strlen(tmp));
+ }
+ if (powers.pwr80in8080 != unsupported_rate) {
+ sprintf(tmp, "%2.2f", (float)powers.pwr80in8080/4);
+ strncpy(rate80in8080, tmp, strlen(tmp));
+ }
+
+
+ printf("%-23s%d ", label, chains);
+ if (!verbose) {
+ switch (channel_bandwidth) {
+ case WL_BW_2P5MHZ:
+ printf("%s\n", rate2P5);
+ break;
+ case WL_BW_5MHZ:
+ printf("%s\n", rate5);
+ break;
+ case WL_BW_10MHZ:
+ printf("%s\n", rate10);
+ break;
+ case WL_BW_20MHZ:
+ printf("%s\n", rate20);
+ break;
+ case WL_BW_40MHZ:
+ printf("%s%s\n", rate20in40, rate40);
+ break;
+ case WL_BW_80MHZ:
+ printf("%s%s%s\n", rate20in80, rate40in80, rate80);
+ break;
+ case WL_BW_160MHZ:
+ printf("%s%s%s%s\n", rate20in160, rate40in160, rate80in160, rate160);
+ break;
+ case WL_BW_8080MHZ:
+ printf("%s%s%s%s%s\n", rate20in8080, rate40in8080, rate80in8080,
+ rate8080, rate8080chan2);
+ break;
+ }
+ } else {
+ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ rate2P5, rate5, rate10,
+ rate20, rate20in40, rate40, rate20in80, rate40in80, rate80,
+ rate20in160, rate40in160, rate80in160, rate160,
+ rate20in8080, rate40in8080, rate80in8080, rate8080, rate8080chan2);
+ }
+
+}
+
+static void
+wl_txpwr_array_row_print(ppr_t *pprptr, int8 channel_bandwidth, reg_rate_index_t rate_index)
+{
+ const char *label;
+ txpwr_row_t powers;
+ memset(&powers, (unsigned char)WL_RATE_DISABLED, sizeof(txpwr_row_t));
+
+ if (rate_index == NO_RATE)
+ {
+ printf("(NO_RATE) - - - - "
+ "- - - - "
+ "- - - - - - - - "
+ "- - - \n");
+ }
+ else
+ {
+ clm_rate_group_id_t group_id = ppr_table[rate_index].id;
+ label = ppr_table[rate_index].label;
+
+ switch (channel_bandwidth) {
+ case WL_BW_2P5MHZ:
+ powers.pwr2p5 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_2P5);
+ break;
+
+ case WL_BW_5MHZ:
+ powers.pwr5 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_5);
+ break;
+
+ case WL_BW_10MHZ:
+ powers.pwr10 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_10);
+ break;
+
+ case WL_BW_20MHZ:
+ powers.pwr20 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20);
+ break;
+
+ case WL_BW_40MHZ:
+ powers.pwr20in40 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20IN40);
+ powers.pwr40 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_40);
+ break;
+
+ case WL_BW_80MHZ:
+ powers.pwr80 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_80);
+ powers.pwr20in80 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20IN80);
+ powers.pwr40in80 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_40IN80);
+ break;
+
+ case WL_BW_160MHZ:
+ powers.pwr160 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_160);
+ powers.pwr20in160 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20IN160);
+ powers.pwr40in160 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_40IN160);
+ powers.pwr80in160 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_80IN160);
+ break;
+
+ case WL_BW_8080MHZ:
+ powers.pwr8080 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_8080);
+ powers.pwr8080chan2 = wl_ppr_get_pwr(pprptr, rate_index,
+ WL_TX_BW_8080CHAN2);
+ powers.pwr20in8080 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20IN8080);
+ powers.pwr40in8080 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_40IN8080);
+ powers.pwr80in8080 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_80IN8080);
+ break;
+ }
+
+ wl_txpwr_print_row(label, ppr_group_table[group_id].chain, powers,
+ WL_RATE_DISABLED, channel_bandwidth, TRUE);
+ }
+}
+
+void
+wl_txpwr_print_header(int8 channel_bandwidth, bool verbose)
+{
+ if (!verbose)
+ {
+ switch (channel_bandwidth) {
+ case WL_BW_2P5MHZ:
+ printf("Rate Chains 2.5MHz\n");
+ break;
+ case WL_BW_5MHZ:
+ printf("Rate Chains 5MHz\n");
+ break;
+ case WL_BW_10MHZ:
+ printf("Rate Chains 10MHz\n");
+ break;
+ case WL_BW_20MHZ:
+ printf("Rate Chains 20MHz\n");
+ break;
+ case WL_BW_40MHZ:
+ printf("Rate Chains 20in40 40MHz\n");
+ break;
+ case WL_BW_80MHZ:
+ printf("Rate Chains 20in80 40in80 80MHz\n");
+ break;
+ case WL_BW_160MHZ:
+ printf(" 20in 40in 80in\n");
+ printf("Rate Chains 160 160 160 160\n");
+ break;
+ case WL_BW_8080MHZ:
+ printf(" 20in 40in 80in chan1 chan2\n");
+ printf("Rate Chains 80+80 80+80 80+80 80+80 80+80\n");
+ break;
+
+ }
+ } else {
+ printf(" 20in"
+ " 20in 40in 20in 40in 80in 20in 40in "
+ "80in chan1 chan2\n");
+ printf("Rate Chains 2.5 5 10 20 40 40"
+ " 80 80 80 160 160 160 160 80+80"
+ " 80+80 80+80 80+80 80+80\n");
+ }
+}
+
+static void
+wl_txpwr_array_print(ppr_t* pprptr, int8 bw, bool verbose, bool is5G)
+{
+ clm_rate_group_id_t i;
+ reg_rate_index_t rate_index = DSSS1;
+ wl_txpwr_print_header(bw, verbose);
+ for (i = RATE_GROUP_ID_DSSS; i < RATE_GROUP_ID_COUNT; i++) {
+ wl_txpwr_ppr_print(pprptr, verbose, ppr_group_table[i].rate_type, i, bw,
+ &rate_index, is5G);
+ /* VHT rates are printed in three parts: MCS + VHT8_9 and VHT10_11 */
+ if (ppr_group_table[i].rate_type == PPR_RATE_VHT)
+ i+=2; /* Skip VHT groups because it is alread printed */
+ }
+}
+
+
+/* Print power values for a group of rates. If not in verbose mode and rates
+ * are uniform, only one power value per channel is printed for the whole group
+ */
+static void
+wl_txpwr_ppr_print(ppr_t* pprptr, int vb, ppr_rate_type_t type,
+ clm_rate_group_id_t gid, int8 bw, reg_rate_index_t *rate_index, bool is5G)
+{
+ int8* rates[5] = {0}; /* Dynamic array of up to 5 ratesets for each channel in bw */
+ uint nchannels, rateset_sz;
+ uint vht_extra_rateset_sz = WL_RATESET_SZ_VHT_MCS - WL_RATESET_SZ_HT_MCS;
+ uint vht_prop_sz = WL_RATESET_SZ_VHT_MCS_P - WL_RATESET_SZ_VHT_MCS;
+ uint i, j;
+ const char *label;
+ uint buniform;
+ uint8 chains = ppr_group_table[gid].chain;
+
+ if (pprptr == NULL) {
+ fprintf(stderr, "illegal ppr data!\n");
+ return;
+ }
+
+ switch (bw) {
+ case WL_BW_2P5MHZ:
+ case WL_BW_5MHZ:
+ case WL_BW_10MHZ:
+ case WL_BW_20MHZ:
+ nchannels = 1;
+ break;
+ case WL_BW_40MHZ:
+ nchannels = 2;
+ break;
+ case WL_BW_80MHZ:
+ nchannels = 3;
+ break;
+ case WL_BW_160MHZ:
+ nchannels = 4;
+ break;
+ case WL_BW_8080MHZ:
+ nchannels = 5;
+ break;
+ default:
+ fprintf(stderr, "Error: Unknown bandwidth %d\n", bw);
+ return;
+ }
+
+ switch (type) {
+ case PPR_RATE_DSSS:
+ rateset_sz = sizeof(ppr_dsss_rateset_t);
+ break;
+ case PPR_RATE_OFDM:
+ rateset_sz = sizeof(ppr_ofdm_rateset_t);
+ break;
+ case PPR_RATE_HT:
+ rateset_sz = sizeof(ppr_ht_mcs_rateset_t);
+ break;
+ case PPR_RATE_VHT:
+ rateset_sz = sizeof(ppr_vht_mcs_rateset_t);
+ break;
+ default:
+ fprintf(stderr, "Error: Unknown rate %d\n", type);
+ return;
+ }
+
+ /* Allocate nchannel * rateset_sz array of powers */
+ for (i = 0; i < nchannels; i++) {
+ if ((rates[i] = (int8*)malloc(sizeof(int8) * rateset_sz)) == NULL) {
+ fprintf(stderr, "Error allocating rates array\n");
+ for (j = 0; j < i; j++) free(rates[j]);
+ return;
+ }
+ }
+
+ /* Load channel ratesets for specific type and group id into rate array */
+ switch (bw) {
+ case WL_BW_2P5MHZ:
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_2P5, rates[0]);
+ break;
+ case WL_BW_5MHZ:
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_5, rates[0]);
+ break;
+ case WL_BW_10MHZ:
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_10, rates[0]);
+ break;
+ case WL_BW_20MHZ:
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_20, rates[0]);
+ break;
+ case WL_BW_40MHZ:
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_40, rates[0]);
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_20IN40, rates[1]);
+ break;
+ case WL_BW_80MHZ:
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_80, rates[0]);
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_40IN80, rates[1]);
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_20IN80, rates[2]);
+ break;
+ case WL_BW_160MHZ:
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_160, rates[0]);
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_80IN160, rates[1]);
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_40IN160, rates[2]);
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_20IN160, rates[3]);
+ break;
+ case WL_BW_8080MHZ:
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_8080, rates[0]);
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_80IN8080, rates[1]);
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_40IN8080, rates[2]);
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_20IN8080, rates[3]);
+ wl_txpwr_ppr_get_rateset(pprptr, type, gid, WL_TX_BW_8080CHAN2, rates[4]);
+ break;
+ }
+
+ if (type == PPR_RATE_DSSS && is5G) {
+ int tx_pwr_min = ppr_get_min(pprptr, WL_RATE_DISABLED);
+ for (i = 0; i < nchannels; i++) {
+ for (j = 0; j < rateset_sz; j++) {
+ if (rates[i][j] == tx_pwr_min)
+ rates[i][j] = WL_RATE_DISABLED;
+ }
+ }
+ }
+
+ /* Split VHT rates into different groups. */
+ if (type == PPR_RATE_VHT) {
+ rateset_sz -= (sizeof(ppr_vht_mcs_rateset_t) - sizeof(ppr_ht_mcs_rateset_t));
+
+ }
+
+ /* Uniform group if for each channel, all rates are equal */
+ buniform = !vb;
+ for (i = 0; i < nchannels && buniform; i++) {
+ buniform &= wl_array_check_val(rates[i], rateset_sz, rates[i][0]);
+ }
+
+ if (buniform) {
+ /* Uniform, so just print first rate */
+ label = get_clm_rate_group_label(gid);
+ if (strcmp(label, ""))
+ wl_txpwr_ppr_print_row(label, chains, bw, vb, rates, 0);
+ } else {
+ for (i = 0; i < rateset_sz; i++) {
+ label = ppr_table[*rate_index + i].label;
+ if (strcmp(label, ""))
+ wl_txpwr_ppr_print_row(label, chains, bw, vb, rates, i);
+ }
+ }
+
+ /* Print VHT8-9 and VHT10-11 as seperate groups */
+ if (type == PPR_RATE_VHT) {
+ /* VHT8-9 */
+ buniform = !vb;
+ for (i = 0; i < nchannels && buniform; i++) {
+ int8* vht_extra_rateset = &rates[i][rateset_sz];
+ buniform &= wl_array_check_val(vht_extra_rateset, vht_extra_rateset_sz,
+ vht_extra_rateset[0]);
+ }
+
+ if (buniform) {
+ /* Uniform, so just print first extra rate */
+ label = get_clm_rate_group_label(gid+1); /* VHT8-9 label */
+ if (strcmp(label, ""))
+ wl_txpwr_ppr_print_row(label, chains, bw, vb, rates, rateset_sz);
+ } else {
+ for (i = rateset_sz; i < (rateset_sz + vht_extra_rateset_sz); i++) {
+ label = ppr_table[*rate_index + i].label;
+ if (strcmp(label, ""))
+ wl_txpwr_ppr_print_row(label, chains, bw, vb, rates, i);
+ }
+ }
+
+ /* VHT10-11 */
+ buniform = !vb;
+ for (i = 0; i < nchannels && buniform; i++) {
+ int8* vht_prop_rateset = &rates[i][rateset_sz + vht_extra_rateset_sz];
+ buniform &= wl_array_check_val(vht_prop_rateset, vht_prop_sz,
+ vht_prop_rateset[0]);
+ }
+
+ if (buniform) {
+ /* Uniform, so just print first extra rate */
+ label = get_clm_rate_group_label(gid+2); /* VHT10-11 label */
+ if (strcmp(label, ""))
+ wl_txpwr_ppr_print_row(label, chains, bw, vb, rates,
+ rateset_sz + vht_extra_rateset_sz);
+ } else {
+ i = rateset_sz + vht_extra_rateset_sz;
+ for (; i < (rateset_sz + vht_extra_rateset_sz + vht_prop_sz);
+ i++) {
+ label = ppr_table[*rate_index + i].label;
+ if (strcmp(label, ""))
+ wl_txpwr_ppr_print_row(label, chains, bw, vb, rates, i);
+ }
+ }
+ }
+
+ *rate_index += rateset_sz;
+ if (type == PPR_RATE_VHT) {
+ *rate_index += (vht_extra_rateset_sz + vht_prop_sz);
+ }
+
+ for (i = 0; i < nchannels; i++) {
+ free(rates[i]);
+ }
+}
+
+/* Print row of power values for a specific rate. */
+void wl_txpwr_ppr_print_row(const char* label, int8 chains, int8 bw, bool vb,
+ int8** rates, uint rate_index)
+{
+ txpwr_row_t powers;
+ memset(&powers, (unsigned char)WL_RATE_DISABLED, sizeof(txpwr_row_t));
+
+ /* Set relevant power values based on bandwidth */
+ switch (bw) {
+ case WL_BW_2P5MHZ:
+ powers.pwr2p5 = rates[0][rate_index];
+ break;
+ case WL_BW_5MHZ:
+ powers.pwr5 = rates[0][rate_index];
+ break;
+ case WL_BW_10MHZ:
+ powers.pwr10 = rates[0][rate_index];
+ break;
+ case WL_BW_20MHZ:
+ powers.pwr20 = rates[0][rate_index];
+ break;
+ case WL_BW_40MHZ:
+ powers.pwr40 = rates[0][rate_index];
+ powers.pwr20in40 = rates[1][rate_index];
+ break;
+ case WL_BW_80MHZ:
+ powers.pwr80 = rates[0][rate_index];
+ powers.pwr40in80 = rates[1][rate_index];
+ powers.pwr20in80 = rates[2][rate_index];
+ break;
+ case WL_BW_160MHZ:
+ powers.pwr160 = rates[0][rate_index];
+ powers.pwr80in160 = rates[1][rate_index];
+ powers.pwr40in160 = rates[2][rate_index];
+ powers.pwr20in160 = rates[3][rate_index];
+ break;
+ case WL_BW_8080MHZ:
+ powers.pwr8080 = rates[0][rate_index];
+ powers.pwr80in8080 = rates[1][rate_index];
+ powers.pwr40in8080 = rates[2][rate_index];
+ powers.pwr20in8080 = rates[3][rate_index];
+ powers.pwr8080chan2 = rates[4][rate_index];
+ break;
+ default:
+ break;
+ }
+
+ wl_txpwr_print_row(label, chains, powers, WL_RATE_DISABLED, bw, vb);
+}
+
+/* Helper function which gets arbitrary rateset as a function of rate_type.
+ * Returns rateset into a int8 array.
+ */
+void wl_txpwr_ppr_get_rateset(ppr_t* pprptr, ppr_rate_type_t type,
+ clm_rate_group_id_t gid, wl_tx_bw_t bw, int8* rateset)
+{
+ const ppr_group_t* group = &ppr_group_table[gid];
+ switch (type) {
+ case PPR_RATE_DSSS:
+ /* ASSERT(rateset_sz == sizeof(ppr_dsss_rateset_t)) */
+ ppr_get_dsss(pprptr, bw, group->chain,
+ (ppr_dsss_rateset_t*)rateset);
+ break;
+ case PPR_RATE_OFDM:
+ /* ASSERT(rateset_sz == sizeof(ppr_ofdm_rateset_t)) */
+ ppr_get_ofdm(pprptr, bw, group->mode, group->chain,
+ (ppr_ofdm_rateset_t*)rateset);
+ break;
+ case PPR_RATE_HT:
+ /* ASSERT(rateset_sz == sizeof(ppr_ht_mcs_rateset_t)) */
+ ppr_get_ht_mcs(pprptr, bw, group->nss, group->mode, group->chain,
+ (ppr_ht_mcs_rateset_t*)rateset);
+ break;
+ case PPR_RATE_VHT:
+ /* ASSERT(rateset_sz == sizeof(ppr_vht_mcs_rateset_t)) */
+ ppr_get_vht_mcs(pprptr, bw, group->nss, group->mode, group->chain,
+ (ppr_vht_mcs_rateset_t*)rateset);
+ break;
+ default:
+ /* ASSERT(0) */
+ break;
+ }
+}
+
+/* helper function to check if the array are uniformly same as the input value */
+static int wl_array_check_val(int8 *pwr, uint count, int8 val)
+{
+ uint i;
+ for (i = 0; i < count; i++) {
+ if (pwr[i] != val)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#define WL_JOIN_PARAMS_MAX WL_JOIN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(chanspec_t)
+
+/* when prescanned option is specified */
+static int
+wl_join_prescanned(void *wl, wl_join_params_t *join_params, uint *join_params_size)
+{
+ /* load with prescanned channels and bssids */
+ int ret, err = 0;
+ char *destbuf;
+ wl_scan_results_t *scanres = NULL;
+ wl_bss_info_t *bi;
+ uint i, cnt, bssid_cnt, bi_len;
+
+ if ((destbuf = malloc(WL_DUMP_BUF_LEN)) == NULL) {
+ fprintf(stderr, "Failed to allocate %d-byte buffer for scanresults\n",
+ WL_DUMP_BUF_LEN);
+ err = BCME_NOMEM;
+ goto pexit;
+ }
+
+ if ((ret = wl_get_scan(wl, WLC_SCAN_RESULTS, destbuf, WL_DUMP_BUF_LEN)) != 0) {
+ fprintf(stderr, "failed to fetch scan results, err %d\n", ret);
+ err = ret;
+ goto pexit;
+ }
+
+ scanres = (wl_scan_results_t *)destbuf;
+ if (scanres->version != WL_BSS_INFO_VERSION) {
+ fprintf(stderr, "scan parsing failed (expect version %d, got %d)\n",
+ WL_BSS_INFO_VERSION, scanres->version);
+ err = -1;
+ goto pexit;
+ }
+
+ /* find matching ssids to fill the channel list */
+ for (cnt = i = 0, bi = scanres->bss_info; i < scanres->count;
+ i++, bi = (wl_bss_info_t*)((int8*)bi + bi_len)) {
+ bi_len = dtoh32(bi->length);
+ if ((bi->SSID_len != join_params->ssid.SSID_len) ||
+ memcmp(bi->SSID, join_params->ssid.SSID,
+ join_params->ssid.SSID_len)) {
+ continue;
+ } else {
+ dump_bss_info(bi);
+ printf("--------------------------------\n");
+ }
+
+ memcpy(&join_params->params.chanspec_list[cnt],
+ &bi->chanspec, sizeof(chanspec_t));
+ cnt++;
+ }
+ bssid_cnt = (uint16)cnt;
+
+ /* append the corresponding bssids */
+ destbuf = (char*)&join_params->params.chanspec_list[cnt];
+ *join_params_size = destbuf - (char*)join_params;
+ *join_params_size += (cnt * sizeof(struct ether_addr));
+
+ if (*join_params_size > WL_JOIN_PARAMS_MAX) {
+ fprintf(stderr, "Can't fit bssids for all %d APs found\n", cnt);
+ err = -1;
+ goto pexit;
+ }
+
+ for (cnt = i = 0, bi = scanres->bss_info;
+ (i < scanres->count) && (cnt < bssid_cnt);
+ i++, bi = (wl_bss_info_t*)((int8*)bi + bi_len)) {
+ bi_len = dtoh32(bi->length);
+ if ((bi->SSID_len != join_params->ssid.SSID_len) ||
+ memcmp(bi->SSID, join_params->ssid.SSID,
+ join_params->ssid.SSID_len)) {
+ continue;
+ }
+
+ memcpy(destbuf, &bi->BSSID, sizeof(struct ether_addr));
+ destbuf += sizeof(struct ether_addr);
+ cnt++;
+ }
+
+ if (cnt != bssid_cnt) {
+ fprintf(stderr, "Mismatched channel and bssid counts!\n");
+ err = -1;
+ goto pexit;
+ }
+
+ if (cnt == 0) {
+ printf("No matches found, issuing normal join.\n");
+ } else {
+ printf("Passing %d channel/bssid pairs.\n", cnt);
+ }
+ join_params->params.bssid_cnt = htod16(bssid_cnt);
+
+pexit:
+ if (scanres)
+ free((char*)scanres);
+ else
+ free(destbuf);
+ return err;
+}
+
+/* wl join <ssid> [key <0-3>:xxxxx]
+ * [imode bss|ibss]
+ * [amode open|shared|openshared|wpa|wpapsk|wpa2|wpa2psk|wpanone|ftpsk]
+ * [options]
+ * Options:
+ * -b MAC, --bssid=MAC, where MAC is in xx:xx:xx:xx:xx:xx format
+ * -c CL, --chanspecs=CL, where CL is a comma or space separated list of chanspecs
+ * -p, -passive: uses join iovar instead of SET_SSID ioctl to force passive assoc scan
+ */
+
+static int
+wl_join(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK, idx = 0;
+ wl_join_params_t *join_params;
+ uint join_params_size;
+ wl_wsec_key_t key;
+ int wsec = 0, auth = 0, infra = 1;
+ int wpa_auth = WPA_AUTH_DISABLED;
+ char* cmd_name;
+ bool prescanned = FALSE;
+ int passive = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ cmd_name = *argv++;
+
+ /* allocate the max storage */
+ join_params_size = WL_JOIN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(chanspec_t);
+ if ((join_params = malloc(join_params_size)) == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for assoc params\n", join_params_size);
+ return BCME_NOMEM;
+ }
+ memset(join_params, 0, join_params_size);
+ memcpy(&join_params->params.bssid, ðer_bcast, ETHER_ADDR_LEN);
+
+ /* verify that SSID was specified and is a valid length */
+ if (!*argv || (strlen(*argv) > DOT11_MAX_SSID_LEN)) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ join_params->ssid.SSID_len = strlen(*argv);
+ memcpy(join_params->ssid.SSID, *argv, join_params->ssid.SSID_len);
+
+ /* default to plain old ioctl */
+ join_params_size = sizeof(wlc_ssid_t);
+
+ /* get infrastructure mode */
+ if (wlu_iovar_getint(wl, "infra_configuration", &infra) < 0) {
+ fprintf(stderr, "iovar infra_configuration GET failed, ret %d\n", ret);
+ goto exit;
+ }
+ infra = dtoh32(infra);
+
+ /* get authentication mode */
+ if ((ret = wlu_get(wl, WLC_GET_AUTH, &auth, sizeof(int))) < 0) {
+ fprintf(stderr, "ioctl WLC_GET_AUTH failed, ret %d\n", ret);
+ goto exit;
+ }
+ auth = dtoh32(auth);
+
+ /* get current wsec */
+ if (wlu_iovar_getint(wl, "wsec", &wsec) < 0) {
+ wsec = 0;
+ }
+ wsec = dtoh32(wsec);
+
+ /* get WPA_auth mode */
+ if ((ret = wlu_get(wl, WLC_GET_WPA_AUTH, &wpa_auth, sizeof(wpa_auth))) < 0) {
+ fprintf(stderr, "ioctl WLC_GET_WPA_AUTH failed, ret %d\n", ret);
+ goto exit;
+ }
+ wpa_auth = dtoh32(wpa_auth);
+
+ while (*++argv) {
+ if (!stricmp(*argv, "wepkey") || !stricmp(*argv, "wep") || !stricmp(*argv, "key")) {
+ /* specified wep key */
+ memset(&key, 0, sizeof(key));
+ if (!*++argv) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /* WEP index specified */
+ if (*(argv[0]+1) == ':') {
+ idx = *argv[0] - 0x30;
+ if (idx < 0 || idx > 3) {
+ fprintf(stderr, "Invalid key index %d specified\n", idx);
+ ret = BCME_BADARG;
+ goto exit;
+ }
+ argv[0] += 2; /* colon + digit */
+ }
+ key.index = idx;
+
+ if (parse_wep(argv, &key, FALSE)) {
+ ret = BCME_BADARG;
+ goto exit;
+ }
+
+ key.index = htod32(key.index);
+ key.len = htod32(key.len);
+ key.algo = htod32(key.algo);
+ key.flags = htod32(key.flags);
+
+ if ((ret = wlu_set(wl, WLC_SET_KEY, &key, sizeof(wl_wsec_key_t))) < 0) {
+ goto exit;
+ }
+ wsec |= WEP_ENABLED;
+ }
+ /* specified infrastructure mode */
+ else if (!stricmp(*argv, "imode") ||
+ !stricmp(*argv, "infra") ||
+ !stricmp(*argv, "mode")) {
+ if (!*++argv) {
+ fprintf(stderr, "%s %s: expected argument after \"infra\" keyword "
+ "but command line ended.\n", wlu_av0, cmd_name);
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ } else if (!stricmp(*argv, "ibss") ||
+ !stricmp(*argv, "adhoc") ||
+ !stricmp(*argv, "ad-hoc")) {
+ infra = WL_BSSTYPE_INDEP;
+ } else if (!stricmp(*argv, "bss") ||
+ !stricmp(*argv, "managed") ||
+ !strnicmp(*argv, "infra", 5)) {
+ infra = WL_BSSTYPE_INFRA;
+ } else {
+ fprintf(stderr, "%s %s: unrecongnized parameter \"%s\" after "
+ "\"infra\" keyword\n", wlu_av0, cmd_name, *argv);
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ /* specified authentication mode */
+ else if (!stricmp(*argv, "amode") || !strnicmp(*argv, "auth", 4)) {
+ if (!*++argv) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ auth = WL_AUTH_OPEN_SYSTEM;
+ wpa_auth = WPA_AUTH_DISABLED;
+ if (!stricmp(*argv, "open"))
+ auth = WL_AUTH_OPEN_SYSTEM;
+ else if (!stricmp(*argv, "shared"))
+ auth = WL_AUTH_SHARED_KEY;
+ else if (!stricmp(*argv, "openshared"))
+ auth = WL_AUTH_OPEN_SHARED;
+ else if (!stricmp(*argv, "wpanone"))
+ wpa_auth = WPA_AUTH_NONE;
+ else if (!stricmp(*argv, "wpa"))
+ wpa_auth = WPA_AUTH_UNSPECIFIED;
+ else if (!stricmp(*argv, "wpapsk"))
+ wpa_auth = WPA_AUTH_PSK;
+ else if (!stricmp(*argv, "wpa2"))
+ wpa_auth = WPA2_AUTH_UNSPECIFIED;
+ else if (!stricmp(*argv, "wpa2psk"))
+ wpa_auth = WPA2_AUTH_PSK;
+#ifdef BCMWAPI_WAI
+ else if (!stricmp(*argv, "wapi"))
+ wpa_auth = WAPI_AUTH_UNSPECIFIED;
+ else if (!stricmp(*argv, "wapipsk"))
+ wpa_auth = WAPI_AUTH_PSK;
+#endif /* BCMWAPI_WAI */
+ else if (!stricmp(*argv, "ftpsk"))
+ wpa_auth = WPA2_AUTH_PSK | WPA2_AUTH_FT;
+ else if (!stricmp(*argv, "wpa2-sha256"))
+ wpa_auth = WPA2_AUTH_1X_SHA256;
+ else if (!stricmp(*argv, "wpa2psk-sha256"))
+ wpa_auth = WPA2_AUTH_PSK_SHA256;
+ else {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ else if (!stricmp(*argv, "-passive") || !stricmp(*argv, "-p")) {
+ /* Use extended join iovar to assoc_scan passively */
+ passive = 1;
+ }
+ /* optional assoc params */
+ else if ((ret = wl_parse_assoc_params(argv, &join_params->params,
+ &prescanned)) == BCME_OK) {
+ join_params_size = WL_JOIN_PARAMS_FIXED_SIZE +
+ dtoh32(join_params->params.chanspec_num) * sizeof(chanspec_t);
+ break;
+ }
+ else {
+ fprintf(stderr, "%s %s: unable to parse parameter \"%s\"\n",
+ wlu_av0, cmd_name, *argv);
+ goto exit;
+ }
+ }
+
+ /* set infrastructure mode */
+ infra = htod32(infra);
+ if ((ret = wlu_set(wl, WLC_SET_INFRA, &infra, sizeof(int))) < 0) {
+ fprintf(stderr, "ioctl WLC_SET_INFRA failed, ret %d\n", ret);
+ goto exit;
+ }
+
+ /* set authentication mode */
+ auth = htod32(auth);
+ if ((ret = wlu_set(wl, WLC_SET_AUTH, &auth, sizeof(int))) < 0) {
+ fprintf(stderr, "ioctl WLC_SET_AUTH failed, ret %d\n", ret);
+ goto exit;
+ }
+
+ /* set wsec mode */
+ wsec = htod32(wsec);
+ if ((ret = wlu_iovar_setint(wl, "wsec", wsec)) < 0) {
+ fprintf(stderr, "iovar wsec SET failed, ret %d\n", ret);
+ goto exit;
+ }
+
+ /* set WPA_auth mode */
+ wpa_auth = htod32(wpa_auth);
+ if ((ret = wlu_set(wl, WLC_SET_WPA_AUTH, &wpa_auth, sizeof(wpa_auth))) < 0) {
+ fprintf(stderr, "ioctl WLC_SET_WPA_AUTH failed, ret %d\n", ret);
+ goto exit;
+ }
+
+ if (passive) {
+ wl_extjoin_params_t *extjoin_params;
+ int extjoin_size;
+ int i;
+ printf("Using passive assoc scan\n");
+ extjoin_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
+ join_params->params.chanspec_num * sizeof(chanspec_t);
+ if ((extjoin_params = malloc(extjoin_size)) == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for extjoin \n", extjoin_size);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ /* Copy assoc params from legacy struct into extended struct */
+ memset(extjoin_params, 0, extjoin_size);
+ memcpy(&extjoin_params->ssid.SSID, &join_params->ssid.SSID, DOT11_MAX_SSID_LEN);
+ extjoin_params->ssid.SSID_len = htod32(join_params->ssid.SSID_len);
+
+ memcpy(&extjoin_params->assoc.bssid, &join_params->params.bssid, ETHER_ADDR_LEN);
+ extjoin_params->assoc.chanspec_num = join_params->params.chanspec_num;
+ for (i = 0; i < join_params->params.chanspec_num; i++) {
+ extjoin_params->assoc.chanspec_list[i] =
+ join_params->params.chanspec_list[i];
+ }
+
+ extjoin_params->scan.scan_type = WL_SCANFLAGS_PASSIVE;
+ extjoin_params->scan.nprobes = -1;
+ extjoin_params->scan.active_time = -1;
+ extjoin_params->scan.passive_time = -1;
+ extjoin_params->scan.home_time = -1;
+
+
+ ret = wlu_var_setbuf(wl, "join", extjoin_params, extjoin_size);
+ free(extjoin_params);
+ } else {
+ /* join parameters starts with the ssid */
+ join_params->ssid.SSID_len = htod32(join_params->ssid.SSID_len);
+
+ if (prescanned) {
+ if ((ret = wl_join_prescanned(wl, join_params, &join_params_size)) < 0)
+ goto exit;
+ }
+
+ ret = wlu_set(wl, WLC_SET_SSID, join_params, join_params_size);
+ }
+
+exit:
+ free(join_params);
+ return ret;
+}
+
+/* Set or Get the "bssid" iovar, with an optional config index argument:
+ * wl bssid [-C N]|[--cfg=N] bssid
+ *
+ * Option:
+ * -C N
+ * --cfg=N
+ * --config=N
+ * --configuration=N
+ * specify the config index N
+ * If cfg index not given on a set, the WLC_SET_BSSID ioctl will be used
+ */
+static int
+wl_bssid(void *wl, cmd_t *cmd, char **argv)
+{
+ struct ether_addr ea;
+ int bsscfg_idx = 0;
+ int consumed;
+ int error;
+
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((error = wl_cfg_option(argv, "bssid", &bsscfg_idx, &consumed)) != 0)
+ return error;
+
+ argv += consumed;
+
+ if (*argv == NULL) {
+ if (consumed == 0) {
+ /* no config index, use WLC_GET_BSSID on the interface */
+ error = wlu_get(wl, WLC_GET_BSSID, &ea, ETHER_ADDR_LEN);
+ } else {
+ /* use "bssid" iovar since a config option was given */
+ error = wlu_bssiovar_get(wl, "bssid", bsscfg_idx, &ea, ETHER_ADDR_LEN);
+ }
+ if (error < 0)
+ return error;
+ printf("%s\n", wl_ether_etoa(&ea));
+
+ } else {
+
+ if (!wl_ether_atoe(*argv, &ea))
+ return BCME_USAGE_ERROR;
+
+ if (consumed == 0) {
+ /* no config index given, use WLC_SET_BSSID */
+ error = wlu_set(wl, WLC_SET_BSSID, &ea, ETHER_ADDR_LEN);
+ } else {
+ /* use "bssid" iovar since a config option was given */
+ error = wl_bssiovar_set(wl, "bssid", bsscfg_idx, &ea, ETHER_ADDR_LEN);
+ }
+ }
+ return error;
+}
+
+/* Set or Get the "ssid" iovar, with an optional config index argument:
+ * wl ssid [-C N]|[--cfg=N] ssid
+ *
+ * Option:
+ * -C N
+ * --cfg=N
+ * --config=N
+ * --configuration=N
+ * specify the config index N
+ * If cfg index not given on a set, the WLC_SET_SSID ioctl will be used
+ */
+int
+wl_ssid(void *wl, cmd_t *cmd, char **argv)
+{
+ char ssidbuf[SSID_FMT_BUF_LEN];
+ wlc_ssid_t ssid = { 0, {0} };
+ int bsscfg_idx = 0;
+ int consumed;
+ int error;
+
+ argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((error = wl_cfg_option(argv, "ssid", &bsscfg_idx, &consumed)) != 0)
+ return error;
+
+ argv += consumed;
+
+ if (*argv == NULL) {
+ if (consumed == 0) {
+ /* no config index, use WLC_GET_SSID on the interface */
+ if (cmd->get == WLC_GET_SSID)
+ error = wlu_get(wl, WLC_GET_SSID, &ssid, sizeof(ssid));
+ else
+ error = wlu_iovar_get(wl, cmd->name, &ssid, sizeof(ssid));
+ } else {
+ if (cmd->get == WLC_GET_SSID) {
+ /* use "ssid" iovar since a config option was given */
+ error = wlu_bssiovar_get(wl, "ssid", bsscfg_idx, &ssid,
+ sizeof(ssid));
+ } else {
+ error = wlu_bssiovar_get(wl, cmd->name, bsscfg_idx, &ssid,
+ sizeof(ssid));
+ }
+ }
+ if (error < 0)
+ return error;
+
+ ssid.SSID_len = dtoh32(ssid.SSID_len);
+ wl_format_ssid(ssidbuf, ssid.SSID, ssid.SSID_len);
+ printf("Current %s: \"%s\"\n",
+ (cmd->get == WLC_GET_SSID)? "SSID": cmd->name,
+ ssidbuf);
+ } else {
+ if (strlen(argv[0]) > DOT11_MAX_SSID_LEN) {
+ fprintf(stderr, "SSID arg \"%s\" must be 32 chars or less\n", argv[0]);
+ return BCME_BADARG;
+ }
+ ssid.SSID_len = strlen(argv[0]);
+ memcpy(ssid.SSID, argv[0], ssid.SSID_len);
+
+ wl_format_ssid(ssidbuf, ssid.SSID, ssid.SSID_len);
+ printf("Setting %s: \"%s\"\n", (cmd->set == WLC_SET_SSID)? "SSID": cmd->name,
+ ssidbuf);
+
+ ssid.SSID_len = htod32(ssid.SSID_len);
+ if (consumed == 0) {
+ /* no config index given, use WLC_SET_SSID */
+ if (cmd->set == WLC_SET_SSID) {
+ error = wlu_set(wl, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
+ } else {
+ error = wlu_iovar_set(wl, cmd->name, &ssid, sizeof(wlc_ssid_t));
+ }
+ } else {
+ if (cmd->set == WLC_SET_SSID) {
+ /* use "ssid" iovar since a config option was given */
+ error = wl_bssiovar_set(wl, "ssid", bsscfg_idx, &ssid,
+ sizeof(wlc_ssid_t));
+ } else
+ error = wl_bssiovar_set(wl, cmd->name, bsscfg_idx, &ssid,
+ sizeof(wlc_ssid_t));
+ }
+ }
+ return error;
+}
+
+static const char*
+wl_smfs_map_type(uint8 type)
+{
+ static const struct {uint8 type; char name[32];} type_names[] = {
+ {SMFS_TYPE_AUTH, "Authentication_Request"},
+ {SMFS_TYPE_ASSOC, "Association_Request"},
+ {SMFS_TYPE_REASSOC, "Reassociation_Request"},
+ {SMFS_TYPE_DISASSOC_TX, "Disassociation_Request_TX"},
+ {SMFS_TYPE_DISASSOC_RX, "Disassociation_Request_RX"},
+ {SMFS_TYPE_DEAUTH_TX, "Deauthentication_Request_TX"},
+ {SMFS_TYPE_DEAUTH_RX, "Deauthentication_Request_RX"}
+ };
+
+ const char *tname = "UNKNOWN";
+ uint i;
+
+ for (i = 0; i < ARRAYSIZE(type_names); i++) {
+ if (type_names[i].type == type)
+ tname = type_names[i].name;
+ }
+ return tname;
+}
+
+static int
+wl_disp_smfs(char *inbuf)
+{
+ static const char *codename[] = {"Status_code", "Reason_code"};
+ wl_smf_stats_t *smf_stats;
+ wl_smfs_elem_t *elemt = NULL;
+ const char *namebuf;
+ uint32 version;
+ int count;
+
+ smf_stats = (wl_smf_stats_t *) inbuf;
+ namebuf = wl_smfs_map_type(smf_stats->type);
+
+ version = dtoh32(smf_stats->version);
+ if (version != SMFS_VERSION) {
+ fprintf(stderr, "Sorry, your driver has smfs_version %d "
+ "but this program supports only version %d.\n",
+ version, SMFS_VERSION);
+ return -1;
+ }
+
+ printf("Frame type: %s\n", namebuf);
+ printf("\tIgnored Count: %d\n", dtoh32(smf_stats->ignored_cnt));
+ printf("\tMalformed Count: %d\n", dtoh32(smf_stats->malformed_cnt));
+
+ count = dtoh32(smf_stats->count_total);
+
+ if (count) {
+ namebuf = codename[dtoh32(smf_stats->codetype)];
+ printf("\tSuccessful/Failed Count:\n");
+ elemt = &smf_stats->elem[0];
+ }
+
+ while (count) {
+ printf("\t\t%s %d Count: %d\n", namebuf, dtoh16(elemt->code),
+ dtoh32(elemt->count));
+ elemt ++;
+ count --;
+ }
+
+ return 0;
+
+}
+
+/*
+ * Check for the smfstats parameters. One of defined parameters can be passed in.
+ */
+static int
+wl_smfs_option(char **argv, int* idx, int *consumed, int* clear)
+{
+ int err = 0;
+ char *p;
+ char const * smfs_opt[] = {"auth", "assoc", "reassoc", "disassoc_tx",
+ "disassoc_rx", "deauth_tx", "deauth_rx"};
+ char const * clear_opt = "clear";
+ int i;
+ char const * cur_opt;
+
+ if (*argv == NULL) {
+ goto exit;
+ }
+
+ p = *argv++;
+
+ for (i = 0; i < SMFS_TYPE_MAX; i++) {
+ cur_opt = smfs_opt[i];
+ if (!strcmp(p, cur_opt)) {
+ *idx = i;
+ *consumed += 1;
+ goto exit;
+ }
+ }
+
+ if (!strcmp(p, clear_opt))
+ *clear = 1;
+
+exit:
+ return err;
+}
+
+/* Get or Clear (set) the "smfstats" iovar, with an optional config index argument:
+ * wl smfstats [-C N]|[--cfg=N] 0
+ *
+ * Option:
+ * -C N
+ * --cfg=N
+ * --config=N
+ * --configuration=N
+ * specify the config index N
+ * If cfg index not given on a set, the WLC_SET_SMF_STATS ioctl will be used
+ */
+static int
+wl_smfstats(void *wl, cmd_t *cmd, char **argv)
+{
+ int bsscfg_idx = 0;
+ int cfg_consumed = 0, smfs_consumed = 0;
+ int err;
+ int i, val;
+ int smf_index = 0;
+ int smfs_clear = 0;
+
+ BCM_REFERENCE(cmd);
+
+ argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((err = wl_cfg_option(argv, "smfstats", &bsscfg_idx, &cfg_consumed)) != 0)
+ return err;
+
+ argv += cfg_consumed;
+
+ if ((err = wl_smfs_option(argv, &smf_index, &smfs_consumed, &smfs_clear)) != 0)
+ return err;
+
+ if (!smfs_clear) {
+ if (cfg_consumed == 0) {
+ if (smfs_consumed) {
+ err = wlu_iovar_getbuf(wl, "smfstats", &smf_index, sizeof(int),
+ buf, WLC_IOCTL_SMLEN);
+ if (!err)
+ err = wl_disp_smfs(buf);
+ }
+ else {
+ for (i = 0; i < SMFS_TYPE_MAX; i++) {
+ smf_index = i;
+ err = wlu_iovar_getbuf(wl, "smfstats", &smf_index,
+ sizeof(int), buf, WLC_IOCTL_SMLEN);
+ if (!err)
+ err = wl_disp_smfs(buf);
+ }
+ }
+ } else {
+ /* use "stats" iovar since a config option was given */
+ if (smfs_consumed) {
+ err = wl_bssiovar_getbuf(wl, "smfstats", bsscfg_idx, &smf_index,
+ sizeof(int), buf, WLC_IOCTL_SMLEN);
+ if (!err)
+ err = wl_disp_smfs(buf);
+ }
+ else {
+ for (i = 0; i < SMFS_TYPE_MAX; i++) {
+ smf_index = i;
+ err = wl_bssiovar_getbuf(wl, "smfstats", bsscfg_idx,
+ &smf_index, sizeof(int), buf, WLC_IOCTL_SMLEN);
+ if (!err)
+ err = wl_disp_smfs(buf);
+ }
+ }
+ }
+ if (err < 0)
+ return err;
+ } else {
+ val = 0;
+
+ if (cfg_consumed == 0)
+ err = wlu_iovar_setint(wl, "smfstats", val);
+ else
+ err = wl_bssiovar_setint(wl, "smfstats", bsscfg_idx, val);
+
+ }
+ return err;
+}
+
+
+/* Quarter dBm units to mW
+ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
+ * Table is offset so the last entry is largest mW value that fits in
+ * a uint16.
+ */
+
+#define QDBM_OFFSET 153 /* QDBM_OFFSET */
+#define QDBM_TABLE_LEN 40 /* QDBM_TABLE_LEN */
+
+/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
+ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
+ */
+#define QDBM_TABLE_LOW_BOUND 6493 /* QDBM_TABLE_LOW_BOUND */
+
+/* Largest mW value that will round down to the last table entry,
+ * QDBM_OFFSET + QDBM_TABLE_LEN-1.
+ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
+ */
+#define QDBM_TABLE_HIGH_BOUND 64938 /* QDBM_TABLE_HIGH_BOUND */
+
+static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
+/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
+/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
+/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
+/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
+/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
+/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
+};
+
+static uint16
+wl_qdbm_to_mw(int8 qdbm)
+{
+ uint factor = 1;
+ int idx = qdbm - QDBM_OFFSET;
+
+ if (idx >= QDBM_TABLE_LEN) {
+ /* clamp to max uint16 mW value */
+ return 0xFFFF;
+ }
+
+ /* scale the qdBm index up to the range of the table 0-40
+ * where an offset of 40 qdBm equals a factor of 10 mW.
+ */
+ while (idx < 0) {
+ idx += 40;
+ factor *= 10;
+ }
+
+ /* return the mW value scaled down to the correct factor of 10,
+ * adding in factor/2 to get proper rounding.
+ */
+ return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
+}
+
+static int8
+wl_mw_to_qdbm(uint16 mw)
+{
+ uint8 qdbm;
+ int offset;
+ uint mw_uint = mw;
+ uint boundary;
+
+ /* handle boundary case */
+ if (mw_uint <= 1)
+ return WL_RATE_DISABLED;
+
+ offset = QDBM_OFFSET;
+
+ /* move mw into the range of the table */
+ while (mw_uint < QDBM_TABLE_LOW_BOUND) {
+ mw_uint *= 10;
+ offset -= 40;
+ }
+
+ for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
+ boundary = nqdBm_to_mW_map[qdbm] +
+ (nqdBm_to_mW_map[qdbm+1] - nqdBm_to_mW_map[qdbm])/2;
+ if (mw_uint < boundary) break;
+ }
+
+ qdbm += (int8)offset;
+
+ return (qdbm);
+}
+
+#define WLC_TXPWR_DB_FACTOR 4
+#define UNIT_MW 1 /* UNIT_MW */
+#define UNIT_QDBM 2 /* UNIT_QDBM */
+#define UNIT_DBM 3 /* UNIT_DBM */
+
+static int
+wl_txpwr1(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, val, new_val = 0, unit;
+ const char *name = "qtxpower";
+ bool override = FALSE;
+ int8 temp_val;
+
+ if (!*++argv) {
+ int divquo, divrem;
+ bool neg;
+
+ if (cmd->get < 0)
+ return -1;
+ if ((ret = wlu_iovar_getint(wl, name, &val)) < 0)
+ return ret;
+
+ override = ((val & WL_TXPWR_OVERRIDE) != 0);
+ val &= ~WL_TXPWR_OVERRIDE;
+ temp_val = (int8)(val & 0xff);
+
+ divquo = DIV_QUO(temp_val, 4);
+ divrem = DIV_REM(temp_val, 4);
+ neg = (divrem < 0) || (divquo < 0);
+ divrem = ABS(divrem);
+ divquo = ABS(divquo);
+ divquo = neg ? -divquo : divquo;
+
+ printf("TxPower is %d qdbm, %d.%d dbm, %d mW Override is %s\n",
+ temp_val, divquo, divrem,
+ (temp_val < 4) ? 0 : wl_qdbm_to_mw(temp_val),
+ override ? "On" : "Off");
+ return 0;
+ } else {
+ /* for set */
+ bool unit_set = FALSE;
+ unit = UNIT_DBM; /* default units */
+
+ /* override can be used in combo with any unit */
+ if (!strcmp(*argv, "-o")) {
+ override = TRUE;
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!strcmp(*argv, "-d")) {
+ unit = UNIT_DBM;
+ unit_set = TRUE;
+ argv++;
+ }
+ else if (!strcmp(*argv, "-q")) {
+ unit = UNIT_QDBM;
+ unit_set = TRUE;
+ argv++;
+ }
+ else if (!strcmp(*argv, "-m")) {
+ unit = UNIT_MW;
+ unit_set = TRUE;
+ argv++;
+ }
+
+ /* override can be used in combo with any unit */
+ if (!strcmp(*argv, "-o")) {
+ override = TRUE;
+ argv++;
+ }
+
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+
+ val = atoi(*argv);
+
+ if (!unit_set) {
+ if (val == -1) {
+ val = WLC_TXPWR_MAX; /* Max val of 127 qdbm */
+ unit = UNIT_QDBM;
+ } else if (val <= 0) {
+ return BCME_BADARG;
+ }
+ }
+
+ if ((val <= 0) && (unit == UNIT_MW)) {
+ return BCME_BADARG;
+ }
+
+ switch (unit) {
+ case UNIT_MW:
+ new_val = (uint8)wl_mw_to_qdbm((uint16)MIN(val, 0xffff));
+ break;
+ case UNIT_DBM:
+ if (val > (WLC_TXPWR_MAX / WLC_TXPWR_DB_FACTOR))
+ return BCME_BADARG;
+ val *= WLC_TXPWR_DB_FACTOR;
+ if (val < WL_RATE_DISABLED)
+ val = WL_RATE_DISABLED;
+ temp_val = (int8)val;
+ new_val = (uint8)temp_val; /* need to keep sign bit in low byte */
+ break;
+ case UNIT_QDBM:
+ if (val > WLC_TXPWR_MAX)
+ return BCME_BADARG;
+ if (val < WL_RATE_DISABLED)
+ val = WL_RATE_DISABLED;
+ temp_val = val;
+ new_val = (uint8)temp_val; /* need to keep sign bit in low byte */
+ break;
+ }
+
+ if (override)
+ new_val |= WL_TXPWR_OVERRIDE;
+
+ return wlu_iovar_setint(wl, name, new_val);
+ }
+}
+
+
+static int
+wl_txpwr(void *wl, cmd_t *cmd, char **argv)
+{
+ int error;
+ uint32 val;
+ char *endptr = NULL;
+ uint32 override;
+ const char *name = "qtxpower";
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!*++argv) {
+ if ((error = wlu_iovar_getint(wl, name, (int *)&val)) < 0)
+ return error;
+
+ /* Report power in mw with WL_TXPWR_OVERRIDE
+ * bit indicating the status
+ */
+ override = ((val & WL_TXPWR_OVERRIDE) != 0);
+ val &= ~WL_TXPWR_OVERRIDE;
+ printf("%d.%d dBm = %d mw. %s\n", DIV_QUO(val, 4), DIV_REM(val, 4),
+ wl_qdbm_to_mw((uint8)(MIN(val, 0xff))), (override ? "(Override ON)" : ""));
+ return 0;
+ } else {
+ if (!strcmp(*argv, "-u")) {
+ override = 0;
+ argv++;
+ } else
+ override = WL_TXPWR_OVERRIDE;
+
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+
+ val = wl_mw_to_qdbm((uint16)MIN(val, 0xffff));
+
+ /* wl command input power will override current power set if told so */
+ val |= override;
+
+ return wlu_iovar_setint(wl, name, val);
+ }
+}
+
+static int
+wl_get_txpwr_limit(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ uint8 val_qdbm;
+ uint16 val_mw;
+ tx_power_legacy_t power;
+
+ UNUSED_PARAMETER(argv);
+
+ ret = wlu_get(wl, cmd->get, &power, sizeof(power));
+ if (ret < 0)
+ return ret;
+
+ val_qdbm = MIN(power.txpwr_band_max[0], power.txpwr_local_max);
+ val_mw = wl_qdbm_to_mw((uint8)(MIN(val_qdbm, 0xff)));
+
+ printf("%d mW (%d.%d dBm)\n", val_mw, DIV_QUO(val_qdbm, 4), DIV_REM(val_qdbm, 4));
+
+ return ret;
+}
+
+int
+wl_maclist(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ struct maclist *maclist = (struct maclist *) buf;
+ struct ether_addr *ea;
+ uint i, max = (WLC_IOCTL_MEDLEN - sizeof(int)) / ETHER_ADDR_LEN;
+ uint len;
+ struct ether_addr tmp_ea;
+ bool found;
+
+ if (!*++argv) {
+ if (cmd->get < 0)
+ return -1;
+ maclist->count = htod32(max);
+ if ((ret = wlu_get(wl, cmd->get, maclist, WLC_IOCTL_MEDLEN)) < 0)
+ return ret;
+ maclist->count = dtoh32(maclist->count);
+ for (i = 0, ea = maclist->ea; i < maclist->count && i < max; i++, ea++)
+ printf("%s %s\n", cmd->name, wl_ether_etoa(ea));
+ return 0;
+ } else {
+ if (cmd->set < 0)
+ return -1;
+ /* Clear list */
+ maclist->count = htod32(0);
+ if (!strncmp(*argv, "none", strlen("none")) ||
+ !strncmp(*argv, "clear", strlen("clear")))
+ return wlu_set(wl, cmd->set, maclist, sizeof(int));
+ /* Get old list */
+ maclist->count = htod32(max);
+ if ((ret = wlu_get(wl, cmd->get, maclist, WLC_IOCTL_MEDLEN)) < 0)
+ return ret;
+ /* Append to old list */
+ maclist->count = dtoh32(maclist->count);
+ if (!strncmp(*argv, "del", strlen("del"))) {
+ argv++;
+ ea = &tmp_ea;
+ while (*argv && maclist->count < max) {
+
+ if (!wl_ether_atoe(*argv, ea)) {
+ printf("Problem parsing MAC address \"%s\".\n", *argv);
+ return -1;
+ }
+ found = FALSE;
+ for (i = 0; i < maclist->count; i++) {
+ if (!memcmp(&maclist->ea[i], ea, ETHER_ADDR_LEN)) {
+ memcpy(&maclist->ea[i],
+ &maclist->ea[maclist->count-1], ETHER_ADDR_LEN);
+ maclist->count--;
+ found = TRUE;
+ }
+ }
+ if (!found)
+ printf("WARNING: cannot find any matched entry"
+ "for deleting %s\n", wl_ether_etoa(ea));
+ argv++;
+ }
+ } else {
+ ea = &maclist->ea[maclist->count];
+ while (*argv && maclist->count < max) {
+ if (!wl_ether_atoe(*argv, ea)) {
+ printf("Problem parsing MAC address \"%s\".\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ maclist->count++;
+ ea++;
+ argv++;
+ }
+ }
+ /* Set new list */
+ len = sizeof(maclist->count) + maclist->count * sizeof(maclist->ea);
+ maclist->count = htod32(maclist->count);
+ return wlu_set(wl, cmd->set, maclist, len);
+ }
+}
+
+#define IOCTLECHO_MAX_SIZE 1000
+
+#if IOCTLECHO_MAX_SIZE + 2 > WLC_IOCTL_MAXLEN
+#error INVALID IOCTLECHO_MAX_SIZE
+#endif
+
+#ifndef ATE_BUILD
+static int
+wl_echo(void *wl, cmd_t *cmd, char **argv)
+{
+char *endptr;
+uint len = 0;
+uint i;
+int ret;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (argv[1])
+ len = strtoul(argv[1], &endptr, 0);
+
+ if (len > IOCTLECHO_MAX_SIZE) {
+ printf("maximum allowed size is : %d\n", IOCTLECHO_MAX_SIZE);
+ len = IOCTLECHO_MAX_SIZE;
+ }
+
+ memset(buf, 0, len+2);
+
+ for (i = 0; i < len; i++)
+ buf[2+i] = (char)i;
+
+ ((ushort*)buf)[0] = len;
+
+ if ((ret = wlu_get(wl, WLC_ECHO, buf, len+2)) < 0)
+ return ret;
+
+ if (((ushort*)buf)[0] != len) {
+ printf("error read size is different then write size\n");
+ return -1;
+ }
+
+ for (i = 0; i < ((ushort*)buf)[0]; i++)
+ if (buf[2+i] != (char)i) {
+ printf("error read data is different then write data\n");
+ return -1;
+ }
+
+ printf("write buffer and read buffer are identical\n");
+
+ return 0;
+
+}
+#endif /* !ATE_BUILD */
+
+static int
+wl_out(void *wl, cmd_t *cmd, char **argv)
+{
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ return wlu_set(wl, WLC_OUT, NULL, 0);
+}
+
+static int
+wl_band(void *wl, cmd_t *cmd, char **argv)
+{
+ uint band;
+ int error;
+
+ UNUSED_PARAMETER(cmd);
+
+ error = 0;
+
+ argv++;
+
+ if (*argv == NULL) { /* get current band */
+ if ((error = wlu_get(wl, WLC_GET_BAND, &band, sizeof(uint))) < 0)
+ return (error);
+ band = dtoh32(band);
+
+ if (band == WLC_BAND_AUTO)
+ printf("auto\n");
+ else if (band == WLC_BAND_5G)
+ printf("a\n");
+ else if (band == WLC_BAND_2G)
+ printf("b\n");
+ else {
+ printf("unrecognized band value %d\n", band);
+ error = BCME_ERROR;
+ }
+ } else { /* set the band */
+ if (!stricmp(*argv, "auto"))
+ band = WLC_BAND_AUTO;
+ else if (!stricmp(*argv, "a"))
+ band = WLC_BAND_5G;
+ else if (!stricmp(*argv, "b"))
+ band = WLC_BAND_2G;
+ else {
+ printf("unsupported band: %s\n", *argv);
+ return BCME_UNSUPPORTED;
+ }
+
+ band = htod32(band);
+ error = wlu_set(wl, WLC_SET_BAND, &band, sizeof(uint));
+
+ }
+ return (error);
+}
+
+static int
+wl_bandlist(void *wl, cmd_t *cmd, char **argv)
+{
+ uint list[3];
+ int error;
+ uint i;
+
+ UNUSED_PARAMETER(cmd);
+
+ error = 0;
+
+ argv++;
+
+ if ((error = wlu_get(wl, WLC_GET_BANDLIST, list, sizeof(list))) < 0)
+ return (error);
+ list[0] = dtoh32(list[0]);
+ list[1] = dtoh32(list[1]);
+ list[2] = dtoh32(list[2]);
+
+ /* list[0] is count, followed by 'count' bands */
+
+ if (list[0] > 2)
+ list[0] = 2;
+
+ for (i = 1; i <= list[0]; i++)
+ if (list[i] == WLC_BAND_5G)
+ printf("a ");
+ else if (list[i] == WLC_BAND_2G)
+ printf("b ");
+ else
+ printf("? ");
+ printf("\n");
+
+ return (0);
+}
+
+static int
+wl_phylist(void *wl, cmd_t *cmd, char **argv)
+{
+ char phylist_buf[128];
+ int error;
+ char *cp;
+
+ UNUSED_PARAMETER(cmd);
+
+ error = 0;
+
+ argv++;
+
+ if ((error = wlu_get(wl, WLC_GET_PHYLIST, phylist_buf, sizeof(phylist_buf))) < 0)
+ return (error);
+
+ cp = phylist_buf;
+
+ for (; *cp; cp++)
+ printf("%c ", *cp);
+ printf("\n");
+
+ return (0);
+}
+
+#ifdef linux
+#define UPGRADE_BUFSIZE 512 /* upgrade buffer size */
+#else
+#define UPGRADE_BUFSIZE 1024 /* upgrade buffer size */
+#endif /* linux */
+
+static int
+wl_upgrade(void *wl, cmd_t *cmd, char **argv)
+{
+#if !defined(BWL_FILESYSTEM_SUPPORT)
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
+ return (-1);
+#elif defined(DONGLEBUILD)
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
+ return 0;
+#else
+ FILE *fp;
+ int ret = 0;
+ struct {
+ uint32 offset;
+ char buf[UPGRADE_BUFSIZE];
+ } block;
+ uint32 offset;
+ uint len;
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ if (!(fp = fopen(*argv, "rb"))) {
+ fprintf(stderr, "%s: No such file or directory\n", *argv);
+ return BCME_BADARG;
+ }
+
+ printf("Programming %s...", *argv);
+ fflush(stdout);
+ offset = 0;
+ block.offset = htod32(offset);
+ while ((len = fread(block.buf, 1, sizeof(block.buf), fp))) {
+ if ((ret = wlu_set(wl, cmd->set, &block, 4 + len)) < 0)
+ break;
+ offset += len;
+ block.offset = htod32(offset);
+ printf(".");
+ fflush(stdout);
+ }
+
+ if (ferror(fp)) {
+ ret = ferror(fp);
+ printf("\nerror reading %s\n", *argv);
+ } else {
+ long status = WLC_UPGRADE_PENDING;
+ int retries;
+
+ printf("\nCommitting image to flash...\n");
+ while (status == WLC_UPGRADE_PENDING) {
+ retries = 10;
+retry:
+ if ((ret = wlu_get(wl, WLC_UPGRADE_STATUS,
+ &status, sizeof(status))) < 0) {
+ /* the first attempt to get status will
+ * likely fail due to dev reset
+ */
+ if (retries--)
+ goto retry;
+ break;
+ }
+ status = dtoh32(status);
+ }
+ if (status == WLC_UPGRADE_SUCCESS)
+ printf("\nDone\n\nSuccessfully downloaded %d bytes\n", block.offset);
+ else
+ fprintf(stderr, "\n*** UPGRADE FAILED! *** (status %ld)\n", status);
+ }
+
+ fclose(fp);
+ return ret;
+#endif /* BWL_FILESYSTEM_SUPPORT */
+}
+
+static int
+wl_get_pktcnt(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ get_pktcnt_t pktcnt;
+
+ UNUSED_PARAMETER(argv);
+
+ memset(&pktcnt, 0, sizeof(pktcnt));
+ if ((ret = wlu_get(wl, cmd->get, &pktcnt, sizeof(pktcnt))) < 0)
+ return ret;
+
+ printf("Receive: good packet %d, bad packet %d, othercast good packet %d\n",
+ dtoh32(pktcnt.rx_good_pkt), dtoh32(pktcnt.rx_bad_pkt),
+ dtoh32(pktcnt.rx_ocast_good_pkt));
+ printf("Transmit: good packet %d, bad packet %d\n",
+ dtoh32(pktcnt.tx_good_pkt), dtoh32(pktcnt.tx_bad_pkt));
+
+ return ret;
+}
+
+static cntry_name_t *
+wlc_cntry_name_to_country(char *long_name)
+{
+ cntry_name_t *cntry;
+ for (cntry = cntry_names; cntry->name &&
+ stricmp(long_name, cntry->name); cntry++);
+ return (!cntry->name ? NULL : cntry);
+}
+
+static cntry_name_t *
+wlc_cntry_abbrev_to_country(const char *abbrev)
+{
+ cntry_name_t *cntry;
+ if (!*abbrev || strlen(abbrev) > 3 || strlen(abbrev) < 2)
+ return (NULL);
+ for (cntry = cntry_names; cntry->name &&
+ strnicmp(abbrev, cntry->abbrev, strlen(abbrev)); cntry++);
+ return (!cntry->name ? NULL : cntry);
+}
+
+static int
+wl_parse_country_spec(const char *spec, char *ccode, int *regrev)
+{
+ char *revstr;
+ char *endptr = NULL;
+ int ccode_len;
+ int rev = -1;
+
+ revstr = strchr(spec, '/');
+
+ if (revstr) {
+ rev = strtol(revstr + 1, &endptr, 10);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ fprintf(stderr,
+ "Could not parse \"%s\" as a regulatory revision "
+ "in the country string \"%s\"\n",
+ revstr + 1, spec);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ if (revstr)
+ ccode_len = (int)(uintptr)(revstr - spec);
+ else
+ ccode_len = (int)strlen(spec);
+
+ if (ccode_len > 3) {
+ fprintf(stderr,
+ "Could not parse a 2-3 char country code "
+ "in the country string \"%s\"\n",
+ spec);
+ return BCME_USAGE_ERROR;
+ }
+
+ memcpy(ccode, spec, ccode_len);
+ ccode[ccode_len] = '\0';
+ *regrev = rev;
+
+ return 0;
+}
+
+int
+wl_country(void *wl, cmd_t *cmd, char **argv)
+{
+ cntry_name_t *cntry;
+ wl_country_t cspec = {{0}, 0, {0}};
+ int argc = 0;
+ int err;
+ int bcmerr = 1;
+ int interr = 1;
+
+ /* skip the command name */
+ argv++;
+
+ /* find the arg count */
+ while (argv[argc])
+ argc++;
+
+ /* check arg list count */
+ if (argc > 2) {
+ fprintf(stderr, "Too many arguments (%d) for command %s\n", argc, cmd->name);
+ return BCME_USAGE_ERROR;
+ }
+
+ buf[0] = 0;
+ if (argc == 0) {
+ const char* name = "<unknown>";
+
+ /* first try the country iovar */
+ err = wlu_iovar_get(wl, "country", &cspec, sizeof(cspec));
+
+ if (!err) {
+ cntry = wlc_cntry_abbrev_to_country(cspec.country_abbrev);
+ if (cntry)
+ name = cntry->name;
+ cspec.rev = dtoh32(cspec.rev);
+
+ printf("%s (%s/%d) %s\n",
+ cspec.country_abbrev, cspec.ccode, cspec.rev, name);
+
+ return 0;
+ }
+
+ /* if there was an error other than BCME_UNSUPPORTED, fail now */
+ interr = wlu_iovar_getint(wl, "bcmerror", &bcmerr);
+ if (!interr && (bcmerr != BCME_UNSUPPORTED))
+ return err;
+
+ /* if the "country" iovar is unsupported, try the WLC_SET_COUNTRY ioctl */
+ if ((err = wlu_get(wl, cmd->get, &buf[0], WLC_IOCTL_SMLEN)) < 0)
+ return err;
+ if (strlen(buf) == 0) {
+ printf("No country set\n");
+ return 0;
+
+ }
+ cntry = wlc_cntry_abbrev_to_country(buf);
+ if (cntry != NULL)
+ name = cntry->name;
+
+ printf("%s () %s\n", buf, name);
+ return 0;
+ }
+
+ if (!stricmp(*argv, "list")) {
+ uint i;
+ const char* abbrev;
+ wl_country_list_t *cl = (wl_country_list_t *)buf;
+
+ cl->buflen = WLC_IOCTL_MAXLEN;
+ cl->count = 0;
+
+ /* band may follow */
+ if (*++argv) {
+ cl->band_set = TRUE;
+ if (!stricmp(*argv, "a"))
+ cl->band = WLC_BAND_5G;
+ else if (!stricmp(*argv, "b") || !stricmp(*argv, "g"))
+ cl->band = WLC_BAND_2G;
+ else {
+ printf("unsupported band: %s\n", *argv);
+ return BCME_UNSUPPORTED;
+ }
+ } else {
+ cl->band_set = FALSE;
+ }
+
+ cl->buflen = htod32(cl->buflen);
+ cl->band_set = htod32(cl->band_set);
+ cl->band = htod32(cl->band);
+ cl->count = htod32(cl->count);
+ err = wlu_get(wl, WLC_GET_COUNTRY_LIST, buf, WLC_IOCTL_MAXLEN);
+ if (err < 0)
+ return err;
+
+ printf("Supported countries: country code and long name\n");
+ for (i = 0; i < dtoh32(cl->count); i++) {
+ abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ];
+ cntry = wlc_cntry_abbrev_to_country(abbrev);
+ printf("%s\t%s\n", abbrev, cntry ? cntry->name : "");
+ }
+ return 0;
+ }
+
+ memset(&cspec, 0, sizeof(cspec));
+ cspec.rev = -1;
+
+ if (argc == 1) {
+ /* check for the first arg being a country name, e.g. "United States",
+ * or country spec, "US/1", or just a country code, "US"
+ */
+ if ((cntry = wlc_cntry_name_to_country(argv[0])) != NULL) {
+ /* arg matched a country name */
+ memcpy(cspec.country_abbrev, cntry->abbrev, WLC_CNTRY_BUF_SZ);
+ err = 0;
+ } else {
+ /* parse a country spec, e.g. "US/1", or a country code.
+ * cspec.rev will be -1 if not specified.
+ */
+ err = wl_parse_country_spec(argv[0], cspec.country_abbrev, &cspec.rev);
+ }
+
+ if (err) {
+ fprintf(stderr,
+ "Argument \"%s\" could not be parsed as a country name, "
+ "country code, or country code and regulatory revision.\n",
+ argv[0]);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* if the arg was a country spec, then fill out ccdoe and rev,
+ * and leave country_abbrev defaulted to the ccode
+ */
+ if (cspec.rev != -1)
+ memcpy(cspec.ccode, cspec.country_abbrev, WLC_CNTRY_BUF_SZ);
+ } else {
+ /* for two args, the first needs to be a country code or country spec */
+ err = wl_parse_country_spec(argv[0], cspec.ccode, &cspec.rev);
+ if (err) {
+ fprintf(stderr,
+ "Argument 1 \"%s\" could not be parsed as a country code, or "
+ "country code and regulatory revision.\n",
+ argv[0]);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* the second arg needs to be a country name or country code */
+ if ((cntry = wlc_cntry_name_to_country(argv[1])) != NULL) {
+ /* arg matched a country name */
+ memcpy(cspec.country_abbrev, cntry->abbrev, WLC_CNTRY_BUF_SZ);
+ } else {
+ int rev;
+ err = wl_parse_country_spec(argv[1], cspec.country_abbrev, &rev);
+ if (rev != -1) {
+ fprintf(stderr,
+ "Argument \"%s\" had a revision. Arg 2 must be "
+ "a country name or country code without a revision\n",
+ argv[1]);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ if (err) {
+ fprintf(stderr,
+ "Argument 2 \"%s\" could not be parsed as "
+ "a country name or country code\n",
+ argv[1]);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ /* first try the country iovar */
+ if (cspec.rev == -1 && cspec.ccode[0] == '\0')
+ err = wlu_iovar_set(wl, "country", &cspec, WLC_CNTRY_BUF_SZ);
+ else {
+ cspec.rev = htod32(cspec.rev);
+ err = wlu_iovar_set(wl, "country", &cspec, sizeof(cspec));
+ }
+
+ if (err == 0)
+ return 0;
+
+ /* if there was an error other than BCME_UNSUPPORTED, fail now */
+ interr = wlu_iovar_getint(wl, "bcmerror", &bcmerr);
+ if (!interr && (bcmerr != BCME_UNSUPPORTED))
+ return err;
+
+ /* if the "country" iovar is unsupported, try the WLC_SET_COUNTRY ioctl if possible */
+
+ if (cspec.rev != -1 || cspec.ccode[0] != '\0') {
+ fprintf(stderr,
+ "Driver does not support full country spec interface, "
+ "only a country name or code may be sepcified\n");
+ return err;
+ }
+
+ /* use the legacy ioctl */
+ err = wlu_set(wl, WLC_SET_COUNTRY, cspec.country_abbrev, WLC_CNTRY_BUF_SZ);
+
+ return err;
+}
+
+int
+wl_country_ie_override(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc = 0;
+ int error, i;
+
+ /* skip the command name */
+ argv++;
+
+ /* find the arg count */
+ while (argv[argc])
+ argc++;
+
+ if (argc == 0) {
+ void *ptr;
+ bcm_tlv_t *ie;
+
+ if ((error = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return (error);
+
+ ie = (bcm_tlv_t *)ptr;
+
+ printf("ie tag:0x%x ie len:0x%x ie data:", ie->id, ie->len);
+
+ for (i = 0; i < ie->len; i++)
+ printf("0x%x ", ie->data[i]);
+
+ printf("\n");
+
+ return error;
+
+ } else {
+ /* Set */
+ char *endptr = NULL;
+ uchar *valsp;
+ int8 ie_len, pad = 0;
+
+ /* retrieve the ie len in advance to check for padding */
+ ie_len = (int8)strtol(*(argv + 1), NULL, 0);
+ if (ie_len & 1) {
+ fprintf(stderr, "country ie len is odd(%d), padding by 1 octet\n", ie_len);
+ pad = 1;
+ }
+
+ valsp = (uchar*)malloc(argc + pad);
+ if (valsp == NULL) {
+ fprintf(stderr, "Error allocating %d bytes country ie\n", argc);
+ return BCME_NOMEM;
+ }
+ memset(valsp, 0, argc + pad);
+
+ for (i = 0; i < argc; i++, argv++) {
+
+ valsp[i] = (uchar)strtol(*argv, &endptr, 0);
+
+ /* make sure all the value string was parsed by strtol */
+ if (*endptr != '\0') {
+ free(valsp);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ /* update ie len if padded */
+ if (pad) {
+ valsp[1] += 1;
+ valsp[ie_len + TLV_HDR_LEN] = 0;
+ }
+
+ error = wlu_var_setbuf(wl, cmd->name, valsp, argc + pad);
+
+ free(valsp);
+
+ return error;
+ }
+}
+
+static int
+wl_actframe(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_action_frame_t * action_frame;
+ wl_af_params_t * af_params;
+ struct ether_addr ea;
+ int argc;
+ int err = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!argv[1] || !argv[2]) {
+ fprintf(stderr, "Too few arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if ((af_params = (wl_af_params_t *) malloc(WL_WIFI_AF_PARAMS_SIZE)) == NULL) {
+ printf("wl_actframe: unable to allocate frame \n");
+ return BCME_NOMEM;
+ }
+ af_params->channel = 0;
+ af_params->dwell_time = -1;
+ action_frame = &af_params->action_frame;
+
+ /* Add the packet Id */
+ action_frame->packetId = (uint32)(uintptr)action_frame;
+
+ /* convert the ea string into an ea struct */
+ if (!wl_ether_atoe(argv[1], &ea)) {
+ free(af_params);
+ printf(" ERROR: no valid ether addr provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ memcpy(&action_frame->da, (char*)&ea, ETHER_ADDR_LEN);
+ /* set default BSSID */
+ memcpy(&af_params->BSSID, (char*)&ea, ETHER_ADDR_LEN);
+
+ /* add the length */
+ if (argv[2]) {
+ action_frame->len = htod16(strlen(argv[2])) / 2;
+ }
+
+ /* add the channel */
+ if (argc > 3 && argv[3]) {
+ af_params->channel = htod32(atoi(argv[3]));
+ }
+
+ /* add the dwell_time */
+ if (argc > 4 && argv[4]) {
+ af_params->dwell_time = htod32(atoi(argv[4]));
+ }
+
+ /* add the BSSID */
+ if (argc > 5 && argv[5]) {
+ if (!wl_ether_atoe(argv[5], &ea)) {
+ free(af_params);
+ printf(" ERROR: no valid ether addr provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ memcpy(&af_params->BSSID, (char*)&ea, ETHER_ADDR_LEN);
+ }
+
+ if ((err = get_ie_data ((uchar *)argv[2],
+ &action_frame->data[0],
+ action_frame->len))) {
+ free(af_params);
+ fprintf(stderr, "Error parsing data arg\n");
+ return err;
+ }
+ err = wlu_var_setbuf(wl, "actframe", af_params, WL_WIFI_AF_PARAMS_SIZE);
+
+ free(af_params);
+
+ return (err);
+
+}
+
+static int
+wl_dfs_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+
+ void *ptr;
+
+ UNUSED_PARAMETER(argv);
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ ret = wl_print_dfs_status(ptr);
+
+ return ret;
+}
+
+static int
+wl_print_dfs_status(wl_dfs_status_t *dfs_status)
+{
+ char chanspec_str[CHANSPEC_STR_LEN];
+
+ dfs_status->state = dtoh32(dfs_status->state);
+ dfs_status->duration = dtoh32(dfs_status->duration);
+ dfs_status->chanspec_cleared = wl_chspec_from_driver(dfs_status->chanspec_cleared);
+
+ if (dfs_status->state >= WL_DFS_CACSTATES) {
+ printf("Unknown dfs state %d.\n", dfs_status->state);
+ return -1;
+ }
+
+ printf("state %s time elapsed %dms radar channel cleared by dfs ",
+ dfs_cacstate_str[dfs_status->state], dfs_status->duration);
+
+ if (dfs_status->chanspec_cleared) {
+ printf("channel %s (0x%04X)\n",
+ wf_chspec_ntoa(dfs_status->chanspec_cleared, chanspec_str),
+ dfs_status->chanspec_cleared);
+ }
+ else {
+ printf("none\n");
+ }
+ return 0;
+}
+
+static int
+wl_dfs_status_all(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+
+ void *ptr;
+
+ UNUSED_PARAMETER(argv);
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ ret = wl_print_dfs_status_all(ptr);
+
+ return ret;
+}
+
+/* prints dfs status from one subset */
+static int
+wl_print_dfs_sub_status(wl_dfs_sub_status_t *sub)
+{
+ char chanspec_str[CHANSPEC_STR_LEN];
+
+ sub->state = dtoh32(sub->state);
+ sub->duration = dtoh32(sub->duration);
+ sub->chanspec = wl_chspec_from_driver(sub->chanspec);
+ sub->chanspec_last_cleared = wl_chspec_from_driver(sub->chanspec_last_cleared);
+ sub->sub_type = dtoh16(sub->sub_type);
+
+ // state
+ if (sub->state >= WL_DFS_CACSTATES) {
+ printf("Unknown dfs state %d.\n", sub->state);
+ return -1;
+ }
+ printf("state: %s, time elapsed: %dms, chanspec: ",
+ dfs_cacstate_str[sub->state], sub->duration);
+ // chanspec
+ if (sub->chanspec) {
+ printf("%s (0x%04X), chanspec last cleared: ",
+ wf_chspec_ntoa(sub->chanspec, chanspec_str),
+ sub->chanspec);
+ } else {
+ printf("none, chanspec last cleared: ");
+ }
+ // chanspec last cleared
+ if (sub->chanspec_last_cleared) {
+ printf("%s (0x%04X), ",
+ wf_chspec_ntoa(sub->chanspec_last_cleared, chanspec_str),
+ sub->chanspec_last_cleared);
+ } else {
+ printf("none, ");
+ }
+ // sub type
+ printf("sub type: 0x%02x\n", sub->sub_type);
+
+ return 0;
+}
+
+/* prints dfs status of all subsets received */
+static int
+wl_print_dfs_status_all(wl_dfs_status_all_t *dfs_status_all)
+{
+ int count;
+ int err;
+ if (dfs_status_all == NULL) {
+ return BCME_ERROR;
+ }
+
+ dfs_status_all->version = dtoh32(dfs_status_all->version);
+ dfs_status_all->num_sub_status = dtoh32(dfs_status_all->num_sub_status);
+
+ if (dfs_status_all->version != WL_DFS_STATUS_ALL_VERSION) {
+ err = BCME_UNSUPPORTED;
+ printf("err=%d version=%d\n", err, dfs_status_all->version);
+ return err;
+ }
+
+ printf("version: %d, num_sub_status: %d\n",
+ dfs_status_all->version, dfs_status_all->num_sub_status);
+
+ for (count = 0; count < dfs_status_all->num_sub_status; ++count) {
+ printf("@%d: ", count);
+ if ((err = wl_print_dfs_sub_status(&dfs_status_all->dfs_sub_status[count]))
+ != BCME_OK) {
+ return err;
+ }
+ }
+
+ return BCME_OK;
+}
+
+static int
+wl_radar_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ uint i;
+ wl_radar_status_t ra;
+ char chanspec_str[CHANSPEC_STR_LEN];
+ static const struct {
+ uint32 radar_type;
+ const char *radar_type_name;
+ } radar_names[] = {
+ {0, "NONE"},
+ {1, "ETSI_1"},
+ {2, "ETSI_2"},
+ {3, "ETSI_3"},
+ {4, "ETSI_4"},
+ {5, "S2"},
+ {6, "S3"},
+ {7, "UNCLASSIFIED"},
+ {8, "FCC-5"},
+ {9, "JP1-2/JP2-3"},
+ {10, "JP2-1"},
+ {11, "JP4"},
+ {12, "FCC_1"},
+ };
+
+ char radar_type_str[24];
+
+ UNUSED_PARAMETER(argv);
+ if ((ret = wlu_iovar_get(wl, cmd->name, &ra, sizeof(ra))) < 0)
+ return ret;
+ ra.ch = wl_chspec_from_driver(ra.ch);
+
+ if (ra.detected == FALSE) {
+ printf("NO RADAR DETECTED \n");
+ } else {
+ for (i = 0; i < ARRAYSIZE(radar_names); i++) {
+ if (radar_names[i].radar_type == ra.radartype)
+ snprintf(radar_type_str, sizeof(radar_type_str),
+ "%s", radar_names[i].radar_type_name);
+ }
+
+ if (ra.pretended == TRUE) {
+ printf("DFS: NONE ########## RADAR DETECTED ON CHAN %s \n",
+ wf_chspec_ntoa(ra.ch, chanspec_str));
+ } else {
+ if (ra.radartype == 8) {
+ printf("DFS: FCC-5 ########## RADAR DETECTED ON CHAN %s \n",
+ wf_chspec_ntoa(ra.ch, chanspec_str));
+ printf(" ########## lp_csect_single = %d, Time from last detection = %u, ",
+ ra.lp_csect_single, ra.timefromL);
+ printf(" = %dmin %dsec AT %dMS \n ",
+ ra.timefromL/60, ra.timefromL%60, ra.timenow);
+ } else {
+ printf("DFS: %s ########## RADAR DETECTED ON CHAN %s \n",
+ radar_type_str, wf_chspec_ntoa(ra.ch, chanspec_str));
+ printf(" ########## detected_pulse_index= %d, nconseq_pulses = %d, ",
+ ra.detected_pulse_index, ra.nconsecq_pulses);
+ printf(" Time from last detection = %u, = %dmin %dsec AT %dMS \n",
+ ra.timefromL, ra.timefromL/60, ra.timefromL%60, ra.timenow);
+ printf("Pruned Intv: ");
+ for (i = 0; i < 10; i++) {
+ printf("%d-%d ", ra.intv[i], i);
+ }
+ printf("\n");
+
+ printf("Pruned PW: ");
+ for (i = 0; i < 10; i++) {
+ printf("%i-%d ", ra.pw[i], i);
+ }
+ printf("\n");
+
+ printf("Pruned FM: ");
+ for (i = 0; i < 10; i++) {
+ printf("%i-%d ", ra.fm[i], i);
+ }
+ printf("\n");
+ }
+ }
+ }
+ return ret;
+}
+
+static int
+wl_radar_sc_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ uint i;
+ wl_radar_status_t ra;
+ static const struct {
+ uint32 radar_type;
+ const char *radar_type_name;
+ } radar_names[] = {
+ {0, "NONE"},
+ {1, "ETSI_1"},
+ {2, "ETSI_2"},
+ {3, "ETSI_3"},
+ {4, "ETSI_4"},
+ {5, "S2"},
+ {6, "S3"},
+ {7, "UNCLASSIFIED"},
+ {8, "FCC-5"},
+ {9, "JP1-2/JP2-3"},
+ {10, "JP2-1"},
+ {11, "JP4"},
+ {12, "FCC_1"},
+ };
+
+ char radar_type_str[24];
+
+ /* Skip the command name */
+ argv++;
+
+ if (*argv == NULL) {
+ if ((ret = wlu_iovar_get(wl, cmd->name, &ra, sizeof(ra))) < 0)
+ return ret;
+
+ if (ra.detected == FALSE) {
+ printf("NO RADAR_SC DETECTED \n");
+ } else {
+ for (i = 0; i < ARRAYSIZE(radar_names); i++) {
+ if (radar_names[i].radar_type == ra.radartype)
+ snprintf(radar_type_str, sizeof(radar_type_str),
+ "%s", radar_names[i].radar_type_name);
+ }
+
+ if (ra.pretended == TRUE) {
+ printf("DFS: NONE ########## RADAR_SC DETECTED ON SC CHAN \n");
+ } else {
+ if (ra.radartype == 8) {
+ printf("DFS: FCC-5 ########## RADAR_SC DETECTED ON SC CHAN \n");
+ printf(" ########## lp_csect_single");
+ printf("= %d, Time from last detection = %u, ",
+ ra.lp_csect_single, ra.timefromL);
+ printf(" = %dmin %dsec AT %dMS \n ",
+ ra.timefromL/60, ra.timefromL%60, ra.timenow);
+ } else {
+ printf("DFS: %s ########## RADAR_SC DETECTED ON SC CHAN \n",
+ radar_type_str);
+ printf(" ########## detected_pulse_index= %d, nconseq_pulses = %d, ",
+ ra.detected_pulse_index, ra.nconsecq_pulses);
+ printf(" Time from last detection = %u, = %dmin %dsec AT %dMS \n",
+ ra.timefromL, ra.timefromL/60, ra.timefromL%60, ra.timenow);
+ printf("Pruned Intv: ");
+ for (i = 0; i < 10; i++) {
+ printf("%d-%d ", ra.intv[i], i);
+ }
+ printf("\n");
+
+ printf("Pruned PW: ");
+ for (i = 0; i < 10; i++) {
+ printf("%i-%d ", ra.pw[i], i);
+ }
+ printf("\n");
+
+ printf("Pruned FM: ");
+ for (i = 0; i < 10; i++) {
+ printf("%i-%d ", ra.fm[i], i);
+ }
+ printf("\n");
+ }
+ }
+ }
+
+ } else {
+ ret = atoi(*argv);
+ if (ret == 0) {
+ printf("Clear SC Radar Status \n");
+ ra.detected = FALSE;
+ return wlu_var_setbuf(wl, "clear_radar_sc_status",
+ &ra, sizeof(wl_radar_status_t));
+ }
+ }
+
+ return ret;
+}
+
+
+static int
+wl_clear_radar_status(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_radar_status_t ra;
+
+ UNUSED_PARAMETER(argv);
+ printf("Clear Radar Status \n");
+
+ ra.detected = FALSE;
+ return wlu_var_setbuf(wl, cmd->name, &ra, sizeof(wl_radar_status_t));
+}
+
+/*
+ * wlu_reg2args is a generic function that is used for setting/getting
+ * WL_IOVAR variables that require address for read, and
+ * address + data for write.
+ */
+int
+wlu_reg2args(void *wl, cmd_t *cmd, char **argv)
+{
+ char var[256];
+ uint32 int_val;
+ bool get = TRUE;
+ uint32 len;
+ void *ptr = NULL;
+ char *endptr;
+ int ret = 0;
+
+ if (argv[1]) {
+ len = sizeof(int_val);
+ int_val = htod32(strtoul(argv[1], &endptr, 0));
+ memcpy(var, (char *)&int_val, sizeof(int_val));
+ }
+ else
+ return BCME_USAGE_ERROR;
+
+ if (argv[2]) {
+ get = FALSE;
+ int_val = htod32(strtoul(argv[2], &endptr, 0));
+ memcpy(&var[len], (char *)&int_val, sizeof(int_val));
+ len += sizeof(int_val);
+ }
+ if (get) {
+ if ((ret = wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr)) < 0)
+ return ret;
+
+ printf("0x%x\n", dtoh32(*(int *)ptr));
+ }
+ else
+ ret = wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
+ return ret;
+}
+
+static int
+wl_measure_req(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 val;
+ struct ether_addr ea;
+
+ if (!*++argv) {
+ printf("error: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!stricmp(*argv, "tpc"))
+ val = WLC_MEASURE_TPC;
+ else if (!stricmp(*argv, "basic"))
+ val = WLC_MEASURE_CHANNEL_BASIC;
+ else if (!stricmp(*argv, "cca"))
+ val = WLC_MEASURE_CHANNEL_CCA;
+ else if (!stricmp(*argv, "rpi"))
+ val = WLC_MEASURE_CHANNEL_RPI;
+ else {
+ printf("error: unknown measurement type %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ argv++;
+
+ if (!*argv) {
+ printf("error: missing target address\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!wl_ether_atoe(*argv, &ea)) {
+ printf("error: could not parse MAC address %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ val = htod32(val);
+ memcpy(&buf[0], &val, sizeof(uint32));
+ memcpy(&buf[4], ea.octet, ETHER_ADDR_LEN);
+
+ return wlu_set(wl, cmd->set, buf, sizeof(uint32) + ETHER_ADDR_LEN);
+}
+
+static int
+wl_send_quiet(void *wl, cmd_t *cmd, char **argv)
+{
+ dot11_quiet_t quiet;
+
+ if (!*++argv) {
+ printf("error: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+ /* Order is count, duration, offset */
+ quiet.count = atoi(*argv);
+ if (!*++argv) {
+ printf("error: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+ quiet.duration = atoi(*argv);
+ if (!*++argv) {
+ printf("error: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+ quiet.offset = atoi(*argv);
+ quiet.period = 0;
+
+ quiet.duration = htod16(quiet.duration);
+ quiet.offset = htod16(quiet.offset);
+ return (wlu_set(wl, cmd->set, &quiet, sizeof(quiet)));
+}
+
+static int
+wl_pm_mute_tx(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_pm_mute_tx_t var;
+
+ var.version = htod16(WL_PM_MUTE_TX_VER);
+ var.len = htod16(sizeof(wl_pm_mute_tx_t));
+
+ if (!*++argv) {
+ goto missing_args;
+ }
+
+ var.enable = atoi(*argv);
+
+ if (var.enable) {
+ if (!*++argv) {
+ goto missing_args;
+ }
+ var.deadline = htod16(atoi(*argv));
+ }
+
+ return (wlu_var_setbuf(wl, cmd->name, &var, var.len));
+
+missing_args:
+ return -1;
+}
+
+static int
+wl_send_csa(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_chan_switch_t csa_arg;
+
+ /* Order is mode, count channel */
+ if (!*++argv) {
+ printf("error: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+ csa_arg.mode = atoi(*argv) ? 1 : 0;
+ if (!*++argv) {
+ printf("error: missing count\n");
+ return BCME_USAGE_ERROR;
+ }
+ csa_arg.count = atoi(*argv);
+ if (!*++argv) {
+ printf("error: missing channel\n");
+ return BCME_USAGE_ERROR;
+ }
+ csa_arg.reg = 0;
+
+ if ((csa_arg.chspec = wf_chspec_aton(*argv))) {
+ csa_arg.chspec = wl_chspec_to_driver(csa_arg.chspec);
+ if (csa_arg.chspec == INVCHANSPEC) {
+ return BCME_USAGE_ERROR;
+ }
+ /* csa action frame type */
+ if (*++argv) {
+ if (strcmp(*argv, "u") == 0)
+ csa_arg.frame_type = CSA_UNICAST_ACTION_FRAME;
+ else {
+ printf("error: invalid frame type: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ } else
+ csa_arg.frame_type = CSA_BROADCAST_ACTION_FRAME;
+
+ err = wlu_var_setbuf(wl, cmd->name, &csa_arg, sizeof(csa_arg));
+ } else {
+ printf("Error: bad parameters \"%s\"\n", *argv);
+ return BCME_BADARG;
+ }
+
+ return err;
+}
+
+int
+wl_var_setint(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 val;
+ char *varname;
+ char *endptr = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!*argv) {
+ printf("set: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ varname = *argv++;
+
+ if (!*argv) {
+ printf("set: missing value argument for set of \"%s\"\n", varname);
+ return BCME_USAGE_ERROR;
+ }
+
+ val = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n",
+ *argv, varname);
+ return BCME_USAGE_ERROR;
+ }
+
+ return wlu_iovar_setint(wl, varname, val);
+}
+
+int
+wl_var_get(void *wl, cmd_t *cmd, char **argv)
+{
+ char *varname;
+ char *p;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!*argv) {
+ printf("get: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ varname = *argv++;
+
+ if (*argv) {
+ printf("get: error, extra arg \"%s\"\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ strcpy(buf, varname);
+ p = buf;
+ while (*p != '\0') {
+ *p = tolower((int)*p);
+ p++;
+ }
+ return (wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN));
+}
+static int
+wl_var_getint(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int32 val;
+ char *varname;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!*argv) {
+ printf("get: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ varname = *argv++;
+
+ if ((err = wlu_iovar_getint(wl, varname, &val)))
+ return (err);
+
+ if (val < 10)
+ printf("%d\n", val);
+ else
+ printf("%d (0x%x)\n", val, val);
+
+ return (0);
+}
+
+int
+wl_var_getandprintstr(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+
+ if ((err = wl_var_get(wl, cmd, argv)))
+ return (err);
+
+ printf("%s\n", buf);
+ return (0);
+}
+
+/* just issue a wl_var_setint() or a wl_var_getint() if there is a 2nd arg */
+int
+wl_varint(void *wl, cmd_t *cmd, char *argv[])
+{
+ if (argv[1])
+ return (wl_var_setint(wl, cmd, argv));
+ else
+ return (wl_var_getint(wl, cmd, argv));
+}
+
+int
+wlu_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr)
+{
+ int len;
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(buf, iovar);
+
+ /* include the null */
+ len = strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy(&buf[len], param, param_len);
+
+ *bufptr = buf;
+
+ return wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN);
+}
+
+/* get buffer for smaller sizes upto 256 bytes */
+int
+wlu_var_getbuf_sm(void *wl, const char *iovar, void *param, int param_len, void **bufptr)
+{
+ int len;
+
+ memset(buf, 0, WLC_IOCTL_SMLEN);
+ strcpy(buf, iovar);
+
+ /* include the null */
+ len = strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy(&buf[len], param, param_len);
+
+ *bufptr = buf;
+
+ return wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_SMLEN);
+}
+
+/* Get buffer of minimal size equal to the sizeof iovar name + param_len */
+int
+wlu_var_getbuf_minimal(void *wl, const char *iovar, void *param, int param_len, void **bufptr)
+{
+ int len;
+
+ /* include the null */
+ len = strlen(iovar) + 1;
+
+ memset(buf, 0, (len + param_len));
+ strcpy(buf, iovar);
+
+ if (param_len)
+ memcpy(&buf[len], param, param_len);
+
+ *bufptr = buf;
+
+ return wlu_get(wl, WLC_GET_VAR, &buf[0], (len + param_len));
+}
+
+/* Get buffer for medium sizes upto 1500 bytes */
+int
+wlu_var_getbuf_med(void *wl, const char *iovar, void *param, int param_len, void **bufptr)
+{
+ int len;
+
+ memset(buf, 0, WLC_IOCTL_MEDLEN);
+ strcpy(buf, iovar);
+
+ /* include the null */
+ len = strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy(&buf[len], param, param_len);
+
+ *bufptr = buf;
+
+ return wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MEDLEN);
+}
+
+
+int
+wlu_var_setbuf(void *wl, const char *iovar, void *param, int param_len)
+{
+ int len;
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(buf, iovar);
+
+ /* include the null */
+ len = strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy(&buf[len], param, param_len);
+
+ len += param_len;
+
+ return wlu_set(wl, WLC_SET_VAR, &buf[0], len);
+}
+
+int
+wlu_var_setbuf_sm(void *wl, const char *iovar, void *param, int param_len)
+{
+ int len;
+
+ memset(buf, 0, WLC_IOCTL_SMLEN);
+ strcpy(buf, iovar);
+
+ /* include the null */
+ len = strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy(&buf[len], param, param_len);
+
+ len += param_len;
+
+ return wlu_set(wl, WLC_SET_VAR, &buf[0], WLC_IOCTL_SMLEN);
+}
+
+int
+wlu_var_setbuf_med(void *wl, const char *iovar, void *param, int param_len)
+{
+ int len;
+
+ memset(buf, 0, WLC_IOCTL_MEDLEN);
+ strcpy(buf, iovar);
+
+ /* include the null */
+ len = strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy(&buf[len], param, param_len);
+
+ len += param_len;
+
+ return wlu_set(wl, WLC_SET_VAR, &buf[0], WLC_IOCTL_MEDLEN);
+}
+
+int
+wl_var_void(void *wl, cmd_t *cmd, char **argv)
+{
+ UNUSED_PARAMETER(argv);
+
+ if (cmd->set < 0)
+ return -1;
+
+ return wlu_var_setbuf(wl, cmd->name, NULL, 0);
+}
+
+/*
+ * format a "prefix" indexed iovar buffer
+ */
+static int
+wl_prefixiovar_mkbuf(const char *iovar, const char *prefix, int prefix_index, void *param,
+ int paramlen, void *bufptr, int buflen, int *perr)
+{
+ int8* p;
+ uint prefixlen;
+ uint namelen;
+ uint iolen;
+
+ prefixlen = strlen(prefix); /* length of iovar prefix "bsscfg:ssid %d wlc:counter %d" */
+ namelen = strlen(iovar) + 1; /* length of iovar name + null */
+ iolen = prefixlen + namelen + sizeof(int) + paramlen;
+
+ /* check for overflow */
+ if (buflen < 0 || iolen > (uint)buflen) {
+ *perr = BCME_BUFTOOSHORT;
+ return 0;
+ }
+
+ p = (int8*)bufptr;
+
+ /* copy prefix, no null */
+ memcpy(p, prefix, prefixlen);
+ p += prefixlen;
+
+ /* copy iovar name including null */
+ memcpy(p, iovar, namelen);
+ p += namelen;
+
+ /* send index as first param */
+ prefix_index = htod32(prefix_index);
+ memcpy(p, &prefix_index, sizeof(int32));
+ p += sizeof(int32);
+
+ /* parameter buffer follows */
+ if (paramlen)
+ memcpy(p, param, paramlen);
+
+ *perr = 0;
+ return iolen;
+}
+
+static int
+wl_bssiovar_mkbuf(const char *iovar, int bssidx, void *param,
+ int paramlen, void *bufptr, int buflen, int *perr)
+{
+ const char *prefix = "bsscfg:";
+ return wl_prefixiovar_mkbuf(iovar, prefix, bssidx, param, paramlen, bufptr, buflen, perr);
+}
+#ifdef NOTYET
+static int
+wl_wlciovar_mkbuf(const char *iovar, int wlcidx, void *param,
+ int paramlen, void *bufptr, int buflen, int *perr)
+{
+ const char *prefix = "wlc:";
+ return wl_prefixiovar_mkbuf(iovar, prefix, wlcidx, param, paramlen, bufptr, buflen, perr);
+}
+#endif
+/*
+ * set named & bss indexed driver iovar providing both parameter and i/o buffers
+ */
+int
+wlu_bssiovar_setbuf(void* wl, const char *iovar, int bssidx,
+ void *param, int paramlen, void *bufptr, int buflen)
+{
+ int err;
+ int iolen;
+
+ iolen = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &err);
+ if (err)
+ return err;
+
+ return wlu_set(wl, WLC_SET_VAR, bufptr, iolen);
+}
+
+/*
+ * get named & bss indexed driver iovar providing both parameter and i/o buffers
+ */
+static int
+wl_bssiovar_getbuf(void* wl, const char *iovar, int bssidx,
+ void *param, int paramlen, void *bufptr, int buflen)
+{
+ int err;
+
+ wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &err);
+ if (err)
+ return err;
+
+ return wlu_get(wl, WLC_GET_VAR, bufptr, buflen);
+}
+
+/*
+ * get named & bss indexed driver variable to buffer value
+ */
+int
+wlu_bssiovar_get(void *wl, const char *iovar, int bssidx, void *outbuf, int len)
+{
+ char smbuf[WLC_IOCTL_SMLEN];
+ int err;
+
+ /* use the return buffer if it is bigger than what we have on the stack */
+ if (len > (int)sizeof(smbuf)) {
+ err = wl_bssiovar_getbuf(wl, iovar, bssidx, NULL, 0, outbuf, len);
+ } else {
+ memset(smbuf, 0, sizeof(smbuf));
+ err = wl_bssiovar_getbuf(wl, iovar, bssidx, NULL, 0, smbuf, sizeof(smbuf));
+ if (err == 0)
+ memcpy(outbuf, smbuf, len);
+ }
+
+ return err;
+}
+
+/*
+ * set named & bss indexed driver variable to buffer value
+ */
+static int
+wl_bssiovar_set(void *wl, const char *iovar, int bssidx, void *param, int paramlen)
+{
+ char smbuf[WLC_IOCTL_SMLEN];
+
+ memset(smbuf, 0, sizeof(smbuf));
+
+ return wlu_bssiovar_setbuf(wl, iovar, bssidx, param, paramlen, smbuf, sizeof(smbuf));
+}
+
+/*
+ * get named & bsscfg indexed driver variable as an int value
+ */
+static int
+wl_bssiovar_getint(void *wl, const char *iovar, int bssidx, int *pval)
+{
+ int ret;
+
+ ret = wlu_bssiovar_get(wl, iovar, bssidx, pval, sizeof(int));
+ if (ret == 0)
+ {
+ *pval = dtoh32(*pval);
+ }
+ return ret;
+}
+
+/*
+ * set named & bsscfg indexed driver variable to int value
+ */
+static int
+wl_bssiovar_setint(void *wl, const char *iovar, int bssidx, int val)
+{
+ val = htod32(val);
+ return wl_bssiovar_set(wl, iovar, bssidx, &val, sizeof(int));
+}
+
+static int
+wl_nvdump(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ const char *iovar = "nvram_dump";
+ void *p = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* skip the "nvdump/nvram_dump" command name */
+ argv++;
+
+ if (*argv) {
+ printf("nvdump error: extra arg \"%s\"\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((err = wlu_var_getbuf(wl, iovar, NULL, 0, &p)) < 0) {
+ if ((err = wlu_get(wl, WLC_NVRAM_DUMP, &buf[0], WLC_IOCTL_MAXLEN)) < 0)
+ return err;
+ p = (void *)buf;
+ }
+ fputs((char *)p, stdout);
+
+ return err;
+}
+
+/** Queries the driver for the value of a caller supplied nvram variable */
+static int
+wl_nvget(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ char *varname;
+ const char *iovar = "nvram_get";
+ void *p;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* skip the "nvget/nvram_get" command name */
+ argv++;
+
+ if (!*argv) {
+ printf("nvget: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ varname = *argv++;
+
+ if (*argv) {
+ printf("nvget error: extra arg \"%s\"\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((err = wlu_var_getbuf(wl, iovar, varname, strlen(varname) + 1, &p)) < 0) {
+
+ strcpy(buf, varname);
+ if ((err = wlu_get(wl, WLC_NVRAM_GET, &buf[0], WLC_IOCTL_MAXLEN)) < 0)
+ return err;
+ }
+
+ printf("%s\n", buf);
+
+ return err;
+}
+
+static int
+wl_nvset(void *wl, cmd_t *cmd, char **argv)
+{
+ char *varname;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* skip the "nvset" command name if present */
+ if (!strcmp("nvset", *argv))
+ argv++;
+
+ if (!*argv) {
+ printf("nvset: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ varname = *argv++;
+
+ if (*argv) {
+ fprintf(stderr,
+ "nvset error: extra arg \"%s\"; format is name=value (no spaces around '=')\n",
+ *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!strchr(varname, '=')) {
+ fprintf(stderr,
+ "nvset error: no '=' in \"%s\", format is name=value (no spaces around '=')\n",
+ *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ strcpy(buf, varname);
+
+ return (wlu_set(wl, WLC_NVRAM_SET, &buf[0], strlen(buf) + 1));
+}
+
+static int
+wl_chan_info(void *wl, cmd_t *cmd, char **argv)
+{
+ uint bitmap;
+ uint channel;
+ uint32 chanspec_arg;
+ int buflen, err, first, last, minutes;
+ char *param;
+ bool all;
+
+ if (!*++argv) {
+ first = 0;
+ last = MAXCHANNEL;
+ all = TRUE;
+ } else {
+ last = first = atoi(*argv);
+ if (last <= 0) {
+ printf(" Usage: %s [channel | All ]\n", cmd->name);
+ return BCME_USAGE_ERROR;
+ }
+ all = FALSE;
+ }
+
+ for (; first <= last; first++) {
+ channel = first;
+ chanspec_arg = CH20MHZ_CHSPEC(channel);
+
+ strcpy(buf, "per_chan_info");
+ buflen = strlen(buf) + 1;
+ param = (char *)(buf + buflen);
+ /* there should be no problem if converting to a legacy chanspec
+ * since chanspec_arg is created as 20MHz
+ */
+ chanspec_arg = wl_chspec32_to_driver(chanspec_arg);
+ memcpy(param, (char*)&chanspec_arg, sizeof(chanspec_arg));
+
+ if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return err;
+
+ bitmap = dtoh32(*(uint *)buf);
+ minutes = (bitmap >> 24) & 0xff;
+
+ if (!(bitmap & WL_CHAN_VALID_HW)) {
+ if (!all)
+ printf("Invalid Channel\n");
+ continue;
+ }
+
+ if (!(bitmap & WL_CHAN_VALID_SW)) {
+ if (!all)
+ printf("Not supported in current locale\n");
+ continue;
+ }
+
+ printf("Channel %d\t", channel);
+
+ if (bitmap & WL_CHAN_BAND_5G)
+ printf("A Band");
+ else
+ printf("B Band");
+
+ if (bitmap & WL_CHAN_RADAR) {
+ printf(", RADAR Sensitive");
+ }
+ if (bitmap & WL_CHAN_RESTRICTED) {
+ printf(", Restricted");
+ }
+ if (bitmap & WL_CHAN_PASSIVE) {
+ printf(", Passive");
+ }
+ if (bitmap & WL_CHAN_INACTIVE) {
+ printf(", Temporarily Out of Service for %d minutes", minutes);
+ }
+ printf("\n");
+ }
+
+ return (0);
+}
+
+
+int
+wl_sta_info(void *wl, cmd_t *cmd, char **argv)
+{
+ sta_info_v4_t *sta;
+ sta_info_v5_t *sta_v5;
+ struct ether_addr ea;
+ char *param;
+ int buflen, err;
+ int i;
+ char buf_chanspec[20];
+ uint32 rxdur_total = 0;
+ bool have_rxdurtotal = FALSE;
+ chanspec_t chanspec;
+ bool have_chanspec = FALSE;
+ wl_rateset_args_t *rateset_adv;
+ bool have_rateset_adv = FALSE;
+
+
+ strcpy(buf, *argv);
+
+ /* convert the ea string into an ea struct */
+ if (!*++argv || !wl_ether_atoe(*argv, &ea)) {
+ printf(" ERROR: no valid ether addr provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ buflen = strlen(buf) + 1;
+ param = (char *)(buf + buflen);
+ memcpy(param, (char*)&ea, ETHER_ADDR_LEN);
+
+ if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MEDLEN)) < 0)
+ return err;
+
+ /* display the sta info */
+ sta = (sta_info_v4_t *)buf;
+ sta->ver = dtoh16(sta->ver);
+ sta->len = dtoh16(sta->len);
+
+ /* Report unrecognized version */
+ if (sta->ver < WL_STA_VER_4) {
+ printf(" ERROR: unsupported driver station info version %d\n", sta->ver);
+ return BCME_ERROR;
+ }
+ else if (sta->ver == WL_STA_VER_4) {
+ rxdur_total = dtoh32(sta->rx_dur_total);
+ have_rxdurtotal = TRUE;
+ if (sta->len >= STRUCT_SIZE_THROUGH(sta, rateset_adv)) {
+ chanspec = dtoh16(sta->chanspec);
+ wf_chspec_ntoa(chanspec, buf_chanspec);
+ have_chanspec = TRUE;
+
+ rateset_adv = &sta->rateset_adv;
+ have_rateset_adv = TRUE;
+ }
+ }
+ else if (sta->ver == WL_STA_VER_5) {
+ sta_v5 = (sta_info_v5_t *)buf;
+ chanspec = dtoh16(sta_v5->chanspec);
+ wf_chspec_ntoa(chanspec, buf_chanspec);
+ have_chanspec = TRUE;
+
+ rateset_adv = &sta_v5->rateset_adv;
+ have_rateset_adv = TRUE;
+ }
+ else {
+ printf(" ERROR: unknown driver station info version %d\n", sta->ver);
+ return BCME_ERROR;
+ }
+
+ sta->cap = dtoh16(sta->cap);
+ sta->aid = dtoh16(sta->aid);
+ sta->flags = dtoh32(sta->flags);
+ sta->idle = dtoh32(sta->idle);
+ sta->rateset.count = dtoh32(sta->rateset.count);
+ sta->in = dtoh32(sta->in);
+ sta->listen_interval_inms = dtoh32(sta->listen_interval_inms);
+ sta->ht_capabilities = dtoh16(sta->ht_capabilities);
+ sta->vht_flags = dtoh16(sta->vht_flags);
+
+ printf("[VER %d] STA %s:\n", sta->ver, *argv);
+ if (have_chanspec) {
+ printf("\t chanspec %s (0x%x)\n", buf_chanspec, chanspec);
+ }
+ printf("\t aid:%d ", WL_STA_AID(sta->aid));
+ printf("\n\t rateset ");
+ dump_rateset(sta->rateset.rates, sta->rateset.count);
+ printf("\n\t idle %d seconds\n", sta->idle);
+ printf("\t in network %d seconds\n", sta->in);
+ printf("\t state:%s%s%s\n",
+ (sta->flags & WL_STA_AUTHE) ? " AUTHENTICATED" : "",
+ (sta->flags & WL_STA_ASSOC) ? " ASSOCIATED" : "",
+ (sta->flags & WL_STA_AUTHO) ? " AUTHORIZED" : "");
+
+ printf("\t flags 0x%x:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ sta->flags,
+ (sta->flags & WL_STA_BRCM) ? " BRCM" : "",
+ (sta->flags & WL_STA_WME) ? " WME" : "",
+ (sta->flags & WL_STA_PS) ? " PS" : "",
+ (sta->flags & WL_STA_NONERP) ? " No-ERP" : "",
+ (sta->flags & WL_STA_APSD_BE) ? " APSD_BE" : "",
+ (sta->flags & WL_STA_APSD_BK) ? " APSD_BK" : "",
+ (sta->flags & WL_STA_APSD_VI) ? " APSD_VI" : "",
+ (sta->flags & WL_STA_APSD_VO) ? " APSD_VO" : "",
+ (sta->flags & WL_STA_N_CAP) ? " N_CAP" : "",
+ (sta->flags & WL_STA_VHT_CAP) ? " VHT_CAP" : "",
+ (sta->flags & WL_STA_AMPDU_CAP) ? " AMPDU" : "",
+ (sta->flags & WL_STA_AMSDU_CAP) ? " AMSDU" : "",
+ (sta->flags & WL_STA_MIMO_PS) ? " MIMO-PS" : "",
+ (sta->flags & WL_STA_MIMO_RTS) ? " MIMO-PS-RTS" : "",
+ (sta->flags & WL_STA_RIFS_CAP) ? " RIFS" : "");
+
+ printf("\t HT caps 0x%x:%s%s%s%s%s%s%s%s%s\n",
+ sta->ht_capabilities,
+ (sta->ht_capabilities & WL_STA_CAP_LDPC_CODING) ? " LDPC" : "",
+ (sta->ht_capabilities & WL_STA_CAP_40MHZ) ? " 40MHz" : " ",
+ (sta->ht_capabilities & WL_STA_CAP_GF) ? " GF" : "",
+ (sta->ht_capabilities & WL_STA_CAP_SHORT_GI_20) ? " SGI20" : "",
+ (sta->ht_capabilities & WL_STA_CAP_SHORT_GI_40) ? " SGI40" : "",
+ (sta->ht_capabilities & WL_STA_CAP_TX_STBC) ? " STBC-Tx" : "",
+ (sta->ht_capabilities & WL_STA_CAP_RX_STBC_MASK) ? " STBC-Rx" : "",
+ (sta->ht_capabilities & WL_STA_CAP_DELAYED_BA) ? " D-BlockAck" : "",
+ (sta->ht_capabilities & WL_STA_CAP_40MHZ_INTOLERANT) ? " 40-Intl" : "");
+
+ if (sta->flags & WL_STA_VHT_CAP) {
+ printf("\t VHT caps 0x%x:%s%s%s%s%s%s%s%s%s%s%s\n",
+ sta->vht_flags,
+ (sta->vht_flags & WL_STA_VHT_LDPCCAP) ? " LDPC" : "",
+ (sta->vht_flags & WL_STA_SGI80) ? " SGI80" : "",
+ (sta->vht_flags & WL_STA_SGI160) ? " SGI160" : "",
+ (sta->vht_flags & WL_STA_VHT_TX_STBCCAP) ? " STBC-Tx" : "",
+ (sta->vht_flags & WL_STA_VHT_RX_STBCCAP) ? " STBC-Rx" : "",
+ (sta->vht_flags & WL_STA_SU_BEAMFORMER) ? " SU-BFR" : "",
+ (sta->vht_flags & WL_STA_SU_BEAMFORMEE) ? " SU-BFE" : "",
+ (sta->vht_flags & WL_STA_MU_BEAMFORMER) ? " MU-BFR" : "",
+ (sta->vht_flags & WL_STA_MU_BEAMFORMEE) ? " MU-BFE" : "",
+ (sta->vht_flags & WL_STA_VHT_TXOP_PS) ? " TXOPPS" : "",
+ (sta->vht_flags & WL_STA_HTC_VHT_CAP) ? " VHT-HTC" : "");
+ }
+
+ if (sta->flags & WL_STA_SCBSTATS)
+ {
+ printf("\t tx total pkts: %d\n", dtoh32(sta->tx_tot_pkts));
+ printf("\t tx total bytes: %llu\n", dtoh64(sta->tx_tot_bytes));
+ printf("\t tx ucast pkts: %d\n", dtoh32(sta->tx_pkts));
+ printf("\t tx ucast bytes: %llu\n", dtoh64(sta->tx_ucast_bytes));
+ printf("\t tx mcast/bcast pkts: %d\n", dtoh32(sta->tx_mcast_pkts));
+ printf("\t tx mcast/bcast bytes: %llu\n", dtoh64(sta->tx_mcast_bytes));
+ printf("\t tx failures: %d\n", dtoh32(sta->tx_failures));
+ printf("\t rx data pkts: %d\n", dtoh32(sta->rx_tot_pkts));
+ printf("\t rx data bytes: %llu\n", dtoh64(sta->rx_tot_bytes));
+ if (have_rxdurtotal) {
+ printf("\t rx data dur: %u\n", rxdur_total);
+ }
+ printf("\t rx ucast pkts: %d\n", dtoh32(sta->rx_ucast_pkts));
+ printf("\t rx ucast bytes: %llu\n", dtoh64(sta->rx_ucast_bytes));
+ printf("\t rx mcast/bcast pkts: %d\n", dtoh32(sta->rx_mcast_pkts));
+ printf("\t rx mcast/bcast bytes: %llu\n", dtoh64(sta->rx_mcast_bytes));
+ printf("\t rate of last tx pkt: %d kbps - %d kbps\n",
+ dtoh32(sta->tx_rate), dtoh32(sta->tx_rate_fallback));
+ printf("\t rate of last rx pkt: %d kbps\n", dtoh32(sta->rx_rate));
+ printf("\t rx decrypt succeeds: %d\n", dtoh32(sta->rx_decrypt_succeeds));
+ printf("\t rx decrypt failures: %d\n", dtoh32(sta->rx_decrypt_failures));
+ printf("\t tx data pkts retried: %d\n", dtoh32(sta->tx_pkts_retried));
+
+ for (i = WL_ANT_IDX_1; i < WL_RSSI_ANT_MAX; i++) {
+ if (i == WL_ANT_IDX_1)
+ printf("\t per antenna rssi of last rx data frame:");
+ printf(" %d", dtoh32(sta->rx_lastpkt_rssi[i]));
+ if (i == WL_RSSI_ANT_MAX-1)
+ printf("\n");
+ }
+ for (i = WL_ANT_IDX_1; i < WL_RSSI_ANT_MAX; i++) {
+ if (i == WL_ANT_IDX_1)
+ printf("\t per antenna average rssi of rx data frames:");
+ printf(" %d", dtoh32(sta->rssi[i]));
+ if (i == WL_RSSI_ANT_MAX-1)
+ printf("\n");
+ }
+ for (i = WL_ANT_IDX_1; i < WL_RSSI_ANT_MAX; i++) {
+ if (i == WL_ANT_IDX_1)
+ printf("\t per antenna noise floor:");
+ printf(" %d", dtoh32(sta->nf[i]));
+ if (i == WL_RSSI_ANT_MAX-1)
+ printf("\n");
+ }
+
+ printf("\t tx total pkts sent: %d\n", dtoh32(sta->tx_pkts_total));
+ printf("\t tx pkts retries: %d\n", dtoh32(sta->tx_pkts_retries));
+ printf("\t tx pkts retry exhausted: %d\n", dtoh32(sta->tx_pkts_retry_exhausted));
+ printf("\t tx FW total pkts sent: %d\n", dtoh32(sta->tx_pkts_fw_total));
+ printf("\t tx FW pkts retries: %d\n", dtoh32(sta->tx_pkts_fw_retries));
+ printf("\t tx FW pkts retry exhausted: %d\n",
+ dtoh32(sta->tx_pkts_fw_retry_exhausted));
+ printf("\t rx total pkts retried: %d\n", dtoh32(sta->rx_pkts_retried));
+ }
+ /* Driver didn't return extended station info */
+ if (sta->len < sizeof(sta_info_v5_t)) {
+ return 0;
+ }
+
+ if (have_rateset_adv) {
+ wl_print_mcsset((char *)rateset_adv->mcs);
+ wl_print_vhtmcsset((uint16 *)rateset_adv->vht_mcs);
+ }
+
+ return (0);
+}
+
+static int
+wl_revinfo(void *wl, cmd_t *cmd, char **argv)
+{
+ char b[8];
+ int err;
+ wlc_rev_info_t revinfo;
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ memset(&revinfo, 0, sizeof(revinfo));
+
+ if ((err = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0)
+ return err;
+
+ printf("vendorid 0x%x\n", dtoh32(revinfo.vendorid));
+ printf("deviceid 0x%x\n", dtoh32(revinfo.deviceid));
+ printf("radiorev 0x%x\n", dtoh32(revinfo.radiorev));
+ printf("chipnum 0x%x\n", dtoh32(revinfo.chipnum));
+ printf("chiprev 0x%x\n", dtoh32(revinfo.chiprev));
+ printf("chippackage 0x%x\n", dtoh32(revinfo.chippkg));
+ printf("corerev %d.%d\n", dtoh32(revinfo.corerev), dtoh32(revinfo.coreminorrev));
+ printf("boardid 0x%x\n", dtoh32(revinfo.boardid));
+ printf("boardvendor 0x%x\n", dtoh32(revinfo.boardvendor));
+ printf("boardrev %s\n", bcm_brev_str(dtoh32(revinfo.boardrev), b));
+ if (revinfo.driverrev) {
+ uint32 rev = dtoh32(revinfo.driverrev);
+ printf("driverrev %d.%d.%d.%d\n",
+ (rev >> 24) & 0xFF,
+ (rev >> 16) & 0xFF,
+ (rev >> 8) & 0xFF,
+ rev & 0xFF);
+ } else {
+ printf("driverrev %d.%d.%d.%d\n",
+ dtoh32(revinfo.drvrev_major),
+ dtoh32(revinfo.drvrev_minor),
+ dtoh32(revinfo.drvrev_rc),
+ dtoh32(revinfo.drvrev_rc_inc));
+ }
+ printf("ucoderev 0x%x\n", dtoh32(revinfo.ucoderev));
+ printf("bus 0x%x\n", dtoh32(revinfo.bus));
+ printf("phytype 0x%x\n", dtoh32(revinfo.phytype));
+ printf("phyrev %d.%d\n", dtoh32(revinfo.phyrev), dtoh32(revinfo.phyminorrev));
+ printf("anarev 0x%x\n", dtoh32(revinfo.anarev));
+ printf("nvramrev %d\n", dtoh32(revinfo.nvramrev));
+
+ return 0;
+}
+
+static int
+wl_rm_request(void *wl, cmd_t *cmd, char **argv)
+{
+ miniopt_t to;
+ const char* fn_name = "wl_rm_request";
+ wl_rm_req_t *rm_ptr;
+ wl_rm_req_t rm;
+ wl_rm_req_elt_t req;
+ int buflen = 0;
+ int err, opt_err;
+ int type;
+ bool in_measure = FALSE;
+
+ UNUSED_PARAMETER(cmd);
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ memset(&rm, 0, WL_RM_REQ_FIXED_LEN);
+ memset(&req, 0, sizeof(wl_rm_req_elt_t));
+
+ strcpy(buf, "rm_req");
+ buflen = strlen(buf) + 1;
+
+ rm_ptr = (wl_rm_req_t*)(buf + buflen);
+ buflen += WL_RM_REQ_FIXED_LEN;
+
+ /* toss the command name */
+ argv++;
+
+ miniopt_init(&to, fn_name, "p", FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 't') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for the token\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ if (!in_measure)
+ rm.token = to.val;
+ else
+ req.token = to.val;
+ }
+ if (to.opt == 'c') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for channel\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ req.chanspec = CH20MHZ_CHSPEC(to.val);
+ }
+ if (to.opt == 'd') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for duration\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ req.dur = to.val;
+ }
+
+ if (to.opt == 'p') {
+ req.flags = WL_RM_FLAG_PARALLEL;
+ }
+
+ if (to.positional) {
+ if (!strcmp(to.valstr, "basic")) {
+ type = WL_RM_TYPE_BASIC;
+ } else if (!strcmp(to.valstr, "cca")) {
+ type = WL_RM_TYPE_CCA;
+ } else if (!strcmp(to.valstr, "rpi")) {
+ type = WL_RM_TYPE_RPI;
+ } else {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a measurement type\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ /* complete the previous measurement */
+ if (in_measure) {
+ req.chanspec = wl_chspec_to_driver(req.chanspec);
+ req.token = htod32(req.token);
+ req.tsf_h = htod32(req.tsf_h);
+ req.tsf_l = htod32(req.tsf_l);
+ req.dur = htod32(req.dur);
+ memcpy(buf + buflen, &req, sizeof(wl_rm_req_elt_t));
+ buflen += sizeof(wl_rm_req_elt_t);
+ rm.count++;
+ req.chanspec = wl_chspec_from_driver(req.chanspec);
+ req.token = dtoh32(req.token);
+ req.tsf_h = dtoh32(req.tsf_h);
+ req.tsf_l = dtoh32(req.tsf_l);
+ req.dur = dtoh32(req.dur);
+ /* measure to measure default param update */
+ req.token++; /* each measure gets a new token */
+ req.flags = 0; /* measure flags are cleared between measures */
+ }
+ in_measure = TRUE;
+ req.type = (int8)type;
+ }
+ }
+
+ /* complete the last measurement */
+ if (in_measure) {
+ req.chanspec = wl_chspec_to_driver(req.chanspec);
+ req.token = htod32(req.token);
+ req.tsf_h = htod32(req.tsf_h);
+ req.tsf_l = htod32(req.tsf_l);
+ req.dur = htod32(req.dur);
+ memcpy(buf + buflen, &req, sizeof(wl_rm_req_elt_t));
+ buflen += sizeof(wl_rm_req_elt_t);
+ rm.count++;
+ }
+
+ if (rm.count == 0) {
+ fprintf(stderr, "%s: no measurement requests specified\n",
+ fn_name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ rm.token = htod32(rm.token);
+ rm.count = htod32(rm.count);
+ memcpy(rm_ptr, &rm, WL_RM_REQ_FIXED_LEN);
+
+ err = wlu_set(wl, WLC_SET_VAR, &buf[0], buflen);
+
+exit:
+ return err;
+}
+
+static int
+wl_rm_report(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_rm_rep_t *rep_set;
+ wl_rm_rep_elt_t rep;
+ char extra[128];
+ char* p;
+ const char* name;
+ uint8* data;
+ int err, bin;
+ uint32 val;
+ uint16 channel;
+ bool aband;
+ int len;
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ strcpy(buf, "rm_rep");
+
+ if ((err = wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN)) < 0)
+ return err;
+
+ rep_set = (wl_rm_rep_t *)buf;
+ rep_set->token = dtoh32(rep_set->token);
+ rep_set->len = dtoh32(rep_set->len);
+
+ printf("Measurement Report: token %d, length %d\n", rep_set->token, rep_set->len);
+
+ len = rep_set->len;
+ data = (uint8*)rep_set->rep;
+ for (; len > 0; (len -= rep.len), (data += rep.len)) {
+ if (len >= WL_RM_REP_ELT_FIXED_LEN)
+ memcpy(&rep, data, WL_RM_REP_ELT_FIXED_LEN);
+ else
+ break;
+
+ rep.chanspec = wl_chspec_from_driver(rep.chanspec);
+ rep.token = dtoh32(rep.token);
+ rep.tsf_h = dtoh32(rep.tsf_h);
+ rep.tsf_l = dtoh32(rep.tsf_l);
+ rep.dur = dtoh32(rep.dur);
+ rep.len = dtoh32(rep.len);
+
+ data += WL_RM_REP_ELT_FIXED_LEN;
+ len -= WL_RM_REP_ELT_FIXED_LEN;
+
+ if (rep.type == WL_RM_TYPE_BASIC)
+ name = "Basic";
+ else if (rep.type == WL_RM_TYPE_CCA)
+ name = "CCA";
+ else if (rep.type == WL_RM_TYPE_RPI)
+ name = "RPI";
+ else
+ name = NULL;
+
+ if (name)
+ printf("\nReport : %s\n", name);
+ else
+ printf("\nReport : %d <unknown>\n", rep.type);
+
+ p = extra;
+ if (rep.flags & WL_RM_FLAG_PARALLEL) {
+ if (p != extra)
+ p += sprintf(p, " | ");
+ p += sprintf(p, "Parallel");
+ }
+ if (rep.flags & WL_RM_FLAG_LATE) {
+ if (p != extra)
+ p += sprintf(p, " | ");
+ p += sprintf(p, "Late");
+ }
+ if (rep.flags & WL_RM_FLAG_INCAPABLE) {
+ if (p != extra)
+ p += sprintf(p, " | ");
+ p += sprintf(p, "Incapable");
+ }
+ if (rep.flags & WL_RM_FLAG_REFUSED) {
+ if (p != extra)
+ p += sprintf(p, " | ");
+ p += sprintf(p, "Refused");
+ }
+
+ if (p != extra) {
+ printf("flags : 0x%02x (%s)\n", rep.flags, extra);
+ } else {
+ printf("flags : 0x%02x\n", rep.flags);
+ }
+ printf("token : %4d\n", rep.token);
+
+ if (rep.flags & (WL_RM_FLAG_LATE |
+ WL_RM_FLAG_INCAPABLE |
+ WL_RM_FLAG_REFUSED)) {
+ continue;
+ }
+
+ channel = CHSPEC_CHANNEL(rep.chanspec);
+ aband = CHSPEC_IS5G(rep.chanspec);
+
+ printf("channel : %4d %s\n", channel,
+ aband ? "(a)":"(b)");
+ printf("start tsf: 0x%x:%08x\n", rep.tsf_h, rep.tsf_l);
+ printf("duration : %4d TU\n", rep.dur);
+
+ if (len < (int)rep.len) {
+ printf("Error: partial report element, %d report bytes "
+ "remain, element claims %d\n",
+ len, rep.len);
+ break;
+ }
+
+ if (rep.type == WL_RM_TYPE_BASIC) {
+ if (rep.len >= 4) {
+ memcpy(&val, data, sizeof(uint32));
+ val = dtoh32(val);
+ printf("Basic bits: 0x%08x\n", val);
+ }
+ } else if (rep.type == WL_RM_TYPE_CCA) {
+ if (rep.len >= 4) {
+ memcpy(&val, data, sizeof(uint32));
+ val = dtoh32(val);
+ printf("Carrier Fraction: %d / 255\n", val);
+ }
+ } else if (rep.type == WL_RM_TYPE_RPI) {
+ if (rep.len >= sizeof(wl_rm_rpi_rep_t)) {
+ wl_rm_rpi_rep_t rpi_rep;
+ int8 min = -128;
+ int8 max;
+
+ memcpy(&rpi_rep, data, sizeof(wl_rm_rpi_rep_t));
+
+ for (bin = 0; bin < 8; bin++) {
+ max = rpi_rep.rpi_max[bin];
+ if (bin == 0)
+ printf(" Power <= %3d: ",
+ max);
+ else if (bin < 7)
+ printf(" %3d < Power <= %3d: ",
+ min, max);
+ else
+ printf(" %3d < Power : ",
+ min);
+ min = max;
+ printf("%3d\n", rpi_rep.rpi[bin]);
+ }
+ }
+ }
+ }
+
+ return err;
+}
+
+static int
+wl_join_pref(void *wl, cmd_t *cmd, char **argv)
+{
+ char* data;
+ int err;
+ int len;
+ int remaining_bytes;
+ int i;
+ bcm_tlv_t *ie;
+
+ UNUSED_PARAMETER(cmd);
+
+ strcpy(buf, "join_pref");
+
+ /* set */
+ if (argv[1]) {
+ len = strlen(buf);
+ data = argv[1];
+ for (i = len + 1, len += 1 + strlen(data) / 2;
+ (i < len) && (i < (int)WLC_IOCTL_MAXLEN); i ++) {
+ char hex[] = "XX";
+ hex[0] = *data++;
+ hex[1] = *data++;
+ buf[i] = (uint8)strtoul(hex, NULL, 16);
+ }
+ err = wlu_set(wl, WLC_SET_VAR, buf, i);
+ }
+ /* get */
+ else if (!(err = wlu_get(wl, WLC_GET_VAR, buf, WLC_IOCTL_MAXLEN))) {
+ len = dtoh32(*(int *)buf);
+ data = buf + sizeof(int);
+ for (i = 0; i < len; i ++)
+ printf("%02x", (uint8)(data[i]));
+ printf("\n");
+ /* pretty print the join pref elements */
+ remaining_bytes = len;
+ ie = (bcm_tlv_t*)data;
+ if (!bcm_valid_tlv(ie, remaining_bytes))
+ ie = NULL;
+ while (ie) {
+ wl_join_pref_print_ie(ie);
+ ie = bcm_next_tlv(ie, &remaining_bytes);
+ }
+ }
+ return err;
+}
+
+static void
+wl_join_pref_print_ie(bcm_tlv_t *ie)
+{
+ int i;
+ uint8 band;
+ uint8 count;
+ int suite_len;
+ uint8 *suite;
+ int data_bytes;
+
+
+ switch (ie->id) {
+ case WL_JOIN_PREF_RSSI:
+ printf("Pref RSSI\n");
+ if (ie->len > 2)
+ printf("\t<%d extra bytes in pref data>\n", ie->len);
+ break;
+ case WL_JOIN_PREF_BAND:
+ printf("Pref BAND: ");
+ if (ie->len < 2) {
+ printf("len = %d <band pref data truncated>\n", ie->len);
+ break;
+ }
+
+ band = ie->data[1];
+ if (band == WLC_BAND_AUTO)
+ printf("0x%x AUTO (no preference)\n", band);
+ else if (band == WLC_BAND_5G)
+ printf("0x%x 5 GHz\n", band);
+ else if (band == WLC_BAND_2G)
+ printf("0x%x 2.4 GHz\n", band);
+ else if (band == WLJP_BAND_ASSOC_PREF)
+ printf("0x%x Use ASSOC_PREFER value\n", band);
+ else
+ printf("0x%x\n", band);
+
+ if (ie->len > 2)
+ printf("\t<%d extra bytes in pref data>\n", ie->len - 1);
+
+ break;
+ case WL_JOIN_PREF_WPA:
+ printf("Pref WPA: ");
+ if (ie->len < 2) {
+ printf("len = %d <WPA pref data truncated>\n", ie->len);
+ break;
+ }
+ count = ie->data[1];
+ printf("%d ACP Specs\n", count);
+
+ data_bytes = ie->len - 2;
+ suite_len = 4; /* WPA Suite Selector length, OUI + type */
+ suite = ie->data + 2;
+
+ for (i = 0; i < (int)count; i++) {
+ if (data_bytes < 3 * suite_len)
+ break;
+ printf("\t");
+ /* AKM Suite */
+ wl_join_pref_print_akm(suite);
+ printf(",");
+
+ suite = suite + suite_len;
+ /* Unicast Cipher Suite */
+ printf("U:");
+ wl_join_pref_print_cipher_suite(suite);
+ printf(",");
+
+ suite = suite + suite_len;
+ /* Multicast Cipher Suite */
+ printf("M:");
+ if (!memcmp(suite, WL_WPA_ACP_MCS_ANY, suite_len))
+ printf("Any");
+ else
+ wl_join_pref_print_cipher_suite(suite);
+ printf("\n");
+
+ suite = suite + suite_len;
+ data_bytes -= 3 * suite_len;
+ }
+
+ if (i != count)
+ printf("\t<expected %d more specs, %d bytes>\n",
+ count - i, suite_len * (count - i));
+ if (data_bytes > 0)
+ printf("\t<%d extra bytes>\n", data_bytes);
+ break;
+ case WL_JOIN_PREF_RSSI_DELTA:
+ printf("RSSI Delta for Pref BAND: ");
+ if (ie->len < 2) {
+ printf("len = %d <rssi delta pref data truncated>\n", ie->len);
+ break;
+ }
+
+ band = ie->data[1];
+ if (band == WLC_BAND_AUTO)
+ printf("0x%x AUTO (no preference)\n", band);
+ else if (band == WLC_BAND_5G)
+ printf("0x%x 5 GHz\n", band);
+ else if (band == WLC_BAND_2G)
+ printf("0x%x 2.4 GHz\n", band);
+ else
+ printf("0x%x\n", band);
+
+ printf("RSSI boost %ddb\n", ie->data[0]);
+
+ break;
+ default:
+ printf("Pref 0x%x: len = %d\n", ie->id, ie->len);
+ for (i = 0; i < ie->len; i++)
+ printf("%02x", ie->data[i]);
+ printf("\n");
+ break;
+
+ }
+
+}
+
+static void
+wl_join_pref_print_akm(uint8* suite)
+{
+ uint8 type = suite[3];
+ const char *oui_name;
+
+ if (!memcmp(suite, WPA_OUI, 3))
+ oui_name = "WPA";
+ else if (!memcmp(suite, WPA2_OUI, 3))
+ oui_name = "WPA2";
+ else
+ oui_name = NULL;
+
+ if (oui_name) {
+ if (type == RSN_AKM_NONE)
+ printf("%s-NONE", oui_name);
+ else if (type == RSN_AKM_UNSPECIFIED)
+ printf("%s", oui_name);
+ else if (type == RSN_AKM_UNSPECIFIED)
+ printf("%s-PSK", oui_name);
+ else
+ printf("%s/0x%x", oui_name, type);
+ } else {
+ printf("0x%02x%02x%02x/0x%02x", suite[0], suite[1], suite[2], suite[3]);
+ }
+}
+
+static void
+wl_join_pref_print_cipher_suite(uint8* suite)
+{
+ uint8 type = suite[3];
+ const char *oui_name;
+
+ if (!memcmp(suite, WPA_OUI, 3))
+ oui_name = "WPA";
+ else if (!memcmp(suite, WPA2_OUI, 3))
+ oui_name = "WPA2";
+ else
+ oui_name = NULL;
+
+ if (oui_name) {
+ if (type == WPA_CIPHER_NONE)
+ printf("%s/NONE", oui_name);
+ else if (type == WPA_CIPHER_WEP_40)
+ printf("%s/WEP40", oui_name);
+ else if (type == WPA_CIPHER_TKIP)
+ printf("%s/TKIP", oui_name);
+ else if (type == WPA_CIPHER_AES_CCM)
+ printf("%s/AES", oui_name);
+ else if (type == WPA_CIPHER_WEP_104)
+ printf("%s/WEP104", oui_name);
+ else
+ printf("%s/0x%x", oui_name, type);
+ } else {
+ printf("0x%02x%02x%02x/0x%02x", suite[0], suite[1], suite[2], suite[3]);
+ }
+}
+
+static int
+wl_assoc_pref(void *wl, cmd_t *cmd, char **argv)
+{
+ uint assoc_pref;
+ int err;
+
+ /* set */
+ if (argv[1]) {
+ if (!strcmp(argv[1], "auto") || !strcmp(argv[1], "0"))
+ assoc_pref = WLC_BAND_AUTO;
+ else if (!strcmp(argv[1], "a") || !strcmp(argv[1], "1"))
+ assoc_pref = WLC_BAND_5G;
+ else if (!strcmp(argv[1], "b") || !strcmp(argv[1], "g") || !strcmp(argv[1], "2"))
+ assoc_pref = WLC_BAND_2G;
+ else
+ return BCME_USAGE_ERROR;
+ assoc_pref = htod32(assoc_pref);
+ err = wlu_set(wl, cmd->set, &assoc_pref, sizeof(assoc_pref));
+ }
+ /* get */
+ else if (!(err = wlu_get(wl, cmd->get, &assoc_pref, sizeof(assoc_pref)))) {
+ assoc_pref = dtoh32(assoc_pref);
+ switch (assoc_pref) {
+ case WLC_BAND_AUTO:
+ printf("auto\n");
+ break;
+ case WLC_BAND_5G:
+ printf("a\n");
+ break;
+ case WLC_BAND_2G:
+ printf("b/g\n");
+ break;
+ }
+ }
+ return err;
+}
+
+static const char ac_names[AC_COUNT][6] = {"AC_BE", "AC_BK", "AC_VI", "AC_VO"};
+
+/*
+ * Get or set WME per-AC transmit parameters
+ */
+static int
+wme_tx_params(void *wl, cmd_t *cmd, char **argv)
+{
+ char *val_p, *ac_str, *param;
+ int buflen;
+ int aci;
+ wme_tx_params_t cur_params[AC_COUNT], new_params[AC_COUNT];
+ int err;
+ int val;
+
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+
+ buflen = WLC_IOCTL_MAXLEN;
+
+ /*
+ * Get current acparams, using buf as an input buffer.
+ * Return data is array of 4 ACs of wme params.
+ */
+
+ strcpy(buf, "wme_tx_params");
+ if ((err = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen)) < 0) {
+ return err;
+ }
+ memcpy(&cur_params, buf, WL_WME_TX_PARAMS_IO_BYTES);
+
+ if ((ac_str = *argv++) == NULL) {
+ printf("WME TX params: \n");
+ for (aci = 0; aci < AC_COUNT; aci++) {
+ printf("%s: short %d. sfb %d. long %d. lfb %d. max %d\n", ac_names[aci],
+ cur_params[aci].short_retry,
+ cur_params[aci].short_fallback,
+ cur_params[aci].long_retry,
+ cur_params[aci].long_fallback,
+ cur_params[aci].max_rate);
+ }
+ } else {
+ int chk_lim;
+ if (strcmp(ac_str, "be") == 0) {
+ aci = AC_BE;
+ } else if (strcmp(ac_str, "bk") == 0) {
+ aci = AC_BK;
+ } else if (strcmp(ac_str, "vi") == 0) {
+ aci = AC_VI;
+ } else if (strcmp(ac_str, "vo") == 0) {
+ aci = AC_VO;
+ } else {
+ printf("Unknown access class: %s\n", ac_str);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Preload new values with current values */
+ memcpy(&new_params, &cur_params, sizeof(new_params));
+ while ((param = *argv++) != NULL) {
+ if ((val_p = *argv++) == NULL) {
+ printf("Need value following %s\n", param);
+ return BCME_USAGE_ERROR;
+ }
+ chk_lim = 15;
+ val = (int)strtoul(val_p, NULL, 0);
+ /* All values must fit in uint8 */
+ if (!strcmp(param, "short")) {
+ new_params[aci].short_retry = (uint8)val;
+ } else if (!strcmp(param, "sfb")) {
+ new_params[aci].short_fallback = (uint8)val;
+ } else if (!strcmp(param, "long")) {
+ new_params[aci].long_retry = (uint8)val;
+ } else if (!strcmp(param, "lfb")) {
+ new_params[aci].long_fallback = (uint8)val;
+ } else if ((!strcmp(param, "max_rate")) || (!strcmp(param, "max")) ||
+ (!strcmp(param, "rate"))) {
+ chk_lim = 255;
+ new_params[aci].max_rate = (uint8)val;
+ } else {
+ printf("Unknown parameter: %s\n", param);
+ return BCME_USAGE_ERROR;
+ }
+ if (val > chk_lim) {
+ printf("Value for %s must be < %d\n", param, chk_lim + 1);
+ return BCME_USAGE_ERROR;
+ }
+ }
+ strcpy(buf, "wme_tx_params");
+ memcpy(buf + strlen(buf) + 1, new_params, WL_WME_TX_PARAMS_IO_BYTES);
+ err = wlu_set(wl, WLC_SET_VAR, &buf[0], buflen);
+ }
+
+ return err;
+}
+
+/*
+ * Get or Set WME Access Class (AC) parameters
+ * wl wme_ac ap|sta [be|bk|vi|vo [ecwmax|ecwmin|txop|aifsn|acm <value>] ...]
+ * Without args past ap|sta, print current values
+ */
+static int
+wl_wme_ac_req(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *iovar_name;
+ int err;
+ edcf_acparam_t acparam_cur[AC_COUNT], acparam_new[AC_COUNT], *acp;
+ char *ac_str, *param, *val;
+ bool acm;
+ int aci, aifsn, ecwmin, ecwmax, txop;
+
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+
+ if ((param = *argv++) == NULL)
+ return BCME_USAGE_ERROR;
+
+ if (!strcmp(param, "ap"))
+ iovar_name = "wme_ac_ap";
+ else if (!strcmp(param, "sta"))
+ iovar_name = "wme_ac_sta";
+ else
+ return BCME_USAGE_ERROR;
+
+ /*
+ * Get current acparams into an array of 4 ACs of wme params.
+ */
+ err = wlu_iovar_get(wl, iovar_name, &acparam_cur, sizeof(acparam_cur));
+ if (err < 0)
+ return err;
+
+ if ((ac_str = *argv++) == NULL) {
+ printf("AC Parameters\n");
+
+ for (aci = 0; aci < AC_COUNT; aci++) {
+ acp = &acparam_cur[aci];
+ acp->TXOP = dtoh16(acp->TXOP);
+ if (((acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT) != aci)
+ printf("Warning: AC params out of order\n");
+ acm = (acp->ACI & EDCF_ACM_MASK) ? 1 : 0;
+ aifsn = acp->ACI & EDCF_AIFSN_MASK;
+ ecwmin = acp->ECW & EDCF_ECWMIN_MASK;
+ ecwmax = (acp->ECW & EDCF_ECWMAX_MASK) >> EDCF_ECWMAX_SHIFT;
+ txop = acp->TXOP;
+ printf("%s: raw: ACI 0x%x ECW 0x%x TXOP 0x%x\n",
+ ac_names[aci],
+ acp->ACI, acp->ECW, acp->TXOP);
+ printf(" dec: aci %d acm %d aifsn %d "
+ "ecwmin %d ecwmax %d txop 0x%x\n",
+ aci, acm, aifsn, ecwmin, ecwmax, txop);
+ /* CWmin = 2^(ECWmin) - 1 */
+ /* CWmax = 2^(ECWmax) - 1 */
+ /* TXOP = number of 32 us units */
+ printf(" eff: CWmin %d CWmax %d TXop %dusec\n",
+ EDCF_ECW2CW(ecwmin), EDCF_ECW2CW(ecwmax), EDCF_TXOP2USEC(txop));
+ }
+
+ err = 0;
+ } else {
+ if (strcmp(ac_str, "be") == 0)
+ aci = AC_BE;
+ else if (strcmp(ac_str, "bk") == 0)
+ aci = AC_BK;
+ else if (strcmp(ac_str, "vi") == 0)
+ aci = AC_VI;
+ else if (strcmp(ac_str, "vo") == 0)
+ aci = AC_VO;
+ else
+ return BCME_USAGE_ERROR;
+
+ /* Preload new values with current values */
+ memcpy(&acparam_new, &acparam_cur, sizeof(acparam_new));
+
+ acp = &acparam_new[aci];
+
+ while ((param = *argv++) != NULL) {
+ if ((val = *argv++) == NULL)
+ return BCME_USAGE_ERROR;
+
+ if (!strcmp(param, "acm")) {
+ if (!stricmp(val, "on") || !stricmp(val, "1"))
+ acp->ACI |= EDCF_ACM_MASK;
+ else if (!stricmp(val, "off") || !stricmp(val, "0"))
+ acp->ACI &= ~EDCF_ACM_MASK;
+ else {
+ fprintf(stderr, "acm value must be 1|0\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!strcmp(param, "aifsn")) {
+ aifsn = (int)strtol(val, NULL, 0);
+ if (aifsn >= EDCF_AIFSN_MIN && aifsn <= EDCF_AIFSN_MAX)
+ acp->ACI =
+ (acp->ACI & ~EDCF_AIFSN_MASK) |
+ (aifsn & EDCF_AIFSN_MASK);
+ else {
+ fprintf(stderr, "aifsn %d out of range (%d-%d)\n",
+ aifsn, EDCF_AIFSN_MIN, EDCF_AIFSN_MAX);
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!strcmp(param, "ecwmax")) {
+ ecwmax = (int)strtol(val, NULL, 0);
+ if (ecwmax >= EDCF_ECW_MIN && ecwmax <= EDCF_ECW_MAX)
+ acp->ECW =
+ ((ecwmax << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK) |
+ (acp->ECW & EDCF_ECWMIN_MASK);
+ else {
+ fprintf(stderr, "ecwmax %d out of range (%d-%d)\n",
+ ecwmax, EDCF_ECW_MIN, EDCF_ECW_MAX);
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!strcmp(param, "ecwmin")) {
+ ecwmin = (int)strtol(val, NULL, 0);
+ if (ecwmin >= EDCF_ECW_MIN && ecwmin <= EDCF_ECW_MAX)
+ acp->ECW =
+ ((acp->ECW & EDCF_ECWMAX_MASK) |
+ (ecwmin & EDCF_ECWMIN_MASK));
+ else {
+ fprintf(stderr, "ecwmin %d out of range (%d-%d)\n",
+ ecwmin, EDCF_ECW_MIN, EDCF_ECW_MAX);
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!strcmp(param, "txop")) {
+ txop = (int)strtol(val, NULL, 0);
+ if (txop >= EDCF_TXOP_MIN && txop <= EDCF_TXOP_MAX)
+ acp->TXOP = htod16(txop);
+ else {
+ fprintf(stderr, "txop %d out of range (%d-%d)\n",
+ txop, EDCF_TXOP_MIN, EDCF_TXOP_MAX);
+ return BCME_USAGE_ERROR;
+ }
+ } else {
+ fprintf(stderr, "unexpected param %s\n", param);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ /*
+ * Now set the new acparams
+ * NOTE: only one of the four ACs can be set at a time.
+ */
+ err = wlu_iovar_set(wl, iovar_name, acp, sizeof(edcf_acparam_t));
+ }
+
+ return err;
+}
+
+/*
+ * Get or Set WME APSD control parameters
+ * wl wme_apsd_sta <max_sp_len> <be> <bk> <vi> <vo>
+ * <max_sp_len> is 0 (all), 2, 4, or 6
+ * <be>, <bk>, <vi>, <vo> are each 0 or 1 for APSD enable
+ * with no args, print current values
+ */
+static int
+wl_wme_apsd_sta(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int buflen;
+ char *param;
+ int qosinfo;
+ int msp, max_sp_len, be, bk, vi, vo;
+
+ /* Display current params if no args, else set params */
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(buf, "wme_qosinfo");
+ buflen = WLC_IOCTL_MAXLEN;
+
+ param = *++argv;
+
+ if (param == NULL) {
+ if ((err = wlu_get(wl, cmd->get, &buf[0], buflen)) < 0)
+ return err;
+
+ memcpy(&qosinfo, buf, sizeof(qosinfo));
+ qosinfo = dtoh32(qosinfo);
+
+ msp = (qosinfo & WME_QI_STA_MAXSPLEN_MASK) >> WME_QI_STA_MAXSPLEN_SHIFT;
+ be = (qosinfo & WME_QI_STA_APSD_BE_MASK) >> WME_QI_STA_APSD_BE_SHIFT;
+ bk = (qosinfo & WME_QI_STA_APSD_BK_MASK) >> WME_QI_STA_APSD_BK_SHIFT;
+ vi = (qosinfo & WME_QI_STA_APSD_VI_MASK) >> WME_QI_STA_APSD_VI_SHIFT;
+ vo = (qosinfo & WME_QI_STA_APSD_VO_MASK) >> WME_QI_STA_APSD_VO_SHIFT;
+
+ max_sp_len = msp * 2;
+
+ printf("Max SP Length = %d, APSD: BE=%d BK=%d VI=%d VO=%d\n",
+ max_sp_len, be, bk, vi, vo);
+ } else {
+ max_sp_len = (int)strtol(param, 0, 0);
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+ be = (int)strtol(param, 0, 0);
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+ bk = (int)strtol(param, 0, 0);
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+ vi = (int)strtol(param, 0, 0);
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+ vo = (int)strtol(param, 0, 0);
+
+ if (((be | bk | vi | vo) & ~1) | (max_sp_len & ~6)) {
+ printf("%s: Invalid parameter\n", cmd->name);
+ return BCME_BADARG;
+ }
+
+ msp = max_sp_len / 2;
+
+ qosinfo = (msp << WME_QI_STA_MAXSPLEN_SHIFT) & WME_QI_STA_MAXSPLEN_MASK;
+ qosinfo |= (be << WME_QI_STA_APSD_BE_SHIFT) & WME_QI_STA_APSD_BE_MASK;
+ qosinfo |= (bk << WME_QI_STA_APSD_BK_SHIFT) & WME_QI_STA_APSD_BK_MASK;
+ qosinfo |= (vi << WME_QI_STA_APSD_VI_SHIFT) & WME_QI_STA_APSD_VI_MASK;
+ qosinfo |= (vo << WME_QI_STA_APSD_VO_SHIFT) & WME_QI_STA_APSD_VO_MASK;
+
+ qosinfo = htod32(qosinfo);
+ memcpy(&buf[strlen(buf) + 1], &qosinfo, sizeof(qosinfo));
+
+ err = wlu_set(wl, cmd->set, &buf[0], buflen);
+ }
+
+ return err;
+}
+
+/*
+ * Get or Set WME discard policy
+ * wl wme_dp <be> <bk> <vi> <vo>
+ * <be>, <bk>, <vi>, <vo> are each 0/1 for discard newest/oldest first
+ * with no args, print current values
+ */
+static int
+wl_wme_dp(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int buflen;
+ char *param;
+ int dp;
+ int be, bk, vi, vo;
+
+ /* Display current params if no args, else set params */
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(buf, "wme_dp");
+ buflen = WLC_IOCTL_MAXLEN;
+
+ param = *++argv;
+
+ if (param == NULL) {
+ if ((err = wlu_get(wl, cmd->get, &buf[0], buflen)) < 0)
+ return err;
+
+ memcpy(&dp, buf, sizeof(dp));
+ dp = dtoh32(dp);
+
+ be = (dp >> AC_BE) & 1;
+ bk = (dp >> AC_BK) & 1;
+ vi = (dp >> AC_VI) & 1;
+ vo = (dp >> AC_VO) & 1;
+
+ printf("Discard oldest first: BE=%d BK=%d VI=%d VO=%d\n", be, bk, vi, vo);
+ } else {
+ be = (int)strtol(param, 0, 0);
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+ bk = (int)strtol(param, 0, 0);
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+ vi = (int)strtol(param, 0, 0);
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+ vo = (int)strtol(param, 0, 0);
+
+ if ((be | bk | vi | vo) & ~1) {
+ printf("%s: Invalid parameter\n", cmd->name);
+ return BCME_BADARG;
+ }
+
+ dp = (be << AC_BE) | (bk << AC_BK) | (vi << AC_VI) | (vo << AC_VO);
+
+ dp = htod32(dp);
+ memcpy(&buf[strlen(buf) + 1], &dp, sizeof(dp));
+
+ err = wlu_set(wl, cmd->set, &buf[0], buflen);
+ }
+
+ return err;
+}
+
+/*
+ * Get or Set WME lifetime parameter
+ * "wl lifetime be|bk|vi|vo [<value>]"},
+ * with no args, print current values
+ */
+static int
+wl_lifetime(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ uint8 ac;
+ char *param, *val;
+ const char *cmdname = "lifetime";
+ wl_lifetime_t lifetime, *reply;
+ void *ptr = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+
+ if (strcmp(param, "be") == 0)
+ ac = AC_BE;
+ else if (strcmp(param, "bk") == 0)
+ ac = AC_BK;
+ else if (strcmp(param, "vi") == 0)
+ ac = AC_VI;
+ else if (strcmp(param, "vo") == 0)
+ ac = AC_VO;
+ else {
+ fprintf(stderr, "unexpected param %s\n", param);
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((val = *++argv) == NULL) {
+ lifetime.ac = htod32(ac);
+ if ((err = wlu_var_getbuf(wl, cmdname, &lifetime, sizeof(lifetime),
+ &ptr)) < 0)
+ return err;
+ reply = (wl_lifetime_t *) ptr;
+ reply->ac = dtoh32(reply->ac);
+ reply->lifetime = dtoh32(reply->lifetime);
+ printf("Lifetime for access class '%s' is %dms\n", param, reply->lifetime);
+ }
+ else {
+ lifetime.ac = htod32(ac);
+ lifetime.lifetime = htod32((uint)strtol(val, 0, 0));
+ err = wlu_var_setbuf(wl, cmdname, &lifetime, sizeof(lifetime));
+ }
+
+ return err;
+}
+
+#define VNDR_IE_OK_FLAGS \
+ (VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | VNDR_IE_ASSOCRSP_FLAG | \
+ VNDR_IE_AUTHRSP_FLAG | VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG | \
+ VNDR_IE_AUTHREQ_FLAG)
+
+static int
+wl_add_ie(void *wl, cmd_t *cmd, char **argv)
+{
+ UNUSED_PARAMETER(cmd);
+
+ return (wl_vndr_ie(wl, "add", VNDR_IE_OK_FLAGS, argv));
+}
+
+static int
+wl_del_ie(void *wl, cmd_t *cmd, char **argv)
+{
+ UNUSED_PARAMETER(cmd);
+
+ return (wl_vndr_ie(wl, "del", VNDR_IE_OK_FLAGS, argv));
+}
+
+int
+wl_mk_ie_setbuf(const char *command, uint32 pktflag_ok, char **argv,
+ vndr_ie_setbuf_t **buf, int *buf_len)
+{
+ vndr_ie_setbuf_t *ie_setbuf;
+ uint32 pktflag;
+ int ielen, datalen, buflen, iecount;
+ int err = 0;
+
+ if (!argv[1] || !argv[2] || !argv[3]) {
+ fprintf(stderr, "Too few arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ pktflag = (uint)strtol(argv[1], 0, 0);
+
+ if (pktflag & ~pktflag_ok) {
+ fprintf(stderr, "Invalid packet flag 0x%x (%d)\n", pktflag, pktflag);
+ return BCME_BADARG;
+ }
+
+ ielen = atoi(argv[2]);
+ if (ielen > VNDR_IE_MAX_LEN) {
+ fprintf(stderr, "IE length is %d, should be <= %d\n", ielen, VNDR_IE_MAX_LEN);
+ return BCME_BADARG;
+ }
+ else if (ielen < VNDR_IE_MIN_LEN) {
+ fprintf(stderr, "IE length is %d, should be >= %d\n", ielen, VNDR_IE_MIN_LEN);
+ return BCME_BADARG;
+ }
+
+ if (strlen(argv[3]) != OUI_STR_SIZE) {
+ fprintf(stderr, "Invalid OUI length %d\n", (int)strlen(argv[3]));
+ return BCME_BADARG;
+ }
+
+ datalen = ielen - VNDR_IE_MIN_LEN;
+ if (datalen > 0) {
+ if (!argv[4]) {
+ fprintf(stderr, "Data bytes should be specified for IE of length %d\n",
+ ielen);
+ return BCME_USAGE_ERROR;
+ }
+ else {
+ /* Ensure each data byte is 2 characters long */
+ if ((int)strlen (argv[4]) < (datalen * 2)) {
+ fprintf(stderr, "Please specify all the data bytes for this IE\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ }
+
+ if (datalen == 0 && (argv[4] != NULL))
+ fprintf(stderr, "Ignoring data bytes for IE of length %d", ielen);
+
+ buflen = sizeof(vndr_ie_setbuf_t) + datalen - 1;
+
+ ie_setbuf = (vndr_ie_setbuf_t *) malloc(buflen);
+
+ if (ie_setbuf == NULL) {
+ fprintf(stderr, "memory alloc failure\n");
+ return BCME_NOMEM;
+ }
+
+ /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
+ strncpy(ie_setbuf->cmd, command, VNDR_IE_CMD_LEN - 1);
+ ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+
+ /* Buffer contains only 1 IE */
+ iecount = htod32(1);
+ memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
+
+ /*
+ * The packet flag bit field indicates the packets that will
+ * contain this IE
+ */
+ pktflag = htod32(pktflag);
+ memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
+ &pktflag, sizeof(uint32));
+
+ /* Now, add the IE to the buffer */
+ ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar)DOT11_MNG_VS_ID;
+ ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
+
+ if ((err = get_oui_bytes ((uchar *)argv[3],
+ &ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0]))) {
+ free(ie_setbuf);
+ fprintf(stderr, "Error parsing OUI arg\n");
+ return BCME_BADARG;
+ }
+
+ if (datalen > 0) {
+ if ((err = get_ie_data ((uchar *)argv[4],
+ &ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0],
+ datalen))) {
+ free(ie_setbuf);
+ fprintf(stderr, "Error parsing data arg\n");
+ return BCME_BADARG;
+ }
+ }
+
+ /* Copy-out */
+ if (buf) {
+ *buf = ie_setbuf;
+ ie_setbuf = NULL;
+ }
+ if (buf_len)
+ *buf_len = buflen;
+
+ /* Clean-up */
+ if (ie_setbuf)
+ free(ie_setbuf);
+
+ return (err);
+}
+
+static int
+wl_vndr_ie(void *wl, const char *command, uint32 pktflag_ok, char **argv)
+{
+ vndr_ie_setbuf_t *ie_setbuf;
+ int buflen;
+ int err = 0;
+ int ret;
+ int bsscfg_idx = 0;
+ int consumed = 0;
+
+ /* parse a bsscfg_idx option if present */
+ if ((ret = wl_cfg_option(argv + 1, argv[0], &bsscfg_idx, &consumed)) != 0)
+ return ret;
+ if (consumed)
+ argv = argv + consumed;
+ else
+ bsscfg_idx = -1;
+
+ if ((err = wl_mk_ie_setbuf(command, pktflag_ok, argv, &ie_setbuf, &buflen)) != 0)
+ return err;
+
+ if (bsscfg_idx == -1)
+ err = wlu_var_setbuf(wl, "vndr_ie", ie_setbuf, buflen);
+ else
+ err = wlu_bssiovar_setbuf(wl, "vndr_ie", bsscfg_idx,
+ ie_setbuf, buflen, buf, WLC_IOCTL_MAXLEN);
+
+ free(ie_setbuf);
+
+ return (err);
+}
+
+int
+wl_list_ie(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ void *ptr;
+ ie_getbuf_t param;
+
+ BCM_REFERENCE(argv);
+
+ param.pktflag = (uint32) -1;
+ param.id = (uint8)DOT11_MNG_VS_ID;
+ err = wlu_var_getbuf(wl, cmd->name, ¶m, sizeof(param), &ptr);
+ if (err == 0) {
+ wl_dump_ie_buf((vndr_ie_buf_t *)ptr);
+ } else {
+ fprintf(stderr, "Error %d getting IOVar\n", err);
+ }
+
+ return err;
+}
+
+static int
+_wl_list_ie(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ const char *old = cmd->name;
+
+ cmd->name = "vndr_ie";
+ err = wl_list_ie(wl, cmd, argv);
+ cmd->name = old;
+
+ return err;
+}
+
+static void
+wl_dump_ie_buf(vndr_ie_buf_t *ie_getbuf)
+{
+ uchar *iebuf;
+ uchar *data;
+ int tot_ie, pktflag, iecount, count, datalen, col;
+ vndr_ie_info_t *ie_info;
+ vndr_ie_t *ie;
+
+ memcpy(&tot_ie, (void *)&ie_getbuf->iecount, sizeof(int));
+ tot_ie = dtoh32(tot_ie);
+ printf("Total IEs %d\n", tot_ie);
+
+ iebuf = (uchar *)&ie_getbuf->vndr_ie_list[0];
+
+ for (iecount = 0; iecount < tot_ie; iecount++) {
+ ie_info = (vndr_ie_info_t *) iebuf;
+ memcpy(&pktflag, (void *)&ie_info->pktflag, sizeof(uint32));
+ pktflag = dtoh32(pktflag);
+ iebuf += sizeof(uint32);
+
+ printf("\n");
+
+ ie = &ie_info->vndr_ie_data;
+ printf("IE index = %d\n", iecount);
+ printf("-----------------\n");
+ printf("Pkt Flg = 0x%x\n", pktflag);
+ printf("Length = %d\n", ie->len);
+ printf("OUI = %02x:%02x:%02x\n",
+ ie->oui[0], ie->oui[1], ie->oui[2]);
+ printf("Data:\n");
+
+ data = &ie->data[0];
+ datalen = ie->len - VNDR_IE_MIN_LEN;
+ for (count = 0; (count < datalen);) {
+ for (col = 0; (col < MAX_DATA_COLS) &&
+ (count < datalen); col++, count++) {
+ printf("%02x ", *data++);
+ }
+ printf("\n");
+ }
+
+ iebuf += ie->len + VNDR_IE_HDR_LEN;
+ }
+}
+
+static int
+wl_rand(void *wl, cmd_t *cmd, char **argv)
+{
+ char *randbuf;
+ uint16 randnum;
+ int err;
+ void *ptr;
+
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_var_getbuf (wl, cmd->name, NULL, 0, &ptr)))
+ return (err);
+
+ randbuf = (char *)ptr;
+ memcpy(&randnum, randbuf, sizeof(uint16));
+ printf("%d\n", randnum);
+
+ return (0);
+}
+
+static int
+wl_wlc_ver(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ int err;
+ wl_wlc_version_t *ver;
+ char buf[256];
+
+ UNUSED_PARAMETER(argv);
+
+ /* skip the command name */
+ argv++;
+
+ /* validate absence of arguments */
+ if (*argv) {
+ fprintf(stderr,
+ "\"%s\" wlc_ver iovar doesn't take any arguments\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, NULL, 0, &ptr))) {
+ return err;
+ }
+
+ ver = (wl_wlc_version_t *)ptr;
+ sprintf(buf, "wlc_ver %d.%d\n" "epi_ver %d.%d.%d.%d\n",
+ ver->wlc_ver_major, ver->wlc_ver_minor, ver->epi_ver_major,
+ ver->epi_ver_minor, ver->epi_rc_num, ver->epi_incr_num);
+
+ fputs(buf, stdout);
+
+ return 0;
+}
+
+static int
+wl_wme_counters(void *wl, cmd_t *cmd, char **argv)
+{
+ char *statsbuf;
+ wl_wme_cnt_t cnt;
+ int err;
+ void *ptr;
+ char *pbuf = buf;
+ uint ac;
+ int ap_mode = 0;
+
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_var_getbuf_sm (wl, cmd->name, NULL, 0, &ptr)))
+ return (err);
+
+ statsbuf = (char *)ptr;
+ memcpy(&cnt, statsbuf, sizeof(cnt));
+ cnt.version = dtoh16(cnt.version);
+ cnt.length = dtoh16(cnt.length);
+
+ if (cnt.version != WL_WME_CNT_VERSION) {
+ printf("\tIncorrect version of counters struct: expected %d; got %d\n",
+ WL_WME_CNT_VERSION, cnt.version);
+ return -1;
+ }
+
+ if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))) < 0) {
+ return err;
+ }
+ ap_mode = dtoh32(ap_mode);
+
+ /* summary stat counter line */
+ for (ac = AC_BE; ac < AC_COUNT; ac++) {
+ pbuf += sprintf(pbuf, "\n%s: tx frames: %u bytes: %u failed frames: %u "
+ "failed bytes: %u\n",
+ ac_names[ac], dtoh32(cnt.tx[ac].packets), dtoh32(cnt.tx[ac].bytes),
+ dtoh32(cnt.tx_failed[ac].packets), dtoh32(cnt.tx_failed[ac].bytes));
+ pbuf += sprintf(pbuf, " rx frames: %u bytes: %u failed frames: %u "
+ "failed bytes: %u\n", dtoh32(cnt.rx[ac].packets),
+ dtoh32(cnt.rx[ac].bytes), dtoh32(cnt.rx_failed[ac].packets),
+ dtoh32(cnt.rx_failed[ac].bytes));
+
+ if (ap_mode)
+ pbuf += sprintf(pbuf, " foward frames: %u bytes: %u \n",
+ dtoh32(cnt.forward[ac].packets),
+ dtoh32(cnt.forward[ac].bytes));
+
+ pbuf += sprintf(pbuf, " tx frames time expired: %u \n",
+ dtoh32(cnt.tx_expired[ac].packets));
+ }
+ pbuf += sprintf(pbuf, "\n");
+ fputs(buf, stdout);
+ return (0);
+}
+
+int
+get_oui_bytes(uchar *oui_str, uchar *oui)
+{
+ int idx;
+ uchar val;
+ uchar *src, *dest;
+ char hexstr[3];
+
+ src = oui_str;
+ dest = oui;
+
+ for (idx = 0; idx < MAX_OUI_SIZE; idx++) {
+ hexstr[0] = src[0];
+ hexstr[1] = src[1];
+ hexstr[2] = '\0';
+
+ val = (uchar) strtoul(hexstr, NULL, 16);
+
+ *dest++ = val;
+ src += 2;
+
+ if ((idx < (MAX_OUI_SIZE - 1)) && (*src++ != ':'))
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+get_ie_data(uchar *data_str, uchar *ie_data, int len)
+{
+ uchar *src, *dest;
+ uchar val;
+ int idx;
+ char hexstr[3];
+
+ src = data_str;
+ dest = ie_data;
+
+ for (idx = 0; idx < len; idx++) {
+ hexstr[0] = src[0];
+ hexstr[1] = src[1];
+ hexstr[2] = '\0';
+
+ val = (uchar) strtoul(hexstr, NULL, 16);
+
+ *dest++ = val;
+ src += 2;
+ }
+
+ return 0;
+}
+
+int
+hexstrtobitvec(const char *cp, uchar *bitvec, int veclen)
+{
+ uchar value = 0;
+ int nibble; /* index of current hex-format nibble to process */
+ int even; /* 1 if even number of nibbles, 0 if odd number */
+ int i = 0;
+
+ if (cp[0] == '0' && cp[1] == 'x')
+ cp += 2;
+
+ memset(bitvec, '\0', veclen);
+ nibble = strlen(cp);
+ if (!nibble)
+ return -1;
+ even = ((nibble % 2) == 0);
+
+ /* convert from right to left (lsb is rightmost byte) */
+ --nibble;
+ while (nibble >= 0 && i < veclen && (isxdigit((int)cp[nibble]) &&
+ (value = isdigit((int)cp[nibble]) ? cp[nibble]-'0' :
+ (islower((int)cp[nibble]) ? toupper((int)cp[nibble]) : cp[nibble])-'A'+10) < 16)) {
+ if (even == ((nibble+1) % 2)) {
+ bitvec[i] += value*16;
+ ++i;
+ } else
+ bitvec[i] = value;
+ --nibble;
+ }
+
+ return ((nibble == -1 && i <= veclen) ? 0 : -1);
+}
+
+#define WL_EVENTING_MASK_MAX_LEN 64
+#define WL_EVENTINT_MAX_GET_SIZE (WL_EVENTING_MASK_MAX_LEN + EVENTMSGS_EXT_STRUCT_SIZE)
+
+static int
+wl_bitvecext(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, bcmerr;
+ eventmsgs_ext_t *eventmask_msg;
+ uint8 masksize;
+ err = 0;
+
+ bcmerr = 1;
+
+ /* set */
+ if (argv[1]) {
+ uint8 send_iovar_datasize;
+ /* send user mask size up to WL_EVENTING_MASK_MAX_LEN */
+ masksize = MIN((strlen(argv[1])/2), WL_EVENTING_MASK_MAX_LEN);
+ send_iovar_datasize = masksize + EVENTMSGS_EXT_STRUCT_SIZE;
+ eventmask_msg = (eventmsgs_ext_t*)malloc(send_iovar_datasize);
+ if (eventmask_msg == NULL) {
+ fprintf(stderr, "fail to allocate event_msgs"
+ "structure of %d bytes\n", send_iovar_datasize);
+ return BCME_NOMEM;
+ }
+ memset((void*)eventmask_msg, 0, send_iovar_datasize);
+ eventmask_msg->len = masksize;
+ eventmask_msg->command = EVENTMSGS_SET_MASK;
+ eventmask_msg->ver = EVENTMSGS_VER;
+ if (!(err = hexstrtobitvec(argv[1], eventmask_msg->mask, eventmask_msg->len))) {
+ err = wlu_var_setbuf(wl, cmd->name, (void*)eventmask_msg,
+ send_iovar_datasize);
+ if (err) {
+ int getint_error = 0;
+ getint_error = wlu_iovar_getint(wl, "bcmerror", &bcmerr);
+ if ((!getint_error) && (bcmerr == BCME_UNSUPPORTED)) {
+ uchar bitvec[WL_EVENTING_MASK_LEN];
+ printf("old firmware support only 128 events"
+ "setting only the first 128 events\n");
+ memset(bitvec, '\0', WL_EVENTING_MASK_LEN);
+ if (!(err = hexstrtobitvec(argv[1], bitvec,
+ WL_EVENTING_MASK_LEN)))
+ err = wlu_var_setbuf(wl, "event_msgs",
+ bitvec, WL_EVENTING_MASK_LEN);
+ }
+ }
+ }
+ else {
+ fprintf(stderr, "Invalid mask %d\n", eventmask_msg->len);
+ }
+ }
+ /* get */
+ else {
+ void *ptr;
+ char *mask;
+ int i;
+ bool skipzeros;
+ eventmsgs_ext_t *eventmask_msg_in;
+
+ skipzeros = TRUE;
+ /* input structure have no mask */
+ eventmask_msg = (eventmsgs_ext_t*)malloc(EVENTMSGS_EXT_STRUCT_SIZE);
+ if (eventmask_msg == NULL) {
+ return BCME_NOMEM;
+ }
+ memset((void*)eventmask_msg, 0, EVENTMSGS_EXT_STRUCT_SIZE);
+ /* command only used for set */
+ eventmask_msg->command = EVENTMSGS_NONE;
+ /* max read mask size is WL_EVENTING_MASK_MAX_LEN */
+ eventmask_msg->len = WL_EVENTING_MASK_MAX_LEN;
+ eventmask_msg->ver = EVENTMSGS_VER;
+ memset(buf, '\0', WL_EVENTINT_MAX_GET_SIZE);
+ if (!(err = wlu_var_getbuf_sm(wl, cmd->name, (void*)eventmask_msg,
+ EVENTMSGS_EXT_STRUCT_SIZE, &ptr))) {
+ eventmask_msg_in = (eventmsgs_ext_t*)ptr;
+ mask = (char *)eventmask_msg_in->mask;
+ masksize = eventmask_msg_in->len;
+ }
+ if (err) {
+ int getint_error = 0;
+ getint_error = wlu_iovar_getint(wl, "bcmerror", &bcmerr);
+ if ((!getint_error) && (bcmerr == BCME_UNSUPPORTED)) {
+ printf("old firmware support only 128 events"
+ "getting only the first 128 events\n");
+ if (!(err = wlu_var_getbuf_sm(wl, "event_msgs", NULL, 0, &ptr))) {
+ mask = (char *)ptr;
+ masksize = WL_EVENTING_MASK_LEN;
+ }
+ }
+ }
+ if (!err) {
+ printf("0x");
+ for (i = masksize - 1; i >= 0; i--) {
+ if (mask[i] || (i == 0))
+ skipzeros = FALSE;
+ if (skipzeros)
+ continue;
+ printf("%02x", mask[i] & 0xff);
+ }
+ printf("\n");
+ }
+ }
+ free(eventmask_msg);
+ return (err);
+}
+
+static int
+wl_eventbitvec(void *wl, cmd_t *cmd, char **argv)
+{
+ char *vbuf;
+ int err;
+ uchar bitvec[WL_EVENTING_MASK_LEN];
+ bool skipzeros;
+ int i;
+
+ err = 0;
+ skipzeros = TRUE;
+
+ /* set */
+ if (argv[1]) {
+ memset(bitvec, '\0', sizeof(bitvec));
+ if (!(err = hexstrtobitvec(argv[1], bitvec, sizeof(bitvec))))
+ err = wlu_var_setbuf(wl, cmd->name, bitvec, sizeof(bitvec));
+ else
+ return BCME_BADARG;
+ }
+ /* get */
+ else {
+ void *ptr;
+
+ memset(buf, '\0', WLC_IOCTL_MAXLEN);
+ if (!(err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr))) {
+ vbuf = (char *)ptr;
+ printf("0x");
+ for (i = (sizeof(bitvec) - 1); i >= 0; i--) {
+ if (vbuf[i] || (i == 0))
+ skipzeros = FALSE;
+ if (skipzeros)
+ continue;
+ printf("%02x", vbuf[i] & 0xff);
+ }
+ printf("\n");
+ }
+ }
+
+ return (err);
+}
+
+static int
+wl_auto_channel_sel(void *wl, cmd_t *cmd, char **argv)
+{
+ /*
+ * The following condition(s) must be met when Auto Channel Selection
+ * is enabled.
+ * - the I/F is up (change radio channel requires it is up?)
+ * - the AP must not be associated (setting SSID to empty should
+ * make sure it for us)
+ */
+ int chosen = 0;
+ wl_uint32_list_t request;
+ int ret = 0;
+
+ if (!*++argv) {
+ ret = wlu_get(wl, cmd->get, &chosen, sizeof(chosen));
+ chosen = wl_chspec32_from_driver(chosen);
+ if (ret >= 0 && chosen != 0) {
+ wf_chspec_ntoa((chanspec_t)chosen, buf);
+ printf("%s (0x%x)\n", buf, chosen);
+ return 0;
+ }
+ else {
+ if (chosen == 0)
+ printf("invalid chanspec (0x%x)\n", chosen);
+ }
+ } else {
+ if (atoi(*argv) == 1) {
+ request.count = htod32(0);
+ ret = wlu_set(wl, cmd->set, &request, sizeof(request));
+ } else if (atoi(*argv) == 2) {
+ ret = wlu_get(wl, cmd->get, &chosen, sizeof(chosen));
+ if (ret >= 0 && chosen != 0)
+ ret = wlu_iovar_setint(wl, "chanspec", (int)chosen);
+ } else {
+ ret = BCME_BADARG;
+ }
+ }
+ return ret;
+}
+
+static int
+wl_varstr(void *wl, cmd_t *cmd, char **argv)
+{
+ int error;
+ char *str;
+
+ if (!*++argv) {
+ void *ptr;
+
+ if ((error = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return (error);
+
+ str = (char *)ptr;
+ printf("%s\n", str);
+ return (0);
+ } else {
+ str = *argv;
+ /* str length include NULL */
+ return wlu_var_setbuf(wl, cmd->name, str, (strlen(str)+1));
+ }
+}
+
+/* Return TRUE if it's one of the wc cmds. If WC_TOOL is not defined,
+ * it'll return TRUE by default so all the commands are allowed.
+ */
+bool wc_cmd_check(const char *cmd_name)
+{
+ uint j;
+ if (wc_cmds == NULL)
+ return TRUE;
+
+ for (j = 0; j < ARRAYSIZE(wc_cmds); j++)
+ if (strcmp(wc_cmds[j], cmd_name) == 0)
+ return TRUE;
+ return FALSE;
+}
+
+
+/* get/set max bandwidth for each access category in ap */
+static int
+wme_maxbw_params(void *wl, cmd_t *cmd, char **argv)
+{
+ wme_max_bandwidth_t cur_params, new_params;
+ char *val_p, *ac_str, *param;
+ int buflen;
+ int aci;
+ int err;
+ int val;
+ int ap_mode = 0;
+
+ argv++;
+
+ if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))) < 0)
+ return err;
+
+ if (!ap_mode) {
+ printf("%s: AP only\n", cmd->name);
+ return -1;
+ }
+
+ buflen = WLC_IOCTL_MAXLEN;
+
+ /* get the current max bandwidth, using buf as an input buffer. */
+ strcpy(buf, "wme_maxbw_params");
+ if ((err = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen)) < 0) {
+ return err;
+ }
+
+ /* cache the current values */
+ memcpy(&cur_params, buf, sizeof(wme_max_bandwidth_t));
+
+ if ((ac_str = *argv) == NULL) {
+ printf("WME bandwidth limit: \n");
+ for (aci = 0; aci < AC_COUNT; aci++) {
+ printf("%s: bandwidth limit %d\n", ac_names[aci],
+ cur_params.ac[aci]);
+ }
+ } else {
+ /* preload new values with current values */
+ memcpy(&new_params, &cur_params, sizeof(new_params));
+ while ((param = *argv++) != NULL) {
+ if ((val_p = *argv++) == NULL) {
+ printf("Need value following %s\n", param);
+ return BCME_USAGE_ERROR;
+ }
+
+ val = (int)strtoul(val_p, NULL, 0);
+
+ if (!strcmp(param, "be")) {
+ new_params.ac[AC_BE] = (uint32)val;
+ } else if (!strcmp(param, "bk")) {
+ new_params.ac[AC_BK] = (uint32)val;
+ } else if (!strcmp(param, "vi")) {
+ new_params.ac[AC_VI] = (uint32)val;
+ } else if (!strcmp(param, "vo")) {
+ new_params.ac[AC_VO] = (uint32)val;
+ } else {
+ printf("Unknown access category: %s\n", param);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ strcpy(buf, "wme_maxbw_params");
+ memcpy(buf + strlen(buf) + 1, &new_params, sizeof(wme_max_bandwidth_t));
+ err = wlu_set(wl, WLC_SET_VAR, &buf[0], buflen);
+
+ }
+
+ return err;
+}
+
+static int
+wl_antsel(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *ant_sel = "fixed";
+ char *val_name;
+ wlc_antselcfg_t val = {{0}, 0};
+ int err, argc, i;
+ char *endptr = NULL;
+ uint32 txchain_bitmap = 0;
+ uint16 antsel_mask = 0;
+
+ /* toss the command name */
+ val_name = *argv++;
+
+ if (!*argv) {
+ if (cmd->get < 0)
+ return -1;
+ if ((err = wlu_iovar_get(wl, "txchain", &txchain_bitmap, sizeof(txchain_bitmap))) < 0)
+ return err;
+
+ /* iterate over max 4 chains */
+ for (i = 0; i < 4; i ++) {
+ if (!(txchain_bitmap & (1<<i)))
+ antsel_mask |= (0xF << i * 4);
+ }
+
+ if ((err = wlu_iovar_get(wl, val_name, &val, sizeof(wlc_antselcfg_t))) < 0)
+ return err;
+
+ printf("C3C2C1C0: ");
+ for (i = ANT_SELCFG_TX_UNICAST; i < ANT_SELCFG_MAX; i++) {
+ if (val.ant_config[i] & ANT_SELCFG_AUTO)
+ ant_sel = "auto";
+ printf("0x%04X %s ",
+ antsel_mask | (val.ant_config[i] & ANT_SELCFG_MASK), ant_sel);
+ }
+ printf("\n");
+ } else {
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+
+ if ((argc >= 2 && argc <= 3) || argc > ANT_SELCFG_MAX) {
+ printf("invalid %d args\n", argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ val.ant_config[ANT_SELCFG_TX_UNICAST] = (uint8)strtol(*argv++, &endptr, 0);
+ printf("UTX 0x%02x\n", val.ant_config[ANT_SELCFG_TX_UNICAST]);
+ if (*endptr != '\0') {
+ printf("Invaild UTX parameter: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ if (argc == 1) {
+ val.ant_config[ANT_SELCFG_RX_UNICAST] =
+ val.ant_config[ANT_SELCFG_TX_UNICAST];
+ val.ant_config[ANT_SELCFG_TX_DEF] = val.ant_config[ANT_SELCFG_TX_UNICAST];
+ val.ant_config[ANT_SELCFG_RX_DEF] = val.ant_config[ANT_SELCFG_TX_UNICAST];
+ } else {
+ val.ant_config[ANT_SELCFG_RX_UNICAST] = (uint8)strtol(*argv++, &endptr, 0);
+ printf("URX 0x%02x\n", val.ant_config[ANT_SELCFG_RX_UNICAST]);
+ if (*endptr != '\0') {
+ printf("Invaild URX parameter: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ val.ant_config[ANT_SELCFG_TX_DEF] = (uint8)strtol(*argv++, &endptr, 0);
+ printf("DTX 0x%02x\n", val.ant_config[ANT_SELCFG_TX_DEF]);
+ if (*endptr != '\0') {
+ printf("Invaild DTX parameter: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ val.ant_config[ANT_SELCFG_RX_DEF] = (uint8)strtol(*argv++, &endptr, 0);
+ printf("DRX 0x%02x\n", val.ant_config[ANT_SELCFG_RX_DEF]);
+ if (*endptr != '\0') {
+ printf("Invaild DRX parameter: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ }
+ err = wlu_iovar_set(wl, val_name, &val, sizeof(wlc_antselcfg_t));
+ }
+ return err;
+}
+
+
+static int
+wl_txfifo_sz(void *wl, cmd_t *cmd, char **argv)
+{
+ char *param;
+ const char *cmdname = "txfifo_sz";
+ wl_txfifo_sz_t ts, *reply;
+ uint fifo;
+ int err;
+ void *ptr = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+
+ fifo = atoi(param);
+ if (fifo > NFIFO)
+ return BCME_USAGE_ERROR;
+ ts.fifo = fifo;
+ ts.magic = WL_TXFIFO_SZ_MAGIC;
+
+ if ((param = *++argv)) {
+ ts.size = atoi(param);
+ err = wlu_var_setbuf(wl, cmdname, &ts, sizeof(ts));
+ } else {
+ if ((err = wlu_var_getbuf_sm(wl, cmdname, &ts, sizeof(ts), &ptr) < 0))
+ return err;
+ reply = (wl_txfifo_sz_t *)ptr;
+ printf("fifo %d size %d\n", fifo, reply->size);
+ }
+ return err;
+}
+
+#ifdef linux
+
+static int
+wl_escan_event_check(void *wl, cmd_t *cmd, char **argv)
+{
+ int fd, err, i, octets;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ char ifnames[IFNAMSIZ] = {"eth1"};
+ uint8 print_flag = 4;
+ bcm_event_t * event;
+ uint32 status;
+ char* data;
+ int event_type;
+ uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* event bit mask */
+
+ wl_escan_result_t* escan_data;
+
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) {
+ if (strlen(*argv) >= IFNAMSIZ) {
+ printf("Interface name %s too long\n", *argv);
+ return -1;
+ }
+ strncpy(ifnames, *argv, (IFNAMSIZ - 1));
+ if (*++argv)
+ print_flag = atoi(*argv);
+ } else {
+ strncpy(ifnames, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
+
+ memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN);
+
+ if ((err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
+ return (err);
+ event_inds_mask[WLC_E_ESCAN_RESULT / 8] |= 1 << (WLC_E_ESCAN_RESULT % 8);
+ if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
+ return (err);
+
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
+ if (fd < 0) {
+ printf("Cannot create socket %d\n", fd);
+ return -1;
+ }
+
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ printf("Cannot get index %d\n", err);
+ close(fd);
+ return -1;
+ }
+
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ printf("Cannot bind %d\n", err);
+ close(fd);
+ return -1;
+ }
+
+ data = (char*)malloc(ESCAN_EVENTS_BUFFER_SIZE);
+
+ if (data == NULL) {
+ printf("Cannot not allocate %d bytes for events receive buffer\n",
+ ESCAN_EVENTS_BUFFER_SIZE);
+ close(fd);
+ return BCME_NOMEM;
+ }
+
+ while (1) {
+ octets = recv(fd, data, ESCAN_EVENTS_BUFFER_SIZE, 0);
+ event = (bcm_event_t *)data;
+
+ event_type = ntoh32(event->event.event_type);
+
+ if ((event_type == WLC_E_ESCAN_RESULT) && (octets > 0)) {
+ escan_data = (wl_escan_result_t*)&data[sizeof(bcm_event_t)];
+ status = ntoh32(event->event.status);
+
+ if (print_flag & 1)
+ printf("WLC_E_ESCAN_RESULT, (sync_id,status) = (%d,%d)\n",
+ escan_data->sync_id, status);
+
+ if (print_flag & 2)
+ for (i = 0; i < escan_data->bss_count; i++)
+ dump_bss_info(&escan_data->bss_info[i]);
+
+ if (print_flag & 4) {
+ if (status == WLC_E_STATUS_PARTIAL) {
+ printf("sync_id: %d, WLC_E_STATUS_PARTIAL\n",
+ escan_data->sync_id);
+ for (i = 0; i < escan_data->bss_count; i++)
+ dump_bss_info(&escan_data->bss_info[i]);
+ }
+ if (status == WLC_E_STATUS_SUCCESS)
+ printf("sync_id: %d, WLC_E_STATUS_SUCCESS => SCAN_DONE\n",
+ escan_data->sync_id);
+ if ((status != WLC_E_STATUS_SUCCESS) &&
+ (status != WLC_E_STATUS_PARTIAL))
+ printf("sync_id: %d, status:%d, misc. error/abort\n",
+ escan_data->sync_id, status);
+ }
+
+ if (print_flag & 8) {
+ int remainder = escan_data->bss_info[0].ie_length;
+ int processed = sizeof(wl_escan_result_t);
+ uint8* iebuf = &((uint8*)escan_data)[sizeof(wl_escan_result_t)];
+
+ if (status != WLC_E_STATUS_PARTIAL)
+ continue;
+
+ printf("MOREINFO: (sync_id,buflen,ielen) = (%d,%d,%d)\n",
+ escan_data->sync_id,
+ escan_data->buflen,
+ escan_data->bss_info[0].ie_length);
+
+ /* do a tlv sanity check */
+ while (remainder > 0) {
+ processed += 1 + 1 + iebuf[1];
+ remainder -= 1 + 1 + iebuf[1];
+ iebuf += 1 + 1 + iebuf[1];
+ }
+ if (processed >= ESCAN_EVENTS_BUFFER_SIZE)
+ break;
+
+ if (remainder != 0) {
+ printf("ERROR: IE tlv sanity check failed for "
+ "(ssid,sync_id,buflen,ielen,remainder) = "
+ "(%s,%d,%d,%d,%d)\n",
+ escan_data->bss_info[0].SSID,
+ escan_data->sync_id, escan_data->buflen,
+ escan_data->bss_info[0].ie_length,
+ remainder);
+ iebuf = &((uint8*)escan_data)[sizeof(wl_escan_result_t)];
+ if ((escan_data->buflen - sizeof(wl_escan_result_t)) > 0) {
+ for (i = 0;
+ i < (int)(escan_data->buflen -
+ sizeof(wl_escan_result_t));
+ i++) {
+ printf("%02x ", iebuf[i]);
+ }
+ printf("\n");
+ }
+ }
+ }
+ }
+ }
+
+ /* if we ever reach here */
+ free(data);
+ close(fd);
+
+ return (0);
+}
+
+static int
+wl_escanresults(void *wl, cmd_t *cmd, char **argv)
+{
+ int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)) +
+ (WL_NUMCHANNELS * sizeof(uint16));
+ wl_escan_params_t *params;
+ int fd, err, octets;
+ int err2 = BCME_OK;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ bcm_event_t *event;
+ uint32 status;
+ char *data;
+ int event_type;
+ uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* event bit mask */
+ bool revert_event_bit = FALSE;
+ wl_escan_result_t *escan_data;
+ struct escan_bss *escan_bss_head = NULL;
+ struct escan_bss *escan_bss_tail = NULL;
+ struct escan_bss *result;
+
+ fd_set rfds;
+ struct timeval tv;
+ int retval;
+
+ params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
+ params = (wl_escan_params_t*)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
+ return BCME_NOMEM;
+ }
+ memset(params, 0, params_size);
+
+ err = wl_scan_prep(wl, cmd, argv, ¶ms->params, ¶ms_size);
+ if (err)
+ goto exit2;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
+
+ memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN);
+
+ /* Read the event mask from driver and unmask the event WLC_E_ESCAN_RESULT */
+ if ((err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
+ goto exit2;
+
+ if (isclr(event_inds_mask, WLC_E_ESCAN_RESULT)) {
+ setbit(event_inds_mask, WLC_E_ESCAN_RESULT);
+ if ((err = wlu_iovar_set(wl, "event_msgs",
+ &event_inds_mask, WL_EVENTING_MASK_LEN)))
+ goto exit2;
+ revert_event_bit = TRUE;
+ }
+
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
+ if (fd < 0) {
+ printf("Cannot create socket %d\n", fd);
+ err = -1;
+ goto exit2;
+ }
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ printf("Cannot get index %d\n", err);
+ goto exit2fd;
+ }
+
+ /* bind the socket first before starting escan so we won't miss any event */
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ printf("Cannot bind %d\n", err);
+ goto exit2fd;
+ }
+
+ params->version = htod32(ESCAN_REQ_VERSION);
+ params->action = htod16(WL_SCAN_ACTION_START);
+
+ srand((unsigned)time(NULL));
+ params->sync_id = htod16(rand() & 0xffff);
+
+ params_size += OFFSETOF(wl_escan_params_t, params);
+ err = wlu_iovar_setbuf(wl, "escan", params, params_size, buf, WLC_IOCTL_MAXLEN);
+ if (err != 0)
+ goto exit2fd;
+
+ data = (char*)malloc(ESCAN_EVENTS_BUFFER_SIZE);
+
+ if (data == NULL) {
+ printf("Cannot not allocate %d bytes for events receive buffer\n",
+ ESCAN_EVENTS_BUFFER_SIZE);
+ err = BCME_NOMEM;
+ goto exit2fd;
+ }
+
+ /* Set scan timeout */
+ tv.tv_sec = WL_EVENT_TIMEOUT;
+ tv.tv_usec = 0;
+
+ /* receive scan result */
+ while ((retval = select(fd+1, &rfds, NULL, NULL, &tv)) > 0) {
+ octets = recv(fd, data, ESCAN_EVENTS_BUFFER_SIZE, 0);
+ event = (bcm_event_t *)data;
+ event_type = ntoh32(event->event.event_type);
+
+ if ((event_type == WLC_E_ESCAN_RESULT) && (octets > 0)) {
+ escan_data = (wl_escan_result_t*)&data[sizeof(bcm_event_t)];
+ status = ntoh32(event->event.status);
+
+ if (status == WLC_E_STATUS_PARTIAL) {
+ wl_bss_info_t *bi = &escan_data->bss_info[0];
+ wl_bss_info_t *bss;
+
+ /* check if we've received info of same BSSID */
+ for (result = escan_bss_head; result; result = result->next) {
+ bss = result->bss;
+
+ if (wlu_bcmp(bi->BSSID.octet, bss->BSSID.octet,
+ ETHER_ADDR_LEN) ||
+ CHSPEC_BAND(bi->chanspec) !=
+ CHSPEC_BAND(bss->chanspec) ||
+ bi->SSID_len != bss->SSID_len ||
+ wlu_bcmp(bi->SSID, bss->SSID, bi->SSID_len))
+ continue;
+
+ /* We've already got this BSS. Update RSSI if necessary */
+ /* Prefer valid RSSI */
+ if (bi->RSSI == WLC_RSSI_INVALID)
+ break;
+ else if (bss->RSSI == WLC_RSSI_INVALID)
+ goto escan_update;
+
+ /* Prefer on-channel RSSI */
+ if (!(bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) &&
+ (bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL))
+ break;
+ else if ((bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) &&
+ !(bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL))
+ goto escan_update;
+
+ /* Prefer probe response RSSI */
+ if ((bi->flags & WL_BSS_FLAGS_FROM_BEACON) &&
+ !(bss->flags & WL_BSS_FLAGS_FROM_BEACON))
+ break;
+ else if (!(bi->flags & WL_BSS_FLAGS_FROM_BEACON) &&
+ (bss->flags & WL_BSS_FLAGS_FROM_BEACON))
+ goto escan_update;
+
+ /* Prefer better RSSI */
+ if (bi->RSSI <= bss->RSSI)
+ break;
+
+escan_update: /* Update known entry */
+ bss->RSSI = bi->RSSI;
+ bss->SNR = bi->SNR;
+ bss->phy_noise = bi->phy_noise;
+ bss->flags = bi->flags;
+ break;
+ }
+
+ if (!result) {
+ /* New BSS. Allocate memory and save it */
+ struct escan_bss *ebss = malloc(
+ OFFSETOF(struct escan_bss, bss) + bi->length);
+
+ if (!ebss) {
+ perror("can't allocate memory for bss");
+ goto exit1;
+ }
+
+ ebss->next = NULL;
+ memcpy(&ebss->bss, bi, bi->length);
+ if (escan_bss_tail) {
+ escan_bss_tail->next = ebss;
+ }
+ else {
+ escan_bss_head = ebss;
+ }
+ escan_bss_tail = ebss;
+ }
+ }
+ else if (status == WLC_E_STATUS_SUCCESS) {
+ /* Escan finished. Let's go dump the results. */
+ break;
+ }
+ else {
+ printf("sync_id: %d, status:%d, misc. error/abort\n",
+ escan_data->sync_id, status);
+ goto exit1;
+ }
+ }
+ }
+
+ if (retval > 0) {
+ /* print scan results */
+ for (result = escan_bss_head; result; result = result->next) {
+ dump_bss_info(result->bss);
+ }
+ } else if (retval == 0) {
+ printf(" Scan timeout! \n");
+ } else {
+ printf(" Receive scan results failed!\n");
+ }
+
+exit1:
+ /* free scan results */
+ result = escan_bss_head;
+ while (result) {
+ struct escan_bss *tmp = result->next;
+ free(result);
+ result = tmp;
+ }
+
+ free(data);
+exit2fd:
+ close(fd);
+exit2:
+ free(params);
+
+ /* Revert the event bit if appropriate */
+ if (revert_event_bit &&
+ !(err2 = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
+ clrbit(event_inds_mask, WLC_E_ESCAN_RESULT);
+ err2 = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN);
+ }
+
+ if (err2) {
+ fprintf(stderr, "Failed to revert event mask, error %d\n", err2);
+ }
+ return err ? err : err2;
+}
+
+/*
+* Description:
+* Primary job of this routine is to open a socket and listening
+* on this socket for BRCM events and display it on console
+*/
+
+#define WL_EVENTS_BUFFER_SIZE 2048
+static int
+wl_event_check(void *wl, cmd_t *cmd, char **argv)
+{
+ int fd, err, octets;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ char ifnames[IFNAMSIZ] = {"eth1"};
+ bcm_event_t * event;
+ uint32 status;
+ char* data;
+ uint event_type;
+ char time_str[TIME_STR_SZ];
+ struct tm ts;
+ struct timespec tspec;
+ uint policy;
+ pid_t pid;
+ struct sched_param sp;
+ uint max;
+ uint ret;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) {
+ if (strlen(*argv) >= IFNAMSIZ) {
+ printf("Interface name %s too long\n", *argv);
+ return -1;
+ }
+ strncpy(ifnames, *argv, (IFNAMSIZ - 1));
+ } else if (wl) {
+ strncpy(ifnames, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
+
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
+ if (fd < 0) {
+ printf("Cannot create socket %d\n", fd);
+ return -1;
+ }
+
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ printf("Cannot get index %d\n", err);
+ close(fd);
+ return -1;
+ }
+
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ printf("Cannot bind %d\n", err);
+ close(fd);
+ return -1;
+ }
+
+ data = (char*)malloc(WL_EVENTS_BUFFER_SIZE);
+
+ if (data == NULL) {
+ printf("Cannot not allocate %d bytes for events receive buffer\n",
+ ESCAN_EVENTS_BUFFER_SIZE);
+ close(fd);
+ return BCME_NOMEM;
+ }
+ /* make this process as rtprocess with highest priority */
+
+ /* get our scheduling policy */
+ pid = getpid();
+ policy = sched_getscheduler(pid);
+ switch (policy) {
+ case SCHED_OTHER:
+ {
+ max = sched_get_priority_max(SCHED_RR);
+ sp.sched_priority = max;
+ /* set the process scheduling also to RR */
+ sched_setscheduler(pid, SCHED_RR, &sp);
+ break;
+ }
+ case SCHED_RR:
+ {
+ max = sched_get_priority_max(SCHED_RR);
+ sp.sched_priority = max;
+ /* set the priority to max */
+ sched_setparam(pid, &sp);
+ break;
+ }
+ case SCHED_FIFO:
+ {
+ max = sched_get_priority_max(SCHED_RR);
+ sp.sched_priority = max;
+ sched_setscheduler(pid, SCHED_RR, &sp);
+ break;
+ }
+ case -1:
+ perror("sched_getscheduler fail!!");
+ break;
+ default:
+ printf("Unknown policy:%u!!Will not change policy to max!!\n", policy);
+ break;
+ }
+
+ while (1) {
+ octets = recv(fd, data, WL_EVENTS_BUFFER_SIZE, 0);
+ UNUSED_PARAMETER(octets);
+ event = (bcm_event_t *)data;
+ event_type = ntoh32(event->event.event_type);
+ /* get the RTC time in sec/usec */
+ ret = clock_gettime(CLOCK_REALTIME, &tspec);
+ if (ret) {
+ printf("clock_gettime error:%d\n", ret);
+ free(data);
+ close(fd);
+ return -1;
+ }
+ /* convert it in year-month-day-hour-min-sec */
+ ts = *localtime(&tspec.tv_sec);
+ strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &ts);
+ /* print first line of events */
+ printf("%s:%09d %-8.16s %d:%s:", time_str, (uint)tspec.tv_nsec, ifnames,
+ event_type, wlu_lookup_name(wlc_event_names,
+ event_type));
+
+ /* event subtype interpretation */
+ switch (event_type)
+ {
+ case WLC_E_SET_SSID:
+ {
+ status = ntoh32(event->event.status);
+ if (status == WLC_E_STATUS_SUCCESS) {
+ uint32 ssid_len = ntoh32(event->event.datalen);
+ char ssid[SSID_FMT_BUF_LEN];
+ wl_format_ssid(ssid, (uint8*)(data+sizeof(bcm_event_t)),
+ ssid_len);
+ printf("SSID->\"%s\"", ssid);
+ }
+ else {
+ printf("SET_SSID_FAIL:%d", status);
+ }
+ break;
+ }
+
+ case WLC_E_JOIN:
+ {
+ status = ntoh32(event->event.status);
+ if (status == WLC_E_STATUS_SUCCESS) {
+ printf("JOIN_SUCCESS:");
+ printf("%02X:%02X:%02X:%02X:%02X:%02X",
+ event->event.addr.octet[0], event->event.addr.octet[1],
+ event->event.addr.octet[2], event->event.addr.octet[3],
+ event->event.addr.octet[4], event->event.addr.octet[5]);
+ }
+ else {
+ printf("JOIN_FAIL:%d", status);
+ }
+ break;
+ }
+ case WLC_E_AUTH:
+ {
+ status = ntoh32(event->event.status);
+ uint32 reason = ntoh32(event->event.reason);
+ if (status == WLC_E_STATUS_SUCCESS) {
+ printf("AUTH_REQ_SUCCESS:%d", reason);
+ }
+ else {
+ printf("AUTH_FAIL:%d", status);
+ }
+ break;
+ }
+ case WLC_E_AUTH_IND:
+ {
+ status = ntoh32(event->event.status);
+ uint32 reason = ntoh32(event->event.reason);
+ if (status == WLC_E_STATUS_SUCCESS) {
+ printf("AUTH_IND:%d", reason);
+ }
+ else {
+ printf("AUTH_IND_FAIL:%d", status);
+ }
+ break;
+ }
+ case WLC_E_DEAUTH:
+ {
+ status = ntoh32(event->event.status);
+ uint32 reason = ntoh32(event->event.reason);
+ if (status == WLC_E_STATUS_SUCCESS) {
+ printf("DEAUTH_REQ:%d", reason);
+ }
+ else {
+ printf("DEAUTH_REQ_FAIL:%d", status);
+ }
+ break;
+ }
+ case WLC_E_DEAUTH_IND:
+ {
+ status = ntoh32(event->event.status);
+ uint32 reason = ntoh32(event->event.reason);
+ if (status == WLC_E_STATUS_SUCCESS) {
+ printf("DEAUTH_IND:%d", reason);
+ }
+ else {
+ printf("DEAUTH_IND:%d", status);
+ }
+ break;
+ }
+ case WLC_E_ASSOC:
+ {
+ status = ntoh32(event->event.status);
+ if (status == WLC_E_STATUS_SUCCESS) {
+ printf("ASSOCRESP_SUCCESS");
+ }
+ else {
+ printf("ASSOCRESP_FAIL:%d", status);
+ }
+ break;
+ }
+ case WLC_E_DISASSOC:
+ {
+ status = ntoh32(event->event.status);
+ uint32 reason = ntoh32(event->event.reason);
+ if (status == WLC_E_STATUS_SUCCESS) {
+ printf("DISASSOC_REQ:%d", reason);
+ }
+ else {
+ printf("DISASSOC_REQ_FAIL:%d", status);
+ }
+ break;
+ }
+ case WLC_E_DISASSOC_IND:
+ {
+ status = ntoh32(event->event.status);
+ uint32 reason = ntoh32(event->event.reason);
+ if (status == WLC_E_STATUS_SUCCESS) {
+ printf("DISASSOC_IND:%d", reason);
+ }
+ else {
+ printf("DISASSOC_IND_FAIL:%d", status);
+ }
+ break;
+ }
+ case WLC_E_SCAN_COMPLETE:
+ {
+ status = ntoh32(event->event.status);
+ if (status == WLC_E_STATUS_SUCCESS) {
+ printf("SCAN_SUCCESS");
+ }
+ else {
+ printf("SCAN_FAIL:%d", status);
+ }
+ break;
+ }
+ case WLC_E_LINK:
+ {
+ uint16 flag = ntoh16(event->event.flags);
+ if (flag) {
+ printf("LINK_UP");
+ }
+ else {
+ printf("LINK_DOWN:%d", ntoh32(event->event.reason));
+ }
+ break;
+ }
+ default:
+ printf(" ");
+ break;
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+
+ /* if we ever reach here */
+ free(data);
+ close(fd);
+ return (0);
+}
+
+#endif /* linux */
+int
+hexstr2hex(char *str)
+{
+ int i, len;
+ char hexstr[3];
+ char *src;
+
+ src = str;
+ len = strlen(str)/2;
+
+ for (i = 0; i < len; i++) {
+ hexstr[0] = src[0];
+ hexstr[1] = src[1];
+ hexstr[2] = '\0';
+ str[i] = strtoul(hexstr, NULL, 16);
+ src += 2;
+ }
+
+ return i;
+}
+
+static int
+wl_hs20_ie(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ int ret;
+ int bsscfg_idx = 0;
+ int consumed = 0;
+ int length;
+ int malloc_size;
+ tlv_t *tlv;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!argv[1]) {
+ fprintf(stderr, "Too few arguments\n");
+ return -1;
+ }
+
+ /* parse a bsscfg_idx option if present */
+ if ((ret = wl_cfg_option(argv + 1, argv[0], &bsscfg_idx, &consumed)) != 0)
+ return ret;
+ if (consumed)
+ argv = argv + consumed;
+
+ length = atoi(argv[1]);
+
+ if (length < 0 || length > 255) {
+ fprintf(stderr, "Invalid length\n");
+ return -1;
+ }
+ else if (length > 0) {
+ if (!argv[2]) {
+ fprintf(stderr,
+ "Data bytes should be specified for non-zero length\n");
+ return -1;
+ }
+ else {
+ /* Ensure each data byte is 2 characters long */
+ if ((int)strlen(argv[2]) != (length * 2)) {
+ fprintf(stderr, "Please specify all the data bytes for this IE\n");
+ return -1;
+ }
+ }
+ }
+
+ malloc_size = OFFSETOF(tlv_t, data) + length;
+ tlv = malloc(malloc_size);
+ if (tlv == 0) {
+ fprintf(stderr, "Error allocating %d bytes for IE params\n", malloc_size);
+ return -1;
+ }
+ tlv->id = DOT11_MNG_VS_ID;
+ tlv->len = length;
+
+ if (length > 0) {
+ if ((err = get_ie_data((uchar *)argv[2], tlv->data, length))) {
+ fprintf(stderr, "Error parsing data arg\n");
+ free(tlv);
+ return err;
+ }
+ }
+
+ if (bsscfg_idx == -1)
+ err = wlu_var_setbuf(wl, "hs20_ie", tlv, malloc_size);
+ else
+ err = wlu_bssiovar_setbuf(wl, "hs20_ie", bsscfg_idx,
+ tlv, malloc_size, buf, WLC_IOCTL_MAXLEN);
+
+ free(tlv);
+ return (err);
+}
+
+static dbg_msg_t toe_cmpnt[] = {
+ {TOE_TX_CSUM_OL, "tx_csum_ol"},
+ {TOE_RX_CSUM_OL, "rx_csum_ol"},
+ {0, NULL}
+};
+
+static dbg_msg_t arpoe_cmpnt[] = {
+ {ARP_OL_AGENT, "agent"},
+ {ARP_OL_SNOOP, "snoop"},
+ {ARP_OL_HOST_AUTO_REPLY, "host_auto_reply"},
+ {ARP_OL_PEER_AUTO_REPLY, "peer_auto_reply"},
+ {0, NULL}
+};
+
+/*
+ * Tcpip Offload Component-wise get/set control.
+ */
+int
+wl_offload_cmpnt(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, i;
+ uint val, last_val = 0, cmpnt_add = 0, cmpnt_del = 0;
+ char *endptr;
+ dbg_msg_t *dbg_msg = NULL;
+ void *ptr = NULL;
+ int cmpnt;
+
+ if (strcmp(cmd->name, "toe_ol") == 0)
+ dbg_msg = toe_cmpnt;
+ else if (strcmp(cmd->name, "arp_ol") == 0)
+ dbg_msg = arpoe_cmpnt;
+ else {
+ printf("Not a valid command\n");
+ return BCME_BADARG;
+ }
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return (ret);
+ cmpnt = dtoh32(*(int *)ptr);
+
+ if (!*++argv) {
+ printf("0x%x ", cmpnt);
+ for (i = 0; (val = dbg_msg[i].value); i++) {
+ if ((cmpnt & val) && (val != last_val))
+ printf(" %s", dbg_msg[i].string);
+ last_val = val;
+ }
+ printf("\n");
+ return (0);
+ }
+
+ while (*argv) {
+ char *s = *argv;
+ if (*s == '+' || *s == '-')
+ s++;
+ else
+ cmpnt_del = ~0; /* make the whole list absolute */
+ val = strtoul(s, &endptr, 0);
+ /* not a plain integer if not all the string was parsed by strtoul */
+ if (*endptr != '\0') {
+ for (i = 0; (val = dbg_msg[i].value); i++)
+ if (stricmp(dbg_msg[i].string, s) == 0)
+ break;
+ if (!val)
+ goto usage;
+ }
+ if (**argv == '-')
+ cmpnt_del |= val;
+ else
+ cmpnt_add |= val;
+ ++argv;
+ }
+
+ cmpnt &= ~cmpnt_del;
+ cmpnt |= cmpnt_add;
+
+ cmpnt = htod32(cmpnt);
+ return (wlu_var_setbuf(wl, cmd->name, &cmpnt, sizeof(int)));
+
+usage:
+ fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");
+ fprintf(stderr, "Use a + or - prefix to make an incremental change.");
+
+ for (i = 0; (val = dbg_msg[i].value); i++) {
+ if (val != last_val)
+ fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string);
+ else
+ fprintf(stderr, ", %s", dbg_msg[i].string);
+ last_val = val;
+ }
+ fprintf(stderr, "\n");
+
+ return 0;
+}
+
+#define MAX_HOST_ICMP_IPV6 4
+
+int
+wl_hostipv6_extended(void *wl, cmd_t *cmd, char **argv)
+{
+
+ int ret;
+ uint16 *ip_addr;
+ wl_icmp_ipv6_cfg_t *cfg;
+
+ if (!*++argv) {
+ /* Get */
+ void *ptr = NULL;
+ uint32 i, k;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ cfg = (wl_icmp_ipv6_cfg_t *)ptr;
+
+ if (cfg->version != WL_ICMP_IPV6_CFG_VERSION) {
+ printf("Version mismatch %d, expected %d\n", cfg->version,
+ WL_ICMP_IPV6_CFG_VERSION);
+ return BCME_VERSION;
+ }
+ /* Check length */
+ if (cfg->length != WL_ICMP_CFG_IPV6_LEN(cfg->num_ipv6)) {
+ printf("Length mismatch %d, calculated length %d\n", cfg->length,
+ (int)WL_ICMP_CFG_IPV6_LEN(cfg->num_ipv6));
+ return BCME_BADARG;
+ }
+ printf("Total %d Host ipv6 addresses\n", cfg->num_ipv6);
+ for (k = 0; k < cfg->num_ipv6; k++) {
+ ip_addr = (uint16*)cfg->host_ipv6[k].addr;
+ /* Print ipv6 Addr */
+ for (i = 0; i < 8; i++) {
+ printf("%x", ntoh16(ip_addr[i]));
+ if (i < 7)
+ printf(":");
+ }
+ printf("\r\n");
+ }
+ } else {
+ int argc, buf_size;
+ struct ipv6_addr ipa_set[MAX_HOST_ICMP_IPV6], null_ipa;
+
+ /* Set */
+ memset(null_ipa.addr, 0, IPV6_ADDR_LEN);
+ for (argc = 0; argc < MAX_HOST_ICMP_IPV6 && argv[argc]; argc++) {
+ if (!wl_atoipv6(argv[argc], &ipa_set[argc]))
+ return BCME_USAGE_ERROR;
+ if (!memcmp(null_ipa.addr, ipa_set->addr, IPV6_ADDR_LEN)) {
+ argc = 0;
+ break;
+ }
+ }
+ buf_size = WL_ICMP_CFG_IPV6_LEN(argc);
+ cfg = (wl_icmp_ipv6_cfg_t *)malloc(buf_size);
+ if (!cfg) {
+ printf("%s: Unable to allocate %d bytes!\n", __FUNCTION__, buf_size);
+ return BCME_NOMEM;
+ }
+ memset(cfg, 0, buf_size);
+ cfg->version = WL_ICMP_IPV6_CFG_VERSION;
+ cfg->fixed_length = WL_ICMP_CFG_IPV6_FIXED_LEN;
+ cfg->length = buf_size;
+ cfg->flags = 0;
+ if (!argc) {
+ cfg->flags |= WL_ICMP_IPV6_CLEAR_ALL;
+ }
+ cfg->num_ipv6 = argc;
+ memcpy(cfg->host_ipv6, ipa_set,
+ cfg->num_ipv6 * sizeof(struct ipv6_addr));
+ ret = wlu_var_setbuf(wl, cmd->name, cfg, buf_size);
+ free(cfg);
+ }
+ return ret;
+}
+
+/*
+ * If a host IP address is given, add it to the host-cache,
+ * e.g. "wl nd_hostip fe00:0:0:0:0:290:1fc0:18c0 ".
+ * If no address is given, dump all the addresses.
+ */
+int
+wl_hostipv6(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, i;
+ struct ipv6_addr ipa_set, *ipa_get, null_ipa;
+ uint16 *ip_addr;
+ if (!*++argv) {
+ /* Get */
+ void *ptr = NULL;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ ip_addr = (uint16*)ptr;
+ memset(null_ipa.addr, 0, IPV6_ADDR_LEN);
+ for (ipa_get = (struct ipv6_addr *)ptr;
+ memcmp(null_ipa.addr, ipa_get->addr, IPV6_ADDR_LEN) != 0;
+ ipa_get++) {
+ /* Print ipv6 Addr */
+ for (i = 0; i < 8; i++) {
+ printf("%x", ntoh16(ip_addr[i]));
+ if (i < 7)
+ printf(":");
+ }
+ printf("\r\n");
+
+ ip_addr += 8;
+ }
+ } else {
+ /* Add */
+ if (!wl_atoipv6(*argv, &ipa_set))
+ return BCME_USAGE_ERROR;
+
+ /* we add one ip-addr at a time */
+ return wlu_var_setbuf(wl, cmd->name, &ipa_set, IPV6_ADDR_LEN);
+ }
+ return ret;
+}
+
+/*
+ * If a host IP address is given, add it to the host-cache, e.g. "wl arp_hostip 192.168.1.1".
+ * If no address is given, dump all the addresses.
+ */
+int
+wl_hostip(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ struct ipv4_addr ipa_set, *ipa_get, null_ipa;
+
+ if (!*++argv) {
+ /* Get */
+ void *ptr = NULL;
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ memset(null_ipa.addr, 0, IPV4_ADDR_LEN);
+
+ for (ipa_get = (struct ipv4_addr *)ptr;
+ memcmp(null_ipa.addr, ipa_get->addr, IPV4_ADDR_LEN) != 0;
+ ipa_get++)
+ printf("%s\n", wl_iptoa(ipa_get));
+
+ printf("Total %d host addresses\n", (int)(ipa_get - (struct ipv4_addr *)ptr));
+ } else {
+ /* Add */
+ if (!wl_atoip(*argv, &ipa_set))
+ return BCME_USAGE_ERROR;
+ /* we add one ip-addr at a time */
+ return wlu_var_setbuf(wl, cmd->name, &ipa_set, sizeof(IPV4_ADDR_LEN));
+ }
+
+ return ret;
+}
+
+static int
+wl_mcast_ar(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ uint argc;
+ wl_rmc_entry_t *reply = NULL;
+ wl_rmc_entry_t rmc_entry;
+ void *ptr = NULL;
+
+ memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t));
+ if (!*++argv) {
+ /* Get and display activer receiver address */
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) {
+ return ret;
+ }
+
+ reply = (wl_rmc_entry_t*)ptr;
+
+ printf("%s\n", wl_ether_etoa(&reply->addr));
+ return 0;
+ }
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* Set activer receiver's mac address */
+ if (argc > 0 && argv[0]) {
+ printf(" %s \n", argv[0]);
+ if (!wl_ether_atoe(argv[0], &rmc_entry.addr)) {
+ if (strlen(argv[0]) == 1 && atoi(argv[0]) == 0) {
+ memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t));
+ } else {
+ printf("Invalid argument, Please enter mac address\n"
+ "or enter \"0\" for auto ar selection\n");
+ return -1;
+ }
+ }
+ } else {
+ printf("Too few arguments\n");
+ return -1;
+ }
+
+ ret = wlu_var_setbuf(wl, cmd->name, &rmc_entry, sizeof(wl_rmc_entry_t));
+
+ return ret;
+}
+
+static void
+wl_rate_histo_print(wl_mac_ratehisto_res_t *rate_histo_res)
+{
+ uint i, nss;
+
+ printf("Rates\n");
+ for (i = 0; i < (DOT11_RATE_MAX + 1); i++) {
+ if (rate_histo_res->rate[i]) {
+ if (DIV_REM(i, 2))
+ printf("%.2d\t%d.%d Mbit/s\n",
+ rate_histo_res->rate[i], DIV_QUO(i, 2), DIV_REM(i, 2)/10);
+ else
+ printf("%.2d\t%d Mbit/s\n",
+ rate_histo_res->rate[i], DIV_QUO(i, 2));
+ }
+ }
+
+ printf("MCS indexes:\n");
+ for (i = 0; i < (WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX); i++) {
+ if (rate_histo_res->mcs[i]) {
+ printf("%d\tMCS %d\n", rate_histo_res->mcs[i], i);
+ }
+ }
+
+ printf("VHT indexes:\n");
+ for (nss = 0; nss < WL_TX_CHAINS_MAX; nss++) {
+ for (i = 0; i < WL_RATESET_SZ_VHT_MCS; i++) {
+ if (rate_histo_res->vht[i][nss]) {
+ printf("%d\tVHT %d Nss %d\n", rate_histo_res->vht[i][nss], i,
+ nss + 1);
+ }
+ }
+ }
+
+ return;
+}
+
+static int
+wl_rate_histo(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr = NULL;
+ int err;
+ wl_mac_ratehisto_res_t *rate_histo_res;
+
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return err;
+
+ rate_histo_res = (wl_mac_ratehisto_res_t *)ptr;
+
+ wl_rate_histo_print(rate_histo_res);
+
+ return 0;
+}
+
+static int
+wl_mac_rate_histo(void *wl, cmd_t *cmd, char **argv)
+{
+ struct ether_addr ea;
+ int buflen, err;
+ wl_mac_ratehisto_cmd_t *rate_histo_cmd;
+ wl_mac_ratehisto_res_t *rate_histo_res;
+
+ if (!*++argv || !wl_ether_atoe(*argv, &ea))
+ return BCME_USAGE_ERROR;
+
+ strcpy(buf, "mac_rate_histo");
+ buflen = strlen(buf) + 1;
+ rate_histo_cmd = (wl_mac_ratehisto_cmd_t *)(buf + buflen);
+ memcpy((char*)&rate_histo_cmd->ea, (char*)&ea, ETHER_ADDR_LEN);
+
+ if (*++argv)
+ {
+ /* The access category is obtained and checked for validity */
+ rate_histo_cmd->ac_cat = (uint8)strtol(*argv, NULL, 0);
+ if (!(rate_histo_cmd->ac_cat == 0x10 || rate_histo_cmd->ac_cat == 0x4)) {
+ printf("Only Access Category 0x10 and 0x4 is supported\n");
+ return BCME_BADARG;
+ }
+
+ if (*++argv) {
+ /* The number of pkts to avg is obtained and checked for valid range */
+ rate_histo_cmd->num_pkts = (uint8)strtol(*argv, NULL, 10);
+ } else {
+ /* Set default value as maximum of all access categories
+ * so that it is set to the max value below
+ */
+ rate_histo_cmd->num_pkts = 64;
+ }
+
+ if (rate_histo_cmd->ac_cat == 0x10 && rate_histo_cmd->num_pkts > 64) {
+ rate_histo_cmd->num_pkts = 64;
+ } else if (rate_histo_cmd->ac_cat == 0x4 && rate_histo_cmd->num_pkts > 32) {
+ rate_histo_cmd->num_pkts = 32;
+ }
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return err;
+
+ rate_histo_res = (wl_mac_ratehisto_res_t *)buf;
+
+ wl_rate_histo_print(rate_histo_res);
+
+ printf("First TSF Timestamp: %08x%08x\n", rate_histo_res->tsf_timer[0][1],
+ rate_histo_res->tsf_timer[0][0]);
+ printf("Last TSF Timestamp : %08x%08x\n", rate_histo_res->tsf_timer[1][1],
+ rate_histo_res->tsf_timer[1][0]);
+
+ return 0;
+}
+
+static int
+wl_sarlimit(void *wl, cmd_t *cmd, char **argv)
+{
+ uint i;
+ int ret;
+ sar_limit_t sar;
+ uint argc;
+ char *endptr;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+ argc--;
+
+ if (argc != 0 && argc != sizeof(sar_limit_t)) {
+ printf("Error: Input %d SAR values, need total %d SAR values\n",
+ argc, (int)sizeof(sar_limit_t));
+ return BCME_USAGE_ERROR;
+ }
+
+ if (argc == 0) {
+ if ((ret = wlu_iovar_get(wl, cmd->name, &sar, sizeof(sar_limit_t))) < 0) {
+ return (ret);
+ }
+ printf("\t2G: %4d %4d %4d %4d\n",
+ sar.band2g[0], sar.band2g[1], sar.band2g[2], sar.band2g[3]);
+ for (i = 0; i < WLC_SUBBAND_MAX; i++) {
+ printf("\t5G[%1d] %4d %4d %4d %4d\n", i,
+ sar.band5g[i][0], sar.band5g[i][1],
+ sar.band5g[i][2], sar.band5g[i][3]);
+ }
+ } else {
+ uint8 *ptr = (uint8 *)&sar;
+ memset(ptr, WLC_TXPWR_MAX, sizeof(sar_limit_t));
+ for (i = 0; i < argc; i++) {
+ ptr[i] = (uint8)(strtol(argv[1 + i], &endptr, 0));
+ if (*endptr != '\0') {
+ printf("error\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ printf("\t2G: %4d %4d %4d %4d\n",
+ sar.band2g[0], sar.band2g[1], sar.band2g[2], sar.band2g[3]);
+ for (i = 0; i < WLC_SUBBAND_MAX; i++) {
+ printf("\t5G[%1d] %4d %4d %4d %4d\n", i,
+ sar.band5g[i][0], sar.band5g[i][1],
+ sar.band5g[i][2], sar.band5g[i][3]);
+ }
+ ret = wlu_iovar_set(wl, cmd->name, &sar, sizeof(sar_limit_t));
+ }
+
+ return ret;
+}
+
+#ifdef SR_DEBUG
+/* Displays PMU related info on screen */
+static int
+wl_dump_pmu(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ pmu_reg_t *pmu_var;
+ int err;
+ uint i;
+ uint32 pmu_chip_ctl_reg;
+ uint32 pmu_chip_reg_reg;
+ uint32 pmu_chip_pll_reg;
+ uint32 pmu_chip_res_reg;
+ UNUSED_PARAMETER(argv);
+ if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr)))
+ return (err);
+ pmu_var = (pmu_reg_t *)ptr;
+ printf("PMU Control : 0x%08x\n", pmu_var->pmu_control);
+ printf("PMU Capabilities : 0x%08x\n", pmu_var->pmu_capabilities);
+ printf("PMU Status : 0x%08x\n", pmu_var->pmu_status);
+ printf("Resource State : 0x%08x\n", pmu_var->res_state);
+ printf("Resurce Pending : 0x%08x\n", pmu_var->res_pending);
+ printf("PMU Timer : 0x%08x\n", pmu_var->pmu_timer1);
+ printf("Minimum Resource Mask: 0x%08x\n", pmu_var->min_res_mask);
+ printf("Maximum Resource Mask: 0x%08x\n", pmu_var->max_res_mask);
+ /* Displays values of the 5 PMU Chip Control Registers */
+ pmu_chip_ctl_reg = (pmu_var->pmu_capabilities & 0xf8000000);
+ pmu_chip_ctl_reg = pmu_chip_ctl_reg >> 27;
+ for (i = 0; i < pmu_chip_ctl_reg; i++) {
+ printf("PMU ChipControl[%d] : 0x%08x\n", i, pmu_var->pmu_chipcontrol1[i]);
+ }
+ /* Displays values of the 6 PMU Reg Control Registers */
+ pmu_chip_reg_reg = (pmu_var->pmu_capabilities & 0x07c00000);
+ pmu_chip_reg_reg = pmu_chip_reg_reg >> 22;
+ for (i = 0; i < pmu_chip_reg_reg; i++) {
+ printf("PMU RegControl[%d] : 0x%08x\n", i, pmu_var->pmu_regcontrol[i]);
+ }
+ /* Displays values of the 6 PMU Pll Control Registers */
+ pmu_chip_pll_reg = (pmu_var->pmu_capabilities & 0x003e0000);
+ pmu_chip_pll_reg = pmu_chip_pll_reg >> 17;
+ for (i = 0; i < pmu_chip_pll_reg; i++) {
+ printf("PMU PllControl[%d] : 0x%08x\n", i, pmu_var->pmu_pllcontrol[i]);
+ }
+ /* Displays values of the 31 PMU Resource Up/Down Timer */
+ pmu_chip_res_reg = (pmu_var->pmu_capabilities & 0x00001f00);
+ pmu_chip_res_reg = pmu_chip_res_reg >> 8;
+ for (i = 0; i < pmu_chip_res_reg; i++) {
+ printf("PMU Resource Up/Down Timer[%d] : 0x%08x\n", i,
+ pmu_var->pmu_rsrc_up_down_timer[i]);
+ }
+ /* Displays values of the 31 PMU Resource Dependancy Mask */
+ pmu_chip_res_reg = (pmu_var->pmu_capabilities & 0x00001f00);
+ pmu_chip_res_reg = pmu_chip_res_reg >> 8;
+ for (i = 0; i < pmu_chip_res_reg; i++) {
+ printf("PMU Resource Dependancy Mask[%d] : 0x%08x\n", i,
+ pmu_var->rsrc_dep_mask[i]);
+ }
+ return 0;
+}
+#endif /* #ifdef SR_DEBUG */
+
+static int
+wl_antgain(void *wl, cmd_t *cmd, char **argv)
+{
+#if defined(DONGLEBUILD)
+ return 0;
+#else
+ int err = 0;
+ uint val;
+ uint8 ag[2];
+ uint8 *rag;
+ void *ptr;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) { /* write maxpower */
+ if (find_pattern(argv, "ag0", &val))
+ ag[0] = val & 0xff;
+ else {
+ printf("Missing ag0\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (find_pattern(argv, "ag1", &val))
+ ag[1] = val & 0xff;
+ else {
+ printf("Missing ag1\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((err = wlu_var_setbuf(wl, "antgain", &ag, 2 * sizeof(uint8)) < 0)) {
+ printf("wl_antgain: fail to set\n");
+ }
+ } else {
+ if ((err = wlu_var_getbuf(wl, "antgain", NULL, 0, &ptr) < 0)) {
+ printf("wl_antgain: fail to get antgain\n");
+ return err;
+ }
+ rag = (uint8*)ptr;
+ printf("ag0=%x\n", rag[0]);
+ printf("ag1=%x\n", rag[1]);
+ }
+
+ return err;
+#endif
+}
+
+/* Convert user's input in hex pattern to byte-size mask */
+int
+wl_pattern_atoh(char *src, char *dst)
+{
+ int i;
+ if (strncmp(src, "0x", 2) != 0 &&
+ strncmp(src, "0X", 2) != 0) {
+ printf("Data invalid format. Needs to start with 0x\n");
+ return -1;
+ }
+ src = src + 2; /* Skip past 0x */
+ if (strlen(src) % 2 != 0) {
+ printf("Data invalid format. Needs to be of even length\n");
+ return -1;
+ }
+ for (i = 0; *src != '\0'; i++) {
+ char num[3];
+ strncpy(num, src, 2);
+ num[2] = '\0';
+ dst[i] = (uint8)strtoul(num, NULL, 16);
+ src += 2;
+ }
+ return i;
+}
+
+
+#define MAX_PWR_STAT_TYPES 32
+
+static int
+wl_pwrstats(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_pwrstats_query_t *p_query;
+ wl_pwrstats_t *p_pwrstats;
+ void *ptr = NULL;
+ int rc = 0;
+ uint i, argc, len, taglen;
+ uint16 type;
+
+ /* Count <type> args and allocate buffer */
+ for (argv++, argc = 0; argv[argc]; argc++)
+ ;
+ if (argc > MAX_PWR_STAT_TYPES) {
+ fprintf(stderr, "Currently limited to %d types in one query\n",
+ MAX_PWR_STAT_TYPES);
+ return -1;
+ }
+
+ len = OFFSETOF(wl_pwrstats_query_t, type) + argc * sizeof(uint16);
+ p_query = (wl_pwrstats_query_t *)malloc(len);
+ if (p_query == NULL) {
+ fprintf(stderr, "malloc failed to allocate %d bytes\n", len);
+ return -1;
+ }
+
+ /* Build a list of types */
+ p_query->length = argc;
+ for (i = 0; i < argc; i++, argv++) {
+ char *endptr;
+ p_query->type[i] = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Type '%s' (arg %d) not a number?\n", *argv, i);
+ free(p_query);
+ return -1;
+ }
+ }
+
+ /* Now issue the get with the query as parameter */
+ rc = wlu_var_getbuf(wl, cmd->name, p_query, len, &ptr);
+ free(p_query);
+ if (rc < 0)
+ return rc;
+
+ p_pwrstats = (wl_pwrstats_t *)ptr;
+
+ if (dtoh16(p_pwrstats->version) != WL_PWRSTATS_VERSION) {
+ printf("Power stats version mismatch\n");
+ return BCME_ERROR;
+ }
+
+ /* Basic information */
+ printf("Version: %d, Length %d bytes\n",
+ dtoh16(p_pwrstats->version), dtoh16(p_pwrstats->length));
+
+ /* Run down tags displaying content */
+ len = dtoh16(p_pwrstats->length) - WL_PWR_STATS_HDRLEN;
+ for (ptr = p_pwrstats->data; len >= 2 * sizeof(uint16); *(uint8**)&ptr += taglen) {
+ /* Grab tag/len words */
+ type = dtoh16(((uint16*)ptr)[0]);
+ taglen = dtoh16(((uint16*)ptr)[1]);
+
+ if ((taglen < 2 * sizeof(uint16)) || (taglen > len)) {
+ fprintf(stderr, "Bad len %d for tag %d, remaining len %d\n",
+ taglen, type, len);
+ rc = BCME_ERROR;
+ break;
+ }
+
+ if (taglen & 0xF000) {
+ fprintf(stderr, "Resrved bits in len %d for tag %d, remaining len %d\n",
+ taglen, type, len);
+ rc = BCME_ERROR;
+ break;
+ }
+
+ /* Tag-specific display */
+ switch (type) {
+ case WL_PWRSTATS_TYPE_PHY:
+ {
+ wl_pwr_phy_stats_t stats;
+
+ if (taglen < sizeof(wl_pwr_phy_stats_t)) {
+ fprintf(stderr, "Short len for %d: %d < %d\n",
+ type, taglen, (int)sizeof(wl_pwr_phy_stats_t));
+ rc = BCME_ERROR;
+ break;
+ }
+
+ memcpy(&stats, ptr, taglen);
+ printf("PHY:\n"
+ " TX Duration: %u\n"
+ " RX Duration: %u\n",
+ dtoh32(stats.tx_dur),
+ dtoh32(stats.rx_dur));
+ }
+ break;
+
+ case WL_PWRSTATS_TYPE_SCAN:
+ {
+ wl_pwr_scan_stats_t stats;
+
+ if (taglen < sizeof(wl_pwr_scan_stats_t)) {
+ fprintf(stderr, "Short len for %d: %d < %d\n",
+ type, taglen, (int)sizeof(wl_pwr_scan_stats_t));
+ rc = BCME_ERROR;
+ break;
+ }
+
+ memcpy(&stats, ptr, taglen);
+ printf("SCAN:\n"
+ " User-Scan:\tCount: %u\tDuration: %u\n"
+ " Assoc-Scan:\tCount: %u\tDuration: %u\n"
+ " Roam-Scan:\tCount: %u\tDuration: %u\n"
+ " PNO-Scan:\tCount: %u\tDuration: %u\n"
+ " Other-Scan:\tCount: %u\tDuration: %u\n",
+ dtoh32(stats.user_scans.count),
+ dtoh32(stats.user_scans.dur),
+ dtoh32(stats.assoc_scans.count),
+ dtoh32(stats.assoc_scans.dur),
+ dtoh32(stats.roam_scans.count),
+ dtoh32(stats.roam_scans.dur),
+ dtoh32(stats.pno_scans[0].count),
+ dtoh32(stats.pno_scans[0].dur),
+ dtoh32(stats.other_scans.count),
+ dtoh32(stats.other_scans.dur));
+ }
+ break;
+
+ case WL_PWRSTATS_TYPE_USB_HSIC:
+ {
+ wl_pwr_usb_hsic_stats_t stats;
+
+ if (taglen < sizeof(wl_pwr_usb_hsic_stats_t)) {
+ fprintf(stderr, "Short len for %d: %d < %d\n",
+ type, taglen, (int)sizeof(wl_pwr_usb_hsic_stats_t));
+ rc = BCME_ERROR;
+ break;
+ }
+
+ memcpy(&stats, ptr, taglen);
+ printf("HSIC:\n"
+ " Suspend count: %u\n"
+ " Resume count: %u\n"
+ " Disconnect count: %u\n"
+ " Reconnect count: %u\n"
+ " Active duration: %u\n"
+ " Suspend duration: %u\n"
+ " Disconnect duration:%u\n",
+ dtoh32(stats.hsic.suspend_ct),
+ dtoh32(stats.hsic.resume_ct),
+ dtoh32(stats.hsic.disconnect_ct),
+ dtoh32(stats.hsic.reconnect_ct),
+ dtoh32(stats.hsic.active_dur),
+ dtoh32(stats.hsic.suspend_dur),
+ dtoh32(stats.hsic.disconnect_dur));
+ }
+ break;
+
+ case WL_PWRSTATS_TYPE_PCIE:
+ {
+ wl_pwr_pcie_stats_t stats;
+
+ if (taglen < sizeof(wl_pwr_pcie_stats_t)) {
+ fprintf(stderr, "Short len for %d: %d < %d\n",
+ type, taglen, (int)sizeof(wl_pwr_pcie_stats_t));
+ rc = BCME_ERROR;
+ break;
+ }
+
+ memcpy(&stats, ptr, taglen);
+ if (dtoh32(stats.pcie.l0_cnt) == 0) {
+ printf("link stats are not supported for this pcie core\n");
+ }
+ printf("PCIE:\n"
+ " D3 Suspend count: %u\n"
+ " D0 Resume count: %u\n"
+ " PERST# assert count: %u\n"
+ " PERST# deassert count: %u\n"
+ " Active duration: %u ms\n"
+ " D3 Suspend duration: %u ms\n"
+ " PERST# duration:%u ms\n"
+ " l0 cnt:%u dur:%u usecs\n"
+ " l1 cnt:%u dur:%u usecs\n"
+ " l1_1 cnt:%u dur:%u usecs\n"
+ " l1_2 cnt:%u dur:%u usecs\n"
+ " l2 cnt:%u dur:%u usecs\n"
+ " LTR_ACTIVE Count %u Duration: %u ms\n"
+ " LTR_SLEEP Count %u Duration: %u ms\n"
+ " DeepSleep Count %u Duration: %u ms\n",
+ dtoh32(stats.pcie.d3_suspend_ct),
+ dtoh32(stats.pcie.d0_resume_ct),
+ dtoh32(stats.pcie.perst_assrt_ct),
+ dtoh32(stats.pcie.perst_deassrt_ct),
+ dtoh32(stats.pcie.active_dur),
+ dtoh32(stats.pcie.d3_suspend_dur),
+ dtoh32(stats.pcie.perst_dur),
+ dtoh32(stats.pcie.l0_cnt),
+ dtoh32(stats.pcie.l0_usecs),
+ dtoh32(stats.pcie.l1_cnt),
+ dtoh32(stats.pcie.l1_usecs),
+ dtoh32(stats.pcie.l1_1_cnt),
+ dtoh32(stats.pcie.l1_1_usecs),
+ dtoh32(stats.pcie.l1_2_cnt),
+ dtoh32(stats.pcie.l1_2_usecs),
+ dtoh32(stats.pcie.l2_cnt),
+ dtoh32(stats.pcie.l2_usecs),
+ dtoh32(stats.pcie.ltr_active_ct),
+ dtoh32(stats.pcie.ltr_active_dur),
+ dtoh32(stats.pcie.ltr_sleep_ct),
+ dtoh32(stats.pcie.ltr_sleep_dur),
+ dtoh32(stats.pcie.deepsleep_count),
+ dtoh32(stats.pcie.deepsleep_dur));
+
+ printf("\nIPC Stats\n");
+ printf(" Submissions:\tCount: %u\th2d drbl: %u\t",
+ dtoh32(stats.pcie.num_submissions),
+ dtoh32(stats.pcie.num_h2d_doorbell));
+ if (stats.pcie.num_h2d_doorbell)
+ printf("Avg per h2d drbl: %d.%d\n",
+ DIV_QUO(dtoh32(stats.pcie.num_submissions),
+ dtoh32(stats.pcie.num_h2d_doorbell)),
+ DIV_REM(dtoh32(stats.pcie.num_submissions),
+ dtoh32(stats.pcie.num_h2d_doorbell)));
+ else
+ printf(" Avg per h2d drbl: 0.0\n");
+
+ printf(" Completions:\tCount: %u\td2h drbl: %u\t",
+ dtoh32(stats.pcie.num_completions),
+ dtoh32(stats.pcie.num_d2h_doorbell));
+ if (stats.pcie.num_d2h_doorbell)
+ printf("Avg per d2h drbl: %d.%d\n",
+ DIV_QUO(dtoh32(stats.pcie.num_completions),
+ dtoh32(stats.pcie.num_d2h_doorbell)),
+ DIV_REM(dtoh32(stats.pcie.num_completions),
+ dtoh32(stats.pcie.num_d2h_doorbell)));
+ else
+ printf("Avg per d2h drbl: 0.0\n");
+
+ printf(" Rx Cmplt:\tCount: %u\trx_cmplt drbl: %u\t",
+ dtoh32(stats.pcie.num_rxcmplt),
+ dtoh32(stats.pcie.num_rxcmplt_drbl));
+ if (stats.pcie.num_rxcmplt_drbl)
+ printf("Avg per rx_cmplt drbl: %d.%d\n",
+ DIV_QUO(dtoh32(stats.pcie.num_rxcmplt),
+ dtoh32(stats.pcie.num_rxcmplt_drbl)),
+ DIV_REM(dtoh32(stats.pcie.num_rxcmplt),
+ dtoh32(stats.pcie.num_rxcmplt_drbl)));
+ else
+ printf("Avg per rx_cmplt drbl: 0.0\n");
+
+ printf(" Tx Cmplt:\tCount: %u\ttx_cmplt drbl: %u\t",
+ dtoh32(stats.pcie.num_txstatus),
+ dtoh32(stats.pcie.num_txstatus_drbl));
+ if (stats.pcie.num_txstatus_drbl)
+ printf("Avg per tx_cmplt drbl: %d.%d\n",
+ DIV_QUO(dtoh32(stats.pcie.num_txstatus),
+ dtoh32(stats.pcie.num_txstatus_drbl)),
+ DIV_REM(dtoh32(stats.pcie.num_txstatus),
+ dtoh32(stats.pcie.num_txstatus_drbl)));
+ else
+ printf("Avg per tx_cmplt drbl: 0.0\n");
+
+ }
+ break;
+
+ case WL_PWRSTATS_TYPE_SDIO:
+ {
+ wl_pwr_sdio_stats_t stats;
+
+ if (taglen < sizeof(wl_pwr_sdio_stats_t)) {
+ fprintf(stderr, "Short len for %d: %d < %d\n",
+ type, taglen, (int)sizeof(wl_pwr_sdio_stats_t));
+ rc = BCME_ERROR;
+ break;
+ }
+
+ memcpy(&stats, ptr, taglen);
+ printf("SDIO:\n"
+ " active duration: %u\n"
+ " wakehost count: %u\n"
+ " intr count: data: %u\tmailbox: %u\terror: %u\n"
+ " ds_wake ON: count: %u\t duration: %u\n"
+ " ds_wake OFF: count: %u\t duration: %u\n"
+ " ds_d0 count: %u\t duration: %u\n"
+ " ds_d3 count: %u\t duration: %u\n"
+ " DEV_WAKE count: ASSRT: %u\tDASST: %u\n"
+ " ds mb rx count: DSACK: %u\tDSNACK: %u\tD3INFORM: %u\n"
+ " ds mb tx count: DSREQ: %u\tDSEXIT: %u\tD3ACK: %u\tD3EXIT: %u\n",
+
+ dtoh32(stats.sdio.active_dur),
+ dtoh32(stats.sdio.wakehost_cnt),
+
+ dtoh32(stats.sdio.data_intr_cnt),
+ dtoh32(stats.sdio.mb_intr_cnt),
+ dtoh32(stats.sdio.error_intr_cnt),
+
+ dtoh32(stats.sdio.ds_wake_on_cnt),
+ dtoh32(stats.sdio.ds_wake_on_dur),
+ dtoh32(stats.sdio.ds_wake_off_cnt),
+ dtoh32(stats.sdio.ds_wake_off_dur),
+
+ dtoh32(stats.sdio.ds_d0_cnt),
+ dtoh32(stats.sdio.ds_d0_dur),
+ dtoh32(stats.sdio.ds_d3_cnt),
+ dtoh32(stats.sdio.ds_d3_dur),
+
+ dtoh32(stats.sdio.ds_dw_assrt_cnt),
+ dtoh32(stats.sdio.ds_dw_dassrt_cnt),
+
+ dtoh32(stats.sdio.ds_rx_dsack_cnt),
+ dtoh32(stats.sdio.ds_rx_dsnack_cnt),
+ dtoh32(stats.sdio.ds_rx_d3inform_cnt),
+ dtoh32(stats.sdio.ds_tx_dsreq_cnt),
+ dtoh32(stats.sdio.ds_tx_dsexit_cnt),
+ dtoh32(stats.sdio.ds_tx_d3ack_cnt),
+ dtoh32(stats.sdio.ds_tx_d3exit_cnt));
+
+ }
+ break;
+
+ case WL_PWRSTATS_TYPE_PM_AWAKE1:
+ {
+ wl_pwr_pm_awake_stats_v1_t stats;
+ bool skip = FALSE;
+ uint32 dur_time, bits;
+ uint endidx;
+
+ if (taglen < sizeof(wl_pwr_pm_awake_stats_v1_t)) {
+ fprintf(stderr, "Short len for %d: %d < %d\n",
+ type, taglen, (int)sizeof(wl_pwr_pm_awake_stats_v1_t));
+ rc = BCME_ERROR;
+ break;
+ }
+
+ memcpy(&stats, ptr, taglen);
+ printf("PM WAKE:\n"
+ " Current Time: %u\n"
+ " HW MACC: 0x%08x\n"
+ " SW MACC: 0x%08x\n"
+ " PM Dur: %u\n"
+ " MPC Dur: %u\n"
+ " TSF Drift (Last/Min/Max/Avg/Cnt): %d/%d/%d/%u/%u\n"
+ " Frts (end_cnt/dur): %u/%u\n",
+ dtoh32(stats.awake_data.curr_time),
+ dtoh32(stats.awake_data.hw_macc),
+ dtoh32(stats.awake_data.sw_macc),
+ dtoh32(stats.awake_data.pm_dur),
+ dtoh32(stats.awake_data.mpc_dur),
+ dtoh32(stats.awake_data.last_drift),
+ dtoh32(stats.awake_data.min_drift),
+ dtoh32(stats.awake_data.max_drift),
+ dtoh32(stats.awake_data.avg_drift),
+ dtoh32(stats.awake_data.drift_cnt),
+ dtoh32(stats.frts_end_cnt),
+ dtoh32(stats.frts_time));
+
+ printf("\n");
+
+ i = endidx = stats.awake_data.pmwake_idx;
+ if (endidx > WLC_STA_AWAKE_STATES_MAX_V1) {
+ fprintf(stderr, "Unexpected idx %d > %d\n",
+ endidx, WLC_STA_AWAKE_STATES_MAX_V1);
+ rc = BCME_ERROR;
+ break;
+ }
+
+ if (endidx == 0)
+ endidx = WLC_STA_AWAKE_STATES_MAX_V1;
+
+ do {
+ if (i >= WLC_STA_AWAKE_STATES_MAX_V1)
+ i = 0;
+
+ dur_time = dtoh32(stats.awake_data.pm_state[i].timestamp);
+ bits = dtoh32(stats.awake_data.pm_state[i].reason);
+ if (dur_time == 0 && bits == 0)
+ continue;
+
+ printf(" State: %2d reason: 0x%04x time: %u\n",
+ i, bits, dur_time);
+ } while (++i != endidx);
+ printf("\n");
+
+ for (i = 0; i < WLC_PMD_EVENT_MAX_V1; i++) {
+ dur_time = dtoh32(stats.awake_data.pmd_event_wake_dur[i]);
+ if (dur_time == 0) {
+ if (i != 0)
+ skip = TRUE;
+ continue;
+ }
+ if (skip) {
+ printf(" ---\n");
+ skip = FALSE;
+ }
+ printf(" Event: %2d Wake-Duration: %u\n", i, dur_time);
+ }
+ }
+ break;
+
+ case WL_PWRSTATS_TYPE_PM_AWAKE2:
+ {
+ wl_pwr_pm_awake_stats_v2_t *stats = (wl_pwr_pm_awake_stats_v2_t *)ptr;
+ bool skip = FALSE;
+ uint32 dur_time, bits;
+ uint endidx;
+
+ if (taglen < sizeof(wl_pwr_pm_awake_stats_v2_t)) {
+ fprintf(stderr, "Short len for %d: %d < %d\n",
+ type, taglen, (int)sizeof(wl_pwr_pm_awake_stats_v2_t));
+ rc = BCME_ERROR;
+ break;
+ }
+
+ printf("PM WAKE:\n"
+ " Current Time: %u\n"
+ " HW MACC: 0x%08x\n"
+ " SW MACC: 0x%08x\n"
+ " PM Dur: %u\n"
+ " MPC Dur: %u\n"
+ " TSF Drift (Last/Min/Max/Avg/Cnt): %d/%d/%d/%u/%u\n"
+ " Frts (end_cnt/dur): %u/%u\n"
+ " Flags: %d, ASLEEP=%s\n",
+ dtoh32(stats->awake_data.curr_time),
+ dtoh32(stats->awake_data.hw_macc),
+ dtoh32(stats->awake_data.sw_macc),
+ dtoh32(stats->awake_data.pm_dur),
+ dtoh32(stats->awake_data.mpc_dur),
+ dtoh32(stats->awake_data.last_drift),
+ dtoh32(stats->awake_data.min_drift),
+ dtoh32(stats->awake_data.max_drift),
+ dtoh32(stats->awake_data.avg_drift),
+ dtoh32(stats->awake_data.drift_cnt),
+ dtoh32(stats->awake_data.frts_end_cnt),
+ dtoh32(stats->awake_data.frts_time),
+ stats->awake_data.flags,
+ ((stats->awake_data.flags &
+ WL_PWR_PM_AWAKE_STATS_WAKE_MASK) == WL_PWR_PM_AWAKE_STATS_ASLEEP) ?
+ "True":"False");
+
+ printf("\n");
+ i = endidx = stats->awake_data.pmwake_idx;
+ if (endidx > stats->awake_data.pm_state_len) {
+ fprintf(stderr, "Unexpected idx %d > %d\n",
+ endidx, stats->awake_data.pm_state_len);
+ rc = BCME_ERROR;
+ break;
+ }
+
+ if (endidx == 0)
+ endidx = stats->awake_data.pm_state_len;
+
+ do {
+ wlc_pm_debug_t *pm_state = (wlc_pm_debug_t *)
+ (((uint8 *)&stats->awake_data) +
+ stats->awake_data.pm_state_offset);
+ if (i >= stats->awake_data.pm_state_len)
+ i = 0;
+
+ dur_time = dtoh32(pm_state[i].timestamp);
+ bits = dtoh32(pm_state[i].reason);
+ if (dur_time == 0 && bits == 0)
+ continue;
+
+ printf(" State: %2d reason: 0x%04x time: %u\n",
+ i, bits, dur_time);
+ } while (++i != endidx);
+ printf("\n");
+
+ for (i = 0; i < stats->awake_data.pmd_event_wake_dur_len; i++) {
+ uint32 *pmd_event_wake_dur = (uint32 *)
+ (((uint8 *)&stats->awake_data) +
+ stats->awake_data.pmd_event_wake_dur_offset);
+ dur_time = dtoh32(pmd_event_wake_dur[i]);
+ if (dur_time == 0) {
+ if (i != 0)
+ skip = TRUE;
+ continue;
+ }
+ if (skip) {
+ printf(" ---\n");
+ skip = FALSE;
+ }
+ printf(" Event: %2d Wake-Duration: %u\n", i, dur_time);
+ }
+ }
+ break;
+
+ case WL_PWRSTATS_TYPE_CONNECTION:
+ {
+ wl_pwr_connect_stats_t connect_stats;
+
+ if (taglen < sizeof(wl_pwr_connect_stats_t)) {
+ fprintf(stderr, "Short len for %d: %d < %d\n",
+ type, taglen, (int)sizeof(wl_pwr_connect_stats_t));
+ rc = BCME_ERROR;
+ break;
+ }
+
+ memcpy(&connect_stats, ptr, taglen);
+ printf("Connect:\n"
+ " Count: %u\n"
+ " Duration: %u\n",
+ dtoh32(connect_stats.count),
+ dtoh32(connect_stats.dur));
+ }
+ break;
+
+ case WL_PWRSTATS_TYPE_MIMO_PS_METRICS:
+ {
+ wl_mimo_meas_metrics_t stats;
+ bool ocl_stats = FALSE;
+
+ if (taglen < STRUCT_SIZE_THROUGH(&stats, total_tx_time_3chain)) {
+ fprintf(stderr, "Short len for %d: %d < %d\n",
+ type, taglen,
+ (int)STRUCT_SIZE_THROUGH(&stats, total_tx_time_3chain));
+ rc = BCME_ERROR;
+ break;
+ } else if (taglen >= STRUCT_SIZE_THROUGH(&stats, total_rx_time_ocl)) {
+ ocl_stats = TRUE;
+ }
+
+ memcpy(&stats, ptr, taglen);
+ printf("MIMO ps measurement metrics:\n");
+ if (ocl_stats) {
+ printf(" MIMO Idle duration:\t%10u (OCL Idle: %10u)\n"
+ " OCL Idle duration:\t%10u\n",
+ dtoh32(stats.total_idle_time_mimo),
+ dtoh32(stats.total_idle_time_ocl),
+ dtoh32(stats.total_idle_time_ocl));
+ } else {
+ printf(" MIMO Idle duration:\t%10u\n",
+ dtoh32(stats.total_idle_time_mimo));
+ }
+ printf(" SISO Idle duration:\t%10u\n",
+ dtoh32(stats.total_idle_time_siso));
+ if (ocl_stats) {
+ printf(" MIMO Rx duration:\t%10u (OCL Rx: %10u)\n"
+ " OCL Rx duration:\t%10u\n",
+ dtoh32(stats.total_rx_time_mimo),
+ dtoh32(stats.total_rx_time_ocl),
+ dtoh32(stats.total_rx_time_ocl));
+ } else {
+ printf(" MIMO Rx duration:\t%10u\n",
+ dtoh32(stats.total_rx_time_mimo));
+ }
+ printf(" SISO RX duration:\t%10u\n"
+ " TX 1-chain duration:\t%10u\n"
+ " TX 2-chain duration:\t%10u\n"
+ " TX 3-chain duration:\t%10u\n",
+ dtoh32(stats.total_rx_time_siso),
+ dtoh32(stats.total_tx_time_1chain),
+ dtoh32(stats.total_tx_time_2chain),
+ dtoh32(stats.total_tx_time_3chain));
+ }
+ break;
+ default:
+ printf("Skipping uknown %d-byte tag %d\n", taglen, type);
+ break;
+ }
+
+ printf("\n");
+ if (rc)
+ break;
+
+ /* Adjust length to account for padding, but don't exceed total len */
+ taglen = (ROUNDUP(taglen, 4) > len) ? len : ROUNDUP(taglen, 4);
+ len -= taglen;
+ }
+
+ if (len && (len < 2 * sizeof(uint16))) {
+ fprintf(stderr, "Invalid length remaining %d\n", len);
+ rc = BCME_ERROR;
+ }
+
+ return (rc);
+}
+
+
+/*
+* Function to output heap details for wl memuse command
+*/
+
+static int
+wl_memuse(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ memuse_info_t *mu;
+ wlc_rev_info_t revinfo;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ if ((err = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0)
+ return err;
+
+ if (revinfo.driverrev && dtoh32(revinfo.driverrev) < DINGO_FW_REV) {
+ /* memuse implementation for FW branch version < 9.0 (before Dingo) */
+ wl_varstr(wl, cmd, argv);
+ }
+ else {
+ /* memuse implementation for FW branch version > 9.0 (Dingo and above) */
+ memset(buf, 0, sizeof(memuse_info_t));
+ strcpy(buf, cmd->name);
+
+ if ((err = wlu_get(wl, WLC_GET_VAR, &buf[0], sizeof(memuse_info_t))) < 0) {
+ return err;
+ }
+
+ mu = (memuse_info_t *)buf;
+
+ if (mu->ver == RTE_MEMUSEINFO_VER && mu->len >= sizeof(memuse_info_t)) {
+ printf("Heap Total: %d(%dK)\n", mu->arena_size, KB(mu->arena_size));
+ printf("Free: %d(%dK), LWM: %d(%dK)\n",
+ mu->arena_free, KB(mu->arena_free),
+ mu->free_lwm, KB(mu->free_lwm));
+ printf("In use: %d(%dK), HWM: %d(%dK)\n",
+ mu->inuse_size, KB(mu->inuse_size),
+ mu->inuse_hwm, KB(mu->inuse_hwm));
+ printf("Malloc failure count: %d\n", mu->mf_count);
+ } else {
+ printf("Heap Total: %d(%dK), Heap Free: %d(%dK)\n",
+ mu->arena_size, KB(mu->arena_size),
+ mu->arena_free, KB(mu->arena_free));
+ }
+ }
+ return (0);
+}
+
+
+/* this is the batched command packet size. now for remoteWL, we set it to 512 bytes */
+#define MEMBLOCK (512 - 32) /* allow 32 bytes for overhead (header, alignment, etc) */
+
+int wl_seq_batch_in_client(bool enable)
+{
+ batch_in_client = enable;
+ return 0;
+}
+
+int
+wl_seq_start(void *wl, cmd_t *cmd, char **argv)
+{
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ if (!batch_in_client) {
+ return wlu_iovar_setbuf(wl, "seq_start", NULL, 0, buf, WLC_IOCTL_MAXLEN);
+ }
+ else {
+ if (cmd_batching_mode) {
+ printf("calling seq_start() when it's already in batching mode\n");
+ clean_up_cmd_list();
+ cmd_batching_mode = FALSE;
+ return BCME_USAGE_ERROR;
+ }
+ else {
+ cmd_batching_mode = TRUE;
+ cmd_pkt_list_num = 0;
+
+ cmd_list.head = NULL;
+ cmd_list.tail = NULL;
+ }
+ }
+
+ return 0;
+}
+
+int
+wl_seq_stop(void *wl, cmd_t *cmd, char **argv)
+{
+ char *bufp;
+ int ret = 0;
+ int seq_list_len;
+ int len;
+ wl_seq_cmd_pkt_t *next_cmd;
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ if (!batch_in_client) {
+ return wlu_iovar_setbuf(wl, "seq_stop", NULL, 0, buf, WLC_IOCTL_MAXLEN);
+ }
+ else {
+ if (!cmd_batching_mode) {
+ printf("calling seq_stop when it's already out of batching mode\n");
+ return BCME_USAGE_ERROR;
+ }
+ cmd_batching_mode = FALSE;
+
+ next_cmd = cmd_list.head;
+
+ /* dump batched commands to the DUT */
+
+ if (next_cmd == NULL) {
+ printf("no command batched\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ ret = wlu_iovar_setbuf(wl, "seq_start", NULL, 0, buf, WLC_IOCTL_MAXLEN);
+ if (ret) {
+ printf("failed to send seq_start\n");
+ goto fail;
+ }
+
+ while (next_cmd != NULL) {
+ bufp = buf;
+ memset(bufp, 0, WLC_IOCTL_MAXLEN);
+
+ strcpy(bufp, "seq_list");
+ bufp += (strlen("seq_list") + 1);
+
+ seq_list_len = bufp - buf;
+
+ while ((seq_list_len < MEMBLOCK) && (next_cmd != NULL)) {
+ /* note, driver handles the IOCTL buffer 32-bit alignment */
+ len = next_cmd->cmd_header.len;
+ len += (seq_list_len + sizeof(wl_seq_cmd_ioctl_t));
+
+ if (len < MEMBLOCK) {
+ memcpy(bufp, &(next_cmd->cmd_header),
+ sizeof(wl_seq_cmd_ioctl_t));
+ bufp += sizeof(wl_seq_cmd_ioctl_t);
+ memcpy(bufp, next_cmd->data, next_cmd->cmd_header.len);
+ bufp += next_cmd->cmd_header.len;
+ seq_list_len = len;
+
+ next_cmd = next_cmd->next;
+ }
+ else
+ break;
+ }
+
+ ret = wl_set(wl, WLC_SET_VAR, &buf[0], seq_list_len);
+
+ if (ret) {
+ printf("failed to send seq_list\n");
+ goto fail;
+ }
+ }
+
+ ret = wlu_iovar_setbuf(wl, "seq_stop", NULL, 0, buf, WLC_IOCTL_MAXLEN);
+ if (ret) {
+ printf("failed to send seq_stop\n");
+ }
+
+ fail:
+ clean_up_cmd_list();
+ return ret;
+ }
+}
+
+/* mkeep-alive : Send a periodic keep-alive packet or null-data at the specificed interval. */
+/* wowl_keepalive : Send a periodic keep alive packet the specificed interval in wowl mode. */
+int
+wl_mkeep_alive(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *str;
+ wl_mkeep_alive_pkt_t mkeep_alive_pkt;
+ wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
+ int buf_len;
+ int str_len;
+ int len_bytes;
+ int i;
+ int rc;
+ void *ptr = NULL;
+ bool immed_flag = FALSE;
+
+ memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t));
+
+ str = *argv; /* mkeep_alive or wowl_keepalive */
+ if (*++argv == NULL) {
+ return BCME_USAGE_ERROR;
+ }
+ else {
+ /* read the packet index */
+ int mkeep_alive_id = htod32(strtoul(*argv, NULL, 0));
+
+ if (*++argv == NULL) {
+ /*
+ ** Get current keep-alive status.
+ */
+ if ((rc = wlu_var_getbuf(wl, cmd->name, &mkeep_alive_id,
+ sizeof(int), &ptr)) < 0)
+ return rc;
+
+ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) ptr;
+
+ printf("Id :%d\n"
+ "Period (msec) :%d\n"
+ "Length :%d\n"
+ "Packet :0x",
+ mkeep_alive_pktp->keep_alive_id,
+ dtoh32(mkeep_alive_pktp->period_msec),
+ dtoh16(mkeep_alive_pktp->len_bytes));
+
+ for (i = 0; i < mkeep_alive_pktp->len_bytes; i++)
+ printf("%02x", mkeep_alive_pktp->data[i]);
+
+ printf("\n");
+ return rc;
+ }
+
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[ str_len ] = '\0';
+ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
+ if (strcmp(*argv, "immediate") == 0) {
+ immed_flag = TRUE;
+ argv++;
+ }
+ mkeep_alive_pkt.period_msec = strtoul(*argv, NULL, 0);
+ if (mkeep_alive_pkt.period_msec & WL_MKEEP_ALIVE_IMMEDIATE) {
+ fprintf(stderr, "Period %d too large\n", mkeep_alive_pkt.period_msec);
+ return -1;
+ }
+ if (immed_flag && mkeep_alive_pkt.period_msec) {
+ mkeep_alive_pkt.period_msec |= WL_MKEEP_ALIVE_IMMEDIATE;
+ }
+ mkeep_alive_pkt.period_msec = htod32(mkeep_alive_pkt.period_msec);
+ buf_len = str_len + 1;
+ mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
+ mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
+ mkeep_alive_pkt.keep_alive_id = mkeep_alive_id;
+
+ len_bytes = 0;
+
+ buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
+ if (mkeep_alive_pkt.period_msec != 0) {
+ if (NULL != *++argv) {
+ len_bytes = wl_pattern_atoh(*argv, (char *) mkeep_alive_pktp->data);
+ buf_len += len_bytes;
+ }
+ }
+ mkeep_alive_pkt.len_bytes = htod16(len_bytes);
+
+ /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
+ * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
+ * guarantee that the buffer is properly aligned.
+ */
+ memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
+
+ rc = wlu_set(wl, WLC_SET_VAR, buf, buf_len);
+ }
+
+ return (rc);
+}
+
+#ifdef RWL_WIFI
+/* Function added to support RWL_WIFI Transport
+* Used to find the remote server with proper mac address given by
+* the user,this cmd is specific to RWL_WIFIi protocol
+*/
+static int wl_wifiserver(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+
+ if ((ret = wlu_iovar_set(wl, cmd->name, *argv, strlen(*argv))) < 0) {
+ printf("Error finding the remote server %s\n", argv[0]);
+ return ret;
+ }
+ return ret;
+}
+#endif
+
+static int
+wl_srchmem(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ struct args {
+ int reg;
+ uint32 ssidlen;
+ uint8 ssid[DOT11_MAX_SSID_LEN];
+ } x;
+ char *endptr;
+ uint argc;
+ char *iovar;
+
+ UNUSED_PARAMETER(cmd);
+
+ memset(&x, 0, sizeof(x));
+
+ /* save command name */
+ iovar = argv[0];
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* required arg: reg offset */
+ if (argc < 1)
+ return BCME_USAGE_ERROR;
+
+ x.reg = strtol(argv[0], &endptr, 0);
+ if (*endptr != '\0' || x.reg > 15)
+ return BCME_USAGE_ERROR;
+
+ if (argc > 2)
+ return BCME_USAGE_ERROR;
+
+ if (argc == 2) {
+ uint32 len;
+
+ len = strlen(argv[1]);
+ if (len > sizeof(x.ssid)) {
+ printf("ssid too long\n");
+ return BCME_BADARG;
+ }
+ memcpy(x.ssid, argv[1], len);
+ x.ssidlen = len;
+ }
+
+ /* issue the get or set ioctl */
+ if (argc == 1) {
+ x.reg = htod32(x.reg);
+
+ ret = wlu_iovar_getbuf(wl, iovar, &x, sizeof(x), buf, WLC_IOCTL_SMLEN);
+ if (ret < 0) {
+ printf("get returned error 0x%x\n", ret);
+ return (ret);
+ }
+
+ wl_hexdump((uchar *)buf, sizeof(x.ssidlen) + sizeof(x.ssid));
+ } else {
+ x.reg = htod32(x.reg);
+ x.ssidlen = htod32(x.ssidlen);
+
+ ret = wlu_iovar_set(wl, iovar, &x, sizeof(x));
+ if (ret < 0) {
+ printf("set returned error 0x%x\n", ret);
+ return (ret);
+ }
+ }
+
+ return (ret);
+}
+
+cntry_name_t cntry_names[] = {
+
+{"AFGHANISTAN", "AF"},
+{"ALBANIA", "AL"},
+{"ALGERIA", "DZ"},
+{"AMERICAN SAMOA", "AS"},
+{"ANDORRA", "AD"},
+{"ANGOLA", "AO"},
+{"ANGUILLA", "AI"},
+{"ANTARCTICA", "AQ"},
+{"ANTIGUA AND BARBUDA", "AG"},
+{"ARGENTINA", "AR"},
+{"ARMENIA", "AM"},
+{"ARUBA", "AW"},
+{"ASCENSION ISLAND", "AC"},
+{"AUSTRALIA", "AU"},
+{"AUSTRIA", "AT"},
+{"AZERBAIJAN", "AZ"},
+{"BAHAMAS", "BS"},
+{"BAHRAIN", "BH"},
+{"BANGLADESH", "BD"},
+{"BARBADOS", "BB"},
+{"BELARUS", "BY"},
+{"BELGIUM", "BE"},
+{"BELIZE", "BZ"},
+{"BENIN", "BJ"},
+{"BERMUDA", "BM"},
+{"BHUTAN", "BT"},
+{"BOLIVIA", "BO"},
+{"BONAIRE SAINT EUSTATIUS AND SABA", "BQ"},
+{"BOSNIA AND HERZEGOVINA", "BA"},
+{"BOTSWANA", "BW"},
+{"BOUVET ISLAND", "BV"},
+{"BRAZIL", "BR"},
+{"BRITISH INDIAN OCEAN TERRITORY", "IO"},
+{"BRUNEI DARUSSALAM", "BN"},
+{"BULGARIA", "BG"},
+{"BURKINA FASO", "BF"},
+{"BURUNDI", "BI"},
+{"CAMBODIA", "KH"},
+{"CAMEROON", "CM"},
+{"CANADA", "CA"},
+{"CAPE VERDE", "CV"},
+{"CAYMAN ISLANDS", "KY"},
+{"CENTRAL AFRICAN REPUBLIC", "CF"},
+{"CHAD", "TD"},
+{"CHILE", "CL"},
+{"CHINA", "CN"},
+{"CHRISTMAS ISLAND", "CX"},
+{"CLIPPERTON ISLAND", "CP"},
+{"COCOS (KEELING) ISLANDS", "CC"},
+{"COLOMBIA", "CO"},
+{"COMOROS", "KM"},
+{"CONGO", "CG"},
+{"CONGO, THE DEMOCRATIC REPUBLIC OF THE", "CD"},
+{"COOK ISLANDS", "CK"},
+{"COSTA RICA", "CR"},
+{"COTE D'IVOIRE", "CI"},
+{"CROATIA", "HR"},
+{"CUBA", "CU"},
+{"CURACAO", "CW"},
+{"CYPRUS", "CY"},
+{"CZECH REPUBLIC", "CZ"},
+{"DENMARK", "DK"},
+{"DJIBOUTI", "DJ"},
+{"DOMINICA", "DM"},
+{"DOMINICAN REPUBLIC", "DO"},
+{"ECUADOR", "EC"},
+{"EGYPT", "EG"},
+{"EL SALVADOR", "SV"},
+{"EQUATORIAL GUINEA", "GQ"},
+{"ERITREA", "ER"},
+{"ESTONIA", "EE"},
+{"ETHIOPIA", "ET"},
+{"FALKLAND ISLANDS (MALVINAS)", "FK"},
+{"FAROE ISLANDS", "FO"},
+{"FIJI", "FJ"},
+{"FINLAND", "FI"},
+{"FRANCE", "FR"},
+{"FRENCH GUIANA", "GF"},
+{"FRENCH POLYNESIA", "PF"},
+{"FRENCH SOUTHERN TERRITORIES", "TF"},
+{"GABON", "GA"},
+{"GAMBIA", "GM"},
+{"GEORGIA", "GE"},
+{"GERMANY", "DE"},
+{"GHANA", "GH"},
+{"GIBRALTAR", "GI"},
+{"GREECE", "GR"},
+{"GREENLAND", "GL"},
+{"GRENADA", "GD"},
+{"GUADELOUPE", "GP"},
+{"GUAM", "GU"},
+{"GUATEMALA", "GT"},
+{"GUERNSEY", "GG"},
+{"GUINEA", "GN"},
+{"GUINEA-BISSAU", "GW"},
+{"GUYANA", "GY"},
+{"HAITI", "HT"},
+{"HEARD ISLAND AND MCDONALD ISLANDS", "HM"},
+{"HOLY SEE (VATICAN CITY STATE)", "VA"},
+{"HONDURAS", "HN"},
+{"HONG KONG", "HK"},
+{"HUNGARY", "HU"},
+{"ICELAND", "IS"},
+{"INDIA", "IN"},
+{"INDONESIA", "ID"},
+{"IRAN, ISLAMIC REPUBLIC OF", "IR"},
+{"IRAQ", "IQ"},
+{"IRELAND", "IE"},
+{"ISRAEL", "IL"},
+{"ITALY", "IT"},
+{"JAMAICA", "JM"},
+{"JAPAN", "JP"},
+{"JERSEY", "JE"},
+{"JORDAN", "JO"},
+{"KAZAKHSTAN", "KZ"},
+{"KENYA", "KE"},
+{"KIRIBATI", "KI"},
+{"KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF", "KP"},
+{"KOREA, REPUBLIC OF", "KR"},
+{"KUWAIT", "KW"},
+{"KYRGYZSTAN", "KG"},
+{"LAO PEOPLE'S DEMOCRATIC REPUBLIC", "LA"},
+{"LATVIA", "LV"},
+{"LEBANON", "LB"},
+{"LESOTHO", "LS"},
+{"LIBERIA", "LR"},
+{"LIBYAN ARAB JAMAHIRIYA", "LY"},
+{"LIECHTENSTEIN", "LI"},
+{"LITHUANIA", "LT"},
+{"LUXEMBOURG", "LU"},
+{"MACAO", "MO"},
+{"MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF", "MK"},
+{"MADAGASCAR", "MG"},
+{"MALAWI", "MW"},
+{"MALAYSIA", "MY"},
+{"MALDIVES", "MV"},
+{"MALI", "ML"},
+{"MALTA", "MT"},
+{"MAN, ISLE OF", "IM"},
+{"MARSHALL ISLANDS", "MH"},
+{"MARTINIQUE", "MQ"},
+{"MAURITANIA", "MR"},
+{"MAURITIUS", "MU"},
+{"MAYOTTE", "YT"},
+{"MEXICO", "MX"},
+{"MICRONESIA, FEDERATED STATES OF", "FM"},
+{"MOLDOVA, REPUBLIC OF", "MD"},
+{"MONACO", "MC"},
+{"MONGOLIA", "MN"},
+{"MONTENEGRO", "ME"},
+{"MONTSERRAT", "MS"},
+{"MOROCCO", "MA"},
+{"MOZAMBIQUE", "MZ"},
+{"MYANMAR", "MM"},
+{"NAMIBIA", "NA"},
+{"NAURU", "NR"},
+{"NEPAL", "NP"},
+{"NETHERLANDS", "NL"},
+{"NETHERLANDS ANTILLES", "AN"},
+{"NEW CALEDONIA", "NC"},
+{"NEW ZEALAND", "NZ"},
+{"NICARAGUA", "NI"},
+{"NIGER", "NE"},
+{"NIGERIA", "NG"},
+{"NIUE", "NU"},
+{"NORFOLK ISLAND", "NF"},
+{"NORTHERN MARIANA ISLANDS", "MP"},
+{"NORWAY", "NO"},
+{"OMAN", "OM"},
+{"PAKISTAN", "PK"},
+{"PALAU", "PW"},
+{"PALESTINIAN TERRITORY, OCCUPIED", "PS"},
+{"PANAMA", "PA"},
+{"PAPUA NEW GUINEA", "PG"},
+{"PARAGUAY", "PY"},
+{"PERU", "PE"},
+{"PHILIPPINES", "PH"},
+{"PITCAIRN", "PN"},
+{"POLAND", "PL"},
+{"PORTUGAL", "PT"},
+{"PUERTO RICO", "PR"},
+{"QATAR", "QA"},
+{"Q1", "Q1"},
+{"REUNION", "RE"},
+{"ROMANIA", "RO"},
+{"RUSSIAN FEDERATION", "RU"},
+{"RWANDA", "RW"},
+{"SAINT HELENA", "SH"},
+{"SAINT KITTS AND NEVIS", "KN"},
+{"SAINT LUCIA", "LC"},
+{"SAINT PIERRE AND MIQUELON", "PM"},
+{"SAINT VINCENT AND THE GRENADINES", "VC"},
+{"SAMOA", "WS"},
+{"SAN MARINO", "SM"},
+{"SAINT MARTIN", "MF"},
+{"SAO TOME AND PRINCIPE", "ST"},
+{"SAUDI ARABIA", "SA"},
+{"SENEGAL", "SN"},
+{"SERBIA", "RS"},
+{"SEYCHELLES", "SC"},
+{"SIERRA LEONE", "SL"},
+{"SINGAPORE", "SG"},
+{"SLOVAKIA", "SK"},
+{"SLOVENIA", "SI"},
+{"SOLOMON ISLANDS", "SB"},
+{"SOMALIA", "SO"},
+{"SOUTH AFRICA", "ZA"},
+{"SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS", "GS"},
+{"SPAIN", "ES"},
+{"SRI LANKA", "LK"},
+{"SUDAN", "SD"},
+{"SURINAME", "SR"},
+{"SVALBARD AND JAN MAYEN", "SJ"},
+{"SWAZILAND", "SZ"},
+{"SWEDEN", "SE"},
+{"SWITZERLAND", "CH"},
+{"SYRIAN ARAB REPUBLIC", "SY"},
+{"TAIWAN, PROVINCE OF CHINA", "TW"},
+{"TAJIKISTAN", "TJ"},
+{"TANZANIA, UNITED REPUBLIC OF", "TZ"},
+{"THAILAND", "TH"},
+{"TIMOR-LESTE (EAST TIMOR)", "TL"},
+{"TOGO", "TG"},
+{"TOKELAU", "TK"},
+{"TONGA", "TO"},
+{"TRINIDAD AND TOBAGO", "TT"},
+{"TRISTAN DA CUNHA", "TA"},
+{"TUNISIA", "TN"},
+{"TURKEY", "TR"},
+{"TURKMENISTAN", "TM"},
+{"TURKS AND CAICOS ISLANDS", "TC"},
+{"TUVALU", "TV"},
+{"UGANDA", "UG"},
+{"UKRAINE", "UA"},
+{"UNITED ARAB EMIRATES", "AE"},
+{"UNITED KINGDOM", "GB"},
+{"UNITED STATES", "US"},
+{"UNITED STATES MINOR OUTLYING ISLANDS", "UM"},
+{"URUGUAY", "UY"},
+{"UZBEKISTAN", "UZ"},
+{"VANUATU", "VU"},
+{"VENEZUELA", "VE"},
+{"VIET NAM", "VN"},
+{"VIRGIN ISLANDS, BRITISH", "VG"},
+{"VIRGIN ISLANDS, U.S.", "VI"},
+{"WALLIS AND FUTUNA", "WF"},
+{"WESTERN SAHARA", "EH"},
+{"YEMEN", "YE"},
+{"YUGOSLAVIA", "YU"},
+{"ZAMBIA", "ZM"},
+{"ZIMBABWE", "ZW"},
+{"RADAR CHANNELS", "RDR"},
+{"ALL CHANNELS", "ALL"},
+{NULL, NULL}
+};
+
+static int
+wl_ptk_start(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *str;
+ int buf_len;
+ int str_len;
+ int rc;
+ int count;
+ struct wl_ptk_start_iov_v1 *ptk_start_args;
+
+ UNUSED_PARAMETER(cmd);
+
+ count = ARGCNT(argv);
+
+ /*
+ ** Set the attributes.
+ */
+ if (count < 5) {
+ fprintf(stderr, "<sec-type> <peer_addr> <pmk> <role> expected\n");
+ rc = -1;
+ goto exit;
+ }
+
+ str = "ptk_start";
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[ str_len ] = '\0';
+
+ ptk_start_args = (struct wl_ptk_start_iov_v1 *) (buf + str_len + 1);
+ ptk_start_args->sec_type = strtoul(*(argv + 1), NULL, 0); /* WL_PTK_START_SEC_TYPE_PMK */
+ if (!wl_ether_atoe(*(argv + 2), &ptk_start_args->peer_addr)) {
+ fprintf(stderr, "awdl ranging config mac addr err\n");
+ rc = -1;
+ goto exit;
+ }
+ ptk_start_args->tlvs[0].id = WL_PTK_START_TLV_PMK;
+ ptk_start_args->tlvs[0].len = strlen(*(argv+3));
+ strncpy((char*)ptk_start_args->tlvs[0].data, *(argv+3), ptk_start_args->tlvs[0].len);
+ printf("PMK[len = %d]: %s\n", ptk_start_args->tlvs[0].len,
+ (char*)ptk_start_args->tlvs[0].data);
+ ptk_start_args->role = strtoul(*(argv + 4), NULL, 0); /* WL_PTK_START_SEC_TYPE_PMK */
+
+ buf_len = str_len + 1 + sizeof(struct wl_ptk_start_iov_v1) + ptk_start_args->tlvs[0].len;
+ rc = wlu_set(wl,
+ WLC_SET_VAR,
+ buf,
+ buf_len);
+exit:
+ return (rc);
+}
+
+void
+wl_print_mcsset(char *mcsset)
+{
+ int i;
+
+ printf("MCS SET : [ ");
+ for (i = 0; i < (MCSSET_LEN * 8); i++)
+ if (isset(mcsset, i))
+ printf("%d ", i);
+ printf("]\n");
+}
+
+static void
+wl_print_vhtmcsset(uint16 *mcsset)
+{
+ int i, j;
+
+ for (i = 0; i < VHT_CAP_MCS_MAP_NSS_MAX; i++) {
+ if (mcsset[i]) {
+ if (i == 0)
+ printf("VHT SET : ");
+ else
+ printf(" : ");
+ /* std MCS 0-9 and prop MCS 10-11 */
+ for (j = 0; j <= 11; j++)
+ if (isbitset(mcsset[i], j))
+ printf("%dx%d ", j, i + 1);
+ printf("\n");
+ } else {
+ break;
+ }
+ }
+}
+
+static void
+wl_print_txbf_mcsset(char *mcsset, char *prefix)
+{
+ int i;
+
+ printf("%s MCS : [ ", prefix);
+ for (i = 0; i < (TXBF_RATE_MCS_ALL * 8); i++)
+ if (isset(mcsset, i))
+ printf("%d ", i);
+ printf("]\n");
+}
+
+static void
+wl_print_txbf_vhtmcsset(uint16 *mcsset, char *prefix)
+{
+ int i, j;
+
+ for (i = 0; i < TXBF_RATE_VHT_ALL; i++) {
+ if (mcsset[i]) {
+ if (i == 0)
+ printf("%s VHT : ", prefix);
+ else
+ printf(" : ");
+ for (j = 0; j <= 11; j++)
+ if (isbitset(mcsset[i], j))
+ printf("%dx%d ", j, i + 1);
+ printf("\n");
+ } else {
+ break;
+ }
+ }
+}
+
+static int
+wl_assertlog(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc;
+ int err;
+ int i;
+ char *log_p = NULL;
+ assertlog_results_t *results;
+ void *ptr = NULL;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc > 1)
+ return BCME_USAGE_ERROR;
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return err;
+
+ results = (assertlog_results_t *)buf;
+
+ printf("get external assert logs: %d\n", results->num);
+ if (!results->num)
+ return 0;
+
+ if (results->version != ASSERTLOG_CUR_VER) {
+ printf("Version mismatch: version = 0x%x, expected 0x%x\n",
+ results->version, ASSERTLOG_CUR_VER);
+ return 0;
+ }
+
+ log_p = (char *)&results->logs[0];
+
+ printf("id: \ttime(ms) \tstring\n");
+ for (i = 0; i < (int)results->num; i++) {
+ printf("%d: \t%d \t%s", i, ((assert_record_t *)log_p)->time,
+ ((assert_record_t *)log_p)->str);
+ log_p += results->record_len;
+ }
+
+ return 0;
+}
+
+static const char *
+cca_level(int score, int med, int hi)
+{
+ if (score < med)
+ return ("Low");
+ if (score >= med && score < hi)
+ return ("Medium");
+ if (score >= hi)
+ return ("High");
+ return NULL;
+}
+
+static const char *cca_errors[] = {
+ "No error",
+ "Preferred band",
+ "Dwell Duration too low",
+ "Channel prefs",
+ "Interference too high",
+ "Only 1 channel inoput"
+};
+static void
+free_cca_array(cca_congest_channel_req_t **favg, int favg_chan_elts)
+{
+ int i;
+
+ if (favg == NULL)
+ {
+ return;
+ }
+ for (i = 0; i < favg_chan_elts; i++) {
+ if (favg[i] != NULL) {
+ free(favg[i]);
+ favg[i] = NULL;
+ }
+ }
+ if (favg != NULL) {
+ free(favg);
+ favg = NULL;
+ }
+}
+static int
+wl_cca_get_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ cca_congest_channel_req_t *results;
+ cca_congest_channel_req_t req;
+ cca_congest_t *chptr;
+ cca_congest_channel_req_t **avg = NULL, **new_avg = NULL; /* Max num of channels */
+ void *ptr = NULL;
+ char *param, *val_p;
+ int base, limit, i, channel, err = 0;
+ int ibss_per, obss_per, inter_per, val;
+ const char *ibss_lvl = NULL;
+ const char *obss_lvl = NULL;
+ const char *inter_lvl = NULL;
+ int tmp_channel;
+ chanspec_t new_chanspec, cur_chanspec;
+ bool do_individ = FALSE;
+ bool do_analyze = TRUE;
+ bool curband = FALSE;
+ int avg_chan_idx = 0, avg_chan_elts = 40;
+ uint32 flags;
+ int j;
+
+
+ req.num_secs = 10;
+ tmp_channel = 0xff;
+
+ argv++;
+
+ /* Parse args */
+ while ((param = *argv++) != NULL) {
+ if (stricmp(param, "-n") == 0) {
+ do_analyze = FALSE;
+ continue;
+ }
+ if (stricmp(param, "-i") == 0) {
+ do_individ = TRUE;
+ continue;
+ }
+ if (stricmp(param, "-curband") == 0) {
+ curband = TRUE;
+ continue;
+ }
+
+ if ((val_p = *argv++) == NULL) {
+ printf("Need value following %s\n", param);
+ return BCME_USAGE_ERROR;
+ }
+ if (stricmp(param, "-c") == 0) {
+ tmp_channel = (int)strtoul(val_p, NULL, 0);
+ }
+
+ if (stricmp(param, "-cs") == 0) {
+ if ((new_chanspec = wf_chspec_aton(val_p)))
+ tmp_channel = wf_chspec_ctlchan(new_chanspec);
+ }
+
+ if (stricmp(param, "-s") == 0) {
+ req.num_secs = (int)strtoul(val_p, NULL, 0);
+ if (req.num_secs == 0 || req.num_secs > MAX_CCA_SECS) {
+ printf("%d: Num of seconds must be <= %d\n",
+ req.num_secs, MAX_CCA_SECS);
+ return BCME_USAGE_ERROR;
+ }
+ }
+ }
+
+ if (tmp_channel == 0) {
+ /* do all channels */
+ base = 1; limit = MAXCHANNEL;
+ } else {
+ /* Use current channel as default if none specified */
+ if (tmp_channel == 0xff) {
+ if ((err = wlu_iovar_getint(wl, "chanspec", (int*)&val)) < 0) {
+ printf("CCA: Can't get currrent chanspec\n");
+ return err;
+ }
+ cur_chanspec = wl_chspec32_from_driver(val);
+ tmp_channel = wf_chspec_ctlchan(cur_chanspec);
+ printf("Using channel %d\n", tmp_channel);
+ }
+ base = limit = tmp_channel;
+ }
+
+ avg = (cca_congest_channel_req_t **)
+ calloc(1, sizeof(cca_congest_channel_req_t*) * avg_chan_elts);
+ if (avg == NULL) {
+ printf("unable to allocate memory\n");
+ return BCME_NOMEM;
+ }
+
+ for (channel = base; channel <= limit; channel++) {
+
+ /* Get stats for each channel */
+ req.chanspec = CH20MHZ_CHSPEC(channel);
+ req.chanspec = wl_chspec_to_driver(req.chanspec);
+ if ((err = wlu_var_getbuf(wl, cmd->name, &req, sizeof(req), &ptr)) < 0) {
+ goto func_exit;
+ }
+
+ results = (cca_congest_channel_req_t *)ptr;
+ results->chanspec = wl_chspec_from_driver(results->chanspec);
+ if (results->chanspec == 0 || results->num_secs == 0)
+ continue;
+
+ if (results->num_secs > MAX_CCA_SECS) {
+ printf("Bogus num of seconds returned %d\n", results->num_secs);
+ err = -1;
+ goto func_exit;
+ }
+
+ /* Summarize and save summary for this channel */
+ if (avg_chan_idx >= avg_chan_elts) {
+ new_avg = (cca_congest_channel_req_t **)calloc
+ (1, sizeof(cca_congest_channel_req_t*) * (avg_chan_elts + 10));
+
+ if (new_avg == NULL) {
+ printf("unable to allocate memory\n");
+ err = BCME_NOMEM;
+ goto func_exit;
+ }
+ memcpy(new_avg, avg, avg_chan_elts);
+ free_cca_array(avg, avg_chan_elts);
+ avg_chan_elts += 10;
+ avg = new_avg;
+ new_avg = NULL;
+ }
+
+ avg[avg_chan_idx] = (cca_congest_channel_req_t *)
+ malloc(sizeof(cca_congest_channel_req_t));
+ if (avg[avg_chan_idx] == NULL) {
+ printf("unable to allocate memory\n");
+ err = BCME_NOMEM;
+ goto func_exit;
+ }
+ cca_per_chan_summary(results, avg[avg_chan_idx], 1);
+ if (avg[avg_chan_idx]->num_secs)
+ avg_chan_idx++;
+
+ /* printf stats for each second of each channel */
+ if (do_individ) {
+ if (channel == base)
+ printf("chan dur ibss obss"
+ " interf time\n");
+ for (i = 0; i < results->num_secs; i++) {
+ chptr = &results->secs[i];
+ if (chptr->duration) {
+ /* Percentages */
+ ibss_per = chptr->congest_ibss * 100 /chptr->duration;
+ obss_per = chptr->congest_obss * 100 /chptr->duration;
+ inter_per = chptr->interference * 100 /chptr->duration;
+ /* Levels */
+ ibss_lvl = cca_level(ibss_per, IBSS_MED, IBSS_HI);
+ obss_lvl = cca_level(obss_per, OBSS_MED, OBSS_HI);
+ inter_lvl = cca_level(inter_per, INTERFER_MED, INTERFER_HI);
+
+ printf("%-3u %4d %4u %2d%% %-6s %4u %2d%% %-6s %4u %2d%% %-6s %d\n",
+ CHSPEC_CHANNEL(results->chanspec),
+ chptr->duration,
+ chptr->congest_ibss, ibss_per, ibss_lvl,
+ chptr->congest_obss, obss_per, obss_lvl,
+ chptr->interference, inter_per, inter_lvl,
+ chptr->timestamp);
+ }
+ }
+ }
+ }
+
+ /* Print summary stats of each channel */
+ printf("Summaries:\n");
+ printf("chan dur ibss obss interf num seconds\n");
+ for (j = 0; j < avg_chan_idx; j++) {
+ /* Percentages */
+ ibss_per = avg[j]->secs[0].congest_ibss;
+ obss_per = avg[j]->secs[0].congest_obss;
+ inter_per = avg[j]->secs[0].interference;
+ /* Levels */
+ ibss_lvl = cca_level(ibss_per, IBSS_MED, IBSS_HI);
+ obss_lvl = cca_level(obss_per, OBSS_MED, OBSS_HI);
+ inter_lvl = cca_level(inter_per, INTERFER_MED, INTERFER_HI);
+
+ if (avg[j]->num_secs) {
+ printf("%-3u %4d %4s %2d%% %-6s %4s %2d%% %-6s %4s %2d%% %-6s %d\n",
+ CHSPEC_CHANNEL(avg[j]->chanspec),
+ avg[j]->secs[0].duration,
+ "", avg[j]->secs[0].congest_ibss, ibss_lvl,
+ "", avg[j]->secs[0].congest_obss, obss_lvl,
+ "", avg[j]->secs[0].interference, inter_lvl,
+ avg[j]->num_secs);
+ }
+ }
+
+ if (!do_analyze) {
+ goto func_exit;
+ }
+
+ if ((err = wlu_iovar_getint(wl, "chanspec", (int *)&val)) < 0) {
+ printf("CCA: Can't get currrent chanspec\n");
+ goto func_exit;
+ }
+ cur_chanspec = wl_chspec32_from_driver(val);
+ flags = 0;
+ if (curband) {
+ if (CHSPEC_IS5G(cur_chanspec))
+ flags |= CCA_FLAG_5G_ONLY;
+ if (CHSPEC_IS2G(cur_chanspec))
+ flags |= CCA_FLAG_2G_ONLY;
+ }
+
+ if ((err = cca_analyze(avg, avg_chan_idx, flags, &new_chanspec)) != 0) {
+ if (err > 0) {
+ printf("Cannot find a good channel due to: %s\n", cca_errors[err]);
+ err = BCME_ERROR;
+ }
+ goto func_exit;
+ }
+ printf("Recommended channel: %d\n", wf_chspec_ctlchan(new_chanspec));
+
+ func_exit:
+ free_cca_array(avg, avg_chan_elts);
+
+ return err;
+}
+
+static int
+wl_txdelay_params(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ txdelay_params_t param;
+ int argc;
+
+ argv++;
+
+ if (*argv == NULL) {
+ /* get current txdelay params */
+ if ((err = wlu_iovar_get(wl, cmd->name, (void *) ¶m,
+ (sizeof(txdelay_params_t)))) < 0)
+ return (err);
+
+ printf("Txdelay params: ratio[%d] cnt[%d] period[%d] tune[%d]\n",
+ param.ratio, param.cnt, param.period, param.tune);
+ }
+ else {
+ char *endptr;
+ /* Validate num of entries */
+ for (argc = 0; argv[argc]; argc++);
+ if (argc != 4)
+ return BCME_USAGE_ERROR;
+
+ argc = 0;
+ param.ratio = strtol(argv[argc], &endptr, 0);
+ argc++;
+ param.cnt = strtol(argv[argc], &endptr, 0);
+ argc++;
+ param.period = strtol(argv[argc], &endptr, 0);
+ argc++;
+ param.tune = strtol(argv[argc], &endptr, 0);
+
+ /* Set txdelay params */
+ err = wlu_iovar_set(wl, cmd->name, (void *) ¶m,
+ (sizeof(txdelay_params_t)));
+ }
+ return (err);
+}
+
+static void
+dlystat_dump(txdelay_stats_t *txdelay_stats)
+{
+ const char *const aci_names[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO"};
+ uint32 i, last, s;
+ uint ac;
+ uint32 sum;
+ uint32 max_val, total = 0;
+ scb_delay_stats_t *delay_stats;
+ struct ether_addr *ea;
+ uint32 dlystat_cnt = txdelay_stats->scb_cnt;
+
+ if (txdelay_stats->full_result == TXDELAY_STATS_PARTIAL_RESULT) {
+ printf("\tThis is partial results for SCBs\n"
+ "\tcaused by insuffient IOCTL buffer\n"
+ "\tIf you want to get full SCBs\n"
+ "\tPlease use iteration for each of specific mac_address\n"
+ "\twhich can be got from other iovars such as assoclist\n");
+ }
+
+ for (s = 0; s < dlystat_cnt; s++) {
+ ea = &txdelay_stats->scb_delay_stats[s].ea;
+ printf("[SCB%d]\n\t%s\n", s, wl_ether_etoa(ea));
+ /* Report Latency and packet loss statistics (for each AC) */
+ for (ac = 0; ac < AC_COUNT; ac++) {
+
+ delay_stats = txdelay_stats->scb_delay_stats[s].dlystats + ac;
+ for (i = 0, total = 0, sum = 0; i < SCB_RETRY_SHORT_DEF; i++) {
+ total += delay_stats->txmpdu_cnt[i];
+ sum += delay_stats->delay_sum[i];
+ }
+ if (total) {
+ printf("%s: PLoss %d/%d (%d%%)\n",
+ aci_names[ac], delay_stats->txmpdu_lost, total,
+ (delay_stats->txmpdu_lost * 100) / total);
+ printf("\tDelay stats in usec (avg/min/max): %d %d %d\n",
+ CEIL(sum, total), delay_stats->delay_min,
+ delay_stats->delay_max);
+ printf("\tTxcnt Hist :");
+ for (i = 0; i < SCB_RETRY_SHORT_DEF; i++) {
+ printf(" %d", delay_stats->txmpdu_cnt[i]);
+ }
+ printf("\n\tDelay vs Txcnt:");
+ for (i = 0; i < SCB_RETRY_SHORT_DEF; i++) {
+ if (delay_stats->txmpdu_cnt[i])
+ printf(" %d", delay_stats->delay_sum[i] /
+ delay_stats->txmpdu_cnt[i]);
+ else
+ printf(" -1");
+ }
+ printf("\n");
+
+ for (i = 0, max_val = 0, last = 0; i < WLPKTDLY_HIST_NBINS; i++) {
+ max_val += delay_stats->delay_hist[i];
+ if (delay_stats->delay_hist[i]) last = i;
+ }
+ last = 8 * (last/8 + 1) - 1;
+ if (max_val) {
+ printf("\tDelay Hist \n\t\t:");
+ for (i = 0; i <= last; i++) {
+ printf(" %d(%d%%)", delay_stats->
+ delay_hist[i],
+ (delay_stats->delay_hist[i] * 100)
+ / max_val);
+ if ((i % 8) == 7 && i != last)
+ printf("\n\t\t:");
+ }
+ }
+ printf("\n");
+ }
+ }
+ printf("\n");
+ }
+}
+
+static int
+wl_dlystats(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ txdelay_stats_t *dlystats_param;
+ txdelay_stats_t *delay_stats;
+
+ dlystats_param = (txdelay_stats_t *)malloc(sizeof(*dlystats_param));
+
+ if (dlystats_param == NULL) {
+ return BCME_NOMEM;
+ }
+
+ memset(dlystats_param, 0, sizeof(*dlystats_param));
+ dlystats_param->version = TXDELAY_STATS_VERSION;
+
+ if (*++argv) {
+ if (!wl_ether_atoe(*argv, &dlystats_param->scb_delay_stats[0].ea)) {
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+ dlystats_param->scb_cnt = 1;
+ } else {
+ dlystats_param->scb_cnt = MAX_TXDELAY_STATS_SCBS;
+ }
+
+ ret = wlu_iovar_getbuf(wl, cmd->name, dlystats_param, sizeof(*dlystats_param),
+ buf, WLC_IOCTL_MAXLEN);
+
+
+ if (ret) {
+ if (ret == BCME_VERSION) {
+ printf("txdelay_stats_t version is mismatched\n");
+ }
+ goto EXIT;
+ }
+
+ delay_stats = (txdelay_stats_t *)buf;
+ dlystat_dump(delay_stats);
+
+EXIT:
+ free(dlystats_param);
+ return ret;
+}
+
+static int
+wl_dlystats_clear(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+
+ UNUSED_PARAMETER(argv);
+
+ err = wlu_iovar_set(wl, cmd->name, buf, 0);
+
+ return err;
+}
+
+static int
+wl_intfer_params(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_intfer_params_t param;
+ int argc;
+ char *endptr = NULL;
+
+ argv++;
+
+ if (*argv == NULL) {
+ /* get current txdelay params */
+ if ((err = wlu_iovar_get(wl, cmd->name, (void *) ¶m,
+ (sizeof(wl_intfer_params_t)))) < 0)
+ goto error;
+
+ if (param.version != INTFER_VERSION) {
+ printf("Interference params structure version (%d) is not the "
+ "version (%d) supported by this tool",
+ INTFER_VERSION, param.version);
+ err = BCME_USAGE_ERROR;
+ }
+ else
+ printf("Intference params: period[%x] cnt[%x] txfail_thresh[%x]"
+ " tcptxfail_thresh[%x]\n", param.period, param.cnt,
+ param.txfail_thresh, param.tcptxfail_thresh);
+ }
+ else {
+ /* Validate num of entries */
+ err = BCME_USAGE_ERROR;
+
+ for (argc = 0; argv[argc]; argc++);
+ if (argc != 4)
+ goto error;
+
+ param.period = (uint8)strtol(argv[0], &endptr, 0);
+ if (*endptr != '\0')
+ goto error;
+
+ param.cnt = (uint8)strtol(argv[1], &endptr, 0);
+ if (*endptr != '\0')
+ goto error;
+
+ param.txfail_thresh = (uint8)strtol(argv[2], &endptr, 0);
+ if (*endptr != '\0')
+ goto error;
+
+ param.tcptxfail_thresh = (uint8)strtol(argv[3], &endptr, 0);
+ if (*endptr != '\0')
+ goto error;
+
+ /* Set intfer params */
+ param.version = INTFER_VERSION;
+ err = wlu_iovar_set(wl, cmd->name, (void *) ¶m,
+ (sizeof(wl_intfer_params_t)));
+ }
+error:
+ return (err);
+}
+
+static int
+wl_rpmt(void *wl, cmd_t *cmd, char **argv)
+{
+ int count;
+ int len;
+ char *endptr;
+ uint32 val;
+
+ argv ++;
+
+ count = ARGCNT(argv);
+ if (count != 2) {
+ return BCME_USAGE_ERROR;
+ }
+
+ strcpy(buf, cmd->name);
+ len = strlen(buf) + 1;
+
+ val = htod32(strtoul(argv[0], &endptr, 0));
+ memcpy(&buf[len], &val, sizeof(uint32));
+ len += sizeof(uint32);
+ val = htod32(strtoul(argv[1], &endptr, 0));
+ memcpy(&buf[len], &val, sizeof(uint32));
+ len += sizeof(uint32);
+
+ return wlu_set(wl, WLC_SET_VAR, buf, len);
+}
+
+static int
+wl_tsf(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "tsf";
+ struct tsf {
+ uint32 low;
+ uint32 high;
+ } tsf_buf;
+ char *endptr;
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* toss the command name */
+ argv++;
+
+ if (*argv == NULL) {
+ /* get */
+ err = wlu_iovar_get(wl, cmdname, &tsf_buf, sizeof(tsf_buf));
+ if (err)
+ return err;
+ printf("0x%08X 0x%08X\n", htod32(tsf_buf.high), htod32(tsf_buf.low));
+ } else {
+ /* set */
+ if (argv[1] == NULL)
+ return BCME_USAGE_ERROR;
+
+ tsf_buf.high = (uint32)strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "%s: %s: error parsing \"%s\" as an integer\n",
+ wlu_av0, cmdname, *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+ tsf_buf.low = (uint32)strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "%s: %s: error parsing \"%s\" as an integer\n",
+ wlu_av0, cmdname, *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ tsf_buf.low = dtoh32(tsf_buf.low);
+ tsf_buf.high = dtoh32(tsf_buf.high);
+
+ err = wlu_iovar_set(wl, cmdname, &tsf_buf, sizeof(tsf_buf));
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+static int wl_event_log_set_init(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "event_log_set_init";
+ wl_el_set_params_t pars;
+ int argc;
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc != 3) {
+ return BCME_USAGE_ERROR;
+ }
+
+ memset(&pars, 0, sizeof(wl_el_set_params_t));
+ pars.set = atoi(argv[1]);
+ pars.size = htod32(atoi(argv[2]));
+
+ err = wlu_iovar_set(wl, cmdname, &pars, sizeof(wl_el_set_params_t));
+
+ return err;
+}
+
+static int wl_event_log_set_expand(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "event_log_set_expand";
+ wl_el_set_params_t pars;
+ int argc;
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc != 3) {
+ return BCME_USAGE_ERROR;
+ }
+
+ memset(&pars, 0, sizeof(wl_el_set_params_t));
+ pars.set = atoi(argv[1]);
+ pars.size = htod32(atoi(argv[2]));
+
+ err = wlu_iovar_set(wl, cmdname, &pars, sizeof(wl_el_set_params_t));
+
+ return err;
+}
+
+static int wl_event_log_set_shrink(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "event_log_set_shrink";
+ wl_el_set_params_t pars;
+ int argc;
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if ((argc < 2) || (argc > 3)) {
+ return BCME_USAGE_ERROR;
+ }
+
+ memset(&pars, 0, sizeof(wl_el_set_params_t));
+ pars.set = atoi(argv[1]);
+ if (argc == 3)
+ pars.size = htod32(atoi(argv[2]));
+
+ err = wlu_iovar_set(wl, cmdname, &pars, sizeof(wl_el_set_params_t));
+
+ return err;
+}
+
+static int wl_event_log_tag_control(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "event_log_tag_control";
+ wl_el_tag_params_t pars;
+ int argc;
+ int err;
+ int flags = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc < 4) {
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+
+ memset(&pars, 0, sizeof(wl_el_tag_params_t));
+ pars.tag = htod16(atoi(*argv++));
+ pars.set = atoi(*argv++);
+
+ while (*argv) {
+ if (!strcmp(*argv, "LOG")) {
+ flags |= EVENT_LOG_TAG_FLAG_LOG;
+ } else if (!strcmp(*argv, "PRINT")) {
+ flags |= EVENT_LOG_TAG_FLAG_PRINT;
+ } else if (!strcmp(*argv, "NONE")) {
+ flags |= EVENT_LOG_TAG_FLAG_NONE;
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+ argv++;
+ }
+
+ pars.flags = flags;
+
+ err = wlu_iovar_set(wl, cmdname, &pars, sizeof(pars));
+
+ return err;
+}
+
+static int wl_event_log_get(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "event_log_get";
+ char *set_arg = NULL;
+ wl_el_set_params_t pars;
+ int argc;
+ int err = BCME_OK;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* arg count */
+ for (argv++, argc = 0; argv[argc]; argc++);
+
+ memset(&pars, 0, sizeof(wl_el_set_params_t));
+
+ /* Look for -f */
+ if ((*argv) && !strcmp(*argv, "-f")) {
+ set_arg = *++argv;
+ if (!set_arg)
+ {
+ fprintf(stderr, "Missing argument to -f option\n");
+ return BCME_USAGE_ERROR;
+ }
+ /* Ignore other arguments */
+ pars.set = atoi(set_arg);
+ pars.size = 0;
+
+ /* cause a flush of an event log buffer associated with this particular
+ * set. This flush is caused by trigerring logtrace
+ */
+ err = wlu_iovar_set(wl, cmdname, &pars, sizeof(wl_el_set_params_t));
+ }
+ else
+ {
+ fprintf(stderr, "Missing -f option. Currently -g <set> -s <buf_len> "
+ "options are not supported\n");
+ err = BCME_USAGE_ERROR;
+ }
+ return err;
+}
+
+#ifdef SERDOWNLOAD
+
+static int dhd_rwl_download(void *dhd, char *fwname, char *command);
+
+int
+rwl_download(void *dhd, cmd_t *cmd, char **argv)
+{
+ char *fname = NULL;
+ char *vname = NULL;
+ int ret = 0;
+ UNUSED_PARAMETER(cmd);
+ if (!*++argv) {
+ fprintf(stderr, "Require dongle image filename \n");
+ ret = -1;
+ goto exit;
+ }
+ else {
+ fname = *argv;
+ if (debug)
+ printf("dongle image file is %s\n", fname);
+ }
+ if (!*++argv) {
+ fprintf(stderr, "vars filename missing, assuming no var file\n");
+ ret = -1;
+ goto exit;
+ }
+ else {
+ vname = *argv;
+ if (debug)
+ printf("dongle var file is %s\n", vname);
+ }
+ ret = dhd_rwl_download(dhd, fname, "download");
+ printf("ret = %d\n", ret);
+
+ if (ret == 0)
+ ret = dhd_rwl_download(dhd, vname, "nvdownload");
+exit:
+ return ret;
+}
+
+static int
+dhd_rwl_download(void *dhd, char *fwfile, char *command)
+{
+ unsigned char *bufp = NULL;
+ int len = 0, length = 0;
+ int ret = 0;
+ char *p;
+ unsigned char *buff = NULL;
+ int remained_bytes;
+ uint32 start = 0;
+ FILE *fp = NULL;
+ struct stat finfo;
+ unsigned long status;
+
+ /* Open the firmware file */
+ if (!(fp = fopen(fwfile, "rb"))) {
+ perror(fwfile);
+ ret = -1;
+ goto exit;
+ }
+
+ if (stat(fwfile, &finfo)) {
+ printf("dhd_rwl_download: %s: %s\n", fwfile, strerror(errno));
+ ret = -1;
+ goto exit;
+ }
+
+ length = finfo.st_size;
+
+ if (length <= 0) {
+ ret = -1;
+ goto exit;
+ }
+
+ if ((bufp = malloc(length +4)) == NULL) {
+ printf("dhd_rwl_download: Unable to allowcate %d bytes!\n", len);
+ ret = -1;
+ goto exit;
+ }
+
+ /* Read the firmware file into the buffer */
+ status = fread(bufp, sizeof(uint8), length, fp);
+
+ /* close the firmware file */
+ fclose(fp);
+ fp = NULL;
+
+ if ((int)status < length) {
+ printf("dhd_rwl_download: Short read in %s!\n", fwfile);
+ ret = -1;
+ goto exit;
+ }
+
+
+ printf("Starting %s, total file length is %d\n", command, length);
+
+ /* do the download reset */
+ if ((ret = wlu_iovar_setint(dhd, command, TRUE))) {
+ fprintf(stderr, "dhd_rwl_download: failed to put dongle to download mode\n");
+ ret = -1;
+ goto exit;
+ }
+
+ buff = bufp;
+ remained_bytes = len = length;
+
+ while (remained_bytes > 0) {
+ printf(".");
+ p = buf;
+ memset(p, 0, WLC_IOCTL_MAXLEN);
+ strcpy(p, "membytes");
+ p += strlen("membytes") + 1;
+
+ memcpy(p, &start, sizeof(int));
+ p += sizeof(int);
+
+ if (remained_bytes >= MEMBLOCK)
+ len = MEMBLOCK;
+ else
+ len = remained_bytes;
+
+ memcpy(p, &len, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, buff, len);
+ p += len;
+
+ if (debug) {
+ printf("sending %d bytes block: \n", (int)(p - buf));
+ }
+
+ ret = wlu_set(dhd, WLC_SET_VAR, &buf[0], (int) (p - buf));
+
+ if (ret) {
+ fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n",
+ "wl_set()", ret, len, start);
+ goto exit;
+ }
+
+ start += len;
+ buff += len;
+ remained_bytes -= len;
+ }
+ printf("\n");
+
+ /* start running the downloaded code, download complete */
+ if ((ret = wlu_iovar_setint(dhd, command, FALSE))) {
+ fprintf(stderr, "dhd_rwl_download: failed to take dongle out of download mode\n");
+ goto exit;
+ }
+
+exit:
+ if (bufp)
+ free(bufp);
+
+ if (fp)
+ fclose(fp);
+
+ return ret;
+}
+
+/* Check that strlen("membytes")+1 + 2*sizeof(int32) + MEMBLOCK <= WLC_IOCTL_MAXLEN */
+#if (MEMBLOCK + 17 > WLC_IOCTL_MAXLEN)
+#error MEMBLOCK/WLC_IOCTL_MAXLEN sizing
+#endif
+
+static int dhd_hsic_download(void *dhd, char *fwname, char *nvname);
+static int ReadFiles(char *fwfile, char *nvfile, unsigned char ** buffer);
+static int check_file(unsigned char *headers);
+
+static char* chip_select = "none";
+
+int
+dhd_init(void *dhd, cmd_t *cmd, char **argv)
+{
+ int ret = -1;
+ UNUSED_PARAMETER(cmd);
+
+ if (!*++argv) {
+ fprintf(stderr, "Error: Missing require chip ID"
+ "<4325, 4329, 43291, 4330a1, 4330 or hsic>\n");
+ ret = BCME_USAGE_ERROR;
+ }
+ else if (strcmp(*argv, "4325") && strcmp(*argv, "4329") &&
+ strcmp(*argv, "43291") && strcmp(*argv, "4330") &&
+ strcmp(*argv, "4330a1") && strcmp(*argv, "hsic")) {
+ fprintf(stderr, "Error: Unsupported chip ID %s\n", *argv);
+ ret = BCME_BADARG;
+ }
+ else if ((ret = wlu_iovar_setbuf(dhd, "init", *argv, strlen(*argv) + 1,
+ buf, WLC_IOCTL_MAXLEN))) {
+ fprintf(stderr, "Error: %s: failed to initialize the dongle \n",
+ "dhd_init()");
+ }
+ else
+ ret = 0;
+
+ if (ret == 0) {
+ if (!strcmp(*argv, "4325")) {
+ fprintf(stdout, "4325 is the selected chip id\n");
+ chip_select = "4325";
+ } else if (!strcmp(*argv, "4329")) {
+ fprintf(stdout, "4329 is the selected chip id\n");
+ chip_select = "4329";
+ } else if (!strcmp(*argv, "43291")) {
+ fprintf(stdout, "43291 is the selected chip id\n");
+ chip_select = "43291";
+ } else if (!strcmp(*argv, "4330")) {
+ fprintf(stdout, "4330b0 is the selected chip id\n");
+ chip_select = "4330b0";
+ } else if (!strcmp(*argv, "4330a1")) {
+ fprintf(stdout, "4330a1 is the selected chip id\n");
+ chip_select = "4330a1";
+ } else if (!strcmp(*argv, "hsic")) {
+ fprintf(stdout, "hsic interface is selected\n");
+ chip_select = "hsic";
+ } else
+ chip_select = "none";
+ }
+
+ return ret;
+}
+
+int
+dhd_download(void *dhd, cmd_t *cmd, char **argv)
+{
+ char *fname = NULL;
+ char *vname = NULL;
+ uint32 start = 0;
+ uint32 last4bytes;
+ int ret = 0;
+ uint file_size;
+ int ram_size = 0, var_size, var_words, nvram_len, remained_bytes;
+ FILE *fp = NULL;
+ struct stat finfo;
+ char *bufp;
+ int len;
+ uint8 memblock[MEMBLOCK];
+ uint8 varbuf[WLC_IOCTL_MAXLEN];
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!strcmp(chip_select, "none")) {
+ fprintf(stderr, "chip init must be called before firmware download. \n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!strcmp(chip_select, "4325")) {
+ fprintf(stdout, "using 4325 ram_info\n");
+ ram_size = RAM_SIZE_4325;
+ } else if (!strcmp(chip_select, "4329")) {
+ fprintf(stdout, "using 4329 ram_info\n");
+ ram_size = RAM_SIZE_4329;
+ } else if (!strcmp(chip_select, "43291")) {
+ fprintf(stdout, "using 43291 ram_info\n");
+ ram_size = RAM_SIZE_43291;
+ } else if (!strcmp(chip_select, "4330b0")) {
+ fprintf(stdout, "using 4330 b0 ram_info\n");
+ ram_size = RAM_SIZE_4330_b0;
+ } else if (!strcmp(chip_select, "4330a1")) {
+ fprintf(stdout, "using 4330a1 ram_info\n");
+ ram_size = RAM_SIZE_4330_a1;
+ } else if (!strcmp(chip_select, "hsic")) {
+ fprintf(stdout, "using hsic interface\n");
+ } else {
+ fprintf(stderr, "Error: unknown chip\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!*++argv) {
+ fprintf(stderr, "Require dongle image filename \n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ else {
+ fname = *argv;
+ if (debug)
+ printf("dongle image file is %s\n", fname);
+ }
+
+ if (!*++argv) {
+ fprintf(stderr, "vars filename missing, assuming no var file\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+
+ }
+ else {
+ vname = *argv;
+ if (debug)
+ printf("dongle var file is %s\n", vname);
+ }
+
+
+ /* do the download on hsic */
+ /* merge the firmware and the nvram */
+ if (!strcmp(chip_select, "hsic")) {
+ /* the hsic firwmare and download code */
+ ret = dhd_hsic_download(dhd, fname, vname);
+ return ret;
+ }
+
+ if (!(fp = fopen(fname, "rb"))) {
+ perror(fname);
+ ret = BCME_BADARG;
+ goto exit;
+ }
+
+ if (stat(fname, &finfo)) {
+ perror(fname);
+ ret = -1;
+ goto exit;
+ }
+ file_size = finfo.st_size;
+ if (debug) {
+ printf("%s file_size=%d\n", fname, file_size);
+ }
+
+ /* do the download reset if not suppressed */
+ if ((ret = wlu_iovar_setint(dhd, "download", TRUE))) {
+ fprintf(stderr, "%s: failed to put dongle in download mode\n",
+ "dhd_iovar_setint()");
+ goto exit;
+ }
+
+ memset(memblock, 0, MEMBLOCK);
+
+ printf("downloading %s, file_size=%d\n", fname, file_size);
+
+ /* read the file and push blocks down to memory */
+ while ((len = fread(memblock, sizeof(uint8), MEMBLOCK, fp))) {
+ if (len < MEMBLOCK && !feof(fp)) {
+ fprintf(stderr, "%s: error reading file %s\n", "fread()", fname);
+ ret = -1;
+ goto exit;
+ }
+
+ if (debug) {
+ printf("memblock=\n%s\n", memblock);
+ }
+
+ bufp = buf;
+ memset(bufp, 0, WLC_IOCTL_MAXLEN);
+ strcpy(bufp, "membytes");
+ bufp += strlen("membytes") + 1;
+ memcpy(bufp, &start, sizeof(int));
+ bufp += sizeof(int);
+ memcpy(bufp, &len, sizeof(int));
+ bufp += sizeof(int);
+ memcpy(bufp, memblock, len);
+
+ ret = wl_set(dhd, WLC_SET_VAR, &buf[0], (bufp - buf + len));
+
+ if (ret) {
+ fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n",
+ "wl_set()", ret, len, start);
+ goto exit;
+ }
+
+ start += len;
+ memset(memblock, 0, MEMBLOCK);
+ }
+
+ if (!feof(fp)) {
+ fprintf(stderr, "%s: error reading file %s\n", "feof()", fname);
+ ret = -1;
+ goto exit;
+ }
+ fclose(fp);
+ fp = NULL;
+
+ if (vname) {
+ /* download the vars file if specified */
+ /* read in the file */
+ if (!(fp = fopen(vname, "rb"))) {
+ perror(vname);
+ ret = BCME_BADARG;
+ goto exit;
+ }
+
+ if (stat(vname, &finfo)) {
+ perror(vname);
+ ret = -1;
+ goto exit;
+ }
+ file_size = finfo.st_size;
+
+ printf("downloading %s, file_size=%d\n", vname, file_size);
+
+ memset(varbuf, 0, WLC_IOCTL_MAXLEN);
+
+ /* read the file and push blocks down to memory */
+ if (fread(varbuf, 1, file_size, fp) != file_size) {
+ perror(fname);
+ ret = -1;
+ goto exit;
+ }
+
+ fclose(fp);
+ fp = NULL;
+
+ if (debug) {
+ printf("the original varbuf=%s\n", varbuf);
+ }
+
+ /* convert linefeeds to nuls */
+ nvram_len = process_nvram_vars((char*)&varbuf, file_size);
+ if (debug) {
+ printf("after process_nvram_vars(), %s nvram_len=%d\n%s\n",
+ vname, nvram_len, varbuf);
+ }
+ bufp = (char*)&varbuf + nvram_len;
+ *bufp++ = 0;
+
+ var_size = ROUNDUP(nvram_len + 1, 4);
+ /* calculate start address */
+ start = ram_size - var_size - 4;
+
+ if (debug) {
+ printf("var_size=%d, start=0x%0X\n", var_size, start);
+ }
+
+ /* need to send the last 4 bytes. */
+ var_words = var_size / 4;
+ last4bytes = (~var_words << 16) | (var_words & 0x0000FFFF);
+ last4bytes = htol32(last4bytes);
+
+ if (debug) {
+ printf("last4bytes=0x%0X\n", last4bytes);
+ }
+
+ bufp = (char*)&varbuf + var_size;
+ memcpy(bufp, &last4bytes, 4);
+
+ /* send down var_size+4 bytes with each time "membytes" MEMBLOCK bytes */
+ bufp = (char*)&varbuf;
+ remained_bytes = var_size + 4;
+
+ while (remained_bytes > 0) {
+ char *p;
+
+ p = buf;
+ memset(p, 0, WLC_IOCTL_MAXLEN);
+
+ strcpy(p, "membytes");
+ p += strlen("membytes") + 1;
+
+ memcpy(p, &start, sizeof(int));
+ p += sizeof(int);
+
+ if (remained_bytes >= MEMBLOCK) {
+ len = MEMBLOCK;
+ }
+ else
+ len = remained_bytes;
+
+ memcpy(p, &len, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, bufp, len);
+ p += len;
+
+ if (debug) {
+ printf("sending %d bytes block:\n", (int)(p - buf));
+ printf("%s\n", buf);
+ }
+
+ ret = wl_set(dhd, WLC_SET_VAR, &buf[0], (p - buf));
+
+ if (ret) {
+ fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n",
+ "wl_set()", ret, len, start);
+ goto exit;
+ }
+
+ start += len;
+ bufp += len;
+ remained_bytes -= len;
+ }
+ }
+
+ /* start running the downloaded code if not suppressed */
+ if ((ret = wlu_iovar_setint(dhd, "download", FALSE))) {
+ fprintf(stderr, "%s: failed to take dongle out of download mode\n",
+ "dhd_iovar_setint()");
+ goto exit;
+ }
+
+exit:
+ if (fp)
+ fclose(fp);
+
+ return ret;
+}
+
+
+int
+dhd_upload(void *dhd, cmd_t *cmd, char **argv)
+{
+ char *fname = NULL;
+ uint32 start = 0;
+ uint32 size;
+ int ram_size;
+ FILE *fp = NULL;
+ uint len;
+ int ret = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!strcmp(chip_select, "none")) {
+ fprintf(stderr, "chip init must be called before firmware download. \n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!strcmp(chip_select, "4325")) {
+ fprintf(stdout, "using 4325 ram_info\n");
+ ram_size = RAM_SIZE_4325;
+ } else if (!strcmp(chip_select, "4329")) {
+ fprintf(stdout, "using 4329 ram_info\n");
+ ram_size = RAM_SIZE_4329;
+ } else if (!strcmp(chip_select, "43291")) {
+ fprintf(stdout, "using 43291 ram_info\n");
+ ram_size = RAM_SIZE_43291;
+ } else if (!strcmp(chip_select, "4330b0")) {
+ fprintf(stdout, "using 4330 b0 ram_info\n");
+ ram_size = RAM_SIZE_4330_b0;
+ } else if (!strcmp(chip_select, "4330a1")) {
+ fprintf(stdout, "using 4330 a1 ram_info\n");
+ ram_size = RAM_SIZE_4330_a1;
+ } else {
+ fprintf(stderr, "Error: unknown chip\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ argv++;
+
+ if (debug) {
+ printf("argv=%s\n", *argv);
+ }
+
+ fname = *argv;
+
+ /* validate arguments */
+ if (!fname) {
+ fprintf(stderr, "filename required\n");
+ ret = BCME_BADARG;
+ goto exit;
+ }
+
+ if (!(fp = fopen(fname, "wb"))) {
+ perror(fname);
+ ret = BCME_BADARG;
+ goto exit;
+ }
+
+ /* default size to full RAM */
+ size = ram_size - start;
+
+ /* read memory and write to file */
+ while (size) {
+ char *ptr;
+ int params[2];
+
+ len = MIN(MEMBLOCK, size);
+
+ params[0] = start;
+ params[1] = len;
+ ret = wlu_iovar_getbuf(dhd, "membytes", params, 2 * sizeof(int),
+ (void**)&ptr, MEMBLOCK);
+ if (ret) {
+ fprintf(stderr, "dhd_upload(): failed reading %d membytes from 0x%08x\n",
+ len, start);
+ break;
+ }
+
+ if (fwrite(ptr, sizeof(*ptr), len, fp) != len) {
+ fprintf(stderr, "dhd_upload(): error writing to file %s\n", fname);
+ ret = -1;
+ break;
+ }
+
+ start += len;
+ size -= len;
+ }
+
+ fclose(fp);
+exit:
+ return ret;
+}
+
+static int
+dhd_hsic_download(void *dhd, char *fwfile, char *nvfile)
+{
+ unsigned char *bufp = NULL;
+ int len = 0, length = 0;
+ int ret = 0;
+ char *p;
+ unsigned char *buff = NULL;
+ int remained_bytes;
+ uint32 start = 0;
+
+ /* read and merge fw and nvram files */
+ length = ReadFiles(fwfile, nvfile, &bufp);
+ if (length <= 0) {
+ ret = -1;
+ goto exit;
+ }
+
+ printf("Starting download, total file length is %d\n", length);
+
+ /* do the download reset */
+ if ((ret = wlu_iovar_setint(dhd, "download", TRUE))) {
+ fprintf(stderr, "dhd_hsic_download: failed to put dongle to download mode\n");
+ goto exit;
+ }
+
+ buff = bufp;
+ remained_bytes = len = length;
+
+ while (remained_bytes > 0) {
+ printf(".");
+ p = buf;
+ memset(p, 0, WLC_IOCTL_MAXLEN);
+ strcpy(p, "membytes");
+ p += strlen("membytes") + 1;
+
+ memcpy(p, &start, sizeof(int));
+ p += sizeof(int);
+
+ if (remained_bytes >= MEMBLOCK)
+ len = MEMBLOCK;
+ else
+ len = remained_bytes;
+
+ memcpy(p, &len, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, buff, len);
+ p += len;
+
+ if (debug) {
+ printf("sending %d bytes block: \n", (int)(p - buf));
+ }
+
+ ret = wlu_set(dhd, WLC_SET_VAR, &buf[0], (p - buf));
+
+ if (ret) {
+ fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n",
+ "wl_set()", ret, len, start);
+ goto exit;
+ }
+
+ start += len;
+ buff += len;
+ remained_bytes -= len;
+ }
+ printf("\n");
+
+ /* start running the downloaded code, download complete */
+ if ((ret = wlu_iovar_setint(dhd, "download", FALSE))) {
+ fprintf(stderr, "dhd_hsic_download: failed to take dongle out of download mode\n");
+ goto exit;
+ }
+
+exit:
+ if (bufp)
+ free(bufp);
+
+ return ret;
+}
+
+static int ReadFiles(char *fname, char *vname, unsigned char ** buffer)
+{
+ FILE *fp = NULL;
+ FILE *fp1 = NULL;
+ struct stat finfo;
+ uint8 *buf = NULL;
+ int len, fwlen, actual_len, nvlen = 0;
+ struct trx_header *hdr;
+ unsigned long status;
+ unsigned int pad;
+ unsigned int i;
+ int ret = -1;
+
+ /* Open the firmware file */
+ if (!(fp = fopen(fname, "rb"))) {
+ perror(fname);
+ ret = BCME_BADARG;
+ goto exit;
+ }
+
+ if (stat(fname, &finfo)) {
+ printf("dhd_download: %s: %s\n", fname, strerror(errno));
+ ret = -1;
+ goto exit;
+ }
+ len = fwlen = finfo.st_size;
+
+ /* Open nvram file */
+ if (!(fp1 = fopen(vname, "rb"))) {
+ perror(fname);
+ ret = BCME_BADARG;
+ goto exit;
+ }
+
+ if (stat(vname, &finfo)) {
+ printf("dhd_download: %s: %s\n", vname, strerror(errno));
+ ret = -1;
+ goto exit;
+ }
+ nvlen = finfo.st_size;
+ len += nvlen;
+
+ if ((buf = malloc(len +4)) == NULL) {
+ printf("dhd_download: Unable to allowcate %d bytes!\n", len);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ /* Read the firmware file into the buffer */
+ status = fread(buf, sizeof(uint8), fwlen, fp);
+
+ /* close the firmware file */
+ fclose(fp);
+
+ if ((int)status < fwlen) {
+ printf("dhd_download: Short read in %s!\n", fname);
+ ret = -1;
+ goto exit;
+ }
+
+ /* Validating the format /length etc of the file */
+ if ((actual_len = check_file(buf)) <= 0) {
+ printf("dhd_download: Failed input file check on %s!\n", fname);
+ ret = -1;
+ goto exit;
+ }
+
+ /* Read the nvram file into the buffer */
+ status = fread(buf + actual_len, sizeof(uint8), nvlen, fp1);
+
+ /* close the nvram file */
+ fclose(fp1);
+
+ if ((int)status < nvlen) {
+ printf("dhd_download: Short read in %s!\n", vname);
+ ret = -1;
+ goto exit;
+ }
+
+ /* porcess nvram vars if user specifics a text file instead of binary */
+ nvlen = process_nvram_vars((char*) &buf[actual_len], (unsigned int) nvlen);
+
+ if (nvlen % 4) {
+ pad = 4 - (nvlen % 4);
+ for (i = 0; i < pad; i ++)
+ buf[actual_len + nvlen + i] = 0;
+ nvlen += pad;
+ }
+
+ /* fix up len to be actual len + nvram len */
+ len = actual_len + nvlen;
+ /* update trx header with added nvram bytes */
+ hdr = (struct trx_header *) buf;
+ hdr->len = htol32(len);
+ /* pass the actual fw len */
+ hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] = htol32(nvlen);
+ /* caculate CRC over header */
+ hdr->crc32 = hndcrc32((uint8 *) &hdr->flag_version,
+ sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version),
+ CRC32_INIT_VALUE);
+
+ /* Calculate CRC over data */
+ for (i = sizeof(struct trx_header); i < (unsigned int)len; ++i)
+ hdr->crc32 = hndcrc32((uint8 *)&buf[i], 1, hdr->crc32);
+ hdr->crc32 = htol32(hdr->crc32);
+
+ *buffer = buf;
+ return len;
+
+exit:
+ if (buf)
+ free(buf);
+
+ return ret;
+}
+
+static int
+check_file(unsigned char *headers)
+{
+ struct trx_header *trx;
+ int actual_len = -1;
+
+ /* Extract trx header */
+ trx = (struct trx_header *)headers;
+ if ((ltoh32(trx->magic)) != TRX_MAGIC) {
+ printf("check_file: Error: trx bad hdr %x!\n", ltoh32(trx->magic));
+ return -1;
+ }
+
+ if (ltoh32(trx->flag_version) & TRX_UNCOMP_IMAGE) {
+ actual_len = ltoh32(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]) +
+ sizeof(struct trx_header);
+ return actual_len;
+ }
+ return actual_len;
+}
+#endif /* SERDOWNLOAD */
+
+static int
+wlu_mempool(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ int ret;
+ int i;
+ wl_mempool_stats_t *stats;
+ bcm_mp_stats_t *mp_stats;
+
+
+ UNUSED_PARAMETER(argv);
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ stats = (wl_mempool_stats_t *) ptr;
+ mp_stats = stats->s;
+
+ printf("%-8s %8s %8s %8s %8s %8s\n", "Name", "SZ", "Max", "Curr", "HiWater", "Failed");
+ for (i = 0; i < stats->num; i++) {
+ printf("%-8s %8d %8d %8d %8d %8d\n", mp_stats->name, (int) mp_stats->objsz,
+ mp_stats->nobj, mp_stats->num_alloc, mp_stats->high_water,
+ mp_stats->failed_alloc);
+
+ mp_stats++;
+ }
+
+ return (0);
+}
+
+static int
+wl_rxfifo_counters(void *wl, cmd_t *cmd, char **argv)
+{
+ char *statsbuf;
+ wl_rxfifo_cnt_t cnt;
+ int err;
+ void *ptr;
+ int i;
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_var_getbuf_sm (wl, cmd->name, NULL, 0, &ptr)))
+ return (err);
+
+ statsbuf = (char *)ptr;
+ memcpy(&cnt, statsbuf, sizeof(cnt));
+ cnt.version = dtoh16(cnt.version);
+ cnt.length = dtoh16(cnt.length);
+
+ if (cnt.version != WL_RXFIFO_CNT_VERSION) {
+ printf("\tIncorrect version of rxfifo counters struct: expected %d; got %d\n",
+ WL_RXFIFO_CNT_VERSION, cnt.version);
+ return -1;
+ }
+
+ for (i = 0; i < MAX_RX_FIFO; i++) {
+ printf("RXFIFO[%d]: data: %u\tmgmtctl: %u \n",
+ i, cnt.rxf_data[i], cnt.rxf_mgmtctl[i]);
+ }
+
+ return (0);
+}
+
+static int
+wl_ie(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ int err;
+ uchar *data;
+ int bsscfg_idx = 0;
+ int consumed = 0;
+ int iecount;
+ ie_setbuf_t *ie_setbuf;
+ ie_getbuf_t param;
+ uchar datalen, type, count, col;
+
+ /* parse a bsscfg_idx option if present */
+ if ((err = wl_cfg_option(argv + 1, argv[0], &bsscfg_idx, &consumed)) != 0)
+ return err;
+ if (consumed)
+ argv = argv + consumed;
+ else
+ bsscfg_idx = -1;
+
+ if (!*++argv) {
+ fprintf(stderr, "missing parameter type\n");
+ return BCME_USAGE_ERROR;
+ }
+ /* get IE type */
+ type = (uchar)atoi(argv[0]);
+
+ if (!*++argv) {
+ param.id = type;
+ ptr = buf;
+ if (bsscfg_idx == -1)
+ err = wlu_var_getbuf(wl, cmd->name, ¶m, sizeof(param), &ptr);
+ else
+ err = wl_bssiovar_getbuf(wl, cmd->name, bsscfg_idx, ¶m, sizeof(param),
+ buf, WLC_IOCTL_MAXLEN);
+ if (err == 0) {
+ data = (uchar *)ptr;
+ datalen = data[1]+2;
+ printf("%s len %d\n", cmd->name, datalen);
+ printf("%s Data:\n", cmd->name);
+ for (count = 0; (count < datalen);) {
+ for (col = 0; (col < MAX_DATA_COLS) &&
+ (count < datalen); col++, count++) {
+ printf("%02x", *data++);
+ }
+ printf("\n");
+ }
+ }
+ else {
+ fprintf(stderr, "Error %d getting IOVar\n", err);
+ }
+ return err;
+ }
+
+ /* get IE length */
+ datalen = (uchar)atoi(argv[0]);
+
+ if (datalen > 0) {
+ if (!argv[1]) {
+ fprintf(stderr, "Data bytes should be specified for IE of length %d\n",
+ datalen);
+ return BCME_USAGE_ERROR;
+ }
+ else {
+ /* Ensure each data byte is 2 characters long */
+ if ((int)strlen (argv[1]) < (datalen * 2)) {
+ fprintf(stderr, "Please specify all the data bytes for this IE\n");
+ return BCME_BADARG;
+ }
+ }
+ }
+
+ if ((datalen == 0) && (argv[1] != NULL))
+ fprintf(stderr, "Ignoring data bytes for IE of length %d\n", datalen);
+
+ count = sizeof(ie_setbuf_t) + datalen - 1;
+ data = malloc(count);
+ if (data == NULL) {
+ fprintf(stderr, "memory alloc failure\n");
+ return BCME_NOMEM;
+ }
+
+ ie_setbuf = (ie_setbuf_t *) data;
+ /* Copy the ie SET command ("add") to the buffer */
+ strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
+ ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+ /* Buffer contains only 1 IE */
+ iecount = htod32(1);
+ memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int));
+
+ /* Now, add the IE to the buffer */
+ ie_setbuf->ie_buffer.ie_list[0].ie_data.id = type;
+ ie_setbuf->ie_buffer.ie_list[0].ie_data.len = datalen;
+
+ if (datalen > 0) {
+ if ((err = get_ie_data ((uchar *)argv[1],
+ (uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0],
+ datalen))) {
+ free(data);
+ fprintf(stderr, "Error parsing data arg\n");
+ return err;
+ }
+ }
+
+ if (bsscfg_idx == -1)
+ err = wlu_var_setbuf(wl, cmd->name, data, count);
+ else
+ err = wlu_bssiovar_setbuf(wl, cmd->name, bsscfg_idx,
+ data, count, buf, WLC_IOCTL_MAXLEN);
+
+ free(data);
+ return (err);
+}
+
+/* Restore the ignored warnings status */
+
+
+static int
+wl_sleep_ret_ext(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int argc, i;
+ uint32 val;
+ char *endptr = NULL;
+ wl_pm2_sleep_ret_ext_t sleep_ret_ext;
+ wl_pm2_sleep_ret_ext_t* sleep_ret_ext_ptr;
+
+ /* Skip the command name */
+ UNUSED_PARAMETER(cmd);
+ argv++;
+
+ /* If no arguments are given, print the existing settings */
+ argc = ARGCNT(argv);
+ if (argc == 0) {
+ char *logic_str;
+
+ /* Get and print the values */
+ if ((ret = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, (void*) &sleep_ret_ext_ptr)))
+ return ret;
+
+ if (sleep_ret_ext_ptr->logic == WL_DFRTS_LOGIC_OFF)
+ logic_str = "DISABLED";
+ else if (sleep_ret_ext_ptr->logic == WL_DFRTS_LOGIC_OR)
+ logic_str = "OR";
+ else if (sleep_ret_ext_ptr->logic == WL_DFRTS_LOGIC_AND)
+ logic_str = "AND";
+ else
+ logic_str = "ERROR";
+
+ printf("logic: %d (%s)\n",
+ sleep_ret_ext_ptr->logic, logic_str);
+ if (sleep_ret_ext_ptr->logic != WL_DFRTS_LOGIC_OFF) {
+ printf("low_ms: %d\n", sleep_ret_ext_ptr->low_ms);
+ printf("high_ms: %d\n", sleep_ret_ext_ptr->high_ms);
+ printf("rx_pkts_threshold: %d\n",
+ sleep_ret_ext_ptr->rx_pkts_threshold);
+ printf("tx_pkts_threshold: %d\n",
+ sleep_ret_ext_ptr->tx_pkts_threshold);
+ printf("txrx_pkts_threshold: %d\n",
+ sleep_ret_ext_ptr->txrx_pkts_threshold);
+ printf("rx_bytes_threshold: %d\n",
+ sleep_ret_ext_ptr->rx_bytes_threshold);
+ printf("tx_bytes_threshold: %d\n",
+ sleep_ret_ext_ptr->tx_bytes_threshold);
+ printf("txrx_bytes_threshold: %d\n",
+ sleep_ret_ext_ptr->txrx_bytes_threshold);
+ }
+ return 0;
+ }
+
+ memset(&sleep_ret_ext, 0, sizeof(wl_pm2_sleep_ret_ext_t));
+ i = 0;
+
+ /* Get the first 'logic' argument. */
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ if (val != WL_DFRTS_LOGIC_OFF && val != WL_DFRTS_LOGIC_OR &&
+ val != WL_DFRTS_LOGIC_AND) {
+ printf("Invalid logic value %u\n", val);
+ goto usage;
+ }
+ sleep_ret_ext.logic = val;
+ ++i;
+
+ /* If logic is 0 (disable) then no more arguments are needed */
+ if (sleep_ret_ext.logic == 0)
+ goto set;
+
+ if (argc < 9)
+ goto usage;
+
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ sleep_ret_ext.low_ms = val;
+ ++i;
+
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ sleep_ret_ext.high_ms = val;
+ ++i;
+
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ sleep_ret_ext.rx_pkts_threshold = val;
+ ++i;
+
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ sleep_ret_ext.tx_pkts_threshold = val;
+ ++i;
+
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ sleep_ret_ext.txrx_pkts_threshold = val;
+ ++i;
+
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ sleep_ret_ext.rx_bytes_threshold = val;
+ ++i;
+
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ sleep_ret_ext.tx_bytes_threshold = val;
+ ++i;
+
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ sleep_ret_ext.txrx_bytes_threshold = val;
+ ++i;
+
+ if (i != argc)
+ goto usage;
+
+set:
+ return wlu_var_setbuf(wl, cmd->name, &sleep_ret_ext,
+ sizeof(wl_pm2_sleep_ret_ext_t));
+
+usage:
+ printf("Usage: %s [logic] [<low_ms> <high_ms>"
+ " <rxP> <txP> <txrxP> <rxB> <txB> <txrxB>\n", wlu_av0);
+ printf("Parameters:\n");
+ printf("logic : 0=disable, 1=OR, 2=AND all non-zero switching thresholds.\n");
+ printf("low_ms : Low pm2_sleep_ret value.\n");
+ printf("high_ms : High pm2_sleep_ret value.\n");
+ printf("rxP : Switching threshold in # of rx packets.\n");
+ printf(" eg. Switch from the low to high FRTS value if rxP or\n");
+ printf(" more packets are received in a PM2 radio wake period.\n");
+ printf(" 0 means ignore this threshold.\n");
+ printf("txP : Switching threshold in # of tx packets.\n");
+ printf("txrxP : Switching threshold in # of combined tx+rx packets.\n");
+ printf("rxB : Switching threshold in # of rx bytes.\n");
+ printf("txB : Switching threshold in # of tx bytes.\n");
+ printf("txrxB : Switching threshold in # of combined tx+rx bytes.\n");
+ return -1;
+}
+
+static int wl_stamon_sta_config(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ wlc_stamon_sta_config_t stamon_cfg;
+ struct maclist *maclist = (struct maclist *) buf;
+ uint i, max = (WLC_IOCTL_MAXLEN - sizeof(int)) / ETHER_ADDR_LEN;
+ struct ether_addr *ea;
+
+ memset(&stamon_cfg, 0, sizeof(wlc_stamon_sta_config_t));
+ if (!*++argv) {
+ maclist->count = htod32(max);
+ err = wlu_iovar_get(wl, cmd->name, maclist,
+ WLC_IOCTL_MAXLEN);
+ if (!err) {
+ for (i = 0, ea = maclist->ea; i < maclist->count && i < max; i++, ea++)
+ printf("%s\n", wl_ether_etoa(ea));
+ }
+ } else {
+ if (!stricmp(*argv, "add")) {
+ stamon_cfg.cmd = STAMON_CFG_CMD_ADD;
+ if (!*++argv || !wl_ether_atoe(*argv, &stamon_cfg.ea)) {
+ printf(" ERROR: no valid ether addr provided\n");
+ err = -1;
+ }
+ } else if (!stricmp(*argv, "del")) {
+ stamon_cfg.cmd = STAMON_CFG_CMD_DEL;
+ if (!*++argv || !wl_ether_atoe(*argv, &stamon_cfg.ea)) {
+ printf(" ERROR: no valid ether addr provided\n");
+ err = -1;
+ }
+ } else if (!stricmp(*argv, "enable"))
+ stamon_cfg.cmd = STAMON_CFG_CMD_ENB;
+ else if (!stricmp(*argv, "disable"))
+ stamon_cfg.cmd = STAMON_CFG_CMD_DSB;
+ else if (!stricmp(*argv, "counters")) {
+ const char *cmdname = "sta_monitor_cnt";
+ uint32 cnt = 0;
+ if ((err = wlu_iovar_getint(wl, cmdname, (int *)&cnt) < 0)) {
+ return err;
+ }
+ printf("stamon cnt=%u\n", cnt);
+ return err;
+ } else if (!stricmp(*argv, "reset_cnts"))
+ stamon_cfg.cmd = STAMON_CFG_CMD_RSTCNT;
+ else if (!stricmp(*argv, "stats")) {
+ stamon_info_t *pbuf;
+
+ stamon_cfg.cmd = STAMON_CFG_CMD_GET_STATS;
+ if (!*++argv || !wl_ether_atoe(*argv, &stamon_cfg.ea)) {
+ printf(" ERROR: no valid ether addr provided\n");
+ err = -1;
+ }
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ if (!err) {
+ err = wlu_iovar_getbuf(wl, cmd->name, &stamon_cfg,
+ sizeof(wlc_stamon_sta_config_t), buf, WLC_IOCTL_MAXLEN);
+ }
+ pbuf = (stamon_info_t*)buf;
+ if (!err) {
+ if (pbuf->count != 0) {
+ /* Success case: Found the mac in STAMON and
+ * read the stats
+ */
+ printf(""MACF" : RSSI :%d \n",
+ ETHER_TO_MACF(pbuf->sta_data[0].ea),
+ pbuf->sta_data[0].rssi);
+ } else if (pbuf->count == 0) {
+ /* Failed case, Didn't Found the Mac
+ * read the stats
+ */
+ printf("STAMON not monitoring "MACF" \n",
+ ETHER_TO_MACF(stamon_cfg.ea));
+ }
+ }
+
+ return err;
+ } else {
+ printf("error: unknown operation option%s\n", *argv);
+ err = -1;
+ }
+
+ if (!err)
+ err = wlu_iovar_set(wl, cmd->name,
+ &stamon_cfg, sizeof(wlc_stamon_sta_config_t));
+
+ }
+
+ return err;
+}
+
+static monitor_promisc_level_msg_t wl_monpromisc_level_msgs[] = {
+ {WL_MONPROMISC_PROMISC, "promisc"},
+ {WL_MONPROMISC_CTRL, "ctrl"},
+ {WL_MONPROMISC_FCS, "fcs"},
+ {0, NULL}
+};
+
+static int
+wl_monitor_promisc_level(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, i;
+ uint val = 0, last_val = 0;
+ uint promiscbitmap = 0, promiscbitmap_add = 0, promiscbitmap_del = 0;
+ char *endptr;
+ const char *cmdname = "monitor_promisc_level";
+
+ UNUSED_PARAMETER(cmd);
+ if ((ret = wlu_iovar_getint(wl, cmdname, (int *)&promiscbitmap) < 0)) {
+ return ret;
+ }
+ promiscbitmap = dtoh32(promiscbitmap);
+ if (!*++argv) {
+ printf("0x%x ", promiscbitmap);
+ for (i = 0; (val = wl_monpromisc_level_msgs[i].value); i++) {
+ if ((promiscbitmap & val) && (val != last_val))
+ printf(" %s", wl_monpromisc_level_msgs[i].string);
+ last_val = val;
+ }
+ printf("\n");
+ return (0);
+ }
+ while (*argv) {
+ char *s = *argv;
+ if (*s == '+' || *s == '-')
+ s++;
+ else
+ promiscbitmap_del = ~0; /* make the whole list absolute */
+ val = strtoul(s, &endptr, 0);
+ if (val == 0xFFFFFFFF) {
+ fprintf(stderr,
+ "Bits >32 are not supported on this driver version\n");
+ val = 1;
+ }
+ /* not an integer if not all the string was parsed by strtoul */
+ if (*endptr != '\0') {
+ for (i = 0; (val = wl_monpromisc_level_msgs[i].value); i++)
+ if (stricmp(wl_monpromisc_level_msgs[i].string, s) == 0)
+ break;
+ if (!val)
+ goto usage;
+ }
+ if (**argv == '-')
+ promiscbitmap_del |= val;
+ else
+ promiscbitmap_add |= val;
+ ++argv;
+ }
+ promiscbitmap &= ~promiscbitmap_del;
+ promiscbitmap |= promiscbitmap_add;
+ promiscbitmap = htod32(promiscbitmap);
+ return (wlu_iovar_setint(wl, cmdname, (int)promiscbitmap));
+
+usage:
+ fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");
+ fprintf(stderr, "Use a + or - prefix to make an incremental change.");
+ for (i = 0; (val = wl_monpromisc_level_msgs[i].value); i++) {
+ if (val != last_val)
+ fprintf(stderr, "\n0x%04x %s", val, wl_monpromisc_level_msgs[i].string);
+ else
+ fprintf(stderr, ", %s", wl_monpromisc_level_msgs[i].string);
+ last_val = val;
+ }
+ fprintf(stderr, "\n");
+ return 0;
+}
+
+static int
+wl_bss_peer_info(void *wl, cmd_t *cmd, char **argv)
+{
+ bss_peer_list_info_t *info;
+ bss_peer_info_t *peer_info;
+ bss_peer_info_param_t param;
+ int err, i;
+ void *ptr;
+
+ memset(¶m, 0, sizeof(bss_peer_info_param_t));
+ param.version = htod16(BSS_PEER_INFO_PARAM_CUR_VER);
+
+ if (*++argv) {
+ if (!wl_ether_atoe(*argv, ¶m.ea)) {
+ printf(" ERROR: no valid ether addr provided\n");
+ return -1;
+ }
+ }
+
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, ¶m, sizeof(bss_peer_info_param_t),
+ &ptr)) < 0)
+ return err;
+
+ info = (bss_peer_list_info_t*)ptr;
+
+ if ((dtoh16(info->version) != BSS_PEER_LIST_INFO_CUR_VER) ||
+ (dtoh16(info->bss_peer_info_len) != sizeof(bss_peer_info_t))) {
+ printf("BSS peer info version/structure size mismatch driver %d firmware %d \r\n",
+ BSS_PEER_LIST_INFO_CUR_VER, dtoh16(info->version));
+ return -1;
+ }
+
+ if (WLC_IOCTL_MEDLEN < (BSS_PEER_LIST_INFO_FIXED_LEN +
+ (dtoh32(info->count) * sizeof(bss_peer_info_t)))) {
+ printf("ERROR : peer list received exceed the buffer size\r\n");
+ }
+
+ for (i = 0; i < (int)dtoh32(info->count); i++) {
+ peer_info = &info->peer_info[i];
+ peer_info->rateset.count = dtoh32(peer_info->rateset.count);
+ printf("PEER%d: MAC: %s: RSSI %d TxRate %d kbps RxRate %d kbps age : %ds\r\n",
+ i, wl_ether_etoa(&peer_info->ea), peer_info->rssi,
+ dtoh32(peer_info->tx_rate), dtoh32(peer_info->rx_rate),
+ dtoh32(peer_info->age));
+ printf("\t rateset ");
+ dump_rateset(peer_info->rateset.rates, peer_info->rateset.count);
+ printf("\r\n");
+ }
+
+ return 0;
+}
+
+static int
+wl_aibss_txfail_config(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = USAGE_ERROR;
+ aibss_txfail_config_t txfail_config;
+
+ if (!*++argv) {
+ memset(&txfail_config, 0, sizeof(txfail_config));
+ /* get current txfail configuration */
+ if ((ret = wlu_iovar_get(wl, cmd->name, &txfail_config,
+ sizeof(txfail_config))) < 0)
+ goto error;
+
+ printf("AIBSS TXFAIL config beacon timeout duration: %d \r\n"
+ "Max consecutive Tx failure before TXFAIL event:%d \r\n",
+ txfail_config.bcn_timeout, txfail_config.max_tx_retry);
+
+ if (txfail_config.version == AIBSS_TXFAIL_CONFIG_VER_1) {
+ printf("Max ATIM failures before TXFAIL event: %d \r\n",
+ txfail_config.max_atim_failure);
+ }
+ } else {
+ txfail_config.bcn_timeout = (uint32) strtoul(*argv, NULL, 0);
+
+
+ if (*++(argv) == NULL) {
+ printf("Incorrect number of arguments\n");
+ goto error;
+ }
+
+ txfail_config.max_tx_retry = (uint32) strtoul(*argv, NULL, 0);
+
+ if (*++(argv) == NULL) {
+ printf("Incorrect number of arguments\n");
+ goto error;
+ }
+
+ txfail_config.max_atim_failure = (uint32) strtoul(*argv, NULL, 0);
+
+ if (*++(argv)) {
+ printf("wrong extra arguments\n");
+ goto error;
+ }
+
+ txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_1;
+ txfail_config.len = sizeof(txfail_config);
+ ret = wlu_iovar_set(wl, cmd->name, (void *) &txfail_config,
+ sizeof(txfail_config));
+ }
+
+error:
+ return ret;
+}
+
+/* Returns the matching config table entry from the wl_config_iovar_list for the passed config
+ * iovar. If no matches are found, then returns the default (last) entry from the list
+ */
+static wl_config_iovar_t *get_config_iovar_entry(const char *iovar_name)
+{
+ int i = 0;
+
+ while (wl_config_iovar_list[i].iovar_name) {
+ if (!stricmp(iovar_name, wl_config_iovar_list[i].iovar_name))
+ break;
+ i++;
+ }
+
+ return &(wl_config_iovar_list[i]);
+}
+
+/* Print function for config iovar.
+ */
+static void wl_bcm_config_print(wl_config_iovar_t *cfg_iovar, wl_config_t *cfg)
+{
+ char *status_str = NULL;
+ int i = 0;
+ char *autostr = (cfg->config == (uint32) AUTO) ? "auto" : "";
+
+ while (cfg_iovar->params[i].name) {
+ if (cfg_iovar->params[i].value == cfg->status) {
+ status_str = cfg_iovar->params[i].name;
+ break;
+ }
+ i++;
+ }
+
+ if (status_str) {
+ printf("%s %d %s\n", status_str, cfg->status, autostr);
+ } else {
+ /* No matching entry found in the table. Just print the value received from
+ the driver
+ */
+ printf("%d %s\n", cfg->status, autostr);
+ }
+}
+
+int
+wl_bcm_config(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ int i = 0;
+ wl_config_iovar_t *config_iovar;
+
+ /* Get the config entry corresponding to this iovar */
+ config_iovar = get_config_iovar_entry((char *)cmd->name);
+
+ if (!config_iovar)
+ return BCME_ERROR;
+
+ if (*++argv == NULL) {
+ /* Get */
+ wl_config_t *cfg;
+ void *ptr = NULL;
+
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return err;
+
+ cfg = (wl_config_t *) ptr;
+ cfg->config = dtoh32(cfg->config);
+ cfg->status = dtoh32(cfg->status);
+
+ /* Call the iovar's print function */
+ config_iovar->pfunc(config_iovar, cfg);
+ } else {
+ /* Set */
+ char *param = *argv++;
+ bool found = 0;
+ wl_config_t cfg;
+ i = 0;
+
+ /* Check if the passed param exist in the config_iovar table */
+ while (config_iovar->params[i].name) {
+ if (!stricmp(config_iovar->params[i].name, param)) {
+ cfg.config = config_iovar->params[i].value;
+ found = 1;
+ break;
+ }
+ i++;
+ }
+
+ if (!found) {
+ /* Check if an integer value is passed as the param */
+ char *endptr = NULL;
+ cfg.config = (uint32) strtol(param, &endptr, 0);
+ if (*endptr == '\0')
+ found = 1;
+ }
+ if (!found) {
+ printf("Unsupported parameter [%s]\n", param);
+ return -1;
+ }
+
+ cfg.config = htod32(cfg.config);
+
+ err = wlu_var_setbuf(wl, cmd->name, &cfg, sizeof(wl_config_t));
+ }
+ return err;
+}
+
+/* Set or Get the "desired_bssid" ioctl
+ */
+static int
+wl_desired_bssid(void *wl, cmd_t *cmd, char **argv)
+{
+ struct ether_addr ea;
+ int error = BCME_OK;
+
+ UNUSED_PARAMETER(cmd);
+ argv++;
+
+ if (*argv == NULL) {
+ if ((error = wlu_get(wl, WLC_GET_DESIRED_BSSID, &ea, ETHER_ADDR_LEN)) < 0) {
+ return error;
+ }
+ printf("%s\n", wl_ether_etoa(&ea));
+ } else {
+ if (!wl_ether_atoe(*argv, &ea))
+ return BCME_USAGE_ERROR;
+
+ error = wlu_set(wl, WLC_SET_DESIRED_BSSID, &ea, ETHER_ADDR_LEN);
+ }
+ return error;
+}
+
+#if defined(BCMDBG) || defined(BCMDBG_DUMP)
+static int wl_dump_modesw_dyn_bwsw(void *wl, cmd_t *cmd, char **argv)
+{
+ char *ptr;
+ int err = 0;
+
+ if (*++argv != NULL) {
+ return BCME_UNSUPPORTED;
+ }
+
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, NULL, 0,
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ return err;
+ }
+
+ ptr = (char *) buf;
+ fputs(ptr, stdout);
+
+ return err;
+}
+#endif
+
+static int
+wl_dfs_channel_forced(void *wl, cmd_t *cmd, char **argv)
+{
+ uint i;
+ int err = -1;
+ char *p;
+ chanspec_t chanspec;
+ wl_dfs_forced_t *dfs_frcd;
+ wl_dfs_forced_t inp;
+ uint32 ioctl_size;
+
+ dfs_frcd = (wl_dfs_forced_t *)buf;
+ memset(buf, 0, WL_DFS_FORCED_PARAMS_MAX_SIZE);
+ memset(&inp, 0, sizeof(wl_dfs_forced_t));
+
+ /* Get the existing configuration first. We need this for
+ * set operations also
+ */
+ inp.version = DFS_PREFCHANLIST_VER;
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, &inp, sizeof(wl_dfs_forced_t),
+ dfs_frcd, WL_DFS_FORCED_PARAMS_MAX_SIZE)) < 0) {
+ return err;
+ }
+
+ if (!argv[1]) {
+ /* Get Operation */
+ char chanbuf[CHANSPEC_STR_LEN];
+ /* List configuration shouldn't be there if we are operating on
+ * old version of driver
+ */
+ if ((dfs_frcd->version == DFS_PREFCHANLIST_VER) && (dfs_frcd->chspec_list.num)) {
+ printf("DFS Preferred channel list:: \n");
+ for (i = 0; i < dfs_frcd->chspec_list.num; i++) {
+ chanspec =
+ wl_chspec32_from_driver(dfs_frcd->chspec_list.list[i]);
+ /* wf_chspec_ntoa will return NULL when N mode is disabled */
+ if (wf_chspec_ntoa(chanspec, chanbuf))
+ printf("%s(0x%x) ", chanbuf, chanspec);
+ else
+ printf("(0x%x) ", chanspec);
+ }
+ printf("\n");
+ } else {
+ if (dfs_frcd->version == DFS_PREFCHANLIST_VER) {
+ /* Not configured since new driver works on list */
+ printf("DFS Preferred Channel:: 0x0 (None)\n");
+ } else {
+ chanspec = wl_chspec32_from_driver(dfs_frcd->chspec);
+ /* wf_chspec_ntoa will return NULL when N mode is disabled */
+ if (chanspec && wf_chspec_ntoa(chanspec, chanbuf)) {
+ printf("DFS Preferred Channel:: %s (0x%x)\n",
+ chanbuf, chanspec);
+ } else {
+ printf("DFS Preferred Channel:: 0x%x\n", chanspec);
+ }
+ }
+ }
+ return err;
+ }
+ if (!strcmp(argv[1], "-l")) {
+ /* List configuration */
+ if (!argv[2]) {
+ printf("Please provide channel list\n");
+ err = BCME_USAGE_ERROR;
+ return err;
+ }
+
+ if (dfs_frcd->version != DFS_PREFCHANLIST_VER) {
+ printf("List Configuration is not supported in this version of driver\n");
+ return err;
+ }
+ p = strtok(argv[2], ", ");
+ while (p) {
+ if ((*p != '+') && (*p != '-')) {
+ printf("channel should be prefixed with +/-\n");
+ err = BCME_USAGE_ERROR;
+ return err;
+ }
+ if (!(chanspec = wf_chspec_aton(p + 1))) {
+ printf("Invalid channel specified\n");
+ err = BCME_USAGE_ERROR;
+ return err;
+ }
+ if (!CHSPEC_IS5G(chanspec)) {
+ printf("Invalid channel specified\n");
+ err = BCME_USAGE_ERROR;
+ return err;
+ }
+ dfs_frcd->chspec = 0;
+ if (*p == '+') {
+ /* check if exists */
+ for (i = 0; i < dfs_frcd->chspec_list.num; i++) {
+ if (chanspec == dfs_frcd->chspec_list.list[i]) {
+ printf("Ignoring chanspec 0x%x\n", chanspec);
+ goto next_token;
+ }
+ }
+ chanspec = wl_chspec32_to_driver(chanspec);
+ dfs_frcd->chspec_list.list[dfs_frcd->chspec_list.num++] = chanspec;
+ } else if (*p == '-') {
+ /* check if exists */
+ for (i = 0; i < dfs_frcd->chspec_list.num; i++) {
+ if (chanspec == dfs_frcd->chspec_list.list[i]) {
+ dfs_frcd->chspec_list.num--;
+ break;
+ }
+ }
+ while (i < dfs_frcd->chspec_list.num) {
+ dfs_frcd->chspec_list.list[i] =
+ dfs_frcd->chspec_list.list[i+1];
+ i++;
+ }
+ }
+next_token:
+ p = strtok(NULL, ", ");
+ }
+ if (dfs_frcd->chspec_list.num > WL_NUMCHANNELS) {
+ printf("Maximum %d channels supported\n", WL_NUMCHANNELS);
+ err = BCME_USAGE_ERROR;
+ return err;
+ }
+ ioctl_size = WL_DFS_FORCED_PARAMS_FIXED_SIZE +
+ (dfs_frcd->chspec_list.num * sizeof(chanspec_t));
+ dfs_frcd->version = DFS_PREFCHANLIST_VER;
+ err = wlu_iovar_set(wl, cmd->name, dfs_frcd, ioctl_size);
+ } else {
+ /* No list provided. Either single channel or clear list */
+ if (dfs_frcd->version == DFS_PREFCHANLIST_VER) {
+ /* Clear configuration */
+ dfs_frcd->chspec = 0;
+ dfs_frcd->chspec_list.num = 0;
+
+ ioctl_size = WL_DFS_FORCED_PARAMS_FIXED_SIZE +
+ (dfs_frcd->chspec_list.num * sizeof(chanspec_t));
+ err = wlu_iovar_set(wl, cmd->name, dfs_frcd, ioctl_size);
+ }
+ /* Single channel configuration. Continue as we were doing earlier */
+ if (strcmp(argv[1], "0"))
+ err = wl_chanspec(wl, cmd, argv);
+ }
+ return err;
+}
+#ifdef WIN32
+#pragma warning(pop)
+#endif
+
+static int
+wl_setiproute(void *wl, cmd_t *cmd, char **argv)
+{
+ uint route_tbl_len;
+ wlc_ipfo_route_tbl_t *route_tbl = NULL;
+ uint32 entries;
+ char *endptr;
+ uint32 i = 0;
+ struct ipv4_addr dipaddr;
+ struct ether_addr ea;
+ int argc;
+ int ret = BCME_OK;
+ int buflen = sprintf(buf, "%s", *argv) + 1;
+
+ UNUSED_PARAMETER(cmd);
+ argv++;
+ route_tbl_len = WL_IPFO_ROUTE_TBL_FIXED_LEN +
+ WL_MAX_IPFO_ROUTE_TBL_ENTRY * sizeof(wlc_ipfo_route_entry_t);
+
+ /* allocate the max storage */
+ if ((route_tbl = malloc(route_tbl_len)) == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for route table\n", route_tbl_len);
+ return BCME_NOMEM;
+ }
+
+ memset(route_tbl, 0, route_tbl_len);
+
+ if (*argv == NULL) {
+ if ((ret = wlu_iovar_get(wl, buf, route_tbl, route_tbl_len)) == BCME_OK) {
+ if (route_tbl->num_entry == 0) {
+ printf("No entries present\n");
+ } else {
+ for (i = 0; i < route_tbl->num_entry; i++) {
+ printf("entry%d", i);
+ printf("\t%s",
+ wl_iptoa(&route_tbl->route_entry[i].ip_addr));
+ printf("\t%s\n",
+ wl_ether_etoa(&route_tbl->route_entry[i].nexthop));
+ }
+ }
+ }
+ } else {
+
+ argc = ARGCNT(argv);
+
+ if (argc <= 0)
+ goto usage;
+
+ entries = strtoul(argv[0], &endptr, 0);
+
+ if (*endptr != '\0')
+ goto usage;
+
+ if ((uint32)argc != (entries * 2 + 1))
+ goto usage;
+
+ route_tbl->num_entry = entries;
+ argv++;
+
+ for (i = 0; i < entries; i++) {
+ if (!wl_atoip(argv[i*2], &dipaddr))
+ goto usage;
+
+ if (!wl_ether_atoe(argv[(i * 2 + 1)], &ea))
+ goto usage;
+
+ memcpy(&route_tbl->route_entry[i].ip_addr, &dipaddr, IPV4_ADDR_LEN);
+ memcpy(&route_tbl->route_entry[i].nexthop, &ea, ETHER_ADDR_LEN);
+ }
+ route_tbl_len = (entries * sizeof(wlc_ipfo_route_entry_t)) + IPV4_ADDR_LEN;
+ memcpy(&buf[buflen], route_tbl, route_tbl_len);
+ ret = wlu_set(wl, WLC_SET_VAR, &buf[0], buflen + route_tbl_len);
+ }
+
+ free(route_tbl);
+ return ret;
+
+usage:
+ fprintf(stderr, "wrong command format\n");
+ if (route_tbl != NULL)
+ free(route_tbl);
+ return ret;
+}
+
+static int
+wl_modesw_timecal(void *wl, cmd_t *cmd, char **argv)
+{
+ int val;
+ int err = 0;
+ char *ptr = NULL;
+ if (*++argv == NULL) {
+ /* retrieving the results */
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, NULL, 0,
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ return err;
+ }
+ ptr = buf;
+ fputs(ptr, stdout);
+ }
+ else
+ {
+ val = htod32(atoi(*argv));
+ if ((err = wlu_iovar_setbuf(wl, cmd->name, &val, sizeof(val),
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ return err;
+ }
+ }
+ return err;
+}
+
+static int
+wl_pcie_bus_throughput_params(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0, opt_err;
+ miniopt_t to;
+ pcie_bus_tput_params_t *params = NULL;
+ pcie_bus_tput_stats_t *stats = NULL;
+ UNUSED_PARAMETER(cmd);
+
+ argv++; /* toss the command name */
+ if (!*argv) { /* Get the pcie bus throughput stats */
+ void *ptr = NULL;
+ uint32 tput = 0;
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) {
+ fprintf(stderr, "Failed to get stats.\n");
+ return err;
+ }
+ stats = (pcie_bus_tput_stats_t *)ptr;
+ if (stats->count) {
+ tput = (stats->count * stats->nbytes_per_descriptor) /
+ stats->time_taken;
+ tput = (tput * 8) / (1024 * 1024); /* convert to Mega bits */
+ fprintf(stdout, "Seconds test run %d\nNo of dma completed %d\n"
+ "Bytes transfered per dma %d\nBus throughput: %d mbps\n",
+ stats->time_taken, stats->count,
+ stats->nbytes_per_descriptor, tput);
+ }
+ }
+ if (*argv) { /* Set the bus throughput params */
+ params = (pcie_bus_tput_params_t *)malloc(sizeof(pcie_bus_tput_params_t));
+ if (params == NULL) {
+ fprintf(stderr, "Failed to allocate buffer.\n");
+ return BCME_NOMEM;
+ }
+ memset(params, 0, sizeof(*params));
+
+ miniopt_init(&to, __FUNCTION__, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ argv += to.consumed;
+ if (to.opt == 'n') {
+ if (!to.good_int) {
+ fprintf(stderr, "%s: could not parse \"%s\" as an int for"
+ " max_dma_descriptors \n", __FUNCTION__, to.valstr);
+ err = BCME_BADARG;
+ goto fail;
+ }
+ params->max_dma_descriptors = to.val;
+ }
+ }
+
+ if (params->max_dma_descriptors == 0)
+ params->max_dma_descriptors = 64; /* set default as 64 */
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, params,
+ sizeof(*params)) < 0)) {
+ fprintf(stderr, "failed to trigger measurement %d\n", err);
+ }
+ }
+fail:
+ if (params)
+ free(params);
+ return err;
+}
+
+static int
+wl_interface_create_action(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_interface_create_t wlif;
+ wl_interface_info_t *pwlif_info;
+ int count, val;
+ int err;
+ char opt, *p, *valstr, *endptr = NULL;
+
+ memset(&wlif, 0, sizeof(wlif));
+ wlif.ver = WL_INTERFACE_CREATE_VER;
+
+ argv++;
+ count = ARGCNT(argv);
+
+ /*
+ * We should have atleast one argument for the create command,
+ * whether to start it as AP or STA.
+ */
+ if (count < 1)
+ return BCME_USAGE_ERROR;
+ /*
+ * First Argument:
+ * Find the interface that user need to create and update the flag/iftype
+ * flags field is still used along with iftype inorder to support the old version of the
+ * FW work with the latest app changes.
+ */
+ if (stricmp(argv[0], "sta") == 0) {
+ wlif.iftype = WL_INTERFACE_TYPE_STA;
+ wlif.flags |= WL_INTERFACE_CREATE_STA;
+ } else if (stricmp(argv[0], "ap") == 0) {
+ wlif.iftype = WL_INTERFACE_TYPE_AP;
+ wlif.flags |= WL_INTERFACE_CREATE_AP;
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+
+ while ((p = *argv) != NULL) {
+ argv++;
+ opt = '\0';
+ valstr = NULL;
+
+ if (!strncmp(p, "-", 1)) {
+ opt = p[1];
+ if (strlen(p) > 2) {
+ fprintf(stderr,
+ "%s: only single char options, error on param \"%s\"\n",
+ __FUNCTION__, p);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (*argv == NULL) {
+ fprintf(stderr,
+ "%s: missing value parameter after \"%s\"\n",
+ __FUNCTION__, p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ valstr = *argv;
+ argv++;
+ } else {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ /* The mac address is optional, if its passed and valid use it. */
+ if (opt == 'm') {
+ if (wl_ether_atoe(valstr, &wlif.mac_addr)) {
+ wlif.flags |= WL_INTERFACE_MAC_USE;
+ }
+ }
+
+ /* The wlc_index is optional, if its passed and valid use it. */
+ if (opt == 'c') {
+ /* parse valstr as int */
+ val = (int)strtol(valstr, &endptr, 0);
+ if (*endptr == '\0') {
+ wlif.flags |= WL_INTERFACE_WLC_INDEX_USE;
+ wlif.wlc_index = val;
+ } else {
+ fprintf(stderr,
+ "wl_interface_create_action: could not parse \"%s\" as an int",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+ }
+
+
+ err = wlu_var_getbuf(wl, cmd->name, &wlif, sizeof(wlif), (void *)&pwlif_info);
+ if (err < 0) {
+ printf("%s(): wlu_var_getbuf failed %d \r\n", __FUNCTION__, err);
+ } else {
+ printf("ifname: %s bsscfgidx: %d mac_addr %s\r\n",
+ pwlif_info->ifname, pwlif_info->bsscfgidx,
+ wl_ether_etoa(&pwlif_info->mac_addr));
+ }
+
+exit:
+ return err;
+}
+
+static int
+wl_interface_remove_action(void *wl, cmd_t *cmd, char **argv)
+{
+ int bsscfg_idx = 0;
+ int consumed;
+ int error;
+
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((error = wl_cfg_option(argv, "interface_remove", &bsscfg_idx, &consumed)) != 0)
+ return error;
+
+ argv += consumed;
+
+ /*
+ * This command supports both "bss" method and "-i" method. First
+ * check if "bss" options is present, and if yes, use the index
+ * otherwise use the normal path.
+ */
+ if (consumed != 0)
+ error = wl_bssiovar_set(wl, "interface_remove", bsscfg_idx, NULL, 0);
+ else
+ error = wlu_var_setbuf(wl, cmd->name, NULL, 0);
+
+ return error;
+}
+
+static int
+wl_phy_txpwrcap_tbl(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_txpwrcap_tbl_t txpwrcap_tbl;
+ wl_txpwrcap_tbl_t *txpwrcap_tbl_ptr;
+ uint8 num_antennas = 0;
+
+ void *ptr = NULL;
+ int err = 0;
+ uint8 i, j, k;
+
+ if (!(*++argv)) { /* Get */
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return err;
+ txpwrcap_tbl_ptr = ptr;
+
+ for (i = 0; i < TXPWRCAP_MAX_NUM_CORES; i++) {
+ if (txpwrcap_tbl_ptr->num_antennas_per_core[i]) {
+ printf("Num Antennas on Core %d = %d\n",
+ i, txpwrcap_tbl_ptr->num_antennas_per_core[i]);
+ num_antennas += txpwrcap_tbl_ptr->num_antennas_per_core[i];
+ }
+ }
+
+ printf("Pwr Caps with Cell On:\n");
+ for (i = 0; i < num_antennas; i++) {
+ printf("\t%d", txpwrcap_tbl_ptr->pwrcap_cell_on[i]);
+ }
+ printf("\n");
+
+
+ printf("Pwr Caps with Cell Off:\n");
+ for (i = 0; i < num_antennas; i++) {
+ printf("\t%d", txpwrcap_tbl_ptr->pwrcap_cell_off[i]);
+ }
+ printf("\n");
+
+ return err;
+ } else { /* Set */
+ txpwrcap_tbl.num_antennas_per_core[0] = strtol(*argv, NULL, 0);
+ num_antennas = txpwrcap_tbl.num_antennas_per_core[0];
+
+ for (i = 1; i < TXPWRCAP_MAX_NUM_CORES; i++) {
+ if (*++argv) {
+ txpwrcap_tbl.num_antennas_per_core[i] = strtol(*argv, NULL, 0);
+ num_antennas += txpwrcap_tbl.num_antennas_per_core[i];
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ if (*++argv) {
+ memset(txpwrcap_tbl.pwrcap_cell_on, 127,
+ TXPWRCAP_MAX_NUM_ANTENNAS *
+ sizeof(txpwrcap_tbl.pwrcap_cell_on[0]));
+ memset(txpwrcap_tbl.pwrcap_cell_off, 127,
+ TXPWRCAP_MAX_NUM_ANTENNAS *
+ sizeof(txpwrcap_tbl.pwrcap_cell_off[0]));
+
+ i = 0;
+ j = 0;
+ k = 0;
+ do {
+ if (k >= 2 * num_antennas) {
+ printf("Entries exceeded max allowed\n");
+ return BCME_ERROR;
+ }
+ if (k >= num_antennas)
+ txpwrcap_tbl.pwrcap_cell_off[j++] = strtoul(*argv, NULL, 0);
+ else
+ txpwrcap_tbl.pwrcap_cell_on[i++] = strtoul(*argv, NULL, 0);
+ k++;
+ } while (*++argv);
+
+ if ((k != 2* num_antennas) &&
+ (k != num_antennas)) {
+ printf("Incorrect Number of Entries. Expected %d/%d, Entered %d\n",
+ num_antennas, 2 * num_antennas, k);
+ return BCME_ERROR;
+ }
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, &txpwrcap_tbl,
+ sizeof(txpwrcap_tbl))) < 0) {
+ printf("Unable to set the txpwrcaps.\n");
+ printf("Check number of antennas for this board.\n");
+ return BCME_ERROR;
+ }
+ }
+ else
+ return BCME_USAGE_ERROR;
+
+ }
+ return err;
+}
+
+
+/*
+ * Get Beacon Trim Stats
+ * wl bcntrim_stats
+ */
+static int
+wl_bcntrim_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ uint16 op_buffer[BCNTRIMST_NUM];
+
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+
+ if (*argv == NULL) {
+ if ((err = wlu_iovar_get(wl, cmd->name, (void *) op_buffer,
+ (BCNTRIMST_NUM * 2))) < 0)
+ return (err);
+
+ printf("- Beacon Trim Statistics -\n");
+ printf("BCNTRIM_PER : %d\n", op_buffer[BCNTRIMST_PER]);
+ printf("BCNTRIM_TIMEND : %d\n", op_buffer[BCNTRIMST_TIMEND]);
+ printf("BCNTRIM_TSFLMT : %d\n", op_buffer[BCNTRIMST_TSFLMT]);
+
+ printf("BCNTRIM_CUR : %d\n", op_buffer[BCNTRIMST_CUR]);
+ printf("BCNTRIM_PREVLEN : %d\n", op_buffer[BCNTRIMST_PREVLEN]);
+ printf("BCNTRIM_TIMLEN : %d\n", op_buffer[BCNTRIMST_TIMLEN]);
+ printf("BCNTRIM_RSSI : %d\n", op_buffer[BCNTRIMST_RSSI]);
+ printf("BCNTRIM_CHAN : %d\n", op_buffer[BCNTRIMST_CHAN]);
+
+ printf("BCNTRIM_DUR : %d\n", op_buffer[BCNTRIMST_DUR]);
+ printf("BCNTRIM_RXMBSS : %d\n", op_buffer[BCNTRIMST_RXMBSS]);
+ printf("BCNTRIM_CANTRIM : %d\n", op_buffer[BCNTRIMST_CANTRIM]);
+ printf("BCNTRIM_LENCHG : %d\n", op_buffer[BCNTRIMST_LENCHG]);
+ printf("BCNTRIM_TSFDRF : %d\n", op_buffer[BCNTRIMST_TSFDRF]);
+ printf("BCNTRIM_NOTIM : %d\n", op_buffer[BCNTRIMST_NOTIM]);
+ } else {
+ /* Set not supported */
+ return USAGE_ERROR;
+ }
+ return err;
+}
+
+#ifdef ATE_BUILD
+static int
+wl_gpaio(void *wl, cmd_t *cmd, char **argv)
+{
+ char **p = argv;
+ int counter = 0;
+ wl_gpaio_option_t option;
+ BCM_REFERENCE(cmd);
+ while (*p) {
+ counter++;
+ p++;
+ }
+ if (counter != 2) {
+ return USAGE_ERROR;
+ }
+ if (strcmp("pmu_afeldo", argv[1]) == 0) {
+ option = GPAIO_PMU_AFELDO;
+ } else if (strcmp("pmu_txldo", argv[1]) == 0) {
+ option = GPAIO_PMU_TXLDO;
+ } else if (strcmp("pmu_vcoldo", argv[1]) == 0) {
+ option = GPAIO_PMU_VCOLDO;
+ } else if (strcmp("pmu_lnaldo", argv[1]) == 0) {
+ option = GPAIO_PMU_LNALDO;
+ } else if (strcmp("pmu_adcldo", argv[1]) == 0) {
+ option = GPAIO_PMU_ADCLDO;
+ } else if (strcmp("clear", argv[1]) == 0) {
+ option = GPAIO_PMU_CLEAR;
+ } else {
+ return USAGE_ERROR;
+ }
+ return (wlu_iovar_setint(wl, argv[0], (int)option));
+}
+#endif /* ATE_BUILD */
+
+
+static int
+wl_macdbg_pmac(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_macdbg_pmac_param_t pmac;
+ int err = BCME_OK;
+ char *p, opt;
+ char *retbuf;
+
+ memset(&pmac, 0, sizeof(pmac));
+ retbuf = malloc(WL_DUMP_BUF_LEN);
+ if (retbuf == NULL) {
+ printf("No memory to allocate return buffer\n");
+ return BCME_NOMEM;
+ }
+
+ /* skip the command name */
+ argv++;
+
+ /* Get the selection */
+ if ((p = *argv) == NULL) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ strncpy(pmac.type, p, MIN(strlen(p), sizeof(pmac.type)));
+ pmac.type[sizeof(pmac.type) - 1] = '\0';
+ /* skip the type */
+ argv++;
+
+ pmac.step = (uint8)(-1);
+ pmac.num = 0;
+ pmac.bitmap = 0;
+ pmac.addr_raw = FALSE;
+ pmac.w_en = FALSE;
+
+ while ((p = *argv)) {
+ argv++;
+ if (!strncmp(p, "-", 1)) {
+ if (strlen(p) > 2 || (p[1] != 'r' && *argv == NULL)) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ opt = p[1];
+
+ switch (opt) {
+ case 's':
+ pmac.step = strtol(*argv, NULL, 0);
+ argv++;
+ break;
+ case 'n':
+ pmac.num = strtol(*argv, NULL, 0);
+ argv++;
+ break;
+ case 'b':
+ pmac.bitmap = strtoul(*argv, NULL, 0);
+ argv++;
+ break;
+ case 'r':
+ pmac.addr_raw = TRUE;
+ break;
+ case 'w':
+ pmac.w_val = strtoul(*argv, NULL, 0);
+ pmac.w_en = TRUE;
+ argv++;
+ break;
+ default:
+ printf("Invalid option!!\n");
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ } else {
+ pmac.addr[pmac.addr_num++] = strtol(p, NULL, 0);
+ if (pmac.addr_num >= MACDBG_PMAC_ADDR_INPUT_MAXNUM) {
+ printf("Reached input limitation!!\n");
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ }
+
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, &pmac,
+ sizeof(pmac), retbuf, WL_DUMP_BUF_LEN) < 0)) {
+ goto exit;
+ }
+
+ if (!pmac.w_en) {
+ fputs(retbuf, stdout);
+ }
+exit:
+ if (retbuf) {
+ free(retbuf);
+ }
+ return err;
+}
+
+static int wl_mu_rate(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ uint32 i = 0;
+ char *endptr = NULL;
+ mu_rate_t mu;
+ BCM_REFERENCE(cmd);
+
+ memset(&mu, 0x0, sizeof(mu));
+ if (!argv[1]) {
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, NULL,
+ 0, &mu, sizeof(mu))) < 0) {
+ fprintf(stderr, "Error reading svmp memory %s %d\n", argv[0], err);
+ goto exit;
+ }
+
+ for (i = 0; i < 4; i++) {
+ printf("0x%04x ", mu.rate_user[i]);
+ }
+ printf("%s\n", mu.auto_rate ? "(Auto)" : "(Fixed)");
+ return err;
+ }
+
+ /* auto rate */
+ if (!stricmp(argv[1], "auto") || (!stricmp(argv[1], "-1"))) {
+ /* turn on auto rate */
+ /* wl svmp_mem 0x20060 1 0 */
+ mu.auto_rate = 1;
+ err = wlu_var_setbuf(wl, cmd->name, &mu, sizeof(mu));
+ } else {
+ for (i = 0; i < 4; i++) {
+ mu.rate_user[i] = 0xffff;
+ }
+
+ /* set rates */
+ mu.auto_rate = 0;
+ for (i = 1; i < 5; i++) {
+ if (!argv[i])
+ break;
+
+ mu.rate_user[i-1] = strtol(argv[i], &endptr, 0);
+ }
+
+ err = wlu_var_setbuf(wl, cmd->name, &mu, sizeof(mu));
+
+ /* barf if set mu_rate but blocked by mu_group */
+ if (err != BCME_OK) {
+ printf("Set fix rate failed!!!\n");
+ printf("Check if blocked by mu_group setting or other error\n");
+ }
+ }
+
+exit:
+ return err;
+}
+
+static int wl_mu_group(void *wl, cmd_t *cmd, char **argv)
+{
+ int m, n, ret = 0;
+ int16 temp;
+
+ mu_group_t mu_group;
+
+ mu_group.version = WL_MU_GROUP_PARAMS_VERSION;
+ mu_group.forced = WL_MU_GROUP_ENTRY_EMPTY;
+ mu_group.forced_group_mcs = WL_MU_GROUP_ENTRY_EMPTY;
+ mu_group.forced_group_num = 0;
+ mu_group.auto_group_num = 0;
+ mu_group.group_method = WL_MU_GROUP_ENTRY_EMPTY;
+ mu_group.group_number = WL_MU_GROUP_ENTRY_EMPTY;
+ for (m = 0; m < WL_MU_GROUP_NGROUP_MAX; m++) {
+ for (n = 0; n < WL_MU_GROUP_NUSER_MAX; n++) {
+ mu_group.group_option[m][n] = WL_MU_GROUP_ENTRY_EMPTY;
+ }
+ mu_group.group_GID[m] = WL_MU_GROUP_ENTRY_EMPTY;
+ }
+
+ if (!argv[1]) {
+ /* read mode */
+ ret = wlu_iovar_getbuf(wl, cmd->name, NULL, 0, &mu_group, sizeof(mu_group));
+ if (mu_group.version != WL_MU_GROUP_PARAMS_VERSION) {
+ printf("\tIncorrect version "
+ "of mu_group struct: expect %d but get %d\n",
+ WL_MU_GROUP_PARAMS_VERSION, mu_group.version);
+ return BCME_BADARG;
+ }
+ printf("mu_group: ");
+ if (mu_group.forced == WL_MU_GROUP_MODE_FORCED) {
+ if (mu_group.forced_group_mcs == WL_MU_GROUP_MODE_FORCED) {
+ printf("forced (fixed MCS)\n");
+ } else {
+ printf("forced (auto MCS)\n");
+ }
+ for (m = 0; m < mu_group.forced_group_num; m++) {
+ printf(" Group %d: ", m);
+ for (n = 0; n < WL_MU_GROUP_NUSER_MAX; n++) {
+ if (mu_group.group_option[m][n]
+ != WL_MU_GROUP_ENTRY_EMPTY) {
+ printf("0x%03x ",
+ mu_group.group_option[m][n]);
+ }
+ }
+ printf("\n");
+ }
+ } else {
+ printf("auto\n");
+ printf("VASIP grouping method: ");
+ if (mu_group.group_method > 0) {
+ printf("new method %d (%s)\n",
+ mu_group.group_method, mu_group.group_method_name);
+ } else {
+ printf("old method ");
+ printf("(one group for all admitted users with GID=9)\n");
+ }
+ printf(" group number: %d\n", mu_group.group_number);
+ if (mu_group.auto_group_num > 0) {
+ printf("Latest recommended groups:\n");
+ }
+ for (m = 0; m < mu_group.auto_group_num; m++) {
+ printf(" Group %d: ", m);
+ for (n = 0; n < WL_MU_GROUP_NUSER_MAX; n++) {
+ if (mu_group.group_option[m][n]
+ != WL_MU_GROUP_ENTRY_EMPTY) {
+ printf("0x%03x ",
+ mu_group.group_option[m][n]);
+ } else {
+ printf(" --- ");
+ }
+ }
+ printf("(GID=%d)\n", mu_group.group_GID[m]);
+ }
+
+ }
+ } else {
+ argv++;
+ do {
+ char *s = *argv++;
+ if (!strcmp(s, "-h")) {
+ ret = BCME_USAGE_ERROR;
+ goto exit_mu_group;
+ } else if (!strcmp(s, "-m")) {
+ mu_group.group_method = (int16)strtol(*argv++, NULL, 0);
+ if (mu_group.group_method < WL_MU_GROUP_METHOD_MIN) {
+ ret = BCME_USAGE_ERROR;
+ printf("Incorrect -m: M<%d\n", WL_MU_GROUP_METHOD_MIN);
+ goto exit_mu_group;
+ }
+ } else if (!strcmp(s, "-n")) {
+ mu_group.group_number = (int16)strtol(*argv++, NULL, 0);
+ if ((mu_group.group_number < WL_MU_GROUP_NUMBER_AUTO_MIN) ||
+ (mu_group.group_number >
+ WL_MU_GROUP_NUMBER_AUTO_MAX)) {
+ ret = BCME_USAGE_ERROR;
+ printf("Incorrect '-n': N is not in the range %d~%d\n",
+ WL_MU_GROUP_NUMBER_AUTO_MIN,
+ WL_MU_GROUP_NUMBER_AUTO_MAX);
+ goto exit_mu_group;
+ }
+ } else if (!strcmp(s, "-f")) {
+ temp = (int)strtol(*argv++, NULL, 0);
+ if ((temp == WL_MU_GROUP_MODE_AUTO) ||
+ (temp == WL_MU_GROUP_MODE_FORCED)) {
+ mu_group.forced_group_mcs = temp;
+ }
+ } else if ((!strcmp(s, "-g")) && (mu_group.forced != 0)) {
+ temp = (int)strtol(*argv++, NULL, 0);
+ if (temp == WL_MU_GROUP_AUTO_COMMAND) {
+ mu_group.forced = WL_MU_GROUP_MODE_AUTO;
+ mu_group.forced_group_num = 0;
+ } else if ((temp < WL_MU_GROUP_NUMBER_FORCED_MAX) &&
+ (temp == mu_group.forced_group_num)) {
+ mu_group.forced = WL_MU_GROUP_MODE_FORCED;
+ mu_group.forced_group_num += 1;
+ m = temp;
+ n = 0;
+ } else {
+ ret = BCME_USAGE_ERROR;
+ printf("Incorrect to set froced group options: ");
+ if (temp != mu_group.forced_group_num) {
+ printf("group index should be successive\n");
+ }
+ if (mu_group.forced_group_num >=
+ WL_MU_GROUP_NUMBER_FORCED_MAX) {
+ printf("support up to %d forced options\n",
+ WL_MU_GROUP_NUMBER_FORCED_MAX);
+ }
+ goto exit_mu_group;
+ }
+ } else if (((mu_group.forced_group_num > 0)) && (n < 4)) {
+ mu_group.group_option[m][n] = (int16)strtol(s, NULL, 0);
+ n += 1;
+ }
+ } while (*argv);
+
+ if ((mu_group.forced == WL_MU_GROUP_MODE_FORCED) &&
+ ((mu_group.group_method != WL_MU_GROUP_ENTRY_EMPTY) ||
+ (mu_group.group_number != WL_MU_GROUP_ENTRY_EMPTY))) {
+ ret = BCME_USAGE_ERROR;
+ printf("Incorrect to set forced grouping options "
+ "with auto grouping parameters\n");
+ goto exit_mu_group;
+ }
+
+ /* default is forced mcs for forced grouping */
+ /* if not specified forced_group_mcs when forced grouping, set forced_group_mcs=1 */
+ if ((mu_group.forced == WL_MU_GROUP_MODE_FORCED) &&
+ (mu_group.forced_group_mcs == WL_MU_GROUP_ENTRY_EMPTY)) {
+ mu_group.forced_group_mcs = WL_MU_GROUP_MODE_FORCED;
+ }
+
+ /* set mode */
+ ret = wlu_var_setbuf(wl, cmd->name, &mu_group, sizeof(mu_group));
+ }
+
+exit_mu_group:
+ return ret;
+}
+
+static int wl_mu_policy(void *wl, cmd_t *cmd, char **argv)
+{
+ mu_policy_t policy;
+ int err = -1;
+ uint32 val;
+
+ memset(&policy, 0, sizeof(mu_policy_t));
+ policy.version = WL_MU_POLICY_PARAMS_VERSION;
+ policy.length = sizeof(mu_policy_t);
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, NULL, 0, &policy, sizeof(mu_policy_t))) < 0) {
+ return err;
+ }
+ /* Check the iovar version */
+ if (policy.version != WL_MU_POLICY_PARAMS_VERSION) {
+ err = BCME_BADARG;
+ goto exit_mu_policy;
+ }
+ if (!argv[1]) {
+ /* read mode */
+ printf("Current MU policy settings:\n");
+ printf(" scheduler: %s", policy.sched_timer? "ON":"OFF");
+ if (policy.sched_timer)
+ printf(", timer: %u seconds\n", policy.sched_timer);
+ else
+ printf(" \n");
+ printf(" performance monitors: %s\n", policy.pfmon? "ON":"OFF");
+ printf(" gpos performance monitors: %s\n", policy.pfmon_gpos? "ON":"OFF");
+ printf(" forced the same BW check: %s\n", policy.samebw? "ON":"OFF");
+ printf(" max number of rx streams in the clients: %u\n", policy.nrx);
+ printf(" max number of admitted clients: %u\n", policy.max_muclients);
+ } else {
+ argv++;
+ do {
+ char *s = *argv++;
+ if (!strcmp(s, "-h")) {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ } else if (!strcmp(s, "-sched_timer")) {
+ if (!*argv) {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ }
+ val = strtoul(*argv++, NULL, 0);
+ policy.sched_timer = val;
+ } else if (!strcmp(s, "-pfmon")) {
+ if (!*argv) {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ }
+ val = strtoul(*argv++, NULL, 0);
+ if ((val == WL_MU_POLICY_DISABLED) ||
+ (val == WL_MU_POLICY_ENABLED)) {
+ policy.pfmon = val;
+ } else {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ }
+ } else if (!strcmp(s, "-pfmon_gpos")) {
+ if (!*argv) {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ }
+ val = strtoul(*argv++, NULL, 0);
+ if ((val == WL_MU_POLICY_DISABLED) ||
+ (val == WL_MU_POLICY_ENABLED)) {
+ policy.pfmon_gpos = val;
+ } else {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ }
+ } else if (!strcmp(s, "-samebw")) {
+ if (!*argv) {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ }
+ val = strtoul(*argv++, NULL, 0);
+ if ((val == WL_MU_POLICY_DISABLED) ||
+ (val == WL_MU_POLICY_ENABLED)) {
+ policy.samebw = val;
+ } else {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ }
+ } else if (!strcmp(s, "-nrx")) {
+ if (!*argv) {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ }
+ val = strtoul(*argv++, NULL, 0);
+ if ((val >= WL_MU_POLICY_NRX_MIN) &&
+ (val <= WL_MU_POLICY_NRX_MAX)) {
+ policy.nrx = val;
+ } else {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ }
+ } else if (!strcmp(s, "-max_muclients")) {
+ if (!*argv) {
+ err = BCME_USAGE_ERROR;
+ goto exit_mu_policy;
+ }
+ val = strtoul(*argv++, NULL, 0);
+ policy.max_muclients = val;
+ }
+ } while (*argv);
+
+ /* set mode */
+ err = wlu_var_setbuf(wl, cmd->name, &policy, sizeof(policy));
+ }
+
+exit_mu_policy:
+ return err;
+}
+
+static int wl_svmp_mem(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ svmp_mem_t mem;
+ uint16 *svmp_buf;
+ uint32 i;
+ char *endptr = NULL;
+
+ if (!argv[1]) {
+ fprintf(stderr, "Too few arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ mem.addr = strtol(argv[1], &endptr, 0);
+
+ if (!argv[2]) {
+ fprintf(stderr, "%s: Length must be specified\n", cmd->name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ mem.len = strtol(argv[2], &endptr, 0);
+
+ if (argv[3]) {
+ mem.val = strtol(argv[3], &endptr, 0);
+ err = wlu_var_setbuf(wl, cmd->name, &mem, sizeof(mem));
+ goto exit;
+ }
+
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, &mem,
+ sizeof(mem), buf, WLC_IOCTL_MAXLEN)) < 0) {
+ fprintf(stderr, "Error reading svmp memory %s %d\n", argv[0], err);
+ goto exit;
+ }
+
+ svmp_buf = (uint16 *)buf;
+ for (i = 0; i < mem.len; i++) {
+ if (!(i&1) && (i+1 < mem.len))
+ printf("0x%04x", svmp_buf[i+1]);
+ else {
+ if ((i%2 != 0) || (i+1 < mem.len))
+ printf("%04x", svmp_buf[i-1]);
+ else
+ printf("0x%04x", svmp_buf[i]);
+ }
+ if (i && (i%2))
+ printf("\n");
+ }
+ printf("\n");
+exit:
+ return err;
+}
+
+#if defined(BCMDBG) || defined(BCMDBG_DUMP)
+static void
+wl_svmp_sampcol_printf_configs(wl_svmp_sampcol_t *psampcol, uint16 mode)
+{
+ char *str_phy1mux[] = {"gpioOut", "fftOut", "dbgHx", "rx1mux"};
+ char *str_rx1mux[] = {"farrowOut", "iqCompOut", "dcFilterOut",
+ "rxFilterOut", "aciFilterOut"};
+ char *str_packmode[] = {"dual", "4-cores", "2-cores", "single-core"};
+ char *str_packorder[] = {"big", "little"};
+
+ printf("version of svmp sample collect params: %d\n", psampcol->version);
+ printf(" enable: %d\n", psampcol->enable);
+ printf(" trigger: %d", psampcol->trigger_mode);
+ if (psampcol->trigger_mode == SVMP_SAMPCOL_TRIGGER_PKTPROC_TRANSITION) {
+ printf(", %d -> %d\n", psampcol->trigger_mode_s[0], psampcol->trigger_mode_s[1]);
+ } else {
+ printf("\n");
+ }
+ printf(" waitcnt: %d\n", psampcol->waitcnt);
+ printf(" caplen: %d\n", psampcol->caplen);
+ printf(" samplerate: %dx\n", (psampcol->data_samplerate + 1));
+ printf(" data: %s", str_phy1mux[psampcol->data_sel_phy1]);
+ if (psampcol->data_sel_phy1 == SVMP_SAMPCOL_PHY1MUX_RX1MUX) {
+ printf(" with %s\n",
+ str_rx1mux[psampcol->data_sel_rx1-SVMP_SAMPCOL_RX1MUX_FARROWOUT]);
+ } else {
+ printf("\n");
+ }
+ printf(" dualcap: ");
+ if (psampcol->data_sel_dualcap >= SVMP_SAMPCOL_RX1MUX_FARROWOUT) {
+ printf("%s\n",
+ str_rx1mux[psampcol->data_sel_dualcap-SVMP_SAMPCOL_RX1MUX_FARROWOUT]);
+ } else {
+ printf("OFF\n");
+ }
+ printf(" pack: %s, %s-endian",
+ str_packmode[psampcol->pack_mode], str_packorder[psampcol->pack_order]);
+ if (psampcol->pack_mode == SVMP_SAMPCOL_PACK_1CORE) {
+ printf(" core%d\n", psampcol->pack_1core_sel);
+ } else {
+ printf("\n");
+ }
+ printf(" buf_addr: 0x%05x~0x%05x\n", psampcol->buff_addr_start, psampcol->buff_addr_end);
+ if (mode == 0) {
+ printf(" status: overflow=%d, running=%d\n",
+ psampcol->status&0x1, (psampcol->status&0x2)>>1);
+ }
+}
+
+static int
+wl_svmp_sampcol(void *wl, cmd_t *cmd, char **argv)
+{
+ int n;
+ int ret;
+
+ wl_svmp_sampcol_t sampcol;
+
+ uint16 cmd_nparam;
+ uint16 cmd_enable;
+
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+ uint32 phyrev;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ if ((ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0)
+ return ret;
+
+ phytype = dtoh32(revinfo.phytype);
+ phyrev = dtoh32(revinfo.phyrev);
+
+ if ((phytype != WLC_PHY_TYPE_AC) || ((phyrev != 32) && (phyrev != 33))) {
+ return BCME_USAGE_ERROR;
+ }
+
+ sampcol.version = WL_SVMP_SAMPCOL_PARAMS_VERSION;
+ sampcol.enable = 0;
+ sampcol.trigger_mode = SVMP_SAMPCOL_TRIGGER_PKTPROC_TRANSITION;
+ sampcol.trigger_mode_s[0] = SVMP_SAMPCOL_PKTPROC_OFDM_PHY;
+ sampcol.trigger_mode_s[1] = SVMP_SAMPCOL_PKTPROC_TIMING_SEARCH;
+ sampcol.waitcnt = 0;
+ sampcol.caplen = 128;
+ sampcol.data_samplerate = SVMP_SAMPCOL_SAMPLERATE_2XBW;
+ sampcol.data_sel_phy1 = SVMP_SAMPCOL_PHY1MUX_RX1MUX;
+ sampcol.data_sel_rx1 = SVMP_SAMPCOL_RX1MUX_FARROWOUT;
+ sampcol.data_sel_dualcap = 0;
+ sampcol.pack_mode = SVMP_SAMPCOL_PACK_4CORE;
+ sampcol.pack_order = 0;
+ sampcol.pack_cfix_fmt = 0;
+ sampcol.pack_1core_sel = 0;
+ sampcol.buff_addr_start = 0x25800;
+ sampcol.buff_addr_end = 0x26800;
+ sampcol.int2vasip = 1;
+
+ ret = -1;
+ cmd_nparam = 0;
+ cmd_enable = 0;
+
+ argv++;
+ while (*argv) {
+ char *s = *argv++;
+ if (*argv == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit_svmp_sampcol;
+ }
+ if (!strcmp(s, "-h")) {
+ ret = BCME_USAGE_ERROR;
+ goto exit_svmp_sampcol;
+ } else if (!strcmp(s, "-e")) {
+ cmd_nparam++;
+ sampcol.enable = (uint8)strtol(*argv++, NULL, 0);
+ cmd_enable = 1;
+ } else if (!strcmp(s, "-t")) {
+ cmd_nparam++;
+ sampcol.trigger_mode = (uint8)strtol(*argv++, NULL, 0);
+ if (sampcol.trigger_mode == SVMP_SAMPCOL_TRIGGER_PKTPROC_TRANSITION) {
+ for (n = 0; n < 2; n++) {
+ if (*argv == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit_svmp_sampcol;
+ } else {
+ sampcol.trigger_mode_s[n]
+ = (uint8)strtol(*argv++, NULL, 0);
+ }
+ }
+ }
+ } else if (!strcmp(s, "-w")) {
+ cmd_nparam++;
+ sampcol.waitcnt = (uint16)strtol(*argv++, NULL, 0);
+ } else if (!strcmp(s, "-l")) {
+ cmd_nparam++;
+ sampcol.caplen = (uint16)strtol(*argv++, NULL, 0);
+ } else if (!strcmp(s, "-s")) {
+ cmd_nparam++;
+ sampcol.data_sel_phy1 = (uint8)strtol(*argv++, NULL, 0);
+ if ((sampcol.data_sel_phy1 == SVMP_SAMPCOL_PHY1MUX_RX1MUX) &&
+ strncmp(*argv, "-", 1)) {
+ sampcol.data_sel_rx1 = (uint8)strtol(*argv++, NULL, 0);
+ }
+ } else if (!strcmp(s, "-d")) {
+ cmd_nparam++;
+ sampcol.data_sel_dualcap = (uint8)strtol(*argv++, NULL, 0);
+ } else if (!strcmp(s, "-r")) {
+ cmd_nparam++;
+ sampcol.data_samplerate = (uint8)strtol(*argv++, NULL, 0);
+ } else if (!strcmp(s, "-p")) {
+ cmd_nparam++;
+ sampcol.pack_mode = (uint8)strtol(*argv++, NULL, 0);
+ if (strncmp(*argv, "-", 1)) {
+ sampcol.pack_order = (uint8)strtol(*argv++, NULL, 0);
+ }
+ if (strncmp(*argv, "-", 1)) {
+ sampcol.pack_cfix_fmt = (uint8)strtol(*argv++, NULL, 0);
+ }
+ if ((phytype == WLC_PHY_TYPE_AC) && (phyrev == 33) &&
+ (sampcol.pack_mode == SVMP_SAMPCOL_PACK_1CORE)) {
+ if (strncmp(*argv, "-", 1)) {
+ sampcol.pack_1core_sel = (uint8)strtol(*argv++, NULL, 0);
+ }
+ }
+ } else if (!strcmp(s, "-a")) {
+ cmd_nparam++;
+ sampcol.buff_addr_start = (uint32)strtol(*argv++, NULL, 0);
+ if (strncmp(*argv, "-", 1)) {
+ sampcol.buff_addr_end = (uint32)strtol(*argv++, NULL, 0);
+ }
+ } else {
+ argv++;
+ }
+ }
+
+ if ((cmd_nparam == 0) || ((cmd_enable == 1) && (cmd_nparam == 1))) {
+ cmd_enable = sampcol.enable;
+ ret = wlu_iovar_get(wl, cmd->name, &sampcol, sizeof(wl_svmp_sampcol_t));
+ if (sampcol.version != WL_SVMP_SAMPCOL_PARAMS_VERSION) {
+ printf("\tIncorrect version "
+ "of SVMP_SAMPCOL_PARAMS struct: expect %d but get %d\n",
+ WL_SVMP_SAMPCOL_PARAMS_VERSION, sampcol.version);
+ return BCME_BADARG;
+ }
+ if (cmd_nparam == 1) {
+ sampcol.enable = cmd_enable;
+ } else {
+ wl_svmp_sampcol_printf_configs(&sampcol, 0);
+ }
+ }
+ if (cmd_nparam > 0) {
+ wl_svmp_sampcol_printf_configs(&sampcol, 1);
+ ret = wlu_var_setbuf(wl, cmd->name, &sampcol, sizeof(wl_svmp_sampcol_t));
+ }
+
+exit_svmp_sampcol:
+ return ret;
+}
+#endif
+
+static int
+wl_scanmac(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1;
+ char *subcmd;
+ int subcmd_len;
+
+ /* skip iovar */
+ argv++;
+
+ /* must have subcommand */
+ subcmd = *argv++;
+ if (!subcmd) {
+ return BCME_USAGE_ERROR;
+ }
+ subcmd_len = strlen(subcmd);
+
+ if (!*argv) {
+ /* get */
+ uint8 buffer[OFFSETOF(wl_scanmac_t, data)];
+ wl_scanmac_t *sm = (wl_scanmac_t *)buffer;
+ int len = OFFSETOF(wl_scanmac_t, data);
+
+ memset(sm, 0, len);
+ if (!strncmp(subcmd, "enable", subcmd_len)) {
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_ENABLE;
+ } else if (!strncmp(subcmd, "bsscfg", subcmd_len)) {
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_BSSCFG;
+ } else if (!strncmp(subcmd, "config", subcmd_len)) {
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_CONFIG;
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* invoke GET iovar */
+ sm->subcmd_id = dtoh16(sm->subcmd_id);
+ sm->len = dtoh16(sm->len);
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, sm, len, buf, WLC_IOCTL_SMLEN)) < 0) {
+ return err;
+ }
+
+ /* process and print GET results */
+ sm = (wl_scanmac_t *)buf;
+ sm->subcmd_id = dtoh16(sm->subcmd_id);
+ sm->len = dtoh16(sm->len);
+
+ switch (sm->subcmd_id) {
+ case WL_SCANMAC_SUBCMD_ENABLE:
+ {
+ wl_scanmac_enable_t *sm_enable = (wl_scanmac_enable_t *)sm->data;
+ if (sm->len >= sizeof(*sm_enable)) {
+ printf("%d\n", sm_enable->enable);
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ case WL_SCANMAC_SUBCMD_BSSCFG:
+ {
+ wl_scanmac_bsscfg_t *sm_bsscfg = (wl_scanmac_bsscfg_t *)sm->data;
+ if (sm->len >= sizeof(*sm_bsscfg)) {
+ sm_bsscfg->bsscfg = dtoh32(sm_bsscfg->bsscfg);
+ printf("%d\n", sm_bsscfg->bsscfg);
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ case WL_SCANMAC_SUBCMD_CONFIG:
+ {
+ wl_scanmac_config_t *sm_config = (wl_scanmac_config_t *)sm->data;
+ if (sm->len >= sizeof(*sm_config)) {
+ sm_config->scan_bitmap = dtoh16(sm_config->scan_bitmap);
+ printf("mac: %s\n", wl_ether_etoa(&sm_config->mac));
+ printf("random mask: %s\n", wl_ether_etoa(&sm_config->random_mask));
+ printf("scan bitmap: 0x%02X\n", sm_config->scan_bitmap);
+ if (sm_config->scan_bitmap & WL_SCANMAC_SCAN_UNASSOC) {
+ printf(" unassoc\n");
+ }
+ if (sm_config->scan_bitmap & WL_SCANMAC_SCAN_ASSOC_ROAM) {
+ printf(" assoc roam\n");
+ }
+ if (sm_config->scan_bitmap & WL_SCANMAC_SCAN_ASSOC_PNO) {
+ printf(" assoc PNO\n");
+ }
+ if (sm_config->scan_bitmap & WL_SCANMAC_SCAN_ASSOC_HOST) {
+ printf(" assoc host\n");
+ }
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ else {
+ /* set */
+ uint8 buffer[OFFSETOF(wl_scanmac_t, data) +
+ MAX(sizeof(wl_scanmac_enable_t), sizeof(wl_scanmac_config_t))];
+ wl_scanmac_t *sm = (wl_scanmac_t *)buffer;
+ int len = OFFSETOF(wl_scanmac_t, data);
+
+ if (!strncmp(subcmd, "enable", subcmd_len) &&
+ (*argv[0] == '0' || *argv[0] == '1')) {
+ wl_scanmac_enable_t *sm_enable = (wl_scanmac_enable_t *)sm->data;
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_ENABLE;
+ sm->len = sizeof(*sm_enable);
+ sm_enable->enable = atoi(argv[0]);
+ } else if (!strncmp(subcmd, "config", subcmd_len) &&
+ argv[0] && argv[1] && argv[2]) {
+ wl_scanmac_config_t *sm_config = (wl_scanmac_config_t *)sm->data;
+ char *mac = argv[0];
+ char *mask = argv[1];
+ char *bitmap = argv[2];
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_CONFIG;
+ sm->len = sizeof(*sm_config);
+ if (!wl_ether_atoe(mac, &sm_config->mac) ||
+ !wl_ether_atoe(mask, &sm_config->random_mask)) {
+ return BCME_USAGE_ERROR;
+ }
+ sm_config->scan_bitmap = (uint16)strtoul(bitmap, NULL, 0);
+ sm_config->scan_bitmap = htod16(sm_config->scan_bitmap);
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* invoke SET iovar */
+ len = OFFSETOF(wl_scanmac_t, data) + sm->len;
+ sm->subcmd_id = htod16(sm->subcmd_id);
+ sm->len = htod16(sm->len);
+ err = wlu_iovar_set(wl, cmd->name, sm, len);
+ }
+
+ return err;
+}
+
+static int wl_winver(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ wl_winver_t wv;
+
+ UNUSED_PARAMETER(argv);
+
+ memset(&wv, 0, sizeof(wv));
+ err = wlu_iovar_get(wl, cmd->name, &wv, sizeof(wv));
+
+ if ((err == BCME_OK) && (wv.struct_version >= WL_WINVER_STRUCT_VER_1)) {
+ printf("\n"
+ "Windows OS ver= %d.%d.%d\n"
+ "NDIS Runtime = %d.%d\n"
+ "NDIS Driver = %d.%d\n"
+ "WDI UE version= %d.%d_%X\n"
+ "WDI LE version= %d.%d_%X\n",
+ wv.os_runtime.major_ver, wv.os_runtime.minor_ver, wv.os_runtime.build,
+ wv.ndis_runtime.major_ver, wv.ndis_runtime.minor_ver,
+ wv.ndis_driver.major_ver, wv.ndis_driver.minor_ver,
+ wv.wdi_ue.major_ver, wv.wdi_ue.minor_ver, wv.wdi_ue.suffix,
+ wv.wdi_le.major_ver, wv.wdi_le.minor_ver, wv.wdi_le.suffix);
+ }
+
+ return err;
+}
+
+#define TCMS_MAX_CORES (8)
+#define TCMS_INPUT_BUFSIZE (1 + 1 + 1)
+
+static int
+wl_get_tcmstbl_entry(void *wl, cmd_t *cmd, char **argv)
+{
+ int32 wl_tcmsarg[TCMS_INPUT_BUFSIZE] = {0, 0, 0};
+ int32* obuf = (int32 *)buf;
+ int err, opt_err;
+ miniopt_t to;
+ const char* fn_name = "wl_get_tcmstbl_entry";
+ int argc = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* counting the number of arguments */
+ while (argv[argc])
+ argc++;
+
+ if (argc < 2)
+ return BCME_USAGE_ERROR;
+
+ memset(buf, 0, WLC_IOCTL_MEDLEN);
+
+ /* toss the command name */
+ argv++;
+
+ /* Validate arguments if any */
+ if (*argv) {
+ miniopt_init(&to, fn_name, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 'c') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for core\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val > (TCMS_MAX_CORES-1)) {
+ fprintf(stderr,
+ "%s: invalid core %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ wl_tcmsarg[0] = to.val;
+ }
+ if (to.opt == 'a') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as"
+ " an int for antenna map\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ wl_tcmsarg[1] = to.val;
+ }
+ if (to.opt == 's') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as"
+ " an int for cell status\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val < 0) | (to.val > 1)) {
+ fprintf(stderr,
+ "%s: invalid cell status %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ wl_tcmsarg[2] = to.val;
+ }
+ }
+ } else {
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ if ((err = wlu_iovar_getbuf(wl, "tcmstbl", wl_tcmsarg, sizeof(wl_tcmsarg),
+ buf, WLC_IOCTL_MEDLEN)) < 0) {
+ printf("\n Incorrect option \n");
+ err = BCME_BADOPTION;
+ goto exit;
+ }
+
+ printf("(Nsts {4..1}) { %d hdBm 0x%02x } { %d hdBm 0x%02x }"
+ "{ %d hdBm 0x%02x } { %d hdBm 0x%02x }\n",
+ obuf[10], obuf[11], obuf[8], obuf[9],
+ obuf[6], obuf[7], obuf[4], obuf[5]);
+ printf("OFDM { %d hdBm 0x%02x } CCK { %d hdBm 0x%02x }\n",
+ obuf[2], obuf[3], obuf[0], obuf[1]);
+exit:
+ return err;
+}
+
+/*
+ * get/set IPv6 RA rate limit interval
+ */
+static int
+wl_nd_ra_limit_intv(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0, opt_err;
+ miniopt_t to;
+ nd_ra_ol_limits_t *ra_limit = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ if ((err = wlu_var_getbuf(wl,
+ "nd_ra_limit_intv", NULL, 0, (void *)&ra_limit) < 0)) {
+ printf("nd_ra_limit_intv: getbuf ioctl failed\n");
+ return err;
+ }
+
+ if (*++argv) {
+ /* set */
+ if (argv[0][0] == 'h' ||
+ argv[0][0] == '?') {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ ra_limit = calloc(1, sizeof(nd_ra_ol_limits_t));
+ if (ra_limit == NULL) {
+ return BCME_NOMEM;
+ }
+
+ miniopt_init(&to, __FUNCTION__, NULL, FALSE);
+
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+ if (to.opt == 't') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " type\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ ra_limit->type = to.val;
+ }
+
+ if (to.opt == 'p') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " percentage value\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ ra_limit->limits.lifetime_relative.lifetime_percent = to.val;
+ }
+
+ if (to.opt == 'm') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " min_time\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ ra_limit->limits.lifetime_relative.min_time = to.val;
+ }
+ }
+
+ ra_limit->version = ND_RA_OL_LIMITS_VER;
+
+ if (ra_limit->type == ND_RA_OL_LIMITS_REL_TYPE) {
+ printf("type %d, lifetime_percent %d, min_time %d\n",
+ ra_limit->type,
+ ra_limit->limits.lifetime_relative.lifetime_percent,
+ ra_limit->limits.lifetime_relative.min_time);
+ ra_limit->length = ND_RA_OL_LIMITS_REL_TYPE_LEN;
+ } else if (ra_limit->type == ND_RA_OL_LIMITS_FIXED_TYPE) {
+ printf("type %d, min_time %d\n",
+ ra_limit->type,
+ ra_limit->limits.fixed.hold_time);
+ ra_limit->length = ND_RA_OL_LIMITS_FIXED_TYPE_LEN;
+ } else {
+ printf("Invalid nd_ra_limit_intv type %d\n",
+ ra_limit->type);
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ if ((err = wlu_var_setbuf(wl, "nd_ra_limit_intv", ra_limit,
+ sizeof(nd_ra_ol_limits_t)) < 0)) {
+ printf("%s: failed to set %d\n", cmd->name, err);
+ }
+ } else {
+ /* get */
+ if (ra_limit->version != ND_RA_OL_LIMITS_VER) {
+ printf("Invalid nd_ra_limit_intv version %d\n",
+ ra_limit->version);
+ err = BCME_VERSION;
+ goto exit;
+ }
+
+ if (ra_limit->type == ND_RA_OL_LIMITS_REL_TYPE) {
+ printf(" type %d, percentage %d, fixed time %d\n",
+ ra_limit->type,
+ ra_limit->limits.lifetime_relative.lifetime_percent,
+ ra_limit->limits.lifetime_relative.min_time);
+ } else if (ra_limit->type == ND_RA_OL_LIMITS_FIXED_TYPE) {
+ printf(" type %d, fixed time %d\n",
+ ra_limit->type,
+ ra_limit->limits.fixed.hold_time);
+ } else {
+ printf("Invalid nd_ra_limit_intv type %d\n",
+ ra_limit->type);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+
+exit:
+ if (ra_limit) {
+ free(ra_limit);
+ }
+
+ return err;
+}
+
+int
+wl_ccode_info(void *wl, cmd_t *cmd, char **argv)
+{
+ int error, i;
+ void *ptr;
+ const char* abbrev;
+ wl_ccode_info_t *ci;
+ wl_ccode_entry_t *ce;
+ cntry_name_t *cntry;
+ const char *band_type[] = {"2G", "5G"};
+ const char *ccode_type[] = {"accode", "hdcode", "11dassoccode", "11dscancode", "defccode"};
+
+ /* skip the command name */
+ argv++;
+
+ if ((error = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return (error);
+
+ ci = (wl_ccode_info_t *)ptr;
+ if (dtoh16(ci->version) != CCODE_INFO_VERSION) {
+ printf("\tIncorrect version of ccode_info IOVAR expected %d; got %d\n",
+ CCODE_INFO_VERSION, dtoh16(ci->version));
+ return -1;
+ }
+ if (dtoh16(ci->count) > 2 * WLC_NUM_CCODE_INFO) {
+ printf("\tBigger than expected country codes. Expected:%d; got %d\n",
+ 2 * WLC_NUM_CCODE_INFO, dtoh16(ci->count));
+ return -1;
+ }
+ for (i = 0; i < dtoh16(ci->count); i++) {
+ ce = &ci->ccodelist[i];
+ abbrev = ce->ccode;
+ cntry = wlc_cntry_abbrev_to_country(abbrev);
+ printf("%s\t%s:%s\t%s\n",
+ band_type[ce->band],
+ ccode_type[ce->role],
+ abbrev, cntry ? cntry->name : "");
+ }
+ return 0;
+}
+
+#if defined(linux)
+int
+wl_wait_for_event(void *wl, char **argv, uint event_id, uint evbuf_size,
+ void (*event_cb_fn)(int event_type, bcm_event_t *bcm_event))
+{
+ int err = BCME_OK;
+ int fd, octets;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ char ifnames[IFNAMSIZ] = {"eth1"};
+ uint8 event_buf[WL_EVENTINT_MAX_GET_SIZE];
+ eventmsgs_ext_t *eventmsgs;
+ char *data;
+
+ /* Override default ifname explicitly or implicitly */
+ if (*++argv) {
+ if (strlen(*argv) >= IFNAMSIZ) {
+ printf("Interface name %s too long\n", *argv);
+ return -1;
+ }
+ strncpy(ifnames, *argv, IFNAMSIZ);
+ } else if (wl) {
+ strncpy(ifnames, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
+ }
+ ifnames[IFNAMSIZ - 1] = '\0';
+
+ /* set event bit using 'event_msgs_ext' */
+ if ((event_id / 8) >= WL_EVENTING_MASK_MAX_LEN) {
+ printf("Event Id %d exceeds max %d event bytes\n",
+ event_id, WL_EVENTING_MASK_MAX_LEN);
+ goto exit2;
+ }
+ memset(event_buf, 0, sizeof(event_buf));
+ eventmsgs = (eventmsgs_ext_t *)event_buf;
+ eventmsgs->ver = EVENTMSGS_VER;
+ eventmsgs->command = EVENTMSGS_SET_BIT;
+ eventmsgs->len = WL_EVENTING_MASK_MAX_LEN;
+ eventmsgs->mask[event_id / 8] |= 1 << (event_id % 8);
+ if ((err = wlu_var_setbuf(wl, "event_msgs_ext", eventmsgs,
+ EVENTMSGS_EXT_STRUCT_SIZE + eventmsgs->len)) < 0) {
+ printf("Failed to set event mask\n");
+ goto exit2;
+ }
+
+ /* Open a socket to read driver WLC_E_* events */
+ memset(&ifr, 0, sizeof(ifr));
+ if (wl)
+ strncpy(ifr.ifr_name, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
+ else
+ strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
+
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
+ if (fd < 0) {
+ printf("Cannot create socket %d\n", fd);
+ err = -1;
+ goto exit2;
+ }
+
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ printf("%s: Cannot get index %d\n", __FUNCTION__, err);
+ goto exit1;
+ }
+
+ /* bind the socket first before starting so we won't miss any event */
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ printf("Cannot bind %d\n", err);
+ goto exit1;
+ }
+
+ data = (char*)malloc(evbuf_size);
+
+ if (data == NULL) {
+ printf("Cannot not allocate %u bytes for events receive buffer\n",
+ evbuf_size);
+ err = -1;
+ goto exit1;
+ }
+
+ /* Loop forever to receive driver events */
+ while (1) {
+ bcm_event_t *bcm_event;
+ int event_type;
+
+ octets = recv(fd, data, evbuf_size, 0);
+ bcm_event = (bcm_event_t *)data;
+ event_type = ntoh32(bcm_event->event.event_type);
+ if (octets >= (int)sizeof(bcm_event_t)) {
+ event_cb_fn(event_type, bcm_event);
+ }
+ }
+
+ free(data);
+exit1:
+ close(fd);
+exit2:
+ return err;
+}
+#endif /* linux */
+
+#define SIM_PM_MAX_CYCLE 10000
+#define SIM_PM_MAX_UP 1000
+#define SIM_PM_DEF_CYCLE 100
+#define SIM_PM_DEF_UP 5
+
+static int
+wl_sim_pm(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = BCME_OK, opt_err;
+ miniopt_t to;
+ const char* fn_name = "wl_sim_pm";
+ sim_pm_params_t *params = (sim_pm_params_t *)buf;
+
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, NULL, 0, buf, WLC_IOCTL_SMLEN)) < 0) {
+ printf("Get %s got error %d\n", cmd->name, err);
+ goto exit;
+ }
+
+ if (!*++argv) {
+ printf("%sabled, Cycle time: %u TUs, Up time: %u TUs\n", params->enabled ? "En" :
+ "Dis", params->cycle, params->up);
+ goto exit;
+ }
+ miniopt_init(&to, fn_name, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == '\0') {
+ if (!to.good_int) {
+ fprintf(stderr, "%s: could not parse \"%s\" as an int for enable\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val != 0 && to.val != 1) {
+ fprintf(stderr, "%s: invalid enable parameter. [0|1]\n", fn_name);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->enabled = to.val;
+ }
+ if (to.opt == 'c') {
+ if (!to.good_int) {
+ fprintf(stderr, "%s: could not parse \"%s\" as an int for cycle\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val <= 0 || to.val > SIM_PM_MAX_CYCLE) {
+ fprintf(stderr, "%s: invalid cycle time. Max. %d\n", fn_name,
+ SIM_PM_MAX_CYCLE);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->cycle = to.val;
+ }
+ if (to.opt == 'u') {
+ if (!to.good_int) {
+ fprintf(stderr, "%s: could not parse \"%s\" as an int for up\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val <= 0 || to.val > SIM_PM_MAX_UP) {
+ fprintf(stderr, "%s: invalid up time. Max. %d\n", fn_name,
+ SIM_PM_MAX_UP);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->up = to.val;
+ }
+ }
+ params->cycle = params->cycle ? params->cycle : SIM_PM_DEF_CYCLE;
+ params->up = params->up ? params->up : SIM_PM_DEF_UP;
+ if (params->up >= params->cycle) {
+ fprintf(stderr, "%s: cycle time (%d) should be greater than up time (%d).\n",
+ fn_name, params->cycle, params->up);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((err = wlu_iovar_set(wl, cmd->name, params, sizeof(*params))) < 0) {
+ printf("Error setting variable %s\n", cmd->name);
+ return err;
+ }
+exit:
+ return err;
+}
+
+/*
+ * Health Check "hc" iovar support
+ */
+
+/* hc command information structure, forward decl. */
+struct hc_sub_cmd_ent;
+
+/* hc sub-command handler function, used in the hc command tables */
+typedef int (*hc_cmd_fn_t)(void *wl, uint16 category, struct hc_sub_cmd_ent *hc_cmd, char **argv);
+
+/* hc command information structure, definition
+ * Used to dispatch action based on a sub-command name
+ */
+struct hc_sub_cmd_ent {
+ const char *name; /* sub-command name for command line */
+ uint16 id; /* cmd id for the handler fn */
+ hc_cmd_fn_t fn; /* sub-command handler fn */
+};
+typedef struct hc_sub_cmd_ent hc_sub_cmd_table_t[];
+
+static struct hc_sub_cmd_ent* wl_hc_cmd_lookup(hc_sub_cmd_table_t tbl, char* cmd);
+static void wl_hc_subcommand_list_dump(void *wl, const char *category, hc_sub_cmd_table_t tbl);
+static int wl_hc_int(void *wl, uint16 category, struct hc_sub_cmd_ent *hc_cmd, char** argv);
+static int wl_hc_exclude_bitmap(void *wl, uint16 category, struct hc_sub_cmd_ent *hc_cmd,
+ char** argv);
+static int wl_hc_setints(void *wl, uint16 category, struct hc_sub_cmd_ent *hc_cmd,
+ int int_count, char **argv);
+static int wl_hc_getints(void *wl, uint16 category, struct hc_sub_cmd_ent *hc_cmd,
+ int int_count, char **argv);
+
+/* HC Tx category commands */
+struct hc_sub_cmd_ent hc_tx_cmds[] = {
+ {"stall_threshold", WL_HC_TX_XTLV_ID_VAL_STALL_THRESHOLD, wl_hc_int},
+ {"stall_sample_size", WL_HC_TX_XTLV_ID_VAL_STALL_SAMPLE_SIZE, wl_hc_int},
+ {"stall_timeout", WL_HC_TX_XTLV_ID_VAL_STALL_TIMEOUT, wl_hc_int},
+ {"stall_force", WL_HC_TX_XTLV_ID_VAL_STALL_FORCE, wl_hc_int},
+ {"stall_exclude", WL_HC_TX_XTLV_ID_VAL_STALL_EXCLUDE, wl_hc_exclude_bitmap},
+ {"fc_timeout", WL_HC_TX_XTLV_ID_VAL_FC_TIMEOUT, wl_hc_int},
+ {"fc_force", WL_HC_TX_XTLV_ID_VAL_FC_FORCE, wl_hc_int},
+ /* NUL terminated table */
+ {NULL, 0, NULL},
+};
+
+/* HC Rx category commands */
+hc_sub_cmd_table_t hc_rx_cmds = {
+ {"dma_stall_timeout", WL_HC_RX_XTLV_ID_VAL_DMA_STALL_TIMEOUT, wl_hc_int},
+ {"dma_stall_force", WL_HC_RX_XTLV_ID_VAL_DMA_STALL_FORCE, wl_hc_int},
+ {"stall_threshold", WL_HC_RX_XTLV_ID_VAL_STALL_THRESHOLD, wl_hc_int},
+ {"stall_sample_size", WL_HC_RX_XTLV_ID_VAL_STALL_SAMPLE_SIZE, wl_hc_int},
+ {"stall_force", WL_HC_RX_XTLV_ID_VAL_STALL_FORCE, wl_hc_int},
+ /* NUL terminated table */
+ {NULL, 0, NULL},
+};
+
+/* Main command line handler for Health Check 'hc' iovar */
+static int
+wl_hc(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ char *sub_cmd_name;
+ struct hc_sub_cmd_ent *sub_cmd;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* Skip the command name */
+ argv++;
+
+ sub_cmd_name = *argv++;
+
+ if (sub_cmd_name == NULL) {
+ /* usage */
+ printf("hc: missing category\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!strcmp(sub_cmd_name, "tx")) {
+ char* attr_name;
+
+ attr_name = *argv++;
+
+ if (attr_name == NULL) {
+ /* usage */
+ printf("hc tx: missing attribute\n");
+ wl_hc_subcommand_list_dump(wl, sub_cmd_name, hc_tx_cmds);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* grab the command info from the sub-command table */
+ sub_cmd = wl_hc_cmd_lookup(hc_tx_cmds, attr_name);
+
+ if (sub_cmd == NULL) {
+ /* usage */
+ printf("hc tx: unknown sub-command \"%s\"\n", attr_name);
+ wl_hc_subcommand_list_dump(wl, sub_cmd_name, hc_tx_cmds);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* execute the sub command */
+ ret = (*sub_cmd->fn)(wl, WL_HC_XTLV_ID_CAT_DATAPATH_TX, sub_cmd, argv);
+
+ } else if (!strcmp(sub_cmd_name, "rx")) {
+ char* attr_name;
+
+ attr_name = *argv++;
+
+ if (attr_name == NULL) {
+ /* usage */
+ printf("hc rx: missing attribute\n");
+ wl_hc_subcommand_list_dump(wl, sub_cmd_name, hc_rx_cmds);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* grab the command info from the sub-command table */
+ sub_cmd = wl_hc_cmd_lookup(hc_rx_cmds, attr_name);
+
+ if (sub_cmd == NULL) {
+ /* usage */
+ printf("hc rx: unknown sub-command \"%s\"\n", attr_name);
+ wl_hc_subcommand_list_dump(wl, sub_cmd_name, hc_rx_cmds);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* execute the sub command */
+ ret = (*sub_cmd->fn)(wl, WL_HC_XTLV_ID_CAT_DATAPATH_RX, sub_cmd, argv);
+
+ } else {
+ /* usage */
+ printf("unknown hc category \"%s\"\n", sub_cmd_name);
+ return BCME_USAGE_ERROR;
+ }
+
+ return ret;
+}
+
+/* Generic set/get of an integer attribute.
+ * Just issue a wl_hc_setints() if there is a 2nd arg, or wl_hc_getints() otherwise.
+ */
+static int
+wl_hc_int(void *wl, uint16 category, struct hc_sub_cmd_ent *hc_cmd, char** argv)
+{
+ if (argv[0] != NULL)
+ return (wl_hc_setints(wl, category, hc_cmd, 1, argv));
+ else
+ return (wl_hc_getints(wl, category, hc_cmd, 1, argv));
+}
+
+/* Set/Get of the "exclude" bitmap.
+ * Just issue a wl_hc_setints() for 2 ints if there is a 2nd arg,
+ * or wl_hc_getints() for 2 ints otherwise.
+ */
+static int
+wl_hc_exclude_bitmap(void *wl, uint16 category, struct hc_sub_cmd_ent *hc_cmd, char** argv)
+{
+ if (argv[0] != NULL)
+ return (wl_hc_setints(wl, category, hc_cmd, 2, argv));
+ else
+ return (wl_hc_getints(wl, category, hc_cmd, 2, argv));
+}
+
+static int
+wl_hc_setints(void *wl, uint16 category, struct hc_sub_cmd_ent *hc_cmd, int int_count, char **argv)
+{
+ char *valstr;
+ char *endptr = NULL;
+ bcm_xtlv_t *hc_tlv;
+ struct {
+ uint16 id;
+ uint16 len;
+ uint32 value[1];
+ } *val_xtlv;
+ uint32 words[2];
+ int i;
+ uint out_len;
+ uint16 val_payload_len;
+ uint16 container_payload_len;
+ uint32 val;
+ int ret = 0;
+
+ for (i = 0; i < int_count; i++) {
+ valstr = *argv++;
+
+ if (!valstr || valstr[0] == '\0') {
+ printf("hc set: missing value argument for set of \"%s\"\n", hc_cmd->name);
+ return BCME_USAGE_ERROR;
+ }
+
+ val = strtoul(valstr, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n",
+ valstr, hc_cmd->name);
+ return BCME_USAGE_ERROR;
+ }
+ words[i] = val;
+ }
+
+ /* total output buffer will be an hc sub-category xtlv holding
+ * an xtvl of 1 or 2 uint32s.
+ */
+ val_payload_len = (int_count * sizeof(val_xtlv->value[0]));
+ container_payload_len = bcm_xtlv_size_for_data(val_payload_len,
+ BCM_XTLV_OPTION_NONE);
+ out_len = bcm_xtlv_size_for_data(container_payload_len,
+ BCM_XTLV_OPTION_NONE);
+
+ /* init the wrapper hc category XTLV in the IO buffer */
+ hc_tlv = (bcm_xtlv_t*)(&buf[0]);
+ hc_tlv->id = htol16(category);
+ hc_tlv->len = htol16(container_payload_len);
+
+ val_xtlv = (void*)hc_tlv->data;
+ val_xtlv->id = htol16(hc_cmd->id);
+ val_xtlv->len = htol16(val_payload_len);
+ for (i = 0; i < int_count; i++) {
+ val_xtlv->value[i] = htol32(words[i]);
+ }
+
+ ret = wlu_iovar_set(wl, "hc", hc_tlv, out_len);
+
+ return ret;
+}
+
+static int
+wl_hc_getints(void *wl, uint16 category, struct hc_sub_cmd_ent *hc_cmd, int int_count, char **argv)
+{
+ int ret = 0;
+ bcm_xtlv_t *hc_tlv;
+ bcm_xtlv_t *val_xtlv;
+ uint16 hc_len, hc_id;
+ uint16 val_len, val_id;
+ struct {
+ uint16 id;
+ uint16 len;
+ uint16 ids[1];
+ } id_list;
+ uint param_len;
+ const bcm_xtlv_opts_t no_pad = BCM_XTLV_OPTION_NONE;
+
+ if (*argv) {
+ printf("hc get: error, extra arg \"%s\"\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* total param buffer will be an hc sub-category xtlv holding
+ * an xtvl ID list of one element.
+ * no padding since the id_list is the last element.
+ */
+ param_len = bcm_xtlv_size_for_data(sizeof(id_list), no_pad);
+
+ /* init an XTLV ID list with the desired attribute ID */
+ bcm_xtlv_pack_xtlv((bcm_xtlv_t *)&id_list, WL_HC_XTLV_ID_IDLIST, sizeof(uint16),
+ NULL, no_pad);
+ id_list.ids[0] = htol16(hc_cmd->id);
+
+ /* init the wrapper hc category XTLV in the IO buffer and copy to it */
+ hc_tlv = (bcm_xtlv_t *)&buf[0];
+ bcm_xtlv_pack_xtlv(hc_tlv, category, sizeof(id_list), (const uint8 *)&id_list, no_pad);
+
+ /* issue the 'hc' get with the one-item id list */
+ if ((ret = wlu_iovar_getbuf(wl, "hc", buf, param_len, buf, WLC_IOCTL_SMLEN)))
+ return ret;
+
+ hc_len = ltoh16(hc_tlv->len);
+ hc_id = ltoh16(hc_tlv->id);
+
+ /* make sure the return xtlv is valid for the iobuffer */
+ if (!bcm_valid_xtlv(hc_tlv, WLC_IOCTL_SMLEN, no_pad)) {
+ printf("hc get: return XTLV specifies length %u too long for iobuffer len %u\n",
+ hc_len, WLC_IOCTL_SMLEN);
+ return BCME_ERROR;
+ }
+
+ /* the return buf should start with the HC xtlv container */
+ if (hc_id != category) {
+ printf("hc get: return category %u did not match %u\n",
+ hc_id, category);
+ return BCME_ERROR;
+ }
+
+ /* make sure the container has enough room for an XTLV header */
+ if (hc_len < BCM_XTLV_HDR_SIZE) {
+ printf("hc get: return XTLV container specifies length %u too small "
+ "to hold any values\n",
+ hc_len);
+ return BCME_ERROR;
+ }
+
+ val_xtlv = (bcm_xtlv_t*)hc_tlv->data;
+ val_len = ltoh16(val_xtlv->len);
+ val_id = ltoh16(val_xtlv->id);
+
+ /* make sure the value xtlv is valid xtlv container */
+ if (!bcm_valid_xtlv(val_xtlv, hc_len, no_pad)) {
+ printf("hc get: return XTLV specifies length %u too long "
+ "for containing xtlv len %u\n",
+ val_len, hc_len);
+ return BCME_ERROR;
+ }
+
+ if (val_len == 0) {
+ printf("hc get: return value XTLV (id:%u) empty\n", val_id);
+ return BCME_ERROR;
+ } else if (val_len != int_count * sizeof(int32)) {
+ printf("hc get: WARNING: return value XTLV (id:%u len:%u) was not "
+ "the expected len %u\n",
+ val_id, val_len, (uint)(int_count * sizeof(int32)));
+ ret = BCME_ERROR;
+ }
+
+ /* print as words if multiple of word size, otherwise hexdump */
+ if (val_len % sizeof(uint32) == 0) {
+ uint32 *w = (uint32*)val_xtlv->data;
+ int i;
+ for (i = 0; i * sizeof(uint32) < val_len; i++) {
+ wl_printint((int)ltoh32(w[i]));
+ }
+ } else {
+ wl_hexdump((uint8*)val_xtlv->data, val_len);
+ }
+
+ return (ret);
+}
+
+static struct hc_sub_cmd_ent*
+wl_hc_cmd_lookup(hc_sub_cmd_table_t tbl, char* cmd)
+{
+ struct hc_sub_cmd_ent* entry;
+
+ for (entry = tbl; entry->name != NULL; entry++) {
+ if (!strcmp(entry->name, cmd)) {
+ break;
+ }
+ }
+
+ if (entry->name == NULL) {
+ entry = NULL;
+ }
+
+ return entry;
+}
+
+static void
+wl_hc_subcommand_list_dump(void *wl, const char *category, hc_sub_cmd_table_t tbl)
+{
+ struct hc_sub_cmd_ent* entry;
+
+ BCM_REFERENCE(wl);
+
+ printf("Sub-Commands for \"%s\":\n", category);
+
+ for (entry = tbl; entry->name != NULL; entry++) {
+ printf(" %s %s\n", category, entry->name);
+ }
+}
+
+static int
+wl_idauth(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ char *sub_cmd_name;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* Skip the command name */
+ argv++;
+
+ sub_cmd_name = *argv++;
+
+ if (sub_cmd_name == NULL) {
+ /* usage */
+ printf("idauth: missing category\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!strcmp(sub_cmd_name, "config")) {
+ char* attr_name;
+
+ attr_name = *argv;
+
+ if (attr_name == NULL) {
+ /* GET IDAUTH CONFIG */
+ ret = wl_idauth_config_get(wl, WL_IDAUTH_CMD_CONFIG, argv);
+ }
+ else {
+ /* SET AUTH Config */
+ ret = wl_idauth_config_set(wl, WL_IDAUTH_CMD_CONFIG, argv);
+ }
+ } else if (!strcmp(sub_cmd_name, "peer_info")) {
+ if (*argv == NULL) {
+ ret = wl_idauth_dump_peer_info(wl, WL_IDAUTH_CMD_PEER_INFO, argv);
+ } else {
+ printf("auth peer_info get: error, extra arg \"%s\"\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ } else if (!strcmp(sub_cmd_name, "counters")) {
+ if (*argv == NULL) {
+ ret = wl_idauth_dump_counters(wl, WL_IDAUTH_CMD_COUNTERS, argv);
+ } else {
+ printf("auth counters get: error, extra arg \"%s\"\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ } else {
+ /* usage */
+ printf("unknown idauth sub-commands \"%s\"\n", sub_cmd_name);
+ return BCME_USAGE_ERROR;
+ }
+ return ret;
+}
+static int
+wl_idauth_config_set(void *wl, uint16 category, char **argv)
+{
+ char *valstr;
+ char *endptr = NULL;
+ bcm_xtlv_t *auth_tlv;
+ bcm_xtlv_t *val_tlv_ptr;
+ uint out_len;
+ uint32 temp;
+ uint16 count;
+ uint16 container_payload_len = 0;
+ int ret = 0;
+
+ char *p;
+ /* total output buffer will be an hc sub-category xtlv holding
+ * an xtvl of 1 or 2 uint32s.
+ */
+ auth_tlv = (bcm_xtlv_t*)(&buf[0]);
+ auth_tlv->id = htol16(category);
+ val_tlv_ptr = (bcm_xtlv_t *)auth_tlv->data;
+ while (*argv) {
+ p = *argv++;
+ switch (p[1]) {
+ case 'a':
+ valstr = *argv++;
+ if (!valstr || valstr[0] == '\0') {
+ printf("idauth config set: missing value for set of %d\n",
+ WL_IDAUTH_XTLV_AUTH_ENAB);
+ return BCME_USAGE_ERROR;
+ }
+ val_tlv_ptr->data[0] = (uint8)strtoul(valstr, &endptr, 0);
+ val_tlv_ptr->id = htol16(WL_IDAUTH_XTLV_AUTH_ENAB);
+ val_tlv_ptr->len = htol16(sizeof(uint8));
+ container_payload_len += bcm_xtlv_size_for_data(sizeof(uint8),
+ BCM_XTLV_OPTION_NONE);
+ break;
+ case 'b':
+ valstr = *argv++;
+ if (!valstr || valstr[0] == '\0') {
+ printf("idauth config set: missing value for set of %d\n",
+ WL_IDAUTH_XTLV_BLKLIST_AGE);
+ return BCME_USAGE_ERROR;
+ }
+ temp = htol32(strtoul(valstr, &endptr, 0));
+ memcpy(&val_tlv_ptr->data[0], &temp, sizeof(uint32));
+ val_tlv_ptr->id = htol16(WL_IDAUTH_XTLV_BLKLIST_AGE);
+ val_tlv_ptr->len = htol16(sizeof(uint32));
+ container_payload_len += bcm_xtlv_size_for_data(sizeof(uint32),
+ BCM_XTLV_OPTION_NONE);
+ break;
+ case 'c':
+ valstr = *argv++;
+ if (!valstr || valstr[0] == '\0') {
+ printf("idauth config set: missing value for set of %d\n",
+ WL_IDAUTH_XTLV_EAPOL_COUNT);
+ return BCME_USAGE_ERROR;
+ }
+ count = htol16(strtoul(valstr, &endptr, 0));
+ memcpy(&val_tlv_ptr->data[0], &count, sizeof(uint16));
+ val_tlv_ptr->id = htol16(WL_IDAUTH_XTLV_EAPOL_COUNT);
+ val_tlv_ptr->len = htol16(sizeof(uint16));
+ container_payload_len += bcm_xtlv_size_for_data(sizeof(uint16),
+ BCM_XTLV_OPTION_NONE);
+ break;
+ case 'e':
+ valstr = *argv++;
+ if (!valstr || valstr[0] == '\0') {
+ printf("idauth config set: missing value for set of %d\n",
+ WL_IDAUTH_XTLV_EAPOL_INTRVL);
+ return BCME_USAGE_ERROR;
+ }
+ temp = htol32(strtoul(valstr, &endptr, 0));
+ memcpy(&val_tlv_ptr->data[0], &temp, sizeof(uint32));
+ val_tlv_ptr->id = htol16(WL_IDAUTH_XTLV_EAPOL_INTRVL);
+ val_tlv_ptr->len = htol16(sizeof(uint32));
+ container_payload_len += bcm_xtlv_size_for_data(sizeof(uint32),
+ BCM_XTLV_OPTION_NONE);
+ break;
+ case 'g':
+ valstr = *argv++;
+ if (!valstr || valstr[0] == '\0') {
+ printf("idauth config set: missing value for set of %d\n",
+ WL_IDAUTH_XTLV_GTK_ROTATION);
+ return BCME_USAGE_ERROR;
+ }
+ temp = htol32(strtoul(valstr, &endptr, 0));
+ memcpy(&val_tlv_ptr->data[0], &temp, sizeof(uint32));
+ val_tlv_ptr->id = htol16(WL_IDAUTH_XTLV_GTK_ROTATION);
+ val_tlv_ptr->len = htol16(sizeof(uint32));
+ container_payload_len += bcm_xtlv_size_for_data(sizeof(uint32),
+ BCM_XTLV_OPTION_NONE);
+ break;
+ case 'm':
+ valstr = *argv++;
+ if (!valstr || valstr[0] == '\0') {
+ printf("idauth config set: missing value for set of %d\n",
+ WL_IDAUTH_XTLV_BLKLIST_COUNT);
+ return BCME_USAGE_ERROR;
+ }
+ count = htol16(strtoul(valstr, &endptr, 0));
+ memcpy(&val_tlv_ptr->data[0], &count, sizeof(uint16));
+ val_tlv_ptr->id = htol16(WL_IDAUTH_XTLV_BLKLIST_COUNT);
+ val_tlv_ptr->len = htol16(sizeof(uint16));
+ container_payload_len += bcm_xtlv_size_for_data(sizeof(uint16),
+ BCM_XTLV_OPTION_NONE);
+ break;
+ default:
+ break;
+ }
+ val_tlv_ptr = (bcm_xtlv_t *)(&auth_tlv->data[container_payload_len]);
+ }
+ auth_tlv->len = htol16(container_payload_len);
+ out_len = bcm_xtlv_size_for_data(container_payload_len,
+ BCM_XTLV_OPTION_NONE);
+ ret = wlu_iovar_set(wl, "idauth", auth_tlv, out_len);
+ return ret;
+}
+static int
+wl_idauth_config_get(void *wl, uint16 category, char **argv)
+{
+ int ret = 0;
+ bcm_xtlv_t *auth_tlv;
+ bcm_xtlv_t *val_xtlv;
+ uint16 hc_len, hc_id;
+ uint16 val_len, val_id;
+ void *val_tlv_ptr;
+ uint16 len_of_tlvs;
+ const bcm_xtlv_opts_t no_pad = BCM_XTLV_OPTION_NONE;
+
+ if (*argv) {
+ printf("idauth config get: error, extra arg \"%s\"\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* init the wrapper hc category XTLV in the IO buffer and copy to it */
+ auth_tlv = (bcm_xtlv_t *)&buf[0];
+ auth_tlv->id = htol16(category);
+ auth_tlv->len = 0;
+ bcm_xtlv_pack_xtlv(auth_tlv, category, 0, 0, no_pad);
+
+ /* issue the 'hc' get with the one-item id list */
+ if ((ret = wlu_iovar_getbuf(wl, "idauth", buf, BCM_XTLV_HDR_SIZE, buf, WLC_IOCTL_SMLEN)))
+ return ret;
+
+ hc_len = ltoh16(auth_tlv->len);
+ hc_id = ltoh16(auth_tlv->id);
+
+ /* make sure the return xtlv is valid for the iobuffer */
+ if (!bcm_valid_xtlv(auth_tlv, WLC_IOCTL_SMLEN, no_pad)) {
+ printf("idauth config get:XTLV specifies length %u too long for iobuffer len %u\n",
+ hc_len, WLC_IOCTL_SMLEN);
+ return BCME_ERROR;
+ }
+
+ /* the return buf should start with the HC xtlv container */
+ if (hc_id != category) {
+ printf("idauth config get: return category %u did not match %u\n",
+ hc_id, category);
+ return BCME_ERROR;
+ }
+
+ /* make sure the container has enough room for an XTLV header */
+ if (hc_len < BCM_XTLV_HDR_SIZE) {
+ printf("idauth config get: return XTLV container specifies length %u too small"
+ "to hold any values\n",
+ hc_len);
+ return BCME_ERROR;
+ }
+ val_xtlv = (bcm_xtlv_t*)auth_tlv->data;
+ val_len = ltoh16(val_xtlv->len);
+ val_id = ltoh16(val_xtlv->id);
+
+ /* make sure the value xtlv is valid xtlv container */
+ if (!bcm_valid_xtlv(val_xtlv, hc_len, no_pad)) {
+ printf("idauth config get: return XTLV specifies length %u too long "
+ "for containing xtlv len %u\n",
+ val_len, hc_len);
+ return BCME_ERROR;
+ }
+
+ if (val_len == 0) {
+ printf("idauth config get: return value XTLV (id:%u) empty\n", val_id);
+ return BCME_ERROR;
+ }
+
+ /* print as words if multiple of word size, otherwise hexdump */
+ val_tlv_ptr = auth_tlv->data;
+ len_of_tlvs = auth_tlv->len;
+ while (len_of_tlvs && len_of_tlvs > BCM_XTLV_HDR_SIZE) {
+ val_xtlv = (bcm_xtlv_t *)val_tlv_ptr;
+ switch (val_xtlv->id) {
+ case WL_IDAUTH_XTLV_AUTH_ENAB:
+ printf("%s:%d\n", "auth_enab", *((uint8*)val_xtlv->data));
+ len_of_tlvs -= BCM_XTLV_HDR_SIZE +sizeof(uint8);
+ break;
+ case WL_IDAUTH_XTLV_GTK_ROTATION:
+ printf("%s:%d\n", "gtk_rot_interval", *((uint32*)val_xtlv->data));
+ len_of_tlvs -= BCM_XTLV_HDR_SIZE + sizeof(uint32);
+ break;
+ case WL_IDAUTH_XTLV_EAPOL_COUNT:
+ printf("%s:%d\n", "eapol_count", *((uint16*)val_xtlv->data));
+ len_of_tlvs -= BCM_XTLV_HDR_SIZE + sizeof(uint16);
+ break;
+ case WL_IDAUTH_XTLV_EAPOL_INTRVL:
+ printf("%s:%d\n", "eapol_interval", *((uint32*)val_xtlv->data));
+ len_of_tlvs -= BCM_XTLV_HDR_SIZE + sizeof(uint32);
+ break;
+ case WL_IDAUTH_XTLV_BLKLIST_COUNT:
+ printf("%s:%d\n", "mic_fail_cnt_blacklist",
+ *((uint16*)val_xtlv->data));
+ len_of_tlvs -= BCM_XTLV_HDR_SIZE + sizeof(uint16);
+ break;
+ case WL_IDAUTH_XTLV_BLKLIST_AGE:
+ printf("%s:%d\n", "blacklist_age", *((uint32*)val_xtlv->data));
+ len_of_tlvs -= BCM_XTLV_HDR_SIZE + sizeof(uint32);
+ break;
+ }
+ val_tlv_ptr = (uint8 *)val_tlv_ptr + bcm_xtlv_size((bcm_xtlv_t *)val_tlv_ptr,
+ BCM_XTLV_OPTION_NONE);
+ }
+ return (ret);
+}
+static int
+wl_idauth_dump_counters(void *wl, uint16 category, char **argv)
+{
+ int ret = 0;
+ bcm_xtlv_t *auth_tlv;
+ bcm_xtlv_t *val_xtlv;
+ uint16 hc_len, hc_id;
+ uint16 val_len, val_id;
+ uint32 *w;
+ const bcm_xtlv_opts_t no_pad = BCM_XTLV_OPTION_NONE;
+
+ if (*argv) {
+ printf("idauth counters get: error, extra arg \"%s\"\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* init the wrapper hc category XTLV in the IO buffer and copy to it */
+ auth_tlv = (bcm_xtlv_t *)&buf[0];
+ auth_tlv->id = htol16(category);
+ auth_tlv->len = 0;
+ bcm_xtlv_pack_xtlv(auth_tlv, category, 0, 0, no_pad);
+
+ /* issue the 'hc' get with the one-item id list */
+ if ((ret = wlu_iovar_getbuf(wl, "idauth", buf, BCM_XTLV_HDR_SIZE, buf, WLC_IOCTL_SMLEN)))
+ return ret;
+
+ hc_len = ltoh16(auth_tlv->len);
+ hc_id = ltoh16(auth_tlv->id);
+
+ /* make sure the return xtlv is valid for the iobuffer */
+ if (!bcm_valid_xtlv(auth_tlv, WLC_IOCTL_SMLEN, no_pad)) {
+ printf("idauth counter get:XTLV specifies length %u too long for iobuffer len %u\n",
+ hc_len, WLC_IOCTL_SMLEN);
+ return BCME_ERROR;
+ }
+
+ /* the return buf should start with the HC xtlv container */
+ if (hc_id != category) {
+ printf("idauth counter get: return category %u did not match %u\n",
+ hc_id, category);
+ return BCME_ERROR;
+ }
+
+ /* make sure the container has enough room for an XTLV header */
+ if (hc_len < BCM_XTLV_HDR_SIZE) {
+ printf("idauth counter get: return XTLV container specifies length %u too small"
+ "to hold any values\n",
+ hc_len);
+ return BCME_ERROR;
+ }
+ val_xtlv = (bcm_xtlv_t*)auth_tlv->data;
+ val_len = ltoh16(val_xtlv->len);
+ val_id = ltoh16(val_xtlv->id);
+
+ /* make sure the value xtlv is valid xtlv container */
+ if (!bcm_valid_xtlv(val_xtlv, hc_len, no_pad)) {
+ printf("idauth counter: return XTLV specifies length %u too long "
+ "for containing xtlv len %u\n",
+ val_len, hc_len);
+ return BCME_ERROR;
+ }
+
+ if (val_len == 0) {
+ printf("idauth counter get: return value XTLV (id:%u) empty\n", val_id);
+ return BCME_ERROR;
+ }
+
+ /* print as words if multiple of word size, otherwise hexdump */
+ w = (uint32*)val_xtlv->data;
+ if (val_xtlv->len < sizeof(wl_idauth_counters_t))
+ printf("Auth counter length lesser than expected\n");
+ else
+ printf("%s %d\t %s %d\t%s %d\n", "authreq", w[0],
+ "micfail", w[1], "4wayhsfail", w[2]);
+ return (ret);
+}
+
+static int
+wl_idauth_dump_peer_info(void *wl, uint16 category, char **argv)
+{
+ int ret = 0;
+ bcm_xtlv_t *auth_tlv;
+ bcm_xtlv_t *val_xtlv;
+ uint16 hc_len, hc_id;
+ uint16 val_len, val_id;
+ auth_peer_t *w;
+ int idx;
+ const bcm_xtlv_opts_t no_pad = BCM_XTLV_OPTION_NONE;
+
+ if (*argv) {
+ printf("idauth peer_info: error, extra arg \"%s\"\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* init the wrapper hc category XTLV in the IO buffer and copy to it */
+ auth_tlv = (bcm_xtlv_t *)&buf[0];
+ auth_tlv->id = htol16(category);
+ auth_tlv->len = 0;
+ bcm_xtlv_pack_xtlv(auth_tlv, category, 0, 0, no_pad);
+
+ /* issue the 'hc' get with the one-item id list */
+ if ((ret = wlu_iovar_getbuf(wl, "idauth", buf, BCM_XTLV_HDR_SIZE, buf, WLC_IOCTL_SMLEN)))
+ return ret;
+
+ hc_len = ltoh16(auth_tlv->len);
+ hc_id = ltoh16(auth_tlv->id);
+ /* make sure the return xtlv is valid for the iobuffer */
+ if (!bcm_valid_xtlv(auth_tlv, WLC_IOCTL_SMLEN, no_pad)) {
+ printf("idauth peer_info:XTLV specifies length %u too long for iobuffer len %u\n",
+ hc_len, WLC_IOCTL_SMLEN);
+ return BCME_ERROR;
+ }
+
+ /* the return buf should start with the HC xtlv container */
+ if (hc_id != category) {
+ printf("idauth peer_info: return category %u did not match %u\n",
+ hc_id, category);
+ return BCME_ERROR;
+ }
+
+ /* make sure the container has enough room for an XTLV header */
+ if (hc_len < BCM_XTLV_HDR_SIZE) {
+ if (hc_len == 0) {
+ printf("idauth peer_info: No peer present\n");
+ return ret;
+ } else {
+ printf("idauth peer_info: return XTLV container specifies"
+ "length %u too small"
+ "to hold any values\n",
+ hc_len);
+ return BCME_ERROR;
+ }
+ }
+ val_xtlv = (bcm_xtlv_t*)auth_tlv->data;
+ val_len = ltoh16(val_xtlv->len);
+ val_id = ltoh16(val_xtlv->id);
+
+ /* make sure the value xtlv is valid xtlv container */
+ if (!bcm_valid_xtlv(val_xtlv, hc_len, no_pad)) {
+ printf("idauth peer_info: return XTLV specifies length %u too long "
+ "for containing xtlv len %u\n",
+ val_len, hc_len);
+ return BCME_ERROR;
+ }
+
+ if (val_len == 0) {
+ printf("idauth peer_info: return value XTLV (id:%u) empty\n", val_id);
+ return BCME_OK;
+ }
+
+ /* print as words if multiple of word size, otherwise hexdump */
+ w = (auth_peer_t*)val_xtlv->data;
+ for (idx = 0; idx * sizeof(auth_peer_t) < val_xtlv->len; idx++) {
+ switch (w[idx].state) {
+ case WL_AUTH_PEER_STATE_AUTHORISED:
+ printf("STA %s\tState:%s\tBlacklist Age:%d\n",
+ wl_ether_etoa(&w[idx].peer_addr), "AUTHORIZED", 0);
+ break;
+ case WL_AUTH_PEER_STATE_BLACKLISTED:
+ printf("STA %s\tState:%s\tBlacklist Age:%d\n",
+ wl_ether_etoa(&w[idx].peer_addr), "BLACKLISTED",
+ w[idx].blklist_end_time);
+ break;
+ case WL_AUTH_PEER_STATE_4WAY_HS_ONGOING:
+ printf("STA %s\tState:%s\tBlacklist Age:%d\n",
+ wl_ether_etoa(&w[idx].peer_addr), "4WAY_HS_ONGOING", 0);
+ break;
+ default:
+ printf("idauth peer info: unknown state\n");
+ }
+ }
+ return (ret);
+}
+
+static int
+fsize(void *fp)
+{
+ long size = BCME_ERROR;
+ long cur_offset = BCME_ERROR;
+
+ if ((cur_offset = ftell(fp)) < 0) {
+ fprintf(stderr, "Could not determine current file offset : %s\n", strerror(errno));
+ return BCME_ERROR;
+ }
+
+ if (!fseek(fp, 0, SEEK_END)) {
+ if ((size = ftell(fp)) < 0)
+ fprintf(stderr, "Could not determine file size : %s\n", strerror(errno));
+
+ fseek(fp, cur_offset, SEEK_SET);
+ }
+ else
+ fprintf(stderr, "Error in performing fseek: %s\n", strerror(errno));
+
+ return (int)size;
+}
+
+static int
+wl_wake_timer(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen;
+ wake_timer_t *w_timer;
+ char *endptr;
+
+ buflen = sprintf(buf, "%s", *argv) + 1;
+
+ if (*++(argv) == NULL) {
+ buf[buflen] = '\0';
+ err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN);
+ if (err < 0)
+ return err;
+ w_timer = (wake_timer_t *)buf;
+ if (dtoh16(w_timer->ver) != WAKE_TIMER_VERSION) {
+ err = BCME_VERSION;
+ return err;
+ }
+ printf("Status:%s\n", dtoh16(w_timer->limit) ? "ENABLED": "DISABLED");
+ printf("Num of events delivered:%d\n", dtoh16(w_timer->count));
+ return 0;
+ } else {
+ w_timer = (wake_timer_t *) (buf + buflen);
+ buflen += sizeof(wake_timer_t);
+
+ w_timer->period = htod16(strtoul(*argv, &endptr, 0));
+
+ if (*endptr != '\0') {
+ fprintf(stderr, "Type '%s' not a number?\n", *argv);
+ return BCME_ERROR;
+ }
+ if (*++(argv) == NULL) {
+ printf("Missing arg <limit>\n");
+ goto usage;
+ }
+ w_timer->limit = htod16(strtoul(*argv, &endptr, 0));
+ if (*endptr != '\0') {
+ fprintf(stderr, "Type '%s' not a number?\n", *argv);
+ return BCME_ERROR;
+ }
+ if (*++(argv)) {
+ printf("extra arguments\n");
+ goto usage;
+ }
+ w_timer->ver = htod16(WAKE_TIMER_VERSION);
+ w_timer->len = htod16(sizeof(wake_timer_t));
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+ }
+usage:
+ printf("Usage: wl wake_timer <period> <limit>\n");
+ return 0;
+}
+
+static int
+wl_utrace_capture(void *wl, cmd_t *cmd, char **argv)
+{
+ void *buff = NULL;
+ uint16 *ptr = NULL;
+ uint j;
+ FILE *fptr = NULL;
+ uint32 capture_args_size = 0;
+ uchar rev_2 = FALSE;
+ int err = BCME_ERROR;
+ uint32 flag = WLC_UTRACE_MORE_DATA;
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ /* Use _v1 version of structure for DINGO and other legacy chips and _v2 for newer chips. */
+ if (wlc_ver_major(wl) <= 5) {
+ /* Handle Legacy chips and chips from DINGO2 */
+ capture_args_size = sizeof(wl_utrace_capture_args_v1_t);
+ rev_2 = FALSE;
+ } else {
+ capture_args_size = sizeof(wl_utrace_capture_args_v2_t);
+ rev_2 = TRUE;
+ }
+
+ fptr = fopen("utrace.txt", "w");
+ if (fptr == NULL) {
+ return BCME_NORESOURCE;
+ }
+ buff = malloc(WLC_UTRACE_LEN + capture_args_size);
+ if (buff == NULL) {
+ fclose(fptr);
+ return BCME_NOMEM;
+ }
+ memset(buff, 0, WLC_UTRACE_LEN + capture_args_size);
+
+ do {
+ if ((err = wlu_iovar_getbuf(wl, cmd->name,
+ buff, 0, buff, (WLC_UTRACE_LEN + capture_args_size))) < 0)
+ {
+ goto exit;
+ }
+ if (rev_2 == TRUE) {
+ wl_utrace_capture_args_v2_t *capture_args;
+ capture_args = (wl_utrace_capture_args_v2_t *) buff;
+ flag = capture_args->flag;
+ /* Check the structure rev */
+ if (capture_args->version == UTRACE_CAPTURE_VER_2) {
+ capture_args->length -= capture_args_size;
+ ptr = (uint16 *) ((uchar*)buff + capture_args_size);
+ for (j = 0; j < capture_args->length/sizeof(uint32); j++) {
+ fprintf(fptr, "%04x %04x \n", ptr[j*2 + 1], ptr[j*2]);
+ }
+ } else {
+ err = BCME_VERSION;
+ flag = WLC_UTRACE_READ_END;
+ printf("Error:Version Mismatch App:%d FW:%d\n",
+ UTRACE_CAPTURE_VER_2, capture_args->version);
+ break;
+ }
+ } else {
+ wl_utrace_capture_args_v1_t *capture_args;
+ capture_args = (wl_utrace_capture_args_v1_t *) buff;
+ flag = capture_args->flag;
+ ptr = (uint16 *) ((uchar*)buff + capture_args_size);
+ for (j = 0; j < capture_args->length/sizeof(uint32); j++) {
+ fprintf(fptr, "%04x %04x \n", ptr[j*2 + 1], ptr[j*2]);
+ }
+
+ }
+ } while (flag == WLC_UTRACE_MORE_DATA);
+
+exit:
+ free(buff);
+ fclose(fptr);
+ return err;
+
+}
+
+static int
+wl_wds_ap_ifname(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+
+ UNUSED_PARAMETER(argv);
+
+ memset(buf, 0, WLC_IOCTL_SMLEN);
+
+ /* query for 'wds_ap_ifname' to get ap ifname */
+ ret = wlu_iovar_get(wl, cmd->name, buf, WLC_IOCTL_SMLEN);
+ buf[WLC_IOCTL_SMLEN -1] = '\0';
+
+ /* if the query is successful, continue on and print the result. */
+ if (ret) {
+ return ret;
+ }
+
+ printf("%s\n", buf);
+ return ret;
+}
+static int
+wl_netx_ifconfig(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ struct ipv4_addr ipa_set;
+ netx_ifconfig_t ifconfig;
+ uint8 *bufptr;
+
+ int i;
+ int argc;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc == 4) {
+ /* Add host addresses, a list of ip, netmask, gateway */
+ bufptr = (uint8*)&ifconfig;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (!wl_atoip(argv[i], &ipa_set))
+ return BCME_USAGE_ERROR;
+ memcpy(bufptr, &ipa_set.addr[0], IPV4_ADDR_LEN);
+ bufptr += IPV4_ADDR_LEN;
+ }
+ return wlu_var_setbuf(wl, cmd->name, &ifconfig, sizeof(ifconfig));
+ }
+ else {
+ void *ptr = NULL;
+ netx_ifconfig_t *if_get;
+ if ((ret = wlu_var_getbuf(wl, cmd->name, &ifconfig, sizeof(ifconfig), &ptr)) < 0)
+ return ret;
+
+ if_get = (netx_ifconfig_t *)ptr;
+ printf("ip: %s ", wl_iptoa((struct ipv4_addr *)&if_get->ipaddr));
+ printf("netmask: %s ", wl_iptoa((struct ipv4_addr *)&if_get->ipaddr_netmask));
+ printf("gw: %s\n", wl_iptoa((struct ipv4_addr *)&if_get->ipaddr_gateway));
+ }
+
+ return 0;
+}
+
+#ifdef TBTT_OFFSET_STAT
+static int
+wl_tbtt_offset_stat(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ tbtt_offset_stat_t *tbtt_offset_stat = NULL;
+
+ UNUSED_PARAMETER(argv);
+
+ /* Get only */
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, (void **)(&tbtt_offset_stat))) < 0)
+ return (ret);
+
+ printf("avg: %d\nmin: %d\nmax: %d\n",
+ dtoh32(tbtt_offset_stat->tbtt_offset_avg),
+ dtoh32(tbtt_offset_stat->tbtt_offset_min),
+ dtoh32(tbtt_offset_stat->tbtt_offset_max));
+
+ return 0;
+}
+#endif /* TBTT_OFFSET_STAT */
diff --git a/wl/src/wl/exe/wlu.h b/wl/src/wl/exe/wlu.h
new file mode 100644
index 0000000..bd4721a
--- /dev/null
+++ b/wl/src/wl/exe/wlu.h
@@ -0,0 +1,371 @@
+/*
+ * Common code for wl command line utility
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
+ * the contents of this file may not be disclosed to third parties, copied or
+ * duplicated in any form, in whole or in part, without the prior written
+ * permission of Broadcom Corporation.
+ *
+ * $Id: wlu.h 660248 2016-09-19 21:45:03Z $
+ */
+
+#ifndef _wlu_h_
+#define _wlu_h_
+
+#include <proto/bcmipv6.h>
+#include "wlu_cmd.h"
+
+#if defined(__FreeBSD__)
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#endif
+
+typedef struct {
+ uint value;
+ const char *string;
+} dbg_msg_t;
+
+typedef struct {
+ int8 pwr2p5;
+ int8 pwr5;
+ int8 pwr10;
+ int8 pwr20;
+ int8 pwr40;
+ int8 pwr20in40;
+ int8 pwr80;
+ int8 pwr20in80;
+ int8 pwr40in80;
+ int8 pwr160;
+ int8 pwr20in160;
+ int8 pwr40in160;
+ int8 pwr80in160;
+ int8 pwr8080;
+ int8 pwr8080chan2;
+ int8 pwr20in8080;
+ int8 pwr40in8080;
+ int8 pwr80in8080;
+} txpwr_row_t;
+
+extern const char *wlu_av0;
+extern int g_wlc_idx;
+
+struct escan_bss {
+ struct escan_bss *next;
+ wl_bss_info_t bss[1];
+};
+
+/* parse common option */
+extern int wl_option(char ***pargv, char **pifname, int *phelp);
+extern void wl_cmd_init(void);
+extern void wlu_init(void);
+
+/* print usage */
+extern void wl_cmd_usage(FILE *fid, cmd_t *cmd);
+extern void wl_usage(FILE *fid, cmd_t *port_cmds);
+extern void wl_cmds_usage(FILE *fid, cmd_t *port_cmds);
+
+/* print helpers */
+extern void wl_printlasterror(void *wl);
+extern void wl_printint(int val);
+
+/* pretty print an SSID */
+extern int wl_format_ssid(char* buf, uint8* ssid, int ssid_len);
+
+/* pretty hex print a contiguous buffer */
+extern void wl_hexdump(uchar *buf, uint nbytes);
+
+/* check driver version */
+extern int wl_check(void *wl);
+
+/* returns major version from "wlc_ver" command */
+extern int wlc_ver_major(void * wl);
+
+extern int wlu_bssiovar_setbuf(void* wl, const char *iovar, int bssidx,
+ void *param, int paramlen, void *bufptr, int buflen);
+extern int wlu_var_getbuf(void *wl, const char *iovar,
+ void *param, int param_len, void **bufptr);
+extern int wlu_var_getbuf_sm(void *wl, const char *iovar,
+ void *param, int param_len, void **bufptr);
+extern int wlu_var_getbuf_med(void *wl, const char *iovar,
+ void *param, int param_len, void **bufptr);
+extern int wlu_var_setbuf_sm(void *wl, const char *iovar,
+ void *param, int param_len);
+extern int wl_parse_ssid_list(char* list_str, wlc_ssid_t* ssid, int idx, int max);
+extern void dump_bss_info(wl_bss_info_t *bi);
+extern cmd_func_t wl_void;
+extern cmd_func_t wl_var_void;
+extern cmd_func_t wl_var_setint;
+extern cmd_func_t wl_var_get;
+extern cmd_func_t wl_var_getandprintstr;
+extern cmd_func_t wl_reg;
+extern cmd_func_t wl_phy_rate;
+extern cmd_func_t wl_ssid;
+extern cmd_func_t wl_iov_mac;
+extern cmd_func_t wl_sta_info;
+extern cmd_func_t wl_seq_start;
+extern cmd_func_t wl_seq_stop;
+extern cmd_func_t wl_hostip;
+extern cmd_func_t wl_hostipv6;
+extern cmd_func_t wl_offload_cmpnt;
+extern cmd_func_t wl_mkeep_alive;
+extern cmd_func_t wl_bsscfg_int;
+extern cmd_func_t wlu_srwrite;
+extern cmd_func_t wlu_reg2args;
+extern cmd_func_t wl_macaddr;
+extern cmd_func_t wl_maclist;
+extern cmd_func_t wl_bcm_config;
+
+extern int ARGCNT(char **argv);
+
+/* return global ioctl_version */
+extern int wl_get_ioctl_version(void);
+/* return the address of bufstruct_wlu, global buf */
+extern char *wl_get_buf(void);
+
+extern int wl_cfg_option(char **argv, const char *fn_name, int *bsscfg_idx, int *consumed);
+extern int wl_scan_prep(void *wl, cmd_t *cmd, char **argv,
+ wl_scan_params_t *params, int *params_size);
+extern chanspec_t wl_chspec_to_driver(chanspec_t chanspec);
+extern chanspec_t wl_chspec_from_driver(chanspec_t chanspec);
+extern uint32 wl_chspec32_to_driver(chanspec_t chanspec);
+extern chanspec_t wl_chspec32_from_driver(uint32 chanspec32);
+extern int wl_parse_channel_list(char* list_str, uint16* channel_list, int channel_num);
+/* return TRUE if all the values in the array are uniformly the same */
+extern int wl_array_uniform(uint8 *pwr, int start, int count);
+extern void wl_txpwr_print_header(int8 channel_bandwidth, bool verbose);
+extern void wl_txpwr_print_row(const char *label, uint8 chains, txpwr_row_t powers,
+ int8 unsupported_rate, int8 channel_bandwidth, bool verbose);
+extern int get_ie_data(uchar *data_str, uchar *ie_data, int len);
+extern int get_oui_bytes(uchar *oui_str, uchar *oui);
+
+
+/* Format a ratespec for output of any of the wl_rate() iovars */
+extern char* wl_rate_print(char *rate_buf, uint32 rspec);
+/* convert rate string in Mbit/s format, like "11", "5.5", to internal 500 Kbit/s units */
+extern int rate_string2int(char *s);
+/* convert rate internal 500 Kbits/s units to string in Mbits/s format, like "11", "5.5" */
+extern char* rate_int2string(char *rate_buf, int val);
+extern void wl_print_mcsset(char *mcsset);
+
+extern int wl_parse_chanspec_list(char* list_str, chanspec_t *chanspec_list, int chanspec_num);
+extern int hexstr2hex(char *str);
+extern char* find_pattern(char **argv, const char *pattern, uint *val);
+extern char* find_pattern2(char **argv, const char *pattern, uint *val, int vnum);
+extern int wl_atoipv6(const char *a, struct ipv6_addr *n);
+extern char * wl_ipv6toa(const void *ipv6);
+extern int wlu_reg3args(void *wl, cmd_t *cmd, char **argv);
+extern int parse_wep(char **argv, wl_wsec_key_t *key, bool options);
+
+/* Convert user's input in hex pattern to byte-size mask */
+extern int wl_pattern_atoh(char *src, char *dst);
+
+/* register commands for a module */
+extern void wl_module_cmds_register(cmd_t *cmds);
+
+extern cmd_t *wlu_find_cmd(char *name);
+
+/* wluc_module init functions */
+extern void wluc_phy_module_init(void);
+extern void wluc_wnm_module_init(void);
+extern void wluc_cac_module_init(void);
+extern void wluc_rmc_module_init(void);
+extern void wluc_rrm_module_init(void);
+extern void wluc_wowl_module_init(void);
+extern void wluc_nan_module_init(void);
+extern void wluc_ap_module_init(void);
+extern void wluc_ampdu_module_init(void);
+extern void wluc_ampdu_cmn_module_init(void);
+extern void wluc_bmac_module_init(void);
+extern void wluc_ht_module_init(void);
+extern void wluc_wds_module_init(void);
+extern void wluc_keymgmt_module_init(void);
+extern void wluc_scan_module_init(void);
+extern void wluc_obss_module_init(void);
+extern void wluc_prot_obss_module_init(void);
+extern void wluc_lq_module_init(void);
+extern void wluc_seq_cmds_module_init(void);
+extern void wluc_btcx_module_init(void);
+extern void wluc_led_module_init(void);
+extern void wluc_interfere_module_init(void);
+extern void wluc_ltecx_module_init(void);
+extern void wluc_extlog_module_init(void);
+extern void wluc_pkt_filter_module_init(void);
+extern void wluc_mfp_module_init(void);
+extern void wluc_ota_module_init(void);
+extern void wluc_bssload_module_init(void);
+extern void wluc_sdio_module_init(void);
+extern void wluc_stf_module_init(void);
+extern void wluc_offloads_module_init(void);
+extern void wluc_tpc_module_init(void);
+extern void wluc_toe_module_init(void);
+extern void wluc_arpoe_module_init(void);
+extern void wluc_ndoe_module_init(void);
+extern void wluc_keep_alive_module_init(void);
+extern void wluc_pfn_module_init(void);
+extern void wluc_tbow_module_init(void);
+extern void wluc_p2p_module_init(void);
+extern void wluc_tdls_module_init(void);
+extern void wluc_trf_mgmt_module_init(void);
+extern void wluc_proxd_module_init(void);
+extern void wluc_p2po_module_init(void);
+extern void wluc_anqpo_module_init(void);
+extern void wluc_btcdyn_module_init(void);
+extern void wluc_mesh_module_init(void);
+extern void wluc_msch_module_init(void);
+extern void wluc_bdo_module_init(void);
+extern void wluc_randmac_module_init(void);
+extern void wluc_tko_module_init(void);
+extern void wluc_natoe_module_init(void);
+extern void wluc_rsdb_module_init(void);
+extern void wluc_he_module_init(void);
+extern void wluc_mbo_module_init(void);
+extern void wluc_hoffload_module_init(void);
+
+extern void wluc_ecounters_module_init(void);
+extern int hexstrtobitvec(const char *cp, uchar *bitvec, int veclen);
+
+extern int get_counter_offset(char *name, uint32 *offset, uint8 counter_ver);
+extern int print_counter_help(uint8 counter_ver);
+
+/* wl functions used by the ndis wl. */
+extern void dump_rateset(uint8 *rates, uint count);
+extern uint freq2channel(uint freq);
+extern int wl_ether_atoe(const char *a, struct ether_addr *n);
+extern char *wl_ether_etoa(const struct ether_addr *n);
+struct ipv4_addr; /* forward declaration */
+extern int wl_atoip(const char *a, struct ipv4_addr *n);
+extern char *wl_iptoa(const struct ipv4_addr *n);
+extern cmd_func_t wl_int;
+extern cmd_func_t wl_varint;
+extern void wl_dump_raw_ie(bcm_tlv_t *ie, uint len);
+extern int wl_mk_ie_setbuf(const char *command, uint32 pktflag_ok, char **argv,
+ vndr_ie_setbuf_t **buf, int *buf_len);
+extern cmd_func_t wl_list_ie;
+
+extern void wl_printlasterror(void *wl);
+extern bool wc_cmd_check(const char *cmd);
+
+#if defined(WL_NAN)
+extern int wl_nan_do_get_ioctl(void *wl, void *nanioc, uint16 iocsz);
+#endif
+
+#define WL_IOV_BATCH_DELIMITER "+"
+
+
+/* functions for downloading firmware to a device via serial or other transport */
+#ifdef SERDOWNLOAD
+extern int dhd_init(void *dhd, cmd_t *cmd, char **argv);
+extern int dhd_download(void *dhd, cmd_t *cmd, char **argv);
+extern int rwl_download(void *dhd, cmd_t *cmd, char **argv);
+#endif /* SERDOWNLOAD */
+
+#ifdef BCMDLL
+#ifdef LOCAL
+extern FILE *dll_fd;
+#else
+extern void * dll_fd_out;
+extern void * dll_fd_in;
+#endif
+#undef printf
+#undef fprintf
+#define printf printf_to_fprintf /* printf to stdout */
+#define fprintf fprintf_to_fprintf /* fprintf to stderr */
+extern void fprintf_to_fprintf(FILE * stderror, const char *fmt, ...);
+extern void printf_to_fprintf(const char *fmt, ...);
+extern void raw_puts(const char *buf, void *dll_fd_out);
+#define fputs(buf, stdout) raw_puts(buf, dll_fd_out)
+#endif /* BCMDLL */
+
+#define PRNL() pbuf += sprintf(pbuf, "\n")
+
+#define RAM_SIZE_4325 0x60000
+#define RAM_SIZE_4329 0x48000
+#define RAM_SIZE_43291 0x60000
+#define RAM_SIZE_4330_a1 0x3c000
+#define RAM_SIZE_4330_b0 0x48000
+
+#define SROM_PAVAR 21
+
+/* useful macros */
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
+#endif /* ARRAYSIZE */
+
+/* buffer length needed for wl_format_ssid
+ * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL
+ */
+#ifndef SSID_FMT_BUF_LEN
+#define SSID_FMT_BUF_LEN (4*32+1) /* Length for SSID format string */
+#endif
+
+/* some OSes (FC4) have trouble allocating (kmalloc) 128KB worth of memory,
+ * hence keeping WL_DUMP_BUF_LEN below that
+ */
+#if !defined(WL_DUMP_BUF_LEN)
+#if defined(BWL_SMALL_WLU_DUMP_BUF)
+#define WL_DUMP_BUF_LEN (4 * 1024)
+#else
+#define WL_DUMP_BUF_LEN (127 * 1024)
+#endif
+#endif /* WL_DUMP_BUF_LEN */
+
+#ifdef linux
+#define ESCAN_EVENTS_BUFFER_SIZE 2048
+#endif /* linux */
+
+#define CMDLINESZ 80
+#define USAGE_ERROR -1 /* Error code for Usage */
+#define CMD_DEPRECATED -4 /* Commands that are functionally deprecated or don't provide
+ * a useful value to a specific OS port of wl
+ */
+
+/* integer output format */
+#define INT_FMT_DEC 0 /* signed integer */
+#define INT_FMT_UINT 1 /* unsigned integer */
+#define INT_FMT_HEX 2 /* hexdecimal */
+
+#define DIV_QUO(num, div) ((num)/div) /* Return the quotient of division to avoid floats */
+#define DIV_REM(num, div) (((num%div) * 100)/div) /* Return the remainder of division */
+
+/* command line argument usage */
+#define CMD_ERR -1 /* Error for command */
+#define CMD_OPT 0 /* a command line option */
+#define CMD_WL 1 /* the start of a wl command */
+
+#define LED_MAX_INDEX 16 /* index limitation for cmd ledbh */
+
+#define SCAN_USAGE "" \
+"\tDefault to an active scan across all channels for any SSID.\n" \
+"\tOptional arg: SSIDs, list of [up to 10] SSIDs to scan (comma or space separated).\n" \
+"\tOptions:\n" \
+"\t-s S, --ssid=S\t\tSSIDs to scan\n" \
+"\t-t ST, --scan_type=ST\t[active|passive|prohibit|offchan|hotspot] scan type\n" \
+"\t--bss_type=BT\t\t[bss/infra|ibss/adhoc] bss type to scan\n" \
+"\t-b MAC, --bssid=MAC\tparticular BSSID MAC address to scan, xx:xx:xx:xx:xx:xx\n" \
+"\t-n N, --nprobes=N\tnumber of probes per scanned channel\n" \
+"\t-a N, --active=N\tdwell time per channel for active scanning\n" \
+"\t-p N, --passive=N\tdwell time per channel for passive scanning\n" \
+"\t-h N, --home=N\t\tdwell time for the home channel between channel scans\n" \
+"\t-c L, --chanspecs=L\tcomma or space separated list of chanspecs to scan" \
+
+#define WL_EVENT_TIMEOUT 10 /* Timeout in second for event from driver */
+#define MAX_SUBCOUNTER_SUPPORTED 64 /* Max subcounters supported. */
+
+#define DINGO_FW_REV 0x9000000
+
+int wl_wait_for_event(void *wl, char **argv, uint event_id, uint evbuf_size,
+ void (*event_cb_fn)(int event_type, bcm_event_t *bcm_event));
+
+#endif /* _wlu_h_ */
diff --git a/wl/src/wl/exe/wlu_avail_utils.c b/wl/src/wl/exe/wlu_avail_utils.c
new file mode 100644
index 0000000..a8d961c
--- /dev/null
+++ b/wl/src/wl/exe/wlu_avail_utils.c
@@ -0,0 +1,249 @@
+/*
+ * Availability support functions
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_avail_utils.c abhik$
+ */
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <bcmendian.h>
+#include <wlioctl.h>
+#if defined(__FreeBSD__)
+#include <machine/stdarg.h>
+#include <stdbool.h>
+#else
+#include <stdarg.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <bcmutils.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define stricmp strcmp
+#define strnicmp strncmp
+
+static bool
+wl_get_tmu_from_str(char *str, wl_tmu_t *p_tmu)
+{
+ if (stricmp(str, "tu") == 0)
+ *p_tmu = WL_TMU_TU;
+ else if (stricmp(str, "s") == 0)
+ *p_tmu = WL_TMU_SEC;
+ else if (stricmp(str, "ms") == 0)
+ *p_tmu = WL_TMU_MILLI_SEC;
+ else if (stricmp(str, "us") == 0)
+ *p_tmu = WL_TMU_MICRO_SEC;
+ else if (stricmp(str, "ns") == 0)
+ *p_tmu = WL_TMU_NANO_SEC;
+ else if (stricmp(str, "ps") == 0)
+ *p_tmu = WL_TMU_PICO_SEC;
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+* parse and pack 'chanspec' from a command-line argument
+* Input:
+* arg_channel: a channel-string
+* out_channel: buffer to store the result
+*/
+static int
+wl_parse_channel(char *arg_channel, uint32 *out_channel)
+{
+ int status = BCME_OK;
+ uint32 src_data_channel = 0; /* default: invalid */
+
+ /* note, chanespec_t is currently defined as 16-bit, however */
+ /* wl-interface use 'uint32' to allow future change for 32-bit */
+ if (arg_channel != (char *) NULL)
+ src_data_channel = (uint32) wf_chspec_aton(arg_channel);
+
+ if (src_data_channel == 0) {
+ printf("error: invalid chanspec\n");
+ status = BCME_BADARG;
+ }
+
+ *out_channel = htol32(src_data_channel);
+ return status;
+}
+
+/*
+* parse and pack 'intvl' param-value from a command-line argument
+* Input:
+* arg_intvl: a time-intvl string
+* out_intvl: buffer to store the result
+*/
+static int
+wl_avail_parse_intvl(char *arg_intvl, wl_time_interval_t *out_intvl)
+{
+ wl_time_interval_t src_data_intvl;
+ char *p_end;
+
+ /* initialize */
+ memset(out_intvl, 0, sizeof(*out_intvl));
+
+ if (arg_intvl == (char *) NULL) {
+ printf("error: time-interval value is not specified\n");
+ return BCME_BADARG;
+ }
+
+ errno = 0;
+ memset(&src_data_intvl, 0, sizeof(src_data_intvl));
+ /* time interval e.g. 10ns */
+ /* get the number */
+ p_end = NULL;
+ src_data_intvl.intvl = htol32(strtoul(arg_intvl, &p_end, 10));
+ if (errno) {
+ printf("error: invalid time interval (errno=%d)\n", errno);
+ return BCME_BADARG;
+ }
+
+ /* get time-unit */
+ src_data_intvl.tmu = WL_TMU_TU; /* default */
+ if (*p_end != '\0') {
+ if (!wl_get_tmu_from_str(p_end, &src_data_intvl.tmu)) {
+ printf("error: invalid time-unit %s\n", p_end);
+ return BCME_BADARG;
+ }
+ }
+ src_data_intvl.tmu = htol16(src_data_intvl.tmu);
+
+ /* return to caller */
+ memcpy(out_intvl, &src_data_intvl, sizeof(*out_intvl));
+
+ return BCME_OK;
+}
+
+/*
+* parse and pack one 'slot' param-value from a command-line
+* Input:
+* arg_slot: 'slot' param-value argument string
+* in "channel:start-tmu:duration-tmu" format
+* out_avail_slot: buffer to store the result
+*/
+int
+wl_avail_parse_slot(char *arg_slot, wl_avail_slot_t *out_avail_slot)
+{
+ int arg_idx;
+ const char *tmp_start, *tmp_end;
+ char tmpbuf[128];
+ int len;
+ int status = BCME_OK;
+
+ if (arg_slot == (char *) NULL) {
+ printf("error: slot value is not specified\n");
+ return BCME_BADARG;
+ }
+
+ /* parse channel:start-tmu:duration-tmu */
+ tmp_start = arg_slot;
+ for (arg_idx = 0; arg_idx < 3; arg_idx++) {
+ tmp_end = strchr(tmp_start, ':');
+ if (tmp_end == NULL) {
+ if (arg_idx != 2 || *tmp_start == '\0') {
+ status = BCME_BADARG;
+ goto done;
+ }
+ /* for last 'duration intvl' */
+ tmp_end = tmp_start + strlen(tmp_start);
+ }
+
+ /* create a temp null-terminated substring */
+ if ((len = tmp_end - tmp_start) >= (int) sizeof(tmpbuf)) {
+ status = BCME_BADARG;
+ goto done;
+ }
+
+ memcpy(tmpbuf, tmp_start, len);
+ tmpbuf[len] = '\0'; /* null-terminate */
+
+ if (arg_idx == 0)
+ status = wl_parse_channel(tmpbuf, &out_avail_slot->chanspec);
+ else if (arg_idx == 1)
+ status = wl_avail_parse_intvl(tmpbuf, &out_avail_slot->start);
+ else /* arg_idx == 2 */
+ status = wl_avail_parse_intvl(tmpbuf, &out_avail_slot->duration);
+
+ if (status != BCME_OK)
+ goto done;
+ /* continue on next element */
+ tmp_start = tmp_end + 1;
+
+ }
+done:
+ if (status == BCME_BADARG)
+ printf("error: invalid value for slot\n");
+
+ return status;
+}
+
+/*
+* parse and pack one 'period' param-value from a command-line
+* Input:
+* arg_slot: 'slot' param-value argument string
+* in "channel:start-tmu:duration-tmu:period" format
+* out_avail_slot: buffer to store the result
+*/
+int
+wl_avail_parse_period(char *arg_slot, wl_time_interval_t *out_intvl)
+{
+ int cnt = 0;
+ char *p = arg_slot;
+ int status = BCME_OK;
+ if (p == NULL) {
+ return BCME_BADARG;
+ }
+
+ /* channel:start-tmu:duration-tmu:period */
+ for (; cnt < 3; cnt++) {
+ p = strchr(p, ':');
+ if (!p) {
+ break;
+ }
+ p++;
+ }
+
+ if (p == NULL) {
+ return BCME_BADARG;
+ }
+ status = wl_avail_parse_intvl(p, out_intvl);
+
+ return status;
+}
+
+int
+wl_avail_validate_format(char *arg_slot)
+{
+ /* channel:start-tmu:duration-tmu:period OR
+ * channel:start-tmu:duration-tmu
+ */
+ char *p = arg_slot;
+ int cnt = 0;
+
+ while (p != NULL) {
+ p = strchr(p, ':');
+ if (p == NULL)
+ break;
+ p++;
+ cnt++;
+ }
+
+ if (cnt == 2 || cnt == 3) {
+ return BCME_OK;
+ }
+
+ return BCME_BADARG;
+}
diff --git a/wl/src/wl/exe/wlu_avail_utils.h b/wl/src/wl/exe/wlu_avail_utils.h
new file mode 100644
index 0000000..245edfc
--- /dev/null
+++ b/wl/src/wl/exe/wlu_avail_utils.h
@@ -0,0 +1,24 @@
+/*
+ * Availability support functions
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_avail_utils.h abhik$
+ */
+#ifndef __WLU_AVAIL_UTILS_H___
+#define __WLU_AVAIL_UTILS_H__
+int
+wl_avail_parse_slot(char *arg_slot, wl_avail_slot_t *out_avail_slot);
+int
+wl_avail_parse_period(char *arg_slot, wl_time_interval_t *out_intvl);
+int
+wl_avail_validate_format(char *arg_slot);
+#endif /* __WLU_AVAIL_UTILS_H___ */
diff --git a/wl/src/wl/exe/wlu_client_shared.c b/wl/src/wl/exe/wlu_client_shared.c
new file mode 100644
index 0000000..3113713
--- /dev/null
+++ b/wl/src/wl/exe/wlu_client_shared.c
@@ -0,0 +1,1264 @@
+/*
+ * Common code for remotewl client
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_client_shared.c 545578 2015-04-01 04:21:19Z $
+ */
+#ifdef WIN32
+#define NEED_IR_TYPES
+
+#include <winsock2.h>
+#include <windows.h>
+#include <ntddndis.h>
+#include <epictrl.h>
+#include <irelay.h>
+#include <winioctl.h>
+#include <nuiouser.h>
+#else /* LINUX */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <net/if.h>
+#include <unistd.h>
+#endif /* WIN32 */
+#include <stdio.h>
+#include <stdlib.h>
+#if !defined(__FreeBSD__)
+#include <malloc.h>
+#endif
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <typedefs.h>
+#include <wlioctl.h>
+#include <proto/ethernet.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <bcmcdc.h>
+#include <proto/802.11.h>
+#include <signal.h>
+#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR)
+#include <rwl_wifi.h>
+#endif /* defined(RWL_WIFI) || defined(WIFI_REFLECTOR) */
+#include "wlu.h"
+#include "wlu_remote.h"
+#include "wlu_pipe.h"
+#include "wlu_client_shared.h"
+
+char* remote_vista_cmds[] = {"join", "sup_wpa", "wsec", "set_pmk", "legacylink", "list",
+ "disassoc", "xlist", NULL};
+int vista_cmd_index;
+#define SHELL_CMD_LEN (256)
+
+#ifdef RWL_SOCKET
+extern int validate_server_address();
+static int rwl_socket_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf);
+#endif
+static int rwl_dongle_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf, int cmd);
+#ifdef RWL_WIFI
+static int rwl_wifi_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf);
+#endif
+#if defined(WIN32) || defined(LINUX)
+/* We don't want the server to allocate bigger buffers for some of the commands
+ * like scanresults. Server can still allocate 8K memory and send the response
+ * in fragments. This is used in case of Get commands only.
+ */
+#define SERVER_RESPONSE_MAX_BUF_LEN 8192
+#endif
+
+extern unsigned short g_rwl_servport;
+extern char *g_rwl_servIP;
+int g_child_pid;
+#ifdef RWL_WIFI
+/* dword align allocation */
+static union {
+ char bufdata[WLC_IOCTL_MAXLEN];
+ uint32 alignme;
+} bufstruct_wlu;
+static char *g_rwl_aligned_buf = (char*) &bufstruct_wlu.bufdata;
+
+extern char *g_rwl_buf_mac;
+#endif
+#ifdef RWL_SOCKET
+/* Make initial connection from client to server through sockets */
+static int
+rwl_connect_socket_server(void)
+{
+ int SockDes = -1;
+ struct sockaddr_in servAddr;
+ memset(&servAddr, 0, sizeof(servAddr));
+ if ((SockDes = (*(int *)rwl_open_pipe(remote_type, "\0", 0, 0))) == FAIL)
+ return FAIL;
+ if (!validate_server_address())
+ return FAIL;
+ DPRINT_DBG(OUTPUT, "ServerIP:%s,ServerPort:%d\n", g_rwl_servIP, g_rwl_servport);
+ servAddr.sin_family = AF_INET;
+ servAddr.sin_port = hton16(g_rwl_servport);
+ servAddr.sin_addr.s_addr = inet_addr(g_rwl_servIP);
+
+ if (rwl_sockconnect(SockDes, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
+ rwl_close_pipe(remote_type, (void*) &SockDes);
+ return FAIL;
+ }
+ return SockDes;
+}
+
+/* This routine is used for both Get and Set Ioctls for the socket */
+static int
+rwl_information_socket(void *wl, int cmd, void* input_buf, unsigned long *input_len,
+ unsigned long *tx_len, uint flags)
+{
+ int error, Sockfd;
+ rem_ioctl_t *rem_ptr = NULL;
+
+ if ((Sockfd = rwl_connect_socket_server()) < 0) {
+ DPRINT_ERR(ERR, "Error in getting the Socket Descriptor\n");
+ return FAIL;
+ }
+ wl = (void *)(&Sockfd);
+
+ if (remote_CDC_tx(wl, cmd, input_buf, *input_len,
+ *tx_len, flags, 0) < 0) {
+ DPRINT_ERR(ERR, "query_info_fe: Send command failed\n");
+ rwl_close_pipe(remote_type, wl);
+ return FAIL;
+ }
+
+ if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) {
+ DPRINT_ERR(ERR, "query_info_fe: Reading CDC header failed\n");
+ rwl_close_pipe(remote_type, wl);
+ return FAIL;
+ }
+ rwl_swap_header(rem_ptr, NETWORK_TO_HOST);
+
+ if (rem_ptr->msg.len > *input_len) {
+ DPRINT_ERR(ERR, "query_info_fe: needed size(%d) > "
+ "actual size(%ld)\n", rem_ptr->msg.len, *input_len);
+ rwl_close_pipe(remote_type, wl);
+ return FAIL;
+ }
+
+ if (remote_CDC_rx(wl, rem_ptr, input_buf, *input_len, 0) == FAIL) {
+ DPRINT_ERR(ERR, "query_info_fe: No results!\n");
+ rwl_close_pipe(remote_type, wl);
+ return FAIL;
+ }
+
+ if (rem_ptr->msg.flags & REMOTE_REPLY)
+ error = rem_ptr->msg.cmd;
+ else
+ error = 0;
+
+ rwl_close_pipe(remote_type, wl);
+
+ return error;
+}
+#endif /* RWL_SOCKET */
+/*
+ * Receives the fragmented response from serial server.
+ * Called from rwl_queryinformation_fe front end function for dongle case only when
+ * the client expects data in chunks more than DATA_FRAME_LEN * (960) bytes.
+ */
+static int
+rwl_serial_fragmented_response_fe(void *wl, rem_ioctl_t *rem_ptr, void* input_buf,
+unsigned long *bytes_to_read)
+{
+ int error = 0;
+ uint32 total_numread;
+ uchar *local_buf, *local_result;
+ uint frames_to_read, frame_count;
+
+ DPRINT_DBG(OUTPUT, "rem_ptr->msg.len=%d \t rem_ptr->data_len=%d\n",
+ rem_ptr->msg.len, rem_ptr->data_len);
+
+ /* Calculate the number of frames for the response */
+ if (rem_ptr->data_len == 0) {
+ DPRINT_ERR(ERR, "data_len is:%d\n", rem_ptr->data_len);
+ return (FAIL);
+ }
+ frames_to_read = (*bytes_to_read)/rem_ptr->data_len;
+ if ((*bytes_to_read) % rem_ptr->data_len > 0)
+ frames_to_read += 1;
+
+ DPRINT_DBG(OUTPUT, "No of frames=%d\n", frames_to_read);
+
+ if ((local_result = (uchar*)malloc(rem_ptr->msg.len)) == NULL) {
+ DPRINT_ERR(ERR, "Malloc failed for serial fragmented frame"
+ "local result \n");
+ return FAIL;
+ }
+
+ /* Response will come in DATA_FRAME_LEN + REMOTE_SIZE (960+16) bytes
+ * packet with CDC header and then followed by response.
+ */
+ total_numread = 0;
+ frame_count = 0;
+ while (total_numread != *bytes_to_read) {
+ error = FAIL;
+ local_buf = (uchar*)malloc(rem_ptr->data_len);
+ if (local_buf == NULL) {
+ free(local_result);
+ return FAIL;
+ }
+
+ DPRINT_DBG(OUTPUT, "Total bytes=%d\n", total_numread);
+ DPRINT_DBG(OUTPUT, "Frame (Reverse):%d\n", frames_to_read);
+
+ if (remote_CDC_rx(wl, rem_ptr, local_buf, rem_ptr->data_len, 0) == -1) {
+ free(local_buf);
+ free(local_result);
+ return FAIL;
+ }
+
+ /* Concatenate the response to loc_res. */
+ memcpy(&local_result[frame_count*DATA_FRAME_LEN], local_buf,
+ rem_ptr->data_len);
+
+ total_numread += rem_ptr->data_len;
+ frame_count++;
+ frames_to_read--;
+
+ DPRINT_DBG(OUTPUT, "Total bytes=%d\n", total_numread);
+
+ if (frames_to_read == 0) {
+ /* When all the frames are received copy the data to original buf */
+ memcpy(input_buf, local_result, total_numread);
+ if (rem_ptr->msg.flags & REMOTE_REPLY)
+ error = rem_ptr->msg.cmd;
+ else
+ error = 0;
+ }
+
+ if (total_numread != *bytes_to_read) {
+ /* Receive the next header */
+ if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) {
+ DPRINT_ERR(ERR, "query_info_fe: Reading CDC header failed");
+ }
+ }
+ free(local_buf);
+ }
+ free(local_result);
+ return error;
+}
+
+/* This routine is common to both set and Get Ioctls for the dongle case */
+static int
+rwl_information_dongle(void *wl, int cmd, void* input_buf, unsigned long *input_len,
+ uint tx_len, uint flags)
+{
+ int error;
+ rem_ioctl_t *rem_ptr = NULL;
+
+ if (remote_CDC_tx(wl, cmd, input_buf, *input_len,
+ tx_len, flags, 0) < 0) {
+ DPRINT_ERR(ERR, "query_info_fe: Send command failed\n");
+ return FAIL;
+ }
+
+ /* Get the header */
+ if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) {
+ DPRINT_ERR(ERR, "query_info_fe: Reading CDC header failed\n");
+ return BCME_SERIAL_PORT_ERR;
+ }
+
+ /* Make sure there is enough room */
+ if (rem_ptr->msg.len > *input_len) {
+ DPRINT_DBG(OUTPUT, "query_info_fe: needed size(%d) > actual"
+ "size(%ld)\n", rem_ptr->msg.len, *input_len);
+ return FAIL;
+ }
+
+ /* We can grab short frames all at once. Longer frames (> 960 bytes)
+ * come in fragments.
+ */
+ if (rem_ptr->data_len < DATA_FRAME_LEN) {
+ if (remote_CDC_rx(wl, rem_ptr, input_buf, *input_len, 0) == FAIL) {
+ DPRINT_ERR(ERR, "query_info_fe: No results!\n");
+ return FAIL;
+ }
+ if (rem_ptr->msg.flags & REMOTE_REPLY)
+ error = rem_ptr->msg.cmd;
+ else
+ error = 0;
+ } else {
+ /* rwl_serial_fragmented_response_fe returns either valid number or FAIL.
+ * In any case return the same value to caller
+ */
+ error = rwl_serial_fragmented_response_fe(wl, rem_ptr, input_buf, input_len);
+ }
+ return error;
+}
+/* Handler to signal the reader thread that ctrl-C is pressed */
+volatile sig_atomic_t g_sig_ctrlc = 1;
+void ctrlc_handler(int num)
+{
+ UNUSED_PARAMETER(num);
+ g_sig_ctrlc = 0;
+}
+
+/* Issue shell commands independent of transport type and return result */
+static int
+rwl_shell_information_fe(void *wl, int cmd, uchar* input_buf, unsigned long *input_len)
+{
+ int error = 0, remote_cmd;
+ uchar* resp_buf = NULL;
+ rem_ioctl_t *rem_ptr = NULL;
+
+#ifdef RWL_WIFI
+ char *cbuf, retry;
+ dot11_action_wifi_vendor_specific_t *list;
+#endif
+
+#ifdef RWL_SOCKET
+ int Sockfd;
+#endif
+
+ remote_cmd = REMOTE_SHELL_CMD;
+
+#ifdef RWLASD
+ if (cmd == ASD_CMD)
+ remote_cmd = REMOTE_ASD_CMD;
+#endif
+ if (cmd == VISTA_CMD)
+ remote_cmd = REMOTE_VISTA_CMD;
+
+ switch (remote_type) {
+ case REMOTE_SOCKET:
+#ifdef RWL_SOCKET
+ if ((Sockfd = rwl_connect_socket_server()) < 0) {
+ DPRINT_ERR(ERR, " Error in getting the SocDes\n");
+ return BCME_ERROR;
+ }
+
+ wl = (void *)(&Sockfd);
+ if (remote_CDC_tx(wl, cmd, input_buf, *input_len, *input_len,
+ remote_cmd, 0) < 0) {
+ DPRINT_ERR(ERR, "shell_info_fe: Send command failed\n");
+ rwl_close_pipe(remote_type, wl);
+ return BCME_ERROR;
+ }
+ /* For backward compatibility for ASD, async and kill commands do the
+ * old way
+ */
+ if (remote_cmd == REMOTE_SHELL_CMD && !strstr((char*)input_buf, "%") &&
+ !strstr((char*)input_buf, "kill"))
+ error = rwl_socket_shellresp(wl, rem_ptr, input_buf);
+ else {
+ if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) {
+ DPRINT_ERR(ERR, "shell_info_fe: Receiving CDC"
+ "header failed\n");
+ rwl_close_pipe(remote_type, wl);
+ return FAIL;
+ }
+
+ if ((resp_buf = malloc(rem_ptr->msg.len + 1)) == NULL) {
+ DPRINT_ERR(ERR, "Mem alloc fails\n");
+ rwl_close_pipe(remote_type, wl);
+ return FAIL;
+ }
+
+ if (remote_CDC_rx(wl, rem_ptr, resp_buf,
+ rem_ptr->msg.len, 0) == FAIL) {
+ DPRINT_ERR(ERR, "shell_info_fe: No results!\n");
+ rwl_close_pipe(remote_type, wl);
+ free(resp_buf);
+ return FAIL;
+ }
+
+ /* print the shell result */
+ resp_buf[rem_ptr->msg.len] = '\0';
+ /* The return value of the shell command
+ * will be stored in rem_ptr->msg.cmd
+ * Return that value to the client process
+ */
+ if (rem_ptr->msg.flags & REMOTE_REPLY)
+ error = rem_ptr->msg.cmd;
+ fputs((char*)resp_buf, stdout);
+ }
+ rwl_close_pipe(remote_type, wl);
+#endif /* RWL_SOCKET */
+ break;
+ case REMOTE_DONGLE:
+ case REMOTE_SERIAL:
+ if (remote_CDC_tx(wl, cmd, input_buf, *input_len, *input_len,
+ remote_cmd, 0) < 0) {
+ DPRINT_ERR(ERR, "shell_info_fe: Send command failed\n");
+ return FAIL;
+ }
+
+ /* For backward compatibility for ASD, async and kill commands do the
+ * old way
+ */
+ if (remote_cmd != REMOTE_ASD_CMD && !strstr((char*)input_buf, "%") &&
+ !strstr((char*)input_buf, "kill"))
+ error = rwl_dongle_shellresp(wl, rem_ptr, input_buf, cmd);
+ else {
+ if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) {
+ DPRINT_ERR(ERR, "shell_info_fe:"
+ "Receiving CDC header failed\n");
+ return BCME_SERIAL_PORT_ERR;
+ }
+ rwl_swap_header(rem_ptr, NETWORK_TO_HOST);
+ /* In case of shell or ASD commands the response
+ * size is not known in advance
+ * Hence based on response from the server memory is allocated
+ */
+ if ((resp_buf = malloc(rem_ptr->msg.len + 1)) == NULL) {
+ DPRINT_ERR(ERR, "Mem alloc fails for shell response buffer\n");
+ return FAIL;
+ }
+
+ if (rem_ptr->data_len < DATA_FRAME_LEN) {
+ /* Response comes in one shot not in fragments */
+ if (remote_CDC_rx(wl, rem_ptr, resp_buf,
+ rem_ptr->msg.len, 0) == FAIL) {
+ DPRINT_ERR(ERR, "shell_info_fe: No results!\n");
+ free(resp_buf);
+ return FAIL;
+ }
+ } else {
+ error = rwl_serial_fragmented_response_fe(wl, rem_ptr,
+ resp_buf, (unsigned long *)&(rem_ptr->msg.len));
+ }
+ /* print the shell result */
+ resp_buf[rem_ptr->msg.len] = '\0';
+ /* The return value of the shell command will be stored in rem_ptr->msg.cmd
+ * Return that value to the client process
+ */
+ if (rem_ptr->msg.flags & REMOTE_REPLY)
+ error = rem_ptr->msg.cmd;
+ fputs((char*)resp_buf, stdout);
+ }
+ break;
+
+ case REMOTE_WIFI:
+#ifdef RWL_WIFI
+ /* Unlike dongle or UART case the response for wi-fi comes in single frame.
+ * (CDC header + data). Hence the single read is called for header and data.
+ * If any error in reading then we sleep for some time before retrying.
+ */
+ if ((list = (dot11_action_wifi_vendor_specific_t *)
+ malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) {
+ return FAIL;
+ }
+ if ((rem_ptr = (rem_ioctl_t *)malloc(REMOTE_SIZE)) == NULL) {
+ free(list);
+ return FAIL;
+ }
+
+ if ((cbuf = (char*) malloc(*input_len)) == NULL) {
+ DPRINT_ERR(ERR, "Malloc failed for shell response\n");
+ free(rem_ptr);
+ free(list);
+ return FAIL;
+ }
+
+ /* copy of the original buf is required for retry */
+ memcpy(cbuf, (char*)input_buf, *input_len);
+ for (retry = 0; retry < RWL_WIFI_RETRY; retry++) {
+
+ if ((error = rwl_wifi_purge_actionframes(wl)) < 0) {
+ break;
+ }
+
+ if (remote_CDC_tx(wl, cmd, input_buf, *input_len, *input_len,
+ remote_cmd, 0) < 0) {
+ DPRINT_DBG(OUTPUT, "rwl_shell_information_fe(wifi):"
+ "Send command failed\n");
+ rwl_sleep(RWL_WIFI_RETRY_DELAY);
+ free(rem_ptr);
+ free(list);
+ return FAIL;
+ }
+ /* For backward compatibility for ASD,
+ * async and kill commands do the
+ * old way
+ */
+ if (remote_cmd == REMOTE_SHELL_CMD &&
+ !strstr((char*)input_buf, "%") &&
+ !strstr((char*)input_buf, "kill")) {
+ error = rwl_wifi_shellresp(wl, rem_ptr, input_buf);
+ if (rem_ptr->msg.len == 0)
+ break;
+ }
+ else if (remote_cmd == REMOTE_VISTA_CMD) {
+ if ((error = remote_CDC_DATA_wifi_rx_frag(wl, rem_ptr, 0,
+ NULL, RWL_WIFI_SHELL_CMD)) < 0) {
+ DPRINT_DBG(OUTPUT, "rwl_shell_information_fe(wifi):"
+ "error in reading shell response\n");
+ continue;
+ }
+ if (rem_ptr->msg.flags & REMOTE_REPLY) {
+ error = rem_ptr->msg.cmd;
+ break;
+ } else {
+ rwl_sleep(RWL_WIFI_RETRY_DELAY);
+ continue;
+ }
+ }
+ else {
+ /* ASD commands may take long time to give back
+ * the response (eg: file transfer)
+ */
+ if (remote_cmd == REMOTE_ASD_CMD) {
+ for (;;) {
+ /* copy back the buffer to input buffer */
+ memcpy((char*)input_buf, cbuf, *input_len);
+
+ if ((error = remote_CDC_DATA_wifi_rx_frag(
+ wl, rem_ptr, 0, NULL,
+ RWL_WIFI_SHELL_CMD)) < 0) {
+ DPRINT_DBG(OUTPUT,
+ "rwl_shell_information_fe(wifi):"
+ "err in reading shell response\n");
+ continue;
+ }
+ if (rem_ptr->msg.flags & REMOTE_REPLY) {
+ error = rem_ptr->msg.cmd;
+ retry = RWL_WIFI_RETRY;
+ break;
+ } else {
+ rwl_sleep(RWL_WIFI_RETRY_DELAY);
+ continue;
+ }
+ }
+ }
+ }
+
+ }
+ free(rem_ptr);
+ free(list);
+ if (cbuf != NULL)
+ free(cbuf);
+#endif /* RWL_WIFI */
+ break;
+
+ default:
+ break;
+ } /* End of switch (remote_type) */
+
+ if (resp_buf)
+ free(resp_buf);
+
+ return error;
+}
+
+/* Prepare to issue shell command */
+int
+rwl_shell_cmd_proc(void *wl, char **argv, int cmd)
+{
+ uchar *buff;
+ unsigned long len = SHELL_CMD_LEN;
+ int err;
+ unsigned int cmdlen = 0;
+
+ if ((buff = malloc(SHELL_CMD_LEN)) == NULL) {
+ DPRINT_ERR(ERR, "\n Mem alloc fails for shell cmd buffer\n");
+ return FAIL;
+ }
+
+ memset(buff, 0, SHELL_CMD_LEN);
+ cmdlen = SHELL_CMD_LEN - 1;
+ while (*argv) {
+ strncat((char*)buff, *argv, cmdlen);
+ cmdlen -= strlen(*argv);
+ argv++;
+ if (*argv) {
+ strcat((char*)buff, " "); /* leave space between args */
+ cmdlen--;
+ }
+ if (*argv && cmdlen < (strlen(*argv)))
+ {
+ free(buff);
+ DPRINT_ERR(ERR, "\n Insufficient length for shell cmd buffer\n");
+ return FAIL;
+ }
+ }
+
+ err = rwl_shell_information_fe(wl, cmd, buff, &len);
+ free(buff);
+ return err;
+}
+
+/* transport independent entry point for GET ioctls */
+int
+rwl_queryinformation_fe(void *wl, int cmd, void* input_buf,
+ unsigned long *input_len, int debug, int rem_ioctl_select) {
+ int error = 0;
+ uint tx_len;
+#if defined(RWL_SERIAL) || RWL_WIFI
+ rem_ioctl_t *rem_ptr = NULL;
+#endif
+
+#ifdef RWL_WIFI
+ int retry;
+ char *cinput_buf;
+#endif
+
+ UNUSED_PARAMETER(debug);
+
+ switch (remote_type) {
+ case REMOTE_SOCKET:
+#ifdef RWL_SOCKET
+ /* We don't want the server to allocate bigger buffers
+ * for some of the commands
+ * like scanresults. Server can still allocate 8K memory
+ * and send the response
+ */
+ if ((int)(*input_len) > SERVER_RESPONSE_MAX_BUF_LEN)
+ *input_len = SERVER_RESPONSE_MAX_BUF_LEN;
+ error = rwl_information_socket(wl, cmd, input_buf, input_len,
+ input_len, rem_ioctl_select);
+#endif /* RWL_SOCKET */
+ break;
+
+#ifdef RWL_SERIAL
+ /* System serial transport is not supported in Linux. Only XP */
+ case REMOTE_SERIAL:
+#ifdef SERDOWNLOAD
+ tx_len = MIN(*input_len, SERVER_RESPONSE_MAX_BUF_LEN);
+#else
+ tx_len = MIN(*input_len, 1024);
+#endif
+ /* Time estimate assumes 115K baud */
+ if (*input_len > (1024 *10))
+ /* Multiply by 2. The buffer has to go there and back */
+ DPRINT_DBG(OUTPUT, "Wait time: %lu seconds\n",
+ ((*input_len)+ tx_len) / (115200/8));
+
+ if (remote_CDC_tx(wl, cmd, input_buf, *input_len,
+ tx_len, rem_ioctl_select, debug) < 0) {
+ DPRINT_ERR(ERR, "query_info_fe: Send command failed\n");
+ return FAIL;
+ }
+
+ if ((rem_ptr = remote_CDC_rx_hdr(wl, debug)) == NULL) {
+ DPRINT_ERR(ERR, "query_info_fe: Reading CDC header failed\n");
+ return FAIL;
+ }
+
+ if (rem_ptr->msg.flags != REMOTE_REPLY) {
+ DPRINT_ERR(ERR, "query_info_fe: response format error.\n");
+ return FAIL;
+ }
+ if (rem_ptr->msg.len > *input_len) {
+ DPRINT_ERR(ERR, "query_info_fe: needed size(%d) greater than "
+ "actual size(%lu)\n", rem_ptr->msg.len, *input_len);
+ return FAIL;
+ }
+
+ error = rem_ptr->msg.cmd;
+ if (error != 0)
+ DPRINT_ERR(ERR, "query_info_fe: remote cdc header return "
+ "error code %d\n", error);
+ if (remote_CDC_rx(wl, rem_ptr, input_buf, *input_len, debug) == -1) {
+ DPRINT_ERR(ERR, "query_info_fe: No results!\n");
+ return FAIL;
+ }
+ if (rem_ptr->msg.flags & REMOTE_REPLY)
+ error = rem_ptr->msg.cmd;
+ break;
+
+#endif /* RWL_SERIAL */
+ case REMOTE_DONGLE:
+ /* We don't want the server to allocate bigger buffers
+ * for some of the commands
+ * like scanresults. Server can still allocate 8K
+ *memory and send the response
+ * in fragments.
+ */
+ if ((int)(*input_len) > SERVER_RESPONSE_MAX_BUF_LEN)
+ *input_len = SERVER_RESPONSE_MAX_BUF_LEN;
+
+ /* Actual buffer to be sent should be max 256 bytes as
+ *UART input buffer
+ * is 512 bytes
+ */
+ tx_len = MIN(*input_len, 256);
+ error = rwl_information_dongle(wl, cmd, input_buf, input_len,
+ tx_len, rem_ioctl_select);
+
+ break;
+
+ case REMOTE_WIFI:
+#ifdef RWL_WIFI
+ /* We don't want the server to allocate bigger buffers
+ * for some of the commands
+ * like scanresults. Server can still allocate 8K memory
+ * and send the response
+ * in fragments.
+ */
+ if ((int)(*input_len) > SERVER_RESPONSE_MAX_BUF_LEN)
+ *input_len = SERVER_RESPONSE_MAX_BUF_LEN;
+
+ /* Actual buffer to be sent should be max 960 bytes
+ * as wifi max frame size if 960
+ * and actual data for any command will not exceed 960 bytes
+ */
+ tx_len = MIN(*input_len, RWL_WIFI_FRAG_DATA_SIZE);
+
+ if ((rem_ptr = (rem_ioctl_t *)malloc(REMOTE_SIZE)) == NULL) {
+ return FAIL;
+ }
+ if ((cinput_buf = (char*)malloc(tx_len)) == NULL) {
+ DPRINT_ERR(ERR, "Malloc failed for query information fe"
+ "character buf \n");
+ free(rem_ptr);
+ return FAIL;
+ }
+
+ memcpy(cinput_buf, (char*)input_buf, tx_len); /* Keep a copy of input_buf */
+
+ for (retry = 0; retry < RWL_WIFI_RETRY; retry++) {
+
+ if ((error = rwl_wifi_purge_actionframes(wl)) < 0) {
+ break;
+ }
+
+ if (retry > 3)
+ DPRINT_INFO(OUTPUT, "ir_queryinformation_fe : retry %d"
+ "cmd %d\n", retry, cmd);
+
+ /* copy back the buffer to input buffer */
+ memcpy((char*)input_buf, cinput_buf, tx_len);
+
+ /* Issue the command */
+ if ((error = remote_CDC_wifi_tx(wl, cmd, input_buf,
+ *input_len, tx_len, rem_ioctl_select)) < 0) {
+ DPRINT_DBG(OUTPUT, "query_info_fe: Send command failed\n");
+ rwl_sleep(RWL_WIFI_RETRY_DELAY);
+ continue;
+ }
+
+ if ((error = remote_CDC_DATA_wifi_rx_frag(wl, rem_ptr,
+ *input_len, input_buf, RWL_WIFI_WL_CMD) < 0)) {
+ DPRINT_DBG(OUTPUT, "ir_queryinformation_fe :"
+ "Error in reading the frag bytes\n");
+ rwl_sleep(RWL_WIFI_RETRY_DELAY);
+ continue;
+ }
+
+ if (rem_ptr->msg.flags & REMOTE_REPLY) {
+ error = rem_ptr->msg.cmd;
+ break;
+ } else {
+ rwl_sleep(RWL_WIFI_RETRY_DELAY);
+ }
+ }
+
+ free(rem_ptr);
+ if (cinput_buf)
+ free(cinput_buf);
+ break;
+#endif /* RWL_WIFI */
+ default:
+ DPRINT_ERR(ERR, "rwl_queryinformation_fe: Unknown"
+ "remote_type %d\n", remote_type);
+ break;
+ }
+ return error;
+}
+
+/*
+* This is the front end query function for Set Ioctls. This is used by clients
+for executing Set Ioctls.
+*/
+int
+rwl_setinformation_fe(void *wl, int cmd, void* buf,
+ unsigned long *len, int debug, int rem_ioctl_select) {
+ int error = 0;
+ uint tx_len;
+#if defined(RWL_SERIAL) || RWL_WIFI
+ rem_ioctl_t *rem_ptr = NULL;
+#endif
+
+#ifdef RWL_WIFI
+ dot11_action_wifi_vendor_specific_t *list = NULL;
+ char *cbuf, retry;
+#endif
+
+ UNUSED_PARAMETER(debug);
+
+ switch (remote_type) {
+ case REMOTE_SOCKET:
+#ifdef RWL_SOCKET
+ error = rwl_information_socket(wl, cmd, buf, len, len, rem_ioctl_select);
+#endif
+ break;
+#ifdef RWL_SERIAL
+ case REMOTE_SERIAL:
+ if (*len > (1024 *10))
+ DPRINT_DBG(OUTPUT, "Wait time: %lu seconds\n", (*len)/(115200/8));
+
+ if (remote_CDC_tx(wl, cmd, buf, *len, *len, rem_ioctl_select, debug) < 0) {
+ DPRINT_ERR(ERR, "set_info_fe: Send command failed\n");
+ return FAIL;
+ }
+
+ if ((rem_ptr = remote_CDC_rx_hdr(wl, debug)) == NULL) {
+ DPRINT_ERR(ERR, "set_info_fe: Reading CDC header failed\n");
+ return FAIL;
+ }
+
+ if (rem_ptr->msg.flags != REMOTE_REPLY) {
+ DPRINT_ERR(ERR, "set_info_fe: response format error.\n");
+ return FAIL;
+ }
+
+ if (rem_ptr->msg.len > *len) {
+ DPRINT_ERR(ERR, "set_info_fe: needed size (%d) greater than "
+ "actual size (%lu)\n", rem_ptr->msg.len, *len);
+ return FAIL;
+ }
+
+ error = rem_ptr->msg.cmd;
+ if (error != 0) {
+ DPRINT_ERR(ERR, "set_info_fe: remote cdc header return "
+ "error code (%d)\n", error);
+ }
+
+ if (remote_CDC_rx(wl, rem_ptr, buf, rem_ptr->msg.len, debug) == -1) {
+ DPRINT_ERR(ERR, "set_info_fe: fetching results failed\n");
+ return FAIL;
+ }
+
+ if (rem_ptr->msg.flags & REMOTE_REPLY)
+ error = rem_ptr->msg.cmd;
+ break;
+#endif /* RWL_SERIAL */
+ case REMOTE_DONGLE:
+ if ((int)(*len) > SERVER_RESPONSE_MAX_BUF_LEN)
+ *len = SERVER_RESPONSE_MAX_BUF_LEN;
+
+ /* Actual buffer to be sent should be max 256 bytes as
+ *UART input buffer
+ * is 512 bytes
+ */
+ tx_len = MIN(*len, 512);
+ error = rwl_information_dongle(wl, cmd, buf, len, tx_len, rem_ioctl_select);
+ break;
+
+ case REMOTE_WIFI:
+#ifdef RWL_WIFI
+ if ((int)(*len) > SERVER_RESPONSE_MAX_BUF_LEN)
+ *len = SERVER_RESPONSE_MAX_BUF_LEN;
+
+ /* Actual buffer to be sent should be max 960 bytes
+ * as wifi max frame size if 960
+ * and actual data for any command will not exceed 960 bytes
+ */
+ tx_len = MIN(*len, RWL_WIFI_FRAG_DATA_SIZE);
+
+ if ((cbuf = (char*) malloc(tx_len)) == NULL) {
+ DPRINT_ERR(ERR, "Malloc failed for set_info_fe character buf\n");
+ return FAIL;
+ }
+ if ((list = (dot11_action_wifi_vendor_specific_t *)
+ malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) {
+ free(cbuf);
+ return FAIL;
+ }
+
+ if ((rem_ptr = (rem_ioctl_t *)malloc(sizeof(rem_ioctl_t))) == NULL) {
+ free(list);
+ free(cbuf);
+ return FAIL;
+ }
+
+ memcpy(cbuf, (char*)buf, tx_len);
+
+ for (retry = 0; retry < RWL_WIFI_RETRY; retry++) {
+
+ if ((error = rwl_wifi_purge_actionframes(wl)) < 0) {
+ break;
+ }
+
+ /* copy back the buffer to input buffer */
+ memcpy((char*)buf, (char*)cbuf, tx_len);
+
+ if (retry > 3)
+ DPRINT_INFO(OUTPUT, "retry %d cmd %d\n", retry, cmd);
+
+ if ((error = remote_CDC_wifi_tx(wl, cmd, buf, *len,
+ tx_len, rem_ioctl_select) < 0)) {
+ DPRINT_ERR(ERR, "ir_setinformation_fe: Send"
+ "command failed\n");
+ rwl_sleep(RWL_WIFI_RETRY_DELAY);
+ continue;
+ }
+
+ if ((char*)buf != NULL) {
+ /* In case cmd is findserver, response is not
+ * required from the server
+ */
+ if (!strcmp((char*)buf, RWL_WIFI_FIND_SER_CMD)) {
+ break;
+ }
+ }
+
+ /* Read the CDC header and data of for the sent cmd
+ * resposne
+ */
+ if ((error = remote_CDC_DATA_wifi_rx((void*)wl, list) < 0)) {
+ DPRINT_ERR(ERR, "ir_setinformation_fe: failed to read"
+ "the response\n");
+ rwl_sleep(RWL_WIFI_RETRY_DELAY);
+ continue;
+ }
+
+ memcpy((char*)rem_ptr,
+ (char*)&list->data[RWL_WIFI_CDC_HEADER_OFFSET],
+ REMOTE_SIZE);
+ rwl_swap_header(rem_ptr, NETWORK_TO_HOST);
+
+ memcpy((char*)buf, (char*)&list->data[REMOTE_SIZE],
+ rem_ptr->msg.len);
+
+ if (rem_ptr->msg.flags & REMOTE_REPLY) {
+ error = rem_ptr->msg.cmd;
+ break;
+ } else {
+ rwl_sleep(RWL_WIFI_RETRY_DELAY);
+ }
+ }
+ free(rem_ptr);
+ free(list);
+ if (cbuf != NULL)
+ free(cbuf);
+ break;
+#endif /* RWL_WIFI */
+ default:
+ DPRINT_ERR(ERR, "rwl_setinformation_fe: Unknown remote_type:%d\n",
+ remote_type);
+ break;
+ }
+
+ return error;
+}
+
+#ifdef RWL_WIFI
+int
+rwl_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr)
+{
+ int len, error;
+
+ memset((char*)g_rwl_aligned_buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(g_rwl_aligned_buf, iovar);
+
+ /* include the null */
+ len = (int)strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy(&g_rwl_aligned_buf[len], param, param_len);
+
+ *bufptr = g_rwl_aligned_buf;
+ /* When user wants to execute local CMD being in remote wifi mode,
+ * rwl_wifi_swap_remote_type fucntion is used to change the remote types.
+ */
+ rwl_wifi_swap_remote_type(remote_type);
+
+ error = wl_get(wl, WLC_GET_VAR, &g_rwl_aligned_buf[0], WLC_IOCTL_MAXLEN);
+ /* revert back to the old remote type */
+ rwl_wifi_swap_remote_type(remote_type);
+ return error;
+}
+
+int
+rwl_var_setbuf(void *wl, const char *iovar, void *param, int param_len)
+{
+ int len, error;
+
+ memset(g_rwl_aligned_buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(g_rwl_aligned_buf, iovar);
+
+ /* include the null */
+ len = (int)strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy(&g_rwl_aligned_buf[len], param, param_len);
+
+ len += param_len;
+ /* When user wants to execute local CMD being in remote wifi mode,
+ * rwl_wifi_swap_remote_type fucntion is used to change the remote types.
+ */
+ rwl_wifi_swap_remote_type(remote_type);
+ error = wl_set(wl, WLC_SET_VAR, &g_rwl_aligned_buf[0], len);
+ /* revert back to the old type */
+ rwl_wifi_swap_remote_type(remote_type);
+ return error;
+}
+
+/* This function will send the buffer to the dongle driver */
+int
+rwl_var_send_vs_actionframe(void* wl, const char* iovar, void* param, int param_len)
+{
+ int len, error;
+
+ memset(g_rwl_aligned_buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(g_rwl_aligned_buf, iovar);
+
+ /* include the null */
+ len = (int)strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy((void*)&g_rwl_aligned_buf[len+ OFFSETOF(wl_action_frame_t, data)],
+ param,
+ param_len);
+
+ /* Set the PacketID (not used by remote WL */
+ memset((void*)&g_rwl_aligned_buf[len + OFFSETOF(wl_action_frame_t, packetId)], 0, 4);
+
+ /* Set the dest addr */
+ memcpy((void*)&g_rwl_aligned_buf[len + OFFSETOF(wl_action_frame_t, da)],
+ (void*)g_rwl_buf_mac,
+ ETHER_ADDR_LEN);
+
+ /* set the length */
+ memcpy((void*)&g_rwl_aligned_buf[len + OFFSETOF(wl_action_frame_t, len)],
+ (void*) ¶m_len,
+ 2);
+
+ len += param_len + ETHER_ADDR_LEN + 2 + 4;
+
+ /* When user wants to execute local CMD being in remote wifi mode,
+ * rwl_wifi_swap_remote_type fucntion is used to change the remote types.
+ */
+ rwl_wifi_swap_remote_type(remote_type);
+
+ error = wl_set(wl, WLC_SET_VAR, &g_rwl_aligned_buf[0], len);
+ /* revert back to the old type */
+ rwl_wifi_swap_remote_type(remote_type);
+ return error;
+}
+#endif /* RWL_WIFI */
+/*
+ * Function for printing the usage if user type invalid command line
+ * options(e.g wl --serial or --dongle or --socket or --wifi)
+ */
+void
+rwl_usage(int remote_type)
+{
+ switch (remote_type) {
+ case REMOTE_SERIAL:
+ fprintf(stderr, " Usage: wl/dhd [--linuxdut/linux] [--debug]");
+ fprintf(stderr, " [--serial port no]");
+ fprintf(stderr, "[--ReadTimeout n] [--interactive] [--clientbatch] \n");
+ fprintf(stderr, "\t--linuxdut/linux removes the WLC_OID_BASE");
+ fprintf(stderr, "when sending the IOCTL command \n");
+ fprintf(stderr, "\t--debug prints out tx packets sending down ");
+ fprintf(stderr, " the serial line, and other debug info \n");
+ fprintf(stderr, "\t--serial enables the remoteWL serial port number\n");
+ fprintf(stderr, "\t--interactive enables using WL in interactive mode\n");
+ fprintf(stderr, "\t--clientbatch enables command batchinng on the client,");
+ fprintf(stderr, " the default is batching on driver\n");
+ break;
+ case REMOTE_DONGLE:
+ fprintf(stderr, " Usage: wl/dhd --dongle <Device Name> <command>\n");
+ fprintf(stderr, "\t<Device Name> COM1/COM2 (WinXP) or /dev/ttyS0"
+ " or /dev/ttyS1 (Linux)\n");
+ fprintf(stderr, "\t<command> - wl, shell or dhd command\n");
+ fprintf(stderr, "\tDepending on the client you are using(wl or dhd)\n");
+ fprintf(stderr, "\t\t shell command usage: sh <command>\n");
+ break;
+ case REMOTE_SOCKET:
+ fprintf(stderr, " Usage: "
+ "wl/dhd --socket <IP ADDRESS> [<PORT>] <command>\n");
+ fprintf(stderr, "\t<IPADDRESS> IP address of server machine\n");
+ fprintf(stderr, "\t<PORT> Port no of server\n");
+ fprintf(stderr, "\t<command> - wl, shell or dhd command\n");
+ fprintf(stderr, "\tDepending on the client you are using(wl or dhd)\n");
+ fprintf(stderr, "\t\t shell command usage: sh <command>\n");
+ fprintf(stderr, "\t If <PORT> is omitted, use default port number 8000\n");
+ break;
+ case REMOTE_WIFI:
+ fprintf(stderr, " Usage: wl/dhd --wifi <MAC Address> <command>\n");
+ fprintf(stderr, "\t<MAC Address> MAC Address\n");
+ fprintf(stderr, "\t<command> - wl, shell or dhd command\n");
+ fprintf(stderr, "\tDepending on the client you are using(wl or dhd)\n");
+ fprintf(stderr, "\t\t shell command usage: sh <command>\n");
+ break;
+ default:
+ break;
+ }
+}
+#ifdef RWL_SOCKET
+/* Note in case of error ( returned value == FAIL) it is assumed that wl is closed by caller,
+ * no treatment in this function
+ */
+static int
+rwl_socket_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf)
+{
+ uchar* resp_buf = NULL;
+ int pid, msg_len = 0, error = FAIL;
+ g_sig_ctrlc = 1;
+ g_child_pid = pid = rwl_shell_createproc(wl);
+ if (pid == 0) {
+ while (g_sig_ctrlc);
+ remote_CDC_tx(wl, 0, input_buf, 0, 0, CTRLC_FLAG, 0);
+ exit(0);
+ }
+
+ do {
+ if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) {
+ DPRINT_ERR(ERR, "rwl_socket_shellresp: Receiving CDC"
+ "header failed\n");
+ return FAIL;
+ }
+ msg_len = rem_ptr->msg.len;
+ if ((resp_buf = malloc(rem_ptr->msg.len + 1)) == NULL) {
+ DPRINT_ERR(ERR, "rwl_socket_shellresp: Mem alloc fails\n");
+ return FAIL;
+ }
+ if (msg_len > 0) {
+ if (remote_CDC_rx(wl, rem_ptr, resp_buf,
+ rem_ptr->msg.len, 0) == FAIL) {
+ DPRINT_ERR(ERR, "rwl_socket_shellresp: No results!\n");
+ free(resp_buf);
+ return FAIL;
+ }
+ }
+ /* print the shell result */
+ resp_buf[rem_ptr->msg.len] = '\0';
+ /* The return value of the shell command
+ * will be stored in rem_ptr->msg.cmd
+ * Return that value to the client process
+ */
+ if (rem_ptr->msg.flags & REMOTE_REPLY)
+ error = rem_ptr->msg.cmd;
+#ifdef LINUX
+ write(1, resp_buf, msg_len);
+#else
+ fputs((char*)resp_buf, stdout);
+#endif
+ } while (msg_len);
+ rwl_shell_killproc(pid);
+ return error;
+}
+#endif /* RWL_SOCKET */
+/* For wifi shell responses read data until server stops sending */
+#ifdef RWL_WIFI
+static int
+rwl_wifi_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf)
+{
+ int pid, msg_len = 0, error = FAIL;
+ g_sig_ctrlc = 1;
+ g_child_pid = pid = rwl_shell_createproc(wl);
+ if (pid == 0)
+ {
+ while (g_sig_ctrlc);
+ remote_CDC_tx(wl, 0, input_buf, 0, 0, CTRLC_FLAG, 0);
+ exit(0);
+ }
+
+ do {
+ if ((error = remote_CDC_DATA_wifi_rx_frag(wl, rem_ptr, 0,
+ NULL, RWL_WIFI_SHELL_CMD)) < 0) {
+ DPRINT_DBG(OUTPUT, "rwl_shell_information_fe(wifi):"
+ "error in reading shell response\n");
+ continue;
+ }
+ msg_len = rem_ptr->msg.len;
+ error = rem_ptr->msg.cmd;
+ } while (msg_len);
+
+ rwl_shell_killproc(pid);
+ return error;
+}
+#endif /* RWL_WIFI */
+
+/* For dongle or system serial shell responses read data until server stops sending */
+static int
+rwl_dongle_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf, int cmd)
+{
+ int pid, msg_len, error = 0;
+ uchar *resp_buf;
+
+ g_sig_ctrlc = 1;
+ g_child_pid = pid = rwl_shell_createproc(wl);
+ if (pid == 0) {
+ while (g_sig_ctrlc);
+ remote_CDC_tx(wl, cmd, input_buf, 0, 0, CTRLC_FLAG, 0);
+ exit(0);
+ }
+
+ do {
+ if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) {
+ DPRINT_ERR(ERR, "shell_info_fe: Receiving CDC header failed\n");
+ return BCME_SERIAL_PORT_ERR;
+ }
+ /* In case of shell or ASD commands the response size is not known in advance
+ * Hence based on response from the server memory is allocated
+ */
+ msg_len = rem_ptr->msg.len;
+ if ((resp_buf = malloc(rem_ptr->msg.len + 1)) == NULL) {
+ DPRINT_ERR(ERR, "Mem alloc fails for shell response buffer\n");
+ return FAIL;
+ }
+ /* Response comes in one shot not in fragments */
+ if (remote_CDC_rx(wl, rem_ptr, resp_buf,
+ rem_ptr->msg.len, 0) == FAIL) {
+ DPRINT_ERR(ERR, "shell_info_fe: No results!\n");
+ free(resp_buf);
+ return FAIL;
+ }
+ /* print the shell result */
+ resp_buf[rem_ptr->msg.len] = '\0';
+ /* The return value of the shell command will be stored in rem_ptr->msg.cmd
+ * Return that value to the client process
+ */
+ if (rem_ptr->msg.flags & REMOTE_REPLY)
+ error = rem_ptr->msg.cmd;
+#ifdef LINUX
+ write(1, resp_buf, msg_len);
+#else
+ fputs((char*)resp_buf, stdout);
+#endif
+ free(resp_buf);
+ } while (msg_len);
+ rwl_shell_killproc(pid);
+ return error;
+}
+
+int rwl_detect(void *wl, bool debug, int* os_type_ptr)
+{
+ int error, buf = UNKNOWN_OS;
+ unsigned long len = sizeof(buf);
+
+ error = rwl_queryinformation_fe(wl,
+ NEGOTIATE_GET_OS, &buf, &len, debug, REMOTE_NEGOTIATE_CMD);
+ if (!error) {
+ if (buf > UNKNOWN_OS && buf < INVALID_OS) {
+ *os_type_ptr = buf;
+ if (debug)
+ fprintf(stderr, "Autodetect: %d\n", *os_type_ptr);
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "Autodetect failed, rwl server is either "
+ "too old or unreachable. Use --nodetect to disable autodetect.\n");
+ return FAIL;
+}
+
+int rwl_check_port_number(char *s, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (!isdigit(s[i]))
+ return FAIL;
+ }
+ return SUCCESS;
+}
diff --git a/wl/src/wl/exe/wlu_client_shared.h b/wl/src/wl/exe/wlu_client_shared.h
new file mode 100644
index 0000000..024432d
--- /dev/null
+++ b/wl/src/wl/exe/wlu_client_shared.h
@@ -0,0 +1,40 @@
+/*
+ * OS independent client specific declarations
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_client_shared.h 514727 2014-11-12 03:02:48Z $
+ */
+#ifndef _wlu_client_shared_h
+#define _wlu_client_shared_h
+
+/* Newly added wrappers from wlu_client_shared.c */
+extern int
+rwl_shell_cmd_proc(void *wl, char **argv, int cmd);
+extern int
+rwl_queryinformation_fe(void *wl, int cmd, void* input_buf, unsigned long *input_len,
+int debug, int rem_ioctl_select);
+extern int
+rwl_setinformation_fe(void *wl, int cmd, void* buf, unsigned long *len, int debug,
+int rem_ioctl_select);
+extern void
+rwl_usage(int remote_type);
+extern int
+rwl_detect(void *wl, bool debug, int* os_type_ptr);
+
+extern int rwl_shell_createproc(void *wl);
+extern void rwl_shell_killproc(int pid);
+/* declaring these as extern to be used in wlu_ndis.c and wlu_linux.c */
+extern volatile sig_atomic_t g_sig_ctrlc;
+extern void ctrlc_handler(int num);
+
+#endif /* _wlu_client_share_h */
diff --git a/wl/src/wl/exe/wlu_cmd.c b/wl/src/wl/exe/wlu_cmd.c
new file mode 100644
index 0000000..b485df2
--- /dev/null
+++ b/wl/src/wl/exe/wlu_cmd.c
@@ -0,0 +1,31 @@
+/*
+ * File: wlu_cmd.c
+ * Purpose: Command and IO variable information commands
+ * Requires:
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_cmd.c 601272 2015-11-20 21:12:22Z $
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <wlioctl.h>
+
+#include "wlu.h"
diff --git a/wl/src/wl/exe/wlu_cmd.h b/wl/src/wl/exe/wlu_cmd.h
new file mode 100644
index 0000000..c6a1cfc
--- /dev/null
+++ b/wl/src/wl/exe/wlu_cmd.h
@@ -0,0 +1,177 @@
+/*
+ * Command structure for wl command line utility
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
+ * the contents of this file may not be disclosed to third parties, copied or
+ * duplicated in any form, in whole or in part, without the prior written
+ * permission of Broadcom Corporation.
+ *
+ * $Id: wlu_cmd.h 635987 2016-05-06 01:49:37Z $
+ */
+
+#ifndef _wlu_cmd_h_
+#define _wlu_cmd_h_
+
+/* wl_nan_sub_cmd may also be used in dhd */
+typedef struct wl_nan_sub_cmd wl_nan_sub_cmd_t;
+typedef int (cmd_handler_t)(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len);
+/*
+ * nan sub-commands list entry
+ */
+struct wl_nan_sub_cmd {
+ char *name;
+ uint8 version;
+ uint16 id;
+ uint16 type;
+ cmd_handler_t *handler;
+};
+
+/*
+ * NAN sub-command help list entry
+ */
+typedef struct wl_nan_cmd_help wl_nan_cmd_help_t;
+typedef void (cmd_help_handler_t)(void);
+struct wl_nan_cmd_help {
+ uint16 type;
+ cmd_help_handler_t *help_handler;
+};
+
+
+typedef struct cmd cmd_t;
+typedef int (cmd_func_t)(void *wl, cmd_t *cmd, char **argv);
+
+/* generic command line argument handler */
+struct cmd {
+ const char *name;
+ cmd_func_t *func;
+ int get;
+ int set;
+ const char *help;
+};
+
+/* list of command line arguments */
+extern cmd_t wl_cmds[];
+extern cmd_t wl_varcmd;
+
+/* per-port ioctl handlers */
+extern int wl_get(void *wl, int cmd, void *buf, int len);
+extern int wl_set(void *wl, int cmd, void *buf, int len);
+
+/*
+ * Flags for command categories. A command may belong to
+ * multiple categories. These are used in bitmaps, so be careful
+ * to keep the macro value (2 ^ n) and the array indexes (n)
+ * consistent.
+ */
+
+#define CMD_PHY 0x1
+#define CMD_CHAN 0x2
+#define CMD_RATE 0x4
+#define CMD_POWER 0x8
+#define CMD_MAC 0x10
+#define CMD_MGMT 0x20
+#define CMD_SEC 0x40
+#define CMD_WME 0x80
+#define CMD_MON 0x100
+#define CMD_AP 0x200
+#define CMD_STA 0x400
+#define CMD_BOARD 0x800
+#define CMD_ADMIN 0x1000
+#define CMD_DEV 0x2000
+#define CMD_DEP 0x4000
+#define CMD_UNCAT 0x8000
+
+#define CMD_ALL 0xffff
+
+/* Initializer for category string array */
+
+#define CMD_CATEGORY_STRINGS_INIT { \
+ "phy", \
+ "chan", \
+ "rate", \
+ "power", \
+ "mac", \
+ "mgmt", \
+ "sec", \
+ "wme", \
+ "mon", \
+ "ap", \
+ "sta", \
+ "board", \
+ "admin", \
+ "dev", \
+ "dep", \
+ "uncat", \
+ "" }
+
+extern const char *wl_cmd_category_strings[];
+extern const int wl_cmd_category_count;
+
+/* Initializer for category description strings array */
+#define CMD_CATEGORY_DESC_INIT { \
+ "PHY and radio; speed, band, etc", \
+ "Channel; subclass of phy", \
+ "Rate; subclass of phy, a/b/g", \
+ "Power; subclass of phy", \
+ "MAC; Media access", \
+ "Management, association, IE, etc", \
+ "Security; subclass of mgmt", \
+ "WME; media extensions", \
+ "Monitoring device (counters, etc)", \
+ "AP subclass of mgmt", \
+ "STA subclass of mgmt", \
+ "Board, hardware", \
+ "Administration; software, UI, diags", \
+ "Device; low level control", \
+ "Deprecated", \
+ "Uncategorized so far", \
+ "" }
+
+extern const char *wl_cmd_category_desc[];
+
+/*
+ *
+ * IO variable information
+ *
+ */
+
+/* Supplemental IO variable info structure */
+typedef const struct wlu_iov_info_s {
+ const char *name;
+ uint32 cat; /* Category flags; same as command categories */
+ uint32 flags; /* See below */
+ int dflt; /* Only for integers; see flags */
+ const char *desc; /* Description */
+} wlu_iov_info_t;
+
+/* Flags for wlu_iov_info_t */
+#define WLU_IOVI_READ_ONLY 0x1 /* Known to be read only */
+#define WLU_IOVI_WRITE_ONLY 0x2 /* Known to be write only */
+#define WLU_IOVI_BCM_INTERNAL 0x4 /* Known to be BCM internal */
+#define WLU_IOVI_DEFAULT_VALID 0x8 /* Default value in structure is valid */
+
+extern wlu_iov_info_t wlu_iov_info[];
+extern int wlu_iov_info_count;
+
+#define WLU_IOV_BLOCK_LEN 10
+
+#define WLU_MOD_NAME_MAX 64 /* Max num modules */
+#define WLU_MOD_NAME_BYTES 16 /* Size of modules name */
+
+extern int wl_get_scan(void *wl, int opc, char *scan_buf, uint buf_len);
+
+#endif /* _wlu_cmd_h_ */
diff --git a/wl/src/wl/exe/wlu_common.c b/wl/src/wl/exe/wlu_common.c
new file mode 100644
index 0000000..a36eac6
--- /dev/null
+++ b/wl/src/wl/exe/wlu_common.c
@@ -0,0 +1,414 @@
+/*
+ * Common code for wl routines
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_common.c 583196 2015-09-01 07:11:55Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include "wlu_common.h"
+#include "wlu.h"
+#include <bcmendian.h>
+
+extern int wl_get(void *wl, int cmd, void *buf, int len);
+extern int wl_set(void *wl, int cmd, void *buf, int len);
+
+wl_cmd_list_t cmd_list;
+int cmd_pkt_list_num;
+bool cmd_batching_mode;
+
+const char *wlu_av0;
+
+/* global wlc index indentifier for RSDB -W/--wlc option */
+int g_wlc_idx = -1;
+
+/* IOCTL swapping mode for Big Endian host with Little Endian dongle. Default to off */
+bool g_swap = FALSE;
+
+#ifdef SERDOWNLOAD
+extern int debug;
+#endif
+
+/*
+ * format an iovar buffer
+ * iovar name is converted to lower case
+ */
+static uint
+wl_iovar_mkbuf(const char *name, char *data, uint datalen, char *iovar_buf, uint buflen, int *perr)
+{
+ uint iovar_len;
+ char *p;
+
+ iovar_len = strlen(name) + 1;
+
+ /* check for overflow */
+ if ((iovar_len + datalen) > buflen) {
+ *perr = BCME_BUFTOOSHORT;
+ return 0;
+ }
+
+ /* copy data to the buffer past the end of the iovar name string */
+ if (datalen > 0)
+ memmove(&iovar_buf[iovar_len], data, datalen);
+
+ /* copy the name to the beginning of the buffer */
+ strcpy(iovar_buf, name);
+
+ /* wl command line automatically converts iovar names to lower case for
+ * ease of use
+ */
+ p = iovar_buf;
+ while (*p != '\0') {
+ *p = tolower((int)*p);
+ p++;
+ }
+
+ *perr = 0;
+ return (iovar_len + datalen);
+}
+
+void
+init_cmd_batchingmode(void)
+{
+ cmd_pkt_list_num = 0;
+ cmd_batching_mode = FALSE;
+}
+
+void
+clean_up_cmd_list(void)
+{
+ wl_seq_cmd_pkt_t *this_cmd, *next_cmd;
+
+ this_cmd = cmd_list.head;
+ while (this_cmd != NULL) {
+ next_cmd = this_cmd->next;
+ if (this_cmd->data != NULL) {
+ free(this_cmd->data);
+ }
+ free(this_cmd);
+ this_cmd = next_cmd;
+ }
+ cmd_list.head = NULL;
+ cmd_list.tail = NULL;
+ cmd_pkt_list_num = 0;
+}
+
+int
+add_one_batched_cmd(int cmd, void *cmdbuf, int len)
+{
+ wl_seq_cmd_pkt_t *new_cmd;
+
+ new_cmd = malloc(sizeof(wl_seq_cmd_pkt_t));
+
+ if (new_cmd == NULL) {
+ printf("malloc(%d) failed, free %d batched commands and exit batching mode\n",
+ (int)sizeof(wl_seq_cmd_pkt_t), cmd_pkt_list_num);
+ goto free_and_exit;
+ } else {
+#ifdef SERDOWNLOAD
+ if (debug)
+#endif /* SERDOWNLOAD */
+ printf("batching %dth command %d\n", cmd_pkt_list_num+1, cmd);
+
+ }
+
+ new_cmd->cmd_header.cmd = cmd;
+ new_cmd->cmd_header.len = len;
+ new_cmd->next = NULL;
+
+ new_cmd->data = malloc(len);
+
+ if (new_cmd->data == NULL) {
+ printf("malloc(%d) failed, free %d batched commands and exit batching mode\n",
+ len, cmd_pkt_list_num);
+ free(new_cmd);
+ goto free_and_exit;
+ }
+
+ memcpy(new_cmd->data, cmdbuf, len);
+
+ if (cmd_list.tail != NULL)
+ cmd_list.tail->next = new_cmd;
+ else
+ cmd_list.head = new_cmd;
+
+ cmd_list.tail = new_cmd;
+
+ cmd_pkt_list_num ++;
+ return 0;
+
+free_and_exit:
+
+ clean_up_cmd_list();
+
+ if (cmd_batching_mode) {
+ cmd_batching_mode = FALSE;
+ }
+ else {
+ printf("calling add_one_batched_cmd() at non-command-batching mode, weird\n");
+ }
+
+ return -1;
+}
+
+int
+wlu_get_req_buflen(int cmd, void *cmdbuf, int len)
+{
+ int modified_len = len;
+ char *cmdstr = (char *)cmdbuf;
+
+ if (len == WLC_IOCTL_MAXLEN) {
+ if ((strcmp(cmdstr, "dump") == 0) ||
+ (cmd == WLC_SCAN_RESULTS))
+ modified_len = WLC_IOCTL_MAXLEN;
+ else
+ modified_len = WLC_IOCTL_MEDLEN;
+ }
+ return modified_len;
+}
+
+/* Wrapper function that converts -W option in to "wlc:" prefix
+ * (1) It converts an existing iovar to the following format
+ * wlc:<iovar_name>\0<wlc_idx><param>
+ * (2) It converts an existing ioctl to the following format
+ * wlc:ioc\0<wlc_idx><ioct_cmd_id><param>
+ * NOTE: (2) requires new iovar named "ioc" in driver
+*/
+static int
+wlu_wlc_wrapper(void *wl, bool get, int* cmd, void *cmdbuf, int len, void **outbuf, int *outlen)
+{
+ void *param = cmdbuf;
+ int paramlen = len;
+ int wlc_idx = g_wlc_idx;
+ char *name = NULL;
+ BCM_REFERENCE(wl);
+ /* Wrap only if we find a valid WLC index and iovar name */
+ if (wlc_idx >= 0) {
+ int cmdlen = 0;
+ int prefix_len = 0;
+ char *lbuf = NULL;
+ char *buf = NULL;
+ bool ioctl_wrap = FALSE;
+ if ((*cmd == WLC_GET_VAR) || (*cmd == WLC_SET_VAR)) {
+ /* incoming command is an iovar */
+ /* pull out name\0param */
+ name = cmdbuf;
+ cmdlen = strlen(name);
+ param = ((char*)cmdbuf) + cmdlen + 1;
+ paramlen = len - cmdlen - 1;
+ } else {
+ /* we are an ioctl, invoke the common "ioc" iovar and wrap the cmd */
+ name = "ioc";
+ cmdlen = strlen(name);
+ /* additional 4 bytes for storing IOCTL_CMD_ID */
+ prefix_len = sizeof(int);
+ ioctl_wrap = TRUE;
+ }
+ prefix_len += strlen("wlc:") + 1 + cmdlen + sizeof(int);
+ /* now create wlc:<name>\0<wlc_idx><param> */
+ buf = lbuf = malloc(prefix_len + paramlen);
+ if (buf == NULL) {
+ printf("%s:malloc(%d) failed\n", __FUNCTION__, prefix_len + paramlen);
+ return BCME_NOMEM;
+ }
+ memcpy(buf, "wlc:", 4); buf += 4;
+ strcpy(buf, name); buf += (cmdlen+1);
+ wlc_idx = htod32(wlc_idx);
+ memcpy(buf, &wlc_idx, sizeof(int32)); buf += sizeof(int32);
+ if (ioctl_wrap) {
+ /* For IOCTL wlc:ioc\0<wlc_idx><ioctl_id><param> */
+ int32 ioctl_cmd = htod32(*cmd);
+ memcpy(buf, &ioctl_cmd, sizeof(int32)); buf += sizeof(int32);
+ }
+ memcpy(buf, param, paramlen);
+ *cmd = (get) ? WLC_GET_VAR : WLC_SET_VAR;
+ param = lbuf;
+ paramlen += prefix_len;
+ }
+ *outlen = paramlen;
+ *outbuf = param;
+ return BCME_OK;
+}
+/* now IOCTL GET commands shall call wlu_get() instead of wl_get() so that the commands
+ * can be batched when needed
+ */
+int
+wlu_get(void *wl, int cmd, void *cmdbuf, int len)
+{
+ void *outbuf = NULL;
+ int outlen;
+ int err = 0;
+ if (cmd_batching_mode) {
+ if (!WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd)) {
+ printf("IOCTL GET command %d is not supported in batching mode\n", cmd);
+ return BCME_UNSUPPORTED;
+ }
+ }
+
+ err = wlu_wlc_wrapper(wl, TRUE, &cmd, cmdbuf, len, &outbuf, &outlen);
+ if (err != BCME_OK) return err;
+ err = wl_get(wl, cmd, outbuf, outlen);
+
+ if (outbuf != cmdbuf) {
+ memcpy(cmdbuf, outbuf, len);
+ free(outbuf);
+ }
+ return err;
+}
+
+/* now IOCTL SET commands shall call wlu_set() instead of wl_set() so that the commands
+ * can be batched when needed
+ */
+int
+wlu_set(void *wl, int cmd, void *cmdbuf, int len)
+{
+ int err = 0;
+ void *outbuf = NULL;
+ int outlen;
+
+ err = wlu_wlc_wrapper(wl, FALSE, &cmd, cmdbuf, len, &outbuf, &outlen);
+ if (err != BCME_OK) return err;
+
+ if (cmd_batching_mode) {
+ err = add_one_batched_cmd(cmd, outbuf, outlen);
+ }
+ else {
+ err = wl_set(wl, cmd, outbuf, outlen);
+ }
+ if (outbuf != cmdbuf) {
+ memcpy(cmdbuf, outbuf, len);
+ free(outbuf);
+ }
+ return err;
+
+}
+
+/*
+ * get named iovar providing both parameter and i/o buffers
+ * iovar name is converted to lower case
+ */
+int
+wlu_iovar_getbuf(void* wl, const char *iovar,
+ void *param, int paramlen, void *bufptr, int buflen)
+{
+ int err;
+
+ wl_iovar_mkbuf(iovar, param, paramlen, bufptr, buflen, &err);
+ if (err)
+ return err;
+
+ return wlu_get(wl, WLC_GET_VAR, bufptr, buflen);
+}
+
+/*
+ * set named iovar providing both parameter and i/o buffers
+ * iovar name is converted to lower case
+ */
+int
+wlu_iovar_setbuf(void* wl, const char *iovar,
+ void *param, int paramlen, void *bufptr, int buflen)
+{
+ int err;
+ int iolen;
+
+ iolen = wl_iovar_mkbuf(iovar, param, paramlen, bufptr, buflen, &err);
+ if (err)
+ return err;
+
+ return wlu_set(wl, WLC_SET_VAR, bufptr, iolen);
+}
+
+/*
+ * get named iovar without parameters into a given buffer
+ * iovar name is converted to lower case
+ */
+int
+wlu_iovar_get(void *wl, const char *iovar, void *outbuf, int len)
+{
+ char smbuf[WLC_IOCTL_SMLEN];
+ int err;
+
+ /* use the return buffer if it is bigger than what we have on the stack */
+ if (len > (int)sizeof(smbuf)) {
+ err = wlu_iovar_getbuf(wl, iovar, NULL, 0, outbuf, len);
+ } else {
+ memset(smbuf, 0, sizeof(smbuf));
+ err = wlu_iovar_getbuf(wl, iovar, NULL, 0, smbuf, sizeof(smbuf));
+ if (err == 0)
+ memcpy(outbuf, smbuf, len);
+ }
+
+ return err;
+}
+
+/*
+ * set named iovar given the parameter buffer
+ * iovar name is converted to lower case
+ */
+int
+wlu_iovar_set(void *wl, const char *iovar, void *param, int paramlen)
+{
+ char smbuf[WLC_IOCTL_SMLEN*2];
+
+ memset(smbuf, 0, sizeof(smbuf));
+
+ return wlu_iovar_setbuf(wl, iovar, param, paramlen, smbuf, sizeof(smbuf));
+}
+
+/*
+ * get named iovar as an integer value
+ * iovar name is converted to lower case
+ */
+int
+wlu_iovar_getint(void *wl, const char *iovar, int *pval)
+{
+ int ret;
+
+ ret = wlu_iovar_get(wl, iovar, pval, sizeof(int));
+ if (ret >= 0)
+ {
+ *pval = dtoh32(*pval);
+ }
+ return ret;
+}
+
+/*
+ * set named iovar given an integer parameter
+ * iovar name is converted to lower case
+ */
+int
+wlu_iovar_setint(void *wl, const char *iovar, int val)
+{
+ val = htod32(val);
+ return wlu_iovar_set(wl, iovar, &val, sizeof(int));
+}
+/*
+ * Name lookup utility.
+ * Given a name table and an ID, will return the name matching the ID,
+ * or a string with the raw ID, i.e. "ID:<num>"
+ */
+const char* wlu_lookup_name(const wlu_name_entry_t* tbl, uint id)
+{
+ const wlu_name_entry_t *elt = tbl;
+ static char unknown[64];
+
+ for (elt = tbl; elt->name != NULL; elt++) {
+ if (id == elt->id)
+ return elt->name;
+ }
+ snprintf(unknown, sizeof(unknown), "ID:%d", id);
+ return unknown;
+}
diff --git a/wl/src/wl/exe/wlu_common.h b/wl/src/wl/exe/wlu_common.h
new file mode 100644
index 0000000..72e6630
--- /dev/null
+++ b/wl/src/wl/exe/wlu_common.h
@@ -0,0 +1,109 @@
+/*
+ * Common code for wl routines
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_common.h 649191 2016-07-15 06:30:56Z $
+ */
+#include <wlioctl.h>
+#include <bcmutils.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#if defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION >= 0x00020000)
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+#define strtol(nptr, endptr, base) (long)bcm_strtoul((nptr), (endptr), (base))
+#endif /* defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION >= 0x00020000) */
+
+#if defined(linux)
+
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+
+#elif defined(_CRT_SECURE_NO_DEPRECATE) /* MSVC common runtime */
+
+#define stricmp _stricmp
+#define strnicmp _strnicmp
+
+#elif defined(DONGLEBUILD)
+
+#define stricmp strcmp
+#define strnicmp strncmp
+
+#elif defined(BWL_STRICMP)
+
+#define stricmp bcmstricmp
+#define strnicmp bcmstrnicmp
+
+#endif /* BWL_STRICMP */
+
+/* IOCTL swapping mode for Big Endian host with Little Endian dongle. Default to off */
+/* The below macros handle endian mis-matches between wl utility and wl driver. */
+extern bool g_swap;
+#define htod64(i) (g_swap?bcmswap64(i):(uint64)(i))
+#define htod32(i) (g_swap?bcmswap32(i):(uint32)(i))
+#define htod16(i) (g_swap?bcmswap16(i):(uint16)(i))
+#define dtoh64(i) (g_swap?bcmswap64(i):(uint64)(i))
+#define dtoh32(i) (g_swap?bcmswap32(i):(uint32)(i))
+#define dtoh16(i) (g_swap?bcmswap16(i):(uint16)(i))
+#define htodchanspec(i) (g_swap?htod16(i):i)
+#define dtohchanspec(i) (g_swap?dtoh16(i):i)
+#define htodenum(i) (g_swap?((sizeof(i) == 4) ? htod32(i) : ((sizeof(i) == 2) ? htod16(i) : i)):i)
+#define dtohenum(i) (g_swap?((sizeof(i) == 4) ? dtoh32(i) : ((sizeof(i) == 2) ? htod16(i) : i)):i)
+
+/* command batching data structure */
+typedef struct wl_seq_cmd_pkt {
+ struct wl_seq_cmd_pkt *next;
+ wl_seq_cmd_ioctl_t cmd_header;
+ char * data; /* user buffer */
+} wl_seq_cmd_pkt_t;
+
+typedef struct wl_cmd_list {
+ wl_seq_cmd_pkt_t *head;
+ wl_seq_cmd_pkt_t *tail;
+} wl_cmd_list_t;
+
+/*
+ * Name table to associate strings with numeric IDs
+ */
+typedef struct wlu_name_entry {
+ uint id;
+ const char *name;
+} wlu_name_entry_t;
+
+extern wl_cmd_list_t cmd_list;
+extern int cmd_pkt_list_num;
+extern bool cmd_batching_mode;
+
+extern int wlu_iovar_getbuf(void* wl, const char *iovar,
+ void *param, int paramlen, void *bufptr, int buflen);
+extern int wlu_iovar_setbuf(void* wl, const char *iovar,
+ void *param, int paramlen, void *bufptr, int buflen);
+extern int wlu_var_setbuf(void *wl, const char *iovar, void *param, int param_len);
+extern int wlu_iovar_getint(void *wl, const char *iovar, int *pval);
+extern void init_cmd_batchingmode(void);
+extern void clean_up_cmd_list(void);
+extern int wl_check(void *wl);
+
+extern int add_one_batched_cmd(int cmd, void *cmdbuf, int len);
+extern int wlu_get_req_buflen(int cmd, void *cmdbuf, int len);
+extern int wlu_get(void *wl, int cmd, void *cmdbuf, int len);
+extern int wlu_set(void *wl, int cmd, void *cmdbuf, int len);
+extern int wlu_iovar_get(void *wl, const char *iovar, void *outbuf, int len);
+extern int wlu_iovar_set(void *wl, const char *iovar, void *param, int paramlen);
+extern int wlu_iovar_getint(void *wl, const char *iovar, int *pval);
+extern int wlu_iovar_setint(void *wl, const char *iovar, int val);
+extern const char* wlu_lookup_name(const wlu_name_entry_t* tbl, uint id);
diff --git a/wl/src/wl/exe/wlu_iov.c b/wl/src/wl/exe/wlu_iov.c
new file mode 100644
index 0000000..b4822f9
--- /dev/null
+++ b/wl/src/wl/exe/wlu_iov.c
@@ -0,0 +1,32 @@
+/*
+ * Automatically generated IOVariable merge information
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_iov.c 572826 2015-07-21 03:59:03Z $
+ *
+ * Contains user IO variable information
+ * Note that variable type information comes from the driver
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <wlioctl.h>
+
+#include "wlu.h"
diff --git a/wl/src/wl/exe/wlu_linux.c b/wl/src/wl/exe/wlu_linux.c
new file mode 100644
index 0000000..79c4e16
--- /dev/null
+++ b/wl/src/wl/exe/wlu_linux.c
@@ -0,0 +1,1049 @@
+/*
+ * Linux port of wl command line utility
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_linux.c 659591 2016-09-15 03:19:00Z $
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#ifndef TARGETENV_android
+#include <error.h>
+#endif /* TARGETENV_android */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <proto/ethernet.h>
+#include <proto/bcmip.h>
+
+#ifndef TARGETENV_android
+#include <linux/types.h>
+#endif /* TARGETENV_android */
+
+#include <linux/sockios.h>
+#include <linux/ethtool.h>
+#include <signal.h>
+#include <typedefs.h>
+#include <wlioctl.h>
+#include <bcmutils.h>
+#include <sys/wait.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include "wlu.h"
+#include <bcmcdc.h>
+#include "wlu_remote.h"
+#include "wlu_client_shared.h"
+#include "wlu_pipe.h"
+#ifdef NL80211
+#include "wlu_nl80211.h"
+#endif /* NL80211 */
+#include <miniopt.h>
+
+#define DEV_TYPE_LEN 3 /* length for devtype 'wl'/'et' */
+#define INTERACTIVE_NUM_ARGS 15
+#define INTERACTIVE_MAX_INPUT_LENGTH 512
+#define NO_ERROR 0
+#define RWL_WIFI_JOIN_DELAY 5
+
+/* Function prototypes */
+static cmd_t *wl_find_cmd(char* name);
+static int do_interactive(struct ifreq *ifr);
+static int wl_do_cmd(struct ifreq *ifr, char **argv);
+int process_args(struct ifreq* ifr, char **argv);
+extern int g_child_pid;
+/* RemoteWL declarations */
+int remote_type = NO_REMOTE;
+int rwl_os_type = LINUX_OS;
+static bool rwl_dut_autodetect = TRUE;
+static bool debug = FALSE;
+extern char *g_rwl_buf_mac;
+extern char* g_rwl_device_name_serial;
+extern int g_rwl_device_baud;
+unsigned short g_rwl_servport;
+char *g_rwl_servIP = NULL;
+unsigned short defined_debug = DEBUG_ERR | DEBUG_INFO;
+static uint interactive_flag = 0;
+extern char *remote_vista_cmds[];
+extern char g_rem_ifname[IFNAMSIZ];
+extern int rwl_check_port_number(char *s, int len);
+
+#ifdef NL80211
+static void
+syserr(char *s)
+{
+ UNUSED_PARAMETER(s);
+}
+
+static int wl_driver_nl80211(void *wl, wl_ioctl_t *ioc)
+{
+ struct wl_netlink_info wl_nli;
+ struct ifreq *ifr = (struct ifreq *)wl;
+ int ret = 0;
+
+ wl_nli.ifidx = if_nametoindex(ifr->ifr_name);
+ if (!wl_nli.ifidx) {
+ fprintf(stderr, "invalid device %s\n", ifr->ifr_name);
+ return BCME_IOCTL_ERROR;
+ }
+
+ if (wlnl_sock_connect(&wl_nli) < 0) {
+ fprintf(stderr, "%s: ", wlu_av0);
+ perror("socket");
+ exit(errno);
+ }
+
+ ret = wlnl_do_vndr_cmd(&wl_nli, ioc);
+ wlnl_sock_disconnect(&wl_nli);
+ return ret;
+}
+#else
+static void
+syserr(char *s)
+{
+ fprintf(stderr, "%s: ", wlu_av0);
+ perror(s);
+ exit(errno);
+}
+
+static int wl_driver_nl80211(void *wl, wl_ioctl_t *ioc)
+{
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(ioc);
+ return BCME_IOCTL_ERROR;
+}
+#endif /* NL80211 */
+
+static int wl_driver_ioctl(void *wl, wl_ioctl_t *ioc)
+{
+ struct ifreq *ifr = (struct ifreq *) wl;
+ int ret;
+ int s;
+
+ /* open socket to kernel */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ syserr("socket");
+
+ /* do it */
+ ifr->ifr_data = (caddr_t)ioc;
+ ret = ioctl(s, SIOCDEVPRIVATE, ifr);
+
+ /* cleanup */
+ close(s);
+ return ret;
+}
+
+static int (*g_driver_io)(void *wl, wl_ioctl_t *ioc) = wl_driver_ioctl;
+int
+wl_ioctl(void *wl, int cmd, void *buf, int len, bool set)
+{
+ wl_ioctl_t ioc;
+ int ret;
+
+ /* do it */
+ ioc.cmd = cmd;
+ ioc.buf = buf;
+ ioc.len = len;
+ ioc.set = set;
+
+ ret = g_driver_io(wl, &ioc);
+ if ((cmd == WLC_GET_MAGIC) && (ret < 0)) {
+ if (g_driver_io == wl_driver_ioctl) {
+ /* try using nl80211 testmode interface */
+ ret = wl_driver_nl80211(wl, &ioc);
+ if (ret >= 0) {
+ g_driver_io = wl_driver_nl80211;
+ goto exit;
+ }
+ }
+ } else if (ret < 0) {
+ ret = BCME_IOCTL_ERROR;
+ }
+
+exit:
+ return ret;
+}
+
+static int
+wl_get_dev_type(char *name, void *buf, int len)
+{
+ int s;
+ int ret;
+ struct ifreq ifr;
+ struct ethtool_drvinfo info;
+
+ /* open socket to kernel */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ syserr("socket");
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ /* get device type */
+ memset(&info, 0, sizeof(info));
+ info.cmd = ETHTOOL_GDRVINFO;
+ ifr.ifr_data = (caddr_t)&info;
+ strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+ if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) {
+
+ /* print a good diagnostic if not superuser */
+ if (errno == EPERM)
+ syserr("wl_get_dev_type");
+
+ *(char *)buf = '\0';
+ } else {
+ strncpy(buf, info.driver, len);
+ }
+
+ close(s);
+ return ret;
+}
+
+static int
+wl_find(struct ifreq *ifr)
+{
+ char proc_net_dev[] = "/proc/net/dev";
+ FILE *fp;
+ char buf[1000], *c, *name;
+ char dev_type[DEV_TYPE_LEN];
+ int status;
+
+ ifr->ifr_name[0] = '\0';
+
+ if (!(fp = fopen(proc_net_dev, "r")))
+ return BCME_ERROR;
+
+ /* eat first two lines */
+ if (!fgets(buf, sizeof(buf), fp) ||
+ !fgets(buf, sizeof(buf), fp)) {
+ fclose(fp);
+ return BCME_ERROR;
+ }
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ c = buf;
+ while (isspace(*c))
+ c++;
+ if (!(name = strsep(&c, ":")))
+ continue;
+ strncpy(ifr->ifr_name, name, IFNAMSIZ-1);
+ ifr->ifr_name[IFNAMSIZ-1] = 0;
+
+ /*
+ * If no -i interface, prioritize ethX, not say wl1.2
+ * wlanX is Android
+ */
+ if (!strncmp(name, "wl", 2) && strncmp(name, "wlan", 4)) {
+ continue;
+ }
+
+ if (wl_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 &&
+ (!strncmp(dev_type, "wl", 2) ||
+ !strncmp(dev_type, "brc", 3)))
+ if (wl_check((void *) ifr) == 0)
+ break;
+ ifr->ifr_name[0] = '\0';
+ }
+ if (ifr->ifr_name[0] == '\0')
+ status = BCME_ERROR;
+ else
+ status = BCME_OK;
+
+ fclose(fp);
+ return status;
+}
+
+
+static int
+ioctl_queryinformation_fe(void *wl, int cmd, void* input_buf, unsigned long *input_len)
+{
+ int error = NO_ERROR;
+
+ if (remote_type == NO_REMOTE) {
+ error = wl_ioctl(wl, cmd, input_buf, *input_len, FALSE);
+ } else {
+ error = rwl_queryinformation_fe(wl, cmd, input_buf,
+ input_len, 0, REMOTE_GET_IOCTL);
+
+ }
+ return error;
+}
+
+static int
+ioctl_setinformation_fe(void *wl, int cmd, void* buf, unsigned long *input_len)
+{
+ int error = 0;
+
+ if (remote_type == NO_REMOTE) {
+ error = wl_ioctl(wl, cmd, buf, *input_len, TRUE);
+ } else {
+ error = rwl_setinformation_fe(wl, cmd, buf,
+ input_len, 0, REMOTE_SET_IOCTL);
+ }
+
+ return error;
+}
+
+int
+wl_get(void *wl, int cmd, void *buf, int len)
+{
+ int error = 0;
+ unsigned long input_len = len;
+
+ if ((rwl_os_type == WIN32_OS || rwl_os_type == WINVISTA_OS) && remote_type != NO_REMOTE)
+ cmd += WL_OID_BASE;
+ error = (int)ioctl_queryinformation_fe(wl, cmd, buf, &input_len);
+
+ if (error == BCME_SERIAL_PORT_ERR)
+ return BCME_SERIAL_PORT_ERR;
+ else if (error == BCME_NODEVICE)
+ return BCME_NODEVICE;
+ else if (error != 0)
+ return BCME_IOCTL_ERROR;
+
+ return 0;
+}
+
+int
+wl_set(void *wl, int cmd, void *buf, int len)
+{
+ int error = 0;
+ unsigned long input_len = len;
+
+ if ((rwl_os_type == WIN32_OS || rwl_os_type == WINVISTA_OS) && remote_type != NO_REMOTE)
+ cmd += WL_OID_BASE;
+ error = (int)ioctl_setinformation_fe(wl, cmd, buf, &input_len);
+
+ if (error == BCME_SERIAL_PORT_ERR)
+ return BCME_SERIAL_PORT_ERR;
+ else if (error == BCME_NODEVICE)
+ return BCME_NODEVICE;
+ else if (error != 0)
+ return BCME_IOCTL_ERROR;
+
+ return 0;
+}
+
+#if defined(WLMSO)
+int wl_os_type_get_rwl()
+{
+ return rwl_os_type;
+}
+
+void wl_os_type_set_rwl(int os_type)
+{
+ rwl_os_type = os_type;
+}
+
+int wl_ir_init_rwl(void **irh)
+{
+ switch (rwl_get_remote_type()) {
+ case NO_REMOTE:
+ case REMOTE_WIFI: {
+ struct ifreq *ifr;
+ ifr = malloc(sizeof(struct ifreq));
+ if (ifr) {
+ memset(ifr, 0, sizeof(ifr));
+ wl_find(ifr);
+ }
+ *irh = ifr;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void wl_close_rwl(int remote_type, void *irh)
+{
+ switch (remote_type) {
+ case NO_REMOTE:
+ case REMOTE_WIFI:
+ free(irh);
+ break;
+ default:
+ break;
+ }
+}
+
+#define LINUX_NUM_ARGS 16
+
+static int
+buf_to_args(char *tmp, char *new_args[])
+{
+ char line[INTERACTIVE_MAX_INPUT_LENGTH];
+ char *token;
+ int argc = 0;
+
+ if (strlen(tmp) >= INTERACTIVE_MAX_INPUT_LENGTH) {
+ printf("wl:error: Input string too long; must be < %d bytes\n",
+ INTERACTIVE_MAX_INPUT_LENGTH);
+ return 0;
+ }
+
+ strcpy(line, tmp);
+ while (argc < (LINUX_NUM_ARGS - 1) &&
+ (token = strtok(argc ? NULL : line, " \t")) != NULL) {
+ new_args[argc] = malloc(strlen(token)+1);
+ strncpy(new_args[argc], token, strlen(token)+1);
+ argc++;
+ }
+ new_args[argc] = NULL;
+ if (argc == (LINUX_NUM_ARGS - 1) && (token = strtok(NULL, " \t")) != NULL) {
+ printf("wl:error: too many args; argc must be < %d\n",
+ (LINUX_NUM_ARGS - 1));
+ argc = LINUX_NUM_ARGS;
+ }
+ return argc;
+}
+
+int
+wl_lib(char *input_str)
+{
+ struct ifreq ifr;
+ char *ifname = NULL;
+ int err = 0;
+ int help = 0;
+ int status = CMD_WL;
+ void* serialHandle = NULL;
+ char *tmp_argv[LINUX_NUM_ARGS];
+ char **argv = tmp_argv;
+ int argc;
+
+ /* buf_to_args return 0 if no args or string too long
+ * or return NDIS_NUM_ARGS if too many args
+ */
+ if (((argc = buf_to_args(input_str, argv)) == 0) || (argc == LINUX_NUM_ARGS)) {
+ printf("wl:error: can't convert input string\n");
+ return (-1);
+ }
+#else
+/* Main client function */
+int
+main(int argc, char **argv)
+{
+ struct ifreq ifr;
+ char *ifname = NULL;
+ int err = 0;
+ int help = 0;
+ int status = CMD_WL;
+#if defined(RWL_DONGLE) || RWL_SERIAL
+ void* serialHandle = NULL;
+#endif
+
+#endif /* WLMSO */
+ wlu_av0 = argv[0];
+
+ wlu_init();
+ memset(&ifr, 0, sizeof(ifr));
+ (void)*argv++;
+
+ if ((status = wl_option(&argv, &ifname, &help)) == CMD_OPT) {
+ if (ifname)
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ /* Bug fix: If -h is used as an option, the above function call
+ * will notice it and raise the flag but it won't be processed
+ * in this function so we undo the argv increment so that the -h
+ * can be spotted by the next call of wl_option. This will ensure
+ * that wl -h [cmd] will function as desired.
+ */
+ else if (help)
+ (void)*argv--;
+ }
+
+ /* Linux client looking for a indongle reflector */
+ if (*argv && strncmp (*argv, "--indongle", strlen(*argv)) == 0) {
+ rwl_dut_autodetect = FALSE;
+ (void)*argv++;
+ }
+ /* Linux client looking for a WinVista server */
+ if (*argv && strncmp (*argv, "--vista", strlen(*argv)) == 0) {
+ rwl_os_type = WINVISTA_OS;
+ rwl_dut_autodetect = FALSE;
+ (void)*argv++;
+ }
+
+ /* Provide option for disabling remote DUT autodetect */
+ if (*argv && strncmp(*argv, "--nodetect", strlen(*argv)) == 0) {
+ rwl_dut_autodetect = FALSE;
+ argv++;
+ }
+
+ if (*argv && strncmp (*argv, "--debug", strlen(*argv)) == 0) {
+ debug = TRUE;
+ argv++;
+ }
+
+ /* RWL socket transport Usage: --socket ipaddr/hostname [port num] */
+ if (*argv && strncmp (*argv, "--socket", strlen(*argv)) == 0) {
+ (void)*argv++;
+
+ remote_type = REMOTE_SOCKET;
+
+ if (!(*argv)) {
+ rwl_usage(remote_type);
+ return err;
+ }
+ /* IP address validation is done in client_shared file */
+ g_rwl_servIP = *argv;
+ (void)*argv++;
+
+ /* Port number validation is done in client_shared file */
+ g_rwl_servport = DEFAULT_SERVER_PORT;
+ if ((*argv) && (rwl_check_port_number(*argv, strlen(*argv)) == SUCCESS)) {
+ g_rwl_servport = atoi(*argv);
+ (void)*argv++;
+ }
+ }
+
+ /* RWL from system serial port on client to uart serial port on server */
+ /* Usage: --serial /dev/ttyS0 [--baud 115200] */
+ if (*argv && strncmp (*argv, "--serial", strlen(*argv)) == 0) {
+ (void)*argv++;
+ remote_type = REMOTE_SERIAL;
+ }
+
+ /* RWL from system serial port on client to uart dongle port on server */
+ /* Usage: --dongle /dev/ttyS0 [--baud 115200] */
+ if (*argv && strncmp (*argv, "--dongle", strlen(*argv)) == 0) {
+ (void)*argv++;
+ remote_type = REMOTE_DONGLE;
+ }
+
+#if defined(RWL_SERIAL) || defined(RWL_DONGLE)
+ if (remote_type == REMOTE_SERIAL || remote_type == REMOTE_DONGLE) {
+ if (!(*argv)) {
+ rwl_usage(remote_type);
+ return err;
+ }
+ g_rwl_device_name_serial = *argv;
+ (void)*argv++;
+ if (*argv && strncmp (*argv, "--baud", strlen(*argv)) == 0) {
+ (void)*argv++;
+ if ((*argv) && (rwl_check_port_number(*argv, strlen(*argv)) == SUCCESS)) {
+ g_rwl_device_baud = atoi(*argv);
+ (void)*argv++;
+ }
+ }
+ if ((serialHandle = rwl_open_pipe(remote_type, g_rwl_device_name_serial, 0, 0))
+ == NULL) {
+ DPRINT_ERR(ERR, "serial device open error\r\n");
+ return -1;
+ }
+ ifr = (*(struct ifreq *)serialHandle);
+ }
+#endif /* RWL_SERIAL */
+
+ /* RWL over wifi. Usage: --wifi mac_address */
+ if (*argv && strncmp (*argv, "--wifi", strlen(*argv)) == 0) {
+ (void)*argv++;
+ /* use default interface */
+ if (!*ifr.ifr_name)
+ wl_find(&ifr);
+
+ /* validate the interface */
+ if (!*ifr.ifr_name || (err = wl_check((void *)&ifr)) < 0) {
+ fprintf(stderr, "%s: wl driver adapter not found\n", wlu_av0);
+ exit(1);
+ }
+
+ remote_type = REMOTE_WIFI;
+
+ if (argc < 4) {
+ rwl_usage(remote_type);
+ return err;
+ }
+ /* copy server mac address to local buffer for later use by findserver cmd */
+ if (!wl_ether_atoe(*argv, (struct ether_addr *)g_rwl_buf_mac)) {
+ fprintf(stderr,
+ "could not parse as an ethternet MAC address\n");
+ return FAIL;
+ }
+ (void)*argv++;
+ }
+
+ if ((*argv) && (strlen(*argv) > 2) &&
+ (strncmp(*argv, "--interactive", strlen(*argv)) == 0)) {
+ interactive_flag = 1;
+ }
+
+ /* Process for local wl */
+ if (remote_type == NO_REMOTE) {
+ if (*argv && strncmp (*argv, "-h", strlen(*argv)) == 0) {
+ wl_usage(stdout, NULL); /* outputs multiple screens of help information */
+ return err;
+ }
+
+ if (interactive_flag == 1)
+ (void)*argv--;
+ err = process_args(&ifr, argv);
+ return err;
+ } else {
+#ifndef OLYMPIC_RWL
+ /* Autodetect remote DUT */
+ if (rwl_dut_autodetect == TRUE)
+ rwl_detect((void*)&ifr, debug, &rwl_os_type);
+#endif /* OLYMPIC_RWL */
+ }
+
+ /* RWL client needs to initialize ioctl_version */
+ if (wl_check((void *)&ifr) != 0) {
+ fprintf(stderr, "%s: wl driver adapter not found\n", wlu_av0);
+ exit(1);
+ }
+
+ if (interactive_flag == 1) {
+ err = do_interactive(&ifr);
+ return err;
+ }
+
+ if ((*argv) && (interactive_flag == 0)) {
+ err = process_args(&ifr, argv);
+ if ((err == BCME_SERIAL_PORT_ERR) && (remote_type == REMOTE_DONGLE)) {
+ DPRINT_ERR(ERR, "\n Retry again\n");
+ err = process_args((struct ifreq*)&ifr, argv);
+ }
+ return err;
+ }
+ rwl_usage(remote_type);
+#if defined(RWL_DONGLE) || RWL_SERIAL
+ if (remote_type == REMOTE_DONGLE || remote_type == REMOTE_SERIAL)
+ rwl_close_pipe(remote_type, (void*)&ifr);
+#endif /* RWL_DONGLE || RWL_SERIAL */
+ return err;
+}
+
+/*
+ * Function called for 'local' execution and for 'remote' non-interactive session
+ * (shell cmd, wl cmd)
+ */
+int
+process_args(struct ifreq* ifr, char **argv)
+{
+ char *ifname = NULL;
+ int help = 0;
+ int status = 0;
+ int vista_cmd_index;
+ int err = 0;
+ cmd_t *cmd = NULL;
+#ifdef RWL_WIFI
+ int retry;
+#endif
+
+ while (*argv) {
+ if ((strcmp (*argv, "sh") == 0) && (remote_type != NO_REMOTE)) {
+ (void)*argv++; /* Get the shell command */
+ if (*argv) {
+ /* Register handler in case of shell command only */
+ err = rwl_shell_cmd_proc((void*)ifr, argv, SHELL_CMD);
+ } else {
+ DPRINT_ERR(ERR, "Enter the shell "
+ "command, e.g. ls(Linux) or dir(Win CE)\n");
+ err = -1;
+ }
+ return err;
+ }
+
+#ifdef RWLASD
+ if ((strcmp (*argv, "asd") == 0) && (remote_type != NO_REMOTE)) {
+ (void)*argv++; /* Get the asd command */
+ if (*argv) {
+ err = rwl_shell_cmd_proc((void*)ifr, argv, ASD_CMD);
+ } else {
+ DPRINT_ERR(ERR, "Enter the ASD command, e.g. ca_get_version\n");
+ err = -1;
+ }
+ return err;
+ }
+#endif
+ if (rwl_os_type == WINVISTA_OS) {
+ for (vista_cmd_index = 0; remote_vista_cmds[vista_cmd_index] &&
+ strcmp(remote_vista_cmds[vista_cmd_index], *argv);
+ vista_cmd_index++);
+ if (remote_vista_cmds[vista_cmd_index] != NULL) {
+ err = rwl_shell_cmd_proc((void *)ifr, argv, VISTA_CMD);
+ if ((remote_type == REMOTE_WIFI) && ((!strcmp(*argv, "join")))) {
+#ifdef RWL_WIFI
+ DPRINT_INFO(OUTPUT,
+ "\nChannel will be synchronized by Findserver\n\n");
+ sleep(RWL_WIFI_JOIN_DELAY);
+ for (retry = 0; retry < RWL_WIFI_RETRY; retry++) {
+ if ((rwl_find_remote_wifi_server(ifr,
+ &g_rwl_buf_mac[0]) == 0)) {
+ break;
+ }
+ }
+#endif /* RWL_WIFI */
+ }
+ return err;
+ }
+ }
+
+ if ((status = wl_option(&argv, &ifname, &help)) == CMD_OPT) {
+ if (help)
+ break;
+ if (ifname) {
+ if (remote_type == NO_REMOTE) {
+ strncpy((*ifr).ifr_name, ifname, IFNAMSIZ);
+ }
+ else {
+ strncpy(g_rem_ifname, ifname, IFNAMSIZ);
+ }
+ }
+ continue;
+ }
+ /* parse error */
+ else if (status == CMD_ERR)
+ break;
+
+ if (remote_type == NO_REMOTE) {
+ /* use default interface */
+ if (!*(*ifr).ifr_name)
+ wl_find(ifr);
+
+ /* validate the interface */
+ if (!*(*ifr).ifr_name || (err = wl_check((void *)ifr)) < 0) {
+ fprintf(stderr, "%s: wl driver adapter not found\n", wlu_av0);
+ exit(1);
+ }
+
+ if ((strcmp (*argv, "--interactive") == 0) || (interactive_flag == 1)) {
+ err = do_interactive(ifr);
+ return err;
+ }
+ }
+ /* search for command */
+ cmd = wl_find_cmd(*argv);
+ /* if not found, use default set_var and get_var commands */
+ if (!cmd) {
+ cmd = &wl_varcmd;
+ }
+#ifdef RWL_WIFI
+ if (!strcmp(cmd->name, "findserver")) {
+ remote_wifi_ser_init_cmds((void *) ifr);
+ }
+#endif /* RWL_WIFI */
+
+ /* RWL over Wifi supports 'lchannel' command which lets client
+ * (ie *this* machine) change channels since normal 'channel' command
+ * applies to the server (ie target machine)
+ */
+ if (remote_type == REMOTE_WIFI) {
+#ifdef RWL_WIFI
+ if (!strcmp(argv[0], "lchannel")) {
+ strcpy(argv[0], "channel");
+ rwl_wifi_swap_remote_type(remote_type);
+ err = (*cmd->func)((void *) ifr, cmd, argv);
+ rwl_wifi_swap_remote_type(remote_type);
+ } else {
+ err = (*cmd->func)((void *) ifr, cmd, argv);
+ }
+ /* After join cmd's gets exeuted on the server side , client needs to know
+ * the channel on which the server is associated with AP , after delay of
+ * few seconds client will intiate the scan on diffrent channels by calling
+ * rwl_find_remote_wifi_server fucntion
+ */
+ if ((!strcmp(cmd->name, "join") || ((!strcmp(cmd->name, "ssid") &&
+ (*(++argv) != NULL))))) {
+ DPRINT_INFO(OUTPUT, "\n Findserver is called to synchronize the"
+ "channel\n\n");
+ sleep(RWL_WIFI_JOIN_DELAY);
+ for (retry = 0; retry < RWL_WIFI_RETRY; retry++) {
+ if ((rwl_find_remote_wifi_server(ifr,
+ &g_rwl_buf_mac[0]) == 0)) {
+ break;
+ }
+ }
+ }
+#endif /* RWL_WIFI */
+ } else {
+ /* do command */
+ err = (*cmd->func)((void *) ifr, cmd, argv);
+ }
+ break;
+ } /* while loop end */
+
+ /* provide for help on a particular command */
+ if (help && *argv) {
+ cmd = wl_find_cmd(*argv);
+ if (cmd) {
+ wl_cmd_usage(stdout, cmd);
+ } else {
+ DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", type -h for help\n",
+ wlu_av0, *argv);
+ }
+ } else if (!cmd) {
+ fprintf(stderr, "type -h for help\n");
+ } else if (err == BCME_USAGE_ERROR) {
+ wl_cmd_usage(stderr, cmd);
+ } else if (err == BCME_IOCTL_ERROR) {
+ wl_printlasterror((void *) ifr);
+ } else if (err == BCME_BADARG) {
+ DPRINT_ERR(ERR, "One or more parameters have invalid values\n");
+ } else if (err == BCME_NODEVICE) {
+ DPRINT_ERR(ERR, "%s : wl driver adapter not found\n", g_rem_ifname);
+ } else if (err) {
+ DPRINT_ERR(ERR, "error\n");
+ }
+
+ return err;
+}
+
+/* Function called for 'local' interactive session and for 'remote' interactive session */
+static int
+do_interactive(struct ifreq *ifr)
+{
+ int err = 0;
+
+#ifdef RWL_WIFI
+ int retry;
+#endif
+
+ while (1) {
+ char *fgsret;
+ char line[INTERACTIVE_MAX_INPUT_LENGTH];
+ fprintf(stdout, "> ");
+ fgsret = fgets(line, sizeof(line), stdin);
+
+ /* end of file */
+ if (fgsret == NULL)
+ break;
+ if (line[0] == '\n')
+ continue;
+
+ if (strlen (line) > 0) {
+ /* skip past first arg if it's "wl" and parse up arguments */
+ char *argv[INTERACTIVE_NUM_ARGS];
+ int argc;
+ char *token;
+ argc = 0;
+
+ while (argc < (INTERACTIVE_NUM_ARGS - 1) &&
+ (token = strtok(argc ? NULL : line, " \t\n")) != NULL) {
+
+ /* Specifically make sure empty arguments (like SSID) are empty */
+ if (token[0] == '"' && token[1] == '"') {
+ token[0] = '\0';
+ }
+
+ argv[argc++] = token;
+ }
+ argv[argc] = NULL;
+ if (argc == (INTERACTIVE_NUM_ARGS - 1) &&
+ (token = strtok(NULL, " \t")) != NULL) {
+ printf("wl:error: too many args; argc must be < %d\n",
+ (INTERACTIVE_NUM_ARGS - 1));
+ continue;
+ }
+#ifdef RWL_WIFI
+ if (!strcmp(argv[0], "findserver")) {
+ remote_wifi_ser_init_cmds((void *) ifr);
+ }
+#endif /* RWL_WIFI */
+
+ if (strcmp(argv[0], "q") == 0 || strcmp(argv[0], "exit") == 0) {
+ break;
+ }
+
+ if ((strcmp(argv[0], "sh") == 0) && (remote_type != NO_REMOTE)) {
+ if (argv[1]) {
+ process_args(ifr, argv);
+ } else {
+ DPRINT_ERR(ERR, "Give shell command");
+ continue;
+ }
+ } else { /* end shell */
+ /* check for lchannel support,applicable only for wifi transport.
+ * when lchannel is called remote type is swapped by calling swap_
+ * remote_type.This is done to change, the remote type to local,
+ * so that local machine's channel can be executed and
+ * returned to the user.
+ * To get back the original remote type, swap is recalled.
+ */
+ if (remote_type == REMOTE_WIFI) {
+#ifdef RWL_WIFI
+ if (!strcmp(argv[0], "lchannel")) {
+ strcpy(argv[0], "channel");
+ rwl_wifi_swap_remote_type(remote_type);
+ err = wl_do_cmd(ifr, argv);
+ rwl_wifi_swap_remote_type(remote_type);
+ } else {
+ err = wl_do_cmd(ifr, argv);
+ }
+ /* After join cmd's gets exeuted on the server side, client
+ * needs to know the channel on which the server is associated
+ * with AP , after delay of few seconds client will intiate the
+ * scan on diffrent channels by calling
+ * rwl_find_remote_wifi_server function
+ */
+ if ((!strcmp(argv[0], "join")) ||
+ (!strcmp(argv[0], "ssid"))) {
+ DPRINT_INFO(OUTPUT, "\n Findserver is called"
+ "after the join issued to remote \n \n");
+ sleep(RWL_WIFI_JOIN_DELAY);
+ for (retry = 0; retry < RWL_WIFI_RETRY; retry++) {
+ if ((rwl_find_remote_wifi_server(ifr,
+ &g_rwl_buf_mac[0]) == 0)) {
+ break;
+ }
+ }
+ }
+#endif /* RWL_WIFI */
+ } else {
+ err = wl_do_cmd(ifr, argv);
+ }
+ } /* end of wl */
+ } /* end of strlen (line) > 0 */
+ } /* while (1) */
+
+ return err;
+}
+
+/*
+ * find command in argv and execute it
+ * Won't handle changing ifname yet, expects that to happen with the --interactive
+ * Return an error if unable to find/execute command
+ */
+static int
+wl_do_cmd(struct ifreq *ifr, char **argv)
+{
+ cmd_t *cmd = NULL;
+ int err = 0;
+ int help = 0;
+ char *ifname = NULL;
+ int status = CMD_WL;
+
+ /* skip over 'wl' if it's there */
+ if (*argv && strcmp (*argv, "wl") == 0) {
+ argv++;
+ }
+
+ /* handle help or interface name changes */
+ if (*argv && (status = wl_option (&argv, &ifname, &help)) == CMD_OPT) {
+ if (ifname) {
+ fprintf(stderr,
+ "Interface name change not allowed within --interactive\n");
+ }
+ }
+
+ /* in case wl_option eats all the args */
+ if (!*argv) {
+ return err;
+ }
+
+ if (status != CMD_ERR) {
+ /* search for command */
+ cmd = wl_find_cmd(*argv);
+
+ /* defaults to using the set_var and get_var commands */
+ if (!cmd) {
+ cmd = &wl_varcmd;
+ }
+ /* do command */
+ err = (*cmd->func)((void *)ifr, cmd, argv);
+ }
+
+ if (help) {
+ if (*argv) {
+ /* provide for help on a particular command */
+ cmd = wl_find_cmd(*argv);
+ if (cmd) {
+ wl_cmd_usage(stdout, cmd);
+ } else {
+ DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", "
+ "type -h for help\n", wlu_av0, *argv);
+ }
+ } else {
+ wl_usage(stdout, NULL); /* outputs multiple screens of help information */
+ }
+ } else if (err == BCME_USAGE_ERROR)
+ wl_cmd_usage(stderr, cmd);
+ else if (err == BCME_IOCTL_ERROR)
+ wl_printlasterror((void *)ifr);
+ else if (err == BCME_NODEVICE)
+ DPRINT_ERR(ERR, "%s : wl driver adapter not found\n", g_rem_ifname);
+
+ return err;
+}
+
+/* Search the wl_cmds table for a matching command name.
+ * Return the matching command or NULL if no match found.
+ */
+static cmd_t *
+wl_find_cmd(char* name)
+{
+ return wlu_find_cmd(name);
+}
+
+void def_handler(int signum)
+{
+ UNUSED_PARAMETER(signum);
+ kill(g_child_pid, SIGINT);
+ kill(getpid(), SIGINT);
+ exit(0);
+}
+/* Create a child that waits for Ctrl-C at the client side
+ */
+int rwl_shell_createproc(void *wl)
+{
+ UNUSED_PARAMETER(wl);
+ signal(SIGINT, ctrlc_handler);
+ signal(SIGTERM, def_handler);
+ signal(SIGABRT, def_handler);
+ return fork();
+}
+
+/* In case if the server shell command exits normally
+ * then kill the thread that was waiting for Ctr-C to happen
+ * at the client side
+ */
+void rwl_shell_killproc(int pid)
+{
+ kill(pid, SIGKILL);
+ signal(SIGINT, SIG_DFL);
+ wait(NULL);
+}
+#ifdef RWL_SOCKET
+/* to validate hostname/ip given by the client */
+int validate_server_address()
+{
+ struct hostent *he;
+ struct ipv4_addr temp;
+ if (!wl_atoip(g_rwl_servIP, &temp)) {
+ /* Wrong IP address format check for hostname */
+ if ((he = gethostbyname(g_rwl_servIP)) != NULL) {
+ if (!wl_atoip(*he->h_addr_list, &temp)) {
+ g_rwl_servIP =
+ inet_ntoa(*(struct in_addr *)*he->h_addr_list);
+ if (g_rwl_servIP == NULL) {
+ DPRINT_ERR(ERR, "Error at inet_ntoa \n");
+ return FAIL;
+ }
+ } else {
+ DPRINT_ERR(ERR, "Error in IP address \n");
+ return FAIL;
+ }
+ } else {
+ DPRINT_ERR(ERR, "Enter correct IP address/hostname format\n");
+ return FAIL;
+ }
+ }
+ return SUCCESS;
+}
+#endif /* RWL_SOCKET */
diff --git a/wl/src/wl/exe/wlu_nl80211.c b/wl/src/wl/exe/wlu_nl80211.c
new file mode 100644
index 0000000..0587aad
--- /dev/null
+++ b/wl/src/wl/exe/wlu_nl80211.c
@@ -0,0 +1,210 @@
+/*
+ * nl80211 linux driver interface.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: $
+ */
+#include <errno.h>
+#include <linux/nl80211.h>
+#include <wlioctl.h>
+#include <brcm_nl80211.h>
+#include "wlu_nl80211.h"
+
+static struct nla_policy wl_nl_policy[BCM_NLATTR_MAX + 1] = {
+ [BCM_NLATTR_LEN] = { .type = NLA_U16 },
+ [BCM_NLATTR_DATA] = { .type = NLA_UNSPEC },
+};
+
+/* libnl 1.x compatibility code */
+#if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30)
+static inline struct nl_handle *nl_socket_alloc(void)
+{
+ return nl_handle_alloc();
+}
+
+static inline void nl_socket_free(struct nl_sock *h)
+{
+ nl_handle_destroy(h);
+}
+#endif /* CONFIG_LIBNL20 && CONFIG_LIBNL30 */
+
+static int wlnl_error_handler(struct sockaddr_nl * nla, struct nlmsgerr *err, void *arg)
+{
+ struct nl_prv_data *prv = arg;
+ UNUSED_PARAMETER(nla);
+
+ if (err->error) {
+ prv->err = err->error;
+ return NL_STOP;
+ }
+ return NL_SKIP;
+}
+
+static int wlnl_finish_handler(struct nl_msg *msg, void *arg)
+{
+ UNUSED_PARAMETER(msg);
+ UNUSED_PARAMETER(arg);
+ return NL_SKIP;
+}
+
+static int wlnl_ack_handler(struct nl_msg *msg, void *arg)
+{
+ struct nl_prv_data *prv = arg;
+ UNUSED_PARAMETER(msg);
+
+ prv->err = 0;
+ return NL_STOP;
+}
+
+static int wlnl_valid_handler(struct nl_msg *msg, void *arg)
+{
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *attrs[NL80211_ATTR_MAX + 1];
+ struct nlattr *bcmnl[BCM_NLATTR_MAX + 1];
+ struct nl_prv_data *prv = arg;
+ int ret;
+ uint payload;
+
+ nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!attrs[NL80211_ATTR_VENDOR_DATA]) {
+ fprintf(stderr, "Could not find attrs NL80211_ATTR_VENDOR_DATA\n");
+ return NL_SKIP;
+ }
+
+ ret = nla_parse_nested(bcmnl, BCM_NLATTR_MAX,
+ attrs[NL80211_ATTR_VENDOR_DATA], wl_nl_policy);
+ if (ret != 0 || !bcmnl[BCM_NLATTR_LEN] || !bcmnl[BCM_NLATTR_DATA]) {
+ fprintf(stderr, "nla_parse_nested error\n");
+ return NL_SKIP;
+ }
+
+ payload = nla_get_u16(bcmnl[BCM_NLATTR_LEN]);
+ if (payload > prv->len)
+ payload = prv->len;
+ memcpy(prv->data, nla_data(bcmnl[BCM_NLATTR_DATA]), payload);
+ prv->data += payload;
+ prv->len -= payload;
+
+ return NL_SKIP;
+}
+
+int wlnl_sock_connect(struct wl_netlink_info *wl_nli)
+{
+ wl_nli->nl = nl_socket_alloc();
+ if (wl_nli->nl == NULL)
+ return -1;
+
+ if (genl_connect(wl_nli->nl) < 0) {
+ fprintf(stderr, "netlink connection failed\n");
+ goto err;
+ }
+
+ wl_nli->nl_id = genl_ctrl_resolve(wl_nli->nl, "nl80211");
+ if (wl_nli->nl_id < 0) {
+ fprintf(stderr, "'nl80211' netlink not found\n");
+ goto err;
+ }
+
+ wl_nli->cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (wl_nli->cb == NULL)
+ goto err;
+
+ nl_socket_set_cb(wl_nli->nl, wl_nli->cb);
+ return 0;
+
+err:
+ nl_cb_put(wl_nli->cb);
+ nl_socket_free(wl_nli->nl);
+ fprintf(stderr, "nl80211 connection failed\n");
+ return -1;
+}
+
+void wlnl_sock_disconnect(struct wl_netlink_info *wl_nli)
+{
+ nl_cb_put(wl_nli->cb);
+ nl_socket_free(wl_nli->nl);
+}
+
+int wlnl_do_vndr_cmd(struct wl_netlink_info *wl_nli, wl_ioctl_t *ioc)
+{
+ struct nl_msg *msg;
+ struct nl_prv_data prv_dat;
+ struct bcm_nlmsg_hdr *nlioc;
+ uint msglen = ioc->len;
+
+ msg = nlmsg_alloc();
+ if (msg == NULL)
+ return -ENOMEM;
+
+ /* nlmsg_alloc() can only allocate default_pagesize packet, cap
+ * any buffer send down to 1536 bytes
+ * DO NOT switch to nlmsg_alloc_size because Android doesn't support it
+ */
+ if (msglen > 0x600)
+ msglen = 0x600;
+ msglen += sizeof(struct bcm_nlmsg_hdr);
+ nlioc = malloc(msglen);
+ if (nlioc == NULL) {
+ nlmsg_free(msg);
+ return -ENOMEM;
+ }
+ nlioc->cmd = ioc->cmd;
+ nlioc->len = ioc->len;
+ nlioc->offset = sizeof(struct bcm_nlmsg_hdr);
+ nlioc->set = ioc->set;
+ nlioc->magic = 0;
+ memcpy(((void *)nlioc) + nlioc->offset, ioc->buf, msglen - nlioc->offset);
+
+ /* fill testmode message */
+ genlmsg_put(msg, 0, 0, wl_nli->nl_id, 0, 0, NL80211_CMD_VENDOR, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wl_nli->ifidx);
+ NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM);
+ NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD, BRCM_VENDOR_SCMD_PRIV_STR);
+ NLA_PUT(msg, NL80211_ATTR_VENDOR_DATA, msglen, nlioc);
+
+ prv_dat.err = nl_send_auto_complete(wl_nli->nl, msg);
+ if (prv_dat.err < 0) {
+ goto out;
+ }
+
+ prv_dat.err = 1;
+ prv_dat.nlioc = nlioc;
+ prv_dat.data = ioc->buf;
+ prv_dat.len = ioc->len;
+ nl_cb_err(wl_nli->cb, NL_CB_CUSTOM, wlnl_error_handler, &prv_dat);
+ nl_cb_set(wl_nli->cb, NL_CB_ACK, NL_CB_CUSTOM,
+ wlnl_ack_handler, &prv_dat);
+ nl_cb_set(wl_nli->cb, NL_CB_FINISH, NL_CB_CUSTOM,
+ wlnl_finish_handler, &prv_dat);
+ nl_cb_set(wl_nli->cb, NL_CB_VALID, NL_CB_CUSTOM,
+ wlnl_valid_handler, &prv_dat);
+ while (prv_dat.err > 0)
+ nl_recvmsgs(wl_nli->nl, wl_nli->cb);
+
+out:
+ free(nlioc);
+ nlmsg_free(msg);
+ return prv_dat.err;
+
+nla_put_failure:
+ fprintf(stderr, "setting netlink attribute failed\n");
+ prv_dat.err = -EFAULT;
+ goto out;
+}
diff --git a/wl/src/wl/exe/wlu_nl80211.h b/wl/src/wl/exe/wlu_nl80211.h
new file mode 100644
index 0000000..3fa0977
--- /dev/null
+++ b/wl/src/wl/exe/wlu_nl80211.h
@@ -0,0 +1,52 @@
+/*
+ * Definitions for DHD nl80211 driver interface.
+ *
+ * Copyright (C) 2017, Broadcom. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: $
+ */
+
+#ifndef DHDU_NL80211_H_
+#define DHDU_NL80211_H_
+
+#ifdef NL80211
+
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+
+/* libnl 1.x compatibility code */
+#if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30)
+#define nl_sock nl_handle
+#endif
+
+struct wl_netlink_info
+{
+ struct nl_sock *nl;
+ struct nl_cb *cb;
+ int nl_id;
+ int ifidx;
+};
+
+int wlnl_sock_connect(struct wl_netlink_info *wl_nli);
+void wlnl_sock_disconnect(struct wl_netlink_info *wl_nli);
+int wlnl_do_vndr_cmd(struct wl_netlink_info *wl_nli, wl_ioctl_t *ioc);
+
+#endif /* NL80211 */
+
+#endif /* DHDU_NL80211_H_ */
diff --git a/wl/src/wl/exe/wlu_pipe.c b/wl/src/wl/exe/wlu_pipe.c
new file mode 100644
index 0000000..157fa24
--- /dev/null
+++ b/wl/src/wl/exe/wlu_pipe.c
@@ -0,0 +1,1109 @@
+/*
+ * Common Functionality for pipe
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_pipe.c 625881 2016-03-18 02:58:34Z $
+ */
+#ifdef WIN32
+#define NEED_IR_TYPES
+
+#include <windows.h>
+#include <epictrl.h>
+#include <irelay.h>
+#endif /* WIN32 */
+
+#ifdef LINUX
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <wlioctl.h>
+#include <net/if.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#if defined(TARGETOS_symbian)
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#else
+#if !defined(TARGETOS_nucleus) && !defined(__FreeBSD__)
+#include <malloc.h>
+#endif
+#endif /* TARGETOS_symbian */
+#include <typedefs.h>
+#include <wlioctl.h>
+
+#include <proto/ethernet.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <bcmcdc.h>
+#include <proto/802.11.h>
+#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR)
+#include <rwl_wifi.h>
+#endif /* defined(RWL_WIFI) || defined(WIFI_REFLECTOR) */
+#include "wlu.h"
+#include "wlu_remote.h"
+#ifdef DHD_VISTA
+#include "wlu_remote_vista.h"
+#endif /* DHD_VISTA */
+
+static rem_ioctl_t rem_cdc;
+char *g_rwl_device_name_serial = "";
+int g_rwl_device_baud = 115200;
+bool g_rwl_swap = FALSE;
+char g_rem_ifname[IFNAMSIZ] = "\0";
+int need_speedy_response; /* Indicate findserver is checking channels */
+
+#ifdef LINUX
+ /* Linux 100 usec */
+#define SYNC_TIME 100
+#else
+ /* WinXP 1 sec */
+#define SYNC_TIME 1
+#endif
+
+#define UART_FIFO_LEN 64
+#define END_OF_PACK_SEP_LEN 2
+#define INIT_CMD_SLEEP 500
+#define dtoh32(i) i
+
+/* dword align allocation */
+union {
+ uchar bufdata[ETHER_ADDR_LEN];
+ uint32 alignme;
+} bufmac_wlu;
+char *g_rwl_buf_mac = (char*) &bufmac_wlu.bufdata;
+
+#ifdef RWL_WIFI
+/* dword align allocation */
+union {
+ uchar shelldata[WL_MAX_BUF_LEN];
+ uint32 alignme;
+} shell_wlu;
+char *g_rwl_buf_shell = (char*) &shell_wlu.shelldata;
+int rwl_find_remote_wifi_server(void *wl, char *id);
+int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set);
+
+#ifdef DHD_VISTA
+extern GUID dev;
+#endif
+
+/*
+ * This function runs a set of commands before running the wi-fi server
+ * This is avoids packet drops and improves performance.
+ * We run the following wl commands
+ * up, mpc 0, wsec 0, slow_timer 999999, fast_timer 999999, glacial_timer 999999
+ * legacylink 1, monitor 1.
+ */
+void remote_wifi_ser_init_cmds(void *wl)
+{
+ int err;
+ char bigbuf[RWL_WIFI_BUF_LEN];
+ uint len = 0, count;
+ /* The array stores command, length and then data format */
+ remote_wifi_cmds_t wifi_cmds[] = {
+ {WLC_UP, NULL, 0x0},
+ {WLC_SET_VAR, "mpc", 0},
+ {WLC_SET_WSEC, NULL, 0x0},
+ {WLC_SET_VAR, "slow_timer", 999999},
+ {WLC_SET_VAR, "fast_timer", 999999},
+ {WLC_SET_VAR, "glacial_timer", 999999},
+ {WLC_SET_MONITOR, NULL, 0x1},
+ {WLC_SET_PM, NULL, 0x0}
+ };
+
+ for (count = 0; count < ARRAYSIZE(wifi_cmds); count++) {
+
+ if (wifi_cmds[count].data == NULL)
+ len = sizeof(int);
+ else
+ len = (uint)strlen(wifi_cmds[count].data) + 1 + sizeof(int);
+
+ /* If the command length exceeds the buffer length continue
+ * executing the next command
+ */
+ if (len > sizeof(bigbuf)) {
+ DPRINT_ERR(ERR, "Err: command len exceeds buf len. Check"
+ "initialization cmds\n");
+ continue;
+ }
+
+ if (wifi_cmds[count].data != NULL) {
+ strcpy(bigbuf, wifi_cmds[count].data);
+ memcpy(&bigbuf[strlen(wifi_cmds[count].data)+1],
+ (char*)&wifi_cmds[count].value, sizeof(int));
+ } else {
+ memcpy(&bigbuf[0], (char*)&wifi_cmds[count].value, sizeof(int));
+ }
+#ifdef WIN32
+ /* Add OID base for NDIS commands */
+
+#ifdef DHD_VISTA
+ err = (int)ir_vista_setinformation(wl, &dev, wifi_cmds[count].cmd + WL_OID_BASE,
+ bigbuf, &len);
+#else
+ err = (int)ir_setinformation(wl, wifi_cmds[count].cmd + WL_OID_BASE, bigbuf, &len);
+#endif
+#endif /* DHD_VISTA */
+
+#if defined(LINUX) || defined(TARGETOS_symbian)
+ if (wifi_cmds[count].cmd == WLC_UP)
+ /* NULL needs to be passed to the driver if WL UP command needs to
+ * be executed Otherwise driver hangs
+ */
+ err = wl_ioctl(wl, wifi_cmds[count].cmd,
+ NULL, 0, TRUE);
+ else
+ err = wl_ioctl(wl, wifi_cmds[count].cmd,
+ (void*)&bigbuf, len, TRUE);
+
+#endif
+ rwl_sleep(INIT_CMD_SLEEP);
+ }
+ BCM_REFERENCE(err);
+}
+
+/* When user wants to execute local CMD being in remote wifi mode, this fucntion is used
+ * to change the remote types.
+ * This fucntion is called to swap the remote type to execute the cmd using the local
+ * driver interface.
+ * This is required for to call proper front end fucntions to achive the local set/get ioctl.
+ */
+void
+rwl_wifi_swap_remote_type(int flag)
+{
+ static int remote_flag;
+ if (flag == REMOTE_WIFI) {
+ remote_type = NO_REMOTE;
+ remote_flag = flag;
+ } else if (remote_flag == REMOTE_WIFI) {
+ remote_type = remote_flag;
+ remote_flag = flag;
+ }
+ return;
+}
+
+void
+rwl_wifi_free_list(dot11_action_wifi_vendor_specific_t *list[])
+{
+ int i;
+ for (i = 0; i < RWL_DEFAULT_WIFI_FRAG_COUNT; i++) {
+ if (list[i])
+ free(list[i]);
+ }
+}
+
+/*
+ * Configures local channel for finding server.
+ * Server call this fucntion for getting its current channel,
+ * client uses this fucntion for setting its channel to new channel.
+ */
+static int
+rwl_wifi_config_channel(void *wl, int cmd, int *channel)
+{
+ int error;
+ channel_info_t ci;
+ error = -1;
+ /* Get functionality is used only by server */
+ if (cmd == WLC_GET_CHANNEL) {
+ memset((char*)&ci, 0, sizeof(ci));
+ if ((error = wl_get(wl, cmd, &ci, sizeof(channel_info_t))) < 0)
+ return error;
+ ci.hw_channel = dtoh32(ci.hw_channel);
+ ci.scan_channel = dtoh32(ci.scan_channel);
+ ci.target_channel = dtoh32(ci.target_channel);
+ if (ci.scan_channel) {
+ printf("Scan in progress.\n");
+ }
+ *channel = ci.hw_channel;
+ }
+
+ if (cmd == WLC_SET_CHANNEL) {
+ /* Set functionality is used by the client */
+ ci.target_channel = *channel;
+ /* When user wants to execute local CMD being in remote wifi mode,
+ * rwl_wifi_swap_remote_type fucntion is used to change the remote types.
+ */
+ rwl_wifi_swap_remote_type(remote_type);
+ error = wl_set(wl, cmd, &ci.target_channel, sizeof(int));
+ /* rever it back to same old remote type */
+ rwl_wifi_swap_remote_type(remote_type);
+ }
+ return error;
+}
+/*
+allocate the memory for action frame and update with wifi tranport header.
+*/
+dot11_action_wifi_vendor_specific_t *
+rwl_wifi_allocate_actionframe()
+{
+ dot11_action_wifi_vendor_specific_t *action_frame;
+
+ if ((action_frame = (dot11_action_wifi_vendor_specific_t *)
+ malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) {
+ DPRINT_ERR(ERR, "rwl_wifi_allocate_actionframe: unable to allocate frame \n");
+ return action_frame;
+ }
+ action_frame->category = RWL_ACTION_WIFI_CATEGORY;
+ action_frame->OUI[0] = RWL_WIFI_OUI_BYTE0;
+ action_frame->OUI[1] = RWL_WIFI_OUI_BYTE1;
+ action_frame->OUI[2] = RWL_WIFI_OUI_BYTE2;
+ action_frame->type = RWL_WIFI_DEFAULT_TYPE;
+ action_frame->subtype = RWL_WIFI_DEFAULT_SUBTYPE;
+
+ return action_frame;
+}
+/*
+ * Send the valid action frame (CDC+DATA) through the REF driver interface.
+ * if the CMD is "findserver" then "findmypeer" frames are sent on the diffrent
+ * channels to reconnect
+ * to with server. Other wl cmd takes the normal path.
+ * parameter 3 , i.e. buf contains the cmd line arguments and buf_len is the actual
+ * length of the buf. data_len is the length of the actual data to be sent to remote server.
+ */
+int
+remote_CDC_wifi_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags)
+{
+ rem_ioctl_t *rem_ptr = &rem_cdc;
+ int error, read_try;
+ dot11_action_wifi_vendor_specific_t *rem_wifi_send;
+
+ /* prepare CDC header */
+ rem_ptr->msg.cmd = cmd;
+ rem_ptr->msg.len = buf_len;
+ rem_ptr->msg.flags = flags;
+ rem_ptr->data_len = data_len;
+
+ if (strlen(g_rem_ifname) != 0)
+ strncpy(rem_ptr->intf_name, g_rem_ifname, (int)IFNAMSIZ);
+ rwl_swap_header(rem_ptr, HOST_TO_NETWORK);
+
+ if ((data_len > buf_len)) {
+ DPRINT_ERR(ERR, "remote_CDC_wifi_tx: data_len (%d) > buf_len (%d)\n",
+ data_len, buf_len);
+ return (FAIL);
+ }
+ /* client will not send data greater than RWL_WIFI_FRAG_DATA_SIZE to server,
+ * this condition should not be hit on client side, when sending the cmd
+ * to remote server
+ */
+ if (data_len > RWL_WIFI_FRAG_DATA_SIZE)
+ DPRINT_DBG(OUTPUT, "data size exceeds data_len %d\n", rem_ptr->msg.len);
+
+ if ((buf != NULL) && (strlen((char*)buf) >= (sizeof(RWL_WIFI_FIND_SER_CMD)-1)) &&
+ (!strcmp((char*)buf, RWL_WIFI_FIND_SER_CMD))) {
+ /* This is special case for wifi, when user wants to findserver,
+ * client has to execute it locally.Find the channel on the on
+ * which DUT is operating and sync up with specified MAC address,
+ * retry if fails to find the server
+ */
+ for (read_try = 0; read_try < RWL_WIFI_RETRY; read_try++) {
+ if (((error = rwl_find_remote_wifi_server(wl,
+ &g_rwl_buf_mac[0])) == 0)) {
+ break;
+ }
+ }
+ return error;
+ }
+
+ if ((rem_wifi_send = rwl_wifi_allocate_actionframe()) == NULL) {
+ DPRINT_ERR(ERR, "remote_CDC_wifi_tx: Failed to allocate memory\n");
+ return (FAIL);
+ }
+ /* only data length needs to be sent to remote server using this function
+ * This function is only meant for client to send data to server
+ * Copy the CDC header and data to action frame data feild
+ * Now we have encapsulated the CDC header and data completely to in the
+ * action frame.
+ */
+ memcpy((void*)&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET],
+ (char*)rem_ptr, REMOTE_SIZE);
+ if (buf != NULL) {
+ memcpy((void*)&rem_wifi_send->data[REMOTE_SIZE], buf, data_len);
+ }
+
+ /* Send the action frame to remote server using the rwl_var_setbuf fucntion,
+ * which will use the local driver interface to send this frame on the air
+ */
+ if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, rem_wifi_send,
+ RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
+ DPRINT_ERR(ERR, "Unable to read the action frame %d error\n", error);
+ }
+ free(rem_wifi_send);
+ return error;
+}
+
+/*
+ * Read the valid action frame through the REF/DUT driver interface.
+ * Retry for no of times, wait for action frame for the specified time.
+ */
+int
+remote_CDC_DATA_wifi_rx(void *wl, dot11_action_wifi_vendor_specific_t * rec_frame)
+{
+ int error, read_try;
+ void *ptr = NULL;
+
+
+ /* retry is to ensure to read late arrival action frame */
+ for (read_try = 0; read_try < RWL_WIFI_RX_RETRY; read_try++) {
+ /* read the action frame queued in the local driver wifi queue */
+ if ((error = rwl_var_getbuf(wl, RWL_WIFI_GET_ACTION_CMD, rec_frame,
+ RWL_WIFI_ACTION_FRAME_SIZE, &ptr)) < 0) {
+ DPRINT_ERR(ERR, "remote_CDC_DATA_wifi_rx: Error in reading the frame %d\n",
+ error);
+ return error;
+ }
+ /* copy the read action frame to the user frame and cjheck for the action category.
+ * If the action category matches with RWL_ACTION_WIFI_CATEGORY ,
+ * then its the valid frame, otherwise ignore it.
+ */
+ memcpy((char*)rec_frame, ptr, RWL_WIFI_ACTION_FRAME_SIZE);
+
+ if (rec_frame->category == RWL_ACTION_WIFI_CATEGORY) {
+ break;
+ } else {
+ /* If we are executing findserver then sleep less */
+ if (!need_speedy_response)
+ rwl_sleep(RWL_WIFI_RX_DELAY);
+ else
+ rwl_sleep(RWL_CHANNEL_RX_SCAN_DELAY);
+ }
+ }
+ /* If failed to get the valid frame , indicate the error */
+ if (!(rec_frame->category == RWL_ACTION_WIFI_CATEGORY)) {
+ return (FAIL);
+ }
+ return error;
+}
+/*
+ * read data that has reached client in fragments. If the functtion is
+ * called from rwl_shell_information_fe then the flag will be set to 1.
+ * For shell response this function will output the response on the standard interface.
+ * Response will be coming in out of order , this fucntion will make it inorder.
+ * Duplicate action frames are ignored.
+ */
+int
+remote_CDC_DATA_wifi_rx_frag(void *wl, rem_ioctl_t *rem_ptr, uint input_len,
+void *input, bool shell)
+{
+ int error, totalfrag, seq_num, num_frags, remainingbytes;
+ dot11_action_wifi_vendor_specific_t *rec_frame;
+ uchar *input_buf = (uchar*)input;
+ /* An array of pointers to each recieved frag */
+ dot11_action_wifi_vendor_specific_t *master_list[RWL_DEFAULT_WIFI_FRAG_COUNT];
+
+ UNUSED_PARAMETER(input_len);
+ remainingbytes = 0;
+
+ memset(master_list, 0, sizeof(master_list));
+ /* in case of shell cmd's receive size is unknown */
+ if (shell) {
+ input_buf = (uchar*)g_rwl_buf_shell;
+ memset(input_buf, 0, WL_MAX_BUF_LEN);
+ }
+
+ /* We don't yet know how many fragments we will need to read since the
+ length is contained in the first frgment of the message itself. Set
+ totalfrag to an arbitry large number and we will readjust it after we
+ successfully recieve the first frag.
+ */
+ totalfrag = RWL_DEFAULT_WIFI_FRAG_COUNT;
+
+ for (num_frags = 0; num_frags <= totalfrag; num_frags++) {
+ if ((rec_frame = rwl_wifi_allocate_actionframe()) == NULL) {
+ DPRINT_DBG(OUTPUT, "malloc failure\n");
+ rwl_wifi_free_list(master_list);
+ return (FAIL);
+ }
+ if ((error = remote_CDC_DATA_wifi_rx((void*)wl, rec_frame)) < 0) {
+ free(rec_frame);
+ rwl_wifi_free_list(master_list);
+ return FAIL;
+ }
+
+ if (rec_frame->subtype >= RWL_DEFAULT_WIFI_FRAG_COUNT) {
+ DPRINT_DBG(OUTPUT, " Read bogus subtype %d\n", rec_frame->subtype);
+ free(rec_frame);
+ continue;
+ }
+ /* Keep only originals and discard any dup frags */
+ if (!master_list[rec_frame->subtype]) {
+ master_list[rec_frame->subtype] = rec_frame;
+ } else {
+ num_frags--;
+ free(rec_frame);
+ }
+
+ /* Look for first frag so we can accurately calculate totalfrag */
+ if (rec_frame->subtype == RWL_WIFI_DEFAULT_SUBTYPE) {
+ memcpy((char*)rem_ptr,
+ (char*)&master_list[rec_frame->subtype]->
+ data[RWL_WIFI_CDC_HEADER_OFFSET], REMOTE_SIZE);
+ rwl_swap_header(rem_ptr, NETWORK_TO_HOST);
+ totalfrag = rem_ptr->msg.len / RWL_WIFI_FRAG_DATA_SIZE;
+ remainingbytes = rem_ptr->msg.len % RWL_WIFI_FRAG_DATA_SIZE;
+ }
+ }
+
+ /* All frags are now read and there are no dups. Check for missing frags */
+ for (seq_num = 0; seq_num < totalfrag; seq_num++) {
+ if (!master_list[seq_num]) {
+ DPRINT_DBG(OUTPUT, "Missing frag number %d\n", seq_num);
+ rwl_wifi_free_list(master_list);
+ return (FAIL);
+ }
+ }
+ /*
+ case 1: response in one frame i.e if (totalfrag==0)
+ case 2: response in multiple frame ( multiple of RWL_WIFI_FRAG_DATA_SIZE)
+ case 3: response in multiple frame and not in multiple of RWL_WIFI_FRAG_DATA_SIZE
+ */
+
+ /* case 1: Check for the response in single frame */
+ if (totalfrag == 0)
+ memcpy((char*)&input_buf[0],
+ (char*)&master_list[0]->data[REMOTE_SIZE], rem_ptr->msg.len);
+ else /* case 2: Copy fragments into contiguous frame */
+ memcpy((char*)&input_buf[0],
+ (char*)&master_list[0]->data[REMOTE_SIZE], RWL_WIFI_FRAG_DATA_SIZE);
+
+ /*
+ * If all the frames are recieved , copy them to a contigues buffer
+ */
+ for (seq_num = 1; seq_num < totalfrag; seq_num++) {
+ memcpy((char*)&input_buf[seq_num*RWL_WIFI_FRAG_DATA_SIZE],
+ (char*)&master_list[seq_num]->data, RWL_WIFI_FRAG_DATA_SIZE);
+ }
+
+ /* case 3 : if response is in fragments and valid data in the last frame is less
+ * than RWL_WIFI_FRAG_DATA_SIZE
+ */
+ if (remainingbytes && (totalfrag > 0))
+ memcpy((char*)&input_buf[seq_num*RWL_WIFI_FRAG_DATA_SIZE],
+ (char*)&master_list[seq_num]->data, remainingbytes);
+
+ if (shell) {
+#ifdef LINUX
+ write(1, (char*)input_buf, strlen((char*)input_buf));
+#else
+ fputs((char*)input_buf, stdout);
+#endif /* LINUX */
+ }
+
+ rwl_wifi_free_list(master_list);
+ return error;
+}
+/*
+ * read out all the action frame which are queued in the driver even
+ * before issuing any wl cmd. This is essential because due to late arrival of frame it can
+ * get queued after the read expires.
+ */
+int
+rwl_wifi_purge_actionframes(void *wl)
+{
+ dot11_action_wifi_vendor_specific_t *rec_frame;
+ void *ptr = NULL;
+ int error = BCME_OK;
+
+ if ((rec_frame = (dot11_action_wifi_vendor_specific_t *)
+ malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) {
+ DPRINT_DBG(OUTPUT, "Purge Error in reading the frame \n");
+ return BCME_NOMEM;
+ }
+
+ for (;;) {
+ if ((error = rwl_var_getbuf(wl, RWL_WIFI_GET_ACTION_CMD, rec_frame,
+ RWL_WIFI_ACTION_FRAME_SIZE, &ptr)) < 0) {
+ DPRINT_DBG(OUTPUT, "rwl_wifi_purge_actionframes:"
+ "Purge Error in reading the frame \n");
+ break;
+ }
+ memcpy((char*)rec_frame, ptr, RWL_WIFI_ACTION_FRAME_SIZE);
+
+ if ((rec_frame->category != RWL_ACTION_WIFI_CATEGORY))
+ break;
+ }
+
+ free(rec_frame);
+
+ return error;
+}
+/*
+ * check for the channel of remote and respond if it matches with its current
+ * channel. Once the server gets the handshake cmd, it will check the channel
+ * number of the remote with its channel and if it matches , then it send out the
+ * ack to the remote client. This fucntion is used only by the server.
+ */
+void
+rwl_wifi_find_server_response(void *wl, dot11_action_wifi_vendor_specific_t *rec_frame)
+{
+ int error, send, server_channel;
+
+ if (rec_frame->type == RWL_WIFI_FIND_MY_PEER) {
+
+ rec_frame->type = RWL_WIFI_FOUND_PEER;
+ /* read channel on of the SERVER */
+ rwl_wifi_config_channel(wl, WLC_GET_CHANNEL, &server_channel);
+ /* overlapping channel not supported,
+ so server will only respond to client on the channel of the client
+ */
+ if (rec_frame->data[RWL_WIFI_CLIENT_CHANNEL_OFFSET] == server_channel) {
+ /* send the response by updating server channel in the frame */
+ rec_frame->data[RWL_WIFI_SERVER_CHANNEL_OFFSET] = server_channel;
+ /* change the TYPE feild for giving the ACK */
+ for (send = 0; send < RWL_WIFI_SEND; send++) {
+ if ((error = rwl_var_send_vs_actionframe(wl,
+ RWL_WIFI_ACTION_CMD,
+ rec_frame,
+ RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
+ DPRINT_ERR(ERR, "rwl_wifi_find_server_response: Failed"
+ "to Send the Frame %d\n", error);
+ break;
+ }
+ rwl_sleep(RWL_WIFI_SEND_DELAY);
+ }
+ }
+ }
+ return;
+}
+/*
+ * This function is used by client only. Sends the finmypeer sync frame to remote
+ * server on diffrent channels and waits for the response.
+ */
+int
+rwl_find_remote_wifi_server(void *wl, char *id)
+{
+ dot11_action_wifi_vendor_specific_t *rem_wifi_send, *rem_wifi_recv;
+ rem_ioctl_t *rem_ptr = &rem_cdc;
+ /* This list is generated considering valid channel and if this
+ * may requires updation or deletion. This needs to be identified.
+ * we have assumed that server band is not known and considered all band channels.
+ */
+ int wifichannel[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 36, 40, 44, 48, 149, 153, 157, 161, 165};
+ int i, error, schannel, channel_count;
+ struct ether_addr * curr_macaddr;
+ int ret;
+ need_speedy_response = TRUE;
+
+ if ((rem_wifi_send = rwl_wifi_allocate_actionframe()) == NULL) {
+ DPRINT_ERR(ERR, " rwl_find_remote_wifi_server : Failed to allocate \n");
+ return FAIL;
+ }
+ if ((rem_wifi_recv = rwl_wifi_allocate_actionframe()) == NULL) {
+ DPRINT_ERR(ERR, " rwl_find_remote_wifi_server : Failed to allocate\n");
+ free(rem_wifi_send);
+ return FAIL;
+ }
+
+ channel_count = sizeof(wifichannel) / sizeof(int);
+
+ /* make dummy read to make sure we don't read the already queued
+ * actionframes against the cmd we issue
+ */
+ if ((error = rwl_wifi_purge_actionframes(wl)) < 0) {
+ free(rem_wifi_send);
+ free(rem_wifi_recv);
+ return error;
+ }
+
+ /* update the client sync specifier */
+ rem_wifi_send->type = RWL_WIFI_FIND_MY_PEER;
+ /* update the CDC flag to indicate it is handshake frame */
+ rem_ptr->msg.cmd = 0;
+ /* cmd =0 ,this will be ignored when server receive frame
+ * with REMOTE_FINDSERVER_IOCTL flag
+ */
+ rem_ptr->msg.len = RWL_WIFI_FRAG_DATA_SIZE;
+ rem_ptr->msg.flags = REMOTE_FINDSERVER_IOCTL;
+ rem_ptr->data_len = RWL_WIFI_FRAG_DATA_SIZE;
+ rwl_swap_header(rem_ptr, HOST_TO_NETWORK);
+
+ memcpy((char*)&rem_wifi_send->data, (char*)rem_ptr, REMOTE_SIZE);
+ /* copy server mac to which ref driver needs to send unicast action frame */
+ memcpy((char*)&rem_wifi_send->data[RWL_REF_MAC_ADDRESS_OFFSET], &id[0], ETHER_ADDR_LEN);
+
+ if ((ret = rwl_var_getbuf(wl, "cur_etheraddr", NULL, 0, (void**) &curr_macaddr)) < 0) {
+ DPRINT_ERR(ERR, "Error getting current Mac addr \n");
+ return FAIL;
+ }
+
+ memcpy((char*)&rem_wifi_send->data[RWL_DUT_MAC_ADDRESS_OFFSET], (char*)curr_macaddr->octet,
+ ETHER_ADDR_LEN);
+ /* Start with the channel in the list and keep changing till the server
+ * responds or channels list ends
+ */
+ for (i = 0; i < channel_count; i++) {
+ DPRINT_INFO(OUTPUT, "Scanning Channel: %d ...\n", wifichannel[i]);
+ if ((error = rwl_wifi_config_channel(wl, WLC_SET_CHANNEL,
+ &wifichannel[i])) < 0) {
+ DPRINT_ERR(ERR, " Failed to set the specified channel %d\n",
+ wifichannel[i]);
+ break;
+ }
+ /* send channel detail of client to server */
+ rem_wifi_send->data[RWL_WIFI_CLIENT_CHANNEL_OFFSET] = wifichannel[i];
+
+ if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, rem_wifi_send,
+ RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
+ DPRINT_DBG(OUTPUT, "Failed to Send the Frame %d\n", error);
+ break;
+ }
+ /* read the server response on the same channel */
+ if ((error = remote_CDC_DATA_wifi_rx(wl, rem_wifi_recv)) < 0) {
+ rwl_sleep(RWL_CHANNEL_SCAN_WAIT);
+ continue;
+ }
+ /* Verify for the Type RWL_WIFI_FOUND_PEER */
+ if (rem_wifi_recv->type == RWL_WIFI_FOUND_PEER) {
+ if (rem_wifi_recv->data[RWL_WIFI_SERVER_CHANNEL_OFFSET] ==
+ rem_wifi_recv->data[RWL_WIFI_CLIENT_CHANNEL_OFFSET]) {
+
+ DPRINT_INFO(OUTPUT, "Server is on channel # %d\n",
+ rem_wifi_recv->data[RWL_WIFI_SERVER_CHANNEL_OFFSET]);
+
+ schannel = rem_wifi_recv->data[RWL_WIFI_SERVER_CHANNEL_OFFSET];
+ /* Set the back to the channel on which REF was originally */
+ if ((error = rwl_wifi_config_channel(wl,
+ WLC_SET_CHANNEL, &schannel) < 0)) {
+ DPRINT_ERR(ERR, "Failed to set the specified"
+ "channel %d\n", schannel);
+ } else {
+ DPRINT_ERR(ERR, "REF now moved to the"
+ "channel of server # %d\n", schannel);
+ }
+ need_speedy_response = FALSE;
+ /* we are done here, end the loop */
+ break;
+ } else {
+ DPRINT_INFO(OUTPUT, "Server is operating on diffrent channel."
+ "continue scanning\n");
+ }
+ }
+ /* before chaning the channel of client and sending sync frame
+ * wait for while and send
+ */
+ rwl_sleep(RWL_CHANNEL_SCAN_WAIT);
+ }
+ need_speedy_response = FALSE;
+
+ free(rem_wifi_send);
+ free(rem_wifi_recv);
+ return error;
+}
+#endif /* RWL_WIFI */
+#ifdef RWL_DONGLE
+static int
+remote_CDC_tx_dongle(void *wl, rem_ioctl_t *rem_ptr, uchar *buf)
+{
+ unsigned long numwritten;
+ char end_of_packet[END_OF_PACK_SEP_LEN] = "\n\n";
+ uchar loc_buf[UART_FIFO_LEN];
+ uint len = END_OF_PACK_SEP_LEN;
+ uint noframes, frame_count, rem_bytes;
+ uint n_bytes;
+ uint data_len;
+
+ /* Converting the CDC header with keyword 'rwl ' in ascii format
+ * as dongle UART understands only ascii format.
+ * In dongle UART driver CDC structure is made from the ascii data
+ * it received.
+ */
+ sprintf((char*)loc_buf, "rwl %d %d %d %d ", rem_ptr->msg.cmd, rem_ptr->msg.len,
+ rem_ptr->msg.flags, rem_ptr->data_len);
+ n_bytes = (uint)strlen((char*)loc_buf);
+
+ data_len = ltoh32(rem_ptr->data_len);
+ DPRINT_DBG(OUTPUT, "rwl %x %d %d %d ", ltoh32(rem_ptr->msg.cmd), ltoh32(rem_ptr->msg.len),
+ ltoh32(rem_ptr->msg.flags), data_len);
+ DPRINT_DBG(OUTPUT, "CDC Header:No of bytes to be sent=%d\n", n_bytes);
+ DPRINT_DBG(OUTPUT, "Data:No of bytes to be sent=%d\n", data_len);
+
+ /* Send the CDC Header */
+ if (rwl_write_serial_port(wl, (char*)loc_buf, n_bytes, &numwritten) < 0) {
+ DPRINT_ERR(ERR, "CDC_Tx: Header: Write failed\n");
+ DPRINT_ERR(ERR, "CDC_Tx: Header: numwritten %ld != n_bytes %d\n",
+ numwritten, n_bytes);
+ return (FAIL);
+ }
+
+ /* Dongle UART FIFO len is 64 bytes and flow control is absent.
+ * While transmitting large chunk of data the data was getting lost
+ * at UART driver so for large chunk of data 64 bytes are sent at a time
+ * folowed by delay and then next set of 64 bytes and so on.
+ * For data which is less than 64 bytes it is sent in one shot
+ */
+
+ noframes = rem_ptr->data_len/UART_FIFO_LEN;
+ if (noframes == 0) {
+ /* Send the data now */
+ if (rwl_write_serial_port(wl, (char*)buf, rem_ptr->data_len, &numwritten) < 0) {
+ DPRINT_ERR(ERR, "Data_Tx: Header: Write failed\n");
+ DPRINT_ERR(ERR, "Data_Tx: Header: numwritten %ld != len %d\n",
+ numwritten, rem_ptr->data_len);
+ return (FAIL);
+ }
+
+ } else {
+ if (rem_ptr->data_len % UART_FIFO_LEN == 0) {
+ rem_bytes = UART_FIFO_LEN;
+ } else {
+ rem_bytes = rem_ptr->data_len % UART_FIFO_LEN;
+ noframes += 1;
+ }
+
+ for (frame_count = 0; frame_count < noframes; frame_count++) {
+ if (frame_count != noframes-1) {
+ memcpy(loc_buf, (char*)(&buf[frame_count*UART_FIFO_LEN]),
+ UART_FIFO_LEN);
+ /* Send the data now */
+ if (rwl_write_serial_port(wl, (char*)loc_buf, UART_FIFO_LEN,
+ &numwritten) == -1) {
+ DPRINT_ERR(ERR, "Data_Tx: Header: Write failed\n");
+ return (-1);
+ }
+
+ } else {
+ memcpy(loc_buf, (char*)(&buf[frame_count*UART_FIFO_LEN]),
+ rem_bytes);
+
+ if (rwl_write_serial_port(wl, (char*)loc_buf, rem_bytes,
+ &numwritten) == -1) {
+ DPRINT_ERR(ERR, "Data_Tx: Header: Write failed\n");
+ return (-1);
+ }
+
+ }
+ rwl_sleep(SYNC_TIME);
+ }
+ }
+
+ /* Send end of packet now */
+ if (rwl_write_serial_port(wl, end_of_packet, len, &numwritten) == -1) {
+ DPRINT_ERR(ERR, "CDC_Tx: Header: Write failed\n");
+ DPRINT_ERR(ERR, "CDC_Tx: Header: numwritten %ld != len %d\n",
+ numwritten, len);
+ return (FAIL);
+ }
+
+ DPRINT_DBG(OUTPUT, "Packet sent!\n");
+
+ /* Return size of actual buffer to satisfy accounting going on above this level */
+ return (ltoh32(rem_ptr->msg.len));
+}
+#endif /* RWL_DONGLE */
+
+#if defined(RWL_SERIAL) || defined(RWL_DONGLE)|| defined(RWL_SOCKET)
+void *
+rwl_open_pipe(int remote_type, char *port, int ReadTotalTimeout, int debug)
+{
+ return rwl_open_transport(remote_type, port, ReadTotalTimeout, debug);
+}
+
+int
+rwl_close_pipe(int remote_type, void* handle)
+{
+ return rwl_close_transport(remote_type, handle);
+}
+#endif
+
+int
+remote_CDC_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags, int debug)
+{
+#ifdef RWL_SERIAL
+ unsigned long numwritten = 0;
+#endif
+ rem_ioctl_t *rem_ptr = &rem_cdc;
+#ifdef RWL_WIFI
+ int error;
+ uint totalframes, tx_count;
+ dot11_action_wifi_vendor_specific_t *rem_wifi_send;
+#endif
+ UNUSED_PARAMETER(debug);
+ UNUSED_PARAMETER(buf);
+ UNUSED_PARAMETER(wl);
+
+ memset(rem_ptr, 0, sizeof(rem_ioctl_t));
+ rem_ptr->msg.cmd = cmd;
+ rem_ptr->msg.len = buf_len;
+ rem_ptr->msg.flags = flags;
+ rem_ptr->data_len = data_len;
+
+ if (strlen(g_rem_ifname) != 0) {
+ strncpy(rem_ptr->intf_name, g_rem_ifname, (int)IFNAMSIZ - 1);
+ rem_ptr->intf_name[IFNAMSIZ - 1] = '\0';
+ }
+ rwl_swap_header(rem_ptr, HOST_TO_NETWORK);
+
+ if (data_len > buf_len) {
+ DPRINT_ERR(ERR, "remote_CDC_tx: data_len (%d) > buf_len (%d)\n", data_len, buf_len);
+ return (FAIL);
+ }
+#ifdef RWL_SERIAL
+ if (remote_type == REMOTE_SERIAL) {
+ int ret;
+ /* Send CDC header first */
+ if ((ret = rwl_write_serial_port(wl, (char *)rem_ptr,
+ REMOTE_SIZE, &numwritten)) == -1) {
+ DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n");
+ return (FAIL);
+ }
+ numwritten = ret;
+
+ /* Send data second */
+ if ((ret = rwl_write_serial_port(wl, (char*)buf,
+ data_len, &numwritten)) == -1) {
+ DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n");
+ return (FAIL);
+ }
+ numwritten = ret;
+
+ return (buf_len);
+ }
+#endif /* RWL_SERIAL */
+#ifdef RWL_DONGLE
+ if (remote_type == REMOTE_DONGLE) {
+ return (remote_CDC_tx_dongle(wl, rem_ptr, buf));
+ }
+#endif /* RWL_DONGLE */
+#ifdef RWL_SOCKET
+ if (remote_type == REMOTE_SOCKET) {
+ int ret;
+
+ /* Send CDC header first */
+ if ((ret = rwl_send_to_streamsocket(*(int*)wl, (char *)rem_ptr,
+ REMOTE_SIZE, 0)) == -1) {
+ DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n");
+ return (FAIL);
+ }
+
+ /* Send data second */
+ if ((ret = rwl_send_to_streamsocket(*(int*)wl, (const char*)buf,
+ data_len, 0)) == -1) {
+ DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n");
+ return (FAIL);
+ }
+
+ return (buf_len);
+ }
+#endif /* RWL_SOCKET */
+
+#ifdef RWL_WIFI
+ /*
+ * wifi action frame is formed based on the CDC header and data.
+ * If the data is bigger than RWL_WIFI_FRAG_DATA_SIZE size, number of fragments are
+ * calculated and sent
+ * similar number of action frames with subtype incremented with sequence.
+ * Frames are sent with delay to avoid the outof order at receving end
+ */
+ if (remote_type == REMOTE_WIFI) {
+ if ((rem_wifi_send = rwl_wifi_allocate_actionframe()) == NULL) {
+ DPRINT_ERR(ERR, "remote_CDC_tx: Failed to get allocated buffer\n");
+ return (FAIL);
+ }
+
+ if (buf_len > RWL_WIFI_FRAG_DATA_SIZE) {
+ /* response needs to be sent in fragments */
+ totalframes = buf_len / RWL_WIFI_FRAG_DATA_SIZE;
+ memcpy((char*)&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET],
+ (char*)rem_ptr, REMOTE_SIZE);
+ memcpy((char*)&rem_wifi_send->data[REMOTE_SIZE], &buf[0],
+ RWL_WIFI_FRAG_DATA_SIZE);
+ /* update type feild to inform receiver it's frammeted response frame
+ */
+ rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE;
+ rem_wifi_send->subtype = RWL_WIFI_DEFAULT_SUBTYPE;
+
+ if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD,
+ rem_wifi_send, RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
+ DPRINT_DBG(OUTPUT, "Failed to Send the Frame %d\n", error);
+ free(rem_wifi_send);
+ return error;
+ }
+ /* Send remaining bytes in fragments */
+ for (tx_count = 1; tx_count < totalframes; tx_count++) {
+ rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE;
+ rem_wifi_send->subtype = tx_count;
+ /* First frame onwards , buf contains only data */
+ memcpy((char*)&rem_wifi_send->data,
+ &buf[tx_count*RWL_WIFI_FRAG_DATA_SIZE], RWL_WIFI_FRAG_DATA_SIZE);
+ if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD,
+ rem_wifi_send, RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
+ free(rem_wifi_send);
+ return error;
+ }
+ rwl_sleep(RWL_WIFI_SEND_DELAY);
+ }
+
+ /* Check for remaing bytes to send */
+ if ((totalframes*RWL_WIFI_FRAG_DATA_SIZE) != buf_len) {
+ rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE;
+ rem_wifi_send->subtype = tx_count;
+ memcpy((char*)&rem_wifi_send->data,
+ &buf[tx_count*RWL_WIFI_FRAG_DATA_SIZE],
+ (buf_len - (tx_count*RWL_WIFI_FRAG_DATA_SIZE)));
+ if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD,
+ rem_wifi_send, RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
+ free(rem_wifi_send);
+ return error;
+ }
+ }
+ } else {
+ /* response fits to single frame */
+ memcpy((char*)&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET],
+ (char*)rem_ptr, REMOTE_SIZE);
+ /* when data_len is 0 , buf will be NULL */
+ if (buf != NULL) {
+ memcpy((char*)&rem_wifi_send->data[REMOTE_SIZE],
+ &buf[0], data_len);
+ }
+ error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, rem_wifi_send,
+ RWL_WIFI_ACTION_FRAME_SIZE);
+ free(rem_wifi_send);
+ return error;
+ }
+ }
+#endif /* RWL_WIFI */
+ return (0);
+}
+
+
+rem_ioctl_t *
+remote_CDC_rx_hdr(void *remote, int debug)
+{
+#ifdef RWL_SOCKET
+ int ret;
+#endif /* RWL_SOCKET */
+
+#if defined(RWL_SERIAL) || defined(RWL_DONGLE) || defined(RWL_SOCKET)
+ uint numread = 0;
+#endif
+ rem_ioctl_t *rem_ptr = &rem_cdc;
+ memset(rem_ptr, 0, sizeof(rem_ioctl_t));
+
+ UNUSED_PARAMETER(remote);
+ UNUSED_PARAMETER(debug);
+
+ switch (remote_type) {
+#if defined(RWL_SERIAL) || defined(RWL_DONGLE)
+ case REMOTE_SERIAL:
+ case REMOTE_DONGLE:
+ if (rwl_read_serial_port(remote, (char *)rem_ptr, sizeof(rem_ioctl_t),
+ &numread) < 0) {
+ DPRINT_ERR(ERR, "remote_CDC_rx_hdr: Header Read failed \n");
+ return (NULL);
+ }
+ break;
+#endif /* RWL_SERIAL | RWL_DONGLE */
+
+
+#ifdef RWL_SOCKET
+ case REMOTE_SOCKET:
+ ret = rwl_receive_from_streamsocket(*(int*)remote, (char *)rem_ptr,
+ sizeof(rem_ioctl_t), 0);
+ numread = ret;
+ if (ret == -1) {
+ DPRINT_ERR(ERR, "remote_CDC_rx_hdr: numread:%d\n", numread);
+ return (NULL);
+ }
+ if (numread == 0) {
+ DPRINT_DBG(OUTPUT, "\n remote_CDC_rx_hdr:No data to receive\n");
+ return NULL;
+ }
+ break;
+#endif
+ default:
+ DPRINT_ERR(ERR, "\n Unknown Transport Type\n");
+ break;
+ }
+
+ return (rem_ptr);
+}
+
+/* Return a CDC type buffer */
+int
+remote_CDC_rx(void *wl, rem_ioctl_t *rem_ptr, uchar *readbuf, uint buflen, int debug)
+{
+ uint numread = 0;
+
+#ifdef RWL_SOCKET
+ int ret;
+#endif
+
+#ifdef RWL_WIFI
+ UNUSED_PARAMETER(numread);
+#endif /* RWL_WIFI */
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(readbuf);
+ UNUSED_PARAMETER(buflen);
+ UNUSED_PARAMETER(debug);
+ UNUSED_PARAMETER(numread);
+
+ if (rem_ptr->data_len > rem_ptr->msg.len) {
+ DPRINT_ERR(ERR, "remote_CDC_rx: remote data len (%d) > msg len (%d)\n",
+ rem_ptr->data_len, rem_ptr->msg.len);
+ return (FAIL);
+ }
+
+
+#if defined(RWL_DONGLE) || defined(RWL_SERIAL)
+ if ((remote_type == REMOTE_DONGLE) || (remote_type == REMOTE_SERIAL)) {
+ if (rwl_read_serial_port(wl, (char*)readbuf, rem_ptr->data_len,
+ &numread) < 0) {
+ DPRINT_ERR(ERR, "remote_CDC_rx_hdr: Data Receivefailed \n");
+ return (FAIL);
+ }
+ }
+#endif /* RWL_DONGLE || RWL_SERIAL */
+
+#ifdef RWL_SOCKET
+ if (remote_type == REMOTE_SOCKET) {
+ if (((ret = rwl_receive_from_streamsocket(*(int*)wl, (char*)readbuf,
+ rem_ptr->data_len, 0)) == -1)) {
+ DPRINT_ERR(ERR, "remote_CDC_rx:Data Receive failed\n");
+ return (FAIL);
+ }
+ }
+#endif /* RWL_SOCKET */
+ return (SUCCESS);
+}
+#ifdef RWL_SOCKET
+int
+rwl_sockconnect(int SockDes, struct sockaddr *servAddr, int size)
+{
+ DPRINT_DBG(OUTPUT, "sockconnet SockDes=%d\n", SockDes);
+ if (rwl_connectsocket(SockDes, servAddr, size) < 0) {
+ DPRINT_ERR(ERR, "\n Server is not running\n");
+ return FAIL;
+ }
+ return SUCCESS;
+}
+#endif /* RWL_SOCKET */
+void
+rwl_swap_header(rem_ioctl_t *rem_ptr, bool host_to_network)
+{
+ rem_ptr->msg.cmd = host_to_network?(htol32(rem_ptr->msg.cmd)):(ltoh32(rem_ptr->msg.cmd));
+ rem_ptr->msg.len = host_to_network?(htol32(rem_ptr->msg.len)):(ltoh32(rem_ptr->msg.len));
+ rem_ptr->msg.flags = host_to_network?(htol32(rem_ptr->msg.flags)):
+ (ltoh32(rem_ptr->msg.flags));
+ rem_ptr->msg.status = host_to_network?(htol32(rem_ptr->msg.status)):
+ (ltoh32(rem_ptr->msg.status));
+ rem_ptr->data_len = host_to_network?(htol32(rem_ptr->data_len)):(ltoh32(rem_ptr->data_len));
+}
diff --git a/wl/src/wl/exe/wlu_pipe.h b/wl/src/wl/exe/wlu_pipe.h
new file mode 100644
index 0000000..a99df56
--- /dev/null
+++ b/wl/src/wl/exe/wlu_pipe.h
@@ -0,0 +1,51 @@
+/*
+ * OS independent declarations
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_pipe.h 532220 2015-02-05 10:00:56Z $
+ */
+#ifndef _wlu_pipe_h
+#define _wlu_pipe_h
+
+/* Function prototypes defined in wlu_pipe.c */
+
+/* Macros to access globals */
+extern char *g_rwl_device_name_serial;
+#define rwl_get_serial_port_name() (g_rwl_device_name_serial)
+#define rwl_set_serial_port_name(name) (g_rwl_device_name_serial = name)
+extern char *g_rwl_buf_mac;
+#define rwl_get_wifi_mac() (g_rwl_buf_mac)
+
+extern int remote_CDC_tx(void *wl, uint cmd, uchar *buf, uint buf_len,
+uint data_len, uint flags, int debug);
+extern rem_ioctl_t *remote_CDC_rx_hdr(void *remote, int debug);
+extern int remote_CDC_rx(void *wl, rem_ioctl_t *rem_ptr, uchar *readbuf, uint buflen, int debug);
+
+extern void* rwl_open_pipe(int remote_type, char *port, int ReadTotalTimeout, int debug);
+extern int rwl_close_pipe(int remote_type, void* hndle);
+
+#ifdef RWL_SOCKET
+extern int rwl_sockconnect(int SockDes, struct sockaddr *servAddr, int size);
+#endif /* RWL_SOCKET */
+
+extern int remote_CDC_DATA_wifi_rx_frag(void *wl, rem_ioctl_t *rem_ptr, uint input_len,
+void *input, bool shell);
+extern int remote_CDC_DATA_wifi_rx(void *wl, struct dot11_action_wifi_vendor_specific *rec_frame);
+extern int
+remote_CDC_wifi_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags);
+extern void rwl_wifi_server_response(void *wl, struct dot11_action_wifi_vendor_specific *rec_frame);
+extern int rwl_find_remote_wifi_server(void *wl, char *id);
+extern int rwl_wifi_purge_actionframes(void *wl);
+extern void rwl_wifi_swap_remote_type(int flag);
+extern void remote_wifi_ser_init_cmds(void *wl);
+#endif /* _wlu_pipe_h */
diff --git a/wl/src/wl/exe/wlu_pipe_linux.c b/wl/src/wl/exe/wlu_pipe_linux.c
new file mode 100644
index 0000000..bd7dec1
--- /dev/null
+++ b/wl/src/wl/exe/wlu_pipe_linux.c
@@ -0,0 +1,645 @@
+/*
+ * linux version of remote Wl transport mechanisms (pipes).
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_pipe_linux.c 625881 2016-03-18 02:58:34Z $
+ */
+
+/* Revision History: Linux version of remote Wl transport mechanisms (pipes).
+ *
+ * Date Author Description
+ *
+ * 27-Dec-2007 Suganthi Version 0.0
+ *
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <proto/802.11.h>
+#include <bcmendian.h>
+#include <bcmcdc.h>
+#include <proto/802.11.h>
+#include <wlioctl.h>
+#include <typedefs.h>
+#include "wlu_remote.h"
+#include <miniopt.h>
+#if defined(RWL_DONGLE) || defined(RWL_SERIAL)
+#define READ_DELAY 500000
+#define BAUD_RATE_115200 115200
+#define VMIN_VAL 16
+#define VTIME_VAL 50
+#define LINUX_SYNC_DELAY 200
+extern char *g_rwl_device_name_serial;
+extern int g_rwl_device_baud;
+#endif
+
+#define MICRO_SEC_CONVERTER_VAL 1000
+int g_irh;
+int g_shellsync_pid;
+
+#ifdef RWL_SOCKET
+#define MAX_INTERFACE_NAME 32
+static int
+rwl_opensocket(int AddrFamily, int Type, int Protocol)
+{
+ int SockDes;
+
+ if ((SockDes = socket(AddrFamily, Type, Protocol)) == -1) {
+ perror("rwl_opensocket Fails:");
+ DPRINT_ERR(ERR, "\nerrno:%d\n", errno);
+ return FAIL;
+ }
+ return SockDes;
+}
+
+static int
+rwl_set_socket_option(int SocketDes, int Level, int OptName, int Val)
+{
+ if (setsockopt(SocketDes, Level, OptName, &Val, sizeof(int)) == -1) {
+ perror("Error at SetTCPSocketOpt()");
+ DPRINT_ERR(ERR, "\n errno:%d\n", errno);
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+/* Function to connect with the server waiting in the same port */
+int
+rwl_connectsocket(int SocketDes, struct sockaddr* SerAddr, int SizeOfAddr)
+{
+ if (connect(SocketDes, SerAddr, SizeOfAddr) == -1) {
+ perror("Failed to connect() to server");
+ DPRINT_ERR(ERR, "\n errno:%d\n", errno);
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+/*
+ * Function for associating a local address with a socket.
+ */
+int
+rwl_bindsocket(int SocketDes, struct sockaddr * MyAddr, int SizeOfAddr)
+{
+ if (bind(SocketDes, MyAddr, SizeOfAddr) == -1) {
+ perror("Error at rwl_bindSocket()");
+ DPRINT_ERR(ERR, "\n errno:%d\n", errno);
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+/*
+ * Function for making the socket to listen for incoming connection.
+ */
+int
+rwl_listensocket(int SocketDes, int BackLog)
+{
+ if (listen(SocketDes, BackLog) == -1) {
+ perror("Error at rwl_listensocket()");
+ DPRINT_ERR(ERR, "\n errno:%d\n", errno);
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+/*
+ * Function for permitting an incoming connection attempt on a socket
+ * Function called by server
+ */
+int
+rwl_acceptconnection(int SocketDes, struct sockaddr* ClientAddr, int *SizeOfAddr)
+{
+ int NewSockDes;
+
+ if ((NewSockDes = accept(SocketDes, ClientAddr, (socklen_t*)SizeOfAddr)) == -1) {
+ perror("Error at rwl_acceptConnection()");
+ DPRINT_ERR(ERR, "\n errno:%d\n", errno);
+ return FAIL;
+ }
+ return NewSockDes;
+}
+
+static int
+rwl_closesocket(int SocketDes)
+{
+ if (close(SocketDes) == -1) {
+ perror("Error at rwl_closeSocket()");
+ DPRINT_ERR(ERR, "\n errno:%d\n", errno);
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+/* Transmit the response in the opened TCP stream socket */
+int
+rwl_send_to_streamsocket(int SocketDes, const char* SendBuff, int data_size, int Flag)
+{
+ int total_numwritten = 0, numwritten = 0;
+ while (total_numwritten < data_size) {
+ if ((numwritten = send(SocketDes, SendBuff,
+ data_size - total_numwritten, Flag)) == -1) {
+ perror("Failed to send()");
+ DPRINT_ERR(ERR, "\n errno:%d\n", errno);
+ return (FAIL);
+ }
+
+ /* Sent successfully at first attempt no more retries */
+ if (numwritten == data_size) {
+ total_numwritten = numwritten;
+ break;
+ }
+
+ /* If socket is busy we may hit this condition */
+ if (numwritten != data_size - total_numwritten) {
+ DPRINT_DBG(OUTPUT, "wanted to send %d bytes sent only %d bytes\n",
+ data_size - total_numwritten, numwritten);
+ }
+
+ /* Now send the remaining buffer */
+ total_numwritten += numwritten;
+ SendBuff += numwritten;
+ }
+
+ return total_numwritten;
+}
+
+/* Receive the response from the opened TCP stream socket */
+int
+rwl_receive_from_streamsocket(int SocketDes, char* RecvBuff, int data_size, int Flag)
+{
+ int numread = 0;
+ int total_numread = 0;
+
+ while (total_numread < data_size) {
+ if ((numread = recv(SocketDes, RecvBuff, data_size - total_numread, Flag)) == -1) {
+ perror("Failed to Receive()");
+ DPRINT_ERR(ERR, "\n errno:%d\n", errno);
+ return FAIL;
+ }
+
+ if (numread != data_size - total_numread) {
+ DPRINT_DBG(OUTPUT, "asked %d bytes got %d bytes\n",
+ data_size - total_numread, numread);
+ }
+
+ if (numread == 0)
+ break;
+
+ total_numread += numread;
+ RecvBuff += numread;
+ }
+
+ return numread;
+}
+
+
+int
+rwl_init_server_socket_setup(int argc, char** argv, uint remote_type)
+{
+ char netif[MAX_INTERFACE_NAME];
+ unsigned short servPort;
+ struct sockaddr_in ServerAddress;
+ int err, SockDes, val;
+
+ /* Default option */
+ servPort = DEFAULT_SERVER_PORT;
+
+ strcpy(netif, "eth0");
+
+ /* User option can override default arguments */
+ if (argc == 3) {
+ argv++;
+
+ if (isalpha(**argv) == FALSE) {
+ DPRINT_ERR(ERR, "USAGE ERROR:Incorrect network interface\n");
+ return FAIL;
+ }
+ strcpy(netif, *argv);
+ argv++;
+
+ if (isdigit(**argv) == FALSE) {
+ DPRINT_ERR(ERR, "USAGE ERROR:Incorrect port\n");
+ return FAIL;
+ }
+ servPort = atoi(*argv);
+ }
+
+ if (argc == 2) {
+ argv++;
+
+ if (isalpha(**argv) == FALSE) {
+ if (isdigit(**argv) == FALSE) {
+ DPRINT_ERR(ERR, "USAGE ERROR\n");
+ return FAIL;
+ }
+ else
+ servPort = atoi(*argv);
+ }
+ else
+ strcpy(netif, *argv);
+ }
+
+ DPRINT_INFO(OUTPUT, "INFO: Network Interface:%s, Port:%d\n",
+ netif, servPort);
+
+ if ((SockDes = (*(int *)rwl_open_transport(remote_type, NULL, 0, 0))) == FAIL)
+ return FAIL;
+
+ val = 1;
+ if ((rwl_set_socket_option(SockDes, SOL_SOCKET, SO_REUSEADDR, val)) == FAIL)
+ return FAIL;
+
+ memset(&ServerAddress, 0, sizeof(ServerAddress));
+
+ rwl_GetifAddr(netif, &ServerAddress);
+ ServerAddress.sin_family = AF_INET; /* host byte order */
+ ServerAddress.sin_port = hton16(servPort); /* short, network byte order */
+
+ if (((err = rwl_bindsocket(SockDes, (struct sockaddr *)&ServerAddress,
+ sizeof(ServerAddress))) == FAIL))
+ return err;
+ if ((err = rwl_listensocket(SockDes, BACKLOG)) == FAIL)
+ return err;
+
+ DPRINT_DBG(OUTPUT, "Waiting for client to connect...\n");
+
+ return SockDes;
+}
+
+int rwl_GetifAddr(char *ifname, struct sockaddr_in *sa)
+{
+ struct ifreq ifr;
+ int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ if (fd < 0)
+ {
+ DPRINT_ERR(ERR, "socket open error\n");
+ return FAIL;
+ }
+
+ strcpy(ifr.ifr_name, ifname);
+ ifr.ifr_addr.sa_family = AF_INET;
+ if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
+ {
+ memcpy(sa, (struct sockaddr_in *)&ifr.ifr_addr, sizeof(struct sockaddr_in));
+ close(fd);
+ return SUCCESS;
+ }
+ close(fd);
+ return FAIL;
+}
+#endif /* RWL_SOCKET */
+
+#if defined(RWL_SERIAL) || defined(RWL_DONGLE)
+static speed_t
+rwl_termios_b(int baud)
+{
+ speed_t result;
+ switch (baud) {
+ case 50: result = B50; break;
+ case 75: result = B75; break;
+ case 110: result = B110; break;
+ case 134: result = B134; break;
+ case 150: result = B150; break;
+ case 200: result = B200; break;
+ case 300: result = B300; break;
+ case 600: result = B600; break;
+ case 1200: result = B1200; break;
+ case 1800: result = B1800; break;
+ case 2400: result = B2400; break;
+ case 4800: result = B4800; break;
+ case 9600: result = B9600; break;
+ case 19200: result = B19200; break;
+ case 38400: result = B38400; break;
+ case 57600: result = B57600; break;
+ case 115200: result = B115200; break;
+ case 230400: result = B230400; break;
+ default: result = B115200; break;
+ }
+ return result;
+}
+static int
+rwl_open_serial(int remote_type, char *port, int baud)
+{
+ struct termios tio;
+ int fCom;
+ long BAUD, DATABITS, STOPBITS, PARITYON;
+ speed_t baud_rate;
+
+ DPRINT_DBG(OUTPUT, "\n rwl_open_serial:%s\n", port);
+ if (remote_type == REMOTE_DONGLE)
+ fCom = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
+ else
+ fCom = open(port, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC);
+ if (fCom < 0) {
+ DPRINT_ERR(ERR, "open COM failed with error %d.\n", errno);
+ return fCom;
+ } else {
+ /* To make the read as a blocking operation */
+ fcntl(fCom, F_SETFL, 0);
+ }
+
+ bzero(&tio, sizeof(tio));
+ /* Get the current option for the port... */
+ tcgetattr(fCom, &tio);
+ /* Set the baud rate */
+ cfsetispeed(&tio, rwl_termios_b(baud));
+ cfsetospeed(&tio, rwl_termios_b(baud));
+ if (remote_type == REMOTE_DONGLE) {
+ if (tcsetattr(fCom, TCSANOW, &tio) < 0) {
+ perror("tcsetattr:setspeed");
+ return FAIL;
+ }
+
+ baud_rate = cfgetospeed(&tio);
+ DPRINT_DBG(OUTPUT, "Baud_rate set is:%d\n", baud_rate);
+
+ BAUD = baud_rate;
+ DATABITS = CS8;
+ STOPBITS = 1;
+ PARITYON = 0;
+
+ tio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | CLOCAL | CREAD;
+ tio.c_iflag = IGNPAR;
+ tio.c_oflag = 0;
+ tio.c_lflag = 0;
+ tio.c_cc[VMIN] = VMIN_VAL;
+ tio.c_cc[VTIME] = VTIME_VAL;
+
+ tcflush(fCom, TCIOFLUSH);
+ if (tcsetattr(fCom, TCSANOW, &tio) < 0) {
+ perror("tcsetattr:");
+ return FAIL;
+ }
+
+ if (tcgetattr(fCom, &tio) < 0) {
+ perror("tcgetattr:");
+ return FAIL;
+ }
+
+ DPRINT_DBG(OUTPUT, "tcgetattr:VMIN is:%d\n", tio.c_cc[VMIN]);
+ DPRINT_DBG(OUTPUT, "tcgetattr:VTIME is:%d\n", tio.c_cc[VTIME]);
+ tcflush(fCom, TCIOFLUSH);
+ }
+ else {
+ UNUSED_PARAMETER(PARITYON);
+ UNUSED_PARAMETER(STOPBITS);
+ UNUSED_PARAMETER(DATABITS);
+ UNUSED_PARAMETER(BAUD);
+ UNUSED_PARAMETER(baud_rate);
+
+ /* Enable the receiver and set local mode */
+ tio.c_cflag |= (CLOCAL | CREAD);
+
+ tio.c_cflag &= ~PARENB;
+ tio.c_cflag &= ~CSTOPB;
+ tio.c_cflag &= ~CSIZE;
+ tio.c_cflag |= CS8;
+ tio.c_cc[VTIME] = 255;
+ tio.c_cc[VMIN] = 1;
+
+ tio.c_iflag = 0;
+ tio.c_iflag |= IGNBRK;
+
+ tio.c_oflag &= ~OPOST;
+#ifndef __FreeBSD__
+ tio.c_oflag &= ~OLCUC;
+#endif
+ tio.c_oflag &= ~ONLCR;
+ tio.c_oflag &= ~OCRNL;
+ tio.c_oflag &= ~ONOCR;
+ tio.c_oflag &= ~ONLRET;
+#ifndef __FreeBSD__
+ tio.c_oflag &= ~OFILL;
+#endif
+
+ tio.c_lflag &= ~ICANON;
+ tio.c_lflag &= ~ISIG;
+#ifndef __FreeBSD__
+ tio.c_lflag &= ~XCASE;
+#endif
+ tio.c_lflag &= ~ECHO;
+ tio.c_lflag &= ~FLUSHO;
+ tio.c_lflag &= ~IEXTEN;
+ tio.c_lflag |= NOFLSH;
+ /* Set the new tio for the port... */
+ tcsetattr(fCom, TCSANOW, &tio);
+ tcflush(fCom, TCIOFLUSH);
+ }
+ return (fCom);
+}
+
+int
+rwl_write_serial_port(void* hndle, char* write_buf, unsigned long size, unsigned long *numwritten)
+{
+ int ret;
+
+ ret = write((*(int *)hndle), (const void*)write_buf, size);
+ *numwritten = ret;
+ if (ret == -1) {
+ perror("WriteToPort Failed");
+ DPRINT_ERR(ERR, "Errno:%d\n", errno);
+ return FAIL;
+ }
+ if (*numwritten != size) {
+ DPRINT_ERR(ERR, "rwl_write_serial_port failed numwritten %ld != len %ld\n",
+ *numwritten, size);
+ return FAIL;
+ }
+ return SUCCESS;
+}
+
+static int
+rwl_check_inqueue(void *hndle, int timeout_ms, int *bufferlen)
+{
+ int inbuflen = 0;
+ int stat;
+ int delay_ms = 10;
+ int n;
+ int div = timeout_ms / delay_ms;
+ if (bufferlen)
+ *bufferlen = 0;
+ for (n = 0; n < div; n++)
+ {
+ stat = ioctl(*(int *)hndle, FIONREAD, &inbuflen);
+ if (stat == 0 && 0 < inbuflen)
+ {
+ if (bufferlen)
+ *bufferlen = inbuflen;
+ return 0;
+ }
+ usleep(delay_ms * 1000);
+ }
+
+ return -1;
+}
+
+int
+rwl_read_serial_port(void* hndle, char* read_buf, uint data_size, uint *numread)
+{
+ int ret;
+ uint total_numread = 0;
+ int count = 0;
+ int inqueuelen;
+ int readlen;
+ while (total_numread < data_size) {
+ if (rwl_check_inqueue (hndle, 10000, &inqueuelen) != 0)
+ {
+ DPRINT_ERR(ERR, "input buffer is empty\n");
+ return FAIL;
+ }
+ readlen = data_size - total_numread;
+ if (inqueuelen < readlen)
+ readlen = inqueuelen;
+
+ ret = read(*(int *)hndle, read_buf, readlen);
+
+ *numread = ret;
+ if (ret == -1) {
+ perror("ReadFromPort Failed");
+ DPRINT_ERR(ERR, "Errno:%d\n", errno);
+ return FAIL;
+ }
+ if (*numread != data_size - total_numread) {
+ DPRINT_DBG(OUTPUT, "asked for %d bytes got %d bytes\n",
+ data_size - total_numread, *numread);
+ }
+ if ((*numread == 0) && (count > 10000)) {
+ DPRINT_ERR(ERR, "rwl_read_serial_port failed after %d retries\n",
+ count);
+ return FAIL;
+ }
+
+ total_numread += *numread;
+ read_buf += *numread;
+ count++;
+ }
+ return SUCCESS;
+}
+
+void
+rwl_sync_delay(uint noframes)
+{
+ if (noframes > 1) {
+ rwl_sleep(LINUX_SYNC_DELAY);
+ }
+}
+
+#endif /* RWL_DONGLE ||RWL_SERIAL */
+
+#if defined(RWL_DONGLE) || defined(RWL_SOCKET) || defined(RWL_SERIAL)
+void*
+rwl_open_transport(int remote_type, char *port, int ReadTotalTimeout, int debug)
+{
+ void* hndle;
+
+ UNUSED_PARAMETER(port);
+ UNUSED_PARAMETER(ReadTotalTimeout);
+ UNUSED_PARAMETER(debug);
+
+ switch (remote_type) {
+#if defined(RWL_DONGLE) || defined(RWL_SERIAL)
+ case REMOTE_SERIAL:
+#ifdef RWL_SERIAL
+ g_rwl_device_name_serial = port;
+#endif
+ case REMOTE_DONGLE:
+ if ((g_irh = rwl_open_serial(remote_type, g_rwl_device_name_serial,
+ g_rwl_device_baud)) == FAIL) {
+ /* Initial port opening settings failed in reboot.
+ * So retry opening the serial port
+ */
+ if ((g_irh = rwl_open_serial(remote_type, g_rwl_device_name_serial,
+ g_rwl_device_baud)) == FAIL) {
+ DPRINT_ERR(ERR, "Can't open serial port\n");
+ return NULL;
+ }
+ }
+ break;
+#endif /* RWL_DONGLE || RWL_SERIAL */
+
+#ifdef RWL_SOCKET
+ case REMOTE_SOCKET:
+ if ((g_irh = rwl_opensocket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == FAIL) {
+ DPRINT_ERR(ERR, "\nCan't open socket \n");
+ return NULL;
+ }
+
+ break;
+#endif /* RWL_SOCKET */
+
+ default:
+ DPRINT_ERR(ERR, "rwl_open_transport: Unknown remote_type %d\n", remote_type);
+ return NULL;
+ break;
+ } /* end - switch case */
+
+ hndle = (void*) &g_irh;
+ return hndle;
+}
+
+int
+rwl_close_transport(int remote_type, void* Des)
+{
+ switch (remote_type) {
+#ifdef RWL_SOCKET
+ case REMOTE_SOCKET:
+ if (Des != NULL) {
+ if (rwl_closesocket(*(int *)Des) == FAIL)
+ return FAIL;
+ }
+ break;
+#endif /* RWL_SOCKET */
+
+#if defined(RWL_DONGLE) || defined(RWL_SERIAL)
+ case REMOTE_DONGLE:
+ case REMOTE_SERIAL:
+ if (close(*(int *)Des) == -1)
+ return FAIL;
+ break;
+#endif /* RWL_DONGLE || RWL_SERIAL */
+
+ default:
+ DPRINT_ERR(ERR, "close_pipe: Unknown remote_type %d\n", remote_type);
+ break;
+ }
+ return SUCCESS;
+}
+#endif /* #if defined (RWL_DONGLE) || defined (RWL_SOCKET) */
+
+void
+rwl_sleep(int delay)
+{
+ usleep(delay * MICRO_SEC_CONVERTER_VAL);
+}
+
+#if defined(WLMSO) || defined(WLDYNLIB)
+int
+rwl_init_socket(void)
+{
+ return 0;
+}
+#endif
diff --git a/wl/src/wl/exe/wlu_rates_matrix.c b/wl/src/wl/exe/wlu_rates_matrix.c
new file mode 100644
index 0000000..3924ff2
--- /dev/null
+++ b/wl/src/wl/exe/wlu_rates_matrix.c
@@ -0,0 +1,1119 @@
+/*
+ * This module does provides various mappings to or from the CLM rate indexes.
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ */
+/*FILE-CSTYLED*/
+
+#include <stdio.h>
+#include <typedefs.h>
+#include <assert.h>
+#include "wlu_rates_matrix.h"
+
+#define CLM_NO_RATE_STRING "NO_RATE"
+#define EXP_MODE_UNKNOWN "Unknown expansion mode"
+#define AUTO_RATESPEC 0x0
+#define MHZ_TO_HALF_MHZ 2
+
+typedef enum exp_mode {
+ EXP_MODE_ID_DEF = 0,
+ EXP_MODE_ID_STBC,
+ EXP_MODE_ID_TXBF,
+ EXP_MODE_ID_MAX
+} exp_mode_t;
+
+static reg_rate_index_t get_legacy_reg_rate_index(int rate_hmhz, int tx_expansion, exp_mode_t mode);
+static reg_rate_index_t get_ht_reg_rate_index(int mcs, int tx_expansion, exp_mode_t mode);
+static reg_rate_index_t get_vht_reg_rate_index(int mcs, int nss, int tx_expansion, exp_mode_t mode);
+static int get_legacy_rate_identifier(int rate_hmhz);
+static int get_legacy_mode_identifier(int tx_expansion, exp_mode_t mode);
+static int get_vht_rate_identifier(int vht_mcs_index);
+static int get_vht_ss1_mode_identifier(int tx_expansion, exp_mode_t mode);
+static int get_vht_ss2_mode_identifier(int tx_expansion, exp_mode_t mode);
+static int get_vht_ss3_mode_identifier(int tx_expansion, exp_mode_t mode);
+static int get_vht_ss4_mode_identifier(int tx_expansion, exp_mode_t mode);
+static const char *get_mode_name(exp_mode_t mode);
+
+enum {
+ LEGACY_RATE_ID_NO_RATE = -1,
+ LEGACY_RATE_ID_1MHZ = 0,
+ LEGACY_RATE_ID_2MHZ,
+ LEGACY_RATE_ID_5_5MHZ,
+ LEGACY_RATE_ID_11MHZ,
+ LEGACY_RATE_ID_6MHZ,
+ LEGACY_RATE_ID_9MHZ,
+ LEGACY_RATE_ID_12MHZ,
+ LEGACY_RATE_ID_18MHZ,
+ LEGACY_RATE_ID_24MHZ,
+ LEGACY_RATE_ID_36MHZ,
+ LEGACY_RATE_ID_48MHZ,
+ LEGACY_RATE_ID_54MHZ,
+ LEGACY_RATE_ID_MAX
+};
+
+enum {
+ LEGACY_MODE_ID_NONE = 0,
+ LEGACY_MODE_ID_TXEXP1,
+ LEGACY_MODE_ID_TXEXP2,
+ LEGACY_MODE_ID_TXEXP3,
+ LEGACY_MODE_ID_TXBF1,
+ LEGACY_MODE_ID_TXBF2,
+ LEGACY_MODE_ID_TXBF3,
+ LEGACY_MODE_ID_MAX
+};
+
+enum {
+ VHT_RATE_INDEX_0 = 0,
+ VHT_RATE_INDEX_1,
+ VHT_RATE_INDEX_2,
+ VHT_RATE_INDEX_3,
+ VHT_RATE_INDEX_4,
+ VHT_RATE_INDEX_5,
+ VHT_RATE_INDEX_6,
+ VHT_RATE_INDEX_7,
+ VHT_RATE_INDEX_8,
+ VHT_RATE_INDEX_9,
+ VHT_RATE_INDEX_10,
+ VHT_RATE_INDEX_11,
+ VHT_RATE_INDEX_MAX
+};
+
+enum {
+ VHT_SS1_MODE_ID_NONE = 0,
+ VHT_SS1_MODE_ID_CDD1,
+ VHT_SS1_MODE_ID_STBC,
+ VHT_SS1_MODE_ID_CDD2,
+ VHT_SS1_MODE_ID_STBC_SPEXP1,
+ VHT_SS1_MODE_ID_CDD3,
+ VHT_SS1_MODE_ID_STBC_SPEXP2,
+ VHT_SS1_MODE_ID_TXBF1,
+ VHT_SS1_MODE_ID_TXBF2,
+ VHT_SS1_MODE_ID_TXBF3,
+ VHT_SS1_MODE_ID_MAX
+};
+
+enum {
+ VHT_SS2_MODE_ID_NONE = 0,
+ VHT_SS2_MODE_ID_SPEXP1,
+ VHT_SS2_MODE_ID_SPEXP2,
+ VHT_SS2_MODE_ID_TXBF0,
+ VHT_SS2_MODE_ID_TXBF1,
+ VHT_SS2_MODE_ID_TXBF2,
+ VHT_SS2_MODE_ID_MAX
+};
+
+enum {
+ VHT_SS3_MODE_ID_NONE = 0,
+ VHT_SS3_MODE_ID_SPEXP1,
+ VHT_SS3_MODE_ID_TXBF0,
+ VHT_SS3_MODE_ID_TXBF1,
+ VHT_SS3_MODE_ID_MAX
+};
+
+enum {
+ VHT_SS4_MODE_ID_NONE = 0,
+ VHT_SS4_MODE_ID_TXBF0,
+ VHT_SS4_MODE_ID_MAX
+};
+
+const char *clm_rate_group_labels[] = {
+ "DSSS",
+ "OFDM",
+ "MCS0_7",
+ "VHT8_9SS1",
+ "VHT10_11SS1",
+ "DSSS_MULTI1",
+ "OFDM_CDD1",
+ "MCS0_7_CDD1",
+ "VHT8_9SS1_CDD1",
+ "VHT10_11SS1_CDD1",
+ "MCS0_7_STBC",
+ "VHT8_9SS1_STBC",
+ "VHT10_11SS1_STBC",
+ "MCS8_15",
+ "VHT8_9SS2",
+ "VHT10_11SS2",
+ "DSSS_MULTI2",
+ "OFDM_CDD2",
+ "MCS0_7_CDD2",
+ "VHT8_9SS1_CDD2",
+ "VHT10_11SS1_CDD2",
+ "MCS0_7_STBC_SPEXP1",
+ "VHT8_9SS1_STBC_SPEXP1",
+ "VHT10_11SS1_STBC_SPEXP1",
+ "MCS8_15_SPEXP1",
+ "VHT8_9SS2_SPEXP1",
+ "VHT10_11SS2_SPEXP1",
+ "MCS16_23",
+ "VHT8_9SS3",
+ "VHT10_11SS3",
+ "DSSS_MULTI3",
+ "OFDM_CDD3",
+ "MCS0_7_CDD3",
+ "VHT8_9SS1_CDD3",
+ "VHT10_11SS1_CDD3",
+ "MCS0_7_STBC_SPEXP2",
+ "VHT8_9SS1_STBC_SPEXP2",
+ "VHT10_11SS1_STBC_SPEXP2",
+ "MCS8_15_SPEXP2",
+ "VHT8_9SS2_SPEXP2",
+ "VHT10_11SS2_SPEXP2",
+ "MCS16_23_SPEXP1",
+ "VHT8_9SS3_SPEXP1",
+ "VHT10_11SS3_SPEXP1",
+ "MCS24_31",
+ "VHT8_9SS4",
+ "VHT10_11SS4",
+ "OFDM_TXBF1",
+ "MCS0_7_TXBF1",
+ "VHT8_9SS1_TXBF1",
+ "VHT10_11SS1_TXBF1",
+ "MCS8_15_TXBF0",
+ "VHT8_9SS2_TXBF0",
+ "VHT10_11SS2_TXBF0",
+ "OFDM_TXBF2",
+ "MCS0_7_TXBF2",
+ "VHT8_9SS1_TXBF2",
+ "VHT10_11SS1_TXBF2",
+ "MCS8_15_TXBF1",
+ "VHT8_9SS2_TXBF1",
+ "VHT10_11SS2_TXBF1",
+ "MCS16_23_TXBF0",
+ "VHT8_9SS3_TXBF0",
+ "VHT10_11SS3_TXBF0",
+ "OFDM_TXBF3",
+ "MCS0_7_TXBF3",
+ "VHT8_9SS1_TXBF3",
+ "VHT10_11SS1_TXBF3",
+ "MCS8_15_TXBF2",
+ "VHT8_9SS2_TXBF2",
+ "VHT10_11SS2_TXBF2",
+ "MCS16_23_TXBF1",
+ "VHT8_9SS3_TXBF1",
+ "VHT10_11SS3_TXBF1",
+ "MCS24_31_TXBF0",
+ "VHT8_9SS4_TXBF0",
+ "VHT10_11SS4_TXBF0",
+};
+
+
+const char *clm_rate_labels[] = {
+ "DSSS1",
+ "DSSS2",
+ "DSSS5",
+ "DSSS11",
+ "OFDM6",
+ "OFDM9",
+ "OFDM12",
+ "OFDM18",
+ "OFDM24",
+ "OFDM36",
+ "OFDM48",
+ "OFDM54",
+ "MCS0",
+ "MCS1",
+ "MCS2",
+ "MCS3",
+ "MCS4",
+ "MCS5",
+ "MCS6",
+ "MCS7",
+ "VHT8SS1",
+ "VHT9SS1",
+ "VHT10SS1",
+ "VHT11SS1",
+ "DSSS1_MULTI1",
+ "DSSS2_MULTI1",
+ "DSSS5_MULTI1",
+ "DSSS11_MULTI1",
+ "OFDM6_CDD1",
+ "OFDM9_CDD1",
+ "OFDM12_CDD1",
+ "OFDM18_CDD1",
+ "OFDM24_CDD1",
+ "OFDM36_CDD1",
+ "OFDM48_CDD1",
+ "OFDM54_CDD1",
+ "MCS0_CDD1",
+ "MCS1_CDD1",
+ "MCS2_CDD1",
+ "MCS3_CDD1",
+ "MCS4_CDD1",
+ "MCS5_CDD1",
+ "MCS6_CDD1",
+ "MCS7_CDD1",
+ "VHT8SS1_CDD1",
+ "VHT9SS1_CDD1",
+ "VHT10SS1_CDD1",
+ "VHT11SS1_CDD1",
+ "MCS0_STBC",
+ "MCS1_STBC",
+ "MCS2_STBC",
+ "MCS3_STBC",
+ "MCS4_STBC",
+ "MCS5_STBC",
+ "MCS6_STBC",
+ "MCS7_STBC",
+ "VHT8SS1_STBC",
+ "VHT9SS1_STBC",
+ "VHT10SS1_STBC",
+ "VHT11SS1_STBC",
+ "MCS8",
+ "MCS9",
+ "MCS10",
+ "MCS11",
+ "MCS12",
+ "MCS13",
+ "MCS14",
+ "MCS15",
+ "VHT8SS2",
+ "VHT9SS2",
+ "VHT10SS2",
+ "VHT11SS2",
+ "DSSS1_MULTI2",
+ "DSSS2_MULTI2",
+ "DSSS5_MULTI2",
+ "DSSS11_MULTI2",
+ "OFDM6_CDD2",
+ "OFDM9_CDD2",
+ "OFDM12_CDD2",
+ "OFDM18_CDD2",
+ "OFDM24_CDD2",
+ "OFDM36_CDD2",
+ "OFDM48_CDD2",
+ "OFDM54_CDD2",
+ "MCS0_CDD2",
+ "MCS1_CDD2",
+ "MCS2_CDD2",
+ "MCS3_CDD2",
+ "MCS4_CDD2",
+ "MCS5_CDD2",
+ "MCS6_CDD2",
+ "MCS7_CDD2",
+ "VHT8SS1_CDD2",
+ "VHT9SS1_CDD2",
+ "VHT10SS1_CDD2",
+ "VHT11SS1_CDD2",
+ "MCS0_STBC_SPEXP1",
+ "MCS1_STBC_SPEXP1",
+ "MCS2_STBC_SPEXP1",
+ "MCS3_STBC_SPEXP1",
+ "MCS4_STBC_SPEXP1",
+ "MCS5_STBC_SPEXP1",
+ "MCS6_STBC_SPEXP1",
+ "MCS7_STBC_SPEXP1",
+ "VHT8SS1_STBC_SPEXP1",
+ "VHT9SS1_STBC_SPEXP1",
+ "VHT10SS1_STBC_SPEXP1",
+ "VHT11SS1_STBC_SPEXP1",
+ "MCS8_SPEXP1",
+ "MCS9_SPEXP1",
+ "MCS10_SPEXP1",
+ "MCS11_SPEXP1",
+ "MCS12_SPEXP1",
+ "MCS13_SPEXP1",
+ "MCS14_SPEXP1",
+ "MCS15_SPEXP1",
+ "VHT8SS2_SPEXP1",
+ "VHT9SS2_SPEXP1",
+ "VHT10SS2_SPEXP1",
+ "VHT11SS2_SPEXP1",
+ "MCS16",
+ "MCS17",
+ "MCS18",
+ "MCS19",
+ "MCS20",
+ "MCS21",
+ "MCS22",
+ "MCS23",
+ "VHT8SS3",
+ "VHT9SS3",
+ "VHT10SS3",
+ "VHT11SS3",
+ "DSSS1_MULTI3",
+ "DSSS2_MULTI3",
+ "DSSS5_MULTI3",
+ "DSSS11_MULTI3",
+ "OFDM6_CDD3",
+ "OFDM9_CDD3",
+ "OFDM12_CDD3",
+ "OFDM18_CDD3",
+ "OFDM24_CDD3",
+ "OFDM36_CDD3",
+ "OFDM48_CDD3",
+ "OFDM54_CDD3",
+ "MCS0_CDD3",
+ "MCS1_CDD3",
+ "MCS2_CDD3",
+ "MCS3_CDD3",
+ "MCS4_CDD3",
+ "MCS5_CDD3",
+ "MCS6_CDD3",
+ "MCS7_CDD3",
+ "VHT8SS1_CDD3",
+ "VHT9SS1_CDD3",
+ "VHT10SS1_CDD3",
+ "VHT11SS1_CDD3",
+ "MCS0_STBC_SPEXP2",
+ "MCS1_STBC_SPEXP2",
+ "MCS2_STBC_SPEXP2",
+ "MCS3_STBC_SPEXP2",
+ "MCS4_STBC_SPEXP2",
+ "MCS5_STBC_SPEXP2",
+ "MCS6_STBC_SPEXP2",
+ "MCS7_STBC_SPEXP2",
+ "VHT8SS1_STBC_SPEXP2",
+ "VHT9SS1_STBC_SPEXP2",
+ "VHT10SS1_STBC_SPEXP2",
+ "VHT11SS1_STBC_SPEXP2",
+ "MCS8_SPEXP2",
+ "MCS9_SPEXP2",
+ "MCS10_SPEXP2",
+ "MCS11_SPEXP2",
+ "MCS12_SPEXP2",
+ "MCS13_SPEXP2",
+ "MCS14_SPEXP2",
+ "MCS15_SPEXP2",
+ "VHT8SS2_SPEXP2",
+ "VHT9SS2_SPEXP2",
+ "VHT10SS2_SPEXP2",
+ "VHT11SS2_SPEXP2",
+ "MCS16_SPEXP1",
+ "MCS17_SPEXP1",
+ "MCS18_SPEXP1",
+ "MCS19_SPEXP1",
+ "MCS20_SPEXP1",
+ "MCS21_SPEXP1",
+ "MCS22_SPEXP1",
+ "MCS23_SPEXP1",
+ "VHT8SS3_SPEXP1",
+ "VHT9SS3_SPEXP1",
+ "VHT10SS3_SPEXP1",
+ "VHT11SS3_SPEXP1",
+ "MCS24",
+ "MCS25",
+ "MCS26",
+ "MCS27",
+ "MCS28",
+ "MCS29",
+ "MCS30",
+ "MCS31",
+ "VHT8SS4",
+ "VHT9SS4",
+ "VHT10SS4",
+ "VHT11SS4",
+ "OFDM6_TXBF1",
+ "OFDM9_TXBF1",
+ "OFDM12_TXBF1",
+ "OFDM18_TXBF1",
+ "OFDM24_TXBF1",
+ "OFDM36_TXBF1",
+ "OFDM48_TXBF1",
+ "OFDM54_TXBF1",
+ "MCS0_TXBF1",
+ "MCS1_TXBF1",
+ "MCS2_TXBF1",
+ "MCS3_TXBF1",
+ "MCS4_TXBF1",
+ "MCS5_TXBF1",
+ "MCS6_TXBF1",
+ "MCS7_TXBF1",
+ "VHT8SS1_TXBF1",
+ "VHT9SS1_TXBF1",
+ "VHT10SS1_TXBF1",
+ "VHT11SS1_TXBF1",
+ "MCS8_TXBF0",
+ "MCS9_TXBF0",
+ "MCS10_TXBF0",
+ "MCS11_TXBF0",
+ "MCS12_TXBF0",
+ "MCS13_TXBF0",
+ "MCS14_TXBF0",
+ "MCS15_TXBF0",
+ "VHT8SS2_TXBF0",
+ "VHT9SS2_TXBF0",
+ "VHT10SS2_TXBF0",
+ "VHT11SS2_TXBF0",
+ "OFDM6_TXBF2",
+ "OFDM9_TXBF2",
+ "OFDM12_TXBF2",
+ "OFDM18_TXBF2",
+ "OFDM24_TXBF2",
+ "OFDM36_TXBF2",
+ "OFDM48_TXBF2",
+ "OFDM54_TXBF2",
+ "MCS0_TXBF2",
+ "MCS1_TXBF2",
+ "MCS2_TXBF2",
+ "MCS3_TXBF2",
+ "MCS4_TXBF2",
+ "MCS5_TXBF2",
+ "MCS6_TXBF2",
+ "MCS7_TXBF2",
+ "VHT8SS1_TXBF2",
+ "VHT9SS1_TXBF2",
+ "VHT10SS1_TXBF2",
+ "VHT11SS1_TXBF2",
+ "MCS8_TXBF1",
+ "MCS9_TXBF1",
+ "MCS10_TXBF1",
+ "MCS11_TXBF1",
+ "MCS12_TXBF1",
+ "MCS13_TXBF1",
+ "MCS14_TXBF1",
+ "MCS15_TXBF1",
+ "VHT8SS2_TXBF1",
+ "VHT9SS2_TXBF1",
+ "VHT10SS2_TXBF1",
+ "VHT11SS2_TXBF1",
+ "MCS16_TXBF0",
+ "MCS17_TXBF0",
+ "MCS18_TXBF0",
+ "MCS19_TXBF0",
+ "MCS20_TXBF0",
+ "MCS21_TXBF0",
+ "MCS22_TXBF0",
+ "MCS23_TXBF0",
+ "VHT8SS3_TXBF0",
+ "VHT9SS3_TXBF0",
+ "VHT10SS3_TXBF0",
+ "VHT11SS3_TXBF0",
+ "OFDM6_TXBF3",
+ "OFDM9_TXBF3",
+ "OFDM12_TXBF3",
+ "OFDM18_TXBF3",
+ "OFDM24_TXBF3",
+ "OFDM36_TXBF3",
+ "OFDM48_TXBF3",
+ "OFDM54_TXBF3",
+ "MCS0_TXBF3",
+ "MCS1_TXBF3",
+ "MCS2_TXBF3",
+ "MCS3_TXBF3",
+ "MCS4_TXBF3",
+ "MCS5_TXBF3",
+ "MCS6_TXBF3",
+ "MCS7_TXBF3",
+ "VHT8SS1_TXBF3",
+ "VHT9SS1_TXBF3",
+ "VHT10SS1_TXBF3",
+ "VHT11SS1_TXBF3",
+ "MCS8_TXBF2",
+ "MCS9_TXBF2",
+ "MCS10_TXBF2",
+ "MCS11_TXBF2",
+ "MCS12_TXBF2",
+ "MCS13_TXBF2",
+ "MCS14_TXBF2",
+ "MCS15_TXBF2",
+ "VHT8SS2_TXBF2",
+ "VHT9SS2_TXBF2",
+ "VHT10SS2_TXBF2",
+ "VHT11SS2_TXBF2",
+ "MCS16_TXBF1",
+ "MCS17_TXBF1",
+ "MCS18_TXBF1",
+ "MCS19_TXBF1",
+ "MCS20_TXBF1",
+ "MCS21_TXBF1",
+ "MCS22_TXBF1",
+ "MCS23_TXBF1",
+ "VHT8SS3_TXBF1",
+ "VHT9SS3_TXBF1",
+ "VHT10SS3_TXBF1",
+ "VHT11SS3_TXBF1",
+ "MCS24_TXBF0",
+ "MCS25_TXBF0",
+ "MCS26_TXBF0",
+ "MCS27_TXBF0",
+ "MCS28_TXBF0",
+ "MCS29_TXBF0",
+ "MCS30_TXBF0",
+ "MCS31_TXBF0",
+ "VHT8SS4_TXBF0",
+ "VHT9SS4_TXBF0",
+ "VHT10SS4_TXBF0",
+ "VHT11SS4_TXBF0",
+};
+
+int legacy_reg_rate_map[LEGACY_RATE_ID_MAX][LEGACY_MODE_ID_MAX] = {
+ {DSSS1, DSSS1_MULTI1, DSSS1_MULTI2, DSSS1_MULTI3, NO_RATE, NO_RATE, NO_RATE},
+ {DSSS2, DSSS2_MULTI1, DSSS2_MULTI2, DSSS2_MULTI3, NO_RATE, NO_RATE, NO_RATE},
+ {DSSS5, DSSS5_MULTI1, DSSS5_MULTI2, DSSS5_MULTI3, NO_RATE, NO_RATE, NO_RATE},
+ {DSSS11, DSSS11_MULTI1, DSSS11_MULTI2,DSSS11_MULTI3, NO_RATE, NO_RATE, NO_RATE},
+ {OFDM6, OFDM6_CDD1, OFDM6_CDD2, OFDM6_CDD3, OFDM6_TXBF1, OFDM6_TXBF2, OFDM6_TXBF3},
+ {OFDM9, OFDM9_CDD1, OFDM9_CDD2, OFDM9_CDD3, OFDM9_TXBF1, OFDM9_TXBF2, OFDM9_TXBF3},
+ {OFDM12, OFDM12_CDD1, OFDM12_CDD2, OFDM12_CDD3, OFDM12_TXBF1, OFDM12_TXBF2, OFDM12_TXBF3},
+ {OFDM18, OFDM18_CDD1, OFDM18_CDD2, OFDM18_CDD3, OFDM18_TXBF1, OFDM18_TXBF2, OFDM18_TXBF3},
+ {OFDM24, OFDM24_CDD1, OFDM24_CDD2, OFDM24_CDD3, OFDM24_TXBF1, OFDM24_TXBF2, OFDM24_TXBF3},
+ {OFDM36, OFDM36_CDD1, OFDM36_CDD2, OFDM36_CDD3, OFDM36_TXBF1, OFDM36_TXBF2, OFDM36_TXBF3},
+ {OFDM48, OFDM48_CDD1, OFDM48_CDD2, OFDM48_CDD3, OFDM48_TXBF1, OFDM48_TXBF2, OFDM48_TXBF3},
+ {OFDM54, OFDM54_CDD1, OFDM54_CDD2, OFDM54_CDD3, OFDM54_TXBF1, OFDM54_TXBF2, OFDM54_TXBF3},
+};
+
+int vht_ss1_reg_rate_map[VHT_RATE_INDEX_MAX][VHT_SS1_MODE_ID_MAX] = {
+ {MCS0, MCS0_CDD1, MCS0_STBC, MCS0_CDD2, MCS0_STBC_SPEXP1, MCS0_CDD3, MCS0_STBC_SPEXP2, MCS0_TXBF1, MCS0_TXBF2, MCS0_TXBF3},
+ {MCS1, MCS1_CDD1, MCS1_STBC, MCS1_CDD2, MCS1_STBC_SPEXP1, MCS1_CDD3, MCS1_STBC_SPEXP2, MCS1_TXBF1, MCS1_TXBF2, MCS1_TXBF3},
+ {MCS2, MCS2_CDD1, MCS2_STBC, MCS2_CDD2, MCS2_STBC_SPEXP1, MCS2_CDD3, MCS2_STBC_SPEXP2, MCS2_TXBF1, MCS2_TXBF2, MCS2_TXBF3},
+ {MCS3, MCS3_CDD1, MCS3_STBC, MCS3_CDD2, MCS3_STBC_SPEXP1, MCS3_CDD3, MCS3_STBC_SPEXP2, MCS3_TXBF1, MCS3_TXBF2, MCS3_TXBF3},
+ {MCS4, MCS4_CDD1, MCS4_STBC, MCS4_CDD2, MCS4_STBC_SPEXP1, MCS4_CDD3, MCS4_STBC_SPEXP2, MCS4_TXBF1, MCS4_TXBF2, MCS4_TXBF3},
+ {MCS5, MCS5_CDD1, MCS5_STBC, MCS5_CDD2, MCS5_STBC_SPEXP1, MCS5_CDD3, MCS5_STBC_SPEXP2, MCS5_TXBF1, MCS5_TXBF2, MCS5_TXBF3},
+ {MCS6, MCS6_CDD1, MCS6_STBC, MCS6_CDD2, MCS6_STBC_SPEXP1, MCS6_CDD3, MCS6_STBC_SPEXP2, MCS6_TXBF1, MCS6_TXBF2, MCS6_TXBF3},
+ {MCS7, MCS7_CDD1, MCS7_STBC, MCS7_CDD2, MCS7_STBC_SPEXP1, MCS7_CDD3, MCS7_STBC_SPEXP2, MCS7_TXBF1, MCS7_TXBF2, MCS7_TXBF3},
+ {VHT8SS1, VHT8SS1_CDD1, VHT8SS1_STBC, VHT8SS1_CDD2, VHT8SS1_STBC_SPEXP1, VHT8SS1_CDD3, VHT8SS1_STBC_SPEXP2, VHT8SS1_TXBF1, VHT8SS1_TXBF2, VHT8SS1_TXBF3},
+ {VHT9SS1, VHT9SS1_CDD1, VHT9SS1_STBC, VHT9SS1_CDD2, VHT9SS1_STBC_SPEXP1, VHT9SS1_CDD3, VHT9SS1_STBC_SPEXP2, VHT9SS1_TXBF1, VHT9SS1_TXBF2, VHT9SS1_TXBF3},
+ {VHT10SS1, VHT10SS1_CDD1, VHT10SS1_STBC, VHT10SS1_CDD2, VHT10SS1_STBC_SPEXP1, VHT10SS1_CDD3, VHT10SS1_STBC_SPEXP2, VHT10SS1_TXBF1, VHT10SS1_TXBF2, VHT10SS1_TXBF3},
+ {VHT11SS1, VHT11SS1_CDD1, VHT11SS1_STBC, VHT11SS1_CDD2, VHT11SS1_STBC_SPEXP1, VHT11SS1_CDD3, VHT11SS1_STBC_SPEXP2, VHT11SS1_TXBF1, VHT11SS1_TXBF2, VHT11SS1_TXBF3},
+};
+
+int vht_ss2_reg_rate_map[VHT_RATE_INDEX_MAX][VHT_SS2_MODE_ID_MAX] = {
+ {MCS8, MCS8_SPEXP1, MCS8_SPEXP2, MCS8_TXBF0, MCS8_TXBF1, MCS8_TXBF2},
+ {MCS9, MCS9_SPEXP1, MCS9_SPEXP2, MCS9_TXBF0, MCS9_TXBF1, MCS9_TXBF2},
+ {MCS10, MCS10_SPEXP1, MCS10_SPEXP2, MCS10_TXBF0, MCS10_TXBF1, MCS10_TXBF2},
+ {MCS11, MCS11_SPEXP1, MCS11_SPEXP2, MCS11_TXBF0, MCS11_TXBF1, MCS11_TXBF2},
+ {MCS12, MCS12_SPEXP1, MCS12_SPEXP2, MCS12_TXBF0, MCS12_TXBF1, MCS12_TXBF2},
+ {MCS13, MCS13_SPEXP1, MCS13_SPEXP2, MCS13_TXBF0, MCS13_TXBF1, MCS13_TXBF2},
+ {MCS14, MCS14_SPEXP1, MCS14_SPEXP2, MCS14_TXBF0, MCS14_TXBF1, MCS14_TXBF2},
+ {MCS15, MCS15_SPEXP1, MCS15_SPEXP2, MCS15_TXBF0, MCS15_TXBF1, MCS15_TXBF2},
+ {VHT8SS2, VHT8SS2_SPEXP1,VHT8SS2_SPEXP2,VHT8SS2_TXBF0, VHT8SS2_TXBF1, VHT8SS2_TXBF2},
+ {VHT9SS2, VHT9SS2_SPEXP1,VHT9SS2_SPEXP2,VHT9SS2_TXBF0, VHT9SS2_TXBF1, VHT9SS2_TXBF2},
+ {VHT10SS2, VHT10SS2_SPEXP1,VHT10SS2_SPEXP2,VHT10SS2_TXBF0, VHT10SS2_TXBF1, VHT10SS2_TXBF2},
+ {VHT11SS2, VHT11SS2_SPEXP1,VHT11SS2_SPEXP2,VHT11SS2_TXBF0, VHT11SS2_TXBF1, VHT11SS2_TXBF2},
+};
+
+int vht_ss3_reg_rate_map[VHT_RATE_INDEX_MAX][VHT_SS3_MODE_ID_MAX] = {
+ {MCS16, MCS16_SPEXP1, MCS16_TXBF0, MCS16_TXBF1},
+ {MCS17, MCS17_SPEXP1, MCS17_TXBF0, MCS17_TXBF1},
+ {MCS18, MCS18_SPEXP1, MCS18_TXBF0, MCS18_TXBF1},
+ {MCS19, MCS19_SPEXP1, MCS19_TXBF0, MCS19_TXBF1},
+ {MCS20, MCS20_SPEXP1, MCS20_TXBF0, MCS20_TXBF1},
+ {MCS21, MCS21_SPEXP1, MCS21_TXBF0, MCS21_TXBF1},
+ {MCS22, MCS22_SPEXP1, MCS22_TXBF0, MCS22_TXBF1},
+ {MCS23, MCS23_SPEXP1, MCS23_TXBF0, MCS23_TXBF1},
+ {VHT8SS3, VHT8SS3_SPEXP1, VHT8SS3_TXBF0, VHT8SS3_TXBF1},
+ {VHT9SS3, VHT9SS3_SPEXP1, VHT9SS3_TXBF0, VHT9SS3_TXBF1},
+ {VHT10SS3, VHT10SS3_SPEXP1, VHT10SS3_TXBF0, VHT10SS3_TXBF1},
+ {VHT11SS3, VHT11SS3_SPEXP1, VHT11SS3_TXBF0, VHT11SS3_TXBF1},
+};
+
+
+int vht_ss4_reg_rate_map[VHT_RATE_INDEX_MAX][VHT_SS4_MODE_ID_MAX] = {
+ {MCS24, MCS24_TXBF0},
+ {MCS25, MCS25_TXBF0},
+ {MCS26, MCS26_TXBF0},
+ {MCS27, MCS27_TXBF0},
+ {MCS28, MCS28_TXBF0},
+ {MCS29, MCS29_TXBF0},
+ {MCS30, MCS30_TXBF0},
+ {MCS31, MCS31_TXBF0},
+ {VHT8SS4, VHT8SS4_TXBF0},
+ {VHT9SS4, VHT9SS4_TXBF0},
+ {VHT10SS4, VHT10SS4_TXBF0},
+ {VHT11SS4, VHT11SS4_TXBF0},
+};
+
+const char *exp_mode_name[EXP_MODE_ID_MAX] = {
+ "CDD",
+ "STBC",
+ "TXBF"
+};
+
+const char *
+get_clm_rate_group_label(int rategroup)
+{
+ return clm_rate_group_labels[rategroup];
+}
+
+const char *
+get_reg_rate_string_from_ratespec(int ratespec)
+{
+ reg_rate_index_t index = get_reg_rate_index_from_ratespec(ratespec);
+
+ if (index >= 0)
+ {
+ return clm_rate_labels[index];
+ }
+ return CLM_NO_RATE_STRING;
+}
+
+reg_rate_index_t
+get_reg_rate_index_from_ratespec(int ratespec)
+{
+ uint encode, rate, txexp;
+ bool stbc,txbf;
+ int rate_index = NO_RATE;
+ exp_mode_t expmode = EXP_MODE_ID_DEF;
+
+ /* If auto is set, we don't get a ratespec that can be decoded */
+ if (ratespec == AUTO_RATESPEC)
+ return rate_index;
+
+ encode = (ratespec & WL_RSPEC_ENCODING_MASK);
+ rate = (ratespec & WL_RSPEC_RATE_MASK);
+ txexp = (ratespec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
+ stbc = (ratespec & WL_RSPEC_STBC) != 0;
+ txbf = (ratespec & WL_RSPEC_TXBF) != 0;
+
+ if (stbc && txbf) {
+ return rate_index;
+ } else if (txbf) {
+ expmode = EXP_MODE_ID_TXBF;
+ } else if (stbc) {
+ expmode = EXP_MODE_ID_STBC;
+ }
+
+ if (encode == WL_RSPEC_ENCODE_RATE) {
+ rate_index = get_legacy_reg_rate_index(rate, txexp, expmode);
+ } else if (encode == WL_RSPEC_ENCODE_HT) {
+ rate_index = get_ht_reg_rate_index(rate, txexp, expmode);
+ } else if (encode == WL_RSPEC_ENCODE_VHT) {
+ uint mcs = (ratespec & WL_RSPEC_VHT_MCS_MASK);
+ uint nss = (ratespec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
+ rate_index = get_vht_reg_rate_index(mcs, nss, txexp, expmode);
+ }
+
+ return rate_index;
+}
+
+reg_rate_index_t
+get_legacy_reg_rate_index(int rate_hmhz, int tx_expansion, exp_mode_t expmode)
+{
+ reg_rate_index_t index = NO_RATE;
+ int rate_id;
+ rate_id = get_legacy_rate_identifier(rate_hmhz);
+ if (rate_id == LEGACY_RATE_ID_NO_RATE || (expmode == EXP_MODE_ID_TXBF && rate_id < LEGACY_RATE_ID_6MHZ))
+ {
+ fprintf(stderr, "ERROR: Bad legacy rate spec: %d\n", rate_hmhz);
+ }
+ else
+ {
+ index = legacy_reg_rate_map[rate_id][get_legacy_mode_identifier(tx_expansion, expmode)];
+ }
+ return index;
+}
+
+static int get_legacy_rate_identifier(int rate_hmhz)
+{
+ int rate_lut[LEGACY_RATE_ID_MAX];
+ int rate_index = LEGACY_RATE_ID_NO_RATE;
+ int i;
+
+ rate_lut[LEGACY_RATE_ID_1MHZ] = 1 * MHZ_TO_HALF_MHZ;
+ rate_lut[LEGACY_RATE_ID_2MHZ] = 2 * MHZ_TO_HALF_MHZ;
+ rate_lut[LEGACY_RATE_ID_5_5MHZ] = 11; /* 5.5 * MHZ_TO_HALF_MHZ */
+ rate_lut[LEGACY_RATE_ID_11MHZ] = 11 * MHZ_TO_HALF_MHZ;
+ rate_lut[LEGACY_RATE_ID_6MHZ] = 6 * MHZ_TO_HALF_MHZ;
+ rate_lut[LEGACY_RATE_ID_9MHZ] = 9 * MHZ_TO_HALF_MHZ;
+ rate_lut[LEGACY_RATE_ID_12MHZ] = 12 * MHZ_TO_HALF_MHZ;
+ rate_lut[LEGACY_RATE_ID_18MHZ] = 18 * MHZ_TO_HALF_MHZ;
+ rate_lut[LEGACY_RATE_ID_24MHZ] = 24 * MHZ_TO_HALF_MHZ;
+ rate_lut[LEGACY_RATE_ID_36MHZ] = 36 * MHZ_TO_HALF_MHZ;
+ rate_lut[LEGACY_RATE_ID_48MHZ] = 48 * MHZ_TO_HALF_MHZ;
+ rate_lut[LEGACY_RATE_ID_54MHZ] = 54 * MHZ_TO_HALF_MHZ;
+
+ for (i = 0; i < LEGACY_RATE_ID_MAX; i++)
+ {
+ if (rate_lut[i] == rate_hmhz)
+ {
+ rate_index = i;
+ break;
+ }
+ }
+
+ return rate_index;
+}
+
+static int get_legacy_mode_identifier(int tx_expansion, exp_mode_t expmode)
+{
+ int mode_identifier = 0;
+
+ if (tx_expansion == 0)
+ {
+ mode_identifier = LEGACY_MODE_ID_NONE;
+ }
+ else if (tx_expansion == 1)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = LEGACY_MODE_ID_TXEXP1;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = LEGACY_MODE_ID_TXBF1;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad legacy tx_expansion spec: %d expansion mode %s\n",
+ tx_expansion, get_mode_name(expmode));
+ break;
+ }
+ }
+ else if (tx_expansion == 2)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = LEGACY_MODE_ID_TXEXP2;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = LEGACY_MODE_ID_TXBF2;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad legacy tx_expansion spec: %d expansion mode %s\n",
+ tx_expansion, get_mode_name(expmode));
+ break;
+ }
+ }
+ else if (tx_expansion == 3)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = LEGACY_MODE_ID_TXEXP3;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = LEGACY_MODE_ID_TXBF3;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad legacy tx_expansion spec: %d expansion mode %s\n",
+ tx_expansion, get_mode_name(expmode));
+ break;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Bad legacy tx_expansion spec: %d expansion mode %s\n", tx_expansion,
+ get_mode_name(expmode));
+ }
+
+ return mode_identifier;
+}
+
+reg_rate_index_t
+get_ht_reg_rate_index(int mcs, int tx_expansion, exp_mode_t expmode)
+{
+ reg_rate_index_t rate_index = NO_RATE;
+ int vht_mcs, nss;
+
+ if (mcs > WLC_MAXMCS)
+ {
+ fprintf(stderr, "ERROR: Bad ht mcs spec: %d\n", mcs);
+ }
+ else
+ {
+ if (IS_PROPRIETARY_11N_MCS(mcs)) {
+ switch (mcs) {
+ case 87:
+ nss = 1;
+ vht_mcs = VHT_RATE_INDEX_8;
+ break;
+ case 99:
+ nss = 2;
+ vht_mcs = VHT_RATE_INDEX_8;
+ break;
+ case 101:
+ nss = 3;
+ vht_mcs = VHT_RATE_INDEX_8;
+ break;
+ case 88:
+ nss = 1;
+ vht_mcs = VHT_RATE_INDEX_9;
+ break;
+ case 100:
+ nss = 2;
+ vht_mcs = VHT_RATE_INDEX_9;
+ break;
+ case 102:
+ nss = 3;
+ vht_mcs = VHT_RATE_INDEX_9;
+ break;
+ default:
+ assert(0);
+ return rate_index;
+ }
+ } else {
+ vht_mcs = mcs % 8;
+ nss = (mcs / 8) + 1;
+ }
+ rate_index = get_vht_reg_rate_index(vht_mcs, nss, tx_expansion, expmode);
+ }
+
+ return rate_index;
+}
+
+reg_rate_index_t
+get_vht_reg_rate_index(int mcs, int nss, int tx_expansion, exp_mode_t expmode)
+{
+ reg_rate_index_t rate_index = NO_RATE;
+ int rate_id = get_vht_rate_identifier(mcs);
+
+ if (nss == 1)
+ {
+ rate_index = vht_ss1_reg_rate_map[rate_id][get_vht_ss1_mode_identifier(tx_expansion, expmode)];
+ }
+ else if (nss == 2)
+ {
+ rate_index = vht_ss2_reg_rate_map[rate_id][get_vht_ss2_mode_identifier(tx_expansion, expmode)];
+ }
+ else if (nss == 3)
+ {
+ rate_index = vht_ss3_reg_rate_map[rate_id][get_vht_ss3_mode_identifier(tx_expansion, expmode)];
+ }
+ else if (nss == 4)
+ {
+ rate_index = vht_ss4_reg_rate_map[rate_id][get_vht_ss4_mode_identifier(tx_expansion, expmode)];
+ }
+
+ return rate_index;
+}
+
+static int get_vht_rate_identifier(int vht_mcs_index)
+{
+ int rate_index = 0;
+
+ if (vht_mcs_index >= VHT_RATE_INDEX_0 && vht_mcs_index < VHT_RATE_INDEX_MAX)
+ {
+ rate_index = vht_mcs_index;
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Bad vht mcs spec: %d\n", vht_mcs_index);
+ }
+ return rate_index;
+}
+
+static int get_vht_ss1_mode_identifier(int tx_expansion, exp_mode_t expmode)
+{
+ int mode_identifier = 0;
+
+ if (tx_expansion == 0)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = VHT_SS1_MODE_ID_NONE;
+ break;
+ case EXP_MODE_ID_STBC:
+ mode_identifier = VHT_SS1_MODE_ID_STBC;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad vht ss1 mode: %d, expansion mode %s\n", tx_expansion,
+ get_mode_name(expmode));
+ break;
+ }
+ }
+ else if (tx_expansion == 1)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = VHT_SS1_MODE_ID_CDD1;
+ break;
+ case EXP_MODE_ID_STBC:
+ mode_identifier = VHT_SS1_MODE_ID_STBC_SPEXP1;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = VHT_SS1_MODE_ID_TXBF1;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad vht ss1 mode: %d, expansion mode %s\n", tx_expansion,
+ get_mode_name(expmode));
+ break;
+ }
+ }
+ else if (tx_expansion == 2)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = VHT_SS1_MODE_ID_CDD2;
+ break;
+ case EXP_MODE_ID_STBC:
+ mode_identifier = VHT_SS1_MODE_ID_STBC_SPEXP2;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = VHT_SS1_MODE_ID_TXBF2;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad vht ss1 mode: %d, expansion mode %s\n", tx_expansion,
+ get_mode_name(expmode));
+ break;
+ }
+ }
+ else if (tx_expansion == 3)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = VHT_SS1_MODE_ID_CDD3;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = VHT_SS1_MODE_ID_TXBF3;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad vht ss1 mode: %d, expansion mode %s\n", tx_expansion,
+ get_mode_name(expmode));
+ break;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Bad vht ss1 mode: %d, expansion mode: %s\n", tx_expansion,
+ get_mode_name(expmode));
+ }
+
+ return mode_identifier;
+}
+
+static int get_vht_ss2_mode_identifier(int tx_expansion, exp_mode_t expmode)
+{
+ int mode_identifier = 0;
+
+ if (tx_expansion == 0)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = VHT_SS2_MODE_ID_NONE;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = VHT_SS2_MODE_ID_TXBF0;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad vht ss2 mode: %d, expansion mode %s\n", tx_expansion,
+ get_mode_name(expmode));
+ break;
+ }
+ }
+ else if (tx_expansion == 1)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = VHT_SS2_MODE_ID_SPEXP1;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = VHT_SS2_MODE_ID_TXBF1;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad vht ss2 mode: %d, expansion mode %s\n", tx_expansion,
+ get_mode_name(expmode));
+ break;
+ }
+ }
+ else if (tx_expansion == 2)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = VHT_SS2_MODE_ID_SPEXP2;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = VHT_SS2_MODE_ID_TXBF2;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad vht ss2 mode: %d, expansion mode %s\n", tx_expansion,
+ get_mode_name(expmode));
+ break;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Bad vht ss2 mode: %d expansion mode: %s\n", tx_expansion,
+ get_mode_name(expmode));
+ }
+
+ return mode_identifier;
+}
+
+static int get_vht_ss3_mode_identifier(int tx_expansion, exp_mode_t expmode)
+{
+ int mode_identifier = 0;
+
+ if (tx_expansion == 0)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = VHT_SS3_MODE_ID_NONE;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = VHT_SS3_MODE_ID_TXBF0;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad vht ss3 mode: %d, expansion mode: %s\n", tx_expansion
+ , get_mode_name(expmode));
+ break;
+ }
+ }
+ else if (tx_expansion == 1)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = VHT_SS3_MODE_ID_SPEXP1;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = VHT_SS3_MODE_ID_TXBF1;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad vht ss3 mode: %d, expansion mode: %s\n", tx_expansion
+ , get_mode_name(expmode));
+ break;
+ }
+
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Bad vht ss3 mode: %d, expansion: %s\n", tx_expansion,
+ get_mode_name(expmode));
+ }
+
+ return mode_identifier;
+}
+
+static int get_vht_ss4_mode_identifier(int tx_expansion, exp_mode_t expmode)
+{
+ int mode_identifier = 0;
+
+ if (tx_expansion == 0)
+ {
+ switch (expmode)
+ {
+ case EXP_MODE_ID_DEF:
+ mode_identifier = VHT_SS4_MODE_ID_NONE;
+ break;
+ case EXP_MODE_ID_TXBF:
+ mode_identifier = VHT_SS4_MODE_ID_TXBF0;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Bad vht ss4 mode: %d, expansion mode: %s\n", tx_expansion
+ , get_mode_name(expmode));
+ break;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Bad vht ss4 mode: %d, expansion: %s\n", tx_expansion,
+ get_mode_name(expmode));
+ }
+
+ return mode_identifier;
+}
+
+
+static const char *get_mode_name(exp_mode_t mode)
+{
+ if (mode >= EXP_MODE_ID_MAX)
+ return EXP_MODE_UNKNOWN;
+
+ return exp_mode_name[mode];
+}
diff --git a/wl/src/wl/exe/wlu_rates_matrix.h b/wl/src/wl/exe/wlu_rates_matrix.h
new file mode 100644
index 0000000..18eb46b
--- /dev/null
+++ b/wl/src/wl/exe/wlu_rates_matrix.h
@@ -0,0 +1,667 @@
+/*
+ * This module does provides various mappings to or from the CLM rate indexes.
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ */
+/*FILE-CSTYLED*/
+
+#ifndef _WLU_RATES_MATRIX_H_
+#define _WLU_RATES_MATRIX_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <bcmwifi_rates.h>
+#include <wlioctl.h>
+#include <typedefs.h>
+#include <epivers.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmwifi_channels.h>
+#include <wlc_ppr.h>
+
+#ifdef LINUX
+#include <inttypes.h>
+#endif
+#include <miniopt.h>
+
+#define WL_UNSUPPORTED_IDX 0xFFF
+
+#define WLC_MAXMCS 102 /* Maximum valid mcs index */
+
+#define IS_PROPRIETARY_11N_MCS(mcs) \
+ ((mcs) == 87 || (mcs) == 88 || (mcs) == 99 || (mcs) == 100 || (mcs) == 101 || (mcs) == 102)
+
+typedef enum clm_rate_group_id {
+ RATE_GROUP_ID_DSSS = 0,
+ RATE_GROUP_ID_OFDM,
+ RATE_GROUP_ID_MCS0_7,
+ RATE_GROUP_ID_VHT8_9SS1,
+ RATE_GROUP_ID_VHT10_11SS1,
+ RATE_GROUP_ID_DSSS_MULTI1,
+ RATE_GROUP_ID_OFDM_CDD1,
+ RATE_GROUP_ID_MCS0_7_CDD1,
+ RATE_GROUP_ID_VHT8_9SS1_CDD1,
+ RATE_GROUP_ID_VHT10_11SS1_CDD1,
+ RATE_GROUP_ID_MCS0_7_STBC,
+ RATE_GROUP_ID_VHT8_9SS1_STBC,
+ RATE_GROUP_ID_VHT10_11SS1_STBC,
+ RATE_GROUP_ID_MCS8_15,
+ RATE_GROUP_ID_VHT8_9SS2,
+ RATE_GROUP_ID_VHT10_11SS2,
+ RATE_GROUP_ID_DSSS_MULTI2,
+ RATE_GROUP_ID_OFDM_CDD2,
+ RATE_GROUP_ID_MCS0_7_CDD2,
+ RATE_GROUP_ID_VHT8_9SS1_CDD2,
+ RATE_GROUP_ID_VHT10_11SS1_CDD2,
+ RATE_GROUP_ID_MCS0_7_STBC_SPEXP1,
+ RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP1,
+ RATE_GROUP_ID_VHT10_11SS1_STBC_SPEXP1,
+ RATE_GROUP_ID_MCS8_15_SPEXP1,
+ RATE_GROUP_ID_VHT8_9SS2_SPEXP1,
+ RATE_GROUP_ID_VHT10_11SS2_SPEXP1,
+ RATE_GROUP_ID_MCS16_23,
+ RATE_GROUP_ID_VHT8_9SS3,
+ RATE_GROUP_ID_VHT10_11SS3,
+ RATE_GROUP_ID_DSSS_MULTI3,
+ RATE_GROUP_ID_OFDM_CDD3,
+ RATE_GROUP_ID_MCS0_7_CDD3,
+ RATE_GROUP_ID_VHT8_9SS1_CDD3,
+ RATE_GROUP_ID_VHT10_11SS1_CDD3,
+ RATE_GROUP_ID_MCS0_7_STBC_SPEXP2,
+ RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP2,
+ RATE_GROUP_ID_VHT10_11SS1_STBC_SPEXP2,
+ RATE_GROUP_ID_MCS8_15_SPEXP2,
+ RATE_GROUP_ID_VHT8_9SS2_SPEXP2,
+ RATE_GROUP_ID_VHT10_11SS2_SPEXP2,
+ RATE_GROUP_ID_MCS16_23_SPEXP1,
+ RATE_GROUP_ID_VHT8_9SS3_SPEXP1,
+ RATE_GROUP_ID_VHT10_11SS3_SPEXP1,
+ RATE_GROUP_ID_MCS24_31,
+ RATE_GROUP_ID_VHT8_9SS4,
+ RATE_GROUP_ID_VHT10_11SS4,
+ RATE_GROUP_ID_OFDM_TXBF1,
+ RATE_GROUP_ID_MCS0_7_TXBF1,
+ RATE_GROUP_ID_VHT8_9SS1_TXBF1,
+ RATE_GROUP_ID_VHT10_11SS1_TXBF1,
+ RATE_GROUP_ID_MCS8_15_TXBF0,
+ RATE_GROUP_ID_VHT8_9SS2_TXBF0,
+ RATE_GROUP_ID_VHT10_11SS2_TXBF0,
+ RATE_GROUP_ID_OFDM_TXBF2,
+ RATE_GROUP_ID_MCS0_7_TXBF2,
+ RATE_GROUP_ID_VHT8_9SS1_TXBF2,
+ RATE_GROUP_ID_VHT10_11SS1_TXBF2,
+ RATE_GROUP_ID_MCS8_15_TXBF1,
+ RATE_GROUP_ID_VHT8_9SS2_TXBF1,
+ RATE_GROUP_ID_VHT10_11SS2_TXBF1,
+ RATE_GROUP_ID_MCS16_23_TXBF0,
+ RATE_GROUP_ID_VHT8_9SS3_TXBF0,
+ RATE_GROUP_ID_VHT10_11SS3_TXBF0,
+ RATE_GROUP_ID_OFDM_TXBF3,
+ RATE_GROUP_ID_MCS0_7_TXBF3,
+ RATE_GROUP_ID_VHT8_9SS1_TXBF3,
+ RATE_GROUP_ID_VHT10_11SS1_TXBF3,
+ RATE_GROUP_ID_MCS8_15_TXBF2,
+ RATE_GROUP_ID_VHT8_9SS2_TXBF2,
+ RATE_GROUP_ID_VHT10_11SS2_TXBF2,
+ RATE_GROUP_ID_MCS16_23_TXBF1,
+ RATE_GROUP_ID_VHT8_9SS3_TXBF1,
+ RATE_GROUP_ID_VHT10_11SS3_TXBF1,
+ RATE_GROUP_ID_MCS24_31_TXBF0,
+ RATE_GROUP_ID_VHT8_9SS4_TXBF0,
+ RATE_GROUP_ID_VHT10_11SS4_TXBF0,
+ RATE_GROUP_ID_COUNT
+} clm_rate_group_id_t;
+
+typedef enum reg_rate_index {
+ NO_RATE = -1,
+ DSSS1, DSSS2, DSSS5, DSSS11,
+ OFDM6, OFDM9, OFDM12, OFDM18,
+ OFDM24, OFDM36, OFDM48, OFDM54,
+ MCS0, MCS1, MCS2, MCS3,
+ MCS4, MCS5, MCS6, MCS7,
+ VHT8SS1, VHT9SS1,VHT10SS1, VHT11SS1,
+ DSSS1_MULTI1, DSSS2_MULTI1, DSSS5_MULTI1, DSSS11_MULTI1,
+ OFDM6_CDD1, OFDM9_CDD1, OFDM12_CDD1, OFDM18_CDD1,
+ OFDM24_CDD1, OFDM36_CDD1, OFDM48_CDD1, OFDM54_CDD1,
+ MCS0_CDD1, MCS1_CDD1, MCS2_CDD1, MCS3_CDD1,
+ MCS4_CDD1, MCS5_CDD1, MCS6_CDD1, MCS7_CDD1,
+ VHT8SS1_CDD1, VHT9SS1_CDD1, VHT10SS1_CDD1, VHT11SS1_CDD1,
+ MCS0_STBC, MCS1_STBC, MCS2_STBC, MCS3_STBC,
+ MCS4_STBC, MCS5_STBC, MCS6_STBC, MCS7_STBC,
+ VHT8SS1_STBC, VHT9SS1_STBC, VHT10SS1_STBC, VHT11SS1_STBC,
+ MCS8, MCS9, MCS10, MCS11,
+ MCS12, MCS13, MCS14, MCS15,
+ VHT8SS2, VHT9SS2, VHT10SS2, VHT11SS2,
+ DSSS1_MULTI2, DSSS2_MULTI2, DSSS5_MULTI2, DSSS11_MULTI2,
+ OFDM6_CDD2, OFDM9_CDD2, OFDM12_CDD2, OFDM18_CDD2,
+ OFDM24_CDD2, OFDM36_CDD2, OFDM48_CDD2, OFDM54_CDD2,
+ MCS0_CDD2, MCS1_CDD2, MCS2_CDD2, MCS3_CDD2,
+ MCS4_CDD2, MCS5_CDD2, MCS6_CDD2, MCS7_CDD2,
+ VHT8SS1_CDD2, VHT9SS1_CDD2, VHT10SS1_CDD2, VHT11SS1_CDD2,
+ MCS0_STBC_SPEXP1, MCS1_STBC_SPEXP1, MCS2_STBC_SPEXP1, MCS3_STBC_SPEXP1,
+ MCS4_STBC_SPEXP1, MCS5_STBC_SPEXP1, MCS6_STBC_SPEXP1, MCS7_STBC_SPEXP1,
+ VHT8SS1_STBC_SPEXP1, VHT9SS1_STBC_SPEXP1, VHT10SS1_STBC_SPEXP1, VHT11SS1_STBC_SPEXP1,
+ MCS8_SPEXP1, MCS9_SPEXP1, MCS10_SPEXP1, MCS11_SPEXP1,
+ MCS12_SPEXP1, MCS13_SPEXP1, MCS14_SPEXP1, MCS15_SPEXP1,
+ VHT8SS2_SPEXP1, VHT9SS2_SPEXP1, VHT10SS2_SPEXP1, VHT11SS2_SPEXP1,
+ MCS16, MCS17, MCS18, MCS19,
+ MCS20, MCS21, MCS22, MCS23,
+ VHT8SS3, VHT9SS3, VHT10SS3, VHT11SS3,
+ DSSS1_MULTI3, DSSS2_MULTI3, DSSS5_MULTI3, DSSS11_MULTI3,
+ OFDM6_CDD3, OFDM9_CDD3, OFDM12_CDD3, OFDM18_CDD3,
+ OFDM24_CDD3, OFDM36_CDD3, OFDM48_CDD3, OFDM54_CDD3,
+ MCS0_CDD3, MCS1_CDD3, MCS2_CDD3, MCS3_CDD3,
+ MCS4_CDD3, MCS5_CDD3, MCS6_CDD3, MCS7_CDD3,
+ VHT8SS1_CDD3, VHT9SS1_CDD3, VHT10SS1_CDD3, VHT11SS1_CDD3,
+ MCS0_STBC_SPEXP2, MCS1_STBC_SPEXP2, MCS2_STBC_SPEXP2, MCS3_STBC_SPEXP2,
+ MCS4_STBC_SPEXP2, MCS5_STBC_SPEXP2, MCS6_STBC_SPEXP2, MCS7_STBC_SPEXP2,
+ VHT8SS1_STBC_SPEXP2, VHT9SS1_STBC_SPEXP2, VHT10SS1_STBC_SPEXP2, VHT11SS1_STBC_SPEXP2,
+ MCS8_SPEXP2, MCS9_SPEXP2, MCS10_SPEXP2, MCS11_SPEXP2,
+ MCS12_SPEXP2, MCS13_SPEXP2, MCS14_SPEXP2, MCS15_SPEXP2,
+ VHT8SS2_SPEXP2, VHT9SS2_SPEXP2, VHT10SS2_SPEXP2, VHT11SS2_SPEXP2,
+ MCS16_SPEXP1, MCS17_SPEXP1, MCS18_SPEXP1, MCS19_SPEXP1,
+ MCS20_SPEXP1, MCS21_SPEXP1, MCS22_SPEXP1, MCS23_SPEXP1,
+ VHT8SS3_SPEXP1, VHT9SS3_SPEXP1, VHT10SS3_SPEXP1, VHT11SS3_SPEXP1,
+ MCS24, MCS25, MCS26, MCS27,
+ MCS28, MCS29, MCS30, MCS31,
+ VHT8SS4, VHT9SS4, VHT10SS4, VHT11SS4,
+ OFDM6_TXBF1, OFDM9_TXBF1, OFDM12_TXBF1, OFDM18_TXBF1,
+ OFDM24_TXBF1, OFDM36_TXBF1, OFDM48_TXBF1, OFDM54_TXBF1,
+ MCS0_TXBF1, MCS1_TXBF1, MCS2_TXBF1, MCS3_TXBF1,
+ MCS4_TXBF1, MCS5_TXBF1, MCS6_TXBF1, MCS7_TXBF1,
+ VHT8SS1_TXBF1, VHT9SS1_TXBF1, VHT10SS1_TXBF1, VHT11SS1_TXBF1,
+ MCS8_TXBF0, MCS9_TXBF0, MCS10_TXBF0, MCS11_TXBF0,
+ MCS12_TXBF0, MCS13_TXBF0, MCS14_TXBF0, MCS15_TXBF0,
+ VHT8SS2_TXBF0, VHT9SS2_TXBF0, VHT10SS2_TXBF0, VHT11SS2_TXBF0,
+ OFDM6_TXBF2, OFDM9_TXBF2, OFDM12_TXBF2, OFDM18_TXBF2,
+ OFDM24_TXBF2, OFDM36_TXBF2, OFDM48_TXBF2, OFDM54_TXBF2,
+ MCS0_TXBF2, MCS1_TXBF2, MCS2_TXBF2, MCS3_TXBF2,
+ MCS4_TXBF2, MCS5_TXBF2, MCS6_TXBF2, MCS7_TXBF2,
+ VHT8SS1_TXBF2, VHT9SS1_TXBF2, VHT10SS1_TXBF2, VHT11SS1_TXBF2,
+ MCS8_TXBF1, MCS9_TXBF1, MCS10_TXBF1, MCS11_TXBF1,
+ MCS12_TXBF1, MCS13_TXBF1, MCS14_TXBF1, MCS15_TXBF1,
+ VHT8SS2_TXBF1, VHT9SS2_TXBF1, VHT10SS2_TXBF1, VHT11SS2_TXBF1,
+ MCS16_TXBF0, MCS17_TXBF0, MCS18_TXBF0, MCS19_TXBF0,
+ MCS20_TXBF0, MCS21_TXBF0, MCS22_TXBF0, MCS23_TXBF0,
+ VHT8SS3_TXBF0, VHT9SS3_TXBF0, VHT10SS3_TXBF0, VHT11SS3_TXBF0,
+ OFDM6_TXBF3, OFDM9_TXBF3, OFDM12_TXBF3, OFDM18_TXBF3,
+ OFDM24_TXBF3, OFDM36_TXBF3, OFDM48_TXBF3, OFDM54_TXBF3,
+ MCS0_TXBF3, MCS1_TXBF3, MCS2_TXBF3, MCS3_TXBF3,
+ MCS4_TXBF3, MCS5_TXBF3, MCS6_TXBF3, MCS7_TXBF3,
+ VHT8SS1_TXBF3, VHT9SS1_TXBF3, VHT10SS1_TXBF3, VHT11SS1_TXBF3,
+ MCS8_TXBF2, MCS9_TXBF2, MCS10_TXBF2, MCS11_TXBF2,
+ MCS12_TXBF2, MCS13_TXBF2, MCS14_TXBF2, MCS15_TXBF2,
+ VHT8SS2_TXBF2, VHT9SS2_TXBF2, VHT10SS2_TXBF2, VHT11SS2_TXBF2,
+ MCS16_TXBF1, MCS17_TXBF1, MCS18_TXBF1, MCS19_TXBF1,
+ MCS20_TXBF1, MCS21_TXBF1, MCS22_TXBF1, MCS23_TXBF1,
+ VHT8SS3_TXBF1, VHT9SS3_TXBF1, VHT10SS3_TXBF1, VHT11SS3_TXBF1,
+ MCS24_TXBF0, MCS25_TXBF0, MCS26_TXBF0, MCS27_TXBF0,
+ MCS28_TXBF0, MCS29_TXBF0, MCS30_TXBF0, MCS31_TXBF0,
+ VHT8SS4_TXBF0, VHT9SS4_TXBF0, VHT10SS4_TXBF0, VHT11SS4_TXBF0,
+} reg_rate_index_t;
+
+typedef enum ppr_rate_type {
+ PPR_RATE_DSSS,
+ PPR_RATE_OFDM,
+ PPR_RATE_HT,
+ PPR_RATE_VHT,
+} ppr_rate_type_t;
+
+typedef struct ppr_tbl {
+ char label[23];
+ clm_rate_group_id_t id;
+// clm_rates_t rate;
+} ppr_tbl_t;
+
+typedef struct ppr_group {
+ clm_rate_group_id_t id;
+ wl_tx_chains_t chain;
+ wl_tx_mode_t mode;
+ wl_tx_nss_t nss;
+ ppr_rate_type_t rate_type;
+ reg_rate_index_t first_rate;
+} ppr_group_t;
+
+static const ppr_group_t ppr_group_table[] = {
+ /*group id chains mode nss rate type offset-first*/
+ {RATE_GROUP_ID_DSSS, WL_TX_CHAINS_1, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_DSSS, DSSS1},
+ {RATE_GROUP_ID_OFDM, WL_TX_CHAINS_1, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6},
+ {RATE_GROUP_ID_MCS0_7, WL_TX_CHAINS_1, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_VHT, MCS0},
+ {RATE_GROUP_ID_VHT8_9SS1, WL_TX_CHAINS_1, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_VHT, MCS0},
+ {RATE_GROUP_ID_VHT10_11SS1, WL_TX_CHAINS_1, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_VHT, MCS0},
+ {RATE_GROUP_ID_DSSS_MULTI1, WL_TX_CHAINS_2, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_DSSS, DSSS1_MULTI1},
+ {RATE_GROUP_ID_OFDM_CDD1, WL_TX_CHAINS_2, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6_CDD1},
+ {RATE_GROUP_ID_MCS0_7_CDD1, WL_TX_CHAINS_2, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD1},
+ {RATE_GROUP_ID_VHT8_9SS1_CDD1, WL_TX_CHAINS_2, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD1},
+ {RATE_GROUP_ID_VHT10_11SS1_CDD1, WL_TX_CHAINS_2, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD1},
+ {RATE_GROUP_ID_MCS0_7_STBC, WL_TX_CHAINS_2, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC},
+ {RATE_GROUP_ID_VHT8_9SS1_STBC, WL_TX_CHAINS_2, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC},
+ {RATE_GROUP_ID_VHT10_11SS1_STBC, WL_TX_CHAINS_2, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC},
+ {RATE_GROUP_ID_MCS8_15, WL_TX_CHAINS_2, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8},
+ {RATE_GROUP_ID_VHT8_9SS2, WL_TX_CHAINS_2, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8},
+ {RATE_GROUP_ID_VHT10_11SS2, WL_TX_CHAINS_2, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8},
+ {RATE_GROUP_ID_DSSS_MULTI2, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_DSSS, DSSS1_MULTI2},
+ {RATE_GROUP_ID_OFDM_CDD2, WL_TX_CHAINS_3, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6_CDD2},
+ {RATE_GROUP_ID_MCS0_7_CDD2, WL_TX_CHAINS_3, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD2},
+ {RATE_GROUP_ID_VHT8_9SS1_CDD2, WL_TX_CHAINS_3, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD2},
+ {RATE_GROUP_ID_VHT10_11SS1_CDD2, WL_TX_CHAINS_3, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD2},
+ {RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, WL_TX_CHAINS_3, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC_SPEXP1},
+ {RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP1, WL_TX_CHAINS_3, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC_SPEXP1},
+ {RATE_GROUP_ID_VHT10_11SS1_STBC_SPEXP1, WL_TX_CHAINS_3, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC_SPEXP1},
+ {RATE_GROUP_ID_MCS8_15_SPEXP1, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_SPEXP1},
+ {RATE_GROUP_ID_VHT8_9SS2_SPEXP1, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_SPEXP1},
+ {RATE_GROUP_ID_VHT10_11SS2_SPEXP1, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_SPEXP1},
+ {RATE_GROUP_ID_MCS16_23, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_3, PPR_RATE_VHT, MCS16},
+ {RATE_GROUP_ID_VHT8_9SS3, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_3, PPR_RATE_VHT, MCS16},
+ {RATE_GROUP_ID_VHT10_11SS3, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_3, PPR_RATE_VHT, MCS16},
+ {RATE_GROUP_ID_DSSS_MULTI3, WL_TX_CHAINS_4, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_DSSS, DSSS1_MULTI3},
+ {RATE_GROUP_ID_OFDM_CDD3, WL_TX_CHAINS_4, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6_CDD3},
+ {RATE_GROUP_ID_MCS0_7_CDD3, WL_TX_CHAINS_4, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD3},
+ {RATE_GROUP_ID_VHT8_9SS1_CDD3, WL_TX_CHAINS_4, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD3},
+ {RATE_GROUP_ID_VHT10_11SS1_CDD3, WL_TX_CHAINS_4, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD3},
+ {RATE_GROUP_ID_MCS0_7_STBC_SPEXP2, WL_TX_CHAINS_4, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC_SPEXP2},
+ {RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP2, WL_TX_CHAINS_4, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC_SPEXP2},
+ {RATE_GROUP_ID_VHT10_11SS1_STBC_SPEXP2, WL_TX_CHAINS_4, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC_SPEXP2},
+ {RATE_GROUP_ID_MCS8_15_SPEXP2, WL_TX_CHAINS_4, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_SPEXP2},
+ {RATE_GROUP_ID_VHT8_9SS2_SPEXP2, WL_TX_CHAINS_4, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_SPEXP2},
+ {RATE_GROUP_ID_VHT10_11SS2_SPEXP2, WL_TX_CHAINS_4, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_SPEXP2},
+ {RATE_GROUP_ID_MCS16_23_SPEXP1, WL_TX_CHAINS_4, WL_TX_MODE_NONE, WL_TX_NSS_3, PPR_RATE_VHT, MCS16_SPEXP1},
+ {RATE_GROUP_ID_VHT8_9SS3_SPEXP1, WL_TX_CHAINS_4, WL_TX_MODE_NONE, WL_TX_NSS_3, PPR_RATE_VHT, MCS16_SPEXP1},
+ {RATE_GROUP_ID_VHT10_11SS3_SPEXP1, WL_TX_CHAINS_4, WL_TX_MODE_NONE, WL_TX_NSS_3, PPR_RATE_VHT, MCS16_SPEXP1},
+ {RATE_GROUP_ID_MCS24_31, WL_TX_CHAINS_4, WL_TX_MODE_NONE, WL_TX_NSS_4, PPR_RATE_VHT, MCS24},
+ {RATE_GROUP_ID_VHT8_9SS4, WL_TX_CHAINS_4, WL_TX_MODE_NONE, WL_TX_NSS_4, PPR_RATE_VHT, MCS24},
+ {RATE_GROUP_ID_VHT10_11SS4, WL_TX_CHAINS_4, WL_TX_MODE_NONE, WL_TX_NSS_4, PPR_RATE_VHT, MCS24},
+ {RATE_GROUP_ID_OFDM_TXBF1, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6_TXBF1},
+ {RATE_GROUP_ID_MCS0_7_TXBF1, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF1},
+ {RATE_GROUP_ID_VHT8_9SS1_TXBF1, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF1},
+ {RATE_GROUP_ID_VHT10_11SS1_TXBF1, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF1},
+ {RATE_GROUP_ID_MCS8_15_TXBF0, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF0},
+ {RATE_GROUP_ID_VHT8_9SS2_TXBF0, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF0},
+ {RATE_GROUP_ID_VHT10_11SS2_TXBF0, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF0},
+ {RATE_GROUP_ID_OFDM_TXBF2, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6_TXBF2},
+ {RATE_GROUP_ID_MCS0_7_TXBF2, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF2},
+ {RATE_GROUP_ID_VHT8_9SS1_TXBF2, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF2},
+ {RATE_GROUP_ID_VHT10_11SS1_TXBF2, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF2},
+ {RATE_GROUP_ID_MCS8_15_TXBF1, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF1},
+ {RATE_GROUP_ID_VHT8_9SS2_TXBF1, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF1},
+ {RATE_GROUP_ID_VHT10_11SS2_TXBF1, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF1},
+ {RATE_GROUP_ID_MCS16_23_TXBF0, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_3, PPR_RATE_VHT, MCS16_TXBF0},
+ {RATE_GROUP_ID_VHT8_9SS3_TXBF0, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_3, PPR_RATE_VHT, MCS16_TXBF0},
+ {RATE_GROUP_ID_VHT10_11SS3_TXBF0, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_3, PPR_RATE_VHT, MCS16_TXBF0},
+ {RATE_GROUP_ID_OFDM_TXBF3, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6_TXBF3},
+ {RATE_GROUP_ID_MCS0_7_TXBF3, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF3},
+ {RATE_GROUP_ID_VHT8_9SS1_TXBF3, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF3},
+ {RATE_GROUP_ID_VHT10_11SS1_TXBF3, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF3},
+ {RATE_GROUP_ID_MCS8_15_TXBF2, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF2},
+ {RATE_GROUP_ID_VHT8_9SS2_TXBF2, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF2},
+ {RATE_GROUP_ID_VHT10_11SS2_TXBF2, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF2},
+ {RATE_GROUP_ID_MCS16_23_TXBF1, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_3, PPR_RATE_VHT, MCS16_TXBF1},
+ {RATE_GROUP_ID_VHT8_9SS3_TXBF1, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_3, PPR_RATE_VHT, MCS16_TXBF1},
+ {RATE_GROUP_ID_VHT10_11SS3_TXBF1, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_3, PPR_RATE_VHT, MCS16_TXBF1},
+ {RATE_GROUP_ID_MCS24_31_TXBF0, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_4, PPR_RATE_VHT, MCS24_TXBF0},
+ {RATE_GROUP_ID_VHT8_9SS4_TXBF0, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_4, PPR_RATE_VHT, MCS24_TXBF0},
+ {RATE_GROUP_ID_VHT10_11SS4_TXBF0, WL_TX_CHAINS_4, WL_TX_MODE_TXBF, WL_TX_NSS_4, PPR_RATE_VHT, MCS24_TXBF0},
+};
+
+static const ppr_tbl_t ppr_table[] = {
+ /* Label Rate Group ID */
+ {"DSSS1", RATE_GROUP_ID_DSSS},
+ {"DSSS2", RATE_GROUP_ID_DSSS},
+ {"DSSS5", RATE_GROUP_ID_DSSS},
+ {"DSSS11", RATE_GROUP_ID_DSSS},
+ {"OFDM6", RATE_GROUP_ID_OFDM},
+ {"OFDM9", RATE_GROUP_ID_OFDM},
+ {"OFDM12", RATE_GROUP_ID_OFDM},
+ {"OFDM18", RATE_GROUP_ID_OFDM},
+ {"OFDM24", RATE_GROUP_ID_OFDM},
+ {"OFDM36", RATE_GROUP_ID_OFDM},
+ {"OFDM48", RATE_GROUP_ID_OFDM},
+ {"OFDM54", RATE_GROUP_ID_OFDM},
+ {"MCS0", RATE_GROUP_ID_MCS0_7},
+ {"MCS1", RATE_GROUP_ID_MCS0_7},
+ {"MCS2", RATE_GROUP_ID_MCS0_7},
+ {"MCS3", RATE_GROUP_ID_MCS0_7},
+ {"MCS4", RATE_GROUP_ID_MCS0_7},
+ {"MCS5", RATE_GROUP_ID_MCS0_7},
+ {"MCS6", RATE_GROUP_ID_MCS0_7},
+ {"MCS7", RATE_GROUP_ID_MCS0_7},
+ {"VHT8SS1", RATE_GROUP_ID_VHT8_9SS1},
+ {"VHT9SS1", RATE_GROUP_ID_VHT8_9SS1},
+ {"VHT10SS1", RATE_GROUP_ID_VHT10_11SS1},
+ {"VHT11SS1", RATE_GROUP_ID_VHT10_11SS1},
+ {"DSSS1_MULTI1", RATE_GROUP_ID_DSSS_MULTI1},
+ {"DSSS2_MULTI1", RATE_GROUP_ID_DSSS_MULTI1},
+ {"DSSS5_MULTI1", RATE_GROUP_ID_DSSS_MULTI1},
+ {"DSSS11_MULTI1", RATE_GROUP_ID_DSSS_MULTI1},
+ {"OFDM6_CDD1", RATE_GROUP_ID_OFDM_CDD1},
+ {"OFDM9_CDD1", RATE_GROUP_ID_OFDM_CDD1},
+ {"OFDM12_CDD1", RATE_GROUP_ID_OFDM_CDD1},
+ {"OFDM18_CDD1", RATE_GROUP_ID_OFDM_CDD1},
+ {"OFDM24_CDD1", RATE_GROUP_ID_OFDM_CDD1},
+ {"OFDM36_CDD1", RATE_GROUP_ID_OFDM_CDD1},
+ {"OFDM48_CDD1", RATE_GROUP_ID_OFDM_CDD1},
+ {"OFDM54_CDD1", RATE_GROUP_ID_OFDM_CDD1},
+ {"MCS0_CDD1", RATE_GROUP_ID_MCS0_7_CDD1},
+ {"MCS1_CDD1", RATE_GROUP_ID_MCS0_7_CDD1},
+ {"MCS2_CDD1", RATE_GROUP_ID_MCS0_7_CDD1},
+ {"MCS3_CDD1", RATE_GROUP_ID_MCS0_7_CDD1},
+ {"MCS4_CDD1", RATE_GROUP_ID_MCS0_7_CDD1},
+ {"MCS5_CDD1", RATE_GROUP_ID_MCS0_7_CDD1},
+ {"MCS6_CDD1", RATE_GROUP_ID_MCS0_7_CDD1},
+ {"MCS7_CDD1", RATE_GROUP_ID_MCS0_7_CDD1},
+ {"VHT8SS1_CDD1", RATE_GROUP_ID_VHT8_9SS1_CDD1},
+ {"VHT9SS1_CDD1", RATE_GROUP_ID_VHT8_9SS1_CDD1},
+ {"VHT10SS1_CDD1", RATE_GROUP_ID_VHT10_11SS1_CDD1},
+ {"VHT11SS1_CDD1", RATE_GROUP_ID_VHT10_11SS1_CDD1},
+ {"MCS0_STBC", RATE_GROUP_ID_MCS0_7_STBC},
+ {"MCS1_STBC", RATE_GROUP_ID_MCS0_7_STBC},
+ {"MCS2_STBC", RATE_GROUP_ID_MCS0_7_STBC},
+ {"MCS3_STBC", RATE_GROUP_ID_MCS0_7_STBC},
+ {"MCS4_STBC", RATE_GROUP_ID_MCS0_7_STBC},
+ {"MCS5_STBC", RATE_GROUP_ID_MCS0_7_STBC},
+ {"MCS6_STBC", RATE_GROUP_ID_MCS0_7_STBC},
+ {"MCS7_STBC", RATE_GROUP_ID_MCS0_7_STBC},
+ {"VHT8SS1_STBC", RATE_GROUP_ID_VHT8_9SS1_STBC},
+ {"VHT9SS1_STBC", RATE_GROUP_ID_VHT8_9SS1_STBC},
+ {"VHT10SS1_STBC", RATE_GROUP_ID_VHT10_11SS1_STBC},
+ {"VHT11SS1_STBC", RATE_GROUP_ID_VHT10_11SS1_STBC},
+ {"MCS8", RATE_GROUP_ID_MCS8_15},
+ {"MCS9", RATE_GROUP_ID_MCS8_15},
+ {"MCS10", RATE_GROUP_ID_MCS8_15},
+ {"MCS11", RATE_GROUP_ID_MCS8_15},
+ {"MCS12", RATE_GROUP_ID_MCS8_15},
+ {"MCS13", RATE_GROUP_ID_MCS8_15},
+ {"MCS14", RATE_GROUP_ID_MCS8_15},
+ {"MCS15", RATE_GROUP_ID_MCS8_15},
+ {"VHT8SS2", RATE_GROUP_ID_VHT8_9SS2},
+ {"VHT9SS2", RATE_GROUP_ID_VHT8_9SS2},
+ {"VHT10SS2", RATE_GROUP_ID_VHT10_11SS2},
+ {"VHT11SS2", RATE_GROUP_ID_VHT10_11SS2},
+ {"DSSS1_MULTI2", RATE_GROUP_ID_DSSS_MULTI2},
+ {"DSSS2_MULTI2", RATE_GROUP_ID_DSSS_MULTI2},
+ {"DSSS5_MULTI2", RATE_GROUP_ID_DSSS_MULTI2},
+ {"DSSS11_MULTI2", RATE_GROUP_ID_DSSS_MULTI2},
+ {"OFDM6_CDD2", RATE_GROUP_ID_OFDM_CDD2},
+ {"OFDM9_CDD2", RATE_GROUP_ID_OFDM_CDD2},
+ {"OFDM12_CDD2", RATE_GROUP_ID_OFDM_CDD2},
+ {"OFDM18_CDD2", RATE_GROUP_ID_OFDM_CDD2},
+ {"OFDM24_CDD2", RATE_GROUP_ID_OFDM_CDD2},
+ {"OFDM36_CDD2", RATE_GROUP_ID_OFDM_CDD2},
+ {"OFDM48_CDD2", RATE_GROUP_ID_OFDM_CDD2},
+ {"OFDM54_CDD2", RATE_GROUP_ID_OFDM_CDD2},
+ {"MCS0_CDD2", RATE_GROUP_ID_MCS0_7_CDD2},
+ {"MCS1_CDD2", RATE_GROUP_ID_MCS0_7_CDD2},
+ {"MCS2_CDD2", RATE_GROUP_ID_MCS0_7_CDD2},
+ {"MCS3_CDD2", RATE_GROUP_ID_MCS0_7_CDD2},
+ {"MCS4_CDD2", RATE_GROUP_ID_MCS0_7_CDD2},
+ {"MCS5_CDD2", RATE_GROUP_ID_MCS0_7_CDD2},
+ {"MCS6_CDD2", RATE_GROUP_ID_MCS0_7_CDD2},
+ {"MCS7_CDD2", RATE_GROUP_ID_MCS0_7_CDD2},
+ {"VHT8SS1_CDD2", RATE_GROUP_ID_VHT8_9SS1_CDD2},
+ {"VHT9SS1_CDD2", RATE_GROUP_ID_VHT8_9SS1_CDD2},
+ {"VHT10SS1_CDD2", RATE_GROUP_ID_VHT10_11SS1_CDD2},
+ {"VHT11SS1_CDD2", RATE_GROUP_ID_VHT10_11SS1_CDD2},
+ {"MCS0_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1},
+ {"MCS1_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1},
+ {"MCS2_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1},
+ {"MCS3_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1},
+ {"MCS4_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1},
+ {"MCS5_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1},
+ {"MCS6_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1},
+ {"MCS7_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1},
+ {"VHT8SS1_STBC_SPEXP1", RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP1},
+ {"VHT9SS1_STBC_SPEXP1", RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP1},
+ {"VHT10SS1_STBC_SPEXP1", RATE_GROUP_ID_VHT10_11SS1_STBC_SPEXP1},
+ {"VHT11SS1_STBC_SPEXP1", RATE_GROUP_ID_VHT10_11SS1_STBC_SPEXP1},
+ {"MCS8_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1},
+ {"MCS9_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1},
+ {"MCS10_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1},
+ {"MCS11_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1},
+ {"MCS12_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1},
+ {"MCS13_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1},
+ {"MCS14_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1},
+ {"MCS15_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1},
+ {"VHT8SS2_SPEXP1", RATE_GROUP_ID_VHT8_9SS2_SPEXP1},
+ {"VHT9SS2_SPEXP1", RATE_GROUP_ID_VHT8_9SS2_SPEXP1},
+ {"VHT10SS2_SPEXP1", RATE_GROUP_ID_VHT10_11SS2_SPEXP1},
+ {"VHT11SS2_SPEXP1", RATE_GROUP_ID_VHT10_11SS2_SPEXP1},
+ {"MCS16", RATE_GROUP_ID_MCS16_23},
+ {"MCS17", RATE_GROUP_ID_MCS16_23},
+ {"MCS18", RATE_GROUP_ID_MCS16_23},
+ {"MCS19", RATE_GROUP_ID_MCS16_23},
+ {"MCS20", RATE_GROUP_ID_MCS16_23},
+ {"MCS21", RATE_GROUP_ID_MCS16_23},
+ {"MCS22", RATE_GROUP_ID_MCS16_23},
+ {"MCS23", RATE_GROUP_ID_MCS16_23},
+ {"VHT8SS3", RATE_GROUP_ID_VHT8_9SS3},
+ {"VHT9SS3", RATE_GROUP_ID_VHT8_9SS3},
+ {"VHT10SS3", RATE_GROUP_ID_VHT10_11SS3},
+ {"VHT11SS3", RATE_GROUP_ID_VHT10_11SS3},
+ {"DSSS1_MULTI3", RATE_GROUP_ID_DSSS_MULTI3},
+ {"DSSS2_MULTI3", RATE_GROUP_ID_DSSS_MULTI3},
+ {"DSSS5_MULTI3", RATE_GROUP_ID_DSSS_MULTI3},
+ {"DSSS11_MULTI3", RATE_GROUP_ID_DSSS_MULTI3},
+ {"OFDM6_CDD3", RATE_GROUP_ID_OFDM_CDD3},
+ {"OFDM9_CDD3", RATE_GROUP_ID_OFDM_CDD3},
+ {"OFDM12_CDD3", RATE_GROUP_ID_OFDM_CDD3},
+ {"OFDM18_CDD3", RATE_GROUP_ID_OFDM_CDD3},
+ {"OFDM24_CDD3", RATE_GROUP_ID_OFDM_CDD3},
+ {"OFDM36_CDD3", RATE_GROUP_ID_OFDM_CDD3},
+ {"OFDM48_CDD3", RATE_GROUP_ID_OFDM_CDD3},
+ {"OFDM54_CDD3", RATE_GROUP_ID_OFDM_CDD3},
+ {"MCS0_CDD3", RATE_GROUP_ID_MCS0_7_CDD3},
+ {"MCS1_CDD3", RATE_GROUP_ID_MCS0_7_CDD3},
+ {"MCS2_CDD3", RATE_GROUP_ID_MCS0_7_CDD3},
+ {"MCS3_CDD3", RATE_GROUP_ID_MCS0_7_CDD3},
+ {"MCS4_CDD3", RATE_GROUP_ID_MCS0_7_CDD3},
+ {"MCS5_CDD3", RATE_GROUP_ID_MCS0_7_CDD3},
+ {"MCS6_CDD3", RATE_GROUP_ID_MCS0_7_CDD3},
+ {"MCS7_CDD3", RATE_GROUP_ID_MCS0_7_CDD3},
+ {"VHT8SS1_CDD3", RATE_GROUP_ID_VHT8_9SS1_CDD3},
+ {"VHT9SS1_CDD3", RATE_GROUP_ID_VHT8_9SS1_CDD3},
+ {"VHT10SS1_CDD3", RATE_GROUP_ID_VHT10_11SS1_CDD3},
+ {"VHT11SS1_CDD3", RATE_GROUP_ID_VHT10_11SS1_CDD3},
+ {"MCS0_STBC_SPEXP2", RATE_GROUP_ID_MCS0_7_STBC_SPEXP2},
+ {"MCS1_STBC_SPEXP2", RATE_GROUP_ID_MCS0_7_STBC_SPEXP2},
+ {"MCS2_STBC_SPEXP2", RATE_GROUP_ID_MCS0_7_STBC_SPEXP2},
+ {"MCS3_STBC_SPEXP2", RATE_GROUP_ID_MCS0_7_STBC_SPEXP2},
+ {"MCS4_STBC_SPEXP2", RATE_GROUP_ID_MCS0_7_STBC_SPEXP2},
+ {"MCS5_STBC_SPEXP2", RATE_GROUP_ID_MCS0_7_STBC_SPEXP2},
+ {"MCS6_STBC_SPEXP2", RATE_GROUP_ID_MCS0_7_STBC_SPEXP2},
+ {"MCS7_STBC_SPEXP2", RATE_GROUP_ID_MCS0_7_STBC_SPEXP2},
+ {"VHT8SS1_STBC_SPEXP2", RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP2},
+ {"VHT9SS1_STBC_SPEXP2", RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP2},
+ {"VHT10SS1_STBC_SPEXP2", RATE_GROUP_ID_VHT10_11SS1_STBC_SPEXP2},
+ {"VHT11SS1_STBC_SPEXP2", RATE_GROUP_ID_VHT10_11SS1_STBC_SPEXP2},
+ {"MCS8_SPEXP2", RATE_GROUP_ID_MCS8_15_SPEXP2},
+ {"MCS9_SPEXP2", RATE_GROUP_ID_MCS8_15_SPEXP2},
+ {"MCS10_SPEXP2", RATE_GROUP_ID_MCS8_15_SPEXP2},
+ {"MCS11_SPEXP2", RATE_GROUP_ID_MCS8_15_SPEXP2},
+ {"MCS12_SPEXP2", RATE_GROUP_ID_MCS8_15_SPEXP2},
+ {"MCS13_SPEXP2", RATE_GROUP_ID_MCS8_15_SPEXP2},
+ {"MCS14_SPEXP2", RATE_GROUP_ID_MCS8_15_SPEXP2},
+ {"MCS15_SPEXP2", RATE_GROUP_ID_MCS8_15_SPEXP2},
+ {"VHT8SS2_SPEXP2", RATE_GROUP_ID_VHT8_9SS2_SPEXP2},
+ {"VHT9SS2_SPEXP2", RATE_GROUP_ID_VHT8_9SS2_SPEXP2},
+ {"VHT10SS2_SPEXP2", RATE_GROUP_ID_VHT10_11SS2_SPEXP2},
+ {"VHT11SS2_SPEXP2", RATE_GROUP_ID_VHT10_11SS2_SPEXP2},
+ {"MCS16_SPEXP1", RATE_GROUP_ID_MCS16_23},
+ {"MCS17_SPEXP1", RATE_GROUP_ID_MCS16_23},
+ {"MCS18_SPEXP1", RATE_GROUP_ID_MCS16_23},
+ {"MCS19_SPEXP1", RATE_GROUP_ID_MCS16_23},
+ {"MCS20_SPEXP1", RATE_GROUP_ID_MCS16_23},
+ {"MCS21_SPEXP1", RATE_GROUP_ID_MCS16_23},
+ {"MCS22_SPEXP1", RATE_GROUP_ID_MCS16_23},
+ {"MCS23_SPEXP1", RATE_GROUP_ID_MCS16_23},
+ {"VHT8SS3_SPEXP1", RATE_GROUP_ID_VHT8_9SS3},
+ {"VHT9SS3_SPEXP1", RATE_GROUP_ID_VHT8_9SS3},
+ {"VHT10SS3_SPEXP1", RATE_GROUP_ID_VHT10_11SS3},
+ {"VHT11SS3_SPEXP1", RATE_GROUP_ID_VHT10_11SS3},
+ {"MCS24", RATE_GROUP_ID_MCS24_31},
+ {"MCS25", RATE_GROUP_ID_MCS24_31},
+ {"MCS26", RATE_GROUP_ID_MCS24_31},
+ {"MCS27", RATE_GROUP_ID_MCS24_31},
+ {"MCS28", RATE_GROUP_ID_MCS24_31},
+ {"MCS29", RATE_GROUP_ID_MCS24_31},
+ {"MCS30", RATE_GROUP_ID_MCS24_31},
+ {"MCS31", RATE_GROUP_ID_MCS24_31},
+ {"VHT8SS4", RATE_GROUP_ID_VHT8_9SS4},
+ {"VHT9SS4", RATE_GROUP_ID_VHT8_9SS4},
+ {"VHT10SS4", RATE_GROUP_ID_VHT10_11SS4},
+ {"VHT11SS4", RATE_GROUP_ID_VHT10_11SS4},
+ {"OFDM6_TXBF1", RATE_GROUP_ID_OFDM_TXBF1},
+ {"OFDM9_TXBF1", RATE_GROUP_ID_OFDM_TXBF1},
+ {"OFDM12_TXBF1", RATE_GROUP_ID_OFDM_TXBF1},
+ {"OFDM18_TXBF1", RATE_GROUP_ID_OFDM_TXBF1},
+ {"OFDM24_TXBF1", RATE_GROUP_ID_OFDM_TXBF1},
+ {"OFDM36_TXBF1", RATE_GROUP_ID_OFDM_TXBF1},
+ {"OFDM48_TXBF1", RATE_GROUP_ID_OFDM_TXBF1},
+ {"OFDM54_TXBF1", RATE_GROUP_ID_OFDM_TXBF1},
+ {"MCS0_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1},
+ {"MCS1_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1},
+ {"MCS2_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1},
+ {"MCS3_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1},
+ {"MCS4_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1},
+ {"MCS5_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1},
+ {"MCS6_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1},
+ {"MCS7_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1},
+ {"VHT8SS1_TXBF1", RATE_GROUP_ID_VHT8_9SS1_TXBF1},
+ {"VHT9SS1_TXBF1", RATE_GROUP_ID_VHT8_9SS1_TXBF1},
+ {"VHT10SS1_TXBF1", RATE_GROUP_ID_VHT10_11SS1_TXBF1},
+ {"VHT11SS1_TXBF1", RATE_GROUP_ID_VHT10_11SS1_TXBF1},
+ {"MCS8_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0},
+ {"MCS9_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0},
+ {"MCS10_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0},
+ {"MCS11_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0},
+ {"MCS12_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0},
+ {"MCS13_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0},
+ {"MCS14_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0},
+ {"MCS15_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0},
+ {"VHT8SS2_TXBF0", RATE_GROUP_ID_VHT8_9SS2_TXBF0},
+ {"VHT9SS2_TXBF0", RATE_GROUP_ID_VHT8_9SS2_TXBF0},
+ {"VHT10SS2_TXBF0", RATE_GROUP_ID_VHT10_11SS2_TXBF0},
+ {"VHT11SS2_TXBF0", RATE_GROUP_ID_VHT10_11SS2_TXBF0},
+ {"OFDM6_TXBF2", RATE_GROUP_ID_OFDM_TXBF2},
+ {"OFDM9_TXBF2", RATE_GROUP_ID_OFDM_TXBF2},
+ {"OFDM12_TXBF2", RATE_GROUP_ID_OFDM_TXBF2},
+ {"OFDM18_TXBF2", RATE_GROUP_ID_OFDM_TXBF2},
+ {"OFDM24_TXBF2", RATE_GROUP_ID_OFDM_TXBF2},
+ {"OFDM36_TXBF2", RATE_GROUP_ID_OFDM_TXBF2},
+ {"OFDM48_TXBF2", RATE_GROUP_ID_OFDM_TXBF2},
+ {"OFDM54_TXBF2", RATE_GROUP_ID_OFDM_TXBF2},
+ {"MCS0_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2},
+ {"MCS1_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2},
+ {"MCS2_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2},
+ {"MCS3_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2},
+ {"MCS4_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2},
+ {"MCS5_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2},
+ {"MCS6_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2},
+ {"MCS7_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2},
+ {"VHT8SS1_TXBF2", RATE_GROUP_ID_VHT8_9SS1_TXBF2},
+ {"VHT9SS1_TXBF2", RATE_GROUP_ID_VHT8_9SS1_TXBF2},
+ {"VHT10SS1_TXBF2", RATE_GROUP_ID_VHT10_11SS1_TXBF2},
+ {"VHT11SS1_TXBF2", RATE_GROUP_ID_VHT10_11SS1_TXBF2},
+ {"MCS8_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1},
+ {"MCS9_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1},
+ {"MCS10_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1},
+ {"MCS11_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1},
+ {"MCS12_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1},
+ {"MCS13_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1},
+ {"MCS14_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1},
+ {"MCS15_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1},
+ {"VHT8SS2_TXBF1", RATE_GROUP_ID_VHT8_9SS2_TXBF1},
+ {"VHT9SS2_TXBF1", RATE_GROUP_ID_VHT8_9SS2_TXBF1},
+ {"VHT10SS2_TXBF1", RATE_GROUP_ID_VHT10_11SS2_TXBF1},
+ {"VHT11SS2_TXBF1", RATE_GROUP_ID_VHT10_11SS2_TXBF1},
+ {"MCS16_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0},
+ {"MCS17_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0},
+ {"MCS18_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0},
+ {"MCS19_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0},
+ {"MCS20_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0},
+ {"MCS21_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0},
+ {"MCS22_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0},
+ {"MCS23_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0},
+ {"VHT8SS3_TXBF0", RATE_GROUP_ID_VHT8_9SS3_TXBF0},
+ {"VHT9SS3_TXBF0", RATE_GROUP_ID_VHT8_9SS3_TXBF0},
+ {"VHT10SS3_TXBF0", RATE_GROUP_ID_VHT10_11SS3_TXBF0},
+ {"VHT11SS3_TXBF0", RATE_GROUP_ID_VHT10_11SS3_TXBF0},
+ {"OFDM6_TXBF3", RATE_GROUP_ID_OFDM_TXBF3},
+ {"OFDM9_TXBF3", RATE_GROUP_ID_OFDM_TXBF3},
+ {"OFDM12_TXBF3", RATE_GROUP_ID_OFDM_TXBF3},
+ {"OFDM18_TXBF3", RATE_GROUP_ID_OFDM_TXBF3},
+ {"OFDM24_TXBF3", RATE_GROUP_ID_OFDM_TXBF3},
+ {"OFDM36_TXBF3", RATE_GROUP_ID_OFDM_TXBF3},
+ {"OFDM48_TXBF3", RATE_GROUP_ID_OFDM_TXBF3},
+ {"OFDM54_TXBF3", RATE_GROUP_ID_OFDM_TXBF3},
+ {"MCS0_TXBF3", RATE_GROUP_ID_MCS0_7_TXBF3},
+ {"MCS1_TXBF3", RATE_GROUP_ID_MCS0_7_TXBF3},
+ {"MCS2_TXBF3", RATE_GROUP_ID_MCS0_7_TXBF3},
+ {"MCS3_TXBF3", RATE_GROUP_ID_MCS0_7_TXBF3},
+ {"MCS4_TXBF3", RATE_GROUP_ID_MCS0_7_TXBF3},
+ {"MCS5_TXBF3", RATE_GROUP_ID_MCS0_7_TXBF3},
+ {"MCS6_TXBF3", RATE_GROUP_ID_MCS0_7_TXBF3},
+ {"MCS7_TXBF3", RATE_GROUP_ID_MCS0_7_TXBF3},
+ {"VHT8SS1_TXBF3", RATE_GROUP_ID_VHT8_9SS1_TXBF3},
+ {"VHT9SS1_TXBF3", RATE_GROUP_ID_VHT8_9SS1_TXBF3},
+ {"VHT10SS1_TXBF3", RATE_GROUP_ID_VHT10_11SS1_TXBF3},
+ {"VHT11SS1_TXBF3", RATE_GROUP_ID_VHT10_11SS1_TXBF3},
+ {"MCS8_TXBF2", RATE_GROUP_ID_MCS8_15_TXBF2},
+ {"MCS9_TXBF2", RATE_GROUP_ID_MCS8_15_TXBF2},
+ {"MCS10_TXBF2", RATE_GROUP_ID_MCS8_15_TXBF2},
+ {"MCS11_TXBF2", RATE_GROUP_ID_MCS8_15_TXBF2},
+ {"MCS12_TXBF2", RATE_GROUP_ID_MCS8_15_TXBF2},
+ {"MCS13_TXBF2", RATE_GROUP_ID_MCS8_15_TXBF2},
+ {"MCS14_TXBF2", RATE_GROUP_ID_MCS8_15_TXBF2},
+ {"MCS15_TXBF2", RATE_GROUP_ID_MCS8_15_TXBF2},
+ {"VHT8SS2_TXBF2", RATE_GROUP_ID_VHT8_9SS2_TXBF2},
+ {"VHT9SS2_TXBF2", RATE_GROUP_ID_VHT8_9SS2_TXBF2},
+ {"VHT10SS2_TXBF2", RATE_GROUP_ID_VHT10_11SS2_TXBF2},
+ {"VHT11SS2_TXBF2", RATE_GROUP_ID_VHT10_11SS2_TXBF2},
+ {"MCS16_TXBF1", RATE_GROUP_ID_MCS16_23_TXBF1},
+ {"MCS17_TXBF1", RATE_GROUP_ID_MCS16_23_TXBF1},
+ {"MCS18_TXBF1", RATE_GROUP_ID_MCS16_23_TXBF1},
+ {"MCS19_TXBF1", RATE_GROUP_ID_MCS16_23_TXBF1},
+ {"MCS20_TXBF1", RATE_GROUP_ID_MCS16_23_TXBF1},
+ {"MCS21_TXBF1", RATE_GROUP_ID_MCS16_23_TXBF1},
+ {"MCS22_TXBF1", RATE_GROUP_ID_MCS16_23_TXBF1},
+ {"MCS23_TXBF1", RATE_GROUP_ID_MCS16_23_TXBF1},
+ {"VHT8SS3_TXBF1", RATE_GROUP_ID_VHT8_9SS3_TXBF1},
+ {"VHT9SS3_TXBF1", RATE_GROUP_ID_VHT8_9SS3_TXBF1},
+ {"VHT10SS3_TXBF1", RATE_GROUP_ID_VHT10_11SS3_TXBF1},
+ {"VHT11SS3_TXBF1", RATE_GROUP_ID_VHT10_11SS3_TXBF1},
+ {"MCS24_TXBF0", RATE_GROUP_ID_MCS24_31_TXBF0},
+ {"MCS25_TXBF0", RATE_GROUP_ID_MCS24_31_TXBF0},
+ {"MCS26_TXBF0", RATE_GROUP_ID_MCS24_31_TXBF0},
+ {"MCS27_TXBF0", RATE_GROUP_ID_MCS24_31_TXBF0},
+ {"MCS28_TXBF0", RATE_GROUP_ID_MCS24_31_TXBF0},
+ {"MCS29_TXBF0", RATE_GROUP_ID_MCS24_31_TXBF0},
+ {"MCS30_TXBF0", RATE_GROUP_ID_MCS24_31_TXBF0},
+ {"MCS31_TXBF0", RATE_GROUP_ID_MCS24_31_TXBF0},
+ {"VHT8SS4_TXBF0", RATE_GROUP_ID_VHT8_9SS4_TXBF0},
+ {"VHT9SS4_TXBF0", RATE_GROUP_ID_VHT8_9SS4_TXBF0},
+ {"VHT10SS4_TXBF0", RATE_GROUP_ID_VHT10_11SS4_TXBF0},
+ {"VHT11SS4_TXBF0", RATE_GROUP_ID_VHT10_11SS4_TXBF0},
+};
+
+#define MHZ_TO_HALF_MHZ 2
+
+const char *get_clm_rate_group_label(int rategroup);
+const char *get_reg_rate_string_from_ratespec(int ratespec);
+reg_rate_index_t get_reg_rate_index_from_ratespec(int ratespec);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _WLU_RATES_MATRIX_H_ */
diff --git a/wl/src/wl/exe/wlu_remote.h b/wl/src/wl/exe/wlu_remote.h
new file mode 100644
index 0000000..879466c
--- /dev/null
+++ b/wl/src/wl/exe/wlu_remote.h
@@ -0,0 +1,247 @@
+/*
+ * OS independent remote wl declarations
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_remote.h 535847 2015-02-19 19:01:29Z $
+ */
+#ifndef _wlu_remote_h
+#define _wlu_remote_h
+#include <wlioctl.h>
+
+#if defined(__FreeBSD__) && defined(RWL_SOCKET)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif /* defined(__FreeBSD__) && defined(RWL_SOCKET) */
+
+/* Remote wl declararions */
+#define NO_REMOTE 0
+#define REMOTE_SERIAL 1
+#define REMOTE_SOCKET 2
+#define REMOTE_WIFI 3
+#define REMOTE_DONGLE 4
+#define SHELL_CMD -1 /* Invalid cmd id for shell */
+#define ASD_CMD -2 /* Cmd id for ASD command */
+#define SERVER_RESPONSE_MAX_BUF_LEN 8192
+#define SHELL_RESP_SIZE 1024
+#define CTRLC_PACKET 0xDEADBEAF
+#define CTRLC_FLAG -4
+#define VISTA_CMD -3 /* cmd id for remote vista */
+
+/* For cross OS support */
+/* For autonegotiation to work, these defines should be
+ * the same for client and server.
+ */
+#define UNKNOWN_OS 0
+#define LINUX_OS 1
+#define WIN32_OS 2
+#define MAC_OSX 3
+#define BACKLOG 4
+#define WINVISTA_OS 5
+#define INDONGLE 6
+#define INVALID_OS 7 /* Should be last */
+
+/* Used in cdc_ioctl_t.flags field */
+#define REMOTE_SET_IOCTL 1
+#define REMOTE_GET_IOCTL 2
+#define REMOTE_REPLY 4
+#define REMOTE_SHELL_CMD 8
+#define REMOTE_FINDSERVER_IOCTL 16 /* Find remote server */
+#define REMOTE_ASD_CMD 32 /* ASD integration */
+#define RDHD_SET_IOCTL 64
+#define RDHD_GET_IOCTL 128
+#define REMOTE_VISTA_CMD 256 /* for remote vista specific commands */
+#define REMOTE_NEGOTIATE_CMD 512 /* for RWL negotiation */
+#define NEGOTIATE_GET_OS 0 /* detect remote OS */
+#define RWL_WIFI_DEFAULT_TYPE 0x00
+#define RWL_WIFI_DEFAULT_SUBTYPE 0x00
+#define RWL_ACTION_FRAME_DATA_SIZE 1024 /* fixed size for the wifi frame data */
+#define RWL_WIFI_CDC_HEADER_OFFSET 0
+#define RWL_WIFI_FRAG_DATA_SIZE 960 /* max size of the frag data */
+#define RWL_DEFAULT_WIFI_FRAG_COUNT 127 /* maximum fragment count */
+#define RWL_WIFI_RETRY 5 /* CMD retry count for wifi */
+#define RWL_WIFI_RX_RETRY 20 /* WIFI response rerty count */
+#define RWL_WIFI_SEND 5 /* WIFI frame sent count */
+#define RWL_WIFI_RETRY_DELAY 1000 /* wifi specific retry delay */
+#define RWL_WIFI_SEND_DELAY 100 /* delay between two frames */
+#define RWL_WIFI_RX_DELAY 250 /* wait between send and receive */
+#define RWL_WIFI_RX_SHELL_DELAY 1000 /* delay added for shell cmd response read */
+#define RWL_CHANNEL_RX_SCAN_DELAY 10 /* Delay between findserver rx calls */
+#define RWL_CHANNEL_SCAN_WAIT 250 /* Sleep time in between the channel scans */
+#define RWL_WIFI_BUF_LEN 64
+#define RWL_WIFI_SHELL_CMD 1
+#define RWL_WIFI_WL_CMD 0
+#define RWL_WIFI_FIND_SER_CMD "findserver"
+#define RWL_WIFI_ACTION_CMD "wifiaction"
+#define RWL_WIFI_GET_ACTION_CMD "rwlwifivsaction"
+#define RWL_DONGLE_SET_CMD "dongleset"
+#define DATA_FRAME_LEN 960
+/* wl & shell cmd work fine for 960 (512+256+128+64) */
+
+
+/*
+ * Information about the action frame data fields in the
+ * dot11_action_wifi_vendor_specific
+ * cdc struct (1 to 16. This does not include status flag. Since this
+ * is not directly visible to the driver code we cant use sizeof struct
+ * cdc_ioctl_t. Hence Ref MAC address offset starts from byte 17.
+ * REF MAC ADDR (6 bytes (MAC Address len) from byte 17 to 22)
+ * DUT MAC ADDR (6 bytes after the REF MAC Address byte 23 to 28)
+ * unused (byte 29 to 49)
+ * REF/Client Channel offset (50)
+ * DUT/Server channel offset (51)
+ * ---------------------------------------------------------------------------------------
+ * cdc struct|REF MAC ADDR|DUT_MAC_ADDR|un used|REF Channel|DUT channel|Action frame Data|
+ * 1---------17-----------23-------------------50----------51----------52----------------1040
+ * REF MAC addr after CDC struct without status flag (status flag not used by wifi)
+ */
+#define RWL_ACTION_WIFI_CATEGORY 127 /* Vendor Specific category value for wifi */
+#define RWL_REF_MAC_ADDRESS_OFFSET 17
+#define RWL_DUT_MAC_ADDRESS_OFFSET 23
+#define RWL_WIFI_CLIENT_CHANNEL_OFFSET 50
+#define RWL_WIFI_SERVER_CHANNEL_OFFSET 51
+
+#define SUCCESS 1
+#define FAIL -1
+#define NO_PACKET -2
+#define SERIAL_PORT_ERR -3
+
+#define DEFAULT_SERVER_PORT 8000
+
+#define WL_MAX_BUF_LEN (127 * 1024)
+#define MAX_VISTA_ARGC 10
+#define HOST_TO_NETWORK TRUE
+#define NETWORK_TO_HOST FALSE
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+#if defined(WIN32) || defined(LINUX)
+/* We don't want the server to allocate bigger buffers for some of the commands
+ * like scanresults. Server can still allocate 8K memory and send the response
+ * in fragments. This is used in case of Get commands only.
+ */
+#define SERVER_RESPONSE_MAX_BUF_LEN 8192
+#endif
+/* Used to set the cmds for wifi specific init */
+typedef struct remote_wifi_cmds {
+ uint32 cmd; /* common ioctl definition */
+ char *data; /* max size of the data length */
+ int value;
+} remote_wifi_cmds_t;
+
+/* Added for debug utility support */
+#define ERR stderr
+#define OUTPUT stdout
+
+#define DEBUG_DEFAULT 0x0001
+#define DEBUG_ERR 0x0001
+#define DEBUG_INFO 0x0002
+#define DEBUG_DBG 0x0004
+
+/* #ifdef TARGETOS_symbian */
+#define DPRINT_ERR if (defined_debug & DEBUG_ERR) \
+ fprintf
+#define DPRINT_INFO if (defined_debug & DEBUG_INFO) \
+ fprintf
+#define DPRINT_DBG if (defined_debug & DEBUG_DBG) \
+ fprintf
+extern unsigned short defined_debug;
+#ifdef WIN32
+/* Function defined in wlu.c for client and wlu_server_ce.c for server */
+extern int wl_atoip(const char *a, struct ipv4_addr *n);
+#endif
+/* Function defined to do host to network and network to host conversions */
+void rwl_swap_header(rem_ioctl_t *rem_ptr, bool host_to_network);
+
+/* Macros to access remote type */
+extern int remote_type;
+#define rwl_get_remote_type() (remote_type)
+#define rwl_set_remote_type(type) (remote_type = type)
+
+/* Macros to access server IP and port globals */
+extern char *g_rwl_servIP;
+#define rwl_get_server_ip() (g_rwl_servIP)
+#define rwl_set_server_ip(ip) (g_rwl_servIP = ip)
+extern unsigned short g_rwl_servport;
+#define rwl_get_server_port() (g_rwl_servport)
+#define rwl_set_server_port(port) (g_rwl_servport = port)
+
+extern int rwl_read_serial_port(void* hndle, char* read_buf, uint data_size, uint *numread);
+extern int rwl_write_serial_port(void* hndle, char* write_buf, unsigned long size,
+unsigned long *numwritten);
+extern void rwl_sleep(int delay);
+extern void* rwl_open_transport(int remote_type, char *port, int ReadTotalTimeout, int debug);
+extern int rwl_close_transport(int remote_type, void * handle);
+extern int rwl_poll_serial_buffer(void *hndle);
+extern int rwl_serial_handle_timeout(void);
+extern void rwl_sync_delay(uint noframes);
+
+#ifdef RWL_SOCKET
+extern int rwl_connectsocket(int SocketDes, struct sockaddr* SerAddr, int SizeOfAddr);
+extern int rwl_acceptconnection(int SocketDes, struct sockaddr *ClientAddr, int *SizeOfAddr);
+extern int rwl_send_to_streamsocket(int SocketDes, const char* SendBuff, int data_size, int Flag);
+extern int rwl_receive_from_streamsocket(int SocketDes, char* RecvBuff, int data_size, int Flag);
+extern int rwl_init_server_socket_setup(int argc, char** argv, uint remote_type);
+extern int rwl_GetifAddr(char *ifname, struct sockaddr_in* sa);
+#endif /* RWL_SOCKET */
+
+#if defined(LINUX)
+extern int set_interface(void *wl, char *intf_name);
+#endif /* defined(LINUX) */
+
+/* Win32 specific function wlu_pipe_win32.c */
+extern int rwl_init_ws2_32dll(void);
+extern int rwl_terminate_ws2_32dll(void);
+
+/* Function definitions for wlu_client_shared.c and wlu_server_shared.c */
+extern int rwl_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr);
+extern int rwl_var_setbuf(void *wl, const char *iovar, void *param, int param_len);
+extern int rwl_var_send_vs_actionframe(void* wl, const char* iovar, void* param, int param_len);
+
+/* Function definitions for wlu_ndis.c/wlu_linux.c and wlu_server_ce.c/wlu_server_linux.c */
+extern int wl_get(void *wl, int cmd, void *buf, int len);
+extern int wl_set(void *wl, int cmd, void *buf, int len);
+#ifdef RWLASD
+typedef unsigned char BYTE;
+extern void wfa_dut_init(BYTE **tBuf, BYTE **rBuf, BYTE **paBuf, BYTE **cBuf, struct timeval **);
+extern int remote_asd_exec(unsigned char* command, int* cmd_len);
+void wfa_dut_deinit(void);
+#endif
+extern int get_ctrlc_header(void *wl);
+extern int remote_tx_response(void *wl, void *buf_ptr, int cmd);
+extern rem_ioctl_t *g_rem_ptr;
+extern int g_rwl_hndle;
+#if defined(LINUX)
+/* Variable to indiate if the server child has completed execution */
+extern volatile sig_atomic_t g_sig_chld;
+#endif
+
+extern int rwl_check_port_number(char *s, int len);
+
+/*
+ * Separate paths are defined for android and linux machines
+ * / filesystem on android is read only memory
+ */
+#ifndef WIN32
+#ifdef TARGETENV_android
+#define SH_PATH "/data/busybox/sh"
+#define SHELL_RESP_PATH "/data/local/RWL/" /* Default path for storing files for shell response */
+#define TEMPLATE "/data/local/RWL/SyncXXXXXX"
+#else
+#define SHELL_RESP_PATH "/tmp/RWL/" /* Default path for storing files for shell response */
+#define TEMPLATE "/tmp/RWL/SyncXXXXXX"
+#define SH_PATH "/bin/sh"
+#endif
+#endif /* !WIN32 */
+#endif /* _wlu_remote_h */
diff --git a/wl/src/wl/exe/wlu_server_linux.c b/wl/src/wl/exe/wlu_server_linux.c
new file mode 100644
index 0000000..0163bf9
--- /dev/null
+++ b/wl/src/wl/exe/wlu_server_linux.c
@@ -0,0 +1,400 @@
+/*
+ * Wl server for linux
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_server_linux.c 659779 2016-09-15 23:33:28Z $
+ */
+
+/* Revision History:Linux port of Remote wl server
+ *
+ * Date Author Description
+ *
+ * 27-Dec-2007 Suganthi Version 0.1
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#ifndef TARGETENV_android
+#include <linux/types.h>
+#endif
+
+#include <linux/sockios.h>
+#include <linux/ethtool.h>
+
+#include <typedefs.h>
+#include <wlioctl.h>
+#include <dhdioctl.h>
+#include <proto/ethernet.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <bcmcdc.h>
+#include <proto/802.11.h>
+#include "wlu_remote.h"
+
+
+#define DEV_TYPE_LEN 3 /* length for devtype 'wl'/'et' */
+#define BUF_LENGTH 1000
+
+#define dtoh32(i) i
+
+
+#ifdef IL_BIGENDIAN
+bool swap = FALSE;
+#endif
+const char *rwl_server_name;
+void *g_wl_handle;
+unsigned short defined_debug = DEBUG_ERR | DEBUG_INFO;
+extern int remote_server_exec(int argc, char **argv, void *ifr);
+
+/* Global to have the PID of the current sync command
+ * This is required in case the sync command fails to respond,
+ * the alarm handler shall kill the PID upon a timeout
+ */
+int g_shellsync_pid;
+unsigned char g_return_stat = 0;
+
+static void
+syserr(char *s)
+{
+ fprintf(stderr, "%s: ", rwl_server_name);
+ perror(s);
+ exit(errno);
+}
+/* The handler for DHD commands */
+int
+dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set)
+{
+ struct ifreq *ifr = (struct ifreq *) dhd;
+ dhd_ioctl_t ioc;
+ int ret = 0;
+ int s;
+
+ /* open socket to kernel */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ syserr("socket");
+
+ /* do it */
+ ioc.cmd = cmd;
+ ioc.buf = buf;
+ ioc.len = len;
+ ioc.set = set;
+ ioc.driver = DHD_IOCTL_MAGIC;
+ ifr->ifr_data = (caddr_t) &ioc;
+ if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) {
+ if (cmd != DHD_GET_MAGIC) {
+ ret = BCME_IOCTL_ERROR;
+ }
+ }
+ /* cleanup */
+ close(s);
+ return ret;
+}
+
+int
+wl_ioctl(void *wl, int cmd, void *buf, int len, bool set)
+{
+ struct ifreq *ifr = (struct ifreq *) wl;
+ wl_ioctl_t ioc;
+ int ret = 0;
+ int s;
+
+ /* open socket to kernel */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ syserr("socket");
+
+ /* do it */
+ ioc.cmd = cmd;
+ ioc.buf = buf;
+ ioc.len = len;
+ ioc.set = set;
+ ifr->ifr_data = (caddr_t) &ioc;
+ if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) {
+ if (cmd != WLC_GET_MAGIC) {
+ ret = BCME_IOCTL_ERROR;
+ }
+ }
+ /* cleanup */
+ close(s);
+ return ret;
+}
+
+/* Functions copied from wlu.c to check for the driver adapter in the server machine */
+int
+wl_check(void *wl)
+{
+ int ret;
+ int val;
+
+ if ((ret = wl_ioctl(wl, WLC_GET_MAGIC, &val, sizeof(int), FALSE)) < 0)
+ return ret;
+#ifdef IL_BIGENDIAN
+ /* Detect if IOCTL swapping is necessary */
+ if (val == (int)bcmswap32(WLC_IOCTL_MAGIC))
+ {
+ val = bcmswap32(val);
+ swap = TRUE;
+ }
+#endif
+ if (val != WLC_IOCTL_MAGIC)
+ return -1;
+ if ((ret = wl_ioctl(wl, WLC_GET_VERSION, &val, sizeof(int), FALSE)) < 0)
+ return ret;
+ val = dtoh32(val);
+
+ if (val > WLC_IOCTL_VERSION) {
+ fprintf(stderr, "Version mismatch, please upgrade\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+wl_get_dev_type(char *name, void *buf, int len)
+{
+ int s;
+ int ret;
+ struct ifreq ifr;
+ struct ethtool_drvinfo info;
+
+ /* open socket to kernel */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ syserr("socket");
+
+ /* get device type */
+ memset(&info, 0, sizeof(info));
+ info.cmd = ETHTOOL_GDRVINFO;
+ ifr.ifr_data = (caddr_t)&info;
+ strncpy(ifr.ifr_name, name, IFNAMSIZ);
+ if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) {
+ /* print a good diagnostic if not superuser */
+ if (errno == EPERM)
+ syserr("wl_get_dev_type");
+ *(char *)buf = '\0';
+ } else {
+ strncpy(buf, info.driver, len);
+ }
+ close(s);
+ return ret;
+}
+
+static void
+wl_find_adapter(struct ifreq *ifr)
+{
+ char proc_net_dev[] = "/proc/net/dev";
+ FILE *fp;
+ char buf[BUF_LENGTH], *c, *name;
+ char dev_type[DEV_TYPE_LEN];
+
+ ifr->ifr_name[0] = '\0';
+
+ if (!(fp = fopen(proc_net_dev, "r")))
+ return;
+
+ /* eat first two lines */
+ if (!fgets(buf, sizeof(buf), fp) ||
+ !fgets(buf, sizeof(buf), fp)) {
+ fclose(fp);
+ return;
+ }
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ c = buf;
+ while (isspace(*c))
+ c++;
+ if (!(name = strsep(&c, ":")))
+ continue;
+ strncpy(ifr->ifr_name, name, IFNAMSIZ-1);
+ ifr->ifr_name[IFNAMSIZ-1] = 0;
+
+ /*
+ * If no -i interface, prioritize ethX, not say wl1.2
+ * wlanX is Android
+ */
+ if (!strncmp(name, "wl", 2) && strncmp(name, "wlan", 4)) {
+ continue;
+ }
+
+ if (wl_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 &&
+ !strncmp(dev_type, "wl", 2))
+ if (wl_check((void *) ifr) == 0)
+ break;
+ ifr->ifr_name[0] = '\0';
+ }
+
+ fclose(fp);
+}
+
+int
+wl_get(void *wl, int cmd, void *buf, int len)
+{
+ int error;
+
+ error = wl_ioctl(wl, cmd, buf, len, FALSE);
+
+ return error;
+}
+
+int
+wl_set(void *wl, int cmd, void *buf, int len)
+{
+ int error;
+
+ error = wl_ioctl(wl, cmd, buf, len, TRUE);
+
+ return error;
+}
+
+extern int set_ctrlc;
+void handle_ctrlc(int unused)
+{
+ UNUSED_PARAMETER(unused);
+ set_ctrlc = 1;
+ return;
+}
+
+volatile sig_atomic_t g_sig_chld = 1;
+void rwl_chld_handler(int num)
+{
+ int child_status;
+
+ UNUSED_PARAMETER(num);
+ /* g_return_stat is being set with the return status of sh commands */
+ waitpid(g_shellsync_pid, &child_status, WNOHANG);
+ if (WIFEXITED(child_status))
+ g_return_stat = WEXITSTATUS(child_status);
+ else if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG)
+ g_return_stat = 0;
+ else
+ g_return_stat = 1;
+ g_sig_chld = 0;
+}
+
+/* Alarm handler called after SHELL_TIMEOUT value
+ * This handler kills the non-responsive shell process
+ * with the PID value g_shellsync_pid
+ */
+static void
+sigalrm_handler(int s)
+{
+ UNUSED_PARAMETER(s);
+
+ if (g_shellsync_pid) {
+ kill(g_shellsync_pid, SIGINT);
+ }
+#ifdef RWL_SOCKET
+ g_sig_chld = 0;
+#endif
+}
+
+static void
+def_handler(int s)
+{
+ UNUSED_PARAMETER(s);
+ kill(g_shellsync_pid, SIGKILL);
+ exit(0);
+}
+
+static void
+pipe_handler(int s)
+{
+ UNUSED_PARAMETER(s);
+ kill(g_shellsync_pid, SIGKILL);
+}
+
+int
+main(int argc, char **argv)
+{
+ int err = 0;
+ struct ifreq *ifr;
+
+ rwl_server_name = argv[0];
+
+ if ((ifr = calloc(1, sizeof(*ifr))) == NULL)
+ {
+ DPRINT_ERR(ERR, "wl_server: Unable to allocate memory for handle\n");
+ exit(1);
+ }
+
+ memset(ifr, 0, sizeof(*ifr));
+#ifdef PCIE_MFGTEST
+ /* For router platform hardcode to eth1 */
+ strcpy(ifr->ifr_name, "eth1");
+#endif /* PCIE_MFGTEST */
+
+ /* use default interface */
+ if (!ifr->ifr_name[0])
+ wl_find_adapter(ifr);
+ /* validate the interface */
+ if (!ifr->ifr_name[0] || wl_check((void *)ifr)) {
+ DPRINT_INFO(OUTPUT, "wl_server: wl driver adapter not found\n");
+ }
+ g_wl_handle = ifr;
+
+ /* Register signal handlers */
+ signal(SIGCHLD, rwl_chld_handler);
+ signal(SIGALRM, sigalrm_handler);
+ signal(SIGTERM, def_handler);
+ signal(SIGPIPE, pipe_handler);
+ signal(SIGABRT, def_handler);
+#ifdef RWL_DONGLE
+ signal(SIGINT, handle_ctrlc);
+#endif
+ /* Main server process for all transport types */
+ err = remote_server_exec(argc, argv, ifr);
+ free(ifr);
+ return err;
+}
+
+/*
+ * Funtion to store old interface.
+ */
+void
+store_old_interface(void *wl, char *old_intf_name)
+{
+ strcpy(old_intf_name, ((struct ifreq *)wl)->ifr_name);
+}
+
+/*
+ * Function to set interface.
+ */
+int
+set_interface(void *wl, char *intf_name)
+{
+ struct ifreq *ifr = (struct ifreq *)wl;
+
+ if (strlen(intf_name) != 0) {
+ strncpy(ifr->ifr_name, intf_name, strlen(intf_name) + 1);
+ return BCME_OK;
+ }
+ else {
+ DPRINT_DBG(OUTPUT, "Default Interface will be used ... \n");
+ return BCME_ERROR;
+ }
+}
diff --git a/wl/src/wl/exe/wlu_server_shared.c b/wl/src/wl/exe/wlu_server_shared.c
new file mode 100644
index 0000000..9fdcb7d
--- /dev/null
+++ b/wl/src/wl/exe/wlu_server_shared.c
@@ -0,0 +1,1177 @@
+/*
+ * File Name: wlu_server_shared.c
+ * Common server specific functions for linux and win32
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_server_shared.c 570087 2015-07-09 22:10:06Z $
+ */
+
+/*
+ * Description: Main Server specific wrappers
+ * This module implements all the server specific functions
+ * for Win32 and Linux
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef TARGETOS_symbian
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+
+#else
+#if !defined(TARGETOS_nucleus)
+#include <malloc.h>
+#endif
+#endif /* TARGETOS_symbian */
+#include <assert.h>
+
+#include <errno.h>
+#ifndef WIN32
+#if !defined(TARGETOS_nucleus)
+#include <sys/types.h>
+#include <sys/socket.h>
+#if !defined(TARGETOS_symbian)
+#include <arpa/inet.h>
+#include <net/if.h>
+#endif
+#include <unistd.h>
+#include <netdb.h>
+#include <signal.h>
+#endif /* TARGETOS_nucleus */
+#endif /* WIN32 */
+
+#ifdef WIN32
+#include <windows.h>
+#include <winioctl.h>
+#include <ntddndis.h>
+#include <typedefs.h>
+#include <epictrl.h>
+#include <irelay.h>
+#include <proto/ethernet.h>
+#include <nuiouser.h>
+#include <bcmendian.h>
+#include <oidencap.h>
+#include <bcmutils.h>
+#include <proto/802.11.h>
+#endif /* WIN32 */
+
+#include <bcmcdc.h>
+#include <wlioctl.h>
+#include <typedefs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR)
+#include <rwl_wifi.h>
+#endif /* defined(RWL_WIFI) || defined(WIFI_REFLECTOR) */
+#include "wlu.h"
+#include "wlu_remote.h"
+#include "wlu_pipe.h"
+#include "wlu_server_shared.h"
+#ifdef RWLASD
+extern int g_serv_sock_desc;
+#endif
+int g_rwl_hndle;
+int set_ctrlc = 0;
+
+#ifdef RWL_DONGLE
+static rem_ioctl_t loc_cdc;
+static const char* cmdname = "remote";
+static const char* dongleset = "dongleset";
+#endif
+
+#if defined(LINUX)
+extern void store_old_interface(void *wl, char *old_intf_name);
+extern int wl_check(void *wl);
+#endif /* defined(LINUX) */
+
+extern void handle_ctrlc(int unused);
+/* Function: rwl_transport_setup
+ * This will do the initialization for
+ * for all the transports
+ */
+static int
+rwl_transport_setup(int argc, char** argv)
+{
+ int transport_descriptor = -1;
+
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(argv);
+
+#ifdef RWL_SOCKET
+ /* This function will parse the socket command line arguments
+ * & open the socket in listen mode
+ */
+ remote_type = REMOTE_SOCKET;
+ transport_descriptor = rwl_init_server_socket_setup(argc, argv, remote_type);
+
+ if (transport_descriptor < 0) {
+ DPRINT_ERR(ERR, "wl_socket_server:Transport setup failed \n");
+ }
+#endif /* RWL_SOCKET */
+#if defined(RWL_DONGLE) || defined(RWL_WIFI) || defined(RWL_SERIAL)
+ g_rem_pkt_ptr = &g_rem_pkt;
+ transport_descriptor = 0;
+
+#ifdef RWL_WIFI
+ remote_type = REMOTE_WIFI;
+#endif
+
+#ifdef RWL_DONGLE
+ remote_type = REMOTE_DONGLE;
+#endif /* RWL_DONGLE */
+#ifdef RWL_SERIAL
+ remote_type = REMOTE_SERIAL;
+ if (argc < 2) {
+ DPRINT_ERR(ERR, "Port name is required from the command line\n");
+ } else {
+ (void)*argv++;
+ DPRINT_DBG(OUTPUT, "Port name is %s\n", *argv);
+ transport_descriptor = *(int*) rwl_open_transport(remote_type, *argv, 0, 0);
+ }
+#endif /* RWL_SERIAL */
+#endif /* RWL_DONGLE ||RWL_SERIAL ||RWL_WIFI */
+#ifdef RWLASD
+ g_serv_sock_desc = transport_descriptor;
+#endif
+ return transport_descriptor;
+
+}
+
+/* Function: remote_rx_header
+ * This function will receive the CDC header from client
+ * for socket transport
+ * It will receive the command or ioctl from dongle driver for
+ * dongle UART serial transport and wifi transport.
+ * Arguments: wl - handle to driver
+ * : Des - Socket Descriptor to pass in AcceptConnection
+ * : g_rwl_hndle - Return socket handle that is used for transmission
+ * : and reception of data in case of socket
+ * In case of serial, it is just a return value
+ */
+static int
+remote_rx_header(void *wl, int trans_Des)
+{
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(trans_Des);
+
+#ifdef RWL_SOCKET
+ {
+ struct sockaddr_in ClientAddress;
+ int SizeOfCliAdd = sizeof(ClientAddress);
+
+ /* Get the socket handle g_rwl_hndle for transmission & reception */
+ if ((g_rwl_hndle = rwl_acceptconnection(trans_Des,
+ (struct sockaddr *)&ClientAddress,
+ &SizeOfCliAdd)) == BCME_ERROR) {
+ return BCME_ERROR;
+ }
+
+ /* Get CDC header in order to determine buffer requirements */
+ if ((g_rem_ptr = remote_CDC_rx_hdr((void *)&g_rwl_hndle, 0)) == NULL) {
+ DPRINT_DBG(OUTPUT, "\n Waiting for client to transmit command\n");
+ return BCME_ERROR;
+ }
+ }
+#endif /* RWL_SOCKET */
+
+#ifdef RWL_DONGLE
+ {
+ void *pkt_ptr = NULL;
+ int error;
+
+ /* wl driver is polled after every 200 ms (POLLING_TIME) */
+ rwl_sleep(POLLING_TIME);
+
+ if ((error = rwl_var_getbuf(wl, cmdname, NULL, 0, &pkt_ptr)) < 0) {
+ DPRINT_ERR(ERR, "No packet in wl driver\r\n");
+ return BCME_ERROR;
+ }
+
+ DPRINT_DBG(OUTPUT, "Polling the wl driver, error status=%d\n", error);
+
+ if ((*(int *)pkt_ptr) == 0) {
+ DPRINT_DBG(ERR, "packet not received\n");
+ return BCME_ERROR;
+ }
+
+ DPRINT_DBG(OUTPUT, "packet received\n");
+
+ /* Extract CDC header in order to determine buffer requirements */
+ memcpy(g_rem_pkt_ptr, pkt_ptr, sizeof(rem_packet_t));
+ g_rem_ptr = &g_rem_pkt_ptr->rem_cdc;
+ }
+#endif /* RWL_DONGLE */
+
+#ifdef RWL_SERIAL
+ {
+ if (g_rwl_hndle == -1) {
+ DPRINT_ERR(ERR, "failed to open com port.\r\n");
+ return BCME_ERROR;
+ }
+
+ if ((g_rem_ptr = remote_CDC_rx_hdr((void *)&g_rwl_hndle, 1)) == NULL) {
+ DPRINT_DBG(OUTPUT, "\n Waiting for client to transmit command\n");
+ return BCME_ERROR;
+ }
+ }
+#endif /* RWL_SERIAL */
+
+#ifdef RWL_WIFI
+ {
+ /* Poll the driver for the valid action frame and update the CDC + data */
+ dot11_action_wifi_vendor_specific_t *list;
+ size_t cdc_and_actionframe_copy_length;
+
+ if ((list = rwl_wifi_allocate_actionframe()) == NULL) {
+ DPRINT_DBG(OUTPUT, "remote_rx_header: Failed to allocate frame \n");
+ return BCME_ERROR;
+ }
+
+ if (remote_CDC_DATA_wifi_rx((void *)wl, list) < 0) {
+ free(list);
+ return BCME_ERROR;
+ }
+
+ /* copy the valid length of the data to the g_rem_pkt_ptr */
+ cdc_and_actionframe_copy_length = sizeof(rem_packet_t) > sizeof(list->data[0])?
+ sizeof(list->data[0]): sizeof(rem_packet_t);
+ memcpy(g_rem_pkt_ptr, &list->data[0], cdc_and_actionframe_copy_length);
+ g_rem_ptr = &g_rem_pkt_ptr->rem_cdc;
+ free(list);
+ }
+#endif /* RWL_WIFI */
+
+ rwl_swap_header(g_rem_ptr, NETWORK_TO_HOST);
+
+ DPRINT_INFO(OUTPUT, "%d %d %d %d\r\n", g_rem_ptr->msg.cmd,
+ g_rem_ptr->msg.len, g_rem_ptr->msg.flags, g_rem_ptr->data_len);
+
+ return SUCCESS;
+
+}
+
+/* Function: remote_rx_data
+ * This function will receive the data from client
+ * for different transports
+ * In case of socket the data comes from a open TCP socket
+ * However in case of dongle UART or wi-fi the data is accessed
+ * from the driver buffers.
+ */
+int
+remote_rx_data(void* buf_ptr)
+{
+#if defined(RWL_SOCKET) || defined(RWL_SERIAL)
+
+ if ((remote_CDC_rx((void *)&g_rwl_hndle, g_rem_ptr, buf_ptr,
+ g_rem_ptr->msg.len, 0)) == BCME_ERROR) {
+ DPRINT_ERR(ERR, "Reading CDC %d data bytes failed\n", g_rem_ptr->msg.len);
+ return BCME_ERROR;
+ }
+#elif defined(RWL_DONGLE) || defined(RWL_WIFI)
+ if (g_rem_ptr->data_len != 0) {
+ int length = g_rem_ptr->data_len;
+ if (g_rem_ptr->data_len > g_rem_ptr->msg.len) {
+ length = g_rem_ptr->msg.len;
+ }
+ memcpy(buf_ptr, g_rem_pkt_ptr->message, length);
+ }
+ else
+ buf_ptr = NULL;
+#else
+ UNUSED_PARAMETER(buf_ptr);
+#endif /* RWL_SOCKET || RWL_SERIAL */
+ return SUCCESS;
+}
+
+#ifdef RWL_DONGLE
+/*
+ * Function to send the serial response to wl driver
+ * The function calculates the no of frames based on the DATA_FRAME_LEN
+ * adds cdc header to every frame, copies the header and fragmented frame
+ * into rem_buf_ptr and sends the packet down to wl driver
+ */
+
+static int
+rwl_serial_fragmented_tx(void* wl, rem_ioctl_t *rem_ptr, uchar *buf_ptr, int error)
+{
+ rem_ioctl_t *loc_ptr = &loc_cdc;
+ uchar* rem_buf_ptr;
+ uint noframes = 1; /* Default noframes = 1 */
+ uint count;
+ uint frame_count;
+ uint rem_bytes;
+
+ loc_ptr->msg.cmd = error;
+ loc_ptr->msg.flags = REMOTE_REPLY;
+ loc_ptr->msg.len = rem_ptr->msg.len;
+ loc_ptr->data_len = rem_ptr->data_len;
+
+ /* Fragment the result if it is more than DATA_FRAME_LEN (960) */
+ if (loc_ptr->msg.len > DATA_FRAME_LEN) {
+ /* Calculate no of frames */
+ noframes = (loc_ptr->msg.len)/DATA_FRAME_LEN;
+ if ((loc_ptr->msg.len) % DATA_FRAME_LEN > 0) {
+ noframes += 1;
+ rem_bytes = (loc_ptr->msg.len) % DATA_FRAME_LEN;
+ } else {
+ rem_bytes = DATA_FRAME_LEN;
+ }
+ } else {
+ rem_bytes = loc_ptr->msg.len;
+ }
+ DPRINT_INFO(OUTPUT, "No of frames = %d, rem_bytes:%d\n", noframes, rem_bytes);
+ count = 0;
+ frame_count = noframes;
+ rem_buf_ptr = (uchar*)malloc(DONGLE_TX_FRAME_SIZE + REMOTE_SIZE);
+
+ while (count < noframes) {
+ memset(rem_buf_ptr, 0, DONGLE_TX_FRAME_SIZE + REMOTE_SIZE);
+ /* Send reply to client */
+ rem_ptr->msg.cmd = loc_ptr->msg.cmd;
+ rem_ptr->msg.flags = loc_ptr->msg.flags;
+ rem_ptr->msg.len = loc_ptr->msg.len;
+
+ if (frame_count == 1)
+ rem_ptr->data_len = rem_bytes;
+ else
+ rem_ptr->data_len = DATA_FRAME_LEN;
+
+ DPRINT_DBG(OUTPUT, "GET--rem_ptr->data_len=%d\n", rem_ptr->data_len);
+
+ /* Copy CDC Header */
+ memcpy(rem_buf_ptr, (uchar*)rem_ptr, REMOTE_SIZE);
+
+ /* Copy Data now */
+ memcpy(&rem_buf_ptr[REMOTE_SIZE], &buf_ptr[count*DATA_FRAME_LEN],
+ rem_ptr->data_len);
+ count++;
+ frame_count--;
+
+ DPRINT_INFO(OUTPUT, "FRAME %d\n", count);
+ DPRINT_INFO(OUTPUT, "%d %d %d %d\n", rem_ptr->msg.cmd, rem_ptr->msg.len,
+ rem_ptr->msg.flags, rem_ptr->data_len);
+
+ rwl_sync_delay(noframes);
+
+ if ((error = rwl_var_setbuf(wl, cmdname, rem_buf_ptr,
+ DONGLE_TX_FRAME_SIZE+REMOTE_SIZE)) < 0) {
+ DPRINT_INFO(OUTPUT, "Unable to send to wl driver,error=%d\n", error);
+ if (rem_buf_ptr)
+ free(rem_buf_ptr);
+ return BCME_ERROR;
+ }
+ else
+ DPRINT_INFO(OUTPUT, "Packet sent to wl driver,error=%d\n", error);
+ }
+
+ if (rem_buf_ptr)
+ free(rem_buf_ptr);
+
+ return error;
+}
+
+/* This function transmits the response to the dongle driver in the case
+ * of serial dongle transport.
+ * In the case of big response, it calls the rwl_serial_fragmented_response
+ * function to fragment the response and sends down to the driver.
+ */
+
+static int
+remote_CDC_dongle_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags)
+{
+ int error;
+ rem_ioctl_t resp_rem_cdc;
+
+ if (flags & REMOTE_SET_IOCTL) {
+ uchar* rem_buf_ptr;
+ /* for set commands message length and data length should be set to zero
+ * unlike Get Ioctl which will have valid data and message length
+ */
+ resp_rem_cdc.msg.len = 0;
+ resp_rem_cdc.data_len = 0;
+ resp_rem_cdc.msg.cmd = cmd;
+ resp_rem_cdc.msg.flags = REMOTE_REPLY;
+
+ DPRINT_INFO(OUTPUT, "Set:Resp packet:%d %d %d %d\n", resp_rem_cdc.msg.cmd,
+ resp_rem_cdc.msg.len, resp_rem_cdc.msg.flags, resp_rem_cdc.data_len);
+
+ if ((rem_buf_ptr = (uchar*)malloc(DONGLE_TX_FRAME_SIZE + REMOTE_SIZE)) == NULL) {
+ DPRINT_ERR(ERR, "malloc failed for remote_CDC_dongle_tx\n");
+ return BCME_ERROR;
+ }
+
+ /* Send reply to client here */
+ memcpy(rem_buf_ptr, (char*)(&resp_rem_cdc), REMOTE_SIZE);
+ if ((error = rwl_var_setbuf((void*)wl, cmdname, rem_buf_ptr,
+ DONGLE_TX_FRAME_SIZE + REMOTE_SIZE)) < 0) {
+ DPRINT_ERR(ERR, "unable to send SET results to driver=%d\n", error);
+ } else
+ DPRINT_INFO(OUTPUT, "Packet sent to wl driver, error=%d\n", error);
+
+ if (rem_buf_ptr)
+ free(rem_buf_ptr);
+
+ } else { /* GET_IOCTL */
+ resp_rem_cdc.msg.cmd = cmd;
+ resp_rem_cdc.msg.len = buf_len;
+ resp_rem_cdc.msg.flags = flags;
+ resp_rem_cdc.data_len = data_len;
+ if ((error = rwl_serial_fragmented_tx(wl, &resp_rem_cdc, buf, cmd)) < 0)
+ DPRINT_ERR(ERR, "wl_server_serial: Return error code failed\n");
+ }
+ return error;
+}
+#endif /* RWL_DONGLE */
+
+/* This function gets the command send by the client from the dongle driver */
+int
+rwl_var_getbuf(void* wl, const char* iovar, void* param, int param_len, void** buf_ptr)
+{
+ int len;
+
+ memset(rwl_buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy((char*)rwl_buf, iovar);
+ /* include the null */
+ len = strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy(&rwl_buf[len], param, param_len);
+
+ *buf_ptr = rwl_buf;
+
+ return wl_get(wl, WLC_GET_VAR, &rwl_buf[0], WLC_IOCTL_MAXLEN);
+}
+
+/* This function will send the buffer to the dongle driver */
+int
+rwl_var_setbuf(void* wl, const char* iovar, void* param, int param_len)
+{
+ int len;
+
+ memset(rwl_buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy((char*)rwl_buf, iovar);
+
+ /* include the null */
+ len = strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy(&rwl_buf[len], param, param_len);
+
+ len += param_len;
+
+ DPRINT_DBG(OUTPUT, "setbuf:%s, len:%d\n", rwl_buf, len);
+
+ return wl_set(wl, WLC_SET_VAR, &rwl_buf[0], len);
+}
+
+/* This function will send the buffer to the dongle driver */
+int
+rwl_var_send_vs_actionframe(void* wl, const char* iovar, void* param, int param_len)
+{
+ int len;
+
+ memset(rwl_buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy((char*) rwl_buf, iovar);
+
+ /* include the null */
+ len = strlen(iovar) + 1;
+
+ if (param_len)
+ memcpy((void*)&rwl_buf[len+ OFFSETOF(wl_action_frame_t, data)], param, param_len);
+
+ /* Set the PacketID (not used by remote WL */
+ memset((void*)&rwl_buf[len + OFFSETOF(wl_action_frame_t, packetId)], 0, 4);
+
+ /* Set the dest addr */
+ memcpy((void*)&rwl_buf[len + OFFSETOF(wl_action_frame_t, da)],
+ (void*)&rwlea,
+ ETHER_ADDR_LEN);
+
+ /* set the length */
+ memcpy((void*)&rwl_buf[len + OFFSETOF(wl_action_frame_t, len)], (void*) ¶m_len, 2);
+
+ len += param_len + ETHER_ADDR_LEN + 2 + 4;
+
+ DPRINT_DBG(OUTPUT, "setbuf:%s, len:%d\n", rwl_buf, len);
+
+ return wl_set(wl, WLC_SET_VAR, &rwl_buf[0], len);
+}
+/*
+ * This function is used for transmitting the response over different
+ * transports.
+ * In case of socket the data is directly sent to the client which is waiting on a open socket.
+ * In case of socket the data is sent in one big chunk unlike other transports
+ *
+ * In case of serial the data is sent to the driver using remote_CDC_dongle_tx function
+ * which in turn may fragment the data and send it in chunks to the client.
+ *
+ * In case of wi-fi the data is sent to the driver using the remote_CDC_tx. However
+ * in this case the data is converted into 802.11 Action frames and sent using wi-fi driver.
+ * Arguments: wl - Driver handle
+ * hndle - Socket handle for socket transport.
+ */
+int
+remote_tx_response(void *wl, void* buf_ptr, int cmd)
+{
+ int error = -1;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(buf_ptr);
+ UNUSED_PARAMETER(cmd);
+
+#if defined(RWL_SOCKET) || defined(RWL_SERIAL)
+ if ((error = remote_CDC_tx((void*)&g_rwl_hndle, cmd, buf_ptr, g_rem_ptr->msg.len,
+ g_rem_ptr->msg.len, REMOTE_REPLY, 0)) < 0)
+ DPRINT_ERR(ERR, "wl_server: Return results failed\n");
+#endif /* RWL_SOCKET || RWL_SERIAL */
+
+#ifdef RWL_DONGLE
+ if ((error = remote_CDC_dongle_tx(wl, cmd, buf_ptr, g_rem_ptr->msg.len,
+ g_rem_ptr->data_len, g_rem_ptr->msg.flags)) < 0)
+ DPRINT_ERR(ERR, "wl_server: Return results failed\n");
+#endif /* RWL_DONGLE */
+
+#ifdef RWL_WIFI
+ /* Purge all the queued cmd's , this to ensure late response time out at */
+ /* client side and client might issue the next cmd if server is slow */
+ if ((error = rwl_wifi_purge_actionframes(wl)) < 0)
+ return error;
+ if ((g_rem_ptr->msg.flags & REMOTE_SHELL_CMD) ||
+ (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL)||
+ (g_rem_ptr->msg.flags & REMOTE_ASD_CMD) ||
+ (g_rem_ptr->msg.flags & REMOTE_VISTA_CMD)) {
+ if ((error = remote_CDC_tx(wl, cmd, buf_ptr, g_rem_ptr->msg.len,
+ g_rem_ptr->msg.len, REMOTE_REPLY, 0)) < 0)
+ DPRINT_ERR(ERR, "Wifi_server: Return results failed\n");
+ } else {
+ if ((error = remote_CDC_tx(wl, cmd, buf_ptr, 0, 0, REMOTE_REPLY, 0)) < 0)
+ DPRINT_ERR(ERR, "Failed due to bad flag %d\n", g_rem_ptr->msg.flags);
+ }
+#endif /* RWL_WIFI */
+ return error;
+}
+
+/* Close the Socket handle */
+void close_sock_handle(int hndle)
+{
+#ifdef RWL_SOCKET
+ rwl_close_pipe(remote_type, (void*)&hndle);
+#else
+ UNUSED_PARAMETER(hndle);
+#endif
+}
+
+
+/*
+ * Send the response to the remote if the channel of the server matches with the
+ * server channel.
+ */
+void remote_wifi_response(void* wl)
+{
+#ifdef RWL_WIFI
+ dot11_action_wifi_vendor_specific_t *list;
+
+ if ((list = rwl_wifi_allocate_actionframe()) == NULL) {
+ DPRINT_DBG(OUTPUT, "remote_wifi_response: Failed to allocate frame \n");
+ return;
+ }
+
+ /* it's sync frame and received from client */
+ memcpy((char*)&list->data[RWL_WIFI_CDC_HEADER_OFFSET],
+ &g_rem_pkt_ptr[RWL_WIFI_CDC_HEADER_OFFSET], REMOTE_SIZE);
+ memcpy((char*)&list->data[REMOTE_SIZE], g_rem_pkt_ptr->message,
+ RWL_WIFI_FRAG_DATA_SIZE);
+ list->type = RWL_WIFI_FIND_MY_PEER;
+ /* Store the client mac addr */
+ memcpy((void*)&rwlea, (void*)&list->data[RWL_DUT_MAC_ADDRESS_OFFSET], ETHER_ADDR_LEN);
+ /* send the response to client if server is on the same channel */
+ rwl_wifi_find_server_response(wl, list);
+
+ free(list);
+#else
+ UNUSED_PARAMETER(wl);
+#endif /* RWL_WIFI */
+ return;
+}
+
+/* Function to check IN-dongle mode firmware */
+int
+rwl_iovar_check(void *wl)
+{
+ void *ptr;
+#ifdef RWL_WIFI
+ dot11_action_wifi_vendor_specific_t rec_frame;
+
+ /* Check for indongle mode firmware */
+ return rwl_var_getbuf(wl, RWL_WIFI_GET_ACTION_CMD, &rec_frame,
+ RWL_WIFI_ACTION_FRAME_SIZE, &ptr);
+#endif
+ UNUSED_PARAMETER(ptr);
+ UNUSED_PARAMETER(wl);
+#ifdef RWL_DONGLE
+ return rwl_var_getbuf(wl, "remote", NULL, 0, &ptr);
+#else
+ return 0;
+#endif
+}
+
+
+#ifndef TARGETOS_symbian
+/* Function to get a ctrl-c packet */
+int
+get_ctrlc_header(void *wl)
+{
+#if defined(RWL_SOCKET) || defined(RWL_SERIAL)
+ fd_set fdset;
+ struct timeval tv;
+ UNUSED_PARAMETER(wl);
+ FD_ZERO(&fdset);
+ FD_SET((unsigned)g_rwl_hndle, &fdset);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ if ((select(g_rwl_hndle+1, &fdset, NULL, NULL, &tv)) > 0) {
+ if (FD_ISSET(g_rwl_hndle, &fdset)) {
+ remote_CDC_rx_hdr((void *)&g_rwl_hndle, 0);
+ return BCME_OK;
+ }
+ }
+ return BCME_ERROR;
+
+#else
+ return remote_rx_header(wl, 0);
+#endif /* if defined(RWL_SOCKET) || defined(RWL_SERIAL) */
+}
+#endif /* TARGETOS_symbian */
+
+/* Main server module common for all transports
+ * This module will do the initial transport setups.
+ * Then it receives the command from client in CDC format
+ * and transmits the response back to the client.
+ * In the case of socket, it receives the command from the client
+ * and sends the response directly to the client via TCP socket.
+ *
+ * In the case of serial & wifi , it receives the command from the driver
+ * and sends the response to the driver.
+ */
+#if defined(PCIE_MFGTEST)
+ char *fw_download_path = "/tmp/media/nand/rtecdc.bin";
+ char *nvram_download_path = "/tmp/media/nand/nvram.txt";
+#endif
+int
+remote_server_exec(int argc, char **argv, void *wl)
+{
+ int err;
+ int transport_descriptor;
+ char *async_cmd_flag = NULL;
+ int skip;
+ int download_flag = 0;
+ FILE *fp = NULL;
+#if defined(PCIE_MFGTEST)
+ char *fn = fw_download_path;
+ char *fw = nvram_download_path;
+#else
+ char *fn = "dwnldfile.bin";
+ char *fw = "nvram.txt";
+#endif
+
+#if defined(LINUX) || defined(OLYMPIC_RWL)
+ char old_intf_name[IFNAMSIZ];
+#endif
+#ifdef WIN32
+ char shell_fname[MAX_SHELL_FILE_LENGTH];
+ DWORD dwlen;
+#endif
+#ifdef RWL_DONGLE
+ int uart_enable = 1;
+ /* To set dongle flag when dongle server starts */
+ if ((err = rwl_var_setbuf(wl, dongleset, &uart_enable,
+ sizeof(int))) < 0) {
+ DPRINT_INFO(OUTPUT, "Unable to send to wl driver,error=%d\n", err);
+ }
+#endif
+ if (rwl_iovar_check (wl) < 0) {
+ DPRINT_ERR(ERR, "wl_server: RWL_WIFI/RWL_DONGLE not defined ");
+ DPRINT_ERR(ERR, "Or In-Dongle mode enabled\n");
+ exit(0);
+ }
+ /* Initialise for all the transports - socket, serial, and wifi
+ * In Socket transport, main socket handler will be returned.
+ */
+ if ((transport_descriptor = rwl_transport_setup(argc, argv)) < 0)
+ return BCME_ERROR;
+
+#ifdef RWL_WIFI
+ remote_wifi_ser_init_cmds(wl);
+#endif
+ /* Create a directory /tmp/RWL for the shell response files */
+ if (rwl_create_dir() < 0)
+ return BCME_ERROR;
+
+
+#ifdef RWLASD
+ /* DUT initialization function */
+ wfa_dut_init(&trafficBuf, &respBuf, &parmsVal, &xcCmdBuf, &toutvalp);
+#endif
+
+#if defined(LINUX)
+ /* Copy old interface name to restore it */
+ store_old_interface(wl, old_intf_name);
+#endif /* defined(LINUX) */
+
+ while (1) {
+ uchar *buf_ptr = NULL;
+#if defined(LINUX)
+ char *errstr = NULL;
+#endif
+#ifdef VISTA_SERVER
+ int index;
+ char *vista_buf[MAX_VISTA_ARGC];
+#endif
+#ifdef RWL_SERIAL
+ g_rwl_hndle = transport_descriptor;
+#else
+ g_rwl_hndle = -1;
+#endif
+#ifdef RWL_DONGLE
+ if (set_ctrlc) {
+ uart_enable = 0;
+ if ((err = rwl_var_setbuf(wl, dongleset, &uart_enable,
+ sizeof(int))) < 0) {
+ DPRINT_INFO(OUTPUT, "Unable to send to wl driver,error=%d\n", err);
+ }
+ set_ctrlc = 0;
+ exit(0);
+ }
+#endif /* RWL_DONGLE */
+
+ /* Receive the CDC header */
+ if ((remote_rx_header(wl, transport_descriptor)) == BCME_ERROR) {
+ DPRINT_DBG(OUTPUT, "\n Waiting for client to transmit command\n");
+ continue;
+ }
+
+ DPRINT_INFO(OUTPUT, "REC : cmd %d\t msg len %d msg flag %d\t msg status %d\n",
+ g_rem_ptr->msg.cmd, g_rem_ptr->msg.len,
+ g_rem_ptr->msg.flags, g_rem_ptr->msg.status);
+
+#ifdef RWL_WIFI
+ /* send the response to remote if it is findserver cmd, this is specific to wifi */
+ if (g_rem_ptr->msg.flags & REMOTE_FINDSERVER_IOCTL) {
+ remote_wifi_response(wl);
+ continue;
+ }
+#endif /* RWL_WIFI */
+
+ /*
+ * Allocate buffer only if there is a response message expected.
+ * Some commands such as up/down do not output anything.
+ */
+ if (g_rem_ptr->msg.len) {
+ if ((buf_ptr = malloc(g_rem_ptr->msg.len)) == NULL) {
+ DPRINT_ERR(ERR, "malloc of %d bytes failed\n", g_rem_ptr->msg.len);
+ continue;
+ }
+ }
+
+ /* Receive the data */
+ if ((err = remote_rx_data(buf_ptr)) == BCME_ERROR) {
+ if (buf_ptr)
+ free(buf_ptr);
+ continue;
+ }
+
+ /* Process RWL negotiate commands */
+ if (g_rem_ptr->msg.flags & REMOTE_NEGOTIATE_CMD) {
+ if (g_rem_ptr->msg.cmd == NEGOTIATE_GET_OS) {
+ if (g_rem_ptr->msg.len >= sizeof(int)) {
+#if defined(LINUX)
+ *(int*)buf_ptr = LINUX_OS;
+#elif defined(VISTA_SERVER)
+ *(int*)buf_ptr = WINVISTA_OS;
+#elif defined(WIN32)
+ *(int*)buf_ptr = WIN32_OS;
+#else
+ *(int*)buf_ptr = UNKNOWN_OS;
+#endif
+ g_rem_ptr->msg.len = sizeof(int);
+
+ DPRINT_INFO(OUTPUT, "RESP : os type %d\n", *(int*)buf_ptr);
+ if (remote_tx_response(wl, buf_ptr, 0) < 0)
+ DPRINT_ERR(ERR, "\nReturn results failed\n");
+ }
+ }
+#ifdef RWL_SOCKET
+ close_sock_handle(g_rwl_hndle);
+#endif /* RWL_SOCKET */
+ if (buf_ptr)
+ free(buf_ptr);
+ continue;
+ }
+
+ /* Process command */
+ if (g_rem_ptr->msg.flags & REMOTE_SHELL_CMD) {
+ /* Get the response length first and get the response buffer in case of
+ * synchronous shell commands and the buf_ptr will have the response file
+ * name. In case of asynchronous shell commands, buf_ptr
+ * will be get updated by the remote_shell_execute function.
+ */
+ need_speedy_response = 1;
+#ifndef WIN32
+ if (buf_ptr) {
+ async_cmd_flag = strstr((char*)buf_ptr, "%");
+ }
+ if ((err = remote_shell_execute((char*)buf_ptr, wl)) > 0) {
+ if (async_cmd_flag)
+ g_rem_ptr->msg.len = err;
+ }
+ /* Sync shell command: No need to send response from here */
+ else {
+#ifdef RWL_SOCKET
+ /* Transmitted to client. Then close the handle &
+ * get the new handle for next transmission & reception.
+ */
+ close_sock_handle(g_rwl_hndle);
+#endif /* RWL_SOCKET */
+ continue;
+ }
+#else
+ if ((err = remote_shell_execute((char*)buf_ptr, wl)) != SUCCESS) {
+ DPRINT_ERR(ERR, "Error in executing shell command\n");
+ if (buf_ptr)
+ free(buf_ptr);
+#ifdef RWL_SOCKET
+ /* Transmitted to client. Then close the handle &
+ * get the new handle for next transmission & reception.
+ */
+ close_sock_handle(g_rwl_hndle);
+#endif /* RWL_SOCKET */
+ continue;
+ }
+ /* Get the response from the temporary file */
+ if ((err = remote_shell_get_resp(shell_fname, wl)) != SUCCESS) {
+ DPRINT_ERR(ERR, "Error in executing shell command\n");
+ }
+ if (buf_ptr)
+ free(buf_ptr);
+#ifdef RWL_SOCKET
+ /* Transmitted to client. Then close the handle &
+ * get the new handle for next transmission & reception.
+ */
+ close_sock_handle(g_rwl_hndle);
+#endif /* RWL_SOCKET */
+ continue;
+#endif /* WIN32 */
+ } /* REMOTE_SHELL_CMD */
+
+#ifdef RWLASD
+ if (g_rem_ptr->msg.flags & REMOTE_ASD_CMD) {
+ if ((err = remote_asd_exec(buf_ptr, (int *)&g_rem_ptr->msg.len)) < 0) {
+ DPRINT_ERR(ERR, "Error in executing asd command\n");
+ }
+ } /* REMOTE_ASD_CMD */
+#endif
+
+/*
+ * added to take care of OID base problem for cross OS RWL cleint server
+ * In case of LX Server and WIN32 client OID base need to be removed
+ * In case of WIN32 server and LX client OID base need to be added
+ */
+ if (!(g_rem_ptr->msg.flags & REMOTE_ASD_CMD)) {
+#if defined(LINUX)
+ if (g_rem_ptr->msg.cmd > MAX_IOVAR)
+ g_rem_ptr->msg.cmd -= WL_OID_BASE;
+#endif
+#if defined(WIN32)
+ if (g_rem_ptr->msg.cmd < MAX_IOVAR)
+ g_rem_ptr->msg.cmd += WL_OID_BASE;
+#endif
+ }
+#ifdef VISTA_SERVER
+ if (g_rem_ptr->msg.flags & REMOTE_VISTA_CMD) {
+ vista_buf[0] = strtok(buf_ptr, " \t\n");
+ for (index = 1; (vista_buf[index] = strtok(NULL, " \t\n")) != NULL;
+ index++);
+ if ((err = remote_vista_exec(wl, vista_buf)) < 0) {
+ DPRINT_ERR(ERR, "Error in executing vista command\n");
+ }
+ memcpy(buf_ptr, vista_buf[0], strlen(vista_buf[0]));
+ g_rem_ptr->msg.len = strlen(vista_buf[0]);
+ } /* REMOTE_VISTA_CMD */
+#endif /* VISTA_SERVER */
+
+#ifndef OLYMPIC_RWL
+#if defined(LINUX)
+#ifndef RWL_DONGLE
+ if (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL ||
+ g_rem_ptr->msg.flags & REMOTE_SET_IOCTL) {
+ if (strlen(g_rem_ptr->intf_name) != 0) {
+ struct ifreq ifr;
+ /* validate the interface */
+ memset(&ifr, 0, sizeof(ifr));
+ if (g_rem_ptr->intf_name)
+ strncpy(ifr.ifr_name, g_rem_ptr->intf_name, IFNAMSIZ);
+
+ if (wl_check((void *)&ifr)) {
+ DPRINT_ERR(ERR, "%s: wl driver adapter not found\n",
+ g_rem_ptr->intf_name);
+ /* Signal end of command output */
+ g_rem_ptr->msg.len = 0;
+ remote_tx_response(wl, NULL, BCME_NODEVICE);
+ if (buf_ptr)
+ free(buf_ptr);
+#ifdef RWL_SOCKET
+ close_sock_handle(g_rwl_hndle);
+#endif
+ continue;
+ }
+
+ if (set_interface(wl, g_rem_ptr->intf_name) == BCME_OK)
+ DPRINT_DBG(OUTPUT, "\n %s Interface will be used \n",
+ (char *)wl);
+ }
+ }
+#endif /* ifndef RWL_DONGLE */
+#endif /* defined(LINUX) */
+#endif /* ifndef OLYMPIC_RWL */
+ if (g_rem_ptr->msg.flags & REMOTE_SET_IOCTL ||
+ g_rem_ptr->msg.flags & RDHD_SET_IOCTL) {
+#ifdef WIN32
+#if defined(RWL_DONGLE) || defined(RWL_WIFI)
+ /* For commands with msg length as zero initialize the buffer to null */
+ if (g_rem_ptr->msg.len == 0)
+ buf_ptr = NULL;
+#endif
+#else
+ if (g_rem_ptr->msg.len == 0)
+ buf_ptr = NULL;
+#endif /* WIN32 */
+
+#if defined(LINUX) || defined(TARGETOS_symbian) || defined(TARGETOS_nucleus)
+#ifdef OLYMPIC_RWL
+ set_interface(wl, old_intf_name);
+#endif
+ if (g_rem_ptr->msg.flags & REMOTE_SET_IOCTL) {
+ if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr &&
+ !strncmp((const char *)buf_ptr,
+ "init", g_rem_ptr->msg.len)) {
+ DPRINT_INFO(OUTPUT, "REC : init command\n");
+ err = 0;
+ } else if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr &&
+ !strncmp((const char *)buf_ptr,
+ "download", g_rem_ptr->msg.len)) {
+ DPRINT_INFO(OUTPUT, "REC : download command\n");
+ download_flag = download_flag? 0: 1;
+ if (download_flag) {
+ DPRINT_INFO(OUTPUT, "download started\n");
+ if (!(fp = fopen(fn, "wb"))) {
+ DPRINT_ERR(ERR, "Failed to open file\n");
+ err = -2;
+ }
+ } else {
+ DPRINT_INFO(OUTPUT, "download completed\n");
+ if (fp != NULL) {
+ (void)fclose(fp);
+ fp = NULL;
+ }
+ }
+ err = 0;
+ } else if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr &&
+ !strncmp((const char *)buf_ptr,
+ "nvdownload", g_rem_ptr->msg.len)) {
+ DPRINT_INFO(OUTPUT, "REC : nvram download command\n");
+ download_flag = download_flag? 0: 1;
+ if (download_flag) {
+ DPRINT_INFO(OUTPUT, "nvram download started\n");
+ if (!(fp = fopen(fw, "wb"))) {
+ DPRINT_ERR(ERR, "Failed to open file\n");
+ err = -2;
+ }
+ } else {
+ DPRINT_INFO(OUTPUT, "nvram download completed\n");
+ if (fp != NULL) {
+ (void)fclose(fp);
+ fp = NULL;
+ }
+ }
+ err = 0;
+ } else if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr &&
+ !strncmp((const char *)buf_ptr,
+ "membytes", g_rem_ptr->msg.len)) {
+ DPRINT_INFO(OUTPUT, "REC : membytes command\n");
+ skip = strlen("membytes ") + 8;
+ if (fp != NULL)
+ fwrite(buf_ptr + skip, 1,
+ g_rem_ptr->msg.len - skip, fp);
+ else
+ DPRINT_ERR(ERR, "Download file has been closed.\n");
+ err = 0;
+ } else {
+ err = wl_ioctl(wl, g_rem_ptr->msg.cmd,
+ (void *)buf_ptr, g_rem_ptr->msg.len, TRUE);
+ DPRINT_INFO(OUTPUT, "SEND : cmd %d\t msg len %d\n",
+ g_rem_ptr->msg.cmd, g_rem_ptr->msg.len);
+ DPRINT_INFO(OUTPUT, "error code: %d\n", err);
+ }
+ }
+#if defined(LINUX)
+ if (err == BCME_IOCTL_ERROR) {
+ if (rwl_var_getbuf(wl, "bcmerrorstr", NULL, 0, (void**)&errstr)) {
+ DPRINT_ERR(ERR, "Error in executing wl_ioctl\r\n");
+ } else {
+ DPRINT_ERR(ERR, "%s\n", errstr);
+ }
+ DPRINT_ERR(ERR, "Setting Default Interface1 \n");
+ set_interface(wl, old_intf_name);
+ }
+
+ if (g_rem_ptr->msg.flags & RDHD_SET_IOCTL) {
+ err = dhd_ioctl(wl, g_rem_ptr->msg.cmd,
+ (void *)buf_ptr, g_rem_ptr->msg.len, TRUE);
+ }
+#endif /* LINUX */
+
+#elif WIN32
+ dwlen = g_rem_ptr->msg.len;
+ if (g_rem_ptr->msg.flags & RDHD_SET_IOCTL) {
+ g_rem_ptr->msg.cmd = g_rem_ptr->msg.cmd
+ - WL_OID_BASE + OID_DHD_IOCTLS;
+ }
+
+ err = (int)ir_setinformation(wl, g_rem_ptr->msg.cmd,
+ buf_ptr, &dwlen);
+#endif
+ g_rem_ptr->msg.flags = REMOTE_SET_IOCTL;
+
+ } /* RDHD/REMOTE_SET_IOCTL */
+
+ if (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL ||
+ g_rem_ptr->msg.flags & RDHD_GET_IOCTL) {
+#if defined(LINUX) || defined(TARGETOS_symbian) || defined(TARGETOS_nucleus)
+ if (g_rem_ptr->msg.cmd == WLC_GET_VAR && buf_ptr &&
+ strncmp((const char *)buf_ptr, "exit", g_rem_ptr->msg.len) == 0) {
+ /* exit command from remote client terminates server */
+ free(buf_ptr);
+ break;
+ }
+ if (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL)
+ err = wl_ioctl(wl, g_rem_ptr->msg.cmd, (void *)buf_ptr,
+ g_rem_ptr->msg.len, FALSE);
+#ifdef PCIE_MFGTEST
+ if (err == CMD_ERR &&
+ g_rem_ptr->msg.cmd == WLC_GET_MAGIC &&
+ g_rem_ptr->msg.len == 4) {
+ err = 0;
+ DPRINT_ERR(ERR, "----command error \n");
+ buf_ptr[0] = WLC_IOCTL_MAGIC & 0xff; // 0x77
+ buf_ptr[1] = (WLC_IOCTL_MAGIC >> 8) & 0xff; // 0x6c
+ buf_ptr[2] = (WLC_IOCTL_MAGIC >> 16) & 0xff; // 0xe4;
+ buf_ptr[3] = (WLC_IOCTL_MAGIC >> 24) & 0xff; // 0x14;
+ }
+#endif /* PCIE_MFGTEST */
+#if defined(LINUX)
+ if (err == BCME_IOCTL_ERROR) {
+#ifdef PCIE_MFGTEST
+ if (g_rem_ptr->msg.cmd == WLC_GET_VERSION &&
+ g_rem_ptr->msg.len == 4) {
+ err = 0;
+ DPRINT_ERR(ERR, "---getversion \n");
+ buf_ptr[0] = WLC_IOCTL_VERSION & 0xff;
+ buf_ptr[1] = (WLC_IOCTL_VERSION >> 8) & 0xff;
+ buf_ptr[2] = (WLC_IOCTL_VERSION >> 16) & 0xff;
+ buf_ptr[3] = (WLC_IOCTL_VERSION >> 24) & 0xff;
+ }
+ else {
+ DPRINT_ERR(ERR, "REMOTE_GET_IOCTL::Error in executing"
+ " wl_ioctl\n");
+ DPRINT_ERR(ERR, "Setting Default Interface \n");
+ set_interface(wl, old_intf_name);
+ }
+#else
+ if (rwl_var_getbuf(wl, "bcmerrorstr", NULL, 0, (void**)&errstr)) {
+ DPRINT_ERR(ERR,
+ "REMOTE_GET_IOCTL::Error in executing wl_ioctl\n");
+ } else {
+ DPRINT_ERR(ERR, "%s\n", errstr);
+ }
+ DPRINT_ERR(ERR, "Setting Default Interface \n");
+ set_interface(wl, old_intf_name);
+#endif /* PCIE_MFGTEST */
+ }
+
+ if (g_rem_ptr->msg.flags & RDHD_GET_IOCTL)
+ err = dhd_ioctl(wl, g_rem_ptr->msg.cmd, (void *)buf_ptr,
+ g_rem_ptr->msg.len, FALSE);
+#endif /* LINUX */
+#elif WIN32
+ if (g_rem_ptr->msg.cmd == (WL_OID_BASE + WLC_GET_VAR) &&
+ strncmp(buf_ptr, "exit", g_rem_ptr->msg.len) == 0) {
+ /* exit command from remote client terminates server */
+ if (buf_ptr) {
+ free(buf_ptr);
+ }
+ break;
+ }
+
+ dwlen = g_rem_ptr->msg.len;
+ if (g_rem_ptr->msg.flags & RDHD_GET_IOCTL) {
+ g_rem_ptr->msg.cmd = g_rem_ptr->msg.cmd -
+ WL_OID_BASE + OID_DHD_IOCTLS;
+ }
+
+ err = (int)ir_queryinformation(wl,
+ g_rem_ptr->msg.cmd, buf_ptr, &dwlen);
+
+#endif /* defined(LINUX) || defined(TARGETOS_symbian) || defined(TARGETOS_nucleus) */
+ g_rem_ptr->msg.flags = REMOTE_GET_IOCTL;
+ } /* REMOTE_GET_IOCTL */
+ DPRINT_INFO(OUTPUT, "RESP : cmd %d\t msg len %d\n",
+ g_rem_ptr->msg.cmd, g_rem_ptr->msg.len);
+#if defined(LINUX)
+ /* setting back default interface */
+ set_interface(wl, old_intf_name);
+#endif /* defined(LINUX) */
+ /* Transmit the response results */
+ if (remote_tx_response(wl, buf_ptr, err) < 0) {
+ DPRINT_ERR(ERR, "\nReturn results failed\n");
+ }
+
+#ifdef RWL_SOCKET
+ if (g_rem_ptr->msg.flags != REMOTE_SHELL_CMD)
+ /* Transmitted to client. Then close the handle & get the new handle
+ * for next transmission & reception. In case of shell commands this
+ * should be closed in respective shellproc files.
+ */
+ close_sock_handle(g_rwl_hndle);
+#endif /* RWL_SOCKET */
+
+ if (buf_ptr) {
+ free(buf_ptr);
+ }
+ } /* end of while */
+#if defined(RWL_SOCKET)
+ /* Close the main handle for socket */
+ close_sock_handle(transport_descriptor);
+#elif defined(RWL_SERIAL)
+ /* Close the main handle for serial pipe */
+ rwl_close_pipe(remote_type, (void*)&transport_descriptor);
+#endif
+
+#ifdef RWLASD
+ wfa_dut_deinit();
+#endif
+
+ return err;
+}
diff --git a/wl/src/wl/exe/wlu_server_shared.h b/wl/src/wl/exe/wlu_server_shared.h
new file mode 100644
index 0000000..e697022
--- /dev/null
+++ b/wl/src/wl/exe/wlu_server_shared.h
@@ -0,0 +1,76 @@
+/*
+ * wl server declarations
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_server_shared.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#ifndef _wlu_server_shared_h
+#define _wlu_server_shared_h
+
+#if defined(LINUX) || defined(SYMBIAN)
+ extern int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set);
+#endif
+
+#if defined(LINUX)
+ extern int dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set);
+#endif
+
+#ifdef RWLASD
+/* streams' buffers */
+BYTE *xcCmdBuf = NULL, *parmsVal = NULL;
+BYTE *trafficBuf = NULL, *respBuf = NULL;
+struct timeval *toutvalp = NULL;
+#endif
+
+#define POLLING_TIME 200
+#define DONGLE_TX_FRAME_SIZE 1024
+#define MESSAGE_LENGTH 1024
+#define MAX_SHELL_FILE_LENGTH 50
+#define MAX_IOVAR 10000
+int remote_type = NO_REMOTE;
+rem_ioctl_t *g_rem_ptr;
+
+#if defined(LINUX) || defined(SYMBIAN) || defined(TARGETOS_nucleus)
+extern int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set);
+#endif
+
+/* Function prototypes from shellpoc_linux.c/shell_ce.c */
+extern int rwl_create_dir(void);
+extern int remote_shell_execute(char *buf_ptr, void *wl);
+extern int remote_shell_get_resp(char* shell_fname, void *wl);
+extern void rwl_wifi_find_server_response(void *wl, dot11_action_wifi_vendor_specific_t *rec_frame);
+extern dot11_action_wifi_vendor_specific_t *rwl_wifi_allocate_actionframe(void);
+
+/* Common code for serial and wifi */
+#if defined(RWL_DONGLE) || defined(RWL_WIFI) || defined(RWL_SERIAL)
+typedef struct rem_packet {
+ rem_ioctl_t rem_cdc;
+ uchar message[MESSAGE_LENGTH];
+} rem_packet_t;
+#define REMOTE_PACKET_SIZE sizeof(rem_packet_t)
+
+rem_packet_t *g_rem_pkt_ptr;
+rem_packet_t g_rem_pkt;
+#endif
+
+static struct ether_addr rwlea;
+
+static union {
+ uchar bufdata[WLC_IOCTL_MAXLEN];
+ uint32 alignme;
+} bufstruct_wlu;
+static uchar* rwl_buf = (uchar*) &bufstruct_wlu.bufdata;
+extern int need_speedy_response;
+
+#endif /* _wlu_server_shared_h_ */
diff --git a/wl/src/wl/exe/wlu_subcounters.c b/wl/src/wl/exe/wlu_subcounters.c
new file mode 100644
index 0000000..62c8f88
--- /dev/null
+++ b/wl/src/wl/exe/wlu_subcounters.c
@@ -0,0 +1,2164 @@
+/*
+ * Availability support functions
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: $
+ */
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include <bcmutils.h>
+#include <wlioctl.h>
+#include <wlioctl_utils.h>
+#include "wlu_cmd.h"
+#include "wlu.h"
+
+#define CAT_TX (1<<0) /**< counter is transmit related */
+#define CAT_RX (1<<1) /**< counter is receive related */
+#define CAT_ERR (1<<2) /**< counter signals a non optimal condition */
+#define CAT_UCAST (1<<3) /**< unicast specific counter */
+#define CAT_MCAST (1<<4) /**< multicast or broadcast specific counter */
+#define CAT_AMPDU (1<<5) /**< AMPDU specific counter */
+#define CAT_UCODE (1<<6) /**< Counter is generated by ucode (contained in SHM in d11 core) */
+#define CAT_CTRL (1<<7) /**< Counters related to d11 control or mgmt frames */
+#define CAT_SEC (1<<8) /**< Counters related to security/encryption */
+#define CAT_ASSOC (1<<9) /**< Counters related to authentication/association */
+
+#define PRINIT() prcnt_init()
+#define PRNL1() prcnt_prnl1(p_cnt_filters)
+
+#define PRFMT1(name) #name " %u " /* converts into the 'default' counters printf format string */
+
+/** prints one string without arguments */
+#define PRSTR(name, str) \
+ if (prcnt_filter1(p_cnt_filters, #name)) { \
+ printf("%s", str); \
+ at_start_of_line = FALSE; \
+ }
+
+/** prints one variable with dtoh32 conversion */
+#define PRVALV1(name) \
+ if (prcnt_filter(p_cnt_filters, #name, cnt_v1->name)) { \
+ printf(PRFMT1(name), dtoh32(cnt_v1->name)); \
+ at_start_of_line = FALSE; \
+ }
+
+#define PRVAL(name) \
+ if (prcnt_filter(p_cnt_filters, #name, cnt->name)) { \
+ printf(PRFMT1(name), dtoh32(cnt->name)); \
+ at_start_of_line = FALSE; \
+ }
+/** prints one variable with dtoh32 conversion */
+#define PRVAL_RENAME(name, prname) \
+ if (prcnt_filter(p_cnt_filters, #name, cnt->name)) { \
+ printf(PRFMT1(prname), dtoh32(cnt->name)); \
+ at_start_of_line = FALSE; \
+ }
+
+/** Safe value print for only valid counter values, and when the counter is within len */
+#define PRVALSF(name) \
+ if ((dtoh32(cnt->name) != INVALID_CNT_VAL) && \
+ (len > ((uint8 *)&cnt->name - (uint8 *)cnt))) \
+ PRVAL(name)
+
+/** prints one variable with dtoh32 conversion */
+#define PRVALSF_RENAME(varname, prname) \
+ if (dtoh32(cnt->varname) != INVALID_CNT_VAL) \
+ PRVAL_RENAME(varname, prname)
+
+/** prints one variable with dtoh32 conversion */
+#define PRVAL_FMTSTR1(varname, fmtstring, value) \
+ if (prcnt_filter(p_cnt_filters, #varname, value)) { \
+ printf(fmtstring, value); \
+ at_start_of_line = FALSE; \
+ }
+
+/** prints two variables, no dtoh32 conversion */
+#define PRVAL_FMTSTR2(varname, fmtstring, value1, value2) \
+ if (prcnt_filter(p_cnt_filters, #varname, value2)) { \
+ printf(fmtstring, value1, value2); \
+ at_start_of_line = FALSE; \
+ }
+
+/** prints one float variable without dtoh32 conversion */
+#define PRVAL_FMTSTR1F(varname, fmtstring, value1) \
+ if (prcnt_filter(p_cnt_filters, #varname, value1 != 0.0 ? TRUE : FALSE)) { \
+ printf(fmtstring, value1); \
+ at_start_of_line = FALSE; \
+ }
+
+#define PRCNT_MACSTAT_TX_VER_GE11 \
+do { \
+ /* UCODE SHM counters */ \
+ /* tx start and those that do not end well */ \
+ PRVAL(txallfrm); PRVAL(txbcnfrm); PRVAL(txrtsfrm); PRVAL(txctsfrm); \
+ PRVAL(txackfrm); PRVAL(txback); PRVAL(txdnlfrm); PRNL1(); \
+ PRVAL(txampdu); PRVAL(txmpdu); PRVAL(txucast); \
+ PRVAL(rxrsptmout); PRVAL(txinrtstxop); PRVAL(txrtsfail); PRNL1(); \
+ PRVAL_FMTSTR1F(txper_ucastdt, "txper_ucastdt %.1f%% ", \
+ cnt->txucast > 0 ? \
+ (float)(1000 - ((cnt->rxackucast + cnt->rxback) * 1000 \
+ / cnt->txucast))/10 : 0); \
+ PRVAL_FMTSTR1F(txper_rts, "txper_rts %.1f%%", \
+ cnt->txrtsfrm > 0 ? \
+ (float)(1000 - (cnt->rxctsucast * 1000 \
+ / cnt->txrtsfrm))/10 : 0); \
+ PRNL1(); \
+ PRSTR(txfunfl, "txfunfl: "); \
+ for (i = 0; i < NFIFO; i++) { \
+ PRVAL_FMTSTR1(txfunfl, "%u ", cnt->txfunfl[i]); \
+ } \
+ PRVAL(txtplunfl); PRVAL(txphyerror); PRNL1(); PRNL1(); \
+} while (0)
+
+
+#define PRCNT_MACSTAT_RX_VER_GE11 \
+do { \
+ /* rx with goodfcs */ \
+ PRVAL(rxctlucast); PRVAL(rxrtsucast); PRVAL(rxctsucast); \
+ PRVAL(rxackucast); PRVAL(rxback); PRNL1(); \
+ PRVAL(rxbeaconmbss); PRVAL(rxdtucastmbss); \
+ PRVAL(rxmgucastmbss); PRNL1(); \
+ PRVAL(rxbeaconobss); PRVAL(rxdtucastobss); PRVAL(rxdtocast); \
+ PRVAL(rxmgocast); PRNL1(); \
+ PRVAL(rxctlocast); PRVAL(rxrtsocast); PRVAL(rxctsocast); PRNL1(); \
+ PRVAL(rxctlmcast); PRVAL(rxdtmcast); PRVAL(rxmgmcast); PRNL1(); PRNL1(); \
+ \
+ PRVAL(rxcgprqfrm); PRVAL(rxcgprsqovfl); PRVAL(txcgprsfail); \
+ PRVAL(txcgprssuc); PRVAL(prs_timeout); PRNL1(); \
+ PRVAL(pktengrxducast); PRVAL(pktengrxdmcast); \
+ PRVAL(bcntxcancl); \
+} while (0)
+
+extern int wlu_var_getbuf_minimal(void *wl, const char *iovar, void *param, int param_len,
+ void **bufptr);
+
+/** specifies filters to apply when printing counters */
+struct cnt_filters_s {
+ bool nonzero; /**< only print nonzero counter values */
+ bool filters_active; /**< FALSE when user did not supply cmd line options */
+ bool invert_selection; /**< inverts entire selection */
+ uint32 filter; /**< only print counters falling into these categorie(s). Ignored if 0. */
+};
+
+typedef struct {
+ char **pbuf_ptr;
+ uint32 cntr_ver;
+ struct cnt_filters_s cnt_filters; /**< specifies filters to apply when printing counters */
+} wl_cnt_cbfn_info_t;
+
+typedef struct counter_offset_info {
+ const char *name; /* Name for the counter */
+ uint32 offset; /* Offset of the counter in structure */
+} counter_offset_info_t;
+
+typedef struct ver_to_cntr_offset_info {
+ counter_offset_info_t *offset_info_tbl;
+ uint32 cntr_ver;
+} ver_to_cntr_offset_info_t;
+
+/** specifies properties of each counter, so it can be optionally not printed on a criterium */
+struct cnt_properties_s {
+ char *name;
+ uint32 categories; /**< a bitmask, '1' means that counter is a member of that category */
+};
+
+static counter_offset_info_t cntr_offset_info_v6[] = {
+ {"txframe", OFFSETOF(wl_cnt_ver_6_t, txframe)},
+ {"txbyte", OFFSETOF(wl_cnt_ver_6_t, txbyte)},
+ {"txretrans", OFFSETOF(wl_cnt_ver_6_t, txretrans)},
+ {"txerror", OFFSETOF(wl_cnt_ver_6_t, txerror)},
+ {"txctl", OFFSETOF(wl_cnt_ver_6_t, txctl)},
+ {"txprshort", OFFSETOF(wl_cnt_ver_6_t, txprshort)},
+ {"txserr", OFFSETOF(wl_cnt_ver_6_t, txserr)},
+ {"txnobuf", OFFSETOF(wl_cnt_ver_6_t, txnobuf)},
+ {"txnoassoc", OFFSETOF(wl_cnt_ver_6_t, txnoassoc)},
+ {"txrunt", OFFSETOF(wl_cnt_ver_6_t, txrunt)},
+ {"txchit", OFFSETOF(wl_cnt_ver_6_t, txchit)},
+ {"txcmiss", OFFSETOF(wl_cnt_ver_6_t, txcmiss)},
+ {"txuflo", OFFSETOF(wl_cnt_ver_6_t, txuflo)},
+ {"txphyerr", OFFSETOF(wl_cnt_ver_6_t, txphyerr)},
+ {"txphycrs", OFFSETOF(wl_cnt_ver_6_t, txphycrs)},
+ {"rxframe", OFFSETOF(wl_cnt_ver_6_t, rxframe)},
+ {"rxbyte", OFFSETOF(wl_cnt_ver_6_t, rxbyte)},
+ {"rxerror", OFFSETOF(wl_cnt_ver_6_t, rxerror)},
+ {"rxctl", OFFSETOF(wl_cnt_ver_6_t, rxctl)},
+ {"rxnobuf", OFFSETOF(wl_cnt_ver_6_t, rxnobuf)},
+ {"rxnondata", OFFSETOF(wl_cnt_ver_6_t, rxnondata)},
+ {"rxbadds", OFFSETOF(wl_cnt_ver_6_t, rxbadds)},
+ {"rxbadcm", OFFSETOF(wl_cnt_ver_6_t, rxbadcm)},
+ {"rxfragerr", OFFSETOF(wl_cnt_ver_6_t, rxfragerr)},
+ {"rxrunt", OFFSETOF(wl_cnt_ver_6_t, rxrunt)},
+ {"rxgiant", OFFSETOF(wl_cnt_ver_6_t, rxgiant)},
+ {"rxnoscb", OFFSETOF(wl_cnt_ver_6_t, rxnoscb)},
+ {"rxbadproto", OFFSETOF(wl_cnt_ver_6_t, rxbadproto)},
+ {"rxbadsrcmac", OFFSETOF(wl_cnt_ver_6_t, rxbadsrcmac)},
+ {"rxbadda", OFFSETOF(wl_cnt_ver_6_t, rxbadda)},
+ {"rxfilter", OFFSETOF(wl_cnt_ver_6_t, rxfilter)},
+ {"rxoflo", OFFSETOF(wl_cnt_ver_6_t, rxoflo)},
+ {"rxuflo[0]", OFFSETOF(wl_cnt_ver_6_t, rxuflo[0])},
+ {"rxuflo[1]", OFFSETOF(wl_cnt_ver_6_t, rxuflo[1])},
+ {"rxuflo[2]", OFFSETOF(wl_cnt_ver_6_t, rxuflo[2])},
+ {"rxuflo[3]", OFFSETOF(wl_cnt_ver_6_t, rxuflo[3])},
+ {"rxuflo[4]", OFFSETOF(wl_cnt_ver_6_t, rxuflo[4])},
+ {"rxuflo[5]", OFFSETOF(wl_cnt_ver_6_t, rxuflo[5])},
+ {"d11cnt_txrts_off", OFFSETOF(wl_cnt_ver_6_t, d11cnt_txrts_off)},
+ {"d11cnt_rxcrc_off", OFFSETOF(wl_cnt_ver_6_t, d11cnt_rxcrc_off)},
+ {"d11cnt_txnocts_off", OFFSETOF(wl_cnt_ver_6_t, d11cnt_txnocts_off)},
+ {"dmade", OFFSETOF(wl_cnt_ver_6_t, dmade)},
+ {"dmada", OFFSETOF(wl_cnt_ver_6_t, dmada)},
+ {"dmape", OFFSETOF(wl_cnt_ver_6_t, dmape)},
+ {"reset", OFFSETOF(wl_cnt_ver_6_t, reset)},
+ {"tbtt", OFFSETOF(wl_cnt_ver_6_t, tbtt)},
+ {"txdmawar", OFFSETOF(wl_cnt_ver_6_t, txdmawar)},
+ {"pkt_callback_reg_fail", OFFSETOF(wl_cnt_ver_6_t, pkt_callback_reg_fail)},
+ {"d11_txfrag", OFFSETOF(wl_cnt_ver_6_t, txfrag)},
+ {"d11_txmulti", OFFSETOF(wl_cnt_ver_6_t, txmulti)},
+ {"txfail", OFFSETOF(wl_cnt_ver_6_t, txfail)},
+ {"d11_txretry", OFFSETOF(wl_cnt_ver_6_t, txretry)},
+ {"d11_txretrie", OFFSETOF(wl_cnt_ver_6_t, txretrie)},
+ {"rxdup", OFFSETOF(wl_cnt_ver_6_t, rxdup)},
+ {"d11_txrts", OFFSETOF(wl_cnt_ver_6_t, txrts)},
+ {"d11_txnocts", OFFSETOF(wl_cnt_ver_6_t, txnocts)},
+ {"d11_txnoack", OFFSETOF(wl_cnt_ver_6_t, txnoack)},
+ {"d11_rxfrag", OFFSETOF(wl_cnt_ver_6_t, rxfrag)},
+ {"d11_rxmulti", OFFSETOF(wl_cnt_ver_6_t, rxmulti)},
+ {"rxcrc", OFFSETOF(wl_cnt_ver_6_t, rxcrc)},
+ {"d11_txfrmsnt", OFFSETOF(wl_cnt_ver_6_t, txfrmsnt)},
+ {"d11_rxundec", OFFSETOF(wl_cnt_ver_6_t, rxundec)},
+ {"tkipmicfaill", OFFSETOF(wl_cnt_ver_6_t, tkipmicfaill)},
+ {"tkipcntrmsr", OFFSETOF(wl_cnt_ver_6_t, tkipcntrmsr)},
+ {"tkipreplay", OFFSETOF(wl_cnt_ver_6_t, tkipreplay)},
+ {"ccmpfmterr", OFFSETOF(wl_cnt_ver_6_t, ccmpfmterr)},
+ {"ccmpreplay", OFFSETOF(wl_cnt_ver_6_t, ccmpreplay)},
+ {"ccmpundec", OFFSETOF(wl_cnt_ver_6_t, ccmpundec)},
+ {"fourwayfail", OFFSETOF(wl_cnt_ver_6_t, fourwayfail)},
+ {"wepundec", OFFSETOF(wl_cnt_ver_6_t, wepundec)},
+ {"wepicverr", OFFSETOF(wl_cnt_ver_6_t, wepicverr)},
+ {"decsuccess", OFFSETOF(wl_cnt_ver_6_t, decsuccess)},
+ {"tkipicverr", OFFSETOF(wl_cnt_ver_6_t, tkipicverr)},
+ {"wepexcluded", OFFSETOF(wl_cnt_ver_6_t, wepexcluded)},
+ {"txchanrej", OFFSETOF(wl_cnt_ver_6_t, txchanrej)},
+ {"psmwds", OFFSETOF(wl_cnt_ver_6_t, psmwds)},
+ {"phywatchdog", OFFSETOF(wl_cnt_ver_6_t, phywatchdog)},
+ {"prq_entries_handled", OFFSETOF(wl_cnt_ver_6_t, prq_entries_handled)},
+ {"prq_undirected_entries", OFFSETOF(wl_cnt_ver_6_t, prq_undirected_entries)},
+ {"prq_bad_entries", OFFSETOF(wl_cnt_ver_6_t, prq_bad_entries)},
+ {"atim_suppress_count", OFFSETOF(wl_cnt_ver_6_t, atim_suppress_count)},
+ {"bcn_template_not_ready", OFFSETOF(wl_cnt_ver_6_t, bcn_template_not_ready)},
+ {"bcn_template_not_ready_done", OFFSETOF(wl_cnt_ver_6_t, bcn_template_not_ready_done)},
+ {"late_tbtt_dpc", OFFSETOF(wl_cnt_ver_6_t, late_tbtt_dpc)},
+ {"rx1mbps", OFFSETOF(wl_cnt_ver_6_t, rx1mbps)},
+ {"rx2mbps", OFFSETOF(wl_cnt_ver_6_t, rx2mbps)},
+ {"rx5mbps5", OFFSETOF(wl_cnt_ver_6_t, rx5mbps5)},
+ {"rx6mbps", OFFSETOF(wl_cnt_ver_6_t, rx6mbps)},
+ {"rx9mbps", OFFSETOF(wl_cnt_ver_6_t, rx9mbps)},
+ {"rx11mbps", OFFSETOF(wl_cnt_ver_6_t, rx11mbps)},
+ {"rx12mbps", OFFSETOF(wl_cnt_ver_6_t, rx12mbps)},
+ {"rx18mbps", OFFSETOF(wl_cnt_ver_6_t, rx18mbps)},
+ {"rx24mbps", OFFSETOF(wl_cnt_ver_6_t, rx24mbps)},
+ {"rx36mbps", OFFSETOF(wl_cnt_ver_6_t, rx36mbps)},
+ {"rx48mbps", OFFSETOF(wl_cnt_ver_6_t, rx48mbps)},
+ {"rx54mbps", OFFSETOF(wl_cnt_ver_6_t, rx54mbps)},
+ {"rx108mbps", OFFSETOF(wl_cnt_ver_6_t, rx108mbps)},
+ {"rx162mbps", OFFSETOF(wl_cnt_ver_6_t, rx162mbps)},
+ {"rx216mbps", OFFSETOF(wl_cnt_ver_6_t, rx216mbps)},
+ {"rx270mbps", OFFSETOF(wl_cnt_ver_6_t, rx270mbps)},
+ {"rx324mbps", OFFSETOF(wl_cnt_ver_6_t, rx324mbps)},
+ {"rx378mbps", OFFSETOF(wl_cnt_ver_6_t, rx378mbps)},
+ {"rx432mbps", OFFSETOF(wl_cnt_ver_6_t, rx432mbps)},
+ {"rx486mbps", OFFSETOF(wl_cnt_ver_6_t, rx486mbps)},
+ {"rx540mbps", OFFSETOF(wl_cnt_ver_6_t, rx540mbps)},
+ {"rfdisable", OFFSETOF(wl_cnt_ver_6_t, rfdisable)},
+ {"txexptime", OFFSETOF(wl_cnt_ver_6_t, txexptime)},
+ {"txmpdu_sgi", OFFSETOF(wl_cnt_ver_6_t, txmpdu_sgi)},
+ {"rxmpdu_sgi", OFFSETOF(wl_cnt_ver_6_t, rxmpdu_sgi)},
+ {"txmpdu_stbc", OFFSETOF(wl_cnt_ver_6_t, txmpdu_stbc)},
+ {"rxmpdu_stbc", OFFSETOF(wl_cnt_ver_6_t, rxmpdu_stbc)},
+ {"rxundec_mcst", OFFSETOF(wl_cnt_ver_6_t, rxundec_mcst)},
+ {"tkipmicfaill_mcst", OFFSETOF(wl_cnt_ver_6_t, tkipmicfaill_mcst)},
+ {"tkipcntrmsr_mcst", OFFSETOF(wl_cnt_ver_6_t, tkipcntrmsr_mcst)},
+ {"tkipreplay_mcst", OFFSETOF(wl_cnt_ver_6_t, tkipreplay_mcst)},
+ {"ccmpfmterr_mcst", OFFSETOF(wl_cnt_ver_6_t, ccmpfmterr_mcst)},
+ {"ccmpreplay_mcst", OFFSETOF(wl_cnt_ver_6_t, ccmpreplay_mcst)},
+ {"ccmpundec_mcst", OFFSETOF(wl_cnt_ver_6_t, ccmpundec_mcst)},
+ {"fourwayfail_mcst", OFFSETOF(wl_cnt_ver_6_t, fourwayfail_mcst)},
+ {"wepundec_mcst", OFFSETOF(wl_cnt_ver_6_t, wepundec_mcst)},
+ {"wepicverr_mcst", OFFSETOF(wl_cnt_ver_6_t, wepicverr_mcst)},
+ {"decsuccess_mcst", OFFSETOF(wl_cnt_ver_6_t, decsuccess_mcst)},
+ {"tkipicverr_mcst", OFFSETOF(wl_cnt_ver_6_t, tkipicverr_mcst)},
+ {"wepexcluded_mcst", OFFSETOF(wl_cnt_ver_6_t, wepexcluded_mcst)},
+ /* macstat counters */
+ {"txallfrm", OFFSETOF(wl_cnt_ver_6_t, txallfrm)},
+ {"txrtsfrm", OFFSETOF(wl_cnt_ver_6_t, txrtsfrm)},
+ {"txctsfrm", OFFSETOF(wl_cnt_ver_6_t, txctsfrm)},
+ {"txackfrm", OFFSETOF(wl_cnt_ver_6_t, txackfrm)},
+ {"txdnlfrm", OFFSETOF(wl_cnt_ver_6_t, txdnlfrm)},
+ {"txbcnfrm", OFFSETOF(wl_cnt_ver_6_t, txbcnfrm)},
+ {"txfunfl[0]", OFFSETOF(wl_cnt_ver_6_t, txfunfl[0])},
+ {"txfunfl[1]", OFFSETOF(wl_cnt_ver_6_t, txfunfl[1])},
+ {"txfunfl[2]", OFFSETOF(wl_cnt_ver_6_t, txfunfl[2])},
+ {"txfunfl[3]", OFFSETOF(wl_cnt_ver_6_t, txfunfl[3])},
+ {"txfunfl[4]", OFFSETOF(wl_cnt_ver_6_t, txfunfl[4])},
+ {"txfunfl[5]", OFFSETOF(wl_cnt_ver_6_t, txfunfl[5])},
+ {"txampdu", OFFSETOF(wl_cnt_ver_6_t, txfbw)},
+ {"txtplunfl", OFFSETOF(wl_cnt_ver_6_t, txtplunfl)},
+ {"txphyerror", OFFSETOF(wl_cnt_ver_6_t, txphyerror)},
+ {"pktengrxducast", OFFSETOF(wl_cnt_ver_6_t, pktengrxducast)},
+ {"pktengrxdmcast", OFFSETOF(wl_cnt_ver_6_t, pktengrxdmcast)},
+ {"rxfrmtoolong", OFFSETOF(wl_cnt_ver_6_t, rxfrmtoolong)},
+ {"rxfrmtooshrt", OFFSETOF(wl_cnt_ver_6_t, rxfrmtooshrt)},
+ {"rxanyerr", OFFSETOF(wl_cnt_ver_6_t, rxinvmachdr)},
+ {"rxbadfcs", OFFSETOF(wl_cnt_ver_6_t, rxbadfcs)},
+ {"rxbadplcp", OFFSETOF(wl_cnt_ver_6_t, rxbadplcp)},
+ {"rxcrsglitch", OFFSETOF(wl_cnt_ver_6_t, rxcrsglitch)},
+ {"rxstrt", OFFSETOF(wl_cnt_ver_6_t, rxstrt)},
+ {"rxdtucastmbss", OFFSETOF(wl_cnt_ver_6_t, rxdfrmucastmbss)},
+ {"rxmgucastmbss", OFFSETOF(wl_cnt_ver_6_t, rxmfrmucastmbss)},
+ {"rxctlucast", OFFSETOF(wl_cnt_ver_6_t, rxcfrmucast)},
+ {"rxrtsucast", OFFSETOF(wl_cnt_ver_6_t, rxrtsucast)},
+ {"rxctsucast", OFFSETOF(wl_cnt_ver_6_t, rxctsucast)},
+ {"rxackucast", OFFSETOF(wl_cnt_ver_6_t, rxackucast)},
+ {"rxdtocast", OFFSETOF(wl_cnt_ver_6_t, rxdfrmocast)},
+ {"rxmgocast", OFFSETOF(wl_cnt_ver_6_t, rxmfrmocast)},
+ {"rxctlocast", OFFSETOF(wl_cnt_ver_6_t, rxcfrmocast)},
+ {"rxrtsocast", OFFSETOF(wl_cnt_ver_6_t, rxrtsocast)},
+ {"rxctsocast", OFFSETOF(wl_cnt_ver_6_t, rxctsocast)},
+ {"rxdtmcast", OFFSETOF(wl_cnt_ver_6_t, rxdfrmmcast)},
+ {"rxmgmcast", OFFSETOF(wl_cnt_ver_6_t, rxmfrmmcast)},
+ {"rxctlmcast", OFFSETOF(wl_cnt_ver_6_t, rxcfrmmcast)},
+ {"rxbeaconmbss", OFFSETOF(wl_cnt_ver_6_t, rxbeaconmbss)},
+ {"rxdtucastobss", OFFSETOF(wl_cnt_ver_6_t, rxdfrmucastobss)},
+ {"rxbeaconobss", OFFSETOF(wl_cnt_ver_6_t, rxbeaconobss)},
+ {"rxrsptmout", OFFSETOF(wl_cnt_ver_6_t, rxrsptmout)},
+ {"bcntxcancl", OFFSETOF(wl_cnt_ver_6_t, bcntxcancl)},
+ {"rxf0ovfl", OFFSETOF(wl_cnt_ver_6_t, rxf0ovfl)},
+ {"rxf1ovfl", OFFSETOF(wl_cnt_ver_6_t, rxf1ovfl)},
+ {"rxhlovfl", OFFSETOF(wl_cnt_ver_6_t, rxf2ovfl)},
+ {"missbcn_dbg", OFFSETOF(wl_cnt_ver_6_t, txsfovfl)},
+ {"pmqovfl", OFFSETOF(wl_cnt_ver_6_t, pmqovfl)},
+ {"rxcgprqfrm", OFFSETOF(wl_cnt_ver_6_t, rxcgprqfrm)},
+ {"rxcgprsqovfl", OFFSETOF(wl_cnt_ver_6_t, rxcgprsqovfl)},
+ {"txcgprsfail", OFFSETOF(wl_cnt_ver_6_t, txcgprsfail)},
+ {"txcgprssuc", OFFSETOF(wl_cnt_ver_6_t, txcgprssuc)},
+ {"prs_timeout", OFFSETOF(wl_cnt_ver_6_t, prs_timeout)},
+ {"txrtsfail", OFFSETOF(wl_cnt_ver_6_t, rxnack)},
+ {"txucast", OFFSETOF(wl_cnt_ver_6_t, frmscons)},
+ {"txinrtstxop", OFFSETOF(wl_cnt_ver_6_t, txnack)},
+ {"rxback", OFFSETOF(wl_cnt_ver_6_t, rxback)},
+ {"txback", OFFSETOF(wl_cnt_ver_6_t, txback)},
+ {"bphy_rxcrsglitch", OFFSETOF(wl_cnt_ver_6_t, bphy_rxcrsglitch)},
+ {"rxdrop20s", OFFSETOF(wl_cnt_ver_6_t, rxdrop20s)},
+ {"rxtoolate", OFFSETOF(wl_cnt_ver_6_t, rxtoolate)},
+ {"bphy_badplcp", OFFSETOF(wl_cnt_ver_6_t, bphy_badplcp)},
+ {NULL, 0},
+};
+
+static counter_offset_info_t cntr_offset_info_v7[] = {
+ {"txframe", OFFSETOF(wl_cnt_ver_7_t, txframe)},
+ {"txbyte", OFFSETOF(wl_cnt_ver_7_t, txbyte)},
+ {"txretrans", OFFSETOF(wl_cnt_ver_7_t, txretrans)},
+ {"txerror", OFFSETOF(wl_cnt_ver_7_t, txerror)},
+ {"txctl", OFFSETOF(wl_cnt_ver_7_t, txctl)},
+ {"txprshort", OFFSETOF(wl_cnt_ver_7_t, txprshort)},
+ {"txserr", OFFSETOF(wl_cnt_ver_7_t, txserr)},
+ {"txnobuf", OFFSETOF(wl_cnt_ver_7_t, txnobuf)},
+ {"txnoassoc", OFFSETOF(wl_cnt_ver_7_t, txnoassoc)},
+ {"txrunt", OFFSETOF(wl_cnt_ver_7_t, txrunt)},
+ {"txchit", OFFSETOF(wl_cnt_ver_7_t, txchit)},
+ {"txcmiss", OFFSETOF(wl_cnt_ver_7_t, txcmiss)},
+ {"txuflo", OFFSETOF(wl_cnt_ver_7_t, txuflo)},
+ {"txphyerr", OFFSETOF(wl_cnt_ver_7_t, txphyerr)},
+ {"txphycrs", OFFSETOF(wl_cnt_ver_7_t, txphycrs)},
+ {"rxframe", OFFSETOF(wl_cnt_ver_7_t, rxframe)},
+ {"rxbyte", OFFSETOF(wl_cnt_ver_7_t, rxbyte)},
+ {"rxerror", OFFSETOF(wl_cnt_ver_7_t, rxerror)},
+ {"rxctl", OFFSETOF(wl_cnt_ver_7_t, rxctl)},
+ {"rxnobuf", OFFSETOF(wl_cnt_ver_7_t, rxnobuf)},
+ {"rxnondata", OFFSETOF(wl_cnt_ver_7_t, rxnondata)},
+ {"rxbadds", OFFSETOF(wl_cnt_ver_7_t, rxbadds)},
+ {"rxbadcm", OFFSETOF(wl_cnt_ver_7_t, rxbadcm)},
+ {"rxfragerr", OFFSETOF(wl_cnt_ver_7_t, rxfragerr)},
+ {"rxrunt", OFFSETOF(wl_cnt_ver_7_t, rxrunt)},
+ {"rxgiant", OFFSETOF(wl_cnt_ver_7_t, rxgiant)},
+ {"rxnoscb", OFFSETOF(wl_cnt_ver_7_t, rxnoscb)},
+ {"rxbadproto", OFFSETOF(wl_cnt_ver_7_t, rxbadproto)},
+ {"rxbadsrcmac", OFFSETOF(wl_cnt_ver_7_t, rxbadsrcmac)},
+ {"rxbadda", OFFSETOF(wl_cnt_ver_7_t, rxbadda)},
+ {"rxfilter", OFFSETOF(wl_cnt_ver_7_t, rxfilter)},
+ {"rxoflo", OFFSETOF(wl_cnt_ver_7_t, rxoflo)},
+ {"rxuflo[0]", OFFSETOF(wl_cnt_ver_7_t, rxuflo[0])},
+ {"rxuflo[1]", OFFSETOF(wl_cnt_ver_7_t, rxuflo[1])},
+ {"rxuflo[2]", OFFSETOF(wl_cnt_ver_7_t, rxuflo[2])},
+ {"rxuflo[3]", OFFSETOF(wl_cnt_ver_7_t, rxuflo[3])},
+ {"rxuflo[4]", OFFSETOF(wl_cnt_ver_7_t, rxuflo[4])},
+ {"rxuflo[5]", OFFSETOF(wl_cnt_ver_7_t, rxuflo[5])},
+ {"d11cnt_txrts_off", OFFSETOF(wl_cnt_ver_7_t, d11cnt_txrts_off)},
+ {"d11cnt_rxcrc_off", OFFSETOF(wl_cnt_ver_7_t, d11cnt_rxcrc_off)},
+ {"d11cnt_txnocts_off", OFFSETOF(wl_cnt_ver_7_t, d11cnt_txnocts_off)},
+ {"dmade", OFFSETOF(wl_cnt_ver_7_t, dmade)},
+ {"dmada", OFFSETOF(wl_cnt_ver_7_t, dmada)},
+ {"dmape", OFFSETOF(wl_cnt_ver_7_t, dmape)},
+ {"reset", OFFSETOF(wl_cnt_ver_7_t, reset)},
+ {"tbtt", OFFSETOF(wl_cnt_ver_7_t, tbtt)},
+ {"txdmawar", OFFSETOF(wl_cnt_ver_7_t, txdmawar)},
+ {"pkt_callback_reg_fail", OFFSETOF(wl_cnt_ver_7_t, pkt_callback_reg_fail)},
+ {"d11_txfrag", OFFSETOF(wl_cnt_ver_7_t, txfrag)},
+ {"d11_txmulti", OFFSETOF(wl_cnt_ver_7_t, txmulti)},
+ {"txfail", OFFSETOF(wl_cnt_ver_7_t, txfail)},
+ {"d11_txretry", OFFSETOF(wl_cnt_ver_7_t, txretry)},
+ {"d11_txretrie", OFFSETOF(wl_cnt_ver_7_t, txretrie)},
+ {"rxdup", OFFSETOF(wl_cnt_ver_7_t, rxdup)},
+ {"d11_txrts", OFFSETOF(wl_cnt_ver_7_t, txrts)},
+ {"d11_txnocts", OFFSETOF(wl_cnt_ver_7_t, txnocts)},
+ {"d11_txnoack", OFFSETOF(wl_cnt_ver_7_t, txnoack)},
+ {"d11_rxfrag", OFFSETOF(wl_cnt_ver_7_t, rxfrag)},
+ {"d11_rxmulti", OFFSETOF(wl_cnt_ver_7_t, rxmulti)},
+ {"rxcrc", OFFSETOF(wl_cnt_ver_7_t, rxcrc)},
+ {"d11_txfrmsnt", OFFSETOF(wl_cnt_ver_7_t, txfrmsnt)},
+ {"d11_rxundec", OFFSETOF(wl_cnt_ver_7_t, rxundec)},
+ {"tkipmicfaill", OFFSETOF(wl_cnt_ver_7_t, tkipmicfaill)},
+ {"tkipcntrmsr", OFFSETOF(wl_cnt_ver_7_t, tkipcntrmsr)},
+ {"tkipreplay", OFFSETOF(wl_cnt_ver_7_t, tkipreplay)},
+ {"ccmpfmterr", OFFSETOF(wl_cnt_ver_7_t, ccmpfmterr)},
+ {"ccmpreplay", OFFSETOF(wl_cnt_ver_7_t, ccmpreplay)},
+ {"ccmpundec", OFFSETOF(wl_cnt_ver_7_t, ccmpundec)},
+ {"fourwayfail", OFFSETOF(wl_cnt_ver_7_t, fourwayfail)},
+ {"wepundec", OFFSETOF(wl_cnt_ver_7_t, wepundec)},
+ {"wepicverr", OFFSETOF(wl_cnt_ver_7_t, wepicverr)},
+ {"decsuccess", OFFSETOF(wl_cnt_ver_7_t, decsuccess)},
+ {"tkipicverr", OFFSETOF(wl_cnt_ver_7_t, tkipicverr)},
+ {"wepexcluded", OFFSETOF(wl_cnt_ver_7_t, wepexcluded)},
+ {"txchanrej", OFFSETOF(wl_cnt_ver_7_t, txchanrej)},
+ {"psmwds", OFFSETOF(wl_cnt_ver_7_t, psmwds)},
+ {"phywatchdog", OFFSETOF(wl_cnt_ver_7_t, phywatchdog)},
+ {"prq_entries_handled", OFFSETOF(wl_cnt_ver_7_t, prq_entries_handled)},
+ {"prq_undirected_entries", OFFSETOF(wl_cnt_ver_7_t, prq_undirected_entries)},
+ {"prq_bad_entries", OFFSETOF(wl_cnt_ver_7_t, prq_bad_entries)},
+ {"atim_suppress_count", OFFSETOF(wl_cnt_ver_7_t, atim_suppress_count)},
+ {"bcn_template_not_ready", OFFSETOF(wl_cnt_ver_7_t, bcn_template_not_ready)},
+ {"bcn_template_not_ready_done", OFFSETOF(wl_cnt_ver_7_t, bcn_template_not_ready_done)},
+ {"late_tbtt_dpc", OFFSETOF(wl_cnt_ver_7_t, late_tbtt_dpc)},
+ {"rx1mbps", OFFSETOF(wl_cnt_ver_7_t, rx1mbps)},
+ {"rx2mbps", OFFSETOF(wl_cnt_ver_7_t, rx2mbps)},
+ {"rx5mbps5", OFFSETOF(wl_cnt_ver_7_t, rx5mbps5)},
+ {"rx6mbps", OFFSETOF(wl_cnt_ver_7_t, rx6mbps)},
+ {"rx9mbps", OFFSETOF(wl_cnt_ver_7_t, rx9mbps)},
+ {"rx11mbps", OFFSETOF(wl_cnt_ver_7_t, rx11mbps)},
+ {"rx12mbps", OFFSETOF(wl_cnt_ver_7_t, rx12mbps)},
+ {"rx18mbps", OFFSETOF(wl_cnt_ver_7_t, rx18mbps)},
+ {"rx24mbps", OFFSETOF(wl_cnt_ver_7_t, rx24mbps)},
+ {"rx36mbps", OFFSETOF(wl_cnt_ver_7_t, rx36mbps)},
+ {"rx48mbps", OFFSETOF(wl_cnt_ver_7_t, rx48mbps)},
+ {"rx54mbps", OFFSETOF(wl_cnt_ver_7_t, rx54mbps)},
+ {"rx108mbps", OFFSETOF(wl_cnt_ver_7_t, rx108mbps)},
+ {"rx162mbps", OFFSETOF(wl_cnt_ver_7_t, rx162mbps)},
+ {"rx216mbps", OFFSETOF(wl_cnt_ver_7_t, rx216mbps)},
+ {"rx270mbps", OFFSETOF(wl_cnt_ver_7_t, rx270mbps)},
+ {"rx324mbps", OFFSETOF(wl_cnt_ver_7_t, rx324mbps)},
+ {"rx378mbps", OFFSETOF(wl_cnt_ver_7_t, rx378mbps)},
+ {"rx432mbps", OFFSETOF(wl_cnt_ver_7_t, rx432mbps)},
+ {"rx486mbps", OFFSETOF(wl_cnt_ver_7_t, rx486mbps)},
+ {"rx540mbps", OFFSETOF(wl_cnt_ver_7_t, rx540mbps)},
+ {"rfdisable", OFFSETOF(wl_cnt_ver_7_t, rfdisable)},
+ {"txexptime", OFFSETOF(wl_cnt_ver_7_t, txexptime)},
+ {"txmpdu_sgi", OFFSETOF(wl_cnt_ver_7_t, txmpdu_sgi)},
+ {"rxmpdu_sgi", OFFSETOF(wl_cnt_ver_7_t, rxmpdu_sgi)},
+ {"txmpdu_stbc", OFFSETOF(wl_cnt_ver_7_t, txmpdu_stbc)},
+ {"rxmpdu_stbc", OFFSETOF(wl_cnt_ver_7_t, rxmpdu_stbc)},
+ {"rxundec_mcst", OFFSETOF(wl_cnt_ver_7_t, rxundec_mcst)},
+ {"tkipmicfaill_mcst", OFFSETOF(wl_cnt_ver_7_t, tkipmicfaill_mcst)},
+ {"tkipcntrmsr_mcst", OFFSETOF(wl_cnt_ver_7_t, tkipcntrmsr_mcst)},
+ {"tkipreplay_mcst", OFFSETOF(wl_cnt_ver_7_t, tkipreplay_mcst)},
+ {"ccmpfmterr_mcst", OFFSETOF(wl_cnt_ver_7_t, ccmpfmterr_mcst)},
+ {"ccmpreplay_mcst", OFFSETOF(wl_cnt_ver_7_t, ccmpreplay_mcst)},
+ {"ccmpundec_mcst", OFFSETOF(wl_cnt_ver_7_t, ccmpundec_mcst)},
+ {"fourwayfail_mcst", OFFSETOF(wl_cnt_ver_7_t, fourwayfail_mcst)},
+ {"wepundec_mcst", OFFSETOF(wl_cnt_ver_7_t, wepundec_mcst)},
+ {"wepicverr_mcst", OFFSETOF(wl_cnt_ver_7_t, wepicverr_mcst)},
+ {"decsuccess_mcst", OFFSETOF(wl_cnt_ver_7_t, decsuccess_mcst)},
+ {"tkipicverr_mcst", OFFSETOF(wl_cnt_ver_7_t, tkipicverr_mcst)},
+ {"wepexcluded_mcst", OFFSETOF(wl_cnt_ver_7_t, wepexcluded_mcst)},
+ /* macstat counters */
+ {"txallfrm", OFFSETOF(wl_cnt_ver_7_t, txallfrm)},
+ {"txrtsfrm", OFFSETOF(wl_cnt_ver_7_t, txrtsfrm)},
+ {"txctsfrm", OFFSETOF(wl_cnt_ver_7_t, txctsfrm)},
+ {"txackfrm", OFFSETOF(wl_cnt_ver_7_t, txackfrm)},
+ {"txdnlfrm", OFFSETOF(wl_cnt_ver_7_t, txdnlfrm)},
+ {"txbcnfrm", OFFSETOF(wl_cnt_ver_7_t, txbcnfrm)},
+ {"txfunfl[0]", OFFSETOF(wl_cnt_ver_7_t, txfunfl[0])},
+ {"txfunfl[1]", OFFSETOF(wl_cnt_ver_7_t, txfunfl[1])},
+ {"txfunfl[2]", OFFSETOF(wl_cnt_ver_7_t, txfunfl[2])},
+ {"txfunfl[3]", OFFSETOF(wl_cnt_ver_7_t, txfunfl[3])},
+ {"txfunfl[4]", OFFSETOF(wl_cnt_ver_7_t, txfunfl[4])},
+ {"txfunfl[5]", OFFSETOF(wl_cnt_ver_7_t, txfunfl[5])},
+ {"txtplunfl", OFFSETOF(wl_cnt_ver_7_t, txtplunfl)},
+ {"txphyerror", OFFSETOF(wl_cnt_ver_7_t, txphyerror)},
+ {"pktengrxducast", OFFSETOF(wl_cnt_ver_7_t, pktengrxducast)},
+ {"pktengrxdmcast", OFFSETOF(wl_cnt_ver_7_t, pktengrxdmcast)},
+ {"rxfrmtoolong", OFFSETOF(wl_cnt_ver_7_t, rxfrmtoolong)},
+ {"rxfrmtooshrt", OFFSETOF(wl_cnt_ver_7_t, rxfrmtooshrt)},
+ {"rxanyerr", OFFSETOF(wl_cnt_ver_7_t, rxinvmachdr)},
+ {"rxbadfcs", OFFSETOF(wl_cnt_ver_7_t, rxbadfcs)},
+ {"rxbadplcp", OFFSETOF(wl_cnt_ver_7_t, rxbadplcp)},
+ {"rxcrsglitch", OFFSETOF(wl_cnt_ver_7_t, rxcrsglitch)},
+ {"rxstrt", OFFSETOF(wl_cnt_ver_7_t, rxstrt)},
+ {"rxdtucastmbss", OFFSETOF(wl_cnt_ver_7_t, rxdfrmucastmbss)},
+ {"rxmgucastmbss", OFFSETOF(wl_cnt_ver_7_t, rxmfrmucastmbss)},
+ {"rxctlucast", OFFSETOF(wl_cnt_ver_7_t, rxcfrmucast)},
+ {"rxrtsucast", OFFSETOF(wl_cnt_ver_7_t, rxrtsucast)},
+ {"rxctsucast", OFFSETOF(wl_cnt_ver_7_t, rxctsucast)},
+ {"rxackucast", OFFSETOF(wl_cnt_ver_7_t, rxackucast)},
+ {"rxdtocast", OFFSETOF(wl_cnt_ver_7_t, rxdfrmocast)},
+ {"rxmgocast", OFFSETOF(wl_cnt_ver_7_t, rxmfrmocast)},
+ {"rxctlocast", OFFSETOF(wl_cnt_ver_7_t, rxcfrmocast)},
+ {"rxrtsocast", OFFSETOF(wl_cnt_ver_7_t, rxrtsocast)},
+ {"rxctsocast", OFFSETOF(wl_cnt_ver_7_t, rxctsocast)},
+ {"rxdtmcast", OFFSETOF(wl_cnt_ver_7_t, rxdfrmmcast)},
+ {"rxmgmcast", OFFSETOF(wl_cnt_ver_7_t, rxmfrmmcast)},
+ {"rxctlmcast", OFFSETOF(wl_cnt_ver_7_t, rxcfrmmcast)},
+ {"rxbeaconmbss", OFFSETOF(wl_cnt_ver_7_t, rxbeaconmbss)},
+ {"rxdtucastobss", OFFSETOF(wl_cnt_ver_7_t, rxdfrmucastobss)},
+ {"rxbeaconobss", OFFSETOF(wl_cnt_ver_7_t, rxbeaconobss)},
+ {"rxrsptmout", OFFSETOF(wl_cnt_ver_7_t, rxrsptmout)},
+ {"bcntxcancl", OFFSETOF(wl_cnt_ver_7_t, bcntxcancl)},
+ {"rxf0ovfl", OFFSETOF(wl_cnt_ver_7_t, rxf0ovfl)},
+ {"rxf1ovfl", OFFSETOF(wl_cnt_ver_7_t, rxf1ovfl)},
+ {"rxhlovfl", OFFSETOF(wl_cnt_ver_7_t, rxf2ovfl)},
+ {"missbcn_dbg", OFFSETOF(wl_cnt_ver_7_t, txsfovfl)},
+ {"pmqovfl", OFFSETOF(wl_cnt_ver_7_t, pmqovfl)},
+ {"rxcgprqfrm", OFFSETOF(wl_cnt_ver_7_t, rxcgprqfrm)},
+ {"rxcgprsqovfl", OFFSETOF(wl_cnt_ver_7_t, rxcgprsqovfl)},
+ {"txcgprsfail", OFFSETOF(wl_cnt_ver_7_t, txcgprsfail)},
+ {"txcgprssuc", OFFSETOF(wl_cnt_ver_7_t, txcgprssuc)},
+ {"prs_timeout", OFFSETOF(wl_cnt_ver_7_t, prs_timeout)},
+ {"txrtsfail", OFFSETOF(wl_cnt_ver_7_t, rxnack)},
+ {"txucast", OFFSETOF(wl_cnt_ver_7_t, frmscons)},
+ {"txinrtstxop", OFFSETOF(wl_cnt_ver_7_t, txnack)},
+ {"bphy_rxcrsglitch", OFFSETOF(wl_cnt_ver_7_t, bphy_rxcrsglitch)},
+ {NULL, 0},
+};
+
+static counter_offset_info_t cntr_offset_info_v11[] = {
+ {"txframe", OFFSETOF(wl_cnt_ver_11_t, txframe)},
+ {"txbyte", OFFSETOF(wl_cnt_ver_11_t, txbyte)},
+ {"txretrans", OFFSETOF(wl_cnt_ver_11_t, txretrans)},
+ {"txerror", OFFSETOF(wl_cnt_ver_11_t, txerror)},
+ {"txctl", OFFSETOF(wl_cnt_ver_11_t, txctl)},
+ {"txprshort", OFFSETOF(wl_cnt_ver_11_t, txprshort)},
+ {"txserr", OFFSETOF(wl_cnt_ver_11_t, txserr)},
+ {"txnobuf", OFFSETOF(wl_cnt_ver_11_t, txnobuf)},
+ {"txnoassoc", OFFSETOF(wl_cnt_ver_11_t, txnoassoc)},
+ {"txrunt", OFFSETOF(wl_cnt_ver_11_t, txrunt)},
+ {"txchit", OFFSETOF(wl_cnt_ver_11_t, txchit)},
+ {"txcmiss", OFFSETOF(wl_cnt_ver_11_t, txcmiss)},
+ {"txuflo", OFFSETOF(wl_cnt_ver_11_t, txuflo)},
+ {"txphyerr", OFFSETOF(wl_cnt_ver_11_t, txphyerr)},
+ {"txphycrs", OFFSETOF(wl_cnt_ver_11_t, txphycrs)},
+ {"rxframe", OFFSETOF(wl_cnt_ver_11_t, rxframe)},
+ {"rxbyte", OFFSETOF(wl_cnt_ver_11_t, rxbyte)},
+ {"rxerror", OFFSETOF(wl_cnt_ver_11_t, rxerror)},
+ {"rxctl", OFFSETOF(wl_cnt_ver_11_t, rxctl)},
+ {"rxnobuf", OFFSETOF(wl_cnt_ver_11_t, rxnobuf)},
+ {"rxnondata", OFFSETOF(wl_cnt_ver_11_t, rxnondata)},
+ {"rxbadds", OFFSETOF(wl_cnt_ver_11_t, rxbadds)},
+ {"rxbadcm", OFFSETOF(wl_cnt_ver_11_t, rxbadcm)},
+ {"rxfragerr", OFFSETOF(wl_cnt_ver_11_t, rxfragerr)},
+ {"rxrunt", OFFSETOF(wl_cnt_ver_11_t, rxrunt)},
+ {"rxgiant", OFFSETOF(wl_cnt_ver_11_t, rxgiant)},
+ {"rxnoscb", OFFSETOF(wl_cnt_ver_11_t, rxnoscb)},
+ {"rxbadproto", OFFSETOF(wl_cnt_ver_11_t, rxbadproto)},
+ {"rxbadsrcmac", OFFSETOF(wl_cnt_ver_11_t, rxbadsrcmac)},
+ {"rxbadda", OFFSETOF(wl_cnt_ver_11_t, rxbadda)},
+ {"rxfilter", OFFSETOF(wl_cnt_ver_11_t, rxfilter)},
+ {"rxoflo", OFFSETOF(wl_cnt_ver_11_t, rxoflo)},
+ {"rxuflo[0]", OFFSETOF(wl_cnt_ver_11_t, rxuflo[0])},
+ {"rxuflo[1]", OFFSETOF(wl_cnt_ver_11_t, rxuflo[1])},
+ {"rxuflo[2]", OFFSETOF(wl_cnt_ver_11_t, rxuflo[2])},
+ {"rxuflo[3]", OFFSETOF(wl_cnt_ver_11_t, rxuflo[3])},
+ {"rxuflo[4]", OFFSETOF(wl_cnt_ver_11_t, rxuflo[4])},
+ {"rxuflo[5]", OFFSETOF(wl_cnt_ver_11_t, rxuflo[5])},
+ {"d11cnt_txrts_off", OFFSETOF(wl_cnt_ver_11_t, d11cnt_txrts_off)},
+ {"d11cnt_rxcrc_off", OFFSETOF(wl_cnt_ver_11_t, d11cnt_rxcrc_off)},
+ {"d11cnt_txnocts_off", OFFSETOF(wl_cnt_ver_11_t, d11cnt_txnocts_off)},
+ {"dmade", OFFSETOF(wl_cnt_ver_11_t, dmade)},
+ {"dmada", OFFSETOF(wl_cnt_ver_11_t, dmada)},
+ {"dmape", OFFSETOF(wl_cnt_ver_11_t, dmape)},
+ {"reset", OFFSETOF(wl_cnt_ver_11_t, reset)},
+ {"tbtt", OFFSETOF(wl_cnt_ver_11_t, tbtt)},
+ {"txdmawar", OFFSETOF(wl_cnt_ver_11_t, txdmawar)},
+ {"pkt_callback_reg_fail", OFFSETOF(wl_cnt_ver_11_t, pkt_callback_reg_fail)},
+ {"d11_txfrag", OFFSETOF(wl_cnt_ver_11_t, txfrag)},
+ {"d11_txmulti", OFFSETOF(wl_cnt_ver_11_t, txmulti)},
+ {"txfail", OFFSETOF(wl_cnt_ver_11_t, txfail)},
+ {"d11_txretry", OFFSETOF(wl_cnt_ver_11_t, txretry)},
+ {"d11_txretrie", OFFSETOF(wl_cnt_ver_11_t, txretrie)},
+ {"rxdup", OFFSETOF(wl_cnt_ver_11_t, rxdup)},
+ {"d11_txrts", OFFSETOF(wl_cnt_ver_11_t, txrts)},
+ {"d11_txnocts", OFFSETOF(wl_cnt_ver_11_t, txnocts)},
+ {"d11_txnoack", OFFSETOF(wl_cnt_ver_11_t, txnoack)},
+ {"d11_rxfrag", OFFSETOF(wl_cnt_ver_11_t, rxfrag)},
+ {"d11_rxmulti", OFFSETOF(wl_cnt_ver_11_t, rxmulti)},
+ {"rxcrc", OFFSETOF(wl_cnt_ver_11_t, rxcrc)},
+ {"d11_txfrmsnt", OFFSETOF(wl_cnt_ver_11_t, txfrmsnt)},
+ {"d11_rxundec", OFFSETOF(wl_cnt_ver_11_t, rxundec)},
+ {"tkipmicfaill", OFFSETOF(wl_cnt_ver_11_t, tkipmicfaill)},
+ {"tkipcntrmsr", OFFSETOF(wl_cnt_ver_11_t, tkipcntrmsr)},
+ {"tkipreplay", OFFSETOF(wl_cnt_ver_11_t, tkipreplay)},
+ {"ccmpfmterr", OFFSETOF(wl_cnt_ver_11_t, ccmpfmterr)},
+ {"ccmpreplay", OFFSETOF(wl_cnt_ver_11_t, ccmpreplay)},
+ {"ccmpundec", OFFSETOF(wl_cnt_ver_11_t, ccmpundec)},
+ {"fourwayfail", OFFSETOF(wl_cnt_ver_11_t, fourwayfail)},
+ {"wepundec", OFFSETOF(wl_cnt_ver_11_t, wepundec)},
+ {"wepicverr", OFFSETOF(wl_cnt_ver_11_t, wepicverr)},
+ {"decsuccess", OFFSETOF(wl_cnt_ver_11_t, decsuccess)},
+ {"tkipicverr", OFFSETOF(wl_cnt_ver_11_t, tkipicverr)},
+ {"wepexcluded", OFFSETOF(wl_cnt_ver_11_t, wepexcluded)},
+ {"txchanrej", OFFSETOF(wl_cnt_ver_11_t, txchanrej)},
+ {"psmwds", OFFSETOF(wl_cnt_ver_11_t, psmwds)},
+ {"phywatchdog", OFFSETOF(wl_cnt_ver_11_t, phywatchdog)},
+ {"prq_entries_handled", OFFSETOF(wl_cnt_ver_11_t, prq_entries_handled)},
+ {"prq_undirected_entries", OFFSETOF(wl_cnt_ver_11_t, prq_undirected_entries)},
+ {"prq_bad_entries", OFFSETOF(wl_cnt_ver_11_t, prq_bad_entries)},
+ {"atim_suppress_count", OFFSETOF(wl_cnt_ver_11_t, atim_suppress_count)},
+ {"bcn_template_not_ready", OFFSETOF(wl_cnt_ver_11_t, bcn_template_not_ready)},
+ {"bcn_template_not_ready_done", OFFSETOF(wl_cnt_ver_11_t, bcn_template_not_ready_done)},
+ {"late_tbtt_dpc", OFFSETOF(wl_cnt_ver_11_t, late_tbtt_dpc)},
+ {"rx1mbps", OFFSETOF(wl_cnt_ver_11_t, rx1mbps)},
+ {"rx2mbps", OFFSETOF(wl_cnt_ver_11_t, rx2mbps)},
+ {"rx5mbps5", OFFSETOF(wl_cnt_ver_11_t, rx5mbps5)},
+ {"rx6mbps", OFFSETOF(wl_cnt_ver_11_t, rx6mbps)},
+ {"rx9mbps", OFFSETOF(wl_cnt_ver_11_t, rx9mbps)},
+ {"rx11mbps", OFFSETOF(wl_cnt_ver_11_t, rx11mbps)},
+ {"rx12mbps", OFFSETOF(wl_cnt_ver_11_t, rx12mbps)},
+ {"rx18mbps", OFFSETOF(wl_cnt_ver_11_t, rx18mbps)},
+ {"rx24mbps", OFFSETOF(wl_cnt_ver_11_t, rx24mbps)},
+ {"rx36mbps", OFFSETOF(wl_cnt_ver_11_t, rx36mbps)},
+ {"rx48mbps", OFFSETOF(wl_cnt_ver_11_t, rx48mbps)},
+ {"rx54mbps", OFFSETOF(wl_cnt_ver_11_t, rx54mbps)},
+ {"rx108mbps", OFFSETOF(wl_cnt_ver_11_t, rx108mbps)},
+ {"rx162mbps", OFFSETOF(wl_cnt_ver_11_t, rx162mbps)},
+ {"rx216mbps", OFFSETOF(wl_cnt_ver_11_t, rx216mbps)},
+ {"rx270mbps", OFFSETOF(wl_cnt_ver_11_t, rx270mbps)},
+ {"rx324mbps", OFFSETOF(wl_cnt_ver_11_t, rx324mbps)},
+ {"rx378mbps", OFFSETOF(wl_cnt_ver_11_t, rx378mbps)},
+ {"rx432mbps", OFFSETOF(wl_cnt_ver_11_t, rx432mbps)},
+ {"rx486mbps", OFFSETOF(wl_cnt_ver_11_t, rx486mbps)},
+ {"rx540mbps", OFFSETOF(wl_cnt_ver_11_t, rx540mbps)},
+ {"rfdisable", OFFSETOF(wl_cnt_ver_11_t, rfdisable)},
+ {"txexptime", OFFSETOF(wl_cnt_ver_11_t, txexptime)},
+ {"txmpdu_sgi", OFFSETOF(wl_cnt_ver_11_t, txmpdu_sgi)},
+ {"rxmpdu_sgi", OFFSETOF(wl_cnt_ver_11_t, rxmpdu_sgi)},
+ {"txmpdu_stbc", OFFSETOF(wl_cnt_ver_11_t, txmpdu_stbc)},
+ {"rxmpdu_stbc", OFFSETOF(wl_cnt_ver_11_t, rxmpdu_stbc)},
+ {"rxundec_mcst", OFFSETOF(wl_cnt_ver_11_t, rxundec_mcst)},
+ {"tkipmicfaill_mcst", OFFSETOF(wl_cnt_ver_11_t, tkipmicfaill_mcst)},
+ {"tkipcntrmsr_mcst", OFFSETOF(wl_cnt_ver_11_t, tkipcntrmsr_mcst)},
+ {"tkipreplay_mcst", OFFSETOF(wl_cnt_ver_11_t, tkipreplay_mcst)},
+ {"ccmpfmterr_mcst", OFFSETOF(wl_cnt_ver_11_t, ccmpfmterr_mcst)},
+ {"ccmpreplay_mcst", OFFSETOF(wl_cnt_ver_11_t, ccmpreplay_mcst)},
+ {"ccmpundec_mcst", OFFSETOF(wl_cnt_ver_11_t, ccmpundec_mcst)},
+ {"fourwayfail_mcst", OFFSETOF(wl_cnt_ver_11_t, fourwayfail_mcst)},
+ {"wepundec_mcst", OFFSETOF(wl_cnt_ver_11_t, wepundec_mcst)},
+ {"wepicverr_mcst", OFFSETOF(wl_cnt_ver_11_t, wepicverr_mcst)},
+ {"decsuccess_mcst", OFFSETOF(wl_cnt_ver_11_t, decsuccess_mcst)},
+ {"tkipicverr_mcst", OFFSETOF(wl_cnt_ver_11_t, tkipicverr_mcst)},
+ {"wepexcluded_mcst", OFFSETOF(wl_cnt_ver_11_t, wepexcluded_mcst)},
+ {"dma_hang", OFFSETOF(wl_cnt_ver_11_t, dma_hang)},
+ {"reinit", OFFSETOF(wl_cnt_ver_11_t, reinit)},
+ {"pstatxucast", OFFSETOF(wl_cnt_ver_11_t, pstatxucast)},
+ {"pstatxnoassoc", OFFSETOF(wl_cnt_ver_11_t, pstatxnoassoc)},
+ {"pstarxucast", OFFSETOF(wl_cnt_ver_11_t, pstarxucast)},
+ {"pstarxbcmc", OFFSETOF(wl_cnt_ver_11_t, pstarxbcmc)},
+ {"pstatxbcmc", OFFSETOF(wl_cnt_ver_11_t, pstatxbcmc)},
+ {"cso_passthrough", OFFSETOF(wl_cnt_ver_11_t, cso_passthrough)},
+ {"cso_normal", OFFSETOF(wl_cnt_ver_11_t, cso_normal)},
+ {"chained", OFFSETOF(wl_cnt_ver_11_t, chained)},
+ {"chainedsz1", OFFSETOF(wl_cnt_ver_11_t, chainedsz1)},
+ {"unchained", OFFSETOF(wl_cnt_ver_11_t, unchained)},
+ {"maxchainsz", OFFSETOF(wl_cnt_ver_11_t, maxchainsz)},
+ {"currchainsz", OFFSETOF(wl_cnt_ver_11_t, currchainsz)},
+ {"pciereset", OFFSETOF(wl_cnt_ver_11_t, pciereset)},
+ {"cfgrestore", OFFSETOF(wl_cnt_ver_11_t, cfgrestore)},
+ {"reinit", OFFSETOF(wl_cnt_ver_11_t, reinit)},
+ {"reinitreason[0]", OFFSETOF(wl_cnt_ver_11_t, reinitreason[0])},
+ {"reinitreason[1]", OFFSETOF(wl_cnt_ver_11_t, reinitreason[1])},
+ {"reinitreason[2]", OFFSETOF(wl_cnt_ver_11_t, reinitreason[2])},
+ {"reinitreason[3]", OFFSETOF(wl_cnt_ver_11_t, reinitreason[3])},
+ {"reinitreason[4]", OFFSETOF(wl_cnt_ver_11_t, reinitreason[4])},
+ {"reinitreason[5]", OFFSETOF(wl_cnt_ver_11_t, reinitreason[5])},
+ {"reinitreason[6]", OFFSETOF(wl_cnt_ver_11_t, reinitreason[6])},
+ {"reinitreason[7]", OFFSETOF(wl_cnt_ver_11_t, reinitreason[7])},
+ {"rxrtry", OFFSETOF(wl_cnt_ver_11_t, rxrtry)},
+ {"rxmpdu_mu", OFFSETOF(wl_cnt_ver_11_t, rxmpdu_mu)},
+ {"txbar", OFFSETOF(wl_cnt_ver_11_t, txbar)},
+ {"rxbar", OFFSETOF(wl_cnt_ver_11_t, rxbar)},
+ {"txpspoll", OFFSETOF(wl_cnt_ver_11_t, txpspoll)},
+ {"rxpspoll", OFFSETOF(wl_cnt_ver_11_t, rxpspoll)},
+ {"txnull", OFFSETOF(wl_cnt_ver_11_t, txnull)},
+ {"rxnull", OFFSETOF(wl_cnt_ver_11_t, rxnull)},
+ {"txqosnull", OFFSETOF(wl_cnt_ver_11_t, txqosnull)},
+ {"rxqosnull", OFFSETOF(wl_cnt_ver_11_t, rxqosnull)},
+ {"txassocreq", OFFSETOF(wl_cnt_ver_11_t, txassocreq)},
+ {"rxassocreq", OFFSETOF(wl_cnt_ver_11_t, rxassocreq)},
+ {"txreassocreq", OFFSETOF(wl_cnt_ver_11_t, txreassocreq)},
+ {"rxreassocreq", OFFSETOF(wl_cnt_ver_11_t, rxreassocreq)},
+ {"txdisassoc", OFFSETOF(wl_cnt_ver_11_t, txdisassoc)},
+ {"rxdisassoc", OFFSETOF(wl_cnt_ver_11_t, rxdisassoc)},
+ {"txassocrsp", OFFSETOF(wl_cnt_ver_11_t, txassocrsp)},
+ {"rxassocrsp", OFFSETOF(wl_cnt_ver_11_t, rxassocrsp)},
+ {"txreassocrsp", OFFSETOF(wl_cnt_ver_11_t, txreassocrsp)},
+ {"rxreassocrsp", OFFSETOF(wl_cnt_ver_11_t, rxreassocrsp)},
+ {"txauth", OFFSETOF(wl_cnt_ver_11_t, txauth)},
+ {"rxauth", OFFSETOF(wl_cnt_ver_11_t, rxauth)},
+ {"txdeauth", OFFSETOF(wl_cnt_ver_11_t, txdeauth)},
+ {"rxdeauth", OFFSETOF(wl_cnt_ver_11_t, rxdeauth)},
+ {"txprobereq", OFFSETOF(wl_cnt_ver_11_t, txprobereq)},
+ {"rxprobereq", OFFSETOF(wl_cnt_ver_11_t, rxprobereq)},
+ {"txprobersp", OFFSETOF(wl_cnt_ver_11_t, txprobersp)},
+ {"rxprobersp", OFFSETOF(wl_cnt_ver_11_t, rxprobersp)},
+ {"txaction", OFFSETOF(wl_cnt_ver_11_t, txaction)},
+ {"rxaction", OFFSETOF(wl_cnt_ver_11_t, rxaction)},
+ /* macstats counters */
+ {"txallfrm", OFFSETOF(wl_cnt_ver_11_t, txallfrm)},
+ {"txrtsfrm", OFFSETOF(wl_cnt_ver_11_t, txrtsfrm)},
+ {"txctsfrm", OFFSETOF(wl_cnt_ver_11_t, txctsfrm)},
+ {"txackfrm", OFFSETOF(wl_cnt_ver_11_t, txackfrm)},
+ {"txdnlfrm", OFFSETOF(wl_cnt_ver_11_t, txdnlfrm)},
+ {"txbcnfrm", OFFSETOF(wl_cnt_ver_11_t, txbcnfrm)},
+ {"txfunfl[0]", OFFSETOF(wl_cnt_ver_11_t, txfunfl[0])},
+ {"txfunfl[1]", OFFSETOF(wl_cnt_ver_11_t, txfunfl[1])},
+ {"txfunfl[2]", OFFSETOF(wl_cnt_ver_11_t, txfunfl[2])},
+ {"txfunfl[3]", OFFSETOF(wl_cnt_ver_11_t, txfunfl[3])},
+ {"txfunfl[4]", OFFSETOF(wl_cnt_ver_11_t, txfunfl[4])},
+ {"txfunfl[5]", OFFSETOF(wl_cnt_ver_11_t, txfunfl[5])},
+ {"txampdu", OFFSETOF(wl_cnt_ver_11_t, txfbw)},
+ {"txmpdu", OFFSETOF(wl_cnt_ver_11_t, txmpdu)},
+ {"txtplunfl", OFFSETOF(wl_cnt_ver_11_t, txtplunfl)},
+ {"txphyerror", OFFSETOF(wl_cnt_ver_11_t, txphyerror)},
+ {"pktengrxducast", OFFSETOF(wl_cnt_ver_11_t, pktengrxducast)},
+ {"pktengrxdmcast", OFFSETOF(wl_cnt_ver_11_t, pktengrxdmcast)},
+ {"rxfrmtoolong", OFFSETOF(wl_cnt_ver_11_t, rxfrmtoolong)},
+ {"rxfrmtooshrt", OFFSETOF(wl_cnt_ver_11_t, rxfrmtooshrt)},
+ {"rxanyerr", OFFSETOF(wl_cnt_ver_11_t, rxinvmachdr)},
+ {"rxbadfcs", OFFSETOF(wl_cnt_ver_11_t, rxbadfcs)},
+ {"rxbadplcp", OFFSETOF(wl_cnt_ver_11_t, rxbadplcp)},
+ {"rxcrsglitch", OFFSETOF(wl_cnt_ver_11_t, rxcrsglitch)},
+ {"rxstrt", OFFSETOF(wl_cnt_ver_11_t, rxstrt)},
+ {"rxdtucastmbss", OFFSETOF(wl_cnt_ver_11_t, rxdfrmucastmbss)},
+ {"rxmgucastmbss", OFFSETOF(wl_cnt_ver_11_t, rxmfrmucastmbss)},
+ {"rxctlucast", OFFSETOF(wl_cnt_ver_11_t, rxcfrmucast)},
+ {"rxrtsucast", OFFSETOF(wl_cnt_ver_11_t, rxrtsucast)},
+ {"rxctsucast", OFFSETOF(wl_cnt_ver_11_t, rxctsucast)},
+ {"rxackucast", OFFSETOF(wl_cnt_ver_11_t, rxackucast)},
+ {"rxdtocast", OFFSETOF(wl_cnt_ver_11_t, rxdfrmocast)},
+ {"rxmgocast", OFFSETOF(wl_cnt_ver_11_t, rxmfrmocast)},
+ {"rxctlocast", OFFSETOF(wl_cnt_ver_11_t, rxcfrmocast)},
+ {"rxrtsocast", OFFSETOF(wl_cnt_ver_11_t, rxrtsocast)},
+ {"rxctsocast", OFFSETOF(wl_cnt_ver_11_t, rxctsocast)},
+ {"rxdtmcast", OFFSETOF(wl_cnt_ver_11_t, rxdfrmmcast)},
+ {"rxmgmcast", OFFSETOF(wl_cnt_ver_11_t, rxmfrmmcast)},
+ {"rxctlmcast", OFFSETOF(wl_cnt_ver_11_t, rxcfrmmcast)},
+ {"rxbeaconmbss", OFFSETOF(wl_cnt_ver_11_t, rxbeaconmbss)},
+ {"rxdtucastobss", OFFSETOF(wl_cnt_ver_11_t, rxdfrmucastobss)},
+ {"rxbeaconobss", OFFSETOF(wl_cnt_ver_11_t, rxbeaconobss)},
+ {"rxrsptmout", OFFSETOF(wl_cnt_ver_11_t, rxrsptmout)},
+ {"bcntxcancl", OFFSETOF(wl_cnt_ver_11_t, bcntxcancl)},
+ {"rxnodelim", OFFSETOF(wl_cnt_ver_11_t, rxnodelim)},
+ {"rxf0ovfl", OFFSETOF(wl_cnt_ver_11_t, rxf0ovfl)},
+ {"rxf1ovfl", OFFSETOF(wl_cnt_ver_11_t, rxf1ovfl)},
+ {"rxhlovfl", OFFSETOF(wl_cnt_ver_11_t, rxf2ovfl)},
+ {"missbcn_dbg", OFFSETOF(wl_cnt_ver_11_t, txsfovfl)},
+ {"pmqovfl", OFFSETOF(wl_cnt_ver_11_t, pmqovfl)},
+ {"rxcgprqfrm", OFFSETOF(wl_cnt_ver_11_t, rxcgprqfrm)},
+ {"rxcgprsqovfl", OFFSETOF(wl_cnt_ver_11_t, rxcgprsqovfl)},
+ {"txcgprsfail", OFFSETOF(wl_cnt_ver_11_t, txcgprsfail)},
+ {"txcgprssuc", OFFSETOF(wl_cnt_ver_11_t, txcgprssuc)},
+ {"prs_timeout", OFFSETOF(wl_cnt_ver_11_t, prs_timeout)},
+ {"txrtsfail", OFFSETOF(wl_cnt_ver_11_t, rxnack)},
+ {"txucast", OFFSETOF(wl_cnt_ver_11_t, frmscons)},
+ {"txinrtstxop", OFFSETOF(wl_cnt_ver_11_t, txnack)},
+ {"rxback", OFFSETOF(wl_cnt_ver_11_t, rxback)},
+ {"txback", OFFSETOF(wl_cnt_ver_11_t, txback)},
+ {"bphy_rxcrsglitch", OFFSETOF(wl_cnt_ver_11_t, bphy_rxcrsglitch)},
+ {"rxdrop20s", OFFSETOF(wl_cnt_ver_11_t, rxdrop20s)},
+ {"rxtoolate", OFFSETOF(wl_cnt_ver_11_t, rxtoolate)},
+ {"bphy_badplcp", OFFSETOF(wl_cnt_ver_11_t, bphy_badplcp)},
+ {NULL, 0},
+};
+
+
+#define OFFSET_MCST_V30(X) (OFFSETOF(wl_cnt_ge40mcst_v1_t, X) +\
+ sizeof(wl_cnt_wlc_t))
+#define OFFSET_RIRNS_V30(X) (sizeof(wl_cnt_wlc_t) +\
+ WL_CNT_MCST_STRUCT_SZ + OFFSETOF(reinit_rsns_t, X))
+static counter_offset_info_t cntr_offset_info_v30[] = {
+ /* wl counters */
+ {"txframe", OFFSETOF(wl_cnt_wlc_t, txframe)},
+ {"txbyte", OFFSETOF(wl_cnt_wlc_t, txbyte)},
+ {"txretrans", OFFSETOF(wl_cnt_wlc_t, txretrans)},
+ {"txerror", OFFSETOF(wl_cnt_wlc_t, txerror)},
+ {"txctl", OFFSETOF(wl_cnt_wlc_t, txctl)},
+ {"txprshort", OFFSETOF(wl_cnt_wlc_t, txprshort)},
+ {"txserr", OFFSETOF(wl_cnt_wlc_t, txserr)},
+ {"txnobuf", OFFSETOF(wl_cnt_wlc_t, txnobuf)},
+ {"txnoassoc", OFFSETOF(wl_cnt_wlc_t, txnoassoc)},
+ {"txrunt", OFFSETOF(wl_cnt_wlc_t, txrunt)},
+ {"txchit", OFFSETOF(wl_cnt_wlc_t, txchit)},
+ {"txcmiss", OFFSETOF(wl_cnt_wlc_t, txcmiss)},
+ {"txuflo", OFFSETOF(wl_cnt_wlc_t, txuflo)},
+ {"txphyerr", OFFSETOF(wl_cnt_wlc_t, txphyerr)},
+ {"txphycrs", OFFSETOF(wl_cnt_wlc_t, txphycrs)},
+ {"rxframe", OFFSETOF(wl_cnt_wlc_t, rxframe)},
+ {"rxbyte", OFFSETOF(wl_cnt_wlc_t, rxbyte)},
+ {"rxerror", OFFSETOF(wl_cnt_wlc_t, rxerror)},
+ {"rxctl", OFFSETOF(wl_cnt_wlc_t, rxctl)},
+ {"rxnobuf", OFFSETOF(wl_cnt_wlc_t, rxnobuf)},
+ {"rxnondata", OFFSETOF(wl_cnt_wlc_t, rxnondata)},
+ {"rxbadds", OFFSETOF(wl_cnt_wlc_t, rxbadds)},
+ {"rxbadcm", OFFSETOF(wl_cnt_wlc_t, rxbadcm)},
+ {"rxfragerr", OFFSETOF(wl_cnt_wlc_t, rxfragerr)},
+ {"rxrunt", OFFSETOF(wl_cnt_wlc_t, rxrunt)},
+ {"rxgiant", OFFSETOF(wl_cnt_wlc_t, rxgiant)},
+ {"rxnoscb", OFFSETOF(wl_cnt_wlc_t, rxnoscb)},
+ {"rxbadproto", OFFSETOF(wl_cnt_wlc_t, rxbadproto)},
+ {"rxbadsrcmac", OFFSETOF(wl_cnt_wlc_t, rxbadsrcmac)},
+ {"rxbadda", OFFSETOF(wl_cnt_wlc_t, rxbadda)},
+ {"rxfilter", OFFSETOF(wl_cnt_wlc_t, rxfilter)},
+ {"rxoflo", OFFSETOF(wl_cnt_wlc_t, rxoflo)},
+ {"rxuflo[0]", OFFSETOF(wl_cnt_wlc_t, rxuflo[0])},
+ {"rxuflo[1]", OFFSETOF(wl_cnt_wlc_t, rxuflo[1])},
+ {"rxuflo[2]", OFFSETOF(wl_cnt_wlc_t, rxuflo[2])},
+ {"rxuflo[3]", OFFSETOF(wl_cnt_wlc_t, rxuflo[3])},
+ {"rxuflo[4]", OFFSETOF(wl_cnt_wlc_t, rxuflo[4])},
+ {"rxuflo[5]", OFFSETOF(wl_cnt_wlc_t, rxuflo[5])},
+ {"d11cnt_txrts_off", OFFSETOF(wl_cnt_wlc_t, d11cnt_txrts_off)},
+ {"d11cnt_rxcrc_off", OFFSETOF(wl_cnt_wlc_t, d11cnt_rxcrc_off)},
+ {"d11cnt_txnocts_off", OFFSETOF(wl_cnt_wlc_t, d11cnt_txnocts_off)},
+ {"dmade", OFFSETOF(wl_cnt_wlc_t, dmade)},
+ {"dmada", OFFSETOF(wl_cnt_wlc_t, dmada)},
+ {"dmape", OFFSETOF(wl_cnt_wlc_t, dmape)},
+ {"reset", OFFSETOF(wl_cnt_wlc_t, reset)},
+ {"tbtt", OFFSETOF(wl_cnt_wlc_t, tbtt)},
+ {"txdmawar", OFFSETOF(wl_cnt_wlc_t, txdmawar)},
+ {"pkt_callback_reg_fail", OFFSETOF(wl_cnt_wlc_t, pkt_callback_reg_fail)},
+ {"d11_txfrag", OFFSETOF(wl_cnt_wlc_t, txfrag)},
+ {"d11_txmulti", OFFSETOF(wl_cnt_wlc_t, txmulti)},
+ {"txfail", OFFSETOF(wl_cnt_wlc_t, txfail)},
+ {"d11_txretry", OFFSETOF(wl_cnt_wlc_t, txretry)},
+ {"d11_txretrie", OFFSETOF(wl_cnt_wlc_t, txretrie)},
+ {"rxdup", OFFSETOF(wl_cnt_wlc_t, rxdup)},
+ {"d11_txrts", OFFSETOF(wl_cnt_wlc_t, txrts)},
+ {"d11_txnocts", OFFSETOF(wl_cnt_wlc_t, txnocts)},
+ {"d11_txnoack", OFFSETOF(wl_cnt_wlc_t, txnoack)},
+ {"d11_rxfrag", OFFSETOF(wl_cnt_wlc_t, rxfrag)},
+ {"d11_rxmulti", OFFSETOF(wl_cnt_wlc_t, rxmulti)},
+ {"rxcrc", OFFSETOF(wl_cnt_wlc_t, rxcrc)},
+ {"d11_txfrmsnt", OFFSETOF(wl_cnt_wlc_t, txfrmsnt)},
+ {"d11_rxundec", OFFSETOF(wl_cnt_wlc_t, rxundec)},
+ {"tkipmicfaill", OFFSETOF(wl_cnt_wlc_t, tkipmicfaill)},
+ {"tkipcntrmsr", OFFSETOF(wl_cnt_wlc_t, tkipcntrmsr)},
+ {"tkipreplay", OFFSETOF(wl_cnt_wlc_t, tkipreplay)},
+ {"ccmpfmterr", OFFSETOF(wl_cnt_wlc_t, ccmpfmterr)},
+ {"ccmpreplay", OFFSETOF(wl_cnt_wlc_t, ccmpreplay)},
+ {"ccmpundec", OFFSETOF(wl_cnt_wlc_t, ccmpundec)},
+ {"fourwayfail", OFFSETOF(wl_cnt_wlc_t, fourwayfail)},
+ {"wepundec", OFFSETOF(wl_cnt_wlc_t, wepundec)},
+ {"wepicverr", OFFSETOF(wl_cnt_wlc_t, wepicverr)},
+ {"decsuccess", OFFSETOF(wl_cnt_wlc_t, decsuccess)},
+ {"tkipicverr", OFFSETOF(wl_cnt_wlc_t, tkipicverr)},
+ {"wepexcluded", OFFSETOF(wl_cnt_wlc_t, wepexcluded)},
+ {"txchanrej", OFFSETOF(wl_cnt_wlc_t, txchanrej)},
+ {"psmwds", OFFSETOF(wl_cnt_wlc_t, psmwds)},
+ {"phywatchdog", OFFSETOF(wl_cnt_wlc_t, phywatchdog)},
+ {"prq_entries_handled", OFFSETOF(wl_cnt_wlc_t, prq_entries_handled)},
+ {"prq_undirected_entries", OFFSETOF(wl_cnt_wlc_t, prq_undirected_entries)},
+ {"prq_bad_entries", OFFSETOF(wl_cnt_wlc_t, prq_bad_entries)},
+ {"atim_suppress_count", OFFSETOF(wl_cnt_wlc_t, atim_suppress_count)},
+ {"bcn_template_not_ready", OFFSETOF(wl_cnt_wlc_t, bcn_template_not_ready)},
+ {"bcn_template_not_ready_done", OFFSETOF(wl_cnt_wlc_t, bcn_template_not_ready_done)},
+ {"late_tbtt_dpc", OFFSETOF(wl_cnt_wlc_t, late_tbtt_dpc)},
+ {"rx1mbps", OFFSETOF(wl_cnt_wlc_t, rx1mbps)},
+ {"rx2mbps", OFFSETOF(wl_cnt_wlc_t, rx2mbps)},
+ {"rx5mbps5", OFFSETOF(wl_cnt_wlc_t, rx5mbps5)},
+ {"rx6mbps", OFFSETOF(wl_cnt_wlc_t, rx6mbps)},
+ {"rx9mbps", OFFSETOF(wl_cnt_wlc_t, rx9mbps)},
+ {"rx11mbps", OFFSETOF(wl_cnt_wlc_t, rx11mbps)},
+ {"rx12mbps", OFFSETOF(wl_cnt_wlc_t, rx12mbps)},
+ {"rx18mbps", OFFSETOF(wl_cnt_wlc_t, rx18mbps)},
+ {"rx24mbps", OFFSETOF(wl_cnt_wlc_t, rx24mbps)},
+ {"rx36mbps", OFFSETOF(wl_cnt_wlc_t, rx36mbps)},
+ {"rx48mbps", OFFSETOF(wl_cnt_wlc_t, rx48mbps)},
+ {"rx54mbps", OFFSETOF(wl_cnt_wlc_t, rx54mbps)},
+ {"rx108mbps", OFFSETOF(wl_cnt_wlc_t, rx108mbps)},
+ {"rx162mbps", OFFSETOF(wl_cnt_wlc_t, rx162mbps)},
+ {"rx216mbps", OFFSETOF(wl_cnt_wlc_t, rx216mbps)},
+ {"rx270mbps", OFFSETOF(wl_cnt_wlc_t, rx270mbps)},
+ {"rx324mbps", OFFSETOF(wl_cnt_wlc_t, rx324mbps)},
+ {"rx378mbps", OFFSETOF(wl_cnt_wlc_t, rx378mbps)},
+ {"rx432mbps", OFFSETOF(wl_cnt_wlc_t, rx432mbps)},
+ {"rx486mbps", OFFSETOF(wl_cnt_wlc_t, rx486mbps)},
+ {"rx540mbps", OFFSETOF(wl_cnt_wlc_t, rx540mbps)},
+ {"rfdisable", OFFSETOF(wl_cnt_wlc_t, rfdisable)},
+ {"txexptime", OFFSETOF(wl_cnt_wlc_t, txexptime)},
+ {"txmpdu_sgi", OFFSETOF(wl_cnt_wlc_t, txmpdu_sgi)},
+ {"rxmpdu_sgi", OFFSETOF(wl_cnt_wlc_t, rxmpdu_sgi)},
+ {"txmpdu_stbc", OFFSETOF(wl_cnt_wlc_t, txmpdu_stbc)},
+ {"rxmpdu_stbc", OFFSETOF(wl_cnt_wlc_t, rxmpdu_stbc)},
+ {"rxundec_mcst", OFFSETOF(wl_cnt_wlc_t, rxundec_mcst)},
+ {"tkipmicfaill_mcst", OFFSETOF(wl_cnt_wlc_t, tkipmicfaill_mcst)},
+ {"tkipcntrmsr_mcst", OFFSETOF(wl_cnt_wlc_t, tkipcntrmsr_mcst)},
+ {"tkipreplay_mcst", OFFSETOF(wl_cnt_wlc_t, tkipreplay_mcst)},
+ {"ccmpfmterr_mcst", OFFSETOF(wl_cnt_wlc_t, ccmpfmterr_mcst)},
+ {"ccmpreplay_mcst", OFFSETOF(wl_cnt_wlc_t, ccmpreplay_mcst)},
+ {"ccmpundec_mcst", OFFSETOF(wl_cnt_wlc_t, ccmpundec_mcst)},
+ {"fourwayfail_mcst", OFFSETOF(wl_cnt_wlc_t, fourwayfail_mcst)},
+ {"wepundec_mcst", OFFSETOF(wl_cnt_wlc_t, wepundec_mcst)},
+ {"wepicverr_mcst", OFFSETOF(wl_cnt_wlc_t, wepicverr_mcst)},
+ {"decsuccess_mcst", OFFSETOF(wl_cnt_wlc_t, decsuccess_mcst)},
+ {"tkipicverr_mcst", OFFSETOF(wl_cnt_wlc_t, tkipicverr_mcst)},
+ {"wepexcluded_mcst", OFFSETOF(wl_cnt_wlc_t, wepexcluded_mcst)},
+ {"dma_hang", OFFSETOF(wl_cnt_wlc_t, dma_hang)},
+ {"reinit", OFFSETOF(wl_cnt_wlc_t, reinit)},
+ {"pstatxucast", OFFSETOF(wl_cnt_wlc_t, pstatxucast)},
+ {"pstatxnoassoc", OFFSETOF(wl_cnt_wlc_t, pstatxnoassoc)},
+ {"pstarxucast", OFFSETOF(wl_cnt_wlc_t, pstarxucast)},
+ {"pstarxbcmc", OFFSETOF(wl_cnt_wlc_t, pstarxbcmc)},
+ {"pstatxbcmc", OFFSETOF(wl_cnt_wlc_t, pstatxbcmc)},
+ {"cso_passthrough", OFFSETOF(wl_cnt_wlc_t, cso_passthrough)},
+ {"cso_normal", OFFSETOF(wl_cnt_wlc_t, cso_normal)},
+ {"chained", OFFSETOF(wl_cnt_wlc_t, chained)},
+ {"chainedsz1", OFFSETOF(wl_cnt_wlc_t, chainedsz1)},
+ {"unchained", OFFSETOF(wl_cnt_wlc_t, unchained)},
+ {"maxchainsz", OFFSETOF(wl_cnt_wlc_t, maxchainsz)},
+ {"currchainsz", OFFSETOF(wl_cnt_wlc_t, currchainsz)},
+ {"pciereset", OFFSETOF(wl_cnt_wlc_t, pciereset)},
+ {"cfgrestore", OFFSETOF(wl_cnt_wlc_t, cfgrestore)},
+ {"reinitreason[0]", OFFSETOF(wl_cnt_wlc_t, reinitreason[0])},
+ {"reinitreason[1]", OFFSETOF(wl_cnt_wlc_t, reinitreason[1])},
+ {"reinitreason[2]", OFFSETOF(wl_cnt_wlc_t, reinitreason[2])},
+ {"reinitreason[3]", OFFSETOF(wl_cnt_wlc_t, reinitreason[3])},
+ {"reinitreason[4]", OFFSETOF(wl_cnt_wlc_t, reinitreason[4])},
+ {"reinitreason[5]", OFFSETOF(wl_cnt_wlc_t, reinitreason[5])},
+ {"reinitreason[6]", OFFSETOF(wl_cnt_wlc_t, reinitreason[6])},
+ {"reinitreason[7]", OFFSETOF(wl_cnt_wlc_t, reinitreason[7])},
+ {"rxrtry", OFFSETOF(wl_cnt_wlc_t, rxrtry)},
+ {"rxmpdu_mu", OFFSETOF(wl_cnt_wlc_t, rxmpdu_mu)},
+ {"txbar", OFFSETOF(wl_cnt_wlc_t, txbar)},
+ {"rxbar", OFFSETOF(wl_cnt_wlc_t, rxbar)},
+ {"txpspoll", OFFSETOF(wl_cnt_wlc_t, txpspoll)},
+ {"rxpspoll", OFFSETOF(wl_cnt_wlc_t, rxpspoll)},
+ {"txnull", OFFSETOF(wl_cnt_wlc_t, txnull)},
+ {"rxnull", OFFSETOF(wl_cnt_wlc_t, rxnull)},
+ {"txqosnull", OFFSETOF(wl_cnt_wlc_t, txqosnull)},
+ {"rxqosnull", OFFSETOF(wl_cnt_wlc_t, rxqosnull)},
+ {"txassocreq", OFFSETOF(wl_cnt_wlc_t, txassocreq)},
+ {"rxassocreq", OFFSETOF(wl_cnt_wlc_t, rxassocreq)},
+ {"txreassocreq", OFFSETOF(wl_cnt_wlc_t, txreassocreq)},
+ {"rxreassocreq", OFFSETOF(wl_cnt_wlc_t, rxreassocreq)},
+ {"txdisassoc", OFFSETOF(wl_cnt_wlc_t, txdisassoc)},
+ {"rxdisassoc", OFFSETOF(wl_cnt_wlc_t, rxdisassoc)},
+ {"txassocrsp", OFFSETOF(wl_cnt_wlc_t, txassocrsp)},
+ {"rxassocrsp", OFFSETOF(wl_cnt_wlc_t, rxassocrsp)},
+ {"txreassocrsp", OFFSETOF(wl_cnt_wlc_t, txreassocrsp)},
+ {"rxreassocrsp", OFFSETOF(wl_cnt_wlc_t, rxreassocrsp)},
+ {"txauth", OFFSETOF(wl_cnt_wlc_t, txauth)},
+ {"rxauth", OFFSETOF(wl_cnt_wlc_t, rxauth)},
+ {"txdeauth", OFFSETOF(wl_cnt_wlc_t, txdeauth)},
+ {"rxdeauth", OFFSETOF(wl_cnt_wlc_t, rxdeauth)},
+ {"txprobereq", OFFSETOF(wl_cnt_wlc_t, txprobereq)},
+ {"rxprobereq", OFFSETOF(wl_cnt_wlc_t, rxprobereq)},
+ {"txprobersp", OFFSETOF(wl_cnt_wlc_t, txprobersp)},
+ {"rxprobersp", OFFSETOF(wl_cnt_wlc_t, rxprobersp)},
+ {"txaction", OFFSETOF(wl_cnt_wlc_t, txaction)},
+ {"rxaction", OFFSETOF(wl_cnt_wlc_t, rxaction)},
+ {"ampdu_wds", OFFSETOF(wl_cnt_wlc_t, ampdu_wds)},
+ {"txlost", OFFSETOF(wl_cnt_wlc_t, txlost)},
+ {"txdatamcast", OFFSETOF(wl_cnt_wlc_t, txdatamcast)},
+ {"txdatabcast", OFFSETOF(wl_cnt_wlc_t, txdatabcast)},
+ {"psmxwds", OFFSETOF(wl_cnt_wlc_t, psmxwds)},
+ {"rxback", OFFSETOF(wl_cnt_wlc_t, rxback)},
+ {"txback", OFFSETOF(wl_cnt_wlc_t, txback)},
+ {"p2p_tbtt", OFFSETOF(wl_cnt_wlc_t, p2p_tbtt)},
+ {"p2p_tbtt_miss", OFFSETOF(wl_cnt_wlc_t, p2p_tbtt_miss)},
+ /* macstats counters */
+ {"txallfrm", OFFSET_MCST_V30(txallfrm)},
+ {"txrtsfrm", OFFSET_MCST_V30(txrtsfrm)},
+ {"txctsfrm", OFFSET_MCST_V30(txctsfrm)},
+ {"txackfrm", OFFSET_MCST_V30(txackfrm)},
+ {"txdnlfrm", OFFSET_MCST_V30(txdnlfrm)},
+ {"txbcnfrm", OFFSET_MCST_V30(txbcnfrm)},
+ {"txfunfl[0]", OFFSET_MCST_V30(txfunfl[0])},
+ {"txfunfl[1]", OFFSET_MCST_V30(txfunfl[1])},
+ {"txfunfl[2]", OFFSET_MCST_V30(txfunfl[2])},
+ {"txfunfl[3]", OFFSET_MCST_V30(txfunfl[3])},
+ {"txfunfl[4]", OFFSET_MCST_V30(txfunfl[4])},
+ {"txfunfl[5]", OFFSET_MCST_V30(txfunfl[5])},
+ {"txampdu", OFFSET_MCST_V30(txampdu)},
+ {"txmpdu", OFFSET_MCST_V30(txmpdu)},
+ {"txtplunfl", OFFSET_MCST_V30(txtplunfl)},
+ {"txphyerror", OFFSET_MCST_V30(txphyerror)},
+ {"pktengrxducast", OFFSET_MCST_V30(pktengrxducast)},
+ {"pktengrxdmcast", OFFSET_MCST_V30(pktengrxdmcast)},
+ {"rxfrmtoolong", OFFSET_MCST_V30(rxfrmtoolong)},
+ {"rxfrmtooshrt", OFFSET_MCST_V30(rxfrmtooshrt)},
+ {"rxanyerr", OFFSET_MCST_V30(rxanyerr)},
+ {"rxbadfcs", OFFSET_MCST_V30(rxbadfcs)},
+ {"rxbadplcp", OFFSET_MCST_V30(rxbadplcp)},
+ {"rxcrsglitch", OFFSET_MCST_V30(rxcrsglitch)},
+ {"rxstrt", OFFSET_MCST_V30(rxstrt)},
+ {"rxdtucastmbss", OFFSET_MCST_V30(rxdtucastmbss)},
+ {"rxmgucastmbss", OFFSET_MCST_V30(rxmgucastmbss)},
+ {"rxctlucast", OFFSET_MCST_V30(rxctlucast)},
+ {"rxrtsucast", OFFSET_MCST_V30(rxrtsucast)},
+ {"rxctsucast", OFFSET_MCST_V30(rxctsucast)},
+ {"rxackucast", OFFSET_MCST_V30(rxackucast)},
+ {"rxdtocast", OFFSET_MCST_V30(rxdtocast)},
+ {"rxmgocast", OFFSET_MCST_V30(rxmgocast)},
+ {"rxctlocast", OFFSET_MCST_V30(rxctlocast)},
+ {"rxrtsocast", OFFSET_MCST_V30(rxrtsocast)},
+ {"rxctsocast", OFFSET_MCST_V30(rxctsocast)},
+ {"rxdtmcast", OFFSET_MCST_V30(rxdtmcast)},
+ {"rxmgmcast", OFFSET_MCST_V30(rxmgmcast)},
+ {"rxctlmcast", OFFSET_MCST_V30(rxctlmcast)},
+ {"rxbeaconmbss", OFFSET_MCST_V30(rxbeaconmbss)},
+ {"rxdtucastobss", OFFSET_MCST_V30(rxdtucastobss)},
+ {"rxbeaconobss", OFFSET_MCST_V30(rxbeaconobss)},
+ {"rxrsptmout", OFFSET_MCST_V30(rxrsptmout)},
+ {"bcntxcancl", OFFSET_MCST_V30(bcntxcancl)},
+ {"rxnodelim", OFFSET_MCST_V30(rxnodelim)},
+ {"rxf0ovfl", OFFSET_MCST_V30(rxf0ovfl)},
+ {"rxf1ovfl", OFFSET_MCST_V30(rxf1ovfl)},
+ {"rxhlovfl", OFFSET_MCST_V30(rxhlovfl)},
+ {"missbcn_dbg", OFFSET_MCST_V30(missbcn_dbg)},
+ {"pmqovfl", OFFSET_MCST_V30(pmqovfl)},
+ {"rxcgprqfrm", OFFSET_MCST_V30(rxcgprqfrm)},
+ {"rxcgprsqovfl", OFFSET_MCST_V30(rxcgprsqovfl)},
+ {"txcgprsfail", OFFSET_MCST_V30(txcgprsfail)},
+ {"txcgprssuc", OFFSET_MCST_V30(txcgprssuc)},
+ {"prs_timeout", OFFSET_MCST_V30(prs_timeout)},
+ {"txrtsfail", OFFSET_MCST_V30(txrtsfail)},
+ {"txucast", OFFSET_MCST_V30(txucast)},
+ {"txinrtstxop", OFFSET_MCST_V30(txinrtstxop)},
+ {"rxback", OFFSET_MCST_V30(rxback)},
+ {"txback", OFFSET_MCST_V30(txback)},
+ {"bphy_rxcrsglitch", OFFSET_MCST_V30(bphy_rxcrsglitch)},
+ {"rxdrop20s", OFFSET_MCST_V30(rxdrop20s)},
+ {"rxtoolate", OFFSET_MCST_V30(rxtoolate)},
+ {"bphy_badplcp", OFFSET_MCST_V30(bphy_badplcp)},
+ /* reinitreason counter */
+ {"reinitreason_counts[0]", OFFSET_RIRNS_V30(rsn[0])},
+ {"reinitreason_counts[1]", OFFSET_RIRNS_V30(rsn[1])},
+ {"reinitreason_counts[2]", OFFSET_RIRNS_V30(rsn[2])},
+ {"reinitreason_counts[3]", OFFSET_RIRNS_V30(rsn[3])},
+ {"reinitreason_counts[4]", OFFSET_RIRNS_V30(rsn[4])},
+ {"reinitreason_counts[5]", OFFSET_RIRNS_V30(rsn[5])},
+ {"reinitreason_counts[6]", OFFSET_RIRNS_V30(rsn[6])},
+ {"reinitreason_counts[7]", OFFSET_RIRNS_V30(rsn[7])},
+ {"reinitreason_counts[8]", OFFSET_RIRNS_V30(rsn[8])},
+ {"reinitreason_counts[9]", OFFSET_RIRNS_V30(rsn[9])},
+ {"reinitreason_counts[10]", OFFSET_RIRNS_V30(rsn[10])},
+ {"reinitreason_counts[11]", OFFSET_RIRNS_V30(rsn[11])},
+ {"reinitreason_counts[12]", OFFSET_RIRNS_V30(rsn[12])},
+ {"reinitreason_counts[13]", OFFSET_RIRNS_V30(rsn[13])},
+ {"reinitreason_counts[14]", OFFSET_RIRNS_V30(rsn[14])},
+ {"reinitreason_counts[15]", OFFSET_RIRNS_V30(rsn[15])},
+ {"reinitreason_counts[16]", OFFSET_RIRNS_V30(rsn[16])},
+ {"reinitreason_counts[17]", OFFSET_RIRNS_V30(rsn[17])},
+ {"reinitreason_counts[18]", OFFSET_RIRNS_V30(rsn[18])},
+ {"reinitreason_counts[19]", OFFSET_RIRNS_V30(rsn[19])},
+ {"reinitreason_counts[20]", OFFSET_RIRNS_V30(rsn[20])},
+ {"reinitreason_counts[21]", OFFSET_RIRNS_V30(rsn[21])},
+ {"reinitreason_counts[22]", OFFSET_RIRNS_V30(rsn[22])},
+ {"reinitreason_counts[23]", OFFSET_RIRNS_V30(rsn[23])},
+ {"reinitreason_counts[24]", OFFSET_RIRNS_V30(rsn[24])},
+ {"reinitreason_counts[25]", OFFSET_RIRNS_V30(rsn[25])},
+ {"reinitreason_counts[26]", OFFSET_RIRNS_V30(rsn[26])},
+ {"reinitreason_counts[27]", OFFSET_RIRNS_V30(rsn[27])},
+ {"reinitreason_counts[28]", OFFSET_RIRNS_V30(rsn[28])},
+ {"reinitreason_counts[29]", OFFSET_RIRNS_V30(rsn[29])},
+ {"reinitreason_counts[30]", OFFSET_RIRNS_V30(rsn[30])},
+ {"reinitreason_counts[31]", OFFSET_RIRNS_V30(rsn[31])},
+ {"reinitreason_counts[32]", OFFSET_RIRNS_V30(rsn[32])},
+ {"reinitreason_counts[33]", OFFSET_RIRNS_V30(rsn[33])},
+ {"reinitreason_counts[34]", OFFSET_RIRNS_V30(rsn[34])},
+ {"reinitreason_counts[35]", OFFSET_RIRNS_V30(rsn[35])},
+ {"reinitreason_counts[36]", OFFSET_RIRNS_V30(rsn[36])},
+ {"reinitreason_counts[37]", OFFSET_RIRNS_V30(rsn[37])},
+ {"reinitreason_counts[38]", OFFSET_RIRNS_V30(rsn[38])},
+ {"reinitreason_counts[39]", OFFSET_RIRNS_V30(rsn[39])},
+ {"reinitreason_counts[40]", OFFSET_RIRNS_V30(rsn[40])},
+ {"reinitreason_counts[41]", OFFSET_RIRNS_V30(rsn[41])},
+ {"reinitreason_counts[42]", OFFSET_RIRNS_V30(rsn[42])},
+ {"reinitreason_counts[43]", OFFSET_RIRNS_V30(rsn[43])},
+ {"reinitreason_counts[44]", OFFSET_RIRNS_V30(rsn[44])},
+ {"reinitreason_counts[45]", OFFSET_RIRNS_V30(rsn[45])},
+ {"reinitreason_counts[46]", OFFSET_RIRNS_V30(rsn[46])},
+ {"reinitreason_counts[47]", OFFSET_RIRNS_V30(rsn[47])},
+ {"reinitreason_counts[48]", OFFSET_RIRNS_V30(rsn[48])},
+ {"reinitreason_counts[49]", OFFSET_RIRNS_V30(rsn[49])},
+ {"reinitreason_counts[50]", OFFSET_RIRNS_V30(rsn[50])},
+ {"reinitreason_counts[51]", OFFSET_RIRNS_V30(rsn[51])},
+ {NULL, 0},
+};
+
+
+static ver_to_cntr_offset_info_t ver_to_cntr_offset_info_tbl[] = {
+ {&cntr_offset_info_v6[0], 6},
+ {&cntr_offset_info_v7[0], 7},
+ {&cntr_offset_info_v7[0], 7001},
+ {&cntr_offset_info_v11[0], 11},
+ {&cntr_offset_info_v30[0], 30},
+ {NULL, 0}
+};
+
+static const struct cnt_properties_s cnt_props[] = {
+ {"active_ant", 0},
+ {"ampdu_wds", CAT_AMPDU},
+ {"auto_en", 0},
+ {"avg_snr_per_ant0", 0},
+ {"avg_snr_per_ant1", 0},
+ {"avg_snr_per_ant2", 0},
+ {"bcntxcancl", CAT_TX | CAT_ERR | CAT_MCAST | CAT_UCODE},
+ {"bphy_badplcp", CAT_ERR | CAT_UCODE},
+ {"bphy_rxcrsglitch", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"ccmpfmterr", CAT_SEC | CAT_ERR},
+ {"ccmpreplay", CAT_SEC | CAT_ERR},
+ {"ccmpundec", CAT_SEC | CAT_ERR},
+ {"cell_policy", 0},
+ {"cfgrestore", 0},
+ {"chained", 0},
+ {"chainedsz1", 0},
+ {"cso_normal", 0},
+ {"cso_passthrough", 0},
+ {"currchainsz", 0},
+ {"dbgoff46", CAT_UCODE},
+ {"dbgoff47", CAT_UCODE},
+ {"dbgoff48", CAT_UCODE},
+ {"decsuccess", 0},
+ {"dma_hang", CAT_ERR},
+ {"fourwayfail", CAT_ERR | CAT_CTRL | CAT_SEC | CAT_ASSOC},
+ {"frmscons", 0},
+ {"m2vmsg", 0},
+ {"macxsusp", 0},
+ {"maxchainsz", 0},
+ {"mboxout", 0},
+ {"missbcn_dbg", CAT_ERR | CAT_MCAST | CAT_UCODE | CAT_CTRL},
+ {"musnd", CAT_CTRL},
+ {"mws_antsel_ovr_rx", CAT_RX},
+ {"mws_antsel_ovr_tx", CAT_TX},
+ {"p2p_tbtt", 0},
+ {"p2p_tbtt_miss", CAT_ERR},
+ {"pciereset", CAT_ERR},
+ {"phywatch", CAT_UCODE},
+ {"pktengrxdmcast", CAT_RX | CAT_MCAST | CAT_UCODE},
+ {"pktengrxducast", CAT_RX | CAT_UCAST | CAT_UCODE},
+ {"pmqovfl", CAT_ERR | CAT_UCODE},
+ {"prs_timeout", CAT_ERR | CAT_UCODE},
+ {"reinit", CAT_ERR},
+ {"reinitreason_counts", CAT_ERR},
+ {"reset", CAT_ERR},
+ {"rx11mbps", CAT_RX},
+ {"rx12mbps", CAT_RX},
+ {"rx18mbps", CAT_RX},
+ {"rx1mbps", CAT_RX},
+ {"rx24mbps", CAT_RX},
+ {"rx2mbps", CAT_RX},
+ {"rx36mbps", CAT_RX},
+ {"rx48mbps", CAT_RX},
+ {"rx54mbps", CAT_RX},
+ {"rx5mbps5", CAT_RX},
+ {"rx6mbps", CAT_RX},
+ {"rx9mbps", CAT_RX},
+ {"rx_policy", CAT_RX},
+ {"rxackucast", CAT_RX | CAT_UCAST | CAT_UCODE},
+ {"rxaction", CAT_RX | CAT_CTRL},
+ {"rxanyerr", CAT_RX | CAT_UCODE},
+ {"rxassocreq", CAT_RX | CAT_CTRL | CAT_ASSOC},
+ {"rxassocrsp", CAT_RX | CAT_CTRL | CAT_ASSOC},
+ {"rxauth", CAT_RX | CAT_CTRL | CAT_SEC | CAT_ASSOC},
+ {"rxback", CAT_RX | CAT_UCODE},
+ {"rxbadcm", CAT_RX | CAT_ERR | CAT_SEC},
+ {"rxbadda", CAT_RX | CAT_CTRL},
+ {"rxbadds", CAT_RX | CAT_CTRL},
+ {"rxbadfcs", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxbadplcp", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxbadproto", CAT_RX | CAT_ERR},
+ {"rxbadsrcmac", CAT_RX | CAT_ERR},
+ {"rxbar", CAT_RX | CAT_AMPDU | CAT_CTRL},
+ {"rxbeaconmbss", CAT_RX | CAT_UCODE | CAT_CTRL},
+ {"rxbeaconobss", CAT_RX | CAT_UCODE | CAT_CTRL},
+ {"rxbyte", CAT_RX},
+ {"rxcfrmmcast", CAT_RX | CAT_MCAST | CAT_CTRL},
+ {"rxcfrmocast", CAT_RX | CAT_CTRL},
+ {"rxcfrmucast", CAT_RX | CAT_UCAST | CAT_CTRL},
+ {"rxcgprqfrm", CAT_RX | CAT_UCODE},
+ {"rxcgprsqovfl", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxcount", CAT_RX},
+ {"rxcrc", CAT_RX},
+ {"rxcrsglitch", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxctl", CAT_RX | CAT_CTRL},
+ {"rxctlmcast", CAT_RX | CAT_MCAST | CAT_UCODE | CAT_CTRL},
+ {"rxctlocast", CAT_RX | CAT_UCODE | CAT_CTRL},
+ {"rxctlucast", CAT_RX | CAT_UCAST | CAT_UCODE | CAT_CTRL},
+ {"rxctsocast", CAT_RX | CAT_UCODE | CAT_CTRL},
+ {"rxctsucast", CAT_RX | CAT_UCAST | CAT_UCODE | CAT_CTRL},
+ {"rxdeauth", CAT_RX | CAT_CTRL | CAT_SEC | CAT_ASSOC},
+ {"rxdfrmmcast", CAT_RX | CAT_MCAST},
+ {"rxdfrmocast", CAT_RX},
+ {"rxdfrmucastmbss", CAT_RX | CAT_UCAST},
+ {"rxdfrmucastobss", CAT_RX | CAT_UCAST},
+ {"rxdisassoc", CAT_RX | CAT_ERR | CAT_ASSOC},
+ {"rxdrop20s", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxdtmcast", CAT_RX | CAT_MCAST | CAT_UCODE},
+ {"rxdtocast", CAT_RX | CAT_UCODE},
+ {"rxdtucastmbss", CAT_RX | CAT_UCAST | CAT_UCODE},
+ {"rxdtucastobss", CAT_RX | CAT_UCAST | CAT_UCODE},
+ {"rxdup", CAT_RX | CAT_ERR},
+ {"rxerror", CAT_RX | CAT_ERR},
+ {"rxf0ovfl", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxf1ovfl", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxf2ovfl", CAT_RX | CAT_ERR},
+ {"rxfilter", CAT_RX},
+ {"rxfrag", CAT_RX},
+ {"rxfragerr", CAT_RX | CAT_ERR},
+ {"rxframe", CAT_RX},
+ {"rxfrmtoolong", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxfrmtooshrt", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxgiant", CAT_RX},
+ {"rxhlovfl", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxinvmachdr", CAT_RX},
+ {"rxmfrmmcast", CAT_RX | CAT_MCAST},
+ {"rxmfrmocast", CAT_RX},
+ {"rxmfrmucastmbss", CAT_RX | CAT_UCAST},
+ {"rxmgmcast", CAT_RX | CAT_MCAST | CAT_UCODE | CAT_CTRL},
+ {"rxmgocast", CAT_RX | CAT_UCODE | CAT_CTRL},
+ {"rxmgucastmbss", CAT_RX| CAT_UCAST | CAT_UCODE | CAT_CTRL},
+ {"rxmpdu_mu", CAT_RX},
+ {"rxmpdu_sgi", CAT_RX},
+ {"rxmpdu_stbc", CAT_RX},
+ {"rxmulti", CAT_RX | CAT_MCAST},
+ {"rxnack", CAT_RX | CAT_ERR},
+ {"rxnobuf", CAT_RX | CAT_ERR},
+ {"rxnodelim", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxnondata", CAT_RX | CAT_ERR | CAT_CTRL},
+ {"rxnoscb", CAT_RX | CAT_ERR},
+ {"rxnull", CAT_RX | CAT_ERR},
+ {"rxprobereq", CAT_RX | CAT_CTRL},
+ {"rxprobersp", CAT_RX | CAT_CTRL},
+ {"rxpspoll", CAT_RX | CAT_CTRL},
+ {"rxqosnull", CAT_RX},
+ {"rxreassocreq", CAT_RX | CAT_CTRL | CAT_ASSOC},
+ {"rxreassocrsp", CAT_RX | CAT_CTRL | CAT_ASSOC},
+ {"rxrsptmout", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxrtry", CAT_RX | CAT_ERR},
+ {"rxrtsocast", CAT_RX | CAT_UCODE | CAT_CTRL},
+ {"rxrtsucast", CAT_RX | CAT_UCAST | CAT_UCODE | CAT_CTRL},
+ {"rxrunt", CAT_RX | CAT_ERR},
+ {"rxstrt", CAT_RX | CAT_UCODE},
+ {"rxtoolate", CAT_RX | CAT_ERR | CAT_UCODE},
+ {"rxuflo", CAT_RX | CAT_ERR},
+ {"rxundec", CAT_RX | CAT_SEC},
+ {"sfb2v", 0},
+ {"swap_alivecheck0", 0},
+ {"swap_alivecheck1", 0},
+ {"swap_ge_rxcount0", CAT_RX},
+ {"swap_ge_rxcount1", CAT_RX},
+ {"swap_ge_snrthresh0", 0},
+ {"swap_ge_snrthresh1", 0},
+ {"swap_snrdrop0", 0},
+ {"swap_snrdrop1", 0},
+ {"swap_timer0", 0},
+ {"swap_timer1", 0},
+ {"swap_trig_event_id", 0},
+ {"swap_txfail0", CAT_TX | CAT_ERR},
+ {"swap_txfail1", CAT_TX | CAT_ERR},
+ {"tbtt", 0},
+ {"tkipcntrmsr", CAT_SEC},
+ {"tkipicverr", CAT_SEC},
+ {"tkipmicfaill", CAT_ERR | CAT_SEC},
+ {"tkipreplay", CAT_ERR | CAT_SEC},
+ {"tx_active_ant", CAT_TX},
+ {"tx_auto_en", CAT_TX},
+ {"tx_policy", CAT_TX},
+ {"txackfrm", CAT_TX | CAT_UCAST | CAT_UCODE},
+ {"txaction", CAT_TX | CAT_CTRL},
+ {"txallfrm", CAT_TX | CAT_UCODE},
+ {"txampdu", CAT_TX | CAT_AMPDU | CAT_UCODE},
+ {"txassocreq", CAT_TX | CAT_CTRL | CAT_ASSOC},
+ {"txassocrsp", CAT_TX | CAT_CTRL | CAT_ASSOC},
+ {"txauth", CAT_TX | CAT_CTRL | CAT_SEC | CAT_ASSOC},
+ {"txback", CAT_TX | CAT_UCODE},
+ {"txbar", CAT_TX | CAT_AMPDU},
+ {"txbcnfrm", CAT_TX | CAT_MCAST | CAT_UCODE | CAT_CTRL},
+ {"txbyte", CAT_TX},
+ {"txcgprsfail", CAT_TX | CAT_ERR | CAT_UCODE},
+ {"txcgprssuc", CAT_TX | CAT_UCODE},
+ {"txchanrej", CAT_TX | CAT_ERR},
+ {"txchit", CAT_TX},
+ {"txcmiss", CAT_TX | CAT_ERR},
+ {"txctsfrm", CAT_TX | CAT_UCODE | CAT_CTRL},
+ {"txdatabcast", CAT_TX | CAT_MCAST},
+ {"txdatamcast", CAT_TX | CAT_MCAST},
+ {"txdeauth", CAT_TX | CAT_ERR | CAT_CTRL | CAT_SEC | CAT_ASSOC},
+ {"txdisassoc", CAT_TX | CAT_ERR | CAT_CTRL | CAT_ASSOC},
+ {"txdmawar", CAT_TX | CAT_ERR},
+ {"txdnlfrm", CAT_TX | CAT_UCODE},
+ {"txerror", CAT_TX | CAT_ERR},
+ {"txfail", CAT_TX | CAT_ERR},
+ {"txfbw", CAT_TX},
+ {"txfrag", CAT_TX},
+ {"txfrag", CAT_TX},
+ {"txframe", CAT_TX},
+ {"txfrmsnt", CAT_TX},
+ {"txfunfl", CAT_TX | CAT_UCODE},
+ {"txinrtstxop", CAT_TX | CAT_UCODE},
+ {"txlost", CAT_TX | CAT_ERR},
+ {"txmpdu", CAT_TX | CAT_UCODE},
+ {"txmpdu_sgi", CAT_TX},
+ {"txmpdu_stbc", CAT_TX},
+ {"txmulti", CAT_TX | CAT_MCAST},
+ {"txnack", CAT_TX | CAT_ERR | CAT_UCAST},
+ {"txnoack", CAT_TX | CAT_ERR | CAT_UCAST},
+ {"txnoassoc", CAT_TX | CAT_ERR | CAT_ASSOC},
+ {"txnobuf", CAT_TX | CAT_ERR},
+ {"txnocts", CAT_TX},
+ {"txnull", CAT_TX},
+ {"txper_rts", CAT_TX | CAT_ERR | CAT_CTRL},
+ {"txper_ucastdt", CAT_TX | CAT_ERR | CAT_UCAST},
+ {"txphycrs", CAT_TX},
+ {"txphyerr", CAT_TX | CAT_ERR},
+ {"txphyerror", CAT_TX | CAT_ERR | CAT_UCODE},
+ {"txprobereq", CAT_TX | CAT_CTRL | CAT_ASSOC},
+ {"txprobersp", CAT_TX | CAT_CTRL | CAT_ASSOC},
+ {"txprshort", CAT_TX},
+ {"txpspoll", CAT_TX | CAT_CTRL},
+ {"txqosnull", CAT_TX | CAT_CTRL},
+ {"txreassocreq", CAT_TX | CAT_CTRL | CAT_ASSOC},
+ {"txreassocrsp", CAT_TX | CAT_CTRL | CAT_ASSOC},
+ {"txretrans", CAT_TX | CAT_ERR},
+ {"txretrie", CAT_TX | CAT_ERR | CAT_UCAST},
+ {"txretry", CAT_TX | CAT_ERR | CAT_UCAST},
+ {"txrts", CAT_TX | CAT_CTRL},
+ {"txrtsfail", CAT_TX | CAT_ERR | CAT_UCODE | CAT_CTRL},
+ {"txrtsfrm", CAT_TX | CAT_UCODE | CAT_CTRL},
+ {"txserr", CAT_TX | CAT_ERR},
+ {"txsfovfl", CAT_TX | CAT_ERR},
+ {"txtplunfl", CAT_TX | CAT_UCODE},
+ {"txucast", CAT_TX | CAT_UCAST | CAT_UCODE},
+ {"unchained", 0},
+ {"v2mmsg", 0},
+ {"wepicverr", CAT_ERR | CAT_SEC},
+ {"wepundec", CAT_SEC},
+ {NULL, 0}
+};
+
+static bool at_start_of_line; /**< prevents printing of empty lines */
+
+static int
+cntr_ver_to_tbl_info(uint8 counter_ver, counter_offset_info_t **cntr_offset_info_tbl)
+{
+ uint32 index = 0;
+
+ while (ver_to_cntr_offset_info_tbl[index].offset_info_tbl != NULL) {
+ if (ver_to_cntr_offset_info_tbl[index].cntr_ver == counter_ver) {
+ *cntr_offset_info_tbl = ver_to_cntr_offset_info_tbl[index].offset_info_tbl;
+ return BCME_OK;
+ }
+ index++;
+ }
+
+ *cntr_offset_info_tbl = NULL;
+ return BCME_ERROR;
+}
+
+/* Returns the offset of the counter in respective version of counters structure */
+/* Returns 0 - Found the offset of the counter */
+/* Returns -1 - Counter name passed do not match to any counter name */
+int
+get_counter_offset(char *name, uint32 *offset, uint8 counter_ver)
+{
+ uint32 index = 0;
+ counter_offset_info_t *offset_info_tbl = NULL;
+
+ if (cntr_ver_to_tbl_info(counter_ver, &offset_info_tbl) != BCME_OK) {
+ fprintf(stderr, "Unsupported counter ver %d\n", counter_ver);
+ return BCME_ERROR;
+ }
+
+ while (offset_info_tbl[index].name != NULL) {
+ if (!strcmp(offset_info_tbl[index].name, name)) {
+ *offset = htod32(offset_info_tbl[index].offset);
+ return BCME_OK;
+ }
+ index++;
+ }
+
+ fprintf(stderr, "Invalid counter name %s\n", name);
+ return BCME_ERROR;
+}
+
+int
+print_counter_help(uint8 counter_ver)
+{
+ uint32 index = 0;
+ counter_offset_info_t *offset_info_tbl = NULL;
+
+ if (cntr_ver_to_tbl_info(counter_ver, &offset_info_tbl) != BCME_OK) {
+ fprintf(stderr, "Unsupported counter ver %d\n", counter_ver);
+ return BCME_ERROR;
+ }
+
+ while (offset_info_tbl[index].name != NULL) {
+ if (index % 5 == 0) {
+ printf("\n");
+ }
+ printf("%s ", offset_info_tbl[index].name);
+ index++;
+ }
+ return BCME_OK;
+}
+
+int
+wl_subcounters(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ void *ptr;
+ char *endptr;
+ uint8 subcntdata[(MAX_SUBCOUNTER_SUPPORTED * sizeof(uint32)) +
+ OFFSETOF(wl_subcnt_info_t, data)];
+ int32 cntr_ver = -1;
+ uint32 cntr_num = 0;
+ uint32 req_len = 0;
+ uint32 arg_index = 1; /* 0th arg is command_name */
+ wl_subcnt_info_t *subcntinfo;
+
+ memset(subcntdata, 0, sizeof(subcntdata));
+
+ if (argv[arg_index] != NULL) {
+ cntr_ver = strtoul(argv[arg_index], &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Invalid cntr ver %s\n", argv[arg_index]);
+ return BCME_BADARG;
+ }
+ arg_index++;
+ }
+
+ subcntinfo = (wl_subcnt_info_t *)subcntdata;
+ while (argv[arg_index] != NULL) {
+ if (cntr_num >= MAX_SUBCOUNTER_SUPPORTED) {
+ fprintf(stderr, "Max counters supported: %d\n", MAX_SUBCOUNTER_SUPPORTED);
+ return BCME_BADARG;
+ }
+
+ if (get_counter_offset(argv[arg_index],
+ &subcntinfo->data[cntr_num], cntr_ver)) {
+ return BCME_BADARG;
+ }
+ arg_index++;
+ cntr_num++;
+ }
+
+ if ((cntr_ver != -1) && (cntr_num == 0)) {
+ print_counter_help(cntr_ver);
+ return BCME_OK;
+ }
+
+ req_len = OFFSETOF(wl_subcnt_info_t, data) + (cntr_num * sizeof(subcntinfo->data[0]));
+ subcntinfo->version = htod16(WL_SUBCNTR_IOV_VER);
+ subcntinfo->counters_version = htod16(cntr_ver);
+ subcntinfo->num_subcounters = htod16(cntr_num);
+ subcntinfo->length = htod16(req_len);
+
+ if ((err = wlu_var_getbuf_minimal(wl, cmd->name, subcntdata, req_len, &ptr))) {
+ return (err);
+ }
+
+ subcntinfo = ptr;
+ subcntinfo->version = dtoh16(subcntinfo->version);
+ subcntinfo->counters_version = dtoh16(subcntinfo->counters_version);
+ subcntinfo->num_subcounters = dtoh16(subcntinfo->num_subcounters);
+ subcntinfo->length = dtoh16(subcntinfo->length);
+
+ if ((cntr_ver == -1) || (cntr_num == 0) || (subcntinfo->num_subcounters == 0)) {
+ printf("FW counter Version %d\n", subcntinfo->counters_version);
+ return BCME_OK;
+ }
+
+ if ((subcntinfo->num_subcounters > MAX_SUBCOUNTER_SUPPORTED) ||
+ (subcntinfo->length != req_len) ||
+ (subcntinfo->length != OFFSETOF(wl_subcnt_info_t, data) +
+ (subcntinfo->num_subcounters * sizeof(subcntinfo->data[0])))) {
+ fprintf(stderr,
+ "Mismatch App:FW cntr_ver %d:%d iov_ver %d:%d num_cntr %d:%d len %d:%d\n",
+ cntr_ver, subcntinfo->counters_version,
+ WL_SUBCNTR_IOV_VER, subcntinfo->version, cntr_num,
+ subcntinfo->num_subcounters, req_len, subcntinfo->length);
+ return BCME_BADARG;
+ }
+
+ for (cntr_num = 0; cntr_num < subcntinfo->num_subcounters; cntr_num++) {
+ /* Print max 5 counters value in a single row */
+ if (cntr_num % 5 == 0)
+ printf("\n");
+ printf("%s %d ", argv[cntr_num + 2],
+ dtoh32(subcntinfo->data[cntr_num]));
+ }
+ printf("\n");
+
+ return 0;
+}
+
+/***************************************************************************************************
+ * The prcnt_*() functions print counter values. The purpose of the functions is to facilitate
+ * filtering of the counter values, e.g. when the user only wants to see non-zero values.
+ */
+
+/** Must be called before any of the other prcnt_*() functions */
+void prcnt_init()
+{
+ at_start_of_line = TRUE;
+}
+
+/**
+ * Returns TRUE if a counter value is allowed by the filters to be printed.
+ * @param cnt_filters Specifies the filters to be applied
+ * @param cntname The name of the variable in the 'cnt' structure
+ */
+static bool prcnt_filter1(struct cnt_filters_s *cnt_filters, char *cntname)
+{
+ if (cnt_filters->filter != 0) {
+ const struct cnt_properties_s *cnt = &cnt_props[0];
+ while (cnt->name != NULL) {
+ if (!strcmp(cntname, cnt->name)) {
+ if ((cnt_filters->filter & cnt->categories) !=
+ cnt_filters->filter) {
+ // returns FALSE in non inverted case
+ return cnt_filters->invert_selection;
+ }
+ break;
+ }
+ cnt++;
+ }
+ if (cnt->name == NULL)
+ fprintf(stderr, "could not find this entry... %s\n", cntname);
+ }
+
+ return !cnt_filters->invert_selection;
+}
+
+/**
+ * Returns TRUE if a counter value is allowed by the filters to be printed.
+ * @param cnt_filters Specifies the filters to be applied
+ * @param cntname The name of the variable in the 'cnt' structure
+ * @param cntvalue The value of the counter
+ */
+static bool prcnt_filter(struct cnt_filters_s *cnt_filters, char *cntname, uint32 cntvalue)
+{
+ if (cnt_filters->nonzero == TRUE && cntvalue == 0)
+ return FALSE;
+
+ return prcnt_filter1(cnt_filters, cntname);
+}
+
+/**
+ * For non-legacy mode (so user specified filter options): prevents empty lines when printing
+ * counter values. For legacy mode: empty lines are preserved for backwards compatibility of tools
+ * that interpret wl utility output.
+ * @param cnt_filters User specified filters to apply
+ * @param ppbuf Output buffer for the sprintf
+ */
+void prcnt_prnl1(struct cnt_filters_s *cnt_filters)
+{
+ if (at_start_of_line == FALSE || cnt_filters->filters_active == FALSE) {
+ printf("\n");
+ at_start_of_line = TRUE;
+ }
+}
+
+static int wl_counters_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
+{
+ int err = BCME_OK;
+ wl_cnt_cbfn_info_t *cbfn_info = ctx;
+ uint i;
+ struct cnt_filters_s *p_cnt_filters = &cbfn_info->cnt_filters;
+
+ PRINIT(); /* initializes printing of counter values */
+
+ switch (type) {
+ case WL_CNT_XTLV_WLC_RINIT_RSN: {
+ /* reinit reason counters */
+ reinit_rsns_t *cnt = (reinit_rsns_t *)data;
+ uint32 *val = cnt->rsn;
+ uint maxoffset = len/sizeof(uint32);
+
+ if (len > sizeof(reinit_rsns_t)) {
+ printf("type %d: cntbuf length too long! %d > %d\n"
+ "May need to use up-to-date wl utility.\n",
+ type, len, (int)sizeof(reinit_rsns_t));
+ }
+
+ if (cnt->rsn[0] != INVALID_CNT_VAL) {
+ PRSTR(reinitreason_counts, "reinitreason_counts: ");
+ for (i = 0; i < WL_REINIT_RC_LAST && i < maxoffset; i++) {
+ PRVAL_FMTSTR2(reinitreason_counts, "%d(%d) ", i, val[i]);
+ }
+ PRNL1();
+ }
+ break;
+ }
+ case WL_CNT_XTLV_WLC: {
+ /* WLC layer counters */
+ wl_cnt_wlc_t *cnt = (wl_cnt_wlc_t *)data;
+
+ if (len > sizeof(wl_cnt_wlc_t)) {
+ printf("type %d: cntbuf length too long! %d > %d\n"
+ "May need to use up-to-date wl utility.\n",
+ type, len, (int)sizeof(wl_cnt_wlc_t));
+ }
+ PRVALSF(reinit);
+
+ /* Display old reinitreason counts */
+ if (cnt->reinitreason[0] != INVALID_CNT_VAL) {
+ PRSTR(reinitreason_counts, "reinitreason_counts: ");
+ for (i = 0; i < NREINITREASONCOUNT; i++)
+ PRVAL_FMTSTR2(reinitreason_counts, "%d(%d) ",
+ i, cnt->reinitreason[i]);
+ PRNL1();
+ }
+
+ PRVALSF(reset); PRVALSF(pciereset); PRVALSF(cfgrestore);
+ PRVALSF(dma_hang); PRVALSF(ampdu_wds); PRNL1();
+
+ PRVALSF(txframe); PRVALSF(txbyte); PRVALSF(txretrans); PRVALSF(txlost);
+ PRVALSF(txfail); PRVALSF(txchanrej);
+ if (cbfn_info->cntr_ver == WL_CNT_VERSION_7001) PRVALSF_RENAME(phywatchdog,rxbcnlossmbss);
+ PRNL1();
+ PRVALSF(txdatamcast); PRVALSF(txdatabcast); PRNL1();
+ PRVALSF(tbtt); PRVALSF(p2p_tbtt); PRVALSF(p2p_tbtt_miss); PRNL1();
+ PRVALSF(rxframe); PRVALSF(rxbyte); PRVALSF(rxerror); PRNL1();
+ PRVALSF(txprshort); PRVALSF(txdmawar); PRVALSF(txnobuf); PRVALSF(txnoassoc);
+ PRVALSF(txchit); PRVALSF(txcmiss); PRNL1();
+ PRVALSF(txserr); PRVALSF(txphyerr); PRVALSF(txphycrs); PRVALSF(txerror);
+ PRNL1();
+ PRVALSF_RENAME(txfrag, d11_txfrag); PRVALSF_RENAME(txmulti, d11_txmulti);
+ PRVALSF_RENAME(txretry, d11_txretry);
+ PRVALSF_RENAME(txretrie, d11_txretrie); PRNL1();
+ PRVALSF_RENAME(txrts, d11_txrts); PRVALSF_RENAME(txnocts, d11_txnocts);
+ PRVALSF_RENAME(txnoack, d11_txnoack);
+ PRVALSF_RENAME(txfrmsnt, d11_txfrmsnt); PRNL1();
+
+ PRVALSF(rxcrc); PRVALSF(rxnobuf); PRVALSF(rxnondata); PRVALSF(rxbadds);
+ PRVALSF(rxbadcm); PRVALSF(rxdup); PRVALSF(rxfragerr); PRNL1();
+
+ PRVALSF(rxrunt); PRVALSF(rxgiant); PRVALSF(rxnoscb); PRVALSF(rxbadproto);
+ PRVALSF(rxbadsrcmac); PRVALSF(rxrtry); PRNL1();
+ PRVALSF_RENAME(rxfrag, d11_rxfrag); PRVALSF_RENAME(rxmulti, d11_rxmulti);
+ PRVALSF_RENAME(rxundec, d11_rxundec); PRNL1();
+ PRVALSF(rxctl); PRVALSF(rxbadda); PRVALSF(rxfilter);
+ if (cnt->rxuflo[0] != INVALID_CNT_VAL) {
+ PRSTR(rxuflo, "rxuflo: ");
+ for (i = 0; i < NFIFO; i++)
+ PRVAL_FMTSTR1(rxuflo, "%u ", cnt->rxuflo[i]);
+ PRNL1();
+ }
+
+ /* WPA2 counters */
+ PRNL1();
+ PRVALSF(tkipmicfaill); PRVALSF(tkipicverr); PRVALSF(tkipcntrmsr); PRNL1();
+ PRVALSF(tkipreplay); PRVALSF(ccmpfmterr); PRVALSF(ccmpreplay); PRNL1();
+ PRVALSF(ccmpundec); PRVALSF(fourwayfail); PRVALSF(wepundec); PRNL1();
+ PRVALSF(wepicverr); PRVALSF(decsuccess); PRVALSF(rxundec); PRNL1();
+ PRNL1();
+
+ /* per-rate receive counters */
+ PRVALSF(rx1mbps); PRVALSF(rx2mbps); PRVALSF(rx5mbps5);
+ PRVALSF(rx11mbps); PRNL1();
+ PRVALSF(rx6mbps); PRVALSF(rx9mbps); PRVALSF(rx12mbps);
+ PRVALSF(rx18mbps); PRNL1();
+ PRVALSF(rx24mbps); PRVALSF(rx36mbps); PRVALSF(rx48mbps);
+ PRVALSF(rx54mbps); PRNL1();
+
+ PRVALSF(txmpdu_sgi); PRVALSF(rxmpdu_sgi); PRVALSF(txmpdu_stbc);
+ PRVALSF(rxmpdu_stbc); PRVALSF(rxmpdu_mu); PRNL1();
+
+ PRVALSF(cso_normal); PRVALSF(cso_passthrough);
+ PRNL1();
+ PRVALSF(chained); PRVALSF(chainedsz1); PRVALSF(unchained);
+ PRVALSF(maxchainsz); PRVALSF(currchainsz); PRNL1();
+ PRNL1();
+
+ /* detailed amangement and control frame counters */
+ PRVALSF(txbar); PRVALSF(txpspoll); PRVALSF(rxbar);
+ PRVALSF(rxpspoll); PRNL1();
+ PRVALSF(txnull); PRVALSF(txqosnull); PRVALSF(rxnull);
+ PRVALSF(rxqosnull); PRNL1();
+ PRVALSF(txassocreq); PRVALSF(txreassocreq); PRVALSF(txdisassoc);
+ PRVALSF(txassocrsp); PRVALSF(txreassocrsp); PRNL1();
+ PRVALSF(txauth); PRVALSF(txdeauth); PRVALSF(txprobereq);
+ PRVALSF(txprobersp); PRVALSF(txaction); PRNL1();
+ PRVALSF(rxassocreq); PRVALSF(rxreassocreq); PRVALSF(rxdisassoc);
+ PRVALSF(rxassocrsp); PRVALSF(rxreassocrsp); PRNL1();
+ PRVALSF(rxauth); PRVALSF(rxdeauth); PRVALSF(rxprobereq);
+ PRVALSF(rxprobersp); PRVALSF(rxaction); PRNL1();
+ break;
+ }
+ case WL_CNT_XTLV_CNTV_LE10_UCODE: {
+ wl_cnt_v_le10_mcst_t *cnt = (wl_cnt_v_le10_mcst_t *)data;
+ if (len != sizeof(wl_cnt_v_le10_mcst_t)) {
+ printf("type %d: cnt struct length mismatch! %d != %d\n",
+ type, len, (int)sizeof(wl_cnt_v_le10_mcst_t));
+ }
+
+ /* UCODE SHM counters */
+ PRVAL(txallfrm); PRVAL(txbcnfrm); PRVAL(txrtsfrm);
+ PRVAL(txctsfrm); PRVAL(txackfrm); PRVAL(txback);
+ PRVAL(txdnlfrm); PRNL1();
+ PRSTR(txfunfl, "txfunfl: ");
+ for (i = 0; i < NFIFO; i++) {
+ PRVAL_FMTSTR1(txfunfl, "%u ", cnt->txfunfl[i]);
+ }
+ PRVAL(txtplunfl); PRVAL(txphyerror); PRNL1();
+ PRNL1();
+
+ PRVAL(rxstrt); PRVAL(rxbadplcp); PRVAL(rxcrsglitch);
+ PRVAL(rxtoolate); PRNL1();
+ PRVAL(rxdrop20s); PRVAL(rxrsptmout); PRNL1();
+ PRVAL(rxbadfcs); PRVAL(rxfrmtoolong); PRVAL(rxfrmtooshrt);
+ PRVAL(rxinvmachdr); PRNL1();
+ PRVAL(rxf0ovfl); PRVAL(rxf1ovfl); PRVAL(rxf2ovfl);
+ PRVAL(txsfovfl); PRVAL(pmqovfl); PRNL1();
+ PRVAL(rxcfrmucast); PRVAL(rxrtsucast); PRVAL(rxctsucast);
+ PRVAL(rxackucast); PRVAL(rxback); PRNL1();
+ PRVAL(rxbeaconmbss); PRVAL(rxdfrmucastmbss);
+ PRVAL(rxmfrmucastmbss); PRNL1();
+ PRVAL(rxbeaconobss); PRVAL(rxdfrmucastobss);
+ PRVAL(rxdfrmocast); PRVAL(rxmfrmocast); PRNL1();
+ PRVAL(rxcfrmocast); PRVAL(rxrtsocast); PRVAL(rxctsocast); PRNL1();
+ PRVAL(rxcfrmmcast); PRVAL(rxdfrmmcast); PRVAL(rxmfrmmcast); PRNL1();
+ PRNL1();
+
+ PRVAL(rxcgprqfrm); PRVAL(rxcgprsqovfl);
+ PRVAL(txcgprsfail); PRVAL(txcgprssuc); PRVAL(prs_timeout); PRNL1();
+ PRVAL(pktengrxducast); PRVAL(pktengrxdmcast);
+ PRVAL(bcntxcancl); PRNL1();
+ PRVAL(txfbw); PRVAL(rxnack); PRVAL(frmscons);
+ PRVAL(txnack); PRNL1();
+ PRNL1();
+ break;
+ }
+ case WL_CNT_XTLV_LT40_UCODE_V1: {
+ wl_cnt_lt40mcst_v1_t *cnt = (wl_cnt_lt40mcst_v1_t *)data;
+ if (len != sizeof(wl_cnt_lt40mcst_v1_t)) {
+ printf("type %d: cnt struct length mismatch! %d != %d\n",
+ type, len, (int)sizeof(wl_cnt_lt40mcst_v1_t));
+ }
+ PRCNT_MACSTAT_TX_VER_GE11;
+ /* rx start and those that do not end well */
+ PRVAL(rxstrt); PRVAL(rxbadplcp); PRVAL(rxcrsglitch);
+ PRVAL(rxtoolate); PRVAL(rxnodelim); PRNL1();
+ PRVAL(bphy_badplcp); PRVAL(bphy_rxcrsglitch); PRNL1();
+ PRVAL(rxbadfcs); PRVAL(rxfrmtoolong); PRVAL(rxfrmtooshrt);
+ PRVAL(rxanyerr); PRNL1();
+ PRVAL(rxf0ovfl); PRVAL(pmqovfl); PRNL1();
+ PRCNT_MACSTAT_RX_VER_GE11;
+ PRNL1();
+ PRVAL(dbgoff46); PRVAL(dbgoff47);
+ PRVAL(dbgoff48); PRVAL(phywatch); PRNL1();
+ PRNL1();
+ break;
+ }
+ case WL_CNT_XTLV_GE40_UCODE_V1: {
+ wl_cnt_ge40mcst_v1_t *cnt = (wl_cnt_ge40mcst_v1_t *)data;
+ if (len != sizeof(wl_cnt_ge40mcst_v1_t)) {
+ printf("type %d: cnt struct length mismatch! %d != %d\n",
+ type, len, (int)sizeof(wl_cnt_ge40mcst_v1_t));
+ }
+ PRCNT_MACSTAT_TX_VER_GE11;
+ /* rx start and those that do not end well */
+ PRVAL(rxstrt); PRVAL(rxbadplcp); PRVAL(rxcrsglitch);
+ PRVAL(rxtoolate); PRVAL(rxnodelim); PRNL1();
+ PRVAL(rxdrop20s); PRVAL(bphy_badplcp); PRVAL(bphy_rxcrsglitch); PRNL1();
+ PRVAL(rxbadfcs); PRVAL(rxfrmtoolong); PRVAL(rxfrmtooshrt);
+ PRVAL(rxanyerr); PRNL1();
+ PRVAL(rxf0ovfl); PRVAL(rxf1ovfl); PRVAL(rxhlovfl); PRVAL(pmqovfl); PRNL1();
+ PRCNT_MACSTAT_RX_VER_GE11;
+ PRVAL(missbcn_dbg); PRNL1();
+ PRNL1();
+ break;
+ }
+ case WL_CNT_XTLV_GE64_UCODEX_V1: {
+ wl_cnt_ge64mcxst_v1_t *cnt = (wl_cnt_ge64mcxst_v1_t *)data;
+ if (len != sizeof(wl_cnt_ge64mcxst_v1_t)) {
+ printf("type %d: cnt struct length mismatch! %d != %d\n",
+ type, len, (int)sizeof(wl_cnt_ge64mcxst_v1_t));
+ }
+ PRVAL(macxsusp); PRVAL(m2vmsg); PRVAL(v2mmsg); PRNL1();
+ PRVAL(mboxout); PRVAL(musnd); PRVAL(sfb2v);
+ PRNL1();
+ break;
+ }
+ default:
+ printf("Unknown counters type %d!! You may try updating wl utility.\n",
+ type);
+ break;
+ }
+
+ return err;
+}
+
+int
+wl_counters(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_cnt_info_t *cntinfo;
+ int err;
+ void *ptr;
+ uint16 ver;
+ uint8 *cntdata;
+ uint32 corerev = 0;
+ wl_cnt_cbfn_info_t cbfn_info;
+#ifdef WL_NAN
+ wl_nan_ioc_t*nanioc;
+ uint16 iocsz = sizeof(wl_nan_ioc_t) + WL_NAN_IOC_BUFSZ;
+#endif /* WL_NAN */
+
+ memset(&cbfn_info, 0, sizeof(cbfn_info));
+ while (*++argv != NULL) {
+ cbfn_info.cnt_filters.filters_active = TRUE;
+ if (!strcmp(*argv, "--nz"))
+ cbfn_info.cnt_filters.nonzero = TRUE;
+ else if (!strcmp(*argv, "--invert")) /* inverts entire selection */
+ cbfn_info.cnt_filters.invert_selection = TRUE;
+ else if (!strcmp(*argv, "--rx"))
+ cbfn_info.cnt_filters.filter |= CAT_RX;
+ else if (!strcmp(*argv, "--tx"))
+ cbfn_info.cnt_filters.filter |= CAT_TX;
+ else if (!strcmp(*argv, "--err"))
+ cbfn_info.cnt_filters.filter |= CAT_ERR;
+ else if (!strcmp(*argv, "--ucast"))
+ cbfn_info.cnt_filters.filter |= CAT_UCAST;
+ else if (!strcmp(*argv, "--mcast")) /* includes broadcast frames */
+ cbfn_info.cnt_filters.filter |= CAT_MCAST;
+ else if (!strcmp(*argv, "--ampdu"))
+ cbfn_info.cnt_filters.filter |= CAT_AMPDU;
+ else if (!strcmp(*argv, "--ucode"))
+ cbfn_info.cnt_filters.filter |= CAT_UCODE;
+ else if (!strcmp(*argv, "--ctrl"))
+ cbfn_info.cnt_filters.filter |= CAT_CTRL;
+ else if (!strcmp(*argv, "--sec"))
+ cbfn_info.cnt_filters.filter |= CAT_SEC;
+ else if (!strcmp(*argv, "--assoc"))
+ cbfn_info.cnt_filters.filter |= CAT_ASSOC;
+ else {
+ fprintf(stderr, "unrecognized option %s\n", *argv);
+ err = BCME_ERROR;
+ goto exit;
+ }
+ }
+
+ if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr))) {
+ goto exit;
+ }
+
+ cntinfo = ptr;
+ cntinfo->version = dtoh16(cntinfo->version);
+ cntinfo->datalen = dtoh16(cntinfo->datalen);
+ CHK_CNTBUF_DATALEN(cntinfo, WLC_IOCTL_MEDLEN);
+ ver = cntinfo->version;
+ if (ver > WL_CNT_T_VERSION && ver != WL_CNT_VERSION_7001) {
+ printf("\tIncorrect version of counters struct: expected %d; got %d\n",
+ WL_CNT_T_VERSION, ver);
+ err = BCME_ERROR;
+ goto exit;
+ }
+
+ printf("counters_version %d\n", ver);
+
+
+ if (ver == WL_CNT_VERSION_11) {
+ wlc_rev_info_t revinfo;
+ memset(&revinfo, 0, sizeof(revinfo));
+ err = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (err) {
+ printf("%s: WLC_GET_REVINFO failed %d\n", __FUNCTION__, err);
+ goto exit;
+ }
+ corerev = dtoh32(revinfo.corerev);
+ }
+ err = wl_cntbuf_to_xtlv_format(NULL, cntinfo, WLC_IOCTL_MEDLEN, corerev);
+
+ if (err) {
+ printf("%s: wl_cntbuf_to_xtlv_format failed %d\n", __FUNCTION__, err);
+ goto exit;
+ }
+
+ /* Now counter buffer of all versions is translated to xtlv format */
+ printf("datalen %d\n", cntinfo->datalen);
+
+ cntdata = (uint8 *)malloc(cntinfo->datalen);
+ if (cntdata == NULL) {
+ err = BCME_NOMEM;
+ printf("malloc fail!\n");
+ goto exit;
+ };
+
+ memcpy(cntdata, cntinfo->data, cntinfo->datalen);
+
+ cbfn_info.cntr_ver = ver;
+ if ((err = bcm_unpack_xtlv_buf(&cbfn_info, cntdata, cntinfo->datalen,
+ BCM_XTLV_OPTION_ALIGN32, wl_counters_cbfn))) {
+ printf("error %d\n", err);
+ }
+ free(cntdata);
+
+exit:
+#ifdef WL_NAN
+ /* alloc mem for ioctl headr + tlv data */
+ nanioc = calloc(1, iocsz);
+ if (nanioc == NULL)
+ return BCME_NOMEM;
+
+ /* make up nan cmd ioctl header */
+ nanioc->version = htod16(WL_NAN_IOCTL_VERSION);
+ nanioc->id = WL_NAN_CMD_CFG_COUNT;
+ nanioc->len = WL_NAN_IOC_BUFSZ;
+
+ wl_nan_do_get_ioctl(wl, nanioc, iocsz);
+ free(nanioc);
+#endif /* WL_NAN */
+
+ return err;
+}
+
+int
+wl_if_counters(void *wl, cmd_t *cmd, char **argv)
+{
+ char *statsbuf;
+ wl_if_stats_t *cnt;
+ int err;
+ void *ptr;
+ struct cnt_filters_s cnt_filters;
+ struct cnt_filters_s *p_cnt_filters = &cnt_filters;
+ UNUSED_PARAMETER(argv);
+
+ memset(&cnt_filters, 0, sizeof(cnt_filters));
+ if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr)))
+ return (err);
+
+ statsbuf = (char *)ptr;
+ cnt = (wl_if_stats_t*)malloc(sizeof(wl_if_stats_t));
+ if (cnt == NULL) {
+ printf("\tCan not allocate %d bytes for counters struct\n",
+ (int)sizeof(wl_if_stats_t));
+ return BCME_NOMEM;
+ } else
+ memcpy(cnt, statsbuf, sizeof(wl_if_stats_t));
+ /* summary stat counter line */
+ PRINIT();
+ PRVAL(txframe); PRVAL(txbyte); PRVAL(txerror);
+ PRVAL(rxframe); PRVAL(rxbyte); PRVAL(rxerror); PRNL1();
+
+ PRVAL(txnobuf); PRVAL(txfail); PRNL1();
+ PRVALSF_RENAME(txfrag, d11_txfrag);
+ PRVALSF_RENAME(txmulti, d11_txmulti);
+ PRVALSF_RENAME(txretry, d11_txretry);
+ PRVALSF_RENAME(txretrie, d11_txretrie);
+ PRNL1();
+ PRVALSF_RENAME(txfrmsnt, d11_txfrmsnt);
+ PRNL1();
+
+ PRVAL(rxnobuf); PRVAL(rxfragerr); PRNL1();
+ PRVAL(rxrunt); PRNL1();
+ PRVALSF_RENAME(rxmulti, d11_rxmulti);
+ PRNL1();
+ if (dtoh16(cnt->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
+ PRVAL(txexptime);
+ PRVAL(txrts); PRVAL(txnocts);
+ }
+ PRNL1();
+
+ if (cnt)
+ free(cnt);
+
+ return (0);
+}
+
+int
+wl_delta_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ char *statsbuf;
+ wl_delta_stats_t *cnt;
+ int err;
+ void *ptr;
+ struct cnt_filters_s cnt_filters;
+ struct cnt_filters_s *p_cnt_filters = &cnt_filters;
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ memset(&cnt_filters, 0, sizeof(cnt_filters));
+
+ if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr)))
+ return (err);
+
+ statsbuf = (char *)ptr;
+
+ cnt = (wl_delta_stats_t*)malloc(sizeof(wl_delta_stats_t));
+ if (cnt == NULL) {
+ printf("\tCan not allocate %d bytes for wl delta stats struct\n",
+ (int)sizeof(wl_delta_stats_t));
+ return BCME_NOMEM;
+ }
+ memcpy(cnt, statsbuf, sizeof(wl_delta_stats_t));
+ cnt->version = dtoh16(cnt->version);
+ cnt->length = dtoh16(cnt->length);
+
+ if (cnt->version != WL_DELTA_STATS_T_VERSION) {
+ printf("\tIncorrect version of delta stats struct: expected %d; got %d\n",
+ WL_DELTA_STATS_T_VERSION, cnt->version);
+ free(cnt);
+ return -1;
+ }
+
+ PRINIT();
+ PRVAL(txframe); PRVAL(txbyte); PRVAL(txretrans); PRVAL(txfail); PRNL1();
+ PRVAL(rxframe); PRVAL(rxbyte); PRNL1();
+ PRVAL(rx1mbps); PRVAL(rx2mbps); PRVAL(rx5mbps5); PRVAL(rx6mbps); PRNL1();
+ PRVAL(rx9mbps); PRVAL(rx11mbps); PRVAL(rx12mbps); PRVAL(rx18mbps); PRNL1();
+ PRVAL(rx24mbps); PRVAL(rx36mbps); PRVAL(rx48mbps); PRVAL(rx54mbps); PRNL1();
+ PRNL1();
+
+ PRVAL(rxbadplcp); PRVAL(rxcrsglitch); PRVAL(bphy_rxcrsglitch); PRVAL(bphy_badplcp);
+ PRNL1();
+
+ if (cnt != NULL)
+ free(cnt);
+
+ return (0);
+}
+
+int
+wl_swdiv_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ char *statsbuf;
+ struct wlc_swdiv_stats_v1 *cnt_v1;
+ struct wlc_swdiv_stats_v2 *cnt;
+ int err = BCME_OK;
+ void *ptr;
+ struct cnt_filters_s cnt_filters;
+ struct cnt_filters_s *p_cnt_filters = &cnt_filters;
+
+ memset(&cnt_filters, 0, sizeof(cnt_filters));
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr)))
+ return (err);
+
+ statsbuf = (char *)ptr;
+
+ /* Check for the firmware version and process accordingly */
+ if (wlc_ver_major(wl) <= 5) {
+ cnt_v1 = (struct wlc_swdiv_stats_v1*)malloc(sizeof(struct wlc_swdiv_stats_v1));
+ if (cnt_v1 == NULL) {
+ printf("\tCan not allocate %d bytes for wl swdiv stats struct\n",
+ (int)sizeof(struct wlc_swdiv_stats_v2));
+ return (-1);
+ }
+ memcpy(cnt_v1, statsbuf, sizeof(struct wlc_swdiv_stats_v1));
+ PRINIT();
+ PRVALV1(mws_antsel_ovr_tx); PRVALV1(mws_antsel_ovr_rx); PRNL1();
+ PRVALV1(rx_policy); PRVALV1(tx_policy); PRVALV1(cell_policy); PRNL1();
+ PRVALV1(auto_en); PRVALV1(active_ant); PRVALV1(rxcount); PRNL1();
+ PRVALV1(tx_auto_en); PRVALV1(tx_active_ant); PRNL1();
+ PRVALV1(avg_snr_per_ant0); PRVALV1(avg_snr_per_ant1);
+ PRVALV1(avg_snr_per_ant2); PRNL1();
+ PRVALV1(swap_ge_rxcount0); PRVALV1(swap_ge_rxcount1); PRNL1();
+ PRVALV1(swap_ge_snrthresh0); PRVALV1(swap_ge_snrthresh1); PRNL1();
+ PRVALV1(swap_txfail0); PRVALV1(swap_txfail1); PRNL1();
+ PRVALV1(swap_timer0); PRVALV1(swap_timer1); PRNL1();
+ PRVALV1(swap_alivecheck0); PRVALV1(swap_alivecheck1); PRNL1();
+ PRVALV1(swap_snrdrop0); PRVALV1(swap_snrdrop1); PRNL1();
+ PRVALV1(swap_trig_event_id); PRNL1();
+ PRNL1();
+
+ } else {
+ cnt = (struct wlc_swdiv_stats_v2*)malloc(sizeof(struct wlc_swdiv_stats_v2));
+ if (cnt == NULL) {
+ printf("\tCan not allocate %d bytes for wl swdiv stats struct\n",
+ (int)sizeof(struct wlc_swdiv_stats_v2));
+ return (-1);
+ }
+ memcpy(cnt, statsbuf, sizeof(struct wlc_swdiv_stats_v2));
+ if (cnt->version != 0) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ PRINIT();
+ PRVAL(mws_antsel_ovr_tx); PRVAL(mws_antsel_ovr_rx); PRNL1();
+ PRVAL(rx_policy); PRVAL(tx_policy); PRVAL(cell_policy); PRNL1();
+ PRVAL(auto_en); PRVAL(active_ant); PRVAL(rxcount); PRNL1();
+ PRVAL(tx_auto_en); PRVAL(tx_active_ant); PRNL1();
+ PRVAL(avg_snr_per_ant0); PRVAL(avg_snr_per_ant1);
+ PRVAL(avg_snr_per_ant2); PRNL1();
+ PRVAL(swap_ge_rxcount0); PRVAL(swap_ge_rxcount1); PRNL1();
+ PRVAL(swap_ge_snrthresh0); PRVAL(swap_ge_snrthresh1); PRNL1();
+ PRVAL(swap_txfail0); PRVAL(swap_txfail1); PRNL1();
+ PRVAL(swap_timer0); PRVAL(swap_timer1); PRNL1();
+ PRVAL(swap_alivecheck0); PRVAL(swap_alivecheck1); PRNL1();
+ PRVAL(swap_snrdrop0); PRVAL(swap_snrdrop1); PRNL1();
+ PRVAL(swap_trig_event_id); PRNL1();
+ PRNL1();
+ }
+
+exit :
+ if (wlc_ver_major(wl) <= 5) {
+ if (cnt_v1 != NULL)
+ free(cnt_v1);
+ } else {
+ if (cnt)
+ free(cnt);
+ }
+
+ return err;
+}
+
+int
+wl_clear_counters(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int val;
+#ifdef WL_NAN
+ wl_nan_ioc_t*nanioc;
+ uint16 iocsz = sizeof(wl_nan_ioc_t) + WL_NAN_IOC_BUFSZ;
+#endif /* WL_NAN */
+
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_iovar_getint(wl, cmd->name, &val)))
+ return (err);
+
+#ifdef WL_NAN
+ /* alloc mem for ioctl headr + tlv data */
+ nanioc = calloc(1, iocsz);
+ if (nanioc == NULL)
+ return BCME_NOMEM;
+
+ /* make up nan cmd ioctl header */
+ nanioc->version = htod16(WL_NAN_IOCTL_VERSION);
+ nanioc->id = WL_NAN_CMD_CFG_CLEARCOUNT;
+ nanioc->len = WL_NAN_IOC_BUFSZ;
+
+ wl_nan_do_get_ioctl(wl, nanioc, iocsz);
+ free(nanioc);
+#endif /* WL_NAN */
+
+ return (0);
+}
diff --git a/wl/src/wl/exe/wlu_subcounters.h b/wl/src/wl/exe/wlu_subcounters.h
new file mode 100644
index 0000000..509af4a
--- /dev/null
+++ b/wl/src/wl/exe/wlu_subcounters.h
@@ -0,0 +1,25 @@
+/*
+ * Availability support functions
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: $
+ */
+
+#ifndef _WLU_SUBCOUNTERS_H_
+#define _WLU_SUBCOUNTERS_H_
+#define MAX_SUBCOUNTER_SUPPORTED 64 /* Max subcounters supported. */
+
+cmd_func_t wl_subcounters;
+cmd_func_t wl_counters, wl_if_counters, wl_swdiv_stats, wl_delta_stats;
+cmd_func_t wl_clear_counters;
+
+#endif /* _WLU_SUBCOUNTERS_H_ */
diff --git a/wl/src/wl/exe/wluc_ampdu.c b/wl/src/wl/exe/wluc_ampdu.c
new file mode 100644
index 0000000..afc4da9
--- /dev/null
+++ b/wl/src/wl/exe/wluc_ampdu.c
@@ -0,0 +1,320 @@
+/*
+ * wl ampdu command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_ampdu.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_ampdu_tid;
+static cmd_func_t wl_ampdu_aggr;
+static cmd_func_t wl_ampdu_retry_limit_tid;
+static cmd_func_t wl_ampdu_rr_retry_limit_tid;
+static cmd_func_t wl_ampdu_send_addba;
+static cmd_func_t wl_ampdu_send_delba;
+
+static cmd_t wl_ampdu_cmds[] = {
+ { "ampdu_tid", wl_ampdu_tid, WLC_GET_VAR, WLC_SET_VAR,
+ "enable/disable per-tid ampdu; usage: wl ampdu_tid <tid> [0/1]" },
+ { "ampdu_txaggr", wl_ampdu_aggr, WLC_GET_VAR, WLC_SET_VAR,
+ "enable/disable tx aggregation per tid or all tid for specific interface;\n"
+ "\tget current status: wl ampdu_txaggr\n"
+ "\tenable/disable all category(tid): wl ampdu_txaggr <0/1>\n"
+ "\tenable/disable per category(tid): wl ampdu_txaggr [<tid> <0/1>]"},
+ { "ampdu_rxaggr", wl_ampdu_aggr, WLC_GET_VAR, WLC_SET_VAR,
+ "enable/disable rx aggregation per tid or all tid for specific interface;\n"
+ "\tget current status: wl ampdu_rxaggr\n"
+ "\tenable/disable all category(tid): wl ampdu_rxaggr <0/1>\n"
+ "\tenable/disable per category(tid): wl ampdu_rxaggr [<tid> <0/1>]"},
+ { "ampdu_retry_limit_tid", wl_ampdu_retry_limit_tid, WLC_GET_VAR, WLC_SET_VAR,
+ "Set per-tid ampdu retry limit; usage: wl ampdu_retry_limit_tid <tid> [0~31]" },
+ { "ampdu_rr_retry_limit_tid", wl_ampdu_rr_retry_limit_tid, WLC_GET_VAR, WLC_SET_VAR,
+ "Set per-tid ampdu regular rate retry limit; usage: "
+ "wl ampdu_rr_retry_limit_tid <tid> [0~31]" },
+ { "ampdu_send_addba", wl_ampdu_send_addba, WLC_GET_VAR, WLC_SET_VAR,
+ "send addba to specified ea-tid; usage: wl ampdu_send_addba <tid> <ea>" },
+ { "ampdu_send_delba", wl_ampdu_send_delba, WLC_GET_VAR, WLC_SET_VAR,
+ "send delba to specified ea-tid; usage: wl ampdu_send_delba <tid> <ea> [initiator]" },
+ { "ampdu_txq_prof_start", wl_var_void, -1, WLC_SET_VAR,
+ "start sample txq profiling data"},
+ { "ampdu_txq_prof_dump", wl_var_void, -1, WLC_SET_VAR,
+ "show txq histogram"},
+ { "ampdu_txq_ss", wl_var_void, -1, WLC_SET_VAR,
+ "take txq snapshot"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_ampdu_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register ampdu commands */
+ wl_module_cmds_register(wl_ampdu_cmds);
+}
+
+static int
+wl_ampdu_tid(void *wl, cmd_t *cmd, char **argv)
+{
+ char *param;
+ const char *cmdname = "ampdu_tid";
+ struct ampdu_tid_control atc, *reply;
+ uint8 tid;
+ int err;
+ void *ptr = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+
+ tid = atoi(param);
+ if (tid > MAXPRIO)
+ return BCME_USAGE_ERROR;
+ atc.tid = tid;
+
+ if ((param = *++argv)) {
+ atc.enable = atoi(param);
+ err = wlu_var_setbuf(wl, cmdname, &atc, sizeof(atc));
+ } else {
+ if ((err = wlu_var_getbuf_sm(wl, cmdname, &atc, sizeof(atc), &ptr) < 0))
+ return err;
+ reply = (struct ampdu_tid_control *)ptr;
+ printf("AMPDU for tid %d: %d\n", tid, reply->enable);
+ }
+ return err;
+}
+
+static int
+wl_ampdu_aggr(void *wl, cmd_t *cmd, char **argv)
+{
+ struct ampdu_aggr aggr, *reply;
+ int err;
+ int idx;
+ void *ptr = NULL;
+
+ if (argv[1] == NULL) {
+ /* get current status of aggregation */
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, &aggr, sizeof(aggr), &ptr) < 0)) {
+ return err;
+ }
+ reply = ptr;
+ printf("%s_override: %s\n", cmd->name, (reply->aggr_override == AUTO) ? "AUTO" :
+ ((reply->aggr_override == ON) ? "ON" : "OFF"));
+ for (idx = 0; idx < NUMPRIO; idx++) {
+ printf("tid:%d status:%d\n", idx, isbitset(reply->enab_TID_bmap, idx));
+ }
+ return err;
+ }
+ memset(&aggr, 0, sizeof(aggr));
+ if (argv[2] == NULL) {
+ /* Set for all TID */
+ bool enab = atoi(*++argv);
+ aggr.enab_TID_bmap = enab ? NBITMASK(NUMPRIO) : 0;
+ aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
+ } else {
+ char *param;
+ /* Set for specific TIDs */
+ while ((param = *++argv) != NULL) {
+ uint8 tid;
+ bool enab;
+ tid = atoi(param);
+ if (tid > MAXPRIO) {
+ return BCME_USAGE_ERROR;
+ }
+ if ((param = *++argv) == NULL) {
+ return BCME_USAGE_ERROR;
+ }
+ enab = atoi(param);
+ setbit(&aggr.conf_TID_bmap, tid);
+ if (enab) {
+ setbit(&aggr.enab_TID_bmap, tid);
+ }
+ }
+ }
+ err = wlu_var_setbuf(wl, cmd->name, &aggr, sizeof(aggr));
+ return err;
+}
+
+static int
+wl_ampdu_retry_limit_tid(void *wl, cmd_t *cmd, char **argv)
+{
+ char *param;
+ const char *cmdname = "ampdu_retry_limit_tid";
+ struct ampdu_retry_tid retry_limit, *reply;
+ uint8 tid;
+ int err;
+ void *ptr = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+
+ tid = atoi(param);
+ if (tid > MAXPRIO)
+ return BCME_USAGE_ERROR;
+ retry_limit.tid = tid;
+
+ if ((param = *++argv)) {
+ retry_limit.retry = atoi(param);
+ err = wlu_var_setbuf(wl, cmdname, &retry_limit, sizeof(retry_limit));
+ } else {
+ if ((err = wlu_var_getbuf(wl, cmdname, &retry_limit,
+ sizeof(retry_limit), &ptr)) < 0)
+ return err;
+ reply = (struct ampdu_retry_tid *)ptr;
+ printf("AMPDU retry limit for tid %d: %d\n", tid, reply->retry);
+ }
+ return err;
+}
+
+static int
+wl_ampdu_rr_retry_limit_tid(void *wl, cmd_t *cmd, char **argv)
+{
+ char *param;
+ const char *cmdname = "ampdu_rr_retry_limit_tid";
+ struct ampdu_retry_tid retry_limit, *reply;
+ uint8 tid;
+ int err;
+ void *ptr = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+
+ tid = atoi(param);
+ if (tid > MAXPRIO)
+ return BCME_USAGE_ERROR;
+ retry_limit.tid = tid;
+
+ if ((param = *++argv)) {
+ retry_limit.retry = atoi(param);
+ err = wlu_var_setbuf(wl, cmdname, &retry_limit, sizeof(retry_limit));
+ } else {
+ if ((err = wlu_var_getbuf(wl, cmdname, &retry_limit,
+ sizeof(retry_limit), &ptr)) < 0)
+ return err;
+ reply = (struct ampdu_retry_tid *)ptr;
+ printf("AMPDU regular rate retry limit for tid %d: %d\n", tid, reply->retry);
+ }
+ return err;
+}
+
+
+static int
+wl_ampdu_send_addba(void *wl, cmd_t *cmd, char **argv)
+{
+ char *param;
+ const char *cmdname = "ampdu_send_addba";
+ struct ampdu_ea_tid aet;
+ uint8 tid;
+
+ UNUSED_PARAMETER(cmd);
+
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+
+ tid = atoi(param);
+ if (tid > MAXPRIO)
+ return BCME_USAGE_ERROR;
+ aet.tid = tid;
+
+ argv++;
+ if (!*argv) {
+ printf("error: missing address\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!wl_ether_atoe(*argv, &aet.ea)) {
+ printf("error: could not parse MAC address %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ return wlu_var_setbuf(wl, cmdname, &aet, sizeof(aet));
+}
+
+static int
+wl_ampdu_send_delba(void *wl, cmd_t *cmd, char **argv)
+{
+ char *param;
+ const char *cmdname = "ampdu_send_delba";
+ struct ampdu_ea_tid aet;
+ uint8 tid;
+
+ UNUSED_PARAMETER(cmd);
+
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+
+ tid = atoi(param);
+ if (tid > MAXPRIO)
+ return BCME_USAGE_ERROR;
+ aet.tid = tid;
+
+ argv++;
+ if (!*argv) {
+ printf("error: missing address\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!wl_ether_atoe(*argv, &aet.ea)) {
+ printf("error: could not parse MAC address %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* initiator (optional argument), 0 is recipient, 1 is originator */
+ argv++;
+ if (*argv) {
+ aet.initiator = atoi(*argv);
+ }
+ else {
+ /* default is originator */
+ aet.initiator = TRUE;
+ }
+
+ return wlu_var_setbuf(wl, cmdname, &aet, sizeof(aet));
+}
diff --git a/wl/src/wl/exe/wluc_ampdu_cmn.c b/wl/src/wl/exe/wluc_ampdu_cmn.c
new file mode 100644
index 0000000..3d7f016
--- /dev/null
+++ b/wl/src/wl/exe/wluc_ampdu_cmn.c
@@ -0,0 +1,93 @@
+/*
+ * wl ampdu_cmn command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_ampdu_cmn.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_ampdu_activate_test;
+
+static cmd_t wl_ampdu_cmn_cmds[] = {
+ { "ampdu_activate_test", wl_ampdu_activate_test, -1, WLC_SET_VAR,
+ "actiate" },
+ { "ampdu_clear_dump", wl_var_void, -1, WLC_SET_VAR,
+ "clear ampdu counters"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_ampdu_cmn_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register ampdu_cmn commands */
+ wl_module_cmds_register(wl_ampdu_cmn_cmds);
+}
+
+static int
+wl_ampdu_activate_test(void *wl, cmd_t *cmd, char **argv)
+{
+ char *param;
+ const char *cmdname = "ampdu_activate_test";
+ struct agg {
+ bool val1;
+ bool val2;
+ } x;
+ int err = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ if ((param = *++argv) == NULL)
+ return BCME_USAGE_ERROR;
+
+ x.val1 = atoi(param);
+ if ((param = *++argv)) {
+ x.val2 = atoi(param);
+ printf("%d %d\n", x.val1, x.val2);
+ err = wlu_var_setbuf(wl, cmdname, &x, sizeof(x));
+ }
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_anqpo.c b/wl/src/wl/exe/wluc_anqpo.c
new file mode 100644
index 0000000..5a11f17
--- /dev/null
+++ b/wl/src/wl/exe/wluc_anqpo.c
@@ -0,0 +1,596 @@
+/*
+ * wl anqpo command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_anqpo.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifdef LINUX
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* LINUX */
+
+static cmd_func_t wl_anqpo_set;
+static cmd_func_t wl_anqpo_stop_query;
+static cmd_func_t wl_anqpo_start_query;
+static cmd_func_t wl_anqpo_ignore_ssid_list;
+static cmd_func_t wl_anqpo_ignore_bssid_list;
+#if defined(linux)
+static cmd_func_t wl_anqpo_results;
+#endif /* linux */
+
+static cmd_t wl_anqpo_cmds[] = {
+ { "anqpo_set", wl_anqpo_set, -1, -1,
+ "set ANQP offload parameters\n"
+ "\tusage: anqpo_set [max_retransmit <number>]\n"
+ "\t\t[response_timeout <msec>] [max_comeback_delay <msec>]\n"
+ "\t\t[max_retries <number>] [query \"encoded ANQP query\"]"
+ },
+ { "anqpo_stop_query", wl_anqpo_stop_query, -1, WLC_SET_VAR,
+ "stop ANQP query\n"
+ "\tusage: anqpo_stop_query"
+ },
+ { "anqpo_start_query", wl_anqpo_start_query, -1, WLC_SET_VAR,
+ "start ANQP query to peer(s)\n"
+ "\tusage: anqpo_start_query <channel> <xx:xx:xx:xx:xx:xx>\n"
+ "\t\t[<channel> <xx:xx:xx:xx:xx:xx>]>"
+ },
+ { "anqpo_auto_hotspot", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "automatic ANQP query to maximum number of hotspot APs, default 0 (disabled)\n"
+ "\tusage: anqpo_auto_hotspot [max]"
+ },
+ { "anqpo_ignore_mode", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "ignore duplicate SSIDs or BSSIDs, default 0 (SSID)\n"
+ "\tusage: anqpo_ignore_mode [0 (SSID) | 1 (BSSID)]"
+ },
+ { "anqpo_ignore_ssid_list", wl_anqpo_ignore_ssid_list, WLC_GET_VAR, WLC_SET_VAR,
+ "get, clear, set, or append to ANQP offload ignore SSID list\n"
+ "\tusage: wl anqpo_ignore_ssid_list [clear |\n"
+ "\t\tset <ssid1> [ssid2] |\n"
+ "\t\tappend <ssid3> [ssid4]>"
+ },
+ { "anqpo_ignore_bssid_list", wl_anqpo_ignore_bssid_list, WLC_GET_VAR, WLC_SET_VAR,
+ "get, clear, set, or append to ANQP offload ignore BSSID list\n"
+ "\tusage: wl anqpo_ignore_bssid_list [clear |\n"
+ "\t\tset <xx:xx:xx:xx:xx:xx> [xx:xx:xx:xx:xx:xx] |\n"
+ "\t\tappend <xx:xx:xx:xx:xx:xx> [xx:xx:xx:xx:xx:xx]]>"
+ },
+#if defined(linux)
+ { "anqpo_results", wl_anqpo_results, -1, WLC_SET_VAR,
+ "Listens and displays ANQP results."
+ },
+#endif /* linux */
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_anqpo_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register anqpo commands */
+ wl_module_cmds_register(wl_anqpo_cmds);
+}
+
+#define ANQPO_EVENTS_BUFFER_SIZE 2048
+
+static int
+wl_anqpo_set(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = BCME_USAGE_ERROR, malloc_size;
+ char *buffer;
+ wl_anqpo_set_t *set;
+ int length;
+
+ UNUSED_PARAMETER(cmd);
+
+ malloc_size = OFFSETOF(wl_anqpo_set_t, query_data) +
+ (ANQPO_MAX_QUERY_SIZE * sizeof(uint8));
+ buffer = malloc(malloc_size);
+ if (buffer == NULL) {
+ fprintf(stderr, "Not enough memory\n");
+ return BCME_NOMEM;
+ }
+ memset(buffer, 0, malloc_size);
+ set = (wl_anqpo_set_t *)buffer;
+ /* parameters not configured by default */
+ set->max_retransmit = -1;
+ set->response_timeout = -1;
+ set->max_comeback_delay = -1;
+ set->max_retries = -1;
+
+ while (*++argv) {
+ if (!stricmp(*argv, "max_retransmit")) {
+ if (*++argv)
+ set->max_retransmit = atoi(*argv);
+ else {
+ fprintf(stderr, "Missing max retransmit\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ }
+ else if (!stricmp(*argv, "response_timeout")) {
+ if (*++argv)
+ set->response_timeout = atoi(*argv);
+ else {
+ fprintf(stderr, "Missing response timeout\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ }
+ else if (!stricmp(*argv, "max_comeback_delay")) {
+ if (*++argv)
+ set->max_comeback_delay = atoi(*argv);
+ else {
+ fprintf(stderr, "Missing max comeback delay\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ }
+ else if (!stricmp(*argv, "max_retries")) {
+ if (*++argv)
+ set->max_retries = atoi(*argv);
+ else {
+ fprintf(stderr, "Missing retries\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ }
+ else if (!stricmp(*argv, "query")) {
+ if (*++argv) {
+ if ((set->query_len = hexstr2hex(*argv)) == 0) {
+ fprintf(stderr, "Invalid ANQP query\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ if (set->query_len > ANQPO_MAX_QUERY_SIZE) {
+ fprintf(stderr, "ANQP query size %d exceeds %d\n",
+ set->query_len, ANQPO_MAX_QUERY_SIZE);
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ memcpy(set->query_data, *argv, set->query_len);
+ }
+ else {
+ fprintf(stderr, "Missing ANQP query\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ }
+ else {
+ fprintf(stderr, "Invalid parameter %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+
+ }
+
+ length = OFFSETOF(wl_anqpo_set_t, query_data) + set->query_len;
+ set->max_retransmit = htod16(set->max_retransmit);
+ set->response_timeout = htod16(set->response_timeout);
+ set->max_comeback_delay = htod16(set->max_comeback_delay);
+ set->max_retries = htod16(set->max_retries);
+ set->query_len = htod16(set->query_len);
+
+ err = wlu_iovar_set(wl, cmd->name, set, length);
+
+done:
+ free(buffer);
+ return err;
+}
+
+static int
+wl_anqpo_stop_query(void *wl, cmd_t *cmd, char **argv)
+{
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ return wlu_iovar_set(wl, cmd->name, 0, 0);
+}
+
+static int
+wl_anqpo_start_query(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = BCME_USAGE_ERROR, malloc_size;
+ char *buffer;
+ wl_anqpo_peer_list_t *list;
+ wl_anqpo_peer_t *peer;
+ int c;
+ int length;
+
+ UNUSED_PARAMETER(cmd);
+
+ malloc_size = OFFSETOF(wl_anqpo_peer_list_t, peer) +
+ (ANQPO_MAX_PEER_LIST * sizeof(wl_anqpo_peer_t));
+ buffer = malloc(malloc_size);
+ if (buffer == NULL) {
+ fprintf(stderr, "Not enough memory\n");
+ return BCME_NOMEM;
+ }
+ memset(buffer, 0, malloc_size);
+ list = (wl_anqpo_peer_list_t *)buffer;
+ peer = &list->peer[0];
+
+ c = 1;
+ while (argv[c] && argv[c + 1]) {
+ if ((peer->channel = htod16(atoi(argv[c]))) == 0) {
+ fprintf(stderr, "Invalid channel\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ if (!wl_ether_atoe(argv[c + 1], &peer->addr)) {
+ fprintf(stderr, "Invalid address\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ list->count++;
+ c += 2;
+ peer++;
+ }
+
+ length = OFFSETOF(wl_anqpo_peer_list_t, peer) +
+ (list->count * sizeof(wl_anqpo_peer_t));
+ list->count = htod16(list->count);
+
+ err = wlu_iovar_set(wl, cmd->name, list, length);
+
+done:
+ free(buffer);
+ return err;
+}
+
+static int
+wl_anqpo_ignore_ssid_list(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = BCME_USAGE_ERROR, malloc_size;
+ char *buffer;
+ wl_anqpo_ignore_ssid_list_t *list;
+ int length;
+
+ UNUSED_PARAMETER(cmd);
+
+ malloc_size = OFFSETOF(wl_anqpo_ignore_ssid_list_t, ssid) +
+ (ANQPO_MAX_IGNORE_SSID * (sizeof(wl_anqpo_ignore_ssid_list_t) -
+ OFFSETOF(wl_anqpo_ignore_ssid_list_t, ssid)));
+ buffer = malloc(malloc_size);
+ if (buffer == NULL) {
+ fprintf(stderr, "Not enough memory\n");
+ return BCME_NOMEM;
+ }
+ memset(buffer, 0, malloc_size);
+ list = (wl_anqpo_ignore_ssid_list_t *)buffer;
+
+ /* get */
+ if (!argv[1]) {
+ int i;
+
+ if ((err = wlu_iovar_get(wl, cmd->name, list, malloc_size)) < 0)
+ goto done;
+ list->count = dtoh16(list->count);
+ for (i = 0; i < list->count; i++) {
+ char ssidbuf[SSID_FMT_BUF_LEN];
+
+ wl_format_ssid(ssidbuf, list->ssid[i].SSID, list->ssid[i].SSID_len);
+ printf("%s\n", ssidbuf);
+ }
+ goto done;
+ }
+
+ /* set */
+ argv++;
+ if (!stricmp(*argv, "clear")) {
+ list->is_clear = TRUE;
+ }
+ else if (!stricmp(*argv, "set")) {
+ list->is_clear = TRUE;
+ while (*++argv) {
+ int len = strlen(*argv);
+ if (list->count > ANQPO_MAX_IGNORE_SSID) {
+ fprintf(stderr, "Too many BSSID\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ if (len > 32) {
+ fprintf(stderr, "SSID too long\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ list->ssid[list->count].SSID_len = len;
+ memcpy(list->ssid[list->count].SSID, *argv, len);
+ list->count++;
+ }
+ }
+ else if (!stricmp(*argv, "append")) {
+ while (*++argv) {
+ int len = strlen(*argv);
+ if (list->count > ANQPO_MAX_IGNORE_SSID) {
+ fprintf(stderr, "Too many BSSID\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ if (len > 32) {
+ fprintf(stderr, "SSID too long\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ list->ssid[list->count].SSID_len = len;
+ memcpy(list->ssid[list->count].SSID, *argv, len);
+ list->count++;
+ }
+ }
+ else {
+ fprintf(stderr, "Invalid parameter %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+
+ length = OFFSETOF(wl_anqpo_ignore_ssid_list_t, ssid) +
+ (list->count * (sizeof(wl_anqpo_ignore_ssid_list_t) -
+ OFFSETOF(wl_anqpo_ignore_ssid_list_t, ssid)));
+ list->count = htod16(list->count);
+
+ err = wlu_iovar_set(wl, cmd->name, list, length);
+
+done:
+ free(buffer);
+ return err;
+}
+
+static int
+wl_anqpo_ignore_bssid_list(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = BCME_USAGE_ERROR, malloc_size;
+ char *buffer;
+ wl_anqpo_ignore_bssid_list_t *list;
+ int length;
+
+ UNUSED_PARAMETER(cmd);
+
+ malloc_size = OFFSETOF(wl_anqpo_ignore_bssid_list_t, bssid) +
+ (ANQPO_MAX_IGNORE_BSSID * (sizeof(wl_anqpo_ignore_bssid_list_t) -
+ OFFSETOF(wl_anqpo_ignore_bssid_list_t, bssid)));
+ buffer = malloc(malloc_size);
+ if (buffer == NULL) {
+ fprintf(stderr, "Not enough memory\n");
+ return BCME_NOMEM;
+ }
+ memset(buffer, 0, malloc_size);
+ list = (wl_anqpo_ignore_bssid_list_t *)buffer;
+
+ /* get */
+ if (!argv[1]) {
+ int i;
+
+ if ((err = wlu_iovar_get(wl, cmd->name, list, malloc_size)) < 0)
+ goto done;
+ list->count = dtoh16(list->count);
+ for (i = 0; i < list->count; i++) {
+ printf("%s\n", wl_ether_etoa(&list->bssid[i]));
+ }
+ goto done;
+ }
+
+ /* set */
+ argv++;
+ if (!stricmp(*argv, "clear")) {
+ list->is_clear = TRUE;
+ }
+ else if (!stricmp(*argv, "set")) {
+ list->is_clear = TRUE;
+ while (*++argv) {
+ if (list->count > ANQPO_MAX_IGNORE_BSSID) {
+ fprintf(stderr, "Too many BSSID\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ if (!wl_ether_atoe(*argv, &list->bssid[list->count])) {
+ fprintf(stderr, "Invalid BSSID\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ list->count++;
+ }
+ }
+ else if (!stricmp(*argv, "append")) {
+ while (*++argv) {
+ if (list->count > ANQPO_MAX_IGNORE_BSSID) {
+ fprintf(stderr, "Too many BSSID\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ if (!wl_ether_atoe(*argv, &list->bssid[list->count])) {
+ fprintf(stderr, "Invalid BSSID\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+ list->count++;
+ }
+ }
+ else {
+ fprintf(stderr, "Invalid parameter %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+
+ length = OFFSETOF(wl_anqpo_ignore_bssid_list_t, bssid) +
+ (list->count * (sizeof(wl_anqpo_ignore_bssid_list_t) -
+ OFFSETOF(wl_anqpo_ignore_bssid_list_t, bssid)));
+ list->count = htod16(list->count);
+
+ err = wlu_iovar_set(wl, cmd->name, list, length);
+
+done:
+ free(buffer);
+ return err;
+}
+
+#if defined(linux)
+static int
+wl_anqpo_results(void *wl, cmd_t *cmd, char **argv)
+{
+ int fd, err, octets;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ char *data;
+ uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* event bit mask */
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
+
+ memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN);
+ event_inds_mask[WLC_E_GAS_FRAGMENT_RX / 8] |= 1 << (WLC_E_GAS_FRAGMENT_RX % 8);
+ event_inds_mask[WLC_E_GAS_COMPLETE / 8] |= 1 << (WLC_E_GAS_COMPLETE % 8);
+ if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
+ goto exit2;
+
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
+ if (fd < 0) {
+ printf("Cannot create socket %d\n", fd);
+ err = -1;
+ goto exit2;
+ }
+
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ printf("Cannot get index %d\n", err);
+ goto exit1;
+ }
+
+ /* bind the socket first before starting so we won't miss any event */
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ printf("Cannot bind %d\n", err);
+ goto exit1;
+ }
+
+ data = (char*)malloc(ANQPO_EVENTS_BUFFER_SIZE);
+
+ if (data == NULL) {
+ printf("Cannot not allocate %d bytes for events receive buffer\n",
+ ANQPO_EVENTS_BUFFER_SIZE);
+ err = BCME_NOMEM;
+ goto exit1;
+ }
+
+ /* receive result */
+ while (1) {
+ bcm_event_t *bcm_event;
+ int event_type;
+
+ octets = recv(fd, data, ANQPO_EVENTS_BUFFER_SIZE, 0);
+ bcm_event = (bcm_event_t *)data;
+ event_type = ntoh32(bcm_event->event.event_type);
+
+ if (octets >= (int)sizeof(bcm_event_t)) {
+ uint32 status = ntoh32(bcm_event->event.status);
+
+ if (event_type == WLC_E_GAS_FRAGMENT_RX) {
+ wl_event_gas_t *gas_data =
+ (wl_event_gas_t *)&data[sizeof(bcm_event_t)];
+
+ gas_data->channel = dtoh16(gas_data->channel);
+ gas_data->status_code = dtoh16(gas_data->status_code);
+ gas_data->data_len = dtoh16(gas_data->data_len);
+
+ printf("WLC_E_GAS_FRAGMENT_RX: %s\n",
+ status == WLC_E_STATUS_PARTIAL ? "WLC_E_STATUS_PARTIAL" :
+ status == WLC_E_STATUS_SUCCESS ? "WLC_E_STATUS_SUCCESS" :
+ status == WLC_E_STATUS_FAIL ? "WLC_E_STATUS_FAIL" :
+ "unknown");
+ printf(" channel = %d\n", gas_data->channel);
+ printf(" peer = %s\n",
+ wl_ether_etoa(&bcm_event->event.addr));
+ printf(" dialog token = 0x%02x (%d)\n",
+ gas_data->dialog_token, gas_data->dialog_token);
+ printf(" fragment id = 0x%02x\n", gas_data->fragment_id);
+ printf(" GAS status = %s\n",
+ gas_data->status_code == DOT11_SC_SUCCESS ? "SUCCESS" :
+ gas_data->status_code == DOT11_SC_FAILURE ? "UNSPECIFIED" :
+ gas_data->status_code == DOT11_SC_ADV_PROTO_NOT_SUPPORTED ?
+ "ADVERTISEMENT_PROTOCOL_NOT_SUPPORTED" :
+ gas_data->status_code == DOT11_SC_NO_OUTSTAND_REQ ?
+ "NO_OUTSTANDING_REQUEST" :
+ gas_data->status_code == DOT11_SC_RSP_NOT_RX_FROM_SERVER ?
+ "RESPONSE_NOT_RECEIVED_FROM_SERVER" :
+ gas_data->status_code == DOT11_SC_TIMEOUT ?
+ "TIMEOUT" :
+ gas_data->status_code == DOT11_SC_QUERY_RSP_TOO_LARGE ?
+ "QUERY_RESPONSE_TOO_LARGE" :
+ gas_data->status_code == DOT11_SC_SERVER_UNREACHABLE ?
+ "SERVER_UNREACHABLE" :
+ gas_data->status_code == DOT11_SC_TRANSMIT_FAILURE ?
+ "TRANSMISSION_FAILURE" : "unknown");
+ printf(" GAS data length = %d\n", gas_data->data_len);
+ if (gas_data->data_len) {
+ wl_hexdump(gas_data->data, gas_data->data_len);
+ }
+ }
+ else if (event_type == WLC_E_GAS_COMPLETE) {
+ printf("WLC_E_GAS_COMPLETE: %s\n",
+ status == WLC_E_STATUS_SUCCESS ? "WLC_E_STATUS_SUCCESS" :
+ "unknown");
+ }
+ }
+ }
+
+ free(data);
+exit1:
+ close(fd);
+exit2:
+ return err;
+}
+#endif /* linux */
diff --git a/wl/src/wl/exe/wluc_ap.c b/wl/src/wl/exe/wluc_ap.c
new file mode 100644
index 0000000..11f5016
--- /dev/null
+++ b/wl/src/wl/exe/wluc_ap.c
@@ -0,0 +1,606 @@
+/*
+ * wl ap command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_ap.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_maclist_1;
+static cmd_func_t wl_management_info;
+static cmd_func_t wl_bsscfg_enable;
+static cmd_func_t wl_radar;
+
+static cmd_t wl_ap_cmds[] = {
+ { "ap", wl_int, WLC_GET_AP, WLC_SET_AP,
+ "Set AP mode: 0 (STA) or 1 (AP)" },
+ { "tkip_countermeasures", wl_int, -1, WLC_TKIP_COUNTERMEASURES,
+ "Enable or disable TKIP countermeasures (TKIP-enabled AP only)\n"
+ "\t0 - disable\n"
+ "\t1 - enable" },
+ { "shortslot_restrict", wl_int, WLC_GET_SHORTSLOT_RESTRICT, WLC_SET_SHORTSLOT_RESTRICT,
+ "Get/Set AP Restriction on associations for 11g Short Slot Timing capable STAs.\n"
+ "\t0 - Do not restrict association based on ShortSlot capability\n"
+ "\t1 - Restrict association to STAs with ShortSlot capability" },
+ { "ignore_bcns", wl_int, WLC_GET_IGNORE_BCNS, WLC_SET_IGNORE_BCNS,
+ "AP only (G mode): Check for beacons without NONERP element"
+ "(0=Examine beacons, 1=Ignore beacons)" },
+ { "scb_timeout", wl_int, WLC_GET_SCB_TIMEOUT, WLC_SET_SCB_TIMEOUT,
+ "AP only: inactivity timeout value for authenticated stas" },
+ { "assoclist", wl_maclist, WLC_GET_ASSOCLIST, -1,
+ "AP only: Get the list of associated MAC addresses."},
+ { "radar", wl_radar, WLC_GET_RADAR, WLC_SET_RADAR,
+ "Enable/Disable radar. One-shot Radar simulation with optional sub-band"},
+ { "authe_sta_list", wl_maclist_1, WLC_GET_VAR, -1,
+ "Get authenticated sta mac address list"},
+ { "autho_sta_list", wl_maclist_1, WLC_GET_VAR, -1,
+ "Get authorized sta mac address list"},
+ { "beacon_info", wl_management_info, WLC_GET_VAR, -1,
+ "Returns the 802.11 management frame beacon information\n"
+ "Usage: wl beacon_info [-f file] [-r]\n"
+ "\t-f Write beacon data to file\n"
+ "\t-r Raw hex dump of beacon data" },
+ { "probe_resp_info", wl_management_info, WLC_GET_VAR, -1,
+ "Returns the 802.11 management frame probe response information\n"
+ "Usage: wl probe_resp_info [-f file] [-r]\n"
+ "\t-f Write probe response data to file\n"
+ "\t-r Raw hex dump of probe response data" },
+ { "bss", wl_bsscfg_enable, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get BSS enabled status: up/down"},
+ { "closednet", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get BSS closed network attribute"},
+ { "ap_isolate", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get AP isolation"},
+ { "mode_reqd", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get operational capabilities required for STA to associate to the BSS "
+ "supported by the interface.\n"
+ "\tUsage: wl [-i ifname] mode_reqd [value]\n"
+ "\t wl mode_reqd [-C bss_idx ] [value]\n"
+ "\t\t <ifname> is the name of the interface corresponding to the BSS.\n"
+ "\t\t\t If the <ifname> is not given, the primary BSS is assumed.\n"
+ "\t\t <bss_idx> is the the BSS configuration index.\n"
+ "\t\t\t If the <bss_idx> is not given, configuraion #0 is assumed\n"
+ "\t\t <value> is the numeric values in the range [0..3]\n"
+ "\t\t 0 - no requirements on joining devices.\n"
+ "\t\t 1 - devices must advertise ERP (11g) capabilities to be allowed to associate\n"
+ "\t\t\t to a 2.4 GHz BSS.\n"
+ "\t\t 2 - devices must advertise HT (11n) capabilities to be allowed to associate\n"
+ "\t\t\t to a BSS.\n"
+ "\t\t 3 - devices must advertise VHT (11ac) capabilities to be allowed to associate\n"
+ "\t\t\t to a BSS.\n"
+ "\tThe command returns an error if the BSS interface is up.\n"
+ "\tThis configuration can only be changed while the BSS interface is down.\n"
+ "\tNote that support for HT implies support for ERP,\n"
+ "\tand support for VHT implies support for HT."},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_ap_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register ap commands */
+ wl_module_cmds_register(wl_ap_cmds);
+}
+
+/*
+ * Get Radar Enable/Disable status
+ * Set one-shot radar simulation with optional subband
+ */
+int
+wl_radar(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int val;
+ char *endptr = NULL;
+ UNUSED_PARAMETER(cmd);
+
+ if (!*++argv) {
+ if ((ret = wlu_get(wl, WLC_GET_RADAR, &val, sizeof(int))) < 0) {
+ return ret;
+ }
+
+ val = dtoh32(val);
+ wl_printint(val);
+ } else {
+ struct {
+ int val;
+ uint sub;
+ } radar;
+ radar.val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+
+ radar.val = htod32(radar.val);
+ radar.sub = 0;
+ if (!*++argv) {
+ ret = wlu_set(wl, WLC_SET_RADAR, &radar.val, sizeof(radar.val));
+ } else {
+ radar.sub = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+ radar.sub = htod32(radar.sub);
+ ret = wlu_set(wl, WLC_SET_RADAR, &radar, sizeof(radar));
+ }
+ }
+
+ return ret;
+}
+
+static int
+wl_bsscfg_enable(void *wl, cmd_t *cmd, char **argv)
+{
+ char *endptr;
+ const char *val_name = "bss";
+ int bsscfg_idx = 0;
+ int val;
+ int consumed;
+ int ret;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* skip the command name */
+ argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((ret = wl_cfg_option(argv, val_name, &bsscfg_idx, &consumed)) != 0)
+ return ret;
+
+ argv += consumed;
+ if (consumed == 0) { /* Use the -i parameter if that was present */
+ bsscfg_idx = -1;
+ }
+
+ if (!*argv) {
+ bsscfg_idx = htod32(bsscfg_idx);
+ ret = wlu_iovar_getbuf(wl, val_name, &bsscfg_idx, sizeof(bsscfg_idx),
+ buf, WLC_IOCTL_MAXLEN);
+ if (ret < 0)
+ return ret;
+ val = *(int*)buf;
+ val = dtoh32(val);
+ if (val)
+ printf("up\n");
+ else
+ printf("down\n");
+ return 0;
+ } else {
+ struct {
+ int cfg;
+ int val;
+ } bss_setbuf;
+ if (!stricmp(*argv, "move"))
+ val = WLC_AP_IOV_OP_MOVE;
+ else if (!stricmp(*argv, "ap"))
+ val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
+ else if (!stricmp(*argv, "sta"))
+ val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
+ else if (!stricmp(*argv, "up"))
+ val = WLC_AP_IOV_OP_ENABLE;
+ else if (!stricmp(*argv, "down"))
+ val = WLC_AP_IOV_OP_DISABLE;
+ else if (!stricmp(*argv, "del"))
+ val = WLC_AP_IOV_OP_DELETE;
+ else {
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+ }
+ bss_setbuf.cfg = htod32(bsscfg_idx);
+ bss_setbuf.val = htod32(val);
+
+ return wlu_iovar_set(wl, val_name, &bss_setbuf, sizeof(bss_setbuf));
+ }
+}
+
+static void dump_management_fields(uint8 *data, int len)
+{
+ int i, tag_len;
+ uint8 tag;
+ char temp[64];
+ uint8 *p;
+
+ while (len > 0) {
+ /* Get the tag */
+ tag = *data;
+ data++; len--;
+
+ /* Get the tag length */
+ tag_len = (int) *data;
+ data++; len--;
+
+ printf("Tag:%d Len:%d - ", tag, tag_len);
+
+ switch (tag) {
+ case DOT11_MNG_SSID_ID:
+ for (i = 0; i < tag_len; i++) {
+ temp[i] = data[i];
+ }
+ if (i < 64) {
+ temp[i] = '\0';
+ }
+ printf("SSID: '%s'\n", temp);
+ break;
+ case DOT11_MNG_FH_PARMS_ID:
+ printf("FH Parameter Set\n");
+ break;
+ case DOT11_MNG_DS_PARMS_ID:
+ printf("DS Parameter Set\n");
+ break;
+ case DOT11_MNG_CF_PARMS_ID:
+ printf("CF Parameter Set\n");
+ break;
+ case DOT11_MNG_RATES_ID:
+ printf("Supported Rates\n");
+ break;
+ case DOT11_MNG_TIM_ID:
+ printf("Traffic Indication Map (TIM)\n");
+ break;
+ case DOT11_MNG_IBSS_PARMS_ID:
+ printf("IBSS Parameter Set\n");
+ break;
+ case DOT11_MNG_COUNTRY_ID:
+ p = data;
+ printf("Country '%c%c%c'\n",
+ data[0], data[1], data[2]);
+ p += DOT11_MNG_COUNTRY_ID_LEN;
+ while (((data+tag_len) - p) >= DOT11_MNG_COUNTRY_ID_LEN) {
+ printf("Start Channel: %d, Channels: %d, "
+ "Max TX Power: %d dBm\n",
+ p[0], p[1], p[2]);
+ p += DOT11_MNG_COUNTRY_ID_LEN;
+ }
+ break;
+ case DOT11_MNG_HOPPING_PARMS_ID:
+ printf("Hopping Pattern Parameters\n");
+ break;
+ case DOT11_MNG_HOPPING_TABLE_ID:
+ printf("Hopping Pattern Table\n");
+ break;
+ case DOT11_MNG_REQUEST_ID:
+ printf("Request\n");
+ break;
+ case DOT11_MNG_QBSS_LOAD_ID:
+ printf("QBSS Load\n");
+ break;
+ case DOT11_MNG_EDCA_PARAM_ID:
+ printf("EDCA Parameter\n");
+ break;
+ case DOT11_MNG_CHALLENGE_ID:
+ printf("Challenge text\n");
+ break;
+ case DOT11_MNG_PWR_CONSTRAINT_ID:
+ printf("Power Constraint\n");
+ break;
+ case DOT11_MNG_PWR_CAP_ID:
+ printf("Power Capability\n");
+ break;
+ case DOT11_MNG_TPC_REQUEST_ID:
+ printf("Transmit Power Control (TPC) Request\n");
+ break;
+ case DOT11_MNG_TPC_REPORT_ID:
+ printf("Transmit Power Control (TPC) Report\n");
+ break;
+ case DOT11_MNG_SUPP_CHANNELS_ID:
+ printf("Supported Channels\n");
+ break;
+ case DOT11_MNG_CHANNEL_SWITCH_ID:
+ printf("Channel Switch Announcement\n");
+ break;
+ case DOT11_MNG_MEASURE_REQUEST_ID:
+ printf("Measurement Request\n");
+ break;
+ case DOT11_MNG_MEASURE_REPORT_ID:
+ printf("Measurement Report\n");
+ break;
+ case DOT11_MNG_QUIET_ID:
+ printf("Quiet\n");
+ break;
+ case DOT11_MNG_IBSS_DFS_ID:
+ printf("IBSS DFS\n");
+ break;
+ case DOT11_MNG_ERP_ID:
+ printf("ERP Information\n");
+ break;
+ case DOT11_MNG_TS_DELAY_ID:
+ printf("TS Delay\n");
+ break;
+ case DOT11_MNG_HT_CAP:
+ printf("HT Capabilities\n");
+ break;
+ case DOT11_MNG_QOS_CAP_ID:
+ printf("QoS Capability\n");
+ break;
+ case DOT11_MNG_NONERP_ID:
+ printf("NON-ERP\n");
+ break;
+ case DOT11_MNG_RSN_ID:
+ printf("RSN\n");
+ break;
+ case DOT11_MNG_EXT_RATES_ID:
+ printf("Extended Supported Rates\n");
+ break;
+ case DOT11_MNG_AP_CHREP_ID:
+ printf("AP Channel Report\n");
+ break;
+ case DOT11_MNG_NEIGHBOR_REP_ID:
+ printf("Neighbor Report\n");
+ break;
+ case DOT11_MNG_MDIE_ID:
+ printf("Mobility Domain\n");
+ break;
+ case DOT11_MNG_FTIE_ID:
+ printf("Fast BSS Transition\n");
+ break;
+ case DOT11_MNG_FT_TI_ID:
+ printf("802.11R Timeout Interval\n");
+ break;
+ case DOT11_MNG_REGCLASS_ID:
+ printf("Regulatory Class\n");
+ break;
+ case DOT11_MNG_EXT_CSA_ID:
+ printf("Extended CSA\n");
+ break;
+ case DOT11_MNG_HT_ADD:
+ printf("HT Information\n");
+ break;
+ case DOT11_MNG_EXT_CHANNEL_OFFSET:
+ printf("Ext Channel\n");
+ break;
+#ifdef BCMWAPI_WAI
+ case DOT11_MNG_WAPI_ID:
+ printf("WAPI\n");
+ break;
+#endif
+ case DOT11_MNG_RRM_CAP_ID:
+ printf("Radio Measurement\n");
+ break;
+ case DOT11_MNG_HT_BSS_COEXINFO_ID:
+ printf("OBSS Coexistence INFO\n");
+ break;
+ case DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID:
+ printf("OBSS Intolerant Channel List\n");
+ break;
+ case DOT11_MNG_HT_OBSS_ID:
+ printf("OBSS HT Info\n");
+ break;
+#ifdef DOT11_MNG_CHANNEL_USAGE
+ case DOT11_MNG_CHANNEL_USAGE:
+ printf("Channel Usage\n");
+ break;
+#endif
+ case DOT11_MNG_LINK_IDENTIFIER_ID:
+ printf("TDLS Link Identifier\n");
+ break;
+ case DOT11_MNG_WAKEUP_SCHEDULE_ID:
+ printf("TDLS Wakeup Schedule\n");
+ break;
+ case DOT11_MNG_CHANNEL_SWITCH_TIMING_ID:
+ printf("TDLS Channel Switch Timing\n");
+ break;
+ case DOT11_MNG_PTI_CONTROL_ID:
+ printf("TDLS PTI Control\n");
+ break;
+ case DOT11_MNG_PU_BUFFER_STATUS_ID:
+ printf("TDLS PU Buffer Status\n");
+ break;
+ case DOT11_MNG_EXT_CAP_ID:
+ printf("Management Ext Capability\n");
+ break;
+ case DOT11_MNG_PROPR_ID:
+ printf("Proprietary\n");
+ break;
+ default:
+ if (tag_len <= len) {
+ printf("Unsupported tag\n");
+ } else {
+ /* Just dump the remaining data */
+ printf("Unsupported tag error/malformed\n");
+ tag_len = len;
+ }
+ break;
+ } /* switch */
+
+ wl_hexdump(data, tag_len);
+
+ data += tag_len;
+ len -= tag_len;
+ } /* while */
+}
+
+static void dump_management_info(uint8 *data, int len)
+{
+ struct dot11_management_header hdr;
+ struct dot11_bcn_prb parms;
+
+ if (len <= (int) (sizeof(hdr)+sizeof(parms))) {
+ /* Management packet invalid */
+ return;
+ }
+
+ memcpy(&hdr, data, sizeof(hdr));
+ data += sizeof(hdr);
+ len -= sizeof(hdr);
+
+ memcpy(&parms, data, sizeof(parms));
+ data += sizeof(parms);
+ len -= sizeof(parms);
+
+ /* 802.11 MAC header */
+ printf("Frame Ctl: 0x%04x\n", ltoh16(hdr.fc));
+ printf("Duration : 0x%04x\n", ltoh16(hdr.durid));
+ printf("Dest addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ hdr.da.octet[0],
+ hdr.da.octet[1],
+ hdr.da.octet[2],
+ hdr.da.octet[3],
+ hdr.da.octet[4],
+ hdr.da.octet[5]);
+ printf("Src addr : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ hdr.sa.octet[0],
+ hdr.sa.octet[1],
+ hdr.sa.octet[2],
+ hdr.sa.octet[3],
+ hdr.sa.octet[4],
+ hdr.sa.octet[5]);
+ printf("BSSID : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ hdr.bssid.octet[0],
+ hdr.bssid.octet[1],
+ hdr.bssid.octet[2],
+ hdr.bssid.octet[3],
+ hdr.bssid.octet[4],
+ hdr.bssid.octet[5]);
+ printf("Seq ctl : 0x%04x\n", hdr.seq);
+
+ /* 802.11 management frame */
+ printf("Timestamp: 0x%08x%08x\n",
+ ltoh32(parms.timestamp[0]), ltoh32(parms.timestamp[1]));
+ printf("Beacon Interval: 0x%04x\n", ltoh16(parms.beacon_interval));
+ printf("Capabilities: 0x%04x\n", ltoh32(parms.capability));
+
+ dump_management_fields(data, len);
+}
+
+static int
+wl_management_info(void *wl, cmd_t *cmd, char**argv)
+{
+ int ret = 0;
+ int len;
+ uint8 *data;
+ FILE *fp = NULL;
+ char *fname = NULL;
+ int raw = 0;
+
+ /* Skip the command name */
+ argv++;
+
+ while (*argv) {
+ char *s = *argv;
+
+ if (!strcmp(s, "-f") && argv[1] != NULL) {
+ /* Write packet to a file */
+ fname = argv[1];
+ argv += 2;
+ } else if (!strcmp(s, "-r")) {
+ /* Do a hex dump to console */
+ raw = 1;
+ argv++;
+ } else
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Get the beacon information */
+ strcpy(buf, cmd->name);
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+
+ /*
+ * Dump out the beacon data. The first word (4 bytes) is the
+ * length of the management packet followed by the data itself.
+ */
+ len = dtoh32(*(int *)buf);
+
+ if (len <= 0) {
+ /* Nothing to do */
+ return ret;
+ }
+
+ data = (uint8 *) (buf + sizeof(int));
+ printf("Data: %p Len: %d bytes\n", data, len);
+
+ if (fname != NULL) {
+ /* Write the packet to a file */
+ if ((fp = fopen(fname, "wb")) == NULL) {
+ fprintf(stderr, "Failed to open file %s\n",
+ fname);
+ ret = BCME_BADARG;
+ } else {
+ ret = fwrite(data, 1, len, fp);
+
+ if (ret != len) {
+ fprintf(stderr,
+ "Error write %d bytes to file %s, rc %d!\n",
+ len, fname, ret);
+ ret = -1;
+ }
+ }
+ } else if (raw) {
+ /* Hex dump */
+ wl_hexdump(data, len);
+ } else {
+ /* Print management (w/some decode) */
+ dump_management_info(data, len);
+ }
+
+ if (fp)
+ fclose(fp);
+
+ return ret;
+}
+
+static int
+wl_maclist_1(void *wl, cmd_t *cmd, char **argv)
+{
+ struct maclist *maclist;
+ struct ether_addr *ea;
+ uint i;
+ int ret;
+
+ strcpy(buf, argv[0]);
+
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+
+ maclist = (struct maclist *)buf;
+
+ for (i = 0, ea = maclist->ea; i < dtoh32(maclist->count); i++, ea++)
+ printf("%s %s\n", cmd->name, wl_ether_etoa(ea));
+ return 0;
+}
diff --git a/wl/src/wl/exe/wluc_arpoe.c b/wl/src/wl/exe/wluc_arpoe.c
new file mode 100644
index 0000000..8c4440b
--- /dev/null
+++ b/wl/src/wl/exe/wluc_arpoe.c
@@ -0,0 +1,108 @@
+/*
+ * wl arpoe command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_arpoe.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_arp_stats;
+
+static cmd_t wl_arpoe_cmds[] = {
+ { "arp_ol", wl_offload_cmpnt, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set arp offload components"},
+ { "arp_peerage", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set age of the arp entry in minutes"},
+ { "arp_table_clear", wl_var_void, -1, WLC_SET_VAR,
+ "Clear arp cache"},
+ { "arp_hostip", wl_hostip, WLC_GET_VAR, WLC_SET_VAR,
+ "Add a host-ip address or display them"},
+ { "arp_hostip_clear", wl_var_void, -1, WLC_SET_VAR,
+ "Clear all host-ip addresses"},
+ { "arp_stats", wl_arp_stats, WLC_GET_VAR, -1,
+ "Display ARP offload statistics"},
+ { "arp_stats_clear", wl_var_void, -1, WLC_SET_VAR,
+ "Clear ARP offload statistics"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_arpoe_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register arpoe commands */
+ wl_module_cmds_register(wl_arpoe_cmds);
+}
+
+static int
+wl_arp_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ struct arp_ol_stats_t *arpstats;
+
+ if (!*++argv) {
+ /* Get */
+ void *ptr = NULL;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+ arpstats = (struct arp_ol_stats_t *)ptr;
+ printf("host_ip_entries = %d\n", dtoh32(arpstats->host_ip_entries));
+ printf("host_ip_overflow = %d\n", dtoh32(arpstats->host_ip_overflow));
+ printf("arp_table_entries = %d\n", dtoh32(arpstats->arp_table_entries));
+ printf("arp_table_overflow = %d\n", dtoh32(arpstats->arp_table_overflow));
+ printf("host_request = %d\n", dtoh32(arpstats->host_request));
+ printf("host_reply = %d\n", dtoh32(arpstats->host_reply));
+ printf("host_service = %d\n", dtoh32(arpstats->host_service));
+ printf("peer_request = %d\n", dtoh32(arpstats->peer_request));
+ printf("peer_request_drop = %d\n", dtoh32(arpstats->peer_request_drop));
+ printf("peer_reply = %d\n", dtoh32(arpstats->peer_reply));
+ printf("peer_reply_drop = %d\n", dtoh32(arpstats->peer_reply_drop));
+ printf("peer_service = %d\n", dtoh32(arpstats->peer_service));
+ printf("host_ip_entries = %d\n", dtoh32(arpstats->host_ip_entries));
+ } else
+ printf("Cannot set arp stats, use 'wl arp_stats_clear' to clear the counters\n");
+
+ return 0;
+}
diff --git a/wl/src/wl/exe/wluc_bdo.c b/wl/src/wl/exe/wluc_bdo.c
new file mode 100644
index 0000000..1ae5bd0
--- /dev/null
+++ b/wl/src/wl/exe/wluc_bdo.c
@@ -0,0 +1,351 @@
+/*
+ * wl bdo command module - Bonjour Dongle Offload
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id:$
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+#include <sys/stat.h>
+#include <errno.h>
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_bdo;
+
+static cmd_t wl_bdo_cmds[] = {
+ { "bdo", wl_bdo, WLC_GET_VAR, WLC_SET_VAR,
+ "Bonjour dongle offload subcommands:\n"
+ "\tbdo download <dbase_filename>\n"
+ "\tbdo enable <0|1>\n"
+ "\tbdo max_download"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_bdo_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register bdo commands */
+ wl_module_cmds_register(wl_bdo_cmds);
+}
+
+/* download database from buffer */
+static int
+wl_bdo_download_database(void *wl, uint8 *database, uint16 len)
+{
+ int err = BCME_OK;
+ uint16 total_size = len;
+ uint16 current_size = 0;
+ uint16 frag_num = 0;
+
+ while (current_size < total_size) {
+ uint8 buffer[OFFSETOF(wl_bdo_t, data) + sizeof(wl_bdo_download_t)];
+ wl_bdo_t *bdo = (wl_bdo_t *)buffer;
+ int length;
+ wl_bdo_download_t *bdo_download = (wl_bdo_download_t *)bdo->data;
+
+ /* update size and fragment */
+ bdo_download->total_size = total_size;
+ bdo_download->frag_num = frag_num;
+ bdo_download->frag_size = MIN(total_size - current_size, BDO_MAX_FRAGMENT_SIZE);
+ memcpy(bdo_download->fragment, &database[current_size], bdo_download->frag_size);
+
+ bdo->subcmd_id = WL_BDO_SUBCMD_DOWNLOAD;
+ bdo->len = OFFSETOF(wl_bdo_download_t, fragment) + bdo_download->frag_size;
+
+ /* update before dongle byte order */
+ current_size += bdo_download->frag_size;
+ frag_num++;
+
+ /* dongle byte order */
+ bdo_download->total_size = htod16(bdo_download->total_size);
+ bdo_download->frag_num = htod16(bdo_download->frag_num);
+ bdo_download->frag_size = htod16(bdo_download->frag_size);
+
+ /* invoke iovar */
+ length = OFFSETOF(wl_bdo_t, data) + bdo->len;
+ bdo->subcmd_id = htod16(bdo->subcmd_id);
+ bdo->len = htod16(bdo->len);
+ if (wlu_iovar_setbuf(wl, "bdo", bdo, length, buf, WLC_IOCTL_MAXLEN) != 0) {
+ err = BCME_ERROR;
+ break;
+ }
+ }
+ return err;
+}
+
+/* reads file into buffer and returns bytes read and malloc'ed buffer with file contents */
+static int
+read_file(char *filename, unsigned char **buffer)
+{
+ FILE *fp = NULL;
+ int ifd;
+ struct stat filest;
+ unsigned int filesize = 0;
+ unsigned long status = 0;
+ unsigned char *buf = NULL;
+
+ /* open the file */
+ if (!(fp = fopen(filename, "rb"))) {
+ fprintf(stderr, "unable to open input file %s\n", filename);
+ goto error;
+ }
+
+ /* get fstat */
+ ifd = fileno(fp);
+ if (fstat(ifd, &filest)) {
+ fprintf(stderr, "fstat on input file %s return error %s\n",
+ filename, strerror(errno));
+ goto error;
+ }
+
+ /* get filesize */
+ filesize = filest.st_size;
+ if (filesize == 0) {
+ fprintf(stderr, "input file %s is empty (i.e. zero length)\n", filename);
+ goto error;
+ }
+
+ /* get buffer */
+ if ((buf = malloc(filesize)) == NULL) {
+ fprintf(stderr, "unable to allocate %u bytes based on input file size!\n",
+ filesize);
+ goto error;
+ }
+
+ /* read from file to buffer and check length */
+ status = fread(buf, 1, filesize, fp);
+ if (status != filesize) {
+ fprintf(stderr, "read of input file %s wasn't good based on fstat size %u\n",
+ filename, filesize);
+ goto error;
+ }
+
+ /* return buffer and filesize */
+ *buffer = buf;
+ fclose(fp);
+ return filesize;
+
+error:
+ if (buf) {
+ free(buf);
+ }
+ if (fp) {
+ fclose(fp);
+ }
+ return 0;
+}
+
+/* converts input hex buffer to binary and returns bytes converted and malloc'ed buffer */
+static int
+hex2bin(char *input, int len, unsigned char **buffer)
+{
+ unsigned char *buf = NULL;
+ int num_converted = 0;
+ char *p;
+
+ /* get buffer */
+ if ((buf = malloc(len)) == NULL) {
+ fprintf(stderr, "unable to allocate %u bytes\n", len);
+ return 0;
+ }
+
+ p = input;
+ while (p < input + len) {
+ char hex[3];
+
+ /* ignore unknown leading/trailing characters */
+ if (!isprint(*p)) {
+ p++;
+ continue;
+ }
+
+ hex[0] = *p++;
+ hex[1] = *p++;
+ hex[2] = 0;
+ /* convert hex to binary */
+ buf[num_converted++] = strtoul(hex, NULL, 16);
+ }
+
+ /* return buffer and number converted */
+ *buffer = buf;
+ return num_converted;
+}
+
+/* read database from file and download buffer */
+static int
+wl_bdo_download_file(void *wl, char *filename)
+{
+ int err;
+ int file_len;
+ unsigned char *file_buf;
+ unsigned char *conv_buf = NULL;
+ int dload_len;
+ unsigned char *dload_buf;
+
+ if ((file_len = read_file(filename, &file_buf)) == 0) {
+ return BCME_BADARG;
+ }
+
+ /* conversion to binary is needed if first char is printable */
+ if (isprint(file_buf[0])) {
+ dload_len = hex2bin((char *)file_buf, file_len, &conv_buf);
+ dload_buf = conv_buf;
+ } else {
+ dload_len = file_len;
+ dload_buf = file_buf;
+ }
+
+ err = wl_bdo_download_database(wl, dload_buf, dload_len);
+ if (err) {
+ printf("Failed to download. Error code: %d\n", err);
+ }
+ else {
+ printf("%s: %d bytes\n", filename, dload_len);
+ }
+
+ free(file_buf);
+ if (conv_buf) {
+ free(conv_buf);
+ }
+
+ return err;
+}
+
+static int
+wl_bdo(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1;
+ char *subcmd;
+ int subcmd_len;
+
+ /* skip iovar */
+ argv++;
+
+ /* must have subcommand */
+ subcmd = *argv++;
+ if (!subcmd) {
+ return BCME_USAGE_ERROR;
+ }
+ subcmd_len = strlen(subcmd);
+
+ if (!*argv) {
+ /* get */
+ uint8 buffer[OFFSETOF(wl_bdo_t, data)];
+ wl_bdo_t *bdo = (wl_bdo_t *)buffer;
+ int len = OFFSETOF(wl_bdo_t, data);
+
+ memset(bdo, 0, len);
+ if (!strncmp(subcmd, "enable", subcmd_len)) {
+ bdo->subcmd_id = WL_BDO_SUBCMD_ENABLE;
+ } else if (!strncmp(subcmd, "max_download", subcmd_len)) {
+ bdo->subcmd_id = WL_BDO_SUBCMD_MAX_DOWNLOAD;
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* invoke GET iovar */
+ bdo->subcmd_id = htod16(bdo->subcmd_id);
+ bdo->len = htod16(bdo->len);
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, bdo, len, buf, WLC_IOCTL_SMLEN)) < 0) {
+ return err;
+ }
+
+ /* process and print GET results */
+ bdo = (wl_bdo_t *)buf;
+ bdo->subcmd_id = dtoh16(bdo->subcmd_id);
+ bdo->len = dtoh16(bdo->len);
+
+ switch (bdo->subcmd_id) {
+ case WL_BDO_SUBCMD_ENABLE:
+ {
+ wl_bdo_enable_t *bdo_enable = (wl_bdo_enable_t *)bdo->data;
+ if (bdo->len >= sizeof(*bdo_enable)) {
+ printf("%d\n", bdo_enable->enable);
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ case WL_BDO_SUBCMD_MAX_DOWNLOAD:
+ {
+ wl_bdo_max_download_t *max_download = (wl_bdo_max_download_t *)bdo->data;
+ if (bdo->len >= sizeof(*max_download)) {
+ printf("%d\n", dtoh16(max_download->size));
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ } else if (!strncmp(subcmd, "download", subcmd_len) && argv[0]) {
+ /* download */
+ err = wl_bdo_download_file(wl, argv[0]);
+ }
+ else {
+ /* set */
+ uint8 buffer[OFFSETOF(wl_bdo_t, data) + sizeof(wl_bdo_enable_t)];
+ wl_bdo_t *bdo = (wl_bdo_t *)buffer;
+ int len;
+
+ if (!strncmp(subcmd, "enable", subcmd_len) &&
+ (!strcmp(argv[0], "0") || !strcmp(argv[0], "1"))) {
+ wl_bdo_enable_t *bdo_enable = (wl_bdo_enable_t *)bdo->data;
+ bdo->subcmd_id = WL_BDO_SUBCMD_ENABLE;
+ bdo->len = sizeof(*bdo_enable);
+ bdo_enable->enable = atoi(argv[0]);
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* invoke SET iovar */
+ len = OFFSETOF(wl_bdo_t, data) + bdo->len;
+ bdo->subcmd_id = htod16(bdo->subcmd_id);
+ bdo->len = htod16(bdo->len);
+ err = wlu_iovar_set(wl, cmd->name, bdo, len);
+ }
+
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_bmac.c b/wl/src/wl/exe/wluc_bmac.c
new file mode 100644
index 0000000..df36f28
--- /dev/null
+++ b/wl/src/wl/exe/wluc_bmac.c
@@ -0,0 +1,742 @@
+/*
+ * wl bmac command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_bmac.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+#include <bcmsrom_fmt.h>
+#include <bcmsrom_tbl.h>
+
+/* For backwards compatibility, the absense of the define 'NO_FILESYSTEM_SUPPORT'
+ * implies that a filesystem is supported.
+ */
+#if !defined(BWL_NO_FILESYSTEM_SUPPORT)
+#define BWL_FILESYSTEM_SUPPORT
+#endif
+
+static cmd_func_t wl_gpioout;
+static cmd_func_t wl_nvsource;
+static cmd_func_t wl_var_getinthex;
+static cmd_func_t wl_otpw, wl_otpraw;
+static cmd_func_t wl_devpath;
+static cmd_func_t wl_diag;
+static cmd_func_t wl_var_setintandprintstr;
+static cmd_func_t wl_otpdump_iter;
+static cmd_func_t wlu_srwrite_data;
+
+static cmd_t wl_bmac_cmds[] = {
+ { "srcrc", wlu_srwrite, WLC_GET_SROM, -1,
+ "Get the CRC for input binary file" },
+ { "cis_source", wl_varint, WLC_GET_VAR, -1,
+ "Display which source is used for the SDIO CIS"},
+ { "nvram_source", wl_nvsource, WLC_GET_VAR, -1,
+ "Display which source is used for nvram"},
+ { "customvar1", wl_var_getinthex, -1, -1,
+ "print the value of customvar1 in hex format" },
+ { "gpioout", wl_gpioout, -1, -1,
+ "Set any GPIO pins to any value. Use with caution as GPIOs would be "
+ "assigned to chipcommon\n"
+ "\tUsage: gpiomask gpioval"},
+ { "devpath", wl_devpath, WLC_GET_VAR, -1,
+ "print device path" },
+ { "otpraw", wl_otpraw, WLC_GET_VAR, WLC_SET_VAR,
+ "Read/Write raw data to on-chip otp\n"
+ "Usage: wl otpraw <offset> <bits> [<data>]"},
+ { "otpw", wl_otpw, -1, WLC_OTPW,
+ "Write an srom image to on-chip otp\n"
+ "Usage: wl otpw file"},
+ { "nvotpw", wl_otpw, -1, WLC_NVOTPW,
+ "Write nvram to on-chip otp\n"
+ "Usage: wl nvotpw file"},
+ { "diag", wl_diag, WLC_GET_VAR, -1,
+ "diag testindex(1-interrupt, 2-loopback, 3-memory, 4-led);"
+ " precede by 'wl down' and follow by 'wl up'" },
+ { "otpdump", wl_otpdump_iter, WLC_GET_VAR, -1,
+ "Dump raw otp"},
+ { "otpstat", wl_var_setintandprintstr, WLC_GET_VAR, -1,
+ "Dump OTP status"},
+ { "srwrite_data", wlu_srwrite_data, WLC_GET_SROM, WLC_SET_SROM,
+ "Write caldata to srom: srwrite_data -t type filename\n"
+ "\t Supported types: calblob"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_bmac_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register bmac commands */
+ wl_module_cmds_register(wl_bmac_cmds);
+}
+
+static int
+wl_gpioout(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 mask;
+ uint32 val;
+ char *endptr = NULL;
+ uint argc;
+ uint32 *int_ptr;
+
+ UNUSED_PARAMETER(cmd);
+
+ val = 0;
+
+ /* eat command name */
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* Get and print the values */
+ if (argc == 0) {
+ uint32 gpio_cntrl;
+ uint32 gpio_out;
+ uint32 gpio_outen;
+ int ret;
+
+ if ((ret = wlu_iovar_get(wl, "gpioout", buf, sizeof(uint32) *3)) < 0)
+ return ret;
+ gpio_cntrl = dtoh32(((uint32 *)buf)[0]);
+ gpio_out = dtoh32(((uint32 *)buf)[1]);
+ gpio_outen = dtoh32(((uint32 *)buf)[2]);
+
+ printf("gpiocontrol 0x%x gpioout 0x%x gpioouten 0x%x\n", gpio_cntrl,
+ gpio_out, gpio_outen);
+
+ return 0;
+ }
+
+ /* required arg: mask value */
+ if (argc < 2)
+ return BCME_USAGE_ERROR;
+
+ mask = strtoul(argv[0], &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ val = strtoul(argv[1], &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ if ((~mask & val) != 0)
+ return BCME_BADARG;
+
+ int_ptr = (uint32 *)buf;
+ mask = htod32(mask);
+ memcpy(int_ptr, (const void *)&mask, sizeof(mask));
+ int_ptr++;
+ val = htod32(val);
+ memcpy(int_ptr, (const void *)&val, sizeof(val));
+
+ return wlu_iovar_set(wl, "gpioout", buf, sizeof(uint32) *2);
+}
+
+static int
+wl_nvsource(void *wl, cmd_t *cmd, char **argv)
+{
+ int32 val, err;
+
+ if ((err = wl_var_get(wl, cmd, argv)))
+ return (err);
+
+ val = dtoh32(*(int32*)buf);
+
+ switch (val) {
+ case 0:
+ printf("SROM\n");
+ break;
+ case 1:
+ printf("OTP\n");
+ break;
+ case 2:
+ printf("NVRAM\n");
+ break;
+ default:
+ printf("Unrecognized source %d\n", val);
+ break;
+ }
+
+ return 0;
+}
+
+#include <bcmnvram.h>
+
+static int
+wl_otpraw(void *wl, cmd_t *cmd, char **argv)
+{
+ char var[392];
+ uint32 offset;
+ uint32 bits;
+ uint32 len;
+ bool get = TRUE;
+ void *ptr = NULL;
+ char *endptr;
+ uint32 i;
+
+ if (argv[1]) {
+ offset = htod32(strtoul(argv[1], &endptr, 0));
+ memcpy(var, (char *)&offset, sizeof(offset));
+ len = sizeof(offset);
+ }
+ else
+ return BCME_USAGE_ERROR;
+
+ if (argv[2]) {
+ bits = htod32(strtoul(argv[2], &endptr, 0));
+ if (bits > 3072)
+ {
+ printf("bit size (%d) too long or negative!!\n", bits);
+ return BCME_BADARG;
+ }
+ }
+ else
+ bits = 1;
+
+ memcpy(&var[len], (char *)&bits, sizeof(bits));
+ len += sizeof(bits);
+
+ if (argv[3]) {
+ unsigned char data[768];
+ uint32 patlen;
+ char *inptr = argv[3];
+
+ get = FALSE;
+
+ if (*inptr == '0' && toupper((int)(*(inptr + 1))) == 'X')
+ inptr += 2;
+
+ patlen = strlen(inptr);
+ if (patlen > 768 || (patlen * 4) < bits)
+ {
+ printf("data length (%d) too long or small!!\n", patlen);
+ return BCME_USAGE_ERROR;
+ }
+
+ for (i = 1; i <= patlen; i++)
+ {
+ int n = (int)((unsigned char)*inptr++);
+ if (!isxdigit(n)) {
+ fprintf(stderr, "invalid hex digit %c\n", n);
+ return BCME_USAGE_ERROR;
+ }
+ data[patlen - i] = (unsigned char)(isdigit(n) ? (n - '0')
+ : ((islower(n) ? (toupper(n)) : n) - 'A' + 10));
+ }
+
+ for (i = 0; i < patlen; i += 2)
+ {
+ unsigned char v;
+ v = data[i];
+ if (i + 1 < patlen)
+ v += (data[i+1] * 16);
+ memcpy(&var[len], (char *)&v, sizeof(v));
+ len += sizeof(v);
+ }
+
+ printf("OTP RAM Write:");
+ for (i = 0; i < bits; i += 8)
+ {
+ unsigned char v;
+ v = var[2*sizeof(uint32) + (i/8)];
+
+ if ((i % 64) == 0)
+ printf("\nbit %4d:", offset + i);
+ printf(" 0x%x", v);
+ }
+ printf("\n");
+
+ }
+
+ if (get) {
+ int ret;
+ unsigned char v, *cptr;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr)) < 0) {
+ printf("Error reading from OTP data\n");
+ return ret;
+ }
+
+ cptr = (unsigned char *)ptr;
+
+ printf("OTP RAM Read:");
+ for (i = 0; i < bits; i += 8)
+ {
+ v = *cptr++;
+
+ if ((i % 64) == 0)
+ printf("\nbit %4d:", offset + i);
+ printf(" 0x%02x", v);
+ }
+ printf("\n");
+ return 0;
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
+}
+
+static int
+wl_otpw(void *wl, cmd_t *cmd, char **argv)
+{
+#if !defined(BWL_FILESYSTEM_SUPPORT)
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
+ return (-1);
+#elif defined(DONGLEBUILD)
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
+ return 0;
+#else
+ FILE *fp;
+ int ret = 0;
+ struct nvram_header *nvr;
+ char *p, otpw_buf[1024 - 128];
+ const char *msg;
+ int len;
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ if (!(fp = fopen(*argv, "rb"))) {
+ fprintf(stderr, "%s: No such file or directory\n", *argv);
+ return BCME_BADARG;
+ }
+
+ len = fread(otpw_buf, 1, sizeof(otpw_buf) - 1, fp);
+ if ((ret = ferror(fp))) {
+ printf("\nerror %d reading %s\n", ret, *argv);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ if (!feof(fp)) {
+ printf("\nFile %s too large\n", *argv);
+ ret = BCME_ERROR;
+ goto out;
+ }
+
+ /* Got the bits, do they look like the output of nvserial? */
+ nvr = (struct nvram_header *)otpw_buf;
+ if (nvr->magic == NVRAM_MAGIC) {
+ if (cmd->set == WLC_OTPW) {
+ printf("File %s looks like an nvserial file, use nvotpw\n", *argv);
+ fflush(stdout);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ len = nvr->len - sizeof(struct nvram_header);
+ if (len <= 0) {
+ printf("Invalid length (%d)\n", len);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ if (len & 1) {
+ otpw_buf[len++] = '\0';
+ }
+ p = (char *)(nvr + 1);
+ msg = "nvserial";
+ } else {
+ if (cmd->set == WLC_NVOTPW) {
+ printf("File %s is not an nvserial file\n", *argv);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ if (len & 1) {
+ printf("File %s has an odd length (%d)\n", *argv, len);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ p = otpw_buf;
+ msg = "raw";
+ }
+
+ printf("Writing %d bytes from %s file %s to otp ...\n", len, msg, *argv);
+ fflush(stdout);
+
+ if ((ret = wlu_set(wl, cmd->set, p, len)) < 0) {
+ printf("\nError %d writing %s to otp\n", ret, *argv);
+ }
+
+out:
+ fclose(fp);
+ return ret;
+#endif /* BWL_FILESYSTEM_SUPPORT */
+}
+
+int wlu_srwrite_data(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, len, nw;
+ uint16 *words = (uint16 *)&buf[8];
+ uint16 caldata_offset;
+ FILE *fp = NULL;
+ srom_rw_t *srt = (srom_rw_t *)buf;
+ char *arg;
+ char *cal_buf;
+ int argc;
+
+ for (argc = 0; argv[argc]; argc++);
+
+ if (argc != 4)
+ return BCME_USAGE_ERROR;
+
+ /* We need at least one arg */
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ arg = *argv++;
+ if (!strcmp(arg, "-t") && !strcmp(*argv++, "calblob")) {
+ arg = *argv++;
+ /*
+ * Avoid wl utility to driver compatibility issues by reading a 'safe' amount of words from
+ * SPROM to determine the SPROM version that the driver supports, once the version is known
+ * the full SPROM contents can be read. At the moment sromrev12 is the largest.
+ */
+ nw = MAX(MAX(SROM10_SIGN, SROM11_SIGN), SROM11_SIGN) + 1;
+ srt->byteoff = htod32(0);
+ srt->nbytes = htod32(2 * nw);
+
+ if (cmd->get < 0)
+ return BCME_ERROR;
+
+ if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+ caldata_offset = words[SROM15_CAL_OFFSET_LOC] & 0xff;
+ if (words[SROM11_SIGN] == SROM15_SIGNATURE) {
+ nw = SROM15_WORDS;
+ } else if (words[SROM16_SIGN] == SROM16_SIGNATURE) {
+ nw = SROM16_WORDS;
+ caldata_offset = SROM16_CAL_DATA_OFFSET;
+ printf("Srom16, byte offset: %d\n", caldata_offset);
+ } else {
+ printf("Unsupported for SROM revs other than rev15\n");
+ return BCME_ERROR;
+ }
+
+
+ /* Reading caldata from msf file */
+ if (!(fp = fopen(arg, "rb"))) {
+ fprintf(stderr, "%s: No such file or directory\n", arg);
+ return BCME_BADARG;
+ }
+
+ cal_buf = malloc(SROM_MAX);
+ if (cal_buf == NULL) {
+ ret = BCME_NOMEM;
+ goto out;
+ }
+ len = fread(cal_buf, 1, SROM_MAX + 1, fp);
+ len = (len + 1) & ~1;
+ if (len > SROM15_MAX_CAL_SIZE) {
+ ret = BCME_BUFTOOLONG;
+ goto out;
+ }
+
+ if ((ret = ferror(fp))) {
+ printf("\nerror %d reading %s\n", ret, arg);
+ ret = BCME_ERROR;
+ goto out;
+ }
+
+ if (!feof(fp)) {
+ printf("\nFile %s is too large\n", arg);
+ ret = BCME_ERROR;
+ goto out;
+ }
+ if ((len - MAX_IOCTL_TXCHUNK_SIZE) > 0) {
+ memcpy(srt->buf, cal_buf, MAX_IOCTL_TXCHUNK_SIZE);
+ srt->byteoff = htod32(caldata_offset);
+ srt->nbytes = htod32(MAX_IOCTL_TXCHUNK_SIZE);
+ ret = wlu_set(wl, cmd->set, buf, MAX_IOCTL_TXCHUNK_SIZE + 8);
+ memcpy(srt->buf, cal_buf + MAX_IOCTL_TXCHUNK_SIZE,
+ len - MAX_IOCTL_TXCHUNK_SIZE);
+ srt->byteoff = htod32(caldata_offset + MAX_IOCTL_TXCHUNK_SIZE);
+ srt->nbytes = htod32(len - MAX_IOCTL_TXCHUNK_SIZE);
+ ret = wlu_set(wl, cmd->set, buf, len - MAX_IOCTL_TXCHUNK_SIZE + 8);
+ }
+ else {
+ memcpy(srt->buf, cal_buf, len);
+ srt->byteoff = htod32(caldata_offset);
+ srt->nbytes = htod32(len);
+ ret = wlu_set(wl, cmd->set, buf, len + 8);
+ }
+ }
+ else {
+ printf("Invalid arguments for srwrite_data\n");
+ return BCME_BADARG;
+ }
+out:
+ fflush(stdout);
+ if (fp)
+ fclose(fp);
+ free(cal_buf);
+ return ret;
+}
+
+
+
+/*
+ * wlu_reg3args is a generic function that is used for setting/getting
+ * WL_IOVAR variables that require address + offset for read, and
+ * address + offset + data for write.
+ */
+int
+wlu_reg3args(void *wl, cmd_t *cmd, char **argv)
+{
+ char var[256];
+ uint32 int_val;
+ bool get = TRUE;
+ uint32 len, i;
+ void *ptr = NULL;
+ char *endptr;
+ uint numargs;
+ int ret = 0;
+
+ len = 0;
+
+ if (!argv[1] || !argv[2]) {
+ printf("Wrong syntax => dev offset [val]\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (argv[3]) {
+ numargs = 3;
+ get = FALSE;
+ } else
+ numargs = 2;
+
+ for (i = 1; i <= numargs; i++) {
+ int_val = htod32(strtoul(argv[i], &endptr, 0));
+ memcpy(&var[len], (char *)&int_val, sizeof(int_val));
+ len += sizeof(int_val);
+ }
+
+ if (get) {
+ if ((ret = wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr)) < 0)
+ return ret;
+
+ printf("0x%x\n", dtoh32(*(int *)ptr));
+ }
+ else
+ ret = wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
+ return ret;
+}
+
+
+static int
+wl_var_getinthex(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int32 val;
+
+ if ((err = wl_var_get(wl, cmd, argv)))
+ return (err);
+
+ val = dtoh32(*(int32*)buf);
+
+ printf("0x%08x\n", val);
+
+ return 0;
+}
+
+/* Variation: Like getandprint, but allow an int arg to be passed */
+static int
+wl_var_setintandprintstr(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int32 val;
+ char *varname;
+ char *endptr = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!*argv) {
+ printf("set: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ varname = *argv++;
+
+ if (!*argv) {
+ val = 0;
+ } else {
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n",
+ *argv, varname);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ val = htod32(val);
+ err = wlu_iovar_getbuf(wl, varname, &val, sizeof(int), buf, WLC_IOCTL_MAXLEN);
+
+ if (err)
+ return (err);
+
+ printf("%s\n", buf);
+ return (0);
+}
+
+#if WL_OTPREAD_VER != 1
+#error "Update this code to handle the new version of wl_otpread_cmd_t !"
+#endif
+
+static int
+wl_otpdump_iter(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int otpsize, readsize, offset = 0;
+ uint i;
+ uint16 *outbuf = (uint16 *)buf;
+ wl_otpread_cmd_t read_cmd;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!*argv) {
+ printf("set: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((ret = wlu_iovar_getint(wl, "otpsize", &otpsize)) < 0) {
+ return wl_var_setintandprintstr(wl, cmd, argv);
+ }
+
+ readsize = otpsize = dtoh32(otpsize);
+ printf("otpsize: %d\n", otpsize);
+
+ read_cmd.version = WL_OTPREAD_VER;
+ read_cmd.cmd_len = sizeof(read_cmd);
+ read_cmd.rdmode = 0;
+
+ while (readsize) {
+ read_cmd.rdsize = (readsize <= WLC_IOCTL_MAXLEN) ? readsize : WLC_IOCTL_MAXLEN;
+ read_cmd.rdoffset = offset;
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+
+ ret = wlu_iovar_getbuf(wl, "otpread", &read_cmd, sizeof(read_cmd),
+ buf, WLC_IOCTL_MAXLEN);
+
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < (read_cmd.rdsize / 2); i++) {
+ if ((i % 4) == 0) {
+ printf("\n0x%04x:", 2 * i + offset);
+ }
+ printf(" 0x%04x", outbuf[i]);
+ }
+
+ readsize -= read_cmd.rdsize;
+ offset += read_cmd.rdsize;
+ }
+ printf("\n\n");
+
+ return (0);
+}
+
+void
+wl_printlasterror(void *wl)
+{
+ char error_str[128];
+
+ if (wlu_iovar_get(wl, "bcmerrorstr", error_str, sizeof(error_str)) != 0) {
+ fprintf(stderr, "%s: \nError getting the last error\n", wlu_av0);
+ } else {
+ fprintf(stderr, "%s: %s\n", wlu_av0, error_str);
+ }
+}
+
+static int
+wl_devpath(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ void *ptr;
+ char *pbuf = buf;
+
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_var_getbuf_sm (wl, cmd->name, NULL, 0, &ptr)))
+ return (err);
+
+ pbuf += strlen(buf);
+ sprintf(pbuf, "\n");
+ fputs(buf, stdout);
+ return (0);
+}
+
+static int
+wl_diag(void *wl, cmd_t *cmd, char **argv)
+{
+ uint testindex;
+ int buflen, err;
+ char *param;
+ uint32 testresult;
+
+ if (!*++argv) {
+ printf(" Usage: %s testindex[1-4]\n", cmd->name);
+ return BCME_USAGE_ERROR;
+ }
+
+ testindex = atoi(*argv);
+
+ strcpy(buf, "diag");
+ buflen = strlen(buf) + 1;
+ param = (char *)(buf + buflen);
+ testindex = htod32(testindex);
+ memcpy(param, (char*)&testindex, sizeof(testindex));
+
+ if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return err;
+
+ testresult = *(uint32 *)buf;
+ testindex = dtoh32(testindex);
+ testresult = dtoh32(testresult);
+ if (testresult != 0) {
+ printf("\ndiag test %d failed(error code %d)\n", testindex, testresult);
+ } else
+ printf("\ndiag test %d passed\n", testindex);
+
+ return (0);
+}
diff --git a/wl/src/wl/exe/wluc_bssload.c b/wl/src/wl/exe/wluc_bssload.c
new file mode 100644
index 0000000..35396d7
--- /dev/null
+++ b/wl/src/wl/exe/wluc_bssload.c
@@ -0,0 +1,270 @@
+/*
+ * wl bssload command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_bssload.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifdef LINUX
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* LINUX */
+
+static int wl_bssload_static(void *wl, cmd_t *cmd, char **argv);
+#if defined(WLBSSLOAD_REPORT)
+static int wl_bssload_report(void *wl, cmd_t *cmd, char **argv);
+static int wl_bssload_report_event(void *wl, cmd_t *cmd, char **argv);
+#if defined(linux)
+static cmd_func_t wl_bssload_event_check;
+#endif /* linux */
+#endif /* WLBSSLOAD_REPORT */
+
+static cmd_t wl_bssload_cmds[] = {
+ { "bssload_static", wl_bssload_static, WLC_GET_VAR, WLC_SET_VAR,
+ "get or set static BSS load\n"
+ "\tusage: wl bssload_static [off | <sta_count> <chan_util> <acc>]"},
+#if defined(WLBSSLOAD_REPORT)
+ { "bssload_report", wl_bssload_report, WLC_GET_VAR, -1,
+ "Get the latest BSS Load IE data from the associated AP's beacon\n"
+ "\tUsage: bssload_report"
+ },
+ { "bssload_report_event", wl_bssload_report_event, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set BSS load threshold for sending WLC_E_BSS_LOAD event\n"
+ "\tUsage: wl bssload_report_event [rate_limit_msec] [level] [level] ...\n"
+ "\t\t[level] is a 0...255 channel utilization value.\n"
+ "\t\tUp to 8 levels in increasing order may be specified."
+ },
+#if defined(linux)
+ { "bssload_event_check", wl_bssload_event_check, -1, -1,
+ "Listens forever for BSS Load events and prints them.\n"
+ "\tUsage: wl bssload_event_check"
+ },
+#endif /* linux */
+#endif /* WLBSSLOAD_REPORT */
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_bssload_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register bssload commands */
+ wl_module_cmds_register(wl_bssload_cmds);
+}
+
+static int
+wl_bssload_static(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1;
+ wl_bssload_static_t bssload;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* get */
+ if (!argv[1]) {
+ if ((err = wlu_iovar_get(wl, cmd->name, &bssload, sizeof(bssload))) < 0)
+ return err;
+ if (bssload.is_static) {
+ printf("station count: %d\n", dtoh16(bssload.sta_count));
+ printf("channel utilization: %d\n", bssload.chan_util);
+ printf("avail admission capacity: %d\n", dtoh16(bssload.aac));
+ }
+ }
+ else {
+ /* set */
+ argv++;
+ memset(&bssload, 0, sizeof(bssload));
+ if (!stricmp(*argv, "off")) {
+ bssload.is_static = FALSE;
+ }
+ else {
+ bssload.sta_count = htod16(strtoul(*argv, NULL, 0));
+
+ if (*++argv == NULL) {
+ printf("wl_bssload_static: "
+ "channel utilization not provided\n");
+ return -1;
+ }
+ bssload.chan_util = strtoul(*argv, NULL, 0);
+
+ if (*++argv == NULL) {
+ printf("wl_bssload_static: "
+ "avail admission capacity not provided\n");
+ return -1;
+ }
+ bssload.aac = htod16(strtoul(*argv, NULL, 0));
+
+ bssload.is_static = TRUE;
+ }
+
+ err = wlu_iovar_set(wl, cmd->name, &bssload, sizeof(bssload));
+ }
+
+ return err;
+}
+
+#if defined(WLBSSLOAD_REPORT)
+static int
+wl_bssload_report(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ wl_bssload_t *bssload = NULL;
+
+ /* If any arguments are given, print help */
+ if (ARGCNT(argv) > 1)
+ goto usage;
+
+ /* Get and print the current BSS Load values */
+ if ((ret = wlu_var_getbuf_sm(wl, cmd->name, NULL, 0, (void*)&bssload)))
+ return ret;
+ if (bssload == NULL)
+ return BCME_ERROR;
+ printf("BSS Load from associated AP beacon:\n");
+ printf("station count : %u\n", dtoh16(bssload->sta_count));
+ printf("channel utilization : %u\n", bssload->chan_util);
+ printf("available admission capacity: %u\n", dtoh16(bssload->aac));
+ return 0;
+
+usage:
+ return -1;
+}
+
+static int
+wl_bssload_report_event(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ wl_bssload_cfg_t blcfg;
+
+ (void) wl;
+ if (!*++argv) {
+ /* get */
+ void *ptr = NULL;
+ uint i;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ memcpy(&blcfg, ptr, sizeof(blcfg));
+ blcfg.rate_limit_msec = dtoh32(blcfg.rate_limit_msec);
+
+ printf("rate_limit_msec: %d\n", blcfg.rate_limit_msec);
+ printf("%d channel utilization levels:", blcfg.num_util_levels);
+ for (i = 0; i < blcfg.num_util_levels; i++) {
+ printf(" %d", blcfg.util_levels[i]);
+ }
+ printf("\n");
+ } else {
+ /* set */
+ memset(&blcfg, 0, sizeof(wl_bssload_cfg_t));
+ blcfg.rate_limit_msec = atoi(*argv);
+
+ while (*++argv && blcfg.num_util_levels < MAX_BSSLOAD_LEVELS) {
+ blcfg.util_levels[blcfg.num_util_levels++] = atoi(*argv);
+ if (blcfg.num_util_levels > 1 &&
+ blcfg.util_levels[blcfg.num_util_levels - 1] <=
+ blcfg.util_levels[blcfg.num_util_levels - 2]) {
+ printf("Channel utilization level %u was <= level %u.\n",
+ blcfg.util_levels[blcfg.num_util_levels - 1],
+ blcfg.util_levels[blcfg.num_util_levels - 2]);
+ goto usage;
+ }
+ }
+
+ if (*argv) {
+ printf("Too many parameters.\n");
+ goto usage;
+ }
+
+ blcfg.rate_limit_msec = htod32(blcfg.rate_limit_msec);
+ ret = wlu_var_setbuf(wl, cmd->name, &blcfg, sizeof(blcfg));
+ }
+ return ret;
+
+usage:
+ return -1;
+}
+
+#if defined(linux)
+static void
+wl_bssload_event_cb(int event_type, bcm_event_t *bcm_event)
+{
+ struct timeval tv;
+ uint32 sec, msec;
+ int ret;
+ wl_bssload_t *data = (wl_bssload_t *) (bcm_event + 1);
+
+ if (event_type == WLC_E_BSS_LOAD) {
+ /* Print a timestamp */
+ ret = gettimeofday(&tv, NULL);
+ if (ret == 0) {
+ sec = (uint32) (tv.tv_sec % 10000);
+ msec = (uint32) tv.tv_usec / 1000;
+ printf("%04d.%03d\n", sec, msec);
+ }
+
+ printf("WLC_E_BSS_LOAD: chan_util = %u\n", data->chan_util);
+ printf(" sta_count = %u\n", dtoh16(data->sta_count));
+ printf(" aac = %u\n", dtoh16(data->aac));
+ }
+}
+
+static int
+wl_bssload_event_check(void *wl, cmd_t *cmd, char **argv)
+{
+ if (argv[1] && argv[1][0] == '-') {
+ wl_cmd_usage(stderr, cmd);
+ return -1;
+ }
+ return wl_wait_for_event(wl, argv, WLC_E_BSS_LOAD, 2048, wl_bssload_event_cb);
+}
+#endif /* linux */
+#endif /* WLBSSLOAD_REPORT */
diff --git a/wl/src/wl/exe/wluc_btcdyn.c b/wl/src/wl/exe/wluc_btcdyn.c
new file mode 100644
index 0000000..1b82e03
--- /dev/null
+++ b/wl/src/wl/exe/wluc_btcdyn.c
@@ -0,0 +1,509 @@
+
+/*
+ * wl dynamic btcoex command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_btcdyn.c $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifdef WIN32
+#define bzero(b, len) memset((b), 0, (len))
+#endif
+
+#ifdef LINUX
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* LINUX */
+
+#include <miniopt.h>
+
+static cmd_func_t wl_btcoex_dynctl;
+static cmd_func_t wl_btcoex_dynctl_status;
+static cmd_func_t wl_btcoex_dynctl_sim;
+
+#define WL_BTCDYNCTL_USAGE \
+"Usage:\n" \
+"\t [-d dflt_dsns_level] [-l low_dsns_level] [-m mid_dsns_level] [-h high_dsns_level]\n" \
+"\t [-c default_btc_mode\n" \
+"\t [-s mode_switching_btrssi_hysteresis in dBm\n\n" \
+"\t [-f dynctl_flags] : bit0: Dynctl on/off, bit1-desense on/off," \
+" bit2-m_switch on/off, bit7-dryrun on/off\n" \
+"\t [-j row_idx:btcmode,bt_pwr,wl_rssi_high,wl_rssi_low] : set one row in mode table\n" \
+"\t [-k row_idx:btcmode,bt_pwr,wl_rssi_high,wl_rssi_low] : set one row in desense table\n" \
+"\t [-n number of active rows in mode switching table\n" \
+"\t [-o number of active rows in desense switching table\n\n"
+
+#define WL_BTCDYNCTL_STATUS_USAGE \
+"Usage: command doeesn't take any arguments]\n"
+
+#define WL_BTCDYNCTL_SIM_USAGE \
+"Usage: wl btc_dynctl_sim [1|0] [-b bt_sim_pwr] [-r bt_sim_rssi] [-w wl_sim_rssi] \n" \
+
+/* bycdyn wl commands */
+static cmd_t wl_btcdyn_cmds[] = {
+ { "btc_dynctl", wl_btcoex_dynctl, WLC_GET_VAR, WLC_SET_VAR, WL_BTCDYNCTL_USAGE},
+ { "btc_dynctl_status", wl_btcoex_dynctl_status, WLC_GET_VAR, -1, WL_BTCDYNCTL_STATUS_USAGE},
+ { "btc_dynctl_sim", wl_btcoex_dynctl_sim, WLC_GET_VAR, WLC_SET_VAR, WL_BTCDYNCTL_SIM_USAGE},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_btcdyn_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register btcdyn commands */
+ wl_module_cmds_register(wl_btcdyn_cmds);
+}
+
+
+static int fill_thd_row(btc_thr_data_t *thd, char *str)
+{
+ char delim[] = ":,\0";
+ int err = BCME_OK;
+ int idx = atoi(strtok(str, delim));
+ char *s_mode, *s_bt_pwr, *s_bt_rssi, *s_wl_rssi_high, *s_wl_rssi_low;
+
+ if (idx >= DCTL_TROWS_MAX) {
+ fprintf(stderr, " invalid index:%d the data:%s\n", idx, str);
+ err = BCME_BADARG;
+ return err;
+ }
+
+ s_mode = strtok(NULL, delim);
+ s_bt_pwr = strtok(NULL, delim);
+ s_bt_rssi = strtok(NULL, delim);
+ s_wl_rssi_high = strtok(NULL, delim);
+ s_wl_rssi_low = strtok(NULL, delim);
+ if (!s_mode || !s_bt_pwr || !s_bt_rssi || !s_wl_rssi_high ||
+ !s_wl_rssi_low) {
+ fprintf(stderr, " invalid row data format or number of parameters\n");
+ err = BCME_BADARG;
+ return err;
+ }
+ /* all present, convert them to int */
+ thd[idx].mode = atoi(s_mode);
+ thd[idx].bt_pwr = atoi(s_bt_pwr);
+ thd[idx].bt_rssi = atoi(s_bt_rssi);
+ thd[idx].wl_rssi_high = atoi(s_wl_rssi_high);
+ thd[idx].wl_rssi_low = atoi(s_wl_rssi_low);
+
+ printf("written table entry:%d: mode:%d, bt_pwr:%d, bt_rssi:%d,"
+ " wl_rssi_high:%d, wl_rssi_low:%d\n",
+ idx, thd[idx].mode, thd[idx].bt_pwr, thd[idx].bt_rssi,
+ thd[idx].wl_rssi_high, thd[idx].wl_rssi_low);
+ return err;
+}
+
+/*
+* get/set dynamic BTCOEX profile (desense, modesw etc)
+*/
+static int
+wl_btcoex_dynctl(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0, opt_err;
+ miniopt_t to;
+ void *ptr;
+ dctl_prof_t *profile = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* get current profile */
+ if ((err = wlu_var_getbuf(wl,
+ "btc_dynctl", NULL, 0, &ptr) < 0)) {
+ fprintf(stderr, "btc_dynctl: getbuf ioctl failed\n");
+ return err;
+ }
+
+ if (*++argv) {
+ /* some arguments are present, do set or help */
+
+ if (argv[0][0] == 'h' ||
+ argv[0][0] == '?') {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ profile = calloc(1, sizeof(dctl_prof_t) + sizeof(dynctl_status_t));
+ if (profile == NULL)
+ return BCME_NOMEM;
+
+ /* copy current profile values into buf allocated for set ioctl */
+ bcopy(ptr, profile, sizeof(dctl_prof_t));
+
+ miniopt_init(&to, __FUNCTION__, NULL, FALSE);
+
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 'c') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " default_btc_mode\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ profile->default_btc_mode = to.val;
+ }
+
+ if (to.opt == 'd') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " dflt_dsns_level\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ profile->dflt_dsns_level = to.val;
+ }
+
+ if (to.opt == 'l') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " low_dsns_level\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ profile->low_dsns_level = to.val;
+ }
+ if (to.opt == 'm') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " mid_dsns_level\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ profile->mid_dsns_level = to.val;
+ }
+ if (to.opt == 'h') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " high_dsns_level\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ profile->high_dsns_level = to.val;
+ }
+
+ if (to.opt == 'f') {
+ /* set dynctl flags */
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " flags \n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ profile->flags = to.val;
+ }
+
+ /* modify mode switching table */
+ if (to.opt == 'j') {
+ if (fill_thd_row(profile->msw_data, to.valstr) != BCME_OK)
+ goto exit;
+ }
+
+ /* modify desense level table */
+ if (to.opt == 'k') {
+ if (fill_thd_row(profile->dsns_data, to.valstr) != BCME_OK)
+ goto exit;
+ }
+
+ /* set number of active rows in msw table */
+ if (to.opt == 'n') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " msw_rows\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ /* check for array bounds */
+ if (to.val > DCTL_TROWS_MAX) {
+ fprintf(stderr, "array index:%d >= MAX:%d !\n",
+ to.val, DCTL_TROWS_MAX);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ profile->msw_rows = to.val;
+ }
+ /* set number of active rows in desense table */
+ if (to.opt == 'o') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " dsns_rows\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ /* check for array bounds */
+ if (to.val > DCTL_TROWS_MAX) {
+ fprintf(stderr, "array index;%d >= MAX:%d !\n",
+ to.val, DCTL_TROWS_MAX);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ profile->dsns_rows = to.val;
+ }
+ if (to.opt == 's') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " btrssi_hysteresis \n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ profile->msw_btrssi_hyster = to.val;
+ }
+ } /* end of miniopt while loop */
+
+ /* write back modified dctl_prof_t structure */
+ if ((err = wlu_var_setbuf(wl, "btc_dynctl", profile,
+ sizeof(dctl_prof_t)) < 0)) {
+ printf("btc_dynctl: fail to set %d\n", err);
+ }
+
+ } else { /* display current dynctl profile */
+ int i;
+ profile = ptr;
+
+ /* get: just display the current profile values */
+ printf(" === btc dynctl: ===\n");
+ printf("DYNCTL(0x%x): %s, Desense:%s, Mode:%s\n",
+ profile->flags,
+ IS_DYNCTL_ON(profile)?"On":"Off",
+ IS_DESENSE_ON(profile)?"On":"Off",
+ IS_MSWITCH_ON(profile)?"On":"Off");
+ printf("dflt_dsns_level:%d\n", profile->dflt_dsns_level);
+ printf("low_dsns_level:%d\n", profile->low_dsns_level);
+ printf("mid_dsns_level:%d\n", profile->mid_dsns_level);
+ printf("high_dsns_level:%d\n", profile->high_dsns_level);
+ printf("btrssi msw hysteresis %d dBm\n", profile->msw_btrssi_hyster);
+ printf("default_btc_mode:%d\n", profile->default_btc_mode);
+
+ printf("--- coex mode switch data table "
+ "msw_rows:%d ---\n", profile->msw_rows);
+
+ for (i = 0; i < MIN(DCTL_TROWS_MAX, profile->msw_rows); i++) {
+ printf("row:%d: btcmode:%d, bt_pwr:%d, bt_rssi:%d,"
+ " wl_rssi_high:%d, wl_rssi_low:%d\n",
+ i,
+ profile->msw_data[i].mode,
+ profile->msw_data[i].bt_pwr,
+ profile->msw_data[i].bt_rssi,
+ profile->msw_data[i].wl_rssi_high,
+ profile->msw_data[i].wl_rssi_low);
+ }
+ printf("--- wl desense data table "
+ "dsns_rows:%d ---\n", profile->dsns_rows);
+ for (i = 0; i < MIN(DCTL_TROWS_MAX, profile->dsns_rows); i++) {
+ printf("row:%d: btcmode:%d, bt_pwr:%d, bt_rssi:%d,"
+ " wl_rssi_high:%d, wl_rssi_low:%d\n",
+ i,
+ profile->dsns_data[i].mode,
+ profile->dsns_data[i].bt_pwr,
+ profile->dsns_data[i].bt_rssi,
+ profile->dsns_data[i].wl_rssi_high,
+ profile->dsns_data[i].wl_rssi_low);
+ }
+ profile = NULL;
+ }
+
+exit:
+ if (profile)
+ free(profile);
+ return err;
+}
+
+/*
+* get dynamic BTCOEX status
+*/
+static int
+wl_btcoex_dynctl_status(void *wl, cmd_t *cmd, char **argv)
+{
+ dynctl_status_t status;
+ void *ptr;
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv != NULL) {
+ fprintf(stderr, "command doesn't accept any params\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* get current profile */
+ if ((err = wlu_var_getbuf(wl,
+ "btc_dynctl_status", NULL, 0, &ptr) < 0)) {
+ printf("btc_dynctl: getbuf ioctl failed\n");
+ return err;
+ }
+ /* copy the status from ioctl buffer */
+ bcopy(ptr, &status, sizeof(dynctl_status_t));
+
+ printf("--- btc dynctl status ---:\n");
+ printf("simulation mode:%s\n", status.sim_on?"On":"Off");
+ printf("bt_pwr_shm %x\n", dtoh16(status.bt_pwr_shm));
+ printf("bt_pwr:%d dBm\n", status.bt_pwr);
+ printf("bt_rssi:%d dBm\n", status.bt_rssi);
+ printf("wl_rssi:%d dBm\n", status.wl_rssi);
+ printf("dsns_level:%d\n", status.dsns_level);
+ printf("btc_mode:%d\n", status.btc_mode);
+
+ return err;
+}
+
+/*
+* get/set dynamic BTCOEX simulation mode
+*/
+static int
+wl_btcoex_dynctl_sim(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0, opt_err;
+ miniopt_t to;
+ void *ptr;
+ dynctl_sim_t *sim = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* get current profile */
+ if ((err = wlu_var_getbuf(wl,
+ "btc_dynctl_sim", NULL, 0, &ptr) < 0)) {
+ printf("btc_dynctl: getbuf ioctl failed\n");
+ return err;
+ }
+
+ if (*++argv) {
+ /* some arguments are present, do set or help */
+
+ if (argv[0][0] == 'h' ||
+ argv[0][0] == '?') {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ sim = calloc(1, sizeof(dynctl_sim_t));
+ if (sim == NULL)
+ return BCME_NOMEM;
+
+ /* copy current ioctl buf into local var */
+ bcopy(ptr, sim, sizeof(dynctl_sim_t));
+
+ /* 1st parameter is on/off ( 0 | 1) */
+ if (*argv[0] == '1') {
+ /* sim enabled */
+ sim->sim_on = TRUE;
+ }
+ else if (*argv[0] == '0') {
+ /* sim disabled */
+ sim->sim_on = FALSE;
+ }
+
+ ++argv;
+
+ miniopt_init(&to, __FUNCTION__, NULL, FALSE);
+
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+ if (to.opt == 'b') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " sim_btpwr\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ sim->btpwr = to.val;
+ }
+
+ if (to.opt == 'r') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " sim_btrssi\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ sim->btrssi = to.val;
+ }
+
+ if (to.opt == 'w') {
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " sim_wlrssi\n", to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ sim->wlrssi = to.val;
+ }
+ }
+
+ /* write back modified structure */
+ if ((err = wlu_var_setbuf(wl, "btc_dynctl_sim", sim,
+ sizeof(dynctl_sim_t)) < 0)) {
+ printf("%s: failed to set %d\n", cmd->name, err);
+ }
+ } else {
+ /* get */
+ sim = ptr;
+ printf("btc dynctl simulation mode:%s\n BT pwr:%ddBm\n"
+ " BT rssi:%ddBm\n WL ssi:%ddBm\n",
+ sim->sim_on?"On":"Off",
+ sim->btpwr, sim->btrssi, sim->wlrssi);
+ sim = NULL;
+ }
+
+exit:
+ if (sim)
+ free(sim);
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_btcx.c b/wl/src/wl/exe/wluc_btcx.c
new file mode 100644
index 0000000..bb30beb
--- /dev/null
+++ b/wl/src/wl/exe/wluc_btcx.c
@@ -0,0 +1,444 @@
+/*
+ * wl btcx command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_btcx.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <miniopt.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_btc_profile;
+
+#define WL_BTCPROFILE_USAGE \
+"Usage:\n" \
+"\t -p profile_index [-e mode_strong_wl_bt_rssi] [-f mode_weak_wl_rssi]" \
+" [-g mode_weak_bt_rssi] [-h mode_weak_wl_bt_rssi]\n" \
+"\t [-W mode_wl_hi_lo_rssi_thresh] [-w mode_wl_lo_hi_rssi_thresh]" \
+" [-B mode_bt_hi_lo_rssi_thresh] [-b mode_bt_lo_hi_rssi_thresh]\n" \
+"\t [-D desense_wl_hi_lo_rssi_thresh] [-d desense_wl_lo_hi_rssi_thresh]\n" \
+"\t [-A ack_pwr_wl_hi_lo_rssi_thresh] [-a ack_pwr_wl_lo_hi_rssi_thresh]\n" \
+"\t [-T tx_pwr_wl_hi_lo_rssi_thresh] [-t tx_pwr_wl_lo_hi_rssi_thresh]\n" \
+"\t [-l desense_level[0] desense_level[1] desense_level[2]] : desense level per chain\n" \
+"\t [-X ack_pwr_strong_wl[0] ack_pwr_strong_wl[1] ack_pwr_strong_wl[2]] :" \
+" ACK power per chain at strong RSSI\n" \
+"\t [-x ack_pwr_weak_wl[0] ack_pwr_weak_wl[1] ack_pwr_weak_wl[2]] :" \
+" ACK power per chain at weak RSSI\n" \
+"\t [-Y tx_pwr_strong_wl[0] tx_pwr_strong_wl[1] tx_pwr_strong_wl[2]] :" \
+" Tx power per chain at strong RSSI\n" \
+"\t [-y tx_pwr_weak_wl[0] tx_pwr_weak_wl[1] tx_pwr_weak_wl[2]] :" \
+" Tx power per chain at weak RSSI\n\n"
+
+static cmd_t wl_btcx_cmds[] = {
+ { "btc_params", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR, "g/set BT Coex parameters"},
+ { "btc_flags", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR, "g/set BT Coex flags"},
+ { "btc_profile", wl_btc_profile, WLC_GET_VAR, WLC_SET_VAR, WL_BTCPROFILE_USAGE},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_btcx_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register btcx commands */
+ wl_module_cmds_register(wl_btcx_cmds);
+}
+
+static void
+wl_btc_print_profile(wlc_btcx_profile_v1_t *pbtcx_profile)
+{
+ int i;
+ uint8 chain_attr_count = pbtcx_profile->chain_attr_count;
+ /* Basic profile information */
+ printf("Profile Version: %u\n"
+ "Profile Size: %u\n"
+ "Profile Initialized: %s\n"
+ "Number of Tx chains: %u\n"
+ "Profile Index: %u\n"
+ "BTC mode under strong WLAN and BT RSSI: %u\n"
+ "BTC mode under weak WLAN RSSI: %u\n"
+ "BTC mode under weak BT RSSI: %u\n"
+ "BTC mode under weak WLAN and BT RSSI: %u\n",
+ pbtcx_profile->version,
+ pbtcx_profile->length,
+ pbtcx_profile->init ? "Yes" : "No",
+ pbtcx_profile->chain_attr_count,
+ pbtcx_profile->profile_index,
+ pbtcx_profile->mode_strong_wl_bt,
+ pbtcx_profile->mode_weak_wl,
+ pbtcx_profile->mode_weak_bt,
+ pbtcx_profile->mode_weak_wl_bt);
+ /* Threshold information */
+ printf("WLAN strong to weak RSSI threshold for mode change: %d\n"
+ "WLAN weak to strong RSSI threshold for mode change: %d\n"
+ "BT strong to weak RSSI threshold for mode change: %d\n"
+ "BT weak to strong RSSI threshold for mode change: %d\n"
+ "WLAN strong to weak RSSI threshold for desense: %d\n"
+ "WLAN weak to strong RSSI threshold for desense: %d\n"
+ "WLAN strong to weak RSSI threshold for ACK power: %d\n"
+ "WLAN weak to strong RSSI threshold for ACK power: %d\n"
+ "WLAN strong to weak RSSI threshold for Tx power: %d\n"
+ "WLAN weak to strong RSSI threshold for Tx power: %d\n",
+ pbtcx_profile->mode_wl_hi_lo_rssi_thresh,
+ pbtcx_profile->mode_wl_lo_hi_rssi_thresh,
+ pbtcx_profile->mode_bt_hi_lo_rssi_thresh,
+ pbtcx_profile->mode_bt_lo_hi_rssi_thresh,
+ pbtcx_profile->desense_wl_hi_lo_rssi_thresh,
+ pbtcx_profile->desense_wl_lo_hi_rssi_thresh,
+ pbtcx_profile->ack_pwr_wl_hi_lo_rssi_thresh,
+ pbtcx_profile->ack_pwr_wl_lo_hi_rssi_thresh,
+ pbtcx_profile->tx_pwr_wl_hi_lo_rssi_thresh,
+ pbtcx_profile->tx_pwr_wl_lo_hi_rssi_thresh);
+ /* Desense and Power values per core */
+ printf("--- Desense and power limits per core ---\n");
+ for (i = 0; i < chain_attr_count; i++) {
+ printf("Core %u:\t desense level:%d\t"
+ "ACK power strong RSSI:%d\t"
+ "ACK power weak RSSI:%d\t"
+ "Tx power strong RSSI:%d\t"
+ "Tx power weak RSSI:%d\n", i,
+ pbtcx_profile->chain_attr[i].desense_level,
+ pbtcx_profile->chain_attr[i].ack_pwr_strong_rssi,
+ pbtcx_profile->chain_attr[i].ack_pwr_weak_rssi,
+ pbtcx_profile->chain_attr[i].tx_pwr_strong_rssi,
+ pbtcx_profile->chain_attr[i].tx_pwr_weak_rssi);
+ }
+}
+
+/* This IOVAR does a read-modify-write of the user specified profile */
+/* Since the utility does not know about the number of Tx chains on the device */
+/* We use the MAX_UCM_CHAINS to size the variable length array to pull the IO buffer */
+/* Once the buffer is modified by the user, the wlu layer passes the buffer back to driver */
+/* This buffer is sized by the number of TX chains (chain_attr_count) on the device */
+static int
+wl_btc_profile(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr = NULL;
+ wlc_btcx_profile_v1_t *pbtcx_profile = NULL;
+ wlc_btcx_chain_attr_t *chain_attr;
+ uint8 chain_attr_count;
+ int8 val;
+ int err, idx, opt_err, ncon;
+ char *endptr = NULL;
+ miniopt_t to;
+ size_t ucm_prof_sz = sizeof(*pbtcx_profile)
+ + MAX_UCM_CHAINS*sizeof(pbtcx_profile->chain_attr[1]);
+
+ /* discard the command name */
+ ++argv;
+ miniopt_init(&to, __FUNCTION__, NULL, FALSE);
+
+ /* First extract the profile index */
+ opt_err = miniopt(&to, argv);
+ if (opt_err == 0) {
+ if (to.opt == 'p') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " the profile index\n", __FUNCTION__, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.uval >= MAX_UCM_PROFILES) {
+ fprintf(stderr, "Profile selected is out of range.\n");
+ err = BCME_RANGE;
+ goto exit;
+ } else {
+ idx = to.uval;
+ }
+ } else {
+ fprintf(stderr, "Invalid first option. "
+ "Please select a profile first.\n");
+ err = BCME_BADOPTION;
+ goto exit;
+ }
+ } else {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ /* Get the relevant btc profile */
+ if (ucm_prof_sz > WLC_IOCTL_SMLEN) {
+ err = BCME_BUFTOOSHORT;
+ goto exit;
+ }
+
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, &idx, sizeof(idx), &ptr)) < 0) {
+ fprintf(stderr, "%s: getbuf ioctl failed\n", __FUNCTION__);
+ err = BCME_ERROR;
+ goto exit;
+ }
+
+ /* WL utility will pull MAX_UCM_CHAINS size variable array */
+ /* however the FW mallocs only chain_attr_count size variable array */
+ pbtcx_profile = calloc(1, ucm_prof_sz);
+ if (pbtcx_profile == NULL) {
+ err = BCME_NOMEM;
+ goto exit;
+ }
+ memcpy(pbtcx_profile, ptr, ucm_prof_sz);
+
+ if (pbtcx_profile->version != UCM_PROFILE_VERSION_1) {
+ err = BCME_VERSION;
+ goto exit;
+ }
+
+ chain_attr_count = pbtcx_profile->chain_attr_count;
+ if (chain_attr_count > MAX_UCM_CHAINS) {
+ fprintf(stderr, "number of Tx chains (%u) on the device exceeds"
+ " the maximum supported chains (%u)\n", chain_attr_count,
+ MAX_UCM_CHAINS);
+ err = BCME_ERROR;
+ goto exit;
+ }
+
+ argv += to.consumed;
+ chain_attr = pbtcx_profile->chain_attr;
+
+ /* Get: no more arguments */
+ if (*argv == NULL) {
+ wl_btc_print_profile(pbtcx_profile);
+ } else {
+ /* Set: more arguments to be parsed */
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!to.good_int) {
+ fprintf(stderr, "could not parse %s as an int for"
+ " option -%c\n", to.valstr, to.opt);
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ switch (to.opt) {
+ case 'e' :
+ pbtcx_profile->mode_strong_wl_bt = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'f' :
+ pbtcx_profile->mode_weak_wl = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'g' :
+ pbtcx_profile->mode_weak_bt = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'h' :
+ pbtcx_profile->mode_weak_wl_bt = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'W' :
+ pbtcx_profile->mode_wl_hi_lo_rssi_thresh = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'w' :
+ pbtcx_profile->mode_wl_lo_hi_rssi_thresh = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'B' :
+ pbtcx_profile->mode_bt_hi_lo_rssi_thresh = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'b' :
+ pbtcx_profile->mode_bt_lo_hi_rssi_thresh = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'D' :
+ pbtcx_profile->desense_wl_hi_lo_rssi_thresh = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'd' :
+ pbtcx_profile->desense_wl_lo_hi_rssi_thresh = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'A' :
+ pbtcx_profile->ack_pwr_wl_hi_lo_rssi_thresh = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'a' :
+ pbtcx_profile->ack_pwr_wl_lo_hi_rssi_thresh = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'T' :
+ pbtcx_profile->tx_pwr_wl_hi_lo_rssi_thresh = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 't' :
+ pbtcx_profile->tx_pwr_wl_lo_hi_rssi_thresh = to.val;
+ ncon = to.consumed;
+ break;
+
+ case 'l' :
+ argv++;
+ for (idx = 0; idx < chain_attr_count; idx++) {
+ if (*(argv+idx) != NULL) {
+ val = (int8)strtoul(*(argv+idx),
+ &endptr, 0);
+ if (*endptr != '\0') {
+ err = BCME_BADOPTION;
+ goto exit;
+ }
+ chain_attr[idx].desense_level = val;
+ } else {
+ err = BCME_BADLEN;
+ goto exit;
+ }
+ }
+ ncon = idx;
+ break;
+
+ case 'X' :
+ argv++;
+ for (idx = 0; idx < chain_attr_count; idx++) {
+ if (*(argv+idx) != NULL) {
+ val = (int8)strtoul(*(argv+idx),
+ &endptr, 0);
+ if (*endptr != '\0') {
+ err = BCME_BADOPTION;
+ goto exit;
+ }
+ chain_attr[idx].ack_pwr_strong_rssi = val;
+ } else {
+ err = BCME_BADLEN;
+ goto exit;
+ }
+ }
+ ncon = idx;
+ break;
+
+ case 'x' :
+ argv++;
+ for (idx = 0; idx < chain_attr_count; idx++) {
+ if (*(argv+idx) != NULL) {
+ val = (int8)strtoul(*(argv+idx),
+ &endptr, 0);
+ if (*endptr != '\0') {
+ err = BCME_BADOPTION;
+ goto exit;
+ }
+ chain_attr[idx].ack_pwr_weak_rssi = val;
+ } else {
+ err = BCME_BADLEN;
+ goto exit;
+ }
+ }
+ ncon = idx;
+ break;
+
+ case 'Y' :
+ argv++;
+ for (idx = 0; idx < chain_attr_count; idx++) {
+ if (*(argv+idx) != NULL) {
+ val = (int8)strtoul(*(argv+idx),
+ &endptr, 0);
+ if (*endptr != '\0') {
+ err = BCME_BADOPTION;
+ goto exit;
+ }
+ chain_attr[idx].tx_pwr_strong_rssi = val;
+ } else {
+ err = BCME_BADLEN;
+ goto exit;
+ }
+ }
+ ncon = idx;
+ break;
+
+ case 'y' :
+ argv++;
+ for (idx = 0; idx < chain_attr_count; idx++) {
+ if (*(argv+idx) != NULL) {
+ val = (int8)strtoul(*(argv+idx),
+ &endptr, 0);
+ if (*endptr != '\0') {
+ err = BCME_BADOPTION;
+ goto exit;
+ }
+ chain_attr[idx].tx_pwr_weak_rssi = val;
+ } else {
+ err = BCME_BADLEN;
+ goto exit;
+ }
+ }
+ ncon = idx;
+ break;
+
+ default :
+ fprintf(stderr, "Invalid option %c\n", to.opt);
+ }
+ argv += ncon;
+ }
+
+ /* write back using var length array size of pbtcx_profile->chain_attr_count */
+ if ((err = wlu_var_setbuf(wl, cmd->name, pbtcx_profile, sizeof(*pbtcx_profile)
+ + chain_attr_count*sizeof(pbtcx_profile->chain_attr[1])) < 0)) {
+ fprintf(stderr, "%s: fail to set %d\n", __FUNCTION__, err);
+ err = BCME_ERROR;
+ goto exit;
+ }
+ }
+ err = BCME_OK;
+
+exit:
+ if (pbtcx_profile != NULL)
+ free(pbtcx_profile);
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_cac.c b/wl/src/wl/exe/wluc_cac.c
new file mode 100644
index 0000000..96425c3
--- /dev/null
+++ b/wl/src/wl/exe/wluc_cac.c
@@ -0,0 +1,775 @@
+/*
+ * wl cac command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_cac.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <proto/802.11e.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_cac, wl_tslist, wl_tspec, wl_tslist_ea, wl_tspec_ea, wl_cac_delts_ea;
+static void wl_cac_addts_usage(void);
+static void wl_cac_delts_usage(void);
+static void wl_print_tspec(tspec_arg_t *ts);
+
+static cmd_t wl_cac_cmds[] = {
+ { "cac_addts", wl_cac, -1, WLC_SET_VAR,
+ "add TSPEC, error if STA is not associated or WME is not enabled\n"
+ "\targ: TSPEC parameter input list"},
+ { "cac_delts", wl_cac, -1, WLC_SET_VAR,
+ "delete TSPEC, error if STA is not associated or WME is not enabled\n"
+ "\targ: TSINFO for the target tspec"},
+ { "cac_delts_ea", wl_cac_delts_ea, -1, WLC_SET_VAR,
+ "delete TSPEC, error if STA is not associated or WME is not enabled\n"
+ "\targ1: Desired TSINFO for the target tspec\n"
+ "\targ2: Desired MAC address"},
+ { "cac_tslist", wl_tslist, WLC_GET_VAR, -1,
+ "Get the list of TSINFO in driver\n"
+ "\teg. 'wl cac_tslist' get a list of TSINFO"},
+ { "cac_tslist_ea", wl_tslist_ea, WLC_GET_VAR, -1,
+ "Get the list of TSINFO for given STA in driver\n"
+ "\teg. 'wl cac_tslist_ea ea' get a list of TSINFO"},
+ { "cac_tspec", wl_tspec, WLC_GET_VAR, -1,
+ "Get specific TSPEC with matching TSINFO\n"
+ "\teg. 'wl cac_tspec 0xaa 0xbb 0xcc' where 0xaa 0xbb & 0xcc are TSINFO octets"},
+ { "cac_tspec_ea", wl_tspec_ea, WLC_GET_VAR, -1,
+ "Get specific TSPEC for given STA with matching TSINFO\n"
+ "\teg. 'wl cac_tspec 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx'\n"
+ "\t where 0xaa 0xbb & 0xcc are TSINFO octets and xx is mac address"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_cac_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register cac commands */
+ wl_module_cmds_register(wl_cac_cmds);
+}
+
+#define NUM_TSLIST_ARG 3 /* minimum number of arguments required for TSLIST */
+#define NUM_TSLIST_PER_EA_ARG 3 /* minimum number of arguments required for TSLIST */
+#define MIN_NUM_DELTS_ARG 4 /* minimum number of arguments required for DELTS */
+#define MIN_NUM_DELTS_EA_ARG 5 /* minimum number of arguments required for DELTS */
+#define MIN_NUM_ADDTS_ARG 20 /* minimum number of arguments required for ADDTS */
+#define PERIODIC_TRAFFIC 1 /* Periodic traffic type */
+#define VO_TID (0 << 1) /* voice TID */
+#define VI_TID (1 << 1) /* signal TID */
+#define UPLINK_DIRECTION (0 << 5) /* uplink direction traffic stream */
+#define DOWNLINK_DIRECTION (1 << 5) /* downlink direction traffic stream */
+#define BI_DIRECTION (3 << 5) /* bi direction traffic stream */
+#define EDCA_ACCESS (1 << 7) /* EDCA access policy */
+#define UAPSD_PSB (1 << 2) /* U-APSD power saving behavior */
+#define VO_USER_PRIO (6 << 3) /* voice user priority */
+#define VI_USER_PRIO (4 << 3) /* signal user priority */
+#define TID_SHIFT 1 /* TID Shift */
+#define UP_SHIFT 3 /* UP Shift */
+
+static void
+wl_cac_format_tspec_htod(tspec_arg_t *tspec_arg)
+{
+ tspec_arg->version = htod16(tspec_arg->version);
+ tspec_arg->length = htod16(tspec_arg->length);
+ tspec_arg->flag = htod32(tspec_arg->flag);
+ tspec_arg->nom_msdu_size = htod16(tspec_arg->nom_msdu_size);
+ tspec_arg->max_msdu_size = htod16(tspec_arg->max_msdu_size);
+ tspec_arg->min_srv_interval = htod32(tspec_arg->min_srv_interval);
+ tspec_arg->max_srv_interval = htod32(tspec_arg->max_srv_interval);
+ tspec_arg->inactivity_interval = htod32(tspec_arg->inactivity_interval);
+ tspec_arg->suspension_interval = htod32(tspec_arg->suspension_interval);
+ tspec_arg->srv_start_time = htod32(tspec_arg->srv_start_time);
+ tspec_arg->min_data_rate = htod32(tspec_arg->min_data_rate);
+ tspec_arg->mean_data_rate = htod32(tspec_arg->mean_data_rate);
+ tspec_arg->peak_data_rate = htod32(tspec_arg->peak_data_rate);
+ tspec_arg->max_burst_size = htod32(tspec_arg->max_burst_size);
+ tspec_arg->delay_bound = htod32(tspec_arg->delay_bound);
+ tspec_arg->min_phy_rate = htod32(tspec_arg->min_phy_rate);
+ tspec_arg->surplus_bw = htod16(tspec_arg->surplus_bw);
+ tspec_arg->medium_time = htod16(tspec_arg->medium_time);
+}
+
+static void
+wl_cac_format_tspec_dtoh(tspec_arg_t *tspec_arg)
+{
+ tspec_arg->version = dtoh16(tspec_arg->version);
+ tspec_arg->length = dtoh16(tspec_arg->length);
+ tspec_arg->flag = dtoh32(tspec_arg->flag);
+ tspec_arg->nom_msdu_size = dtoh16(tspec_arg->nom_msdu_size);
+ tspec_arg->max_msdu_size = dtoh16(tspec_arg->max_msdu_size);
+ tspec_arg->min_srv_interval = dtoh32(tspec_arg->min_srv_interval);
+ tspec_arg->max_srv_interval = dtoh32(tspec_arg->max_srv_interval);
+ tspec_arg->inactivity_interval = dtoh32(tspec_arg->inactivity_interval);
+ tspec_arg->suspension_interval = dtoh32(tspec_arg->suspension_interval);
+ tspec_arg->srv_start_time = dtoh32(tspec_arg->srv_start_time);
+ tspec_arg->min_data_rate = dtoh32(tspec_arg->min_data_rate);
+ tspec_arg->mean_data_rate = dtoh32(tspec_arg->mean_data_rate);
+ tspec_arg->peak_data_rate = dtoh32(tspec_arg->peak_data_rate);
+ tspec_arg->max_burst_size = dtoh32(tspec_arg->max_burst_size);
+ tspec_arg->delay_bound = dtoh32(tspec_arg->delay_bound);
+ tspec_arg->min_phy_rate = dtoh32(tspec_arg->min_phy_rate);
+ tspec_arg->surplus_bw = dtoh16(tspec_arg->surplus_bw);
+ tspec_arg->medium_time = dtoh16(tspec_arg->medium_time);
+
+}
+
+static void wl_cac_addts_usage(void)
+{
+ fprintf(stderr, "Too few arguments\n");
+ fprintf(stderr, "wl cac_addts ver dtoken tid dir psb up a b c d e ...\n");
+ fprintf(stderr, "\twhere ver is the structure version\n");
+ fprintf(stderr, "\twhere dtoken is the dialog token [range 1-255]\n");
+ fprintf(stderr, "\twhere tid is the tspec identifier [range 0-7]\n");
+ fprintf(stderr, "\twhere dir is direction [uplink | downlink | bi-directional]\n");
+ fprintf(stderr, "\twhere psb is power save mode [legacy|U-APSD]\n");
+ fprintf(stderr, "\twhere up is user priority [range 0-7]\n");
+ fprintf(stderr, "\twhere a is the nominal MSDU size\n");
+ fprintf(stderr, "\twhere b is bool for fixed size msdu [ 0 and 1]\n");
+ fprintf(stderr, "\twhere c is the maximum MSDU size\n");
+ fprintf(stderr, "\twhere d is the minimum service interval\n");
+ fprintf(stderr, "\twhere e is the maximum service interval\n");
+ fprintf(stderr, "\twhere f is the inactivity interval\n");
+ fprintf(stderr, "\twhere g is the suspension interval\n");
+ fprintf(stderr, "\twhere h is the minimum data rate\n");
+ fprintf(stderr, "\twhere i is the mean data rate\n");
+ fprintf(stderr, "\twhere j is the peak data rate\n");
+ fprintf(stderr, "\twhere k is the max burst size\n");
+ fprintf(stderr, "\twhere l is the delay bound\n");
+ fprintf(stderr, "\twhere m is the surplus bandwidth [fixed point notation]\n");
+ fprintf(stderr, "\twhere n is the minimum PHY rate\n");
+}
+
+static void wl_cac_delts_usage(void)
+{
+ fprintf(stderr, "Too few arguments\n");
+ fprintf(stderr, "wl cac_delts ver a b c \n");
+ fprintf(stderr, "\twhere ver is the tspec version\n");
+ fprintf(stderr, "\twhere a is byte[0] of tsinfo (bits 0-7)\n");
+ fprintf(stderr, "\twhere b is byte[1] of tsinfo (bits 8-15)\n");
+ fprintf(stderr, "\twhere c is byte[2] of tsinfo (bits 16-23)\n");
+}
+
+static int
+wl_cac(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1;
+ int ap_mode = 0;
+ int apsta_mode = 0;
+ int cmd_type = 0;
+ tspec_arg_t tspec_arg;
+ char *endptr = NULL;
+ uint buflen;
+ char *arg1, *user_argv;
+ uint8 direction = BI_DIRECTION;
+ uint8 user_tid, user_prio, user_psb;
+ uint fixed;
+
+
+ if ((err = wlu_iovar_get(wl, "apsta", &apsta_mode, sizeof(apsta_mode))))
+ return err;
+
+ if (!apsta_mode) {
+ if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
+ return err;
+ else {
+ if (dtoh32(ap_mode)) {
+ fprintf(stderr,
+ "This command can ONLY be executed on a STA or APSTA\n");
+ return err;
+ }
+ }
+ }
+
+ if (!strcmp(*argv, "cac_addts"))
+ cmd_type = 1;
+ else if (!strcmp(*argv, "cac_delts"))
+ cmd_type = 2;
+ else {
+ fprintf(stderr, "unknown command\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* eat command name */
+ if (!*++argv) {
+ (cmd_type == 1) ? wl_cac_addts_usage():wl_cac_delts_usage();
+ return BCME_BADARG;
+ }
+
+ buflen = sizeof(tspec_arg_t);
+ memset((uint8 *)&tspec_arg, 0, buflen);
+
+ /* get direction option */
+ arg1 = *argv;
+
+ /* Unidirectional DL/UL */
+ if (!strcmp(arg1, "UDL") || (!strcmp(arg1, "UUL")))
+ direction = DOWNLINK_DIRECTION;
+
+ if (cmd_type == 1) {
+ uint argc = 0;
+
+ /* arg count */
+ while (argv[argc])
+ argc++;
+
+ /* required argments */
+ if (argc < MIN_NUM_ADDTS_ARG) {
+ wl_cac_addts_usage();
+ return BCME_USAGE_ERROR;
+ }
+
+ tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
+ tspec_arg.version = (uint16)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.dialog_token = (uint8)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ user_tid = (uint8)strtol(*argv++, &endptr, 0);
+ user_tid <<= TID_SHIFT;
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ /* store the pointer for parsing */
+ user_argv = *argv++;
+
+ if (!strcmp(user_argv, "uplink"))
+ direction = UPLINK_DIRECTION;
+ else if (!strcmp(user_argv, "downlink"))
+ direction = DOWNLINK_DIRECTION;
+ else if (!strcmp(user_argv, "bi-directional"))
+ direction = BI_DIRECTION;
+ else
+ return BCME_USAGE_ERROR;
+
+ /* store the pointer for parsing */
+ user_argv = *argv++;
+
+ if (!strcmp(user_argv, "legacy"))
+ user_psb = 0;
+ else if (!strcmp(user_argv, "U-APSD"))
+ user_psb = UAPSD_PSB;
+ else
+ return BCME_USAGE_ERROR;
+
+ user_prio = (uint8)strtol(*argv++, &endptr, 0);
+ user_prio <<= UP_SHIFT;
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.tsinfo.octets[0] = (uint8)(user_tid |
+ direction | EDCA_ACCESS);
+
+ tspec_arg.tsinfo.octets[1] = (uint8)(user_prio | user_psb);
+ tspec_arg.tsinfo.octets[2] = 0x00;
+
+ tspec_arg.nom_msdu_size = (uint16)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ fixed = (uint)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ if (fixed == 1)
+ tspec_arg.nom_msdu_size |= 0x8000;
+
+ tspec_arg.max_msdu_size = (uint16)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.min_srv_interval = strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.max_srv_interval = strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.inactivity_interval = strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.suspension_interval = strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.min_data_rate = strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.mean_data_rate = strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.peak_data_rate = strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.max_burst_size = strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.delay_bound = strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.surplus_bw = (uint16)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.min_phy_rate = strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ printf("Setting min_phy_rate to 0x%x\n", tspec_arg.min_phy_rate);
+ } else {
+ uint argc = 0;
+
+ /* arg count */
+ while (argv[argc])
+ argc++;
+
+ /* required argments */
+ if (argc < MIN_NUM_DELTS_ARG) {
+ wl_cac_delts_usage();
+ return BCME_USAGE_ERROR;
+ }
+
+ tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
+ tspec_arg.version = (uint16)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.tsinfo.octets[0] = (uint8)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.tsinfo.octets[1] = (uint8)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.tsinfo.octets[2] = (uint8)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+
+ wl_cac_format_tspec_htod(&tspec_arg);
+ err = wlu_var_setbuf(wl, cmd->name, &tspec_arg, buflen);
+
+ return err;
+}
+
+/* get a list of traffic stream (TSINFO) in driver */
+static int
+wl_tslist(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ int i;
+ int ap_mode, err = -1;
+ int apsta_mode = 0;
+ struct tslist *tslist;
+
+ UNUSED_PARAMETER(argv);
+
+
+ if ((err = wlu_iovar_get(wl, "apsta", &apsta_mode, sizeof(apsta_mode))))
+ return err;
+
+ if (!apsta_mode) {
+ if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
+ return err;
+ else {
+ if (dtoh32(ap_mode)) {
+ fprintf(stderr,
+ "This command can ONLY be executed on a STA or APSTA\n");
+ return err;
+ }
+ }
+ }
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return err;
+
+ tslist = (struct tslist *)ptr;
+ tslist->count = dtoh32(tslist->count);
+ for (i = 0; i < tslist->count; i++)
+ printf("tsinfo 0x%02X 0x%02X 0x%02X TID %d User Prio %d Direction %d\n",
+ tslist->tsinfo[i].octets[0],
+ tslist->tsinfo[i].octets[1],
+ tslist->tsinfo[i].octets[2],
+ WLC_CAC_GET_TID(tslist->tsinfo[i]),
+ WLC_CAC_GET_USER_PRIO(tslist->tsinfo[i]),
+ WLC_CAC_GET_DIR(tslist->tsinfo[i]));
+
+ return 0;
+}
+
+/* get specific TSPEC in driver */
+static int
+wl_tspec(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ int ap_mode, err = -1;
+ tspec_arg_t *ts, tspec_arg;
+ char *temp = NULL;
+ uint argc = 0;
+
+ if ((wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
+ return err;
+ ap_mode = dtoh32(ap_mode);
+
+ if (ap_mode) {
+ fprintf(stderr, "This command can only be executed on the STA\n");
+ return err;
+ }
+
+ /* eat command name */
+ argv++;
+
+ /* arg count */
+ while (argv[argc])
+ argc++;
+
+ /* required argments */
+ if (argc < NUM_TSLIST_ARG) {
+ fprintf(stderr, "Too few arguments\n");
+ fprintf(stderr, "wl cac_tspec 0xaa 0xbb 0xcc \n");
+ fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n");
+ fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n");
+ fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ memset((uint8 *)&tspec_arg, 0, sizeof(tspec_arg_t));
+
+ tspec_arg.tsinfo.octets[0] = (uint8)strtol(*argv++, &temp, 0);
+ if (*temp != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.tsinfo.octets[1] = (uint8)strtol(*argv++, &temp, 0);
+ if (*temp != '\0')
+ return BCME_USAGE_ERROR;
+
+ tspec_arg.tsinfo.octets[2] = (uint8)strtol(*argv++, &temp, 0);
+ if (*temp != '\0')
+ return BCME_USAGE_ERROR;
+ if ((err = wlu_var_getbuf(wl, cmd->name, &tspec_arg, sizeof(tspec_arg_t), &ptr)) < 0)
+ return err;
+
+ ts = (tspec_arg_t *)ptr;
+ wl_cac_format_tspec_dtoh(ts);
+ wl_print_tspec(ts);
+
+ return 0;
+}
+
+/* get the tspec list for the given station */
+static int
+wl_tslist_ea(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ int i;
+ int ap_mode, err = -1;
+ struct tslist *tslist;
+ scb_val_t scb_val;
+
+
+ if (!*++argv) {
+ printf("MAC address must be specified\n");
+ return BCME_USAGE_ERROR;
+ } else if (!wl_ether_atoe(*argv, &scb_val.ea)) {
+ printf("Malformed MAC address parameter\n");
+ return BCME_USAGE_ERROR;
+ }
+ if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
+ return err;
+
+ ap_mode = dtoh32(ap_mode);
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, &scb_val.ea, ETHER_ADDR_LEN, &ptr)) < 0)
+ return err;
+
+ tslist = (struct tslist *)ptr;
+
+ for (i = 0; i < tslist->count; i++)
+ printf("tsinfo 0x%02X 0x%02X 0x%02X TID %d User Prio %d Direction %d\n",
+ tslist->tsinfo[i].octets[0],
+ tslist->tsinfo[i].octets[1],
+ tslist->tsinfo[i].octets[2],
+ WLC_CAC_GET_TID(tslist->tsinfo[i]),
+ WLC_CAC_GET_USER_PRIO(tslist->tsinfo[i]),
+ WLC_CAC_GET_DIR(tslist->tsinfo[i]));
+
+ return 0;
+
+}
+
+/* get specific TSPEC for a STA */
+static int
+wl_tspec_ea(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ int err = -1;
+ tspec_per_sta_arg_t tsea;
+ tspec_arg_t *ts;
+ char *temp;
+ uint argc = 0;
+
+ /* eat command name */
+ argv++;
+
+ while (argv[argc])
+ argc++;
+
+ /* required argments */
+ if (argc < (NUM_TSLIST_PER_EA_ARG + 1)) {
+ fprintf(stderr, "Too few arguments\n");
+ fprintf(stderr, "wl cac_tspec 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx\n");
+ fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n");
+ fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n");
+ fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n");
+ fprintf(stderr, "\twhere xx:xx:xx:xx:xx:xx is mac address )\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ memset((uint8 *)&tsea, 0, sizeof(tspec_per_sta_arg_t));
+
+ ts = &tsea.ts;
+
+ ts->tsinfo.octets[0] = (uint8)strtol(*argv++, &temp, 0);
+ if (*temp != '\0')
+ return BCME_USAGE_ERROR;
+
+ ts->tsinfo.octets[1] = (uint8)strtol(*argv++, &temp, 0);
+ if (*temp != '\0')
+ return BCME_USAGE_ERROR;
+
+ ts->tsinfo.octets[2] = (uint8)strtol(*argv++, &temp, 0);
+ if (*temp != '\0')
+ return BCME_USAGE_ERROR;
+
+ /* add the ether address after tsinfo */
+ if (!*argv) {
+ printf("MAC address must be specified\n");
+ return BCME_USAGE_ERROR;
+ } else if (!wl_ether_atoe(*argv, &tsea.ea)) {
+ printf("Malformed MAC address parameter\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, &tsea, sizeof(tspec_per_sta_arg_t), &ptr)) < 0)
+ return err;
+
+ ts = (tspec_arg_t *)ptr;
+ wl_cac_format_tspec_dtoh(ts);
+ wl_print_tspec(ts);
+ return 0;
+
+}
+
+static const uint8 wlu_wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE,
+ AC_BE };
+static const uint8 wlu_prio2fifo[NUMPRIO] = {
+ 0, /* 0 BE AC_BE Best Effort */
+ 1, /* 1 BK AC_BK Background */
+ 2, /* 2 -- AC_BK Background */
+ 3, /* 3 EE AC_BE Best Effort */
+ 4, /* 4 CL AC_VI Video */
+ 5, /* 5 VI AC_VI Video */
+ 6, /* 6 VO AC_VO Voice */
+ 7 /* 7 NC AC_VO Voice */
+};
+#define WME_PRIO2AC(prio) wlu_wme_fifo2ac[wlu_prio2fifo[(prio)]]
+
+static void
+wl_print_tspec(tspec_arg_t *ts)
+{
+ const char *str;
+ if (ts->version != TSPEC_ARG_VERSION) {
+ printf("\tIncorrect version of TSPEC struct: expected %d; got %d\n",
+ TSPEC_ARG_VERSION, ts->version);
+ return;
+ }
+
+ if (ts->length < (sizeof(tspec_arg_t) - (2 * sizeof(uint16)))) {
+ printf("\tTSPEC arg length too short: expected %d; got %d\n",
+ (int)(sizeof(tspec_arg_t) - (2 * sizeof(uint16))), ts->length);
+ return;
+ }
+
+ switch (ts->flag & TSPEC_STATUS_MASK) {
+ case TSPEC_PENDING:
+ str = "PENDING";
+ break;
+ case TSPEC_ACCEPTED:
+ str = "ACCEPTED";
+ break;
+ case TSPEC_REJECTED:
+ str = "REJECTED";
+ break;
+ default:
+ str = "UNKNOWN";
+ break;
+ }
+
+ printf("version %d\n", ts->version);
+ printf("length %d\n", ts->length);
+
+ printf("TID %d %s\n", WLC_CAC_GET_TID(ts->tsinfo), str);
+ printf("tsinfo 0x%02x 0x%02x 0x%02x\n", ts->tsinfo.octets[0],
+ ts->tsinfo.octets[1], ts->tsinfo.octets[2]);
+
+ /* breakout bitfields for apsd */
+ if (WLC_CAC_GET_PSB(ts->tsinfo)) {
+ int ac = WME_PRIO2AC(WLC_CAC_GET_USER_PRIO(ts->tsinfo));
+ switch (WLC_CAC_GET_DIR(ts->tsinfo)) {
+ case (TS_INFO_UPLINK >> TS_INFO_DIRECTION_SHIFT):
+ printf("AC[%d] : Trigger enabled\n", ac);
+ break;
+
+ case (TS_INFO_DOWNLINK >> TS_INFO_DIRECTION_SHIFT):
+ printf("AC[%d] : Delivery enabled\n", ac);
+ break;
+
+ case (TS_INFO_BIDIRECTIONAL >>
+ TS_INFO_DIRECTION_SHIFT):
+ printf("AC[%d] : Trig & Delv enabled\n", ac);
+ break;
+ }
+ } else {
+ int ac;
+ ac = WME_PRIO2AC(WLC_CAC_GET_USER_PRIO(ts->tsinfo));
+ printf("AC [%d] : Legacy Power save\n", ac);
+ }
+
+
+ printf("nom_msdu_size %d %s\n", (ts->nom_msdu_size & 0x7fff),
+ ((ts->nom_msdu_size & 0x8000) ? "fixed size" : ""));
+ printf("max_msdu_size %d\n", ts->max_msdu_size);
+ printf("min_srv_interval %d\n", ts->min_srv_interval);
+ printf("max_srv_interval %d\n", ts->max_srv_interval);
+ printf("inactivity_interval %d\n", ts->inactivity_interval);
+ printf("suspension_interval %d\n", ts->suspension_interval);
+ printf("srv_start_time %d\n", ts->srv_start_time);
+ printf("min_data_rate %d\n", ts->min_data_rate);
+ printf("mean_data_rate %d\n", ts->mean_data_rate);
+ printf("peak_data_rate %d\n", ts->peak_data_rate);
+ printf("max_burst_size %d\n", ts->max_burst_size);
+ printf("delay_bound %d\n", ts->delay_bound);
+ printf("min_phy_rate %d\n", ts->min_phy_rate);
+ printf("surplus_bw %d\n", ts->surplus_bw);
+ printf("medium_time %d\n", ts->medium_time);
+}
+
+
+/* send delts for a specific ea */
+/* TODO : Club this with wl_tspec_ea */
+static int
+wl_cac_delts_ea(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ int err = -1;
+ char *endptr = NULL;
+ tspec_per_sta_arg_t tsea;
+ tspec_arg_t *ts;
+ uint argc = 0;
+
+ /* eat command name */
+ argv++;
+
+ while (argv[argc])
+ argc++;
+
+ /* required argments */
+ if (argc < (NUM_TSLIST_PER_EA_ARG + 1)) {
+ fprintf(stderr, "Too few arguments\n");
+ fprintf(stderr, "wl cac_delts_ea ver 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx\n");
+ fprintf(stderr, "\twhere ver is the tspec version\n");
+ fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n");
+ fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n");
+ fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n");
+ fprintf(stderr, "\twhere xx:xx:xx:xx:xx:xx is mac address )\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ memset((uint8 *)&tsea, 0, sizeof(tspec_per_sta_arg_t));
+
+ ts = &tsea.ts;
+
+ ts->length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
+ ts->version = (uint16)strtol(*argv++, &endptr, 0);
+
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ts->tsinfo.octets[0] = (uint8)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ts->tsinfo.octets[1] = (uint8)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ts->tsinfo.octets[2] = (uint8)strtol(*argv++, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+
+ /* add the ether address after tsinfo */
+ if (!*argv) {
+ printf("MAC address must be specified\n");
+ return BCME_USAGE_ERROR;
+ } else if (!wl_ether_atoe(*argv, &tsea.ea)) {
+ printf("Malformed MAC address parameter\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ wl_cac_format_tspec_htod(ts);
+ if ((err = wlu_var_getbuf(wl, cmd->name, &tsea, sizeof(tspec_per_sta_arg_t), &ptr)) < 0)
+ return err;
+
+ return 0;
+
+}
diff --git a/wl/src/wl/exe/wluc_ecounters.c b/wl/src/wl/exe/wluc_ecounters.c
new file mode 100644
index 0000000..5d2fe1f
--- /dev/null
+++ b/wl/src/wl/exe/wluc_ecounters.c
@@ -0,0 +1,340 @@
+/*
+ * wl ecounters command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id:$
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+#if defined(linux)
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* linux */
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+#include <sys/stat.h>
+#include <errno.h>
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <proto/802.3.h>
+#include <proto/bcmip.h>
+#include <proto/bcmipv6.h>
+#include <proto/bcmtcp.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#define EVENT_LOG_DUMPER
+#include <event_log.h>
+
+static cmd_func_t wl_ecounters_config;
+static cmd_func_t wl_event_ecounters_config;
+
+static cmd_t wl_ecounters_cmds[] = {
+ { "ecounters", wl_ecounters_config, -1, WLC_SET_VAR,
+ "\tDescription: Configure ecounters to retrieve statistics at periodic intervals"
+ "\tusage: wl ecounters <event_log_set_num> <event_log_buffer_size> "
+ "<periodicity in secs> <num_events> <event_log_tag_num1> <event_log_tag_num2>..."
+ "\tTo disable ecounters: set periodicity and num_events = 0 with no tags. "
+ "For ex. wl ecounters 0 0 0 0"
+ },
+ { "event_ecounters", wl_event_ecounters_config, -1, WLC_SET_VAR,
+ "\tDescription: Configure WLC events to trigger ecounters when an event to be \n"
+ "\tgenerated matches a hosts supplied events mask\n"
+ "\tusage: wl event_ecounters -m mask [-s set -t <tag> [<tag> ...]]\n"
+ "\twhere mask is hex bitmask of events\n"
+ "\tset is the event log set where ecounters should write data.\n"
+ "\ttag(s) is/are event log tags that ecounters should report.\n"
+ "\tNote that the host must initialize event log set of\n"
+ "\tinterest with event_log_set_init iovar\n"
+ "\tTo disable event ecounters configuration:\n"
+ "\twl event_ecounters -m 0x0\n"
+ },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+/* Command format: wl counters <event log set> < event log buffer size>
+ * <periodicity in secs> <number of events> <tag1> <tag 2> ...
+ */
+#define ECOUNTERS_ARG_EVENT_LOG_SET_POS 0
+#define ECOUNTERS_ARG_EVENT_LOG_BUFFER_SIZE_POS 1
+#define ECOUNTERS_ARG_PERIODICITY_POS 2
+#define ECOUNTERS_ARG_NUM_EVENTS 3
+#define ECOUNTERS_NUM_BASIC_ARGS 4
+
+static int wl_ecounters_config(void *wl, cmd_t *cmd, char **argv)
+{
+ ecounters_config_request_t *p_config;
+ int rc = 0;
+ uint i, argc, len, alloc_size_adjustment;
+ uint ecounters_basic_args[ECOUNTERS_NUM_BASIC_ARGS];
+
+ /* Count <type> args and allocate buffer */
+ for (argv++, argc = 0; argv[argc]; argc++);
+
+ if (argc < ECOUNTERS_NUM_BASIC_ARGS) {
+ fprintf(stderr, "Minimum 4 arguments are required for Ecounters. \n");
+ fprintf(stderr, "wl ecounters <event log set > < event log buffer size> "
+ "<periodicity> <num_events> <tag1> <tag2>..\n");
+ return BCME_ERROR;
+ }
+
+ for (i = 0; i < ECOUNTERS_NUM_BASIC_ARGS; i++, argv++) {
+ char *endptr;
+ ecounters_basic_args[i] = strtoul(*argv, &endptr, 0);
+ argc--;
+ if (*endptr != '\0') {
+ fprintf(stderr, "Type '%s' (arg %d) not a number?\n", *argv, i);
+ return BCME_ERROR;
+ }
+ }
+
+ if (ecounters_basic_args[ECOUNTERS_ARG_EVENT_LOG_SET_POS] > NUM_EVENT_LOG_SETS)
+ {
+ fprintf(stderr, " Event log set > MAX sets (%d)\n", NUM_EVENT_LOG_SETS);
+ return BCME_ERROR;
+ }
+
+ if (ecounters_basic_args[ECOUNTERS_ARG_EVENT_LOG_BUFFER_SIZE_POS] >
+ EVENT_LOG_MAX_BLOCK_SIZE)
+ {
+ fprintf(stderr, " Event log buffer size > MAX buffer size (%d)\n",
+ EVENT_LOG_MAX_BLOCK_SIZE);
+ return BCME_ERROR;
+ }
+
+ /* Allocate memory for structure to be sent. If no types were passed, allocated
+ * config structure must have aleast one type present even if not used.
+ */
+ alloc_size_adjustment = (argc) ? argc : 1;
+
+ len = OFFSETOF(ecounters_config_request_t, type) +
+ (alloc_size_adjustment) * sizeof(uint16);
+ p_config = (ecounters_config_request_t *)malloc(len);
+ if (p_config == NULL) {
+ fprintf(stderr, "malloc failed to allocate %d bytes\n", len);
+ return -1;
+ }
+ memset(p_config, 0, len);
+
+ p_config->version = ECOUNTERS_VERSION_1;
+ p_config->set =
+ ecounters_basic_args[ECOUNTERS_ARG_EVENT_LOG_SET_POS];
+ p_config->size =
+ ecounters_basic_args[ECOUNTERS_ARG_EVENT_LOG_BUFFER_SIZE_POS];
+ p_config->timeout =
+ ecounters_basic_args[ECOUNTERS_ARG_PERIODICITY_POS];
+ p_config->num_events =
+ ecounters_basic_args[ECOUNTERS_ARG_NUM_EVENTS];
+
+ /* No types were passed. So ntypes = 0. */
+ p_config->ntypes = (argc == 0) ? 0 : argc;
+ for (i = 0; i < argc; i++, argv++) {
+ char *endptr;
+ p_config->type[i] = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Type '%s' (arg %d) not a number?\n", *argv, i);
+ free(p_config);
+ return -1;
+ }
+ }
+
+ rc = wlu_var_setbuf(wl, cmd->name, p_config, len);
+ free(p_config);
+ return rc;
+}
+
+/* Command format: wl event_ecounters -m <hex string> -s <set> -t <tag list> */
+static int wl_event_ecounters_config(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc = 0, err = 0;
+ char *mask_arg = NULL, *set_arg = NULL;
+ uint16 masksize, eventmsgs_len, trig_config_len, set, i;
+ ecounters_eventmsgs_ext_t *eventmsgs;
+ ecounters_trigger_config_t *trigger_config;
+ uint8* iovar_data_ptr = NULL;
+
+ /* Count <type> args and allocate buffer */
+ for (argv++, argc = 0; argv[argc]; argc++);
+
+ /* Look for -m. Position of these arguments is fixed. */
+ if ((*argv) && !strcmp(*argv, "-m")) {
+ mask_arg = *++argv;
+ if (!mask_arg) {
+ fprintf(stderr, "Missing argument to -m option\n");
+ return BCME_USAGE_ERROR;
+ }
+ /* Consumed 2 arguments -m and its argument */
+ argc -= 2;
+ argv++;
+ }
+ else {
+ fprintf(stderr, "Missing -m <hex string> option\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Skip any 0x if there are any */
+ if (mask_arg[0] == '0' && mask_arg[1] == 'x')
+ mask_arg += 2;
+
+ /* adjust the length. If there are <= 2 characters, minimum 1 byte id required */
+ masksize = (strlen(mask_arg)/2);
+ if (masksize < 1) {
+ masksize = 1;
+ }
+ masksize = MIN(masksize, WL_EVENTING_MASK_LEN);
+ eventmsgs_len =
+ ROUNDUP((masksize + ECOUNTERS_EVENTMSGS_EXT_MASK_OFFSET), sizeof(uint32));
+ /* send user mask size up to WL_EVENTING_MASK_MAX_LEN */
+ eventmsgs = (ecounters_eventmsgs_ext_t*)malloc(eventmsgs_len);
+
+ if (eventmsgs == NULL) {
+ fprintf(stderr, "fail to allocate event_msgs"
+ "structure of %d bytes\n", eventmsgs_len);
+ return BCME_NOMEM;
+ }
+ memset((void*)eventmsgs, 0, eventmsgs_len);
+ err = hexstrtobitvec(mask_arg, eventmsgs->mask, masksize);
+ if (err) {
+ fprintf(stderr, "hexstrtobitvec() error: %d\n", err);
+ free(eventmsgs);
+ return BCME_BADARG;
+ }
+ eventmsgs->len = masksize;
+ eventmsgs->version = ECOUNTERS_EVENTMSGS_VERSION_1;
+
+ /* if all entries in mask = 0 => disable command
+ * the tags do not matter in this case
+ * A disable command results in ecounters config release in dongle
+ */
+ for (i = 0; i < eventmsgs->len; i++) {
+ if (eventmsgs->mask[i])
+ break;
+ }
+
+ if (i == eventmsgs->len) {
+ /* Send only mask no trigger config */
+ iovar_data_ptr = (uint8*)eventmsgs;
+ trig_config_len = 0;
+ }
+ else {
+ /* look for -s */
+ if ((*argv) && !strcmp(*argv, "-s")) {
+ set_arg = *++argv;
+ if (!set_arg) {
+ if (eventmsgs)
+ free(eventmsgs);
+ fprintf(stderr, "Missing argument to -s option\n");
+ return BCME_USAGE_ERROR;
+ }
+ /* Consumed 2 arguments -s and its argument */
+ argc -= 2;
+ argv++;
+ }
+ else {
+ if (eventmsgs)
+ free(eventmsgs);
+ fprintf(stderr, "Missing -s <set> option\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ set = atoi(set_arg);
+ /* look for -t */
+ if ((*argv) && !strcmp(*argv, "-t")) {
+ /* Consumed only one argument. This will result in argc = 0
+ * but since there is no more argv, the if condition below
+ * will be satisfied and we will get out.
+ */
+ argc--;
+ if (!(*++argv)) {
+ if (eventmsgs)
+ free(eventmsgs);
+ fprintf(stderr, "argc: %d Missing argument to -t option\n", argc);
+ return BCME_USAGE_ERROR;
+ }
+ }
+ else {
+ if (eventmsgs)
+ free(eventmsgs);
+ fprintf(stderr, "Missing -t <tag list> option\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ trig_config_len = ECOUNTERS_TRIG_CONFIG_TYPE_OFFSET;
+ trig_config_len += argc * sizeof(uint16);
+
+ iovar_data_ptr = (uint8*)malloc(trig_config_len + eventmsgs_len);
+ if (iovar_data_ptr == NULL) {
+ fprintf(stderr, "fail to allocate memory to populate iovar"
+ " %d bytes\n", eventmsgs_len + trig_config_len);
+ free(eventmsgs);
+ return BCME_NOMEM;
+ }
+
+ /* copy eventmsgs struct in the allocate dmemory */
+ memcpy(iovar_data_ptr, eventmsgs, eventmsgs_len);
+ trigger_config = (ecounters_trigger_config_t *)(iovar_data_ptr + eventmsgs_len);
+
+ trigger_config->version = ECOUNTERS_TRIGGER_CONFIG_VERSION_1;
+ trigger_config->set = set;
+ trigger_config->ntypes = argc;
+
+ /* we don't need this anymore. Release any associated memories */
+ free(eventmsgs);
+
+ for (i = 0; i < argc; i++, argv++) {
+ char *endptr;
+ trigger_config->type[i] = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Type '%s' (tag %d) not a number?\n", *argv, i);
+ free(iovar_data_ptr);
+ return BCME_ERROR;
+ }
+ }
+ }
+
+ err = wlu_var_setbuf(wl, cmd->name, iovar_data_ptr, (eventmsgs_len + trig_config_len));
+ free(iovar_data_ptr);
+ return err;
+}
+
+/* module initialization */
+void
+wluc_ecounters_module_init(void)
+{
+ /* register ecounters commands */
+ wl_module_cmds_register(wl_ecounters_cmds);
+}
diff --git a/wl/src/wl/exe/wluc_extlog.c b/wl/src/wl/exe/wluc_extlog.c
new file mode 100644
index 0000000..b24d720
--- /dev/null
+++ b/wl/src/wl/exe/wluc_extlog.c
@@ -0,0 +1,203 @@
+/*
+ * wl extlog command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_extlog.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#include <wlc_extlog_idstr.h>
+
+static int wl_extlog(void *wl, cmd_t *cmd, char **argv);
+static int wl_extlog_cfg(void *wl, cmd_t *cmd, char **argv);
+
+static cmd_t wl_extlog_cmds[] = {
+ { "extlog", wl_extlog, WLC_GET_VAR, -1,
+ "get external logs\n"
+ "\tUsage: wl extlog <from_last> <number>\n"
+ "\tfrom_last: 1 - from the last log record; 0 - whole log recrods\n"
+ "\tnumber: number of log records to get, MAX is 32."},
+ { "extlog_clr", wl_var_void, -1, WLC_SET_VAR, "clear external log records"},
+ { "extlog_cfg", wl_extlog_cfg, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set external log configuration"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_extlog_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register extlog commands */
+ wl_module_cmds_register(wl_extlog_cmds);
+}
+
+static int
+wl_extlog(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc;
+ char *endptr;
+ int err;
+ int from_last;
+ int i, j;
+ char *log_p = NULL;
+ wlc_extlog_req_t r_args;
+ wlc_extlog_results_t *results;
+ void *ptr = NULL;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc > 3)
+ return BCME_USAGE_ERROR;
+
+ if (argc == 1)
+ from_last = 0;
+ else {
+ from_last = htod32(strtoul(argv[1], &endptr, 0));
+ if ((from_last != 0) && (from_last != 1))
+ return BCME_BADARG;
+ }
+
+ r_args.from_last = from_last;
+ if (argc == 3)
+ r_args.num = htod32(strtoul(argv[2], &endptr, 0));
+ else
+ r_args.num = 32;
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, &r_args, sizeof(wlc_extlog_req_t), &ptr)) < 0)
+ return err;
+
+ results = (wlc_extlog_results_t *)buf;
+
+ printf("get external log records: %d\n", results->num);
+ if (!results->num)
+ return 0;
+
+ if (results->version != EXTLOG_CUR_VER) {
+ printf("version mismatch: version = 0x%x, expected 0x%0x\n",
+ results->version, EXTLOG_CUR_VER);
+ return 0;
+ }
+
+ log_p = (char *)&results->logs[0];
+
+ printf("Seq:\tTime(ms) Log\n");
+ for (i = 0; i < (int)results->num; i++) {
+ printf("%d:\t%d\t ", ((log_record_t*)log_p)->seq_num,
+ ((log_record_t*)log_p)->time);
+ for (j = 0; j < FMTSTR_MAX_ID; j++)
+ if (((log_record_t*)log_p)->id == extlog_fmt_str[j].id)
+ break;
+ if (j == FMTSTR_MAX_ID) {
+ printf("fmt string not found for id %d\n", ((log_record_t*)log_p)->id);
+ log_p += results->record_len;
+ continue;
+ }
+
+ switch (extlog_fmt_str[j].arg_type) {
+ case LOG_ARGTYPE_NULL:
+ printf("%s", extlog_fmt_str[j].fmt_str);
+ break;
+
+ case LOG_ARGTYPE_STR:
+ printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->str);
+ break;
+
+ case LOG_ARGTYPE_INT:
+ printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->arg);
+ break;
+
+ case LOG_ARGTYPE_INT_STR:
+ printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->arg,
+ ((log_record_t*)log_p)->str);
+ break;
+
+ case LOG_ARGTYPE_STR_INT:
+ printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->str,
+ ((log_record_t*)log_p)->arg);
+ break;
+ }
+ log_p += results->record_len;
+ }
+
+ return 0;
+
+}
+
+static int
+wl_extlog_cfg(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc;
+ int err = 0;
+ char *endptr;
+ wlc_extlog_cfg_t *r_cfg;
+ wlc_extlog_cfg_t w_cfg;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc == 1) {
+ err = wl_var_get(wl, cmd, argv);
+ if (err < 0)
+ return err;
+ r_cfg = (wlc_extlog_cfg_t *)buf;
+ printf("max_number=%d, module=%x, level=%d, flag=%d, version=0x%04x\n",
+ r_cfg->max_number, r_cfg->module, r_cfg->level,
+ r_cfg->flag, r_cfg->version);
+ }
+ else if (argc == 4) {
+ w_cfg.module = htod16((uint16)(strtoul(argv[1], &endptr, 0)));
+ w_cfg.level = (uint8)strtoul(argv[2], &endptr, 0);
+ w_cfg.flag = (uint8)strtoul(argv[3], &endptr, 0);
+ err = wlu_var_setbuf(wl, cmd->name, &w_cfg, sizeof(wlc_extlog_cfg_t));
+ }
+ else {
+ fprintf(stderr, "illegal command!\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_he.c b/wl/src/wl/exe/wluc_he.c
new file mode 100644
index 0000000..88f0277
--- /dev/null
+++ b/wl/src/wl/exe/wluc_he.c
@@ -0,0 +1,818 @@
+/*
+ * wl he command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_he.c 627609 2016-03-25 21:00:45Z $
+ */
+
+#ifdef WIN32
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+
+#include <proto/802.11ah.h>
+
+#include <miniopt.h>
+
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifndef bzero
+#define bzero(mem, len) memset(mem, 0, len)
+#endif
+
+#ifdef _WIN32
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+#define NEED_STRTOULL
+#endif
+#if defined(_MSC_VER) && _MSC_VER > 1200
+#define strtoull _strtoui64
+#endif
+#endif /* _WIN32 */
+
+#define HE_CMD_HELP_STR \
+ "HE (802.11ax) protocol control commands\n\n" \
+ "\tUsage: wl he [command] [cmd options]\n\n" \
+ "Available commands and command options:\n" \
+ "\twl he enab [0|1] - query or enable/disable HE feature\n" \
+ "\twl he features [<features mask>] - query or enable/disable HE sub-features\n" \
+ "\twl he twt setup [<flow flags>] [<twt type] [<options>] <setup cmd> <flow id> - "\
+ "setup target wake time (TWT)\n" \
+ "\t\t<flow flags>:\n" \
+ "\t\t\t-b - Broadcast TWT\n" \
+ "\t\t\t-i - Implicit TWT\n" \
+ "\t\t\t-u - Unannounced\n" \
+ "\t\t\t-b - Trigger\n" \
+ "\t\t<twt type>:\n" \
+ "\t\t\t-y tsf - Absolute TSF\n" \
+ "\t\t\t-y offset - TSF offset\n" \
+ "\t\t<options>:\n" \
+ "\t\t\t-a <peer MAC address>\n" \
+ "\t\t\t-k <dialog token>\n" \
+ "\t\t\t-w <target wake time>\n" \
+ "\t\t\t-d <wake duration>\n" \
+ "\t\t\t-p <wake interval>\n" \
+ "\t\t<setup cmd>:\n" \
+ "\t\t\trequest\n" \
+ "\t\t\tsuggest\n" \
+ "\t\t\tdemand\n" \
+ "\twl he twt teardown [<flow flags>] [<options>] <flow id> - teardown flow\n" \
+ "\t\t<flow flags>:\n" \
+ "\t\t\t-b - Broadcast TWT\n" \
+ "\t\t<options>:\n" \
+ "\t\t\t-a <peer MAC address>\n" \
+ "\twl he twt info [<flow flags>] [<options>] <flow id> - request information\n" \
+ "\t\t<flow flags>:\n" \
+ "\t\t\t-r - response request\n" \
+ "\t\t<options>:\n" \
+ "\t\t\t-a <peer MAC address>\n" \
+ "\t\t\t-w <target wake time>\n"
+
+static cmd_func_t wl_he_cmd;
+
+/* wl he top level command list */
+static cmd_t wl_he_cmds[] = {
+ { "he", wl_he_cmd, WLC_GET_VAR, WLC_SET_VAR, HE_CMD_HELP_STR },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_he_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register HE commands */
+ wl_module_cmds_register(wl_he_cmds);
+}
+
+/* HE sub cmd */
+typedef struct sub_cmd sub_cmd_t;
+typedef int (sub_cmd_func_t)(void *wl, const cmd_t *cmd, const sub_cmd_t *sub, char **argv);
+struct sub_cmd {
+ char *name;
+ uint16 id; /* id for the dongle f/w switch/case */
+ uint16 type; /* base type of argument IOVT_XXXX */
+ sub_cmd_func_t *hdlr; /* cmd handler */
+};
+
+/* HE ioctl sub cmd handler functions */
+static sub_cmd_func_t wl_he_cmd_uint;
+static sub_cmd_func_t wl_he_cmd_twt;
+static sub_cmd_func_t wl_he_cmd_twt_setup;
+static sub_cmd_func_t wl_he_cmd_twt_teardown;
+static sub_cmd_func_t wl_he_cmd_twt_info;
+
+/* wl he sub cmd list */
+static const sub_cmd_t he_cmd_list[] = {
+ /* wl he enab [0|1] */
+ {"enab", WL_HE_CMD_ENAB, IOVT_UINT8, wl_he_cmd_uint},
+ /* wl he features [<features>] */
+ {"features", WL_HE_CMD_FEATURES, IOVT_UINT32, wl_he_cmd_uint},
+ /* wl he twt ... */
+ {"twt", 0, 0, wl_he_cmd_twt},
+ {NULL, 0, 0, NULL}
+};
+
+/* wl he twt sub cmd list */
+static const sub_cmd_t twt_cmd_list[] = {
+ /* wl he twt setup ... */
+ {"setup", WL_HE_CMD_TWT_SETUP, IOVT_BUFFER, wl_he_cmd_twt_setup},
+ /* wl he twt teardown ... */
+ {"teardown", WL_HE_CMD_TWT_TEARDOWN, IOVT_BUFFER, wl_he_cmd_twt_teardown},
+ /* wl he twt info ... */
+ {"info", WL_HE_CMD_TWT_INFO, IOVT_BUFFER, wl_he_cmd_twt_info},
+ {NULL, 0, 0, NULL}
+};
+
+#ifdef NEED_STRTOULL
+static unsigned long long int
+strtoull(const char *nptr, char **endptr, int base)
+{
+ unsigned long long int result;
+ unsigned char value;
+ bool minus;
+
+ minus = FALSE;
+
+ while (bcm_isspace(*nptr)) {
+ nptr++;
+ }
+
+ if (nptr[0] == '+') {
+ nptr++;
+ }
+ else if (nptr[0] == '-') {
+ minus = TRUE;
+ nptr++;
+ }
+
+ if (base == 0) {
+ if (nptr[0] == '0') {
+ if ((nptr[1] == 'x') || (nptr[1] == 'X')) {
+ base = 16;
+ nptr = &nptr[2];
+ } else {
+ base = 8;
+ nptr = &nptr[1];
+ }
+ } else {
+ base = 10;
+ }
+ } else if (base == 16 &&
+ (nptr[0] == '0') && ((nptr[1] == 'x') || (nptr[1] == 'X'))) {
+ nptr = &nptr[2];
+ }
+
+ result = 0;
+
+ while (bcm_isxdigit(*nptr) &&
+ (value = bcm_isdigit(*nptr) ? *nptr - '0' : bcm_toupper(*nptr) - 'A' + 10) <
+ (unsigned char)base) {
+ /* TODO: The strtoul() function should only convert the initial part
+ * of the string in nptr to an unsigned long int value according to
+ * the given base...so strtoull() should follow the same rule...
+ */
+ result = result * base + value;
+ nptr++;
+ }
+
+ if (minus) {
+ result = result * -1;
+ }
+
+ if (endptr) {
+ *endptr = DISCARD_QUAL(nptr, char);
+ }
+
+ return result;
+}
+#endif /* NEED_STRTOULL */
+
+/* wl he command */
+static int
+wl_he_cmd(void *wl, cmd_t *cmd, char **argv)
+{
+ const sub_cmd_t *sub = he_cmd_list;
+ char *he_query[2] = {"enab", NULL};
+ char *he_en[3] = {"enab", "1", NULL};
+ char *he_dis[3] = {"enab", "0", NULL};
+ int ret = BCME_USAGE_ERROR;
+
+ /* skip to cmd name after "he" */
+ argv++;
+
+ if (!*argv) {
+ /* query he "enab" state */
+ argv = he_query;
+ }
+ else if (*argv[0] == '1') {
+ argv = he_en;
+ }
+ else if (*argv[0] == '0') {
+ argv = he_dis;
+ }
+ else if (!strcmp(*argv, "-h") || !strcmp(*argv, "help")) {
+ /* help , or -h* */
+ return BCME_USAGE_ERROR;
+ }
+
+ while (sub->name != NULL) {
+ if (strcmp(sub->name, *argv) == 0) {
+ /* dispacth subcmd to the handler */
+ if (sub->hdlr != NULL) {
+ ret = sub->hdlr(wl, cmd, sub, ++argv);
+ }
+ return ret;
+ }
+ sub ++;
+ }
+
+ return BCME_IOCTL_ERROR;
+}
+
+typedef struct {
+ uint16 id;
+ uint16 len;
+ uint32 val;
+} he_xtlv_v32;
+
+
+static uint
+wl_he_iovt2len(uint iovt)
+{
+ switch (iovt) {
+ case IOVT_BOOL:
+ case IOVT_INT8:
+ case IOVT_UINT8:
+ return sizeof(uint8);
+ case IOVT_INT16:
+ case IOVT_UINT16:
+ return sizeof(uint16);
+ case IOVT_INT32:
+ case IOVT_UINT32:
+ return sizeof(uint32);
+ default:
+ /* ASSERT(0); */
+ return 0;
+ }
+}
+
+static bool
+wl_he_get_uint_cb(void *ctx, uint16 *id, uint16 *len)
+{
+ he_xtlv_v32 *v32 = ctx;
+
+ *id = v32->id;
+ *len = v32->len;
+
+ return FALSE;
+}
+
+static void
+wl_he_pack_uint_cb(void *ctx, uint16 id, uint16 len, uint8 *buf)
+{
+ he_xtlv_v32 *v32 = ctx;
+
+ BCM_REFERENCE(id);
+ BCM_REFERENCE(len);
+
+ v32->val = htod32(v32->val);
+
+ switch (v32->len) {
+ case sizeof(uint8):
+ *buf = (uint8)v32->val;
+ break;
+ case sizeof(uint16):
+ store16_ua(buf, (uint16)v32->val);
+ break;
+ case sizeof(uint32):
+ store16_ua(buf, v32->val);
+ break;
+ default:
+ /* ASSERT(0); */
+ break;
+ }
+}
+
+/* ******** generic uint8/uint16/uint32 ******** */
+static int
+wl_he_cmd_uint(void *wl, const cmd_t *cmd, const sub_cmd_t *sub, char **argv)
+{
+ int res = BCME_OK;
+
+ /* get */
+ if (*argv == NULL) {
+ bcm_xtlv_t mybuf;
+ uint8 *resp;
+
+ mybuf.id = sub->id;
+ mybuf.len = 0;
+
+ /* send getbuf iovar */
+ res = wlu_var_getbuf_sm(wl, cmd->name, &mybuf, sizeof(mybuf),
+ (void **)&resp);
+
+ /* check the response buff */
+ if (res == BCME_OK && resp != NULL) {
+ uint len = wl_he_iovt2len(sub->type);
+ uint32 v32;
+
+ switch (len) {
+ case sizeof(uint8):
+ v32 = *resp;
+ break;
+ case sizeof(uint16):
+ v32 = load16_ua(resp);
+ break;
+ case sizeof(uint32):
+ v32 = load32_ua(resp);
+ break;
+ default:
+ v32 = ~0;
+ break;
+ }
+ v32 = dtoh32(v32);
+ printf("%u\n", v32);
+ }
+ }
+ /* set */
+ else {
+ uint8 mybuf[32];
+ int mybuf_len = sizeof(mybuf);
+ he_xtlv_v32 v32;
+
+ v32.id = sub->id;
+ v32.len = wl_he_iovt2len(sub->type);
+ v32.val = atoi(*argv);
+
+ res = bcm_pack_xtlv_buf((void *)&v32, mybuf, sizeof(mybuf),
+ BCM_XTLV_OPTION_ALIGN32, wl_he_get_uint_cb, wl_he_pack_uint_cb,
+ &mybuf_len);
+ if (res != BCME_OK) {
+ goto fail;
+ }
+
+ res = wlu_var_setbuf(wl, cmd->name, mybuf, mybuf_len);
+ }
+
+ return res;
+
+fail:
+ fprintf(stderr, "error:%d\n", res);
+ return res;
+}
+
+/* wl he twt top level commend */
+static int
+wl_he_cmd_twt(void *wl, const cmd_t *cmd, const sub_cmd_t *sub, char **argv)
+{
+ const sub_cmd_t *sub2 = twt_cmd_list;
+ int res = BCME_OK;
+
+ BCM_REFERENCE(sub);
+
+ if (*argv == NULL) {
+ return BCME_USAGE_ERROR;
+ }
+
+ while (sub2->name != NULL) {
+ if (strcmp(sub2->name, *argv) == 0) {
+ /* dispacth subcmd to the handler */
+ if (sub2->hdlr != NULL) {
+ res = sub2->hdlr(wl, cmd, sub2, ++argv);
+ }
+ return res;
+ }
+ sub2 ++;
+ }
+
+ return BCME_USAGE_ERROR;
+}
+
+/* setup command name to value conversion */
+static struct {
+ const char *name;
+ uint8 val;
+} setup_cmd_val[] = {
+ {"request", TWT_SETUP_CMD_REQUEST_TWT},
+ {"suggest", TWT_SETUP_CMD_SUGGEST_TWT},
+ {"demand", TWT_SETUP_CMD_DEMAND_TWT}
+};
+
+#define WL_HE_TWT_CMD_INVAL 255
+
+static uint8
+wl_he_twt_cmd2val(const char *name)
+{
+ uint i;
+
+ for (i = 0; i < ARRAYSIZE(setup_cmd_val); i ++) {
+ if (strcmp(name, setup_cmd_val[i].name) == 0) {
+ return setup_cmd_val[i].val;
+ }
+ }
+
+ return WL_HE_TWT_CMD_INVAL;
+}
+
+/* target wake time (twt) type to value conversion */
+static struct {
+ const char *name;
+ uint8 val;
+} twt_type_val[] = {
+ {"tsf", WL_TWT_TIME_TYPE_BSS},
+ {"offset", WL_TWT_TIME_TYPE_OFFSET}
+};
+
+#define WL_HE_TWT_TYPE_INVAL 255
+
+static uint8
+wl_he_twt_type2val(const char *name)
+{
+ uint i;
+
+ for (i = 0; i < ARRAYSIZE(twt_type_val); i ++) {
+ if (strcmp(name, twt_type_val[i].name) == 0) {
+ return twt_type_val[i].val;
+ }
+ }
+
+ return WL_HE_TWT_TYPE_INVAL;
+}
+
+/* wl he twt setup command */
+static int
+wl_he_cmd_twt_setup(void *wl, const cmd_t *cmd, const sub_cmd_t *sub, char **argv)
+{
+ int res = BCME_OK;
+ uint8 mybuf[64];
+ uint8 *rem = mybuf;
+ uint16 rem_len = sizeof(mybuf);
+ wl_twt_setup_t val;
+ miniopt_t opt;
+ int opt_err;
+ int argc;
+ bool got_mandatory = FALSE;
+
+ BCM_REFERENCE(wl);
+
+ if (*argv == NULL) {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ bzero(&val, sizeof(val));
+
+ val.version = WL_TWT_SETUP_VER;
+ val.length = sizeof(val.version) + sizeof(val.length);
+
+ miniopt_init(&opt, __FUNCTION__, "biut", FALSE);
+
+ while ((opt_err = miniopt(&opt, argv)) != -1) {
+
+ if (opt_err == 1) {
+ res = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ /* flags and options */
+ if (!opt.positional) {
+
+ /* flags */
+
+ /* -b (broadcast) */
+ if (opt.opt == 'b') {
+ val.desc.flow_flags |= WL_TWT_FLOW_FLAG_BROADCAST;
+ }
+ /* -i (implicit) */
+ else if (opt.opt == 'i') {
+ val.desc.flow_flags |= WL_TWT_FLOW_FLAG_IMPLICIT;
+ }
+ /* -u (unannounced) */
+ else if (opt.opt == 'u') {
+ val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNANNOUNCED;
+ }
+ /* -t (trigger) */
+ else if (opt.opt == 't') {
+ val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER;
+ }
+
+ /* options */
+
+ /* -a peer_address */
+ else if (opt.opt == 'a') {
+ if (!wl_ether_atoe(opt.valstr, &val.peer)) {
+ fprintf(stderr, "Malformed TWT peer address '%s'\n",
+ opt.valstr);
+ res = BCME_BADARG;
+ goto fail;
+ }
+ }
+ /* -k dialog_token */
+ else if (opt.opt == 'k') {
+ val.dialog = (uint8)strtoul(opt.valstr, NULL, 0);
+ }
+ /* -y twt type */
+ else if (opt.opt == 'y') {
+ if ((val.desc.wake_type =
+ wl_he_twt_type2val(opt.valstr)) == WL_HE_TWT_TYPE_INVAL) {
+ fprintf(stderr, "Unrecognized TWT type '%s'\n",
+ opt.valstr);
+ res = BCME_BADARG;
+ goto fail;
+ }
+ }
+ /* -w target_wake_time (twt) */
+ else if (opt.opt == 'w') {
+ uint64 twt = strtoull(opt.valstr, NULL, 0);
+ val.desc.wake_time_h = htod32((uint32)(twt >> 32));
+ val.desc.wake_time_l = htod32((uint32)twt);
+ }
+ /* -d duration */
+ else if (opt.opt == 'd') {
+ val.desc.wake_dur = htod32(opt.uval);
+ }
+ /* -p interval */
+ else if (opt.opt == 'p') {
+ val.desc.wake_int = htod32(opt.uval);
+ }
+ else {
+ fprintf(stderr, "Unrecognized option '%s'\n", *argv);
+ res = BCME_BADARG;
+ goto fail;
+ }
+ }
+
+ /* positional/mandatory */
+ else {
+ if (argc < 2) {
+ res = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ /* setup_cmd */
+ if ((val.desc.setup_cmd =
+ wl_he_twt_cmd2val(*argv)) == WL_HE_TWT_CMD_INVAL) {
+ fprintf(stderr, "Unrecognized TWT Setup command '%s'\n", *argv);
+ res = BCME_BADARG;
+ goto fail;
+ }
+ argv++;
+
+ /* flow_id */
+ val.desc.flow_id = (uint8)strtoul(*argv, NULL, 0);
+ argv++;
+
+ got_mandatory = TRUE;
+
+ break;
+ }
+
+ argv += opt.consumed;
+ argc -= opt.consumed;
+ }
+
+ if (!got_mandatory) {
+ res = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ res = bcm_pack_xtlv_entry(&rem, &rem_len, sub->id,
+ sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
+ if (res != BCME_OK) {
+ goto fail;
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, mybuf, sizeof(mybuf) - rem_len);
+
+fail:
+ fprintf(stderr, "error:%d\n", res);
+ return res;
+}
+
+/* wl he twt teardown command */
+static int
+wl_he_cmd_twt_teardown(void *wl, const cmd_t *cmd, const sub_cmd_t *sub, char **argv)
+{
+ int res = BCME_OK;
+ uint8 mybuf[64];
+ uint8 *rem = mybuf;
+ uint16 rem_len = sizeof(mybuf);
+ wl_twt_teardown_t val;
+ miniopt_t opt;
+ int opt_err;
+ int argc;
+ bool got_mandatory = FALSE;
+
+ BCM_REFERENCE(wl);
+
+ if (*argv == NULL) {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ bzero(&val, sizeof(val));
+
+ val.version = WL_TWT_TEARDOWN_VER;
+ val.length = sizeof(val.version) + sizeof(val.length);
+
+ miniopt_init(&opt, __FUNCTION__, "b", FALSE);
+
+ while ((opt_err = miniopt(&opt, argv)) != -1) {
+
+ if (opt_err == 1) {
+ res = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ /* flags and options */
+ if (!opt.positional) {
+
+ /* flags */
+
+ /* -b (broadcast) */
+ if (opt.opt == 'b') {
+ val.flow_flags |= WL_TWT_FLOW_FLAG_BROADCAST;
+ }
+
+ /* options */
+
+ /* -a peer_address */
+ else if (opt.opt == 'a') {
+ if (!wl_ether_atoe(opt.valstr, &val.peer)) {
+ res = BCME_BADARG;
+ goto fail;
+ }
+ }
+ }
+
+ /* positionals */
+ else {
+ if (argc < 1) {
+ res = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ /* flow_id */
+ val.flow_id = (uint8)strtoul(*argv, NULL, 0);
+ argv++;
+
+ got_mandatory = TRUE;
+
+ break;
+ }
+
+ argv += opt.consumed;
+ }
+
+ if (!got_mandatory) {
+ res = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ res = bcm_pack_xtlv_entry(&rem, &rem_len, sub->id,
+ sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
+ if (res != BCME_OK) {
+ goto fail;
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, mybuf, sizeof(mybuf) - rem_len);
+
+fail:
+ fprintf(stderr, "error:%d\n", res);
+ return res;
+}
+
+/* wl he twt info command */
+static int
+wl_he_cmd_twt_info(void *wl, const cmd_t *cmd, const sub_cmd_t *sub, char **argv)
+{
+ int res = BCME_OK;
+ uint8 mybuf[64];
+ uint8 *rem = mybuf;
+ uint16 rem_len = sizeof(mybuf);
+ wl_twt_info_t val;
+ miniopt_t opt;
+ int opt_err;
+ int argc;
+ bool got_mandatory = FALSE;
+
+ BCM_REFERENCE(wl);
+
+ if (*argv == NULL) {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ bzero(&val, sizeof(val));
+
+ val.version = WL_TWT_INFO_VER;
+ val.length = sizeof(val.version) + sizeof(val.length);
+
+ miniopt_init(&opt, __FUNCTION__, "r", FALSE);
+
+ while ((opt_err = miniopt(&opt, argv)) != -1) {
+
+ if (opt_err == 1) {
+ res = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ /* flags and options */
+ if (!opt.positional) {
+
+ /* flags */
+
+ /* -r (response request) */
+ if (opt.opt == 'r') {
+ val.desc.flow_flags |= WL_TWT_INFO_FLAG_RESP_REQ;
+ }
+
+ /* options */
+
+ /* -a peer_address */
+ else if (opt.opt == 'a') {
+ if (!wl_ether_atoe(opt.valstr, &val.peer)) {
+ res = BCME_BADARG;
+ goto fail;
+ }
+ }
+ /* -w target_wake_time (twt) */
+ else if (opt.opt == 'w') {
+ uint64 twt = strtoull(opt.valstr, NULL, 0);
+ val.desc.next_twt_h = htod32((uint32)(twt >> 32));
+ val.desc.next_twt_l = htod32((uint32)twt);
+ }
+ }
+
+ /* positionals */
+ else {
+ if (argc < 1) {
+ res = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ /* flow_id */
+ val.desc.flow_id = (uint8)strtoul(*argv, NULL, 0);
+ argv++;
+
+ got_mandatory = TRUE;
+
+ break;
+ }
+
+ argv += opt.consumed;
+ }
+
+ if (!got_mandatory) {
+ res = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ res = bcm_pack_xtlv_entry(&rem, &rem_len, sub->id,
+ sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
+ if (res != BCME_OK) {
+ goto fail;
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, mybuf, sizeof(mybuf) - rem_len);
+
+fail:
+ fprintf(stderr, "error:%d\n", res);
+ return res;
+}
diff --git a/wl/src/wl/exe/wluc_ht.c b/wl/src/wl/exe/wluc_ht.c
new file mode 100644
index 0000000..62cc0a7
--- /dev/null
+++ b/wl/src/wl/exe/wluc_ht.c
@@ -0,0 +1,479 @@
+/*
+ * wl ht command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_ht.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#include <miniopt.h>
+
+static cmd_func_t wl_bw_cap;
+static cmd_func_t wl_nrate;
+static cmd_func_t wl_cur_mcsset;
+static cmd_func_t wl_txmcsset;
+static cmd_func_t wl_rxmcsset;
+
+static cmd_t wl_ht_cmds[] = {
+ { "bw_cap", wl_bw_cap, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/set the per-band bandwidth.\n"
+ "Usage: wl bw_cap <2g|5g> [<cap>]\n"
+ "\t2g|5g - Band: 2.4GHz or 5GHz respectively\n"
+ "cap:\n"
+ "\t0x1 - 20MHz\n"
+ "\t0x3 - 20/40MHz\n"
+ "\t0x7 - 20/40/80MHz\n"
+ "\t0xf - 20/40/80/160MHz\n"
+ "\t0xff - Unrestricted" },
+ { "cur_mcsset", wl_cur_mcsset, WLC_GET_VAR, -1,
+ "Get the current mcs set"
+ },
+ { "mimo_ps", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set mimo power save mode, (0=Dont send MIMO, 1=proceed MIMO with RTS, 2=N/A, "
+ "3=No restriction)"},
+ { "ofdm_txbw", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set ofdm txbw (2=20Mhz(lower), 3=20Mhz upper, 4(not allowed), 5=40Mhz dup)"},
+ { "cck_txbw", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set cck txbw (2=20Mhz(lower), 3=20Mhz upper)"},
+ { "frameburst", wl_int, WLC_GET_FAKEFRAG, WLC_SET_FAKEFRAG,
+ "Disable/Enable frameburst mode" },
+ { "nrate", wl_nrate, WLC_GET_VAR, WLC_SET_VAR,
+ "\"auto\" to clear a rate override, or:\n"
+ "-r legacy rate (CCK, OFDM)\n"
+ "-m HT MCS index\n"
+ "-s stf mode (0=SISO,1=CDD,2=STBC,3=SDM)\n"
+ "-w Override MCS only to support STA's with/without STBC capability"},
+ { "mimo_txbw", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set mimo txbw (2=20Mhz(lower), 3=20Mhz upper, 4=40Mhz, 4=40Mhz(DUP)\n"
+ "\t6=80Mhz(20LL), 7=80Mhz(20LU), 8=80Mhz(20UL), 9=80Mhz(20UU)\n"
+ "\t10=80Mhz(40L), 11=80Mhz(40U), 12=80Mhz)"},
+ { "txmcsset", wl_txmcsset, WLC_GET_VAR, -1, "get Transmit MCS rateset for 11N device"},
+ { "rxmcsset", wl_rxmcsset, WLC_GET_VAR, -1, "get Receive MCS rateset for 11N device"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* IOCtl version read from targeted driver */
+static int ioctl_version;
+
+
+/* module initialization */
+void
+wluc_ht_module_init(void)
+{
+ (void)g_swap;
+
+ /* get global ioctl_version */
+ ioctl_version = wl_get_ioctl_version();
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register ht commands */
+ wl_module_cmds_register(wl_ht_cmds);
+}
+
+/* Format a ratespec for "nrate" output
+ * Will handle both current wl_ratespec and legacy (ioctl_version 1) nrate ratespec
+ */
+static void
+wl_nrate_print(uint32 rspec)
+{
+ const char * rspec_auto = "auto";
+ uint encode, rate, txexp = 0, bw_val;
+ const char* stbc = "";
+ const char* ldpc = "";
+ const char* sgi = "";
+ const char* bw = "";
+ int stf;
+
+ if (rspec == 0) {
+ encode = WL_RSPEC_ENCODE_RATE;
+ } else if (ioctl_version == 1) {
+ encode = (rspec & OLD_NRATE_MCS_INUSE) ? WL_RSPEC_ENCODE_HT : WL_RSPEC_ENCODE_RATE;
+ stf = (int)((rspec & OLD_NRATE_STF_MASK) >> OLD_NRATE_STF_SHIFT);
+ rate = (rspec & OLD_NRATE_RATE_MASK);
+
+ if (rspec & OLD_NRATE_OVERRIDE) {
+ if (rspec & OLD_NRATE_OVERRIDE_MCS_ONLY)
+ rspec_auto = "fixed mcs only";
+ else
+ rspec_auto = "fixed";
+ }
+ } else {
+ int siso;
+ encode = (rspec & WL_RSPEC_ENCODING_MASK);
+ rate = (rspec & WL_RSPEC_RATE_MASK);
+ txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
+ stbc = ((rspec & WL_RSPEC_STBC) != 0) ? " stbc" : "";
+ ldpc = ((rspec & WL_RSPEC_LDPC) != 0) ? " ldpc" : "";
+ sgi = ((rspec & WL_RSPEC_SGI) != 0) ? " sgi" : "";
+ bw_val = (rspec & WL_RSPEC_BW_MASK);
+
+ if (bw_val == WL_RSPEC_BW_20MHZ) {
+ bw = "bw20";
+ } else if (bw_val == WL_RSPEC_BW_40MHZ) {
+ bw = "bw40";
+ } else if (bw_val == WL_RSPEC_BW_80MHZ) {
+ bw = "bw80";
+ } else if (bw_val == WL_RSPEC_BW_160MHZ) {
+ bw = "bw160";
+ }
+ else if (bw_val == WL_RSPEC_BW_10MHZ) {
+ bw = "bw10";
+ } else if (bw_val == WL_RSPEC_BW_5MHZ) {
+ bw = "bw5";
+ } else if (bw_val == WL_RSPEC_BW_2P5MHZ) {
+ bw = "bw2.5";
+ }
+
+ /* initialize stf mode to an illegal value and
+ * fix to a backward compatable value if possible
+ */
+ stf = -1;
+ /* for stf calculation, determine if the rate is single stream.
+ * Legacy rates WL_RSPEC_ENCODE_RATE are single stream, and
+ * HT rates for mcs 0-7 are single stream
+ */
+ siso = (encode == WL_RSPEC_ENCODE_RATE) ||
+ ((encode == WL_RSPEC_ENCODE_HT) && rate < 8);
+
+ /* calc a value for nrate stf mode */
+ if (txexp == 0) {
+ if ((rspec & WL_RSPEC_STBC) && siso) {
+ /* STF mode STBC */
+ stf = OLD_NRATE_STF_STBC;
+ } else {
+ /* STF mode SISO or SDM */
+ stf = (siso) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
+ }
+ } else if (txexp == 1 && siso) {
+ /* STF mode CDD */
+ stf = OLD_NRATE_STF_CDD;
+ }
+
+ if (rspec & WL_RSPEC_OVERRIDE_RATE) {
+ rspec_auto = "fixed";
+ }
+ }
+
+ if (encode == WL_RSPEC_ENCODE_RATE) {
+ if (rspec == 0) {
+ printf("auto\n");
+ } else {
+ printf("legacy rate %d%s Mbps stf mode %d %s\n",
+ rate/2, (rate % 2)?".5":"", stf, rspec_auto);
+ }
+ } else if (encode == WL_RSPEC_ENCODE_HT) {
+ printf("mcs index %d stf mode %d %s\n",
+ rate, stf, rspec_auto);
+ } else {
+ uint vht = (rspec & WL_RSPEC_VHT_MCS_MASK);
+ uint Nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
+ printf("vht mcs %d Nss %d Tx Exp %d %s%s%s%s %s\n",
+ vht, Nss, txexp, bw, stbc, ldpc, sgi, rspec_auto);
+ }
+}
+
+static int
+wl_nrate(void *wl, cmd_t *cmd, char **argv)
+{
+ miniopt_t to;
+ const char* fn_name = "wl_nrate";
+ bool mcs_set = FALSE, legacy_set = FALSE, stf_set = FALSE;
+ bool mcs_only = FALSE;
+ int err, opt_err;
+ uint32 val = 0;
+ uint32 rate = 0;
+ uint32 nrate = 0;
+ uint32 mcs = 0;
+ uint stf = 0; /* (0=SISO,1=CDD,2=STBC,3=SDM) */
+
+ /* toss the command name */
+ argv++;
+
+ if (!*argv) {
+ if (cmd->get < 0)
+ return -1;
+ if ((err = wlu_iovar_getint(wl, "nrate", (int*)&val)) < 0)
+ return err;
+
+ /* print a user readable line for the nrate rspec */
+ wl_nrate_print(val);
+
+ return 0;
+ }
+
+ /* check for a single argument of "auto" or -1 */
+ if ((!strcmp(argv[0], "auto") || !strcmp(argv[0], "-1")) &&
+ argv[1] == NULL) {
+ /* clear the nrate override */
+ err = wlu_iovar_setint(wl, "nrate", 0);
+ goto exit;
+ }
+
+ miniopt_init(&to, fn_name, "w", FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 'r') {
+ if (!to.good_int) {
+ /* special case check for "-r 5.5" */
+ if (!strcmp(to.valstr, "5.5")) {
+ to.val = 11;
+ } else {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a rate value\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ } else
+ to.val = to.val*2;
+ if (mcs_set) {
+ fprintf(stderr, "%s: cannot use -r and -m\n", fn_name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ legacy_set = TRUE;
+ rate = to.val;
+ }
+ if (to.opt == 'm') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for mcs\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (legacy_set) {
+ fprintf(stderr, "%s: cannot use -r and -m\n", fn_name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ mcs_set = TRUE;
+ mcs = to.val;
+ }
+ if (to.opt == 's') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for stf mode\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ stf = to.val;
+ stf_set = TRUE;
+ }
+ if (to.opt == 'w') {
+ mcs_only = TRUE;
+ }
+ }
+
+ if ((mcs_only && !mcs_set) || (mcs_only && (stf_set || legacy_set))) {
+ fprintf(stderr, "%s: can use -w only with -m\n", fn_name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!stf_set) {
+ if (legacy_set)
+ stf = OLD_NRATE_STF_SISO; /* SISO */
+ else if (mcs_set) {
+ if (GET_11N_MCS_NSS(mcs & OLD_NRATE_RATE_MASK) == 1)
+ stf = OLD_NRATE_STF_SISO; /* SISO */
+ else
+ stf = OLD_NRATE_STF_SDM; /* SDM */
+ }
+ }
+
+ if (!legacy_set && !mcs_set) {
+ fprintf(stderr, "%s: you need to set a legacy or mcs rate\n", fn_name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (ioctl_version == 1) {
+ if (legacy_set) {
+ nrate = rate;
+ } else {
+ nrate = mcs;
+ nrate |= OLD_NRATE_MCS_INUSE;
+ if (mcs_only) {
+ nrate |= OLD_NRATE_OVERRIDE_MCS_ONLY;
+ }
+ }
+
+ nrate |= (stf << OLD_NRATE_STF_SHIFT) & OLD_NRATE_STF_MASK;
+ } else {
+ uint tx_exp = 0;
+
+ /* set the ratespec encoding type and basic rate value */
+ if (legacy_set) {
+ nrate = WL_RSPEC_ENCODE_RATE; /* 11abg */
+ nrate |= rate;
+ } else {
+ nrate = WL_RSPEC_ENCODE_HT; /* 11n HT */
+ nrate |= mcs;
+ }
+
+ /* decode nrate stf value into tx expansion and STBC */
+ if (stf == OLD_NRATE_STF_CDD) {
+ tx_exp = 1;
+ } else if (stf == OLD_NRATE_STF_STBC) {
+ nrate |= WL_RSPEC_STBC;
+ }
+
+ nrate |= (tx_exp << WL_RSPEC_TXEXP_SHIFT);
+ }
+
+ err = wlu_iovar_setint(wl, "nrate", (int)nrate);
+
+exit:
+ return err;
+} /* wl_nrate */
+
+/* Set per-band bandwidth */
+static int wl_bw_cap(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ struct {
+ uint32 band;
+ uint32 bw_cap;
+ } param = { 0, 0 };
+ char *s = NULL;
+ void *ptr = NULL;
+
+ /* Skip the command name */
+ argv++;
+
+ if (*argv) {
+ if (!strcmp(*argv, "a") || !strcmp(*argv, "5") || !strcmp(*argv, "5g")) {
+ param.band = WLC_BAND_5G;
+ } else if (!strcmp(*argv, "b") || !strcmp(*argv, "2") || !strcmp(*argv, "2g")) {
+ param.band = WLC_BAND_2G;
+ } else {
+ fprintf(stderr,
+ "%s: invalid band %s\n",
+ cmd->name, *argv);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ argv++;
+
+ if (*argv) {
+ /* Optional 2nd arg is used to set the bandwidth cap */
+ s = NULL;
+
+ param.bw_cap = (uint32) strtoul(*argv, &s, 0);
+ if (s && *s != '\0') {
+ fprintf(stderr, "%s: invalid bandwidth '%s'\n",
+ cmd->name, *argv);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ } else {
+ fprintf(stderr, "%s: band unspecified\n", cmd->name);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (param.bw_cap == 0) {
+ if ((err = wlu_var_getbuf(wl, cmd->name, ¶m, sizeof(param), &ptr)) < 0)
+ return err;
+
+ printf("0x%x\n", *((uint32 *)ptr));
+ } else {
+ err = wlu_var_setbuf(wl, cmd->name, ¶m, sizeof(param));
+ }
+
+exit:
+ return err;
+}
+
+static int
+wl_cur_mcsset(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ memset(buf, 0, WLC_IOCTL_SMLEN);
+ ret = wlu_iovar_get(wl, "cur_mcsset", &buf[0], MCSSET_LEN);
+ if (ret < 0)
+ return ret;
+
+ wl_print_mcsset(buf);
+
+ return ret;
+}
+
+static int
+wl_txmcsset(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+
+ if ((err = wl_var_get(wl, cmd, argv)) < 0)
+ return err;
+ wl_print_mcsset(buf);
+
+ return err;
+}
+
+static int
+wl_rxmcsset(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+
+ if ((err = wl_var_get(wl, cmd, argv)) < 0)
+ return err;
+
+ wl_print_mcsset(buf);
+
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_interfere.c b/wl/src/wl/exe/wluc_interfere.c
new file mode 100644
index 0000000..ccf15ef
--- /dev/null
+++ b/wl/src/wl/exe/wluc_interfere.c
@@ -0,0 +1,103 @@
+/*
+ * wl interfere command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_interfere.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_itfr_get_stats;
+
+static cmd_t wl_interfere_cmds[] = {
+ { "itfr_get_stats", wl_itfr_get_stats, WLC_GET_VAR, -1,
+ "get interference source information"
+ },
+ { "itfr_enab", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set STA interference detection mode(STA only)\n"
+ "\t 0 - disable\n"
+ "\t 1 - enable maual detection\n"
+ "\t 2 - enable auto detection"
+ },
+ { "itfr_detect", wl_var_void, -1, WLC_SET_VAR,
+ "issue an interference detection request"
+ },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_interfere_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register interfere commands */
+ wl_module_cmds_register(wl_interfere_cmds);
+}
+
+static int
+wl_itfr_get_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ interference_source_rep_t *iftr_stats = NULL;
+ const char *iftr_source[] = {"none", "wireless phone", "wireless video camera",
+ "microwave oven", "wireless baby monitor", "bluetooth device",
+ "wireless video camera or baby monitor", "bluetooth or baby monitor",
+ "video camera or phone", "unidentified"}; /* sync with interference_source_t */
+
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, (void*)&iftr_stats)) < 0)
+ return err;
+
+ if (iftr_stats->flags & ITFR_NOISY_ENVIRONMENT)
+ printf("Feature is stopped due to noisy environment\n");
+ else
+ printf("Interference %s detected. last interference at timestamp %d: "
+ "source is %s on %s channel\n",
+ (iftr_stats->flags & ITFR_INTERFERENCED) ? "is" : "is not",
+ iftr_stats->timestamp, iftr_source[iftr_stats->source],
+ (iftr_stats->flags & ITFR_HOME_CHANNEL) ? "home" : "non-home");
+
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_keep_alive.c b/wl/src/wl/exe/wluc_keep_alive.c
new file mode 100644
index 0000000..31633fc
--- /dev/null
+++ b/wl/src/wl/exe/wluc_keep_alive.c
@@ -0,0 +1,179 @@
+/*
+ * wl keep_alive command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_keep_alive.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_keep_alive;
+
+static cmd_t wl_keep_alive_cmds[] = {
+ {"mkeep_alive", wl_mkeep_alive, WLC_GET_VAR, WLC_SET_VAR,
+ "Send specified \"mkeep-alive\" packet periodically.\n"
+ "\tUsage: wl mkeep_alive <index0-3> <period> <packet>\n"
+ "\t\tindex: 0 - 3.\n"
+ "\t\tperiod: Re-transmission period in milli-seconds. 0 to disable packet transmits.\n"
+ "\t\tpacket: Hex packet contents to transmit. The packet contents should include "
+ "the entire ethernet packet (ethernet header, IP header, UDP header, and UDP "
+ "payload) specified in network byte order. If no packet is specified, a nulldata frame "
+ "will be sent instead.\n"
+ "\n\te.g. Send keep alive packet every 30 seconds using id-1:\n"
+ "\twl mkeep_alive 1 30000 0x0014a54b164f000f66f45b7e08004500001e000040004011c"
+ "52a0a8830700a88302513c413c4000a00000a0d" },
+ {"keep_alive", wl_keep_alive, -1, -1,
+ "Send specified \"keep-alive\" packet periodically.\n"
+ "\tUsage: wl keep_alive <period> <packet>\n"
+ "\t\tperiod: Re-transmission period in milli-seconds. 0 to disable packet transmits.\n"
+ "\t\tpacket: Hex packet contents to transmit. The packet contents should include "
+ "the entire ethernet packet (ethernet header, IP header, UDP header, and UDP "
+ "payload) specified in network byte order.\n"
+ "\n\te.g. Send keep alive packet every 30 seconds:\n"
+ "\twl keep_alive 30000 0x0014a54b164f000f66f45b7e08004500001e000040004011c"
+ "52a0a8830700a88302513c413c4000a00000a0d" },
+ {"wowl_keepalive", wl_mkeep_alive, WLC_GET_VAR, WLC_SET_VAR,
+ "Send specified keep alive packet periodically in w mode.\n"
+ "\tUsage: wl wowl_keepalive <index0-1> <period> <packet>\n"
+ "\t\tindex: 0 - 1.\n"
+ "\t\tperiod: Re-transmission period in milli-seconds. 0 to disable packet transmits.\n"
+ "\t\tpacket: Hex packet contents to transmit. The packet contents should include "
+ "the entire ethernet packet (ethernet header, IP header, UDP header, and UDP "
+ "payload) specified in network byte order.\n"
+ "\n\te.g. Send keep alive packet every 30 seconds using id-1:\n"
+ "\twl wowl_keepalive 1 30000 0x0014a54b164f000f66f45b7e08004500001e000040004011c"
+ "52a0a8830700a88302513c413c4000a00000a0d\n" },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_keep_alive_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register keep_alive commands */
+ wl_module_cmds_register(wl_keep_alive_cmds);
+}
+
+/* Send a periodic keep-alive packet at the specificed interval. */
+static int
+wl_keep_alive(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *str;
+ wl_keep_alive_pkt_t keep_alive_pkt;
+ wl_keep_alive_pkt_t *keep_alive_pktp;
+ int buf_len;
+ int str_len;
+ int i;
+ int rc;
+ void *ptr = NULL;
+
+ memset(&keep_alive_pkt, 0, sizeof(keep_alive_pkt));
+
+ if (*++argv == NULL) {
+ /*
+ ** Get current keep-alive status.
+ */
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+
+ keep_alive_pktp = (wl_keep_alive_pkt_t *) ptr;
+
+ printf("Period (msec) :%d\n"
+ "Length :%d\n"
+ "Packet :0x",
+ dtoh32(keep_alive_pktp->period_msec),
+ dtoh16(keep_alive_pktp->len_bytes));
+
+ for (i = 0; i < keep_alive_pktp->len_bytes; i++)
+ printf("%02x", keep_alive_pktp->data[i]);
+
+ printf("\n");
+ }
+ else {
+ /*
+ ** Set keep-alive attributes.
+ */
+
+ str = "keep_alive";
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[ str_len ] = '\0';
+
+ keep_alive_pktp = (wl_keep_alive_pkt_t *) (buf + str_len + 1);
+ keep_alive_pkt.period_msec = htod32(strtoul(*argv, NULL, 0));
+ buf_len = str_len + 1;
+
+
+ if (keep_alive_pkt.period_msec == 0) {
+ keep_alive_pkt.len_bytes = 0;
+
+ buf_len += sizeof(wl_keep_alive_pkt_t);
+ }
+ else {
+ if (NULL != *++argv) {
+ keep_alive_pkt.len_bytes =
+ htod16(wl_pattern_atoh(*argv, (char *) keep_alive_pktp->data));
+ buf_len += (WL_KEEP_ALIVE_FIXED_LEN + keep_alive_pkt.len_bytes);
+ }
+ else {
+ keep_alive_pkt.len_bytes = 0;
+ buf_len += WL_KEEP_ALIVE_FIXED_LEN;
+ }
+ }
+
+ /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
+ * then memcpy'ed into buffer (keep_alive_pktp) since there is no
+ * guarantee that the buffer is properly aligned.
+ */
+ memcpy((char *)keep_alive_pktp, &keep_alive_pkt, WL_KEEP_ALIVE_FIXED_LEN);
+
+
+ rc = wlu_set(wl,
+ WLC_SET_VAR,
+ buf,
+ buf_len);
+
+ }
+
+ return (rc);
+}
diff --git a/wl/src/wl/exe/wluc_keymgmt.c b/wl/src/wl/exe/wluc_keymgmt.c
new file mode 100644
index 0000000..4523a1e
--- /dev/null
+++ b/wl/src/wl/exe/wluc_keymgmt.c
@@ -0,0 +1,420 @@
+/*
+ * wl keymgmt command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_keymgmt.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_wepstatus;
+static cmd_func_t wl_addwep, wl_rmwep;
+static cmd_func_t wl_primary_key;
+static cmd_func_t wl_keys, wl_wsec_test;
+static cmd_func_t wl_tsc;
+
+static cmd_t wl_keymgmt_cmds[] = {
+ { "wepstatus", wl_wepstatus, -1, -1, /* Deprecated. Use "wsec" */
+ "Set or Get WEP status\n"
+ "\twepstatus [on|off]" },
+ { "primary_key", wl_primary_key, WLC_GET_KEY_PRIMARY, WLC_SET_KEY_PRIMARY,
+ "Set or get index of primary key" },
+ { "addwep", wl_addwep, -1, WLC_SET_KEY,
+ "Set an encryption key. The key must be 5, 13 or 16 bytes long, or\n"
+ "\t10, 26, 32, or 64 hex digits long. The encryption algorithm is\n"
+ "\tautomatically selected based on the key size. keytype is accepted\n"
+ "\tonly when key length is 16 bytes/32 hex digits and specifies\n"
+ "\twhether AES-OCB or AES-CCM encryption is used. Default is ccm.\n"
+ "\tWAPI is selected if key len is 32 and arguments contain wapi.\n"
+ "\taddwep <keyindex> <keydata> [ocb | ccm | wapi] [notx] [xx:xx:xx:xx:xx:xx]" },
+ { "rmwep", wl_rmwep, -1, WLC_SET_KEY,
+ "Remove the encryption key at the specified key index." },
+ { "keys", wl_keys, WLC_GET_KEY, -1,
+ "Prints a list of the current WEP keys" },
+ { "tsc", wl_tsc, WLC_GET_KEY_SEQ, -1,
+ "Print Tx Sequence Couter for key at specified key index." },
+ { "wsec_test", wl_wsec_test, -1, WLC_SET_WSEC_TEST,
+ "Generate wsec errors\n"
+ "\twsec_test <test_type> <keyindex|xx:xx:xx:xx:xx:xx>\n"
+ "\ttype \'wl wsec_test ?\' for test_types" },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_keymgmt_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register keymgmt commands */
+ wl_module_cmds_register(wl_keymgmt_cmds);
+}
+
+
+static int
+wl_wepstatus(void *wl, cmd_t *cmd, char **argv)
+{
+ int val, error;
+ const char *name = "wsec";
+ int wsec;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!*++argv) {
+ if ((error = wlu_iovar_getint(wl, name, &val) < 0))
+ return error;
+
+ printf("%d\n", val);
+ return 0;
+ } else {
+ val = atoi(*argv);
+ if ((error = wlu_iovar_getint(wl, name, &wsec) < 0))
+ return error;
+
+ if (val)
+ wsec |= WEP_ENABLED;
+ else
+ wsec &= ~WEP_ENABLED;
+
+ return wlu_iovar_setint(wl, name, wsec);
+ }
+}
+
+static int
+wl_primary_key(void *wl, cmd_t *cmd, char **argv)
+{
+ int i, val, ret = 0;
+
+ if (!*++argv) {
+ i = 0;
+ do {
+ val = htod32(i);
+ if ((ret = wlu_get(wl, cmd->get, &val, sizeof(val))) < 0) {
+ return ret;
+ }
+ if (dtoh32(val)) {
+ printf("Key %d is primary\n", i);
+ return 0;
+ }
+ } while (++i < DOT11_MAX_DEFAULT_KEYS);
+ printf("No primary key set\n");
+
+ } else {
+ val = htod32(atoi(*argv));
+ ret = wlu_set(wl, cmd->set, &val, sizeof(val));
+ }
+ return ret;
+}
+
+static int
+wl_addwep(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_wsec_key_t key;
+ int bsscfg_idx = 0;
+ int consumed;
+ int error;
+
+ memset(&key, 0, sizeof(key));
+
+ argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((error = wl_cfg_option(argv, "addwep", &bsscfg_idx, &consumed)) != 0)
+ return error;
+
+ argv += consumed;
+
+ /* GET operation not allowed */
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+
+ key.index = atoi(*argv++);
+
+ if (!*argv) {
+ fprintf(stderr, "No key specified\n");
+ return BCME_USAGE_ERROR;
+ }
+ if (parse_wep(argv, &key, TRUE))
+ return BCME_BADARG;
+
+ key.index = htod32(key.index);
+ key.len = htod32(key.len);
+ key.algo = htod32(key.algo);
+ key.flags = htod32(key.flags);
+
+ if (consumed == 0) {
+ error = wlu_set(wl, cmd->set, &key, sizeof(key));
+ } else {
+ error = wlu_bssiovar_setbuf(wl, "wsec_key", bsscfg_idx,
+ &key, sizeof(key), buf, WLC_IOCTL_MAXLEN);
+ }
+
+ return error;
+}
+
+static int
+wl_rmwep(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_wsec_key_t key;
+ int bsscfg_idx = 0;
+ int consumed;
+ int error;
+
+ memset(&key, 0, sizeof(key));
+
+ argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((error = wl_cfg_option(argv, "rmwep", &bsscfg_idx, &consumed)) != 0)
+ return error;
+
+ argv += consumed;
+
+ /* GET operation not allowed */
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+
+ key.index = htod32(atoi(*argv++));
+
+ if (*argv) {
+ if (!(wl_ether_atoe(*argv, &key.ea)))
+ return BCME_USAGE_ERROR;
+ }
+
+ if (consumed == 0) {
+ error = wlu_set(wl, cmd->set, &key, sizeof(key));
+ } else {
+ error = wlu_var_setbuf(wl, "wsec_key", &key, sizeof(key));
+ }
+
+ return error;
+}
+
+static struct {
+ uint value;
+ const char *string;
+} wsec_test[] = {
+ {WSEC_GEN_MIC_ERROR, "mic_error"},
+ {WSEC_GEN_REPLAY, "replay"},
+ {WSEC_GEN_ICV_ERROR, "icv_error"},
+ {WSEC_GEN_MFP_ACT_ERROR, "act_error"},
+ {WSEC_GEN_MFP_DISASSOC_ERROR, "disassoc_error"},
+ {WSEC_GEN_MFP_DEAUTH_ERROR, "deauth_error"},
+ {0, NULL}
+};
+
+
+static int
+wl_wsec_test(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_wsec_key_t *key;
+ int i, len;
+ char *endptr = NULL, *wsec_buf = NULL;
+ uint32 val, last_val;
+ int err = 0;
+
+ if (!*++argv) {
+ err = BCME_USAGE_ERROR;
+ goto usage;
+ }
+
+ val = strtol(*argv, &endptr, 0);
+ if (endptr == *argv) {
+ /* the value string was not parsed by strtol */
+ for (i = 0; wsec_test[i].value; i++)
+ if (stricmp(wsec_test[i].string, *argv) == 0) {
+ val = wsec_test[i].value;
+ break;
+ }
+ if (wsec_test[i].value == 0) {
+ err = BCME_BADARG;
+ goto usage;
+ }
+ }
+ ++argv;
+
+ switch (val) {
+ case WSEC_GEN_REPLAY:
+ case WSEC_GEN_MIC_ERROR:
+ case WSEC_GEN_ICV_ERROR:
+ case WSEC_GEN_MFP_ACT_ERROR:
+ case WSEC_GEN_MFP_DISASSOC_ERROR:
+ case WSEC_GEN_MFP_DEAUTH_ERROR:
+ if (!*argv) {
+ fprintf(stderr, "insufficient arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+ len = sizeof(wl_wsec_key_t) + 4;
+ wsec_buf = malloc(len);
+ if (wsec_buf == NULL) {
+ fprintf(stderr, "Error allocating memory failed for wsec_buf");
+ return BCME_NOMEM;
+ }
+ *(uint32 *)wsec_buf = htod32(val);
+ key = (wl_wsec_key_t *)&wsec_buf[4];
+ memset(key, 0, sizeof(wl_wsec_key_t));
+ /* If it doesn't look like an ether addr, suppose it's a key index */
+ if (!(wl_ether_atoe(*argv, &key->ea))) {
+ memset(&key->ea, 0, ETHER_ADDR_LEN);
+ key->index = htod32(atoi(*argv));
+ }
+ break;
+ default:
+ goto usage;
+ }
+
+ err = wlu_set(wl, cmd->set, wsec_buf, len);
+ free(wsec_buf);
+ goto exit;
+
+usage:
+ fprintf(stderr, "wsec test_type may be a number or name from the following set:");
+ last_val = 0xffffffff;
+ for (i = 0; (val = wsec_test[i].value); i++) {
+ if (val != last_val)
+ fprintf(stderr, "\n0x%04x %s", val, wsec_test[i].string);
+ else
+ fprintf(stderr, ", %s", wsec_test[i].string);
+ last_val = val;
+ }
+ fprintf(stderr, "\n");
+
+exit:
+ return err;
+}
+
+static int
+wl_keys(void *wl, cmd_t *cmd, char **argv)
+{
+ uint i, j;
+ union {
+ int index;
+ wl_wsec_key_t key;
+ } u;
+ int wep_is_on = 0;
+ const char *addr;
+ int ret = BCME_OK;
+
+ UNUSED_PARAMETER(argv);
+
+ if (wlu_iovar_getint(wl, "wsec", &wep_is_on) < 0)
+ fprintf(stderr, "Could not query wsec status.\n");
+
+ for (i = 0; i < 256; i++) {
+ memset(&u, 0, sizeof(u));
+ u.index = htod32(i);
+ ret = wlu_get(wl, cmd->get, &u, sizeof(u));
+ if (ret == BCME_IOCTL_ERROR) {
+ int bcmerr;
+ if (wlu_iovar_getint(wl, "bcmerror", &bcmerr) >= 0 &&
+ (bcmerr == BCME_BADKEYIDX)) {
+ ret = BCME_OK;
+ }
+ }
+
+ if (ret != BCME_OK)
+ break;
+
+ /* ignore empty keys */
+ if (dtoh32(u.key.algo) == CRYPTO_ALGO_OFF || (u.key.len == 0))
+ continue;
+
+ if (ETHER_ISNULLADDR(&u.key.ea))
+ addr = "(default)";
+ else
+ addr = wl_ether_etoa(&u.key.ea);
+
+ printf("%3d: %-17s Key %d: %s ", i, addr, dtoh32(u.key.index),
+ bcm_crypto_algo_name(dtoh32(u.key.algo)));
+
+ if (wep_is_on && dtoh32(u.key.flags) & WL_PRIMARY_KEY)
+ printf("*");
+ printf("\t");
+
+ if (dtoh32(u.key.len) == 0)
+ printf("No key present");
+ else {
+ if (dtoh32(u.key.flags) & WL_SOFT_KEY)
+ printf("soft ");
+ printf("len %d, data 0x", dtoh32(u.key.len));
+ for (j = 0; j < dtoh32(u.key.len); j++)
+ printf("%02X", u.key.data[j]);
+
+ for (j = 0; j < dtoh32(u.key.len); j++)
+ if (!isprint(u.key.data[j]))
+ break;
+ if (j == dtoh32(u.key.len))
+ printf(" (%.*s)", (int)dtoh32(u.key.len), u.key.data);
+
+ }
+
+ printf("\n");
+ }
+
+ return ret;
+}
+
+static int
+wl_tsc(void *wl, cmd_t *cmd, char **argv)
+{
+ union {
+ int32 index;
+ uint8 tsc[DOT11_WPA_KEY_RSC_LEN];
+ } u;
+ uint32 hi, lo;
+ int idx, ret;
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ idx = atoi(*argv);
+ if (idx < 0) {
+ fprintf(stderr, "Key index %d out of range. Should be positive.\n", idx);
+ return BCME_BADARG;
+ }
+ u.index = htod32(idx);
+ if ((ret = wlu_get(wl, cmd->get, &u, sizeof(u))) < 0)
+ return ret;
+ lo = u.tsc[0] | (u.tsc[1] << 8) | (u.tsc[2] << 16) | (u.tsc[3] << 24);
+ hi = u.tsc[4] | (u.tsc[5] << 8) | (u.tsc[6] << 16) | (u.tsc[7] << 24);
+
+ printf("Key %d TSC: 0x%04x:%08x\n", idx, hi, lo);
+ return 0;
+}
diff --git a/wl/src/wl/exe/wluc_led.c b/wl/src/wl/exe/wluc_led.c
new file mode 100644
index 0000000..ccfd697
--- /dev/null
+++ b/wl/src/wl/exe/wluc_led.c
@@ -0,0 +1,153 @@
+/*
+ * wl led command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_led.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_ledbh;
+static cmd_func_t wl_led_blink_sync;
+
+static cmd_t wl_led_cmds[] = {
+ { "ledbh", wl_ledbh, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get led behavior\n"
+ "\tUsage: wl ledbh [0-3] [0-15]"},
+ { "led_blink_sync", wl_led_blink_sync, WLC_GET_VAR, WLC_SET_VAR, "set/get led_blink_sync\n"
+ "\tUsage: wl led_blink_sync [0-3] [0/1]"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_led_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register led commands */
+ wl_module_cmds_register(wl_led_cmds);
+}
+
+static int
+wl_ledbh(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_led_info_t led;
+ void *ptr = NULL;
+
+ memset(&led, 0, sizeof(wl_led_info_t));
+ if (*++argv == NULL) {
+ printf("Usage: ledbh [led#] [behavior#]\n");
+ return BCME_USAGE_ERROR;
+ }
+ led.index = (int)strtoul(*argv, NULL, 10);
+
+ if (led.index >= LED_MAX_INDEX) {
+ printf("only %d led supported\n", LED_MAX_INDEX);
+ return BCME_BADARG;
+ }
+
+ if (*++argv) { /* set */
+ /* Read the original back so we don't toggle the activehi */
+ if ((err = wlu_var_getbuf(wl, cmd->name, (void*)&led,
+ sizeof(wl_led_info_t), &ptr)) < 0) {
+ printf("wl_ledbh: fail to get. code %x\n", err);
+ }
+ led.behavior = (int)strtoul(*argv, NULL, 10);
+ led.activehi = ((wl_led_info_t*)ptr)->activehi;
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, (void*)&led,
+ sizeof(wl_led_info_t))) < 0) {
+ printf("wl_ledbh: fail to set\n");
+ }
+ } else { /* get */
+ wl_led_info_t *ledo;
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, (void*)&led,
+ sizeof(wl_led_info_t), &ptr)) < 0) {
+ printf("wl_ledbh: fail to get\n");
+ }
+ ledo = (wl_led_info_t*)ptr;
+
+ printf("led %d behavior %d\n", ledo->index, ledo->behavior);
+ }
+
+ return err;
+}
+
+static int
+wl_led_blink_sync(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc;
+ int err = 0;
+ int in_arg[2];
+ void *ptr = NULL;
+ char *endptr;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc > 3 || argc < 2)
+ return BCME_USAGE_ERROR;
+
+ in_arg[0] = htod32((uint32)(strtoul(argv[1], &endptr, 0)));
+
+ if (in_arg[0] > 3) {
+ printf("only 4 led supported\n");
+ return BCME_BADARG;
+ }
+
+ if (argc == 2) {
+ err = wlu_var_getbuf(wl, cmd->name, (void*)in_arg, sizeof(int), &ptr);
+ if (err < 0)
+ return err;
+ printf("led%d, blink_sync is %s\n", in_arg[0],
+ (dtoh32(*(int*)ptr) != 0) ? "TRUE" : "FALSE");
+ }
+ else if (argc == 3) {
+ in_arg[1] = htod32((uint32)(strtoul(argv[2], &endptr, 0)));
+ err = wlu_var_setbuf(wl, cmd->name, in_arg, sizeof(in_arg));
+ }
+
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_lq.c b/wl/src/wl/exe/wluc_lq.c
new file mode 100644
index 0000000..ff493ca
--- /dev/null
+++ b/wl/src/wl/exe/wluc_lq.c
@@ -0,0 +1,550 @@
+/*
+ * wl lq command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_lq.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_rssi_event, wl_chan_qual_event;
+static cmd_func_t wl_chanim_state, wl_chanim_mode;
+static cmd_func_t wl_dump_lq;
+static cmd_func_t wl_monitor_lq;
+static cmd_func_t wl_chanim_acs_record;
+static cmd_func_t wl_chanim_stats;
+static int _wl_dump_lq(void *wl);
+
+static cmd_t wl_lq_cmds[] = {
+ { "rssi_event", wl_rssi_event, WLC_GET_VAR, WLC_SET_VAR,
+ "Set parameters associated with RSSI event notification\n"
+ "\tusage: wl rssi_event <rate_limit> <rssi_levels>\n"
+ "\trate_limit: Number of events posted to application will be limited"
+ " to 1 per this rate limit. Set to 0 to disable rate limit.\n"
+ "\trssi_levels: Variable number of RSSI levels (maximum 8) "
+ " in increasing order (e.g. -85 -70 -60). An event will be posted"
+ " each time the RSSI of received beacons/packets crosses a level."},
+ { "chq_event", wl_chan_qual_event, WLC_GET_VAR, WLC_SET_VAR,
+ "Set parameters associated with channel quality event notification\n"
+ "\tusage: wl chq_event <rate_limit> <cca_levels> <nf_levels> <nf_lte_levels>\n"
+ "\trate_limit: Number of events posted to application will be limited"
+ " to 1 per this rate limit. Set to 0 to disable rate limit.\n"
+ "\tcsa/nf/nf_lte levels: Variable number of threshold levels (maximum 8)"
+ " in pairs of hi-to-low/lo-to-hi, and in increasing order (e.g. -90 -85 -80)."
+ " A 0 0 pair terminates level array for one metric."
+ " An event will be posted whenever a threshold is being crossed."},
+ {"chanim_state", wl_chanim_state, WLC_GET_VAR, -1,
+ "get channel interference state\n"
+ "\tUsage: wl chanim_state channel\n"
+ "\tValid channels: 1 - 14\n"
+ "\treturns: 0 - Acceptable; 1 - Severe"
+ },
+ {"chanim_mode", wl_chanim_mode, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set channel interference measure (chanim) mode\n"
+ "\tUsage: wl chanim_mode <value>\n"
+ "\tvalue: 0 - disabled; 1 - detection only; 2 - detection and avoidance"
+ },
+ {"chanim_acs_record", wl_chanim_acs_record, WLC_GET_VAR, -1,
+ "get the auto channel scan record. \n"
+ "\t Usage: wl acs_record"
+ },
+ {"chanim_stats", wl_chanim_stats, WLC_GET_VAR, -1,
+ "get chanim stats \n"
+ "\t Usage: wl chanim_stats"
+ },
+ { "monitor_lq", wl_monitor_lq, WLC_GET_VAR, WLC_SET_VAR,
+ "Start/Stop monitoring link quality metrics - RSSI and SNR\n"
+ "\tUsage: wl monitor_lq <0: turn off / 1: turn on"},
+ { "monitor_lq_status", wl_dump_lq, WLC_GET_VAR, -1 /* Set not reqd */,
+ "Returns averaged link quality metrics - RSSI and SNR values"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_lq_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register lq commands */
+ wl_module_cmds_register(wl_lq_cmds);
+}
+
+static int
+wl_chan_qual_event(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ const char *CHAN_QUAL_NAME[WL_CHAN_QUAL_TOTAL] = {" CCA", " NF", "NF_LTE"};
+
+ if (!*++argv) {
+ /* get */
+ void *ptr = NULL;
+ wl_chan_qual_event_t chq;
+ uint i, j;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ memcpy(&chq, ptr, sizeof(chq));
+ chq.rate_limit_msec = dtoh32(chq.rate_limit_msec);
+
+ printf("rate per %dms\n", chq.rate_limit_msec);
+ for (i = 0; i < WL_CHAN_QUAL_TOTAL; i++) {
+ printf("%s[%d]:", CHAN_QUAL_NAME[i], chq.metric[i].id);
+ for (j = 0; (j < chq.metric[i].num_levels) &&
+ (j < MAX_CHAN_QUAL_LEVELS); j++) {
+ printf(" (%d, %d)", chq.metric[i].htol[j], chq.metric[i].ltoh[j]);
+ }
+ printf("\n");
+ }
+ } else {
+ /* set */
+ wl_chan_qual_event_t chq;
+ uint i;
+
+ memset(&chq, 0, sizeof(wl_chan_qual_event_t));
+ chq.rate_limit_msec = atoi(*argv++);
+ chq.rate_limit_msec = htod32(chq.rate_limit_msec);
+ chq.num_metrics = htod16(WL_CHAN_QUAL_TOTAL);
+
+ for (i = 0; i < WL_CHAN_QUAL_TOTAL; i++) {
+ chq.metric[i].id = i;
+ while (argv[0] && argv[1]) {
+ int16 htol, ltoh;
+ htol = htod16(atoi(*argv++));
+ ltoh = htod16(atoi(*argv++));
+
+ /* double zeros terminate one metric */
+ if ((htol == 0) && (ltoh == 0))
+ break;
+
+ /* make sure that ltoh >= htol */
+ if (ltoh < htol)
+ return -1;
+
+ /* ignore extra thresholds */
+ if (chq.metric[i].num_levels >= MAX_CHAN_QUAL_LEVELS)
+ continue;
+
+ chq.metric[i].htol[chq.metric[i].num_levels] = htol;
+ chq.metric[i].ltoh[chq.metric[i].num_levels] = ltoh;
+
+ /* all metric threshold levels must be in increasing order */
+ if (chq.metric[i].num_levels > 0) {
+ if ((chq.metric[i].htol[chq.metric[i].num_levels] <=
+ chq.metric[i].htol[chq.metric[i].num_levels - 1]) ||
+ (chq.metric[i].ltoh[chq.metric[i].num_levels] <=
+ chq.metric[i].ltoh[chq.metric[i].num_levels - 1])) {
+ return -1;
+ }
+ }
+
+ (chq.metric[i].num_levels)++;
+ }
+ }
+
+ if (*argv) {
+ /* too many parameters */
+ return -1;
+ }
+
+ ret = wlu_var_setbuf(wl, cmd->name, &chq, sizeof(chq));
+ }
+ return ret;
+}
+
+static int
+wl_rssi_event(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+
+ if (!*++argv) {
+ /* get */
+ void *ptr = NULL;
+ wl_rssi_event_t rssi;
+ uint i;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ memcpy(&rssi, ptr, sizeof(rssi));
+ rssi.rate_limit_msec = dtoh32(rssi.rate_limit_msec);
+
+ printf("%d", rssi.rate_limit_msec);
+ for (i = 0; i < rssi.num_rssi_levels; i++) {
+ printf(" %d", rssi.rssi_levels[i]);
+ }
+ printf("\n");
+ } else {
+ /* set */
+ wl_rssi_event_t rssi;
+
+ memset(&rssi, 0, sizeof(wl_rssi_event_t));
+ rssi.rate_limit_msec = atoi(*argv);
+
+ while (*++argv && rssi.num_rssi_levels < MAX_RSSI_LEVELS) {
+ rssi.rssi_levels[rssi.num_rssi_levels++] = atoi(*argv);
+ if (rssi.num_rssi_levels > 1) {
+ if (rssi.rssi_levels[rssi.num_rssi_levels - 1] <=
+ rssi.rssi_levels[rssi.num_rssi_levels - 2]) {
+ /* rssi levels must be in increasing order */
+ return BCME_USAGE_ERROR;
+ }
+ }
+ }
+
+ if (*argv) {
+ /* too many parameters */
+ return BCME_USAGE_ERROR;
+ }
+
+ rssi.rate_limit_msec = htod32(rssi.rate_limit_msec);
+ ret = wlu_var_setbuf(wl, cmd->name, &rssi, sizeof(rssi));
+ }
+ return ret;
+}
+
+static int
+wl_chanim_state(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 chanspec;
+ int argc = 0;
+ int ret, val;
+
+ argv++;
+
+ /* find the arg count */
+ while (argv[argc])
+ argc++;
+
+ if (argc != 1)
+ return BCME_USAGE_ERROR;
+
+ chanspec = wf_chspec_aton(*argv);
+ chanspec = wl_chspec32_to_driver(chanspec);
+ if (chanspec == INVCHANSPEC) {
+ return BCME_USAGE_ERROR;
+ }
+
+ ret = wlu_iovar_getbuf(wl, cmd->name, &chanspec, sizeof(chanspec),
+ buf, WLC_IOCTL_SMLEN);
+ if (ret < 0)
+ return ret;
+ val = *(int*)buf;
+ val = dtoh32(val);
+
+ printf("%d\n", val);
+ return 0;
+}
+
+static int
+wl_chanim_mode(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int val;
+ char *endptr;
+ int mode;
+
+ if (!*++argv) {
+ if (cmd->get < 0)
+ return -1;
+ if ((ret = wlu_iovar_getint(wl, cmd->name, &mode)) < 0)
+ return ret;
+
+ switch (mode) {
+ case CHANIM_DISABLE:
+ printf("CHANIM mode: disabled.\n");
+ break;
+ case CHANIM_DETECT:
+ printf("CHANIM mode: detect only.\n");
+ break;
+ case CHANIM_EXT:
+ printf("CHANIM mode: external (acsd).\n");
+ break;
+ case CHANIM_ACT:
+ printf("CHANIM mode: detect + act.\n");
+ break;
+ }
+ return 0;
+ } else {
+ mode = CHANIM_DETECT;
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ switch (val) {
+ case 0:
+ mode = CHANIM_DISABLE;
+ break;
+ case 1:
+ mode = CHANIM_DETECT;
+ break;
+ case 2:
+ mode = CHANIM_EXT;
+ break;
+ case 3:
+ mode = CHANIM_ACT;
+ break;
+ default:
+ return BCME_BADARG;
+ }
+
+ mode = htod32(mode);
+ return wlu_iovar_setint(wl, cmd->name, mode);
+ }
+}
+
+static int
+_wl_dump_lq(void *wl)
+{
+ int ret = BCME_OK, noise = 0;
+ wl_lq_t *plq = NULL;
+ void *ptr = NULL;
+
+ memset(buf, 0, sizeof(wl_lq_t));
+
+ /* Display stats when disabled */
+ if ((ret = wlu_get(wl, WLC_GET_PHY_NOISE, &noise, sizeof(int))) < 0) {
+ printf("wlc_get noise failed with retcode:%d\n", ret);
+ return ret;
+ }
+
+ if ((ret = wlu_var_getbuf_sm (wl, "monitor_lq_status", NULL, 0, &ptr)) < 0) {
+ printf("wlc_get lq_status failed with retcode:%d\n", ret);
+ return ret;
+ }
+
+ plq = (wl_lq_t *)ptr;
+
+ if (!plq->isvalid) {
+ printf("Stats collection currently disabled"
+ "['wl monitor_lq 1' to enable statistics collection]\n");
+ return ret;
+ }
+
+ noise = dtoh32(noise);
+ plq->rssi[LQ_IDX_MIN] = dtoh32(plq->rssi[LQ_IDX_MIN]);
+ plq->rssi[LQ_IDX_MAX] = dtoh32(plq->rssi[LQ_IDX_MAX]);
+ plq->rssi[LQ_IDX_AVG] = dtoh32(plq->rssi[LQ_IDX_AVG]);
+
+ printf("rss: %d, %d, %d\nsnr: %d, %d, %d\n",
+ plq->rssi[LQ_IDX_MIN],
+ plq->rssi[LQ_IDX_AVG],
+ plq->rssi[LQ_IDX_MAX],
+ plq->rssi[LQ_IDX_MIN]-noise,
+ plq->rssi[LQ_IDX_AVG]-noise,
+ plq->rssi[LQ_IDX_MAX]-noise);
+
+ return ret;
+} /* _wl_dump_lq */
+
+static int
+wl_dump_lq(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!*++argv)
+ ret = _wl_dump_lq(wl);
+
+ return ret;
+} /* wl_dump_lq */
+
+static int
+wl_monitor_lq(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ char *endptr = NULL;
+ char **startptr = argv;
+
+ if (!*++startptr) { /* Get */
+ ret = wl_varint(wl, cmd, argv);
+ }
+ else {
+ int val = *startptr[0];
+ val = strtol(*startptr, &endptr, 0);
+
+ if (*endptr != '\0') {
+ return BCME_USAGE_ERROR;
+ }
+
+ val = htod32(val);
+
+ if (val == LQ_STOP_MONITOR) {
+ if ((ret = _wl_dump_lq(wl)))
+ return ret;
+ }
+
+ ret = wl_varint(wl, cmd, argv); /* Standard set call after getting stats */
+ }
+
+ return ret;
+} /* wl_monitor_lq */
+
+static int
+wl_chanim_acs_record(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr = NULL;
+ int err = 0, i;
+ wl_acs_record_t *result;
+
+ /* need to add to this str if new acs trigger type is added */
+ const char *trig_str[] = {"None", "IOCTL", "CHANIM", "TIMER", "BTA"};
+
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return err;
+
+ result = (wl_acs_record_t *) ptr;
+
+ if (!result->count) {
+ printf("There is no ACS recorded\n");
+ return err;
+ }
+
+ printf("current timestamp: %u (ms)\n", result->timestamp);
+
+ printf("Timestamp(ms) ACS Trigger Selected Channel Glitch Count CCA Count\n");
+ for (i = 0; i < result->count; i++) {
+ uint8 idx = CHANIM_ACS_RECORD - result->count + i;
+ chanim_acs_record_t * record = &result->acs_record[idx];
+
+ record->selected_chspc = wl_chspec_from_driver(record->selected_chspc);
+
+ printf("%10u \t%s \t%10d \t%12d \t%8d\n", record->timestamp,
+ trig_str[record->trigger], wf_chspec_ctlchan(record->selected_chspc),
+ record->glitch_cnt, record->ccastats);
+ }
+ return err;
+}
+
+static int
+wl_chanim_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_chanim_stats_t *stats;
+ int stats_size;
+ int i, err;
+ void *ptr;
+
+ UNUSED_PARAMETER(argv);
+
+ /* get fw chanim stats version */
+ stats_size = WL_CHANIM_STATS_FIXED_LEN +
+ MAX(sizeof(chanim_stats_t), sizeof(chanim_stats_v2_t));
+ stats = (wl_chanim_stats_t *)malloc(stats_size);
+ if (stats == NULL) {
+ fprintf(stderr, "memory alloc failure\n");
+ return BCME_NOMEM;
+ }
+ memset(stats, 0, stats_size);
+
+ stats->buflen = htod32(stats_size);
+ if ((err = wlu_var_getbuf(wl, cmd->name, stats, stats_size, &ptr)) < 0) {
+ printf("failed to get chanim results");
+ free(stats);
+ return err;
+ }
+ memcpy(stats, ptr, stats_size);
+
+ stats->version = dtoh32(stats->version);
+ if (!((stats->version == WL_CHANIM_STATS_VERSION) ||
+ (stats->version == WL_CHANIM_STATS_V2))) {
+ printf("Sorry, your driver has wl_chanim_stats version %d "
+ "but this program supports only version %d and %d.\n",
+ stats->version, WL_CHANIM_STATS_V2, WL_CHANIM_STATS_VERSION);
+ free(stats);
+ return 0;
+ }
+
+ /* get fw chanim stats */
+ stats->buflen = htod32(stats_size);
+ stats->count = htod32(WL_CHANIM_COUNT_ONE);
+ if ((err = wlu_var_getbuf(wl, cmd->name, stats, stats_size, &ptr)) < 0) {
+ printf("failed to get chanim results");
+ free(stats);
+ return err;
+ }
+ memcpy(stats, ptr, stats_size);
+ stats->version = dtoh32(stats->version);
+ stats->buflen = dtoh32(stats->buflen);
+ stats->count = dtoh32(stats->count);
+
+ printf("version: %d \n", stats->version);
+
+ if (stats->version == WL_CHANIM_STATS_VERSION) {
+ chanim_stats_t *stats_v3 = (chanim_stats_t *)stats->stats;
+ stats_v3->glitchcnt = dtoh32(stats_v3->glitchcnt);
+ stats_v3->badplcp = dtoh32(stats_v3->badplcp);
+ stats_v3->chanspec = dtoh16(stats_v3->chanspec);
+ stats_v3->timestamp = dtoh32(stats_v3->timestamp);
+
+ printf("chanspec tx inbss obss nocat nopkt doze txop "
+ "goodtx badtx glitch badplcp knoise idle timestamp\n");
+ printf("0x%4x\t", stats_v3->chanspec);
+ for (i = 0; i < CCASTATS_MAX; i++) {
+ printf("%d\t", stats_v3->ccastats[i]);
+ }
+ printf("%d\t%d\t%d\t%d\t%d", stats_v3->glitchcnt, stats_v3->badplcp,
+ stats_v3->bgnoise, stats_v3->chan_idle, stats_v3->timestamp);
+ printf("\n");
+ } else if (stats->version == WL_CHANIM_STATS_V2) {
+ chanim_stats_v2_t *stats_v2 = (chanim_stats_v2_t *)stats->stats;
+ stats_v2->glitchcnt = dtoh32(stats_v2->glitchcnt);
+ stats_v2->badplcp = dtoh32(stats_v2->badplcp);
+ stats_v2->chanspec = dtoh16(stats_v2->chanspec);
+ stats_v2->timestamp = dtoh32(stats_v2->timestamp);
+
+ printf("chanspec tx inbss obss nocat nopkt doze txop "
+ "goodtx badtx glitch badplcp knoise idle timestamp\n");
+ printf("0x%4x\t", stats_v2->chanspec);
+ for (i = 0; i < CCASTATS_V2_MAX; i++) {
+ printf("%d\t", stats_v2->ccastats[i]);
+ }
+ printf("%d\t%d\t%d\t%d\t%d", stats_v2->glitchcnt, stats_v2->badplcp,
+ stats_v2->bgnoise, stats_v2->chan_idle, stats_v2->timestamp);
+ printf("\n");
+ }
+
+ free(stats);
+ return (err);
+}
diff --git a/wl/src/wl/exe/wluc_ltecx.c b/wl/src/wl/exe/wluc_ltecx.c
new file mode 100644
index 0000000..2931490
--- /dev/null
+++ b/wl/src/wl/exe/wluc_ltecx.c
@@ -0,0 +1,516 @@
+/*
+ * wl ltecx command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_ltecx.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+/* LTE coex funcs */
+static cmd_func_t wl_wci2_config;
+static cmd_func_t wl_mws_params;
+static cmd_func_t wl_mws_wci2_msg;
+static cmd_func_t wl_mws_frame_config;
+static cmd_func_t wl_mws_antmap;
+static cmd_func_t wl_mws_oclmap;
+static cmd_func_t wl_mws_scanreq_bm;
+
+static cmd_t wl_ltecx_cmds[] = {
+ { "wci2_config", wl_wci2_config, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set LTE coex MWS signaling config\n"
+ "\tUsage: wl wci2_config <rxassert_off> <rxassert_jit> <rxdeassert_off> <rxdeassert_jit> "
+ "<txassert_off> <txassert_jit> <txdeassert_off> <txdeassert_jit> "
+ "<patassert_off> <patassert_jit> <inactassert_off> <inactassert_jit> "
+ "<scanfreqassert_off> <scanfreqassert_jit> <priassert_off_req>"},
+ { "mws_params", wl_mws_params, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set LTE coex MWS channel params\n"
+ "\tUsage: wl mws_params <rx_center_freq> <tx_center_freq> "
+ "<rx_channel_bw> <tx_channel_bw> <channel_en> <channel_type>"},
+ { "mws_debug_msg", wl_mws_wci2_msg, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set LTE coex BT-SIG message\n"
+ "\tUsage: wl mws_debug_msg <Message> <Interval 20us-32000us> "
+ "<Repeats>"},
+ { "mws_frame_config", wl_mws_frame_config, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set LTE Frame configuration\n"
+ "\tUsage: wl mws_frame_config <mws_frame_dur> <mws_framesync_assert_offset>"
+ "<mws_framesync_assert_jitter> <mws_num_periods>"
+ "{<mws_period_dur[i]> <mws_period_type>[i]}"},
+ { "mws_antenna_selection", wl_mws_antmap, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set Antenna selection params\n"
+ "\tUsage: wl mws_antenna_selection <band-AntTx-combo1> <band-AntTx-combo2> "
+ "<band-AntTx-combo3> <band-AntTx-combo4>\n"},
+ { "mws_ocl_override", wl_mws_oclmap, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set OCL maps\n"
+ "\tUsage: wl mws_ocl_override <bitmap_2G> <bitmap_5G_lo> "
+ "<bitmap_5G_mid> <bitmap_5G_high>\n"},
+ { "mws_scanreq_bm", wl_mws_scanreq_bm, WLC_GET_VAR, WLC_SET_VAR,
+ "\tusage: wl mws_scanreq_bm [idx 2.4G-bitmap 5G-bitmap-lo 5G-bitmap-mid 5G-bitmap-hi]\n"
+ "Set/Get the channel bitmaps corresponding to MWS (cellular) scan index <idx>"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_ltecx_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register ltecx commands */
+ wl_module_cmds_register(wl_ltecx_cmds);
+}
+
+static int
+wl_wci2_config(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 val;
+ char *endptr = NULL;
+ uint argc;
+ wci2_config_t wci2_config;
+ uint16 *configp = (uint16 *)&wci2_config;
+ int ret, i;
+
+ UNUSED_PARAMETER(cmd);
+
+ val = 0;
+
+ /* eat command name */
+ argv++;
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+
+ memset(&wci2_config, '\0', sizeof(wci2_config_t));
+
+ if (argc == 0) {
+ /* Get and print the values */
+ ret = wlu_iovar_getbuf(wl, "wci2_config", &wci2_config, sizeof(wci2_config_t),
+ buf, WLC_IOCTL_SMLEN);
+ if (ret)
+ return ret;
+
+ printf("rxassert_off %d rxassert_jit %d rxdeassert_off %d rxdeassert_jit %d "
+ "txassert_off %d txassert_jit %d txdeassert_off %d txdeassert_jit %d "
+ "patassert_off %d patassert_jit %d inactassert_off %d inactassert_jit %d "
+ "scanfreqassert_off %d scanfreqassert_jit %d priassert_off_req %d\n",
+ dtoh16(((uint16 *)buf)[0]), dtoh16(((uint16 *)buf)[1]),
+ dtoh16(((uint16 *)buf)[2]), dtoh16(((uint16 *)buf)[3]),
+ dtoh16(((uint16 *)buf)[4]), dtoh16(((uint16 *)buf)[5]),
+ dtoh16(((uint16 *)buf)[6]), dtoh16(((uint16 *)buf)[7]),
+ dtoh16(((uint16 *)buf)[8]), dtoh16(((uint16 *)buf)[9]),
+ dtoh16(((uint16 *)buf)[10]), dtoh16(((uint16 *)buf)[11]),
+ dtoh16(((uint16 *)buf)[12]), dtoh16(((uint16 *)buf)[13]),
+ dtoh16(((uint16 *)buf)[14]));
+ return 0;
+ }
+
+ if (argc < 15)
+ goto usage;
+
+ for (i = 0; i < 15; ++i) {
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ configp[i] = htod16((uint16)val);
+ }
+ return wlu_iovar_setbuf(wl, "wci2_config", &wci2_config, sizeof(wci2_config_t),
+ buf, WLC_IOCTL_SMLEN);
+
+usage:
+ return BCME_USAGE_ERROR;
+}
+
+static int
+wl_mws_params(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 val;
+ char *endptr = NULL;
+ uint argc;
+ mws_params_t mws_params;
+ uint16 *paramsp = (uint16 *)&mws_params;
+ int ret, i;
+
+ UNUSED_PARAMETER(cmd);
+
+ val = 0;
+
+ /* eat command name */
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+
+ memset(&mws_params, '\0', sizeof(mws_params_t));
+
+ if (argc == 0) {
+ /* Get and print the values */
+ ret = wlu_iovar_getbuf(wl, "mws_params", &mws_params, sizeof(mws_params_t),
+ buf, WLC_IOCTL_SMLEN);
+ if (ret)
+ return ret;
+
+ printf("rx_center_freq %d tx_center_freq %d rx_channel_bw %d tx_channel_bw %d "
+ "channel_en %d channel_type %d\n",
+ dtoh16(((uint16 *)buf)[0]), dtoh16(((uint16 *)buf)[1]),
+ dtoh16(((uint16 *)buf)[2]), dtoh16(((uint16 *)buf)[3]), buf[8], buf[9]);
+ return 0;
+ }
+
+ if (argc < 6)
+ goto usage;
+ for (i = 0; i < 4; ++i) {
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ paramsp[i] = htod16((uint16)val);
+ }
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ mws_params.mws_channel_en = val;
+ ++i;
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ mws_params.mws_channel_type = val;
+
+ return wlu_iovar_setbuf(wl, "mws_params", &mws_params, sizeof(mws_params_t),
+ buf, WLC_IOCTL_SMLEN);
+
+usage:
+ return BCME_USAGE_ERROR;
+}
+
+static int
+wl_mws_wci2_msg(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 val;
+ char *endptr = NULL;
+ uint argc;
+ mws_wci2_msg_t mws_wci2_msg;
+ uint16 *paramsp = (uint16 *)&mws_wci2_msg;
+ int ret, i = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ val = 0;
+
+ /* eat command name */
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+
+ memset(&mws_wci2_msg, '\0', sizeof(mws_wci2_msg_t));
+
+ if (argc == 0) {
+ /* Get and print the values */
+ ret = wlu_iovar_getbuf(wl, "mws_debug_msg", &mws_wci2_msg, sizeof(mws_wci2_msg_t),
+ buf, WLC_IOCTL_SMLEN);
+ if (ret)
+ return ret;
+
+ printf("Message %d Interval %d Repeats %d \n",
+ dtoh16(((uint16 *)buf)[0]), dtoh16(((uint16 *)buf)[1]),
+ dtoh16(((uint16 *)buf)[2]));
+ return 0;
+ }
+
+ if (argc < 3)
+ goto usage;
+
+ for (i = 0; i < 3; ++i) {
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ paramsp[i] = htod16((uint16)val);
+ }
+ if ((paramsp[1] < 20) || (paramsp[1] > 32000))
+ goto usage;
+ return wlu_iovar_setbuf(wl, "mws_debug_msg", &mws_wci2_msg, sizeof(mws_wci2_msg_t),
+ buf, WLC_IOCTL_SMLEN);
+
+usage:
+ return BCME_USAGE_ERROR;
+}
+
+static int
+wl_mws_frame_config(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 val;
+ char *endptr = NULL;
+ uint argc;
+ mws_frame_config_t mws_frame_config;
+ uint16 *paramsp = (uint16 *)&mws_frame_config;
+ int ret, j = 3, k = 4, l = 20;
+ uint8 i = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ val = 0;
+
+ /* eat command name */
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+
+ memset(&mws_frame_config, '\0', sizeof(mws_frame_config_t));
+
+ if (argc == 0) {
+ /* Get and print the values */
+ ret = wlu_iovar_getbuf(wl, "mws_frame_config", &mws_frame_config,
+ sizeof(mws_frame_config_t), buf, WLC_IOCTL_SMLEN);
+ if (ret) {
+ return ret;
+ }
+ printf("mws_frame_dur %d us mws_framesync_assert_offset %d "
+ "mws_framesync_assert_jitter %d mws_num_periods %d \n",
+ dtoh16(((uint16 *)buf)[0]), dtoh16(((uint16 *)buf)[1]),
+ dtoh16(((uint16 *)buf)[2]), buf[27]);
+ for (i = 0; i < buf[27]; i++) {
+ printf("mws_period_dur[%d] %d us mws_period_type[%d] %d\n",
+ i, dtoh16(((uint16 *)buf)[j]), i, buf[l]);
+ j++;
+ l++;
+ }
+ return 0;
+ }
+
+ if (argc <= 4)
+ goto usage;
+ /* Loop to populate the first three elements of the structure */
+ for (i = 0; i < 3; ++i) {
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ paramsp[i] = htod16((uint16)val);
+ }
+
+ val = strtoul(argv[3], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ mws_frame_config.mws_num_periods = val;
+
+ /* Error check for insufficient data entered */
+ if ((uint8)argc != ((mws_frame_config.mws_num_periods * 2) + 4)) {
+ goto usage;
+ }
+ /* Loop to populate the arrays of size equal to mws_frame_config.mws_num_periods */
+ for (i = 0; i < mws_frame_config.mws_num_periods; i++)
+ {
+ val = strtoul(argv[k], &endptr, 0);
+ if (*endptr != '\0') {
+ goto usage;
+ }
+ mws_frame_config.mws_period_dur[i] = val;
+ k++;
+
+ val = strtoul(argv[k], &endptr, 0);
+ if (*endptr != '\0') {
+ goto usage;
+ }
+ mws_frame_config.mws_period_type[i] = val;
+ k++;
+ }
+ /* Set the values */
+ return wlu_iovar_setbuf(wl, "mws_frame_config", &mws_frame_config,
+ sizeof(mws_frame_config_t), buf, WLC_IOCTL_SMLEN);
+
+ usage:
+ return BCME_USAGE_ERROR;
+}
+
+static int
+wl_mws_antmap(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 val;
+ char *endptr = NULL;
+ uint argc;
+ mws_ant_map_t mws_antmap;
+ uint16 *paramsp = (uint16 *)&mws_antmap;
+ int ret, i = 0, j = 0;
+ uint16 error_mask = 0xc000;
+ uint16 ant_set[4];
+ UNUSED_PARAMETER(cmd);
+ val = 0;
+ /* eat command name */
+ argv++;
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+ memset(&mws_antmap, '\0', sizeof(mws_antmap));
+ if (argc == 0) {
+ /* Get and print the values */
+ ret = wlu_iovar_getbuf(wl, "mws_antenna_selection",
+ &mws_antmap, sizeof(mws_antmap),
+ buf, WLC_IOCTL_SMLEN);
+ if (ret)
+ return ret;
+ printf("band_ant_combo1 %x band_ant_combo2 %x "
+ "band_ant_combo3 %x band_ant_combo4 %x\n",
+ dtoh16(((uint16 *)buf)[0]), dtoh16(((uint16 *)buf)[1]),
+ dtoh16(((uint16 *)buf)[2]), dtoh16(((uint16 *)buf)[3]));
+ return 0;
+ }
+ if (argc < 4)
+ goto usage;
+ for (i = 0; i < 4; ++i) {
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ paramsp[i] = htod16((uint16)val);
+ ant_set[i] = (paramsp[i] & error_mask) >> 14;
+ for (j = 0; j < i; ++j) {
+ if (ant_set[i] == ant_set[j]) {
+ printf("duplicate band ant_tx combiniation\n");
+ goto usage;
+ }
+ }
+ }
+ return wlu_iovar_setbuf(wl, "mws_antenna_selection", paramsp, sizeof(mws_antmap),
+ buf, WLC_IOCTL_SMLEN);
+usage:
+ return BCME_USAGE_ERROR;
+}
+
+static int
+wl_mws_oclmap(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 val;
+ char *endptr = NULL;
+ uint argc;
+ wl_mws_ocl_override_t mws_oclmap;
+ uint16 *paramsp = (uint16 *)&mws_oclmap;
+ int ret, i = 0;
+ UNUSED_PARAMETER(cmd);
+ val = 0;
+ /* eat command name */
+ argv++;
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+ memset(&mws_oclmap, '\0', sizeof(mws_oclmap));
+ if (argc == 0) {
+ /* Get and print the values */
+ ret = wlu_iovar_getbuf(wl, "mws_ocl_override",
+ &mws_oclmap, sizeof(mws_oclmap),
+ buf, WLC_IOCTL_SMLEN);
+ if (ret)
+ return ret;
+ printf(" bitmap_2g %x bitmap_5g_lo %x "
+ "babitmap_5g_mid %x bitmap_5g_high %x\n",
+ dtoh16(((uint16 *)buf)[1]), dtoh16(((uint16 *)buf)[2]),
+ dtoh16(((uint16 *)buf)[3]), dtoh16(((uint16 *)buf)[4]));
+ return 0;
+ }
+ if (argc < 4)
+ goto usage;
+ paramsp[0] = WL_MWS_OCL_OVERRIDE_VERSION;
+ for (i = 0; i < 4; ++i) {
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ paramsp[i+1] = htod16((uint16)val);
+ }
+ return wlu_iovar_setbuf(wl, "mws_ocl_override", paramsp, sizeof(mws_oclmap),
+ buf, WLC_IOCTL_SMLEN);
+usage:
+ return BCME_USAGE_ERROR;
+}
+
+static int
+wl_mws_scanreq_bm(void *wl, cmd_t *cmd, char **argv)
+{
+ mws_scanreq_params_t mws_scanreq_params;
+ uint16 *paramsp = (uint16 *)&mws_scanreq_params;
+ char *endptr = NULL;
+ uint32 val;
+ uint argc, i;
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* eat command name */
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+
+ memset(&mws_scanreq_params, 0, sizeof(mws_scanreq_params_t));
+
+ if (argc == 0) {
+ goto usage;
+ } else if (argc == 1) {
+ val = strtoul(argv[0], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ mws_scanreq_params.idx = htod16((uint16)val);
+
+ if ((mws_scanreq_params.idx < 1) || (mws_scanreq_params.idx > 31)) {
+ printf("LTE Index should be in range 1-31\n");
+ goto usage;
+ }
+
+ err = wlu_iovar_getbuf(wl, cmd->name, &mws_scanreq_params,
+ sizeof(mws_scanreq_params_t), buf, WLC_IOCTL_SMLEN);
+ if (err < 0)
+ return err;
+ mws_scanreq_params = *(mws_scanreq_params_t *)buf;
+ printf("\n Current LTE Timesharing coex : \n"
+ "\t LTE channel index = %d\n \t 2G Channel = %d \n\t 5G low channel= %d\n"
+ "\t 5G Middle channel= %d\n\t 5G High channel= %d\n",
+ mws_scanreq_params.idx, mws_scanreq_params.bm_2g, mws_scanreq_params.bm_5g_lo,
+ mws_scanreq_params.bm_5g_mid, mws_scanreq_params.bm_5g_hi);
+ return 0;
+ } else if (argc > 1 && argc < 5) {
+ goto usage;
+ }
+ memset(&mws_scanreq_params, 0, sizeof(mws_scanreq_params_t));
+ for (i = 0; i < 5; ++i) {
+ val = strtoul(argv[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto usage;
+ paramsp[i] = htod16((uint16)val);
+ }
+
+ return wlu_iovar_setbuf(wl, "mws_scanreq_bm", &mws_scanreq_params,
+ sizeof(mws_scanreq_params_t), buf, WLC_IOCTL_SMLEN);
+usage:
+ return BCME_USAGE_ERROR;
+}
diff --git a/wl/src/wl/exe/wluc_mbo.c b/wl/src/wl/exe/wluc_mbo.c
new file mode 100644
index 0000000..e55e2f5
--- /dev/null
+++ b/wl/src/wl/exe/wluc_mbo.c
@@ -0,0 +1,875 @@
+/*
+ * wl mbo command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id:$
+ */
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+#include <wlioctl.h>
+#include <bcmiov.h>
+#include <proto/mbo.h>
+
+/* from bcmiov.h: non-batched command version = major|minor w/ major <= 127 */
+#define WL_MBO_IOV_MAJOR_VER 1
+#define WL_MBO_IOV_MINOR_VER 1
+#define WL_MBO_IOV_MAJOR_VER_SHIFT 8
+#define WL_MBO_IOV_VERSION \
+ ((WL_MBO_IOV_MAJOR_VER << WL_MBO_IOV_MAJOR_VER_SHIFT)| WL_MBO_IOV_MINOR_VER)
+
+typedef struct wl_mbo_sub_cmd wl_mbo_sub_cmd_t;
+typedef int (subcmd_handler_t)(void *wl, const wl_mbo_sub_cmd_t *cmd,
+ char **argv);
+typedef void (help_handler_t) (void);
+struct wl_mbo_sub_cmd {
+ char *name;
+ uint8 version;
+ uint16 cmd_id;
+ uint16 type;
+ subcmd_handler_t *hndler;
+ help_handler_t *help;
+};
+
+static cmd_func_t wl_mbo_main;
+
+static cmd_t wl_mbo_cmds[] = {
+ { "mbo", wl_mbo_main, WLC_GET_VAR, WLC_SET_VAR,
+ "Please follow usage shown above\n"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+/* command handlers */
+static subcmd_handler_t wl_mbo_sub_cmd_add_chan_pref;
+static subcmd_handler_t wl_mbo_sub_cmd_del_chan_pref;
+static subcmd_handler_t wl_mbo_sub_cmd_list_chan_pref;
+static subcmd_handler_t wl_mbo_sub_cmd_cell_data_cap;
+static subcmd_handler_t wl_mbo_sub_cmd_dump_counters;
+static subcmd_handler_t wl_mbo_sub_cmd_clear_counters;
+static subcmd_handler_t wl_mbo_sub_cmd_force_assoc;
+static subcmd_handler_t wl_mbo_sub_cmd_bsstrans_reject;
+
+/* help handlers */
+static help_handler_t wl_mbo_add_chan_pref_help_fn;
+static help_handler_t wl_mbo_del_chan_pref_help_fn;
+static help_handler_t wl_mbo_list_chan_pref_help_fn;
+static help_handler_t wl_mbo_cell_data_cap_help_fn;
+static help_handler_t wl_mbo_counters_help_fn;
+static help_handler_t wl_mbo_clear_counters_help_fn;
+static help_handler_t wl_mbo_force_assoc_help_fn;
+static help_handler_t wl_mbo_bsstrans_reject_help_fn;
+
+#define WL_MBO_CMD_ALL 0
+static const wl_mbo_sub_cmd_t mbo_subcmd_lists[] = {
+ { "add_chan_pref", 0x1, WL_MBO_CMD_ADD_CHAN_PREF,
+ IOVT_BUFFER, wl_mbo_sub_cmd_add_chan_pref,
+ wl_mbo_add_chan_pref_help_fn
+ },
+ { "del_chan_pref", 0x1, WL_MBO_CMD_DEL_CHAN_PREF,
+ IOVT_BUFFER, wl_mbo_sub_cmd_del_chan_pref,
+ wl_mbo_del_chan_pref_help_fn
+ },
+ { "list_chan_pref", 0x1, WL_MBO_CMD_LIST_CHAN_PREF,
+ IOVT_BUFFER, wl_mbo_sub_cmd_list_chan_pref,
+ wl_mbo_list_chan_pref_help_fn
+ },
+ { "cell_data_cap", 0x1, WL_MBO_CMD_CELLULAR_DATA_CAP,
+ IOVT_BUFFER, wl_mbo_sub_cmd_cell_data_cap,
+ wl_mbo_cell_data_cap_help_fn
+ },
+ { "counters", 0x1, WL_MBO_CMD_DUMP_COUNTERS,
+ IOVT_BUFFER, wl_mbo_sub_cmd_dump_counters,
+ wl_mbo_counters_help_fn
+ },
+ { "clear_counters", 0x1, WL_MBO_CMD_CLEAR_COUNTERS,
+ IOVT_BUFFER, wl_mbo_sub_cmd_clear_counters,
+ wl_mbo_clear_counters_help_fn
+ },
+#ifdef WL_MBO_WFA_CERT
+ { "force_assoc", 0x1, WL_MBO_CMD_FORCE_ASSOC,
+ IOVT_BUFFER, wl_mbo_sub_cmd_force_assoc,
+ wl_mbo_force_assoc_help_fn
+ },
+ { "bsstrans_reject", 0x1, WL_MBO_CMD_BSSTRANS_REJECT,
+ IOVT_BUFFER, wl_mbo_sub_cmd_bsstrans_reject,
+ wl_mbo_bsstrans_reject_help_fn
+ },
+#endif /* WL_MBO_WFA_CERT */
+ { NULL, 0, 0, 0, NULL, NULL }
+};
+
+void wluc_mbo_module_init(void)
+{
+ /* register mbo commands */
+ wl_module_cmds_register(wl_mbo_cmds);
+}
+
+static void
+wl_mbo_usage(int cmd_id)
+{
+ const wl_mbo_sub_cmd_t *subcmd = &mbo_subcmd_lists[0];
+
+ if (cmd_id > (WL_MBO_CMD_LAST - 1)) {
+ return;
+ }
+ while (subcmd->name) {
+ if (cmd_id == WL_MBO_CMD_ALL) {
+ subcmd->help();
+ } else if (cmd_id == subcmd->cmd_id) {
+ subcmd->help();
+ } else {
+ /* do nothing */
+ }
+ subcmd++;
+ }
+ return;
+}
+
+static int
+wl_mbo_main(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ const wl_mbo_sub_cmd_t *subcmd = &mbo_subcmd_lists[0];
+
+ UNUSED_PARAMETER(cmd);
+ /* skip to command name */
+ argv++;
+
+ if (*argv) {
+ if (!strcmp(*argv, "-h") || !strcmp(*argv, "help")) {
+ wl_mbo_usage(WL_MBO_CMD_ALL);
+ return BCME_OK;
+ }
+ while (subcmd->name) {
+ if (strcmp(subcmd->name, *argv) == 0) {
+ if (subcmd->hndler) {
+ ret = subcmd->hndler(wl, subcmd, ++argv);
+ return ret;
+ }
+ }
+ subcmd++;
+ }
+ } else {
+ wl_mbo_usage(WL_MBO_CMD_ALL);
+ return BCME_USAGE_ERROR;
+ }
+
+ return ret;
+}
+
+static int
+wl_mbo_sub_cmd_add_chan_pref(void *wl, const wl_mbo_sub_cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ bcm_iov_buf_t *iov_buf = NULL;
+ uint8 *pxtlv = NULL;
+ uint16 buflen = 0, buflen_start = 0;
+ char *param = NULL, *val_p = NULL;
+ uint16 iovlen = 0;
+ bool opclass_set = FALSE, chan_set = FALSE, reason_set = FALSE, pref_set = FALSE;
+
+ /* only set */
+ if (*argv == NULL) {
+ wl_mbo_usage(WL_MBO_CMD_ADD_CHAN_PREF);
+ return BCME_USAGE_ERROR;
+ } else {
+ iov_buf = (bcm_iov_buf_t *)calloc(1, WLC_IOCTL_MEDLEN);
+ if (iov_buf == NULL) {
+ return BCME_NOMEM;
+ }
+ /* fill header */
+ iov_buf->version = WL_MBO_IOV_VERSION;
+ iov_buf->id = cmd->cmd_id;
+
+ pxtlv = (uint8 *)&iov_buf->data[0];
+ buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
+
+ /* parse and pack config parameters */
+ while ((param = *argv++)) {
+ val_p = *argv++;
+ if (!val_p || *val_p == '-') {
+ fprintf(stderr, "%s: No value following %s\n", __FUNCTION__, param);
+ wl_mbo_usage(WL_MBO_CMD_ADD_CHAN_PREF);
+ ret = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ if (strcmp(param, "-o") == 0) {
+ uint8 opclass = strtoul(val_p, NULL, 0);
+ /* TBD: validation */
+ opclass_set = TRUE;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_OPCLASS,
+ sizeof(opclass), &opclass, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ } else if (strcmp(param, "-c") == 0) {
+ uint8 chan = strtoul(val_p, NULL, 0);
+ /* TBD: validation */
+ chan_set = TRUE;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CHAN,
+ sizeof(chan), &chan, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ } else if (strcmp(param, "-p") == 0) {
+ uint8 pref = strtoul(val_p, NULL, 0);
+ if ((pref != MBO_STA_NON_OPERABLE_BAND_CHAN) &&
+ (pref != MBO_STA_NON_PREFERRED_BAND_CHAN) &&
+ (pref != MBO_STA_PREFERRED_BAND_CHAN)) {
+ fprintf(stderr, "Wrong preference value %u\n", pref);
+ ret = BCME_BADOPTION;
+ goto fail;
+ }
+ pref_set = TRUE;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_PREFERENCE,
+ sizeof(pref), &pref, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ } else if (strcmp(param, "-r") == 0) {
+ uint8 rc = strtoul(val_p, NULL, 0);
+ reason_set = TRUE;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_REASON_CODE,
+ sizeof(rc), &rc, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ } else {
+ fprintf(stderr, "Unknown param %s\n", param);
+ }
+ }
+ if (opclass_set && chan_set && pref_set && reason_set) {
+ iov_buf->len = buflen_start - buflen;
+ iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
+ ret = wlu_var_setbuf(wl, "mbo", (void *)iov_buf, iovlen);
+ } else {
+ wl_mbo_usage(WL_MBO_CMD_ADD_CHAN_PREF);
+ ret = BCME_USAGE_ERROR;
+ }
+ }
+fail:
+ if (iov_buf) {
+ free(iov_buf);
+ }
+ return ret;
+}
+
+static void
+wl_mbo_add_chan_pref_help_fn(void)
+{
+ printf("wl mbo add_chan_pref -o <op_class> -c <chan> -p <pref val> -r <reason_code>\n");
+ printf("\top class: operating class defined by IEEE\n");
+ printf("\tchan: valid channel number\n");
+ printf("\tpref val: preference value [<0/1/255>]\n");
+ printf("\t\t 0 = non operable band/chan\n");
+ printf("\t\t 1 = non preferred band/chan\n");
+ printf("\t\t 255 = preferred band/chan\n");
+ printf("\treason code: [<0-3>]\n");
+}
+
+static int
+wl_mbo_sub_cmd_del_chan_pref(void *wl, const wl_mbo_sub_cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ bcm_iov_buf_t *iov_buf = NULL;
+ uint8 *pxtlv = NULL;
+ uint16 buflen = 0, buflen_start = 0;
+ char *param = NULL, *val_p = NULL;
+ uint16 iovlen = 0;
+ bool opclass_set = FALSE, chan_set = FALSE;
+
+ /* only set */
+ if (*argv == NULL) {
+ wl_mbo_usage(WL_MBO_CMD_DEL_CHAN_PREF);
+ return BCME_USAGE_ERROR;
+ } else {
+ iov_buf = (bcm_iov_buf_t *)calloc(1, WLC_IOCTL_MEDLEN);
+ if (iov_buf == NULL) {
+ return BCME_NOMEM;
+ }
+ /* fill header */
+ iov_buf->version = WL_MBO_IOV_VERSION;
+ iov_buf->id = cmd->cmd_id;
+
+ pxtlv = (uint8 *)&iov_buf->data[0];
+ buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
+
+ /* parse and pack config parameters */
+ while ((param = *argv++)) {
+ val_p = *argv++;
+ if (!val_p || *val_p == '-') {
+ fprintf(stderr, "%s: No value following %s\n", __FUNCTION__, param);
+ wl_mbo_usage(WL_MBO_CMD_DEL_CHAN_PREF);
+ ret = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ if (strcmp(param, "-o") == 0) {
+ uint8 opclass = strtoul(val_p, NULL, 0);
+ opclass_set = TRUE;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_OPCLASS,
+ sizeof(opclass), &opclass, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ } else if (strcmp(param, "-c") == 0) {
+ uint8 chan = strtoul(val_p, NULL, 0);
+ chan_set = TRUE;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CHAN,
+ sizeof(chan), &chan, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ } else {
+ fprintf(stderr, "Unknown param %s\n", param);
+ }
+ }
+ if (opclass_set && chan_set) {
+ iov_buf->len = buflen_start - buflen;
+ iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
+ ret = wlu_var_setbuf(wl, "mbo", (void *)iov_buf, iovlen);
+ } else {
+ wl_mbo_usage(WL_MBO_CMD_DEL_CHAN_PREF);
+ ret = BCME_USAGE_ERROR;
+ }
+ }
+fail:
+ if (iov_buf) {
+ free(iov_buf);
+ }
+ return ret;
+}
+
+static void
+wl_mbo_del_chan_pref_help_fn(void)
+{
+ printf("wl mbo del_chan_pref -o <op_class> -c <chan>\n");
+ printf("\top class: operating class defined by IEEE\n");
+ printf("\tchan: valid channel number\n");
+}
+
+static int
+wl_mbo_process_iov_resp_buf(void *iov_resp, uint16 cmd_id, bcm_xtlv_unpack_cbfn_t cbfn)
+{
+ int ret = BCME_OK;
+ uint16 version;
+
+ /* Check for version */
+ version = dtoh16(*(uint16 *)iov_resp);
+ if (version != WL_MBO_IOV_VERSION) {
+ ret = BCME_UNSUPPORTED;
+ }
+ bcm_iov_buf_t *p_resp = (bcm_iov_buf_t *)iov_resp;
+ if (p_resp->id == cmd_id && cbfn != NULL) {
+ ret = bcm_unpack_xtlv_buf((void *)p_resp, (uint8 *)p_resp->data, p_resp->len,
+ BCM_XTLV_OPTION_ALIGN32, cbfn);
+ }
+ return ret;
+}
+
+static int
+wl_mbo_get_iov_resp(void *wl, const wl_mbo_sub_cmd_t *cmd, bcm_xtlv_unpack_cbfn_t cbfn)
+{
+ int ret = BCME_OK;
+ bcm_iov_buf_t *iov_buf = NULL;
+ uint8 *iov_resp = NULL;
+
+ UNUSED_PARAMETER(wl);
+ iov_buf = (bcm_iov_buf_t *)calloc(1, WLC_IOCTL_SMLEN);
+ if (iov_buf == NULL) {
+ ret = BCME_NOMEM;
+ goto fail;
+ }
+ iov_resp = (uint8 *)calloc(1, WLC_IOCTL_MAXLEN);
+ if (iov_resp == NULL) {
+ ret = BCME_NOMEM;
+ goto fail;
+ }
+ /* fill header */
+ iov_buf->version = WL_MBO_IOV_VERSION;
+ iov_buf->id = cmd->cmd_id;
+
+ ret = wlu_iovar_getbuf(wl, "mbo", iov_buf, WLC_IOCTL_SMLEN, iov_resp, WLC_IOCTL_MAXLEN);
+ if ((ret == BCME_OK) && (iov_resp != NULL)) {
+ wl_mbo_process_iov_resp_buf(iov_resp, cmd->cmd_id, cbfn);
+ }
+fail:
+ if (iov_buf) {
+ free(iov_buf);
+ }
+ if (iov_resp) {
+ free(iov_resp);
+ }
+ return ret;
+}
+
+static int
+wl_mbo_list_chan_pref_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
+{
+ UNUSED_PARAMETER(ctx);
+ UNUSED_PARAMETER(len);
+ if (data == NULL) {
+ printf("%s: Bad argument !!\n", __FUNCTION__);
+ return BCME_BADARG;
+ }
+ switch (type) {
+ case WL_MBO_XTLV_OPCLASS:
+ printf("Opclass: %u\t", *data);
+ break;
+ case WL_MBO_XTLV_CHAN:
+ printf("Chan: %u\t", *data);
+ break;
+ case WL_MBO_XTLV_PREFERENCE:
+ printf("Preference: %u\t", *data);
+ break;
+ case WL_MBO_XTLV_REASON_CODE:
+ printf("Reason Code: %u\n", *data);
+ break;
+ default:
+ printf("%s: Unknown tlv %u\n", __FUNCTION__, type);
+ }
+ return BCME_OK;
+}
+
+static int
+wl_mbo_sub_cmd_list_chan_pref(void *wl, const wl_mbo_sub_cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ /* only get */
+ if (*argv == NULL) {
+ ret = wl_mbo_get_iov_resp(wl, cmd, wl_mbo_list_chan_pref_cbfn);
+ } else {
+ wl_mbo_usage(WL_MBO_CMD_LIST_CHAN_PREF);
+ return BCME_USAGE_ERROR;
+ }
+ return ret;
+}
+
+static void
+wl_mbo_list_chan_pref_help_fn(void)
+{
+ printf("wl mbo list_chan_pref\n");
+}
+
+static int
+wl_mbo_cell_data_cap_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
+{
+ UNUSED_PARAMETER(ctx);
+ UNUSED_PARAMETER(len);
+ if (data == NULL) {
+ printf("%s: Bad argument !!\n", __FUNCTION__);
+ return BCME_BADARG;
+ }
+ switch (type) {
+ case WL_MBO_XTLV_CELL_DATA_CAP:
+ if (*data == 0) {
+ printf("Cellular data capability: value not set\n");
+ } else {
+ printf("Cellular data capability: %0x\n", *data);
+ }
+ break;
+ default:
+ printf("%s: Unknown tlv %u\n", __FUNCTION__, type);
+ }
+ return BCME_OK;
+}
+
+static int
+wl_mbo_sub_cmd_cell_data_cap(void *wl, const wl_mbo_sub_cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ bcm_iov_buf_t *iov_buf = NULL;
+ uint8 *pxtlv = NULL;
+ uint16 buflen = 0, buflen_start = 0;
+ char *param = NULL, *val_p = NULL;
+ uint16 iovlen = 0;
+
+ /* get */
+ if (*argv == NULL) {
+ ret = wl_mbo_get_iov_resp(wl, cmd, wl_mbo_cell_data_cap_cbfn);
+ } else {
+ iov_buf = (bcm_iov_buf_t *)calloc(1, WLC_IOCTL_MEDLEN);
+ if (iov_buf == NULL) {
+ ret = BCME_NOMEM;
+ goto fail;
+ }
+ /* fill header */
+ iov_buf->version = WL_MBO_IOV_VERSION;
+ iov_buf->id = cmd->cmd_id;
+
+ pxtlv = (uint8 *)&iov_buf->data[0];
+ param = *argv++;
+ if (strcmp(param, "-c") == 0) {
+ val_p = *argv;
+ if (val_p == NULL || *val_p == '-') {
+ wl_mbo_usage(WL_MBO_CMD_CELLULAR_DATA_CAP);
+ ret = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ uint8 cell_data_cap = strtoul(val_p, NULL, 0);
+ if (cell_data_cap < MBO_CELL_DATA_CONN_AVAILABLE ||
+ cell_data_cap > MBO_CELL_DATA_CONN_NOT_CAPABLE) {
+ fprintf(stderr, "wrong value %u\n", cell_data_cap);
+ ret = BCME_BADARG;
+ goto fail;
+ }
+ buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CELL_DATA_CAP,
+ sizeof(cell_data_cap), &cell_data_cap, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ } else {
+ fprintf(stderr, "wrong parameter %s\n", param);
+ wl_mbo_usage(WL_MBO_CMD_CELLULAR_DATA_CAP);
+ ret = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ iov_buf->len = buflen_start - buflen;
+ iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
+ ret = wlu_var_setbuf(wl, "mbo", (void *)iov_buf, iovlen);
+ }
+fail:
+ if (iov_buf) {
+ free(iov_buf);
+ }
+ return ret;
+}
+
+static void
+wl_mbo_cell_data_cap_help_fn(void)
+{
+ printf("wl mbo cell_data_cap -c <capability>\n");
+ printf("\tcapability: cellular connection capability <1/2/3>\n");
+ printf("\t\t 1 = Cellular data connection available\n");
+ printf("\t\t 2 = Cellular data connection not available\n");
+ printf("\t\t 3 = Cellular data connection not capable\n");
+}
+
+static int
+wl_mbo_dump_counters_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
+{
+ UNUSED_PARAMETER(ctx);
+ UNUSED_PARAMETER(len);
+ if (data == NULL) {
+ printf("%s: Bad argument !!\n", __FUNCTION__);
+ return BCME_BADARG;
+ }
+ switch (type) {
+ case WL_MBO_XTLV_COUNTERS:
+ {
+ wl_mbo_counters_t *cntr = (wl_mbo_counters_t *)data;
+ printf("BTM req::\n");
+ printf("\trcvd:%u disassoc:%u termination:%u\n",
+ cntr->trans_req_rcvd, cntr->trans_req_disassoc,
+ cntr->trans_req_bss_term);
+ printf("Transition Reason::\n");
+ printf("\tunspecified:%u frame loss:%u traffic delay:%u "
+ "low bandwidth:%u\n",
+ cntr->trans_resn_unspec, cntr->trans_resn_frm_loss,
+ cntr->trans_resn_traffic_delay, cntr->trans_resn_insuff_bw);
+ printf("\tload balance:%u low rssi:%u excss retransmission:%u\n",
+ cntr->trans_resn_load_bal, cntr->trans_resn_low_rssi,
+ cntr->trans_resn_xcess_retransmn);
+ printf("\tGray zone:%u premium AP switch:%u\n",
+ cntr->trans_resn_gray_zone, cntr->trans_resn_prem_ap_sw);
+ printf("Num of transition rejection:%u\n", cntr->trans_rejn_sent);
+ printf("Transition rejection reason::\n");
+ printf("\texcess frame loss:%u traffic delay:%u low QoS:%u\n",
+ cntr->trans_rejn_insuffic_qos_cap,
+ cntr->trans_rejn_xcess_frm_loss,
+ cntr->trans_rejn_xcess_traffic_delay);
+ printf("\tlow RSSI:%u: high interference:%u service unavail:%u\n",
+ cntr->trans_rejn_low_rssi,
+ cntr->trans_rejn_high_interference,
+ cntr->trans_rejn_service_unavail);
+ printf("Beacon req_rcvd:%u\n", cntr->bcn_req_rcvd);
+ printf("Beacon rep sent:%u\n", cntr->bcn_rep_sent);
+ printf("NULL beacon rep sent:%u\n", cntr->null_bcn_rep_sent);
+ printf("Switch wlan to cell:%u\n", cntr->wifi_to_cell);
+ }
+ break;
+ default:
+ printf("%s: Unknown tlv %u\n", __FUNCTION__, type);
+ }
+ return BCME_OK;
+}
+
+static int
+wl_mbo_sub_cmd_dump_counters(void *wl, const wl_mbo_sub_cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ /* only get */
+ if (*argv == NULL) {
+ ret = wl_mbo_get_iov_resp(wl, cmd, wl_mbo_dump_counters_cbfn);
+ } else {
+ wl_mbo_usage(WL_MBO_CMD_DUMP_COUNTERS);
+ return BCME_USAGE_ERROR;
+ }
+ return ret;
+}
+
+static void
+wl_mbo_counters_help_fn(void)
+{
+ printf("wl mbo counters\n");
+}
+
+static int
+wl_mbo_sub_cmd_clear_counters(void *wl, const wl_mbo_sub_cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ bcm_iov_buf_t *iov_buf = NULL;
+ uint16 iovlen = 0;
+ /* only set */
+ if (*argv == NULL) {
+ iov_buf = (bcm_iov_buf_t *)calloc(1, WLC_IOCTL_MEDLEN);
+ if (iov_buf == NULL) {
+ ret = BCME_NOMEM;
+ goto fail;
+ }
+ /* fill header */
+ iov_buf->version = WL_MBO_IOV_VERSION;
+ iov_buf->id = cmd->cmd_id;
+ iov_buf->len = 0;
+ iovlen = sizeof(bcm_iov_buf_t);
+ ret = wlu_var_setbuf(wl, "mbo", (void *)iov_buf, iovlen);
+ } else {
+ wl_mbo_usage(WL_MBO_CMD_CLEAR_COUNTERS);
+ return BCME_USAGE_ERROR;
+ }
+fail:
+ if (iov_buf) {
+ free(iov_buf);
+ }
+ return ret;
+}
+
+static void
+wl_mbo_clear_counters_help_fn(void)
+{
+ printf("wl mbo clear_counters\n");
+}
+
+#ifdef WL_MBO_WFA_CERT
+static int
+wl_mbo_force_assoc_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
+{
+ UNUSED_PARAMETER(ctx);
+ UNUSED_PARAMETER(len);
+ if (data == NULL) {
+ printf("%s: Bad argument !!\n", __FUNCTION__);
+ return BCME_BADARG;
+ }
+ switch (type) {
+ case WL_MBO_XTLV_ENABLE:
+ printf("Force association: %s\n", (*data == 0) ? "disabled" : "enabled");
+ break;
+ default:
+ printf("%s: Unknown tlv %u\n", __FUNCTION__, type);
+ }
+ return BCME_OK;
+}
+
+static int
+wl_mbo_sub_cmd_force_assoc(void *wl, const wl_mbo_sub_cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ bcm_iov_buf_t *iov_buf = NULL;
+ uint8 *pxtlv = NULL;
+ uint16 buflen = 0, buflen_start = 0;
+ char *param = NULL, *val_p = NULL;
+ uint16 iovlen = 0;
+
+ /* get */
+ if (*argv == NULL) {
+ ret = wl_mbo_get_iov_resp(wl, cmd, wl_mbo_force_assoc_cbfn);
+ } else {
+ iov_buf = (bcm_iov_buf_t *)calloc(1, WLC_IOCTL_MEDLEN);
+ if (iov_buf == NULL) {
+ ret = BCME_NOMEM;
+ goto fail;
+ }
+ /* fill header */
+ iov_buf->version = WL_MBO_IOV_VERSION;
+ iov_buf->id = cmd->cmd_id;
+
+ pxtlv = (uint8 *)&iov_buf->data[0];
+ param = *argv++;
+ if (strcmp(param, "-e") == 0) {
+ val_p = *argv;
+ if (val_p == NULL || *val_p == '-') {
+ wl_mbo_usage(WL_MBO_CMD_FORCE_ASSOC);
+ ret = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ uint8 force = strtoul(val_p, NULL, 0);
+ if ((force != 0) && (force != 1)) {
+ fprintf(stderr, "wrong value %u\n", force);
+ ret = BCME_BADARG;
+ goto fail;
+ }
+ buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_ENABLE,
+ sizeof(force), &force, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ } else {
+ fprintf(stderr, "wrong parameter %s\n", param);
+ wl_mbo_usage(WL_MBO_CMD_FORCE_ASSOC);
+ ret = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ iov_buf->len = buflen_start - buflen;
+ iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
+ ret = wlu_var_setbuf(wl, "mbo", (void *)iov_buf, iovlen);
+ }
+fail:
+ if (iov_buf) {
+ free(iov_buf);
+ }
+ return ret;
+}
+
+static void
+wl_mbo_force_assoc_help_fn(void)
+{
+ printf("wl mbo force_assoc -e <value>\n");
+ printf("\tvalue: Enable/disable assoc attempt even if "
+ "association disallowed by AP <1/0>\n");
+ printf("\t\t 1 = Enable force association attempt when "
+ "AP is not accepting new connection\n");
+ printf("\t\t 0 = disable force association attempt\n");
+}
+
+static int
+wl_mbo_bsstrans_reject_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
+{
+ UNUSED_PARAMETER(ctx);
+ UNUSED_PARAMETER(len);
+ if (data == NULL) {
+ printf("%s: Bad argument !!\n", __FUNCTION__);
+ return BCME_BADARG;
+ }
+ switch (type) {
+ case WL_MBO_XTLV_ENABLE:
+ printf("Bss Transition Reject: %s\n",
+ (*data == 0) ? "disabled" : "enabled");
+ break;
+ case WL_MBO_XTLV_REASON_CODE:
+ printf("Reason Code: %u\n", *data);
+ break;
+ default:
+ printf("%s: Unknown tlv %u\n", __FUNCTION__, type);
+ }
+ return BCME_OK;
+}
+
+static int
+wl_mbo_sub_cmd_bsstrans_reject(void *wl, const wl_mbo_sub_cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ bcm_iov_buf_t *iov_buf = NULL;
+ uint8 *pxtlv = NULL;
+ uint16 buflen = 0, buflen_start = 0;
+ char *param = NULL, *val_p = NULL;
+ uint16 iovlen = 0;
+ bool reason_set = FALSE;
+ uint8 enable = 0;
+
+ /* get */
+ if (*argv == NULL) {
+ ret = wl_mbo_get_iov_resp(wl, cmd, wl_mbo_bsstrans_reject_cbfn);
+ } else {
+ iov_buf = (bcm_iov_buf_t *)calloc(1, WLC_IOCTL_MEDLEN);
+ if (iov_buf == NULL) {
+ return BCME_NOMEM;
+ }
+ /* fill header */
+ iov_buf->version = WL_MBO_IOV_VERSION;
+ iov_buf->id = cmd->cmd_id;
+
+ pxtlv = (uint8 *)&iov_buf->data[0];
+ buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
+
+ /* parse and pack config parameters */
+ while ((param = *argv++)) {
+ val_p = *argv++;
+ if (!val_p || *val_p == '-') {
+ fprintf(stderr, "%s: wrong usage %s\n", __FUNCTION__, param);
+ wl_mbo_usage(WL_MBO_CMD_BSSTRANS_REJECT);
+ ret = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ if (strcmp(param, "-e") == 0) {
+ enable = strtoul(val_p, NULL, 0);
+ if ((enable != 0) && (enable != 1)) {
+ fprintf(stderr, "wrong value %u\n", enable);
+ ret = BCME_BADARG;
+ goto fail;
+ }
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_ENABLE,
+ sizeof(enable), &enable, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ } else if (strcmp(param, "-r") == 0) {
+ uint8 reason = strtoul(val_p, NULL, 0);
+ if (reason > MBO_TRANS_REJ_REASON_SERVICE_UNAVAIL) {
+ fprintf(stderr, "wrong reason value %u\n", reason);
+ ret = BCME_BADARG;
+ goto fail;
+ }
+ reason_set = TRUE;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_REASON_CODE,
+ sizeof(reason), &reason, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ } else {
+ fprintf(stderr, "Unknown param %s\n", param);
+ }
+ }
+ if ((enable && reason_set) || (!enable)) {
+ iov_buf->len = buflen_start - buflen;
+ iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
+ ret = wlu_var_setbuf(wl, "mbo", (void *)iov_buf, iovlen);
+ } else {
+ wl_mbo_usage(WL_MBO_CMD_BSSTRANS_REJECT);
+ ret = BCME_USAGE_ERROR;
+ }
+ }
+fail:
+ if (iov_buf) {
+ free(iov_buf);
+ }
+ return ret;
+}
+
+static void
+wl_mbo_bsstrans_reject_help_fn(void)
+{
+ printf("wl mbo bsstrans_reject -e <value> -r <reason>\n");
+ printf("\tvalue: Enable/Disable bsstrans rejection <1/0>\n");
+ printf("\t\t 1 = Enable bsstrans rejection\n");
+ printf("\t\t 0 = Disable bsstrans rejection\n");
+ printf("\treason: reason code for rejection <0-6>\n");
+ printf("\t\t 0 = Unspecified reason\n");
+ printf("\t\t 1 = Excessive frame loss expected on transition\n");
+ printf("\t\t 2 = Excessive delay for current traffic stream on transition\n");
+ printf("\t\t 3 = Insufficient QoS capacity expected on transition\n");
+ printf("\t\t 4 = Low RSSI observed on suggested BSS\n");
+ printf("\t\t 5 = High interference observed on suggested BSS\n");
+ printf("\t\t 6 = Service unavailability on suggested BSS\n");
+}
+#endif /* WL_MBO_WFA_CERT */
diff --git a/wl/src/wl/exe/wluc_mfp.c b/wl/src/wl/exe/wluc_mfp.c
new file mode 100644
index 0000000..d62bf9f
--- /dev/null
+++ b/wl/src/wl/exe/wluc_mfp.c
@@ -0,0 +1,345 @@
+/*
+ * wl mfp command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_mfp.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static int wl_mfp_config(void *wl, cmd_t *cmd, char **argv);
+static int wl_mfp_sha256(void *wl, cmd_t *cmd, char **argv);
+static int wl_mfp_sa_query(void *wl, cmd_t *cmd, char **argv);
+static int wl_mfp_disassoc(void *wl, cmd_t *cmd, char **argv);
+static int wl_mfp_deauth(void *wl, cmd_t *cmd, char **argv);
+static int wl_mfp_assoc(void *wl, cmd_t *cmd, char **argv);
+static int wl_mfp_auth(void *wl, cmd_t *cmd, char **argv);
+static int wl_mfp_reassoc(void *wl, cmd_t *cmd, char **argv);
+
+static cmd_t wl_mfp_cmds[] = {
+ { "mfp_config", wl_mfp_config, -1, WLC_SET_VAR,
+ "Config PMF capability\n"
+ "\tusage: wl mfp 0/disable, 1/capable, 2/requred" },
+ { "mfp_sha256", wl_mfp_sha256, WLC_GET_VAR, WLC_SET_VAR,
+ "Config SHA256 capability\n"
+ "\tusage: wl sha256 0/disable, 1/enable" },
+ { "mfp_sa_query", wl_mfp_sa_query, -1, WLC_SET_VAR,
+ "Send a sa query req/resp to a peer\n"
+ "\tusage: wl mfp_sa_query flag action id" },
+ { "mfp_disassoc", wl_mfp_disassoc, WLC_GET_VAR, WLC_SET_VAR,
+ "send bogus disassoc\n"
+ "\tUsage: wl mfp_disassoc"},
+ { "mfp_deauth", wl_mfp_deauth, WLC_GET_VAR, WLC_SET_VAR,
+ "send bogus deauth\n"
+ "\tUsage: wl mfp_dedauth"},
+ { "mfp_assoc", wl_mfp_assoc, WLC_GET_VAR, WLC_SET_VAR,
+ "send assoc\n"
+ "\tUsage: wl mfp_assoc"},
+ { "mfp_auth", wl_mfp_auth, WLC_GET_VAR, WLC_SET_VAR,
+ "send auth\n"
+ "\tUsage: wl mfp_auth"},
+ { "mfp_reassoc", wl_mfp_reassoc, WLC_GET_VAR, WLC_SET_VAR,
+ "send reassoc\n"
+ "\tUsage: wl mfp_reassoc"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_mfp_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register mfp commands */
+ wl_module_cmds_register(wl_mfp_cmds);
+}
+
+static int
+wl_mfp_config(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc;
+ int err = 0;
+ int flag = 0;
+ const char *cmdname = "mfp";
+
+ UNUSED_PARAMETER(cmd);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc > 1 && argv[1]) {
+ flag = htod32(atoi(argv[1]));
+ *(int *)buf = flag;
+ }
+
+ err = wlu_iovar_set(wl, cmdname, buf, 256);
+
+ return (err);
+
+}
+
+static int
+wl_mfp_sha256(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc;
+ int err = 0;
+ int flag = 0;
+ const char *cmdname = "mfp_sha256";
+
+ UNUSED_PARAMETER(cmd);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc > 1 && argv[1]) {
+ flag = htod32(atoi(argv[1]));
+ *(int *)buf = flag;
+ err = wlu_iovar_set(wl, cmdname, buf, 256);
+ } else {
+ /* get */
+ err = wlu_iovar_getint(wl, cmdname, &flag);
+ if (err == BCME_OK)
+ printf("%d\n", flag);
+ }
+
+ return (err);
+
+}
+
+static int
+wl_mfp_sa_query(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_sa_query_t * query;
+ int argc;
+ int err = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if ((query = (wl_sa_query_t *) malloc(sizeof(wl_sa_query_t))) == NULL) {
+ printf("unable to allocate frame \n");
+ return BCME_NOMEM;
+ }
+ memset(query, 0, sizeof(wl_sa_query_t));
+
+ /* add the flag */
+ if (argc > 1 && argv[1]) {
+ query->flag = htod32(atoi(argv[1]));
+ }
+
+ /* add the action */
+ if (argc > 2 && argv[2]) {
+ query->action = htod32(atoi(argv[2]));
+ }
+
+ /* add the id */
+ if (argc > 3 && argv[3]) {
+ query->id = htod32(atoi(argv[3]));
+ }
+
+ err = wlu_var_setbuf(wl, "mfp_sa_query", query, sizeof(wl_sa_query_t));
+
+ free(query);
+
+ return (err);
+
+}
+
+static int
+wl_mfp_disassoc(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "mfp_disassoc";
+ int argc;
+ int flag;
+ char varbuf[256];
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+ memset(varbuf, 0, 256);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* add the action */
+ if (argc > 1 && argv[1]) {
+ flag = htod32(atoi(argv[1]));
+ *(int *)varbuf = flag;
+ }
+ if (argc > 2 && argv[2]) {
+ flag = htod32(atoi(argv[2]));
+ *(int *)(varbuf + sizeof(flag)) = flag;
+ }
+
+ err = wlu_iovar_set(wl, cmdname, varbuf, 256);
+
+ return err;
+}
+
+static int
+wl_mfp_deauth(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "mfp_deauth";
+ int argc;
+ int flag;
+ char varbuf[256];
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+
+ memset(varbuf, 0, 256);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* add the action */
+ if (argc > 1 && argv[1]) {
+ flag = htod32(atoi(argv[1]));
+ *(int *)varbuf = flag;
+ }
+ if (argc > 2 && argv[2]) {
+ flag = htod32(atoi(argv[2]));
+ *(int *)(varbuf + sizeof(flag)) = flag;
+ }
+
+ err = wlu_iovar_set(wl, cmdname, varbuf, 256);
+
+ return err;
+}
+
+static int
+wl_mfp_assoc(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "mfp_assoc";
+ int argc;
+ int flag;
+ char varbuf[256];
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+ memset(varbuf, 0, 256);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* add the action */
+ if (argc > 1 && argv[1]) {
+ flag = htod32(atoi(argv[1]));
+ *(int *)varbuf = flag;
+ }
+ if (argc > 2 && argv[2]) {
+ flag = htod32(atoi(argv[2]));
+ *(int *)(varbuf + sizeof(int)) = flag;
+ }
+
+ err = wlu_iovar_set(wl, cmdname, varbuf, 256);
+
+ return err;
+}
+
+static int
+wl_mfp_auth(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "mfp_auth";
+ int argc;
+ int flag;
+ char varbuf[256];
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+ memset(varbuf, 0, 256);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* add the action */
+ if (argc > 1 && argv[1]) {
+ flag = htod32(atoi(argv[1]));
+ *(int *)varbuf = flag;
+ }
+ if (argc > 2 && argv[2]) {
+ flag = htod32(atoi(argv[2]));
+ *(int *)(varbuf + sizeof(int)) = flag;
+ }
+
+ err = wlu_iovar_set(wl, cmdname, varbuf, 256);
+
+ return err;
+}
+
+static int
+wl_mfp_reassoc(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname = "mfp_reassoc";
+ int argc;
+ int flag;
+ char varbuf[256];
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+ memset(varbuf, 0, 256);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* add the action */
+ if (argc > 1 && argv[1]) {
+ flag = htod32(atoi(argv[1]));
+ *(int *)varbuf = flag;
+ }
+ if (argc > 2 && argv[2]) {
+ flag = htod32(atoi(argv[2]));
+ *(int *)(varbuf + sizeof(int)) = flag;
+ }
+
+ err = wlu_iovar_set(wl, cmdname, varbuf, 256);
+
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_msch.c b/wl/src/wl/exe/wluc_msch.c
new file mode 100644
index 0000000..244b2e2
--- /dev/null
+++ b/wl/src/wl/exe/wluc_msch.c
@@ -0,0 +1,2539 @@
+/*
+ * wl msch command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlu_msch.c 502986 2014-09-16 23:06:58Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifdef WIN32
+#define bzero(b, len) memset((b), 0, (len))
+#endif
+
+#ifdef LINUX
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* LINUX */
+
+#include <miniopt.h>
+#include <sys/stat.h>
+#include <trxhdr.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef WIN32
+#include <fcntl.h>
+#endif /* WIN32 */
+
+#include <event_log.h>
+
+#if defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION >= 0x00020000)
+extern int wlu_efi_stat(char *filename, struct stat *filest);
+extern long wlu_efi_ftell(void *fp);
+extern int wlu_efi_fseek(void *fp, long offset, int whence);
+extern size_t wlu_efi_fwrite(void *buf, size_t size, size_t nmemb, void *fp);
+extern size_t wlu_efi_fread(void *buf, size_t size, size_t nmemb, void *fp);
+extern void wlu_efi_fclose(void *fp);
+extern void * wlu_efi_fopen(char *filename, char *mode);
+
+#define fopen(filename, mode) (FILE *)wlu_efi_fopen(filename, mode)
+#define fread(buf, size, nmemb, fp) wlu_efi_fread(buf, size, nmemb, fp)
+#define fwrite(buf, size, nmemb, fp) wlu_efi_fwrite(buf, size, nmemb, fp)
+#define fseek(fp, offset, origin) wlu_efi_fseek(fp, offset, origin)
+#define ftell(fp) wlu_efi_ftell(fp)
+#define stat(fname, filest) wlu_efi_stat(fname, (struct stat *)(filest))
+#define fclose(fp) wlu_efi_fclose(fp)
+#ifdef stderr
+#undef stderr
+#define stderr stdout
+#endif
+#endif /* defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION >= 0x00020000) */
+
+#if defined(linux)
+static cmd_func_t wl_msch_event_check;
+#endif /* linux */
+static cmd_func_t wl_msch_request;
+static cmd_func_t wl_msch_collect;
+static cmd_func_t wl_msch_dump;
+static cmd_func_t wl_msch_profiler;
+
+static char *mschbufp = NULL, *mschdata = NULL;
+static FILE *mschfp = NULL;
+
+#define MSCH_COLLECT_USAGE \
+ "{enable|disable} [+/-register] [+/-callback] [+/-profiler] " \
+ "[+/-error] [+/-debug] [+/-info] [+/-trace]\n" \
+ "\tenable: alloc memory to save profiler data\n" \
+ "\tdisable: stop monitor, and free memory\n" \
+ "\t+/-register: save or skip register data\n" \
+ "\t+/-callback: save or skip register data\n" \
+ "\t+/-profiler: save or skip profiler data\n" \
+ "\t+/-error: save or skip error messages\n" \
+ "\t+/-debug: save or skip debug messages\n" \
+ "\t+/-info: save or skip infomation messages\n" \
+ "\t+/-trace: save or skip trace messages\n"
+
+#define MSCH_FMTFILE_USAGE \
+ "-D copydir -F \"logstrs_path=xxxx st_str_file_path=xxxx " \
+ "map_file_path=xxxx rom_st_str_file_path=xxxx rom_map_file_path=xxxx\"\n"
+
+static cmd_t wl_msch_cmds[] = {
+ { "msch_req", wl_msch_request, WLC_GET_VAR, WLC_SET_VAR,
+ "register multiple channel scheduler \n"
+ "\tUsage: msch_req <id> -w wlc_index -c \"channel_list\" -f flags -t type [params] "
+ "-p priority -s start_time -d duration -i interval"
+ "\t-w W, --wlc_index=W\tset wlc index\n"
+ "\t-c L, --channels=L\tcomma or space separated list of channels to scheduler\n"
+ "\t-f F, --flags=F\tset flags, 1 for contiguous cahhhel scheduler\n"
+ "\t-t T, --type=T\tset scheduler type: fix, sf, df dur-flex, bf params\n\n"
+ "\t-p P, --priority=P\tpriority for the scheduler\n"
+ "\t-s S, --start-time=S\tstart time(ms) for the scheduler\n"
+ "\t-d D, --duration=D\tduration(ms) for the scheduler\n"
+ "\t-i I, --interval=I\tinterval(ms) for the scheduler\n"},
+
+ { "msch_collect", wl_msch_collect, WLC_GET_VAR, WLC_SET_VAR,
+ "control multiple channel scheduler profiler saving data\n"
+ "\tUsage: msch_collect " MSCH_COLLECT_USAGE},
+
+ { "msch_dump", wl_msch_dump, WLC_GET_VAR, WLC_SET_VAR,
+ "dump multiple channel scheduler profiler data\n"
+ "\tUsage: msch_dump [filename] " MSCH_FMTFILE_USAGE},
+
+ { "msch_profiler", wl_msch_profiler, WLC_GET_VAR, WLC_SET_VAR,
+ "dump multiple channel scheduler profiler data\n"
+ "\tUsage: msch_profiler [uploadfilename] [filename] " MSCH_FMTFILE_USAGE},
+
+ { "msch_event", wl_msch_collect, WLC_GET_VAR, WLC_SET_VAR,
+ "control multiple channel scheduler profiler event data\n"
+ "\tUsage: msch_event " MSCH_COLLECT_USAGE},
+
+ { "msch_event_log", wl_msch_collect, WLC_GET_VAR, WLC_SET_VAR,
+ "control multiple channel scheduler profiler event Log data\n"
+ "\tUsage: msch_event_log " MSCH_COLLECT_USAGE},
+
+#if defined(linux)
+ { "msch_event_check", wl_msch_event_check, -1, -1,
+ "Listen and print Multiple channel scheduler events\n"
+ "\tmsch_event_check syntax is: msch_event_check ifname [filename]"
+ "[+/-register] [+/-callback] [+/-profiler] "
+ "[+/-error] [+/-debug] [+/-info] [+/-trace] " MSCH_FMTFILE_USAGE},
+#endif /* linux */
+ { NULL, NULL, 0, 0, NULL }
+};
+
+/* module initialization */
+void
+wluc_msch_module_init(void)
+{
+ /* get the global buf */
+ if (WLC_IOCTL_MAXLEN >= 2 * WL_MSCH_PROFILER_BUFFER_SIZE) {
+ mschdata = wl_get_buf();
+ } else {
+ mschdata = (char *)malloc(2 * WL_MSCH_PROFILER_BUFFER_SIZE);
+ if (!mschdata)
+ return;
+ }
+ mschbufp = (char *)&mschdata[WL_MSCH_PROFILER_BUFFER_SIZE];
+
+ /* register proxd commands */
+ wl_module_cmds_register(wl_msch_cmds);
+}
+
+static int
+wl_parse_msch_chanspec_list(char *list_str, chanspec_t *chanspec_list, int chanspec_num)
+{
+ int num = 0;
+ chanspec_t chanspec;
+ char *next, str[8];
+ size_t len;
+
+ if ((next = list_str) == NULL)
+ return BCME_ERROR;
+
+ while ((len = strcspn(next, " ,")) > 0) {
+ if (len >= sizeof(str)) {
+ fprintf(stderr, "string \"%s\" before ',' or ' ' is too long\n", next);
+ return BCME_ERROR;
+ }
+ strncpy(str, next, len);
+ str[len] = 0;
+ chanspec = wf_chspec_aton(str);
+ if (chanspec == 0) {
+ fprintf(stderr, "could not parse chanspec starting at "
+ "\"%s\" in list:\n%s\n", str, list_str);
+ return BCME_ERROR;
+ }
+ if (num == chanspec_num) {
+ fprintf(stderr, "too many chanspecs (more than %d) in chanspec list:\n%s\n",
+ chanspec_num, list_str);
+ return BCME_ERROR;
+ }
+ chanspec_list[num++] = htodchanspec(chanspec);
+ next += len;
+ next += strspn(next, " ,");
+ }
+
+ return num;
+}
+
+static int
+wl_parse_msch_bf_param(char *param_str, uint32 *param)
+{
+ int num;
+ uint32 val;
+ char* str;
+ char* endptr = NULL;
+
+ if (param_str == NULL)
+ return BCME_ERROR;
+
+ str = param_str;
+ num = 0;
+ while (*str != '\0') {
+ val = (uint32)strtol(str, &endptr, 0);
+ if (endptr == str) {
+ fprintf(stderr,
+ "could not parse bf param starting at"
+ " substring \"%s\" in list:\n%s\n",
+ str, param_str);
+ return -1;
+ }
+ str = endptr + strspn(endptr, " ,");
+
+ if (num >= 4) {
+ fprintf(stderr, "too many bf param (more than 6) in param str:\n%s\n",
+ param_str);
+ return BCME_ERROR;
+ }
+
+ param[num++] = htod32(val);
+ }
+
+ return num;
+}
+
+static int
+wl_msch_request(void *wl, cmd_t *cmd, char **argv)
+{
+ int params_size = sizeof(msch_register_params_t);
+ msch_register_params_t *params;
+ uint32 val = 0;
+ uint16 val16;
+ char key[64];
+ int keylen;
+ char *p, *eq, *valstr, *endptr = NULL;
+ char opt;
+ bool good_int;
+ int err = BCME_OK;
+ int i;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ params = (msch_register_params_t*)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for msch register params\n",
+ params_size);
+ return BCME_NOMEM;
+ }
+ memset(params, 0, params_size);
+
+ /* skip the command name */
+ argv++;
+
+ params->id = 0;
+
+ while ((p = *argv) != NULL) {
+ argv++;
+ memset(key, 0, sizeof(key));
+ opt = '\0';
+ valstr = NULL;
+ good_int = FALSE;
+
+ if (!strncmp(p, "--", 2)) {
+ eq = strchr(p, '=');
+ if (eq == NULL) {
+ fprintf(stderr,
+ "wl_msch_request: missing \" = \" in long param \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ keylen = eq - (p + 2);
+ if (keylen > 63)
+ keylen = 63;
+ memcpy(key, p + 2, keylen);
+
+ valstr = eq + 1;
+ if (*valstr == '\0') {
+ fprintf(stderr, "wl_msch_request: missing value after "
+ "\" = \" in long param \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ else if (!strncmp(p, "-", 1)) {
+ opt = p[1];
+ if (strlen(p) > 2) {
+ fprintf(stderr, "wl_msch_request: only single char options, "
+ "error on param \"%s\"\n", p);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (*argv == NULL) {
+ fprintf(stderr,
+ "wl_msch_request: missing value parameter after \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ valstr = *argv;
+ argv++;
+ } else {
+ val = (uint32)strtol(p, &endptr, 0);
+ if (*endptr == '\0') {
+ /* not all the value string was parsed by strtol */
+ good_int = TRUE;
+ }
+ if (!good_int) {
+ fprintf(stderr,
+ "wl_msch_request: parameter error \"%s\"\n", p);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ val16 = (uint16)val;
+ params->id = htod16(val16);
+ continue;
+ }
+
+ /* parse valstr as int just in case */
+ val = (uint32)strtol(valstr, &endptr, 0);
+ if (*endptr == '\0') {
+ /* not all the value string was parsed by strtol */
+ good_int = TRUE;
+ }
+
+ if (opt == 'h' || !strcmp(key, "help")) {
+ printf("%s", cmd->help);
+ goto exit;
+ } else if (opt == 'w' || !strcmp(key, "wlc_index")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as an wlc_index\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ val16 = (uint16)val;
+ params->wlc_index = htod16(val16);
+ } else if (opt == 'c' || !strcmp(key, "channels")) {
+ i = wl_parse_msch_chanspec_list(valstr,
+ (chanspec_t *)params->chanspec_list, WL_MSCH_NUMCHANNELS);
+ if (i == BCME_ERROR) {
+ fprintf(stderr, "error parsing channel list arg\n");
+ err = BCME_BADARG;
+ goto exit;
+ }
+ val = (uint32)i;
+ params->chanspec_cnt = htod32(val);
+ } else if (opt == 'n' || !strcmp(key, "id")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as an register id\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ val16 = (uint16)val;
+ params->id = htod16(val16);
+ } else if (opt == 'f' || !strcmp(key, "flags")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as an flages\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ val16 = (uint16)val;
+ params->flags = htod16(val16);
+ } else if (opt == 't' || !strcmp(key, "type")) {
+ if (!strcmp(valstr, "f") || !strncmp(valstr, "fix", 3)) {
+ params->req_type = (uint32)WL_MSCH_RT_BOTH_FIXED;
+ } else if (!strcmp(valstr, "sf") || !strcmp(valstr, "start-flex")) {
+ params->req_type = (uint32)WL_MSCH_RT_START_FLEX;
+ } else if (!strcmp(valstr, "df") || !strcmp(valstr, "dur-flex")) {
+ if (*argv == NULL) {
+ fprintf(stderr,
+ "wl_msch_request: missing param of dur-flex\n");
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ valstr = *argv;
+ argv++;
+
+ val = (uint32)strtol(valstr, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "could not parse \"%s\" as dur-flex value\n", valstr);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ params->req_type = (uint32)WL_MSCH_RT_DUR_FLEX;
+ params->dur_flex = htod32(val);
+ } else if (!strcmp(valstr, "bf") || !strcmp(valstr, "both-flex")) {
+ if (*argv == NULL) {
+ fprintf(stderr,
+ "wl_msch_request: missing param of both-flex\n");
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ valstr = *argv;
+ argv++;
+
+ if (wl_parse_msch_bf_param(valstr, ¶ms->min_dur) != 4) {
+ fprintf(stderr, "error parsing both flex params\n");
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->req_type = (uint32)WL_MSCH_RT_BOTH_FLEX;
+ } else {
+ fprintf(stderr,
+ "error type param \"%s\"\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ params->req_type = htod32(params->req_type);
+ } else if (opt == 'p' || !strcmp(key, "priority")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as priority\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ val16 = (uint16)val;
+ params->priority = htod16(val16);
+ } else if (opt == 's' || !strcmp(key, "start-time")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as start time\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->start_time = htod32(val);
+ } else if (opt == 'd' || !strcmp(key, "duration")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as duration\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->duration = htod32(val);
+ } else if (opt == 'i' || !strcmp(key, "interval")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as interval\n",
+ valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->interval = htod32(val);
+ } else {
+ fprintf(stderr,
+ "wl_msch_request: error option param \"%s\"\n", p);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+
+ err = wlu_var_setbuf(wl, cmd->name, params, params_size);
+exit:
+ free(params);
+ return err;
+}
+
+static int
+wl_msch_collect(void *wl, cmd_t *cmd, char **argv)
+{
+ bool eventcmd = (!strcmp(cmd->name, "msch_event"));
+ bool eventlogcmd = (!strcmp(cmd->name, "msch_event_log"));
+ bool collectcmd = (!strcmp(cmd->name, "msch_collect"));
+ char *p, *endptr;
+ int opt, v, val, err = BCME_OK;
+
+ UNUSED_PARAMETER(wl);
+
+ if ((err = wlu_iovar_getint(wl, cmd->name, &val)) < 0)
+ return err;
+
+ err = BCME_OK;
+ if (!*++argv) {
+ printf("MSCH %s: %sable {", (eventcmd? "Event" : (eventlogcmd? "EventLog" :
+ "Profile")), ((val & WL_MSCH_CMD_ENABLE_BIT)? "En" : "Dis"));
+ if (val & WL_MSCH_CMD_REGISTER_BIT)
+ printf("registe ");
+ if (val & WL_MSCH_CMD_CALLBACK_BIT)
+ printf("callbac ");
+ if (val & WL_MSCH_CMD_PROFILE_BIT)
+ printf("profiler ");
+ if (val & WL_MSCH_CMD_ERROR_BIT)
+ printf("error ");
+ if (val & WL_MSCH_CMD_DEBUG_BIT)
+ printf("debug ");
+ if (val & WL_MSCH_CMD_INFOM_BIT)
+ printf("info ");
+ if (val & WL_MSCH_CMD_TRACE_BIT)
+ printf("trace ");
+ printf("\x08}\n");
+ return err;
+ }
+
+ while ((p = *argv) != NULL) {
+ opt = 0;
+ if (p[0] == '+') {
+ opt = 1;
+ p++;
+ }
+ else if (p[0] == '-') {
+ opt = 2;
+ p++;
+ }
+
+ if (opt == 0) {
+ v = (uint32)strtol(p, &endptr, 0);
+ if (*endptr == '\0') {
+ if (v == 1)
+ val |= WL_MSCH_CMD_ENABLE_BIT;
+ else if (v == 0)
+ val &= ~WL_MSCH_CMD_ENABLE_BIT;
+ else {
+ err = BCME_EPERM;
+ break;
+ }
+ }
+ else if (!strcmp(p, "enable") || !strcmp(p, "start")) {
+ val |= WL_MSCH_CMD_ENABLE_BIT;
+ }
+ else if (!strcmp(p, "disable") || !strcmp(p, "stop"))
+ val &= ~WL_MSCH_CMD_ENABLE_BIT;
+ else if (collectcmd && !strcmp(p, "dump"))
+ return wl_msch_dump(wl, cmd, argv);
+ else {
+ err = BCME_EPERM;
+ break;
+ }
+ } else {
+ if (opt == 2 && (!strcmp(p, "-help") || !strcmp(p, "h"))) {
+ printf("%s", cmd->help);
+ return BCME_OK;
+ } else if (opt == 2 && (!strcmp(p, "all") || !strcmp(p, "a"))) {
+ val &= ~WL_MSCH_CMD_ALL_BITS;
+ } else if (!strcmp(p, "profiler") || !strcmp(p, "p")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_PROFILE_BIT;
+ else
+ val &= ~WL_MSCH_CMD_PROFILE_BIT;
+ }
+ else if (!strcmp(p, "callback") || !strcmp(p, "c")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_CALLBACK_BIT;
+ else
+ val &= ~WL_MSCH_CMD_CALLBACK_BIT;
+ }
+ else if (!strcmp(p, "register") || !strcmp(p, "r")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_REGISTER_BIT;
+ else
+ val &= ~WL_MSCH_CMD_REGISTER_BIT;
+ }
+ else if (!strcmp(p, "error") || !strcmp(p, "e")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_ERROR_BIT;
+ else
+ val &= ~WL_MSCH_CMD_ERROR_BIT;
+ }
+ else if (!strcmp(p, "debug") || !strcmp(p, "d")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_DEBUG_BIT;
+ else
+ val &= ~WL_MSCH_CMD_DEBUG_BIT;
+ }
+ else if (!strcmp(p, "info") || !strcmp(p, "i")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_INFOM_BIT;
+ else
+ val &= ~WL_MSCH_CMD_INFOM_BIT;
+ }
+ else if (!strcmp(p, "trace") || !strcmp(p, "t")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_TRACE_BIT;
+ else
+ val &= ~WL_MSCH_CMD_TRACE_BIT;
+ }
+ else if (collectcmd && opt == 2 && !strcmp(p, "s") && *++argv) {
+ p = *argv;
+ v = (uint32)strtol(p, &endptr, 0);
+ if (*endptr == '\0') {
+ val &= ~WL_MSCH_CMD_SIZE_MASK;
+ val |= (v << WL_MSCH_CMD_SIZE_SHIFT);
+ } else {
+ err = BCME_EPERM;
+ break;
+ }
+ }
+ else {
+ err = BCME_EPERM;
+ break;
+ }
+ }
+
+ argv++;
+ }
+
+ if (eventcmd && (val & WL_MSCH_CMD_ENABLE_BIT)) {
+ uint8 event_inds_mask[WL_EVENTING_MASK_LEN];
+ /* read current mask state */
+ if ((err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask,
+ WL_EVENTING_MASK_LEN))) {
+ fprintf(stderr, "couldn't read event_msgs\n");
+ goto exit;
+ }
+ event_inds_mask[WLC_E_MSCH / 8] |= (1 << (WLC_E_MSCH % 8));
+ if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask,
+ WL_EVENTING_MASK_LEN))) {
+ fprintf(stderr, "couldn't write event_msgs\n");
+ goto exit;
+ }
+ }
+
+ val &= ~WL_MSCH_CMD_VER_MASK;
+ val |= (WL_MSCH_PROFILER_VER << WL_MSCH_CMD_VER_SHIFT);
+ if (err == BCME_OK)
+ err = wlu_iovar_setint(wl, cmd->name, val);
+exit:
+ return err;
+}
+
+typedef struct {
+ int num_fmts;
+ char **fmts;
+ char *raw_fmts;
+ char *raw_sstr;
+ uint32 fmts_size;
+ uint32 raw_fmts_size;
+ uint32 raw_sstr_size;
+ uint32 ramstart;
+ uint32 rodata_start;
+ uint32 rodata_end;
+ char *rom_raw_sstr;
+ uint32 rom_raw_sstr_size;
+ uint32 rom_ramstart;
+ uint32 rom_rodata_start;
+ uint32 rom_rodata_end;
+} wl_event_log_t;
+
+wl_event_log_t raw_event;
+
+#define BYTES_AHEAD_NUM 11 /* address in map file is before these many bytes */
+#define READ_NUM_BYTES 1000 /* read map file each time this No. of bytes */
+#define GO_BACK_FILE_POS_NUM_BYTES 100 /* set file pos back to cur pos */
+static char *ramstart_str = "text_start"; /* string in mapfile has addr ramstart */
+static char *rodata_start_str = "rodata_start"; /* string in mapfile has addr rodata start */
+static char *rodata_end_str = "rodata_end"; /* string in mapfile has addr rodata end */
+#define RAMSTART_BIT 0x01
+#define RDSTART_BIT 0x02
+#define RDEND_BIT 0x04
+#define ALL_MAP_VAL (RAMSTART_BIT | RDSTART_BIT | RDEND_BIT)
+
+static char *logstrs_path = "/root/logstrs.bin";
+static char *st_str_file_path = "/root/rtecdc.bin";
+static char *map_file_path = "/root/rtecdc.map";
+static char *rom_st_str_file_path = "/root/roml.bin";
+static char *rom_map_file_path = "/root/roml.map";
+static char *ram_file_str = "rtecdc";
+static char *rom_file_str = "roml";
+
+static int
+wl_read_map(char *fname, uint32 *ramstart, uint32 *rodata_start, uint32 *rodata_end)
+{
+ FILE *filep = NULL;
+ char *raw_fmts = NULL;
+ int read_size = READ_NUM_BYTES;
+ int keep_size = GO_BACK_FILE_POS_NUM_BYTES;
+ int error = 0;
+ char * cptr = NULL;
+ char c;
+ uint8 count = 0;
+
+ if (fname == NULL) {
+ fprintf(stderr, "%s: ERROR fname is NULL \n", __FUNCTION__);
+ return BCME_ERROR;
+ }
+
+ filep = fopen(fname, "rb");
+ if (!filep) {
+ perror(fname);
+ fprintf(stderr, "Cannot open file %s\n", fname);
+ return BCME_ERROR;
+ }
+
+ *ramstart = 0;
+ *rodata_start = 0;
+ *rodata_end = 0;
+
+ /* Allocate 1 byte more than read_size to terminate it with NULL */
+ raw_fmts = (char *)malloc(read_size + keep_size + 1);
+ if (raw_fmts == NULL) {
+ fprintf(stderr, "%s: Failed to allocate raw_fmts memory \n", __FUNCTION__);
+ goto fail;
+ }
+ memset(raw_fmts, ' ', GO_BACK_FILE_POS_NUM_BYTES);
+
+ /* read ram start, rodata_start and rodata_end values from map file */
+ while (count != ALL_MAP_VAL)
+ {
+ error = fread(&raw_fmts[keep_size], 1, read_size, filep);
+ if (error < 0) {
+ fprintf(stderr, "%s: map file read failed err:%d \n", __FUNCTION__,
+ error);
+ goto fail;
+ }
+
+ /* End raw_fmts with NULL as strstr expects NULL terminated strings */
+ raw_fmts[read_size + keep_size] = '\0';
+
+ /* Get ramstart address */
+ if ((cptr = strstr(raw_fmts, ramstart_str))) {
+ cptr = cptr - BYTES_AHEAD_NUM;
+ sscanf(cptr, "%x %c text_start", ramstart, &c);
+ count |= RAMSTART_BIT;
+ }
+
+ /* Get ram rodata start address */
+ if ((cptr = strstr(raw_fmts, rodata_start_str))) {
+ cptr = cptr - BYTES_AHEAD_NUM;
+ sscanf(cptr, "%x %c rodata_start", rodata_start, &c);
+ count |= RDSTART_BIT;
+ }
+
+ /* Get ram rodata end address */
+ if ((cptr = strstr(raw_fmts, rodata_end_str))) {
+ cptr = cptr - BYTES_AHEAD_NUM;
+ sscanf(cptr, "%x %c rodata_end", rodata_end, &c);
+ count |= RDEND_BIT;
+ }
+
+ if (error < read_size) {
+ /*
+ * since we reset file pos back to earlier pos by
+ * GO_BACK_FILE_POS_NUM_BYTES bytes we won't reach EOF.
+ * The reason for this is if string is spreaded across
+ * bytes, the read function should not miss it.
+ * So if ret value is less than read_size, reached EOF don't read further
+ */
+ break;
+ }
+ /*
+ * go back to predefined NUM of bytes so that we won't miss
+ * the string and addr even if it comes as splited in next read.
+ */
+ memcpy(raw_fmts, &raw_fmts[read_size], keep_size);
+ }
+
+fail:
+ if (filep) {
+ fclose(filep);
+ }
+
+ if (raw_fmts) {
+ free(raw_fmts);
+ }
+
+ if (count != ALL_MAP_VAL) {
+ fprintf(stderr, "%s: readmap error 0X%x \n", __FUNCTION__, count);
+ return BCME_ERROR;
+ }
+ return BCME_OK;
+}
+
+static void
+wl_init_static_strs_array(char *str_file, char *map_file)
+{
+ FILE *filep = NULL;
+ char *raw_fmts = NULL;
+ uint32 logstrs_size = 0;
+
+ int error = 0;
+ uint32 ramstart = 0;
+ uint32 rodata_start = 0;
+ uint32 rodata_end = 0;
+ uint32 logfilebase = 0;
+
+ error = wl_read_map(map_file, &ramstart, &rodata_start, &rodata_end);
+ if (error != BCME_OK) {
+ fprintf(stderr, "readmap Error!! \n");
+ /* don't do event log parsing in actual case */
+ if (strstr(str_file, ram_file_str) != NULL) {
+ raw_event.raw_sstr = NULL;
+ } else if (strstr(str_file, rom_file_str) != NULL) {
+ raw_event.rom_raw_sstr = NULL;
+ }
+ return;
+ }
+
+ if (str_file == NULL) {
+ fprintf(stderr, "%s: ERROR fname is NULL \n", __FUNCTION__);
+ return;
+ }
+
+ filep = fopen(str_file, "rb");
+ if (!filep) {
+ perror(str_file);
+ fprintf(stderr, "Cannot open file %s\n", str_file);
+ return;
+ }
+
+ /* Full file size is huge. Just read required part */
+ logstrs_size = rodata_end - rodata_start;
+
+ raw_fmts = (char *)malloc(logstrs_size);
+ if (raw_fmts == NULL) {
+ fprintf(stderr, "%s: Failed to allocate raw_fmts memory \n", __FUNCTION__);
+ goto fail;
+ }
+
+ logfilebase = rodata_start - ramstart;
+
+ error = fseek(filep, logfilebase, SEEK_SET);
+ if (error < 0) {
+ fprintf(stderr, "%s: %s llseek failed %d \n", __FUNCTION__, str_file, error);
+ goto fail;
+ }
+
+ error = fread(raw_fmts, 1, logstrs_size, filep);
+ if (error != (int)logstrs_size) {
+ fprintf(stderr, "%s: %s read failed %d \n", __FUNCTION__, str_file, error);
+ goto fail;
+ }
+
+ if (strstr(str_file, ram_file_str) != NULL) {
+ raw_event.raw_sstr = raw_fmts;
+ raw_event.raw_sstr_size = logstrs_size;
+ raw_event.ramstart = ramstart;
+ raw_event.rodata_start = rodata_start;
+ raw_event.rodata_end = rodata_end;
+ } else if (strstr(str_file, rom_file_str) != NULL) {
+ raw_event.rom_raw_sstr = raw_fmts;
+ raw_event.rom_raw_sstr_size = logstrs_size;
+ raw_event.rom_ramstart = ramstart;
+ raw_event.rom_rodata_start = rodata_start;
+ raw_event.rom_rodata_end = rodata_end;
+ }
+
+ fclose(filep);
+
+ free(raw_fmts);
+
+ return;
+
+fail:
+ if (raw_fmts) {
+ free(raw_fmts);
+ }
+
+ if (filep) {
+ fclose(filep);
+ }
+
+ if (strstr(str_file, ram_file_str) != NULL) {
+ raw_event.raw_sstr = NULL;
+ } else if (strstr(str_file, rom_file_str) != NULL) {
+ raw_event.rom_raw_sstr = NULL;
+ }
+
+ return;
+}
+
+static void
+wl_init_logstrs_array(char *logstrs_path)
+{
+ FILE *filep = NULL;
+ char *raw_fmts = NULL;
+ int logstrs_size = 0;
+ int error = 0;
+ logstr_header_t *hdr = NULL;
+ uint32 *lognums = NULL;
+ char *logstrs = NULL;
+ int ram_index = 0;
+ char **fmts = NULL;
+ int num_fmts = 0;
+ int i = 0;
+
+ if (logstrs_path == NULL) {
+ fprintf(stderr, "%s: ERROR fname is NULL \n", __FUNCTION__);
+ return;
+ }
+
+ filep = fopen(logstrs_path, "rb");
+ if (!filep) {
+ perror(logstrs_path);
+ fprintf(stderr, "Cannot open file %s\n", logstrs_path);
+ return;
+ }
+
+ if (fseek(filep, 0, SEEK_END) < 0 ||
+ (logstrs_size = ftell(filep)) < 0) {
+ fprintf(stderr, "%s: Could not determine size of %s \n", __FUNCTION__,
+ logstrs_path);
+ goto fail;
+ }
+
+ raw_fmts = (char *)malloc(logstrs_size);
+ if (raw_fmts == NULL) {
+ fprintf(stderr, "%s: Failed to allocate memory \n", __FUNCTION__);
+ goto fail;
+ }
+
+ fseek(filep, 0, SEEK_SET);
+ error = fread(raw_fmts, 1, logstrs_size, filep);
+ if (error != logstrs_size) {
+ fprintf(stderr, "%s: Failed to read file %s", __FUNCTION__, logstrs_path);
+ goto fail;
+ }
+
+ /* Remember header from the logstrs.bin file */
+ hdr = (logstr_header_t *) (raw_fmts + logstrs_size -
+ sizeof(logstr_header_t));
+
+ if (hdr->log_magic == LOGSTRS_MAGIC) {
+ /*
+ * logstrs.bin start with header.
+ */
+ num_fmts = hdr->rom_logstrs_offset / sizeof(uint32);
+ ram_index = (hdr->ram_lognums_offset -
+ hdr->rom_lognums_offset) / sizeof(uint32);
+ lognums = (uint32 *)&raw_fmts[hdr->rom_lognums_offset];
+ logstrs = (char *)&raw_fmts[hdr->rom_logstrs_offset];
+ } else {
+ /*
+ * Legacy logstrs.bin format without header.
+ */
+ num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32);
+ if (num_fmts == 0) {
+ /* Legacy ROM/RAM logstrs.bin format:
+ * - ROM 'lognums' section
+ * - RAM 'lognums' section
+ * - ROM 'logstrs' section.
+ * - RAM 'logstrs' section.
+ *
+ * 'lognums' is an array of indexes for the strings in the
+ * 'logstrs' section. The first uint32 is 0 (index of first
+ * string in ROM 'logstrs' section).
+ *
+ * The 4324b5 is the only ROM that uses this legacy format. Use the
+ * fixed number of ROM fmtnums to find the start of the RAM
+ * 'lognums' section. Use the fixed first ROM string ("Con\n") to
+ * find the ROM 'logstrs' section.
+ */
+ #define NUM_4324B5_ROM_FMTS 186
+ #define FIRST_4324B5_ROM_LOGSTR "Con\n"
+ ram_index = NUM_4324B5_ROM_FMTS;
+ lognums = (uint32 *) raw_fmts;
+ num_fmts = ram_index;
+ logstrs = (char *) &raw_fmts[num_fmts << 2];
+ while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) {
+ num_fmts++;
+ logstrs = (char *) &raw_fmts[num_fmts << 2];
+ }
+ } else {
+ /* Legacy RAM-only logstrs.bin format:
+ * - RAM 'lognums' section
+ * - RAM 'logstrs' section.
+ *
+ * 'lognums' is an array of indexes for the strings in the
+ * 'logstrs' section. The first uint32 is an index to the
+ * start of 'logstrs'. Therefore, if this index is divided
+ * by 'sizeof(uint32)' it provides the number of logstr
+ * entries.
+ */
+ ram_index = 0;
+ lognums = (uint32 *)raw_fmts;
+ logstrs = (char *)&raw_fmts[num_fmts << 2];
+ }
+ }
+ if (num_fmts)
+ fmts = (char **)malloc(num_fmts * sizeof(char *));
+ if (fmts == NULL) {
+ fprintf(stderr, "%s: Failed to allocate fmts memory\n", __FUNCTION__);
+ goto fail;
+ }
+
+ raw_event.fmts_size = num_fmts * sizeof(char *);
+
+ for (i = 0; i < num_fmts; i++) {
+ /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base
+ * (they are 0-indexed relative to 'rom_logstrs_offset').
+ *
+ * RAM lognums are already indexed to point to the correct RAM logstrs (they
+ * are 0-indexed relative to the start of the logstrs.bin file).
+ */
+ if (i == ram_index) {
+ logstrs = raw_fmts;
+ }
+ fmts[i] = &logstrs[lognums[i]];
+ }
+ raw_event.fmts = fmts;
+ raw_event.raw_fmts_size = logstrs_size;
+ raw_event.raw_fmts = raw_fmts;
+ raw_event.num_fmts = num_fmts;
+
+ fclose(filep);
+ return;
+
+fail:
+ if (raw_fmts) {
+ free(raw_fmts);
+ }
+
+ if (filep) {
+ fclose(filep);
+ }
+}
+
+static int wl_init_frm_array(char *dir, char *files)
+{
+ char *logstrs = NULL, *logstrs_d = NULL;
+ char *st_str_file = NULL, *st_str_file_d = NULL;
+ char *map_file = NULL, *map_file_d = NULL;
+ char *rom_st_str_file = NULL, *rom_st_str_file_d = NULL;
+ char *rom_map_file = NULL, *rom_map_file_d = NULL;
+ char *next, *str, *eq, *valstr;
+ size_t len;
+
+ if ((next = files)) {
+ while ((len = strcspn(next, " ,")) > 0) {
+ str = next;
+ next += len;
+ next += strspn(next, " ,");
+
+ str[len] = '\0';
+ eq = strchr(str, '=');
+ if (eq == NULL) {
+ fprintf(stderr, "wl_init_frm_array: missing \" = \" in file "
+ "param \"%s\"\n", str);
+ return BCME_USAGE_ERROR;
+ }
+ valstr = eq + 1;
+ if (*valstr == '\0') {
+ fprintf(stderr, "wl_init_frm_array: missing value after "
+ "\" = \" in file param \"%s\"\n", str);
+ return BCME_USAGE_ERROR;
+ }
+ *eq = '\0';
+
+ if (!strcmp(str, "logstrs_path"))
+ logstrs = valstr;
+ else if (!strcmp(str, "st_str_file_path"))
+ st_str_file = valstr;
+ else if (!strcmp(str, "map_file_path"))
+ map_file = valstr;
+ else if (!strcmp(str, "rom_st_str_file_path"))
+ rom_st_str_file = valstr;
+ else if (!strcmp(str, "rom_map_file_path"))
+ rom_map_file = valstr;
+ else {
+ fprintf(stderr, "wl_init_frm_array: error file %s\n", str);
+ return BCME_USAGE_ERROR;
+ }
+ }
+ }
+
+ if (dir) {
+ len = strlen(dir);
+ if (!logstrs) {
+ logstrs_d = (char *)malloc(len + 32);
+ logstrs = logstrs_d;
+ if (logstrs) {
+ strcpy(logstrs, dir);
+ strcat(logstrs, "/logstrs.bin");
+ }
+ }
+ if (!st_str_file) {
+ st_str_file_d = (char *)malloc(len + 32);
+ st_str_file = st_str_file_d;
+ if (st_str_file) {
+ strcpy(st_str_file, dir);
+ strcat(st_str_file, "/rtecdc.bin");
+ }
+ }
+ if (!map_file) {
+ map_file_d = (char *)malloc(len + 32);
+ map_file = map_file_d;
+ if (map_file) {
+ strcpy(map_file, dir);
+ strcat(map_file, "/rtecdc.map");
+ }
+ }
+ if (!rom_st_str_file) {
+ rom_st_str_file_d = (char *)malloc(len + 32);
+ rom_st_str_file = rom_st_str_file_d;
+ if (rom_st_str_file) {
+ strcpy(rom_st_str_file, dir);
+ strcat(rom_st_str_file, "/roml.bin");
+ }
+ }
+ if (!rom_map_file) {
+ rom_map_file_d = (char *)malloc(len + 32);
+ rom_map_file = rom_map_file_d;
+ if (rom_map_file) {
+ strcpy(rom_map_file, dir);
+ strcat(rom_map_file, "/roml.map");
+ }
+ }
+ }
+
+ if (!logstrs)
+ logstrs = logstrs_path;
+ if (!st_str_file)
+ st_str_file = st_str_file_path;
+ if (!map_file)
+ map_file = map_file_path;
+ if (!rom_st_str_file)
+ rom_st_str_file = rom_st_str_file_path;
+ if (!rom_map_file)
+ rom_map_file = rom_map_file_path;
+
+ wl_init_logstrs_array(logstrs);
+ wl_init_static_strs_array(st_str_file, map_file);
+ wl_init_static_strs_array(rom_st_str_file, rom_map_file);
+
+ if (dir) {
+ if (logstrs_d) {
+ free(logstrs_d);
+ }
+ if (st_str_file_d) {
+ free(st_str_file_d);
+ }
+ if (map_file_d) {
+ free(map_file_d);
+ }
+ if (rom_st_str_file_d) {
+ free(rom_st_str_file_d);
+ }
+ if (rom_map_file_d) {
+ free(rom_map_file_d);
+ }
+ }
+
+ return BCME_OK;
+}
+
+#define MSCH_EVENTS_PRINT(nbytes) \
+ do { \
+ printf("%s", mschbufp); \
+ if (mschfp) \
+ fwrite(mschbufp, 1, nbytes, mschfp); \
+ } while (0)
+
+#define MSCH_EVENTS_SPPRINT(space) \
+ do { \
+ if (space > 0) { \
+ int ii; \
+ for (ii = 0; ii < space; ii++) mschbufp[ii] = ' '; \
+ mschbufp[space] = '\0'; \
+ MSCH_EVENTS_PRINT(space); \
+ } \
+ } while (0)
+
+#define MSCH_EVENTS_PRINTF(fmt) \
+ do { \
+ int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt); \
+ MSCH_EVENTS_PRINT(nbytes); \
+ } while (0)
+
+#define MSCH_EVENTS_PRINTF1(fmt, a) \
+ do { \
+ int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt, \
+ (a)); \
+ MSCH_EVENTS_PRINT(nbytes); \
+ } while (0)
+
+#define MSCH_EVENTS_PRINTF2(fmt, a, b) \
+ do { \
+ int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt, \
+ (a), (b)); \
+ MSCH_EVENTS_PRINT(nbytes); \
+ } while (0)
+
+#define MSCH_EVENTS_PRINTF3(fmt, a, b, c) \
+ do { \
+ int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt, \
+ (a), (b), (c)); \
+ MSCH_EVENTS_PRINT(nbytes); \
+ } while (0)
+
+#define MSCH_EVENTS_PRINTF4(fmt, a, b, c, d) \
+ do { \
+ int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt, \
+ (a), (b), (c), (d)); \
+ MSCH_EVENTS_PRINT(nbytes); \
+ } while (0)
+
+#define MSCH_EVENTS_PRINTF5(fmt, a, b, c, d, e) \
+ do { \
+ int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt, \
+ (a), (b), (c), (d), (e)); \
+ MSCH_EVENTS_PRINT(nbytes); \
+ } while (0)
+
+#define MSCH_EVENTS_SPPRINTF(space, fmt) \
+ do { \
+ MSCH_EVENTS_SPPRINT(space); \
+ MSCH_EVENTS_PRINTF(fmt); \
+ } while (0)
+
+#define MSCH_EVENTS_SPPRINTF1(space, fmt, a) \
+ do { \
+ MSCH_EVENTS_SPPRINT(space); \
+ MSCH_EVENTS_PRINTF1(fmt, (a)); \
+ } while (0)
+
+#define MSCH_EVENTS_SPPRINTF2(space, fmt, a, b) \
+ do { \
+ MSCH_EVENTS_SPPRINT(space); \
+ MSCH_EVENTS_PRINTF2(fmt, (a), (b)); \
+ } while (0)
+
+#define MSCH_EVENTS_SPPRINTF3(space, fmt, a, b, c) \
+ do { \
+ MSCH_EVENTS_SPPRINT(space); \
+ MSCH_EVENTS_PRINTF3(fmt, (a), (b), (c)); \
+ } while (0)
+
+#define MSCH_EVENTS_SPPRINTF4(space, fmt, a, b, c, d) \
+ do { \
+ MSCH_EVENTS_SPPRINT(space); \
+ MSCH_EVENTS_PRINTF4(fmt, (a), (b), (c), (d)); \
+ } while (0)
+
+#define MSCH_EVENTS_SPPRINTF5(space, fmt, a, b, c, d, e) \
+ do { \
+ MSCH_EVENTS_SPPRINT(space); \
+ MSCH_EVENTS_PRINTF5(fmt, (a), (b), (c), (d), (e)); \
+ } while (0)
+
+static char *wl_msch_display_time(uint32 time_h, uint32 time_l)
+{
+ static char display_time[32];
+ uint64 t;
+ uint32 s, ss;
+
+ if (time_h == 0xffffffff && time_l == 0xffffffff) {
+ snprintf(display_time, 31, "-1");
+ } else {
+ t = ((uint64)(ntoh32(time_h)) << 32) | ntoh32(time_l);
+ s = (uint32)(t / 1000000);
+ ss = (uint32)(t % 1000000);
+ snprintf(display_time, 31, "%d.%06d", s, ss);
+ }
+ return display_time;
+}
+
+static void
+wl_msch_chanspec_list(int sp, char *data, uint16 ptr, uint16 chanspec_cnt)
+{
+ int i, cnt = (int)ntoh16(chanspec_cnt);
+ uint16 *chanspec_list = (uint16 *)(data + ntoh16(ptr));
+ char buf[CHANSPEC_STR_LEN];
+ chanspec_t c;
+
+ MSCH_EVENTS_SPPRINTF(sp, "<chanspec_list>:");
+ for (i = 0; i < cnt; i++) {
+ c = (chanspec_t)ntoh16(chanspec_list[i]);
+ MSCH_EVENTS_PRINTF1(" %s", wf_chspec_ntoa(c, buf));
+ }
+ MSCH_EVENTS_PRINTF("\n");
+}
+
+static void
+wl_msch_elem_list(int sp, char *title, char *data, uint16 ptr, uint16 list_cnt)
+{
+ int i, cnt = (int)ntoh16(list_cnt);
+ uint32 *list = (uint32 *)(data + ntoh16(ptr));
+
+ MSCH_EVENTS_SPPRINTF1(sp, "%s_list: ", title);
+ for (i = 0; i < cnt; i++) {
+ MSCH_EVENTS_PRINTF1("0x%08x->", ntoh32(list[i]));
+ }
+ MSCH_EVENTS_PRINTF("null\n");
+}
+
+static void
+wl_msch_req_param_profiler_data(int sp, int ver, char *data, uint16 ptr)
+{
+ int sn = sp + 4;
+ msch_req_param_profiler_event_data_t *p =
+ (msch_req_param_profiler_event_data_t *)(data + ntoh16(ptr));
+ uint32 type, flags;
+
+ UNUSED_PARAMETER(ver);
+
+ MSCH_EVENTS_SPPRINTF(sp, "<request parameters>\n");
+ MSCH_EVENTS_SPPRINTF(sn, "req_type: ");
+
+ type = p->req_type;
+ if (type < 4) {
+ char *req_type[] = {"fixed", "start-flexible", "duration-flexible",
+ "both-flexible"};
+ MSCH_EVENTS_PRINTF1("%s", req_type[type]);
+ }
+ else
+ MSCH_EVENTS_PRINTF1("unknown(%d)", type);
+
+ flags = ntoh16(p->flags);
+ if (flags & WL_MSCH_REQ_FLAGS_CHAN_CONTIGUOUS)
+ MSCH_EVENTS_PRINTF(", CHAN_CONTIGUOUS");
+ if (flags & WL_MSCH_REQ_FLAGS_MERGE_CONT_SLOTS)
+ MSCH_EVENTS_PRINTF(", MERGE_CONT_SLOTS");
+ if (flags & WL_MSCH_REQ_FLAGS_PREMTABLE)
+ MSCH_EVENTS_PRINTF(", PREMTABLE");
+ if (flags & WL_MSCH_REQ_FLAGS_PREMT_CURTS)
+ MSCH_EVENTS_PRINTF(", PREMT_CURTS");
+ if (flags & WL_MSCH_REQ_FLAGS_PREMT_IMMEDIATE)
+ MSCH_EVENTS_PRINTF(", PREMT_IMMEDIATE");
+ MSCH_EVENTS_PRINTF1(", priority: %d\n", p->priority);
+
+ MSCH_EVENTS_SPPRINTF3(sn, "start-time: %s, duration: %d(us), interval: %d(us)\n",
+ wl_msch_display_time(p->start_time_h, p->start_time_l),
+ ntoh32(p->duration), ntoh32(p->interval));
+
+ if (type == WL_MSCH_RT_DUR_FLEX)
+ MSCH_EVENTS_SPPRINTF1(sn, "dur_flex: %d(us)\n", ntoh32(p->flex.dur_flex));
+ else if (type == WL_MSCH_RT_BOTH_FLEX) {
+ MSCH_EVENTS_SPPRINTF2(sn, "min_dur: %d(us), max_away_dur: %d(us)\n",
+ ntoh32(p->flex.bf.min_dur), ntoh32(p->flex.bf.max_away_dur));
+
+ MSCH_EVENTS_SPPRINTF2(sn, "hi_prio_time: %s, hi_prio_interval: %d(us)\n",
+ wl_msch_display_time(p->flex.bf.hi_prio_time_h,
+ p->flex.bf.hi_prio_time_l),
+ ntoh32(p->flex.bf.hi_prio_interval));
+ }
+}
+
+static void
+wl_msch_timeslot_profiler_data(int sp, int ver, char *title, char *data, uint16 ptr, bool empty)
+{
+ int s, sn = sp + 4;
+ msch_timeslot_profiler_event_data_t *p =
+ (msch_timeslot_profiler_event_data_t *)(data + ntoh16(ptr));
+ char *state[] = {"NONE", "CHN_SW", "ONCHAN_FIRE", "OFF_CHN_PREP",
+ "OFF_CHN_DONE", "TS_COMPLETE"};
+
+ UNUSED_PARAMETER(ver);
+
+ MSCH_EVENTS_SPPRINTF1(sp, "<%s timeslot>: ", title);
+ if (empty) {
+ MSCH_EVENTS_PRINTF(" null\n");
+ return;
+ }
+ else
+ MSCH_EVENTS_PRINTF1("0x%08x\n", ntoh32(p->p_timeslot));
+
+ s = (int)(ntoh32(p->state));
+ if (s > 5) s = 0;
+
+ MSCH_EVENTS_SPPRINTF4(sn, "id: %d, state[%d]: %s, chan_ctxt: [0x%08x]\n",
+ ntoh32(p->timeslot_id), ntoh32(p->state), state[s], ntoh32(p->p_chan_ctxt));
+
+ MSCH_EVENTS_SPPRINTF1(sn, "fire_time: %s",
+ wl_msch_display_time(p->fire_time_h, p->fire_time_l));
+
+ MSCH_EVENTS_PRINTF1(", pre_start_time: %s",
+ wl_msch_display_time(p->pre_start_time_h, p->pre_start_time_l));
+
+ MSCH_EVENTS_PRINTF1(", end_time: %s",
+ wl_msch_display_time(p->end_time_h, p->end_time_l));
+
+ MSCH_EVENTS_PRINTF1(", sch_dur: %s\n",
+ wl_msch_display_time(p->sch_dur_h, p->sch_dur_l));
+}
+
+static void
+wl_msch_req_timing_profiler_data(int sp, int ver, char *title, char *data, uint16 ptr, bool empty)
+{
+ int sn = sp + 4;
+ msch_req_timing_profiler_event_data_t *p =
+ (msch_req_timing_profiler_event_data_t *)(data + ntoh16(ptr));
+ uint32 type;
+
+ UNUSED_PARAMETER(ver);
+
+ MSCH_EVENTS_SPPRINTF1(sp, "<%s req_timing>: ", title);
+ if (empty) {
+ MSCH_EVENTS_PRINTF(" null\n");
+ return;
+ }
+ else
+ MSCH_EVENTS_PRINTF3("0x%08x (prev 0x%08x, next 0x%08x)\n",
+ ntoh32(p->p_req_timing), ntoh32(p->p_prev), ntoh32(p->p_next));
+
+ MSCH_EVENTS_SPPRINTF(sn, "flags:");
+ type = ntoh16(p->flags);
+ if ((type & 0x7f) == 0)
+ MSCH_EVENTS_PRINTF(" NONE");
+ else {
+ if (type & WL_MSCH_RC_FLAGS_ONCHAN_FIRE)
+ MSCH_EVENTS_PRINTF(" ONCHAN_FIRE");
+ if (type & WL_MSCH_RC_FLAGS_START_FIRE_DONE)
+ MSCH_EVENTS_PRINTF(" START_FIRE");
+ if (type & WL_MSCH_RC_FLAGS_END_FIRE_DONE)
+ MSCH_EVENTS_PRINTF(" END_FIRE");
+ if (type & WL_MSCH_RC_FLAGS_ONFIRE_DONE)
+ MSCH_EVENTS_PRINTF(" ONFIRE_DONE");
+ if (type & WL_MSCH_RC_FLAGS_SPLIT_SLOT_START)
+ MSCH_EVENTS_PRINTF(" SPLIT_SLOT_START");
+ if (type & WL_MSCH_RC_FLAGS_SPLIT_SLOT_END)
+ MSCH_EVENTS_PRINTF(" SPLIT_SLOT_END");
+ if (type & WL_MSCH_RC_FLAGS_PRE_ONFIRE_DONE)
+ MSCH_EVENTS_PRINTF(" PRE_ONFIRE_DONE");
+ }
+ MSCH_EVENTS_PRINTF("\n");
+
+ MSCH_EVENTS_SPPRINTF1(sn, "pre_start_time: %s",
+ wl_msch_display_time(p->pre_start_time_h, p->pre_start_time_l));
+
+ MSCH_EVENTS_PRINTF1(", start_time: %s",
+ wl_msch_display_time(p->start_time_h, p->start_time_l));
+
+ MSCH_EVENTS_PRINTF1(", end_time: %s\n",
+ wl_msch_display_time(p->end_time_h, p->end_time_l));
+
+ if (p->p_timeslot && (p->timeslot_ptr == 0))
+ MSCH_EVENTS_SPPRINTF2(sn, "<%s timeslot>: 0x%08x\n", title, ntoh32(p->p_timeslot));
+ else
+ wl_msch_timeslot_profiler_data(sn, ver, title, data, p->timeslot_ptr,
+ (p->timeslot_ptr == 0));
+}
+
+static void
+wl_msch_chan_ctxt_profiler_data(int sp, int ver, char *data, uint16 ptr, bool empty)
+{
+ int sn = sp + 4;
+ msch_chan_ctxt_profiler_event_data_t *p =
+ (msch_chan_ctxt_profiler_event_data_t *)(data + ntoh16(ptr));
+ chanspec_t c;
+ char buf[CHANSPEC_STR_LEN];
+
+ UNUSED_PARAMETER(ver);
+
+ MSCH_EVENTS_SPPRINTF(sp, "<chan_ctxt>: ");
+ if (empty) {
+ MSCH_EVENTS_PRINTF(" null\n");
+ return;
+ }
+ else
+ MSCH_EVENTS_PRINTF3("0x%08x (prev 0x%08x, next 0x%08x)\n",
+ ntoh32(p->p_chan_ctxt), ntoh32(p->p_prev), ntoh32(p->p_next));
+
+ c = (chanspec_t)ntoh16(p->chanspec);
+ MSCH_EVENTS_SPPRINTF3(sn, "channel: %s, bf_sch_pending: %s, bf_skipped: %d\n",
+ wf_chspec_ntoa(c, buf), p->bf_sch_pending? "TRUE" : "FALSE",
+ ntoh32(p->bf_skipped_count));
+ MSCH_EVENTS_SPPRINTF2(sn, "bf_link: prev 0x%08x, next 0x%08x\n",
+ ntoh32(p->bf_link_prev), ntoh32(p->bf_link_next));
+
+ MSCH_EVENTS_SPPRINTF1(sn, "onchan_time: %s",
+ wl_msch_display_time(p->onchan_time_h, p->onchan_time_l));
+
+ MSCH_EVENTS_PRINTF1(", actual_onchan_dur: %s",
+ wl_msch_display_time(p->actual_onchan_dur_h, p->actual_onchan_dur_l));
+
+ MSCH_EVENTS_PRINTF1(", pend_onchan_dur: %s\n",
+ wl_msch_display_time(p->pend_onchan_dur_h, p->pend_onchan_dur_l));
+
+ wl_msch_elem_list(sn, "req_entity", data, p->req_entity_list_ptr, p->req_entity_list_cnt);
+ wl_msch_elem_list(sn, "bf_entity", data, p->bf_entity_list_ptr, p->bf_entity_list_cnt);
+}
+
+static void
+wl_msch_req_entity_profiler_data(int sp, int ver, char *data, uint16 ptr, bool empty)
+{
+ int sn = sp + 4;
+ msch_req_entity_profiler_event_data_t *p =
+ (msch_req_entity_profiler_event_data_t *)(data + ntoh16(ptr));
+ char buf[CHANSPEC_STR_LEN];
+ chanspec_t c;
+ uint32 flags;
+
+ MSCH_EVENTS_SPPRINTF(sp, "<req_entity>: ");
+ if (empty) {
+ MSCH_EVENTS_PRINTF(" null\n");
+ return;
+ }
+ else
+ MSCH_EVENTS_PRINTF3("0x%08x (prev 0x%08x, next 0x%08x)\n",
+ ntoh32(p->p_req_entity), ntoh32(p->req_hdl_link_prev),
+ ntoh32(p->req_hdl_link_next));
+
+ MSCH_EVENTS_SPPRINTF1(sn, "req_hdl: [0x%08x]\n", ntoh32(p->p_req_hdl));
+ MSCH_EVENTS_SPPRINTF2(sn, "chan_ctxt_link: prev 0x%08x, next 0x%08x\n",
+ ntoh32(p->chan_ctxt_link_prev), ntoh32(p->chan_ctxt_link_next));
+ MSCH_EVENTS_SPPRINTF2(sn, "rt_specific_link: prev 0x%08x, next 0x%08x\n",
+ ntoh32(p->rt_specific_link_prev), ntoh32(p->rt_specific_link_next));
+ MSCH_EVENTS_SPPRINTF2(sn, "start_fixed_link: prev 0x%08x, next 0x%08x\n",
+ ntoh32(p->start_fixed_link_prev), ntoh32(p->start_fixed_link_next));
+ MSCH_EVENTS_SPPRINTF2(sn, "both_flex_list: prev 0x%08x, next 0x%08x\n",
+ ntoh32(p->both_flex_list_prev), ntoh32(p->both_flex_list_next));
+
+ c = (chanspec_t)ntoh16(p->chanspec);
+ if (ver >= 2) {
+ MSCH_EVENTS_SPPRINTF4(sn, "channel: %s, onchan Id %d, current chan Id %d, "
+ "priority %d", wf_chspec_ntoa(c, buf), ntoh16(p->onchan_chn_idx),
+ ntoh16(p->cur_chn_idx), ntoh16(p->priority));
+ flags = ntoh32(p->flags);
+ if (flags & WL_MSCH_ENTITY_FLAG_MULTI_INSTANCE)
+ MSCH_EVENTS_PRINTF(" : MULTI_INSTANCE\n");
+ else
+ MSCH_EVENTS_PRINTF("\n");
+ MSCH_EVENTS_SPPRINTF1(sn, "actual_start_time: %s, ",
+ wl_msch_display_time(p->actual_start_time_h, p->actual_start_time_l));
+ MSCH_EVENTS_PRINTF1("curts_fire_time: %s, ",
+ wl_msch_display_time(p->curts_fire_time_h, p->curts_fire_time_l));
+ } else {
+ MSCH_EVENTS_SPPRINTF2(sn, "channel: %s, priority %d, ", wf_chspec_ntoa(c, buf),
+ ntoh16(p->priority));
+ }
+ MSCH_EVENTS_PRINTF1("bf_last_serv_time: %s\n",
+ wl_msch_display_time(p->bf_last_serv_time_h, p->bf_last_serv_time_l));
+
+ wl_msch_req_timing_profiler_data(sn, ver, "current", data, p->cur_slot_ptr,
+ (p->cur_slot_ptr == 0));
+ wl_msch_req_timing_profiler_data(sn, ver, "pending", data, p->pend_slot_ptr,
+ (p->pend_slot_ptr == 0));
+
+ if (p->p_chan_ctxt && (p->chan_ctxt_ptr == 0))
+ MSCH_EVENTS_SPPRINTF1(sn, "<chan_ctxt>: 0x%08x\n", ntoh32(p->p_chan_ctxt));
+ else
+ wl_msch_chan_ctxt_profiler_data(sn, ver, data, p->chan_ctxt_ptr,
+ (p->chan_ctxt_ptr == 0));
+}
+
+static void
+wl_msch_req_handle_profiler_data(int sp, int ver, char *data, uint16 ptr, bool empty)
+{
+ int sn = sp + 4;
+ msch_req_handle_profiler_event_data_t *p =
+ (msch_req_handle_profiler_event_data_t *)(data + ntoh16(ptr));
+ uint32 flags;
+
+ MSCH_EVENTS_SPPRINTF(sp, "<req_handle>: ");
+ if (empty) {
+ MSCH_EVENTS_PRINTF(" null\n");
+ return;
+ }
+ else
+ MSCH_EVENTS_PRINTF3("0x%08x (prev 0x%08x, next 0x%08x)\n",
+ ntoh32(p->p_req_handle), ntoh32(p->p_prev), ntoh32(p->p_next));
+
+ wl_msch_elem_list(sn, "req_entity", data, p->req_entity_list_ptr, p->req_entity_list_cnt);
+ MSCH_EVENTS_SPPRINTF2(sn, "cb_func: [0x%08x], cb_func: [0x%08x]",
+ ntoh32(p->cb_func), ntoh32(p->cb_ctxt));
+ if (ver < 2) {
+ MSCH_EVENTS_PRINTF1(", chan_cnt: %d", ntoh16(p->chan_cnt));
+ }
+ flags = ntoh32(p->flags);
+ if (flags & WL_MSCH_REQ_HDL_FLAGS_NEW_REQ)
+ MSCH_EVENTS_PRINTF(", NEW_REQ");
+ MSCH_EVENTS_PRINTF("\n");
+
+ wl_msch_req_param_profiler_data(sn, ver, data, p->req_param_ptr);
+
+ if (ver >= 2) {
+ MSCH_EVENTS_SPPRINTF1(sn, "req_time: %s\n",
+ wl_msch_display_time(p->req_time_h, p->req_time_l));
+ MSCH_EVENTS_SPPRINTF3(sn, "chan_cnt: %d, chan idx %d, last chan idx %d\n",
+ ntoh16(p->chan_cnt), ntoh16(p->chan_idx), ntoh16(p->last_chan_idx));
+ if (p->chanspec_list && p->chanspec_cnt) {
+ wl_msch_chanspec_list(sn, data, p->chanspec_list, p->chanspec_cnt);
+ }
+ }
+}
+
+static void
+wl_msch_profiler_profiler_data(int sp, int ver, char *data, uint16 ptr)
+{
+ msch_profiler_profiler_event_data_t *p =
+ (msch_profiler_profiler_event_data_t *)(data + ntoh16(ptr));
+ uint32 flags;
+
+ MSCH_EVENTS_SPPRINTF4(sp, "free list: req_hdl 0x%08x, req_entity 0x%08x,"
+ " chan_ctxt 0x%08x, chanspec 0x%08x\n",
+ ntoh32(p->free_req_hdl_list), ntoh32(p->free_req_entity_list),
+ ntoh32(p->free_chan_ctxt_list), ntoh32(p->free_chanspec_list));
+
+ MSCH_EVENTS_SPPRINTF5(sp, "alloc count: chanspec %d, req_entity %d, req_hdl %d, "
+ "chan_ctxt %d, timeslot %d\n",
+ ntoh16(p->msch_chanspec_alloc_cnt), ntoh16(p->msch_req_entity_alloc_cnt),
+ ntoh16(p->msch_req_hdl_alloc_cnt), ntoh16(p->msch_chan_ctxt_alloc_cnt),
+ ntoh16(p->msch_timeslot_alloc_cnt));
+
+ wl_msch_elem_list(sp, "req_hdl", data, p->msch_req_hdl_list_ptr,
+ p->msch_req_hdl_list_cnt);
+ wl_msch_elem_list(sp, "chan_ctxt", data, p->msch_chan_ctxt_list_ptr,
+ p->msch_chan_ctxt_list_cnt);
+ wl_msch_elem_list(sp, "req_timing", data, p->msch_req_timing_list_ptr,
+ p->msch_req_timing_list_cnt);
+ wl_msch_elem_list(sp, "start_fixed", data, p->msch_start_fixed_list_ptr,
+ p->msch_start_fixed_list_cnt);
+ wl_msch_elem_list(sp, "both_flex_req_entity", data,
+ p->msch_both_flex_req_entity_list_ptr,
+ p->msch_both_flex_req_entity_list_cnt);
+ wl_msch_elem_list(sp, "start_flex", data, p->msch_start_flex_list_ptr,
+ p->msch_start_flex_list_cnt);
+ wl_msch_elem_list(sp, "both_flex", data, p->msch_both_flex_list_ptr,
+ p->msch_both_flex_list_cnt);
+
+ if (p->p_cur_msch_timeslot && (p->cur_msch_timeslot_ptr == 0))
+ MSCH_EVENTS_SPPRINTF1(sp, "<cur_msch timeslot>: 0x%08x\n",
+ ntoh32(p->p_cur_msch_timeslot));
+ else
+ wl_msch_timeslot_profiler_data(sp, ver, "cur_msch", data,
+ p->cur_msch_timeslot_ptr, (p->cur_msch_timeslot_ptr == 0));
+
+ if (p->p_next_timeslot && (p->next_timeslot_ptr == 0))
+ MSCH_EVENTS_SPPRINTF1(sp, "<next timeslot>: 0x%08x\n", ntoh32(p->p_next_timeslot));
+ else
+ wl_msch_timeslot_profiler_data(sp, ver, "next", data,
+ p->next_timeslot_ptr, (p->next_timeslot_ptr == 0));
+
+ MSCH_EVENTS_SPPRINTF1(sp, "ts_id: %d, ", ntoh32(p->ts_id));
+ flags = ntoh32(p->flags);
+ if (flags & WL_MSCH_STATE_IN_TIEMR_CTXT)
+ MSCH_EVENTS_PRINTF("IN_TIEMR_CTXT, ");
+ if (flags & WL_MSCH_STATE_SCHD_PENDING)
+ MSCH_EVENTS_PRINTF("SCHD_PENDING, ");
+ MSCH_EVENTS_PRINTF2("slotskip_flags: %d, cur_armed_timeslot: 0x%08x\n",
+ (ver >= 2)? ntoh32(p->slotskip_flag) : 0, ntoh32(p->cur_armed_timeslot));
+ MSCH_EVENTS_SPPRINTF3(sp, "flex_list_cnt: %d, service_interval: %d, "
+ "max_lo_prio_interval: %d\n",
+ ntoh16(p->flex_list_cnt), ntoh32(p->service_interval),
+ ntoh32(p->max_lo_prio_interval));
+}
+
+#define MAX_NO_OF_ARG 10
+#define FMTSTR_SIZE 132
+#define ROMSTR_SIZE 200
+#define SIZE_LOC_STR 50
+
+static bool
+check_valid_string_format(char *curr_ptr)
+{
+ char *next_ptr;
+ if ((next_ptr = bcmstrstr(curr_ptr, "s")) != NULL) {
+ /* Default %s format */
+ if (curr_ptr == next_ptr) {
+ return TRUE;
+ }
+
+ /* Verify each charater between '%' and 's' is a valid number */
+ while (curr_ptr < next_ptr) {
+ if (bcm_isdigit(*curr_ptr) == FALSE) {
+ return FALSE;
+ }
+ curr_ptr++;
+ }
+
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static void
+wl_msch_profiler_event_log_data(int ver, event_log_hdr_t *hdr, uint32 *data)
+{
+ uint16 count;
+ char fmtstr_loc_buf[ROMSTR_SIZE] = { 0 };
+ char (*str_buf)[SIZE_LOC_STR] = NULL;
+ char *str_tmpptr = NULL;
+ uint32 addr = 0;
+ typedef union {
+ uint32 val;
+ char * addr;
+ } u_arg;
+ u_arg arg[MAX_NO_OF_ARG] = {{0}};
+ char *c_ptr = NULL;
+ int nbytes;
+
+ UNUSED_PARAMETER(ver);
+
+ /* print the message out in a logprint */
+ if (!(((raw_event.raw_sstr) || (raw_event.rom_raw_sstr)) &&
+ raw_event.fmts) || hdr->fmt_num == 0xffff) {
+ MSCH_EVENTS_PRINTF2("0.0 EL: %x %x",
+ hdr->tag & EVENT_LOG_TAG_FLAG_SET_MASK,
+ hdr->fmt_num);
+ for (count = 0; count < hdr->count; count++)
+ MSCH_EVENTS_PRINTF1(" %x", data[count]);
+ MSCH_EVENTS_PRINTF("\n");
+ return;
+ }
+
+ str_buf = malloc(MAX_NO_OF_ARG * SIZE_LOC_STR);
+ if (!str_buf) {
+ fprintf(stderr, "%s: malloc failed str_buf\n", __FUNCTION__);
+ return;
+ }
+
+ if ((hdr->fmt_num >> 2) < raw_event.num_fmts) {
+ snprintf(fmtstr_loc_buf, FMTSTR_SIZE, "%s",
+ raw_event.fmts[hdr->fmt_num >> 2]);
+ c_ptr = fmtstr_loc_buf;
+ } else {
+ fprintf(stderr, "%s: fmt number out of range \n", __FUNCTION__);
+ goto exit;
+ }
+
+ for (count = 0; count < hdr->count; count++) {
+ if (c_ptr != NULL)
+ if ((c_ptr = bcmstrstr(c_ptr, "%")) != NULL)
+ c_ptr++;
+
+ if (c_ptr != NULL) {
+ if (check_valid_string_format(c_ptr)) {
+ if ((raw_event.raw_sstr) &&
+ ((data[count] > raw_event.rodata_start) &&
+ (data[count] < raw_event.rodata_end))) {
+ /* ram static string */
+ addr = data[count] - raw_event.rodata_start;
+ str_tmpptr = raw_event.raw_sstr + addr;
+ memcpy(str_buf[count], str_tmpptr,
+ SIZE_LOC_STR);
+ str_buf[count][SIZE_LOC_STR-1] = '\0';
+ arg[count].addr = str_buf[count];
+ } else if ((raw_event.rom_raw_sstr) &&
+ ((data[count] >
+ raw_event.rom_rodata_start) &&
+ (data[count] <
+ raw_event.rom_rodata_end))) {
+ /* rom static string */
+ addr = data[count] - raw_event.rom_rodata_start;
+ str_tmpptr = raw_event.rom_raw_sstr + addr;
+ memcpy(str_buf[count], str_tmpptr,
+ SIZE_LOC_STR);
+ str_buf[count][SIZE_LOC_STR-1] = '\0';
+ arg[count].addr = str_buf[count];
+ } else {
+ /*
+ * Dynamic string OR
+ * No data for static string.
+ * So store all string's address as string.
+ */
+ snprintf(str_buf[count], SIZE_LOC_STR,
+ "(s)0x%x", data[count]);
+ arg[count].addr = str_buf[count];
+ }
+ } else {
+ /* Other than string */
+ arg[count].val = data[count];
+ }
+ }
+ }
+
+ nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmtstr_loc_buf,
+ arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]);
+ MSCH_EVENTS_PRINT(nbytes);
+exit:
+ free(str_buf);
+}
+
+static uint64 solt_start_time[4], req_start_time[4], profiler_start_time[4];
+static uint32 solt_chanspec[4] = {0, }, req_start[4] = {0, };
+static bool lastMessages = FALSE;
+
+static void wl_msch_dump_data(char *data, int type)
+{
+ uint64 t = 0, tt = 0;
+ uint32 s = 0, ss = 0;
+ int wlc_index, ver;
+
+ ver = (type & WL_MSCH_PROFILER_VER_MASK) >> WL_MSCH_PROFILER_VER_SHIFT;
+ wlc_index = (type & WL_MSCH_PROFILER_WLINDEX_MASK) >> WL_MSCH_PROFILER_WLINDEX_SHIFT;
+ if (wlc_index >= 4)
+ return;
+
+ type &= WL_MSCH_PROFILER_TYPE_MASK;
+ if (type <= WL_MSCH_PROFILER_PROFILE_END || type == WL_MSCH_PROFILER_EVENT_LOG) {
+ msch_profiler_event_data_t *pevent = (msch_profiler_event_data_t *)data;
+ tt = ((uint64)(ntoh32(pevent->time_hi)) << 32) | ntoh32(pevent->time_lo);
+ s = (uint32)(tt / 1000000);
+ ss = (uint32)(tt % 1000000);
+ }
+
+ if (lastMessages && (type != WL_MSCH_PROFILER_MESSAGE) &&
+ (type != WL_MSCH_PROFILER_EVENT_LOG)) {
+ MSCH_EVENTS_PRINTF("\n");
+ lastMessages = FALSE;
+ }
+
+ switch (type) {
+ case WL_MSCH_PROFILER_START:
+ MSCH_EVENTS_PRINTF2("\n%06d.%06d START\n", s, ss);
+ break;
+
+ case WL_MSCH_PROFILER_EXIT:
+ MSCH_EVENTS_PRINTF2("\n%06d.%06d EXIT\n", s, ss);
+ break;
+
+ case WL_MSCH_PROFILER_REQ:
+ {
+ msch_req_profiler_event_data_t *p = (msch_req_profiler_event_data_t *)data;
+ MSCH_EVENTS_PRINTF("\n===============================\n");
+ MSCH_EVENTS_PRINTF3("%06d.%06d [wl%d] REGISTER:\n", s, ss, wlc_index);
+ wl_msch_req_param_profiler_data(4, ver, data, p->req_param_ptr);
+ wl_msch_chanspec_list(4, data, p->chanspec_ptr, p->chanspec_cnt);
+ MSCH_EVENTS_PRINTF("===============================\n\n");
+ }
+ break;
+
+ case WL_MSCH_PROFILER_CALLBACK:
+ {
+ msch_callback_profiler_event_data_t *p =
+ (msch_callback_profiler_event_data_t *)data;
+ char buf[CHANSPEC_STR_LEN];
+ uint16 cbtype;
+
+ MSCH_EVENTS_PRINTF3("%06d.%06d [wl%d] CALLBACK: ", s, ss, wlc_index);
+ ss = ntoh16(p->chanspec);
+ if (ver >= 2) {
+ MSCH_EVENTS_PRINTF2("req_hdl[0x%08x], channel %s --",
+ ntoh32(p->p_req_hdl), wf_chspec_ntoa(ss, buf));
+ } else {
+ MSCH_EVENTS_PRINTF1("channel %s --", wf_chspec_ntoa(ss, buf));
+ }
+ cbtype = ntoh16(p->type);
+ if (cbtype & WL_MSCH_CT_ON_CHAN)
+ MSCH_EVENTS_PRINTF(" ON_CHAN");
+ if (cbtype & WL_MSCH_CT_OFF_CHAN)
+ MSCH_EVENTS_PRINTF(" OFF_CHAN");
+ if (cbtype & WL_MSCH_CT_REQ_START)
+ MSCH_EVENTS_PRINTF(" REQ_START");
+ if (cbtype & WL_MSCH_CT_REQ_END)
+ MSCH_EVENTS_PRINTF(" REQ_END");
+ if (cbtype & WL_MSCH_CT_SLOT_START)
+ MSCH_EVENTS_PRINTF(" SLOT_START");
+ if (cbtype & WL_MSCH_CT_SLOT_SKIP)
+ MSCH_EVENTS_PRINTF(" SLOT_SKIP");
+ if (cbtype & WL_MSCH_CT_SLOT_END)
+ MSCH_EVENTS_PRINTF(" SLOT_END");
+ if (cbtype & WL_MSCH_CT_OFF_CHAN_DONE)
+ MSCH_EVENTS_PRINTF(" OFF_CHAN_DONE");
+ if (cbtype & WL_MSCH_CT_PARTIAL)
+ MSCH_EVENTS_PRINTF(" PARTIAL");
+ if (cbtype & WL_MSCH_CT_PRE_ONCHAN)
+ MSCH_EVENTS_PRINTF(" PRE_ONCHAN");
+ if (cbtype & WL_MSCH_CT_PRE_REQ_START)
+ MSCH_EVENTS_PRINTF(" PRE_REQ_START");
+
+ if (cbtype & (WL_MSCH_CT_ON_CHAN | WL_MSCH_CT_SLOT_SKIP)) {
+ MSCH_EVENTS_PRINTF("\n ");
+ if (cbtype & WL_MSCH_CT_ON_CHAN) {
+ if (ver >= 2) {
+ MSCH_EVENTS_PRINTF3("ID %d onchan idx %d seq_start %s ",
+ ntoh32(p->timeslot_id), ntoh32(p->onchan_idx),
+ wl_msch_display_time(p->cur_chan_seq_start_time_h,
+ p->cur_chan_seq_start_time_l));
+ } else {
+ MSCH_EVENTS_PRINTF1("ID %d ", ntoh32(p->timeslot_id));
+ }
+ }
+ t = ((uint64)(ntoh32(p->start_time_h)) << 32) |
+ ntoh32(p->start_time_l);
+ MSCH_EVENTS_PRINTF1("start %s ",
+ wl_msch_display_time(p->start_time_h,
+ p->start_time_l));
+ tt = ((uint64)(ntoh32(p->end_time_h)) << 32) | ntoh32(p->end_time_l);
+ MSCH_EVENTS_PRINTF2("end %s duration %d",
+ wl_msch_display_time(p->end_time_h, p->end_time_l),
+ (p->end_time_h == 0xffffffff && p->end_time_l == 0xffffffff)?
+ -1 : (int)(tt - t));
+ }
+
+ if (cbtype & WL_MSCH_CT_REQ_START) {
+ req_start[wlc_index] = 1;
+ req_start_time[wlc_index] = tt;
+ } else if (cbtype & WL_MSCH_CT_REQ_END) {
+ if (req_start[wlc_index]) {
+ MSCH_EVENTS_PRINTF1(" : REQ duration %d",
+ (uint32)(tt - req_start_time[wlc_index]));
+ req_start[wlc_index] = 0;
+ }
+ }
+
+ if (cbtype & WL_MSCH_CT_SLOT_START) {
+ solt_chanspec[wlc_index] = p->chanspec;
+ solt_start_time[wlc_index] = tt;
+ } else if (cbtype & WL_MSCH_CT_SLOT_END) {
+ if (p->chanspec == solt_chanspec[wlc_index]) {
+ MSCH_EVENTS_PRINTF1(" : SLOT duration %d",
+ (uint32)(tt - solt_start_time[wlc_index]));
+ solt_chanspec[wlc_index] = 0;
+ }
+ }
+ MSCH_EVENTS_PRINTF("\n");
+ }
+ break;
+
+ case WL_MSCH_PROFILER_EVENT_LOG:
+ {
+ msch_event_log_profiler_event_data_t *p =
+ (msch_event_log_profiler_event_data_t *)data;
+ p->hdr.fmt_num = ntoh16(p->hdr.fmt_num);
+ MSCH_EVENTS_PRINTF3("%06d.%06d [wl%d]: ", s, ss, wlc_index);
+ wl_msch_profiler_event_log_data(ver, &p->hdr, p->data);
+ lastMessages = TRUE;
+ break;
+ }
+
+ case WL_MSCH_PROFILER_MESSAGE:
+ {
+ msch_message_profiler_event_data_t *p = (msch_message_profiler_event_data_t *)data;
+ MSCH_EVENTS_PRINTF4("%06d.%06d [wl%d]: %s", s, ss, wlc_index, p->message);
+ lastMessages = TRUE;
+ break;
+ }
+
+ case WL_MSCH_PROFILER_PROFILE_START:
+ profiler_start_time[wlc_index] = tt;
+ MSCH_EVENTS_PRINTF("-------------------------------\n");
+ MSCH_EVENTS_PRINTF3("%06d.%06d [wl%d] PROFILE DATA:\n", s, ss, wlc_index);
+ wl_msch_profiler_profiler_data(4, ver, data, 0);
+ break;
+
+ case WL_MSCH_PROFILER_PROFILE_END:
+ MSCH_EVENTS_PRINTF4("%06d.%06d [wl%d] PROFILE END: take time %d\n", s, ss,
+ wlc_index, (uint32)(tt - profiler_start_time[wlc_index]));
+ MSCH_EVENTS_PRINTF("-------------------------------\n\n");
+ break;
+
+ case WL_MSCH_PROFILER_REQ_HANDLE:
+ wl_msch_req_handle_profiler_data(4, ver, data, 0, FALSE);
+ break;
+
+ case WL_MSCH_PROFILER_REQ_ENTITY:
+ wl_msch_req_entity_profiler_data(4, ver, data, 0, FALSE);
+ break;
+
+ case WL_MSCH_PROFILER_CHAN_CTXT:
+ wl_msch_chan_ctxt_profiler_data(4, ver, data, 0, FALSE);
+ break;
+
+ case WL_MSCH_PROFILER_REQ_TIMING:
+ wl_msch_req_timing_profiler_data(4, ver, "msch", data, 0, FALSE);
+ break;
+
+ default:
+ fprintf(stderr, "[wl%d] ERROR: unsupported EVENT reason code:%d; ",
+ wlc_index, type);
+ break;
+ }
+}
+
+int wl_msch_dump(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ int type;
+ char *data, *p, opt;
+ char *fname = NULL, *dir = NULL, *files = NULL;
+ int val, err, start = 1;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ while ((p = *++argv) != NULL) {
+ if (!strcmp(p, "--help") || !strcmp(p, "-h")) {
+ printf("%s", cmd->help);
+ return BCME_OK;
+ }
+
+ if (!strncmp(p, "-", 1)) {
+ opt = p[1];
+ if (strlen(p) > 2) {
+ fprintf(stderr, "wl_msch_dump: only single char options, "
+ "error on param \"%s\"\n", p);
+ return BCME_BADARG;
+ }
+
+ argv++;
+ if (*argv == NULL) {
+ fprintf(stderr, "wl_msch_dump: missing value parameter "
+ "after \"%s\"\n", p);
+ return BCME_USAGE_ERROR;
+ }
+
+ if (opt == 'D')
+ dir = *argv;
+ else if (opt == 'F')
+ files = *argv;
+ else {
+ fprintf(stderr, "error param: %s\n", p);
+ return BCME_BADARG;
+ }
+ } else if (!fname) {
+ fname = p;
+ } else {
+ fprintf(stderr, "error param: %s\n", p);
+ return BCME_BADARG;
+ }
+ }
+
+ if ((err = wlu_iovar_getint(wl, "msch_collect", &val)) < 0)
+ return err;
+
+ if (!(val & WL_MSCH_CMD_ENABLE_BIT))
+ return BCME_NOTREADY;
+
+ if (fname) {
+ if (!(mschfp = fopen(fname, "wb"))) {
+ perror(fname);
+ fprintf(stderr, "Cannot open file %s\n", fname);
+ return BCME_BADARG;
+ }
+ }
+
+ wl_init_frm_array(dir, files);
+
+ err = wlu_var_getbuf(wl, "msch_dump", &start, sizeof(int), &ptr);
+ while (err >= 0) {
+ msch_collect_tlv_t *ptlv = (msch_collect_tlv_t *)ptr;
+
+ type = dtoh16(ptlv->type);
+ data = ptlv->value;
+
+ wl_msch_dump_data(data, type);
+
+ err = wlu_var_getbuf(wl, "msch_dump", NULL, 0, &ptr);
+ }
+
+ if (mschfp) {
+ fflush(mschfp);
+ fclose(mschfp);
+ mschfp = NULL;
+ }
+
+ fflush(stdout);
+ return BCME_OK;
+}
+
+#if defined(linux)
+
+int wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len);
+
+int wl_msch_event_check(void *wl, cmd_t *cmd, char **argv)
+{
+ int fd, err, octets;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ char ifnames[IFNAMSIZ] = {"eth0"};
+ bcm_event_t *event;
+ char *data;
+ int event_type, reason;
+ uint8 event_inds_mask[WL_EVENTING_MASK_LEN];
+ char *p, *fname = NULL, *dir = NULL, *files = NULL;
+ int opt, val;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ if (argv[1] == NULL) {
+ fprintf(stderr, "<ifname> param is missing\n");
+ return -1;
+ }
+
+ if (*++argv) {
+ if (!strcmp(*argv, "--help") || !strcmp(*argv, "-h")) {
+ printf("%s", cmd->help);
+ return BCME_OK;
+ }
+ strncpy(ifnames, *argv, (IFNAMSIZ - 1));
+ }
+
+ if ((err = wlu_iovar_getint(wl, "msch_event", &val)) < 0)
+ return err;
+
+ bzero(&ifr, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
+
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
+ if (fd < 0) {
+ fprintf(stderr, "Cannot create socket %d\n", fd);
+ return -1;
+ }
+
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ fprintf(stderr, "Cannot get iface:%s index \n", ifr.ifr_name);
+ goto exit;
+ }
+
+ bzero(&sll, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ fprintf(stderr, "Cannot bind %d\n", err);
+ goto exit;
+ }
+
+ while (*++argv) {
+ opt = 0;
+ p = *argv;
+ if (p[0] == '+') {
+ opt = 1;
+ p++;
+ }
+ else if (p[0] == '-') {
+ opt = 2;
+ p++;
+ }
+
+ if (opt == 0) {
+ fname = p;
+ if (mschfp == NULL) {
+ if (!(mschfp = fopen(fname, "wb"))) {
+ perror(fname);
+ fprintf(stderr, "Cannot open file %s\n", fname);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+ else {
+ err = BCME_BADARG;
+ fprintf(stderr, "error param: %s\n", p);
+ goto exit;
+ }
+ } else {
+ if (opt == 2 && (!strcmp(p, "all") || !strcmp(p, "a"))) {
+ val &= ~WL_MSCH_CMD_ALL_BITS;
+ } else if (!strcmp(p, "profiler") || !strcmp(p, "p")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_PROFILE_BIT;
+ else
+ val &= ~WL_MSCH_CMD_PROFILE_BIT;
+ }
+ else if (!strcmp(p, "callback") || !strcmp(p, "c")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_CALLBACK_BIT;
+ else
+ val &= ~WL_MSCH_CMD_CALLBACK_BIT;
+ }
+ else if (!strcmp(p, "register") || !strcmp(p, "r")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_REGISTER_BIT;
+ else
+ val &= ~WL_MSCH_CMD_REGISTER_BIT;
+ }
+ else if (!strcmp(p, "error") || !strcmp(p, "e")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_ERROR_BIT;
+ else
+ val &= ~WL_MSCH_CMD_ERROR_BIT;
+ }
+ else if (!strcmp(p, "debug") || !strcmp(p, "d")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_DEBUG_BIT;
+ else
+ val &= ~WL_MSCH_CMD_DEBUG_BIT;
+ }
+ else if (!strcmp(p, "info") || !strcmp(p, "i")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_INFOM_BIT;
+ else
+ val &= ~WL_MSCH_CMD_INFOM_BIT;
+ }
+ else if (!strcmp(p, "trace") || !strcmp(p, "t")) {
+ if (opt == 1)
+ val |= WL_MSCH_CMD_TRACE_BIT;
+ else
+ val &= ~WL_MSCH_CMD_TRACE_BIT;
+ }
+ else if (opt == 2 && !strcmp(p, "D") && *++argv) {
+ dir = *argv;
+ printf("dir: %s\n", dir);
+ }
+ else if (opt == 2 && !strcmp(p, "F") && *++argv) {
+ files = *argv;
+ printf("files: %s\n", files);
+ }
+ else {
+ err = BCME_EPERM;
+ goto exit;
+ }
+ }
+ }
+
+ data = &mschdata[sizeof(bcm_event_t)];
+
+ /* read current mask state */
+ if ((err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
+ fprintf(stderr, "couldn't read event_msgs\n");
+ goto exit;
+ }
+ event_inds_mask[WLC_E_MSCH / 8] |= (1 << (WLC_E_MSCH % 8));
+ if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
+ fprintf(stderr, "couldn't write event_msgs\n");
+ goto exit;
+ }
+
+ val &= ~WL_MSCH_CMD_VER_MASK;
+ val |= (WL_MSCH_CMD_ENABLE_BIT | (WL_MSCH_PROFILER_VER << WL_MSCH_CMD_VER_SHIFT));
+ if ((err = wlu_iovar_setint(wl, "msch_event", val))) {
+ fprintf(stderr, "couldn't start msch event\n");
+ goto exit;
+ }
+
+ wl_init_frm_array(dir, files);
+
+ printf("wating for MSCH events :%s\n", ifr.ifr_name);
+
+ while (1) {
+ fflush(stdout);
+ octets = recv(fd, mschdata, WL_MSCH_PROFILER_BUFFER_SIZE, 0);
+
+ if (octets <= 0) {
+ /* sigterm */
+ err = -1;
+ break;
+ }
+
+ event = (bcm_event_t *)mschdata;
+ event_type = ntoh32(event->event.event_type);
+ reason = ntoh32(event->event.reason);
+
+ if ((event_type != WLC_E_MSCH)) {
+ if (event_type == WLC_E_ESCAN_RESULT) {
+ wl_escan_result_t* escan_data = (wl_escan_result_t*)data;
+ uint16 i;
+ MSCH_EVENTS_PRINTF1("MACEVENT_%d: WLC_E_ESCAN_RESULT:", event_type);
+ for (i = 0; i < escan_data->bss_count; i++) {
+ wl_bss_info_t *bi = &escan_data->bss_info[i];
+ char ssidbuf[SSID_FMT_BUF_LEN];
+ char chspec_str[CHANSPEC_STR_LEN];
+ wl_format_ssid(ssidbuf, bi->SSID, bi->SSID_len);
+ MSCH_EVENTS_PRINTF2(" SSID: \"%s\", Channel: %s;",
+ ssidbuf, wf_chspec_ntoa(bi->chanspec, chspec_str));
+ }
+ MSCH_EVENTS_PRINTF("\n");
+ } else {
+ char *event_name;
+ switch (event_type) {
+ case WLC_E_JOIN:
+ event_name = "WLC_E_JOIN";
+ break;
+
+ case WLC_E_AUTH:
+ event_name = "WLC_E_AUTH";
+ break;
+
+ case WLC_E_ASSOC:
+ event_name = "WLC_E_ASSOC";
+ break;
+
+ case WLC_E_LINK:
+ event_name = "WLC_E_LINK";
+ break;
+
+ case WLC_E_ROAM:
+ event_name = "WLC_E_ROAM";
+ break;
+
+ case WLC_E_SCAN_COMPLETE:
+ event_name = "WLC_E_SCAN_COMPLETE";
+ break;
+
+ case WLC_E_SCAN_CONFIRM_IND:
+ event_name = "WLC_E_SCAN_CONFIRM_IND";
+ break;
+
+ case WLC_E_ASSOC_REQ_IE:
+ event_name = "WLC_E_ASSOC_REQ_IE";
+ break;
+
+ case WLC_E_ASSOC_RESP_IE:
+ event_name = "WLC_E_ASSOC_RESP_IE";
+ break;
+
+ case WLC_E_BSSID:
+ event_name = "WLC_E_BSSID";
+ break;
+
+ default:
+ event_name = "Unknown Event";
+ }
+ MSCH_EVENTS_PRINTF2("MACEVENT_%d: %s\n", event_type, event_name);
+ }
+ continue;
+ }
+
+ wl_msch_dump_data(data, reason);
+
+ if ((reason & WL_MSCH_PROFILER_TYPE_MASK) == WL_MSCH_PROFILER_EXIT)
+ goto exit;
+ }
+exit:
+ /* if we ever reach here */
+ close(fd);
+ if (mschfp) {
+ fflush(mschfp);
+ fclose(mschfp);
+ mschfp = NULL;
+ }
+
+ /* Read the event mask from driver and mask the event WLC_E_MSCH */
+ if (!(err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
+ event_inds_mask[WLC_E_MSCH / 8] &= (~(1 << (WLC_E_MSCH % 8)));
+ err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN);
+ }
+
+ fflush(stdout);
+ return (err);
+}
+#endif /* linux */
+
+typedef struct wl_msch_profiler_struct {
+ uint32 start_ptr;
+ uint32 write_ptr;
+ uint32 write_size;
+ uint32 read_ptr;
+ uint32 read_size;
+ uint32 total_size;
+ uint32 buffer;
+} wl_msch_profiler_struct_t;
+
+#define MSCH_MAGIC_1 0x4d534348
+#define MSCH_MAGIC_2 0x61676963
+
+#undef ROUNDUP
+#define ROUNDUP(x) (((x) + 3) & (~0x03))
+
+#define MAX_PROFILE_DATA_SIZE 4096
+
+int wl_msch_profiler(void *wl, cmd_t *cmd, char **argv)
+{
+ char *fname_r = NULL, *fname_w = NULL, *dir = NULL, *files = NULL;
+ char *buffer = NULL, *p, opt;
+ FILE *fp = NULL;
+ int err = BCME_OK;
+ uint32 magicdata;
+ uint32 rptr, rsize, wsize, tsize;
+ wl_msch_profiler_struct_t profiler;
+ bool found = FALSE;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ while ((p = *++argv) != NULL) {
+ if (!strcmp(p, "--help") || !strcmp(p, "-h")) {
+ printf("%s", cmd->help);
+ return BCME_OK;
+ }
+
+ if (!strncmp(p, "-", 1)) {
+ opt = p[1];
+ if (strlen(p) > 2) {
+ fprintf(stderr, "wl_msch_profiler: only single char options, "
+ "error on param \"%s\"\n", p);
+ return BCME_BADARG;
+ }
+
+ argv++;
+ if (*argv == NULL) {
+ fprintf(stderr, "wl_msch_profiler: missing value parameter "
+ "after \"%s\"\n", p);
+ return BCME_USAGE_ERROR;
+ }
+
+ if (opt == 'D')
+ dir = *argv;
+ else if (opt == 'F')
+ files = *argv;
+ else {
+ fprintf(stderr, "error param: %s\n", p);
+ return BCME_BADARG;
+ }
+ } else if (!fname_r) {
+ fname_r = p;
+ } else if (!fname_w) {
+ fname_w = p;
+ } else {
+ fprintf(stderr, "error param: %s\n", p);
+ return BCME_BADARG;
+ }
+ }
+
+ if (fname_r == NULL) {
+ fprintf(stderr, "<input filename> param is missing\n");
+ return -1;
+ }
+
+ if (!(fp = fopen(fname_r, "rb"))) {
+ perror(fname_r);
+ fprintf(stderr, "Cannot open input file %s\n", fname_r);
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ rptr = 0;
+ while ((rsize = fread(&magicdata, 1, sizeof(uint32), fp)) > 0) {
+ rptr += rsize;
+ magicdata = dtoh32(magicdata);
+ if (magicdata != MSCH_MAGIC_1)
+ continue;
+
+ if ((rsize = fread(&magicdata, 1, sizeof(uint32), fp)) > 0) {
+ rptr += rsize;
+ magicdata = dtoh32(magicdata);
+ if (magicdata != MSCH_MAGIC_2)
+ continue;
+ }
+
+ rsize = fread(&profiler, 1, sizeof(wl_msch_profiler_struct_t), fp);
+ rptr += rsize;
+ magicdata = dtoh32(profiler.buffer);
+
+ if (((rptr ^ magicdata) & 0xffff) == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ fprintf(stderr, "Cannot find profiler data from file %s\n", fname_r);
+ err = BCME_NOTFOUND;
+ goto exit;
+ }
+
+ if (fname_w) {
+ if (!(mschfp = fopen(fname_w, "wb"))) {
+ perror(fname_w);
+ fprintf(stderr, "Cannot open file %s\n", fname_w);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+
+ tsize = dtoh32(profiler.total_size);
+ buffer = (char*)malloc(tsize + MAX_PROFILE_DATA_SIZE);
+ if (buffer == NULL) {
+ fprintf(stderr, "Cannot not allocate %d bytes for profiler buffer\n",
+ tsize);
+ err = BCME_NOMEM;
+ goto exit;
+ }
+
+ if ((rsize = fread(buffer, 1, tsize, fp)) != tsize) {
+ fprintf(stderr, "Cannot read profiler data from file %s, req %d, read %d\n",
+ fname_r, tsize, rsize);
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ wsize = dtoh32(profiler.write_size);
+ rptr = dtoh32(profiler.start_ptr);
+ rsize = 0;
+
+ wl_init_frm_array(dir, files);
+
+ while (rsize < wsize) {
+ msch_collect_tlv_t *ptlv = (msch_collect_tlv_t *)(buffer + rptr);
+ int type, size, remain;
+ char *data;
+
+ size = ROUNDUP(WL_MSCH_PROFILE_HEAD_SIZE + dtoh16(ptlv->size));
+
+ rsize += size;
+ if (rsize > wsize)
+ break;
+
+ remain = tsize - rptr;
+ if (remain >= size) {
+ rptr += size;
+ if (rptr == tsize)
+ rptr = 0;
+ } else {
+ remain = size - remain;
+ memcpy(buffer + tsize, buffer, remain);
+ rptr = remain;
+ }
+
+ type = dtoh16(ptlv->type);
+ data = ptlv->value;
+
+ wl_msch_dump_data(data, type);
+ }
+
+ err = BCME_OK;
+
+exit:
+ if (fp)
+ fclose(fp);
+
+ if (buffer)
+ free(buffer);
+
+ if (mschfp) {
+ fflush(mschfp);
+ fclose(mschfp);
+ mschfp = NULL;
+ }
+
+ fflush(stdout);
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_nan.c b/wl/src/wl/exe/wluc_nan.c
new file mode 100644
index 0000000..3211439
--- /dev/null
+++ b/wl/src/wl/exe/wluc_nan.c
@@ -0,0 +1,6288 @@
+/*
+ * wl nan command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_nan.c 458728 2014-02-27 18:15:25Z $
+ */
+#ifdef WL_NAN
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+#include "wlu_avail_utils.h"
+#include <bcmiov.h>
+
+#if defined(linux)
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* linux */
+
+#include <miniopt.h>
+
+#include <bcmcrypto/sha256.h>
+#include <proto/nan.h>
+#include <bcmbloom.h>
+#include <bcmtlv.h>
+
+#define MAX_MAC_BUF 20
+#define MAX_RSSI_BUF 128
+#define MAX_OOB_AF_LIFETIME 512
+static void
+print_peer_rssi(wl_nan_peer_rssi_data_t *prssi);
+
+static cmd_func_t wl_nan_control;
+
+#define WLU_AVAIL_MAX_SLOTS 32
+#define WL_NAN_INVALID_NDPID 0
+
+#define NAN_PARAMS_USAGE \
+"\tUsage: wl nan [command] [cmd options] as follows:\n" \
+"\t\twl nan enable [1/0] - enable disable nan functionality\n" \
+"\t\twl nan state [role] - sets or gets the nan role\n" \
+"\t\twl nan hop_count [value] - sets or gets the hop count value\n" \
+"\t\twl nan hop_limit [value] - sets or gets the hop count threshold "\
+"value\n" \
+"\t\twl nan warm_up_time [value] - sets or gets the warm-up time in"\
+"units of seconds\n" \
+"\t\twl nan rssi_threshold [band][close][mid] - set rssi threshold for a band\n"\
+"\t\twl nan status - gets the status of NAN network \n" \
+"\t\twl nan OUI [value] - sets or gets the OUI value\n" \
+"\t\twl nan count - get counters\n" \
+"\t\twl nan clearcount - clears the counters\n" \
+"\t\twl nan chan [chan num] - sets the channel value\n" \
+"\t\twl nan band [value] - sets the band value(a/g/auto)\n" \
+"\t\twl nan host_enable [value] - enable/disable host election\n" \
+"\t\twl nan election_metrics [random_fact][master pref] - set random factor and preference\n" \
+"\t\twl nan election_metrics_state - get random fact and preference\n" \
+"\t\twl nan join [-start][cid] - joins/starts a nan network\n" \
+"\t\twl nan leave [cid]- leaves the network with cid mentioned\n" \
+"\t\twl nan merge [cid]- merges the network with cid mentioned\n" \
+"\t\twl nan stop [cid]- stop participating in the network\n" \
+"\t\twl nan publish [instance] [service name] [options] - get/set\n" \
+"\t\twl nan publish_list [..]\n" \
+"\t\twl nan cancel_publish [..]\n" \
+"\t\twl nan subscribe [instance] [service name] [options]\n" \
+"\t\twl nan subscribe_list [..]\n" \
+"\t\twl nan cancel_subscribe [..]\n" \
+"\t\twl nan vendor_info [..]\n" \
+"\t\twl nan disc_stats [..]\n" \
+"\t\twl nan disc_transmit [..]\n" \
+"\t\twl nan followup_transmit [..]\n" \
+"\t\twl nan show - Shows the NAN status\n" \
+"\t\twl nan tsreserve [bitmap] [channel list]\n" \
+"\t\twl nan tsschedule [..]\n" \
+"\t\twl nan tsrelease [bitmap]\n" \
+"\t\twl nan disc_connection [..]\n" \
+"\t\twl nan scan_params -s [scantime] -h [hometime] -i "\
+"[merge_scan_interval] -d [merge_scan_duration] -c [6,44,149]\n"\
+"\t\twl nan scan\n" \
+"\t\twl nan scanresults\n" \
+"\t\twl nan event_msgs\n" \
+"\t\twl nan event_check\n" \
+"\t\twl nan dump\n" \
+"\t\twl nan clear\n" \
+"\t\twl nan rssi\n" \
+"\t\twl nan disc_results\n" \
+"\t\twl nan dp_show\n" \
+"\t\twl nan dp_stats\n" \
+"\t\twl nan dp_status <ndp_id> <reason_code>\n" \
+"\t\twl nan dp_schedupd <ndp_id> \n" \
+"\t\twl nan dp_autoconn <val> - 0th bit for auto_dpresp, 1st bit for auto_dpconf \n" \
+"\t\twl nan dp_conf <ndp id> <status>\n" \
+"\t\twl nan dp_end <ndp id> <status>\n" \
+"\t\twl nan dp_req ucast/mcast pub_id <publisher id> peer_mac<peer mac address>" \
+" mcast_mac <if dest multicast addr exists> qos <tid, pkt_size, mean_data_rate, " \
+" max_service_interval> security <val> svc_spec_info <app specific info in hex>\n" \
+"\t\twl nan dp_resp ucast/mcast ndp_id <ndp id/ mc_id for unicast or multicast>" \
+" peer_mac<peer mac address> mcast_mac <if dest multicast addr exists>" \
+" qos <tid, pkt_size, mean_data_rate, max_service_interval> security <val>" \
+" svc_spec_info <app specific info in hex>\n" \
+"\tUsage: mutiple commands batching\n\n"\
+"\tA set of either SET or GET commands can be batched\n"\
+"\t\twl nan enable [1/0] + attr [MAC, ETC]\n" \
+"\t\tabove command issues SET enable and SET attr commands at a time\n"\
+"\t\twl nan enable + scanresults\n" \
+"\t\tabove command issues GET enable and GET scanresults commands at a time\n"
+
+typedef struct wl_nan_dp_sub_cmd wl_nan_dp_sub_cmd_t;
+typedef int (nan_dp_cmd_hdlr_t)(void *wl, const wl_nan_dp_sub_cmd_t *cmd, char **argv, int ndp_id);
+/* nan cmd list entry */
+struct wl_nan_dp_sub_cmd {
+ char *name; /* cmd name */
+ uint8 version; /* cmd version */
+ uint16 id; /* id for the dongle f/w switch/case */
+ uint16 type; /* base type of argument */
+ nan_dp_cmd_hdlr_t *handler; /* cmd handler */
+};
+
+#define NAN_DP_AVAIL_MAX_STR_LEN 32
+#define NAN_DP_AVAIL_ENTRIES 8
+
+typedef struct wl_nan_dp_avail_entry {
+ uint32 period;
+ char entry[NAN_DP_AVAIL_MAX_STR_LEN];
+} wl_nan_dp_avail_entry_t;
+
+static char *
+bcm_ether_ntoa(const struct ether_addr *ea, char *buf);
+
+static cmd_t wl_nan_cmds[] = {
+ { "nan", wl_nan_control, WLC_GET_VAR, WLC_SET_VAR, ""},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_nan_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register nan commands */
+ wl_module_cmds_register(wl_nan_cmds);
+}
+
+uint8
+wl_nan_resolution_timeunit(uint8 dur)
+{
+ switch (dur) {
+ case NAN_AVAIL_RES_16_TU:
+ return 16;
+ break;
+ case NAN_AVAIL_RES_32_TU:
+ return 32;
+ break;
+ case NAN_AVAIL_RES_64_TU:
+ return 64;
+ break;
+ default:
+ return 255;
+ }
+}
+
+uint8
+wl_nan_resolution_string_to_num(const char *res)
+{
+ uint8 res_n = NAN_AVAIL_RES_INVALID;
+ if (!strcmp(res, "16tu")) {
+ res_n = NAN_AVAIL_RES_16_TU;
+ }
+ else if (!strcmp(res, "32tu")) {
+ res_n = NAN_AVAIL_RES_32_TU;
+ }
+ else if (!strcmp(res, "64tu")) {
+ res_n = NAN_AVAIL_RES_64_TU;
+ }
+ else {
+ // Invalid
+ }
+ return res_n;
+}
+
+static wl_nan_status_t
+wl_nan_is_instance_valid(int id)
+{
+ wl_nan_status_t ret = WL_NAN_E_OK;
+
+ if (id <= 0 || id > 255) {
+ ret = WL_NAN_E_BAD_INSTANCE;
+ }
+
+ return ret;
+}
+
+static int
+bcm_pack_xtlv_entry_from_hex_string(uint8 **tlv_buf, uint16 *buflen, uint16 type, char *hex);
+static int wl_nan_bloom_create(bcm_bloom_filter_t** bp, uint* idx, uint size);
+static void* wl_nan_bloom_alloc(void *ctx, uint size);
+static void wl_nan_bloom_free(void *ctx, void *buf, uint size);
+static uint wl_nan_hash(void* ctx, uint idx, const uint8 *input, uint input_len);
+static void wlu_nan_print_wl_avail_entry(uint8 avail_type, wl_avail_entry_t* entry);
+static int wl_nan_set_avail_entry_optional(char** argv, wl_avail_new_t* avail,
+ wl_avail_entry_t* entry, uint8 avail_type, uint8* num);
+
+/* ************************** wl NAN command & event handlers ********************** */
+#define NAN_ERROR(x) printf x
+#define WL_NAN_FUNC(suffix) wl_nan_subcmd_ ##suffix
+#define NAN_IOC_BUFSZ 256 /* some sufficient ioc buff size for our module */
+#define NAN_BLOOM_LENGTH_DEFAULT 240
+#define NAN_SRF_MAX_MAC (NAN_BLOOM_LENGTH_DEFAULT / ETHER_ADDR_LEN)
+/* Mask for CRC32 output, used in hash function for NAN bloom filter */
+#define NAN_BLOOM_CRC32_MASK 0xFFFF
+
+struct tlv_info_list {
+ char *name;
+ enum wl_nan_sub_cmd_xtlv_id type;
+};
+
+/* nan ioctl sub cmd handler functions */
+static cmd_handler_t wl_nan_subcmd_cfg_enable;
+static cmd_handler_t wl_nan_subcmd_cfg_state;
+static cmd_handler_t wl_nan_subcmd_cfg_hop_count;
+static cmd_handler_t wl_nan_subcmd_cfg_hop_limit;
+static cmd_handler_t wl_nan_subcmd_cfg_warmup_time;
+static cmd_handler_t wl_nan_subcmd_cfg_rssi_threshold;
+static cmd_handler_t wl_nan_subcmd_cfg_status;
+static cmd_handler_t wl_nan_subcmd_cfg_oui;
+static cmd_handler_t wl_nan_subcmd_cfg_count;
+static cmd_handler_t wl_nan_subcmd_cfg_clearcount;
+static cmd_handler_t wl_nan_subcmd_cfg_channel;
+static cmd_handler_t wl_nan_subcmd_cfg_band;
+static cmd_handler_t wl_nan_subcmd_cfg_cid;
+static cmd_handler_t wl_nan_subcmd_cfg_if_addr;
+static cmd_handler_t wl_nan_subcmd_cfg_bcn_interval;
+static cmd_handler_t wl_nan_subcmd_cfg_sdf_txtime;
+static cmd_handler_t wl_nan_subcmd_cfg_stop_bcn_tx;
+static cmd_handler_t wl_nan_subcmd_cfg_sid_beacon;
+static cmd_handler_t wl_nan_subcmd_cfg_dw_len;
+static cmd_handler_t wl_nan_subcmd_cfg_awake_dw;
+static cmd_handler_t wl_nan_subcmd_cfg_wfa_testmode;
+static cmd_handler_t wl_nan_subcmd_election_host_enable;
+static cmd_handler_t wl_nan_subcmd_election_metrics_config;
+static cmd_handler_t wl_nan_subcmd_election_metrics_state;
+static cmd_handler_t wl_nan_subcmd_join;
+static cmd_handler_t wl_nan_subcmd_leave;
+static cmd_handler_t wl_nan_subcmd_merge;
+static cmd_handler_t wl_nan_subcmd_stop;
+static cmd_handler_t wl_nan_subcmd_publish;
+static cmd_handler_t wl_nan_subcmd_publish_list;
+static cmd_handler_t wl_nan_subcmd_cancel_publish;
+static cmd_handler_t wl_nan_subcmd_subscribe;
+static cmd_handler_t wl_nan_subcmd_subscribe_list;
+static cmd_handler_t wl_nan_subcmd_cancel_subscribe;
+static cmd_handler_t wl_nan_subcmd_sd_vendor_info;
+static cmd_handler_t wl_nan_subcmd_sd_statistics;
+static cmd_handler_t wl_nan_subcmd_sd_transmit;
+static cmd_handler_t wl_nan_subcmd_sd_connection;
+static cmd_handler_t wl_nan_subcmd_sd_show;
+static cmd_handler_t wl_nan_subcmd_sync_tsreserve;
+static cmd_handler_t wl_nan_subcmd_sync_tsschedule;
+static cmd_handler_t wl_nan_subcmd_sync_tsrelease;
+static cmd_handler_t wl_nan_subcmd_scan;
+static cmd_handler_t wl_nan_subcmd_scan_params;
+static cmd_handler_t wl_nan_subcmd_disc_results;
+static cmd_handler_t wl_nan_subcmd_dbg_scan_results;
+static cmd_handler_t wl_nan_subcmd_event_msgs;
+#if defined(linux)
+static cmd_handler_t wl_nan_subcmd_event_check;
+#endif
+static cmd_handler_t wl_nan_subcmd_dump;
+static cmd_handler_t wl_nan_subcmd_clear;
+static cmd_handler_t wl_nan_subcmd_dbg_rssi;
+static cmd_handler_t wl_nan_subcmd_dbg_level;
+/* nan 2.0 */
+static cmd_handler_t wl_nan_subcmd_dp_cap;
+static cmd_handler_t wl_nan_subcmd_dp_autoconn;
+static cmd_handler_t wl_nan_subcmd_dp_req;
+static cmd_handler_t wl_nan_subcmd_dp_resp;
+static cmd_handler_t wl_nan_subcmd_dp_conf;
+static cmd_handler_t wl_nan_subcmd_dp_dataend;
+static cmd_handler_t wl_nan_subcmd_dp_status;
+static cmd_handler_t wl_nan_subcmd_dp_stats;
+static cmd_handler_t wl_nan_subcmd_dp_show;
+static cmd_handler_t wl_nan_subcmd_dp_schedupd;
+static cmd_handler_t wl_nan_subcmd_cfg_avail;
+static cmd_handler_t wl_nan_subcmd_range_req;
+static cmd_handler_t wl_nan_subcmd_range_resp;
+static cmd_handler_t wl_nan_subcmd_range_cancel;
+static cmd_handler_t wl_nan_subcmd_range_auto;
+
+/* Mandatory parameters count for different commands */
+#define WL_NAN_CMD_CFG_OUI_ARGC 2
+#define WL_NAN_CMD_CFG_RSSI_THRESHOLD_ARGC 3
+#define WL_NAN_CMD_CFG_ELECTION_METRICS_ARGC 2
+#define WL_NAN_CMD_CFG_SID_BCN_ARGC 2
+
+static const wl_nan_sub_cmd_t nan_cmd_list[] = {
+ /* wl nan enable [0/1] or new: "wl nan [0/1]" */
+ {"enable", 0x01, WL_NAN_CMD_CFG_ENABLE,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_enable)
+ },
+ /* read write multiple nan attributes (obsolete) */
+ {"state", 0x01, WL_NAN_CMD_CFG_STATE,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_state),
+ },
+ /* -- var attributes (treated as cmds now) -- */
+ {"hop_count", 0x01, WL_NAN_CMD_CFG_HOP_CNT,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_hop_count),
+ },
+ {"hop_limit", 0x01, WL_NAN_CMD_CFG_HOP_LIMIT,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_hop_limit),
+ },
+ {"warm_up_time", 0x01, WL_NAN_CMD_CFG_WARMUP_TIME,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_warmup_time),
+ },
+ {"rssi_threshold", 0x01, WL_NAN_CMD_CFG_RSSI_THRESHOLD,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_rssi_threshold),
+ },
+ {"status", 0x01, WL_NAN_CMD_CFG_STATUS,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_status),
+ },
+ {"OUI", 0x01, WL_NAN_CMD_CFG_OUI,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_oui)
+ },
+ {"count", 0x01, WL_NAN_CMD_CFG_COUNT,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_count)
+ },
+ {"clearcount", 0x01, WL_NAN_CMD_CFG_CLEARCOUNT,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_clearcount)
+ },
+ {"chan", 0x01, WL_NAN_CMD_CFG_CHANNEL,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_channel)
+ },
+ {"band", 0x01, WL_NAN_CMD_CFG_BAND,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_band)
+ },
+ {"cluster_id", 0x01, WL_NAN_CMD_CFG_CID,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_cid)
+ },
+ {"if_addr", 0x01, WL_NAN_CMD_CFG_IF_ADDR,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_if_addr)
+ },
+ {"bcn_interval", 0x01, WL_NAN_CMD_CFG_BCN_INTERVAL,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_bcn_interval)
+ },
+ {"sdf_txtime", 0x01, WL_NAN_CMD_CFG_SDF_TXTIME,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_sdf_txtime)
+ },
+ {"stop_bcn_tx", 0x01, WL_NAN_CMD_CFG_STOP_BCN_TX,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_stop_bcn_tx)
+ },
+ {"sid_beacon", 0x01, WL_NAN_CMD_CFG_SID_BEACON,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_sid_beacon)
+ },
+ {"dw_len", 0x01, WL_NAN_CMD_CFG_DW_LEN,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_dw_len)
+ },
+ {"avail", 0x01, WL_NAN_CMD_CFG_AVAIL,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_avail)
+ },
+ {"awake_dw", 0x01, WL_NAN_CMD_CFG_AWAKE_DW,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_awake_dw)
+ },
+ {"wfa_testmode", 0x01, WL_NAN_CMD_CFG_WFA_TM,
+ IOVT_BUFFER, WL_NAN_FUNC(cfg_wfa_testmode)
+ },
+ /* ------- nan mac/disc engine commands ---- */
+ {"host_enable", 0x01, WL_NAN_CMD_ELECTION_HOST_ENABLE,
+ IOVT_BUFFER, WL_NAN_FUNC(election_host_enable)
+ },
+ {"election_metrics", 0x01, WL_NAN_CMD_ELECTION_METRICS_CONFIG,
+ IOVT_BUFFER, WL_NAN_FUNC(election_metrics_config)
+ },
+ {"election_metrics_state", 0x01, WL_NAN_CMD_ELECTION_METRICS_STATE,
+ IOVT_BUFFER, WL_NAN_FUNC(election_metrics_state)
+ },
+ {"join", 0x01, WL_NAN_CMD_ELECTION_JOIN,
+ IOVT_BUFFER, WL_NAN_FUNC(join)
+ },
+ {"leave", 0x01, WL_NAN_CMD_ELECTION_LEAVE,
+ IOVT_BUFFER, WL_NAN_FUNC(leave)
+ },
+ {"merge", 0x01, WL_NAN_CMD_ELECTION_MERGE,
+ IOVT_BUFFER, WL_NAN_FUNC(merge)
+ },
+ {"stop", 0x01, WL_NAN_CMD_ELECTION_STOP,
+ IOVT_BUFFER, WL_NAN_FUNC(stop)
+ },
+ {"publish", 0x01, WL_NAN_CMD_SD_PUBLISH,
+ IOVT_BUFFER, WL_NAN_FUNC(publish)
+ },
+ {"publish_list", 0x01, WL_NAN_CMD_SD_PUBLISH_LIST,
+ IOVT_BUFFER, WL_NAN_FUNC(publish_list)
+ },
+ {"cancel_publish", 0x01, WL_NAN_CMD_SD_CANCEL_PUBLISH,
+ IOVT_BUFFER, WL_NAN_FUNC(cancel_publish)
+ },
+ {"subscribe", 0x01, WL_NAN_CMD_SD_SUBSCRIBE,
+ IOVT_BUFFER, WL_NAN_FUNC(subscribe)
+ },
+ {"subscribe_list", 0x01, WL_NAN_CMD_SD_SUBSCRIBE_LIST,
+ IOVT_BUFFER, WL_NAN_FUNC(subscribe_list)
+ },
+ {"cancel_subscribe", 0x01, WL_NAN_CMD_SD_CANCEL_SUBSCRIBE,
+ IOVT_BUFFER, WL_NAN_FUNC(cancel_subscribe)
+ },
+ {"vendor_info", 0x01, WL_NAN_CMD_SD_VND_INFO,
+ IOVT_BUFFER, WL_NAN_FUNC(sd_vendor_info)
+ },
+ {"disc_stats", 0x01, WL_NAN_CMD_SD_STATS,
+ IOVT_BUFFER, WL_NAN_FUNC(sd_statistics)
+ },
+ {"disc_transmit", 0x01, WL_NAN_CMD_SD_TRANSMIT,
+ IOVT_BUFFER, WL_NAN_FUNC(sd_transmit)
+ },
+ {"followup_transmit", 0x01, WL_NAN_CMD_SD_FUP_TRANSMIT,
+ IOVT_BUFFER, WL_NAN_FUNC(sd_transmit)
+ },
+ {"disc_connection", 0x01, WL_NAN_CMD_SD_CONNECTION,
+ IOVT_BUFFER, WL_NAN_FUNC(sd_connection)
+ },
+ /* uses same cmd handler for as status */
+ {"show", 0x01, WL_NAN_CMD_SD_SHOW,
+ IOVT_BUFFER, WL_NAN_FUNC(sd_show)
+ },
+ /* time sync commands */
+ {"tsreserve", 0x01, WL_NAN_CMD_SYNC_TSRESERVE,
+ IOVT_BUFFER, WL_NAN_FUNC(sync_tsreserve)
+ },
+ {"tsschedule", 0x01, WL_NAN_CMD_SYNC_TSSCHEDULE,
+ IOVT_BUFFER, WL_NAN_FUNC(sync_tsschedule)
+ },
+ {"tsrelease", 0x01, WL_NAN_CMD_SYNC_TSRELEASE,
+ IOVT_BUFFER, WL_NAN_FUNC(sync_tsrelease)
+ },
+ /* nan debug commands */
+ {"scan_params", 0x01, WL_NAN_CMD_DBG_SCAN_PARAMS,
+ IOVT_BUFFER, WL_NAN_FUNC(scan_params)
+ },
+ {"scan", 0x01, WL_NAN_CMD_DBG_SCAN,
+ IOVT_BUFFER, WL_NAN_FUNC(scan)
+ },
+ {"scanresults", 0x01, WL_NAN_CMD_DBG_SCAN_RESULTS,
+ IOVT_BUFFER, WL_NAN_FUNC(dbg_scan_results)
+ },
+ {"event_msgs", 0x01, WL_NAN_CMD_DBG_EVENT_MASK,
+ IOVT_BUFFER, WL_NAN_FUNC(event_msgs)
+ },
+ {"dbg", 0x01, WL_NAN_CMD_DBG_LEVEL,
+ IOVT_BUFFER, WL_NAN_FUNC(dbg_level)
+ },
+#if defined(linux)
+ {"event_check", 0x01, WL_NAN_CMD_DBG_EVENT_CHECK,
+ IOVT_BUFFER, WL_NAN_FUNC(event_check)
+ },
+#endif
+ {"dump", 0x01, WL_NAN_CMD_DBG_DUMP,
+ IOVT_BUFFER, WL_NAN_FUNC(dump),
+ },
+ {"clear", 0x01, WL_NAN_CMD_DBG_CLEAR,
+ IOVT_BUFFER, WL_NAN_FUNC(clear),
+ },
+ /* uses same cmd handler for as status */
+ {"rssi", 0x01, WL_NAN_CMD_DBG_RSSI,
+ IOVT_BUFFER, WL_NAN_FUNC(dbg_rssi)
+ },
+ {"disc_results", 0x01, WL_NAN_CMD_DBG_DISC_RESULTS,
+ IOVT_BUFFER, WL_NAN_FUNC(disc_results)
+ },
+ /* nan2.0 data iovars */
+ {"dp_cap", 0x01, WL_NAN_CMD_DATA_CAP,
+ IOVT_BUFFER, WL_NAN_FUNC(dp_cap)
+ },
+ {"dp_autoconn", 0x01, WL_NAN_CMD_DATA_AUTOCONN,
+ IOVT_BUFFER, WL_NAN_FUNC(dp_autoconn)
+ },
+ {"dp_req", 0x01, WL_NAN_CMD_DATA_DATAREQ,
+ IOVT_BUFFER, WL_NAN_FUNC(dp_req)
+ },
+ {"dp_resp", 0x01, WL_NAN_CMD_DATA_DATARESP,
+ IOVT_BUFFER, WL_NAN_FUNC(dp_resp)
+ },
+ {"dp_conf", 0x01, WL_NAN_CMD_DATA_DATACONF,
+ IOVT_BUFFER, WL_NAN_FUNC(dp_conf)
+ },
+ {"dp_end", 0x01, WL_NAN_CMD_DATA_DATAEND,
+ IOVT_BUFFER, WL_NAN_FUNC(dp_dataend)
+ },
+ {"dp_status", 0x01, WL_NAN_CMD_DATA_STATUS,
+ IOVT_BUFFER, WL_NAN_FUNC(dp_status)
+ },
+ {"dp_stats", 0x01, WL_NAN_CMD_DATA_STATS,
+ IOVT_BUFFER, WL_NAN_FUNC(dp_stats)
+ },
+ {"dp_schedupd", 0x01, WL_NAN_CMD_DATA_SCHEDUPD,
+ IOVT_BUFFER, WL_NAN_FUNC(dp_schedupd)
+ },
+ {"dp_show", 0x01, WL_NAN_CMD_DATA_NDP_SHOW,
+ IOVT_BUFFER, WL_NAN_FUNC(dp_show)
+ },
+ {"range_req", 0x01, WL_NAN_CMD_RANGE_REQUEST,
+ IOVT_BUFFER, WL_NAN_FUNC(range_req)
+ },
+ {"range_auto", 0x01, WL_NAN_CMD_RANGE_AUTO,
+ IOVT_BUFFER, WL_NAN_FUNC(range_auto)
+ },
+ {"range_resp", 0x01, WL_NAN_CMD_RANGE_RESPONSE,
+ IOVT_BUFFER, WL_NAN_FUNC(range_resp)
+ },
+ {"range_cncl", 0x01, WL_NAN_CMD_RANGE_CANCEL,
+ IOVT_BUFFER, WL_NAN_FUNC(range_cancel)
+ },
+ {NULL, 0, 0, 0, NULL}
+};
+
+#define NAN_HELP_ALL 0
+#define WL_NAN_HELP_FUNC(suffix) wl_nan_help_ ##suffix
+
+/* nan ioctl sub cmd handler functions */
+static cmd_help_handler_t wl_nan_help_cfg_enable;
+static cmd_help_handler_t wl_nan_help_sd_transmit;
+static cmd_help_handler_t wl_nan_help_sd_publish;
+static cmd_help_handler_t wl_nan_help_sd_cancel_publish;
+static cmd_help_handler_t wl_nan_help_sd_publish_list;
+static cmd_help_handler_t wl_nan_help_sd_subscribe;
+static cmd_help_handler_t wl_nan_help_sd_cancel_subscribe;
+static cmd_help_handler_t wl_nan_help_sd_subscribe_list;
+static cmd_help_handler_t wl_nan_help_cfg_avail;
+static cmd_help_handler_t wl_nan_help_dp_req;
+static cmd_help_handler_t wl_nan_help_dp_resp;
+static cmd_help_handler_t wl_nan_help_dp_conf;
+static cmd_help_handler_t wl_nan_help_dp_end;
+static cmd_help_handler_t wl_nan_help_cfg_wfa_testmode;
+
+static const wl_nan_cmd_help_t nan_cmd_help_list[] = {
+ /* wl nan enable [0/1] or new: "wl nan [0/1]" */
+ {WL_NAN_CMD_CFG_ENABLE, WL_NAN_HELP_FUNC(cfg_enable)},
+ {WL_NAN_CMD_SD_FUP_TRANSMIT, WL_NAN_HELP_FUNC(sd_transmit)},
+ {WL_NAN_CMD_SD_TRANSMIT, WL_NAN_HELP_FUNC(sd_transmit)},
+ {WL_NAN_CMD_SD_PUBLISH, WL_NAN_HELP_FUNC(sd_publish)},
+ {WL_NAN_CMD_SD_CANCEL_PUBLISH, WL_NAN_HELP_FUNC(sd_cancel_publish)},
+ {WL_NAN_CMD_SD_PUBLISH_LIST, WL_NAN_HELP_FUNC(sd_publish_list)},
+ {WL_NAN_CMD_SD_SUBSCRIBE, WL_NAN_HELP_FUNC(sd_subscribe)},
+ {WL_NAN_CMD_SD_CANCEL_SUBSCRIBE, WL_NAN_HELP_FUNC(sd_cancel_subscribe)},
+ {WL_NAN_CMD_SD_SUBSCRIBE_LIST, WL_NAN_HELP_FUNC(sd_subscribe_list)},
+ {WL_NAN_CMD_CFG_AVAIL, WL_NAN_HELP_FUNC(cfg_avail)},
+ {WL_NAN_CMD_DATA_DATAREQ, WL_NAN_HELP_FUNC(dp_req)},
+ {WL_NAN_CMD_DATA_DATARESP, WL_NAN_HELP_FUNC(dp_resp)},
+ {WL_NAN_CMD_DATA_DATACONF, WL_NAN_HELP_FUNC(dp_conf)},
+ {WL_NAN_CMD_DATA_DATAEND, WL_NAN_HELP_FUNC(dp_end)},
+ {WL_NAN_CMD_CFG_WFA_TM, WL_NAN_HELP_FUNC(cfg_wfa_testmode)},
+ {0, NULL}
+};
+
+void
+wl_nan_help_cfg_enable(void)
+{
+ printf("wl nan enable [<1|0>]\n");
+ printf("\t1: Enable\n\t0: Disable\n");
+}
+
+void
+wl_nan_help_sd_transmit(void)
+{
+ printf("wl nan followup_transmit lcl-inst <local-instance-id> "
+ "remote-inst <remote-instance-id> dest-mac <destination MAC>\n");
+}
+
+void
+wl_nan_help_sd_publish(void)
+{
+ printf("\t\twl nan publish [instance] [service name] [options] - get/set\n");
+}
+
+void
+wl_nan_help_sd_cancel_publish(void)
+{
+ printf("\t\twl nan cancel_publish [..]\n");
+}
+
+void
+wl_nan_help_sd_publish_list(void)
+{
+ printf("\t\twl nan publish_list [..]\n");
+}
+
+void
+wl_nan_help_sd_subscribe(void)
+{
+ printf("\t\twl nan subscribe [instance] [service name] [options]\n");
+}
+
+void
+wl_nan_help_sd_cancel_subscribe(void)
+{
+ printf("\t\twl nan cancel_subscribe [..]\n");
+}
+
+void
+wl_nan_help_sd_subscribe_list(void)
+{
+ printf("\t\twl nan subscribe_list [..]\n");
+}
+
+void
+wl_nan_help_cfg_avail(void)
+{
+ printf("\twl nan avail <avail type> entry <entry type> [bitmap | otahexmap <>] ");
+ printf("[optional params] [entry...]\n\n");
+ printf("\tMandatory params\n");
+ printf("\t\t<avail type> 1=local, 2=peer, 3=ndc base sched, 4=immutable, ");
+ printf("5=response, 6=counter, 7=ranging\n");
+ printf("\t\t<entry type> 1=committed, 2=potential, 4=conditional\n");
+ printf("\tOptional params\n");
+ printf("\t\t[bitdur <0=16TU(default), 1=32TU, 2=64TU, 3=128TU>]\n");
+ printf("\t\t[period <0=non-repeatable, 1=128TU, 2=256TU, 3=512TU(default), ");
+ printf("4=1024TU, 5=2048TU, 6=4096TU, 7=8192TU>]\n");
+ printf("\t\t[offset <0 - 511>] default = 0\n");
+ printf("\t\t[usage <0-3>] default = 3\n");
+ printf("\t\t[ndc <ether addr format>] default = AA:BB:CC:00:00:00, ");
+ printf("ndc id for ndc base sched avail\n");
+ printf("\t\t[chanspec | band <chanspec or band id>] default = 0, ");
+ printf("which means all bands/chanspec are supported\n");
+ printf("\t\t[peer <ether addr format>] default = 00:90:4c:AA:BB:CC, ");
+ printf("peer nmi address for peer avail\n");
+}
+
+void
+wl_nan_help_dp_req(void)
+{
+ printf("\twl nan dp_req ucast/mcast pub_id <publisher id> [confirm] peer_mac"
+ "<peer mac address> [mcast_mac <if dest multicast addr exists>] qos"
+ "<tid, pkt_size, mean_data_rate, max_service_interval> [security <val>]"
+ "[svc_spec_info <app specific info in hex>]\n");
+}
+
+void
+wl_nan_help_dp_resp(void)
+{
+ printf("\twl nan dp_resp ucast/mcast ndp_id <ndp id/ mc_id for unicast or multicast>"
+ "peer_mac<peer mac address> mcast_mac <if dest multicast addr exists>"
+ "qos <tid, pkt_size, mean_data_rate, max_service_interval> security <val>"
+ "svc_spec_info <app specific info in hex>\n");
+}
+
+void
+wl_nan_help_dp_conf(void)
+{
+ printf("\twl nan dp_conf <ndp id> <status>\n");
+}
+
+void
+wl_nan_help_dp_end(void)
+{
+ printf("\twl nan dp_end <ndp id> <status>\n");
+}
+
+void
+wl_nan_help_cfg_wfa_testmode(void)
+{
+ printf("\twl nan wfa_testmode [<flags>]\n");
+ printf("\t\t<flags> for wfa testmode operation\n");
+ printf("\t\t0x00000001 ignore NDP terminate AF\n");
+ printf("\t\t0x00000002 ignore rx'ed data frame outside NDL CRBs\n");
+ printf("\t\t0x00000004 allow tx data frame outside NDL CRBs\n");
+ printf("\t\t0x00000008 enforce NDL counter proposal\n");
+}
+
+static char *
+bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
+{
+ static const char hex[] =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+ const uint8 *octet = ea->octet;
+ char *p = buf;
+ int i;
+ for (i = 0; i < 6; i++, octet++) {
+ *p++ = hex[(*octet >> 4) & 0xf];
+ *p++ = hex[*octet & 0xf];
+ *p++ = ':';
+ }
+ *(p-1) = '\0';
+ return (buf);
+}
+void print_nan_role(uint32 role)
+{
+ const char *msg = "";
+ if (role == WL_NAN_ROLE_AUTO) {
+ msg = "auto";
+ } else
+ if (role == WL_NAN_ROLE_NON_MASTER_NON_SYNC) {
+ msg = "non-master-non-sync";
+ } else
+ if (role == WL_NAN_ROLE_NON_MASTER_SYNC) {
+ msg = "non-master-sync";
+ } else
+ if (role == WL_NAN_ROLE_MASTER) {
+ msg = "master";
+ } else
+ if (role == WL_NAN_ROLE_ANCHOR_MASTER) {
+ msg = "anchor-master";
+ } else {
+ msg = "undefined";
+ }
+ printf("> role %d: %s\n", role, msg);
+}
+
+static void
+get_nan_band(char *str, uint8 band)
+{
+ if (band == NAN_BAND_B)
+ memcpy(str, "b", sizeof("b"));
+ else if (band == NAN_BAND_A)
+ memcpy(str, "a", sizeof("a"));
+ else if (band == NAN_BAND_AUTO)
+ memcpy(str, "auto", WL_NAN_BAND_STR_SIZE);
+}
+
+static uint8
+set_nan_band(char *str)
+{
+ uint8 nan_band = NAN_BAND_INVALID;
+ if (!strcmp("a", str))
+ nan_band = NAN_BAND_A;
+ else if (!strcmp("b", str))
+ nan_band = NAN_BAND_B;
+ else if (!strcmp("auto", str))
+ nan_band = NAN_BAND_AUTO;
+
+ return nan_band;
+}
+
+static char *
+get_nan_cmd_name(uint16 cmd_id)
+{
+ const wl_nan_sub_cmd_t *nancmd = &nan_cmd_list[0];
+
+ while (nancmd->name != NULL) {
+ if (nancmd->id == cmd_id) {
+ return nancmd->name;
+ }
+ nancmd++;
+ }
+ return NULL;
+}
+
+static void
+wl_nan_print_status(wl_nan_cfg_status_t *nstatus)
+{
+ printf("> enabled:%d\n", nstatus->enabled);
+ printf("> inited:%d\n", nstatus->inited);
+ printf("> joined:%d\n", nstatus->joined);
+ bcm_ether_ntoa(&nstatus->cid, buf);
+ printf("> cluster_id: %s\n", buf);
+
+ nstatus->chspec[0] = dtoh16(nstatus->chspec[0]);
+ if (wf_chspec_valid(nstatus->chspec[0])) {
+ wf_chspec_ntoa(nstatus->chspec[0], buf);
+ printf("> chanspec[0]:%s 0x%x\n", buf,
+ nstatus->chspec[0]);
+ } else {
+ printf("> chanspec[0]: invalid 0x%x\n",
+ nstatus->chspec[0]);
+ }
+
+ nstatus->chspec[1] = dtoh16(nstatus->chspec[1]);
+ if (wf_chspec_valid(nstatus->chspec[1])) {
+ wf_chspec_ntoa(nstatus->chspec[1], buf);
+ printf("> chanspec[1]:%s 0x%x\n", buf,
+ nstatus->chspec[1]);
+ } else {
+ printf("> chanspec[1]: invalid 0x%x\n",
+ nstatus->chspec[1]);
+ }
+ print_nan_role(nstatus->role);
+ prhex("> master_rank:", nstatus->mr, NAN_MASTER_RANK_LEN);
+ prhex("> amr", nstatus->amr, NAN_MASTER_RANK_LEN);
+ printf("> hop_count:%d\n", nstatus->hop_count);
+ printf("> ambtt:%d\n", nstatus->ambtt);
+ printf("> cnt_pend_txfrm:%d\n",
+ dtoh32(nstatus->cnt_pend_txfrm));
+ printf("> cnt_bcn_tx:%d\n",
+ dtoh32(nstatus->cnt_bcn_tx));
+ printf("> cnt_bcn_rx:%d\n",
+ dtoh32(nstatus->cnt_bcn_rx));
+ printf("> cnt_svc_disc_tx:%d\n",
+ dtoh32(nstatus->cnt_svc_disc_tx));
+ printf("> cnt_svc_disc_rx:%d\n",
+ dtoh32(nstatus->cnt_svc_disc_rx));
+}
+
+static void
+wlu_nan_print_wl_avail_entry(uint8 avail_type, wl_avail_entry_t* entry)
+{
+ wl_avail_entry_t* e = entry;
+ uint16 eflags = (ltoh_ua(&e->flags));
+ int j, k;
+ uint8 tmp;
+
+ prhex("\n Entry", (uchar*)e, e->length);
+ if (avail_type < WL_AVAIL_NDC) {
+ printf(" Avail type (1=committed, 2=potential, 4=conditional): ");
+ printf("%d\n", eflags & (WL_AVAIL_ENTRY_COM | WL_AVAIL_ENTRY_POT |
+ WL_AVAIL_ENTRY_COND));
+ if (eflags & WL_AVAIL_ENTRY_BAND_PRESENT) {
+ printf(" Band: %d\n", ltoh_ua(&e->u.band));
+ } else if (eflags & WL_AVAIL_ENTRY_CHAN_PRESENT) {
+ printf(" Chanspec: 0x%x\n", ltoh_ua(&e->u.channel_info));
+ } else {
+ printf(" Support all bands and channels\n");
+ }
+ printf(" Flags: 0x%04x, Usage pref: %d \n", eflags,
+ WL_AVAIL_ENTRY_USAGE_VAL(eflags));
+ }
+ if (e->bitmap_len) {
+ printf(" Start offset: %d TU | Period: %d TU | Bit dur: %d TU\n",
+ 16 * (ltoh_ua(&e->start_offset)),
+ (e->period ? 128 << (e->period - 1) : 0),
+ 16 << (WL_AVAIL_ENTRY_BIT_DUR_VAL(ltoh_ua(&e->flags))));
+ printf(" Time bitmap (b0b1...): ");
+ for (j = 0; j < e->bitmap_len; j++) {
+ if ((uint8*)(e->bitmap + j)) {
+ tmp = *((uint8*)(e->bitmap + j));
+ for (k = 0; k < NBBY; k++) {
+ printf("%d", (tmp & 1) ? 1 : 0);
+ tmp >>= 1;
+ }
+ }
+ }
+ printf("\n");
+ } else {
+ printf(" No time bitmap: availabile on all time slots\n");
+ }
+}
+
+/*
+ * a cbfn function, displays bcm_xtlv variables rcvd in get ioctl's xtlv buffer.
+ * it can process GET result for all nan commands, provided that
+ * XTLV types (AKA the explicit xtlv types) packed into the ioctl buff
+ * are unique across all nan ioctl commands
+ */
+static int
+wlu_nan_set_vars_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
+{
+ int res = BCME_OK;
+ bcm_iov_batch_buf_t *b_resp = (bcm_iov_batch_buf_t *)ctx;
+ uint8 uv8;
+ int32 status;
+ uint16 cmd_rsp_len;
+ char *cmd_name;
+ char band_str[WL_NAN_BAND_STR_SIZE];
+
+ /* cbfn params may be used in f/w */
+ if (len < sizeof(status)) {
+ return BCME_ERROR;
+ }
+
+ /* first 4 bytes consists status */
+ status = dtoh32(*(uint32 *)data);
+
+ data = data + sizeof(status);
+ cmd_rsp_len = len - sizeof(status);
+
+ if (b_resp->count == 0) {
+ /* No more tlvs to parse */
+ return BCME_OK;
+ }
+ /* If status is non zero */
+ if (status != BCME_OK) {
+ if ((cmd_name = get_nan_cmd_name(type)) == NULL) {
+ printf("Undefined command type %04x len %04x\n", type, len);
+ } else {
+ printf("%s failed, status: %04x\n", cmd_name, status);
+ }
+ return status;
+ }
+
+ /* Every response expects some data, return error if there is no data */
+ if (!cmd_rsp_len) {
+ return BCME_ERROR;
+ }
+
+ switch (type) {
+ case WL_NAN_CMD_CFG_ENABLE:
+ {
+ uv8 = *data;
+
+ printf("> nan: %s\n", uv8?"enabled":"disabled");
+ break;
+ }
+ case WL_NAN_CMD_DATA_DATAREQ:
+ {
+ wl_nan_dp_req_ret_t *dpreq_ret = (wl_nan_dp_req_ret_t *)data;
+
+ printf("> ndp_id: %d\n", (dpreq_ret->ndp_id));
+ bcm_ether_ntoa(&dpreq_ret->indi, buf);
+ printf("> ndi: %s\n", buf);
+ break;
+ }
+ case WL_NAN_CMD_DATA_DATARESP:
+ {
+ wl_nan_dp_resp_ret_t *dpresp_ret = (wl_nan_dp_resp_ret_t *)data;
+
+ printf("> nmsgid: %d\n", (dpresp_ret->nmsgid));
+ break;
+ }
+ case WL_NAN_CMD_RANGE_REQUEST:
+ {
+ wl_nan_range_id *range_id = (wl_nan_range_id *)data;
+ printf("> range_id %d\n", *range_id);
+ break;
+ }
+ case WL_NAN_CMD_ELECTION_MERGE:
+ {
+ uv8 = *data;
+
+ printf("> merge: %s\n", uv8?"enabled":"disabled");
+ break;
+ }
+ case WL_NAN_CMD_CFG_HOP_LIMIT:
+ {
+ uv8 = *data;
+
+ printf("> hop limit: %d\n", uv8);
+ break;
+ }
+ case WL_NAN_CMD_CFG_OUI:
+ {
+ wl_nan_oui_type_t *nan_oui_type = (wl_nan_oui_type_t *)data;
+
+ printf("> NAN OUI, type: \n");
+ printf("\tOUI %02X-%02X-%02X type %02X\n", nan_oui_type->nan_oui[0],
+ nan_oui_type->nan_oui[1], nan_oui_type->nan_oui[2],
+ nan_oui_type->type);
+ break;
+ }
+ case WL_NAN_CMD_CFG_CLEARCOUNT:
+ {
+ wl_nan_count_t *ncount = (wl_nan_count_t *)data;
+
+ printf("> NAN Counter:");
+ printf("\tnan_bcn_tx %d", dtoh32(ncount->cnt_bcn_tx));
+ printf("\tnan_bcn_rx %d", dtoh32(ncount->cnt_bcn_rx));
+ printf("\tnan_svc_disc_tx %d",
+ dtoh32(ncount->cnt_svc_disc_tx));
+ printf("\tnan_svc_disc_rx %d\n",
+ dtoh32(ncount->cnt_svc_disc_rx));
+ break;
+ }
+ case WL_NAN_CMD_CFG_RSSI_THRESHOLD:
+ {
+ wl_nan_rssi_threshold_t *rssi_threshold = (wl_nan_rssi_threshold_t *)data;
+
+ get_nan_band(band_str, *data);
+ printf("> nan band : %s\n", band_str);
+ printf("\trssi close : %d\n", rssi_threshold->rssi_close);
+ printf("\trssi mid : %d\n", rssi_threshold->rssi_mid);
+ break;
+ }
+ case WL_NAN_CMD_CFG_AWAKE_DW:
+ {
+ wl_nan_awake_dw_t *awake_dw = (wl_nan_awake_dw_t *)data;
+
+ get_nan_band(band_str, *data);
+ printf("> nan band : %s\n", band_str);
+ printf("\t DW Awake interval : %d\n", awake_dw->interval);
+ break;
+ }
+ case WL_NAN_CMD_ELECTION_METRICS_STATE:
+ {
+ wl_nan_election_metric_state_t *metric_state;
+ metric_state = (wl_nan_election_metric_state_t *)data;
+
+ printf("> Election metrics:\n");
+ printf("\tmaster preference:%d\n", metric_state->master_pref);
+ printf("\trandom factor:%d\n", metric_state->random_factor);
+ break;
+ }
+ case WL_NAN_CMD_DBG_DUMP:
+ {
+ wl_nan_dbg_dump_rsp_t *dump_rsp = (wl_nan_dbg_dump_rsp_t *)data;
+
+ if (dump_rsp->dump_type == WL_NAN_DBG_DT_STATS_DATA) {
+ wl_nan_stats_t *nan_stats = &dump_rsp->u.nan_stats;
+
+ printf("DWSlots: %u \t",
+ dtoh32(nan_stats->cnt_dw));
+ printf("DiscBcnSlots: %u\t",
+ dtoh32(nan_stats->cnt_disc_bcn_sch));
+ printf("AnchorMasterRecExp: %u\t",
+ dtoh32(nan_stats->cnt_amr_exp));
+ printf("BcnTpltUpd: %u\n",
+ dtoh32(nan_stats->cnt_bcn_upd));
+ printf("BcnTx: %u\t",
+ dtoh32(nan_stats->cnt_bcn_tx));
+ printf("SyncBcnTx: %u\t",
+ dtoh32(nan_stats->cnt_sync_bcn_tx));
+ printf("DiscBcnTx: %u\t",
+ dtoh32(nan_stats->cnt_disc_bcn_tx));
+ printf("BcnRx: %u\t",
+ dtoh32(nan_stats->cnt_bcn_rx));
+ printf("SyncBcnRx: %u\t",
+ dtoh32(nan_stats->cnt_sync_bcn_rx));
+ printf("DiscBcnRx: %u\n",
+ dtoh32(nan_stats->cnt_bcn_rx) -
+ dtoh32(nan_stats->cnt_sync_bcn_rx));
+ printf("SdfTx -> BcMc: %u Ucast: %u UcFail: %u\t",
+ dtoh32(nan_stats->cnt_sdftx_bcmc),
+ dtoh32(nan_stats->cnt_sdftx_uc),
+ dtoh32(nan_stats->cnt_sdftx_fail));
+ printf("SDFRx: %u\n",
+ dtoh32(nan_stats->cnt_sdf_rx));
+ printf("Roles -> AnchorMaster: %u\t",
+ dtoh32(nan_stats->cnt_am));
+ printf("Master: %u\t",
+ dtoh32(nan_stats->cnt_master));
+ printf("NonMasterSync: %u\t",
+ dtoh32(nan_stats->cnt_nms));
+ printf("NonMasterNonSync: %u\n",
+ dtoh32(nan_stats->cnt_nmns));
+ printf("UnschTx: %u\t",
+ dtoh32(nan_stats->cnt_err_unsch_tx));
+ printf("BcnTxErr: %u\t",
+ dtoh32(nan_stats->cnt_err_bcn_tx));
+ printf("SyncBcnTxMiss: %u\t",
+ dtoh32(nan_stats->cnt_sync_bcn_tx_miss));
+ printf("SyncBcnTxtimeErr: %u\n",
+ dtoh32(nan_stats->cnt_err_txtime));
+ printf("MschRegErr: %u\t",
+ dtoh32(nan_stats->cnt_err_msch_reg));
+ printf("WrongChCB: %u\t",
+ dtoh32(nan_stats->cnt_err_wrong_ch_cb));
+ printf("DWEarlyCB: %u\t",
+ dtoh32(nan_stats->cnt_dw_start_early));
+ printf("DWLateCB: %u\t",
+ dtoh32(nan_stats->cnt_dw_start_late));
+ printf("DWSkips: %u\t", dtoh16(nan_stats->cnt_dw_skip));
+ printf("DiscBcnSkips: %u\n",
+ dtoh16(nan_stats->cnt_disc_skip));
+ printf("MrgScan: %u\t",
+ dtoh32(nan_stats->cnt_mrg_scan));
+ printf("MrgScanRej: %u\t",
+ dtoh32(nan_stats->cnt_err_ms_rej));
+ printf("JoinScanRej: %u\t",
+ dtoh32(nan_stats->cnt_join_scan_rej));
+ printf("NanScanAbort: %u\t",
+ dtoh32(nan_stats->cnt_nan_scan_abort));
+ printf("ScanRes: %u\t",
+ dtoh32(nan_stats->cnt_scan_results));
+ printf("NanEnab: %u\t",
+ dtoh32(nan_stats->cnt_nan_enab));
+ printf("NanDisab: %u\n",
+ dtoh32(nan_stats->cnt_nan_disab));
+ } else if (dump_rsp->dump_type == WL_NAN_DBG_DT_RSSI_DATA) {
+ wl_nan_peer_rssi_data_t *prssi = &dump_rsp->u.peer_rssi;
+
+ print_peer_rssi(prssi);
+ }
+ }
+ break;
+ case WL_NAN_CMD_ELECTION_HOST_ENABLE:
+ {
+ uv8 = *data;
+
+ printf("> nan host: %s\n", uv8?"enabled":"disabled");
+ break;
+ }
+ case WL_NAN_CMD_DBG_LEVEL:
+ {
+ wl_nan_dbg_level_t *dbg_level = (wl_nan_dbg_level_t *)data;
+
+ printf("> nan_err_level : 0x%x\n> nan_dbg_level : 0x%x\n> nan_info_level : 0x%x\n ",
+ dtoh32(dbg_level->nan_err_level), dtoh32(dbg_level->nan_dbg_level),
+ dtoh32(dbg_level->nan_info_level));
+ break;
+ }
+ case WL_NAN_CMD_CFG_STATE:
+ {
+ wl_nan_role_config_t* r = (wl_nan_role_config_t*)data;
+
+ printf("> nan role/state : %d\n", r->role);
+ bcm_ether_ntoa(&r->target_master, buf);
+ printf("> target master: %s\n", buf);
+ break;
+ }
+ case WL_NAN_CMD_CFG_HOP_CNT:
+ {
+ uv8 = *data;
+
+ printf("> nan hop_cnt : %d\n", uv8);
+ break;
+ }
+ case WL_NAN_CMD_CFG_WARMUP_TIME:
+ {
+ printf("> nan warm up time : %d\n", dtoh16(*(uint16*)data));
+ break;
+ }
+ case WL_NAN_CMD_CFG_COUNT:
+ {
+ wl_nan_count_t *ncount = (wl_nan_count_t *)data;
+
+ printf("> NAN Counter:");
+ printf("\tnan_bcn_tx %d", dtoh32(ncount->cnt_bcn_tx));
+ printf("\tnan_bcn_rx %d", dtoh32(ncount->cnt_bcn_rx));
+ printf("\tnan_svc_disc_tx %d",
+ dtoh32(ncount->cnt_svc_disc_tx));
+ printf("\tnan_svc_disc_rx %d\n",
+ dtoh32(ncount->cnt_svc_disc_rx));
+
+ break;
+ }
+ case WL_NAN_CMD_CFG_STATUS:
+ {
+ wl_nan_cfg_status_t *nstatus = (wl_nan_cfg_status_t *)data;
+
+ wl_nan_print_status(nstatus);
+ break;
+ }
+ case WL_NAN_CMD_SYNC_TSRESERVE:
+ {
+ wl_nan_timeslot_t *tsp = (wl_nan_timeslot_t *)data;
+ int i;
+
+ printf("Bitmap 0x%08x\n", dtoh32(tsp->abitmap));
+ for (i = 0; i < NAN_MAX_TIMESLOT; i++) {
+ if (dtoh32(tsp->abitmap) & (1 << i)) {
+ printf("Slot %d Chanspec %x\n",
+ i, dtoh32(tsp->chanlist[i]));
+ }
+ }
+ }
+ break;
+ case WL_NAN_CMD_CFG_CID:
+ {
+ wl_nan_cluster_id_t *clid = (wl_nan_cluster_id_t *)data;
+ prhex("> Cluster-id:", (uint8 *)clid, ETHER_ADDR_LEN);
+ }
+ break;
+ case WL_NAN_CMD_CFG_IF_ADDR:
+ {
+ struct ether_addr *ea;
+
+ ea = (struct ether_addr *)data;
+ bcm_ether_ntoa(ea, buf);
+ printf("> if_addr: %s\n", buf);
+ }
+ break;
+ case WL_NAN_CMD_CFG_BCN_INTERVAL:
+ {
+ wl_nan_disc_bcn_interval_t bcn_interval;
+ bcn_interval = dtoh16(*(uint16 *)data);
+ printf("BCN interval = %d\n", bcn_interval);
+ }
+ break;
+ case WL_NAN_CMD_CFG_SDF_TXTIME:
+ {
+ wl_nan_svc_disc_txtime_t sdf_txtime;
+ sdf_txtime = dtoh16(*(uint16 *)data);
+ printf("SDF TXTIME = %d\n", sdf_txtime);
+ }
+ break;
+ case WL_NAN_CMD_CFG_STOP_BCN_TX:
+ {
+ wl_nan_stop_bcn_tx_t stop_bcn_tx;
+ stop_bcn_tx = dtoh16(*(uint16*)data);
+ printf("Stop bcn tx = %d\n", stop_bcn_tx);
+ }
+ break;
+ case WL_NAN_CMD_CFG_SID_BEACON:
+ {
+ wl_nan_sid_beacon_control_t *sid_bcn;
+ sid_bcn = (wl_nan_sid_beacon_control_t *)data;
+
+ printf("> SID beacon ctrl info:\n");
+ printf("\tsid: %s", sid_bcn->sid_enable?"enabled":"disabled");
+ printf("\tsid limit count: %d\n", sid_bcn->sid_count);
+ }
+ break;
+ case WL_NAN_CMD_CFG_DW_LEN:
+ {
+ wl_nan_dw_len_t dw_len;
+
+ dw_len = dtoh16(*(uint16 *)data);
+ printf("DW_LEN = %d\n", dw_len);
+ }
+ break;
+ case WL_NAN_CMD_CFG_AVAIL:
+ {
+ wl_avail_new_t *a = (wl_avail_new_t*)data;
+ wl_avail_entry_t *e;
+ uint8* p = (uint8*)a->entry;
+ uint16 flags = dtoh16(a->flags);
+ int i;
+ if (!a->length) {
+ break;
+ }
+ printf("\nType (1=local, 2=peer, 3=ndc, 4=immutable, 5=response, "
+ "6=counter, 7=ranging): %d\n", flags);
+ if (flags == WL_AVAIL_NDC) {
+ prhex("ndc id", (uint8 *)&a->u.addr, ETHER_ADDR_LEN);
+ }
+ for (i = 0; i < a->num_entries; i++) {
+ e = (wl_avail_entry_t*)p;
+ wlu_nan_print_wl_avail_entry(flags & WL_AVAIL_TYPE_MASK, e);
+ p += e->length;
+ }
+ break;
+ }
+ case WL_NAN_CMD_CFG_WFA_TM:
+ {
+ wl_nan_wfa_testmode_t flags;
+
+ flags = dtoh32(*(uint32 *)data);
+ printf("flag: 0x%08x\n", flags);
+
+ if (flags & WL_NAN_WFA_TM_IGNORE_TERMINATE_NAF) {
+ printf("\t0x00000001 ignore NDP terminate AF\n");
+ }
+ if (flags & WL_NAN_WFA_TM_IGNORE_RX_DATA_OUTSIDE_CRB) {
+ printf("\t0x00000002 ignore rx'ed data frame outside NDL CRBs\n");
+ }
+ if (flags & WL_NAN_WFA_TM_ALLOW_TX_DATA_OUTSIDE_CRB) {
+ printf("\t0x00000004 allow tx data frame outside NDL CRBs\n");
+ }
+ if (flags & WL_NAN_WFA_TM_ENFORCE_NDL_COUNTER) {
+ printf("\t0x00000008 enforce NDL counter proposal\n");
+ }
+ }
+ break;
+ case WL_NAN_CMD_SD_PARAMS:
+ case WL_NAN_CMD_SD_PUBLISH:
+ case WL_NAN_CMD_SD_SUBSCRIBE:
+ {
+ wl_nan_sd_params_t *sd_params = (wl_nan_sd_params_t *)data;
+ uint16 flags;
+
+ printf(">Instance ID: %d\n", sd_params->instance_id);
+ printf(">Length: %d\n", dtoh16(sd_params->length));
+ prhex(">Service Hash:", sd_params->svc_hash,
+ WL_NAN_SVC_HASH_LEN);
+ flags = dtoh16(sd_params->flags);
+ printf(">Flags: 0x%04x\n", flags);
+ if (flags & WL_NAN_PUB_UNSOLICIT) {
+ printf(" unsolicited/active\n");
+ }
+ if (flags & WL_NAN_PUB_SOLICIT) {
+ printf(" solicited\n");
+ }
+ if (!(flags & WL_NAN_PUB_UNSOLICIT) &&
+ !(flags & WL_NAN_PUB_SOLICIT)) {
+ printf(" passive\n");
+ }
+ if (flags & WL_NAN_FOLLOWUP) {
+ printf(" follow-up\n");
+ }
+ printf("\n");
+ printf(">RSSI: %d\n", sd_params->proximity_rssi);
+ printf(">TTL: 0x%08x\n", dtoh32(sd_params->ttl));
+ printf(">Period: %d\n", sd_params->period);
+ break;
+ }
+ case WL_NAN_CMD_SD_PUBLISH_LIST:
+ case WL_NAN_CMD_SD_SUBSCRIBE_LIST:
+ {
+ wl_nan_service_list_t *svc_list = (wl_nan_service_list_t *)data;
+ wl_nan_service_info_t *svc_info = NULL;
+ int i = 0;
+
+ printf("%s\n",
+ (type == WL_NAN_CMD_SD_PUBLISH_LIST) ? ">Publish List" :
+ ">Subscribe List");
+ printf(">Count: %d\n", svc_list->id_count);
+ for (i = 0; i < svc_list->id_count; i++) {
+ svc_info = &svc_list->list[i];
+ printf(">Instance ID: %d\n", svc_info->instance_id);
+ prhex(">Service Hash:", svc_info->service_hash,
+ WL_NAN_SVC_HASH_LEN);
+ printf("\n");
+ }
+ break;
+ }
+ case WL_NAN_CMD_DBG_EVENT_MASK:
+ {
+ wl_nan_event_mask_t mask;
+ mask = ltoh32_ua(data);
+ mask = dtoh32(mask);
+ printf("> event_mask: %x\n %s:%d\n %s:%d\n %s:%d\n"
+ " %s:%d\n %s:%d\n %s:%d\n %s:%d\n %s:%d\n"
+ " %s:%d\n %s:%d\n %s:%d\n %s:%d\n %s:%d\n",
+ mask,
+ "WL_NAN_EVENT_START",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_START),
+ "WL_NAN_EVENT_JOIN",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_JOIN),
+ "WL_NAN_EVENT_ROLE",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_ROLE),
+ "WL_NAN_EVENT_SCAN_COMPLETE",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_SCAN_COMPLETE),
+ "WL_NAN_EVENT_DISCOVERY_RESULT",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_DISCOVERY_RESULT),
+ "WL_NAN_EVENT_REPLIED",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_REPLIED),
+ "WL_NAN_EVENT_TERMINATED",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_TERMINATED),
+ "WL_NAN_EVENT_RECEIVE",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_RECEIVE),
+ "WL_NAN_EVENT_STATUS_CHG",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_STATUS_CHG),
+ "WL_NAN_EVENT_MERGE",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_MERGE),
+ "WL_NAN_EVENT_STOP",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_STOP),
+ "WL_NAN_EVENT_P2P",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_P2P),
+ "WL_NAN_EVENT_BCN_RX",
+ IS_NAN_EVT_ON(mask, WL_NAN_EVENT_BCN_RX));
+ }
+ break;
+ case WL_NAN_CMD_DBG_DISC_RESULTS:
+ {
+ wl_nan_disc_results_list_t *p;
+ int i;
+ char hash[WL_NAN_SVC_HASH_LEN+1];
+
+ p = (wl_nan_disc_results_list_t *)data;
+ printf(">Disc results: \n\n");
+ for (i = 0; i < WL_NAN_MAX_DISC_RESULTS; i++) {
+
+ memcpy(hash,
+ p->disc_result[i].svc_hash,
+ WL_NAN_SVC_HASH_LEN);
+
+ hash[WL_NAN_SVC_HASH_LEN] = '\0';
+
+ bcm_ether_ntoa(
+ (struct ether_addr *)
+ &p->disc_result[i].peer_mac,
+ buf);
+
+ printf(">Instance id: 0x%x \n"
+ ">Peer instance id: 0x%x \n",
+ p->disc_result[i].instance_id,
+ p->disc_result[i].peer_instance_id);
+ prhex(">Service hash", (uchar *)hash,
+ WL_NAN_SVC_HASH_LEN);
+ printf(">Peer MAC: %s \n\n", buf);
+ }
+ }
+ break;
+ case WL_NAN_CMD_DBG_STATS:
+ {
+ wl_nan_stats_t *nan_stats =
+ (wl_nan_stats_t *)data;
+ printf("DWSlots: %u \t",
+ dtoh32(nan_stats->cnt_dw));
+ printf("DiscBcnSlots: %u\t",
+ dtoh32(nan_stats->cnt_disc_bcn_sch));
+ printf("AnchorMasterRecExp: %u\t",
+ dtoh32(nan_stats->cnt_amr_exp));
+ printf("BcnTpltUpd: %u\n",
+ dtoh32(nan_stats->cnt_bcn_upd));
+ printf("BcnTx: %u\t",
+ dtoh32(nan_stats->cnt_bcn_tx));
+ printf("SyncBcnTx: %u\t",
+ dtoh32(nan_stats->cnt_sync_bcn_tx));
+ printf("DiscBcnTx: %u\t",
+ dtoh32(nan_stats->cnt_disc_bcn_tx));
+ printf("BcnRx: %u\t",
+ dtoh32(nan_stats->cnt_bcn_rx));
+ printf("SyncBcnRx: %u\t",
+ dtoh32(nan_stats->cnt_sync_bcn_rx));
+ printf("DiscBcnRx: %u\n",
+ dtoh32(nan_stats->cnt_bcn_rx) -
+ dtoh32(nan_stats->cnt_sync_bcn_rx));
+ printf("SdfTx -> BcMc: %u Ucast: %u UcFail: %u\t",
+ dtoh32(nan_stats->cnt_sdftx_bcmc),
+ dtoh32(nan_stats->cnt_sdftx_uc),
+ dtoh32(nan_stats->cnt_sdftx_fail));
+ printf("SDFRx: %u\n",
+ dtoh32(nan_stats->cnt_sdf_rx));
+ printf("Roles -> AnchorMaster: %u\t",
+ dtoh32(nan_stats->cnt_am));
+ printf("Master: %u\t",
+ dtoh32(nan_stats->cnt_master));
+ printf("NonMasterSync: %u\t",
+ dtoh32(nan_stats->cnt_nms));
+ printf("NonMasterNonSync: %u\n",
+ dtoh32(nan_stats->cnt_nmns));
+ printf("UnschTx: %u\t",
+ dtoh32(nan_stats->cnt_err_unsch_tx));
+ printf("BcnTxErr: %u\t",
+ dtoh32(nan_stats->cnt_err_bcn_tx));
+ printf("SyncBcnTxMiss: %u\t",
+ dtoh32(nan_stats->cnt_sync_bcn_tx_miss));
+ printf("SyncBcnTxtimeErr: %u\n",
+ dtoh32(nan_stats->cnt_err_txtime));
+ printf("MschRegErr: %u\t",
+ dtoh32(nan_stats->cnt_err_msch_reg));
+ printf("WrongChCB: %u\t",
+ dtoh32(nan_stats->cnt_err_wrong_ch_cb));
+ printf("DWEarlyCB: %u\t",
+ dtoh32(nan_stats->cnt_dw_start_early));
+ printf("DWLateCB: %u\t",
+ dtoh32(nan_stats->cnt_dw_start_late));
+ printf("DWSkips: %u\t", dtoh16(nan_stats->cnt_dw_skip));
+ printf("DiscBcnSkips: %u\n",
+ dtoh16(nan_stats->cnt_disc_skip));
+ printf("MrgScan: %u\t",
+ dtoh32(nan_stats->cnt_mrg_scan));
+ printf("MrgScanRej: %u\t",
+ dtoh32(nan_stats->cnt_err_ms_rej));
+ printf("JoinScanRej: %u\t",
+ dtoh32(nan_stats->cnt_join_scan_rej));
+ printf("NanScanAbort: %u\t",
+ dtoh32(nan_stats->cnt_nan_scan_abort));
+ printf("ScanRes: %u\t",
+ dtoh32(nan_stats->cnt_scan_results));
+ printf("NanEnab: %u\t",
+ dtoh32(nan_stats->cnt_nan_enab));
+ printf("NanDisab: %u\n",
+ dtoh32(nan_stats->cnt_nan_disab));
+ }
+ break;
+
+ case WL_NAN_CMD_DATA_NDP_SHOW:
+ {
+ int i = 0;
+ wl_nan_ndp_id_list_t *id_list;
+ id_list = (wl_nan_ndp_id_list_t *)data;
+
+ if (id_list == NULL) {
+ return BCME_ERROR;
+ }
+
+ for (; i < id_list->ndp_count; i++) {
+ printf("%d \t", id_list->lndp_id[i]);
+ }
+ printf("\n");
+ }
+ break;
+
+ case WL_NAN_CMD_DATA_CONFIG:
+ {
+ wl_nan_ndp_config_t *config = (wl_nan_ndp_config_t *)data;
+ int i = 0;
+ printf("ndp_id: %d\tpub_id: %d\ttid: %d\tpkt_size: %d\t"
+ "mean_rate: %d\tsvc_interval: %d\n",
+ config->ndp_id, config->pub_id,
+ config->qos.tid, config->qos.pkt_size,
+ config->qos.mean_rate,
+ config->qos.svc_interval);
+
+
+ bcm_ether_ntoa(&config->pub_addr, buf);
+ printf("pub_addr: %s\n", buf);
+
+ bcm_ether_ntoa(&config->data_addr, buf);
+ printf("data_addr: %s\n", buf);
+
+ for (; i < WL_NAN_DATA_SVC_SPEC_INFO_LEN; i++) {
+ putchar(config->svc_spec_info[i]);
+ }
+ printf("\n");
+
+ }
+ break;
+ case WL_NAN_CMD_DATA_AUTOCONN:
+ {
+ printf("autoconn: %d\n", *data);
+ if (*data & WL_NAN_AUTO_DPRESP) {
+ printf("auto_dpresp enabled \n");
+ } else {
+ printf("auto_dpresp disabled \n");
+ }
+ if (*data & WL_NAN_AUTO_DPCONF) {
+ printf("auto_dpconf enabled \n");
+ } else {
+ printf("auto_dpconf disabled \n");
+ }
+ }
+ break;
+ case WL_NAN_CMD_DATA_SCHEDUPD:
+ break;
+ case WL_NAN_CMD_DATA_CAP:
+ break;
+ case WL_NAN_CMD_DATA_STATUS:
+ {
+ wl_nan_ndp_status_t *status = (wl_nan_ndp_status_t *)data;
+
+ prhex("PEER_NMI", (uint8 *)&status->peer_nmi, ETHER_ADDR_LEN);
+ prhex("PEER_NDI", (uint8 *)&status->peer_ndi, ETHER_ADDR_LEN);
+ printf("lndp_id = %d\n", status->session.lndp_id);
+ printf("state = %d\n", status->session.state);
+ printf("pub_id = %d\n", status->session.pub_id);
+ }
+ break;
+ case WL_NAN_CMD_DATA_STATS:
+ break;
+
+ default:
+ res = BCME_ERROR;
+ break;
+ }
+
+ if (b_resp->count > 0) {
+ b_resp->count--;
+ } else {
+ printf("All subcmd resp tlvs are parsed\n");
+ }
+
+ return res;
+}
+
+/*
+* listens on bcm events on given interface and prints NAN_EVENT data
+* event data is a var size array of bcm_xtlv_t items
+*/
+#if defined(linux)
+static int
+wl_nan_print_event_data_tlvs(void *ctx, const uint8 *data, uint16 type, uint16 len)
+{
+ int err = BCME_OK;
+
+ UNUSED_PARAMETER(ctx);
+
+ switch (type) {
+ case WL_NAN_XTLV_SVC_INFO:
+ {
+ prhex("SVC info", (uint8 *)data, len);
+ break;
+ }
+ case WL_NAN_XTLV_SDF_RX:
+ {
+ prhex("SDF RX", (uint8 *)data, len);
+ break;
+ }
+ default:
+ {
+ printf("Unknown xtlv type received: %x\n", type);
+ err = BCME_ERROR;
+ break;
+ }
+ }
+
+ return err;
+}
+
+static int
+wl_nan_print_event_data(uint32 nan_evtnum, uint8 *event_data, uint16 data_len)
+{
+ uint16 tlvs_offset, opt_tlvs_len = 0;
+ uint8 *tlv_buf;
+ int err = BCME_OK;
+
+ switch (nan_evtnum) {
+ case WL_NAN_EVENT_START:
+ /* intentional fall through */
+ case WL_NAN_EVENT_JOIN:
+ /* intentional fall through */
+ case WL_NAN_EVENT_ROLE:
+ /* intentional fall through */
+ case WL_NAN_EVENT_SCAN_COMPLETE:
+ /* intentional fall through */
+ case WL_NAN_EVENT_MERGE:
+ /* intentional fall through */
+ case WL_NAN_EVENT_STOP:
+ {
+ wl_nan_cfg_status_t *nstatus = (wl_nan_cfg_status_t *)event_data;
+
+ wl_nan_print_status(nstatus);
+ break;
+ }
+ case WL_NAN_EVENT_DISCOVERY_RESULT:
+ {
+ wl_nan_ev_disc_result_t *ev_disc_result;
+ ev_disc_result = (wl_nan_ev_disc_result_t *)event_data;
+
+ printf("Publish ID: %d\n", ev_disc_result->pub_id);
+ printf("Subscribe ID: %d\n", ev_disc_result->sub_id);
+
+ bcm_ether_ntoa(&ev_disc_result->pub_mac, buf);
+ printf("Publish MAC addr: %s\n", buf);
+
+ tlvs_offset = OFFSETOF(wl_nan_ev_disc_result_t, opt_tlvs[0]);
+ opt_tlvs_len = data_len - tlvs_offset;
+ break;
+ }
+ case WL_NAN_EVENT_REPLIED:
+ {
+ bcm_xtlv_t *xtlv = (bcm_xtlv_t *)event_data;
+ wl_nan_ev_replied_t *evr =
+ (wl_nan_ev_replied_t *)xtlv->data;
+ printf("Publish ID: %d\n", evr->pub_id);
+ bcm_ether_ntoa(&evr->sub_mac, buf);
+ printf("Subscriber MAC addr: %s\n", buf);
+ printf("Subscriber RSSI : %d\n", evr->sub_rssi);
+ printf("Subscriber ID : %d\n", evr->sub_id);
+ break;
+ }
+ case WL_NAN_EVENT_TERMINATED:
+ {
+ bcm_xtlv_t *xtlv = (bcm_xtlv_t *)event_data;
+ wl_nan_ev_terminated_t *pev = (wl_nan_ev_terminated_t *)xtlv->data;
+ printf("Instance ID: %d\n", pev->instance_id);
+ printf("Reason: %d\n", pev->reason);
+ printf("Service Type: %d\n", pev->svctype);
+ break;
+ }
+ case WL_NAN_EVENT_RECEIVE:
+ {
+ bcm_xtlv_t *xtlv = (bcm_xtlv_t *)event_data;
+ wl_nan_ev_receive_t *ev = (wl_nan_ev_receive_t *)xtlv->data;
+ printf("Local ID: %d\n", ev->local_id);
+ printf("Remote ID: %d\n", ev->remote_id);
+ bcm_ether_ntoa(&ev->remote_addr, buf);
+ printf("Peer MAC addr: %s\n", buf);
+ printf("Peer RSSI : %d\n", ev->fup_rssi);
+ break;
+ }
+ case WL_NAN_EVENT_STATUS_CHG:
+ break;
+ case WL_NAN_EVENT_P2P:
+ {
+ wl_nan_ev_p2p_avail_t *ev_p2p_avail;
+ chanspec_t chanspec;
+ ev_p2p_avail = (wl_nan_ev_p2p_avail_t *)event_data;
+
+ printf("Device Role: %d\n", ev_p2p_avail->dev_role);
+
+ bcm_ether_ntoa(&ev_p2p_avail->sender, buf);
+ printf("Sender MAC addr: %s\n", buf);
+
+ bcm_ether_ntoa(&ev_p2p_avail->p2p_dev_addr, buf);
+ printf("P2P dev addr: %s\n", buf);
+
+ printf("Repeat: %d\n", ev_p2p_avail->repeat);
+ printf("Resolution: %d\n", ev_p2p_avail->resolution);
+ chanspec = dtoh16(ev_p2p_avail->chanspec);
+ if (wf_chspec_valid(chanspec)) {
+ wf_chspec_ntoa(chanspec, buf);
+ printf("> Chanspec:%s 0x%x\n", buf, chanspec);
+ } else {
+ printf("> Chanspec: invalid 0x%x\n", chanspec);
+ }
+ printf("Avail bitmap: 0x%08x\n", dtoh32(ev_p2p_avail->avail_bmap));
+
+ break;
+ }
+ case WL_NAN_EVENT_PEER_DATAPATH_IND:
+ case WL_NAN_EVENT_PEER_DATAPATH_RESP:
+ case WL_NAN_EVENT_PEER_DATAPATH_CONF:
+ case WL_NAN_EVENT_DATAPATH_ESTB:
+ {
+ wl_nan_ev_datapath_cmn_t *event;
+
+ event = (wl_nan_ev_datapath_cmn_t *)event_data;
+ printf("Event type = %d\n", event->type);
+ printf("Status = %d\n", event->status);
+ printf("pub_id = %d\n", event->pub_id);
+ printf("security = %d\n", event->security);
+ if (event->type == NAN_DP_SESSION_UNICAST) {
+ printf("NDPID = %d\n", event->ndp_id);
+ prhex("INITIATOR_NDI", (uint8 *)&event->initiator_ndi,
+ ETHER_ADDR_LEN);
+ prhex("RESPONDOR_NDI", (uint8 *)&event->responder_ndi,
+ ETHER_ADDR_LEN);
+ } else {
+ printf("NDPID = %d\n", event->mc_id);
+ prhex("INITIATOR_NDI", (uint8 *)&event->initiator_ndi,
+ ETHER_ADDR_LEN);
+ }
+ tlvs_offset = OFFSETOF(wl_nan_ev_datapath_cmn_t, opt_tlvs);
+ opt_tlvs_len = data_len - tlvs_offset;
+
+ }
+ break;
+ case WL_NAN_EVENT_DATAPATH_END:
+ break;
+ case WL_NAN_EVENT_SDF_RX:
+ {
+ tlvs_offset = 0;
+ opt_tlvs_len = data_len;
+ break;
+ }
+ case WL_NAN_EVENT_BCN_RX:
+ {
+
+ bcm_xtlv_t *xtlv = (bcm_xtlv_t *)event_data;
+ int ctr = 0;
+ printf("Len : %d\n", xtlv->len);
+ printf("Beacon Payload \n");
+ for (; ctr < xtlv->len; ctr++) {
+ printf("%02X ", xtlv->data[ctr]);
+ if ((ctr + 1) % 8 == 0)
+ printf("\n");
+ }
+
+ }
+ break;
+ default:
+ {
+ printf("WARNING: unimplemented NAN APP EVENT code:%d\n", nan_evtnum);
+ err = BCME_ERROR;
+ }
+ break;
+ }
+
+ if (opt_tlvs_len) {
+ tlv_buf = event_data + tlvs_offset;
+
+ /* Extract event data tlvs and print their resp in cb fn */
+ err = bcm_unpack_xtlv_buf((void *)&nan_evtnum,
+ (const uint8 *)tlv_buf,
+ opt_tlvs_len, BCM_IOV_CMD_OPT_ALIGN32,
+ wl_nan_print_event_data_tlvs);
+ }
+
+ return err;
+}
+
+static int
+wl_nan_subcmd_event_check(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int fd, err, octets;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ char ifnames[IFNAMSIZ] = {"eth0"};
+ bcm_event_t *event;
+ uint32 nan_evtnum, evt_status;
+ char* data;
+ int event_type;
+ void *nandata;
+
+ uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* 128-bit mask */
+ UNUSED_PARAMETER(nandata);
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+ UNUSED_PARAMETER(argc);
+ if (argv[0] == NULL) {
+ printf("<ifname> param is missing\n");
+ return BCME_USAGE_ERROR;
+ }
+ strncpy(ifnames, *argv, (IFNAMSIZ - 1));
+ printf("ifname:%s\n", ifnames);
+ bzero(&ifr, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
+ if ((err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
+ printf("couldn't read event_msgs\n");
+ return (err);
+ }
+ event_inds_mask[WLC_E_NAN / 8] |= 1 << (WLC_E_NAN % 8);
+ if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
+ return (err);
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
+ if (fd < 0) {
+ printf("Cannot create socket %d\n", fd);
+ return -1;
+ }
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ printf("Cannot get iface:%s index \n", ifr.ifr_name);
+ goto exit1;
+ }
+ bzero(&sll, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ printf("Cannot bind %d\n", err);
+ goto exit1;
+ }
+ data = (char*)malloc(NAN_EVENT_BUFFER_SIZE);
+ if (data == NULL) {
+ printf("Cannot not allocate %d bytes for events receive buffer\n",
+ NAN_EVENT_BUFFER_SIZE);
+ goto exit1;
+ }
+ printf("wating for NAN events on iface:%s\n", ifr.ifr_name);
+ while (1) {
+ uint16 datalen;
+ fflush(stdout);
+ octets = recv(fd, data, NAN_EVENT_BUFFER_SIZE, 0);
+ if (octets <= 0) {
+ err = -1;
+ printf(".");
+ continue;
+ }
+ event = (bcm_event_t *)data;
+ event_type = ntoh32(event->event.event_type);
+ evt_status = ntoh32(event->event.status);
+ nan_evtnum = ntoh32(event->event.reason);
+ datalen = ntoh32(event->event.datalen);
+ if ((event_type != WLC_E_NAN)) {
+ continue;
+ }
+
+ err = BCME_OK;
+ /* set ptr to event data body */
+ nandata = &data[sizeof(bcm_event_t)];
+
+ /* printf("nan event_num:%d len :%d\n", nan_evtnum, datalen); */
+ switch (nan_evtnum) {
+ case WL_NAN_EVENT_START:
+ printf("WL_NAN_EVENT_START:\n");
+ break;
+ case WL_NAN_EVENT_JOIN:
+ printf("WL_NAN_EVENT_JOIN:\n");
+ break;
+ case WL_NAN_EVENT_ROLE:
+ printf("WL_NAN_EVENT_ROLE:\n");
+ break;
+ case WL_NAN_EVENT_SCAN_COMPLETE:
+ printf("WL_NAN_EVENT_SCAN_COMPLETE:\n");
+ break;
+ case WL_NAN_EVENT_DISCOVERY_RESULT:
+ printf("WL_NAN_EVENT_DISCOVERY_RESULT:\n");
+ break;
+ case WL_NAN_EVENT_REPLIED:
+ printf("WL_NAN_EVENT_REPLIED:\n");
+ break;
+ case WL_NAN_EVENT_TERMINATED:
+ printf("WL_NAN_EVENT_TERMINATED:\n");
+ break;
+ case WL_NAN_EVENT_RECEIVE:
+ printf("WL_NAN_EVENT_RECEIVE:\n");
+ break;
+ case WL_NAN_EVENT_STATUS_CHG:
+ printf("WL_NAN_EVENT_STATUS_CHG:\n");
+ break;
+ case WL_NAN_EVENT_MERGE:
+ printf("WL_NAN_EVENT_MERGE:\n");
+ break;
+ case WL_NAN_EVENT_STOP:
+ printf("WL_NAN_EVENT_STOP:\n");
+ break;
+ case WL_NAN_EVENT_P2P:
+ printf("WL_NAN_EVENT_P2P:\n");
+ break;
+ case WL_NAN_EVENT_PEER_DATAPATH_IND:
+ printf("WL_NAN_EVENT_PEER_DATAPATH_IND:\n");
+ break;
+ case WL_NAN_EVENT_PEER_DATAPATH_RESP:
+ printf("WL_NAN_EVENT_PEER_DATAPATH_RESP:\n");
+ break;
+ case WL_NAN_EVENT_PEER_DATAPATH_CONF:
+ printf("WL_NAN_EVENT_PEER_DATAPATH_CONF:\n");
+ break;
+ case WL_NAN_EVENT_DATAPATH_ESTB:
+ printf("WL_NAN_EVENT_DATAPATH_ESTB:\n");
+ break;
+ case WL_NAN_EVENT_DATAPATH_END:
+ printf("WL_NAN_EVENT_DATAPATH_END:\n");
+ break;
+ case WL_NAN_EVENT_SDF_RX:
+ printf("WL_NAN_EVENT_SDF_RX:\n");
+ break;
+ case WL_NAN_EVENT_BCN_RX:
+ printf("WL_NAN_EVENT_BCN_RX:\n");
+ break;
+ default:
+ printf("WARNING: unimplemented NAN APP EVENT code:%d\n", nan_evtnum);
+ err = BCME_ERROR;
+ break;
+ }
+ if (evt_status)
+ printf("Event status:-%u\n", evt_status);
+
+ if (err == BCME_OK) {
+ err = wl_nan_print_event_data(nan_evtnum, (uint8 *)nandata, datalen);
+ }
+ }
+ free(data);
+exit1:
+ close(fd);
+ if (!(err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
+ event_inds_mask[WLC_E_NAN / 8] &= (~(1 << (WLC_E_NAN % 8)));
+ err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN);
+ }
+ fflush(stdout);
+ return (err);
+}
+#endif /* linux */
+
+static int
+process_get_resp_buf(void *iov_resp)
+{
+ int res = BCME_OK;
+ uint16 version;
+ uint16 tlvs_len;
+
+ /* Check for version */
+ version = dtoh16(*(uint16 *)iov_resp);
+
+ if (version & BCM_IOV_BATCH_MASK) {
+ bcm_iov_batch_buf_t *p_resp = (bcm_iov_batch_buf_t *)iov_resp;
+
+ /* number of tlvs count */
+ tlvs_len = WLC_IOCTL_MAXLEN - OFFSETOF(bcm_iov_batch_buf_t, cmds[0]);
+
+ /* Extract the tlvs and print their resp in cb fn */
+ if ((res = bcm_unpack_xtlv_buf((void *)p_resp,
+ (const uint8 *)&p_resp->cmds[0],
+ tlvs_len, BCM_IOV_CMD_OPT_ALIGN32,
+ wlu_nan_set_vars_cbfn)) != BCME_OK) {
+ if (p_resp->count == 0) {
+ res = BCME_OK;
+ }
+ }
+ } else {
+ res = BCME_UNSUPPORTED;
+ }
+
+ return res;
+}
+
+/*
+ * --- common for all nan get commands ----
+ */
+int
+wl_nan_do_get_ioctl(void *wl, void *nanioc, uint16 iocsz)
+{
+ /* for gets we only need to pass ioc header */
+ uint8 *iocresp = NULL;
+ int res;
+
+ if ((iocresp = malloc(WLC_IOCTL_MAXLEN)) == NULL) {
+ printf("Failed to malloc %d bytes \n",
+ WLC_IOCTL_MAXLEN);
+ return BCME_NOMEM;
+ }
+
+ /* send getbuf nan iovar */
+ res = wlu_iovar_getbuf(wl, "nan", nanioc, iocsz, iocresp, WLC_IOCTL_MAXLEN);
+
+ /* check the response buff */
+ if ((res == BCME_OK) && (iocresp != NULL)) {
+ res = process_get_resp_buf(iocresp);
+ }
+
+ free(iocresp);
+ return res;
+}
+
+
+/* nan event_msgs: enable/disable nan events */
+static int
+wl_nan_subcmd_event_msgs(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ /* bit num = event enum -1 */
+ const char usage[] = "nan event_msgs [bit] [0/1]\n"
+ " bit 0 - WL_NAN_EVENT_START\n"
+ " bit 1 - WL_NAN_EVENT_JOIN\n"
+ " bit 2 - WL_NAN_EVENT_ROLE\n"
+ " bit 3 - WL_NAN_EVENT_SCAN_COMPLETE\n"
+ " bit 4 - WL_NAN_EVENT_DISCOVERY_RESULT\n"
+ " bit 5 - WL_NAN_EVENT_REPLIED\n"
+ " bit 6 - WL_NAN_EVENT_TERMINATED\n"
+ " bit 7 - WL_NAN_EVENT_RECEIVE\n"
+ " bit 8 - WL_NAN_EVENT_STATUS_CHG\n"
+ " bit 9 - WL_NAN_EVENT_MERGE\n"
+ " bit 10 - WL_NAN_EVENT_STOP\n"
+ " bit 11 - WL_NAN_EVENT_P2P\n"
+ " bit 16 - WL_NAN_EVENT_POST_DISC\n"
+ " bit 17 - WL_NAN_EVENT_DATA_IF_ADD\n"
+ " bit 18 - WL_NAN_EVENT_DATA_PEER_ADD\n"
+ " bit 19 - WL_NAN_EVENT_DATA_IND\n"
+ " bit 20 - WL_NAN_EVENT_DATA_CONF\n"
+ " bit 21 - WL_NAN_EVENT_DATA_SDF_RX\n"
+ " bit 22 - WL_NAN_EVENT_DATA_END\n"
+ " bit 23 - WL_NAN_EVENT_BCN_RX\n"
+ " bit 24 ..30 - unused\n"
+ " bit 31 - set/clr all eventmask bits\n";
+
+ if (*argv == NULL) {
+ /* get: handled by cbfn */
+ *is_set = FALSE;
+ goto exit;
+ } else {
+ /* args are present, do set ioctl */
+ uint8 bit = 32, val = 3;
+ uint8 *pxtlv = iov_data;
+ uint32 eventmask;
+
+ bit = atoi(argv[0]);
+
+ if ((argv[0][0] == '-')) {
+ fprintf(stderr,
+ "%s\n", usage);
+ res = BCME_BADARG;
+ goto exit;
+ }
+
+ if (bit > 31) {
+ fprintf(stderr, "1st param should be [0..31]\n");
+ fprintf(stderr, "%s\n", usage);
+ res = BCME_BADARG;
+ goto exit;
+ }
+
+ if (argv[1])
+ val = atoi(argv[1]);
+
+ if (val > 1) {
+ fprintf(stderr, "2nd param should be [0|1]\n");
+ fprintf(stderr, "%s\n", usage);
+ res = BCME_BADARG;
+ goto exit;
+ }
+
+ if (bit == 31) {
+ /* set all bits */
+ eventmask = 0x7fffffff;
+ } else {
+ /* set/reset one bit */
+ eventmask = 1 << bit;
+ }
+ if (val == 0) {
+ /* and mask to rst bit */
+ eventmask = ~eventmask;
+ }
+
+ eventmask = htod32(eventmask);
+
+ memcpy(pxtlv, &eventmask, sizeof(eventmask));
+ *avail_len -= sizeof(eventmask);
+
+ }
+
+exit:
+ return res;
+}
+
+/*
+* ******** various debug features, for internal use only ********
+*/
+
+/*
+* ******** get NAN status info ********
+*/
+static int
+wl_nan_subcmd_scan_params(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ int opt_err;
+ miniopt_t to;
+ const char* fn_name = "scan_params";
+ int nchan = 0;
+
+ /* nan scan params inited to dflt */
+ wl_nan_scan_params_t scan_params = {
+ .scan_time = 0,
+ .home_time = 0,
+ .ms_intvl = 0,
+ .ms_dur = 0,
+ .chspec_num = 0,
+ .chspec_list = {0x1006, 0xd02c, 0xd095} /* ch 6/20, ch 44/20 , ch 149/20 */
+ };
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(avail_len);
+ UNUSED_PARAMETER(argc);
+
+ if (*argv == NULL) {
+ /* get: handled by cbfn */
+ *is_set = FALSE;
+ goto exit;
+ } else {
+ /* args are present, do set ioctl */
+ int ok_params_cnt = 0;
+ int i;
+ uint8 *pxtlv = iov_data;
+
+ miniopt_init(&to, fn_name, NULL, FALSE);
+
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+
+ if (opt_err == 1) {
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 's') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: option value %s\" is not an integer\n",
+ fn_name, to.valstr);
+ res = BCME_BADARG;
+ goto exit;
+ }
+ scan_params.scan_time = to.uval;
+ ok_params_cnt++;
+ }
+
+ if (to.opt == 'h') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: option value %s\" is not an integer\n",
+ fn_name, to.valstr);
+ res = BCME_BADARG;
+ goto exit;
+ }
+
+ scan_params.home_time = to.uval;
+ ok_params_cnt++;
+ }
+
+ if (to.opt == 'i') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: option value %s\" is not an integer\n",
+ fn_name, to.valstr);
+ res = BCME_BADARG;
+ goto exit;
+ }
+ scan_params.ms_intvl = to.uval;
+ ok_params_cnt++;
+ }
+
+ if (to.opt == 'd') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: option value %s\" is not an integer\n",
+ fn_name, to.valstr);
+ res = BCME_BADARG;
+ goto exit;
+ }
+ scan_params.ms_dur = to.uval;
+ ok_params_cnt++;
+ }
+
+ if (to.opt == 'c') {
+ nchan = wl_parse_chanspec_list(to.valstr,
+ scan_params.chspec_list, 8);
+
+ if ((nchan == -1) | (nchan >= 8)) {
+ fprintf(stderr, "error parsing channel list arg\n");
+ res = BCME_BADARG;
+ goto exit;
+ }
+
+ /* convert to dongle endianness */
+ for (i = 0; i < nchan; i++) {
+ scan_params.chspec_list[i] =
+ htodchanspec(scan_params.chspec_list[i]);
+ }
+ scan_params.chspec_num = nchan;
+ ok_params_cnt++;
+ } /* if chan list */
+
+
+ } /* while options proc loop */
+
+ if (ok_params_cnt == 0) {
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ /* convert to dongle indianness */
+ scan_params.scan_time = htod16(scan_params.scan_time);
+ scan_params.home_time = htod16(scan_params.home_time);
+ scan_params.ms_intvl = htod16(scan_params.ms_intvl);
+ scan_params.ms_dur = htod16(scan_params.ms_dur);
+
+ memcpy(&pxtlv, (uint8 *)&scan_params, sizeof(scan_params));
+
+ }
+
+exit:
+ return res;
+}
+
+/*
+* ******** get nan discovery results ********
+*/
+static int
+wl_nan_subcmd_disc_results(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ if (*argv == NULL || argc == 0) {
+ *is_set = FALSE;
+ } else if (!*argv) {
+ res = BCME_USAGE_ERROR;
+ }
+
+ return res;
+}
+/*
+* ******** nan scan for clusters ********
+*/
+static int
+wl_nan_subcmd_scan(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint8 *pxtlv = iov_data;
+ struct ether_addr cid;
+
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(argc);
+
+ /* nan scan is a SET only ioctl no params passes NULL ether addr */
+ if (*argv) {
+ if (!wl_ether_atoe(*argv, &cid)) {
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ } else {
+ /* bcast mac: scan for all nan clusters */
+ bcopy(ðer_null, &cid, ETHER_ADDR_LEN);
+ }
+
+ memcpy(pxtlv, (uint8 *)&cid, ETHER_ADDR_LEN);
+ *avail_len -= ETHER_ADDR_LEN;
+
+exit:
+ return res;
+}
+
+static int
+wl_nan_subcmd_dbg_scan_results(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_USAGE_ERROR;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_dbg_rssi(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_USAGE_ERROR;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+ UNUSED_PARAMETER(argc);
+
+ return res;
+}
+
+static void
+wl_nan_help_usage()
+{
+ printf("%s\n", NAN_PARAMS_USAGE);
+}
+
+static void
+wl_nan_help(uint16 type)
+{
+ int i;
+ const wl_nan_cmd_help_t *p_help_info = &nan_cmd_help_list[0];
+
+ if (type == NAN_HELP_ALL) {
+ wl_nan_help_usage();
+ return;
+ }
+
+ for (i = 0; i < (int) ARRAYSIZE(nan_cmd_help_list); i++) {
+ if (p_help_info->type == type) {
+ if (p_help_info->help_handler) {
+ (p_help_info->help_handler)();
+ break;
+ }
+ }
+ p_help_info++;
+ }
+
+ return;
+}
+
+/* ******** enable/disable feature ************** */
+static int
+wl_nan_subcmd_cfg_enable(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+
+ int res = BCME_OK;
+ uint8 enable = 0;
+ uint16 len;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(enable);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ enable = (uint8)atoi(*argv);
+ memcpy(iov_data, &enable, sizeof(enable));
+ }
+
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_state(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_role_t role;
+ wl_nan_role_config_t *rcfg;
+ struct ether_addr master = ether_null;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(*rcfg);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ res = BCME_BUFTOOSHORT;
+ goto exit;
+ }
+ role = atoi(*argv++);
+ if (role > WL_NAN_ROLE_ANCHOR_MASTER) {
+ printf("%s : Invalid role\n", __FUNCTION__);
+ res = BCME_BADOPTION;
+ goto exit;
+ }
+
+ if (!*argv) {
+ if (role != WL_NAN_ROLE_AUTO && role != WL_NAN_ROLE_ANCHOR_MASTER) {
+ printf("%s : Missing target master address.\n", __FUNCTION__);
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ } else {
+ if (!wl_ether_atoe(*argv, &master)) {
+ printf("%s: Invalid ether addr provided\n", __FUNCTION__);
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+
+ rcfg = (wl_nan_role_config_t *)iov_data;
+ rcfg->role = role;
+ memcpy(&rcfg->target_master, &master, ETHER_ADDR_LEN);
+
+ }
+ *avail_len -= len;
+
+exit:
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_hop_count(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_hop_count_t hop_cnt;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(is_set);
+
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(hop_cnt);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+ hop_cnt = (uint8)atoi(*argv);
+ memcpy(iov_data, (uint8 *)&hop_cnt, sizeof(hop_cnt));
+ }
+
+ *avail_len -= len;
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_hop_limit(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ wl_nan_hop_count_t hop_limit;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(hop_limit);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ hop_limit = (uint8)atoi(*argv);
+ memcpy(iov_data, &hop_limit, sizeof(hop_limit));
+ }
+
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_warmup_time(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_warmup_time_ticks_t wup_ticks;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(is_set);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(wup_ticks);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+ wup_ticks = (uint32)atoi(*argv);
+ memcpy(iov_data, (uint8 *)&wup_ticks, sizeof(wup_ticks));
+ }
+
+ *avail_len -= len;
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_rssi_threshold(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ wl_nan_rssi_threshold_t *rssi_threshold;
+ wl_nan_band_t nan_band;
+ uint16 len;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* For GET, band is the input argument and for SET, band and rssi_info are input params */
+ if ((*argv == NULL) || argc == 0) {
+ printf("rssi_threshold expects at least one argument i.e band\n");
+ return BCME_USAGE_ERROR;
+ } else {
+ nan_band = set_nan_band(argv[0]);
+ if ((nan_band != NAN_BAND_A) && (nan_band != NAN_BAND_B)) {
+ return BCME_USAGE_ERROR;
+ }
+ /* advance to the next param */
+ argv++;
+ argc -= 1;
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = sizeof(nan_band);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+ *iov_data = nan_band;
+ } else {
+ /* band arument is already passed above, so -1 from ARGC */
+ if (ARGCNT(argv) < (WL_NAN_CMD_CFG_RSSI_THRESHOLD_ARGC - 1)) {
+ return BCME_USAGE_ERROR;
+ }
+
+ *is_set = TRUE;
+ len = sizeof(*rssi_threshold);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ rssi_threshold = (wl_nan_rssi_threshold_t *)iov_data;
+
+ rssi_threshold->band = nan_band;
+
+ rssi_threshold->rssi_close = (int8)strtol(*argv, NULL, 0);
+
+ /* advance to the next param */
+ argv++;
+
+ rssi_threshold->rssi_mid = (int8)strtol(*argv, NULL, 0);
+ }
+ }
+
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_count(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ } else {
+ printf("config_count doesn't expect any parameters\n");
+ return BCME_ERROR;
+ }
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_clearcount(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ /* Its Set only */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = TRUE;
+ } else {
+ printf("clearcount cmd doesn't accept any parameters\n");
+ res = BCME_USAGE_ERROR;
+ }
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_channel(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ chanspec_t chspec;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ *is_set = TRUE;
+ len = sizeof(chspec);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ if (*argv) {
+ chspec = wf_chspec_aton(*argv);
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ if (chspec != 0) {
+ memcpy(iov_data, (uint8 *)&chspec, sizeof(chspec));
+ }
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_band(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ wl_nan_band_t nan_band;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ *is_set = TRUE;
+ len = sizeof(nan_band);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ if (*argv) {
+ nan_band = set_nan_band(*argv);
+ if (nan_band == NAN_BAND_INVALID) {
+ return BCME_USAGE_ERROR;
+ }
+
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ memcpy(iov_data, (uint8*)&nan_band, sizeof(nan_band));
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_cid(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ wl_nan_cluster_id_t cid;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(cid);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ if (!wl_ether_atoe(*argv, &cid)) {
+ printf("Malformed MAC address parameter\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ memcpy(iov_data, (uint8*)&cid, sizeof(cid));
+ }
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_if_addr(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ struct ether_addr if_addr;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if ((*argv == NULL) || (!strcmp(*argv, WL_IOV_BATCH_DELIMITER))) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(if_addr);
+ if (len > *avail_len) {
+ printf("%s: Buf short, requested:%d, available:%d\n",
+ __FUNCTION__, len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ if (!wl_ether_atoe(*argv, &if_addr)) {
+ printf("Malformed MAC address parameter\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ memcpy(iov_data, (uint8*)&if_addr, sizeof(if_addr));
+ }
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_bcn_interval(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_disc_bcn_interval_t bcn_intvl;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if ((*argv == NULL) || (!strcmp(*argv, WL_IOV_BATCH_DELIMITER))) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(bcn_intvl);
+ bcn_intvl = htod16(atoi(*argv));
+ if (len > *avail_len) {
+ printf("%s: Buf short, requested:%d, available:%d\n",
+ __FUNCTION__, len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ memcpy(iov_data, (uint8*)&bcn_intvl, sizeof(bcn_intvl));
+ }
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_sdf_txtime(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_svc_disc_txtime_t sdf_txtime;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if ((*argv == NULL) || (!strcmp(*argv, WL_IOV_BATCH_DELIMITER))) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(sdf_txtime);
+ sdf_txtime = htod16(atoi(*argv));
+ if (len > *avail_len) {
+ printf("%s: Buf short, requested:%d, available:%d\n",
+ __FUNCTION__, len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ memcpy(iov_data, (uint8*)&sdf_txtime, sizeof(sdf_txtime));
+ }
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_stop_bcn_tx(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_stop_bcn_tx_t stop_bcn_tx;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if ((*argv == NULL) || (!strcmp(*argv, WL_IOV_BATCH_DELIMITER))) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(stop_bcn_tx);
+ stop_bcn_tx = htod16(atoi(*argv));
+ if (len > *avail_len) {
+ printf("%s: Buf short, requested:%d, available:%d\n",
+ __FUNCTION__, len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ memcpy(iov_data, (uint8*)&stop_bcn_tx, sizeof(stop_bcn_tx));
+ }
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_sid_beacon(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_sid_beacon_control_t *sid_beacon;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if ((*argv == NULL) || (!strcmp(*argv, WL_IOV_BATCH_DELIMITER))) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ if (ARGCNT(argv) < WL_NAN_CMD_CFG_SID_BCN_ARGC) {
+ printf(" Must mention sid_enable and sid_count\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ *is_set = TRUE;
+ len = sizeof(*sid_beacon);
+
+ sid_beacon = (wl_nan_sid_beacon_control_t *)iov_data;
+ sid_beacon->sid_enable = atoi(*argv);
+ argv++;
+ sid_beacon->sid_count = atoi(*argv);
+
+ *avail_len -= len;
+ }
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_dw_len(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_dw_len_t dw_len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if ((*argv == NULL) || (!strcmp(*argv, WL_IOV_BATCH_DELIMITER))) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(dw_len);
+ dw_len = htod16((uint16)atoi(*argv));
+ if (len > *avail_len) {
+ printf("%s: Buf short, requested:%d, available:%d\n",
+ __FUNCTION__, len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ memcpy(iov_data, (uint8*)&dw_len, sizeof(dw_len));
+ }
+ *avail_len -= len;
+
+ return res;
+}
+
+#define AWAKE_DW_BANDOPTION_LEN 4
+enum {
+ NAN_AWAKE_DW_INTERVAL = 1,
+ NAN_AWAKE_DW_BAND = 2
+};
+
+typedef struct nan_awake_dw_config_param {
+ char *name; /* <param-name> string to identify the config item */
+ uint16 id;
+ uint16 len; /* len in bytes */
+ char *help_msg; /* Help message */
+} nan_awake_dw_config_param_t;
+
+static const nan_awake_dw_config_param_t nan_awake_dw_param[] = {
+ /* param-name param_id len help message */
+ { "band", NAN_AWAKE_DW_BAND, AWAKE_DW_BANDOPTION_LEN,
+ "Band value can be either 'a', or 'b' " },
+ { "interval", NAN_AWAKE_DW_INTERVAL, sizeof(uint8),
+ "DW interval assumes 1,2,4,8,16 values" },
+};
+
+const nan_awake_dw_config_param_t *
+nan_lookup_awake_dw_config_param(char *param_name)
+{
+ int i = 0;
+ const nan_awake_dw_config_param_t *param_p = &nan_awake_dw_param[0];
+
+ for (i = 0; i < (int)ARRAYSIZE(nan_awake_dw_param); i++) {
+ if (stricmp(param_p->name, param_name) == 0) {
+ return param_p;
+ }
+ param_p++;
+ }
+
+ return NULL;
+}
+static int
+wl_nan_subcmd_cfg_awake_dw(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_awake_dw_t *awake_dw;
+ const nan_awake_dw_config_param_t *param_p = NULL;
+ wl_nan_band_t nan_band;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ /* For GET, band is the input argument and for SET, band and interval are input params */
+ if ((*argv == NULL) || argc == 0) {
+ printf("awake_dw expects at least one argument i.e band\n");
+ return BCME_USAGE_ERROR;
+ } else {
+ len = sizeof(wl_nan_awake_dw_t);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ awake_dw = (wl_nan_awake_dw_t *)iov_data;
+ while (*argv != NULL) {
+ if ((param_p = nan_lookup_awake_dw_config_param(*argv)) == NULL) {
+ res = BCME_USAGE_ERROR;
+ break;
+ }
+ /*
+ * Skip param name
+ */
+ argv++;
+ switch (param_p->id) {
+ case NAN_AWAKE_DW_INTERVAL:
+ awake_dw->interval = (uint8)atoi(*argv);
+ *is_set = TRUE;
+ if (awake_dw->interval != 1 && awake_dw->interval != 2 &&
+ awake_dw->interval != 4 && awake_dw->interval != 8 &&
+ awake_dw->interval != 16) {
+ printf("%s\n", param_p->help_msg);
+ res = BCME_USAGE_ERROR;
+ }
+ break;
+ case NAN_AWAKE_DW_BAND:
+ nan_band = set_nan_band(argv[0]);
+
+ if ((nan_band != NAN_BAND_A) && (nan_band != NAN_BAND_B)) {
+ printf("%s\n", param_p->help_msg);
+ res = BCME_USAGE_ERROR;
+ }
+ *is_set = FALSE;
+ awake_dw->band = nan_band;
+
+ break;
+ default:
+ res = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ argv++;
+ }
+ }
+
+ *avail_len -= len;
+fail:
+ return res;
+}
+
+/*
+* ******** get NAN election commands ********
+*/
+static int
+wl_nan_subcmd_election_host_enable(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ wl_nan_host_enable_t enable;
+ uint16 len;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(enable);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ enable = (uint8)atoi(*argv);
+ memcpy(iov_data, (uint8 *)&enable, sizeof(enable));
+ /* advance to the next param */
+ }
+
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_election_metrics_config(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_election_metric_config_t *metrics;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ *is_set = TRUE;
+ if (*argv == NULL) {
+ printf(" Must mention random factor and master pref\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (ARGCNT(argv) < WL_NAN_CMD_CFG_ELECTION_METRICS_ARGC) {
+ return BCME_USAGE_ERROR;
+ }
+
+ len = sizeof(wl_nan_election_metric_config_t);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ metrics = (wl_nan_election_metric_config_t *)iov_data;
+ metrics->random_factor = (uint8)atoi(*argv);
+ argv++;
+ metrics->master_pref = (uint8)atoi(*argv);
+
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_election_metrics_state(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ } else {
+ printf("metrics state doesn't expect any parameters\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ return res;
+}
+
+/*
+* ******** get NAN status info ********
+*/
+static int
+wl_nan_subcmd_cfg_status(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ } else {
+ printf("config_status doesn't expect any parameters\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ return res;
+}
+
+/*
+* ******** get NAN status info ********
+*/
+static int
+wl_nan_subcmd_stop(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ wl_nan_cluster_id_t cid;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ *is_set = TRUE;
+ len = sizeof(cid);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ /* For stop, only parameter cluster ID is an optional param */
+ if ((*argv == NULL) || argc == 0) {
+ /* Send null ether address as cid */
+ memcpy(&cid, ðer_null, len);
+ } else {
+ if (!wl_ether_atoe(*argv, &cid)) {
+ printf("Malformed MAC address parameter\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ memcpy(iov_data, &cid, len);
+
+ *avail_len -= len;
+
+ return res;
+}
+
+
+/* nan join cluter or start a new one */
+static int
+wl_nan_subcmd_join(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ wl_nan_join_t *join_req;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ *is_set = TRUE;
+ len = sizeof(*join_req);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ join_req = (wl_nan_join_t *)iov_data;
+
+ memset(join_req, 0, len);
+
+ /* -start from wl join command is optional */
+ /* Join command can expect optional params cid and -start */
+ while (*argv && (argc > 0)) {
+ if (!stricmp(*argv, "-start")) {
+ join_req->start_cluster = TRUE;
+ } else if (!wl_ether_atoe(*argv, &join_req->cluster_id)) {
+ printf("Malformed MAC address parameter\n");
+ return BCME_USAGE_ERROR;
+ }
+ argv++;
+ argc--;
+ }
+
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_leave(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ wl_nan_cluster_id_t cid;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ *is_set = TRUE;
+ len = sizeof(cid);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ /* For stop, only parameter cluster ID is an optional param */
+ if ((*argv == NULL) || argc == 0) {
+ /* Send null ether address as cid */
+ memcpy(&cid, ðer_null, len);
+ } else {
+ if (!wl_ether_atoe(*argv, &cid)) {
+ printf("Malformed MAC address parameter\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ memcpy(iov_data, &cid, len);
+
+ *avail_len -= len;
+
+ return res;
+}
+enum {
+ NAN_SD_PARAM_LENGTH = 0x0000,
+ NAN_SD_PARAM_FLAGS = 0x0001,
+ NAN_SD_PARAM_SVC_HASH = 0x0002,
+ NAN_SD_PARAM_INST_ID = 0x0003,
+ NAN_SD_PARAM_RSSI = 0x0004,
+ NAN_SD_PARAM_PERIOD = 0x0005,
+ NAN_SD_PARAM_TTL = 0x0006,
+ NAN_SD_PARAM_OPTIONS = 0x0007,
+ NAN_SD_PARAM_LCL_SVC_ID = 0x0008,
+ NAN_SD_PARAM_REQ_SVC_ID = 0x0009,
+ NAN_SD_PARAM_PRIORITY = 0x000A,
+ NAN_SD_PARAM_MAC_INCLUDE = 0x000B,
+ NAN_SD_PARAM_TOKEN = 0x000C,
+ NAN_SD_PARAM_SVC_INFO_LEN = 0x000D,
+ NAN_SD_PARAM_SVC_INFO = 0x000E,
+ NAN_SD_PARAM_SVC_BLOOM = 0x000F,
+ NAN_SD_PARAM_SVC_MATCH_TX = 0x0010,
+ NAN_SD_PARAM_SVC_MATCH_RX = 0x0011,
+ NAN_SD_PARAM_SVC_SRF_RAW = 0x0012,
+ NAN_SD_PARAM_SVC_NAME = 0x0013,
+ NAN_SD_PARAM_SVC_MATCH_BOTH = 0x0014,
+ NAN_SD_PARAM_MAC_EXCLUDE = 0x0015,
+ NAN_SD_PARAM_SVC_BLOOM_IDX = 0x0016,
+ NAN_SD_PARAM_SVC_MATCH_RAW = 0x0017,
+ NAN_SD_PARAM_SVC_FOLLOWUP = 0x0018,
+ NAN_SD_PARAM_SVC_MATCH_RX_RAW = 0x0019,
+ NAN_SD_PARAM_DEST_INST_ID = 0x001A,
+ NAN_SD_PARAM_DEST_MAC = 0x001B,
+ NAN_SD_PARAM_SDE_CONTROL = 0x001C,
+ NAN_SD_PARAM_SDE_RANGE_LIMIT = 0x001D
+};
+
+typedef struct nan_sd_config_param_info {
+ char *name; /* <param-name> string to identify the config item */
+ uint16 id;
+ uint16 len; /* len in bytes */
+ char *help_msg; /* Help message */
+} nan_sd_config_param_info_t;
+/*
+ * Parameter name and size for service discovery IOVARs
+ */
+static const nan_sd_config_param_info_t nan_sd_config_param_info[] = {
+ /* param-name param_id len help message */
+ { "length", NAN_SD_PARAM_LENGTH, sizeof(uint16),
+ "Length of SD including options" },
+ { "flags", NAN_SD_PARAM_FLAGS, sizeof(uint16),
+ "Bitmap representing optional flags" },
+ { "svc-hash", NAN_SD_PARAM_SVC_HASH, WL_NAN_SVC_HASH_LEN,
+ "6 bytes service hash" },
+ { "id", NAN_SD_PARAM_INST_ID, sizeof(uint8),
+ "Instance of current service" },
+ { "rssi", NAN_SD_PARAM_RSSI, sizeof(int8),
+ "RSSI limit to Rx subscribe or pub SDF, 0 no effect" },
+ { "period", NAN_SD_PARAM_PERIOD, sizeof(uint8),
+ "period of unsolicited SDF xmission in DWs" },
+ { "ttl", NAN_SD_PARAM_TTL, sizeof(int32),
+ "TTL for this instance or - 1 till cancelled" },
+ { "options", NAN_SD_PARAM_OPTIONS, sizeof(uint8),
+ "Optional fileds in SDF as appropriate" },
+ { "lcl-svc-id", NAN_SD_PARAM_LCL_SVC_ID, sizeof(uint8),
+ "Sender Service ID" },
+ { "req-svc-id", NAN_SD_PARAM_REQ_SVC_ID, sizeof(uint8),
+ "Destination Service ID" },
+ { "priority", NAN_SD_PARAM_PRIORITY, sizeof(uint8),
+ "requested relative priority" },
+ { "mac-incl", NAN_SD_PARAM_MAC_INCLUDE, ETHER_ADDR_LEN,
+ "Adds MAC addr to SRF and sets include bit" },
+ { "token", NAN_SD_PARAM_TOKEN, sizeof(uint16),
+ "follow_up_token when a follow-up msg is queued successfully" },
+ { "svc-info-len", NAN_SD_PARAM_SVC_INFO_LEN, sizeof(uint8),
+ "size in bytes of the service info payload" },
+ { "svc-info", NAN_SD_PARAM_SVC_INFO, sizeof(uint8), "Service Info payload" },
+ { "bloom", NAN_SD_PARAM_SVC_BLOOM, NAN_BLOOM_LENGTH_DEFAULT,
+ "Encode the Service Response Filter using a bloom filter rather than a mac list" },
+ { "match-tx", NAN_SD_PARAM_SVC_MATCH_TX, WL_NAN_MAX_SVC_MATCH_FILTER_LEN,
+ "Match filter (hex bytes) to transmit" },
+ { "match-rx", NAN_SD_PARAM_SVC_MATCH_RX, WL_NAN_MAX_SVC_MATCH_FILTER_LEN,
+ "Match filter (hex bytes) for receive" },
+ { "match-both", NAN_SD_PARAM_SVC_MATCH_BOTH, WL_NAN_MAX_SVC_MATCH_FILTER_LEN,
+ "Match filter (hex bytes) to transmit" },
+ { "srfraw", NAN_SD_PARAM_SVC_SRF_RAW, WL_NAN_MAX_SVC_MATCH_FILTER_LEN,
+ "SRF control byte + SRF data" },
+ { "name", NAN_SD_PARAM_SVC_NAME, WL_NAN_MAX_SVC_NAME_LEN, "Service name" },
+ { "mac-excl", NAN_SD_PARAM_MAC_EXCLUDE, ETHER_ADDR_LEN,
+ "Adds MAC addr to SRF and clears include bit" },
+ { "bloom-idx", NAN_SD_PARAM_SVC_BLOOM_IDX, sizeof(uint8),
+ "Bloom hash index used for bloom filter creation" },
+ { "match-raw", NAN_SD_PARAM_SVC_MATCH_RAW, WL_NAN_MAX_SVC_MATCH_FILTER_LEN,
+ "Match filter (raw hex bytes) to transmit" },
+ { "followup", NAN_SD_PARAM_SVC_FOLLOWUP, 0, "Follow up" },
+ { "match-rx-raw", NAN_SD_PARAM_SVC_MATCH_RX_RAW, WL_NAN_MAX_SVC_MATCH_FILTER_LEN,
+ "Match Rx filter (raw hex bytes) to receive" },
+ { "dest-inst-id", NAN_SD_PARAM_DEST_INST_ID, sizeof(uint8),
+ "Destination Instance ID" },
+ { "dest-mac", NAN_SD_PARAM_DEST_MAC, ETHER_ADDR_LEN,
+ "Destination MAC address" },
+ { "sde-ctrl", NAN_SD_PARAM_SDE_CONTROL, sizeof(uint16),
+ "Service descriptor extension attribute control" },
+ { "sde-range", NAN_SD_PARAM_SDE_RANGE_LIMIT, sizeof(uint32),
+ "Service descriptor extension attribute range limit" },
+};
+
+const nan_sd_config_param_info_t *
+nan_lookup_sd_config_param(char *param_name)
+{
+ int i = 0;
+ const nan_sd_config_param_info_t *param_p = &nan_sd_config_param_info[0];
+
+ for (i = 0; i < (int)ARRAYSIZE(nan_sd_config_param_info); i++) {
+ if (stricmp(param_p->name, param_name) == 0) {
+ return param_p;
+ }
+ param_p++;
+ }
+
+ return NULL;
+}
+static int
+wl_nan_subcmd_svc(void *wl, const wl_nan_sub_cmd_t *cmd, int instance_id, int argc, char **argv,
+ uint8 *iov_data, uint16 *avail_len, uint32 default_flags)
+{
+ int ret = BCME_OK;
+ wl_nan_sd_params_t *params = (wl_nan_sd_params_t *)iov_data;
+ char *val_p, *endptr, *svc_info = NULL;
+ char *followup = NULL;
+ uint32 val = 0;
+ uint8 *pxtlv = (uint8 *)¶ms->optional[0];
+ uint16 buflen, buflen_at_start;
+ char *hash = NULL, *hash_raw = NULL;
+
+ /* Matching filter variables */
+ char *match_raw = NULL, *match_rx_raw = NULL;
+ uint8 *match = NULL, *matchtmp = NULL;
+ uint8 *match_rx = NULL, *match_rxtmp = NULL;
+ uint8 m_len;
+
+ /* SRF variables */
+ uint8 *srf = NULL, *srftmp = NULL, *mac_list = NULL;
+ bool srfraw_started = FALSE;
+ bool srf_started = FALSE;
+ /* Bloom length default, indicates use mac filter not bloom */
+ uint bloom_len = 0;
+ struct ether_addr srf_mac;
+ bcm_bloom_filter_t *bp = NULL;
+ /* Bloom filter index default, indicates it has not been set */
+ uint bloom_idx = 0xFFFFFFFF;
+ uint mac_num = 0;
+ char *srf_raw = NULL;
+ uint16 srf_include = 0;
+ const nan_sd_config_param_info_t *param_p;
+ bool zero_lv_pair = FALSE;
+
+ /* Service discovery extension variables */
+ int16 sde_control = -1;
+ int32 sde_range_limit = -1;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(argc);
+
+ /* Default options */
+ params->period = 1;
+ params->ttl = WL_NAN_TTL_UNTIL_CANCEL;
+ params->flags = default_flags;
+
+ /* Copy mandatory parameters from command line. */
+ if (!*argv) {
+ printf("Missing parameters.\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ params->instance_id = instance_id;
+
+ /*
+ * wl nan [publish|subscribe] <instance-id> name <service-name>
+ */
+ if (!*argv || (stricmp(*argv, "name") != 0)) {
+ printf("Missing service name parameter.\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv++;
+ hash = *argv;
+ argv++;
+ buflen = *avail_len;
+ buflen_at_start = buflen;
+ buflen -= OFFSETOF(wl_nan_sd_params_t, optional[0]);
+
+ /* Parse optional args. Validity is checked by discovery engine */
+ while (*argv != NULL) {
+ if ((param_p = nan_lookup_sd_config_param(*argv)) == NULL) {
+ break;
+ }
+ /*
+ * Skip param name
+ */
+ argv++;
+ switch (param_p->id) {
+ case NAN_SD_PARAM_SVC_BLOOM:
+ if (srfraw_started) {
+ printf("Cannot use -bloom-idx with -srfraw\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ srf_started = TRUE;
+
+ if (bloom_len) {
+ printf("-bloom can only be set once\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /* Value is optional */
+ if (!*argv) {
+ bloom_len = NAN_BLOOM_LENGTH_DEFAULT;
+ } else {
+ val = strtoul(*argv, &endptr, 0);
+
+ if (*endptr != '\0' || val < 1 || val > 254) {
+ printf("Invalid bloom length.\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ bloom_len = val;
+ break;
+ case NAN_SD_PARAM_SVC_MATCH_BOTH:
+ if (match_raw) {
+ printf("-match has already been used, cannot use -m \n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ /* Allocate and initalize matching filter buffer */
+ if (!match) {
+ if ((match = malloc(WLC_IOCTL_MEDLEN)) == NULL) {
+ printf("Failed to malloc %d bytes \n",
+ WLC_IOCTL_MEDLEN);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+ matchtmp = match;
+ }
+
+ /* If no value is given, then it is a zero length LV pair.
+ * So, checking for arg NULL OR
+ * calling nan_lookup_sd_config_param() which return non-NULL
+ * incase the argument is the next config param.
+ */
+ if (!*argv || nan_lookup_sd_config_param(*argv)) {
+ zero_lv_pair = TRUE;
+ *matchtmp++ = 0;
+ } else {
+ /* Add LV pair to temporary buffer */
+ val_p = *argv;
+ m_len = strlen(val_p);
+ *matchtmp++ = m_len;
+ strncpy((char*)matchtmp, val_p, m_len);
+ matchtmp += m_len;
+ }
+ break;
+ case NAN_SD_PARAM_SVC_MATCH_RX:
+ if (match_rx_raw) {
+ printf("match-rx-raw has already been used, cannot use match-rx\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ /* Allocate and initalize matching filter buffer */
+ if (!match_rx) {
+ if ((match_rx = malloc(WLC_IOCTL_MEDLEN)) == NULL) {
+ printf("Failed to malloc %d bytes \n",
+ WLC_IOCTL_MEDLEN);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+ match_rxtmp = match_rx;
+ }
+ /* If no value is given, then it is a zero length LV pair.
+ * So, checking for arg NULL OR
+ * calling nan_lookup_sd_config_param() which return non-NULL
+ * incase the argument is the next config param.
+ */
+ if (!*argv || nan_lookup_sd_config_param(*argv)) {
+ zero_lv_pair = TRUE;
+ *match_rxtmp++ = 0;
+ } else {
+ /* Add LV pair to temporary buffer */
+ val_p = *argv;
+ m_len = strlen(val_p);
+ *match_rxtmp++ = m_len;
+ strncpy((char*)match_rxtmp, val_p, m_len);
+ match_rxtmp += m_len;
+ }
+ break;
+ case NAN_SD_PARAM_SVC_MATCH_TX:
+ if (match_raw) {
+ printf("match-raw has already been used, cannot use match-tx \n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ /* Allocate and initalize matching filter buffer */
+ if (!match) {
+ if ((match = malloc(WLC_IOCTL_MEDLEN)) == NULL) {
+ printf("Failed to malloc %d bytes \n",
+ WLC_IOCTL_MEDLEN);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+ matchtmp = match;
+ }
+ /* If no value is given, then it is a zero length LV pair.
+ * So, checking for arg NULL OR
+ * calling nan_lookup_sd_config_param() which return non-NULL
+ * incase the argument is the next config param.
+ */
+ if (!*argv || nan_lookup_sd_config_param(*argv)) {
+ zero_lv_pair = TRUE;
+ *matchtmp++ = 0;
+ } else {
+ /* Add LV pair to temporary buffer */
+ val_p = *argv;
+ m_len = strlen(val_p);
+ *matchtmp++ = m_len;
+ strncpy((char*)matchtmp, val_p, m_len);
+ matchtmp += m_len;
+ }
+ break;
+ case NAN_SD_PARAM_MAC_INCLUDE:
+ case NAN_SD_PARAM_MAC_EXCLUDE:
+ if (srfraw_started) {
+ printf("Cannot use -i or -x with -srfraw\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ srf_started = TRUE;
+
+ if (!srf_include) {
+ /* mac include or exclude param ID */
+ srf_include = param_p->id;
+ } else if (srf_include != param_p->id) {
+ printf("Cannot use mac-incl or mac-excl together\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /* Allocate and initalize SRF buffer */
+ if (!srftmp) {
+ if ((mac_list = malloc(WLC_IOCTL_MEDLEN)) == NULL) {
+ printf("Failed to malloc %d bytes \n",
+ WLC_IOCTL_MEDLEN);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+ srftmp = mac_list;
+ }
+ val_p = *argv;
+ /* Add MAC address to temporary buffer */
+ if (!wl_ether_atoe(val_p, &srf_mac)) {
+ printf("Invalid ether addr\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ memcpy(srftmp, &srf_mac, ETHER_ADDR_LEN);
+ srftmp += ETHER_ADDR_LEN;
+ mac_num++;
+ break;
+ case NAN_SD_PARAM_SVC_BLOOM_IDX:
+ if (srfraw_started) {
+ printf("Cannot use -bloom-idx with -srfraw\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ srf_started = TRUE;
+
+ if (bloom_idx != 0xFFFFFFFF) {
+ printf("-bloom-idx can only be set once\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /* Set bloom index */
+ bloom_idx = atoi(*argv);
+ if (bloom_idx > 3) {
+ printf("Invalid -bloom-idx value\n");
+ }
+ break;
+ case NAN_SD_PARAM_SVC_SRF_RAW:
+ /* Send raw hex bytes of SRF control and SRF to firmware */
+ /* Temporarily store SRF */
+ if (srf_started) {
+ printf("srfraw is used without other srf options\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ srf_raw = *argv;
+ srfraw_started = TRUE;
+ break;
+ case NAN_SD_PARAM_SVC_INFO:
+ /* Temporarily store service info */
+ svc_info = *argv;
+ break;
+ case NAN_SD_PARAM_SVC_MATCH_RAW:
+ /* Send raw hex bytes of matching filter to firmware */
+ if (match) {
+ printf("-m has already been used, cannot use -match \n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /* Temporarily store matching filter */
+ match_raw = *argv;
+ break;
+ case NAN_SD_PARAM_SVC_MATCH_RX_RAW:
+ /* Send raw hex bytes of matching filter rx to firmware */
+ if (match_rx) {
+ printf("-m-rx has already been used, cannot use"
+ "-match_rx\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /* Temporarily store matching filter rx */
+ match_rx_raw = *argv;
+ break;
+ case NAN_SD_PARAM_SVC_FOLLOWUP:
+ /* Temporarily store service info for Follow-Up */
+ followup = *argv;
+ break;
+ case NAN_SD_PARAM_SVC_HASH:
+ /* Temporarily store raw service ID hash */
+ hash_raw = *argv;
+ break;
+ case NAN_SD_PARAM_FLAGS:
+ val_p = *argv;
+ val = strtoul(val_p, &endptr, 0);
+ if (*endptr != '\0') {
+ printf("Value is not uint or hex %s\n",
+ val_p);
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ params->flags = val;
+ break;
+ case NAN_SD_PARAM_PERIOD:
+ val_p = *argv;
+ val = strtoul(val_p, &endptr, 0);
+ if (*endptr != '\0') {
+ printf("Value is not uint or hex %s\n",
+ val_p);
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ params->period = val;
+ break;
+ case NAN_SD_PARAM_TTL:
+ val_p = *argv;
+ val = strtoul(val_p, &endptr, 0);
+ if (*endptr != '\0') {
+ printf("Value is not uint or hex %s\n",
+ val_p);
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ params->ttl = val;
+ break;
+ case NAN_SD_PARAM_RSSI:
+ params->proximity_rssi = atoi(*argv);
+ break;
+ case NAN_SD_PARAM_LENGTH:
+ params->length = atoi(*argv);
+ break;
+ case NAN_SD_PARAM_SDE_CONTROL:
+ if (cmd->id != WL_NAN_CMD_SD_PUBLISH) {
+ printf("SDE options are for publish only\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ sde_control = atoi(*argv);
+ break;
+ case NAN_SD_PARAM_SDE_RANGE_LIMIT:
+ if (cmd->id != WL_NAN_CMD_SD_PUBLISH) {
+ printf("SDE options are for publish only\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ sde_range_limit = atoi(*argv);
+ break;
+ default:
+ printf("Unrecognized parameter %s\n",
+ param_p->name);
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ /* TODO add matching filters, service specific info */
+ }
+
+ if (zero_lv_pair) {
+ zero_lv_pair = FALSE;
+ } else {
+ argv++;
+ }
+ }
+
+ /* If service ID raw value was not provided, calculate from name */
+ if (!hash_raw) {
+ /* As focus is on NaN1.0 CERT so for making test setup, we need to support old
+ * chip like 4359 which have svc_hash as non hash value so to accept that
+ * we made svc_hash as non hash value beacuse publish with hash and subscibe
+ * without hash and vice-versa is not acceptable.
+ */
+ strncpy((char*)params->svc_hash, hash, WL_NAN_SVC_HASH_LEN);
+ } else {
+ /* 6-byte Service ID (hash) value */
+ if (strlen(hash_raw)/2 != WL_NAN_SVC_HASH_LEN) {
+ printf("Need 6 byte service id\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ } else {
+ if (get_ie_data((uchar*)hash_raw, params->svc_hash,
+ WL_NAN_SVC_HASH_LEN)) {
+ ret = BCME_BADARG;
+ goto exit;
+ }
+ }
+ }
+
+ /* Optional parameters */
+ /* TODO other optional params */
+ if (svc_info) {
+ ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv,
+ &buflen, WL_NAN_XTLV_SVC_INFO, svc_info);
+ if (ret != BCME_OK)
+ goto exit;
+ }
+ if (match_raw) {
+ ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv,
+ &buflen, WL_NAN_XTLV_MATCH_TX, match_raw);
+ if (ret != BCME_OK)
+ goto exit;
+ }
+ if (match_rx_raw) {
+ /* Create XTLV only if matching filter rx is unique from tx */
+ if (!match_raw || (match_raw && strcmp(match_raw, match_rx_raw))) {
+ ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv,
+ &buflen, WL_NAN_XTLV_MATCH_RX, match_rx_raw);
+ if (ret != BCME_OK)
+ goto exit;
+ }
+ }
+ if (followup) {
+ ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv,
+ &buflen, WL_NAN_XTLV_FOLLOWUP, followup);
+ if (ret != BCME_OK)
+ goto exit;
+ }
+ if (match) {
+ m_len = matchtmp - match;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_NAN_XTLV_MATCH_TX,
+ m_len, match, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) goto exit;
+ }
+ if (match_rx) {
+ m_len = match_rxtmp - match_rx;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_NAN_XTLV_MATCH_RX,
+ m_len, match_rx, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) goto exit;
+ }
+ /* Check that there is a list of MAC addresses */
+ if (mac_list) {
+ uint8 srf_control = 0;
+ /* Construct SRF control field */
+ if (bloom_len) {
+ /* This is a bloom filter */
+ srf_control = 1;
+ if (bloom_idx == 0xFFFFFFFF) {
+ bloom_idx = params->instance_id % 4;
+ }
+ srf_control |= bloom_idx << 2;
+ }
+ if (srf_include == NAN_SD_PARAM_MAC_INCLUDE) {
+ srf_control |= 1 << 1;
+ }
+
+ if (bloom_len == 0) {
+ /* MAC list */
+ if (mac_num < NAN_SRF_MAX_MAC) {
+ if ((srf = malloc(mac_num * ETHER_ADDR_LEN + 1)) == NULL) {
+ printf("Failed to malloc %d bytes \n",
+ mac_num * ETHER_ADDR_LEN + 1);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ srftmp = srf;
+ memcpy(srftmp++, &srf_control, 1);
+ memcpy(srftmp, mac_list, mac_num * ETHER_ADDR_LEN);
+ } else {
+ printf("%s: Too many MAC addresses\n", __FUNCTION__);
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen,
+ WL_NAN_XTLV_SR_FILTER, (mac_num * ETHER_ADDR_LEN + 1),
+ (uint8 *)srf, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK)
+ goto exit;
+
+ } else {
+ /* Bloom filter */
+ if (wl_nan_bloom_create(&bp, &bloom_idx, bloom_len) != BCME_OK) {
+ printf("%s: Bloom create failed\n", __FUNCTION__);
+ ret = BCME_ERROR;
+ goto exit;
+ }
+ uint i;
+ srftmp = mac_list;
+ for (i = 0; i < mac_num; i++) {
+ if (bcm_bloom_add_member(bp, srftmp,
+ ETHER_ADDR_LEN) != BCME_OK) {
+ printf("%s: Cannot add to bloom filter\n",
+ __FUNCTION__);
+ }
+ srftmp += ETHER_ADDR_LEN;
+ }
+
+ /* Create bloom filter */
+ if ((srf = malloc(bloom_len + 1)) == NULL) {
+ printf("Failed to malloc %d bytes \n", bloom_len + 1);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+ srftmp = srf;
+ memcpy(srftmp++, &srf_control, 1);
+
+ uint bloom_size;
+ if ((bcm_bloom_get_filter_data(bp, bloom_len, srftmp,
+ &bloom_size)) != BCME_OK) {
+ printf("%s: Cannot get filter data\n", __FUNCTION__);
+ ret = BCME_ERROR;
+ goto exit;
+ }
+
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_NAN_XTLV_SR_FILTER,
+ (bloom_len + 1), (uint8 *)srf, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK)
+ goto exit;
+ }
+ }
+ if (srf_raw) {
+ ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv,
+ &buflen, WL_NAN_XTLV_SR_FILTER, srf_raw);
+ if (ret != BCME_OK)
+ goto exit;
+ }
+ if (sde_control >= 0) {
+ uint16 tmp = (uint16)sde_control;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_NAN_XTLV_SDE_CONTROL,
+ sizeof(uint16), (uint8*)&tmp, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK)
+ goto exit;
+ }
+ if (sde_range_limit >= 0) {
+ uint32 tmp = (uint32)sde_range_limit;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_NAN_XTLV_SDE_RANGE_LIMIT,
+ sizeof(uint32), (uint8*)&tmp, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK)
+ goto exit;
+ }
+ /* adjust avail_len to the end of last data record */
+ *avail_len -= (buflen_at_start - buflen);
+
+exit:
+ if (srf)
+ free(srf);
+ if (mac_list)
+ free(mac_list);
+ if (match)
+ free(match);
+ if (match_rx)
+ free(match_rx);
+ if (bp)
+ bcm_bloom_destroy(&bp, wl_nan_bloom_free);
+ return ret;
+}
+
+static int wl_nan_bloom_create(bcm_bloom_filter_t** bp, uint* idx, uint size)
+{
+ uint i;
+ int err;
+
+ err = bcm_bloom_create(wl_nan_bloom_alloc, wl_nan_bloom_free,
+ idx, WL_NAN_HASHES_PER_BLOOM, size, bp);
+ if (err != BCME_OK) {
+ goto exit;
+ }
+
+ /* Populate bloom filter with hash functions */
+ for (i = 0; i < WL_NAN_HASHES_PER_BLOOM; i++) {
+ err = bcm_bloom_add_hash(*bp, wl_nan_hash, &i);
+ if (err) {
+ goto exit;
+ }
+ }
+exit:
+ return err;
+}
+
+static void* wl_nan_bloom_alloc(void *ctx, uint size)
+{
+ BCM_REFERENCE(ctx);
+ uint8 *buf;
+
+ if ((buf = malloc(size)) == NULL) {
+ printf("Failed to malloc %d bytes \n", size);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+static void wl_nan_bloom_free(void *ctx, void *buf, uint size)
+{
+ BCM_REFERENCE(ctx);
+ BCM_REFERENCE(size);
+
+ free(buf);
+}
+
+static uint wl_nan_hash(void* ctx, uint index, const uint8 *input, uint input_len)
+{
+ uint8* filter_idx = (uint8*)ctx;
+ uint8 i = (*filter_idx * WL_NAN_HASHES_PER_BLOOM) + (uint8)index;
+ uint b = 0;
+
+ /* Steps 1 and 2 as explained in Section 6.2 */
+ /* Concatenate index to input and run CRC32 by calling hndcrc32 twice */
+ b = hndcrc32(&i, sizeof(uint8), CRC32_INIT_VALUE);
+ b = hndcrc32((uint8*) input, input_len, b);
+ /* Obtain the last 2 bytes of the CRC32 output */
+ b &= NAN_BLOOM_CRC32_MASK;
+
+ /* Step 3 is completed by bcmbloom functions */
+ return b;
+
+}
+
+/*
+ * Service Discovery commands
+ */
+#define NAN_SD_PARAMS_FLAGS_RANGE_CLOSE ((1 << 6))
+#define NAN_SD_PARAMS_FLAGS_RANGE_LIMIT (~(1 << 6))
+#define NAN_SD_PARAMS_FLAGS_UNSOLICITED ((1 << 12))
+#define NAN_SD_PARAMS_FLAGS_SOLICITED ((1 << 13))
+#define NAN_SD_PARAMS_FLAGS_UCAST (~(1 << 14))
+#define NAN_SD_PARAMS_FLAGS_BCAST ((1 << 14))
+#define NAN_SD_PARAMS_DEFAULT_PERIOD 1
+#define NAN_SD_PARAMS_DEFAULT_TTL 0xFFFFFFFF
+static int
+wl_nan_subcmd_publish(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len = 0;
+ int int_val = 0;
+
+ UNUSED_PARAMETER(is_set);
+
+ if (*argv == NULL) {
+ res = BCME_USAGE_ERROR;
+ goto done;
+ }
+
+ int_val = atoi(*argv);
+ /* Instance ID must be from 1 to 255 */
+ if ((res = wl_nan_is_instance_valid(int_val)) != WL_NAN_E_OK) {
+ printf("Invalid instance_id.\n");
+ goto done;
+ }
+ argv++;
+ argc--;
+ if (*argv == NULL || argc == 0) {
+ memcpy(iov_data, &int_val, sizeof(int_val));
+ *avail_len -= sizeof(int_val);
+ /* GET command support for publish */
+ *is_set = FALSE;
+ goto done;
+ } else {
+ len = sizeof(wl_nan_sd_params_t);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ res = BCME_BUFTOOSHORT;
+ goto done;
+ }
+
+ res = wl_nan_subcmd_svc(wl, cmd, int_val, argc, argv, iov_data,
+ avail_len, WL_NAN_PUB_BOTH);
+ }
+done:
+ return res;
+}
+
+static int
+wl_nan_subcmd_publish_list(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ if (*argv == NULL || argc == 0) {
+ *is_set = FALSE;
+ } else if (!*argv) {
+ printf("publish_list: requires no parameters\n");
+ res = BCME_USAGE_ERROR;
+ }
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_subscribe(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ int int_val = 0;
+ uint16 len = 0;
+
+ UNUSED_PARAMETER(is_set);
+
+ if (*argv == NULL) {
+ res = BCME_USAGE_ERROR;
+ goto done;
+ }
+
+ int_val = atoi(*argv);
+ /* Instance ID must be from 1 to 255 */
+ if ((res = wl_nan_is_instance_valid(int_val)) != WL_NAN_E_OK) {
+ printf("Invalid instance_id.\n");
+ *is_set = FALSE;
+ goto done;
+ }
+ argv++;
+ argc--;
+ if (*argv == NULL || argc == 0) { /* get */
+ memcpy(iov_data, &int_val, sizeof(int_val));
+ *avail_len -= sizeof(int_val);
+ *is_set = FALSE;
+ goto done;
+ } else {
+ len = sizeof(wl_nan_sd_params_t);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ res = BCME_BUFTOOSHORT;
+ goto done;
+ }
+
+ res = wl_nan_subcmd_svc(wl, cmd, int_val, argc, argv, iov_data,
+ avail_len, 0);
+ }
+
+done:
+ return res;
+}
+
+/*
+ * Returns active subscribe list instance
+ */
+static int
+wl_nan_subcmd_subscribe_list(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ if (*argv == NULL || argc == 0) {
+ *is_set = FALSE;
+ } else if (*argv) {
+ printf("subscribe: requires no parameters\n");
+ res = BCME_USAGE_ERROR;
+ }
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cancel(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int ret = BCME_OK;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(argc);
+ int int_val = 0;
+ wl_nan_instance_id_t instance_id;
+ uint16 buflen, buflen_at_start;
+
+ if (!argv[0] || argv[1]) {
+ printf("Incorrect number of parameters.\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+
+ }
+ int_val = atoi(argv[0]);
+ /* instance id '0' means cancel all publish/subscribe.
+ * So, allowing instance ID '0' also for cancel IOVARs.
+ */
+ if (int_val && ((ret = wl_nan_is_instance_valid(int_val)) != WL_NAN_E_OK)) {
+ printf("Invalid instance id.\n");
+ goto exit;
+ }
+
+ instance_id = int_val;
+
+ /* max data we can write, it will be decremented as we pack */
+ buflen = *avail_len;
+ buflen_at_start = buflen;
+
+ /* Mandatory parameters */
+ memcpy(iov_data, &instance_id, sizeof(instance_id));
+ buflen -= sizeof(instance_id);
+
+ /* adjust iocsz to the end of last data record */
+ *avail_len -= (buflen_at_start - buflen);
+
+
+exit:
+ return ret;
+}
+
+/*
+ * wl "nan" iovar iovar handler
+ */
+static int
+wl_nan_subcmd_cancel_publish(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ return wl_nan_subcmd_cancel(wl, cmd, argc, argv,
+ is_set, iov_data, avail_len);
+}
+
+static int
+wl_nan_subcmd_cancel_subscribe(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ return wl_nan_subcmd_cancel(wl, cmd, argc, argv,
+ is_set, iov_data, avail_len);
+}
+
+static int
+wl_nan_subcmd_sd_transmit(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int ret = BCME_OK;
+ int id, dest_id = 0;
+ struct ether_addr dest = ether_null;
+ /* Set highest value as the default value for priority */
+ uint8 *pxtlv = NULL;
+ uint16 buflen, buflen_at_start, sd_info_len_start;
+ wl_nan_sd_transmit_t *sd_xmit = NULL;
+ const nan_sd_config_param_info_t *param_p = NULL;
+ bool is_lcl_id = FALSE;
+ bool is_dest_id = FALSE;
+ bool is_dest_mac = FALSE;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(argc);
+
+ /* Copy mandatory parameters from command line. */
+ if (!*argv) {
+ printf("Missing instance id parameter.\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ id = atoi(*argv);
+ if ((ret = wl_nan_is_instance_valid(id)) != WL_NAN_E_OK) {
+ printf("Invalid instance_id.\n");
+ goto exit;
+ }
+ is_lcl_id = TRUE;
+ argv++;
+ sd_xmit = (wl_nan_sd_transmit_t *)iov_data;
+ sd_xmit->local_service_id = id;
+ pxtlv = (uint8 *)&sd_xmit->service_info[0];
+
+ /* max data we can write, it will be decremented as we pack */
+ buflen = *avail_len;
+ buflen_at_start = buflen;
+
+ buflen -= OFFSETOF(wl_nan_sd_transmit_t, service_info[0]);
+
+ while (*argv != NULL) {
+ if ((param_p = nan_lookup_sd_config_param(*argv)) == NULL) {
+ break;
+ }
+ /*
+ * Skip param name
+ */
+ argv++;
+ switch (param_p->id) {
+ case NAN_SD_PARAM_DEST_INST_ID:
+ if (!*argv) {
+ printf("Missing requestor id parameter.\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ dest_id = atoi(*argv);
+ if ((ret = wl_nan_is_instance_valid(dest_id)) != WL_NAN_E_OK) {
+ printf("Invalid requestor_id.\n");
+ goto exit;
+ }
+ sd_xmit->requestor_service_id = dest_id;
+ is_dest_id = TRUE;
+ break;
+ case NAN_SD_PARAM_DEST_MAC:
+ if (!*argv) {
+ printf("Missing destination MAC address.\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ if (!wl_ether_atoe(*argv, &dest)) {
+ printf("Invalid ether addr provided\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ memcpy(&sd_xmit->destination_addr, &dest, ETHER_ADDR_LEN);
+ is_dest_mac = TRUE;
+ break;
+ case NAN_SD_PARAM_PRIORITY:
+ sd_xmit->priority = atoi(*argv);
+ break;
+ case NAN_SD_PARAM_SVC_INFO:
+ sd_info_len_start = buflen;
+ ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv, &buflen,
+ WL_NAN_XTLV_SVC_INFO, *argv);
+ if (ret != BCME_OK) {
+ goto exit;
+ }
+ if ((sd_info_len_start - buflen) > 0xFF) {
+ printf("Invalid service info length %d\n",
+ (sd_info_len_start - buflen));
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ sd_xmit->service_info_len = (uint8)(sd_info_len_start - buflen);
+ break;
+ default:
+ printf("Unrecognized parameter %s\n", *argv);
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv++;
+ }
+
+ /* Check if all mandatory params are provided */
+ if (is_lcl_id && is_dest_id && is_dest_mac) {
+ /* adjust avail_len to the end of last data record */
+ *avail_len -= (buflen_at_start - buflen);
+ } else {
+ printf("Missing parameters\n");
+ ret = BCME_USAGE_ERROR;
+ }
+exit:
+ return ret;
+}
+
+static int
+wl_nan_subcmd_sd_vendor_info(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_sd_statistics(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_sd_connection(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_sd_show(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_sync_tsschedule(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ return res;
+}
+
+/*
+ * packs user data (in hex string) into tlv record
+ * advances tlv pointer to next xtlv slot
+ * buflen is used for tlv_buf space check
+ */
+static int
+bcm_pack_xtlv_entry_from_hex_string(uint8 **tlv_buf, uint16 *buflen, uint16 type, char *hex)
+{
+ bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf;
+ uint16 len = strlen(hex)/2;
+
+ /* copy data from tlv buffer to dst provided by user */
+
+ if (ALIGN_SIZE(BCM_XTLV_HDR_SIZE_EX(BCM_XTLV_OPTION_ALIGN32) + len,
+ sizeof(uint32)) > *buflen) {
+ printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n",
+ ((int)BCM_XTLV_HDR_SIZE_EX(BCM_XTLV_OPTION_ALIGN32) + len), *buflen);
+ return BCME_BADLEN;
+ }
+ ptlv->id = htol16(type);
+ ptlv->len = htol16(len);
+
+ /* copy callers data */
+ if (get_ie_data((uchar*)hex, ptlv->data, len)) {
+ return BCME_BADARG;
+ }
+
+ /* advance callers pointer to tlv buff */
+ *tlv_buf += BCM_XTLV_SIZE_EX(ptlv, BCM_XTLV_OPTION_ALIGN32);
+ /* decrement the len */
+ *buflen -= BCM_XTLV_SIZE_EX(ptlv, BCM_XTLV_OPTION_ALIGN32);
+ return BCME_OK;
+}
+
+static int
+wl_nan_subcmd_merge(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+
+ int res = BCME_OK;
+ wl_nan_merge_enable_t enable;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(enable);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ enable = (uint8)atoi(*argv);
+ memcpy(iov_data, &enable, sizeof(enable));
+ }
+
+ *avail_len -= len;
+
+ return res;
+}
+
+const wl_nan_sub_cmd_t *
+nan_get_subcmd_info(char **argv)
+{
+ char *cmdname = *argv;
+ const wl_nan_sub_cmd_t *p_subcmd_info = &nan_cmd_list[0];
+
+ while (p_subcmd_info->name != NULL) {
+ if (stricmp(p_subcmd_info->name, cmdname) == 0) {
+ return p_subcmd_info;
+ }
+ p_subcmd_info++;
+ }
+
+ return NULL;
+}
+
+static int
+nan_get_arg_count(char **argv)
+{
+ int count = 0;
+ while (*argv != NULL) {
+ if (strcmp(*argv, WL_IOV_BATCH_DELIMITER) == 0) {
+ break;
+ }
+ argv++;
+ count++;
+ }
+
+ return count;
+}
+
+static int
+wl_nan_control(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = BCME_USAGE_ERROR;
+ const wl_nan_sub_cmd_t *nancmd = NULL;
+ bcm_iov_batch_buf_t *b_buf = NULL;
+ uint8 *p_iov_buf;
+ uint16 iov_len, iov_len_start, subcmd_len, nancmd_data_len;
+ bool is_set = TRUE;
+ bool first_cmd_req = is_set;
+ int argc = 0;
+ /* Skip the command name */
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+ /* skip to cmd name after "nan" */
+ if (*argv) {
+ if (!strcmp(*argv, "-h") || !strcmp(*argv, "help")) {
+ /* help , or -h* */
+ argv++;
+ wl_nan_help(NAN_HELP_ALL);
+ goto fail;
+ }
+ }
+
+ /*
+ * malloc iov buf memory
+ */
+ b_buf = (bcm_iov_batch_buf_t *)calloc(1, WLC_IOCTL_MEDLEN);
+ if (b_buf == NULL) {
+ return BCME_NOMEM;
+ }
+ /*
+ * Fill the header
+ */
+ iov_len = iov_len_start = WLC_IOCTL_MEDLEN;
+ b_buf->version = htol16(0x8000);
+ b_buf->count = 0;
+ p_iov_buf = (uint8 *)(&b_buf->cmds[0]);
+ iov_len -= OFFSETOF(bcm_iov_batch_buf_t, cmds[0]);
+
+ while (*argv != NULL) {
+ bcm_iov_batch_subcmd_t *sub_cmd =
+ (bcm_iov_batch_subcmd_t *)p_iov_buf;
+ /*
+ * Lookup sub-command info
+ */
+ nancmd = nan_get_subcmd_info(argv);
+ if (!nancmd) {
+ goto fail;
+ }
+ /* skip over sub-cmd name */
+ argv++;
+
+ /*
+ * Get arg count for sub-command
+ */
+ argc = nan_get_arg_count(argv);
+
+ sub_cmd->u.options =
+ htol32(BCM_XTLV_OPTION_ALIGN32);
+ /*
+ * Skip over sub-command header
+ */
+ iov_len -= OFFSETOF(bcm_iov_batch_subcmd_t, data);
+
+ /*
+ * take a snapshot of curr avail len,
+ * to calculate iovar data len to be packed.
+ */
+ subcmd_len = iov_len;
+
+ /* invoke nan sub-command handler */
+ ret = nancmd->handler(wl, nancmd, argc, argv, &is_set,
+ (uint8 *)&sub_cmd->data[0], &subcmd_len);
+
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+ nancmd_data_len = (iov_len - subcmd_len);
+ /*
+ * In Batched commands, sub-commands TLV length
+ * includes size of options as well. Because,
+ * options are considered as part bcm xtlv data
+ * considered as part bcm xtlv data
+ */
+ nancmd_data_len += sizeof(sub_cmd->u.options);
+
+ /*
+ * Data buffer is set NULL, because sub-cmd
+ * tlv data is already filled by command hanlder
+ * and no need of memcpy.
+ */
+ ret = bcm_pack_xtlv_entry(&p_iov_buf, &iov_len,
+ nancmd->id, nancmd_data_len,
+ NULL, BCM_XTLV_OPTION_ALIGN32);
+
+ /*
+ * iov_len is already compensated before sending
+ * the buffer to cmd handler.
+ * xtlv hdr and options size are compensated again
+ * in bcm_pack_xtlv_entry().
+ */
+ iov_len += OFFSETOF(bcm_iov_batch_subcmd_t, data);
+ if (ret == BCME_OK) {
+ /* Note whether first command is set/get */
+ if (!b_buf->count) {
+ first_cmd_req = is_set;
+ } else if (first_cmd_req != is_set) {
+ /* Returning error, if sub-sequent commands req is
+ * not same as first_cmd_req type.
+ */
+ ret = BCME_UNSUPPORTED;
+ break;
+ }
+
+ /* bump sub-command count */
+ b_buf->count++;
+ /* No more commands to parse */
+ if (*argv == NULL) {
+ break;
+ }
+ /* Still un parsed arguments exist and
+ * immediate argument to parse is not
+ * a BATCH_DELIMITER
+ */
+ while (*argv != NULL) {
+ if (strcmp(*argv, WL_IOV_BATCH_DELIMITER) == 0) {
+ /* skip BATCH_DELIMITER i.e "+" */
+ argv++;
+ break;
+ }
+ argv++;
+ }
+ } else {
+ printf("Error handling sub-command %d\n", ret);
+ break;
+ }
+ }
+
+ /* Command usage error handling case */
+ if (ret != BCME_OK) {
+ goto fail;
+ }
+
+ iov_len = iov_len_start - iov_len;
+
+ /*
+ * Dispatch iovar
+ */
+ if (is_set) {
+ ret = wlu_var_setbuf(wl, "nan", (void *)b_buf, iov_len);
+ } else {
+ ret = wl_nan_do_get_ioctl(wl, (void *)b_buf, iov_len);
+ }
+
+fail:
+ if (ret != BCME_OK) {
+ printf("Error: %d\n", ret);
+ if (nancmd) {
+ wl_nan_help(nancmd->id);
+ } else {
+ wl_nan_help(NAN_HELP_ALL);
+ }
+ }
+ free(b_buf);
+ return ret;
+}
+
+static int
+wl_nan_subcmd_sync_tsreserve(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ chanspec_t chanspec;
+ wl_nan_timeslot_t tsconfig;
+ uint16 len;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(wl_nan_timeslot_t);
+ bzero(&tsconfig, sizeof(wl_nan_timeslot_t));
+ tsconfig.abitmap = strtoul(*argv, NULL, 0);
+ argv++;
+ if (tsconfig.abitmap) {
+ /* bitmap chanlist */
+ int i;
+ uint32 bitmap = tsconfig.abitmap;
+ for (i = 0; (i < NAN_MAX_TIMESLOT) && bitmap; i++) {
+ if (bitmap & (1 << i)) {
+ if (!*argv) {
+ fprintf(stderr, "missing chanspec\n");
+ goto fail;
+ }
+ if ((chanspec = wf_chspec_aton(*argv)) == 0) {
+ fprintf(stderr, "invalid chanspec %s\n", argv[0]);
+ res = BCME_BADARG;
+ goto fail;
+ }
+ tsconfig.chanlist[i] = chanspec;
+ bitmap &= ~(1 << i);
+ argv++;
+ }
+ }
+ } else {
+ /* bitmap chanspec duration */
+ if (*argv && *(argv + 1)) {
+ if ((chanspec = wf_chspec_aton(*argv)) == 0) {
+ fprintf(stderr, "%s: could not parse \"%s\" as channel\n",
+ cmd->name, argv[0]);
+ res = BCME_BADARG;
+ goto fail;
+ }
+ tsconfig.chanlist[0] = wl_chspec_to_driver(chanspec);
+ tsconfig.chanlist[1] = atoi(*(argv + 1));
+ } else if (!*argv) {
+ fprintf(stderr, "missing chanspec\n");
+ goto fail;
+ } else {
+ fprintf(stderr, "missing duration\n");
+ goto fail;
+ }
+ }
+ memcpy(iov_data, (uint8 *)&tsconfig, sizeof(wl_nan_timeslot_t));
+ }
+ *avail_len -= len;
+
+fail:
+ return res;
+}
+
+static int
+wl_nan_subcmd_sync_tsrelease(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ wl_nan_ts_bitmap_t rbitmap;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ *is_set = TRUE;
+ rbitmap = strtoul(*argv, NULL, 0);
+ memcpy(iov_data, (uint8 *)&rbitmap, sizeof(rbitmap));
+ *avail_len -= sizeof(rbitmap);
+
+ return res;
+}
+static int
+wl_nan_subcmd_cfg_oui(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ wl_nan_oui_type_t *nan_oui_type;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ if (ARGCNT(argv) < WL_NAN_CMD_CFG_OUI_ARGC) {
+ return BCME_USAGE_ERROR;
+ }
+
+ *is_set = TRUE;
+ len = sizeof(*nan_oui_type);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ nan_oui_type = (wl_nan_oui_type_t *)iov_data;
+
+ if (get_oui_bytes((uchar *)(*argv), (uchar *)nan_oui_type->nan_oui)) {
+ fprintf(stderr, "invalid OUI\n");
+ return BCME_BADARG;
+ }
+
+ /* advance to the next param */
+ argv++;
+
+ nan_oui_type->type = strtoul(*argv, NULL, 0);
+ }
+
+ *avail_len -= len;
+
+ return res;
+}
+
+static void
+print_peer_rssi(wl_nan_peer_rssi_data_t *prssi)
+{
+ uint16 peer_cnt, rssi_cnt;
+ wl_nan_peer_rssi_entry_t *peer;
+ char buf[MAX_MAC_BUF] = {'\0'};
+ char raw_rssi[MAX_RSSI_BUF] = {'\0'};
+ char avg_rssi[MAX_RSSI_BUF] = {'\0'};
+ size_t raw_sz_left, avg_sz_left;
+ uint16 raw_sz = 0, avg_sz = 0;
+
+ printf("> RSSI Data: \n");
+ printf("no of peers: %d\n", prssi->peer_cnt);
+ for (peer_cnt = 0; peer_cnt < prssi->peer_cnt; peer_cnt++) {
+ peer = &prssi->peers[peer_cnt];
+ bcm_ether_ntoa(&peer->mac, buf);
+ raw_sz_left = avg_sz_left = 128;
+ raw_sz = avg_sz = 0;
+ for (rssi_cnt = 0; rssi_cnt < peer->rssi_cnt; rssi_cnt++) {
+ raw_sz += snprintf(raw_rssi+raw_sz, MAX_RSSI_BUF-raw_sz,
+ "%d(%u) ", peer->rssi[rssi_cnt].rssi_raw,
+ peer->rssi[rssi_cnt].rx_chan);
+ raw_sz_left -= raw_sz;
+ avg_sz += snprintf(avg_rssi+avg_sz, MAX_RSSI_BUF-avg_sz,
+ "%d(%u) ", peer->rssi[rssi_cnt].rssi_avg,
+ peer->rssi[rssi_cnt].rx_chan);
+ avg_sz_left -= avg_sz;
+ }
+ if (prssi->flags & WL_NAN_PEER_RSSI) {
+ printf("%s %s %s \n", buf, raw_rssi, avg_rssi);
+ }
+ else if (prssi->flags & WL_NAN_PEER_RSSI_LIST)
+ {
+ printf("%s\n", buf);
+ printf("raw: %s\n", raw_rssi);
+ printf("avg: %s\n", avg_rssi);
+ } else {
+ /* Invalid */
+ }
+ }
+}
+
+static int
+wl_nan_subcmd_dump(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int ret = BCME_OK;
+ wl_nan_dbg_dump_type_t dump_type;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* It is always a get */
+ *is_set = FALSE;
+
+ if (!argv[0] || argc != 1) {
+ printf("Incorrect number of parameters.\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ if (!strcmp(argv[0], "rssi")) {
+ dump_type = WL_NAN_DBG_DT_RSSI_DATA;
+ } else if (!strcmp(argv[0], "stats")) {
+ dump_type = WL_NAN_DBG_DT_STATS_DATA;
+ } else {
+ printf("Invalid argument %s.\n", argv[0]);
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ len = sizeof(dump_type);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ memcpy(iov_data, &dump_type, len);
+ *avail_len -= len;
+
+exit:
+ return ret;
+}
+
+static int
+wl_nan_subcmd_dbg_level(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint16 len;
+ wl_nan_dbg_level_t dbg_level;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(is_set);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(wl_nan_dbg_level_t);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ memset(&dbg_level, 0, len);
+ if ((*argv != NULL)) {
+ dbg_level.nan_err_level = strtoul(*argv, NULL, 16);
+ argv++;
+ if ((*argv != NULL)) {
+ dbg_level.nan_dbg_level = strtoul(*argv, NULL, 16);
+ argv++;
+ if ((*argv != NULL)) {
+ dbg_level.nan_info_level = strtoul(*argv, NULL, 16);
+ }
+ }
+ }
+ memcpy(iov_data, (uint8 *)&dbg_level, sizeof(wl_nan_dbg_level_t));
+ }
+
+ *avail_len -= len;
+ return res;
+}
+
+static int
+wl_nan_subcmd_clear(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int ret = BCME_OK;
+ wl_nan_dbg_dump_type_t clear_type;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* It is always set */
+ *is_set = TRUE;
+
+ if (!argv[0] || argc != 1) {
+ printf("Incorrect number of parameters.\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ if (!strcmp(argv[0], "rssi")) {
+ clear_type = WL_NAN_DBG_DT_RSSI_DATA;
+ } else if (!strcmp(argv[0], "stats")) {
+ clear_type = WL_NAN_DBG_DT_STATS_DATA;
+ } else {
+ printf("Invalid argument %s.\n", argv[0]);
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ len = sizeof(clear_type);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ memcpy(iov_data, &clear_type, len);
+ *avail_len -= len;
+
+exit:
+ return ret;
+}
+
+/* nan 2.0 iovars */
+
+/* device capabilities */
+static int
+wl_nan_subcmd_dp_cap(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ return res;
+}
+
+/* status */
+static int
+wl_nan_subcmd_dp_status(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint8 ndp_id;
+ uint16 len;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if (*argv == NULL) {
+ return BCME_IOCTL_ERROR;
+ } else {
+ /* set is not supported */
+ *is_set = FALSE;
+ ndp_id = atoi(*argv);
+
+ if (ndp_id == 255) {
+ return BCME_BADARG;
+ }
+ len = sizeof(ndp_id);
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+ memcpy(iov_data, &ndp_id, sizeof(ndp_id));
+ }
+ *avail_len -= len;
+ return res;
+}
+
+/* statistics */
+static int
+wl_nan_subcmd_dp_stats(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ return res;
+}
+
+/* schedule update */
+static int
+wl_nan_subcmd_dp_schedupd(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(is_set);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ return res;
+}
+
+enum {
+ NAN_DP_CFG_TYPE_UCAST = 0x0001,
+ NAN_DP_CFG_TYPE_MCAST = 0x0002,
+ NAN_DP_CFG_SECURITY = 0x0003,
+ NAN_DP_CFG_QOS = 0x0004,
+ NAN_DP_CFG_PUB_INST = 0x0005,
+ NAN_DP_CFG_PEER_IFADDR = 0x0006,
+ NAN_DP_CFG_MCAST_IFADDR = 0x0007,
+ NAN_DP_CFG_DATA_IFADDR = 0x0008,
+ NAN_DP_CFG_SVC_SPEC_INFO = 0x0009,
+ NAN_DP_CFG_NDPID = 0x000a,
+ NAN_DP_CFG_STATUS = 0x000b,
+ NAN_DP_CFG_REASON_CODE = 0x000c,
+ NAN_DP_CFG_AVAIL = 0x000d,
+ NAN_DP_CFG_INIT_DATA_IFADDR = 0x000e,
+ NAN_DP_CFG_CONFIRM = 0x000f
+};
+
+typedef struct nan_dp_config_param_info {
+ char *name; /* <param-name> string to identify the config item */
+ uint16 id;
+ uint16 len; /* len in bytes */
+ char *help_msg; /* Help message */
+} nan_dp_config_param_info_t;
+
+/*
+ * Parameter name and size for service discovery IOVARs
+ */
+static const nan_dp_config_param_info_t nan_dp_config_param_info[] = {
+ /* param-name param_id len help message */
+ {"ucast", NAN_DP_CFG_TYPE_UCAST, 0,
+ "unicast req"},
+ {"mcast", NAN_DP_CFG_TYPE_MCAST, 0,
+ "multicast req"},
+ {"pub_id", NAN_DP_CFG_PUB_INST, sizeof(uint16),
+ "public instance id"},
+ {"status", NAN_DP_CFG_STATUS, sizeof(uint8),
+ "response frame status"},
+ {"confirm", NAN_DP_CFG_CONFIRM, sizeof(uint8),
+ "sets confirm/explicit confirm for dp_req/dp_resp"},
+ {"reason", NAN_DP_CFG_REASON_CODE, sizeof(uint8),
+ "response frame reason code"},
+ {"ndp_id", NAN_DP_CFG_NDPID, sizeof(uint8),
+ "Local ndp_id of peer"},
+ {"security", NAN_DP_CFG_SECURITY, sizeof(uint8),
+ "is security enabled"},
+ {"peer_mac", NAN_DP_CFG_PEER_IFADDR, ETHER_ADDR_LEN,
+ "peer mac address"},
+ {"data_mac", NAN_DP_CFG_DATA_IFADDR, ETHER_ADDR_LEN,
+ "local data mac address"},
+ {"init_data_mac", NAN_DP_CFG_INIT_DATA_IFADDR, ETHER_ADDR_LEN,
+ "Initiators data address(used in dataresp)"},
+ {"mcast_mac", NAN_DP_CFG_MCAST_IFADDR, ETHER_ADDR_LEN,
+ "multicast mac address"},
+ {"qos", NAN_DP_CFG_QOS, sizeof(wl_nan_dp_qos_t),
+ "qos <tid> <pkt size> <mean rate> <svc_interval>"},
+ {"svc_spec_info", NAN_DP_CFG_SVC_SPEC_INFO, WL_NAN_DP_MAX_SVC_INFO,
+ "service specific info"},
+ {"avail", NAN_DP_CFG_AVAIL, (OFFSETOF(wl_nan_ndp_config_t, data) +
+ WL_AVAIL_ALLOC_SIZE(WLU_AVAIL_MAX_SLOTS)),
+ "availability window"}
+};
+
+const nan_dp_config_param_info_t *
+nan_lookup_dp_config_param(char *param_name)
+{
+ int i = 0;
+ const nan_dp_config_param_info_t *param_p = &nan_dp_config_param_info[0];
+
+ for (i = 0; i < (int)ARRAYSIZE(nan_dp_config_param_info); i++) {
+ if (stricmp(param_p->name, param_name) == 0) {
+ return param_p;
+ }
+ param_p++;
+ }
+
+ return NULL;
+}
+
+static int
+wl_nan_subcmd_dp_autoconn(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint8 autoconn = 0;
+ uint16 len;
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ len = 0;
+ } else {
+ *is_set = TRUE;
+ len = sizeof(autoconn);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ autoconn = (uint8)atoi(*argv);
+ if (autoconn & WL_NAN_AUTO_DPRESP) {
+ printf("auto_dpresp enabled \n");
+ } else {
+ printf("auto_dpresp disabled \n");
+ }
+ if (autoconn & WL_NAN_AUTO_DPCONF) {
+ printf("auto_dpconf enabled \n");
+ } else {
+ printf("auto_dpconf disabled \n");
+ }
+ memcpy(iov_data, &autoconn, sizeof(autoconn));
+ }
+
+ *avail_len -= len;
+
+ return res;
+}
+
+int
+wl_nan_get_qos_params(char **argv, wl_nan_dp_qos_t *qos, uint8 *qos_num_params)
+{
+ if (*argv != NULL) {
+ qos->tid = (uint8)atoi(*argv);
+ argv++;
+ (*qos_num_params)++;
+
+ if (*argv != NULL) {
+ qos->pkt_size = (uint16)atoi(*argv);
+ argv++;
+ (*qos_num_params)++;
+
+ if (*argv != NULL) {
+ qos->mean_rate = (uint16)atoi(*argv);
+ argv++;
+ (*qos_num_params)++;
+
+ if (*argv != NULL) {
+ qos->svc_interval = (uint16)atoi(*argv);
+ (*qos_num_params)++;
+ return BCME_OK;
+ }
+ }
+ }
+ }
+ return BCME_ERROR;
+}
+
+static int
+wl_nan_subcmd_dp_req(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ wl_nan_dp_req_t *datareq = NULL;
+ int ret = BCME_OK;
+ uint16 len = 0;
+ uint8 qos_num_params = 0;
+ const nan_dp_config_param_info_t *param_p = NULL;
+
+ uint8 *pxtlv;
+ uint16 buflen = *avail_len, buflen_at_start;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if (*argv == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ datareq = (wl_nan_dp_req_t *)iov_data;
+ pxtlv = (uint8 *)&datareq->svc_spec_info;
+
+ if (*avail_len < sizeof(*datareq)) {
+ /* buffer is insufficient */
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ /* Setting default data path type to unicast */
+ datareq->type = WL_NAN_DP_TYPE_UNICAST;
+
+ *is_set = FALSE;
+
+ /* Parse optional args. Validity is checked by discovery engine */
+ while (*argv != NULL) {
+ if ((param_p = nan_lookup_dp_config_param(*argv)) == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /*
+ * Skip param name
+ */
+ argv++;
+ switch (param_p->id) {
+
+ case NAN_DP_CFG_TYPE_UCAST:
+ datareq->type = WL_NAN_DP_TYPE_UNICAST;
+ break;
+
+ case NAN_DP_CFG_TYPE_MCAST:
+ datareq->type = WL_NAN_DP_TYPE_MULTICAST;
+ break;
+
+ case NAN_DP_CFG_CONFIRM:
+ datareq->flag |= WL_NAN_DP_FLAG_CONFIRM;
+ break;
+
+ case NAN_DP_CFG_SECURITY:
+ if (*argv != NULL) {
+ datareq->security = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_DP_CFG_QOS:
+ ret = wl_nan_get_qos_params(argv, &datareq->qos, &qos_num_params);
+ if (ret != BCME_OK) {
+ return ret;
+ }
+ argv += qos_num_params;
+ break;
+
+ case NAN_DP_CFG_PUB_INST:
+ if (*argv != NULL) {
+ datareq->pub_id = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_DP_CFG_PEER_IFADDR:
+ if (*argv) {
+ if (!wl_ether_atoe(argv[0], &datareq->peer_mac)) {
+ printf("Malformed MAC address parameter\n");
+ break;
+ }
+ argv++;
+ }
+ break;
+
+ case NAN_DP_CFG_MCAST_IFADDR:
+ if (*argv != NULL) {
+ if (datareq->type != WL_NAN_DP_TYPE_MULTICAST) {
+ printf("ERROR: multicast mac addr specified"
+ "with unicast type\n");
+ return BCME_ERROR;
+ }
+ if (!wl_ether_atoe(argv[0], &datareq->mcast_mac)) {
+ printf("Malformed MAC address parameter\n");
+ break;
+ }
+ argv++;
+ }
+ break;
+
+ case NAN_DP_CFG_SVC_SPEC_INFO:
+ if (*argv) {
+ buflen_at_start = buflen;
+ ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv,
+ &buflen, WL_NAN_XTLV_SVC_INFO, *argv);
+ if (ret != BCME_OK) {
+ printf("unable to process svc_spec_info: %d\n", ret);
+ return ret;
+ }
+ len += (uint8)(buflen_at_start - buflen);
+ datareq->flag |= WL_NAN_DP_FLAG_SVC_INFO;
+ argv++;
+ }
+ break;
+
+ default:
+ return BCME_ERROR;
+ break;
+
+ } /* switch */
+ } /* while */
+
+ len += OFFSETOF(wl_nan_dp_req_t, svc_spec_info);
+ *avail_len -= len;
+
+exit:
+ return ret;
+}
+
+static int
+wl_nan_subcmd_dp_resp(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ wl_nan_dp_resp_t *dataresp = NULL;
+ int ret = BCME_OK;
+ uint16 len = 0;
+ uint8 qos_num_params = 0;
+ const nan_dp_config_param_info_t *param_p = NULL;
+
+ uint8 *pxtlv;
+ uint16 buflen = *avail_len, buflen_at_start;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if (*argv == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ dataresp = (wl_nan_dp_resp_t *)iov_data;
+ pxtlv = (uint8 *)&dataresp->svc_spec_info;
+
+ if (*avail_len < sizeof(*dataresp)) {
+ /* buffer is insufficient */
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ /* Setting default data path type to unicast */
+ dataresp->type = WL_NAN_DP_TYPE_UNICAST;
+
+ *is_set = FALSE;
+
+ /* Parse optional args. Validity is checked by discovery engine */
+ while (*argv != NULL) {
+ if ((param_p = nan_lookup_dp_config_param(*argv)) == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /*
+ * Skip param name
+ */
+ argv++;
+ switch (param_p->id) {
+
+ case NAN_DP_CFG_TYPE_UCAST:
+ dataresp->type = WL_NAN_DP_TYPE_UNICAST;
+ break;
+
+ case NAN_DP_CFG_TYPE_MCAST:
+ dataresp->type = WL_NAN_DP_TYPE_MULTICAST;
+ break;
+
+ case NAN_DP_CFG_CONFIRM:
+ dataresp->flag |= WL_NAN_DP_FLAG_EXPLICIT_CFM;
+ break;
+
+ case NAN_DP_CFG_SECURITY:
+ if (*argv != NULL) {
+ dataresp->security = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_DP_CFG_STATUS:
+ if (*argv != NULL) {
+ dataresp->status = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_DP_CFG_REASON_CODE:
+ if (*argv != NULL) {
+ dataresp->reason_code = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_DP_CFG_QOS:
+ ret = wl_nan_get_qos_params(argv, &dataresp->qos, &qos_num_params);
+ if (ret != BCME_OK) {
+ return ret;
+ }
+ argv += qos_num_params;
+ break;
+
+ case NAN_DP_CFG_NDPID:
+ if (*argv != NULL) {
+ dataresp->ndp_id = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_DP_CFG_PEER_IFADDR:
+ case NAN_DP_CFG_MCAST_IFADDR:
+ if (*argv != NULL) {
+ if (!wl_ether_atoe(argv[0], &dataresp->mac_addr)) {
+ printf("Malformed MAC address parameter\n");
+ break;
+ }
+ argv++;
+ }
+ break;
+
+ case NAN_DP_CFG_SVC_SPEC_INFO:
+ if (*argv) {
+ buflen_at_start = buflen;
+ ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv,
+ &buflen, WL_NAN_XTLV_SVC_INFO, *argv);
+ if (ret != BCME_OK) {
+ printf("unable to process svc_spec_info: %d\n", ret);
+ return ret;
+ }
+ len += (uint8)(buflen_at_start - buflen);
+ dataresp->flag |= WL_NAN_DP_FLAG_SVC_INFO;
+ argv++;
+ }
+ break;
+
+ default:
+ return BCME_ERROR;
+ break;
+
+ } /* switch */
+ } /* while */
+
+ len += OFFSETOF(wl_nan_dp_resp_t, svc_spec_info);
+ *avail_len -= len;
+
+exit:
+ return ret;
+}
+
+static int
+wl_nan_subcmd_dp_conf(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint8 ndp_id;
+ uint8 status;
+ uint16 len;
+ wl_nan_dp_conf_t *dataconf = (wl_nan_dp_conf_t *)iov_data;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ if ((*argv == NULL) || (*argv != NULL && argc < 2)) {
+ return BCME_IOCTL_ERROR;
+ } else {
+ *is_set = TRUE;
+ ndp_id = atoi(*argv);
+
+ if (ndp_id == WL_NAN_INVALID_NDPID) {
+ return BCME_BADARG;
+ }
+
+ len = sizeof(*dataconf);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ argv++;
+ status = atoi(*argv);
+
+ dataconf->lndp_id = ndp_id;
+ dataconf->status = status;
+ }
+
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_dp_dataend(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+ uint8 ndp_id;
+ uint8 status;
+ uint16 len;
+ wl_nan_dp_end_t dataend;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ if ((*argv == NULL) || (*argv != NULL && argc < 2)) {
+ return BCME_IOCTL_ERROR;
+ } else {
+ /* get is not supported */
+ *is_set = TRUE;
+ ndp_id = atoi(*argv);
+
+ if (ndp_id == WL_NAN_INVALID_NDPID) {
+ return BCME_BADARG;
+ }
+
+ len = sizeof(dataend);
+
+ if (len > *avail_len) {
+ printf("Buf short, requested:%d, available:%d\n",
+ len, *avail_len);
+ return BCME_BUFTOOSHORT;
+ }
+
+ argv++;
+ status = atoi(*argv);
+ dataend.lndp_id = ndp_id;
+ dataend.status = status;
+
+ memcpy(iov_data, &dataend, sizeof(dataend));
+ }
+
+ *avail_len -= len;
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_dp_show(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int res = BCME_OK;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(iov_data);
+ UNUSED_PARAMETER(avail_len);
+
+ if ((*argv != NULL) || argc != 0) {
+ return BCME_IOCTL_ERROR;
+ } else {
+ /* only get is supported */
+ *is_set = FALSE;
+ }
+
+ return res;
+}
+
+static int
+wl_nan_subcmd_cfg_avail(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int ret = BCME_OK;
+ bool started = FALSE;
+ wl_avail_new_t *avail = (wl_avail_new_t *)iov_data;
+ wl_avail_entry_t *entry; /* used for filling entry structure */
+ uint8 *p = avail->entry; /* tracking pointer */
+ uint8 avail_type; /* 1=local, 2=peer, 3=ndc, 4=immutable, 5=response, 6=counter */
+ uint8 entry_type; /* 1=committed, 2=potential */
+ uint8 optional_num;
+
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ if (*argv == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ avail_type = atoi(*argv++);
+ if (avail_type < WL_AVAIL_LOCAL || avail_type > WL_AVAIL_TYPE_MAX) {
+ printf("Invalid availability type\n");
+ ret = BCME_USAGE_ERROR; goto exit;
+ }
+
+ /* check for GET first */
+ if (*argv == NULL || argc == 1) {
+ if ((avail_type >= WL_AVAIL_LOCAL) &&
+ (avail_type <= WL_AVAIL_TYPE_MAX)) {
+ memcpy(iov_data, &avail_type, sizeof(avail_type));
+ *avail_len -= sizeof(avail_type);
+ *is_set = FALSE;
+ goto exit;
+ }
+ }
+
+ *is_set = TRUE;
+ /* populate wl_avail fields */
+ avail->flags = avail_type;
+ avail->time_ref = WL_TIME_REF_NAN_DW0;
+ avail->length = sizeof(*avail);
+ avail->num_entries = 0;
+
+ printf("\nType (1=local, 2=peer, 3=ndc, 4=immutable, 5=response, "
+ "6=counter, 7=ranging): %d\n", avail_type);
+ /* populate avail entries */
+ while (*argv != NULL) {
+ entry = (wl_avail_entry_t*)p;
+ if ((stricmp(*argv++, "entry") != 0)) {
+ prhex("argv", (uchar*)*argv, 7);
+ if (!started) {
+ printf("Missing avail entry type\n");
+ ret = BCME_USAGE_ERROR; goto exit;
+ }
+ break;
+ } else {
+ started = TRUE;
+ entry_type = atoi(*argv++);
+ if ((entry_type == (WL_AVAIL_ENTRY_COM | WL_AVAIL_ENTRY_COND)) ||
+ (entry_type >= (WL_AVAIL_ENTRY_COM |
+ WL_AVAIL_ENTRY_POT | WL_AVAIL_ENTRY_COND))) {
+ printf("Invalid entry type\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ entry->flags = entry_type;
+ }
+ /* optional parameters */
+ optional_num = 0;
+ if ((ret = wl_nan_set_avail_entry_optional(argv, avail, entry,
+ avail_type, &optional_num)) != BCME_OK) {
+ goto exit;
+ }
+
+ /* update wl_avail and populate wl_avail_entry */
+ entry->length = htod16(sizeof(*entry) + entry->bitmap_len);
+ entry->flags = htod16(entry->flags);
+ avail->num_entries++;
+ avail->length += entry->length;
+
+ /* advance pointer for next entry */
+ p += entry->length;
+ argv += optional_num;
+
+ /* output configuration info */
+ wlu_nan_print_wl_avail_entry(avail_type & WL_AVAIL_TYPE_MASK, entry);
+ }
+
+ /* update avail_len only if there are avail entries */
+ if (avail->num_entries) {
+ *avail_len -= avail->length;
+ }
+ avail->length = htod16(avail->length);
+
+ prhex("\ntotal wl_avail", (uchar*)avail, avail->length);
+exit:
+ return ret;
+}
+
+#define WLU_AVAIL_NUM_ARGS_PER_PARAM 2
+/* process optional parameters and sets them in wl_avail_entry */
+static int
+wl_nan_set_avail_entry_optional(char** argv, wl_avail_new_t* avail, wl_avail_entry_t* entry,
+ uint8 avail_type, uint8* num)
+{
+ int ret = BCME_OK;
+ uint8 i;
+ char *a;
+ uint8 bitdur_type;
+ uint8 period_type;
+ uint16 offset; /* start offset, 0-511 */
+ uint8 usage; /* usage preference, 0-3 */
+ uint32 chanspec; /* 0=all channels/bands */
+ uint32 band; /* 0=all bands, 1=sub-1G, 2=2.4G, 4=5G */
+ struct ether_addr ndc_id;
+ struct ether_addr peer_nmi;
+ char def_ndc_id[ETHER_ADDR_LEN] = { 0xAA, 0xBB, 0xCC, 0x00, 0x0, 0x0 };
+ char def_peer_nmi[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0xaa, 0xbb, 0xcc };
+
+ /* set default values for optional parameters */
+ entry->start_offset = 0;
+ entry->u.band = 0;
+ entry->period = WL_AVAIL_PERIOD_512;
+ entry->flags |= (3 << WL_AVAIL_ENTRY_USAGE_SHIFT) |
+ (WL_AVAIL_BIT_DUR_16 << WL_AVAIL_ENTRY_BIT_DUR_SHIFT);
+ if (avail_type == WL_AVAIL_NDC) {
+ memcpy(&avail->u.addr, def_ndc_id, ETHER_ADDR_LEN);
+ } else if (avail_type == WL_AVAIL_PEER) {
+ memcpy(&avail->u.addr, def_peer_nmi, ETHER_ADDR_LEN);
+ }
+ entry->bitmap_len = 0;
+
+ /* parse optional parameters */
+ while ((*argv != NULL) && (stricmp(*argv, "entry") != 0)) {
+ if ((stricmp(*argv, "bitdur") == 0)) {
+ argv++;
+ bitdur_type = atoi(*argv++);
+ /* by design, local avail slots are 16TU */
+ if (bitdur_type > WL_AVAIL_BIT_DUR_128) {
+ printf("Invalid bitdur type\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ entry->flags |= bitdur_type << WL_AVAIL_ENTRY_BIT_DUR_SHIFT;
+ } else if ((stricmp(*argv, "period") == 0)) {
+ argv++;
+ period_type = atoi(*argv++);
+ if (period_type > WL_AVAIL_PERIOD_8192) {
+ printf("Invalid period type\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ entry->period = period_type;
+ } else if ((stricmp(*argv, "offset") == 0)) {
+ argv++;
+ offset = atoi(*argv++);
+ if (offset > 511) {
+ printf("Invalid offset\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ entry->start_offset = htod16(offset);
+ } else if ((stricmp(*argv, "usage") == 0)) {
+ argv++;
+ usage = atoi(*argv++);
+ if (usage > 3) {
+ printf("Invalid usage pref\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ entry->flags &= ~(WL_AVAIL_ENTRY_USAGE_MASK);
+ entry->flags |= usage << WL_AVAIL_ENTRY_USAGE_SHIFT;
+ } else if ((stricmp(*argv, "ndc") == 0)) {
+ argv++;
+ if (avail_type != WL_AVAIL_NDC) {
+ printf("ndc id is for type ndc\n");
+ ret = BCME_USAGE_ERROR; goto exit;
+ }
+ if (!wl_ether_atoe(*argv++, &ndc_id)) {
+ printf("Invalid ndc id\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ memcpy(&avail->u.addr, &ndc_id, ETHER_ADDR_LEN);
+ } else if ((stricmp(*argv, "chanspec") == 0)) {
+ argv++;
+ chanspec = wf_chspec_aton(*argv++);
+ if (chanspec == 0) {
+ printf("Invalid chanspec\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ entry->flags |= 1 << WL_AVAIL_ENTRY_CHAN_SHIFT;
+ entry->u.channel_info = htod32(chanspec);
+ } else if ((stricmp(*argv, "band") == 0)) {
+ argv++;
+ band = atoi(*argv++);
+ if (band > 4) {
+ printf("Invalid band\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ entry->flags |= 1 << WL_AVAIL_ENTRY_BAND_SHIFT;
+ entry->u.band = htod32(band);
+ } else if ((stricmp(*argv, "bitmap") == 0)) {
+ argv++;
+ /* point to bitmap value for processing */
+ a = *argv;
+ for (i = 0; i < strlen(*argv); i++) {
+ if (*a == '1') {
+ setbit(entry->bitmap, i);
+ }
+ a++;
+ }
+ argv++;
+ /* account for partially filled most significant byte */
+ entry->bitmap_len = (i + NBBY - 1) / NBBY;
+ } else if (stricmp(*argv, "otahexmap") == 0) {
+ argv++;
+ entry->bitmap_len = (strlen(*argv) + 1) / 2;
+ if (get_ie_data((uchar*)*argv++, entry->bitmap, entry->bitmap_len)) {
+ ret = BCME_BADARG;
+ goto exit;
+ }
+ /* peer nmi address for peer NA */
+ } else if ((stricmp(*argv, "peer") == 0)) {
+ /* peer nmi address for peer NA */
+ argv++;
+ if (avail_type != WL_AVAIL_PEER) {
+ printf("peer nmi is for type peer\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ if (!wl_ether_atoe(*argv++, &peer_nmi)) {
+ printf("Invalid peer nmi\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ memcpy(&avail->u.addr, &peer_nmi, ETHER_ADDR_LEN);
+ } else {
+ printf("Recognized parameter %s\n", *argv);
+ ret = BCME_BADARG;
+ *num = 0;
+ goto exit;
+ }
+ (*num)++;
+ /* TODO add option for channel entry in hex data (opclass + bitmap) */
+
+ /* TODO add option for entire avail entry in hex data */
+ }
+exit:
+ *num *= WLU_AVAIL_NUM_ARGS_PER_PARAM;
+ return ret;
+}
+
+typedef struct nan_rng_config_param_info {
+ char *name; /* <param-name> string to identify the config item */
+ uint16 id;
+ uint16 len; /* len in bytes */
+ char *help_msg; /* Help message */
+} nan_rng_config_param_info_t;
+enum {
+ NAN_RNG_CFG_PEER = 0x0001,
+ NAN_RNG_CFG_RANGE_ID = 0x0002,
+ NAN_RNG_CFG_PUB_ID = 0x0003,
+ NAN_RNG_CFG_INTERVAL = 0x0004,
+ NAN_RNG_CFG_RESOLUTION = 0x0005,
+ NAN_RNG_CFG_INDICATION = 0x0006,
+ NAN_RNG_CFG_INGRESS_LIMIT = 0x0007,
+ NAN_RNG_CFG_EGRESS_LIMIT = 0x0008,
+ NAN_RNG_CFG_RESULT_REQUIRED = 0x0009,
+ NAN_RNG_CFG_AUTO_RESPONSE = 0x000a,
+ NAN_RNG_CFG_RANGE_STATUS = 0x000b
+};
+
+
+/*
+ * Parameter name and size for service discovery IOVARs
+ */
+static const nan_rng_config_param_info_t nan_rng_config_param_info[] = {
+ /* param-name param_id len help message */
+ {"range_id", NAN_RNG_CFG_RANGE_ID, sizeof(uint8),
+ "unique handle"},
+ {"peer", NAN_RNG_CFG_PEER, ETHER_ADDR_LEN,
+ "ranging peer"},
+ {"pub_id", NAN_RNG_CFG_PUB_ID, sizeof(uint8),
+ "range service public instance id"},
+ {"resolution", NAN_RNG_CFG_RESOLUTION, sizeof(uint32),
+ "resolution of distance"},
+ {"interval", NAN_RNG_CFG_INTERVAL, sizeof(uint32),
+ "interval in TU b/w ranging sessions"},
+ {"indication", NAN_RNG_CFG_INDICATION, sizeof(uint8),
+ "eventing condition, cont/ingress/egress/both"},
+ {"ingress", NAN_RNG_CFG_INGRESS_LIMIT, sizeof(uint32),
+ "ingress distance condition"},
+ {"egress", NAN_RNG_CFG_EGRESS_LIMIT, sizeof(uint32),
+ "egress distance condition"},
+ {"result", NAN_RNG_CFG_RESULT_REQUIRED, 0,
+ "report required from peer"},
+ {"auto", NAN_RNG_CFG_AUTO_RESPONSE, 0,
+ "auto respond to range req"},
+ {"status", NAN_RNG_CFG_RANGE_STATUS, sizeof(uint8),
+ "host status whether accepted or rejected"},
+};
+
+const nan_rng_config_param_info_t *
+nan_lookup_rng_config_param(char *param_name)
+{
+ int i = 0;
+ const nan_rng_config_param_info_t *param_p = &nan_rng_config_param_info[0];
+
+ for (i = 0; i < (int)ARRAYSIZE(nan_rng_config_param_info); i++) {
+ if (stricmp(param_p->name, param_name) == 0) {
+ return param_p;
+ }
+ param_p++;
+ }
+
+ return NULL;
+}
+
+static int
+wl_nan_subcmd_range_req(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ wl_nan_range_req_t *range_req = NULL;
+ int ret = BCME_OK;
+ uint16 len = 0;
+ const nan_rng_config_param_info_t *param_p = NULL;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if (*argv == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ range_req = (wl_nan_range_req_t *)iov_data;
+
+
+ if (*avail_len < NAN_RNG_REQ_IOV_LEN) {
+ /* buffer is insufficient */
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ *is_set = FALSE;
+
+ /* Parse optional args. Validity is checked by discovery engine */
+ while (*argv != NULL) {
+ if ((param_p = nan_lookup_rng_config_param(*argv)) == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /*
+ * Skip param name
+ */
+ argv++;
+ switch (param_p->id) {
+
+ case NAN_RNG_CFG_PUB_ID:
+ if (*argv != NULL) {
+ range_req->publisher_id = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_PEER:
+ if (*argv != NULL) {
+ if (!wl_ether_atoe(argv[0], &range_req->peer)) {
+ printf("Malformed MAC address parameter\n");
+ break;
+ }
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_INDICATION:
+ if (*argv != NULL) {
+ range_req->indication = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_RESOLUTION:
+ if (*argv != NULL) {
+ range_req->resolution = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_INGRESS_LIMIT:
+ if (*argv != NULL) {
+ range_req->ingress = (uint32)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_EGRESS_LIMIT:
+ if (*argv != NULL) {
+ range_req->egress = (uint32)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_INTERVAL:
+ if (*argv != NULL) {
+ range_req->interval = (uint16)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ default:
+ return BCME_ERROR;
+ break;
+ }
+ }
+ len += NAN_RNG_REQ_IOV_LEN;
+ *avail_len -= len;
+exit:
+ return ret;
+}
+
+static int
+wl_nan_subcmd_range_auto(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ int ret = BCME_OK;
+ uint16 len = 0;
+ uint8 auto_accept = 0;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if (*argv == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ if (*avail_len < sizeof(auto_accept)) {
+ /* buffer is insufficient */
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ *is_set = TRUE;
+
+ *iov_data = auto_accept = (uint8)(atoi(*argv));
+
+ len += sizeof(auto_accept);
+ *avail_len -= len;
+exit:
+ return ret;
+
+}
+
+static int
+wl_nan_subcmd_range_resp(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ wl_nan_range_resp_t *range_resp = NULL;
+ int ret = BCME_OK;
+ uint16 len = 0;
+ uint8 flags = 0;
+ const nan_rng_config_param_info_t *param_p = NULL;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if (*argv == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ range_resp = (wl_nan_range_resp_t *)iov_data;
+
+ if (*avail_len < NAN_RNG_RESP_IOV_LEN) {
+ /* buffer is insufficient */
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ range_resp->range_id = (uint8)(atoi(*argv));
+ argv++;
+ argc--;
+
+ *is_set = TRUE;
+
+ /* Parse optional args. Validity is checked by discovery engine */
+ while (*argv != NULL) {
+ if ((param_p = nan_lookup_rng_config_param(*argv)) == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ /*
+ * Skip param name
+ */
+ argv++;
+ switch (param_p->id) {
+
+ case NAN_RNG_CFG_INDICATION:
+ if (*argv != NULL) {
+ range_resp->indication = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_RESOLUTION:
+ if (*argv != NULL) {
+ range_resp->resolution = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_INGRESS_LIMIT:
+ if (*argv != NULL) {
+ range_resp->ingress = (uint32)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_EGRESS_LIMIT:
+ if (*argv != NULL) {
+ range_resp->egress = (uint32)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_INTERVAL:
+ if (*argv != NULL) {
+ range_resp->interval = (uint16)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ case NAN_RNG_CFG_RESULT_REQUIRED:
+ flags |= NAN_RANGE_FLAG_RESULT_REQUIRED;
+ break;
+
+ case NAN_RNG_CFG_RANGE_STATUS:
+ if (*argv != NULL) {
+ range_resp->status = (uint8)(atoi(*argv));
+ argv++;
+ }
+ break;
+
+ default:
+ return BCME_ERROR;
+ break;
+ }
+ }
+ range_resp->flags = flags;
+ len += NAN_RNG_RESP_IOV_LEN;
+ *avail_len -= len;
+exit:
+ return ret;
+}
+
+static int
+wl_nan_subcmd_range_cancel(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ wl_nan_range_id range_id = 0;
+ int ret = BCME_OK;
+ uint16 len = 0;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argc);
+
+ if (*argv == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (*avail_len < sizeof(range_id)) {
+ /* buffer is insufficient */
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ *is_set = TRUE;
+
+ *iov_data = range_id = (uint8)(atoi(*argv));
+
+ len += sizeof(range_id);
+ *avail_len -= len;
+exit:
+ return ret;
+}
+
+/* WFA testmode operation */
+static int
+wl_nan_subcmd_cfg_wfa_testmode(void *wl, const wl_nan_sub_cmd_t *cmd, int argc, char **argv,
+ bool *is_set, uint8 *iov_data, uint16 *avail_len)
+{
+ wl_nan_wfa_testmode_t flags = 0;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* If no more parameters are passed, it is GET command */
+ if ((*argv == NULL) || argc == 0) {
+ *is_set = FALSE;
+ } else {
+ char *endptr = NULL;
+
+ *is_set = TRUE;
+ flags = strtoul(*argv, &endptr, 0);
+
+ if (flags & ~WL_NAN_WFA_TM_FLAG_MASK) {
+ return BCME_BADARG;
+ }
+ if (*avail_len < sizeof(flags)) {
+ return BCME_BUFTOOSHORT;
+ }
+
+ flags = htod32(flags);
+ memcpy(iov_data, &flags, sizeof(flags));
+ *avail_len -= sizeof(flags);
+ }
+
+ return BCME_OK;
+}
+
+#endif /* WL_NAN */
diff --git a/wl/src/wl/exe/wluc_natoe.c b/wl/src/wl/exe/wluc_natoe.c
new file mode 100644
index 0000000..dd30b51
--- /dev/null
+++ b/wl/src/wl/exe/wluc_natoe.c
@@ -0,0 +1,572 @@
+/*
+ * wl natoe command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_natoe.c 625864 2016-03-18 00:12:54Z $
+ */
+#include <wlioctl.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_natoe_control;
+typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
+typedef int (natoe_cmd_handler_t)(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
+
+struct wl_natoe_sub_cmd {
+ char *name;
+ uint8 version; /* cmd version */
+ uint16 id; /* id for the dongle f/w switch/case */
+ uint16 type; /* base type of argument */
+ natoe_cmd_handler_t *handler; /* cmd handler */
+};
+
+#define NATOE_PARAMS_USAGE \
+"\tUsage: wl natoe [command] [cmd options] as follows:\n" \
+"\t\twl natoe enable [1/0] - enable disable natoe functionality\n" \
+"\t\twl natoe config_ips [sta ip][sta netmask][default router][sta dns]\n" \
+"\t\t\t[ap ip][ap netmask]\n" \
+"\t\twl natoe config_ports [starting port number][no of ports]\n" \
+"\t\twl natoe stats [0] - 0 to clear stats\n" \
+"\t\twl natoe tbl_cnt [no_tbl_entries]\n"
+
+#define WL_NATOE_CMD "natoe"
+#define WL_NATOE_MAX_PORT_NUM 65535
+
+#define WL_NATOE_SUBCMD_ENABLE_ARGC 1
+#define WL_NATOE_SUBCMD_CONFIG_IPS_ARGC 6
+#define WL_NATOE_SUBCMD_CONFIG_PORTS_ARGC 2
+#define WL_NATOE_SUBCMD_DBG_STATS_ARGC 1
+#define WL_NATOE_SUBCMD_TBL_CNT_ARGC 1
+
+#define WL_NATOE_FUNC(suffix) wl_natoe_subcmd_ ##suffix
+static int wl_natoe_subcmd_enable(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
+static int wl_natoe_subcmd_config_ips(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
+static int wl_natoe_subcmd_config_ports(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
+static int wl_natoe_subcmd_dbg_stats(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
+static int wl_natoe_subcmd_tbl_cnt(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv);
+
+static cmd_t wl_natoe_cmds[] = {
+ { WL_NATOE_CMD, wl_natoe_control, WLC_GET_VAR, WLC_SET_VAR,
+ "superfunction for natoe commands \n\n"
+ NATOE_PARAMS_USAGE},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
+ /* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
+ {"enable", WL_NATOE_IOCTL_VERSION, WL_NATOE_CMD_ENABLE,
+ IOVT_BUFFER, WL_NATOE_FUNC(enable)
+ },
+ {"config_ips", WL_NATOE_IOCTL_VERSION, WL_NATOE_CMD_CONFIG_IPS,
+ IOVT_BUFFER, WL_NATOE_FUNC(config_ips)
+ },
+ {"config_ports", WL_NATOE_IOCTL_VERSION, WL_NATOE_CMD_CONFIG_PORTS,
+ IOVT_BUFFER, WL_NATOE_FUNC(config_ports)
+ },
+ {"stats", WL_NATOE_IOCTL_VERSION, WL_NATOE_CMD_DBG_STATS,
+ IOVT_BUFFER, WL_NATOE_FUNC(dbg_stats)
+ },
+ {"tbl_cnt", WL_NATOE_IOCTL_VERSION, WL_NATOE_CMD_TBL_CNT,
+ IOVT_BUFFER, WL_NATOE_FUNC(tbl_cnt)
+ },
+ {NULL, 0, 0, 0, NULL}
+};
+
+void
+wluc_natoe_module_init(void)
+{
+ /* register natoe commands */
+ wl_module_cmds_register(wl_natoe_cmds);
+}
+
+static int
+wlu_natoe_set_vars_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
+{
+ int res = BCME_OK;
+
+ UNUSED_PARAMETER(ctx);
+ UNUSED_PARAMETER(len);
+
+ switch (type) {
+
+ case WL_NATOE_XTLV_ENABLE:
+ {
+ printf("natoe: %s\n", *data?"enabled":"disabled");
+ break;
+ }
+
+ case WL_NATOE_XTLV_CONFIG_IPS:
+ {
+ wl_natoe_config_ips_t *config_ips;
+
+ config_ips = (wl_natoe_config_ips_t *)data;
+ printf("sta ip: %s\n", wl_iptoa((struct ipv4_addr *)&config_ips->sta_ip));
+ printf("sta netmask: %s\n", wl_iptoa((struct ipv4_addr *)&config_ips->sta_netmask));
+ printf("sta router ip: %s\n",
+ wl_iptoa((struct ipv4_addr *)&config_ips->sta_router_ip));
+ printf("sta dns ip: %s\n", wl_iptoa((struct ipv4_addr *)&config_ips->sta_dnsip));
+ printf("ap ip: %s\n", wl_iptoa((struct ipv4_addr *)&config_ips->ap_ip));
+ printf("ap netmask: %s\n", wl_iptoa((struct ipv4_addr *)&config_ips->ap_netmask));
+ break;
+ }
+
+ case WL_NATOE_XTLV_CONFIG_PORTS:
+ {
+ wl_natoe_ports_config_t *ports_config;
+
+ ports_config = (wl_natoe_ports_config_t *)data;
+ printf("starting port num: %d\n", dtoh16(ports_config->start_port_num));
+ printf("number of ports: %d\n", dtoh16(ports_config->no_of_ports));
+ break;
+ }
+
+ case WL_NATOE_XTLV_DBG_STATS:
+ {
+ char *stats_dump = ((char *)data);
+
+ printf("%s\n", stats_dump);
+ break;
+ }
+
+ case WL_NATOE_XTLV_TBL_CNT:
+ {
+ printf("natoe max table entries count: %d\n", dtoh32(*(uint32 *)data));
+ break;
+ }
+
+ default:
+ /* ignore */
+ break;
+ }
+ return res;
+}
+
+static int
+wl_natoe_get_stats(void *wl, wl_natoe_ioc_t *natoe_ioc, uint16 iocsz)
+{
+ /* for gets we only need to pass ioc header */
+ wl_natoe_ioc_t *iocresp = NULL;
+ int res;
+ int iocresp_sz = sizeof(*iocresp) + WL_NATOE_DBG_STATS_BUFSZ;
+
+ /* send getbuf natoe iovar */
+ iocresp = calloc(1, iocresp_sz);
+ if (iocresp == NULL) {
+ return BCME_NOMEM;
+ }
+
+ res = wlu_iovar_getbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz,
+ (void *)iocresp, iocresp_sz);
+ /* check the response buff */
+ if (res == BCME_OK) {
+ /* scans ioctl tlvbuf f& invokes the cbfn for processing */
+ res = bcm_unpack_xtlv_buf(natoe_ioc, iocresp->data, iocresp->len,
+ BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
+ }
+
+ free(iocresp);
+
+ return res;
+}
+
+/*
+ * --- common for all natoe get commands except for stats ----
+ */
+static int
+wl_natoe_get_ioctl(void *wl, wl_natoe_ioc_t *natoe_ioc, uint16 iocsz)
+{
+ /* for gets we only need to pass ioc header */
+ wl_natoe_ioc_t *iocresp = NULL;
+ int res;
+
+ /* send getbuf natoe iovar */
+ res = wlu_var_getbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz, (void *)&iocresp);
+ /* check the response buff */
+ if ((res == BCME_OK) && (iocresp != NULL)) {
+ /* scans ioctl tlvbuf f& invokes the cbfn for processing */
+ res = bcm_unpack_xtlv_buf(natoe_ioc, iocresp->data, iocresp->len,
+ BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
+ }
+
+ return res;
+}
+
+static int
+wl_natoe_subcmd_enable(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv)
+{
+ int res = BCME_OK;
+ wl_natoe_ioc_t *natoe_ioc;
+ uint16 buflen, buflen_at_start;
+ uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
+ bcm_xtlv_t *pxtlv = NULL;
+
+ /* alloc mem for ioctl headr + tlv data */
+ natoe_ioc = calloc(1, iocsz);
+ if (natoe_ioc == NULL) {
+ return BCME_NOMEM;
+ }
+
+ /* make up natoe cmd ioctl header */
+ natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
+ natoe_ioc->id = htod16(cmd->id);
+ natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
+ pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
+
+ if(*argv == NULL) { /* get */
+ iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
+ res = wl_natoe_get_ioctl(wl, natoe_ioc, iocsz);
+
+ } else { /* set */
+ /* max tlv data we can write, it will be decremented as we pack */
+ uint8 val;
+
+ if (ARGCNT(argv) != WL_NATOE_SUBCMD_ENABLE_ARGC) {
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ val = atoi(*argv);
+ buflen = WL_NATOE_IOC_BUFSZ;
+ /* save buflen at start */
+ buflen_at_start = buflen;
+
+ /* we'll adjust final ioc size at the end */
+ res = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
+ sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
+
+ if (res != BCME_OK) {
+ goto exit;
+ }
+
+ /* adjust iocsz to the end of last data record */
+ natoe_ioc->len = (buflen_at_start - buflen);
+ iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
+
+ res = wlu_var_setbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz);
+ }
+exit:
+
+ free(natoe_ioc);
+ return res;
+}
+
+static int
+wl_natoe_subcmd_config_ips(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv)
+{
+ int res = BCME_USAGE_ERROR;
+ wl_natoe_config_ips_t config_ips;
+ wl_natoe_ioc_t *natoe_ioc = NULL;
+ uint16 buflen, buflen_at_start;
+ uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
+ bcm_xtlv_t *pxtlv = NULL;
+
+ /* alloc mem for ioctl headr + tlv data */
+ natoe_ioc = calloc(1, iocsz);
+ if (natoe_ioc == NULL) {
+ return BCME_NOMEM;
+ }
+
+ /* make up natoe cmd ioctl header */
+ natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
+ natoe_ioc->id = htod16(cmd->id);
+ natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
+ pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
+
+ if (*argv == NULL) {
+ iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
+ res = wl_natoe_get_ioctl(wl, natoe_ioc, iocsz);
+ } else {
+ memset(&config_ips, 0, sizeof(config_ips));
+
+ if (ARGCNT(argv) != WL_NATOE_SUBCMD_CONFIG_IPS_ARGC) {
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.sta_ip)) {
+ printf("%s: Invalid STA IP addr provided\n", __FUNCTION__);
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.sta_netmask)) {
+ printf("%s: Invalid STA netmask addr provided\n", __FUNCTION__);
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
+ printf("%s: Invalid STA router IP addr provided\n", __FUNCTION__);
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
+ printf("%s: Invalid STA DNS IP addr provided\n", __FUNCTION__);
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.ap_ip)) {
+ printf("%s: Invalid AP IP addr provided\n", __FUNCTION__);
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (!wl_atoip(*argv++, (struct ipv4_addr *)&config_ips.ap_netmask)) {
+ printf("%s: Invalid AP netmask addr provided\n", __FUNCTION__);
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ /* max data we can write, it will be decremented as we pack */
+ buflen = WL_NATOE_IOC_BUFSZ;
+ buflen_at_start = buflen;
+
+ res = bcm_pack_xtlv_entry((uint8 **)&pxtlv,
+ &buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
+ (uint8 *)&config_ips, BCM_XTLV_OPTION_ALIGN32);
+
+ if (res != BCME_OK) {
+ goto exit;
+ }
+
+ /* adjust iocsz to the end of last data record */
+ natoe_ioc->len = (buflen_at_start - buflen);
+ iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
+ res = wlu_var_setbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz);
+ }
+
+exit:
+ free(natoe_ioc);
+ return res;
+}
+
+static int
+wl_natoe_subcmd_config_ports(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv)
+{
+ int res = BCME_USAGE_ERROR;
+ wl_natoe_ports_config_t ports_config;
+ wl_natoe_ioc_t *natoe_ioc = NULL;
+ uint16 buflen, buflen_at_start;
+ uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
+ bcm_xtlv_t *pxtlv = NULL;
+
+ /* alloc mem for ioctl headr + tlv data */
+ natoe_ioc = calloc(1, iocsz);
+ if (natoe_ioc == NULL) {
+ return BCME_NOMEM;
+ }
+
+ /* make up natoe cmd ioctl header */
+ natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
+ natoe_ioc->id = htod16(cmd->id);
+ natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
+ pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
+
+ if (*argv == NULL) {
+ iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
+ res = wl_natoe_get_ioctl(wl, natoe_ioc, iocsz);
+ } else {
+ memset(&ports_config, 0, sizeof(ports_config));
+
+ if (ARGCNT(argv) != WL_NATOE_SUBCMD_CONFIG_PORTS_ARGC) {
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ ports_config.start_port_num = htod16(strtoul(*argv++, NULL, 0));
+ ports_config.no_of_ports = htod16(strtoul(*argv++, NULL, 0));
+
+ if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
+ WL_NATOE_MAX_PORT_NUM) {
+ res = BCME_BADOPTION;
+ goto exit;
+ }
+ /* max data we can write, it will be decremented as we pack */
+ buflen = WL_NATOE_IOC_BUFSZ;
+ buflen_at_start = buflen;
+
+ res = bcm_pack_xtlv_entry((uint8 **)&pxtlv,
+ &buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
+ (uint8 *)&ports_config, BCM_XTLV_OPTION_ALIGN32);
+
+ if (res != BCME_OK) {
+ goto exit;
+ }
+
+ /* adjust iocsz to the end of last data record */
+ natoe_ioc->len = (buflen_at_start - buflen);
+ iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
+ res = wlu_var_setbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz);
+ }
+
+exit:
+ free(natoe_ioc);
+ return res;
+}
+
+static int
+wl_natoe_subcmd_dbg_stats(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv)
+{
+ int res = BCME_USAGE_ERROR;
+ wl_natoe_ioc_t *natoe_ioc = NULL;
+ uint16 buflen, buflen_at_start;
+ uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
+ bcm_xtlv_t *pxtlv = NULL;
+
+ /* alloc mem for ioctl headr + tlv data */
+ natoe_ioc = calloc(1, iocsz);
+ if (natoe_ioc == NULL) {
+ return BCME_NOMEM;
+ }
+
+ /* make up natoe cmd ioctl header */
+ natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
+ natoe_ioc->id = htod16(cmd->id);
+ natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
+ pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
+
+ if (*argv == NULL) {
+ iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
+ res = wl_natoe_get_stats(wl, natoe_ioc, iocsz);
+ } else {
+ uint8 val;
+
+ if (ARGCNT(argv) != WL_NATOE_SUBCMD_DBG_STATS_ARGC) {
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ val = atoi(*argv);
+ buflen = WL_NATOE_DBG_STATS_BUFSZ;
+ /* save buflen at start */
+ buflen_at_start = buflen;
+
+ /* we'll adjust final ioc size at the end */
+ res = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_DBG_STATS,
+ sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
+
+ if (res != BCME_OK) {
+ goto exit;
+ }
+
+ /* adjust iocsz to the end of last data record */
+ natoe_ioc->len = (buflen_at_start - buflen);
+ iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
+
+ res = wlu_var_setbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz);
+ }
+
+exit:
+ free(natoe_ioc);
+ return res;
+}
+
+static int
+wl_natoe_subcmd_tbl_cnt(void *wl, const wl_natoe_sub_cmd_t *cmd, char **argv)
+{
+ int res = BCME_OK;
+ wl_natoe_ioc_t *natoe_ioc;
+ uint16 buflen, buflen_at_start;
+ uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
+ bcm_xtlv_t *pxtlv = NULL;
+
+ /* alloc mem for ioctl headr + tlv data */
+ natoe_ioc = calloc(1, iocsz);
+ if (natoe_ioc == NULL) {
+ return BCME_NOMEM;
+ }
+
+ /* make up natoe cmd ioctl header */
+ natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
+ natoe_ioc->id = htod16(cmd->id);
+ natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
+ pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
+
+ if(*argv == NULL) { /* get */
+ iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
+ res = wl_natoe_get_ioctl(wl, natoe_ioc, iocsz);
+
+ } else { /* set */
+ /* max tlv data we can write, it will be decremented as we pack */
+ uint32 val;
+
+ if (ARGCNT(argv) != WL_NATOE_SUBCMD_TBL_CNT_ARGC) {
+ res = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ val = atoi(*argv);
+ buflen = WL_NATOE_IOC_BUFSZ;
+ /* save buflen at start */
+ buflen_at_start = buflen;
+
+ /* we'll adjust final ioc size at the end */
+ res = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
+ sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
+
+ if (res != BCME_OK) {
+ goto exit;
+ }
+
+ /* adjust iocsz to the end of last data record */
+ natoe_ioc->len = (buflen_at_start - buflen);
+ iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
+
+ res = wlu_var_setbuf(wl, WL_NATOE_CMD, natoe_ioc, iocsz);
+ }
+exit:
+
+ free(natoe_ioc);
+ return res;
+}
+
+static int
+wl_natoe_control(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = BCME_USAGE_ERROR;
+ char *natoe_query[2] = {"enable", NULL};
+ char *natoe_en[3] = {"enable", "1", NULL};
+ char *natoe_dis[3] = {"enable", "0", NULL};
+ const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
+ /* Skip the command name */
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+ /* skip to cmd name after "natoe" */
+ if (!*argv) {
+ /* query natoe "enable" state */
+ argv = natoe_query;
+ } else if (*argv[0] == '1') {
+ argv = natoe_en;
+ } else if (*argv[0] == '0') {
+ argv = natoe_dis;
+ } else if (!strcmp(*argv, "-h") || !strcmp(*argv, "help")) {
+ /* help , or -h* */
+ return ret;
+ }
+
+ while (natoe_cmd->name != NULL) {
+ if (strcmp(natoe_cmd->name, *argv) == 0) {
+ /* dispacth cmd to appropriate handler */
+ if (natoe_cmd->handler) {
+ ret = natoe_cmd->handler(wl, natoe_cmd, ++argv);
+ }
+ return ret;
+ }
+ natoe_cmd++;
+ }
+ return ret;
+}
diff --git a/wl/src/wl/exe/wluc_ndoe.c b/wl/src/wl/exe/wluc_ndoe.c
new file mode 100644
index 0000000..021f27e
--- /dev/null
+++ b/wl/src/wl/exe/wluc_ndoe.c
@@ -0,0 +1,368 @@
+/*
+ * wl ndoe command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_ndoe.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_ndstatus, wl_solicitipv6, wl_remoteipv6;
+static cmd_func_t wl_nd_hostip_extended;
+
+static cmd_t wl_ndoe_cmds[] = {
+ { "nd_hostip", wl_nd_hostip_extended, WLC_GET_VAR, WLC_SET_VAR,
+ "Add/delete a local host Ipv6 address or get list of address\n"
+ "Usage: wl nd_hostip <ver|add|del|list> [addr] [-t <uc|ac>]\n"
+ " wl nd_hostip ver : get iovar version supported\n"
+ " wl nd_hostip add <addr> : add unicast host ip addr\n"
+ " wl nd_hostip add <addr> -t ac : add anycast host ip addr\n"
+ " wl nd_hostip del <addr> : delete specified addr\n"
+ " wl nd_hostip del -t uc : delete all unicast addr\n"
+ " wl nd_hostip del -t ac : delete all anycast addr\n"
+ " wl nd_hostip del : delete all addr\n"
+ " wl nd_hostip list : get list of all addr\n"
+ " * wl nd_hostip <addr> : add unicast host ip address\n"
+ " * wl nd_hostip : display list of address\n"},
+ { "nd_solicitip", wl_solicitipv6, WLC_GET_VAR, WLC_SET_VAR,
+ "Add a local host solicit ipv6 address or display them"},
+ { "nd_remoteip", wl_remoteipv6, WLC_GET_VAR, WLC_SET_VAR,
+ "Add a local remote ipv6 address or display them"},
+ { "nd_status", wl_ndstatus, WLC_GET_VAR, -1,
+ "Displays Neighbor Discovery Status"},
+ { "nd_hostip_clear", wl_var_void, -1, WLC_SET_VAR,
+ "Clear all host-ip addresses"},
+ { "nd_macaddr", wl_iov_mac, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/set the MAC address for offload" },
+ { "nd_status_clear", wl_var_void, -1, WLC_SET_VAR,
+ "Clear neighbor discovery status"},
+ { "nd_unsolicited_na_filter", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/disable Unsolicited Neighbor Advertisement Filtering"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_ndoe_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register ndoe commands */
+ wl_module_cmds_register(wl_ndoe_cmds);
+}
+
+static int
+wl_print_ipv6_addr(struct ipv6_addr *addr)
+{
+ if (addr) {
+ uint i;
+ uint16 *ip_addr = (uint16*)addr;
+
+ /* IPv6 is represented as 8 groups of 4 hex digit separated by : */
+ for (i = 0; i < (IPV6_ADDR_LEN/sizeof(uint16)); i++) {
+ printf("%x", ntoh16(ip_addr[i]));
+ if (i < 7)
+ printf(":");
+ }
+ return 0;
+ } else {
+ printf("null");
+ return -1;
+ }
+}
+
+static int
+wl_nd_hostip_extended(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ wl_nd_hostip_t hostip_op;
+ char **saved_argv = argv;
+
+ if (!*++argv) {
+ /* Get for nd_hostip iovar old syntax */
+ return wl_hostipv6(wl, cmd, saved_argv);
+ } else if (!stricmp(*argv, "ver")) {
+ wl_nd_hostip_t *nd_hostip_ver = NULL;
+
+ /* Get iovar version */
+ hostip_op.version = htod16(WL_ND_HOSTIP_IOV_VER);
+ hostip_op.op_type = htod16(WL_ND_HOSTIP_OP_VER);
+ hostip_op.length = htod32(WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16));
+ hostip_op.u.version = 0;
+
+ ret = wlu_var_getbuf(wl, cmd->name, &hostip_op,
+ WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16), (void **)&nd_hostip_ver);
+
+ if (ret < 0) {
+ return BCME_UNSUPPORTED;
+ }
+
+ nd_hostip_ver->version = dtoh16(nd_hostip_ver->version);
+ nd_hostip_ver->op_type = dtoh16(nd_hostip_ver->op_type);
+ nd_hostip_ver->length = dtoh32(nd_hostip_ver->length);
+ nd_hostip_ver->u.version = dtoh16(nd_hostip_ver->u.version);
+
+ if ((nd_hostip_ver->version == WL_ND_HOSTIP_IOV_VER) &&
+ (nd_hostip_ver->op_type == WL_ND_HOSTIP_OP_VER) &&
+ (nd_hostip_ver->length == WL_ND_HOSTIP_FIXED_LEN +
+ sizeof(uint16))) {
+ printf("nd_hostip ver %d\n", nd_hostip_ver->u.version);
+ } else {
+ printf("nd_hostip ver 0\n");
+ return BCME_UNSUPPORTED;
+ }
+ } else if (!stricmp(*argv, "add")) {
+ /* Add host ip */
+ hostip_op.version = htod16(WL_ND_HOSTIP_IOV_VER);
+ hostip_op.op_type = htod16(WL_ND_HOSTIP_OP_ADD);
+ hostip_op.length = htod32(WL_ND_HOSTIP_WITH_ADDR_LEN);
+
+ if (*++argv) {
+ /* address */
+ if (!wl_atoipv6(*argv, &hostip_op.u.host_ip.ip_addr)) {
+ /* Invalid address */
+ return BCME_USAGE_ERROR;
+ }
+
+ /* type of address (unicast default) */
+ hostip_op.u.host_ip.type = WL_ND_IPV6_ADDR_TYPE_UNICAST;
+
+ if (*++argv && !stricmp(*argv, "-t")) {
+ if (*++argv && !stricmp(*argv, "ac")) {
+ /* anycast address */
+ hostip_op.u.host_ip.type = WL_ND_IPV6_ADDR_TYPE_ANYCAST;
+ }
+ }
+
+ ret = wlu_var_setbuf(wl, cmd->name, &hostip_op,
+ WL_ND_HOSTIP_WITH_ADDR_LEN);
+ } else {
+ /* no address given */
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "del")) {
+ /* Delete host ip */
+ hostip_op.version = htod16(WL_ND_HOSTIP_IOV_VER);
+
+ if (!*++argv) {
+ /* delete all address */
+ hostip_op.op_type = htod16(WL_ND_HOSTIP_OP_DEL_ALL);
+ hostip_op.length = htod32(WL_ND_HOSTIP_FIXED_LEN);
+ ret = wlu_var_setbuf(wl, cmd->name, &hostip_op, WL_ND_HOSTIP_FIXED_LEN);
+ } else if (!stricmp(*argv, "-t")) {
+ if (*++argv) {
+ if (!stricmp(*argv, "uc")) {
+ /* delete unicast address */
+ hostip_op.op_type = htod16(WL_ND_HOSTIP_OP_DEL_UC);
+ hostip_op.length = htod32(WL_ND_HOSTIP_FIXED_LEN);
+ } else if (!stricmp(*argv, "ac")) {
+ /* delete anycast address */
+ hostip_op.op_type = htod16(WL_ND_HOSTIP_OP_DEL_AC);
+ hostip_op.length = htod32(WL_ND_HOSTIP_FIXED_LEN);
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+ ret = wlu_var_setbuf(wl, cmd->name, &hostip_op,
+ WL_ND_HOSTIP_FIXED_LEN);
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+ } else if (wl_atoipv6(*argv, &hostip_op.u.host_ip.ip_addr)) {
+ /* delete specified address */
+ hostip_op.op_type = htod16(WL_ND_HOSTIP_OP_DEL);
+ hostip_op.length = htod32(WL_ND_HOSTIP_WITH_ADDR_LEN);
+ hostip_op.u.host_ip.type = 0; /* don't care */
+ ret = wlu_var_setbuf(wl, cmd->name, &hostip_op,
+ WL_ND_HOSTIP_WITH_ADDR_LEN);
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ } else if (!stricmp(*argv, "list")) {
+ /* get list of address */
+ wl_nd_host_ip_list_t *list = NULL;
+
+ hostip_op.version = htod16(WL_ND_HOSTIP_IOV_VER);
+ hostip_op.op_type = htod16(WL_ND_HOSTIP_OP_LIST);
+ hostip_op.length = htod32(WL_ND_HOSTIP_FIXED_LEN);
+
+ ret = wlu_var_getbuf(wl, cmd->name, &hostip_op,
+ WL_ND_HOSTIP_FIXED_LEN, (void **)&list);
+ if (!ret) {
+ uint i;
+ list->count = dtoh32(list->count);
+ for (i = 0; i < list->count; i++) {
+ uint32 addr_type = list->host_ip[i].type;
+ wl_print_ipv6_addr(&list->host_ip[i].ip_addr);
+ if (addr_type == WL_ND_IPV6_ADDR_TYPE_UNICAST) {
+ printf(" unicast\r\n");
+ } else if (addr_type == WL_ND_IPV6_ADDR_TYPE_ANYCAST) {
+ printf(" anycast\r\n");
+ } else {
+ printf(" unknown type\n\n");
+ }
+ }
+ }
+ } else {
+ /* Set for nd_hostip iovar old syntax */
+ return wl_hostipv6(wl, cmd, saved_argv);
+ }
+
+ return ret;
+}
+
+static int
+wl_ndstatus(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ struct nd_ol_stats_t *nd_stats;
+
+ if (!*++argv) {
+ /* Get */
+ void *ptr = NULL;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ nd_stats = (struct nd_ol_stats_t *)ptr;
+
+ printf("host_ip_entries %d\r\n", nd_stats->host_ip_entries);
+ printf("host_ip_overflow %d\r\n", nd_stats->host_ip_overflow);
+ printf("peer_request %d\r\n", nd_stats->peer_request);
+ printf("peer_request_drop %d\r\n", nd_stats->peer_request_drop);
+ printf("peer_reply_drop %d\r\n", nd_stats->peer_reply_drop);
+ printf("peer_service %d\r\n", nd_stats->peer_service);
+ } else {
+ printf("Cannot set nd stats\n");
+ }
+
+ return 0;
+}
+
+/*
+ * If a solicit IP address is given, add it
+ * e.g. "wl nd_solicitip fe00:0:0:0:0:290:1fc0:18c0 ".
+ * If no address is given, dump all the addresses.
+ */
+static int
+wl_solicitipv6(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, i;
+ struct ipv6_addr ipa_set, *ipa_get, null_ipa;
+ uint16 *ip_addr;
+ if (!*++argv) {
+ /* Get */
+ void *ptr = NULL;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ ip_addr = (uint16*)ptr;
+ memset(null_ipa.addr, 0, IPV6_ADDR_LEN);
+ for (ipa_get = (struct ipv6_addr *)ptr;
+ memcmp(null_ipa.addr, ipa_get->addr, IPV6_ADDR_LEN) != 0;
+ ipa_get++) {
+ /* Print ipv6 Addr */
+ for (i = 0; i < 8; i++) {
+ printf("%x", ntoh16(ip_addr[i]));
+ if (i < 7)
+ printf(":");
+ }
+ printf("\r\n");
+
+ ip_addr += 8;
+ }
+ } else {
+ /* Add */
+ if (!wl_atoipv6(*argv, &ipa_set))
+ return BCME_USAGE_ERROR;
+
+ /* we add one ip-addr at a time */
+ return wlu_var_setbuf(wl, cmd->name, &ipa_set, IPV6_ADDR_LEN);
+ }
+ return ret;
+}
+
+/*
+ * If a remote IP address is given, add it
+ * e.g. "wl nd_remoteip fe00:0:0:0:0:290:1fc0:18c0 ".
+ * If no address is given, dump the addresses.
+ */
+static int
+wl_remoteipv6(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, i;
+ struct ipv6_addr ipa_set, *ipa_get, null_ipa;
+ uint16 *ip_addr;
+ if (!*++argv) {
+ /* Get */
+ void *ptr = NULL;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+
+ ip_addr = (uint16*)ptr;
+ memset(null_ipa.addr, 0, IPV6_ADDR_LEN);
+ for (ipa_get = (struct ipv6_addr *)ptr;
+ memcmp(null_ipa.addr, ipa_get->addr, IPV6_ADDR_LEN) != 0;
+ ipa_get++) {
+ /* Print ipv6 Addr */
+ for (i = 0; i < 8; i++) {
+ printf("%x", ntoh16(ip_addr[i]));
+ if (i < 7)
+ printf(":");
+ }
+ printf("\r\n");
+
+ ip_addr += 8;
+ }
+ } else {
+ /* Add */
+ if (!wl_atoipv6(*argv, &ipa_set))
+ return BCME_USAGE_ERROR;
+
+ /* we add one ip-addr at a time */
+ return wlu_var_setbuf(wl, cmd->name, &ipa_set, IPV6_ADDR_LEN);
+ }
+ return ret;
+}
diff --git a/wl/src/wl/exe/wluc_obss.c b/wl/src/wl/exe/wluc_obss.c
new file mode 100644
index 0000000..df23873
--- /dev/null
+++ b/wl/src/wl/exe/wluc_obss.c
@@ -0,0 +1,289 @@
+/*
+ * wl obss command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_obss.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_obss_scan, wl_obss_coex_action;
+
+static cmd_t wl_obss_cmds[] = {
+ { "obss_scan_params", wl_obss_scan, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get Overlapping BSS scan parameters\n"
+ "Usage: wl obss_scan a b c d e ...; where\n"
+ "\ta-Passive Dwell, {5-1000TU}, default = 100\n"
+ "\tb-Active Dwell, {10-1000TU}, default = 20\n"
+ "\tc-Width Trigger Scan Interval, {10-900sec}, default = 300\n"
+ "\td-Passive Total per Channel, {200-10000TU}, default = 200\n"
+ "\te-Active Total per Channel, {20-1000TU}, default = 20\n"
+ "\tf-Channel Transition Delay Factor, {5-100}, default = 5\n"
+ "\tg-Activity Threshold, {0-100%}, default = 25"},
+ { "obss_coex_action", wl_obss_coex_action, -1, WLC_SET_VAR,
+ "send OBSS 20/40 Coexistence Mangement Action Frame\n"
+ "\tUsage: wl obss_coex_action -i <1/0> -w <1/0> -c <channel list>\n"
+ "\t -i: 40MHz intolerate bit; -w: 20MHz width Req bit;\n"
+ "\t -c: channel list, 1 - 14\n"
+ "\t At least one option must be provided"
+ },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_obss_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register obss commands */
+ wl_module_cmds_register(wl_obss_cmds);
+}
+
+static int
+wl_obss_scan_params_range_chk(wl_obss_scan_arg_t *obss_scan_arg)
+{
+ if (obss_scan_arg->passive_dwell < 0)
+ obss_scan_arg->passive_dwell = WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT;
+ else if (obss_scan_arg->passive_dwell < WLC_OBSS_SCAN_PASSIVE_DWELL_MIN ||
+ obss_scan_arg->passive_dwell > WLC_OBSS_SCAN_PASSIVE_DWELL_MAX) {
+ printf("passive dwell not in range %d\n", obss_scan_arg->passive_dwell);
+ return -1;
+ }
+
+ if (obss_scan_arg->active_dwell < 0)
+ obss_scan_arg->active_dwell = WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT;
+ else if (obss_scan_arg->active_dwell < WLC_OBSS_SCAN_ACTIVE_DWELL_MIN ||
+ obss_scan_arg->active_dwell > WLC_OBSS_SCAN_ACTIVE_DWELL_MAX) {
+ printf("active dwell not in range %d\n", obss_scan_arg->active_dwell);
+ return -1;
+ }
+
+ if (obss_scan_arg->bss_widthscan_interval < 0)
+ obss_scan_arg->bss_widthscan_interval =
+ WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT;
+ else if (obss_scan_arg->bss_widthscan_interval < WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN ||
+ obss_scan_arg->bss_widthscan_interval > WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX) {
+ printf("Width Trigger Scan Interval not in range %d\n",
+ obss_scan_arg->bss_widthscan_interval);
+ return -1;
+ }
+
+ if (obss_scan_arg->chanwidth_transition_delay < 0)
+ obss_scan_arg->chanwidth_transition_delay =
+ WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT;
+ else if ((obss_scan_arg->chanwidth_transition_delay <
+ WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN) ||
+ (obss_scan_arg->chanwidth_transition_delay >
+ WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX)) {
+ printf("Width Channel Transition Delay Factor not in range %d\n",
+ obss_scan_arg->chanwidth_transition_delay);
+ return -1;
+ }
+
+ if (obss_scan_arg->passive_total < 0)
+ obss_scan_arg->passive_total = WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT;
+ else if (obss_scan_arg->passive_total < WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN ||
+ obss_scan_arg->passive_total > WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX) {
+ printf("Passive Total per Channel not in range %d\n", obss_scan_arg->passive_total);
+ return -1;
+ }
+
+ if (obss_scan_arg->active_total < 0)
+ obss_scan_arg->active_total = WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT;
+ if (obss_scan_arg->active_total < WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN ||
+ obss_scan_arg->active_total > WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX) {
+ printf("Active Total per Channel not in range %d\n", obss_scan_arg->active_total);
+ return -1;
+ }
+
+ if (obss_scan_arg->activity_threshold < 0)
+ obss_scan_arg->activity_threshold = WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT;
+ else if (obss_scan_arg->activity_threshold < WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN ||
+ obss_scan_arg->activity_threshold > WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX) {
+ printf("Activity Threshold not in range %d\n", obss_scan_arg->activity_threshold);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+wl_obss_scan(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1;
+ wl_obss_scan_arg_t obss_scan_arg;
+ char *endptr = NULL;
+ uint buflen;
+ uint argc = 0;
+
+ if (!*++argv) {
+ void *ptr = NULL;
+ wl_obss_scan_arg_t *obss_scan_param;
+
+ err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr);
+ if (err < 0)
+ return err;
+
+ obss_scan_param = (wl_obss_scan_arg_t *)ptr;
+ printf("%d %d %d %d %d %d %d\n",
+ dtoh16(obss_scan_param->passive_dwell),
+ dtoh16(obss_scan_param->active_dwell),
+ dtoh16(obss_scan_param->bss_widthscan_interval),
+ dtoh16(obss_scan_param->passive_total),
+ dtoh16(obss_scan_param->active_total),
+ dtoh16(obss_scan_param->chanwidth_transition_delay),
+ dtoh16(obss_scan_param->activity_threshold));
+ return 0;
+ }
+
+ /* arg count */
+ while (argv[argc])
+ argc++;
+
+ buflen = WL_OBSS_SCAN_PARAM_LEN;
+ memset((uint8 *)&obss_scan_arg, 0, buflen);
+
+ /* required argments */
+ if (argc < WL_MIN_NUM_OBSS_SCAN_ARG) {
+ fprintf(stderr, "Too few/many arguments (require %d, got %d)\n",
+ WL_MIN_NUM_OBSS_SCAN_ARG, argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ obss_scan_arg.passive_dwell = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ obss_scan_arg.active_dwell = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ obss_scan_arg.bss_widthscan_interval = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ obss_scan_arg.passive_total = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ obss_scan_arg.active_total = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ obss_scan_arg.chanwidth_transition_delay = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ obss_scan_arg.activity_threshold = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ if (wl_obss_scan_params_range_chk(&obss_scan_arg))
+ return BCME_RANGE;
+
+ err = wlu_var_setbuf(wl, cmd->name, &obss_scan_arg, buflen);
+
+ return err;
+}
+
+static int
+wl_obss_coex_action(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ char var[256];
+ wl_action_obss_coex_req_t *req = (wl_action_obss_coex_req_t *)var;
+ int val;
+ int num = 0;
+ uint8 options = 0;
+
+ argv++;
+ memset(&var, 0, sizeof(wl_action_obss_coex_req_t));
+ while (*argv) {
+ if (!strncmp(*argv, "-i", 2) && ((options & 0x1) != 0x1)) {
+ argv++;
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+ val = atoi(*argv);
+ if ((val != 0) && (val != 1))
+ return BCME_BADARG;
+ req->info |= val ? WL_COEX_40MHZ_INTOLERANT : 0;
+ options |= 0x1;
+ }
+ else if (!strncmp(*argv, "-w", 2) && ((options & 0x2) != 0x2)) {
+ argv++;
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+ val = atoi(*argv);
+ if ((val != 0) && (val != 1))
+ return BCME_BADARG;
+ req->info |= val ? WL_COEX_WIDTH20 : 0;
+ options |= 0x2;
+ }
+ else if (!strncmp(*argv, "-c", 2) && ((options & 0x4) != 0x4)) {
+ argv++;
+ while (*argv) {
+ if (isdigit((unsigned char)(**argv))) {
+ val = htod32(strtoul(*argv, NULL, 0));
+ if ((val == 0) || (val > 14)) {
+ printf("Invalid channel %d\n", val);
+ return BCME_BADARG;
+ }
+ req->ch_list[num] = (uint8)val;
+ num++;
+ argv++;
+ if (num > 14) {
+ printf("Too many channels (max 14)\n");
+ return BCME_BADARG;
+ }
+ } else
+ break;
+ }
+ if (!num) {
+ printf("With option '-c' specified, a channel list is required\n");
+ return BCME_BADARG;
+ }
+ req->num = num;
+ options |= 0x4;
+ continue;
+ }
+ else
+ return BCME_USAGE_ERROR;
+ argv++;
+ }
+ if (!options)
+ return BCME_BADARG;
+ err = wlu_var_setbuf(wl, cmd->name, &var, (sizeof(wl_action_obss_coex_req_t) +
+ (req->num ? (req->num - 1) * sizeof(uint8) : 0)));
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_offloads.c b/wl/src/wl/exe/wluc_offloads.c
new file mode 100644
index 0000000..1a92298
--- /dev/null
+++ b/wl/src/wl/exe/wluc_offloads.c
@@ -0,0 +1,242 @@
+/*
+ * wl offloads command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_offloads.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wlu_offloads_stats;
+static cmd_func_t wl_ol_notify_bcn_ie;
+
+static cmd_t wl_offloads_cmds[] = {
+ { "ol_stats", wlu_offloads_stats, WLC_GET_VAR, -1,
+ "Give suboption \"list\" to list various suboptions" },
+ { "ol_eventlog", wlu_offloads_stats, WLC_GET_VAR, -1,
+ "Give suboption \"list\" to list various suboptions" },
+ { "ol_cons", wlu_offloads_stats, WLC_GET_VAR, WLC_SET_VAR,
+ "Display the ARM console or issue a command to the ARM console\n"
+ " Usage: ol_cons [<cmd>]\n"
+ "\t\"?\" - Display the list of active console commands"
+ },
+ { "ol_wowl_cons", wlu_offloads_stats, WLC_GET_VAR, -1,
+ "Give suboption \"list\" to list various suboptions" },
+ { "ol_clr", wlu_offloads_stats, WLC_GET_VAR, -1,
+ "Give suboption \"list\" to list various suboptions" },
+ { "ol_notify_bcn_ie", wl_ol_notify_bcn_ie, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/Disable IE ID notification"},
+ { "ol_arp_hostip", wl_hostip, WLC_GET_VAR, WLC_SET_VAR,
+ "Add a host-ip address or display them"},
+ { "ol_nd_hostip", wl_hostipv6, WLC_GET_VAR, WLC_SET_VAR,
+ "Add a local host-ipv6 address or display them"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_offloads_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register offloads commands */
+ wl_module_cmds_register(wl_offloads_cmds);
+}
+
+static int
+wlu_offloads_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ char *dump_buf;
+ int bufsz = WL_DUMP_BUF_LEN;
+ bool cons_cmd = FALSE;
+
+ if (cmd->get < 0)
+ return -1;
+
+ if (!strcmp(cmd->name, "ol_clr"))
+ {
+ ret = wlu_iovar_get(wl, cmd->name, NULL, 0);
+ return ret;
+ }
+
+ if (!strcmp(cmd->name, "ol_cons")) {
+ /* Check for command */
+ if (*(argv + 1)) {
+ argv++;
+ cons_cmd = TRUE;
+ bufsz = CMDLINESZ;
+ }
+ }
+
+ dump_buf = malloc(bufsz);
+ if (dump_buf == NULL) {
+ fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", bufsz);
+ return -1;
+ }
+ memset(dump_buf, 0, bufsz);
+
+ while (*argv) {
+ /* add space delimiter if this is not the first section name */
+ if (dump_buf[0] != '\0')
+ strcat(dump_buf, " ");
+
+ strcat(dump_buf, *argv);
+
+ argv++;
+ }
+
+ if (cons_cmd) {
+ ret = wlu_iovar_set(wl, cmd->name, dump_buf, bufsz);
+ } else {
+ ret = wlu_iovar_get(wl, cmd->name, dump_buf, bufsz);
+ if (!ret)
+ fputs(dump_buf, stdout);
+ }
+
+ free(dump_buf);
+
+ return ret;
+}
+
+static int
+wl_ol_notify_bcn_ie(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = -1;
+ void *ptr = NULL;
+
+#define VNDR_IE_ID (221)
+#define OLMSG_BCN_MAX_IE (222)
+
+ struct beacon_ie_notify_cmd {
+ uint32 id;
+ uint32 enable;
+ struct ipv4_addr vndriemask;
+ } beacon_notification_cmd;
+
+ memset(&beacon_notification_cmd, 0, sizeof(beacon_notification_cmd));
+
+ ++argv; /* skip the command iteself */
+
+ if (!*argv) {
+ /* Get Everything */
+ beacon_notification_cmd.id = -1; /* -1 indicates NONE */
+ ret = wlu_var_getbuf(wl, cmd->name, &beacon_notification_cmd,
+ sizeof(beacon_notification_cmd), &ptr);
+ } else {
+ if (stricmp(*argv, "enable") == 0) { /* Enable Global flag */
+ beacon_notification_cmd.id = -1; /* -1 indicates NONE */
+ beacon_notification_cmd.enable = 1;
+ return wlu_var_setbuf(wl, cmd->name, &beacon_notification_cmd,
+ sizeof(beacon_notification_cmd));
+ } else if (stricmp(*argv, "disable") == 0) { /* Disable Global flag */
+ beacon_notification_cmd.id = -1; /* -1 indicates NONE */
+ beacon_notification_cmd.enable = 0;
+ return wlu_var_setbuf(wl, cmd->name, &beacon_notification_cmd,
+ sizeof(beacon_notification_cmd));
+ } else { /* Get/Set Enable/Disable some ID */
+
+ beacon_notification_cmd.id = (uint8) atoi(*argv);
+
+ if (beacon_notification_cmd.id == VNDR_IE_ID) {
+ /* Get VNDR OUI */
+ ++argv;
+ if (*argv) { /* Get a specific Vendor IE */
+ if (!wl_atoip(*argv, &beacon_notification_cmd.vndriemask)) {
+ return -1;
+ }
+ ++argv;
+ /* Get enable/disable flag */
+ if (*argv) { /* Set a specific Vendor ie */
+ if (stricmp(*argv, "enable") == 0)
+ beacon_notification_cmd.enable = 1;
+ else if (stricmp(*argv, "disable") == 0)
+ beacon_notification_cmd.enable = 0;
+ else
+ return -1;
+
+ return wlu_var_setbuf(wl, cmd->name,
+ &beacon_notification_cmd,
+ sizeof(beacon_notification_cmd));
+ } else {
+ ret = wlu_var_getbuf(wl, cmd->name,
+ &beacon_notification_cmd,
+ sizeof(beacon_notification_cmd),
+ &ptr);
+ }
+ } else { /* Get ALL Vendor IE */
+ ret = wlu_var_getbuf(wl, cmd->name,
+ &beacon_notification_cmd,
+ sizeof(beacon_notification_cmd),
+ &ptr);
+ }
+ } else {
+ if (beacon_notification_cmd.id > OLMSG_BCN_MAX_IE) {
+ return -1;
+ }
+ /* Get enable/disable flag */
+ ++argv;
+ if(*argv) { /* Set IE ID */
+ if (stricmp(*argv, "enable") == 0)
+ beacon_notification_cmd.enable = 1;
+ else if (stricmp(*argv, "disable") == 0)
+ beacon_notification_cmd.enable = 0;
+ else
+ return -1;
+ return wlu_var_setbuf(wl, cmd->name,
+ &beacon_notification_cmd,
+ sizeof(beacon_notification_cmd));
+ } else { /* Get IE ID */
+ ret = wlu_var_getbuf(wl, cmd->name,
+ &beacon_notification_cmd,
+ sizeof(beacon_notification_cmd),
+ &ptr);
+ }
+ }
+ }
+ }
+ if ((ret >= 0) && (ptr != NULL)) {
+ printf("%s\n", (char *)ptr); /* Print Everything */
+ }
+ return ret;
+}
diff --git a/wl/src/wl/exe/wluc_ota_test.c b/wl/src/wl/exe/wluc_ota_test.c
new file mode 100644
index 0000000..772af42
--- /dev/null
+++ b/wl/src/wl/exe/wluc_ota_test.c
@@ -0,0 +1,903 @@
+/*
+ * wl ota test command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_ota_test.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_ota_loadtest, wl_otatest_status, wl_load_cmd_stream;
+static cmd_func_t wl_ota_teststop, wl_otatest_rssi;
+
+static cmd_t wl_ota_cmds[] = {
+ { "ota_teststop", wl_ota_teststop, -1, WLC_SET_VAR,
+ "\tUsage: ota_teststop"
+ },
+ { "ota_loadtest", wl_ota_loadtest, -1, WLC_SET_VAR,
+ "\tUsage: ota_loadtest [filename] \n"
+ "\t\tpicks up ota_test.txt if file is not given"
+ },
+ { "ota_stream", wl_load_cmd_stream, -1, WLC_SET_VAR,
+ "\tUsage: wl ota_stream start : to start the test\n"
+ "\twl ota_stream ota_sync \n"
+ "\twl ota_stream test_setup synchtimeoout(seconds) synchbreak/loop synchmac txmac rxmac \n"
+ "\twl ota_stream ota_tx chan bandwidth contrlchan rates stf txant rxant tx_ifs tx_len"
+ "num_pkt pwrctrl start:delta:end \n"
+ "\twl ota_stream ota_rx chan bandwidth contrlchan -1 stf txant rxant tx_ifs"
+ "tx_len num_pkt \n"
+ "\twl ota_stream stop : to stop the test"
+ },
+ { "ota_teststatus", wl_otatest_status, WLC_GET_VAR, -1,
+ "\tUsage: otatest_status"
+ "\t\tDisplays current running test details"
+ "\totatest_status n "
+ "\t\tdisplays test arguments for nth line"
+ },
+ { "ota_rssi", wl_otatest_rssi, WLC_GET_VAR, -1,
+ "\tUsage: wl ota_rssi"
+ "\t\tDisplays RSSI values for each ota_rx test"
+ },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_ota_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register ota test commands */
+ wl_module_cmds_register(wl_ota_cmds);
+}
+
+#define WL_OTA_STRING_MAX_LEN 100
+#define WL_OTA_CMDSTREAM_MAX_LEN 200
+
+/* test_setup cmd argument ordering */
+enum {
+ WL_OTA_SYNC_TIMEOUT = 1, /* Timeout in seconds */
+ WL_OTA_SYNCFAIL_ACTION, /* Fail actio -1/0/1 */
+ WL_OTA_SYNC_MAC, /* Mac address for sync */
+ WL_OTA_TX_MAC, /* Mac address for tx test */
+ WL_OTA_RX_MAC, /* Mac address for rx test */
+ WL_OTA_LOOP_TEST /* Put test into loop mode */
+};
+
+/* ota_tx / ota_rx format ordering */
+enum {
+ WL_OTA_CUR_TEST, /* ota_tx or ota_rx */
+ WL_OTA_CHAN, /* cur channel */
+ WL_OTA_BW, /* cur bandwidth */
+ WL_OTA_CONTROL_BAND, /* cur control band */
+ WL_OTA_RATE, /* cur rate */
+ WL_OTA_STF_MODE, /* cur stf mode */
+ WL_OTA_TXANT, /* tx ant to be used */
+ WL_OTA_RXANT, /* rx ant to be used */
+ WL_OTA_TX_IFS, /* ifs */
+ WL_OTA_TX_PKT_LEN, /* pkt length */
+ WL_OTA_TX_NUM_PKT, /* num of packets */
+ WL_OTA_PWR_CTRL_ON, /* power control on/off */
+ WL_OTA_PWR_SWEEP, /* start:delta:stop */
+ WL_OTA_LDPC, /* Use LDPC Encoding */
+ WL_OTA_SGI /* Use Short Guard Interval */
+};
+/* Various error chcking options */
+enum {
+ WL_OTA_SYNCFAILACTION,
+ WL_OTA_CTRLBANDVALID,
+ WL_OTA_TXANTVALID,
+ WL_OTA_RXANTVALID,
+ WL_OTA_PWRCTRLVALID
+};
+/* Display init test seq */
+void
+wl_ota_display_test_init_info(wl_ota_test_status_t *init_info)
+{
+ printf("Test Init Summary\n");
+ printf("----------------------------------------------------------\n");
+ printf("Toatl Number of test req %d\n\n", init_info->test_cnt);
+ printf("Sync timeout %d synch fail action: %d \n", init_info->sync_timeout,
+ init_info->sync_fail_action);
+ printf("Sync Mac address : \t");
+ printf("%s\n", wl_ether_etoa(&(init_info->sync_mac)));
+ printf("Tx Mac address : \t");
+ printf("%s\n", wl_ether_etoa(&(init_info->tx_mac)));
+ printf("Rx Mac address : \t");
+ printf("%s\n", wl_ether_etoa(&(init_info->rx_mac)));
+ printf("Test in Loop mode : %d \n", init_info->loop_test);
+ printf("\n\n\n");
+}
+static void
+wl_ota_display_rt_info(uint16 rate)
+{
+ if (rate & VHT_MCS_INUSE) {
+ printf("v");
+ printf("%d ", rate & OTA_RATE_MASK);
+ } else if (rate & HT_MCS_INUSE) {
+ printf("m");
+ printf("%d ", rate & OTA_RATE_MASK);
+ } else if (rate == 11) {
+ printf("5.5 ");
+ } else {
+ printf("%d ", (rate & OTA_RATE_MASK) / 2);
+ }
+}
+/* display nth tesr arg details */
+void
+wl_ota_display_test_option(wl_ota_test_args_t *test_arg, int16 cnt)
+{
+ uint8 i;
+ printf("Test cnt %d \n", cnt);
+ printf("-----------------------------------------------------------\n");
+ printf("Curr Test : %s\n", ((test_arg->cur_test == 0) ? "TX" : "RX"));
+ printf("Wait for sync enabled %d \n", test_arg->wait_for_sync);
+ printf("Channel : %d", test_arg->chan);
+ printf("\t Bandwidth : %s ", ((test_arg->bw == WL_OTA_TEST_BW_20MHZ) ? "20" :
+ ((test_arg->bw == WL_OTA_TEST_BW_40MHZ) ? "40" : "20 in 40")));
+ printf("\t Control Band : %c \n", test_arg->control_band);
+ printf("Rates : ");
+ for (i = 0; i < test_arg->rt_info.rate_cnt; i++)
+ wl_ota_display_rt_info(test_arg->rt_info.rate_val_mbps[i]);
+ printf("\nStf mode : %d \n", test_arg->stf_mode);
+ printf("Txant: %d(0x%2x) rxant: %d(0x%2x) \n",
+ test_arg->txant, test_arg->txant, test_arg->rxant, test_arg->rxant);
+ printf("Pkt eng Options : ifs %d len: %d num: %d \n", test_arg->pkteng.delay,
+ test_arg->pkteng.length, test_arg->pkteng.nframes);
+ printf("Tx power sweep options :\nPower control %d \nstart pwr: %d "
+ "delta: %d end pwr : %d \n", test_arg->pwr_info.pwr_ctrl_on,
+ test_arg->pwr_info.start_pwr, test_arg->pwr_info.delta_pwr,
+ test_arg->pwr_info.end_pwr);
+}
+/* do minimum string validations possible */
+/* Make stricter conditions in future */
+static int
+wl_ota_validate_string(uint8 arg, void* value)
+{
+ int ret = 0;
+ uint8 cores;
+
+ switch (arg) {
+ case WL_OTA_TXANTVALID:
+ case WL_OTA_RXANTVALID:
+ /* check if the 'txCore bitmask' of txant/rxant parameter is valid or not */
+ cores = WL_OTA_TEST_GET_CORE(*(uint8*) value);
+ if (cores > 7)
+ ret = -1;
+ break;
+ case WL_OTA_CTRLBANDVALID:
+ if ((strncmp((char *)value, "l", 1)) && (strncmp((char *)value, "u", 1)))
+ ret = -1;
+ break;
+ case WL_OTA_PWRCTRLVALID:
+ case WL_OTA_SYNCFAILACTION:
+ if ((*(int8 *)value < -2) || (*(int8 *)value > 1))
+ ret = -1;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+
+/* convert power info string to integer */
+/* start:delta:end */
+static int
+wl_ota_pwrinfo_parse(const char *tok_bkp, wl_ota_test_args_t *test_arg)
+{
+ char *endptr = NULL;
+ int ret = 0;
+
+ /* convert string to int */
+ /* Read start pwr */
+ test_arg->pwr_info.start_pwr = (int8)strtol(tok_bkp, &endptr, 10);
+ if (*endptr == ':') {
+ endptr++;
+ tok_bkp = endptr;
+ } else {
+ return -1;
+ }
+ /* read delta pwr */
+ test_arg->pwr_info.delta_pwr = (int8)strtol(tok_bkp, &endptr, 10);
+ if (*endptr == ':') {
+ endptr++;
+ tok_bkp = endptr;
+ } else {
+ return -1;
+ }
+ /* read end pwr */
+ test_arg->pwr_info.end_pwr = (int8)strtol(tok_bkp, &endptr, 10);
+
+ if ((*endptr != '\0') && (*endptr != '\n') && (*endptr != ' '))
+ ret = -1;
+
+ return ret;
+}
+
+/* parsing the test init seq line */
+static int
+wl_ota_parse_test_init(wl_ota_test_vector_t * init_info, char * tok, uint16 cnt)
+{
+ int ret = 0;
+ char * endptr = NULL;
+
+ switch (cnt) {
+ case WL_OTA_SYNC_TIMEOUT:
+ init_info->sync_timeout = (uint8)strtol(tok, &endptr, 10);
+ if (*endptr != '\0')
+ ret = -1;
+ break;
+ case WL_OTA_SYNCFAIL_ACTION:
+ init_info->sync_fail_action = (int8)strtol(tok, &endptr, 10);
+ if (*endptr != '\0') {
+ ret = -1;
+ break;
+ } else {
+ ret = wl_ota_validate_string(WL_OTA_SYNCFAILACTION,
+ &(init_info->sync_fail_action));
+ }
+ break;
+ case WL_OTA_SYNC_MAC:
+ if (!wl_ether_atoe(tok, &(init_info->sync_mac)))
+ ret = -1;
+ break;
+ case WL_OTA_TX_MAC:
+ if (!wl_ether_atoe(tok, &(init_info->tx_mac)))
+ ret = -1;
+ break;
+ case WL_OTA_RX_MAC:
+ if (!wl_ether_atoe(tok, &(init_info->rx_mac)))
+ ret = -1;
+ break;
+ case WL_OTA_LOOP_TEST:
+ init_info->loop_test = (int8)strtol(tok, &endptr, 10);
+
+ if ((*endptr != '\0') && (*endptr != '\n') && (*endptr != ' '))
+ ret = -1;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+/* parse test arguments */
+static int
+wl_ota_test_parse_test_option(wl_ota_test_args_t *test_arg, char * tok, uint16 cnt,
+ char rt_string[])
+{
+ char * endptr = NULL;
+ uint16 tok_len = 0;
+ int ret = 0;
+
+ if (test_arg->cur_test == WL_OTA_TEST_RX) {
+ switch (cnt) {
+ case WL_OTA_PWR_CTRL_ON:
+ case WL_OTA_PWR_SWEEP:
+ return 0;
+ break;
+ default:
+ break;
+ }
+ }
+ switch (cnt) {
+ case WL_OTA_CUR_TEST:
+ if (strncmp(tok, "ota_tx", 6) == 0)
+ test_arg->cur_test = WL_OTA_TEST_TX;
+ else if (strncmp(tok, "ota_rx", 6) == 0)
+ test_arg->cur_test = WL_OTA_TEST_RX;
+ else
+ ret = -1;
+ break;
+ case WL_OTA_CHAN:
+ test_arg->chan = (uint8)strtol(tok, &endptr, 10);
+ if (*endptr != '\0')
+ ret = -1;
+ break;
+ case WL_OTA_BW:
+ if (strncmp(tok, "20/40", 5) == 0) {
+ test_arg->bw = WL_OTA_TEST_BW_20MHZ;
+ } else if (strncmp(tok, "20", 2) == 0) {
+ test_arg->bw = WL_OTA_TEST_BW_20MHZ;
+ } else if (strncmp(tok, "40", 2) == 0) {
+ test_arg->bw = WL_OTA_TEST_BW_40MHZ;
+ } else if (strncmp(tok, "80", 2) == 0) {
+ test_arg->bw = WL_OTA_TEST_BW_80MHZ;
+ } else {
+ ret = -1;
+ }
+ break;
+ case WL_OTA_CONTROL_BAND:
+ test_arg->control_band = *tok;
+ ret = wl_ota_validate_string(WL_OTA_CTRLBANDVALID, tok);
+ break;
+ case WL_OTA_RATE:
+ tok_len = strlen(tok);
+ if (tok_len > WL_OTA_STRING_MAX_LEN) {
+ ret = -1;
+ goto fail;
+ }
+ strncpy(rt_string, tok, tok_len);
+ break;
+ case WL_OTA_STF_MODE:
+#ifndef D11AC_IOTYPES
+ if (strncmp(tok, "siso", 4) == 0)
+ test_arg->stf_mode = OTA_STF_SISO;
+ else if (strncmp(tok, "cdd", 3) == 0)
+ test_arg->stf_mode = OTA_STF_CDD;
+ else if (strncmp(tok, "stbc", 4) == 0)
+ test_arg->stf_mode = OTA_STF_STBC;
+ else if (strncmp(tok, "sdm", 3) == 0)
+ test_arg->stf_mode = OTA_STF_SDM;
+ else
+ ret = -1;
+#endif
+ break;
+ case WL_OTA_TXANT:
+ test_arg->txant = (uint8) strtol(tok, &endptr, 0);
+ if (*endptr != '\0') {
+ ret = -1;
+ goto fail;
+ }
+ ret = wl_ota_validate_string(WL_OTA_TXANTVALID, &test_arg->txant);
+ break;
+ case WL_OTA_RXANT:
+ test_arg->rxant = (uint8)strtol(tok, &endptr, 0);
+ if (*endptr != '\0') {
+ ret = -1;
+ goto fail;
+ }
+ ret = wl_ota_validate_string(WL_OTA_RXANTVALID, &test_arg->rxant);
+ break;
+ case WL_OTA_TX_IFS:
+ test_arg->pkteng.delay = (uint16)strtol(tok, &endptr, 10);
+ if (*endptr != '\0')
+ ret = -1;
+ break;
+ case WL_OTA_TX_PKT_LEN:
+ test_arg->pkteng.length = (uint16)strtol(tok, &endptr, 10);
+ if (*endptr != '\0')
+ ret = -1;
+ break;
+ case WL_OTA_TX_NUM_PKT:
+ test_arg->pkteng.nframes = (uint16)strtol(tok, &endptr, 10);
+ if ((*endptr != '\0') && (*endptr != '\n') && (*endptr != ' '))
+ ret = -1;
+ break;
+ case WL_OTA_PWR_CTRL_ON:
+ test_arg->pwr_info.pwr_ctrl_on = (int8)strtol(tok, &endptr, 10);
+ if (*endptr != '\0') {
+ ret = -1;
+ goto fail;
+ }
+ ret = wl_ota_validate_string(WL_OTA_PWRCTRLVALID,
+ &test_arg->pwr_info.pwr_ctrl_on);
+ break;
+ case WL_OTA_PWR_SWEEP:
+ ret = wl_ota_pwrinfo_parse(tok, test_arg);
+ break;
+ case WL_OTA_LDPC:
+ test_arg->ldpc = (uint8)strtol(tok, &endptr, 10);
+ if (*endptr != '\0')
+ ret = -1;
+ break;
+ case WL_OTA_SGI:
+ test_arg->sgi = (uint8)strtol(tok, &endptr, 10);
+ if (*endptr != '\0')
+ ret = -1;
+ break;
+ default:
+ break;
+ }
+
+fail:
+ return ret;
+}
+static int
+wl_ota_test_parse_rate_string(wl_ota_test_args_t *test_arg, char rt_string[100])
+{
+
+ uint8 cnt = 0;
+ char * tok = NULL;
+ char rate_st[5] = "\0";
+ uint16 int_val = 0;
+ uint16 tok_len = 0;
+ int ret = 0;
+ tok = strtok(rt_string, ",");
+
+ /* convert rate strings to int array */
+ while (tok != NULL) {
+ strncpy(rate_st, " ", 4);
+ /* skip rate parsing if its rx test case */
+ if (test_arg->cur_test == WL_OTA_TEST_RX) {
+ test_arg->rt_info.rate_val_mbps[cnt] = 0;
+ cnt = 1;
+ break;
+ }
+
+ /* Support a max of 30 rates */
+ if (cnt >= WL_OTA_TEST_MAX_NUM_RATE) {
+ ret = -1;
+ break;
+ }
+ tok_len = strlen(tok);
+ if (tok_len > 5) {
+ ret = -1;
+ break;
+ }
+ strncpy(rate_st, tok, tok_len);
+ if (strncmp(rate_st, "5.5", 3) == 0) {
+ int_val = 11;
+ } else {
+ if (rate_st[0] == 'm') {
+ rate_st[0] = ' ';
+ int_val = atoi(rate_st);
+ int_val |= HT_MCS_INUSE;
+ } else if (rate_st[0] == 'v') {
+ rate_st[0] = ' ';
+ int_val = atoi(rate_st);
+ int_val |= VHT_MCS_INUSE;
+ } else {
+ int_val = 2 * atoi(rate_st);
+ }
+ }
+ test_arg->rt_info.rate_val_mbps[cnt] = int_val;
+ tok = strtok(NULL, ",");
+ cnt++;
+ }
+ test_arg->rt_info.rate_cnt = cnt;
+ return ret;
+}
+static int
+wl_ota_test_parse_arg(char line[], wl_ota_test_vector_t *ota_test_vctr, uint16 *test_cnt,
+ uint8 *ota_sync_found)
+{
+ char * tok = NULL;
+ char rt_string[WL_OTA_STRING_MAX_LEN] = "\0";
+ uint16 cnt = 0;
+ int ret = 0;
+ tok = strtok(line, " ");
+
+ if (tok == NULL)
+ goto fail;
+
+ /* Initialize the power arguments */
+ ota_test_vctr->test_arg[*test_cnt].pwr_info.pwr_ctrl_on = -1;
+ ota_test_vctr->test_arg[*test_cnt].pwr_info.start_pwr = -1;
+ ota_test_vctr->test_arg[*test_cnt].pwr_info.delta_pwr = -1;
+ ota_test_vctr->test_arg[*test_cnt].pwr_info.end_pwr = -1;
+
+ if (!strncmp(tok, "test_setup", 10)) {
+ /* Parse test setup details */
+ cnt = 0;
+ while (tok != NULL) {
+ if ((ret = wl_ota_parse_test_init(ota_test_vctr, tok, cnt)) != 0)
+ return ret;
+ tok = strtok(NULL, " ");
+ cnt++;
+ }
+ } else if (!(strncmp(tok, "ota_tx", 6)) || (!strncmp(tok, "ota_rx", 6))) {
+ /* parse tx /rx test argumenst */
+ cnt = 0;
+ while (tok != NULL) {
+ if ((ret = wl_ota_test_parse_test_option
+ (&(ota_test_vctr->test_arg[*test_cnt]),
+ tok, cnt, rt_string)) != 0) {
+ goto fail;
+ }
+ tok = strtok(NULL, " ");
+ cnt++;
+ }
+
+ /* split rate string into integer array */
+ if ((ret = wl_ota_test_parse_rate_string(&(ota_test_vctr->test_arg[*test_cnt]),
+ rt_string)) != 0) {
+ goto fail;
+ }
+
+ /* Add sync option if specified by user */
+ ota_test_vctr->test_arg[*test_cnt].wait_for_sync = (*ota_sync_found);
+
+ /* Reset ota_sync_found for next test arg */
+ *ota_sync_found = 0;
+
+ /* Increment test cnt */
+ *test_cnt = *test_cnt + 1;
+ } else if (strncmp(tok, "ota_sync", 8) == 0) {
+ /* detect if a sync packet is required */
+ *ota_sync_found = 1;
+ ret = 0;
+ }
+fail:
+ return (ret);
+}
+static int
+wl_load_cmd_stream(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = -1;
+ char test_arg[WL_OTA_CMDSTREAM_MAX_LEN] = "\0";
+ uint16 test_cnt = 0;
+ uint8 * ptr1 = NULL;
+ uint8 i, num_loop = 0;
+ uint8 ota_sync_found = 0;
+ uint cmdlen = 0;
+
+ wl_seq_cmd_pkt_t *next_cmd;
+ wl_ota_test_vector_t *ota_test_vctr = NULL;
+
+ argv++;
+
+ if (*argv == NULL) {
+ return ret;
+ } else if (!strncmp(argv[0], "start", 5)) {
+ ret = wl_seq_start(wl, cmd, argv);
+ } else if (!strncmp(argv[0], "stop", 4)) {
+ ret = 0;
+ /* test info pointer */
+ ota_test_vctr = (wl_ota_test_vector_t *)malloc(sizeof(wl_ota_test_vector_t));
+
+ if (ota_test_vctr == NULL) {
+ fprintf(stderr, "Failed to allocate %d bytes of memory \n",
+ (uint16)sizeof(wl_ota_test_vector_t));
+ return BCME_NOMEM;
+ }
+
+ /* Assign a new pointer so that byte wise operation is possible */
+ ptr1 = (uint8 *)ota_test_vctr;
+
+ /* Passing test structure to dongle happens in steps */
+ /* For OTA implementations its split up into chunks of 1200 bytes */
+ num_loop = sizeof(wl_ota_test_vector_t) / WL_OTA_ARG_PARSE_BLK_SIZE;
+
+ if (!cmd_batching_mode) {
+ printf("calling ota_stream stop when it's already out of batching mode\n");
+ ret = BCME_ERROR;
+ goto fail;
+ }
+ cmd_batching_mode = FALSE;
+ next_cmd = cmd_list.head;
+ if (next_cmd == NULL) {
+ printf("no command batched\n");
+ ret = 0;
+ goto fail;
+ }
+ test_cnt = 0;
+ while (next_cmd != NULL) {
+ /* Max number of test options is ARRAYSIZE(ota_test_vctr->test_arg) */
+ if (test_cnt == ARRAYSIZE(ota_test_vctr->test_arg))
+ break;
+
+ if ((ret = wl_ota_test_parse_arg(next_cmd->data, ota_test_vctr, &test_cnt,
+ &ota_sync_found)) != 0) {
+ printf("Error Parsing the test command \n");
+ ret = BCME_BADARG;
+ goto fail;
+ }
+ next_cmd = next_cmd->next;
+ }
+ ota_test_vctr->test_cnt = test_cnt;
+ /* Full size of wl_ota_test_vector_t can not be parse through wl */
+ /* max size whihc can be passed from host to dongle is limited by eth size */
+ for (i = 0; i <= num_loop; i++) {
+ /* pass on the test info to wl->test_info structure */
+ if ((ret = wlu_var_setbuf(wl, "ota_loadtest", ptr1 + i *
+ WL_OTA_ARG_PARSE_BLK_SIZE, WL_OTA_ARG_PARSE_BLK_SIZE)) < 0) {
+ fprintf(stderr, "host to dongle download failed to pass %d"
+ "bytes in stage %d \n",
+ WL_OTA_ARG_PARSE_BLK_SIZE, i);
+ }
+ }
+fail:
+ clean_up_cmd_list();
+ free(ota_test_vctr);
+ } else {
+ cmdlen = sizeof(test_arg) - 1;
+ while (*argv) {
+ strncat(test_arg, *argv, cmdlen);
+ cmdlen -= strlen(*argv);
+ argv++;
+ if (*argv) {
+ strncat(test_arg, " ", 1);
+ cmdlen--;
+ }
+ if (*argv && cmdlen < (strlen(*argv)))
+ {
+ fprintf(stderr, "\n Insufficient length for cmd buffer\n");
+ return -1;
+ }
+ }
+ return add_one_batched_cmd(WLC_SET_VAR, test_arg, strlen(test_arg));
+
+ }
+ return ret;
+}
+
+int
+ota_loadtest(void *wl, char *command, char **argv)
+{
+ int ret = -1;
+ FILE *fp;
+ const char *fname = "ota_test.txt";
+ char line[WL_OTA_CMDSTREAM_MAX_LEN] = "\0";
+ char line_bkp[WL_OTA_CMDSTREAM_MAX_LEN] = "\0";
+ uint16 test_cnt = 0;
+ uint8 * ptr1 = NULL;
+ uint8 i, num_loop = 0;
+ uint8 ota_sync_found = 0;
+ wl_ota_test_vector_t *ota_test_vctr = NULL;
+
+ UNUSED_PARAMETER(wl);
+
+ /* Read the file name */
+ if (argv[1]) {
+ fname = argv[1];
+ } else {
+ fprintf(stderr, "Missing ota test flow file name\n");
+ return BCME_BADARG;
+ }
+
+ /* test info pointer */
+ ota_test_vctr = (wl_ota_test_vector_t *)malloc(sizeof(wl_ota_test_vector_t));
+
+ if (ota_test_vctr == NULL) {
+ fprintf(stderr, "Failed to allocate %d bytes of memory \n",
+ (uint16)sizeof(wl_ota_test_vector_t));
+ return BCME_NOMEM;
+ }
+
+ /* Assign a new pointer so that byte wide operation is possible */
+ ptr1 = (uint8 *)ota_test_vctr;
+
+ /* find number of iterations required to parse full block form host to dongle */
+ num_loop = sizeof(wl_ota_test_vector_t) / WL_OTA_ARG_PARSE_BLK_SIZE;
+
+
+ /* open the flow file */
+ if ((fp = fopen(fname, "r")) == NULL) {
+ fprintf(stderr, "Problem opening file %s\n", fname);
+ free(ota_test_vctr);
+ return BCME_BADARG;
+ }
+
+ /* Updating version for wl_ota_test_vector_t */
+ ota_test_vctr->version = WL_OTA_TESTVEC_T_VERSION;
+
+ test_cnt = 0;
+ while (1) {
+ fgets(line, WL_OTA_CMDSTREAM_MAX_LEN - 1, fp);
+
+ if (feof(fp)) {
+ break;
+ }
+
+ /* Max number of test options is ARRAYSIZE(ota_test_vctr->test_arg) */
+ if (test_cnt == ARRAYSIZE(ota_test_vctr->test_arg))
+ break;
+
+ strncpy(line_bkp, line, WL_OTA_CMDSTREAM_MAX_LEN - 1);
+
+ if ((ret = wl_ota_test_parse_arg(line_bkp, ota_test_vctr,
+ &test_cnt, &ota_sync_found)) != 0) {
+ printf("Flow File Error: \nError Parsing string : %s \n", line);
+ ret = BCME_BADARG;
+ goto fail;
+ }
+ }
+ if (ota_sync_found) {
+ ret = -1;
+ printf("Flow File Error : \nFile can not end with ota_sync\n");
+ goto fail;
+ }
+ ota_test_vctr->test_cnt = test_cnt;
+
+ /* Full size of wl_ota_test_vector_t can not be parse through wl */
+ /* max size whihc can be passed from host to dongle is limited by eth size */
+ for (i = 0; i <= num_loop; i++) {
+ /* pass on the test info to wl->test_info structure */
+ if ((ret = wlu_var_setbuf(wl, command, ptr1 + i * WL_OTA_ARG_PARSE_BLK_SIZE,
+ WL_OTA_ARG_PARSE_BLK_SIZE)) < 0) {
+ fprintf(stderr, "host to dongle download failed to pass %d"
+ "bytes in stage %d \n",
+ WL_OTA_ARG_PARSE_BLK_SIZE, i);
+ break;
+ }
+ }
+fail:
+ /* close the fp */
+ if (fp)
+ fclose(fp);
+
+ free(ota_test_vctr);
+ return ret;
+}
+
+static int
+wl_ota_loadtest(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd);
+ ret = ota_loadtest(wl, "ota_loadtest", argv);
+
+ return ret;
+}
+
+void
+wl_otatest_display_skip_test_reason(int8 skip_test_reason)
+{
+ switch (skip_test_reason) {
+ case 0 :
+ printf("Test successfully finished\n");
+ break;
+ case WL_OTA_SKIP_TEST_CAL_FAIL:
+ printf("Phy cal Failure \n");
+ break;
+ case WL_OTA_SKIP_TEST_SYNCH_FAIL:
+ printf("Sync Packet failure \n");
+ break;
+ case WL_OTA_SKIP_TEST_FILE_DWNLD_FAIL:
+ printf("File download Failure \n");
+ break;
+ case WL_OTA_SKIP_TEST_NO_TEST_FOUND:
+ printf("No test found in the flow file \n");
+ break;
+ case WL_OTA_SKIP_TEST_WL_NOT_UP:
+ printf("WL Not UP \n");
+ break;
+ case WL_OTA_SKIP_TEST_UNKNOWN_CALL:
+ printf("Erroneous scheduling of test. Not intended \n");
+ break;
+ default:
+ printf("Unknown test state \n");
+ break;
+ }
+}
+
+static int
+wl_otatest_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ int16 cnt = 0;
+ wl_ota_test_status_t *test_status = NULL;
+ wl_ota_test_vector_t *ota_test_vctr = NULL;
+
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd);
+
+ test_status = (wl_ota_test_status_t *)buf;
+ if (argv[1]) {
+
+ cnt = atoi(argv[1]);
+ if ((cnt < 1) || ((uint16)cnt > ARRAYSIZE(ota_test_vctr->test_arg))) {
+ printf("Error, Out of range \n");
+ return BCME_RANGE;
+ }
+ /* read nth test arg details */
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, &cnt, sizeof(uint16),
+ buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+ if (cnt > (test_status->test_cnt)) {
+ printf("Error : Number of test seq downloaded %d \n",
+ test_status->test_cnt);
+ return BCME_RANGE;
+ }
+
+ /* Display Test init info */
+ wl_ota_display_test_init_info(test_status);
+
+ /* Dsiplay test arg info */
+ wl_ota_display_test_option(&(test_status->test_arg), cnt);
+ } else {
+ /* read back current state */
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, NULL, 0,
+ buf, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+ cnt = test_status->cur_test_cnt;
+
+ switch (test_status->test_stage) {
+ case WL_OTA_TEST_IDLE: /* Idle state */
+ printf("Init state \n");
+ break;
+ case WL_OTA_TEST_ACTIVE: /* Active test state */
+ /* Read back details for current test arg */
+ cnt++;
+ ret = wlu_iovar_getbuf(wl, cmd->name, &cnt, sizeof(uint16),
+ buf, WLC_IOCTL_MAXLEN);
+ if (test_status->sync_status == WL_OTA_SYNC_ACTIVE)
+ printf("Waiting for sync \n");
+ else
+ wl_ota_display_test_option(&(test_status->test_arg), cnt);
+ break;
+ case WL_OTA_TEST_SUCCESS: /* Test Finished */
+ printf("Test completed \n");
+ break;
+ case WL_OTA_TEST_FAIL: /* Test Failed to complete */
+ wl_otatest_display_skip_test_reason(test_status->skip_test_reason);
+ break;
+ default:
+ printf("Invalid test Phase \n");
+ break;
+ }
+ }
+ return ret;
+}
+static int
+wl_otatest_rssi(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ int16 cnt = 0, rssi;
+ wl_ota_test_rssi_t *test_rssi = NULL;
+ wl_ota_rx_rssi_t *rx_rssi = NULL;
+
+ if (*++(argv)) {
+ printf("Too many arguments\n");
+ return BCME_ERROR;
+ }
+
+ test_rssi = (wl_ota_test_rssi_t *)buf;
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, NULL, 0,
+ buf, WLC_IOCTL_MEDLEN)) < 0)
+ return ret;
+
+ if (test_rssi->version != WL_OTARSSI_T_VERSION)
+ return BCME_VERSION;
+
+ rx_rssi = test_rssi->rx_rssi;
+ for (cnt = 0; cnt < test_rssi->testcnt; cnt++) {
+ rssi = dtoh16(rx_rssi[cnt].rssi);
+ if (rssi < 0)
+ printf("-%d.%02d ", ((-rssi) >> 2),
+ ((-rssi) & 0x3)*25);
+ else
+ printf("%d.%02d ", (rssi >> 2),
+ (rssi & 0x3)*25);
+ }
+ printf("\n");
+ return ret;
+}
+/* To stop the ota test suite */
+static int
+wl_ota_teststop(void *wl, cmd_t *cmd, char **argv)
+{
+ UNUSED_PARAMETER(argv);
+ return (wlu_iovar_setint(wl, cmd->name, 1));
+}
diff --git a/wl/src/wl/exe/wluc_p2p.c b/wl/src/wl/exe/wluc_p2p.c
new file mode 100644
index 0000000..dacafb3
--- /dev/null
+++ b/wl/src/wl/exe/wluc_p2p.c
@@ -0,0 +1,539 @@
+/*
+ * wl p2p command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_p2p.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifdef LINUX
+#include <time.h>
+#endif /* LINUX */
+
+static cmd_func_t wl_p2p_state;
+static cmd_func_t wl_p2p_scan;
+static cmd_func_t wl_p2p_ifadd;
+static cmd_func_t wl_p2p_ifdel;
+static cmd_func_t wl_p2p_ifupd;
+static cmd_func_t wl_p2p_if;
+static cmd_func_t wl_p2p_ops;
+static cmd_func_t wl_p2p_noa;
+
+static cmd_t wl_p2p_cmds[] = {
+ { "p2p_ssid", wl_ssid, WLC_GET_VAR, WLC_SET_VAR,
+ "set WiFi P2P wildcard ssid.\n"
+ "\tUsage: wl p2p_ssid <ssid>"
+ },
+ { "p2p_state", wl_p2p_state, -1, WLC_SET_VAR,
+ "set WiFi P2P discovery state.\n"
+ "\tUsage: wl p2p_state <state> [<chanspec> <dwell time>]"
+ },
+ { "p2p_scan", wl_p2p_scan, -1, WLC_SET_VAR,
+ "initiate WiFi P2P scan.\n"
+ "\tUsage: wl p2p_scan S|E <scan parms>\n"
+ SCAN_USAGE
+ },
+ { "p2p_ifadd", wl_p2p_ifadd, -1, WLC_SET_VAR,
+ "add WiFi P2P interface\n"
+ "\tUsage: wl p2p_ifadd <MAC-address> go|client|dyngo [chanspec]\n"
+ "MAC-address: xx:xx:xx:xx:xx:xx"
+ },
+ { "p2p_ifdel", wl_p2p_ifdel, -1, WLC_SET_VAR,
+ "delete WiFi P2P interface\n"
+ "\tUsage: wl p2p_ifdel <MAC-address>\n"
+ "MAC-address: xx:xx:xx:xx:xx:xx"
+ },
+ { "p2p_ifupd", wl_p2p_ifupd, -1, WLC_SET_VAR,
+ "update an interface to WiFi P2P interface\n"
+ "\tUsage: wl p2p_ifupd <MAC-address> go|client\n"
+ "MAC-address: xx:xx:xx:xx:xx:xx"
+ },
+ { "p2p_if", wl_p2p_if, WLC_GET_VAR, -1,
+ "query WiFi P2P interface bsscfg index\n"
+ "\tUsage: wl p2p_if <MAC-address>\n"
+ "MAC-address: xx:xx:xx:xx:xx:xx"
+ },
+ { "p2p_noa", wl_p2p_noa, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get WiFi P2P NoA schedule\n"
+ "\tUsage: wl p2p_noa <type> <type-specific-params>\n"
+ "\t\ttype 0: Scheduled Absence (on GO): <type> <action> <action-specific-params>\n"
+ "\t\t\taction -1: Cancel the schedule: <type> <action>\n"
+ "\t\t\taction 0,1,2: <type> <action> <option> <option-specific-params>\n"
+ "\t\t\t\taction 0: Do nothing during absence periods\n"
+ "\t\t\t\taction 1: Sleep during absence periods\n"
+ "\t\t\t\toption 0: <start:tsf> <interval> <duration> <count> ...\n"
+ "\t\t\t\toption 1 [<start-percentage>] <duration-percentage>\n"
+ "\t\t\t\toption 2 <start:tsf-offset> <interval> <duration> <count>\n"
+ "\t\ttype 1: Requested Absence (on GO): \n"
+ "\t\t\taction -1: Cancel the schedule: <type> <action>\n"
+ "\t\t\taction 2: <type> <action> <option> <option-specific-params>\n"
+ "\t\t\t\taction 2: Turn off GO beacons and probe responses during absence period\n"
+ "\t\t\t\toption 2 <start:tsf-offset> <interval> <duration> <count>"
+ },
+ { "p2p_ops", wl_p2p_ops, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get WiFi P2P OppPS and CTWindow\n"
+ "\tUsage: wl p2p_ops <ops> [<ctw>]\n"
+ "\t\t<ops>:\n"
+ "\t\t\t0: Disable OppPS\n"
+ "\t\t\t1: Enable OppPS\n"
+ "\t\t<ctw>:\n"
+ "\t\t\t10 and up to beacon interval"
+ },
+ { "p2p_da_override", wl_iov_mac, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set WiFi P2P device interface addr\n"
+ "\tUsage: wl p2p_da_override <MAC-address>\n"
+ "MAC-address: xx:xx:xx:xx:xx:xx\n"
+ "(When MAC-address is set to 00:00:00:00:00:00, default da restored)"
+ },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_p2p_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register p2p commands */
+ wl_module_cmds_register(wl_p2p_cmds);
+}
+
+static int
+wl_p2p_state(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_p2p_disc_st_t st;
+ int count;
+ char *endptr;
+
+ argv++;
+
+ count = ARGCNT(argv);
+ if (count < 1)
+ return BCME_USAGE_ERROR;
+
+ st.state = (uint8) strtol(argv[0], &endptr, 0);
+ if (st.state == WL_P2P_DISC_ST_LISTEN) {
+ if (count != 3)
+ return BCME_USAGE_ERROR;
+ if ((st.chspec = wf_chspec_aton(argv[1])) == 0) {
+ fprintf(stderr, "error parsing chanspec arg \"%s\"\n", argv[1]);
+ return BCME_BADARG;
+ }
+ st.chspec = wl_chspec_to_driver(st.chspec);
+ if (st.chspec == INVCHANSPEC) {
+ return BCME_USAGE_ERROR;
+ }
+ st.dwell = (uint16) strtol(argv[2], &endptr, 0);
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, &st, sizeof(st));
+}
+
+static int
+wl_p2p_scan(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_p2p_scan_t *params = NULL;
+ int params_size = 0;
+ int malloc_size = 0;
+ int sparams_size = 0;
+ int err = 0;
+
+ if (*(argv + 1) != NULL) {
+ malloc_size = sizeof(wl_p2p_scan_t);
+ switch (toupper(**(argv + 1))) {
+ case 'S':
+ malloc_size += WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
+ break;
+ case 'E':
+ malloc_size += OFFSETOF(wl_escan_params_t, params) +
+ WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
+ break;
+ }
+ }
+ if (malloc_size == 0) {
+ fprintf(stderr, "wrong syntax, need 'S' or 'E'\n");
+ return BCME_BADARG;
+ }
+
+ malloc_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
+ params = (wl_p2p_scan_t *)malloc(malloc_size);
+ if (params == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for scan params\n", malloc_size);
+ return BCME_NOMEM;
+ }
+ memset(params, 0, malloc_size);
+
+ switch (toupper(**(argv + 1))) {
+ case 'S': {
+ wl_scan_params_t *sparams = (wl_scan_params_t *)(params+1);
+ sparams_size = malloc_size - sizeof(wl_p2p_scan_t);
+
+ params->type = 'S';
+
+ if ((err = wl_scan_prep(wl, cmd, argv + 1, sparams, &sparams_size)) == 0)
+ params_size = sizeof(wl_p2p_scan_t) + sparams_size;
+ break;
+ }
+
+ case 'E': {
+ wl_escan_params_t *eparams = (wl_escan_params_t *)(params+1);
+ sparams_size = malloc_size - sizeof(wl_p2p_scan_t) - sizeof(wl_escan_params_t);
+
+ params->type = 'E';
+
+ eparams->version = htod32(ESCAN_REQ_VERSION);
+ eparams->action = htod16(WL_SCAN_ACTION_START);
+
+#if defined(linux)
+ srand((unsigned)time(NULL));
+ eparams->sync_id = htod16(rand() & 0xffff);
+#else
+ eparams->sync_id = htod16(4321);
+#endif /* #if defined(linux) */
+
+ if ((err = wl_scan_prep(wl, cmd, argv + 1, &eparams->params, &sparams_size)) == 0)
+ params_size = sizeof(wl_p2p_scan_t) + sizeof(wl_escan_params_t) +
+ sparams_size;
+ break;
+ }
+ }
+
+ if (!err)
+ err = wlu_iovar_setbuf(wl, cmd->name, params, params_size, buf, WLC_IOCTL_MAXLEN);
+
+ free(params);
+ return err;
+}
+
+static int
+wl_p2p_ifadd(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_p2p_if_t ifreq;
+ int count;
+
+ argv++;
+
+ count = ARGCNT(argv);
+ if (count < 2)
+ return BCME_USAGE_ERROR;
+
+ if (!wl_ether_atoe(argv[0], &ifreq.addr))
+ return BCME_USAGE_ERROR;
+
+ if (stricmp(argv[1], "go") == 0)
+ ifreq.type = WL_P2P_IF_GO;
+ else if (stricmp(argv[1], "client") == 0)
+ ifreq.type = WL_P2P_IF_CLIENT;
+ else if (stricmp(argv[1], "dyngo") == 0)
+ ifreq.type = WL_P2P_IF_DYNBCN_GO;
+ else
+ return BCME_USAGE_ERROR;
+
+ if (ifreq.type == WL_P2P_IF_GO || ifreq.type == WL_P2P_IF_DYNBCN_GO) {
+ if (count > 2) {
+ if ((ifreq.chspec = wf_chspec_aton(argv[2])) == 0) {
+ fprintf(stderr, "error parsing chanspec arg \"%s\"\n", argv[2]);
+ return BCME_BADARG;
+ }
+ ifreq.chspec = wl_chspec_to_driver(ifreq.chspec);
+ if (ifreq.chspec == INVCHANSPEC) {
+ return BCME_BADARG;
+ }
+ }
+ else
+ ifreq.chspec = 0;
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, &ifreq, sizeof(ifreq));
+}
+
+static int
+wl_p2p_ifdel(void *wl, cmd_t *cmd, char **argv)
+{
+ struct ether_addr addr;
+ int count;
+
+ argv++;
+
+ count = ARGCNT(argv);
+ if (count != 1)
+ return BCME_USAGE_ERROR;
+
+ if (!wl_ether_atoe(argv[0], &addr))
+ return BCME_USAGE_ERROR;
+
+ return wlu_var_setbuf(wl, cmd->name, &addr, sizeof(addr));
+}
+
+static int
+wl_p2p_ifupd(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_p2p_if_t ifreq;
+ int count;
+ int ret;
+ int bsscfg_idx = 0;
+ int consumed = 0;
+
+ argv++;
+
+ /* parse a bsscfg_idx option if present */
+ if ((ret = wl_cfg_option(argv, cmd->name, &bsscfg_idx, &consumed)) != 0)
+ return ret;
+ argv += consumed;
+ if (consumed == 0)
+ bsscfg_idx = -1;
+
+ count = ARGCNT(argv);
+ if (count < 2)
+ return BCME_USAGE_ERROR;
+
+ if (!wl_ether_atoe(argv[0], &ifreq.addr))
+ return BCME_USAGE_ERROR;
+
+ if (stricmp(argv[1], "go") == 0)
+ ifreq.type = WL_P2P_IF_GO;
+ else if (stricmp(argv[1], "client") == 0)
+ ifreq.type = WL_P2P_IF_CLIENT;
+ else
+ return BCME_USAGE_ERROR;
+
+ ifreq.chspec = 0;
+
+ if (bsscfg_idx == -1)
+ return wlu_var_setbuf(wl, cmd->name, &ifreq, sizeof(ifreq));
+ return wlu_bssiovar_setbuf(wl, cmd->name, bsscfg_idx,
+ &ifreq, sizeof(ifreq),
+ buf, WLC_IOCTL_MAXLEN);
+}
+
+static int
+wl_p2p_if(void *wl, cmd_t *cmd, char **argv)
+{
+ struct ether_addr addr;
+ int count;
+ wl_p2p_ifq_t *ptr;
+ int err;
+
+ argv++;
+
+ count = ARGCNT(argv);
+ if (count != 1)
+ return BCME_USAGE_ERROR;
+
+ if (!wl_ether_atoe(argv[0], &addr))
+ return BCME_USAGE_ERROR;
+
+ err = wlu_var_getbuf(wl, cmd->name, &addr, sizeof(addr), (void*)&ptr);
+ if (err >= 0)
+ printf("%u %s\n", dtoh32(ptr->bsscfgidx), (ptr->ifname));
+
+ return err;
+}
+
+static int
+wl_p2p_ops(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_p2p_ops_t ops;
+ int count;
+ char *endptr;
+
+ argv++;
+
+ count = ARGCNT(argv);
+ if (count < 1) {
+ wl_p2p_ops_t *ops;
+ int err;
+
+ err = wlu_var_getbuf(wl, cmd->name, NULL, 0, (void *)&ops);
+ if (err != BCME_OK) {
+ fprintf(stderr, "%s: error %d\n", cmd->name, err);
+ return err;
+ }
+
+ printf("ops: %u ctw: %u\n", ops->ops, ops->ctw);
+
+ return BCME_OK;
+ }
+
+ ops.ops = (uint8) strtol(argv[0], &endptr, 0);
+ if (ops.ops != 0) {
+ if (count != 2)
+ return BCME_USAGE_ERROR;
+ ops.ctw = (uint8) strtol(argv[1], &endptr, 0);
+ }
+ else
+ ops.ctw = 0;
+
+ return wlu_var_setbuf(wl, cmd->name, &ops, sizeof(ops));
+}
+
+static int
+wl_p2p_noa(void *wl, cmd_t *cmd, char **argv)
+{
+ int count;
+ wl_p2p_sched_t *noa;
+ int len;
+ int i;
+ char *endptr;
+
+ argv ++;
+
+ strcpy(buf, cmd->name);
+
+ count = ARGCNT(argv);
+ if (count < 2) {
+ int err = wlu_get(wl, WLC_GET_VAR, buf, WLC_IOCTL_MAXLEN);
+ wl_p2p_sched_t *sched;
+ int i;
+
+ if (err != BCME_OK) {
+ fprintf(stderr, "%s: error %d\n", cmd->name, err);
+ return err;
+ }
+
+ sched = (wl_p2p_sched_t *)buf;
+ for (i = 0; i < 16; i ++) {
+ if (sched->desc[i].count == 0)
+ break;
+ printf("start: %u interval: %u duration: %u count: %u\n",
+ sched->desc[i].start, sched->desc[i].interval,
+ sched->desc[i].duration, sched->desc[i].count);
+ }
+
+ return BCME_OK;
+ }
+
+ len = strlen(buf);
+
+ noa = (wl_p2p_sched_t *)&buf[len + 1];
+ len += 1;
+
+ noa->type = (uint8)strtol(argv[0], &endptr, 0);
+ len += sizeof(noa->type);
+ noa->action = (uint8)strtol(argv[1], &endptr, 0);
+ len += sizeof(noa->action);
+
+ argv += 2;
+ count -= 2;
+
+ /* action == -1 is to cancel the current schedule */
+ if (noa->action == WL_P2P_SCHED_ACTION_RESET) {
+ /* the fixed portion of wl_p2p_sched_t with action == WL_P2P_SCHED_ACTION_RESET
+ * is required to cancel the curret schedule.
+ */
+ len += (char *)&noa->desc[0] - ((char *)buf + len);
+ }
+ /* Take care of any special cases only and let all other cases fall through
+ * as normal 'start/interval/duration/count' descriptions.
+ * All cases start with 'type' 'action' 'option'.
+ * Any count value greater than 255 is to repeat unlimited.
+ */
+ else {
+ switch (noa->type) {
+ case WL_P2P_SCHED_TYPE_ABS:
+ case WL_P2P_SCHED_TYPE_REQ_ABS:
+ if (count < 1)
+ return BCME_USAGE_ERROR;
+ noa->option = (uint8)strtol(argv[0], &endptr, 0);
+ len += sizeof(noa->option);
+ argv += 1;
+ count -= 1;
+ break;
+ }
+
+ /* add any paddings before desc field */
+ len += (char *)&noa->desc[0] - ((char *)buf + len);
+
+ switch (noa->type) {
+ case WL_P2P_SCHED_TYPE_ABS:
+ switch (noa->option) {
+ case WL_P2P_SCHED_OPTION_BCNPCT:
+ if (count == 1) {
+ noa->desc[0].duration = htod32(strtol(argv[0], &endptr, 0));
+ noa->desc[0].start = 100 - noa->desc[0].duration;
+ }
+ else if (count == 2) {
+ noa->desc[0].start = htod32(strtol(argv[0], &endptr, 0));
+ noa->desc[0].duration = htod32(strtol(argv[1], &endptr, 0));
+ }
+ else {
+ fprintf(stderr, "Usage: wl p2p_noa 0 %d 1 "
+ "<start-pct> <duration-pct>\n",
+ noa->action);
+ return BCME_USAGE_ERROR;
+ }
+ len += sizeof(wl_p2p_sched_desc_t);
+ break;
+
+ default:
+ if (count < 4 || (count % 4) != 0) {
+ fprintf(stderr, "Usage: wl p2p_noa 0 %d 0 "
+ "<start> <interval> <duration> <count> ...\n",
+ noa->action);
+ return BCME_USAGE_ERROR;
+ }
+ goto normal;
+ }
+ break;
+
+ default:
+ if (count != 4) {
+ fprintf(stderr, "Usage: wl p2p_noa 1 %d "
+ "<start> <interval> <duration> <count> ...\n",
+ noa->action);
+ return BCME_USAGE_ERROR;
+ }
+ /* fall through... */
+ normal:
+ for (i = 0; i < count; i += 4) {
+ noa->desc[i / 4].start = htod32(strtoul(argv[i], &endptr, 0));
+ noa->desc[i / 4].interval = htod32(strtol(argv[i + 1], &endptr, 0));
+ noa->desc[i / 4].duration = htod32(strtol(argv[i + 2], &endptr, 0));
+ noa->desc[i / 4].count = htod32(strtol(argv[i + 3], &endptr, 0));
+ len += sizeof(wl_p2p_sched_desc_t);
+ }
+ break;
+ }
+ }
+
+ return wlu_set(wl, WLC_SET_VAR, buf, len);
+}
diff --git a/wl/src/wl/exe/wluc_p2po.c b/wl/src/wl/exe/wluc_p2po.c
new file mode 100644
index 0000000..6fc7f98
--- /dev/null
+++ b/wl/src/wl/exe/wluc_p2po.c
@@ -0,0 +1,1050 @@
+/*
+ * wl p2po command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_p2po.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#include <string.h>
+
+#ifdef LINUX
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* LINUX */
+
+static cmd_func_t wl_p2po_listen;
+static cmd_func_t wl_p2po_addsvc;
+static cmd_func_t wl_p2po_delsvc;
+static cmd_func_t wl_p2po_sd_reqresp;
+static cmd_func_t wl_p2po_listen_channel;
+static cmd_func_t wl_p2po_find_config;
+static int wl_p2po_gas_config(void *wl, cmd_t *cmd, char **argv);
+static int wl_p2po_wfds_seek_get(void *wl, cmd_t *cmd, char **argv);
+static int wl_p2po_wfds_seek_add(void *wl, cmd_t *cmd, char **argv);
+static int wl_p2po_wfds_seek_del(void *wl, cmd_t *cmd, char **argv);
+static int wl_p2po_wfds_advertise_add(void *wl, cmd_t *cmd, char **argv);
+static int wl_p2po_wfds_advertise_del(void *wl, cmd_t *cmd, char **argv);
+#if defined(linux)
+static cmd_func_t wl_p2po_results;
+#endif /* linux */
+
+
+static cmd_t wl_p2po_cmds[] = {
+ { "p2po_listen", wl_p2po_listen, -1, -1,
+ "start/get listen\n"
+ "\n"
+ "\tStart listen\n"
+ "\tusage: p2po_listen <period(ms)> <interval(ms)> [count]\n"
+ "\n"
+ "\tRead back listen period, interval, count\n"
+ "\tusage: p2po_listen"
+ },
+ { "p2po_find", wl_var_void, -1, WLC_SET_VAR,
+ "start discovery"
+ },
+ { "p2po_stop", wl_var_void, -1, WLC_SET_VAR,
+ "stop both P2P listen and P2P device discovery offload\n"
+ "\tusage: p2po_stop"
+ },
+ { "p2po_addsvc", wl_p2po_addsvc, -1, WLC_SET_VAR,
+ "add query-service pair\n"
+ "\tusage: p2po_addsvc <protocol> <\"query\"> <\"response\">\n"
+ "\t\t<protocol>: 1 = Bonjour, 2 = UPnP"
+ },
+ { "p2po_delsvc", wl_p2po_delsvc, -1, WLC_SET_VAR,
+ "delete query-service pair\n"
+ "\tusage: p2po_delsvc <protocol> <\"query\">\n"
+ "\t\t<protocol>: 1 = Bonjour, 2 = UPnP, 0 = delete all"
+ },
+ { "p2po_sd_req_resp", wl_p2po_sd_reqresp, -1, WLC_SET_VAR,
+ "find a service\n"
+ "\tusage: p2po_sd_req_resp <protocol> <\"query\">\n"
+ "\t\t<protocol>: 1 = Bonjour, 2 = UPnP"
+ },
+ { "p2po_sd_cancel", wl_var_void, -1, WLC_SET_VAR,
+ "cancel finding a service"
+ },
+ { "p2po_listen_channel", wl_p2po_listen_channel, WLC_GET_VAR, WLC_SET_VAR,
+ "set listen channel to channel 1, 6, 11, or default\n"
+ "\tusage: p2po_listen_channel <1|6|11|0>"
+ },
+ { "p2po_find_config", wl_p2po_find_config, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get the parameters for the p2po_find command\n"
+ "\tusage: p2po_find_config <flags> <home_time> <social channels>\n"
+ "\t flags: bit 0 = scan for both P2P devices and non-P2P APs\n"
+ "\texample: p2po_find_config 0 100 11 165\n"
+ "\t Scan for only P2P devices, home time 100ms, social channels 11 165\n"
+ },
+#if defined(linux)
+ { "p2po_results", wl_p2po_results, -1, WLC_SET_VAR,
+ "Listens and displays P2PO results."
+ },
+#endif /* linux */
+ { "p2po_gas_config", wl_p2po_gas_config, WLC_GET_VAR, WLC_SET_VAR,
+ "set GAS state machine tunable parameters\n"
+ "\tusage: p2po_gas_config <max_retrans> <resp_timeout> <max_comeback_delay> <max_retries>"
+ },
+ { "p2po_wfds_seek_add", wl_p2po_wfds_seek_add, WLC_GET_VAR, WLC_SET_VAR,
+ "\tSet usage: p2po_wfds_seek_add <seek_hdl> <service_hash> <macaddr> <service_name>"
+ " [service_info_req]\n"
+ "Add a WFDS service to seek\n"
+ "\t\t<hdl> An arbitrary number identifying this add request\n"
+ "\t\t<service_hash> 6 hex byte service hash of the service to seek\n"
+ "\t\t<macaddr> 6 hex byte advertiser MAC address to match, all FFs if wildcard\n"
+ "\t\t<service_name> Service name to seek\n"
+ "\t\t<service_info_req> Service Info Request string to send in Service Discovery request\n"
+ "\teg. p2po_wfds_seek_add 1234 1 0x090a0b112233 org.wi-fi.wfds.print.rx\n"
+ "\teg. p2po_wfds_seek_add 1234 1 0x090a0b112233 org.wi-fi.wfds.* abcdefg"
+ "\n"
+ "\tGet usage: p2po_wfds_seek_add <seek_hdl>"
+ "Get information about a configured WFDS seek\n"
+ "\t\t<hdl> The hdl of a previously added WFDS service to seek\n"
+ "\teg. p2po_wfds_seek_add 1234"
+ },
+ { "p2po_wfds_seek_del", wl_p2po_wfds_seek_del, -1, WLC_SET_VAR,
+ "delete a WFDS service to seek\n"
+ "\tusage: p2po_wfds_seek_del <seek_hdl>\n"
+ "\t\t<hdl> the hdl specified in a previous p2po_wfds_seek_add"
+ },
+ { "p2po_wfds_seek_dump", wl_var_void, -1, WLC_SET_VAR,
+ "dump WFDS services to seek"
+ },
+ { "p2po_wfds_advertise_add", wl_p2po_wfds_advertise_add, WLC_GET_VAR, WLC_SET_VAR,
+ "add a WFDS service to advertise\n"
+ "\tSet usage: p2po_wfds_advertise_add <adv_hdl> <adv_id> <cfg_meth>"
+ " <hash> <service_name> <status> [service_info]\n"
+ "\t\t<hdl> An arbitrary number identifying this add request\n"
+ "\t\t<adv_id> 4 hex byte advertisement ID\n"
+ "\t\t<cfg_meth> 2 hex byte WPS config methods supported by this service\n"
+ "\t\t<service_hash> 6 hex byte service hash of the service to advertise\n"
+ "\t\t<service_name> Service name. Text string up to 255 chars\n"
+ "\t\t<status> Status code of the service to advertise, 0...255\n"
+ "\t\t<service_info> Service information to send in Service Discovery Response."
+ " Text string up to 255 chars\n"
+ "\teg. p2po_wfds_advertise_add 4321 0x7a7b9e9f 0x0080 0x1133557799aa"
+ " org.wi-fi.wfds.print.rx 0 abcdefg"
+ "\n"
+ "\tGet usage: p2po_wfds_advertise_add <adv_hdl>"
+ "Get information about a configured WFDS advertise service\n"
+ "\t\t<adv_hdl> The hdl of a previously added WFDS advertise service\n"
+ "\teg. p2po_wfds_advertise_add 4321"
+ },
+ { "p2po_wfds_advertise_del", wl_p2po_wfds_advertise_del, -1, WLC_SET_VAR,
+ "\tusage: p2po_wfds_advertise_del <adv_hdl>\n"
+ "\t\t<hdl> the hdl specified in a previous p2po_wfds_advertise_add\n"
+ "\teg. p2po_wfds_advertise_del 4321"
+ },
+ { "p2po_wfds_advertise_dump", wl_var_void, -1, WLC_SET_VAR,
+ "dump WFDS services to advertise"
+ },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_p2po_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register p2po commands */
+ wl_module_cmds_register(wl_p2po_cmds);
+}
+
+#define UPNP_QUERY_VERSION "0x10"
+#define BCM_SVC_RPOTYPE_ALL 0
+#define BCM_SVC_RPOTYPE_BONJOUR 1
+#define BCM_SVC_RPOTYPE_UPNP 2
+#define BCM_SVC_RPOTYPE_WSD 3
+#define BCM_SVC_RPOTYPE_VENDOR 255
+
+static int
+wl_p2po_listen(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, params_size;
+ wl_p2po_listen_t params;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!argv[1]) {
+ if ((err = wlu_iovar_get(wl, cmd->name, (void *) ¶ms,
+ (sizeof(wl_p2po_listen_t)))) < 0)
+ return (err);
+ printf(" listen period=%u listen interval=%u listen count=%u\n",
+ dtoh16(params.period), dtoh16(params.interval), dtoh16(params.count));
+ return BCME_OK;
+ }
+
+ if (!argv[2] || !argv[3])
+ return BCME_USAGE_ERROR;
+
+ params.period = atoi(argv[1]);
+ params.interval = atoi(argv[2]);
+ params.count = atoi(argv[3]);
+
+ params_size = sizeof(wl_p2po_listen_t);
+
+ err = wlu_iovar_set(wl, "p2po_listen", ¶ms, params_size);
+
+ return err;
+}
+
+static int
+wl_p2po_addsvc(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int protocol, query_len, response_len, params_size;
+ char *query, *response;
+ wl_p2po_qr_t *params;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!argv[1] || !argv[2] || !argv[3]) {
+ fprintf(stderr, "Too few arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ protocol = atoi(argv[1]);
+ if (protocol == BCM_SVC_RPOTYPE_BONJOUR) {
+ query = argv[2];
+ response = argv[3];
+ query_len = hexstr2hex(query);
+ response_len = hexstr2hex(response);
+ } else if (protocol == BCM_SVC_RPOTYPE_UPNP) {
+ if (memcmp(argv[2], UPNP_QUERY_VERSION, strlen(UPNP_QUERY_VERSION)) != 0 ||
+ memcmp(argv[3], UPNP_QUERY_VERSION, strlen(UPNP_QUERY_VERSION)) != 0) {
+ fprintf(stderr, "UPnP query/response string must start with 0x10");
+ return BCME_USAGE_ERROR;
+ }
+ query = argv[2] + strlen(UPNP_QUERY_VERSION) - 1;
+ response = argv[3] + strlen(UPNP_QUERY_VERSION) - 1;
+ query[0] = strtoul(UPNP_QUERY_VERSION, NULL, 16);
+ response[0] = strtoul(UPNP_QUERY_VERSION, NULL, 16);
+
+ query_len = strlen(query);
+ response_len = strlen(response);
+ }
+ else {
+ fprintf(stderr, "<protocol> should be <1|2>\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ params_size = sizeof(wl_p2po_qr_t) + query_len + response_len - 1;
+ params = (wl_p2po_qr_t *)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Not enough memory\n");
+ return BCME_NOMEM;
+ }
+
+ params->protocol = protocol;
+ params->query_len = query_len;
+ params->response_len = response_len;
+ memcpy(params->qrbuf, query, query_len);
+ memcpy(params->qrbuf+query_len, response, response_len);
+
+ err = wlu_iovar_setbuf(wl, "p2po_addsvc", params, params_size, buf, WLC_IOCTL_MAXLEN);
+
+ free(params);
+
+ return err;
+}
+
+static int
+wl_p2po_delsvc(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int protocol, query_len, params_size;
+ char *query = NULL;
+ wl_p2po_qr_t *params;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!argv[1] || (*argv[1] != '0' && !argv[2])) {
+ fprintf(stderr, "Too few arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (*argv[1] == '0') {
+ protocol = 0;
+ query_len = 0;
+ }
+ else {
+ protocol = atoi(argv[1]);
+ if (protocol == BCM_SVC_RPOTYPE_BONJOUR) {
+ query = argv[2];
+ query_len = hexstr2hex(query);
+ } else if (protocol == BCM_SVC_RPOTYPE_UPNP) {
+ if (memcmp(argv[2], UPNP_QUERY_VERSION, strlen(UPNP_QUERY_VERSION)) != 0) {
+ fprintf(stderr, "UPnP query string must start with 0x10");
+ return BCME_USAGE_ERROR;
+ }
+ query = argv[2] + strlen(UPNP_QUERY_VERSION) - 1;
+ query[0] = strtoul(UPNP_QUERY_VERSION, NULL, 16);
+
+ query_len = strlen(query);
+ }
+ else {
+ fprintf(stderr, "<protocol> should be <1|2>\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ params_size = sizeof(wl_p2po_qr_t) + (query_len ? query_len - 1 : 0);
+ params = (wl_p2po_qr_t *)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Not enough memory\n");
+ return BCME_NOMEM;
+ }
+
+ params->protocol = protocol;
+ params->query_len = query_len;
+ if (query_len)
+ memcpy(params->qrbuf, query, query_len);
+
+ err = wlu_iovar_set(wl, "p2po_delsvc", params, params_size);
+
+ free(params);
+
+ return err;
+}
+
+static int
+wl_p2po_sd_reqresp(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int transaction_id, protocol, query_len, params_size;
+ char *query = NULL;
+ wl_p2po_qr_t *params;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!argv[1] || !argv[2]) {
+ fprintf(stderr, "Too few arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ transaction_id = atoi(argv[1]);
+ if (transaction_id < 0 || transaction_id > 255) {
+ fprintf(stderr, "<transaction id> should be between 0 and 255\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ protocol = atoi(argv[2]);
+ if (!argv[3]) {
+ /* find everything for protocol */
+ query_len = 0;
+ } else if (protocol == BCM_SVC_RPOTYPE_BONJOUR) {
+ query = argv[3];
+ query_len = hexstr2hex(query);
+ } else if (protocol == BCM_SVC_RPOTYPE_UPNP) {
+ if (memcmp(argv[3], UPNP_QUERY_VERSION, strlen(UPNP_QUERY_VERSION)) != 0) {
+ fprintf(stderr, "UPnP query string must start with 0x10");
+ return BCME_USAGE_ERROR;
+ }
+ query = argv[3] + strlen(UPNP_QUERY_VERSION) - 1;
+ query[0] = strtoul(UPNP_QUERY_VERSION, NULL, 16);
+
+ query_len = strlen(query);
+ } else {
+ fprintf(stderr, "<protocol> should be <0|1|2>\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ params_size = sizeof(wl_p2po_qr_t) + (query_len ? query_len - 1 : 0);
+ params = (wl_p2po_qr_t *)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Not enough memory\n");
+ return BCME_NOMEM;
+ }
+
+ params->transaction_id = transaction_id;
+ params->protocol = protocol;
+ params->query_len = query_len;
+ if (query_len)
+ memcpy(params->qrbuf, query, query_len);
+
+ err = wlu_iovar_set(wl, "p2po_sd_req_resp", params, params_size);
+
+ free(params);
+
+ return err;
+}
+
+static int
+wl_p2po_listen_channel(void *wl, cmd_t *cmd, char **argv)
+{
+ int error;
+ int32 val;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) {
+ val = atoi(*argv);
+ return wlu_iovar_setint(wl, "p2po_listen_channel", val);
+ } else {
+ error = wlu_iovar_getint(wl, "p2po_listen_channel", &val);
+ if (error < 0)
+ return error;
+ printf("P2P Offload Listen Channel: %d\n", dtoh32(val));
+ return BCME_OK;
+ }
+}
+
+static int
+wl_p2po_find_config(void *wl, cmd_t *cmd, char **argv)
+{
+ uint argc;
+ int error;
+ int i;
+ wl_p2po_find_config_t *fc;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* Get arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc == 0)
+ return BCME_ERROR;
+
+ if (argc == 1) {
+ error = wlu_iovar_getbuf(wl, cmd->name, NULL, 0, buf, WLC_IOCTL_MEDLEN);
+ if (error < 0)
+ return error;
+
+ fc = (wl_p2po_find_config_t*) buf;
+ printf("P2P Offload Find configuration:\n");
+ printf(" Version: %u Length: %u\n",
+ dtoh16(fc->version), dtoh16(fc->length));
+ printf(" Scan for non-P2P APs: %d\n",
+ (fc->flags & P2PO_FIND_FLAG_SCAN_ALL_APS) != 0);
+ printf(" Search home time: %d\n", dtoh32(fc->search_home_time));
+ printf(" # of social channels: %u\n", fc->num_social_channels);
+ printf(" Social channels:");
+ for (i = 0; i < fc->num_social_channels; i++) {
+ printf(" %u", fc->social_channels[i]);
+ }
+ printf("\n");
+ } else if (argc <= 3) {
+ fprintf(stderr, "At least 1 social channel is required.\n");
+ error = BCME_BADARG;
+ } else {
+ uint fc_size;
+ uint16 channel;
+ uint j;
+
+ fc_size = sizeof(wl_p2po_find_config_t) + (argc - 2) * sizeof(uint16);
+ fc = (wl_p2po_find_config_t*) malloc(fc_size);
+ if (fc == NULL) {
+ printf("Cannot not allocate %d bytes for p2po_find_config buffer\n",
+ fc_size);
+ return BCME_NOMEM;
+ }
+ memset(fc, 0, fc_size);
+
+ fc->version = WL_P2PO_FIND_CONFIG_VERSION;
+ fc->length = sizeof(*fc);
+ fc->flags = atoi(argv[1]);
+ fc->search_home_time = atoi(argv[2]);
+
+ /* Set the social channel list */
+ i = 0;
+ for (j = 3; j < argc; j++, i++) {
+ channel = atoi(argv[j]);
+ if (channel == 0) {
+ printf("Invalid channel %s\n", argv[j]);
+ break;
+ } else {
+ fc->social_channels[i] = channel;
+ }
+ }
+ fc->num_social_channels = i;
+
+ error = wlu_iovar_setbuf(wl, cmd->name, fc, fc_size, buf,
+ WLC_IOCTL_MEDLEN);
+ free(fc);
+ }
+
+ return error;
+}
+
+#if defined(linux)
+#define P2PO_EVENTS_BUFFER_SIZE 2048
+
+static int
+wl_p2po_results(void *wl, cmd_t *cmd, char **argv)
+{
+ int fd, err, octets;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ char *data;
+ uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* event bit mask */
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
+
+ memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN);
+ event_inds_mask[WLC_E_SERVICE_FOUND / 8] |= 1 << (WLC_E_SERVICE_FOUND % 8);
+ event_inds_mask[WLC_E_GAS_FRAGMENT_RX / 8] |= 1 << (WLC_E_GAS_FRAGMENT_RX % 8);
+ if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
+ goto exit2;
+
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
+ if (fd < 0) {
+ printf("Cannot create socket %d\n", fd);
+ err = -1;
+ goto exit2;
+ }
+
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ printf("Cannot get index %d\n", err);
+ goto exit1;
+ }
+
+ /* bind the socket first before starting so we won't miss any event */
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ printf("Cannot bind %d\n", err);
+ goto exit1;
+ }
+
+ data = (char*)malloc(P2PO_EVENTS_BUFFER_SIZE);
+
+ if (data == NULL) {
+ printf("Cannot not allocate %d bytes for events receive buffer\n",
+ P2PO_EVENTS_BUFFER_SIZE);
+ err = BCME_NOMEM;
+ goto exit1;
+ }
+
+ /* receive result */
+ while (1) {
+ bcm_event_t *bcm_event;
+ int event_type;
+
+ octets = recv(fd, data, P2PO_EVENTS_BUFFER_SIZE, 0);
+ bcm_event = (bcm_event_t *)data;
+ event_type = ntoh32(bcm_event->event.event_type);
+
+ if (octets >= (int)sizeof(bcm_event_t)) {
+ if (event_type == WLC_E_SERVICE_FOUND) {
+ uint32 status = ntoh32(bcm_event->event.status);
+ wl_event_sd_t *sd_data =
+ (wl_event_sd_t *)&data[sizeof(bcm_event_t)];
+
+ sd_data->channel = dtoh16(sd_data->channel);
+
+ printf("WLC_E_SERVICE_FOUND: %s\n",
+ status == WLC_E_STATUS_PARTIAL ? "WLC_E_STATUS_PARTIAL" :
+ status == WLC_E_STATUS_SUCCESS ? "WLC_E_STATUS_SUCCESS" :
+ status == WLC_E_STATUS_FAIL ? "WLC_E_STATUS_FAIL" :
+ "unknown");
+ printf(" channel = %d\n", sd_data->channel);
+ printf(" peer = %s\n",
+ wl_ether_etoa(&bcm_event->event.addr));
+ if (status == WLC_E_STATUS_SUCCESS) {
+ wl_sd_tlv_t *tlv;
+ int i;
+
+ tlv = sd_data->tlv;
+ for (i = 0; i < sd_data->count; i++) {
+ printf(" [TLV %d]\n", i);
+ tlv->length = dtoh16(tlv->length);
+ printf(" protocol type = %s\n",
+ tlv->protocol == 0 ? "ALL" :
+ tlv->protocol == BCM_SVC_RPOTYPE_BONJOUR ?
+ "BONJOUR" :
+ tlv->protocol == BCM_SVC_RPOTYPE_UPNP ?
+ "UPnP" :
+ tlv->protocol == BCM_SVC_RPOTYPE_WSD ?
+ "WS-Discovery" :
+ tlv->protocol == BCM_SVC_RPOTYPE_VENDOR ?
+ "Vendor specific" : "Unknown");
+ printf(" transaction id = %u\n",
+ tlv->transaction_id);
+ printf(" status code = %u\n",
+ tlv->status_code);
+ printf(" length = %u\n", tlv->length);
+ wl_hexdump(tlv->data, tlv->length);
+
+ tlv = (wl_sd_tlv_t *)((void *)tlv + tlv->length +
+ OFFSETOF(wl_sd_tlv_t, data));
+ }
+ }
+ else {
+ /* fragments */
+ }
+ }
+ }
+ }
+
+ free(data);
+exit1:
+ close(fd);
+exit2:
+ return err;
+}
+#endif /* linux */
+
+static int
+wl_p2po_gas_config(void *wl, cmd_t *cmd, char **argv)
+{
+ int error;
+ wl_gas_config_t set;
+ wl_gas_config_t* get;
+
+ if (!argv[1]) {
+ error = wlu_iovar_getbuf(wl, "p2po_gas_config", &set, sizeof(set),
+ buf, WLC_IOCTL_MAXLEN);
+ if (error < 0)
+ return error;
+ get = (wl_gas_config_t*) buf;
+ printf("P2P Offload GAS state machine tunable parameters:\n");
+ printf(" max_retrans=%u resp_timeout=%u\n",
+ dtoh16(get->max_retransmit), dtoh16(get->response_timeout));
+ printf(" max_comeback_delay=%u max_retries=%u\n",
+ dtoh16(get->max_comeback_delay), dtoh16(get->max_retries));
+ return BCME_OK;
+ }
+
+ if (!argv[1] || !argv[2] || !argv[3] || !argv[4]) {
+ fprintf(stderr, "Too few arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ set.max_retransmit = htod16(atoi(argv[1]));
+ set.response_timeout = htod16(atoi(argv[2]));
+ set.max_comeback_delay = htod16(atoi(argv[3]));
+ set.max_retries = htod16(atoi(argv[4]));
+
+ return wlu_iovar_setbuf(wl, cmd->name, &set, sizeof(set), buf, WLC_IOCTL_MEDLEN);
+}
+
+void
+wl_p2po_print_name(char *prefix, uint namelen, uint8 *name)
+{
+ char namez[32 + 1];
+
+ if (namelen > sizeof(namez) - 1)
+ namelen = sizeof(namez) - 1;
+ memcpy(namez, name, namelen);
+ namez[namelen] = '\0';
+
+ printf("%s%u,%s\n", prefix, namelen, namez);
+}
+
+static int
+wl_p2po_wfds_seek_get(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_p2po_wfds_seek_add_t* seek = (wl_p2po_wfds_seek_add_t*) buf;
+ wl_p2po_wfds_seek_add_t seek0;
+ int ret;
+
+ if (!argv[1]) {
+ fprintf(stderr, "Too few arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ memset(&seek0, 0, sizeof(seek0));
+ seek0.seek_hdl = atoi(argv[1]);
+
+ ret = wlu_iovar_getbuf(wl, cmd->name, &seek0, sizeof(seek0), seek, WLC_IOCTL_MAXLEN);
+ if (ret < 0) {
+ goto exit;
+ }
+
+ printf("Seek service hdl=%u\n", seek->seek_hdl);
+ printf(" hash=0x%02x%02x%02x%02x%02x%02x\n",
+ seek->service_hash[0], seek->service_hash[1], seek->service_hash[2],
+ seek->service_hash[3], seek->service_hash[4], seek->service_hash[5]);
+ printf(" mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
+ seek->addr[0], seek->addr[1], seek->addr[2],
+ seek->addr[3], seek->addr[4], seek->addr[5]);
+ printf(" name length=%u\n", seek->service_name_len);
+ printf(" name=%s\n", seek->service_name);
+ printf(" info_req length=%u\n", seek->service_info_req_len);
+ printf(" info_req=%s\n", seek->service_info_req);
+
+exit:
+ return ret;
+}
+
+static int
+wl_p2po_wfds_seek_add(void *wl, cmd_t *cmd, char **argv)
+{
+ int malloc_size;
+ wl_p2po_wfds_seek_add_t* seek;
+ int len;
+ int ret;
+ int iovbuf_size;
+ uint8 *iovbuf;
+
+ /* If only a seek_hdl parameter is given, read an existing seek */
+ if (!argv[2]) {
+ return wl_p2po_wfds_seek_get(wl, cmd, argv);
+ }
+
+ if (!argv[4]) {
+ fprintf(stderr, "Too few arguments for iovar SET\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ malloc_size = sizeof(*seek) + MAX_WFDS_SEEK_SVC_INFO_LEN - 1;
+ seek = malloc(malloc_size);
+ if (!seek) {
+ fprintf(stderr, "malloc error, size=%d\n", malloc_size);
+ return BCME_NOMEM;
+ }
+ memset(seek, 0, malloc_size);
+
+ /* Get <seek_hdl> argument */
+ seek->seek_hdl = atoi(argv[1]);
+
+ /* Get <service_hash> argument */
+ if (argv[2]) {
+ if (strlen(argv[2]) != 14) {
+ fprintf(stderr, "bad argument: %s\n", argv[2]);
+ fprintf(stderr, "<svc_hash> must be 6 hex bytes, eg. '0x112233aabbcc'\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ len = wl_pattern_atoh(argv[2], (char*)seek->service_hash);
+ if (len != 6) {
+ fprintf(stderr, "invalid hex string: %s\n", argv[2]);
+ fprintf(stderr, "<svc_hash> must be 6 hex bytes, eg. '0x112233aabbcc'\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+
+ /* Get <macaddr> argument */
+ if (!wl_ether_atoe(argv[3], (struct ether_addr*) seek->addr)) {
+ fprintf(stderr, "invalid MAC address: %s\n", argv[2]);
+ fprintf(stderr, "<macaddr> must be like '00:90:4c:7a:8b:fe'\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ /* Get <service_name> argument */
+ if (argv[4]) {
+ len = strlen(argv[4]);
+ memcpy(seek->service_name, argv[4], len);
+ seek->service_name_len = len;
+ } else {
+ memcpy(seek->service_name, "org.wi-fi.wfds", strlen("org.wi-fi.wfds"));
+ seek->service_name_len = strlen((char*)seek->service_name);
+ }
+ wl_p2po_print_name("svc_name: ", seek->service_name_len, seek->service_name);
+
+ /* Get optional [service_info] argument */
+ if (argv[5]) {
+ len = strlen(argv[5]);
+ if (len > MAX_WFDS_SEEK_SVC_INFO_LEN)
+ len = MAX_WFDS_SEEK_SVC_INFO_LEN;
+ memcpy(seek->service_info_req, argv[5], len);
+ seek->service_info_req_len = len;
+ } else {
+ seek->service_info_req_len = 0;
+ }
+ wl_p2po_print_name("svc_info_req: ", seek->service_info_req_len,
+ seek->service_info_req);
+
+ iovbuf_size = malloc_size + strlen(cmd->name) + 1;
+ iovbuf = malloc(iovbuf_size);
+ if (!iovbuf) {
+ fprintf(stderr, "malloc error, size=%d\n", iovbuf_size);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+ ret = wlu_iovar_setbuf(wl, cmd->name, seek, malloc_size, iovbuf, iovbuf_size);
+ free(iovbuf);
+ if (ret != BCME_OK)
+ fprintf(stderr, "%s failed: %d\n", cmd->name, ret);
+exit:
+ free(seek);
+ return ret;
+}
+
+static int
+wl_p2po_wfds_seek_del(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_p2po_wfds_seek_del_t* del;
+ int ret;
+
+ if (!argv[1]) {
+ fprintf(stderr, "No seek_hdl is specified\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ del = malloc(sizeof(*del));
+ if (!del) {
+ fprintf(stderr, "malloc error, size=%u\n", (uint)sizeof(*del));
+ return BCME_NOMEM;
+ }
+
+ del->seek_hdl = atoi(argv[1]);
+ ret = wlu_iovar_setbuf(wl, cmd->name, del, sizeof(*del), buf, WLC_IOCTL_MAXLEN);
+
+ free(del);
+ return ret;
+}
+
+static int
+wl_p2po_wfds_advertise_get(void *wl, cmd_t *cmd, char **argv)
+{
+ int malloc_size;
+ wl_p2po_wfds_advertise_add_t* add;
+ wl_p2po_wfds_advertise_add_t add0;
+ uint16 svc_info_len;
+ int ret;
+
+ if (!argv[1]) {
+ fprintf(stderr, "Too few arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ memset(&add0, 0, sizeof(add0));
+ add0.advertise_hdl = atoi(argv[1]);
+ svc_info_len = MAX_WFDS_ADV_SVC_INFO_LEN;
+
+ /* Allocate enough memory to hold the full advertisement data */
+ malloc_size = sizeof(*add) + svc_info_len + strlen(cmd->name) + 1;
+ add = malloc(malloc_size);
+ if (!add) {
+ fprintf(stderr, "malloc error, size=%d\n", malloc_size);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+
+ ret = wlu_iovar_getbuf(wl, cmd->name, &add0, sizeof(add0), add, malloc_size);
+ if (ret < 0) {
+ goto exit;
+ }
+
+ /* Print the retrieved advertisement data */
+ printf("Advertise service hdl=%u\n", add->advertise_hdl);
+ printf(" hash=0x%02x%02x%02x%02x%02x%02x\n",
+ add->service_hash[0], add->service_hash[1], add->service_hash[2],
+ add->service_hash[3], add->service_hash[4], add->service_hash[5]);
+ printf(" advertisement_id=0x%x\n", add->advertisement_id);
+ printf(" config_method=0x%x\n", add->service_config_method);
+ printf(" name length=%u\n", add->service_name_len);
+ printf(" name=%s\n", add->service_name);
+ printf(" status=%u\n", add->service_status);
+ printf(" info length=%u\n", add->service_info_len);
+ printf(" info=%s\n", add->service_info);
+ goto exit;
+
+exit:
+ free(add);
+ return ret;
+}
+
+static int
+wl_p2po_wfds_advertise_add(void *wl, cmd_t *cmd, char **argv)
+{
+ int malloc_size;
+ wl_p2po_wfds_advertise_add_t* add = NULL;
+ uint16 svc_info_len = 0;
+ int gen_data_len = 0;
+ int len;
+ int ret;
+ int iovbuf_size;
+ uint8 *iovbuf;
+
+ /* If only an adv_hdl parameter is given, read an existing advertisement */
+ if (!argv[2]) {
+ return wl_p2po_wfds_advertise_get(wl, cmd, argv);
+ }
+
+ if (!argv[6]) {
+ fprintf(stderr, "Too few arguments for iovar SET\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (argv[7]) {
+ svc_info_len = strlen(argv[7]);
+ if (svc_info_len > 7 && memcmp(argv[7], "gendata", 7) == 0) {
+ gen_data_len = atoi((char*)(argv[7] + 7));
+ if (gen_data_len > MAX_WFDS_ADV_SVC_INFO_LEN) {
+ fprintf(stderr, "gendata length %d too long, max is %d\n",
+ gen_data_len, MAX_WFDS_ADV_SVC_INFO_LEN);
+ return BCME_USAGE_ERROR;
+ }
+ svc_info_len = gen_data_len;
+ }
+ }
+
+ malloc_size = sizeof(*add) + svc_info_len;
+ add = malloc(malloc_size);
+ if (!add) {
+ fprintf(stderr, "malloc error, size=%d\n", malloc_size);
+ return BCME_NOMEM;
+ }
+
+ add->advertise_hdl = atoi(argv[1]);
+
+ if (strlen(argv[2]) != 10) {
+ fprintf(stderr, "<adv_id> must be 4 hex bytes, eg. '0x8899aabb'\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ len = wl_pattern_atoh(argv[2], (char*)&add->advertisement_id);
+ if (len != 4) {
+ fprintf(stderr, "<adv_id> must be 4 hex bytes, eg. '0x8899aabb'\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (strlen(argv[3]) != 6) {
+ fprintf(stderr, "<cfg_meth> must be 2 hex bytes, eg. '0x0080'\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ len = wl_pattern_atoh(argv[3], (char*)&add->service_config_method);
+ if (len != 2) {
+ fprintf(stderr, "<cfg_meth> must be 2 hex bytes, eg. '0x0080'\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ if (strlen(argv[4]) != 14) {
+ fprintf(stderr, "Bad <hash> parameter: %s\n", argv[4]);
+ fprintf(stderr, "<hash> must be 6 hex bytes, eg. '0x1133557799aa'\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ len = wl_pattern_atoh(argv[4], (char*)&add->service_hash);
+ if (len != 6) {
+ fprintf(stderr, "Incorrect <hash> parameter: %s\n", argv[4]);
+ fprintf(stderr, "<hash> must be 6 hex bytes, eg. '0x1133557799aa'\n");
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ add->service_name_len = strlen(argv[5]);
+ memcpy(add->service_name, argv[5], add->service_name_len);
+
+ add->service_status = atoi(argv[6]);
+
+ if (svc_info_len) {
+ add->service_info_len = svc_info_len;
+ if (add->service_info_len > MAX_WFDS_ADV_SVC_INFO_LEN)
+ add->service_info_len = MAX_WFDS_ADV_SVC_INFO_LEN;
+ if (gen_data_len == 0)
+ memcpy(add->service_info, argv[7], add->service_info_len);
+ } else {
+ add->service_info_len = 0;
+ }
+
+
+ /* If the service info consists of a magic string of the form
+ * "gendata<N>" then generate N bytes of service info data.
+ * eg. "gendata2048" will generate a 2048 byte service info string
+ * consisting of the repeated string "0123456789".
+ */
+ if (gen_data_len > 0) {
+ int i;
+
+ fprintf(stderr, "Generating %u bytes of service info data\n",
+ add->service_info_len);
+ for (i = 0; i < add->service_info_len; i++) {
+ add->service_info[i] = '0' + (i % 10);
+ }
+ }
+
+ iovbuf_size = malloc_size + strlen(cmd->name) + 1;
+ iovbuf = malloc(iovbuf_size);
+ if (!iovbuf) {
+ fprintf(stderr, "malloc error, size=%d\n", iovbuf_size);
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+ ret = wlu_iovar_setbuf(wl, cmd->name, add, malloc_size, iovbuf, iovbuf_size);
+ free(iovbuf);
+ if (ret != BCME_OK)
+ fprintf(stderr, "%s failed: %d\n", cmd->name, ret);
+exit:
+ free(add);
+ return ret;
+}
+
+static int
+wl_p2po_wfds_advertise_del(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_p2po_wfds_advertise_del_t* del;
+ unsigned int malloc_size = sizeof(*del);
+ int ret;
+
+ del = malloc(malloc_size);
+ if (!del) {
+ fprintf(stderr, "malloc error, size=%u\n", malloc_size);
+ return BCME_NOMEM;
+ }
+
+ if (!argv[1]) {
+ fprintf(stderr, "No advertise_hdl is specified\n");
+ free(del);
+ return BCME_USAGE_ERROR;
+ }
+
+ del->advertise_hdl = atoi(argv[1]);
+ ret = wlu_iovar_setbuf(wl, cmd->name, del, sizeof(*del), buf, WLC_IOCTL_MAXLEN);
+
+ free(del);
+ return ret;
+}
diff --git a/wl/src/wl/exe/wluc_pfn.c b/wl/src/wl/exe/wluc_pfn.c
new file mode 100644
index 0000000..f62844e
--- /dev/null
+++ b/wl/src/wl/exe/wluc_pfn.c
@@ -0,0 +1,2578 @@
+/*
+ * wl pfn command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_pfn.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifdef WIN32
+#define bzero(b, len) memset((b), 0, (len))
+#endif
+
+#ifdef LINUX
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* LINUX */
+
+static cmd_func_t wl_pfn_set;
+static cmd_func_t wl_pfn_add;
+static cmd_func_t wl_pfn_ssid_param;
+static cmd_func_t wl_pfn_add_bssid;
+static cmd_func_t wl_pfn_cfg;
+static cmd_func_t wl_pfn;
+static cmd_func_t wl_pfnbest, wl_pfnbest_bssid;
+static cmd_func_t wl_pfn_suspend;
+static cmd_func_t wl_pfnlbest;
+static cmd_func_t wl_pfn_mem;
+static cmd_func_t wl_pfn_override;
+static cmd_func_t wl_pfn_macaddr;
+#if defined(linux)
+static cmd_func_t wl_pfn_event_check;
+#endif /* linux */
+static cmd_func_t wl_event_filter;
+static cmd_func_t wl_pfn_roam_alert_thresh;
+#ifdef WL_MPF
+static cmd_func_t wl_pfn_mpfset;
+static cmd_func_t wl_mpf_map;
+static cmd_func_t wl_mpf_state;
+#endif /* WL_MPF */
+
+static cmd_t wl_pfn_cmds[] = {
+ { "pfnset", wl_pfn_set, -1, -1,
+ "Configures preferred network offload parameter\n"
+ "\tpfnset syntax is: pfnset [scanfrq xxxxx(30 sec)] [netimeout xxxx(60 sec)]"
+ "[slowfrq xxxx(180 sec)] [bestn (2)|[1-BESTN_MAX]] [mscan (0)|[0-MSCAN_MAX]]"
+ "[bdscan (0)|1] [adapt (off)|[smart, strict, slow]]"
+ "[rssi_delta xxxx(30 dBm)] [sort (listorder)|rssi] [bkgscan (0)|1] [immediateevent (0)|1]"
+ "[immediate 0|(1)] [repeat (10)|[1-20]] [exp (2)|[1-5]] [separate 0|(1)]"
+ "[bestn_bssid (0)|1]"},
+ { "pfnadd", wl_pfn_add, -1, -1,
+ "Adding SSID based preferred networks to monitor and connect\n"
+ "\tpfnadd syntax is: pfnadd ssid <SSID> [hidden (0)|1]"
+ "[imode (bss)|ibss] [same_network (0)|1] [imprecise (0)|1] [trig a|abg|bg]"
+ "[clear] [no_aging (0)|1]"
+ "[amode (open)|shared] [wpa_auth (wpadisabled)|wpapsk|wpa2psk|wpanone|any]"
+ "[wsec WEP|TKIP|AES|TKIPAES] [suppress (neither)|found|lost] [rssi <rssi>(0 dBm)]\n"
+ "Up to 16 SSID networks can be added together in one pfnadd\n"
+ "\tTo specify more than one WPA methods, use a number (same format as wpa_auth iovar) "
+ "as the parameter of wpa_auth (e.g. 0x84 for wpapsk and wpa2psk.)"},
+ { "pfn_ssid_cfg", wl_pfn_ssid_param, WLC_GET_VAR, WLC_SET_VAR,
+ "Adding PFN SSID params to be used to determine FOUND when associated\n"
+ "\tpfn_ssid_cfg syntax is: pfn_ssid_cfg [min5g_rssi <rssi>(-45 dBm)]\n"
+ "\t[min2g_rssi <rssi>(-50 dBm)] [init_score_max (110)]\n"
+ "\t[cur_bssid_bonus (0)] [same_ssid_bonus (0)] [secure_bonus (0)]\n"
+ "\t[band_5g_bonus (0)] [clear]"},
+ { "pfnadd_bssid", wl_pfn_add_bssid, -1, -1,
+ "Adding BSSID based preferred networks to monitor and connect\n"
+ "\tpfnadd_bssid syntax is: pfnadd_bssid bssid <BSSID> [suppress (neither)|found|lost]"
+ "[rssi <rssi>(0 dBm)]\n"
+ "\tUp to 150 BSSIDs can be added together in one pfnadd_bssid"},
+ { "pfncfg", wl_pfn_cfg, -1, -1,
+ "Configures channel list and report type\n"
+ "Usage: pfncfg [channel <list>] [report <type>] [prohibited 1|0] [history_off 1|0]\n"
+ "\treport <type> is ssidonly, bssidonly, or both (default: both)\n"
+ "\tprohibited flag 1: allow and (passively) scan any channel (default 0)"},
+ { "pfn", wl_pfn, -1, -1,
+ "Enable/disable preferred network off load monitoring\n"
+ "\tpfn syntax is: pfn 0|1"},
+ { "pfnclear", wl_var_void, -1, WLC_SET_VAR,
+ "Clear the preferred network list\n"
+ "\tpfnclear syntax is: pfnclear"},
+ { "pfnbest", wl_pfnbest, -1, -1,
+ "Get the best n networks in each of up to m scans, with 16bit timestamp\n"
+ "\tpfnbest syntax is: pfnbest"},
+ { "pfnlbest", wl_pfnlbest, -1, -1,
+ "Get the best n networks in each scan, up to m scans, with 32bit timestamp\n"
+ "\tpfnbest syntax is: pfnlbest"},
+ { "pfnbest_bssid", wl_pfnbest_bssid, -1, -1,
+ "Get the best n networks in each of up to m scans, without ssid\n"
+ "\tpfnbest syntax is: pfnbest_bssid"},
+ { "pfnsuspend", wl_pfn_suspend, -1, -1,
+ "Suspend/resume pno scan\n"
+ "\tpfnsuspend syntax is: pfnsuspend 0|1"},
+ { "pfnmem", wl_pfn_mem, -1, -1,
+ "Get supported mscan with given bestn\n"
+ "\tpfnmem syntax is: pfnmscan bestn [1-BESTN_MAX]"},
+#if defined(linux)
+ { "pfneventchk", wl_pfn_event_check, -1, -1,
+ "Listen and prints the preferred network off load event from dongle\n"
+ "\tpfneventchk syntax is: pfneventchk [ifname]"},
+#endif /* linux */
+ { "event_filter", wl_event_filter, -1, -1,
+ "Set/get event filter\n"
+ "\tevent_filter syntax is: event_filter [value]"},
+ { "pfn_roam_alert_thresh", wl_pfn_roam_alert_thresh, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set PFN and roam alert threshold\n"
+ "\tUsage: wl pfn_roam_alert_thresh [pfn_alert_thresh] [roam_alert_thresh]"
+ },
+ { "pfn_override", wl_pfn_override, WLC_GET_VAR, WLC_SET_VAR,
+ "Temporary override for PNO scan parameters:\n"
+ " pfn_override [<start> <duration> scanfrq <secs> [netimeout <secs>]\n"
+ " [adapt (off | smart | strict | slow)] [repeat cnt>]\n"
+ " [exp <cnt>] [slowfrq <secs>]]\n"
+ " <start> is seconds until these parameters should be activated\n"
+ " <duration> is seconds these parameters should remain in force\n"
+ " Unspecified parameters use the values from pfnset."},
+ { "pfn_macaddr", wl_pfn_macaddr, WLC_GET_VAR, WLC_SET_VAR,
+ "Private MAC address to use as source for PNO scans:\n"
+ " pfn_macaddr [<mac>]"},
+#ifdef WL_MPF
+ { "pfn_mpfset", wl_pfn_mpfset, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set mpf-based pfn parameters\n"
+ " pfn_mpfset <groupid> [state <state> scanfrq <secs> [netimeout <secs>]\n"
+ " [adapt (off | smart | strict | slow)] [repeat <cnt>]\n"
+ " [exp <cnt>] [slowfrq <secs>] ] ...\n"
+ " <groupid> is 0 (SSID list) or 1 (BSSID list)\n"
+ " <state> is 0 thru 3\n"
+ " unspecified states or subparameters us the values from pfnset."},
+ { "mpf_map", wl_mpf_map, WLC_GET_VAR, WLC_SET_VAR,
+ " mpf_map [type <type>] <mask> <val>/<state>[/<name>] ...\n"
+ " <type> must be 0 if present no (effect)\n"
+ " <mask> and <val> are 16-bit hex values, max 1s allowed: 3\n"
+ " <state> is a small number, 0 thru N-1 (N is # of bit combos)\n"
+ " <name> is an optional string name for the state"},
+ { "mpf_state", wl_mpf_state, WLC_GET_VAR, WLC_SET_VAR,
+ " mpf_state [type <type>] [<state> | <name> | gpio ]\n"
+ " <mpf_state [type <type>] [<state> | <name> | gpio ]\n"
+ " <type> must be 0 if present no (effect)\n"
+ " <state> or <name>, if specified, override current value,\n"
+ " setting gpio returns to simply tracking hardware state"},
+#endif /* WL_MPF */
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_pfn_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register pfn commands */
+ wl_module_cmds_register(wl_pfn_cmds);
+}
+
+static int
+wl_pfn_set(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_pfn_param_t pfn_param;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* Setup default values */
+ pfn_param.version = PFN_VERSION;
+ /* Sorting based on list order, no back ground scan, no autoswitch,
+ * no immediate event report, no adaptvie scan, but immediate scan
+ */
+ pfn_param.flags = (PFN_LIST_ORDER << SORT_CRITERIA_BIT | ENABLE << IMMEDIATE_SCAN_BIT);
+ /* Scan frequency of 30 sec */
+ pfn_param.scan_freq = 30;
+ /* slow adapt scan is off by default */
+ pfn_param.slow_freq = 0;
+ /* RSSI margin of 30 dBm */
+ pfn_param.rssi_margin = 30;
+ /* Network timeout 60 sec */
+ pfn_param.lost_network_timeout = 60;
+ /* best n = 2 by default */
+ pfn_param.bestn = DEFAULT_BESTN;
+ /* mscan m=0 by default, so not record best networks by default */
+ pfn_param.mscan = DEFAULT_MSCAN;
+ /* default repeat = 10 */
+ pfn_param.repeat = DEFAULT_REPEAT;
+ /* by default, maximum scan interval = 2^2*scan_freq when adaptive scan is turned on */
+ pfn_param.exp = DEFAULT_EXP;
+
+ while (*++argv) {
+ if (!stricmp(*argv, "scanfrq")) {
+ if (*++argv)
+ pfn_param.scan_freq = atoi(*argv);
+ else {
+ fprintf(stderr, "Missing scanfrq option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "netimeout")) {
+ if (*++argv)
+ pfn_param.lost_network_timeout = atoi(*argv);
+ else {
+ fprintf(stderr, "Missing netimeout option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "rssi_delta")) {
+ if (*++argv)
+ pfn_param.rssi_margin = atoi(*argv);
+ else {
+ fprintf(stderr, "Missing rssi_delta option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "sort")) {
+ if (*++argv) {
+ pfn_param.flags &= ~SORT_CRITERIA_MASK;
+ if (!stricmp(*argv, "listorder"))
+ pfn_param.flags |= (PFN_LIST_ORDER << SORT_CRITERIA_BIT);
+ else if (!stricmp(*argv, "rssi"))
+ pfn_param.flags |= (PFN_RSSI << SORT_CRITERIA_BIT);
+ else {
+ fprintf(stderr, "Invalid sort option %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ } else {
+ fprintf(stderr, "Missing sort option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "immediateevent")) {
+ if (*++argv) {
+ if (!stricmp(*argv, "1")) {
+ pfn_param.flags |= IMMEDIATE_EVENT_MASK;
+ } else if (!stricmp(*argv, "0")) {
+ pfn_param.flags &= ~IMMEDIATE_EVENT_MASK;
+ } else {
+ fprintf(stderr, "Invalid immediateevent option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else {
+ fprintf(stderr, "Missing immediateevent option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "bkgscan")) {
+ if (*++argv) {
+ pfn_param.flags &= ~ENABLE_BKGRD_SCAN_MASK;
+ if (atoi(*argv))
+ pfn_param.flags |= (ENABLE << ENABLE_BKGRD_SCAN_BIT);
+ else
+ pfn_param.flags |= (DISABLE << ENABLE_BKGRD_SCAN_BIT);
+ } else {
+ fprintf(stderr, "Missing bkgscan option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "immediate")) {
+ pfn_param.flags &= ~IMMEDIATE_SCAN_MASK;
+ if (*++argv) {
+ if (atoi(*argv))
+ pfn_param.flags |= (ENABLE << IMMEDIATE_SCAN_BIT);
+ else
+ pfn_param.flags |= (DISABLE << IMMEDIATE_SCAN_BIT);
+ } else {
+ fprintf(stderr, "Missing immediate option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "bdscan")) {
+ if (*++argv) {
+ pfn_param.flags &= ~ENABLE_BD_SCAN_MASK;
+ if (atoi(*argv))
+ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT);
+ else
+ pfn_param.flags |= (DISABLE << ENABLE_BD_SCAN_BIT);
+ } else {
+ fprintf(stderr, "Missing bdscan option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "separate")) {
+ if (*++argv) {
+ pfn_param.flags &= ~REPORT_SEPERATELY_MASK;
+ if (atoi(*argv))
+ pfn_param.flags |= (ENABLE << REPORT_SEPERATELY_BIT);
+ else
+ pfn_param.flags |= (DISABLE << REPORT_SEPERATELY_BIT);
+ } else {
+ fprintf(stderr, "Missing seperate option\n");
+ return -1;
+ }
+ } else if (!stricmp(*argv, "adapt")) {
+ if (*++argv) {
+ pfn_param.flags &= ~ENABLE_ADAPTSCAN_MASK;
+ if (!stricmp(*argv, "off")) {
+ pfn_param.flags |= (OFF_ADAPT << ENABLE_ADAPTSCAN_BIT);
+ } else if (!stricmp(*argv, "smart")) {
+ pfn_param.flags |= (SMART_ADAPT << ENABLE_ADAPTSCAN_BIT);
+ } else if (!stricmp(*argv, "strict")) {
+ pfn_param.flags |= (STRICT_ADAPT << ENABLE_ADAPTSCAN_BIT);
+ } else if (!stricmp(*argv, "slow")) {
+ pfn_param.flags |= (SLOW_ADAPT << ENABLE_ADAPTSCAN_BIT);
+ } else {
+ fprintf(stderr, "Invalid adaptive scan option %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ } else {
+ fprintf(stderr, "Missing adaptive scan option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "bestn")) {
+ pfn_param.bestn = atoi(*++argv);
+ } else if (!stricmp(*argv, "mscan")) {
+ pfn_param.mscan = atoi(*++argv);
+ } else if (!stricmp(*argv, "repeat")) {
+ pfn_param.repeat = atoi(*++argv);
+ if (pfn_param.repeat < 1 || pfn_param.repeat > 20) {
+ fprintf(stderr, "repeat %d out of range (1-20)\n",
+ pfn_param.repeat);
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "exp")) {
+ pfn_param.exp = atoi(*++argv);
+ if (pfn_param.exp < 1 || pfn_param.exp > 5) {
+ fprintf(stderr, "exp %d out of range (1-5)\n",
+ pfn_param.exp);
+ return BCME_BADARG;
+ }
+ } else if (!stricmp(*argv, "slowfrq")) {
+ if (*++argv)
+ pfn_param.slow_freq = atoi(*argv);
+ else {
+ fprintf(stderr, "Missing slowfrq option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "bestn_bssid")) {
+ if (*++argv) {
+ pfn_param.flags &= ~BESTN_BSSID_ONLY_MASK;
+ if (atoi(*argv))
+ pfn_param.flags |= (ENABLE << BESTN_BSSID_ONLY_BIT);
+ else
+ pfn_param.flags |= (DISABLE << BESTN_BSSID_ONLY_BIT);
+ } else {
+ fprintf(stderr, "Missing bestn_bssid option\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else {
+ fprintf(stderr, "Invalid parameter %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ if ((((pfn_param.flags & ENABLE_ADAPTSCAN_MASK) ==
+ (SLOW_ADAPT << ENABLE_ADAPTSCAN_BIT)) &&
+ !pfn_param.slow_freq) ||
+ (((pfn_param.flags & ENABLE_ADAPTSCAN_MASK) !=
+ (SLOW_ADAPT << ENABLE_ADAPTSCAN_BIT)) &&
+ pfn_param.slow_freq)) {
+ fprintf(stderr, "SLOW_ADAPT flag and slowfrq value not match\n");
+ return BCME_BADARG;
+ }
+ pfn_param.version = htod32(pfn_param.version);
+ pfn_param.scan_freq = htod32(pfn_param.scan_freq);
+ pfn_param.lost_network_timeout = htod32(pfn_param.lost_network_timeout);
+ pfn_param.flags = htod16(pfn_param.flags);
+ pfn_param.rssi_margin = htod16(pfn_param.rssi_margin);
+ pfn_param.slow_freq = htod32(pfn_param.slow_freq);
+
+ if ((err = wlu_iovar_set(wl, "pfn_set", &pfn_param, sizeof(wl_pfn_param_t))))
+ return (err);
+
+ return (0);
+}
+
+static bool
+validate_hex(char hexchar)
+{
+ if ((hexchar >= '0' && hexchar <= '9') ||
+ (hexchar >= 'a' || hexchar <= 'z') ||
+ (hexchar >= 'A' || hexchar <= 'Z'))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static uint8
+char2hex(char hexchar)
+{
+ if (hexchar >= '0' && hexchar <= '9')
+ return (hexchar - '0');
+ else if (hexchar >= 'a' && hexchar <= 'f')
+ return (hexchar - 'a' + 10);
+ else if (hexchar >= 'A' && hexchar <= 'F')
+ return (hexchar - 'A' + 10);
+ else
+ {
+ fprintf(stderr, "non-hex\n");
+ return 0xff;
+ }
+}
+
+#define MAXNUM_SSID_PER_ADD 16
+
+static int
+wl_pfn_add(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_pfn_t *p_pfn_element = NULL;
+ int i, pfn_element_len, cnt;
+ wl_pfn_t *pssidnet = NULL;
+ uint32 val;
+
+ UNUSED_PARAMETER(cmd);
+
+ pfn_element_len = MAXNUM_SSID_PER_ADD * sizeof(wl_pfn_t);
+ p_pfn_element = (wl_pfn_t *)malloc(pfn_element_len);
+ if (p_pfn_element == NULL) {
+ fprintf(stderr, "Failed to allocate buffer for %d bytes\n", pfn_element_len);
+ return BCME_NOMEM;
+ }
+ memset(p_pfn_element, '\0', pfn_element_len);
+
+ pssidnet = p_pfn_element;
+ for (i = 0; i < MAXNUM_SSID_PER_ADD; i++) {
+ /* Default setting, open, no WPA, no WEP and bss */
+ pssidnet->auth = DOT11_OPEN_SYSTEM;
+ pssidnet->wpa_auth = WPA_AUTH_DISABLED;
+ pssidnet->wsec = 0;
+ pssidnet->infra = 1;
+ pssidnet->flags = 0;
+ pssidnet++;
+ }
+ cnt = -1;
+ pssidnet = p_pfn_element;
+ while (*++argv) {
+ if (!stricmp(*argv, "ssid")) {
+ if (*++argv) {
+ if (++cnt >= MAXNUM_SSID_PER_ADD) {
+ fprintf(stderr, "exceed max 16 SSID per pfn_add\n");
+ err = BCME_BADARG;
+ goto error;
+ }
+ if (cnt > 0) {
+ pssidnet->flags = htod32(pssidnet->flags);
+ pssidnet++;
+ }
+ strncpy((char *)pssidnet->ssid.SSID, *argv,
+ sizeof(pssidnet->ssid.SSID));
+ pssidnet->ssid.SSID_len =
+ strlen((char *)pssidnet->ssid.SSID);
+ if (pssidnet->ssid.SSID_len > 32) {
+ fprintf(stderr, "SSID too long: %s\n", *argv);
+ err = BCME_BADARG;
+ goto error;
+ }
+ pssidnet->ssid.SSID_len = htod32(pssidnet->ssid.SSID_len);
+ } else {
+ fprintf(stderr, "no value for ssid\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ }
+ else if (!stricmp(*argv, "hidden")) {
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ if (*++argv) {
+ val = **argv - '0';
+ if (val != ENABLE && val != DISABLE) {
+ fprintf(stderr, "invalid hidden setting, use 0/1\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ pssidnet->flags |= val << WL_PFN_HIDDEN_BIT;
+ } else {
+ fprintf(stderr, "no value for hidden\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "imode")) {
+ if (*++argv) {
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ if (!stricmp(*argv, "bss")) {
+ pssidnet->infra = 1;
+ } else if (!stricmp(*argv, "ibss")) {
+ pssidnet->infra = 0;
+ } else {
+ fprintf(stderr, "Invalid imode arg %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ pssidnet->infra = htod32(pssidnet->infra);
+ } else {
+ fprintf(stderr, "Missing option for imode\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "amode")) {
+ if (*++argv) {
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ if (!stricmp(*argv, "open"))
+ pssidnet->auth = DOT11_OPEN_SYSTEM;
+ else if (!stricmp(*argv, "shared"))
+ pssidnet->auth = DOT11_SHARED_KEY;
+ else {
+ fprintf(stderr, "Invalid imode arg %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ pssidnet->auth = htod32(pssidnet->auth);
+ } else {
+ fprintf(stderr, "Missing option for amode\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "wpa_auth")) {
+ if (*++argv) {
+ uint32 wpa_auth;
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+
+ /* figure requested auth, allow "any" */
+ if (!stricmp(*argv, "wpapsk"))
+ pssidnet->wpa_auth = WPA_AUTH_PSK;
+ else if (!stricmp(*argv, "wpa2psk"))
+ pssidnet->wpa_auth = WPA2_AUTH_PSK;
+ else if (!stricmp(*argv, "wpadisabled"))
+ pssidnet->wpa_auth = WPA_AUTH_DISABLED;
+ else if (!stricmp(*argv, "any"))
+ pssidnet->wpa_auth = (uint16)WPA_AUTH_PFN_ANY;
+ else if ((wpa_auth = strtoul(*argv, 0, 0)))
+ pssidnet->wpa_auth = wpa_auth;
+ else {
+ fprintf(stderr, "Invalid wpa_auth option %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ pssidnet->wpa_auth = htod32(pssidnet->wpa_auth);
+ } else {
+ fprintf(stderr, "Missing option for wpa_auth\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "wsec")) {
+ if (*++argv) {
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ if (!stricmp(*argv, "WEP")) {
+ pssidnet->wsec = WEP_ENABLED;
+ } else if (!stricmp(*argv, "TKIP"))
+ pssidnet->wsec = TKIP_ENABLED;
+ else if (!stricmp(*argv, "AES"))
+ pssidnet->wsec = AES_ENABLED;
+ else if (!stricmp(*argv, "TKIPAES"))
+ pssidnet->wsec = TKIP_ENABLED | AES_ENABLED;
+ else {
+ fprintf(stderr, "Invalid wsec option %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ pssidnet->wsec = htod32(pssidnet->wsec);
+ } else {
+ fprintf(stderr, "Missing option for wsec\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "suppress")) {
+ if (*++argv) {
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ if (!stricmp(*argv, "found")) {
+ pssidnet->flags |= WL_PFN_SUPPRESSFOUND_MASK;
+ } else if (!stricmp(*argv, "lost")) {
+ pssidnet->flags |= WL_PFN_SUPPRESSLOST_MASK;
+ } else if (!stricmp(*argv, "neither")) {
+ pssidnet->flags &=
+ ~(WL_PFN_SUPPRESSLOST_MASK | WL_PFN_SUPPRESSFOUND_MASK);
+ } else {
+ fprintf(stderr, "Invalid suppress option %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "Missing option for suppress\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "rssi")) {
+ if (*++argv) {
+ int rssi = atoi(*argv);
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ if (rssi >= -128 && rssi <= 0) {
+ pssidnet->flags |= (rssi << WL_PFN_RSSI_SHIFT)
+ & WL_PFN_RSSI_MASK;
+ } else {
+ fprintf(stderr, "Invalid rssi option %s\n", *argv);
+ err = BCME_BADARG;
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "Missing option for rssi\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "trig")) {
+ if (*++argv) {
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ if (!stricmp(*argv, "a")) {
+ pssidnet->flags |= WL_PFN_SSID_A_BAND_TRIG;
+ } else if (!stricmp(*argv, "bg")) {
+ pssidnet->flags |= WL_PFN_SSID_BG_BAND_TRIG;
+ } else if (!stricmp(*argv, "abg")) {
+ pssidnet->flags |=
+ (WL_PFN_SSID_A_BAND_TRIG | WL_PFN_SSID_BG_BAND_TRIG);
+ } else {
+ fprintf(stderr, "Invalid trigger option %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "Missing option for trigger\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "same_network")) {
+ if (*++argv) {
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ val = **argv - '0';
+ if (val != ENABLE && val != DISABLE) {
+ fprintf(stderr, "invalid same_network setting, use 0/1\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ if (val) {
+ pssidnet->flags |= WL_PFN_SSID_SAME_NETWORK;
+ }
+ } else {
+ fprintf(stderr, "Missing option for same_network\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "no_aging")) {
+ if (*++argv) {
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ val = **argv - '0';
+ if (val != ENABLE && val != DISABLE) {
+ fprintf(stderr, "invalid same_network setting, use 0/1\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ if (val) {
+ pssidnet->flags |= WL_PFN_SUPPRESS_AGING_MASK;
+ }
+ } else {
+ fprintf(stderr, "Missing option for same_network\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "imprecise")) {
+ if (*++argv) {
+ if (pssidnet->ssid.SSID_len == 0) {
+ fprintf(stderr, "Wrong! Start with SSID\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ val = **argv - '0';
+ if (val != ENABLE && val != DISABLE) {
+ fprintf(stderr, "invalid imprecise setting, use 0/1\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ if (val) {
+ pssidnet->flags |= WL_PFN_SSID_IMPRECISE_MATCH;
+ }
+ } else {
+ fprintf(stderr, "Missing option for imprecise match\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "clear")) {
+ if (*++argv) {
+ if (cnt >= 1) {
+ fprintf(stderr, "Will only clear, ssids ignored\n");
+ }
+ cnt = 0;
+ pssidnet = p_pfn_element;
+ pssidnet->flags = WL_PFN_FLUSH_ALL_SSIDS;
+ } else {
+ fprintf(stderr, "Missing option for clear\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "Invalid parameter %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ }
+ pssidnet->flags = htod32(pssidnet->flags);
+
+ pfn_element_len = (cnt + 1) * sizeof(wl_pfn_t);
+ if ((err = wlu_iovar_set(wl, "pfn_add", p_pfn_element,
+ pfn_element_len))) {
+ fprintf(stderr, "pfn_add fail\n");
+ goto error;
+ }
+ free(p_pfn_element);
+ return (0);
+
+error:
+ free(p_pfn_element);
+ return err;
+}
+
+#define DEFAULT_INIT_SCORE_MAX 110
+#define DEFAULT_MIN_5G_RSSI -45
+#define DEFAULT_MIN_2G_RSSI -50
+
+static int
+wl_pfn_ssid_param(void *wl, cmd_t *cmd, char **argv)
+{
+ int i = 0, err = BCME_OK;
+ wl_pfn_ssid_cfg_t cfg;
+ char *endptr = NULL;
+ uint16 val;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* process a GET */
+ if (!*(argv + 1)) {
+ if (cmd->get < 0)
+ return -1;
+ memset(&cfg, 0, sizeof(cfg));
+ if ((err = wlu_iovar_get(wl, "pfn_ssid_cfg", (void *)&cfg,
+ sizeof(wl_pfn_ssid_cfg_t))) < 0) {
+ fprintf(stderr, "Failed to get pfn_ssid_cfg %d\n", err);
+ return err;
+ }
+ if (cfg.version != WL_PFN_SSID_CFG_VERSION) {
+ fprintf(stderr, "Mismatched version expected %d, got %d\n",
+ WL_PFN_SSID_CFG_VERSION, cfg.version);
+ return err;
+ }
+ fprintf(stderr, "min2G_rssi %d min5G_rssi %d init_score_max %d\n",
+ cfg.params.min2G_rssi, cfg.params.min5G_rssi,
+ dtoh16(cfg.params.init_score_max));
+ fprintf(stderr, "band_5g_bonus %d secure_bonus %d same_ssid_bonus %d\n",
+ dtoh16(cfg.params.band_5g_bonus), dtoh16(cfg.params.secure_bonus),
+ dtoh16(cfg.params.same_ssid_bonus));
+ fprintf(stderr, "cur_bssid_bonus %d\n", dtoh16(cfg.params.cur_bssid_bonus));
+ return 0;
+ }
+
+ /* process a SET */
+ cfg.version = htod16(WL_PFN_SSID_CFG_VERSION);
+ cfg.flags = 0;
+ cfg.params.band_5g_bonus = 0;
+ cfg.params.secure_bonus = 0;
+ cfg.params.same_ssid_bonus = 0;
+ cfg.params.init_score_max = htod16(DEFAULT_INIT_SCORE_MAX);
+ cfg.params.cur_bssid_bonus = 0;
+ cfg.params.min2G_rssi = DEFAULT_MIN_2G_RSSI;
+ cfg.params.min5G_rssi = DEFAULT_MIN_5G_RSSI;
+ while (*++argv) {
+ if (!stricmp(*argv, "min5g_rssi")) {
+ if (*++argv) {
+ int rssi = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ if (rssi >= -128 && rssi <= 0) {
+ cfg.params.min5G_rssi = rssi;
+ } else {
+ fprintf(stderr, "Invalid rssi option %s\n", *argv);
+ err = BCME_BADARG;
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "Missing option for rssi\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+
+ } else if (!stricmp(*argv, "min2g_rssi")) {
+ if (*++argv) {
+ int rssi = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ if (rssi >= -128 && rssi <= 0) {
+ cfg.params.min2G_rssi = rssi;
+ } else {
+ fprintf(stderr, "Invalid rssi option %s\n", *argv);
+ err = BCME_BADARG;
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "Missing option for rssi\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "init_score_max")) {
+ if (*++argv) {
+ val = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ cfg.params.init_score_max = htod16(val);
+ } else {
+ fprintf(stderr, "Missing option for init_score_max\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "cur_bssid_bonus")) {
+ if (*++argv) {
+ val = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ cfg.params.cur_bssid_bonus = htod16(val);
+ } else {
+ fprintf(stderr, "Missing option for cur_bssid_bonus\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+
+ } else if (!stricmp(*argv, "same_ssid_bonus")) {
+ if (*++argv) {
+ val = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ cfg.params.same_ssid_bonus = htod16(val);
+ } else {
+ fprintf(stderr, "Missing option for same_ssid_bonus\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+
+ } else if (!stricmp(*argv, "secure_bonus")) {
+ if (*++argv) {
+ val = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ cfg.params.secure_bonus = htod16(val);
+ } else {
+ fprintf(stderr, "Missing option for secure_bonus\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "band_5g_bonus")) {
+ if (*++argv) {
+ val = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ cfg.params.band_5g_bonus = htod16(val);
+ } else {
+ fprintf(stderr, "Missing option for band_5g_bonus\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+
+ } else if (!stricmp(*argv, "clear")) {
+ cfg.flags = WL_PFN_SSID_CFG_CLEAR;
+ if (i) {
+ fprintf(stderr, "Params will ONLY be cleared\n");
+ }
+ }
+ i++;
+ }
+ if ((err = wlu_iovar_set(wl, "pfn_ssid_cfg", &cfg,
+ sizeof(wl_pfn_ssid_cfg_t)))) {
+ fprintf(stderr, "Failed to set pfn_ssid_cfg %d\n", err);
+ }
+error:
+ return err;
+}
+
+#define MAXNUM_BSSID_PER_ADD 180
+
+static int
+wl_pfn_add_bssid(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ uint8 *ptr;
+ int i, bssidlistlen, cnt;
+ wl_pfn_bssid_t *bssidlist;
+ wl_pfn_bssid_t *pbssid = NULL;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!*(argv + 1)) {
+ fprintf(stderr, "Invalid command\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ bssidlistlen = MAXNUM_BSSID_PER_ADD * sizeof(wl_pfn_bssid_t);
+ bssidlist = (wl_pfn_bssid_t *)malloc(bssidlistlen);
+ if (bssidlist == NULL) {
+ fprintf(stderr, "Failed to allocate buffer for %d bytes\n", bssidlistlen);
+ return BCME_NOMEM;
+ }
+ memset(bssidlist, '\0', bssidlistlen);
+
+ cnt = 0;
+ while (*++argv) {
+ if (!stricmp(*argv, "bssid")) {
+ if (*++argv) {
+ if (cnt >= MAXNUM_BSSID_PER_ADD) {
+ fprintf(stderr, "exceed max %d BSSID per pfn_add_bssid\n",
+ MAXNUM_BSSID_PER_ADD);
+ err = BCME_BADARG;
+ goto error;
+ }
+ if (!cnt)
+ pbssid = bssidlist;
+ else {
+ pbssid->flags = htod16(pbssid->flags);
+ pbssid++;
+ }
+
+ ptr = (uint8 *)*argv;
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ {
+ if (!validate_hex(*ptr) || !validate_hex(*(ptr + 1)))
+ {
+ fprintf(stderr, "non-hex in BSSID\n");
+ err = BCME_BADARG;
+ goto error;
+ }
+ pbssid->macaddr.octet[i] =
+ char2hex(*ptr) << 4 | char2hex(*(ptr+1));
+ ptr += 3;
+ }
+ cnt++;
+ } else {
+ fprintf(stderr, "Missing option for bssid\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "suppress")) {
+ if (!pbssid || ETHER_ISNULLADDR(pbssid->macaddr.octet)) {
+ fprintf(stderr, "Wrong! Start with BSSID\n");
+ err = BCME_BADARG;
+ goto error;
+ }
+ if (*++argv) {
+ if (!stricmp(*argv, "found")) {
+ pbssid->flags |= WL_PFN_SUPPRESSFOUND_MASK;
+ } else if (!stricmp(*argv, "lost")) {
+ pbssid->flags |= WL_PFN_SUPPRESSLOST_MASK;
+ } else if (!stricmp(*argv, "neither")) {
+ pbssid->flags &=
+ ~(WL_PFN_SUPPRESSFOUND_MASK | WL_PFN_SUPPRESSLOST_MASK);
+ } else {
+ fprintf(stderr, "Invalid suppress option %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "Missing option for suppress\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else if (!stricmp(*argv, "rssi")) {
+ if (*++argv) {
+ int rssi = atoi(*argv);
+ if (!pbssid || ETHER_ISNULLADDR(pbssid->macaddr.octet)) {
+ fprintf(stderr, "Wrong! Start with BSSID\n");
+ err = BCME_BADARG;
+ goto error;
+ }
+ if (rssi >= -128 && rssi <= 0) {
+ pbssid->flags |= (rssi << WL_PFN_RSSI_SHIFT)
+ & WL_PFN_RSSI_MASK;
+ } else {
+ fprintf(stderr, "Invalid rssi option %s\n", *argv);
+ err = BCME_BADARG;
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "Missing option for rssi\n");
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "Invalid parameter %s\n", *argv);
+ err = BCME_USAGE_ERROR;
+ goto error;
+ }
+ }
+ pbssid->flags = htod16(pbssid->flags);
+
+ bssidlistlen = cnt * sizeof(wl_pfn_bssid_t);
+ if ((err = wlu_iovar_setbuf(wl, "pfn_add_bssid", bssidlist,
+ bssidlistlen, buf, ETHER_MAX_LEN))) {
+ fprintf(stderr, "pfn_add_bssid fail\n");
+ goto error;
+ }
+ free(bssidlist);
+ return 0;
+
+error:
+ free(bssidlist);
+ return err;
+}
+
+static int
+wl_pfn_cfg(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_pfn_cfg_t pfncfg_param;
+ int nchan = 0;
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+
+ memset(&pfncfg_param, '\0', sizeof(wl_pfn_cfg_t));
+
+ /* Setup default values */
+ pfncfg_param.reporttype = WL_PFN_REPORT_ALLNET;
+ pfncfg_param.channel_num = 0;
+
+ while (*++argv) {
+ if (!stricmp(*argv, "report")) {
+ if (*++argv) {
+ if (!stricmp(*argv, "all")) {
+ pfncfg_param.reporttype = WL_PFN_REPORT_ALLNET;
+ } else if (!stricmp(*argv, "ssidonly")) {
+ pfncfg_param.reporttype = WL_PFN_REPORT_SSIDNET;
+ } else if (!stricmp(*argv, "bssidonly")) {
+ pfncfg_param.reporttype = WL_PFN_REPORT_BSSIDNET;
+ } else {
+ fprintf(stderr, "Invalid report option %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ } else {
+ fprintf(stderr, "no value for report\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "channel")) {
+ if (*++argv) {
+ nchan = wl_parse_channel_list(*argv, pfncfg_param.channel_list,
+ WL_NUMCHANNELS);
+ if (nchan < 0) {
+ fprintf(stderr, "error parsing channel\n");
+ return BCME_BADARG;
+ }
+ } else {
+ fprintf(stderr, "Missing option for channel\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "prohibited")) {
+ if (*++argv) {
+ pfncfg_param.flags &= ~WL_PFN_CFG_FLAGS_PROHIBITED;
+ if (atoi(*argv))
+ pfncfg_param.flags |= WL_PFN_CFG_FLAGS_PROHIBITED;
+ } else {
+ fprintf(stderr, "Missing prohibited option value\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (!stricmp(*argv, "history_off")) {
+ if (*++argv) {
+ pfncfg_param.flags &= ~WL_PFN_CFG_FLAGS_HISTORY_OFF;
+ if (atoi(*argv))
+ pfncfg_param.flags |= WL_PFN_CFG_FLAGS_HISTORY_OFF;
+ } else {
+ fprintf(stderr, "Missing history_off option value\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else {
+ fprintf(stderr, "Invalid parameter %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ pfncfg_param.reporttype = htod32(pfncfg_param.reporttype);
+ pfncfg_param.channel_num = htod32(nchan);
+ pfncfg_param.flags = htod32(pfncfg_param.flags);
+
+ if ((err = wlu_iovar_set(wl, "pfn_cfg", &pfncfg_param,
+ sizeof(wl_pfn_cfg_t)))) {
+ fprintf(stderr, "pfn_cfg fail\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+wl_pfn(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, val;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) {
+ val = atoi(*argv);
+ err = wlu_iovar_setint(wl, "pfn", (val ? 1 : 0));
+ } else {
+ err = wlu_iovar_getint(wl, "pfn", &val);
+ if (!err)
+ wl_printint(val);
+ }
+
+ return err;
+}
+
+/* Use MEDLEN for efficient read, pre-calculate maximum possible nets for later checks */
+#define WL_MAX_BESTNET_V1 ((WLC_IOCTL_MEDLEN - OFFSETOF(wl_pfn_scanresults_v1_t, netinfo)) \
+ / sizeof(wl_pfn_net_info_v1_t))
+#define WL_MAX_BESTNET_V2 ((WLC_IOCTL_MEDLEN - OFFSETOF(wl_pfn_scanresults_v2_t, netinfo)) \
+ / sizeof(wl_pfn_net_info_v2_t))
+
+static int
+wl_pfnbest(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_pfn_scanresults_v1_t *bestnet_v1;
+ wl_pfn_net_info_v1_t *netinfo_v1;
+ wl_pfn_scanresults_v2_t *bestnet_v2;
+ wl_pfn_net_info_v2_t *netinfo_v2;
+ uint status;
+ uint32 i, j;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) {
+ fprintf(stderr, "Invalid parameter %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Use generic buffer to read and parse results */
+ bestnet_v1 = (wl_pfn_scanresults_v1_t *)buf;
+ bestnet_v2 = (wl_pfn_scanresults_v2_t *)buf;
+
+ /* Read results until completion indicated */
+ do {
+ bzero(buf, WLC_IOCTL_MEDLEN);
+
+ if ((err = wlu_iovar_get(wl, "pfnbest", (void*)buf, WLC_IOCTL_MEDLEN))) {
+ fprintf(stderr, "pfnbest fail\n");
+ return err;
+ }
+
+ if (bestnet_v2->version == PFN_SCANRESULTS_VERSION_V2) {
+ /* Use version 2 variables for processing */
+ status = bestnet_v2->status;
+ if (bestnet_v2->count > WL_MAX_BESTNET_V2) {
+ fprintf(stderr, "Invalid data, count %d exceeds max buflen\n",
+ bestnet_v2->count);
+ return BCME_ERROR;
+ }
+
+ printf("ver %d, status %d, count %d\n",
+ bestnet_v2->version, bestnet_v2->status, bestnet_v2->count);
+ netinfo_v2 = bestnet_v2->netinfo;
+ for (i = 0; i < bestnet_v2->count; i++) {
+ for (j = 0; j < netinfo_v2->pfnsubnet.SSID_len; j++)
+ printf("%c", netinfo_v2->pfnsubnet.u.SSID[j]);
+ printf("\n");
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ netinfo_v2->pfnsubnet.BSSID.octet[0],
+ netinfo_v2->pfnsubnet.BSSID.octet[1],
+ netinfo_v2->pfnsubnet.BSSID.octet[2],
+ netinfo_v2->pfnsubnet.BSSID.octet[3],
+ netinfo_v2->pfnsubnet.BSSID.octet[4],
+ netinfo_v2->pfnsubnet.BSSID.octet[5]);
+ printf("channel: %d, RSSI: %d, timestamp: %d\n",
+ netinfo_v2->pfnsubnet.channel, netinfo_v2->RSSI,
+ netinfo_v2->timestamp);
+ netinfo_v2++;
+ }
+ } else if (bestnet_v1->version == PFN_SCANRESULTS_VERSION_V1) {
+ /* Use version 1 variables for processing */
+ status = bestnet_v1->status;
+ if (bestnet_v1->count > WL_MAX_BESTNET_V1) {
+ fprintf(stderr, "Invalid data, count %d exceeds max buflen\n",
+ bestnet_v1->count);
+ return BCME_ERROR;
+ }
+
+ printf("ver %d, status %d, count %d\n",
+ bestnet_v1->version, bestnet_v1->status, bestnet_v1->count);
+ netinfo_v1 = bestnet_v1->netinfo;
+ for (i = 0; i < bestnet_v1->count; i++) {
+ for (j = 0; j < netinfo_v1->pfnsubnet.SSID_len; j++)
+ printf("%c", netinfo_v1->pfnsubnet.SSID[j]);
+ printf("\n");
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ netinfo_v1->pfnsubnet.BSSID.octet[0],
+ netinfo_v1->pfnsubnet.BSSID.octet[1],
+ netinfo_v1->pfnsubnet.BSSID.octet[2],
+ netinfo_v1->pfnsubnet.BSSID.octet[3],
+ netinfo_v1->pfnsubnet.BSSID.octet[4],
+ netinfo_v1->pfnsubnet.BSSID.octet[5]);
+ printf("channel: %d, RSSI: %d, timestamp: %d\n",
+ netinfo_v1->pfnsubnet.channel, netinfo_v1->RSSI,
+ netinfo_v1->timestamp);
+ netinfo_v1++;
+ }
+ } else {
+ fprintf(stderr, "Unrecognized version %d\n", bestnet_v1->version);
+ return BCME_ERROR;
+ }
+ } while (status != PFN_COMPLETE);
+
+ return 0;
+}
+
+/* Use MEDLEN for efficient read, pre-calculate maximum possible nets for later checks */
+#define WL_MAX_LBESTNET_V1 ((WLC_IOCTL_MEDLEN - OFFSETOF(wl_pfn_lscanresults_v1_t, netinfo)) \
+ / sizeof(wl_pfn_net_info_v1_t))
+#define WL_MAX_LBESTNET_V2 ((WLC_IOCTL_MEDLEN - OFFSETOF(wl_pfn_lscanresults_v2_t, netinfo)) \
+ / sizeof(wl_pfn_lnet_info_v2_t))
+
+static int
+wl_pfnlbest(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_pfn_lscanresults_v1_t *bestnet_v1;
+ wl_pfn_lnet_info_v1_t *netinfo_v1;
+ wl_pfn_lscanresults_v2_t *bestnet_v2;
+ wl_pfn_lnet_info_v2_t *netinfo_v2;
+ uint status;
+ uint32 i, j;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) {
+ fprintf(stderr, "Invalid parameter %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Use generic buffer to read and parse results */
+ bestnet_v1 = (wl_pfn_lscanresults_v1_t *)buf;
+ bestnet_v2 = (wl_pfn_lscanresults_v2_t *)buf;
+
+ /* Read results until completion indicated */
+ do {
+ bzero(buf, WLC_IOCTL_MEDLEN);
+
+ if ((err = wlu_iovar_get(wl, "pfnlbest", (void *)buf, WLC_IOCTL_MEDLEN))) {
+ fprintf(stderr, "pfnlbest fail\n");
+ return err;
+ }
+
+ if (bestnet_v2->version == PFN_LBEST_SCAN_RESULT_VERSION_V2) {
+ /* Use version 2 variables for processing */
+ status = bestnet_v2->status;
+ if (bestnet_v2->count > WL_MAX_LBESTNET_V2) {
+ fprintf(stderr, "Invalid data, count %d exceeds max buflen\n",
+ bestnet_v2->count);
+ return BCME_ERROR;
+ }
+
+ printf("ver %d, status %d, count %d\n",
+ bestnet_v2->version, bestnet_v2->status, bestnet_v2->count);
+ netinfo_v2 = bestnet_v2->netinfo;
+ for (i = 0; i < bestnet_v2->count; i++) {
+ for (j = 0; j < netinfo_v2->pfnsubnet.SSID_len; j++)
+ printf("%c", netinfo_v2->pfnsubnet.u.SSID[j]);
+ printf("\n");
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ netinfo_v2->pfnsubnet.BSSID.octet[0],
+ netinfo_v2->pfnsubnet.BSSID.octet[1],
+ netinfo_v2->pfnsubnet.BSSID.octet[2],
+ netinfo_v2->pfnsubnet.BSSID.octet[3],
+ netinfo_v2->pfnsubnet.BSSID.octet[4],
+ netinfo_v2->pfnsubnet.BSSID.octet[5]);
+ printf("channel: %d, flags: %d, RSSI: %d, timestamp: %d\n",
+ netinfo_v2->pfnsubnet.channel, netinfo_v2->flags,
+ netinfo_v2->RSSI, netinfo_v2->timestamp);
+ printf("RTT0: %d, RTT1: %d\n", netinfo_v2->rtt0, netinfo_v2->rtt1);
+ netinfo_v2++;
+ }
+ } else if (bestnet_v1->version == PFN_LBEST_SCAN_RESULT_VERSION_V1) {
+ /* Use version 1 variables for processing */
+ status = bestnet_v1->status;
+ if (bestnet_v1->count > WL_MAX_LBESTNET_V1) {
+ fprintf(stderr, "Invalid data, count %d exceeds max buflen\n",
+ bestnet_v1->count);
+ return BCME_ERROR;
+ }
+
+ printf("ver %d, status %d, count %d\n",
+ bestnet_v1->version, bestnet_v1->status, bestnet_v1->count);
+ netinfo_v1 = bestnet_v1->netinfo;
+ for (i = 0; i < bestnet_v1->count; i++) {
+ for (j = 0; j < netinfo_v1->pfnsubnet.SSID_len; j++)
+ printf("%c", netinfo_v1->pfnsubnet.SSID[j]);
+ printf("\n");
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ netinfo_v1->pfnsubnet.BSSID.octet[0],
+ netinfo_v1->pfnsubnet.BSSID.octet[1],
+ netinfo_v1->pfnsubnet.BSSID.octet[2],
+ netinfo_v1->pfnsubnet.BSSID.octet[3],
+ netinfo_v1->pfnsubnet.BSSID.octet[4],
+ netinfo_v1->pfnsubnet.BSSID.octet[5]);
+ printf("channel: %d, flags: %d, RSSI: %d, timestamp: %d\n",
+ netinfo_v1->pfnsubnet.channel, netinfo_v1->flags,
+ netinfo_v1->RSSI, netinfo_v1->timestamp);
+ printf("RTT0: %d, RTT1: %d\n", netinfo_v1->rtt0, netinfo_v1->rtt1);
+ netinfo_v1++;
+ }
+ } else {
+ fprintf(stderr, "Unrecognized version %d\n", bestnet_v1->version);
+ return BCME_ERROR;
+ }
+ } while (status == PFN_INCOMPLETE);
+
+ return 0;
+}
+
+static int
+wl_pfnbest_bssid(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_pfn_scanhist_bssid_t *bestnet;
+ wl_pfn_net_info_bssid_t *netinfo;
+ uint32 i;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) {
+ fprintf(stderr, "Invalid parameter %s\n", *argv);
+ return BCME_ERROR;
+ }
+
+ /* Use generic buffer to read and parse results */
+ bestnet = (wl_pfn_scanhist_bssid_t *)buf;
+
+ do {
+ memset(bestnet, 0, WLC_IOCTL_MEDLEN);
+
+ if ((err = wlu_iovar_get(wl, "pfnbest_bssid",
+ (void *)bestnet, WLC_IOCTL_MEDLEN))) {
+ fprintf(stderr, "pfnbest_bssid fail\n");
+ return err;
+ }
+
+ printf("ver %d, status %d, count %d\n",
+ bestnet->version, bestnet->status, bestnet->count);
+ netinfo = bestnet->netinfo;
+ for (i = 0; i < bestnet->count; i++) {
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ netinfo->BSSID.octet[0],
+ netinfo->BSSID.octet[1],
+ netinfo->BSSID.octet[2],
+ netinfo->BSSID.octet[3],
+ netinfo->BSSID.octet[4],
+ netinfo->BSSID.octet[5]);
+ printf("channel: %d, RSSI: %d, timestamp: %d\n",
+ netinfo->channel, netinfo->RSSI, netinfo->timestamp);
+ netinfo++;
+ }
+ } while (bestnet->status != PFN_COMPLETE);
+
+ return 0;
+}
+
+static int
+wl_pfn_suspend(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, val;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) {
+ val = atoi(*argv);
+ err = wlu_iovar_setint(wl, "pfn_suspend", (val ? 1 : 0));
+ } else {
+ err = wlu_iovar_getint(wl, "pfn_suspend", &val);
+ if (!err)
+ wl_printint(val);
+ }
+
+ return err;
+}
+
+static int
+wl_pfn_mem(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, val;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv && !stricmp(*argv, "bestn")) {
+ if (*++argv)
+ val = atoi(*argv);
+ else {
+ fprintf(stderr, "Missing bestn value\n");
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "Missing bestn option\n");
+ return -1;
+ }
+
+ err = wlu_iovar_setint(wl, "pfnmem", val);
+ if (err) {
+ fprintf(stderr, "pfnmem set wrong!\n");
+ return err;
+ }
+
+ err = wlu_iovar_getint(wl, "pfnmem", &val);
+ if (!err)
+ wl_printint(val);
+ else
+ fprintf(stderr, "pfnmem get wrong!\n");
+ return err;
+}
+
+#if defined(linux)
+static void
+wl_pfn_printnet(void *ptr, int event_type)
+{
+ wl_pfn_net_info_v1_t *netinfo_v1;
+ wl_pfn_net_info_v2_t *netinfo_v2;
+ uint32 i, j;
+
+ if (WLC_E_PFN_NET_FOUND == event_type) {
+ printf("WLC_E_PFN_NET_FOUND:\n");
+ } else if (WLC_E_PFN_NET_LOST == event_type) {
+ printf("WLC_E_PFN_NET_LOST:\n");
+ } else if (WLC_E_PFN_BSSID_NET_FOUND == event_type) {
+ printf("WLC_E_PFN_BSSID_NET_FOUND:\n");
+ } else if (WLC_E_PFN_BSSID_NET_LOST == event_type) {
+ printf("WLC_E_PFN_BSSID_NET_LOST:\n");
+ } else {
+ return;
+ }
+
+ if (((wl_pfn_scanresults_v2_t *)ptr)->version == PFN_SCANRESULTS_VERSION_V2) {
+ netinfo_v2 = ((wl_pfn_scanresults_v2_t *)ptr)->netinfo;
+ printf("ver %d, status %d, count %d\n",
+ ((wl_pfn_scanresults_v2_t *)ptr)->version,
+ ((wl_pfn_scanresults_v2_t *)ptr)->status,
+ ((wl_pfn_scanresults_v2_t *)ptr)->count);
+ for (i = 0; i < ((wl_pfn_scanresults_v2_t *)ptr)->count; i++) {
+ printf("%d. ", i + 1);
+ for (j = 0; j < netinfo_v2->pfnsubnet.SSID_len; j++)
+ printf("%c", netinfo_v2->pfnsubnet.u.SSID[j]);
+ printf("\n");
+ printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ netinfo_v2->pfnsubnet.BSSID.octet[0],
+ netinfo_v2->pfnsubnet.BSSID.octet[1],
+ netinfo_v2->pfnsubnet.BSSID.octet[2],
+ netinfo_v2->pfnsubnet.BSSID.octet[3],
+ netinfo_v2->pfnsubnet.BSSID.octet[4],
+ netinfo_v2->pfnsubnet.BSSID.octet[5]);
+ printf("channel %d, RSSI %d, timestamp %d\n",
+ netinfo_v2->pfnsubnet.channel, netinfo_v2->RSSI,
+ netinfo_v2->timestamp);
+ netinfo_v2++;
+ }
+ } else if (((wl_pfn_scanresults_v1_t *)ptr)->version == PFN_SCANRESULTS_VERSION_V1) {
+ netinfo_v1 = ((wl_pfn_scanresults_v1_t *)ptr)->netinfo;
+ printf("ver %d, status %d, count %d\n",
+ ((wl_pfn_scanresults_v1_t *)ptr)->version,
+ ((wl_pfn_scanresults_v1_t *)ptr)->status,
+ ((wl_pfn_scanresults_v1_t *)ptr)->count);
+ for (i = 0; i < ((wl_pfn_scanresults_v1_t *)ptr)->count; i++) {
+ printf("%d. ", i + 1);
+ for (j = 0; j < netinfo_v1->pfnsubnet.SSID_len; j++)
+ printf("%c", netinfo_v1->pfnsubnet.SSID[j]);
+ printf("\n");
+ printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ netinfo_v1->pfnsubnet.BSSID.octet[0],
+ netinfo_v1->pfnsubnet.BSSID.octet[1],
+ netinfo_v1->pfnsubnet.BSSID.octet[2],
+ netinfo_v1->pfnsubnet.BSSID.octet[3],
+ netinfo_v1->pfnsubnet.BSSID.octet[4],
+ netinfo_v1->pfnsubnet.BSSID.octet[5]);
+ printf("channel %d, RSSI %d, timestamp %d\n",
+ netinfo_v1->pfnsubnet.channel, netinfo_v1->RSSI,
+ netinfo_v1->timestamp);
+
+ netinfo_v1++;
+ }
+ }
+}
+
+static int
+wl_pfn_event_check(void *wl, cmd_t *cmd, char **argv)
+{
+ int fd, err;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ char ifnames[IFNAMSIZ] = {"eth1"};
+ bcm_event_t * event;
+ char data[512];
+ int event_type;
+ struct ether_addr *addr;
+ char eabuf[ETHER_ADDR_STR_LEN];
+ wl_pfn_scanresults_v1_t *ptr_v1;
+ wl_pfn_net_info_v1_t *info_v1;
+ wl_pfn_scanresults_v2_t *ptr_v2;
+ wl_pfn_net_info_v2_t *info_v2;
+ uint32 i, j;
+ uint32 foundcnt, lostcnt;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ /* Override default ifname explicitly or implicitly */
+ if (*++argv) {
+ if (strlen(*argv) >= IFNAMSIZ) {
+ printf("Interface name %s too long\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ strncpy(ifnames, *argv, IFNAMSIZ);
+ } else {
+ strncpy(ifnames, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
+ }
+
+ ifnames[IFNAMSIZ - 1] = '\0';
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifnames, IFNAMSIZ);
+
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
+ if (fd < 0) {
+ printf("Cannot create socket %d\n", fd);
+ return BCME_ERROR;
+ }
+
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ printf("Cannot get index %d\n", err);
+ close(fd);
+ return BCME_ERROR;
+ }
+
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ printf("Cannot get index %d\n", err);
+ close(fd);
+ return BCME_ERROR;
+ }
+
+ /* Pre-set the results pointers for any data we might receive */
+ ptr_v1 = (wl_pfn_scanresults_v1_t *)(data + sizeof(bcm_event_t));
+ ptr_v2 = (wl_pfn_scanresults_v2_t *)(data + sizeof(bcm_event_t));
+
+ while (1) {
+ recv(fd, data, sizeof(data), 0);
+ event = (bcm_event_t *)data;
+ addr = (struct ether_addr *)&(event->event.addr);
+
+ event_type = ntoh32(event->event.event_type);
+
+ if (addr != NULL) {
+ sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x",
+ (uchar)addr->octet[0]&0xff,
+ (uchar)addr->octet[1]&0xff,
+ (uchar)addr->octet[2]&0xff,
+ (uchar)addr->octet[3]&0xff,
+ (uchar)addr->octet[4]&0xff,
+ (uchar)addr->octet[5]&0xff);
+ }
+
+ if (ntoh32(event->event.datalen)) {
+ if (WLC_E_PFN_SCAN_COMPLETE == event_type) {
+ /* Version check for PFN */
+ if (ptr_v2->version == PFN_SCANRESULTS_VERSION_V2) {
+ info_v2 = ptr_v2->netinfo;
+ foundcnt = ptr_v2->count & 0xffff;
+ lostcnt = ptr_v2->count >> 16;
+ printf("ver %d, status %d, found %d, lost %d\n",
+ ptr_v2->version, ptr_v2->status,
+ foundcnt, lostcnt);
+ if (foundcnt)
+ printf("Network found:\n");
+ for (i = 0; i < foundcnt; i++) {
+ printf("%d. ", i + 1);
+ for (j = 0; j < info_v2->pfnsubnet.SSID_len; j++)
+ printf("%c", info_v2->pfnsubnet.u.SSID[j]);
+ printf("\n");
+ printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ info_v2->pfnsubnet.BSSID.octet[0],
+ info_v2->pfnsubnet.BSSID.octet[1],
+ info_v2->pfnsubnet.BSSID.octet[2],
+ info_v2->pfnsubnet.BSSID.octet[3],
+ info_v2->pfnsubnet.BSSID.octet[4],
+ info_v2->pfnsubnet.BSSID.octet[5]);
+ printf("channel %d, RSSI %d, timestamp %d\n",
+ info_v2->pfnsubnet.channel, info_v2->RSSI,
+ info_v2->timestamp);
+ info_v2++;
+ }
+ if (lostcnt)
+ printf("Network lost:\n");
+ for (i = 0; i < lostcnt; i++) {
+ printf("%d. ", i + 1);
+ for (j = 0; j < info_v2->pfnsubnet.SSID_len; j++)
+ printf("%c", info_v2->pfnsubnet.u.SSID[j]);
+ printf("\n");
+ printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ info_v2->pfnsubnet.BSSID.octet[0],
+ info_v2->pfnsubnet.BSSID.octet[1],
+ info_v2->pfnsubnet.BSSID.octet[2],
+ info_v2->pfnsubnet.BSSID.octet[3],
+ info_v2->pfnsubnet.BSSID.octet[4],
+ info_v2->pfnsubnet.BSSID.octet[5]);
+ printf("channel %d, RSSI %d, timestamp %d\n",
+ info_v2->pfnsubnet.channel, info_v2->RSSI,
+ info_v2->timestamp);
+ info_v2++;
+ }
+ } else if (ptr_v1->version == PFN_SCANRESULTS_VERSION_V1) {
+ info_v1 = ptr_v1->netinfo;
+ foundcnt = ptr_v1->count & 0xffff;
+ lostcnt = ptr_v1->count >> 16;
+ printf("ver %d, status %d, found %d, lost %d\n",
+ ptr_v1->version, ptr_v1->status,
+ foundcnt, lostcnt);
+ if (foundcnt)
+ printf("Network found:\n");
+ for (i = 0; i < foundcnt; i++) {
+ printf("%d. ", i + 1);
+ for (j = 0; j < info_v1->pfnsubnet.SSID_len; j++)
+ printf("%c", info_v1->pfnsubnet.SSID[j]);
+ printf("\n");
+ printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ info_v1->pfnsubnet.BSSID.octet[0],
+ info_v1->pfnsubnet.BSSID.octet[1],
+ info_v1->pfnsubnet.BSSID.octet[2],
+ info_v1->pfnsubnet.BSSID.octet[3],
+ info_v1->pfnsubnet.BSSID.octet[4],
+ info_v1->pfnsubnet.BSSID.octet[5]);
+ printf("channel %d, RSSI %d, timestamp %d\n",
+ info_v1->pfnsubnet.channel, info_v1->RSSI,
+ info_v1->timestamp);
+ info_v1++;
+ }
+ if (lostcnt)
+ printf("Network lost:\n");
+ for (i = 0; i < lostcnt; i++) {
+ printf("%d. ", i + 1);
+ for (j = 0; j < info_v1->pfnsubnet.SSID_len; j++)
+ printf("%c", info_v1->pfnsubnet.SSID[j]);
+ printf("\n");
+ printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ info_v1->pfnsubnet.BSSID.octet[0],
+ info_v1->pfnsubnet.BSSID.octet[1],
+ info_v1->pfnsubnet.BSSID.octet[2],
+ info_v1->pfnsubnet.BSSID.octet[3],
+ info_v1->pfnsubnet.BSSID.octet[4],
+ info_v1->pfnsubnet.BSSID.octet[5]);
+ printf("channel %d, RSSI %d, timestamp %d\n",
+ info_v1->pfnsubnet.channel, info_v1->RSSI,
+ info_v1->timestamp);
+ info_v1++;
+ }
+ } else {
+ fprintf(stderr, "Unrecognized version %d\n",
+ ptr_v1->version);
+ return BCME_ERROR;
+ }
+ } else if ((WLC_E_PFN_NET_FOUND == event_type) ||
+ (WLC_E_PFN_NET_LOST == event_type) ||
+ (WLC_E_PFN_BSSID_NET_FOUND == event_type) ||
+ (WLC_E_PFN_BSSID_NET_LOST == event_type)) {
+ wl_pfn_printnet((void *)(data + sizeof(bcm_event_t)), event_type);
+ }
+
+ if (WLC_E_LINK == event_type || WLC_E_NDIS_LINK == event_type) {
+ if (ntoh16(event->event.flags) & WLC_EVENT_MSG_LINK)
+ printf("MACEVENT Link up :%s\n", eabuf);
+ else
+ printf("MACEVENT Link down :%s\n", eabuf);
+ }
+ } else {
+ if (WLC_E_PFN_SCAN_NONE == event_type) {
+ printf("Got WLC_E_PFN_SCAN_NONE\n");
+ }
+ if (WLC_E_PFN_SCAN_ALLGONE == event_type) {
+ printf("Got WLC_E_PFN_SCAN_ALLGONE\n");
+ }
+ if (WLC_E_PFN_BEST_BATCHING == event_type) {
+ printf("Got WLC_E_PFN_BEST_BATCHING\n");
+ }
+ }
+ }
+
+ close(fd);
+ return (0);
+}
+#endif /* linux */
+
+static int
+wl_event_filter(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* event bit mask */
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN);
+
+ /* Register for following event for pfn */
+ event_inds_mask[WLC_E_LINK / 8] |= 1 << (WLC_E_LINK % 8);
+ event_inds_mask[WLC_E_PFN_NET_FOUND / 8] |= 1 << (WLC_E_PFN_NET_FOUND % 8);
+ event_inds_mask[WLC_E_PFN_NET_LOST / 8] |= 1 << (WLC_E_PFN_NET_LOST % 8);
+ event_inds_mask[WLC_E_PFN_SCAN_NONE/ 8] |= 1 << (WLC_E_PFN_SCAN_NONE % 8);
+ event_inds_mask[WLC_E_PFN_SCAN_ALLGONE/ 8] |= 1 << (WLC_E_PFN_SCAN_ALLGONE % 8);
+
+ if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
+ return (err);
+
+ return (0);
+}
+
+static int
+wl_pfn_roam_alert_thresh(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen;
+ wl_pfn_roam_thresh_t *pfn_roam_alert;
+
+ buflen = sprintf(buf, "%s", *argv) + 1;
+
+ if (*++(argv) == NULL) {
+ buf[buflen] = '\0';
+ err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN);
+ if (err < 0)
+ return err;
+
+ pfn_roam_alert = (wl_pfn_roam_thresh_t *)buf;
+ printf("pfn_alert_thresh %u\n", pfn_roam_alert->pfn_alert_thresh);
+ printf("roam_alert_thresh %u\n", pfn_roam_alert->roam_alert_thresh);
+ return 0;
+
+ } else {
+ pfn_roam_alert = (wl_pfn_roam_thresh_t *) (buf + buflen);
+ buflen += sizeof(wl_pfn_roam_thresh_t);
+
+ pfn_roam_alert->pfn_alert_thresh = (uint32) strtoul(*argv, NULL, 0);
+
+ if (*++(argv) == NULL) {
+ printf("Incorrect number of arguments\n");
+ return BCME_ERROR;
+ }
+ pfn_roam_alert->roam_alert_thresh = (uint32) strtoul(*argv, NULL, 0);
+
+ if (*++(argv)) {
+ printf("extra arguments\n");
+ return BCME_ERROR;
+ }
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+ }
+ return 0;
+}
+
+static char *adaptname[] = { "off", "smart", "strict", "slow" };
+
+static int
+wl_pfn_override(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_pfn_override_param_t pfnov_params;
+ wl_pfn_override_param_t *pfnov_paramp;
+ wl_pfn_mpf_state_params_t *statep;
+ char *endptr;
+
+ uint16 start, duration;
+
+ /* Initialize the structure (both set and get) */
+ memset(&pfnov_params, 0, sizeof(pfnov_params));
+ pfnov_params.version = dtoh16(WL_PFN_OVERRIDE_VERSION);
+
+ if (*++argv == NULL) {
+ /* No arguments: do a GET and display results */
+ err = wlu_iovar_getbuf(wl, cmd->name,
+ &pfnov_params, sizeof(pfnov_params),
+ buf, WLC_IOCTL_MAXLEN);
+ if (err >= 0) {
+ pfnov_paramp = (wl_pfn_override_param_t *)buf;
+ if (dtoh16(pfnov_paramp->version) != WL_PFN_OVERRIDE_VERSION) {
+ fprintf(stderr, "Incorrect version (%d != %d).\n",
+ dtoh16(pfnov_paramp->version), WL_PFN_OVERRIDE_VERSION);
+ return -1;
+ }
+ start = dtoh16(pfnov_paramp->start_offset);
+ duration = dtoh16(pfnov_paramp->duration);
+
+ if (duration) {
+ if (start == 0)
+ printf("Active, remaining duration %d\n", duration);
+ else
+ printf("Scheduled in %d, duration %d\n", start, duration);
+
+ /* Disaply the actual parameters */
+ statep = &pfnov_paramp->override;
+ statep->scan_freq = dtoh32(statep->scan_freq);
+ statep->lost_network_timeout =
+ dtoh32(statep->lost_network_timeout);
+ statep->flags = dtoh16(statep->flags);
+ statep->slow_freq = dtoh32(statep->slow_freq);
+
+ printf("Scan frequency: %d\n", statep->scan_freq);
+ if (statep->lost_network_timeout)
+ printf("Net timeout: %d\n",
+ dtoh32(statep->lost_network_timeout));
+ if (statep->flags & WL_PFN_MPF_ADAPT_ON_MASK) {
+ uint atype;
+ atype = statep->flags & WL_PFN_MPF_ADAPTSCAN_MASK;
+ atype = atype >> WL_PFN_MPF_ADAPTSCAN_BIT;
+ printf("Adapt: %s\n", adaptname[atype]);
+ }
+ if (statep->exp)
+ printf(" Exp: %d\n", statep->exp);
+ if (statep->repeat)
+ printf(" Repeat: %d\n", statep->repeat);
+ if (statep->slow_freq)
+ printf(" Slow: %d\n", statep->slow_freq);
+ } else {
+ printf("Override not configured\n");
+ }
+ }
+ } else {
+ /* Additional arguments: parse and do a set */
+
+ /* Start field (required) */
+ start = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Non-numeric start value %s\n", *argv);
+ return -1;
+ }
+
+ /* Duration field (required) */
+ if (*++argv == NULL) {
+ fprintf(stderr, "Duration required\n");
+ return -1;
+ }
+ duration = strtoul(*argv, &endptr, 0);
+ argv++;
+
+ /* Allow duration and start both 0 to mean cancel, otherwise
+ * zero duration is meaningless. A nonzero duration requires
+ * a scan frequency at a minimum
+ */
+ if (!duration) {
+ if (start) {
+ fprintf(stderr, "Start with no duration invalid\n");
+ return -1;
+ }
+ } else {
+ /* Read the actual timing parameters */
+ statep = &pfnov_params.override;
+ if ((*argv == NULL) || strcmp(*argv, "scanfrq")) {
+ fprintf(stderr, "scanfrq required as first parameter\n");
+ return -1;
+ }
+
+ if (argv[1] == NULL) {
+ fprintf(stderr, "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ statep->scan_freq = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Non-numeric scanfrq %s\n", *argv);
+ return -1;
+ }
+ argv++;
+
+ /* As long as there was a scan_freq, pick up other options */
+ while (*argv && statep->scan_freq) {
+ if (*argv && !strcmp(*argv, "netimeout")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr,
+ "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ statep->lost_network_timeout = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "Non-numeric netimeout %s\n", *argv);
+ return -1;
+ }
+ argv++;
+ } else if (*argv && !strcmp(*argv, "adapt")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr,
+ "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ if (!strcmp(*argv, "off")) {
+ statep->flags |=
+ (OFF_ADAPT << WL_PFN_MPF_ADAPTSCAN_BIT);
+ } else if (!strcmp(*argv, "smart")) {
+ statep->flags |=
+ (SMART_ADAPT << WL_PFN_MPF_ADAPTSCAN_BIT);
+ } else if (!strcmp(*argv, "strict")) {
+ statep->flags |=
+ (STRICT_ADAPT << WL_PFN_MPF_ADAPTSCAN_BIT);
+ } else if (!strcmp(*argv, "slow")) {
+ statep->flags |=
+ (SLOW_ADAPT << WL_PFN_MPF_ADAPTSCAN_BIT);
+ } else {
+ fprintf(stderr,
+ "Invalid adaptive scan option %s\n",
+ *argv);
+ return -1;
+ }
+ statep->flags |= WL_PFN_MPF_ADAPT_ON_MASK;
+ argv++;
+ } else if (*argv && !strcmp(*argv, "repeat")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr,
+ "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ statep->repeat = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "Non-numeric repeat value %s\n", *argv);
+ return -1;
+ }
+ argv++;
+ } else if (*argv && !strcmp(*argv, "exp")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr,
+ "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ statep->exp = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "Non-numeric exp value %s\n", *argv);
+ return -1;
+ }
+ argv++;
+ } else if (*argv && !strcmp(*argv, "slowfrq")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr,
+ "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ statep->slow_freq = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "Non-numeric slowfrq value %s\n", *argv);
+ return -1;
+ }
+ argv++;
+ } else {
+ /* Not a recognized option, exit loop */
+ break;
+ }
+ }
+
+ statep->scan_freq = htod32(statep->scan_freq);
+ statep->lost_network_timeout = htod32(statep->lost_network_timeout);
+ statep->flags = htod16(statep->flags);
+ statep->slow_freq = htod32(statep->slow_freq);
+ }
+
+ /* Should be no leftover args at this point */
+ if (*argv) {
+ fprintf(stderr, "Input error at %s\n", *argv);
+ return -1;
+ }
+
+ /* Fill in the start and duration fields */
+ pfnov_params.start_offset = htod16(start);
+ pfnov_params.duration = htod16(duration);
+
+ /* Now do the set */
+ err = wlu_iovar_setbuf(wl, cmd->name,
+ &pfnov_params, sizeof(pfnov_params), buf, WLC_IOCTL_MAXLEN);
+ }
+
+ return err;
+}
+
+static int
+wl_pfn_macaddr(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = BCME_OK;
+ wl_pfn_macaddr_cfg_t pfn_mac;
+
+ UNUSED_PARAMETER(cmd);
+
+ memset(&pfn_mac, 0, sizeof(pfn_mac));
+ pfn_mac.version = WL_PFN_MACADDR_CFG_VER;
+
+ if (argv[1] != NULL) {
+ if (!wl_ether_atoe(argv[1], &pfn_mac.macaddr)) {
+ fprintf(stderr, "Invalid MAC address %s\n", *argv);
+ return -1;
+ }
+
+ return wlu_iovar_set(wl, "pfn_macaddr", &pfn_mac, sizeof(pfn_mac));
+ } else {
+ if ((ret = wlu_iovar_get(wl, "pfn_macaddr", &pfn_mac, sizeof(pfn_mac))) < 0)
+ return ret;
+
+ printf("%s\n", wl_ether_etoa(&pfn_mac.macaddr));
+ }
+
+ return ret;
+}
+
+#ifdef WL_MPF
+static int
+wl_pfn_mpfset(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_pfn_mpf_param_t mpf_params;
+ wl_pfn_mpf_param_t *mpf_paramp;
+ wl_pfn_mpf_state_params_t *statep;
+ char *endptr;
+ uint state;
+
+ if (*++argv == NULL) {
+ fprintf(stderr, "Requires at least <groupid>\n");
+ return -1;
+ }
+
+ /* Initialize the structure (both set and get) */
+ memset(&mpf_params, 0, sizeof(mpf_params));
+ mpf_params.version = dtoh16(WL_PFN_MPF_VERSION);
+ mpf_params.groupid = dtoh16(strtoul(*argv, &endptr, 0));
+ if (*endptr != '\0') {
+ fprintf(stderr, "Non-numeric groupid %s\n", *argv);
+ return -1;
+ }
+
+ if (*++argv == NULL) {
+ /* No arguments beyond groupid: do a GET and display results */
+ err = wlu_iovar_getbuf(wl, cmd->name,
+ &mpf_params, OFFSETOF(wl_pfn_mpf_param_t, state),
+ buf, WLC_IOCTL_MAXLEN);
+ if (err >= 0) {
+ mpf_paramp = (wl_pfn_mpf_param_t *)buf;
+ if (dtoh16(mpf_paramp->version) != WL_PFN_MPF_VERSION) {
+ fprintf(stderr, "Incorrect version (%d != %d).\n",
+ dtoh16(mpf_paramp->version), WL_PFN_MPF_VERSION);
+ return -1;
+ }
+ if (mpf_paramp->groupid != mpf_params.groupid) {
+ fprintf(stderr, "Groupid modified (%d -> %d)?\n",
+ dtoh16(mpf_params.groupid), dtoh16(mpf_paramp->groupid));
+ return -1;
+ }
+
+ for (state = 0, statep = mpf_paramp->state;
+ state < WL_PFN_MPF_STATES_MAX; state++, statep++) {
+ if (!statep->scan_freq)
+ continue;
+
+ statep->scan_freq = dtoh32(statep->scan_freq);
+ statep->lost_network_timeout =
+ dtoh32(statep->lost_network_timeout);
+ statep->flags = dtoh16(statep->flags);
+ statep->slow_freq = dtoh32(statep->slow_freq);
+
+ printf("State %d:\n"
+ " Scan frequency: %d\n",
+ state, statep->scan_freq);
+ if (statep->lost_network_timeout)
+ printf(" Net timeout: %d\n",
+ dtoh32(statep->lost_network_timeout));
+ if (statep->flags & WL_PFN_MPF_ADAPT_ON_MASK) {
+ uint atype;
+ atype = statep->flags & WL_PFN_MPF_ADAPTSCAN_MASK;
+ atype = atype >> WL_PFN_MPF_ADAPTSCAN_BIT;
+ printf(" Adapt: %s\n", adaptname[atype]);
+ }
+ if (statep->exp)
+ printf(" Exp: %d\n", statep->exp);
+ if (statep->repeat)
+ printf(" Repeat: %d\n", statep->repeat);
+ if (statep->slow_freq)
+ printf(" Slow: %d\n", statep->slow_freq);
+ }
+ }
+ } else {
+ /* Additional arguments: parse and do a set */
+ while (*argv && !strcmp(*argv, "state")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr, "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ state = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Non-numeric state %s\n", *argv);
+ return -1;
+ }
+ if (state >= WL_PFN_MPF_STATES_MAX) {
+ fprintf(stderr, "Invalid state %d\n", state);
+ return -1;
+ }
+ argv++;
+
+ /* Set up for this state and get the scan frequency */
+ statep = &mpf_params.state[state];
+ if (statep->scan_freq) {
+ fprintf(stderr, "Repeated state (%d)\n", state);
+ return -1;
+ }
+
+ if (*argv && !strcmp(*argv, "scanfrq")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr, "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ statep->scan_freq = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Non-numeric scanfrq %s\n", *argv);
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "State requires scanfrq\n");
+ return -1;
+ }
+ argv++;
+
+ /* If scan_freq is 0, don't allow other options */
+ if (!statep->scan_freq)
+ continue;
+
+ /* Pick up any other options */
+ while (*argv) {
+ if (*argv && !strcmp(*argv, "netimeout")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr,
+ "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ statep->lost_network_timeout = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "Non-numeric netimeout %s\n", *argv);
+ return -1;
+ }
+ argv++;
+ } else if (*argv && !strcmp(*argv, "adapt")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr,
+ "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ if (!strcmp(*argv, "off")) {
+ statep->flags |=
+ (OFF_ADAPT << WL_PFN_MPF_ADAPTSCAN_BIT);
+ } else if (!strcmp(*argv, "smart")) {
+ statep->flags |=
+ (SMART_ADAPT << WL_PFN_MPF_ADAPTSCAN_BIT);
+ } else if (!strcmp(*argv, "strict")) {
+ statep->flags |=
+ (STRICT_ADAPT << WL_PFN_MPF_ADAPTSCAN_BIT);
+ } else if (!strcmp(*argv, "slow")) {
+ statep->flags |=
+ (SLOW_ADAPT << WL_PFN_MPF_ADAPTSCAN_BIT);
+ } else {
+ fprintf(stderr,
+ "Invalid adaptive scan option %s\n",
+ *argv);
+ return -1;
+ }
+ statep->flags |= WL_PFN_MPF_ADAPT_ON_MASK;
+ argv++;
+ } else if (*argv && !strcmp(*argv, "repeat")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr,
+ "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ statep->repeat = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "Non-numeric repeat value %s\n", *argv);
+ return -1;
+ }
+ argv++;
+ } else if (*argv && !strcmp(*argv, "exp")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr,
+ "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ statep->exp = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "Non-numeric exp value %s\n", *argv);
+ return -1;
+ }
+ argv++;
+ } else if (*argv && !strcmp(*argv, "slowfrq")) {
+ if (argv[1] == NULL) {
+ fprintf(stderr,
+ "Missing value for '%s'\n", *argv);
+ return -1;
+ }
+ argv++;
+ statep->slow_freq = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "Non-numeric slowfrq value %s\n", *argv);
+ return -1;
+ }
+ argv++;
+ } else {
+ /* Not a recognized option, exit inner loop */
+ break;
+ }
+ }
+
+ statep->scan_freq = htod32(statep->scan_freq);
+ statep->lost_network_timeout = htod32(statep->lost_network_timeout);
+ statep->flags = htod16(statep->flags);
+ statep->slow_freq = htod32(statep->slow_freq);
+ }
+
+ /* Should be no leftover args at this point */
+ if (*argv) {
+ fprintf(stderr, "Input error at %s\n", *argv);
+ return -1;
+ }
+
+ /* Now do the set */
+ err = wlu_iovar_setbuf(wl, cmd->name,
+ &mpf_params, sizeof(mpf_params), buf, WLC_IOCTL_MAXLEN);
+ }
+
+ return err;
+}
+
+static int
+wl_mpf_map(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_mpf_map_t map;
+ wl_mpf_map_t *mapp;
+ wl_mpf_val_t *valp, *valp2;
+ uint16 mask, val, state, type = 0;
+ uint8 count;
+ char *endptr;
+ uint bitcount;
+
+ argv++;
+
+ memset(&map, 0, sizeof(map));
+ map.version = dtoh16(WL_MPF_VERSION);
+
+ if (*argv && !strcmp(*argv, "type")) {
+ argv++;
+ if (*argv == NULL) {
+ fprintf(stderr, "No type value specified\n");
+ return -1;
+ }
+ type = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Non-numeric type value %s\n", *argv);
+ return -1;
+ }
+ if (type != 0) {
+ fprintf(stderr, "Nonzero type not yet implemented\n");
+ return -1;
+ }
+ /* If/when nonzero allowed, swap/assign it here */
+ argv++;
+ }
+
+ if (*argv == NULL) {
+ /* No arguments beyond type, do a GET and display results */
+ err = wlu_iovar_getbuf(wl, cmd->name,
+ &map, OFFSETOF(wl_mpf_map_t, mask), buf, WLC_IOCTL_MAXLEN);
+ if (err >= 0) {
+ mapp = (wl_mpf_map_t *)buf;
+ if (dtoh16(mapp->version) != WL_MPF_VERSION) {
+ fprintf(stderr, "Incorrect version (%d != %d).\n",
+ dtoh16(mapp->version), WL_MPF_VERSION);
+ return -1;
+ }
+ printf("Type %d, mask %04x, %d state mappings:\n",
+ dtoh16(mapp->type), dtoh16(mapp->mask), mapp->count);
+ bitcount = bcm_bitcount((uint8*)&mapp->mask, sizeof(mapp->mask));
+ if (bitcount > WL_MPF_MAX_BITS) {
+ fprintf(stderr, "Invalid mask: more than %d bits\n",
+ WL_MPF_MAX_BITS);
+ return -1;
+ }
+
+ count = dtoh16(mapp->count);
+ if (!count && !bitcount) {
+ printf("No map configured\n");
+ } else {
+ if (count != (1 << bitcount)) {
+ fprintf(stderr, "Bit/count mismatch (%d != %d)\n",
+ bitcount, count);
+ return -1;
+ }
+ }
+
+ for (valp = mapp->vals; count; count--, valp++) {
+ if (valp->name[WL_MPF_STATE_NAME_MAX-1]) {
+ char c = valp->name[WL_MPF_STATE_NAME_MAX-1];
+ valp->name[WL_MPF_STATE_NAME_MAX-1] = 0;
+ fprintf(stderr, "Invalid name: %s%c\n",
+ valp->name, c);
+ return -1;
+ }
+
+ printf(" Value: %04x State: %d (%s)\n",
+ dtoh16(valp->val), dtoh16(valp->state), valp->name);
+ }
+ }
+ } else {
+ /* Additional arguments: parse and do a set */
+ mask = strtoul(*argv, &endptr, 16);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Cannot parse mask %s\n", *argv);
+ return -1;
+ }
+ bitcount = bcm_bitcount((uint8*)&mask, sizeof(mask));
+ if (bitcount > WL_MPF_MAX_BITS) {
+ fprintf(stderr, "Invalid mask: more than %d bits\n",
+ WL_MPF_MAX_BITS);
+ return -1;
+ }
+ map.mask = htod16(mask);
+ argv++;
+
+ count = 1 << bitcount;
+ map.count = count;
+
+ for (valp = map.vals; count && *argv; count--, argv++, valp++) {
+ val = strtoul(*argv, &endptr, 16);
+ if (endptr == *argv || *endptr != '/') {
+ fprintf(stderr, "Invalid value, or missing /state: %s\n", *argv);
+ return -1;
+ }
+ if (val & ~mask) {
+ fprintf(stderr, "Value bits outside mask: %04x/%04x -> %04x\n",
+ val, mask, val & ~mask);
+ return -1;
+ }
+ val = htod16(val);
+ for (valp2 = map.vals; valp2 < valp; valp2++) {
+ if (val == valp2->val) {
+ fprintf(stderr, "Invalid repeated value: %04x\n",
+ dtoh16(val));
+ return -1;
+ }
+ }
+ valp->val = val;
+
+ endptr++;
+ if (*endptr == '\0' || *endptr == '/') {
+ fprintf(stderr, "Missing required /<state>: %s\n", *argv);
+ return -1;
+ }
+ state = strtoul(endptr, &endptr, 0);
+ if (*endptr != '\0' && *endptr != '/') {
+ fprintf(stderr, "Non-numeric state value %s\n", endptr);
+ return -1;
+ }
+ if (state >= map.count) {
+ fprintf(stderr, "Invalid state %d, must be 0-%d\n",
+ state, map.count - 1);
+ return -1;
+ }
+ valp->state = htod16(state);
+
+ if (*endptr++ == '/') {
+ if (strlen(endptr) >= WL_MPF_STATE_NAME_MAX - 1) {
+ fprintf(stderr, "Name %s too long, limit %d chars\n",
+ endptr, WL_MPF_STATE_NAME_MAX - 2);
+ return -1;
+ }
+ if (isdigit(*endptr)) {
+ fprintf(stderr, "Names cannot start with a digit: %s\n",
+ endptr);
+ return -1;
+ }
+ if (!strcmp(endptr, "gpio")) {
+ fprintf(stderr, "Name 'gpio' is reserved\n");
+ return -1;
+ }
+ strcpy(valp->name, endptr);
+ }
+ }
+
+ /* Closing overall checks */
+ if (count) {
+ fprintf(stderr, "Specify all %d possible values, missing %d\n",
+ map.count, count);
+ return -1;
+ } else if (*argv) {
+ fprintf(stderr, "Too many arguments for %d possible states at %s\n",
+ map.count, *argv);
+ return -1;
+ }
+
+ /* All ok, do the set */
+ err = wlu_iovar_setbuf(wl, cmd->name,
+ &map, sizeof(map), buf, WLC_IOCTL_MAXLEN);
+ }
+
+ return err;
+}
+
+static int
+wl_mpf_state(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_mpf_state_t mpstate;
+ wl_mpf_state_t *mpstatep;
+ uint16 state, type = 0;
+ char *endptr;
+
+ argv++;
+
+ memset(&mpstate, 0, sizeof(mpstate));
+ mpstate.version = dtoh16(WL_MPF_VERSION);
+
+ if (*argv && !strcmp(*argv, "type")) {
+ argv++;
+ if (*argv == NULL) {
+ fprintf(stderr, "No type value specified\n");
+ return -1;
+ }
+ type = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Non-numeric type value %s\n", *argv);
+ return -1;
+ }
+ if (type != 0) {
+ fprintf(stderr, "Nonzero type not yet implemented\n");
+ return -1;
+ }
+ /* If/when nonzero allowed, swap/assign it here */
+ argv++;
+ }
+
+ if (*argv == NULL) {
+ /* No arguments beyond type, do a GET and display results */
+ err = wlu_iovar_getbuf(wl, cmd->name,
+ &mpstate, OFFSETOF(wl_mpf_state_t, state),
+ buf, WLC_IOCTL_MAXLEN);
+ if (err >= 0) {
+ mpstatep = (wl_mpf_state_t *)buf;
+ if (dtoh16(mpstatep->version) != WL_MPF_VERSION) {
+ fprintf(stderr, "Incorrect version (%d != %d).\n",
+ dtoh16(mpstatep->version), WL_MPF_VERSION);
+ return -1;
+ }
+ if (mpstatep->name[WL_MPF_STATE_NAME_MAX-1]) {
+ fprintf(stderr, "Invalid name\n");
+ mpstatep->name[WL_MPF_STATE_NAME_MAX-1] = '\0';
+ }
+ printf("Type %d: state %d, name %s (%s)\n",
+ dtoh16(mpstatep->type), dtoh16(mpstatep->state),
+ (mpstatep->name ? mpstatep->name : "(unknown)"),
+ ((mpstatep->force) ? "forced" : "auto"));
+ }
+ } else {
+ /* Should be one argument, but need to determine what kind */
+ if (isdigit(**argv)) {
+ state = strtoul(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Non-numeric state: %s\n", *argv);
+ return -1;
+ }
+ mpstate.state = htod16(state);
+ mpstate.force = 1;
+ } else if (!strcmp(*argv, "gpio")) {
+ mpstate.force = 0;
+ } else {
+ if (strlen(*argv) >= WL_MPF_STATE_NAME_MAX-1) {
+ fprintf(stderr, "Name %s too long, limit %d chars\n",
+ *argv, WL_MPF_STATE_NAME_MAX - 2);
+ return -1;
+ }
+ strcpy(mpstate.name, *argv);
+ mpstate.force = 1;
+ }
+ argv++;
+
+ if (*argv) {
+ fprintf(stderr, "Too many arguments at %s\n", *argv);
+ return -1;
+ }
+
+ /* All ok, do the set */
+ err = wlu_iovar_setbuf(wl, cmd->name,
+ &mpstate, sizeof(mpstate), buf, WLC_IOCTL_MAXLEN);
+ }
+
+ return err;
+}
+#endif /* WL_MPF */
diff --git a/wl/src/wl/exe/wluc_phy.c b/wl/src/wl/exe/wluc_phy.c
new file mode 100644
index 0000000..1fc4841
--- /dev/null
+++ b/wl/src/wl/exe/wluc_phy.c
@@ -0,0 +1,5494 @@
+/*
+ * wl phy command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_phy.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmsrom_fmt.h>
+#include <bcmsrom_tbl.h>
+#include <bcmdevs.h>
+#include "wlu_common.h"
+#include "wlu.h"
+#include <miniopt.h>
+
+/* For backwards compatibility, the absense of the define 'NO_FILESYSTEM_SUPPORT'
+ * implies that a filesystem is supported.
+ */
+#if !defined(BWL_NO_FILESYSTEM_SUPPORT)
+#define BWL_FILESYSTEM_SUPPORT
+#endif
+
+static cmd_func_t wl_pkteng, wl_pkteng_stats, wl_phy_txpwrindex, wl_pkteng_status;
+static cmd_func_t wl_sample_collect;
+static cmd_func_t wl_phy_force_crsmin;
+static cmd_func_t wl_phy_rssi_ant;
+static cmd_func_t wl_phy_snr_ant;
+static cmd_func_t wl_tssi, wl_atten, wl_evm;
+static cmd_func_t wl_interfere, wl_interfere_override;
+static cmd_func_t wl_get_instant_power;
+static cmd_func_t wl_phymsglevel;
+#if defined(BCMDBG)
+static cmd_func_t wl_phy_debug_cmd;
+#endif
+static cmd_func_t wl_rifs;
+static cmd_func_t wl_rifs_advert;
+static cmd_func_t wl_test_tssi, wl_test_tssi_offs, wl_phy_rssiant, wl_rxiq;
+static cmd_func_t wl_rxiq_sweep;
+static cmd_func_t wl_test_idletssi;
+static cmd_func_t wlu_afeoverride;
+static cmd_func_t wl_phy_papdepstbl;
+static cmd_func_t wl_phy_txiqcc, wl_phy_txlocc;
+static cmd_func_t wl_rssi_cal_freq_grp_2g;
+static cmd_func_t wl_phy_rssi_gain_delta_2g, wl_phy_rssi_gain_delta_5g;
+static cmd_func_t wl_phy_rssi_gain_delta_2g_sub;
+static cmd_func_t wl_phy_rxgainerr_2g, wl_phy_rxgainerr_5g;
+static cmd_func_t wl_phytable, wl_phy_pavars, wl_phy_povars;
+static cmd_func_t wl_phy_fem, wl_phy_maxpower;
+static cmd_func_t wl_phy_rpcalvars;
+static cmd_func_t wl_phy_rpcalphasevars;
+static cmd_func_t wl_phy_force_vsdb_chans;
+static cmd_func_t wl_radar_args, wl_radar_thrs, wl_radar_thrs2;
+static cmd_func_t wl_phy_dyn_switch_th;
+static cmd_func_t wl_btcoex_desense_rxgain;
+
+static cmd_func_t wl_phy_tpc_av, wl_phy_tpc_vmid;
+
+
+/* txcal iovars */
+static cmd_func_t wl_txcal_gainsweep;
+static cmd_func_t wl_txcal_gainsweep_meas;
+static cmd_func_t wl_txcal_pwr_tssi_tbl;
+static cmd_func_t wl_olpc_anchoridx;
+static cmd_func_t wl_read_estpwrlut;
+static cmd_func_t wl_olpc_offset;
+
+typedef struct {
+ uint value;
+ const char *string;
+} phy_msg_t;
+
+static cmd_t wl_phy_cmds[] = {
+ { "restart", wl_void, -1, WLC_RESTART,
+ "Restart driver. Driver must already be down."},
+ { "phymsglevel", wl_phymsglevel, WLC_GET_VAR, WLC_SET_VAR,
+ "set phy debugging message bitvector\n"
+ "\ttype \'wl phymsglevel ?\' for values" },
+ { "tssi", wl_tssi, WLC_GET_TSSI, -1,
+ "Get the tssi value from radio" },
+ { "txpathpwr", wl_int, WLC_GET_TX_PATH_PWR, WLC_SET_TX_PATH_PWR,
+ "Turn the tx path power on or off on 2050 radios" },
+ { "powerindex", wl_int, WLC_GET_PWRIDX, WLC_SET_PWRIDX,
+ "Set the transmit power for A band(0-63).\n"
+ "\t-1 - default value" },
+ { "atten", wl_atten, WLC_GET_ATTEN, WLC_SET_ATTEN,
+ "Set the transmit attenuation for B band. Args: bb radio txctl1.\n"
+ "\tauto to revert to automatic control\n"
+ "\tmanual to supspend automatic control" },
+ { "phyreg", wl_reg, WLC_GET_PHYREG, WLC_SET_PHYREG,
+ "Get/Set a phy register:\n"
+ "\toffset [ value ] [ band ]" },
+ { "radioreg", wl_reg, WLC_GET_RADIOREG, WLC_SET_RADIOREG,
+ "Get/Set a radio register:\n"
+ "\toffset [ value ] [ band/core ]\n"
+ "HTPHY:\n"
+ "\tGet a radio register: wl radioreg [ offset ] [ cr0/cr1/cr2 ]\n"
+ "\tSet a radio register: wl radioreg [ offset ] [ value ] [ cr0/cr1/cr2/all ]\n"
+ "ACPHY:\n"
+ "\tGet a radio register: wl radioreg [ offset ] [ cr0/cr1/cr2/pll/pll0/pll1 ]\n"
+ "\tSet a radio register: wl radioreg [ offset ] [ value ]"
+ " [ cr0/cr1/cr2/pll/pll0/pll1/all ]"},
+ { "phy_afeoverride", wlu_afeoverride, WLC_GET_VAR, WLC_SET_VAR, "g/set AFE override"},
+ { "pcieserdesreg", wlu_reg3args, WLC_GET_VAR, WLC_SET_VAR,
+ "g/set SERDES registers: dev offset [val]"},
+ { "txinstpwr", wl_get_instant_power, WLC_GET_VAR, -1,
+ "Return tx power based on instant TSSI "},
+ { "evm", wl_evm, -1, WLC_EVM,
+ "Start an EVM test on the given channel, or stop EVM test.\n"
+ "\tArg 1 is channel number 1-14, or \"off\" or 0 to stop the test.\n"
+ "\tArg 2 is optional rate (1, 2, 5.5 or 11)"},
+ { "noise", wl_int, WLC_GET_PHY_NOISE, -1,
+ "Get noise (moving average) right after tx in dBm" },
+ { "fqacurcy", wl_int, -1, WLC_FREQ_ACCURACY,
+ "Manufacturing test: set frequency accuracy mode.\n"
+ "\tfreqacuracy syntax is: fqacurcy <channel>\n"
+ "\tArg is channel number 1-14, or 0 to stop the test." },
+ { "crsuprs", wl_int, -1, WLC_CARRIER_SUPPRESS,
+ "Manufacturing test: set carrier suppression mode.\n"
+ "\tcarriersuprs syntax is: crsuprs <channel>\n"
+ "\tArg is channel number 1-14, or 0 to stop the test." },
+ { "longtrain", wl_int, -1, WLC_LONGTRAIN,
+ "Manufacturing test: set longtraining mode.\n"
+ "\tlongtrain syntax is: longtrain <channel>\n"
+ "\tArg is A band channel number or 0 to stop the test." },
+ { "interference", wl_interfere, WLC_GET_INTERFERENCE_MODE, WLC_SET_INTERFERENCE_MODE,
+ "NON-ACPHY. Get/Set interference mitigation mode. Choices are:\n"
+ "\t0 = none\n"
+ "\t1 = non wlan\n"
+ "\t2 = wlan manual\n"
+ "\t3 = wlan automatic\n"
+ "\t4 = wlan automatic with noise reduction"
+ "\n\n\tACPHY. Get/Set interference mitigation mode. Bit-Mask:\n"
+ "\t0 = desense based on glitches\n"
+ "\t1 = limit pktgain based on hwaci (high pwr aci)\n"
+ "\t2 = limit pktgain based on w2/nb (high pwr aci)\n"
+ "\t3 = enable preemption\n"
+ "\t4 = enable HWACI based mitigation\n"
+ "\t5 = enable low power detect preemption (requires bit 3 - preemption - to be set too)\n"
+ "\tSo a value of 63 would enable all six\n"},
+ { "interference_override", wl_interfere_override,
+ WLC_GET_INTERFERENCE_OVERRIDE_MODE,
+ WLC_SET_INTERFERENCE_OVERRIDE_MODE,
+ "NON-ACPHY. Get/Set interference mitigation override. Choices are:\n"
+ "\t0 = no interference mitigation\n"
+ "\t1 = non wlan\n"
+ "\t2 = wlan manual\n"
+ "\t3 = wlan automatic\n"
+ "\t4 = wlan automatic with noise reduction\n"
+ "\t-1 = remove override, override disabled"
+ "\n\n\tACPHY. Get/Set interference mitigation mode. Bit-Mask:\n"
+ "\t-1 = remove override, override disabled\n"
+ "\t0 = desense based on glitches\n"
+ "\t1 = limit pktgain based on hwaci (high pwr aci)\n"
+ "\t2 = limit pktgain based on w2/nb (high pwr aci)\n"
+ "\t3 = enable preemption\n"
+ "\t4 = enable HWACI based mitigation\n"
+ "\t5 = enable low power detect preemption (requires bit 3 - preemption - to be set too)\n"
+ "\tSo a value of 63 would enable all six\n"},
+ { "phy_txpwrindex", wl_phy_txpwrindex, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: (set) phy_txpwrindex core0_idx core1_idx core2_idx core3_idx"
+ " (get) phy_txpwrindex, return format: core0_idx core1_idx core2_idx core3_idx"
+ "Set/Get txpwrindex"
+ },
+ { "rssi_cal_freq_grp_2g", wl_rssi_cal_freq_grp_2g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: wl_rssi_cal_freq_grp_2g [chan_1_2,chan_3_4,...,chan_13_14]\n"
+ "Each of the variables like - chan_1_2 is a byte"
+ "Upper nibble of this byte is for chan1 and lower for chan2"
+ "MSB of the nibble tells if the channel is used for calibration"
+ "3 LSB's tell which group the channel falls in"
+ "Set/get rssi calibration frequency grouping"
+ },
+ { "phy_rssi_gain_delta_2gb0", wl_phy_rssi_gain_delta_2g_sub, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rssi_gain_delta_2gb0 [val0 val1 ....]\n"
+ "Number of arguments can be - "
+ "\t 8 for single core (4345 and 4350)"
+ "\t 9 by specifying core_num followed by 8 arguments (4345 and 4350)"
+ "\t 16 for both cores (4350)"
+ "Set/get rssi gain delta values"
+ },
+ { "phy_rssi_gain_delta_2gb1", wl_phy_rssi_gain_delta_2g_sub, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rssi_gain_delta_2gb1 [val0 val1 ....]\n"
+ "Number of arguments can be - "
+ "\t 8 for single core (4345 and 4350)"
+ "\t 9 by specifying core_num followed by 8 arguments (4345 and 4350)"
+ "\t 16 for both cores (4350)"
+ "Set/get rssi gain delta values"
+ },
+ { "phy_rssi_gain_delta_2gb2", wl_phy_rssi_gain_delta_2g_sub, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rssi_gain_delta_2gb2 [val0 val1 ....]\n"
+ "Number of arguments can be - "
+ "\t 8 for single core (4345 and 4350)"
+ "\t 9 by specifying core_num followed by 8 arguments (4345 and 4350)"
+ "\t 16 for both cores (4350)"
+ "Set/get rssi gain delta values"
+ },
+ { "phy_rssi_gain_delta_2gb3", wl_phy_rssi_gain_delta_2g_sub, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rssi_gain_delta_2gb3 [val0 val1 ....]\n"
+ "Number of arguments can be - "
+ "\t 8 for single core (4345 and 4350)"
+ "\t 9 by specifying core_num followed by 8 arguments (4345 and 4350)"
+ "\t 16 for both cores (4350)"
+ "Set/get rssi gain delta values"
+ },
+ { "phy_rssi_gain_delta_2gb4", wl_phy_rssi_gain_delta_2g_sub, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rssi_gain_delta_2gb4 [val0 val1 ....]\n"
+ "Number of arguments can be - "
+ "\t 8 for single core (4345 and 4350)"
+ "\t 9 by specifying core_num followed by 8 arguments (4345 and 4350)"
+ "\t 16 for both cores (4350)"
+ "Set/get rssi gain delta values"
+ },
+ { "phy_rssi_gain_delta_2g", wl_phy_rssi_gain_delta_2g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rssi_gain_delta_2g [val0 val1 ....]\n"
+ "Set/get rssi gain delta values"
+ },
+ { "phy_rssi_gain_delta_5gl", wl_phy_rssi_gain_delta_5g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rssi_gain_delta_5gl [val0 val1 ....]\n"
+ "Set/get rssi gain delta values"
+ },
+ { "phy_rssi_gain_delta_5gml", wl_phy_rssi_gain_delta_5g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rssi_gain_delta_5gml [val0 val1 ....]\n"
+ "Set/get rssi gain delta values"
+ },
+ { "phy_rssi_gain_delta_5gmu", wl_phy_rssi_gain_delta_5g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rssi_gain_delta_5gmu [val0 val1 ....]\n"
+ "Set/get rssi gain delta values"
+ },
+ { "phy_rssi_gain_delta_5gh", wl_phy_rssi_gain_delta_5g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rssi_gain_delta_5gh [val0 val1 ....]\n"
+ "Set/get rssi gain delta values"
+ },
+ { "phy_rxgainerr_2g", wl_phy_rxgainerr_2g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rxgainerr_2g [val0 val1 ....]\n"
+ "Set/get rx gain delta values"
+ },
+ { "phy_rxgainerr_5gl", wl_phy_rxgainerr_5g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rxgainerr_5gl [val0 val1 ....]\n"
+ "Set/get rx gain delta values"
+ },
+ { "phy_rxgainerr_5gm", wl_phy_rxgainerr_5g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rxgainerr_5gml [val0 val1 ....]\n"
+ "Set/get rx gain delta values"
+ },
+ { "phy_rxgainerr_5gh", wl_phy_rxgainerr_5g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rxgainerr_5gmu [val0 val1 ....]\n"
+ "Set/get rx gain delta values"
+ },
+ { "phy_rxgainerr_5gu", wl_phy_rxgainerr_5g, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_rxgainerr_5gh [val0 val1 ....]\n"
+ "Set/get rx gain delta values"
+ },
+ { "phy_test_tssi", wl_test_tssi, WLC_GET_VAR, -1,
+ "wl phy_test_tssi val"},
+ { "phy_test_tssi_offs", wl_test_tssi_offs, WLC_GET_VAR, -1,
+ "wl phy_test_tssi_offs val"},
+ { "phy_rssiant", wl_phy_rssiant, WLC_GET_VAR, -1,
+ "wl phy_rssiant antindex(0-3)"},
+ { "phy_rssi_ant", wl_phy_rssi_ant, WLC_GET_VAR, WLC_SET_VAR,
+ "Get RSSI per antenna (only gives RSSI of current antenna for SISO PHY)"},
+ { "phy_test_idletssi", wl_test_idletssi, WLC_GET_VAR, -1,
+ "get idletssi for the given core; wl phy_test_idletssi corenum"},
+ { "phy_setrptbl", wl_var_void, -1, WLC_SET_VAR,
+ "populate the reciprocity compensation table based on SROM cal content\n\n"
+ "\tusage: wl phy_setrptbl"},
+ { "phy_forceimpbf", wl_var_void, -1, WLC_SET_VAR,
+ "force the beamformer into implicit TXBF mode and ready to construct steering matrix\n\n"
+ "\tusage: wl phy_forceimpbf"},
+ { "phy_forcesteer", wl_var_setint, -1, WLC_SET_VAR,
+ "force the beamformer to apply steering matrix when TXBF is turned on\n\n"
+ "\tusage: wl phy_forcesteer 1/0"},
+#if defined(BCMDBG)
+ { "phy_force_gainlevel", wl_phy_debug_cmd, WLC_GET_VAR, WLC_SET_VAR,
+ "Force rxgain level \n"
+ "\t 0 : force to init gain\n"
+ "\t 1 : force to clip hi gain\n"
+ "\t 2 : force to clip md gain\n"
+ "\t 3 : force to clip lo gain\n"
+ "\t 4 : force to adc clip gain\n"
+ "\t 5 : force to nb clip gain\n"
+ "\t 6 : force to wb clip gain\n"
+ "\t -1 : disable\n"
+ "\t usage: wl phy_force_gainlevel <int32 var>"
+ },
+#endif
+#if defined(BCMDBG)
+ { "phy_force_fdiqi", wl_phy_debug_cmd, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/disable FDIQI Cal/Comp \n"
+ "\t 0 : disable\n"
+ "\t 1 : enable\n"
+ "\t usage: wl phy_force_fdiqi <int32 var>"
+ },
+#endif
+#if defined(BCMDBG)
+ { "phy_btcoex_desense", wl_phy_debug_cmd, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/disable btcoex desense\n"
+ "\t 0 : disable\n"
+ "\t 1 : mode 1\n"
+ "\t usage: wl phy_btcoex_desense <int32 var>"
+ },
+#endif
+ { "phy_btcoex_desense_rxgain", wl_btcoex_desense_rxgain, WLC_GET_VAR, WLC_SET_VAR,
+ "Set the phy btcoex desence rxgain values \n"
+ "\t usage: wl phy_btcoex_desense_rxgain band num_cores value1 value2 ..\n"
+ "Get the phy btcoex desence rxgain values \n"
+ "\t usage: wl phy_btcoex_desense_rxgain ..\n"
+ },
+ { "lcnphy_papdepstbl", wl_phy_papdepstbl, -1, WLC_GET_VAR,
+ "print papd eps table; Usage: wl lcnphy_papdepstbl"
+ },
+ { "rifs", wl_rifs, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get the rifs status; usage: wl rifs <1/0> (On/Off)"
+ },
+ { "rifs_advert", wl_rifs_advert, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get the rifs mode advertisement status; usage: wl rifs_advert <-1/0> (Auto/Off)"
+ },
+ { "phy_rxiqest", wl_rxiq, WLC_GET_VAR, -1,
+ "Get phy RX IQ noise in dBm:\n"
+ "\t-s # of samples (2^n)\n"
+ "\t-a antenna select, 0,1,2 or 3\n"
+ "\t-r resolution select, 0 (coarse) or 1 (fine)\n"
+ "\t-f lpf hpc override select, 0 (hpc unchanged) or 1 (overridden to ltrn mode)\n"
+ "\t-w dig lpf override select, 0 (lpf unchanged) or 1 (overridden to ltrn_lpf mode)"
+ "\t or 2 (bypass)\n"
+ "\t-g gain-correction select, 0 (disable), 1(enable full correction) \n"
+ "\t 2 (enable temperature correction) or 3(verify rssi_gain_delta)\n"
+ "\t-e extra INITgain in dB on top of default. Valid values = {0, 3, 6, .., 21, 24}\n"
+ "\t-i gain mode select, 0 (default gain), 1 (fixed high gain) or 4 (fixed low gain)."
+ "\t-n number of averaging iterations.\n"
+ "\t-d delay in usecs between iterations - default 10usecs.\n"
+ },
+ { "phy_rxiqest_sweep", wl_rxiq_sweep, WLC_GET_VAR, -1,
+ "Get phy RX IQ noise in dBm for requested channels:\n"
+ "\t-c\n"
+ "\t\tall - All channels"
+ "\t\tcomma separated list of channels (e.g. 1,2,4,136)"
+ "\t-s # of samples (2^n)\n"
+ "\t-a antenna select, 0,1 or 3\n"
+ "\t-r resolution select, 0 (coarse) or 1 (fine)\n"
+ "\t-f lpf hpc override select, 0 (hpc unchanged) or 1 (overridden to ltrn mode)\n"
+ "\t-w dig lpf override select, 0 (lpf unchanged) or 1 (overridden to ltrn_lpf mode)"
+ "\t or 2 (bypass)\n"
+ "\t-g gain-correction select, 0 (disable), 1(enable full correction) \n"
+ "\t 2 (enable temperature correction) or 3(verify rssi_gain_delta)\n"
+ "\t-e extra INITgain in dB on top of default. Valid values = {0, 3, 6, .., 21, 24}\n"
+ "\t-i gain mode select, 0 (default gain), 1 (fixed high gain) or 4 (fixed low gain). \n"
+ "\t-n number of averaging iterations. Max 5 iterations for a sweep of 10 channels or more\n"
+ "\t-d delay in usecs between iterations - default 10usecs.\n"
+ },
+ { "phy_txiqcc", wl_phy_txiqcc, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_txiqcc [a b]\n"
+ "Set/get the iqcc a, b values"
+ },
+ { "phy_txlocc", wl_phy_txlocc, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: phy_txlocc [di dq ei eq fi fq]\n"
+ "Set/get locc di dq ei eq fi fq values"
+ },
+ { "phytable", wl_phytable, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: wl phytable table_id offset width_of_table_element [table_element]\n"
+ "Set/get table element of a table with the given ID at the given offset\n"
+ "Note that table width supplied should be 8, 16, 32, 48 or 64\n"
+ "table ID, table offset can not be negative"
+ },
+ { "force_vsdb_chans", wl_phy_force_vsdb_chans, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/get channels for forced vsdb mode\n"
+ "usage: wl force_vsdb_chans chan1 chan2\n"
+ "Note: Give chan in the same format as chanspec: eg force_vsdb_chans 1l 48u"
+ },
+ { "pavars", wl_phy_pavars, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/get temp PA parameters\n"
+ "usage: wl down\n"
+ " wl pavars pa2gw0a0=0x1 pa2gw1a0=0x2 pa2gw2a0=0x3 ... \n"
+ " wl pavars\n"
+ " wl up\n"
+ " override the PA parameters after driver attach(srom read), before diver up\n"
+ " These override values will be propogated to HW when driver goes up\n"
+ " PA parameters in one band range (2g, 5gl, 5g, 5gh) must all present if\n"
+ " one of them is specified in the command, otherwise it will be filled with 0"
+ },
+ { "povars", wl_phy_povars, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/get temp power offset\n"
+ "usage: wl down\n"
+ " wl povars cck2gpo=0x1 ofdm2gpo=0x2 mcs2gpo=0x3 ... \n"
+ " wl povars\n"
+ " wl up\n"
+ " override the power offset after driver attach(srom read), before diver up\n"
+ " These override values will be propogated to HW when driver goes up\n"
+ " power offsets in one band range (2g, 5gl, 5g, 5gh) must all present if\n"
+ " one of them is specified in the command, otherwise it will be filled with 0"
+ " cck(2g only), ofdm, and mcs(0-7) for NPHY are supported "
+ },
+ { "rpcalvars", wl_phy_rpcalvars, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/get temp RPCAL parameters\n"
+ "usage: wl down\n"
+ " wl rpcalvars rpcal2g=0x1 \n"
+ " wl rpcalvars\n"
+ " wl up\n"
+ " override the RPCAL parameters after driver attach(srom read), before diver up\n"
+ " These override values will be propogated to HW when driver goes up\n"
+ " Only the RPCAL parameter specified in the command is updated, the rest is untouched"
+ },
+ { "rpcalphasevars", wl_phy_rpcalphasevars, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/get temp RPCAL PHASE parameters\n"
+ "usage: wl down\n"
+ " wl rpcalphasevars rpcal_phase2g=0x1 \n"
+ " wl rpcalphasevars\n"
+ " wl up\n"
+ " override the RPCAL PHASE parameters after driver attach(srom read), before diver up\n"
+ " These override values will be propogated to HW when driver goes up\n"
+ " Only the RPCALPHASE parameter specified in command is updated, the rest is untouched"
+ },
+ { "fem", wl_phy_fem, WLC_GET_VAR, WLC_SET_VAR,
+ "Set temp fem2g/5g value\n"
+ "usage: wl fem (tssipos2g=0x1 extpagain2g=0x2 pdetrange2g=0x1 triso2g=0x1 antswctl2g=0)\n"
+ " (tssipos5g=0x1 extpagain5g=0x2 pdetrange5g=0x1 triso5g=0x1 antswctl5g=0)"
+ },
+ { "maxpower", wl_phy_maxpower, WLC_GET_VAR, WLC_SET_VAR,
+ "Set temp maxp2g(5g)a0(a1) value\n"
+ "usage: wl maxpower maxp2ga0=0x1 maxp2ga1=0x2 maxp5ga0=0xff maxp5ga1=0xff\n"
+ " maxp5gla0=0x3 maxp5gla1=0x4 maxp5gha0=0x5 maxp5gha1=0x6"
+ },
+ { "sample_collect", wl_sample_collect, WLC_PHY_SAMPLE_COLLECT, -1,
+ "Optional parameters ACPHY/HTPHY/(NPHY with NREV >= 7) are:\n"
+ "\t-f File name to dump the sample buffer (default \"sample_collect.dat\")\n"
+ "\t-t Trigger condition (default now)\n"
+ "\t\t now, good_fcs, bad_fcs, bad_plcp, crs, crs_glitch, crs_deassert\n"
+ "\t-b PreTrigger duration in us (default 10)\n"
+ "\t-a PostTrigger duration in us (default 10) \n"
+ "\t-m Sample collect mode (default 1) \n"
+ "\t\tSC_MODE_0_sd_adc\t\t\t0\n"
+ "\t\tSC_MODE_1_sd_adc_5bits\t\t\t1\n"
+ "\t\tSC_MODE_2_cic0\t\t\t\t2\n"
+ "\t\tSC_MODE_3_cic1\t\t\t\t3\n"
+ "\t\tSC_MODE_4s_rx_farrow_1core\t\t4\n"
+ "\t\tSC_MODE_4m_rx_farrow\t\t\t5\n"
+ "\t\tSC_MODE_5_iq_comp\t\t\t6\n"
+ "\t\tSC_MODE_6_dc_filt\t\t\t7\n"
+ "\t\tSC_MODE_7_rx_filt\t\t\t8\n"
+ "\t\tSC_MODE_8_rssi\t\t\t\t9\n"
+ "\t\tSC_MODE_9_rssi_all\t\t\t10\n"
+ "\t\tSC_MODE_10_tx_farrow\t\t\t11\n"
+ "\t\tSC_MODE_11_gpio\t\t\t\t12\n"
+ "\t\tSC_MODE_12_gpio_trans\t\t\t13\n"
+ "\t\tSC_MODE_14_spect_ana\t\t\t14\n"
+ "\t\tSC_MODE_5s_iq_comp\t\t\t15\n"
+ "\t\tSC_MODE_6s_dc_filt\t\t\t16\n"
+ "\t\tSC_MODE_7s_rx_filt\t\t\t17\n"
+ "\t\t HTPHY: 0=adc, 1..3=adc+rssi, 4=gpio\n"
+ "\t\t NPHY: 1=Dual-Core adc[9:2], 2=Core0 adc[9:0], 3=Core1 adc[9:0], gpio=gpio\n"
+ "\t-g GPIO mux select (default 0)\n"
+ "\t\t use only for gpio mode\n"
+ "\t-k GPIO capture mask. For ACPHY written to gpioCapMaskHigh/gpioCapMaskLow\n"
+ "\t\t use only for gpio mode (default 0xFFFFFFFF)\n"
+ "\t-d Downsample enable (default 0)\n"
+ "\t\t use only for HTPHY\n"
+ "\t-e BeDeaf enable (default 0)\n"
+ "\t-i Timeout in units of 10us. (ACPHY is in 10ms unit) (default 1000)\n"
+ "Optional parameters (NPHY with NREV < 7) are:\n"
+ "\t-u Sample collect duration in us (default 60)\n"
+ "\t-c Cores to do sample collect, only if BW=40MHz (default both)\n"
+ "Optional parameters LCN40PHY are:\n"
+ "\t-s Trigger State (default 0)\n"
+ "\t-x Module_Sel1 (default 2)\n"
+ "\t-y Module_Sel2 (default 6)\n"
+ "\t-n Number of samples (Max 2048, default 2048)\n"
+ "For (NREV < 7), the NPHY buffer returned has the format:\n"
+ "\tIn 20MHz [(uint16)num_bytes, <I(core0), Q(core0), I(core1), Q(core1)>]\n"
+ "\tIn 40MHz [(uint16)num_bytes(core0), <I(core0), Q(core0)>,\n"
+ "\t\t(uint16)num_bytes(core1), <I(core1), Q(core1)>]"},
+ { "pkteng_start", wl_pkteng, -1, WLC_SET_VAR,
+ "start packet engine tx usage: wl pkteng_start <xx:xx:xx:xx:xx:xx>"
+ " <tx|txwithack> [(async)|sync |sync_unblk] [ipg] [len] [nframes] [src]\n"
+ "\tstart packet engine rx usage: wl pkteng_start <xx:xx:xx:xx:xx:xx>"
+ " <rx|rxwithack> [(async)|sync] [rxframes] [rxtimeout]\n"
+ "\tsync: synchronous mode\n"
+ "\tsync_unblk: synchronous unblock mode\n"
+ "\tipg: inter packet gap in us\n"
+ "\tlen: packet length\n"
+ "\tnframes: number of frames; 0 indicates continuous tx test\n"
+ "\tsrc: source mac address\n"
+ "\trxframes: number of receive frames (sync mode only)\n"
+ "\trxtimeout: maximum timout in msec (sync mode only)"},
+ { "pkteng_stop", wl_pkteng, -1, WLC_SET_VAR,
+ "stop packet engine; usage: wl pkteng_stop <tx|rx>"},
+ { "pkteng_stats", wl_pkteng_stats, -1, WLC_GET_VAR,
+ "packet engine stats; usage: wl pkteng_stats:\n"
+ "\t-g temperature correction mode, 0 (enabled by default), 1 (disable)"},
+ { "pkteng_status", wl_pkteng_status, -1, WLC_GET_VAR,
+ "packet engine status; usage: wl pkteng_status"},
+ {"phy_force_crsmin", wl_phy_force_crsmin, -1, WLC_SET_VAR,
+ "Auto crsmin: \n"
+ " phy_force_crsmin -1\n"
+ "Default crsmin value\n\n"
+ " phy_force_crsmin 0\n"
+ "Set the crsmin value\n"
+ " phy_force_crsmin core0_th core1_offset core2_offset\n"
+ "\n"
+ "Threshold values = 2.5 x NoisePwr_dBm + intercept\n"
+ " where\n"
+ " NoisePwr_dBm ~= -36/-33/-30dBm for 20/40/80MHz, respectively\n"
+ " Intercept = 132/125/119 for 20/40/80MHz, respectively"
+ },
+ { "radarargs", wl_radar_args, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set Radar parameters in \n"
+ "\torder as version, npulses, ncontig, min_pw, max_pw, thresh0, thresh1,\n"
+ "\tblank, fmdemodcfg, npulses_lp, min_pw_lp, max_pw_lp,\n"
+ "\tmin_fm_lp, max_span_lp, min_deltat, max_deltat,\n"
+ "\tautocorr, st_level_time, t2_min, fra_pulse_err, npulses_fra,\n"
+ "\tnpulses_stg2, npulses_stg3, percal_mask, quant, \n"
+ "\tmin_burst_intv_lp, max_burst_intv_lp, nskip_rst_lp, max_pw_tol, feature_mask, \n"
+ "\tthresh0_sc, thresh1_sc"},
+ { "radarargs40", wl_radar_args, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set Radar parameters for 40Mhz channel in \n"
+ "\torder as version, npulses, ncontig, min_pw, max_pw, thresh0, thresh1,\n"
+ "\tthresh0_sc, thresh1_sc, blank, fmdemodcfg, npulses_lp, min_pw_lp, max_pw_lp,\n"
+ "\tmin_fm_lp, max_span_lp, min_deltat, max_deltat,\n"
+ "\tautocorr, st_level_time, t2_min, fra_pulse_err, npulses_fra,\n"
+ "\tnpulses_stg2, npulses_stg3, percal_mask, quant, \n"
+ "\tmin_burst_intv_lp, max_burst_intv_lp, nskip_rst_lp, max_pw_tol, feature_mask,\n"
+ "\tthresh0_sc, thresh1_sc"},
+ { "radarthrs", wl_radar_thrs, -1, WLC_SET_VAR,
+ "Set Radar threshold for both 20 & 40MHz & 80MHz BW:\n"
+ "\torder as thresh0_20_lo, thresh1_20_lo, thresh0_40_lo, thresh1_40_lo\n"
+ "\tthresh0_80_lo, thresh1_80_lo, thresh0_20_hi, thresh1_20_hi\n"
+ "\tthresh0_40_hi, thresh1_40_hi, thresh0_80_hi, thresh1_80_hi\n"
+ #ifdef WL11AC160
+ "\tthresh0_160_lo, thresh1_160_lo, thresh0_160_hi, thresh1_160_hi"
+ #endif
+ },
+ { "radarthrs2", wl_radar_thrs2, WLC_GET_VAR, WLC_SET_VAR,
+ "Set Radar threshold for both 20 & 40MHz & 80MHz BW:\n"
+ "\tthresh0_sc_20_lo, thresh1_sc_20_lo, thresh0_sc_40_lo, thresh1_sc_40_lo\n"
+ "\tthresh0_sc_80_lo, thresh1_sc_80_lo, thresh0_sc_20_hi, thresh1_sc_20_hi\n"
+ "\tthresh0_sc_40_hi, thresh1_sc_40_hi, thresh0_sc_80_hi, thresh1_sc_80_hi\n"
+ "\tfc_varth_sb, fc_varth_bin5_sb, notradar_enb, max_notradar_lp, max_notradar,\n"
+ "\tmax_notradar_lp_sc, max_notradar_sc, highpow_war_enb, highpow_sp_ratio"},
+ { "phy_dyn_switch_th", wl_phy_dyn_switch_th, WLC_GET_VAR, WLC_SET_VAR,
+ "Set wighting number for dynamic switch:\n"
+ "\trssi_gain_80_3, rssi_gain_80_2, rssi_gain_80_1, rssi_gain_80_0\n"
+ "\trssi_gain_160_3, rssi_gain_160_2, rssi_gain_160_1, rssi_gain_160_0\n"
+ "\trssi_th_2, rssi_th_1, rssi_th_0"},
+ { "phy_tpc_av", wl_phy_tpc_av, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: \n\t(set) phy_tpc_av <core> <sub-band> <av-value>"
+ " \n\t(get) phy_tpc_av <core> <sub-band>"
+ "\n\tSet/Get Av for the given core and sub-band"
+ "\n\tsub-band, 0 for 2G"
+ "\n\tsub-band, 1 for 5G-ll"
+ "\n\tsub-band, 2 for 5G-lu"
+ "\n\tsub-band, 3 for 5G-ul"
+ "\n\tsub-band, 4 for 5G-uu"
+ "\n\tav-value, 0 to 7"
+ },
+ { "phy_tpc_vmid", wl_phy_tpc_vmid, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: \n\t(set) phy_tpc_vmid <core> <sub-band> <vmid-value>"
+ " \n\t(get) phy_tpc_vmid <core> <sub-band>"
+ "\n\tSet/Get Vmid for the given core and sub-band"
+ "\n\tsub-band, 0 for 2G"
+ "\n\tsub-band, 1 for 5G-ll"
+ "\n\tsub-band, 2 for 5G-lu"
+ "\n\tsub-band, 3 for 5G-ul"
+ "\n\tsub-band, 4 for 5G-uu"
+ "\n\tvmid-value, 0 to 255"
+ },
+ /* TXCAL IOVARS */
+ {"phy_read_estpwrlut", wl_read_estpwrlut, WLC_GET_VAR, -1,
+ "Read EstPwr LUT: wl phy_read_estpwrlut core"},
+ { "txcal_gainsweep", wl_txcal_gainsweep, -1, WLC_SET_VAR,
+ "start Gain Sweep for TX Cal: wl txcal_gainsweep <xx:xx:xx:xx:xx:xx>"
+ " [ipg] [len] [nframes] [gidx_start:step:gidx_stop]\n"
+ "\tipg: inter packet gap in us\n"
+ "\tlen: packet length\n"
+ "\tnframes: number of frames; 0 indicates continuous tx test\n"
+ "\tgidx_start: Starting TX gain Index\n"
+ "\tgidx_stop: Stopping TX gain Index\n"
+ "\tstep:step size for tx gain index increment"},
+ { "txcal_gainsweep_meas", wl_txcal_gainsweep_meas, WLC_GET_VAR, WLC_SET_VAR,
+ "Get TSSI/PWR measurments from last TX Cal Gain Sweep: wl txcal_gainsweep_meas\n"
+ "Set PWR measurements for TX Cal Gain Sweep: wl txcal_gainsweep_meas core p0 p1 ... p127"},
+ {"txcal_pwr_tssi_tbl", wl_txcal_pwr_tssi_tbl, WLC_GET_VAR, WLC_SET_VAR,
+ "Get the saved consolidated TSSI/PWR table: wl txcal_pwr_tssi_tbl <core> <chan>\n"
+ "\tGenerate consolidated TSSI/PWR table from last TX Cal Gain Sweep:"
+ " wl txcal_pwr_tssi_tbl <core> <Ps> <N> <Ch>\n"
+ "\t\tPs: Starting Power in 6.3 format\n"
+ "\t\tN: Number of entries in the table covering the power range (Ps : (Ps+N-1))\n"
+ "\tSet the cosolidated TSSI/PWR table: "
+ "wl txcal_pwr_tssi_tbl <core> <Ps> <N> <Ch> <Tssi_Ps Tssi_Ps+1 .. Tssi_Ps+N-1>\n"
+ "\t\tPs: Starting Power in 6.3 format\n"
+ "\t\tN: Number of entries in the table covering the power range (Ps : (Ps+N-1))\n"
+ "\t\tCh: Channel Number\n"
+ "\t\tTssi_X: Adjusted TSSI corresponding to Power X\n"
+ "\tMax number of channel data allowed: 32\n"},
+ {"olpc_anchoridx", wl_olpc_anchoridx, WLC_GET_VAR, WLC_SET_VAR,
+ "Get the saved tx power idx and temperature at the olpc anchor power level:\n"
+ "wl olpc_anchoridx <core> <chan>\n"
+ "Set the temperature and tx power idx at the olpc anchor power level:\n"
+ "wl olpc_anchoridx <core> <chan> <idx> <temp>\n"
+ "olpc anchor power level is specified via nvram paramter or iovar.\n"},
+ {"olpc_offset", wl_olpc_offset, WLC_GET_VAR, WLC_SET_VAR,
+ "Get the offset to tx idx to be applied for baseindex calculation in LUT based OLPC\n"
+ "wl olpc_offset \n"
+ "Set the offset to tx idx to be applied for baseindex calculation in LUT based OLPC\n"
+ "wl olpc_offset 2G 5GLow 5GMid 5Ghigh 5GX1\n"},
+ { "phy_snr_ant", wl_phy_snr_ant, WLC_GET_VAR, WLC_SET_VAR,
+ "Get SNR per antenna (only gives SNR of current antenna for SISO PHY)"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_phy_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register phy commands */
+ wl_module_cmds_register(wl_phy_cmds);
+}
+
+static int
+wl_phy_rssi_ant(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ uint i;
+ wl_rssi_ant_t *rssi_ant_p;
+ struct ether_addr ea;
+ struct ether_addr *ea_p;
+ int ea_l;
+ void *ptr = NULL;
+
+ if (!*++argv) {
+ ea_p = NULL;
+ ea_l = 0;
+ }
+ else if (wl_ether_atoe(*argv, &ea)) {
+ ea_p = &ea;
+ ea_l = ETHER_ADDR_LEN;
+ }
+ else {
+ fprintf(stderr, " ERROR: no valid ether addr provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, ea_p, ea_l, &ptr)) < 0)
+ return ret;
+
+ rssi_ant_p = (wl_rssi_ant_t *)ptr;
+ rssi_ant_p->version = dtoh32(rssi_ant_p->version);
+ rssi_ant_p->count = dtoh32(rssi_ant_p->count);
+
+ if (rssi_ant_p->count == 0) {
+ printf("not supported on this chip\n");
+ } else {
+ for (i = 0; i < rssi_ant_p->count; i++)
+ printf("rssi[%d] %d ", i, rssi_ant_p->rssi_ant[i]);
+ printf("\n");
+ }
+ return ret;
+}
+
+static int
+wl_phy_snr_ant(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ uint i;
+ wl_snr_ant_t *snr_ant_p;
+ struct ether_addr ea;
+ struct ether_addr *ea_p;
+ int ea_l;
+ void *ptr = NULL;
+
+ if (!*++argv) {
+ ea_p = NULL;
+ ea_l = 0;
+ }
+ else if (wl_ether_atoe(*argv, &ea)) {
+ ea_p = &ea;
+ ea_l = ETHER_ADDR_LEN;
+ }
+ else {
+ fprintf(stderr, " ERROR: no valid ether addr provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((ret = wlu_var_getbuf_sm(wl, cmd->name, ea_p, ea_l, &ptr)) < 0)
+ return ret;
+
+ snr_ant_p = (wl_snr_ant_t *)ptr;
+ snr_ant_p->version = dtoh32(snr_ant_p->version);
+ snr_ant_p->count = dtoh32(snr_ant_p->count);
+
+ if (snr_ant_p->count == 0) {
+ printf("not supported on this chip\n");
+ } else {
+ for (i = 0; i < snr_ant_p->count; i++)
+ printf("snr[%d] %d ", i, snr_ant_p->snr_ant[i]);
+ printf("\n");
+ }
+ return ret;
+}
+
+
+#include <devctrl_if/phyioctl_defs.h>
+
+static phy_msg_t wl_phy_msgs[] = {
+ {PHYHAL_ERROR, "error"},
+ {PHYHAL_ERROR, "err"},
+ {PHYHAL_TRACE, "trace"},
+ {PHYHAL_INFORM, "inform"},
+ {PHYHAL_TMP, "tmp"},
+ {PHYHAL_TXPWR, "txpwr"},
+ {PHYHAL_CAL, "cal"},
+ {PHYHAL_RADAR, "radar"},
+ {PHYHAL_THERMAL, "thermal"},
+ {PHYHAL_PAPD, "papd"},
+ {PHYHAL_RXIQ, "rxiq"},
+ {PHYHAL_FCBS, "fcbs"},
+ {PHYHAL_CHANLOG, "chanlog"},
+ {0, NULL}
+ };
+
+static int
+wl_phymsglevel(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, i;
+ uint val = 0, last_val = 0;
+ uint phymsglevel = 0, phymsglevel_add = 0, phymsglevel_del = 0;
+ char *endptr;
+ phy_msg_t *phy_msg = wl_phy_msgs;
+ const char *cmdname = "phymsglevel";
+
+ UNUSED_PARAMETER(cmd);
+ if ((ret = wlu_iovar_getint(wl, cmdname, (int *)&phymsglevel) < 0)) {
+ return ret;
+ }
+ phymsglevel = dtoh32(phymsglevel);
+ if (!*++argv) {
+ printf("0x%x ", phymsglevel);
+ for (i = 0; (val = phy_msg[i].value); i++) {
+ if ((phymsglevel & val) && (val != last_val))
+ printf(" %s", phy_msg[i].string);
+ last_val = val;
+ }
+ printf("\n");
+ return (0);
+ }
+ while (*argv) {
+ char *s = *argv;
+ if (*s == '+' || *s == '-')
+ s++;
+ else
+ phymsglevel_del = ~0; /* make the whole list absolute */
+ val = strtoul(s, &endptr, 0);
+ if (val == 0xFFFFFFFF) {
+ fprintf(stderr,
+ "Bits >32 are not supported on this driver version\n");
+ val = 1;
+ }
+ /* not an integer if not all the string was parsed by strtoul */
+ if (*endptr != '\0') {
+ for (i = 0; (val = phy_msg[i].value); i++)
+ if (stricmp(phy_msg[i].string, s) == 0)
+ break;
+ if (!val)
+ goto usage;
+ }
+ if (**argv == '-')
+ phymsglevel_del |= val;
+ else
+ phymsglevel_add |= val;
+ ++argv;
+ }
+ phymsglevel &= ~phymsglevel_del;
+ phymsglevel |= phymsglevel_add;
+ phymsglevel = htod32(phymsglevel);
+ return (wlu_iovar_setint(wl, cmdname, (int)phymsglevel));
+
+usage:
+ fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");
+ fprintf(stderr, "Use a + or - prefix to make an incremental change.");
+ for (i = 0; (val = phy_msg[i].value); i++) {
+ if (val != last_val)
+ fprintf(stderr, "\n0x%04x %s", val, phy_msg[i].string);
+ else
+ fprintf(stderr, ", %s", phy_msg[i].string);
+ last_val = val;
+ }
+ return 0;
+}
+static int
+wl_get_instant_power(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ tx_inst_power_t *power;
+ uint band_list[3];
+
+ UNUSED_PARAMETER(cmd);
+ UNUSED_PARAMETER(argv);
+
+ strcpy(buf, "txinstpwr");
+ if ((ret = wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN)) < 0) {
+ return ret;
+ }
+
+ power = (tx_inst_power_t *)buf;
+ /* Make the most of the info returned in band_list!
+ * b/g and a
+ * b/g-uni
+ * a-uni
+ * NOTE: NO a and b/g case ...
+ */
+ if ((ret = wlu_get(wl, WLC_GET_BANDLIST, band_list, sizeof(band_list))) < 0)
+ return (ret);
+ band_list[0] = dtoh32(band_list[0]);
+ band_list[1] = dtoh32(band_list[1]);
+ band_list[2] = dtoh32(band_list[2]);
+
+ /* If B/G is present it's always the lower index */
+ if (band_list[1] == WLC_BAND_2G) {
+ printf("Last B phy CCK est. power:\t%2d.%d dBm\n",
+ DIV_QUO(power->txpwr_est_Pout[0], 4),
+ DIV_REM(power->txpwr_est_Pout[0], 4));
+ printf("Last B phy OFDM est. power:\t%2d.%d dBm\n",
+ DIV_QUO(power->txpwr_est_Pout_gofdm, 4),
+ DIV_REM(power->txpwr_est_Pout_gofdm, 4));
+
+ printf("\n");
+ }
+
+ /* A band */
+ if (band_list[1] == WLC_BAND_5G || (band_list[0] > 1 && band_list[2] == WLC_BAND_5G)) {
+ printf("Last A phy est. power:\t\t%2d.%d dBm\n",
+ DIV_QUO(power->txpwr_est_Pout[1], 4),
+ DIV_REM(power->txpwr_est_Pout[1], 4));
+ }
+
+ return ret;
+}
+
+static int
+wl_evm(void *wl, cmd_t *cmd, char **argv)
+{
+ int val[3];
+
+ /* Get channel */
+ if (!*++argv) {
+ fprintf(stderr, "Need to specify at least one parameter\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!stricmp(*argv, "off"))
+ val[0] = 0;
+ else
+ val[0] = atoi(*argv);
+
+ /* set optional parameters to default */
+ val[1] = 4; /* rate in 500Kb units */
+ val[2] = 0; /* This is ignored */
+
+ /* Get optional rate and convert to 500Kb units */
+ if (*++argv)
+ val[1] = rate_string2int(*argv);
+
+ val[0] = htod32(val[0]);
+ val[1] = htod32(val[1]);
+ val[2] = htod32(val[2]);
+ return wlu_set(wl, cmd->set, val, sizeof(val));
+}
+
+static int
+wl_tssi(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int val;
+
+ UNUSED_PARAMETER(argv);
+
+ if (cmd->get < 0)
+ return -1;
+ if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0)
+ return ret;
+
+ val = dtoh32(val);
+ printf("CCK %d OFDM %d\n", (val & 0xff), (val >> 8) & 0xff);
+ return 0;
+}
+
+static int
+wl_atten(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ atten_t atten;
+ char *endptr;
+
+ memset(&atten, 0, sizeof(atten_t));
+
+ if (!*++argv) {
+ if (cmd->get < 0)
+ return -1;
+
+ if ((ret = wlu_get(wl, cmd->get, &atten, sizeof(atten_t))) < 0)
+ return ret;
+
+ printf("tx %s bb/radio/ctl1 %d/%d/%d\n",
+ (dtoh16(atten.auto_ctrl) ? "auto" : ""),
+ dtoh16(atten.bb), dtoh16(atten.radio), dtoh16(atten.txctl1));
+
+ return 0;
+ } else {
+ if (cmd->set < 0)
+ return -1;
+
+ if (!stricmp(*argv, "auto")) {
+ atten.auto_ctrl = WL_ATTEN_PCL_ON;
+ atten.auto_ctrl = htod16(atten.auto_ctrl);
+ }
+ else if (!stricmp(*argv, "manual")) {
+ atten.auto_ctrl = WL_ATTEN_PCL_OFF;
+ atten.auto_ctrl = htod16(atten.auto_ctrl);
+ }
+ else {
+ atten.auto_ctrl = WL_ATTEN_APP_INPUT_PCL_OFF;
+ atten.auto_ctrl = htod16(atten.auto_ctrl);
+
+ atten.bb = (uint16)strtoul(*argv, &endptr, 0);
+ atten.bb = htod16(atten.bb);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ atten.radio = (uint16)strtoul(*argv, &endptr, 0);
+ atten.radio = htod16(atten.radio);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ atten.txctl1 = (uint16)strtoul(*argv, &endptr, 0);
+ atten.txctl1 = htod16(atten.txctl1);
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ return BCME_USAGE_ERROR;
+ }
+
+ }
+
+ return wlu_set(wl, cmd->set, &atten, sizeof(atten_t));
+ }
+}
+
+static int
+wl_interfere(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int val;
+ char *endptr = NULL;
+ int mode;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (ret) {
+ return ret;
+ }
+ phytype = dtoh32(revinfo.phytype);
+
+ if (!*++argv) {
+ if (cmd->get < 0)
+ return -1;
+ if ((ret = wlu_get(wl, cmd->get, &mode, sizeof(mode))) < 0)
+ return ret;
+ mode = dtoh32(mode);
+ if (phytype == WLC_PHY_TYPE_AC) {
+ mode &= 0x7f;
+ if (mode == INTERFERE_NONE) {
+ printf("All interference mitigation is disabled. (mode 0)\n");
+ } else {
+ printf("\nMode = %d. Following ACI modes are enabled:\n", mode);
+ if (mode & ACPHY_ACI_GLITCHBASED_DESENSE)
+ printf("\tbit-mask %d: Reciever Desense based on glitch "
+ "count\n",
+ ACPHY_ACI_GLITCHBASED_DESENSE);
+ if (mode & ACPHY_ACI_HWACI_PKTGAINLMT)
+ printf("\tbit-mask %d: Limit pktgain based on hwaci "
+ "(high pwr aci)\n",
+ ACPHY_ACI_HWACI_PKTGAINLMT);
+ if (mode & ACPHY_ACI_W2NB_PKTGAINLMT)
+ printf("\tbit-mask %d: Limit pktgain based on w2/nb "
+ "(high pwr aci)\n",
+ ACPHY_ACI_W2NB_PKTGAINLMT);
+ if (mode & ACPHY_ACI_PREEMPTION)
+ printf("\tbit-mask %d: Preemption is enabled\n",
+ ACPHY_ACI_PREEMPTION);
+ if (mode & ACPHY_HWACI_MITIGATION)
+ printf("\tbit-mask %d: HW ACI Detection + Mitigation\n",
+ ACPHY_HWACI_MITIGATION);
+ if (mode & ACPHY_LPD_PREEMPTION)
+ printf("\tbit-mask %d: Low Power Detect Preemption\n",
+ ACPHY_LPD_PREEMPTION);
+ if (mode & ACPHY_HWOBSS_MITIGATION)
+ printf("\tbit-mask %d: HW OBSS Detection + Mitigation\n",
+ ACPHY_HWOBSS_MITIGATION);
+ }
+ printf("\n");
+ } else {
+ switch (mode & 0x7f) {
+ case INTERFERE_NONE:
+ printf("All interference mitigation is disabled. (mode 0)\n");
+ break;
+ case NON_WLAN:
+ printf("Non-wireless LAN Interference mitigation is enabled."
+ " (mode 1)\n");
+ break;
+ case WLAN_MANUAL:
+ printf("Wireless LAN Interference mitigation is enabled."
+ " (mode 2)\n");
+ break;
+ case WLAN_AUTO:
+ printf("Auto Wireless LAN Interference mitigation is enabled and ");
+ if (mode & AUTO_ACTIVE)
+ printf("active. (mode 3)\n");
+ else
+ printf("not active. (mode 3)\n");
+
+ break;
+ case WLAN_AUTO_W_NOISE:
+ printf("Auto Wireless LAN Interference mitigation is enabled and ");
+ if (mode & AUTO_ACTIVE)
+ printf("active, ");
+ else
+ printf("not active, ");
+
+ printf("and noise reduction is enabled. (mode 4)\n");
+ break;
+ }
+ }
+ return 0;
+ } else {
+ mode = INTERFERE_NONE;
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ if (phytype == WLC_PHY_TYPE_AC) {
+ if (val > ACPHY_ACI_MAX_MODE) {
+ printf("ACPHY Interference mode > ACPHY_ACI_MAX_MODE!\n");
+ return -1;
+ } else if ((val & ACPHY_LPD_PREEMPTION) && !(val & ACPHY_ACI_PREEMPTION)) {
+ fprintf(stderr, "Low Power Detect Preemption (bit 5)"
+ " requires Preemption (bit3) to be enabled\n");
+ return BCME_USAGE_ERROR;
+ } else {
+ mode = val;
+ }
+ } else {
+ switch (val) {
+ case 0:
+ mode = INTERFERE_NONE;
+ break;
+ case 1:
+ mode = NON_WLAN;
+ break;
+ case 2:
+ mode = WLAN_MANUAL;
+ break;
+ case 3:
+ mode = WLAN_AUTO;
+ break;
+ case 4:
+ mode = WLAN_AUTO_W_NOISE;
+ break;
+ default:
+ return BCME_BADARG;
+ }
+ }
+
+ mode = htod32(mode);
+ return wlu_set(wl, cmd->set, &mode, sizeof(mode));
+ }
+}
+
+static int
+wl_interfere_override(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int val;
+ char *endptr;
+ int mode;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (ret) {
+ return ret;
+ }
+ phytype = dtoh32(revinfo.phytype);
+
+ if (!*++argv) {
+ if (cmd->get < 0)
+ return -1;
+ if ((ret = wlu_get(wl, cmd->get, &mode, sizeof(mode))) < 0) {
+ return ret;
+ }
+ printf("\nMode = %d. Following ACI modes :\n", mode);
+ mode = dtoh32(mode);
+ if (phytype == WLC_PHY_TYPE_AC) {
+ if (mode == INTERFERE_OVRRIDE_OFF)
+ printf("Interference override disabled.\n");
+ else if (mode == INTERFERE_NONE)
+ printf("Interference override NONE, "
+ "all mitigation disabled. (mode 0)\n");
+ else {
+ printf("\nInterference override mode = %d. Following ACI modes "
+ "are enabled:\n", mode);
+ if (mode & ACPHY_ACI_GLITCHBASED_DESENSE)
+ printf("\tbit-mask %d: Reciever Desense based on glitch "
+ "count\n",
+ ACPHY_ACI_GLITCHBASED_DESENSE);
+ if (mode & ACPHY_ACI_HWACI_PKTGAINLMT)
+ printf("\tbit-mask %d: Limit pktgain based on hwaci "
+ "(high pwr aci)\n",
+ ACPHY_ACI_HWACI_PKTGAINLMT);
+ if (mode & ACPHY_ACI_W2NB_PKTGAINLMT)
+ printf("\tbit-mask %d: Limit pktgain based on w2/nb "
+ "(high pwr aci)\n",
+ ACPHY_ACI_W2NB_PKTGAINLMT);
+ if (mode & ACPHY_ACI_PREEMPTION)
+ printf("\tbit-mask %d: Preemption is enabled\n",
+ ACPHY_ACI_PREEMPTION);
+ if (mode & ACPHY_HWACI_MITIGATION)
+ printf("\tbit-mask %d: HW ACI Detection + Mitigation\n",
+ ACPHY_HWACI_MITIGATION);
+ if (mode & ACPHY_LPD_PREEMPTION)
+ printf("\tbit-mask %d: Low Power Detect Preemption\n",
+ ACPHY_LPD_PREEMPTION);
+ if (mode & ACPHY_HWOBSS_MITIGATION)
+ printf("\tbit-mask %d: HW OBSS Detection + Mitigation\n",
+ ACPHY_HWOBSS_MITIGATION);
+ }
+ printf("\n");
+ } else {
+ switch (mode & 0x7f) {
+ case INTERFERE_NONE:
+ printf("Interference override NONE, "
+ "all mitigation disabled. (mode 0)\n");
+ break;
+ case NON_WLAN:
+ printf("Interference override enabled. "
+ " Non-wireless LAN Interference mitigation is enabled."
+ " (mode 1)\n");
+ break;
+ case WLAN_MANUAL:
+ printf("Interference override enabled. "
+ " Wireless LAN Interference mitigation is enabled."
+ " (mode 2)\n");
+ break;
+ case WLAN_AUTO:
+ printf("Interference override enabled. "
+ " Interference mitigation is enabled and ");
+ if (mode & AUTO_ACTIVE)
+ printf("active. (mode 3)\n");
+ else
+ printf("not active. (mode 3)\n");
+ break;
+ case WLAN_AUTO_W_NOISE:
+ printf("Interference override enabled. "
+ " Interference mitigation is enabled and ");
+ if (mode & AUTO_ACTIVE)
+ printf("active, ");
+ else
+ printf("not active, ");
+ printf("and noise reduction is enabled. (mode 4)\n");
+ break;
+ case INTERFERE_OVRRIDE_OFF:
+ printf("Interference override disabled. \n");
+ break;
+ }
+ }
+ return 0;
+ } else {
+ mode = INTERFERE_NONE;
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ if (phytype == WLC_PHY_TYPE_AC) {
+ if (val > ACPHY_ACI_MAX_MODE) {
+ return -1;
+ } else if ((val & ACPHY_LPD_PREEMPTION) && !(val & ACPHY_ACI_PREEMPTION)) {
+ fprintf(stderr, "Low Power Detect Preemption (bit 5)"
+ " requires Preemption (bit3) to be enabled\n");
+ return BCME_USAGE_ERROR;
+ } else {
+ mode = val;
+ }
+ } else {
+ switch (val) {
+ case 0:
+ mode = INTERFERE_NONE;
+ break;
+ case 1:
+ mode = NON_WLAN;
+ break;
+ case 2:
+ mode = WLAN_MANUAL;
+ break;
+ case 3:
+ mode = WLAN_AUTO;
+ break;
+ case 4:
+ mode = WLAN_AUTO_W_NOISE;
+ break;
+ case INTERFERE_OVRRIDE_OFF:
+ mode = INTERFERE_OVRRIDE_OFF;
+ break;
+ default:
+ return BCME_BADARG;
+ }
+ }
+
+ mode = htod32(mode);
+ return wlu_set(wl, cmd->set, &mode, sizeof(mode));
+ }
+}
+
+#define ACI_SPIN "spin"
+#define ACI_ENTER "enter"
+#define ACI_EXIT "exit"
+#define ACI_GLITCH "glitch"
+
+#define NPHY_ACI_ADCPWR_ENTER "adcpwr_enter"
+#define NPHY_ACI_ADCPWR_EXIT "adcpwr_exit"
+#define NPHY_ACI_REPEAT_CTR "repeat"
+#define NPHY_ACI_NUM_SAMPLES "samples"
+#define NPHY_ACI_UNDETECT "undetect_sz"
+#define NPHY_ACI_LOPWR "loaci"
+#define NPHY_ACI_MDPWR "mdaci"
+#define NPHY_ACI_HIPWR "hiaci"
+#define NPHY_ACI_NOISE_NOASSOC_GLITCH_TH_UP "nphy_noise_noassoc_glitch_th_up"
+#define NPHY_ACI_NOISE_NOASSOC_GLITCH_TH_DN "nphy_noise_noassoc_glitch_th_dn"
+#define NPHY_ACI_NOISE_ASSOC_GLITCH_TH_UP "nphy_noise_assoc_glitch_th_up"
+#define NPHY_ACI_NOISE_ASSOC_GLITCH_TH_DN "nphy_noise_assoc_glitch_th_dn"
+#define NPHY_ACI_NOISE_ASSOC_ACI_GLITCH_TH_UP "nphy_noise_assoc_aci_glitch_th_up"
+#define NPHY_ACI_NOISE_ASSOC_ACI_GLITCH_TH_DN "nphy_noise_assoc_aci_glitch_th_dn"
+#define NPHY_ACI_NOISE_NOASSOC_ENTER_TH "nphy_noise_noassoc_enter_th"
+#define NPHY_ACI_NOISE_ASSOC_ENTER_TH "nphy_noise_assoc_enter_th"
+#define NPHY_ACI_NOISE_ASSOC_RX_GLITCH_BADPLCP_ENTER_TH \
+"nphy_noise_assoc_rx_glitch_badplcp_enter_th"
+#define NPHY_ACI_NOISE_ASSOC_CRSIDX_INCR "nphy_noise_assoc_crsidx_incr"
+#define NPHY_ACI_NOISE_NOASSOC_CRSIDX_INCR "nphy_noise_noassoc_crsidx_incr"
+#define NPHY_ACI_NOISE_CRSIDX_DECR "nphy_noise_crsidx_decr"
+
+
+#if defined(BWL_FILESYSTEM_SUPPORT)
+#if !defined(DONGLEBUILD)
+static int
+wl_do_samplecollect_lcn40(void *wl, wl_samplecollect_args_t *collect, uint8 *buff, FILE *fp)
+{
+ uint32 cnt;
+ int ret = 0;
+ uint32 *data;
+ int16 IData, QData;
+ uint16 wordlength = 14;
+ uint16 mask = ((0x1 << wordlength) - 1);
+ uint16 wrap = (0x1 << (wordlength - 1));
+ uint16 maxd = (0x1 << wordlength);
+
+ ret = wlu_iovar_getbuf(wl, "sample_collect", collect, sizeof(wl_samplecollect_args_t),
+ buff, WLC_SAMPLECOLLECT_MAXLEN);
+
+ if (ret)
+ return ret;
+
+ data = (uint32*)buff;
+ for (cnt = 0; cnt < collect->nsamps; cnt++) {
+
+ IData = data[cnt] & mask;
+ QData = ((data[cnt] >> 16) & mask);
+
+ if (IData >= wrap) {
+ IData = IData - maxd;
+ }
+ if (QData >= wrap) {
+ QData = QData - maxd;
+ }
+ fprintf(fp, "%d %d\n", IData, QData);
+ }
+ return cnt;
+}
+static int
+wl_do_samplecollect_n(void *wl, wl_samplecollect_args_t *collect, uint8 *buff, FILE *fp)
+{
+ uint16 nbytes;
+ int ret = 0;
+
+ ret = wlu_iovar_getbuf(wl, "sample_collect", collect, sizeof(wl_samplecollect_args_t),
+ buff, WLC_SAMPLECOLLECT_MAXLEN);
+
+ if (ret)
+ return ret;
+
+ /* bytes 1:0 indicate capture length */
+ while ((nbytes = ltoh16_ua(buff))) {
+ nbytes += 2;
+ ret = fwrite(buff, 1, nbytes, fp);
+ if (ret != nbytes) {
+ fprintf(stderr, "Error writing %d bytes to file, rc %d!\n",
+ nbytes, ret);
+ ret = -1;
+ break;
+ } else {
+ fprintf(stderr, "Wrote %d bytes\n", nbytes);
+ }
+ buff += nbytes;
+ }
+ return (ret);
+}
+#endif
+#endif /* defined(BWL_FILESYSTEM_SUPPORT) */
+
+#if defined(BWL_FILESYSTEM_SUPPORT)
+#if !defined(DONGLEBUILD)
+static int
+wl_do_samplecollect(void *wl, wl_samplecollect_args_t *collect, int sampledata_version,
+ uint32 *buff, FILE *fp)
+{
+ uint16 nbytes, tag;
+ uint32 flag, *header, sync;
+ uint8 *ptr;
+ int err;
+ wl_sampledata_t *sample_collect;
+ wl_sampledata_t sample_data, *psample;
+
+ err = wlu_iovar_getbuf(wl, "sample_collect", collect, sizeof(wl_samplecollect_args_t),
+ buff, WLC_SAMPLECOLLECT_MAXLEN);
+
+ if (err)
+ return err;
+
+ sample_collect = (wl_sampledata_t *)buff;
+ header = (uint32 *)&sample_collect[1];
+ tag = ltoh16_ua(&sample_collect->tag);
+ if (tag != WL_SAMPLEDATA_HEADER_TYPE) {
+ fprintf(stderr, "Expect SampleData Header type %d, receive type %d\n",
+ WL_SAMPLEDATA_HEADER_TYPE, tag);
+ return -1;
+ }
+
+ nbytes = ltoh16_ua(&sample_collect->length);
+ flag = ltoh32_ua(&sample_collect->flag);
+ sync = ltoh32_ua(&header[0]);
+ if (sync != 0xACDC2009) {
+ fprintf(stderr, "Header sync word mismatch (0x%08x)\n", sync);
+ return -1;
+ }
+
+ err = fwrite((uint8 *)header, 1, nbytes, fp);
+ if (err != (int)nbytes)
+ fprintf(stderr, "Failed write file-header to file %d\n", err);
+
+ memset(&sample_data, 0, sizeof(wl_sampledata_t));
+ sample_data.version = sampledata_version;
+ sample_data.size = htol16(sizeof(wl_sampledata_t));
+ flag = 0;
+ /* new format, used in htphy */
+ do {
+ sample_data.tag = htol16(WL_SAMPLEDATA_TYPE);
+ sample_data.length = htol16(WLC_SAMPLECOLLECT_MAXLEN);
+ /* mask seq# */
+ sample_data.flag = htol32((flag & 0xff));
+
+ err = wlu_iovar_getbuf(wl, "sample_data", &sample_data, sizeof(wl_sampledata_t),
+ buff, WLC_SAMPLECOLLECT_MAXLEN);
+ if (err) {
+ fprintf(stderr, "Error reading back sample collected data\n");
+ err = -1;
+ break;
+ }
+
+ ptr = (uint8 *)buff + sizeof(wl_sampledata_t);
+ psample = (wl_sampledata_t *)buff;
+ tag = ltoh16_ua(&psample->tag);
+ nbytes = ltoh16_ua(&psample->length);
+ flag = ltoh32_ua(&psample->flag);
+ if (tag != WL_SAMPLEDATA_TYPE) {
+ fprintf(stderr, "Expect SampleData type %d, receive type %d\n",
+ WL_SAMPLEDATA_TYPE, tag);
+ err = -1;
+ break;
+ }
+ if (nbytes == 0) {
+ fprintf(stderr, "Done retrieving sample data\n");
+ err = -1;
+ break;
+ }
+
+ err = fwrite(ptr, 1, nbytes, fp);
+ if (err != (int)nbytes) {
+ fprintf(stderr, "Error writing %d bytes to file, rc %d!\n",
+ (int)nbytes, err);
+ err = -1;
+ break;
+ } else {
+ printf("Wrote %d bytes\n", err);
+ err = 0;
+ }
+ } while (flag & WL_SAMPLEDATA_MORE_DATA);
+ return err;
+}
+#endif
+#endif /* defined(BWL_FILESYSTEM_SUPPORT) */
+
+static int
+wl_sample_collect(void *wl, cmd_t *cmd, char **argv)
+{
+#if !defined(BWL_FILESYSTEM_SUPPORT)
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
+ return (-1);
+#elif defined(DONGLEBUILD)
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
+ return 0;
+#else
+ int ret = -1;
+ uint8 *buff = NULL;
+ wl_samplecollect_args_t collect;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+ uint32 phyrev;
+ const char *fname = "sample_collect.dat";
+ FILE *fp = NULL;
+
+ /* Default setting for sampledata_version */
+ int sampledata_version = htol16(WL_SAMPLEDATA_T_VERSION);
+
+ UNUSED_PARAMETER(cmd);
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ if ((ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0)
+ return ret;
+
+ phytype = dtoh32(revinfo.phytype);
+ phyrev = dtoh32(revinfo.phyrev);
+
+ /* Assign some default params first */
+ /* 60us is roughly the max we can store (for NPHY with NREV < 7). */
+ collect.coll_us = 60;
+ collect.cores = -1;
+ collect.bitStart = -1;
+ /* extended settings */
+ collect.trigger = TRIGGER_NOW;
+ collect.mode = 1;
+ collect.post_dur = 10;
+ collect.pre_dur = 10;
+ collect.gpio_sel = 0;
+ collect.gpioCapMask = (uint32)-1;
+ collect.downsamp = FALSE;
+ collect.be_deaf = FALSE;
+ collect.timeout = 1000;
+ collect.agc = FALSE;
+ collect.filter = FALSE;
+ collect.trigger_state = 0;
+ collect.module_sel1 = 2;
+ collect.module_sel2 = 6;
+ collect.nsamps = 2048;
+ collect.version = WL_SAMPLECOLLECT_T_VERSION;
+ collect.length = sizeof(wl_samplecollect_args_t);
+
+ /* Skip the command name */
+ argv++;
+ ret = -1;
+ while (*argv) {
+ char *s = *argv;
+
+ if (argv[1] == NULL) {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ if (!strcmp(s, "-f")) {
+ fname = argv[1];
+ } else if (!strcmp(s, "-u"))
+ collect.coll_us = atoi(argv[1]);
+ else if (!strcmp(s, "-c"))
+ collect.cores = atoi(argv[1]);
+ /* extended settings */
+ else if (!strcmp(s, "-t")) {
+ /* event trigger */
+ if (!strcmp(argv[1], "crs"))
+ collect.trigger = TRIGGER_CRS;
+ else if (!strcmp(argv[1], "crs_deassert"))
+ collect.trigger = TRIGGER_CRSDEASSERT;
+ else if (!strcmp(argv[1], "good_fcs"))
+ collect.trigger = TRIGGER_GOODFCS;
+ else if (!strcmp(argv[1], "bad_fcs"))
+ collect.trigger = TRIGGER_BADFCS;
+ else if (!strcmp(argv[1], "bad_plcp"))
+ collect.trigger = TRIGGER_BADPLCP;
+ else if (!strcmp(argv[1], "crs_glitch"))
+ collect.trigger = TRIGGER_CRSGLITCH;
+ }
+ else if (!strcmp(s, "-m")) {
+ if (!strcmp(argv[1], "gpio")) {
+ if (phytype == WLC_PHY_TYPE_HT) {
+ collect.mode = 4;
+ } else {
+ /* MIMOPHY */
+ collect.mode = 0xff;
+ }
+ } else {
+ collect.mode = atoi(argv[1]);
+ }
+ }
+ else if (!strcmp(s, "-k"))
+ collect.gpioCapMask = atoi(argv[1]);
+ else if (!strcmp(s, "-s"))
+ collect.bitStart = atoi(argv[1]);
+ else if (!strcmp(s, "-b"))
+ collect.pre_dur = atoi(argv[1]);
+ else if (!strcmp(s, "-a"))
+ collect.post_dur = atoi(argv[1]);
+ else if (!strcmp(s, "-g"))
+ collect.gpio_sel = atoi(argv[1]);
+ else if (!strcmp(s, "-d"))
+ collect.downsamp = atoi(argv[1]);
+ else if (!strcmp(s, "-e"))
+ collect.be_deaf = atoi(argv[1]);
+ else if (!strcmp(s, "-i"))
+ collect.timeout = atoi(argv[1]);
+ else if (!strcmp(s, "--agc")) {
+ /* perform software agc for sample collect */
+ collect.agc = atoi(argv[1]);
+ }
+ else if (!strcmp(s, "--filter")) {
+ /* Set HPC for LPF to lowest possible value (0x1) */
+ collect.filter = atoi(argv[1]);
+ }
+ else if (!strcmp(s, "-v"))
+ sampledata_version = atoi(argv[1]);
+ else if (!strcmp(s, "-s"))
+ collect.trigger_state = atoi(argv[1]);
+ else if (!strcmp(s, "-x"))
+ collect.module_sel1 = atoi(argv[1]);
+ else if (!strcmp(s, "-y"))
+ collect.module_sel2 = atoi(argv[1]);
+ else if (!strcmp(s, "-n"))
+ collect.nsamps = atoi(argv[1]);
+ else {
+ ret = BCME_USAGE_ERROR;
+ goto exit;
+ }
+
+ argv += 2;
+ }
+
+ buff = malloc(WLC_SAMPLECOLLECT_MAXLEN);
+ if (buff == NULL) {
+ fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n",
+ WLC_SAMPLECOLLECT_MAXLEN);
+ return BCME_NOMEM;
+ }
+ memset(buff, 0, WLC_SAMPLECOLLECT_MAXLEN);
+
+ if ((fp = fopen(fname, "wb")) == NULL) {
+ fprintf(stderr, "Problem opening file %s\n", fname);
+ ret = BCME_BADARG;
+ goto exit;
+ }
+
+ if ((phytype == WLC_PHY_TYPE_HT) || (phytype == WLC_PHY_TYPE_AC)) {
+ ret = wl_do_samplecollect(wl, &collect, sampledata_version, (uint32 *)buff, fp);
+ }
+ else if (phytype == WLC_PHY_TYPE_N) {
+ if (phyrev < 7) {
+ ret = wl_do_samplecollect_n(wl, &collect, buff, fp);
+ } else {
+ ret = wl_do_samplecollect(wl, &collect, sampledata_version,
+ (uint32 *)buff, fp);
+ }
+ } else if (phytype == WLC_PHY_TYPE_LCN40) {
+ if (collect.nsamps > (WLC_SAMPLECOLLECT_MAXLEN >> 2)) {
+ fprintf(stderr, "Max number of samples supported = %d\n",
+ WLC_SAMPLECOLLECT_MAXLEN >> 2);
+ ret = -1;
+ goto exit;
+ }
+ ret = wl_do_samplecollect_lcn40(wl, &collect, buff, fp);
+ }
+exit:
+ if (buff) free(buff);
+#ifndef ATE_BUILD
+ if (fp) fclose(fp);
+#endif
+ return ret;
+#endif /* !BWL_FILESYSTEM_SUPPORT */
+}
+
+static int
+wl_test_tssi(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int val;
+ char* endptr = NULL;
+
+ /* toss the command name */
+ argv++;
+
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+
+ val = htod32(strtol(*argv, &endptr, 0));
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ printf("set: error parsing value \"%s\" as an integer\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ ret = wlu_iovar_getbuf(wl, cmd->name, &val, sizeof(val),
+ buf, WLC_IOCTL_MAXLEN);
+
+ if (ret)
+ return ret;
+
+ val = dtoh32(*(int*)buf);
+
+ wl_printint(val);
+
+ return ret;
+}
+
+static int
+wl_test_tssi_offs(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int val;
+ char* endptr = NULL;
+
+ /* toss the command name */
+ argv++;
+
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+
+ val = htod32(strtol(*argv, &endptr, 0));
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ printf("set: error parsing value \"%s\" as an integer\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ ret = wlu_iovar_getbuf(wl, cmd->name, &val, sizeof(val),
+ buf, WLC_IOCTL_MAXLEN);
+
+ if (ret)
+ return ret;
+
+ val = dtoh32(*(int*)buf);
+
+ wl_printint(val);
+
+ return ret;
+}
+
+static int
+wl_test_idletssi(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ int val;
+ char* endptr = NULL;
+
+ /* toss the command name */
+ argv++;
+
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+
+ val = htod32(strtol(*argv, &endptr, 0));
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ printf("set: error parsing value \"%s\" as an integer\n", *argv);
+ return -1;
+ }
+
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, &val, sizeof(val),
+ buf, WLC_IOCTL_MAXLEN)) >= 0) {
+ val = dtoh32(*(int*)buf);
+ wl_printint(val);
+ }
+
+ return ret;
+}
+
+static int
+wl_phy_rssiant(void *wl, cmd_t *cmd, char **argv)
+{
+ uint32 antindex;
+ int buflen, err;
+ char *param;
+ int16 antrssi;
+
+ if (!*++argv) {
+ printf(" Usage: %s antenna_index[0-3]\n", cmd->name);
+ return BCME_USAGE_ERROR;
+ }
+
+ antindex = htod32(atoi(*argv));
+
+ strcpy(buf, "nphy_rssiant");
+ buflen = strlen(buf) + 1;
+ param = (char *)(buf + buflen);
+ memcpy(param, (char*)&antindex, sizeof(antindex));
+
+ if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return err;
+
+ antindex = dtoh32(antindex);
+ antrssi = dtoh16(*(int16 *)buf);
+ printf("\nnphy_rssiant ant%d = %d\n", antindex, antrssi);
+
+ return (0);
+}
+
+static int
+wl_pkteng_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_pkteng_stats_t *stats;
+ void *ptr = NULL;
+ int err, argc, opt_err;
+ uint16 *pktstats;
+ int i, j;
+ miniopt_t to;
+ uint8 gain_correct = 0;
+ const char* fn_name = "wl_pkteng_stats";
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+
+ if (argc != 0) {
+ miniopt_init(&to, fn_name, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 'g') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int"
+ " for gain-correction (0, 1)\n",
+ fn_name, to.valstr);
+
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val < 0) || (to.val > 1)) {
+ fprintf(stderr, "%s: invalid gain-correction select %d"
+ " (0,1)\n", fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ gain_correct = to.val & 0xf;
+ }
+ }
+ }
+
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, &gain_correct, 1, &ptr)) < 0)
+ return err;
+
+ stats = ptr;
+ printf("Lost frame count %d\n", dtoh32(stats->lostfrmcnt));
+ printf("RSSI %d\n", dtoh32(stats->rssi));
+ printf("Signal to noise ratio %d\n", dtoh32(stats->snr));
+ printf("rx1mbps %d rx2mbps %d rx5mbps5 %d\n"
+ "rx6mbps %d rx9mbps %d, rx11mbps %d\n"
+ "rx12mbps %d rx18mbps %d rx24mbps %d\n"
+ "rx36mbps %d rx48mbps %d rx54mbps %d\n",
+ stats->rxpktcnt[3], stats->rxpktcnt[1], stats->rxpktcnt[2],
+ stats->rxpktcnt[7], stats->rxpktcnt[11], stats->rxpktcnt[0],
+ stats->rxpktcnt[6], stats->rxpktcnt[10], stats->rxpktcnt[5],
+ stats->rxpktcnt[9], stats->rxpktcnt[4], stats->rxpktcnt[8]);
+ pktstats = &stats->rxpktcnt[NUM_80211b_RATES+NUM_80211ag_RATES];
+ for (i = 0; i < NUM_80211n_RATES/4; i++) {
+ for (j = 0; j < 4; j++) {
+ printf("rxmcs%d %d ", j+4*i, pktstats[j+4*i]);
+ }
+ printf("\n");
+ }
+ printf("rxmcsother %d\n", stats->rxpktcnt[NUM_80211_RATES]);
+ return 0;
+
+exit:
+ return err;
+}
+
+static int
+wl_pkteng_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int status = 0;
+
+ BCM_REFERENCE(argv);
+ if ((err = wlu_iovar_get(wl, cmd->name, &status, sizeof(status))) < 0) {
+ return err;
+ }
+
+ printf("pkteng_status : %d \n", status);
+ return 0;
+}
+
+#define LPPHY_PAPD_EPS_TBL_SIZE 64
+static int
+wl_phy_papdepstbl(void *wl, cmd_t *cmd, char **argv)
+{
+ int32 eps_real, eps_imag;
+ int i;
+ uint32 eps_tbl[LPPHY_PAPD_EPS_TBL_SIZE];
+ int err;
+
+ UNUSED_PARAMETER(argv);
+
+ if ((err = wlu_iovar_get(wl, cmd->name, &eps_tbl, sizeof(eps_tbl))) < 0)
+ return err;
+
+ for (i = 0; i < LPPHY_PAPD_EPS_TBL_SIZE; i++) {
+ if ((eps_real = (int32)(eps_tbl[i] >> 12)) > 0x7ff)
+ eps_real -= 0x1000; /* Sign extend */
+ if ((eps_imag = (int32)(eps_tbl[i] & 0xfff)) > 0x7ff)
+ eps_imag -= 0x1000; /* Sign extend */
+ printf("%d %d\n", eps_real, eps_imag);
+ }
+
+ return 0;
+}
+
+static int
+wl_phy_txiqcc(void *wl, cmd_t *cmd, char **argv)
+{
+ int i;
+ int err;
+ int32 iqccValues[4];
+ int32 value;
+ char *endptr;
+ int32 a, b, a1, b1;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ if ((err = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0)
+ return err;
+
+ phytype = dtoh32(revinfo.phytype);
+
+ if (phytype != WLC_PHY_TYPE_N) {
+ if (!*++argv) {
+ if ((err = wlu_iovar_get(wl, cmd->name, iqccValues, 2*sizeof(int32))) < 0)
+ return err;
+ a = (int16)iqccValues[0];
+ b = (int16)iqccValues[1];
+ /* sign extend a, b from 10 bit signed value to 32 bit signed value */
+ a = ((a << 22) >> 22);
+ b = ((b << 22) >> 22);
+ printf("%d %d\n", a, b);
+ }
+ else
+ {
+ for (i = 0; i < 2; i++) {
+ value = strtol(*argv++, &endptr, 0);
+ if (value > 511 || value < -512) {
+ return BCME_BADARG;
+ }
+ iqccValues[i] = value;
+ }
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, iqccValues, 2*sizeof(int32))) < 0)
+ return err;
+ }
+ } else {
+ if (!*++argv) {
+ if ((err = wlu_iovar_get(wl, cmd->name, iqccValues, 4*sizeof(int32))) < 0)
+ return err;
+ a = (int16)iqccValues[0];
+ b = (int16)iqccValues[1];
+ a1 = (int16)iqccValues[2];
+ b1 = (int16)iqccValues[3];
+ /* sign extend a, b from 10 bit signed value to 32 bit signed value */
+ a = ((a << 22) >> 22);
+ b = ((b << 22) >> 22);
+ a1 = ((a1 << 22) >> 22);
+ b1 = ((b1 << 22) >> 22);
+ printf("%d %d %d %d\n", a, b, a1, b1);
+ }
+ else
+ {
+ for (i = 0; i < 4; i++) {
+ value = strtol(*argv++, &endptr, 0);
+ if (value > 511 || value < -512) {
+ return BCME_BADARG;
+ }
+ iqccValues[i] = value;
+ }
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, iqccValues, 4*sizeof(int32))) < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int
+wl_phy_txlocc(void *wl, cmd_t *cmd, char **argv)
+{
+ int i;
+ int err;
+ int8 loccValues[12];
+ int32 value;
+ char *endptr;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ if ((err = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0)
+ return err;
+
+ phytype = dtoh32(revinfo.phytype);
+
+ if (phytype != WLC_PHY_TYPE_N) {
+ if (!*++argv) {
+ if ((err = wlu_iovar_get(wl, cmd->name, loccValues,
+ sizeof(loccValues))) < 0)
+ return err;
+
+ /* sign extend the loccValues */
+ loccValues[2] = (loccValues[2] << 3) >> 3;
+ loccValues[3] = (loccValues[3] << 3) >> 3;
+ loccValues[4] = (loccValues[4] << 3) >> 3;
+ loccValues[5] = (loccValues[5] << 3) >> 3;
+
+ printf("%d %d %d %d %d %d\n", loccValues[0],
+ loccValues[1], loccValues[2], loccValues[3],
+ loccValues[4], loccValues[5]);
+ }
+ else
+ {
+ for (i = 0; i < 6; i++) {
+ value = strtol(*argv++, &endptr, 0);
+ if ((i >= 2) && (value > 15 || value < -15)) {
+ return BCME_BADARG;
+ }
+ loccValues[i] = (int8)value;
+ }
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, loccValues, 6*sizeof(int8))) < 0)
+ return err;
+ }
+ } else {
+ if (!*++argv) {
+ if ((err = wlu_iovar_get(wl, cmd->name, loccValues,
+ sizeof(loccValues))) < 0)
+ return err;
+
+ /* sign extend the loccValues */
+ loccValues[2] = (loccValues[2] << 3) >> 3;
+ loccValues[3] = (loccValues[3] << 3) >> 3;
+ loccValues[4] = (loccValues[4] << 3) >> 3;
+ loccValues[5] = (loccValues[5] << 3) >> 3;
+ loccValues[8] = (loccValues[8] << 3) >> 3;
+ loccValues[9] = (loccValues[9] << 3) >> 3;
+ loccValues[10] = (loccValues[10] << 3) >> 3;
+ loccValues[11] = (loccValues[11] << 3) >> 3;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d\n", loccValues[0],
+ loccValues[1], loccValues[2], loccValues[3], loccValues[4],
+ loccValues[5], loccValues[6], loccValues[7], loccValues[8],
+ loccValues[9], loccValues[10], loccValues[11]);
+ }
+ else
+ {
+ for (i = 0; i < 12; i++) {
+ value = strtol(*argv++, &endptr, 0);
+ if (((i < 2) && (value > 63 || value < -64)) ||
+ ((i >= 2) && (value > 15 || value < -15))) {
+ return BCME_BADARG;
+ }
+ loccValues[i] = (int8)value;
+ }
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, loccValues, 12*sizeof(int8))) < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int
+wl_rssi_cal_freq_grp_2g(void *wl, cmd_t *cmd, char **argv)
+{
+ int i;
+ int err = -1;
+ uint8 nvramValues[14];
+ char *endptr;
+ uint8 N = 0;
+
+ if (!*++argv) {
+ /* Reading the NVRAM variable */
+ if ((err = wlu_iovar_get(wl, cmd->name, nvramValues, sizeof(nvramValues))) < 0)
+ return err;
+
+ N = 14; /* 14 corresponds to number of channels in 2g */
+
+ for (i = 0; i < N-2; i++) {
+ printf("0x%x%x,", nvramValues[i], nvramValues[i+1]);
+ i++;
+ }
+ printf("0x%x%x\n", nvramValues[i], nvramValues[i+1]);
+ } else {
+ /* Writing to NVRAM variable */
+
+ char *splt;
+ int8 tmp;
+ splt = strtok(*argv, ",");
+
+ /* N = 14 corresponds to number of channels in 2g */
+ /* N = N /2 to package 2 channel's nibbles into 1 byte */
+ N = 7;
+
+ i = 0;
+ while (splt != NULL) {
+ /* Splitting the input based on charecter ','
+ * Further each byte is divided into 2 nibbles
+ * and saved into 2 elements of array.
+ */
+ tmp = strtol(splt, &endptr, 0);
+ nvramValues[i] = (tmp >> 4) & 0xf;
+ i++;
+ nvramValues[i] = tmp & 0xf;
+ splt = strtok(NULL, ",");
+ i++;
+ }
+ if (i != 14) {
+ printf("Insufficient arguments \n");
+ return BCME_BADARG;
+ }
+ if ((err = wlu_var_setbuf(wl, cmd->name, nvramValues, N*2*sizeof(int8))) < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+wl_phy_rssi_gain_delta_2g_sub(void *wl, cmd_t *cmd, char **argv)
+{
+ int i;
+ int err = -1;
+ int8 deltaValues[28];
+ int32 value;
+ char *endptr;
+ int ret = -1;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+ uint8 N = 0;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (ret) {
+ return ret;
+ }
+ phytype = dtoh32(revinfo.phytype);
+
+ if (phytype != WLC_PHY_TYPE_AC) {
+ return err;
+ }
+
+ if (!*++argv) {
+ if ((err = wlu_iovar_get(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0)
+ return err;
+ N = 27; /* 9 entries per core, 43602WLCSP - 27 MAX entried;
+ * 4350 - 18 MAX entries; 4345 9 MAX entries
+ */
+ for (i = 0; i < N; i++) {
+ if (i%9 == 0 && i > 0) {
+ printf("\n");
+ if (deltaValues[i] == -1) break;
+ }
+
+ printf("%d ", deltaValues[i]);
+ }
+ if (i == N)
+ printf("\n");
+ } else {
+ int argc = 0;
+ int index = 0;
+ while (argv[argc])
+ argc++;
+
+ /* ACPHY : 8/9 entries for a core; core 0 delta's can be
+ * given with or with out core_num as first element
+ */
+ N = argc;
+
+ if (!(N == 9 || N == 8 || N == 16 || N == 24)) {
+ printf("Incorrect number of arguments.\n");
+ return 0;
+ }
+
+ for (i = 0; i < N; i++) {
+ value = strtol(*argv++, &endptr, 0);
+ if ((value > 63 || value < -64)) {
+ return BCME_BADARG;
+ }
+ if (argc == 9) {
+ /* If number of arguments is 9, then core
+ * number has been provided.
+ * And 8 elements related to 2
+ * (BWs - 20 n 40) and 4 gain settings
+ * (elna_on, elna_off, rout_1, rout_2) are
+ * provided. So, 2 * 4 = 8 + 1 core_num = 9
+ */
+ deltaValues[i] = (int8)value;
+ } else {
+ /* If the number of elements is not eq to 9,
+ * then, core number was not provided.
+ * So, if only 8 elements are provided, only
+ * core 0's info is given. So, for i = 0,
+ * deltaValues element is 0 (core_num). If 16
+ * elements are provided, then core 0 and 1's info is
+ * provided. So, i =0 element has core_num = 0,
+ * then, next 8 elements are core 0's
+ * deltas. For i = 8, core 1's core_num = 1
+ * is inserted into deltaValues array.
+ * Similarly for third core data.
+ */
+ if (i == 0) {
+ deltaValues[index] = 0;
+ index++;
+ } else if (i == 8) {
+ deltaValues[index] = 1;
+ index++;
+ } else if (i == 16) {
+ deltaValues[index] = 2;
+ index++;
+ }
+ deltaValues[index] = (int8)value;
+ index++;
+ }
+ }
+ /* If argc == 8, then only 1 core's info was given,
+ * so, setbuf() is called once.
+ * If argc == 16 then core 0 and 1's info was given.
+ * So, setbuf() is called twice.
+ * If argc == 24 then core 0, 1 and 2's info was given.
+ * So, setbuf() is called thrice.
+ */
+ if ((err = wlu_var_setbuf(wl, cmd->name,
+ deltaValues, 9*sizeof(int8))) < 0)
+ return err;
+ if (argc >= 16) {
+ if ((err = wlu_var_setbuf(wl, cmd->name,
+ deltaValues + 9, 9*sizeof(int8))) < 0)
+ return err;
+ }
+ if (argc == 24) {
+ if ((err = wlu_var_setbuf(wl, cmd->name,
+ deltaValues + 18, 9*sizeof(int8))) < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int
+wl_phy_rssi_gain_delta_2g(void *wl, cmd_t *cmd, char **argv)
+{
+ int i;
+ int err = -1;
+ int8 deltaValues[18];
+ int32 value;
+ char *endptr;
+ int ret = -1;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+ uint8 N = 0;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (ret) {
+ return ret;
+ }
+ phytype = dtoh32(revinfo.phytype);
+
+ if (phytype != WLC_PHY_TYPE_AC) {
+ return err;
+ }
+
+ if (!*++argv) {
+ if ((err = wlu_iovar_get(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0)
+ return err;
+ if (phytype == WLC_PHY_TYPE_AC)
+ N = 15; /* ACPHY: 3 cores max x 5 entries */
+ for (i = 0; i < N; i++) {
+ if ((phytype == WLC_PHY_TYPE_AC) && (i%5 == 0)) {
+ if (i > 0) printf("\n");
+ if (deltaValues[i] == -1) break;
+ }
+ printf("%d ", deltaValues[i]);
+ }
+ if (i == N)
+ printf("\n");
+ } else {
+ int argc = 0;
+ int index = 0;
+ while (argv[argc])
+ argc++;
+ if (phytype == WLC_PHY_TYPE_AC) {
+ /* N = 5; ACPHY : 5 entries for a core */
+ N = argc;
+ }
+
+ for (i = 0; i < N; i++) {
+ value = strtol(*argv++, &endptr, 0);
+ if ((value > 63 || value < -64)) {
+ return BCME_BADARG;
+ }
+ if (argc == 5) {
+ /* If number of arguments is 5, then core number has been provided.
+ * And 8 elements related to 2 (BWs - 20 n 40) and 2 gain settings
+ * (elna_on, elna_off) are provided. So, 2 * 2 = 4 + 1 core_num = 5
+ */
+ deltaValues[i] = (int8)value;
+ } else {
+ /* If the number of elements is not eq to 5,
+ * then, core number was not provided.
+ * So, if only 4 elements are provided, only
+ * core 0's info is given. So, for i = 0,
+ * deltaValues element is 0 (core_num). If 8
+ * elements are provided, then core 0 and 1's info is
+ * provided. So, i =0 element has core_num = 0,
+ * then, next 4 elements are core 0's
+ * deltas. For i = 4, core 1's core_num = 1
+ * is inserted into deltaValues array.
+ * Similarly for third core data.
+ */
+ if (i == 0) {
+ deltaValues[index] = 0;
+ index++;
+ } else if (i == 4) {
+ deltaValues[index] = 1;
+ index++;
+ } else if (i == 8) {
+ deltaValues[index] = 2;
+ index++;
+ }
+ deltaValues[index] = (int8)value;
+ index++;
+ }
+
+ }
+ /* If argc == 4, then only 1 core's info was given,
+ * so, setbuf() is called once.
+ * If argc == 8 then core 0 and 1's info was given.
+ * So, setbuf() is called twice.
+ * If argc == 12 then core 0, 1 and 2's info was given.
+ * So, setbuf() is called thrice.
+ */
+ if ((err = wlu_var_setbuf(wl, cmd->name,
+ deltaValues, 5*sizeof(int8))) < 0)
+ return err;
+ if (argc >= 8) {
+ if ((err = wlu_var_setbuf(wl, cmd->name,
+ deltaValues + 5, 5*sizeof(int8))) < 0)
+ return err;
+ }
+ if (argc == 12) {
+ if ((err = wlu_var_setbuf(wl, cmd->name,
+ deltaValues + 10, 5*sizeof(int8))) < 0)
+ return err;
+ }
+
+ }
+
+ return 0;
+}
+
+static int
+wl_phy_rssi_gain_delta_5g(void *wl, cmd_t *cmd, char **argv)
+{
+ int i;
+ int err = -1;
+ int8 deltaValues[40];
+ int32 value = 0;
+ char *endptr;
+ int ret = -1;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+ uint8 N = 0, n_per_core, n_per_core_p1;
+
+ char *varname = "rssi_cal_rev";
+
+ err = wlu_iovar_getint(wl, varname, &value);
+ if ((err < 0) || ((err == 0) && (value == 0))) {
+ /* This means, 'rssi_cal_rev' is not supported or Variable is 0 */
+ /* Calls old function */
+ n_per_core = 6;
+ } else {
+ n_per_core = 12;
+ }
+
+ n_per_core_p1 = n_per_core + 1;
+ memset(&revinfo, 0, sizeof(revinfo));
+ ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (ret) {
+ return ret;
+ }
+ phytype = dtoh32(revinfo.phytype);
+
+ if (phytype != WLC_PHY_TYPE_AC) {
+ return err;
+ }
+
+ if (!*++argv) {
+ if ((err = wlu_iovar_get(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0)
+ return err;
+ if (phytype == WLC_PHY_TYPE_AC)
+ N = n_per_core_p1 * 3; /* ACPHY: 3 cores max x 7 entries */
+ for (i = 0; i < N; i++) {
+ if ((phytype == WLC_PHY_TYPE_AC) && (i%n_per_core_p1 == 0)) {
+ if (i > 0) printf("\n");
+ if (deltaValues[i] == -1) break;
+ }
+ printf("%d ", deltaValues[i]);
+ }
+ if (i == N)
+ printf("\n");
+ } else {
+ int argc = 0;
+ int index = 0;
+ while (argv[argc])
+ argc++;
+
+ if (phytype == WLC_PHY_TYPE_AC) {
+ /* N = 7; ACPHY : 7 entries for a core if n_per_core == 6 */
+ /* N = 13; ACPHY : 12 entries for a core if n_per_core == 12 */
+ N = argc;
+ }
+
+ if ((n_per_core == 12) && !(N == 13 || N == 12 || N == 24 || N == 36)) {
+ printf("Incorrect number of arguments\n");
+ return 0;
+ }
+
+ for (i = 0; i < N; i++) {
+ value = strtol(*argv++, &endptr, 0);
+ if ((value > 63 || value < -64)) {
+ return BCME_BADARG;
+ }
+ if (argc == n_per_core_p1) {
+ /* For Old implementation, ie, no Routs, n_per_core_p1 == 5
+ * for New implementation, ie, no Routs, n_per_core_p1 == 9
+ * If number of arguments is "n_per_core_p1",
+ * then core number has been provided.
+ */
+ deltaValues[i] = (int8)value;
+ } else {
+ /* If the number of elements is not eq to
+ *"n_per_core", then, core number was not provided.
+ * So, if only "n_per_core" elements are provided,
+ * only core 0's info is given. So, for i = 0,
+ * deltaValues element is 0 (core_num). If "n_per_core * 2"
+ * elements are provided, then core 0 and 1's info is
+ * provided. So, i =0 element has core_num = 0, then,
+ * next "n_per_core" elements are core 0's
+ * deltas. For i = "n_per_core", core 1's
+ * core_num = 1 is inserted into deltaValues array.
+ * Similarly for third core data.
+ */
+
+ if (i == (n_per_core * 0)) {
+ deltaValues[index] = 0;
+ index++;
+ }
+ if (i == (n_per_core * 1)) {
+ deltaValues[index] = 1;
+ index++;
+ }
+ if (i == (n_per_core * 2)) {
+ deltaValues[index] = 2;
+ index++;
+ }
+
+ deltaValues[index] = (int8)value;
+ index++;
+ }
+
+ }
+ /* If argc == "n_per_core", then only 1 core's infoxs
+ * was given, so, setbuf() is called once.
+ * If argc == "n_per_core * 2" then core 0 and 1's info
+ * was given. So, setbuf() is called twice.
+ * If argc == "n_per_core * 3" then core 0, 1 and 2's
+ * info was given. So, setbuf() is called thrice.
+ */
+ if ((err = wlu_var_setbuf(wl, cmd->name, deltaValues,
+ n_per_core_p1*sizeof(int8))) < 0)
+ return err;
+ if (argc >= (n_per_core * 2)) {
+ if ((err = wlu_var_setbuf(wl, cmd->name, deltaValues +
+ (n_per_core_p1 * 1), n_per_core_p1*sizeof(int8))) < 0)
+ return err;
+ }
+ if (argc == (n_per_core * 3)) {
+ if ((err = wlu_var_setbuf(wl, cmd->name, deltaValues +
+ (n_per_core_p1 * 2), n_per_core_p1*sizeof(int8))) < 0)
+ return err;
+ }
+
+ }
+ return 0;
+}
+
+static int
+wl_phy_rxgainerr_2g(void *wl, cmd_t *cmd, char **argv)
+{
+ int i;
+ int err = -1;
+ int8 deltaValues[18];
+ int32 value;
+ char *endptr;
+ int ret = -1;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+ uint8 N = 0;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (ret) {
+ return ret;
+ }
+ phytype = dtoh32(revinfo.phytype);
+
+ if (phytype != WLC_PHY_TYPE_AC) {
+ return err;
+ }
+
+ if (!*++argv) {
+ if ((err = wlu_iovar_get(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0)
+ return err;
+ if (phytype == WLC_PHY_TYPE_AC) {
+ if (BCM4365_CHIP(dtoh32(revinfo.chipnum)))
+ N = 4;
+ else
+ N = 2;
+ }
+ for (i = 0; i < N; i++) {
+ printf("%d ", deltaValues[i]);
+ }
+ if (i == N)
+ printf("\n");
+ } else {
+ int argc = 0;
+ while (argv[argc])
+ argc++;
+
+ if (BCM4365_CHIP(dtoh32(revinfo.chipnum))) {
+ if (argc != 4) {
+ printf("IOVAR works only for 4 cores scenario. \n");
+ return err;
+ }
+ } else {
+ if (argc != 2) {
+ printf("IOVAR works only for 2 cores scenario. \n");
+ return err;
+ }
+ }
+
+ if (phytype == WLC_PHY_TYPE_AC) {
+ if (BCM4365_CHIP(dtoh32(revinfo.chipnum)))
+ N = 4;
+ else
+ N = 2;
+ }
+ for (i = 0; i < N; i++) {
+ value = strtol(*argv++, &endptr, 0);
+ if ((value > 63 || value < -64)) {
+ return BCME_BADARG;
+ }
+ deltaValues[i] = (int8)value;
+ }
+ if ((err = wlu_var_setbuf(wl, cmd->name, deltaValues, N*sizeof(int8))) < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+wl_phy_rxgainerr_5g(void *wl, cmd_t *cmd, char **argv)
+{
+ int i;
+ int err = -1;
+ int8 deltaValues[28];
+ int32 value;
+ char *endptr;
+ int ret = -1;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+ uint8 N = 0;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (ret) {
+ return ret;
+ }
+ phytype = dtoh32(revinfo.phytype);
+
+ if (phytype != WLC_PHY_TYPE_AC) {
+ return err;
+ }
+
+ if (!*++argv) {
+ if ((err = wlu_iovar_get(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0)
+ return err;
+ if (phytype == WLC_PHY_TYPE_AC) {
+ if (BCM4365_CHIP(dtoh32(revinfo.chipnum)))
+ N = 4;
+ else
+ N = 2;
+ }
+
+ for (i = 0; i < N; i++) {
+ printf("%d ", deltaValues[i]);
+ }
+ if (i == N)
+ printf("\n");
+ } else {
+ int argc = 0;
+ while (argv[argc])
+ argc++;
+ if (BCM4365_CHIP(dtoh32(revinfo.chipnum))) {
+ if (argc != 4) {
+ printf("IOVAR works only for 4 cores scenario. \n");
+ return err;
+ }
+ } else {
+ if (argc != 2) {
+ printf("IOVAR works only for 2 cores scenario. \n");
+ return err;
+ }
+ }
+ if (phytype == WLC_PHY_TYPE_AC) {
+ if (BCM4365_CHIP(dtoh32(revinfo.chipnum)))
+ N = 4;
+ else
+ N = 2;
+ }
+
+ for (i = 0; i < N; i++) {
+ value = strtol(*argv++, &endptr, 0);
+ if ((value > 63 || value < -64)) {
+ return BCME_BADARG;
+ }
+ deltaValues[i] = (int8)value;
+ }
+ if ((err = wlu_var_setbuf(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int
+wl_phytable(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ uint32 tableInfo[5];
+ char *endptr;
+ void *ptr = NULL;
+ int32 tableId, tableOffset, tableWidth;
+ uint64 tableElement;
+
+ if (*++argv != NULL)
+ tableId = strtol(*argv, &endptr, 0);
+ else
+ return BCME_USAGE_ERROR;
+
+ if (*++argv != NULL)
+ tableOffset = strtol(*argv, &endptr, 0);
+ else
+ return BCME_USAGE_ERROR;
+
+ if (*++argv != NULL)
+ tableWidth = strtol(*argv, &endptr, 0);
+ else
+ return BCME_USAGE_ERROR;
+
+ if ((tableId < 0) || (tableOffset < 0))
+ return BCME_BADARG;
+
+ if ((tableWidth != 8) && (tableWidth != 16) && (tableWidth != 32) &&
+ (tableWidth != 48) && (tableWidth != 64))
+ return BCME_BADARG;
+
+ if (!*++argv) { /* wl utility reads a PHY table element */
+ tableInfo[0] = tableId;
+ tableInfo[1] = tableOffset;
+ tableInfo[2] = tableWidth;
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, tableInfo, 4*sizeof(int32), &ptr)) < 0)
+ return err;
+
+ tableElement = ((uint64*)ptr)[0]; /* ptr is guaranteed to be 64 bits aligned */
+
+ /* Mask out the correct data */
+ if (tableWidth == 8)
+ tableElement &= 0xFF;
+ else if (tableWidth == 16)
+ tableElement &= 0xFFFF;
+ else if (tableWidth == 32)
+ tableElement &= 0xFFFFFFFF;
+ else if (tableWidth == 48)
+ tableElement &= 0xFFFFFFFFFFFFULL;
+
+ printf("0x%llx(%lld)\n", tableElement, tableElement);
+ } else { /* wl utility writes a PHY table element */
+ tableElement = bcm_strtoull(*argv++, &endptr, 0);
+
+ tableInfo[0] = tableId;
+ tableInfo[1] = tableOffset;
+ tableInfo[2] = tableWidth;
+ htol64_ua_store(tableElement, &tableInfo[3]);
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, tableInfo, 5 * sizeof(int32))) < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+wl_phy_force_crsmin(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1;
+ int8 th[4] = { 0 };
+ int32 value;
+ uint argc = 0;
+ char *endptr;
+ uint8 i = 0;
+ int ret = -1;
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+ if (ret) {
+ return ret;
+ }
+ phytype = dtoh32(revinfo.phytype);
+
+ if (phytype != WLC_PHY_TYPE_AC) {
+ return err;
+ }
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+ argc--;
+
+ if (argc == 0) {
+ /* No get for now */
+ return err;
+ } else {
+ if (argc > 3) {
+ printf("IOVAR works only for up to 3 cores. \n");
+ return err;
+ }
+ for (i = 0; i < argc; i++) {
+ value = strtol(argv[i + 1], &endptr, 0);
+ if ((i == 0) && (value < -1)) {
+ /* Offset values (2nd/3rd arguments) can be negative */
+ return BCME_BADARG;
+ }
+ th[i] = (int8) value;
+ }
+ if ((err = wlu_var_setbuf(wl, cmd->name, th, 4*sizeof(int8))) < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+wl_phy_txpwrindex(void *wl, cmd_t *cmd, char **argv)
+{
+ uint i;
+ int ret;
+ uint32 txpwridx[4] = { 0 };
+ int8 idx[4] = { 0 };
+ uint argc;
+ char *endptr;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+ argc--;
+
+ for (i = 0; i < 4; i++) {
+ if (argc > i) {
+ txpwridx[i] = strtol(argv[1 + i], &endptr, 0);
+ if (*endptr != '\0') {
+ printf("error\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ }
+
+ if (argc == 0) {
+ if ((ret = wlu_iovar_getint(wl, cmd->name, (int*)&txpwridx[0])) < 0) {
+ return (ret);
+ }
+ txpwridx[0] = dtoh32(txpwridx[0]);
+ idx[0] = (int8)(txpwridx[0] & 0xff);
+ idx[1] = (int8)((txpwridx[0] >> 8) & 0xff);
+ idx[2] = (int8)((txpwridx[0] >> 16) & 0xff);
+ idx[3] = (int8)((txpwridx[0] >> 24) & 0xff);
+ printf("txpwrindex for core{0...3}: %d %d %d %d\n", idx[0], idx[1],
+ idx[2], idx[3]);
+ } else {
+ wlc_rev_info_t revinfo;
+ uint32 phytype;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ if ((ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0)
+ return ret;
+
+ phytype = dtoh32(revinfo.phytype);
+
+ if (phytype == WLC_PHY_TYPE_HT) {
+ if (argc != 3) {
+ printf("HTPHY must specify 3 core txpwrindex\n");
+ return BCME_USAGE_ERROR;
+ }
+ } else if (phytype == WLC_PHY_TYPE_N) {
+ if (argc != 2) {
+ printf("NPHY must specify 2 core txpwrindex\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ ret = wlu_iovar_setbuf(wl, cmd->name, txpwridx, 4*sizeof(uint32),
+ buf, WLC_IOCTL_MAXLEN);
+ }
+
+ return ret;
+}
+
+static int
+wl_phy_force_vsdb_chans(void *wl, cmd_t *cmd, char **argv)
+{
+ uint16 *chans = NULL;
+ int ret = 0;
+ void *ptr;
+
+ UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd);
+
+
+ if (argv[1] == NULL) {
+ if ((ret = wlu_var_getbuf(wl, "force_vsdb_chans", NULL, 0, &ptr) < 0)) {
+ printf("wl_phy_maxpower: fail to get maxpower\n");
+ return ret;
+ }
+ chans = (uint16*)ptr;
+ printf("Chans : %x %x \n", chans[0], chans[1]);
+ } else if (argv[1] && argv[2]) {
+ /* Allocate memory */
+ chans = (uint16*)malloc(2 * sizeof(uint16));
+ if (chans == NULL) {
+ printf("unable to allocate Memory \n");
+ return BCME_NOMEM;
+ }
+ chans[0] = wf_chspec_aton(argv[1]);
+ chans[1] = wf_chspec_aton(argv[2]);
+ if (((chans[0] & 0xff) == 0) || ((chans[1] & 0xff) == 0)) {
+ chans[0] = 0;
+ chans[1] = 0;
+ }
+ ret = wlu_iovar_setbuf(wl, cmd->name, chans, 2 * sizeof(uint16),
+ buf, WLC_IOCTL_MAXLEN);
+ if (chans)
+ free(chans);
+ } else {
+ ret = BCME_USAGE_ERROR;
+ }
+
+ return ret;
+}
+
+static int
+wl_phy_pavars(void *wl, cmd_t *cmd, char **argv)
+{
+#if defined(DONGLEBUILD)
+ return 0;
+#else
+ const pavars_t *pav = pavars;
+ uint16 inpa[WL_PHY_PAVARS_LEN];
+ char *cpar = NULL, *p = NULL;
+ char *par;
+ char delimit[2] = " \0";
+ int err = 0;
+ unsigned int val, val2[SROM_PAVAR];
+ void *ptr = NULL;
+ int paparambwver = 0;
+ int sromrev = 0;
+
+ const char *iovar = "nvram_dump";
+ void *p1 = NULL;
+
+ if ((err = wlu_var_getbuf(wl, iovar, NULL, 0, &p1)) < 0) {
+ if ((err = wlu_get(wl, WLC_NVRAM_DUMP, &buf[0], WLC_IOCTL_MAXLEN)) < 0)
+ return err;
+ p1 = (void *)buf;
+ }
+ if ((p1 = strstr(p1, "paparambwver"))) {
+ char *q = NULL;
+ p1 = (void*)((char*)p1 + 13);
+ paparambwver = strtoul(p1, &q, 10);
+ }
+
+ err = wlu_iovar_getint(wl, "sromrev", &sromrev);
+ if (paparambwver == 1)
+ pav = pavars_bwver_1;
+ else if (paparambwver == 2)
+ pav = pavars_bwver_2;
+ else if (paparambwver == 3)
+ pav = pavars_bwver_3;
+ else {
+ if (sromrev > 12)
+ pav = pavars_SROM13;
+ if (sromrev == 12)
+ pav = pavars_SROM12;
+ if (sromrev < 12)
+ pav = pavars;
+ }
+ if (*++argv) { /* set */
+ while (pav->phy_type != PHY_TYPE_NULL) {
+ bool found = FALSE;
+ int i = 0;
+ inpa[i++] = pav->phy_type;
+ inpa[i++] = pav->bandrange;
+ inpa[i++] = pav->chain;
+
+ par = malloc(strlen(pav->vars)+1);
+ if (!par)
+ return BCME_NOMEM;
+
+ strcpy(par, pav->vars);
+
+ cpar = strtok (par, delimit); /* current param */
+
+ if ((pav->phy_type == PHY_TYPE_AC) ||
+ (pav->phy_type == PHY_TYPE_LCN20)) {
+ int pnum = 0, n;
+ if (sromrev >= 12) {
+ if ((pav->bandrange == WL_CHAN_FREQ_RANGE_2G) ||
+ (pav->bandrange == WL_CHAN_FREQ_RANGE_2G_40))
+ pnum = 4;
+ else if ((pav->bandrange ==
+ WL_CHAN_FREQ_RANGE_5G_5BAND) ||
+ (pav->bandrange ==
+ WL_CHAN_FREQ_RANGE_5G_5BAND_40) ||
+ (pav->bandrange ==
+ WL_CHAN_FREQ_RANGE_5G_5BAND_80))
+ pnum = 20;
+ }
+ if (sromrev < 12) {
+ if (pav->bandrange == WL_CHAN_FREQ_RANGE_2G)
+ pnum = 3;
+ else if (pav->bandrange == WL_CHAN_FREQ_RANGE_5G_4BAND)
+ pnum = 12;
+ }
+ if (cpar) {
+ /* Find the parameter in the input argument list */
+ if ((p = find_pattern2(argv, cpar, val2, pnum))) {
+ found = TRUE;
+ for (n = 0; n < pnum; n ++)
+ inpa[i + n] = (uint16)val2[n];
+ }
+ }
+ } else {
+ do {
+ val = 0;
+ if (cpar == NULL) {
+ inpa[i] = val;
+ break;
+ }
+ /* Find the parameter in the input argument list */
+ if ((p = find_pattern(argv, cpar, &val))) {
+ found = TRUE;
+ inpa[i] = (uint16)val;
+ } else
+ inpa[i] = 0;
+ i++;
+ } while ((cpar = strtok (NULL, delimit)) != NULL);
+ }
+ free(par);
+
+ if (found) {
+ if ((err = wlu_var_setbuf(wl, cmd->name, inpa,
+ WL_PHY_PAVARS_LEN * sizeof(uint16))) < 0) {
+ printf("wl_phy_pavars: fail to set\n");
+ return err;
+ }
+ }
+ pav++;
+ }
+ } else { /* get */
+ while (pav->phy_type != PHY_TYPE_NULL) {
+ int i = 0;
+ uint16 *outpa;
+
+ inpa[i++] = pav->phy_type;
+ inpa[i++] = pav->bandrange;
+ inpa[i++] = pav->chain;
+
+ par = malloc(strlen(pav->vars)+1);
+ if (!par)
+ return BCME_NOMEM;
+ strcpy(par, pav->vars);
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, inpa,
+ WL_PHY_PAVARS_LEN * sizeof(uint16), &ptr)) < 0) {
+ printf("phy %x band %x chain %d err %d\n", pav->phy_type,
+ pav->chain, pav->bandrange, err);
+ free(par);
+ break;
+ }
+
+ outpa = (uint16*)ptr;
+ if (outpa[0] == PHY_TYPE_NULL) {
+ pav++;
+ free(par);
+ continue;
+ }
+
+ cpar = strtok(par, delimit); /* current param */
+
+ if ((pav->phy_type == PHY_TYPE_AC) ||
+ (pav->phy_type == PHY_TYPE_LCN20)) {
+ int pnum = 0, n;
+ if (sromrev >= 12) {
+ if ((pav->bandrange == WL_CHAN_FREQ_RANGE_2G) ||
+ (pav->bandrange == WL_CHAN_FREQ_RANGE_2G_40))
+ pnum = 4;
+ else if ((pav->bandrange ==
+ WL_CHAN_FREQ_RANGE_5G_5BAND) ||
+ (pav->bandrange ==
+ WL_CHAN_FREQ_RANGE_5G_5BAND_40) ||
+ (pav->bandrange == WL_CHAN_FREQ_RANGE_5G_5BAND_80))
+ pnum = 20;
+ }
+ if (sromrev < 12) {
+ if (pav->bandrange == WL_CHAN_FREQ_RANGE_2G)
+ pnum = 3;
+ else if (pav->bandrange == WL_CHAN_FREQ_RANGE_5G_4BAND)
+ pnum = 12;
+ }
+ printf("%s=", cpar);
+ for (n = 0; n < pnum; n ++) {
+ if (n != 0)
+ printf(",");
+ printf("0x%x", outpa[i + n]);
+ }
+ printf("\n");
+ } else {
+ do {
+ printf("%s=0x%x\n", cpar, outpa[i++]);
+ } while ((cpar = strtok (NULL, delimit)) != NULL);
+ }
+ pav++;
+ free(par);
+ }
+ }
+ return err;
+#endif
+
+}
+
+static int
+wl_phy_povars(void *wl, cmd_t *cmd, char **argv)
+{
+#if defined(DONGLEBUILD)
+ return 0;
+#else
+ const povars_t *pov = povars;
+ wl_po_t inpo;
+ char *cpar = NULL, *p = NULL;
+ char *par; /* holds longest povars->vars */
+ char delimit[2] = " \0";
+ int err = 0;
+ uint val;
+ void *ptr = NULL;
+
+ if (*++argv) { /* set */
+ while (pov->phy_type != PHY_TYPE_NULL) {
+ bool found = FALSE;
+ int i = 0;
+
+ inpo.phy_type = pov->phy_type;
+ inpo.band = pov->bandrange;
+
+ par = malloc(strlen(pov->vars)+1);
+ if (!par)
+ return BCME_NOMEM;
+
+ strcpy(par, pov->vars);
+
+ /* Take care of cck and ofdm before walking through povars->vars */
+ if (pov->bandrange == WL_CHAN_FREQ_RANGE_2G) {
+ p = find_pattern(argv, "cck2gpo", &val);
+ if (p) found = TRUE;
+ inpo.cckpo = p ? (uint16)val : 0;
+
+ p = find_pattern(argv, "ofdm2gpo", &val);
+ } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GL) {
+ p = find_pattern(argv, "ofdm5glpo", &val);
+ } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GM) {
+ p = find_pattern(argv, "ofdm5gpo", &val);
+ } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GH) {
+ p = find_pattern(argv, "ofdm5ghpo", &val);
+ }
+ inpo.ofdmpo = p ? (uint32)val : 0;
+ if (p) found = TRUE;
+
+ cpar = strtok (par, delimit); /* current param */
+ do {
+ val = 0;
+ if (cpar == NULL) {
+ inpo.mcspo[i] = val;
+ break;
+ }
+
+ /* Find the parameter in the input argument list */
+ p = find_pattern(argv, cpar, &val);
+ if (p) found = TRUE;
+ inpo.mcspo[i] = p ? (uint16)val : 0;
+ i++;
+ } while ((cpar = strtok (NULL, delimit)) != NULL);
+
+ if (found) {
+ if ((err = wlu_var_setbuf(wl, cmd->name, &inpo,
+ sizeof(wl_po_t))) < 0) {
+ printf("wl_phy_povars: fail to set\n");
+ free(par);
+ return err;
+ }
+ }
+ pov++;
+ free(par);
+ }
+ } else { /* get */
+ while (pov->phy_type != PHY_TYPE_NULL) {
+ int i = 0;
+ wl_po_t *outpo;
+
+ inpo.phy_type = pov->phy_type;
+ inpo.band = pov->bandrange;
+
+ par = malloc(strlen(pov->vars)+1);
+ if (!par)
+ return BCME_NOMEM;
+
+ strcpy(par, pov->vars);
+
+ if ((err = wlu_var_getbuf(wl, cmd->name, &inpo, sizeof(povars_t),
+ &ptr)) < 0) {
+ printf("phy %x band %x err %d\n", pov->phy_type,
+ pov->bandrange, err);
+ free(par);
+ break;
+ }
+
+ outpo = (wl_po_t*)ptr;
+ if (outpo->phy_type == PHY_TYPE_NULL) {
+ pov++;
+ free(par);
+ continue;
+ }
+
+ /* Take care of cck and ofdm before walking through povars->vars */
+ if (outpo->band == WL_CHAN_FREQ_RANGE_2G) {
+ printf("cck2gpo=0x%x\n", outpo->cckpo);
+ printf("ofdm2gpo=0x%x\n", outpo->ofdmpo);
+ } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GL) {
+ printf("ofdm5glpo=0x%x\n", outpo->ofdmpo);
+ } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GM) {
+ printf("ofdm5gpo=0x%x\n", outpo->ofdmpo);
+ } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GH) {
+ printf("ofdm5ghpo=0x%x\n", outpo->ofdmpo);
+ }
+
+ cpar = strtok(par, delimit); /* current param */
+ do {
+ printf("%s=0x%x\n", cpar, outpo->mcspo[i++]);
+ } while ((cpar = strtok (NULL, delimit)));
+
+ pov++;
+ free(par);
+ }
+ }
+
+ return err;
+#endif
+}
+
+static int
+wl_phy_rpcalvars(void *wl, cmd_t *cmd, char **argv)
+{
+#if defined(DONGLEBUILD)
+ return 0;
+#else
+ int err = 0, k;
+ unsigned int val;
+ wl_rpcal_t rpcal[2*WL_NUM_RPCALVARS], *rpcal_out;
+ void *ptr = NULL;
+
+ if (*++argv) { /* set */
+ bool found = FALSE;
+
+ /* initialization */
+ memset(&(rpcal[0]), 0, sizeof(wl_rpcal_t)*2*WL_NUM_RPCALVARS);
+
+ if (find_pattern(argv, "rpcal2g", &val)) {
+ found = TRUE;
+ rpcal[WL_CHAN_FREQ_RANGE_2G].value = (uint16) val;
+ rpcal[WL_CHAN_FREQ_RANGE_2G].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal5gb0", &val)) {
+ found = TRUE;
+ rpcal[WL_CHAN_FREQ_RANGE_5G_BAND0].value = (uint16) val;
+ rpcal[WL_CHAN_FREQ_RANGE_5G_BAND0].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal5gb1", &val)) {
+ found = TRUE;
+ rpcal[WL_CHAN_FREQ_RANGE_5G_BAND1].value = (uint16) val;
+ rpcal[WL_CHAN_FREQ_RANGE_5G_BAND1].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal5gb2", &val)) {
+ found = TRUE;
+ rpcal[WL_CHAN_FREQ_RANGE_5G_BAND2].value = (uint16) val;
+ rpcal[WL_CHAN_FREQ_RANGE_5G_BAND2].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal5gb3", &val)) {
+ found = TRUE;
+ rpcal[WL_CHAN_FREQ_RANGE_5G_BAND3].value = (uint16) val;
+ rpcal[WL_CHAN_FREQ_RANGE_5G_BAND3].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal2gcore3", &val)) {
+ found = TRUE;
+ rpcal[WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_2G].value =
+ (uint16) (val & 0xff);
+ rpcal[WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_2G].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal5gb0core3", &val)) {
+ found = TRUE;
+ rpcal[WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND0].value =
+ (uint16) (val & 0xff);
+ rpcal[WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND0].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal5gb1core3", &val)) {
+ found = TRUE;
+ rpcal[WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND1].value =
+ (uint16) (val & 0xff);
+ rpcal[WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND1].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal5gb2core3", &val)) {
+ found = TRUE;
+ rpcal[WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND2].value =
+ (uint16) (val & 0xff);
+ rpcal[WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND2].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal5gb3core3", &val)) {
+ found = TRUE;
+ rpcal[WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND3].value =
+ (uint16) (val & 0xff);
+ rpcal[WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND3].update = 1;
+ }
+
+ if (found) {
+ err = wlu_var_setbuf(wl, cmd->name, &(rpcal[0]),
+ sizeof(wl_rpcal_t)*2*WL_NUM_RPCALVARS);
+ if (err < 0) {
+ printf("wl_phy_rpcalvars: fail to set\n");
+ return err;
+ }
+ } else {
+ printf("wl_phy_rpcalvars: fail to found matching rpcalvar name\n");
+ return err;
+ }
+
+ } else { /* get */
+
+ err = wlu_var_getbuf(wl, cmd->name, &(rpcal[0]),
+ sizeof(wl_rpcal_t)*2*WL_NUM_RPCALVARS, &ptr);
+
+ if (err < 0) {
+ printf("wl_phy_rpcalvars: fail to get\n");
+ return err;
+ } else {
+ rpcal_out = (wl_rpcal_t*) ptr;
+ }
+
+ for (k = 0; k < 2*WL_NUM_RPCALVARS; k++) {
+
+ switch (k) {
+ case WL_CHAN_FREQ_RANGE_2G:
+ printf("rpcal2g=0x%x ", rpcal_out[k].value);
+ break;
+ case WL_CHAN_FREQ_RANGE_5G_BAND0:
+ printf("rpcal5gb0=0x%x ", rpcal_out[k].value);
+ break;
+ case WL_CHAN_FREQ_RANGE_5G_BAND1:
+ printf("rpcal5gb1=0x%x ", rpcal_out[k].value);
+ break;
+ case WL_CHAN_FREQ_RANGE_5G_BAND2:
+ printf("rpcal5gb2=0x%x ", rpcal_out[k].value);
+ break;
+ case WL_CHAN_FREQ_RANGE_5G_BAND3:
+ printf("rpcal5gb3=0x%x\n", rpcal_out[k].value);
+ break;
+ case WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_2G:
+ printf("rpcal2gcore3=0x%x ", rpcal_out[k].value);
+ break;
+ case WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND0:
+ printf("rpcal5gb0core3=0x%x ", rpcal_out[k].value);
+ break;
+ case WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND1:
+ printf("rpcal5gb1core3=0x%x ", rpcal_out[k].value);
+ break;
+ case WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND2:
+ printf("rpcal5gb2core3=0x%x ", rpcal_out[k].value);
+ break;
+ case WL_NUM_RPCALVARS+WL_CHAN_FREQ_RANGE_5G_BAND3:
+ printf("rpcal5gb3core3=0x%x\n", rpcal_out[k].value);
+ break;
+ }
+ }
+ }
+
+ return 0;
+#endif
+}
+
+static int
+wl_phy_rpcalphasevars(void *wl, cmd_t *cmd, char **argv)
+{
+#if defined(DONGLEBUILD)
+ return 0;
+#else
+ int err = 0, k;
+ unsigned int val;
+ wl_rpcal_phase_t rpcal_phase[WL_NUM_RPCALPHASEVARS], *rpcal_phase_out;
+ void *ptr = NULL;
+
+ if (*++argv) { /* set */
+ bool found = FALSE;
+
+ /* initialization */
+ memset(&(rpcal_phase[0]), 0, sizeof(wl_rpcal_phase_t)*WL_NUM_RPCALPHASEVARS);
+
+ if (find_pattern(argv, "rpcal_phase2g", &val)) {
+ found = TRUE;
+ rpcal_phase[WL_CHAN_FREQ_RANGE_2G].value = (uint16) val;
+ rpcal_phase[WL_CHAN_FREQ_RANGE_2G].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal_phase5gb0", &val)) {
+ found = TRUE;
+ rpcal_phase[WL_CHAN_FREQ_RANGE_5G_BAND0].value = (uint16) val;
+ rpcal_phase[WL_CHAN_FREQ_RANGE_5G_BAND0].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal_phase5gb1", &val)) {
+ found = TRUE;
+ rpcal_phase[WL_CHAN_FREQ_RANGE_5G_BAND1].value = (uint16) val;
+ rpcal_phase[WL_CHAN_FREQ_RANGE_5G_BAND1].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal_phase5gb2", &val)) {
+ found = TRUE;
+ rpcal_phase[WL_CHAN_FREQ_RANGE_5G_BAND2].value = (uint16) val;
+ rpcal_phase[WL_CHAN_FREQ_RANGE_5G_BAND2].update = 1;
+ }
+
+ if (find_pattern(argv, "rpcal_phase5gb3", &val)) {
+ found = TRUE;
+ rpcal_phase[WL_CHAN_FREQ_RANGE_5G_BAND3].value = (uint16) val;
+ rpcal_phase[WL_CHAN_FREQ_RANGE_5G_BAND3].update = 1;
+ }
+
+ if (found) {
+ err = wlu_var_setbuf(wl, cmd->name, &(rpcal_phase[0]),
+ sizeof(wl_rpcal_phase_t)*WL_NUM_RPCALPHASEVARS);
+ if (err < 0) {
+ printf("wl_phy_rpcalphasevars: fail to set\n");
+ return err;
+ }
+ } else {
+ printf("wl_phy_rpcalphasevars: fail to found matching rpcalphase name\n");
+ return err;
+ }
+
+ } else { /* get */
+
+ err = wlu_var_getbuf(wl, cmd->name, &(rpcal_phase[0]),
+ sizeof(wl_rpcal_phase_t)*WL_NUM_RPCALPHASEVARS, &ptr);
+
+ if (err < 0) {
+ printf("wl_phy_rpcalphasevars: fail to get\n");
+ return err;
+ } else {
+ rpcal_phase_out = (wl_rpcal_phase_t*) ptr;
+ }
+
+ for (k = 0; k < WL_NUM_RPCALPHASEVARS; k++) {
+
+ switch (k) {
+ case WL_CHAN_FREQ_RANGE_2G:
+ printf("rpcal_phase2g=0x%x ", rpcal_phase_out[k].value);
+ break;
+ case WL_CHAN_FREQ_RANGE_5G_BAND0:
+ printf("rpcal_phase5gb0=0x%x ", rpcal_phase_out[k].value);
+ break;
+ case WL_CHAN_FREQ_RANGE_5G_BAND1:
+ printf("rpcal_phase5gb1=0x%x ", rpcal_phase_out[k].value);
+ break;
+ case WL_CHAN_FREQ_RANGE_5G_BAND2:
+ printf("rpcal_phase5gb2=0x%x ", rpcal_phase_out[k].value);
+ break;
+ case WL_CHAN_FREQ_RANGE_5G_BAND3:
+ printf("rpcal_phase5gb3=0x%x\n", rpcal_phase_out[k].value);
+ break;
+ }
+ }
+ }
+
+ return 0;
+#endif
+}
+
+static int
+wl_phy_fem(void *wl, cmd_t *cmd, char **argv)
+{
+#if defined(DONGLEBUILD)
+ return 0;
+#else
+ srom_fem_t fem;
+ srom_fem_t *rfem;
+ void *ptr;
+ bool found = FALSE;
+ int err = 0;
+ uint val;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) { /* write fem */
+
+ /* fem2g */
+ memset(&fem, 0, sizeof(srom_fem_t));
+
+ if (find_pattern(argv, "tssipos2g", &val)) {
+ found = TRUE;
+ fem.tssipos = val;
+ }
+
+ if (find_pattern(argv, "extpagain2g", &val)) {
+ found = TRUE;
+ fem.extpagain = val;
+ }
+
+ if (find_pattern(argv, "pdetrange2g", &val)) {
+ found = TRUE;
+ fem.pdetrange = val;
+ }
+
+ if (find_pattern(argv, "triso2g", &val)) {
+ found = TRUE;
+ fem.triso = val;
+ }
+
+ if (find_pattern(argv, "antswctl2g", &val)) {
+ found = TRUE;
+ fem.antswctrllut = val;
+ }
+
+ if (found) {
+ if ((err = wlu_var_setbuf(wl, "fem2g", &fem, sizeof(srom_fem_t)) < 0))
+ printf("wl_phy_fem: fail to set fem2g\n");
+ else
+ printf("fem2g set\n");
+ }
+
+ found = FALSE;
+ /* fem5g */
+ memset(&fem, 0, sizeof(srom_fem_t));
+
+ if (find_pattern(argv, "tssipos5g", &val)) {
+ found = TRUE;
+ fem.tssipos = val;
+ }
+
+ if (find_pattern(argv, "extpagain5g", &val)) {
+ found = TRUE;
+ fem.extpagain = val;
+ }
+
+ if (find_pattern(argv, "pdetrange5g", &val)) {
+ found = TRUE;
+ fem.pdetrange = val;
+ }
+
+ if (find_pattern(argv, "triso5g", &val)) {
+ found = TRUE;
+ fem.triso = val;
+ }
+
+ if (find_pattern(argv, "antswctl5g", &val)) {
+ found = TRUE;
+ fem.antswctrllut = val;
+ }
+
+ if (found) {
+ if ((err = wlu_var_setbuf(wl, "fem5g", &fem, sizeof(srom_fem_t)) < 0))
+ printf("wl_phy_fem: fail to set fem5g\n");
+ else
+ printf("fem5g set\n");
+ }
+ } else {
+ if ((err = wlu_var_getbuf(wl, "fem2g", NULL, 0, (void**)&ptr) < 0)) {
+ printf("wl_phy_fem: fail to get fem2g\n");
+ } else {
+ rfem = (srom_fem_t*)ptr; /* skip the "fem2g" */
+ printf("tssipos2g=0x%x extpagain2g=0x%x pdetrange2g=0x%x"
+ " triso2g=0x%x antswctl2g=0x%x\n",
+ rfem->tssipos, rfem->extpagain, rfem->pdetrange,
+ rfem->triso, rfem->antswctrllut);
+ }
+
+ if ((err = wlu_var_getbuf(wl, "fem5g", NULL, 0, (void**)&ptr) < 0)) {
+ printf("wl_phy_fem: fail to get fem5g\n");
+ } else {
+ rfem = (srom_fem_t*)ptr; /* skip the "fem2g" */
+ printf("tssipos5g=0x%x extpagain5g=0x%x pdetrange5g=0x%x"
+ " triso5g=0x%x antswctl5g=0x%x\n",
+ rfem->tssipos, rfem->extpagain, rfem->pdetrange,
+ rfem->triso, rfem->antswctrllut);
+ }
+ }
+
+ return err;
+#endif
+}
+
+static int
+wl_phy_maxpower(void *wl, cmd_t *cmd, char **argv)
+{
+#if defined(DONGLEBUILD)
+ return 0;
+#else
+ int err = 0;
+ uint val;
+ uint8 maxp[8];
+ void *ptr;
+ uint8 *rmaxp;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) { /* write maxpower */
+
+ if (find_pattern(argv, "maxp2ga0", &val))
+ maxp[0] = val;
+ else
+ printf("Missing maxp2ga0\n");
+
+ if (find_pattern(argv, "maxp2ga1", &val))
+ maxp[1] = val;
+ else
+ printf("Missing maxp2ga1\n");
+
+ if (find_pattern(argv, "maxp5ga0", &val))
+ maxp[2] = val;
+ else
+ printf("Missing maxp5ga0\n");
+
+ if (find_pattern(argv, "maxp5ga1", &val))
+ maxp[3] = val;
+ else
+ printf("Missing maxp5ga1\n");
+
+ if (find_pattern(argv, "maxp5gla0", &val))
+ maxp[4] = val;
+ else
+ printf("Missing maxp5gla0\n");
+
+ if (find_pattern(argv, "maxp5gla1", &val))
+ maxp[5] = val;
+ else
+ printf("Missing maxp5gla1\n");
+
+ if (find_pattern(argv, "maxp5gha0", &val))
+ maxp[6] = val;
+ else
+ printf("Missing maxp5gha0\n");
+
+ if (find_pattern(argv, "maxp5gha1", &val))
+ maxp[7] = val;
+ else
+ printf("Missing maxp5gha1\n");
+
+ if ((err = wlu_var_setbuf(wl, "maxpower", &maxp, 8 * sizeof(uint8)) < 0)) {
+ printf("wl_phy_maxpower: fail to set\n");
+ }
+ } else {
+ if ((err = wlu_var_getbuf(wl, "maxpower", NULL, 0, &ptr) < 0)) {
+ printf("wl_phy_maxpower: fail to get maxpower\n");
+ return err;
+ }
+ rmaxp = (uint8*)ptr;
+ printf("maxp2ga0=%x\n", rmaxp[0]);
+ printf("maxp2ga1=%x\n", rmaxp[1]);
+ printf("maxp5ga0=%x\n", rmaxp[2]);
+ printf("maxp5ga1=%x\n", rmaxp[3]);
+ printf("maxp5gla0=%x\n", rmaxp[4]);
+ printf("maxp5gla1=%x\n", rmaxp[5]);
+ printf("maxp5gha0=%x\n", rmaxp[6]);
+ printf("maxp5gha1=%x\n", rmaxp[7]);
+ }
+
+ return err;
+#endif
+}
+
+static int
+wl_pkteng(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_pkteng_t pkteng;
+
+ memset(&pkteng, 0, sizeof(pkteng));
+ if (strcmp(cmd->name, "pkteng_stop") == 0) {
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ if (strcmp(*argv, "tx") == 0)
+ pkteng.flags = WL_PKTENG_PER_TX_STOP;
+ else if (strcmp(*argv, "rx") == 0)
+ pkteng.flags = WL_PKTENG_PER_RX_STOP;
+ else
+ return BCME_USAGE_ERROR;
+ }
+ else if (strcmp(cmd->name, "pkteng_start") == 0) {
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ if (!wl_ether_atoe(*argv, (struct ether_addr *)&pkteng.dest))
+ return BCME_USAGE_ERROR;
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ if ((strcmp(*argv, "tx") == 0) || (strcmp(*argv, "txwithack") == 0)) {
+ if (strcmp(*argv, "tx") == 0)
+ pkteng.flags = WL_PKTENG_PER_TX_START;
+ else
+ pkteng.flags = WL_PKTENG_PER_TX_WITH_ACK_START;
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ if (strcmp(*argv, "async") == 0)
+ pkteng.flags &= ~(WL_PKTENG_SYNCHRONOUS |
+ WL_PKTENG_SYNCHRONOUS_UNBLK);
+ else if (strcmp(*argv, "sync") == 0)
+ pkteng.flags |= WL_PKTENG_SYNCHRONOUS;
+ else if (!strncmp(*argv, "sync_unblk", strlen("sync_unblk"))) {
+ pkteng.flags |= WL_PKTENG_SYNCHRONOUS_UNBLK;
+ }
+ else {
+ /* neither optional parameter [async|sync|sync_unblk] */
+ --argv;
+ }
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ pkteng.delay = strtoul(*argv, NULL, 0);
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ pkteng.length = strtoul(*argv, NULL, 0);
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ pkteng.nframes = strtoul(*argv, NULL, 0);
+ if (*++argv)
+ if (!wl_ether_atoe(*argv, (struct ether_addr *)&pkteng.src))
+ return BCME_USAGE_ERROR;
+ }
+ else if ((strcmp(*argv, "rx") == 0) || (strcmp(*argv, "rxwithack") == 0)) {
+ if ((strcmp(*argv, "rx") == 0))
+ pkteng.flags = WL_PKTENG_PER_RX_START;
+ else
+ pkteng.flags = WL_PKTENG_PER_RX_WITH_ACK_START;
+
+ if (*++argv) {
+ if (strcmp(*argv, "async") == 0)
+ pkteng.flags &= ~WL_PKTENG_SYNCHRONOUS;
+ else if (strcmp(*argv, "sync") == 0) {
+ pkteng.flags |= WL_PKTENG_SYNCHRONOUS;
+ /* sync mode requires number of frames and timeout */
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ pkteng.nframes = strtoul(*argv, NULL, 0);
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ pkteng.delay = strtoul(*argv, NULL, 0);
+ }
+ }
+ }
+ else
+ return BCME_USAGE_ERROR;
+ }
+ else {
+ printf("Invalid command name %s\n", cmd->name);
+ return 0;
+ }
+
+ pkteng.flags = htod32(pkteng.flags);
+ pkteng.delay = htod32(pkteng.delay);
+ pkteng.nframes = htod32(pkteng.nframes);
+ pkteng.length = htod32(pkteng.length);
+
+ return (wlu_var_setbuf(wl, "pkteng", &pkteng, sizeof(pkteng)));
+}
+
+static uint32
+wl_rxiq_prepare(char **argv, wl_iqest_params_t *params, uint8 *resolution)
+{
+ miniopt_t to;
+ const char* fn_name = "wl_rxiqest_prepare";
+ int err = BCME_OK, argc, opt_err;
+ uint8 lpf_hpc = 1;
+ uint8 dig_lpf = 1;
+ uint8 gain_correct = 0;
+ uint8 extra_gain_3dBsteps = 0;
+ uint8 force_gain_type = 0;
+ uint8 antenna = 3;
+
+ *resolution = 0;
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+
+ /* DEFAULT:
+ * gain_correct = 0 (disable gain correction),
+ * lpf_hpc = 1 (sets lpf hpc to lowest value),
+ * dig_lpf = 1; (sets to ltrn_lpf mode)
+ * resolution = 0 (coarse),
+ * samples = 1024 (2^10) and antenna = 3
+ * force_gain_type = 0 (init gain mode)
+ */
+ params->rxiq = (extra_gain_3dBsteps << 28) | (gain_correct << 24) | (dig_lpf << 22)
+ | (lpf_hpc << 20) | (*resolution << 16) | (10 << 8) | (force_gain_type << 4)
+ | antenna;
+
+ params->niter = 1;
+ params->delay = PHY_RXIQEST_AVERAGING_DELAY;
+ if (argc == 0)
+ return 0;
+
+ miniopt_init(&to, fn_name, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 'g') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int"
+ " for gain-correction (0, 1, 2, 3, 4, 7, 8)\n",
+ fn_name, to.valstr);
+
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val < 0) || (to.val > 8)) {
+ fprintf(stderr, "%s: invalid gain-correction select %d"
+ " (0,1,2,3,4,7,8)\n", fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ gain_correct = to.val & 0xf;
+ params->rxiq = ((gain_correct << 24) | (params->rxiq & 0xf0ffffff));
+ }
+ if (to.opt == 'f') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int"
+ " for lpf-hpc override select (0, 1)\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val < 0) || (to.val > 1)) {
+ fprintf(stderr, "%s: invalid lpf-hpc override select %d"
+ " (0,1)\n", fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ lpf_hpc = to.val & 0x3;
+ params->rxiq = ((lpf_hpc << 20) | (params->rxiq & 0xffcfffff));
+ }
+ if (to.opt == 'w') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int"
+ " for dig-lpf override select (0, 1 or 2)\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val < 0) || (to.val > 2)) {
+ fprintf(stderr, "%s: invalid dig-lpf override select %d"
+ " (0,1,2)\n", fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ dig_lpf = to.val & 0x3;
+ params->rxiq = ((dig_lpf << 22) | (params->rxiq & 0xff3fffff));
+ }
+ if (to.opt == 'r') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int"
+ " for resolution (0, 1)\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val < 0) || (to.val > 1)) {
+ fprintf(stderr, "%s: invalid resolution select %d"
+ " (0,1)\n", fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ *resolution = to.val & 0xf;
+ params->rxiq = ((*resolution << 16) | (params->rxiq & 0xfff0ffff));
+ }
+ if (to.opt == 's') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for"
+ " the sample count\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (to.val < 0 || to.val > 16) {
+ fprintf(stderr, "%s: sample count too large %d"
+ "(10 <= x <= 16)\n", fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->rxiq = (((to.val & 0xff) << 8) | (params->rxiq & 0xffff00ff));
+ }
+ if (to.opt == 'a') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int"
+ " for antenna (0, 1, 3)\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val < 0) || (to.val > 3)) {
+ fprintf(stderr, "%s: invalid antenna select %d\n",
+ fn_name, to.val);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->rxiq = ((params->rxiq & 0xfffffff0) | (to.val & 0xf));
+ }
+ if (to.opt == 'e') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int"
+ " for extra INITgain\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val < 0) || (to.val > 24) || (to.val % 3 != 0)) {
+ fprintf(stderr,
+ "%s: Valid extra INITgain = {0, 3, .., 21, 24}\n",
+ fn_name);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->rxiq = ((((to.val/3) & 0xf) << 28) | (params->rxiq & 0x0fffffff));
+ }
+ if (to.opt == 'i') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int"
+ " for init or clipLO mode\n", fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if ((to.val != 0) && (to.val != 1) &&
+ (to.val != 2) && (to.val != 3) && (to.val != 4)) {
+ fprintf(stderr,
+ "%s: Valid options - 0(default gain), 1(fixed high gain)"
+ "or 4(fixed low gain). \n",
+ fn_name);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->rxiq = ((params->rxiq & 0xffffff0f) | ((to.val << 4) & 0xf0));
+ }
+ }
+ params->rxiq = htod32(params->rxiq);
+exit:
+ return err;
+}
+
+static void
+wl_rxiq_print_4365(uint16 *iqest_core, uint8 resolution)
+{
+ if (resolution == 1) {
+ /* fine resolution power reporting (0.25dB resolution) */
+ uint8 core;
+ int16 tmp;
+ /* Four chains: */
+ for (core = 0; core < WL_STA_ANT_MAX; core ++) {
+ tmp = iqest_core[core];
+ if (tmp < 0) {
+ tmp = -1*tmp;
+ printf("-%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25);
+ } else if (tmp > 0) {
+ printf("%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25);
+ }
+ }
+ printf("\n");
+ } else {
+ /* fine resolution power reporting (0.25dB resolution) */
+ uint8 core;
+ int16 tmp;
+ /* Four chains: */
+ for (core = 0; core < WL_STA_ANT_MAX; core ++) {
+ tmp = (int8)(iqest_core[core]);
+ if (tmp != 0)
+ printf("%ddBm ", tmp);
+ }
+ printf("\n");
+ }
+}
+
+static void
+wl_rxiq_print(uint32 rxiq, uint8 resolution)
+{
+ if (resolution == 1) {
+ /* fine resolution power reporting (0.25dB resolution) */
+ uint8 core;
+ int16 tmp;
+ if (rxiq >> 20) {
+ /* Three chains: */
+ for (core = 0; core < 3; core ++) {
+ tmp = (rxiq >> (10*core)) & 0x3ff;
+ tmp = ((int16)(tmp << 6)) >> 6; /* sign extension */
+ if (tmp < 0) {
+ tmp = -1*tmp;
+ printf("-%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25);
+ } else {
+ printf("%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25);
+ }
+ }
+ printf("\n");
+ } else if (rxiq >> 10) {
+ /* 2 chains */
+ for (core = 0; core < 2; core ++) {
+ tmp = (rxiq >> (10*core)) & 0x3ff;
+ tmp = ((int16)(tmp << 6)) >> 6; /* sign extension */
+ if (tmp < 0) {
+ tmp = -1*tmp;
+ printf("-%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25);
+ } else {
+ printf("%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25);
+ }
+ }
+ printf("\n");
+ } else {
+ /* 1 chain */
+ tmp = rxiq & 0x3ff;
+ tmp = ((int16)(tmp << 6)) >> 6; /* sign extension */
+ if (tmp < 0) {
+ tmp = -1*tmp;
+ printf("-%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25);
+ } else {
+ printf("%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25);
+ }
+ printf("\n");
+ }
+
+ } else {
+ if (rxiq >> 24)
+ printf("%ddBm %ddBm %ddBm %ddBm \n", (int8)(rxiq & 0xff),
+ (int8)((rxiq >> 8) & 0xff), (int8)((rxiq >> 16) & 0xff),
+ (int8)((rxiq >> 24) & 0xff));
+ else if (rxiq >> 16)
+ printf("%ddBm %ddBm %ddBm\n", (int8)(rxiq & 0xff),
+ (int8)((rxiq >> 8) & 0xff), (int8)((rxiq >> 16) & 0xff));
+ else if (rxiq >> 8)
+ printf("%ddBm %ddBm\n", (int8)(rxiq & 0xff), (int8)((rxiq >> 8) & 0xff));
+ else
+ printf("%ddBm\n", (int8)(rxiq & 0xff));
+ }
+}
+
+#define IFERR(x) do { err = (x); if (err) return err; } while (0)
+static int
+wl_rxiq(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_iqest_params_t params = {0, 0, 0};
+ uint8 resolution;
+ int err;
+ uint16 iqest_core[WL_STA_ANT_MAX];
+ wlc_rev_info_t revinfo;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ IFERR(wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)));
+
+ IFERR(wl_rxiq_prepare(argv, ¶ms, &resolution));
+
+ if (BCM4365_CHIP(dtoh32(revinfo.chipnum))) {
+ iqest_core[0] = params.rxiq & 0xffff;
+ iqest_core[1] = (params.rxiq >> 16) & 0xffff;
+ IFERR(wlu_var_setbuf(wl, cmd->name, iqest_core, WL_STA_ANT_MAX*sizeof(int16)));
+ IFERR(wlu_iovar_get(wl, cmd->name, iqest_core, WL_STA_ANT_MAX*sizeof(int16)));
+ wl_rxiq_print_4365(iqest_core, resolution);
+ return BCME_OK;
+ }
+
+ IFERR(wlu_iovar_set(wl, cmd->name, ¶ms, sizeof(params)));
+ IFERR(wlu_iovar_getint(wl, cmd->name, (int*)¶ms.rxiq));
+ wl_rxiq_print(params.rxiq, resolution);
+
+ return BCME_OK;
+}
+
+#define SWEEP_ERROR "phy_rxiqest_sweep Error: "
+static int
+wl_rxiq_sweep(void *wl, cmd_t *cmd, char **argv)
+{
+ miniopt_t to;
+ int err, params_size, buf_size, i, offset;
+ uint8 nchannels, resolution, all;
+ char *ptr, *channels = NULL;
+ wl_iqest_sweep_params_t *sweep_params;
+ wl_iqest_result_t *result;
+ wlc_rev_info_t revinfo;
+
+ memset(&revinfo, 0, sizeof(revinfo));
+ IFERR(wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)));
+
+ if (BCM4365_CHIP(dtoh32(revinfo.chipnum)))
+ return BCME_UNSUPPORTED;
+
+ offset = strlen(cmd->name) + 1;
+ sweep_params = (wl_iqest_sweep_params_t *)(buf + offset);
+ if ((err = wl_rxiq_prepare(argv, &sweep_params->params, &resolution)))
+ return err;
+ miniopt_init(&to, "wl_rxiq_sweep", NULL, FALSE);
+ while ((err = miniopt(&to, argv)) != -1) {
+ if (err == 1)
+ return BCME_USAGE_ERROR;
+
+ argv += to.consumed;
+
+ if (to.opt == 'c') {
+ if (channels) {
+ err = BCME_BADARG;
+ fprintf(stderr, SWEEP_ERROR "Duplicate channel parameters\n");
+ goto Exit;
+ }
+ channels = strdup(to.valstr);
+ if (!channels) {
+ fprintf(stderr, SWEEP_ERROR "Unable to allocate %d bytes for "
+ "wl_rxiq_sweep\n", (int)strlen(to.valstr));
+ return BCME_NOMEM;
+ }
+ }
+ }
+
+ if (!channels) {
+ err = BCME_BADCHAN;
+ fprintf(stderr, SWEEP_ERROR "Missing channel parameters\n");
+ goto Exit;
+ }
+
+ for (nchannels = 0, all = 0, ptr = channels; ptr; ptr = strchr(ptr + 1, ','), ++nchannels) {
+ char *channel = *ptr == ',' ? ptr + 1 : ptr;
+
+ if (!strnicmp(channel, "all", 3)) {
+ if (channel == ptr && !channel[3]) {
+ nchannels = 1;
+ all = 1;
+ break;
+ }
+ fprintf(stderr, SWEEP_ERROR "Channel argument should be either all or a "
+ "comma separated list of channels\n");
+ err = BCME_BADCHAN;
+ goto Exit;
+ }
+ }
+
+ if (nchannels > WL_NUMCHANNELS) {
+ fprintf(stderr, SWEEP_ERROR "Maximum of %d channels allowed\n", WL_NUMCHANNELS);
+ err = BCME_BADCHAN;
+ goto Exit;
+ }
+
+ params_size = sizeof(*sweep_params) + (nchannels - 1) * sizeof(uint8);
+ buf_size = sizeof(*result) + ((all ? WL_NUMCHANNELS : nchannels) - 1)
+ * sizeof(wl_iqest_value_t);
+ if (buf_size < params_size + offset)
+ buf_size = params_size + offset;
+ if (buf_size > WLC_IOCTL_MEDLEN) {
+ fprintf(stderr, SWEEP_ERROR "Internal error - buffer is not big enough\n");
+ err = BCME_BUFTOOSHORT;
+ goto Exit;
+ }
+ offset += params_size;
+ if (all) {
+ sweep_params->nchannels = 1;
+ sweep_params->channel[0] = 0;
+ if (sweep_params->params.niter > WL_ITER_LIMIT_MANY_CHAN) {
+ fprintf(stderr, SWEEP_ERROR "Maximum %d averaging iterations allowed if "
+ "number of channel is greater than %d\n", WL_ITER_LIMIT_MANY_CHAN,
+ WL_NUMCHANNELS_MANY_CHAN);
+ err = BCME_BADARG;
+ goto Exit;
+ }
+ }
+ else {
+ sweep_params->nchannels = 0;
+ for (i = 0, ptr = strtok(channels, ","); ptr; ++i, ptr = strtok(NULL, ",")) {
+ int j;
+ char *endptr = NULL;
+ int channel = (int)strtoul(ptr, &endptr, 0);
+
+ if (*endptr || channel < 1 || channel > 165) {
+ fprintf(stderr, SWEEP_ERROR "wrong channel value %s\n", ptr);
+ err = BCME_BADARG;
+ goto Exit;
+ }
+ for (j = 0; j < sweep_params->nchannels; ++j) {
+ if (channel == sweep_params->channel[j]) {
+ err = BCME_BADCHAN;
+ fprintf(stderr, SWEEP_ERROR "Duplicate channel "
+ "parameters\n");
+ goto Exit;
+ }
+ }
+ sweep_params->channel[sweep_params->nchannels++] = (uint8)channel;
+ }
+ }
+
+ if (sweep_params->nchannels > WL_NUMCHANNELS_MANY_CHAN && sweep_params->params.niter
+ > WL_ITER_LIMIT_MANY_CHAN) {
+ fprintf(stderr, SWEEP_ERROR "Maximum %d averaging iterations allowed if number"
+ " of channel is greater than %d\n", WL_ITER_LIMIT_MANY_CHAN,
+ WL_NUMCHANNELS_MANY_CHAN);
+ err = BCME_BADARG;
+ goto Exit;
+ }
+
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, sweep_params, params_size, buf, buf_size)) < 0)
+ goto Exit;
+
+ result = (wl_iqest_result_t *)buf;
+ for (i = 0; i < result->nvalues; ++i) {
+ printf("Channel: %u\t", result->value[i].channel);
+ wl_rxiq_print(dtoh32(result->value[i].rxiq), resolution);
+ }
+Exit:
+ free(channels);
+ return err;
+}
+
+#if defined(BCMDBG)
+static int
+wl_phy_debug_cmd(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int val;
+ char *val_name;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* command name */
+ val_name = *argv++;
+ val = (*argv == NULL) ? 0 : atoi(*argv);
+
+
+ if ((err = wlu_iovar_setint(wl, val_name, (int)val)) < 0)
+ printf("PHY DEBUG COMMAND error %d\n", err);
+
+ return err;
+
+}
+#endif
+
+static int
+wl_rifs(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int val, rifs;
+ char *val_name;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* command name */
+ val_name = *argv++;
+
+ if (!*argv) {
+ if ((err = wlu_iovar_getint(wl, val_name, (int*)&rifs)) < 0)
+ return err;
+
+ printf("%s\n", ((rifs & 0xff) ? "On" : "Off"));
+ return 0;
+ }
+
+ val = rifs = (atoi(*argv) ? 1 : 0);
+
+ if ((err = wlu_set(wl, WLC_SET_FAKEFRAG, &val, sizeof(int))) < 0) {
+ printf("Set frameburst error %d\n", err);
+ return err;
+ }
+ if ((err = wlu_iovar_setint(wl, val_name, (int)rifs)) < 0)
+ printf("Set rifs error %d\n", err);
+
+ return err;
+}
+
+static int
+wl_rifs_advert(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ int rifs_advert;
+ char *val_name;
+
+ BCM_REFERENCE(cmd);
+
+ /* command name */
+ val_name = *argv++;
+
+ if (!*argv) {
+ if ((err = wlu_iovar_getint(wl, val_name, (int*)&rifs_advert)) < 0)
+ return err;
+
+ printf("%s\n", ((rifs_advert & 0xff) ? "On" : "Off"));
+ return 0;
+ }
+
+ if (strcmp(*argv, "-1") && strcmp(*argv, "0"))
+ return BCME_USAGE_ERROR;
+
+ rifs_advert = atoi(*argv);
+
+ if ((err = wlu_iovar_setint(wl, val_name, (int)rifs_advert)) < 0)
+ printf("Set rifs mode advertisement error %d\n", err);
+
+ return err;
+}
+
+static int
+wlu_afeoverride(void *wl, cmd_t *cmd, char **argv)
+{
+ char var[256];
+ uint32 int_val;
+ bool get = TRUE;
+ void *ptr = NULL;
+ char *endptr;
+
+ if (argv[1]) {
+ uint32 get_val;
+ get = FALSE;
+ int_val = htod32(strtoul(argv[1], &endptr, 0));
+ if (wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr) < 0)
+ return -1;
+ get_val = *(int *)ptr;
+ get_val &= ~1;
+ if (int_val)
+ int_val = get_val | 1;
+ else
+ int_val = get_val;
+ memcpy(var, (char *)&int_val, sizeof(int_val));
+ }
+ if (get) {
+ if (wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr) < 0)
+ return -1;
+ printf("0x%x\n", dtoh32(*(int *)ptr));
+ }
+ else
+ wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
+ return 0;
+}
+
+/*
+ * RADAR detection parameter control
+ */
+static int
+wl_radar_args(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ wl_radar_args_t ra;
+
+ /* Skip the command name */
+ argv++;
+
+ if (*argv == NULL) {
+ /* Get */
+
+ if ((ret = wlu_iovar_get(wl, cmd->name, &ra, sizeof(ra))) < 0)
+ return ret;
+
+ if (ra.version != WL_RADAR_ARGS_VERSION) {
+ printf("\tIncorrect version of RADAR_ARGS struct: expected %d; got %d\n",
+ WL_RADAR_ARGS_VERSION, ra.version);
+ return -1;
+ }
+ printf("version %d npulses %d ncontig %d min_pw %d max_pw %d thresh0 0x%x "
+ "thresh1 0x%x\n",
+ ra.version, ra.npulses, ra.ncontig, ra.min_pw,
+ ra.max_pw, ra.thresh0, ra.thresh1);
+ printf("blank 0x%x fmdemodcfg 0x%x npulses_lp %d min_pw_lp %d "
+ "max_pw_lp %d\n",
+ ra.blank, ra.fmdemodcfg, ra.npulses_lp, ra.min_pw_lp,
+ ra.max_pw_lp);
+ printf("min_fm_lp %d max_span_lp %d min_deltat %d max_deltat %d\n",
+ ra.min_fm_lp, ra.max_span_lp, ra.min_deltat, ra.max_deltat);
+
+ printf("autocorr 0x%x st_level_time 0x%x t2_min %d fra_pulse_err %d\n",
+ ra.autocorr, ra.st_level_time, ra.t2_min, ra.fra_pulse_err);
+ printf("npulses_fra %d npulses_stg2 %d npulses_stg3 %d percal_mask 0x%x quant %d\n",
+ ra.npulses_fra, ra.npulses_stg2, ra.npulses_stg3, ra.percal_mask,
+ ra.quant);
+ printf("min_burst_intv_lp %d max_burst_intv_lp %d nskip_rst_lp %d max_pw_tol %d "
+ "feature_mask 0x%x\n",
+ ra.min_burst_intv_lp, ra.max_burst_intv_lp, ra.nskip_rst_lp,
+ ra.max_pw_tol, ra.feature_mask);
+ printf("thresh0_sc 0x%x thresh1_sc 0x%x\n",
+ ra.thresh0_sc, ra.thresh1_sc);
+
+ /* this part prints only param values */
+ printf("%d %d %d %d %d 0x%x "
+ "0x%x",
+ ra.version, ra.npulses, ra.ncontig, ra.min_pw,
+ ra.max_pw, ra.thresh0, ra.thresh1);
+ printf(" 0x%x 0x%x %d %d "
+ "%d",
+ ra.blank, ra.fmdemodcfg, ra.npulses_lp, ra.min_pw_lp,
+ ra.max_pw_lp);
+ printf(" %d %d %d %d",
+ ra.min_fm_lp, ra.max_span_lp, ra.min_deltat, ra.max_deltat);
+
+ printf(" 0x%x 0x%x %d %d",
+ ra.autocorr, ra.st_level_time, ra.t2_min, ra.fra_pulse_err);
+ printf(" %d %d %d 0x%x %d",
+ ra.npulses_fra, ra.npulses_stg2, ra.npulses_stg3, ra.percal_mask,
+ ra.quant);
+ printf(" %d %d %d %d "
+ "0x%x 0x%x 0x%x\n",
+ ra.min_burst_intv_lp, ra.max_burst_intv_lp, ra.nskip_rst_lp,
+ ra.max_pw_tol, ra.feature_mask, ra.thresh0_sc, ra.thresh1_sc);
+
+
+ } else {
+ /* Set */
+ char *endptr = NULL;
+ int val_count = 32;
+ long vals[32];
+ long *pval;
+ int i;
+
+ for (i = 0; i < val_count; i++, argv++) {
+ /* verify that there is another arg */
+ if (*argv == NULL)
+ return BCME_USAGE_ERROR;
+
+ vals[i] = strtol(*argv, &endptr, 0);
+
+ /* make sure all the value string was parsed by strtol */
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+
+ pval = vals;
+
+ ra.version = *pval++;
+ ra.npulses = *pval++;
+ ra.ncontig = *pval++;
+ ra.min_pw = *pval++;
+ ra.max_pw = *pval++;
+ ra.thresh0 = (uint16)*pval++;
+ ra.thresh1 = (uint16)*pval++;
+ ra.blank = (uint16)*pval++;
+ ra.fmdemodcfg = (uint16)*pval++;
+ ra.npulses_lp = *pval++;
+ ra.min_pw_lp = *pval++;
+ ra.max_pw_lp = *pval++;
+ ra.min_fm_lp = *pval++;
+ ra.max_span_lp = *pval++;
+ ra.min_deltat = *pval++;
+ ra.max_deltat = *pval++;
+ ra.autocorr = (uint16)*pval++;
+ ra.st_level_time = (uint16)*pval++;
+ ra.t2_min = (uint16)*pval++;
+ ra.fra_pulse_err = (uint32)*pval++;
+ ra.npulses_fra = (int)*pval++;
+ ra.npulses_stg2 = (int)*pval++;
+ ra.npulses_stg3 = (int)*pval++;
+ ra.percal_mask = (int)*pval++;
+ ra.quant = (int)*pval++;
+ ra.min_burst_intv_lp = (uint32)*pval++;
+ ra.max_burst_intv_lp = (uint32)*pval++;
+ ra.nskip_rst_lp = (int)*pval++;
+ ra.max_pw_tol = (int)*pval++;
+ ra.feature_mask = (uint16)*pval++;
+ ra.thresh0_sc = (uint16)*pval++;
+ ra.thresh1_sc = (uint16)*pval++;
+
+ return wlu_var_setbuf(wl, cmd->name, &ra, sizeof(wl_radar_args_t));
+ }
+ return ret;
+}
+
+static int
+wl_radar_thrs(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = -1;
+ wl_radar_thr_t radar_thrs;
+
+ if (*++argv) {
+ /* Set */
+ char *endptr;
+ #ifdef WL11AC160
+ int val_count = 16;
+ uint16 vals[16];
+ #else
+ int val_count = 12;
+ uint16 vals[12];
+ #endif /* WL11AC160 */
+
+ uint16 *pval;
+ int i;
+
+ for (i = 0; i < val_count; i++, argv++) {
+ /* verify that there is another arg */
+ if (i < 12) {
+ /* for BW20,40,80 */
+ if (*argv == NULL)
+ return BCME_USAGE_ERROR;
+ vals[i] = (uint16)strtol(*argv, &endptr, 0);
+ /* make sure all the value string was parsed by strtol */
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+ #ifdef WL11AC160
+ else {
+ /* for BW160 */
+ if (*argv == NULL) {
+ if (i == 12) {
+ /* To be compatable with older commands */
+ vals[i] = 0;
+ vals[i+1] = 0;
+ vals[i+2] = 0;
+ vals[i+3] = 0;
+ break;
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+ } else {
+ vals[i] = (uint16)strtol(*argv, &endptr, 0);
+ /* make sure all the value string was parsed by strtol */
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+
+ }
+ #endif /* WL11AC160 */
+ }
+
+ radar_thrs.version = WL_RADAR_THR_VERSION;
+
+ /* Order thresh0_20_lo, thresh1_20_lo, thresh0_40_lo, thresh1_40_lo
+ * thresh0_20_hi, thresh1_20_hi, thresh0_40_hi, thresh1_40_hi
+ */
+ pval = vals;
+ radar_thrs.thresh0_20_lo = (uint16)*pval++;
+ radar_thrs.thresh1_20_lo = (uint16)*pval++;
+ radar_thrs.thresh0_40_lo = (uint16)*pval++;
+ radar_thrs.thresh1_40_lo = (uint16)*pval++;
+ radar_thrs.thresh0_80_lo = (uint16)*pval++;
+ radar_thrs.thresh1_80_lo = (uint16)*pval++;
+ radar_thrs.thresh0_20_hi = (uint16)*pval++;
+ radar_thrs.thresh1_20_hi = (uint16)*pval++;
+ radar_thrs.thresh0_40_hi = (uint16)*pval++;
+ radar_thrs.thresh1_40_hi = (uint16)*pval++;
+ radar_thrs.thresh0_80_hi = (uint16)*pval++;
+ radar_thrs.thresh1_80_hi = (uint16)*pval++;
+ #ifdef WL11AC160
+ radar_thrs.thresh0_160_lo = (uint16)*pval++;
+ radar_thrs.thresh1_160_lo = (uint16)*pval++;
+ radar_thrs.thresh0_160_hi = (uint16)*pval++;
+ radar_thrs.thresh1_160_hi = (uint16)*pval++;
+ #endif /* WL11AC160 */
+
+
+ return wlu_var_setbuf(wl, cmd->name, &radar_thrs, sizeof(wl_radar_thr_t));
+ }
+ return ret;
+}
+
+
+static int
+wl_radar_thrs2(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = -1;
+ wl_radar_thr2_t radar_thrs2;
+ argv++;
+
+ if (*argv == NULL) {
+ if ((ret = wlu_iovar_get(wl, cmd->name, &radar_thrs2, sizeof(radar_thrs2))) < 0)
+ return ret;
+
+ if (radar_thrs2.version != WL_RADAR_ARGS_VERSION) {
+ printf("\tIncorrect version"
+ "\tof RADAR_ARGS struct:expected %d; got %d\n",
+ WL_RADAR_ARGS_VERSION, radar_thrs2.version);
+ return -1;
+ }
+ printf("version %d\n"
+ "thresh0_sc_20_lo 0x%x thresh1_sc_20_lo 0x%x"
+ "thresh0_sc_40_lo 0x%x thresh1_sc_40_lo 0x%x"
+ "thresh0_sc_80_lo 0x%x thresh1_sc_80_lo 0x%x\n"
+ "thresh0_sc_20_hi 0x%x thresh1_sc_20_hi 0x%x"
+ "thresh0_sc_40_hi 0x%x thresh1_sc_40_hi 0x%x"
+ "thresh0_sc_80_hi 0x%x thresh1_sc_80_hi 0x%x\n"
+ "fc_varth_sb 0x%x fc_varth_bin5_sb 0x%x notradar_enb 0x%x\n"
+ "max_notradar_lp 0x%x max_notradar 0x%x max_notradar_lp_sc 0x%x "
+ "max_notradar_sc 0x%x highpow_war_enb 0x%x highpow_sp_ratio 0x%x\n",
+ radar_thrs2.version, radar_thrs2.thresh0_sc_20_lo,
+ radar_thrs2.thresh1_sc_20_lo,
+ radar_thrs2.thresh0_sc_40_lo, radar_thrs2.thresh1_sc_40_lo,
+ radar_thrs2.thresh0_sc_80_lo, radar_thrs2.thresh1_sc_80_lo,
+ radar_thrs2.thresh0_sc_20_hi, radar_thrs2.thresh1_sc_20_hi,
+ radar_thrs2.thresh0_sc_40_hi, radar_thrs2.thresh1_sc_40_hi,
+ radar_thrs2.thresh0_sc_80_hi, radar_thrs2.thresh1_sc_80_hi,
+ radar_thrs2.fc_varth_sb, radar_thrs2.fc_varth_bin5_sb,
+ radar_thrs2.notradar_enb, radar_thrs2.max_notradar_lp,
+ radar_thrs2.max_notradar,
+ radar_thrs2.max_notradar_lp_sc, radar_thrs2.max_notradar_sc,
+ radar_thrs2.highpow_war_enb, radar_thrs2.highpow_sp_ratio);
+
+ /* this part prints only param values */
+ printf("0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x "
+ "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ radar_thrs2.thresh0_sc_20_lo, radar_thrs2.thresh1_sc_20_lo,
+ radar_thrs2.thresh0_sc_40_lo, radar_thrs2.thresh1_sc_40_lo,
+ radar_thrs2.thresh0_sc_80_lo, radar_thrs2.thresh1_sc_80_lo,
+ radar_thrs2.thresh0_sc_20_hi, radar_thrs2.thresh1_sc_20_hi,
+ radar_thrs2.thresh0_sc_40_hi, radar_thrs2.thresh1_sc_40_hi,
+ radar_thrs2.thresh0_sc_80_hi, radar_thrs2.thresh1_sc_80_hi,
+ radar_thrs2.fc_varth_sb, radar_thrs2.fc_varth_bin5_sb,
+ radar_thrs2.notradar_enb,
+ radar_thrs2.max_notradar_lp, radar_thrs2.max_notradar,
+ radar_thrs2.max_notradar_lp_sc, radar_thrs2.max_notradar_sc,
+ radar_thrs2.highpow_war_enb, radar_thrs2.highpow_sp_ratio);
+
+ } else {
+ /* Set */
+ char *endptr = NULL;
+ int val_count = 21;
+ long vals[21];
+ long *pval;
+ int i;
+
+ for (i = 0; i < val_count; i++, argv++) {
+ /* verify that there is another arg */
+ if (*argv == NULL)
+ return BCME_USAGE_ERROR;
+
+ vals[i] = strtol(*argv, &endptr, 0);
+
+ /* make sure all the value string was parsed by strtol */
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+
+ radar_thrs2.version = WL_RADAR_THR_VERSION;
+
+ pval = vals;
+ radar_thrs2.thresh0_sc_20_lo = (uint16)*pval++;
+ radar_thrs2.thresh1_sc_20_lo = (uint16)*pval++;
+ radar_thrs2.thresh0_sc_40_lo = (uint16)*pval++;
+ radar_thrs2.thresh1_sc_40_lo = (uint16)*pval++;
+ radar_thrs2.thresh0_sc_80_lo = (uint16)*pval++;
+ radar_thrs2.thresh1_sc_80_lo = (uint16)*pval++;
+ radar_thrs2.thresh0_sc_20_hi = (uint16)*pval++;
+ radar_thrs2.thresh1_sc_20_hi = (uint16)*pval++;
+ radar_thrs2.thresh0_sc_40_hi = (uint16)*pval++;
+ radar_thrs2.thresh1_sc_40_hi = (uint16)*pval++;
+ radar_thrs2.thresh0_sc_80_hi = (uint16)*pval++;
+ radar_thrs2.thresh1_sc_80_hi = (uint16)*pval++;
+ radar_thrs2.fc_varth_sb = (uint16)*pval++;
+ radar_thrs2.fc_varth_bin5_sb = (uint16)*pval++;
+ radar_thrs2.notradar_enb = (uint16)*pval++;
+ radar_thrs2.max_notradar_lp = (uint16)*pval++;
+ radar_thrs2.max_notradar = (uint16)*pval++;
+ radar_thrs2.max_notradar_lp_sc = (uint16)*pval++;
+ radar_thrs2.max_notradar_sc = (uint16)*pval++;
+ radar_thrs2.highpow_war_enb = (uint16)*pval++;
+ radar_thrs2.highpow_sp_ratio = (uint16)*pval++;
+ return wlu_var_setbuf(wl, cmd->name, &radar_thrs2, sizeof(wl_radar_thr2_t));
+ }
+ return ret;
+
+}
+
+static int
+wl_phy_dyn_switch_th(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = -1;
+ wl_dyn_switch_th_t dyn_switch_th;
+ argv++;
+
+ if (*argv == NULL) {
+ if ((ret = wlu_iovar_get(wl, cmd->name, &dyn_switch_th, sizeof(dyn_switch_th))) < 0)
+ return ret;
+
+ if (dyn_switch_th.ver != WL_PHY_DYN_SWITCH_TH_VERSION) {
+ printf("\tIncorrect version"
+ "\tof phy_dyn_switch_th:expected %d; got %d\n",
+ WL_PHY_DYN_SWITCH_TH_VERSION, dyn_switch_th.ver);
+ return -1;
+ }
+ printf("version %d\n"
+ "rssi_gain_80_3 %d rssi_gain_80_2 %d "
+ "rssi_gain_80_1 %d rssi_gain_80_0 %d \n"
+ "rssi_gain_160_3 %d rssi_gain_160_2 %d "
+ "rssi_gain_160_1 %d rssi_gain_160_0 %d \n"
+ "rssi_th_2 %d rssi_th_1 %d "
+ "rssi_th_0 %d\n",
+ dyn_switch_th.ver, dyn_switch_th.rssi_gain_80[3],
+ dyn_switch_th.rssi_gain_80[2],
+ dyn_switch_th.rssi_gain_80[1], dyn_switch_th.rssi_gain_80[0],
+ dyn_switch_th.rssi_gain_160[3], dyn_switch_th.rssi_gain_160[2],
+ dyn_switch_th.rssi_gain_160[1], dyn_switch_th.rssi_gain_160[0],
+ dyn_switch_th.rssi_th[2], dyn_switch_th.rssi_th[1],
+ dyn_switch_th.rssi_th[0]);
+
+ /* this part prints only param values */
+ printf("%d %d %d %d %d %d %d %d %d "
+ "%d %d\n",
+ dyn_switch_th.rssi_gain_80[3], dyn_switch_th.rssi_gain_80[2],
+ dyn_switch_th.rssi_gain_80[1], dyn_switch_th.rssi_gain_80[0],
+ dyn_switch_th.rssi_gain_160[3], dyn_switch_th.rssi_gain_160[2],
+ dyn_switch_th.rssi_gain_160[1], dyn_switch_th.rssi_gain_160[0],
+ dyn_switch_th.rssi_th[2], dyn_switch_th.rssi_th[1],
+ dyn_switch_th.rssi_th[0]);
+
+ } else {
+ /* Set */
+ char *endptr = NULL;
+ uint val_count = 11;
+ long vals[11];
+ long *pval;
+ uint i;
+
+ for (i = 0; i < val_count; i++, argv++) {
+ /* verify that there is another arg */
+ if (*argv == NULL)
+ return BCME_USAGE_ERROR;
+ vals[i] = strtol(*argv, &endptr, 0);
+
+ /* make sure all the value string was parsed by strtol */
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+
+ dyn_switch_th.ver = WL_PHY_DYN_SWITCH_TH_VERSION;
+
+ pval = vals;
+ dyn_switch_th.rssi_gain_80[3] = (uint16)*pval++;
+ dyn_switch_th.rssi_gain_80[2] = (uint16)*pval++;
+ dyn_switch_th.rssi_gain_80[1] = (uint16)*pval++;
+ dyn_switch_th.rssi_gain_80[0] = (uint16)*pval++;
+ dyn_switch_th.rssi_gain_160[3] = (uint16)*pval++;
+ dyn_switch_th.rssi_gain_160[2] = (uint16)*pval++;
+ dyn_switch_th.rssi_gain_160[1] = (uint16)*pval++;
+ dyn_switch_th.rssi_gain_160[0] = (uint16)*pval++;
+ dyn_switch_th.rssi_th[2] = (int16)*pval++;
+ dyn_switch_th.rssi_th[1] = (int16)*pval++;
+ dyn_switch_th.rssi_th[0] = (int16)*pval++;
+ return wlu_var_setbuf(wl, cmd->name, &dyn_switch_th, sizeof(wl_dyn_switch_th_t));
+ }
+ return ret;
+
+}
+
+static int
+wl_phy_tpc_av(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ uint argc;
+ char *endptr;
+ uint8 Av_buff[3];
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+ argc--;
+
+ if (argc < 2 || argc > 3)
+ return BCME_USAGE_ERROR;
+ Av_buff[0] = (uint8)strtol(argv[1], &endptr, 0);
+ Av_buff[1] = (uint8)strtol(argv[2], &endptr, 0);
+
+ if (argc == 2) {
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, Av_buff, 2*sizeof(uint8),
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ return (ret);
+ }
+ printf("Av = %d for core%d and sub-band %d\n", *(uint*)buf, Av_buff[0], Av_buff[1]);
+ } else if (argc == 3) {
+ Av_buff[2] = (uint8)strtol(argv[3], &endptr, 0);
+ ret = wlu_iovar_setbuf(wl, cmd->name, Av_buff, 3*sizeof(uint8),
+ buf, WLC_IOCTL_MAXLEN);
+ }
+ return ret;
+}
+
+static int
+wl_phy_tpc_vmid(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ uint argc;
+ char *endptr;
+ uint8 Vmid_buff[3];
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+ argc--;
+
+ if (argc < 2 || argc > 3)
+ return BCME_USAGE_ERROR;
+ Vmid_buff[0] = (uint8)strtol(argv[1], &endptr, 0);
+ Vmid_buff[1] = (uint8)strtol(argv[2], &endptr, 0);
+
+ if (argc == 2) {
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, Vmid_buff, 2*sizeof(uint8),
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ return (ret);
+ }
+ printf("Vmid = %d for core%d and sub-band %d\n", *(uint*)buf, Vmid_buff[0],
+ Vmid_buff[1]);
+ } else if (argc == 3) {
+ Vmid_buff[2] = (uint8)strtol(argv[3], &endptr, 0);
+ ret = wlu_iovar_setbuf(wl, cmd->name, Vmid_buff, 3*sizeof(uint8),
+ buf, WLC_IOCTL_MAXLEN);
+ }
+ return ret;
+}
+
+
+
+
+/* TXCAL IOVARS */
+static int
+wl_txcal_gainsweep_meas(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_txcal_meas_ncore_t * txcal_meas, * txcal_meas_old;
+ wl_txcal_meas_percore_t * per_core;
+ wl_txcal_meas_old_t * txcal_meas_legacy;
+ int16 pwr[WLC_TXCORE_MAX][MAX_NUM_TXCAL_MEAS];
+
+ void *ptr = NULL;
+ int err = BCME_OK;
+ int version_err = BCME_OK;
+ void* buf = NULL;
+ uint8 core;
+ uint16 i;
+ uint16 buf_size = OFFSETOF(wl_txcal_meas_ncore_t, txcal_percore) +
+ WLC_TXCORE_MAX* sizeof(wl_txcal_meas_percore_t);
+
+ /* Allocate buffer for set iovar */
+ buf = malloc(buf_size);
+ if (buf == NULL) {
+ err = BCME_NOMEM;
+ goto fail;
+ }
+ memset(buf, 0, buf_size);
+ txcal_meas = (wl_txcal_meas_ncore_t *)buf;
+
+ if (*++argv) {
+ i = 0;
+ core = strtoul(*argv, NULL, 0);
+
+ if (core > (WLC_TXCORE_MAX- 1)) {
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ if (!*++argv) {
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ /* Check for version */
+ version_err = wlu_var_getbuf_sm(wl, "txcal_ver", NULL, 0, &ptr);
+ if ((version_err != BCME_OK) || (*(int*)ptr == 0)) {
+ /* using wl with backward compatibility for old firmware */
+ memset(pwr, 0, WLC_TXCORE_MAX_OLD*MAX_NUM_TXCAL_MEAS*sizeof(pwr[0][0]));
+ i = 0;
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ goto fail;
+ txcal_meas_legacy = (wl_txcal_meas_old_t *)ptr;
+ memcpy(&pwr[0][0], &txcal_meas_legacy->pwr[0][0],
+ WLC_TXCORE_MAX_OLD*MAX_NUM_TXCAL_MEAS*sizeof(pwr[0][0]));
+ do {
+ if (i >= MAX_NUM_TXCAL_MEAS) {
+ printf("Entries exceeded max allowed\n");
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ pwr[core][i] = strtoul(*argv, NULL, 0);
+ i++;
+ } while (*++argv);
+ if (i != txcal_meas_legacy->valid_cnt) {
+ printf("Incorrect Number of Entries. Expected %d, Entered %d\n",
+ txcal_meas_legacy->valid_cnt, i);
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ err = wlu_var_setbuf(wl, cmd->name, pwr, WLC_TXCORE_MAX_OLD*
+ MAX_NUM_TXCAL_MEAS*sizeof(pwr[0][0]));
+ } else {
+ txcal_meas->version = TXCAL_IOVAR_VERSION;
+ if ((err = wlu_var_getbuf(wl, cmd->name, txcal_meas, buf_size, &ptr)) < 0)
+ goto fail;
+ txcal_meas_old = (wl_txcal_meas_ncore_t *)ptr;
+
+ if (txcal_meas_old->version != TXCAL_IOVAR_VERSION) {
+ printf("Version mismatch %d \n", txcal_meas_old->version);
+ err = BCME_UNSUPPORTED;
+ goto fail;
+ }
+ /* wl support for new txcal structures
+ * check for max core support from dongle
+ */
+ if (core > txcal_meas_old->num_core - 1) {
+ printf("Dongle supports only %d cores \n"
+ "Allowed range 0 - %d \n", txcal_meas_old->num_core,
+ txcal_meas_old->num_core - 1);
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ /* Initialize set structure with fw copy to start with */
+ memcpy(txcal_meas, txcal_meas_old, buf_size);
+
+ /* Get to per core info */
+ per_core = txcal_meas->txcal_percore;
+ per_core += core;
+ do {
+ if (i >= MAX_NUM_TXCAL_MEAS) {
+ printf("Entries exceeded max allowed\n");
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ per_core->pwr[i] = strtoul(*argv, NULL, 0);
+ i++;
+ } while (*++argv);
+ if (i != txcal_meas_old->valid_cnt) {
+ printf("Incorrect Number of Entries. Expected %d, Entered %d\n",
+ txcal_meas_old->valid_cnt, i);
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ /* Add magic seq number */
+ txcal_meas->version = TXCAL_IOVAR_VERSION;
+ err = wlu_var_setbuf(wl, cmd->name, txcal_meas, buf_size);
+ }
+ } else {
+
+ /* Check for version */
+ version_err = wlu_var_getbuf_sm(wl, "txcal_ver", NULL, 0, &ptr);
+ if ((version_err != BCME_OK) || (*(int*)ptr == 0)) {
+ /* support for old firmware with old txcal structures */
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ goto fail;
+ txcal_meas_legacy = (wl_txcal_meas_old_t *)ptr;
+ for (core = 0; core < WLC_TXCORE_MAX_OLD; core++) {
+ printf("CORE%d\tTSSI\t\tPWR\n", core);
+ for (i = 0; i < txcal_meas_legacy->valid_cnt; i++)
+ printf("\t%d\t\t%d\n", txcal_meas_legacy->tssi[core][i],
+ txcal_meas_legacy->pwr[core][i]);
+ }
+ } else {
+ txcal_meas->version = TXCAL_IOVAR_VERSION;
+ if ((err = wlu_var_getbuf(wl, cmd->name, txcal_meas, buf_size, &ptr)) < 0)
+ goto fail;
+ if (txcal_meas->version != TXCAL_IOVAR_VERSION) {
+ printf("version %d unsupported \n", txcal_meas->version);
+ err = BCME_UNSUPPORTED;
+ goto fail;
+ }
+ /* support for new firmware with new txcal structures */
+ txcal_meas = (wl_txcal_meas_ncore_t *)ptr;
+ per_core = txcal_meas->txcal_percore;
+ /* Dump the info */
+ for (core = 0; core < txcal_meas->num_core; core++) {
+ printf("CORE%d\tTSSI\t\tPWR\n", core);
+ for (i = 0; i < txcal_meas->valid_cnt; i++) {
+ printf("\t%d\t\t%d\n", per_core->tssi[i],
+ per_core->pwr[i]);
+ }
+ per_core++;
+ }
+ }
+ }
+
+fail:
+ if (buf) {
+ free(buf);
+ }
+
+ return err;
+}
+
+static int
+wl_txcal_gainsweep(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_txcal_params_t txcal_params;
+ uint8 gidx_start, gidx_stop;
+ int8 gidx_step;
+ char *endptr = NULL;
+ char *gidx_str;
+ int ret;
+
+ memset(&txcal_params, 0, sizeof(txcal_params));
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ if (!wl_ether_atoe(*argv, (struct ether_addr *)&txcal_params.pkteng.dest))
+ return BCME_USAGE_ERROR;
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ txcal_params.pkteng.delay = strtoul(*argv, NULL, 0);
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ txcal_params.pkteng.length = strtoul(*argv, NULL, 0);
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ txcal_params.pkteng.nframes = strtoul(*argv, NULL, 0);
+ if (txcal_params.pkteng.nframes == 0)
+ txcal_params.pkteng.nframes = 4;
+
+ txcal_params.pkteng.flags = WL_PKTENG_PER_TX_START;
+ txcal_params.pkteng.flags |= WL_PKTENG_SYNCHRONOUS;
+
+ txcal_params.pkteng.flags = htod32(txcal_params.pkteng.flags);
+ txcal_params.pkteng.delay = htod32(txcal_params.pkteng.delay);
+ txcal_params.pkteng.nframes = htod32(txcal_params.pkteng.nframes);
+ txcal_params.pkteng.length = htod32(txcal_params.pkteng.length);
+
+ /* read gidx start */
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+ gidx_str = *argv;
+ gidx_start = strtoul(gidx_str, &endptr, 10);
+ if (*endptr == ':') {
+ endptr++;
+ gidx_str = endptr;
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* read gidx step */
+ gidx_step = strtoul(gidx_str, &endptr, 10);
+ if (*endptr == ':') {
+ endptr++;
+ gidx_str = endptr;
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+ if (gidx_step == 0)
+ return BCME_USAGE_ERROR;
+
+ /* read gidx stop */
+ gidx_stop = strtoul(gidx_str, &endptr, 10);
+ if ((*endptr != '\0') && (*endptr != '\n') && (*endptr != ' '))
+ return BCME_USAGE_ERROR;
+
+ txcal_params.gidx_start = gidx_start;
+ txcal_params.gidx_step = gidx_step;
+ txcal_params.gidx_stop = gidx_stop;
+
+ ret = (wlu_var_setbuf(wl, cmd->name, &txcal_params, sizeof(txcal_params)));
+
+ return ret;
+}
+/* wl txcal_pwr_tssi_tbl */
+static int
+wl_txcal_pwr_tssi_tbl(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_txcal_power_tssi_ncore_t * txcal_tssi;
+ wl_txcal_power_tssi_ncore_t * txcal_tssi_old;
+ wl_txcal_power_tssi_percore_t * per_core;
+ wl_txcal_power_tssi_old_t txcal_pwr_tssi;
+ wl_txcal_power_tssi_old_t *txcal_pwr_tssi_ptr;
+
+ /* Total buffer size to be allocated */
+ uint16 buf_size = OFFSETOF(wl_txcal_power_tssi_ncore_t, tssi_percore) +
+ WLC_TXCORE_MAX* sizeof(wl_txcal_power_tssi_percore_t);
+
+ void *ptr = NULL;
+ int err = BCME_OK;
+ int version_err = BCME_OK;
+ uint8 i, core = 0;
+ uint8 channel = 0;
+ void * buf = NULL;
+ int16 pwr_start = 0;
+ uint8 num_entries = 0;
+
+ /* Allocate buffer for set iovar */
+ buf = malloc(buf_size);
+ if (buf == NULL) {
+ err = BCME_NOMEM;
+ goto fail;
+ }
+ memset(buf, 0, buf_size);
+
+ /* copy older values */
+ txcal_tssi = (wl_txcal_power_tssi_ncore_t *)buf;
+
+ /* core info */
+ if (!(*++argv)) {
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ core = strtoul(*argv, NULL, 0);
+
+ if (core > (WLC_TXCORE_MAX- 1)) {
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ /* channle info */
+ if (!(*++argv)) {
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ channel = strtoul(*argv, NULL, 0);
+
+ if (!(*++argv)) { /* Get */
+
+ version_err = wlu_var_getbuf_sm(wl, "txcal_ver", NULL, 0, &ptr);
+ if ((version_err != BCME_OK) || (*(int*)ptr == 0)) {
+ /* support for firmware with old txcal structures */
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, &channel,
+ sizeof(uint8), &ptr)) < 0)
+ goto fail;
+ txcal_pwr_tssi_ptr = (wl_txcal_power_tssi_old_t *)ptr;
+ printf("CORE %d\n", core);
+ printf("\tChannel = %d\n", txcal_pwr_tssi_ptr->channel);
+ printf("\tStarting Power = %d\n", txcal_pwr_tssi_ptr->pwr_start[core]);
+ printf("\tNum of Entries = %d\n", txcal_pwr_tssi_ptr->num_entries[core]);
+ printf("\tTSSI values:\n");
+ for (i = 0; i < txcal_pwr_tssi_ptr->num_entries[core]; i++)
+ printf("\t%d\n", txcal_pwr_tssi_ptr->tssi[core][i]);
+
+ goto fail;
+ } else {
+ txcal_tssi->version = TXCAL_IOVAR_VERSION;
+ txcal_tssi->channel = channel;
+ if ((err = wlu_var_getbuf(wl, cmd->name, txcal_tssi, buf_size, &ptr)) < 0)
+ goto fail;
+ txcal_tssi = (wl_txcal_power_tssi_ncore_t *)ptr;
+
+ /* checking txcal version */
+ if (txcal_tssi->version != TXCAL_IOVAR_VERSION) {
+ printf("version %d unsupported \n", txcal_tssi->version);
+ err = BCME_UNSUPPORTED;
+ goto fail;
+ }
+
+ /* support for firmware with new txcal structures
+ * check for max core support from dongle
+ */
+ if (core > txcal_tssi->num_core - 1) {
+ printf("Dongle supports only %d cores \n"
+ "Allowed range 0 - %d \n", txcal_tssi->num_core,
+ txcal_tssi->num_core - 1);
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ /* per core pointer */
+ per_core = txcal_tssi->tssi_percore;
+
+ /* Move to requested core */
+ per_core += core;
+ printf("CORE %d\n", core);
+ printf("\tChannel = %d\n", txcal_tssi->channel);
+ printf("\tStarting Power = %d\n", per_core->pwr_start);
+ printf("\tNum of Entries = %d\n", per_core->num_entries);
+ printf("\tTSSI values:\n");
+ for (i = 0; i < per_core->num_entries; i++)
+ printf("\t%d\n", per_core->tssi[i]);
+
+ goto fail;
+ }
+ } else {
+ argv = argv - 2;
+ }
+ if (*++argv) {
+ pwr_start = strtol(*argv, NULL, 0);
+ } else {
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ if (*++argv) {
+ num_entries = strtoul(*argv, NULL, 0);
+ } else {
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+ if (num_entries >= MAX_NUM_PWR_STEP) {
+ printf("Entries exceeded max allowed\n");
+ err = -1;
+ goto fail;
+ }
+
+ if (*++argv) {
+ channel = strtoul(*argv, NULL, 0);
+ } else {
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ version_err = wlu_var_getbuf_sm(wl, "txcal_ver", NULL, 0, &ptr);
+ if ((version_err != BCME_OK) || (*(int*)ptr == 0)) {
+ /* support for firmware with old txcal structures */
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, &channel, sizeof(uint8), &ptr)) < 0)
+ goto fail;
+ txcal_pwr_tssi_ptr = ptr;
+ txcal_pwr_tssi = *txcal_pwr_tssi_ptr;
+ txcal_pwr_tssi.channel = channel;
+ txcal_pwr_tssi.set_core = core;
+ txcal_pwr_tssi.pwr_start[core] = pwr_start;
+ txcal_pwr_tssi.num_entries[core] = num_entries;
+
+ if (*++argv) { /* Set */
+ memset(txcal_pwr_tssi.tssi[core], 0,
+ MAX_NUM_PWR_STEP*sizeof(txcal_pwr_tssi.tssi[0][0]));
+ i = 0;
+ do {
+ if (i >= MAX_NUM_PWR_STEP) {
+ printf("Entries exceeded max allowed\n");
+ err = -1;
+ goto fail;
+ }
+ txcal_pwr_tssi.tssi[core][i] = strtoul(*argv, NULL, 0);
+ i++;
+ } while (*++argv);
+ if (i != txcal_pwr_tssi.num_entries[core]) {
+ printf("Incorrect Number of Entries. Expected %d, Entered %d\n",
+ txcal_pwr_tssi.num_entries[core], i);
+ err = -1;
+ goto fail;
+ }
+ txcal_pwr_tssi.gen_tbl = 0;
+
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, &txcal_pwr_tssi,
+ sizeof(txcal_pwr_tssi))) < 0)
+ goto fail;
+ } else { /* Generate */
+ txcal_pwr_tssi.gen_tbl = 1;
+ err = wlu_var_setbuf(wl, cmd->name, &txcal_pwr_tssi,
+ sizeof(txcal_pwr_tssi));
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, &channel,
+ sizeof(uint8), &ptr)) < 0)
+ goto fail;
+ txcal_pwr_tssi_ptr = ptr;
+ printf("CORE %d\n", core);
+ printf("\tChannel = %d\n", txcal_pwr_tssi_ptr->channel);
+ printf("Starting Power = %d\n", txcal_pwr_tssi_ptr->pwr_start[core]);
+ printf("Num of Entries = %d\n", txcal_pwr_tssi_ptr->num_entries[core]);
+ printf("TSSI values:\n");
+ for (i = 0; i < txcal_pwr_tssi_ptr->num_entries[core]; i++)
+ printf("%d\n", txcal_pwr_tssi_ptr->tssi[core][i]);
+ }
+
+ } else {
+
+ txcal_tssi->version = TXCAL_IOVAR_VERSION;
+ txcal_tssi->channel = channel;
+ if ((err = wlu_var_getbuf(wl, cmd->name, txcal_tssi, buf_size, &ptr)) < 0)
+ goto fail;
+
+ /* Current copy form fw */
+ txcal_tssi_old = (wl_txcal_power_tssi_ncore_t *)ptr;
+
+ if (txcal_tssi_old->version != TXCAL_IOVAR_VERSION) {
+ printf("version %d unsupported \n", txcal_tssi_old->version);
+ err = BCME_UNSUPPORTED;
+ goto fail;
+ }
+ /* support for firmware with new txcal structures */
+ /* check for max core support from dongle */
+ if (core > txcal_tssi_old->num_core - 1) {
+ printf("Dongle supports only %d cores \n"
+ "Allowed range 0 - %d\n", txcal_tssi_old->num_core,
+ txcal_tssi_old->num_core - 1);
+ err = BCME_USAGE_ERROR;
+ goto fail;
+ }
+
+ memcpy(txcal_tssi, txcal_tssi_old, buf_size);
+
+ /* Update user input values */
+ txcal_tssi->channel = channel;
+ txcal_tssi->set_core = core;
+
+ /* Move to requested core */
+ per_core = txcal_tssi->tssi_percore;
+ per_core += core;
+
+ /* Update per core info */
+ per_core->pwr_start = pwr_start;
+ per_core->num_entries = num_entries;
+
+ if (*++argv) { /* Set */
+ memset(per_core->tssi, 0, MAX_NUM_PWR_STEP * sizeof(per_core->tssi[0]));
+ i = 0;
+ do {
+ if (i >= MAX_NUM_PWR_STEP) {
+ printf("Entries exceeded max allowed\n");
+ err = -1;
+ goto fail;
+ }
+ per_core->tssi[i] = strtoul(*argv, NULL, 0);
+ i++;
+ } while (*++argv);
+ if (i != num_entries) {
+ printf("Incorrect Number of Entries. Expected %d, Entered %d\n",
+ num_entries, i);
+ err = -1;
+ goto fail;
+ }
+ txcal_tssi->gen_tbl = 0;
+ txcal_tssi->version = TXCAL_IOVAR_VERSION;
+ if ((err = wlu_var_setbuf(wl, cmd->name, txcal_tssi,
+ buf_size)) < 0)
+ goto fail;
+ } else { /* Generate */
+ txcal_tssi->gen_tbl = 1;
+
+ txcal_tssi->version = TXCAL_IOVAR_VERSION;
+ err = wlu_var_setbuf(wl, cmd->name, txcal_tssi, buf_size);
+
+ txcal_tssi->version = TXCAL_IOVAR_VERSION;
+ txcal_tssi->channel = channel;
+ if ((err = wlu_var_getbuf(wl, cmd->name, txcal_tssi, buf_size, &ptr)) < 0)
+ goto fail;
+
+ txcal_tssi = (wl_txcal_power_tssi_ncore_t *)ptr;
+
+
+ /* Move to requested core */
+ per_core = txcal_tssi->tssi_percore;
+ per_core += core;
+
+ printf("CORE %d\n", core);
+ printf("\tChannel = %d\n", txcal_tssi->channel);
+ printf("Starting Power = %d\n", per_core->pwr_start);
+ printf("Num of Entries = %d\n", per_core->num_entries);
+ printf("TSSI values:\n");
+ for (i = 0; i < per_core->num_entries; i++)
+ printf("%d\n", per_core->tssi[i]);
+ }
+ }
+
+fail:
+ if (buf)
+ free(buf);
+ return err;
+}
+static int
+wl_olpc_anchoridx(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_txcal_power_tssi_old_t txcal_pwr_tssi;
+ wl_txcal_power_tssi_old_t *txcal_pwr_tssi_ptr;
+ wl_olpc_pwr_t *olpc_pwr_ptr, olpc_pwr;
+ void *ptr = NULL;
+ int err = 0;
+ int version_err = BCME_OK;
+ uint8 core = 0;
+ uint8 channel = 0;
+ int16 tempsense = 0;
+ uint8 olpc_idx = 0;
+ uint16 buf_size = sizeof(wl_olpc_pwr_t);
+ if (!(*++argv)) {
+ return BCME_USAGE_ERROR;
+ }
+ core = strtoul(*argv, NULL, 0);
+ if (!(*++argv)) {
+ return BCME_USAGE_ERROR;
+ }
+ channel = strtoul(*argv, NULL, 0);
+ olpc_pwr_ptr = &olpc_pwr;
+ olpc_pwr_ptr->core = core;
+ olpc_pwr_ptr->channel = channel;
+ olpc_pwr_ptr->version = TXCAL_IOVAR_VERSION;
+
+ if (!(*++argv)) { /* Get */
+ version_err = wlu_var_getbuf_sm(wl, "txcal_ver", NULL, 0, &ptr);
+ if ((version_err != BCME_OK) || (*(int*)ptr == 0)) {
+ /* support for firmware with old txcal structures */
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, &channel,
+ sizeof(uint8), &ptr)) < 0)
+ return err;
+ txcal_pwr_tssi_ptr = ptr;
+ printf("CORE %d\n", core);
+ printf("\tChannel = %d\n", txcal_pwr_tssi_ptr->channel);
+ printf("\tTemperature = %d\n", txcal_pwr_tssi_ptr->tempsense[core]);
+ printf("\tTx pwr idx at anchor power is %d\n",
+ txcal_pwr_tssi_ptr->pwr_start_idx[core]);
+ return err;
+ } else {
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, olpc_pwr_ptr,
+ buf_size, &ptr)) < 0)
+ return err;
+ olpc_pwr_ptr = (wl_olpc_pwr_t *)ptr;
+ /* Checking for txcal version */
+ if (olpc_pwr_ptr->version != TXCAL_IOVAR_VERSION) {
+ printf("version %d unsupported \n", olpc_pwr_ptr->version);
+ err = BCME_UNSUPPORTED;
+ return err;
+ }
+ /* support for firmware with new txcal structures */
+ printf("CORE %d\n", core);
+ printf("\tChannel = %d\n", olpc_pwr_ptr->channel);
+ printf("\tTemperature = %d\n", olpc_pwr_ptr->tempsense);
+ printf("\tTx pwr idx at anchor power is %d\n",
+ olpc_pwr_ptr->olpc_idx);
+ return err;
+ }
+ } else {
+ olpc_idx = strtoul(*argv, NULL, 0);
+ }
+ if (!(*++argv))
+ return BCME_USAGE_ERROR;
+
+ tempsense = strtoul(*argv, NULL, 0);
+
+ if (*++argv)
+ return BCME_USAGE_ERROR;
+
+ version_err = wlu_var_getbuf_sm(wl, "txcal_ver", NULL, 0, &ptr);
+ if ((version_err != BCME_OK) || (*(int*)ptr == 0)) {
+ /* support for firmware with old txcal structures */
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, &channel, sizeof(uint8), &ptr)) < 0)
+ return err;
+ txcal_pwr_tssi_ptr = ptr;
+ txcal_pwr_tssi = *txcal_pwr_tssi_ptr;
+ txcal_pwr_tssi.channel = channel;
+ txcal_pwr_tssi.tempsense[core] = tempsense;
+ txcal_pwr_tssi.set_core = core;
+ txcal_pwr_tssi.pwr_start_idx[core] = olpc_idx;
+ if ((err = wlu_var_setbuf(wl, cmd->name, &txcal_pwr_tssi,
+ sizeof(txcal_pwr_tssi))) < 0)
+ return err;
+ } else {
+ /* Checking for txcal version */
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, olpc_pwr_ptr, buf_size, &ptr)) < 0)
+ return err;
+ txcal_pwr_tssi_ptr = ptr;
+ if (olpc_pwr_ptr->version != TXCAL_IOVAR_VERSION) {
+ printf("version %d unsupported \n", olpc_pwr_ptr->version);
+ err = BCME_UNSUPPORTED;
+ return err;
+ }
+ /* support for firmware with new txcal structures */
+ olpc_pwr_ptr = &olpc_pwr;
+ olpc_pwr_ptr->channel = channel;
+ olpc_pwr_ptr->tempsense = tempsense;
+ olpc_pwr_ptr->core = core;
+ olpc_pwr_ptr->olpc_idx = olpc_idx;
+ olpc_pwr_ptr->version = TXCAL_IOVAR_VERSION;
+
+ if ((err = wlu_var_setbuf_sm(wl, cmd->name, olpc_pwr_ptr, buf_size)) < 0)
+ return err;
+ }
+ return err;
+}
+
+static int
+wl_read_estpwrlut(void *wl, cmd_t *cmd, char **argv)
+{
+ uint16 *estpwrlut;
+ void *ptr = NULL;
+ int err;
+ uint8 i;
+ int val;
+ char* endptr = NULL;
+
+ argv++;
+
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+
+ val = htod32(strtol(*argv, &endptr, 0));
+ if (*endptr != '\0') {
+ /* not all the value string was parsed by strtol */
+ printf("set: error parsing value \"%s\" as an integer\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, &val, sizeof(val), &ptr)) < 0)
+ return err;
+ estpwrlut = ptr;
+ printf("ESTPWR LUT FOR CORE %d\n", val);
+ for (i = 0; i < 128; i++)
+ printf("%d\n", estpwrlut[i] > 0x7F ? (int16) (estpwrlut[i] - 0x100) : estpwrlut[i]);
+
+ return err;
+}
+
+static int
+wl_olpc_offset(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr = NULL;
+ int err = 0;
+ int8 olpc_offset[5];
+ int8 *olpc_offset_ptr;
+ uint8 i = 0;
+
+ if (!(*++argv)) {
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, &ptr)) < 0) {
+ return err;
+ }
+ olpc_offset_ptr = ptr;
+ printf("OLPC offset for 2G: %d\n", olpc_offset_ptr[0]);
+ printf("OLPC offset for 5G low/mid/high/x1: %d %d %d %d\n", olpc_offset_ptr[1],
+ olpc_offset_ptr[2], olpc_offset_ptr[3], olpc_offset_ptr[4]);
+ } else {
+ do {
+ if (i > 4) {
+ return BCME_USAGE_ERROR;
+ }
+
+ olpc_offset[i] = strtol(*argv, NULL, 0);
+ i++;
+ } while (*++argv);
+
+ /* Expect 5 entries */
+ if (i != 5) {
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, olpc_offset, 5*sizeof(int8))) < 0) {
+ printf("Unable to set olpc_offsets.\n");
+ return BCME_ERROR;
+ }
+ }
+ return err;
+}
+
+static int
+wl_btcoex_desense_rxgain(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_desense_restage_gain_t desense_restage_gain;
+ wl_desense_restage_gain_t *desense_restage_gain_ptr;
+ uint8 num_cores = 0, i;
+ uint32 num_params = 0;
+ int err = 0;
+ void *ptr = NULL;
+
+ memset(&desense_restage_gain, 0, sizeof(desense_restage_gain));
+ desense_restage_gain.version = 0;
+ desense_restage_gain.length = sizeof(desense_restage_gain);
+
+ if (!(*++argv)) { /* Get */
+ if ((err = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return err;
+
+ desense_restage_gain_ptr = ptr;
+
+ if (desense_restage_gain_ptr->band == WLC_BAND_2G)
+ printf("Band: 2G\n");
+
+ if (desense_restage_gain_ptr->band == WLC_BAND_5G)
+ printf("Band: 5G\n");
+
+ printf("# of cores: %d\n", desense_restage_gain_ptr->num_cores);
+
+ for (i = 0; i < desense_restage_gain_ptr->num_cores; i++)
+ printf("Desense for core[%d] = %d \n",
+ i, desense_restage_gain_ptr->desense_array[i]);
+
+ return BCME_OK;
+ }
+
+ /* Set */
+ if (strcmp(*argv, "b") == 0) {
+ desense_restage_gain.band = WLC_BAND_2G;
+ } else if (strcmp(*argv, "a") == 0) {
+ desense_restage_gain.band = WLC_BAND_5G;
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ ++argv;
+ if (*argv == NULL) {
+ return BCME_USAGE_ERROR;
+ }
+ num_cores = strtoul(*argv, NULL, 0);
+
+ if (num_cores > WL_TX_CHAINS_MAX) {
+ printf("Number of cores %d greater than max value %d\n",
+ num_cores, WL_TX_CHAINS_MAX);
+ return BCME_USAGE_ERROR;
+ }
+
+ desense_restage_gain.num_cores = num_cores;
+
+ ++argv;
+ while ((argv[num_params] != NULL) &&
+ (num_params < num_cores)) {
+ desense_restage_gain.desense_array[num_params] =
+ strtoul(argv[num_params], NULL, 0);
+ num_params++;
+ }
+
+ if (num_params != num_cores || (argv[num_params] != NULL)) {
+ printf("Number of parameters(%d) not matching number of cores(%d)\n",
+ num_params, num_cores);
+ return BCME_USAGE_ERROR;
+ }
+
+ return (wlu_var_setbuf(wl, cmd->name, &desense_restage_gain, sizeof(desense_restage_gain)));
+}
diff --git a/wl/src/wl/exe/wluc_pkt_filter.c b/wl/src/wl/exe/wluc_pkt_filter.c
new file mode 100644
index 0000000..6085c49
--- /dev/null
+++ b/wl/src/wl/exe/wluc_pkt_filter.c
@@ -0,0 +1,843 @@
+/*
+ * wl pkt_filter command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_pkt_filter.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_pkt_filter_add;
+static cmd_func_t wl_pkt_filter_enable;
+static cmd_func_t wl_pkt_filter_list;
+static cmd_func_t wl_pkt_filter_stats;
+static cmd_func_t wl_pkt_filter_ports;
+
+static cmd_t wl_pkt_filter_cmds[] = {
+ { "pkt_filter_add", wl_pkt_filter_add, -1, -1,
+ "Install a packet filter.\n"
+ "\tUsage: wl pkt_filter_add <id> <polarity> <type> <offset> <bitmask> <pattern>\n"
+ "\tid: Integer. User specified id.\n"
+ "\ttype: 0 (Pattern matching filter)\n"
+ "\t 1 (Magic pattern match (variable offset)\n"
+ "\t 2 (Extended pattern list)\n"
+ "\t 4 (Android Packet Filter)\n"
+ "\t 5 (Pattern matching filter with timeout event)\n"
+ "\t 6 (Immediate Packet filter)\n"
+ "\toffset: (type 0): Integer offset in received packet to start matching.\n"
+ "\t (type 1): Integer offset, match here are anywhere later.\n"
+ "\t (type 2): [<base>:]<offset>. Symbolic packet loc plus relative\n"
+ "\t offset, use wl_pkt_filter_add -l for a <base> list.\n"
+ "\t (type 5): Integer offset in received packet to start matching.\n"
+ "\t (type 6): [<base>:]<offset>. Symbolic packet loc plus relative\n"
+ "\t offset, use wl_pkt_filter_add -l for a <base> list.\n"
+ "\tpolarity: Set to 1 to negate match result. 0 is default.\n"
+ "\tbitmask: Hex bitmask that indicates which bits of 'pattern' to match.\n"
+ "\t Must be same size as 'pattern'. Bit 0 of bitmask corresponds\n"
+ "\t to bit 0 of pattern, etc. If bit N of bitmask is 0, then do\n"
+ "\t *not* match bit N of the pattern with the received payload. If\n"
+ "\t bit N of bitmask is 1, then perform match.\n"
+ "\tpattern: Hex pattern to match. Must be same size as <bitmask>.\n"
+ "\t Syntax: same as bitmask, but for type 2 (pattern list), a '!'\n"
+ "\t may be used to negate that pattern match (e.g. !0xff03).\n"
+ "\tFor type 2 & 6: [<base>:]<offset> <bitmask> [!]<pattern> triple may be\n"
+ "\trepeated; all sub-patterns must match for the filter to match.\n"
+ "\tFor type 4: <id> <polarity> <type> <apf program> \n"
+ "\ttimeout: (type 5): Number of seconds to wait before sending a timeout event when\n"
+ "\t a matching pattern packet is not received.\n"},
+ { "pkt_filter_clear_stats", wl_varint, -1, WLC_SET_VAR,
+ "Clear packet filter statistic counter values.\n"
+ "\tUsage: wl pkt_filter_clear_stats <id>" },
+ { "pkt_filter_enable", wl_pkt_filter_enable, -1, -1,
+ "Enable/disable a packet filter.\n"
+ "\tUsage: wl pkt_filter_enable <id> <0|1>"},
+ { "pkt_filter_list", wl_pkt_filter_list, -1, -1,
+ "List installed packet filters.\n"
+ "\tUsage: wl pkt_filter_list [val]\n"
+ "\tval: 0 (disabled filters) 1 (enabled filters)"},
+ { "pkt_filter_mode", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Set packet filter match action.\n"
+ "\tUsage: wl pkt_filter_mode <value>\n"
+ "\tvalue: 1 - Forward packet on match, discard on non-match (default).\n"
+ "\t 0 - Discard packet on match, forward on non-match." },
+ { "pkt_filter_delete", wl_varint, -1, WLC_SET_VAR,
+ "Uninstall a packet filter.\n"
+ "\tUsage: wl pkt_filter_delete <id>"},
+ { "pkt_filter_stats", wl_pkt_filter_stats, -1, -1,
+ "Retrieve packet filter statistic counter values.\n"
+ "\tUsage: wl pkt_filter_stats <id>"},
+ { "pkt_filter_ports", wl_pkt_filter_ports, WLC_GET_VAR, WLC_SET_VAR,
+ "Set up additional port filters for TCP and UDP packets.\n"
+ "\tUsage: wl pkt_filter_ports [<port-number>] ...\n"
+ "\t wl pkt_filter_ports none (to clear/disable)"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_pkt_filter_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register pkt_filter commands */
+ wl_module_cmds_register(wl_pkt_filter_cmds);
+}
+
+/* Packet filter section: extended filters have named offsets, add table here */
+typedef struct {
+ char *name;
+ uint16 base;
+} wl_pfbase_t;
+
+static wl_pfbase_t basenames[] = { WL_PKT_FILTER_BASE_NAMES };
+
+static void
+wl_pkt_filter_base_list(void)
+{
+ uint i;
+
+ printf("Names accepted for base offsets:\n");
+ for (i = 0; i < ARRAYSIZE(basenames); i++)
+ {
+ printf("\t%s\n", basenames[i].name);
+ }
+}
+
+static int
+wl_pkt_filter_base_parse(char *name)
+{
+ uint i;
+ char *bname, *uname;
+
+ for (i = 0; i < ARRAYSIZE(basenames); i++) {
+ bname = basenames[i].name;
+ for (uname = name; *uname; bname++, uname++) {
+ if (*bname != toupper(*uname))
+ break;
+ }
+ if (!*uname && !*bname)
+ break;
+ }
+
+ if (i < ARRAYSIZE(basenames)) {
+ return basenames[i].base;
+ } else {
+ return -1;
+ }
+}
+
+static char *
+wl_pkt_filter_base_show(uint16 base)
+{
+ uint i;
+ static char numeric[6];
+
+ for (i = 0; i < ARRAYSIZE(basenames); i++) {
+ if (basenames[i].base == base)
+ return basenames[i].name;
+ }
+
+ sprintf(numeric, "%d", base);
+ return numeric;
+}
+
+/* Enable/disable installed packet filter. */
+static int
+wl_pkt_filter_enable(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_pkt_filter_enable_t enable_parm;
+ int rc;
+
+ if (*++argv == NULL) {
+ printf("No args provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Parse packet filter id. */
+ enable_parm.id = htod32(strtoul(*argv, NULL, 0));
+
+ if (*++argv == NULL) {
+ printf("Enable/disable value not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Parse enable/disable value. */
+ enable_parm.enable = htod32(strtoul(*argv, NULL, 0));
+
+
+ /* Enable/disable the specified filter. */
+ rc = wlu_var_setbuf(wl,
+ cmd->name,
+ &enable_parm,
+ sizeof(wl_pkt_filter_enable_t));
+
+ return (rc);
+}
+
+
+/* Install a new packet filter. */
+static int
+wl_pkt_filter_add(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *str;
+ wl_pkt_filter_t pkt_filter;
+ wl_pkt_filter_t *pkt_filterp;
+ int buf_len;
+ int str_len;
+ int rc;
+ uint32 mask_size;
+ uint32 pattern_size;
+ uint ftype;
+ char *endptr;
+
+ UNUSED_PARAMETER(cmd);
+
+ str = "pkt_filter_add";
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[ str_len ] = '\0';
+ buf_len = str_len + 1;
+
+ pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
+
+ if (argv[1] && strcmp(argv[1], "-l") == 0) {
+ wl_pkt_filter_base_list();
+ return BCME_OK;
+ }
+
+ /* Parse packet filter id. */
+ if (*++argv == NULL) {
+ printf("No args provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ pkt_filter.id = htod32(strtoul(*argv, &endptr, 0));
+ if (*endptr) {
+ printf("Invalid number for id: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Parse filter polarity. */
+ if (*++argv == NULL) {
+ printf("Polarity not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ pkt_filter.negate_match = htod32(strtoul(*argv, &endptr, 0));
+ if (*endptr) {
+ printf("Invalid number for polarity: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Parse filter type. */
+ if (*++argv == NULL) {
+ printf("Filter type not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ pkt_filter.type = htod32(strtoul(*argv, &endptr, 0));
+ ftype = htod32(strtoul(*argv, &endptr, 0));
+ if (*endptr) {
+ printf("Invalid number for filter type: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ if ((ftype != WL_PKT_FILTER_TYPE_PATTERN_MATCH) &&
+ (ftype != WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH) &&
+ (ftype != WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH) &&
+ (ftype != WL_PKT_FILTER_TYPE_APF_MATCH) &&
+ (ftype != WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT) &&
+ (ftype != WL_PKT_FILTER_TYPE_IMMEDIATE_PATTERN_MATCH)) {
+ printf("Invalid filter type %d\n", ftype);
+ return BCME_USAGE_ERROR;
+ }
+ pkt_filter.type = htod32(ftype);
+
+ /* Handle basic (or magic) pattern filter */
+ if ((ftype == WL_PKT_FILTER_TYPE_PATTERN_MATCH) ||
+ (ftype == WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH)) {
+ wl_pkt_filter_pattern_t *pfilter = &pkt_filterp->u.pattern;
+
+ /* Parse pattern filter offset. */
+ if (*++argv == NULL) {
+ printf("Offset not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ pkt_filter.u.pattern.offset = htod32(strtoul(*argv, &endptr, 0));
+ if (*endptr) {
+ printf("Invalid number for offset: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Parse pattern filter mask. */
+ if (*++argv == NULL) {
+ printf("Bitmask not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ rc = wl_pattern_atoh(*argv, (char *)pfilter->mask_and_pattern);
+ if (rc == -1) {
+ printf("Rejecting: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ mask_size = htod32(rc);
+
+ /* Parse pattern filter pattern. */
+ if (*++argv == NULL) {
+ printf("Pattern not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ rc = wl_pattern_atoh(*argv, (char *)&pfilter->mask_and_pattern[rc]);
+ if (rc == -1) {
+ printf("Rejecting: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ pattern_size = htod32(rc);
+
+ if (mask_size != pattern_size) {
+ printf("Mask and pattern not the same size\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ pkt_filter.u.pattern.size_bytes = mask_size;
+ buf_len += WL_PKT_FILTER_FIXED_LEN;
+ buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * rc);
+
+ /* The fields that were put in a local for alignment purposes now
+ * get copied to the right place in the ioctl buffer.
+ */
+ memcpy((char *)pkt_filterp, &pkt_filter,
+ WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
+ }
+
+ /* Handle pattern list */
+ if ((ftype == WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH) ||
+ (ftype == WL_PKT_FILTER_TYPE_IMMEDIATE_PATTERN_MATCH)) {
+ int list_cnt = 0;
+ wl_pkt_filter_pattern_listel_t *pf_el = &pkt_filterp->u.patlist.patterns[0];
+
+ while (*++argv != NULL) {
+ /* Parse pattern filter base and offset. */
+ if (isdigit(**argv)) {
+ /* Numeric base */
+ rc = strtoul(*argv, &endptr, 0);
+ } else {
+ endptr = strchr(*argv, ':');
+ if (endptr) {
+ *endptr = '\0';
+ rc = wl_pkt_filter_base_parse(*argv);
+ if (rc == -1) {
+ printf("Invalid base %s\n", *argv);
+ wl_pkt_filter_base_list();
+ return BCME_USAGE_ERROR;
+ }
+ *endptr = ':';
+ } else {
+ printf("Invalid [base:]offset format: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ if (*endptr == ':') {
+ pkt_filter.u.patlist.patterns[0].base_offs = htod16(rc);
+ rc = strtoul(endptr + 1, &endptr, 0);
+ } else {
+ /* Must have had a numeric offset only */
+ pkt_filter.u.patlist.patterns[0].base_offs = htod16(0);
+ }
+
+ if (*endptr) {
+ printf("Invalid [base:]offset format: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ if (rc > 0x0000FFFF) {
+ printf("Offset too large\n");
+ return BCME_USAGE_ERROR;
+ }
+ pkt_filter.u.patlist.patterns[0].rel_offs = htod16(rc);
+
+ /* Clear match_flag (may be set in parsing which follows) */
+ pkt_filter.u.patlist.patterns[0].match_flags = htod16(0);
+
+ /* Parse pattern filter mask and pattern directly into ioctl buffer */
+ if (*++argv == NULL) {
+ printf("Bitmask not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ rc = wl_pattern_atoh(*argv, (char*)pf_el->mask_and_data);
+ if (rc == -1) {
+ printf("Rejecting: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ mask_size = htod16(rc);
+
+ if (*++argv == NULL) {
+ printf("Pattern not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (**argv == '!') {
+ pkt_filter.u.patlist.patterns[0].match_flags =
+ htod16(WL_PKT_FILTER_MFLAG_NEG);
+ (*argv)++;
+ }
+ if (*argv == '\0') {
+ printf("Pattern not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ rc = wl_pattern_atoh(*argv, (char*)&pf_el->mask_and_data[rc]);
+ if (rc == -1) {
+ printf("Rejecting: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ pattern_size = htod16(rc);
+
+ if (mask_size != pattern_size) {
+ printf("Mask and pattern not the same size\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ pkt_filter.u.patlist.patterns[0].size_bytes = mask_size;
+
+
+ /* Account for the size of this pattern element */
+ buf_len += WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 2 * rc;
+
+ /* And the pattern element fields that were put in a local for
+ * alignment purposes now get copied to the ioctl buffer.
+ */
+ memcpy((char*)pf_el, &pkt_filter.u.patlist.patterns[0],
+ WL_PKT_FILTER_PATTERN_FIXED_LEN);
+
+ /* Move to next element location in ioctl buffer */
+ pf_el = (wl_pkt_filter_pattern_listel_t*)
+ ((uint8*)pf_el + WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 2 * rc);
+
+ /* Count list element */
+ list_cnt++;
+ }
+
+ /* Account for initial fixed size, and copy initial fixed fields */
+ buf_len += WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN;
+
+ /* Update list count and total size */
+ pkt_filter.u.patlist.list_cnt = list_cnt;
+ pkt_filter.u.patlist.PAD1[0] = 0;
+ pkt_filter.u.patlist.totsize = buf + buf_len - (char*)pkt_filterp;
+ pkt_filter.u.patlist.totsize -= WL_PKT_FILTER_FIXED_LEN;
+
+ memcpy((char *)pkt_filterp, &pkt_filter,
+ WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN);
+ }
+ /* Android Packet Filter */
+ if (ftype == WL_PKT_FILTER_TYPE_APF_MATCH) {
+ wl_apf_program_t *apf_program = &pkt_filterp->u.apf_program;
+ char *token = *++argv;
+ int count;
+ char num[3];
+
+ if (strlen(token) % 2) {
+ printf("Invalid APF program length: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ for (count = 0; *token != '\0'; count++, token += 2) {
+ strncpy(num, token, 2);
+ num[2] = '\0';
+ apf_program->instrs[count] = (uint8)strtoul(num, NULL, 16);
+ }
+ apf_program->instr_len = htod16(count);
+ apf_program->version = htod16(WL_APF_INTERNAL_VERSION);
+
+ buf_len += WL_PKT_FILTER_FIXED_LEN;
+ buf_len += WL_APF_PROGRAM_TOTAL_LEN(apf_program);
+
+ memcpy((char *)pkt_filterp, &pkt_filter, WL_PKT_FILTER_FIXED_LEN);
+ }
+
+ /* Handle pattern filter with timeout event */
+ if (ftype == WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT) {
+ wl_pkt_filter_pattern_timeout_t *pfilter = &pkt_filterp->u.pattern_timeout;
+
+ /* Parse pattern filter offset. */
+ if (*++argv == NULL) {
+ printf("Offset not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ pkt_filter.u.pattern.offset = htod32(strtoul(*argv, &endptr, 0));
+ if (*endptr) {
+ printf("Invalid number for offset: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Parse pattern filter mask. */
+ if (*++argv == NULL) {
+ printf("Bitmask not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ rc = wl_pattern_atoh(*argv, (char *)pfilter->mask_and_pattern);
+ if (rc == -1) {
+ printf("Rejecting: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ mask_size = htod32(rc);
+
+ /* Parse pattern filter pattern. */
+ if (*++argv == NULL) {
+ printf("Pattern not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ rc = wl_pattern_atoh(*argv, (char *)&pfilter->mask_and_pattern[rc]);
+ if (rc == -1) {
+ printf("Rejecting: %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ pattern_size = htod32(rc);
+
+ if (mask_size != pattern_size) {
+ printf("Mask and pattern not the same size\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (*++argv == NULL) {
+ printf("timeout not specified\n");
+ return BCME_USAGE_ERROR;
+ }
+ pkt_filter.u.pattern_timeout.timeout = htod32(strtoul(*argv, &endptr, 0));
+ pkt_filter.u.pattern.size_bytes = mask_size;
+ buf_len += WL_PKT_FILTER_FIXED_LEN;
+ buf_len += (WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN + 2 * rc);
+
+ /* The fields that were put in a local for alignment purposes now
+ * get copied to the right place in the ioctl buffer.
+ */
+ memcpy((char *)pkt_filterp, &pkt_filter,
+ WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN);
+ }
+
+ rc = wlu_set(wl, WLC_SET_VAR, buf, buf_len);
+
+ return (rc);
+}
+
+/* List installed packet filters. */
+static void
+wl_pkt_filter_list_mask_pat(uint8 *bytes, uint size, char *indent)
+{
+ uint j;
+
+ printf("%sMask :0x", indent);
+
+ for (j = 0; j < size; j++)
+ printf("%02x", bytes[j]);
+
+ printf("\n%sPattern :0x", indent);
+
+ for (; j < 2 * size; j++)
+ printf("%02x", bytes[j]);
+
+ printf("\n\n");
+}
+
+/* List installed packet filters. */
+static int
+wl_pkt_filter_list(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_pkt_filter_list_t *list;
+ wl_pkt_filter_t *filterp;
+ void *ptr = NULL;
+ unsigned int i;
+ unsigned int j;
+ int rc;
+ unsigned int filter_len;
+ uint32 enable;
+
+
+ if (*++argv == NULL) {
+ printf("No args provided\n");
+ return (BCME_USAGE_ERROR);
+ }
+
+ /* Parse filter list to retrieve (enabled/disabled). */
+ enable = htod32(strtoul(*argv, NULL, 0));
+ /*
+ ** Get list of installed packet filters.
+ */
+ if ((rc = wlu_var_getbuf(wl, cmd->name, &enable, sizeof(enable), &ptr)) < 0)
+ return rc;
+
+ list = (wl_pkt_filter_list_t *) ptr;
+
+ printf("Num filters: %d\n\n", list->num);
+
+ filterp = list->filter;
+ for (i = 0; i < list->num; i++)
+ {
+ uint type = dtoh32(filterp->type);
+
+ if (type == WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT) {
+ printf("Id :%d\n"
+ "Negate :%d\n"
+ "Type :%d\n"
+ "Offset :%d\n"
+ "Pattern len :%d\n"
+ "Timeout :%d seconds\n",
+ dtoh32(filterp->id),
+ dtoh32(filterp->negate_match),
+ dtoh32(filterp->type),
+ dtoh32(filterp->u.pattern_timeout.offset),
+ dtoh32(filterp->u.pattern_timeout.size_bytes),
+ dtoh32(filterp->u.pattern_timeout.timeout));
+
+ wl_pkt_filter_list_mask_pat(filterp->u.pattern_timeout.mask_and_pattern,
+ dtoh32(filterp->u.pattern_timeout.size_bytes), "");
+ filter_len = WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN +
+ 2 * dtoh32(filterp->u.pattern_timeout.size_bytes);
+ } else if (type == WL_PKT_FILTER_TYPE_APF_MATCH) {
+ wl_apf_program_t *apf_program;
+ uint8 *pc;
+ uint16 len;
+
+ apf_program = &filterp->u.apf_program;
+ pc = apf_program->instrs;
+ len = dtoh16(apf_program->instr_len);
+
+ if (dtoh16(apf_program->version) != WL_APF_INTERNAL_VERSION) {
+ printf("%s: APF: incorrect version, version=%d, "
+ "expected version=%d\n", __FUNCTION__,
+ dtoh16(apf_program->version), WL_APF_INTERNAL_VERSION);
+ rc = BCME_BADARG;
+ break;
+ }
+ printf("Id :%d\n"
+ "Negate :%d\n"
+ "Type :%d\n"
+ "Program len :%d\n",
+ dtoh32(filterp->id),
+ dtoh32(filterp->negate_match),
+ dtoh32(filterp->type),
+ len);
+ printf("Program :");
+ for (j = 0; pc && (j < len); pc++, j++) {
+ printf("%02X", *pc);
+ }
+ printf("\n\n");
+ filter_len = WL_APF_PROGRAM_TOTAL_LEN(apf_program);
+ } else if ((type == WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH) ||
+ (type == WL_PKT_FILTER_TYPE_IMMEDIATE_PATTERN_MATCH)) {
+ char *indent = " ";
+ uint cnt = filterp->u.patlist.list_cnt;
+ wl_pkt_filter_pattern_listel_t *listel = filterp->u.patlist.patterns;
+
+ printf("Id :%d\n"
+ "Negate :%d\n"
+ "Type :%d\n"
+ "List count :%d\n",
+ dtoh32(filterp->id),
+ dtoh32(filterp->negate_match),
+ dtoh32(filterp->type),
+ cnt);
+
+ for (j = 1; j <= cnt; j++) {
+ printf("%sPattern %d\n", indent, j);
+ printf("%sOffset :%s:%d\n"
+ "%sMatch flags :%04x\n"
+ "%sPattern len :%d\n",
+ indent, wl_pkt_filter_base_show(dtoh16(listel->base_offs)),
+ dtoh16(listel->rel_offs),
+ indent, dtoh16(listel->match_flags),
+ indent, dtoh16(listel->size_bytes));
+ wl_pkt_filter_list_mask_pat(listel->mask_and_data,
+ dtoh16(listel->size_bytes), indent);
+ listel = (wl_pkt_filter_pattern_listel_t*)
+ ((uintptr)listel +
+ WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN +
+ 2 * dtoh16(listel->size_bytes));
+ }
+
+ filter_len = (uint8*)listel - (uint8*)&filterp->u.patlist;
+ } else {
+ printf("Id :%d\n"
+ "Negate :%d\n"
+ "Type :%d\n"
+ "Offset :%d\n"
+ "Pattern len :%d\n",
+ dtoh32(filterp->id),
+ dtoh32(filterp->negate_match),
+ dtoh32(filterp->type),
+ dtoh32(filterp->u.pattern.offset),
+ dtoh32(filterp->u.pattern.size_bytes));
+
+ wl_pkt_filter_list_mask_pat(filterp->u.pattern.mask_and_pattern,
+ dtoh32(filterp->u.pattern.size_bytes), "");
+ filter_len = WL_PKT_FILTER_PATTERN_FIXED_LEN +
+ 2 * dtoh32(filterp->u.pattern.size_bytes);
+ }
+
+ filter_len += WL_PKT_FILTER_FIXED_LEN;
+ filterp = (wl_pkt_filter_t *) ((uint8 *)filterp + filter_len);
+ filterp = ALIGN_ADDR(filterp, sizeof(uint32));
+
+ }
+
+ return (rc);
+}
+
+/* Get packet filter debug statistics. */
+static int
+wl_pkt_filter_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_pkt_filter_stats_t *stats;
+ uint32 id;
+ int rc;
+ void *ptr = NULL;
+
+ if (*++argv == NULL) {
+ printf("No args provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Parse filter id to retrieve. */
+ id = htod32(strtoul(*argv, NULL, 0));
+
+
+ /* Get debug stats. */
+ if ((rc = wlu_var_getbuf(wl, cmd->name, &id, sizeof(id), &ptr)) < 0)
+ return rc;
+
+ stats = (wl_pkt_filter_stats_t *) ptr;
+
+ printf("Packets matched for filter '%d': %d\n"
+ "Total packets discarded : %d\n"
+ "Total packet forwarded : %d\n",
+ id,
+ dtoh32(stats->num_pkts_matched),
+ dtoh32(stats->num_pkts_discarded),
+ dtoh32(stats->num_pkts_forwarded));
+
+ return (rc);
+}
+
+/* Get/set packet filter port list */
+static int
+wl_pkt_filter_ports(void *wl, cmd_t *cmd, char **argv)
+{
+ int rc, i;
+ void *ptr;
+ uint16 count;
+ uint16 *ports;
+ wl_pkt_filter_ports_t *portlist;
+
+ uint len;
+ char *endptr = NULL;
+ unsigned long portnum;
+
+ if ((strlen("pkt_filter_ports") + 1 +
+ WL_PKT_FILTER_PORTS_FIXED_LEN +
+ sizeof(uint16) * WL_PKT_FILTER_PORTS_MAX) > WLC_IOCTL_MEDLEN) {
+ fprintf(stderr, "Ioctl sizing error.\n");
+ return -1;
+ }
+
+ if (*++argv == NULL) {
+ /* Get iovar */
+ if ((rc = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, &ptr)))
+ return rc;
+
+ portlist = (wl_pkt_filter_ports_t*)ptr;
+ count = dtoh16(portlist->count);
+ ports = &portlist->ports[0];
+
+ /* Bail if anything in the headeer is unexpected */
+ if (portlist->version != WL_PKT_FILTER_PORTS_VERSION) {
+ printf("Unsupported version %d, only support %d\n",
+ portlist->version, WL_PKT_FILTER_PORTS_VERSION);
+ return BCME_USAGE_ERROR;
+ }
+ if (portlist->reserved != 0) {
+ printf("Format error: nonzero reserved element 0x%02x\n",
+ portlist->reserved);
+ return BCME_USAGE_ERROR;
+ }
+ if (count > WL_PKT_FILTER_PORTS_MAX) {
+ printf("Invalid count %d\n", count);
+ return BCME_USAGE_ERROR;
+ }
+
+ printf("Port count %d:\n", count);
+ for (i = 0; i < count; i++) {
+ printf("%d\n", dtoh16(ports[i]));
+ }
+
+ return 0;
+
+ } else {
+ /* Set iovar - build the structure in the global buffer */
+ portlist = (wl_pkt_filter_ports_t*)buf;
+ portlist->version = WL_PKT_FILTER_PORTS_VERSION;
+ portlist->reserved = 0;
+
+ ports = &portlist->ports[0];
+
+ for (count = 0; *argv && (count < WL_PKT_FILTER_PORTS_MAX); count++, argv++) {
+ portnum = strtoul(*argv, &endptr, 0);
+ if ((*endptr != '\0') || (portnum > 0xffff)) {
+ if (!strcmp(*argv, "none")) {
+ argv += 1;
+ break;
+ } else {
+ printf("Bad port number %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ }
+ ports[count] = htod16((uint16)portnum);
+ }
+
+ if (*argv) {
+ printf("Too many port numbers!\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ portlist->count = htod16(count);
+
+ len = WL_PKT_FILTER_PORTS_FIXED_LEN + (count * sizeof(uint16));
+ memmove((buf + strlen("pkt_filter_ports") + 1), buf, len);
+ strcpy(buf, "pkt_filter_ports");
+ len += strlen("pkt_filter_ports") + 1;
+
+ return wlu_set(wl, WLC_SET_VAR, buf, len);
+ }
+}
diff --git a/wl/src/wl/exe/wluc_prot_obss.c b/wl/src/wl/exe/wluc_prot_obss.c
new file mode 100644
index 0000000..7698551
--- /dev/null
+++ b/wl/src/wl/exe/wluc_prot_obss.c
@@ -0,0 +1,248 @@
+/*
+ * wl prot_obss command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_prot_obss.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#if defined(BCMDBG) || defined(BCMDBG_DUMP)
+static cmd_func_t wl_ccastats;
+#endif
+static cmd_func_t wl_dyn_bwsw_params;
+
+static cmd_t wl_prot_obss_cmds[] = {
+ { "obss_prot", wl_bcm_config, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/set OBSS protection (-1=auto, 0=disable, 1=enable)\n" },
+#if defined(BCMDBG) || defined(BCMDBG_DUMP)
+ { "dump_obss", wl_ccastats, WLC_GET_VAR, -1,
+ "Usage: \n\t wl dump_obss [-d num msecs] to begin measurement\n"
+ "\t wl dump_obss to query for the measurement results" },
+ { "ccastats", wl_ccastats, WLC_GET_VAR, -1,
+ "Usage: \n\t wl ccastats [-d num msecs] to begin measurement\n"
+ "\t wl ccastats [-o option: 0=default, 1=detail, 2=1+CRS] to query for measurements" },
+ { "dump_obss_dyn_bwsw", wl_ccastats, WLC_GET_VAR, -1,
+ "Usage: \n\t wl dump_obss_dyn_bwsw [-d num msecs] to begin measurement\n"
+ "\t wl dump_obss_dyn_bwsw to query for the results" },
+#endif
+ { "dyn_bwsw_params", wl_dyn_bwsw_params, WLC_GET_VAR, WLC_SET_VAR,
+ "Configure the params for dynamic bandswitch\n"
+ "\tUsage (Get): wl dyn_bwsw_params \n"
+ "\tUsage (Set): wl dyn_bwsw_params actvcfm=0x03 noactcfm=0x06\n"
+ " noactincr=0x05 psense=2000\n"
+ " rxcrsthresh=0x20 secdurlim=30 \n"
+ "\t To reset to default value give val 0\n"
+ "\t Example : wl dyn_bwsw_params rxcrsthresh=0\n" },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_prot_obss_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register prot_obss commands */
+ wl_module_cmds_register(wl_prot_obss_cmds);
+}
+
+#if defined(BCMDBG) || defined(BCMDBG_DUMP)
+static int
+wl_ccastats(void *wl, cmd_t *cmd, char **argv)
+{
+ cca_stats_n_flags *results;
+ int err = 0;
+ int msr_time;
+ uint8 option = 0;
+ cca_msrmnt_query req;
+ char *ptr;
+
+ /* skip the command name */
+ argv++;
+
+ /* only switch -d for now */
+ if (*argv != NULL && !strcmp(*argv, "-d")) {
+ argv++;
+ if (*argv == NULL || (msr_time = htod32(atoi(*argv))) <= 0) {
+ printf("enter correct duration\n");
+ return 0;
+ }
+ req.msrmnt_query = 0;
+ req.time_req = msr_time;
+
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, &req, sizeof(req),
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ return err;
+ }
+
+ printf("Measuring %d ms ...\n", msr_time);
+ } else {
+ if (*argv != NULL && !strcmp(*argv, "-o")) {
+ argv++;
+ if (*argv != NULL) {
+ option = (uint8)htod32(atoi(*argv));
+ }
+ }
+
+ req.msrmnt_query = 1;
+ req.time_req = 0;
+ req.report_opt = option;
+
+ // retrieving the results
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, &req, sizeof(req),
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ return err;
+ }
+
+ results = (cca_stats_n_flags *)buf;
+ ptr = results->buf;
+
+ fputs(ptr, stdout);
+ }
+
+ return err;
+}
+#endif
+
+/* static function for iovar dyn_bwsw_params */
+static INLINE void
+dynbwsw_config_params(uint32 mask, uint32 *cfg_flag,
+ uint32 *rst_flag, uint val)
+{
+ (!val) ? (*rst_flag = (*rst_flag | mask)) : (*cfg_flag = (*cfg_flag | mask));
+}
+
+/* Given an argument String, Set/Get the dynamic bandswitch parameters */
+static int
+wl_dyn_bwsw_params(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ uint val;
+ void *ptr;
+ obss_config_params_t *params;
+ wlc_obss_dynbwsw_config_t *config_params;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) { /* write dyn_bwsw parameters */
+ params = (obss_config_params_t *)malloc(sizeof(obss_config_params_t));
+
+ if (params == NULL) {
+ printf("memory alloc failure\n");
+ return BCME_NOMEM;
+ }
+
+ config_params = ¶ms->config_params;
+ params->reset_mask = 0x0000;
+ params->config_mask = 0x0000;
+ params->version = WL_PROT_OBSS_CONFIG_PARAMS_VERSION;
+
+ if (find_pattern(argv, "actvcfm", &val)) {
+ dynbwsw_config_params(WL_OBSS_DYN_BWSW_FLAG_ACTIVITY_PERIOD,
+ ¶ms->config_mask, ¶ms->reset_mask, val);
+ config_params->obss_bwsw_activity_cfm_count_cfg =
+ val;
+ }
+
+ if (find_pattern(argv, "noactcfm", &val)) {
+ dynbwsw_config_params(WL_OBSS_DYN_BWSW_FLAG_NOACTIVITY_PERIOD,
+ ¶ms->config_mask, ¶ms->reset_mask, val);
+
+ config_params->obss_bwsw_no_activity_cfm_count_cfg =
+ val;
+ }
+ if (find_pattern(argv, "noactincr", &val)) {
+ dynbwsw_config_params(WL_OBSS_DYN_BWSW_FLAG_NOACTIVITY_INCR_PERIOD,
+ ¶ms->config_mask, ¶ms->reset_mask, val);
+ config_params->obss_bwsw_no_activity_cfm_count_incr_cfg =
+ val;
+ }
+
+ if (find_pattern(argv, "psense", &val)) {
+ dynbwsw_config_params(WL_OBSS_DYN_BWSW_FLAG_PSEUDO_SENSE_PERIOD,
+ ¶ms->config_mask, ¶ms->reset_mask, val);
+ config_params->obss_bwsw_pseudo_sense_count_cfg = val;
+ }
+
+ if (find_pattern(argv, "rxcrsthresh", &val)) {
+ dynbwsw_config_params(WL_OBSS_DYN_BWSW_FLAG_RX_CRS_PERIOD,
+ ¶ms->config_mask, ¶ms->reset_mask, val);
+ config_params->obss_bwsw_rx_crs_threshold_cfg = val;
+ }
+ if (find_pattern(argv, "secdurlim", &val)) {
+ dynbwsw_config_params(WL_OBSS_DYN_BWSW_FLAG_DUR_THRESHOLD,
+ ¶ms->config_mask, ¶ms->reset_mask, val);
+ config_params->obss_bwsw_dur_thres = val;
+ }
+ if (find_pattern(argv, "txopthresh", &val)) {
+ dynbwsw_config_params(WL_OBSS_DYN_BWSW_FLAG_TXOP_PERIOD,
+ ¶ms->config_mask, ¶ms->reset_mask, val);
+ config_params->obss_bwsw_txop_threshold_cfg = val;
+ }
+ if ((err = wlu_var_setbuf(wl, "dyn_bwsw_params", params,
+ sizeof(obss_config_params_t)) < 0)) {
+ printf("wl_dyn_bwsw_params: fail to set %d\n", err);
+ }
+ config_params = NULL;
+ free(params);
+ } else {
+ if ((err = wlu_var_getbuf(wl, "dyn_bwsw_params", NULL, 0, &ptr) < 0)) {
+ printf("wl_dyn_bwsw_params: fail to get params\n");
+ return err;
+ }
+ params = (obss_config_params_t *)ptr;
+ config_params = ¶ms->config_params;
+
+ printf("Version=%d\n", params->version);
+ printf("actvcfm=%d\n", config_params->obss_bwsw_activity_cfm_count_cfg);
+ printf("noactcfm=%d\n",
+ config_params->obss_bwsw_no_activity_cfm_count_cfg);
+ printf("noactincr=%d\n",
+ config_params->obss_bwsw_no_activity_cfm_count_incr_cfg);
+ printf("psense=%d\n", config_params->obss_bwsw_pseudo_sense_count_cfg);
+ printf("rxcrsthresh=%d\n", config_params->obss_bwsw_rx_crs_threshold_cfg);
+ printf("secdurlim=%d\n", config_params->obss_bwsw_dur_thres);
+ printf("txopthresh=%d\n", config_params->obss_bwsw_txop_threshold_cfg);
+ }
+
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_proxd.c b/wl/src/wl/exe/wluc_proxd.c
new file mode 100644
index 0000000..ab03cb1
--- /dev/null
+++ b/wl/src/wl/exe/wluc_proxd.c
@@ -0,0 +1,6356 @@
+/*
+ * wl proxd command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_proxd.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifdef WIN32
+#define bzero(b, len) memset((b), 0, (len))
+#endif
+
+#ifdef LINUX
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* LINUX */
+
+#include <miniopt.h>
+#include <errno.h>
+
+static cmd_func_t wl_proxd;
+static cmd_func_t wl_proxd_tune;
+static cmd_func_t wl_proxd_collect;
+static cmd_func_t wl_proxd_params;
+static cmd_func_t wl_proxd_status;
+static cmd_func_t wl_proxd_payload;
+#if defined(linux)
+static cmd_func_t wl_proxd_event_check;
+#endif /* linux */
+static cmd_func_t wl_proxd_report;
+#if defined(WL_NAN)
+static cmd_func_t wl_nan_ranging_config;
+static cmd_func_t wl_nan_ranging_start;
+static cmd_func_t wl_nan_ranging_results_host;
+#endif /* WL_NAN */
+#define WL_PROXD_PAYLOAD_LEN 1026
+#define TOF_DEFAULT_FTMCNT_SEQ 3
+
+#define PROXD_PARAMS_USAGE \
+"\tUsage: wl proxd_params method [-c channel] [-i interval] [-d duration] [-s rssi_thresh]" \
+" [-p tx_power] [-r tx_rate] [-t timeout] [-m maxconvergetime] [-g <xx:xx:xx:xx:xx:xx>]" \
+" [-y retrycnt]\n\n" \
+"\tMandatory args:\n" \
+"\t\tmethod: == 1 (RSSI) or == 2 (TOF) methods are supported) \n\n" \
+"\tOptional method specific args - for method 1: \n" \
+"\t\t-c chanspec : (all methods) channel to use for Proximity Detection\n" \
+"\t\t : e.g: 161/80, if [/BW] omitted, driver will assume 20Mhz by default\n" \
+"\t\t-i interval : (RSSI method) interval between neighbor finding attempts (in TU)\n" \
+"\t\t : (Once associated as STA mode, this value is ignored and\n" \
+"\t\t : the interval follows DTIM)\n" \
+"\t\t-d duration : (RSSI method) duration of neighbor finding attempts (in ms)\n" \
+"\t\t : == dwelling time on home channel specificed by -c channel\n" \
+"\t\t-s rssi_thresh : RSSI threshold for Proximity Detection criteria (in dBm)\n" \
+"\t\t : (-99 to -1)\n" \
+"\t\t-p tx_power : (RSSI method) tx power of Proximity Detection frames (in dBm)\n" \
+"\t\t-r tx_rate : (all methods) tx rate of Proximity Detection frames (in Mbps)\n" \
+"\t\t : (TOF) tx_rate format is {R|{hM|vM[xS]}[s][l][g]}[eT][bB]\n" \
+"\t\t : R - legacy rate, hM - HT MCS index[0-23], " \
+"vMxS - VHT MCS index[0-9] and Nss[1-8]\n" \
+"\t\t : s - Use STBC expansion, l - Use LDPC encoding, " \
+"g - SGI, Short Guard Interval\n" \
+"\t\t : eT - Tx expansion, number of tx chains[0-3], " \
+"bB - tx bandwidth, MHz: 20, 40, 80\n" \
+"\t\t-t timeout : (all methods) state machine receive timeout of Proximity Detection " \
+"frames (in ms)\n" \
+"\t\t-m maxconverge : (RSSI method) device stays up for a whole interval to detect the peer\n" \
+"\t\t : when no peer found after max converge time (in ms)\n\n" \
+"\t\t-g tgt_mac : (TOF) proximity target mac address for a method \n" \
+"\t\t-f ftm_cnt : (TOF) number of ftm frames requested by initiator from target \n" \
+"\t\t-y retry_cnt : (TOF) number of retransmit attempts for FTM frames \n" \
+"\tExample: wl proxd_params 1 -c 36 -i 100 -d 10 -s -40 -p 12 -r 6 -t 20 -m 1000\n" \
+"\tExample: wl proxd_params 1 -s -55\n" \
+"\tExample: wl proxd_params 2 -c 11 -f 10 -g 00:90:4c:a5:01:32 -r v0"
+
+#define PROXD_TUNE_USAGE \
+"\tUsage: wl proxd_tune method [operations]\n\n" \
+"\tMandatory args:\n" \
+"\t\tmethod: == 2 (TOF) methods are supported \n\n" \
+"\tOperations:\n" \
+"\t\t-k K factor : hardware dependant RTD delay adjustment factor \n" \
+"\t\t-b vhtack : 0:disable VHT ACK, 1:enable VHT ACK\n" \
+"\t\t-n minDT : min time difference of T1 and T4 or T2 and T3 \n" \
+"\t\t-x maxDT : max time difference of T1 and T4 or T2 and T3 \n" \
+"\t\t-t total_frmcnt : total count limit of measurement frames transmitted \n" \
+"\t\t-N threshold_log2 : log2 number of simple threshold crossing \n" \
+"\t\t-S threshold_scale: scale number of simple threshold crossing \n" \
+"\t\t-F ftm_cnt : number of measurement frames requested by initiator \n" \
+"\t\t-r rsv_media_value: reserve media duration value for TOF \n" \
+"\t\t-f flags : TOF state machine control flags\n" \
+"\t\t-A timestamp_adj : enable/disable sw/hw/seq assisted timestamp adjustment, " \
+"the data format is s[0|1]h[0|1]r[0|1] \n" \
+"\t\t-W window_adjust : set search window length and offset, " \
+"the data format is bBlLoO, B is bandwidth \n" \
+"\t\t : with value 20, 40 or 80, L is window length, O is offset"
+
+static cmd_t wl_proxd_cmds[] = {
+ { "proxd", wl_proxd, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/Disable Proximity Detection\n"
+ "\t0 : disable\n"
+ "\t1 [initiator|target|neutral] [u/r]: enable with the specified mode and wakeup"
+ " mechanism\n"
+ "\tftm [<session-id>] <cmd> [<param-name><param-value>...]:"
+ " enable FTM, type 'wl proxd -h ftm' for more information\n\n"
+ "\tExample: wl proxd 1 initiator"},
+ { "proxd_collect", wl_proxd_collect, WLC_GET_VAR, WLC_SET_VAR,
+ "collect the debugging informations of Proximity Detection \n\n"
+ "Optional parameters is:\n"
+ "\tenable to enable the proxd collection.\n"
+ "\tdisable to disable the proxd collection.\n"
+ "\t-l, dump local collect data and request load remote AP collect data.\n"
+ "\t-r, dump remote collect data or request load remote AP collect data.\n"
+ "\t-f File name to dump the sample buffer (default \"proxd_collect.dat\")\n"},
+ { "proxd_params", wl_proxd_params, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get operational parameters for a method of Proximity Detection\n\n"
+ PROXD_PARAMS_USAGE},
+ { "proxd_tune", wl_proxd_tune, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get tune parameters for TOF method of Proximity Detection\n\n"
+ PROXD_TUNE_USAGE},
+ { "proxd_bssid", wl_iov_mac, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get BSSID to be used in proximity detection frames\n\n"
+ "\tUsage: wl proxd_bssid <xx:xx:xx:xx:xx:xx>"},
+ { "proxd_mcastaddr", wl_iov_mac, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get Multicast MAC address of Proximity Detection Frames\n\n"
+ "\tUsage: wl proxd_mcastaddr <xx:xx:xx:xx:xx:xx>"},
+ { "proxd_find", wl_var_void, -1, WLC_SET_VAR,
+ "Start Proximity Detection" },
+ { "proxd_stop", wl_var_void, -1, WLC_SET_VAR,
+ "Stop Proximity Detection" },
+ { "proxd_status", wl_proxd_status, WLC_GET_VAR, -1,
+ "Get status of Proximity Detection" },
+ { "proxd_monitor", wl_iov_mac, -1, WLC_SET_VAR,
+ "Monitor detected peer status in proximity\n\n"
+ "\tUsage: wl proxd_monitor <xx:xx:xx:xx:xx:xx>"},
+ { "proxd_payload", wl_proxd_payload, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set payload content transferred between the proximity detected peers\n\n"
+ "\tUsage: wl proxd_payload [len hexstring]"},
+ { "proxd_report", wl_proxd_report, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set report distance results list\n\n"
+ "\tUsage: wl proxd_report [mac address list]"},
+#if defined(WL_NAN)
+ {"proxd_nancfg", wl_nan_ranging_config, -1, -1,
+ "Get/Set \"proxd_nancfg\" params .\n"
+ "\tUsage: wl proxd_nancfg <chanspec> <start_timeslot> <duration> [<allow_mac> [flag]]\n"},
+ {"proxd_nanfind", wl_nan_ranging_start, -1, -1,
+ "Send specified \"proxd_nanfind \" params .\n"
+ "\tUsage: wl proxd_nanfind <num_dws> [<chanspec> <peer addr> <bitmap> "
+ "<count> <retry> <flag>]\n"
+ "\t\t for each peer, add the [<chanspec> <peer addr> <bitmap> <count> <retry> <flag>]\n"},
+ {"proxd_nanstatus", wl_nan_ranging_results_host, WLC_GET_VAR, -1,
+ "Return host initiated ranging results.\n"},
+ {"proxd_nanpeer", wl_nan_ranging_results_host, WLC_GET_VAR, -1,
+ "Return peer initiated ranging results.\n"},
+#endif /* WL_NAN */
+#if defined(linux)
+ { "proxd_event_check", wl_proxd_event_check, -1, -1,
+ "Listen and print Location Based Service events\n"
+ "\tproxd_event_check syntax is: proxd_event_check ifname"},
+#endif /* linux */
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/*
+* for FTM
+*/
+
+static int wl_proxd_cmd_method_handler(void *wl, cmd_t *cmd, char **argv);
+static int ftm_handle_help(char **argv);
+#if defined(linux)
+static int ftm_event_check(bcm_event_t *p_bcm_event);
+#endif
+static void ftm_display_config_help();
+static void ftm_display_config_options_help();
+static void ftm_display_config_avail_help();
+static void ftm_unpack_and_display_session_flags(const uint8 *p_data, uint16 tlvid);
+static void ftm_unpack_and_display_config_flags(const uint8 *p_data, uint16 tlvid);
+static int proxd_tune_display(wl_proxd_params_tof_tune_t *tof_tune, uint16 len);
+
+/*
+*for debug: define the flag WL_FTM_DEBUG to enable debug log for FTM
+*/
+/* #define WL_FTM_DEBUG */
+#ifdef WL_FTM_DEBUG
+static void ftm_format_event_mask(wl_proxd_event_type_t event, char *p_strbuf, int bufsize);
+#endif /* WL_FTM_DEBUG */
+
+/* module initialization */
+void
+wluc_proxd_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register proxd commands */
+ wl_module_cmds_register(wl_proxd_cmds);
+}
+
+static int
+wl_proxd(void *wl, cmd_t *cmd, char **argv)
+{
+ uint16 var[2], *reply;
+ uint16 method = 0, role = 0;
+ void *ptr;
+ int ret;
+
+ /* skip the command name and check if NULL */
+ if (!*++argv) {
+ /* Get */
+ ret = wlu_var_getbuf(wl, cmd->name, &var, sizeof(var), &ptr);
+ if (ret != BCME_OK) {
+ return ret;
+ }
+
+ reply = (uint16 *)ptr;
+
+ method = dtoh16(reply[0]);
+
+ printf("%d\n", method);
+
+ if (method > 0) {
+ char c = 'u';
+ role = dtoh16(reply[1]);
+ if (role & WL_PROXD_RANDOM_WAKEUP) {
+ c = 'r';
+ role &= ~WL_PROXD_RANDOM_WAKEUP;
+ }
+ if (role == WL_PROXD_MODE_INITIATOR)
+ printf("%s %c\n", "initiator", c);
+ else if (role == WL_PROXD_MODE_TARGET)
+ printf("%s %c\n", "target", c);
+ else if (role == WL_PROXD_MODE_NEUTRAL)
+ printf("%s %c\n", "neutral", c);
+ }
+ } else {
+ /* Set */
+ if (!isdigit((int)*argv[0]))
+ return wl_proxd_cmd_method_handler(wl, cmd, argv);
+
+ /* parse method and role */
+ method = (uint16)atoi(argv[0]);
+ if (method > 0) {
+ if (!argv[1]) {
+ /* Default when it is not specified */
+ role = WL_PROXD_MODE_NEUTRAL | WL_PROXD_RANDOM_WAKEUP;
+ }
+ else {
+ if (stricmp(argv[1], "initiator") == 0)
+ role = WL_PROXD_MODE_INITIATOR;
+ else if (stricmp(argv[1], "target") == 0)
+ role = WL_PROXD_MODE_TARGET;
+ else if (stricmp(argv[1], "neutral") == 0) {
+ role = WL_PROXD_MODE_NEUTRAL;
+ role |= WL_PROXD_RANDOM_WAKEUP;
+ }
+ else
+ return BCME_USAGE_ERROR;
+
+ if (argv[2]) {
+ if (*argv[2] == 'R' || *argv[2] == 'r')
+ role |= WL_PROXD_RANDOM_WAKEUP;
+ else if (*argv[2] == 'u' || *argv[2] == 'U')
+ role &= ~WL_PROXD_RANDOM_WAKEUP;
+ }
+ }
+ }
+
+ var[0] = htod16(method);
+ var[1] = htod16(role);
+
+ ret = wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
+ }
+
+ return ret;
+}
+
+static int
+wl_proxd_get_debug_data(void *wl, cmd_t *cmd, int index)
+{
+ int ret;
+ void *buff;
+ wl_proxd_collect_query_t query;
+ wl_proxd_debug_data_t *replay;
+
+ bzero(&query, sizeof(query));
+ query.method = htol32(PROXD_TOF_METHOD);
+ query.request = PROXD_COLLECT_QUERY_DEBUG;
+ query.index = htol16(index);
+
+ ret = wlu_var_getbuf(wl, cmd->name, &query, sizeof(query), &buff);
+ if (ret != BCME_OK)
+ return ret;
+
+ replay = (wl_proxd_debug_data_t *)buff;
+
+ if (index == 0)
+ printf("\n/* Debug Informations */\n");
+
+ printf("%s[%u,%u]: type %u action(%u,%u) token(%u, %u)\n",
+ replay->received? "RX" : "TX",
+ replay->count, replay->stage,
+ replay->paket_type,
+ replay->category, replay->action,
+ replay->token, replay->follow_token);
+
+ if (replay->tof_cmd == 0 && replay->tof_rsp == 0) {
+ printf("\n");
+ return BCME_OK;
+ }
+
+ printf("Index=%d\n", ltoh16(replay->index));
+ printf("M_TOF_CMD=0x%04x\tM_TOF_RSP=0x%04x\tM_TOF_ID=0x%04x\n",
+ ltoh16(replay->tof_cmd), ltoh16(replay->tof_rsp), ltoh16(replay->tof_id));
+ printf("M_TOF_AVB_RX_L=0x%04x\tM_TOF_AVB_RX_H=0x%04x\t",
+ ltoh16(replay->tof_avb_rxl), ltoh16(replay->tof_avb_rxh));
+ printf("M_TOF_AVB_TX_L=0x%04x\tM_TOF_AVB_TX_H=0x%04x\n",
+ ltoh16(replay->tof_avb_txl), ltoh16(replay->tof_avb_txh));
+ printf("M_TOF_STATUS0=0x%04x\tM_TOF_STATUS2=0x%04x\t",
+ ltoh16(replay->tof_status0), ltoh16(replay->tof_status2));
+ printf("M_TOF_CHNSM_0=0x%04x\tM_TOF_CHNSM_1=0x%04x\n",
+ ltoh16(replay->tof_chsm0), 0);
+ printf("M_TOF_PHYCTL0=0x%04x\tM_TOF_PHYCTL1=0x%04x\tM_TOF_PHYCTL2=0x%04x\n",
+ ltoh16(replay->tof_phyctl0), ltoh16(replay->tof_phyctl1),
+ ltoh16(replay->tof_phyctl2));
+ printf("M_TOF_LSIG=0x%04x\tM_TOF_VHTA0=0x%04x\tM_TOF_VHTA1=0x%04x\n",
+ ltoh16(replay->tof_lsig), ltoh16(replay->tof_vhta0), ltoh16(replay->tof_vhta1));
+ printf("M_TOF_VHTA2=0x%04x\tM_TOF_VHTB0=0x%04x\tM_TOF_VHTB1=0x%04x\n",
+ ltoh16(replay->tof_vhta2), ltoh16(replay->tof_vhtb0), ltoh16(replay->tof_vhtb1));
+ printf("M_TOF_AMPDU_CTL=0x%04x\tM_TOF_AMPDU_DLIM=0x%04x\tM_TOF_AMPDU_LEN=0x%04x\n\n",
+ ltoh16(replay->tof_apmductl), ltoh16(replay->tof_apmdudlim),
+ ltoh16(replay->tof_apmdulen));
+
+ return BCME_OK;
+}
+
+static void
+wlc_proxd_collec_header_dump(wl_proxd_collect_header_t *pHdr)
+{
+ int i;
+
+ printf("total_frames %lu\n", (unsigned long)ltoh16(pHdr->total_frames));
+ printf("nfft %lu\n", (unsigned long)ltoh16(pHdr->nfft));
+ printf("bandwidth %lu\n", (unsigned long)ltoh16(pHdr->bandwidth));
+ printf("channel %lu\n", (unsigned long)ltoh16(pHdr->channel));
+ printf("chanspec %lu\n", (unsigned long)ltoh32(pHdr->chanspec));
+ printf("fpfactor %lu\n", (unsigned long)ltoh32(pHdr->fpfactor));
+ printf("fpfactor_shift %lu\n", (unsigned long)ltoh16(pHdr->fpfactor_shift));
+ printf("distance %li\n", (long)ltoh32(pHdr->distance));
+ printf("meanrtt %lu\n", (unsigned long)ltoh32(pHdr->meanrtt));
+ printf("modertt %lu\n", (unsigned long)ltoh32(pHdr->modertt));
+ printf("medianrtt %lu\n", (unsigned long)ltoh32(pHdr->medianrtt));
+ printf("sdrtt %lu\n", (unsigned long)ltoh32(pHdr->sdrtt));
+ printf("clkdivisor %lu\n", (unsigned long)ltoh32(pHdr->clkdivisor));
+ printf("chipnum %lu\n", (unsigned long)ltoh16(pHdr->chipnum));
+ printf("chiprev %lu\n", (unsigned long)pHdr->chiprev);
+ printf("phyver %lu\n", (unsigned long)pHdr->phyver);
+ printf("localMacAddr %s\n", wl_ether_etoa(&(pHdr->localMacAddr)));
+ printf("remoteMacAddr %s\n", wl_ether_etoa(&(pHdr->remoteMacAddr)));
+ printf("params_Ki %lu\n", (unsigned long)ltoh32(pHdr->params.Ki));
+ printf("params_Kt %lu\n", (unsigned long)ltoh32(pHdr->params.Kt));
+ printf("params_vhtack %li\n", (long)ltoh16(pHdr->params.vhtack));
+ printf("params_N_log2 %d\n", TOF_BW_NUM);
+ for (i = 0; i < TOF_BW_NUM; i++) {
+ printf("%li\n", (long)ltoh16(pHdr->params.N_log2[i]));
+ }
+ printf("params_N_scale %d\n", TOF_BW_NUM);
+ for (i = 0; i < TOF_BW_NUM; i++) {
+ printf("%li\n", (long)ltoh16(pHdr->params.N_scale[i]));
+ }
+ printf("params_sw_adj %lu\n", (unsigned long)pHdr->params.sw_adj);
+ printf("params_hw_adj %lu\n", (unsigned long)pHdr->params.hw_adj);
+ printf("params_seq_en %lu\n", (unsigned long)pHdr->params.seq_en);
+ printf("params_core %lu\n", (unsigned long)pHdr->params.core);
+ printf("params_N_log2_seq 2\n");
+ for (i = 0; i < 2; i++) {
+ printf("%li\n", (long)ltoh16(pHdr->params.N_log2[i + TOF_BW_NUM]));
+ }
+ printf("params_N_scale_seq 2\n");
+ for (i = 0; i < 2; i++) {
+ printf("%li\n", (long)ltoh16(pHdr->params.N_scale[i + TOF_BW_NUM]));
+ }
+ printf("params_w_offset %d\n", TOF_BW_NUM);
+ for (i = 0; i < TOF_BW_NUM; i++) {
+ printf("%li\n", (long)ltoh16(pHdr->params.w_offset[i]));
+ };
+ printf("params_w_len %d\n", TOF_BW_NUM);
+ for (i = 0; i < TOF_BW_NUM; i++) {
+ printf("%li\n", (long)ltoh16(pHdr->params.w_len[i]));
+ };
+ printf("params_maxDT %li\n", (long)ltoh32(pHdr->params.maxDT));
+ printf("params_minDT %li\n", (long)ltoh32(pHdr->params.minDT));
+ printf("params_totalfrmcnt %lu\n", (unsigned long)pHdr->params.totalfrmcnt);
+ printf("params_rsv_media %lu\n", (unsigned long)ltoh16(pHdr->params.rsv_media));
+}
+
+static int wlc_proxd_collect_data_check_ver_len(uint16 expected_ver,
+ uint16 ver, uint16 len)
+{
+ int ret = BCME_OK;
+
+ switch (expected_ver) {
+ case WL_PROXD_COLLECT_DATA_VERSION_1:
+ /* v1 does not haver version and length fields */
+ ret = BCME_OK;
+ break;
+ case WL_PROXD_COLLECT_DATA_VERSION_2:
+ if ((ver != expected_ver) ||
+ (len != sizeof(wl_proxd_collect_data_t_v2) -
+ OFFSETOF(wl_proxd_collect_data_t_v2, len))) {
+ ret = BCME_VERSION;
+ }
+ break;
+ default:
+ ret = BCME_UNSUPPORTED;
+ }
+
+ return ret;
+}
+static int wlc_proxd_collec_data_dump(void *replay, FILE *fp,
+ wl_proxd_rssi_bias_avg_t *rssi_bias_avg, uint16 version)
+{
+ int i, n, nbytes;
+ int ret = BCME_OK;
+ wl_proxd_collect_data_t_v1 *replay_v1 = NULL;
+ wl_proxd_collect_data_t_v2 *replay_v2 = NULL;
+ wl_proxd_collect_info_t *info = NULL;
+ uint32 *H = NULL;
+ uint32 *chan = NULL;
+ uint8 *ri_rr = NULL;
+ int nfft = 0;
+#ifdef RSSI_REFINE
+ int rssi_dec = 0;
+#else
+ /* rssi_bias_avg is unused under !RSSI_REFINE. */
+ /* Macro to prevent compiler warning under some platforms */
+ UNUSED_PARAMETER(rssi_bias_avg);
+#endif
+
+ BCM_REFERENCE(H);
+ BCM_REFERENCE(chan);
+ BCM_REFERENCE(ri_rr);
+
+ /* Depending on version add the corresponding case and pointers to point
+ * to the correct member for use in the function
+ */
+ switch (version) {
+ case WL_PROXD_COLLECT_DATA_VERSION_1:
+ replay_v1 = (wl_proxd_collect_data_t_v1 *)replay;
+ info = &replay_v1->info;
+ H = replay_v1->H;
+ ri_rr = replay_v1->ri_rr;
+ nbytes = sizeof(wl_proxd_collect_data_t_v1)
+ - (K_TOF_COLLECT_H_SIZE_20MHZ - nfft) * sizeof(uint32);
+ break;
+ case WL_PROXD_COLLECT_DATA_VERSION_2:
+ replay_v2 = (wl_proxd_collect_data_t_v2 *)replay;
+ ret = wlc_proxd_collect_data_check_ver_len(version, replay_v2->version,
+ replay_v2->len);
+ if (ret != BCME_OK) {
+ break;
+ }
+ info = &replay_v2->info;
+ H = replay_v2->H;
+ ri_rr = replay_v2->ri_rr;
+ chan = replay_v2->chan;
+ nbytes = sizeof(wl_proxd_collect_data_t_v2)
+ - (K_TOF_COLLECT_H_SIZE_20MHZ - nfft) * sizeof(uint32);
+ break;
+ default:
+ ret = BCME_VERSION;
+ break;
+ }
+ if (ret != BCME_OK) {
+ goto done;
+ }
+
+ if (info) {
+ nfft = (int)ltoh16(info->nfft);
+#ifdef RSSI_REFINE
+ if (nfft > 0) {
+ printf("}\nImpulse Response = {\n");
+ for (i = 0; i < nfft; i++) {
+ printf("%010d ", ltoh32(info->rssi_bias.imp_resp[i]));
+ if ((i & 7) == 7)
+ printf("\n");
+ }
+ printf("RSSI_VERSION = %d\n", ltoh32(info->rssi_bias.version));
+ printf("PEAK_OFFSET = %d\n", ltoh32(info->rssi_bias.peak_offset));
+ rssi_bias_avg->avg_peak_offset += ltoh32(info->rssi_bias.peak_offset);
+ printf("PEAK_TO_AVG = %d", ltoh32(info->rssi_bias.bias));
+ rssi_bias_avg->avg_bias += ltoh32(info->rssi_bias.bias);
+ printf("\n");
+ for (i = 0; i < 10; i++) {
+ printf("THRESHOLD_%d = %u", i,
+ ltoh32(info->rssi_bias.threshold[i]));
+ if ((i+1) % 5)
+ printf(", ");
+ else
+ printf("\n");
+ rssi_bias_avg->avg_threshold[i] +=
+ ltoh32(info->rssi_bias.threshold[i]);
+ }
+ printf("SCALAR = %d", info->rssi_bias.threshold[10]);
+ }
+
+ /* convert tof_status2 from hex to dec */
+ rssi_dec = info->tof_rssi;
+ printf("\nRSSI10 = %d", rssi_dec);
+ rssi_bias_avg->avg_rssi += rssi_dec;
+ printf("\n\n");
+#endif /* RSSI_REFINE */
+
+ /* printing the info portion */
+ printf("info_type %lu\n", (unsigned long)ltoh16(info->type));
+ printf("info_index %lu\n", (unsigned long)ltoh16(info->index));
+ printf("info_tof_cmd %lu\n", (unsigned long)ltoh16(info->tof_cmd));
+ printf("info_tof_rsp %lu\n", (unsigned long)ltoh16(info->tof_rsp));
+ printf("info_tof_avb_rxl %lu\n", (unsigned long)ltoh16(info->tof_avb_rxl));
+ printf("info_tof_avb_rxh %lu\n", (unsigned long)ltoh16(info->tof_avb_rxh));
+ printf("info_tof_avb_txl %lu\n", (unsigned long)ltoh16(info->tof_avb_txl));
+ printf("info_tof_avb_txh %lu\n", (unsigned long)ltoh16(info->tof_avb_txh));
+ printf("info_tof_id %lu\n", (unsigned long)ltoh16(info->tof_id));
+ printf("info_tof_frame_type %lu\n", (unsigned long)info->tof_frame_type);
+ printf("info_tof_frame_bw %lu\n", (unsigned long)info->tof_frame_bw);
+ printf("info_tof_rssi %li\n", (long)info->tof_rssi);
+ printf("info_tof_cfo %li\n", (long)ltoh32(info->tof_cfo));
+ printf("info_gd_adj_ns %li\n", (long)ltoh32(info->gd_adj_ns));
+ printf("info_gd_h_adj_ns %li\n", (long)ltoh32(info->gd_h_adj_ns));
+ printf("info_nfft %li\n", (long)ltoh16(info->nfft));
+
+ if (H) {
+ /* printing the H portion */
+ printf("H %d\n", nfft);
+ for (i = 0; i < nfft; i++) {
+ printf("%lu\n", (unsigned long)ltoh32(H[i]));
+ }
+ }
+
+ /* printing the chan and ri_rr */
+ if (info->index == 1) {
+ if (chan && version >= WL_PROXD_COLLECT_DATA_VERSION_2) {
+ n = (int)ltoh16((info->num_max_cores + 1)*
+ (K_TOF_COLLECT_CHAN_SIZE >> (2 - info->tof_frame_bw)));
+ printf("chan_est %d\n", n);
+ for (i = 0; i < n; i++) {
+ printf("%u\n", chan[i]);
+ }
+ }
+ if (ri_rr) {
+ printf("ri_rr %d\n", FTM_TPK_RI_RR_LEN);
+ for (i = 0; i < FTM_TPK_RI_RR_LEN; i++) {
+ printf("%u\n", ri_rr[i]);
+ }
+ }
+ }
+
+ ret = fwrite(replay, 1, nbytes, fp);
+ if (ret != nbytes) {
+ fprintf(stderr, "Error writing %d bytes to file, rc %d!\n",
+ nbytes, ret);
+ return BCME_ERROR;
+ }
+ }
+
+done:
+ return ret;
+}
+
+static int
+wl_proxd_get_collect_data(void *wl, cmd_t *cmd, FILE *fp, int index,
+ wl_proxd_rssi_bias_avg_t *rssi_bias_avg)
+{
+ int ret;
+ void *buff;
+ wl_proxd_collect_query_t query;
+ uint16 expected_collect_data_ver = 0;
+
+ /* check firmware version */
+ /* Select collect data structure version based on FW version.
+ * Extend here for future versions
+ */
+ if (wlc_ver_major(wl) <= 5) {
+ /* use v1 */
+ expected_collect_data_ver = WL_PROXD_COLLECT_DATA_VERSION_1;
+ } else {
+ /* use v2 */
+ expected_collect_data_ver = WL_PROXD_COLLECT_DATA_VERSION_2;
+ }
+
+ bzero(&query, sizeof(query));
+ query.method = htol32(PROXD_TOF_METHOD);
+ query.request = PROXD_COLLECT_QUERY_DATA;
+ query.index = htol16(index);
+
+ ret = wlu_var_getbuf(wl, cmd->name, &query, sizeof(query), &buff);
+ if (ret != BCME_OK)
+ return ret;
+
+ ret = wlc_proxd_collec_data_dump(buff, fp, rssi_bias_avg,
+ expected_collect_data_ver);
+ if (ret != BCME_OK) {
+ return ret;
+ }
+
+ return BCME_OK;
+}
+
+static int
+wl_proxd_collect(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ void *buff;
+ wl_proxd_collect_query_t query, *pStatus;
+ wl_proxd_collect_header_t *pHdr;
+ const char *fname = "proxd_collect.dat";
+ FILE *fp = NULL;
+ int i, collect_method, total_frames, load_request = 0, remote_request = 0;
+ char chspec_str[CHANSPEC_STR_LEN];
+ chanspec_t chanspec;
+ float d_ref = -1;
+#ifdef RSSI_REFINE
+ wl_proxd_rssi_bias_avg_t rssi_bias_avg;
+
+ bzero(&rssi_bias_avg, sizeof(rssi_bias_avg));
+#endif
+ bzero(&query, sizeof(query));
+ query.method = htol32(PROXD_TOF_METHOD);
+
+ /* Skip the command name */
+ argv++;
+ while (*argv) {
+ if (strcmp(argv[0], "disable") == 0 || *argv[0] == '0') {
+ query.request = PROXD_COLLECT_SET_STATUS;
+ query.status = 0;
+ return wlu_var_getbuf(wl, cmd->name, &query, sizeof(query), &buff);
+ }
+ collect_method = (uint16)atoi(argv[0]);
+ if (strcmp(argv[0], "enable") == 0) {
+ query.request = PROXD_COLLECT_SET_STATUS;
+ query.status = 1;
+ return wlu_var_getbuf(wl, cmd->name, &query, sizeof(query), &buff);
+ } else if (isdigit((int)*argv[0]) &&
+ ((collect_method >= WL_PROXD_COLLECT_METHOD_TYPE_DISABLE) &&
+ (collect_method <= WL_PROXD_COLLECT_METHOD_TYPE_EVENT_LOG))) {
+ query.request = PROXD_COLLECT_SET_STATUS;
+ query.status = collect_method;
+ return wlu_var_getbuf(wl, cmd->name, &query, sizeof(query), &buff);
+ }
+ if (!strcmp(argv[0], "-l")) {
+ load_request = 1;
+ argv++;
+ }
+ else if (!strcmp(argv[0], "-r")) {
+ remote_request = 1;
+ argv++;
+ }
+ else if (!strcmp(argv[0], "-f")) {
+ if (argv[1] == NULL)
+ return -1;
+ fname = argv[1];
+ argv += 2;
+ }
+ else if (!strcmp(argv[0], "-d")) {
+ if (argv[1] == NULL)
+ return -1;
+ sscanf((const char*)argv[1], "%f", &d_ref);
+ argv += 2;
+ } else
+ return -1;
+ }
+
+ query.request = PROXD_COLLECT_GET_STATUS;
+ ret = wlu_var_getbuf(wl, cmd->name, &query, sizeof(query), &buff);
+ if (ret != BCME_OK)
+ return ret;
+
+ pStatus = (wl_proxd_collect_query_t *)buff;
+ if (!pStatus->status) {
+ printf("Disable\n");
+ return BCME_OK;
+ }
+
+ if (pStatus->busy) {
+ printf("Busy\n");
+ return BCME_OK;
+ }
+
+ if ((pStatus->mode == WL_PROXD_MODE_TARGET) &&
+ (remote_request || load_request)) {
+ printf("Unsupport\n");
+ return BCME_OK;
+ }
+
+ if (remote_request && !pStatus->remote) {
+ printf("Remote data have not ready, please run this command again\n");
+ load_request = 1;
+ goto exit;
+ }
+
+ if (load_request && pStatus->remote) {
+ printf("Local data have not ready, please run command 'proxd_find' to get it\n");
+ goto exit;
+ }
+
+ query.request = PROXD_COLLECT_QUERY_HEADER;
+ ret = wlu_var_getbuf(wl, cmd->name, &query, sizeof(query), &buff);
+ if (ret != BCME_OK)
+ return ret;
+
+ pHdr = (wl_proxd_collect_header_t *)buff;
+ total_frames = (int)ltoh32(pHdr->total_frames);
+ if (!total_frames) {
+ printf("Enable\n");
+ goto exit;
+ }
+
+ chanspec = wl_chspec_from_driver(pHdr->chanspec);
+ wf_chspec_ntoa(chanspec, chspec_str);
+
+ printf("d_ref %5.1f\n", d_ref);
+ wlc_proxd_collec_header_dump(pHdr);
+
+ if ((fp = fopen(fname, "wb")) == NULL) {
+ fprintf(stderr, "Problem opening file %s\n", fname);
+ return 0;
+ }
+
+ ret = fwrite(buff, 1, sizeof(wl_proxd_collect_header_t), fp);
+ if (ret != sizeof(wl_proxd_collect_header_t)) {
+ fprintf(stderr, "Error writing to file rc %d\n", ret);
+ ret = -1;
+ goto exit;
+ }
+
+ for (i = 0; i < total_frames; i++) {
+#ifdef RSSI_REFINE
+ ret = wl_proxd_get_collect_data(wl, cmd, fp, i, &rssi_bias_avg);
+#else
+ ret = wl_proxd_get_collect_data(wl, cmd, fp, i, NULL);
+#endif
+ if (ret != BCME_OK)
+ goto exit;
+ }
+#ifdef RSSI_REFINE
+ if (total_frames > 0) {
+ printf("avg_rssi = %d avg_peak_offset = %d\n",
+ rssi_bias_avg.avg_rssi/total_frames,
+ rssi_bias_avg.avg_peak_offset/total_frames);
+ for (i = 0; i < 10; i++) {
+ printf("avg_threshold_%d = %d",
+ i, rssi_bias_avg.avg_threshold[i]/total_frames);
+ if ((i+1) % 5)
+ printf(", ");
+ else
+ printf("\n");
+ }
+ printf("avg_bias = %d\n", rssi_bias_avg.avg_bias/total_frames);
+ }
+#endif
+ for (i = 0; i < 256; i++) {
+ ret = wl_proxd_get_debug_data(wl, cmd, i);
+ if (ret != BCME_OK)
+ break;
+ }
+ if (!load_request) {
+ /* FTM remote collect done */
+ query.request = PROXD_COLLECT_DONE;
+ (void)wlu_var_getbuf(wl, cmd->name, &query, sizeof(query), &buff);
+ }
+ ret = BCME_OK;
+exit:
+ if (ret == BCME_OK && load_request) {
+ query.request = PROXD_COLLECT_REMOTE_REQUEST;
+ ret = wlu_var_getbuf(wl, cmd->name, &query, sizeof(query), &buff);
+ }
+ if (fp) fclose(fp);
+ return ret;
+}
+
+/* set measurement packet transmit rate */
+static int proxd_method_set_vht_rate(miniopt_t *mopt)
+{
+ char *startp, *endp;
+ char c;
+ bool legacy_set = FALSE, ht_set = FALSE, vht_set = FALSE;
+ int rate, mcs, Nss, tx_exp, bw, val;
+ bool stbc, ldpc, sgi;
+ uint32 rspec = 0;
+
+ /* set default values */
+ rate = 0;
+ mcs = 0;
+ Nss = 0;
+ tx_exp = 0;
+ stbc = FALSE;
+ ldpc = FALSE;
+ sgi = FALSE;
+ bw = 0;
+
+ startp = mopt->valstr;
+ endp = NULL;
+ if (*startp != 'h' && *startp != 'v') {
+ if ((rate = (int)strtol(startp, &endp, 10)) == 0)
+ return -1;
+
+ rate *= 2;
+ if (endp[0] == '.' && endp[1] == '5') {
+ rate += 1;
+ endp += 2;
+ }
+ startp = endp;
+ legacy_set = TRUE;
+ }
+
+ while (startp && ((c = *startp++) != '\0')) {
+ if (c == 'h') {
+ ht_set = TRUE;
+ mcs = (int)strtol(startp, &endp, 10);
+ if (mcs < 0 || mcs > 23) {
+ printf("HT MCS index %d out of range [0-23].\n", mcs);
+ return -1;
+ }
+ startp = endp;
+ }
+ else if (c == 'v') {
+ vht_set = TRUE;
+ mcs = (int)strtol(startp, &endp, 10);
+ if (mcs < 0 || mcs > 9) {
+ printf("HT MCS index %d out of range [0-9].\n", mcs);
+ return -1;
+ }
+ startp = endp;
+ }
+ else if (c == 'x') {
+ Nss = (int)strtol(startp, &endp, 10);
+ if (Nss < 1 || Nss > 8) {
+ printf("Nss %d out of range [1-8].\n", Nss);
+ return -1;
+ }
+ startp = endp;
+ }
+ else if (c == 'e') {
+ tx_exp = (int)strtol(startp, &endp, 10);
+ if (tx_exp < 0 || tx_exp > 3) {
+ printf("tx expansion %d out of range [0-3].\n", tx_exp);
+ return -1;
+ }
+ startp = endp;
+ }
+ else if (c == 's') {
+ stbc = TRUE;
+ continue;
+ }
+ else if (c == 'l') {
+ ldpc = TRUE;
+ continue;
+ }
+ else if (c == 'g') {
+ sgi = TRUE;
+ continue;
+ }
+ else if (c == 'b') {
+ val = (int)strtol(startp, &endp, 10);
+ if (val == 20) {
+ bw = WL_RSPEC_BW_20MHZ;
+ } else if (val == 40) {
+ bw = WL_RSPEC_BW_40MHZ;
+ } else if (val == 80) {
+ bw = WL_RSPEC_BW_80MHZ;
+ } else if (val == 160) {
+ bw = WL_RSPEC_BW_160MHZ;
+ } else {
+ printf("unexpected bandwidth specified \"%d\", "
+ "expected 20, 40, 80, or 160\n", val);
+ return -1;
+ }
+ startp = endp;
+ }
+ }
+
+ if (!legacy_set && !ht_set && !vht_set) {
+ printf("must specify one of legacy rate, HT (11n) rate hM, "
+ "or VHT (11ac) rate vM[xS]\n");
+ return -1;
+ }
+
+ if (legacy_set && (ht_set || vht_set)) {
+ printf("cannot use legacy rate and HT rate or VHT rate at the same time\n");
+ return -1;
+ }
+
+ if (ht_set && vht_set) {
+ printf("cannot use HT rate hM and HT rate vM[xS] at the same time\n");
+ return -1;
+ }
+
+ if (!vht_set && Nss != 0) {
+ printf("cannot use xS option with non VHT rate\n");
+ return -1;
+ }
+
+ if ((stbc || ldpc || sgi) && !(ht_set || vht_set)) {
+ printf("cannot use STBC/LDPC/SGI options with non HT/VHT rates\n");
+ return -1;
+ }
+
+ if (legacy_set) {
+ rspec = WL_RSPEC_ENCODE_RATE; /* 11abg */
+ rspec |= rate;
+ } else if (ht_set) {
+ rspec = WL_RSPEC_ENCODE_HT; /* 11n HT */
+ rspec |= mcs;
+ } else {
+ rspec = WL_RSPEC_ENCODE_VHT; /* 11ac VHT */
+ if (Nss == 0) {
+ Nss = 1; /* default Nss = 1 if --ss option not given */
+ }
+ rspec |= (Nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs;
+ }
+
+ /* set the other rspec fields */
+ rspec |= (tx_exp << WL_RSPEC_TXEXP_SHIFT);
+ rspec |= bw;
+ rspec |= (stbc ? WL_RSPEC_STBC : 0);
+ rspec |= (ldpc ? WL_RSPEC_LDPC : 0);
+ rspec |= (sgi ? WL_RSPEC_SGI : 0);
+
+ mopt->uval = rspec;
+
+ return 0;
+}
+
+/* proxd set params common cmdl opts */
+int proxd_method_set_common_param_from_opt(cmd_t *cmd,
+ miniopt_t *mopt, wl_proxd_params_common_t *proxd_params)
+{
+ chanspec_t chanspec;
+
+ if (mopt->opt == 'c') {
+ /* chanspec iovar uses wl_chspec32_to_driver(chanspec), why ? */
+ if ((chanspec = wf_chspec_aton(mopt->valstr)) == 0) {
+ fprintf(stderr, "%s: could not parse \"%s\" as a channel\n",
+ cmd->name, mopt->valstr);
+ return BCME_BADARG;
+ }
+
+ proxd_params->chanspec
+ = wl_chspec_to_driver(chanspec);
+
+ if (proxd_params->chanspec == INVCHANSPEC) {
+ fprintf(stderr,
+ "%s: wl_chspec_to_driver() error \"%s\" \n",
+ cmd->name, mopt->valstr);
+ return BCME_BADARG;
+ }
+ } else if (mopt->opt == 't') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a timeout\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_params->timeout = htod16(mopt->val);
+ }
+ else
+ return BCME_USAGE_ERROR;
+
+ return BCME_OK;
+}
+
+/* proxd TOF cmdl ops */
+int proxd_method_tof_set_param_from_opt(cmd_t *cmd,
+ miniopt_t *mopt, wl_proxd_params_tof_method_t *proxd_params)
+{
+ if (mopt->opt == 'g') {
+ /* this param is only valid for TOF method only */
+ struct ether_addr ea;
+
+ if (!wl_ether_atoe(mopt->valstr, &ea)) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as MAC address\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ memcpy(&proxd_params->tgt_mac, &ea, 6);
+ } else if (mopt->opt == 'f') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as FTM frame count\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_params->ftm_cnt = htod16(mopt->val);
+ } else if (mopt->opt == 'y') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as Retry Count\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_params->retry_cnt = htod16(mopt->val);
+ } else if (mopt->opt == 'r') {
+ if (!mopt->good_int) {
+ /* special case check for "-r 5.5" */
+ if (!strcmp(mopt->valstr, "5.5")) {
+ mopt->uval = 11;
+ } else if (proxd_method_set_vht_rate(mopt)) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a rate\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ } else
+ mopt->uval = mopt->uval*2;
+ proxd_params->tx_rate = htod16((mopt->uval & 0xffff));
+ proxd_params->vht_rate = htod16((mopt->uval >> 16));
+ } else
+ return BCME_USAGE_ERROR;
+
+ return BCME_OK;
+}
+
+/* RSSI method specific mdl opts */
+int proxd_method_rssi_set_param_from_opt(cmd_t *cmd,
+ miniopt_t *mopt, wl_proxd_params_rssi_method_t *proxd_params)
+{
+
+ if (mopt->opt == 'i') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an interval\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_params->interval = htod16(mopt->val);
+ } else if (mopt->opt == 'd') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a duration\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_params->duration = htod16(mopt->val);
+ } else if (mopt->opt == 'p') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a power\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_params->tx_power = htod16(mopt->val);
+ } else if (mopt->opt == 's') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a RSSI\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_params->rssi_thresh = htod16(mopt->val);
+ } else if (mopt->opt == 'm') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a maxconvergetime\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_params->maxconvergtmo = htod16(mopt->val);
+ } else if (mopt->opt == 'r') {
+ if (!mopt->good_int) {
+ /* special case check for "-r 5.5" */
+ if (!strcmp(mopt->valstr, "5.5")) {
+ mopt->val = 11;
+ } else {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a rate\n",
+ cmd->name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ } else
+ mopt->val = mopt->val*2;
+ proxd_params->tx_rate = htod16(mopt->val);
+ }
+ else
+ return BCME_USAGE_ERROR;
+
+ return BCME_OK;
+}
+
+static int
+wl_proxd_params(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_proxd_params_iovar_t proxd_params, *reply;
+ uint16 method;
+ void *ptr = NULL;
+ int ret, opt_err;
+ miniopt_t to;
+ char chspec_str[CHANSPEC_STR_LEN];
+ char rate_str[64];
+ chanspec_t chanspec;
+ uint16 interval, duration;
+ uint32 tx_rate;
+
+ /* skip the command name and check if mandatory exists */
+ if (!*++argv) {
+ fprintf(stderr, "missing mandatory parameter \'method\'\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* parse method */
+ method = (uint16)atoi(argv[0]);
+ if (method == 0) {
+ fprintf(stderr, "invalid parameter \'method\'\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ bzero(&proxd_params, sizeof(proxd_params));
+
+ /* set method to get/set */
+ proxd_params.method = htod16(method);
+
+ ret = wlu_var_getbuf_sm(wl, cmd->name, &proxd_params, sizeof(proxd_params), &ptr);
+ if (ret != BCME_OK) {
+ return ret;
+ }
+
+ if (!*++argv) {
+ /* get */
+ /* display proxd_params got */
+ reply = (wl_proxd_params_iovar_t *)ptr;
+
+ printf("bf proxd_params.method:%d\n", proxd_params.method);
+ switch (proxd_params.method) {
+
+ case PROXD_RSSI_METHOD:
+
+ chanspec = wl_chspec_from_driver(reply->u.rssi_params.chanspec);
+ tx_rate = dtoh16(reply->u.rssi_params.tx_rate);
+ wf_chspec_ntoa(chanspec, chspec_str);
+
+ printf("channel=%s\n", chspec_str);
+ printf("interval=%d TU\n", dtoh16(reply->u.rssi_params.interval));
+ printf("duration=%d ms\n", dtoh16(reply->u.rssi_params.duration));
+ printf("rssi_thresh=%d dBm\n",
+ (int16)dtoh16(reply->u.rssi_params.rssi_thresh));
+ printf("maxconvergetime=%d ms\n\n",
+ dtoh16(reply->u.rssi_params.maxconvergtmo));
+ printf("tx_power=%d dBm\n",
+ (int16)dtoh16(reply->u.rssi_params.tx_power));
+ printf("tx_rate=%d%s Mbps\n",
+ (tx_rate / 2), (tx_rate & 1) ? ".5" : "");
+ printf("timeout=%d ms\n", dtoh16(reply->u.rssi_params.timeout));
+ break;
+
+ case PROXD_TOF_METHOD:
+
+ chanspec = wl_chspec_from_driver(reply->u.tof_params.chanspec);
+ tx_rate = dtoh16(reply->u.tof_params.tx_rate) |
+ (dtoh16(reply->u.tof_params.vht_rate) << 16);
+ wf_chspec_ntoa(chanspec, chspec_str);
+ wl_rate_print(rate_str, tx_rate);
+
+ printf("tgt_mac=%s \n",
+ wl_ether_etoa(&reply->u.tof_params.tgt_mac));
+ printf("ftm_cnt= %d\n", dtoh16(reply->u.tof_params.ftm_cnt));
+ printf("channel=%s (0x%04x)\n", chspec_str, chanspec);
+ printf("tx_rate=%s (0x%08x)\n", rate_str, tx_rate);
+ printf("timeout=%d ms\n",
+ dtoh16(reply->u.tof_params.timeout));
+ printf("retry_cnt=%d \n", dtoh16(reply->u.tof_params.retry_cnt));
+ break;
+
+ default:
+ fprintf(stderr,
+ "%s: ERROR undefined method \n", cmd->name);
+ return BCME_BADARG;
+ }
+ } else { /* set */
+ memcpy((void *)&proxd_params, (void *)ptr, sizeof(proxd_params));
+ proxd_params.method = method;
+
+ /* set */
+ miniopt_init(&to, cmd->name, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ int com_res, meth_res;
+
+ if (opt_err == 1) {
+ return BCME_USAGE_ERROR;
+ }
+ argv += to.consumed;
+
+ /* process cmd opts common for all methods */
+ com_res = proxd_method_set_common_param_from_opt(cmd,
+ &to, &proxd_params.u.cmn_params);
+
+ /* method specific opts */
+ switch (method) {
+ case PROXD_RSSI_METHOD:
+ meth_res = proxd_method_rssi_set_param_from_opt(cmd,
+ &to, &proxd_params.u.rssi_params);
+ break;
+ case PROXD_TOF_METHOD:
+ meth_res = proxd_method_tof_set_param_from_opt(cmd,
+ &to, &proxd_params.u.tof_params);
+ if (meth_res == BCME_BADARG)
+ return meth_res;
+ break;
+ default:
+ printf("ERROR: unsupported method\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* if option is unknown to both common and meth specific */
+ if ((com_res != BCME_OK) && (meth_res != BCME_OK)) {
+ printf(">>>> Method:%d doesn't support cmd option:'%c'\n",
+ method, to.opt);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ /* Sanity check of parameters against each other */
+ interval = dtoh16(proxd_params.u.rssi_params.interval);
+ duration = dtoh16(proxd_params.u.rssi_params.duration);
+
+ if (interval < duration) {
+ fprintf(stderr,
+ "%s: \'interval\' cannot be shorter than \'duration\'\n",
+ cmd->name);
+ return BCME_BADARG;
+ }
+
+ ret = wlu_var_setbuf(wl, cmd->name, &proxd_params, sizeof(proxd_params));
+ }
+
+ return ret;
+}
+
+/* proxd parse mixed param: <str0><val0><str1><val1>... */
+static void
+proxd_method_tof_parse_mixed_param(char* str, const char** p_name, int* p_val, int* p_map)
+{
+ char* p;
+
+ /* parse stuff of format <str0><val0><str1><val1>... */
+ while (*p_name) {
+ p = strstr((const char*)str, (const char*)*p_name);
+ if (p) {
+ p += strlen((const char*)*p_name);
+ *p_map = 1;
+ *p_val = strtol(p, NULL, 10);
+ } else {
+ *p_map = 0;
+ }
+
+ p_name++;
+ p_map++;
+ p_val++;
+ }
+}
+
+/* proxd TOF tune ops */
+static int
+proxd_tune_set_param_from_opt(const char* cmd_name,
+ miniopt_t *mopt, wl_proxd_params_tof_tune_t *proxd_tune)
+{
+ if (mopt->opt == 'k') {
+ if (!mopt->good_int) {
+ char *p = strstr(mopt->valstr, ",");
+ if (p) {
+ proxd_tune->Ki = htod32(atoi(mopt->valstr));
+ proxd_tune->Kt = htod32(atoi(p+1));
+ }
+ else {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as K\n",
+ cmd_name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ }
+ else {
+ proxd_tune->Ki = htod32(mopt->val);
+ proxd_tune->Kt = htod32(mopt->val);
+ }
+ proxd_tune->setflags |= WL_PROXD_SETFLAG_K;
+ } else if (mopt->opt == 'b') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as vhtack\n",
+ cmd_name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->vhtack = htod16(mopt->val);
+ } else if (mopt->opt == 'c') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as core\n",
+ cmd_name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->core = htod16(mopt->val);
+ } else if (mopt->opt == 'A') {
+ const char* n[4] = {"s", "h", "r", NULL};
+ int v[3] = {0, 0, 0};
+ int m[3] = {0, 0, 0};
+
+ proxd_method_tof_parse_mixed_param(mopt->valstr, n, v, m);
+ if (m[TOF_ADJ_SOFTWARE]) {
+ /* sw adj */
+ proxd_tune->sw_adj = (int16)v[TOF_ADJ_SOFTWARE];
+ }
+ if (m[TOF_ADJ_HARDWARE]) {
+ /* hw adj */
+ proxd_tune->hw_adj = (int16)v[TOF_ADJ_HARDWARE];
+ }
+ if (m[TOF_ADJ_SEQ]) {
+ /* ranging sequence */
+ proxd_tune->seq_en = (int16)v[TOF_ADJ_SEQ];
+ }
+
+ if ((m[TOF_ADJ_SOFTWARE] | m[TOF_ADJ_HARDWARE] | m[TOF_ADJ_SEQ]) == 0) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as hw/sw adjustment enable params\n",
+ cmd_name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ } else if (mopt->opt == 'n') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as min time difference limitation\n",
+ cmd_name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->minDT = htod32(mopt->val);
+ } else if (mopt->opt == 'x') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as max time difference limitation\n",
+ cmd_name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->maxDT = htod32(mopt->val);
+ } else if (mopt->opt == 'N') {
+ int i = 0;
+ if (!mopt->good_int) {
+ char *p = mopt->valstr;
+ while (p && i < TOF_BW_SEQ_NUM) {
+ if (htod16(atoi(p)))
+ proxd_tune->N_log2[i] = htod16(atoi(p));
+ i++;
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ if (p) {
+ proxd_tune->N_log2_2g = htod16(atoi(p));
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ if (p) {
+ proxd_tune->seq_5g20.N_tx_log2 = htod16(atoi(p));
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ if (p) {
+ proxd_tune->seq_5g20.N_rx_log2 = htod16(atoi(p));
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ if (p) {
+ proxd_tune->seq_2g20.N_tx_log2 = htod16(atoi(p));
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ if (p) {
+ proxd_tune->seq_2g20.N_rx_log2 = htod16(atoi(p));
+ }
+
+ } else {
+ for (; i < TOF_BW_SEQ_NUM; i++) {
+ proxd_tune->N_log2[i] = htod16(mopt->val);
+ }
+ proxd_tune->N_log2_2g = htod16(mopt->val);
+ proxd_tune->seq_5g20.N_tx_log2 = htod16(mopt->val);
+ proxd_tune->seq_5g20.N_rx_log2 = htod16(mopt->val);
+ proxd_tune->seq_2g20.N_tx_log2 = htod16(mopt->val);
+ proxd_tune->seq_2g20.N_rx_log2 = htod16(mopt->val);
+ }
+ proxd_tune->setflags |= WL_PROXD_SETFLAG_N;
+ } else if (mopt->opt == 'S') {
+ int i = 0;
+ if (!mopt->good_int) {
+ char *p = mopt->valstr;
+ while (p && i < TOF_BW_SEQ_NUM) {
+ if (htod16(atoi(p)))
+ proxd_tune->N_scale[i] = htod16(atoi(p));
+ i++;
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ if (p) {
+ proxd_tune->N_scale_2g = htod16(atoi(p));
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ if (p) {
+ proxd_tune->seq_5g20.N_tx_scale = htod16(atoi(p));
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ if (p) {
+ proxd_tune->seq_5g20.N_rx_scale = htod16(atoi(p));
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ if (p) {
+ proxd_tune->seq_2g20.N_tx_scale = htod16(atoi(p));
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ if (p) {
+ proxd_tune->seq_2g20.N_rx_scale = htod16(atoi(p));
+ }
+ } else {
+ for (; i < TOF_BW_SEQ_NUM; i++) {
+ proxd_tune->N_scale[i] = htod16(mopt->val);
+ }
+ proxd_tune->N_scale_2g = htod16(mopt->val);
+ proxd_tune->seq_5g20.N_tx_scale = htod16(mopt->val);
+ proxd_tune->seq_5g20.N_rx_scale = htod16(mopt->val);
+ proxd_tune->seq_2g20.N_rx_scale = htod16(mopt->val);
+ proxd_tune->seq_2g20.N_rx_scale = htod16(mopt->val);
+ }
+ proxd_tune->setflags |= WL_PROXD_SETFLAG_S;
+ } else if (mopt->opt == 'F') {
+ int i = 0;
+ if (!mopt->good_int) {
+ char *p = mopt->valstr;
+ while (p && i < TOF_BW_SEQ_NUM) {
+ if (htod16(atoi(p)))
+ proxd_tune->ftm_cnt[i] = htod16(atoi(p));
+ i++;
+ p = strstr(p, ",");
+ if (p)
+ p++;
+ }
+ } else {
+ for (; i < TOF_BW_SEQ_NUM; i++) {
+ proxd_tune->ftm_cnt[i] = htod16(mopt->val);
+ }
+ }
+ } else if (mopt->opt == 't') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as total frmcnt\n",
+ cmd_name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->totalfrmcnt = (mopt->val);
+ } else if (mopt->opt == 'r') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as media reserve value\n",
+ cmd_name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->rsv_media = (mopt->val);
+ } else if (mopt->opt == 'f') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as flags\n",
+ cmd_name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->flags = htod16(mopt->val);
+ } else if (mopt->opt == 'W') {
+ const char* n[4] = {"b", "l", "o", NULL};
+ const char* s[4] = {"s", "l", "o", NULL};
+ const char **p;
+ int v[TOF_BW_NUM] = {0, 0, 0};
+ int m[TOF_BW_NUM] = {0, 0, 0};
+ int i;
+ if (*mopt->valstr == 's')
+ p = s;
+ else
+ p = n;
+ proxd_method_tof_parse_mixed_param(mopt->valstr, p, v, m);
+ if (m[0]) {
+ /* Got bw */
+ if (v[0] == TOF_BW_80MHZ)
+ i = TOF_BW_80MHZ_INDEX;
+ else if (v[0] == TOF_BW_40MHZ)
+ i = TOF_BW_40MHZ_INDEX;
+ else if (v[0] == TOF_BW_20MHZ)
+ i = TOF_BW_20MHZ_INDEX;
+ else {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as window params\n",
+ cmd_name, mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ if (p == n) {
+ /* Normal */
+ if (m[1]) {
+ /* Got length */
+ proxd_tune->w_len[i] = (int16)v[1];
+ }
+ if (m[2]) {
+ /* Got offset */
+ proxd_tune->w_offset[i] = (int16)v[2];
+ }
+ } else {
+ /* Seq */
+ if (m[1] && i == TOF_BW_20MHZ_INDEX) {
+ /* Got length */
+ proxd_tune->seq_5g20.w_len = (int16)v[1];
+ proxd_tune->seq_2g20.w_len = (int16)v[1];
+ }
+ if (m[2]&& i == TOF_BW_20MHZ_INDEX) {
+ /* Got offset */
+ proxd_tune->seq_5g20.w_offset = (int16)v[2];
+ proxd_tune->seq_2g20.w_offset = (int16)v[2];
+ }
+ }
+ }
+ } else if (mopt->opt == 'B') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "proxd ftm tune: could not parse \"%s\" as bitflip_threshold\n",
+ mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->bitflip_thresh = htod16(mopt->val);
+ } else if (mopt->opt == 'R') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "proxd ftm tune: could not parse \"%s\" as snr_threshold\n",
+ mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->snr_thresh = htod16(mopt->val);
+ } else if (mopt->opt == 'T') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "proxd ftm tune: could not parse \"%s\" as recv_2g_threshold\n",
+ mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ if (mopt->val >= 0)
+ return BCME_RANGE;
+ proxd_tune->recv_2g_thresh = mopt->val;
+ } else if (mopt->opt == 'V') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "proxd ftm tune: could not parse \"%s\" as Auto Core Select "
+ "Group Delay Variance threshold\n",
+ mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->acs_gdv_thresh = htod32(mopt->val);
+ } else if (mopt->opt == 'I') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "proxd ftm tune: could not parse \"%s\" as Auto Core Select "
+ "RSSI threshold\n",
+ mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ if (mopt->val >= 0)
+ return BCME_RANGE;
+ proxd_tune->acs_rssi_thresh = mopt->val;
+ } else if (mopt->opt == 's') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "proxd ftm tune: could not parse \"%s\" as smoothing window "
+ "enable\n",
+ mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->smooth_win_en = mopt->val;
+ } else if (mopt->opt == 'M') {
+ if (!mopt->good_int) {
+ fprintf(stderr,
+ "proxd ftm tune: could not parse \"%s\" as auto core select "
+ "group delay max - min threshold\n",
+ mopt->valstr);
+ return BCME_USAGE_ERROR;
+ }
+ proxd_tune->acs_gdmm_thresh = htod32(mopt->val);
+ } else
+ return BCME_USAGE_ERROR;
+
+ return BCME_OK;
+}
+
+static int
+wl_proxd_tune(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_proxd_params_iovar_t proxd_tune, *reply;
+ uint16 method;
+ void *ptr = NULL;
+ int ret, opt_err;
+ miniopt_t to;
+
+ /* skip the command name and check if mandatory exists */
+ if (!*++argv) {
+ fprintf(stderr, "missing mandatory parameter \'method\'\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* parse method */
+ method = (uint16)atoi(argv[0]);
+ if (method == 0) {
+ fprintf(stderr, "invalid parameter \'method\'\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ bzero(&proxd_tune, sizeof(proxd_tune));
+
+ proxd_tune.method = htod16(method);
+ ret = wlu_var_getbuf_sm(wl, cmd->name, &proxd_tune, sizeof(proxd_tune), &ptr);
+ if (ret != BCME_OK) {
+ return ret;
+ }
+
+ if (!*++argv) {
+ /* get */
+ /* display proxd_params got */
+ reply = (wl_proxd_params_iovar_t *)ptr;
+
+ printf("bf proxd_params.method:%d\n", proxd_tune.method);
+ switch (proxd_tune.method) {
+ case PROXD_RSSI_METHOD:
+ break;
+
+ case PROXD_TOF_METHOD:
+ ret = proxd_tune_display(&reply->u.tof_tune, sizeof(reply->u.tof_tune));
+ break;
+
+ default:
+ fprintf(stderr,
+ "%s: ERROR undefined method \n", cmd->name);
+ return BCME_BADARG;
+ }
+ } else {
+ /* set */
+ memcpy((void *)&proxd_tune, (void *)ptr, sizeof(proxd_tune));
+ proxd_tune.method = method;
+
+ miniopt_init(&to, cmd->name, NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ int meth_res = BCME_USAGE_ERROR;
+
+ if (opt_err == 1) {
+ return BCME_USAGE_ERROR;
+ }
+ argv += to.consumed;
+
+ /* method specific opts */
+ switch (method) {
+ case PROXD_RSSI_METHOD:
+ break;
+
+ case PROXD_TOF_METHOD:
+ meth_res = proxd_tune_set_param_from_opt(cmd->name,
+ &to, &proxd_tune.u.tof_tune);
+ break;
+
+ default:
+ printf("ERROR: unsupported method\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* if option is unknown to tune specific */
+ if (meth_res != BCME_OK) {
+ printf(">>>> Method:%d doesn't support cmd option:'%c'\n",
+ method, to.opt);
+ return meth_res;
+ }
+ }
+ ret = wlu_var_setbuf(wl, cmd->name, &proxd_tune, sizeof(proxd_tune));
+ }
+
+ return ret;
+}
+
+static const char *wl_proxd_mode_str(uint8 mode)
+{
+ static const char *proxd_mode[] = {"Undetected", "Neutral", "Initiator", "Target",
+ "UNKNOWN"};
+
+ if (mode > WL_PROXD_MODE_TARGET)
+ mode = WL_PROXD_MODE_TARGET+1;
+
+ return proxd_mode[mode];
+}
+static const char *wl_proxd_state_str(uint8 state)
+{
+ static const char *proxd_state[] = {"Poll", "Pairing", "Handshake", "Detected",
+ "Pipeline", "NegMode", "Monitor", "Unknown"};
+
+ if (state == RSSI_STATE_POLL)
+ return proxd_state[0];
+ if (state == RSSI_STATE_TPAIRING || state == RSSI_STATE_IPAIRING)
+ return proxd_state[1];
+ if (state == RSSI_STATE_THANDSHAKE || state == RSSI_STATE_IHANDSHAKE)
+ return proxd_state[2];
+ if (state == RSSI_STATE_CONFIRMED)
+ return proxd_state[3];
+ if (state == RSSI_STATE_PIPELINE)
+ return proxd_state[4];
+ if (state == RSSI_STATE_NEGMODE)
+ return proxd_state[5];
+ if (state == RSSI_STATE_MONITOR)
+ return proxd_state[6];
+
+ return proxd_state[7];
+}
+
+static const char *wl_proxd_tof_state_str(uint8 state)
+{
+ static const char *tof_proxd_state[] =
+ {"Idle", "Wait", "LegacyWait", "Confirmed", "Unknown", "Report"};
+
+ if (state == TOF_STATE_IDLE)
+ return tof_proxd_state[0];
+ if (state == TOF_STATE_IWAITM || state == TOF_STATE_TWAITM ||
+ state == TOF_STATE_IWAITCL || state == TOF_STATE_TWAITCL)
+ return tof_proxd_state[1];
+ if (state == TOF_STATE_ILEGACY)
+ return tof_proxd_state[2];
+ if (state == TOF_STATE_ICONFIRM)
+ return tof_proxd_state[3];
+ if (state == TOF_STATE_IREPORT)
+ return tof_proxd_state[5];
+
+ return tof_proxd_state[4];
+}
+
+static const char *wl_proxd_tof_reason_str(uint8 reason)
+{
+ static const char *tof_proxd_reason[] = {"OK", "RxedReqEnd", "Timeout",
+ "LostACK", "InvalidAVB"};
+
+ if (reason > TOF_REASON_INVALIDAVB)
+ reason = 0;
+
+ return tof_proxd_reason[reason];
+}
+
+static const char *wl_proxd_reason_str(uint8 reason)
+{
+ static const char *proxd_reason[] = {"Unknown", "Low rssi", "State machine out of SYNC",
+ "Timeout"};
+
+ if (reason > RSSI_REASON_TIMEOUT)
+ reason = 0;
+
+ return proxd_reason[reason];
+}
+
+static int
+wl_proxd_status(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_proxd_status_iovar_t status, *statusp;
+ int ret = BCME_BADARG;
+
+ if (!*++argv) {
+ /* Get */
+ bzero(&status, sizeof(wl_proxd_status_iovar_t));
+ if ((ret = wlu_iovar_get(wl, cmd->name, (void *) &status,
+ (sizeof(wl_proxd_status_iovar_t)))) < 0)
+ return (ret);
+
+ statusp = &status;
+ switch (statusp->method)
+ {
+ case PROXD_RSSI_METHOD:
+ printf("mode=%s\n", wl_proxd_mode_str(statusp->mode));
+ printf("state=%s\n", wl_proxd_state_str(statusp->state));
+ printf("peer mode=%s\n", wl_proxd_mode_str(statusp->peermode));
+ printf("peer=%s\n", wl_ether_etoa(&statusp->peer));
+ printf("lowest rssi=%d\n", statusp->low_rssi);
+ printf("highest rssi=%d\n", statusp->hi_rssi);
+ printf("tx pkts=%d\n", statusp->txcnt);
+ printf("rx pkts=%d\n", statusp->rxcnt);
+ printf("reason=%s\n\n", wl_proxd_reason_str(statusp->reason));
+ break;
+
+ case PROXD_TOF_METHOD:
+ printf("mode=%s\n", wl_proxd_mode_str(statusp->mode));
+ printf("state=%s\n", wl_proxd_tof_state_str(statusp->state));
+ if (statusp->distance == 0xffffffff)
+ printf("distance=-1\n");
+ else
+ printf("distance=%d.%04d\n", statusp->distance >> 4,
+ ((statusp->distance & 0xf)*625));
+ printf("peer=%s\n", wl_ether_etoa(&statusp->peer));
+ printf("avg rssi=%d\n", statusp->avg_rssi);
+ printf("tx pkts=%d\n", statusp->txcnt);
+ printf("rx pkts=%d\n", statusp->rxcnt);
+ printf("frame types = CCK %d OFDM %d 11N %d 11AC %d\n",
+ statusp->frame_type_cnt[FRAME_TYPE_CCK],
+ statusp->frame_type_cnt[FRAME_TYPE_OFDM],
+ statusp->frame_type_cnt[FRAME_TYPE_11N],
+ statusp->frame_type_cnt[FRAME_TYPE_11AC]);
+ printf("adj types = SW %d HW %d SEQ %d NONE %d\n",
+ statusp->adj_type_cnt[TOF_ADJ_SOFTWARE],
+ statusp->adj_type_cnt[TOF_ADJ_HARDWARE],
+ statusp->adj_type_cnt[TOF_ADJ_SEQ],
+ statusp->adj_type_cnt[TOF_ADJ_NONE]);
+ printf("report status= %d\n", statusp->dbgstatus);
+ printf("reason=%s\n", wl_proxd_tof_reason_str(statusp->reason));
+ printf("frmcnt=%d\n", statusp->low_rssi);
+ if (statusp->hi_rssi == TOF_LEGACY_AP)
+ printf("measure=OneSide\n\n");
+ else
+ printf("measure=TwoSide\n\n");
+ break;
+
+ default:
+ printf("ERROR: unsupported method\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ else
+ printf("Cannot set proxd_status\n");
+
+ return ret;
+}
+static int
+wl_proxd_payload(void *wl, cmd_t *cmd, char **argv)
+{
+ char *buf;
+ uint16 len, *reply;
+ int ret;
+
+ buf = malloc(WL_PROXD_PAYLOAD_LEN);
+ if (buf == NULL) {
+ fprintf(stderr, "Failed to allocate buffer of %d bytes\n", WL_PROXD_PAYLOAD_LEN);
+ return -1;
+ }
+ bzero(buf, WL_PROXD_PAYLOAD_LEN);
+
+ /* skip the command name and check if NULL */
+ if (!*++argv) {
+ /* Get */
+ if ((ret = wlu_iovar_get(wl, cmd->name, (void *)buf, WL_PROXD_PAYLOAD_LEN)) < 0) {
+ free(buf);
+ return (ret);
+ }
+ reply = (uint16 *)buf;
+ len = dtoh16(reply[0]);
+
+ if (len > 0) {
+ char *ptr = buf+sizeof(uint16);
+ char *endptr = ptr+len;
+ int num = 0;
+ uint8 val;
+
+ printf("Payload Length %d\n", len);
+ while (ptr < endptr)
+ {
+ val = *(uint8 *)ptr++;
+ printf("%02X", val);
+ if (++num == 40)
+ {
+ printf("\n");
+ num = 0;
+ }
+ }
+ if (num) printf("\n");
+ }
+ } else {
+ /* Set */
+ len = (uint16)atoi(argv[0]);
+ if (len > 0) {
+ if (!argv[1]) {
+ printf("Payload content is missing\n");
+ free(buf);
+ return -1;
+ }
+ else {
+ char *ptr = argv[1];
+ char *bufp = buf;
+ char hex[] = "XX";
+
+ if ((uint16)strlen(ptr) != len*2)
+ {
+ printf("Payload length mismatch %d %d\n", len,
+ ((int)strlen(ptr))/2);
+ free(buf);
+ return -1;
+ }
+ while (*ptr) {
+ strncpy(hex, ptr, 2);
+ *bufp++ = (char) strtoul(hex, NULL, 16);
+ ptr += 2;
+ }
+ }
+ }
+ ret = wlu_var_setbuf(wl, cmd->name, buf, len);
+ }
+ free(buf);
+ return ret;
+}
+
+static int wl_proxd_report(void *wl, cmd_t *cmd, char **argv)
+{
+ uint16 len;
+ int i, ret;
+ struct ether_addr addrlist[WL_PROXD_MAXREPORT];
+
+ /* skip the command name and check if NULL */
+ if (!*++argv) {
+ /* Get */
+ len = sizeof(struct ether_addr) * WL_PROXD_MAXREPORT;
+ bzero(&addrlist[0], len);
+ if ((ret = wlu_iovar_get(wl, cmd->name, (void *)addrlist, len)) < 0) {
+ return (ret);
+ }
+
+ for (i = 0; i < WL_PROXD_MAXREPORT; i++)
+ {
+ if (ETHER_ISNULLADDR(&addrlist[i]))
+ break;
+ printf("%s ", wl_ether_etoa(&addrlist[i]));
+ }
+ printf("\n");
+ } else {
+ /* Set */
+ i = 0;
+ while (argv[0]) {
+ if (i >= WL_PROXD_MAXREPORT) {
+ printf("Over the maxium report number %d\n", WL_PROXD_MAXREPORT);
+ return BCME_BUFTOOLONG;
+ }
+ if (!wl_ether_atoe(argv[0], &addrlist[i])) {
+ if (i == 0)
+ return BCME_BADADDR;
+ break;
+ }
+ i++;
+ argv++;
+ }
+ ret = wlu_var_setbuf(wl, cmd->name, addrlist, ETHER_ADDR_LEN * i);
+ }
+
+ return ret;
+}
+
+/* print or calculate & print location info */
+void wl_proxd_tof_host_calc(wl_proxd_event_data_t* evp)
+{
+ uint32 distance;
+ uint32 meanrtt, modertt, medianrtt, dst_sigma; /* standard deviation */
+ int ftm_cnt;
+ int16 avg_rssi, validfrmcnt;
+ int32 var1, var2, var3;
+ char diststr[40];
+
+ distance = ntoh32(evp->distance);
+ dst_sigma = ntoh32(evp->sdrtt);
+ ftm_cnt = ntoh16(evp->ftm_cnt);
+ avg_rssi = ntoh16(evp->avg_rssi);
+ validfrmcnt = ntoh16(evp->validfrmcnt);
+ meanrtt = ntoh32(evp->meanrtt);
+ modertt = ntoh32(evp->modertt);
+ medianrtt = ntoh32(evp->medianrtt);
+ var1 = ntoh32(evp->var1);
+ var2 = ntoh32(evp->var2);
+ var3 = ntoh32(evp->var3);
+
+ bzero(diststr, sizeof(diststr));
+ if (distance == 0xffffffff)
+ sprintf(diststr, "distance=-1m\n");
+ else
+ sprintf(diststr, "distance=%d.%04dm\n", distance>>4, (distance & 0xf) * 625);
+
+ if (ntoh16(evp->mode) == WL_PROXD_MODE_TARGET) {
+ if (evp->TOF_type == TOF_TYPE_REPORT) {
+ printf("Report:(%s) and ", wl_ether_etoa(&evp->peer_mac));
+ printf("(%s); %s", wl_ether_etoa((struct ether_addr *)
+ &evp->peer_router_info), diststr);
+ }
+ else
+ printf("Target:(%s); %s; ", wl_ether_etoa(&evp->peer_mac), diststr);
+ printf("mean %d mode %d median %d\n", meanrtt, modertt, medianrtt);
+ }
+ else
+ printf("Initiator:(%s); %s; ", wl_ether_etoa(&evp->peer_mac), diststr);
+
+ printf("sigma:%d.%d;", dst_sigma/10, dst_sigma % 10);
+ printf("rssi:%d validfrmcnt %d\n", avg_rssi, validfrmcnt);
+
+ if (evp->TOF_type == TOF_TYPE_REPORT)
+ printf("var3: %d\n", var3);
+ else
+ printf("var: %d %d %d\n", var1, var2, var3);
+
+ if (ftm_cnt > 1) {
+ int i;
+ printf("event contains %d rtd samples for host side calculation:\n",
+ ftm_cnt);
+
+ for (i = 0; i < ftm_cnt; i++) {
+ printf("ftm[%d] --> value:%d rssi:%d\n", i,
+ ntoh32(evp->ftm_buff[i].value), evp->ftm_buff[i].rssi);
+ }
+
+ printf("host side calculation result: TBD\n");
+ /* TODO: process raw samples */
+ /* e.g:
+ 1) mean Mn = (S1+S2+... Sn)/N
+ 2) variatin: Xn = (Sn - M)^2;
+ 3) sqrt((X1 + X2 + .. Xn)/N)
+ */
+ }
+}
+#ifdef WL_NAN
+static const char *wl_proxd_nan_status_str(uint8 status)
+{
+ static const char *proxd_nan_status[] = {"Unknown", "Success", "Fail", "Timeout", "Abort"};
+
+ if (status > WL_NAN_RANGING_STATUS_ABORT)
+ status = 0;
+
+ return proxd_nan_status[status];
+}
+
+/* print or calculate & print nan event */
+void wl_proxd_nan_host_calc(wl_nan_ranging_event_data_t* evp)
+{
+ wl_nan_ranging_result_t *rp;
+ int i;
+ uint32 distance;
+ uint32 dst_sigma; /* standard deviation */
+ uint8 validfrmcnt;
+ char dist[40];
+
+ rp = evp->rr;
+ for (i = 0; i < evp->count; i++, rp++) {
+ distance = rp->distance;
+ dst_sigma = rp->rtt_var;
+ validfrmcnt = rp->sounding_count;
+
+ bzero(dist, sizeof(dist));
+ if (distance == 0xffffffff)
+ sprintf(dist, "distance=-1m\n");
+ else
+ sprintf(dist, "distance=%d.%dm\n", distance>>4, (distance & 0xf)*625);
+
+ if (evp->mode == WL_PROXD_MODE_TARGET) {
+ if (!ETHER_ISNULLADDR(&rp->tgtea)) {
+ printf("Report:(%s) and ", wl_ether_etoa(&rp->ea));
+ printf("(%s); %s", wl_ether_etoa(&rp->tgtea), dist);
+ }
+ else
+ printf("Target:(%s); %s; ", wl_ether_etoa(&rp->ea), dist);
+ }
+ else
+ printf("Initiator:(%s); %s", wl_ether_etoa(&rp->ea), dist);
+
+ printf("%s sigma:%d.%d validfrmcnt %d\n", wl_proxd_nan_status_str(rp->status),
+ dst_sigma/10, dst_sigma % 10, validfrmcnt);
+ }
+}
+#endif /* WL_NAN */
+
+#if defined(linux)
+/* print timestamp info */
+static void wl_proxd_tof_ts_results(wl_proxd_event_ts_results_t* tsp)
+{
+ int16 ver;
+ int tscnt;
+ int i;
+
+ ver = ntoh16(tsp->ver);
+ tscnt = ntoh16(tsp->ts_cnt);
+ if (ver == 2) {
+ printf("Frame Count %d\n Timestamps:\n", tscnt);
+ if (tscnt > 0) {
+ for (i = 0; i < tscnt; i++) {
+ printf("t1[%d]=%u : t2[%d]=%u : t3[%d]=%u : t4[%d]=%u\n",
+ i, ntoh32(tsp->ts_buff[i].t1),
+ i, ntoh32(tsp->ts_buff[i].t2),
+ i, ntoh32(tsp->ts_buff[i].t3),
+ i, ntoh32(tsp->ts_buff[i].t4));
+ }
+ }
+ }
+}
+
+#define PROXD_EVENTS_BUFFER_SIZE 2048
+static int
+wl_proxd_event_check(void *wl, cmd_t *cmd, char **argv)
+{
+ bool exit_on1stresult = FALSE;
+ int fd, err, octets;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ char ifnames[IFNAMSIZ] = {"eth0"};
+ bcm_event_t *event;
+ uint32 reason;
+ uint16 mode; /* target or initiator */
+ char* data;
+ int event_type;
+ uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* 128-bit mask */
+ wl_proxd_event_data_t* evp = NULL;
+#ifdef WL_NAN
+ wl_nan_ranging_event_data_t *nanevp = NULL;
+#endif
+ wl_proxd_event_ts_results_t* tsp = NULL;
+
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ if (argv[1] == NULL) {
+ printf("<ifname> param is missing\n");
+ return -1;
+ }
+
+ if (*++argv) {
+ strncpy(ifnames, *argv, (IFNAMSIZ - 1));
+ }
+
+ bzero(&ifr, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
+
+
+ /* read current mask state */
+ if ((err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
+ printf("couldn't read event_msgs\n");
+ return (err);
+ }
+ event_inds_mask[WLC_E_PROXD / 8] |= 1 << (WLC_E_PROXD % 8);
+ if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
+ return (err);
+
+ if (*++argv) {
+ if (strcmp(*argv, "osh") == 0) {
+ /* exit after processing 1st proximity result */;
+ exit_on1stresult = TRUE;
+ }
+ }
+
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
+ if (fd < 0) {
+ printf("Cannot create socket %d\n", fd);
+ return -1;
+ }
+
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ printf("Cannot get iface:%s index \n", ifr.ifr_name);
+ goto exit1;
+ }
+
+ bzero(&sll, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ printf("Cannot bind %d\n", err);
+ goto exit1;
+ }
+
+ data = (char*)malloc(PROXD_EVENTS_BUFFER_SIZE);
+
+ if (data == NULL) {
+ printf("Cannot not allocate %d bytes for events receive buffer\n",
+ PROXD_EVENTS_BUFFER_SIZE);
+ goto exit1;
+ }
+
+ printf("waiting for LBS events :%s\n", ifr.ifr_name);
+
+ while (1) {
+ fflush(stdout);
+ octets = recv(fd, data, PROXD_EVENTS_BUFFER_SIZE, 0);
+
+ if (octets <= 0) {
+ /* sigterm */
+ err = -1;
+ break;
+ }
+
+ event = (bcm_event_t *)data;
+ event_type = ntoh32(event->event.event_type);
+ reason = ntoh32(event->event.reason);
+
+#ifdef WL_FTM_DEBUG
+ printf("%s: event_type 0x%x, ntoh32()=0x%x, ltoh32()=0x%x\n",
+ __FUNCTION__, event->event.event_type, event_type,
+ ltoh32(event->event.event_type));
+#endif /* WL_FTM_DEBUG */
+
+ if ((event_type != WLC_E_PROXD)) {
+ /* may be other BCM events we are not interested in */
+#ifdef WL_FTM_DEBUG
+ printf("WARNING: not a proxd BCM_EVENT:%d\n", event_type);
+#endif /* WL_FTM_DEBUG */
+ continue;
+ }
+
+ /* check 'version' for FTM events */
+ if (ftm_event_check((bcm_event_t *) data) == 0)
+ continue; /* continue to rx event */
+ /* continue to handle non-FTM events */
+
+#ifdef WL_NAN
+ if (reason == WLC_E_PROXD_NAN_EVENT) {
+ nanevp = (wl_nan_ranging_event_data_t *)&data[sizeof(bcm_event_t)];
+ mode = nanevp->mode;
+ }
+ else
+#endif
+ if (reason == WLC_E_PROXD_TS_RESULTS) {
+ tsp = (wl_proxd_event_ts_results_t*)&data[sizeof(bcm_event_t)];
+ mode = ntoh16(tsp->mode);
+ } else {
+ /* move to bcm event payload, which is proxd event structure */
+ evp = (wl_proxd_event_data_t*)&data[sizeof(bcm_event_t)];
+ mode = ntoh16(evp->mode);
+ }
+
+ printf("mode:%s; event:",
+ (mode == WL_PROXD_MODE_INITIATOR)?"initiator":"target");
+
+ switch (reason) {
+ case WLC_E_PROXD_FOUND:
+ printf("WLC_E_PROXD_FOUND; ");
+ wl_proxd_tof_host_calc(evp); /* backward compatibility with RSSI method */
+ break;
+ case WLC_E_PROXD_GONE:
+ printf("WLC_E_PROXD_GONE; ");
+ break;
+ case WLC_E_PROXD_START:
+ /* event for targets / accesspoints */
+ printf("WLC_E_PROXD_START; ");
+ break;
+ case WLC_E_PROXD_STOP:
+ printf("WLC_E_PROXD_STOP; ");
+ break;
+ case WLC_E_PROXD_COMPLETED:
+ printf("WLC_E_PROXD_COMPLETED; ");
+ /* all new method results should land here */
+ wl_proxd_tof_host_calc(evp);
+ if (exit_on1stresult)
+ goto exit0;
+ break;
+ case WLC_E_PROXD_TS_RESULTS:
+ printf("WLC_E_PROXD_TS_RESULTS; ");
+ wl_proxd_tof_ts_results(tsp);
+ if (exit_on1stresult)
+ goto exit0;
+ break;
+ case WLC_E_PROXD_ERROR:
+ printf("WLC_E_PROXD_ERROR:%d;", evp->err_code);
+ /* all new method results should land here */
+ wl_proxd_tof_host_calc(evp);
+ if (exit_on1stresult)
+ goto exit0;
+ break;
+ case WLC_E_PROXD_COLLECT_START:
+ printf("WLC_E_PROXD_COLLECT_START; ");
+ break;
+ case WLC_E_PROXD_COLLECT_STOP:
+ printf("WLC_E_PROXD_COLLECT_STOP; ");
+ break;
+ case WLC_E_PROXD_COLLECT_COMPLETED:
+ printf("WLC_E_PROXD_COLLECT_COMPLETED; ");
+ break;
+ case WLC_E_PROXD_COLLECT_ERROR:
+ printf("WLC_E_PROXD_COLLECT_ERROR; ");
+ break;
+#ifdef WL_NAN
+ case WLC_E_PROXD_NAN_EVENT:
+ printf("WLC_E_NAN_EVENT; ");
+ wl_proxd_nan_host_calc(nanevp);
+ break;
+#endif
+ default:
+ printf("ERROR: unsupported EVENT reason code:%d; ",
+ reason);
+ err = -1;
+ break;
+ }
+
+ printf("\n");
+ }
+exit0:
+ /* if we ever reach here */
+ free(data);
+exit1:
+ close(fd);
+
+ /* Read the event mask from driver and mask the event WLC_E_PROXD */
+ if (!(err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
+ event_inds_mask[WLC_E_PROXD / 8] &= (~(1 << (WLC_E_PROXD % 8)));
+ err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN);
+ }
+
+ fflush(stdout);
+ return (err);
+}
+#endif /* linux */
+
+#if defined(WL_NAN)
+static int wl_nan_ranging_config(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_nan_ranging_config_t nanconfig, *pnan_config;
+ char chspec_str[CHANSPEC_STR_LEN];
+ int rc;
+ void *ptr = NULL;
+ int count;
+ chanspec_t chanspec;
+
+ count = ARGCNT(argv);
+
+ /* GET operation */
+ if (*++argv == NULL) {
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+ pnan_config = (wl_nan_ranging_config_t *)ptr;
+ wf_chspec_ntoa(pnan_config->chanspec, chspec_str);
+ printf("chanspec: %s(0x%04x)\n", chspec_str, pnan_config->chanspec);
+ printf("timeslot: %d\n", pnan_config->timeslot);
+ printf("duration: %d\n", pnan_config->duration);
+ printf("allowed mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pnan_config->allow_mac.octet[0],
+ pnan_config->allow_mac.octet[1],
+ pnan_config->allow_mac.octet[2],
+ pnan_config->allow_mac.octet[3],
+ pnan_config->allow_mac.octet[4],
+ pnan_config->allow_mac.octet[5]);
+ printf("flags: 0x%04x\n", pnan_config->flags);
+ return rc;
+ }
+
+ /*
+ ** Set the attributes.
+ */
+ if (count < 4) {
+ return BCME_USAGE_ERROR;
+ }
+
+ pnan_config = &nanconfig;
+
+ if ((chanspec = wf_chspec_aton(*argv)) == 0) {
+ fprintf(stderr, "%s: could not parse \"%s\" as a channel\n",
+ cmd->name, *argv);
+ return BCME_BADARG;
+ }
+
+ pnan_config->chanspec = wl_chspec_to_driver(chanspec);
+
+ if (pnan_config->chanspec == INVCHANSPEC) {
+ fprintf(stderr, "%s: wl_chspec_to_driver() error \"%s\" \n",
+ cmd->name, *argv);
+ return BCME_BADARG;
+ }
+
+ pnan_config->timeslot = strtoul(*++argv, NULL, 0);
+ if (pnan_config->timeslot == 0 || pnan_config->timeslot >= 512) {
+ fprintf(stderr, "Invalid timeslot \"%s\" \n", *argv);
+ return BCME_BADARG;
+ }
+
+ pnan_config->duration = strtoul(*++argv, NULL, 0);
+ if (pnan_config->duration == 0 || pnan_config->duration >= 512) {
+ fprintf(stderr, "Invalid duration \"%s\" \n", *argv);
+ return BCME_BADARG;
+ }
+
+ if (*++argv) {
+ /* MAC address */
+ if (!wl_ether_atoe(*argv, &pnan_config->allow_mac)) {
+ fprintf(stderr, "nan ranging config mac addr err\n");
+ return BCME_BADARG;
+ }
+ if (*++argv) {
+ pnan_config->flags = strtoul(*argv, NULL, 0);
+ } else
+ pnan_config->flags = 0;
+ } else {
+ memcpy(&pnan_config->allow_mac, ðer_bcast, ETHER_ADDR_LEN);
+ pnan_config->flags = 0;
+ }
+
+ rc = wlu_var_setbuf(wl, cmd->name, pnan_config, sizeof(wl_nan_ranging_config_t));
+
+ return (rc);
+}
+
+static int wl_nan_ranging_start(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *str;
+ wl_nan_ranging_list_t *pnan_list;
+ int buf_len;
+ int str_len;
+ int rc, i;
+ void *ptr = NULL;
+ int count;
+ chanspec_t chanspec;
+
+ count = ARGCNT(argv);
+
+ /* GET operation */
+ if (*++argv == NULL) {
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+ pnan_list = (wl_nan_ranging_list_t *)ptr;
+ printf("num peers: %d \n", pnan_list->count);
+ printf("num peers done: %d \n", pnan_list->num_peers_done);
+ printf("num dws: %d \n", pnan_list->num_dws);
+
+ printf("----------------------------------------------------------------------\n");
+ printf("Address \t\tchanspec\tcount\tretry\tabitmap\tflags\n");
+ for (i = 0; i < pnan_list->count; i++) {
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\t0x%04x\t\t%d\t%d\t0x%x\t0x%x\n",
+ pnan_list->rp[i].ea.octet[0],
+ pnan_list->rp[i].ea.octet[1],
+ pnan_list->rp[i].ea.octet[2],
+ pnan_list->rp[i].ea.octet[3],
+ pnan_list->rp[i].ea.octet[4],
+ pnan_list->rp[i].ea.octet[5],
+ pnan_list->rp[i].chanspec,
+ pnan_list->rp[i].frmcnt,
+ pnan_list->rp[i].retrycnt,
+ pnan_list->rp[i].abitmap,
+ pnan_list->rp[i].flags);
+ }
+ return rc;
+ }
+
+ /*
+ ** Set the attributes.
+ */
+ if ((count % 6) != 2) {
+ return BCME_USAGE_ERROR;
+ }
+
+ str = cmd->name;
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[ str_len ] = '\0';
+
+ pnan_list = (wl_nan_ranging_list_t *) (buf + str_len + 1);
+ pnan_list->count = count/6;
+ pnan_list->num_peers_done = 0;
+ pnan_list->num_dws = strtoul(*argv++, NULL, 0);
+ for (i = 0; i < pnan_list->count; i++, argv++) {
+ if ((chanspec = wf_chspec_aton(*argv)) == 0) {
+ fprintf(stderr, "%s: could not parse \"%s\" as a channel\n",
+ cmd->name, *argv);
+ return BCME_BADARG;
+ }
+
+ pnan_list->rp[i].chanspec = wl_chspec_to_driver(chanspec);
+
+ if (pnan_list->rp[i].chanspec == INVCHANSPEC) {
+ fprintf(stderr, "%s: wl_chspec_to_driver() error \"%s\" \n",
+ cmd->name, *argv);
+ return BCME_BADARG;
+ }
+
+ if (!wl_ether_atoe(*++argv, &pnan_list->rp[i].ea)) {
+ fprintf(stderr, "ranging mac addr err\n");
+ return BCME_BADADDR;
+ }
+
+ pnan_list->rp[i].abitmap = strtoul(*++argv, NULL, 0);
+ pnan_list->rp[i].frmcnt = strtoul(*++argv, NULL, 0);
+ if (pnan_list->rp[i].frmcnt >= 255) {
+ fprintf(stderr, "Invalid frame count \"%s\" \n", *argv);
+ return BCME_BADARG;
+ }
+
+ pnan_list->rp[i].retrycnt = strtoul(*++argv, NULL, 0);
+ pnan_list->rp[i].flags = strtoul(*++argv, NULL, 0);
+ }
+
+ fprintf(stderr, "count %d\n", pnan_list->count);
+ buf_len = str_len + 1 + sizeof(wl_nan_ranging_list_t) +
+ sizeof(wl_nan_ranging_peer_t) * (pnan_list->count - 1);
+
+ rc = wlu_set(wl, WLC_SET_VAR, buf, buf_len);
+
+ return (rc);
+}
+
+static int wl_nan_ranging_results_host(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_nan_ranging_event_data_t *pnan_event;
+ int rc, i;
+ void *ptr = NULL;
+
+ UNUSED_PARAMETER(argv);
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+ pnan_event = (wl_nan_ranging_event_data_t *) ptr;
+ printf("num results: %d \n", pnan_event->count);
+ printf("num good results: %d \n", pnan_event->success_count);
+ printf("------------------------------------------------------------------------------\n");
+ printf("Address\t\t\tchanspec\tvalidcnt\tts\t\tdist\tstatus\n");
+ for (i = 0; i < pnan_event->count; i++) {
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\t",
+ pnan_event->rr[i].ea.octet[0],
+ pnan_event->rr[i].ea.octet[1],
+ pnan_event->rr[i].ea.octet[2],
+ pnan_event->rr[i].ea.octet[3],
+ pnan_event->rr[i].ea.octet[4],
+ pnan_event->rr[i].ea.octet[5]);
+ printf("%04x\t\t%d\t\t%u\t",
+ pnan_event->rr[i].chanspec,
+ pnan_event->rr[i].sounding_count,
+ pnan_event->rr[i].timestamp);
+ if (pnan_event->rr[i].distance == 0xffffffff)
+ printf("-1\t");
+ else
+ printf("%d.%04d\t", pnan_event->rr[i].distance >> 4,
+ (pnan_event->rr[i].distance & 0x0f) * 625);
+ printf("%s\n", wl_proxd_nan_status_str(pnan_event->rr[i].status));
+ }
+
+ return (rc);
+}
+#endif /* WL_NAN */
+
+/*
+* proxd ftm sub-commands info and handlers
+*/
+typedef struct ftm_subcmd_info ftm_subcmd_info_t;
+typedef int (ftm_cmd_handler_t)(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv);
+
+/* bitmask indicating which command groups; */
+typedef enum {
+ FTM_SUBCMD_FLAG_METHOD = 0x01, /* FTM method command */
+ FTM_SUBCMD_FLAG_SESSION = 0x02, /* FTM session command */
+ FTM_SUBCMD_FLAG_ALL = FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION
+} ftm_subcmd_flag_t;
+
+struct ftm_subcmd_info {
+ char *name; /* cmd-name string as cmdline input */
+ wl_proxd_cmd_t cmdid; /* cmd-id */
+ ftm_cmd_handler_t *handler; /* cmd-handler */
+ ftm_subcmd_flag_t cmdflag;
+ char *helpmsg; /* messages for 'wl proxd -h ftm' */
+};
+
+#define FTM_IOC_BUFSZ 2048 /* ioc buffsize for our module (> BCM_XTLV_HDR_SIZE) */
+
+/* declare proxd ftm-method command handlers ftm_subcmd_xxxx() */
+/* e.g. static ftm_cmd_handler_t ftm_subcmd_get_version; */
+#define FTM_SUBCMD_FUNC(suffix) ftm_subcmd_ ##suffix
+#define DECL_CMDHANDLER(X) static ftm_cmd_handler_t ftm_subcmd_##X
+
+/* get */
+DECL_CMDHANDLER(get_version); /* method-only */
+DECL_CMDHANDLER(get_result); /* session-only */
+DECL_CMDHANDLER(get_info); /* method + session */
+DECL_CMDHANDLER(get_status); /* method + session */
+DECL_CMDHANDLER(get_sessions); /* method-only */
+DECL_CMDHANDLER(get_counters); /* method + session */
+DECL_CMDHANDLER(dump); /* method + session */
+DECL_CMDHANDLER(get_ranging_info); /* method-only */
+
+/* set */
+DECL_CMDHANDLER(enable); /* method-only */
+DECL_CMDHANDLER(disable); /* method-only */
+DECL_CMDHANDLER(config); /* method + session */
+DECL_CMDHANDLER(start_session); /* session-only */
+DECL_CMDHANDLER(burst_request); /* session-only */
+DECL_CMDHANDLER(stop_session); /* session-only */
+DECL_CMDHANDLER(delete_session); /* session-only */
+DECL_CMDHANDLER(clear_counters); /* method + session */
+DECL_CMDHANDLER(start_ranging); /* method-only */
+DECL_CMDHANDLER(stop_ranging); /* method-only */
+
+DECL_CMDHANDLER(tune); /* method-only both set/get */
+
+static const ftm_subcmd_info_t ftm_cmdlist[] = {
+ /* (get) wl proxd ftm ver */
+ {"ver", WL_PROXD_CMD_GET_VERSION, FTM_SUBCMD_FUNC(get_version),
+ FTM_SUBCMD_FLAG_METHOD, "Get the proxd FTM method API version information" },
+ /* (get) wl proxd ftm <session-id> result */
+ {"result", WL_PROXD_CMD_GET_RESULT, FTM_SUBCMD_FUNC(get_result),
+ FTM_SUBCMD_FLAG_SESSION, "Get a session result" },
+ /* (get) wl proxd ftm [<session-id>] info */
+ {"info", WL_PROXD_CMD_GET_INFO, FTM_SUBCMD_FUNC(get_info),
+ FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION,
+ "Get the detail information for the FTM method or a specific session" },
+ /* (get) wl proxd ftm [<session-id>] status */
+ {"status", WL_PROXD_CMD_GET_STATUS, FTM_SUBCMD_FUNC(get_status),
+ FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION,
+ "Get the status for the FTM method or a specific session" },
+ /* (get) wl proxd ftm sessions */
+ {"sessions", WL_PROXD_CMD_GET_SESSIONS, FTM_SUBCMD_FUNC(get_sessions),
+ FTM_SUBCMD_FLAG_METHOD, "List all sessions" },
+ /* (get) wl proxd ftm [<session-id>] counters */
+ {"counters", WL_PROXD_CMD_GET_COUNTERS, FTM_SUBCMD_FUNC(get_counters),
+ FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION,
+ "Get the counters for the FTM method or a specific session" },
+ /* (get) wl proxd ftm ranging-info */
+ { "ranging-info", WL_PROXD_CMD_GET_RANGING_INFO, FTM_SUBCMD_FUNC(get_ranging_info),
+ FTM_SUBCMD_FLAG_METHOD,
+ "Get the ranging information for the FTM method" },
+ /* (get) wl proxd ftm [<session-id>] dump */
+ {"dump", WL_PROXD_CMD_DUMP, FTM_SUBCMD_FUNC(dump),
+ FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION,
+ "Dump all information for the FTM method or a specific session" },
+ /* (set) wl proxd ftm enable */
+ {"enable", WL_PROXD_CMD_ENABLE, FTM_SUBCMD_FUNC(enable),
+ FTM_SUBCMD_FLAG_METHOD, "Enable proximity detection using FTM method" },
+ /* (set) wl proxd ftm disable */
+ {"disable", WL_PROXD_CMD_DISABLE, FTM_SUBCMD_FUNC(disable),
+ FTM_SUBCMD_FLAG_METHOD, "Disable proximity detection using FTM method" },
+ /* wl proxd ftm [<session-id>] config .... */
+ {"config", WL_PROXD_CMD_CONFIG, FTM_SUBCMD_FUNC(config),
+ FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION,
+ "Set the configuration for the FTM method or a specific session" },
+ /* (set) wl proxd ftm <session-id> start */
+ {"start", WL_PROXD_CMD_START_SESSION, FTM_SUBCMD_FUNC(start_session),
+ FTM_SUBCMD_FLAG_SESSION, "Start scheduling the burst(s) for a session" },
+ /* (set) wl proxd ftm <session-id> burst-request */
+ {"burst-request", WL_PROXD_CMD_BURST_REQUEST, FTM_SUBCMD_FUNC(burst_request),
+ FTM_SUBCMD_FLAG_SESSION,
+ "On initiator, send burst requests and process FTM frames. On target, send FTM frames" },
+ /* (set) wl proxd ftm <session-id> stop */
+ {"stop", WL_PROXD_CMD_STOP_SESSION, FTM_SUBCMD_FUNC(stop_session),
+ FTM_SUBCMD_FLAG_SESSION, "Stop a session" },
+ /* (set) wl proxd ftm <session-id> delete */
+ {"delete", WL_PROXD_CMD_DELETE_SESSION, FTM_SUBCMD_FUNC(delete_session),
+ FTM_SUBCMD_FLAG_SESSION, "Delete a session" },
+ /* (set) wl proxd ftm [<session-id>] clear_counters */
+ {"clear-counters", WL_PROXD_CMD_CLEAR_COUNTERS, FTM_SUBCMD_FUNC(clear_counters),
+ FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION,
+ "Clear the counters for the FTM method or a specific session" },
+ {"start-ranging", WL_PROXD_CMD_START_RANGING, FTM_SUBCMD_FUNC(start_ranging),
+ FTM_SUBCMD_FLAG_METHOD, "Start ranging for sessions" },
+ { "stop-ranging", WL_PROXD_CMD_STOP_RANGING, FTM_SUBCMD_FUNC(stop_ranging),
+ FTM_SUBCMD_FLAG_METHOD, "Stop ranging" },
+ { "tune", WL_PROXD_CMD_TUNE, FTM_SUBCMD_FUNC(tune),
+ FTM_SUBCMD_FLAG_METHOD, "proxd_tune" },
+};
+
+/*
+* get subcmd info for a specific FTM 'cmdname'
+* return NULL if specified <cmdname> is not supported.
+*/
+const ftm_subcmd_info_t *
+ftm_get_subcmd_info(char *cmdname)
+{
+ int i;
+ const ftm_subcmd_info_t *p_subcmd_info;
+
+ /* search for the specified cmdname from the pre-defined supported cmd list */
+ p_subcmd_info = &ftm_cmdlist[0];
+ for (i = 0; i < (int) ARRAYSIZE(ftm_cmdlist); i++) {
+ if (stricmp(p_subcmd_info->name, cmdname) == 0)
+ return p_subcmd_info;
+ p_subcmd_info++;
+ }
+
+ return NULL; /* cmd not supported */
+}
+
+/*
+* 'wl proxd ascii-method' handler
+* handle 'wl proxd ftm [<session-id>] <cmdname> [<param-name><param-value>]*'
+*/
+static int
+wl_proxd_cmd_method_handler(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_proxd_method_t method;
+ wl_proxd_session_id_t session_id;
+ const ftm_subcmd_info_t *p_subcmd_info;
+
+ /* ignore the command name 'proxd' */
+ UNUSED_PARAMETER(cmd);
+
+ /* check for "wl proxd -h ftm" or "wl proxd help ftm" --> display the usage */
+ if (!stricmp(*argv, "-h") || !stricmp(*argv, "help")) {
+ return ftm_handle_help(++argv); /* return BCME_USAGE_ERROR; */
+ }
+
+ /* parse proxd-method, currently only support 'ftm' */
+ if (stricmp(*argv, "ftm") != 0) { /* un-supported proxd-method */
+ printf("error: proxd-method '%s' is not supported\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ method = WL_PROXD_METHOD_FTM;
+
+ /* skip 'ftm-method' and parse session-id if specified */
+ session_id = WL_PROXD_SESSION_ID_GLOBAL;
+ if (*++argv) {
+ if (isdigit((int)*argv[0])) {
+ session_id = (wl_proxd_session_id_t) atoi(argv[0]);
+ argv++; /* skip to 'cmdname' */
+ }
+ }
+
+ /* parse 'cmd' in "wl proxd ftm [<session-id>] <cmd> [<param-name><param-value>]*" */
+ if (!*argv) {
+ printf("error: proxd ftm-method cmdname is not specified\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* search for the specified <cmdname> from the pre-defined supported cmd list */
+ p_subcmd_info = ftm_get_subcmd_info(*argv);
+ if (p_subcmd_info == NULL) {
+ /* cannot find the cmd in the ftm_cmdlist */
+ printf("error: invalid proxd ftm command '%s'\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* dispacth cmd to appropriate handler */
+ if (p_subcmd_info->handler) {
+ /* For 'method-only' commands, 'session-id' can be omitted */
+ if (((p_subcmd_info->cmdflag & FTM_SUBCMD_FLAG_METHOD) != 0) &&
+ ((p_subcmd_info->cmdflag & FTM_SUBCMD_FLAG_SESSION) == 0)) {
+ if (session_id != WL_PROXD_SESSION_ID_GLOBAL) {
+ printf("proxd ftm %s: error, does not accept non-zero session-id\n",
+ p_subcmd_info->name);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ /* For 'session-only' commands, 'session-id' must be provided */
+ if (((p_subcmd_info->cmdflag & FTM_SUBCMD_FLAG_METHOD) == 0) &&
+ ((p_subcmd_info->cmdflag & FTM_SUBCMD_FLAG_SESSION) != 0)) {
+ if (session_id == WL_PROXD_SESSION_ID_GLOBAL) {
+ printf("proxd ftm %s: error, please specify a valid session-id\n",
+ p_subcmd_info->name);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ return p_subcmd_info->handler(wl, p_subcmd_info, method, session_id, ++argv);
+ }
+
+ return BCME_OK;
+
+}
+
+/*
+* definition for id-string mapping.
+* This is used to map an id (can be cmd-id, tlv-id, ....) to a text-string
+* for debug-display or cmd-log-display
+*/
+typedef struct ftm_strmap_entry {
+ int32 id;
+ char *text;
+} ftm_strmap_entry_t;
+
+/*
+* lookup 'id' (as a key) from a table
+* if found, return the entry pointer, otherwise return NULL
+*/
+static const ftm_strmap_entry_t*
+ftm_get_strmap_info(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries)
+{
+ int i;
+ const ftm_strmap_entry_t *p_entry;
+
+ /* scan thru the table till end */
+ p_entry = p_table;
+ for (i = 0; i < (int) num_entries; i++)
+ {
+ if (p_entry->id == id)
+ return p_entry;
+ p_entry++; /* next entry */
+ }
+
+ return NULL; /* not found */
+}
+
+/*
+* lookup 'str' (as a key) from a table
+* if found, return the entry pointer, otherwise return NULL
+*/
+static const ftm_strmap_entry_t*
+ftm_get_strmap_info_strkey(char *strkey, const ftm_strmap_entry_t *p_table, uint32 num_entries)
+{
+ int i;
+ const ftm_strmap_entry_t *p_entry;
+
+ /* scan thru the table till end */
+ p_entry = p_table;
+ for (i = 0; i < (int) num_entries; i++)
+ {
+ if (stricmp(p_entry->text, strkey) == 0)
+ return p_entry;
+ p_entry++; /* next entry */
+ }
+
+ return NULL; /* not found */
+}
+
+/*
+* map enum to a text-string for display, this function is called by the following:
+* For debug/trace:
+* ftm_[cmdid|tlvid]_to_str()
+* For TLV-output log for 'get' commands
+* ftm_[method|tmu|caps|status|state]_value_to_logstr()
+* Input:
+* pTable -- point to a 'enum to string' table.
+*/
+static const char *
+ftm_map_id_to_str(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries)
+{
+ const ftm_strmap_entry_t*p_entry = ftm_get_strmap_info(id, p_table, num_entries);
+ if (p_entry)
+ return (p_entry->text);
+
+ return "invalid";
+}
+
+/* define entry, e.g. { WL_PROXD_CMD_xxx, "WL_PROXD_CMD_xxx" } */
+#define DEF_STRMAP_ENTRY(id) { (id), #id }
+
+#ifdef WL_FTM_DEBUG
+/* ftm cmd-id mapping */
+static const ftm_strmap_entry_t ftm_cmdid_map[] = {
+ /* {wl_proxd_cmd_t(WL_PROXD_CMD_xxx), "WL_PROXD_CMD_xxx" }, */
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_NONE),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_VERSION),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_ENABLE),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_DISABLE),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_CONFIG),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_SESSION),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_BURST_REQUEST),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_SESSION),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_DELETE_SESSION),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RESULT),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_INFO),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_STATUS),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_SESSIONS),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_COUNTERS),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_CLEAR_COUNTERS),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_DUMP),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_RANGING),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_RANGING),
+ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RANGING_INFO),
+};
+
+/*
+* map a ftm cmd-id to a text-string for display
+*/
+static const char *
+ftm_cmdid_to_str(uint16 cmdid)
+{
+ return ftm_map_id_to_str((int32) cmdid, &ftm_cmdid_map[0], ARRAYSIZE(ftm_cmdid_map));
+}
+#endif /* WL_FTM_DEBUG */
+
+/* ftm tlv-id mapping */
+static const ftm_strmap_entry_t ftm_tlvid_loginfo[] = {
+ /* { WL_PROXD_TLV_ID_xxx, "text for WL_PROXD_TLV_ID_xxx" }, */
+ { WL_PROXD_TLV_ID_NONE, "none" },
+ { WL_PROXD_TLV_ID_METHOD, "method" },
+ { WL_PROXD_TLV_ID_FLAGS, "flags" },
+ { WL_PROXD_TLV_ID_CHANSPEC, "chanspec" },
+ { WL_PROXD_TLV_ID_TX_POWER, "tx power" },
+ { WL_PROXD_TLV_ID_RATESPEC, "ratespec" },
+ { WL_PROXD_TLV_ID_BURST_DURATION, "burst duration" },
+ { WL_PROXD_TLV_ID_BURST_PERIOD, "burst period" },
+ { WL_PROXD_TLV_ID_BURST_FTM_SEP, "burst ftm sep" },
+ { WL_PROXD_TLV_ID_BURST_NUM_FTM, "burst num ftm" },
+ { WL_PROXD_TLV_ID_NUM_BURST, "num burst" },
+ { WL_PROXD_TLV_ID_FTM_RETRIES, "ftm retries" },
+ { WL_PROXD_TLV_ID_BSS_INDEX, "BSS index" },
+ { WL_PROXD_TLV_ID_BSSID, "bssid" },
+ { WL_PROXD_TLV_ID_INIT_DELAY, "burst init delay" },
+ { WL_PROXD_TLV_ID_BURST_TIMEOUT, "burst timeout" },
+ { WL_PROXD_TLV_ID_EVENT_MASK, "event mask" },
+ { WL_PROXD_TLV_ID_FLAGS_MASK, "flags mask" },
+ { WL_PROXD_TLV_ID_PEER_MAC, "peer addr" },
+ { WL_PROXD_TLV_ID_FTM_REQ, "ftm req" },
+ { WL_PROXD_TLV_ID_LCI_REQ, "lci req" },
+ { WL_PROXD_TLV_ID_LCI, "lci" },
+ { WL_PROXD_TLV_ID_CIVIC_REQ, "civic req" },
+ { WL_PROXD_TLV_ID_CIVIC, "civic" },
+ { WL_PROXD_TLV_ID_AVAIL24, "availability" },
+ { WL_PROXD_TLV_ID_SESSION_FLAGS, "session flags" },
+ { WL_PROXD_TLV_ID_SESSION_FLAGS_MASK, "session flags mask" },
+ { WL_PROXD_TLV_ID_RX_MAX_BURST, "rx max bursts" },
+ { WL_PROXD_TLV_ID_RANGING_INFO, "ranging info" },
+ { WL_PROXD_TLV_ID_RANGING_FLAGS, "ranging flags" },
+ { WL_PROXD_TLV_ID_RANGING_FLAGS_MASK, "ranging flags mask" },
+ { WL_PROXD_TLV_ID_NAN_MAP_ID, "nan map id" },
+ { WL_PROXD_TLV_ID_DEV_ADDR, "dev addr" },
+ { WL_PROXD_TLV_ID_AVAIL, "availability" },
+ { WL_PROXD_TLV_ID_FTM_REQ_RETRIES, "ftm request retries" },
+ { WL_PROXD_TLV_ID_TPK, "FTM TPK" },
+
+ /* output - 512 + x */
+ { WL_PROXD_TLV_ID_STATUS, "status" },
+ { WL_PROXD_TLV_ID_COUNTERS, "counters" },
+ { WL_PROXD_TLV_ID_INFO, "info" },
+ { WL_PROXD_TLV_ID_RTT_RESULT, "rtt result" },
+ { WL_PROXD_TLV_ID_AOA_RESULT, "aoa result" },
+ { WL_PROXD_TLV_ID_SESSION_INFO, "session info" },
+ { WL_PROXD_TLV_ID_SESSION_STATUS, "session status" },
+ { WL_PROXD_TLV_ID_SESSION_ID_LIST, "session ids" },
+ /* debug tlvs can be added starting 1024 */
+ { WL_PROXD_TLV_ID_DEBUG_MASK, "debug mask" },
+ { WL_PROXD_TLV_ID_COLLECT, "collect" },
+ { WL_PROXD_TLV_ID_STRBUF, "result" }
+};
+
+/*
+* map a ftm TLV-id to a text-string for display as a 'heading'
+*/
+static const char *
+ftm_tlvid_to_logstr(uint16 tlvid)
+{
+ return ftm_map_id_to_str((int32) tlvid,
+ &ftm_tlvid_loginfo[0], ARRAYSIZE(ftm_tlvid_loginfo));
+}
+
+/*
+* The following string mapping tables are used for TLVs display received from 'get' commands
+*/
+/*
+* proximity detection method --> text string mapping
+*/
+static const ftm_strmap_entry_t ftm_method_value_loginfo[] = {
+ /* wl_proxd_method_t, text-string */
+ { WL_PROXD_METHOD_RSVD1, "RSSI not supported" },
+ { WL_PROXD_METHOD_TOF, "11v+BCM proprietary" },
+ { WL_PROXD_METHOD_RSVD2, "11v only" },
+ { WL_PROXD_METHOD_FTM, "FTM" }, /* IEEE rev mc/2014 */
+ { WL_PROXD_METHOD_NONE, "none" }
+};
+static const char *
+ftm_method_value_to_logstr(wl_proxd_method_t method)
+{
+ return ftm_map_id_to_str((int32)method,
+ &ftm_method_value_loginfo[0], ARRAYSIZE(ftm_method_value_loginfo));
+}
+
+/*
+* time interval unit --> text string mapping
+*/
+static const ftm_strmap_entry_t ftm_tmu_value_loginfo[] = {
+ /* wl_proxd_tmu_t, text-string */
+ { WL_PROXD_TMU_TU, "TU" },
+ { WL_PROXD_TMU_SEC, "sec" },
+ { WL_PROXD_TMU_MILLI_SEC, "ms" },
+ { WL_PROXD_TMU_MICRO_SEC, "us" },
+ { WL_PROXD_TMU_NANO_SEC, "ns" },
+ { WL_PROXD_TMU_PICO_SEC, "ps" }
+};
+
+static const char *
+ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu)
+{
+ return ftm_map_id_to_str((int32)tmu,
+ &ftm_tmu_value_loginfo[0], ARRAYSIZE(ftm_tmu_value_loginfo));
+}
+
+/*
+* proxd FTM method capabilities --> text string mapping
+*/
+static const ftm_strmap_entry_t ftm_caps_value_loginfo[] = {
+ /* wl_proxd_ftm_capts_t, text-string */
+ { WL_PROXD_FTM_CAP_FTM1, "FTM" },
+ { WL_PROXD_FTM_CAP_NONE, "none" }
+};
+
+static const char *
+ftm_caps_value_to_logstr(wl_proxd_ftm_caps_t caps)
+{
+ return ftm_map_id_to_str((int32)caps,
+ &ftm_caps_value_loginfo[0], ARRAYSIZE(ftm_caps_value_loginfo));
+}
+
+/*
+* status --> text string mapping
+*/
+static const ftm_strmap_entry_t ftm_status_value_loginfo[] = {
+ /* wl_proxd_status_t, text-string */
+ { WL_PROXD_E_NOT_BCM, "different vendor" },
+ { WL_PROXD_E_FRAME_TYPE, "invalid frame type" },
+ { WL_PROXD_E_VERNOSUPPORT, "unsupported version" },
+ { WL_PROXD_E_SEC_NOKEY, "no key" },
+ { WL_PROXD_E_SEC_POLICY, "security policy violation" },
+ { WL_PROXD_E_SCAN_INPROCESS, "scan in process" },
+ { WL_PROXD_E_BAD_PARTIAL_TSF, "bad partial TSF" },
+ { WL_PROXD_E_SCANFAIL, "scan failed" },
+ { WL_PROXD_E_NOTSF, "no TSF" },
+ { WL_PROXD_E_POLICY, "policy failed" },
+ { WL_PROXD_E_INCOMPLETE, "incomplete" },
+ { WL_PROXD_E_OVERRIDDEN, "overridden" },
+ { WL_PROXD_E_ASAP_FAILED, "ASAP failed" },
+ { WL_PROXD_E_NOTSTARTED, "not started" },
+ { WL_PROXD_E_INVALIDMEAS, "invalid measurement" },
+ { WL_PROXD_E_INCAPABLE, "incapable" },
+ { WL_PROXD_E_MISMATCH, "mismatch"},
+ { WL_PROXD_E_DUP_SESSION, "dup session" },
+ { WL_PROXD_E_REMOTE_FAIL, "remote fail" },
+ { WL_PROXD_E_REMOTE_INCAPABLE, "remote incapable" },
+ { WL_PROXD_E_SCHED_FAIL, "sched failure" },
+ { WL_PROXD_E_PROTO, "protocol error" },
+ { WL_PROXD_E_EXPIRED, "expired" },
+ { WL_PROXD_E_TIMEOUT, "timeout" },
+ { WL_PROXD_E_NOACK, "no ack" },
+ { WL_PROXD_E_DEFERRED, "deferred" },
+ { WL_PROXD_E_INVALID_SID, "invalid session id" },
+ { WL_PROXD_E_REMOTE_CANCEL, "remote cancel" },
+ { WL_PROXD_E_CANCELED, "canceled" },
+ { WL_PROXD_E_INVALID_SESSION, "invalid session" },
+ { WL_PROXD_E_BAD_STATE, "bad state" },
+ { WL_PROXD_E_ERROR, "error" },
+ { WL_PROXD_E_OK, "OK" }
+};
+
+/*
+* convert BCME_xxx error codes into related error strings
+* note, bcmerrorstr() defined in bcmutils is for BCMDRIVER only,
+* this duplicate copy is for WL access and may need to clean up later
+*/
+static const char *ftm_bcmerrorstrtable[] = BCMERRSTRINGTABLE;
+static const char *
+ftm_status_value_to_logstr(wl_proxd_status_t status)
+{
+ static char ftm_msgbuf_status_undef[32];
+ const ftm_strmap_entry_t *p_loginfo;
+ int bcmerror;
+
+ /* check if within BCME_xxx error range */
+ bcmerror = (int) status;
+ if (VALID_BCMERROR(bcmerror))
+ return ftm_bcmerrorstrtable[-bcmerror];
+
+ /* otherwise, look for 'proxd ftm status' range */
+ p_loginfo = ftm_get_strmap_info((int32) status,
+ &ftm_status_value_loginfo[0], ARRAYSIZE(ftm_status_value_loginfo));
+ if (p_loginfo)
+ return p_loginfo->text;
+
+ /* report for 'out of range' FTM-status error code */
+ memset(ftm_msgbuf_status_undef, 0, sizeof(ftm_msgbuf_status_undef));
+ snprintf(ftm_msgbuf_status_undef, sizeof(ftm_msgbuf_status_undef),
+ "Undefined status %d", status);
+ return &ftm_msgbuf_status_undef[0];
+}
+
+/*
+* session-state --> text string mapping
+*/
+static const ftm_strmap_entry_t ftm_session_state_value_loginfo[] = {
+ /* wl_proxd_session_state_t, text string */
+ { WL_PROXD_SESSION_STATE_CREATED, "created" },
+ { WL_PROXD_SESSION_STATE_CONFIGURED, "configured" },
+ { WL_PROXD_SESSION_STATE_STARTED, "started" },
+ { WL_PROXD_SESSION_STATE_DELAY, "delay" },
+ { WL_PROXD_SESSION_STATE_USER_WAIT, "user-wait" },
+ { WL_PROXD_SESSION_STATE_SCHED_WAIT, "sched-wait" },
+ { WL_PROXD_SESSION_STATE_BURST, "burst" },
+ { WL_PROXD_SESSION_STATE_STOPPING, "stopping" },
+ { WL_PROXD_SESSION_STATE_ENDED, "ended" },
+ { WL_PROXD_SESSION_STATE_START_WAIT, "start-wait" },
+ { WL_PROXD_SESSION_STATE_DESTROYING, "destroying" },
+ { WL_PROXD_SESSION_STATE_NONE, "none" }
+};
+
+static const char *
+ftm_session_state_value_to_logstr(wl_proxd_session_state_t state)
+{
+ return ftm_map_id_to_str((int32)state, &ftm_session_state_value_loginfo[0],
+ ARRAYSIZE(ftm_session_state_value_loginfo));
+}
+
+/*
+* ranging-state --> text string mapping
+*/
+static const ftm_strmap_entry_t ftm_ranging_state_value_loginfo [] = {
+ /* wl_proxd_ranging_state_t, text string */
+ { WL_PROXD_RANGING_STATE_NONE, "none" },
+ { WL_PROXD_RANGING_STATE_NOTSTARTED, "nonstarted" },
+ { WL_PROXD_RANGING_STATE_INPROGRESS, "inprogress" },
+ { WL_PROXD_RANGING_STATE_DONE, "done" },
+};
+
+static const char *
+ftm_ranging_state_value_to_logstr(wl_proxd_ranging_state_t state)
+{
+ return ftm_map_id_to_str((int32) state, &ftm_ranging_state_value_loginfo[0],
+ ARRAYSIZE(ftm_ranging_state_value_loginfo));
+}
+
+/*
+* ranging-flags --> text string mapping
+*/
+static const ftm_strmap_entry_t ftm_ranging_flags_value_loginfo [] = {
+ /* wl_proxd_ranging_flags_t, text string */
+ { WL_PROXD_RANGING_FLAG_NONE, "none" }, /* no flags */
+ { WL_PROXD_RANGING_FLAG_DEL_SESSIONS_ON_STOP, "del sessions on stop" },
+ { WL_PROXD_RANGING_FLAG_ALL, "all" },
+};
+
+static const char *
+ftm_ranging_flags_value_to_logstr(wl_proxd_ranging_flags_t flags)
+{
+ return ftm_map_id_to_str((int32) flags, &ftm_ranging_flags_value_loginfo[0],
+ ARRAYSIZE(ftm_ranging_flags_value_loginfo));
+}
+
+/*
+* availability flag --> text string mapping
+*/
+static const ftm_strmap_entry_t ftm_avail_flags_value_loginfo [] = {
+ /* wl_proxd_avail_flags_t, text string */
+ { WL_PROXD_AVAIL_NONE, "none" },
+ { WL_PROXD_AVAIL_NAN_PUBLISHED, "NAN published" },
+ { WL_PROXD_AVAIL_SCHEDULED, "scheduled" } /* scheduled by proxd */
+};
+
+static const char *
+ftm_avail_flags_value_to_logstr(wl_proxd_avail_flags_t flags)
+{
+ return ftm_map_id_to_str((int32) flags, &ftm_avail_flags_value_loginfo[0],
+ ARRAYSIZE(ftm_avail_flags_value_loginfo));
+}
+
+/*
+* availability time-ref --> text string mapping
+* (use for logging and cmd-line params parsing)
+*/
+static const ftm_strmap_entry_t ftm_avail_timeref_value_loginfo [] = {
+ /* wl_proxd_time_ref_t, text string */
+ { WL_PROXD_TREF_NONE, "none" },
+ { WL_PROXD_TREF_DEV_TSF, "dev-tsf" },
+ { WL_PROXD_TREF_NAN_DW, "nan-dw" },
+ { WL_PROXD_TREF_TBTT, "tbtt" }
+};
+
+static const char *
+ftm_avail_timeref_value_to_logstr(wl_proxd_time_ref_t timeref)
+{
+ return ftm_map_id_to_str((int32) timeref, &ftm_avail_timeref_value_loginfo[0],
+ ARRAYSIZE(ftm_avail_timeref_value_loginfo));
+}
+
+/*
+* allocate a buffer for get/set 'proxd ftm' iovar
+*
+* Input:
+* tlvs_bufsize: specify the max-size of all TLVs reserved for this buffer
+* The following fields will be used for setting the proxd-method iovar header:
+* method, session_id, cmdid
+*
+* if succeeds, this function allocates a buffer, setup proxd-method iovar header
+* then returns the pointer to allocated buffer and the bufsize(in bytes)
+* to caller. Note, the 'len' and a dummy-TLV will be set in the iovar header,
+* caller may adjust the 'len' based on #of valid TLVs later.
+* if failed, return 'NULL' to indicate error (e.g. no memory).
+*/
+static wl_proxd_iov_t *
+ftm_alloc_getset_buf(wl_proxd_method_t method, wl_proxd_session_id_t session_id,
+ wl_proxd_cmd_t cmdid, uint16 tlvs_bufsize, uint16 *p_out_bufsize)
+{
+ uint16 proxd_iovsize;
+ wl_proxd_tlv_t *p_tlv;
+ wl_proxd_iov_t *p_proxd_iov = (wl_proxd_iov_t *) NULL;
+
+ *p_out_bufsize = 0; /* init */
+
+ /* calculate the whole buffer size, including one reserve-tlv entry in the header */
+ proxd_iovsize = sizeof(wl_proxd_iov_t) + tlvs_bufsize;
+
+ p_proxd_iov = calloc(1, proxd_iovsize);
+ if (p_proxd_iov == NULL) {
+ printf("error: failed to allocate %d bytes of memory\n", proxd_iovsize);
+ return NULL;
+ }
+
+ /* setup proxd-FTM-method iovar header */
+ p_proxd_iov->version = htol16(WL_PROXD_API_VERSION);
+ p_proxd_iov->len = htol16(proxd_iovsize); /* caller may adjust it based on #of TLVs */
+ p_proxd_iov->cmd = htol16(cmdid);
+ p_proxd_iov->method = htol16(method);
+ p_proxd_iov->sid = htol16(session_id);
+
+ /* initialize the reserved/dummy-TLV in iovar header */
+ p_tlv = p_proxd_iov->tlvs;
+ p_tlv->id = htol16(WL_PROXD_TLV_ID_NONE);
+ p_tlv->len = htol16(0);
+
+ *p_out_bufsize = proxd_iovsize; /* for caller's reference */
+
+ return p_proxd_iov;
+}
+
+/*
+* unpack and display rtt_result TLV
+*/
+
+#define PDFTM_BURST_STATE_NAMES \
+ {"INVALID", \
+ "FTM2/M1/RESPONSE", \
+ "FTM3/M2/LTFTRIGGER", \
+ "FTM4/M3/DONE", \
+ }
+
+#define FTM_FRAME_TYPES \
+ {"SETUP", "TRIGGER", "TIMESTAMP"}
+
+static void
+ftm_unpack_and_display_rtt_result(const uint8 *p_data, uint16 tlvid, uint16 len)
+{
+ int i;
+ char dispbuf[256];
+ char *p_dest;
+ wl_proxd_rtt_result_t *p_data_info;
+ wl_proxd_result_flags_t flags;
+ wl_proxd_session_state_t session_state;
+ int32 avg_dist;
+ wl_proxd_rtt_sample_t *p_sample;
+ uint16 num_rtt;
+ char* pstatestr[] = PDFTM_BURST_STATE_NAMES;
+ char *ftm_frame_types[] = FTM_FRAME_TYPES;
+
+ UNUSED_PARAMETER(len);
+
+ p_data_info = (wl_proxd_rtt_result_t *) p_data;
+
+ /* unpack and format 'flags' for display */
+ flags = ltoh16_ua(&p_data_info->flags);
+ memset(dispbuf, 0, sizeof(dispbuf));
+ p_dest = &dispbuf[0];
+ if (flags & WL_PROXD_RESULT_FLAG_NLOS) {
+ strncpy(p_dest, "NLOS", sizeof(dispbuf) - strlen(dispbuf) - 1);
+ p_dest = &dispbuf[strlen(dispbuf)];
+ }
+ if (flags & WL_PROXD_RESULT_FLAG_LOS)
+ strncpy(p_dest, " LOS", sizeof(dispbuf) - strlen(dispbuf) - 1);
+ if (flags & WL_PROXD_RESULT_FLAG_FATAL)
+ strncpy(p_dest, " Fatal error", sizeof(dispbuf) - strlen(dispbuf) - 1);
+
+ printf("> %s:\n>\tsessionId=%d, flags=0x%04x('%s'), peer=%s\n",
+ ftm_tlvid_to_logstr(tlvid),
+ ltoh16_ua(&p_data_info->sid),
+ flags,
+ dispbuf, /* flags */
+ wl_ether_etoa(&p_data_info->peer));
+
+ /* session state and status */
+ session_state = ltoh16_ua(&p_data_info->state);
+ printf(">\tsession state=%d(%s)",
+ session_state, ftm_session_state_value_to_logstr(session_state));
+
+ printf(">\tburst_duration: %d%s\n",
+ ltoh32_ua(&p_data_info->u.burst_duration.intvl),
+ ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu)));
+
+ /* show avg_dist (1/256m units), burst_num */
+ avg_dist = ltoh32_ua(&p_data_info->avg_dist);
+ if ((uint32)avg_dist == 0xffffffff) { /* report 'failure' case */
+ printf(">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d num_ftm=%d\n",
+ ltoh16_ua(&p_data_info->burst_num),
+ p_data_info->num_valid_rtt, p_data_info->num_ftm); /* in a session */
+ }
+ else {
+ printf(">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d\n",
+ avg_dist >> 8, /* 1/256m units */
+ ((avg_dist & 0xff) * 625) >> 4,
+ ltoh16_ua(&p_data_info->burst_num),
+ p_data_info->num_valid_rtt, p_data_info->num_ftm); /* in a session */
+ }
+
+ /* show 'avg_rtt' sample */
+ p_sample = &p_data_info->avg_rtt;
+ printf(">\tavg_rtt sample: rssi=%d snr=%d bitflips=%d rtt=%d%s "
+ "std_deviation =%d.%d ratespec=0x%08x\n",
+ (wl_proxd_rssi_t) ltoh16_ua(&p_sample->rssi),
+ (wl_proxd_snr_t) ltoh16_ua(&p_sample->snr),
+ (wl_proxd_bitflips_t) ltoh16_ua(&p_sample->bitflips),
+ ltoh32_ua(&p_sample->rtt.intvl),
+ ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)),
+ ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10,
+ ltoh32_ua(&p_sample->ratespec));
+
+ printf(">\tnum_measurements: %d ", p_data_info->num_meas);
+ printf(" Flags:");
+ if (p_data_info->flags & WL_PROXD_REQUEST_SENT) {
+ if (p_data_info->flags & WL_PROXD_REQUEST_ACKED) {
+ if (p_data_info->num_meas)
+ printf("(%s)", pstatestr[p_data_info->num_meas]);
+ else
+ printf("(FTM1/REQSENT/ACKED)");
+ } else {
+ printf("(FTM1/REQSENT/NOACK)");
+ }
+ } else {
+ printf("(NO_REQ_SENT)");
+ }
+ printf("(LTFSEQ %sSTARTED)\n", (p_data_info->flags & WL_PROXD_LTFSEQ_STARTED)? "":"not ");
+
+ /* display detail if available */
+ num_rtt = ltoh16_ua(&p_data_info->num_rtt);
+ if (num_rtt > 0)
+ {
+ printf(">\tnum rtt: %d samples\n", num_rtt);
+ p_sample = &p_data_info->rtt[0];
+ for (i = 0; i < num_rtt; i++)
+ {
+ uint16 snr = 0, bitflips = 0;
+ int16 rssi = 0;
+ int32 dist = 0;
+ /* FTM frames 1,4,7,11 have valid snr, rssi and bitflips */
+ if ((i%TOF_DEFAULT_FTMCNT_SEQ) == 1) {
+ rssi = (wl_proxd_rssi_t) ltoh16_ua(&p_sample->rssi);
+ snr = (wl_proxd_snr_t) ltoh16_ua(&p_sample->snr);
+ bitflips = (wl_proxd_bitflips_t) ltoh16_ua(&p_sample->bitflips);
+ dist = ltoh32_ua(&p_sample->distance);
+ } else {
+ rssi = -1;
+ snr = 0;
+ bitflips = 0;
+ dist = 0;
+ }
+ printf(">\t sample[%d]: id=%d rssi=%d snr=%d bitflips=%d "
+ "dist=%d rtt=%d%s status %s Type %s coreid=%d\n",
+ i, p_sample->id, rssi, snr, bitflips, dist,
+ ltoh32_ua(&p_sample->rtt.intvl),
+ ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)),
+ ftm_status_value_to_logstr(ltoh32_ua(&p_sample->status)),
+ ftm_frame_types[i % TOF_DEFAULT_FTMCNT_SEQ], p_sample->coreid);
+ p_sample++;
+ }
+ }
+ return;
+}
+
+/*
+* unpack and display session_info TLV (WL_PROXD_TLV_ID_SESSION_INFO)
+*/
+static void
+ftm_unpack_and_display_session_info(const uint8 *p_data, uint16 tlvid, uint16 len)
+{
+ wl_proxd_ftm_session_info_t *p_data_info;
+ wl_proxd_session_state_t session_state;
+ wl_proxd_status_t proxd_status;
+
+ UNUSED_PARAMETER(len);
+
+ p_data_info = (wl_proxd_ftm_session_info_t *) p_data;
+
+ printf("> %s: bssidx=%d, bssid=%s\n",
+ ftm_tlvid_to_logstr(tlvid),
+ p_data_info->bss_index,
+ wl_ether_etoa(&p_data_info->bssid));
+
+ session_state = ltoh16_ua(&p_data_info->state);
+ proxd_status = ltoh32_ua(&p_data_info->status);
+
+ printf("\tsessionId=%d, state=%d(%s), status=%d(%s), burst_num=%d, "
+ "meas_start %u.%u\n",
+ ltoh16_ua(&p_data_info->sid),
+ session_state,
+ ftm_session_state_value_to_logstr(session_state),
+ proxd_status,
+ ftm_status_value_to_logstr(proxd_status),
+ ltoh16_ua(&p_data_info->burst_num),
+ ltoh32_ua(&p_data_info->meas_start_hi), ltoh32_ua(&p_data_info->meas_start_lo));
+
+ return;
+}
+
+/*
+* unpack and display session status TLV (WL_PROXD_TLV_ID_SESSION_STATUS)
+*/
+static void
+ftm_unpack_and_display_session_status(const uint8 *p_data, uint16 tlvid, uint16 len)
+{
+ wl_proxd_ftm_session_status_t *p_data_info;
+ wl_proxd_session_state_t session_state;
+ wl_proxd_status_t proxd_status;
+
+ UNUSED_PARAMETER(len);
+
+ p_data_info = (wl_proxd_ftm_session_status_t *) p_data;
+ session_state = ltoh16_ua(&p_data_info->state);
+ proxd_status = ltoh32_ua(&p_data_info->status);
+ printf("> %s: sessionId=%d, state=%d(%s), status=%d(%s), burst_num=%d\n",
+ ftm_tlvid_to_logstr(tlvid),
+ ltoh16_ua(&p_data_info->sid),
+ session_state,
+ ftm_session_state_value_to_logstr(session_state),
+ proxd_status,
+ ftm_status_value_to_logstr(proxd_status),
+ ltoh16_ua(&p_data_info->burst_num));
+
+ return;
+}
+
+/*
+* unpack and display session_id lists TLV (WL_PROXD_TLV_ID_COUNTERS)
+*/
+static void
+ftm_unpack_and_display_counters(const uint8 *p_data, uint16 tlvid, uint16 len)
+{
+ wl_proxd_counters_t *p_data_info;
+
+ UNUSED_PARAMETER(len);
+
+ p_data_info = (wl_proxd_counters_t *) p_data;
+ printf("> %s:\n\ttx-frame-count=%d, rx-frame_count=%d\n",
+ ftm_tlvid_to_logstr(tlvid),
+ ltoh32_ua(&p_data_info->tx), /* tx frame count */
+ ltoh32_ua(&p_data_info->rx)); /* rx frame count */
+
+ printf("\tnoack=%d, txfail=%d num_meas=%d\n",
+ ltoh32_ua(&p_data_info->noack), /* tx w/o ack */
+ ltoh32_ua(&p_data_info->txfail), /* tx failures */
+ ltoh32_ua(&p_data_info->num_meas)); /* tx failures */
+
+ printf("\tburst=%d, sessions=%d, max_sessions=%d\n",
+ ltoh32_ua(&p_data_info->burst), /* # of burst */
+ ltoh32_ua(&p_data_info->sessions), /* # of sessions */
+ ltoh32_ua(&p_data_info->max_sessions)); /* max concurrency */
+
+ printf("\tsched_fail=%d, timeouts=%d, protocol errors=%d\n",
+ ltoh32_ua(&p_data_info->sched_fail), /* scheduling failures */
+ ltoh32_ua(&p_data_info->timeouts), /* timeouts */
+ ltoh32_ua(&p_data_info->protoerr)); /* protocol err */
+
+ printf("\tLCI: tx request=%d, rx request=%d, tx report=%d, rx report=%d\n",
+ ltoh32_ua(&p_data_info->lci_req_tx), /* tx LCI requests */
+ ltoh32_ua(&p_data_info->lci_req_rx), /* rx LCI requests */
+ ltoh32_ua(&p_data_info->lci_rep_tx), /* tx LCI reports */
+ ltoh32_ua(&p_data_info->lci_rep_rx)); /* rx LCI reports */
+
+ printf("\tcivic: tx request=%d, rx request=%d, tx report=%d, "
+ "rx report=%d\n",
+ ltoh32_ua(&p_data_info->civic_req_tx), /* tx civic requests */
+ ltoh32_ua(&p_data_info->civic_req_rx), /* rx civic requests */
+ ltoh32_ua(&p_data_info->civic_rep_tx), /* tx civic reports */
+ ltoh32_ua(&p_data_info->civic_rep_rx)); /* rx civic reports */
+
+ printf("\tranging: created=%d, done=%d\n",
+ ltoh32_ua(&p_data_info->rctx), ltoh32_ua(&p_data_info->rctx_done));
+
+ printf("\tpublish errors=%d\n", ltoh32_ua(&p_data_info->publish_err));
+ printf("\tsched on_chan=%d off_chan=%d\n", ltoh32_ua(&p_data_info->on_chan),
+ ltoh32_ua(&p_data_info->off_chan));
+ printf("\ttsf %u.%u\n",
+ ltoh32_ua(&p_data_info->tsf_hi),
+ ltoh32_ua(&p_data_info->tsf_lo));
+ return;
+}
+
+/*
+* unpack and display session_id lists TLV (WL_PROXD_TLV_ID_SESSION_ID_LIST)
+*/
+static void
+ftm_unpack_and_display_session_idlist(const uint8 *p_data, uint16 tlvid, uint16 len)
+{
+ wl_proxd_session_id_list_t *p_data_info;
+ int i;
+ uint16 num_ids;
+
+ UNUSED_PARAMETER(len);
+
+ p_data_info = (wl_proxd_session_id_list_t *) p_data;
+ num_ids = ltoh16_ua(&p_data_info->num_ids);
+ printf("> %s: total %d id(s)\n", ftm_tlvid_to_logstr(tlvid), num_ids);
+
+ for (i = 0; i < num_ids; i++) {
+ printf(">\tsession[%d]: %d\n", i, ltoh16_ua(&p_data_info->ids[i]));
+ }
+
+ return;
+}
+
+/*
+* unpack and display availability TLV
+*/
+static void
+ftm_unpack_and_display_avail(const uint8 *p_data, uint16 tlvid, uint16 len)
+{
+ wl_proxd_avail_t *avail;
+ wl_proxd_avail24_t *avail24;
+ wl_proxd_avail_t l_avail;
+ wl_proxd_avail_flags_t flags;
+ wl_proxd_time_ref_t time_ref;
+ uint16 num_slots;
+ wl_proxd_time_slot_t *avail_slot;
+ chanspec_t chanspec;
+ int i;
+ char dispbuf[256];
+
+ UNUSED_PARAMETER(len);
+
+ /* unpack and format the avail-header for display */
+ if (tlvid == WL_PROXD_TLV_ID_AVAIL24) {
+ avail24 = (wl_proxd_avail24_t *) p_data;
+ /* convert the old version */
+ l_avail.flags = avail24->flags;
+ l_avail.time_ref = avail24->time_ref;
+ l_avail.num_slots = avail24->num_slots;
+ l_avail.max_slots = avail24->max_slots;
+ l_avail.repeat = avail24->repeat;
+ avail = &l_avail;
+
+ avail_slot = &avail24->ts0[0];
+ }
+ else { /* WL_PROXD_TLV_ID_AVAIL */
+ avail = (wl_proxd_avail_t *) p_data;
+ avail_slot = WL_PROXD_AVAIL_TIMESLOTS(avail);
+ }
+
+ flags = ltoh16_ua(&avail->flags);
+ time_ref = ltoh16_ua(&avail->time_ref);
+ num_slots = ltoh16_ua(&avail->num_slots);
+
+ printf("> %s:\n>\tflags=0x%04x('%s'), time-ref=0x%04x('%s'), "
+ "period=%d%s, num_slots=%d, max_slots=%d\n",
+ ftm_tlvid_to_logstr(tlvid),
+ flags, ftm_avail_flags_value_to_logstr(flags),
+ time_ref, ftm_avail_timeref_value_to_logstr(time_ref),
+ ltoh32_ua(&avail->repeat.intvl),
+ ftm_tmu_value_to_logstr(ltoh16_ua(&avail->repeat.tmu)),
+ num_slots, ltoh16_ua(&avail->max_slots));
+
+ /* unpack and format the time slots for display */
+ for (i = 0; i < num_slots; i++) {
+ printf(">\tslots[%d]: start: %d%s duration: %d%s",
+ i, ltoh32_ua(&avail_slot->start.intvl),
+ ftm_tmu_value_to_logstr(ltoh16_ua(&avail_slot->start.tmu)),
+ ltoh32_ua(&avail_slot->duration.intvl),
+ ftm_tmu_value_to_logstr(ltoh16_ua(&avail_slot->duration.tmu)));
+
+ chanspec = (chanspec_t) ltoh32_ua(&avail_slot->chanspec);
+ if (wf_chspec_valid(chanspec)) {
+ memset(dispbuf, 0, sizeof(dispbuf));
+ wf_chspec_ntoa(chanspec, dispbuf);
+ printf(" chanspec: 0x%04x(%s)\n", chanspec, dispbuf);
+ }
+ else {
+ printf(" chanspec: 0x%04x(invalid)\n", chanspec);
+ }
+ avail_slot++;
+ }
+}
+
+/*
+* unpack and display session_info TLV (WL_PROXD_TLV_ID_RANGING_INFO)
+*/
+static void
+ftm_unpack_and_display_ranging_info(const uint8 *p_data, uint16 tlvid, uint16 len)
+{
+ wl_proxd_ranging_info_t *p_data_info;
+ wl_proxd_status_t proxd_status;
+ wl_proxd_ranging_state_t state;
+ wl_proxd_ranging_flags_t flags;
+
+ UNUSED_PARAMETER(len);
+
+ p_data_info = (wl_proxd_ranging_info_t *) p_data;
+
+ printf("> %s:\n", ftm_tlvid_to_logstr(tlvid));
+
+ proxd_status = ltoh32_ua(&p_data_info->status);
+ state = ltoh16_ua(&p_data_info->state);
+ flags = ltoh16_ua(&p_data_info->flags);
+
+ printf("\tstatus=%d(%s), state=%d(%s), flags=0x%04x(%s), num_sids=%d, num_done=%d\n",
+ proxd_status,
+ ftm_status_value_to_logstr(proxd_status),
+ state,
+ ftm_ranging_state_value_to_logstr(state),
+ flags,
+ ftm_ranging_flags_value_to_logstr(flags),
+ ltoh16_ua(&p_data_info->num_sids),
+ ltoh16_ua(&p_data_info->num_done));
+
+ return;
+}
+
+/*
+ * a callback function, displays (wl_proxd_tlv_t) bcm_xtlv variables rcvd in
+ * get ioctl's xtlv buffer.
+ * -- This function processes GET result for all 'proxd ftm' commands, provided
+ * that XTLV types (AKA the explicit xtlv types) packed into the ioctl buff
+ * are unique across all 'proxd ftm' ioctl commands
+ * -- This function is also used to display rx FTM events (content in XTLVs),
+ * see ftm_event_check().
+ */
+static int
+ftm_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len)
+{
+ int res = BCME_OK;
+ char dispbuf[256];
+ wl_proxd_event_type_t event_data;
+ char event_dispbuf[256];
+ chanspec_t chanspec;
+ wl_proxd_intvl_t *p_data_intvl;
+ wl_proxd_ftm_info_t *p_data_info;
+ wl_proxd_tpk_t *tpk_info;
+
+
+#ifdef WL_FTM_DEBUG
+ /* for 'get' commands :
+ wl_proxd_iov_t *p_proxd_iov = (wl_proxd_iov_t *) ctx;
+ for event_check:
+ ctx is NULL
+ */
+ printf("enter %s(ctx=%p, data=%p, tlvid=%d, len=%d)...\n",
+ __FUNCTION__, ctx, p_data, tlvid, len);
+#else
+ UNUSED_PARAMETER(ctx);
+#endif /* WL_FTM_DEBUG */
+
+ memset(dispbuf, 0, sizeof(dispbuf)); /* clear the buffer for display */
+
+ switch (tlvid) {
+ /* data=uint8 as a number, display in decimal */
+ case WL_PROXD_TLV_ID_BSS_INDEX:
+ case WL_PROXD_TLV_ID_FTM_RETRIES: /* at FTM level */
+ case WL_PROXD_TLV_ID_FTM_REQ_RETRIES:
+ printf("> %s: %d\n", ftm_tlvid_to_logstr(tlvid), *p_data);
+ break;
+
+ /* data=uint16 as a number, display in decimal */
+ case WL_PROXD_TLV_ID_BURST_NUM_FTM: /* per burst */
+ case WL_PROXD_TLV_ID_NUM_BURST:
+ case WL_PROXD_TLV_ID_RX_MAX_BURST:
+ printf("> %s: %d\n", ftm_tlvid_to_logstr(tlvid), ltoh16_ua(p_data));
+ break;
+
+ /* data=uin32 as a number, display in decimal */
+ case WL_PROXD_TLV_ID_NONE:
+ case WL_PROXD_TLV_ID_TX_POWER:
+ case WL_PROXD_TLV_ID_STATUS: /* not used ? SJL_FIXME */
+ case WL_PROXD_TLV_ID_NAN_MAP_ID:
+ printf("> %s: %d\n", ftm_tlvid_to_logstr(tlvid), ltoh32_ua(p_data));
+ break;
+
+ /* data=uint32 as a number, display in hex */
+ case WL_PROXD_TLV_ID_RATESPEC:
+ case WL_PROXD_TLV_ID_DEBUG_MASK:
+ case WL_PROXD_TLV_ID_RANGING_FLAGS:
+ case WL_PROXD_TLV_ID_RANGING_FLAGS_MASK:
+ printf("> %s: 0x%x\n", ftm_tlvid_to_logstr(tlvid), ltoh32_ua(p_data));
+ break;
+
+ /* data=uint32 as a number, display in hex */
+ case WL_PROXD_TLV_ID_FLAGS:
+ case WL_PROXD_TLV_ID_FLAGS_MASK:
+ ftm_unpack_and_display_config_flags(p_data, tlvid);
+ break;
+
+ /* data=uint32 as a number, display in hex */
+ case WL_PROXD_TLV_ID_SESSION_FLAGS:
+ case WL_PROXD_TLV_ID_SESSION_FLAGS_MASK:
+ ftm_unpack_and_display_session_flags(p_data, tlvid);
+ break;
+
+ /* data=uint32 as a number, display in hex */
+ case WL_PROXD_TLV_ID_EVENT_MASK:
+ {
+ event_data = ltoh32_ua(p_data);
+ event_dispbuf[0] = '\0';
+#ifdef WL_FTM_DEBUG
+ /* convert to a readable text-string */
+ ftm_format_event_mask(event_data, event_dispbuf, sizeof(event_dispbuf));
+#endif /* WL_FTM_DEBUG */
+ printf("> %s: 0x%x %s\n",
+ ftm_tlvid_to_logstr(tlvid), event_data, event_dispbuf);
+ }
+ break;
+
+ /* data=uin32 as a number, convert and display a text-string */
+ case WL_PROXD_TLV_ID_METHOD:
+ printf("> %s: %s\n", ftm_tlvid_to_logstr(tlvid),
+ ftm_method_value_to_logstr((wl_proxd_method_t) ltoh32_ua(p_data)));
+ break;
+
+ /* data=uint32 as a chanspec */
+ case WL_PROXD_TLV_ID_CHANSPEC:
+ {
+ chanspec = (chanspec_t) ltoh32_ua(p_data);
+ if (wf_chspec_valid(chanspec)) {
+ wf_chspec_ntoa(chanspec, dispbuf);
+ printf("> %s: %s 0x%04x\n",
+ ftm_tlvid_to_logstr(tlvid), dispbuf, chanspec);
+ } else {
+ printf("> %s: invalid 0x%04x\n",
+ ftm_tlvid_to_logstr(tlvid), chanspec);
+ }
+ }
+ break;
+
+ /* data=intvl */
+ case WL_PROXD_TLV_ID_BURST_DURATION:
+ case WL_PROXD_TLV_ID_BURST_PERIOD:
+ case WL_PROXD_TLV_ID_BURST_FTM_SEP:
+ case WL_PROXD_TLV_ID_INIT_DELAY:
+ case WL_PROXD_TLV_ID_BURST_TIMEOUT:
+ {
+ p_data_intvl = (wl_proxd_intvl_t *) p_data;
+ printf("> %s: %d%s\n", ftm_tlvid_to_logstr(tlvid),
+ ltoh32_ua(&p_data_intvl->intvl),
+ ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_intvl->tmu)));
+ }
+ break;
+
+ case WL_PROXD_TLV_ID_BSSID:
+ case WL_PROXD_TLV_ID_PEER_MAC:
+ case WL_PROXD_TLV_ID_DEV_ADDR:
+ printf("> %s: %s\n", ftm_tlvid_to_logstr(tlvid),
+ wl_ether_etoa((struct ether_addr *)p_data));
+ break;
+
+ case WL_PROXD_TLV_ID_TPK:
+ {
+ tpk_info = (wl_proxd_tpk_t *)p_data;
+ printf("> %s: mac addr%s \n", ftm_tlvid_to_logstr(tlvid),
+ wl_ether_etoa((struct ether_addr *)&tpk_info->peer));
+ }
+ break;
+
+ case WL_PROXD_TLV_ID_INFO: /* data=wl_proxd_ftm_info_t */
+ {
+ p_data_info = (wl_proxd_ftm_info_t *) p_data;
+ printf("> %s: capabilities=%s, max sessions=%d, num sessions=%d,"
+ "rx_max_burst=%d\n",
+ ftm_tlvid_to_logstr(tlvid),
+ ftm_caps_value_to_logstr(ltoh16_ua(&p_data_info->caps)),
+ ltoh16_ua(&p_data_info->max_sessions),
+ ltoh16_ua(&p_data_info->num_sessions),
+ ltoh16_ua(&p_data_info->rx_max_burst));
+ }
+ break;
+
+ case WL_PROXD_TLV_ID_FTM_REQ: /* data=dot11_ftm_req_t, var-len */
+ printf("> %s: data-len=%d byte(s)\n",
+ ftm_tlvid_to_logstr(tlvid), len);
+ if (len > 0)
+ prhex(NULL, (uint8 *)p_data, len);
+ break;
+
+ case WL_PROXD_TLV_ID_RTT_RESULT: /* data=wl_proxd_rtt_result_t */
+ ftm_unpack_and_display_rtt_result(p_data, tlvid, len);
+ break;
+
+ case WL_PROXD_TLV_ID_SESSION_INFO: /* data=wl_proxd_ftm_session_info_t */
+ ftm_unpack_and_display_session_info(p_data, tlvid, len);
+ break;
+
+ case WL_PROXD_TLV_ID_SESSION_STATUS: /* data=wl_proxd_ftm_session_status_t */
+ ftm_unpack_and_display_session_status(p_data, tlvid, len);
+ break;
+
+ case WL_PROXD_TLV_ID_COUNTERS: /* data=wl_proxd_counters_t */
+ ftm_unpack_and_display_counters(p_data, tlvid, len);
+ break;
+
+ case WL_PROXD_TLV_ID_SESSION_ID_LIST: /* data=wl_proxd_session_id_list */
+ ftm_unpack_and_display_session_idlist(p_data, tlvid, len);
+ break;
+
+ case WL_PROXD_TLV_ID_RANGING_INFO: /* data=wl_proxd_ranging_info_t */
+ ftm_unpack_and_display_ranging_info(p_data, tlvid, len);
+ break;
+
+ case WL_PROXD_TLV_ID_STRBUF:
+ if (len > 0)
+ printf("> %s:\n%s\n", ftm_tlvid_to_logstr(tlvid), p_data);
+ break;
+
+ case WL_PROXD_TLV_ID_AVAIL24:
+ case WL_PROXD_TLV_ID_AVAIL:
+ ftm_unpack_and_display_avail(p_data, tlvid, len);
+ break;
+
+ case WL_PROXD_TLV_ID_LCI:
+ case WL_PROXD_TLV_ID_CIVIC:
+ printf("> %s: data-len=%d byte(s)\n",
+ ftm_tlvid_to_logstr(tlvid), len);
+ if (len > 0)
+ prhex(NULL, (uint8*)p_data, len);
+ break;
+ case WL_PROXD_TLV_ID_TUNE:
+ res = proxd_tune_display((wl_proxd_params_tof_tune_t *)p_data, len);
+ break;
+ case WL_PROXD_TLV_ID_AOA_RESULT: /* SJL_FIXME */
+ case WL_PROXD_TLV_ID_COLLECT: /* SJL_FIXME */
+ case WL_PROXD_TLV_ID_LCI_REQ: /* SJL_FIXME */
+ case WL_PROXD_TLV_ID_CIVIC_REQ: /* SJL_FIXME */
+ /* fall thru (not used/supported now) */
+ default:
+ printf("> Unsupported %s: %d\n", ftm_tlvid_to_logstr(tlvid), tlvid);
+ res = BCME_ERROR;
+ break;
+ }
+
+ return res;
+}
+
+/* pack TLVs for checking if a specific tlv-id is supported or not
+* for WL_PROXD_CMD_IS_TLV_SUPPORTED
+*/
+static int
+ftm_pack_tlv_id_support(uint8 *buf, uint16 bufsize, void *ctx, uint16 *all_tlvsize)
+{
+ int err = BCME_OK;
+ uint16 buf_space_left;
+ uint16 tlv_id;
+ wl_proxd_tlv_t *p_tlv = (wl_proxd_tlv_t *) buf;
+
+ *all_tlvsize = 0;
+
+ if (!ctx)
+ return BCME_BADARG;
+
+ /* TLV buffer starts with a full size, will decrement for each packed TLV */
+ buf_space_left = bufsize;
+
+ tlv_id = htol16(*((uint16 *) ctx));
+ err = bcm_pack_xtlv_entry((uint8 **) &p_tlv, &buf_space_left,
+ WL_PROXD_TLV_ID_TLV_ID, sizeof(uint16), (void *) &tlv_id,
+ BCM_XTLV_OPTION_ALIGN32);
+ if (err != BCME_OK) {
+ printf("%s: failed to pack TLVs, err=%d\n",
+ __FUNCTION__, err);
+ goto done;
+ }
+
+ /* return the len to include all TLVs(including TLV header) */
+ *all_tlvsize = (bufsize - buf_space_left);
+
+done:
+ return err;
+}
+
+/*
+* check if a tlv-id is supported:
+* return BCME_OK if tlv-id is supported
+*/
+static int
+ftm_is_tlv_id_supported(void *wl, uint16 tlv_id)
+{
+ int err;
+ wl_proxd_iov_t *p_proxd_iov;
+ uint16 proxd_iovsize;
+ uint16 all_tlvsize = 0;
+ wl_proxd_iov_t *p_iovresp = NULL;
+
+ /* alloc mem for ioctl header + reserved bufsize for tlvs (initialize to zero) */
+ p_proxd_iov = ftm_alloc_getset_buf(WL_PROXD_METHOD_FTM,
+ WL_PROXD_SESSION_ID_GLOBAL, WL_PROXD_CMD_IS_TLV_SUPPORTED,
+ FTM_IOC_BUFSZ, &proxd_iovsize);
+ if (p_proxd_iov == NULL) {
+ err = BCME_NOMEM;
+ goto done;
+ }
+
+ /* Setup TLVs -- pack a TLV_ID for support checking */
+ err = ftm_pack_tlv_id_support((uint8 *) &p_proxd_iov->tlvs[0],
+ proxd_iovsize - WL_PROXD_IOV_HDR_SIZE,
+ (void *) &tlv_id, &all_tlvsize);
+ if (err != BCME_OK)
+ goto done;
+
+ /* update the iov header, set len to include all TLVs + header */
+ proxd_iovsize = all_tlvsize + WL_PROXD_IOV_HDR_SIZE;
+ p_proxd_iov->len = htol16(proxd_iovsize);
+
+ /* submit a 'get' request to see if the tlv-id is supported or not */
+ err = wlu_var_getbuf(wl, "proxd", p_proxd_iov, proxd_iovsize, (void *) &p_iovresp);
+
+done:
+ /* clean up */
+ free(p_proxd_iov);
+
+ return err;
+
+}
+
+/*
+* send 'proxd' iovar for all ftm get-related commands
+*/
+static int
+ftm_do_get_ioctl(void *wl, wl_proxd_iov_t *p_proxd_iov, uint16 proxd_iovsize,
+ const ftm_subcmd_info_t *p_subcmd_info)
+{
+
+ /* for gets we only need to pass ioc header */
+ wl_proxd_iov_t *p_iovresp = NULL;
+ int status;
+
+ /* send getbuf proxd iovar */
+ status = wlu_var_getbuf(wl, "proxd", p_proxd_iov, proxd_iovsize, (void *)&p_iovresp);
+ if (status != BCME_OK) {
+#ifdef WL_FTM_DEBUG
+ printf("%s: failed to send getbuf proxd iovar, status=%d\n",
+ __FUNCTION__, status);
+#endif /* WL_FTM_DEBUG */
+ return status;
+ }
+
+ if (p_iovresp != NULL) {
+ int tlvs_len = ltoh16(p_iovresp->len) - WL_PROXD_IOV_HDR_SIZE;
+ if (tlvs_len < 0)
+ {
+#ifdef WL_FTM_DEBUG
+ printf("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n",
+ __FUNCTION__, ltoh16(p_iovresp->len), (int) WL_PROXD_IOV_HDR_SIZE);
+#endif /* WL_FTM_DEBUG */
+ tlvs_len = 0;
+ }
+
+ if (p_subcmd_info->cmdid == WL_PROXD_CMD_GET_VERSION) /* 'wl proxd ftm version' */
+ printf("> version: 0x%x\n", ltoh16(p_iovresp->version));
+
+#ifdef WL_FTM_DEBUG
+ printf("%s: p_iovresp->(tlvs=%p,len=%d), tlvs_len=%d, cmdid=%d(%s) ver=0x%x\n",
+ __FUNCTION__, p_iovresp->tlvs, ltoh16(p_iovresp->len), tlvs_len,
+ ltoh16(p_iovresp->cmd), ftm_cmdid_to_str(ltoh16(p_iovresp->cmd)),
+ ltoh16(p_iovresp->version));
+#endif /* WL_FTM_DEBUG */
+
+ if (tlvs_len > 0)
+ {
+ /* unpack TLVs and invokes the cbfn for processing */
+ status = bcm_unpack_xtlv_buf(p_proxd_iov, (uint8 *)p_iovresp->tlvs,
+ tlvs_len, BCM_XTLV_OPTION_ALIGN32, ftm_unpack_xtlv_cbfn);
+ printf("\n");
+ }
+ }
+
+ return status;
+}
+
+/*
+* common handler for all get-related proxd method commands (no TLVs params for these commands)
+* wl proxd ftm [session-id] <get-subcmd>
+* where <get-subcmd> can be "ver", "result", "info", "status",
+* "sessions", "counters", "dump"
+* Note, this <get-subcmd> does not accept any parameters (i.e. no <param-name><param-value>)
+*/
+static int
+ftm_common_getcmd_handler(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ int status = BCME_OK;
+ uint16 proxd_iovsize = 0;
+
+#ifdef WL_FTM_DEBUG
+ printf("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
+ __FUNCTION__, method, session_id, p_subcmd_info->cmdid,
+ ftm_cmdid_to_str(p_subcmd_info->cmdid));
+#endif /* WL_FTM_DEBUG */
+
+ /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */
+ wl_proxd_iov_t *p_proxd_iov;
+ p_proxd_iov = ftm_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid,
+ 0, &proxd_iovsize);
+ if (p_proxd_iov == NULL)
+ return BCME_NOMEM;
+
+ if (*argv == NULL) { /* get */
+ status = ftm_do_get_ioctl(wl, p_proxd_iov, proxd_iovsize, p_subcmd_info);
+ } else {
+ printf("error: proxd ftm %s cmd doesn't accept any parameters\n",
+ p_subcmd_info->name);
+ status = BCME_ERROR;
+ }
+
+ /* clean up */
+ free(p_proxd_iov);
+
+#ifdef WL_FTM_DEBUG
+ if (status != BCME_OK)
+ printf("%s failed: status=%d\n", __FUNCTION__, status);
+#endif /* WL_FTM_DEBUG */
+
+ return status;
+}
+
+/*
+* get proxd ftm-method version (API version)
+* Usage: wl proxd ftm ver
+*
+* Note, 'session-id' is ignore
+*/
+static int
+ftm_subcmd_get_version(void *wl, const ftm_subcmd_info_t *p_subcmd_info, wl_proxd_method_t method,
+ wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar and display the 'version' */
+ return ftm_common_getcmd_handler(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* get session result - may be in progress. Both rtt and aoa results returned (as available).
+* Also lci and civic location if available.
+* Usage: wl proxd ftm <session-id> result
+* Note, caller should have verified the session-id before this call.
+*/
+static int
+ftm_subcmd_get_result(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar and display the 'session result' */
+ return ftm_common_getcmd_handler(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* get the global ftm-method info or session-info if session-id is specified.
+* Usage:
+* wl proxd ftm [<session-id>] info
+*/
+static int
+ftm_subcmd_get_info(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar and display the 'method/session info' */
+ return ftm_common_getcmd_handler(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* get the ftm-method status or session status if session-id is specified.
+* Usage: wl proxd ftm [<session-id>] status
+*/
+static int
+ftm_subcmd_get_status(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar and display the 'method/session status' */
+ return ftm_common_getcmd_handler(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* list all sessions for the ftm method
+* Usage: wl proxd ftm sessions
+*/
+static int
+ftm_subcmd_get_sessions(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar and display the 'sessions' */
+ return ftm_common_getcmd_handler(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* get the ftm-method counters or sessions counters if session-id is specified.
+* Usage:wl proxd ftm [<session-id>] counters
+*/
+static int
+ftm_subcmd_get_counters(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar and display the 'method/session counters' */
+ return ftm_common_getcmd_handler(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* get the global ftm-method ranging-info
+* Usage:
+* wl proxd ftm ranging-info
+*/
+static int
+ftm_subcmd_get_ranging_info(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar and display the 'ranging info' */
+ return ftm_common_getcmd_handler(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* dump the ftm-method or a session if session-id is specified.
+* Usage: wl proxd ftm [<session-id>] dump
+*/
+static int
+ftm_subcmd_dump(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar and display the 'dump result' */
+ return ftm_common_getcmd_handler(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/* ***************************** set commands ********************* */
+
+/*
+* common handler for set-related proxd method commands which require no TLV as input
+* wl proxd ftm [session-id] <set-subcmd>
+* e.g.
+* wl proxd ftm enable -- to enable ftm
+* wl proxd ftm disable -- to disable ftm
+* wl proxd ftm <session-id> start -- to start a specified session
+* wl proxd ftm <session-id> stop -- to cancel a specified session;
+* state is maintained till session is delete.
+* wl proxd ftm <session-id> delete -- to delete a specified session
+* wl proxd ftm [<session-id>] clear-counters -- to clear counters
+* wl proxd ftm <session-id> burst-request -- on initiator: to send burst request;
+* on target: send FTM frame
+* wl proxd ftm <session-id> collect
+* wl proxd ftm tune (TBD)
+*/
+static int
+ftm_subcmd_setiov_no_tlv(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ uint16 proxd_iovsize;
+ wl_proxd_iov_t *p_proxd_iov;
+ int res;
+
+ UNUSED_PARAMETER(wl);
+
+#ifdef WL_FTM_DEBUG
+ printf("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
+ __FUNCTION__, method, session_id,
+ p_subcmd_info->cmdid, ftm_cmdid_to_str(p_subcmd_info->cmdid));
+#endif /* WL_FTM_DEBUG */
+
+ /* do not accept any parameters */
+ if (*argv != NULL)
+ {
+ printf("error: proxd ftm %s cmd doesn't accept any parameters\n",
+ p_subcmd_info->name);
+ return BCME_USAGE_ERROR;
+ }
+
+ /* allocate and initialize a temp buffer for 'set proxd' iovar */
+ proxd_iovsize = 0;
+ p_proxd_iov = ftm_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid,
+ 0, &proxd_iovsize); /* no TLV */
+ if (p_proxd_iov == NULL)
+ return BCME_NOMEM;
+
+ /* no TLV to pack, simply issue a set-proxd iovar */
+ res = wlu_var_setbuf(wl, "proxd", (void *) p_proxd_iov, proxd_iovsize);
+ if (res != BCME_OK) {
+ printf("error: IOVAR failed, status=%d\n", res);
+ }
+
+ /* clean up */
+ free(p_proxd_iov);
+
+ return res;
+}
+
+/*
+* enable FTM method
+* Usage: wl proxd ftm enable
+*/
+static int
+ftm_subcmd_enable(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar call */
+ return ftm_subcmd_setiov_no_tlv(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* disable FTM method
+* Usage: wl proxd ftm disable
+*/
+static int
+ftm_subcmd_disable(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar call */
+ return ftm_subcmd_setiov_no_tlv(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* start scheduling the burst(s) for the session. Initiates FTM request or await requests on target.
+* Usage: wl proxd ftm <session-id> start
+*
+* Note, caller should have verified the session-id before this call.
+*/
+static int
+ftm_subcmd_start_session(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar call */
+ return ftm_subcmd_setiov_no_tlv(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* cancel the session. State maintained until session is deleted.
+* Usage: wl proxd ftm <session-id> stop
+*
+* Note, caller should have verify the session-id before this call.
+*/
+static int ftm_subcmd_stop_session(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar call */
+ return ftm_subcmd_setiov_no_tlv(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* burst request: on initiator send burst request and process FTM frames.
+* On target, send FTM frames
+* Usage: wl proxd ftm <session-id> burst-request
+*
+* Note, caller should have verified the session-id before this call.
+*/
+static int
+ftm_subcmd_burst_request(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar call */
+ return ftm_subcmd_setiov_no_tlv(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* delete the session.
+* Usage: wl proxd ftm <session-id> delete
+*
+* Note, caller should have verify the session-id before this call.
+*/
+static int
+ftm_subcmd_delete_session(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar call */
+ return ftm_subcmd_setiov_no_tlv(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* clear counters
+* Usage: wl proxd ftm [<session-id>] clear_counters
+*
+* Note, caller should have verify the session-id before this call.
+*/
+static int
+ftm_subcmd_clear_counters(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* issue an iovar call */
+ return ftm_subcmd_setiov_no_tlv(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* define param-info for global/session 'non-options' configuration for
+* 'wl proxd ftm [<session-id>] config [<param-name> <param-value>]*'
+*/
+typedef struct ftm_config_param_info {
+ char *name; /* <param-name> string to identify a configurable item */
+ uint16 tlvid; /* mapping TLV id for the item */
+ char *name_helpmsg; /* help message for the <param-name> config-item */
+ ftm_subcmd_flag_t cmdflag; /* supported group(s) */
+} ftm_config_param_info_t;
+
+static const ftm_config_param_info_t ftm_config_param_info[] = {
+ /* "name", tlv_id param-name helpmsg */
+ { "bssidx", WL_PROXD_TLV_ID_BSS_INDEX, "BSS index to use for the session",
+ FTM_SUBCMD_FLAG_ALL },
+ { "chanspec", WL_PROXD_TLV_ID_CHANSPEC, "channel spec to use",
+ FTM_SUBCMD_FLAG_ALL },
+ { "tx-power", WL_PROXD_TLV_ID_TX_POWER, "tx power to use in dbm",
+ FTM_SUBCMD_FLAG_ALL },
+ { "ratespec", WL_PROXD_TLV_ID_RATESPEC, "rate to use",
+ FTM_SUBCMD_FLAG_ALL },
+ { "num-ftm", WL_PROXD_TLV_ID_BURST_NUM_FTM, "number of FTM frames in a burst",
+ FTM_SUBCMD_FLAG_ALL },
+ { "num-burst", WL_PROXD_TLV_ID_NUM_BURST, "number of bursts in the session",
+ FTM_SUBCMD_FLAG_ALL },
+ { "retries", WL_PROXD_TLV_ID_FTM_RETRIES, "number of retries; not 802.11 mac level retries",
+ FTM_SUBCMD_FLAG_ALL },
+ { "event-mask", WL_PROXD_TLV_ID_EVENT_MASK, "bitmask of subscribed events",
+ FTM_SUBCMD_FLAG_ALL },
+ { "debug-mask", WL_PROXD_TLV_ID_DEBUG_MASK, "bitmask for logging FTM messages",
+ FTM_SUBCMD_FLAG_ALL },
+ { "burst-duration", WL_PROXD_TLV_ID_BURST_DURATION, "duration for a single burst",
+ FTM_SUBCMD_FLAG_ALL },
+ { "burst-period", WL_PROXD_TLV_ID_BURST_PERIOD, "time between bursts",
+ FTM_SUBCMD_FLAG_ALL },
+ { "ftm-sep", WL_PROXD_TLV_ID_BURST_FTM_SEP, "time between FTM frames in a burst",
+ FTM_SUBCMD_FLAG_ALL },
+ { "burst-timeout", WL_PROXD_TLV_ID_BURST_TIMEOUT, "timeout",
+ FTM_SUBCMD_FLAG_ALL },
+ { "init-delay", WL_PROXD_TLV_ID_INIT_DELAY, "delay after start",
+ FTM_SUBCMD_FLAG_ALL },
+ { "bssid", WL_PROXD_TLV_ID_BSSID, "BSSID used for the session",
+ FTM_SUBCMD_FLAG_ALL },
+ { "peer", WL_PROXD_TLV_ID_PEER_MAC, "peer mac address",
+ FTM_SUBCMD_FLAG_ALL },
+ { "rx-max-burst", WL_PROXD_TLV_ID_RX_MAX_BURST, "limit bursts for rx(method only)",
+ FTM_SUBCMD_FLAG_METHOD },
+ /* special 'config options', no matching TLV */
+ { "options", WL_PROXD_TLV_ID_NONE,
+ "type 'wl proxd -h ftm config options' for more information",
+ FTM_SUBCMD_FLAG_ALL },
+ { "session-options", WL_PROXD_TLV_ID_NONE,
+ "type 'wl proxd -h ftm config options' for more information",
+ FTM_SUBCMD_FLAG_ALL },
+ { "avail", WL_PROXD_TLV_ID_NONE,
+ "type 'wl proxd -h ftm config avail' for more information",
+ FTM_SUBCMD_FLAG_ALL },
+ { "nan-map-id", WL_PROXD_TLV_ID_NAN_MAP_ID, "NAN map id(method only)",
+ FTM_SUBCMD_FLAG_METHOD },
+ { "dev-addr", WL_PROXD_TLV_ID_DEV_ADDR, "deivce address(method only)",
+ FTM_SUBCMD_FLAG_METHOD },
+ { "req-retries", WL_PROXD_TLV_ID_FTM_REQ_RETRIES, "number of FTM request retries",
+ FTM_SUBCMD_FLAG_ALL },
+ { "tpk", WL_PROXD_TLV_ID_TPK, "tpk to be configured", FTM_SUBCMD_FLAG_ALL }
+};
+
+/* map a specified text-string to a proxd time unit
+*
+* return true if succeeds, otherwise return false.
+*/
+static bool
+ftm_get_tmu_from_str(char *str, wl_proxd_tmu_t *p_tmu)
+{
+ if (stricmp(str, "tu") == 0)
+ *p_tmu = WL_PROXD_TMU_TU;
+ else if (stricmp(str, "s") == 0)
+ *p_tmu = WL_PROXD_TMU_SEC;
+ else if (stricmp(str, "ms") == 0)
+ *p_tmu = WL_PROXD_TMU_MILLI_SEC;
+ else if (stricmp(str, "us") == 0)
+ *p_tmu = WL_PROXD_TMU_MICRO_SEC;
+ else if (stricmp(str, "ns") == 0)
+ *p_tmu = WL_PROXD_TMU_NANO_SEC;
+ else if (stricmp(str, "ps") == 0)
+ *p_tmu = WL_PROXD_TMU_PICO_SEC;
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+* get the config_param_info from the table based on 'param-name' for 'wl proxd ftm config' command
+*
+* return NULL if 'param-name' is not supported
+*/
+static const ftm_config_param_info_t *
+ftm_get_config_param_info(char *p_param_name, wl_proxd_session_id_t session_id)
+{
+ int i;
+ ftm_subcmd_flag_t search_cmdflag;
+ const ftm_config_param_info_t *p_config_param_info;
+
+ /* determine if this is for 'session' or 'method' config */
+ search_cmdflag = (session_id == WL_PROXD_SESSION_ID_GLOBAL) ? FTM_SUBCMD_FLAG_METHOD
+ : FTM_SUBCMD_FLAG_SESSION;
+
+ p_config_param_info = &ftm_config_param_info[0];
+ for (i = 0; i < (int) ARRAYSIZE(ftm_config_param_info); i++) {
+ if (stricmp(p_param_name, p_config_param_info->name) == 0) {
+ /* check if this config-param is supported for method/session */
+ if ((p_config_param_info->cmdflag & search_cmdflag) == 0) {
+ /* not supported for this method/session command */
+ return (ftm_config_param_info_t *) NULL;
+ }
+
+ return p_config_param_info;
+ }
+ p_config_param_info++; /* next */
+ }
+
+ return (ftm_config_param_info_t *) NULL; /* 'invalid param name' */
+}
+
+/*
+* define param-value info for global/session 'options' configuration for
+* 'wl proxd ftm [<session-id>] config options {[+|-]<param-value>}*'
+*/
+typedef struct ftm_config_options_info {
+ char *param_value_str; /* <param-value> str to identify an options-flag */
+ uint32 flags; /* wl_proxd_flags_t/wl_proxd_session_flags_t */
+ char *helpmsg; /* help message for the param-value */
+} ftm_config_options_info_t;
+
+/* global/method config options/flags */
+static const ftm_config_options_info_t ftm_method_options_info[] = {
+ /* param-value-string wl_proxd_flags_t helpmsg */
+ { "rx-enable", WL_PROXD_FLAG_RX_ENABLED,
+ "If enabled, process requests; If disabled, requests will be ignored"},
+ { "rx-range-req", WL_PROXD_FLAG_RX_RANGE_REQ,
+ "If enabled, process 11mc range requests; If disabled, requests will be ignored" },
+ { "tx-lci", WL_PROXD_FLAG_TX_LCI, "transmit LCI, if available" },
+ { "tx-civic", WL_PROXD_FLAG_TX_CIVIC, "tx civic location, if available" },
+ { "rx-auto-burst", WL_PROXD_FLAG_RX_AUTO_BURST,
+ "If enabled, respond to requests without host action.\n"
+ "\t\t "
+ "If disabled, the request is forwarded to host via an event.\n"
+ "\t\t "
+ "If the event is masked, the request is dropped" },
+ { "tx-auto-burst", WL_PROXD_FLAG_TX_AUTO_BURST,
+ "If enabled, continue an initiated session with a new burst without host action\n"
+ "\t\t "
+ "until the number of bursts for the session is completed" },
+ { "avail-publish", WL_PROXD_FLAG_AVAIL_PUBLISH, "publish local availability" },
+ { "avail-schedule", WL_PROXD_FLAG_AVAIL_SCHEDULE, "schedule local availability" },
+ { "asap-capable", WL_PROXD_FLAG_ASAP_CAPABLE, "capable of ASAP scheduling"},
+ { "mburst-followup", WL_PROXD_FLAG_MBURST_FOLLOWUP,
+ "enable multi-burst followup algorithm " },
+ { "secure", WL_PROXD_FLAG_SECURE,
+ "Enable security for ftm - per BSS" },
+ { "all", WL_PROXD_FLAG_ALL, "all of the above" }
+};
+
+/* config session options/flags */
+static const ftm_config_options_info_t ftm_session_options_info[] = {
+ /* param-value-string wl_proxd_session_flags_t helpmsg */
+ { "initiator", WL_PROXD_SESSION_FLAG_INITIATOR, "local device is an initiator" },
+ { "target", WL_PROXD_SESSION_FLAG_TARGET, "local device is a target" },
+ { "one-way", WL_PROXD_SESSION_FLAG_ONE_WAY, "(initiated) 1-way rtt " },
+ { "auto-burst", WL_PROXD_SESSION_FLAG_AUTO_BURST, "created with rx_auto_burst" },
+ { "immediate", WL_PROXD_SESSION_FLAG_MBURST_NODELAY, "immediate next burst" },
+ { "rtt-detail", WL_PROXD_SESSION_FLAG_RTT_DETAIL, "provide rtt detail in results" },
+#ifdef SJL_FIXME
+ { "aoa", WL_PROXD_SESSION_FLAG_AOA, "AOA along with RTT" },
+#endif /* SJL_FIXME */
+ { "rx-auto-burst", WL_PROXD_SESSION_FLAG_RX_AUTO_BURST,
+ "Same as proxd flags above, applies to the session" },
+ { "tx-auto-burst", WL_PROXD_SESSION_FLAG_TX_AUTO_BURST,
+ "Same as proxd flags above, applies to the session" },
+ { "nan-bss", WL_PROXD_SESSION_FLAG_NAN_BSS, "Use NAN BSS, if applicable" },
+ { "ts1", WL_PROXD_SESSION_FLAG_TS1, "FTM1 - ASAP-capable" }, /* readonly */
+#ifdef SJL_FIXME
+ { "rpt-failure", WL_PROXD_SESSION_FLAG_REPORT_FAILURE,
+ "(target) report not rx distance to host" },
+#endif /* SJL_FIXME */
+ { "initiator-rpt", WL_PROXD_SESSION_FLAG_INITIATOR_RPT,
+ "tx initiator-report to target" },
+ { "neutral", WL_PROXD_SESSION_FLAG_NETRUAL, "neutral mode" },
+ { "seq-en", WL_PROXD_SESSION_FLAG_SEQ_EN, "sequence sampling capture" },
+ {"no-param-override", WL_PROXD_SESSION_FLAG_NO_PARAM_OVRD,
+ "disallow override from target"},
+ {"asap", WL_PROXD_SESSION_FLAG_ASAP, "use ASAP scheduling"},
+ { "tx-lci-req", WL_PROXD_SESSION_FLAG_REQ_LCI, "transmit LCI request" },
+ { "tx-civic-req", WL_PROXD_SESSION_FLAG_REQ_CIV, "tx civic location request" },
+ { "pre-scan", WL_PROXD_SESSION_FLAG_PRE_SCAN, "enable asap pre-scan on initiator" },
+ { "auto-vhtack", WL_PROXD_SESSION_FLAG_AUTO_VHTACK, "use vhtack based on brcm ie" },
+ { "vhtack", WL_PROXD_SESSION_FLAG_VHTACK, "vht ack is in use - output only" },
+ { "burst-duration-nopref", WL_PROXD_SESSION_FLAG_BDUR_NOPREF,
+ "duration for a single burst - no preference" },
+ { "num-ftm-nopref", WL_PROXD_SESSION_FLAG_NUM_FTM_NOPREF,
+ "number of FTM frames in a burst - no preference" },
+ { "ftm-sep-nopref", WL_PROXD_SESSION_FLAG_FTM_SEP_NOPREF,
+ "time between FTM frames in a burst - no preference " },
+ { "num-burst-nopref", WL_PROXD_SESSION_FLAG_NUM_BURST_NOPREF,
+ "number of bursts in a session - no preference " },
+ { "burst-period-nopref", WL_PROXD_SESSION_FLAG_BURST_PERIOD_NOPREF,
+ "time between bursts - no preference " },
+ { "all", WL_PROXD_SESSION_FLAG_ALL, "all of the above" }
+};
+
+static void
+ftm_cmn_display_config_options_value(uint32 flags,
+ const ftm_config_options_info_t *p_table, uint32 num_entries)
+{
+ const ftm_config_options_info_t *p_entry;
+ uint32 i;
+
+ if (flags) {
+ printf(" (");
+
+ /* walk thru the table to find a match indicating
+ the specified param_value_str is valid
+ */
+ p_entry = p_table;
+ for (i = 0; i < num_entries; i++) {
+ if ((p_entry->flags & flags) == p_entry->flags) {
+ printf(" %s", p_entry->param_value_str);
+ }
+
+ p_entry++; /* next */
+ }
+
+ printf(" )");
+
+ }
+ printf("\n");
+}
+
+static void
+ftm_unpack_and_display_session_flags(const uint8 *p_data, uint16 tlvid)
+{
+ wl_proxd_session_flags_t flags = ltoh32_ua(p_data);
+
+ printf("> %s: 0x%x", ftm_tlvid_to_logstr(tlvid), flags);
+ /* display the value in a readable format */
+ ftm_cmn_display_config_options_value((uint32) flags,
+ &ftm_session_options_info[0], ARRAYSIZE(ftm_session_options_info));
+}
+
+static void
+ftm_unpack_and_display_config_flags(const uint8 *p_data, uint16 tlvid)
+{
+ wl_proxd_flags_t flags = ltoh32_ua(p_data);
+
+ printf("> %s: 0x%x", ftm_tlvid_to_logstr(tlvid), flags);
+ /* display the value in a readable format */
+ return ftm_cmn_display_config_options_value((uint32) flags,
+ &ftm_method_options_info[0], ARRAYSIZE(ftm_method_options_info));
+}
+
+/* get the method/session config-options info from the table based on 'options param_value_str'
+* Input:
+* param_value_str -- a 'config options' param-value string to identify a config-options flag
+* useMethod -- set to true to look up 'config options' table for FTM method
+* set to false to look up 'config options' table for a session
+* if succeeds, return a pointer to the config_options_info, otherwise return NULL
+*/
+static const ftm_config_options_info_t *
+ftm_get_config_options_info(char *param_value_str, bool useMethod)
+{
+ int i;
+ const ftm_config_options_info_t *p_entry;
+ int num_entries;
+ if (useMethod) { /* choose an options table for method command */
+ p_entry = &ftm_method_options_info[0];
+ num_entries = ARRAYSIZE(ftm_method_options_info);
+ }
+ else { /* choose an options table for sessions command */
+ p_entry = &ftm_session_options_info[0];
+ num_entries = ARRAYSIZE(ftm_session_options_info);
+ }
+
+ /* walk thru the table to find a match indicating the specified param_value_str is valid */
+ for (i = 0; i < num_entries; i++) {
+ if (stricmp(param_value_str, p_entry->param_value_str) == 0)
+ return p_entry;
+ p_entry++; /* next */
+ }
+
+ return (ftm_config_options_info_t *) NULL; /* 'invalid param value' */
+}
+
+/*
+* handle 'wl proxd ftm [<session-id>] config options [+|-]param-value'
+* parse cmd-line, setup method/sessions options/flags TLVs in caller
+* provided buffer and adjusted-buffer-space if applies.
+* Note, input '<session-id>' is used to determine if config-options is
+* for 'global/method' or 'sessions'.
+*
+* This function is invoked from ftm_subcmd_config().
+*/
+static int
+ftm_handle_config_options(wl_proxd_session_id_t session_id, char **argv,
+ wl_proxd_tlv_t **p_tlv, uint16 *p_buf_space_left, bool useMethod)
+{
+ bool bEnable;
+ int status;
+ char *p_param_value;
+ uint32 flags = WL_PROXD_FLAG_NONE;
+ uint32 flags_mask = WL_PROXD_FLAG_NONE;
+ uint32 new_mask; /* cmdline input */
+ const ftm_config_options_info_t *p_options_info;
+
+ UNUSED_PARAMETER(session_id);
+
+ /* check if user provides param-values for 'config options' command */
+ if (*argv == NULL)
+ return BCME_USAGE_ERROR;
+
+ /* <param-value> followed 'wl proxd ftm [session-id] config options' */
+ while (*argv != NULL) {
+ bEnable = TRUE; /* default: set the flag if '+/-' is omitted */
+ if ((*argv)[0] == '-' || (*argv)[0] == '+') {
+ bEnable = ((*argv)[0] == '-') ? FALSE : TRUE;
+ p_param_value = *argv + 1; /* skip the prefix */
+ if (*p_param_value == '\0')
+ return BCME_USAGE_ERROR;
+ }
+ else
+ p_param_value = *argv;
+
+ /* check if 'param-value' (specified in ascii-string) is valid */
+ p_options_info = ftm_get_config_options_info(p_param_value, useMethod);
+ if (p_options_info != (ftm_config_options_info_t *) NULL) {
+ new_mask = p_options_info->flags;
+ }
+ else {
+ /* check if specifed as an intergral number string */
+ new_mask = strtoul(p_param_value, NULL, 0);
+ if (new_mask == 0) { /* conversion error, abort */
+ printf("error: invalid param-value(%s)\n", p_param_value);
+ return BCME_USAGE_ERROR; /* param-value is invalid */
+ }
+ }
+
+ /* update flags mask */
+ flags_mask = flags_mask | new_mask;
+ if (bEnable)
+ flags |= new_mask; /* set the bit on */
+ else
+ flags &= ~new_mask; /* set the bit off */
+
+ argv++; /* continue on next <param-value> */
+ }
+
+#ifdef WL_FTM_DEBUG
+ printf("%s: about to set TLVs for %s-options flags_mask=0x%x flags=0x%x\n",
+ __FUNCTION__, useMethod ? "method" : "sessions", flags_mask, flags);
+#endif /* WL_FTM_DEBUG */
+
+ flags = htol32(flags);
+ flags_mask = htol32(flags_mask);
+
+ /* setup flags_mask TLV */
+ status = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left,
+ useMethod ? WL_PROXD_TLV_ID_FLAGS_MASK : WL_PROXD_TLV_ID_SESSION_FLAGS_MASK,
+ sizeof(uint32), (uint8 *)&flags_mask, BCM_XTLV_OPTION_ALIGN32);
+ if (status != BCME_OK) {
+#ifdef WL_FTM_DEBUG
+ printf("%s: bcm_pack_xltv_entry() for flags_mask failed, status=%d\n",
+ __FUNCTION__, status);
+#endif /* WL_FTM_DEBUG */
+ return status; /* abort */
+ }
+
+ /* setup flags TLV */
+ status = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left,
+ useMethod ? WL_PROXD_TLV_ID_FLAGS : WL_PROXD_TLV_ID_SESSION_FLAGS,
+ sizeof(uint32), (uint8 *)&flags, BCM_XTLV_OPTION_ALIGN32);
+ if (status != BCME_OK) {
+#ifdef WL_FTM_DEBUG
+ printf("%s: bcm_pack_xltv_entry() for flags failed, status=%d\n",
+ __FUNCTION__, status);
+#endif /* WL_FTM_DEBUG */
+ return status; /* abort */
+ }
+
+ return BCME_OK;
+}
+
+/*
+ num_burst must be power of 2 (max exponent is 14)
+*/
+static int
+ftm_validate_num_burst(uint16 num_burst, const ftm_config_param_info_t *p_config_param_info)
+{
+#define WL_FTM_MAX_NUM_BURST_EXP 14
+ uint16 exponent;
+ uint64 x_num_burst;
+ int i;
+
+ /* get the exponent value */
+ exponent = 0;
+ x_num_burst = (uint64) num_burst;
+ for (i = 0; i < (int) (sizeof(num_burst) * NBBY); ++i, x_num_burst >>= 1) {
+ if (x_num_burst & 0x1)
+ exponent = i;
+ }
+
+ if (exponent > WL_FTM_MAX_NUM_BURST_EXP) {
+ printf("error:' %s' value is out of range (should not exceed 0x%x)\n",
+ p_config_param_info->name, 1 << WL_FTM_MAX_NUM_BURST_EXP);
+ return BCME_RANGE;
+ }
+
+ if (num_burst != (1 << exponent)) {
+ printf("error: '%s' value must be power of 2\n",
+ p_config_param_info->name);
+ return BCME_RANGE; /* not power of 2 */
+ }
+
+ return BCME_OK;
+}
+
+/*
+ parse 'param-value' for 'ftm config' command
+*/
+static int
+ftm_config_parse_ul(char **argv, const ftm_config_param_info_t *p_config_param_info,
+ unsigned long int min_value, unsigned long int max_value,
+ unsigned long int *out_data)
+{
+ int status = BCME_OK;
+ unsigned long int tmp_data_ul;
+
+ tmp_data_ul = strtoul(*argv, NULL, 0);
+ if (tmp_data_ul < min_value || tmp_data_ul > max_value) {
+ printf("error: '%s' value is out of range\n",
+ p_config_param_info->name);
+ return BCME_RANGE;
+ }
+
+ /* validate the arguments */
+ if (p_config_param_info->tlvid == WL_PROXD_TLV_ID_NUM_BURST ||
+ p_config_param_info->tlvid == WL_PROXD_TLV_ID_RX_MAX_BURST) {
+ status = ftm_validate_num_burst((uint16) tmp_data_ul, p_config_param_info);
+ if (status != BCME_OK)
+ return status;
+ }
+
+ /* param-value parsing: success */
+ *out_data = tmp_data_ul;
+
+ return BCME_OK;
+}
+
+/*
+* parse and pack 'chanspec' from a command-line argument
+* Input:
+* arg_channel: a channel-string
+* out_channel: buffer to store the result
+*/
+static int
+ftm_config_parse_channel(char *arg_channel, uint32 *out_channel)
+{
+ int status = BCME_OK;
+ uint32 src_data_channel = 0; /* default: invalid */
+
+ /* note, chanespec_t is currently defined as 16-bit, however */
+ /* wl-interface use 'uint32' to allow future change for 32-bit */
+ if (arg_channel != (char *) NULL)
+ src_data_channel = (uint32) wf_chspec_aton(arg_channel);
+
+ if (src_data_channel == 0) {
+ printf("error: invalid chanspec\n");
+ status = BCME_BADARG;
+ }
+
+ *out_channel = htol32(src_data_channel);
+ return status;
+}
+
+/*
+* parse and pack 'intvl' param-value from a command-line argument
+* Input:
+* arg_intvl: a time-intvl string
+* out_intvl: buffer to store the result
+*/
+static int
+ftm_config_parse_intvl(char *arg_intvl, wl_proxd_intvl_t *out_intvl)
+{
+ wl_proxd_intvl_t src_data_intvl;
+ char *p_end;
+
+ /* initialize */
+ memset(out_intvl, 0, sizeof(*out_intvl));
+
+ if (arg_intvl == (char *) NULL) {
+ printf("error: time-interval value is not specified\n");
+ return BCME_BADARG;
+ }
+
+ errno = 0;
+ memset(&src_data_intvl, 0, sizeof(src_data_intvl));
+ /* time interval e.g. 10ns */
+ /* get the number */
+ p_end = NULL;
+ src_data_intvl.intvl = htol32(strtoul(arg_intvl, &p_end, 10));
+ if (errno) {
+ printf("error: invalid time interval (errno=%d)\n", errno);
+ return BCME_BADARG;
+ }
+
+ /* get time-unit */
+ src_data_intvl.tmu = WL_PROXD_TMU_TU; /* default */
+ if (*p_end != '\0') {
+ if (!ftm_get_tmu_from_str(p_end, &src_data_intvl.tmu)) {
+ printf("error: invalid time-unit %s\n", p_end);
+ return BCME_BADARG;
+ }
+ }
+ src_data_intvl.tmu = htol16(src_data_intvl.tmu);
+
+ /* return to caller */
+ memcpy(out_intvl, &src_data_intvl, sizeof(*out_intvl));
+
+ return BCME_OK;
+}
+
+/*
+* parse and pack 'intvl' param-value from a command-line argument
+* Input:
+* arg_tpk: tpk param-value argument string
+* out_tpk: buffer to store tpk and mac address
+*/
+static int
+ftm_config_parse_tpk_peer(char *arg_tpk, wl_proxd_tpk_t *out_tpk)
+{
+ wl_proxd_tpk_t src_data_tpk;
+
+ /* initialize */
+ memset(out_tpk, 0, sizeof(*out_tpk));
+
+ if (arg_tpk == (char *) NULL) {
+ printf("error: tpk value is not specified\n");
+ return BCME_BADARG;
+ }
+
+ errno = 0;
+ memset(&src_data_tpk, 0, sizeof(src_data_tpk));
+ /* get link mac address */
+ if (!wl_ether_atoe(arg_tpk, &src_data_tpk.peer))
+ return BCME_USAGE_ERROR;
+ /* get TPK */
+ if (*arg_tpk) {
+ memcpy(&src_data_tpk.peer, arg_tpk, ETHER_ADDR_LEN);
+ }
+
+ /* return to caller */
+ memcpy(out_tpk, &src_data_tpk, sizeof(*out_tpk));
+
+ return BCME_OK;
+}
+
+
+/*
+* parse and pack one 'config avail slot' param-value from a command-line
+* Input:
+* arg_slot: 'slot' param-value argument string
+* in "channel:start-tmu:duration-tmu" format
+* out_avail_slot: buffer to store the result
+*/
+static int
+ftm_config_avail_parse_slot(char *arg_slot, wl_proxd_time_slot_t *out_avail_slot)
+{
+ int arg_idx;
+ const char *tmp_start, *tmp_end;
+ char tmpbuf[128];
+ int len;
+ int status = BCME_OK;
+
+ if (arg_slot == (char *) NULL) {
+ printf("error: slot value is not specified\n");
+ return BCME_BADARG;
+ }
+
+ /* parse channel:start-tmu:duration-tmu */
+ tmp_start = arg_slot;
+ for (arg_idx = 0; arg_idx < 3; arg_idx++) {
+ tmp_end = strchr(tmp_start, ':');
+ if (tmp_end == NULL) {
+ if (arg_idx != 2 || *tmp_start == '\0') {
+ status = BCME_BADARG;
+ goto done;
+ }
+ /* for last 'duration intvl' */
+ tmp_end = tmp_start + strlen(tmp_start);
+ }
+
+ /* create a temp null-terminated substring */
+ if ((len = tmp_end - tmp_start) >= (int) sizeof(tmpbuf)) {
+ status = BCME_BADARG;
+ goto done;
+ }
+
+ memcpy(tmpbuf, tmp_start, len);
+ tmpbuf[len] = '\0'; /* null-terminate */
+
+ if (arg_idx == 0)
+ status = ftm_config_parse_channel(tmpbuf, &out_avail_slot->chanspec);
+ else if (arg_idx == 1)
+ status = ftm_config_parse_intvl(tmpbuf, &out_avail_slot->start);
+ else /* arg_idx == 2 */
+ status = ftm_config_parse_intvl(tmpbuf, &out_avail_slot->duration);
+
+ if (status != BCME_OK)
+ goto done;
+ /* continue on next element */
+ tmp_start = tmp_end + 1;
+
+ }
+ /* make sure no string beyond 'channel:start-tmu:duration-tmu' */
+ if (*tmp_end != '\0') {
+ printf("error: invalid 'slot' value '%s'\n", tmp_end);
+ status = BCME_BADARG;
+ }
+
+done:
+ if (status == BCME_BADARG)
+ printf("error: invalid value for slot\n");
+
+ return status;
+}
+
+/*
+* parse and pack 'config avail time-ref' param-value from a command-line
+* Input:
+* arg_tref: 'time-ref' param-value argument string
+* in "none|dev-tsf|nan-dw|tbtt" format
+* out_tref: buffer to store the result
+*/
+static int
+ftm_config_avail_parse_tref(char *arg_tref, wl_proxd_time_ref_t *out_tref)
+{
+ wl_proxd_time_ref_t src_data_tref;
+ const ftm_strmap_entry_t *p_entry;
+
+ if (arg_tref == (char *) NULL) {
+ printf("error: time-ref value is not specified\n");
+ return BCME_BADARG;
+ }
+
+ /* loop up */
+ p_entry = ftm_get_strmap_info_strkey(arg_tref, &ftm_avail_timeref_value_loginfo[0],
+ ARRAYSIZE(ftm_avail_timeref_value_loginfo));
+ if (p_entry)
+ src_data_tref = p_entry->id;
+ else {
+ printf("error: invalid time-ref value\n");
+ return BCME_BADARG;
+ }
+
+ *out_tref = htol16((uint16) src_data_tref);
+
+ return BCME_OK;
+
+}
+
+#define FTM_AVAIL_MAX_SLOTS 32 /* also in pdftmpvt.h */
+/*
+* parse and pack a list of 'slot-value' for availability
+* Input:
+* argv -- point to something like "ch1:start-tmu1:duration-tmu1
+* ch2:start-tmu2:duration-tmu2 ..."
+*/
+static int
+ftm_config_avail_parse_all_slots(char **argv, wl_proxd_avail_t *avail, uint16 *out_num_slots)
+{
+ int err = BCME_OK;
+ uint16 num_slots;
+ wl_proxd_time_slot_t *avail_slot;
+
+ *out_num_slots = 0;
+
+ num_slots = 0;
+ avail_slot = WL_PROXD_AVAIL_TIMESLOTS(avail);
+ while (*argv != NULL) { /* parse each slot-value */
+ if (num_slots >= FTM_AVAIL_MAX_SLOTS) {
+ printf("error: number of slots exceed the limit (%d)\n",
+ FTM_AVAIL_MAX_SLOTS);
+ err = BCME_BADARG; /* too many time-slots */
+ goto done;
+ }
+
+ /* parse channel:start-tmu:duration-tmu */
+ err = ftm_config_avail_parse_slot(*argv, avail_slot);
+ if (err != BCME_OK)
+ goto done;
+
+ num_slots++;
+ avail_slot++;
+
+ ++argv; /* continue on next slot-value */
+ }
+
+ if (num_slots == 0) {
+ printf("error: slot-value is not specified\n");
+ err = BCME_BADARG;
+ goto done;
+ }
+
+ *out_num_slots = num_slots;
+
+done:
+ return err;
+}
+
+/*
+* allocate the availability info
+* if succeeds, an avail-buffer with 'max_slots' will be allocated
+*/
+static int
+ftm_config_avail_alloc(wl_proxd_avail_t **out_avail)
+{
+ uint16 bufsize;
+ wl_proxd_avail_t *avail;
+
+ /* init */
+ *out_avail = (wl_proxd_avail_t *) NULL;
+
+ bufsize = WL_PROXD_AVAIL_SIZE(avail, FTM_AVAIL_MAX_SLOTS);
+ avail = calloc(1, bufsize);
+ if (avail == NULL) {
+ printf("error: failed to allocate %d bytes of memory for avail\n",
+ bufsize);
+ return BCME_NOMEM;
+ }
+
+ /* initialize */
+ avail->flags = htol16(WL_PROXD_AVAIL_NONE); /* don't care, for query only */
+ avail->time_ref = htol16(WL_PROXD_TREF_NONE);
+ avail->max_slots = htol16(FTM_AVAIL_MAX_SLOTS);
+ avail->num_slots = htol16(0);
+
+#define WLU_PROXD_AVAIL_REPEAT_TU 512 /* default interval */
+ avail->repeat.intvl = htol32(WLU_PROXD_AVAIL_REPEAT_TU);
+ avail->repeat.tmu = htol16(WL_PROXD_TMU_TU);
+
+ *out_avail = avail;
+
+ return BCME_OK;
+}
+
+/* Support AVAIL24 */
+/*
+* allocate and convert the availability info to AVAIL24 format
+* if succeeds, an avail-buffer with 'in_avail_num_slots' time slot in AVAIL24
+* format will be allocated.
+*/
+static int
+ftm_config_avail_to_avail24(wl_proxd_avail_t *in_avail,
+ uint16 in_avail_num_slots, wl_proxd_avail24_t **out_avail)
+{
+ uint16 bufsize;
+ wl_proxd_avail24_t *avail24 = NULL;
+ wl_proxd_time_slot_t *avail_slot, *avail24_slot;
+
+ /* init */
+ *out_avail = (wl_proxd_avail24_t *) NULL;
+
+ bufsize = WL_PROXD_AVAIL24_SIZE(avail24, in_avail_num_slots);
+ avail24 = calloc(1, bufsize);
+ if (avail24 == NULL) {
+ printf("error: failed to allocate %d bytes of memory for avail\n",
+ bufsize);
+ return BCME_NOMEM;
+ }
+
+ /* convert the header */
+ avail24->flags = in_avail->flags;
+ avail24->time_ref = in_avail->time_ref;
+ avail24->max_slots = htol16(in_avail_num_slots); /* don't care, for query only */
+ avail24->num_slots = avail24->max_slots;
+ avail24->repeat.intvl = in_avail->repeat.intvl;
+ avail24->repeat.tmu = in_avail->repeat.tmu;
+
+ /* convert time-slot */
+ avail_slot = WL_PROXD_AVAIL_TIMESLOTS(in_avail);
+ avail24_slot = WL_PROXD_AVAIL24_TIMESLOTS(avail24); /* &avail24->ts0[0]; */
+
+ memcpy(avail24_slot, avail_slot, in_avail_num_slots * sizeof(avail24->ts0[0]));
+
+ *out_avail = avail24;
+
+ return BCME_OK;
+}
+
+/*
+* parse cmd-line for 'wl proxd ftm [<session-id>] config avail' command
+* { [ftm-ref] none |
+* time-ref dev-tsf|nan-adv|tbtt repeat repeat-tmu slot {channel:start-tmu:duration-tmu}+ }
+* if succeeds, an avail info is allocated (data is packed) and returned.
+* Also, number of time-slots associated with this buffer will be returned
+* in 'out_num_slots'.
+*/
+static int
+ftm_pack_config_avail_from_cmdarg(char **argv,
+ wl_proxd_avail_t **out_avail, uint16 *out_num_slots)
+{
+ wl_proxd_avail_t *avail = NULL;
+ wl_proxd_time_ref_t time_ref;
+ uint16 num_slots = 0;
+ int err = BCME_OK;
+
+ /* init */
+ *out_avail = NULL;
+ *out_num_slots = 0;
+
+ /* check if user provides <param-name><param-value> for 'config avail' command */
+ if (*argv == NULL) {
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+
+ /* allocate a buffer for parsing cmd-args */
+ err = ftm_config_avail_alloc(&avail);
+ if (err != BCME_OK)
+ goto done;
+
+ /* parse input arguments */
+ num_slots = 0;
+ time_ref = htol16(WL_PROXD_TREF_NONE); /* default */
+ while (*argv != NULL) {
+ if (stricmp(*argv, "none") == 0) {
+ time_ref = htol16(WL_PROXD_TREF_NONE);
+ }
+ else if (stricmp(*argv, "time-ref") == 0) {
+ ++argv; /* advance to 'param-value' */
+ err = ftm_config_avail_parse_tref(*argv, &time_ref);
+ if (err != BCME_OK)
+ goto done;
+ }
+ else if (stricmp(*argv, "repeat") == 0) {
+ ++argv; /* advance to 'param-value' */
+ err = ftm_config_parse_intvl(*argv, &avail->repeat);
+ if (err != BCME_OK)
+ goto done;
+ }
+ else if (stricmp(*argv, "slot") == 0) {
+ if (time_ref == htol16(WL_PROXD_TREF_NONE)) {
+ printf("error: time-ref is missing or invalid for slot\n");
+ err = BCME_BADARG;
+ goto done;
+ }
+ ++argv; /* advance to 'param-value' */
+
+ err = ftm_config_avail_parse_all_slots(argv, avail, &num_slots);
+ if (err != BCME_OK)
+ goto done;
+ break; /* done parsing */
+ }
+ else {
+ printf("error: invalid param-name (%s)\n", *argv);
+ err = BCME_USAGE_ERROR; /* param-name is not specified */
+ goto done;
+ }
+
+ ++argv; /* continue on next 'param-name' */
+ }
+
+ avail->time_ref = time_ref;
+ avail->num_slots = htol16(num_slots);
+
+ *out_avail = avail;
+ *out_num_slots = num_slots;
+ avail = (wl_proxd_avail_t *) NULL;
+
+done:
+ if (err != BCME_OK) {
+ if (avail) /* cleanup */
+ free(avail);
+ }
+
+ return err;
+
+}
+
+/*
+* handle 'wl proxd ftm [<session-id>] config avail
+* { [ftm-ref] none |
+* time-ref dev-tsf|nan-adv|tbtt repeat repeat-tmu slot {channel:start-tmu:duration-tmu}+ }
+* parse cmd-line, setup local/peer(method/sessions) availability TLVs in caller
+* provided buffer and adjusted-buffer-space if applies.
+* Note, input '<session-id>' is used to determine if config-avail is
+* for 'local' or 'peer'.
+*
+* This function is invoked from ftm_subcmd_config().
+*/
+static int
+ftm_do_config_avail_iovar(void *wl, wl_proxd_iov_t *p_proxd_iov, uint16 proxd_iovsize,
+ uint16 tlvid, void *avail, int avail_size)
+{
+ int err = BCME_OK;
+ uint16 bufsize;
+ wl_proxd_tlv_t *p_tlv;
+ uint16 buf_space_left;
+ uint16 all_tlvsize;
+
+ /* setup TLVs */
+ bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */
+ p_tlv = &p_proxd_iov->tlvs[0];
+
+ /* TLV buffer starts with a full size, will decrement for each packed TLV */
+ buf_space_left = bufsize;
+
+ err = bcm_pack_xtlv_entry((uint8 **) &p_tlv, &buf_space_left,
+ tlvid, avail_size, (void *) avail,
+ BCM_XTLV_OPTION_ALIGN32);
+ if (err != BCME_OK) {
+ printf("%s: failed to pack TLVs for availability, status=%d\n",
+ __FUNCTION__, err);
+ goto done;
+ }
+
+ /* update the iov header, set len to include all TLVs + header */
+ all_tlvsize = (bufsize - buf_space_left);
+ p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE);
+ err = wlu_var_setbuf(wl, "proxd", p_proxd_iov,
+ all_tlvsize + WL_PROXD_IOV_HDR_SIZE);
+
+done:
+ return err;
+}
+
+static int
+ftm_handle_config_avail(void *wl, wl_proxd_iov_t *p_proxd_iov, uint16 proxd_iovsize,
+wl_proxd_session_id_t session_id, char **argv)
+{
+ int err = BCME_OK;
+ wl_proxd_avail_t *avail = NULL;
+ wl_proxd_avail24_t *avail24 = NULL;
+ uint16 num_slots;
+ int avail_size;
+
+ UNUSED_PARAMETER(session_id);
+
+ /* parse cmd line and alloc/pack the avail info */
+ err = ftm_pack_config_avail_from_cmdarg(argv,
+ &avail, &num_slots);
+ if (err != BCME_OK)
+ goto done;
+
+ /* pack and request to config the avail using the latest AVAIL if supported */
+ err = ftm_is_tlv_id_supported(wl, WL_PROXD_TLV_ID_AVAIL);
+ if (err == BCME_OK) {
+ /* adjust size based on num-slots available */
+ avail_size = WL_PROXD_AVAIL_SIZE(avail, num_slots);
+ err = ftm_do_config_avail_iovar(wl, p_proxd_iov, proxd_iovsize,
+ WL_PROXD_TLV_ID_AVAIL, (void *) avail, avail_size);
+ goto done;
+ }
+
+ /* try AVAIL24 */
+ /* convert to AVAIL24 format */
+ err = ftm_config_avail_to_avail24(avail,
+ num_slots, &avail24);
+ if (err != BCME_OK)
+ goto done;
+
+ /* adjust size based on num-slots available */
+ avail_size = WL_PROXD_AVAIL24_SIZE(avail24, num_slots);
+ err = ftm_do_config_avail_iovar(wl, p_proxd_iov, proxd_iovsize,
+ WL_PROXD_TLV_ID_AVAIL24, (void *) avail24, avail_size);
+
+done:
+ if (avail) /* clean up */
+ free(avail);
+ if (avail24)
+ free(avail24);
+
+ return err;
+}
+
+/* proxd ftm config-category definition */
+typedef enum {
+ FTM_CONFIG_CAT_GENERAL = 1, /* generial configuration */
+ FTM_CONFIG_CAT_OPTIONS = 2, /* 'config options' */
+ FTM_CONFIG_CAT_AVAIL = 3, /* 'config avail' */
+ FTM_CONFIG_CAT_SESSION_OPTIONS = 4
+} ftm_config_category_t;
+
+/*
+* parse the config-category from a command-line
+* Input:
+* arg_type: a config-category string after 'wl proxd ftm config' from the command-line
+*/
+static ftm_config_category_t
+ftm_parse_config_category(char *arg_category)
+{
+ if (stricmp(arg_category, "options") == 0)
+ return FTM_CONFIG_CAT_OPTIONS;
+ if (stricmp(arg_category, "avail") == 0)
+ return FTM_CONFIG_CAT_AVAIL;
+ if (stricmp(arg_category, "session-options") == 0)
+ return FTM_CONFIG_CAT_SESSION_OPTIONS;
+
+ return FTM_CONFIG_CAT_GENERAL;
+}
+
+/*
+* 'wl proxd ftm config' handler for general-configuration:
+* wl proxd ftm [<session-id>] config [<param-name> <param-value>]+
+*/
+static int
+ftm_handle_config_general(wl_proxd_session_id_t session_id, char **argv,
+wl_proxd_tlv_t **p_tlv, uint16 *p_buf_space_left)
+{
+ int status = BCME_OK;
+ /* data from command line as 'src' */
+ unsigned long int tmp_data_ul;
+ uint8 src_data_uint8;
+ uint16 src_data_uint16;
+ uint32 src_data_uint32;
+ struct ether_addr src_data_mac = ether_null;
+ wl_proxd_intvl_t src_data_intvl;
+ wl_proxd_tpk_t src_data_tpk;
+
+ void *p_src_data;
+ uint16 src_data_size; /* size of data pointed by p_src_data as 'source' */
+ const ftm_config_param_info_t *p_config_param_info;
+
+ /* parse the cmd-line, scan thru all <param-name> <param-value> */
+ while (*argv != NULL) {
+ /* look up 'config-param-info' based on 'param-name' */
+ p_config_param_info = ftm_get_config_param_info(*argv, session_id);
+ if (p_config_param_info == (ftm_config_param_info_t *) NULL) {
+ printf("error: invalid param-name (%s)\n", *argv);
+ status = BCME_USAGE_ERROR; /* param-name is not specified */
+ break;
+ }
+
+ /* parse 'param-value' */
+ if (*(argv + 1) == NULL) {
+ printf("error: invalid param-value\n");
+ status = BCME_USAGE_ERROR; /* param-value is not specified */
+ break;
+ }
+ ++argv;
+
+ /* parse param-value, setup tlv-data */
+ p_src_data = (void *) NULL;
+ src_data_size = 0;
+ switch (p_config_param_info->tlvid) {
+ case WL_PROXD_TLV_ID_BSS_INDEX: /* uint8 */
+ case WL_PROXD_TLV_ID_NAN_MAP_ID:
+ case WL_PROXD_TLV_ID_FTM_REQ_RETRIES:
+ case WL_PROXD_TLV_ID_FTM_RETRIES:
+ src_data_uint8 = atoi(*argv);
+ p_src_data = (void *) &src_data_uint8;
+ src_data_size = sizeof(uint8);
+ break;
+
+ case WL_PROXD_TLV_ID_BURST_NUM_FTM: /* uint16 */
+ case WL_PROXD_TLV_ID_NUM_BURST:
+ case WL_PROXD_TLV_ID_RX_MAX_BURST:
+ if ((status = ftm_config_parse_ul(argv, p_config_param_info,
+ (unsigned long int) 0, (unsigned long int) 0xffff,
+ &tmp_data_ul)) != BCME_OK)
+ break;
+ src_data_uint16 = htol16((uint16) tmp_data_ul);
+ p_src_data = (void *) &src_data_uint16;
+ src_data_size = sizeof(uint16);
+ break;
+
+ case WL_PROXD_TLV_ID_TX_POWER: /* uint32 */
+ case WL_PROXD_TLV_ID_RATESPEC:
+ case WL_PROXD_TLV_ID_EVENT_MASK: /* wl_proxd_event_mask_t/uint32 */
+ case WL_PROXD_TLV_ID_DEBUG_MASK: /* allow in 0x######## format */
+ if ((status = ftm_config_parse_ul(argv, p_config_param_info,
+ (unsigned long int) 0, (unsigned long int) 0xffffffff,
+ &tmp_data_ul)) != BCME_OK)
+ break;
+ /* get the bitmask */
+ src_data_uint32 = htol32((uint32) tmp_data_ul);
+ p_src_data = &src_data_uint32;
+ src_data_size = sizeof(uint32);
+ break;
+
+ case WL_PROXD_TLV_ID_CHANSPEC: /* chanspec_t --> 32bit */
+ status = ftm_config_parse_channel(*argv, &src_data_uint32);
+ if (status == BCME_OK) {
+ p_src_data = (void *) &src_data_uint32;
+ src_data_size = sizeof(uint32);
+ }
+ break;
+
+ case WL_PROXD_TLV_ID_BSSID: /* mac address */
+ case WL_PROXD_TLV_ID_PEER_MAC:
+ case WL_PROXD_TLV_ID_DEV_ADDR:
+ src_data_mac = ether_null;
+ if (!wl_ether_atoe(*argv, &src_data_mac)) {
+ printf("error: invalid MAC address parameter\n");
+ status = BCME_USAGE_ERROR;
+ break;
+ }
+ p_src_data = &src_data_mac;
+ src_data_size = sizeof(src_data_mac);
+ break;
+
+ case WL_PROXD_TLV_ID_BURST_DURATION: /* wl_proxd_intvl_t */
+ case WL_PROXD_TLV_ID_BURST_PERIOD:
+ case WL_PROXD_TLV_ID_BURST_FTM_SEP:
+ case WL_PROXD_TLV_ID_BURST_TIMEOUT:
+ case WL_PROXD_TLV_ID_INIT_DELAY:
+ status = ftm_config_parse_intvl(*argv, &src_data_intvl);
+ if (status == BCME_OK) {
+ p_src_data = (void *) &src_data_intvl;
+ src_data_size = sizeof(src_data_intvl);
+ }
+ break;
+
+ case WL_PROXD_TLV_ID_TPK:
+ status = ftm_config_parse_tpk_peer(*argv, &src_data_tpk);
+ if (status == BCME_OK) {
+ p_src_data = (void *) &src_data_tpk;
+ src_data_size = sizeof(src_data_tpk);
+ }
+ break;
+
+ default:
+ /* not supported now */
+ status = BCME_USAGE_ERROR;
+ break;
+ }
+
+ if (status != BCME_OK)
+ break; /* abort */
+
+ status = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left,
+ p_config_param_info->tlvid, src_data_size, p_src_data,
+ BCM_XTLV_OPTION_ALIGN32);
+ if (status != BCME_OK)
+ {
+#ifdef WL_FTM_DEBUG
+ printf("%s: bcm_pack_xltv_entry() failed, status=%d\n",
+ __FUNCTION__, status);
+#endif /* WL_FTM_DEBUG */
+ break; /* abort */
+ }
+
+ argv++; /* continue on next <param-name><param-value> */
+ }
+
+ return status;
+
+}
+
+/*
+* 'wl proxd ftm config' handler, there are two formats:
+* For options/flags config, use
+* wl proxd ftm [<session-id>] config options { [+|-]<param-value> }+
+* for non-options/flags config, use
+* wl proxd ftm [<session-id>] config [<param-name> <param-value>]+
+*/
+static int
+ftm_subcmd_config(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ ftm_config_category_t category;
+ uint16 proxd_iovsize;
+ wl_proxd_iov_t *p_proxd_iov;
+ int status = BCME_OK;
+ uint16 bufsize;
+ wl_proxd_tlv_t *p_tlv;
+ uint16 buf_space_left;
+ uint16 all_tlvsize;
+
+ if (*argv == NULL) {
+ printf("error: config command requires parameters\n");
+ /* display 'proxd -h ftm config' helpmsg */
+ ftm_display_config_help();
+ return BCME_OK; /* no need to show 'proxd'-level help */
+ }
+
+ /* allocate a buffer for proxd-ftm config via 'set' iovar */
+ p_proxd_iov = ftm_alloc_getset_buf(method, session_id,
+ p_subcmd_info->cmdid, FTM_IOC_BUFSZ, &proxd_iovsize);
+ if (p_proxd_iov == (wl_proxd_iov_t *) NULL)
+ return BCME_NOMEM;
+
+ /* setup TLVs */
+ bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */
+ p_tlv = &p_proxd_iov->tlvs[0];
+
+ /* TLV buffer starts with a full size, will decrement for each packed TLV */
+ buf_space_left = bufsize;
+
+ /* parse the cmd-line, get the config-category and dispatch to the handler */
+ /* to parse the parameters based on the 'config-category' */
+ category = ftm_parse_config_category(*argv);
+ if (category == FTM_CONFIG_CAT_OPTIONS) {
+ /* for 'wl proxd ftm [session-id] config options' */
+ /* dispatch to setup TLVs for method/session options/flags */
+ status = ftm_handle_config_options(session_id, ++argv, &p_tlv,
+ &buf_space_left, session_id != WL_PROXD_SESSION_ID_GLOBAL ? FALSE : TRUE);
+ } else if (category == FTM_CONFIG_CAT_SESSION_OPTIONS) {
+ status = ftm_handle_config_options(session_id, ++argv, &p_tlv,
+ &buf_space_left, FALSE);
+ } else if (category == FTM_CONFIG_CAT_AVAIL) {
+ status = ftm_handle_config_avail(wl, p_proxd_iov, proxd_iovsize,
+ session_id, ++argv);
+ }
+ else
+ status = ftm_handle_config_general(session_id, argv, &p_tlv,
+ &buf_space_left);
+
+ if (status == BCME_OK && category != FTM_CONFIG_CAT_AVAIL) {
+ /* update the iov header, set len to include all TLVs + header */
+ all_tlvsize = (bufsize - buf_space_left);
+ p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE);
+ status = wlu_var_setbuf(wl, "proxd", p_proxd_iov,
+ all_tlvsize + WL_PROXD_IOV_HDR_SIZE);
+ }
+
+ if (status == BCME_USAGE_ERROR) {
+ if (category == FTM_CONFIG_CAT_OPTIONS)
+ ftm_display_config_options_help();
+ else if (category == FTM_CONFIG_CAT_AVAIL)
+ ftm_display_config_avail_help();
+ else
+ ftm_display_config_help();
+ status = BCME_OK; /* reset to avoid showing 'proxd'-level help */
+ }
+
+ /* clean up */
+ free(p_proxd_iov);
+
+#ifdef WL_FTM_DEBUG
+ if (status != BCME_OK)
+ printf("error: exit %s, status = %d\n", __FUNCTION__, status);
+#endif /* WL_FTM_DEBUG */
+
+ return status;
+}
+
+static void
+ftm_display_cmd_help(const ftm_subcmd_info_t *p_subcmd_info,
+const char *cmd_params)
+{
+ if (p_subcmd_info == (ftm_subcmd_info_t *) NULL)
+ return;
+
+ if (p_subcmd_info->helpmsg == (char *) NULL)
+ return;
+
+ /* print help messages for a specific FTM sub-command */
+ printf("\n\t%s\n", p_subcmd_info->helpmsg);
+
+ /* display cmd usage (these commands require no parameters) */
+ printf("\tUsage: wl proxd ftm ");
+ if (p_subcmd_info->cmdflag & FTM_SUBCMD_FLAG_SESSION) {
+ if (p_subcmd_info->cmdflag & FTM_SUBCMD_FLAG_METHOD)
+ printf("[<session-id>] ");
+ else
+ printf("<session-id> ");
+ }
+ printf("%s%s\n\n",
+ p_subcmd_info->name, cmd_params ? cmd_params : "");
+
+}
+
+/*
+* pack tlvs for 'wl proxd ftm start-ranging [-d] <sid1> <sid2> ...'
+* parse cmd-line, setup TLVs in caller provided buffer,
+* adjusted buffer-space if applies.
+* This function is invoked from ftm_subcmd_start_ranging().
+*/
+static int
+ftm_pack_sids_from_cmdarg(char **argv,
+ wl_proxd_tlv_t **p_tlv, uint16 *p_buf_space_left)
+{
+ char **tmp_argv;
+ uint16 num_sids;
+ int err = BCME_OK;
+ uint16 ranging_sids_size;
+ wl_proxd_session_id_list_t *ranging_sids = NULL;
+ wl_proxd_session_id_t sid;
+ uint16 count;
+
+ /* figout out number of session-id from the input */
+ tmp_argv = argv;
+ num_sids = 0;
+ while (*tmp_argv != NULL) {
+ tmp_argv++;
+ num_sids++;
+ }
+ if (num_sids == 0) {
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+
+ /* allocate a temp buffer for parsing cmd-args */
+ ranging_sids_size = OFFSETOF(wl_proxd_session_id_list_t, ids) +
+ num_sids * sizeof(wl_proxd_session_id_t);
+ ranging_sids = calloc(1, ranging_sids_size);
+ if (ranging_sids == (wl_proxd_session_id_list_t *) NULL) {
+ printf("error: failed to allocate %d bytes of memory for ranging\n",
+ ranging_sids_size);
+ err = BCME_NOMEM;
+ goto done;
+ }
+
+ /* get session-ids followed 'wl proxd ftm start-ranging [-d]' */
+ count = 0;
+ while (*argv != NULL) {
+ sid = (uint16) atoi(*argv);
+ ranging_sids->ids[count++] = htol16(sid);
+ argv++; /* continue on next session-id */
+ }
+
+ ranging_sids->num_ids = htol16(num_sids);
+ err = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left,
+ WL_PROXD_TLV_ID_SESSION_ID_LIST, ranging_sids_size,
+ (uint8 *)ranging_sids, BCM_XTLV_OPTION_ALIGN32);
+
+ if (err != BCME_OK) {
+ printf("%s: failed to pack ranging-ids in xtlv, err=%d\n",
+ __FUNCTION__, err);
+ goto done;
+ }
+
+done:
+ /* clean up */
+ if (ranging_sids)
+ free(ranging_sids);
+
+ return err;
+}
+
+/*
+* pack tlvs for 'wl proxd ftm start-ranging [-d] <sid1> <sid2> ...'
+* parse cmd-line, setup TLVs in caller provided buffer,
+* adjusted buffer-space if applies.
+* This function is invoked from ftm_subcmd_start_ranging().
+*/
+static int
+ftm_pack_ranging_config_from_cmdarg(char **argv,
+wl_proxd_tlv_t **p_tlv, uint16 *p_buf_space_left)
+{
+ int err = BCME_OK;
+ wl_proxd_ranging_flags_t flags;
+ wl_proxd_ranging_flags_t flags_mask;
+
+ /* parse the ranging-flags '-d' followed 'wl proxd ftm start-ranging' if available */
+ flags = WL_PROXD_RANGING_FLAG_NONE;
+ while (*argv != NULL) {
+ if (stricmp(*argv, "-d") != 0)
+ break; /* skip to handle 'sids' arguments */
+
+ flags = WL_PROXD_RANGING_FLAG_DEL_SESSIONS_ON_STOP;
+ argv++; /* continue on next session-id */
+ }
+
+ /* pack ranging-flags/mask in xTLVs if provided */
+ if (flags != WL_PROXD_RANGING_FLAG_NONE) {
+ /* setup ranging flags TLV */
+ err = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left,
+ WL_PROXD_TLV_ID_RANGING_FLAGS,
+ sizeof(uint16), (uint8 *)&flags, BCM_XTLV_OPTION_ALIGN32);
+ if (err != BCME_OK) {
+ printf("%s: failed to pack ranging-flags in xtlv, err=%d\n",
+ __FUNCTION__, err);
+ goto done; /* abort */
+ }
+
+ /* setup ranging flags_mask TLV */
+ flags_mask = WL_PROXD_RANGING_FLAG_ALL;
+ err = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left,
+ WL_PROXD_TLV_ID_RANGING_FLAGS_MASK,
+ sizeof(uint16), (uint8 *)&flags_mask, BCM_XTLV_OPTION_ALIGN32);
+ if (err != BCME_OK) {
+ printf("%s: failed to pack ranging flags_mask in xtlv, err=%d\n",
+ __FUNCTION__, err);
+ goto done; /* abort */
+ }
+ }
+
+ /* parse the 'sids' followed 'wl proxd ftm start-ranging [-d]' and
+ * pack the parameters in xTLVs if available
+ */
+ err = ftm_pack_sids_from_cmdarg(argv, p_tlv, p_buf_space_left);
+
+done:
+ if (err != BCME_OK)
+ printf("%s failed, err = %d\n",
+ __FUNCTION__, err);
+ return err;
+}
+
+/*
+* 'wl proxd ftm start-ranging' handler
+* wl proxd ftm start-ranging [-d] <sid1> <sid2> ...
+*/
+static int
+ftm_subcmd_start_ranging(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ wl_proxd_iov_t *p_proxd_iov = NULL;
+ uint16 proxd_iovsize;
+ uint16 bufsize;
+ wl_proxd_tlv_t *p_tlv;
+ uint16 buf_space_left;
+ int err = BCME_OK;
+ uint16 all_tlvsize;
+
+ UNUSED_PARAMETER(wl);
+
+ /* this should apply to a method command */
+ if (*argv == NULL || session_id != WL_PROXD_SESSION_ID_GLOBAL) {
+ printf("error: start-ranging command requires parameters\n");
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+
+ /* allocate a buffer for proxd-ftm config via 'set' iovar */
+ p_proxd_iov = ftm_alloc_getset_buf(method, session_id,
+ p_subcmd_info->cmdid, FTM_IOC_BUFSZ, &proxd_iovsize);
+ if (p_proxd_iov == (wl_proxd_iov_t *) NULL) {
+ err = BCME_NOMEM;
+ goto done;
+ }
+
+ /* setup TLVs */
+ bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */
+ p_tlv = &p_proxd_iov->tlvs[0];
+
+ /* TLV buffer starts with a full size, will decrement for each packed TLV */
+ buf_space_left = bufsize;
+
+ /* parse the cmd-line, pack the parameters in TLVs */
+ err = ftm_pack_ranging_config_from_cmdarg(argv, &p_tlv,
+ &buf_space_left);
+ if (err != BCME_OK)
+ goto done;
+
+ /* update the iov header, set len to include all TLVs + header */
+ all_tlvsize = (bufsize - buf_space_left);
+ p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE);
+ err = wlu_var_setbuf(wl, "proxd", p_proxd_iov,
+ all_tlvsize + WL_PROXD_IOV_HDR_SIZE);
+
+done:
+ /* clean up */
+ if (p_proxd_iov)
+ free(p_proxd_iov);
+
+ if (err == BCME_USAGE_ERROR) {
+ /* display 'proxd -h ftm' helpmsg */
+ ftm_display_cmd_help(p_subcmd_info, "[-d] <sid1> <sid2> ...");
+ err = BCME_OK; /* reset to avoid showing 'proxd'-level help */
+ }
+
+ return err;
+}
+
+/*
+* 'wl proxd ftm stop-ranging' handler,
+* wl proxd ftm stop-ranging
+*/
+static int
+ftm_subcmd_stop_ranging(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ /* this should apply to a method command */
+ if (session_id != WL_PROXD_SESSION_ID_GLOBAL) {
+ printf("error: no session-id is allowed for stop-ranging\n");
+ /* display 'proxd -h ftm stop-ranging ' helpmsg */
+ ftm_display_cmd_help(p_subcmd_info, "");
+ return BCME_OK; /* no need to show 'proxd'-level help */
+ }
+
+ /* issue an iovar call */
+ return ftm_subcmd_setiov_no_tlv(wl, p_subcmd_info, method, session_id, argv);
+}
+
+/*
+* display help-messages for 'wl proxd -h ftm'
+*/
+static void
+ftm_display_method_help()
+{
+ int i;
+ int max_cmdname_len = 20;
+ const ftm_subcmd_info_t *p_subcmd_info;
+
+ /* a header */
+ printf("\n\tProximity Detection using FTM\n");
+ printf("\tUsage: wl proxd ftm [<session-id>] <cmd> [<param-name> <param-value>]*\n");
+ printf("\t\t<session-id>: specify a session; If omitted, <cmd> applies to FTM method\n");
+ printf("\t\t<cmd>: specify a command from the following list,\n");
+
+ /* show the command list and the help messages for each FTM command */
+ p_subcmd_info = &ftm_cmdlist[0];
+ for (i = 0; i < (int) ARRAYSIZE(ftm_cmdlist); i++) {
+ printf("\t\t %*s: %s\n", max_cmdname_len, p_subcmd_info->name,
+ p_subcmd_info->helpmsg);
+ p_subcmd_info++;
+ }
+
+ printf("\t\t<param-name> <param-value>: <cmd>-specific parameters\n\n");
+
+ printf("\t\ttype 'wl proxd -h ftm config' for configuration command usage.\n");
+ printf("\t\ttype 'wl proxd -h ftm config options' "
+ "for options-configuration command usage.\n");
+ printf("\t\ttype 'wl proxd -h ftm config avail' "
+ "for availability-configuration command usage.\n");
+ printf("\t\ttype 'wl proxd -h ftm <cmd>' for others command usage.\n\n");
+
+ /* show examples */
+ printf("\tExample: wl proxd ftm enable\n\n");
+
+ return;
+}
+
+/*
+* display help-messages for 'wl proxd -h ftm config'
+*/
+static void
+ftm_display_config_help()
+{
+ int i;
+ int max_param_name_len = 20;
+ const ftm_config_param_info_t *p_config_param_info;
+
+ /* a header */
+ printf("\n\tConfigure Proximity Detection using FTM\n");
+ printf("\tUsage: wl proxd ftm [<session-id>] config { <param-name> <param-value> }+ \n");
+ printf("\t\t<session-id>: specify a session id; If omitted, configure global items\n");
+ /* print helpmsg for each config-item */
+ printf("\t\t<param-name> <param-value>: configuration parameters from the following\n");
+ p_config_param_info = &ftm_config_param_info[0];
+ for (i = 0; i < (int) ARRAYSIZE(ftm_config_param_info); i++) {
+ printf("\t\t %*s: %s\n", max_param_name_len, p_config_param_info->name,
+ p_config_param_info->name_helpmsg);
+
+ p_config_param_info++;
+ }
+
+ /* show examples */
+ printf("\n\tExample: wl proxd ftm config retries 10\n");
+ printf("\t wl proxd ftm 1 config retries 10\n");
+}
+
+/*
+* display help-messages for 'wl proxd -h ftm config options'
+*/
+static void
+ftm_display_config_options_help()
+{
+ int i;
+ int max_option_name_len = 20;
+ const ftm_config_options_info_t *p_config_options_info;
+
+ /* a header */
+ printf("\n\tConfigure-Options Proximity Detection using FTM\n");
+ printf("\tUsage: wl proxd ftm [<session-id>] config options { [+|-]<param-value> }+ \n");
+ printf("\t\t<session-id>: specify a session id; If omitted, set the global options\n");
+ printf("\t\t+|- prefix: to add or remove an option\n");
+ printf("\t\t<param-value>: specify an option\n");
+
+ /* print helpmsg for each global option flag */
+ printf("\t\t\tConfigurable options for a FTM method:\n");
+ p_config_options_info = &ftm_method_options_info[0];
+ for (i = 0; i < (int) ARRAYSIZE(ftm_method_options_info); i++) {
+ printf("\t\t %*s (0x%08x): %s\n", max_option_name_len,
+ p_config_options_info->param_value_str,
+ p_config_options_info->flags, p_config_options_info->helpmsg);
+ p_config_options_info++;
+ }
+
+ /* print helpmsg for each session option flag */
+ printf("\n\t\t\tConfigurable options for a specific session:\n");
+ p_config_options_info = &ftm_session_options_info[0];
+ for (i = 0; i < (int) ARRAYSIZE(ftm_session_options_info); i++) {
+ printf("\t\t %*s (0x%08x): %s\n", max_option_name_len,
+ p_config_options_info->param_value_str,
+ p_config_options_info->flags, p_config_options_info->helpmsg);
+ p_config_options_info++;
+ }
+
+ /* show examples */
+ printf("\n\tExample: wl proxd ftm config options +rx-enable\n");
+ printf("\t wl proxd ftm config options +0x00000001\n");
+ printf("\t wl proxd ftm 1 config options +rx-auto-burst -rtt-detail\n\n");
+
+ return;
+}
+
+/*
+* display help-messages for 'wl proxd -h ftm config avail'
+*/
+static void
+ftm_display_config_avail_help()
+{
+ /* a header */
+ printf("\n\tConfigure-availability Proximity Detection using FTM\n");
+ printf("\t\tUsage: wl proxd ftm [<session-id>] config avail\n");
+ printf("\t\t { [time-ref] none |\n");
+ printf("\t\t time-ref <timeref-value> repeat <repeat-tmu> slot {<slot-value>}+ }\n");
+ printf("\t\t<session-id>: a session id; If omitted, set the local availability\n");
+ printf("\t\t otherwise, set the peer availability\n");
+ printf("\t\tnone or time-ref none: to clear availability\n");
+ printf("\t\t<timeref-value>: a timer reference. Possible values are:\n");
+ printf("\t\t dev-tsf | nan-dw | tbtt\n");
+ printf("\t\t<repeat-tmu>: repeat period in time-interval format\n");
+ printf("\t\t<slot-value>: a time slot in channel:start-tmu:duration-tmu\n");
+ printf("\t\t channel -- a channel (see 'wl chanspec')\n");
+ printf("\t\t start-tmu -- start time in time-interval format\n");
+ printf("\t\t (a number followed by a time unit)\n");
+ printf("\t\t duration-tmu -- duration in time-interval format\n");
+ printf("\t\t Time uints are:\n");
+ printf("\t\t s (seconds) | ms (milliseconds) | us (microseconds)\n");
+ printf("\t\t ns (nanoseconds) | ps (picoseconds) | tu (for TUs,default)\n");
+ printf("\t\tMore than one <slot-value>' can be specified for setting\n");
+ printf("\t\tmultiple time slots\n");
+
+ /* show examples */
+ printf("\n\tExample: wl proxd ftm config avail none\n");
+ printf("\t wl proxd ftm config avail time-ref dev-tsf slot 11:100s:100tu\n");
+ printf("\t wl proxd ftm 1 config avail time-ref dev-tsf slot 11:200s:300tu");
+ printf(" 11:600s:400tu\n");
+
+ return;
+}
+
+/*
+* handle
+* wl proxd -h
+* wl proxd -h ftm
+* wl proxd -h ftm <cmd>
+* wl proxd -h ftm config options
+* Output:
+* BCME_USAGE_ERROR -- caller should bring up 'proxd' level help messages
+* BCME_OK -- this func displays context-help for FTM method,
+* caller does not need to show any help messages.
+*/
+static int
+ftm_handle_help(char **argv)
+{
+ const ftm_subcmd_info_t *p_subcmd_info;
+
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+
+ if (stricmp(*argv, "ftm") != 0) /* check 'wl proxd -h ftm' */
+ return BCME_USAGE_ERROR;
+
+ ++argv;
+ if (*argv == NULL) {
+ /* show help messages for 'wl proxd -h ftm' */
+ ftm_display_method_help();
+ return BCME_OK;
+ }
+
+ /* parse 'wl proxd -h ftm <cmd>' */
+ p_subcmd_info = ftm_get_subcmd_info(*argv);
+ if (p_subcmd_info != NULL) {
+ if (p_subcmd_info->cmdid == WL_PROXD_CMD_CONFIG) {
+ /* help for 'wl proxd -h ftm config' */
+ ++argv;
+ if (*argv != NULL) { /* parse 'wl proxd -h ftm config options' */
+ if (stricmp(*argv, "options") == 0) {
+ /* display help for 'wl proxd -h ftm config options' */
+ ftm_display_config_options_help();
+ return BCME_OK;
+ }
+ if (stricmp(*argv, "avail") == 0) {
+ /* display help for 'wl proxd -h ftm config avail' */
+ ftm_display_config_avail_help();
+ return BCME_OK;
+ }
+ }
+
+ /* display help for 'wl proxd -h ftm config' */
+ ftm_display_config_help();
+ return BCME_OK;
+
+ }
+ else {
+ /* print help messages for a specific FTM sub-command */
+ ftm_display_cmd_help(p_subcmd_info, "");
+ return BCME_OK;
+ }
+ }
+
+ /* invalid <cmd>, display help messages for FTM method */
+ ftm_display_method_help();
+ return BCME_OK;
+}
+
+static const ftm_strmap_entry_t ftm_event_type_loginfo[] = {
+ /* wl_proxd_event_type_t, text-string */
+ { WL_PROXD_EVENT_NONE, "none" },
+ { WL_PROXD_EVENT_SESSION_CREATE, "session create" },
+ { WL_PROXD_EVENT_SESSION_START, "session start" },
+ { WL_PROXD_EVENT_FTM_REQ, "FTM req" },
+ { WL_PROXD_EVENT_BURST_START, "burst start" },
+ { WL_PROXD_EVENT_BURST_END, "burst end" },
+ { WL_PROXD_EVENT_SESSION_END, "session end" },
+ { WL_PROXD_EVENT_SESSION_RESTART, "session restart" },
+ { WL_PROXD_EVENT_BURST_RESCHED, "burst rescheduled" },
+ { WL_PROXD_EVENT_SESSION_DESTROY, "session destroy" },
+ { WL_PROXD_EVENT_RANGE_REQ, "range request" },
+ { WL_PROXD_EVENT_FTM_FRAME, "FTM frame" },
+ { WL_PROXD_EVENT_DELAY, "delay" },
+ { WL_PROXD_EVENT_VS_INITIATOR_RPT, "initiator-report " }, /* rx initiator-rpt */
+ { WL_PROXD_EVENT_RANGING, "ranging " },
+ { WL_PROXD_EVENT_LCI_MEAS_REP, "LCI measurement report" },
+ { WL_PROXD_EVENT_CIVIC_MEAS_REP, "civic measurement report" },
+ { WL_PROXD_EVENT_START_WAIT, "start wait" },
+};
+
+#if defined(linux)
+static const ftm_strmap_entry_t*
+ftm_get_event_type_loginfo(wl_proxd_event_type_t event_type)
+{
+ /* look up 'event-type' from a predefined table */
+ return ftm_get_strmap_info((int32) event_type,
+ ftm_event_type_loginfo, ARRAYSIZE(ftm_event_type_loginfo));
+}
+
+/*
+* check FTM event
+* return -1: if event's version does not match. In this case,
+* caller should continue the event checking.
+* return 0: this func reports receving a new-version FTM-event and
+* caller should skip the checking for this event.
+*/
+static int
+ftm_event_check(bcm_event_t *p_bcm_event)
+{
+ int status;
+ wl_proxd_event_t *p_event;
+ uint16 version;
+ wl_proxd_event_type_t event_type;
+ const ftm_strmap_entry_t *p_loginfo;
+ int tlvs_len;
+
+ /* move to bcm event payload, which is proxd event structure */
+ p_event = (wl_proxd_event_t *) (p_bcm_event + 1);
+ version = ltoh16(p_event->version);
+ if (version < WL_PROXD_API_VERSION) {
+#ifdef WL_FTM_DEBUG
+ printf("ignore non-ftm event version = 0x%x < WL_PROXD_API_VERSION (0x%x)\n",
+ version, WL_PROXD_API_VERSION);
+#endif /* WL_FTM_DEBUG */
+ return -1; /* let caller handle the old version */
+ }
+
+ event_type = (wl_proxd_event_type_t) ltoh16(p_event->type);
+#ifdef WL_FTM_DEBUG
+ printf("event_type=0x%x, ntoh16()=0x%x, ltoh16()=0x%x",
+ p_event->type, ntoh16(p_event->type), ltoh16(p_event->type));
+#endif /* WL_FTM_DEBUG */
+ p_loginfo = ftm_get_event_type_loginfo(event_type);
+ if (p_loginfo == NULL) {
+ printf("receive an invalid FTM event %d\n", event_type);
+ return 0; /* ignore this event */
+ }
+
+ /* get TLVs len, skip over event header */
+ tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs);
+ printf("receive '%s' event: version=0x%x len=%d method=%s sid=%d tlvs_len=%d\n",
+ p_loginfo->text,
+ version,
+ ltoh16(p_event->len),
+ ftm_method_value_to_logstr(ltoh16(p_event->method)),
+ ltoh16(p_event->sid),
+ tlvs_len);
+
+ /* print event contents TLVs */
+ if (tlvs_len > 0) {
+ /* unpack TLVs and invokes the cbfn to print the event content TLVs */
+ status = bcm_unpack_xtlv_buf((void *) NULL, (uint8 *)&p_event->tlvs[0],
+ tlvs_len, BCM_XTLV_OPTION_ALIGN32, ftm_unpack_xtlv_cbfn);
+ if (status != BCME_OK)
+ printf("Failed to unpack xtlv for an event\n");
+ }
+
+ return 0; /* indicate we have processed this FTM event */
+}
+#endif /* linux */
+#ifdef WL_FTM_DEBUG
+/*
+* Format an 'event' bitmask to a text-string to caller-provided buffer
+*/
+static void
+ftm_format_event_mask(wl_proxd_event_type_t event, char *p_strbuf, int bufsize)
+{
+ int i, nChars;
+ int event_enabled_count = 0;
+
+ memset(p_strbuf, 0, bufsize);
+
+ char *p_tmpbuf = p_strbuf;
+ const ftm_strmap_entry_t *p_loginfo = &ftm_event_type_loginfo[0];
+ for (i = 0; i < (int) ARRAYSIZE(ftm_event_type_loginfo); i++) {
+ if (WL_PROXD_EVENT_ENABLED(event, (wl_proxd_event_type_t) p_loginfo->id)) {
+ if (event_enabled_count == 0) {
+ if ((nChars = snprintf(p_tmpbuf, bufsize, "(")) < 0)
+ return; /* error, ignore */
+ bufsize -= nChars;
+ p_tmpbuf += nChars;
+ }
+
+ nChars = snprintf(p_tmpbuf, bufsize, "'%s' ", p_loginfo->text);
+ if (nChars < 0)
+ return; /* abort if error */
+ bufsize -= nChars;
+ p_tmpbuf += nChars;
+ event_enabled_count++;
+ }
+ p_loginfo++;
+ }
+
+ if (event_enabled_count > 0)
+ snprintf(p_tmpbuf, bufsize, ")");
+}
+#endif /* WL_FTM_DEBUG */
+
+/*
+* 'wl proxd ftm tune' handler,
+* wl proxd ftm tune
+*/
+static int
+ftm_handle_tune_options(char **argv, wl_proxd_tlv_t **p_tlv, uint16 *p_buf_space_left,
+ wl_proxd_params_tof_tune_t *tof_tune)
+{
+ miniopt_t to;
+ int opt_err;
+ int ret = BCME_USAGE_ERROR;
+
+ if (*argv == NULL)
+ return BCME_USAGE_ERROR;
+
+ miniopt_init(&to, "tune", NULL, FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ return BCME_USAGE_ERROR;
+ }
+ argv += to.consumed;
+ ret = proxd_tune_set_param_from_opt("proxd ftm tune", &to, tof_tune);
+ }
+#ifdef WL_FTM_DEBUG
+ prhex("tune_opt", (uint8*)tof_tune, sizeof(wl_proxd_params_tof_tune_t));
+#endif /* WL_FTM_DEBUG */
+ ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left,
+ WL_PROXD_TLV_ID_TUNE, sizeof(wl_proxd_params_tof_tune_t), (uint8*)tof_tune,
+ BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ printf("%s: failed to pack proxd ftm tune in xtlv, err=%d\n",
+ __FUNCTION__, ret);
+ return ret;
+ }
+
+ return BCME_OK;
+}
+
+/* Used for getting the current options before setting the new ones only */
+static int
+ftm_tune_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len)
+{
+ wl_proxd_params_tof_tune_t *tunep = (wl_proxd_params_tof_tune_t *)ctx;
+
+ if (tlvid == WL_PROXD_TLV_ID_TUNE) {
+#ifdef WL_FTM_DEBUG
+ prhex("ftm_tune_cbbn", p_data, len);
+#endif /* WL_FTM_DEBUG */
+ if (len < sizeof(wl_proxd_params_tof_tune_t)) {
+ /* FW has older version */
+ memcpy(&tunep->Ki, p_data, len);
+ } else {
+ memcpy(tunep, p_data, sizeof(wl_proxd_params_tof_tune_t));
+ }
+ }
+ return BCME_OK;
+}
+
+static int
+ftm_subcmd_tune(void *wl, const ftm_subcmd_info_t *p_subcmd_info,
+ wl_proxd_method_t method, wl_proxd_session_id_t session_id, char **argv)
+{
+ uint16 proxd_tune_method;
+ uint16 proxd_iovsize;
+ wl_proxd_iov_t *p_proxd_iov, *p_iovresp;
+ uint16 bufsize;
+ wl_proxd_tlv_t *p_tlv;
+ uint16 buf_space_left;
+ uint16 all_tlvsize = 0;
+ int ret = BCME_OK;
+ wl_proxd_params_tof_tune_t tof_tune; /* TOF tune parameters */
+ memset(&tof_tune, 0, sizeof(tof_tune));
+
+ /* this should apply to a method command */
+ if (session_id != WL_PROXD_SESSION_ID_GLOBAL) {
+ printf("error: no session-id is allowed for tune\n");
+ return BCME_OK;
+ }
+
+ /* skip the command name and check if mandatory exists */
+ if (!*argv) {
+ fprintf(stderr, "missing mandatory parameter \'method\'\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* parse method */
+ proxd_tune_method = (uint16)atoi(argv[0]);
+ if (proxd_tune_method == 0) {
+ fprintf(stderr, "invalid parameter \'method\'\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* only supports PROXD_TOF_METHOD */
+ if (proxd_tune_method == PROXD_RSSI_METHOD)
+ return BCME_OK;
+
+ if (!*++argv) {
+ /* get */
+ return ftm_common_getcmd_handler(wl, p_subcmd_info, method, session_id, argv);
+ } else {
+ /* allocate iovar getset buffer */
+ p_proxd_iov = ftm_alloc_getset_buf(method, session_id,
+ p_subcmd_info->cmdid, sizeof(wl_proxd_params_tof_tune_t),
+ &proxd_iovsize);
+ if (p_proxd_iov == (wl_proxd_iov_t *) NULL)
+ return BCME_NOMEM;
+ bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE;
+ p_tlv = &p_proxd_iov->tlvs[0];
+ buf_space_left = bufsize;
+
+ /* get current tune params */
+ ret = wlu_var_getbuf(wl, "proxd", p_proxd_iov, proxd_iovsize,
+ (void *)&p_iovresp);
+ if (ret != BCME_OK) {
+#ifdef WL_FTM_DEBUG
+ printf("%s: failed to send getbuf proxd iovar, status=%d\n",
+ __FUNCTION__, ret);
+#endif /* WL_FTM_DEBUG */
+ goto done;
+ }
+ if (p_iovresp != NULL) {
+ int tlvs_len = ltoh16(p_iovresp->len) - WL_PROXD_IOV_HDR_SIZE;
+ if (tlvs_len > 0) {
+ ret = bcm_unpack_xtlv_buf(&tof_tune, (uint8 *)p_iovresp->tlvs,
+ tlvs_len, BCM_XTLV_OPTION_ALIGN32, ftm_tune_cbfn);
+ }
+ }
+
+ /* handle options */
+ ret = ftm_handle_tune_options(argv, &p_tlv, &buf_space_left, &tof_tune);
+ if (ret == BCME_OK) {
+ /* prep to transport xtlv */
+ all_tlvsize = bufsize - buf_space_left;
+ p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE);
+ ret = wlu_var_setbuf(wl, "proxd", p_proxd_iov,
+ all_tlvsize + WL_PROXD_IOV_HDR_SIZE);
+ }
+ }
+
+done:
+ /* clean up */
+ free(p_proxd_iov);
+#ifdef wL_FTM_DEBUG
+ if (ret != BCME_OK)
+ printf("error: exit %s, status = %d\n", __FUNCTION__, ret);
+#endif /* WL_FTM_DEBUG */
+
+ return ret;
+}
+
+static int
+proxd_tune_display(wl_proxd_params_tof_tune_t *tof_tune, uint16 len)
+{
+ int err = BCME_OK;
+ int i, version = 0;
+
+ if (!tof_tune)
+ return err;
+
+ printf("Ki=%d \n", dtoh32(tof_tune->Ki));
+ printf("Kt=%d \n", dtoh32(tof_tune->Kt));
+ printf("vhtack=%d \n", dtoh16(tof_tune->vhtack));
+ printf("seq_en=%d\n", dtoh16(tof_tune->seq_en));
+ printf("core=%d\n", tof_tune->core);
+ printf("sw_adj=%d\n", dtoh16(tof_tune->sw_adj));
+ printf("hw_adj=%d\n", dtoh16(tof_tune->hw_adj));
+ printf("minDT = %d\n", tof_tune->minDT);
+ printf("maxDT = %d\n", tof_tune->maxDT);
+ printf("threshold_log2=%d %d %d seqtx %d seqrx %d 2g %d seqtx5g20 %d"
+ " seqrx5g20 %d seqtx2g20 %d seqrx2g20 %d\n",
+ dtoh16(tof_tune->N_log2[TOF_BW_20MHZ_INDEX]),
+ dtoh16(tof_tune->N_log2[TOF_BW_40MHZ_INDEX]),
+ dtoh16(tof_tune->N_log2[TOF_BW_80MHZ_INDEX]),
+ dtoh16(tof_tune->N_log2[TOF_BW_SEQTX_INDEX]),
+ dtoh16(tof_tune->N_log2[TOF_BW_SEQRX_INDEX]),
+ dtoh16(tof_tune->N_log2_2g),
+ dtoh16(tof_tune->seq_5g20.N_tx_log2),
+ dtoh16(tof_tune->seq_5g20.N_rx_log2),
+ dtoh16(tof_tune->seq_2g20.N_tx_log2),
+ dtoh16(tof_tune->seq_2g20.N_rx_log2));
+ printf("threshold_scale=%d %d %d seqtx %d seqrx %d 2g %d seqtx5g20 %d"
+ " seqrx5g20 %d seqtx2g20 %d seqrx2g20 %d\n",
+ dtoh16(tof_tune->N_scale[TOF_BW_20MHZ_INDEX]),
+ dtoh16(tof_tune->N_scale[TOF_BW_40MHZ_INDEX]),
+ dtoh16(tof_tune->N_scale[TOF_BW_80MHZ_INDEX]),
+ dtoh16(tof_tune->N_scale[TOF_BW_SEQTX_INDEX]),
+ dtoh16(tof_tune->N_scale[TOF_BW_SEQRX_INDEX]),
+ dtoh16(tof_tune->N_scale_2g),
+ dtoh16(tof_tune->seq_5g20.N_tx_scale),
+ dtoh16(tof_tune->seq_5g20.N_rx_scale),
+ dtoh16(tof_tune->seq_2g20.N_tx_scale),
+ dtoh16(tof_tune->seq_2g20.N_rx_scale));
+ printf("total_frmcnt=%d \n", tof_tune->totalfrmcnt);
+ printf("reserve_media=%d \n", tof_tune->rsv_media);
+ printf("flags=0x%x \n", dtoh16(tof_tune->flags));
+ for (i = 0; i < TOF_BW_NUM; i++) {
+ printf("window length %dMHz = %d\n",
+ (20 << i), tof_tune->w_len[i]);
+ printf("window offset %dMHz = %d\n",
+ (20 << i), tof_tune->w_offset[i]);
+ }
+ printf("seq window length 5G-20MHz = %2d 2G-20MHz = %2d\n",
+ tof_tune->seq_5g20.w_len,
+ tof_tune->seq_2g20.w_len);
+ printf("seq window offset 5G-20MHz = %2d 2G-20MHz = %2d\n",
+ tof_tune->seq_5g20.w_offset,
+ tof_tune->seq_2g20.w_offset);
+ printf("frame count=%d %d %d seq %d\n",
+ tof_tune->ftm_cnt[TOF_BW_20MHZ_INDEX],
+ tof_tune->ftm_cnt[TOF_BW_40MHZ_INDEX],
+ tof_tune->ftm_cnt[TOF_BW_80MHZ_INDEX],
+ tof_tune->ftm_cnt[TOF_BW_SEQTX_INDEX]);
+
+ if (len == sizeof(wl_proxd_params_tof_tune_t)) {
+ version = dtoh32(tof_tune->version);
+ switch (version) {
+ case WL_PROXD_TUNE_VERSION_1:
+ printf("bitflip threshold=%u\n", dtoh16(tof_tune->bitflip_thresh));
+ printf("SNR threshold=%u\n", dtoh16(tof_tune->snr_thresh));
+ printf("2G receive sensitivity threshold=%d\n", tof_tune->recv_2g_thresh);
+ printf("ACS GDV threshold=%u\n", dtoh32(tof_tune->acs_gdv_thresh));
+ printf("ACS RSSI threshold=%d\n", tof_tune->acs_rssi_thresh);
+ printf("Smoothing window enable=%u\n", tof_tune->smooth_win_en);
+ break;
+ default:
+ break;
+ }
+ }
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_randmac.c b/wl/src/wl/exe/wluc_randmac.c
new file mode 100644
index 0000000..01cd0e8
--- /dev/null
+++ b/wl/src/wl/exe/wluc_randmac.c
@@ -0,0 +1,807 @@
+/*
+ * wl randmac command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id$
+ */
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifdef WIN32
+#define bzero(b, len) memset((b), 0, (len))
+#endif
+
+#ifdef LINUX
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* LINUX */
+
+#include <miniopt.h>
+#include <errno.h>
+
+#define RANDMAC_IOC_BUFSZ 2048
+#define WL_RANDMAC_IOV_VERSION_SIZE (sizeof(wl_randmac_version_t))
+#define WL_RANDMAC_IOV_CONFIG_SIZE (sizeof(wl_randmac_config_t))
+#define WL_RANDMAC_IOV_STATS_SIZE (sizeof(wl_randmac_stats_t))
+
+static cmd_func_t wl_randmac;
+
+typedef struct randmac_subcmd_info randmac_subcmd_info_t;
+typedef int (randmac_subcmd_handler_t)(void *wl, const randmac_subcmd_info_t *p_subcmd_info,
+ char **argv);
+
+struct randmac_subcmd_info {
+ char *name; /* subcmd-name */
+ wl_randmac_subcmd_t subcmd_id; /* id */
+ wl_randmac_method_t method;
+ randmac_subcmd_handler_t *handler; /* subcmd handler */
+ char *helpmsg; /* message for wl randmac -h config */
+};
+
+typedef struct randmac_config_method_param_info {
+ char *name;
+ uint16 value;
+} randmac_config_method_param_info_t;
+
+static const randmac_config_method_param_info_t randmac_config_methods[] = {
+ /* Name Value */
+ { "None", WL_RANDMAC_USER_NONE },
+ { "FTM", WL_RANDMAC_USER_FTM },
+ { "NAN", WL_RANDMAC_USER_NAN },
+ { "SCAN", WL_RANDMAC_USER_SCAN },
+ { "ALL", 0xFFFF },
+};
+
+typedef struct randmac_config_param_info {
+ char *name; /* <param-name> identify configuration item */
+ wl_randmac_tlv_id_t tlvid; /* map config item TLV id */
+ char *name_helpmsg; /* help message */
+} randmac_config_param_info_t;
+
+static const randmac_config_param_info_t randmac_config_param_info[] = {
+ /* Name TLV ID Help Message */
+ {"mac-addr", WL_RANDMAC_TLV_ADDR, "Random MAC/OUI as xx:xx:xx:xx:xx:xx" },
+ {"bitmask", WL_RANDMAC_TLV_MASK, "Bitmask yy:yy:yy:yy:yy:yy" },
+ {"method", WL_RANDMAC_TLV_METHOD, "Methods using random MAC FTM|NAN|SCAN" }
+};
+
+static cmd_t wl_randmac_cmds[] = {
+ { "randmac", wl_randmac, WLC_GET_VAR, WLC_SET_VAR,
+ "\tEnable/Disable MAC Address Randomization\n"
+ "\t0 : disable\n"
+ "\t1 : enable\n"
+ "\tUsage: wl randmac enable\n\n"
+ "\t\t wl randmac disable\n\n"
+ "config [<param-name><param-value>...]\n"
+ "\tGet/Set MAC address (OUI), bitmask, method\n\n"
+ "\tGet current configuration\n"
+ "\tUsage: wl randmac config\n"
+ "\tSet or update new configuration\n"
+ "\tUsage: wl randmac config mac-addr <xx:xx:xx:xx:xx:xx> bitmask <yy:yy:yy:yy:yy:yy> "
+ "<method [ALL|FTM|NAN|SCAN]>"
+ "version"
+ "\tGet version\n\n"
+ "\tUsage: wl randmac version\n\n"
+ "getstats"
+ "\tGet statistics\n\n"
+ "\tUsage: wl randmac getstats\n\n"
+ "clearstats"
+ "\tClear statistics\n\n"
+ "\tUsage: wl randmac clearstats\n\n" },
+
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+static wl_randmac_t *randmac_alloc_getset_buf(wl_randmac_subcmd_t subcmd_id,
+ uint16 subcmd_bufsize);
+static int wl_randmac_subcmd_method_handler(void *wl, cmd_t *cmd, char **argv);
+static int randmac_common_getcmd_handler(void *wl,
+ const randmac_subcmd_info_t *p_subcmd_info, char **argv);
+static int randmac_do_get_ioctl(void *wl, wl_randmac_t *p_iov, uint16 iov_len,
+ const randmac_subcmd_info_t *p_subcmd_info);
+static int randmac_handle_help(char **argv);
+static void randmac_display_config_help();
+
+/* module initialization */
+void
+wluc_randmac_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register randmac commands */
+ wl_module_cmds_register(wl_randmac_cmds);
+}
+
+static int
+wl_randmac(void *wl, cmd_t *cmd, char **argv)
+{
+ uint16 randmac_iovsize;
+ wl_randmac_t *p_randmac_iov = NULL;
+ int ret;
+
+ /* skip the command name and check if NULL */
+ if (argv[1] == NULL) {
+ wl_randmac_t *iov_resp;
+ randmac_iovsize = 0;
+ p_randmac_iov = randmac_alloc_getset_buf(WL_RANDMAC_SUBCMD_ENABLE,
+ randmac_iovsize);
+ /* Get wl randmac */
+ if (!p_randmac_iov) {
+ ret = BCME_NOMEM;
+ goto done;
+ }
+ ret = wlu_var_getbuf(wl, cmd->name, p_randmac_iov, sizeof(*p_randmac_iov),
+ (void *)&iov_resp);
+ if (ret != BCME_OK) {
+ goto done;
+ }
+
+ printf(">%s\n",
+ (iov_resp->subcmd_id == WL_RANDMAC_SUBCMD_ENABLE) ? "Enabled" : "Disabled");
+ goto done;
+
+ } else {
+ /* Set */
+ argv++;
+ ret = wl_randmac_subcmd_method_handler(wl, cmd, argv);
+ }
+done:
+ if (p_randmac_iov) {
+ free(p_randmac_iov);
+ }
+ return ret;
+}
+
+/* declare randmac subcommand handlers randmac_subcmd_xxxx() */
+/* e.g. static randmac_cmd_handler_t randmac_subcmd_get_version; */
+#define RANDMAC_SUBCMD_FUNC(suffix) randmac_subcmd_ ##suffix
+#define DECL_CMDHANDLER(X) static randmac_subcmd_handler_t randmac_subcmd_##X
+
+/* get */
+DECL_CMDHANDLER(get_version); /* method-only */
+
+/* set */
+DECL_CMDHANDLER(enable); /* method */
+DECL_CMDHANDLER(disable); /* method */
+DECL_CMDHANDLER(config); /* method */
+DECL_CMDHANDLER(getstats); /* method */
+DECL_CMDHANDLER(clearstats); /* method */
+
+static const randmac_subcmd_info_t randmac_subcmdlist[] = {
+ /* Name Subcommand Method Handler Help */
+ {"version", WL_RANDMAC_SUBCMD_GET_VERSION, WL_RANDMAC_USER_NONE,
+ RANDMAC_SUBCMD_FUNC(get_version), "Get randmac method API version information" },
+ {"enable", WL_RANDMAC_SUBCMD_ENABLE, WL_RANDMAC_USER_NONE,
+ RANDMAC_SUBCMD_FUNC(enable), "Enable randmac method"},
+ {"disable", WL_RANDMAC_SUBCMD_ENABLE, WL_RANDMAC_USER_NONE,
+ RANDMAC_SUBCMD_FUNC(disable), "Disable randmac method"},
+ {"config", WL_RANDMAC_SUBCMD_CONFIG, WL_RANDMAC_USER_NONE,
+ RANDMAC_SUBCMD_FUNC(config),
+ "Configure random MAC OUI, bitmask to randomize MAC address and method"},
+ {"getstats", WL_RANDMAC_SUBCMD_STATS, WL_RANDMAC_USER_NONE,
+ RANDMAC_SUBCMD_FUNC(getstats),
+ "Get MAC randomization method statistics"},
+ {"clearstats", WL_RANDMAC_SUBCMD_CLEAR_STATS, WL_RANDMAC_USER_NONE,
+ RANDMAC_SUBCMD_FUNC(clearstats), "Clear MAC randomization method statistics"},
+};
+
+const randmac_subcmd_info_t *
+randmac_get_subcmd_info(char *cmdname)
+{
+ int i;
+ const randmac_subcmd_info_t *p_subcmd_info;
+
+ /* Search subcmd name */
+ p_subcmd_info = &randmac_subcmdlist[0];
+ for (i = 0; i < (int)ARRAYSIZE(randmac_subcmdlist); i++) {
+ if (stricmp(p_subcmd_info->name, cmdname) == 0)
+ return p_subcmd_info;
+ p_subcmd_info++;
+ }
+
+ return NULL;
+}
+
+static int
+randmac_subcmd_get_version(void *wl,
+ const randmac_subcmd_info_t *p_subcmd_info, char **argv)
+{
+ /* Issue IOVAR and display version information */
+ return randmac_common_getcmd_handler(wl, p_subcmd_info, argv);
+}
+/*
+* 'wl randmac ascii-method' handler
+* handle 'wl randmac <cmdname> [<param-name><param-value>]*'
+*/
+static int
+wl_randmac_subcmd_method_handler(void *wl, cmd_t *cmd, char **argv)
+{
+ const randmac_subcmd_info_t *p_subcmd_info;
+
+ /* ignore the command name 'proxd' */
+ UNUSED_PARAMETER(cmd);
+
+ /*
+ * check for "wl randmac -h config" or
+ * "wl randmac help config" --> display the usage
+ */
+ if (!stricmp(*argv, "-h") || !stricmp(*argv, "help")) {
+ return randmac_handle_help(++argv); /* return BCME_USAGE_ERROR; */
+ }
+
+ /*
+ * search for the specified <cmdname> from the
+ * pre-defined supported cmd list
+ */
+ p_subcmd_info = randmac_get_subcmd_info(*argv);
+ if (p_subcmd_info == NULL) {
+ /* cannot find the cmd in the randmac_subcmdlist */
+ return BCME_USAGE_ERROR;
+ }
+
+ /* dispatch cmd to appropriate handler */
+ if (p_subcmd_info->handler) {
+ return p_subcmd_info->handler(wl, p_subcmd_info, ++argv);
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ return BCME_OK;
+
+}
+
+/* ***************************** set commands ********************* */
+
+/* randmac config-category definition */
+typedef enum {
+ RANDMAC_CONFIG_CAT_GENERAL = 1, /* generial configuration */
+} randmac_config_category_t;
+
+/*
+* display help-messages for 'wl randmac -h config'
+*/
+static void
+randmac_display_method_help()
+{
+ int i;
+ int max_cmdname_len = 20;
+ const randmac_subcmd_info_t *p_subcmd_info;
+
+ /* a header */
+ printf("\n\tMAC Address Randomization\n");
+ printf("\tUsage: wl randmac <cmd> [<param-name> <param-value>]*\n");
+ printf("\t\t<cmd>: specify a command from the following list,\n");
+
+ /* show the command list and the help messages for each FTM command */
+ p_subcmd_info = &randmac_subcmdlist[0];
+ for (i = 0; i < (int) ARRAYSIZE(randmac_subcmdlist); i++) {
+ printf("\t\t %*s: %s\n", max_cmdname_len, p_subcmd_info->name,
+ p_subcmd_info->helpmsg);
+ p_subcmd_info++;
+ }
+
+ printf("\t\t<param-name> <param-value>: <cmd>-specific parameters\n\n");
+
+ printf("\t\ttype 'wl randmac -h config' for configuration command usage.\n");
+
+ /* show examples */
+ printf("\tExample: wl randmac [0/1 0 - Disable, 1 - Enable]\n\n");
+ printf("\tExample: wl randmac config "
+ "[Random MAC Address/OUI<xx:xx:xx:xx:xx:xx>] "
+ "[Bitmask to randmize MAC Address<yy:yy:yy:yy:yy:yy>] [Method <FTM>]\n\n");
+
+ return;
+}
+
+/*
+* display help-messages for 'wl randmac -h config'
+*/
+static void
+randmac_display_config_help()
+{
+ int i;
+ int max_param_name_len = 20;
+ const randmac_config_param_info_t *p_config_param_info;
+
+ /* a header */
+ printf("\n\tConfigure MAC Address Randomization feature\n");
+ printf("\tUsage: wl randmac config { <param-name> <param-value> }+ \n");
+ /* print helpmsg for each config-item */
+ printf("\t\t<param-name> <param-value>: "
+ "configuration parameters from the following\n");
+ p_config_param_info = &randmac_config_param_info[0];
+ for (i = 0; i < (int) ARRAYSIZE(randmac_config_param_info); i++) {
+ printf("\t\t %*s: %s\n", max_param_name_len, p_config_param_info->name,
+ p_config_param_info->name_helpmsg);
+
+ p_config_param_info++;
+ }
+
+ /* show examples */
+ printf("\n\tExample: wl randmac config mac-addr <xx:xx:xx:xx:xx:xx> "
+ "bitmask <yy:yy:yy:yy:yy:yy> method <FTM>\n");
+}
+
+/*
+* handle
+* wl randmac -h
+* wl randmac -h config
+* Output:
+* BCME_USAGE_ERROR -- caller should bring up 'randmac' level help messages
+* BCME_OK -- this func displays context-help for RANDMAC method,
+* caller does not need to show any help messages.
+*/
+static int
+randmac_handle_help(char **argv)
+{
+ if (!*argv)
+ return BCME_USAGE_ERROR;
+
+ if (stricmp(*argv, "config") != 0) /* check 'wl randmac -h config' */
+ return BCME_USAGE_ERROR;
+
+ ++argv;
+ if (*argv == NULL) {
+ /* show help messages for 'wl randmac -h config' */
+ randmac_display_config_help();
+ return BCME_OK;
+ }
+
+ /* invalid <cmd>, display help messages for RANDMAC method */
+ randmac_display_method_help();
+ return BCME_OK;
+}
+
+static randmac_config_category_t
+randmac_parse_config_category(char *arg_category)
+{
+ BCM_REFERENCE(arg_category);
+ return RANDMAC_CONFIG_CAT_GENERAL;
+}
+
+static const randmac_config_param_info_t *
+randmac_get_config_param_info(char *p_param_name)
+{
+ int i;
+ const randmac_config_param_info_t *p_config_param_info;
+
+ p_config_param_info = &randmac_config_param_info[0];
+ for (i = 0; i < (int) ARRAYSIZE(randmac_config_param_info); i++) {
+ if (stricmp(p_param_name, p_config_param_info->name) == 0) {
+ return p_config_param_info;
+ }
+ p_config_param_info++; /* next */
+ }
+ return (randmac_config_param_info_t *) NULL; /* 'invalid param name' */
+}
+
+static uint16
+randmac_parse_method(char *method_name)
+{
+ int i = 0;
+ const randmac_config_method_param_info_t *p_method_param_info;
+
+ p_method_param_info = &randmac_config_methods[0];
+
+ for (; i < (int) ARRAYSIZE(randmac_config_methods); i++) {
+ if (stricmp(method_name, p_method_param_info->name) == 0) {
+ return p_method_param_info->value;
+ }
+ p_method_param_info++;
+ }
+
+ return 0;
+}
+
+static int
+randmac_handle_config_general(char **argv, wl_randmac_config_t *p_config)
+{
+ int status = BCME_OK;
+ const randmac_config_param_info_t *p_config_param_info;
+ char *method_name;
+
+ /* check if user provides param-values for 'config options' command */
+ if (*argv == NULL)
+ return BCME_USAGE_ERROR;
+
+ /* <param-value> followed 'wl proxd ftm [session-id] config options' */
+ while (*argv != NULL) {
+ /* look up 'config-param-info' based on 'param-name' */
+ p_config_param_info = randmac_get_config_param_info(*argv);
+ if (p_config_param_info == (randmac_config_param_info_t *) NULL) {
+ printf("error: invalid param-name (%s)\n", *argv);
+ status = BCME_USAGE_ERROR; /* param-name is not specified */
+ break;
+ }
+
+ /* parse 'param-value' */
+ if (*(argv + 1) == NULL) {
+ printf("error: invalid param-value\n");
+ status = BCME_USAGE_ERROR; /* param-value is not specified */
+ break;
+ }
+ ++argv;
+
+ /* parse param-value */
+ switch (p_config_param_info->tlvid) {
+ case WL_RANDMAC_TLV_ADDR:
+ p_config->addr = ether_null;
+ if (!wl_ether_atoe(*argv, &p_config->addr)) {
+ printf("error: invalid MAC address parameter\n");
+ status = BCME_USAGE_ERROR;
+ break;
+ }
+ p_config->flags |= WL_RANDMAC_FLAGS_ADDR;
+ break;
+
+ case WL_RANDMAC_TLV_MASK:
+ p_config->addr_mask = ether_null;
+ if (!wl_ether_atoe(*argv, &p_config->addr_mask)) {
+ printf("error: invalid MAC address parameter\n");
+ status = BCME_USAGE_ERROR;
+ break;
+ }
+ p_config->flags |= WL_RANDMAC_FLAGS_MASK;
+ break;
+
+ case WL_RANDMAC_TLV_METHOD:
+ method_name = *argv;
+ p_config->method |= randmac_parse_method(method_name);
+ p_config->flags |= WL_RANDMAC_FLAGS_METHOD;
+ break;
+
+ default:
+ /* not supported */
+ status = BCME_USAGE_ERROR;
+ break;
+ }
+
+ if (status != BCME_OK)
+ break; /* abort */
+
+ ++argv; /* Next param */
+ }
+
+ return status;
+}
+
+static int
+randmac_subcmd_disable(void *wl, const randmac_subcmd_info_t *p_subcmd_info,
+ char **argv)
+{
+ return randmac_subcmd_enable(wl, p_subcmd_info, argv);
+}
+
+static int
+randmac_subcmd_enable(void *wl, const randmac_subcmd_info_t *p_subcmd_info,
+ char **argv)
+{
+ wl_randmac_t *p_iov = NULL;
+ int status = BCME_OK;
+ uint16 iov_len = WL_RANDMAC_IOV_HDR_SIZE;
+
+ BCM_REFERENCE(*argv);
+ /* allocate a buffer for randmac config via 'set' iovar */
+ p_iov = randmac_alloc_getset_buf(p_subcmd_info->subcmd_id, iov_len);
+ if (p_iov == (wl_randmac_t *) NULL) {
+ status = BCME_NOMEM;
+ goto done;
+ }
+
+ if (!(stricmp("enable", p_subcmd_info->name))) {
+ p_iov->subcmd_id = WL_RANDMAC_SUBCMD_ENABLE;
+ } else if (!(stricmp("disable", p_subcmd_info->name))) {
+ p_iov->subcmd_id = WL_RANDMAC_SUBCMD_DISABLE;
+ } else {
+ randmac_display_method_help();
+ }
+ p_iov->version = WL_RANDMAC_API_VERSION;
+ p_iov->len = iov_len;
+ status = wlu_var_setbuf(wl, "randmac", p_iov, iov_len);
+
+done:
+ if (p_iov) {
+ /* clean up */
+ free(p_iov);
+ }
+ return status;
+}
+
+static int
+randmac_subcmd_config(void *wl, const randmac_subcmd_info_t *p_subcmd_info,
+ char **argv)
+{
+ wl_randmac_t *p_iov = NULL;
+ int status = BCME_OK;
+ wl_randmac_config_t *p_config;
+ uint16 iov_len = WL_RANDMAC_IOV_HDR_SIZE;
+ randmac_config_category_t category;
+
+ if (*argv == NULL) {
+ status = randmac_common_getcmd_handler(wl, p_subcmd_info, argv);
+ goto done;
+ }
+
+ /* allocate a buffer for randmac config via 'set' iovar */
+ iov_len += sizeof(*p_config);
+ p_iov = randmac_alloc_getset_buf(p_subcmd_info->subcmd_id, iov_len);
+ if (p_iov == (wl_randmac_t *) NULL) {
+ status = BCME_NOMEM;
+ goto done;
+ }
+
+ /* setup config data */
+ p_config = (wl_randmac_config_t *)&p_iov->data[0];
+
+ /* parse the cmd-line, get the config-category and dispatch to the handler */
+ /* to parse the parameters based on the 'config-category' */
+ category = randmac_parse_config_category(*argv);
+ if (category == RANDMAC_CONFIG_CAT_GENERAL)
+ status = randmac_handle_config_general(argv, p_config);
+
+ if (status == BCME_USAGE_ERROR) {
+ randmac_display_config_help();
+ } else {
+ p_iov->version = WL_RANDMAC_API_VERSION;
+ p_iov->subcmd_id = WL_RANDMAC_SUBCMD_CONFIG;
+ p_iov->len = WL_RANDMAC_IOV_CONFIG_SIZE;
+ status = wlu_var_setbuf(wl, "randmac", p_iov, iov_len);
+ }
+
+done:
+ if (p_iov) {
+ /* clean up */
+ free(p_iov);
+ }
+ return status;
+}
+
+static int
+randmac_subcmd_getstats(void *wl, const randmac_subcmd_info_t *p_subcmd_info,
+ char **argv)
+{
+ return randmac_common_getcmd_handler(wl, p_subcmd_info, argv);
+}
+
+static int
+randmac_subcmd_clearstats(void *wl, const randmac_subcmd_info_t *p_subcmd_info,
+ char **argv)
+{
+ wl_randmac_t *p_iov;
+ int status = BCME_OK;
+ uint16 iov_len = WL_RANDMAC_IOV_HDR_SIZE;
+
+ BCM_REFERENCE(*argv);
+ /* allocate a buffer for randmac config via 'set' iovar */
+ p_iov = randmac_alloc_getset_buf(p_subcmd_info->subcmd_id, iov_len);
+ if (p_iov == (wl_randmac_t *) NULL) {
+ status = BCME_NOMEM;
+ goto done;
+ }
+
+ p_iov->version = WL_RANDMAC_API_VERSION;
+ p_iov->subcmd_id = WL_RANDMAC_SUBCMD_CLEAR_STATS;
+ p_iov->len = iov_len;
+ status = wlu_var_setbuf(wl, "randmac", p_iov, iov_len);
+
+done:
+ if (p_iov) {
+ /* clean up */
+ free(p_iov);
+ }
+ return status;
+}
+
+static wl_randmac_t *
+randmac_alloc_getset_buf(wl_randmac_subcmd_t subcmd_id, uint16 subcmd_bufsize)
+{
+ uint16 randmac_iovsize;
+ wl_randmac_t *p_randmac_iov = (wl_randmac_t *)NULL;
+
+ BCM_REFERENCE(subcmd_id);
+ /* header + subcommand */
+ randmac_iovsize = sizeof(wl_randmac_t) + subcmd_bufsize;
+
+ p_randmac_iov = calloc(1, randmac_iovsize);
+ if (p_randmac_iov == NULL) {
+ printf("error: failed to allocate %d bytes of memory\n", randmac_iovsize);
+ return NULL;
+ }
+
+ /* setup randmac method iovar header */
+ p_randmac_iov->version = htol16(WL_RANDMAC_API_VERSION);
+ /* caller may adjust it based on subcommand */
+ p_randmac_iov->len = htol16(randmac_iovsize);
+ p_randmac_iov->subcmd_id = htol16(subcmd_id);
+
+ return p_randmac_iov;
+}
+
+static int
+randmac_common_getcmd_handler(void *wl, const randmac_subcmd_info_t *p_subcmd_info,
+ char **argv)
+{
+ int status = BCME_OK;
+ uint16 iov_len = WL_RANDMAC_IOV_HDR_SIZE;
+ wl_randmac_t *p_iov = (wl_randmac_t *) NULL;
+
+ BCM_REFERENCE(*argv);
+ switch (p_subcmd_info->subcmd_id) {
+ case WL_RANDMAC_SUBCMD_GET_VERSION:
+ iov_len += WL_RANDMAC_IOV_VERSION_SIZE;
+ p_iov = randmac_alloc_getset_buf(p_subcmd_info->subcmd_id, iov_len);
+ break;
+
+ case WL_RANDMAC_SUBCMD_CONFIG:
+ iov_len += WL_RANDMAC_IOV_CONFIG_SIZE;
+ p_iov = randmac_alloc_getset_buf(p_subcmd_info->subcmd_id, iov_len);
+ break;
+
+ case WL_RANDMAC_SUBCMD_STATS:
+ iov_len += WL_RANDMAC_IOV_STATS_SIZE;
+ p_iov = randmac_alloc_getset_buf(p_subcmd_info->subcmd_id, iov_len);
+ break;
+
+ default:
+ /* Unknown subcommand */
+ break;
+ }
+
+ if (p_iov != NULL) {
+ /* get */
+ status = randmac_do_get_ioctl(wl, p_iov, iov_len, p_subcmd_info);
+ }
+
+ /* Clean up memory */
+ free(p_iov);
+
+ return status;
+}
+
+static int
+randmac_do_get_ioctl(void *wl, wl_randmac_t *p_iov, uint16 iov_len,
+const randmac_subcmd_info_t *p_subcmd_info)
+{
+ /* for gets we only need to pass ioc header */
+ wl_randmac_t *p_iovresp = NULL;
+ int status;
+ /* send getbuf proxd iovar */
+ status = wlu_var_getbuf(wl, "randmac", p_iov, iov_len, (void *)&p_iovresp);
+ if (status != BCME_OK) {
+ return status;
+ }
+
+ if (p_iovresp != NULL) {
+ switch (p_subcmd_info->subcmd_id) {
+ case WL_RANDMAC_SUBCMD_GET_VERSION:
+ {
+ wl_randmac_version_t *p_iov_ver;
+ p_iov_ver = (wl_randmac_version_t *)(&p_iovresp->data[0]);
+ printf("> Version: 0x%04x\n", p_iov_ver->version);
+ }
+ break;
+
+ case WL_RANDMAC_SUBCMD_DISABLE:
+ case WL_RANDMAC_SUBCMD_ENABLE:
+ {
+ printf(">%s\n",
+ (p_subcmd_info->subcmd_id == WL_RANDMAC_SUBCMD_ENABLE) ?
+ "Enabled" : "Disabled");
+ }
+ break;
+
+ case WL_RANDMAC_SUBCMD_CONFIG:
+ {
+ uint32 i = 0;
+ const randmac_config_method_param_info_t *methods_info;
+ wl_randmac_config_t *p_iov_config;
+ p_iov_config = (wl_randmac_config_t *)(&p_iovresp->data[0]);
+ printf(">MAC Address:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ p_iov_config->addr.octet[0],
+ p_iov_config->addr.octet[1],
+ p_iov_config->addr.octet[2],
+ p_iov_config->addr.octet[3],
+ p_iov_config->addr.octet[4],
+ p_iov_config->addr.octet[5]);
+ printf(">Bitmask:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ p_iov_config->addr_mask.octet[0],
+ p_iov_config->addr_mask.octet[1],
+ p_iov_config->addr_mask.octet[2],
+ p_iov_config->addr_mask.octet[3],
+ p_iov_config->addr_mask.octet[4],
+ p_iov_config->addr_mask.octet[5]);
+ if (p_iov_config->method == WL_RANDMAC_USER_NONE) {
+ printf("> Method: None\n");
+ } else if (p_iov_config->method == WL_RANDMAC_USER_ALL) {
+ printf(">Method: All\n");
+ } else {
+ printf(">Method:");
+ while (p_iov_config->method) {
+ if (p_iov_config->method & (1 << i)) {
+ methods_info =
+ &randmac_config_methods[i + 1];
+ printf(" %s ", methods_info->name);
+ p_iov_config->method &= ~(1 << i);
+ }
+ i++;
+ }
+ printf("\n");
+ }
+ }
+ break;
+ case WL_RANDMAC_SUBCMD_STATS:
+ {
+ wl_randmac_stats_t *pstats =
+ (wl_randmac_stats_t *)(&p_iovresp->data[0]);
+ printf(">MAC randomization set calls success:\t %u\n",
+ pstats->set_ok);
+ printf(">MAC randomization set calls failed:\t %u\n",
+ pstats->set_fail);
+ printf(">MAC randomization set requests:\t %u\n",
+ pstats->set_reqs);
+ printf(">MAC randomization reset requests:\t %u\n",
+ pstats->reset_reqs);
+ printf(">MAC randomization restore calls success:%u\n",
+ pstats->restore_ok);
+ printf(">MAC randomization restore calls failed: %u\n",
+ pstats->restore_fail);
+ printf(">MAC randomization events sent:\t\t %u\n",
+ pstats->events_sent);
+ printf(">MAC randomization events received:\t %u\n",
+ pstats->events_rcvd);
+ printf("\n");
+ }
+ break;
+
+ default:
+ /* Unknown response */
+ break;
+ }
+ }
+
+ return status;
+}
diff --git a/wl/src/wl/exe/wluc_relmcast.c b/wl/src/wl/exe/wluc_relmcast.c
new file mode 100644
index 0000000..bdd00ce
--- /dev/null
+++ b/wl/src/wl/exe/wluc_relmcast.c
@@ -0,0 +1,607 @@
+/*
+ * wl rmc command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_relmcast.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+#include <miniopt.h>
+
+static cmd_func_t wl_mcast_ackmac, wl_mcast_ackreq, wl_mcast_status;
+static cmd_func_t wl_mcast_actf_time, wl_mcast_rssi_thresh, wl_mcast_stats;
+static cmd_func_t wl_mcast_rssi_delta, wl_mcast_vsie, wl_mcast_ar_timeout;
+
+static cmd_t wl_rmc_cmds[] = {
+ { "rmc_ackmac", wl_mcast_ackmac, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get ACK required multicast mac address\n"
+ "\tusage: wl rmc_ackmac -i [index] -t [multicast mac address]"
+ },
+ { "rmc_ackreq", wl_mcast_ackreq, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get ACK rmc_mode 0 disable, 1 enable transmitter, 2 enable initiator \n"
+ "\tusage: wl rmc_ackreq [mode]"
+ },
+ { "rmc_txrate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get a fixed transmit rate for the reliable multicast:\n"
+ "\tvalid values for 802.11ac are (6, 9, 12, 18, 24, 36, 48, 54)\n"
+ "\t-1 (default) means automatically determine the best rate"
+ },
+ { "rmc_status", wl_mcast_status, WLC_GET_VAR, -1,
+ "Display reliable multicast client status"
+ },
+ { "rmc_actf_time", wl_mcast_actf_time, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get mcast action frame tx time period in ms\n"
+ "\tusage: wl rmc_actf_time [value]"
+ },
+ { "rmc_ar_timeout", wl_mcast_ar_timeout, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get rmc active receiver timeout in ms\n"
+ "\tusage: wl rmc_ar_timeout [duration in ms]"
+ },
+ { "rmc_rssi_thresh", wl_mcast_rssi_thresh, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get minimum rssi needed for a station to be an active receiver\n"
+ "\tusage: wl rmc_rssi_thresh [value]"
+ },
+ { "rmc_stats", wl_mcast_stats, WLC_GET_VAR, WLC_SET_VAR,
+ "Display/Clear reliable multicast client statistical counters\n"
+ "\tusage: wl rmc_stats [arg]"
+ },
+ { "rmc_rssi_delta", wl_mcast_rssi_delta, WLC_GET_VAR, WLC_SET_VAR,
+ "Display/Set RSSI delta to switch receive leader\n"
+ "\tusage: wl rmc_rssi_delta [arg]"
+ },
+ { "rmc_vsie", wl_mcast_vsie, WLC_GET_VAR, WLC_SET_VAR,
+ "Display/Set vendor specific IE contents\n"
+ "\tusage: wl rmc_vsie [OUI] [Data]"
+ },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_rmc_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register rmc commands */
+ wl_module_cmds_register(wl_rmc_cmds);
+}
+
+static int
+wl_mcast_ackmac(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ int i, err;
+ uint8 num_tr;
+ wl_rmc_entry_t ackmac_params;
+ wl_rmc_entry_table_t tablelist;
+ void *ptr = NULL;
+ wl_rmc_trans_in_network_t *reply = NULL;
+ miniopt_t to;
+ struct ether_addr* ea = NULL;
+ bool index_set = FALSE; bool mac_set = FALSE;
+
+ /* muticast mac address - ipv4 & ipv6 resp. */
+ uint8 mc_mac[6] = {0x1, 0x0, 0x5e, 0x7f, 0xff, 0xff};
+ uint8 mc_mac_ipv6[6] = {0x33, 0x33, 0x0, 0x0, 0x0, 0x0};
+
+ /* index will tell us what to do */
+
+ if (!*++argv) {
+ /* Get and display all entries in the table */
+ if ((ret = wlu_var_getbuf(wl, cmd->name,
+ NULL,
+ 0,
+ &ptr)) < 0) {
+ return ret;
+ }
+ reply = (wl_rmc_trans_in_network_t*)ptr;
+ num_tr = reply->num_tr;
+
+ printf("\n Num of transmitters %02x ", num_tr);
+ printf("\n Transmitter Mac \t AR Mac");
+ printf("\t rmc_ar_timeout\t amt_idx flag ");
+
+ for (i = 0; (i < WL_RMC_MAX_NUM_TRS) && (i < num_tr); i++) {
+ printf("\n %s \t", wl_ether_etoa(&reply->trs[i].tr_mac));
+ printf(" %s \t", wl_ether_etoa(&reply->trs[i].ar_mac));
+ printf(" %d \t %d %04x",
+ reply->trs[i].artmo, reply->trs[i].amt_idx, reply->trs[i].flag);
+ }
+
+ printf("\n");
+ return 0;
+ }
+
+ miniopt_init(&to, cmd->name, NULL, FALSE);
+
+ while ((err = miniopt(&to, argv)) != -1) {
+ if (err == 1) {
+ return BCME_USAGE_ERROR;
+ }
+ argv += to.consumed;
+ /* Index for multicast address in RMC table */
+ if (to.opt == 'i') {
+ /* wl rmc_ackmac -i 8 -t <control multi-cast address> */
+ /* this is used to change the AF multi-cast address */
+ if (!to.good_int || ((to.val != 8) && to.val)) {
+ fprintf(stderr, "%s: Invalid mode value\n", cmd->name);
+ err = -1;
+ goto exit;
+ }
+ tablelist.index = to.val;
+ index_set = TRUE;
+ }
+
+ /* Add multicast address with index "i" to RMC table */
+ if (to.opt == 't') {
+ if (!wl_ether_atoe(to.valstr, &ackmac_params.addr)) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as a MAC address\n",
+ cmd->name, to.valstr);
+ err = -1;
+ goto exit;
+ }
+ mac_set = TRUE;
+ }
+ }
+
+ if (index_set) {
+ if (!mac_set) {
+ printf("\n Invalid without mac address");
+ ret = BCME_USAGE_ERROR;
+ } else if (tablelist.index == 8) {
+ /* Index 8 is for changing the destination address of the AF */
+ /* This multi-cast address is the da of the action frame that */
+ /* is sent out periodically */
+ memcpy(&tablelist.entry[0].addr, &ackmac_params.addr,
+ sizeof(struct ether_addr));
+
+ /* insert to list */
+ ea = &tablelist.entry[0].addr;
+ tablelist.entry[0].flag = RELMCAST_ENTRY_OP_ENABLE;
+
+ /* for ipv4, initial three bytes in mc address are standard &
+ 2 bytes for ipv6
+ */
+ if ((!memcmp(ea, mc_mac, 3) && !(ea->octet[3] & 0x80)) ||
+ !memcmp(ea, mc_mac_ipv6, 2)) {
+
+ fprintf(stderr,
+ "\nAdding multi-cast mac %s\n", wl_ether_etoa(ea));
+
+ return wlu_var_setbuf(wl, cmd->name,
+ &tablelist,
+ sizeof(wl_rmc_entry_table_t));
+
+ } else {
+
+ fprintf(stderr, "multicast mac started with"
+ "01:00:5e:0... or 33:33:...\n");
+ ret = BCME_BADARG;
+
+ }
+ } else {
+ printf("\n Invalid index ");
+ ret = BCME_USAGE_ERROR;
+ }
+ }
+exit:
+ return ret;
+}
+
+static int
+wl_mcast_ackreq(void *wl, cmd_t *cmd, char **argv)
+{
+ const char* fn_name = "wl_mcast_ackreq";
+ int err, i = 0;
+ uint argc;
+ char *endptr = NULL;
+ void *ptr = NULL;
+ uint8 *reply_mode = NULL;
+ uint8 params_mode, old_mode;
+ wl_relmcast_status_t status;
+
+ memset(¶ms_mode, 0, sizeof(uint8));
+ /* toss the command name */
+ argv++;
+
+ if ((err = wlu_var_getbuf_sm(wl, cmd->name, ¶ms_mode,
+ sizeof(uint8), &ptr)) != BCME_OK) {
+ fprintf(stderr, "Error getting variable %s\n", argv[0]);
+ return err;
+ }
+
+ reply_mode = (uint8 *)ptr;
+ old_mode = *reply_mode;
+
+ if (!*argv) {
+ fprintf(stderr, "%s mode %d \n", fn_name, *reply_mode);
+ return err;
+ }
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ /* required arg: mode disable, enable or initiator enabled */
+ if (argc < 1)
+ return -1;
+
+ /* get the new ackreq mode */
+ params_mode = strtol(argv[0], &endptr, 0);
+
+ if ((*endptr != '\0') || (params_mode > WL_RMC_MODE_INITIATOR))
+ return -1;
+
+ if (argc > 1) {
+ fprintf(stderr,
+ "%s: could not parse extra argument %s:\n",
+ fn_name, argv[1]);
+
+ err = -1;
+ goto exit;
+ }
+
+ if ((err = wlu_var_setbuf(wl, cmd->name, ¶ms_mode, sizeof(uint8))) != BCME_OK) {
+ goto out_of_here;
+ }
+
+ if (params_mode == WL_RMC_MODE_INITIATOR ||
+ ((params_mode == WL_RMC_MODE_RECEIVER) &&
+ (old_mode == WL_RMC_MODE_INITIATOR))) {
+
+ for (i = 0; i <= 10; i++) {
+ /* check status of the RCV bit to make sure ack are receive */
+ if ((err = wlu_iovar_get(wl, "rmc_status",
+ (void *) &status,
+ (sizeof(wl_relmcast_status_t)))) < 0) {
+ return (err);
+ }
+
+ if (status.err != (uint16)BCME_NOTREADY) {
+ if (status.err == (uint16)BCME_RXFAIL) {
+ fprintf(stderr, "%s: error in setting mode: no ack receive"
+ "%d tx code %d \n",
+ fn_name, params_mode, status.err);
+
+ err = -1;
+ } else {
+ err = 0;
+ }
+ goto out_of_here;
+ }
+
+ /* Allow ample time (by staying in loop) to get ACK
+ for previous TX frame
+ */
+ {
+ volatile uint16 busycnt = -1;
+ /* There is no system call for sleep that will work for */
+ /* all os flavors. When there is a common sleep call we */
+ /* can replace the following busy wait loop */
+ while (--busycnt)
+ ;
+ busycnt = -1;
+ }
+ } /* for loop */
+ }
+out_of_here:
+ if ((err < 0) || (i > 10))
+ fprintf(stderr, "%s: Error setting %d err %d \n", fn_name, params_mode, err);
+ else
+ fprintf(stderr, "%s: setting %d err %d \n", fn_name, params_mode, err);
+exit:
+ return 0;
+}
+
+
+static int
+wl_mcast_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, i;
+ wl_relmcast_status_t status;
+
+ if (!*++argv) {
+ /* Get */
+ if ((err = wlu_iovar_get(wl, cmd->name, (void *) &status,
+ (sizeof(wl_relmcast_status_t)))) < 0)
+ return (err);
+
+ if (status.ver != WL_RMC_VER) {
+ printf("Wrong Version %d %d\n", WL_RMC_VER, status.ver);
+ } else if (status.num == 0) {
+ printf("No clients associated\n");
+ } else {
+ for (i = 0; i < status.num; i++) {
+ printf("%s\t%d\t%c%c%c\n",
+ wl_ether_etoa(&status.clients[i].addr),
+ status.clients[i].rssi,
+ ((status.clients[i].flag &
+ WL_RMC_FLAG_ACTIVEACKER) ? 'A' : ' '),
+ ((status.clients[i].flag &
+ WL_RMC_FLAG_INBLACKLIST) ? 'B' : ' '),
+ ((status.clients[i].flag &
+ WL_RMC_FLAG_RELMCAST) ? 'R' : ' '));
+ }
+ printf("Notification Frame TimePeriod: %d ms\n", status.actf_time);
+ }
+ } else {
+ printf("Cannot set reliable multicast status\n");
+ }
+
+ return 0;
+}
+
+static int
+wl_mcast_actf_time(void *wl, cmd_t *cmd, char **argv)
+{
+ int val, error = -1;
+ const char *name = cmd->name;
+
+ /* toss the command name from the args */
+ argv++;
+
+ if (!*argv) {
+ error = wlu_iovar_getint(wl, name, &val);
+ if (error < 0)
+ return (error);
+ printf("Action Frame tx time period: %dms\n", val);
+
+ } else {
+
+ val = (uint16)strtol(*argv, NULL, 10); /* 10 is for base 10 (decimal) */
+
+ if (val >= WL_RMC_ACTF_TIME_MIN &&
+ val <= WL_RMC_ACTF_TIME_MAX) {
+
+ error = wlu_iovar_setint(wl, name, val);
+
+ } else {
+
+ printf("\"Out of range\": valid range %dms - %dms\n",
+ WL_RMC_ACTF_TIME_MIN,
+ WL_RMC_ACTF_TIME_MAX);
+ }
+ }
+ return error;
+}
+
+static int
+wl_mcast_ar_timeout(void *wl, cmd_t *cmd, char **argv)
+{
+ int val, error = -1;
+ const char *name = cmd->name;
+
+ /* toss the command name from the args */
+ argv++;
+
+ if (!*argv) {
+ error = wlu_iovar_getint(wl, name, &val);
+ if (error < 0)
+ return (error);
+ printf("Active Receiver time out: %dms\n", val);
+
+ } else {
+ val = (uint16)strtol(*argv, NULL, 10);
+ if (val >= WL_RMC_ARTMO_MIN &&
+ val <= WL_RMC_ARTMO_MAX)
+ error = wlu_iovar_setint(wl, name, val);
+ else
+ printf("\"Out of range\": valid range %dms - %dms\n",
+ WL_RMC_ARTMO_MIN,
+ WL_RMC_ARTMO_MAX);
+ }
+ return error;
+}
+
+static int
+wl_mcast_rssi_thresh(void *wl, cmd_t *cmd, char **argv)
+{
+ int val, error = -1;
+ const char *name = cmd->name;
+
+ /* toss the command name from the args */
+ argv++;
+
+ if (!*argv) {
+ error = wlu_iovar_getint(wl, name, &val);
+ if (error < 0)
+ return (error);
+ printf("rmc rssi: %d\n", val);
+
+ } else {
+ val = (int8)strtol(*argv, NULL, 10);
+ error = wlu_iovar_setint(wl, name, val);
+ }
+
+ return error;
+}
+
+static int
+wl_mcast_stats(void *wl, cmd_t *cmd, char **argv)
+{
+#define PRCNT(name) pbuf += sprintf(pbuf, "%s %u ", #name, dtoh16(cnts_v.name))
+#define PRCNT32(name) pbuf += sprintf(pbuf, "%s %u ", #name, dtoh32(cnts_v.name))
+ wl_rmc_cnts_t *cnts = NULL;
+ wl_rmc_cnts_t cnts_v;
+ int err = BCME_OK;
+ uint8 argval, argc;
+ char *pbuf = buf;
+ char *endptr = NULL;
+ void *ptr = NULL;
+
+ if (!*++argv) {
+ /* no arg - get and display all values */
+
+ if ((err = wlu_var_getbuf (wl, cmd->name, &cnts_v, sizeof(wl_rmc_cnts_t), &ptr)))
+ return (err);
+
+ cnts = (wl_rmc_cnts_t*)ptr;
+
+ memcpy((wl_rmc_cnts_t*)&cnts_v, cnts, sizeof(wl_rmc_cnts_t));
+ cnts_v.version = dtoh16(cnts->version);
+ cnts_v.length = dtoh16(cnts->length);
+
+ if (cnts_v.version != WL_RMC_CNT_VERSION) {
+ printf("\tIncorrect version of counters struct: expected %d; got %d\n",
+ WL_RMC_CNT_VERSION, cnts->version);
+
+ return -1;
+ }
+
+ PRCNT(dupcnt); PRCNT(ackreq_err); PRCNT(af_tx_err); PRNL();
+ PRCNT(null_tx_err); PRCNT(af_unicast_tx_err); PRCNT(mc_no_amt_slot); PRNL();
+ PRCNT(mc_not_mirrored); PRCNT(mc_existing_tr); PRCNT(mc_exist_in_amt); PRNL();
+ PRCNT(mc_utilized); PRCNT(mc_taken_other_tr); PRCNT32(rmc_rx_frames_mac); PRNL();
+ PRCNT32(rmc_tx_frames_mac); PRCNT32(mc_ar_role_selected);
+ PRCNT32(mc_ar_role_deleted); PRNL();
+ PRCNT32(mc_noacktimer_expired); PRCNT32(mc_null_ar_cnt);
+ PRCNT(mc_no_wl_clk); PRNL();
+ PRCNT(mc_tr_cnt_exceeded); PRNL();
+ fputs(buf, stdout);
+
+ } else {
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+ argval = strtol(argv[0], &endptr, 0);
+ if (argval == 255) {
+ /* arg is -1, clear all the values */
+ fprintf(stderr, "clearing rmc counters\n");
+ err = wlu_var_setbuf(wl, cmd->name, &cnts_v, sizeof(wl_rmc_cnts_t));
+
+ } else {
+ fprintf(stderr, "Invalid arg, only -1"
+ "is allowed to clear counters\n");
+ err = BCME_BADARG;
+ }
+ }
+ return err;
+}
+
+static int
+wl_mcast_rssi_delta(void *wl, cmd_t *cmd, char **argv)
+{
+ int val, error = -1;
+ const char *name = cmd->name;
+
+ /* toss the command name from the args */
+ argv++;
+
+ if (!*argv) {
+ error = wlu_iovar_getint(wl, name, &val);
+ if (error < 0)
+ return (error);
+ printf("rmc rssi delta: %d\n", val);
+
+ } else {
+ val = (uint16)strtol(*argv, NULL, 10);
+ if (val >= 0) /* rssi delta value should be a whole number */
+ error = wlu_iovar_setint(wl, name, val);
+ else
+ printf("\"Out of range\": rmc rssi delta should be >=0\n");
+ }
+ return error;
+}
+
+static int
+wl_mcast_vsie(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = 0;
+ void *ptr = NULL;
+ wl_rmc_vsie_t *reply = NULL;
+ wl_rmc_vsie_t vsie;
+ char *parse = NULL;
+ char tmp[4];
+ int idx, cnt;
+
+ if (!*++argv) {
+
+ /* Get and display all entries in the table */
+ if ((ret = wlu_var_getbuf(wl, cmd->name,
+ NULL,
+ 0,
+ &ptr)) < 0) {
+ return ret;
+ }
+
+ reply = (wl_rmc_vsie_t*)ptr;
+
+ printf("0x%x%x%x 0x%x", reply->oui[0], reply->oui[1],
+ reply->oui[2], reply->payload);
+
+ } else {
+
+ parse = *argv++;
+
+ /* remove "0x" from the input string which is in hex */
+ if (strlen(parse)/2 > DOT11_OUI_LEN) {
+ if (!strncmp("0x", parse, strlen("0x")) ||
+ !strncmp("0X", parse, strlen("0X"))) {
+ parse += strlen("0x");
+ }
+ }
+
+ /* if OUI string is not 6 characters, simply reject */
+ if (strlen(parse) != DOT11_OUI_LEN * 2)
+ return BCME_ERROR;
+
+ /* parse oui string */
+ for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
+ for (cnt = 0; cnt < 2; cnt++) {
+ tmp[cnt] = *parse++;
+ }
+ tmp[cnt] = '\0';
+ vsie.oui[idx] = (uint8)(strtoul(tmp, NULL, 16));
+ }
+
+ /* second argument is missing!! */
+ if (!*argv) {
+ return BCME_ERROR;
+ }
+
+ vsie.payload = (uint16)(strtoul(*argv, NULL, 16));
+ ret = wlu_var_setbuf(wl, cmd->name, &vsie, sizeof(vsie));
+ }
+
+ return ret;
+}
diff --git a/wl/src/wl/exe/wluc_rrm.c b/wl/src/wl/exe/wluc_rrm.c
new file mode 100644
index 0000000..80b07b0
--- /dev/null
+++ b/wl/src/wl/exe/wluc_rrm.c
@@ -0,0 +1,913 @@
+/*
+ * wl rrm command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_rrm.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_rrm;
+static cmd_func_t wl_rrm_nbr_req;
+static cmd_func_t wl_rrm_bcn_req;
+static cmd_func_t wl_rrm_chload_req;
+static cmd_func_t wl_rrm_noise_req;
+static cmd_func_t wl_rrm_frame_req;
+static cmd_func_t wl_rrm_stat_req;
+static cmd_func_t wl_rrm_stat_rpt;
+static cmd_func_t wl_rrm_lm_req;
+static cmd_func_t wl_rrm_nbr_list;
+static cmd_func_t wl_rrm_nbr_del_nbr;
+static cmd_func_t wl_rrm_nbr_add_nbr;
+
+static cmd_func_t wl_rrm_config;
+
+static cmd_t wl_rrm_cmds[] = {
+ { "rrm", wl_rrm, WLC_GET_VAR, WLC_SET_VAR,
+ "enable or disable RRM feature\n"
+ "\tUsage: wl rrm [0/1] to disable/enable RRM feature"},
+ { "rrm_bcn_req", wl_rrm_bcn_req, -1, WLC_SET_VAR,
+ "send 11k beacon measurement request\n"
+ "\tUsage: wl rrm_bcn_req [bcn mode] [da] [duration] [random int] [channel] [ssid]"
+ " [repetitions]"},
+ { "rrm_chload_req", wl_rrm_chload_req, -1, WLC_SET_VAR,
+ "send 11k channel load measurement request\n"
+ "\tUsage: wl rrm_chload_req [regulatory] [da] [duration] [random int] [channel]"
+ " [repetitions]"},
+ { "rrm_noise_req", wl_rrm_noise_req, -1, WLC_SET_VAR,
+ "send 11k noise measurement request\n"
+ "\tUsage: wl rrm_noise_req [regulatory] [da] [duration] [random int] [channel]"
+ " [repetitions] "},
+ { "rrm_frame_req", wl_rrm_frame_req, -1, WLC_SET_VAR,
+ "send 11k frame measurement request\n"
+ "\tUsage: wl rrm_frame_req [regulatory] [da] [duration] [random int] [channel] [ta]"
+ " [repetitions]"},
+ { "rrm_stat_req", wl_rrm_stat_req, -1, WLC_SET_VAR,
+ "send 11k stat measurement request\n"
+ "\tUsage: wl rrm_stat_req [da] [random int] [duration] [peer] [group id] [repetitions]"},
+ { "rrm_stat_rpt", wl_rrm_stat_rpt, -1, WLC_GET_VAR,
+ "Read 11k stat measurement report from STA\n"
+ "\tUsage: wl rrm_stat_rpt [mac]"},
+ { "rrm_lm_req", wl_rrm_lm_req, -1, WLC_SET_VAR,
+ "send 11k link measurement request\n"
+ "\tUsage: wl rrm_lm_req [da]"},
+ { "rrm_nbr_req", wl_rrm_nbr_req, -1, WLC_SET_VAR,
+ "send 11k neighbor report measurement request\n"
+ "\tUsage: wl rrm_nbr_req [ssid]"},
+ { "rrm_nbr_list", wl_rrm_nbr_list, WLC_GET_VAR, -1,
+ "get 11k neighbor report list\n"
+ "\tUsage: wl rrm_nbr_list"},
+ { "rrm_nbr_del_nbr", wl_rrm_nbr_del_nbr, -1, WLC_SET_VAR,
+ "delete node from 11k neighbor report list\n"
+ "\tUsage: wl rrm_nbr_del_nbr [bssid]"},
+ { "rrm_nbr_add_nbr", wl_rrm_nbr_add_nbr, -1, WLC_SET_VAR,
+ "add node to 11k neighbor report list\n"
+ "\tUsage: wl rrm_nbr_add_nbr [bssid] [bssid info] [regulatory] [channel] [phytype]"},
+ { "rrm_config", wl_rrm_config, -1, WLC_SET_VAR,
+ "Configure information (LCI/Civic location) for self\n"
+ "\tUsage: wl rrm_config lci [lci_location]\n"
+ "\tUsage: wl rrm_config civic [civic_location]"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_rrm_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register rrm commands */
+ wl_module_cmds_register(wl_rrm_cmds);
+}
+
+/* RM Enable Capabilities */
+static dbg_msg_t rrm_msgs[] = {
+ {DOT11_RRM_CAP_LINK, "Link_Measurement"}, /* bit0 */
+ {DOT11_RRM_CAP_NEIGHBOR_REPORT, "Neighbor_Report"}, /* bit1 */
+ {DOT11_RRM_CAP_PARALLEL, "Parallel_Measurement"}, /* bit2 */
+ {DOT11_RRM_CAP_REPEATED, "Repeated_Measurement"}, /* bit3 */
+ {DOT11_RRM_CAP_BCN_PASSIVE, "Beacon_Passive"}, /* bit4 */
+ {DOT11_RRM_CAP_BCN_ACTIVE, "Beacon_Active"}, /* bit5 */
+ {DOT11_RRM_CAP_BCN_TABLE, "Beacon_Table"}, /* bit6 */
+ {DOT11_RRM_CAP_BCN_REP_COND, "Beacon_measurement_Reporting_Condition"}, /* bit7 */
+ {DOT11_RRM_CAP_FM, "Frame_Measurement"}, /* bit8 */
+ {DOT11_RRM_CAP_CLM, "Channel_load_Measurement"}, /* bit9 */
+ {DOT11_RRM_CAP_NHM, "Noise_Histogram_measurement"}, /* bit10 */
+ {DOT11_RRM_CAP_SM, "Statistics_Measurement"}, /* bit11 */
+ {DOT11_RRM_CAP_LCIM, "LCI_Measurement"}, /* bit12 */
+ {DOT11_RRM_CAP_LCIA, "LCI_Azimuth"}, /* bit13 */
+ {DOT11_RRM_CAP_TSCM, "Tx_Stream_Category_Measurement"}, /* bit14 */
+ {DOT11_RRM_CAP_TTSCM, "Triggered_Tx_stream_Category_Measurement"}, /* bit15 */
+ {DOT11_RRM_CAP_AP_CHANREP, "AP_Channel_Report"}, /* bit16 */
+ {DOT11_RRM_CAP_RMMIB, "RM_MIB"}, /* bit17 */
+ /* bit 18-26, unused */
+ {DOT11_RRM_CAP_MPTI, "Measurement_Pilot_Transmission_Information"}, /* bit27 */
+ {DOT11_RRM_CAP_NBRTSFO, "Neighbor_Report_TSF_Offset"}, /* bit28 */
+ {DOT11_RRM_CAP_RCPI, "RCPI_Measurement"}, /* bit29 */
+ {DOT11_RRM_CAP_RSNI, "RSNI_Measurement"}, /* bit30 */
+ {DOT11_RRM_CAP_BSSAAD, "BSS_Average_Access_Delay"}, /* bit31 */
+ {DOT11_RRM_CAP_BSSAAC, "BSS_Available_Admission_Capacity"}, /* bit32 */
+ {DOT11_RRM_CAP_AI, "Antenna_Information"}, /* bit33 */
+ {DOT11_RRM_CAP_FTM_RANGE, "FTM_Range_Reporting"}, /* bit34 */
+ {DOT11_RRM_CAP_CIVIC_LOC, "Civic_Location_Measurement"}, /* bit35 */
+ {0, NULL}
+};
+
+static bool rrm_input_validation(uint val, uint hval, dbg_msg_t *dbg_msg)
+{
+ int i;
+ uint32 flag = 0;
+
+ if ((val == 0) && (hval == 0))
+ return TRUE;
+
+ for (i = 0; dbg_msg[i].value <= DOT11_RRM_CAP_BSSAAD; i++)
+ flag |= 1 << dbg_msg[i].value;
+ flag = ~flag;
+ if (val & flag)
+ return FALSE;
+
+ flag = 0;
+ if (hval != 0) {
+ for (; dbg_msg[i].value; i++) {
+ flag |= 1 << (dbg_msg[i].value - DOT11_RRM_CAP_BSSAAC);
+ }
+ flag = ~flag;
+ if (hval & flag)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int
+wl_rrm(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, i;
+ uint hval = 0, val = 0, len, found, rmcap_del = 0, rmcap2_del = 0;
+ uint rmcap_add = 0, rmcap2_add = 0;
+ char *endptr = NULL;
+ dbg_msg_t *dbg_msg = rrm_msgs;
+ void *ptr = NULL;
+ dot11_rrm_cap_ie_t rrm_cap, *reply;
+ uint high = 0, low = 0, bit = 0, hbit = 0;
+ const char *cmdname = "rrm";
+ char *s = NULL;
+ char t[32], c[32] = "0x";
+
+ UNUSED_PARAMETER(cmd);
+
+ err = wlu_var_getbuf_sm(wl, cmdname, &rrm_cap, sizeof(rrm_cap), &ptr);
+ if (err < 0)
+ return err;
+ reply = (dot11_rrm_cap_ie_t *)ptr;
+
+ high = reply->cap[4];
+ low = reply->cap[0] | (reply->cap[1] << 8) | (reply->cap[2] << 16) | (reply->cap[3] << 24);
+ if (!*++argv) {
+ if (high != 0)
+ printf("0x%x%08x", high, low);
+ else
+ printf("0x%x ", low);
+ for (i = 0; ((bit = dbg_msg[i].value) <= DOT11_RRM_CAP_BSSAAD); i++) {
+ if (low & (1 << bit))
+ printf(" %s", dbg_msg[i].string);
+ }
+ for (; (hbit = dbg_msg[i].value); i++) {
+ if (high & (1 << (hbit - DOT11_RRM_CAP_BSSAAC)))
+ printf(" %s", dbg_msg[i].string);
+ }
+ printf("\n");
+
+ return err;
+ }
+ while (*argv) {
+ s = *argv;
+
+ found = 0;
+ if (*s == '+' || *s == '-')
+ s++;
+ else {
+ /* used for clearing previous value */
+ rmcap_del = ~0;
+ rmcap2_del = ~0;
+ }
+ val = strtoul(s, &endptr, 0);
+ /* Input is decimal number or hex with prefix 0x and > 32 bits */
+ if (val == 0xFFFFFFFF) {
+ if (!(*s == '0' && *(s+1) == 'x')) {
+ fprintf(stderr,
+ "Msg bits >32 take only numerical input in hex\n");
+ val = 0;
+ } else {
+ /* Input number with prefix 0x */
+ len = strlen(s);
+ hval = strtoul(strncpy(t, s, len-8), &endptr, 0);
+ *endptr = 0;
+ s = s + strlen(t);
+ s = strcat(c, s);
+ val = strtoul(s, &endptr, 0);
+ /* Input number > 64bit */
+ if (hval == 0xFFFFFFFF) {
+ fprintf(stderr, "Invalid entry for RM Capabilities\n");
+ hval = 0;
+ val = 0;
+ }
+ }
+ }
+ /* validet the input number */
+ if (!rrm_input_validation(val, hval, dbg_msg))
+ goto usage;
+ /* Input is a string */
+ if (*endptr != '\0') {
+ for (i = 0; ((bit = dbg_msg[i].value) <= DOT11_RRM_CAP_BSSAAD); i++) {
+ if (stricmp(dbg_msg[i].string, s) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ for (; (hbit = dbg_msg[i].value); i++) {
+ if (stricmp(dbg_msg[i].string, s) == 0)
+ break;
+ }
+ if (hbit)
+ hval = 1 << (hbit - DOT11_RRM_CAP_BSSAAC);
+ else
+ hval = 0;
+ } else {
+ val = 1 << bit;
+ }
+ if (!val && !hval)
+ goto usage;
+ }
+ if (**argv == '-') {
+ rmcap_del |= val;
+ if (!found)
+ rmcap2_del |= hval;
+ }
+ else {
+ rmcap_add |= val;
+ if (!found)
+ rmcap2_add |= hval;
+ }
+ ++argv;
+ }
+
+ low &= ~rmcap_del;
+ high &= ~rmcap2_del;
+ low |= rmcap_add;
+ high |= rmcap2_add;
+
+ rrm_cap.cap[4] = high;
+ rrm_cap.cap[0] = low & 0x000000ff;
+ rrm_cap.cap[1] = (low & 0x0000ff00) >> 8;
+ rrm_cap.cap[2] = (low & 0x00ff0000) >> 16;
+ rrm_cap.cap[3] = (low & 0xff000000) >> 24;
+
+ err = wlu_var_setbuf(wl, cmdname, &rrm_cap, sizeof(dot11_rrm_cap_ie_t));
+ return err;
+
+usage:
+ fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");
+ fprintf(stderr, "Use a + or - prefix to make an incremental change.");
+ for (i = 0; (bit = dbg_msg[i].value) <= DOT11_RRM_CAP_BSSAAD; i++) {
+ fprintf(stderr, "\n0x%04x %s", (1 << bit), dbg_msg[i].string);
+ }
+ for (; (hbit = dbg_msg[i].value); i++) {
+ hbit -= DOT11_RRM_CAP_BSSAAC;
+ fprintf(stderr, "\n0x%x00000000 %s", (1 << hbit), dbg_msg[i].string);
+ }
+ fprintf(stderr, "\n");
+ return BCME_OK;
+}
+
+static int
+wl_rrm_stat_req(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ const char *cmdname = "rrm_stat_req";
+ statreq_t sreq_buf;
+
+ UNUSED_PARAMETER(cmd);
+ memset(&sreq_buf, 0, sizeof(statreq_t));
+
+ if (argv[1]) {
+ /* da */
+ if (!wl_ether_atoe(argv[1], &sreq_buf.da)) {
+ printf("wl_rrm_stat_req parsing da failed\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ /* random interval */
+ if (argv[2]) {
+ sreq_buf.random_int = htod32(strtoul(argv[2], NULL, 0));
+ }
+ /* duration */
+ if (argv[3]) {
+ sreq_buf.dur = htod32(strtoul(argv[3], NULL, 0));
+ }
+ /* peer address */
+ if (argv[4]) {
+ if (!wl_ether_atoe(argv[4], &sreq_buf.peer)) {
+ printf("wl_rrm_stat_req parsing peer failed\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ /* group id */
+ if (argv[5]) {
+ sreq_buf.group_id =
+ htod32(strtoul(argv[5], NULL, 0));
+ }
+ /* repetitions */
+ if (argv[6]) {
+ sreq_buf.reps = htod32(strtoul(argv[6], NULL, 0));
+ }
+ err = wlu_iovar_set(wl, cmdname, &sreq_buf, sizeof(sreq_buf));
+ return err;
+}
+
+static int
+wl_rrm_stat_rpt(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret = BCME_USAGE_ERROR;
+ statrpt_t *rpt_ptr, rpt;
+ int cnt;
+
+ if (!*++argv) return -1;
+
+ /* get sta mac address */
+ if (!wl_ether_atoe(*argv++, &rpt.addr))
+ goto done;
+
+ rpt.ver = htod16(WL_RRM_RPT_VER);
+ memset(buf, 0, WLC_IOCTL_MEDLEN);
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, (void *) &rpt,
+ sizeof(rpt), buf, WLC_IOCTL_MEDLEN)) < 0) {
+ fprintf(stderr, "ERROR: cmd:%s\n", cmd->name);
+ goto done;
+ }
+
+ /* display the sta info */
+ rpt_ptr = (statrpt_t *)buf;
+ rpt_ptr->ver = dtoh16(rpt_ptr->ver);
+
+ /* Report unrecognized version */
+ if (rpt_ptr->ver != WL_RRM_RPT_VER) {
+ fprintf(stderr, "ERROR: Mismatch ver[%d] Driver ver[%d]\n",
+ WL_RRM_RPT_VER, rpt_ptr->ver);
+ goto done;
+ }
+
+ printf("ver:%d timestamp:%u flag:%d len:%d\n",
+ rpt_ptr->ver, dtoh32(rpt_ptr->timestamp),
+ dtoh16(rpt_ptr->flag), rpt_ptr->len);
+ for (cnt = 0; cnt < rpt_ptr->len; cnt++) {
+ if (cnt % 8 == 0)
+ printf("\n[%d]:", cnt);
+ printf("[0x%02x][%d] ", rpt_ptr->data[cnt], (signed char)(rpt_ptr->data[cnt]));
+ }
+ printf("\n");
+
+done:
+ return ret;
+}
+
+static int
+wl_rrm_frame_req(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ const char *cmdname = "rrm_frame_req";
+ framereq_t freq_buf;
+
+ UNUSED_PARAMETER(cmd);
+
+ memset(&freq_buf, 0, sizeof(framereq_t));
+ if (argv[1]) {
+ /* Regulatory class */
+ freq_buf.reg = htod32(strtoul(argv[1], NULL, 0));
+ }
+
+ /* da */
+ if (argv[2]) {
+ if (!wl_ether_atoe(argv[2], &freq_buf.da)) {
+ printf("wl_rrm_frame_req parsing da failed\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ /* duration */
+ if (argv[3]) {
+ freq_buf.dur = htod32(strtoul(argv[3], NULL, 0));
+ }
+ /* random interval */
+ if (argv[4]) {
+ freq_buf.random_int = htod32(strtoul(argv[4], NULL, 0));
+ }
+ /* channel */
+ if (argv[5]) {
+ freq_buf.chan = htod32(strtoul(argv[5], NULL, 0));
+ }
+ /* transmit address */
+ if (argv[6]) {
+ if (!wl_ether_atoe(argv[6], &freq_buf.ta)) {
+ printf("wl_rrm_frame_req parsing ta failed\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ /* repetitions */
+ if (argv[7]) {
+ freq_buf.reps = htod32(strtoul(argv[7], NULL, 0));
+ }
+ err = wlu_iovar_set(wl, cmdname, &freq_buf, sizeof(freq_buf));
+ return err;
+}
+
+static int
+wl_rrm_chload_req(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ const char *cmdname = "rrm_chload_req";
+ rrmreq_t chreq_buf;
+
+ UNUSED_PARAMETER(cmd);
+ memset(&chreq_buf, 0, sizeof(rrmreq_t));
+
+ if (argv[1]) {
+ /* Regulatory class */
+ chreq_buf.reg = htod32(strtoul(argv[1], NULL, 0));
+ }
+ /* da */
+ if (argv[2]) {
+ if (!wl_ether_atoe(argv[2], &chreq_buf.da)) {
+ printf("wl_rrm_chload_req parsing da failed\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ /* duration */
+ if (argv[3]) {
+ chreq_buf.dur = htod32(strtoul(argv[3], NULL, 0));
+ }
+ /* random interval */
+ if (argv[4]) {
+ chreq_buf.random_int = htod32(strtoul(argv[4], NULL, 0));
+ }
+ /* channel */
+ if (argv[5]) {
+ chreq_buf.chan = htod32(strtoul(argv[5], NULL, 0));
+ }
+ /* repetitions */
+ if (argv[6]) {
+ chreq_buf.reps = htod32(strtoul(argv[6], NULL, 0));
+ }
+ err = wlu_iovar_set(wl, cmdname, &chreq_buf, sizeof(chreq_buf));
+ return err;
+}
+
+static int
+wl_rrm_noise_req(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ const char *cmdname = "rrm_noise_req";
+ rrmreq_t nreq_buf;
+
+ UNUSED_PARAMETER(cmd);
+ printf("wl_rrm_noise_req\n");
+
+ memset(&nreq_buf, 0, sizeof(rrmreq_t));
+ if (argv[1]) {
+ /* Regulatory class */
+ nreq_buf.reg = htod32(strtoul(argv[1], NULL, 0));
+ }
+ /* da */
+ if (argv[2]) {
+ if (!wl_ether_atoe(argv[2], &nreq_buf.da)) {
+ printf("wl_rrm_noise_req parsing da failed\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ /* duration */
+ if (argv[3]) {
+ nreq_buf.dur = htod32(strtoul(argv[3], NULL, 0));
+
+ }
+ /* random interval */
+ if (argv[4]) {
+ nreq_buf.random_int = htod32(strtoul(argv[4], NULL, 0));
+ }
+ /* channel */
+ if (argv[5]) {
+ nreq_buf.chan = htod32(strtoul(argv[5], NULL, 0));
+ }
+ /* repetitions */
+ if (argv[6]) {
+ nreq_buf.reps = htod32(strtoul(argv[6], NULL, 0));
+ }
+ err = wlu_iovar_set(wl, cmdname, &nreq_buf, sizeof(nreq_buf));
+ return err;
+}
+
+static int
+wl_rrm_bcn_req(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ uint8 mode = 0;
+ const char *cmdname = "rrm_bcn_req";
+ bcnreq_t bcnreq_buf;
+ wlc_ssid_t ssid;
+
+ UNUSED_PARAMETER(cmd);
+ memset(&bcnreq_buf, 0, sizeof(bcnreq_t));
+
+ if (argv[1]) {
+ /* bcn mode: ACTIVE/PASSIVE/SCAN_CACHE */
+ mode = htod32(strtoul(argv[1], NULL, 0));
+ if (mode > 2) {
+ printf("wl_rrm_bcn_req parsing bcn mode failed\n");
+ return BCME_BADARG;
+ }
+ bcnreq_buf.bcn_mode = mode;
+ }
+ /* da */
+ if (argv[2]) {
+ if (!wl_ether_atoe(argv[2], &bcnreq_buf.da)) {
+ printf("wl_rrm_bcn_req parsing da failed\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ /* duration */
+ if (argv[3]) {
+ bcnreq_buf.dur = htod32(strtoul(argv[3], NULL, 0));
+ }
+
+ /* random interval */
+ if (argv[4]) {
+ bcnreq_buf.random_int = htod32(strtoul(argv[4], NULL, 0));
+ }
+
+ /* channel */
+ if (argv[5]) {
+ bcnreq_buf.channel = htod32(strtoul(argv[5], NULL, 0));
+ }
+ printf("wl_rrm_bcn_req:bcn mode: %d, duration: %d, "
+ "chan: %d\n", mode,
+ bcnreq_buf.dur, bcnreq_buf.channel);
+
+ /* SSID */
+ if (argv[6]) {
+ uint32 len;
+
+ len = strlen(argv[6]);
+ if (len > DOT11_MAX_SSID_LEN) {
+ printf("ssid too long\n");
+ return BCME_BADARG;
+ }
+ memset(&ssid, 0, sizeof(wlc_ssid_t));
+ memcpy(ssid.SSID, argv[6], len);
+ ssid.SSID_len = len;
+ memcpy(&bcnreq_buf.ssid, &ssid, sizeof(wlc_ssid_t));
+ }
+
+ /* repetitions */
+ if (argv[7]) {
+ bcnreq_buf.reps = htod32(strtoul(argv[7], NULL, 0));
+ }
+
+ err = wlu_iovar_set(wl, cmdname, &bcnreq_buf, sizeof(bcnreq_buf));
+ return err;
+}
+
+static int
+wl_rrm_lm_req(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ const char *cmdname = "rrm_lm_req";
+
+ struct ether_addr da;
+ UNUSED_PARAMETER(cmd);
+
+ if (argv[1]) {
+ if (!wl_ether_atoe(argv[1], &da)) {
+ printf("wl_rrm_lm_req parsing arg1 failed\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ err = wlu_iovar_set(wl, cmdname, &da, sizeof(da));
+ return err;
+}
+
+static int
+wl_rrm_nbr_req(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen;
+ wlc_ssid_t ssid;
+
+ UNUSED_PARAMETER(cmd);
+
+ strcpy(buf, "rrm_nbr_req");
+ buflen = strlen("rrm_nbr_req") + 1;
+
+ if (*++argv) {
+ uint32 len;
+
+ len = strlen(*argv);
+ if (len > DOT11_MAX_SSID_LEN) {
+ printf("ssid too long\n");
+ return BCME_BADARG;
+ }
+ memset(&ssid, 0, sizeof(wlc_ssid_t));
+ memcpy(ssid.SSID, *argv, len);
+ ssid.SSID_len = len;
+ memcpy(&buf[buflen], &ssid, sizeof(wlc_ssid_t));
+ buflen += sizeof(wlc_ssid_t);
+ }
+
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+}
+
+/* For mapping customer's user space command, two calls of the same iovar. */
+static int
+wl_rrm_nbr_list(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0, buflen, i;
+ uint16 list_cnt;
+ nbr_element_t *nbr_elt;
+ uint8 *ptr;
+
+ UNUSED_PARAMETER(cmd);
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(buf, "rrm_nbr_list");
+ buflen = strlen("rrm_nbr_list") + 1;
+
+ if (*++argv != NULL)
+ return BCME_USAGE_ERROR;
+
+ if ((err = wlu_get(wl, WLC_GET_VAR, buf, buflen)) < 0)
+ return err;
+
+ list_cnt = *(uint16 *)buf;
+
+ if (list_cnt == 0)
+ return err;
+
+ memset(buf, 0, WLC_IOCTL_MAXLEN);
+ strcpy(buf, "rrm_nbr_list");
+ buflen = strlen("rrm_nbr_list") + 1;
+
+ memcpy(&buf[buflen], &list_cnt, sizeof(uint16));
+
+ printf("RRM Neighbor Report List:\n");
+
+ if ((err = wlu_get(wl, WLC_GET_VAR, buf, WLC_IOCTL_MAXLEN)) < 0)
+ return err;
+
+ ptr = (uint8 *)buf;
+
+ for (i = 0; i < list_cnt; i++) {
+ nbr_elt = (nbr_element_t *)ptr;
+ printf("AP %2d: ", i + 1);
+ printf("bssid %02x:%02x:%02x:%02x:%02x:%02x ", nbr_elt->bssid.octet[0],
+ nbr_elt->bssid.octet[1], nbr_elt->bssid.octet[2], nbr_elt->bssid.octet[3],
+ nbr_elt->bssid.octet[4], nbr_elt->bssid.octet[5]);
+
+ printf("bssid_info %08x ", load32_ua(&nbr_elt->bssid_info));
+ printf("reg %2d channel %3d phytype %d\n", nbr_elt->reg,
+ nbr_elt->channel, nbr_elt->phytype);
+
+ ptr += TLV_HDR_LEN + DOT11_NEIGHBOR_REP_IE_FIXED_LEN;
+ }
+
+ return err;
+}
+
+static int
+wl_rrm_nbr_del_nbr(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ const char *cmdname = "rrm_nbr_del_nbr";
+ struct ether_addr ea;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv == NULL) {
+ printf("no bssid specified\n");
+ return BCME_USAGE_ERROR;
+ } else {
+ if (!wl_ether_atoe(*argv, &ea)) {
+ printf("Incorrect bssid format\n");
+ return BCME_ERROR;
+ }
+ err = wlu_iovar_set(wl, cmdname, &ea, sizeof(ea));
+ }
+
+ return err;
+}
+
+static int
+wl_rrm_nbr_add_nbr(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc;
+ int err = 0;
+ const char *cmdname = "rrm_nbr_add_nbr";
+ nbr_element_t nbr_elt;
+
+ UNUSED_PARAMETER(cmd);
+ memset(&nbr_elt, 0, sizeof(nbr_element_t));
+
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (argc != 6)
+ return BCME_USAGE_ERROR;
+
+ /* bssid */
+ if (!wl_ether_atoe(argv[1], &nbr_elt.bssid)) {
+ printf("wl_rrm_nbr_add_nbr parsing bssid failed\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* bssid info */
+ nbr_elt.bssid_info = htod32(strtoul(argv[2], NULL, 0));
+
+ /* Regulatory class */
+ nbr_elt.reg = htod32(strtoul(argv[3], NULL, 0));
+
+ /* channel */
+ nbr_elt.channel = htod32(strtoul(argv[4], NULL, 0));
+
+ /* phytype */
+ nbr_elt.phytype = htod32(strtoul(argv[5], NULL, 0));
+
+ nbr_elt.id = DOT11_MNG_NEIGHBOR_REP_ID;
+ nbr_elt.len = DOT11_NEIGHBOR_REP_IE_FIXED_LEN;
+
+ err = wlu_iovar_set(wl, cmdname, &nbr_elt, TLV_HDR_LEN + DOT11_NEIGHBOR_REP_IE_FIXED_LEN);
+ return err;
+}
+
+static int
+wl_rrm_parse_location(char *loc_arg, char *bufptr, int buflen)
+{
+ int len = 0;
+ char *ptr = loc_arg;
+ char hex[] = "XX";
+
+ if (!loc_arg) {
+ printf("%s: Location data is missing\n", __FUNCTION__);
+ len = -1;
+ goto done;
+ }
+
+ len = strlen(loc_arg)/2;
+ if ((len <= 0) || (len > buflen)) {
+ len = -1;
+ goto done;
+ }
+
+ if ((uint16)strlen(ptr) != len*2) {
+ printf("%s: Invalid length. Even number of characters expected.\n",
+ __FUNCTION__);
+ len = -1;
+ goto done;
+ }
+
+ while (*ptr) {
+ strncpy(hex, ptr, 2);
+ *bufptr++ = (char) strtoul(hex, NULL, 16);
+ ptr += 2;
+ }
+done:
+ return len;
+}
+
+
+static int
+wl_rrm_self_lci_civic(void *wl, cmd_t *cmd, char **argv, int argc, int cmd_id)
+{
+ int err = BCME_OK;
+ int len = 0;
+ char *bufptr;
+ wl_rrm_config_ioc_t *rrm_config_cmd = NULL;
+ wl_rrm_config_ioc_t rrm_config_param;
+ int malloc_len = sizeof(*rrm_config_cmd) + TLV_BODY_LEN_MAX -
+ DOT11_MNG_IE_MREP_FIXED_LEN;
+
+ rrm_config_cmd = (wl_rrm_config_ioc_t *) calloc(1, malloc_len);
+ if (rrm_config_cmd == NULL) {
+ printf("Failed to allocate buffer of %d bytes\n", malloc_len);
+ err = BCME_NOMEM;
+ goto done;
+ }
+
+ rrm_config_cmd->id = cmd_id;
+
+ if (argc == 3) {
+ bufptr = (char *)&rrm_config_cmd->data[0];
+ len = wl_rrm_parse_location(argv[1], bufptr, TLV_BODY_LEN_MAX -
+ DOT11_MNG_IE_MREP_FIXED_LEN);
+ if (len <= 0) {
+ printf("%s: parsing location arguments failed\n", __FUNCTION__);
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+
+ rrm_config_cmd->len = len;
+ err = wlu_iovar_set(wl, cmd->name, (void *)rrm_config_cmd,
+ WL_RRM_CONFIG_MIN_LENGTH + len);
+ goto done;
+
+ } else if (argc == 2) {
+ memset(&rrm_config_param, 0, sizeof(rrm_config_param));
+ rrm_config_param.id = cmd_id;
+ err = wlu_iovar_getbuf(wl, cmd->name, (void *)&rrm_config_param,
+ sizeof(rrm_config_param), (void *)rrm_config_cmd, malloc_len);
+ if (err < 0) {
+ printf("wlu_iov_get for \"%s\" returned error %d\n", cmd->name, err);
+ goto done;
+ }
+
+ prhex(cmd_id == WL_RRM_CONFIG_GET_CIVIC ? "Self Civic data" : "Self LCI data",
+ rrm_config_cmd->data, rrm_config_cmd->len);
+ printf("\n");
+ } else {
+ err = BCME_USAGE_ERROR;
+ }
+done:
+ if (rrm_config_cmd)
+ free(rrm_config_cmd);
+
+ return err;
+}
+
+static int
+wl_rrm_config(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = BCME_OK;
+ int argc = 0;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!argv[1]) {
+ printf("%s: no element type given, must be lci or civic\n", __FUNCTION__);
+ err = BCME_USAGE_ERROR;
+ goto done;
+ }
+
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ if (strcmp(argv[1], "lci") == 0) {
+ argv++;
+ err = wl_rrm_self_lci_civic(wl, cmd, argv, argc,
+ (argc == 3) ? WL_RRM_CONFIG_SET_LCI : WL_RRM_CONFIG_GET_LCI);
+ } else if (strcmp(argv[1], "civic") == 0) {
+ argv++;
+ err = wl_rrm_self_lci_civic(wl, cmd, argv, argc,
+ (argc == 3) ? WL_RRM_CONFIG_SET_CIVIC : WL_RRM_CONFIG_GET_CIVIC);
+ } else {
+ printf("%s: incorrect element type, not lci or civic\n", __FUNCTION__);
+ err = BCME_USAGE_ERROR;
+ }
+done:
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_rsdb.c b/wl/src/wl/exe/wluc_rsdb.c
new file mode 100644
index 0000000..f5745e6
--- /dev/null
+++ b/wl/src/wl/exe/wluc_rsdb.c
@@ -0,0 +1,358 @@
+/*
+ * wl rsdb command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_rsdb.c $
+ */
+#ifdef WLRSDB
+#ifdef WIN32
+#include <windows.h>
+#endif
+#include <wlioctl.h>
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_rsdb_caps;
+static cmd_func_t wl_rsdb_bands;
+static cmd_func_t wl_rsdb_config;
+
+static int wl_parse_infra_mode_list(char *list_str, uint8* list, int list_num);
+static int wl_parse_SIB_param_list(char *list_str, uint32* list, int list_num);
+
+static cmd_t wl_rsdb_cmds[] = {
+ {"rsdb_caps", wl_rsdb_caps, WLC_GET_VAR, -1,
+ "Get rsdb capabilities for given chip\n"
+ "\tUsage : wl rsdb_caps"},
+ {"rsdb_bands", wl_rsdb_bands, WLC_GET_VAR, -1,
+ "Get band of each wlc/core"
+ "\tUsage : wl rsdb_bands"},
+ {"rsdb_config", wl_rsdb_config, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set rsdb config\n"
+ "\t wl rsdb_config -n <NonInfraMode> -i <Infra(2G),Infra(5G)> -p <SIB(2G),SIB(5G)> \n"
+ "\t-n : <NonInfraMode> Default mode of operation of the device "
+ "\t-i : <InfraMode> target mode of operation for Infra 2G/5G connection"
+ "\t-p : <allowSIBParallelScan> Allow 2G/5G SIB parallel passive scan"
+ "\t SDB op Modes:"
+ "\t\tWLC_SDB_MODE_NOSDB_MAIN = 1 :NoSDB mode and Infra is on core 0"
+ "\t\tWLC_SDB_MODE_NOSDB_AUX = 2 :NoSDB mode and Infra is on core 1 "
+ "\t\tWLC_SDB_MODE_SDB_MAIN = 3 : SDB mode and infra on core-0"
+ "\t\tWLC_SDB_MODE_SDB_AUX = 4 : SDB mode and infra on core-1"
+ "\t\tWLC_SDB_MODE_SDB_AUTO = 5 : SDB mode and auto infra"
+ "Ex : rsdb_config -n 5 -i 5,1 -p 1,1"
+ },
+ { NULL, NULL, 0, 0, NULL },
+};
+static char *buf;
+
+/* module initialization */
+void
+wluc_rsdb_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register scan commands */
+ wl_module_cmds_register(wl_rsdb_cmds);
+}
+
+static const struct {
+ uint8 state;
+ char name[28];
+} sdb_op_modes[] = {
+ {WLC_SDB_MODE_NOSDB_MAIN, "NOSDB_MAIN"},
+ {WLC_SDB_MODE_NOSDB_AUX, "NOSDB_AUX"},
+ {WLC_SDB_MODE_SDB_MAIN, "SDB_MAIN"},
+ {WLC_SDB_MODE_SDB_AUX, "SDB_AUX"},
+ {WLC_SDB_MODE_SDB_AUTO, "SDB_AUTO"}
+};
+
+static const char *
+wlc_sdb_op_mode_name(uint8 state)
+{
+ uint i;
+ for (i = 0; i < ARRAYSIZE(sdb_op_modes); i++) {
+ if (sdb_op_modes[i].state == state)
+ return sdb_op_modes[i].name;
+ }
+ return "UNKNOWN";
+}
+static const struct {
+ uint8 state;
+ char name[28];
+} rsdb_band_names[] = {
+ {WLC_BAND_AUTO, "AUTO"},
+ {WLC_BAND_2G, "2G"},
+ {WLC_BAND_5G, "5G"},
+ {WLC_BAND_ALL, "ALL"},
+ {WLC_BAND_INVALID, "INVALID"}
+};
+static const char *
+wlc_rsdb_band_name(uint8 state)
+{
+ uint i;
+ for (i = 0; i < ARRAYSIZE(rsdb_band_names); i++) {
+ if (rsdb_band_names[i].state == state)
+ return rsdb_band_names[i].name;
+ }
+ return "UNKNOWN";
+}
+static int
+wl_rsdb_caps(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, i;
+ rsdb_caps_response_t *rsdb_caps_ptr = NULL;
+
+ argv++;
+ printf("in rsdb caps\n");
+ if (*argv == NULL) {
+ /* get */
+ err = wlu_var_getbuf_sm(wl, cmd->name, NULL, 0, (void *)&rsdb_caps_ptr);
+ if (err < 0) {
+ printf("%s(): wlu_var_getbuf failed %d \r\n", __FUNCTION__, err);
+ } else {
+ if (rsdb_caps_ptr->ver != WL_RSDB_CAPS_VER) {
+ printf("Bad version : %d\n", rsdb_caps_ptr->ver);
+ return BCME_VERSION;
+ }
+ if (rsdb_caps_ptr->len >= WL_RSDB_CAPS_FIXED_LEN) {
+ printf("**RSDB CAPABILITIES**\n");
+ printf("RSDB: %d\n", rsdb_caps_ptr->rsdb);
+ printf("Num of cores: %d\n", rsdb_caps_ptr->num_of_cores);
+ printf("Flags: ");
+ if (rsdb_caps_ptr->flags & SYNCHRONOUS_OPERATION_TRUE)
+ printf("\tSynchronous Operation supported\n");
+ printf("\n");
+ /* Add in more capabilites here */
+ for (i = 0; i < rsdb_caps_ptr->num_of_cores; i++) {
+ printf("Num of chains in core-%d: %d\n", i,
+ rsdb_caps_ptr->num_chains[i]);
+ }
+ }
+ }
+ } else {
+ /* set not allowed */
+ return USAGE_ERROR;
+ }
+ return err;
+}
+
+static int
+wl_rsdb_bands(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ uint8 i;
+ rsdb_bands_t *ptr;
+
+ memset(&ptr, 0, sizeof(*ptr));
+ argv++;
+
+ if (*argv == NULL) {
+ /* get */
+ err = wlu_var_getbuf_sm(wl, cmd->name, NULL, 0, (void *)&ptr);
+ if (err < 0) {
+ printf("%s(): wlu_var_getbuf_sm failed %d \r\n", __FUNCTION__, err);
+ } else {
+ /* Check return value of version */
+ if (ptr->ver != WL_RSDB_BANDS_VER) {
+ printf("Bad version : %d\n", ptr->ver);
+ return BCME_VERSION;
+ }
+ if (ptr->len >= WL_RSDB_BANDS_FIXED_LEN) {
+ printf("Num of cores:%d\n", ptr->num_cores);
+ for (i = 0; i < ptr->num_cores; i++) {
+ printf("WLC[%d]: %s\n", i,
+ wlc_rsdb_band_name(ptr->band[i]));
+ }
+ }
+ }
+ } else {
+ /* set not allowed */
+ return USAGE_ERROR;
+ }
+ return err;
+}
+static int
+wl_rsdb_config(void *wl, cmd_t *cmd, char **argv)
+{
+ rsdb_config_t rsdb_config;
+ int err, i;
+ char opt, *p, *endptr = NULL;
+
+ memset(&rsdb_config, 0, sizeof(rsdb_config));
+
+ if (!*++argv) {
+ if ((err = wlu_iovar_get(wl, cmd->name, &rsdb_config,
+ sizeof(rsdb_config))) < 0) {
+ return err;
+ }
+ if (rsdb_config.ver != WL_RSDB_CONFIG_VER) {
+ err = BCME_VERSION;
+ goto exit;
+ }
+ if (rsdb_config.len >= WL_RSDB_CONFIG_LEN) {
+
+ printf("NonInfraMode:%s\n",
+ wlc_sdb_op_mode_name(rsdb_config.non_infra_mode));
+
+ for (i = 0; i < MAX_BANDS; i++) {
+ printf("InfraMode(%s):%s\n", (i == 0) ? "2G":"5G",
+ wlc_sdb_op_mode_name(rsdb_config.infra_mode[i]));
+ }
+ for (i = 0; i < MAX_BANDS; i++) {
+ printf("SIB Scan(%s):", (i == 0) ? "2G":"5G");
+ printf("%s\n",
+ (rsdb_config.flags[i] & ALLOW_SIB_PARALLEL_SCAN) ?
+ "ENABLED":"DISABLED");
+ }
+ printf("Current_mode: %s\n",
+ wlc_sdb_op_mode_name(rsdb_config.current_mode));
+ }
+ } else {
+ /* Get the existing config and change only the fields passed */
+ if ((err = wlu_iovar_get(wl, cmd->name, &rsdb_config,
+ sizeof(rsdb_config))) < 0) {
+ return err;
+ }
+ if (rsdb_config.ver != WL_RSDB_CONFIG_VER) {
+ err = BCME_VERSION;
+ goto exit;
+ }
+ while ((p = *argv) != NULL) {
+ argv++;
+ opt = '\0';
+
+ if (!strncmp(p, "-", 1)) {
+ if ((strlen(p) > 2) || (*argv == NULL)) {
+ fprintf(stderr, "Invalid option %s \n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ } else {
+ fprintf(stderr, "Invalid option %s \n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ opt = p[1];
+
+ switch (opt) {
+ case 'n':
+ rsdb_config.non_infra_mode = (uint8)strtol(*argv,
+ &endptr, 0);
+ argv++;
+ break;
+ case 'i':
+ wl_parse_infra_mode_list(*argv, rsdb_config.infra_mode,
+ MAX_BANDS);
+ argv++;
+ break;
+ case 'p':
+ wl_parse_SIB_param_list(*argv, rsdb_config.flags,
+ MAX_BANDS);
+ argv++;
+ break;
+ default:
+ fprintf(stderr, "Invalid option %s \n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ rsdb_config.len = WL_RSDB_CONFIG_LEN;
+ if ((err = wlu_var_setbuf(wl, cmd->name, &rsdb_config,
+ sizeof(rsdb_config))) < 0) {
+ return err;
+ }
+ }
+
+exit:
+ return err;
+}
+
+static int
+wl_parse_infra_mode_list(char *list_str, uint8* list, int list_num)
+{
+ int num;
+ int val;
+ char* str;
+ char* endptr = NULL;
+
+ if (list_str == NULL)
+ return -1;
+
+ str = list_str;
+ num = 0;
+ while (*str != '\0') {
+ val = (int)strtol(str, &endptr, 0);
+ if (endptr == str) {
+ fprintf(stderr,
+ "could not parse list number starting at"
+ " substring \"%s\" in list:\n%s\n",
+ str, list_str);
+ return -1;
+ }
+ str = endptr + strspn(endptr, " ,");
+
+ if (num == list_num) {
+ fprintf(stderr, "too many members (more than %d) in list:\n%s\n",
+ list_num, list_str);
+ return -1;
+ }
+
+ list[num++] = (uint16)val;
+ }
+
+ return num;
+}
+
+static int
+wl_parse_SIB_param_list(char *list_str, uint32* list, int list_num)
+{
+ int num;
+ int val;
+ char* str;
+ char* endptr = NULL;
+
+ if (list_str == NULL)
+ return -1;
+
+ str = list_str;
+ num = 0;
+ while (*str != '\0') {
+ val = (int)strtol(str, &endptr, 0);
+ if (endptr == str) {
+ fprintf(stderr,
+ "could not parse list number starting at"
+ " substring \"%s\" in list:\n%s\n",
+ str, list_str);
+ return -1;
+ }
+ str = endptr + strspn(endptr, " ,");
+
+ if (num == list_num) {
+ fprintf(stderr, "too many members (more than %d) in list:\n%s\n",
+ list_num, list_str);
+ return -1;
+ }
+
+ list[num++] = (uint16)val;
+ }
+ return num;
+}
+#endif /* WLRSDB */
diff --git a/wl/src/wl/exe/wluc_scan.c b/wl/src/wl/exe/wluc_scan.c
new file mode 100644
index 0000000..c5306b3
--- /dev/null
+++ b/wl/src/wl/exe/wluc_scan.c
@@ -0,0 +1,511 @@
+/*
+ * wl scan command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_scan.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifdef EXTENDED_SCAN
+static cmd_func_t wl_extdscan;
+static int wl_parse_extdchannel_list(char* list_str,
+ chan_scandata_t* channel_list, int channel_num);
+#endif
+static cmd_func_t wl_scanmac;
+
+static cmd_t wl_scan_cmds[] = {
+ { "scancache_clear", wl_var_void, -1, WLC_SET_VAR,
+ "clear the scan cache"},
+#ifdef EXTENDED_SCAN
+ { "extdscan", wl_extdscan, -1, WLC_SET_VAR,
+ "Initiate an extended scan.\n"
+ "\tDefault to an active scan across all channels for any SSID.\n"
+ "\tOptional args: list of SSIDs to scan.\n"
+ "\tOptions:\n"
+ "\t-s S1 S2 S3, --ssid=S1 S2 S3\t\tSSIDs to scan, comma or space separated\n"
+ "\t-x x, --split_scan=ST\t[split_scan] scan type\n"
+ "\t-t ST, --scan_type=ST\t[background:0/forcedbackground:1/foreground:2] scan type\n"
+ "\t-n N, --nprobes=N\tnumber of probes per scanned channel, per SSID\n"
+ "\t-c L, --channels=L\tcomma or space separated list of channels to scan"},
+#endif
+ { "passive", wl_int, WLC_GET_PASSIVE_SCAN, WLC_SET_PASSIVE_SCAN,
+ "Puts scan engine into passive mode" },
+ { "scansuppress", wl_int, WLC_GET_SCANSUPPRESS, WLC_SET_SCANSUPPRESS,
+ "Suppress all scans for testing.\n"
+ "\t0 - allow scans\n"
+ "\t1 - suppress scans" },
+ { "scan_channel_time", wl_int, WLC_GET_SCAN_CHANNEL_TIME, WLC_SET_SCAN_CHANNEL_TIME,
+ "Get/Set scan channel time"},
+ { "scan_unassoc_time", wl_int, WLC_GET_SCAN_UNASSOC_TIME, WLC_SET_SCAN_UNASSOC_TIME,
+ "Get/Set unassociated scan channel dwell time"},
+ { "scan_home_time", wl_int, WLC_GET_SCAN_HOME_TIME, WLC_SET_SCAN_HOME_TIME,
+ "Get/Set scan home channel dwell time"},
+ { "scan_passive_time", wl_int, WLC_GET_SCAN_PASSIVE_TIME, WLC_SET_SCAN_PASSIVE_TIME,
+ "Get/Set passive scan channel dwell time"},
+ { "scan_nprobes", wl_int, WLC_GET_SCAN_NPROBES, WLC_SET_SCAN_NPROBES,
+ "Get/Set scan parameter for number of probes to use per channel scanned"},
+ { "scan_ps", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set scan power optimization enable/disable"},
+ { "scanmac", wl_scanmac, WLC_GET_VAR, WLC_SET_VAR,
+ "Configure scan MAC using subcommands:\n"
+ "\tscanmac enable <0|1>\n"
+ "\tscanmac bsscfg\n"
+ "\tscanmac config <mac> <random_mask> <scan_bitmap>\n"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_scan_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register scan commands */
+ wl_module_cmds_register(wl_scan_cmds);
+}
+
+#ifdef EXTENDED_SCAN
+/* wl extdscan
+ * -s --ssid=ssid1 ssid2 ssid3
+ * -b --split_scan=0 : [split_scan]
+ * -t --scan_type=0 : [background/forcedbackground/foreground]
+ * -n --nprobes=
+ * -c --channels=
+ */
+static int
+wl_extdscan(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_extdscan_params_t *params;
+ int params_size = WL_EXTDSCAN_PARAMS_FIXED_SIZE +
+ (WL_NUMCHANNELS * sizeof(chan_scandata_t));
+ int val = 0;
+ char *p, *eq, *valstr, *endptr;
+ char opt;
+ bool positional_param;
+ bool good_int;
+ bool opt_end;
+ int err = 0;
+ int keylen;
+ char key[64];
+ int i;
+ int nssid = 0;
+
+ fprintf(stderr, "params alloc size is %d\n", params_size);
+ params = (wl_extdscan_params_t *)malloc(params_size);
+ if (params == NULL) {
+ fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
+ return BCME_NOMEM;
+ }
+ memset(params, 0, params_size);
+
+ params->scan_type = EXTDSCAN_FORCEDBACKGROUND_SCAN;
+ params->nprobes = 3;
+ params->band = WLC_BAND_2G;
+ params->split_scan = 0;
+
+ /* skip the command name */
+ argv++;
+
+ if (*argv == NULL) {
+ fprintf(stderr, "no arguments to wl_extdscan\n");
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ opt_end = FALSE;
+ while ((p = *argv) != NULL) {
+ argv++;
+ positional_param = FALSE;
+ memset(key, 0, sizeof(key));
+ opt = '\0';
+ valstr = NULL;
+ good_int = FALSE;
+
+ if (opt_end) {
+ positional_param = TRUE;
+ valstr = p;
+ }
+ else if (!strcmp(p, "--")) {
+ opt_end = TRUE;
+ continue;
+ }
+ else if (!strncmp(p, "--", 2)) {
+ eq = strchr(p, '=');
+ if (eq == NULL) {
+ fprintf(stderr,
+ "wl_extdscan: missing \" = \" in long param \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ keylen = eq - (p + 2);
+ if (keylen > 63)
+ keylen = 63;
+ memcpy(key, p + 2, keylen);
+
+ valstr = eq + 1;
+ if (*valstr == '\0') {
+ fprintf(stderr,
+ "extdscan: missing value after \" = \" in long param \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ else if (!strncmp(p, "-", 1)) {
+ opt = p[1];
+ if (strlen(p) > 2) {
+ fprintf(stderr,
+ "extdscan: only single char options, error on param \"%s\"\n", p);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ if (*argv == NULL) {
+ fprintf(stderr,
+ "extdscan: missing value parameter after \"%s\"\n", p);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ valstr = *argv;
+ argv++;
+ } else {
+ positional_param = TRUE;
+ valstr = p;
+ }
+
+ /* parse valstr as int just in case */
+ if (valstr) {
+ val = (int)strtol(valstr, &endptr, 0);
+ if (*endptr == '\0') {
+ /* not all the value string was parsed by strtol */
+ good_int = TRUE;
+ }
+ }
+
+ if (opt == 's' || !strcmp(key, "ssid") || positional_param) {
+ nssid = wl_parse_ssid_list(valstr, params->ssid,
+ nssid, WLC_EXTDSCAN_MAX_SSID);
+ if (nssid < 0) {
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+ if (opt == 'b' || !strcmp(key, "band")) {
+ if (!strcmp(valstr, "5G")) {
+ params->band = WLC_BAND_5G;
+ }
+ else if (!strcmp(valstr, "2.4G")) {
+ params->band = WLC_BAND_2G;
+ }
+ else if (!strcmp(valstr, "all")) {
+ params->band = WLC_BAND_ALL;
+ } else {
+ fprintf(stderr,
+ "scan_type value should be \"5G\" "
+ "or \"2.4G\" " "or \"all\" but got \"%s\"\n", valstr);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ if (opt == 't' || !strcmp(key, "scan_type")) {
+ if (!strcmp(valstr, "background")) {
+ params->scan_type = EXTDSCAN_BACKGROUND_SCAN;
+ } else if (!strcmp(valstr, "fbackground")) {
+ params->scan_type = EXTDSCAN_FORCEDBACKGROUND_SCAN;
+ } else if (!strcmp(valstr, "foreground")) {
+ params->scan_type = EXTDSCAN_FOREGROUND_SCAN;
+ } else {
+ fprintf(stderr,
+ "scan_type value should be \"background\" "
+ "or \"fbackground\" " "or \"foreground\" but got \"%s\"\n", valstr);
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ }
+ if (opt == 'n' || !strcmp(key, "nprobes")) {
+ if (!good_int) {
+ fprintf(stderr,
+ "could not parse \"%s\" as an int for value nprobes\n", valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ params->nprobes = val;
+ }
+ if (opt == 'x' || !strcmp(key, "split_scan")) {
+ if (val != 0)
+ params->split_scan = 1;
+ }
+ if (opt == 'c' || !strcmp(key, "channels")) {
+ params->channel_num = wl_parse_extdchannel_list(valstr,
+ params->channel_list, WL_NUMCHANNELS);
+ if (params->channel_num == -1) {
+ fprintf(stderr, "error parsing channel list arg\n");
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+ }
+
+ if (nssid > WLC_EXTDSCAN_MAX_SSID) {
+ fprintf(stderr, "ssid count %d exceeds max of %d\n",
+ nssid, WLC_EXTDSCAN_MAX_SSID);
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ params_size = WL_EXTDSCAN_PARAMS_FIXED_SIZE +
+ (params->channel_num * sizeof(chan_scandata_t));
+
+ fprintf(stderr, "ssid list is %s(%d) %s(%d) %s(%d) %s(%d) %s(%d)\n",
+ (char *)¶ms->ssid[0].SSID, params->ssid[0].SSID_len,
+ (char *)¶ms->ssid[1].SSID, params->ssid[1].SSID_len,
+ (char *)¶ms->ssid[2].SSID, params->ssid[2].SSID_len,
+ (char *)¶ms->ssid[3].SSID, params->ssid[3].SSID_len,
+ (char *)¶ms->ssid[4].SSID, params->ssid[4].SSID_len);
+ if (params->split_scan)
+ fprintf(stderr, "split scan is enabled\n");
+ else
+ fprintf(stderr, "split scan is not enabled\n");
+
+ fprintf(stderr, "scan type is %d, nprobes are %d, band is %d, channels are %d\n",
+ params->scan_type, params->nprobes, params->band, params->channel_num);
+
+ fprintf(stderr, "params size is %d\n", params_size);
+ params->scan_type = htodenum(params->scan_type);
+ for (i = 0; i < WLC_EXTDSCAN_MAX_SSID; i++) {
+ params->ssid[i].SSID_len = htod32(params->ssid[i].SSID_len);
+ }
+ for (i = 0; i < params->channel_num; i++) {
+ chanspec_t chanspec = params->channel_list[i].channel;
+ chanspec = wl_chspec_to_driver(chanspec);
+ if (chanspec == INVCHANSPEC) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ params->channel_list[i].channel = chanspec;
+ params->channel_list[i].channel_mintime =
+ htod32(params->channel_list[i].channel_mintime);
+ params->channel_list[i].channel_maxtime =
+ htod32(params->channel_list[i].channel_maxtime);
+ }
+ params->channel_num = htod32(params->channel_num);
+ err = wlu_var_setbuf(wl, cmd->name, params, params_size);
+
+exit:
+ free(params);
+ return err;
+}
+
+static int
+wl_parse_extdchannel_list(char* list_str, chan_scandata_t* channel_list, int channel_num)
+{
+ int num;
+ int val;
+ char* str;
+ char* endptr;
+
+ if (list_str == NULL)
+ return -1;
+
+ str = list_str;
+ num = 0;
+ while (*str != '\0') {
+ val = (int)strtol(str, &endptr, 0);
+ if (endptr == str) {
+ fprintf(stderr,
+ "could not parse channel number starting at"
+ " substring \"%s\" in list:\n%s\n",
+ str, list_str);
+ return -1;
+ }
+ str = endptr + strspn(endptr, " ,");
+
+ if (num == channel_num) {
+ fprintf(stderr, "too many channels (more than %d) in channel list:\n%s\n",
+ channel_num, list_str);
+ return -1;
+ }
+ channel_list->channel = (uint16)val;
+ channel_list++;
+ num++;
+ }
+
+ return num;
+}
+#endif /* EXTENDED_SCAN */
+
+static int
+wl_scanmac(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1;
+ char *subcmd;
+ int subcmd_len;
+
+ /* skip iovar */
+ argv++;
+
+ /* must have subcommand */
+ subcmd = *argv++;
+ if (!subcmd) {
+ return BCME_USAGE_ERROR;
+ }
+ subcmd_len = strlen(subcmd);
+
+ if (!*argv) {
+ /* get */
+ uint8 buffer[OFFSETOF(wl_scanmac_t, data)];
+ wl_scanmac_t *sm = (wl_scanmac_t *)buffer;
+ int len = OFFSETOF(wl_scanmac_t, data);
+
+ memset(sm, 0, len);
+ if (!strncmp(subcmd, "enable", subcmd_len)) {
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_ENABLE;
+ } else if (!strncmp(subcmd, "bsscfg", subcmd_len)) {
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_BSSCFG;
+ } else if (!strncmp(subcmd, "config", subcmd_len)) {
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_CONFIG;
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* invoke GET iovar */
+ sm->subcmd_id = dtoh16(sm->subcmd_id);
+ sm->len = dtoh16(sm->len);
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, sm, len, buf, WLC_IOCTL_SMLEN)) < 0) {
+ return err;
+ }
+
+ /* process and print GET results */
+ sm = (wl_scanmac_t *)buf;
+ sm->subcmd_id = dtoh16(sm->subcmd_id);
+ sm->len = dtoh16(sm->len);
+
+ switch (sm->subcmd_id) {
+ case WL_SCANMAC_SUBCMD_ENABLE:
+ {
+ wl_scanmac_enable_t *sm_enable = (wl_scanmac_enable_t *)sm->data;
+ if (sm->len >= sizeof(*sm_enable)) {
+ printf("%d\n", sm_enable->enable);
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ case WL_SCANMAC_SUBCMD_BSSCFG:
+ {
+ wl_scanmac_bsscfg_t *sm_bsscfg = (wl_scanmac_bsscfg_t *)sm->data;
+ if (sm->len >= sizeof(*sm_bsscfg)) {
+ sm_bsscfg->bsscfg = dtoh32(sm_bsscfg->bsscfg);
+ printf("%d\n", sm_bsscfg->bsscfg);
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ case WL_SCANMAC_SUBCMD_CONFIG:
+ {
+ wl_scanmac_config_t *sm_config = (wl_scanmac_config_t *)sm->data;
+ if (sm->len >= sizeof(*sm_config)) {
+ sm_config->scan_bitmap = dtoh16(sm_config->scan_bitmap);
+ printf("mac: %s\n", wl_ether_etoa(&sm_config->mac));
+ printf("random mask: %s\n", wl_ether_etoa(&sm_config->random_mask));
+ printf("scan bitmap: 0x%02X\n", sm_config->scan_bitmap);
+ if (sm_config->scan_bitmap & WL_SCANMAC_SCAN_UNASSOC) {
+ printf(" unassoc\n");
+ }
+ if (sm_config->scan_bitmap & WL_SCANMAC_SCAN_ASSOC_ROAM) {
+ printf(" assoc roam\n");
+ }
+ if (sm_config->scan_bitmap & WL_SCANMAC_SCAN_ASSOC_PNO) {
+ printf(" assoc PNO\n");
+ }
+ if (sm_config->scan_bitmap & WL_SCANMAC_SCAN_ASSOC_HOST) {
+ printf(" assoc host\n");
+ }
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ else {
+ /* set */
+ uint8 buffer[OFFSETOF(wl_scanmac_t, data) +
+ MAX(sizeof(wl_scanmac_enable_t), sizeof(wl_scanmac_config_t))];
+ wl_scanmac_t *sm = (wl_scanmac_t *)buffer;
+ int len = OFFSETOF(wl_scanmac_t, data);
+
+ if (!strncmp(subcmd, "enable", subcmd_len) &&
+ (*argv[0] == '0' || *argv[0] == '1')) {
+ wl_scanmac_enable_t *sm_enable = (wl_scanmac_enable_t *)sm->data;
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_ENABLE;
+ sm->len = sizeof(*sm_enable);
+ sm_enable->enable = atoi(argv[0]);
+ } else if (!strncmp(subcmd, "config", subcmd_len) &&
+ argv[0] && argv[1] && argv[2]) {
+ wl_scanmac_config_t *sm_config = (wl_scanmac_config_t *)sm->data;
+ char *mac = argv[0];
+ char *mask = argv[1];
+ char *bitmap = argv[2];
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_CONFIG;
+ sm->len = sizeof(*sm_config);
+ if (!wl_ether_atoe(mac, &sm_config->mac) ||
+ !wl_ether_atoe(mask, &sm_config->random_mask)) {
+ return BCME_USAGE_ERROR;
+ }
+ sm_config->scan_bitmap = (uint16)strtoul(bitmap, NULL, 0);
+ sm_config->scan_bitmap = htod16(sm_config->scan_bitmap);
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* invoke SET iovar */
+ len = OFFSETOF(wl_scanmac_t, data) + sm->len;
+ sm->subcmd_id = htod16(sm->subcmd_id);
+ sm->len = htod16(sm->len);
+ err = wlu_iovar_set(wl, cmd->name, sm, len);
+ }
+
+ return err;
+}
diff --git a/wl/src/wl/exe/wluc_sdio.c b/wl/src/wl/exe/wluc_sdio.c
new file mode 100644
index 0000000..9ca285a
--- /dev/null
+++ b/wl/src/wl/exe/wluc_sdio.c
@@ -0,0 +1,16 @@
+/*
+ * wl sdio command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_sdio.c 458728 2014-02-27 18:15:25Z $
+ */
diff --git a/wl/src/wl/exe/wluc_seq_cmds.c b/wl/src/wl/exe/wluc_seq_cmds.c
new file mode 100644
index 0000000..54976b5
--- /dev/null
+++ b/wl/src/wl/exe/wluc_seq_cmds.c
@@ -0,0 +1,72 @@
+/*
+ * wl seq_cmds command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_seq_cmds.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_t wl_seq_cmds[] = {
+ { "seq_start", wl_seq_start, -1, WLC_SET_VAR,
+ "Initiates command batching sequence. Subsequent IOCTLs will be queued until\n"
+ "seq_stop is received."},
+ { "seq_stop", wl_seq_stop, -1, WLC_SET_VAR,
+ "Defines the end of command batching sequence. Queued IOCTLs will be executed."},
+ { "seq_delay", wl_varint, -1, WLC_SET_VAR,
+ "Driver should spin for the indicated amount of time.\n"
+ "It is only valid within the context of batched commands."},
+ { "seq_error_index", wl_varint, WLC_GET_VAR, -1,
+ "Used to retrieve the index (starting at 1) of the command that failed within a batch"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_seq_cmds_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register seq_cmds commands */
+ wl_module_cmds_register(wl_seq_cmds);
+}
diff --git a/wl/src/wl/exe/wluc_stf.c b/wl/src/wl/exe/wluc_stf.c
new file mode 100644
index 0000000..a04353e
--- /dev/null
+++ b/wl/src/wl/exe/wluc_stf.c
@@ -0,0 +1,1327 @@
+/*
+ * wl stf command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_stf.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#include "wlu_rates_matrix.h"
+
+#define WL_MIMO_PS_MAX_PARAMS 4
+#define WL_MIMO_PS_LEARNING_MAX_PARAMS 3
+
+static void wl_txppr_print(ppr_t *ppr, int cck, uint flags);
+static void wl_txppr_print_bw(ppr_t *ppr, int cck, uint flags, wl_tx_bw_t bw);
+static cmd_func_t wl_get_current_txppr;
+static cmd_func_t wl_txcore;
+static cmd_func_t wl_txcore_pwr_offset;
+static int wl_mimo_stf(void *wl, cmd_t *cmd, char **argv);
+static cmd_func_t wl_spatial_policy, wl_ratetbl_ppr;
+static cmd_func_t wl_mimo_ps_cfg;
+static cmd_func_t wl_mimo_ps_learning_cfg;
+static int wl_mimo_ps_learning_cfg_get_status(void *wl, const char *iovar);
+static cmd_func_t wl_mimo_ps_status;
+static int wl_mimo_ps_status_dump(wl_mimo_ps_status_t *status);
+static int wl_mimo_ps_status_assoc_status_dump(uint8 assoc_status);
+static void wl_mimo_ps_status_hw_state_dump(uint16 hw_state);
+static cmd_func_t wl_temp_throttle_control;
+static cmd_func_t wl_ocl_status;
+static void wl_ocl_status_fw_dump(uint16 fw_state);
+static void wl_ocl_status_hw_dump(uint8 hw_state);
+
+static cmd_t wl_stf_cmds[] = {
+ { "curppr", wl_get_current_txppr, WLC_GET_VAR, -1,
+ "Return current tx power per rate offset."},
+ { "txcore", wl_txcore, WLC_GET_VAR, WLC_SET_VAR,
+ "Usage: wl txcore -k <CCK core mask> -o <OFDM core mask> -s <1..4> -c <core bitmap>\n"
+ "\t-k CCK core mask\n"
+ "\t-o OFDM core mask\n"
+ "\t-s # of space-time-streams\n"
+ "\t-c active core (bitmask) to be used when transmitting frames"
+ },
+ { "txcore_override", wl_txcore, WLC_GET_VAR, -1,
+ "Usage: wl txcore_override\n"
+ "\tget the user override of txcore"
+ },
+ { "txchain_pwr_offset", wl_txcore_pwr_offset, WLC_GET_VAR, WLC_SET_VAR,
+ "Usage: wl txchain_pwr_offset [qdBm offsets]\n"
+ "\tGet/Set the current offsets for each core in qdBm (quarter dBm)"
+ },
+ { "mimo_ss_stf", wl_mimo_stf, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set SS STF mode.\n"
+ "\tUsage: wl mimo_ss_stf <value> <-b a | b>\n"
+ "\tvalue: 0 - SISO; 1 - CDD\n"
+ "\t-b(band): a - 5G; b - 2.4G"},
+ { "spatial_policy", wl_spatial_policy, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get spatial_policy\n"
+ "\tUsage: wl spatial_policy <-1: auto / 0: turn off / 1: turn on>\n"
+ "\t to control individual band/sub-band use\n"
+ "\t wl spatial_policy a b c d e\n"
+ "\t where a is 2.4G band setting\n"
+ "\t where b is 5G lower band setting\n"
+ "\t where c is 5G middle band setting\n"
+ "\t where d is 5G high band setting\n"
+ "\t where e is 5G upper band setting"},
+ { "ratetbl_ppr", wl_ratetbl_ppr, WLC_GET_VAR, WLC_SET_VAR,
+ "Usage: For get: wl ratetbl_ppr\n"
+ "\t For set: wl ratetbl_ppr <rate> <ppr>" },
+ { "mrc_rssi_threshold", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set mrc_rssi_threshold for mimo power save,\n "
+ "\twhen RSSI is below RSSI level specified by mrc_rssi_threshold then \n"
+ "\tall rx chains will be made active for all rx frames to benefit "
+ "from Maximal ratio combining (MRC) "
+ },
+ { "mimo_ps_cfg_change_wait_time", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set mimo_ps_guard_interval for mimo power save,\n "
+ "\tspecifies the time STA will wait before receiving packets"
+ "when moving from higher configuration to lower configuration\n"
+ },
+ { "mimo_ps_cfg", wl_mimo_ps_cfg, WLC_GET_VAR, WLC_SET_VAR,
+ "Description: Configure MIMO Power save configuration.\n"
+ "\twhere active_chains: 0 for all, 1 for 1 chain. Only 0 and 1 are supported for now.\n"
+ "\tIn future more than 1 can be supported to enable more than 1 but less than max chains.\n"
+ "\tmode = static (0) or dynamic (1) or disabled(3)."
+ "Mode applies only when active_chains is 0.\n"
+ "\tbandwidth = Full (0), 20M (1), 40M (2), 80M (3).\n"
+ "\tApply changes after learning donot appy(0) apply(1).\n"
+ },
+ { "mimo_ps_status", wl_mimo_ps_status, WLC_GET_VAR, -1,
+ "usage: mimo_ps_status\n"
+ "Displays MIMO PS related state/information"
+ },
+ { "mimo_ps_learning_config", wl_mimo_ps_learning_cfg, WLC_GET_VAR, WLC_SET_VAR,
+ "Description: Configure mimo ps learning related parameters\n"
+ "\tusage: wl mimo_ps_learning_config <flag> <no_of_packets> \n"
+ "\tFlag :\n\t0 - Get status of current learning\n"
+ "\t1 - ABORT current learning. \n"
+ "\t2 - used to configure only no of packets\n"
+ },
+ { "temp_throttle_control", wl_temp_throttle_control, WLC_GET_VAR, WLC_SET_VAR,
+ "Usage: temp_throttle_control <enable/disable> <value>\n"
+ },
+ { "ocl_status", wl_ocl_status, WLC_GET_VAR, -1,
+ "usage: ocl_status\n"
+ "Displays ocl fw/hw state/information"
+ },
+ { "ocl_rssi_threshold", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set ocl_rssi_threshold such that,\n "
+ "\twhen RSSI is below the specified ocl_rssi_threshold then \n"
+ "\tocl is disabled.\n"
+ },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_stf_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register stf commands */
+ wl_module_cmds_register(wl_stf_cmds);
+}
+
+static void
+wl_txppr_print(ppr_t *ppr, int cck, uint flags)
+{
+
+ switch (ppr_get_ch_bw(ppr)) {
+ case WL_TX_BW_20:
+ printf("\n20MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_20);
+ break;
+ case WL_TX_BW_40:
+ printf("\n20 in 40MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_20IN40);
+ printf("\n40MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_40);
+ break;
+ case WL_TX_BW_80:
+ printf("\n20 in 80MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_20IN80);
+ printf("\n40 in 80MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_40IN80);
+ printf("\n80MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_80);
+ break;
+ case WL_TX_BW_160:
+ printf("\n20 in 160MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_20IN160);
+ printf("\n40 in 160MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_40IN160);
+ printf("\n80 in 160MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_80IN160);
+ printf("\n160MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_160);
+ break;
+ case WL_TX_BW_8080:
+ printf("\n20 in 80+80MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_20IN8080);
+ printf("\n40 in 80+80MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_40IN8080);
+ printf("\n80 in 80+80MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_80IN8080);
+ printf("\nchan1 80+80MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_8080);
+ printf("\nchan2 80+80MHz:\n");
+ wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_8080CHAN2);
+ break;
+ default:
+ break;
+ }
+ /* MCS32 value is obsoleted */
+ /* printf("MCS32 %2d\n", ppr->mcs32); */
+ printf("\n");
+}
+
+
+#define PRINT_PPR_RATE_LOOP(idx, len, rates) \
+ for (idx = 0; idx < len; idx++) { \
+ if (rates[idx] == WL_RATE_DISABLED) \
+ printf(" -"); \
+ else \
+ printf(" %2d", rates[idx]); \
+ }
+
+/* print power offset for for a given bandwidth */
+static void
+wl_txppr_print_bw(ppr_t *ppr, int cck, uint flags, wl_tx_bw_t bw)
+{
+ uint i, j, rlen;
+ uint n = WL_NUM_2x2_ELEMENTS;
+ uint offset = 0;
+ int8 *ptr, *vhtptr;
+ const char *str = "";
+ bool siso = ((flags & WL_TX_POWER_F_MIMO) == 0);
+ bool vht = ((flags & WL_TX_POWER_F_VHT) != 0);
+ ppr_ofdm_rateset_t ofdm_rate;
+ ppr_vht_mcs_rateset_t vhtrate;
+
+
+ if (!siso) {
+ offset = WL_NUM_3x3_ELEMENTS;
+ n = WL_NUM_4x4_ELEMENTS;
+ }
+
+ if (cck) {
+ ppr_dsss_rateset_t rate;
+ ppr_get_dsss(ppr, bw, WL_TX_CHAINS_1, &rate);
+ printf("CCK ");
+ PRINT_PPR_RATE_LOOP(j, WL_RATESET_SZ_DSSS, rate.pwr);
+ if (!siso) {
+ for (i = WL_TX_CHAINS_2; i <= WL_TX_CHAINS_4; i++) {
+ ppr_get_dsss(ppr, bw, i, &rate);
+ printf("\nCCK CDD 1x%d ", i);
+ PRINT_PPR_RATE_LOOP(j, WL_RATESET_SZ_DSSS, rate.pwr);
+ }
+ }
+ }
+ ppr_get_ofdm(ppr, bw, WL_TX_MODE_NONE, WL_TX_CHAINS_1, &ofdm_rate);
+ printf("\nOFDM ");
+ PRINT_PPR_RATE_LOOP(j, WL_RATESET_SZ_OFDM, ofdm_rate.pwr);
+ for (i = WL_TX_CHAINS_2; i <= WL_TX_CHAINS_4; i++) {
+ ppr_get_ofdm(ppr, bw, WL_TX_MODE_CDD, i, &ofdm_rate);
+ printf("\nOFDM-CDD 1x%d", i);
+ PRINT_PPR_RATE_LOOP(j, WL_RATESET_SZ_OFDM, ofdm_rate.pwr);
+ }
+ printf("\n");
+ for (i = 0; i < n; i++) {
+ wl_tx_nss_t nss;
+ wl_tx_mode_t mode;
+ wl_tx_chains_t chains;
+ switch (i + offset) {
+ case 0:
+ str = "MCS-SISO ";
+ nss = WL_TX_NSS_1;
+ mode = WL_TX_MODE_NONE;
+ chains = WL_TX_CHAINS_1;
+ ptr = vhtrate.pwr;
+ vhtptr = NULL;
+ break;
+ case 1:
+ str = "MCS-CDD ";
+ nss = WL_TX_NSS_1;
+ mode = WL_TX_MODE_CDD;
+ chains = WL_TX_CHAINS_2;
+ ptr = vhtrate.pwr;
+ vhtptr = NULL;
+ break;
+ case 2:
+ str = "MCS STBC ";
+ nss = WL_TX_NSS_1;
+ mode = WL_TX_MODE_STBC;
+ chains = WL_TX_CHAINS_2;
+ ptr = vhtrate.pwr;
+ vhtptr = NULL;
+ break;
+ case 3:
+ str = "MCS 8~15 ";
+ nss = WL_TX_NSS_2;
+ mode = WL_TX_MODE_NONE;
+ chains = WL_TX_CHAINS_2;
+ ptr = vhtrate.pwr;
+ vhtptr = NULL;
+ break;
+ case 4:
+ case 5:
+ ptr = NULL;
+ vhtptr = NULL;
+ break;
+ case 6:
+ str = "1 Nsts 1 Tx";
+ nss = WL_TX_NSS_1;
+ mode = WL_TX_MODE_NONE;
+ chains = WL_TX_CHAINS_1;
+ ptr = vhtrate.pwr;
+ vhtptr = &vhtrate.pwr[8];
+ break;
+ case 7:
+ str = "1 Nsts 2 Tx";
+ nss = WL_TX_NSS_1;
+ mode = WL_TX_MODE_CDD;
+ chains = WL_TX_CHAINS_2;
+ ptr = vhtrate.pwr;
+ vhtptr = &vhtrate.pwr[8];
+ break;
+ case 8:
+ str = "1 Nsts 3 Tx";
+ nss = WL_TX_NSS_1;
+ mode = WL_TX_MODE_CDD;
+ chains = WL_TX_CHAINS_3;
+ ptr = vhtrate.pwr;
+ vhtptr = &vhtrate.pwr[8];
+ break;
+ case 9:
+ str = "1 Nsts 4 Tx";
+ nss = WL_TX_NSS_1;
+ mode = WL_TX_MODE_CDD;
+ chains = WL_TX_CHAINS_4;
+ ptr = vhtrate.pwr;
+ vhtptr = &vhtrate.pwr[8];
+ break;
+
+ case 10:
+ str = "2 Nsts 2 Tx";
+ nss = WL_TX_NSS_2;
+ mode = WL_TX_MODE_NONE;
+ chains = WL_TX_CHAINS_2;
+ ptr = vhtrate.pwr;
+ vhtptr = &vhtrate.pwr[8];
+ break;
+ case 11:
+ str = "2 Nsts 3 Tx";
+ nss = WL_TX_NSS_2;
+ mode = WL_TX_MODE_NONE;
+ chains = WL_TX_CHAINS_3;
+ ptr = vhtrate.pwr;
+ vhtptr = &vhtrate.pwr[8];
+ break;
+ case 12:
+ str = "2 Nsts 4 Tx";
+ nss = WL_TX_NSS_2;
+ mode = WL_TX_MODE_NONE;
+ chains = WL_TX_CHAINS_4;
+ ptr = vhtrate.pwr;
+ vhtptr = &vhtrate.pwr[8];
+ break;
+ case 13:
+ str = "3 Nsts 3 Tx";
+ nss = WL_TX_NSS_3;
+ mode = WL_TX_MODE_NONE;
+ chains = WL_TX_CHAINS_3;
+ ptr = vhtrate.pwr;
+ vhtptr = &vhtrate.pwr[8];
+ break;
+ case 14:
+ str = "3 Nsts 4 Tx";
+ nss = WL_TX_NSS_3;
+ mode = WL_TX_MODE_NONE;
+ chains = WL_TX_CHAINS_4;
+ ptr = vhtrate.pwr;
+ vhtptr = &vhtrate.pwr[8];
+ break;
+ case 15:
+ str = "4 Nsts 4 Tx";
+ nss = WL_TX_NSS_4;
+ mode = WL_TX_MODE_NONE;
+ chains = WL_TX_CHAINS_4;
+ ptr = vhtrate.pwr;
+ vhtptr = &vhtrate.pwr[8];
+ break;
+ default:
+ ptr = NULL;
+ vhtptr = NULL;
+ break;
+ }
+ if (ptr == NULL)
+ continue;
+ ppr_get_vht_mcs(ppr, bw, nss, mode, chains, &vhtrate);
+ printf("%s ", str);
+ if (vht && vhtptr)
+ rlen = WL_RATESET_SZ_VHT_MCS_P;
+ else
+ rlen = WL_RATESET_SZ_HT_MCS;
+ PRINT_PPR_RATE_LOOP(j, rlen, ptr);
+ printf("\n");
+ }
+}
+
+static int
+wl_get_current_txppr(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ uint flags;
+ chanspec_t chanspec;
+ char chanspec_str[CHANSPEC_STR_LEN];
+ uint pprsize = ppr_ser_size_by_bw(ppr_get_max_bw());
+ wl_txppr_t *wl_txppr;
+ ppr_t *pprptr = NULL;
+
+ wl_txppr = (wl_txppr_t *)malloc(sizeof(*wl_txppr) + pprsize);
+
+ if (wl_txppr == NULL) {
+ fprintf(stderr, "Error allocating memory failed for curppr");
+ return BCME_NOMEM;
+ }
+
+ memset(wl_txppr, 0, sizeof(*wl_txppr));
+ wl_txppr->buflen = pprsize;
+ if ((err = ppr_init_ser_mem_by_bw(wl_txppr->pprbuf, ppr_get_max_bw(), pprsize))
+ != BCME_OK) {
+ free(wl_txppr);
+ return err;
+ }
+
+ if (WLC_IOCTL_MAXLEN < sizeof(wl_txppr_t) + pprsize) {
+ free(wl_txppr);
+ return BCME_ERROR;
+ }
+
+ argv++;
+ if (*argv)
+ fprintf(stderr, "Ignoring arguments for %s\n", cmd->name);
+
+ wl_txppr->ver = WL_TXPPR_VERSION;
+ wl_txppr->len = WL_TXPPR_LENGTH;
+ if ((err = wlu_iovar_getbuf(wl, "curppr", wl_txppr, sizeof(*wl_txppr) + pprsize,
+ buf, WLC_IOCTL_MAXLEN)) < 0) {
+ free(wl_txppr);
+ return err;
+ }
+
+ /* the input buffer is no longer needed, output results are in buf */
+ free(wl_txppr);
+ wl_txppr = (wl_txppr_t *)buf;
+
+ /* parse */
+ wl_txppr->flags = dtoh32(wl_txppr->flags);
+ wl_txppr->chanspec = wl_chspec_from_driver(wl_txppr->chanspec);
+ wl_txppr->local_chanspec = wl_chspec_from_driver(wl_txppr->local_chanspec);
+
+ chanspec = wl_txppr->chanspec;
+ flags = (wl_txppr->flags & WL_TX_POWER_F_VHT) |
+ (wl_txppr->flags & WL_TX_POWER_F_HT) |
+ (wl_txppr->flags & WL_TX_POWER_F_MIMO) |
+ (wl_txppr->flags & WL_TX_POWER_F_SISO);
+
+ /* dump */
+ printf("Current channel:\t %s\n",
+ wf_chspec_ntoa(wl_txppr->chanspec, chanspec_str));
+ printf("BSS channel:\t\t %s\n",
+ wf_chspec_ntoa(wl_txppr->local_chanspec, chanspec_str));
+
+ printf("Power/Rate Dump (in %s): Channel %d\n", (wl_txppr->flags & WL_TX_POWER_F_UNIT_QDBM)?
+ "1/4dB":"1/2dB", CHSPEC_CHANNEL(chanspec));
+ if ((err = ppr_deserialize_create(NULL, wl_txppr->pprbuf, pprsize, &pprptr)) == BCME_OK) {
+ wl_txppr_print(pprptr, CHSPEC_IS2G(chanspec), flags);
+ ppr_delete(NULL, pprptr);
+ }
+ return err;
+}
+
+static int
+wl_txcore_pwr_offset(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_txchain_pwr_offsets_t offsets;
+ char *endptr;
+ int i;
+ long val;
+ int err;
+
+ /* toss the command name */
+ argv++;
+
+ if (!*argv) {
+ err = wlu_iovar_get(wl, cmd->name, &offsets, sizeof(wl_txchain_pwr_offsets_t));
+
+ if (err < 0)
+ return err;
+
+ printf("txcore offsets qdBm: %d %d %d %d\n",
+ offsets.offset[0], offsets.offset[1],
+ offsets.offset[2], offsets.offset[3]);
+
+ return 0;
+ }
+
+ memset(&offsets, 0, sizeof(wl_txchain_pwr_offsets_t));
+
+ for (i = 0; i < WL_NUM_TXCHAIN_MAX; i++, argv++) {
+ if (!*argv)
+ break;
+
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ if (val > 0)
+ return BCME_BADARG;
+
+ offsets.offset[i] = (int8)val;
+ }
+
+ err = wlu_iovar_set(wl, cmd->name, &offsets, sizeof(wl_txchain_pwr_offsets_t));
+
+ return err;
+}
+
+static int
+wl_txcore(void *wl, cmd_t *cmd, char **argv)
+{
+ miniopt_t to;
+ const char* fn_name = "wl_txcore";
+ int err = 0, opt_err, val;
+ uint8 streams = 0;
+ bool streams_set = FALSE;
+ uint8 core = 0;
+ bool core_set = FALSE;
+ uint8 cck_mask = 0;
+ bool cck_set = FALSE;
+ uint8 ofdm_mask = 0;
+ bool ofdm_set = FALSE;
+ uint8 mcs_mask[4] = {0, 0, 0, 0}; /* pre-initialize # of streams {core:4 | stream:4} */
+ bool mcs_set = FALSE;
+ uint8 idx;
+ uint32 coremask[2] = {0, 0};
+
+ /* toss the command name */
+ argv++;
+
+ if (!*argv) {
+ if (cmd->get < 0)
+ return -1;
+ if ((err = wlu_iovar_get(wl, cmd->name, &coremask, sizeof(uint32)*2)) < 0)
+ return err;
+
+ printf("txcore enabled bitmap (Nsts {4..1}) 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ (coremask[0] >> 24) & 0xff, (coremask[0] >> 16) & 0xff,
+ (coremask[0] >> 8) & 0xff, coremask[0] & 0xff);
+ printf("txcore mask OFDM 0x%02x CCK 0x%02x\n",
+ (coremask[1] >> 8) & 0xff, coremask[1] & 0xff);
+ return 0;
+ }
+
+ val = atoi(*argv);
+ if (val == -1)
+ goto next;
+
+ miniopt_init(&to, fn_name, "w", FALSE);
+ while ((opt_err = miniopt(&to, argv)) != -1) {
+ if (opt_err == 1) {
+ err = BCME_USAGE_ERROR;
+ goto exit;
+ }
+ argv += to.consumed;
+
+ if (to.opt == 's') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for streams\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ streams_set = TRUE;
+ streams = (to.val & 0x0f);
+ if (streams > 4)
+ fprintf(stderr, "%s: Nsts > %d\n", fn_name, to.val);
+ }
+ if (to.opt == 'c') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for stf core\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ core_set = TRUE;
+ core = (to.val & 0x0f) << 4;
+ if (core == 0) {
+ fprintf(stderr, "%s: %1d-stream core cannot be zero\n",
+ fn_name, streams);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+ if (to.opt == 'o') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for streams\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ ofdm_set = TRUE;
+ ofdm_mask = (to.val & 0x0f);
+ if (ofdm_mask == 0) {
+ fprintf(stderr, "%s: OFDM core cannot be zero\n", fn_name);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+ if (to.opt == 'k') {
+ if (!to.good_int) {
+ fprintf(stderr,
+ "%s: could not parse \"%s\" as an int for streams\n",
+ fn_name, to.valstr);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ cck_set = TRUE;
+ cck_mask = (to.val & 0x0f);
+ if (cck_mask == 0) {
+ fprintf(stderr, "%s: CCK core cannot be zero\n", fn_name);
+ err = BCME_BADARG;
+ goto exit;
+ }
+ }
+
+ if (streams_set && core_set) {
+ streams_set = core_set = FALSE;
+ mcs_set = TRUE;
+ idx = streams - 1;
+ mcs_mask[idx] = (uint8)(core|streams);
+ }
+ }
+
+ if (streams_set != core_set) {
+ fprintf(stderr, "%s: require to set both -s x -c y\n", fn_name);
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ if (mcs_set) {
+ coremask[0] |= mcs_mask[0] << 0;
+ coremask[0] |= mcs_mask[1] << 8;
+ coremask[0] |= mcs_mask[2] << 16;
+ coremask[0] |= mcs_mask[3] << 24;
+ }
+ if (cck_set)
+ coremask[1] |= cck_mask;
+ if (ofdm_set)
+ coremask[1] |= ofdm_mask << 8;
+next:
+ err = wlu_var_setbuf(wl, cmd->name, coremask, sizeof(uint32)*2);
+exit:
+ return err;
+}
+
+static int
+wl_mimo_stf(void *wl, cmd_t *cmd, char **argv)
+{
+ char var[256];
+ int32 int_val;
+ bool get = TRUE;
+ uint32 len = 0;
+ void *ptr = NULL;
+ char *endptr;
+ int i = 0, j = 0;
+ int ret = 0;
+
+ while (argv[i])
+ i++;
+
+ if (i > 4)
+ return BCME_USAGE_ERROR;
+
+ /* toss the command name */
+ argv++;
+ j = 1;
+
+ if (i == 1) {
+ int_val = -1;
+ memcpy(&var[len], (char *)&int_val, sizeof(int_val));
+ len += sizeof(int_val);
+ }
+ else {
+ if (isdigit((unsigned char)(**argv))) {
+ get = FALSE;
+ int_val = htod32(strtoul(*argv, &endptr, 0));
+ if ((int_val != 0) && (int_val != 1)) {
+ fprintf(stderr, "wl mimo_ss_stf: bad stf mode.\n");
+ return BCME_BADARG;
+ }
+ memcpy(var, (char *)&int_val, sizeof(int_val));
+ len += sizeof(int_val);
+ argv++;
+ j++;
+ }
+
+ if (j == i) {
+ int_val = -1;
+ memcpy(&var[len], (char *)&int_val, sizeof(int_val));
+ len += sizeof(int_val);
+ }
+ else if (!strncmp(*argv, "-b", 2)) {
+ argv++;
+ j++;
+ if (j == i)
+ return BCME_BADARG;
+
+ if (!strcmp(*argv, "a"))
+ int_val = 1;
+ else if (!strcmp(*argv, "b"))
+ int_val = 0;
+ else {
+ fprintf(stderr,
+ "wl mimo_ss_stf: wrong -b option, \"-b a\" or \"-b b\"\n");
+ return BCME_USAGE_ERROR;
+ }
+ j++;
+ if (j < i)
+ return BCME_BADARG;
+ memcpy(&var[len], (char *)&int_val, sizeof(int_val));
+ len += sizeof(int_val);
+ }
+ }
+
+ if (get) {
+ if ((ret = wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr)) < 0)
+ return ret;
+
+ printf("0x%x\n", dtoh32(*(int *)ptr));
+ }
+ else
+ ret = wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
+ return ret;
+}
+
+static int
+wl_spatial_policy(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr = NULL;
+ int err, i, *reply;
+ int mode[SPATIAL_MODE_MAX_IDX] = {-1, -1, -1, -1, -1};
+
+ /* Order is 2G, 5G-LOW, 5G-MID, 5G-HIGH, 5G-UPPER
+ * if only one argument given, than all band or sub-band take the
+ * same value
+ */
+ if (!*++argv) {
+ bool all_same = TRUE;
+ if ((err = wlu_var_getbuf(wl, cmd->name, &mode, sizeof(mode), &ptr)) < 0)
+ return err;
+ reply = (int *)ptr;
+ for (i = 1; i < SPATIAL_MODE_MAX_IDX; i++) {
+ /* check if return values for each band/sub-band is same or not */
+ if (reply[i-1] != reply[i])
+ all_same = FALSE;
+ }
+ if (all_same)
+ printf("%2d\n", reply[0]);
+ else {
+ printf("2.4GHz : %2d\n", reply[SPATIAL_MODE_2G_IDX]);
+ printf("5GHz (lower) : %2d\n", reply[SPATIAL_MODE_5G_LOW_IDX]);
+ printf("5GHz (middle): %2d\n", reply[SPATIAL_MODE_5G_MID_IDX]);
+ printf("5GHz (high) : %2d\n", reply[SPATIAL_MODE_5G_HIGH_IDX]);
+ printf("5GHz (upper) : %2d\n", reply[SPATIAL_MODE_5G_UPPER_IDX]);
+ }
+ return 0;
+ }
+ mode[0] = atoi(*argv);
+ if (!*++argv) {
+ for (i = 1; i < SPATIAL_MODE_MAX_IDX; i++)
+ mode[i] = mode[0];
+ } else {
+ for (i = 1; i < SPATIAL_MODE_MAX_IDX; i++) {
+ mode[i] = atoi(*argv);
+ if (!*++argv && i < (SPATIAL_MODE_MAX_IDX - 1)) {
+ printf("error: missing arguments\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ }
+ err = wlu_var_setbuf(wl, cmd->name, &mode, sizeof(mode));
+ return err;
+}
+
+static int
+wl_ratetbl_ppr(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr = NULL;
+ int err, i, *reply;
+ int val[12];
+
+ /* Order is 2G, 5G-LOW, 5G-MID, 5G-HIGH, 5G-UPPER
+ * if only one argument given, than all band or sub-band take the
+ * same value
+ */
+ memset(&val, 0, sizeof(val));
+ if (!*++argv) {
+ if ((err = wlu_var_getbuf(wl, cmd->name, &val, sizeof(val), &ptr)) < 0)
+ return err;
+ reply = (int *)ptr;
+ for (i = 0; i < 12; i++)
+ printf("%s: %2d\n", (reply[i] & 0x80) ? "OFDM" : "CCK ", (reply[i] & 0x7f));
+ return 0;
+ }
+ val[0] = atoi(*argv++);
+ val[1] = atoi(*argv++);
+ err = wlu_var_setbuf(wl, cmd->name, &val, sizeof(val));
+ return err;
+}
+
+static int
+wl_mimo_ps_learning_cfg(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_mimops_learning_cfg_t mimo_ps_learning_cfg;
+ char *endptr;
+ int i;
+ long val;
+ int err;
+
+ /* toss the command name */
+ argv++;
+ if (!*argv) {
+ err = wl_mimo_ps_learning_cfg_get_status(wl, cmd->name);
+ return err;
+ }
+ memset(&mimo_ps_learning_cfg, 0, sizeof(wl_mimops_learning_cfg_t));
+ for (i = 0; i < WL_MIMO_PS_LEARNING_MAX_PARAMS; i++, argv++) {
+ if (!*argv) {
+ break;
+ }
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ return BCME_BADARG;
+ }
+
+ switch (i) {
+ case 0:
+ if (val == 0)
+ mimo_ps_learning_cfg.flag =
+ (uint8)WL_MIMO_PS_PS_LEARNING_CFG_STATUS;
+ else if (val == 1)
+ mimo_ps_learning_cfg.flag =
+ (uint8)WL_MIMO_PS_PS_LEARNING_CFG_ABORT;
+ else if (val == 2)
+ mimo_ps_learning_cfg.flag =
+ (uint8)WL_MIMO_PS_PS_LEARNING_CFG_CONFIG;
+ else
+ return BCME_BADARG;
+ break;
+ case 1:
+ mimo_ps_learning_cfg.no_of_packets_for_learning = (uint32)val;
+ mimo_ps_learning_cfg.learning_rssi_threshold = 0;
+ break;
+ case 2:
+ mimo_ps_learning_cfg.learning_rssi_threshold = (int8)val;
+ break;
+
+ default:
+ return BCME_BADARG;
+ }
+ }
+ /* At the end get the configuration and display */
+ mimo_ps_learning_cfg.version = WL_MIMO_PS_PS_LEARNING_CFG_V1;
+ err = wlu_iovar_set(wl, cmd->name,
+ (void*)&mimo_ps_learning_cfg, sizeof(wl_mimops_learning_cfg_t));
+ return err;
+}
+
+
+static int
+wl_mimo_ps_learning_cfg_get_status(void *wl, const char *iovar)
+{
+ wl_mimops_learning_cfg_t mimo_ps_learning_data;
+ int err;
+ err = wlu_iovar_get(wl, iovar, &mimo_ps_learning_data, sizeof(wl_mimops_learning_cfg_t));
+ if (err < 0)
+ return err;
+
+ printf("\n Current MIMO PS Learning data :- \n");
+ printf("\t BSSID %s\n",
+ wl_ether_etoa(&mimo_ps_learning_data.mimops_learning_data.BSSID));
+ printf("\t Start time stamp %d\n",
+ mimo_ps_learning_data.mimops_learning_data.startTimeStamp);
+ printf("\t End time stamp %d\n",
+ mimo_ps_learning_data.mimops_learning_data.endTimeStamp);
+ printf("\t Total MIMO above threshold %d\n",
+ mimo_ps_learning_data.mimops_learning_data.totalMIMO_above_rssi_threshold);
+ printf("\t Total MIMO below threshold %d\n",
+ mimo_ps_learning_data.mimops_learning_data.totalMIMO_below_rssi_threshold);
+ printf("\t Total SISO above threshold %d\n",
+ mimo_ps_learning_data.mimops_learning_data.totalSISO_above_rssi_threshold);
+ printf("\t Total SISO below threshold %d\n",
+ mimo_ps_learning_data.mimops_learning_data.totalSISO_below_rssi_threshold);
+ if (mimo_ps_learning_data.version == WL_MIMO_PS_PS_LEARNING_CFG_V1) {
+ printf("\t mimo_ps learning version %d\n",
+ mimo_ps_learning_data.version);
+ printf("\t mimo_ps learning rssi threshold value %d\n",
+ mimo_ps_learning_data.learning_rssi_threshold);
+ }
+ printf("\t mimo_ps no of packets to wait for %d\n",
+ mimo_ps_learning_data.no_of_packets_for_learning);
+ if (mimo_ps_learning_data.mimops_learning_data.reason ==
+ WL_MIMO_PS_PS_LEARNING_ABORTED)
+ printf("\t REASON : MIMO PS LEARNING ABORTED\n");
+ else if (mimo_ps_learning_data.mimops_learning_data.reason ==
+ WL_MIMO_PS_PS_LEARNING_COMPLETED)
+ printf("\t REASON : MIMO PS LEARNING COMPLETED\n");
+ else if (mimo_ps_learning_data.mimops_learning_data.reason ==
+ WL_MIMO_PS_PS_LEARNING_ONGOING)
+ printf("\t REASON : MIMO PS LEARNING IN PRPGRESS\n");
+ else
+ printf("\t REASON : UNKNOWN \n");
+ return err;
+}
+
+static int
+wl_mimo_ps_cfg(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_mimops_cfg_t mimo_ps_cfg;
+ char *endptr;
+ int i;
+ long val;
+ int err;
+
+ /* toss the command name */
+ argv++;
+ if (!*argv) {
+ err = wlu_iovar_get(wl, cmd->name, &mimo_ps_cfg, sizeof(wl_mimops_cfg_t));
+
+ if (err < 0)
+ return err;
+ printf("\n Current MIMO PS CFG :- \n"
+ "\t active chains = %d\n \t mode = %d \n\t bandwidth = %d "
+ "\t apply changes after learning = %d\n",
+ mimo_ps_cfg.active_chains, mimo_ps_cfg.mode, mimo_ps_cfg.bandwidth,
+ mimo_ps_cfg.applychangesafterlearning);
+ return 0;
+ }
+ memset(&mimo_ps_cfg, 0, sizeof(wl_mimops_cfg_t));
+ for (i = 0; i < WL_MIMO_PS_MAX_PARAMS; i++, argv++) {
+ if (!*argv) {
+ break;
+ }
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0') {
+ return BCME_BADARG;
+ }
+
+ switch (i) {
+ case 0:
+ mimo_ps_cfg.active_chains = (int8)val;
+ break;
+ case 1:
+ mimo_ps_cfg.mode = (int8)val;
+ break;
+ case 2:
+ mimo_ps_cfg.bandwidth = (int8)val;
+ break;
+ case 3:
+ mimo_ps_cfg.applychangesafterlearning = (int8) val;
+ break;
+ default:
+ return BCME_BADARG;
+ }
+ }
+ mimo_ps_cfg.version = WL_MIMO_PS_CFG_VERSION_1;
+ err = wlu_iovar_set(wl, cmd->name, (void*)&mimo_ps_cfg, sizeof(wl_mimops_cfg_t));
+ return err;
+}
+
+static int
+wl_mimo_ps_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_mimo_ps_status_t mimo_ps_status;
+
+ /* toss the command name */
+ argv++;
+
+ err = wlu_iovar_get(wl, cmd->name, &mimo_ps_status, sizeof(wl_mimo_ps_status_t));
+ if (err < 0)
+ return err;
+ /* Check version */
+ if ((mimo_ps_status.version != WL_MIMO_PS_STATUS_VERSION_1) &&
+ (mimo_ps_status.version != WL_MIMO_PS_STATUS_VERSION_2) &&
+ (mimo_ps_status.version != WL_MIMO_PS_STATUS_VERSION_3)) {
+ printf("Unexpected version: %u\n", mimo_ps_status.version);
+ return BCME_VERSION;
+ }
+ /* dump */
+ err = wl_mimo_ps_status_dump(&mimo_ps_status);
+ return err;
+}
+
+static const char *mimo_ps_status_state_str_tbl[] = {
+ "STATE_NONE",
+ "INFORM_AP_IN_PROGRESS",
+ "INFORM_AP_DONE",
+ "LEARNING",
+ "HW_CONFIGURE",
+ "INFORM_AP_PENDING"
+};
+
+static const char *mimo_ps_status_bw_str_tbl[] = {
+ "FULL",
+ "20MHz",
+ "40MHz",
+ "80MHz",
+ "160MHz",
+ "8080MHz"
+};
+
+static const char *mimo_ps_status_hw_state_str_tbl[] = {
+ "NONE",
+ "LTE_COEX",
+ "MIMOPS_BSS",
+ "AWDL_BSS",
+ "SCAN",
+ "TXPPR",
+ "PWRTHOTTLE",
+ "TEMPSENSE",
+ "IOVAR",
+ "AP_BSS"
+};
+
+static const char *mimo_ps_status_mhf_flag[] = {
+ "Disabled",
+ "Enabled",
+ "Core Down",
+ "Unsupported"
+};
+
+static int
+wl_mimo_ps_status_dump(wl_mimo_ps_status_t *status)
+{
+ int err = BCME_OK;
+ uint8 ap_cap_bw;
+
+ if (status == NULL)
+ return BCME_ERROR;
+
+ ap_cap_bw = WL_MIMO_PS_STATUS_AP_CAP_BW(status->ap_cap);
+
+ /* AP capability (MIMO,SISO)/BW */
+ printf("AP capability: ");
+ err = wl_mimo_ps_status_assoc_status_dump(WL_MIMO_PS_STATUS_AP_CAP(status->ap_cap));
+ if (ap_cap_bw > (ARRAYSIZE(mimo_ps_status_bw_str_tbl)-1)) {
+ printf("/Invalid BW value=%d\n", ap_cap_bw);
+ err = BCME_BADARG;
+ } else {
+ if (WL_MIMO_PS_STATUS_AP_CAP(status->ap_cap) != WL_MIMO_PS_STATUS_ASSOC_NONE)
+ printf("/%s", mimo_ps_status_bw_str_tbl[ap_cap_bw]);
+ printf("\n");
+ }
+
+ /* Association */
+ printf("Association: ");
+ err = wl_mimo_ps_status_assoc_status_dump(status->association_status &
+ WL_MIMO_PS_STATUS_ASSOC_STATUS_MASK);
+ if (status->association_status & WL_MIMO_PS_STATUS_ASSOC_STATUS_VHT_WITHOUT_OMN)
+ printf("\t(AP without OMN)");
+ printf("\n");
+
+ /* mimo_ps_cfg state */
+ printf("MIMO PS state: ");
+ if (status->mimo_ps_state > (ARRAYSIZE(mimo_ps_status_state_str_tbl)-1)) {
+ printf("\tInvalid MIMO PS state=%d\n", status->mimo_ps_state);
+ err = BCME_BADARG;
+ } else {
+ printf("\t%s\n", mimo_ps_status_state_str_tbl[status->mimo_ps_state]);
+ }
+
+ /* mrc_state */
+ printf("MRC state: ");
+ if (status->mrc_state == WL_MIMO_PS_STATUS_MRC_NONE)
+ printf("\tNot active\n");
+ else if (status->mrc_state == WL_MIMO_PS_STATUS_MRC_ACTIVE)
+ printf("\tACTIVE\n");
+ else {
+ printf("\tInvalid MRC state\n");
+ err = BCME_BADARG;
+ }
+ /* bss information */
+ printf("bss_rxchain:\t0x%02x\n", status->bss_rxchain);
+ printf("bss_txchain:\t0x%02x\n", status->bss_txchain);
+ printf("bss_bw: ");
+ if (status->bss_bw > (ARRAYSIZE(mimo_ps_status_bw_str_tbl)-1)) {
+ printf("\tInvalid bandwidth value=%d\n", status->bss_bw);
+ err = BCME_BADARG;
+ } else
+ printf("\t%s\n", mimo_ps_status_bw_str_tbl[status->bss_bw]);
+
+ /* hw_state */
+ wl_mimo_ps_status_hw_state_dump(status->hw_state);
+
+ /* hw information */
+ printf("hw_rxchain:\t0x%02x\n", status->hw_rxchain);
+ printf("hw_txchain:\t0x%02x\n", status->hw_txchain);
+ printf("hw_bw: ");
+ if (status->hw_bw > (ARRAYSIZE(mimo_ps_status_bw_str_tbl)-1)) {
+ printf("\tInvalid bandwidth value=%d\n", status->hw_bw);
+ err = BCME_BADARG;
+ } else
+ printf("\t\t%s\n", mimo_ps_status_bw_str_tbl[status->hw_bw]);
+
+ if (status->version == WL_MIMO_PS_STATUS_VERSION_1)
+ return err;
+
+ printf("PM_BCNRX state: ");
+ if (status->pm_bcnrx_state > (ARRAYSIZE(mimo_ps_status_mhf_flag) - 1)) {
+ printf("\tInvalid value %d\n", status->pm_bcnrx_state);
+ } else {
+ printf("\t%s\n", mimo_ps_status_mhf_flag[status->pm_bcnrx_state]);
+ }
+
+ printf("SISO_BCMC_RX state: ");
+ if (status->siso_bcmc_rx_state > (ARRAYSIZE(mimo_ps_status_mhf_flag) - 1)) {
+ printf("\tInvalid value %d\n", status->siso_bcmc_rx_state);
+ } else {
+ char *astr = "";
+ if (status->siso_bcmc_rx_state == WL_MIMO_PS_STATUS_MHF_FLAG_ACTIVE) {
+ if ((status->pm_bcnrx_state == WL_MIMO_PS_STATUS_MHF_FLAG_NONE) ||
+ (status->pm_bcnrx_state == WL_MIMO_PS_STATUS_MHF_FLAG_INVALID))
+ astr = " (Inactive)";
+ else if (status->pm_bcnrx_state == WL_MIMO_PS_STATUS_MHF_FLAG_ACTIVE)
+ astr = " (Active)";
+ }
+ printf("\t%s%s\n", mimo_ps_status_mhf_flag[status->siso_bcmc_rx_state], astr);
+ }
+
+ printf("BSSBasicRateSet: %s\n", (status->basic_rates_present ? "Yes" : "No"));
+
+ return err;
+}
+
+static void
+wl_mimo_ps_status_hw_state_dump(uint16 hw_state)
+{
+ uint i, n;
+
+ printf("HW state: \t0x%04x\n", hw_state);
+ if (hw_state == 0) {
+ printf("\t\t%s\n", mimo_ps_status_hw_state_str_tbl[hw_state]);
+ return;
+ }
+ n = MIN(ARRAYSIZE(mimo_ps_status_hw_state_str_tbl), NBITS(hw_state));
+ for (i = 0; i < n; i++) {
+ if (hw_state & (0x1 << (i-1))) {
+ printf("\t\t%s\n", mimo_ps_status_hw_state_str_tbl[i]);
+ }
+ }
+}
+
+static int
+wl_mimo_ps_status_assoc_status_dump(uint8 assoc_status)
+{
+ switch (assoc_status) {
+ case WL_MIMO_PS_STATUS_ASSOC_NONE:
+ printf("\tNot associated");
+ break;
+ case WL_MIMO_PS_STATUS_ASSOC_SISO:
+ printf("\tSISO");
+ break;
+ case WL_MIMO_PS_STATUS_ASSOC_MIMO:
+ printf("\tMIMO");
+ break;
+ case WL_MIMO_PS_STATUS_ASSOC_LEGACY:
+ printf("\tLEGACY");
+ break;
+ default:
+ printf("Invalid AP cap/association status\n");
+ break;
+ }
+ return BCME_OK;
+}
+
+static int
+wl_temp_throttle_control(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_temp_control_t temp_control;
+ char *endptr;
+ long val;
+ int err;
+
+ memset(&temp_control, 0, sizeof(wl_temp_control_t));
+
+ if (!*++argv) {
+ /* Get */
+ err = wlu_iovar_get(wl, cmd->name, &temp_control, sizeof(wl_temp_control_t));
+
+ if (err < 0) {
+ return err;
+ }
+
+ if (temp_control.enable == 0) {
+ printf("Temp control is off\n");
+ return BCME_OK;
+ }
+
+ printf("Current mode : 0x%x\n", temp_control.control_bit);
+ return BCME_OK;
+ } else {
+ /* Enable / Disable */
+ val = atoi(*argv);
+ temp_control.enable = val;
+ argv++;
+
+ if (temp_control.enable == 1) {
+ if (!*argv) {
+ return BCME_ERROR;
+ }
+
+ val = strtol(*argv, &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ if (val > 0xFF) {
+ printf("Out of range\n");
+ return BCME_OUTOFRANGECHAN;
+ }
+
+ temp_control.control_bit = val;
+ }
+
+ err = wlu_iovar_set(wl, cmd->name, &temp_control, sizeof(wl_temp_control_t));
+
+ return err;
+ }
+}
+static int
+wl_ocl_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = BCME_OK;
+ ocl_status_info_t ocl_status;
+
+ /* toss the command name */
+ argv++;
+
+ err = wlu_iovar_get(wl, cmd->name, &ocl_status, sizeof(ocl_status));
+ if (err < 0)
+ return err;
+ /* Check version */
+ if (ocl_status.version != WL_OCL_STATUS_VERSION) {
+ printf("Unexpected version: %u\n", ocl_status.version);
+ return BCME_VERSION;
+ }
+ /* validate length */
+ if (ocl_status.len < (uint8) sizeof(ocl_status)) {
+ fprintf(stderr, "OCL Status: short len %d < %d\n",
+ ocl_status.len, (int)sizeof(ocl_status));
+ return BCME_ERROR;
+ }
+ /* dump fw/hw state */
+ wl_ocl_status_fw_dump(ocl_status.fw_status);
+ wl_ocl_status_hw_dump(ocl_status.hw_status);
+ printf("OCL Coremask : 0x%02x (Core-%d)\n",
+ ocl_status.coremask, ocl_status.coremask-1);
+
+ return err;
+}
+
+static const char *ocl_status_fw_state_str_tbl[] = {
+ "HOST",
+ "RSSI",
+ "LTEC",
+ "SISO",
+ "CAL",
+ "CHAN",
+ "ASPND"
+};
+static const char *ocl_status_hw_state_str_tbl[] = {
+ "OCL",
+ "MIMO",
+ "", "", "", "", "",
+ "Core Down"
+};
+
+static void
+wl_ocl_status_fw_dump(uint16 fw_state)
+{
+ uint i, n;
+ bool first = TRUE;
+
+ printf("FW Disable Reason : 0x%04x (", fw_state);
+ if (fw_state == 0) {
+ printf("%s)\n", "NONE");
+ return;
+ }
+ n = MIN(ARRAYSIZE(ocl_status_fw_state_str_tbl), NBITS(fw_state));
+ for (i = 0; i < n; i++) {
+ if (fw_state & (0x1 << (i))) {
+ printf("%s%s", first ? "": ", ", ocl_status_fw_state_str_tbl[i]);
+ first = FALSE;
+ }
+ }
+ printf(")\n");
+}
+
+static void
+wl_ocl_status_hw_dump(uint8 hw_state)
+{
+ uint i, n;
+ bool first = TRUE;
+
+ printf("HW Status Bits : 0x%02x ", hw_state);
+ n = MIN(ARRAYSIZE(ocl_status_hw_state_str_tbl), NBITS(hw_state));
+ for (i = 0; i < n; i++) {
+ if (hw_state & (0x1 << (i))) {
+ printf("%s%s", first ? "(": ", ", ocl_status_hw_state_str_tbl[i]);
+ first = FALSE;
+ }
+ }
+ printf("%s\n", hw_state ? ")" : "");
+}
diff --git a/wl/src/wl/exe/wluc_tbow.c b/wl/src/wl/exe/wluc_tbow.c
new file mode 100644
index 0000000..fc41684
--- /dev/null
+++ b/wl/src/wl/exe/wluc_tbow.c
@@ -0,0 +1,164 @@
+/*
+ * wl tbow command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_tbow.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+#ifdef LINUX
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* LINUX */
+
+static cmd_func_t wl_tbow_doho;
+
+static cmd_t wl_tbow_cmds[] = {
+ { "tbow_doho", wl_tbow_doho, -1, WLC_SET_VAR,
+ "Trigger the BT-WiFi handover/handback"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_tbow_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register tbow commands */
+ wl_module_cmds_register(wl_tbow_cmds);
+}
+
+static int
+wl_tbow_doho(void *wl, cmd_t *cmd, char **argv)
+{
+ tbow_setup_netinfo_t netinfo;
+ char ssid_buf[TBOW_MAX_SSID_LEN + 1];
+ char passph[TBOW_MAX_PASSPHRASE_LEN + 1];
+
+ if (!*++argv) {
+ printf("wl tbow_doho <opmode> <chanspec> <ssid> <passphrase> <go_ifaddr>\n");
+ return -1;
+ }
+
+ netinfo.version = WL_TBOW_SETUPINFO_T_VERSION;
+ netinfo.opmode = atoi(*argv++);
+ switch (netinfo.opmode) {
+ case TBOW_HO_MODE_START_GO: /* Start GO */
+ case TBOW_HO_MODE_START_STA: /* Start STA */
+ case TBOW_HO_MODE_START_GC: /* Start GC */
+ netinfo.chanspec = wf_chspec_aton(*argv++);
+ printf("Chanspec: 0x%x\n", netinfo.chanspec);
+
+ if (!*argv) {
+ printf("SSID is not given\n");
+ return -1;
+ }
+ netinfo.ssid_len = strlen(*argv);
+ if (netinfo.ssid_len > TBOW_MAX_SSID_LEN) {
+ printf("Too long SSID: %d bytes\n", netinfo.ssid_len);
+ return -1;
+ }
+ memcpy(netinfo.ssid, *argv, netinfo.ssid_len);
+ memcpy(ssid_buf, *argv, netinfo.ssid_len);
+ ssid_buf[netinfo.ssid_len] = 0;
+ printf("SSID: %s\n", ssid_buf);
+
+ ++argv;
+ if (!*argv) {
+ printf("Passphrase is not given\n");
+ return -1;
+ }
+ netinfo.passphrase_len = strlen(*argv);
+ if (netinfo.passphrase_len > TBOW_MAX_PASSPHRASE_LEN) {
+ printf("Too long passphrase: %d bytes\n", netinfo.passphrase_len);
+ return -1;
+ }
+ memcpy(netinfo.passphrase, *argv, netinfo.passphrase_len);
+ memcpy(passph, *argv, netinfo.passphrase_len);
+ passph[netinfo.passphrase_len] = 0;
+ printf("PASSPHRASE: %s\n", passph);
+
+ /* Start GO */
+ if (netinfo.opmode == TBOW_HO_MODE_START_GO ||
+ netinfo.opmode == TBOW_HO_MODE_START_GC) {
+ ++argv;
+ if (!*argv) {
+ printf("MAC address is not given for GO/GC\n");
+ return -1;
+ }
+ if (!wl_ether_atoe(*argv, (struct ether_addr *)&netinfo.macaddr)) {
+ printf(" ERROR: no valid ether addr provided\n");
+ return -1;
+ }
+ if (netinfo.opmode == TBOW_HO_MODE_START_GO)
+ printf("Own MAC ADDRESS: %s\n",
+ wl_ether_etoa((struct ether_addr *)&netinfo.macaddr));
+ else
+ printf("GO BSSID: %s\n",
+ wl_ether_etoa((struct ether_addr *)&netinfo.macaddr));
+ }
+ break;
+
+ case TBOW_HO_MODE_STOP_GO:
+ case TBOW_HO_MODE_STOP_GC:
+ case TBOW_HO_MODE_STOP_STA:
+ case TBOW_HO_MODE_TEST_GO:
+ case TBOW_HO_MODE_TEARDOWN:
+ break;
+
+ default:
+ printf("Invalid opmode: %d\n", netinfo.opmode);
+ return -1;
+ }
+
+ return wlu_iovar_set(wl, cmd->name, &netinfo, sizeof(netinfo));
+}
diff --git a/wl/src/wl/exe/wluc_tdls.c b/wl/src/wl/exe/wluc_tdls.c
new file mode 100644
index 0000000..00e1720
--- /dev/null
+++ b/wl/src/wl/exe/wluc_tdls.c
@@ -0,0 +1,600 @@
+/*
+ * wl tdls command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_tdls.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_tdls_endpoint;
+static cmd_func_t wl_tdls_wfd_ie;
+
+static cmd_t wl_tdls_cmds[] = {
+ { "tdls_endpoint", wl_tdls_endpoint, WLC_GET_VAR, WLC_SET_VAR,
+ "Available TDLS operations to each TDLS peer.\n"
+ "\tusage: wl tdls_endpoint <disc, create, delete, PM, wake, cw> <ea> [chanspec]\n"
+ "\t [chanspec] only applies to 'cw' operaton.\n\n"
+ "\t addendum:\n"
+ "\t wl tdls_endpoint wfd_disc <ea> sends a WFD tunneled Probe Request"},
+ { "tdls_wfd_ie", wl_tdls_wfd_ie, WLC_GET_VAR, -1,
+ "To set, get and clear additional WFD IE in setup_req and setup_resp\n"
+ "\tTo set2, get2 and clear2 additional WFD IE in tunneled probe_req and probe_resp\n"
+ "\tusage: wl tdls_wfd_ie get <own|peer_eth_addr#> [ip] [port]\n"
+ "\t wl tdls_wfd_ie get2 <own|peer_eth_addr#> [alt_mac] [port] [PC_bit]\n"
+ "\t\t peer_eth_addr#: HH:HH:HH:HH:HH:HH\n"
+ "\t\t and peer must be TDLS connected (only in case of setup)\n\n"
+ "\t wl tdls_wfd_ie <clr|clr2> own\n\n"
+ "\t wl tdls_wfd_ie set own wfd_ie_hexa_string [ip# [port# [type# [bssid#]]]]\n"
+ "\t wl tdls_wfd_ie set2 own wfd_ie_hexa_string [alt_mac# [port# [type#]]]\n"
+ "\t\t wfd_ie_hexa_string: should start with the full WFD IE header\n"
+ "\t\t e.g. 0xDDXX506F9A0A...\n"
+ "\t\t ip#: XXX.XXX.XXX.XXX\n"
+ "\t\t alt_mac#: HH:HH:HH:HH:HH:HH\n"
+ "\t\t port#: 0-65535\n"
+ "\t\t type#: 0 for source, 1 for primary sink\n"
+ "\t\t bssid#: HH:HH:HH:HH:HH:HH"},
+ { "tdls_sta_info", wl_sta_info, WLC_GET_VAR, -1,
+ "wl tdls_sta_info <xx:xx:xx:xx:xx:xx>"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_tdls_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register tdls commands */
+ wl_module_cmds_register(wl_tdls_cmds);
+}
+
+static int
+wl_tdls_endpoint(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname_tdls = "tdls_endpoint";
+ tdls_iovar_t info;
+ chanspec_t chanspec;
+
+ if (strcmp(cmd->name, cmdname_tdls)) {
+ printf("error: invalid command name.\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ memset(&info, 0, sizeof(tdls_iovar_t));
+
+ if (!strcmp("create", *argv))
+ info.mode = TDLS_MANUAL_EP_CREATE;
+ else if (!strcmp("modify", *argv))
+ info.mode = TDLS_MANUAL_EP_MODIFY;
+ else if (!strcmp("delete", *argv))
+ info.mode = TDLS_MANUAL_EP_DELETE;
+ else if (!strcmp("PM", *argv))
+ info.mode = TDLS_MANUAL_EP_PM;
+ else if (!strcmp("wake", *argv))
+ info.mode = TDLS_MANUAL_EP_WAKE;
+ else if (!strcmp("disc", *argv))
+ info.mode = TDLS_MANUAL_EP_DISCOVERY;
+ else if (!strcmp("cw", *argv)) {
+ info.mode = TDLS_MANUAL_EP_CHSW;
+ }
+ else if (!strcmp("wfd_disc", *argv))
+ info.mode = TDLS_MANUAL_EP_WFD_TPQ;
+ else {
+ printf("error: invalid mode string\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+ if (!*argv) {
+ printf("error: missing ea\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!wl_ether_atoe(*argv, &info.ea)) {
+ printf("error: could not parse MAC address %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ if (info.mode == TDLS_MANUAL_EP_CHSW) {
+ argv++;
+ if (!*argv) {
+ printf("error: missing target channel number\n");
+ return BCME_USAGE_ERROR;
+ }
+ if (atoi(*argv) != 0) {
+ chanspec = wf_chspec_aton(*argv);
+ if (chanspec == 0) {
+ printf("error: bad chanspec \"%s\".\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+ chanspec = wl_chspec_to_driver(chanspec);
+ if (chanspec == INVCHANSPEC) {
+ return BCME_USAGE_ERROR;
+ }
+ info.chanspec = chanspec;
+ }
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info));
+}
+
+
+#define WFD_DEV 0
+#define WFD_DEV_LEN 6
+#define WFD_IP 8
+#define WFD_IP_LEN 5
+#define WFD_ALT_MAC 10
+#define WFD_ALT_MAC_LEN 6
+
+static int
+wl_tdls_wfd_ie(void *wl, cmd_t *cmd, char **argv)
+{
+ const char *cmdname_tdls = "tdls_wfd_ie";
+ tdls_wfd_ie_iovar_t info;
+ tdls_wfd_ie_iovar_t* buf_info = (tdls_wfd_ie_iovar_t*) buf;
+ int ret;
+ uint8* ptr;
+ uint8 element, subelement = 0;
+ uint16 offset;
+ uint8 buffer[TDLS_WFD_IE_SIZE - (WFA_OUI_LEN + 3)];
+ uint16 length, element_length, current_length;
+ bcm_tlv_t * ie;
+ unsigned long value;
+ struct ether_addr ea;
+ struct ipv4_addr ipa_set;
+
+ if (strcmp(cmd->name, cmdname_tdls)) {
+ printf("error: invalid command name.\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ if (!strcmp(*argv, "clr")) {
+ memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ if (!strcmp("own", *argv))
+ info.mode = TDLS_WFD_IE_TX;
+ else {
+ printf("error: invalid mode string\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info));
+
+ } else if (!strcmp(*argv, "get")) {
+ memset(buf_info, 0, sizeof(*buf_info));
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ if (!strcmp("own", *argv))
+ buf_info->mode = TDLS_WFD_IE_TX;
+ else if (wl_ether_atoe(*argv, &buf_info->ea))
+ buf_info->mode = TDLS_WFD_IE_RX;
+ else {
+ printf("error: invalid mode string\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, buf_info,
+ sizeof(*buf_info), buf, WLC_IOCTL_MAXLEN)) < 0) {
+ return ret;
+ }
+
+ /* empty */
+ if (!buf_info->length)
+ return ret;
+
+ if (!*++argv)
+ wl_hexdump((uchar *)buf_info->data, buf_info->length);
+ else {
+ if (!strcmp("ip", *argv)) {
+ element = WFD_IP;
+ element_length = WFD_IP_LEN;
+ } else if (!strcmp("port", *argv)) {
+ element = WFD_DEV;
+ element_length = WFD_DEV_LEN;
+ } else {
+ printf("error: unknown element\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Reassemble the WFD IE (without header) */
+
+ ptr = buf_info->data;
+ length = buf_info->length;
+ offset = 0;
+ current_length = 0;
+
+ while (length - offset > WFA_OUI_LEN + 3) {
+ if ((ie = bcm_parse_tlvs(ptr + offset,
+ length - offset, DOT11_MNG_VS_ID)) != NULL) {
+ if (ie->len > WFA_OUI_LEN + 1) {
+ if ((!memcmp(ie->data, WFA_OUI, WFA_OUI_LEN)) &&
+ (*(ie->data + WFA_OUI_LEN) ==
+ WFA_OUI_TYPE_WFD)) {
+ /* WFD */
+ memcpy(buffer + current_length,
+ ie->data + WFA_OUI_LEN + 1,
+ ie->len - WFA_OUI_LEN - 1);
+ current_length += ie->len - WFA_OUI_LEN - 1;
+ }
+ }
+ offset = (uint16)((uint8*)ie - ptr + ie->len + 2);
+ }
+ else
+ break;
+ }
+
+ /* Find the elements */
+
+ ptr = buffer;
+ length = current_length;
+
+ while (length > 3) {
+ current_length = (ptr[1] << 8) + ptr[2];
+ if ((ptr[0] == element) && (current_length == element_length) &&
+ (current_length <= length - 3)) {
+
+ switch (element) {
+ case WFD_IP:
+ /* we do not care about the IP version i.e. ptr[3] */
+ printf("%u.%u.%u.%u\n", ptr[4], ptr[5], ptr[6], ptr[7]);
+ break;
+
+ case WFD_DEV:
+ /* just get the RTSP TCP valid port */
+ printf("%u\n", (ptr[5] << 8) + ptr[6]);
+ break;
+ }
+ break;
+
+ } else {
+ if (current_length + 3 < length) {
+ length -= current_length + 3;
+ ptr += current_length + 3;
+ } else
+ break;
+ }
+ }
+ }
+
+ return ret;
+
+ } else if (!strcmp(*argv, "set")) {
+ memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ if (!strcmp("own", *argv))
+ info.mode = TDLS_WFD_IE_TX;
+ else {
+ printf("error: invalid mode string\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+ if (!*argv) {
+ printf("error: missing IE string\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (strlen((char*)*argv) - 2 > sizeof(info.data) * 2) {
+ printf("error: IE string too long; max is %u bytes\n",
+ (unsigned int)sizeof(info.data));
+ return BCME_BADARG;
+ }
+
+ ret = wl_pattern_atoh(*argv, (char*)info.data);
+
+ if (ret <= 0) {
+ printf("error: could not parse IE string address %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ info.length = ret;
+
+ if (*++argv) {
+ /* IP specified */
+
+ /* watchdog */
+ if (info.length != 32) {
+ printf(
+ "if one or several set fields are used, "
+ "the following the IE string must be\n"
+ "exactly 32 bytes and must have the following order:\n"
+ "\t6-byte header (0xDD1E506F9A0A)\n"
+ "\t9-byte subelement 0 (WFD device information)\n"
+ "\t9-byte subelement 1 (BSSID)\n"
+ "\t8-byte subelement 8 (IP address)\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!wl_atoip(*argv, &ipa_set))
+ return BCME_USAGE_ERROR;
+
+ memcpy(&info.data[28], (uint8*) &ipa_set, sizeof(ipa_set));
+
+ if (*++argv) {
+ /* port specified */
+
+ value = strtoul(*argv, NULL, 0);
+ info.data[11] = (uint8) (0xFF & (value >> 8));
+ info.data[12] = (uint8) (0xFF & value);
+
+ if (*++argv) {
+ /* WFD type (Source or Primary Sink) specified */
+
+ element = (uint8) (0x01 & strtoul(*argv, NULL, 0));
+ if (element)
+ info.data[10] |= 0x01;
+ else
+ info.data[10] &= ~0x01;
+
+ if (*++argv) {
+ /* BSSID specified */
+
+ if (!wl_ether_atoe(*argv, &ea))
+ return BCME_USAGE_ERROR;
+
+ memcpy(&info.data[18], (uint8*) &ea, sizeof(ea));
+ }
+ }
+ }
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info));
+
+ } else if (!strcmp(*argv, "clr2")) {
+ memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ if (!strcmp("own", *argv))
+ info.mode = TDLS_WFD_PROBE_IE_TX;
+ else {
+ printf("error: invalid mode string\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info));
+
+ } else if (!strcmp(*argv, "get2")) {
+ memset(buf_info, 0, sizeof(*buf_info));
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ if (!strcmp("own", *argv))
+ buf_info->mode = TDLS_WFD_PROBE_IE_TX;
+ else if (wl_ether_atoe(*argv, &buf_info->ea))
+ buf_info->mode = TDLS_WFD_PROBE_IE_RX;
+ else {
+ printf("error: invalid mode string\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((ret = wlu_iovar_getbuf(wl, cmd->name, buf_info,
+ sizeof(*buf_info), buf, WLC_IOCTL_MAXLEN)) < 0) {
+ return ret;
+ }
+
+ /* empty */
+ if (!buf_info->length)
+ return ret;
+
+ if (!*++argv)
+ wl_hexdump((uchar *)buf_info->data, buf_info->length);
+
+ else {
+ if (!strcmp("alt_mac", *argv)) {
+ element = WFD_ALT_MAC;
+ element_length = WFD_ALT_MAC_LEN;
+ } else if (!strcmp("port", *argv)) {
+ element = WFD_DEV;
+ element_length = WFD_DEV_LEN;
+ subelement = 1;
+ } else if (!strcmp("PC_bit", *argv)) {
+ element = WFD_DEV;
+ element_length = WFD_DEV_LEN;
+ subelement = 0;
+ } else {
+ printf("error: unknown element\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Reassemble the WFD IE (without header) */
+
+ ptr = buf_info->data;
+ length = buf_info->length;
+ offset = 0;
+ current_length = 0;
+
+ while (length - offset > WFA_OUI_LEN + 3) {
+ if ((ie = bcm_parse_tlvs(ptr + offset,
+ length - offset, DOT11_MNG_VS_ID)) != NULL) {
+ if (ie->len > WFA_OUI_LEN + 1) {
+ if ((!memcmp(ie->data, WFA_OUI, WFA_OUI_LEN)) &&
+ (*(ie->data + WFA_OUI_LEN) ==
+ WFA_OUI_TYPE_WFD)) {
+ /* WFD */
+ memcpy(buffer + current_length,
+ ie->data + WFA_OUI_LEN + 1,
+ ie->len - WFA_OUI_LEN - 1);
+ current_length += ie->len - WFA_OUI_LEN - 1;
+ }
+ }
+ offset = (uint16)((uint8*)ie - ptr + ie->len + 2);
+ }
+ else
+ break;
+ }
+
+ /* Find the elements */
+
+ ptr = buffer;
+ length = current_length;
+
+ while (length > 3) {
+ current_length = (ptr[1] << 8) + ptr[2];
+ if ((ptr[0] == element) && (current_length == element_length) &&
+ (current_length <= length - 3)) {
+
+ switch (element) {
+ case WFD_ALT_MAC:
+ printf("%02X:%02X:%02X:%02X:%02X:%02X\n",
+ ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8]);
+ break;
+ case WFD_DEV:
+ if (subelement)
+ /* just get the RTSP TCP valid port */
+ printf("%u\n", (ptr[5] << 8) + ptr[6]);
+ else
+ /* just get the Preferred Connection bit */
+ printf("%u\n", ptr[4] >> 7);
+ break;
+ }
+ break;
+
+ } else {
+ if (current_length + 3 < length) {
+ length -= current_length + 3;
+ ptr += current_length + 3;
+ } else
+ break;
+ }
+ }
+ }
+
+ return ret;
+
+ } else if (!strcmp(*argv, "set2")) {
+ memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
+
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ if (!strcmp("own", *argv))
+ info.mode = TDLS_WFD_PROBE_IE_TX;
+ else {
+ printf("error: invalid mode string\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ argv++;
+ if (!*argv) {
+ printf("error: missing IE string\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (strlen((char*)*argv) - 2 > sizeof(info.data) * 2) {
+ printf("error: IE string too long; max is %u bytes\n",
+ (unsigned int)sizeof(info.data));
+ return BCME_USAGE_ERROR;
+ }
+
+ ret = wl_pattern_atoh(*argv, (char*)info.data);
+
+ if (ret <= 0) {
+ printf("error: could not parse IE string address %s\n", *argv);
+ return BCME_USAGE_ERROR;
+ }
+
+ info.length = ret;
+
+ if (*++argv) {
+ /* alt MAC specified */
+
+ /* watchdog */
+ if (info.length != 24) {
+ printf(
+ "if one or several set2 fields are used, "
+ "the following the IE string must be\n"
+ "exactly 24 bytes and must have the following order:\n"
+ "\t6-byte header (0xDD16506F9A0A)\n"
+ "\t9-byte subelement 0 (WFD device information)\n"
+ "\t9-byte subelement 10 (alternate MAC address)\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!wl_ether_atoe(*argv, &ea))
+ return BCME_USAGE_ERROR;
+ memcpy(&info.data[18], (uint8*) &ea, sizeof(ea));
+
+ if (*++argv) {
+ /* port specified */
+
+ value = strtoul(*argv, NULL, 0);
+ info.data[11] = (uint8) (0xFF & (value >> 8));
+ info.data[12] = (uint8) (0xFF & value);
+
+ if (*++argv) {
+ /* WFD type (Source or Primary Sink) specified */
+
+ element = (uint8) (0x01 & strtoul(*argv, NULL, 0));
+ if (element)
+ info.data[10] |= 0x01;
+ else
+ info.data[10] &= ~0x01;
+ }
+ }
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info));
+
+ } else {
+ printf("error: unknown operation\n");
+ return BCME_USAGE_ERROR;
+ }
+}
diff --git a/wl/src/wl/exe/wluc_tko.c b/wl/src/wl/exe/wluc_tko.c
new file mode 100644
index 0000000..b8de37b
--- /dev/null
+++ b/wl/src/wl/exe/wluc_tko.c
@@ -0,0 +1,908 @@
+/*
+ * wl tko command module - TCP Keepalive Offload
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id:$
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+#if defined(linux)
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#endif /* linux */
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+#include <sys/stat.h>
+#include <errno.h>
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <proto/802.3.h>
+#include <proto/bcmip.h>
+#include <proto/bcmipv6.h>
+#include <proto/bcmtcp.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_tko;
+#if defined(linux)
+static cmd_func_t wl_tko_auto_config;
+static cmd_func_t wl_tko_event_check;
+#endif /* linux */
+
+static cmd_t wl_tko_cmds[] = {
+ { "tko", wl_tko, WLC_GET_VAR, WLC_SET_VAR,
+ "TCP keepalive offload subcommands:\n"
+ "\ttko max_tcp\n"
+ "\ttko param <interval> <retry interval> <retry count>\n"
+ "\ttko connect <index> [<ip_addr_type> <src MAC> <dst MAC>\n"
+ "<src IP> <dst IP> <src port> <dst port>\n"
+ "<seq num> <ack num> <TCP window>]\n"
+ "\ttko enable <0|1>\n"
+ "\ttko status\n"},
+#if defined(linux)
+ { "tko_auto_config", wl_tko_auto_config, -1, WLC_SET_VAR,
+ "Listens for TCP and automatically configures TKO.\n"},
+ { "tko_event_check", wl_tko_event_check, -1, WLC_SET_VAR,
+ "Listens for TKO event.\n"},
+#endif /* linux */
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_tko_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register tko commands */
+ wl_module_cmds_register(wl_tko_cmds);
+}
+
+/* encode IPv6 TCP keepalive packet
+ * input 'buf' size = (ETHER_HDR_LEN + sizeof(struct ipv6_hdr) +
+ * sizeof(struct bcmtcp_hdr))
+ * returns the size of the encoded packet
+ */
+static int
+wl_ipv6_tcp_keepalive_pkt(uint8 *buf,
+ struct ether_addr *daddr, struct ether_addr *saddr,
+ struct ipv6_addr *dipv6addr, struct ipv6_addr *sipv6addr,
+ uint16 sport, uint16 dport, uint32 seq, uint32 ack, uint16 tcpwin)
+{
+ struct ether_header *eth;
+ struct ipv6_hdr *ipv6;
+ struct bcmtcp_hdr *tcp;
+
+ if (buf == NULL) {
+ return 0;
+ }
+
+ /* encode ethernet header */
+ eth = (struct ether_header *)buf;
+ memcpy(eth->ether_dhost, daddr, ETHER_ADDR_LEN);
+ memcpy(eth->ether_shost, saddr, ETHER_ADDR_LEN);
+ eth->ether_type = hton16(ETHER_TYPE_IPV6);
+
+ /* encode IPv6 header */
+ ipv6 = (struct ipv6_hdr *)(buf + sizeof(struct ether_header));
+ memset(ipv6, 0, sizeof(*ipv6));
+ ipv6->version = IPV6_VERSION;
+ ipv6->payload_len = hton16(sizeof(struct bcmtcp_hdr));
+ ipv6->nexthdr = IP_PROT_TCP;
+ ipv6->hop_limit = IPV6_HOP_LIMIT;
+ memcpy(&ipv6->daddr, dipv6addr, sizeof(ipv6->daddr));
+ memcpy(&ipv6->saddr, sipv6addr, sizeof(ipv6->saddr));
+
+ /* encode TCP header */
+ tcp = (struct bcmtcp_hdr *)(buf + sizeof(struct ether_header) + sizeof(struct ipv6_hdr));
+ memset(tcp, 0, sizeof(*tcp));
+ tcp->src_port = hton16(sport);
+ tcp->dst_port = hton16(dport);
+ tcp->seq_num = hton32(seq);
+ tcp->ack_num = hton32(ack);
+ tcp->tcpwin = hton16(tcpwin);
+ tcp->chksum = 0;
+ tcp->urg_ptr = 0;
+ tcp->hdrlen_rsvd_flags = (TCP_FLAG_ACK << 8) |
+ ((sizeof(struct bcmtcp_hdr) >> 2) << TCP_HDRLEN_SHIFT);
+
+ /* calculate checksum */
+ tcp->chksum = ipv6_tcp_hdr_cksum((uint8 *)ipv6, (uint8 *)tcp, sizeof(*tcp));
+
+ return (sizeof(struct ether_header) + sizeof(struct ipv6_hdr) +
+ sizeof(struct bcmtcp_hdr));
+}
+
+/* encode TCP keepalive packet
+ * input 'buf' size = (ETHER_HDR_LEN + sizeof(struct ipv4_hdr) +
+ * sizeof(struct bcmtcp_hdr))
+ * returns the size of the encoded packet
+ */
+static int
+wl_tcp_keepalive_pkt(uint8 *buf,
+ struct ether_addr *daddr, struct ether_addr *saddr,
+ struct ipv4_addr *dipaddr, struct ipv4_addr *sipaddr,
+ uint16 sport, uint16 dport, uint32 seq, uint32 ack, uint16 tcpwin)
+{
+ struct ether_header *eth;
+ struct ipv4_hdr *ip;
+ struct bcmtcp_hdr *tcp;
+
+ if (buf == NULL) {
+ return 0;
+ }
+ eth = (struct ether_header *)buf;
+ memcpy(eth->ether_dhost, daddr, ETHER_ADDR_LEN);
+ memcpy(eth->ether_shost, saddr, ETHER_ADDR_LEN);
+ eth->ether_type = hton16(ETHER_TYPE_IP);
+ ip = (struct ipv4_hdr *)(buf + sizeof(struct ether_header));
+ memcpy(ip->dst_ip, dipaddr, IPV4_ADDR_LEN);
+ memcpy(ip->src_ip, sipaddr, IPV4_ADDR_LEN);
+ ip->version_ihl = (IP_VER_4 << IPV4_VER_SHIFT) | (IPV4_MIN_HEADER_LEN / 4);
+ ip->tos = 0;
+ ip->tot_len = hton16(sizeof(struct ipv4_hdr) + sizeof(struct bcmtcp_hdr));
+ ip->id = hton16(0);
+ ip->frag = 0;
+ ip->ttl = 32;
+ ip->prot = IP_PROT_TCP;
+ ip->hdr_chksum = 0;
+ ip->hdr_chksum = ipv4_hdr_cksum((uint8 *)ip, IPV4_HLEN(ip));
+ tcp = (struct bcmtcp_hdr *)(buf + sizeof(struct ether_header) +
+ sizeof(struct ipv4_hdr));
+ tcp->src_port = hton16(sport);
+ tcp->dst_port = hton16(dport);
+ tcp->seq_num = hton32(seq);
+ tcp->ack_num = hton32(ack);
+ tcp->tcpwin = hton16(tcpwin);
+ tcp->chksum = 0;
+ tcp->urg_ptr = 0;
+ tcp->hdrlen_rsvd_flags = (TCP_FLAG_ACK << 8) |
+ ((sizeof(struct bcmtcp_hdr) >> 2) << TCP_HDRLEN_SHIFT);
+
+ /* calculate TCP header checksum */
+ tcp->chksum = ipv4_tcp_hdr_cksum((uint8 *)ip, (uint8 *)tcp, sizeof(*tcp));
+
+ return (sizeof(struct ether_header) + sizeof(struct ipv4_hdr) +
+ sizeof(struct bcmtcp_hdr));
+}
+
+/* intialize TKO connect struct and returns the length of connect struct */
+static int
+wl_tko_connect_init(wl_tko_connect_t *connect, uint8 index, uint8 ip_addr_type,
+ struct ether_addr *saddr, struct ether_addr *daddr, void *sipaddr, void *dipaddr,
+ uint16 local_port, uint16 remote_port, uint32 local_seq, uint32 remote_seq, uint16 tcpwin)
+{
+ int data_len = 0;
+
+ connect->index = index;
+ connect->ip_addr_type = ip_addr_type;
+ connect->local_port = htod16(local_port);
+ connect->remote_port = htod16(remote_port);
+ connect->local_seq = htod32(local_seq);
+ connect->remote_seq = htod32(remote_seq);
+
+ if (ip_addr_type) {
+ /* IPv6 */
+ struct ipv6_addr *sipv6addr = sipaddr;
+ struct ipv6_addr *dipv6addr = dipaddr;
+
+ memcpy(&connect->data[data_len], sipv6addr, sizeof(*sipv6addr));
+ data_len += sizeof(*sipv6addr);
+ memcpy(&connect->data[data_len], dipv6addr, sizeof(*dipv6addr));
+ data_len += sizeof(*dipv6addr);
+ /* IPv6 TCP keepalive request */
+ connect->request_len = wl_ipv6_tcp_keepalive_pkt(
+ &connect->data[data_len], daddr, saddr,
+ dipv6addr, sipv6addr, local_port, remote_port,
+ local_seq - 1, remote_seq, tcpwin);
+ data_len += connect->request_len;
+ /* IPv6 TCP keepalive response */
+ connect->response_len = wl_ipv6_tcp_keepalive_pkt(
+ &connect->data[data_len], daddr, saddr,
+ dipv6addr, sipv6addr, local_port, remote_port,
+ local_seq, remote_seq, tcpwin);
+ data_len += connect->response_len;
+ } else {
+ /* IPv4 */
+ struct ipv4_addr *sipv4addr = sipaddr;
+ struct ipv4_addr *dipv4addr = dipaddr;
+
+ memcpy(&connect->data[data_len], sipv4addr, sizeof(*sipv4addr));
+ data_len += sizeof(*sipv4addr);
+ memcpy(&connect->data[data_len], dipv4addr, sizeof(*dipv4addr));
+ data_len += sizeof(*dipv4addr);
+ /* TCP keepalive request */
+ connect->request_len = wl_tcp_keepalive_pkt(
+ &connect->data[data_len], daddr, saddr,
+ dipv4addr, sipv4addr, local_port, remote_port,
+ local_seq - 1, remote_seq, tcpwin);
+ data_len += connect->request_len;
+ /* TCP keepalive response */
+ connect->response_len = wl_tcp_keepalive_pkt(
+ &connect->data[data_len], daddr, saddr,
+ dipv4addr, sipv4addr, local_port, remote_port,
+ local_seq, remote_seq, tcpwin);
+ data_len += connect->response_len;
+ }
+
+ return (OFFSETOF(wl_tko_connect_t, data) + data_len);
+}
+
+static int
+wl_tko(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1;
+ char *subcmd;
+ int subcmd_len;
+
+ /* skip iovar */
+ argv++;
+
+ /* must have subcommand */
+ subcmd = *argv++;
+ if (!subcmd) {
+ return BCME_USAGE_ERROR;
+ }
+ subcmd_len = strlen(subcmd);
+
+ /* GET for "connect" has 1 parameter */
+ if ((!*argv && strncmp(subcmd, "connect", subcmd_len)) ||
+ (!strncmp(subcmd, "connect", subcmd_len) && argv[0] && !argv[1])) {
+ /* get */
+ uint8 buffer[OFFSETOF(wl_tko_t, data) + sizeof(wl_tko_get_connect_t)];
+ wl_tko_t *tko = (wl_tko_t *)buffer;
+ int len = OFFSETOF(wl_tko_t, data);
+
+ memset(tko, 0, len);
+ if (!strncmp(subcmd, "max_tcp", subcmd_len)) {
+ tko->subcmd_id = WL_TKO_SUBCMD_MAX_TCP;
+ } else if (!strncmp(subcmd, "param", subcmd_len)) {
+ tko->subcmd_id = WL_TKO_SUBCMD_PARAM;
+ } else if (!strncmp(subcmd, "connect", subcmd_len)) {
+ wl_tko_get_connect_t *get_connect = (wl_tko_get_connect_t *)tko->data;
+ tko->subcmd_id = WL_TKO_SUBCMD_CONNECT;
+ tko->len = sizeof(*get_connect);
+ get_connect->index = atoi(argv[0]);
+ } else if (!strncmp(subcmd, "enable", subcmd_len)) {
+ tko->subcmd_id = WL_TKO_SUBCMD_ENABLE;
+ } else if (!strncmp(subcmd, "status", subcmd_len)) {
+ tko->subcmd_id = WL_TKO_SUBCMD_STATUS;
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+ len += tko->len;
+
+ /* invoke GET iovar */
+ tko->subcmd_id = htod16(tko->subcmd_id);
+ tko->len = htod16(tko->len);
+ if ((err = wlu_iovar_getbuf(wl, cmd->name, tko, len, buf, WLC_IOCTL_MEDLEN)) < 0) {
+ return err;
+ }
+
+ /* process and print GET results */
+ tko = (wl_tko_t *)buf;
+ tko->subcmd_id = dtoh16(tko->subcmd_id);
+ tko->len = dtoh16(tko->len);
+
+ switch (tko->subcmd_id) {
+ case WL_TKO_SUBCMD_MAX_TCP:
+ {
+ wl_tko_max_tcp_t *max_tcp =
+ (wl_tko_max_tcp_t *)tko->data;
+ if (tko->len >= sizeof(*max_tcp)) {
+ printf("max TCP: %d\n", max_tcp->max);
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+
+ }
+ case WL_TKO_SUBCMD_PARAM:
+ {
+ wl_tko_param_t *param = (wl_tko_param_t *)tko->data;
+ if (tko->len >= sizeof(*param)) {
+ param->interval = dtoh16(param->interval);
+ param->retry_interval = dtoh16(param->retry_interval);
+ param->retry_count = dtoh16(param->retry_count);
+ printf("interval: %d\n", param->interval);
+ printf("retry interval: %d\n", param->retry_interval);
+ printf("retry count: %d\n", param->retry_count);
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ case WL_TKO_SUBCMD_CONNECT:
+ {
+ wl_tko_connect_t *connect = (wl_tko_connect_t *)tko->data;
+ if (tko->len >= sizeof(*connect)) {
+ connect->local_port = dtoh16(connect->local_port);
+ connect->remote_port = dtoh16(connect->remote_port);
+ connect->local_seq = dtoh32(connect->local_seq);
+ connect->remote_seq = dtoh32(connect->remote_seq);
+ printf("index: %d\n", connect->index);
+ printf("IP addr type: %d\n", connect->ip_addr_type);
+ printf("local port: %u\n", connect->local_port);
+ printf("remote port: %u\n", connect->remote_port);
+ printf("local seq: %u\n", connect->local_seq);
+ printf("remote seq: %u\n", connect->remote_seq);
+ if (connect->ip_addr_type) {
+ /* IPv6 */
+ printf("src IPv6: %s\n",
+ wl_ipv6toa((struct ipv6_addr *)&connect->data[0]));
+ printf("dst IPv6: %s\n",
+ wl_ipv6toa((struct ipv6_addr *)
+ &connect->data[IPV6_ADDR_LEN]));
+ printf("IPv6 TCP keepalive request\n");
+ wl_hexdump(&connect->data[2 * IPV6_ADDR_LEN],
+ connect->request_len);
+ printf("IPv6 TCP keepalive response\n");
+ wl_hexdump(&connect->data[2 * IPV6_ADDR_LEN +
+ connect->request_len], connect->response_len);
+ } else {
+ /* IPv4 */
+ printf("src IP: %s\n",
+ wl_iptoa((struct ipv4_addr *)&connect->data[0]));
+ printf("dst IP: %s\n",
+ wl_iptoa((struct ipv4_addr *)
+ &connect->data[IPV4_ADDR_LEN]));
+ printf("TCP keepalive request\n");
+ wl_hexdump(&connect->data[2 * IPV4_ADDR_LEN],
+ connect->request_len);
+ printf("TCP keepalive response\n");
+ wl_hexdump(&connect->data[2 * IPV4_ADDR_LEN +
+ connect->request_len], connect->response_len);
+ }
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ case WL_TKO_SUBCMD_ENABLE:
+ {
+ wl_tko_enable_t *tko_enable = (wl_tko_enable_t *)tko->data;
+ if (tko->len >= sizeof(*tko_enable)) {
+ printf("%d\n", tko_enable->enable);
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ case WL_TKO_SUBCMD_STATUS:
+ {
+ wl_tko_status_t *tko_status = (wl_tko_status_t *)tko->data;
+ if (tko->len >= sizeof(*tko_status)) {
+ int i;
+ for (i = 0; i < tko_status->count; i++) {
+ uint8 status = tko_status->status[i];
+ printf("%d: %s\n", i,
+ status == TKO_STATUS_NORMAL ? "normal" :
+ status == TKO_STATUS_NO_RESPONSE ? "no response" :
+ status == TKO_STATUS_NO_TCP_ACK_FLAG ? "no TCP ACK flag" :
+ status == TKO_STATUS_UNEXPECT_TCP_FLAG ?
+ "unexpected TCP flag" :
+ status == TKO_STATUS_SEQ_NUM_INVALID ? "seq num invalid" :
+ status == TKO_STATUS_REMOTE_SEQ_NUM_INVALID ?
+ "remote seq num invalid" :
+ status == TKO_STATUS_TCP_DATA ? "TCP data" :
+ status == TKO_STATUS_UNAVAILABLE ? "unavailable" :
+ "unknown");
+ }
+ } else {
+ err = BCME_BADLEN;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ else {
+ /* set */
+ wl_tko_t *tko = (wl_tko_t *)buf;
+ int len;
+
+ if (!strncmp(subcmd, "param", subcmd_len) &&
+ argv[0] && argv[1] && argv[2]) {
+ wl_tko_param_t *param =
+ (wl_tko_param_t *)tko->data;
+ tko->subcmd_id = WL_TKO_SUBCMD_PARAM;
+ tko->len = sizeof(*param);
+ param->interval = htod16(atoi(argv[0]));
+ param->retry_interval = htod16(atoi(argv[1]));
+ param->retry_count = htod16(atoi(argv[2]));
+ } else if (!strncmp(subcmd, "connect", subcmd_len) &&
+ argv[0] && argv[1] && argv[2] && argv[3] && argv[4] &&
+ argv[5] && argv[6] && argv[7] && argv[8] && argv[9] && argv[10]) {
+ wl_tko_connect_t *connect = (wl_tko_connect_t *)tko->data;
+ uint8 index;
+ uint8 ip_addr_type;
+ struct ether_addr saddr;
+ struct ether_addr daddr;
+ struct ipv4_addr sipaddr;
+ struct ipv4_addr dipaddr;
+ struct ipv6_addr sipv6addr;
+ struct ipv6_addr dipv6addr;
+ uint16 local_port;
+ uint16 remote_port;
+ uint32 local_seq;
+ uint32 remote_seq;
+ uint16 tcpwin;
+
+ index = atoi(argv[0]);
+ ip_addr_type = atoi(argv[1]);
+ if (!wl_ether_atoe(argv[2], &saddr)) {
+ return BCME_USAGE_ERROR;
+ }
+ if (!wl_ether_atoe(argv[3], &daddr)) {
+ return BCME_USAGE_ERROR;
+ }
+ if (ip_addr_type) {
+ /* IPv6 */
+ if (!wl_atoipv6(argv[4], &sipv6addr)) {
+ return BCME_USAGE_ERROR;
+ }
+ if (!wl_atoipv6(argv[5], &dipv6addr)) {
+ return BCME_USAGE_ERROR;
+ }
+ } else {
+ /* IPv4 */
+ if (!wl_atoip(argv[4], &sipaddr)) {
+ return BCME_USAGE_ERROR;
+ }
+ if (!wl_atoip(argv[5], &dipaddr)) {
+ return BCME_USAGE_ERROR;
+ }
+ }
+ local_port = atoi(argv[6]);
+ remote_port = atoi(argv[7]);
+ local_seq = bcm_strtoul(argv[8], NULL, 0);
+ remote_seq = bcm_strtoul(argv[9], NULL, 0);
+ tcpwin = atoi(argv[10]);
+
+ tko->subcmd_id = WL_TKO_SUBCMD_CONNECT;
+ tko->len = wl_tko_connect_init(connect, index, ip_addr_type,
+ &saddr, &daddr,
+ ip_addr_type ? (void *)&sipv6addr : (void *)&sipaddr,
+ ip_addr_type ? (void *)&dipv6addr : (void *)&dipaddr,
+ local_port, remote_port, local_seq, remote_seq, tcpwin);
+
+ } else if (!strncmp(subcmd, "enable", subcmd_len) &&
+ (!strcmp(argv[0], "0") || !strcmp(argv[0], "1"))) {
+ wl_tko_enable_t *tko_enable = (wl_tko_enable_t *)tko->data;
+ tko->subcmd_id = WL_TKO_SUBCMD_ENABLE;
+ tko->len = sizeof(*tko_enable);
+ tko_enable->enable = atoi(argv[0]);
+
+ } else {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* invoke SET iovar */
+ len = OFFSETOF(wl_tko_t, data) + tko->len;
+ tko->subcmd_id = htod16(tko->subcmd_id);
+ tko->len = htod16(tko->len);
+ err = wlu_iovar_set(wl, cmd->name, tko, len);
+ }
+
+ return err;
+}
+
+#if defined(linux)
+
+#define ETH_P_ALL 0x0003
+#define TKO_BUFFER_SIZE 2048
+#define TKO_TCP_WINDOW_SIZE 400
+
+/* automatically configures TKO by monitoring TCP connections */
+static int
+wl_tko_auto_config(void *wl, cmd_t *cmd, char **argv)
+{
+ /* 802.3 llc/snap header */
+ static const uint8 llc_snap_hdr[SNAP_HDR_LEN] =
+ {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+ bool is_checksum = TRUE;
+ int err;
+ int fd = -1;
+ int i;
+ wl_tko_t *tko;
+ wl_tko_max_tcp_t *tko_max;
+ uint8 cur_tcp = 0;
+ uint8 max_tcp = 0;
+ uint8 **tko_buf = NULL;
+ uint8 *frame = NULL;
+ struct ether_addr ea;
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+ char ifnames[IFNAMSIZ] = {"eth1"};
+
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+ if (*argv) {
+ if (!stricmp(*argv, "-nochecksum")) {
+ /* note: ssh on FC15 has TCP checksum failures on packets read
+ * from socket but checksum correct over-the-air
+ */
+ printf("no checksum check\n");
+ is_checksum = FALSE;
+ }
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ if (wl) {
+ strncpy(ifr.ifr_name, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
+ } else {
+ strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
+ }
+
+ if ((err = wlu_iovar_get(wl, "cur_etheraddr", &ea, ETHER_ADDR_LEN)) < 0) {
+ printf("Failed to get current ether address\n");
+ goto exit;
+ }
+
+ fd = socket(PF_PACKET, SOCK_RAW, hton16(ETH_P_ALL));
+ if (fd < 0) {
+ printf("Cannot create socket %d\n", fd);
+ err = -1;
+ goto exit;
+ }
+
+ err = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (err < 0) {
+ printf("Cannot get index %d\n", err);
+ goto exit;
+ }
+
+ /* bind the socket first before starting so we won't miss any event */
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = hton16(ETH_P_ALL);
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (err < 0) {
+ printf("Cannot bind %d\n", err);
+ goto exit;
+ }
+
+ /* get the max TCP connections supported */
+ tko = (wl_tko_t *)buf;
+ memset(tko, 0, sizeof(*tko));
+ tko->subcmd_id = htod16(WL_TKO_SUBCMD_MAX_TCP);
+ tko->len = htod16(tko->len);
+ if ((err = wlu_iovar_getbuf(wl, "tko", tko, sizeof(*tko), buf, WLC_IOCTL_SMLEN)) < 0) {
+ goto exit;
+ }
+ tko = (wl_tko_t *)buf;
+ tko_max = (wl_tko_max_tcp_t *)tko->data;
+ max_tcp = tko_max->max;
+
+ /* allocate TKO buffers */
+ tko_buf = (uint8 **)malloc(sizeof(uint8 *) * max_tcp);
+ if (tko_buf == NULL) {
+ printf("Cannot not allocate %d bytes for TKO buffer\n",
+ (int)(sizeof(uint8 *) * max_tcp));
+ err = BCME_NOMEM;
+ goto exit;
+ }
+ for (i = 0; i < max_tcp; i++) {
+ int size = OFFSETOF(wl_tko_t, data) + OFFSETOF(wl_tko_connect_t, data) + 1024;
+ tko_buf[i] = malloc(size);
+ if (tko_buf[i] == NULL) {
+ printf("Cannot not allocate %d bytes for TKO buffer\n", size);
+ err = BCME_NOMEM;
+ goto exit;
+ }
+ memset(tko_buf[i], 0, size);
+ }
+
+ /* frame buffer */
+ frame = (uint8 *)malloc(TKO_BUFFER_SIZE);
+ if (frame == NULL) {
+ printf("Cannot not allocate %d bytes for receive buffer\n",
+ TKO_BUFFER_SIZE);
+ err = BCME_NOMEM;
+ goto exit;
+ }
+
+ /* receive result */
+ while (1) {
+ int length;
+ uint8 *end, *pt;
+ uint16 ethertype;
+ struct bcmtcp_hdr *tcp_hdr = NULL;
+ uint16 tcp_len = 0;
+ uint8 ip_addr_type = 0;
+ uint8 *src_ip = NULL;
+ uint8 *dst_ip = NULL;
+
+ length = recv(fd, frame, TKO_BUFFER_SIZE, 0);
+ end = frame + length;
+
+ if (length < ETHER_HDR_LEN) {
+ continue;
+ }
+
+ /* process only tx'ed packets */
+ if (memcmp(ea.octet, &frame[ETHER_SRC_OFFSET], sizeof(ea)) != 0) {
+ continue;
+ }
+
+ /* process Ethernet II or SNAP-encapsulated 802.3 frames */
+ if (ntoh16_ua((const void *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) {
+ /* Frame is Ethernet II */
+ pt = frame + ETHER_TYPE_OFFSET;
+ } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN &&
+ !memcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) {
+ pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN;
+ } else {
+ continue;
+ }
+
+ ethertype = ntoh16_ua((const void *)pt);
+ pt += ETHER_TYPE_LEN;
+
+ /* check ethertype */
+ if ((ethertype != ETHER_TYPE_IP) && (ethertype != ETHER_TYPE_IPV6)) {
+ continue;
+ }
+
+ if (ethertype == ETHER_TYPE_IP) {
+ struct ipv4_hdr *ipv4_hdr;
+ uint16 iphdr_len;
+ uint16 cksum;
+
+ ipv4_hdr = (struct ipv4_hdr *)pt;
+ iphdr_len = IPV4_HLEN(ipv4_hdr);
+ if (pt + iphdr_len > end) {
+ continue;
+ }
+ pt += iphdr_len;
+
+ if (ipv4_hdr->prot != IP_PROT_TCP) {
+ continue;
+ }
+
+ if (ntoh16(ipv4_hdr->frag) & IPV4_FRAG_OFFSET_MASK) {
+ continue;
+ }
+
+ if (ntoh16(ipv4_hdr->frag) & IPV4_FRAG_MORE) {
+ continue;
+ }
+
+ tcp_len = ntoh16(ipv4_hdr->tot_len) - iphdr_len;
+ if (pt + tcp_len > end) {
+ continue;
+ }
+ tcp_hdr = (struct bcmtcp_hdr *)pt;
+
+ /* verify IP header checksum */
+ cksum = ipv4_hdr_cksum((uint8 *)ipv4_hdr, iphdr_len);
+ if (cksum != ipv4_hdr->hdr_chksum) {
+ continue;
+ }
+
+ /* verify TCP header checksum */
+ if (is_checksum) {
+ cksum = ipv4_tcp_hdr_cksum((uint8 *)ipv4_hdr,
+ (uint8 *)tcp_hdr, tcp_len);
+ if (cksum != tcp_hdr->chksum) {
+ printf("TCP checksum failed: 0x%04x 0x%04x\n",
+ ntoh16(cksum), ntoh16(tcp_hdr->chksum));
+ continue;
+ }
+ }
+
+ ip_addr_type = 0;
+ src_ip = ipv4_hdr->src_ip;
+ dst_ip = ipv4_hdr->dst_ip;
+
+ } else if (ethertype == ETHER_TYPE_IPV6) {
+ struct ipv6_hdr *ipv6_hdr;
+ uint16 cksum;
+
+ if (pt + sizeof(struct ipv6_hdr) > end) {
+ continue;
+ }
+ ipv6_hdr = (struct ipv6_hdr *)pt;
+ pt += sizeof(struct ipv6_hdr);
+
+ if (ipv6_hdr->nexthdr != IP_PROT_TCP) {
+ continue;
+ }
+
+ tcp_len = ntoh16(ipv6_hdr->payload_len);
+ if (pt + tcp_len > end) {
+ continue;
+ }
+ tcp_hdr = (struct bcmtcp_hdr *)pt;
+
+ /* verify TCP checksum */
+ if (is_checksum) {
+ cksum = ipv6_tcp_hdr_cksum((uint8 *)ipv6_hdr,
+ (uint8 *)tcp_hdr, tcp_len);
+ if (cksum != tcp_hdr->chksum) {
+ printf("IPv6 TCP checksum failed: 0x%04x 0x%04x\n",
+ ntoh16(cksum), ntoh16(tcp_hdr->chksum));
+ continue;
+ }
+ }
+
+ ip_addr_type = 1;
+ src_ip = ipv6_hdr->saddr.addr;
+ dst_ip = ipv6_hdr->daddr.addr;
+ }
+
+ if (src_ip != NULL && dst_ip != NULL && tcp_hdr != NULL) {
+ uint16 src_port = ntoh16(tcp_hdr->src_port);
+ uint16 dst_port = ntoh16(tcp_hdr->dst_port);
+ uint32 seq_num = ntoh32(tcp_hdr->seq_num);
+ uint32 ack_num = ntoh32(tcp_hdr->ack_num);
+ uint8 tcp_flags[2];
+ uint16 tcp_data_len;
+ wl_tko_connect_t *connect;
+ uint8 index;
+ int len;
+
+ /* find existing TCP connection */
+ for (i = 0; i < cur_tcp; i++) {
+ int ip_addr_size = ip_addr_type ? sizeof(struct ipv6_addr) :
+ sizeof(struct ipv4_addr);
+
+ tko = (wl_tko_t *)tko_buf[i];
+ connect = (wl_tko_connect_t *)tko->data;
+
+ /* existing TCP connection if src/dst IP and ports match */
+ if (connect->ip_addr_type == ip_addr_type &&
+ memcmp(src_ip, &connect->data[0], ip_addr_size) == 0 &&
+ memcmp(dst_ip, &connect->data[ip_addr_size],
+ ip_addr_size) == 0 &&
+ connect->local_port == src_port &&
+ connect->remote_port == dst_port) {
+ /* found existing TCP connection */
+ index = connect->index;
+ break;
+ }
+ }
+ /* TCP connection not found */
+ if (i == cur_tcp) {
+ if (cur_tcp < max_tcp) {
+ /* new TCP connection */
+ index = cur_tcp;
+ cur_tcp++;
+ } else {
+ /* no more */
+ printf("max TCP connections supported %d\n", max_tcp);
+ continue;
+ }
+ }
+
+ /* TCP data length */
+ memcpy(tcp_flags, &tcp_hdr->hdrlen_rsvd_flags, sizeof(tcp_flags));
+ tcp_data_len = tcp_len - (TCP_HDRLEN(tcp_flags[0]) << 2);
+ if (tcp_data_len != 0) {
+ printf("TCP data len=%d\n", tcp_data_len);
+ }
+
+ /* adjust the sequence num with the TCP data length */
+ seq_num += tcp_data_len;
+
+ printf("index: %d\n", index);
+ if (ip_addr_type) {
+ /* IPv6 */
+ printf("src IPv6: %s\n",
+ wl_ipv6toa((struct ipv6_addr *)src_ip));
+ printf("dst IPv6: %s\n",
+ wl_ipv6toa((struct ipv6_addr *)dst_ip));
+ } else {
+ /* IPv4 */
+ printf("src IP: %s\n",
+ wl_iptoa((struct ipv4_addr *)src_ip));
+ printf("dst IP: %s\n",
+ wl_iptoa((struct ipv4_addr *)dst_ip));
+ }
+ printf("local port: %u\n", src_port);
+ printf("remote port: %u\n", dst_port);
+ printf("local seq: %u\n", seq_num);
+ printf("remote seq: %u\n", ack_num);
+
+ tko = (wl_tko_t *)tko_buf[index];
+ connect = (wl_tko_connect_t *)tko->data;
+
+ tko->len = wl_tko_connect_init(connect, index, ip_addr_type,
+ (struct ether_addr *)&frame[ETHER_SRC_OFFSET],
+ (struct ether_addr *)&frame[ETHER_DEST_OFFSET],
+ src_ip, dst_ip, src_port, dst_port, seq_num,
+ ack_num, TKO_TCP_WINDOW_SIZE);
+
+ /* invoke SET iovar */
+ tko->subcmd_id = WL_TKO_SUBCMD_CONNECT;
+ len = OFFSETOF(wl_tko_t, data) + tko->len;
+ tko->subcmd_id = htod16(tko->subcmd_id);
+ tko->len = htod16(tko->len);
+ err = wlu_iovar_set(wl, "tko", tko, len);
+ if (err < 0) {
+ printf("TKO connect failed\n");
+ break;
+ }
+ }
+ }
+
+exit:
+ if (tko_buf != NULL) {
+ for (i = 0; i < max_tcp; i++) {
+ if (tko_buf[i] != NULL) {
+ free(tko_buf[i]);
+ }
+ }
+ free(tko_buf);
+ }
+ if (frame != NULL) {
+ free(frame);
+ }
+ if (fd >= 0) {
+ close(fd);
+ }
+ return err;
+}
+
+static void
+wl_tko_event_cb(int event_type, bcm_event_t *bcm_event)
+{
+ wl_event_tko_t *data = (wl_event_tko_t *) (bcm_event + 1);
+
+ if (event_type == WLC_E_TKO) {
+ printf("WLC_E_TKO(%d): status=%d index=%d\n",
+ WLC_E_TKO, ntoh32(bcm_event->event.status), data->index);
+ }
+}
+
+static int
+wl_tko_event_check(void *wl, cmd_t *cmd, char **argv)
+{
+ if (argv[1] && argv[1][0] == '-') {
+ wl_cmd_usage(stderr, cmd);
+ return -1;
+ }
+ return wl_wait_for_event(wl, argv, WLC_E_TKO, 256, wl_tko_event_cb);
+}
+
+#endif /* linux */
diff --git a/wl/src/wl/exe/wluc_toe.c b/wl/src/wl/exe/wluc_toe.c
new file mode 100644
index 0000000..ffa3f11
--- /dev/null
+++ b/wl/src/wl/exe/wluc_toe.c
@@ -0,0 +1,106 @@
+/*
+ * wl toe command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_toe.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_toe_stats;
+
+static cmd_t wl_toe_cmds[] = {
+ { "toe_ol", wl_offload_cmpnt, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set tcpip offload components"},
+ { "toe_stats", wl_toe_stats, WLC_GET_VAR, -1,
+ "Display checksum offload statistics"},
+ { "toe_stats_clear", wl_var_void, -1, WLC_SET_VAR,
+ "Clear checksum offload statistics"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_toe_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register toe commands */
+ wl_module_cmds_register(wl_toe_cmds);
+}
+
+static int
+wl_toe_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ struct toe_ol_stats_t *toestats;
+
+ if (!*++argv) {
+ /* Get */
+ void *ptr = NULL;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+ toestats = (struct toe_ol_stats_t *)ptr;
+ printf("tx_summed = %d\n", dtoh32(toestats->tx_summed));
+ printf("tx_iph_fill = %d\n", dtoh32(toestats->tx_iph_fill));
+ printf("tx_tcp_fill = %d\n", dtoh32(toestats->tx_tcp_fill));
+ printf("tx_udp_fill = %d\n", dtoh32(toestats->tx_udp_fill));
+ printf("tx_icmp_fill = %d\n", dtoh32(toestats->tx_icmp_fill));
+ printf("rx_iph_good = %d\n", dtoh32(toestats->rx_iph_good));
+ printf("rx_iph_bad = %d\n", dtoh32(toestats->rx_iph_bad));
+ printf("rx_tcp_good = %d\n", dtoh32(toestats->rx_tcp_good));
+ printf("rx_tcp_bad = %d\n", dtoh32(toestats->rx_tcp_bad));
+ printf("rx_udp_good = %d\n", dtoh32(toestats->rx_udp_good));
+ printf("rx_udp_bad = %d\n", dtoh32(toestats->rx_udp_bad));
+ printf("rx_icmp_good = %d\n", dtoh32(toestats->rx_icmp_good));
+ printf("rx_icmp_bad = %d\n", dtoh32(toestats->rx_icmp_bad));
+ printf("tx_tcp_errinj = %d\n", dtoh32(toestats->tx_tcp_errinj));
+ printf("tx_udp_errinj = %d\n", dtoh32(toestats->tx_udp_errinj));
+ printf("tx_icmp_errinj = %d\n", dtoh32(toestats->tx_icmp_errinj));
+ printf("rx_tcp_errinj = %d\n", dtoh32(toestats->rx_tcp_errinj));
+ printf("rx_udp_errinj = %d\n", dtoh32(toestats->rx_udp_errinj));
+ printf("rx_icmp_errinj = %d\n", dtoh32(toestats->rx_icmp_errinj));
+ } else
+ printf("Cannot set toe stats, use 'wl toe_stats_clear' to clear the counters\n");
+
+ return 0;
+}
diff --git a/wl/src/wl/exe/wluc_tpc.c b/wl/src/wl/exe/wluc_tpc.c
new file mode 100644
index 0000000..70db77b
--- /dev/null
+++ b/wl/src/wl/exe/wluc_tpc.c
@@ -0,0 +1,93 @@
+/*
+ * wl tpc command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_tpc.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_tpc_lm;
+
+static cmd_t wl_tpc_cmds[] = {
+ { "tpc_mode", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/disable AP TPC.\n"
+ "Usage: wl tpc_mode <mode> \n"
+ "\t0 - disable, 1 - BSS power control, 2 - AP power control, 3 - Both (1) and (2)"},
+ { "tpc_period", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Set AP TPC periodicity in secs.\n"
+ "Usage: wl tpc_period <secs> "},
+ { "tpc_lm", wl_tpc_lm, WLC_GET_VAR, -1,
+ "Get current link margins."},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_tpc_module_init(void)
+{
+ (void)g_swap;
+
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register tpc commands */
+ wl_module_cmds_register(wl_tpc_cmds);
+}
+
+static int
+wl_tpc_lm(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ uint16 val;
+ int8 aplm, stalm;
+
+ UNUSED_PARAMETER(argv);
+
+ if ((ret = wlu_iovar_getint(wl, cmd->name, (int *)(uintptr)&val)) < 0)
+ return ret;
+
+ stalm = val & 0xff;
+ aplm = (val >> 8) & 0xff;
+
+ printf("TPC: APs link margin:%d\t STAs link margin:%d\n", aplm, stalm);
+
+ return 0;
+}
diff --git a/wl/src/wl/exe/wluc_traffic_mgmt.c b/wl/src/wl/exe/wluc_traffic_mgmt.c
new file mode 100644
index 0000000..af0c78d
--- /dev/null
+++ b/wl/src/wl/exe/wluc_traffic_mgmt.c
@@ -0,0 +1,1011 @@
+/*
+ * wl traffic_mgmt command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_traffic_mgmt.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_trf_mgmt_config;
+static cmd_func_t wl_trf_mgmt_filters_add;
+static cmd_func_t wl_trf_mgmt_filters_addex;
+static cmd_func_t wl_trf_mgmt_filters_remove;
+static cmd_func_t wl_trf_mgmt_filters_removeex;
+static cmd_func_t wl_trf_mgmt_filters_list;
+static cmd_func_t wl_trf_mgmt_filters_clear;
+static cmd_func_t wl_trf_mgmt_bandwidth;
+static cmd_func_t wl_trf_mgmt_flags;
+static cmd_func_t wl_trf_mgmt_stats;
+static cmd_func_t wl_trf_mgmt_stats_clear;
+static cmd_func_t wl_trf_mgmt_shaping_info;
+
+static cmd_t wl_trf_mgmt_cmds[] = {
+ {"trf_mgmt_config", wl_trf_mgmt_config, WLC_GET_VAR, WLC_SET_VAR,
+ "Sets/gets traffic management configuration.\n"
+ "\tUsage: wl trf_mgmt_config [<enable> \n"
+ "\t [<host IP address> <host IP subnet mask> \n"
+ "\t <downlink kbps> <uplink kbps> [<flags>]]] \n"
+ "\tenable: 0 - Disable traffic management\n"
+ "\t 1 - Enables traffic management (host IP arguments required)\n"
+ "\tFlag values are the following:\n"
+ "\t0x0001 : Add DSCP values to tx packets\n"
+ "\t0x0002 : Disable traffic shaping...just do priority classification\n"
+ "\nIf no arguments are entered, the current traffic management configuration \n"
+ "is displayed.\n"
+ "\ne.g. Configure traffic management and specify local ip addr. and bandwidth data:\n"
+ "\nwl trf_mgmt_config 1 12.0.0.1 255.0.0.0 5000 650"},
+
+ {"trf_mgmt_filters_add", wl_trf_mgmt_filters_add, -1, WLC_SET_VAR,
+ "Adds a traffic management filter.\n"
+ "\tUsage: wl trf_mgmt_filter_add [dst_port src_port prot priority]\n"
+ "\tdst_port : Destination TCP or UDP port \n"
+ "\tsrc_port : Source TCP or UDP port (0 - wildcard for any source port)\n"
+ "\tprot : L4 protocol (6 - TCP, 17 - UDP)\n"
+ "\tpriority : Priority value (see trf_mgmt_priority_values enum) \n"
+ "\ne.g. Add a tcp wildcard filter:\n"
+ "\nwl trf_mgmt_filters_add 80 0 6 2"},
+
+ {"trf_mgmt_filters_addex", wl_trf_mgmt_filters_addex, -1, WLC_SET_VAR,
+ "Adds a traffic management filter.\n"
+ "\tUsage: wl trf_mgmt_filter_add flag [dst_port src_port prot priority]\n"
+ "\tUsage: wl trf_mgmt_filter_add flag [dst_mac priority] \n"
+ "\tFlag values are the following:\n"
+ "\t0x0000 : filter on tcp/udp src/dst port\n"
+ "\t0x0001 : filter on destination MAC address\n"
+ "\t0x0010 : do not update the packet priority \n"
+ "\t0x0020 : Tag packets as Favored\n"
+ "\tdst_mac : Destination MAC address \n"
+ "\tdst_port : Destination TCP or UDP port \n"
+ "\tsrc_port : Source TCP or UDP port (0 - wildcard for any source port)\n"
+ "\tprot : L4 protocol (6 - TCP, 17 - UDP)\n"
+ "\tpriority : Priority value (see trf_mgmt_priority_values enum) \n"
+ "\ne.g. Add a tcp wildcard filter for all src/dst ports:\n"
+ "\nwl trf_mgmt_filters_addex 0 0 0 6 2\n"
+ "\ne.g. Add a dst mac address filter\n"
+ "\nwl trf_mgmt_filters_addex 0x31 aa:bb:cc:dd:ee:ff 2"},
+
+ {"trf_mgmt_filters_remove", wl_trf_mgmt_filters_remove, -1, WLC_SET_VAR,
+ "Removes a traffic management filter.\n"
+ "\tUsage: wl trf_mgmt_filter_remove [dst_port src_port prot]\n"
+ "\tdst_port : Destination TCP or UDP port \n"
+ "\tsrc_port : Source TCP or UDP port (0 - wildcard for any source port)\n"
+ "\tprot : L4 protocol (6 - TCP, 17 - UDP)\n"
+ "\ne.g. Remove a tcp wildcard filter:\n"
+ "\nwl trf_mgmt_filters_remove 80 0 6"},
+
+ {"trf_mgmt_filters_removeex", wl_trf_mgmt_filters_removeex, -1, WLC_SET_VAR,
+ "Removes a traffic management filter.\n"
+ "\tUsage: wl trf_mgmt_filter_remove flag [dst_port src_port prot]\n"
+ "\tUsage: wl trf_mgmt_filter_remove flag [dst_mac]\n"
+ "\tFlag values are the following:\n"
+ "\t0x0000 : filter on tcp/udp src/dst port\n"
+ "\t0x0001 : filter on destination MAC address\n"
+ "\t0x0010 : do not update the packet priority \n"
+ "\t0x0020 : Tag packets as Favored\n"
+ "\tdst_mac : Destination MAC address \n"
+ "\tdst_port : Destination TCP or UDP port \n"
+ "\tsrc_port : Source TCP or UDP port (0 - wildcard for any source port)\n"
+ "\tprot : L4 protocol (6 - TCP, 17 - UDP)\n"
+ "\ne.g. Remove a tcp wildcard filter:\n"
+ "\nwl trf_mgmt_filters_removeex 0 80 0 6\n"
+ "\nwl trf_mgmt_filters_removeex 0x31 00:90:4c:52:a8:83"},
+
+ {"trf_mgmt_filters_list", wl_trf_mgmt_filters_list, WLC_GET_VAR, -1,
+ "Lists all traffic management filters.\n"
+ "\tUsage: wl trf_mgmt_filter_list"},
+
+ {"trf_mgmt_filters_clear", wl_trf_mgmt_filters_clear, -1, WLC_SET_VAR,
+ "Clears all traffic management filters.\n"
+ "\tUsage: wl trf_mgmt_filters_clear"},
+
+ {"trf_mgmt_bandwidth", wl_trf_mgmt_bandwidth, WLC_GET_VAR, WLC_SET_VAR,
+ "Sets/gets traffic management bandwidth configuration.\n"
+ "\tUsage: wl trf_mgmt_bandwidth \n"
+ "\t [downlink uplink min_tx_bk min_tx_be min_tx_vi\n"
+ "\t [min_rx_b min_rx_be min_rx_vi]]\n"
+ "\tdownlink : downlink bandwidth (kbps)\n"
+ "\tuplink : uplink bandwidth (kbps)\n"
+ "\tmin_tx_bk : min. guaranteed tx bandwidth percentage for BK (kbps)\n"
+ "\tmin_tx_be : min. guaranteed tx bandwidth percentage for BE (kbps)\n"
+ "\tmin_tx_vi : min. guaranteed tx bandwidth percentage for VI (kbps)\n"
+ "\n(min_tx_bo + min_tx_be + min_tx_vi) must equal 100.\n"
+ "\tmin_rx_bk : min. guaranteed rx bandwidth percentage for BK (kbps)\n"
+ "\tmin_rx_be : min. guaranteed rx bandwidth percentage for BE (kbps)\n"
+ "\tmin_rx_vi : min. guaranteed rx bandwidth percentage for VI (kbps)\n"
+ "\n(min_rx_bk + min_rx_be + min_rx_vi) must equal 100."
+ "\nIf no rx gandwidth arguments are entered, tx bandwidth is used for rx."
+ "\nIf no arguments are entered, the current bandwidth configuration is displayed."},
+
+ {"trf_mgmt_flags", wl_trf_mgmt_flags, WLC_GET_VAR, WLC_SET_VAR,
+ "Sets/gets traffic management operational flags.\n"
+ "\tUsage: wl trf_mgmt_flags [flags]\n\n"
+ "\tFlag values are the following:\n"
+ "\t0x0001 : Add DSCP values to tx packets\n"
+ "\t0x0002 : Disable traffic shaping...just do priority classification\n"
+ "\nIf no arguments are entered, the current operational flags are displayed."},
+
+ {"trf_mgmt_stats", wl_trf_mgmt_stats, WLC_GET_VAR, -1,
+ "Gets traffic management statistics.\n"
+ "\tUsage: wl trf_mgmt_stats [index]\n"
+ "\tindex : Queue index"},
+
+ {"trf_mgmt_stats_clear", wl_trf_mgmt_stats_clear, -1, WLC_SET_VAR,
+ "Clears traffic management statistics.\n"
+ "\tUsage: wl trf_mgmt_stats_clear"},
+
+ {"trf_mgmt_shaping_info", wl_trf_mgmt_shaping_info, WLC_GET_VAR, -1,
+ "Gets traffic management shaping parameters.\n"
+ "\tUsage: wl trf_mgmt_shaping_info [index]\n"
+ "\tindex : Queue index"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_trf_mgmt_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register trf_mgmt commands */
+ wl_module_cmds_register(wl_trf_mgmt_cmds);
+}
+
+/* Get/set traffic management configuration. */
+static int
+wl_trf_mgmt_config(void *wl, cmd_t *cmd, char **argv)
+{
+ uint argc = 0;
+ uint32 i;
+ trf_mgmt_config_t *ptrf_mgmt_config;
+ uint8 buf[sizeof(trf_mgmt_config_t)];
+ int buf_len;
+ char *endptr = NULL;
+ int rc = -1;
+ void *ptr = NULL;
+
+ if (!*++argv) {
+ /*
+ * Get current traffic management configuration.
+ */
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+
+ ptrf_mgmt_config = (trf_mgmt_config_t *)ptr;
+
+ printf("Enabled : %d\n",
+ dtoh32(ptrf_mgmt_config->trf_mgmt_enabled));
+ printf("Host IP Address : %s\n",
+ wl_iptoa((void *)&ptrf_mgmt_config->host_ip_addr));
+ printf("Host IP Subnet Mask : %s\n",
+ wl_iptoa((void *)&ptrf_mgmt_config->host_subnet_mask));
+ printf("Downlink Bandwidth : %d\n",
+ dtoh32(ptrf_mgmt_config->downlink_bandwidth));
+ printf("Uplink Bandwidth : %d\n",
+ dtoh32(ptrf_mgmt_config->uplink_bandwidth));
+ printf("\n");
+
+ printf("Minimum Tx Bandwidth[BK] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_tx_bandwidth[0]));
+ printf("Minimum Tx Bandwidth[BE] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_tx_bandwidth[1]));
+ printf("Minimum Tx Bandwidth[VI] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_tx_bandwidth[2]));
+ printf("\n");
+
+ printf("Minimum Rx Bandwidth[BK] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_rx_bandwidth[0]));
+ printf("Minimum Rx Bandwidth[BE] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_rx_bandwidth[1]));
+ printf("Minimum Rx Bandwidth[VI] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_rx_bandwidth[2]));
+ printf("\n");
+
+ printf("Flags : 0x%04X\n",
+ dtoh32(ptrf_mgmt_config->flags));
+ }
+ else {
+ /* arg count */
+ while (argv[argc])
+ argc++;
+
+ /* required arguments */
+ if ((argc != 1) && (argc != 5) && (argc != 6)) {
+ fprintf(stderr, "Too few/many arguments (require 1 or 5 or 6 , got %d)\n", argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ ptrf_mgmt_config = (trf_mgmt_config_t *)buf;
+ buf_len = sizeof(trf_mgmt_config_t);
+ memset((uint8 *)buf, 0, buf_len);
+
+ ptrf_mgmt_config->trf_mgmt_enabled = htod32((int32)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0') {
+ return BCME_USAGE_ERROR;
+ }
+
+ if (argc > 1) {
+ if (ptrf_mgmt_config->trf_mgmt_enabled) {
+ if (!wl_atoip(*argv++, (void *)&ptrf_mgmt_config->host_ip_addr)) {
+ return BCME_USAGE_ERROR;
+ }
+ if (!wl_atoip(*argv++, (void *)&ptrf_mgmt_config->host_subnet_mask)) {
+ return BCME_USAGE_ERROR;
+ }
+ ptrf_mgmt_config->downlink_bandwidth =
+ htod32((int32)strtol(*argv++, &endptr, 0));
+ ptrf_mgmt_config->uplink_bandwidth =
+ htod32((int32)strtol(*argv++, &endptr, 0));
+
+ /*
+ * Zero-fill min bandwidth based. This will cause the driver to use
+ * defult settings
+ */
+ for (i = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) {
+ ptrf_mgmt_config->min_tx_bandwidth[i] = 0;
+ ptrf_mgmt_config->min_rx_bandwidth[i] = 0;
+ }
+
+ if (argc == 6) {
+ ptrf_mgmt_config->flags = htod32((int32)strtol(*argv++, &endptr, 0));
+ }
+ } else {
+ return BCME_BADARG;
+ }
+ }
+
+ rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_config, buf_len);
+ }
+ return rc;
+}
+
+/* Sets a traffic management filter. */
+static int
+wl_trf_mgmt_filters_add(void *wl, cmd_t *cmd, char **argv)
+{
+ uint argc = 0;
+ trf_mgmt_filter_list_t *ptrf_mgmt_filter_list;
+ trf_mgmt_filter_t *ptrf_mgmt_filter;
+ uint8 buf[sizeof(trf_mgmt_filter_list_t)];
+ int buf_len;
+ char *param;
+ char *endptr = NULL;
+ int rc = -1;
+
+ (void)param;
+ /* arg count */
+ param = *++argv;
+ while (argv[argc])
+ argc++;
+
+ /* required arguments */
+ if (argc != 4) {
+ fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 4, argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ ptrf_mgmt_filter_list = (trf_mgmt_filter_list_t *)buf;
+ buf_len = sizeof(trf_mgmt_filter_list_t);
+ memset((uint8 *)buf, 0, buf_len);
+
+ ptrf_mgmt_filter_list->num_filters = 1;
+ ptrf_mgmt_filter = &ptrf_mgmt_filter_list->filter[0];
+
+ ptrf_mgmt_filter->dst_port = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ptrf_mgmt_filter->priority = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_filter_list, buf_len);
+
+ return rc;
+}
+/* Sets a traffic management filter L2/L3/L4 */
+static int
+wl_trf_mgmt_filters_addex(void *wl, cmd_t *cmd, char **argv)
+{
+ uint argc = 0;
+ trf_mgmt_filter_list_t *ptrf_mgmt_filter_list;
+ trf_mgmt_filter_t *ptrf_mgmt_filter;
+ uint8 buf[sizeof(trf_mgmt_filter_list_t)];
+ int buf_len;
+ char *param;
+ char *endptr = NULL;
+ int rc = -1;
+
+ (void)param;
+ (void)cmd;
+ /* arg count */
+ param = *++argv;
+ while (argv[argc])
+ argc++;
+
+ /* required arguments */
+ if (argc < 3) {
+ fprintf(stderr, "Too few arguments (require > 3 got %d)\n", argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ ptrf_mgmt_filter_list = (trf_mgmt_filter_list_t *)buf;
+ buf_len = sizeof(trf_mgmt_filter_list_t);
+ memset((uint8 *)buf, 0, buf_len);
+
+ ptrf_mgmt_filter_list->num_filters = 1;
+ ptrf_mgmt_filter = &ptrf_mgmt_filter_list->filter[0];
+
+ ptrf_mgmt_filter->flags = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ if (ptrf_mgmt_filter->flags & TRF_FILTER_MAC_ADDR) {
+
+ if (argc != 3) {
+ fprintf(stderr, "Too many arguments (require 3 got %d)\n", argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!wl_ether_atoe(*argv++, &ptrf_mgmt_filter->dst_ether_addr))
+ return BCME_USAGE_ERROR;
+
+ ptrf_mgmt_filter->priority = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ } else {
+ /* required arguments */
+ if (argc != 5) {
+ fprintf(stderr, "Too few/many arguments (require 5 got %d)\n", argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ ptrf_mgmt_filter->dst_port = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ptrf_mgmt_filter->priority = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+
+ rc = wlu_var_setbuf(wl, "trf_mgmt_filters_add", ptrf_mgmt_filter_list, buf_len);
+
+ return rc;
+}
+
+/* Removes a traffic management filter. */
+static int
+wl_trf_mgmt_filters_remove(void *wl, cmd_t *cmd, char **argv)
+{
+ uint argc = 0;
+ trf_mgmt_filter_list_t *ptrf_mgmt_filter_list;
+ trf_mgmt_filter_t *ptrf_mgmt_filter;
+ uint8 buf[sizeof(trf_mgmt_filter_list_t)];
+ int buf_len;
+ char *endptr = NULL;
+ char *param;
+ int rc = -1;
+
+ (void)param;
+ /* arg count */
+ param = *++argv;
+ while (argv[argc])
+ argc++;
+
+ /* required arguments */
+ if (argc != 3) {
+ fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 3, argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ ptrf_mgmt_filter_list = (trf_mgmt_filter_list_t *)buf;
+ buf_len = sizeof(trf_mgmt_filter_list_t);
+
+ memset((uint8 *)buf, 0, buf_len);
+
+ ptrf_mgmt_filter_list->num_filters = 1;
+ ptrf_mgmt_filter = &ptrf_mgmt_filter_list->filter[0];
+
+ ptrf_mgmt_filter->dst_port = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_filter_list, buf_len);
+
+ return rc;
+}
+
+/* Removes a traffic management filter for L2/L3/L4 */
+static int
+wl_trf_mgmt_filters_removeex(void *wl, cmd_t *cmd, char **argv)
+{
+ uint argc = 0;
+ trf_mgmt_filter_list_t *ptrf_mgmt_filter_list;
+ trf_mgmt_filter_t *ptrf_mgmt_filter;
+ uint8 buf[sizeof(trf_mgmt_filter_list_t)];
+ int buf_len;
+ char *endptr = NULL;
+ char *param;
+ int rc = -1;
+
+ (void)param;
+ (void)cmd;
+ /* arg count */
+ param = *++argv;
+ while (argv[argc])
+ argc++;
+
+ /* required arguments */
+ if (argc < 2) {
+ fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 2, argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ ptrf_mgmt_filter_list = (trf_mgmt_filter_list_t *)buf;
+ buf_len = sizeof(trf_mgmt_filter_list_t);
+
+ memset((uint8 *)buf, 0, buf_len);
+
+ ptrf_mgmt_filter_list->num_filters = 1;
+ ptrf_mgmt_filter = &ptrf_mgmt_filter_list->filter[0];
+
+ ptrf_mgmt_filter->flags = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0') {
+ return BCME_USAGE_ERROR;
+ }
+ if (ptrf_mgmt_filter->flags & TRF_FILTER_MAC_ADDR) {
+
+ if (argc != 2) {
+ fprintf(stderr, "Too many arguments (require 2 got %d)\n", argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ if (!wl_ether_atoe(*argv++, &ptrf_mgmt_filter->dst_ether_addr)) {
+ return BCME_USAGE_ERROR;
+ }
+
+ } else {
+ if (argc < 4) {
+ fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 4, argc);
+ return BCME_USAGE_ERROR;
+ }
+ ptrf_mgmt_filter->dst_port = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+
+ rc = wlu_var_setbuf(wl, "trf_mgmt_filters_remove", ptrf_mgmt_filter_list, buf_len);
+
+ return rc;
+}
+
+/* lists the current traffic management filters. */
+static int
+wl_trf_mgmt_filters_list(void *wl, cmd_t *cmd, char **argv)
+{
+ trf_mgmt_filter_list_t *ptrf_mgmt_filter_list;
+ trf_mgmt_filter_t *ptrf_mgmt_filter;
+ uint i;
+ int rc = -1;
+ void *ptr = NULL;
+
+ UNUSED_PARAMETER(argv);
+
+ /*
+ * Get current traffic management filters.
+ */
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+
+ ptrf_mgmt_filter_list = (trf_mgmt_filter_list_t *)ptr;
+
+ printf("Number of filters : %d\n", dtoh32(ptrf_mgmt_filter_list->num_filters));
+
+ for (i = 0; i < ptrf_mgmt_filter_list->num_filters; i++) {
+ ptrf_mgmt_filter = &ptrf_mgmt_filter_list->filter[i];
+
+ if (ptrf_mgmt_filter->flags & TRF_FILTER_MAC_ADDR) {
+ printf("\n");
+ printf("Filter #%d\n", i);
+ printf("Flags : 0x%02x\n", dtoh32(ptrf_mgmt_filter->flags));
+ printf("Dst EtherAddr : %s\n",
+ wl_ether_etoa(&ptrf_mgmt_filter->dst_ether_addr));
+ printf("Priority : %d\n", dtoh32(ptrf_mgmt_filter->priority));
+ } else {
+ printf("\n");
+ printf("Filter #%d\n", i);
+ printf("Dst Port : %d\n", dtoh32(ptrf_mgmt_filter->dst_port));
+ printf("Src Port : %d\n", dtoh32(ptrf_mgmt_filter->src_port));
+ printf("Protocol : %d\n", dtoh32(ptrf_mgmt_filter->prot));
+ printf("Flags : 0x%02x\n", dtoh32(ptrf_mgmt_filter->flags));
+ printf("Priority : %d\n", dtoh32(ptrf_mgmt_filter->priority));
+ }
+ }
+
+ return rc;
+}
+
+/* Clears the traffic management filters. */
+static int
+wl_trf_mgmt_filters_clear(void *wl, cmd_t *cmd, char **argv)
+{
+ int rc = -1;
+
+ UNUSED_PARAMETER(argv);
+
+ rc = wlu_var_setbuf(wl, cmd->name, NULL, 0);
+
+ return rc;
+}
+
+/*
+ * Get/set traffic management bandwidth configuration. We support the ability to get/set just the
+ * bandwidth parameters in the global trf_mgmt_config_t structure.
+ */
+static int
+wl_trf_mgmt_bandwidth(void *wl, cmd_t *cmd, char **argv)
+{
+ uint argc = 0;
+ trf_mgmt_config_t *ptrf_mgmt_config;
+ uint8 buf[sizeof(trf_mgmt_config_t)];
+ int buf_len;
+ char *endptr = NULL;
+ int i, total_bandwidth;
+ int rc = -1;
+ void *ptr = NULL;
+
+ if (!*++argv) {
+ /*
+ * Get current traffic management bandwidth settings.
+ */
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+
+ ptrf_mgmt_config = (trf_mgmt_config_t *)ptr;
+
+ printf("Downlink Bandwidth : %d\n",
+ dtoh32(ptrf_mgmt_config->downlink_bandwidth));
+ printf("Uplink Bandwidth : %d\n",
+ dtoh32(ptrf_mgmt_config->uplink_bandwidth));
+ printf("\n");
+
+ printf("Minimum Tx Bandwidth[BK] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_tx_bandwidth[0]));
+ printf("Minimum Tx Bandwidth[BE] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_tx_bandwidth[1]));
+ printf("Minimum Tx Bandwidth[VI] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_tx_bandwidth[2]));
+ printf("\n");
+
+ printf("Minimum Rx Bandwidth[BK] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_tx_bandwidth[0]));
+ printf("Minimum Rx Bandwidth[BE] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_tx_bandwidth[1]));
+ printf("Minimum Rx Bandwidth[VI] : %d\n",
+ dtoh32(ptrf_mgmt_config->min_tx_bandwidth[2]));
+ }
+ else {
+ /* arg count */
+ while (argv[argc])
+ argc++;
+
+ /* required arguments */
+ if (argc < 5) {
+ fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 5, argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+
+ ptrf_mgmt_config = (trf_mgmt_config_t *)buf;
+ buf_len = sizeof(trf_mgmt_config_t);
+
+ memcpy(buf, ptr, buf_len);
+
+ ptrf_mgmt_config->downlink_bandwidth = htod32((int32)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ ptrf_mgmt_config->uplink_bandwidth = htod32((int32)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ for (i = 0, total_bandwidth = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) {
+ ptrf_mgmt_config->min_tx_bandwidth[i] =
+ htod32((int32)strtol(*argv++, &endptr, 0));
+
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ total_bandwidth += ptrf_mgmt_config->min_tx_bandwidth[i];
+ }
+
+ if (total_bandwidth != 100) {
+ fprintf(stderr,
+ "Sum of gauranteed bandwidth levels must equal 100 (got %d)\n",
+ total_bandwidth);
+ return BCME_BADARG;
+ }
+
+ if (argc > 5) {
+ for (i = 0, total_bandwidth = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) {
+ ptrf_mgmt_config->min_rx_bandwidth[i] =
+ htod32((int32)strtol(*argv++, &endptr, 0));
+
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ total_bandwidth += ptrf_mgmt_config->min_rx_bandwidth[i];
+ }
+
+ if (total_bandwidth != 100) {
+ fprintf(stderr,
+ "Sum of gauranteed rx bandwidth levels must equal 100 (got %d)\n",
+ total_bandwidth);
+ return BCME_BADARG;
+ }
+ } else {
+ for (i = 0, total_bandwidth = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) {
+ ptrf_mgmt_config->min_rx_bandwidth[i] = ptrf_mgmt_config->min_tx_bandwidth[i];
+ }
+ }
+
+ rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_config, buf_len);
+ }
+
+ return rc;
+}
+
+/*
+ * Get/set traffic management operational flags. We use this to change flags that
+ * can't be set by GUI. This allows us to configure certain options that we may want to
+ * enable/disable in the shipping product.
+ */
+static int
+wl_trf_mgmt_flags(void *wl, cmd_t *cmd, char **argv)
+{
+ uint argc = 0;
+ uint32 flags;
+ char *endptr = NULL;
+ int rc = -1;
+ void *ptr = NULL;
+
+ if (!*++argv) {
+ /*
+ * Get current traffic management bandwidth settings.
+ */
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+
+ flags = *(uint32 *)ptr;
+
+ printf("Flags : 0x%04X\n", flags);
+ }
+ else {
+ /* arg count */
+ while (argv[argc])
+ argc++;
+
+ /* required arguments */
+ if (argc != 1) {
+ fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 1, argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ flags = htod32((int32)strtol(*argv++, &endptr, 0));
+ if (*endptr != '\0') {
+ return BCME_USAGE_ERROR;
+ }
+ rc = wlu_var_setbuf(wl, cmd->name, &flags, sizeof(uint32));
+ }
+
+ return rc;
+}
+
+/* Print traffic management statistics. */
+static void
+wl_trf_mgmt_print_stats(void *ptr, uint index)
+{
+ trf_mgmt_stats_array_t *ptrf_mgmt_statistics_array;
+ trf_mgmt_stats_t *ptrf_mgmt_statistics;
+
+ ptrf_mgmt_statistics_array = (trf_mgmt_stats_array_t *)ptr;
+
+ ptrf_mgmt_statistics = &ptrf_mgmt_statistics_array->tx_queue_stats[index];
+
+ printf("Statistics for Tx Queue[%d]\n", index);
+ printf("\n");
+ printf("Num. packets processed : %d\n",
+ dtoh32(ptrf_mgmt_statistics->num_processed_packets));
+ printf("Num. bytes processed : %d\n",
+ dtoh32(ptrf_mgmt_statistics->num_processed_bytes));
+ printf("Num. packets discarded : %d\n",
+ dtoh32(ptrf_mgmt_statistics->num_discarded_packets));
+
+ ptrf_mgmt_statistics = &ptrf_mgmt_statistics_array->rx_queue_stats[index];
+
+ printf("\n");
+ printf("Statistics for Rx Queue[%d]\n", index);
+ printf("\n");
+ printf("Num. packets processed : %d\n",
+ dtoh32(ptrf_mgmt_statistics->num_processed_packets));
+ printf("Num. bytes processed : %d\n",
+ dtoh32(ptrf_mgmt_statistics->num_processed_bytes));
+ printf("Num. packets discarded : %d\n",
+ dtoh32(ptrf_mgmt_statistics->num_discarded_packets));
+
+ printf("\n");
+}
+
+/* Get traffic management statistics. */
+static int
+wl_trf_mgmt_stats(void *wl, cmd_t *cmd, char **argv)
+{
+ uint argc = 0;
+ uint i;
+ int rc = -1;
+ char *endptr = NULL;
+ void *ptr = NULL;
+
+ /*
+ * Get current traffic management statistics.
+ */
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+
+ if (!*++argv) {
+ /*
+ * Print all of the current traffic management statistics.
+ */
+ for (i = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) {
+ wl_trf_mgmt_print_stats(ptr, i);
+ }
+ }
+ else {
+ /* arg count */
+ while (argv[argc])
+ argc++;
+
+ /* required arguments */
+ if (argc != 1) {
+ fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 1, argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ i = htod16((int16)strtol(*argv, &endptr, 0));
+ if (i >= TRF_MGMT_MAX_PRIORITIES) {
+ fprintf(stderr, "Index must be < %d)\n", TRF_MGMT_MAX_PRIORITIES);
+ return BCME_BADARG;
+ }
+
+ /* Print the current traffic management statistics for the specified queue index. */
+ wl_trf_mgmt_print_stats(ptr, i);
+ }
+
+
+ return rc;
+}
+
+/* Clears the traffic management statistics. */
+static int
+wl_trf_mgmt_stats_clear(void *wl, cmd_t *cmd, char **argv)
+{
+ int rc = -1;
+
+ UNUSED_PARAMETER(argv);
+
+ rc = wlu_var_setbuf(wl, cmd->name, NULL, 0);
+
+ return rc;
+}
+
+/* Print traffic management shaping info. */
+static void
+wl_trf_mgmt_print_global_shaping_info(void *ptr)
+{
+ trf_mgmt_shaping_info_array_t *ptrf_mgmt_shaping_info_array;
+ trf_mgmt_global_info_t *ptrf_mgmt_global_info;
+
+ ptrf_mgmt_shaping_info_array = (trf_mgmt_shaping_info_array_t *)ptr;
+
+ ptrf_mgmt_global_info = &ptrf_mgmt_shaping_info_array->tx_global_shaping_info;
+
+ printf("Global shaping info. for Tx Queues\n");
+ printf("\n");
+ printf("Maximum bytes/second : %d\n",
+ ptrf_mgmt_global_info->maximum_bytes_per_second);
+ printf("Maximum bytes/sampling period : %d\n",
+ ptrf_mgmt_global_info->maximum_bytes_per_sampling_period);
+ printf("Total bytes consumed per second : %d\n",
+ ptrf_mgmt_global_info->total_bytes_consumed_per_second);
+ printf("Total bytes consumed per sampling period : %d\n",
+ ptrf_mgmt_global_info->total_bytes_consumed_per_sampling_period);
+ printf("Unused bytes for current sampling period : %d\n",
+ ptrf_mgmt_global_info->total_unused_bytes_per_sampling_period);
+
+ printf("\n");
+
+ ptrf_mgmt_global_info = &ptrf_mgmt_shaping_info_array->rx_global_shaping_info;
+
+ printf("Global shaping info. for Rx Queues\n");
+ printf("\n");
+ printf("Maximum bytes/second : %d\n",
+ ptrf_mgmt_global_info->maximum_bytes_per_second);
+ printf("Maximum bytes/sampling period : %d\n",
+ ptrf_mgmt_global_info->maximum_bytes_per_sampling_period);
+ printf("Total bytes consumed per second : %d\n",
+ ptrf_mgmt_global_info->total_bytes_consumed_per_second);
+ printf("Total bytes consumed per sampling period : %d\n",
+ ptrf_mgmt_global_info->total_bytes_consumed_per_sampling_period);
+ printf("Unused bytes for current sampling period : %d\n",
+ ptrf_mgmt_global_info->total_unused_bytes_per_sampling_period);
+
+ printf("\n");
+}
+
+static void
+wl_trf_mgmt_print_shaping_info(void *ptr, uint index)
+{
+ trf_mgmt_shaping_info_array_t *ptrf_mgmt_shaping_info_array;
+ trf_mgmt_shaping_info_t *ptrf_mgmt_shaping_info;
+
+ ptrf_mgmt_shaping_info_array = (trf_mgmt_shaping_info_array_t *)ptr;
+
+ ptrf_mgmt_shaping_info = &ptrf_mgmt_shaping_info_array->tx_queue_shaping_info[index];
+
+ printf("Shaping info. for Tx Queue[%d]\n", index);
+ printf("\n");
+ printf("Gauranteed bandwidth percentage : %d%%\n",
+ dtoh32(ptrf_mgmt_shaping_info->gauranteed_bandwidth_percentage));
+ printf("Guaranteed bytes/second : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->guaranteed_bytes_per_second));
+ printf("Guaranteed bytes/sampling period : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->guaranteed_bytes_per_sampling_period));
+ printf("Num. bytes produced per second : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->num_bytes_produced_per_second));
+ printf("Num. bytes consumed per second : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->num_bytes_consumed_per_second));
+ printf("Num. packets pending : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->num_queued_packets));
+ printf("Num. bytes pending : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->num_queued_bytes));
+
+ ptrf_mgmt_shaping_info = &ptrf_mgmt_shaping_info_array->rx_queue_shaping_info[index];
+
+ printf("\n");
+ printf("Shaping info. for Rx Queue[%d]\n", index);
+ printf("\n");
+ printf("Gauranteed bandwidth percentage : %d%%\n",
+ dtoh32(ptrf_mgmt_shaping_info->gauranteed_bandwidth_percentage));
+ printf("Guaranteed bytes/second : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->guaranteed_bytes_per_second));
+ printf("Guaranteed bytes/sampling period : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->guaranteed_bytes_per_sampling_period));
+ printf("Num. bytes produced per second : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->num_bytes_produced_per_second));
+ printf("Num. bytes consumed per second : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->num_bytes_consumed_per_second));
+ printf("Num. packets pending : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->num_queued_packets));
+ printf("Num. bytes pending : %d\n",
+ dtoh32(ptrf_mgmt_shaping_info->num_queued_bytes));
+
+ printf("\n");
+}
+
+/* Get traffic management shaping info. */
+static int
+wl_trf_mgmt_shaping_info(void *wl, cmd_t *cmd, char **argv)
+{
+ uint argc = 0;
+ uint i;
+ int rc = -1;
+ char *endptr = NULL;
+ void *ptr = NULL;
+
+ /*
+ * Get current traffic management shaping info.
+ */
+ if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return rc;
+
+ if (!*++argv) {
+ /*
+ * Print all of the current traffic management shaping info.
+ */
+ wl_trf_mgmt_print_global_shaping_info(ptr);
+
+ for (i = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) {
+ wl_trf_mgmt_print_shaping_info(ptr, i);
+ }
+ }
+ else {
+ /* arg count */
+ while (argv[argc])
+ argc++;
+
+ /* required arguments */
+ if (argc != 1) {
+ fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 1, argc);
+ return BCME_USAGE_ERROR;
+ }
+
+ i = htod16((int16)strtol(*argv, &endptr, 0));
+ if (i >= TRF_MGMT_MAX_PRIORITIES) {
+ fprintf(stderr, "Index must be < %d)\n", TRF_MGMT_MAX_PRIORITIES);
+ return BCME_BADARG;
+ }
+
+ /* Print the current traffic management shaping info for the specified queue index. */
+ wl_trf_mgmt_print_global_shaping_info(ptr);
+ wl_trf_mgmt_print_shaping_info(ptr, i);
+ }
+
+
+ return rc;
+}
diff --git a/wl/src/wl/exe/wluc_wds.c b/wl/src/wl/exe/wluc_wds.c
new file mode 100644
index 0000000..2fdc4b8
--- /dev/null
+++ b/wl/src/wl/exe/wluc_wds.c
@@ -0,0 +1,206 @@
+/*
+ * wl wds command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_wds.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_wds_wpa_role_old, wl_wds_wpa_role;
+#if defined(DWDS)
+static cmd_func_t wl_dwds_config;
+#endif
+
+#define WDS_TYPE_USAGE \
+"\tUsage: wl wds_type -i <ifname>\n" \
+"\tifname is the name of the interface to query the type.\n" \
+"\tReturn values:\n" \
+"\t\t0:The interface type is neither WDS nor DWDS.\n" \
+"\t\t1:The interface is WDS type.\n" \
+"\t\t2:The interface is DWDS type.\n"
+
+static cmd_t wl_wds_cmds[] = {
+ { "wds", wl_maclist, WLC_GET_WDSLIST, WLC_SET_WDSLIST,
+ "Set or get the list of WDS member MAC addresses.\n"
+ "\tSet using a space separated list of MAC addresses.\n"
+ "\twl wds xx:xx:xx:xx:xx:xx [xx:xx:xx:xx:xx:xx ...]" },
+ { "lazywds", wl_int, WLC_GET_LAZYWDS, WLC_SET_LAZYWDS,
+ "Set or get \"lazy\" WDS mode (dynamically grant WDS membership to anyone)."},
+ { "wds_remote_mac", wl_macaddr, WLC_WDS_GET_REMOTE_HWADDR, -1,
+ "Get WDS link remote endpoint's MAC address"},
+ { "wds_wpa_role_old", wl_wds_wpa_role_old, WLC_WDS_GET_WPA_SUP, -1,
+ "Get WDS link local endpoint's WPA role (old)"},
+ { "wds_wpa_role", wl_wds_wpa_role, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set WDS link local endpoint's WPA role"},
+#if defined(DWDS)
+ { "dwds_config", wl_dwds_config, -1, WLC_SET_VAR,
+ "wl dwds_config <enable/disable> <sta/ap> <xx:xx:xx:xx:xx:xx>"},
+#endif
+ { "wds_type", wl_varint, WLC_GET_VAR, -1,
+ "Indicate whether the interface to which this IOVAR is sent is of WDS or DWDS type.\n\n"
+ WDS_TYPE_USAGE},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_wds_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register wds commands */
+ wl_module_cmds_register(wl_wds_cmds);
+}
+
+static int
+wl_wds_wpa_role_old(void *wl, cmd_t *cmd, char **argv)
+{
+ uint remote[2];
+ uint *sup = remote;
+ int ret = 0;
+
+ UNUSED_PARAMETER(argv);
+
+ if ((ret = wlu_get(wl, WLC_WDS_GET_REMOTE_HWADDR, remote, sizeof(remote))) < 0) {
+ printf("Unable to get remote endpoint's hwaddr\n");
+ return ret;
+ }
+ if ((ret = wlu_get(wl, cmd->get, remote, sizeof(remote))) < 0) {
+ printf("Unable to get local endpoint's WPA role\n");
+ return ret;
+ }
+ printf("Local endpoing's WPA role: %s\n", dtoh32(*sup) ? "supplicant" : "authenticator");
+ return 0;
+}
+
+static int
+wl_wds_wpa_role(void *wl, cmd_t *cmd, char **argv)
+{
+ char var[256];
+ char *mac;
+ char *sup;
+ int len;
+ int ret;
+ if (strlen("wds_wpa_role") + 1 + ETHER_ADDR_LEN + 1 > sizeof(var))
+ return -1;
+ /* build var required by WLC_GET|SET_VAR */
+ len = sprintf(var, "%s", "wds_wpa_role") + 1;
+ mac = var + len;
+ if ((ret = wlu_get(wl, WLC_WDS_GET_REMOTE_HWADDR, mac, ETHER_ADDR_LEN)) < 0) {
+ printf("Unable to get remote endpoint's hwaddr\n");
+ return ret;
+ }
+ len += ETHER_ADDR_LEN + 1;
+ if (argv[1]) {
+ sup = mac + ETHER_ADDR_LEN;
+ switch ((uchar)(*sup = atoi(argv[1]))) {
+ case WL_WDS_WPA_ROLE_AUTH:
+ case WL_WDS_WPA_ROLE_SUP:
+ case WL_WDS_WPA_ROLE_AUTO:
+ if ((ret = wlu_set(wl, cmd->set, var, len)) < 0)
+ printf("Unable to set local endpoint's WPA role\n");
+ break;
+ default:
+ printf("Invalid WPA role %s. %u:authenticator, %u:supplicant, %u:auto\n",
+ argv[1], WL_WDS_WPA_ROLE_AUTH,
+ WL_WDS_WPA_ROLE_SUP, WL_WDS_WPA_ROLE_AUTO);
+ break;
+ }
+ }
+ else if ((ret = wlu_get(wl, cmd->get, var, len)) < 0) {
+ printf("Unable to get local endpoint's WPA role\n");
+ return ret;
+ }
+ else {
+ sup = var;
+ printf("Local endpoint's WPA role: %s\n", *sup ? "supplicant" : "authenticator");
+ }
+ return ret;
+}
+
+#if defined(DWDS)
+static int
+wl_dwds_config(void *wl, cmd_t *cmd, char **argv)
+{
+ wlc_dwds_config_t dwds;
+ int err;
+
+ memset(&dwds, 0, sizeof(wlc_dwds_config_t));
+
+ if (!*++argv) {
+ printf("error: missing arguments\n");
+ return -1;
+ }
+
+ if (!stricmp(*argv, "enable"))
+ dwds.enable = 1;
+ else if (!stricmp(*argv, "disable"))
+ dwds.enable = 0;
+ else {
+ printf("error: unknown mode option %s\n", *argv);
+ return -1;
+ }
+ argv++;
+ /* look for sta/dwds */
+ if (!stricmp(*argv, "sta"))
+ dwds.mode = 1;
+ else if (!stricmp(*argv, "ap"))
+ dwds.mode = 0;
+ else {
+ printf("error: unknown mode option %s\n", *argv);
+ return -1;
+ }
+
+ argv++;
+ /* convert the ea string into an ea struct */
+ if (!*argv || !wl_ether_atoe(*argv, &dwds.ea)) {
+ printf(" ERROR: no valid ether addr provided\n");
+ return -1;
+ }
+
+ if ((err = wlu_iovar_set(wl, cmd->name, &dwds, sizeof(wlc_dwds_config_t))) < 0)
+ return err;
+
+ return (0);
+
+}
+#endif /* DWDS */
diff --git a/wl/src/wl/exe/wluc_wnm.c b/wl/src/wl/exe/wluc_wnm.c
new file mode 100644
index 0000000..8480b80
--- /dev/null
+++ b/wl/src/wl/exe/wluc_wnm.c
@@ -0,0 +1,1711 @@
+/*
+ * wl wnm command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_wnm.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_wnm_bsstrans_roamthrottle;
+static cmd_func_t wl_wnm_bsstrans_rssi_rate_map;
+static cmd_func_t wl_wnm_bss_select_table;
+static cmd_func_t wl_wnm_bss_select_weight;
+static cmd_func_t wl_wnm;
+static cmd_func_t wl_wnm_bsstq;
+static cmd_func_t wl_tclas_add;
+static cmd_func_t wl_tclas_del;
+static cmd_func_t wl_tclas_list;
+static cmd_func_t wl_wnm_tfsreq_add;
+static cmd_func_t wl_wnm_dms_set;
+static cmd_func_t wl_wnm_dms_status;
+static cmd_func_t wl_wnm_dms_term;
+static cmd_func_t wl_wnm_service_term;
+static cmd_func_t wl_wnm_timbc_offset;
+static cmd_func_t wl_wnm_timbc_set;
+static cmd_func_t wl_wnm_timbc_status;
+static cmd_func_t wl_wnm_maxidle;
+static cmd_func_t wl_wnm_bsstrans_req;
+static cmd_func_t wl_wnm_keepalives_max_idle;
+static cmd_func_t wl_wnm_url;
+
+static cmd_t wl_wnm_cmds[] = {
+ { "wnm", wl_wnm, WLC_GET_VAR, WLC_SET_VAR,
+ "set driver wnm feature mask\n"
+ "\ttype \'wl msglevel ?\' for values" },
+ { "wnm_bsstq", wl_wnm_bsstq, -1, WLC_SET_VAR,
+ "send 11v BSS transition management query\n"
+ "\tUsage: wl wnm_bsstq [ssid]"},
+ { "tclas_add", wl_tclas_add, -1, WLC_SET_VAR,
+ "add tclas frame classifier type entry\n"
+ "\tUsage: wl tclas_add <user priority> <type> <mask> <...>\n"
+ "\ttype 0 eth2: <src mac> <dst mac> <ether type>\n"
+ "\ttype 1/4 ipv4: <ver> <src> <dst> <s_port> <d_port> <dscp> <prot>\n"
+ "\ttype 2 802.1Q: <vlan tag>\n"
+ "\ttype 3 filter: <offset> <value> <mask>\n"
+ "\ttype 4 ipv6: <ver> <src> <dst> <s_port> <d_port> <dscp> <nxt_hdr> <flw_lbl>\n"
+ "\ttype 5 802.1D/Q: <802.1Q PCP> <802.1Q CFI> <802.1Q VID>"
+ },
+ { "tclas_del", wl_tclas_del, -1, WLC_SET_VAR,
+ "delete tclas frame classifier type entry\n"
+ "\tUsage: wl tclas_del [<idx> [<len>]]"
+ },
+ { "tclas_list", wl_tclas_list, WLC_GET_VAR, -1,
+ "list the added tclas frame classifier type entry\n"
+ "\tUsage: wl tclas_list"
+ },
+ { "wnm_tfsreq_add", wl_wnm_tfsreq_add, -1, WLC_SET_VAR,
+ "add one tfs request element and send tfs request frame\n"
+ "\tUsage: wl wnm_tfsreq_add <tfs_id> <tfs_action_code> <tfs_subelem_id> <send>\n"
+ "\ttfs_id: a non-zero value (1 ~ 255)\n"
+ "\ttfs_action_code bitfield: 1: delete after match, 2: notify\n"
+ "\ttfs_subelem_id: TFS subelement (0 for none or 1 for previous tclas_add)\n"
+ "\tsend: 0: store element, 1: send all stored elements"
+ },
+ { "wnm_dms_set", wl_wnm_dms_set, -1, WLC_SET_VAR,
+ "Optionally add pending DMS desc (after tclas_add) and optionally register all desc\n"
+ "on AP side to enable the service (with send=1)"
+ "\tUsage: wl wnm_dms_set <send> [<user_id> [<tc_pro>]]\n"
+ "\t\tsend: 0: store descriptor, 1: send all stored descs/enable DMS on AP\n"
+ "\t\tuser_id: new ID to assign to the created desc (if TCLAS added)\n"
+ "\t\t or existing ID to enable on AP (if no TCLAS added), 0 for all desc\n"
+ "\t\ttc_pro: TCLAS processing element (if several TCLAS added)"
+ },
+ { "wnm_dms_status", wl_wnm_dms_status, WLC_GET_VAR, -1,
+ "list all DMS descriptors and provide their internal and AP status\n"
+ "\tUsage: wl wl_wnm_dms_status"
+ },
+ { "wnm_dms_term", wl_wnm_dms_term, -1, WLC_SET_VAR,
+ "Disable registered DMS des on AP side and optionally discard them\n"
+ "\tUsage: wl wnm_dms_term <del> [<user_id>]\n"
+ "\t\tdel: Discard desc after disabling the service on AP side\n"
+ "\t\tuser_id: desc to disable/delete, 0 for all desc"
+ },
+ { "wnm_service_term", wl_wnm_service_term, -1, WLC_SET_VAR,
+ "Disable service. Check specific wnm_XXX_term for more info\n"
+ "\tUsage: wl wnm_service_term <srv> <service realted params>\n"
+ "\t\tsrv: 1 for DMS, 2 for FMS, 3 for TFS"
+ },
+ { "wnm_timbc_offset", wl_wnm_timbc_offset, WLC_GET_VAR, WLC_SET_VAR,
+ "get/set TIM broadcast offset by -32768 period > offset(us) > 32768\n"
+ "CAUTION!! Due to resource limitation, one radio can have only one set of TIMBC offset\n"
+ "setting. MBSS need to share the same setting\n"
+ "\tUsage: wl wnm_timbc_offset <offset> [<tsf_present> [<fix_interval> [<rate_ovreride>]]]\n"
+ "\t\toffset: in unit of us. Transmit TIM frame in specific TBTT transmit time time\n"
+ "\t\ttsf_present: can be omitted. If set to 1, timestamp field will present in TIM frame."
+ "If omitted, default setup to 1\n"
+ "\t\tfix_interval: can be omitted. If set with non-zero value, override STA request "
+ "interval in TIM Broadcast request. If omitted, default setup to 0\n"
+ "\t\trate_override: can be omitted. In unit of 500k, max setup to 108. If set, override"
+ "override high rate used to transmit TIM broadcast high rate frame"
+ },
+ { "wnm_timbc_set", wl_wnm_timbc_set, -1, WLC_SET_VAR,
+ "Enable/disable TIM Broadcast. Station will send appropriate request if AP suport TIMBC\n"
+ "\tUsage: wl wnm_timbc_set <interval> [<flags> [<min_rate> [<max_rate>]]]\n"
+ "\t\tinterval: Beacon interval requested for TIM frames, 0 to disable TIM BC\n"
+ "\t\tflags: Bitfield with minimal requirements to keep the service enabled (check doc)\n"
+ "\t\tmin_rate: Minimal rate requirement, in Mbps, for TIM high or low rate frames\n"
+ "\t\tmax_rate: Maximal rate requirement"
+ },
+ { "wnm_timbc_status", wl_wnm_timbc_status, WLC_GET_VAR, -1,
+ "Retrieve TIM Broadcast configuration set with current AP"
+ },
+ { "wnm_maxidle", wl_wnm_maxidle, WLC_GET_VAR, WLC_SET_VAR,
+ "setup WNM BSS Max Idle Period interval and option\n"
+ "\tUsage: wl wnm_maxidle <Idle Period> <Option>\n"
+ "\tIdle Period: in unit of 1000TU(1.024s)\n"
+ "\tOption: protected keep alive required(0 ~ 1)"
+ },
+ { "wnm_bsstrans_query", wl_wnm_bsstq, -1, WLC_SET_VAR,
+ "send 11v BSS transition management query\n"
+ "\tUsage: wl wnm_bsstrans_query [ssid]"},
+ { "wnm_bsstrans_req", wl_wnm_bsstrans_req, -1, WLC_SET_VAR,
+ "send BSS transition management request frame with BSS termination included bit set\n"
+ "\tUsage: wl wnm_bsstrans_req <reqmode> <tbtt> <dur> [unicast]\n"
+ "\treqmode: request mode of BSS transition request\n"
+ "\ttbtt: time of BSS to end of life, in unit of TBTT, max to 65535\n"
+ "\tdur: time of BSS to keep off, in unit of minute, max to 65535\n"
+ "\tunicast: [1|0] unicast or broadcast to notify STA in BSS. Default in unicast."
+ },
+ { "wnm_keepalives_max_idle", wl_wnm_keepalives_max_idle, -1, -1,
+ "\tUsage: wl wnm_keepalives_max_idle <keepalives_per_bss_max_idle> <mkeepalive_index>"
+ " [<max_interval>]\n"
+ "set/get the number of keepalives, mkeep-alive index and max_interval configured"
+ " per BSS-Idle period."},
+ { "wnm_url", wl_wnm_url, WLC_GET_VAR, WLC_SET_VAR,
+ "set/get wnm session information url\n"
+ "Usage for set: wl wnm_url length urlstring\n"
+ "Usage for get: wl wnm_url" },
+ { "wnm_bsstrans_roamthrottle", wl_wnm_bsstrans_roamthrottle, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set number of roam scans allowed in throttle period\n"
+ "\tUsage: wl wnm_bsstrans_roamthrottle [throttle_period] [scans_allowed]"
+ },
+ { "wnm_bsstrans_rssi_rate_map", wl_wnm_bsstrans_rssi_rate_map, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set rssi to rate map\n"
+ "\tUsage: wl wnm_bsstrans_rssi_rate_map mode data\n"
+ "\tData is interpeted based on mode\n"
+ "\tFor mode=0: data = rssi0, rssi1, rssi2.... as per wl_bsstrans_rssi_rate_map_t\n"
+ "\tFor mode=1: data = phy-type band streams rssi0, rssi1...\n"
+ "\t\twhere, phy-type = cck, ofdm, 11n, 11ac\n"
+ "\t\tband = 2g or 5g for ofdm, 11n and 11ac. Only 2g for cck\n"
+ "\t\tstreams = Only 1 for cck and ofdm. 1 to 4 for 11n and 11ac\n"
+ "\t\trssiX = monotonically non-decreasing rssi values for the combination of phy-type,\n"
+ "\t\tband and streams. Max rssi values for 11ac: 10, 11n: 8, ofdm: 8, cck: 4"
+ },
+ { "wnm_bss_select_table", wl_wnm_bss_select_table, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set RSSI or Channel usage factor table in AP Selection\n"
+ "\tGet: wnm_bss_select_table [rssi|cu] [a|b]\n"
+ "\tSet: wnm_bss_select_table [rssi|cu] <tuple> [a|b|all]"
+ },
+ { "wnm_bss_select_weight", wl_wnm_bss_select_weight, WLC_GET_VAR, WLC_SET_VAR,
+ "Get/Set RSSI or Channel usage weightage in AP selection\n"
+ "\tGet: wnm_bss_select_weight [rssi|cu] [a|b]\n"
+ "\tSet: wnm_bss_select_weight [rssi|cu] <integer> [a|b|all]"
+ },
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_wnm_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register wnm commands */
+ wl_module_cmds_register(wl_wnm_cmds);
+}
+
+static int
+wl_wnm_bsstrans_roamthrottle(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen;
+ wl_bsstrans_roamthrottle_t *throttle;
+
+ buflen = sprintf(buf, "%s", *argv) + 1;
+
+ if (*++(argv) == NULL) {
+ buf[buflen] = '\0';
+ err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN);
+ if (err < 0)
+ return err;
+
+ throttle = (wl_bsstrans_roamthrottle_t *)buf;
+ printf("period %u\n", throttle->period);
+ printf("scans allowed per period %u\n", throttle->scans_allowed);
+ return 0;
+
+ } else {
+ throttle = (wl_bsstrans_roamthrottle_t *) (buf + buflen);
+ buflen += sizeof(*throttle);
+ throttle->ver = WL_BSSTRANS_ROAMTHROTTLE_VERSION;
+ throttle->period = (uint32) strtoul(*argv, NULL, 0);
+
+ if (*++(argv) == NULL) {
+ printf("Incorrect number of arguments\n");
+ return BCME_ERROR;
+ }
+ throttle->scans_allowed = (uint16) strtoul(*argv, NULL, 0);
+
+ if (*++(argv)) {
+ printf("extra arguments\n");
+ return BCME_ERROR;
+ }
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+ }
+ return 0;
+}
+#define RSSI_RATE_MAP_PHY_TYPE_CCK 0
+#define RSSI_RATE_MAP_PHY_TYPE_OFDM 1
+#define RSSI_RATE_MAP_PHY_TYPE_N 2
+#define RSSI_RATE_MAP_PHY_TYPE_AC 3
+
+static int
+wl_wnm_bsstrans_rssi_rate_map(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen;
+ wl_bsstrans_rssi_rate_map_t *map;
+ int i;
+ uint32 mode;
+
+ buflen = sprintf(buf, "%s", *argv) + 1;
+
+ if (*++(argv) == NULL) {
+ printf("Mode is required \n");
+ return BCME_ERROR;
+ }
+ mode = (uint32)atoi(*argv);
+ if (mode > 1) {
+ printf("Mode can only be 0 or 1\n");
+ return BCME_ERROR;
+ }
+
+ if (mode == 0) {
+ /* Get */
+ if (*++(argv) == NULL) {
+ buf[buflen] = '\0';
+ err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN);
+ if (err < 0)
+ return err;
+
+ map = (wl_bsstrans_rssi_rate_map_t *)buf;
+
+ printf("cck rssi-2g:\n");
+ for (i = 0; i < WL_NUM_RATES_CCK; i++) {
+ printf("%d, ", map->cck[i].rssi_2g);
+ }
+ printf("\n");
+
+ printf("cck rssi-5g:\n");
+ for (i = 0; i < WL_NUM_RATES_CCK; i++) {
+ printf("%d, ", map->cck[i].rssi_5g);
+ }
+ printf("\n");
+
+ printf("ofdm rssi-2g:\n");
+ for (i = 0; i < WL_NUM_RATES_OFDM; i++) {
+ printf("%d, ", map->ofdm[i].rssi_2g);
+ }
+ printf("\n");
+
+ printf("ofdm rssi-5g:\n");
+ for (i = 0; i < WL_NUM_RATES_OFDM; i++) {
+ printf("%d, ", map->ofdm[i].rssi_5g);
+ }
+ printf("\n");
+
+ printf("phy_n 1x1 rssi-2g:\n");
+ for (i = 0; i < WL_NUM_RATES_MCS_1STREAM; i++) {
+ printf("%d, ", map->phy_n[0][i].rssi_2g);
+ }
+ printf("\n");
+
+ printf("phy_n 1x1 rssi-5g:\n");
+ for (i = 0; i < WL_NUM_RATES_MCS_1STREAM; i++) {
+ printf("%d, ", map->phy_n[0][i].rssi_5g);
+ }
+ printf("\n");
+
+ printf("phy_n 2x2 rssi-2g:\n");
+ for (i = 0; i < WL_NUM_RATES_MCS_1STREAM; i++) {
+ printf("%d, ", map->phy_n[1][i].rssi_2g);
+ }
+ printf("\n");
+
+ printf("phy_n 2x2 rssi-5g:\n");
+ for (i = 0; i < WL_NUM_RATES_MCS_1STREAM; i++) {
+ printf("%d, ", map->phy_n[1][i].rssi_5g);
+ }
+ printf("\n");
+
+ printf("phy_ac 1x1 rssi-2g:\n");
+ for (i = 0; i < WL_NUM_RATES_VHT; i++) {
+ printf("%d, ", map->phy_ac[0][i].rssi_2g);
+ }
+ printf("\n");
+
+ printf("phy_ac 1x1 rssi-5g:\n");
+ for (i = 0; i < WL_NUM_RATES_VHT; i++) {
+ printf("%d, ", map->phy_ac[0][i].rssi_5g);
+ }
+ printf("\n");
+
+ printf("phy_ac 2x2 rssi-2g:\n");
+ for (i = 0; i < WL_NUM_RATES_VHT; i++) {
+ printf("%d, ", map->phy_ac[1][i].rssi_2g);
+ }
+ printf("\n");
+
+ printf("phy_ac 2x2 rssi-5g:\n");
+ for (i = 0; i < WL_NUM_RATES_VHT; i++) {
+ printf("%d, ", map->phy_ac[1][i].rssi_5g);
+ }
+ printf("\n");
+
+ return 0;
+ } else { /* Set */
+ int8 *rssi;
+ uint32 len = 0;
+ map = (wl_bsstrans_rssi_rate_map_t *) (buf + buflen);
+ rssi = (int8 *)map->cck;
+ buflen += sizeof(*map);
+ map->ver = WL_BSSTRANS_RSSI_RATE_MAP_VERSION;
+ while (*argv) {
+ *rssi++ = (int8) strtol(*argv, NULL, 0);
+ len++;
+ argv++;
+ }
+ map->len = sizeof(map->ver) + sizeof(map->len) + len;
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+ return err;
+ }
+ } else { /* Mode 1 */
+ uint32 phy_type, band, streams;
+
+ if (*++(argv) == NULL) {
+ goto insufficient_params;
+ }
+ if (!strcmp(*argv, "cck")) {
+ phy_type = RSSI_RATE_MAP_PHY_TYPE_CCK;
+ }
+ else if (!strcmp(*argv, "ofdm")) {
+ phy_type = RSSI_RATE_MAP_PHY_TYPE_OFDM;
+ }
+ else if (!strcmp(*argv, "11n")) {
+ phy_type = RSSI_RATE_MAP_PHY_TYPE_N;
+ }
+ else if (!strcmp(*argv, "11ac")) {
+ phy_type = RSSI_RATE_MAP_PHY_TYPE_AC;
+ }
+ else {
+ printf("Wrong phy-type: only cck/ofdm/11n/11ac supported\n");
+ return BCME_ERROR;
+ }
+
+ if (*++(argv) == NULL) {
+ goto insufficient_params;
+ }
+
+ if (!strcmp(*argv, "2g")) {
+ band = 0;
+ }
+ else if (!strcmp(*argv, "5g")) {
+ if (phy_type == RSSI_RATE_MAP_PHY_TYPE_CCK) {
+ printf("cck not allowed on 5g\n");
+ return BCME_ERROR;
+ }
+ band = 1;
+ }
+ else {
+ printf("Wrong band-type: only '2g' and '5g' are supported\n");
+ return BCME_ERROR;
+ }
+
+ if (*++(argv) == NULL) {
+ goto insufficient_params;
+ }
+
+ streams = atoi(*argv);
+ if (streams < 1 || streams > 4) {
+ printf("Wrong number of streams: Only 1 to 4 supported\n");
+ return BCME_ERROR;
+ }
+ if ((phy_type == RSSI_RATE_MAP_PHY_TYPE_CCK ||
+ phy_type == RSSI_RATE_MAP_PHY_TYPE_OFDM) && streams > 1) {
+ printf("Only 1 stream allowed for CCK/OFDM\n");
+ return BCME_ERROR;
+ }
+
+ buf[buflen] = '\0';
+ err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN);
+ if (err < 0) {
+ return err;
+ }
+ map = (wl_bsstrans_rssi_rate_map_t *)buf;
+
+ /* GET */
+ if (*++(argv) == NULL) {
+ switch (phy_type) {
+ case RSSI_RATE_MAP_PHY_TYPE_CCK:
+ printf("cck rssi-2g:\n");
+ for (i = 0; i < WL_NUM_RATES_CCK; i++) {
+ printf("%d, ", map->cck[i].rssi_2g);
+ }
+ printf("\n");
+ break;
+ case RSSI_RATE_MAP_PHY_TYPE_OFDM:
+ printf("ofdm rssi-%sg:\n", band == 0?"2":"5");
+ for (i = 0; i < WL_NUM_RATES_OFDM; i++) {
+ if (band == 0)
+ printf("%d, ", map->ofdm[i].rssi_2g);
+ else
+ printf("%d, ", map->ofdm[i].rssi_5g);
+ }
+ printf("\n");
+ break;
+ case RSSI_RATE_MAP_PHY_TYPE_N:
+ printf("11N streams:%dx%d rssi-%sg:\n", streams,
+ streams, band == 0 ? "2" : "5");
+ for (i = 0; i < WL_NUM_RATES_MCS_1STREAM; i++) {
+ if (band == 0) {
+ printf("%d, ", map->phy_n[streams-1][i].rssi_2g);
+ } else {
+ printf("%d, ", map->phy_n[streams-1][i].rssi_5g);
+ }
+ }
+ printf("\n");
+ break;
+ case RSSI_RATE_MAP_PHY_TYPE_AC:
+ printf("11AC streams:%dx%d rssi-%sg:\n", streams,
+ streams, band == 0 ? "2" : "5");
+ for (i = 0; i < WL_NUM_RATES_VHT; i++) {
+ if (band == 0) {
+ printf("%d, ", map->phy_ac[streams-1][i].rssi_2g);
+ } else {
+ printf("%d, ", map->phy_ac[streams-1][i].rssi_5g);
+ }
+ }
+ printf("\n");
+ break;
+ }
+ } else { /* Set */
+ int cmdlen = strlen(cmd->name);
+
+ /* Make space for writing cmd name */
+ memmove(buf+cmdlen+1, buf, sizeof(*map));
+
+ buflen = sprintf(buf, "%s", cmd->name) + 1;
+ buf[buflen] = '\0';
+
+ /* SET */
+ map = (wl_bsstrans_rssi_rate_map_t *) (buf + buflen);
+
+ switch (phy_type) {
+ case RSSI_RATE_MAP_PHY_TYPE_CCK:
+ for (i = 0; i < WL_NUM_RATES_CCK; i++) {
+ if (*argv == NULL) {
+ break;
+ }
+ map->cck[i].rssi_2g = (int8) strtol(*argv, NULL, 0);
+ argv++;
+ }
+ break;
+ case RSSI_RATE_MAP_PHY_TYPE_OFDM:
+ for (i = 0; i < WL_NUM_RATES_OFDM; i++) {
+ if (*argv == NULL) {
+ break;
+ }
+ if (band == 0) {
+ map->ofdm[i].rssi_2g = (int8)strtol(*argv, NULL, 0);
+ } else {
+ map->ofdm[i].rssi_5g = (int8)strtol(*argv, NULL, 0);
+ }
+ argv++;
+ }
+ break;
+ case RSSI_RATE_MAP_PHY_TYPE_N:
+ for (i = 0; i < WL_NUM_RATES_MCS_1STREAM; i++) {
+ if (*argv == NULL) {
+ break;
+ }
+ if (band == 0) {
+ map->phy_n[streams-1][i].rssi_2g =
+ (int8)strtol(*argv, NULL, 0);
+ } else {
+ map->phy_n[streams-1][i].rssi_5g =
+ (int8)strtol(*argv, NULL, 0);
+ }
+ argv++;
+ }
+ break;
+ case RSSI_RATE_MAP_PHY_TYPE_AC:
+ for (i = 0; i < WL_NUM_RATES_VHT; i++) {
+ if (*argv == NULL) {
+ break;
+ }
+ if (band == 0) {
+ map->phy_ac[streams-1][i].rssi_2g =
+ (int8)strtol(*argv, NULL, 0);
+ } else {
+ map->phy_ac[streams-1][i].rssi_5g =
+ (int8)strtol(*argv, NULL, 0);
+ }
+ argv++;
+ }
+ break;
+ }
+
+ buflen += sizeof(*map);
+ map->ver = WL_BSSTRANS_RSSI_RATE_MAP_VERSION;
+ map->len = sizeof(*map);
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+ return err;
+ }
+ return 0;
+insufficient_params:
+ printf("Insufficient params for mode 1\n");
+ return BCME_ERROR;
+ } /* Mode 1 */
+ return 0;
+}
+
+static dbg_msg_t wl_wnm_msgs[] = {
+ {WL_WNM_BSSTRANS, "BSS-Transition"},
+ {WL_WNM_PROXYARP, "Proxy-ARP"},
+ {WL_WNM_MAXIDLE, "BSS-Max-Idle-Period"},
+ {WL_WNM_TIMBC, "TIM-Broadcast"},
+ {WL_WNM_TFS, "Traffic-Filtering"},
+ {WL_WNM_SLEEP, "WNM-Sleep-Mode"},
+ {WL_WNM_DMS, "Directed-Multicast"},
+ {WL_WNM_FMS, "Flexible-Multicast"},
+ {WL_WNM_NOTIF, "Notification"},
+ {0, ""}
+};
+
+static int
+wl_wnm(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret, i;
+ uint val;
+ int wnmmask;
+ char *s;
+
+ ret = wlu_iovar_getint(wl, cmd->name, &wnmmask);
+ if (ret < 0)
+ return ret;
+
+ if (!*++argv) {
+ printf("0x%x:", wnmmask);
+ for (i = 0; wl_wnm_msgs[i].value; i++)
+ if (wnmmask & wl_wnm_msgs[i].value)
+ printf(" %s", wl_wnm_msgs[i].string);
+ printf("\n");
+ return 0;
+ }
+
+ s = *argv;
+ if (*s == '+' || *s == '-')
+ s++;
+
+ if (!*s)
+ goto usage;
+
+ val = strtoul(s, &s, 0);
+ if (*s)
+ goto usage;
+
+ if (**argv == '+')
+ wnmmask |= val;
+ else if (**argv == '-')
+ wnmmask &= ~val;
+ else
+ wnmmask = val;
+
+ return wlu_iovar_setint(wl, cmd->name, wnmmask);
+
+usage:
+ fprintf(stderr, "WNM mask is a bitfield from the following set. "
+ "Use + or - prefix to combine with current value:\n");
+
+ for (i = 0; wl_wnm_msgs[i].value; i++)
+ fprintf(stderr, " 0x%04x %s\n", wl_wnm_msgs[i].value, wl_wnm_msgs[i].string);
+
+ return 0;
+}
+
+static int
+wl_wnm_bsstq(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen;
+ wlc_ssid_t ssid;
+
+ UNUSED_PARAMETER(cmd);
+
+ strcpy(buf, "wnm_bsstrans_query");
+ buflen = strlen("wnm_bsstrans_query") + 1;
+
+ if (*++argv) {
+ uint32 len;
+
+ len = strlen(*argv);
+ if (len > DOT11_MAX_SSID_LEN) {
+ printf("ssid too long\n");
+ return (-1);
+ }
+ memset(&ssid, 0, sizeof(wlc_ssid_t));
+ memcpy(ssid.SSID, *argv, len);
+ ssid.SSID_len = len;
+ memcpy(&buf[buflen], &ssid, sizeof(wlc_ssid_t));
+ buflen += sizeof(wlc_ssid_t);
+ }
+
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+}
+
+#define TCLAS_ARG_CHECK(argv, str) \
+ do { \
+ if (*++(argv) == NULL) { \
+ printf("TCLAS Frame Classifier: %s not provided\n", (str)); \
+ return BCME_ERROR; \
+ } \
+ } while (0)
+
+static int
+wl_tclas_add(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1, buflen;
+ dot11_tclas_fc_t *fc;
+
+ UNUSED_PARAMETER(cmd);
+
+ buflen = sprintf(buf, "%s", *argv) + 1;
+
+ /* Check the user priority value */
+ TCLAS_ARG_CHECK(argv, "user priority");
+ buf[buflen++] = (uint8)strtoul(*argv, NULL, 0);
+
+ /* unaligned! */
+ fc = (dot11_tclas_fc_t *) (buf + buflen);
+ memset((void *)fc, 0, sizeof(dot11_tclas_fc_t));
+
+ /* Parse frame classifier type and mask */
+ TCLAS_ARG_CHECK(argv, "type");
+ fc->hdr.type = (uint8)strtoul(*argv, NULL, 0);
+
+ TCLAS_ARG_CHECK(argv, "mask");
+ fc->hdr.mask = (uint8)strtoul(*argv, NULL, 0);
+ if (fc->hdr.type == DOT11_TCLAS_FC_0_ETH) {
+ dot11_tclas_fc_0_eth_t *fc_eth = (dot11_tclas_fc_0_eth_t *)fc;
+
+ TCLAS_ARG_CHECK(argv, "src mac");
+ if (strlen(*argv) > 1) {
+ if (!wl_ether_atoe(*argv, (struct ether_addr *)fc_eth->sa)) {
+ printf(" ERROR: no valid src ether addr provided\n");
+ return BCME_ERROR;
+ }
+ }
+ else
+ memset(fc_eth->sa, 0, ETHER_ADDR_LEN);
+
+ TCLAS_ARG_CHECK(argv, "dst mac");
+ if (strlen(*argv) > 1) {
+ if (!wl_ether_atoe(*argv, (struct ether_addr *)fc_eth->da)) {
+ printf(" ERROR: no valid dst ether addr provided\n");
+ return BCME_ERROR;
+ }
+ }
+ else
+ memset(fc_eth->da, 0, ETHER_ADDR_LEN);
+
+ TCLAS_ARG_CHECK(argv, "ether type");
+ fc_eth->eth_type = hton16((uint16)strtoul(*argv, NULL, 0));
+
+ buflen += DOT11_TCLAS_FC_0_ETH_LEN;
+
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+ }
+ else if (fc->hdr.type == DOT11_TCLAS_FC_1_IP ||
+ fc->hdr.type == DOT11_TCLAS_FC_4_IP_HIGHER) {
+ uint8 version;
+
+ TCLAS_ARG_CHECK(argv, "ip version");
+ version = (uint8)strtoul(*argv, NULL, 0);
+ if (version == IP_VER_6) {
+ dot11_tclas_fc_4_ipv6_t *fc_ipv6 = (dot11_tclas_fc_4_ipv6_t *)fc;
+ uint32 fl;
+
+ fc_ipv6->version = version;
+
+ TCLAS_ARG_CHECK(argv, "ipv6 source ip");
+ if (!wl_atoipv6(*argv, (struct ipv6_addr *)&fc_ipv6->saddr)) {
+ printf("incorrect ipv6 source ip format\n");
+ return BCME_ERROR;
+ }
+
+ TCLAS_ARG_CHECK(argv, "ipv6 dest ip");
+ if (!wl_atoipv6(*argv, (struct ipv6_addr *)&fc_ipv6->daddr)) {
+ printf("incorrect ipv6 dest ip format\n");
+ return BCME_ERROR;
+ }
+
+ TCLAS_ARG_CHECK(argv, "ipv6 source port");
+ fc_ipv6->src_port = hton16((uint16)strtoul(*argv, NULL, 0));
+
+ TCLAS_ARG_CHECK(argv, "ipv6 dest port");
+ fc_ipv6->dst_port = hton16((uint16)strtoul(*argv, NULL, 0));
+
+ TCLAS_ARG_CHECK(argv, "ipv6 dscp");
+ fc_ipv6->dscp = (uint8)strtoul(*argv, NULL, 0);
+
+ TCLAS_ARG_CHECK(argv, "ipv6 next header");
+ fc_ipv6->nexthdr = (uint8)strtoul(*argv, NULL, 0);
+
+ TCLAS_ARG_CHECK(argv, "ipv6 flow label");
+ fl = (uint32) strtoul(*argv, NULL, 0);
+ fc_ipv6->flow_lbl[2] = (fl >> 16) & 0xFF;
+ fc_ipv6->flow_lbl[1] = (fl >> 8) & 0xFF;
+ fc_ipv6->flow_lbl[0] = (fl >> 0) & 0xFF;
+
+ buflen += DOT11_TCLAS_FC_4_IPV6_LEN;
+
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ } else
+ if (version == IP_VER_4) {
+ dot11_tclas_fc_1_ipv4_t *fc_ipv4 = (dot11_tclas_fc_1_ipv4_t *)fc;
+
+ fc_ipv4->version = version;
+
+ TCLAS_ARG_CHECK(argv, "ipv4 source ip");
+ if (!wl_atoip(*argv, (struct ipv4_addr *)&fc_ipv4->src_ip)) {
+ printf("incorrect source ip format\n");
+ return BCME_ERROR;
+ }
+
+ TCLAS_ARG_CHECK(argv, "ipv4 dest ip");
+ if (!wl_atoip(*argv, (struct ipv4_addr *)&fc_ipv4->dst_ip)) {
+ printf("incorrect dest ip format\n");
+ return BCME_ERROR;
+ }
+
+ TCLAS_ARG_CHECK(argv, "ipv4 source port");
+ fc_ipv4->src_port = (uint16)strtoul(*argv, NULL, 0);
+ fc_ipv4->src_port = hton16(fc_ipv4->src_port);
+
+ TCLAS_ARG_CHECK(argv, "ipv4 dest port");
+ fc_ipv4->dst_port = (uint16)strtoul(*argv, NULL, 0);
+ fc_ipv4->dst_port = hton16(fc_ipv4->dst_port);
+
+ TCLAS_ARG_CHECK(argv, "ipv4 dscp");
+ fc_ipv4->dscp = (uint8)strtoul(*argv, NULL, 0);
+
+ TCLAS_ARG_CHECK(argv, "ipv4 protocol");
+ fc_ipv4->protocol = (uint8)strtoul(*argv, NULL, 0);
+
+ buflen += DOT11_TCLAS_FC_1_IPV4_LEN;
+
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+ } else
+ return BCME_ERROR;
+ } else {
+ printf("Unsupported frame classifier type 0x%2x\n", fc->hdr.type);
+ return BCME_ERROR;
+ }
+
+ return err;
+}
+
+static int
+wl_tclas_del(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen, totlen;
+
+ UNUSED_PARAMETER(cmd);
+
+ buflen = sprintf(buf, "%s", *argv) + 1;
+ totlen = buflen + 2;
+
+ /* Set initial length */
+ buf[buflen] = 0; /* first value present for init index */
+ buf[buflen + 1] = 0; /* second value present for delete count */
+
+ /* Check idx and add if present */
+ if (*++argv == NULL)
+ goto set;
+ buf[buflen] = 1;
+ buf[buflen + 1] = (uint8)strtoul(*argv, NULL, 0);
+
+ /* Check len and add if present */
+ if (*++argv == NULL)
+ goto set;
+ buf[buflen] = 2;
+ buf[buflen + 2] = (uint8)strtoul(*argv, NULL, 0);
+
+ if (*++argv) {
+ printf("Too much args provided\n");
+ return BCME_ERROR;
+ }
+set:
+ err = wlu_set(wl, WLC_SET_VAR, buf, totlen);
+
+ return err;
+}
+
+
+static void
+wl_tclas_dump(wl_tclas_t *tclas)
+{
+ dot11_tclas_fc_hdr_t *fc = &tclas->fc.hdr;
+ dot11_tclas_fc_0_eth_t *eth = &tclas->fc.t0_eth;
+ dot11_tclas_fc_1_ipv4_t *ipv4 = &tclas->fc.t1_ipv4;
+ dot11_tclas_fc_4_ipv6_t *ipv6 = &tclas->fc.t4_ipv6;
+
+#define TCDMP(x) ((fc->mask & (x))?'+':'-')
+
+ printf("up %d type %d mask 0x%x ", tclas->user_priority, fc->type, fc->mask);
+
+ /* Check frame classifier parameter type */
+ if (fc->type == DOT11_TCLAS_FC_0_ETH) {
+ printf("(Eth: ");
+ printf("%cSA %s ", TCDMP(1), wl_ether_etoa((struct ether_addr*)eth->sa));
+ printf("%cDA %s ", TCDMP(2), wl_ether_etoa((struct ether_addr*)eth->da));
+ printf("%ctype 0x%04x", TCDMP(4), ntoh16(eth->eth_type));
+ printf(")\n");
+ } else if (fc->type == DOT11_TCLAS_FC_1_IP ||
+ (fc->type == DOT11_TCLAS_FC_4_IP_HIGHER && ipv4->version == IP_VER_4)) {
+ /* Check parameter type 1/4 IPv4 version */
+ printf("(IPv4: ");
+ printf("%cver %d ", TCDMP(1), ipv4->version);
+ printf("%csip %s ", TCDMP(2), wl_iptoa((struct ipv4_addr *)&ipv4->src_ip));
+ printf("%cdip %s ", TCDMP(4), wl_iptoa((struct ipv4_addr *)&ipv4->dst_ip));
+ printf("%csp %d ", TCDMP(8), ntoh16(ipv4->src_port));
+ printf("%cdp %d ", TCDMP(16), ntoh16(ipv4->dst_port));
+ printf("%cdscp 0x%x ", TCDMP(32), ipv4->dscp);
+ printf("%cprot %d", TCDMP(64), ipv4->protocol);
+ printf(")\n");
+ } else if (fc->type == DOT11_TCLAS_FC_4_IP_HIGHER && ipv6->version == IP_VER_6) {
+ /* Check parameter type 4 IPv6 version */
+ printf("(IPv6: ");
+ printf("%cver %d ", TCDMP(1), ipv6->version);
+ printf("%csip %s ", TCDMP(2), wl_ipv6toa(ipv6->saddr));
+ printf("%cdip %s ", TCDMP(4), wl_ipv6toa(ipv6->daddr));
+ printf("%csp %d ", TCDMP(8), ntoh16(ipv6->src_port));
+ printf("%cdp %d ", TCDMP(16), ntoh16(ipv6->dst_port));
+ printf("%cdscp 0x%x ", TCDMP(32), ipv6->dscp);
+ printf("%cprot %d", TCDMP(64), ipv6->nexthdr);
+ printf("%cfl %d", TCDMP(64),
+ ipv6->flow_lbl[2]<<16 | ipv6->flow_lbl[1]<<8 | ipv6->flow_lbl[0]);
+ printf(")\n");
+ } else {
+ printf("(type unsupported)\n");
+ }
+}
+
+static int
+wl_tclas_list_parse(wl_tclas_list_t *list)
+{
+ uint32 i;
+ uint8 *ptr = (uint8 *)&list->tclas[0];
+ int retlen = 0;
+
+ for (i = 0; i < list->num; i++) {
+ wl_tclas_t *tclas = (wl_tclas_t *)ptr;
+
+ printf("tclas idx %d: ", i);
+
+ wl_tclas_dump(tclas);
+
+ retlen += WL_TCLAS_FIXED_SIZE + tclas->fc_len;
+
+ /* Move to the next tclas frame classifier parameter */
+ ptr += WL_TCLAS_FIXED_SIZE + tclas->fc_len;
+ }
+
+ return retlen;
+}
+
+static int
+wl_tclas_list(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ wl_tclas_list_t *tclas_list = NULL;
+ void *ptr = NULL;
+
+ if (*++argv) {
+ printf("Too much args provided\n");
+ return BCME_ERROR;
+ }
+
+ err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr);
+ if (err == BCME_OK) {
+ tclas_list = (wl_tclas_list_t *)ptr;
+ if (tclas_list->num == 0)
+ printf("No tclas frame classifier parameter entry\n");
+ else
+ wl_tclas_list_parse(tclas_list);
+ }
+
+ return err;
+}
+
+static int
+wl_wnm_tfsreq_add(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc;
+ int err = -1, buflen;
+ wl_tfs_req_t tfs_req;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ strcpy(buf, "wnm_tfsreq_add");
+ buflen = strlen("wnm_tfsreq_add") + 1;
+
+ if (argc != 5 || *++(argv) == NULL) {
+ printf("Incorrect args provided\n");
+ return BCME_ERROR;
+ }
+
+ tfs_req.tfs_id = (uint8)strtoul(*argv++, NULL, 0);
+
+ if (*argv != NULL)
+ tfs_req.tfs_actcode = (uint8)strtoul(*argv++, NULL, 0);
+ else {
+ printf("Incorrect args provided\n");
+ return BCME_ERROR;
+ }
+
+ if (*argv != NULL)
+ tfs_req.tfs_subelem_id = (uint8)strtoul(*argv++, NULL, 0);
+ else {
+ printf("Incorrect args provided\n");
+ return BCME_ERROR;
+ }
+
+ if (*argv != NULL)
+ tfs_req.send = strtoul(*argv, NULL, 0) == 0 ? FALSE : TRUE;
+ else {
+ printf("Incorrect args provided\n");
+ return BCME_ERROR;
+ }
+
+ if (tfs_req.tfs_id == 0 ||
+ tfs_req.tfs_actcode > 3 ||
+ tfs_req.tfs_subelem_id > 1) {
+ printf("Input args not in range\n");
+ return BCME_ERROR;
+ }
+
+ buf[buflen++] = tfs_req.tfs_id;
+ buf[buflen++] = tfs_req.tfs_actcode;
+ buf[buflen++] = tfs_req.tfs_subelem_id;
+ buf[buflen++] = tfs_req.send;
+
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+}
+
+static int
+wl_wnm_dms_set(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen;
+ wl_dms_set_t *dms_set;
+
+ UNUSED_PARAMETER(cmd);
+
+ buflen = sprintf(buf, "%s", *argv) + 1;
+ dms_set = (wl_dms_set_t *) (buf + buflen);
+ dms_set->user_id = 0;
+ dms_set->tclas_proc = 0;
+ buflen += sizeof(wl_dms_set_t);
+
+ if (*++(argv) == NULL) {
+ printf("Missing <send> argument\n");
+ return BCME_ERROR;
+ }
+ dms_set->send = (uint8) strtoul(*argv, NULL, 0);
+
+ if (*++(argv) == NULL)
+ goto set;
+ dms_set->user_id = (uint8) strtoul(*argv, NULL, 0);
+
+ if (*++(argv) == NULL)
+ goto set;
+ dms_set->tclas_proc = (uint8) strtoul(*argv, NULL, 0);
+
+ if (*++(argv)) {
+ printf("extra argument\n");
+ return BCME_ERROR;
+ }
+set:
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+}
+
+static int
+wl_wnm_dms_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ wl_dms_status_t *dms_list = (wl_dms_status_t *)buf;
+ uint8 *p = (uint8 *)dms_list->desc;
+
+ strcpy(buf, argv[0]);
+
+ ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN);
+ if (ret < 0)
+ return ret;
+
+ dms_list->cnt = dtoh32(dms_list->cnt);
+
+ while (dms_list->cnt--) {
+
+ wl_dms_desc_t *desc = (wl_dms_desc_t *)p;
+
+ printf("DMS desc UserID %d:\n", desc->user_id);
+ printf("\tstatus:%d token:%d DMS ID:%d TCLAS proc:%d\n",
+ desc->status, desc->token, desc->dms_id, desc->tclas_proc);
+
+ p += WL_DMS_DESC_FIXED_SIZE;
+
+ if (desc->mac_len) {
+ printf("\tRegistered STA:\n");
+
+ while (desc->mac_len) {
+ printf("\t\t- %s\n", wl_ether_etoa((struct ether_addr*)p));
+ p += ETHER_ADDR_LEN;
+ desc->mac_len -= ETHER_ADDR_LEN;
+ }
+ }
+
+ printf("\tTCLAS:\n");
+ while (desc->tclas_len) {
+ wl_tclas_t *tclas = (wl_tclas_t *)p;
+
+ printf("\t\t- ");
+ wl_tclas_dump(tclas);
+
+ p += WL_TCLAS_FIXED_SIZE + tclas->fc_len;
+ desc->tclas_len -= WL_TCLAS_FIXED_SIZE + tclas->fc_len;
+ }
+ }
+
+ return 0;
+}
+
+static int
+wl_wnm_dms_term(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen;
+ wl_dms_term_t *dms_term;
+
+ UNUSED_PARAMETER(cmd);
+
+ buflen = sprintf(buf, "%s", *argv) + 1;
+
+ dms_term = (wl_dms_term_t *) (buf + buflen);
+ dms_term->user_id = 0;
+ buflen += sizeof(wl_dms_term_t);
+
+ if (*++(argv) == NULL) {
+ printf("Missing <del> argument\n");
+ return BCME_ERROR;
+ }
+ dms_term->del = (uint8) strtoul(*argv, NULL, 0);
+
+ if (*++(argv) == NULL)
+ goto set;
+ dms_term->user_id = (uint8) strtoul(*argv, NULL, 0);
+
+ if (*++(argv)) {
+ printf("extra argument\n");
+ return BCME_ERROR;
+ }
+set:
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+}
+
+static int
+wl_wnm_service_term(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen;
+ wl_service_term_t *term;
+
+ UNUSED_PARAMETER(cmd);
+
+ buflen = sprintf(buf, "%s", *argv) + 1;
+
+ term = (wl_service_term_t *) (buf + buflen);
+ term->u.dms.user_id = 0;
+ buflen += sizeof(wl_service_term_t);
+
+ if (*++(argv) == NULL) {
+ printf("Missing <service> argument\n");
+ return BCME_ERROR;
+ }
+ term->service = (uint8) strtoul(*argv, NULL, 0);
+
+ /* Need per service processing from here? */
+ if (*++(argv) == NULL) {
+ printf("Missing <del> argument\n");
+ return BCME_ERROR;
+ }
+ term->u.dms.del = (uint8) strtoul(*argv, NULL, 0);
+
+ if (*++(argv) == NULL)
+ goto set;
+ term->u.dms.user_id = (uint8) strtoul(*argv, NULL, 0);
+
+ if (*++(argv)) {
+ printf("extra argument\n");
+ return BCME_ERROR;
+ }
+set:
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+}
+
+static int
+wl_wnm_timbc_offset(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_timbc_offset_t *timbc_offset;
+ char *p = buf;
+ int size;
+ UNUSED_PARAMETER(cmd);
+
+ size = sprintf(p, "%s", *argv++) + 1;
+
+ if (*argv == NULL) {
+ /* retrieve bss idle period if argument count incorrect */
+ int err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN);
+ if (err < 0)
+ return err;
+
+ timbc_offset = (wl_timbc_offset_t *)buf;
+ printf("TIMBC offset: %d, tsf_present: %d, fix_interval: %d, rate_override: %d\n",
+ timbc_offset->offset, timbc_offset->tsf_present, timbc_offset->fix_intv,
+ timbc_offset->rate_override);
+
+ return BCME_OK;
+
+ } else {
+ if (!isdigit((int)*argv[0]))
+ return BCME_ERROR;
+
+ timbc_offset = (wl_timbc_offset_t *)(p + size);
+
+ timbc_offset->offset = (int16)strtoul(*argv++, NULL, 0);
+ timbc_offset->tsf_present = TRUE;
+ timbc_offset->fix_intv = 0;
+ timbc_offset->rate_override = 0;
+
+ if (*argv != NULL) {
+ timbc_offset->tsf_present = (bool)strtoul(*argv++, NULL, 0);
+ if (*argv != NULL) {
+ timbc_offset->fix_intv = (uint16)strtoul(*argv++, NULL, 0);
+ if (*argv != NULL) {
+ timbc_offset->rate_override =
+ (uint16)strtoul(*argv++, NULL, 0);
+ }
+ }
+ }
+
+ return wlu_set(wl, WLC_SET_VAR, buf, size + sizeof(wl_timbc_offset_t));
+ }
+}
+
+static int
+wl_wnm_timbc_set(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, buflen;
+ wl_timbc_set_t *req;
+
+ UNUSED_PARAMETER(cmd);
+
+ buflen = sprintf(buf, "%s", *argv) + 1;
+
+ req = (wl_timbc_set_t *) (buf + buflen);
+ req->flags = 0;
+ req->rate_min = 0;
+ req->rate_max = 0;
+ buflen += sizeof(wl_timbc_set_t);
+
+ if (*++(argv) == NULL) {
+ printf("Missing <interval> argument\n");
+ return BCME_ERROR;
+ }
+ req->interval = (uint8) strtoul(*argv, NULL, 0);
+
+ if (*++(argv) == NULL)
+ goto set;
+ req->flags = (uint8) strtoul(*argv, NULL, 0);
+
+ if (*++(argv) == NULL)
+ goto set;
+ req->rate_min = htod16(rate_string2int(*argv));
+
+ if (*++(argv) == NULL)
+ goto set;
+ req->rate_max = htod16(rate_string2int(*argv));
+
+ if (*++(argv)) {
+ printf("Too many arguments\n");
+ return BCME_ERROR;
+ }
+set:
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+}
+
+static int
+wl_wnm_timbc_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int ret;
+ wl_timbc_status_t *status = (wl_timbc_status_t *)buf;
+ char hrate[16], lrate[16];
+
+ strcpy(buf, argv[0]);
+
+ ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN);
+ if (ret < 0)
+ return ret;
+
+ printf("TIM BC current status: %d status_ap: %d\n"
+ " interval: %d offset: %d\n"
+ " high rate: %s low rate: %s\n",
+ status->status_sta,
+ status->status_ap,
+ status->interval, status->offset,
+ rate_int2string(hrate, status->rate_high),
+ rate_int2string(lrate, status->rate_low));
+
+ return BCME_OK;
+}
+
+static int
+wl_wnm_maxidle(void *wl, cmd_t *cmd, char **argv)
+{
+ struct {
+ int period;
+ int protect;
+ } params = { 0, 0 };
+ char *endptr;
+
+ if (*++argv == NULL) {
+ /* retrieve bss idle period if argument count incorrect */
+ int err = wlu_iovar_getint(wl, cmd->name, ¶ms.period);
+ if (err < 0)
+ return err;
+
+ printf("BSS Max Idle Period: %d\n", dtoh32(params.period));
+ return BCME_OK;
+
+ } else {
+ /* parse the idle period */
+ params.period = strtoul(*argv++, &endptr, 0);
+ htod32(params.period);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+
+ /* parse the optional keep-alive protect flag */
+ if (*argv) {
+ params.protect = strtoul(*argv, &endptr, 0);
+ htod32(params.protect);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+
+ return wlu_var_setbuf(wl, cmd->name, ¶ms, sizeof(params));
+ }
+}
+
+static int
+wl_wnm_bsstrans_req(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1;
+ wl_bsstrans_req_t bsstrans_req;
+ int buflen = sprintf(buf, "%s", *argv) + 1;
+ int tmp;
+
+ UNUSED_PARAMETER(cmd);
+
+ /* req mode parsing */
+ if (*++argv == NULL) {
+ fprintf(stderr, "%s: error: reqmode missing\n", __FUNCTION__);
+ return BCME_ERROR;
+ }
+ bsstrans_req.reqmode = strtoul(*argv, NULL, 0);
+
+ /* tbtt parsing */
+ if (*++argv == NULL) {
+ fprintf(stderr, "%s: error: tbtt missing\n", __FUNCTION__);
+ return BCME_ERROR;
+ }
+ tmp = strtoul(*argv, NULL, 0);
+ if (tmp > 65535 || tmp < 0) {
+ fprintf(stderr, "%s: error: tbtt out of range(%d)\n", __FUNCTION__, tmp);
+ return BCME_ERROR;
+ }
+ else
+ bsstrans_req.tbtt = tmp;
+
+ /* dur parsing */
+ if (*++argv == NULL) {
+ fprintf(stderr, "%s: error: dur missing\n", __FUNCTION__);
+ return BCME_ERROR;
+ }
+ tmp = strtoul(*argv, NULL, 0);
+ if (tmp > 65535 || tmp < 0) {
+ fprintf(stderr, "%s: error: dur out of range(%d)\n", __FUNCTION__, tmp);
+ return BCME_ERROR;
+ }
+ else
+ bsstrans_req.dur = tmp;
+
+ /* unicast/broadcast parsing */
+ if (*++argv != NULL)
+ bsstrans_req.unicast = strtoul(*argv, NULL, 0);
+ else
+ bsstrans_req.unicast = 1;
+
+ memcpy(&buf[buflen], &bsstrans_req, sizeof(bsstrans_req));
+ buflen += sizeof(bsstrans_req);
+
+ err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
+
+ return err;
+}
+
+/*
+ * Get or Set wnm keepalive configuration
+ */
+static int
+wl_wnm_keepalives_max_idle(void *wl, cmd_t *cmd, char **argv)
+{
+ int err, argc;
+ keepalives_max_idle_t keepalive;
+
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+
+ if (*argv == NULL) {
+ /* get current params */
+ if ((err = wlu_iovar_get(wl, cmd->name, (void *) &keepalive,
+ (sizeof(keepalive)))) < 0)
+ return (err);
+
+ printf("Keepalives_max_idle parameters -\n");
+ printf("num_of_keepalives_per_bss_max_idle\t\t= %d\nmkeep_alive_index\t= %d"
+ "\nmax_interval\t= %d\n", keepalive.keepalive_count,
+ keepalive.mkeepalive_index, keepalive.max_interval);
+ } else {
+ char *endptr;
+ /* Validate num of entries */
+ for (argc = 0; argv[argc]; argc++);
+ if (argc < 2 || argc > 3)
+ return BCME_ERROR;
+
+ keepalive.keepalive_count = strtol(argv[0], &endptr, 0);
+ keepalive.mkeepalive_index = strtol(argv[1], &endptr, 0);
+ if (argc == 3)
+ keepalive.max_interval = strtol(argv[2], &endptr, 0);
+ else
+ keepalive.max_interval = 0;
+
+ /* Set params */
+ err = wlu_iovar_set(wl, cmd->name, (void *) &keepalive,
+ (sizeof(keepalives_max_idle_t)));
+ }
+
+ return err;
+}
+
+static int
+wl_wnm_url(void *wl, cmd_t *cmd, char **argv)
+{
+ void *ptr;
+ int err;
+ uchar *data;
+ uchar datalen, count;
+ wnm_url_t *url;
+
+ if (!*++argv) {
+ err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr);
+ if (err == 0) {
+ data = (uchar *)ptr;
+ datalen = data[0];
+ data ++;
+ *(data + datalen) = '\0';
+ printf("%s URL len %d\n", cmd->name, datalen);
+ printf("%s URL: %s\n", cmd->name, data);
+ }
+ else {
+ fprintf(stderr, "Error %d getting IOVar\n", err);
+ }
+ return err;
+ }
+
+ /* get URL length */
+ datalen = (uchar)atoi(argv[0]);
+
+ if (datalen > 0) {
+ if (!argv[1]) {
+ fprintf(stderr, "URL string should be specified for URL length %d\n",
+ datalen);
+ return BCME_BADARG;
+ }
+ else {
+ if ((int)strlen (argv[1]) != datalen) {
+ fprintf(stderr, "length is not matching to string\n");
+ return BCME_BADARG;
+ }
+ }
+ }
+
+ if ((datalen == 0) && (argv[1] != NULL))
+ fprintf(stderr, "Ignoring data bytes for length %d\n", datalen);
+
+ count = sizeof(wnm_url_t) + datalen - 1;
+ data = malloc(count);
+ if (data == NULL) {
+ fprintf(stderr, "memory alloc failure\n");
+ return BCME_NOMEM;
+ }
+
+ url = (wnm_url_t *) data;
+ url->len = datalen;
+ if (datalen > 0) {
+ memcpy(url->data, argv[1], datalen);
+ }
+
+ err = wlu_var_setbuf(wl, cmd->name, data, count);
+
+ free(data);
+ return (err);
+}
+
+static int
+wl_wnm_bss_select_table(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc;
+ int ret;
+ char *endptr = NULL;
+ wnm_bss_select_factor_cfg_t *btcfg;
+ int btcfg_size = WNM_BSS_SELECT_FIXED_SIZE +
+ (sizeof(wnm_bss_select_factor_params_t) * BSS_MAXTABLE_SIZE);
+ int i;
+
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+
+ /* minimum 2 argument required */
+ if ((argc < 2) || (argc / 3) > BSS_MAXTABLE_SIZE) {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* invalid set argument */
+ if ((argc > 2) && ((argc - 1) % 3)) {
+ if ((((argc - 1) % 3) == 2) || (stricmp(argv[argc-1], "a") &&
+ stricmp(argv[argc-1], "b") && stricmp(argv[argc-1], "all"))) {
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ btcfg = (wnm_bss_select_factor_cfg_t *)malloc(btcfg_size);
+ if (btcfg == NULL) {
+ fprintf(stderr, "memory alloc failure\n");
+ return BCME_NOMEM;
+ }
+ memset(btcfg, 0, btcfg_size);
+
+ btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
+ btcfg->band = WLC_BAND_AUTO;
+ btcfg->type = 0;
+ btcfg->count = 0;
+
+ /* First arg: type */
+ if (argc >= 2) {
+ if (!strcmp(argv[0], "rssi"))
+ btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
+ else if (!strcmp(argv[0], "cu"))
+ btcfg->type = WNM_BSS_SELECT_TYPE_CU;
+ else {
+ free(btcfg);
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ /* Second arg: value or band */
+ for (i = 1; i < argc; i = i + 3) {
+ if (!stricmp(argv[i], "a")) {
+ btcfg->band = WLC_BAND_5G;
+ break;
+ } else if (!stricmp(argv[i], "b")) {
+ btcfg->band = WLC_BAND_2G;
+ break;
+ } else if (!stricmp(argv[i], "all")) {
+ btcfg->band = WLC_BAND_ALL;
+ break;
+ } else {
+ btcfg->params[i/3].low = strtol(argv[i+0], &endptr, 0);
+ if (*endptr != '\0') {
+ free(btcfg);
+ return BCME_USAGE_ERROR;
+ }
+
+ btcfg->params[i/3].high = strtol(argv[i+1], &endptr, 0);
+ if (*endptr != '\0') {
+ free(btcfg);
+ return BCME_USAGE_ERROR;
+ }
+
+ btcfg->params[i/3].factor = strtol(argv[i+2], &endptr, 0);
+ if (*endptr != '\0') {
+ free(btcfg);
+ return BCME_USAGE_ERROR;
+ }
+ }
+ }
+
+ /* number of elements */
+ btcfg->count = i / 3;
+
+ /* issue the get or set ioctl */
+ if ((argc == 2) && (btcfg->band != WLC_BAND_AUTO)) {
+ void *ptr = NULL;
+ if (btcfg->band == WLC_BAND_ALL) {
+ printf("band option \"all\" is for set only, not get\n");
+ free(btcfg);
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, btcfg, btcfg_size, &ptr)) < 0) {
+ free(btcfg);
+ return ret;
+ }
+
+ memcpy(btcfg, ptr, WNM_BSS_SELECT_FIXED_SIZE);
+
+ btcfg_size = WNM_BSS_SELECT_FIXED_SIZE +
+ (btcfg->count * sizeof(wnm_bss_select_factor_params_t));
+ memcpy(btcfg, ptr, btcfg_size);
+
+ printf("no of entries in table: %d\n", btcfg->count);
+ printf("%s factor table\n",
+ (btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
+ printf("low\thigh\tfactor\n");
+ for (i = 0; i < btcfg->count; i++) {
+ printf("%d\t%d\t%d\n", btcfg->params[i].low,
+ btcfg->params[i].high, btcfg->params[i].factor);
+ }
+ printf("\n");
+ } else {
+ if (btcfg->band == WLC_BAND_AUTO) {
+ btcfg->band = WLC_BAND_ALL;
+ }
+
+ btcfg_size = WNM_BSS_SELECT_FIXED_SIZE +
+ (btcfg->count * sizeof(wnm_bss_select_factor_params_t));
+ ret = wlu_var_setbuf(wl, cmd->name, btcfg, btcfg_size);
+ }
+
+ free(btcfg);
+ return ret;
+}
+
+static int
+wl_wnm_bss_select_weight(void *wl, cmd_t *cmd, char **argv)
+{
+ int argc;
+ int ret;
+ char *endptr = NULL;
+ wnm_bss_select_weight_cfg_t bwcfg;
+
+ argv++;
+
+ /* arg count */
+ for (argc = 0; argv[argc]; argc++);
+
+ bwcfg.version = WNM_BSSLOAD_MONITOR_VERSION;
+ bwcfg.band = WLC_BAND_AUTO;
+ bwcfg.type = 0;
+ bwcfg.weight = 0;
+
+ /* minimum 2 argument required */
+ if (argc < 2) {
+ return BCME_USAGE_ERROR;
+ }
+
+ /* First arg: type */
+ if (argc >= 2) {
+ if (!strcmp(argv[0], "rssi"))
+ bwcfg.type = WNM_BSS_SELECT_TYPE_RSSI;
+ else if (!strcmp(argv[0], "cu"))
+ bwcfg.type = WNM_BSS_SELECT_TYPE_CU;
+ else
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Second arg: value or band */
+ if (argc >= 2) {
+ if (!stricmp(argv[1], "a"))
+ bwcfg.band = WLC_BAND_5G;
+ else if (!stricmp(argv[1], "b"))
+ bwcfg.band = WLC_BAND_2G;
+ else if (!stricmp(argv[1], "all"))
+ bwcfg.band = WLC_BAND_ALL;
+ else {
+ bwcfg.weight = strtol(argv[1], &endptr, 0);
+ if (*endptr != '\0')
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ /* third arg: band */
+ if (argc >= 3) {
+ if (!stricmp(argv[2], "a"))
+ bwcfg.band = WLC_BAND_5G;
+ else if (!stricmp(argv[2], "b"))
+ bwcfg.band = WLC_BAND_2G;
+ else if (!stricmp(argv[2], "all"))
+ bwcfg.band = WLC_BAND_ALL;
+ else
+ return BCME_USAGE_ERROR;
+ }
+
+ /* issue the get or set ioctl */
+ if ((argc == 2) && (bwcfg.band != WLC_BAND_AUTO)) {
+ void *ptr = NULL;
+ if (bwcfg.band == WLC_BAND_ALL) {
+ printf("band option \"all\" is for set only, not get\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, &bwcfg, sizeof(bwcfg), &ptr)) < 0)
+ return ret;
+
+ memcpy(&bwcfg, ptr, sizeof(bwcfg));
+ printf("%s %s weight = %d\n",
+ (bwcfg.type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU",
+ (bwcfg.band == WLC_BAND_2G) ? "2G" : "5G", bwcfg.weight);
+ } else {
+ if (bwcfg.band == WLC_BAND_AUTO) {
+ bwcfg.band = WLC_BAND_ALL;
+ }
+ ret = wlu_var_setbuf(wl, cmd->name, &bwcfg, sizeof(bwcfg));
+ }
+
+ return ret;
+}
diff --git a/wl/src/wl/exe/wluc_wowl.c b/wl/src/wl/exe/wluc_wowl.c
new file mode 100644
index 0000000..c79ff61
--- /dev/null
+++ b/wl/src/wl/exe/wluc_wowl.c
@@ -0,0 +1,1177 @@
+/*
+ * wl wowl command module
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wluc_wowl.c 458728 2014-02-27 18:15:25Z $
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <wlioctl.h>
+
+#if defined(DONGLEBUILD)
+#include <typedefs.h>
+#include <osl.h>
+#endif
+
+/* Because IL_BIGENDIAN was removed there are few warnings that need
+ * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
+ * Hence these warnings were not seen earlier.
+ * For now ignore the following warnings
+ */
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include "wlu_common.h"
+#include "wlu.h"
+
+static cmd_func_t wl_nshostip;
+static cmd_func_t wl_wowl_pattern, wl_wowl_wakeind, wl_wowl_pkt, wl_wowl_status;
+static cmd_func_t wl_wowl_wake_reason, wl_wowl_extended_magic, wl_wowl_radio_duty_cycle;
+static cmd_func_t wl_wowl_wog_appid;
+static cmd_func_t wl_wowl_wog_resp;
+
+static cmd_t wl_wowl_cmds[] = {
+ { "ns_hostip", wl_nshostip, WLC_GET_VAR, WLC_SET_VAR,
+ "Add a ns-ip address or display then"},
+ { "ns_hostip_clear", wl_var_void, -1, WLC_SET_VAR,
+ "Clear all ns-ip addresses"},
+ { "wowl", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Enable/disable WOWL events\n"
+ " 0 - Clear all events\n"
+ "Bit 0 - Wakeup on Magic Packet\n"
+ "Bit 1 - Wakeup on NetPattern (use 'wl wowl_pattern' to configure pattern)\n"
+ "Bit 2 - Wakeup on loss-of-link due to Disassociation/Deauth\n"
+ "Bit 3 - Wakeup on retrograde tsf\n"
+ "Bit 4 - Wakeup on loss of beacon (use 'wl wowl_bcn_loss' to configure time)"},
+ { "wowl_radio_duty_cycle", wl_wowl_radio_duty_cycle, -1, -1,
+ "usage: wowl_radio_duty_cycle [ wake interval , sleep interval]\n"
+ "No options -- lists existing power intervals\n"
+ "wake interval -- Time of radio on period in MS \n"
+ "sleep interval -- Time of sleep period in MS "
+ },
+ { "wowl_bcn_loss", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "Set #of seconds of beacon loss for wakeup event"},
+ { "wowl_pattern", wl_wowl_pattern, -1, -1,
+ "usage: wowl_pattern [ [clr | [[ add | del ] offset mask value ]]]\n"
+ "No options -- lists existing pattern list\n"
+ "add -- Adds the pattern to the list\n"
+ "del -- Removes a pattern from the list\n"
+ "clr -- Clear current list\n"
+ "offset -- Starting offset for the pattern\n"
+ "mask -- Mask to be used for pattern. Bit i of mask => byte i of the pattern\n"
+ "value -- Value of the pattern"
+ },
+ { "wowl_wakeind", wl_wowl_wakeind, WLC_GET_VAR, WLC_SET_VAR,
+ "usage: wowl_wakeind [clear]\n"
+ "Shows last system wakeup event indications from PCI and D11 cores\n"
+ "clear - Clear the indications"
+ },
+ { "wowl_status", wl_wowl_status, WLC_GET_VAR, -1,
+ "usage: wowl_status [clear]\n"
+ "Shows last system wakeup setting"
+ },
+ {"wowl_pkt", wl_wowl_pkt, -1, -1,
+ "Send a wakeup frame to wakup a sleeping STA in WAKE mode\n"
+ "Usage: wl wowl_pkt <len> <dst ea | bcast | ucast <STA ea>>"
+ "[ magic [<STA ea>] | net <offset> <pattern> <reason code> ]\n"
+ "e.g. To send bcast magic frame -- "
+ "wl wowl_pkt 102 bcast magic 00:90:4c:AA:BB:CC\n"
+ " To send ucast magic frame -- "
+ "wl wowl_pkt 102 ucast 00:90:4c:aa:bb:cc magic\n"
+ " To send a frame with L2 unicast - "
+ "wl wowl_pkt 102 00:90:4c:aa:bb:cc net 0 0x00904caabbcc 0x03\n"
+ " NOTE: offset for netpattern frame starts from \"Dest EA\" of ethernet frame."
+ "So dest ea will be used only when offset is >= 6\n"
+ " To send a eapol identity frame with L2 unicast - "
+ "wl wowl_pkt 102 00:90:4c:aa:bb:cc eapid id-string"},
+ {"wowl_ext_magic", wl_wowl_extended_magic, WLC_GET_VAR, WLC_SET_VAR,
+ "Set 6-byte extended magic pattern\n"
+ "Usage: wl wowl_ext_magic 0x112233445566"},
+ { "wowl_wakeup_reason", wl_wowl_wake_reason, WLC_GET_VAR, -1 /* Set not reqd */,
+ "Returns pattern id and associated wakeup reason"},
+ { "wowl_rls_wake_pkt", wl_var_void, -1, WLC_SET_VAR,
+ "Release packet that triggered the host wake up"},
+ { "wowl_wog", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
+ "WOG(Wake On Googlecast) on/off\n"
+ "Setting is available only under wowl mode deativated\n"
+ "\tUsage:\n\t wl wowl_wog [0|1]\n"},
+ { "wowl_wog_appid", wl_wowl_wog_appid, WLC_GET_VAR, WLC_SET_VAR,
+ "App/Del/Clear/List Application IDs\n"
+ "\tUsage:\n\t wl wowl_wog_appid add <_APPID>\n"
+ "\t wl wowl_wog_appid del <_APPID>\n"
+ "\t wl wowl_wog_appid clear\n"
+ "\t wl wowl_wog_appid list\n"
+ "\t wl wowl_wog_appid maxcnt [max_appid_count]\n"
+ "\t\t max_appid_count > 1 and if maxcnt is changed AppId list will be cleared.\n"
+ "\t\t if maxcnt is same with before, maxcnt won't be applied.\n"},
+ { "wowl_wog_resp", wl_wowl_wog_resp, WLC_GET_VAR, WLC_SET_VAR,
+ "Set/Get Wake On Googlecast Response\n"
+ "\tUsage:\n\t wl wowl_wog_resp devname <devname>"
+ " ip <x.x.x.x> [ttl <ttl>]\n"
+ "\t txt id <uuid> [ca <capability>] [st <receiver_status_flag>] "
+ "[ve <version>] [md <model_name>]\n"
+ "\t [pk <public_key>] [fn <friendly_name>] "
+ "[rs <receiver_status>] [ttl <txt_ttl>]\n"
+ "\t [srv port <port> [ttl <srv_ttl>]]\n"
+ "\t [a ttl]\n"
+ "\n\t wl wowl_wog_resp show\n\n"},
+ { NULL, NULL, 0, 0, NULL }
+};
+
+static char *buf;
+
+/* module initialization */
+void
+wluc_wowl_module_init(void)
+{
+ /* get the global buf */
+ buf = wl_get_buf();
+
+ /* register wowl commands */
+ wl_module_cmds_register(wl_wowl_cmds);
+}
+
+/*
+ * If a host IP address is given, add it to the host-cache,
+ * e.g. "wl nd_hostip fe00:0:0:0:0:290:1fc0:18c0 ".
+ * If no address is given, dump all the addresses.
+ */
+static int
+wl_nshostip(void *wl, cmd_t *cmd, char **argv)
+{
+
+ int ret = 0, i;
+ struct ipv6_addr ipa_set, *ipa_get, null_ipa;
+ uint16 *ip_addr;
+ if (!*++argv) {
+ /* Get */
+ void *ptr = NULL;
+
+ if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
+ return ret;
+ ip_addr = (uint16*)ptr;
+ memset(null_ipa.addr, 0, IPV6_ADDR_LEN);
+ for (ipa_get = (struct ipv6_addr *)ptr;
+ memcmp(null_ipa.addr, ipa_get->addr, IPV6_ADDR_LEN) != 0;
+ ipa_get++) {
+ /* Print ipv6 Addr */
+ for (i = 0; i < 8; i++)
+ {
+ printf("%x", ntoh16(ip_addr[i]));
+ if (i < 7)
+ printf(":");
+ }
+ }
+ printf("\r\n");
+ ip_addr += 8;
+ }
+ else {
+ /* Add */
+ if (!wl_atoipv6(*argv, &ipa_set))
+ return -1;
+ /* we add one ip-addr at a time */
+ return wlu_var_setbuf(wl, cmd->name,
+ &ipa_set, IPV6_ADDR_LEN);
+ }
+ return ret;
+}
+
+static int
+wl_wowl_status(void *wl, cmd_t *cmd, char **argv)
+{
+ int flags_prev = 0;
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+
+ if ((err = wlu_iovar_getint(wl, "wowl_status", &flags_prev)))
+ return err;
+
+ printf("Status of last wakeup:\n");
+ printf("\tflags:0x%x\n", flags_prev);
+
+ if (flags_prev & WL_WOWL_BCN)
+ printf("\t\tWake-on-Loss-of-Beacons enabled\n");
+
+ if (flags_prev & WL_WOWL_MAGIC)
+ printf("\t\tWake-on-Magic frame enabled\n");
+ if (flags_prev & WL_WOWL_NET)
+ printf("\t\tWake-on-Net pattern enabled\n");
+ if (flags_prev & WL_WOWL_DIS)
+ printf("\t\tWake-on-Deauth enabled\n");
+
+ if (flags_prev & WL_WOWL_RETR)
+ printf("\t\tRetrograde TSF enabled\n");
+ if (flags_prev & WL_WOWL_TST)
+ printf("\t\tTest-mode enabled\n");
+
+ printf("\n");
+
+ return 0;
+}
+
+static int
+wl_wowl_wakeind(void *wl, cmd_t *cmd, char **argv)
+{
+ wl_wowl_wakeind_t wake = {0, 0};
+ int err;
+
+ UNUSED_PARAMETER(cmd);
+
+ argv++;
+
+ if (*argv) {
+ if (strcmp(*argv, "clear"))
+ return BCME_USAGE_ERROR;
+ memset(&wake, 0, sizeof(wake));
+ memcpy(&wake, *argv, strlen("clear"));
+ err = wlu_iovar_set(wl, "wowl_wakeind", &wake, sizeof(wl_wowl_wakeind_t));
+ return err;
+ }
+
+ if ((err = wlu_iovar_get(wl, "wowl_wakeind", &wake, sizeof(wl_wowl_wakeind_t))) < 0)
+ return err;
+
+ if (wake.pci_wakeind)
+ printf("PCI Indication set\n");
+ wake.ucode_wakeind = dtoh32(wake.ucode_wakeind);
+ if (wake.ucode_wakeind != 0) {
+ printf("MAC Indication set\n");
+
+ if ((wake.ucode_wakeind & WL_WOWL_MAGIC) == WL_WOWL_MAGIC)
+ printf("\tMAGIC packet received\n");
+ if ((wake.ucode_wakeind & WL_WOWL_NET) == WL_WOWL_NET)
+ printf("\tPacket received with Netpattern\n");
+ if ((wake.ucode_wakeind & WL_WOWL_DIS) == WL_WOWL_DIS)
+ printf("\tDisassociation/Deauth received\n");
+ if ((wake.ucode_wakeind & WL_WOWL_RETR) == WL_WOWL_RETR)
+ printf("\tRetrograde TSF detected\n");
+ if ((wake.ucode_wakeind & WL_WOWL_BCN) == WL_WOWL_BCN)
+ printf("\tBeacons Lost\n");
+ if ((wake.ucode_wakeind & WL_WOWL_TST) == WL_WOWL_TST)
+ printf("\tTest Mode\n");
+ if ((wake.ucode_wakeind & WL_WOWL_M1) == WL_WOWL_M1)
+ printf("\tPTK Refresh received.\n");
+ if ((wake.ucode_wakeind & WL_WOWL_EAPID) == WL_WOWL_EAPID)
+ printf("\tEAP-Identity request received\n");
+ if ((wake.ucode_wakeind & WL_WOWL_GTK_FAILURE) == WL_WOWL_GTK_FAILURE)
+ printf("\tWake on GTK failure.\n");
+ if ((wake.ucode_wakeind & WL_WOWL_EXTMAGPAT) == WL_WOWL_EXTMAGPAT)
+ printf("\tExtended Magic Packet received.\n");
+ if ((wake.ucode_wakeind & WL_WOWL_KEYROT) == WL_WOWL_KEYROT)
+ printf("\tKey Rotation Packet received.\n");
+ if ((wake.ucode_wakeind & (WL_WOWL_NET | WL_WOWL_MAGIC | WL_WOWL_EXTMAGPAT))) {
+ if ((wake.ucode_wakeind & WL_WOWL_BCAST) == WL_WOWL_BCAST)
+ printf("\t\tBroadcast/Mcast frame received\n");
+ else
+ printf("\t\tUnicast frame received\n");
+ }
+ }
+
+ if (!wake.pci_wakeind && wake.ucode_wakeind == 0)
+ printf("No wakeup indication set\n");
+
+ return 0;
+}
+/* Used by NINTENDO2 */
+static int
+wl_wowl_wake_reason(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = -1;
+ wl_wr_t wr;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (!*++argv) {
+ err = wlu_iovar_get(wl, "wakeup_reason", &wr, sizeof(wl_wr_t));
+ if (err)
+ return err;
+
+ if (wr.reason && wr.reason < REASON_LAST) {
+ printf("ID: %d\t", wr.id);
+
+ if (wr.reason == LCD_ON)
+ printf("Reason: LCD_ON\n");
+ else if (wr.reason == LCD_OFF)
+ printf("Reason: LCD_OFF\n");
+ else if (wr.reason == DRC1_WAKE)
+ printf("Reason: DRC1_WAKE\n");
+ else if (wr.reason == DRC2_WAKE)
+ printf("Reason: DRC2_WAKE\n");
+ }
+ else
+ printf("Unknown wakeup Reason\n");
+ }
+ return err;
+}
+
+/* Send a wakeup frame to sta in WAKE mode */
+static int
+wl_wowl_pkt(void *wl, cmd_t *cmd, char **argv)
+{
+ char *arg = buf;
+ const char *str;
+ char *dst;
+ uint tot = 0;
+ uint16 type, pkt_len;
+ int dst_ea = 0; /* 0 == manual, 1 == bcast, 2 == ucast */
+ char *ea[ETHER_ADDR_LEN];
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ UNUSED_PARAMETER(cmd);
+
+ str = "wowl_pkt";
+ strncpy(arg, str, strlen(str));
+ arg[strlen(str)] = '\0';
+ dst = arg + strlen(str) + 1;
+ tot += strlen(str) + 1;
+
+ pkt_len = (uint16)htod32(strtoul(*argv, NULL, 0));
+
+ *((uint16*)dst) = pkt_len;
+
+ dst += sizeof(pkt_len);
+ tot += sizeof(pkt_len);
+
+ if (!*++argv) {
+ printf("Dest of the packet needs to be provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Dest of the frame */
+ if (!strcmp(*argv, "bcast")) {
+ dst_ea = 1;
+ if (!wl_ether_atoe("ff:ff:ff:ff:ff:ff", (struct ether_addr *)dst))
+ return BCME_USAGE_ERROR;
+ } else if (!strcmp(*argv, "ucast")) {
+ dst_ea = 2;
+ if (!*++argv) {
+ printf("EA of ucast dest of the packet needs to be provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ if (!wl_ether_atoe(*argv, (struct ether_addr *)dst))
+ return BCME_USAGE_ERROR;
+ /* Store it */
+ memcpy(ea, dst, ETHER_ADDR_LEN);
+ } else if (!wl_ether_atoe(*argv, (struct ether_addr *)dst))
+ return BCME_USAGE_ERROR;
+
+ dst += ETHER_ADDR_LEN;
+ tot += ETHER_ADDR_LEN;
+
+ if (!*++argv) {
+ printf("type - magic/net needs to be provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (strncmp(*argv, "magic", strlen("magic")) == 0)
+ type = WL_WOWL_MAGIC;
+ else if (strncmp(*argv, "net", strlen("net")) == 0)
+ type = WL_WOWL_NET;
+ else if (strncmp(*argv, "eapid", strlen("eapid")) == 0)
+ type = WL_WOWL_EAPID;
+ else
+ return BCME_USAGE_ERROR;
+
+ *((uint16*)dst) = type;
+ dst += sizeof(type);
+ tot += sizeof(type);
+
+ if (type == WL_WOWL_MAGIC) {
+ if (pkt_len < MAGIC_PKT_MINLEN)
+ return BCME_BADARG;
+
+ if (dst_ea == 2)
+ memcpy(dst, ea, ETHER_ADDR_LEN);
+ else {
+ if (!*++argv)
+ return BCME_USAGE_ERROR;
+
+ if (!wl_ether_atoe(*argv, (struct ether_addr *)dst))
+ return BCME_USAGE_ERROR;
+ }
+ tot += ETHER_ADDR_LEN;
+ } else if (type == WL_WOWL_NET) {
+ wl_wowl_pattern_t *wl_pattern;
+ wl_pattern = (wl_wowl_pattern_t *)dst;
+
+ if (!*++argv) {
+ printf("Starting offset not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ wl_pattern->offset = (uint)htod32(strtoul(*argv, NULL, 0));
+
+ wl_pattern->masksize = 0;
+
+ wl_pattern->patternoffset = (uint)htod32(sizeof(wl_wowl_pattern_t));
+
+ dst += sizeof(wl_wowl_pattern_t);
+
+ if (!*++argv) {
+ printf("pattern not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ wl_pattern->patternsize =
+ (uint)htod32(wl_pattern_atoh((char *)(uintptr)*argv, dst));
+ dst += wl_pattern->patternsize;
+ tot += sizeof(wl_wowl_pattern_t) + wl_pattern->patternsize;
+
+ wl_pattern->reasonsize = 0;
+ if (*++argv) {
+ wl_pattern->reasonsize =
+ (uint)htod32(wl_pattern_atoh((char *)(uintptr)*argv, dst));
+ tot += wl_pattern->reasonsize;
+ }
+ } else { /* eapid */
+ if (!*++argv) {
+ printf("EAPOL identity string not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ *dst++ = strlen(*argv);
+ strncpy(dst, *argv, strlen(*argv));
+ tot += 1 + strlen(*argv);
+ }
+ return (wlu_set(wl, WLC_SET_VAR, arg, tot));
+}
+
+static int
+wl_wowl_pattern(void *wl, cmd_t *cmd, char **argv)
+{
+ int err;
+ uint i, j;
+ uint8 *ptr;
+ wl_wowl_pattern_t *wl_pattern;
+
+ UNUSED_PARAMETER(cmd);
+
+ if (*++argv) {
+ char *arg = buf;
+ const char *str;
+ char *dst;
+ uint tot = 0;
+
+ if (strcmp(*argv, "add") != 0 && strcmp(*argv, "del") != 0 &&
+ strcmp(*argv, "clr") != 0) {
+ return BCME_USAGE_ERROR;
+ }
+
+ str = "wowl_pattern";
+ strncpy(arg, str, strlen(str));
+ arg[strlen(str)] = '\0';
+ dst = arg + strlen(str) + 1;
+ tot += strlen(str) + 1;
+
+ str = *argv;
+ strncpy(dst, str, strlen(str));
+ tot += strlen(str) + 1;
+
+ if (strcmp(str, "clr") != 0) {
+ wl_pattern = (wl_wowl_pattern_t *)(dst + strlen(str) + 1);
+ dst = (char*)wl_pattern + sizeof(wl_wowl_pattern_t);
+ if (!*++argv) {
+ printf("Starting offset not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+ wl_pattern->offset = htod32(strtoul(*argv, NULL, 0));
+ if (!*++argv) {
+ printf("Mask not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Parse the mask */
+ str = *argv;
+ wl_pattern->masksize = htod32(wl_pattern_atoh((char *)(uintptr)str, dst));
+ if (wl_pattern->masksize == (uint)-1)
+ return BCME_USAGE_ERROR;
+
+ dst += wl_pattern->masksize;
+ wl_pattern->patternoffset = htod32((sizeof(wl_wowl_pattern_t) +
+ wl_pattern->masksize));
+
+ if (!*++argv) {
+ printf("Pattern value not provided\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ /* Parse the value */
+ str = *argv;
+ wl_pattern->patternsize =
+ htod32(wl_pattern_atoh((char *)(uintptr)str, dst));
+ if (wl_pattern->patternsize == (uint)-1)
+ return BCME_USAGE_ERROR;
+ tot += sizeof(wl_wowl_pattern_t) + wl_pattern->patternsize +
+ wl_pattern->masksize;
+ }
+
+ return (wlu_set(wl, WLC_SET_VAR, arg, tot));
+ } else {
+ wl_wowl_pattern_list_t *list;
+ if ((err = wlu_iovar_get(wl, "wowl_pattern", buf, WLC_IOCTL_MAXLEN)) < 0)
+ return err;
+ list = (wl_wowl_pattern_list_t *)buf;
+ printf("#of patterns :%d\n", list->count);
+ ptr = (uint8 *)list->pattern;
+ for (i = 0; i < list->count; i++) {
+ uint8 *pattern;
+
+ wl_pattern = (wl_wowl_pattern_t *)ptr;
+ printf("Pattern %d:\n", i+1);
+ printf("ID :0x%x\n"
+ "Offset :%d\n"
+ "Masksize :%d\n"
+ "Mask :0x",
+ (uint32)wl_pattern->id, wl_pattern->offset, wl_pattern->masksize);
+ pattern = ((uint8 *)wl_pattern + sizeof(wl_wowl_pattern_t));
+ for (j = 0; j < wl_pattern->masksize; j++)
+ printf("%02x", pattern[j]);
+ printf("\n"
+ "PatternSize:%d\n"
+ "Pattern :0x", wl_pattern->patternsize);
+ /* Go to end to find pattern */
+ pattern = ((uint8*)wl_pattern + wl_pattern->patternoffset);
+ for (j = 0; j < wl_pattern->patternsize; j++)
+ printf("%02x", pattern[j]);
+ printf("\n\n");
+ ptr += (wl_pattern->masksize + wl_pattern->patternsize +
+ sizeof(wl_wowl_pattern_t));
+ }
+ }
+
+ return err;
+}
+
+
+static int
+wl_wowl_radio_duty_cycle(void *wl, cmd_t *cmd, char **argv)
+{
+ int err = 0;
+ char *endptr = NULL;
+ int argc;
+ wowl_radio_duty_cycle_t cfg;
+
+ UNUSED_PARAMETER(cmd);
+
+ for (argc = 0; argv[argc]; argc++);
+ argc--;
+
+ if (argc != 0 && argc != 2) {
+ printf("required args: wake interval and sleep interval\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ if (argc == 0)
+ {
+ err = wl_var_get(wl, cmd, argv);
+ if (err < 0)
+ return err;
+ printf(" wake interval =%d ms\n sleep interval = %d ms\n",
+ ((wowl_radio_duty_cycle_t*)buf)->wake_interval,
+ ((wowl_radio_duty_cycle_t*)buf)->sleep_interval);
+ }
+ else
+ {
+ cfg.wake_interval = htod16((uint16)(strtoul(argv[1], &endptr, 0)));
+ cfg.sleep_interval = htod16((uint16)(strtoul(argv[2], &endptr, 0)));
+ err = wlu_var_setbuf(wl, cmd->name, &cfg, sizeof(wowl_radio_duty_cycle_t));
+ printf(" wake interval = %d ms\n sleep interval = %d ms\n",
+ cfg.wake_interval, cfg.sleep_interval);
+ }
+
+ return err;
+
+}
+
+static int
+wl_wowl_extended_magic(void *wl, cmd_t *cmd, char **argv)
+{
+ char *arg = buf;
+ const char *str;
+ char *dst;
+ uint tot;
+ int ret;
+
+ str = "wowl_ext_magic";
+ strncpy(arg, str, strlen(str));
+ arg[strlen(str)] = '\0';
+
+ if (*++argv) {
+ dst = arg + strlen(str) + 1;
+ tot = strlen(str) + 1;
+ ret = wl_pattern_atoh(*argv, dst);
+ if (ret == -1)
+ return BCME_USAGE_ERROR;
+ if (ret != 6) {
+ printf("Extended magic pattern must be 6-byte length\n");
+ return BCME_USAGE_ERROR;
+ }
+ tot += 6;
+
+ ret = wlu_set(wl, cmd->set, arg, tot);
+ return ret;
+ }
+
+
+ if ((ret = wlu_get(wl, cmd->get, arg, WLC_IOCTL_MAXLEN)) < 0)
+ return ret;
+
+ printf("0x");
+ for (ret = 0; ret < 6; ret++)
+ printf("%02x", (uint8)arg[ret]);
+ printf("\n");
+
+ return 0;
+
+}
+
+static int
+wl_wowl_wog_appid(void *wl, cmd_t *cmd, char **argv)
+{
+ wog_appid_iov_t *wog_appid;
+ char *appid, *command;
+ uint len;
+ int ret = BCME_OK;
+
+ if (!*++argv) {
+ return BCME_USAGE_ERROR;
+ }
+
+ wog_appid = (wog_appid_iov_t *)malloc(sizeof(*wog_appid));
+
+ if (wog_appid == NULL) {
+ return BCME_NOMEM;
+ }
+
+ memset(wog_appid, 0, sizeof(*wog_appid));
+
+ wog_appid->ver = htod32(WOG_APPID_IOV_VER);
+
+ command = *argv;
+ if (!strncmp(command, "add", 4) || !strncmp(command, "del", 4)) {
+ appid = *++argv;
+
+ if (!appid) {
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+
+ len = strlen(appid);
+
+ if (!len || appid[0] != '_') {
+ printf("Appid should start with '_'\n");
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+
+ wog_appid->cnt = htod32(1);
+ wog_appid->operation = (!strncmp(command, "add", 4))? htod32(WOG_APPID_ADD) :
+ htod32(WOG_APPID_DEL);
+ if (len > MAX_DNS_LABEL) {
+ len = MAX_DNS_LABEL;
+ }
+ memcpy(wog_appid->appids[0].appID, appid, len);
+ wog_appid->appids[0].appID[len] = 0;
+ ret = wlu_iovar_set(wl, cmd->name, wog_appid, sizeof(*wog_appid));
+ } else if (!strncmp(command, "clear", 6)) {
+ wog_appid->operation = htod32(WOG_APPID_CLEAR);
+ ret = wlu_iovar_set(wl, cmd->name, wog_appid, sizeof(*wog_appid));
+ } else if (!strncmp(command, "list", 5)) {
+ wog_appid_iov_t *list;
+ uint i;
+
+ wog_appid->operation = htod32(WOG_APPID_LIST);
+ ret = wlu_iovar_getbuf(wl, cmd->name, wog_appid, sizeof(*wog_appid),
+ buf, WLC_IOCTL_MAXLEN);
+ if (ret != BCME_OK) {
+ goto EXIT;
+ }
+
+ list = (wog_appid_iov_t *)buf;
+ list->cnt = dtoh32(list->cnt);
+ printf("AppID count : %d\n", list->cnt);
+ for (i = 0; i < list->cnt; i++) {
+ printf("AppID[%d]=%s\n", i, list->appids[i].appID);
+ }
+ } else if (!strncmp(command, "maxcnt", 7)) {
+ int max_count;
+
+ wog_appid->operation = htod32(WOG_MAX_APPID_CNT);
+
+ argv++;
+ if (*argv) {
+ max_count = atoi(*argv);
+ if (max_count < 1) {
+ printf("Maximum AppID count should be greater than 0\n");
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+ wog_appid->cnt = htod32(max_count);
+ ret = wlu_iovar_set(wl, cmd->name, wog_appid, sizeof(*wog_appid));
+ } else {
+ wog_appid_iov_t *appid;
+ ret = wlu_iovar_getbuf(wl, cmd->name, wog_appid, sizeof(*wog_appid),
+ buf, WLC_IOCTL_SMLEN);
+ if (ret != BCME_OK) {
+ goto EXIT;
+ }
+
+ appid = (wog_appid_iov_t *)buf;
+ appid->cnt = dtoh32(appid->cnt);
+ printf("Maximum AppID count : %d\n", appid->cnt);
+ }
+ } else {
+ ret = BCME_USAGE_ERROR;
+ }
+
+EXIT:
+ if (wog_appid) {
+ free(wog_appid);
+ }
+ return ret;
+}
+
+#define WOG_RESP_MAX_CMD_LEN 11
+#define WOG_RESP_MAX_SUBCMD 10
+typedef struct wowl_wog_resp_subcmd {
+ int mandatory;
+ char subname[WOG_RESP_MAX_CMD_LEN + 1];
+} wowl_wog_resp_subcmd_t;
+
+#define WOG_CMD_DEVNAME 0
+#define WOG_CMD_IP 1
+#define WOG_CMD_TTL 2
+#define WOG_CMD_TXT 3
+#define WOG_CMD_SRV 4
+#define WOG_CMD_A 5
+
+#define WOG_SUBCMD_TXT_ID 0
+#define WOG_SUBCMD_TXT_CA 1
+#define WOG_SUBCMD_TXT_ST 2
+#define WOG_SUBCMD_TXT_VE 3
+#define WOG_SUBCMD_TXT_MD 4
+#define WOG_SUBCMD_TXT_PK 5
+#define WOG_SUBCMD_TXT_FN 6
+#define WOG_SUBCMD_TXT_RS 7
+#define WOG_SUBCMD_TXT_TTL 8
+
+#define WOG_SUBCMD_SRV_PORT 0
+#define WOG_SUBCMD_SRV_TTL 1
+
+#define WOG_SUBCMD_A_TTL 0
+
+typedef struct wowl_wog_resp_cmd {
+ int mandatory;
+ char cname[WOG_RESP_MAX_CMD_LEN + 1];
+ int subcnt;
+ wowl_wog_resp_subcmd_t subcmd[WOG_RESP_MAX_SUBCMD];
+} wowl_wog_resp_cmd_t;
+
+const wowl_wog_resp_cmd_t wog_resp_cmdlist[] = {
+ {1, "devname", 0, {{0, {0, }}, }},
+ {1, "ip", 0, {{0, {0, }}, }},
+ {0, "ttl", 0, {{0, {0, }}, }},
+ {1, "txt", 9,
+ {{1, "id"}, {0, "ca"}, {0, "st"}, {0, "ve"}, {0, "md"},
+ {0, "pk"}, {0, "fn"}, {0, "rs"}, {0, "ttl"}, }
+ },
+ {0, "srv", 2, {{1, "port"}, {0, "ttl"}, }},
+ {0, "a", 1, {{1, "ttl"}, }}
+};
+
+static int
+wl_wowl_wog_parse_txt(char ***argv, wog_sd_resp_t *resp,
+ int subcnt, wowl_wog_resp_subcmd_t *sublist)
+{
+ int ret = BCME_OK;
+ int subidx;
+ int i;
+ int val;
+ char *stop;
+
+ while (**argv) {
+ subidx = -1;
+ for (i = 0; i < subcnt; i++) {
+ if (!strncmp(**argv, sublist[i].subname,
+ WOG_RESP_MAX_CMD_LEN + 1)) {
+ subidx = i;
+ break;
+ }
+ }
+
+ /* Toss cmd to upper layer */
+ if (subidx < 0) {
+ goto EXIT;
+ }
+
+ if (!*++*argv) {
+ printf("no subparam for txt record.\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ switch (subidx) {
+ case WOG_SUBCMD_TXT_ID:
+ strncpy(resp->txt.id, **argv, GCAST_UUID_LEN);
+ resp->txt.id[GCAST_UUID_LEN] = 0;
+ break;
+ case WOG_SUBCMD_TXT_CA:
+ val = strtoul(**argv, &stop, 16);
+ if (val > 0x0f ||
+ (!val && stop == **argv)) {
+ printf("TXT capability should be 0 to f and hex value\n");
+ return BCME_BADARG;
+ }
+ resp->txt.capability = ***argv;
+ break;
+ case WOG_SUBCMD_TXT_ST:
+ val = strtoul(**argv, NULL, 16);
+ if ((val != 0) && (val != 1)) {
+ printf("TXT receiver_status_flag should be 0 or 1\n");
+ return BCME_BADARG;
+ }
+ resp->txt.receiver_status_flag = ***argv;
+ break;
+ case WOG_SUBCMD_TXT_VE:
+ val = strtoul(**argv, NULL, 16);
+ if (val < 2 || val > 255) {
+ printf("TXT version >= 2 && version <= 255\n");
+ return BCME_BADARG;
+ }
+ snprintf(resp->txt.ver, GCAST_VER_LEN + 1, "%02x", val);
+ break;
+ case WOG_SUBCMD_TXT_MD:
+ strncpy(resp->txt.model_name, **argv, GCAST_MAX_MODEL_NAME_LEN);
+ resp->txt.model_name[GCAST_MAX_MODEL_NAME_LEN] = 0;
+ break;
+ case WOG_SUBCMD_TXT_PK:
+ strncpy(resp->txt.public_key, **argv, GCAST_PUBLICKEY_ID_LEN);
+ resp->txt.public_key[GCAST_PUBLICKEY_ID_LEN] = 0;
+ break;
+ case WOG_SUBCMD_TXT_FN:
+ strncpy(resp->txt.friendly_name, **argv, GCAST_MAX_FNAME_LEN);
+ resp->txt.friendly_name[GCAST_MAX_FNAME_LEN] = 0;
+ break;
+ case WOG_SUBCMD_TXT_RS:
+ strncpy(resp->txt.receiver_status, **argv, GCAST_MAX_RS_LEN);
+ resp->txt.receiver_status[GCAST_MAX_RS_LEN] = 0;
+ break;
+ case WOG_SUBCMD_TXT_TTL:
+ val = atoi(**argv);
+ if (val <= 0) {
+ printf("TXT ttl > 0\n");
+ return BCME_BADARG;
+ }
+ resp->txt.ttl = htod32(val);
+ break;
+ }
+
+ sublist[subidx].mandatory = 0;
+ ++*argv;
+ }
+
+
+EXIT:
+ --*argv; /* rewind for upper layer */
+
+ for (i = 0; i < subcnt; i++) {
+ if (sublist[i].mandatory) {
+ return BCME_USAGE_ERROR;
+ }
+ }
+ return ret;
+}
+
+static int
+wl_wowl_wog_parse_srv(char ***argv, wog_sd_resp_t *resp,
+ int subcnt, wowl_wog_resp_subcmd_t *sublist)
+{
+ int ret = BCME_OK;
+ int subidx;
+ int i, val;
+
+ while (**argv) {
+ subidx = -1;
+ for (i = 0; i < subcnt; i++) {
+ if (!strncmp(**argv, sublist[i].subname,
+ WOG_RESP_MAX_CMD_LEN + 1)) {
+ subidx = i;
+ break;
+ }
+ }
+
+ /* Toss cmd to upper layer */
+ if (subidx < 0) {
+ goto EXIT;
+ }
+
+ if (!*++*argv) {
+ printf("no subparam for SRV record.\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ switch (subidx) {
+ case WOG_SUBCMD_SRV_PORT:
+ val = atoi(**argv);
+ if (val <= 0 || val > 0xffff) {
+ printf("SRV port : 0 < port && port <= 0xffff\n");
+ return BCME_BADARG;
+ }
+ resp->srv.port = htod16(val);
+ break;
+ case WOG_SUBCMD_SRV_TTL:
+ val = atoi(**argv);
+ if (val <= 0) {
+ printf("SRV ttl > 0\n");
+ return BCME_BADARG;
+ }
+ resp->srv.ttl = htod32(val);
+ break;
+ }
+
+ sublist[subidx].mandatory = 0;
+ ++*argv;
+ }
+
+EXIT:
+ --*argv; /* rewind for upper layer */
+
+ for (i = 0; i < subcnt; i++) {
+ if (sublist[i].mandatory) {
+ printf("No input for srv port or ttl\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+
+ return ret;
+}
+
+static int
+wl_wowl_wog_parse_a(char ***argv, wog_sd_resp_t *resp,
+ int subcnt, wowl_wog_resp_subcmd_t *sublist)
+{
+ int ret = BCME_OK;
+ int subidx;
+ int i, val;
+
+ while (**argv) {
+ subidx = -1;
+ for (i = 0; i < subcnt; i++) {
+ if (!strncmp(**argv, sublist[i].subname,
+ WOG_RESP_MAX_CMD_LEN + 1)) {
+ subidx = i;
+ break;
+ }
+ }
+
+ /* Toss cmd to upper layer */
+ if (subidx < 0) {
+ goto EXIT;
+ }
+
+ if (!*++*argv) {
+ printf("no subparam for A record.\n");
+ return BCME_USAGE_ERROR;
+ }
+
+ switch (subidx) {
+ case WOG_SUBCMD_A_TTL:
+ val = atoi(**argv);
+ if (val <= 0) {
+ printf("A ttl > 0\n");
+ return BCME_BADARG;
+ }
+
+ resp->a.ttl = htod32(val);
+ break;
+ }
+
+ sublist[subidx].mandatory = 0;
+ ++*argv;
+ }
+
+EXIT:
+ --*argv; /* rewind for upper layer */
+
+ for (i = 0; i < subcnt; i++) {
+ if (sublist[i].mandatory) {
+ printf("No input for a ttl\n");
+ return BCME_USAGE_ERROR;
+ }
+ }
+ return ret;
+}
+
+static int
+wl_wowl_wog_resp(void *wl, cmd_t *cmd, char **argv)
+{
+ wog_sd_resp_t *resp = NULL;
+ int ret = BCME_OK;
+ int cmdcnt;
+ int cmdidx;
+ int i, val;
+ struct ipv4_addr ip;
+ wowl_wog_resp_cmd_t *cmdlist = NULL;
+
+ UNUSED_PARAMETER(wl);
+ UNUSED_PARAMETER(cmd);
+
+ if (!*++argv) {
+ return BCME_USAGE_ERROR;
+ }
+
+ resp = (wog_sd_resp_t *)malloc(sizeof(*resp));
+ cmdlist = (wowl_wog_resp_cmd_t *)malloc(sizeof(wog_resp_cmdlist));
+
+ if (!resp || !cmdlist) {
+ ret = BCME_NOMEM;
+ goto EXIT;
+ }
+
+ memset(resp, 0, sizeof(*resp));
+ memcpy(cmdlist, wog_resp_cmdlist, sizeof(wog_resp_cmdlist));
+ cmdcnt = sizeof(wog_resp_cmdlist)/sizeof(wowl_wog_resp_cmd_t);
+
+ resp->ver = WOG_SD_RESP_VER;
+
+ if (!strncmp(*argv, "show", 5)) {
+ wog_sd_resp_t *r;
+ ret = wlu_iovar_getbuf(wl, cmd->name, NULL, 0, buf, WLC_IOCTL_MAXLEN);
+ if (ret != BCME_OK) {
+ goto EXIT;
+ }
+
+ r = (wog_sd_resp_t *)buf;
+
+ if (r->ver != WOG_SD_RESP_VER) {
+ ret = BCME_VERSION;
+ goto EXIT;
+ }
+
+ printf("device name=%s\n"
+ "ip=%d.%d.%d.%d, answer ttl=%d\n"
+ "txt id=%s, capability=%c, receiver_status_flag=%c, "
+ "version=%s, model_name=%s, public_key=%s, "
+ "friendly_name=%s, receiver_status=%s, txt ttl=%d\n"
+ "srv port=%d, srv ttl=%d\n"
+ "a ttl=%d\n",
+ r->device_name,
+ r->ip[0], r->ip[1], r->ip[2], r->ip[3],
+ dtoh32(r->ptr_ttl),
+ r->txt.id, r->txt.capability, r->txt.receiver_status_flag,
+ r->txt.ver, r->txt.model_name, r->txt.public_key,
+ r->txt.friendly_name, r->txt.receiver_status,
+ dtoh32(r->txt.ttl),
+ dtoh16(r->srv.port), dtoh32(r->srv.ttl),
+ dtoh32(r->a.ttl));
+ goto EXIT;
+ }
+
+ while (*argv) {
+ cmdidx = -1;
+ for (i = 0; i < cmdcnt; i++) {
+ if (!strncmp(*argv, cmdlist[i].cname,
+ WOG_RESP_MAX_CMD_LEN + 1)) {
+ cmdidx = i;
+ break;
+ }
+ }
+
+ if (cmdidx < 0 || !*++argv) {
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+
+ switch (cmdidx) {
+ case WOG_CMD_DEVNAME:
+ strncpy(resp->device_name, *argv, MAX_DNS_LABEL);
+ resp->device_name[MAX_DNS_LABEL] = 0;
+ break;
+ case WOG_CMD_IP:
+ if (!wl_atoip(*argv, &ip)) {
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+ memcpy(resp->ip, ip.addr, IPV4_ADDR_LEN);
+ break;
+ case WOG_CMD_TTL:
+ val = atoi(*argv);
+ if (val <= 0) {
+ printf("PTR ttl > 0\n");
+ ret = BCME_BADARG;
+ goto EXIT;
+ }
+ resp->ptr_ttl = htod32(val);
+ break;
+ case WOG_CMD_TXT:
+ if (wl_wowl_wog_parse_txt(&argv, resp,
+ cmdlist[WOG_CMD_TXT].subcnt,
+ cmdlist[WOG_CMD_TXT].subcmd) != BCME_OK) {
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+ break;
+ case WOG_CMD_SRV:
+ if (wl_wowl_wog_parse_srv(&argv, resp,
+ cmdlist[WOG_CMD_SRV].subcnt,
+ cmdlist[WOG_CMD_SRV].subcmd) != BCME_OK) {
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+ break;
+ case WOG_CMD_A:
+ if (wl_wowl_wog_parse_a(&argv, resp,
+ cmdlist[WOG_CMD_A].subcnt,
+ cmdlist[WOG_CMD_A].subcmd) != BCME_OK) {
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+ break;
+ default:
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+ cmdlist[cmdidx].mandatory = 0;
+ argv++;
+ }
+
+ /* Check if all mendatory fields exist or not */
+ for (i = 0; i < cmdcnt; i++) {
+ if (cmdlist[i].mandatory) {
+ ret = BCME_USAGE_ERROR;
+ goto EXIT;
+ }
+ }
+
+ ret = wlu_iovar_set(wl, cmd->name, resp, sizeof(*resp));
+
+EXIT:
+ if (resp) {
+ free(resp);
+ }
+ if (cmdlist) {
+ free(cmdlist);
+ }
+ return ret;
+}
diff --git a/wl/src/wl/ppr/include/wlc_ppr.h b/wl/src/wl/ppr/include/wlc_ppr.h
new file mode 100644
index 0000000..5818b75
--- /dev/null
+++ b/wl/src/wl/ppr/include/wlc_ppr.h
@@ -0,0 +1,461 @@
+/**
+ * @file
+ * @brief
+ * PHY module Power-per-rate API. Provides interface functions and definitions for opaque
+ * ppr structure for use containing regulatory and board limits and tx power targets.
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id$
+ */
+
+/** Twiki's: [MfgcPresentations] [PPRTxPowerCache] */
+
+#ifndef _wlc_ppr_h_
+#define _wlc_ppr_h_
+
+#include <bcmwifi_rates.h>
+#include <bcmutils.h>
+#include <bcmwifi_channels.h>
+
+#ifdef EVENT_LOG_COMPILE
+#include <event_log.h>
+#endif /* EVENT_LOG_COMPILE */
+
+#ifdef BCMDRIVER
+#include <osl.h>
+
+#ifdef BCMDBG_ERR
+#if defined(ERR_USE_EVENT_LOG)
+#define PPR_ERROR(args) EVENT_LOG_COMPACT_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_ERROR, args)
+#else
+#define PPR_ERROR(args) printf args
+#endif /* ERR_USE_EVENT_LOG */
+#else
+#define PPR_ERROR(args)
+#endif /* BCMDBG_ERR */
+#else
+#include <stdio.h>
+#define osl_t void
+#define PPR_ERROR(args) printf args
+#endif /* BCMDRIVER */
+
+#ifndef BCMPHYCORENUM
+#define PPR_MAX_TX_CHAINS 4
+#else
+#if (BCMPHYCORENUM < 1) || (BCMPHYCORENUM > 4)
+#error Invalid number of PHY cores
+#endif /* BCMPHYCORENUM < 1 || BCMPHYCORENUM > 4 */
+#define PPR_MAX_TX_CHAINS (BCMPHYCORENUM)
+#endif /* !defined(BCMPHYCORENUM) */
+
+#define WL_RATE_GROUP_VHT_INDEX_MCS_7 7
+#define WL_RATE_GROUP_VHT_INDEX_MCS_87 8
+#define WL_RATE_GROUP_VHT_INDEX_MCS_88 9
+
+#ifdef NO_EXTRA_BW_SUPPORT /* For ROM compatiblity */
+#define PPR_CHSPEC_BW(x) (CHSPEC_IS80(x) ? WL_TX_BW_80 : \
+ (CHSPEC_IS40(x) ? WL_TX_BW_40 : WL_TX_BW_20))
+#else
+#define PPR_CHSPEC_BW(x) ppr_chanspec_bw(x)
+#endif /* NO_EXTRA_BW_SUPPORT */
+
+
+/* Opaque PPR data - it keeps its structure to itself */
+typedef struct ppr ppr_t;
+
+
+/* Power values for DSSS 1, 2, 5.5, 11 */
+typedef struct ppr_dsss_rateset { int8 pwr[WL_RATESET_SZ_DSSS]; } ppr_dsss_rateset_t;
+
+/* Power values for OFDM 6, 9, 12... 54 */
+typedef struct ppr_ofdm_rateset { int8 pwr[WL_RATESET_SZ_OFDM]; } ppr_ofdm_rateset_t;
+
+/* Power values one set of 8 HT MCS values (0-7, 8-15, etc) */
+typedef struct ppr_ht_mcs_rateset { int8 pwr[WL_RATESET_SZ_HT_MCS]; } ppr_ht_mcs_rateset_t;
+
+/* Power values one set of 10 VHT MCS values (0-9) */
+
+#ifdef NO_PROPRIETARY_VHT_RATES
+typedef struct ppr_vht_mcs_rateset { int8 pwr[WL_RATESET_SZ_VHT_MCS]; } ppr_vht_mcs_rateset_t;
+#else
+typedef struct ppr_vht_mcs_rateset { int8 pwr[WL_RATESET_SZ_VHT_MCS_P]; } ppr_vht_mcs_rateset_t;
+#endif
+
+
+/* API Routines */
+
+/* Initialization routine for opaque PPR struct */
+void ppr_init(ppr_t* pprptr, wl_tx_bw_t bw);
+
+/* Reinitialization routine for opaque PPR struct */
+void ppr_clear(ppr_t* pprptr);
+
+
+/* Size routine for user alloc/dealloc */
+uint32 ppr_size(wl_tx_bw_t bw);
+
+/* Size routine for user serialization alloc */
+uint32 ppr_ser_size(const ppr_t* pprptr);
+
+/* Size routine for user serialization alloc for a given bw */
+uint32 ppr_ser_size_by_bw(wl_tx_bw_t bw);
+
+/* Init allocated memory with a ppr serialization head
+ * This function must be called if serialization side has different
+ * compilation conditions (e.g PPR_MAX_TX_CHAINS, WL_BEAMFORMING etc.)
+ */
+int ppr_init_ser_mem_by_bw(uint8* pbuf, wl_tx_bw_t bw, uint32 len);
+
+/* Init allocated memory with a ppr serialization head for the given ppr pointer
+ * This function must be called if serialization side has different
+ * compilation conditions (e.g PPR_MAX_TX_CHAINS, WL_BEAMFORMING etc.)
+ */
+int ppr_init_ser_mem(uint8* pbuf, ppr_t * ppr, uint32 len);
+
+/* Constructor routine for opaque PPR struct */
+ppr_t* ppr_create(osl_t* osh, wl_tx_bw_t bw);
+
+/* Constructor routine for opaque PPR struct on pre-alloc memory */
+ppr_t* ppr_create_prealloc(wl_tx_bw_t bw, int8 *buf, uint len);
+
+/* Update the bw for the given opaque PPR struct */
+void ppr_set_ch_bw(ppr_t* pprptr, wl_tx_bw_t bw);
+
+/* Destructor routine for opaque PPR struct */
+void ppr_delete(osl_t* osh, ppr_t* pprptr);
+
+/* Type routine for inferring opaque structure size */
+wl_tx_bw_t ppr_get_ch_bw(const ppr_t* pprptr);
+
+/* Type routine to get ppr supported maximum bw */
+wl_tx_bw_t ppr_get_max_bw(void);
+/* Get the maximum power in the dsss ppr set */
+int8 ppr_get_dsss_max(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains);
+/* Get the DSSS values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_get_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains,
+ ppr_dsss_rateset_t* dsss);
+
+/* Get the OFDM values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_get_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains,
+ ppr_ofdm_rateset_t* ofdm);
+
+/* Get the HT MCS values for the group specified by Nss, with the given bw and tx chains */
+int ppr_get_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, ppr_ht_mcs_rateset_t* mcs);
+
+/* Get the VHT MCS values for the group specified by Nss, with the given bw and tx chains */
+int ppr_get_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, ppr_vht_mcs_rateset_t* mcs);
+
+/* Get the minimum power for a VHT MCS rate specified by Nss, with the given bw and tx chains.
+ * Disabled rates are ignored
+ */
+int ppr_get_vht_mcs_min(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, int8* mcs_min);
+
+
+/* Routines to set target powers per rate for a whole rate set */
+
+/* Set the DSSS values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_set_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains,
+ const ppr_dsss_rateset_t* dsss);
+
+/* Set the OFDM values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_set_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains,
+ const ppr_ofdm_rateset_t* ofdm);
+
+/* Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */
+int ppr_set_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, const ppr_ht_mcs_rateset_t* mcs);
+
+/* Set the VHT MCS values for the group specified by Nss, with the given bw and tx chains */
+int ppr_set_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, const ppr_vht_mcs_rateset_t* mcs);
+
+
+/* Routines to set a whole rate set to a single target value */
+
+/* Set the DSSS values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_set_same_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains, const int8 power);
+
+/* Set the OFDM values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_set_same_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains,
+ const int8 power);
+
+/* Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */
+int ppr_set_same_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, const int8 power);
+
+
+/* Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */
+int ppr_set_same_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, const int8 power);
+
+
+/* Helper routines to operate on the entire ppr set */
+
+/* Ensure no rate limit is greater than the specified maximum */
+uint ppr_apply_max(ppr_t* pprptr, int8 max);
+
+/* Make disabled rates explicit. If one rate in a group is disabled, disable the whole group */
+int ppr_force_disabled(ppr_t* pprptr, int8 threshold);
+
+/* Explicitly disable all VHT-only MIMO rates - i.e. vht8SS2 and above. */
+int ppr_disable_vht_mimo_rates(ppr_t* pprptr);
+
+/*
+ * Reduce total transmitted power to level of constraint.
+ * For two chain rates, the per-antenna power must be halved.
+ * For three chain rates, it must be a third of the constraint.
+ */
+uint ppr_apply_constraint_total_tx(ppr_t* pprptr, int8 constraint);
+
+/* Ensure no rate limit is lower than the specified minimum */
+uint ppr_apply_min(ppr_t* pprptr, int8 min);
+
+
+/* Ensure no rate limit in this ppr set is greater than the corresponding limit in ppr_cap */
+uint ppr_apply_vector_ceiling(ppr_t* pprptr, const ppr_t* ppr_cap);
+
+/* Ensure no rate limit in this ppr set is lower than the corresponding limit in ppr_min */
+uint ppr_apply_vector_floor(ppr_t* pprptr, const ppr_t* ppr_min);
+
+
+/* Get the maximum power in the ppr set */
+int8 ppr_get_max(ppr_t* pprptr);
+
+/*
+ * Get the minimum power in the ppr set excluding disallowed
+ * rates and powers set to the minimum for the phy
+ */
+int8 ppr_get_min(ppr_t* pprptr, int8 floor);
+
+
+/* Get the maximum power for a given bandwidth in the ppr set */
+int8 ppr_get_max_for_bw(ppr_t* pprptr, wl_tx_bw_t bw);
+
+/* Get the minimum power for a given bandwidth in the ppr set */
+int8 ppr_get_min_for_bw(ppr_t* pprptr, wl_tx_bw_t bw);
+
+
+typedef void (*ppr_mapfn_t)(void *context, uint8 *a, uint8 *b);
+
+/* Map the given function with its context value over the two power vectors */
+void ppr_map_vec_dsss(ppr_mapfn_t fn, void* context, ppr_t* pprptr1,
+ ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_chains_t tx_chains);
+
+/* Map the given function with its context value over the two power vectors */
+void ppr_map_vec_ofdm(ppr_mapfn_t fn, void* context, ppr_t* pprptr1,
+ ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains);
+
+/* Map the given function with its context value over the two power vectors */
+void ppr_map_vec_ht_mcs(ppr_mapfn_t fn, void* context, ppr_t* pprptr1,
+ ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains);
+
+/* Map the given function with its context value over the two power vectors */
+void ppr_map_vec_vht_mcs(ppr_mapfn_t fn, void* context, ppr_t* pprptr1,
+ ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains);
+
+/* Map the given function with its context value over the two power vectors */
+void ppr_map_vec_all(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, ppr_t* pprptr2);
+
+/* Get the first index that is larger than a given power level */
+int16 ppr_get_idx(ppr_t* pprptr, int8 pwr);
+
+/* Set PPR struct to a certain power level */
+void ppr_set_cmn_val(ppr_t* pprptr, int8 val);
+
+/* Make an identical copy of a ppr structure (for ppr_bw==all case) */
+void ppr_copy_struct(ppr_t* pprptr_s, ppr_t* pprptr_d);
+
+/* Subtract each power from a common value and re-store */
+void ppr_cmn_val_minus(ppr_t* pprptr, int8 val);
+
+/* Compare two ppr variables p1 and p2, save the min. value of each
+ * contents to variable p1
+ */
+void ppr_compare_min(ppr_t* p1, ppr_t* p2);
+
+/* compare two ppr variables p1 and p2, save the max. value of each
+ * contents to variable p1
+ */
+void ppr_compare_max(ppr_t* p1, ppr_t* p2);
+
+/* Serialize the contents of the opaque ppr struct.
+ * Writes number of bytes copied, zero on error.
+ * Returns error code, BCME_OK if successful.
+ */
+int ppr_serialize(const ppr_t* pprptr, uint8* buf, uint buflen, uint* bytes_copied);
+
+/* Deserialize the contents of a buffer into an existing opaque ppr struct.
+ * The ppr struct *must* be of the same type as the one that was serialized.
+ * Returns error code, BCME_OK if successful.
+ */
+int ppr_deserialize(ppr_t* pprptr, const uint8* buf, uint buflen);
+
+/* Deserialize the contents of a buffer into a new opaque ppr struct.
+ * Creates an opaque structure referenced by *pptrptr, NULL on error.
+ * Returns error code, BCME_OK if successful.
+ */
+int ppr_deserialize_create(osl_t* osh, const uint8* buf, uint buflen, ppr_t** pprptr);
+
+/* Subtract a common value from each power and re-store */
+void ppr_minus_cmn_val(ppr_t* pprptr, int8 val);
+
+/* Add a common value to the given bw struct components */
+void ppr_plus_cmn_val(ppr_t* pprptr, int8 val);
+
+/* Multiply a percentage */
+void ppr_multiply_percentage(ppr_t* pprptr, uint8 val);
+
+/* Get transmit channel bandwidths from chanspec */
+wl_tx_bw_t ppr_chanspec_bw(chanspec_t chspec);
+
+#if defined(WL_EXPORT_CURPOWER) || !defined(BCMDRIVER)
+/* Convert ppr structure to TLV data */
+void ppr_convert_to_tlv(ppr_t* pprptr, wl_tx_bw_t bw, uint8 *to_tlv_buf, uint32 tlv_buf_len,
+ wl_tx_chains_t max_chain);
+
+/* Convert TLV data to ppr structure */
+int ppr_convert_from_tlv(ppr_t* pprptr, uint8 *from_tlv_buf, uint32 tlv_buf_len);
+
+/* Get the total ppr TLV buffer size for given bandwidth and chain number */
+uint32 ppr_get_tlv_size(ppr_t* pprptr, wl_tx_bw_t bw, uint32 max_chain);
+
+/* Get current PPR TLV version */
+uint32 ppr_get_tlv_ver(void);
+#endif /* WL_EXPORT_CURPOWER || !BCMDRIVER */
+
+/* Forward declaration */
+typedef struct tx_pwr_cache_entry tx_pwr_cache_entry_t;
+
+#ifdef WLTXPWR_CACHE
+
+/**
+ * Usage of the WLTXPWR_CACHE API:
+ * 1. Reserve one or more entries in the cache for a specific chanspec:
+ * wlc_phy_txpwr_setup_entry(chanspec1);
+ * wlc_phy_txpwr_setup_entry(chanspec2);
+ * 2. Use any of the getter/setter functions. Note that they may return an error on a chanspec
+ * that was not reserved. For setter functions, for pointer type arguments (e.g. ppr_t), the
+ * cache maintains a reference to the caller provided object rather than copying it.
+ * 3. Use wlc_phy_txpwr_cache_clear() or wlc_phy_txpwr_cache_invalidate() to get rid of cache
+ * entries. Note that this clears, amongst others, ppr_t structs.
+ *
+ * For non-BMAC builds, only the cache is allowed to delete the ppr_t object, and the driver code is
+ * not allowed to reuse it for another channel as it can when the cache is not being used.
+ *
+ * For BMAC builds, the cache has to be made to release the stf offsets object to avoid some nasty
+ * race conditions.
+ *
+ * Mike thinks when this is reimplemented for trunk he would consider having a reference count
+ * associated with each object to make this cleaner.
+ *
+ * Note that the functions start with wlc_phy_* despite not residing in the PHY code. This is
+ * probably for historical reasons.
+ */
+
+enum txpwr_cache_info_type {
+ TXPWR_CACHE_STF_OFFSETS, /* PPR offsets for stf */
+ TXPWR_CACHE_POWER_OFFSETS, /* PPR offsets for phy */
+ TXPWR_CACHE_NUM_TYPES, /* How many types of pwr info */
+};
+
+#define TXPWR_STF_PWR_MIN_INVALID 0x80
+#define TXPWR_STF_TARGET_PWR_MIN_INVALID 0x40
+#define TXPWR_STF_TARGET_PWR_NOT_CACHED 0x20
+extern bool wlc_phy_get_cached_pwr(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint pwr_type, ppr_t* pprptr);
+
+extern ppr_t* wlc_phy_get_cached_ppr_ptr(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint pwr_type);
+
+extern int wlc_phy_set_cached_pwr(osl_t* osh, tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint pwr_type, ppr_t* pwrptr);
+
+extern int8 wlc_phy_get_cached_boardlim(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint core);
+
+extern int wlc_phy_set_cached_boardlim(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint core, int8 board_lim);
+
+extern uint8 wlc_phy_get_cached_pwr_max(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint core);
+
+extern int wlc_phy_set_cached_pwr_max(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint core, uint8 max_pwr);
+
+extern uint8 wlc_phy_get_cached_pwr_min(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint core);
+
+extern int wlc_phy_set_cached_pwr_min(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint core, uint8 min_pwr);
+
+extern int wlc_phy_get_cached_stf_target_pwr_min(tx_pwr_cache_entry_t* cacheptr,
+ chanspec_t chanspec);
+
+extern int wlc_phy_set_cached_stf_target_pwr_min(tx_pwr_cache_entry_t* cacheptr,
+ chanspec_t chanspec, int min_pwr);
+
+extern int8 wlc_phy_get_cached_txchain_offsets(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint core);
+
+extern int wlc_phy_set_cached_txchain_offsets(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint core, int8 offset);
+
+extern bool wlc_phy_txpwr_cache_is_cached(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec);
+
+extern bool wlc_phy_is_pwr_cached(tx_pwr_cache_entry_t* cacheptr, uint pwr_type, ppr_t* pwrptr);
+
+extern void wlc_phy_uncache_pwr(tx_pwr_cache_entry_t* cacheptr, uint pwr_type, ppr_t* pwrptr);
+
+extern chanspec_t wlc_phy_txpwr_cache_find_other_cached_chanspec(tx_pwr_cache_entry_t* cacheptr,
+ chanspec_t chanspec);
+
+extern tx_pwr_cache_entry_t* wlc_phy_txpwr_cache_create(osl_t* osh);
+
+extern void wlc_phy_txpwr_cache_clear(osl_t* osh, tx_pwr_cache_entry_t* cacheptr,
+ chanspec_t chanspec);
+
+extern void wlc_phy_txpwr_cache_invalidate(tx_pwr_cache_entry_t* cacheptr);
+
+extern void wlc_phy_txpwr_cache_close(osl_t* osh, tx_pwr_cache_entry_t* cacheptr);
+
+extern int wlc_phy_txpwr_setup_entry(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec);
+
+#ifdef WL_SARLIMIT
+void wlc_phy_set_cached_sar_lims(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint32 sar_lims);
+
+uint32 wlc_phy_get_cached_sar_lims(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec);
+#endif
+
+#ifndef WLTXPWR_CACHE_PHY_ONLY
+extern bool wlc_phy_get_stf_ppr_cached(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec);
+
+extern void wlc_phy_set_stf_ppr_cached(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ bool bcached);
+
+extern int wlc_phy_get_cached_stf_pwr_min_dbm(tx_pwr_cache_entry_t* cacheptr);
+
+extern void wlc_phy_set_cached_stf_pwr_min_dbm(tx_pwr_cache_entry_t* cacheptr, int min_pwr);
+
+extern void wlc_phy_set_cached_stf_max_offset(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint8 max_offset);
+
+extern uint8 wlc_phy_get_cached_stf_max_offset(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec);
+#endif /* WLTXPWR_CACHE_PHY_ONLY */
+#endif /* WLTXPWR_CACHE */
+#endif /* _wlc_ppr_h_ */
diff --git a/wl/src/wl/ppr/src/wlc_ppr.c b/wl/src/wl/ppr/src/wlc_ppr.c
new file mode 100644
index 0000000..29f92be
--- /dev/null
+++ b/wl/src/wl/ppr/src/wlc_ppr.c
@@ -0,0 +1,3515 @@
+/**
+ * @file
+ * @brief
+ * PHY module Power-per-rate API. Provides interface functions and definitions for
+ * ppr structure for use containing regulatory and board limits and tx power targets.
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: $
+ */
+
+/**
+ * @file
+ * @brief
+ * Sometimes not all rates should reach the same max power, in order to comply with FCC. Different
+ * rates (even different sub-band bands) may want different max power.
+ *
+ * real_max_power[antenna, rate] = max_power[antenna] - power_offset[rate]
+ *
+ * Both regulatory restrictions (by wlc_channel.c) and SPROM restrictions (SPROm is read by phy
+ * code) determine this power offset.
+ */
+
+
+#if defined(__FreeBSD__)
+#if defined(_KERNEL)
+#include <wlc_cfg.h>
+#endif /* defined(_KERNEL) */
+#endif
+
+#include <typedefs.h>
+#include <bcmendian.h>
+#include <bcmwifi_channels.h>
+#include <wlc_ppr.h>
+#include <bcmutils.h>
+
+#ifndef BCMDRIVER
+
+#ifndef WL_BEAMFORMING
+#define WL_BEAMFORMING /* enable TxBF definitions for utility code */
+#endif
+
+#ifndef WL11AC_160
+#define WL11AC_160 /* Enable WL11AC_160 for utility code */
+#endif
+
+#ifndef WL11AC_80P80
+#define WL11AC_80P80 /* Enable WL11AC_80P80 for utility code */
+#endif
+
+#ifndef bcopy
+#include <string.h>
+#include <stdlib.h>
+#define bcopy(src, dst, len) memcpy((dst), (src), (len))
+#endif
+
+#ifndef ASSERT
+#define ASSERT(exp) do {} while (0)
+#endif
+#endif /* BCMDRIVER */
+
+/* ppr local TXBF_ENAB() macro because wlc->pub struct is not accessible */
+#ifdef WL_BEAMFORMING
+#if defined(WLTXBF_DISABLED)
+#define PPR_TXBF_ENAB() (0)
+#else
+#define PPR_TXBF_ENAB() (1)
+#endif
+#else
+#define PPR_TXBF_ENAB() (0)
+#endif /* WL_BEAMFORMING */
+
+typedef enum ppr_tlv_id {
+ PPR_RGRP_DSSS_ID = 1,
+ PPR_RGRP_OFDM_ID,
+ PPR_RGRP_MCS_ID
+} ppr_tlv_id_t;
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#define PPR_SERIALIZATION_VER 3
+#define PPR_TLV_VER (PPR_SERIALIZATION_VER + 1)
+
+/** ppr deserialization header */
+typedef BWL_PRE_PACKED_STRUCT struct ppr_deser_header {
+ uint8 version;
+ uint8 bw;
+ uint16 per_band_size;
+ uint32 flags;
+ uint16 chain3size; /* ppr data size of 3 Tx chains, needed in deserialisation process */
+} BWL_POST_PACKED_STRUCT ppr_deser_header_t;
+
+
+typedef BWL_PRE_PACKED_STRUCT struct ppr_ser_mem_flag {
+ uint32 magic_word;
+ uint32 flag;
+} BWL_POST_PACKED_STRUCT ppr_ser_mem_flag_t;
+
+
+#define WLC_TXPWR_DB_FACTOR 4 /* conversion for phy txpwr cacluations that use .25 dB units */
+
+
+/* QDB() macro takes a dB value and converts to a quarter dB value */
+#ifdef QDB
+#undef QDB
+#endif
+#define QDB(n) ((n) * WLC_TXPWR_DB_FACTOR)
+
+#define PPR_HDR_CUR_BW_MASK 0x000000FF
+#define PPR_HDR_ALLOC_BW_MASK 0x0000FF00
+#define PPR_HDR_FLAG_MASK 0xFFFF0000
+#define PPR_HDR_ALLOC_BW_SHIFT 8
+
+/* PPR flags, start defining from left to right, in case bandwidth needs more bits */
+#define PPR_HDR_FLAG_PREALLOC 0x80000000 /* ppr structure is on a pre-allocaed memory */
+
+/* Flag bits in serialization/deserialization */
+#define PPR_MAX_TX_CHAIN_MASK 0x0000007 /* mask of Tx chains */
+#define PPR_SER_MEM_WORD 0xBEEFC0FF /* magic word indicates serialization start */
+
+
+/* size of serialization header */
+#define SER_HDR_LEN sizeof(ppr_deser_header_t)
+
+/** Per band tx powers */
+typedef BWL_PRE_PACKED_STRUCT struct pprpb {
+ /* start of 20MHz tx power limits */
+ int8 p_1x1dsss[WL_RATESET_SZ_DSSS]; /* Legacy CCK/DSSS */
+ int8 p_1x1ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM transmission */
+ int8 p_1x1vhtss1[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 1x1mcs0 */
+#if (PPR_MAX_TX_CHAINS > 1)
+ int8 p_1x2dsss[WL_RATESET_SZ_DSSS]; /* Legacy CCK/DSSS */
+ int8 p_1x2cdd_ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM CDD transmission */
+ int8 p_1x2cdd_vhtss1[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 1x2cdd_mcs0 */
+ int8 p_2x2stbc_vhtss1[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 2x2stbc_mcs0 */
+ int8 p_2x2vhtss2[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 2x2sdm_mcs8 */
+ int8 p_1x2txbf_ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM TXBF transmission */
+ int8 p_1x2txbf_vhtss1[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 1x2txbf_mcs0 */
+ int8 p_2x2txbf_vhtss2[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 2x2txbf_mcs8 */
+#if (PPR_MAX_TX_CHAINS > 2)
+ int8 p_1x3dsss[WL_RATESET_SZ_DSSS]; /* Legacy CCK/DSSS */
+ int8 p_1x3cdd_ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM CDD transmission */
+ int8 p_1x3cdd_vhtss1[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 1x3cdd_mcs0 */
+ int8 p_2x3stbc_vhtss1[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 2x3stbc_mcs0 */
+ int8 p_2x3vhtss2[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 2x3sdm_mcs8 spexp1 */
+ int8 p_3x3vhtss3[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 3x3sdm_mcs16 */
+ int8 p_1x3txbf_ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM TXBF transmission */
+ int8 p_1x3txbf_vhtss1[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 1x3txbf_mcs0 */
+ int8 p_2x3txbf_vhtss2[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 2x3txbf_mcs8 */
+ int8 p_3x3txbf_vhtss3[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 3x3txbf_mcs16 */
+#if (PPR_MAX_TX_CHAINS > 3)
+ int8 p_1x4dsss[WL_RATESET_SZ_DSSS]; /* Legacy CCK/DSSS */
+ int8 p_1x4cdd_ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM CDD transmission */
+ int8 p_1x4cdd_vhtss1[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 1x4cdd_mcs0 */
+ int8 p_2x4stbc_vhtss1[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 2x4stbc_mcs0 */
+ int8 p_2x4vhtss2[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 2x4sdm_mcs8 spexp1 */
+ int8 p_3x4vhtss3[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 3x4 ht_vht */
+ int8 p_4x4vhtss4[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 4x4 */
+ int8 p_1x4txbf_ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM TXBF transmission */
+ int8 p_1x4txbf_vhtss1[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 1x4txbf_mcs0 */
+ int8 p_2x4txbf_vhtss2[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 2x4txbf_mcs8 */
+ int8 p_3x4txbf_vhtss3[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 3x4txbf_mcs16 */
+ int8 p_4x4txbf_vhtss4[WL_RATESET_SZ_VHT_MCS_P]; /* 10HT/12VHT pwrs from 4x4txbf_mcs16 */
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+#endif /* PPR_MAX_TX_CHAINS > 1 */
+} BWL_POST_PACKED_STRUCT pprpbw_t;
+
+
+#define PPR_CHAIN1_FIRST OFFSETOF(pprpbw_t, p_1x1dsss)
+#define PPR_CHAIN1_END (OFFSETOF(pprpbw_t, p_1x1vhtss1) + sizeof(((pprpbw_t *)0)->p_1x1vhtss1))
+#define PPR_CHAIN1_SIZE PPR_CHAIN1_END
+#if (PPR_MAX_TX_CHAINS > 1)
+#define PPR_CHAIN2_FIRST OFFSETOF(pprpbw_t, p_1x2dsss)
+#define PPR_CHAIN2_FIRST_MCS OFFSETOF(pprpbw_t, p_1x2cdd_vhtss1)
+#define PPR_CHAIN2_END (OFFSETOF(pprpbw_t, p_2x2txbf_vhtss2) + \
+ sizeof(((pprpbw_t *)0)->p_2x2txbf_vhtss2))
+#define PPR_CHAIN2_SIZE (PPR_CHAIN2_END - PPR_CHAIN2_FIRST)
+#define PPR_CHAIN2_MCS_END (OFFSETOF(pprpbw_t, p_2x2vhtss2) + sizeof(((pprpbw_t *)0)->p_2x2vhtss2))
+#define PPR_CHAIN2_MCS_SIZE (PPR_CHAIN2_MCS_END - PPR_CHAIN2_FIRST_MCS)
+#define PPR_BF_CHAIN2_FIRST OFFSETOF(pprpbw_t, p_1x2txbf_ofdm)
+#define PPR_BF_CHAIN2_FIRST_MCS OFFSETOF(pprpbw_t, p_1x2txbf_vhtss1)
+#define PPR_BF_CHAIN2_END (OFFSETOF(pprpbw_t, p_2x2txbf_vhtss2) + \
+ sizeof(((pprpbw_t *)0)->p_2x2txbf_vhtss2))
+#define PPR_BF_CHAIN2_SIZE (PPR_BF_CHAIN2_END - PPR_BF_CHAIN2_FIRST)
+#define PPR_BF_CHAIN2_MCS_SIZE (PPR_BF_CHAIN2_END - PPR_BF_CHAIN2_FIRST_MCS)
+#if (PPR_MAX_TX_CHAINS > 2)
+#define PPR_CHAIN3_FIRST OFFSETOF(pprpbw_t, p_1x3dsss)
+#define PPR_CHAIN3_FIRST_MCS OFFSETOF(pprpbw_t, p_1x3cdd_vhtss1)
+#define PPR_CHAIN3_END (OFFSETOF(pprpbw_t, p_3x3txbf_vhtss3) + \
+ sizeof(((pprpbw_t *)0)->p_3x3txbf_vhtss3))
+#define PPR_CHAIN3_SIZE (PPR_CHAIN3_END - PPR_CHAIN3_FIRST)
+#define PPR_CHAIN3_MCS_END (OFFSETOF(pprpbw_t, p_3x3vhtss3) + sizeof(((pprpbw_t *)0)->p_3x3vhtss3))
+#define PPR_CHAIN3_MCS_SIZE (PPR_CHAIN3_MCS_END - PPR_CHAIN3_FIRST_MCS)
+#define PPR_BF_CHAIN3_FIRST OFFSETOF(pprpbw_t, p_1x3txbf_ofdm)
+#define PPR_BF_CHAIN3_FIRST_MCS OFFSETOF(pprpbw_t, p_1x3txbf_vhtss1)
+#define PPR_BF_CHAIN3_END (OFFSETOF(pprpbw_t, p_3x3txbf_vhtss3) + \
+ sizeof(((pprpbw_t *)0)->p_3x3txbf_vhtss3))
+#define PPR_BF_CHAIN3_SIZE (PPR_BF_CHAIN3_END - PPR_BF_CHAIN3_FIRST)
+#define PPR_BF_CHAIN3_MCS_SIZE (PPR_BF_CHAIN3_END - PPR_BF_CHAIN3_FIRST_MCS)
+#if (PPR_MAX_TX_CHAINS > 3)
+#define PPR_CHAIN4_FIRST OFFSETOF(pprpbw_t, p_1x4dsss)
+#define PPR_CHAIN4_FIRST_MCS OFFSETOF(pprpbw_t, p_1x4cdd_vhtss1)
+#define PPR_CHAIN4_END (OFFSETOF(pprpbw_t, p_4x4txbf_vhtss4) + \
+ sizeof(((pprpbw_t *)0)->p_4x4txbf_vhtss4))
+#define PPR_CHAIN4_SIZE (PPR_CHAIN4_END - PPR_CHAIN4_FIRST)
+#define PPR_CHAIN4_MCS_END (OFFSETOF(pprpbw_t, p_4x4vhtss4) + sizeof(((pprpbw_t *)0)->p_4x4vhtss4))
+#define PPR_CHAIN4_MCS_SIZE (PPR_CHAIN4_MCS_END - PPR_CHAIN4_FIRST_MCS)
+#define PPR_BF_CHAIN4_FIRST OFFSETOF(pprpbw_t, p_1x4txbf_ofdm)
+#define PPR_BF_CHAIN4_FIRST_MCS OFFSETOF(pprpbw_t, p_1x4txbf_vhtss1)
+#define PPR_BF_CHAIN4_END (OFFSETOF(pprpbw_t, p_4x4txbf_vhtss4) + \
+ sizeof(((pprpbw_t *)0)->p_4x4txbf_vhtss4))
+#define PPR_BF_CHAIN4_SIZE (PPR_BF_CHAIN4_END - PPR_BF_CHAIN4_FIRST)
+#define PPR_BF_CHAIN4_MCS_SIZE (PPR_BF_CHAIN4_END - PPR_BF_CHAIN4_FIRST_MCS)
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+#endif /* PPR_MAX_TX_CHAINS > 1 */
+
+/* Maximum supported bandwidth */
+#if defined(WL11AC_80P80)
+#define PPR_BW_MAX WL_TX_BW_8080
+#define MAX_PPR_SIZE (sizeof(ppr_bw_8080_t) + sizeof(wl_tx_bw_t))
+#elif defined(WL11AC_160)
+#define PPR_BW_MAX WL_TX_BW_160
+#define MAX_PPR_SIZE (sizeof(ppr_bw_160_t) + sizeof(wl_tx_bw_t))
+#else
+#define PPR_BW_MAX WL_TX_BW_80
+#define MAX_PPR_SIZE (sizeof(ppr_bw_80_t) + sizeof(wl_tx_bw_t))
+#endif
+
+/* If a bw is ULB */
+#define IS_ULB_BW(bw) ((bw == WL_TX_BW_2P5) || (bw == WL_TX_BW_5) || (bw == WL_TX_BW_10))
+
+/** Structure to contain ppr values for a 20MHz channel */
+typedef BWL_PRE_PACKED_STRUCT struct ppr_bw_20 {
+ /* 20MHz tx power limits */
+ pprpbw_t b20;
+} BWL_POST_PACKED_STRUCT ppr_bw_20_t;
+
+/** Structure to contain ppr values for a 40MHz channel */
+typedef BWL_PRE_PACKED_STRUCT struct ppr_bw_40 {
+ /* 40MHz tx power limits */
+ pprpbw_t b40;
+ /* 20in40MHz tx power limits */
+ pprpbw_t b20in40;
+} BWL_POST_PACKED_STRUCT ppr_bw_40_t;
+
+
+/** Structure to contain ppr values for an 80MHz channel */
+typedef BWL_PRE_PACKED_STRUCT struct ppr_bw_80 {
+ /* 80MHz tx power limits */
+ pprpbw_t b80;
+ /* 20in80MHz tx power limits */
+ pprpbw_t b20in80;
+ /* 40in80MHz tx power limits */
+ pprpbw_t b40in80;
+} BWL_POST_PACKED_STRUCT ppr_bw_80_t;
+
+/** Structure to contain ppr values for a 160MHz channel */
+typedef BWL_PRE_PACKED_STRUCT struct ppr_bw_160 {
+ /* 160MHz tx power limits */
+ pprpbw_t b160;
+ /* 20in160MHz tx power limits */
+ pprpbw_t b20in160;
+ /* 40in160MHz tx power limits */
+ pprpbw_t b40in160;
+ /* 80in160MHz tx power limits */
+ pprpbw_t b80in160;
+} BWL_POST_PACKED_STRUCT ppr_bw_160_t;
+
+
+/** Structure to contain ppr values for an 80+80MHz channel */
+typedef BWL_PRE_PACKED_STRUCT struct ppr_bw_8080 {
+ /* 80+80MHz chan1 tx power limits */
+ pprpbw_t b80ch1;
+ /* 80+80MHz chan2 tx power limits */
+ pprpbw_t b80ch2;
+ /* 80in80+80MHz (chan1 subband) tx power limits */
+ pprpbw_t b80in8080;
+ /* 20in80+80MHz (chan1 subband) tx power limits */
+ pprpbw_t b20in8080;
+ /* 40in80+80MHz (chan1 subband) tx power limits */
+ pprpbw_t b40in8080;
+} BWL_POST_PACKED_STRUCT ppr_bw_8080_t;
+
+/**
+ * This is the initial implementation of the structure we're hiding. It is sized to contain only
+ * the set of powers it requires, so the union is not necessarily the size of the largest member.
+ */
+BWL_PRE_PACKED_STRUCT struct ppr {
+ uint32 hdr;
+
+ BWL_PRE_PACKED_STRUCT union {
+ ppr_bw_20_t ch20;
+ ppr_bw_40_t ch40;
+ ppr_bw_80_t ch80;
+ ppr_bw_160_t ch160;
+ ppr_bw_8080_t ch8080;
+ } ppr_bw;
+} BWL_POST_PACKED_STRUCT;
+
+typedef BWL_PRE_PACKED_STRUCT struct ppr_dsss_tlv {
+ uint8 bw;
+ uint8 chains;
+ uint8 pwr[];
+} BWL_POST_PACKED_STRUCT ppr_dsss_tlv_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct ppr_ofdm_tlv {
+ uint8 bw;
+ uint8 chains;
+ uint8 mode;
+ uint8 pwr[];
+} BWL_POST_PACKED_STRUCT ppr_ofdm_tlv_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct ppr_mcs_tlv {
+ uint8 bw;
+ uint8 chains;
+ uint8 mode;
+ uint8 nss;
+ uint8 pwr[];
+} BWL_POST_PACKED_STRUCT ppr_mcs_tlv_t;
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+static wl_tx_bw_t ppr_get_cur_bw(const ppr_t* p)
+{
+ return ((p->hdr) & PPR_HDR_CUR_BW_MASK);
+}
+
+#ifdef BCMDRIVER
+static wl_tx_bw_t ppr_get_alloc_bw(uint32 hdr)
+{
+ return (((hdr) & PPR_HDR_ALLOC_BW_MASK) >> PPR_HDR_ALLOC_BW_SHIFT);
+}
+#endif
+
+#if (defined(BCMDBG_ASSERT) || defined(BCMASSERT_LOG)) && defined(BCMDRIVER)
+static bool ppr_is_valid_bw(wl_tx_bw_t bw)
+{
+ bool ret = FALSE;
+ if ((bw == WL_TX_BW_20) || (bw == WL_TX_BW_40) || (bw == WL_TX_BW_80) ||
+ (bw == WL_TX_BW_160) || (bw == WL_TX_BW_8080) || (bw == PPR_BW_MAX) ||
+ IS_ULB_BW(bw)) {
+ ret = TRUE;
+ }
+
+ return ret;
+}
+#endif
+
+/** Returns a flag of ppr conditions (chains, txbf etc.) */
+static uint32 ppr_get_flag(void)
+{
+ uint32 flag = 0;
+ flag |= PPR_MAX_TX_CHAINS & PPR_MAX_TX_CHAIN_MASK;
+ return flag;
+}
+
+static uint16 ppr_ser_size_per_band(uint32 flags)
+{
+ uint16 ret = PPR_CHAIN1_SIZE; /* at least 1 chain rates should be there */
+ uint8 chain = flags & PPR_MAX_TX_CHAIN_MASK;
+ BCM_REFERENCE(chain);
+#if (PPR_MAX_TX_CHAINS > 1)
+ if (chain > 1) {
+ ret += PPR_CHAIN2_SIZE;
+ }
+#if (PPR_MAX_TX_CHAINS > 2)
+ if (chain > 2) {
+ ret += PPR_CHAIN3_SIZE;
+ }
+#if (PPR_MAX_TX_CHAINS > 3)
+ if (chain > 3) {
+ ret += PPR_CHAIN4_SIZE;
+ }
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+#endif /* PPR_MAX_TX_CHAINS > 1 */
+ return ret;
+}
+
+/** Returns the number of bands for a specific bandwidth bw */
+static uint ppr_bands_by_bw(wl_tx_bw_t bw)
+{
+ switch (bw) {
+ case WL_TX_BW_2P5:
+ case WL_TX_BW_5:
+ case WL_TX_BW_10:
+ case WL_TX_BW_20:
+ return sizeof(ppr_bw_20_t)/sizeof(pprpbw_t);
+ case WL_TX_BW_40:
+ return sizeof(ppr_bw_40_t)/sizeof(pprpbw_t);
+ case WL_TX_BW_80:
+ return sizeof(ppr_bw_80_t)/sizeof(pprpbw_t);
+ case WL_TX_BW_160:
+ return sizeof(ppr_bw_160_t)/sizeof(pprpbw_t);
+ case WL_TX_BW_8080:
+ return sizeof(ppr_bw_8080_t)/sizeof(pprpbw_t);
+ default:
+ ASSERT(0);
+ return 0;
+ }
+}
+
+/** Return the required serialization size based on the flag field. */
+static uint ppr_ser_size_by_flag(uint32 flag, wl_tx_bw_t bw)
+{
+ return ppr_ser_size_per_band(flag) * ppr_bands_by_bw(bw);
+}
+
+#define COPY_PPR_TOBUF(x, y) do { bcopy(&pprbuf[x], *buf, y); \
+ *buf += y; ret += y; } while (0);
+
+
+/** Serialize ppr data of a bandwidth into the given buffer */
+static uint ppr_serialize_block(const uint8* pprbuf, uint8** buf, uint32 serflag)
+{
+ uint ret = 0;
+#if (PPR_MAX_TX_CHAINS > 1)
+ uint chain = serflag & PPR_MAX_TX_CHAIN_MASK; /* chain number in serialized block */
+#endif
+
+ COPY_PPR_TOBUF(PPR_CHAIN1_FIRST, PPR_CHAIN1_SIZE);
+#if (PPR_MAX_TX_CHAINS > 1)
+ if (chain > 1) {
+ COPY_PPR_TOBUF(PPR_CHAIN2_FIRST, PPR_CHAIN2_SIZE);
+ }
+#if (PPR_MAX_TX_CHAINS > 2)
+ if (chain > 2) {
+ COPY_PPR_TOBUF(PPR_CHAIN3_FIRST, PPR_CHAIN3_SIZE);
+ }
+#if (PPR_MAX_TX_CHAINS > 3)
+ if (chain > 3) {
+ COPY_PPR_TOBUF(PPR_CHAIN4_FIRST, PPR_CHAIN4_SIZE);
+ }
+#endif /* (PPR_MAX_TX_CHAINS > 2) */
+#endif /* (PPR_MAX_TX_CHAINS > 2) */
+#endif /* (PPR_MAX_TX_CHAINS > 1) */
+ return ret;
+}
+
+
+/** Serialize ppr data of each bandwidth into the given buffer, returns bytes copied */
+static uint ppr_serialize_data(const ppr_t *pprptr, uint8* buf, uint32 serflag)
+{
+ uint i;
+ uint bands;
+ const uint8* pprbuf;
+
+ uint ret = sizeof(ppr_deser_header_t);
+ ppr_deser_header_t* header = (ppr_deser_header_t*)buf;
+ ASSERT(pprptr && buf);
+ header->version = PPR_SERIALIZATION_VER;
+ header->bw = (uint8)ppr_get_cur_bw(pprptr);
+ header->flags = HTON32(ppr_get_flag());
+ header->per_band_size = HTON16(ppr_ser_size_per_band(serflag));
+
+ buf += sizeof(*header);
+
+ bands = ppr_bands_by_bw(header->bw);
+ pprbuf = (const uint8*)&pprptr->ppr_bw;
+ for (i = 0; i < bands; i++) {
+ ret += ppr_serialize_block(pprbuf, &buf, serflag);
+ pprbuf += sizeof(pprpbw_t); /* Jump to next band */
+ }
+
+ return ret;
+}
+
+
+/** Copy serialized ppr data of a bandwidth */
+static void
+ppr_copy_serdata(uint8* pobuf, const uint8** inbuf, uint32 flag, uint16 per_band_size)
+{
+ uint chain = flag & PPR_MAX_TX_CHAIN_MASK;
+ uint16 len = PPR_CHAIN1_SIZE;
+ BCM_REFERENCE(chain);
+ bcopy(*inbuf, pobuf, PPR_CHAIN1_SIZE);
+ *inbuf += PPR_CHAIN1_SIZE;
+#if (PPR_MAX_TX_CHAINS > 1)
+ if (chain > 1) {
+ bcopy(*inbuf, &pobuf[PPR_CHAIN2_FIRST], PPR_CHAIN2_SIZE);
+ *inbuf += PPR_CHAIN2_SIZE;
+ len += PPR_CHAIN2_SIZE;
+ }
+#if (PPR_MAX_TX_CHAINS > 2)
+ if (chain > 2) {
+ bcopy(*inbuf, &pobuf[PPR_CHAIN3_FIRST], PPR_CHAIN3_SIZE);
+ *inbuf += PPR_CHAIN3_SIZE;
+ len += PPR_CHAIN3_SIZE;
+ }
+#if (PPR_MAX_TX_CHAINS > 3)
+ if (chain > 3) {
+ bcopy(*inbuf, &pobuf[PPR_CHAIN4_FIRST], PPR_CHAIN4_SIZE);
+ *inbuf += PPR_CHAIN4_SIZE;
+ len += PPR_CHAIN4_SIZE;
+ }
+#endif /* (PPR_MAX_TX_CHAINS > 3) */
+#endif /* (PPR_MAX_TX_CHAINS > 2) */
+#endif /* (PPR_MAX_TX_CHAINS > 1) */
+ if (len < per_band_size) {
+ *inbuf += (per_band_size - len);
+ }
+}
+
+
+/* Deserialize data into a ppr_t structure */
+static void
+ppr_deser_cpy(ppr_t* pptr, const uint8* inbuf, uint32 flag, wl_tx_bw_t bw, uint16 per_band_size)
+{
+ uint i;
+ uint bands;
+ uint8* pobuf;
+
+ ppr_set_ch_bw(pptr, bw);
+ bands = ppr_bands_by_bw(bw);
+ pobuf = (uint8*)&pptr->ppr_bw;
+ for (i = 0; i < bands; i++) {
+ ppr_copy_serdata(pobuf, &inbuf, flag, per_band_size);
+ pobuf += sizeof(pprpbw_t); /* Jump to next band */
+ }
+}
+
+
+/** Get a pointer to the power values for a given channel bandwidth */
+static pprpbw_t* ppr_get_bw_powers_20(ppr_t* p, wl_tx_bw_t bw)
+{
+ pprpbw_t* pwrs = NULL;
+
+ if (bw == WL_TX_BW_20 || IS_ULB_BW(bw))
+ pwrs = &p->ppr_bw.ch20.b20;
+ /* else */
+ /* ASSERT(0); */
+ return pwrs;
+}
+
+
+/** Get a pointer to the power values for a given channel bandwidth */
+static pprpbw_t* ppr_get_bw_powers_40(ppr_t* p, wl_tx_bw_t bw)
+{
+ pprpbw_t* pwrs = NULL;
+
+ switch (bw) {
+ case WL_TX_BW_40:
+ pwrs = &p->ppr_bw.ch40.b40;
+ break;
+ case WL_TX_BW_2P5:
+ case WL_TX_BW_5:
+ case WL_TX_BW_10:
+ case WL_TX_BW_20:
+
+ case WL_TX_BW_20IN40:
+ pwrs = &p->ppr_bw.ch40.b20in40;
+ break;
+ default:
+ /* ASSERT(0); */
+ break;
+ }
+ return pwrs;
+}
+
+
+/** Get a pointer to the power values for a given channel bandwidth */
+static pprpbw_t* ppr_get_bw_powers_80(ppr_t* p, wl_tx_bw_t bw)
+{
+ pprpbw_t* pwrs = NULL;
+
+ switch (bw) {
+ case WL_TX_BW_80:
+ pwrs = &p->ppr_bw.ch80.b80;
+ break;
+ case WL_TX_BW_2P5:
+ case WL_TX_BW_5:
+ case WL_TX_BW_10:
+ case WL_TX_BW_20:
+ case WL_TX_BW_20IN40:
+ case WL_TX_BW_20IN80:
+ pwrs = &p->ppr_bw.ch80.b20in80;
+ break;
+ case WL_TX_BW_40:
+ case WL_TX_BW_40IN80:
+ pwrs = &p->ppr_bw.ch80.b40in80;
+ break;
+ default:
+ /* ASSERT(0); */
+ break;
+ }
+ return pwrs;
+}
+
+/** Get a pointer to the power values for a given channel bandwidth */
+static pprpbw_t* ppr_get_bw_powers_160(ppr_t* p, wl_tx_bw_t bw)
+{
+ pprpbw_t* pwrs = NULL;
+
+ switch (bw) {
+ case WL_TX_BW_160:
+ case WL_TX_BW_8080: // stf function doesn't care much if we're 160 or 80p80
+ pwrs = &p->ppr_bw.ch160.b160;
+ break;
+ case WL_TX_BW_2P5:
+ case WL_TX_BW_5:
+ case WL_TX_BW_10:
+ case WL_TX_BW_20:
+ case WL_TX_BW_20IN40:
+ case WL_TX_BW_20IN80:
+ case WL_TX_BW_20IN160:
+ pwrs = &p->ppr_bw.ch160.b20in160;
+ break;
+ case WL_TX_BW_40:
+ case WL_TX_BW_40IN80:
+ case WL_TX_BW_40IN160:
+ pwrs = &p->ppr_bw.ch160.b40in160;
+ break;
+ case WL_TX_BW_80:
+ case WL_TX_BW_80IN160:
+ pwrs = &p->ppr_bw.ch160.b80in160;
+ break;
+ default:
+ /* ASSERT(0); */
+ break;
+ }
+ return pwrs;
+}
+
+
+/** Get a pointer to the power values for a given channel bandwidth */
+static pprpbw_t* ppr_get_bw_powers_8080(ppr_t* p, wl_tx_bw_t bw)
+{
+ pprpbw_t* pwrs = NULL;
+
+ switch (bw) {
+ case WL_TX_BW_160: // stf function doesn't care much if we're 160 or 80p80
+ case WL_TX_BW_8080:
+ pwrs = &p->ppr_bw.ch8080.b80ch1;
+ break;
+ case WL_TX_BW_8080CHAN2:
+ pwrs = &p->ppr_bw.ch8080.b80ch2;
+ break;
+ case WL_TX_BW_2P5:
+ case WL_TX_BW_5:
+ case WL_TX_BW_10:
+ case WL_TX_BW_20:
+ case WL_TX_BW_20IN40:
+ case WL_TX_BW_20IN80:
+ case WL_TX_BW_20IN160:
+ case WL_TX_BW_20IN8080:
+ pwrs = &p->ppr_bw.ch8080.b20in8080;
+ break;
+ case WL_TX_BW_40:
+ case WL_TX_BW_40IN80:
+ case WL_TX_BW_40IN160:
+ case WL_TX_BW_40IN8080:
+ pwrs = &p->ppr_bw.ch8080.b40in8080;
+ break;
+ case WL_TX_BW_80:
+ case WL_TX_BW_80IN160:
+ case WL_TX_BW_80IN8080:
+ pwrs = &p->ppr_bw.ch8080.b80in8080;
+ break;
+ default:
+ /* ASSERT(0); */
+ break;
+ }
+ return pwrs;
+}
+
+typedef pprpbw_t* (*wlc_ppr_get_bw_pwrs_fn_t)(ppr_t* p, wl_tx_bw_t bw);
+
+typedef struct {
+ wl_tx_bw_t ch_bw; /* Bandwidth of the channel for which powers are stored */
+ /* Function to retrieve the powers for the requested bandwidth */
+ wlc_ppr_get_bw_pwrs_fn_t fn;
+} wlc_ppr_get_bw_pwrs_pair_t;
+
+
+static const wlc_ppr_get_bw_pwrs_pair_t ppr_get_bw_pwrs_fn[] = {
+ {WL_TX_BW_20, ppr_get_bw_powers_20},
+ {WL_TX_BW_40, ppr_get_bw_powers_40},
+ {WL_TX_BW_80, ppr_get_bw_powers_80},
+ {WL_TX_BW_160, ppr_get_bw_powers_160},
+ {WL_TX_BW_8080, ppr_get_bw_powers_8080},
+ {WL_TX_BW_2P5, ppr_get_bw_powers_20},
+ {WL_TX_BW_5, ppr_get_bw_powers_20},
+ {WL_TX_BW_10, ppr_get_bw_powers_20},
+};
+
+
+/** Get a pointer to the power values for a given channel bandwidth */
+static pprpbw_t* ppr_get_bw_powers(ppr_t* p, wl_tx_bw_t bw)
+{
+ uint32 i;
+
+ if (p == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < (int)ARRAYSIZE(ppr_get_bw_pwrs_fn); i++) {
+ if (ppr_get_bw_pwrs_fn[i].ch_bw == ppr_get_cur_bw(p))
+ return ppr_get_bw_pwrs_fn[i].fn(p, bw);
+ }
+
+ ASSERT(0);
+ return NULL;
+}
+
+
+/**
+ * Rate group power finder functions: ppr_get_xxx_group()
+ * To preserve the opacity of the PPR struct, even inside the API we try to limit knowledge of
+ * its details. Almost all API functions work on the powers for individual rate groups, rather than
+ * directly accessing the struct. Once the section of the structure corresponding to the bandwidth
+ * has been identified using ppr_get_bw_powers(), the ppr_get_xxx_group() functions use knowledge
+ * of the number of spatial streams, the number of tx chains, and the expansion mode to return a
+ * pointer to the required group of power values.
+ */
+
+/** Get a pointer to the power values for the given dsss rate group for a given channel bandwidth */
+static int8* ppr_get_dsss_group(pprpbw_t* bw_pwrs, wl_tx_chains_t tx_chains)
+{
+ int8* group_pwrs = NULL;
+
+ switch (tx_chains) {
+#if (PPR_MAX_TX_CHAINS > 1)
+#if (PPR_MAX_TX_CHAINS > 2)
+#if (PPR_MAX_TX_CHAINS > 3)
+ case WL_TX_CHAINS_4:
+ group_pwrs = bw_pwrs->p_1x4dsss;
+ break;
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+ case WL_TX_CHAINS_3:
+ group_pwrs = bw_pwrs->p_1x3dsss;
+ break;
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+ case WL_TX_CHAINS_2:
+ group_pwrs = bw_pwrs->p_1x2dsss;
+ break;
+#endif /* PPR_MAX_TX_CHAINS > 1 */
+ case WL_TX_CHAINS_1:
+ group_pwrs = bw_pwrs->p_1x1dsss;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ return group_pwrs;
+}
+
+
+/** Get a pointer to the power values for the given ofdm rate group for a given channel bandwidth */
+static int8* ppr_get_ofdm_group(pprpbw_t* bw_pwrs, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains)
+{
+ int8* group_pwrs = NULL;
+ BCM_REFERENCE(mode);
+ switch (tx_chains) {
+#if (PPR_MAX_TX_CHAINS > 1)
+#if (PPR_MAX_TX_CHAINS > 2)
+#if (PPR_MAX_TX_CHAINS > 3)
+ case WL_TX_CHAINS_4:
+ if (mode == WL_TX_MODE_TXBF) {
+ group_pwrs = bw_pwrs->p_1x4txbf_ofdm;
+ } else {
+ group_pwrs = bw_pwrs->p_1x4cdd_ofdm;
+ }
+ break;
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+ case WL_TX_CHAINS_3:
+ if (mode == WL_TX_MODE_TXBF)
+ group_pwrs = bw_pwrs->p_1x3txbf_ofdm;
+ else
+ group_pwrs = bw_pwrs->p_1x3cdd_ofdm;
+ break;
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+ case WL_TX_CHAINS_2:
+ if (mode == WL_TX_MODE_TXBF)
+ group_pwrs = bw_pwrs->p_1x2txbf_ofdm;
+ else
+ group_pwrs = bw_pwrs->p_1x2cdd_ofdm;
+ break;
+#endif /* PPR_MAX_TX_CHAINS > 1 */
+ case WL_TX_CHAINS_1:
+ group_pwrs = bw_pwrs->p_1x1ofdm;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ return group_pwrs;
+}
+
+
+/**
+ * Tables to provide access to HT/VHT rate group powers. This avoids an ugly nested switch with
+ * messy conditional compilation.
+ *
+ * Access to a given table entry is via table[chains - Nss][mode], except for the Nss3 table, which
+ * only has one row, so it can be indexed directly by table[mode].
+ *
+ * Separate tables are provided for each of Nss1, Nss2 and Nss3 because they are all different
+ * sizes. A combined table would be very sparse, and this arrangement also simplifies the
+ * conditional compilation.
+ *
+ * Each row represents a given number of chains, so there's no need for a zero row. Because
+ * chains >= Nss is always true, there is no one-chain row for Nss2 and there are no one- or
+ * two-chain rows for Nss3. With the tables correctly sized, we can index the rows
+ * using [chains - Nss].
+ *
+ * Then, inside each row, we index by mode:
+ * WL_TX_MODE_NONE, WL_TX_MODE_STBC, WL_TX_MODE_CDD, WL_TX_MODE_TXBF.
+ */
+
+#define OFFSNONE (-1)
+
+static const int mcs_groups_nss1[PPR_MAX_TX_CHAINS][WL_NUM_TX_MODES] = {
+ /* WL_TX_MODE_NONE
+ WL_TX_MODE_STBC
+ WL_TX_MODE_CDD
+ WL_TX_MODE_TXBF
+ */
+ /* 1 chain */
+ {OFFSETOF(pprpbw_t, p_1x1vhtss1),
+ OFFSNONE,
+ OFFSNONE,
+ OFFSNONE},
+#if (PPR_MAX_TX_CHAINS > 1)
+ /* 2 chain */
+ {OFFSNONE,
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_1x2cdd_vhtss1),
+ OFFSNONE},
+#if (PPR_MAX_TX_CHAINS > 2)
+ /* 3 chain */
+ {OFFSNONE,
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_1x3cdd_vhtss1),
+ OFFSNONE},
+#if (PPR_MAX_TX_CHAINS > 3)
+ /* 4 chain */
+ {OFFSNONE,
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_1x4cdd_vhtss1),
+ OFFSNONE}
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+#endif /* PPR_MAX_TX_CHAINS > 1 */
+};
+
+/** mcs group with TXBF data */
+static const int mcs_groups_nss1_txbf[PPR_MAX_TX_CHAINS][WL_NUM_TX_MODES] = {
+ /* WL_TX_MODE_NONE
+ WL_TX_MODE_STBC
+ WL_TX_MODE_CDD
+ WL_TX_MODE_TXBF
+ */
+ /* 1 chain */
+ {OFFSETOF(pprpbw_t, p_1x1vhtss1),
+ OFFSNONE,
+ OFFSNONE,
+ OFFSNONE},
+#if (PPR_MAX_TX_CHAINS > 1)
+ /* 2 chain */
+ {OFFSNONE,
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_1x2cdd_vhtss1),
+ OFFSETOF(pprpbw_t, p_1x2txbf_vhtss1)},
+#if (PPR_MAX_TX_CHAINS > 2)
+ /* 3 chain */
+ {OFFSNONE,
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_1x3cdd_vhtss1),
+ OFFSETOF(pprpbw_t, p_1x3txbf_vhtss1)},
+#if (PPR_MAX_TX_CHAINS > 3)
+ /* 4 chain */
+ {OFFSNONE,
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_1x4cdd_vhtss1),
+ OFFSETOF(pprpbw_t, p_1x4txbf_vhtss1)}
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+#endif /* PPR_MAX_TX_CHAINS > 1 */
+};
+
+#if (PPR_MAX_TX_CHAINS > 1)
+static const int mcs_groups_nss2[PPR_MAX_TX_CHAINS - 1][WL_NUM_TX_MODES] = {
+ /* 2 chain */
+ {OFFSETOF(pprpbw_t, p_2x2vhtss2),
+ OFFSETOF(pprpbw_t, p_2x2stbc_vhtss1),
+ OFFSNONE,
+ OFFSNONE},
+#if (PPR_MAX_TX_CHAINS > 2)
+ /* 3 chain */
+ {OFFSETOF(pprpbw_t, p_2x3vhtss2),
+ OFFSETOF(pprpbw_t, p_2x3stbc_vhtss1),
+ OFFSNONE,
+ OFFSNONE},
+#if (PPR_MAX_TX_CHAINS > 3)
+ /* 4 chain */
+ {OFFSETOF(pprpbw_t, p_2x4vhtss2),
+ OFFSETOF(pprpbw_t, p_2x4stbc_vhtss1),
+ OFFSNONE,
+ OFFSNONE}
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+};
+
+/** mcs group with TXBF data */
+static const int mcs_groups_nss2_txbf[PPR_MAX_TX_CHAINS - 1][WL_NUM_TX_MODES] = {
+ /* 2 chain */
+ {OFFSETOF(pprpbw_t, p_2x2vhtss2),
+ OFFSETOF(pprpbw_t, p_2x2stbc_vhtss1),
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_2x2txbf_vhtss2)},
+#if (PPR_MAX_TX_CHAINS > 2)
+ /* 3 chain */
+ {OFFSETOF(pprpbw_t, p_2x3vhtss2),
+ OFFSETOF(pprpbw_t, p_2x3stbc_vhtss1),
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_2x3txbf_vhtss2)},
+#if (PPR_MAX_TX_CHAINS > 3)
+ /* 4 chain */
+ {OFFSETOF(pprpbw_t, p_2x4vhtss2),
+ OFFSETOF(pprpbw_t, p_2x4stbc_vhtss1),
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_2x4txbf_vhtss2)}
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+};
+#if (PPR_MAX_TX_CHAINS > 2)
+static const int mcs_groups_nss3[PPR_MAX_TX_CHAINS - 2][WL_NUM_TX_MODES] = {
+/* 3 chains */
+ {OFFSETOF(pprpbw_t, p_3x3vhtss3),
+ OFFSNONE,
+ OFFSNONE,
+ OFFSNONE},
+#if (PPR_MAX_TX_CHAINS > 3)
+ {OFFSETOF(pprpbw_t, p_3x4vhtss3),
+ OFFSNONE,
+ OFFSNONE,
+ OFFSNONE}
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+};
+
+/** mcs group with TXBF data */
+static const int mcs_groups_nss3_txbf[PPR_MAX_TX_CHAINS - 2][WL_NUM_TX_MODES] = {
+/* 3 chains */
+ {OFFSETOF(pprpbw_t, p_3x3vhtss3),
+ OFFSNONE,
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_3x3txbf_vhtss3)},
+#if (PPR_MAX_TX_CHAINS > 3)
+ {OFFSETOF(pprpbw_t, p_3x4vhtss3),
+ OFFSNONE,
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_3x4txbf_vhtss3)}
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+};
+#if (PPR_MAX_TX_CHAINS > 3)
+static const int mcs_groups_nss4[WL_NUM_TX_MODES] = {
+/* 4 chains only */
+ OFFSETOF(pprpbw_t, p_4x4vhtss4),
+ OFFSNONE,
+ OFFSNONE,
+ OFFSNONE,
+};
+/** mcs group with TXBF data */
+static const int mcs_groups_nss4_txbf[WL_NUM_TX_MODES] = {
+/* 4 chains only */
+ OFFSETOF(pprpbw_t, p_4x4vhtss4),
+ OFFSNONE,
+ OFFSNONE,
+ OFFSETOF(pprpbw_t, p_4x4txbf_vhtss4)
+};
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+#endif /* PPR_MAX_TX_CHAINS > 1 */
+
+/** Get a pointer to the power values for the given rate group for a given channel bandwidth */
+static int8* ppr_get_mcs_group(pprpbw_t* bw_pwrs, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains)
+{
+ int8* group_pwrs = NULL;
+ int offset;
+
+ switch (Nss) {
+#if (PPR_MAX_TX_CHAINS > 1)
+#if (PPR_MAX_TX_CHAINS > 2)
+#if (PPR_MAX_TX_CHAINS > 3)
+ case WL_TX_NSS_4:
+ if (tx_chains == WL_TX_CHAINS_4) {
+ if (mode == WL_TX_MODE_TXBF && PPR_TXBF_ENAB()) {
+ offset = mcs_groups_nss4_txbf[mode];
+ } else {
+ offset = mcs_groups_nss4[mode];
+ }
+ if (offset != OFFSNONE) {
+ group_pwrs = (int8*)bw_pwrs + offset;
+ }
+ }
+ else
+ ASSERT(0);
+ break;
+#endif /* PPR_MAX_TX_CHAINS > 3 */
+ case WL_TX_NSS_3:
+ if ((tx_chains >= WL_TX_CHAINS_3) && (tx_chains <= PPR_MAX_TX_CHAINS)) {
+ if (PPR_TXBF_ENAB()) {
+ offset = mcs_groups_nss3_txbf[tx_chains - Nss][mode];
+ } else {
+ offset = mcs_groups_nss3[tx_chains - Nss][mode];
+ }
+ if (offset != OFFSNONE) {
+ group_pwrs = (int8*)bw_pwrs + offset;
+ }
+ }
+ else
+ ASSERT(0);
+ break;
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+ case WL_TX_NSS_2:
+ if ((tx_chains >= WL_TX_CHAINS_2) && (tx_chains <= PPR_MAX_TX_CHAINS)) {
+ if (PPR_TXBF_ENAB()) {
+ offset = mcs_groups_nss2_txbf[tx_chains - Nss][mode];
+ } else {
+ offset = mcs_groups_nss2[tx_chains - Nss][mode];
+ }
+ if (offset != OFFSNONE) {
+ group_pwrs = (int8*)bw_pwrs + offset;
+ }
+ }
+ else
+ ASSERT(0);
+ break;
+#endif /* PPR_MAX_TX_CHAINS > 1 */
+ case WL_TX_NSS_1:
+ if (tx_chains <= PPR_MAX_TX_CHAINS) {
+ if (PPR_TXBF_ENAB()) {
+ offset = mcs_groups_nss1_txbf[tx_chains - Nss][mode];
+ } else {
+ offset = mcs_groups_nss1[tx_chains - Nss][mode];
+ }
+ if (offset != OFFSNONE) {
+ group_pwrs = (int8*)bw_pwrs + offset;
+ }
+ }
+ else
+ ASSERT(0);
+ break;
+ default:
+#ifdef BCMQT
+ printf("%s: %d: WL_TX_CHAINS_4 not supported yet, ignoring for now!!\n",
+ __FUNCTION__, __LINE__);
+#else
+ ASSERT(0);
+#endif
+ break;
+ }
+ return group_pwrs;
+}
+
+/** Size routine for user alloc/dealloc */
+static uint32 ppr_pwrs_size(uint32 hdr)
+{
+ uint32 size;
+
+ switch ((hdr & PPR_HDR_CUR_BW_MASK)) {
+ case WL_TX_BW_2P5:
+ case WL_TX_BW_5:
+ case WL_TX_BW_10:
+ case WL_TX_BW_20:
+ size = sizeof(ppr_bw_20_t);
+ break;
+ case WL_TX_BW_40:
+ size = sizeof(ppr_bw_40_t);
+ break;
+ case WL_TX_BW_80:
+ size = sizeof(ppr_bw_80_t);
+ break;
+#ifdef WL11AC_160
+ case WL_TX_BW_160:
+ size = sizeof(ppr_bw_160_t);
+ break;
+#endif
+#ifdef WL11AC_80P80
+ case WL_TX_BW_8080:
+ size = sizeof(ppr_bw_8080_t);
+ break;
+#endif
+ default:
+ ASSERT(0);
+ size = 0;
+ break;
+ }
+ return size;
+}
+
+
+/** Initialization routine */
+void ppr_init(ppr_t* pprptr, wl_tx_bw_t bw)
+{
+ memset(pprptr, (int8)WL_RATE_DISABLED, ppr_size(bw));
+ pprptr->hdr = 0;
+ pprptr->hdr |= (bw & PPR_HDR_CUR_BW_MASK);
+ pprptr->hdr |= ((bw << PPR_HDR_ALLOC_BW_SHIFT) & PPR_HDR_ALLOC_BW_MASK);
+}
+
+
+/** Reinitialization routine for opaque PPR struct */
+void ppr_clear(ppr_t* pprptr)
+{
+ memset((uchar*)&pprptr->ppr_bw, (int8)WL_RATE_DISABLED,
+ ppr_pwrs_size(pprptr->hdr));
+}
+
+
+/** Size routine for user alloc/dealloc */
+uint32 ppr_size(wl_tx_bw_t bw)
+{
+ uint32 ret = ppr_pwrs_size(bw) + sizeof(wl_tx_bw_t);
+ ASSERT(ret <= MAX_PPR_SIZE);
+ return ret;
+}
+
+
+/** Size routine for user serialization alloc */
+uint32 ppr_ser_size(const ppr_t* pprptr)
+{
+ return ppr_pwrs_size(pprptr->hdr) + SER_HDR_LEN; /* struct size plus headers */
+}
+
+
+/** Size routine for user serialization alloc */
+uint32 ppr_ser_size_by_bw(wl_tx_bw_t bw)
+{
+ return ppr_pwrs_size(bw) + SER_HDR_LEN;
+}
+
+
+/** Constructor routine for opaque PPR struct */
+ppr_t* ppr_create(osl_t *osh, wl_tx_bw_t bw)
+{
+ ppr_t* pprptr;
+
+ ASSERT(ppr_is_valid_bw(bw));
+#ifndef BCMDRIVER
+ BCM_REFERENCE(osh);
+ if ((pprptr = (ppr_t*)malloc((uint)ppr_size(bw))) != NULL) {
+#else
+ if ((pprptr = (ppr_t*)MALLOC_NOPERSIST(osh, (uint)ppr_size(bw))) != NULL) {
+#endif
+ ppr_init(pprptr, bw);
+ } else {
+ PPR_ERROR(("%s: MALLOC(%d) failed\n", __FUNCTION__, (int)ppr_size(bw)));
+ }
+ return pprptr;
+}
+
+
+/* Constructor routine for opaque PPR struct on pre-alloc memory */
+ppr_t* ppr_create_prealloc(wl_tx_bw_t bw, int8 *buf, uint len)
+{
+ ppr_t* pprptr = NULL;
+ ASSERT(ppr_is_valid_bw(bw));
+
+ if (ppr_size(bw) <= len) {
+ pprptr = (ppr_t*) buf;
+ ppr_init(pprptr, bw);
+ pprptr->hdr |= PPR_HDR_FLAG_PREALLOC;
+ } else {
+ PPR_ERROR(("%s: Insufficient mem(%d), need %d\n", __FUNCTION__, len,
+ (int)ppr_size(bw)));
+ ASSERT(0);
+ }
+ return pprptr;
+}
+
+/**
+ * Init flags in the memory block for serialization, the serializer will check
+ * the flag to decide which ppr to be copied
+ */
+int ppr_init_ser_mem_by_bw(uint8* pbuf, wl_tx_bw_t bw, uint32 len)
+{
+ ppr_ser_mem_flag_t *pmflag;
+
+ if (pbuf == NULL || ppr_ser_size_by_bw(bw) > len)
+ return BCME_BADARG;
+
+ pmflag = (ppr_ser_mem_flag_t *)pbuf;
+ pmflag->magic_word = HTON32(PPR_SER_MEM_WORD);
+ pmflag->flag = HTON32(ppr_get_flag());
+
+ /* init the memory */
+ memset(pbuf + sizeof(*pmflag), (uint8)WL_RATE_DISABLED, len-sizeof(*pmflag));
+ return BCME_OK;
+}
+
+
+int ppr_init_ser_mem(uint8* pbuf, ppr_t * ppr, uint32 len)
+{
+ return ppr_init_ser_mem_by_bw(pbuf, ppr->hdr, len);
+}
+
+/** Destructor routine for opaque PPR struct */
+void ppr_delete(osl_t *osh, ppr_t* pprptr)
+{
+ ASSERT(ppr_is_valid_bw(ppr_get_cur_bw(pprptr)));
+
+ if (pprptr->hdr & PPR_HDR_FLAG_PREALLOC)
+ return;
+
+#ifndef BCMDRIVER
+ BCM_REFERENCE(osh);
+ free(pprptr);
+#else
+ MFREE(osh, pprptr, (uint)ppr_size(ppr_get_alloc_bw(pprptr->hdr)));
+#endif
+}
+
+/* Update the bw for the given opaque PPR struct
+ * This function is used when an opaque PPR struct has been allocated
+ * with enough space for the given bandwidth.
+ * USE WITH CAUTION
+ */
+void ppr_set_ch_bw(ppr_t* pprptr, wl_tx_bw_t bw)
+{
+ ASSERT(ppr_size(ppr_get_alloc_bw(pprptr->hdr)) >= ppr_size(bw));
+ pprptr->hdr &= ~PPR_HDR_CUR_BW_MASK;
+ pprptr->hdr |= (bw & PPR_HDR_CUR_BW_MASK);
+}
+
+/** Type routine for inferring opaque structure size */
+wl_tx_bw_t ppr_get_ch_bw(const ppr_t* pprptr)
+{
+ return ppr_get_cur_bw(pprptr);
+}
+
+/** Type routine to get ppr supported maximum bw */
+wl_tx_bw_t ppr_get_max_bw(void)
+{
+ return PPR_BW_MAX;
+}
+
+
+/** Get the dsss values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_get_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains,
+ ppr_dsss_rateset_t* dsss)
+{
+ pprpbw_t* bw_pwrs;
+ const int8* powers;
+ int cnt = 0;
+
+ ASSERT(pprptr);
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ powers = ppr_get_dsss_group(bw_pwrs, tx_chains);
+ if (powers != NULL) {
+ bcopy(powers, dsss->pwr, sizeof(*dsss));
+ cnt = sizeof(*dsss);
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d TX_Chain:%d rateset:%p\n",
+ __FUNCTION__, pprptr, bw, tx_chains, dsss));
+ memset(dsss->pwr, (int8)WL_RATE_DISABLED, sizeof(*dsss));
+ }
+ return cnt;
+}
+
+
+/** Get the ofdm values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_get_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains,
+ ppr_ofdm_rateset_t* ofdm)
+{
+ pprpbw_t* bw_pwrs;
+ const int8* powers;
+ int cnt = 0;
+
+ ASSERT(pprptr);
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ powers = ppr_get_ofdm_group(bw_pwrs, mode, tx_chains);
+ if (powers != NULL) {
+ bcopy(powers, ofdm->pwr, sizeof(*ofdm));
+ cnt = sizeof(*ofdm);
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d mode:%d TX_Chain:%d rateset:%p\n",
+ __FUNCTION__, pprptr, bw, mode, tx_chains, ofdm));
+ memset(ofdm->pwr, (int8)WL_RATE_DISABLED, sizeof(*ofdm));
+ }
+ return cnt;
+}
+
+
+/**
+ * Get the HT MCS values for the group specified by Nss, with the given bw and tx chains. Function
+ * is not called by ACPHY code, but even in case of ACPHY, function is called by wlc_channel.c.
+ */
+int ppr_get_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, ppr_ht_mcs_rateset_t* mcs)
+{
+ pprpbw_t* bw_pwrs;
+ const int8* powers;
+ int cnt = 0;
+
+ ASSERT(pprptr);
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ powers = ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains);
+ if (powers != NULL) {
+ bcopy(powers, mcs->pwr, sizeof(*mcs));
+ cnt = sizeof(*mcs);
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d Nss:%d mode:%d TX_Chain:%d rateset:%p\n",
+ __FUNCTION__, pprptr, bw, Nss, mode, tx_chains, mcs));
+ memset(mcs->pwr, (int8)WL_RATE_DISABLED, sizeof(*mcs));
+ }
+
+ return cnt;
+}
+
+
+/** Get the VHT MCS values for the group specified by Nss, with the given bw and tx chains */
+int ppr_get_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, ppr_vht_mcs_rateset_t* mcs)
+{
+ pprpbw_t* bw_pwrs;
+ const int8* powers;
+ int cnt = 0;
+
+ ASSERT(pprptr);
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ powers = ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains);
+ if (powers != NULL) {
+ bcopy(powers, mcs->pwr, sizeof(*mcs));
+ cnt = sizeof(*mcs);
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d Nss:%d mode:%d TX_Chain:%d rateset:%p\n",
+ __FUNCTION__, pprptr, bw, Nss, mode, tx_chains, mcs));
+ memset(mcs->pwr, (int8)WL_RATE_DISABLED, sizeof(*mcs));
+ }
+ return cnt;
+}
+
+
+#define TXPPR_TXPWR_MAX 0x7f /* WLC_TXPWR_MAX */
+
+/**
+ * Get the minimum power for a VHT MCS rate specified by Nss, with the given bw and tx chains.
+ * Disabled rates are ignored
+ */
+int ppr_get_vht_mcs_min(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, int8* mcs_min)
+{
+ pprpbw_t* bw_pwrs;
+ const int8* powers;
+ int result = BCME_ERROR;
+ uint i = 0;
+
+ *mcs_min = TXPPR_TXPWR_MAX;
+
+ ASSERT(pprptr);
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ powers = ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains);
+ if (powers != NULL) {
+ for (i = 0; i < sizeof(ppr_vht_mcs_rateset_t); i++) {
+ /* ignore disabled rates! */
+ if (powers[i] != WL_RATE_DISABLED)
+ *mcs_min = MIN(*mcs_min, powers[i]);
+ }
+ result = BCME_OK;
+ }
+ }
+ return result;
+}
+
+
+/* Routines to set target powers per rate in a group */
+
+/** Set the dsss values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_set_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains,
+ const ppr_dsss_rateset_t* dsss)
+{
+ pprpbw_t* bw_pwrs;
+ int8* powers;
+ int cnt = 0;
+
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ powers = (int8*)ppr_get_dsss_group(bw_pwrs, tx_chains);
+ if (powers != NULL) {
+ bcopy(dsss->pwr, powers, sizeof(*dsss));
+ cnt = sizeof(*dsss);
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d TX_Chain:%d rateset:%p\n",
+ __FUNCTION__, pprptr, bw, tx_chains, dsss));
+ }
+ return cnt;
+}
+
+
+/** Set the ofdm values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_set_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains,
+ const ppr_ofdm_rateset_t* ofdm)
+{
+ pprpbw_t* bw_pwrs;
+ int8* powers;
+ int cnt = 0;
+
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ powers = (int8*)ppr_get_ofdm_group(bw_pwrs, mode, tx_chains);
+ if (powers != NULL) {
+ bcopy(ofdm->pwr, powers, sizeof(*ofdm));
+ cnt = sizeof(*ofdm);
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d mode:%d TX_Chain:%d rateset:%p\n",
+ __FUNCTION__, pprptr, bw, mode, tx_chains, ofdm));
+ }
+ return cnt;
+}
+
+/**
+ * Set the HT MCS values for the group specified by Nss, with the given bw and tx chains. Function
+ * is not called by ACPHY code, but even in case of ACPHY, function is called by wlc_channel.c.
+ */
+int ppr_set_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, const ppr_ht_mcs_rateset_t* mcs)
+{
+ pprpbw_t* bw_pwrs;
+ int8* powers;
+ int cnt = 0;
+
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ powers = (int8*)ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains);
+ if (powers != NULL) {
+ bcopy(mcs->pwr, powers, sizeof(*mcs));
+ cnt = sizeof(*mcs);
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d Nss:%d mode:%d TX_Chain:%d rateset:%p\n",
+ __FUNCTION__, pprptr, bw, Nss, mode, tx_chains, mcs));
+ }
+ return cnt;
+}
+
+
+/** Set the VHT MCS values for the group specified by Nss, with the given bw and tx chains */
+int ppr_set_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, const ppr_vht_mcs_rateset_t* mcs)
+{
+ pprpbw_t* bw_pwrs;
+ int8* powers;
+ int cnt = 0;
+
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ powers = (int8*)ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains);
+ if (powers != NULL) {
+ bcopy(mcs->pwr, powers, sizeof(*mcs));
+ cnt = sizeof(*mcs);
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d Nss:%d mode:%d TX_Chain:%d rateset:%p\n",
+ __FUNCTION__, pprptr, bw, Nss, mode, tx_chains, mcs));
+ }
+ return cnt;
+}
+
+
+/* Routines to set rate groups to a single target value */
+
+/** Set the dsss values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_set_same_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains, const int8 power)
+{
+ pprpbw_t* bw_pwrs;
+ int8* dest_group;
+ int cnt = 0;
+ int i;
+
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ dest_group = (int8*)ppr_get_dsss_group(bw_pwrs, tx_chains);
+ if (dest_group != NULL) {
+ cnt = sizeof(ppr_dsss_rateset_t);
+ for (i = 0; i < cnt; i++)
+ *dest_group++ = power;
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d TX_Chain:%d power:%d\n",
+ __FUNCTION__, pprptr, bw, tx_chains, power));
+ }
+ return cnt;
+}
+
+
+/** Set the ofdm values for the given number of tx_chains and 20, 20in40, etc. */
+int ppr_set_same_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains,
+ const int8 power)
+{
+ pprpbw_t* bw_pwrs;
+ int8* dest_group;
+ int cnt = 0;
+ int i;
+
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ dest_group = (int8*)ppr_get_ofdm_group(bw_pwrs, mode, tx_chains);
+ if (dest_group != NULL) {
+ cnt = sizeof(ppr_ofdm_rateset_t);
+ for (i = 0; i < cnt; i++)
+ *dest_group++ = power;
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d mode:%d TX_Chain:%d power:%d\n",
+ __FUNCTION__, pprptr, bw, mode, tx_chains, power));
+ }
+ return cnt;
+}
+
+
+/** Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */
+int ppr_set_same_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, const int8 power)
+{
+ pprpbw_t* bw_pwrs;
+ int8* dest_group;
+ int cnt = 0;
+ int i;
+
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ dest_group = (int8*)ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains);
+ if (dest_group != NULL) {
+ cnt = sizeof(ppr_ht_mcs_rateset_t);
+ for (i = 0; i < cnt; i++)
+ *dest_group++ = power;
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d Nss:%d mode:%d TX_Chain:%d power:%d\n",
+ __FUNCTION__, pprptr, bw, Nss, mode, tx_chains, power));
+ }
+ return cnt;
+}
+
+
+/** Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */
+int ppr_set_same_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains, const int8 power)
+{
+ pprpbw_t* bw_pwrs;
+ int8* dest_group;
+ int cnt = 0;
+ int i;
+
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ dest_group = (int8*)ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains);
+ if (dest_group != NULL) {
+ cnt = sizeof(ppr_vht_mcs_rateset_t);
+ for (i = 0; i < cnt; i++)
+ *dest_group++ = power;
+ }
+ }
+ if (cnt == 0) {
+ PPR_ERROR(("%s: Failed ppr_t:%p BW:%d Nss:%d mode:%d TX_Chain:%d power:%d\n",
+ __FUNCTION__, pprptr, bw, Nss, mode, tx_chains, power));
+ }
+ return cnt;
+}
+
+
+/* Helper routines to operate on the entire ppr set */
+
+/** Ensure no rate limit is greater than the cap */
+uint ppr_apply_max(ppr_t* pprptr, int8 maxval)
+{
+ uint i;
+ int8* rptr = (int8*)&pprptr->ppr_bw;
+
+ for (i = 0; i < ppr_pwrs_size(pprptr->hdr); i++, rptr++) {
+ *rptr = MIN(*rptr, maxval);
+ }
+ return i;
+}
+
+/** number of non proprietary 802.11n single stream MCS'es excluding MCS32 */
+#define N_HT_SS_MCS 8
+
+/**
+ * Before the OLPC calibration (needs to send out some training frames to converge TX Power control)
+ * rates need to be disabled that cannot be controlled to with the accuracy needed to avoid
+ * regulatory violations. Once the calibration completes a newer reduced threshold is set to enable
+ * all valid rates.
+ *
+ * Check for any power in the rate group at or below the threshold. If any is found, set the entire
+ * group to WL_RATE_DISABLED. An exception is made for HT 87 and 88 and VHT 8 and 9 which will not
+ * cause the entire group to be disabled if they are disabled or below the threshold.
+ */
+static void ppr_force_disabled_group(int8* powers, int8 threshold, uint len)
+{
+ uint i;
+
+ for (i = 0; (i < len) && (i < N_HT_SS_MCS); i++) {
+ /* if we find a below-threshold rate in the set... */
+ if (powers[i] < threshold) {
+ /* disable the entire rate set and return */
+ for (i = 0; i < len; i++) {
+ powers[i] = WL_RATE_DISABLED;
+ }
+ return;
+ }
+ }
+ /* VHT 8 and 11 can be disabled separately */
+ for (; i < len; i++) {
+ if (powers[i] < threshold) {
+ powers[i] = WL_RATE_DISABLED;
+ }
+ }
+}
+
+
+/**
+ * Before the OLPC calibration (needs to send out some training frames to converge TX Power control)
+ * rates need to be disabled that cannot be controlled to with the accuracy needed to avoid
+ * regulatory violations. Once the calibration completes a newer reduced threshold is set to enable
+ * all valid rates.
+ *
+ * Make low power rates (below the threshold) explicitly disabled. If one rate in a group is
+ * disabled, disable the whole group.
+ */
+int ppr_force_disabled(ppr_t* pprptr, int8 threshold)
+{
+ wl_tx_bw_t bw;
+
+ for (bw = WL_TX_BW_20; bw <= WL_TX_BW_80; bw++) {
+ pprpbw_t* bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+
+ if (bw_pwrs != NULL) {
+ int8* powers;
+#if (PPR_MAX_TX_CHAINS > 1)
+ int8* mcs_powers;
+#endif
+ powers = (int8*)ppr_get_dsss_group(bw_pwrs, WL_TX_CHAINS_1);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_DSSS);
+
+ powers = (int8*)ppr_get_ofdm_group(bw_pwrs,
+ WL_TX_MODE_NONE, WL_TX_CHAINS_1);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM);
+
+ powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, WL_TX_MODE_NONE,
+ WL_TX_CHAINS_1);
+ ASSERT(powers);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_VHT_MCS_P);
+
+#if (PPR_MAX_TX_CHAINS > 1)
+ powers = (int8*)ppr_get_dsss_group(bw_pwrs, WL_TX_CHAINS_2);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_DSSS);
+
+ powers = (int8*)ppr_get_ofdm_group(bw_pwrs, WL_TX_MODE_CDD, WL_TX_CHAINS_2);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM);
+
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, WL_TX_MODE_CDD,
+ WL_TX_CHAINS_2);
+ ASSERT(mcs_powers);
+ for (powers = mcs_powers; powers < &mcs_powers[PPR_CHAIN2_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS_P) {
+ ppr_force_disabled_group(powers, threshold,
+ WL_RATESET_SZ_VHT_MCS_P);
+ }
+
+#ifdef WL_BEAMFORMING
+ if (PPR_TXBF_ENAB()) {
+ powers = (int8*)ppr_get_ofdm_group(bw_pwrs, WL_TX_MODE_TXBF,
+ WL_TX_CHAINS_2);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM);
+
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1,
+ WL_TX_MODE_TXBF, WL_TX_CHAINS_2);
+ ASSERT(mcs_powers);
+ for (powers = mcs_powers;
+ powers < &mcs_powers[PPR_BF_CHAIN2_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS_P) {
+ ppr_force_disabled_group(powers, threshold,
+ WL_RATESET_SZ_VHT_MCS_P);
+ }
+ }
+#endif /* WL_BEAMFORMING */
+
+#if (PPR_MAX_TX_CHAINS > 2)
+ powers = (int8*)ppr_get_dsss_group(bw_pwrs, WL_TX_CHAINS_3);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_DSSS);
+
+ powers = (int8*)ppr_get_ofdm_group(bw_pwrs, WL_TX_MODE_CDD, WL_TX_CHAINS_3);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM);
+
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, WL_TX_MODE_CDD,
+ WL_TX_CHAINS_3);
+ ASSERT(mcs_powers);
+ for (powers = mcs_powers; powers < &mcs_powers[PPR_CHAIN3_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS_P) {
+ ppr_force_disabled_group(powers, threshold,
+ WL_RATESET_SZ_VHT_MCS_P);
+ }
+
+#ifdef WL_BEAMFORMING
+ if (PPR_TXBF_ENAB()) {
+ powers = (int8*)ppr_get_ofdm_group(bw_pwrs, WL_TX_MODE_TXBF,
+ WL_TX_CHAINS_3);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM);
+
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1,
+ WL_TX_MODE_TXBF, WL_TX_CHAINS_3);
+ ASSERT(mcs_powers);
+ for (powers = mcs_powers;
+ powers < &mcs_powers[PPR_BF_CHAIN3_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS_P) {
+ ppr_force_disabled_group(powers, threshold,
+ WL_RATESET_SZ_VHT_MCS_P);
+ }
+ }
+#endif /* WL_BEAMFORMING */
+#if (PPR_MAX_TX_CHAINS > 3)
+ powers = (int8*)ppr_get_dsss_group(bw_pwrs, WL_TX_CHAINS_4);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_DSSS);
+
+ powers = (int8*)ppr_get_ofdm_group(bw_pwrs, WL_TX_MODE_CDD, WL_TX_CHAINS_4);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM);
+
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, WL_TX_MODE_CDD,
+ WL_TX_CHAINS_4);
+ ASSERT(mcs_powers);
+ for (powers = mcs_powers; powers < &mcs_powers[PPR_CHAIN4_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS_P) {
+ ppr_force_disabled_group(powers, threshold,
+ WL_RATESET_SZ_VHT_MCS_P);
+ }
+
+#ifdef WL_BEAMFORMING
+ if (PPR_TXBF_ENAB()) {
+ powers = (int8*)ppr_get_ofdm_group(bw_pwrs, WL_TX_MODE_TXBF,
+ WL_TX_CHAINS_4);
+ ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM);
+
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1,
+ WL_TX_MODE_TXBF, WL_TX_CHAINS_4);
+ ASSERT(mcs_powers);
+ for (powers = mcs_powers;
+ powers < &mcs_powers[PPR_BF_CHAIN4_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS_P) {
+ ppr_force_disabled_group(powers, threshold,
+ WL_RATESET_SZ_VHT_MCS_P);
+ }
+ }
+#endif /* WL_BEAMFORMING */
+#endif /* (PPR_MAX_TX_CHAINS > 3) */
+#endif /* (PPR_MAX_TX_CHAINS > 2) */
+#endif /* (PPR_MAX_TX_CHAINS > 1) */
+ }
+ }
+ return BCME_OK;
+}
+
+
+#if (PPR_MAX_TX_CHAINS > 1)
+/**
+ * LCN20 PHY doesn't support VHT rates, but it seems some of its regulatory data does. We need
+ * to explicitly disable the VHT rates so there's no temptation to use them.
+ */
+static void ppr_force_disabled_vht_in_group(int8* powers, uint len)
+{
+ uint i;
+
+ for (i = N_HT_SS_MCS; (i < len); i++) {
+ powers[i] = WL_RATE_DISABLED;
+ }
+}
+#endif /* (PPR_MAX_TX_CHAINS > 1) */
+
+
+/**
+ * LCN20 PHY doesn't support VHT MIMO rates, but it seems some of its regulatory data does. We need
+ * to explicitly disable the VHT MIMO rates so there's no temptation to use them.
+ */
+int
+ppr_disable_vht_mimo_rates(ppr_t* pprptr)
+{
+#if (PPR_MAX_TX_CHAINS > 1)
+ wl_tx_bw_t bw;
+
+ for (bw = WL_TX_BW_20; bw <= WL_TX_BW_80; bw++) {
+ pprpbw_t* bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+
+ if (bw_pwrs != NULL) {
+ int8* mcs_powers;
+ int8* powers;
+
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, WL_TX_MODE_CDD,
+ WL_TX_CHAINS_2);
+ ASSERT(mcs_powers);
+ /* skip CDD */
+ /* mcs_powers += WL_RATESET_SZ_VHT_MCS; */
+ for (powers = mcs_powers; powers < &mcs_powers[PPR_CHAIN2_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS) {
+ ppr_force_disabled_vht_in_group(powers, WL_RATESET_SZ_VHT_MCS);
+ }
+
+#ifdef WL_BEAMFORMING
+ if (PPR_TXBF_ENAB()) {
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1,
+ WL_TX_MODE_TXBF, WL_TX_CHAINS_2);
+ ASSERT(mcs_powers);
+ for (powers = mcs_powers;
+ powers < &mcs_powers[PPR_BF_CHAIN2_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS) {
+ ppr_force_disabled_vht_in_group(powers,
+ WL_RATESET_SZ_VHT_MCS);
+ }
+ }
+#endif /* WL_BEAMFORMING */
+
+#if (PPR_MAX_TX_CHAINS > 2)
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, WL_TX_MODE_CDD,
+ WL_TX_CHAINS_3);
+ ASSERT(mcs_powers);
+ /* skip CDD */
+ /* mcs_powers += WL_RATESET_SZ_VHT_MCS; */
+ for (powers = mcs_powers; powers < &mcs_powers[PPR_CHAIN3_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS) {
+ ppr_force_disabled_vht_in_group(powers, WL_RATESET_SZ_VHT_MCS);
+ }
+
+#ifdef WL_BEAMFORMING
+ if (PPR_TXBF_ENAB()) {
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1,
+ WL_TX_MODE_TXBF, WL_TX_CHAINS_3);
+ ASSERT(mcs_powers);
+ for (powers = mcs_powers;
+ powers < &mcs_powers[PPR_BF_CHAIN3_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS) {
+ ppr_force_disabled_vht_in_group(powers,
+ WL_RATESET_SZ_VHT_MCS);
+ }
+ }
+#endif /* WL_BEAMFORMING */
+
+#if (PPR_MAX_TX_CHAINS > 3)
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, WL_TX_MODE_CDD,
+ WL_TX_CHAINS_4);
+ ASSERT(mcs_powers);
+ /* skip CDD */
+ /* mcs_powers += WL_RATESET_SZ_VHT_MCS; */
+ for (powers = mcs_powers; powers < &mcs_powers[PPR_CHAIN4_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS) {
+ ppr_force_disabled_vht_in_group(powers, WL_RATESET_SZ_VHT_MCS);
+ }
+
+#ifdef WL_BEAMFORMING
+ if (PPR_TXBF_ENAB()) {
+ mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1,
+ WL_TX_MODE_TXBF, WL_TX_CHAINS_4);
+ ASSERT(mcs_powers);
+ for (powers = mcs_powers;
+ powers < &mcs_powers[PPR_BF_CHAIN4_MCS_SIZE];
+ powers += WL_RATESET_SZ_VHT_MCS) {
+ ppr_force_disabled_vht_in_group(powers,
+ WL_RATESET_SZ_VHT_MCS);
+ }
+ }
+#endif /* WL_BEAMFORMING */
+#endif /* (PPR_MAX_TX_CHAINS > 3) */
+#endif /* (PPR_MAX_TX_CHAINS > 2) */
+ }
+ }
+#endif /* (PPR_MAX_TX_CHAINS > 1) */
+ return BCME_OK;
+}
+
+
+#if (PPR_MAX_TX_CHAINS > 1)
+#define APPLY_CONSTRAINT(x, y, max) do { \
+ ret += (y - x); \
+ for (i = x; i < y; i++) \
+ pprbuf[i] = MIN(pprbuf[i], max); \
+ } while (0);
+
+
+/** Apply appropriate single-, two- and three-chain constraints across the appropriate ppr block */
+static uint ppr_apply_constraint_to_block(int8* pprbuf, int8 constraint)
+{
+ uint ret = 0;
+ uint i = 0;
+ int8 constraint_2chain = constraint - QDB(3);
+#if (PPR_MAX_TX_CHAINS > 2)
+ int8 constraint_3chain = constraint - (QDB(4) + 3); /* - 4.75dBm */
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+
+ APPLY_CONSTRAINT(PPR_CHAIN1_FIRST, PPR_CHAIN1_END, constraint);
+ APPLY_CONSTRAINT(PPR_CHAIN2_FIRST, PPR_CHAIN2_END, constraint_2chain);
+#if (PPR_MAX_TX_CHAINS > 2)
+ APPLY_CONSTRAINT(PPR_CHAIN3_FIRST, PPR_CHAIN3_END, constraint_3chain);
+#endif /* PPR_MAX_TX_CHAINS > 2 */
+ return ret;
+}
+#endif /* (PPR_MAX_TX_CHAINS > 1) */
+
+
+/**
+ * Reduce total transmitted power to level of constraint.
+ * For two chain rates, the per-antenna power must be halved.
+ * For three chain rates, it must be a third of the constraint.
+ */
+uint ppr_apply_constraint_total_tx(ppr_t* pprptr, int8 constraint)
+{
+ uint ret = 0;
+
+#if (PPR_MAX_TX_CHAINS > 1)
+ int8* pprbuf;
+ ASSERT(pprptr);
+
+ /**
+ * TXPPR_TXPWR_MAX implies no constrains applied
+ * so skip applying constrains for multiple chains
+ */
+ if (constraint == TXPPR_TXPWR_MAX)
+ return ret;
+
+ switch (ppr_get_cur_bw(pprptr)) {
+ case WL_TX_BW_20:
+ {
+ pprbuf = (int8*)&pprptr->ppr_bw.ch20.b20;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ }
+ break;
+ case WL_TX_BW_40:
+ {
+ pprbuf = (int8*)&pprptr->ppr_bw.ch40.b40;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ pprbuf = (int8*)&pprptr->ppr_bw.ch40.b20in40;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ }
+ break;
+ case WL_TX_BW_80:
+ {
+ pprbuf = (int8*)&pprptr->ppr_bw.ch80.b80;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ pprbuf = (int8*)&pprptr->ppr_bw.ch80.b20in80;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ pprbuf = (int8*)&pprptr->ppr_bw.ch80.b40in80;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ }
+ break;
+#ifdef WL11AC_160
+ case WL_TX_BW_160:
+ {
+ pprbuf = (int8*)&pprptr->ppr_bw.ch160.b160;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ pprbuf = (int8*)&pprptr->ppr_bw.ch160.b20in160;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ pprbuf = (int8*)&pprptr->ppr_bw.ch160.b40in160;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ pprbuf = (int8*)&pprptr->ppr_bw.ch160.b80in160;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ }
+ break;
+#endif /* WL11AC_160 */
+#ifdef WL11AC_80P80
+ case WL_TX_BW_8080:
+ {
+ pprbuf = (int8*)&pprptr->ppr_bw.ch8080.b80ch1;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ pprbuf = (int8*)&pprptr->ppr_bw.ch8080.b80ch2;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ pprbuf = (int8*)&pprptr->ppr_bw.ch8080.b80in8080;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ pprbuf = (int8*)&pprptr->ppr_bw.ch8080.b20in8080;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ pprbuf = (int8*)&pprptr->ppr_bw.ch8080.b40in8080;
+ ret += ppr_apply_constraint_to_block(pprbuf, constraint);
+ }
+ break;
+#endif /* WL11AC_80P80 */
+ default:
+ ASSERT(0);
+ }
+
+#else
+ ASSERT(pprptr);
+ ret = ppr_apply_max(pprptr, constraint);
+#endif /* PPR_MAX_TX_CHAINS > 1 */
+ return ret;
+}
+
+
+/** Ensure no rate limit is lower than the specified minimum */
+uint ppr_apply_min(ppr_t* pprptr, int8 minval)
+{
+ uint i;
+ int8* rptr = (int8*)&pprptr->ppr_bw;
+
+ for (i = 0; i < ppr_pwrs_size(pprptr->hdr); i++, rptr++) {
+ *rptr = MAX(*rptr, minval);
+ }
+ return i;
+}
+
+
+/** Ensure no rate limit in this ppr set is greater than the corresponding limit in ppr_cap */
+uint ppr_apply_vector_ceiling(ppr_t* pprptr, const ppr_t* ppr_cap)
+{
+ uint i = 0;
+ int8* rptr = (int8*)&pprptr->ppr_bw;
+ const int8* capptr = (const int8*)&ppr_cap->ppr_bw;
+
+ if (ppr_get_cur_bw(pprptr) == ppr_get_cur_bw(ppr_cap)) {
+ for (i = 0; i < ppr_pwrs_size(pprptr->hdr); i++, rptr++, capptr++) {
+ *rptr = MIN(*rptr, *capptr);
+ }
+ }
+ return i;
+}
+
+
+/** Ensure no rate limit in this ppr set is lower than the corresponding limit in ppr_min */
+uint ppr_apply_vector_floor(ppr_t* pprptr, const ppr_t* ppr_min)
+{
+ uint i = 0;
+ int8* rptr = (int8*)&pprptr->ppr_bw;
+ const int8* minptr = (const int8*)&ppr_min->ppr_bw;
+
+ if (ppr_get_cur_bw(pprptr) == ppr_get_cur_bw(ppr_min)) {
+ for (i = 0; i < ppr_pwrs_size(pprptr->hdr); i++, rptr++, minptr++) {
+ *rptr = MAX((uint8)*rptr, (uint8)*minptr);
+ }
+ }
+ return i;
+}
+
+
+/** Get the maximum power in the ppr set */
+int8 ppr_get_max(ppr_t* pprptr)
+{
+ uint i;
+ int8* rptr = (int8*)&pprptr->ppr_bw;
+ int8 maxval = *rptr++;
+
+ for (i = 1; i < ppr_pwrs_size(pprptr->hdr); i++, rptr++) {
+ maxval = MAX(maxval, *rptr);
+ }
+ return maxval;
+}
+
+/* Get the maximum power in the dsss ppr set */
+int8 ppr_get_dsss_max(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains)
+{
+ ppr_dsss_rateset_t dsss;
+ uint8 rate;
+ int8 maxval = 0;
+ ppr_get_dsss(pprptr, bw, tx_chains, &dsss);
+ maxval = dsss.pwr[0];
+ for (rate = 1; rate < WL_RATESET_SZ_DSSS; rate++) {
+ maxval = MAX(maxval, dsss.pwr[rate]);
+ }
+ return maxval;
+}
+/**
+ * Get the minimum power in the ppr set, excluding disallowed
+ * rates and (possibly) powers set to the minimum for the phy
+ */
+int8 ppr_get_min(ppr_t* pprptr, int8 floor)
+{
+ uint i;
+ int8* rptr = (int8*)&pprptr->ppr_bw;
+ int8 minval = WL_RATE_DISABLED;
+
+ for (i = 0; (i < ppr_pwrs_size(pprptr->hdr)) && ((minval == WL_RATE_DISABLED) ||
+ (minval == floor)); i++, rptr++) {
+ minval = *rptr;
+ }
+ for (; i < ppr_pwrs_size(pprptr->hdr); i++, rptr++) {
+ if ((*rptr != WL_RATE_DISABLED) && (*rptr != floor))
+ minval = MIN(minval, *rptr);
+ }
+ return minval;
+}
+
+
+/** Get the maximum power for a given bandwidth in the ppr set */
+int8 ppr_get_max_for_bw(ppr_t* pprptr, wl_tx_bw_t bw)
+{
+ uint i;
+ const pprpbw_t* bw_pwrs;
+ const int8* rptr;
+ int8 maxval;
+
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ rptr = (const int8*)bw_pwrs;
+ maxval = *rptr++;
+
+ for (i = 1; i < sizeof(*bw_pwrs); i++, rptr++) {
+ maxval = MAX(maxval, *rptr);
+ }
+ } else {
+ maxval = WL_RATE_DISABLED;
+ }
+ return maxval;
+}
+
+
+/** Get the minimum power for a given bandwidth in the ppr set */
+int8 ppr_get_min_for_bw(ppr_t* pprptr, wl_tx_bw_t bw)
+{
+ uint i;
+ const pprpbw_t* bw_pwrs;
+ const int8* rptr;
+ int8 minval;
+
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ if (bw_pwrs != NULL) {
+ rptr = (const int8*)bw_pwrs;
+ minval = *rptr++;
+
+ for (i = 1; i < sizeof(*bw_pwrs); i++, rptr++) {
+ minval = MIN(minval, *rptr);
+ }
+ } else
+ minval = WL_RATE_DISABLED;
+ return minval;
+}
+
+
+/** Map the given function with its context value over the two power vectors */
+void
+ppr_map_vec_dsss(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, ppr_t* pprptr2,
+ wl_tx_bw_t bw, wl_tx_chains_t tx_chains)
+{
+ pprpbw_t* bw_pwrs1;
+ pprpbw_t* bw_pwrs2;
+ int8* powers1;
+ int8* powers2;
+ uint i;
+
+ ASSERT(pprptr1);
+ ASSERT(pprptr2);
+
+ bw_pwrs1 = ppr_get_bw_powers(pprptr1, bw);
+ bw_pwrs2 = ppr_get_bw_powers(pprptr2, bw);
+ if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) {
+ powers1 = (int8*)ppr_get_dsss_group(bw_pwrs1, tx_chains);
+ powers2 = (int8*)ppr_get_dsss_group(bw_pwrs2, tx_chains);
+ if ((powers1 != NULL) && (powers2 != NULL)) {
+ for (i = 0; i < WL_RATESET_SZ_DSSS; i++)
+ (fn)(context, (uint8*)powers1++, (uint8*)powers2++);
+ }
+ }
+}
+
+
+/** Map the given function with its context value over the two power vectors */
+void
+ppr_map_vec_ofdm(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, ppr_t* pprptr2,
+ wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains)
+{
+ pprpbw_t* bw_pwrs1;
+ pprpbw_t* bw_pwrs2;
+ int8* powers1;
+ int8* powers2;
+ uint i;
+
+ bw_pwrs1 = ppr_get_bw_powers(pprptr1, bw);
+ bw_pwrs2 = ppr_get_bw_powers(pprptr2, bw);
+ if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) {
+ powers1 = (int8*)ppr_get_ofdm_group(bw_pwrs1, mode, tx_chains);
+ powers2 = (int8*)ppr_get_ofdm_group(bw_pwrs2, mode, tx_chains);
+ if ((powers1 != NULL) && (powers2 != NULL)) {
+ for (i = 0; i < WL_RATESET_SZ_OFDM; i++)
+ (fn)(context, (uint8*)powers1++, (uint8*)powers2++);
+ }
+ }
+}
+
+
+/** Map the given function with its context value over the two power vectors */
+void
+ppr_map_vec_ht_mcs(ppr_mapfn_t fn, void* context, ppr_t* pprptr1,
+ ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode,
+ wl_tx_chains_t tx_chains)
+{
+ pprpbw_t* bw_pwrs1;
+ pprpbw_t* bw_pwrs2;
+ int8* powers1;
+ int8* powers2;
+ uint i;
+
+ bw_pwrs1 = ppr_get_bw_powers(pprptr1, bw);
+ bw_pwrs2 = ppr_get_bw_powers(pprptr2, bw);
+ if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) {
+ powers1 = (int8*)ppr_get_mcs_group(bw_pwrs1, Nss, mode, tx_chains);
+ powers2 = (int8*)ppr_get_mcs_group(bw_pwrs2, Nss, mode, tx_chains);
+ if ((powers1 != NULL) && (powers2 != NULL)) {
+ for (i = 0; i < WL_RATESET_SZ_HT_MCS; i++)
+ (fn)(context, (uint8*)powers1++, (uint8*)powers2++);
+ }
+ }
+}
+
+
+/** Map the given function with its context value over the two power vectors */
+void
+ppr_map_vec_vht_mcs(ppr_mapfn_t fn, void* context, ppr_t* pprptr1,
+ ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, wl_tx_chains_t
+ tx_chains)
+{
+ pprpbw_t* bw_pwrs1;
+ pprpbw_t* bw_pwrs2;
+ int8* powers1;
+ int8* powers2;
+ uint i;
+
+ bw_pwrs1 = ppr_get_bw_powers(pprptr1, bw);
+ bw_pwrs2 = ppr_get_bw_powers(pprptr2, bw);
+ if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) {
+ powers1 = (int8*)ppr_get_mcs_group(bw_pwrs1, Nss, mode, tx_chains);
+ powers2 = (int8*)ppr_get_mcs_group(bw_pwrs2, Nss, mode, tx_chains);
+ if ((powers1 != NULL) && (powers2 != NULL)) {
+ for (i = 0; i < WL_RATESET_SZ_VHT_MCS; i++)
+ (fn)(context, (uint8*)powers1++, (uint8*)powers2++);
+ }
+ }
+}
+
+static bool
+ppr_map_vec_per_bw(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, ppr_t* pprptr2, wl_tx_bw_t bw)
+{
+ uint i;
+ pprpbw_t* bw_pwrs1;
+ pprpbw_t* bw_pwrs2;
+ int8* rptr1 = (int8*)&pprptr1->ppr_bw;
+ int8* rptr2 = (int8*)&pprptr2->ppr_bw;
+ bool ret = TRUE;
+
+ bw_pwrs1 = ppr_get_bw_powers(pprptr1, bw);
+ bw_pwrs2 = ppr_get_bw_powers(pprptr2, bw);
+
+ if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) {
+ rptr1 = (int8*)bw_pwrs1;
+ rptr2 = (int8*)bw_pwrs2;
+ for (i = 0; i < sizeof(pprpbw_t); i++, rptr1++, rptr2++) {
+ (fn)(context, (uint8*)rptr1, (uint8*)rptr2);
+ }
+ } else {
+ ret = FALSE;
+ }
+ return ret;
+}
+
+/** Map the given function with its context value over the two power vectors */
+
+void
+ppr_map_vec_all(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, ppr_t* pprptr2)
+{
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_20);
+
+ if (ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_40)) {
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_20IN40);
+ }
+
+ if (ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_80)) {
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_20IN80);
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_40IN80);
+ }
+
+ if (ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_160)) {
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_20IN160);
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_40IN160);
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_80IN160);
+ }
+
+ if (ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_8080)) {
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_20IN8080);
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_40IN8080);
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_80IN8080);
+ (void)ppr_map_vec_per_bw(fn, context, pprptr1, pprptr2, WL_TX_BW_8080CHAN2);
+ }
+}
+
+
+/** Set PPR struct to a certain power level */
+void
+ppr_set_cmn_val(ppr_t* pprptr, int8 val)
+{
+ memset((uchar*)&pprptr->ppr_bw, val, ppr_pwrs_size(pprptr->hdr));
+}
+
+
+/** Make an identical copy of a ppr structure (for ppr_bw==all case) */
+void
+ppr_copy_struct(ppr_t* pprptr_s, ppr_t* pprptr_d)
+{
+ int8* rptr_s = (int8*)&pprptr_s->ppr_bw;
+ int8* rptr_d = (int8*)&pprptr_d->ppr_bw;
+ /* ASSERT(ppr_pwrs_size(pprptr_d->hdr) >= ppr_pwrs_size(pprptr_s->hdr)); */
+
+ if (ppr_get_cur_bw(pprptr_s) ==
+ ppr_get_cur_bw(pprptr_d))
+ memcpy(rptr_d, rptr_s, ppr_pwrs_size(pprptr_s->hdr));
+ else {
+ const pprpbw_t* src_bw_pwrs;
+ pprpbw_t* dest_bw_pwrs;
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_20);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_20);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_40);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_40);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_20IN40);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_20IN40);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_80);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_80);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_20IN80);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_20IN80);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_40IN80);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_40IN80);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_160);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_160);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_20IN160);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_20IN160);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_40IN160);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_40IN160);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_80IN160);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_80IN160);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_8080);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_8080);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_8080CHAN2);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_8080CHAN2);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_20IN8080);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_20IN8080);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_40IN8080);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_40IN8080);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+
+ src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_80IN8080);
+ dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_80IN8080);
+ if (src_bw_pwrs && dest_bw_pwrs)
+ bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs,
+ sizeof(*src_bw_pwrs));
+ }
+}
+
+
+/** Subtract each power from a common value and re-store */
+void
+ppr_cmn_val_minus(ppr_t* pprptr, int8 val)
+{
+ uint i;
+ int8* rptr = (int8*)&pprptr->ppr_bw;
+
+ for (i = 0; i < ppr_pwrs_size(pprptr->hdr); i++, rptr++) {
+ if (*rptr != (int8)WL_RATE_DISABLED)
+ *rptr = val - *rptr;
+ }
+
+}
+
+
+/** Subtract a common value from each power and re-store */
+void
+ppr_minus_cmn_val(ppr_t* pprptr, int8 val)
+{
+ uint i;
+ int8* rptr = (int8*)&pprptr->ppr_bw;
+
+ for (i = 0; i < ppr_pwrs_size(pprptr->hdr); i++, rptr++) {
+ if (*rptr != (int8)WL_RATE_DISABLED)
+ *rptr = *rptr - val;
+ }
+
+}
+
+
+/** Add a common value to each power and re-store */
+void
+ppr_plus_cmn_val(ppr_t* pprptr, int8 val)
+{
+ uint i;
+ int8* rptr = (int8*)&pprptr->ppr_bw;
+
+ for (i = 0; i < ppr_pwrs_size(pprptr->hdr); i++, rptr++) {
+ if (*rptr != (int8)WL_RATE_DISABLED)
+ *rptr += val;
+ }
+
+}
+
+
+/** Multiply by a percentage */
+void
+ppr_multiply_percentage(ppr_t* pprptr, uint8 val)
+{
+ uint i;
+ int8* rptr = (int8*)&pprptr->ppr_bw;
+
+ for (i = 0; i < ppr_pwrs_size(pprptr->hdr); i++, rptr++) {
+ if (*rptr != (int8)WL_RATE_DISABLED)
+ *rptr = (*rptr * val) / 100;
+ }
+
+}
+
+
+/**
+ * Compare two ppr variables p1 and p2, save the min value of each
+ * contents to variable p1
+ */
+void
+ppr_compare_min(ppr_t* p1, ppr_t* p2)
+{
+ uint i;
+ int8* rptr1 = NULL;
+ int8* rptr2 = NULL;
+ uint32 pprsize = 0;
+
+ if (ppr_get_cur_bw(p1) == ppr_get_cur_bw(p2)) {
+ rptr1 = (int8*)&p1->ppr_bw;
+ rptr2 = (int8*)&p2->ppr_bw;
+ pprsize = ppr_pwrs_size(p1->hdr);
+ }
+
+ for (i = 0; i < pprsize; i++, rptr1++, rptr2++) {
+ *rptr1 = MIN(*rptr1, *rptr2);
+ }
+}
+
+
+/**
+ * Compare two ppr variables p1 and p2, save the max. value of each
+ * contents to variable p1
+ */
+void
+ppr_compare_max(ppr_t* p1, ppr_t* p2)
+{
+ uint i;
+ int8* rptr1 = NULL;
+ int8* rptr2 = NULL;
+ uint32 pprsize = 0;
+
+ if (ppr_get_cur_bw(p1) == ppr_get_cur_bw(p2)) {
+ rptr1 = (int8*)&p1->ppr_bw;
+ rptr2 = (int8*)&p2->ppr_bw;
+ pprsize = ppr_pwrs_size(p1->hdr);
+ }
+
+ for (i = 0; i < pprsize; i++, rptr1++, rptr2++) {
+ *rptr1 = MAX(*rptr1, *rptr2);
+ }
+}
+
+
+/**
+ * Serialize the contents of the opaque ppr struct.
+ * Writes number of bytes copied, zero on error.
+ * Returns error code, BCME_OK if successful.
+ */
+int
+ppr_serialize(const ppr_t* pprptr, uint8* buf, uint buflen, uint* bytes_copied)
+{
+ int err = BCME_OK;
+ if (buflen <= sizeof(ppr_ser_mem_flag_t)) {
+ err = BCME_BUFTOOSHORT;
+ } else {
+ ppr_ser_mem_flag_t *smem_flag = (ppr_ser_mem_flag_t *)buf;
+ uint32 flag = NTOH32(smem_flag->flag);
+
+ /* check if memory contains a valid flag, if not, use current
+ * condition (num of chains, txbf etc.) to serialize data.
+ */
+ if (NTOH32(smem_flag->magic_word) != PPR_SER_MEM_WORD) {
+ flag = ppr_get_flag();
+ }
+
+ if (buflen >= ppr_ser_size_by_flag(flag, ppr_get_cur_bw(pprptr))) {
+ *bytes_copied = ppr_serialize_data(pprptr, buf, flag);
+ } else {
+ err = BCME_BUFTOOSHORT;
+ }
+ }
+ return err;
+}
+
+
+/**
+ * Deserialize the contents of a buffer into an opaque ppr struct.
+ * Creates an opaque structure referenced by *pptrptr, NULL on error.
+ * Returns error code, BCME_OK if successful.
+ */
+int
+ppr_deserialize_create(osl_t *osh, const uint8* buf, uint buflen, ppr_t** pprptr)
+{
+ const uint8* bptr = buf;
+ int err = BCME_OK;
+ ppr_t* lpprptr = NULL;
+
+ if ((buflen > SER_HDR_LEN) && (bptr != NULL) && (*bptr == PPR_SERIALIZATION_VER)) {
+ const ppr_deser_header_t * ser_head = (const ppr_deser_header_t *)bptr;
+ wl_tx_bw_t ch_bw = ser_head->bw;
+ /* struct size plus header */
+ uint32 ser_size = ppr_pwrs_size((ch_bw)) + SER_HDR_LEN;
+
+ if ((lpprptr = ppr_create(osh, ch_bw)) != NULL) {
+ uint32 flags = NTOH32(ser_head->flags);
+ uint16 per_band_size = NTOH16(ser_head->per_band_size);
+ /* set the data with default value before deserialize */
+ ppr_set_cmn_val(lpprptr, WL_RATE_DISABLED);
+
+ ppr_deser_cpy(lpprptr, bptr + sizeof(*ser_head), flags, ch_bw,
+ per_band_size);
+ } else if (buflen < ser_size) {
+ err = BCME_BUFTOOSHORT;
+ } else {
+ err = BCME_NOMEM;
+ }
+ } else if (buflen <= SER_HDR_LEN) {
+ err = BCME_BUFTOOSHORT;
+ } else if (bptr == NULL) {
+ err = BCME_BADARG;
+ } else {
+ err = BCME_VERSION;
+ }
+ *pprptr = lpprptr;
+ return err;
+}
+
+
+/**
+ * Deserialize the contents of a buffer into an opaque ppr struct.
+ * Creates an opaque structure referenced by *pptrptr, NULL on error.
+ * Returns error code, BCME_OK if successful.
+ */
+int
+ppr_deserialize(ppr_t* pprptr, const uint8* buf, uint buflen)
+{
+ const uint8* bptr = buf;
+ int err = BCME_OK;
+ ASSERT(pprptr);
+ if ((buflen > SER_HDR_LEN) && (bptr != NULL) && (*bptr == PPR_SERIALIZATION_VER)) {
+ const ppr_deser_header_t * ser_head = (const ppr_deser_header_t *)bptr;
+ wl_tx_bw_t ch_bw = ser_head->bw;
+
+ if (ch_bw == ppr_get_cur_bw(pprptr)) {
+ uint32 flags = NTOH32(ser_head->flags);
+ uint16 per_band_size = NTOH16(ser_head->per_band_size);
+ ppr_set_cmn_val(pprptr, WL_RATE_DISABLED);
+ ppr_deser_cpy(pprptr, bptr + sizeof(*ser_head), flags, ch_bw,
+ per_band_size);
+ } else {
+ err = BCME_BADARG;
+ }
+ } else if (buflen <= SER_HDR_LEN) {
+ err = BCME_BUFTOOSHORT;
+ } else if (bptr == NULL) {
+ err = BCME_BADARG;
+ } else {
+ err = BCME_VERSION;
+ }
+ return err;
+}
+
+/* Get transmit channel bandwidths from chanspec */
+wl_tx_bw_t ppr_chanspec_bw(chanspec_t chspec)
+{
+ uint chspec_bw = CHSPEC_BW(chspec);
+ wl_tx_bw_t ret = WL_TX_BW_20;
+ switch (chspec_bw) {
+ case WL_CHANSPEC_BW_2P5:
+ case WL_CHANSPEC_BW_5:
+ case WL_CHANSPEC_BW_10:
+ case WL_CHANSPEC_BW_20:
+ ret = WL_TX_BW_20;
+ break;
+ case WL_CHANSPEC_BW_40:
+ ret = WL_TX_BW_40;
+ break;
+ case WL_CHANSPEC_BW_80:
+ ret = WL_TX_BW_80;
+ break;
+ case WL_CHANSPEC_BW_160:
+ ret = WL_TX_BW_160;
+ break;
+ case WL_CHANSPEC_BW_8080:
+ ret = WL_TX_BW_8080;
+ break;
+ default :
+ ASSERT(0);
+ }
+ return ret;
+}
+
+#if defined(WL_EXPORT_CURPOWER) || !defined(BCMDRIVER)
+
+#define DSSS_TLV_LEN (sizeof(ppr_dsss_tlv_t) + sizeof(ppr_dsss_rateset_t))
+#define OFDM_TLV_LEN (sizeof(ppr_ofdm_tlv_t) + sizeof(ppr_ofdm_rateset_t))
+#define MCS_TLV_LEN (sizeof(ppr_mcs_tlv_t) + sizeof(ppr_vht_mcs_rateset_t))
+#define PPR_TLV_VER_SIZE (sizeof(int8))
+
+/* Fill DSSS TLV data into the given buffer */
+static uint32
+ppr_to_dssstlv_per_band(ppr_t* pprptr, wl_tx_bw_t bw, uint8 **to_tlv_buf, uint32 tlv_buf_len,
+ wl_tx_chains_t max_chain)
+{
+ uint32 len = 0;
+ wl_tx_chains_t chain;
+
+ pprpbw_t* bw_pwrs;
+ bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ for (chain = WL_TX_CHAINS_1; chain <= max_chain; chain++) {
+ bcm_tlv_t *tlv_hdr = (bcm_tlv_t *)(*to_tlv_buf);
+ ppr_dsss_tlv_t *dsss_tlv = (ppr_dsss_tlv_t *)tlv_hdr->data;
+ if (len + DSSS_TLV_LEN + BCM_TLV_HDR_SIZE <= tlv_buf_len) {
+ const int8* powers;
+ bool found = FALSE;
+
+ if (bw_pwrs != NULL) {
+ powers = ppr_get_dsss_group(bw_pwrs, chain);
+ if (powers) {
+ memcpy(dsss_tlv->pwr, powers, sizeof(ppr_dsss_rateset_t));
+ found = TRUE;
+ }
+ }
+
+ if (found) {
+ tlv_hdr->id = PPR_RGRP_DSSS_ID;
+ tlv_hdr->len = DSSS_TLV_LEN;
+ dsss_tlv->bw = bw;
+ dsss_tlv->chains = (uint8)chain;
+ len += (DSSS_TLV_LEN + BCM_TLV_HDR_SIZE);
+ *to_tlv_buf += (DSSS_TLV_LEN + BCM_TLV_HDR_SIZE);
+ }
+ } else {
+ break;
+ }
+ }
+ return len;
+}
+
+/* Fill OFDM TLV data into the given buffer */
+static uint32
+ppr_to_ofdmtlv_per_band(ppr_t* pprptr, wl_tx_bw_t bw, uint8 **to_tlv_buf, uint32 tlv_buf_len,
+ wl_tx_chains_t max_chain)
+{
+ uint32 len = 0;
+ wl_tx_chains_t chain;
+ wl_tx_mode_t mode;
+ pprpbw_t* bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ for (chain = WL_TX_CHAINS_1; chain <= max_chain; chain++) {
+ for (mode = WL_TX_MODE_NONE; mode < WL_NUM_TX_MODES; mode ++) {
+ bcm_tlv_t *tlv_hdr = (bcm_tlv_t *)(*to_tlv_buf);
+ ppr_ofdm_tlv_t *ofdm_tlv = (ppr_ofdm_tlv_t *)tlv_hdr->data;
+ const int8* powers;
+ bool found = FALSE;
+ if (len + OFDM_TLV_LEN + BCM_TLV_HDR_SIZE <= tlv_buf_len) {
+ if (bw_pwrs != NULL) {
+ powers = ppr_get_ofdm_group(bw_pwrs, mode, chain);
+ if (powers != NULL) {
+ memcpy(ofdm_tlv->pwr, powers,
+ sizeof(ppr_ofdm_rateset_t));
+ found = TRUE;
+ }
+ }
+ if (found) {
+ tlv_hdr->id = PPR_RGRP_OFDM_ID;
+ tlv_hdr->len = OFDM_TLV_LEN;
+ ofdm_tlv->bw = bw;
+ ofdm_tlv->chains = (uint8)chain;
+ ofdm_tlv->mode = mode;
+
+ len += (OFDM_TLV_LEN + BCM_TLV_HDR_SIZE);
+ *to_tlv_buf += (OFDM_TLV_LEN + BCM_TLV_HDR_SIZE);
+ }
+ } else {
+ return len;
+ }
+ }
+
+ }
+ return len;
+}
+
+/* Fill MCS TLV data into the given buffer */
+static uint32
+ppr_to_mcstlv_per_band(ppr_t* pprptr, wl_tx_bw_t bw, uint8 **to_tlv_buf, uint32 tlv_buf_len,
+ wl_tx_chains_t max_chain)
+{
+ uint32 len = 0;
+ wl_tx_chains_t chain;
+ wl_tx_mode_t mode;
+ uint8 nss;
+ pprpbw_t* bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ for (chain = WL_TX_CHAINS_1; chain <= max_chain; chain++) {
+ for (nss = WL_TX_NSS_1; nss <= chain; nss++) {
+ for (mode = WL_TX_MODE_NONE; mode < WL_NUM_TX_MODES; mode ++) {
+ bcm_tlv_t *tlv_hdr = (bcm_tlv_t *)(*to_tlv_buf);
+ ppr_mcs_tlv_t *mcs_tlv = (ppr_mcs_tlv_t *)tlv_hdr->data;
+ if (len + MCS_TLV_LEN + BCM_TLV_HDR_SIZE <= tlv_buf_len) {
+ const int8* powers;
+ bool found = FALSE;
+ if (bw_pwrs != NULL) {
+ powers = ppr_get_mcs_group(bw_pwrs, nss, mode,
+ chain);
+ if (powers != NULL) {
+ memcpy(mcs_tlv->pwr, powers,
+ sizeof(ppr_vht_mcs_rateset_t));
+ found = TRUE;
+ }
+ }
+
+ if (found) {
+ tlv_hdr->id = PPR_RGRP_MCS_ID;
+ tlv_hdr->len = MCS_TLV_LEN;
+ mcs_tlv->bw = bw;
+ mcs_tlv->chains = (uint8)chain;
+ mcs_tlv->mode = mode;
+ mcs_tlv->nss = nss;
+ len += (MCS_TLV_LEN + BCM_TLV_HDR_SIZE);
+ *to_tlv_buf += (MCS_TLV_LEN + BCM_TLV_HDR_SIZE);
+ }
+ } else {
+ return len;
+ }
+ }
+ }
+ }
+ return len;
+}
+
+/* Convert ppr structure to TLV data */
+void ppr_convert_to_tlv(ppr_t* pprptr, wl_tx_bw_t bw, uint8 *to_tlv_buf, uint32 tlv_buf_len,
+ wl_tx_chains_t max_chain)
+{
+ uint32 len = tlv_buf_len;
+ wl_tx_bw_t check_bw;
+ ASSERT(pprptr && to_tlv_buf);
+ to_tlv_buf[0] = PPR_TLV_VER;
+ to_tlv_buf++;
+ switch (bw) {
+ case WL_TX_BW_2P5:
+ case WL_TX_BW_5:
+ case WL_TX_BW_10:
+ case WL_TX_BW_20:
+ len -= ppr_to_dssstlv_per_band(pprptr, bw, &to_tlv_buf, len, max_chain);
+ len -= ppr_to_ofdmtlv_per_band(pprptr, bw, &to_tlv_buf, len, max_chain);
+ ppr_to_mcstlv_per_band(pprptr, bw, &to_tlv_buf, len, max_chain);
+ break;
+ case WL_TX_BW_40:
+ len -= ppr_to_dssstlv_per_band(pprptr, WL_TX_BW_20IN40, &to_tlv_buf, len,
+ max_chain);
+ len -= ppr_to_ofdmtlv_per_band(pprptr, WL_TX_BW_20IN40, &to_tlv_buf, len,
+ max_chain);
+ len -= ppr_to_mcstlv_per_band(pprptr, WL_TX_BW_20IN40, &to_tlv_buf, len,
+ max_chain);
+ len -= ppr_to_ofdmtlv_per_band(pprptr, WL_TX_BW_40, &to_tlv_buf, len, max_chain);
+ len -= ppr_to_mcstlv_per_band(pprptr, WL_TX_BW_40, &to_tlv_buf, len, max_chain);
+ break;
+ case WL_TX_BW_80:
+ for (check_bw = WL_TX_BW_80; check_bw <= WL_TX_BW_40IN80; check_bw++) {
+ if (check_bw == WL_TX_BW_20IN40)
+ continue;
+ if (check_bw == WL_TX_BW_20IN80) {
+ len -= ppr_to_dssstlv_per_band(pprptr, check_bw, &to_tlv_buf, len,
+ max_chain);
+ }
+ len -= ppr_to_ofdmtlv_per_band(pprptr, check_bw, &to_tlv_buf, len,
+ max_chain);
+ len -= ppr_to_mcstlv_per_band(pprptr, check_bw, &to_tlv_buf, len,
+ max_chain);
+ }
+ break;
+ case WL_TX_BW_160:
+ for (check_bw = WL_TX_BW_160; check_bw <= WL_TX_BW_80IN160; check_bw++) {
+ if (check_bw == WL_TX_BW_20IN160) {
+ len -= ppr_to_dssstlv_per_band(pprptr, check_bw, &to_tlv_buf, len,
+ max_chain);
+ }
+ len -= ppr_to_ofdmtlv_per_band(pprptr, check_bw, &to_tlv_buf, len,
+ max_chain);
+ len -= ppr_to_mcstlv_per_band(pprptr, check_bw, &to_tlv_buf, len,
+ max_chain);
+ }
+ break;
+ case WL_TX_BW_8080:
+ for (check_bw = WL_TX_BW_8080; check_bw <= WL_TX_BW_80IN8080; check_bw++) {
+ if (check_bw == WL_TX_BW_20IN8080) {
+ len -= ppr_to_dssstlv_per_band(pprptr, WL_TX_BW_8080, &to_tlv_buf,
+ len, max_chain);
+ }
+ len -= ppr_to_ofdmtlv_per_band(pprptr, check_bw, &to_tlv_buf, len,
+ max_chain);
+ len -= ppr_to_mcstlv_per_band(pprptr, check_bw, &to_tlv_buf, len,
+ max_chain);
+ }
+ break;
+ default:
+ break;
+ };
+}
+
+/* Convert TLV data to ppr structure */
+int ppr_convert_from_tlv(ppr_t* pprptr, uint8 *from_tlv_buf, uint32 tlv_buf_len)
+{
+ uint8 ser_ver = from_tlv_buf[0];
+ bcm_tlv_t *elt = (bcm_tlv_t *)(&from_tlv_buf[1]);
+ int ret = BCME_OK;
+ if (ser_ver != PPR_TLV_VER) {
+ ret = BCME_VERSION;
+ } else {
+ do {
+ switch (elt->id) {
+ case PPR_RGRP_DSSS_ID:
+ {
+ ppr_dsss_tlv_t *dsss_tlv = (ppr_dsss_tlv_t *)elt->data;
+ ppr_set_dsss(pprptr, dsss_tlv->bw, dsss_tlv->chains,
+ (ppr_dsss_rateset_t*)dsss_tlv->pwr);
+ }
+ break;
+ case PPR_RGRP_OFDM_ID:
+ {
+ ppr_ofdm_tlv_t *ofdm_tlv = (ppr_ofdm_tlv_t *)elt->data;
+ ppr_set_ofdm(pprptr, ofdm_tlv->bw, ofdm_tlv->mode,
+ ofdm_tlv->chains,
+ (ppr_ofdm_rateset_t*)(ofdm_tlv->pwr));
+ }
+ break;
+ case PPR_RGRP_MCS_ID:
+ {
+ ppr_mcs_tlv_t *mcs_tlv = (ppr_mcs_tlv_t *)elt->data;
+ ppr_set_vht_mcs(pprptr, mcs_tlv->bw, mcs_tlv->nss,
+ mcs_tlv->mode, mcs_tlv->chains,
+ (ppr_vht_mcs_rateset_t*)mcs_tlv->pwr);
+ }
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ } while ((elt = bcm_next_tlv(elt, (int *)&tlv_buf_len)) != NULL);
+ }
+ return ret;
+}
+
+/* Get the required buffer size for DSSS TLV data */
+static uint32 ppr_get_tlv_size_dsss(uint32 max_chain)
+{
+ uint32 size = 0;
+ uint32 chain;
+ for (chain = 1; chain <= max_chain; chain++) {
+ size += (DSSS_TLV_LEN + BCM_TLV_HDR_SIZE);
+ }
+ return size;
+}
+
+/* Get the required buffer size for MCS/OFDM TLV data */
+static uint32 ppr_get_ofdmmcs_size(ppr_t* pprptr, uint32 max_chain, wl_tx_bw_t bw)
+{
+ uint32 size = 0;
+ uint32 chain;
+ wl_tx_mode_t mode;
+ uint32 nss;
+ const int8* powers;
+ pprpbw_t* bw_pwrs = ppr_get_bw_powers(pprptr, bw);
+ for (chain = 1; chain <= max_chain; chain++) {
+ for (mode = WL_TX_MODE_NONE; mode < WL_NUM_TX_MODES; mode ++) {
+ if (bw_pwrs != NULL) {
+ powers = ppr_get_ofdm_group(bw_pwrs, mode, chain);
+ if (powers != NULL) {
+ size += (OFDM_TLV_LEN + BCM_TLV_HDR_SIZE);
+ }
+ for (nss = WL_TX_NSS_1; nss <= chain; nss++) {
+ powers = ppr_get_mcs_group(bw_pwrs, nss, mode,
+ chain);
+ if (powers != NULL) {
+ size += (MCS_TLV_LEN + BCM_TLV_HDR_SIZE);
+ }
+ }
+ }
+ }
+ }
+ return size;
+}
+
+/* Get the total TLV buffer size for the given ppr data of bandwidth and max chains */
+uint32 ppr_get_tlv_size(ppr_t* pprptr, wl_tx_bw_t bw, uint32 max_chain)
+{
+ uint32 dsss_size = ppr_get_tlv_size_dsss(max_chain);
+ uint32 mcs_ofdm_size = ppr_get_ofdmmcs_size(pprptr, max_chain, bw);
+ uint32 ret = PPR_TLV_VER_SIZE;
+ switch (bw) {
+ case WL_TX_BW_2P5:
+ case WL_TX_BW_5:
+ case WL_TX_BW_10:
+ case WL_TX_BW_20:
+ ret += (dsss_size + mcs_ofdm_size);
+ break;
+ case WL_TX_BW_40:
+ /* 20IN40 and 40 */
+ ret += (dsss_size + 2*mcs_ofdm_size);
+ break;
+ case WL_TX_BW_80:
+ /* 20IN80, 40IN80,80 */
+ ret += (dsss_size + 3*mcs_ofdm_size);
+ break;
+ case WL_TX_BW_160:
+ /* 20IN160, 40IN160, 80IN160, 160 */
+ ret += (dsss_size + 4*mcs_ofdm_size);
+ break;
+ case WL_TX_BW_8080:
+ /* 20IN8080, 40IN8080, 80IN8080, 8080, 8080CHAN2 */
+ ret += (dsss_size + 5*mcs_ofdm_size);
+ break;
+ default:
+ ret = 0;
+ ASSERT(0);
+ break;
+ };
+
+ return ret;
+}
+
+/* Get current PPR TLV version */
+uint32 ppr_get_tlv_ver(void)
+{
+ return PPR_TLV_VER;
+}
+
+#endif /* WL_EXPORT_CURPOWER || !BCMDRIVER */
+
+#ifdef WLTXPWR_CACHE
+
+#define MAX_TXPWR_CACHE_ENTRIES 2
+#define TXPWR_ALL_INVALID 0xff
+#define TXPWR_CACHE_TXPWR_MAX 0x7f /* WLC_TXPWR_MAX; */
+#define TXPWR_CACHE_SARLIMS_MAX ((TXPWR_CACHE_TXPWR_MAX << 24) \
+ | (TXPWR_CACHE_TXPWR_MAX << 16) | (TXPWR_CACHE_TXPWR_MAX << 8) \
+ | TXPWR_CACHE_TXPWR_MAX)
+
+/** transmit power cache */
+struct tx_pwr_cache_entry {
+ chanspec_t chanspec;
+ ppr_t* cache_pwrs[TXPWR_CACHE_NUM_TYPES];
+ uint8 tx_pwr_max[PPR_MAX_TX_CHAINS];
+ uint8 tx_pwr_min[PPR_MAX_TX_CHAINS];
+ int8 txchain_offsets[PPR_MAX_TX_CHAINS];
+ uint8 data_invalid_flags;
+ uint8 stf_tx_max_offset;
+#ifdef WL_SARLIMIT
+ uint32 sar_lims;
+#endif
+ int8 tx_pwr_max_boardlim[PPR_MAX_TX_CHAINS];
+};
+
+#ifdef TXPWR_CACHE_IN_ROM
+uint8 txpwr_cache[MAX_TXPWR_CACHE_ENTRIES*16] = {0};
+#endif
+
+#ifndef WLTXPWR_CACHE_PHY_ONLY
+static int stf_tx_pwr_min = TXPWR_CACHE_TXPWR_MAX;
+#endif
+
+static tx_pwr_cache_entry_t* wlc_phy_txpwr_cache_get_entry(tx_pwr_cache_entry_t* cacheptr,
+ chanspec_t chanspec);
+static tx_pwr_cache_entry_t* wlc_phy_txpwr_cache_get_diff_entry(tx_pwr_cache_entry_t* cacheptr,
+ chanspec_t chanspec);
+static void wlc_phy_txpwr_cache_clear_entry(osl_t *osh, tx_pwr_cache_entry_t* entryptr);
+static tx_pwr_cache_entry_t* tx_pwr_cache_get(tx_pwr_cache_entry_t* cacheptr, uint32 idx);
+
+static tx_pwr_cache_entry_t*
+BCMRAMFN(tx_pwr_cache_get)(tx_pwr_cache_entry_t* tx_pwr_cache, uint32 idx)
+{
+ return (&tx_pwr_cache[idx]);
+}
+
+/** Find a cache entry for the specified chanspec. */
+static tx_pwr_cache_entry_t* wlc_phy_txpwr_cache_get_entry(tx_pwr_cache_entry_t* cacheptr,
+ chanspec_t chanspec)
+{
+ uint i;
+ tx_pwr_cache_entry_t* entryptr = NULL;
+
+ for (i = 0; i < (MAX_TXPWR_CACHE_ENTRIES); i++) {
+ entryptr = tx_pwr_cache_get(cacheptr, i);
+ if (entryptr->chanspec == chanspec) {
+ return entryptr;
+ }
+ }
+ return NULL;
+}
+
+
+/** Find a cache entry that's NOT for the specified chanspec. */
+static tx_pwr_cache_entry_t* wlc_phy_txpwr_cache_get_diff_entry(tx_pwr_cache_entry_t* cacheptr,
+ chanspec_t chanspec)
+{
+ uint i;
+ tx_pwr_cache_entry_t* entryptr = NULL;
+
+ for (i = 0; i < (MAX_TXPWR_CACHE_ENTRIES) && (entryptr == NULL); i++) {
+ if (tx_pwr_cache_get(cacheptr, i)->chanspec != chanspec) {
+ entryptr = tx_pwr_cache_get(cacheptr, i);
+ }
+ }
+ return entryptr;
+}
+
+
+/** Clear a specific cache entry. Delete any ppr_t structs and clear the pointers. */
+static void wlc_phy_txpwr_cache_clear_entry(osl_t *osh, tx_pwr_cache_entry_t* entryptr)
+{
+ uint i;
+
+ entryptr->chanspec = 0;
+
+ ASSERT(entryptr != NULL);
+ for (i = 0; i < TXPWR_CACHE_NUM_TYPES; i++) {
+ if (entryptr->cache_pwrs[i] != NULL) {
+ ppr_delete(osh, entryptr->cache_pwrs[i]);
+ entryptr->cache_pwrs[i] = NULL;
+ }
+ }
+ /*
+ * Don't bother with max, min and txchain_offsets, as they need to be
+ * initialised when the entry is setup for a new chanspec
+ */
+}
+
+
+/**
+ * Get a ppr_t struct of a given type from the cache for the specified chanspec.
+ * Don't return the pointer if the cached data is invalid.
+ */
+bool wlc_phy_get_cached_pwr(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec, uint pwr_type,
+ ppr_t* pprptr)
+{
+ bool ret = FALSE;
+ if (pwr_type < TXPWR_CACHE_NUM_TYPES) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if ((entryptr != NULL) &&
+ ((entryptr->data_invalid_flags & (0x01 << pwr_type)) == 0)) {
+ ppr_copy_struct(entryptr->cache_pwrs[pwr_type], pprptr);
+ ret = TRUE;
+ }
+ }
+
+ return ret;
+}
+
+
+int wlc_phy_set_cached_pwr(osl_t* osh, tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint pwr_type, ppr_t* pwrptr)
+{
+ int result = BCME_NOTFOUND;
+
+ if (pwr_type < TXPWR_CACHE_NUM_TYPES) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL) {
+ ppr_copy_struct(pwrptr, entryptr->cache_pwrs[pwr_type]);
+ entryptr->data_invalid_flags &= ~(0x01 << pwr_type); /* now valid */
+ result = BCME_OK;
+ }
+ }
+ return result;
+}
+
+
+void wlc_phy_txpwr_cache_clear(osl_t* osh, tx_pwr_cache_entry_t* cacheptr,
+ chanspec_t chanspec)
+{
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+ if (entryptr != NULL) {
+ entryptr->chanspec = 0;
+ entryptr->data_invalid_flags = TXPWR_ALL_INVALID;
+ }
+}
+
+
+void wlc_phy_txpwr_cache_close(osl_t* osh, tx_pwr_cache_entry_t* cacheptr)
+{
+ uint i;
+
+ for (i = 0; i < MAX_TXPWR_CACHE_ENTRIES; i++) {
+ tx_pwr_cache_entry_t* entryptr = tx_pwr_cache_get(cacheptr, i);
+ wlc_phy_txpwr_cache_clear_entry(osh, entryptr);
+ }
+ MFREE(osh, cacheptr, (uint)sizeof(*cacheptr) * MAX_TXPWR_CACHE_ENTRIES);
+}
+
+
+tx_pwr_cache_entry_t* wlc_phy_txpwr_cache_create(osl_t* osh)
+{
+ int i, j;
+ tx_pwr_cache_entry_t* cacheptr =
+ (tx_pwr_cache_entry_t*)MALLOC(osh,
+ (uint)sizeof(tx_pwr_cache_entry_t) * MAX_TXPWR_CACHE_ENTRIES);
+ if (cacheptr != NULL) {
+ memset(cacheptr, 0, (uint)sizeof(tx_pwr_cache_entry_t) * MAX_TXPWR_CACHE_ENTRIES);
+ /* Allocate memory for each entry */
+ for (i = 0; i < MAX_TXPWR_CACHE_ENTRIES; i++) {
+ tx_pwr_cache_entry_t* entryptr = tx_pwr_cache_get(cacheptr, i);
+ entryptr->data_invalid_flags = TXPWR_ALL_INVALID;
+ for (j = 0; j < TXPWR_CACHE_NUM_TYPES; j++) {
+ entryptr->cache_pwrs[j] = ppr_create(osh, ppr_get_max_bw());
+ if (!entryptr->cache_pwrs[j]) {
+ wlc_phy_txpwr_cache_close(osh, cacheptr);
+ return NULL;
+ }
+ }
+ }
+ }
+ return cacheptr;
+}
+
+
+/*
+ * Get a ppr_t struct of a given type from the cache for the specified chanspec.
+ * Return the pointer even if the cached data is invalid.
+ */
+ppr_t* wlc_phy_get_cached_ppr_ptr(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint pwr_type)
+{
+ ppr_t* pwrptr = NULL;
+
+ if (pwr_type < TXPWR_CACHE_NUM_TYPES) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL)
+ pwrptr = entryptr->cache_pwrs[pwr_type];
+ }
+
+ return pwrptr;
+}
+
+
+/** Indicate if we have cached a particular ppr_t struct for any chanspec. */
+bool wlc_phy_is_pwr_cached(tx_pwr_cache_entry_t* cacheptr, uint pwr_type, ppr_t* pwrptr)
+{
+ bool result = FALSE;
+ uint i;
+
+ if (pwr_type < TXPWR_CACHE_NUM_TYPES) {
+ for (i = 0; (i < MAX_TXPWR_CACHE_ENTRIES) && (result == FALSE); i++) {
+ if (tx_pwr_cache_get(cacheptr, i)->cache_pwrs[pwr_type] == pwrptr) {
+ result = TRUE;
+ }
+ }
+ }
+ return result;
+}
+
+
+/* Get the maximum boardlim for the specified core and chanspec. */
+int8 wlc_phy_get_cached_boardlim(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec, uint core)
+{
+ uint8 board_lim = WL_RATE_DISABLED;
+
+ if (core < PPR_MAX_TX_CHAINS) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL)
+ board_lim = entryptr->tx_pwr_max_boardlim[core];
+ }
+
+ return board_lim;
+}
+
+
+/* Set the maximum boardlim for the specified core and chanspec. */
+int wlc_phy_set_cached_boardlim(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec, uint core,
+ int8 board_lim)
+{
+ int result = BCME_NOTFOUND;
+
+ if (core < PPR_MAX_TX_CHAINS) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL) {
+ entryptr->tx_pwr_max_boardlim[core] = board_lim;
+ result = BCME_OK;
+ }
+ }
+ return result;
+}
+
+/** Get the maximum power for the specified core and chanspec. */
+uint8 wlc_phy_get_cached_pwr_max(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec, uint core)
+{
+ uint8 max_pwr = WL_RATE_DISABLED;
+
+ if (core < PPR_MAX_TX_CHAINS) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL)
+ max_pwr = entryptr->tx_pwr_max[core];
+ }
+
+ return max_pwr;
+}
+
+
+/** Set the maximum power for the specified core and chanspec. */
+int wlc_phy_set_cached_pwr_max(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec, uint core,
+ uint8 max_pwr)
+{
+ int result = BCME_NOTFOUND;
+
+ if (core < PPR_MAX_TX_CHAINS) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL) {
+ entryptr->tx_pwr_max[core] = max_pwr;
+ result = BCME_OK;
+ }
+ }
+ return result;
+}
+
+
+/** Get the minimum power for the specified core and chanspec. */
+uint8 wlc_phy_get_cached_pwr_min(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec, uint core)
+{
+ uint8 min_pwr = WL_RATE_DISABLED;
+
+ if (core < PPR_MAX_TX_CHAINS) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL)
+ min_pwr = entryptr->tx_pwr_min[core];
+ }
+
+ return min_pwr;
+}
+
+
+/** Set the minimum power for the specified core and chanspec. */
+int wlc_phy_set_cached_pwr_min(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec, uint core,
+ uint8 min_pwr)
+{
+ int result = BCME_NOTFOUND;
+
+ if (core < PPR_MAX_TX_CHAINS) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL) {
+ entryptr->tx_pwr_min[core] = min_pwr;
+ result = BCME_OK;
+ }
+ }
+ return result;
+}
+
+
+/** Get the txchain offsets for the specified chanspec. */
+int8 wlc_phy_get_cached_txchain_offsets(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint core)
+{
+ uint8 offset = WL_RATE_DISABLED;
+
+ if (core < PPR_MAX_TX_CHAINS) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL)
+ offset = entryptr->txchain_offsets[core];
+ }
+
+ return offset;
+}
+
+
+/** Set the txchain offsets for the specified chanspec. */
+int wlc_phy_set_cached_txchain_offsets(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint core, int8 offset)
+{
+ int result = BCME_NOTFOUND;
+
+ if (core < PPR_MAX_TX_CHAINS) {
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL) {
+ entryptr->txchain_offsets[core] = offset;
+ result = BCME_OK;
+ }
+ }
+ return result;
+}
+
+
+/** Indicate if we have a cache entry for the specified chanspec. */
+bool wlc_phy_txpwr_cache_is_cached(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec)
+{
+ bool result = FALSE;
+
+ if (wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec)) {
+ result = TRUE;
+ }
+ return result;
+}
+
+
+/** Find a cache entry that's NOT for the specified chanspec. Return the chanspec. */
+chanspec_t wlc_phy_txpwr_cache_find_other_cached_chanspec(tx_pwr_cache_entry_t* cacheptr,
+ chanspec_t chanspec)
+{
+ chanspec_t chan = 0;
+
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_diff_entry(cacheptr, chanspec);
+ if (entryptr != NULL) {
+ chan = entryptr->chanspec;
+ }
+ return chan;
+}
+
+
+/** Invalidate all cached data. */
+void wlc_phy_txpwr_cache_invalidate(tx_pwr_cache_entry_t* cacheptr)
+{
+ uint j;
+
+ for (j = 0; j < MAX_TXPWR_CACHE_ENTRIES; j++) {
+ tx_pwr_cache_entry_t* entryptr = tx_pwr_cache_get(cacheptr, j);
+ if (entryptr->chanspec != 0) {
+ uint i;
+ entryptr->data_invalid_flags = TXPWR_ALL_INVALID;
+ for (i = 0; i < PPR_MAX_TX_CHAINS; i++) {
+ entryptr->tx_pwr_min[i] = TXPWR_CACHE_TXPWR_MAX;
+ entryptr->tx_pwr_max[i] = WL_RATE_DISABLED;
+ entryptr->txchain_offsets[i] = WL_RATE_DISABLED;
+ }
+ entryptr->stf_tx_max_offset = TXPWR_CACHE_TXPWR_MAX;
+#ifdef WL_SARLIMIT
+ entryptr->sar_lims = TXPWR_CACHE_SARLIMS_MAX;
+#endif
+ }
+ }
+}
+
+
+/** Find an empty cache entry and initialise it. */
+int wlc_phy_txpwr_setup_entry(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec)
+{
+ int result = BCME_NOTFOUND;
+
+ /* find an empty entry */
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, 0);
+ if (entryptr != NULL) {
+ uint i;
+
+ entryptr->chanspec = chanspec;
+ for (i = 0; i < PPR_MAX_TX_CHAINS; i++) {
+ entryptr->tx_pwr_min[i] = TXPWR_CACHE_TXPWR_MAX; /* WLC_TXPWR_MAX; */
+ entryptr->tx_pwr_max[i] = WL_RATE_DISABLED;
+ entryptr->txchain_offsets[i] = WL_RATE_DISABLED;
+ }
+ entryptr->stf_tx_max_offset = TXPWR_CACHE_TXPWR_MAX;
+#ifdef WL_SARLIMIT
+ entryptr->sar_lims = TXPWR_CACHE_SARLIMS_MAX;
+#endif
+ result = BCME_OK;
+ }
+ return result;
+}
+
+#ifdef WL_SARLIMIT
+void wlc_phy_set_cached_sar_lims(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint32 sar_lims)
+{
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL) {
+ entryptr->sar_lims = sar_lims;
+ }
+}
+
+
+uint32 wlc_phy_get_cached_sar_lims(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec)
+{
+ uint32 sar_lims = TXPWR_CACHE_SARLIMS_MAX;
+
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL)
+ sar_lims = entryptr->sar_lims;
+
+ return sar_lims;
+}
+#endif /* WL_SARLIMIT */
+
+
+#ifndef WLTXPWR_CACHE_PHY_ONLY
+
+/** Get the cached minimum Tx power */
+int wlc_phy_get_cached_stf_pwr_min_dbm(tx_pwr_cache_entry_t* cacheptr)
+{
+ return stf_tx_pwr_min;
+}
+
+/** set the cached minimum Tx power */
+void wlc_phy_set_cached_stf_pwr_min_dbm(tx_pwr_cache_entry_t* cacheptr, int min_pwr)
+{
+ stf_tx_pwr_min = min_pwr;
+}
+
+void wlc_phy_set_cached_stf_max_offset(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec,
+ uint8 max_offset)
+{
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL) {
+ entryptr->stf_tx_max_offset = max_offset;
+ }
+}
+
+uint8 wlc_phy_get_cached_stf_max_offset(tx_pwr_cache_entry_t* cacheptr, chanspec_t chanspec)
+{
+ uint8 max_offset = TXPWR_CACHE_TXPWR_MAX;
+
+ tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(cacheptr, chanspec);
+
+ if (entryptr != NULL)
+ max_offset = entryptr->stf_tx_max_offset;
+
+ return max_offset;
+
+}
+#endif /* WLTXPWR_CACHE_PHY_ONLY */
+#endif /* WLTXPWR_CACHE */
diff --git a/wl/src/wl/sys/wlc_rwl.c b/wl/src/wl/sys/wlc_rwl.c
new file mode 100644
index 0000000..d58b82a
--- /dev/null
+++ b/wl/src/wl/sys/wlc_rwl.c
@@ -0,0 +1,524 @@
+/*
+ * RWL module of
+ * Broadcom 802.11bang Networking Device Driver
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlc_rwl.c 619400 2016-02-16 13:52:43Z $*
+ *
+ */
+
+/**
+ * @file
+ * @brief
+ * Remote WL utility support
+ */
+
+
+#include <wlc_cfg.h>
+
+#ifndef WLRWL
+#error "Cannot use this file without WLRWL defined"
+#endif
+
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <wlioctl.h>
+#include <proto/802.11.h>
+#include <d11.h>
+#include <wlc_rate.h>
+#include <wlc_pub.h>
+#include <wlc_bsscfg.h>
+#include <wlc.h>
+#include <wlc_phy_hal.h>
+#include <wl_export.h>
+
+#include <wlc_rwl.h>
+
+enum {
+ IOV_RWLVS_ACTION_FRAME, /* RWL Vendor specific queue */
+ IOV_RWLDONGLE_DATA,
+ IOV_DONGLE_FLAG,
+ IOV_LAST
+};
+
+static const bcm_iovar_t rwl_iovars[] = {
+ {"rwlwifivsaction", IOV_RWLVS_ACTION_FRAME,
+ (0), 0, IOVT_BUFFER, RWL_WIFI_ACTION_FRAME_SIZE
+ },
+#ifdef RWL_DONGLE
+ {"remote", IOV_RWLDONGLE_DATA, 0, 0, IOVT_BUFFER, 1040},
+ {"dongleset", IOV_DONGLE_FLAG, 0, 0, IOVT_UINT32, 0},
+#endif /* RWL_DONGLE */
+ {NULL, 0, 0, 0, 0, 0 }
+};
+
+#ifdef RWL_DONGLE
+int g_rwl_dongle_flag = 0;
+#endif
+
+/* rwl function prototypes */
+
+static int wlc_rwl_doiovar(void *hdl, uint32 actionid,
+ void *params, uint p_len, void *arg, uint len,
+ uint val_size, struct wlc_if *wlcif);
+
+rwl_info_t *
+BCMATTACHFN(wlc_rwl_attach)(wlc_info_t *wlc)
+{
+ rwl_info_t *ri;
+ wlc_pub_t *pub = wlc->pub;
+
+ WL_TRACE(("wl: wlc_rwl_attach\n"));
+
+ if ((ri = (rwl_info_t *)MALLOCZ(pub->osh, sizeof(rwl_info_t))) == NULL) {
+ WL_ERROR(("wlc_rwl_attach: out of memory, malloced %d bytes", MALLOCED(pub->osh)));
+ goto fail;
+ }
+ ri->wlc = (void*) wlc;
+ ri->pub = pub;
+
+ /* register module */
+ if (wlc_module_register(pub, rwl_iovars, "rwl", ri, wlc_rwl_doiovar,
+ NULL, NULL, NULL)) {
+ WL_ERROR(("wl%d: rwl wlc_module_register() failed\n", pub->unit));
+ goto fail;
+ }
+
+ return ri;
+
+fail:
+ if (ri) {
+ MFREE(ri->pub->osh, ri, sizeof(rwl_info_t));
+ }
+ return NULL;
+}
+
+int
+BCMATTACHFN(wlc_rwl_detach)(rwl_info_t *ri)
+{
+ wlc_info_t *wlc;
+ rwl_request_t *cleanup_node = (rwl_request_t *)(NULL);
+
+ WL_TRACE(("wl: %s: ri = %p\n", __FUNCTION__, OSL_OBFUSCATE_BUF(ri)));
+
+ wlc = (wlc_info_t*) ri->wlc;
+ wlc_module_unregister(ri->pub, "rwl", ri);
+
+ /* Clean up the queue only during the driver cleanup */
+ while (ri->rwl_first_action_node != NULL) {
+ cleanup_node = ri->rwl_first_action_node->next_request;
+ MFREE(wlc->osh, ri->rwl_first_action_node,
+ sizeof(rwl_request_t));
+ ri->rwl_first_action_node = cleanup_node;
+ }
+
+ MFREE(ri->pub->osh, ri, sizeof(rwl_info_t));
+
+ return 0;
+}
+
+void
+BCMINITFN(wlc_rwl_init)(rwl_info_t *ri)
+{
+}
+
+void
+BCMUNINITFN(wlc_rwl_deinit)(rwl_info_t *ri)
+{
+}
+
+void
+wlc_rwl_up(wlc_info_t *wlc)
+{
+}
+
+uint
+wlc_rwl_down(wlc_info_t *wlc)
+{
+ return 0;
+}
+
+/* Handling RWL related iovars */
+static int
+wlc_rwl_doiovar(void *hdl, uint32 actionid,
+ void *params, uint p_len, void *arg, uint len, uint val_size, struct wlc_if *wlcif)
+{
+ rwl_info_t *ri = (rwl_info_t *)hdl;
+ int err = 0;
+ int32 int_val;
+
+ if (p_len >= (int)sizeof(int_val))
+ bcopy(params, &int_val, sizeof(int_val));
+
+ switch (actionid) {
+ case IOV_GVAL(IOV_RWLVS_ACTION_FRAME):
+ {
+ dot11_action_wifi_vendor_specific_t *list;
+ rwl_request_t *intermediate_node;
+ list = (dot11_action_wifi_vendor_specific_t*)arg;
+ if (ri->rwl_first_action_node != NULL) {
+ /* pop from the list and copy to user buffer
+ * and move the node to next node
+ */
+ bcopy((char*)&ri->rwl_first_action_node->action_frame,
+ (char*)list, RWL_WIFI_ACTION_FRAME_SIZE);
+ intermediate_node = ri->rwl_first_action_node->next_request;
+ MFREE(ri->wlc->osh, ri->rwl_first_action_node,
+ sizeof(rwl_request_t));
+ ri->rwl_first_action_node = intermediate_node;
+ }
+ break;
+ }
+
+#ifdef RWL_DONGLE
+ case IOV_GVAL(IOV_RWLDONGLE_DATA):
+ /* Wait for serial protocol layer to set the packet_status bit
+ * if bit set then copy the data in arg
+ * reset the packet_status bit
+ * if not set send 0 to server application
+ */
+ if (g_rwl_dongle_data.packet_status) {
+ if (g_rwl_dongle_data.packet_buf != NULL) {
+ bcopy(g_rwl_dongle_data.packet_buf, (char*)arg,
+ g_rwl_dongle_data.packet_len);
+ MFREE(NULL, g_rwl_dongle_data.packet_buf,
+ g_rwl_dongle_data.packet_len);
+ }
+ g_rwl_dongle_data.packet_status = 0;
+ } else {
+ uint status = 0;
+ bcopy(&status, arg, sizeof(status));
+ }
+ break;
+ case IOV_SVAL(IOV_RWLDONGLE_DATA):
+ /* Transmit the server response to client
+ * Code jumps to hnd_cons.c at this point
+ */
+ remote_uart_tx(arg);
+ break;
+ case IOV_GVAL(IOV_DONGLE_FLAG):
+ {
+ *ret_int_ptr = g_rwl_dongle_flag;
+ break;
+ }
+ case IOV_SVAL(IOV_DONGLE_FLAG):
+ {
+ g_rwl_dongle_flag = int_val;
+ break;
+ }
+#endif /* RWL_DONGLE */
+
+ default:
+ err = BCME_UNSUPPORTED;
+ break;
+ }
+
+ return err;
+}
+
+#ifdef WIFI_REFLECTOR
+/* Allocate and initialize an wifi action frame */
+static dot11_action_wifi_vendor_specific_t *
+allocate_action_frame(wlc_info_t *wlc)
+{
+ dot11_action_wifi_vendor_specific_t *frame;
+
+ if ((frame = (dot11_action_wifi_vendor_specific_t *)
+ MALLOC(wlc->osh, RWL_WIFI_ACTION_FRAME_SIZE)) == NULL)
+ return NULL;
+
+ frame->category = DOT11_ACTION_CAT_VS;
+ frame->OUI[0] = RWL_WIFI_OUI_BYTE0;
+ frame->OUI[1] = RWL_WIFI_OUI_BYTE1;
+ frame->OUI[2] = RWL_WIFI_OUI_BYTE2;
+ frame->type = RWL_WIFI_DEFAULT_TYPE;
+ frame->subtype = RWL_WIFI_DEFAULT_SUBTYPE;
+
+ return frame;
+}
+
+/* Send out the action frame */
+static int
+rwl_send_wifi_response(wlc_info_t *wlc,
+ dot11_action_wifi_vendor_specific_t *response,
+ const struct ether_addr * dest_addr_ptr)
+{
+ uint32 err = 0;
+
+#ifdef WIFI_ACT_FRAME
+ wl_action_frame_t *action_frame;
+
+ if ((action_frame = (wl_action_frame_t *)
+ MALLOC(wlc->osh, sizeof(wl_action_frame_t))) == NULL)
+ return BCME_NOMEM;
+
+ memcpy(&action_frame->data, response, RWL_WIFI_ACTION_FRAME_SIZE);
+
+ /* Set the dest addr */
+ memcpy(&action_frame->da, dest_addr_ptr, ETHER_ADDR_LEN);
+
+ /* set the length */
+ action_frame->len = RWL_WIFI_ACTION_FRAME_SIZE;
+
+ wlc_send_action_frame(wlc, wlc->cfg, NULL, (void *)action_frame);
+
+ MFREE(wlc->osh, action_frame, sizeof(wl_action_frame_t));
+#endif /* WIFI_ACT_FRAME */
+
+ return err;
+}
+
+/* Function to specify the client that an invalid wl command has been received
+ * This command cannot be processed by the In-dongle reflector.
+ */
+static int
+rwl_wifi_send_error(wlc_info_t *wlc, const struct ether_addr * dest_addr_ptr)
+{
+ int err;
+ dot11_action_wifi_vendor_specific_t *response;
+ rem_ioctl_t rem_cdc, *rem_ptr = &rem_cdc;
+ const char *errmsg = "In-dongle does not support shell/DHD/ASD\n";
+
+ if ((response = allocate_action_frame(wlc)) == NULL)
+ return BCME_NOMEM;
+
+ rem_ptr->msg.cmd = -1;
+ rem_ptr->msg.len = rem_ptr->data_len = strlen(errmsg) + 1;
+ rem_ptr->msg.flags = REMOTE_REPLY;
+
+ memcpy(&response->data[RWL_WIFI_CDC_HEADER_OFFSET], rem_ptr, REMOTE_SIZE);
+ memcpy(&response->data[REMOTE_SIZE], errmsg, rem_ptr->data_len);
+
+ err = rwl_send_wifi_response(wlc, response, dest_addr_ptr);
+
+ MFREE(wlc->osh, response, sizeof(dot11_action_wifi_vendor_specific_t));
+
+ return err;
+}
+
+/* Function which responds to the findserver command when sent by the client
+ * application. The client sends out packet in every channel available.
+ * we recieve the packet on a particular channel we respond back by sending
+ * our channel number
+ */
+static int
+rwl_wifi_findserver_response(wlc_info_t *wlc,
+ dot11_action_wifi_vendor_specific_t *response,
+ const struct ether_addr * dest_addr_ptr)
+{
+ int err;
+ channel_info_t ci;
+ uint32 tx_count;
+
+ /* Query the server channel */
+ response->type = RWL_WIFI_FOUND_PEER;
+
+ err = wlc_ioctl(wlc, WLC_GET_CHANNEL, &ci, sizeof(ci), NULL);
+ if (err)
+ return err;
+
+ /* Match the client channel with our channel */
+ if (response->data[RWL_WIFI_CLIENT_CHANNEL_OFFSET] == ci.hw_channel) {
+ response->data[RWL_WIFI_SERVER_CHANNEL_OFFSET] = ci.hw_channel;
+ for (tx_count = 0; tx_count < RWL_WIFI_SEND; ++tx_count) {
+ err = rwl_send_wifi_response(wlc, response, dest_addr_ptr);
+ if (err)
+ break;
+ }
+ }
+
+ return err;
+}
+
+/* Function which responds to the set command sent by the client.
+ * We call wlc_ioctl to set the specified value and send back the
+ * results of setting to the client
+ */
+static int
+rwl_wifi_set_cmd_response(wlc_info_t *wlc,
+ rem_packet_t *rem_packet_ptr,
+ const struct ether_addr * dest_addr_ptr)
+{
+ int err;
+ rem_ioctl_t rem_cdc, *rem_ptr = &rem_cdc;
+ rem_ioctl_t *rem_ioctl_ptr = (rem_ioctl_t *)&(rem_packet_ptr->rem_cdc);
+
+ dot11_action_wifi_vendor_specific_t *rem_wifi_send = allocate_action_frame(wlc);
+
+ if (rem_wifi_send == NULL)
+ return BCME_NOMEM;
+
+ /* Execute the command locally */
+
+ err = wlc_ioctl(wlc, rem_ioctl_ptr->msg.cmd, rem_packet_ptr->message,
+ rem_ioctl_ptr->msg.len, NULL);
+
+ rem_ptr->msg.cmd = err;
+ rem_ptr->msg.len = 0;
+ rem_ptr->msg.flags = REMOTE_REPLY;
+ rem_ptr->data_len = 0;
+
+ memcpy(&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET], rem_ptr, REMOTE_SIZE);
+
+ err = rwl_send_wifi_response(wlc, rem_wifi_send, dest_addr_ptr);
+
+ MFREE(wlc->osh, rem_wifi_send, sizeof(*rem_wifi_send));
+
+ return err;
+}
+
+/* This function responds to the remote wl get command.
+ * On reception of packet we call wlc_ioctl() to get the results.
+ * If the result fits into a single packet we send it directly
+ * else we fragment the results and send it though multiple packets
+ */
+static int
+rwl_wifi_get_cmd_response(wlc_info_t *wlc,
+ rem_packet_t *rem_packet_ptr,
+ const struct ether_addr * dest_addr_ptr)
+{
+ int err;
+ uint32 tx_count;
+ uint32 totalframes;
+ uchar *buf;
+ rem_ioctl_t rem_cdc, *rem_ptr = &rem_cdc;
+ rem_ioctl_t *rem_ioctl_ptr = (rem_ioctl_t *)&(rem_packet_ptr->rem_cdc);
+ dot11_action_wifi_vendor_specific_t *rem_wifi_send = allocate_action_frame(wlc);
+
+ if (rem_wifi_send == NULL)
+ return BCME_NOMEM;
+
+ if ((buf = MALLOC(wlc->osh, rem_ioctl_ptr->msg.len)) == NULL) {
+ MFREE(wlc->osh, rem_wifi_send, sizeof(*rem_wifi_send));
+ return BCME_NOMEM;
+ }
+
+ /* Execute the command locally */
+ memcpy(buf, rem_packet_ptr->message, rem_ioctl_ptr->data_len);
+ err = wlc_ioctl(wlc, rem_ioctl_ptr->msg.cmd, (void*)buf,
+ rem_ioctl_ptr->msg.len, NULL);
+
+ rem_ptr->msg.cmd = err;
+ rem_ptr->msg.len = rem_ioctl_ptr->msg.len;
+ rem_ptr->msg.flags = REMOTE_REPLY;
+ rem_ptr->data_len = rem_ioctl_ptr->msg.len;
+
+ if (rem_ioctl_ptr->msg.len > RWL_WIFI_FRAG_DATA_SIZE) {
+ totalframes = rem_ptr->msg.len / RWL_WIFI_FRAG_DATA_SIZE;
+ memcpy(&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET], rem_ptr, REMOTE_SIZE);
+ memcpy((char*)&rem_wifi_send->data[REMOTE_SIZE], &buf[0], RWL_WIFI_FRAG_DATA_SIZE);
+ rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE;
+ rem_wifi_send->subtype = RWL_WIFI_DEFAULT_SUBTYPE;
+
+ if ((err = rwl_send_wifi_response (wlc, rem_wifi_send, dest_addr_ptr)) != 0)
+ goto exit;
+
+ /* Send remaining bytes in fragments */
+ for (tx_count = 1; tx_count < totalframes; tx_count++) {
+ rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE;
+ rem_wifi_send->subtype = tx_count;
+ /* First frame onwards , buf contains only data */
+ memcpy((char*)&rem_wifi_send->data,
+ &buf[tx_count*RWL_WIFI_FRAG_DATA_SIZE], RWL_WIFI_FRAG_DATA_SIZE);
+ if ((err = rwl_send_wifi_response (wlc,
+ rem_wifi_send,
+ dest_addr_ptr)) != 0) {
+ goto exit;
+ }
+
+ }
+ /* Check for remaining bytes to send */
+ if ((totalframes * RWL_WIFI_FRAG_DATA_SIZE) != rem_ptr->msg.len) {
+ rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE;
+ rem_wifi_send->subtype = tx_count;
+ memcpy((char*)&rem_wifi_send->data,
+ &buf[tx_count*RWL_WIFI_FRAG_DATA_SIZE],
+ (rem_ptr->msg.len - (tx_count*RWL_WIFI_FRAG_DATA_SIZE)));
+ err = rwl_send_wifi_response(wlc, rem_wifi_send, dest_addr_ptr);
+ }
+ } else {
+ /* Packet fits into a single frame; send it off at one go */
+ memcpy(&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET], rem_ptr, REMOTE_SIZE);
+ memcpy((char*)&rem_wifi_send->data[REMOTE_SIZE],
+ buf, rem_ioctl_ptr->msg.len);
+
+ err = rwl_send_wifi_response(wlc, rem_wifi_send, dest_addr_ptr);
+ }
+exit:
+ MFREE(wlc->osh, rem_wifi_send,
+ sizeof(dot11_action_wifi_vendor_specific_t));
+
+ MFREE(wlc->osh, buf, rem_ioctl_ptr->msg.len);
+
+ return err;
+}
+#endif /* WIFI_REFLECTOR */
+
+/* If the management frame is an RWL action frame then the action frame will be queued.
+ * This queued frame will be read by the application.
+ */
+void
+wlc_recv_wifi_mgmtact(rwl_info_t *rwlh, uint8 *body, const struct ether_addr *sa)
+{
+
+#ifdef WIFI_REFLECTOR
+ rem_packet_t *rem_packet_ptr;
+ rem_ioctl_t *rem_ioctl_ptr;
+#endif
+ rwl_request_t *rwl_new_action_node =
+ (rwl_request_t *)(NULL);
+ wlc_info_t *wlc = (wlc_info_t*) rwlh->wlc;
+
+ if ((rwl_new_action_node = (rwl_request_t*)MALLOC(wlc->osh,
+ sizeof(rwl_request_t))) == NULL) {
+ return;
+ }
+
+ bcopy((char*)body, (char*)&rwl_new_action_node->action_frame, RWL_WIFI_ACTION_FRAME_SIZE);
+#ifdef WIFI_REFLECTOR
+ rem_packet_ptr = (rem_packet_t *)&(rwl_new_action_node->action_frame.data[0]);
+ rem_ioctl_ptr = (rem_ioctl_t *)&(rem_packet_ptr->rem_cdc);
+
+ /* Do not queue the packets if it is an RWL command.
+ * Just parse, process and send back the results depending
+ * upon the query packet. Do not queue any packets, as
+ * after a certain number of packets the dongle memory would
+ * be exhausted.
+ */
+ if (rem_ioctl_ptr->msg.flags & REMOTE_FINDSERVER_CMD)
+ rwl_wifi_findserver_response(wlc, &rwl_new_action_node->action_frame, sa);
+ else if (rem_ioctl_ptr->msg.flags & REMOTE_SET_CMD)
+ rwl_wifi_set_cmd_response(wlc, rem_packet_ptr, sa);
+ else if (rem_ioctl_ptr->msg.flags & REMOTE_GET_CMD)
+ rwl_wifi_get_cmd_response(wlc, rem_packet_ptr, sa);
+ else
+ rwl_wifi_send_error(wlc, sa);
+
+ MFREE(wlc->osh, rwl_new_action_node, sizeof(rwl_request_t));
+ return;
+
+#endif /* WIFI_REFLECTOR */
+ if (rwlh->rwl_first_action_node == NULL) {
+ rwlh->rwl_first_action_node = rwl_new_action_node;
+ rwlh->rwl_last_action_node = rwlh->rwl_first_action_node;
+ rwlh->rwl_first_action_node->next_request = NULL;
+ } else {
+ /* insert the all incoming frame at the end of the queue */
+ rwlh->rwl_last_action_node->next_request = rwl_new_action_node;
+ rwlh->rwl_last_action_node = rwl_new_action_node;
+ rwlh->rwl_last_action_node->next_request = NULL;
+ }
+}
diff --git a/wl/src/wl/sys/wlc_rwl.h b/wl/src/wl/sys/wlc_rwl.h
new file mode 100644
index 0000000..279278c
--- /dev/null
+++ b/wl/src/wl/sys/wlc_rwl.h
@@ -0,0 +1,64 @@
+/*
+ * RWL module of
+ * Broadcom 802.11bang Networking Device Driver
+ *
+ * Broadcom Proprietary and Confidential. Copyright (C) 2017,
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of Broadcom.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary:>>
+ *
+ * $Id: wlc_rwl.h 524641 2015-01-07 15:25:03Z $
+ *
+ */
+
+
+#ifndef _wlc_rwl_h_
+#define _wlc_rwl_h_
+
+#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR)
+
+#include <rwl_wifi.h>
+
+typedef struct rwl_info {
+ wlc_info_t *wlc;
+ wlc_pub_t *pub;
+ rwl_request_t *rwl_first_action_node;
+ rwl_request_t *rwl_last_action_node;
+ struct ether_addr rwl_ea;
+} rwl_info_t;
+
+extern rwl_info_t* wlc_rwl_attach(wlc_info_t *wlc);
+extern int wlc_rwl_detach(rwl_info_t *rwlh);
+extern void wlc_rwl_init(rwl_info_t *rwlh);
+extern void wlc_rwl_deinit(rwl_info_t *rwlh);
+extern void wlc_rwl_up(wlc_info_t *wlc);
+extern uint wlc_rwl_down(wlc_info_t *wlc);
+extern void wlc_rwl_frameaction(rwl_info_t *rwlh, struct dot11_management_header *hdr,
+ uint8 *body, int body_len);
+extern void wlc_recv_wifi_mgmtact(rwl_info_t *rwlh, uint8 *body, const struct ether_addr * sa);
+
+#else /* !defined(RWL_WIFI) && !defined(WIFI_REFLECTOR) && !defined(WLTEST) */
+
+typedef struct rwl_info {
+ wlc_info_t *wlc;
+ wlc_pub_t *pub;
+} rwl_info_t;
+
+#define wlc_rwl_attach(a) (rwl_info_t *)0xdeadbeef
+#define wlc_rwl_detach(a) 0
+#define wlc_rwl_init(a) do {} while (0)
+#define wlc_rwl_deinit(a) do {} while (0)
+#define wlc_rwl_up(a) do {} while (0)
+#define wlc_rwl_down(a) 0
+#define wlc_rwl_frameaction(a) do {} while (0)
+#define wlc_recv_wifi_mgmtact(a, b, c) do {} while (0)
+
+#endif
+
+#endif /* _wlc_rwl_h_ */