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_ */