blob: ac78088d8326c0e9023d0ca344772057fd6e8744 [file] [log] [blame]
/*
* wlu capext procesing. Shared between DHD and WLU tool.
*
* Copyright (C) 2023, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
*
* <<Broadcom-WL-IPTag/Dual:>>
*/
#include <typedefs.h>
#include <bcmdefs.h>
#if defined(CONFIG_BCMDHD) && defined(__linux__)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0))
#include <linux/stdarg.h>
#else
#include <stdarg.h>
#endif /* LINUX_VERSION_CODE */
#else
#include <stdarg.h>
#endif /* CONFIG_BCMDHD && __linux__ */
#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 <bcmutils.h>
#include <bcmendian.h>
#include <bcmtlv.h>
#include <wlioctl.h>
#include <bcmstdlib_s.h>
#include <bcmcapext.h>
#define CAPEXT_SUBFEATURE_MAP(bitpos, str) { bitpos, str }
#ifdef BCMDONGLEHOST
#define CAPEXT_CAPS_NUM_MAX (224u)
#else
#define CAPEXT_CAPS_NUM_MAX (1024u)
#endif
typedef struct capext_output_buffer_ctx_s {
const char *cap_strs[CAPEXT_CAPS_NUM_MAX];
uint16 num_items_populated;
uint16 type;
uint16 num_strings;
uint16 last_cap_bit_pos;
uint8 more_caps;
} capext_output_buffer_ctx_t;
typedef struct capext_bitpos_to_string_map {
uint16 bitpos;
const char *str;
} capext_bitpos_to_string_map_t;
typedef struct fw_feature_xtlv_parser_map {
uint16 type;
const capext_bitpos_to_string_map_t *bitpos_to_str_map;
uint16 num_strings;
} capext_fw_feature_xtlv_parser_map_t;
typedef struct capext_partition_init_info_s {
uint16 base;
uint16 max_feature_id;
const capext_fw_feature_xtlv_parser_map_t *parser;
} capext_partition_init_info_t;
static int capext_get_caps(void *ctx, const capext_fw_feature_xtlv_parser_map_t *map,
const uint8 *buf, uint16 len);
static int capext_parse_xtlvs(void *ctx, const uint8 *buf, uint16 type, uint16 len);
/* Generic XTLV parsing function */
static int capext_generic_xtlv_cbfn(void *ctx, const uint8 *buf, uint16 type, uint16 len);
#ifndef BCMDONGLEHOST
static int capext_str_comparator(const void *p1, const void *p2);
#endif
static int capext_print_caps(capext_output_buffer_ctx_t *ctx, char *outbuf, uint16 outbuflen);
static const capext_fw_feature_xtlv_parser_map_t *capext_get_xtlv_parser_map(uint16 type);
/* Bus features partition */
/* Bus features bit positions to string mapping.
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_bus_features_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(CAPEXT_BUS_FEATURE_BITPOS_HP2P, "hp2p"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_BUS_FEATURE_BITPOS_PTM, "ptm"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_BUS_FEATURE_BITPOS_PKTLAT, "pktlatency"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_BUS_FEATURE_BITPOS_BUSTPUT, "bustput"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_BUS_FEATURE_BITPOS_MAX, NULL)
};
/* Packet latency subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_pktlat_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(CAPEXT_PKTLAT_BITPOS_IPC, "pktlat_ipc"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_PKTLAT_BITPOS_META, "pktlat_meta"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_PKTLAT_BITPOS_MAX, NULL)
};
/* RTE features partition */
/* RTE features bit positions to string mapping.
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_rte_features_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_CST, "cst"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_ECOUNTERS, "ecounters"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_ETD, "etd_info"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_EVENT_LOG, "event_log"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_H2D_LOG_TIME_SYNC, "h2dlogts"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_HCHK, "hchk"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_HWRNG, "hwrng"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_LOGTRACE, "logtrace"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_SMD, "smd"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_SPMI, "spmi"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_RTE_FEATURE_BITPOS_MAX, NULL)
};
/* ecounters subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_ecounters_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(CAPEXT_ECOUNTERS_BITPOS_ADV, "adv_ecounters"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_ECOUNTERS_BITPOS_CHSTATS, "chstats"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_ECOUNTERS_BITPOS_PHY_CAL, "phy_cal_ecounter"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_ECOUNTERS_BITPOS_PHY, "phy_ecounter"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_ECOUNTERS_BITPOS_PEERSTATS, "peerstats"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_ECOUNTERS_BITPOS_TXHIST, "txhist"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_ECOUNTERS_BITPOS_DTIM_MISS, "dtim_miss"),
CAPEXT_SUBFEATURE_MAP(CAPEXT_ECOUNTERS_BITPOS_MAX, NULL)
};
/* WL features partition */
/* AMPDU subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_ampdu_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AMPDU_BITPOS_RX, "ampdu_rx"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AMPDU_BITPOS_TX, "ampdu_tx"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AMPDU_BITPOS_MAX, NULL)
};
/* AMSDU subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_amsdu_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AMSDU_BITPOS_DYNLEN, "amsdudynlen"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AMSDU_BITPOS_RX, "amsdurx"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AMSDU_BITPOS_TX, "amsdutx"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AMSDU_BITPOS_MAX, NULL)
};
/* AP subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_ap_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AP_BITPOS_AX_5G_ONLY, "5g_he_ap"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AP_BITPOS_NONAX, "non_he_ap"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AP_BITPOS_SAE, "sae-ap"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AP_BITPOS_BCNPROT_AP, "bcnprot-ap"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_AP_BITPOS_MAX, NULL)
};
/* COEX subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_coex_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_COEX_BITPOS_BTC_WIFI_PROT, "btc_wifi_prot"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_COEX_BITPOS_LTE, "ltecx"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_COEX_BITPOS_LTECX_LBT, "ltecxlbt"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_COEX_BITPOS_RC1, "rc1cx"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_COEX_BITPOS_SIB, "sib"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_COEX_BITPOS_MAX, NULL)
};
/* EHT subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_eht_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_EHT_BITPOS_320MHZ, "320"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_EHT_BITPOS_MLO, "mlo"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_EHT_BITPOS_MAX, NULL)
};
/* FBT subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_fbt_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FBT_BITPOS_ADPT, "fbt_adpt"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FBT_BITPOS_OVERDS, "fbtoverds"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FBT_BITPOS_MAX, NULL)
};
/* FW features bit positions to string mapping.
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_wl_features_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_11AZ, "11az"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_160MHZ_SUPPORT, "160"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_6G, "6g"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_802_11d, "802.11d"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_802_11h, "802.11h"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_AMPDU, "ampdu"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_AMSDU, "amsdu"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_ANQPO, "anqpo"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_AP, "ap"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_APF, "apf"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_ARB, "arb"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_ARPOE, "arpoe"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_AVOID_BSSID, "avoid-bssid"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_BCMDCS, "bcmdcs"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_BCNPROT, "bcnprot"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_BCNTRIM, "bcntrim"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_BDO, "bdo"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_BGDFS, "bgdfs"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_BKOFF_EVT, "bkoff_evt"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_BSSTRANS, "bsstrans"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_CAC, "cac"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_CDEF, "cdef"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_CLM_RESTRICT, "clm_restrict"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_COEX, "coex"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_CQA, "cqa"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_CSI, "csi"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_CSO, "cso"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_D11STATUS, "d11status"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_D3CBUF, "d3cbuf"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_DFRTS, "dfrts"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_DSA, "dsa"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_DTPC, "dtpc"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_DUALBAND, "dualband"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_DWDS, "dwds"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_DYN_BW, "dynbw"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_EHT, "eht"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_ESTM, "estm"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_EVT_EXT, "evt_ext"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_EXTSAE, "extsae"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_FBT, "fbt"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_FIE, "fie"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_EPNO, "epno"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_GCMP, "gcmp"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_HE, "he"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_HOST_SFHLLC, "host_sfhllc"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_ICMP, "icmp"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_IDAUTH, "idauth"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_IDSUP, "idsup"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_IFST, "ifst"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_IFVER, "ifver"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_IGMPOE, "igmpoe"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_IOT_BD, "iot_bd"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_IOT_BM, "iot_bm"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_LPAS, "lpas"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_LPC, "lpc"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_LPR_SCAN, "lpr_scan"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MBO, "mbo"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MBO_MIN, "mbomin"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MBSS, "mbss"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MFP, "mfp"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MCHAN, "mchan"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MIMO_PS, "mimo_ps"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MONITOR, "monitor"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MP2P, "mp2p"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MU_BEAMFORMEE, "multi-user-beamformee"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MU_BEAMFORMER, "multi-user-beanformer"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_NAN, "nan"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_NAP, "nap"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_NATOE, "natoe"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_NDOE, "ndoe"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_OBSS_HW, "obss_hw"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_OCL, "ocl"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_OCT, "oct"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_OPS, "ops"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_OWE, "owe"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_P2P, "p2p"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_P2P0, "p2po"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PASN, "pasn"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PFNX, "pfnx"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PKT_FILTER, "pkt_filter"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PMR, "pmr"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PPR, "ppr"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PRBRESP_MAC_FLTR,
"probresp_mac_filter"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PROP_TXSTATUS, "proptxstatus"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PROXD, "proxd"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PRUNE_WPA, "prune_wpa"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PS_PRETEND, "pspretend"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_PSBW, "psbw"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_QOS_MGMT, "qos_mgmt"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_RM, "rm"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_RSDB, "rsdb"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_TDLS, "tdls"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_TDMTX, "tdmtx"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_TKO, "tko"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_TOE, "toe"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_TSYNC, "tsync"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_TVPM, "tvpm"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_TX_PROF, "tx-prof"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_TXPWRCAP, "txcap"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_TXPWRCACHE, "txpwrcache"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_RADIO_PWRSAVE, "radio_pwrsave"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_RCO, "rco"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_ROAMSTATS, "roamstats"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_RSSI_MON, "rssi_mon"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_RXCHAIN_PWRSAVE, "rxchain_pwrsave"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SAE, "sae"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SAE_H2E, "sae_h2e"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SAE_PK, "sae_pk"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SC, "sc"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SCANCACHE, "scancache"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SCANMAC, "scanmac"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SCCA, "scca"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SCR, "scr"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SU_BEAMFORMEE,
"single-user-beamformee"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SU_BEAMFORMER,
"single-user-beamformer"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_STA, "sta"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_STBC, "stbc"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_UCM, "ucm"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_VE, "ve"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_VHT_PROP_RATES, "vht-prop-rates"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_WDS, "wds"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_WME, "wme"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_WMF, "wmf"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_WNM, "wnm"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_OCV, "ocv"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_OCV_AP, "ocv_ap"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SAE_EXT, "sae_ext"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_SC_6G_HE, "sc_6g_he"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_FEATURE_BITPOS_MAX, NULL)
};
/* MBSS subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_mbss_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_MBSS_BITPOS_UCODE_BSS_0, "mbss-0"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_MBSS_BITPOS_UCODE_BSS_1, "mbss-1"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_MBSS_BITPOS_UCODE_BSS_2, "mbss-2"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_MBSS_BITPOS_MAX, NULL)
};
/* NAN subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_nan_subfeature_map[] = {
#ifdef NAN_DAM_ANDROID
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_NAN_BITPOS_AUTODAM, "autodam"),
#endif
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_NAN_BITPOS_MESH, "meshnan"),
#ifdef NAN_DAM_ANDROID
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_NAN_BITPOS_P2P, "nanp2p"),
#endif
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_NAN_BITPOS_RANGE, "nanrange"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_NAN_BITPOS_MAX, NULL)
};
/* Packet filter subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_pkt_filter_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_PKT_FILTER_BITPOS_PKT_FILTER6, "pf6"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_PKT_FILTER_BITPOS_PKT_FILTER2, "pktfltr2"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_PKT_FILTER_BITPOS_MAX, NULL)
};
/* PPR subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_ppr_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_PPR_BITPOS_TLV_VER_1, "cptlv-1"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_PPR_BITPOS_TLV_VER_2, "cptlv-2"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_PPR_BITPOS_TLV_VER_3, "cptlv-3"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_PPR_BITPOS_TLV_VER_4, "cptlv-4"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_PPR_BITPOS_MAX, NULL)
};
/* STBC subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_stbc_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_STBC_BITPOS_RX_1SS, "stbc-rx-1ss"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_STBC_BITPOS_TX, "stbc-tx"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_STBC_BITPOS_MAX, NULL)
};
/* TX power cap subfeatures bit positions to string mapping
* Insert new entries in the array below in sorted order of output string to be printed
*/
static const capext_bitpos_to_string_map_t capext_txpwrcap_subfeature_map[] = {
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_TXPWRCAP_BITPOS_TXPWRCAP_1, "txcap1"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_TXPWRCAP_BITPOS_TXPWRCAP_2, "txcap2"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_TXPWRCAP_BITPOS_TXPWRCAP_3, "txcap3"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_TXPWRCAP_BITPOS_TXPWRCAP_4, "txcap4"),
CAPEXT_SUBFEATURE_MAP(WLC_CAPEXT_TXPWRCAP_BITPOS_MAX, NULL)
};
/* Bus partition: Info about parsing BUS XTLV caps */
static const capext_fw_feature_xtlv_parser_map_t capext_bus_feature_xtlv_parser_map[] = {
{ CAPEXT_BUS_FEATURE_RSVD, NULL, 0},
{ CAPEXT_BUS_FEATURE_BUS_FEATURES, capext_bus_features_subfeature_map,
CAPEXT_BUS_FEATURE_BITPOS_MAX},
{ CAPEXT_BUS_FEATURE_PKTLAT, capext_pktlat_subfeature_map, CAPEXT_PKTLAT_BITPOS_MAX},
{ CAPEXT_BUS_FEATURE_MAX, NULL, 0}
};
/* Rte partition: Info about parsing RTE XTLV caps */
static const capext_fw_feature_xtlv_parser_map_t capext_rte_feature_xtlv_parser_map[] = {
{ CAPEXT_RTE_FEATURE_RSVD, NULL, 0},
{ CAPEXT_RTE_FEATURE_RTE_FEATURES, capext_rte_features_subfeature_map,
CAPEXT_RTE_FEATURE_BITPOS_MAX},
{ CAPEXT_RTE_FEATURE_ECOUNTERS, capext_ecounters_subfeature_map,
CAPEXT_ECOUNTERS_BITPOS_MAX},
{ CAPEXT_RTE_FEATURE_MAX, NULL, 0}
};
/* WL partition: Info about parsing WL XTLV caps */
static const capext_fw_feature_xtlv_parser_map_t capext_wl_feature_xtlv_parser_map[] = {
{ CAPEXT_WL_FEATURE_RSVD, NULL, 0},
{ CAPEXT_WL_FEATURE_WL_FEATURES, capext_wl_features_subfeature_map,
WLC_CAPEXT_FEATURE_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_AMPDU, capext_ampdu_subfeature_map, WLC_CAPEXT_AMPDU_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_AMSDU, capext_amsdu_subfeature_map, WLC_CAPEXT_AMSDU_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_STBC, capext_stbc_subfeature_map, WLC_CAPEXT_STBC_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_NAN, capext_nan_subfeature_map, WLC_CAPEXT_NAN_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_COEX, capext_coex_subfeature_map, WLC_CAPEXT_COEX_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_FBT, capext_fbt_subfeature_map, WLC_CAPEXT_FBT_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_MBSS, capext_mbss_subfeature_map, WLC_CAPEXT_MBSS_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_TXPWRCAP, capext_txpwrcap_subfeature_map,
WLC_CAPEXT_TXPWRCAP_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_PPR, capext_ppr_subfeature_map, WLC_CAPEXT_PPR_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_PKT_FILTER, capext_pkt_filter_subfeature_map,
WLC_CAPEXT_PKT_FILTER_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_EHT, capext_eht_subfeature_map, WLC_CAPEXT_EHT_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_AP, capext_ap_subfeature_map, WLC_CAPEXT_AP_BITPOS_MAX},
{ CAPEXT_WL_FEATURE_MAX, NULL, 0}
};
/* Partition info for parsing various XTLV types */
static const capext_partition_init_info_t cat_init_info[CAPEXT_FEATURE_ID_NUM_PARTITIONS] = {
{ CAPEXT_BUS_FEATURE_ID_BASE, CAPEXT_BUS_FEATURE_MAX, capext_bus_feature_xtlv_parser_map },
{ CAPEXT_RTE_FEATURE_ID_BASE, CAPEXT_RTE_FEATURE_MAX, capext_rte_feature_xtlv_parser_map},
{ CAPEXT_WL_FEATURE_ID_BASE, CAPEXT_WL_FEATURE_MAX, capext_wl_feature_xtlv_parser_map},
};
#ifndef BCMDONGLEHOST
/* Sort comparator routine */
static int
capext_str_comparator(const void *p1, const void *p2)
{
/* From man qsort: The actual arguments to this function are "pointers to
* pointers to char", but strcmp arguments are "pointers
* to char", hence the following cast plus dereference
*/
return strcmp(* (const char **) p1, * (const char **) p2);
}
#endif /* BCMDONGLEHOST */
/* Invoke a chain of function calls to parse output of dngl:capext iovar */
int
bcmcapext_parse_output(void *bufptr, uint16 maxlen, char *outbuf, uint16 outbuflen)
{
capext_info_t *capext;
capext_output_buffer_ctx_t ctx;
uint16 payload_len;
int rc;
capext = (capext_info_t *)bufptr;
if (bufptr == NULL || outbuf == NULL || maxlen > WLC_IOCTL_MAXLEN ||
outbuflen == 0 || outbuflen > WLC_IOCTL_MAXLEN) {
return BCME_BADARG;
}
if (ltoh16(capext->version) != CAPEXT_INFO_VERSION_1) {
return BCME_VERSION;
}
payload_len = ltoh16(capext->datalen);
if (payload_len > maxlen) {
return BCME_BADLEN;
}
ctx.num_items_populated = 0;
ctx.more_caps = FALSE;
rc = bcm_unpack_xtlv_buf(&ctx, capext->data, payload_len,
BCM_XTLV_OPTION_ALIGN32, capext_parse_xtlvs);
if (rc != BCME_OK) {
return rc;
}
#ifndef BCMDONGLEHOST
qsort(ctx.cap_strs, ctx.num_items_populated, sizeof(char *), capext_str_comparator);
#endif
return capext_print_caps(&ctx, outbuf, outbuflen);
}
/* Parse value payload on an XTLV */
static int
capext_parse_xtlvs(void *ctx, const uint8 *buf, uint16 type, uint16 len)
{
capext_output_buffer_ctx_t *out_ctx;
out_ctx = (capext_output_buffer_ctx_t *) ctx;
if (out_ctx == NULL) {
return BCME_BADARG;
}
if (len == 0) {
return BCME_OK; /* Nothing to do */
}
return capext_generic_xtlv_cbfn(ctx, buf, type, len);
}
/* Find position of the last set bit in this XTLV payload */
static int
capext_last_cap_bitpos(const uint8 *buf, uint16 len)
{
uint8 bitmap = 0;
uint16 index;
int position = -1;
/* Necesary length checks are already performed prior to calling this function. */
index = len - 1; /* Point to the last byte of the payload mentioned by XTLV len field */
/* Get index of the first non-zero byte from the end */
while (buf[index] == 0) {
if (index == 0) {
return BCME_NOTFOUND;
}
index--;
}
/* buf[index] is now a non-zero value */
bitmap = buf[index];
/* Find out position of the most significant bit set */
while (bitmap) {
position++;
bitmap >>= 1;
}
/* calculate position of the last cap bit set */
return (index * NBBY) + position;
}
/* Go through bitmaps present in input buffer and print names of features/sub-features
* corresponding to bits that are set.
*/
static int
capext_get_caps(void *ctx, const capext_fw_feature_xtlv_parser_map_t *map,
const uint8 *buf, uint16 len)
{
uint16 bitindex = 0, strindex = 0;
capext_output_buffer_ctx_t *out_ctx;
const char *str;
uint16 num_strings;
int last_cap_bit_pos;
out_ctx = (capext_output_buffer_ctx_t *) ctx;
last_cap_bit_pos = capext_last_cap_bitpos(buf, len);
if (last_cap_bit_pos == BCME_NOTFOUND) {
num_strings = 0; /* There is nothing to parse */
} else if (map->num_strings < ((uint16) last_cap_bit_pos + 1)) {
/* Version compatibility check */
/* Perhaps this is new FW and old WL tool. IF the last capability bit position
* populated is more than the number of mappings that are in the tool,
* the user needs to update the WL tool.
*/
num_strings = map->num_strings;
if (out_ctx->more_caps == FALSE) {
out_ctx->type = map->type;
out_ctx->num_strings = map->num_strings;
out_ctx->last_cap_bit_pos = last_cap_bit_pos;
}
out_ctx->more_caps = TRUE;
} else {
/* If last capability position is less than or equal the number of mappings
* in the tool, the tool has necessary mapping to continue parsing this XTLV.
* In that case, parse only upto last capability bit position populated
*/
num_strings = (uint16) last_cap_bit_pos + 1;
}
while (bitindex < num_strings) {
if (isset(buf, bitindex)) {
str = NULL;
/* Get string corresponding to the set bit position
* The map is holding strings in sorted order. So search through the
* enire string table for that map.
*/
for (strindex = 0; strindex < map->num_strings; strindex++) {
if (bitindex != map->bitpos_to_str_map[strindex].bitpos) {
continue;
}
/* Note string at matching index */
str = map->bitpos_to_str_map[strindex].str;
break;
}
/* The bit is set in the XTLV payload but corresponding matching entry is
* not found in the bitpos_to_str_map table. This can also happen
* in case the feature does not need implementation in the host driver
* and the corresponding map entry is not compiled in into the host driver.
* Therefore do not exit, but continue to the next bitindex.
*/
if (strindex == map->num_strings) {
bitindex++;
continue;
}
/* No string is defined at matching entry in bitpos_to_str map */
if (str == NULL) {
bitindex++;
continue;
}
if (out_ctx->num_items_populated >= CAPEXT_CAPS_NUM_MAX) {
return BCME_BUFTOOSHORT;
}
/* Store pointer to string corresponding to the set bit position for later
* processing.
*/
out_ctx->cap_strs[out_ctx->num_items_populated] = str;
out_ctx->num_items_populated++;
}
bitindex++;
}
return BCME_OK;
}
/* Get parsing info for an XTLV type */
static const capext_fw_feature_xtlv_parser_map_t *
capext_get_xtlv_parser_map(uint16 type)
{
uint16 partition;
const capext_partition_init_info_t *cat_init_entry;
/* Partitions are contiguous and fixed size. O(1) lookup for partition */
partition = type / CAPEXT_FEATURE_ID_PARTITION_SIZE;
if (partition >= CAPEXT_FEATURE_ID_NUM_PARTITIONS) {
return NULL;
}
cat_init_entry = &cat_init_info[partition];
/* type in range? */
if (type > cat_init_entry->base && type < cat_init_entry->max_feature_id) {
type -= cat_init_entry->base; /* Offset from base to index in parser[] */
return &cat_init_entry->parser[type]; /* Return appropriate parser */
}
return NULL;
}
/* Generic XTLV parsing function */
static int
capext_generic_xtlv_cbfn(void *ctx, const uint8 *buf, uint16 type, uint16 len)
{
const capext_fw_feature_xtlv_parser_map_t *ptr;
ptr = capext_get_xtlv_parser_map(type);
if (ptr == NULL) {
return BCME_BADARG;
}
if (ptr->bitpos_to_str_map == NULL || ptr->num_strings == 0) {
return BCME_ERROR;
}
return capext_get_caps(ctx, ptr, buf, len);
}
/* Prints caps in a provided buffer. */
static int
capext_print_caps(capext_output_buffer_ctx_t *ctx, char *outbuf, uint16 outbuflen)
{
uint16 i = 0;
int rc = BCME_OK;
uint16 clen = 0;
uint16 cap_str_size;
char more_cap_str[30u];
/* Put a null terminator at the end of the buffer */
outbuf[outbuflen - 1] = '\0';
outbuflen--; /* available size */
if (ctx->more_caps == TRUE) {
if (ctx->num_items_populated >= CAPEXT_CAPS_NUM_MAX) {
return BCME_BUFTOOSHORT;
}
/* Print type:starting_bit_pos-ending_bit_pos that could not be
* translated as FW is new and WL tool is old.
* The translation table is does not have enough entries to parse new bits
*/
(void)snprintf(more_cap_str, sizeof(more_cap_str), "unknown:%u:%u-%u",
ctx->type, ctx->num_strings, ctx->last_cap_bit_pos);
ctx->cap_strs[ctx->num_items_populated] = more_cap_str;
ctx->num_items_populated++;
}
while (i < ctx->num_items_populated) {
/* cap string size is actual string + space character */
cap_str_size = strlen(ctx->cap_strs[i]) + 1;
if (snprintf(outbuf, (outbuflen - clen), "%s ", ctx->cap_strs[i]) <
(int)cap_str_size) {
rc = BCME_BUFTOOSHORT;
break;
}
clen += cap_str_size;
outbuf += cap_str_size;
i++;
}
return rc;
}