mirror of
https://github.com/DrHo1y/orangepi-build.git
synced 2026-11-05 07:17:21 +07:00
37928 lines
988 KiB
C
37928 lines
988 KiB
C
/*
|
|
* Common code for wl command-line swiss-army-knife utility
|
|
*
|
|
* $Copyright (C) 2002-2005 Broadcom Corporation$
|
|
*
|
|
* $Id: wlu.c 404565 2013-05-28 08:08:21Z cylee $
|
|
*/
|
|
|
|
#ifdef BCMINTERNAL
|
|
/*
|
|
* Policy notes:
|
|
* This source file generates both the "wl" command and the
|
|
* more restricted "wl-tool" manufacturing test command (-DWL_TOOL).
|
|
* - wl driver wlc_ioctl() commands which are enclosed within #ifdef BCMINTERNAL
|
|
* should be enclosed within #ifdef BCMINTERNAL in wlu.c .
|
|
* - exposing any new commands in wl-tool requires an "ok" from romanb.
|
|
*/
|
|
#endif /* BCMINTERNAL */
|
|
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#if !defined(WLNINTENDO) && !defined(TARGETOS_nucleus)
|
|
#define CLMDOWNLOAD
|
|
#endif
|
|
|
|
#if defined(_HNDRTE_)
|
|
#include <typedefs.h>
|
|
#include <osl.h>
|
|
#endif
|
|
|
|
#if defined(__NetBSD__)
|
|
#include <typedefs.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"
|
|
|
|
#ifdef BCMCCX
|
|
#include <proto/802.11_ccx.h>
|
|
#endif
|
|
#ifdef WLBTAMP
|
|
#include <proto/bt_amp_hci.h>
|
|
#endif
|
|
#ifdef BCMSDIO
|
|
#include <sdiovar.h>
|
|
#endif
|
|
#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(WLPFN) && 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>
|
|
#endif /* WLPFN */
|
|
|
|
#ifdef WLEXTLOG
|
|
#include <wlc_extlog_idstr.h>
|
|
#endif
|
|
|
|
#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 */
|
|
|
|
/* XXX HACK!! Should read this from target */
|
|
#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>
|
|
#include <wlc_ppr.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
|
|
|
|
|
|
cmd_func_t wl_int;
|
|
|
|
const ofdm_rates_t ofdm_rates[] = { /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
|
|
0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c };
|
|
|
|
#ifdef ATE_BUILD
|
|
/* These are the only functions being used from this file by the ATE firmware */
|
|
static cmd_func_t wl_channel, wl_version, wl_void, wl_rate_mrate, wl_nrate;
|
|
static cmd_func_t wl_pkteng, wl_pkteng_stats, wl_phy_txpwrindex, wl_reg, wl_band;
|
|
int wl_seq_batch_in_client(bool enable);
|
|
int wlu_get(void *wl, int cmd, void *buf, int len);
|
|
int wlu_set(void *wl, int cmd, void *buf, int len);
|
|
static void wl_printrate(int val);
|
|
static int rate_string2int(char *s);
|
|
static char *rate_int2string(char *buf, int val);
|
|
int wlu_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr);
|
|
int wlu_var_getbuf_sm(void *wl, const char *iovar, void *param, int param_len, void **bufptr);
|
|
int wlu_var_getbuf_med(void *wl, const char *iovar, void *param, int param_len, void **bufptr);
|
|
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 cmd_func_t wl_gpioout;
|
|
|
|
#else /* ATE_BUILD */
|
|
|
|
static cmd_func_t wl_print_deprecate;
|
|
static cmd_func_t wl_void, wl_rssi, wl_rssi_event, wl_phy_rssi_ant, wl_gmode;
|
|
static cmd_func_t wlu_dump, wlu_mempool, wlu_srdump, wlu_srwrite, wlu_srvar, wl_nvsource;
|
|
static cmd_func_t wlu_ciswrite, wlu_cisupdate, wlu_cisdump, wlu_offloads_stats;
|
|
#ifdef D11AC_IOTYPES
|
|
static cmd_func_t wl_rate, wl_rate_mrate, wl_phy_rate, wl_bss_max;
|
|
#else
|
|
static cmd_func_t wl_rate_mrate, wl_phy_rate, wl_bss_max;
|
|
#endif
|
|
|
|
static cmd_func_t wl_channel, wl_chanspec, wl_chanim_state, wl_chanim_mode;
|
|
static cmd_func_t wl_radio, wl_version, wl_list, wl_band, wl_bandlist, wl_phylist;
|
|
static cmd_func_t wl_join, wl_tssi, wl_txpwr, wl_atten, wl_evm, wl_country;
|
|
static cmd_func_t wl_out, wl_txpwr1, wl_country_ie_override;
|
|
static cmd_func_t wl_maclist, wl_get_pktcnt, wl_upgrade;
|
|
static cmd_func_t wl_maclist_1;
|
|
static cmd_func_t wl_rateset, wl_txbf_rateset, wl_interfere, wl_interfere_override;
|
|
static cmd_func_t wl_radar_args, wl_radar_thrs, wl_dfs_status;
|
|
static cmd_func_t wl_radar_status, wl_clear_radar_status;
|
|
static cmd_func_t wl_get_txpwr_limit, wl_get_current_power, wl_get_instant_power;
|
|
static cmd_func_t wl_get_current_txppr;
|
|
static cmd_func_t wl_var_get, wl_var_getint, wl_var_getinthex, wl_var_getandprintstr;
|
|
static cmd_func_t wl_var_setint, wl_addwep, wl_rmwep;
|
|
static cmd_func_t wl_nvdump, wl_nvget, wl_nvset, wl_sta_info, 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, wl_otpw, wl_otpraw, wl_counters, wl_delta_stats;
|
|
static cmd_func_t wl_assoc_info, wl_wme_counters, wl_devpath;
|
|
static cmd_func_t wl_management_info;
|
|
static cmd_func_t wl_event_bitvec, wl_diag, wl_var_void;
|
|
static cmd_func_t wl_auto_channel_sel;
|
|
static cmd_func_t wl_bsscfg_int, wl_bsscfg_enable, wl_ap_bsscfg;
|
|
static cmd_func_t wl_msglevel, wl_plcphdr, wl_reg, wl_macreg, wl_band_elm;
|
|
static cmd_func_t wl_phymsglevel;
|
|
static cmd_func_t wl_rateparam, wl_wepstatus, wl_status, wl_spect;
|
|
static cmd_func_t wl_sup_rateset, wl_scan, wl_send_csa, wl_iscan, wl_escan, wl_scanol;
|
|
#ifdef BCMINTERNAL
|
|
static cmd_func_t wl_sendprb;
|
|
#endif /* BCMINTERNAL */
|
|
#ifdef EXTENDED_SCAN
|
|
static cmd_func_t wl_extdscan;
|
|
#endif
|
|
static cmd_func_t wl_dump_chanlist, wl_primary_key, wl_measure_req, wl_send_quiet;
|
|
static cmd_func_t wl_dump_chanspecs, wl_cur_mcsset;
|
|
static cmd_func_t wl_wsec, wl_keys, wl_wsec_test;
|
|
static cmd_func_t wl_channels_in_country;
|
|
static cmd_func_t wl_wpa_auth, wl_tsc, wl_deauth_rc, wl_ssid, wl_bssid, wl_smfstats;
|
|
static cmd_func_t wl_wds_wpa_role_old, wl_wds_wpa_role, 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_mac, wl_revinfo, wl_iov_mac, wl_iov_mac_params;
|
|
static cmd_func_t wl_cac, wl_tslist, wl_tspec, wl_tslist_ea, wl_tspec_ea, wl_cac_delts_ea;
|
|
static cmd_func_t wl_varstr, wl_var_setintandprintstr;
|
|
#if defined(BCMINTERNAL) || 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_obss_scan, wl_obss_coex_action;
|
|
static cmd_func_t wl_dump_lq;
|
|
static cmd_func_t wl_monitor_lq;
|
|
static cmd_func_t wl_test_idletssi;
|
|
|
|
#ifdef WLPFN
|
|
static cmd_func_t wl_pfn_set;
|
|
static cmd_func_t wl_pfn_add;
|
|
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;
|
|
static cmd_func_t wl_pfn_suspend;
|
|
#if defined(linux)
|
|
static cmd_func_t wl_pfn_event_check;
|
|
static cmd_func_t wl_escan_event_check;
|
|
static cmd_func_t wl_escanresults;
|
|
#endif /* linux */
|
|
static cmd_func_t wl_event_filter;
|
|
#endif /* WLPFN */
|
|
|
|
#ifdef WLP2PO
|
|
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_stop;
|
|
#if defined(linux)
|
|
static cmd_func_t wl_p2po_results;
|
|
#endif /* linux */
|
|
|
|
#endif /* WLP2PO */
|
|
|
|
#ifdef WLANQPO
|
|
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 */
|
|
#endif /* WLANQPO */
|
|
static cmd_func_t wl_hs20_ie;
|
|
|
|
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;
|
|
static cmd_func_t wl_reassoc;
|
|
|
|
#ifdef BCMSDIO
|
|
static cmd_func_t wl_sd_reg, wl_sd_msglevel, wl_sd_blocksize, wl_sd_mode;
|
|
#endif
|
|
|
|
static cmd_func_t wl_overlay;
|
|
static cmd_func_t wl_pmkid_info;
|
|
|
|
#ifdef BCMCCX
|
|
static cmd_func_t wl_leap;
|
|
#endif
|
|
|
|
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 wl_sample_collect;
|
|
static cmd_func_t wlu_reg3args;
|
|
|
|
#ifdef BCMINTERNAL
|
|
static cmd_func_t wlu_reg1or3args;
|
|
static cmd_func_t wl_coma;
|
|
static cmd_func_t wl_aci_args;
|
|
static cmd_func_t wlu_ratedump, wlu_fixrate;
|
|
static cmd_func_t wlu_ccreg;
|
|
static cmd_func_t wl_send_wpa_m1;
|
|
#endif
|
|
static cmd_func_t wl_tpc_lm;
|
|
#if defined(BCMINTERNAL)
|
|
static cmd_func_t wl_tpc_rpt_override;
|
|
#endif /* BCMINTERNAL */
|
|
static cmd_func_t wlu_reg2args;
|
|
static cmd_func_t wme_tx_params;
|
|
static cmd_func_t wme_maxbw_params;
|
|
static cmd_func_t wl_ampdu_tid, wl_ampdu_activate_test;
|
|
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_func_t wl_dpt_deny;
|
|
static cmd_func_t wl_dpt_endpoint;
|
|
static cmd_func_t wl_dpt_pmk;
|
|
static cmd_func_t wl_dpt_fname;
|
|
static cmd_func_t wl_dpt_list;
|
|
#ifdef WLTDLS
|
|
static cmd_func_t wl_tdls_endpoint;
|
|
static cmd_func_t wl_tdls_wfd_ie;
|
|
#endif /* WLTDLS */
|
|
#ifdef WLBTAMP
|
|
static cmd_func_t wl_HCI_cmd;
|
|
static cmd_func_t wl_HCI_ACL_data;
|
|
static cmd_func_t wl_get_btamp_log;
|
|
#endif
|
|
static cmd_func_t wl_actframe;
|
|
|
|
static cmd_func_t wl_gpioout;
|
|
|
|
static cmd_func_t wl_bw_cap;
|
|
static cmd_func_t wl_nrate, wl_antsel, wl_txcore;
|
|
static cmd_func_t wl_txcore_pwr_offset;
|
|
static cmd_func_t wl_txfifo_sz;
|
|
static cmd_func_t wl_pkteng, wl_pkteng_stats;
|
|
|
|
static cmd_func_t wl_offload_cmpnt;
|
|
static cmd_func_t wl_hostip, wl_arp_stats, wl_toe_stats, wl_nshostip;
|
|
static cmd_func_t wl_mcast_ackmac, wl_mcast_status;
|
|
#ifdef WLOFFLD
|
|
static cmd_func_t wl_ol_notify_bcn_ie;
|
|
#endif
|
|
|
|
#if defined(WLNDOE) || defined(WLOFFLD)
|
|
static cmd_func_t wl_hostipv6;
|
|
#endif
|
|
#ifdef WLNDOE
|
|
static cmd_func_t wl_ndstatus, wl_solicitipv6, wl_remoteipv6;
|
|
#endif
|
|
static cmd_func_t wl_phy_papdepstbl;
|
|
|
|
int wl_seq_batch_in_client(bool enable);
|
|
cmd_func_t wl_seq_start;
|
|
cmd_func_t wl_seq_stop;
|
|
|
|
static cmd_func_t wl_phy_txiqcc, wl_phy_txlocc;
|
|
static cmd_func_t wl_phytable, wl_phy_pavars, wl_phy_povars;
|
|
static cmd_func_t wl_phy_fem, wl_phy_maxpower, wl_antgain, wl_phy_txpwrindex;
|
|
static cmd_func_t wl_keep_alive;
|
|
static cmd_func_t wl_mkeep_alive;
|
|
static cmd_func_t wl_srchmem;
|
|
static cmd_func_t wl_phy_rpcalvars;
|
|
static cmd_func_t wl_wake_inf;
|
|
|
|
#ifdef WLAWDL
|
|
static cmd_func_t wl_awdl_sync_params;
|
|
static cmd_func_t wl_awdl_af_hdr;
|
|
static cmd_func_t wl_awdl_opmode;
|
|
static cmd_func_t wl_awdl_ext_counts;
|
|
static cmd_func_t wl_bsscfg_awdl_enable;
|
|
static cmd_func_t wl_awdl_mon_bssid;
|
|
static cmd_func_t wl_awdl_advertisers;
|
|
static cmd_func_t wl_awdl_election;
|
|
static cmd_func_t wl_awdl_election_tree;
|
|
static cmd_func_t wl_awdl_payload;
|
|
static cmd_func_t wl_awdl_long_payload;
|
|
static cmd_func_t wl_awdl_chan_seq;
|
|
static cmd_func_t wl_awdl_peer_op;
|
|
static cmd_func_t wl_awdl_oob_af;
|
|
static cmd_func_t wl_awdl_aw_ap_align;
|
|
static cmd_func_t wl_awdl_uct_test;
|
|
static cmd_func_t wl_awdl_counters;
|
|
static cmd_func_t wl_awdl_uct_counters;
|
|
#ifdef WLAWDL_LATENCY_SUPPORT
|
|
static cmd_func_t wl_awdl_tx_latency_clr;
|
|
#endif
|
|
#endif /* WLAWDL */
|
|
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_tcp_keep_conn_set;
|
|
static cmd_func_t wl_tcp_keep_timers_set;
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
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;
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef CLMDOWNLOAD
|
|
static cmd_func_t wl_clmload;
|
|
#endif /* CLMDOWNLOAD */
|
|
static cmd_func_t wl_ledbh;
|
|
|
|
#ifdef RWL_WIFI
|
|
/* Function added to support RWL_WIFI Transport */
|
|
static cmd_func_t wl_wifiserver;
|
|
#endif
|
|
|
|
static cmd_func_t wl_led_blink_sync;
|
|
static cmd_func_t wl_cca_get_stats;
|
|
static cmd_func_t wl_itfr_get_stats;
|
|
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_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_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_tfs_set;
|
|
static cmd_func_t wl_wnm_tfs_status;
|
|
static cmd_func_t wl_wnm_tfs_term;
|
|
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_chanim_acs_record;
|
|
static cmd_func_t wl_chanim_stats;
|
|
static cmd_func_t wl_txdelay_params;
|
|
static cmd_func_t wl_intfer_params;
|
|
|
|
#if defined(BCMINTERNAL) || defined(WLTEST)
|
|
static cmd_func_t wl_sslpnphy_papd_debug;
|
|
static cmd_func_t wl_sslpnphy_debug;
|
|
static cmd_func_t wl_sslpnphy_spbdump;
|
|
static cmd_func_t wl_sslpnphy_percal_debug;
|
|
static cmd_func_t wl_phy_spbrange;
|
|
static cmd_func_t wl_phy_sslpnphy_cga_2g;
|
|
static cmd_func_t wl_phy_sslpnphy_cga_5g;
|
|
static cmd_func_t wl_sslpnphy_tx_iqcc;
|
|
static cmd_func_t wl_sslpnphy_tx_locc;
|
|
#endif /* BCMINTERNAL || WLTEST */
|
|
|
|
#ifdef WLP2P
|
|
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;
|
|
#endif
|
|
|
|
static cmd_func_t wl_rpmt;
|
|
static cmd_func_t wl_spatial_policy, wl_ratetbl_ppr;
|
|
static cmd_func_t wl_sarlimit;
|
|
|
|
static cmd_func_t wl_ie;
|
|
static cmd_func_t wl_wnm_url;
|
|
|
|
#if defined(BCMINTERNAL)
|
|
static cmd_func_t wl_nwoe_ifconfig;
|
|
#endif /* BCMINTERNAL */
|
|
|
|
#ifdef SERDOWNLOAD
|
|
static cmd_func_t dhd_upload;
|
|
int debug = 0;
|
|
#endif
|
|
|
|
#if defined(WL_PROXDETECT)
|
|
static cmd_func_t wl_proxd;
|
|
static cmd_func_t wl_proxd_params;
|
|
static cmd_func_t wl_proxd_status;
|
|
static cmd_func_t wl_proxd_payload;
|
|
#define WL_PROXD_PAYLOAD_LEN 1026
|
|
#endif
|
|
|
|
#if defined(DWDS)
|
|
static cmd_func_t wl_dwds_config;
|
|
#endif
|
|
|
|
static cmd_func_t wl_staprio;
|
|
|
|
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 void wl_txpwr_print_row(const char *label, uint8 chains, int8 pwr20,
|
|
int8 pwr20in40, int8 pwr40, int8 pwr80, int8 pwr20in80, int8 pwr40in80,
|
|
int8 unsupported_rate, int8 channel_bandwidth, bool verbose);
|
|
#ifdef D11AC_IOTYPES
|
|
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);
|
|
#endif
|
|
static void wl_txpwr_array_print(ppr_t* pprptr, int8 channel_bandwidth, bool verbose);
|
|
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);
|
|
#ifdef D11AC_IOTYPES
|
|
static void wl_txpwr_regulatory_array_row_print(int8 *powers, int8 *powers_subchan1,
|
|
int8 *powers_subchan2, int8 channel_bandwidth, reg_rate_index_t rate_index);
|
|
#endif
|
|
static void wl_txpwr_regulatory_array_print(int8 *powers, int8 *powers_subchan1,
|
|
int8 *powers_subchan2, int8 channel_bandwidth, bool verbose);
|
|
static int wl_array_uniform(uint8 *pwr, int start, int count);
|
|
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 int wl_parse_txbf_rateset(wl_txbf_rateset_t *rs, char **argv);
|
|
static void wl_print_mcsset(char *mcsset);
|
|
static void wl_print_vhtmcsset(uint16 *mcsset);
|
|
static void wl_print_txbf_mcsset(char *mcsset, char *prefix);
|
|
static void wl_print_txbf_vhtmcsset(uint16 *mcsset, char *prefix);
|
|
|
|
static void dump_networks(char *buf);
|
|
void dump_bss_info(wl_bss_info_t *bi);
|
|
static void wl_dump_wpa_rsn_ies(uint8* cp, uint len);
|
|
static void wl_rsn_ie_dump(bcm_tlv_t *ie);
|
|
static cmd_func_t wl_lpc_params;
|
|
|
|
int wlu_get(void *wl, int cmd, void *buf, int len);
|
|
int wlu_set(void *wl, int cmd, void *buf, int len);
|
|
|
|
static int _wl_dump_lq(void *wl);
|
|
|
|
/* 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);
|
|
|
|
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 int wl_parse_channel_list(char* list_str, uint16* channel_list, int channel_num);
|
|
static int wl_parse_chanspec_list(char* list_str, chanspec_t *chanspec_list, int chanspec_num);
|
|
static chanspec_t wl_chspec_to_driver(chanspec_t chanspec);
|
|
static uint32 wl_chspec32_to_driver(chanspec_t chanspec);
|
|
static chanspec_t wl_chspec_from_driver(chanspec_t chanspec);
|
|
static chanspec_t wl_chspec32_from_driver(uint32 chanspec);
|
|
|
|
#ifdef EXTENDED_SCAN
|
|
static int wl_parse_extdchannel_list(char* list_str,
|
|
chan_scandata_t* channel_list, int channel_num);
|
|
#endif
|
|
|
|
static uint16 wl_qdbm_to_mw(uint8 qdbm);
|
|
static uint8 wl_mw_to_qdbm(uint16 mw);
|
|
|
|
static int wl_cfg_option(char **argv, const char *fn_name, int *bsscfg_idx, int *consumed);
|
|
static int get_oui_bytes(uchar *oui_str, uchar *oui);
|
|
static int get_ie_data(uchar *data_str, uchar *ie_data, int len);
|
|
static void wl_printrate(int val);
|
|
static int rate_string2int(char *s);
|
|
static char *rate_int2string(char *buf, int val);
|
|
|
|
static int wl_get_iscan(void *wl, char *buf, uint buf_len);
|
|
int wlu_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr);
|
|
int wlu_var_getbuf_sm(void *wl, const char *iovar, void *param, int param_len, void **bufptr);
|
|
int wlu_var_getbuf_med(void *wl, const char *iovar, void *param, int param_len, void **bufptr);
|
|
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 int hexstrtobitvec(const char *cp, uchar *bitvec, int veclen);
|
|
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 void wl_print_tspec(tspec_arg_t *ts);
|
|
static void wl_cac_addts_usage(void);
|
|
static void wl_cac_delts_usage(void);
|
|
|
|
static cmd_func_t wl_txmcsset;
|
|
static cmd_func_t wl_rxmcsset;
|
|
|
|
static int wl_mimo_stf(void *wl, cmd_t *cmd, char **argv);
|
|
|
|
#ifdef WLEXTLOG
|
|
static int wl_extlog(void *wl, cmd_t *cmd, char **argv);
|
|
static int wl_extlog_cfg(void *wl, cmd_t *cmd, char **argv);
|
|
#endif
|
|
|
|
static int wl_assertlog(void *wl, cmd_t *cmd, char **argv);
|
|
static int wl_tsf(void *wl, cmd_t *cmd, char **argv);
|
|
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);
|
|
#ifdef BCMINTERNAL
|
|
static int wl_mfp_bip_test(void *wl, cmd_t *cmd, char **argv);
|
|
#endif
|
|
static void wl_tclas_dump(wl_tclas_t *elem);
|
|
static int wl_tclas_list_parse(wl_tclas_list_t *list);
|
|
static cmd_func_t wl_patrim;
|
|
#endif /* ATE_BUILD */
|
|
|
|
static int wl_sleep_ret_ext(void *wl, cmd_t *cmd, char **argv);
|
|
|
|
char *ver2str(unsigned int vms, unsigned int vls);
|
|
|
|
|
|
/* some OSes (FC4) have trouble allocating (kmalloc) 128KB worth of memory,
|
|
* hence keeping WL_DUMP_BUF_LEN below that
|
|
*/
|
|
#if defined(BWL_SMALL_WLU_DUMP_BUF) || defined(__IOPOS__)
|
|
#define WL_DUMP_BUF_LEN (4 * 1024)
|
|
#else
|
|
#define WL_DUMP_BUF_LEN (127 * 1024)
|
|
#endif /* __IOPOS__ */
|
|
|
|
#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 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 */
|
|
|
|
#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)
|
|
|
|
/* IOCtl version read from targeted driver */
|
|
static int ioctl_version;
|
|
|
|
/* dword align allocation */
|
|
static union {
|
|
char bufdata[WLC_IOCTL_MAXLEN];
|
|
uint32 alignme;
|
|
} bufstruct_wlu;
|
|
static char *buf = (char*) &bufstruct_wlu.bufdata;
|
|
|
|
/* integer output format, default to signed integer */
|
|
static uint8 int_fmt;
|
|
|
|
#ifndef ATE_BUILD
|
|
/*
|
|
* 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 */
|
|
#endif /* !ATE_BUILD */
|
|
|
|
typedef struct {
|
|
uint value;
|
|
const char *string;
|
|
} dbg_msg_t;
|
|
|
|
typedef struct {
|
|
uint value;
|
|
const char *string;
|
|
} phy_msg_t;
|
|
|
|
#define WL_SCAN_PARAMS_SSID_MAX 10
|
|
#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] 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, --channels=L\tcomma or space separated list of channels to scan" \
|
|
|
|
#define OLSCAN_PARAM_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-f F, --flag=<FLAG>\t Flags bits, enable/disable, active_mode/passive_mode\n" \
|
|
"\t-a T, --active=<T in ms>\t active scan time\n" \
|
|
"\t-p T, --passive=<T in ms>\t passive scan time\n" \
|
|
"\t-r T, --scirt=<T in ms>\t Scan Cycle Idle Rest Time\n" \
|
|
"\t-m N, --scirtm=N\t Scan Cycle Idle Rest Time Multiplier\n" \
|
|
"\t-R T, --scart=<T in ms>\t Scan Cycle Active Rest Time\n" \
|
|
"\t-M N, --scartm=N\t Scan Cycle Active Rest Time Multiplier\n" \
|
|
"\t-x T, --mrt=<time in ms>\t Maximum rest time\n" \
|
|
"\t-y N, --msc=N\t Maximum Scan Cycle\n" \
|
|
"\t-n N, --nprobes=N\tnumber of probes per scanned channel\n" \
|
|
"\t-d N, --ssd=N\t Scan Cycle Delay\n" \
|
|
"\t-s S, --ssid=S\t\tSSIDs to scan\n" \
|
|
"\t-c L, --channels=L\tcomma or space separated list of channels to scan" \
|
|
|
|
#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; 20, 40, 80"
|
|
|
|
#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; 20, 40, 80"
|
|
|
|
#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 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]\n\n" \
|
|
"\tMandatory args:\n" \
|
|
"\t\tmethod: Proximity Detection method (currently only method == 1 is supported) \n\n" \
|
|
"\tOptional method specific args - for method 1: \n" \
|
|
"\t\t-c channel : channel number for Proximity Detection common channel\n" \
|
|
"\t\t-i interval : 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 : 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 : tx power of Proximity Detection frames (in dBm)\n" \
|
|
"\t\t-r tx_rate : tx rate of Proximity Detection frames (in Mbps)\n" \
|
|
"\t\t-t timeout : state machine receive timeout of Proximity Detection frames (in ms)\n" \
|
|
"\t\t-m maxconverge : 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" \
|
|
"\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"
|
|
|
|
/* the default behavior is batching in driver,
|
|
* to indicate client batching, users should specify --interactive and --clientbatch
|
|
*/
|
|
static bool batch_in_client;
|
|
|
|
/* 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[] = {
|
|
{ "ver", wl_version, -1, -1,
|
|
"get version information" },
|
|
#ifndef ATE_BUILD
|
|
{ "cmds", wl_list, -1, -1,
|
|
"generate a short list of available commands"},
|
|
#endif
|
|
{ "up", wl_void, -1, WLC_UP,
|
|
"reinitialize and mark adapter up (operational)" },
|
|
#ifndef ATE_BUILD
|
|
{ "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" },
|
|
{ "restart", wl_void, -1, WLC_RESTART,
|
|
"Restart driver. Driver must already be down."},
|
|
{ "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" },
|
|
{ "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, -1,
|
|
"Give suboption \"list\" to list various suboptions" },
|
|
{ "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" },
|
|
{ "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" },
|
|
{ "srcrc", wlu_srwrite, WLC_GET_SROM, -1,
|
|
"Get the CRC for input binary file" },
|
|
{ "ciswrite", wlu_ciswrite, -1, WLC_SET_VAR,
|
|
"Write specified <file> to the SDIO CIS source (either SROM or OTP)"},
|
|
{ "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)"},
|
|
{ "cis_source", wl_varint, WLC_GET_VAR, -1,
|
|
"Display which source is used for the SDIO CIS"},
|
|
{ "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_source", wl_nvsource, WLC_GET_VAR, -1,
|
|
"Display which source is used for nvram"},
|
|
{ "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" },
|
|
{ "customvar1", wl_var_getinthex, -1, -1,
|
|
"print the value of customvar1 in hex format" },
|
|
{ "msglevel", wl_msglevel, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set driver console debugging message bitvector\n"
|
|
"\ttype \'wl msglevel ?\' for values" },
|
|
{ "phymsglevel", wl_phymsglevel, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set phy debugging message bitvector\n"
|
|
"\ttype \'wl phymsglevel ?\' 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])" },
|
|
#endif /* !ATE_BUILD */
|
|
{ "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" },
|
|
#ifndef ATE_BUILD
|
|
{ "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" },
|
|
#ifdef D11AC_IOTYPES
|
|
{ "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
|
|
},
|
|
#endif
|
|
{ "infra", wl_int, WLC_GET_INFRA, WLC_SET_INFRA,
|
|
"Set Infrastructure mode: 0 (IBSS) or 1 (Infra BSS)" },
|
|
{ "ap", wl_int, WLC_GET_AP, WLC_SET_AP,
|
|
"Set AP mode: 0 (STA) or 1 (AP)" },
|
|
#ifdef BCMINTERNAL
|
|
{ "bssid", wl_bssid, WLC_GET_BSSID, WLC_SET_BSSID,
|
|
"Set or get the BSS ID value\n"
|
|
"\t(mac address, e.g. 00:11:20:11:33:33, colons optional)" },
|
|
#else
|
|
{ "bssid", wl_bssid, WLC_GET_BSSID, -1,
|
|
"Get the BSSID value, error if STA and not associated"},
|
|
#endif /* BCMINTERNAL */
|
|
{ "bssmax", wl_bss_max, WLC_GET_VAR, -1,
|
|
"get number of BSSes " },
|
|
{ "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"
|
|
"\t0xff - Unrestricted" },
|
|
#endif /* !ATE_BUILD */
|
|
{ "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,\n"
|
|
"\t\t149, 153, 157, 161,\n"
|
|
"\t\t184, 188, 192, 196, 200, 204, 208, 212, 216"},
|
|
#ifndef ATE_BUILD
|
|
{ "cur_mcsset", wl_cur_mcsset, WLC_GET_VAR, -1,
|
|
"Get the current mcs set"
|
|
},
|
|
{ "clmver", wl_var_getandprintstr, WLC_GET_VAR, -1,
|
|
"Get version information for CLM data and tools"},
|
|
{ "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 or 80\n"
|
|
"\t[-c country_abbrev]"
|
|
},
|
|
{ "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"
|
|
"\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"
|
|
"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"},
|
|
{ "dfs_channel_forced", wl_chanspec, 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"},
|
|
{ "tssi", wl_tssi, WLC_GET_TSSI, -1,
|
|
"Get the tssi value from radio" },
|
|
{ "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\n"
|
|
"\t-q quarter dbm units\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"},
|
|
{ "txpathpwr", wl_int, WLC_GET_TX_PATH_PWR, WLC_SET_TX_PATH_PWR,
|
|
"Turn the tx path power on or off on 2050 radios" },
|
|
{ "txpwrlimit", wl_get_txpwr_limit, WLC_CURRENT_PWR, -1,
|
|
"Return current tx power limit" },
|
|
{ "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 ]" },
|
|
#endif /* !ATE_BUILD */
|
|
{ "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 ]\n"
|
|
"\tSet a radio register: wl radioreg [ offset ] [ value ] [ cr0/cr1/cr2/pll/all ]"},
|
|
#ifndef ATE_BUILD
|
|
{ "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 ]" },
|
|
{ "ucantdiv", wl_int, WLC_GET_UCANTDIV, WLC_SET_UCANTDIV,
|
|
"Enable/disable ucode antenna diversity (1/0 or on/off)" },
|
|
#endif /* !ATE_BUILD */
|
|
{ "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"},
|
|
|
|
#ifndef ATE_BUILD
|
|
{ "devpath", wl_devpath, WLC_GET_VAR, -1,
|
|
"print device path" },
|
|
|
|
#ifdef BCMINTERNAL
|
|
{ "help", wl_cmd_help, -1, -1,
|
|
"List commands by category"},
|
|
{"iov", wl_iov_names, -1, -1,
|
|
"Get information on driver IO variables"},
|
|
{ "shownetworks", wl_dump_networks, WLC_SCAN_RESULTS, -1,
|
|
"Pretty-print the BSSID list" },
|
|
{ "loop", wl_int, WLC_GET_LOOP, WLC_SET_LOOP,
|
|
"enable mac-level or mii-level loopback" },
|
|
{ "piomode", wl_int, WLC_GET_PIOMODE, WLC_SET_PIOMODE,
|
|
"Get/Set piomode" },
|
|
{ "shmem_dump", wl_print_deprecate, -1, -1, "Deprecated. Folded under 'wl dump shmem'" },
|
|
{ "pcieregdump", wl_print_deprecate, -1, -1, "Deprecated.Folded under 'wl dump pcieregs'" },
|
|
{ "gpiodump", wl_print_deprecate, -1, -1, "Deprecated. Folded under 'wl dump gpio'" },
|
|
{ "tsf_dump", wl_print_deprecate, -1, -1, "Deprecated. Folded under 'wl dump tsf'" },
|
|
{ "ampdu_dump", wl_print_deprecate, -1, -1, "Deprecated. Folded under 'wl dump ampdu'" },
|
|
{ "amsdu_dump", wl_print_deprecate, -1, -1, "Deprecated. Folded under 'wl dump amsdu'" },
|
|
{ "amsdu_clear_counters", wl_var_void, -1, WLC_SET_VAR,
|
|
"clear amsdu counters"},
|
|
{ "fixrate", wlu_fixrate, WLC_GET_FIXRATE, WLC_SET_FIXRATE,
|
|
"get/set the fixrate per scb/ac:\n"
|
|
"To get: wl fixrate xx:xx:xx:xx:xx:xx (the remote mac addr).\n"
|
|
"To set: wl fixrate xx:xx:xx:xx:xx:xx <ac> <rateid>, \n"
|
|
"\twhere <ac> = -1 means for all ACs, and \n"
|
|
"\t<rateid> is the index to the rate set, -1 means auto."},
|
|
{ "ratedump", wlu_ratedump, WLC_DUMP_RATE, -1,
|
|
"Print driver rate selection tunables and per-scb state to stdout\n"
|
|
"\tbased on remote station mac address[xx:xx:xx:xx:xx:xx]" },
|
|
{ "ccreg", wlu_ccreg, WLC_GET_VAR, WLC_SET_VAR, "g/set cc registers"},
|
|
{ "corereg", wlu_reg3args, WLC_GET_VAR, WLC_SET_VAR,
|
|
"!!! internal only !!! g/set ANY registers in ANY core: coreidx offset [val]"},
|
|
{ "corewrapperreg", wlu_reg3args, WLC_GET_VAR, WLC_SET_VAR,
|
|
"!!! internal only !!! g/set ANY core wrapper register in ANY core: coreidx offset [val]"},
|
|
{ "sflags", wlu_reg1or3args, WLC_GET_VAR, WLC_SET_VAR, "g/set core iostatus flags"},
|
|
{ "cflags", wlu_reg1or3args, WLC_GET_VAR, WLC_SET_VAR, "g/set core ioctrl flags"},
|
|
{ "jtagureg", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR, "g/set JTAG user registers"},
|
|
{ "coma", wl_coma, -1, WLC_SET_VAR, "Put the router in a catatonic state"},
|
|
{ "pciereg", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR, "g/set pcie tlp/dlp/plp registers"},
|
|
{ "pcicfgreg", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR, "g/set pci cfg register"},
|
|
{ "n_bw", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"get/set mimo channel bandwidth (10=10MHz, 20=20Mhz, 40=40Mhz), will cause phy to reset"},
|
|
{ "mimo_ofdm", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"get/set stf mode for legacy ofdm frame (0=SISO, 1=CDD)"},
|
|
{ "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)"},
|
|
{ "aciargs", wl_aci_args, WLC_GET_ACI_ARGS, WLC_SET_ACI_ARGS,
|
|
"Get/Set various aci tuning parameters. Choices are:\n"
|
|
"\tenter:\tCRS glitch trigger level to start detecting ACI\n"
|
|
"\texit:\tCRS glitch trigger level to exit ACI mode\n"
|
|
"\tglitch\tSeconds interval between ACI scans when glitchcount is continuously high\n"
|
|
"\tspin:\tNum microsecs to delay between rssi samples\n\n"
|
|
"\tenter:\t\t(NPHY) CRS glitch trigger level to start detecting ACI\n"
|
|
"\tadcpwr_enter:\t(NPHY) ADC power to enter ACI Mitigation mode\t\n"
|
|
"\tadcpwr_exit:\t(NPHY) ADC power to exit ACI Mitigation mode\t\n"
|
|
"\trepeat:\t\t(NPHY) Number of tries per channel to compute power\t\n"
|
|
"\tsamples:\t(NPHY) Number of samples to use to compute power on a channel\t\n"
|
|
"\tundetect_sz:\t(NPHY) # Undetects to wait before coming out of ACI Mitigation mode\t\n"
|
|
"\tloaci:\t\t(NPHY) bphy energy threshold for low aci pwr \t\n"
|
|
"\tmdaci:\t\t(NPHY) bphy energy threshold for medium aci pwr \t\n"
|
|
"\thiaci:\t\t(NPHY) bphy energy threshold for hi aci pwr \t\n\n"
|
|
"\tUsage: wl aciargs [enter x][exit x][spin x][glitch x]"},
|
|
{ "hwkeys", wl_var_getandprintstr, WLC_GET_VAR, -1,
|
|
"Dump all keys in h/w"},
|
|
{ "pllreset", wl_var_void, -1, WLC_SET_VAR, "set the pll to reset value\n"
|
|
"\tUsage: wl pllreset"},
|
|
{ "timestamp", wl_var_getandprintstr, WLC_GET_VAR, -1,
|
|
"Get the debug hw timestamp"},
|
|
#endif /* BCMINTERNAL */
|
|
{ "pcieserdesreg", wlu_reg3args, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set SERDES registers: dev offset [val]"},
|
|
{ "ampdu_activate_test", wl_ampdu_activate_test, -1, WLC_SET_VAR,
|
|
"actiate" },
|
|
/* nphy parameter setting is internal only for now */
|
|
{ "ampdu_tid", wl_ampdu_tid, WLC_GET_VAR, WLC_SET_VAR,
|
|
"enable/disable per-tid ampdu; usage: wl ampdu_tid <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>" },
|
|
{ "ampdu_clear_dump", wl_var_void, -1, WLC_SET_VAR,
|
|
"clear ampdu counters"},
|
|
{ "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"},
|
|
{ "dpt_deny", wl_dpt_deny, WLC_GET_VAR, WLC_SET_VAR,
|
|
"adds/removes ea to dpt deny list\n"
|
|
"\tusage: wl dpt_deny <add,remove> <ea>" },
|
|
{ "dpt_endpoint", wl_dpt_endpoint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"creates/updates/deletes dpt endpoint for ea\n"
|
|
"\tusage: wl dpt_endpoint <create, update, delete> <ea>" },
|
|
{ "dpt_pmk", wl_dpt_pmk, -1, WLC_SET_VAR,
|
|
"sets DPT pre-shared key" },
|
|
{ "dpt_fname", wl_dpt_fname, WLC_GET_VAR, WLC_SET_VAR,
|
|
"sets/gets DPT friendly name" },
|
|
{ "dpt_list", wl_dpt_list, WLC_GET_VAR, -1,
|
|
"gets status of all dpt peers" },
|
|
#ifdef WLBTAMP
|
|
{ "HCI_cmd", wl_HCI_cmd, WLC_GET_VAR, WLC_SET_VAR,
|
|
"carries HCI commands to the driver\n"
|
|
"\tusage: wl HCI_cmd <command> <args>" },
|
|
{ "HCI_ACL_data", wl_HCI_ACL_data, WLC_GET_VAR, WLC_SET_VAR,
|
|
"carries HCI ACL data packet to the driver\n"
|
|
"\tusage: wl HCI_ACL_data <logical link handle> <data>" },
|
|
{ "btamp_statelog", wl_get_btamp_log, WLC_GET_VAR, WLC_SET_VAR,
|
|
"Return state transistion log of BTAMP" },
|
|
#endif /* WLBTAMP */
|
|
{ "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" },
|
|
{ "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" },
|
|
{ "tkip_countermeasures", wl_int, -1, WLC_TKIP_COUNTERMEASURES,
|
|
"Enable or disable TKIP countermeasures (TKIP-enabled AP only)\n"
|
|
"\t0 - disable\n"
|
|
"\t1 - enable" },
|
|
{ "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_mac, -1, WLC_SCB_AUTHORIZE,
|
|
"restrict traffic to 802.1X packets until 802.1X authorization succeeds" },
|
|
{ "deauthorize", wl_mac, -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\n"
|
|
"\t0x200 - MFP capable\n"
|
|
"\t0x400 - MFP required\n"
|
|
"\t0x800 - MFP use KDF (SHA256)"
|
|
},
|
|
{ "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"
|
|
#ifdef BCMCCX
|
|
"\t8 CCKM (WPA)\n"
|
|
#endif /* BCMCCX */
|
|
#if defined (BCMCCX)
|
|
"\t16 CCKM (WPA2)\n"
|
|
#endif /* BCMCCX */
|
|
"\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." },
|
|
#ifdef BCMINTERNAL
|
|
{ "sendprb", wl_sendprb, -1, WLC_SET_VAR,
|
|
"Send a probe request.\n"
|
|
"\t-s S, --ssid=S\t\tSSIDs to scan\n"
|
|
"\t-b MAC, --bssid=MAC\tparticular BSSID MAC address, xx:xx:xx:xx:xx:xx\n"
|
|
"\t-d MAC, --da=MAC\tDestnation Address" },
|
|
#endif /* BCMINTERNAL */
|
|
{ "scan", wl_scan, -1, WLC_SCAN,
|
|
"Initiate a scan.\n" SCAN_USAGE
|
|
},
|
|
{ "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
|
|
},
|
|
{ "scancache_clear", wl_var_void, -1, WLC_SET_VAR,
|
|
"clear the scan cache"},
|
|
{ "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
|
|
},
|
|
{ "ol_scanparams", wl_scanol, -1, WLC_SET_VAR,
|
|
"set offload Scan parameters\n" OLSCAN_PARAM_USAGE
|
|
},
|
|
{ "olssid", wl_scan, -1, WLC_SET_VAR,
|
|
"set offload Directed Scan SSID\n" SCAN_USAGE
|
|
},
|
|
{ "ol_prefssid", wl_scan, -1, WLC_SET_VAR,
|
|
"set offload scan preferred SSID\n" SCAN_USAGE
|
|
},
|
|
#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" },
|
|
{ "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." },
|
|
{ "curppr", wl_get_current_txppr, WLC_GET_VAR, -1,
|
|
"Return current tx power per rate offset."},
|
|
{ "txinstpwr", wl_get_instant_power, WLC_GET_VAR, -1,
|
|
"Return tx power based on instant TSSI "},
|
|
{ "scansuppress", wl_int, WLC_GET_SCANSUPPRESS, WLC_SET_SCANSUPPRESS,
|
|
"Suppress all scans for testing.\n"
|
|
"\t0 - allow scans\n"
|
|
"\t1 - suppress scans" },
|
|
{ "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)"},
|
|
{ "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},
|
|
{ "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"},
|
|
{ "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"},
|
|
{ "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"},
|
|
{ "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."},
|
|
#ifdef BCMCCX
|
|
{ "leap", wl_leap, WLC_GET_LEAP_LIST, WLC_SET_LEAP_LIST,
|
|
"Set parameters for LEAP authentication\n"
|
|
"\tleap <ssid> <username> <password> [domain]" },
|
|
#endif /* BCMCCX */
|
|
{ "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."},
|
|
{ "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)."},
|
|
{ "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." },
|
|
#endif /* !ATE_BUILD */
|
|
{ "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" },
|
|
#ifndef ATE_BUILD
|
|
{ "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)" },
|
|
{ "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)" },
|
|
{ "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)" },
|
|
{ "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."},
|
|
{ "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" },
|
|
{ "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."},
|
|
{ "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."},
|
|
{ "radar", wl_int, WLC_GET_RADAR, WLC_SET_RADAR,
|
|
"Enable/Disable radar"},
|
|
{ "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,\n"
|
|
"\tthresh1, 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"},
|
|
{ "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,\n"
|
|
"\tthresh1, 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"},
|
|
{ "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"},
|
|
{ "dfs_status", wl_dfs_status, WLC_GET_VAR, -1,
|
|
"Get dfs status"},
|
|
{ "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"},
|
|
{ "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 = none\n"
|
|
"\t1 = desnese based on glitches\n"
|
|
"\t2 = limit pktgain based on hwaci (high pwr aci)\n"
|
|
"\t3 = limit pktgain based on w2/nb (high pwr aci)\n"
|
|
"\tSo a value of 7 would enable all three\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"
|
|
"\t0 = none\n"
|
|
"\t1 = desnese based on glitches\n"
|
|
"\t2 = limit pktgain based on hwaci (high pwr aci)\n"
|
|
"\t3 = limit pktgain based on w2/nb (high pwr aci)\n"
|
|
"\tSo a value of 7 would enable all three\n"},
|
|
{ "frameburst", wl_int, WLC_GET_FAKEFRAG, WLC_SET_FAKEFRAG,
|
|
"Disable/Enable frameburst mode" },
|
|
{ "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"},
|
|
{ "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"},
|
|
{ "arpoe", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"Enable/Disable arp agent offload feature"},
|
|
{ "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"},
|
|
#ifdef WLOFFLD
|
|
{ "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"},
|
|
#endif
|
|
{ "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"},
|
|
{ "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"},
|
|
{ "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"},
|
|
{ "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"},
|
|
{ "wds_remote_mac", wl_mac, 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"},
|
|
{ "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"},
|
|
{ "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)>"},
|
|
{ "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_mac_params, WLC_GET_VAR, -1,
|
|
"Dumps packet queue log info for [C] common, [A] AMPDU or [P] power save queues\n"
|
|
"A: 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"
|
|
"wl pktq_stats [C:[+]]|[A:[+]|P:[+]<xx:xx:xx:xx:xx:xx>][/<PREC>[/<PREC>]]..." },
|
|
{ "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"
|
|
"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"
|
|
"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"},
|
|
{ "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"},
|
|
{ "otpraw", wl_otpraw, WLC_GET_VAR, WLC_SET_VAR,
|
|
"Read/Write raw data to on-chip otp\n"
|
|
"Usage: wl otpraw <offset> <bits> [<data>]"},
|
|
{ "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_event_bitvec, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set/get 128-bit hex filter bitmask for MAC event reporting up to application layer"},
|
|
{ "event_msgs", wl_event_bitvec, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set/get 128-bit hex filter bitmask for MAC event reporting via packet indications"},
|
|
{ "counters", wl_counters, WLC_GET_VAR, -1,
|
|
"Return driver counter values" },
|
|
{ "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" },
|
|
{ "assoc_info", wl_assoc_info, WLC_GET_VAR, -1,
|
|
"Returns the assoc req and resp information [STA only]" },
|
|
{ "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" },
|
|
{ "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" },
|
|
{ "bss", wl_bsscfg_enable, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set/get BSS enabled status: up/down"},
|
|
{ "ap_bss", wl_ap_bsscfg, -1, WLC_SET_VAR,
|
|
"Create AP BSS default down:\n"
|
|
"Usage: wl ap_bss [create/destroy] [-m mac-addr]\n"
|
|
"\t create: creates ap bss in down state\n"
|
|
"\t destroy: disable and delete ap bss\n"
|
|
"\t-m Mac-addr of new bss to create\n"
|
|
"\t auto-generate mac-addr if not provided\n"},
|
|
{ "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"},
|
|
{ "eap_restrict", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set/get EAP restriction"},
|
|
{ "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'" },
|
|
{ "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"},
|
|
{ "otpdump", wl_var_setintandprintstr, WLC_GET_VAR, -1,
|
|
"Dump raw otp"},
|
|
{ "otpstat", wl_var_setintandprintstr, WLC_GET_VAR, -1,
|
|
"Dump OTP status"},
|
|
#endif /* !ATE_BUILD */
|
|
{ "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"},
|
|
#ifndef ATE_BUILD
|
|
{ "mimo_txbw", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"get/set mimo txbw (2=20Mhz(lower), 3=20Mhz upper, 4=40Mhz)"},
|
|
{ "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"},
|
|
|
|
#ifdef BCMSDIO
|
|
{ "sd_cis", wl_var_getandprintstr, WLC_GET_VAR, -1,
|
|
"dump sdio CIS"},
|
|
{ "sd_devreg", wl_sd_reg, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set device register across SDIO bus"},
|
|
{ "sd_drivestrength", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set SDIO bus drive strenth in mA"},
|
|
{ "sd_hostreg", wl_sd_reg, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set local controller register"},
|
|
{ "sd_blockmode", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set blockmode"},
|
|
{ "sd_blocksize", wl_sd_blocksize, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set block size for a function"},
|
|
{ "sd_ints", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set client ints"},
|
|
{ "sd_dma", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set dma usage"},
|
|
{ "sd_numints", wl_varint, WLC_GET_VAR, -1,
|
|
"number of device interrupts"},
|
|
{ "sd_numlocalints", wl_varint, WLC_GET_VAR, -1,
|
|
"number of non-device controller interrupts"},
|
|
{ "sd_divisor", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set the divisor for SDIO clock generation"},
|
|
{ "sd_mode", wl_sd_mode, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set SDIO bus mode (spi, sd1, sd4)"},
|
|
{ "sd_highspeed", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set the high-speed clocking mode"},
|
|
{ "sd_msglevel", wl_sd_msglevel, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set debug message level"},
|
|
#ifdef BCMDBG
|
|
{ "sd_hciregs", wl_var_getandprintstr, WLC_GET_VAR, -1,
|
|
"dump sdio Host Controller Interrupt Registers"},
|
|
#endif /* BCMDBG */
|
|
#endif /* BCMSDIO */
|
|
|
|
{ "overlay", wl_overlay, WLC_GET_VAR, WLC_SET_VAR,
|
|
"overlay virt_addr phy_addr size"},
|
|
#endif /* !ATE_BUILD */
|
|
{ "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"
|
|
},
|
|
#ifndef ATE_BUILD
|
|
{ "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)"},
|
|
{ "lpphy_papdepstbl", wl_phy_papdepstbl, -1, WLC_GET_VAR,
|
|
"print papd eps table; Usage: wl lpphy_papdepstbl"
|
|
},
|
|
{ "lcnphy_papdepstbl", wl_phy_papdepstbl, -1, WLC_GET_VAR,
|
|
"print papd eps table; Usage: wl lcnphy_papdepstbl"
|
|
},
|
|
{ "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
|
|
#ifdef BCMINTERNAL
|
|
{ "phy_force_crsmin", wl_phy_debug_cmd, WLC_GET_VAR, -1,
|
|
"Enable auto crs min power/set a desired value\n"
|
|
"\t x : set the crsmin threshold to be 'x'\n"
|
|
"\t -1 : enable\n"
|
|
"\t 0 : disable\n"
|
|
"\t usage: wl phy_force_crsmin <int32 var>"
|
|
},
|
|
#endif
|
|
#ifdef BCMINTERNAL
|
|
{ "phy_debug_cmd", wl_phy_debug_cmd, WLC_GET_VAR, WLC_SET_VAR,
|
|
"general purpose command for phy debugging\n"
|
|
"\t phy function call can be added to wlc_phy_cmn.c\n"
|
|
"\t usage: wl phy_debug_cmd <int32 var>"
|
|
},
|
|
#endif
|
|
{ "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 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) or 1 (enable)\n"
|
|
"\t-e extra INITgain in dB on top of default. Valid values = {0, 3, 6, .., 21, 24}"
|
|
},
|
|
{ "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 or 16 or 32\n"
|
|
"table ID, table offset can not be negative"
|
|
},
|
|
{ "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 \n"
|
|
},
|
|
{ "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)"
|
|
},
|
|
{ "antgain", wl_antgain, WLC_GET_VAR, WLC_SET_VAR,
|
|
"Set temp ag0/1 value\n"
|
|
"usage: wl antgain ag0=0x1 ag1=0x2"
|
|
},
|
|
{ "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"
|
|
},
|
|
|
|
{ "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"
|
|
#ifdef BCMINTERNAL
|
|
"\n\tadvanced paramaters to set: <utx> <urx> <dtx> <drx>\n"
|
|
"\t\twhere utx = TX unicast antenna configuration -1 = AUTO\n"
|
|
"\t\t\turx = RX unicast antenna configuration, -1 = AUTO\n"
|
|
"\t\t\tdtx = TX default (non-unicast) antenna configuration, -1 = AUTO\n"
|
|
"\t\t\tdrx = RX default (non-unicast) antenna configuration, -1 = AUTO"
|
|
#endif
|
|
},
|
|
{ "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)"
|
|
},
|
|
{ "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-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-f File name to dump the sample buffer (binary format, default \"sample_collect.dat\")\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-f File name to dump the sample buffer (default \"sample_collect.dat\")\n"
|
|
"\t-t Trigger condition (default now)\n"
|
|
"\t\t now\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)>]"},
|
|
{ "txfifo_sz", wl_txfifo_sz, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set/get the txfifo size; usage: wl txfifo_sz <fifonum> <size_in_bytes>" },
|
|
#ifdef WLPFN
|
|
{ "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-3]] [mscan (0)|[0-90]] [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]]"},
|
|
{ "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]"
|
|
"[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.)"},
|
|
{ "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\n"},
|
|
{ "pfncfg", wl_pfn_cfg, -1, -1,
|
|
"Configures channel list and report type\n"
|
|
"\tpfncfg syntax is: pfncfg [channel <channel list>] [report (both)|ssidonly|bssidonly]"},
|
|
{ "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\n"
|
|
"\tpfnbest syntax is: pfnbest"},
|
|
{ "pfnsuspend", wl_pfn_suspend, -1, -1,
|
|
"Suspend/resume pno scan\n"
|
|
"\tpfnsuspend syntax is: pfnsuspend 0|1"},
|
|
#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 [(eth1)ifname]"},
|
|
{ "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
|
|
},
|
|
#endif /* linux */
|
|
{ "event_filter", wl_event_filter, -1, -1,
|
|
"Set/get event filter\n"
|
|
"\tevent_filter syntax is: event_filter [value]"},
|
|
#endif /* WLPFN */
|
|
#ifdef WLP2PO
|
|
{ "p2po_listen", wl_p2po_listen, -1, WLC_SET_VAR,
|
|
"start listen (with period and interval)\n"
|
|
"\tusage: p2po_listen [\"period\"] [\"interval\"]\n"
|
|
},
|
|
{ "p2po_find", wl_var_void, -1, WLC_SET_VAR,
|
|
"start discovery\n"
|
|
},
|
|
{ "p2po_stop", wl_p2po_stop, -1, WLC_SET_VAR,
|
|
"stop both P2P listen and P2P device discovery offload(0:stop; 1:pause).\n"
|
|
"\tusage: p2po_stop <0|1>\n"
|
|
},
|
|
{ "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\n"
|
|
},
|
|
{ "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\n"
|
|
},
|
|
{ "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\n"
|
|
},
|
|
{ "p2po_sd_cancel", wl_var_void, -1, WLC_SET_VAR,
|
|
"cancel finding a service\n"
|
|
},
|
|
{ "p2po_listen_channel", wl_p2po_listen_channel, -1, WLC_SET_VAR,
|
|
"set listen channel to channel 1, 6, 11, or default\n"
|
|
"\tusage: p2po_listen_channel <1|6|11|0>\n"
|
|
},
|
|
#if defined(linux)
|
|
{ "p2po_results", wl_p2po_results, -1, WLC_SET_VAR,
|
|
"Listens and displays P2PO results.\n"
|
|
},
|
|
#endif /* linux */
|
|
#endif /* WLP2PO */
|
|
#ifdef WLANQPO
|
|
{ "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\"]\n"
|
|
},
|
|
{ "anqpo_stop_query", wl_anqpo_stop_query, -1, WLC_SET_VAR,
|
|
"stop ANQP query\n"
|
|
"\tusage: anqpo_stop_query\n"
|
|
},
|
|
{ "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>]>\n"
|
|
},
|
|
{ "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]\n"
|
|
},
|
|
{ "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)]\n"
|
|
},
|
|
{ "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]>\n"
|
|
},
|
|
{ "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]]>\n"
|
|
},
|
|
#if defined(linux)
|
|
{ "anqpo_results", wl_anqpo_results, -1, WLC_SET_VAR,
|
|
"Listens and displays ANQP results.\n"
|
|
},
|
|
#endif /* linux */
|
|
#endif /* WLANQPO */
|
|
{ "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"
|
|
},
|
|
#endif /* !ATE_BUILD */
|
|
{ "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] [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"
|
|
"\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"},
|
|
#ifndef ATE_BUILD
|
|
{ "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_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_keepalive shares structures and functions with "mkeep_alive" */
|
|
{"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" },
|
|
|
|
{ "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"
|
|
},
|
|
|
|
#if defined(BCMINTERNAL) || defined(WLTEST)
|
|
{ "sslpnphy_papd_debug", wl_sslpnphy_papd_debug, -1, WLC_GET_VAR,
|
|
"shows sslpnphy papd debug data"},
|
|
{ "sslpnphy_papd_dumplut", wl_sslpnphy_debug, -1, WLC_GET_VAR,
|
|
"shows sslpnphy papd compdelta table data"},
|
|
{ "sslpnphy_spbdump", wl_sslpnphy_spbdump, -1, WLC_GET_VAR,
|
|
"shows sslpnphy spb dump"},
|
|
{ "sslpnphy_percal_debug", wl_sslpnphy_percal_debug, -1, WLC_GET_VAR,
|
|
"shows sslpnphy percal debug data"},
|
|
{ "sslpnphy_spbrange", wl_phy_spbrange, WLC_GET_VAR, WLC_SET_VAR,
|
|
"usage: sslpnphy_spbrange [start end}"},
|
|
{ "sslpnphy_cga_5g", wl_phy_sslpnphy_cga_5g, WLC_GET_VAR, WLC_SET_VAR,
|
|
"usage: sslpnphy_cga_5g cga1 cga2... cga24 }"},
|
|
{ "sslpnphy_cga_2g", wl_phy_sslpnphy_cga_2g, WLC_GET_VAR, WLC_SET_VAR,
|
|
"usage: sslpnphy_cga_2g cga1 cga2... cga14 }"},
|
|
{ "sslpnphy_tx_iqcc", wl_sslpnphy_tx_iqcc, WLC_GET_VAR, WLC_SET_VAR,
|
|
"usage: sslpnphy_tx_iqcc }"},
|
|
{ "sslpnphy_tx_locc", wl_sslpnphy_tx_locc, WLC_GET_VAR, WLC_SET_VAR,
|
|
"usage: slpnphy_tx_locc}"},
|
|
#endif /* BCMINTERNAL || WLTEST */
|
|
{ "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"},
|
|
#ifdef BCMINTERNAL
|
|
{ "auth_rekey_init", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"init/de-init group key rekey(for send_wpa_m1 cmd)\n"
|
|
"\t Must be enabled before connection for sending"},
|
|
{ "wpa_m1", wl_send_wpa_m1, -1, WLC_SET_VAR,
|
|
"send a WPA M1 to mac address\n"
|
|
"\tUsage: wl wpa_m1 <ptk | gtk | gtk_bad> xx:xx:xx:xx:xx:xx\n"
|
|
"\tptk: Send a WPA PTK M1\n"
|
|
"\tgtk: Send a WPA GTK M1\n"
|
|
"\tgtk_bad: Send a invalid WPA GTK M1"},
|
|
#endif /* BCMINTERNAL */
|
|
{ "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" },
|
|
{ "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"},
|
|
{ "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"},
|
|
{"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_pkt_info", wl_wake_inf, WLC_GET_VAR, -1,
|
|
"returns packet that woke host\n"},
|
|
{ "srchmem", wl_srchmem, WLC_GET_VAR, WLC_SET_VAR,
|
|
"g/set ucode srch engine memory"},
|
|
#ifdef WLAWDL
|
|
{"awdl_sync_params", wl_awdl_sync_params, -1, -1,
|
|
"Send specified \"awdl_sync_params\" action frames Sync params.\n"
|
|
"\tUsage: wl awdl_sync_params <period> <aw period> <aw cmn time> <Guard time>"
|
|
" <master_chan>\n"},
|
|
{"awdl_af_hdr", wl_awdl_af_hdr, -1, -1,
|
|
"Send specified \"awdl_af_hdr\" action frame header.\n"
|
|
"\tUsage: wl awdl_af_hdr <dest mac > <4 byte hdr> \n"
|
|
"\t\tpacket: Hex packet contents to transmit. \n"
|
|
"\twl awdl_af_hdr xxxxxx \n" },
|
|
{"awdl_ext_counts", wl_awdl_ext_counts, -1, -1,
|
|
"Set the AWDL max/min extension counts.\n"
|
|
"\tUsage: wl awdl_ext_counts <minExt> <maxExtMulti> <maxExtUni> <maxAfExt>\n"},
|
|
{"awdl_opmode", wl_awdl_opmode, -1, -1,
|
|
"Set AWDL operating mode.\n"
|
|
"\tUsage: wl awdl_opmode mode role bcast_period master_addr\n"
|
|
"\t\tmode: 0: Auto, 1: Fixed.\n"
|
|
"\t\trole: 0: Slave, 1: NE Master, 2: Master.\n"
|
|
"\t\tbcast_period: bcasting period(ms) for NE master.\n"
|
|
"\t\tmaster_addr: remote master address for fixed mode.\n"},
|
|
{ "awdl_if", wl_bsscfg_awdl_enable, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set/get awdl bsscfg enabled status: up/down \n"},
|
|
{ "awdl_mon_bssid", wl_awdl_mon_bssid, -1, WLC_SET_VAR,
|
|
"set/get awdl monitor BSSID: wl awdl_mon_bssid <BSSID>\n"},
|
|
{ "awdl_advertisers", wl_awdl_advertisers, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set/get awdl peers table\n"},
|
|
{"awdl_election", wl_awdl_election, -1, -1,
|
|
"Send specified \"awdl_election\" Election metrics .\n"
|
|
"\tUsage: wl awdl_election <flag> <id> <top master dis> <master mac>\n"
|
|
"<Master metrics> <self metrics>\n"},
|
|
{"awdl_election_tree", wl_awdl_election_tree, -1, -1,
|
|
"Send specified \"awdl_election_tree\" Election metrics .\n"
|
|
"\tUsage: wl awdl_election <flag> <id> <top master dis> \n"
|
|
"\t <master mac> <masterSyncRssiThld> <slaveSyncRssiThld>\n"
|
|
"\t <edgeSyncRssiThld> <clseRangeRssiThld> \n"
|
|
"\t <midRangeRssiThld> <maxHigherMastersCloseRange> \n"
|
|
"\t <maxHigherMastersMidRange> <maxTreeDepth>\n"},
|
|
{"awdl_payload", wl_awdl_payload, -1, -1,
|
|
"Send specified \"awdl_payload\" Payload .\n"
|
|
"\tUsage: wl awdl_payload xxxxxxxx \n"},
|
|
{"awdl_long_psf", wl_awdl_long_payload, -1, -1,
|
|
"Send specified \"awdl_long_psf\" Payload .\n"
|
|
"\tUsage: wl awdl_long_psf <long psf period> <long psf tx offset> xxxxxxxx \n"},
|
|
{"awdl_chan_seq", wl_awdl_chan_seq, -1, -1,
|
|
"Send specified \"awdl_chan_seq\" Channel Sequence .\n"
|
|
"\tUsage: wl awdl_chan_seq <encoding> <Step count> <duplicate> <fill chan> <Sequence>\n"},
|
|
{"awdl_peer_op", wl_awdl_peer_op, -1, WLC_SET_VAR,
|
|
"add or delete awdl peer.\n"
|
|
"\tUsage: \twl awdl_peer_op add <peer addr> [<TLVs hex string>]\n"
|
|
"\t\twl awdl_peer_op del <peer addr>\n"},
|
|
{"awdl_oob_af", wl_awdl_oob_af, -1, WLC_SET_VAR,
|
|
"Send an out of band AWDL action frame.\n"
|
|
"\tUsage: \twl awdl_oob_af <bssid> <dst_mac> <channel> <dwell_time>\n"
|
|
"\t\t <flags> <pkt_lifetime> <tx_rate> <max_retries>\n"
|
|
"\t\t <hex payload>\n"},
|
|
{"awdl_aw_ap_align", wl_awdl_aw_ap_align, -1, -1,
|
|
"Set/Get AWDL Availability window AP alignment.\n"
|
|
"\tUsage: \twl awdl_aw_ap_align <enabled> <offset> [align_on_dtime]\n"},
|
|
{"awdl_uct_test", wl_awdl_uct_test, -1, WLC_SET_VAR,
|
|
"Set AW interval and offset.\n"
|
|
"\tUsage: \twl awdl_uct_test <interval> <offset>\n"},
|
|
|
|
{ "awdl_stats", wl_awdl_counters, WLC_GET_VAR, -1,
|
|
"Return awdl counter values" },
|
|
{ "awdl_uct_stats", wl_awdl_uct_counters, WLC_GET_VAR, -1,
|
|
"Return awdl uct counter values" },
|
|
#ifdef WLAWDL_LATENCY_SUPPORT
|
|
{ "awdl_tx_latency_clr", wl_awdl_tx_latency_clr, -1, -1,
|
|
"Clear awdl tx latency (in ms)" },
|
|
#endif
|
|
#endif /* WLAWDL */
|
|
{ "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"
|
|
"\toffset: Integer. Offset within received packets to start matching.\n"
|
|
"\tpolarity: Set to 1 to negate match result. 0 is default.\n"
|
|
"\tbitmask: Hex bitmask that indicates which bits of 'pattern' to match. Must be same\n"
|
|
"\t\tsize as 'pattern'. Bit 0 of bitmask corresponds to bit 0 of pattern, etc.\n"
|
|
"\t\tIf bit N of bitmask is 0, then do *not* match bit N of the pattern with\n"
|
|
"\t\tthe received payload. If bit N of bitmask is 1, then perform match.\n"
|
|
"\tpattern: Hex pattern to match." },
|
|
{ "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)"},
|
|
{ "wl_tcpkeepalive_conn", wl_tcp_keep_conn_set, -1, WLC_SET_VAR,
|
|
"Set TCP Keep-Alive with connection data.\n"
|
|
"\tUsage: wl tcp_keep_set [smac][dmac][sip][dip][sport][dport][seq][ack][wnd]\n"},
|
|
{ "wl_tcpkeepalive_timers", wl_tcp_keep_timers_set, -1, WLC_SET_VAR,
|
|
"Set TCP Keep-Alive timers.\n"
|
|
"\tUsage: wl tcp_keep_set [interval][retry interval][retry count]\n"},
|
|
{ "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>"},
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
{"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\n"},
|
|
|
|
{"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\n"},
|
|
|
|
{"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\n"},
|
|
|
|
{"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\n"},
|
|
|
|
{"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\n"},
|
|
|
|
{"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\n"},
|
|
|
|
{"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\n"},
|
|
|
|
{"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 \n"},
|
|
|
|
{"trf_mgmt_stats_clear", wl_trf_mgmt_stats_clear, -1, WLC_SET_VAR,
|
|
"Clears traffic management statistics.\n"
|
|
"\tUsage: wl trf_mgmt_stats_clear\n"},
|
|
|
|
{"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 \n"},
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
{ "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"},
|
|
#ifdef CLMDOWNLOAD
|
|
{ "clmload", wl_clmload, -1, WLC_SET_VAR,
|
|
"Used to download CLM data onto the dongle"},
|
|
#endif /* CLMDOWNLOAD */
|
|
{ "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
|
|
{ "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"},
|
|
{ "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"},
|
|
#ifdef WLEXTLOG
|
|
{ "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"},
|
|
#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)"
|
|
},
|
|
{ "ledbh", wl_ledbh, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set/get led behavior\n"
|
|
"\tUsage: wl ledbh [0-3] [0-15]"},
|
|
{ "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"
|
|
},
|
|
{"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"
|
|
},
|
|
{ "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]"},
|
|
#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"
|
|
},
|
|
{ "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"
|
|
},
|
|
{ "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"},
|
|
{ "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_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]"},
|
|
{ "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,
|
|
"deprecated, please use wnm_bsstrans_query"},
|
|
{ "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_tfs_set", wl_wnm_tfs_set, -1, WLC_SET_VAR,
|
|
"If <tfs_id> is set, add pending TCLASs (after tclas_add) to this filter set and create\n"
|
|
"or reinitialize it. If <send> is set, register all filter set on AP to enable TFS.\n\n"
|
|
"\tUsage: wl wnm_tfs_set <send> [tfs_id action [tc_pro]]\n"
|
|
"\t\tsend: 0: store filter, 1: send all stored filters to AP\n"
|
|
"\t\ttfs_id: ID to assign to the filter set (if TCLAS added)\n"
|
|
"\t\t or existing ID to append as new filter to the set , 0 for all filters\n"
|
|
"\t\taction: TFS action bitfiled: bit 0 -> delete after match, bit 1 -> notify\n"
|
|
"\t\ttc_pro: TCLAS processing element (if several TCLAS added)"
|
|
},
|
|
{ "wnm_tfs_status", wl_wnm_tfs_status, WLC_GET_VAR, -1,
|
|
"list all TFS filters and provide their internal and AP status\n"
|
|
"\tUsage: wl wl_wnm_tfs_status"
|
|
},
|
|
{ "wnm_tfs_term", wl_wnm_tfs_term, -1, WLC_SET_VAR,
|
|
"Disable registered TFS filter on AP side and optionally discard them\n"
|
|
"\tUsage: wl wnm_tfs_term <flags> [<tfs_id>]\n"
|
|
"\t\tflags: 1: send immendiatly; 2: also delete filter internally\n"
|
|
"\t\ttfs_id: filter to disable/delete, 0 for all filters"
|
|
},
|
|
{ "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)\n"
|
|
"\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 desc 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.\n"
|
|
},
|
|
#ifdef WLP2P
|
|
{ "p2p_ssid", wl_ssid, -1, 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)"
|
|
},
|
|
#endif /* WLP2P */
|
|
{ "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>"},
|
|
{"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"
|
|
},
|
|
{"txdelay_params", wl_txdelay_params, WLC_GET_VAR, -1,
|
|
"get chanim stats \n"
|
|
"\t Usage: wl txdelay_params ratio cnt period tune"
|
|
},
|
|
{"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>]"},
|
|
{ "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."},
|
|
#if defined(BCMINTERNAL)
|
|
{ "tpc_rpt_override", wl_tpc_rpt_override, WLC_GET_VAR, WLC_SET_VAR,
|
|
"set/get tpc report txpwr and linkmargin values\n"
|
|
"\tUsage: wl tpc_rpt_override [<txpwr> <link_margin>]"},
|
|
#endif /* BCMINTERNAL */
|
|
{ "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"},
|
|
#ifdef BCMINTERNAL
|
|
{ "mfp_bip_test", wl_mfp_bip_test, WLC_GET_VAR, WLC_SET_VAR,
|
|
"bip test\n"
|
|
"\tUsage: wl mfp_bip_test"},
|
|
#endif
|
|
{ "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"},
|
|
{ "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
|
|
{ "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"
|
|
},
|
|
{ "hsic_download", hsic_download, WLC_GET_VAR, WLC_SET_VAR,
|
|
"hsic_download <binfile> <varsfile>\n"
|
|
"\thsic_download file to dongle ram and start CPU\n"
|
|
"\tvars file will replace vars parsed from the CIS\n"
|
|
},
|
|
{ "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>\n"},
|
|
#ifdef WLTDLS
|
|
{ "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>"},
|
|
#endif /* WLTDLS */
|
|
{ "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"},
|
|
{ "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" },
|
|
{ "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" },
|
|
{ "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>" },
|
|
{ "wowl_wakeup_reason", wl_wowl_wake_reason, WLC_GET_VAR, -1 /* Set not reqd */,
|
|
"Returns pattern id and associated wakeup reason"},
|
|
{ "mempool", wlu_mempool, WLC_GET_VAR, -1,
|
|
"Get memory pool statistics" },
|
|
#ifdef BCMINTERNAL
|
|
{ "sr_enable", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
|
|
"\tGet/Set SaveRestore functionality"},
|
|
#endif
|
|
#endif /* !ATE_BUILD */
|
|
#ifdef BCMINTERNAL
|
|
{ "nwoe_ifconfig", wl_nwoe_ifconfig, WLC_GET_VAR, WLC_SET_VAR,
|
|
"Configure the network offload interface, or display current settings\n"
|
|
"\tUsage: wl nwoe_ifconfig [<ip> <netmask> <gateway>]\n"},
|
|
#endif
|
|
#ifdef WLNDOE
|
|
{ "nd_hostip", wl_hostipv6, WLC_GET_VAR, WLC_SET_VAR,
|
|
"Add a local host-ipv6 address or display them"},
|
|
{ "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"},
|
|
#endif
|
|
#ifndef ATE_BUILD
|
|
{ "lpc_params", wl_lpc_params, WLC_GET_VAR, WLC_SET_VAR,
|
|
"Set/Get Link Power Control params\n"
|
|
"\tUsage: wl lpc_params <rate_stab_thresh>\n"
|
|
"\t\t<pwr_stab_thresh> <lpc_exp_time>\n"
|
|
"\t\t<pwrup_slow_step> <pwrup_fast_step> <pwrdn_slow_step>\n"},
|
|
{ "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."},
|
|
{ "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"
|
|
},
|
|
{ "rmc_ackmac", wl_mcast_ackmac, WLC_GET_VAR, WLC_SET_VAR,
|
|
"Set/Get ACK required multicast mac address\n"
|
|
"\tusage: wl mcast_ackmac [multicast mac address]\n"
|
|
},
|
|
{ "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\n"
|
|
},
|
|
{ "rmc_status", wl_mcast_status, WLC_GET_VAR, -1,
|
|
"Display reliable multicast client status\n"
|
|
},
|
|
#if defined(WL_PROXDETECT)
|
|
{ "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\n"
|
|
"\tExample: wl proxd 1 initiator"},
|
|
{ "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_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]"},
|
|
#endif /* WL_PROXDETECT */
|
|
#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
|
|
{ "patrim", wl_patrim, WLC_GET_VAR, -1,
|
|
"Get PA trim option" },
|
|
#endif /* !ATE_BUILD */
|
|
{ "pm2_sleep_ret_ext", wl_sleep_ret_ext, WLC_GET_VAR, WLC_SET_VAR,
|
|
"Get/Set Dynamic Fast Return To Sleep params"},
|
|
#if defined(BCMINTERNAL) || defined(WLTEST) || defined(BCMDBG_DUMP)
|
|
{ "btcx_clear_dump", wl_var_void, -1, WLC_SET_VAR,
|
|
"clear btcoex debug counters"},
|
|
#endif
|
|
{ NULL, NULL, 0, 0, NULL }
|
|
};
|
|
|
|
cmd_t wl_varcmd = {"var", wl_varint, -1, -1, "unrecognized name, type -h for help"};
|
|
|
|
#ifndef ATE_BUILD
|
|
#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 */
|
|
#endif /* !ATE_BUILD */
|
|
|
|
/* initialize stuff needed before processing the command */
|
|
void
|
|
wl_cmd_init(void)
|
|
{
|
|
int_fmt = INT_FMT_DEC;
|
|
}
|
|
|
|
|
|
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;
|
|
batch_in_client = FALSE;
|
|
init_cmd_batchingmode();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
/* 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;
|
|
}
|
|
/* 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);
|
|
|
|
for (cmd = wl_cmds, nrows = 0; 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 -1;
|
|
}
|
|
for (i = 0; i < len; i++)
|
|
*(list_buf+i) = 0;
|
|
|
|
row = col = 0;
|
|
for (letter = 'a'; letter < 'z'; letter++) {
|
|
for (cmd = wl_cmds; 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;
|
|
|
|
/* 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 (cmd = wl_cmds; 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] <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, "\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 -1 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.
|
|
*/
|
|
static 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 -1;
|
|
|
|
/* 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 -1;
|
|
}
|
|
*bsscfg_idx = mo.val;
|
|
*consumed = mo.consumed;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
static 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);
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
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 -1;
|
|
}
|
|
}
|
|
|
|
val = htod32(val);
|
|
ret = wlu_set(wl, cmd->set, &val, sizeof(int));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef D11AC_IOTYPES
|
|
/* 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;
|
|
}
|
|
#endif
|
|
|
|
/* given a chanspec value, do the endian and chanspec version conversion to
|
|
* a chanspec_t value
|
|
* Returns INVCHANSPEC on error
|
|
*/
|
|
static chanspec_t
|
|
wl_chspec_to_driver(chanspec_t chanspec)
|
|
{
|
|
#ifdef D11AC_IOTYPES
|
|
if (ioctl_version == 1) {
|
|
chanspec = wl_chspec_to_legacy(chanspec);
|
|
if (chanspec == INVCHANSPEC) {
|
|
return chanspec;
|
|
}
|
|
}
|
|
#endif
|
|
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
|
|
*/
|
|
static uint32
|
|
wl_chspec32_to_driver(chanspec_t chanspec)
|
|
{
|
|
uint32 val;
|
|
#ifdef D11AC_IOTYPES
|
|
if (ioctl_version == 1) {
|
|
chanspec = wl_chspec_to_legacy(chanspec);
|
|
if (chanspec == INVCHANSPEC) {
|
|
return chanspec;
|
|
}
|
|
}
|
|
#endif
|
|
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
|
|
*/
|
|
static chanspec_t
|
|
wl_chspec_from_driver(chanspec_t chanspec)
|
|
{
|
|
chanspec = dtohchanspec(chanspec);
|
|
#ifdef D11AC_IOTYPES
|
|
if (ioctl_version == 1) {
|
|
chanspec = wl_chspec_from_legacy(chanspec);
|
|
}
|
|
#endif
|
|
|
|
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
|
|
*/
|
|
static chanspec_t
|
|
wl_chspec32_from_driver(uint32 chanspec32)
|
|
{
|
|
chanspec_t chanspec;
|
|
|
|
chanspec = (chanspec_t)dtoh32(chanspec32);
|
|
#ifdef D11AC_IOTYPES
|
|
if (ioctl_version == 1) {
|
|
chanspec = wl_chspec_from_legacy(chanspec);
|
|
}
|
|
#endif
|
|
return chanspec;
|
|
}
|
|
|
|
|
|
#ifdef CLMDOWNLOAD
|
|
/*
|
|
Generic interface for downloading required data onto the dongle
|
|
*/
|
|
int
|
|
download2dongle(void *wl, 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);
|
|
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, "generic_dload",
|
|
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;
|
|
|
|
download2dongle(wl, DL_TYPE_CLM, new_buf,
|
|
chunk_len + clm_info_offset + chunk_offset);
|
|
|
|
datalen = datalen - chunk_len;
|
|
} while (datalen > 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;
|
|
struct stat filest;
|
|
unsigned long status = 0;
|
|
unsigned char *new_buf = NULL;
|
|
uint32 clm_data_len;
|
|
unsigned char *new_ptr;
|
|
int ifd;
|
|
const char trx_magic_string[] = {'H', 'D', 'R', '0'};
|
|
const char clm_magic_string[] = {'C', 'L', 'M', ' ', 'D', 'A', 'T', 'A'};
|
|
|
|
if (clmfn == NULL) {
|
|
printf("Reverting any previous %s CLM download\n",
|
|
ds_id ? "incremental":"base");
|
|
/* Performing a zero length CLM download reverts the previous download
|
|
* of that type.
|
|
*/
|
|
clm_data_len = 0;
|
|
new_ptr = NULL;
|
|
goto do_clm_load;
|
|
}
|
|
|
|
/* Open the clm download file */
|
|
if (!(fp = fopen(clmfn, "rb"))) {
|
|
fprintf(stderr, "unable to open input file %s\n", clmfn);
|
|
ret = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
/* XXX REVISIT fstat is a linux/unix, not a stdio function. This should
|
|
* be replace with an appropriate fseek(fp, 0L, SEEK_END), ftell(fp),
|
|
* fseek(fp, 0L, SEEK_SET) sequence. I am not doing this at this time as I
|
|
* don't want to mix it with the real change, reading two formats of CLM files.
|
|
* Making this change also invovles removing the fstat related includes which
|
|
* according to the man pages are sys/types.h, sys/stat.h and unistd.h (Argh!)
|
|
* To remove these means you must make sure that they are not elsewhere in
|
|
* the file (or other includes) and worry that this program is built on
|
|
* many different OS's. I am not ready to do this as part of this other work.
|
|
*/
|
|
ifd = fileno(fp);
|
|
|
|
if (fstat(ifd, &filest)) {
|
|
fprintf(stderr, "fstat on input file %s return error %s\n", clmfn, strerror(errno));
|
|
ret = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
clm_filelen = filest.st_size;
|
|
|
|
if (clm_filelen == 0) {
|
|
fprintf(stderr, "input file %s is empty (i.e. zero length)\n", clmfn);
|
|
ret = -EINVAL;
|
|
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 = -ENOMEM;
|
|
goto error;
|
|
}
|
|
|
|
/* We can read the pure CLM binary file or a trx format wrapped CLM binary.
|
|
* The CLM download iovar receives the CLM binary file content so any difference
|
|
* in processing is limited to our local processing.
|
|
*
|
|
* The trx wrapped CLM binary was the original approach but it now being phased
|
|
* out for the simpler, non-wrapped binary. To maintain backward compatibility
|
|
* for some period of time, wlu is accepting both formats transparently to the
|
|
* user. The two file types are identified by the magic word(s) at the beginning
|
|
* of each. A trx file starts with "HDR0" and a CLM binary starts with "CLM DATA".
|
|
*/
|
|
|
|
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 = -EINVAL;
|
|
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 = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
/* trx wrapped CLM binary file? Look for the 'HDR0' magic string */
|
|
if (memcmp(new_buf, trx_magic_string, sizeof(trx_magic_string)) == 0)
|
|
{
|
|
struct trx_header *trx;
|
|
|
|
/* Extract trx header */
|
|
trx = (struct trx_header *)new_buf;
|
|
|
|
/* The clm binary data follows the trx header and the length is the trx
|
|
* header's first offset field. All other trx header files are unused.
|
|
* Note length in the offset doesn't include the trx header or any
|
|
* trailing/padding zeroes add by the trx format.
|
|
*/
|
|
clm_data_len = trx->offsets[0];
|
|
|
|
/* A sanity testing on length value in the trx offset field. It can't
|
|
* indicate the following CLM data is bigger than the actual file.
|
|
*/
|
|
if (clm_data_len + sizeof(struct trx_header) > clm_filelen) {
|
|
fprintf(stderr,
|
|
"input file %s trx offset[0] is inconsistent"
|
|
" for being a CLM file\n",
|
|
clmfn);
|
|
ret = -1;
|
|
goto error;
|
|
}
|
|
new_ptr = new_buf + sizeof(struct trx_header);
|
|
} 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;
|
|
} else {
|
|
fprintf(stderr, "input file is missing trx or CLM binary magic string\n");
|
|
ret = -1;
|
|
goto error;
|
|
}
|
|
|
|
printf("Downloading file %s as a %s CLM\n", clmfn, ds_id ? "incremental":"base");
|
|
|
|
do_clm_load:
|
|
dload_clm(wl, clm_data_len, new_ptr, ds_id);
|
|
|
|
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 = 1;
|
|
|
|
++argv;
|
|
if (cmd->set == -1)
|
|
return -1;
|
|
{
|
|
int ds_id = atoi(*argv);
|
|
char* fname = *++argv;
|
|
|
|
if ((ds_id == 0) || (ds_id == 1))
|
|
process_clm_data(wl, fname, ds_id);
|
|
}
|
|
return ret;
|
|
}
|
|
#endif /* CLMDOWNLOAD */
|
|
|
|
/* Set or Get a BSS Configuration idexed integer, with an optional config index argument:
|
|
* wl xxx [-C N]|[--cfg=N] <integer>
|
|
*
|
|
* Option:
|
|
* -C N
|
|
* --cfg==N
|
|
* --config==N
|
|
* --configuration==N
|
|
* specify the config index N
|
|
* If cfg index is not given, the "bsscfg:" iovar prefix is not used.
|
|
* If cfg index is not given, and the cmd->set value is not WLC_SET_VAR, then
|
|
* this funtion will support a legacy IOCTL wl_int() call for the cmd->set and
|
|
* cmd->get ioctl commands.
|
|
*/
|
|
static 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 -1;
|
|
}
|
|
}
|
|
|
|
if (consumed == 0)
|
|
ret = wlu_iovar_setint(wl, val_name, val);
|
|
else
|
|
ret = wl_bssiovar_setint(wl, val_name, bsscfg_idx, val);
|
|
}
|
|
|
|
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, "ap"))
|
|
val = 3;
|
|
else if (!stricmp(*argv, "sta"))
|
|
val = 2;
|
|
else if (!stricmp(*argv, "up"))
|
|
val = 1;
|
|
else if (!stricmp(*argv, "down"))
|
|
val = 0;
|
|
else if (!stricmp(*argv, "del"))
|
|
val = -1;
|
|
else {
|
|
val = strtol(*argv, &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
/* not all the value string was parsed by strtol */
|
|
return -1;
|
|
}
|
|
}
|
|
bss_setbuf.cfg = htod32(bsscfg_idx);
|
|
bss_setbuf.val = htod32(val);
|
|
|
|
return wlu_iovar_set(wl, val_name, &bss_setbuf, sizeof(bss_setbuf));
|
|
}
|
|
}
|
|
|
|
static int
|
|
wl_ap_bsscfg(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char *endptr;
|
|
const char *val_name = "ap_bss";
|
|
int bsscfg_idx = 0;
|
|
int val;
|
|
int consumed;
|
|
int ret;
|
|
struct {
|
|
int cfg;
|
|
int val;
|
|
struct ether_addr ea;
|
|
} bss_setbuf;
|
|
|
|
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;
|
|
}
|
|
|
|
memset(&bss_setbuf, 0, sizeof(bss_setbuf));
|
|
|
|
if (!*argv) {
|
|
/* By default up and auto-alloc macaddr */
|
|
val = 0;
|
|
} else {
|
|
if (!stricmp(*argv, "create"))
|
|
val = 0;
|
|
else if (!stricmp(*argv, "destroy"))
|
|
val = -1;
|
|
else {
|
|
val = strtol(*argv, &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
/* not all the value string was parsed by strtol */
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
bss_setbuf.cfg = htod32(bsscfg_idx);
|
|
bss_setbuf.val = htod32(val);
|
|
|
|
/* check for mac-addr or SSID */
|
|
if ((val == 0) && argv[1]) {
|
|
miniopt_t to;
|
|
const char* fn_name = "ap_bss";
|
|
int opt_err;
|
|
|
|
argv++;
|
|
miniopt_init(&to, fn_name, NULL, FALSE);
|
|
while ((opt_err = miniopt(&to, argv)) != -1) {
|
|
if (opt_err == 1) {
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
argv += to.consumed;
|
|
|
|
if (to.opt == 'm') {
|
|
if (!wl_ether_atoe(to.valstr, &bss_setbuf.ea)) {
|
|
printf(" ERROR: no valid ether addr provided\n");
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((ret = wlu_iovar_setbuf(wl, val_name, &bss_setbuf, sizeof(bss_setbuf),
|
|
buf, WLC_IOCTL_MAXLEN)) == BCME_OK) {
|
|
memcpy(&val, ((char *)buf + strlen(val_name) + 1), sizeof(val));
|
|
val = dtoh32(val);
|
|
if (val >= 0) printf("Interface index : %d\n", val);
|
|
}
|
|
exit:
|
|
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;
|
|
#ifdef BCMINTERNAL
|
|
case GMODE_B_DEFERRED:
|
|
gconfig = "54g B Deferred";
|
|
break;
|
|
#endif
|
|
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;
|
|
#ifdef BCMINTERNAL
|
|
else if (!strnicmp(*argv, "bdefer", 6))
|
|
val = GMODE_B_DEFERRED;
|
|
#endif
|
|
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 -1;
|
|
}
|
|
}
|
|
|
|
/* Set the gmode configration */
|
|
val = htod32(val);
|
|
if ((ret = wlu_set(wl, cmd->set, &val, sizeof(val))))
|
|
goto done;
|
|
|
|
}
|
|
|
|
done:
|
|
return (ret);
|
|
}
|
|
|
|
#ifdef BCMSDIO
|
|
static dbg_msg_t wl_sd_msgs[] = {
|
|
{SDH_ERROR_VAL, "error"},
|
|
{SDH_TRACE_VAL, "trace"},
|
|
{SDH_INFO_VAL, "info"},
|
|
{SDH_DATA_VAL, "data"},
|
|
{SDH_CTRL_VAL, "control"}
|
|
};
|
|
|
|
static int
|
|
wl_sd_msglevel(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret, i;
|
|
uint val, last_val = 0, msglevel_add = 0, msglevel_del = 0;
|
|
char *endptr = NULL;
|
|
int msglevel;
|
|
dbg_msg_t *dbg_msg = wl_sd_msgs;
|
|
|
|
if ((ret = wlu_iovar_getint(wl, cmd->name, &msglevel)) < 0)
|
|
return (ret);
|
|
|
|
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);
|
|
/* 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 == '-')
|
|
msglevel_del |= val;
|
|
else
|
|
msglevel_add |= val;
|
|
++argv;
|
|
}
|
|
|
|
msglevel &= ~msglevel_del;
|
|
msglevel |= msglevel_add;
|
|
|
|
return (wlu_iovar_setint(wl, cmd->name, msglevel));
|
|
|
|
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;
|
|
}
|
|
|
|
static int
|
|
wl_sd_blocksize(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret;
|
|
int argc;
|
|
char *endptr = NULL;
|
|
void *ptr = NULL;
|
|
int func, size;
|
|
|
|
/* arg count */
|
|
for (argc = 0; argv[argc]; argc++);
|
|
argc--;
|
|
|
|
if (argc < 1 || argc > 2) {
|
|
printf("required args: function [size] (size 0 means max)\n");
|
|
return -1;
|
|
}
|
|
|
|
func = strtol(argv[1], &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
printf("Invaild function: %s\n", argv[1]);
|
|
return -1;
|
|
}
|
|
|
|
if (argc > 1) {
|
|
size = strtol(argv[2], &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
printf("Invalid size: %s\n", argv[1]);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (argc == 1) {
|
|
func = htod32(func);
|
|
if ((ret = wlu_var_getbuf(wl, cmd->name, &func, sizeof(func), &ptr)) >= 0)
|
|
printf("Function %d block size: %d\n", func, dtoh32(*(int*)ptr));
|
|
} else {
|
|
printf("Setting function %d block size to %d\n", func, size);
|
|
size &= 0x0000ffff; size |= (func << 16);
|
|
size = htod32(size);
|
|
ret = wlu_var_setbuf(wl, cmd->name, &size, sizeof(size));
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
wl_sd_mode(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret;
|
|
int argc;
|
|
int sdmode;
|
|
|
|
/* arg count */
|
|
for (argc = 0; argv[argc]; argc++);
|
|
argc--;
|
|
|
|
if (argv[1]) {
|
|
if (!strcmp(argv[1], "spi")) {
|
|
strcpy(argv[1], "0");
|
|
} else if (!strcmp(argv[1], "sd1")) {
|
|
strcpy(argv[1], "1");
|
|
} else if (!strcmp(argv[1], "sd4")) {
|
|
strcpy(argv[1], "2");
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
ret = wl_var_setint(wl, cmd, argv);
|
|
|
|
} else {
|
|
if ((ret = wl_var_get(wl, cmd, argv))) {
|
|
return (ret);
|
|
} else {
|
|
sdmode = dtoh32(*(int32*)buf);
|
|
|
|
printf("SD Mode is: %s\n",
|
|
sdmode == 0 ? "SPI"
|
|
: sdmode == 1 ? "SD1"
|
|
: sdmode == 2 ? "SD4" : "Unknown");
|
|
}
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
wl_sd_reg(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret;
|
|
sdreg_t sdreg;
|
|
char *endptr = NULL;
|
|
uint argc;
|
|
void *ptr = NULL;
|
|
|
|
memset(&sdreg, 0, sizeof(sdreg));
|
|
|
|
/* arg count */
|
|
for (argc = 0; argv[argc]; argc++);
|
|
argc--;
|
|
|
|
/* hostreg: offset [value]; devreg: func offset [value] */
|
|
if (!strcmp(cmd->name, "sd_hostreg")) {
|
|
argv++;
|
|
if (argc < 1) {
|
|
printf("required args: offset [value]\n");
|
|
return -1;
|
|
}
|
|
|
|
} else if (!strcmp(cmd->name, "sd_devreg")) {
|
|
argv++;
|
|
if (argc < 2) {
|
|
printf("required args: func offset [value]\n");
|
|
return -1;
|
|
}
|
|
|
|
sdreg.func = htod32(strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0') {
|
|
printf("Bogus endptr\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
sdreg.offset = htod32(strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0') {
|
|
printf("Bogus endptr 1\n");
|
|
return -1;
|
|
}
|
|
|
|
/* third arg: value */
|
|
if (*argv) {
|
|
sdreg.value = htod32(strtol(*argv, &endptr, 0));
|
|
if (*endptr != '\0') {
|
|
printf("Bogus endptr 2\n");
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
/* no third arg means get, otherwise set */
|
|
if (!*argv) {
|
|
if ((ret = wlu_var_getbuf(wl, cmd->name, &sdreg, sizeof(sdreg), &ptr)) >= 0)
|
|
printf("0x%x\n", dtoh32(*(int *)ptr));
|
|
} else {
|
|
ret = wlu_var_setbuf(wl, cmd->name, &sdreg, sizeof(sdreg));
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
#endif /* BCMSDIO */
|
|
|
|
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 -1;
|
|
}
|
|
|
|
param[0] = strtol(argv[1], &endptr, 0);
|
|
if (*endptr != '\0' || (param[0] & ~0x003FFE00) != 0) {
|
|
printf("Invaild virtual address: %s\n", argv[1]);
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
} 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);
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
static 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 -1;
|
|
|
|
reg = strtol(argv[0], &endptr, 0);
|
|
|
|
if (*endptr != '\0')
|
|
return -1;
|
|
|
|
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], "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 (-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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], "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 (-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
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_gpioout(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
uint32 mask;
|
|
uint32 val;
|
|
char *endptr = NULL;
|
|
uint argc;
|
|
uint32 *int_ptr;
|
|
#ifdef ATE_BUILD
|
|
uint32 params[2];
|
|
#endif
|
|
|
|
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;
|
|
|
|
if (wlu_iovar_get(wl, "gpioout", buf, sizeof(uint32) *3))
|
|
return -1;
|
|
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 -1;
|
|
|
|
mask = strtoul(argv[0], &endptr, 0);
|
|
if (*endptr != '\0')
|
|
return -1;
|
|
|
|
val = strtoul(argv[1], &endptr, 0);
|
|
if (*endptr != '\0')
|
|
return -1;
|
|
|
|
if ((~mask & val) != 0)
|
|
return -1;
|
|
|
|
#ifdef ATE_BUILD
|
|
int_ptr = (uint32 *)params;
|
|
#else
|
|
int_ptr = (uint32 *)buf;
|
|
#endif
|
|
mask = htod32(mask);
|
|
memcpy(int_ptr, (const void *)&mask, sizeof(mask));
|
|
int_ptr++;
|
|
val = htod32(val);
|
|
memcpy(int_ptr, (const void *)&val, sizeof(val));
|
|
|
|
#ifdef ATE_BUILD
|
|
return (wlu_var_setbuf(wl, "gpioout", params, sizeof(uint32) *2));
|
|
#else
|
|
return wlu_iovar_set(wl, "gpioout", buf, sizeof(uint32) *2);
|
|
#endif /* ATE_BUILD */
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
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 -1;
|
|
|
|
reg = strtol(argv[0], &endptr, 0);
|
|
if (*endptr != '\0')
|
|
return -1;
|
|
|
|
/* required arg: reg size */
|
|
if (argc < 2)
|
|
return (-1);
|
|
|
|
size = strtol(argv[1], &endptr, 0);
|
|
if (*endptr != '\0')
|
|
return -1;
|
|
|
|
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 -1;
|
|
}
|
|
|
|
}
|
|
|
|
/* 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 (-1);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* 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 (-1);
|
|
}
|
|
}
|
|
|
|
/* 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 (-1);
|
|
}
|
|
|
|
/* 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 (-1);
|
|
}
|
|
|
|
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 -1;
|
|
if ((ret = wlu_get(wl, cmd->get, &scb_val, sizeof(scb_val))) < 0)
|
|
return ret;
|
|
printf("%d\n", dtoh32(scb_val.val));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*argv) {
|
|
/* too many parameters */
|
|
return -1;
|
|
}
|
|
|
|
rssi.rate_limit_msec = htod32(rssi.rate_limit_msec);
|
|
ret = wlu_var_setbuf(wl, cmd->name, &rssi, sizeof(rssi));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
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;
|
|
|
|
if (!*++argv) {
|
|
/* Get */
|
|
void *ptr = NULL;
|
|
|
|
if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &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");
|
|
}
|
|
} else {
|
|
ret = USAGE_ERROR;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* Commands that take a MAC address */
|
|
static int
|
|
wl_mac(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 -1;
|
|
return wlu_set(wl, cmd->set, &ea, ETHER_ADDR_LEN);
|
|
}
|
|
}
|
|
|
|
/* IO variables that take a MAC address */
|
|
static 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 -1;
|
|
}
|
|
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)
|
|
{
|
|
switch (iov_pktq_log->version)
|
|
{
|
|
case 0x04:
|
|
{
|
|
const char* title[2] = {"", ""};
|
|
const char* form[2] = {"", ""};
|
|
char* headings = "";
|
|
|
|
uint8 index, prec;
|
|
pktq_log_format_v04_t* logv04 = &iov_pktq_log->pktq_log.v04;
|
|
uint32 prec_mask = 0;
|
|
|
|
char marker[4] = "[X]";
|
|
|
|
headings = &logv04->headings[0];
|
|
|
|
/* long form */
|
|
title[0] = "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 (+v%d)\n";
|
|
form[0] = " %02u: %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, "
|
|
"%7u, %7u, %7u, %7u, %7u, %7u, %7u, %8.2f, %8.2f,"
|
|
" %8.2f\n";
|
|
|
|
/* short form */
|
|
title[1] = "prec: rqstd, stored, dropped, retried,"
|
|
" rtsfail,rtrydrop, psretry, acked,utlisatn,"
|
|
"q length,Data Mbits/s,Phy Mbits/s (v%d)\n";
|
|
form[1] = " %02u: %7u, %7u, %7u, %7u, %7u, %7u, %7u,"
|
|
" %7u, %7u, %7u, %8.2f, %8.2f\n";
|
|
|
|
for (index = 0; index < (uint8)iov_pktq_log->params.num_addrs; index++) {
|
|
|
|
char* heading_start;
|
|
char* heading_end;
|
|
uint32 num_prec = 0;
|
|
|
|
prec_mask = logv04->counter_info[index];
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
num_prec = logv04->num_prec[index];
|
|
|
|
/* Note that this is zero if the data is invalid */
|
|
if (num_prec) {
|
|
|
|
/* check for short form or long form (top bit set) */
|
|
fprintf(stdout,
|
|
iov_pktq_log->params.addr_type[index] & 0x80 ?
|
|
title[0] : title [1], 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_v04_t* counters = 0;
|
|
uint32 try_count;
|
|
|
|
if (!(prec_mask & (1 << prec))) {
|
|
continue;
|
|
}
|
|
|
|
counters = &logv04->counters[index][prec];
|
|
|
|
if (counters->time_delta != 0) {
|
|
/* convert bytes to bits */
|
|
tput = (float)counters->throughput;
|
|
tput *= 8.0;
|
|
|
|
/* converts to rate of bits per us,
|
|
because time_delta is in micro-seconds
|
|
*/
|
|
tput /= (float) counters->time_delta;
|
|
}
|
|
|
|
if (counters->acked) {
|
|
txrate_succ =
|
|
(float)counters->txrate_succ * 0.5;
|
|
txrate_succ /= (float) counters->acked;
|
|
}
|
|
|
|
try_count = counters->acked + counters->retry;
|
|
|
|
if (try_count) {
|
|
txrate_main =
|
|
(float)counters->txrate_main * 0.5;
|
|
txrate_main /= (float) try_count;
|
|
}
|
|
|
|
if (iov_pktq_log->params.addr_type[index] & 0x80) {
|
|
/* long form */
|
|
fprintf(stdout, form[0], 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);
|
|
}
|
|
else {
|
|
/* short form */
|
|
fprintf(stdout, form[1], 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);
|
|
}
|
|
}
|
|
fputs("\n", stdout);
|
|
}
|
|
else {
|
|
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]));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
fprintf(stderr, "Unknown/unsupported binary format (%x)\n",
|
|
iov_pktq_log->version);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* IO variables that take MAC addresses (with optional single letter prefix)
|
|
* and output a string buffer
|
|
*/
|
|
static int
|
|
wl_iov_mac_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;
|
|
|
|
if (cmd->get < 0)
|
|
return -1;
|
|
|
|
memset(full_params, 0, sizeof(*full_params));
|
|
|
|
/* only pass up to WL_IOV_MAC_PARAM_LEN parameters */
|
|
while (params->num_addrs < WL_IOV_MAC_PARAM_LEN && *macaddrs) {
|
|
|
|
char* ptr = *macaddrs;
|
|
|
|
/* 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++;
|
|
}
|
|
}
|
|
|
|
/* the prefix C: denotes no given MAC address (to refer to "common") */
|
|
if ((params->addr_type[params->num_addrs] & 0x7F) == 'C') {
|
|
}
|
|
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);
|
|
}
|
|
|
|
if (params->addr_type[params->num_addrs]) {
|
|
uint32 bitmask = 0;
|
|
|
|
while (ptr && (ptr[0] == ',' || ptr[0] == '/') &&
|
|
(ptr[1] >= '0' && ptr[1] <= '9')) {
|
|
|
|
uint8 prec;
|
|
char* endptr = 0;
|
|
|
|
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) {
|
|
bitmask = 0xFFFF;
|
|
}
|
|
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)
|
|
{
|
|
params->addr_type[0] = 'C';
|
|
extra_params->addr_info[0] = 0xFFFF;
|
|
params->num_addrs = 1;
|
|
}
|
|
|
|
/* set a "version" indication (ie extra_params present) */
|
|
params->num_addrs |= (4 << 8);
|
|
|
|
if ((ret = wlu_iovar_getbuf(wl, cmd->name, params,
|
|
sizeof(*params) + sizeof(*extra_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);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
wlu_dump(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret;
|
|
char *dump_buf;
|
|
int bcmerr;
|
|
|
|
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 -1;
|
|
}
|
|
memset(dump_buf, 0, WL_DUMP_BUF_LEN);
|
|
|
|
/* skip the command name */
|
|
argv++;
|
|
|
|
/* XXX: Remove "if (*argv == NULL)" conditional code after 5/20/06
|
|
* when there is no need to run wl command over old driver
|
|
*/
|
|
/* 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) {
|
|
wlu_iovar_getint(wl, "bcmerror", &bcmerr);
|
|
if (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");
|
|
ret = IOCTL_ERROR;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "dump: error on query of dump list\n");
|
|
ret = IOCTL_ERROR;
|
|
}
|
|
}
|
|
} 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, strlen(dump_buf),
|
|
dump_buf, WL_DUMP_BUF_LEN);
|
|
}
|
|
|
|
if (!ret) {
|
|
fputs(dump_buf, stdout);
|
|
}
|
|
|
|
free(dump_buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
wlu_offloads_stats(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret;
|
|
char *dump_buf;
|
|
|
|
if (cmd->get < 0)
|
|
return -1;
|
|
|
|
if (!strcmp(cmd->name, "ol_clr"))
|
|
{
|
|
ret = wlu_iovar_get(wl, cmd->name, NULL, 0);
|
|
return ret;
|
|
}
|
|
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 -1;
|
|
}
|
|
memset(dump_buf, 0, WL_DUMP_BUF_LEN);
|
|
|
|
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++;
|
|
}
|
|
|
|
ret = wlu_iovar_get(wl, cmd->name, dump_buf, WL_DUMP_BUF_LEN);
|
|
|
|
if (!ret) {
|
|
fputs(dump_buf, stdout);
|
|
}
|
|
|
|
free(dump_buf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
static int
|
|
wl_staprio(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret = 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;
|
|
}
|
|
|
|
#ifdef BCMINTERNAL
|
|
static int
|
|
wlu_fixrate(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret = 0;
|
|
link_val_t link_val;
|
|
|
|
if (!*++argv) return -1;
|
|
|
|
/* get link mac address */
|
|
if (!wl_ether_atoe(*argv++, &link_val.ea))
|
|
return -1;
|
|
|
|
link_val.ac = 0xFF;
|
|
if (argv[0]) {
|
|
link_val.ac = atoi(argv[0]);
|
|
if (link_val.ac != -1 && (link_val.ac < 0 || link_val.ac > 3)) {
|
|
printf("ac %d out of range [0, 3] or -1 to indicate all\n", link_val.ac);
|
|
}
|
|
|
|
if (argv[1]) {
|
|
link_val.val = atoi(argv[1]);
|
|
ret = wlu_set(wl, cmd->set, &link_val, sizeof(link_val));
|
|
} else {
|
|
printf("too few parameters.\n");
|
|
}
|
|
} else {
|
|
memcpy(buf, &link_val.ea, sizeof(struct ether_addr));
|
|
if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
|
|
return ret;
|
|
fputs(buf, stdout);
|
|
return 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
wlu_ratedump(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret;
|
|
|
|
if (cmd->get < 0)
|
|
return -1;
|
|
|
|
if (!*++argv) {
|
|
return -1;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv, (struct ether_addr *)buf))
|
|
return -1;
|
|
|
|
if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) {
|
|
fprintf(stderr, "Could not find corresponding scb from given mac address.\n");
|
|
return ret;
|
|
}
|
|
fputs(buf, stdout);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* BCMINTERNAL */
|
|
|
|
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;
|
|
|
|
/* srom has been expanded a few times, at the moment sromrev11 are the largest */
|
|
nw = SROM11_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 -1;
|
|
}
|
|
nw = nb / 2;
|
|
}
|
|
|
|
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] == SROM11_SIGNATURE) {
|
|
nw = SROM11_WORDS;
|
|
} else if (words[SROM10_SIGN] == SROM4_SIGNATURE) {
|
|
nw = SROM10_WORDS;
|
|
} else {
|
|
nw = SROM4_WORDS;
|
|
if ((words[SROM4_SIGN] != SROM4_SIGNATURE) &&
|
|
(words[SROM8_SIGN] != SROM4_SIGNATURE))
|
|
nw = nb ? nw : SROM_WORDS;
|
|
}
|
|
for (i = 0; i < nw; i++) {
|
|
if ((i % 8) == 0)
|
|
printf("\n srom[%03d]: ", i);
|
|
printf("0x%04x ", words[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static 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(_CFE_)
|
|
UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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;
|
|
|
|
erase = !strcmp(*argv, "srclear");
|
|
srcrc = !strcmp(*argv, "srcrc");
|
|
|
|
/* We need at least one arg */
|
|
if (!*++argv)
|
|
return USAGE_ERROR;
|
|
|
|
arg = *argv++;
|
|
|
|
if (erase) {
|
|
if (*argv)
|
|
return 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 BAD_PARAM;
|
|
}
|
|
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 -2;
|
|
}
|
|
|
|
len = fread(srt->buf, 1, SROM_MAX + 1, fp);
|
|
if ((ret = ferror(fp))) {
|
|
printf("\nerror %d reading %s\n", ret, arg);
|
|
ret = -3;
|
|
goto out;
|
|
}
|
|
|
|
if (!feof(fp)) {
|
|
printf("\nFile %s is too large\n", arg);
|
|
ret = -4;
|
|
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 = -5;
|
|
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 = -5;
|
|
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 = -6;
|
|
goto out;
|
|
}
|
|
|
|
srt->byteoff = 0;
|
|
} else {
|
|
if (srcrc) {
|
|
printf("srcrc only takes one arg\n");
|
|
ret = BCME_BADARG;
|
|
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 = -7;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (srt->byteoff & 1) {
|
|
printf("Byte offset (%d) is odd or negative\n", srt->byteoff);
|
|
ret = -8;
|
|
goto out;
|
|
}
|
|
|
|
len = 2 * i;
|
|
if ((srt->byteoff + len) > SROM_MAX) {
|
|
printf("Data extends past %d bytes\n", SROM_MAX);
|
|
ret = -9;
|
|
goto out;
|
|
}
|
|
}
|
|
srt->nbytes = len;
|
|
|
|
if (srcrc) {
|
|
srt->byteoff = 0x55ab; /* Hack for srcrc */
|
|
ret = wlu_get(wl, cmd->get, buf, len + 8);
|
|
printf("0x%x\n", (uint8)buf[0]);
|
|
} else {
|
|
printf("Writing srom. ioctl %d, iolen %d, sroff %d, len %d\n",
|
|
cmd->set, len + 8, srt->byteoff, srt->nbytes);
|
|
|
|
ret = wlu_set(wl, cmd->set, buf, len + 8);
|
|
}
|
|
|
|
out:
|
|
fflush(stdout);
|
|
if (fp)
|
|
fclose(fp);
|
|
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(_CFE_)
|
|
UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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);
|
|
|
|
/* We need extacly one arg */
|
|
if (!*++argv || argv[1])
|
|
return -1;
|
|
|
|
/* 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);
|
|
|
|
cish.source = htod32(0);
|
|
|
|
/* grab the filename arg */
|
|
arg = *argv;
|
|
if (!(fp = fopen(arg, "rb"))) {
|
|
fprintf(stderr, "%s: No such file or directory\n", arg);
|
|
return -2;
|
|
}
|
|
|
|
len = fread(cisdata, 1, SROM_MAX + 1, fp);
|
|
if ((ret = ferror(fp))) {
|
|
printf("\nerror %d reading %s\n", ret, arg);
|
|
ret = -3;
|
|
goto out;
|
|
}
|
|
|
|
if (!feof(fp)) {
|
|
printf("\nFile %s is too large\n", arg);
|
|
ret = -4;
|
|
goto out;
|
|
}
|
|
|
|
/* fill in offset and length */
|
|
cish.byteoff = htod32(0);
|
|
cish.nbytes = htod32(len);
|
|
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(_CFE_)
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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 -1;
|
|
|
|
if (argv[2] && !strcmp(argv[2], "--preview"))
|
|
preview = 1;
|
|
|
|
/* grab byte offset */
|
|
off = (uint32)strtol(argv[0], &endptr, 0);
|
|
if (*endptr != '\0')
|
|
return -1;
|
|
|
|
|
|
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 */
|
|
cish.source = 0;
|
|
cish.byteoff = 0;
|
|
cish.nbytes = 0;
|
|
|
|
/* set up the buffer and do the get (+9 allows space for "ciswrite" string later) */
|
|
memset(buf + 9, 0, WLC_IOCTL_MAXLEN);
|
|
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 (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 */
|
|
cish.source = 0;
|
|
cish.byteoff = 0;
|
|
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 /* _CFE_ */
|
|
}
|
|
|
|
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 = -1;
|
|
goto done;
|
|
}
|
|
if (nbytes > SROM_MAX) {
|
|
printf("Count %d too large\n", nbytes);
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* Prepare the read info */
|
|
cish.source = 0;
|
|
cish.byteoff = 0;
|
|
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 = dtoh32(cish.source);
|
|
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(_CFE_) && !defined(_HNDRTE_) && !defined(__IOPOS__)
|
|
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 = -1;
|
|
} else {
|
|
printf("Wrote %d bytes to %s\n", ret, fname);
|
|
ret = 0;
|
|
}
|
|
fclose(fp);
|
|
} else {
|
|
fprintf(stderr, "Problem opening file %s\n", fname);
|
|
ret = -1;
|
|
}
|
|
}
|
|
#endif /* !(CFE|HNDRTE|IOPOS) -- has stdio filesystem */
|
|
#endif /* BWL_FILESYSTEM_SUPPORT */
|
|
|
|
done:
|
|
return ret;
|
|
}
|
|
|
|
#if defined(linux) || defined(MACOSX) || defined(_CFE_) || defined(_HNDRTE_) || \
|
|
defined(__IOPOS__) || defined(__NetBSD__)
|
|
/* linux, MacOS, NetBSD: ffs is in the standard C library */
|
|
/* CFE, HNDRTE & 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 /* linux, MACOSX, CFE, HNDRTE, IOPOS, NetBSD */
|
|
|
|
#if !defined(_CFE_) && !defined(_HNDRTE_) && !defined(__IOPOS__)
|
|
|
|
/* VX wants prototypes even for static functions. */
|
|
static char* find_pattern(char **argv, const char *pattern, uint *val);
|
|
static char* find_pattern2(char **argv, const char *pattern, uint *val, int vnum);
|
|
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.
|
|
*/
|
|
static 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.
|
|
*/
|
|
static 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;
|
|
}
|
|
|
|
static int
|
|
parsecis(char *b, char **argv, int sromrev)
|
|
{
|
|
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 all the 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; /* XXX CIS rev 8 (low byte) */
|
|
b[cnt++] = 0; /* XXX CIS rev 8 (high byte) */
|
|
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_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;
|
|
|
|
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 /* !(_CFE_ || _HNDRTE_|| __IOPOS__) */
|
|
|
|
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;
|
|
}
|
|
|
|
static int
|
|
wlu_srvar(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
#if defined(_CFE_)
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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 -1;
|
|
|
|
/* Check the cis source */
|
|
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); */
|
|
}
|
|
|
|
/* XXX If driver supports cissource and it's from OTP, consider it as CIS
|
|
* Not support SROM format OTP yet
|
|
*/
|
|
if (buf[0] == WLC_CIS_OTP)
|
|
otp = TRUE;
|
|
if (otp && ro) {
|
|
/* Do the same thing as nvget */
|
|
wl_nvget(wl, cmd, argv);
|
|
return ret;
|
|
}
|
|
|
|
if ((otp && wr) || co) {
|
|
int cnt = 0, err = 0;
|
|
uint sromrev = 8;
|
|
void *p = NULL;
|
|
|
|
/* Find out sromrev from nvram.txt or fakenvram */
|
|
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);
|
|
sromrev = strtoul(p, &q, strncmp(p, "0x", 2) ? 10 : 16);
|
|
} else {
|
|
printf("sromrev not defined in nvram file!\n");
|
|
return BCME_ERROR;
|
|
}
|
|
|
|
/* leave an empty srom_rw_t at the front for backward
|
|
* compatibility
|
|
*/
|
|
if ((cnt = parsecis(buf, argv, sromrev)) <= 0) {
|
|
printf("CIS parse failure!\n");
|
|
return BCME_ERROR;
|
|
}
|
|
|
|
if (!co)
|
|
/* Pass the append buffer to driver */
|
|
ret = wlu_iovar_set(wl, "cisvar", buf, cnt);
|
|
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[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 -2;
|
|
}
|
|
|
|
nw = 0;
|
|
while ((name = *argv++) != NULL) {
|
|
int off, off_base;
|
|
|
|
newval = strchr(name, '=');
|
|
if (newval)
|
|
*newval++ = '\0';
|
|
nlen = strlen(name);
|
|
if ((nlen == 0) || (nlen > 16)) {
|
|
printf("Bad variable name: %s\n", name);
|
|
continue;
|
|
}
|
|
off = 0;
|
|
srv = srvlookup(pci_sromvars, name, nlen + 1, sromrev);
|
|
if (srv->name == NULL) {
|
|
int path;
|
|
|
|
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 >= 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);
|
|
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 /* _CFE_ */
|
|
}
|
|
|
|
/* 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_TXPWR_VAL, "txpwr"},
|
|
{WL_TXPWR_VAL, "pwr"},
|
|
{WL_PORT_VAL, "port"},
|
|
{WL_DUAL_VAL, "dual"},
|
|
{WL_WSEC_VAL, "wsec"},
|
|
{WL_WSEC_DUMP_VAL, "wsec_dump"},
|
|
{WL_LOG_VAL, "log"},
|
|
{WL_NRSSI_VAL, "nrssi"},
|
|
{WL_LOFT_VAL, "loft"},
|
|
{WL_REGULATORY_VAL, "regulatory"},
|
|
{WL_RADAR_VAL, "radar"},
|
|
{WL_MPC_VAL, "mpc"},
|
|
{WL_APSTA_VAL, "apsta"},
|
|
{WL_DFS_VAL, "dfs"},
|
|
#if defined(WLNINTENDO)
|
|
{WL_NITRO_VAL, "nitro"},
|
|
#else
|
|
{WL_MBSS_VAL, "mbss"},
|
|
#endif /* WLNINTENDO */
|
|
{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_DPT_VAL, "dpt"},
|
|
{WL_SCAN_VAL, "scan"},
|
|
{WL_WOWL_VAL, "wowl"},
|
|
{WL_COEX_VAL, "coex"},
|
|
{WL_RTDC_VAL, "rtdc"},
|
|
{WL_PROTO_VAL, "proto"},
|
|
#ifdef WLBTAMP
|
|
{WL_BTA_VAL, "bta"},
|
|
#endif
|
|
{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_MCNX_VAL, "mcnx"},
|
|
{WL_PSTA_VAL, "psta"},
|
|
{WL_TSO_VAL, "tso"},
|
|
{WL_TIMESTAMP_VAL, "time"},
|
|
{WL_LPC_VAL, "lpc"},
|
|
{WL_TXBF_VAL, "txbf"},
|
|
#ifdef WLP2PO
|
|
{WL_P2PO_VAL, "p2po"},
|
|
#endif
|
|
#ifdef WLAWDL
|
|
{WL_AWDL_VAL, "awdl"},
|
|
#endif
|
|
{WL_WNM_VAL, "wnm"},
|
|
{WL_PCIE_VAL, "pcie"},
|
|
{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";
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
/* XXX: Newer drivers have IOVAR for msglevel, */
|
|
/* 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 {
|
|
char c[32] = "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);
|
|
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;
|
|
}
|
|
|
|
/* make sure the PHY msg level here are in sync with wlc_phy_int.h */
|
|
#define WL_PHYHAL_ERROR 0x0001
|
|
#define WL_PHYHAL_TRACE 0x0002
|
|
#define WL_PHYHAL_INFORM 0x0004
|
|
#define WL_PHYHAL_TMP 0x0008
|
|
#define WL_PHYHAL_TXPWR 0x0010
|
|
#define WL_PHYHAL_CAL 0x0020
|
|
#define WL_PHYHAL_ACI 0x0040
|
|
#define WL_PHYHAL_RADAR 0x0080
|
|
#define WL_PHYHAL_THERMAL 0x0100
|
|
#define WL_PHYHAL_PAPD 0x0200
|
|
#define WL_PHYHAL_FCBS 0x0400
|
|
#define WL_PHYHAL_TIMESTAMP 0x8000
|
|
|
|
static phy_msg_t wl_phy_msgs[] = {
|
|
{WL_PHYHAL_ERROR, "error"},
|
|
{WL_PHYHAL_ERROR, "err"},
|
|
{WL_PHYHAL_TRACE, "trace"},
|
|
{WL_PHYHAL_INFORM, "inform"},
|
|
{WL_PHYHAL_TMP, "tmp"},
|
|
{WL_PHYHAL_TXPWR, "txpwr"},
|
|
{WL_PHYHAL_CAL, "cal"},
|
|
{WL_PHYHAL_ACI, "aci"},
|
|
{WL_PHYHAL_RADAR, "radar"},
|
|
{WL_PHYHAL_THERMAL, "thermal"},
|
|
{WL_PHYHAL_PAPD, "papd"},
|
|
{WL_PHYHAL_FCBS, "fcbs"},
|
|
{WL_PHYHAL_TIMESTAMP, "time"},
|
|
{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;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
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 */
|
|
};
|
|
#ifdef D11AC_IOTYPES
|
|
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;
|
|
}
|
|
#endif
|
|
/* 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 */
|
|
static 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" */
|
|
static 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);
|
|
}
|
|
#ifdef D11AC_IOTYPES
|
|
|
|
/* 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* txbf = "";
|
|
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" : "";
|
|
txbf = ((rspec & WL_RSPEC_TXBF) != 0) ? " txbf" : "";
|
|
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";
|
|
}
|
|
|
|
/* 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 %s\n",
|
|
vht, Nss, txexp, bw, stbc, txbf, ldpc, sgi, rspec_auto);
|
|
}
|
|
}
|
|
#endif
|
|
#if !defined(ATE_BUILD) && defined(D11AC_IOTYPES)
|
|
/*
|
|
* Format a ratespec for output of any of the wl_rate() iovars
|
|
*/
|
|
static 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;
|
|
const char* txbf;
|
|
|
|
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" : "";
|
|
txbf = ((rspec & WL_RSPEC_TXBF) != 0) ? " txbf" : "";
|
|
|
|
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 {
|
|
bw = "???";
|
|
}
|
|
|
|
if (rspec == 0) {
|
|
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%s",
|
|
rate, txexp, bw, stbc, txbf, 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%s",
|
|
mcs, Nss, txexp, bw, stbc, txbf, ldpc, sgi);
|
|
} else {
|
|
sprintf(rate_buf, "<unknown encoding for ratespec 0x%08X>", rspec);
|
|
}
|
|
|
|
return rate_buf;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
/* 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 IOCTL_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 BAD_PARAM;
|
|
} else if (list[1] == WLC_BAND_5G)
|
|
name = (char *)aname;
|
|
else if (list[1] == WLC_BAND_2G)
|
|
name = (char *)bgname;
|
|
else
|
|
return IOCTL_ERROR;
|
|
|
|
break;
|
|
|
|
case WLC_BAND_5G :
|
|
name = (char *)aname;
|
|
break;
|
|
|
|
case WLC_BAND_2G :
|
|
name = (char *)bgname;
|
|
break;
|
|
|
|
default :
|
|
return IOCTL_ERROR;
|
|
}
|
|
|
|
if (!*argv) {
|
|
/* it is "mrate" get */
|
|
if ((error = wlu_iovar_getint(wl, name, &val) < 0))
|
|
return error;
|
|
|
|
val = dtoh32(val);
|
|
#ifdef D11AC_IOTYPES
|
|
if (ioctl_version == 1) {
|
|
wl_printrate(val);
|
|
} else {
|
|
wl_printrate(wl_ratespec2rate((uint32)val));
|
|
}
|
|
#else
|
|
wl_printrate(val);
|
|
#endif
|
|
} 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 {
|
|
#ifdef D11AC_IOTYPES
|
|
/* 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);
|
|
#endif
|
|
}
|
|
|
|
val = htod32(val);
|
|
|
|
error = wlu_iovar_setint(wl, name, val);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
#ifndef ATE_BUILD
|
|
/* 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
|
|
*/
|
|
#ifdef D11AC_IOTYPES
|
|
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-9, and next char is 's' or 'x' */
|
|
if (mcs < 0 || mcs > 9 || 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 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 -1;
|
|
}
|
|
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 = 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 -1;
|
|
}
|
|
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 = -1;
|
|
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) {
|
|
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 == 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 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;
|
|
}
|
|
#endif
|
|
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_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);
|
|
}
|
|
|
|
static 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);
|
|
#ifdef D11AC_IOTYPES
|
|
if (ioctl_version > 1) {
|
|
wl_printrate(wl_ratespec2rate((uint32)val));
|
|
} else {
|
|
wl_printrate(val);
|
|
}
|
|
#else
|
|
wl_printrate(val);
|
|
#endif
|
|
} 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.
|
|
*/
|
|
#ifdef D11AC_IOTYPES
|
|
val = WL_RSPEC_ENCODE_RATE | rate_string2int(*argv);
|
|
#endif
|
|
}
|
|
|
|
|
|
val = htod32(val);
|
|
error = wlu_iovar_setint(wl, name, val);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
#ifdef D11AC_IOTYPES
|
|
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;
|
|
|
|
/* 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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
} else
|
|
to.val = to.val*2;
|
|
if (mcs_set) {
|
|
fprintf(stderr, "%s: cannot use -r and -m\n", fn_name);
|
|
err = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if (legacy_set) {
|
|
fprintf(stderr, "%s: cannot use -r and -m\n", fn_name);
|
|
err = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if (!stf_set) {
|
|
if (legacy_set)
|
|
stf = OLD_NRATE_STF_SISO; /* SISO */
|
|
else if (mcs_set) {
|
|
if ((nrate & OLD_NRATE_RATE_MASK) <= HIGHEST_SINGLE_STREAM_MCS ||
|
|
(nrate & OLD_NRATE_RATE_MASK) == 32)
|
|
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 = 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;
|
|
}
|
|
#else
|
|
static int
|
|
wl_nrate(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
miniopt_t to;
|
|
const char* fn_name = "wl_nrate", *rspec_auto = "auto";
|
|
bool mcs_set = FALSE, legacy_set = FALSE, stf_set = FALSE;
|
|
bool mcs_only = FALSE;
|
|
int err, opt_err;
|
|
uint32 val = 0;
|
|
uint32 nrate = 0;
|
|
uint stf;
|
|
void *ptr;
|
|
uint32 mcastgetflag = 0;
|
|
|
|
/* toss the command name */
|
|
argv++;
|
|
|
|
if (!*argv || ((strcmp(*argv, "-b") == 0) && (*(argv+1) == NULL))) {
|
|
if (cmd->get < 0)
|
|
return -1;
|
|
if (*argv && strcmp(*argv, "-b") == 0)
|
|
mcastgetflag = 1;
|
|
if ((err = wlu_var_getbuf_sm(wl, "nrate",
|
|
&mcastgetflag, sizeof(mcastgetflag), &ptr) < 0))
|
|
return err;
|
|
val = *(uint32*)ptr;
|
|
|
|
if (!val) {
|
|
printf("auto\n");
|
|
} else {
|
|
stf = (uint)((val & NRATE_STF_MASK) >> NRATE_STF_SHIFT);
|
|
nrate = (val & NRATE_RATE_MASK);
|
|
if (val & NRATE_OVERRIDE) {
|
|
if (val & NRATE_OVERRIDE_MCS_ONLY)
|
|
rspec_auto = "fixed mcs only";
|
|
else
|
|
rspec_auto = "fixed";
|
|
}
|
|
|
|
if (val & NRATE_BCMC_OVERRIDE)
|
|
printf("multicast override: ");
|
|
|
|
if (val & NRATE_MCS_INUSE)
|
|
printf("mcs index %d stf mode %d %s\n",
|
|
nrate, stf, rspec_auto);
|
|
else
|
|
printf("legacy rate %d%s Mbps stf mode %d %s\n",
|
|
nrate/2, (nrate % 2)?".5":"", stf, rspec_auto);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
miniopt_init(&to, fn_name, "wb", FALSE);
|
|
while ((opt_err = miniopt(&to, argv)) != -1) {
|
|
if (opt_err == 1) {
|
|
err = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
} else
|
|
to.val = to.val*2;
|
|
if (mcs_set) {
|
|
fprintf(stderr, "%s: cannot use -r and -m\n", fn_name);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
nrate |= to.val & NRATE_RATE_MASK;
|
|
legacy_set = TRUE;
|
|
}
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if (legacy_set) {
|
|
fprintf(stderr, "%s: cannot use -r and -m\n", fn_name);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
mcs_set = TRUE;
|
|
nrate |= to.val & NRATE_RATE_MASK;
|
|
nrate |= NRATE_MCS_INUSE;
|
|
}
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
nrate |= (to.val << NRATE_STF_SHIFT) & NRATE_STF_MASK;
|
|
stf_set = TRUE;
|
|
}
|
|
if (to.opt == 'w') {
|
|
nrate |= NRATE_OVERRIDE_MCS_ONLY;
|
|
mcs_only = TRUE;
|
|
}
|
|
if (to.opt == 'b') {
|
|
nrate |= NRATE_BCMC_OVERRIDE;
|
|
}
|
|
}
|
|
|
|
if ((mcs_only && !mcs_set) || (mcs_only && (stf_set || legacy_set))) {
|
|
fprintf(stderr, "%s: can use -w only with -m\n", fn_name);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if (!stf_set) {
|
|
stf = 0;
|
|
if (legacy_set)
|
|
stf = NRATE_STF_SISO; /* SISO */
|
|
else if (mcs_set) {
|
|
if ((nrate & NRATE_RATE_MASK) <= HIGHEST_SINGLE_STREAM_MCS ||
|
|
(nrate & NRATE_RATE_MASK) == 32)
|
|
stf = NRATE_STF_SISO; /* SISO */
|
|
else
|
|
stf = NRATE_STF_SDM; /* SDM */
|
|
}
|
|
nrate |= (stf << NRATE_STF_SHIFT) & NRATE_STF_MASK;
|
|
}
|
|
|
|
if (legacy_set || mcs_set) {
|
|
err = wlu_iovar_setint(wl, "nrate", (int)nrate);
|
|
} else {
|
|
fprintf(stderr, "%s: you need to set a legacy or mcs rate\n", fn_name);
|
|
err = -1;
|
|
}
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
#endif
|
|
#ifndef ATE_BUILD
|
|
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 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 -1;
|
|
}
|
|
|
|
/* 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 = -1;
|
|
} 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_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 -1;
|
|
}
|
|
if ((pmkid_info = (pmkid_list_t *)malloc(len)) == NULL) {
|
|
printf("\tfailed to allocate buffer\n");
|
|
return -1;
|
|
}
|
|
|
|
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 = BAD_PARAM;
|
|
fprintf(stderr,
|
|
"Bad Args: at least one rate must be marked Basic\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
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 (USAGE_ERROR, BAD_PARAM).
|
|
*
|
|
*/
|
|
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;
|
|
bool mcs_args, vht_args;
|
|
wl_rateset_args_t cur_rs;
|
|
|
|
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 = 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 = 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 = BAD_PARAM;
|
|
break;
|
|
}
|
|
|
|
/* no legacy rates specified */
|
|
if ((rs->count == 0) && (r == 0)) {
|
|
fprintf(stderr, "empty legacy rateset not supported\n");
|
|
error = USAGE_ERROR;
|
|
break;
|
|
}
|
|
|
|
rs->rates[rs->count++] = r;
|
|
}
|
|
|
|
if (error)
|
|
return error;
|
|
|
|
if (!mcs_args && !vht_args && !rs->count)
|
|
return 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 = USAGE_ERROR;
|
|
break;
|
|
}
|
|
|
|
mcs_mask = strtoul(arg, &endp, 16);
|
|
|
|
if (endp == arg) {
|
|
fprintf(stderr, "unable to convert the mcs parameter \"%s\"\n", arg);
|
|
error = BAD_PARAM;
|
|
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 = 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 = BAD_PARAM;
|
|
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 != 0x00ff) && /* vht mcs0-7 */
|
|
(mcs_mask != 0x01ff) && /* vht mcs0-8 */
|
|
(mcs_mask != 0x03ff)) { /* vht mcs0-9 */
|
|
fprintf(stderr, "Error: VHT rate mask must be 0 (disabled),"
|
|
" 0xff (MCS0-7), 0x1ff (MCS0-8), or 0x3ff (MCS0-9).\n");
|
|
error = BAD_PARAM;
|
|
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 (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 (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 (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 (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 (BAD_PARAM);
|
|
}
|
|
mcs_mask = (uint8)strtoul(arg, &endp, 16);
|
|
if (endp == arg) {
|
|
fprintf(stderr, "ERR: failed to convert %s\n", arg);
|
|
return (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 (BAD_PARAM);
|
|
}
|
|
vht_mask = (uint16)strtoul(arg, &endp, 16);
|
|
if (endp == arg) {
|
|
fprintf(stderr, "ERR: failed to convert %s\n", arg);
|
|
return (USAGE_ERROR);
|
|
}
|
|
|
|
/* Validate bitmask value */
|
|
if (vht_mask > 0x03ff) {
|
|
fprintf(stderr, "ERR: vht bitmask must be 0 (disabled)"
|
|
" or up to a maximum of 3ff (MCS0-9).\n");
|
|
return (BAD_PARAM);
|
|
}
|
|
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_lpc_params(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err, argc;
|
|
lpc_params_t lpc_params;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
argv++;
|
|
|
|
if (*argv == NULL) {
|
|
/* get current LPC params */
|
|
if ((err = wlu_iovar_get(wl, cmd->name, (void *) &lpc_params,
|
|
(sizeof(lpc_params_t)))) < 0)
|
|
return (err);
|
|
|
|
printf("- Link Power Control parameters -\n");
|
|
printf("rate_stab_thresh\t= %d\n", lpc_params.rate_stab_thresh);
|
|
printf("pwr_stab_thresh\t\t= %d\nlpc_exp_time\t\t= %d\n",
|
|
lpc_params.pwr_stab_thresh, lpc_params.lpc_exp_time);
|
|
printf("pwrup_slow_step\t\t= %d\npwrup_fast_step\t\t= %d\n",
|
|
lpc_params.pwrup_slow_step, lpc_params.pwrup_fast_step);
|
|
printf("pwrdn_slow_step\t\t= %d\n", lpc_params.pwrdn_slow_step);
|
|
} else {
|
|
char *endptr;
|
|
/* Validate num of entries */
|
|
for (argc = 0; argv[argc]; argc++);
|
|
if (argc != 6)
|
|
return USAGE_ERROR;
|
|
|
|
argc = 0;
|
|
lpc_params.rate_stab_thresh = (uint8) strtol(argv[argc], &endptr, 0);
|
|
argc++;
|
|
lpc_params.pwr_stab_thresh = (uint8) strtol(argv[argc], &endptr, 0);
|
|
argc++;
|
|
lpc_params.lpc_exp_time = (uint8) strtol(argv[argc], &endptr, 0);
|
|
argc++;
|
|
lpc_params.pwrup_slow_step = (uint8) strtol(argv[argc], &endptr, 0);
|
|
argc++;
|
|
lpc_params.pwrup_fast_step = (uint8) strtol(argv[argc], &endptr, 0);
|
|
argc++;
|
|
lpc_params.pwrdn_slow_step = (uint8) strtol(argv[argc], &endptr, 0);
|
|
|
|
/* Set LPC params */
|
|
err = wlu_iovar_set(wl, cmd->name, (void *) &lpc_params,
|
|
(sizeof(lpc_params_t)));
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/* 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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
}
|
|
} else {
|
|
fprintf(stderr, "%s: band unspecified\n", cmd->name);
|
|
err = -1;
|
|
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;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
#if !defined(ATE_BUILD) && defined(D11AC_IOTYPES)
|
|
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 = USAGE_ERROR;
|
|
}
|
|
} else {
|
|
miniopt_init(&to, fn_name, NULL, FALSE);
|
|
while ((opt_err = miniopt(&to, argv)) != -1) {
|
|
if (opt_err == 1) {
|
|
err = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if (to.val > 224) {
|
|
fprintf(stderr, "%s: invalid channel %d\n",
|
|
fn_name, to.val);
|
|
err = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if ((to.val != 5) && (to.val != 2)) {
|
|
fprintf(stderr,
|
|
"%s: invalid band %d\n",
|
|
fn_name, to.val);
|
|
err = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if ((to.val != 20) && (to.val != 40) && (to.val != 80)) {
|
|
fprintf(stderr,
|
|
"%s: invalid bandwidth %d\n",
|
|
fn_name, to.val);
|
|
err = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = 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 = -1;
|
|
}
|
|
}
|
|
|
|
if (!err)
|
|
printf("Chanspec set to 0x%x\n", chanspec);
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
#else
|
|
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;
|
|
|
|
wf_chspec_ntoa((chanspec_t)val, buf);
|
|
printf("%s (0x%x)\n", buf, val);
|
|
return 0;
|
|
}
|
|
|
|
|
|
if ((chanspec = wf_chspec_aton(*argv))) {
|
|
err = wlu_iovar_setint(wl, cmd->name, (int)chanspec);
|
|
} else {
|
|
miniopt_init(&to, fn_name, NULL, FALSE);
|
|
while ((opt_err = miniopt(&to, argv)) != -1) {
|
|
if (opt_err == 1) {
|
|
err = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if (to.val > 224) {
|
|
fprintf(stderr, "%s: invalid channel %d\n",
|
|
fn_name, to.val);
|
|
err = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if ((to.val != 5) && (to.val != 2)) {
|
|
fprintf(stderr,
|
|
"%s: invalid band %d\n",
|
|
fn_name, to.val);
|
|
err = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if ((to.val != 20) && (to.val != 40)) {
|
|
fprintf(stderr,
|
|
"%s: invalid bandwidth %d\n",
|
|
fn_name, to.val);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
if (to.val == 20)
|
|
chanspec |= WL_CHANSPEC_BW_20;
|
|
else
|
|
chanspec |= WL_CHANSPEC_BW_40;
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if (to.val == -1)
|
|
chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
|
|
else if (to.val == 1)
|
|
chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
|
|
else
|
|
chanspec |= WL_CHANSPEC_CTL_SB_NONE;
|
|
ctl_sb_set = TRUE;
|
|
}
|
|
}
|
|
|
|
/* set ctl sb to 20 if not set and 20mhz is selected */
|
|
if (!ctl_sb_set && CHSPEC_IS20(chanspec)) {
|
|
chanspec |= WL_CHANSPEC_CTL_SB_NONE;
|
|
ctl_sb_set = TRUE;
|
|
}
|
|
|
|
if (ch_set && band_set && bw_set && ctl_sb_set) {
|
|
err = wlu_iovar_setint(wl, cmd->name, (int)chanspec);
|
|
} 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 = -1;
|
|
}
|
|
}
|
|
|
|
if (!err)
|
|
printf("Chanspec set to 0x%x\n", chanspec);
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
#endif
|
|
#ifndef ATE_BUILD
|
|
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 USAGE_ERROR;
|
|
|
|
chanspec = wf_chspec_aton(*argv);
|
|
chanspec = wl_chspec32_to_driver(chanspec);
|
|
if (chanspec == INVCHANSPEC) {
|
|
return 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 (-1);
|
|
|
|
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 (-1);
|
|
}
|
|
|
|
mode = htod32(mode);
|
|
return wlu_iovar_setint(wl, cmd->name, mode);
|
|
}
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
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);
|
|
}
|
|
#ifndef ATE_BUILD
|
|
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;
|
|
char *t2;
|
|
int colons = 0;
|
|
int double_colons = 0;
|
|
int zero_req = 0;
|
|
|
|
BCM_REFERENCE(t2);
|
|
|
|
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;
|
|
t2 = x;
|
|
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 -1;
|
|
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 -1;
|
|
}
|
|
|
|
/* 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));
|
|
}
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
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;
|
|
|
|
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 -1;
|
|
}
|
|
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) {
|
|
wlu_iovar_getint(wl, "bcmerror", &bcmerr);
|
|
if (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 IOCTL_ERROR;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
static int
|
|
wl_rateparam(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int val[2];
|
|
|
|
if (!*++argv)
|
|
return -1;
|
|
val[0] = htod32(atoi(*argv));
|
|
if (!*++argv)
|
|
return -1;
|
|
val[1] = htod32(atoi(*argv));
|
|
return wlu_set(wl, cmd->set, val, 2 * 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.
|
|
*/
|
|
static 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;
|
|
}
|
|
|
|
static 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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if (*argv == NULL) {
|
|
fprintf(stderr,
|
|
"wl_scan: missing value parameter after \"%s\"\n", p);
|
|
err = -1;
|
|
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, ssids, nssid, WL_SCAN_PARAMS_SSID_MAX);
|
|
if (nssid < 0) {
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
}
|
|
if (opt == 't' || !strcmp(key, "scan_type")) {
|
|
if (!strcmp(valstr, "active")) {
|
|
params->scan_type = 0;
|
|
} 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, "hotspot")) {
|
|
params->scan_type |= WL_SCANFLAGS_HOTSPOT;
|
|
} else {
|
|
fprintf(stderr,
|
|
"scan_type value should be \"active\" "
|
|
"or \"passive\", but got \"%s\"\n", valstr);
|
|
err = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
params->home_time = val;
|
|
}
|
|
if (opt == 'c' || !strcmp(key, "channels")) {
|
|
nchan = wl_parse_channel_list(valstr, params->channel_list,
|
|
WL_NUMCHANNELS);
|
|
if (nchan == -1) {
|
|
fprintf(stderr, "error parsing channel list arg\n");
|
|
err = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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_scanol_prep(void *wl, cmd_t *cmd, char **argv, scanol_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];
|
|
uint16 channels[WL_NUMCHANNELS];
|
|
|
|
UNUSED_PARAMETER(wl);
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
params->active_time = -1;
|
|
params->passive_time = -1;
|
|
params->idle_rest_time = -1;
|
|
params->idle_rest_time_multiplier = -1;
|
|
params->active_rest_time = -1;
|
|
params->active_rest_time_multiplier = -1;
|
|
params->scan_cycle_idle_rest_time = -1;
|
|
params->scan_cycle_idle_rest_multiplier = -1;
|
|
params->scan_cycle_active_rest_time = -1;
|
|
params->scan_cycle_active_rest_multiplier = -1;
|
|
params->max_rest_time = -1;
|
|
params->max_scan_cycles = -1;
|
|
params->nprobes = -1;
|
|
params->scan_start_delay = -1;
|
|
memset(ssids, 0, sizeof(wlc_ssid_t) * WL_SCAN_PARAMS_SSID_MAX);
|
|
memset(channels, 0, sizeof(uint16) * WL_NUMCHANNELS);
|
|
|
|
/* 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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if (*argv == NULL) {
|
|
fprintf(stderr,
|
|
"wl_scan: missing value parameter after \"%s\"\n", p);
|
|
err = -1;
|
|
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 == 'f' || !strcmp(key, "flags")) {
|
|
if (!good_int) {
|
|
fprintf(stderr,
|
|
"could not parse \"%s\" as an int for flags\n", valstr);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
params->flags = (uint32)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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
params->passive_time = val;
|
|
}
|
|
if (opt == 'r' || !strcmp(key, "scirt")) {
|
|
if (!good_int) {
|
|
fprintf(stderr,
|
|
"could not parse \"%s\" as an int for value "
|
|
"scan_cycle_idle_rest_time\n", valstr);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
params->scan_cycle_idle_rest_time = val;
|
|
}
|
|
if (opt == 'm' || !strcmp(key, "scirtm")) {
|
|
if (!good_int) {
|
|
fprintf(stderr,
|
|
"could not parse \"%s\" as an int for value "
|
|
"scan_cycle_idle_rest_time_multiplier\n", valstr);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
params->scan_cycle_idle_rest_multiplier = val;
|
|
}
|
|
if (opt == 'R' || !strcmp(key, "scart")) {
|
|
if (!good_int) {
|
|
fprintf(stderr,
|
|
"could not parse \"%s\" as an int for value "
|
|
"scan_cycle_idle_rest_time\n", valstr);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
params->scan_cycle_active_rest_time = val;
|
|
}
|
|
if (opt == 'M' || !strcmp(key, "scartm")) {
|
|
if (!good_int) {
|
|
fprintf(stderr,
|
|
"could not parse \"%s\" as an int for value "
|
|
"scan_cycle_idle_rest_time_multiplier\n", valstr);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
params->scan_cycle_active_rest_multiplier = val;
|
|
}
|
|
if (opt == 'x' || !strcmp(key, "mrt")) {
|
|
if (!good_int) {
|
|
fprintf(stderr,
|
|
"could not parse \"%s\" as an int for value "
|
|
"max_rest_time\n", valstr);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
params->max_rest_time = val;
|
|
}
|
|
if (opt == 'y' || !strcmp(key, "msc")) {
|
|
if (!good_int) {
|
|
fprintf(stderr,
|
|
"could not parse \"%s\" as an int for value "
|
|
"max_scan_cycle\n", valstr);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
params->max_scan_cycles = val;
|
|
}
|
|
if (opt == 'n' || !strcmp(key, "nprobes")) {
|
|
if (!good_int) {
|
|
fprintf(stderr,
|
|
"could not parse \"%s\" as an int for "
|
|
"value nprobes\n", valstr);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
params->nprobes = val;
|
|
}
|
|
if (opt == 'd' || !strcmp(key, "ssd")) {
|
|
if (!good_int) {
|
|
fprintf(stderr,
|
|
"could not parse \"%s\" as an int for value "
|
|
"scan_start_delay\n", valstr);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
params->scan_start_delay = val;
|
|
}
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
}
|
|
if (opt == 'c' || !strcmp(key, "channels")) {
|
|
nchan = wl_parse_channel_list(valstr, channels, WL_NUMCHANNELS);
|
|
if (nchan == -1) {
|
|
fprintf(stderr, "error parsing channel list arg\n");
|
|
err = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
|
|
params->active_time = htod32(params->active_time);
|
|
params->passive_time = htod32(params->passive_time);
|
|
params->flags = htod32(params->flags);
|
|
params->scan_cycle_idle_rest_time = htod32(params->scan_cycle_idle_rest_time);
|
|
params->scan_cycle_idle_rest_multiplier = htod32(params->scan_cycle_idle_rest_multiplier);
|
|
params->nprobes = htod32(params->nprobes);
|
|
params->max_rest_time = htod32(params->max_rest_time);
|
|
params->max_scan_cycles = htod32(params->max_scan_cycles);
|
|
params->scan_start_delay = htod32(params->scan_start_delay);
|
|
|
|
params->nchannels = htod32(nchan);
|
|
params->ssid_count = htod32(nssid);
|
|
|
|
for (i = 0; i < nssid; i++) {
|
|
ssids[i].SSID_len = htod32(ssids[i].SSID_len);
|
|
}
|
|
|
|
/* Copy ssid array if applicable */
|
|
if (nssid > 0) {
|
|
memcpy(params->ssidlist, ssids, nssid * sizeof(wlc_ssid_t));
|
|
p = (char *)¶ms->ssidlist[nssid];
|
|
} else {
|
|
p = (char *)params;
|
|
p += sizeof(scanol_params_t);
|
|
}
|
|
if ((((uintptr)p - (uintptr)params) + nchan * sizeof(uint16)) > (uint)*params_size) {
|
|
fprintf(stderr, "additional channels exceed params_size\n");
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
|
|
for (i = 0; i < nchan; i++) {
|
|
channels[i] = htodchanspec(channels[i]);
|
|
}
|
|
memcpy(p, channels, sizeof(uint16) * nchan);
|
|
p += sizeof(uint16) * nchan;
|
|
*params_size = p - (char*)params + sizeof(wlc_ssid_t) * ((nssid > 0) ? (nssid - 1) : 0);
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
#ifdef BCMINTERNAL
|
|
/* Send a probe request frame.
|
|
* user can specify BSSID, MAC, and SSID
|
|
* unspecified params default to broadcast
|
|
*/
|
|
static int
|
|
wl_sendprb(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int params_size = sizeof(wl_probe_params_t);
|
|
wl_probe_params_t *params;
|
|
int err = 0;
|
|
wlc_ssid_t ssids[1];
|
|
int nssid = 0;
|
|
char key[64];
|
|
int keylen;
|
|
char *p, *eq, *valstr;
|
|
char opt;
|
|
bool opt_end;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
params = (wl_probe_params_t*)malloc(params_size);
|
|
if (params == NULL) {
|
|
fprintf(stderr, "Error allocating %d bytes for probe params\n", params_size);
|
|
return -1;
|
|
}
|
|
memset(params, 0, params_size);
|
|
|
|
/* skip the command name */
|
|
argv++;
|
|
|
|
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 (!strncmp(p, "--", 2)) {
|
|
eq = strchr(p, '=');
|
|
if (eq == NULL) {
|
|
fprintf(stderr,
|
|
"missing \" = \" in long param \"%s\"\n", p);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
keylen = eq - (p + 2);
|
|
if (keylen > 63) keylen = 63;
|
|
memcpy(key, p + 2, keylen);
|
|
|
|
valstr = eq + 1;
|
|
if (*valstr == '\0') {
|
|
fprintf(stderr,
|
|
"missing value after \" = \" in long param \"%s\"\n", p);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
}
|
|
else if (!strncmp(p, "-", 1)) {
|
|
opt = p[1];
|
|
if (strlen(p) > 2) {
|
|
fprintf(stderr,
|
|
"only single char options, error on param \"%s\"\n", p);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
if (*argv == NULL) {
|
|
fprintf(stderr, "missing value parameter after \"%s\"\n", p);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
valstr = *argv;
|
|
argv++;
|
|
} else {
|
|
valstr = p;
|
|
}
|
|
|
|
if (opt == 's' || !strcmp(key, "ssid")) {
|
|
nssid = wl_parse_ssid_list(valstr, ssids, nssid, WL_SCAN_PARAMS_SSID_MAX);
|
|
if (nssid != 1) {
|
|
fprintf(stderr, "doesn't support multiple ssids\n");
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
if (nssid == 1) {
|
|
nssid = 0;
|
|
memcpy(¶ms->ssid, &ssids[0], sizeof(ssids[0]));
|
|
}
|
|
fprintf(stderr, "\"%s\" ssid\n", valstr);
|
|
|
|
} else 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 = -1;
|
|
goto exit;
|
|
}
|
|
fprintf(stderr, "\"%s\" bssid address\n", valstr);
|
|
|
|
} else if (opt == 'd' || !strcmp(key, "da")) {
|
|
if (!wl_ether_atoe(valstr, ¶ms->mac)) {
|
|
fprintf(stderr,
|
|
"could not parse \"%s\" as an ethernet MAC address\n", valstr);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
fprintf(stderr, "\"%s\" MAC address\n", valstr);
|
|
} else {
|
|
fprintf(stderr, "\"%s\" ignored\n", valstr);
|
|
}
|
|
}
|
|
|
|
/* Default to broadcast address for MAC and BSSID if user didn't specify one */
|
|
if (ETHER_ISNULLADDR(¶ms->mac))
|
|
memcpy(¶ms->mac, ðer_bcast, ETHER_ADDR_LEN);
|
|
if (ETHER_ISNULLADDR(¶ms->bssid))
|
|
memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN);
|
|
|
|
err = wlu_iovar_setbuf(wl, "sendprb", params, params_size, buf, WLC_IOCTL_MAXLEN);
|
|
|
|
exit:
|
|
free(params);
|
|
return err;
|
|
}
|
|
#endif /* BCMINTERNAL */
|
|
|
|
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 -1;
|
|
}
|
|
memset(params, 0, params_size);
|
|
|
|
err = wl_scan_prep(wl, cmd, argv, params, ¶ms_size);
|
|
|
|
if (err) {
|
|
free(params);
|
|
return err;
|
|
}
|
|
if (strcmp(cmd->name, "scan") == 0)
|
|
err = wlu_set(wl, WLC_SCAN, params, params_size);
|
|
else
|
|
err = wlu_iovar_setbuf(wl, cmd->name, params, params_size, buf, WLC_IOCTL_MAXLEN);
|
|
free(params);
|
|
return err;
|
|
}
|
|
|
|
static int
|
|
wl_scanol(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int params_size = sizeof(scanol_params_t) + WL_NUMCHANNELS * sizeof(uint16);
|
|
scanol_params_t *params;
|
|
int argc;
|
|
int err = 0;
|
|
|
|
/* arg count */
|
|
for (argc = 0; argv[argc]; argc++);
|
|
argc--;
|
|
|
|
params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
|
|
if (argc) {
|
|
params = (scanol_params_t *)malloc(params_size);
|
|
if (params == NULL) {
|
|
fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
|
|
return -1;
|
|
}
|
|
memset(params, 0, params_size);
|
|
params->version = SCANOL_PARAMS_VERSION;
|
|
err = wl_scanol_prep(wl, cmd, argv, params, ¶ms_size);
|
|
if (!err)
|
|
err = wlu_iovar_setbuf(wl, cmd->name, params, params_size, buf,
|
|
WLC_IOCTL_MAXLEN);
|
|
free(params);
|
|
} else {
|
|
uint nchan;
|
|
uint nssid;
|
|
chanspec_t *chanspecs;
|
|
uint i;
|
|
void *ptr = NULL;
|
|
|
|
/* Get */
|
|
if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return err;
|
|
|
|
params = (scanol_params_t *)ptr;
|
|
if (params->version != SCANOL_PARAMS_VERSION)
|
|
fprintf(stderr, "Structure version don't match to the driver\n");
|
|
|
|
nchan = params->nchannels;
|
|
nssid = params->ssid_count;
|
|
printf("flags 0x%x\n", params->flags);
|
|
printf("Active Time %d Passive Time %d\n",
|
|
params->active_time, params->passive_time);
|
|
printf("Idle Rest Time %d Idle Rest Time Multiplier %d\n",
|
|
params->idle_rest_time, params->idle_rest_time_multiplier);
|
|
printf("Active Rest Time %d Active Rest Time Multiplier %d\n",
|
|
params->active_rest_time, params->active_rest_time_multiplier);
|
|
printf("Scan Cycle Idle Rest Time %d"
|
|
" Scan Cycle Idle Rest Time Multiplier %d\n",
|
|
params->scan_cycle_idle_rest_time,
|
|
params->scan_cycle_idle_rest_multiplier);
|
|
printf("Scan Cycle Active Rest Time %d"
|
|
" Scan Cycle Active Rest Time Multiplier %d\n",
|
|
params->scan_cycle_active_rest_time,
|
|
params->scan_cycle_active_rest_multiplier);
|
|
printf("Maximum Rest Time %d Maximum Scan Cycles %d Scan Start Delay %d\n",
|
|
params->max_rest_time, params->max_scan_cycles, params->scan_start_delay);
|
|
printf("nprobes %d\n", params->nprobes);
|
|
printf("SSID (%d): ", nssid);
|
|
if (params->ssidlist[0].SSID[0] == 0)
|
|
printf("None\n");
|
|
else {
|
|
for (i = 0; nssid && i < nssid; i++)
|
|
printf(" \"%s\"", params->ssidlist[i].SSID);
|
|
printf("\n");
|
|
}
|
|
printf("Scan Channels (%d): ", nchan);
|
|
if (nchan == 0)
|
|
printf("None\n");
|
|
else {
|
|
printf("None\n");
|
|
chanspecs = (chanspec_t *)¶ms->ssidlist[nssid];
|
|
for (i = 0; i < nchan; i++) {
|
|
printf("%04x ", chanspecs[i]);
|
|
if (((i + 1) % 10) == 0)
|
|
printf("\n");
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
#if defined(linux)
|
|
extern time_t time(time_t *ptr);
|
|
#endif
|
|
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 0;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
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 0;
|
|
}
|
|
|
|
/* 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 -1;
|
|
}
|
|
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_BADARG;
|
|
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_BADARG;
|
|
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_BADARG;
|
|
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_BADARG;
|
|
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 = 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_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_BADARG;
|
|
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;
|
|
}
|
|
|
|
#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 -1;
|
|
}
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if (*argv == NULL) {
|
|
fprintf(stderr,
|
|
"extdscan: missing value parameter after \"%s\"\n", p);
|
|
err = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nssid > WLC_EXTDSCAN_MAX_SSID) {
|
|
fprintf(stderr, "ssid count %d exceeds max of %d\n",
|
|
nssid, WLC_EXTDSCAN_MAX_SSID);
|
|
err = -1;
|
|
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 = 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_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;
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
|
|
/* 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},
|
|
|
|
/* 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:\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;
|
|
}
|
|
}
|
|
#ifdef BCMCCX
|
|
else if (!wlu_bcmp(rsn_info.mcast->oui, CISCO_AIRONET_OUI, 3)) {
|
|
switch (rsn_info.mcast->type + CISCO_BASE) {
|
|
case WPA_CIPHER_CKIP:
|
|
printf("CKIP\n");
|
|
break;
|
|
case WPA_CIPHER_CKIP_MMH:
|
|
printf("CKIP+CMIC\n");
|
|
break;
|
|
case WPA_CIPHER_WEP_MMH:
|
|
printf("CMIC\n");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif /* BCMCCX */
|
|
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;
|
|
}
|
|
}
|
|
#ifdef BCMCCX
|
|
else if (!wlu_bcmp(suite->oui, CISCO_AIRONET_OUI, 3)) {
|
|
switch (suite->type + CISCO_BASE) {
|
|
case WPA_CIPHER_CKIP:
|
|
printf("CKIP ");
|
|
break;
|
|
case WPA_CIPHER_CKIP_MMH:
|
|
printf("CKIP+CMIC ");
|
|
break;
|
|
case WPA_CIPHER_WEP_MMH:
|
|
printf("CMIC ");
|
|
break;
|
|
default:
|
|
printf("Cisco-Unknown(#%d) ", suite->type);
|
|
break;
|
|
}
|
|
}
|
|
#endif /* BCMCCX */
|
|
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("WPA ");
|
|
break;
|
|
case RSN_AKM_PSK:
|
|
printf("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;
|
|
}
|
|
}
|
|
#ifdef BCMCCX
|
|
else if (!wlu_bcmp(suite->oui, CISCO_AIRONET_OUI, 3)) {
|
|
switch (suite->type + CISCO_BASE) {
|
|
case WPA_AUTH_CCKM:
|
|
printf("CCKM ");
|
|
break;
|
|
default:
|
|
printf("Cisco-Unknown(#%d) ", suite->type);
|
|
break;
|
|
}
|
|
}
|
|
#endif /* BCMCCX */
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
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 ");
|
|
if (capability & DOT11_CAP_DELAY_BA) printf("Delay-BA ");
|
|
if (capability & DOT11_CAP_IMMEDIATE_BA) printf("Immediate-BA ");
|
|
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));
|
|
|
|
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");
|
|
printf("\tChanspec: %sGHz channel %d %dMHz (0x%x)\n",
|
|
CHSPEC_IS2G(bi->chanspec)?"2.4":"5", CHSPEC_CHANNEL(bi->chanspec),
|
|
#ifdef D11AC_IOTYPES
|
|
(CHSPEC_IS80(bi->chanspec) ?
|
|
80 : (CHSPEC_IS40(bi->chanspec) ?
|
|
#else
|
|
(CHSPEC_IS40(bi->chanspec) ?
|
|
#endif
|
|
40 : (CHSPEC_IS20(bi->chanspec) ? 20 : 10))
|
|
#ifdef D11AC_IOTYPES
|
|
)
|
|
#endif
|
|
,
|
|
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 MCS : [ ");
|
|
for (mcs_idx = 0; mcs_idx < (MCSSET_LEN * 8); mcs_idx++)
|
|
if (isset(bi->basic_mcs, mcs_idx))
|
|
printf("%d ", mcs_idx);
|
|
printf("]\n");
|
|
|
|
if (bi->vht_cap) {
|
|
int i;
|
|
uint mcs;
|
|
printf("\tVHT Capabilities: \n");
|
|
printf("\tSupported VHT (tx) Rates:\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));
|
|
if (mcs != VHT_CAP_MCS_MAP_NONE)
|
|
printf("\t\tNSS: %d MCS: %s\n", i,
|
|
(mcs == VHT_CAP_MCS_MAP_0_9 ? "0-9" :
|
|
(mcs == VHT_CAP_MCS_MAP_0_8 ? "0-8" : "0-7")));
|
|
}
|
|
printf("\tSupported VHT (rx) Rates:\n");
|
|
for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
|
|
mcs = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
|
|
if (mcs != VHT_CAP_MCS_MAP_NONE)
|
|
printf("\t\tNSS: %d MCS: %s\n", i,
|
|
(mcs == VHT_CAP_MCS_MAP_0_9 ? "0-9" :
|
|
(mcs == VHT_CAP_MCS_MAP_0_8 ? "0-8" : "0-7")));
|
|
}
|
|
}
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
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); /* XXX: Quick and dirty way of SNR calc */
|
|
|
|
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 */
|
|
wl_varint(wl, cmd, argv);
|
|
}
|
|
else {
|
|
int val = *startptr[0];
|
|
val = strtol(*startptr, &endptr, 0);
|
|
|
|
if (*endptr != '\0') {
|
|
return -1;
|
|
}
|
|
|
|
val = htod32(val);
|
|
|
|
if (val == LQ_STOP_MONITOR) {
|
|
ret = _wl_dump_lq(wl);
|
|
}
|
|
|
|
wl_varint(wl, cmd, argv); /* Standard set call after getting stats */
|
|
}
|
|
|
|
return ret;
|
|
} /* wl_monitor_lq */
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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 = -1;
|
|
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;
|
|
}
|
|
|
|
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_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;
|
|
char abbrev[WLC_CNTRY_BUF_SZ] = ""; /* default.. current locale */
|
|
char chspec_str[CHANSPEC_STR_LEN];
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
memset(buf, 0, WLC_IOCTL_MAXLEN);
|
|
|
|
strcpy(buf, "chanspecs");
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
if ((to.val != 5) && (to.val != 2)) {
|
|
fprintf(stderr,
|
|
"%s: invalid band %d\n",
|
|
fn_name, to.val);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
if (to.val == 5)
|
|
c |= WL_CHANSPEC_BAND_5G;
|
|
else
|
|
c |= 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 = -1;
|
|
goto exit;
|
|
}
|
|
if ((to.val != 20) && (to.val != 40) && (to.val != 80)) {
|
|
fprintf(stderr,
|
|
"%s: invalid bandwidth %d\n",
|
|
fn_name, to.val);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
if (to.val == 20)
|
|
c |= WL_CHANSPEC_BW_20;
|
|
else if (to.val == 40)
|
|
c |= WL_CHANSPEC_BW_40;
|
|
#ifdef D11AC_IOTYPES
|
|
else {
|
|
if (ioctl_version == 1) {
|
|
fprintf(stderr,
|
|
"%s: bandwidth 80 MHz is not supported by "
|
|
"this version driver.\n",
|
|
fn_name);
|
|
err = USAGE_ERROR;
|
|
goto exit;
|
|
|
|
}
|
|
c |= WL_CHANSPEC_BW_80;
|
|
}
|
|
#endif
|
|
bw_set = TRUE;
|
|
}
|
|
if (to.opt == 'c') {
|
|
if (!to.valstr) {
|
|
fprintf(stderr,
|
|
"%s: please provide country abbrev \n", fn_name);
|
|
err = -1;
|
|
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>'\n",
|
|
fn_name);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
/* convert chanspec to legacy if needed */
|
|
if (c != 0) {
|
|
c = wl_chspec_to_driver(c);
|
|
if (c == INVCHANSPEC) {
|
|
err = USAGE_ERROR;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
/* Add chanspec argument */
|
|
chanspec = (chanspec_t *) (buf + buflen);
|
|
*chanspec = c;
|
|
buflen += (sizeof(chanspec_t));
|
|
|
|
/* Add country abbrev */
|
|
strncpy(buf + buflen, abbrev, WLC_CNTRY_BUF_SZ);
|
|
buflen += WLC_CNTRY_BUF_SZ;
|
|
|
|
/* Add list */
|
|
list = (wl_uint32_list_t *)(buf + buflen);
|
|
list->count = htod32(WL_NUMCHANSPECS);
|
|
buflen += sizeof(uint32)*(WL_NUMCHANSPECS + 1);
|
|
|
|
ret = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
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 -1;
|
|
}
|
|
|
|
len = strlen(*argv);
|
|
if ((len > 3) || (len < 2)) {
|
|
fprintf(stderr, "invalid country abbrev: %s\n", *argv);
|
|
return -1;
|
|
}
|
|
|
|
strcpy(cic->country_abbrev, *argv);
|
|
|
|
/* band must follow */
|
|
if (!*++argv) {
|
|
fprintf(stderr, "missing band\n");
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
return (0);
|
|
} else {
|
|
spect = strtol(*argv, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
return (-1);
|
|
|
|
if (spect < SPECT_MNGMT_OFF || spect > SPECT_MNGMT_LOOSE_11H_D)
|
|
return (-1);
|
|
|
|
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 0;
|
|
|
|
} else if (!wl_ether_atoe(*argv, &scb_val.ea)) {
|
|
fprintf(stderr, "Malformed STA MAC parameter\n");
|
|
ret = -1;
|
|
|
|
} 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"},
|
|
#ifdef BCMCCX
|
|
{WPA_AUTH_CCKM, "CCKM(WPA)"},
|
|
{WPA2_AUTH_CCKM, "CCKM(WPA2)"},
|
|
#endif /* BCMCCX */
|
|
{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_FT, "FT"},
|
|
{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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static 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;
|
|
#ifdef BCMWAPI_WPI
|
|
else if (!strnicmp("wapi", *argv, 4) && key->len == 32)
|
|
key->algo = CRYPTO_ALGO_SMS4;
|
|
#endif /* BCMWAPI_WPI */
|
|
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;
|
|
}
|
|
|
|
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 (wlu_get(wl, cmd->get, &val, sizeof(val)) < 0) {
|
|
return -1;
|
|
}
|
|
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 -1;
|
|
|
|
key.index = atoi(*argv++);
|
|
|
|
if (!*argv) {
|
|
fprintf(stderr, "No key specified\n");
|
|
return -1;
|
|
}
|
|
if (parse_wep(argv, &key, TRUE))
|
|
return -1;
|
|
|
|
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 -1;
|
|
|
|
key.index = htod32(atoi(*argv++));
|
|
|
|
if (*argv) {
|
|
if (!(wl_ether_atoe(*argv, &key.ea)))
|
|
return -1;
|
|
}
|
|
|
|
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)
|
|
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)
|
|
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 -1;
|
|
}
|
|
len = sizeof(wl_wsec_key_t) + 4;
|
|
wsec_buf = malloc(len);
|
|
*(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)
|
|
{
|
|
int ret;
|
|
uint i, j;
|
|
union {
|
|
int index;
|
|
wl_wsec_key_t key;
|
|
} u;
|
|
int wep_is_on = 0;
|
|
const char *addr;
|
|
int empty_first, empty_last;
|
|
bool empty;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if ((ret = wlu_iovar_getint(wl, "wsec", &wep_is_on)) < 0)
|
|
fprintf(stderr, "Could not query wsec status.\n");
|
|
|
|
empty_first = empty_last = -1;
|
|
|
|
for (i = 0; ; i++) { /* The upper limit is not known here. */
|
|
u.index = htod32(i);
|
|
ret = wlu_get(wl, cmd->get, &u, sizeof(u));
|
|
empty = (ETHER_ISNULLADDR(&u.key.ea) && dtoh32(u.key.algo) == CRYPTO_ALGO_OFF);
|
|
|
|
if (empty_first != -1 &&
|
|
(ret < 0 || !empty)) {
|
|
if (empty_first == empty_last)
|
|
printf("%3d: <empty>\n", empty_first);
|
|
else
|
|
printf("%3d - %3d: <empty>\n", empty_first, empty_last);
|
|
empty_first = empty_last = -1;
|
|
}
|
|
|
|
if (ret < 0) {
|
|
/* If at least one beyond the defaults could be read,
|
|
* not knowing the limit must have been the error.
|
|
*/
|
|
return (i >= DOT11_MAX_DEFAULT_KEYS) ? 0 : ret;
|
|
}
|
|
|
|
/* Key may not have been set yet */
|
|
if (i < DOT11_MAX_DEFAULT_KEYS)
|
|
addr = "(default)";
|
|
else if (empty) {
|
|
if (empty_first == -1) empty_first = i;
|
|
empty_last = i;
|
|
continue;
|
|
} 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");
|
|
}
|
|
}
|
|
|
|
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 -1;
|
|
idx = atoi(*argv);
|
|
if (idx < 0) {
|
|
fprintf(stderr, "Key index %d out of range. Should be positive.\n", idx);
|
|
return -1;
|
|
}
|
|
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;
|
|
}
|
|
|
|
/* 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;
|
|
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_ofdm_rateset_t ofdm_cdd_rate;
|
|
ppr_vht_mcs_rateset_t vhtrate;
|
|
|
|
if (!siso) {
|
|
offset = n = WL_NUM_3x3_ELEMENTS;
|
|
}
|
|
|
|
if (cck) {
|
|
ppr_dsss_rateset_t rate;
|
|
ppr_get_dsss(ppr, bw, WL_TX_CHAINS_1, &rate);
|
|
printf("CCK %2d %2d %2d %2d\n", rate.pwr[0], rate.pwr[1],
|
|
rate.pwr[2], rate.pwr[3]);
|
|
if (!siso) {
|
|
ppr_get_dsss(ppr, bw, WL_TX_CHAINS_2, &rate);
|
|
printf("CCK CDD 1x2 %2d %2d %2d %2d\n",
|
|
rate.pwr[0], rate.pwr[1],
|
|
rate.pwr[2], rate.pwr[3]);
|
|
ppr_get_dsss(ppr, bw, WL_TX_CHAINS_3, &rate);
|
|
printf("CCK CDD 1x3 %2d %2d %2d %2d\n",
|
|
rate.pwr[0], rate.pwr[1],
|
|
rate.pwr[2], rate.pwr[3]);
|
|
}
|
|
}
|
|
ppr_get_ofdm(ppr, bw, WL_TX_MODE_NONE, WL_TX_CHAINS_1, &ofdm_rate);
|
|
printf("OFDM %2d %2d %2d %2d %2d %2d %2d %2d\n",
|
|
ofdm_rate.pwr[0], ofdm_rate.pwr[1], ofdm_rate.pwr[2], ofdm_rate.pwr[3],
|
|
ofdm_rate.pwr[4], ofdm_rate.pwr[5], ofdm_rate.pwr[6], ofdm_rate.pwr[7]);
|
|
ppr_get_ofdm(ppr, bw, WL_TX_MODE_CDD, WL_TX_CHAINS_2, &ofdm_cdd_rate);
|
|
printf("OFDM-CDD %2d %2d %2d %2d %2d %2d %2d %2d\n",
|
|
ofdm_cdd_rate.pwr[0], ofdm_cdd_rate.pwr[1], ofdm_cdd_rate.pwr[2],
|
|
ofdm_cdd_rate.pwr[3],
|
|
ofdm_cdd_rate.pwr[4], ofdm_cdd_rate.pwr[5], ofdm_cdd_rate.pwr[6],
|
|
ofdm_cdd_rate.pwr[7]);
|
|
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 = "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 10:
|
|
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 11:
|
|
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;
|
|
default:
|
|
ptr = NULL;
|
|
vhtptr = NULL;
|
|
break;
|
|
}
|
|
if (ptr == NULL)
|
|
continue;
|
|
ppr_get_vht_mcs(ppr, bw, nss, mode, chains, &vhtrate);
|
|
printf("%s %2d %2d %2d %2d %2d %2d %2d %2d",
|
|
str, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
|
|
if (vht && vhtptr)
|
|
printf(" %2d %2d", vhtptr[0], vhtptr[1]);
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
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;
|
|
default:
|
|
break;
|
|
}
|
|
/* MCS32 value is obsoleted */
|
|
/* printf("MCS32 %2d\n", ppr->mcs32); */
|
|
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];
|
|
uint32 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);
|
|
memset(wl_txppr, 0, sizeof(*wl_txppr));
|
|
wl_txppr->buflen = pprsize;
|
|
if (ppr_init_ser_mem_by_bw(wl_txppr->pprbuf, ppr_get_max_bw(), pprsize) != BCME_OK) {
|
|
free(wl_txppr);
|
|
return IOCTL_ERROR;
|
|
}
|
|
|
|
if (WLC_IOCTL_MAXLEN < sizeof(wl_txppr_t) + pprsize) {
|
|
free(wl_txppr);
|
|
return IOCTL_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 1/4dB): Channel %d\n", CHSPEC_CHANNEL(chanspec));
|
|
if (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;
|
|
}
|
|
|
|
/* 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 "5.1"
|
|
|
|
#define RATE_STR_LEN 64
|
|
|
|
static int
|
|
wl_get_current_power(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
int mimo;
|
|
int i;
|
|
chanspec_t chanspec;
|
|
char chanspec_str[CHANSPEC_STR_LEN];
|
|
bool verbose = FALSE;
|
|
bool brief = FALSE;
|
|
int16 power_target;
|
|
#ifdef D11AC_IOTYPES
|
|
char rate_str[RATE_STR_LEN];
|
|
#endif
|
|
size_t pprsize = ppr_ser_size_by_bw(ppr_get_max_bw());
|
|
tx_pwr_rpt_t *ppr_wl = (tx_pwr_rpt_t *)malloc(sizeof(tx_pwr_rpt_t) + pprsize*3);
|
|
uint8 *ppr_ser = ppr_wl->pprdata;
|
|
memset(ppr_wl, 0, sizeof(tx_pwr_rpt_t) + pprsize*3);
|
|
ppr_wl->board_limit_len = pprsize;
|
|
ppr_wl->target_len = pprsize;
|
|
ppr_wl->version = TX_POWER_T_VERSION;
|
|
/* init allocated mem for serialisation */
|
|
ppr_init_ser_mem_by_bw(ppr_ser, ppr_get_max_bw(), ppr_wl->board_limit_len);
|
|
ppr_ser += ppr_wl->board_limit_len;
|
|
ppr_init_ser_mem_by_bw(ppr_ser, ppr_get_max_bw(), ppr_wl->target_len);
|
|
|
|
|
|
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, sizeof(tx_pwr_rpt_t) + pprsize*3)) < 0) {
|
|
fprintf(stderr, "Error: Curpower failed. ");
|
|
fprintf(stderr, "Bring up interface and disable mpc if necessary (wl mpc 0)\n");
|
|
free(ppr_wl);
|
|
return err;
|
|
}
|
|
/* 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 = IOCTL_ERROR;
|
|
} else {
|
|
ppr_t* ppr_board = NULL;
|
|
ppr_t* ppr_target = NULL;
|
|
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);
|
|
|
|
chanspec = ppr_wl->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);
|
|
if (ppr_deserialize_create(NULL, ppr_wl->pprdata,
|
|
ppr_wl->board_limit_len, &ppr_board) != BCME_OK) {
|
|
err = IOCTL_ERROR; /* XXX better ret code? */
|
|
goto exit;
|
|
}
|
|
|
|
if (ppr_deserialize_create(NULL, ppr_ser, ppr_wl->target_len, &ppr_target)
|
|
!= BCME_OK) {
|
|
err = IOCTL_ERROR; /* XXX better ret code? */
|
|
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%s\n", "Channel Width:",
|
|
((ppr_wl->channel_bandwidth == WL_BW_20MHZ) ? "20MHz" :
|
|
((ppr_wl->channel_bandwidth == WL_BW_40MHZ) ? "40MHz" : "80MHz")));
|
|
printf("%-23s%d.%d dBm\n", "User Target:",
|
|
DIV_QUO(ppr_wl->user_target, 4), DIV_REM(ppr_wl->user_target, 4));
|
|
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");
|
|
#ifdef D11AC_IOTYPES
|
|
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);
|
|
#endif
|
|
printf("\n");
|
|
|
|
printf("Regulatory Limits:\n");
|
|
#ifdef D11AC_IOTYPES
|
|
if (brief)
|
|
{
|
|
wl_txpwr_regulatory_array_row_print(ppr_wl->clm_limits,
|
|
ppr_wl->clm_limits_subchan1, ppr_wl->clm_limits_subchan2,
|
|
ppr_wl->channel_bandwidth,
|
|
get_reg_rate_index_from_ratespec(ppr_wl->last_tx_ratespec));
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
wl_txpwr_regulatory_array_print(ppr_wl->clm_limits,
|
|
ppr_wl->clm_limits_subchan1, ppr_wl->clm_limits_subchan2,
|
|
ppr_wl->channel_bandwidth, verbose);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("%-23s%d\n", "Core Index:", ppr_wl->display_core);
|
|
printf("Board Limits:\n");
|
|
#ifdef D11AC_IOTYPES
|
|
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
|
|
#endif
|
|
{
|
|
wl_txpwr_array_print(ppr_board, ppr_wl->channel_bandwidth, verbose);
|
|
printf("\n");
|
|
}
|
|
|
|
printf("Power Targets:\n");
|
|
#ifdef D11AC_IOTYPES
|
|
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
|
|
#endif
|
|
{
|
|
wl_txpwr_array_print(ppr_target, ppr_wl->channel_bandwidth, verbose);
|
|
}
|
|
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++)
|
|
printf("%2d.%02d ",
|
|
DIV_QUO(ppr_wl->tx_power_max[i], 4),
|
|
DIV_REM(ppr_wl->tx_power_max[i], 4));
|
|
printf("\n");
|
|
|
|
printf("Last est. power :\t");
|
|
for (i = 0; i < ppr_wl->rf_cores; i++)
|
|
printf("%2d.%02d ",
|
|
DIV_QUO(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 = 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];
|
|
printf("%2d.%02d ",
|
|
DIV_QUO(power_target, 4),
|
|
DIV_REM(power_target, 4));
|
|
}
|
|
else
|
|
{
|
|
printf(" - ");
|
|
}
|
|
}
|
|
printf("\n");
|
|
|
|
printf("Last adjusted est. power :\t");
|
|
for (i = 0; i < ppr_wl->rf_cores; i++)
|
|
printf("%2d.%02d ",
|
|
DIV_QUO(ppr_wl->est_Pout_act[i], 4),
|
|
DIV_REM(ppr_wl->est_Pout_act[i], 4));
|
|
printf("\n");
|
|
} else {
|
|
printf("Last est. power:\t%2d.%02d dBm\n",
|
|
DIV_QUO(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(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);
|
|
}
|
|
}
|
|
|
|
free(ppr_wl);
|
|
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
|
|
*/
|
|
static void
|
|
wl_txpwr_print_row(const char *label, uint8 chains, int8 pwr20,
|
|
int8 pwr20in40, int8 pwr40, int8 pwr80, int8 pwr20in80, int8 pwr40in80,
|
|
int8 unsupported_rate, int8 channel_bandwidth, bool verbose)
|
|
{
|
|
/* homebrew conversion to qdB, pseudo-floating point representation. */
|
|
int pwr20_q = DIV_QUO(pwr20, 4);
|
|
int pwr20_r = DIV_REM(pwr20, 4);
|
|
|
|
int pwr20in40_q = DIV_QUO(pwr20in40, 4);
|
|
int pwr20in40_r = DIV_REM(pwr20in40, 4);
|
|
|
|
int pwr40_q = DIV_QUO(pwr40, 4);
|
|
int pwr40_r = DIV_REM(pwr40, 4);
|
|
|
|
int pwr80_q = DIV_QUO(pwr80, 4);
|
|
int pwr80_r = DIV_REM(pwr80, 4);
|
|
|
|
int pwr20in80_q = DIV_QUO(pwr20in80, 4);
|
|
int pwr20in80_r = DIV_REM(pwr20in80, 4);
|
|
|
|
int pwr40in80_q = DIV_QUO(pwr40in80, 4);
|
|
int pwr40in80_r = DIV_REM(pwr40in80, 4);
|
|
|
|
|
|
char rate20[] = "- ";
|
|
char rate20in40[] = "- ";
|
|
char rate40[] = "- ";
|
|
char rate80[] = "- ";
|
|
char rate20in80[] = "- ";
|
|
char rate40in80[] = "- ";
|
|
char pad[] = " ";
|
|
|
|
if (pwr20 != unsupported_rate)
|
|
sprintf(rate20, "%2d.%-2d", pwr20_q, pwr20_r);
|
|
if (pwr20in40 != unsupported_rate)
|
|
sprintf(rate20in40, "%2d.%-2d", pwr20in40_q, pwr20in40_r);
|
|
if (pwr40 != unsupported_rate)
|
|
sprintf(rate40, "%2d.%-2d", pwr40_q, pwr40_r);
|
|
if (pwr80 != unsupported_rate)
|
|
sprintf(rate80, "%2d.%-2d", pwr80_q, pwr80_r);
|
|
if (pwr20in80 != unsupported_rate)
|
|
sprintf(rate20in80, "%2d.%-2d", pwr20in80_q, pwr20in80_r);
|
|
if (pwr40in80 != unsupported_rate)
|
|
sprintf(rate40in80, "%2d.%-2d", pwr40in80_q, pwr40in80_r);
|
|
|
|
printf("%-23s%d ", label, chains);
|
|
if (!verbose) {
|
|
switch (channel_bandwidth) {
|
|
case WL_BW_20MHZ:
|
|
printf("%s\n", rate20);
|
|
break;
|
|
case WL_BW_40MHZ:
|
|
printf("%s%s%s\n", rate20in40, pad, rate40);
|
|
break;
|
|
case WL_BW_80MHZ:
|
|
printf("%s%s%s%s%s\n", rate20in80, pad, rate40in80, pad, rate80);
|
|
break;
|
|
}
|
|
} else {
|
|
printf("%s%s%s%s%s%s%s%s%s%s%s\n", rate20, pad, rate20in40, pad,
|
|
rate40, pad, rate20in80, pad, rate40in80, pad, rate80);
|
|
}
|
|
|
|
}
|
|
|
|
static void
|
|
wl_txpwr_print_header(int8 channel_bandwidth, bool verbose)
|
|
{
|
|
printf("Rate Chains ");
|
|
if (!verbose)
|
|
{
|
|
switch (channel_bandwidth) {
|
|
case WL_BW_20MHZ:
|
|
printf("20MHz\n");
|
|
break;
|
|
case WL_BW_40MHZ:
|
|
printf("20in40 40MHz\n");
|
|
break;
|
|
case WL_BW_80MHZ:
|
|
printf("20in80 40in80 80MHz\n");
|
|
break;
|
|
}
|
|
} else {
|
|
printf("20MHz 20in40 40MHz 20in80 40in80 80MHz\n");
|
|
}
|
|
}
|
|
#ifdef D11AC_IOTYPES
|
|
/* 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 void
|
|
wl_txpwr_array_row_print(ppr_t *pprptr, int8 channel_bandwidth, reg_rate_index_t rate_index)
|
|
{
|
|
const char *label;
|
|
int8 pwr20 = WL_RATE_DISABLED;
|
|
int8 pwr20in40 = WL_RATE_DISABLED;
|
|
int8 pwr40 = WL_RATE_DISABLED;
|
|
int8 pwr80 = WL_RATE_DISABLED;
|
|
int8 pwr20in80 = WL_RATE_DISABLED;
|
|
int8 pwr40in80 = WL_RATE_DISABLED;
|
|
|
|
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_20MHZ:
|
|
pwr20 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20);
|
|
break;
|
|
|
|
case WL_BW_40MHZ:
|
|
pwr20in40 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20IN40);
|
|
pwr40 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_40);
|
|
break;
|
|
|
|
case WL_BW_80MHZ:
|
|
pwr80 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_80);
|
|
pwr20in80 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20IN80);
|
|
pwr40in80 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_40IN80);
|
|
break;
|
|
}
|
|
|
|
wl_txpwr_print_row(label, ppr_group_table[group_id].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80, pwr40in80,
|
|
WL_RATE_DISABLED, channel_bandwidth, TRUE);
|
|
}
|
|
}
|
|
#endif
|
|
/* print power value for each group of rates, if not in verbose mode and rates
|
|
* are uniform, one power value is printed out 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)
|
|
{
|
|
uint i;
|
|
const char *label;
|
|
int buniform = FALSE;
|
|
int8 pwr20 = WL_RATE_DISABLED;
|
|
int8 pwr20in40 = WL_RATE_DISABLED;
|
|
int8 pwr40 = WL_RATE_DISABLED;
|
|
int8 pwr80 = WL_RATE_DISABLED;
|
|
int8 pwr20in80 = WL_RATE_DISABLED;
|
|
int8 pwr40in80 = WL_RATE_DISABLED;
|
|
uint len = 0;
|
|
if (pprptr == NULL) {
|
|
fprintf(stderr, "illegal ppr data!\n");
|
|
return;
|
|
}
|
|
switch (type) {
|
|
case PPR_RATE_DSSS:
|
|
{
|
|
len = sizeof(ppr_dsss_rateset_t);
|
|
if (bw == WL_BW_20MHZ) {
|
|
ppr_dsss_rateset_t rate;
|
|
ppr_get_dsss(pprptr, WL_TX_BW_20, ppr_group_table[gid].chain,
|
|
&rate);
|
|
buniform = wl_array_check_val(rate.pwr,
|
|
sizeof(rate), rate.pwr[0]) && !vb;
|
|
if (buniform) {
|
|
pwr20 = rate.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < len; i++) {
|
|
pwr20 = rate.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
} else if (bw == WL_BW_40MHZ) {
|
|
ppr_dsss_rateset_t rate20in40;
|
|
ppr_dsss_rateset_t rate40;
|
|
|
|
ppr_get_dsss(pprptr, WL_TX_BW_20IN40, ppr_group_table[gid].chain,
|
|
&rate20in40);
|
|
ppr_get_dsss(pprptr, WL_TX_BW_40, ppr_group_table[gid].chain,
|
|
&rate40);
|
|
buniform = wl_array_check_val(rate40.pwr,
|
|
sizeof(ppr_dsss_rateset_t), rate40.pwr[0]) && !vb &&
|
|
wl_array_check_val(rate20in40.pwr,
|
|
sizeof(ppr_dsss_rateset_t), rate20in40.pwr[0]);
|
|
if (buniform) {
|
|
pwr20in40 = rate20in40.pwr[0];
|
|
pwr40 = rate40.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < len; i++) {
|
|
pwr20in40 = rate20in40.pwr[i];
|
|
pwr40 = rate40.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
} else if (bw == WL_BW_80MHZ) {
|
|
ppr_dsss_rateset_t rate20in80;
|
|
ppr_dsss_rateset_t rate40in80;
|
|
ppr_dsss_rateset_t rate80;
|
|
ppr_get_dsss(pprptr, WL_TX_BW_20IN80, ppr_group_table[gid].chain,
|
|
&rate20in80);
|
|
ppr_get_dsss(pprptr, WL_TX_BW_40IN80, ppr_group_table[gid].chain,
|
|
&rate40in80);
|
|
ppr_get_dsss(pprptr, WL_TX_BW_80, ppr_group_table[gid].chain,
|
|
&rate80);
|
|
buniform = wl_array_check_val(rate80.pwr,
|
|
sizeof(ppr_dsss_rateset_t), rate80.pwr[0]) && !vb &&
|
|
wl_array_check_val(rate20in80.pwr,
|
|
sizeof(ppr_dsss_rateset_t), rate20in80.pwr[0]) &&
|
|
wl_array_check_val(rate40in80.pwr,
|
|
sizeof(ppr_dsss_rateset_t), rate40in80.pwr[0]);
|
|
if (buniform) {
|
|
pwr20in80 = rate20in80.pwr[0];
|
|
pwr40in80 = rate40in80.pwr[0];
|
|
pwr80 = rate80.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < len; i++) {
|
|
pwr20in80 = rate20in80.pwr[i];
|
|
pwr40in80 = rate40in80.pwr[i];
|
|
pwr80 = rate80.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
}
|
|
*rate_index += len;
|
|
}
|
|
break;
|
|
case PPR_RATE_OFDM:
|
|
{
|
|
len = sizeof(ppr_ofdm_rateset_t);
|
|
if (bw == WL_BW_20MHZ) {
|
|
ppr_ofdm_rateset_t rate;
|
|
ppr_get_ofdm(pprptr, WL_TX_BW_20, ppr_group_table[gid].mode,
|
|
ppr_group_table[gid].chain, &rate);
|
|
buniform = wl_array_check_val(rate.pwr,
|
|
sizeof(rate), rate.pwr[0]) && !vb;
|
|
if (buniform) {
|
|
pwr20 = rate.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < len; i++) {
|
|
pwr20 = rate.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
} else if (bw == WL_BW_40MHZ) {
|
|
ppr_ofdm_rateset_t rate20in40;
|
|
ppr_ofdm_rateset_t rate40;
|
|
|
|
ppr_get_ofdm(pprptr, WL_TX_BW_20IN40, ppr_group_table[gid].mode,
|
|
ppr_group_table[gid].chain, &rate20in40);
|
|
ppr_get_ofdm(pprptr, WL_TX_BW_40, ppr_group_table[gid].mode,
|
|
ppr_group_table[gid].chain, &rate40);
|
|
buniform = wl_array_check_val(rate40.pwr,
|
|
sizeof(ppr_ofdm_rateset_t), rate40.pwr[0]) && !vb &&
|
|
wl_array_check_val(rate20in40.pwr,
|
|
sizeof(ppr_ofdm_rateset_t), rate20in40.pwr[0]);
|
|
if (buniform) {
|
|
pwr20in40 = rate20in40.pwr[0];
|
|
pwr40 = rate40.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < len; i++) {
|
|
pwr20in40 = rate20in40.pwr[i];
|
|
pwr40 = rate40.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
} else if (bw == WL_BW_80MHZ) {
|
|
ppr_ofdm_rateset_t rate20in80;
|
|
ppr_ofdm_rateset_t rate40in80;
|
|
ppr_ofdm_rateset_t rate80;
|
|
ppr_get_ofdm(pprptr, WL_TX_BW_20IN80, ppr_group_table[gid].mode,
|
|
ppr_group_table[gid].chain, &rate20in80);
|
|
ppr_get_ofdm(pprptr, WL_TX_BW_40IN80, ppr_group_table[gid].mode,
|
|
ppr_group_table[gid].chain, &rate40in80);
|
|
ppr_get_ofdm(pprptr, WL_TX_BW_80, ppr_group_table[gid].mode,
|
|
ppr_group_table[gid].chain, &rate80);
|
|
buniform = wl_array_check_val(rate80.pwr,
|
|
sizeof(ppr_ofdm_rateset_t), rate80.pwr[0]) && !vb &&
|
|
wl_array_check_val(rate20in80.pwr,
|
|
sizeof(ppr_ofdm_rateset_t), rate20in80.pwr[0]) &&
|
|
wl_array_check_val(rate40in80.pwr,
|
|
sizeof(ppr_ofdm_rateset_t), rate40in80.pwr[0]);
|
|
if (buniform) {
|
|
pwr20in80 = rate20in80.pwr[0];
|
|
pwr40in80 = rate40in80.pwr[0];
|
|
pwr80 = rate80.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < len; i++) {
|
|
pwr20in80 = rate20in80.pwr[i];
|
|
pwr40in80 = rate40in80.pwr[i];
|
|
pwr80 = rate80.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
}
|
|
*rate_index += len;
|
|
}
|
|
break;
|
|
case PPR_RATE_HT:
|
|
{
|
|
len = sizeof(ppr_ht_mcs_rateset_t);
|
|
if (bw == WL_BW_20MHZ) {
|
|
ppr_ht_mcs_rateset_t rate;
|
|
ppr_get_ht_mcs(pprptr, WL_TX_BW_20, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate);
|
|
buniform = wl_array_check_val(rate.pwr,
|
|
sizeof(rate), rate.pwr[0]) && !vb;
|
|
if (buniform) {
|
|
pwr20 = rate.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < len; i++) {
|
|
pwr20 = rate.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
} else if (bw == WL_BW_40MHZ) {
|
|
ppr_ht_mcs_rateset_t rate20in40;
|
|
ppr_ht_mcs_rateset_t rate40;
|
|
|
|
ppr_get_ht_mcs(pprptr, WL_TX_BW_20IN40, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate20in40);
|
|
ppr_get_ht_mcs(pprptr, WL_TX_BW_40, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate40);
|
|
buniform = wl_array_check_val(rate40.pwr,
|
|
sizeof(ppr_ht_mcs_rateset_t), rate40.pwr[0]) && !vb &&
|
|
wl_array_check_val(rate20in40.pwr,
|
|
sizeof(ppr_ht_mcs_rateset_t), rate20in40.pwr[0]);
|
|
if (buniform) {
|
|
pwr20in40 = rate20in40.pwr[0];
|
|
pwr40 = rate40.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < len; i++) {
|
|
pwr20in40 = rate20in40.pwr[i];
|
|
pwr40 = rate40.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
} else if (bw == WL_BW_80MHZ) {
|
|
ppr_ht_mcs_rateset_t rate20in80;
|
|
ppr_ht_mcs_rateset_t rate40in80;
|
|
ppr_ht_mcs_rateset_t rate80;
|
|
ppr_get_ht_mcs(pprptr, WL_TX_BW_20IN80, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate20in80);
|
|
ppr_get_ht_mcs(pprptr, WL_TX_BW_40IN80, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate40in80);
|
|
ppr_get_ht_mcs(pprptr, WL_TX_BW_80, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate80);
|
|
buniform = wl_array_check_val(rate80.pwr,
|
|
sizeof(ppr_ht_mcs_rateset_t), rate80.pwr[0]) && !vb &&
|
|
wl_array_check_val(rate20in80.pwr,
|
|
sizeof(ppr_ht_mcs_rateset_t), rate20in80.pwr[0]) &&
|
|
wl_array_check_val(rate40in80.pwr,
|
|
sizeof(ppr_ht_mcs_rateset_t), rate40in80.pwr[0]);
|
|
if (buniform) {
|
|
pwr20in80 = rate20in80.pwr[0];
|
|
pwr40in80 = rate40in80.pwr[0];
|
|
pwr80 = rate80.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < len; i++) {
|
|
pwr20in80 = rate20in80.pwr[i];
|
|
pwr40in80 = rate40in80.pwr[i];
|
|
pwr80 = rate80.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
}
|
|
*rate_index += len;
|
|
}
|
|
break;
|
|
case PPR_RATE_VHT:
|
|
{
|
|
uint bvhtuniform = FALSE;
|
|
uint lenht = sizeof(ppr_ht_mcs_rateset_t);
|
|
len = sizeof(ppr_vht_mcs_rateset_t);
|
|
/* VHT RATES are printed as two parts: MCS0-7 and VTH8-9 */
|
|
if (bw == WL_BW_20MHZ) {
|
|
ppr_vht_mcs_rateset_t rate;
|
|
ppr_get_vht_mcs(pprptr, WL_TX_BW_20, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate);
|
|
buniform = wl_array_check_val(rate.pwr, lenht, rate.pwr[0])&& !vb;
|
|
bvhtuniform = wl_array_check_val(&rate.pwr[lenht], len-lenht,
|
|
rate.pwr[lenht]) && !vb;
|
|
if (buniform) {
|
|
pwr20 = rate.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < lenht; i++) {
|
|
pwr20 = rate.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
if (bvhtuniform) {
|
|
pwr20 = rate.pwr[lenht];
|
|
/* print VHT8-9 label */
|
|
label = get_clm_rate_group_label(gid+1);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
} else {
|
|
for (i = lenht; i < len; i++) {
|
|
pwr20 = rate.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
} else if (bw == WL_BW_40MHZ) {
|
|
ppr_vht_mcs_rateset_t rate20in40;
|
|
ppr_vht_mcs_rateset_t rate40;
|
|
|
|
ppr_get_vht_mcs(pprptr, WL_TX_BW_20IN40, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate20in40);
|
|
ppr_get_vht_mcs(pprptr, WL_TX_BW_40, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate40);
|
|
|
|
buniform = wl_array_check_val(rate40.pwr,
|
|
sizeof(ppr_ht_mcs_rateset_t), rate40.pwr[0]) && !vb &&
|
|
wl_array_check_val(rate20in40.pwr,
|
|
sizeof(ppr_ht_mcs_rateset_t), rate20in40.pwr[0]);
|
|
bvhtuniform = wl_array_check_val(&rate40.pwr[lenht], len-lenht,
|
|
rate40.pwr[lenht]) && !vb &&
|
|
wl_array_check_val(&rate20in40.pwr[lenht], len-lenht,
|
|
rate20in40.pwr[lenht]);
|
|
if (buniform) {
|
|
pwr20in40 = rate20in40.pwr[0];
|
|
pwr40 = rate40.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < lenht; i++) {
|
|
pwr20in40 = rate20in40.pwr[i];
|
|
pwr40 = rate40.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
if (bvhtuniform) {
|
|
pwr20in40 = rate20in40.pwr[lenht];
|
|
pwr40 = rate40.pwr[lenht];
|
|
/* print VHT8-9 label */
|
|
label = get_clm_rate_group_label(gid+1);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
} else {
|
|
for (i = lenht; i < len; i++) {
|
|
pwr20in40 = rate20in40.pwr[i];
|
|
pwr40 = rate40.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
} else if (bw == WL_BW_80MHZ) {
|
|
ppr_vht_mcs_rateset_t rate20in80;
|
|
ppr_vht_mcs_rateset_t rate40in80;
|
|
ppr_vht_mcs_rateset_t rate80;
|
|
ppr_get_vht_mcs(pprptr, WL_TX_BW_20IN80, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate20in80);
|
|
ppr_get_vht_mcs(pprptr, WL_TX_BW_40IN80, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate40in80);
|
|
ppr_get_vht_mcs(pprptr, WL_TX_BW_80, ppr_group_table[gid].nss,
|
|
ppr_group_table[gid].mode, ppr_group_table[gid].chain,
|
|
&rate80);
|
|
buniform = wl_array_check_val(rate80.pwr,
|
|
sizeof(ppr_ht_mcs_rateset_t), rate80.pwr[0]) && !vb &&
|
|
wl_array_check_val(rate20in80.pwr,
|
|
sizeof(ppr_ht_mcs_rateset_t), rate20in80.pwr[0]) &&
|
|
wl_array_check_val(rate40in80.pwr,
|
|
sizeof(ppr_ht_mcs_rateset_t), rate40in80.pwr[0]);
|
|
bvhtuniform = wl_array_check_val(&rate80.pwr[lenht], len-lenht,
|
|
rate80.pwr[lenht]) && !vb &&
|
|
wl_array_check_val(&rate20in80.pwr[lenht], len-lenht,
|
|
rate20in80.pwr[lenht]) &&
|
|
wl_array_check_val(&rate40in80.pwr[lenht], len-lenht,
|
|
rate40in80.pwr[lenht]);
|
|
|
|
if (buniform) {
|
|
pwr20in80 = rate20in80.pwr[0];
|
|
pwr40in80 = rate40in80.pwr[0];
|
|
pwr80 = rate80.pwr[0];
|
|
label = get_clm_rate_group_label(gid);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
|
|
} else {
|
|
for (i = 0; i < lenht; i++) {
|
|
pwr20in80 = rate20in80.pwr[i];
|
|
pwr40in80 = rate40in80.pwr[i];
|
|
pwr80 = rate80.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
if (bvhtuniform) {
|
|
pwr20in80 = rate20in80.pwr[lenht];
|
|
pwr40in80 = rate40in80.pwr[lenht];
|
|
pwr80 = rate80.pwr[lenht];
|
|
/* print VHT8-9 label */
|
|
label = get_clm_rate_group_label(gid+1);
|
|
wl_txpwr_print_row(label, ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED, bw, vb);
|
|
} else {
|
|
for (i = lenht; i < len; i++) {
|
|
pwr20in80 = rate20in80.pwr[i];
|
|
pwr40in80 = rate40in80.pwr[i];
|
|
pwr80 = rate80.pwr[i];
|
|
label = ppr_table[*rate_index+i].label;
|
|
wl_txpwr_print_row(label,
|
|
ppr_group_table[gid].chain,
|
|
pwr20, pwr20in40, pwr40, pwr80, pwr20in80,
|
|
pwr40in80, WL_RATE_DISABLED,
|
|
bw, vb);
|
|
}
|
|
}
|
|
}
|
|
*rate_index += len;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
wl_txpwr_array_print(ppr_t* pprptr, int8 bw, bool verbose)
|
|
{
|
|
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);
|
|
/* VHT rates are printed in two parts: MCS + VHT8,9 */
|
|
if (ppr_group_table[i].rate_type == PPR_RATE_VHT)
|
|
i++;
|
|
}
|
|
}
|
|
#ifdef D11AC_IOTYPES
|
|
static void
|
|
wl_txpwr_regulatory_array_row_print(int8 *powers, int8 *powers_subchan1,
|
|
int8 *powers_subchan2, int8 channel_bandwidth, reg_rate_index_t rate_index)
|
|
{
|
|
const int RATE_UNSUPPORTED = -128; /* CLM uses -128 as the unsupported rate */
|
|
const char* label;
|
|
uint8 chains;
|
|
int pwr20 = RATE_UNSUPPORTED;
|
|
int pwr20in40 = RATE_UNSUPPORTED;
|
|
int pwr40 = RATE_UNSUPPORTED;
|
|
int pwr80 = RATE_UNSUPPORTED;
|
|
int pwr20in80 = RATE_UNSUPPORTED;
|
|
int pwr40in80 = RATE_UNSUPPORTED;
|
|
|
|
wl_txpwr_print_header(channel_bandwidth, TRUE);
|
|
|
|
if (rate_index == NO_RATE)
|
|
{
|
|
printf("(NO_RATE) - - - - - - -\n");
|
|
}
|
|
else
|
|
{
|
|
label = ppr_table[rate_index].label;
|
|
chains = ppr_group_table[ppr_table[rate_index].id].chain;
|
|
|
|
switch (channel_bandwidth) {
|
|
case WL_BW_20MHZ:
|
|
pwr20 = powers[ppr_table[rate_index].rate];
|
|
break;
|
|
case WL_BW_40MHZ:
|
|
pwr40 = powers[ppr_table[rate_index].rate];
|
|
pwr20in40 = powers_subchan1[ppr_table[rate_index].rate];
|
|
break;
|
|
case WL_BW_80MHZ:
|
|
pwr80 = powers[ppr_table[rate_index].rate];
|
|
pwr40in80 = powers_subchan1[ppr_table[rate_index].rate];
|
|
pwr20in80 = powers_subchan2[ppr_table[rate_index].rate];
|
|
break;
|
|
}
|
|
wl_txpwr_print_row(label, chains, pwr20, pwr20in40,
|
|
pwr40, pwr80, pwr20in80, pwr40in80, RATE_UNSUPPORTED,
|
|
channel_bandwidth, TRUE);
|
|
}
|
|
}
|
|
#endif
|
|
/* Essentially the same as wl_txpwr_array_print, but the
|
|
* format of the regulatory data is now diffreent enough that we need a separate function.
|
|
* The data format should be unified, and this code removed.
|
|
*/
|
|
static void
|
|
wl_txpwr_regulatory_array_print(int8 *powers, int8 *powers_subchan1,
|
|
int8 *powers_subchan2, int8 channel_bandwidth, bool verbose)
|
|
{
|
|
int i, j;
|
|
const int RATE_UNSUPPORTED = -128; /* CLM uses -128 as the unsupported rate */
|
|
const char* label;
|
|
|
|
/* This code assumes that all of the rates in a group will be contiguous */
|
|
wl_txpwr_print_header(channel_bandwidth, verbose);
|
|
for (i = 0; i < RATE_GROUP_ID_COUNT; i++) {
|
|
int first_rate = 0;
|
|
int num_rates = 0;
|
|
uint8 chains;
|
|
bool compress_rate = FALSE;
|
|
int pwr20 = RATE_UNSUPPORTED;
|
|
int pwr20in40 = RATE_UNSUPPORTED;
|
|
int pwr40 = RATE_UNSUPPORTED;
|
|
int pwr80 = RATE_UNSUPPORTED;
|
|
int pwr20in80 = RATE_UNSUPPORTED;
|
|
int pwr40in80 = RATE_UNSUPPORTED;
|
|
|
|
/* find the first rate index in this group. */
|
|
while ((int)ppr_table[first_rate].id != i)
|
|
first_rate++;
|
|
/* how many rates in that group? */
|
|
while ((first_rate + num_rates < WL_NUMRATES) &&
|
|
((int)ppr_table[first_rate + num_rates].id == i))
|
|
num_rates++;
|
|
|
|
/* are the regulatory power settings the same? */
|
|
switch (channel_bandwidth) {
|
|
case WL_BW_20MHZ:
|
|
compress_rate = !verbose &&
|
|
wl_array_uniform((uint8*)&powers[ppr_table[first_rate].rate], 0,
|
|
num_rates);
|
|
break;
|
|
case WL_BW_40MHZ:
|
|
compress_rate = !verbose &&
|
|
wl_array_uniform((uint8*)&powers[ppr_table[first_rate].rate], 0,
|
|
num_rates) &&
|
|
wl_array_uniform((uint8*)&powers_subchan1[ppr_table
|
|
[first_rate].rate], 0, num_rates);
|
|
break;
|
|
case WL_BW_80MHZ:
|
|
compress_rate = !verbose &&
|
|
wl_array_uniform((uint8*)&powers[ppr_table[first_rate].rate], 0,
|
|
num_rates) &&
|
|
wl_array_uniform((uint8*)&powers_subchan1[ppr_table
|
|
[first_rate].rate], 0, num_rates) &&
|
|
wl_array_uniform((uint8*)&powers_subchan2[ppr_table
|
|
[first_rate].rate], 0, num_rates);
|
|
break;
|
|
}
|
|
|
|
if (compress_rate)
|
|
j = num_rates - 1;
|
|
else
|
|
j = 0;
|
|
|
|
for (; j < num_rates; j++) {
|
|
if (compress_rate)
|
|
label = get_clm_rate_group_label(i);
|
|
else
|
|
label = ppr_table[first_rate + j].label;
|
|
|
|
chains = ppr_group_table[ppr_table[first_rate + j].id].chain;
|
|
|
|
switch (channel_bandwidth) {
|
|
case WL_BW_20MHZ:
|
|
pwr20 = powers[ppr_table[first_rate + j].rate];
|
|
break;
|
|
case WL_BW_40MHZ:
|
|
pwr40 = powers[ppr_table[first_rate + j].rate];
|
|
pwr20in40 = powers_subchan1[ppr_table[first_rate + j].rate];
|
|
break;
|
|
case WL_BW_80MHZ:
|
|
pwr80 = powers[ppr_table[first_rate + j].rate];
|
|
pwr40in80 = powers_subchan1[ppr_table[first_rate + j].rate];
|
|
pwr20in80 = powers_subchan2[ppr_table[first_rate + j].rate];
|
|
break;
|
|
}
|
|
wl_txpwr_print_row(label, chains, pwr20, pwr20in40,
|
|
pwr40, pwr80, pwr20in80, pwr40in80, RATE_UNSUPPORTED,
|
|
channel_bandwidth, verbose);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* return TRUE if all the values in the array are uniformly the same */
|
|
static int
|
|
wl_array_uniform(uint8 *pwr, int start, int count)
|
|
{
|
|
int i, rate;
|
|
|
|
for (i = 1, rate = start + 1; i < count; i++, rate++)
|
|
if (pwr[rate] != pwr[rate - 1])
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
#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_BADARG;
|
|
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 current wsec */
|
|
if (wlu_iovar_getint(wl, "wsec", &wsec) < 0)
|
|
wsec = 0;
|
|
|
|
while (*++argv) {
|
|
if (!stricmp(*argv, "wepkey") || !stricmp(*argv, "wep") || !stricmp(*argv, "key")) {
|
|
/* specified wep key */
|
|
memset(&key, 0, sizeof(key));
|
|
if (!*++argv) {
|
|
ret = BCME_BADARG;
|
|
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) {
|
|
ret = BCME_BADARG;
|
|
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_BADARG;
|
|
goto exit;
|
|
} else if (!stricmp(*argv, "ibss") ||
|
|
!stricmp(*argv, "adhoc") ||
|
|
!stricmp(*argv, "ad-hoc")) {
|
|
infra = 0;
|
|
} else if (!stricmp(*argv, "bss") ||
|
|
!stricmp(*argv, "managed") ||
|
|
!strnicmp(*argv, "infra", 5)) {
|
|
infra = 1;
|
|
} else {
|
|
fprintf(stderr, "%s %s: unrecongnized parameter \"%s\" after "
|
|
"\"infra\" keyword\n", wlu_av0, cmd_name, *argv);
|
|
ret = BCME_BADARG;
|
|
goto exit;
|
|
}
|
|
}
|
|
/* specified authentication mode */
|
|
else if (!stricmp(*argv, "amode") || !strnicmp(*argv, "auth", 4)) {
|
|
if (!*++argv) {
|
|
ret = BCME_BADARG;
|
|
goto exit;
|
|
}
|
|
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;
|
|
#ifdef BCMCCX
|
|
else if (!stricmp(*argv, "cckm"))
|
|
wpa_auth = WPA_AUTH_CCKM;
|
|
else if (!stricmp(*argv, "cckmwpa2"))
|
|
wpa_auth = WPA2_AUTH_CCKM;
|
|
#endif /* BCMCCX */
|
|
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 {
|
|
ret = BCME_BADARG;
|
|
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)
|
|
goto exit;
|
|
|
|
/* set authentication mode */
|
|
auth = htod32(auth);
|
|
if ((ret = wlu_set(wl, WLC_SET_AUTH, &auth, sizeof(int))) < 0)
|
|
goto exit;
|
|
|
|
/* set wsec mode */
|
|
if ((ret = wlu_iovar_setint(wl, "wsec", wsec)) < 0)
|
|
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)
|
|
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;
|
|
}
|
|
|
|
/* set ssid with extend assoc params (if any) */
|
|
join_params->ssid.SSID_len = htod32(join_params->ssid.SSID_len);
|
|
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 -1;
|
|
|
|
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
|
|
*/
|
|
static 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 -1;
|
|
}
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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;
|
|
}
|
|
|
|
#ifdef BCMCCX
|
|
static int
|
|
wl_leap(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
wl_leap_list_t leap_list, *get_list;
|
|
wl_leap_info_t *list_item;
|
|
size_t len;
|
|
int ret, i;
|
|
|
|
if (!*++argv) {
|
|
/* no parameter means this is a `get'. */
|
|
len = sizeof(wl_leap_list_t) + 42 * sizeof(wl_leap_info_t);
|
|
get_list = (wl_leap_list_t *)malloc(len);
|
|
if (!get_list) {
|
|
fprintf(stderr, "memory alloc failure\n");
|
|
return -1;
|
|
}
|
|
get_list->buflen = htod32(len);
|
|
if ((ret = wlu_get(wl, cmd->get, get_list, len)) < 0) {
|
|
free(get_list);
|
|
return ret;
|
|
}
|
|
get_list->buflen = dtoh32(get_list->buflen);
|
|
get_list->version = dtoh32(get_list->version);
|
|
get_list->count = dtoh32(get_list->count);
|
|
printf("buflen %d version %d count %d\n",
|
|
get_list->buflen, get_list->version, get_list->count);
|
|
|
|
for (i = 0, list_item = get_list->leap_info;
|
|
i < (int) get_list->count;
|
|
i++, list_item++) {
|
|
|
|
char user[sizeof(leap_list.leap_info[0].user)+1];
|
|
char pw[sizeof(leap_list.leap_info[0].password)+1];
|
|
char dom[sizeof(leap_list.leap_info[0].domain)+1];
|
|
char ssidbuf[SSID_FMT_BUF_LEN];
|
|
|
|
list_item->ssid.SSID_len = dtoh32(list_item->ssid.SSID_len);
|
|
wl_format_ssid(ssidbuf, list_item->ssid.SSID,
|
|
list_item->ssid.SSID_len);
|
|
memcpy(user, list_item->user, list_item->user_len);
|
|
user[list_item->user_len] = '\0';
|
|
memcpy(pw, list_item->password, list_item->password_len);
|
|
pw[list_item->password_len] = '\0';
|
|
memcpy(dom, list_item->domain, list_item->domain_len);
|
|
dom[list_item->domain_len] = '\0';
|
|
|
|
printf(" % 2d: ssid \"%s\", user \"%s\", password \"%s\", domain \"%s\"\n",
|
|
i, ssidbuf, user, pw, dom);
|
|
|
|
|
|
}
|
|
free(get_list);
|
|
return 0;
|
|
}
|
|
len = strlen(*argv);
|
|
/* ssid has to be a leagal size */
|
|
if (len > DOT11_MAX_SSID_LEN)
|
|
return -1;
|
|
|
|
memset(&leap_list, 0, sizeof(leap_list));
|
|
leap_list.buflen = htod32(sizeof(leap_list));
|
|
leap_list.count = htod32(1);
|
|
|
|
leap_list.leap_info[0].ssid.SSID_len = htod32(len);
|
|
memcpy(leap_list.leap_info[0].ssid.SSID, *argv, len);
|
|
|
|
/* user name must follow */
|
|
if (!*++argv)
|
|
return -1;
|
|
|
|
len = strlen(*argv);
|
|
if (len > sizeof(leap_list.leap_info[0].user))
|
|
return -1;
|
|
leap_list.leap_info[0].user_len = len;
|
|
memcpy(leap_list.leap_info[0].user, *argv, len);
|
|
|
|
/* password must follow */
|
|
if (!*++argv)
|
|
return -1;
|
|
|
|
len = strlen(*argv);
|
|
if (len > sizeof(leap_list.leap_info[0].password))
|
|
return -1;
|
|
leap_list.leap_info[0].password_len = len;
|
|
memcpy(leap_list.leap_info[0].password, *argv, len);
|
|
|
|
/* If there's more, it's a domain name */
|
|
if (*++argv) {
|
|
len = strlen(*argv);
|
|
if (len > sizeof(leap_list.leap_info[0].domain))
|
|
return -1;
|
|
leap_list.leap_info[0].domain_len = len;
|
|
memcpy(leap_list.leap_info[0].domain, *argv, len);
|
|
}
|
|
|
|
return wlu_set(wl, cmd->set, &leap_list, sizeof(leap_list));
|
|
}
|
|
#endif /* BCMCCX */
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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(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);
|
|
}
|
|
|
|
static uint8
|
|
wl_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);
|
|
}
|
|
|
|
#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;
|
|
|
|
if (!*++argv) {
|
|
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;
|
|
printf("TxPower is %d qdbm, %d.%d dbm, %d mW Override is %s\n",
|
|
val, DIV_QUO(val, 4), DIV_REM(val, 4),
|
|
wl_qdbm_to_mw((uint8)(MIN(val, 0xff))),
|
|
override ? "On" : "Off");
|
|
return 0;
|
|
} else {
|
|
/* for set */
|
|
unit = UNIT_DBM; /* default units */
|
|
|
|
/* override can be used in combo with any unit */
|
|
if (!strcmp(*argv, "-o")) {
|
|
override = TRUE;
|
|
if (!*++argv)
|
|
return (-1);
|
|
}
|
|
|
|
if (!strcmp(*argv, "-d")) {
|
|
unit = UNIT_DBM;
|
|
if (!*++argv)
|
|
return (-1);
|
|
}
|
|
else if (!strcmp(*argv, "-q")) {
|
|
unit = UNIT_QDBM;
|
|
if (!*++argv)
|
|
return (-1);
|
|
}
|
|
else if (!strcmp(*argv, "-m")) {
|
|
unit = UNIT_MW;
|
|
if (!*++argv)
|
|
return (-1);
|
|
}
|
|
|
|
/* override can be used in combo with any unit */
|
|
if (!strcmp(*argv, "-o")) {
|
|
override = TRUE;
|
|
if (!*++argv)
|
|
return (-1);
|
|
}
|
|
|
|
val = atoi(*argv);
|
|
|
|
if (val == -1) {
|
|
val = 127; /* Max val of 127 qdbm */
|
|
unit = UNIT_QDBM;
|
|
}
|
|
|
|
if (val <= 0) {
|
|
return -1;
|
|
}
|
|
|
|
switch (unit) {
|
|
case UNIT_MW:
|
|
new_val = wl_mw_to_qdbm((uint16)MIN(val, 0xffff));
|
|
break;
|
|
case UNIT_DBM:
|
|
new_val = val * 4;
|
|
break;
|
|
case UNIT_QDBM:
|
|
new_val = val;
|
|
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 -1;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
if (!*++argv)
|
|
return -1;
|
|
|
|
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 -1;
|
|
}
|
|
|
|
if (!*++argv)
|
|
return -1;
|
|
|
|
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 -1;
|
|
}
|
|
|
|
}
|
|
|
|
return wlu_set(wl, cmd->set, &atten, sizeof(atten_t));
|
|
}
|
|
}
|
|
|
|
static 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_MAXLEN - sizeof(int)) / ETHER_ADDR_LEN;
|
|
uint len;
|
|
|
|
if (!*++argv) {
|
|
if (cmd->get < 0)
|
|
return -1;
|
|
maclist->count = htod32(max);
|
|
if ((ret = wlu_get(wl, cmd->get, maclist, WLC_IOCTL_MAXLEN)) < 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 (!stricmp(*argv, "none") || !stricmp(*argv, "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_MAXLEN)) < 0)
|
|
return ret;
|
|
/* Append to old list */
|
|
maclist->count = dtoh32(maclist->count);
|
|
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 -1;
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
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);
|
|
} 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 (-1);
|
|
}
|
|
|
|
band = htod32(band);
|
|
error = wlu_set(wl, WLC_SET_BAND, &band, sizeof(uint));
|
|
|
|
}
|
|
return (error);
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
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(_CFE_)
|
|
UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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 -1;
|
|
|
|
if (!(fp = fopen(*argv, "rb"))) {
|
|
fprintf(stderr, "%s: No such file or directory\n", *argv);
|
|
return -2;
|
|
}
|
|
|
|
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 */
|
|
}
|
|
|
|
#include <bcmnvram.h>
|
|
|
|
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(_CFE_)
|
|
UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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 -1;
|
|
|
|
if (!(fp = fopen(*argv, "rb"))) {
|
|
fprintf(stderr, "%s: No such file or directory\n", *argv);
|
|
return -2;
|
|
}
|
|
|
|
len = fread(otpw_buf, 1, sizeof(otpw_buf) - 1, fp);
|
|
if ((ret = ferror(fp))) {
|
|
printf("\nerror %d reading %s\n", ret, *argv);
|
|
ret = -3;
|
|
goto out;
|
|
}
|
|
if (!feof(fp)) {
|
|
printf("\nFile %s too large\n", *argv);
|
|
ret = -4;
|
|
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 = -5;
|
|
goto out;
|
|
}
|
|
len = nvr->len - sizeof(struct nvram_header);
|
|
if (len <= 0) {
|
|
printf("Invalid length (%d)\n", len);
|
|
ret = -8;
|
|
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 = -6;
|
|
goto out;
|
|
}
|
|
if (len & 1) {
|
|
printf("File %s has an odd length (%d)\n", *argv, len);
|
|
ret = -7;
|
|
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 */
|
|
}
|
|
|
|
|
|
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 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 -1;
|
|
}
|
|
}
|
|
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 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 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) {
|
|
unsigned char v, *cptr;
|
|
|
|
if (wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr) < 0) {
|
|
printf("Error reading from OTP data\n");
|
|
return IOCTL_ERROR;
|
|
}
|
|
|
|
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_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 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);
|
|
}
|
|
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 ");
|
|
printf("enabled. (mode 1)\n");
|
|
break;
|
|
case WLAN_MANUAL:
|
|
printf("Wireless LAN Interference mitigation ");
|
|
printf("is enabled. (mode 2)\n");
|
|
break;
|
|
case WLAN_AUTO:
|
|
printf("Auto Wireless LAN Interference mitigation is ");
|
|
if (mode & AUTO_ACTIVE)
|
|
printf("enabled and active. (mode 3)\n");
|
|
else
|
|
printf("enabled and 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 (-1);
|
|
|
|
if (phytype == WLC_PHY_TYPE_AC) {
|
|
if (val > ACPHY_ACI_MAX_MODE)
|
|
return -1;
|
|
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 (-1);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
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);
|
|
}
|
|
printf("\n");
|
|
} else {
|
|
switch (mode) {
|
|
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 (-1);
|
|
|
|
if (phytype == WLC_PHY_TYPE_AC) {
|
|
if (val > ACPHY_ACI_MAX_MODE)
|
|
return -1;
|
|
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 (-1);
|
|
}
|
|
}
|
|
|
|
mode = htod32(mode);
|
|
return wlu_set(wl, cmd->set, &mode, sizeof(mode));
|
|
}
|
|
}
|
|
|
|
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 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 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;
|
|
|
|
/* 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 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 */
|
|
wlu_iovar_getint(wl, "bcmerror", &bcmerr);
|
|
if (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 -1;
|
|
}
|
|
} 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 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 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 USAGE_ERROR;
|
|
}
|
|
}
|
|
|
|
if (err) {
|
|
fprintf(stderr,
|
|
"Argument 2 \"%s\" could not be parsed as "
|
|
"a country name or country code\n",
|
|
argv[1]);
|
|
return 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 */
|
|
wlu_iovar_getint(wl, "bcmerror", &bcmerr);
|
|
if (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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
#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"
|
|
|
|
#ifdef BCMINTERNAL
|
|
static int
|
|
wl_aci_args(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
wl_aci_args_t aci_args;
|
|
int val;
|
|
char *endptr;
|
|
int *data;
|
|
uint16 *data2;
|
|
|
|
memset(&aci_args, 0, sizeof(wl_aci_args_t));
|
|
if (!*++argv) {
|
|
if (wlu_get(wl, cmd->get, &aci_args, sizeof(wl_aci_args_t)) < 0) {
|
|
printf("Cannot get ACI args\n");
|
|
printf("aci_args.enter_aci_thresh = %d\n",
|
|
dtoh32(aci_args.enter_aci_thresh));
|
|
return 1;
|
|
}
|
|
aci_args.enter_aci_thresh = dtoh32(aci_args.enter_aci_thresh);
|
|
aci_args.exit_aci_thresh = dtoh32(aci_args.exit_aci_thresh);
|
|
aci_args.usec_spin = dtoh32(aci_args.usec_spin);
|
|
aci_args.glitch_delay = dtoh32(aci_args.glitch_delay);
|
|
aci_args.nphy_adcpwr_enter_thresh = dtoh16(aci_args.nphy_adcpwr_enter_thresh);
|
|
aci_args.nphy_adcpwr_exit_thresh = dtoh16(aci_args.nphy_adcpwr_exit_thresh);
|
|
aci_args.nphy_repeat_ctr = dtoh16(aci_args.nphy_repeat_ctr);
|
|
aci_args.nphy_num_samples = dtoh16(aci_args.nphy_num_samples);
|
|
aci_args.nphy_undetect_window_sz = dtoh16(aci_args.nphy_undetect_window_sz);
|
|
aci_args.nphy_b_energy_lo_aci = dtoh16(aci_args.nphy_b_energy_lo_aci);
|
|
aci_args.nphy_b_energy_md_aci = dtoh16(aci_args.nphy_b_energy_md_aci);
|
|
aci_args.nphy_b_energy_hi_aci = dtoh16(aci_args.nphy_b_energy_hi_aci);
|
|
aci_args.nphy_noise_noassoc_glitch_th_up =
|
|
dtoh16(aci_args.nphy_noise_noassoc_glitch_th_up);
|
|
aci_args.nphy_noise_noassoc_glitch_th_dn =
|
|
dtoh16(aci_args.nphy_noise_noassoc_glitch_th_dn);
|
|
aci_args.nphy_noise_assoc_glitch_th_up =
|
|
dtoh16(aci_args.nphy_noise_assoc_glitch_th_up);
|
|
aci_args.nphy_noise_assoc_glitch_th_dn =
|
|
dtoh16(aci_args.nphy_noise_assoc_glitch_th_dn);
|
|
aci_args.nphy_noise_assoc_aci_glitch_th_up =
|
|
dtoh16(aci_args.nphy_noise_assoc_aci_glitch_th_up);
|
|
aci_args.nphy_noise_assoc_aci_glitch_th_dn =
|
|
dtoh16(aci_args.nphy_noise_assoc_aci_glitch_th_dn);
|
|
aci_args.nphy_noise_assoc_enter_th =
|
|
dtoh16(aci_args.nphy_noise_assoc_enter_th);
|
|
aci_args.nphy_noise_noassoc_enter_th =
|
|
dtoh16(aci_args.nphy_noise_noassoc_enter_th);
|
|
aci_args.nphy_noise_assoc_rx_glitch_badplcp_enter_th =
|
|
dtoh16(aci_args.nphy_noise_assoc_rx_glitch_badplcp_enter_th);
|
|
aci_args.nphy_noise_noassoc_crsidx_incr =
|
|
dtoh16(aci_args.nphy_noise_noassoc_crsidx_incr);
|
|
aci_args.nphy_noise_assoc_crsidx_incr =
|
|
dtoh16(aci_args.nphy_noise_assoc_crsidx_incr);
|
|
|
|
printf("Glitch count to enter ACI scan mode: %d\n", aci_args.enter_aci_thresh);
|
|
printf("Glitch count to exit ACI mode: %d\n", aci_args.exit_aci_thresh);
|
|
printf("Usecs to spin between rssi samples : %d\n", aci_args.usec_spin);
|
|
printf("Interval (in seconds) for ACI scanning "
|
|
"in presence of high glitch count: %d\n\n",
|
|
aci_args.glitch_delay);
|
|
|
|
printf("(NPHY) Glitch count to enter ACI scan mode: %d\n",
|
|
aci_args.enter_aci_thresh);
|
|
printf("(NPHY) ADC power to enter ACI Mitigation mode: %d\n",
|
|
aci_args.nphy_adcpwr_enter_thresh);
|
|
printf("(NPHY) ADC power to exit ACI Mitigation mode: %d\n",
|
|
aci_args.nphy_adcpwr_exit_thresh);
|
|
printf("(NPHY) Number of tries per channel to compute power: %d\n",
|
|
aci_args.nphy_repeat_ctr);
|
|
printf("(NPHY) Number of samples to use to compute power on a channel: %d\n",
|
|
aci_args.nphy_num_samples);
|
|
printf("(NPHY) # Undetects to wait before coming out of ACI Mitigation mode: %d\n",
|
|
aci_args.nphy_undetect_window_sz);
|
|
|
|
printf("(NPHY) bphy energy threshold for low aci pwr: %d\n",
|
|
aci_args.nphy_b_energy_lo_aci);
|
|
printf("(NPHY) bphy energy threshold for medium aci pwr: %d\n",
|
|
aci_args.nphy_b_energy_md_aci);
|
|
printf("(NPHY) bphy energy threshold for high aci pwr: %d\n",
|
|
aci_args.nphy_b_energy_hi_aci);
|
|
printf("(NPHY) nphy_noise_noassoc_glitch_th_up: %d\n",
|
|
aci_args.nphy_noise_noassoc_glitch_th_up);
|
|
printf("(NPHY) nphy_noise_noassoc_glitch_th_dn: %d\n",
|
|
aci_args.nphy_noise_noassoc_glitch_th_dn);
|
|
printf("(NPHY) nphy_noise_assoc_glitch_th_up: %d\n",
|
|
aci_args.nphy_noise_assoc_glitch_th_up);
|
|
printf("(NPHY) nphy_noise_assoc_glitch_th_dn: %d\n",
|
|
aci_args.nphy_noise_assoc_glitch_th_dn);
|
|
printf("(NPHY) nphy_noise_assoc_aci_glitch_th_up: %d\n",
|
|
aci_args.nphy_noise_assoc_aci_glitch_th_up);
|
|
printf("(NPHY) nphy_noise_assoc_aci_glitch_th_dn: %d\n",
|
|
aci_args.nphy_noise_assoc_aci_glitch_th_dn);
|
|
printf("(NPHY) nphy_noise_assoc_enter_th: %d\n",
|
|
aci_args.nphy_noise_assoc_enter_th);
|
|
printf("(NPHY) nphy_noise_noassoc_enter_th: %d\n",
|
|
aci_args.nphy_noise_noassoc_enter_th);
|
|
printf("(NPHY) nphy_noise_assoc_rx_glitch_badplcp_enter_th: %d\n",
|
|
aci_args.nphy_noise_assoc_rx_glitch_badplcp_enter_th);
|
|
printf("(NPHY) nphy_noise_noassoc_crsidx_incr: %d\n",
|
|
aci_args.nphy_noise_noassoc_crsidx_incr);
|
|
printf("(NPHY) nphy_noise_assoc_crsidx_incr: %d\n",
|
|
aci_args.nphy_noise_assoc_crsidx_incr);
|
|
printf("(NPHY) nphy_noise_crsidx_decr: %d\n",
|
|
aci_args.nphy_noise_crsidx_decr);
|
|
|
|
} else {
|
|
if (wlu_get(wl, cmd->get, &aci_args, sizeof(wl_aci_args_t)) < 0) {
|
|
printf("Cannot get ACI args for setting\n");
|
|
return (-1);
|
|
}
|
|
aci_args.enter_aci_thresh = dtoh32(aci_args.enter_aci_thresh);
|
|
aci_args.exit_aci_thresh = dtoh32(aci_args.exit_aci_thresh);
|
|
aci_args.usec_spin = dtoh32(aci_args.usec_spin);
|
|
aci_args.glitch_delay = dtoh32(aci_args.glitch_delay);
|
|
aci_args.nphy_adcpwr_enter_thresh = dtoh16(aci_args.nphy_adcpwr_enter_thresh);
|
|
aci_args.nphy_adcpwr_exit_thresh = dtoh16(aci_args.nphy_adcpwr_exit_thresh);
|
|
aci_args.nphy_repeat_ctr = dtoh16(aci_args.nphy_repeat_ctr);
|
|
aci_args.nphy_num_samples = dtoh16(aci_args.nphy_num_samples);
|
|
aci_args.nphy_undetect_window_sz = dtoh16(aci_args.nphy_undetect_window_sz);
|
|
aci_args.nphy_b_energy_lo_aci = dtoh16(aci_args.nphy_b_energy_lo_aci);
|
|
aci_args.nphy_b_energy_md_aci = dtoh16(aci_args.nphy_b_energy_md_aci);
|
|
aci_args.nphy_b_energy_hi_aci = dtoh16(aci_args.nphy_b_energy_hi_aci);
|
|
aci_args.nphy_noise_noassoc_glitch_th_up =
|
|
dtoh16(aci_args.nphy_noise_noassoc_glitch_th_up);
|
|
aci_args.nphy_noise_noassoc_glitch_th_dn =
|
|
dtoh16(aci_args.nphy_noise_noassoc_glitch_th_dn);
|
|
aci_args.nphy_noise_assoc_glitch_th_up =
|
|
dtoh16(aci_args.nphy_noise_assoc_glitch_th_up);
|
|
aci_args.nphy_noise_assoc_glitch_th_dn =
|
|
dtoh16(aci_args.nphy_noise_assoc_glitch_th_dn);
|
|
aci_args.nphy_noise_assoc_aci_glitch_th_up =
|
|
dtoh16(aci_args.nphy_noise_assoc_aci_glitch_th_up);
|
|
aci_args.nphy_noise_assoc_aci_glitch_th_dn =
|
|
dtoh16(aci_args.nphy_noise_assoc_aci_glitch_th_dn);
|
|
aci_args.nphy_noise_noassoc_enter_th =
|
|
dtoh16(aci_args.nphy_noise_noassoc_enter_th);
|
|
aci_args.nphy_noise_assoc_enter_th =
|
|
dtoh16(aci_args.nphy_noise_assoc_enter_th);
|
|
aci_args.nphy_noise_assoc_rx_glitch_badplcp_enter_th =
|
|
dtoh16(aci_args.nphy_noise_assoc_rx_glitch_badplcp_enter_th);
|
|
aci_args.nphy_noise_noassoc_crsidx_incr =
|
|
dtoh16(aci_args.nphy_noise_noassoc_crsidx_incr);
|
|
aci_args.nphy_noise_assoc_crsidx_incr =
|
|
dtoh16(aci_args.nphy_noise_assoc_crsidx_incr);
|
|
|
|
while (*argv) {
|
|
/* Parse keyword */
|
|
data = (void *)NULL;
|
|
data2 = (void *)NULL;
|
|
if (!strncmp(*argv, ACI_ENTER, strlen("en")))
|
|
data = &aci_args.enter_aci_thresh;
|
|
if (!strncmp(*argv, ACI_EXIT, strlen("ex")))
|
|
data = &aci_args.exit_aci_thresh;
|
|
if (!strncmp(*argv, ACI_SPIN, strlen(*argv)))
|
|
data = &aci_args.usec_spin;
|
|
if (!strncmp(*argv, ACI_GLITCH, strlen(*argv)))
|
|
data = &aci_args.glitch_delay;
|
|
|
|
if (!strncmp(*argv, NPHY_ACI_ADCPWR_ENTER, strlen(*argv)))
|
|
data2 = &aci_args.nphy_adcpwr_enter_thresh;
|
|
if (!strncmp(*argv, NPHY_ACI_ADCPWR_EXIT, strlen(*argv)))
|
|
data2 = &aci_args.nphy_adcpwr_exit_thresh;
|
|
if (!strncmp(*argv, NPHY_ACI_REPEAT_CTR, strlen(*argv)))
|
|
data2 = &aci_args.nphy_repeat_ctr;
|
|
if (!strncmp(*argv, NPHY_ACI_NUM_SAMPLES, strlen(*argv)))
|
|
data2 = &aci_args.nphy_num_samples;
|
|
if (!strncmp(*argv, NPHY_ACI_UNDETECT, strlen(*argv)))
|
|
data2 = &aci_args.nphy_undetect_window_sz;
|
|
if (!strncmp(*argv, NPHY_ACI_LOPWR, strlen(*argv)))
|
|
data2 = &aci_args.nphy_b_energy_lo_aci;
|
|
if (!strncmp(*argv, NPHY_ACI_MDPWR, strlen(*argv)))
|
|
data2 = &aci_args.nphy_b_energy_md_aci;
|
|
if (!strncmp(*argv, NPHY_ACI_HIPWR, strlen(*argv)))
|
|
data2 = &aci_args.nphy_b_energy_hi_aci;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_NOASSOC_GLITCH_TH_UP, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_noassoc_glitch_th_up;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_NOASSOC_GLITCH_TH_DN, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_noassoc_glitch_th_dn;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_ASSOC_GLITCH_TH_UP, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_assoc_glitch_th_up;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_ASSOC_GLITCH_TH_DN, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_assoc_glitch_th_dn;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_ASSOC_ACI_GLITCH_TH_UP, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_assoc_aci_glitch_th_up;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_ASSOC_ACI_GLITCH_TH_DN, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_assoc_aci_glitch_th_dn;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_NOASSOC_ENTER_TH, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_noassoc_enter_th;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_ASSOC_ENTER_TH, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_assoc_enter_th;
|
|
if (!strncmp(*argv,
|
|
NPHY_ACI_NOISE_ASSOC_RX_GLITCH_BADPLCP_ENTER_TH, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_assoc_rx_glitch_badplcp_enter_th;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_ASSOC_CRSIDX_INCR, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_assoc_crsidx_incr;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_NOASSOC_CRSIDX_INCR, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_noassoc_crsidx_incr;
|
|
if (!strncmp(*argv, NPHY_ACI_NOISE_CRSIDX_DECR, strlen(*argv)))
|
|
data2 = &aci_args.nphy_noise_crsidx_decr;
|
|
|
|
if (!data && !data2) {
|
|
printf("Bad parameter specification\n");
|
|
return (-1);
|
|
}
|
|
/* Parse value */
|
|
if (*(argv+1)) {
|
|
val = strtol(*(argv+1), &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
/* not all the value string was parsed by strtol */
|
|
return (-1);
|
|
}
|
|
if (val < 0) {
|
|
printf("Invalid value for %s\n", *argv);
|
|
return (-1);
|
|
}
|
|
if (data) *data = val;
|
|
if (data2) *data2 = (uint16)val;
|
|
|
|
} else {
|
|
printf("Need to specify a value\n");
|
|
return (-1);
|
|
}
|
|
argv += 2;
|
|
}
|
|
|
|
aci_args.enter_aci_thresh = htod32(aci_args.enter_aci_thresh);
|
|
aci_args.exit_aci_thresh = htod32(aci_args.exit_aci_thresh);
|
|
aci_args.usec_spin = htod32(aci_args.usec_spin);
|
|
aci_args.glitch_delay = htod32(aci_args.glitch_delay);
|
|
aci_args.nphy_adcpwr_enter_thresh = htod16(aci_args.nphy_adcpwr_enter_thresh);
|
|
aci_args.nphy_adcpwr_exit_thresh = htod16(aci_args.nphy_adcpwr_exit_thresh);
|
|
aci_args.nphy_repeat_ctr = htod16(aci_args.nphy_repeat_ctr);
|
|
aci_args.nphy_num_samples = htod16(aci_args.nphy_num_samples);
|
|
aci_args.nphy_undetect_window_sz = htod16(aci_args.nphy_undetect_window_sz);
|
|
aci_args.nphy_b_energy_lo_aci = htod16(aci_args.nphy_b_energy_lo_aci);
|
|
aci_args.nphy_b_energy_md_aci = htod16(aci_args.nphy_b_energy_md_aci);
|
|
aci_args.nphy_b_energy_hi_aci = htod16(aci_args.nphy_b_energy_hi_aci);
|
|
aci_args.nphy_noise_noassoc_glitch_th_up =
|
|
htod16(aci_args.nphy_noise_noassoc_glitch_th_up);
|
|
aci_args.nphy_noise_noassoc_glitch_th_dn =
|
|
htod16(aci_args.nphy_noise_noassoc_glitch_th_dn);
|
|
aci_args.nphy_noise_assoc_glitch_th_up =
|
|
htod16(aci_args.nphy_noise_assoc_glitch_th_up);
|
|
aci_args.nphy_noise_assoc_glitch_th_dn =
|
|
htod16(aci_args.nphy_noise_assoc_glitch_th_dn);
|
|
aci_args.nphy_noise_assoc_aci_glitch_th_up =
|
|
htod16(aci_args.nphy_noise_assoc_aci_glitch_th_up);
|
|
aci_args.nphy_noise_assoc_aci_glitch_th_dn =
|
|
htod16(aci_args.nphy_noise_assoc_aci_glitch_th_dn);
|
|
aci_args.nphy_noise_assoc_enter_th =
|
|
htod16(aci_args.nphy_noise_assoc_enter_th);
|
|
aci_args.nphy_noise_noassoc_enter_th =
|
|
htod16(aci_args.nphy_noise_noassoc_enter_th);
|
|
aci_args.nphy_noise_assoc_rx_glitch_badplcp_enter_th =
|
|
htod16(aci_args.nphy_noise_assoc_rx_glitch_badplcp_enter_th);
|
|
aci_args.nphy_noise_noassoc_crsidx_incr =
|
|
htod16(aci_args.nphy_noise_noassoc_crsidx_incr);
|
|
aci_args.nphy_noise_assoc_crsidx_incr =
|
|
htod16(aci_args.nphy_noise_assoc_crsidx_incr);
|
|
|
|
if (wlu_set(wl, cmd->set, &aci_args, sizeof(wl_aci_args_t)) < 0) {
|
|
printf("Cannot set ACI args\n");
|
|
return (-1);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
#endif /* BCMINTERNAL */
|
|
|
|
#if defined(BWL_FILESYSTEM_SUPPORT)
|
|
#if !defined(_CFE_) && !defined(_HNDRTE_) && !defined(__IOPOS__)
|
|
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_LCN40);
|
|
|
|
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);
|
|
}
|
|
|
|
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 /* !defined(_CFE_) && !defined(_HNDRTE_) && !defined(__IOPOS__) */
|
|
#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(_CFE_)
|
|
UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
|
|
return 0;
|
|
#else
|
|
int ret = -1;
|
|
uint8 *buff = NULL;
|
|
wl_samplecollect_args_t collect;
|
|
const char *fname = "sample_collect.dat";
|
|
wlc_rev_info_t revinfo;
|
|
uint32 phytype, phyrev;
|
|
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.downsamp = FALSE;
|
|
collect.be_deaf = FALSE;
|
|
collect.timeout = 1000; /* XXX FIXME */
|
|
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)
|
|
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
|
|
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 -1;
|
|
}
|
|
memset(buff, 0, WLC_SAMPLECOLLECT_MAXLEN);
|
|
|
|
if ((fp = fopen(fname, "wb")) == NULL) {
|
|
fprintf(stderr, "Problem opening file %s\n", fname);
|
|
ret = -1;
|
|
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_LCN40 >> 2)) {
|
|
fprintf(stderr, "Max number of samples supported = %d\n",
|
|
WLC_SAMPLECOLLECT_MAXLEN_LCN40 >> 2);
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
ret = wl_do_samplecollect_lcn40(wl, &collect, buff, fp);
|
|
}
|
|
|
|
exit:
|
|
if (buff) free(buff);
|
|
if (fp) fclose(fp);
|
|
return ret;
|
|
#endif /* !BWL_FILESYSTEM_SUPPORT */
|
|
}
|
|
|
|
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 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;
|
|
}
|
|
|
|
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 USAGE_ERROR;
|
|
|
|
tid = atoi(param);
|
|
if (tid > MAXPRIO)
|
|
return 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_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 USAGE_ERROR;
|
|
|
|
tid = atoi(param);
|
|
if (tid > MAXPRIO)
|
|
return 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 USAGE_ERROR;
|
|
|
|
tid = atoi(param);
|
|
if (tid > MAXPRIO)
|
|
return 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 USAGE_ERROR;
|
|
|
|
tid = atoi(param);
|
|
if (tid > MAXPRIO)
|
|
return USAGE_ERROR;
|
|
aet.tid = tid;
|
|
|
|
argv++;
|
|
if (!*argv) {
|
|
printf("error: missing address\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv, &aet.ea)) {
|
|
printf("error: could not parse MAC address %s\n", *argv);
|
|
return -1;
|
|
}
|
|
|
|
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 USAGE_ERROR;
|
|
|
|
tid = atoi(param);
|
|
if (tid > MAXPRIO)
|
|
return USAGE_ERROR;
|
|
aet.tid = tid;
|
|
|
|
argv++;
|
|
if (!*argv) {
|
|
printf("error: missing address\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv, &aet.ea)) {
|
|
printf("error: could not parse MAC address %s\n", *argv);
|
|
return -1;
|
|
}
|
|
|
|
return wlu_var_setbuf(wl, cmdname, &aet, sizeof(aet));
|
|
}
|
|
|
|
static int
|
|
wl_dpt_deny(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *cmdname = "dpt_deny";
|
|
dpt_iovar_t info;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (!*++argv)
|
|
return USAGE_ERROR;
|
|
|
|
info.pad = 0;
|
|
|
|
if (!strcmp("add", *argv))
|
|
info.mode = DPT_DENY_LIST_ADD;
|
|
else if (!strcmp("remove", *argv))
|
|
info.mode = DPT_DENY_LIST_REMOVE;
|
|
else {
|
|
printf("error: invalid mode string\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
argv++;
|
|
if (!*argv) {
|
|
printf("error: missing mode value\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv, &info.ea)) {
|
|
printf("error: could not parse MAC address %s\n", *argv);
|
|
return -1;
|
|
}
|
|
|
|
return wlu_var_setbuf(wl, cmdname, &info, sizeof(info));
|
|
}
|
|
|
|
static int
|
|
wl_dpt_endpoint(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *cmdname = "dpt_endpoint";
|
|
dpt_iovar_t info;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (!*++argv)
|
|
return USAGE_ERROR;
|
|
|
|
info.pad = 0;
|
|
|
|
if (!strcmp("create", *argv))
|
|
info.mode = DPT_MANUAL_EP_CREATE;
|
|
else if (!strcmp("modify", *argv))
|
|
info.mode = DPT_MANUAL_EP_MODIFY;
|
|
else if (!strcmp("delete", *argv))
|
|
info.mode = DPT_MANUAL_EP_DELETE;
|
|
else {
|
|
printf("error: invalid mode string\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
argv++;
|
|
if (!*argv) {
|
|
printf("error: missing ea\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv, &info.ea)) {
|
|
printf("error: could not parse MAC address %s\n", *argv);
|
|
return -1;
|
|
}
|
|
|
|
return wlu_var_setbuf(wl, cmdname, &info, sizeof(info));
|
|
}
|
|
|
|
#ifdef WLTDLS
|
|
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 USAGE_ERROR;
|
|
}
|
|
|
|
if (!*++argv)
|
|
return 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 USAGE_ERROR;
|
|
}
|
|
|
|
argv++;
|
|
if (!*argv) {
|
|
printf("error: missing ea\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv, &info.ea)) {
|
|
printf("error: could not parse MAC address %s\n", *argv);
|
|
return -1;
|
|
}
|
|
|
|
if (info.mode == TDLS_MANUAL_EP_CHSW) {
|
|
argv++;
|
|
if (!*argv) {
|
|
printf("error: missing target channel number\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
if (atoi(*argv) != 0) {
|
|
chanspec = wf_chspec_aton(*argv);
|
|
if (chanspec == 0) {
|
|
printf("error: bad chanspec \"%s\".\n", *argv);
|
|
return USAGE_ERROR;
|
|
}
|
|
chanspec = wl_chspec_to_driver(chanspec);
|
|
if (chanspec == INVCHANSPEC) {
|
|
return USAGE_ERROR;
|
|
}
|
|
info.chanspec = chanspec;
|
|
}
|
|
}
|
|
|
|
return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info));
|
|
}
|
|
|
|
static int
|
|
wl_pattern_atoh(char *, char *);
|
|
|
|
#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;
|
|
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 USAGE_ERROR;
|
|
}
|
|
|
|
if (!*++argv)
|
|
return USAGE_ERROR;
|
|
|
|
if (!strcmp(*argv, "clr")) {
|
|
memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
|
|
|
|
if (!*++argv)
|
|
return USAGE_ERROR;
|
|
|
|
if (!strcmp("own", *argv))
|
|
info.mode = TDLS_WFD_IE_TX;
|
|
else {
|
|
printf("error: invalid mode string\n");
|
|
return 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 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 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 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 USAGE_ERROR;
|
|
|
|
if (!strcmp("own", *argv))
|
|
info.mode = TDLS_WFD_IE_TX;
|
|
else {
|
|
printf("error: invalid mode string\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
argv++;
|
|
if (!*argv) {
|
|
printf("error: missing IE string\n");
|
|
return 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 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 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 USAGE_ERROR;
|
|
}
|
|
|
|
if (!wl_atoip(*argv, &ipa_set))
|
|
return 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 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 USAGE_ERROR;
|
|
|
|
if (!strcmp("own", *argv))
|
|
info.mode = TDLS_WFD_PROBE_IE_TX;
|
|
else {
|
|
printf("error: invalid mode string\n");
|
|
return 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 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 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 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 USAGE_ERROR;
|
|
|
|
if (!strcmp("own", *argv))
|
|
info.mode = TDLS_WFD_PROBE_IE_TX;
|
|
else {
|
|
printf("error: invalid mode string\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
argv++;
|
|
if (!*argv) {
|
|
printf("error: missing IE string\n");
|
|
return 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 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 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 USAGE_ERROR;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv, &ea)) return 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 USAGE_ERROR;
|
|
}
|
|
}
|
|
#endif /* WLTDLS */
|
|
|
|
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 -1;
|
|
}
|
|
|
|
/* 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 -1;
|
|
}
|
|
af_params->channel = 0;
|
|
af_params->dwell_time = -1;
|
|
action_frame = &af_params->action_frame;
|
|
|
|
/* Add the packet Id */
|
|
/* xxx Not 64-bit safe */
|
|
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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
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_dpt_pmk(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *cmdname = "dpt_pmk";
|
|
wsec_pmk_t psk;
|
|
size_t key_len;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (!*++argv)
|
|
return 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 -1;
|
|
}
|
|
psk.key_len = htod16((ushort) key_len);
|
|
psk.flags = htod16(WSEC_PASSPHRASE);
|
|
memcpy(psk.key, *argv, key_len);
|
|
|
|
return wlu_var_setbuf(wl, cmdname, &psk, sizeof(wsec_pmk_t));
|
|
}
|
|
|
|
static int
|
|
wl_dpt_fname(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char *param;
|
|
const char *cmdname = "dpt_fname";
|
|
int err;
|
|
dpt_fname_t fname, *reply;
|
|
void *ptr = NULL;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if ((param = *++argv)) {
|
|
fname.len = strlen(param);
|
|
if (fname.len >= (DPT_FNAME_LEN - 1)) {
|
|
fprintf(stderr, "Name must be less than 32 characters\n");
|
|
return -1;
|
|
}
|
|
memcpy(fname.name, param, fname.len);
|
|
fname.name[fname.len] = '\0';
|
|
err = wlu_var_setbuf(wl, cmdname, &fname, sizeof(fname));
|
|
} else {
|
|
if ((err = wlu_var_getbuf(wl, cmdname, &fname, sizeof(fname), &ptr) < 0))
|
|
return err;
|
|
reply = (dpt_fname_t *)ptr;
|
|
printf("%s\n", reply->name);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static int
|
|
wl_dpt_list(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
uint32 i;
|
|
dpt_list_t *list;
|
|
|
|
if (*++argv)
|
|
return USAGE_ERROR;
|
|
|
|
strcpy(buf, cmd->name);
|
|
if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
|
|
return err;
|
|
|
|
list = (dpt_list_t *) buf;
|
|
|
|
printf("List of DPT connections:\n");
|
|
for (i = 0; i < list->num; i++) {
|
|
printf("%s: status 0x%x rx %d tx %d rssi %d\n",
|
|
list->status[i].name,
|
|
list->status[i].status,
|
|
list->status[i].sta.rx_ucast_pkts,
|
|
list->status[i].sta.tx_pkts,
|
|
list->status[i].rssi);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
#ifdef WLBTAMP
|
|
#define MATCH_OP(op, opstr) (strlen(op) == strlen(opstr) && strncmp(op, opstr, strlen(op)) == 0)
|
|
|
|
static int
|
|
wl_HCI_cmd(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
union {
|
|
char buf[HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE];
|
|
uint32 alignme;
|
|
} cbuf;
|
|
amp_hci_cmd_t *cpkt = (amp_hci_cmd_t *)&cbuf.buf[0];
|
|
char *op;
|
|
uint8 plen;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (!*++argv)
|
|
return USAGE_ERROR;
|
|
|
|
/* recognize and encode operations */
|
|
op = *argv++;
|
|
if (MATCH_OP(op, "Read_Link_Quality")) {
|
|
cpkt->opcode = HCI_Read_Link_Quality;
|
|
} else if (MATCH_OP(op, "Read_Local_AMP_Info")) {
|
|
cpkt->opcode = HCI_Read_Local_AMP_Info;
|
|
} else if (MATCH_OP(op, "Read_Local_AMP_ASSOC")) {
|
|
cpkt->opcode = HCI_Read_Local_AMP_ASSOC;
|
|
} else if (MATCH_OP(op, "Write_Remote_AMP_ASSOC")) {
|
|
cpkt->opcode = HCI_Write_Remote_AMP_ASSOC;
|
|
} else if (MATCH_OP(op, "Create_Physical_Link")) {
|
|
cpkt->opcode = HCI_Create_Physical_Link;
|
|
} else if (MATCH_OP(op, "Accept_Physical_Link_Request")) {
|
|
cpkt->opcode = HCI_Accept_Physical_Link_Request;
|
|
} else if (MATCH_OP(op, "Disconnect_Physical_Link")) {
|
|
cpkt->opcode = HCI_Disconnect_Physical_Link;
|
|
} else if (MATCH_OP(op, "Create_Logical_Link")) {
|
|
cpkt->opcode = HCI_Create_Logical_Link;
|
|
} else if (MATCH_OP(op, "Accept_Logical_Link")) {
|
|
cpkt->opcode = HCI_Accept_Logical_Link;
|
|
} else if (MATCH_OP(op, "Disconnect_Logical_Link")) {
|
|
cpkt->opcode = HCI_Disconnect_Logical_Link;
|
|
} else if (MATCH_OP(op, "Logical_Link_Cancel")) {
|
|
cpkt->opcode = HCI_Logical_Link_Cancel;
|
|
} else if (MATCH_OP(op, "Short_Range_Mode")) {
|
|
cpkt->opcode = HCI_Short_Range_Mode;
|
|
} else if (MATCH_OP(op, "Read_Connection_Accept_Timeout")) {
|
|
cpkt->opcode = HCI_Read_Connection_Accept_Timeout;
|
|
} else if (MATCH_OP(op, "Write_Connection_Accept_Timeout")) {
|
|
cpkt->opcode = HCI_Write_Connection_Accept_Timeout;
|
|
} else if (MATCH_OP(op, "Read_Link_Supervision_Timeout")) {
|
|
cpkt->opcode = HCI_Read_Link_Supervision_Timeout;
|
|
} else if (MATCH_OP(op, "Write_Link_Supervision_Timeout")) {
|
|
cpkt->opcode = HCI_Write_Link_Supervision_Timeout;
|
|
} else if (MATCH_OP(op, "Reset")) {
|
|
cpkt->opcode = HCI_Reset;
|
|
} else if (MATCH_OP(op, "Enhanced_Flush")) {
|
|
cpkt->opcode = HCI_Enhanced_Flush;
|
|
} else if (MATCH_OP(op, "Read_Best_Effort_Flush_Timeout")) {
|
|
cpkt->opcode = HCI_Read_Best_Effort_Flush_Timeout;
|
|
} else if (MATCH_OP(op, "Write_Best_Effort_Flush_Timeout")) {
|
|
cpkt->opcode = HCI_Write_Best_Effort_Flush_Timeout;
|
|
} else if (MATCH_OP(op, "Read_Logical_Link_Accept_Timeout")) {
|
|
cpkt->opcode = HCI_Read_Logical_Link_Accept_Timeout;
|
|
} else if (MATCH_OP(op, "Write_Logical_Link_Accept_Timeout")) {
|
|
cpkt->opcode = HCI_Write_Logical_Link_Accept_Timeout;
|
|
} else if (MATCH_OP(op, "Read_Buffer_Size")) {
|
|
cpkt->opcode = HCI_Read_Buffer_Size;
|
|
} else if (MATCH_OP(op, "Read_Data_Block_Size")) {
|
|
cpkt->opcode = HCI_Read_Data_Block_Size;
|
|
} else if (MATCH_OP(op, "Set_Event_Mask_Page_2")) {
|
|
cpkt->opcode = HCI_Set_Event_Mask_Page_2;
|
|
} else if (MATCH_OP(op, "Flow_Spec_Modify")) {
|
|
cpkt->opcode = HCI_Flow_Spec_Modify;
|
|
} else if (MATCH_OP(op, "Read_Local_Version_Info")) {
|
|
cpkt->opcode = HCI_Read_Local_Version_Info;
|
|
} else if (MATCH_OP(op, "Read_Local_Supported_Commands")) {
|
|
cpkt->opcode = HCI_Read_Local_Supported_Commands;
|
|
} else if (MATCH_OP(op, "Read_Failed_Contact_Counter")) {
|
|
cpkt->opcode = HCI_Read_Failed_Contact_Counter;
|
|
} else if (MATCH_OP(op, "Reset_Failed_Contact_Counter")) {
|
|
cpkt->opcode = HCI_Reset_Failed_Contact_Counter;
|
|
} else {
|
|
printf("unsupported HCI command: %s\n", op);
|
|
return (-1);
|
|
}
|
|
|
|
plen = 0;
|
|
while (*argv && (plen < HCI_CMD_DATA_SIZE)) {
|
|
cpkt->parms[plen++] = (uint8)strtol(*argv++, NULL, 0);
|
|
}
|
|
cpkt->plen = plen;
|
|
|
|
return wlu_var_setbuf(wl, cmd->name, cpkt, HCI_CMD_PREAMBLE_SIZE + plen);
|
|
}
|
|
|
|
static int
|
|
wl_HCI_ACL_data(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
amp_hci_ACL_data_t *dpkt;
|
|
uint16 dlen;
|
|
int ret;
|
|
|
|
if (!*++argv)
|
|
return USAGE_ERROR;
|
|
|
|
dpkt = (amp_hci_ACL_data_t *) malloc(HCI_ACL_DATA_PREAMBLE_SIZE + 2048);
|
|
if (!dpkt)
|
|
return -1;
|
|
|
|
/* get logical link handle */
|
|
dpkt->handle = (HCI_ACL_DATA_BC_FLAGS | HCI_ACL_DATA_PB_FLAGS);
|
|
dpkt->handle |= (uint16)strtol(*argv++, NULL, 0);
|
|
|
|
/* get data */
|
|
dlen = 0;
|
|
while (*argv && (dlen < 2048)) {
|
|
dpkt->data[dlen++] = (uint8)strtol(*argv++, NULL, 0);
|
|
}
|
|
dpkt->dlen = dlen;
|
|
|
|
ret = wlu_var_setbuf(wl, cmd->name, dpkt, HCI_ACL_DATA_PREAMBLE_SIZE + dlen);
|
|
|
|
free(dpkt);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
wl_get_btamp_log(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err, i, j;
|
|
char *val_name;
|
|
uint8 *state;
|
|
uint8 idx = 0;
|
|
void *ptr = buf;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
/* command name */
|
|
val_name = *argv++;
|
|
|
|
if (!*argv) {
|
|
if ((err = wlu_var_getbuf_sm (wl, cmd->name, NULL, 0, &ptr)))
|
|
return err;
|
|
state = (uint8 *)ptr;
|
|
idx = *state++;
|
|
|
|
for (i = 0; i < BTA_STATE_LOG_SZ; i++, idx--) {
|
|
j = (idx & (BTA_STATE_LOG_SZ - 1));
|
|
switch (state[j]) {
|
|
case HCIReset:
|
|
printf("%2d: HCI Reset\n", state[j]);
|
|
break;
|
|
case HCIReadLocalAMPInfo:
|
|
printf("%2d: HCI Read Local AMPInfo\n", state[j]);
|
|
break;
|
|
case HCIReadLocalAMPASSOC:
|
|
printf("%2d: HCI Read Local AMPASSOC\n", state[j]);
|
|
break;
|
|
case HCIWriteRemoteAMPASSOC:
|
|
printf("%2d: HCI Write Remote AMPASSOC\n", state[j]);
|
|
break;
|
|
case HCICreatePhysicalLink:
|
|
printf("%2d: HCI Create Physical Link\n", state[j]);
|
|
break;
|
|
case HCIAcceptPhysicalLinkRequest:
|
|
printf("%2d: HCI Accept Physical Link Request\n", state[j]);
|
|
break;
|
|
case HCIDisconnectPhysicalLink:
|
|
printf("%2d: HCI Disconnect Physical Link\n", state[j]);
|
|
break;
|
|
case HCICreateLogicalLink:
|
|
printf("%2d: HCI Create Logical Link\n", state[j]);
|
|
break;
|
|
case HCIAcceptLogicalLink:
|
|
printf("%2d: HCI Accept Logical Link\n", state[j]);
|
|
break;
|
|
case HCIDisconnectLogicalLink:
|
|
printf("%2d: HCI Disconnect Logical Link\n", state[j]);
|
|
break;
|
|
case HCILogicalLinkCancel:
|
|
printf("%2d: HCI Logical Link Cancel\n", state[j]);
|
|
break;
|
|
case HCIAmpStateChange:
|
|
printf("%2d: HCI Amp State Change\n", state[j]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
} else
|
|
err = wlu_iovar_setint(wl, val_name, (int)idx);
|
|
|
|
return err;
|
|
}
|
|
#endif /* WLBTAMP */
|
|
|
|
/*
|
|
* 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);
|
|
/* 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\n",
|
|
ra.min_burst_intv_lp, ra.max_burst_intv_lp, ra.nskip_rst_lp,
|
|
ra.max_pw_tol, ra.feature_mask);
|
|
|
|
} else {
|
|
/* Set */
|
|
char *endptr = NULL;
|
|
int val_count = 30;
|
|
long vals[30];
|
|
long *pval;
|
|
int i;
|
|
|
|
for (i = 0; i < val_count; i++, argv++) {
|
|
/* verify that there is another arg */
|
|
if (*argv == NULL)
|
|
return -1;
|
|
|
|
vals[i] = strtol(*argv, &endptr, 0);
|
|
|
|
/* make sure all the value string was parsed by strtol */
|
|
if (*endptr != '\0')
|
|
return -1;
|
|
}
|
|
|
|
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++;
|
|
|
|
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;
|
|
int val_count = 12;
|
|
uint16 vals[12];
|
|
uint16 *pval;
|
|
int i;
|
|
|
|
for (i = 0; i < val_count; i++, argv++) {
|
|
/* verify that there is another arg */
|
|
if (*argv == NULL)
|
|
return -1;
|
|
|
|
vals[i] = (uint16)strtol(*argv, &endptr, 0);
|
|
|
|
/* make sure all the value string was parsed by strtol */
|
|
if (*endptr != '\0')
|
|
return -1;
|
|
}
|
|
|
|
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++;
|
|
return wlu_var_setbuf(wl, cmd->name, &radar_thrs, sizeof(wl_radar_thr_t));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
wl_dfs_status(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret;
|
|
wl_dfs_status_t *dfs_status_ptr;
|
|
char chanspec_str[CHANSPEC_STR_LEN];
|
|
|
|
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)"
|
|
};
|
|
|
|
void *ptr;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return ret;
|
|
|
|
dfs_status_ptr = (wl_dfs_status_t *)ptr;
|
|
|
|
dfs_status_ptr->state = dtoh32(dfs_status_ptr->state);
|
|
dfs_status_ptr->duration = dtoh32(dfs_status_ptr->duration);
|
|
dfs_status_ptr->chanspec_cleared = wl_chspec_from_driver(dfs_status_ptr->chanspec_cleared);
|
|
|
|
if (dfs_status_ptr->state >= WL_DFS_CACSTATES) {
|
|
printf("Unknown dfs state %d.\n", dfs_status_ptr->state);
|
|
return -1;
|
|
}
|
|
|
|
printf("state %s time elapsed %dms radar channel cleared by dfs ",
|
|
dfs_cacstate_str[dfs_status_ptr->state], dfs_status_ptr->duration);
|
|
|
|
if (dfs_status_ptr->chanspec_cleared) {
|
|
printf("channel %s (0x%04X)\n",
|
|
wf_chspec_ntoa(dfs_status_ptr->chanspec_cleared, chanspec_str),
|
|
dfs_status_ptr->chanspec_cleared);
|
|
}
|
|
else {
|
|
printf("none\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
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];
|
|
ra.ch = wl_chspec_from_driver(ra.ch);
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
if ((ret = wlu_iovar_get(wl, cmd->name, &ra, sizeof(ra))) < 0)
|
|
return ret;
|
|
|
|
if (ra.detected == FALSE) {
|
|
printf("NO RADAR DETEDTED \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_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));
|
|
}
|
|
static int
|
|
wl_wds_wpa_role_old(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
uint remote[2];
|
|
uint *sup = remote;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if (wlu_get(wl, WLC_WDS_GET_REMOTE_HWADDR, remote, sizeof(remote)) < 0) {
|
|
printf("Unable to get remote endpoint's hwaddr\n");
|
|
return -1;
|
|
}
|
|
if (wlu_get(wl, cmd->get, remote, sizeof(remote)) < 0) {
|
|
printf("Unable to get local endpoint's WPA role\n");
|
|
return -1;
|
|
}
|
|
printf("Local endpoing's WPA role: %s\n", dtoh32(*sup) ? "supplicant" : "authenticator");
|
|
return 0;
|
|
}
|
|
|
|
#ifdef BCMINTERNAL
|
|
static int
|
|
wlu_ccreg(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char var[256];
|
|
uint32 int_val;
|
|
bool get = TRUE;
|
|
uint32 len;
|
|
void *ptr = NULL;
|
|
char *endptr;
|
|
|
|
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 -1;
|
|
|
|
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 (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;
|
|
}
|
|
#endif /* BCMINTERNAL */
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
static 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;
|
|
|
|
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 -1;
|
|
|
|
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 (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;
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
static 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;
|
|
|
|
len = 0;
|
|
|
|
if (!argv[1] || !argv[2]) {
|
|
printf("Wrong syntax => dev offset [val]\n");
|
|
return -1;
|
|
}
|
|
|
|
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 (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;
|
|
}
|
|
|
|
#ifdef BCMINTERNAL
|
|
/*
|
|
* wlu_reg1or3args is a generic function that is used for setting/getting
|
|
* WL_IOVAR variables that require address for read, and
|
|
* address + mask + data for write.
|
|
*/
|
|
static int
|
|
wlu_reg1or3args(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;
|
|
|
|
len = 0;
|
|
|
|
if (!argv[1]) {
|
|
printf("Wrong syntax => cmd addr [mask val]\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!argv[2]) {
|
|
numargs = 1;
|
|
} else {
|
|
if (!argv[3]) {
|
|
printf("Wrong syntax => cmd addr [mask val]\n");
|
|
return -1;
|
|
}
|
|
get = FALSE;
|
|
numargs = 3;
|
|
}
|
|
|
|
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 (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;
|
|
}
|
|
|
|
static int
|
|
wl_coma(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char var[256];
|
|
uint32 int_val;
|
|
uint32 len, i;
|
|
char *endptr;
|
|
uint numargs;
|
|
int err = 0;
|
|
|
|
len = 0;
|
|
|
|
if (!argv[1]) {
|
|
printf("Wrong syntax => coma [reset-time] [delay]\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!argv[2]) {
|
|
numargs = 1;
|
|
} else if (!argv[3]) {
|
|
numargs = 2;
|
|
} else {
|
|
numargs = 3;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
err = wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
|
|
|
|
return err;
|
|
}
|
|
#endif /* BCMINTERNAL */
|
|
|
|
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;
|
|
}
|
|
|
|
#if defined(BCMINTERNAL)
|
|
static int
|
|
wl_tpc_rpt_override(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char *endptr;
|
|
int err = 0;
|
|
uint32 txpwr_linkm = 0;
|
|
|
|
/* toss the command name */
|
|
argv++;
|
|
|
|
if (*argv == NULL) {
|
|
/* get */
|
|
err = wlu_iovar_getint(wl, cmd->name, (int*)&txpwr_linkm);
|
|
if (err)
|
|
return err;
|
|
printf("TxPwr:%d Link Margin:%d\n", ((txpwr_linkm>> 8) & 0xff),
|
|
(txpwr_linkm & 0xff));
|
|
} else {
|
|
int8 txpwr, linkm;
|
|
/* set */
|
|
if (argv[1] == NULL)
|
|
return USAGE_ERROR;
|
|
|
|
txpwr = (uint8)strtoul(*argv, &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
fprintf(stderr, "%s: %s: error parsing \"%s\" as an integer\n",
|
|
wlu_av0, cmd->name, *argv);
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
argv++;
|
|
linkm = (uint8)strtoul(*argv, &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
fprintf(stderr, "%s: %s: error parsing \"%s\" as an integer\n",
|
|
wlu_av0, cmd->name, *argv);
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
txpwr_linkm = (txpwr << 8) | linkm;
|
|
|
|
err = wlu_iovar_setint(wl, cmd->name, (int)txpwr_linkm);
|
|
if (err)
|
|
return err;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
#endif /* BCMINTERNAL */
|
|
|
|
static int
|
|
wl_wds_wpa_role(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char var[256];
|
|
char *mac;
|
|
char *sup;
|
|
int len;
|
|
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 (wlu_get(wl, WLC_WDS_GET_REMOTE_HWADDR, mac, ETHER_ADDR_LEN) < 0) {
|
|
printf("Unable to get remote endpoint's hwaddr\n");
|
|
return -1;
|
|
}
|
|
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 (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 (wlu_get(wl, cmd->get, var, len) < 0) {
|
|
printf("Unable to get local endpoint's WPA role\n");
|
|
return -1;
|
|
}
|
|
else {
|
|
sup = var;
|
|
printf("Local endpoint's WPA role: %s\n", *sup ? "supplicant" : "authenticator");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
argv++;
|
|
|
|
if (!*argv) {
|
|
printf("error: missing target address\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv, &ea)) {
|
|
printf("error: could not parse MAC address %s\n", *argv);
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
/* Order is count, duration, offset */
|
|
quiet.count = atoi(*argv);
|
|
if (!*++argv) {
|
|
printf("error: missing arguments\n");
|
|
return -1;
|
|
}
|
|
quiet.duration = atoi(*argv);
|
|
if (!*++argv) {
|
|
printf("error: missing arguments\n");
|
|
return -1;
|
|
}
|
|
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_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 -1;
|
|
}
|
|
csa_arg.mode = atoi(*argv) ? 1 : 0;
|
|
if (!*++argv) {
|
|
printf("error: missing count\n");
|
|
return -1;
|
|
}
|
|
csa_arg.count = atoi(*argv);
|
|
if (!*++argv) {
|
|
printf("error: missing channel\n");
|
|
return -1;
|
|
}
|
|
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 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 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 -1;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
static int
|
|
wl_var_setint(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int32 val;
|
|
char *varname;
|
|
char *endptr = NULL;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (!*argv) {
|
|
printf("set: missing arguments\n");
|
|
return -1;
|
|
}
|
|
|
|
varname = *argv++;
|
|
|
|
if (!*argv) {
|
|
printf("set: missing value argument for set of \"%s\"\n", varname);
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
return wlu_iovar_setint(wl, varname, val);
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
static 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 -1;
|
|
}
|
|
|
|
varname = *argv++;
|
|
|
|
if (*argv) {
|
|
printf("get: error, extra arg \"%s\"\n", *argv);
|
|
return -1;
|
|
}
|
|
|
|
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_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;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
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 -1;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
static 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);
|
|
}
|
|
|
|
/* 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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
/* 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 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);
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
static 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 bsscfg indexed iovar buffer
|
|
*/
|
|
static int
|
|
wl_bssiovar_mkbuf(const char *iovar, int bssidx, void *param,
|
|
int paramlen, void *bufptr, int buflen, int *perr)
|
|
{
|
|
const char *prefix = "bsscfg:";
|
|
int8* p;
|
|
uint prefixlen;
|
|
uint namelen;
|
|
uint iolen;
|
|
|
|
prefixlen = strlen(prefix); /* length of bsscfg prefix */
|
|
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;
|
|
|
|
/* bss config index as first param */
|
|
bssidx = htod32(bssidx);
|
|
memcpy(p, &bssidx, sizeof(int32));
|
|
p += sizeof(int32);
|
|
|
|
/* parameter buffer follows */
|
|
if (paramlen)
|
|
memcpy(p, param, paramlen);
|
|
|
|
*perr = 0;
|
|
return iolen;
|
|
}
|
|
|
|
/*
|
|
* 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 -1;
|
|
}
|
|
|
|
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;
|
|
}
|
|
printf("%s\n", (char *)p);
|
|
|
|
return err;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
varname = *argv++;
|
|
|
|
if (*argv) {
|
|
printf("nvget error: extra arg \"%s\"\n", *argv);
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
varname = *argv++;
|
|
|
|
if (*argv) {
|
|
fprintf(stderr,
|
|
"nvset error: extra arg \"%s\"; format is name=value (no spaces around '=')\n",
|
|
*argv);
|
|
return -1;
|
|
}
|
|
|
|
if (!strchr(varname, '=')) {
|
|
fprintf(stderr,
|
|
"nvset error: no '=' in \"%s\", format is name=value (no spaces around '=')\n",
|
|
*argv);
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
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);
|
|
}
|
|
|
|
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 -1;
|
|
|
|
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;
|
|
}
|
|
|
|
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 -1;
|
|
|
|
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;
|
|
}
|
|
|
|
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 -1;
|
|
|
|
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;
|
|
}
|
|
|
|
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_sta_info(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
sta_info_t *sta;
|
|
struct ether_addr ea;
|
|
char *param;
|
|
int buflen, err;
|
|
|
|
/* copy the IOV command */
|
|
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 -1;
|
|
}
|
|
|
|
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_t *)buf;
|
|
sta->ver = dtoh16(sta->ver);
|
|
|
|
/* Report unrecognized version */
|
|
if (sta->ver > WL_STA_VER) {
|
|
printf(" ERROR: unknown driver station info version %d\n", sta->ver);
|
|
return -1;
|
|
}
|
|
|
|
sta->len = dtoh16(sta->len);
|
|
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(" STA %s:\n", *argv);
|
|
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" : "");
|
|
}
|
|
|
|
/* Driver didn't return extended station info */
|
|
if (sta->len < sizeof(sta_info_t))
|
|
return 0;
|
|
|
|
if (sta->flags & WL_STA_SCBSTATS)
|
|
{
|
|
printf("\t tx data pkts: %d\n", dtoh32(sta->tx_tot_pkts));
|
|
printf("\t tx data 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));
|
|
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\n", dtoh32(sta->tx_rate));
|
|
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));
|
|
}
|
|
|
|
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 0x%x\n", dtoh32(revinfo.corerev));
|
|
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));
|
|
printf("driverrev 0x%x\n", dtoh32(revinfo.driverrev));
|
|
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 0x%x\n", dtoh32(revinfo.phyrev));
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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", 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 -1;
|
|
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 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 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 USAGE_ERROR;
|
|
}
|
|
if (val > chk_lim) {
|
|
printf("Value for %s must be < %d\n", param, chk_lim + 1);
|
|
return 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 0;
|
|
}
|
|
|
|
/*
|
|
* 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 USAGE_ERROR;
|
|
|
|
if (!strcmp(param, "ap"))
|
|
iovar_name = "wme_ac_ap";
|
|
else if (!strcmp(param, "sta"))
|
|
iovar_name = "wme_ac_sta";
|
|
else
|
|
return 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 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 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 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 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 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 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 USAGE_ERROR;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "unexpected param %s\n", param);
|
|
return 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 ap_mode;
|
|
int qosinfo;
|
|
int msp, max_sp_len, be, bk, vi, vo;
|
|
|
|
if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))) < 0)
|
|
return err;
|
|
|
|
if (ap_mode) {
|
|
printf("%s: STA only\n", cmd->name);
|
|
return -1;
|
|
}
|
|
|
|
/* 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 -1;
|
|
be = (int)strtol(param, 0, 0);
|
|
if ((param = *++argv) == NULL)
|
|
return -1;
|
|
bk = (int)strtol(param, 0, 0);
|
|
if ((param = *++argv) == NULL)
|
|
return -1;
|
|
vi = (int)strtol(param, 0, 0);
|
|
if ((param = *++argv) == NULL)
|
|
return -1;
|
|
vo = (int)strtol(param, 0, 0);
|
|
|
|
if (((be | bk | vi | vo) & ~1) | (max_sp_len & ~6)) {
|
|
printf("%s: Invalid parameter\n", cmd->name);
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
bk = (int)strtol(param, 0, 0);
|
|
if ((param = *++argv) == NULL)
|
|
return -1;
|
|
vi = (int)strtol(param, 0, 0);
|
|
if ((param = *++argv) == NULL)
|
|
return -1;
|
|
vo = (int)strtol(param, 0, 0);
|
|
|
|
if ((be | bk | vi | vo) & ~1) {
|
|
printf("%s: Invalid parameter\n", cmd->name);
|
|
return -1;
|
|
}
|
|
|
|
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 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 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_IWAPID_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 -1;
|
|
}
|
|
|
|
pktflag = (uint)strtol(argv[1], 0, 0);
|
|
|
|
if (pktflag & ~pktflag_ok) {
|
|
fprintf(stderr, "Invalid packet flag 0x%x (%d)\n", pktflag, pktflag);
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
else if (ielen < VNDR_IE_MIN_LEN) {
|
|
fprintf(stderr, "IE length is %d, should be >= %d\n", ielen, VNDR_IE_MIN_LEN);
|
|
return -1;
|
|
}
|
|
|
|
/* XXX is OUI a fixed length? */
|
|
if (strlen(argv[3]) != OUI_STR_SIZE) {
|
|
fprintf(stderr, "Invalid OUI length %d\n", (int)strlen(argv[3]));
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
/* 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_PROPR_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 err;
|
|
}
|
|
|
|
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 err;
|
|
}
|
|
}
|
|
|
|
/* 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, "ie", ie_setbuf, buflen);
|
|
else
|
|
err = wlu_bssiovar_setbuf(wl, "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_PROPR_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 = "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);
|
|
}
|
|
|
|
#define PRVAL(name) pbuf += sprintf(pbuf, "%s %u ", #name, dtoh32(cnt->name))
|
|
#define PRD11VAL(name) pbuf += sprintf(pbuf, "d11_%s %d ", #name, dtoh32(cnt->name))
|
|
#define PRVALSIX(name) pbuf += sprintf(pbuf, "%s %u ", #name, dtoh32(cnt_six->name))
|
|
#define PRVALSEVEN(name) pbuf += sprintf(pbuf, "%s %u ", #name, dtoh32(cnt_seven->name))
|
|
|
|
#define PRNL() pbuf += sprintf(pbuf, "\n")
|
|
|
|
#define WL_CNT_VERSION_FIVE 5
|
|
#define WL_CNT_VERSION_SIX 6
|
|
#define WL_CNT_VERSION_SEVEN 7
|
|
|
|
static int
|
|
wl_counters5(void *ptr)
|
|
{
|
|
wl_cnt_ver_five_t *cnt;
|
|
uint i;
|
|
char *pbuf = buf;
|
|
uint len;
|
|
char tmp;
|
|
|
|
cnt = (wl_cnt_ver_five_t*)malloc(sizeof(wl_cnt_ver_five_t));
|
|
if (cnt == NULL) {
|
|
printf("\tCan not allocate %d bytes for counters five struct\n",
|
|
(int)sizeof(wl_cnt_ver_five_t));
|
|
return (-1);
|
|
} else
|
|
memcpy(cnt, (char *)ptr, sizeof(wl_cnt_ver_five_t));
|
|
|
|
cnt->version = dtoh16(cnt->version);
|
|
cnt->length = dtoh16(cnt->length);
|
|
|
|
/* summary stat counter line */
|
|
PRVAL(txframe); PRVAL(txbyte); PRVAL(txretrans); PRVAL(txerror);
|
|
PRVAL(rxframe); PRVAL(rxbyte); PRVAL(rxerror); PRNL();
|
|
|
|
PRVAL(txprshort); PRVAL(txdmawar); PRVAL(txnobuf); PRVAL(txnoassoc);
|
|
PRVAL(txchit); PRVAL(txcmiss); PRNL();
|
|
|
|
PRVAL(reset); PRVAL(txserr); PRVAL(txphyerr); PRVAL(txphycrs);
|
|
PRVAL(txfail); PRVAL(tbtt); PRNL();
|
|
|
|
PRD11VAL(txfrag); PRD11VAL(txmulti); PRD11VAL(txretry); PRD11VAL(txretrie); PRNL();
|
|
PRD11VAL(txrts); PRD11VAL(txnocts); PRD11VAL(txnoack); PRD11VAL(txfrmsnt); PRNL();
|
|
|
|
PRVAL(rxcrc); PRVAL(rxnobuf); PRVAL(rxnondata); PRVAL(rxbadds);
|
|
PRVAL(rxbadcm); PRVAL(rxdup); PRVAL(rxfragerr); PRNL();
|
|
|
|
PRVAL(rxrunt); PRVAL(rxgiant); PRVAL(rxnoscb); PRVAL(rxbadproto);
|
|
PRVAL(rxbadsrcmac); PRNL();
|
|
|
|
PRD11VAL(rxfrag); PRD11VAL(rxmulti); PRD11VAL(rxundec); PRNL();
|
|
|
|
PRVAL(rxctl); PRVAL(rxbadda); PRVAL(rxfilter); PRNL();
|
|
|
|
pbuf += sprintf(pbuf, "rxuflo: ");
|
|
for (i = 0; i < NFIFO; i++)
|
|
pbuf += sprintf(pbuf, "%d ", dtoh32(cnt->rxuflo[i]));
|
|
PRNL();
|
|
PRVAL(txallfrm); PRVAL(txrtsfrm); PRVAL(txctsfrm); PRVAL(txackfrm); PRNL();
|
|
PRVAL(txdnlfrm); PRVAL(txbcnfrm); PRVAL(txtplunfl); PRVAL(txphyerr); PRNL();
|
|
pbuf += sprintf(pbuf, "txfunfl: ");
|
|
for (i = 0; i < NFIFO; i++)
|
|
pbuf += sprintf(pbuf, "%d ", dtoh32(cnt->txfunfl[i]));
|
|
PRNL();
|
|
|
|
/* WPA2 counters */
|
|
PRNL();
|
|
PRVAL(tkipmicfaill); PRVAL(tkipicverr); PRVAL(tkipcntrmsr); PRNL();
|
|
PRVAL(tkipreplay); PRVAL(ccmpfmterr); PRVAL(ccmpreplay); PRNL();
|
|
PRVAL(ccmpundec); PRVAL(fourwayfail); PRVAL(wepundec); PRNL();
|
|
PRVAL(wepicverr); PRVAL(decsuccess); PRVAL(rxundec); PRNL();
|
|
|
|
PRNL();
|
|
PRVAL(rxfrmtoolong); PRVAL(rxfrmtooshrt);
|
|
PRVAL(rxinvmachdr); PRVAL(rxbadfcs); PRNL();
|
|
PRVAL(rxbadplcp); PRVAL(rxcrsglitch);
|
|
PRVAL(rxstrt); PRVAL(rxdfrmucastmbss); PRNL();
|
|
PRVAL(rxmfrmucastmbss); PRVAL(rxcfrmucast);
|
|
PRVAL(rxrtsucast); PRVAL(rxctsucast); PRNL();
|
|
PRVAL(rxackucast); PRVAL(rxdfrmocast);
|
|
PRVAL(rxmfrmocast); PRVAL(rxcfrmocast); PRNL();
|
|
PRVAL(rxrtsocast); PRVAL(rxctsocast);
|
|
PRVAL(rxdfrmmcast); PRVAL(rxmfrmmcast); PRNL();
|
|
PRVAL(rxcfrmmcast); PRVAL(rxbeaconmbss);
|
|
PRVAL(rxdfrmucastobss); PRVAL(rxbeaconobss); PRNL();
|
|
PRVAL(rxrsptmout); PRVAL(bcntxcancl);
|
|
PRVAL(rxf0ovfl); PRVAL(rxf1ovfl); PRNL();
|
|
PRVAL(rxf2ovfl); PRVAL(txsfovfl); PRVAL(pmqovfl); PRNL();
|
|
PRVAL(rxcgprqfrm); PRVAL(rxcgprsqovfl);
|
|
PRVAL(txcgprsfail); PRVAL(txcgprssuc); PRNL();
|
|
PRVAL(prs_timeout); PRVAL(rxnack); PRVAL(frmscons);
|
|
PRVAL(txnack); PRVAL(txglitch_nack); PRNL();
|
|
PRVAL(txburst); PRVAL(txphyerror); PRNL();
|
|
PRVAL(txchanrej); PRNL();
|
|
|
|
if (cnt->version >= 4) {
|
|
/* per-rate receive counters */
|
|
PRVAL(rx1mbps); PRVAL(rx2mbps); PRVAL(rx5mbps5); PRNL();
|
|
PRVAL(rx6mbps); PRVAL(rx9mbps); PRVAL(rx11mbps); PRNL();
|
|
PRVAL(rx12mbps); PRVAL(rx18mbps); PRVAL(rx24mbps); PRNL();
|
|
PRVAL(rx36mbps); PRVAL(rx48mbps); PRVAL(rx54mbps); PRNL();
|
|
}
|
|
|
|
if (cnt->version >= 5) {
|
|
PRVAL(pktengrxducast); PRVAL(pktengrxdmcast); PRNL();
|
|
}
|
|
|
|
pbuf = buf;
|
|
len = strlen(buf);
|
|
for (i = 0; i < len; i++) {
|
|
if (buf[i] == '\n') {
|
|
tmp = buf[i+1];
|
|
buf[i+1] = '\0';
|
|
fputs(pbuf, stdout);
|
|
buf[i+1] = tmp;
|
|
pbuf = &buf[i+1];
|
|
}
|
|
}
|
|
|
|
if (cnt)
|
|
free(cnt);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
wl_counters(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char *statsbuf;
|
|
wl_cnt_t *cnt = NULL;
|
|
wl_cnt_ver_six_t *cnt_six = NULL;
|
|
wl_cnt_ver_seven_t *cnt_seven = NULL;
|
|
int err;
|
|
uint i;
|
|
char *pbuf = buf;
|
|
void *ptr;
|
|
uint16 ver;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr)))
|
|
return (err);
|
|
|
|
statsbuf = (char *)ptr;
|
|
|
|
ver = *(uint16*)statsbuf;
|
|
|
|
/* PR49085: makes wl compable with older driver */
|
|
if (ver > WL_CNT_T_VERSION) {
|
|
printf("\tIncorrect version of counters struct: expected %d; got %d\n",
|
|
WL_CNT_T_VERSION, ver);
|
|
return -1;
|
|
}
|
|
else if (ver == WL_CNT_VERSION_FIVE) {
|
|
printf("\tUse version 5 counters struct\n");
|
|
return wl_counters5(ptr);
|
|
}
|
|
else if (ver == WL_CNT_VERSION_SIX) {
|
|
printf("\t wl counters will use version 6 counters struct\n");
|
|
cnt_six = (wl_cnt_ver_six_t*)malloc(sizeof(wl_cnt_ver_six_t));
|
|
if (cnt_six == NULL) {
|
|
printf("\tCan not allocate %d bytes for counters six struct\n",
|
|
(int)sizeof(wl_cnt_ver_six_t));
|
|
return (-1);
|
|
} else
|
|
memcpy(cnt_six, statsbuf, sizeof(wl_cnt_ver_six_t));
|
|
} else if (ver == WL_CNT_VERSION_SEVEN) {
|
|
printf("\t wl counters will use version 7 counters struct\n");
|
|
cnt_seven = (wl_cnt_ver_seven_t*)malloc(sizeof(wl_cnt_ver_seven_t));
|
|
if (cnt_seven == NULL) {
|
|
printf("\tCan not allocate %d bytes for counters seven struct\n",
|
|
(int)sizeof(wl_cnt_ver_seven_t));
|
|
return (-1);
|
|
} else
|
|
memcpy(cnt_seven, statsbuf, sizeof(wl_cnt_ver_seven_t));
|
|
}
|
|
|
|
cnt = (wl_cnt_t*)malloc(sizeof(wl_cnt_t));
|
|
if (cnt == NULL) {
|
|
printf("\tCan not allocate %d bytes for counters struct\n",
|
|
(int)sizeof(wl_cnt_t));
|
|
return (-1);
|
|
} else
|
|
memcpy(cnt, statsbuf, sizeof(wl_cnt_t));
|
|
|
|
/* summary stat counter line */
|
|
PRVAL(txframe); PRVAL(txbyte); PRVAL(txretrans); PRVAL(txerror);
|
|
PRVAL(rxframe); PRVAL(rxbyte); PRVAL(rxerror); PRNL();
|
|
|
|
PRVAL(txprshort); PRVAL(txdmawar); PRVAL(txnobuf); PRVAL(txnoassoc);
|
|
PRVAL(txchit); PRVAL(txcmiss); PRNL();
|
|
|
|
PRVAL(reset); PRVAL(txserr); PRVAL(txphyerr); PRVAL(txphycrs);
|
|
PRVAL(txfail); PRVAL(tbtt); PRNL();
|
|
|
|
pbuf += sprintf(pbuf, "d11_txfrag %u d11_txmulti %u d11_txretry %u d11_txretrie %u\n",
|
|
dtoh32(cnt->txfrag), dtoh32(cnt->txmulti), dtoh32(cnt->txretry),
|
|
dtoh32(cnt->txretrie));
|
|
|
|
pbuf += sprintf(pbuf, "d11_txrts %u d11_txnocts %u d11_txnoack %u d11_txfrmsnt %u\n",
|
|
dtoh32(cnt->txrts), dtoh32(cnt->txnocts), dtoh32(cnt->txnoack),
|
|
dtoh32(cnt->txfrmsnt));
|
|
|
|
PRVAL(rxcrc); PRVAL(rxnobuf); PRVAL(rxnondata); PRVAL(rxbadds);
|
|
PRVAL(rxbadcm); PRVAL(rxdup); PRVAL(rxfragerr); PRNL();
|
|
|
|
PRVAL(rxrunt); PRVAL(rxgiant); PRVAL(rxnoscb); PRVAL(rxbadproto);
|
|
PRVAL(rxbadsrcmac); PRNL();
|
|
|
|
pbuf += sprintf(pbuf, "d11_rxfrag %u d11_rxmulti %u d11_rxundec %u\n",
|
|
dtoh32(cnt->rxfrag), dtoh32(cnt->rxmulti), dtoh32(cnt->rxundec));
|
|
|
|
PRVAL(rxctl); PRVAL(rxbadda); PRVAL(rxfilter); PRNL();
|
|
|
|
pbuf += sprintf(pbuf, "rxuflo: ");
|
|
for (i = 0; i < NFIFO; i++)
|
|
pbuf += sprintf(pbuf, "%u ", dtoh32(cnt->rxuflo[i]));
|
|
pbuf += sprintf(pbuf, "\n");
|
|
PRVAL(txallfrm); PRVAL(txrtsfrm); PRVAL(txctsfrm); PRVAL(txackfrm); PRVAL(txback); PRNL();
|
|
PRVAL(txdnlfrm); PRVAL(txbcnfrm); PRVAL(txtplunfl); PRVAL(txphyerr); PRNL();
|
|
pbuf += sprintf(pbuf, "txfunfl: ");
|
|
for (i = 0; i < NFIFO; i++)
|
|
pbuf += sprintf(pbuf, "%d ", dtoh32(cnt->txfunfl[i]));
|
|
pbuf += sprintf(pbuf, "\n");
|
|
|
|
/* WPA2 counters */
|
|
PRNL();
|
|
if ((cnt->version == WL_CNT_VERSION_SIX) && (cnt->version != WL_CNT_T_VERSION)) {
|
|
PRVALSIX(tkipmicfaill); PRVALSIX(tkipicverr); PRVALSIX(tkipcntrmsr); PRNL();
|
|
PRVALSIX(tkipreplay); PRVALSIX(ccmpfmterr); PRVALSIX(ccmpreplay); PRNL();
|
|
PRVALSIX(ccmpundec); PRVALSIX(fourwayfail); PRVALSIX(wepundec); PRNL();
|
|
PRVALSIX(wepicverr); PRVALSIX(decsuccess); PRVALSIX(rxundec); PRNL();
|
|
} else if ((cnt->version == WL_CNT_VERSION_SEVEN) && (cnt->version != WL_CNT_T_VERSION)) {
|
|
PRVALSEVEN(tkipmicfaill); PRVALSEVEN(tkipicverr); PRVALSEVEN(tkipcntrmsr); PRNL();
|
|
PRVALSEVEN(tkipreplay); PRVALSEVEN(ccmpfmterr); PRVALSEVEN(ccmpreplay); PRNL();
|
|
PRVALSEVEN(ccmpundec); PRVALSEVEN(fourwayfail); PRVALSEVEN(wepundec); PRNL();
|
|
PRVALSEVEN(wepicverr); PRVALSEVEN(decsuccess); PRVALSEVEN(rxundec); PRNL();
|
|
} else {
|
|
PRVAL(tkipmicfaill); PRVAL(tkipicverr); PRVAL(tkipcntrmsr); PRNL();
|
|
PRVAL(tkipreplay); PRVAL(ccmpfmterr); PRVAL(ccmpreplay); PRNL();
|
|
PRVAL(ccmpundec); PRVAL(fourwayfail); PRVAL(wepundec); PRNL();
|
|
PRVAL(wepicverr); PRVAL(decsuccess); PRVAL(rxundec); PRNL();
|
|
}
|
|
PRNL();
|
|
PRVAL(rxfrmtoolong); PRVAL(rxfrmtooshrt); PRVAL(rxtoolate);
|
|
PRVAL(rxinvmachdr); PRVAL(rxbadfcs); PRNL();
|
|
PRVAL(rxbadplcp); PRVAL(rxcrsglitch);
|
|
PRVAL(bphy_rxcrsglitch); PRVAL(bphy_badplcp); PRNL();
|
|
PRVAL(rxstrt); PRVAL(rxdfrmucastmbss);
|
|
PRVAL(rxmfrmucastmbss); PRVAL(rxcfrmucast); PRNL();
|
|
PRVAL(rxrtsucast); PRVAL(rxctsucast);
|
|
PRVAL(rxackucast); PRVAL(rxback); PRNL();
|
|
PRVAL(rxdfrmocast); PRVAL(rxmfrmocast); PRVAL(rxcfrmocast); PRNL();
|
|
PRVAL(rxrtsocast); PRVAL(rxctsocast);
|
|
PRVAL(rxdfrmmcast); PRVAL(rxmfrmmcast); PRNL();
|
|
PRVAL(rxcfrmmcast); PRVAL(rxbeaconmbss);
|
|
PRVAL(rxdfrmucastobss); PRVAL(rxbeaconobss); PRNL();
|
|
PRVAL(rxrsptmout); PRVAL(bcntxcancl);
|
|
PRVAL(rxf0ovfl); PRVAL(rxf1ovfl); PRNL();
|
|
PRVAL(rxf2ovfl); PRVAL(txsfovfl); PRVAL(pmqovfl); PRNL();
|
|
PRVAL(rxcgprqfrm); PRVAL(rxcgprsqovfl);
|
|
PRVAL(txcgprsfail); PRVAL(txcgprssuc); PRNL();
|
|
PRVAL(prs_timeout); PRVAL(rxnack); PRVAL(frmscons);
|
|
PRVAL(prs_timeout); PRVAL(rxdrop20s); PRVAL(txfbw); PRNL();
|
|
PRVAL(txphyerror); PRVAL(txchanrej); PRNL();
|
|
|
|
if ((cnt->version == WL_CNT_VERSION_SIX) && (cnt->version != WL_CNT_T_VERSION)) {
|
|
/* per-rate receive counters */
|
|
PRVALSIX(rx1mbps); PRVALSIX(rx2mbps); PRVALSIX(rx5mbps5); PRNL();
|
|
PRVALSIX(rx6mbps); PRVALSIX(rx9mbps); PRVALSIX(rx11mbps); PRNL();
|
|
PRVALSIX(rx12mbps); PRVALSIX(rx18mbps); PRVALSIX(rx24mbps); PRNL();
|
|
PRVALSIX(rx36mbps); PRVALSIX(rx48mbps); PRVALSIX(rx54mbps); PRNL();
|
|
|
|
PRVALSIX(pktengrxducast); PRVALSIX(pktengrxdmcast); PRNL();
|
|
|
|
PRVALSIX(txmpdu_sgi); PRVALSIX(rxmpdu_sgi); PRVALSIX(txmpdu_stbc);
|
|
PRVALSIX(rxmpdu_stbc); PRNL();
|
|
} else if ((cnt->version == WL_CNT_VERSION_SEVEN) && (cnt->version != WL_CNT_T_VERSION)) {
|
|
/* per-rate receive counters */
|
|
PRVALSEVEN(rx1mbps); PRVALSEVEN(rx2mbps); PRVALSEVEN(rx5mbps5); PRNL();
|
|
PRVALSEVEN(rx6mbps); PRVALSEVEN(rx9mbps); PRVALSEVEN(rx11mbps); PRNL();
|
|
PRVALSEVEN(rx12mbps); PRVALSEVEN(rx18mbps); PRVALSEVEN(rx24mbps); PRNL();
|
|
PRVALSEVEN(rx36mbps); PRVALSEVEN(rx48mbps); PRVALSEVEN(rx54mbps); PRNL();
|
|
|
|
PRVALSEVEN(pktengrxducast); PRVALSEVEN(pktengrxdmcast); PRNL();
|
|
|
|
PRVALSEVEN(txmpdu_sgi); PRVALSEVEN(rxmpdu_sgi); PRVALSEVEN(txmpdu_stbc);
|
|
PRVALSEVEN(rxmpdu_stbc); PRNL();
|
|
|
|
} else {
|
|
if (cnt->version >= 4) {
|
|
/* per-rate receive counters */
|
|
PRVAL(rx1mbps); PRVAL(rx2mbps); PRVAL(rx5mbps5); PRNL();
|
|
PRVAL(rx6mbps); PRVAL(rx9mbps); PRVAL(rx11mbps); PRNL();
|
|
PRVAL(rx12mbps); PRVAL(rx18mbps); PRVAL(rx24mbps); PRNL();
|
|
PRVAL(rx36mbps); PRVAL(rx48mbps); PRVAL(rx54mbps); PRNL();
|
|
}
|
|
|
|
if (cnt->version >= 5) {
|
|
PRVAL(pktengrxducast); PRVAL(pktengrxdmcast); PRNL();
|
|
}
|
|
|
|
if (cnt->version >= 6) {
|
|
PRVAL(txmpdu_sgi); PRVAL(rxmpdu_sgi); PRVAL(txmpdu_stbc);
|
|
PRVAL(rxmpdu_stbc); PRNL();
|
|
}
|
|
|
|
if (cnt->version >= 8) {
|
|
PRVAL(reinit); PRNL();
|
|
if (cnt->length >= OFFSETOF(wl_cnt_t, cso_passthrough) + sizeof(uint32)) {
|
|
PRVAL(cso_normal);
|
|
PRVAL(cso_passthrough);
|
|
PRNL();
|
|
}
|
|
PRVAL(chained); PRVAL(chainedsz1); PRVAL(unchained); PRVAL(maxchainsz);
|
|
PRVAL(currchainsz); PRNL();
|
|
}
|
|
if (cnt->version >= 9) {
|
|
PRVAL(pciereset); PRVAL(cfgrestore); PRNL();
|
|
}
|
|
if (cnt->version >= 10) {
|
|
/* Display reinitreason counts */
|
|
pbuf += sprintf(pbuf, "reinitreason counts: ");
|
|
for (i = 0; i < NREINITREASONCOUNT; i++)
|
|
pbuf += sprintf(pbuf, "%2d(%d) ", i, cnt->reinitreason[i]);
|
|
pbuf += sprintf(pbuf, "\n");
|
|
}
|
|
}
|
|
|
|
pbuf += sprintf(pbuf, "\n");
|
|
fputs(buf, stdout);
|
|
exit:
|
|
if (cnt)
|
|
free(cnt);
|
|
|
|
if (cnt_six)
|
|
free(cnt_six);
|
|
|
|
if (cnt_seven)
|
|
free(cnt_seven);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
wl_delta_stats(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char *statsbuf;
|
|
wl_delta_stats_t *cnt;
|
|
int err;
|
|
char *pbuf = buf;
|
|
void *ptr;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
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 (-1);
|
|
}
|
|
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;
|
|
}
|
|
|
|
PRVAL(txframe); PRVAL(txbyte); PRVAL(txretrans); PRVAL(txfail); PRNL();
|
|
|
|
PRVAL(rxframe); PRVAL(rxbyte); PRNL();
|
|
|
|
PRVAL(rx1mbps); PRVAL(rx2mbps); PRVAL(rx5mbps5); PRVAL(rx6mbps); PRNL();
|
|
PRVAL(rx9mbps); PRVAL(rx11mbps); PRVAL(rx12mbps); PRVAL(rx18mbps); PRNL();
|
|
PRVAL(rx24mbps); PRVAL(rx36mbps); PRVAL(rx48mbps); PRVAL(rx54mbps); PRNL();
|
|
pbuf += sprintf(pbuf, "\n");
|
|
|
|
PRVAL(rxbadplcp); PRVAL(rxcrsglitch); PRVAL(bphy_rxcrsglitch); PRVAL(bphy_badplcp);
|
|
pbuf += sprintf(pbuf, "\n");
|
|
|
|
fputs(buf, stdout);
|
|
|
|
if (cnt != NULL)
|
|
free(cnt);
|
|
|
|
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 -1;
|
|
}
|
|
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);
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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
|
|
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;
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
|
|
static int
|
|
wl_event_bitvec(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));
|
|
}
|
|
/* 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 = -1;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
#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 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 ((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;
|
|
}
|
|
|
|
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_BADARG;
|
|
}
|
|
|
|
/* 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_BADARG;
|
|
}
|
|
|
|
tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
|
|
tspec_arg.version = (uint16)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.dialog_token = (uint8)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
user_tid = (uint8)strtol(*argv++, &endptr, 0);
|
|
user_tid <<= TID_SHIFT;
|
|
if (*endptr != '\0')
|
|
goto 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
|
|
goto 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
|
|
goto error;
|
|
|
|
user_prio = (uint8)strtol(*argv++, &endptr, 0);
|
|
user_prio <<= UP_SHIFT;
|
|
if (*endptr != '\0')
|
|
goto 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')
|
|
goto error;
|
|
|
|
fixed = (uint)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
if (fixed == 1)
|
|
tspec_arg.nom_msdu_size |= 0x8000;
|
|
|
|
tspec_arg.max_msdu_size = (uint16)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.min_srv_interval = strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.max_srv_interval = strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.inactivity_interval = strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.suspension_interval = strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.min_data_rate = strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.mean_data_rate = strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.peak_data_rate = strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.max_burst_size = strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.delay_bound = strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.surplus_bw = (uint16)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.min_phy_rate = strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto 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_BADARG;
|
|
}
|
|
|
|
tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
|
|
tspec_arg.version = (uint16)strtol(*argv++, &endptr, 0);
|
|
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.tsinfo.octets[0] = (uint8)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.tsinfo.octets[1] = (uint8)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.tsinfo.octets[2] = (uint8)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
}
|
|
|
|
wl_cac_format_tspec_htod(&tspec_arg);
|
|
err = wlu_var_setbuf(wl, cmd->name, &tspec_arg, buflen);
|
|
|
|
error:
|
|
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;
|
|
struct tslist *tslist;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
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;
|
|
}
|
|
|
|
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_BADARG;
|
|
}
|
|
|
|
memset((uint8 *)&tspec_arg, 0, sizeof(tspec_arg_t));
|
|
|
|
tspec_arg.tsinfo.octets[0] = (uint8)strtol(*argv++, &temp, 0);
|
|
if (*temp != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.tsinfo.octets[1] = (uint8)strtol(*argv++, &temp, 0);
|
|
if (*temp != '\0')
|
|
goto error;
|
|
|
|
tspec_arg.tsinfo.octets[2] = (uint8)strtol(*argv++, &temp, 0);
|
|
if (*temp != '\0')
|
|
goto 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;
|
|
error:
|
|
return err;
|
|
}
|
|
|
|
/* 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 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 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 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;
|
|
int ret = 0;
|
|
|
|
|
|
if (!*++argv) {
|
|
printf("MAC address must be specified\n");
|
|
ret = -1;
|
|
} else if (!wl_ether_atoe(*argv, &scb_val.ea)) {
|
|
printf("Malformed MAC address parameter\n");
|
|
ret = -1;
|
|
}
|
|
if ((ret != 0) || (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_BADARG;
|
|
}
|
|
|
|
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')
|
|
goto error;
|
|
|
|
ts->tsinfo.octets[1] = (uint8)strtol(*argv++, &temp, 0);
|
|
if (*temp != '\0')
|
|
goto error;
|
|
|
|
ts->tsinfo.octets[2] = (uint8)strtol(*argv++, &temp, 0);
|
|
if (*temp != '\0')
|
|
goto error;
|
|
|
|
/* add the ether address after tsinfo */
|
|
if (!*argv) {
|
|
printf("MAC address must be specified\n");
|
|
return -1;
|
|
} else if (!wl_ether_atoe(*argv, &tsea.ea)) {
|
|
printf("Malformed MAC address parameter\n");
|
|
return -1;
|
|
}
|
|
|
|
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;
|
|
|
|
error:
|
|
return err;
|
|
}
|
|
|
|
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_BADARG;
|
|
}
|
|
|
|
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')
|
|
goto error;
|
|
|
|
ts->tsinfo.octets[0] = (uint8)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
ts->tsinfo.octets[1] = (uint8)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
ts->tsinfo.octets[2] = (uint8)strtol(*argv++, &endptr, 0);
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
|
|
/* add the ether address after tsinfo */
|
|
if (!*argv) {
|
|
printf("MAC address must be specified\n");
|
|
return -1;
|
|
} else if (!wl_ether_atoe(*argv, &tsea.ea)) {
|
|
printf("Malformed MAC address parameter\n");
|
|
return -1;
|
|
}
|
|
|
|
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;
|
|
|
|
error:
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
}
|
|
err = wlu_iovar_set(wl, val_name, &val, sizeof(wlc_antselcfg_t));
|
|
}
|
|
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 -1;
|
|
|
|
if (val > 0)
|
|
return -1;
|
|
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
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_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 USAGE_ERROR;
|
|
|
|
fifo = atoi(param);
|
|
if (fifo > NFIFO)
|
|
return 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 WLPFN
|
|
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 -1;
|
|
}
|
|
} else if (!stricmp(*argv, "netimeout")) {
|
|
if (*++argv)
|
|
pfn_param.lost_network_timeout = atoi(*argv);
|
|
else {
|
|
fprintf(stderr, "Missing netimeout option\n");
|
|
return -1;
|
|
}
|
|
} else if (!stricmp(*argv, "rssi_delta")) {
|
|
if (*++argv)
|
|
pfn_param.rssi_margin = atoi(*argv);
|
|
else {
|
|
fprintf(stderr, "Missing rssi_delta option\n");
|
|
return -1;
|
|
}
|
|
} 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 -1;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Missing sort option\n");
|
|
return -1;
|
|
}
|
|
} 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 -1;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Missing immediateevent option\n");
|
|
return -1;
|
|
}
|
|
} 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 -1;
|
|
}
|
|
} 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 -1;
|
|
}
|
|
} 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 -1;
|
|
}
|
|
} 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 -1;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Missing adaptive scan option\n");
|
|
return -1;
|
|
}
|
|
} 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 -1;
|
|
}
|
|
} 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 -1;
|
|
}
|
|
} else if (!stricmp(*argv, "slowfrq")) {
|
|
if (*++argv)
|
|
pfn_param.slow_freq = atoi(*argv);
|
|
else {
|
|
fprintf(stderr, "Missing slowfrq option\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Invalid parameter %s\n", *argv);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
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 <= 'z')
|
|
return (hexchar - 'a' + 10);
|
|
else if (hexchar >= 'A' && hexchar <= 'Z')
|
|
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;
|
|
int32 hidden;
|
|
|
|
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 -1;
|
|
}
|
|
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");
|
|
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);
|
|
goto error;
|
|
}
|
|
pssidnet->ssid.SSID_len = htod32(pssidnet->ssid.SSID_len);
|
|
} else {
|
|
fprintf(stderr, "no value for ssid\n");
|
|
goto error;
|
|
}
|
|
}
|
|
else if (!stricmp(*argv, "hidden")) {
|
|
if (pssidnet->ssid.SSID_len == 0) {
|
|
fprintf(stderr, "Wrong! Start with SSID\n");
|
|
goto error;
|
|
}
|
|
if (*++argv) {
|
|
hidden = **argv - '0';
|
|
if (hidden != ENABLE && hidden != DISABLE) {
|
|
fprintf(stderr, "invalid hidden setting, use 0/1\n");
|
|
goto error;
|
|
}
|
|
pssidnet->flags |= hidden << WL_PFN_HIDDEN_BIT;
|
|
} else {
|
|
fprintf(stderr, "no value for hidden\n");
|
|
goto error;
|
|
}
|
|
} else if (!stricmp(*argv, "imode")) {
|
|
if (*++argv) {
|
|
if (pssidnet->ssid.SSID_len == 0) {
|
|
fprintf(stderr, "Wrong! Start with SSID\n");
|
|
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);
|
|
goto error;
|
|
}
|
|
pssidnet->infra = htod32(pssidnet->infra);
|
|
} else {
|
|
fprintf(stderr, "Missing option for imode\n");
|
|
goto error;
|
|
}
|
|
} else if (!stricmp(*argv, "amode")) {
|
|
if (*++argv) {
|
|
if (pssidnet->ssid.SSID_len == 0) {
|
|
fprintf(stderr, "Wrong! Start with SSID\n");
|
|
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);
|
|
goto error;
|
|
}
|
|
pssidnet->auth = htod32(pssidnet->auth);
|
|
} else {
|
|
fprintf(stderr, "Missing option for amode\n");
|
|
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");
|
|
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 = 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);
|
|
goto error;
|
|
}
|
|
pssidnet->wpa_auth = htod32(pssidnet->wpa_auth);
|
|
} else {
|
|
fprintf(stderr, "Missing option for wpa_auth\n");
|
|
goto error;
|
|
}
|
|
} else if (!stricmp(*argv, "wsec")) {
|
|
if (*++argv) {
|
|
if (pssidnet->ssid.SSID_len == 0) {
|
|
fprintf(stderr, "Wrong! Start with SSID\n");
|
|
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);
|
|
goto error;
|
|
}
|
|
pssidnet->wsec = htod32(pssidnet->wsec);
|
|
} else {
|
|
fprintf(stderr, "Missing option for wsec\n");
|
|
goto error;
|
|
}
|
|
} else if (!stricmp(*argv, "suppress")) {
|
|
if (*++argv) {
|
|
if (pssidnet->ssid.SSID_len == 0) {
|
|
fprintf(stderr, "Wrong! Start with SSID\n");
|
|
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);
|
|
goto error;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Missing option for suppress\n");
|
|
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");
|
|
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);
|
|
goto error;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Missing option for rssi\n");
|
|
goto error;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Invalid parameter %s\n", *argv);
|
|
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 -1;
|
|
}
|
|
|
|
#define MAXNUM_BSSID_PER_ADD 150
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
memset(bssidlist, '\0', bssidlistlen);
|
|
|
|
cnt = 0;
|
|
while (*++argv) {
|
|
if (!stricmp(*argv, "bssid")) {
|
|
if (*++argv) {
|
|
if (cnt >= MAXNUM_BSSID_PER_ADD) {
|
|
fprintf(stderr, "exceed max 150 BSSID per pfn_add_bssid\n");
|
|
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");
|
|
goto error;
|
|
}
|
|
pbssid->macaddr.octet[i] =
|
|
char2hex(*ptr) << 4 | char2hex(*(ptr+1));
|
|
ptr += 3;
|
|
}
|
|
cnt++;
|
|
} else {
|
|
fprintf(stderr, "Missing option for bssid\n");
|
|
goto error;
|
|
}
|
|
} else if (!stricmp(*argv, "suppress")) {
|
|
if (!pbssid || ETHER_ISNULLADDR(pbssid->macaddr.octet)) {
|
|
fprintf(stderr, "Wrong! Start with BSSID\n");
|
|
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);
|
|
goto error;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Missing option for suppress\n");
|
|
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");
|
|
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);
|
|
goto error;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Missing option for rssi\n");
|
|
goto error;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Invalid parameter %s\n", *argv);
|
|
goto error;
|
|
}
|
|
}
|
|
pbssid->flags = htod16(pbssid->flags);
|
|
|
|
bssidlistlen = cnt * sizeof(wl_pfn_bssid_t);
|
|
if ((err = wlu_iovar_set(wl, "pfn_add_bssid", bssidlist,
|
|
bssidlistlen))) {
|
|
fprintf(stderr, "pfn_add_bssid fail\n");
|
|
goto error;
|
|
}
|
|
free(bssidlist);
|
|
return 0;
|
|
|
|
error:
|
|
free(bssidlist);
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "no value for report\n");
|
|
return -1;
|
|
}
|
|
} 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 -1;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Missing option for channel\n");
|
|
return -1;
|
|
}
|
|
} 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 -1;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Invalid parameter %s\n", *argv);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
#define WL_PFN_BESTNET_LEN 1024
|
|
|
|
static int
|
|
wl_pfnbest(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
wl_pfn_scanresults_t *bestnet;
|
|
wl_pfn_net_info_t *netinfo;
|
|
uint32 i, j;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (*++argv) {
|
|
fprintf(stderr, "Invalid parameter %s\n", *argv);
|
|
return -1;
|
|
}
|
|
bestnet = (wl_pfn_scanresults_t *)malloc(WL_PFN_BESTNET_LEN);
|
|
if (bestnet == NULL) {
|
|
fprintf(stderr, "Failed to allocate buffer of %d bytes\n", WL_PFN_BESTNET_LEN);
|
|
return -1;
|
|
}
|
|
bzero(bestnet, WL_PFN_BESTNET_LEN);
|
|
while (bestnet->status != PFN_COMPLETE) {
|
|
if ((err = wlu_iovar_get(wl, "pfnbest", (void *)bestnet, WL_PFN_BESTNET_LEN))) {
|
|
fprintf(stderr, "pfnbest fail\n");
|
|
free(bestnet);
|
|
return err;
|
|
}
|
|
if (bestnet->count >
|
|
(WL_PFN_BESTNET_LEN / sizeof(wl_pfn_net_info_t)))
|
|
{
|
|
fprintf(stderr, "invalid data\n");
|
|
free(bestnet);
|
|
return -1;
|
|
}
|
|
|
|
printf("ver %d, status %d, count %d\n",
|
|
bestnet->version, bestnet->status, bestnet->count);
|
|
netinfo = bestnet->netinfo;
|
|
for (i = 0; i < bestnet->count; i++) {
|
|
for (j = 0; j < netinfo->pfnsubnet.SSID_len; j++)
|
|
printf("%c", netinfo->pfnsubnet.SSID[j]);
|
|
printf("\n");
|
|
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
netinfo->pfnsubnet.BSSID.octet[0],
|
|
netinfo->pfnsubnet.BSSID.octet[1],
|
|
netinfo->pfnsubnet.BSSID.octet[2],
|
|
netinfo->pfnsubnet.BSSID.octet[3],
|
|
netinfo->pfnsubnet.BSSID.octet[4],
|
|
netinfo->pfnsubnet.BSSID.octet[5]);
|
|
printf("channel: %d, RSSI: %d, timestamp: %d\n",
|
|
netinfo->pfnsubnet.channel, netinfo->RSSI, netinfo->timestamp);
|
|
netinfo++;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#if defined(linux)
|
|
static void
|
|
wl_pfn_printnet(wl_pfn_scanresults_t *ptr, int event_type)
|
|
{
|
|
wl_pfn_net_info_t *netinfo = ptr->netinfo;
|
|
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 {
|
|
return;
|
|
}
|
|
printf("ver %d, status %d, count %d\n",
|
|
ptr->version, ptr->status, ptr->count);
|
|
for (i = 0; i < ptr->count; i++) {
|
|
printf("%d. ", i + 1);
|
|
for (j = 0; j < netinfo->pfnsubnet.SSID_len; j++)
|
|
printf("%c", netinfo->pfnsubnet.SSID[j]);
|
|
printf("\n");
|
|
printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
netinfo->pfnsubnet.BSSID.octet[0],
|
|
netinfo->pfnsubnet.BSSID.octet[1],
|
|
netinfo->pfnsubnet.BSSID.octet[2],
|
|
netinfo->pfnsubnet.BSSID.octet[3],
|
|
netinfo->pfnsubnet.BSSID.octet[4],
|
|
netinfo->pfnsubnet.BSSID.octet[5]);
|
|
printf("channel %d, RSSI %d, timestamp %d\n",
|
|
netinfo->pfnsubnet.channel, netinfo->RSSI, netinfo->timestamp);
|
|
|
|
netinfo++;
|
|
}
|
|
}
|
|
|
|
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_t *ptr;
|
|
wl_pfn_net_info_t *info;
|
|
uint32 i, j;
|
|
uint32 foundcnt, lostcnt;
|
|
|
|
UNUSED_PARAMETER(wl);
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (*++argv)
|
|
strncpy(ifnames, *argv, IFNAMSIZ);
|
|
|
|
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 -1;
|
|
}
|
|
|
|
err = ioctl(fd, SIOCGIFINDEX, &ifr);
|
|
if (err < 0) {
|
|
printf("Cannot get index %d\n", err);
|
|
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 get index %d\n", err);
|
|
return -1;
|
|
}
|
|
|
|
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) {
|
|
ptr = (wl_pfn_scanresults_t *)(data + sizeof(bcm_event_t));
|
|
info = ptr->netinfo;
|
|
foundcnt = ptr->count & 0xffff;
|
|
lostcnt = ptr->count >> 16;
|
|
printf("ver %d, status %d, found %d, lost %d\n",
|
|
ptr->version, ptr->status, foundcnt, lostcnt);
|
|
if (foundcnt)
|
|
printf("Network found:\n");
|
|
for (i = 0; i < foundcnt; i++) {
|
|
printf("%d. ", i + 1);
|
|
for (j = 0; j < info->pfnsubnet.SSID_len; j++)
|
|
printf("%c", info->pfnsubnet.SSID[j]);
|
|
printf("\n");
|
|
printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
info->pfnsubnet.BSSID.octet[0],
|
|
info->pfnsubnet.BSSID.octet[1],
|
|
info->pfnsubnet.BSSID.octet[2],
|
|
info->pfnsubnet.BSSID.octet[3],
|
|
info->pfnsubnet.BSSID.octet[4],
|
|
info->pfnsubnet.BSSID.octet[5]);
|
|
printf("channel %d, RSSI %d, timestamp %d\n",
|
|
info->pfnsubnet.channel, info->RSSI, info->timestamp);
|
|
info++;
|
|
}
|
|
if (lostcnt)
|
|
printf("Network lost:\n");
|
|
for (i = 0; i < lostcnt; i++) {
|
|
printf("%d. ", i + 1);
|
|
for (j = 0; j < info->pfnsubnet.SSID_len; j++)
|
|
printf("%c", info->pfnsubnet.SSID[j]);
|
|
printf("\n");
|
|
printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
info->pfnsubnet.BSSID.octet[0],
|
|
info->pfnsubnet.BSSID.octet[1],
|
|
info->pfnsubnet.BSSID.octet[2],
|
|
info->pfnsubnet.BSSID.octet[3],
|
|
info->pfnsubnet.BSSID.octet[4],
|
|
info->pfnsubnet.BSSID.octet[5]);
|
|
printf("channel %d, RSSI %d, timestamp %d\n",
|
|
info->pfnsubnet.channel, info->RSSI, info->timestamp);
|
|
info++;
|
|
}
|
|
} else if ((WLC_E_PFN_NET_FOUND == event_type) ||
|
|
(WLC_E_PFN_NET_LOST == event_type)) {
|
|
wl_pfn_printnet(
|
|
(wl_pfn_scanresults_t *)(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");
|
|
}
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
#define ESCAN_EVENTS_BUFFER_SIZE 2048
|
|
|
|
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]; /* 128-bit mask */
|
|
|
|
wl_escan_result_t* escan_data;
|
|
|
|
|
|
UNUSED_PARAMETER(wl);
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (*++argv) {
|
|
strncpy(ifnames, *argv, (IFNAMSIZ - 1));
|
|
if (*++argv)
|
|
print_flag = atoi(*argv);
|
|
}
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
|
|
|
|
memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN);
|
|
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);
|
|
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);
|
|
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);
|
|
return -1;
|
|
}
|
|
|
|
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);
|
|
|
|
return (0);
|
|
}
|
|
|
|
struct escan_bss {
|
|
struct escan_bss *next;
|
|
wl_bss_info_t bss[1];
|
|
};
|
|
#define ESCAN_BSS_FIXED_SIZE 4
|
|
|
|
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;
|
|
struct sockaddr_ll sll;
|
|
struct ifreq ifr;
|
|
char ifnames[IFNAMSIZ] = {"eth1"};
|
|
bcm_event_t *event;
|
|
uint32 status;
|
|
char *data;
|
|
int event_type;
|
|
uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* 128-bit mask */
|
|
wl_escan_result_t *escan_data;
|
|
struct escan_bss *escan_bss_head = NULL;
|
|
struct escan_bss *escan_bss_tail = NULL;
|
|
struct escan_bss *result;
|
|
|
|
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 -1;
|
|
}
|
|
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));
|
|
if (wl)
|
|
strncpy(ifr.ifr_name, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
|
|
else
|
|
strncpy(ifr.ifr_name, ifnames, (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;
|
|
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)))
|
|
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 exit2;
|
|
}
|
|
|
|
/* 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 exit2;
|
|
}
|
|
|
|
params->version = htod32(ESCAN_REQ_VERSION);
|
|
params->action = htod16(WL_SCAN_ACTION_START);
|
|
|
|
#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);
|
|
|
|
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 = -1;
|
|
goto exit2;
|
|
}
|
|
|
|
/* receive scan result */
|
|
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 (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;
|
|
|
|
#define WLC_BSS_RSSI_ON_CHANNEL 0x0002 /* Copied from wlc.h. Is there a better way to do this? */
|
|
|
|
if (!wlu_bcmp(bi->SSID, bss->SSID, 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))
|
|
break;
|
|
}
|
|
|
|
if (!result) {
|
|
/* New BSS. Allocate memory and save it */
|
|
struct escan_bss *ebss = malloc(ESCAN_BSS_FIXED_SIZE
|
|
+ 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 {
|
|
/* We've got this BSS. Update rssi if necessary */
|
|
if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
|
|
(bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
|
|
/* preserve max RSSI if the measurements are
|
|
* both on-channel or both off-channel
|
|
*/
|
|
bss->RSSI = MAX(bss->RSSI, bi->RSSI);
|
|
} else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
|
|
(bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
|
|
/* preserve the on-channel rssi measurement
|
|
* if the new measurement is off channel
|
|
*/
|
|
bss->RSSI = bi->RSSI;
|
|
bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* print scan results */
|
|
for (result = escan_bss_head; result; result = result->next) {
|
|
dump_bss_info(result->bss);
|
|
}
|
|
|
|
exit1:
|
|
/* free scan results */
|
|
result = escan_bss_head;
|
|
while (result) {
|
|
struct escan_bss *tmp = result->next;
|
|
free(result);
|
|
result = tmp;
|
|
}
|
|
|
|
free(data);
|
|
close(fd);
|
|
exit2:
|
|
free(params);
|
|
|
|
/* Read the event mask from driver and mask the event WLC_E_ESCAN_RESULT */
|
|
if (!(err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
|
|
event_inds_mask[WLC_E_ESCAN_RESULT / 8] &= (~(1 << (WLC_E_ESCAN_RESULT % 8)));
|
|
err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
#endif /* linux */
|
|
|
|
static int
|
|
wl_event_filter(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* 128-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);
|
|
}
|
|
#endif /* WLPFN */
|
|
|
|
#ifdef WLP2PO
|
|
#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] || !argv[2]) {
|
|
params.period = 0;
|
|
params.interval = 0;
|
|
}
|
|
else {
|
|
params.period = atoi(argv[1]);
|
|
params.interval = atoi(argv[2]);
|
|
}
|
|
params_size = sizeof(wl_p2po_listen_t);
|
|
|
|
err = wlu_iovar_set(wl, "p2po_listen", ¶ms, params_size);
|
|
|
|
return err;
|
|
}
|
|
|
|
static 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_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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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;
|
|
wl_p2po_qr_t *params;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (!argv[1] || (*argv[1] != '0' && !argv[2])) {
|
|
fprintf(stderr, "Too few arguments\n");
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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;
|
|
wl_p2po_qr_t *params;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (!argv[1] || !argv[2]) {
|
|
fprintf(stderr, "Too few arguments\n");
|
|
return -1;
|
|
}
|
|
|
|
transaction_id = atoi(argv[1]);
|
|
if (transaction_id < 0 || transaction_id > 255) {
|
|
fprintf(stderr, "<transaction id> should be between 0 and 255\n");
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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)
|
|
{
|
|
uint32 val;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (*++argv) {
|
|
val = atoi(*argv);
|
|
return wlu_iovar_setint(wl, "p2po_listen_channel", val);
|
|
}
|
|
|
|
fprintf(stderr, "No channel is specified\n");
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
wl_p2po_stop(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
uint32 val;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (*++argv) {
|
|
val = atoi(*argv);
|
|
return wlu_iovar_setint(wl, "p2po_stop", val);
|
|
}
|
|
|
|
fprintf(stderr, "Please specify - 0:stop, 1:pause\n");
|
|
return -1;
|
|
}
|
|
|
|
#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 ifnames[IFNAMSIZ] = {"eth1"};
|
|
char *data;
|
|
uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* 128-bit mask */
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
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));
|
|
|
|
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 = -1;
|
|
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 */
|
|
#endif /* WLP2PO */
|
|
|
|
#ifdef WLANQPO
|
|
|
|
#define ANQPO_EVENTS_BUFFER_SIZE 2048
|
|
|
|
static int
|
|
wl_anqpo_set(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err = -1, 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 -1;
|
|
}
|
|
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");
|
|
goto done;
|
|
}
|
|
}
|
|
else if (!stricmp(*argv, "response_timeout")) {
|
|
if (*++argv)
|
|
set->response_timeout = atoi(*argv);
|
|
else {
|
|
fprintf(stderr, "Missing response timeout\n");
|
|
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");
|
|
goto done;
|
|
}
|
|
}
|
|
else if (!stricmp(*argv, "max_retries")) {
|
|
if (*++argv)
|
|
set->max_retries = atoi(*argv);
|
|
else {
|
|
fprintf(stderr, "Missing retries\n");
|
|
goto done;
|
|
}
|
|
}
|
|
else if (!stricmp(*argv, "query")) {
|
|
if (*++argv) {
|
|
if ((set->query_len = hexstr2hex(*argv)) == 0) {
|
|
fprintf(stderr, "Invalid ANQP query\n");
|
|
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);
|
|
goto done;
|
|
}
|
|
memcpy(set->query_data, *argv, set->query_len);
|
|
}
|
|
else {
|
|
fprintf(stderr, "Missing ANQP query\n");
|
|
goto done;
|
|
}
|
|
}
|
|
else {
|
|
fprintf(stderr, "Invalid parameter %s\n", *argv);
|
|
err = -1;
|
|
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 = -1, 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 -1;
|
|
}
|
|
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");
|
|
goto done;
|
|
}
|
|
if (!wl_ether_atoe(argv[c + 1], &peer->addr)) {
|
|
fprintf(stderr, "Invalid address\n");
|
|
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 = -1, 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 -1;
|
|
}
|
|
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");
|
|
goto done;
|
|
}
|
|
if (len > 32) {
|
|
fprintf(stderr, "SSID too long\n");
|
|
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");
|
|
goto done;
|
|
}
|
|
if (len > 32) {
|
|
fprintf(stderr, "SSID too long\n");
|
|
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 = -1;
|
|
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 = -1, 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 -1;
|
|
}
|
|
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");
|
|
goto done;
|
|
}
|
|
if (!wl_ether_atoe(*argv, &list->bssid[list->count])) {
|
|
fprintf(stderr, "Invalid BSSID\n");
|
|
goto done;
|
|
}
|
|
list->count++;
|
|
}
|
|
}
|
|
else if (!stricmp(*argv, "append")) {
|
|
while (*++argv) {
|
|
if (list->count > ANQPO_MAX_IGNORE_BSSID) {
|
|
fprintf(stderr, "Too many BSSID\n");
|
|
goto done;
|
|
}
|
|
if (!wl_ether_atoe(*argv, &list->bssid[list->count])) {
|
|
fprintf(stderr, "Invalid BSSID\n");
|
|
goto done;
|
|
}
|
|
list->count++;
|
|
}
|
|
}
|
|
else {
|
|
fprintf(stderr, "Invalid parameter %s\n", *argv);
|
|
err = -1;
|
|
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 ifnames[IFNAMSIZ] = {"eth1"};
|
|
char *data;
|
|
uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* 128-bit mask */
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
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));
|
|
|
|
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 = -1;
|
|
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 */
|
|
#endif /* WLANQPO */
|
|
|
|
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.
|
|
*/
|
|
static 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;
|
|
|
|
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;
|
|
}
|
|
|
|
#if defined(WLNDOE) || defined(WLOFFLD)
|
|
/*
|
|
* 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_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 -1;
|
|
|
|
/* we add one ip-addr at a time */
|
|
return wlu_var_setbuf(wl, cmd->name, &ipa_set, IPV6_ADDR_LEN);
|
|
}
|
|
return ret;
|
|
}
|
|
#endif /* defined(WLOFFLD) || defined(WLNDOE) */
|
|
|
|
#ifdef WLNDOE
|
|
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 -1;
|
|
|
|
/* 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 = 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;
|
|
}
|
|
#endif /* WLNDOE */
|
|
/*
|
|
* 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.
|
|
*/
|
|
static 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 -1;
|
|
/* we add one ip-addr at a time */
|
|
return wlu_var_setbuf(wl, cmd->name, &ipa_set, sizeof(IPV4_ADDR_LEN));
|
|
}
|
|
|
|
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.
|
|
*/
|
|
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;
|
|
}
|
|
|
|
#ifdef WLOFFLD
|
|
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;
|
|
}
|
|
#endif /* WLOFFLD */
|
|
|
|
static int
|
|
wl_mcast_ackmac(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret = 0;
|
|
struct ether_addr ea;
|
|
|
|
if (!*++argv) {
|
|
if ((ret = wlu_iovar_get(wl, cmd->name, &ea, ETHER_ADDR_LEN)) < 0)
|
|
return ret;
|
|
printf("%s\n", wl_ether_etoa(&ea));
|
|
} else {
|
|
if (!wl_ether_atoe(*argv, &ea))
|
|
return -1;
|
|
if ((ea.octet[0] == 1 && ea.octet[1] == 0 && ea.octet[2] == 0x5e &&
|
|
!(ea.octet[3] & 0x80)) || (ea.octet[0] == 0x33 && ea.octet[1] == 0x33))
|
|
{
|
|
ret = wlu_iovar_set(wl, cmd->name, &ea, ETHER_ADDR_LEN);
|
|
}
|
|
else {
|
|
fprintf(stderr, "multicast mac started with 01:00:5e:0... or 33:33:...\n");
|
|
ret = -1;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
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_RELMCAST_VER)
|
|
printf("Wrong Version %d %d\n", WL_RELMCAST_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_RELMCAST_FLAG_ACTIVEACKER) ?
|
|
'A' : ' '),
|
|
((status.clients[i].flag & WL_RELMCAST_FLAG_INBLACKLIST) ?
|
|
'B' : ' '),
|
|
((status.clients[i].flag & WL_RELMCAST_FLAG_RELMCAST) ?
|
|
'R' : ' '));
|
|
}
|
|
}
|
|
} else {
|
|
printf("Cannot set reliable multicast status\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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 -1;
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
static int
|
|
wl_pkteng_stats(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
wl_pkteng_stats_t *stats;
|
|
void *ptr = NULL;
|
|
int err;
|
|
uint16 *pktstats;
|
|
int i, j;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &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;
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
#if defined(BCMINTERNAL) || defined(WLTEST)
|
|
static int
|
|
wl_phy_sslpnphy_cga_2g(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
int8 offset[14];
|
|
char *endptr;
|
|
int8 cga[14];
|
|
uint8 i;
|
|
|
|
if (!*++argv) {
|
|
if ((err = wlu_iovar_get(wl, cmd->name, buf, 14 * sizeof(int8))) < 0)
|
|
return err;
|
|
printf("cga_2g : ");
|
|
for (i = 0; i <= 13; i++) {
|
|
cga[i] = ((int8*)buf)[i];
|
|
printf("%d ", cga[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; (i < 14) && (*argv != NULL); i++, argv++) {
|
|
offset[i] = (int8)strtol(*argv, &endptr, 0);
|
|
if ((endptr == *argv) || (*endptr != '\0'))
|
|
break;
|
|
}
|
|
|
|
if (((i < 14) && (*argv == NULL)) || ((i == 14) && (*argv != NULL))) {
|
|
fprintf(stderr, "Wrong number of args\n");
|
|
return -1;
|
|
}
|
|
|
|
|
|
if ((err = wlu_var_setbuf(wl, cmd->name, offset, 14*sizeof(int8))) < 0)
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
static int
|
|
wl_phy_sslpnphy_cga_5g(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
int8 offset[24];
|
|
char *endptr;
|
|
int8 cga[24];
|
|
uint8 i;
|
|
|
|
if (!*++argv) {
|
|
if ((err = wlu_iovar_get(wl, cmd->name, buf, 24 * sizeof(int8))) < 0)
|
|
return err;
|
|
printf("cga_5g : ");
|
|
for (i = 0; i <= 23; i++) {
|
|
cga[i] = ((int8*)buf)[i];
|
|
printf("%d ", cga[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; (i < 24) && (*argv != NULL); i++, argv++) {
|
|
offset[i] = (int8)strtol(*argv, &endptr, 0);
|
|
if ((endptr == *argv) || (*endptr != '\0'))
|
|
break;
|
|
}
|
|
|
|
if (((i < 24) && (*argv == NULL)) || ((i == 24) && (*argv != NULL))) {
|
|
fprintf(stderr, "Wrong number of args\n");
|
|
return -1;
|
|
}
|
|
|
|
|
|
if ((err = wlu_var_setbuf(wl, cmd->name, offset, 24*sizeof(int8))) < 0)
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
static int
|
|
wl_sslpnphy_tx_locc(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
int8 offset[6];
|
|
char *endptr;
|
|
int8 di0, dq0, ei0, eq0, fi0, fq0;
|
|
|
|
if (!*++argv) {
|
|
if ((err = wlu_iovar_get(wl, cmd->name, buf, 6 * sizeof(int8))) < 0)
|
|
return err;
|
|
|
|
di0 = ((int8*)buf)[0];
|
|
dq0 = ((int8*)buf)[1];
|
|
ei0 = ((int8*)buf)[2];
|
|
eq0 = ((int8*)buf)[3];
|
|
fi0 = ((int8*)buf)[4];
|
|
fq0 = ((int8*)buf)[5];
|
|
|
|
printf("lo cc : %d %d %d %d %d %d \n ", di0, dq0, ei0, eq0, fi0, fq0);
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
for (i = 0; (i < 6) && (*argv != NULL); i++, argv++) {
|
|
offset[i] = (int8)strtol(*argv, &endptr, 0);
|
|
if ((endptr == *argv) || (*endptr != '\0'))
|
|
break;
|
|
}
|
|
|
|
if (((i < 6) && (*argv == NULL)) || ((i == 6) && (*argv != NULL))) {
|
|
fprintf(stderr, "Wrong number of args\n");
|
|
return -1;
|
|
}
|
|
|
|
if (i < 6) {
|
|
fprintf(stderr, "Bad value for %s: <%s>\n",
|
|
((i == 0) ? "start" : "end"), *argv);
|
|
return -1;
|
|
}
|
|
|
|
if ((err = wlu_var_setbuf(wl, cmd->name, offset, 6*sizeof(int8))) < 0)
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
static int
|
|
wl_sslpnphy_tx_iqcc(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
int8 offset[2];
|
|
char *endptr;
|
|
int8 a, b;
|
|
|
|
if (!*++argv) {
|
|
if ((err = wlu_iovar_get(wl, cmd->name, buf, 2 * sizeof(int8))) < 0)
|
|
return err;
|
|
|
|
a = ((int8*)buf)[0];
|
|
b = ((int8*)buf)[1];
|
|
|
|
printf("iq cc : %d %d\n ", a, b);
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
for (i = 0; (i < 2) && (*argv != NULL); i++, argv++) {
|
|
offset[i] = (int8)strtol(*argv, &endptr, 0);
|
|
if ((endptr == *argv) || (*endptr != '\0'))
|
|
break;
|
|
}
|
|
|
|
if (((i < 2) && (*argv == NULL)) || ((i == 2) && (*argv != NULL))) {
|
|
fprintf(stderr, "Wrong number of args\n");
|
|
return -1;
|
|
}
|
|
|
|
if (i < 2) {
|
|
fprintf(stderr, "Bad value for %s: <%s>\n",
|
|
((i == 0) ? "start" : "end"), *argv);
|
|
return -1;
|
|
}
|
|
|
|
if ((err = wlu_var_setbuf(wl, cmd->name, offset, 2*sizeof(int8))) < 0)
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
static int
|
|
wl_phy_spbrange(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
uint16 offset[2];
|
|
char *endptr;
|
|
uint16 start, end;
|
|
|
|
if (!*++argv) {
|
|
if ((err = wlu_iovar_get(wl, cmd->name, buf, 2 * sizeof(uint16))) < 0)
|
|
return err;
|
|
|
|
start = ((uint16*)buf)[0];
|
|
end = ((uint16*)buf)[1];
|
|
|
|
printf("start=%d, end=%d \n", start, end);
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
for (i = 0; (i < 2) && (*argv != NULL); i++, argv++) {
|
|
offset[i] = (uint16)strtol(*argv, &endptr, 0);
|
|
if ((endptr == *argv) || (*endptr != '\0'))
|
|
break;
|
|
}
|
|
|
|
if (((i < 2) && (*argv == NULL)) || ((i == 2) && (*argv != NULL))) {
|
|
fprintf(stderr, "Wrong number of args\n");
|
|
return -1;
|
|
}
|
|
|
|
if (i < 2) {
|
|
fprintf(stderr, "Bad value for %s: <%s>\n",
|
|
((i == 0) ? "start" : "end"), *argv);
|
|
return -1;
|
|
}
|
|
|
|
if ((err = wlu_var_setbuf(wl, cmd->name, offset, 2*sizeof(uint16))) < 0)
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
static int
|
|
wl_sslpnphy_spbdump(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
wl_sslpnphy_spbdump_data_t *debug;
|
|
void *ptr = NULL;
|
|
int err;
|
|
uint i;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) {
|
|
printf("err\n");
|
|
return err;
|
|
}
|
|
debug = ptr;
|
|
for (i = 0; i < debug->tbl_length; i++)
|
|
printf("%4d %4d \n", debug->spbreal[i], debug->spbimg[i]);
|
|
|
|
return 0;
|
|
}
|
|
static int
|
|
wl_sslpnphy_debug(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
wl_sslpnphy_debug_data_t *debug;
|
|
void *ptr = NULL;
|
|
int err;
|
|
uint i;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) {
|
|
printf("err\n");
|
|
return err;
|
|
}
|
|
debug = ptr;
|
|
for (i = 0; i < 64; i++)
|
|
printf("%d \t %d \n", debug->papdcompRe[i], debug->papdcompIm[i]);
|
|
|
|
return 0;
|
|
}
|
|
static int
|
|
wl_sslpnphy_papd_debug(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
wl_sslpnphy_papd_debug_data_t *papd_debug;
|
|
void *ptr = NULL;
|
|
int err;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) {
|
|
printf("err\n");
|
|
return err;
|
|
}
|
|
papd_debug = ptr;
|
|
printf("psat_pwr =%d \n", papd_debug->psat_pwr);
|
|
printf("psat_indx =%d \n", papd_debug->psat_indx);
|
|
printf("min_phase =%d \n", papd_debug->min_phase);
|
|
printf("final_idx =%d \n", papd_debug->final_idx);
|
|
printf("start_idx =%d \n", papd_debug->start_idx);
|
|
printf("voltage =%d \n", papd_debug->voltage);
|
|
printf("temperature =%d \n", papd_debug->temperature);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
wl_sslpnphy_percal_debug(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
wl_sslpnphy_percal_debug_data_t *percal_debug;
|
|
void *ptr = NULL;
|
|
int err;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) {
|
|
printf("err\n");
|
|
return err;
|
|
}
|
|
percal_debug = ptr;
|
|
printf("cur_idx =%d \n", percal_debug->cur_idx);
|
|
printf("tx_drift =%d \n", percal_debug->tx_drift);
|
|
printf("prev_cal_idx =%d \n", percal_debug->prev_cal_idx);
|
|
printf("percal_ctr =%d \n", percal_debug->percal_ctr);
|
|
printf("nxt_cal_idx =%d \n", percal_debug->nxt_cal_idx);
|
|
printf("force_1idxcal =%d \n", percal_debug->force_1idxcal);
|
|
printf("1dxcal_req =%d \n", percal_debug->onedxacl_req);
|
|
printf("lastcal_volt =%d \n", percal_debug->last_cal_volt);
|
|
printf("last_cal_temp =%d \n", percal_debug->last_cal_temp);
|
|
printf("volt winner =%d \n", percal_debug->volt_winner);
|
|
printf("vbat ripple =%d \n", percal_debug->vbat_ripple);
|
|
printf("exit route =%d \n", percal_debug->exit_route);
|
|
return 0;
|
|
}
|
|
|
|
#endif /* BCMINTERNAL || WLTEST */
|
|
|
|
#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_phytable(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
int32 tableInfo[4];
|
|
char *endptr;
|
|
void *ptr = NULL;
|
|
int32 tableId, tableOffset, tableWidth, tableElement;
|
|
FILE *fp = NULL;
|
|
char line[32];
|
|
|
|
if (*++argv != NULL)
|
|
tableId = strtol(*argv, &endptr, 0);
|
|
else
|
|
return USAGE_ERROR;
|
|
|
|
if (*++argv != NULL)
|
|
tableOffset = strtol(*argv, &endptr, 0);
|
|
else
|
|
return USAGE_ERROR;
|
|
|
|
if (*++argv != NULL)
|
|
tableWidth = strtol(*argv, &endptr, 0);
|
|
else
|
|
return USAGE_ERROR;
|
|
|
|
if ((tableId < 0) || (tableOffset < 0))
|
|
return BCME_BADARG;
|
|
|
|
if ((tableWidth != 8) && (tableWidth != 16) && (tableWidth != 32))
|
|
return BCME_BADARG;
|
|
|
|
if (!*++argv) {
|
|
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 = ((int32*)ptr)[0];
|
|
|
|
printf("0x%x(%d)\n", tableElement, tableElement);
|
|
}
|
|
else
|
|
{
|
|
fp = fopen(*argv, "r");
|
|
|
|
while (((fp == NULL) && (*argv)) ||
|
|
((fp != NULL) && (fgets(line, 32*sizeof(char), fp) != NULL))) {
|
|
|
|
tableElement = (int32) strtoul((fp == NULL) ? *argv++ : line, &endptr, 0);
|
|
|
|
tableInfo[0] = tableId;
|
|
tableInfo[1] = tableOffset++;
|
|
tableInfo[2] = tableWidth;
|
|
tableInfo[3] = tableElement;
|
|
|
|
if ((err = wlu_var_setbuf(wl, cmd->name, tableInfo, 4*sizeof(int32))) < 0) {
|
|
if (fp != NULL)
|
|
fclose(fp);
|
|
return err;
|
|
}
|
|
}
|
|
|
|
if (fp != NULL)
|
|
fclose(fp);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
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 -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
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_BADARG;
|
|
}
|
|
} else if (phytype == WLC_PHY_TYPE_N) {
|
|
if (argc != 2) {
|
|
printf("NPHY must specify 2 core txpwrindex\n");
|
|
return BCME_BADARG;
|
|
}
|
|
}
|
|
|
|
ret = wlu_iovar_setbuf(wl, cmd->name, txpwridx, 4*sizeof(uint32),
|
|
buf, WLC_IOCTL_MAXLEN);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
static int
|
|
wl_phy_pavars(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
#if defined(_CFE_)
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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[16];
|
|
void *ptr = NULL;
|
|
int paparambwver = 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);
|
|
}
|
|
|
|
if (paparambwver == 1)
|
|
pav = pavars_bwver_1;
|
|
else if (paparambwver == 2)
|
|
pav = pavars_bwver_2;
|
|
else
|
|
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) {
|
|
int pnum = 0, n;
|
|
|
|
if (pav->bandrange == WL_CHAN_FREQ_RANGE_2G)
|
|
pnum = 3;
|
|
else if (pav->bandrange == WL_CHAN_FREQ_RANGE_5G_4BAND)
|
|
pnum = 12;
|
|
|
|
/* 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;
|
|
|
|
/* 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)));
|
|
}
|
|
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) {
|
|
int pnum = 0, n;
|
|
|
|
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)));
|
|
}
|
|
pav++;
|
|
free(par);
|
|
}
|
|
}
|
|
|
|
return err;
|
|
#endif /* _CFE_ */
|
|
}
|
|
|
|
static int
|
|
wl_phy_povars(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
#if defined(_CFE_)
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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;
|
|
|
|
/* 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)));
|
|
|
|
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 /* _CFE_ */
|
|
}
|
|
|
|
static int
|
|
wl_phy_rpcalvars(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
#if defined(_CFE_)
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
return 0;
|
|
#else
|
|
int err = 0, k;
|
|
unsigned int val;
|
|
wl_rpcal_t rpcal[WL_NUM_RPCALVARS], *rpcal_out;
|
|
void *ptr = NULL;
|
|
|
|
if (*++argv) { /* set */
|
|
bool found = FALSE;
|
|
|
|
/* initialization */
|
|
memset(&(rpcal[0]), 0, sizeof(wl_rpcal_t)*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 (found) {
|
|
err = wlu_var_setbuf(wl, cmd->name, &(rpcal[0]),
|
|
sizeof(wl_rpcal_t)*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)*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 < 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
#endif /* _CFE_ */
|
|
}
|
|
|
|
static int
|
|
wl_phy_fem(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
#if defined(_CFE_)
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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 /* _CFE_ */
|
|
}
|
|
|
|
static int
|
|
wl_phy_maxpower(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
#if defined(_CFE_)
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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");
|
|
err = -1;
|
|
}
|
|
} else {
|
|
if ((err = wlu_var_getbuf(wl, "maxpower", NULL, 0, &ptr) < 0)) {
|
|
printf("wl_phy_maxpower: fail to get maxpower\n");
|
|
err = -1;
|
|
}
|
|
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 /* _CFE_ */
|
|
}
|
|
|
|
static int
|
|
wl_antgain(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
#if defined(_CFE_)
|
|
return CFE_ERR_UNSUPPORTED;
|
|
#elif defined(_HNDRTE_) || defined(__IOPOS__)
|
|
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 0;
|
|
}
|
|
|
|
if (find_pattern(argv, "ag1", &val))
|
|
ag[1] = val & 0xff;
|
|
else {
|
|
printf("Missing ag1\n");
|
|
return 0;
|
|
}
|
|
|
|
if ((err = wlu_var_setbuf(wl, "antgain", &ag, 2 * sizeof(uint8)) < 0)) {
|
|
printf("wl_antgain: fail to set\n");
|
|
err = -1;
|
|
}
|
|
} else {
|
|
if ((err = wlu_var_getbuf(wl, "antgain", NULL, 0, &ptr) < 0)) {
|
|
printf("wl_antgain: fail to get antgain\n");
|
|
err = -1;
|
|
}
|
|
rag = (uint8*)ptr;
|
|
printf("ag0=%x\n", rag[0]);
|
|
printf("ag1=%x\n", rag[1]);
|
|
}
|
|
|
|
return err;
|
|
#endif /* _CFE_ */
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
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 -1;
|
|
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 -1;
|
|
}
|
|
else if (strcmp(cmd->name, "pkteng_start") == 0) {
|
|
if (!*++argv)
|
|
return -1;
|
|
if (!wl_ether_atoe(*argv, (struct ether_addr *)&pkteng.dest))
|
|
return -1;
|
|
if (!*++argv)
|
|
return -1;
|
|
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 -1;
|
|
if (strcmp(*argv, "async") == 0)
|
|
pkteng.flags &= ~WL_PKTENG_SYNCHRONOUS;
|
|
else if (strcmp(*argv, "sync") == 0)
|
|
pkteng.flags |= WL_PKTENG_SYNCHRONOUS;
|
|
else
|
|
/* neither optional parameter [async|sync] */
|
|
--argv;
|
|
if (!*++argv)
|
|
return -1;
|
|
pkteng.delay = strtoul(*argv, NULL, 0);
|
|
if (!*++argv)
|
|
return -1;
|
|
pkteng.length = strtoul(*argv, NULL, 0);
|
|
if (!*++argv)
|
|
return -1;
|
|
pkteng.nframes = strtoul(*argv, NULL, 0);
|
|
if (*++argv)
|
|
if (!wl_ether_atoe(*argv, (struct ether_addr *)&pkteng.src))
|
|
return -1;
|
|
}
|
|
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 -1;
|
|
pkteng.nframes = strtoul(*argv, NULL, 0);
|
|
if (!*++argv)
|
|
return -1;
|
|
pkteng.delay = strtoul(*argv, NULL, 0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
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)));
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
static int
|
|
wl_rxiq(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
miniopt_t to;
|
|
const char* fn_name = "wl_rxiqest";
|
|
int err, argc, opt_err;
|
|
uint32 rxiq;
|
|
uint8 resolution = 0;
|
|
uint8 lpf_hpc = 1;
|
|
uint8 dig_lpf = 1;
|
|
uint8 gain_correct = 0;
|
|
uint8 extra_gain_3dBsteps = 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
|
|
*/
|
|
/* XXX Currently the lpf_hpc override option applies only for HTPHY */
|
|
rxiq = (extra_gain_3dBsteps << 28) | (gain_correct << 24) | (dig_lpf << 22)
|
|
| (lpf_hpc << 20) | (resolution << 16) | (10 << 8) | 3;
|
|
|
|
if (argc != 0) {
|
|
miniopt_init(&to, fn_name, NULL, FALSE);
|
|
while ((opt_err = miniopt(&to, argv)) != -1) {
|
|
if (opt_err == 1) {
|
|
err = -1;
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
gain_correct = to.val & 0xf;
|
|
rxiq = ((gain_correct << 24) | (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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
lpf_hpc = to.val & 0xf;
|
|
rxiq = ((lpf_hpc << 20) | (rxiq & 0xff0fffff));
|
|
}
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
dig_lpf = to.val & 0x3;
|
|
rxiq = ((dig_lpf << 22) | (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 = -1;
|
|
goto exit;
|
|
}
|
|
if ((to.val < 0) || (to.val > 1)) {
|
|
fprintf(stderr, "%s: invalid resolution select %d"
|
|
" (0,1)\n", fn_name, to.val);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
resolution = to.val & 0xf;
|
|
rxiq = ((resolution << 16) | (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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
rxiq = (((to.val & 0xff) << 8) | (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 = -1;
|
|
goto exit;
|
|
}
|
|
if ((to.val < 0) || (to.val > 3)) {
|
|
fprintf(stderr, "%s: invalid antenna select %d\n",
|
|
fn_name, to.val);
|
|
err = -1;
|
|
goto exit;
|
|
}
|
|
rxiq = ((rxiq & 0xffffff00) | (to.val & 0xff));
|
|
}
|
|
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 = -1;
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
rxiq = ((((to.val/3) & 0xf) << 28) | (rxiq & 0x0fffffff));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((err = wlu_iovar_setint(wl, cmd->name, (int)rxiq)) < 0)
|
|
return err;
|
|
if ((err = wlu_iovar_getint(wl, cmd->name, (int*)&rxiq)) < 0)
|
|
return err;
|
|
|
|
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 >> 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));
|
|
}
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
/* Convert user's input in hex pattern to byte-size mask */
|
|
static 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;
|
|
}
|
|
|
|
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 -1;
|
|
err = wlu_iovar_set(wl, "wowl_wakeind", *argv, strlen(*argv));
|
|
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");
|
|
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_SCANOL) == WL_WOWL_SCANOL)
|
|
printf("\tWake on Scan offload.\n");
|
|
if ((wake.ucode_wakeind & WL_WOWL_MDNS_CONFLICT) == WL_WOWL_MDNS_CONFLICT)
|
|
printf("\tWake on MDNS Conflict.\n");
|
|
if ((wake.ucode_wakeind & WL_WOWL_MDNS_SERVICE) == WL_WOWL_MDNS_SERVICE)
|
|
printf("\tWake on MDNS Service.\n");
|
|
if ((wake.ucode_wakeind & WL_WOWL_TCPKEEP) == WL_WOWL_TCPKEEP)
|
|
printf("\tWake on TCP data or timeout.\n");
|
|
if ((wake.ucode_wakeind & WL_WOWL_FW_HALT) == WL_WOWL_FW_HALT)
|
|
printf("\tWake on Firmware died in wowl mode.\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 -1;
|
|
|
|
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 -1;
|
|
}
|
|
|
|
/* 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 -1;
|
|
} else if (!strcmp(*argv, "ucast")) {
|
|
dst_ea = 2;
|
|
if (!*++argv) {
|
|
printf("EA of ucast dest of the packet needs to be provided\n");
|
|
return -1;
|
|
}
|
|
if (!wl_ether_atoe(*argv, (struct ether_addr *)dst))
|
|
return -1;
|
|
/* Store it */
|
|
memcpy(ea, dst, ETHER_ADDR_LEN);
|
|
} else if (!wl_ether_atoe(*argv, (struct ether_addr *)dst))
|
|
return -1;
|
|
|
|
dst += ETHER_ADDR_LEN;
|
|
tot += ETHER_ADDR_LEN;
|
|
|
|
if (!*++argv) {
|
|
printf("type - magic/net needs to be provided\n");
|
|
return -1;
|
|
}
|
|
|
|
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 -1;
|
|
|
|
*((uint16*)dst) = type;
|
|
dst += sizeof(type);
|
|
tot += sizeof(type);
|
|
|
|
if (type == WL_WOWL_MAGIC) {
|
|
if (pkt_len < MAGIC_PKT_MINLEN)
|
|
return -1;
|
|
|
|
if (dst_ea == 2)
|
|
memcpy(dst, ea, ETHER_ADDR_LEN);
|
|
else {
|
|
if (!*++argv)
|
|
return -1;
|
|
|
|
if (!wl_ether_atoe(*argv, (struct ether_addr *)dst))
|
|
return -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
*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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
wl_pattern->offset = htod32(strtoul(*argv, NULL, 0));
|
|
if (!*++argv) {
|
|
printf("Mask not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Parse the mask */
|
|
str = *argv;
|
|
wl_pattern->masksize = htod32(wl_pattern_atoh((char *)(uintptr)str, dst));
|
|
if (wl_pattern->masksize == (uint)-1)
|
|
return -1;
|
|
|
|
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 -1;
|
|
}
|
|
|
|
/* Parse the value */
|
|
str = *argv;
|
|
wl_pattern->patternsize =
|
|
htod32(wl_pattern_atoh((char *)(uintptr)str, dst));
|
|
if (wl_pattern->patternsize == (uint)-1)
|
|
return -1;
|
|
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;
|
|
}
|
|
|
|
#if defined(BCMINTERNAL) || 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);
|
|
|
|
/* XXX
|
|
printf("\n--------------------------------------------------------\n");
|
|
printf("PHY COMMAND (%s) with input argument : %d", val_name, val);
|
|
printf("\n--------------------------------------------------------\n");
|
|
printf("\n");
|
|
*/
|
|
|
|
if ((err = wlu_iovar_setint(wl, val_name, (int)val)) < 0)
|
|
printf("PHY DEBUG COMMAND error %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
#endif /* defined(BCMINTERNAL) || defined(BCMDBG) */
|
|
|
|
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 -1;
|
|
if (ret != 6) {
|
|
printf("Extended magic pattern must be 6-byte length\n");
|
|
return -1;
|
|
}
|
|
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;
|
|
|
|
}
|
|
|
|
#ifdef BCMINTERNAL
|
|
static int
|
|
wl_send_wpa_m1(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char *arg = buf;
|
|
const char *str;
|
|
char *dst;
|
|
uint tot;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (!*++argv)
|
|
return -1;
|
|
|
|
if (strncmp(*argv, "ptk", strlen("ptk")) == 0)
|
|
str = "auth_ptk_m1";
|
|
else if (strncmp(*argv, "gtk_bad", strlen("gtk_bad")) == 0)
|
|
str = "auth_gtk_bad_m1";
|
|
else if (strncmp(*argv, "gtk", strlen("gtk")) == 0)
|
|
str = "auth_gtk_m1";
|
|
else {
|
|
printf("Unknown option\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!*++argv) {
|
|
printf("Mac address missing\n");
|
|
return -1;
|
|
}
|
|
|
|
strncpy(arg, str, strlen(str));
|
|
arg[strlen(str)] = '\0';
|
|
dst = arg + strlen(str) + 1;
|
|
tot = strlen(str) + 1;
|
|
if (!wl_ether_atoe(*argv, (struct ether_addr*)dst))
|
|
return -1;
|
|
tot += ETHER_ADDR_LEN;
|
|
|
|
return (wlu_set(wl, WLC_SET_VAR, arg, tot));
|
|
}
|
|
#endif /* BCMINTERNAL */
|
|
|
|
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 (rifs != 0 && rifs != 1)
|
|
return USAGE_ERROR;
|
|
|
|
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 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;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
/* 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;
|
|
}
|
|
|
|
#ifndef ATE_BUILD
|
|
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 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 IOCTL_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 0;
|
|
}
|
|
|
|
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);
|
|
bufp = ALIGN_ADDR(bufp, WL_SEQ_CMD_ALIGN_BYTES);
|
|
seq_list_len = bufp - buf;
|
|
|
|
while ((seq_list_len < MEMBLOCK) && (next_cmd != NULL)) {
|
|
len = ROUNDUP(next_cmd->cmd_header.len, WL_SEQ_CMD_ALIGN_BYTES);
|
|
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;
|
|
bufp = ALIGN_ADDR(bufp, WL_SEQ_CMD_ALIGN_BYTES);
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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;
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
/* 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. */
|
|
static 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;
|
|
|
|
memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t));
|
|
|
|
str = *argv; /* mkeep_alive or wowl_keepalive */
|
|
if (*++argv == NULL) {
|
|
return -1;
|
|
}
|
|
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);
|
|
mkeep_alive_pkt.period_msec = htod32(strtoul(*argv, NULL, 0));
|
|
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);
|
|
}
|
|
|
|
|
|
/* 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 (-1);
|
|
}
|
|
|
|
/* Parse packet filter id. */
|
|
enable_parm.id = htod32(strtoul(*argv, NULL, 0));
|
|
|
|
if (*++argv == NULL) {
|
|
printf("Enable/disable value not provided\n");
|
|
return (-1);
|
|
}
|
|
|
|
/* 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;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
if (*++argv == NULL) {
|
|
printf("No args provided\n");
|
|
return (-1);
|
|
}
|
|
|
|
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);
|
|
|
|
/* Parse packet filter id. */
|
|
pkt_filter.id = htod32(strtoul(*argv, NULL, 0));
|
|
|
|
if (*++argv == NULL) {
|
|
printf("Polarity not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Parse filter polarity. */
|
|
pkt_filter.negate_match = htod32(strtoul(*argv, NULL, 0));
|
|
|
|
if (*++argv == NULL) {
|
|
printf("Filter type not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Parse filter type. */
|
|
pkt_filter.type = htod32(strtoul(*argv, NULL, 0));
|
|
|
|
if (*++argv == NULL) {
|
|
printf("Offset not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Parse pattern filter offset. */
|
|
pkt_filter.u.pattern.offset = htod32(strtoul(*argv, NULL, 0));
|
|
|
|
if (*++argv == NULL) {
|
|
printf("Bitmask not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Parse pattern filter mask. */
|
|
rc = wl_pattern_atoh(*argv, (char *) pkt_filterp->u.pattern.mask_and_pattern);
|
|
if (rc <= 0) {
|
|
printf("Invalid mask provided\n");
|
|
return -1;
|
|
}
|
|
mask_size = htod32(rc);
|
|
|
|
if (*++argv == NULL) {
|
|
printf("Pattern not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Parse pattern filter pattern. */
|
|
rc = wl_pattern_atoh(*argv, (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]);
|
|
if (rc <= 0) {
|
|
printf("Invalid pattern provided\n");
|
|
return -1;
|
|
}
|
|
pattern_size = htod32(rc);
|
|
|
|
if (mask_size != pattern_size) {
|
|
printf("Mask and pattern not the same size\n");
|
|
return -1;
|
|
}
|
|
|
|
|
|
pkt_filter.u.pattern.size_bytes = mask_size;
|
|
buf_len += WL_PKT_FILTER_FIXED_LEN;
|
|
buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
|
|
|
|
/* 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 *)pkt_filterp,
|
|
&pkt_filter,
|
|
WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
|
|
|
|
|
|
rc = wlu_set(wl,
|
|
WLC_SET_VAR,
|
|
buf,
|
|
buf_len);
|
|
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
/* 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 (-1);
|
|
}
|
|
|
|
/* 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++)
|
|
{
|
|
printf("Id :%d\n"
|
|
"Negate :%d\n"
|
|
"Type :%d\n"
|
|
"Offset :%d\n"
|
|
"Pattern len :%d\n"
|
|
"Mask :0x",
|
|
dtoh32(filterp->id),
|
|
dtoh32(filterp->negate_match),
|
|
dtoh32(filterp->type),
|
|
dtoh32(filterp->u.pattern.offset),
|
|
dtoh32(filterp->u.pattern.size_bytes));
|
|
|
|
|
|
for (j = 0; j < filterp->u.pattern.size_bytes; j++)
|
|
printf("%02x", filterp->u.pattern.mask_and_pattern[j]);
|
|
|
|
printf("\nPattern :0x");
|
|
|
|
for (; j < 2 * filterp->u.pattern.size_bytes; j++)
|
|
printf("%02x", filterp->u.pattern.mask_and_pattern[j]);
|
|
|
|
printf("\n\n");
|
|
|
|
|
|
filter_len = WL_PKT_FILTER_FIXED_LEN;
|
|
filter_len += WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * filterp->u.pattern.size_bytes;
|
|
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 (-1);
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
static int
|
|
ARGCNT(char **argv)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; argv[i] != NULL; i ++)
|
|
;
|
|
return i;
|
|
}
|
|
|
|
#ifdef WLAWDL
|
|
/* Send a periodic bcast/mcast action frame at the specificed intervalm at low power */
|
|
static int
|
|
wl_awdl_sync_params(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *str;
|
|
awdl_sync_params_t awdl_config;
|
|
awdl_sync_params_t *pawdl_config;
|
|
int buf_len;
|
|
int str_len;
|
|
int rc;
|
|
void *ptr = NULL;
|
|
|
|
if (*++argv == NULL) {
|
|
/*
|
|
** Get current AWDL params.
|
|
*/
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
|
|
pawdl_config = (awdl_sync_params_t *) ptr;
|
|
|
|
printf("AFPeriod(msec):%d\n"
|
|
"AW Period :%d\n"
|
|
"AW Cmn time :%d\n"
|
|
"Guard timr :%d\n"
|
|
"Ext period :%d\n"
|
|
"AWDL Flags :%#04x\n"
|
|
"Master chan :%d\n",
|
|
dtoh16(pawdl_config->action_frame_period),
|
|
dtoh16(pawdl_config->aw_period),
|
|
dtoh16(pawdl_config->aw_cmn_length),
|
|
pawdl_config->guard_time,
|
|
dtoh16(pawdl_config->aw_ext_length),
|
|
dtoh16(pawdl_config->awdl_flags),
|
|
pawdl_config->master_chan);
|
|
printf("\n");
|
|
}
|
|
else {
|
|
/*
|
|
** Set the attributes.
|
|
*/
|
|
|
|
str = "awdl_sync_params";
|
|
str_len = strlen(str);
|
|
strncpy(buf, str, str_len);
|
|
buf[ str_len ] = '\0';
|
|
|
|
pawdl_config = (awdl_sync_params_t *) (buf + str_len + 1);
|
|
awdl_config.action_frame_period = htod16(strtoul(*argv, NULL, 0));
|
|
awdl_config.aw_period = htod16(strtoul(*(argv + 1), NULL, 0));
|
|
awdl_config.aw_cmn_length = htod16(strtoul(*(argv + 2), NULL, 0));
|
|
awdl_config.guard_time = htod16(strtoul(*(argv + 3), NULL, 0));
|
|
awdl_config.aw_ext_length = htod16(strtoul(*(argv + 4), NULL, 0));
|
|
awdl_config.master_chan = strtoul(*(argv + 5), NULL, 0);
|
|
buf_len = str_len + 1 + sizeof(awdl_sync_params_t);
|
|
|
|
memcpy((char *)pawdl_config, &awdl_config,
|
|
sizeof(awdl_sync_params_t));
|
|
|
|
rc = wlu_set(wl,
|
|
WLC_SET_VAR,
|
|
buf,
|
|
buf_len);
|
|
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_af_hdr(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *str;
|
|
int buf_len;
|
|
int str_len;
|
|
int i;
|
|
int rc;
|
|
void *ptr = NULL;
|
|
awdl_af_hdr_t *paf_hdr;
|
|
|
|
if (*++argv == NULL) {
|
|
/*
|
|
** Get current AWDL action frame.
|
|
*/
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
paf_hdr = (awdl_af_hdr_t *) ptr;
|
|
|
|
printf("Dst Addr :%02x:%02x:%02x:%02x:%02x:%02x \n",
|
|
paf_hdr->dst_mac.octet[0],
|
|
paf_hdr->dst_mac.octet[1],
|
|
paf_hdr->dst_mac.octet[2],
|
|
paf_hdr->dst_mac.octet[3],
|
|
paf_hdr->dst_mac.octet[4],
|
|
paf_hdr->dst_mac.octet[5]);
|
|
|
|
printf("Category and OUI[3] :0x");
|
|
for (i = 0; i < 4; i++)
|
|
printf("%02x", paf_hdr->action_hdr[i]);
|
|
|
|
printf("\n");
|
|
}
|
|
else {
|
|
/*
|
|
** Set the attributes.
|
|
*/
|
|
|
|
str = "awdl_af_hdr";
|
|
str_len = strlen(str);
|
|
strncpy(buf, str, str_len);
|
|
buf[ str_len ] = '\0';
|
|
|
|
paf_hdr = (awdl_af_hdr_t *) (buf + str_len + 1);
|
|
if (*argv)
|
|
if (!wl_ether_atoe(*argv, (struct ether_addr *)&paf_hdr->dst_mac)) {
|
|
printf("Problem parsing MAC address \"%s\".\n", *argv);
|
|
return -1;
|
|
}
|
|
argv++;
|
|
buf_len = str_len + 1 + sizeof(awdl_sync_params_t);
|
|
htod16(wl_pattern_atoh(*argv, (char *) paf_hdr->action_hdr));
|
|
|
|
rc = wlu_set(wl,
|
|
WLC_SET_VAR,
|
|
buf,
|
|
buf_len);
|
|
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_ext_counts(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *str;
|
|
int buf_len;
|
|
int str_len;
|
|
int rc;
|
|
void *ptr = NULL;
|
|
awdl_extcount_t extcnt, *pextcnt;
|
|
|
|
if (*++argv == NULL) {
|
|
/*
|
|
** Get current AWDL action frame.
|
|
*/
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
pextcnt = (awdl_extcount_t *) ptr;
|
|
|
|
memcpy(&extcnt, (char *)pextcnt, sizeof(extcnt));
|
|
printf("MinExt:\t%d\nMaxExtMulti:\t%d\nMaxExtUni:\t%d\nMaxAfExt:\t%d\n",
|
|
extcnt.minExt, extcnt.maxExtMulti, extcnt.maxExtUni, extcnt.maxAfExt);
|
|
}
|
|
else {
|
|
/*
|
|
** Set the attributes.
|
|
*/
|
|
|
|
str = "awdl_ext_counts";
|
|
str_len = strlen(str);
|
|
strncpy(buf, str, str_len);
|
|
buf[ str_len ] = '\0';
|
|
|
|
pextcnt = (awdl_extcount_t *) (buf + str_len + 1);
|
|
extcnt.minExt = strtoul(*argv++, NULL, 0);
|
|
if (*argv)
|
|
extcnt.maxExtMulti = strtoul(*argv++, NULL, 0);
|
|
else
|
|
return BCME_BADARG;
|
|
if (*argv)
|
|
extcnt.maxExtUni = strtoul(*argv++, NULL, 0);
|
|
else
|
|
return BCME_BADARG;
|
|
if (*argv)
|
|
extcnt.maxAfExt = strtoul(*argv++, NULL, 0);
|
|
else
|
|
return BCME_BADARG;
|
|
memcpy((char *)pextcnt, &extcnt, sizeof(extcnt));
|
|
|
|
buf_len = str_len + 1 + sizeof(awdl_extcount_t);
|
|
|
|
rc = wlu_set(wl,
|
|
WLC_SET_VAR,
|
|
buf,
|
|
buf_len);
|
|
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_opmode(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *str;
|
|
int buf_len;
|
|
int str_len;
|
|
int rc;
|
|
void *ptr = NULL;
|
|
awdl_opmode_t opmode, *popmode;
|
|
|
|
if (*++argv == NULL) {
|
|
/*
|
|
** Get current AWDL action frame.
|
|
*/
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
popmode = (awdl_opmode_t *) ptr;
|
|
|
|
memcpy(&opmode, (char *)popmode, sizeof(opmode));
|
|
printf("Mode:\t%d\nRole:\t%d\n",
|
|
opmode.mode, opmode.role);
|
|
printf(" Non-Election Bcasting Period: %d\n Current Bcasting Period: %d\n",
|
|
opmode.bcast_tu, opmode.cur_bcast_tu);
|
|
printf("Master Addr :%02x:%02x:%02x:%02x:%02x:%02x \n",
|
|
opmode.master.octet[0], opmode.master.octet[1],
|
|
opmode.master.octet[2], opmode.master.octet[3],
|
|
opmode.master.octet[4], opmode.master.octet[5]);
|
|
}
|
|
else {
|
|
/*
|
|
** Set the attributes.
|
|
*/
|
|
|
|
str = "awdl_opmode";
|
|
str_len = strlen(str);
|
|
strncpy(buf, str, str_len);
|
|
buf[ str_len ] = '\0';
|
|
|
|
popmode = (awdl_opmode_t *) (buf + str_len + 1);
|
|
opmode.mode = strtoul(*argv++, NULL, 0);
|
|
if (*argv) {
|
|
opmode.role = strtoul(*argv++, NULL, 0);
|
|
if (*argv)
|
|
opmode.bcast_tu = strtoul(*argv++, NULL, 0);
|
|
else
|
|
opmode.bcast_tu = 1000; /* default */
|
|
}
|
|
if (*argv)
|
|
if (!wl_ether_atoe(*argv, &opmode.master)) {
|
|
printf("Problem parsing MAC address \"%s\".\n", *(argv + 3));
|
|
return -1;
|
|
}
|
|
memcpy((char *)popmode, &opmode, sizeof(opmode));
|
|
|
|
buf_len = str_len + 1 + sizeof(awdl_opmode_t);
|
|
|
|
rc = wlu_set(wl,
|
|
WLC_SET_VAR,
|
|
buf,
|
|
buf_len);
|
|
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_election(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *str;
|
|
awdl_election_info_t *pawdl_config;
|
|
int buf_len;
|
|
int str_len;
|
|
int rc;
|
|
void *ptr = NULL;
|
|
|
|
if (*++argv == NULL) {
|
|
/*
|
|
** Get current AWDL params.
|
|
*/
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
|
|
pawdl_config = (awdl_election_info_t *) ptr;
|
|
|
|
printf("Flags :%d\n"
|
|
"ID :%d\n"
|
|
"Self Metrics :%d\n",
|
|
pawdl_config->election_flags,
|
|
pawdl_config->election_ID,
|
|
pawdl_config->self_metrics);
|
|
}
|
|
else {
|
|
/*
|
|
** Set the attributes.
|
|
*/
|
|
|
|
str = "awdl_election";
|
|
str_len = strlen(str);
|
|
strncpy(buf, str, str_len);
|
|
buf[ str_len ] = '\0';
|
|
|
|
pawdl_config = (awdl_election_info_t *) (buf + str_len + 1);
|
|
pawdl_config->election_flags = strtoul(*argv, NULL, 0);
|
|
pawdl_config->election_ID = strtoul(*(argv + 1), NULL, 0);
|
|
pawdl_config->self_metrics = strtoul(*(argv + 2), NULL, 0);
|
|
|
|
buf_len = str_len + 1 + sizeof(awdl_election_info_t);
|
|
|
|
rc = wlu_set(wl,
|
|
WLC_SET_VAR,
|
|
buf,
|
|
buf_len);
|
|
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_election_tree(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *str;
|
|
awdl_election_tree_info_t *pawdl_config;
|
|
int buf_len;
|
|
int str_len;
|
|
int rc;
|
|
void *ptr = NULL;
|
|
|
|
if (*++argv == NULL) {
|
|
/*
|
|
** Get current AWDL election info.
|
|
*/
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
|
|
pawdl_config = (awdl_election_tree_info_t *) ptr;
|
|
|
|
printf("Flags :%d\n"
|
|
"ID :%d\n"
|
|
"Self Metric :%d\n",
|
|
pawdl_config->election_flags,
|
|
pawdl_config->election_ID,
|
|
pawdl_config->self_metrics);
|
|
|
|
printf("RSSI thresholds:\n"
|
|
" master sync :%d\n"
|
|
" slave sync :%d\n"
|
|
" edge sync :%d\n"
|
|
" close range :%d\n"
|
|
" mid range :%d\n",
|
|
pawdl_config->master_sync_rssi_thld,
|
|
pawdl_config->slave_sync_rssi_thld,
|
|
pawdl_config->edge_sync_rssi_thld,
|
|
pawdl_config->close_range_rssi_thld,
|
|
pawdl_config->mid_range_rssi_thld);
|
|
|
|
printf("Max number of higher masters:\n"
|
|
" close range :%d\n"
|
|
" mid range :%d\n"
|
|
"Max tree depth :%d\n",
|
|
pawdl_config->max_higher_masters_close_range,
|
|
pawdl_config->max_higher_masters_mid_range,
|
|
pawdl_config->max_tree_depth);
|
|
|
|
printf("Current top master:\n");
|
|
printf(" addr : %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
pawdl_config->top_master.octet[0],
|
|
pawdl_config->top_master.octet[1],
|
|
pawdl_config->top_master.octet[2],
|
|
pawdl_config->top_master.octet[3],
|
|
pawdl_config->top_master.octet[4],
|
|
pawdl_config->top_master.octet[5]);
|
|
|
|
printf(" self metric :%d\n", pawdl_config->top_master_self_metric);
|
|
printf("Current tree depth:%d\n", pawdl_config->current_tree_depth);
|
|
} else {
|
|
/*
|
|
** Set the attributes.
|
|
*/
|
|
|
|
str = "awdl_election_tree";
|
|
str_len = strlen(str);
|
|
strncpy(buf, str, str_len);
|
|
buf[ str_len ] = '\0';
|
|
|
|
pawdl_config = (awdl_election_tree_info_t *) (buf + str_len + 1);
|
|
pawdl_config->election_flags = strtoul(*argv, NULL, 0);
|
|
pawdl_config->election_ID = strtoul(*(argv + 1), NULL, 0);
|
|
pawdl_config->self_metrics = strtoul(*(argv + 2), NULL, 0);
|
|
|
|
pawdl_config->slave_sync_rssi_thld = strtoul(*(argv+4), NULL, 0);
|
|
pawdl_config->edge_sync_rssi_thld = strtoul(*(argv+5), NULL, 0);
|
|
pawdl_config->close_range_rssi_thld = strtoul(*(argv+6), NULL, 0);
|
|
pawdl_config->mid_range_rssi_thld = strtoul(*(argv+7), NULL, 0);
|
|
pawdl_config->max_higher_masters_close_range = strtoul(*(argv+8), NULL, 0);
|
|
pawdl_config->max_higher_masters_mid_range = strtoul(*(argv+9), NULL, 0);
|
|
pawdl_config->max_tree_depth = strtoul(*(argv+10), NULL, 0);
|
|
|
|
buf_len = str_len + 1 + sizeof(awdl_election_tree_info_t);
|
|
|
|
rc = wlu_set(wl,
|
|
WLC_SET_VAR,
|
|
buf,
|
|
buf_len);
|
|
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_payload(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *str;
|
|
awdl_payload_t *pawdl_config;
|
|
int buf_len;
|
|
int str_len;
|
|
int rc, i;
|
|
void *ptr = NULL;
|
|
|
|
if (*++argv == NULL) {
|
|
/*
|
|
** Get current AWDL params.
|
|
*/
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
|
|
pawdl_config = (awdl_payload_t *) ptr;
|
|
printf("Length :%d\n"
|
|
"Packet :0x",
|
|
dtoh32(pawdl_config->len));
|
|
|
|
for (i = 0; i < pawdl_config->len; i++)
|
|
printf("%02x", pawdl_config->payload[i]);
|
|
printf("\n");
|
|
}
|
|
else {
|
|
/*
|
|
** Set the attributes.
|
|
*/
|
|
|
|
str = "awdl_payload";
|
|
str_len = strlen(str);
|
|
strncpy(buf, str, str_len);
|
|
buf[ str_len ] = '\0';
|
|
|
|
pawdl_config = (awdl_payload_t *) (buf + str_len + 1);
|
|
pawdl_config->len = htod32(wl_pattern_atoh(*argv, (char *) pawdl_config->payload));
|
|
buf_len = str_len + 1 + pawdl_config->len + sizeof(uint32);
|
|
|
|
|
|
rc = wlu_set(wl,
|
|
WLC_SET_VAR,
|
|
buf,
|
|
buf_len);
|
|
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_long_payload(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *str;
|
|
awdl_long_payload_t *pawdl_config;
|
|
int buf_len;
|
|
int str_len;
|
|
int rc, i;
|
|
void *ptr = NULL;
|
|
|
|
if (*++argv == NULL) {
|
|
/*
|
|
** Get current AWDL params.
|
|
*/
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
|
|
pawdl_config = (awdl_long_payload_t *) ptr;
|
|
printf("long psf period :%d\n"
|
|
"long psf tx offset :%d\n"
|
|
"Length :%d\n"
|
|
"Packet :0x",
|
|
pawdl_config->long_psf_period,
|
|
pawdl_config->long_psf_tx_offset,
|
|
dtoh16(pawdl_config->len));
|
|
|
|
for (i = 0; i < pawdl_config->len; i++)
|
|
printf("%02x", pawdl_config->payload[i]);
|
|
printf("\n");
|
|
}
|
|
else {
|
|
/*
|
|
** Set the attributes.
|
|
*/
|
|
|
|
str = "awdl_long_psf";
|
|
str_len = strlen(str);
|
|
strncpy(buf, str, str_len);
|
|
buf[ str_len ] = '\0';
|
|
|
|
pawdl_config = (awdl_long_payload_t *) (buf + str_len + 1);
|
|
|
|
pawdl_config->long_psf_period = strtoul(*argv, NULL, 0);
|
|
pawdl_config->long_psf_tx_offset = strtoul(*(argv + 1), NULL, 0);
|
|
pawdl_config->len = 0;
|
|
if (*(argv + 2))
|
|
pawdl_config->len = htod16(wl_pattern_atoh(*(argv + 2),
|
|
(char *)pawdl_config->payload));
|
|
buf_len = str_len + 1 + pawdl_config->len + 2 + sizeof(uint16);
|
|
|
|
rc = wlu_set(wl,
|
|
WLC_SET_VAR,
|
|
buf,
|
|
buf_len);
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_chan_seq(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *str;
|
|
awdl_channel_sequence_t *pawdl_config;
|
|
int buf_len;
|
|
int str_len;
|
|
int rc, i;
|
|
void *ptr = NULL;
|
|
|
|
if (*++argv == NULL) {
|
|
/*
|
|
** Get current AWDL params.
|
|
*/
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
|
|
pawdl_config = (awdl_channel_sequence_t *) ptr;
|
|
|
|
printf("Seq Len :%d\n"
|
|
"Encoding :%d\n"
|
|
"Step count :%d\n"
|
|
"dupilcate :%d\n"
|
|
"fill channel :%d\n"
|
|
"Chan Sequence :",
|
|
(uint8)pawdl_config->aw_seq_len,
|
|
(uint8)pawdl_config->aw_seq_enc,
|
|
(uint8)pawdl_config->seq_step_cnt,
|
|
(uint8)pawdl_config->aw_seq_duplicate_cnt,
|
|
(uint16)pawdl_config->seq_fill_chan);
|
|
|
|
for (i = 0; i <= pawdl_config->aw_seq_len; i++)
|
|
printf("0x%02x", pawdl_config->chan_sequence[i]);
|
|
printf("\n");
|
|
}
|
|
else {
|
|
/*
|
|
** Set the attributes.
|
|
*/
|
|
|
|
str = "awdl_chan_seq";
|
|
str_len = strlen(str);
|
|
strncpy(buf, str, str_len);
|
|
buf[ str_len ] = '\0';
|
|
|
|
pawdl_config = (awdl_channel_sequence_t *) (buf + str_len + 1);
|
|
pawdl_config->aw_seq_enc = strtoul(*argv, NULL, 0);
|
|
pawdl_config->seq_step_cnt = strtoul(*(argv + 1), NULL, 0);
|
|
pawdl_config->aw_seq_duplicate_cnt = strtoul(*(argv + 2), NULL, 0);
|
|
pawdl_config->seq_fill_chan = strtoul(*(argv + 3), NULL, 0);
|
|
pawdl_config->aw_seq_len = 0;
|
|
if (*(argv + 4))
|
|
pawdl_config->aw_seq_len += wl_pattern_atoh(*(argv + 4),
|
|
(char *)pawdl_config->chan_sequence);
|
|
buf_len = str_len + 1 + pawdl_config->aw_seq_len + WL_AWDL_CHAN_SEQ_FIXED_LEN;
|
|
|
|
pawdl_config->aw_seq_len /= (pawdl_config->aw_seq_enc + 1);
|
|
pawdl_config->aw_seq_len--;
|
|
|
|
rc = wlu_set(wl,
|
|
WLC_SET_VAR,
|
|
buf,
|
|
buf_len);
|
|
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
wl_bsscfg_awdl_enable(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char *endptr;
|
|
const char *val_name = "awdl_if";
|
|
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 {
|
|
wl_awdl_if_t bss_setbuf;
|
|
|
|
bzero(&bss_setbuf, sizeof(wl_awdl_if_t));
|
|
if (!wl_ether_atoe(*argv, &bss_setbuf.bssid))
|
|
return -1;
|
|
argv++;
|
|
if (!stricmp(*argv, "up"))
|
|
val = 1;
|
|
else if (!stricmp(*argv, "down"))
|
|
val = 0;
|
|
else {
|
|
val = strtol(*argv, &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
/* not all the value string was parsed by strtol */
|
|
return -1;
|
|
}
|
|
}
|
|
bss_setbuf.cfg_idx = htod32(bsscfg_idx);
|
|
bss_setbuf.up = htod32(val);
|
|
|
|
|
|
return wlu_iovar_set(wl, val_name, &bss_setbuf, sizeof(bss_setbuf));
|
|
}
|
|
}
|
|
|
|
static int
|
|
wl_awdl_mon_bssid(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
struct ether_addr bssid;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
/* skip the command name */
|
|
argv++;
|
|
|
|
if (!wl_ether_atoe(*argv, &bssid))
|
|
return -1;
|
|
|
|
return wlu_iovar_set(wl, "awdl_mon_bssid", &bssid, ETHER_ADDR_LEN);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_advertisers(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
awdl_peer_table_t *pawdl_peer_tbl;
|
|
awdl_peer_node_t *pawdl_peer;
|
|
uint32 rem_len;
|
|
int rc;
|
|
void *ptr = NULL;
|
|
|
|
if (*++argv == NULL) {
|
|
/*
|
|
** Get current AWDL params.
|
|
*/
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
pawdl_peer_tbl = (awdl_peer_table_t *) ptr;
|
|
rem_len = pawdl_peer_tbl->len;
|
|
pawdl_peer = (awdl_peer_node_t *)pawdl_peer_tbl->peer_nodes;
|
|
while (rem_len >= sizeof(awdl_peer_node_t)) {
|
|
printf("----------------------------\n");
|
|
printf("Address :%02x:%02x:%02x:%02x:%02x:%02x \n",
|
|
pawdl_peer->addr.octet[0],
|
|
pawdl_peer->addr.octet[1],
|
|
pawdl_peer->addr.octet[2],
|
|
pawdl_peer->addr.octet[3],
|
|
pawdl_peer->addr.octet[4],
|
|
pawdl_peer->addr.octet[5]);
|
|
printf("Top Master : %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
pawdl_peer->top_master.octet[0],
|
|
pawdl_peer->top_master.octet[1],
|
|
pawdl_peer->top_master.octet[2],
|
|
pawdl_peer->top_master.octet[3],
|
|
pawdl_peer->top_master.octet[4],
|
|
pawdl_peer->top_master.octet[5]);
|
|
printf("Type/state : %x\n"
|
|
"AF rssi (avg) : %d\n"
|
|
"AF rssi (last) : %d\n"
|
|
"AW period : %d\n"
|
|
"Aw counter : %d\n"
|
|
"AW Cmn time : %d\n"
|
|
"Tx counter : %d\n"
|
|
"Tx delay : %d\n"
|
|
"Aw Ext length : %d\n"
|
|
"Action period : %d\n"
|
|
"Election Metrics : %d\n"
|
|
"Top Master Metrics: %d\n"
|
|
"Distance From Top : %d\n",
|
|
dtoh16(pawdl_peer->type_state),
|
|
pawdl_peer->rssi,
|
|
pawdl_peer->last_rssi,
|
|
dtoh16(pawdl_peer->aw_period),
|
|
dtoh16(pawdl_peer->aw_counter),
|
|
dtoh16(pawdl_peer->aw_cmn_length),
|
|
dtoh16(pawdl_peer->tx_counter),
|
|
dtoh16(pawdl_peer->tx_delay),
|
|
dtoh16(pawdl_peer->aw_ext_length),
|
|
dtoh16(pawdl_peer->period_tu),
|
|
dtoh32(pawdl_peer->self_metrics),
|
|
dtoh32(pawdl_peer->top_master_metrics),
|
|
pawdl_peer->dist_top);
|
|
|
|
printf("-----------------------------\n");
|
|
|
|
rem_len -= sizeof(awdl_peer_node_t);
|
|
pawdl_peer++;
|
|
}
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_peer_op(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
awdl_peer_op_t *peer_op;
|
|
int peer_op_len = 0;
|
|
int rc = BCME_OK;
|
|
int count;
|
|
void *ptr = NULL;
|
|
|
|
count = ARGCNT(argv);
|
|
|
|
/* GET operation */
|
|
if (count < 2) {
|
|
awdl_peer_op_tbl_t *pawdl_peer_tbl;
|
|
awdl_peer_op_node_t *pawdl_peer;
|
|
uint32 rem_len;
|
|
if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
|
|
return rc;
|
|
pawdl_peer_tbl = (awdl_peer_op_tbl_t *) ptr;
|
|
rem_len = pawdl_peer_tbl->len;
|
|
if (!rem_len)
|
|
goto exit;
|
|
|
|
pawdl_peer = (awdl_peer_op_node_t *)pawdl_peer_tbl->tbl;
|
|
printf("--------------------------------------------------\n");
|
|
printf(" Address \t Flags \n");
|
|
while (rem_len >= sizeof(awdl_peer_op_node_t)) {
|
|
printf("%02x:%02x:%02x:%02x:%02x:%02x\t",
|
|
pawdl_peer->addr.octet[0],
|
|
pawdl_peer->addr.octet[1],
|
|
pawdl_peer->addr.octet[2],
|
|
pawdl_peer->addr.octet[3],
|
|
pawdl_peer->addr.octet[4],
|
|
pawdl_peer->addr.octet[5]);
|
|
printf("0x%x\n", pawdl_peer->flags);
|
|
rem_len -= sizeof(awdl_peer_op_node_t);
|
|
pawdl_peer++;
|
|
}
|
|
printf("---------------------------------------------------\n");
|
|
goto exit;
|
|
}
|
|
|
|
peer_op = (awdl_peer_op_t *)buf;
|
|
peer_op->version = AWDL_PEER_OP_CUR_VER;
|
|
|
|
/* opcode */
|
|
if (strcmp(argv[1], "add") == 0)
|
|
peer_op->opcode = AWDL_PEER_OP_ADD;
|
|
else if (strcmp(argv[1], "del") == 0)
|
|
peer_op->opcode = AWDL_PEER_OP_DEL;
|
|
else {
|
|
fprintf(stderr, "operation '%s' is not supported\n", argv[1]);
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if (count < 3) {
|
|
fprintf(stderr, "Peer address is expected\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
/* peer address */
|
|
wl_ether_atoe(argv[2], &peer_op->addr);
|
|
if (count < 4) {
|
|
fprintf(stderr, "Peer Operation mode is expected\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
peer_op_len = sizeof(awdl_peer_op_t);
|
|
|
|
/* TLV string */
|
|
if (count > 4)
|
|
peer_op_len += wl_pattern_atoh(argv[4], (char *)peer_op + peer_op_len);
|
|
|
|
rc = wlu_iovar_set(wl, cmd->name, peer_op, peer_op_len);
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
wl_awdl_oob_af(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
awdl_oob_af_params_t *af_params;
|
|
int rc = BCME_OK;
|
|
int err;
|
|
int count;
|
|
const char *str;
|
|
int str_len;
|
|
int buf_len;
|
|
|
|
count = ARGCNT(argv);
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
/* GET operation not supported */
|
|
if (count < 2) {
|
|
fprintf(stderr, "GET operation is not supported\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
str = "awdl_oob_af";
|
|
str_len = strlen(str);
|
|
strncpy(buf, str, str_len);
|
|
buf[ str_len ] = '\0';
|
|
|
|
af_params = (awdl_oob_af_params_t *) (buf + str_len + 1);
|
|
|
|
if (!wl_ether_atoe(argv[1], &af_params->bssid)) {
|
|
fprintf(stderr, "Invalid BSSID\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if (count < 3) {
|
|
fprintf(stderr, "Dst mac is expected\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if (!wl_ether_atoe(argv[2], &af_params->dst_mac)) {
|
|
fprintf(stderr, "Invalid dst mac\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if (count < 4) {
|
|
fprintf(stderr, "Channel is expected\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
af_params->channel = htod32(strtoul(*(argv + 3), NULL, 0));
|
|
|
|
if (count < 5) {
|
|
fprintf(stderr, "Dwell time is expected\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
af_params->dwell_time = htod32(strtoul(*(argv + 4), NULL, 0));
|
|
|
|
if (count < 6) {
|
|
fprintf(stderr, "Flags are expected\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
af_params->flags = htod32(strtoul(*(argv + 5), NULL, 0));
|
|
|
|
if (count < 7) {
|
|
fprintf(stderr, "Pkt lifetime is expected\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
af_params->pkt_lifetime = htod32(strtoul(*(argv + 6), NULL, 0));
|
|
|
|
if (count < 8) {
|
|
fprintf(stderr, "Tx rate is expected\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
af_params->tx_rate = htod32(strtoul(*(argv + 7), NULL, 0));
|
|
|
|
if (count < 9) {
|
|
fprintf(stderr, "Max retries count is expected\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
af_params->max_retries = htod32(strtoul(*(argv + 8), NULL, 0));
|
|
|
|
if (count < 10) {
|
|
fprintf(stderr, "Payload is expected\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
/* Variable length payload */
|
|
af_params->payload_len = htod16(strlen(argv[9])) / 2;
|
|
|
|
if ((err = get_ie_data ((uchar *)argv[9],
|
|
af_params->payload,
|
|
af_params->payload_len))) {
|
|
fprintf(stderr, "Error parsing payload\n");
|
|
rc = -1;
|
|
goto exit;
|
|
}
|
|
|
|
/* AF params contains 1 byte of payload - reduce buf_len accordingly */
|
|
buf_len = str_len + 1 + AWDL_OOB_AF_PARAMS_SIZE + af_params->payload_len;
|
|
|
|
rc = wlu_set(wl, WLC_SET_VAR, buf, buf_len);
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
wl_awdl_aw_ap_align(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
awdl_aw_ap_alignment_t ap_align;
|
|
void *ptr = NULL;
|
|
int rc;
|
|
|
|
if (*++argv == NULL) {
|
|
awdl_aw_ap_alignment_t *ret_p;
|
|
rc = wlu_var_getbuf(wl,
|
|
cmd->name,
|
|
NULL,
|
|
0,
|
|
&ptr);
|
|
if (rc)
|
|
return rc;
|
|
|
|
ret_p = (awdl_aw_ap_alignment_t*)ptr;
|
|
|
|
printf("AW AP alignment: enabled = %d, offset = 0x%08x"
|
|
"align_on_dtim = 0x%08x\n", ret_p->enabled,
|
|
ret_p->offset, ret_p->align_on_dtim);
|
|
return 0;
|
|
}
|
|
|
|
ap_align.enabled = htod32(strtoul(*argv, NULL, 0));
|
|
if (*++argv == NULL) {
|
|
printf("missing argument: offset\n");
|
|
return -1;
|
|
}
|
|
ap_align.offset = htod32(strtoul(*argv, NULL, 0));
|
|
if (*++argv)
|
|
ap_align.align_on_dtim = htod32(strtoul(*argv, NULL, 0));
|
|
else
|
|
ap_align.align_on_dtim = 0;
|
|
|
|
rc = wlu_var_setbuf(wl,
|
|
cmd->name,
|
|
&ap_align,
|
|
sizeof(awdl_aw_ap_alignment_t));
|
|
|
|
return (rc);
|
|
|
|
}
|
|
|
|
static int
|
|
wl_awdl_uct_test(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int count;
|
|
struct {
|
|
uint interval;
|
|
uint offset;
|
|
} param;
|
|
|
|
count = ARGCNT(argv);
|
|
|
|
/* GET operation not supported */
|
|
if (count < 3)
|
|
return -1;
|
|
|
|
param.interval = strtoul(argv[1], NULL, 0);
|
|
param.offset = strtoul(argv[2], NULL, 0);
|
|
|
|
return wlu_iovar_set(wl, cmd->name, ¶m, sizeof(param));
|
|
}
|
|
|
|
static int
|
|
wl_awdl_counters(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char *statsbuf;
|
|
awdl_stats_t cnt_v;
|
|
awdl_stats_t *cnt;
|
|
char *pbuf = buf;
|
|
int err;
|
|
void *ptr;
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr)))
|
|
return (err);
|
|
|
|
statsbuf = (char *)ptr;
|
|
memcpy(&cnt_v, statsbuf, sizeof(cnt_v));
|
|
|
|
cnt = &cnt_v;
|
|
|
|
/* summary stat counter line */
|
|
PRVAL(aftx); PRVAL(afrx); PRVAL(datatx); PRVAL(datarx);
|
|
PRVAL(txdrop); PRVAL(rxdrop); PRVAL(monrx); PRVAL(txsupr); PRNL();
|
|
PRVAL(afrxdrop); PRVAL(lostmaster); PRVAL(misalign); PRVAL(aw_dur); PRVAL(aws);
|
|
PRVAL(rx80211); PRVAL(awdrop); PRVAL(noawchansw); PRVAL(debug);
|
|
PRVAL(peeropdrop); PRNL();
|
|
|
|
pbuf += sprintf(pbuf, "\n");
|
|
fputs(buf, stdout);
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
wl_awdl_uct_counters(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
char *statsbuf;
|
|
awdl_uct_stats_t cnt_v;
|
|
awdl_uct_stats_t *cnt;
|
|
char *pbuf = buf;
|
|
int err;
|
|
void *ptr;
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr)))
|
|
return (err);
|
|
|
|
statsbuf = (char *)ptr;
|
|
memcpy(&cnt_v, statsbuf, sizeof(cnt_v));
|
|
|
|
cnt = &cnt_v;
|
|
|
|
/* summary stat counter line */
|
|
PRVAL(aw_proc_in_aw_sched); PRVAL(aw_upd_in_pre_aw_proc);
|
|
PRVAL(pre_aw_proc_in_aw_set); PRVAL(ignore_pre_aw_proc);
|
|
PRVAL(miss_pre_aw_intr); PRVAL(aw_dur_zero);
|
|
PRVAL(aw_sched); PRVAL(aw_proc); PRVAL(pre_aw_proc);
|
|
PRVAL(not_init); PRVAL(null_awdl);
|
|
PRNL();
|
|
|
|
pbuf += sprintf(pbuf, "\n");
|
|
fputs(buf, stdout);
|
|
return (0);
|
|
}
|
|
|
|
#ifdef WLAWDL_LATENCY_SUPPORT
|
|
static int
|
|
wl_awdl_tx_latency_clr(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
err = wlu_var_setbuf(wl, cmd->name, NULL, 0);
|
|
return (err);
|
|
}
|
|
#endif
|
|
|
|
#endif /* WLAWDL */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/* 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 rc;
|
|
}
|
|
|
|
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')
|
|
goto error;
|
|
|
|
if (argc > 1) {
|
|
if (ptrf_mgmt_config->trf_mgmt_enabled) {
|
|
if (!wl_atoip(*argv++, (void *)&ptrf_mgmt_config->host_ip_addr))
|
|
goto error;
|
|
|
|
if (!wl_atoip(*argv++, (void *)&ptrf_mgmt_config->host_subnet_mask))
|
|
goto 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
|
|
goto error;
|
|
}
|
|
|
|
rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_config, buf_len);
|
|
}
|
|
|
|
error:
|
|
return rc;
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/* 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 rc;
|
|
}
|
|
|
|
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')
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->priority = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_filter_list, buf_len);
|
|
|
|
error:
|
|
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 rc;
|
|
}
|
|
|
|
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')
|
|
goto 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 rc;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv++, &ptrf_mgmt_filter->dst_ether_addr))
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->priority = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
} else {
|
|
/* required arguments */
|
|
if (argc != 5) {
|
|
fprintf(stderr, "Too few/many arguments (require 5 got %d)\n", argc);
|
|
return rc;
|
|
}
|
|
|
|
ptrf_mgmt_filter->dst_port = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->priority = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
}
|
|
|
|
rc = wlu_var_setbuf(wl, "trf_mgmt_filters_add", ptrf_mgmt_filter_list, buf_len);
|
|
|
|
error:
|
|
return rc;
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/* 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 rc;
|
|
}
|
|
|
|
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')
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_filter_list, buf_len);
|
|
|
|
error:
|
|
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 rc;
|
|
}
|
|
|
|
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')
|
|
goto 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 rc;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv++, &ptrf_mgmt_filter->dst_ether_addr))
|
|
goto error;
|
|
|
|
} else {
|
|
if (argc < 4) {
|
|
fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 4, argc);
|
|
return rc;
|
|
}
|
|
ptrf_mgmt_filter->dst_port = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
}
|
|
|
|
rc = wlu_var_setbuf(wl, "trf_mgmt_filters_remove", ptrf_mgmt_filter_list, buf_len);
|
|
|
|
error:
|
|
return rc;
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/* 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;
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/* 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;
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/*
|
|
* 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 rc;
|
|
}
|
|
|
|
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')
|
|
goto error;
|
|
|
|
ptrf_mgmt_config->uplink_bandwidth = htod32((int32)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto 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')
|
|
goto 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 rc;
|
|
}
|
|
|
|
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')
|
|
goto 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 rc;
|
|
}
|
|
} 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);
|
|
}
|
|
|
|
error:
|
|
return rc;
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/*
|
|
* 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 rc;
|
|
}
|
|
|
|
flags = htod32((int32)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
rc = wlu_var_setbuf(wl, cmd->name, &flags, sizeof(uint32));
|
|
}
|
|
|
|
error:
|
|
return rc;
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/* 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");
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/* 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 rc;
|
|
}
|
|
|
|
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 rc;
|
|
}
|
|
|
|
/* Print the current traffic management statistics for the specified queue index. */
|
|
wl_trf_mgmt_print_stats(ptr, i);
|
|
}
|
|
|
|
|
|
return rc;
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/* 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;
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/* 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");
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
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");
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
#ifdef TRAFFIC_MGMT
|
|
/* 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 rc;
|
|
}
|
|
|
|
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 rc;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
#endif /* TRAFFIC_MGMT */
|
|
|
|
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 err;
|
|
}
|
|
|
|
obss_scan_arg.passive_dwell = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
obss_scan_arg.active_dwell = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
obss_scan_arg.bss_widthscan_interval = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
obss_scan_arg.passive_total = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
obss_scan_arg.active_total = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
obss_scan_arg.chanwidth_transition_delay = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto error;
|
|
|
|
obss_scan_arg.activity_threshold = htod16((int16)strtol(*argv++, &endptr, 0));
|
|
if (*endptr != '\0')
|
|
goto 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);
|
|
|
|
error:
|
|
return err;
|
|
}
|
|
|
|
#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_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 -1;
|
|
val = atoi(*argv);
|
|
if ((val != 0) && (val != 1))
|
|
return -1;
|
|
req->info |= val ? WL_COEX_40MHZ_INTOLERANT : 0;
|
|
options |= 0x1;
|
|
}
|
|
else if (!strncmp(*argv, "-w", 2) && ((options & 0x2) != 0x2)) {
|
|
argv++;
|
|
if (!*argv)
|
|
return -1;
|
|
val = atoi(*argv);
|
|
if ((val != 0) && (val != 1))
|
|
return -1;
|
|
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 -1;
|
|
}
|
|
req->ch_list[num] = (uint8)val;
|
|
num++;
|
|
argv++;
|
|
if (num > 14) {
|
|
printf("Too many channels (max 14)\n");
|
|
return -1;
|
|
}
|
|
} else
|
|
break;
|
|
}
|
|
if (!num) {
|
|
printf("With option '-c' specified, a channel list is required\n");
|
|
return -1;
|
|
}
|
|
req->num = num;
|
|
options |= 0x4;
|
|
continue;
|
|
}
|
|
else
|
|
return -1;
|
|
argv++;
|
|
}
|
|
if (!options)
|
|
return -1;
|
|
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;
|
|
}
|
|
|
|
static int
|
|
wl_wake_inf(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
|
|
int ret;
|
|
uchar *dump_buf;
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
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 -1;
|
|
}
|
|
|
|
memset(dump_buf, 0, WL_DUMP_BUF_LEN);
|
|
|
|
ret = wlu_iovar_get(wl, cmd->name, dump_buf, WL_DUMP_BUF_LEN);
|
|
|
|
if (!ret)
|
|
{
|
|
prhex("wake info", dump_buf, 300);
|
|
}
|
|
free(dump_buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
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 -1;
|
|
|
|
x.reg = strtol(argv[0], &endptr, 0);
|
|
if (*endptr != '\0' || x.reg > 15)
|
|
return -1;
|
|
|
|
if (argc > 2)
|
|
return (-1);
|
|
|
|
if (argc == 2) {
|
|
uint32 len;
|
|
|
|
len = strlen(argv[1]);
|
|
if (len > sizeof(x.ssid)) {
|
|
printf("ssid too long\n");
|
|
return (-1);
|
|
}
|
|
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"},
|
|
{"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"},
|
|
{"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"},
|
|
{"PALESTINE", "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"},
|
|
{"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 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(" : ");
|
|
for (j = 0; j <= 9; 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 <= 9; j++)
|
|
if (isbitset(mcsset[i], j))
|
|
printf("%dx%d ", j, i + 1);
|
|
printf("\n");
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
while (argv[i])
|
|
i++;
|
|
|
|
if (i > 4)
|
|
return -1;
|
|
|
|
/* 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 -1;
|
|
}
|
|
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 -1;
|
|
|
|
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 -1;
|
|
}
|
|
j++;
|
|
if (j < i)
|
|
return -1;
|
|
memcpy(&var[len], (char *)&int_val, sizeof(int_val));
|
|
len += 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;
|
|
}
|
|
|
|
#ifdef WLEXTLOG
|
|
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 -1;
|
|
|
|
if (argc == 1)
|
|
from_last = 0;
|
|
else {
|
|
from_last = htod32(strtoul(argv[1], &endptr, 0));
|
|
if ((from_last != 0) && (from_last != 1))
|
|
return -1;
|
|
}
|
|
|
|
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);
|
|
wlu_var_setbuf(wl, cmd->name, &w_cfg, sizeof(wlc_extlog_cfg_t));
|
|
}
|
|
else {
|
|
fprintf(stderr, "illegal command!\n");
|
|
return -1;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
#endif /* WLEXTLOG */
|
|
|
|
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 -1;
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
|
|
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 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[MAX_CCA_CHANNELS]; /* 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_average = TRUE;
|
|
bool do_individ = FALSE;
|
|
bool do_analyze = TRUE;
|
|
bool curband = FALSE;
|
|
int avg_chan_idx = 0;
|
|
uint32 flags;
|
|
|
|
|
|
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 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 USAGE_ERROR;
|
|
}
|
|
}
|
|
}
|
|
if (!do_average && !do_individ) {
|
|
printf("Must pick at least one of averages or individual secs\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
if (tmp_channel == 0) {
|
|
/* do all channels */
|
|
base = 1; limit = 255;
|
|
} 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;
|
|
}
|
|
|
|
|
|
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)
|
|
return err;
|
|
|
|
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);
|
|
return -1;
|
|
}
|
|
|
|
/* Summarize and save summary for this channel */
|
|
if (do_average) {
|
|
avg[avg_chan_idx] = (cca_congest_channel_req_t *)
|
|
malloc(sizeof(cca_congest_channel_req_t));
|
|
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 */
|
|
if (do_average) {
|
|
int j;
|
|
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)
|
|
return err;
|
|
|
|
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);
|
|
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) {
|
|
printf("Cannot find a good channel due to: %s\n", cca_errors[err]);
|
|
return 0;
|
|
}
|
|
printf("Recommended channel: %d\n", wf_chspec_ctlchan(new_chanspec));
|
|
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
int err;
|
|
wl_chanim_stats_t *list;
|
|
wl_chanim_stats_t param;
|
|
chanim_stats_t *stats;
|
|
void *ptr;
|
|
int j;
|
|
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
param.buflen = htod32(sizeof(wl_chanim_stats_t));
|
|
param.count = htod32(WL_CHANIM_COUNT_ONE);
|
|
|
|
if ((err = wlu_var_getbuf(wl, cmd->name, ¶m, sizeof(wl_chanim_stats_t), &ptr)) < 0) {
|
|
printf("failed to get chanim results");
|
|
return err;
|
|
}
|
|
|
|
list = (wl_chanim_stats_t*)ptr;
|
|
|
|
list->buflen = dtoh32(list->buflen);
|
|
list->version = dtoh32(list->version);
|
|
list->count = dtoh32(list->count);
|
|
|
|
printf("version: %d \n", list->version);
|
|
|
|
if (list->buflen == 0) {
|
|
list->version = 0;
|
|
list->count = 0;
|
|
} else if (list->version != WL_CHANIM_STATS_VERSION) {
|
|
printf("Sorry, your driver has wl_chanim_stats version %d "
|
|
"but this program supports only version %d.\n",
|
|
list->version, WL_CHANIM_STATS_VERSION);
|
|
list->buflen = 0;
|
|
list->count = 0;
|
|
}
|
|
|
|
stats = list->stats;
|
|
stats->glitchcnt = htod32(stats->glitchcnt);
|
|
stats->badplcp = htod32(stats->badplcp);
|
|
stats->chanspec = htod16(stats->chanspec);
|
|
stats->timestamp = htod32(stats->timestamp);
|
|
|
|
printf("chanspec tx inbss obss nocat nopkt doze txop "
|
|
"goodtx badtx glitch badplcp knoise timestamp\n");
|
|
printf("0x%4x\t", stats->chanspec);
|
|
for (j = 0; j < CCASTATS_MAX; j++)
|
|
printf("%d\t", stats->ccastats[j]);
|
|
printf("%d\t%d\t%d\t%d", dtoh32(stats->glitchcnt), dtoh32(stats->badplcp),
|
|
stats->bgnoise, dtoh32(stats->timestamp));
|
|
printf("\n");
|
|
|
|
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 USAGE_ERROR;
|
|
|
|
argc = 0;
|
|
param.ratio = (uint8) strtol(argv[argc], &endptr, 0);
|
|
argc++;
|
|
param.cnt = (uint8) strtol(argv[argc], &endptr, 0);
|
|
argc++;
|
|
param.period = (uint8) strtol(argv[argc], &endptr, 0);
|
|
argc++;
|
|
param.tune = (uint8) strtol(argv[argc], &endptr, 0);
|
|
|
|
/* Set txdelay params */
|
|
err = wlu_iovar_set(wl, cmd->name, (void *) ¶m,
|
|
(sizeof(txdelay_params_t)));
|
|
}
|
|
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 = 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 = 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);
|
|
}
|
|
|
|
#ifdef WLP2P
|
|
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 -1;
|
|
|
|
st.state = (uint8) strtol(argv[0], &endptr, 0);
|
|
if (st.state == WL_P2P_DISC_ST_LISTEN) {
|
|
if (count != 3)
|
|
return -1;
|
|
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 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 -1;
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
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';
|
|
|
|
err = wl_scan_prep(wl, cmd, argv + 1, sparams, &sparams_size);
|
|
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) */
|
|
|
|
err = wl_scan_prep(wl, cmd, argv + 1, &eparams->params, &sparams_size);
|
|
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 -1;
|
|
|
|
if (!wl_ether_atoe(argv[0], &ifreq.addr))
|
|
return -1;
|
|
|
|
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 -1;
|
|
|
|
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 -1;
|
|
|
|
if (!wl_ether_atoe(argv[0], &addr))
|
|
return -1;
|
|
|
|
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 -1;
|
|
|
|
if (!wl_ether_atoe(argv[0], &ifreq.addr))
|
|
return -1;
|
|
|
|
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 -1;
|
|
|
|
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 -1;
|
|
|
|
if (!wl_ether_atoe(argv[0], &addr))
|
|
return -1;
|
|
|
|
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 BCME_ERROR;
|
|
}
|
|
|
|
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 -1;
|
|
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 BCME_ERROR;
|
|
}
|
|
|
|
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 -2;
|
|
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_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_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_ERROR;
|
|
}
|
|
/* fall through... */
|
|
normal:
|
|
/* XXX check buffer size */
|
|
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);
|
|
}
|
|
#endif /* WLP2P */
|
|
|
|
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_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_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 -1;
|
|
}
|
|
led.index = (int)strtoul(*argv, NULL, 10);
|
|
|
|
if (led.index > 3) {
|
|
printf("only 4 led supported\n");
|
|
return -1;
|
|
}
|
|
|
|
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 0;
|
|
}
|
|
|
|
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 -1;
|
|
|
|
in_arg[0] = htod32((uint32)(strtoul(argv[1], &endptr, 0)));
|
|
|
|
if (in_arg[0] > 3) {
|
|
printf("only 4 led supported\n");
|
|
return -1;
|
|
}
|
|
|
|
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)));
|
|
wlu_var_setbuf(wl, cmd->name, in_arg, sizeof(in_arg));
|
|
}
|
|
else {
|
|
fprintf(stderr, "illegal command!\n");
|
|
return -1;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/* 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 */
|
|
{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";
|
|
|
|
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))
|
|
printf(" %s", dbg_msg[i].string);
|
|
}
|
|
printf("\n");
|
|
|
|
return err;
|
|
}
|
|
while (*argv) {
|
|
char *s = *argv;
|
|
char t[32];
|
|
|
|
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 */
|
|
char c[32] = "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 -1;
|
|
}
|
|
}
|
|
/* 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 -1;
|
|
}
|
|
}
|
|
/* 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_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 -1;
|
|
}
|
|
}
|
|
/* 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 -1;
|
|
}
|
|
}
|
|
/* 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 -1;
|
|
}
|
|
}
|
|
/* 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 -1;
|
|
}
|
|
}
|
|
/* 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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
}
|
|
/* 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 (-1);
|
|
}
|
|
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 -1;
|
|
}
|
|
}
|
|
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 (-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;
|
|
}
|
|
|
|
/* 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 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 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 USAGE_ERROR;
|
|
|
|
/* bssid */
|
|
if (!wl_ether_atoe(argv[1], &nbr_elt.bssid)) {
|
|
printf("wl_rrm_nbr_add_nbr parsing bssid failed\n");
|
|
return 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 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) { \
|
|
fprintf(stderr, "TCLAS: %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)) {
|
|
fprintf(stderr, "TCLAS: 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)) {
|
|
fprintf(stderr, "TCLAS: 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;
|
|
|
|
} 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");
|
|
wl_atoipv6(*argv, (struct ipv6_addr *)&fc_ipv6->saddr);
|
|
|
|
TCLAS_ARG_CHECK(argv, "ipv6 dest ip");
|
|
wl_atoipv6(*argv, (struct ipv6_addr *)&fc_ipv6->daddr);
|
|
|
|
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;
|
|
|
|
} 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");
|
|
wl_atoip(*argv, (struct ipv4_addr *)&fc_ipv4->src_ip);
|
|
|
|
TCLAS_ARG_CHECK(argv, "ipv4 dest ip");
|
|
wl_atoip(*argv, (struct ipv4_addr *)&fc_ipv4->dst_ip);
|
|
|
|
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;
|
|
|
|
} else
|
|
return BCME_ERROR;
|
|
} else {
|
|
fprintf(stderr, "TCLAS: Unsupported frame classifier type 0x%2x\n", fc->hdr.type);
|
|
return BCME_ERROR;
|
|
}
|
|
|
|
if (*++argv) {
|
|
fprintf(stderr, "TCLAS: superflous argument %s\n", *argv);
|
|
return BCME_ERROR;
|
|
}
|
|
|
|
err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
|
|
|
|
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_tfs_set(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err, buflen;
|
|
wl_tfs_set_t *tfs_set;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
buflen = sprintf(buf, "%s", *argv) + 1;
|
|
tfs_set = (wl_tfs_set_t *) (buf + buflen);
|
|
tfs_set->tfs_id = 0;
|
|
tfs_set->tclas_proc = 0;
|
|
tfs_set->actcode = 0;
|
|
buflen += sizeof(wl_tfs_set_t);
|
|
|
|
if (*++(argv) == NULL) {
|
|
printf("Missing <send> argument\n");
|
|
return BCME_ERROR;
|
|
}
|
|
tfs_set->send = (uint8) strtoul(*argv, NULL, 0);
|
|
|
|
if (*++(argv) == NULL)
|
|
goto set;
|
|
tfs_set->tfs_id = (uint8) strtoul(*argv, NULL, 0);
|
|
|
|
if (*++(argv) == NULL)
|
|
goto set;
|
|
tfs_set->actcode = (uint8) strtoul(*argv, NULL, 0);
|
|
|
|
if (*++(argv) == NULL)
|
|
goto set;
|
|
tfs_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_tfs_status(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret;
|
|
wl_tfs_status_t *wl_list = (wl_tfs_status_t *)buf;
|
|
uint8 *p = (uint8 *)wl_list->fset;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
strcpy(buf, argv[0]);
|
|
ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
printf("TFS filter set(s):\n");
|
|
while (wl_list->fset_cnt--) {
|
|
wl_tfs_fset_t *fset = (wl_tfs_fset_t *) p;
|
|
|
|
printf(" - %s TFS ID=%d status=%d token=%d "
|
|
"action code=%d notify=%d filter(s):\n",
|
|
wl_ether_etoa(&fset->ea), fset->tfs_id, fset->status, fset->token,
|
|
fset->actcode, fset->notify);
|
|
|
|
p += WL_TFS_FSET_FIXED_SIZE;
|
|
|
|
while (fset->filter_cnt--) {
|
|
wl_tfs_filter_t *filter = (wl_tfs_filter_t *) p;
|
|
|
|
printf("\t- status=%d TCLAS proc=%d TCLAS(s):\n",
|
|
filter->status, filter->tclas_proc);
|
|
|
|
p += WL_TFS_FILTER_FIXED_SIZE;
|
|
|
|
while (filter->tclas_cnt--) {
|
|
wl_tclas_t *tclas = (wl_tclas_t *)p;
|
|
|
|
printf("\t\t- ");
|
|
wl_tclas_dump(tclas);
|
|
|
|
p += WL_TCLAS_FIXED_SIZE + tclas->fc_len;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
wl_wnm_tfs_term(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int err, buflen;
|
|
wl_tfs_term_t *tfs_term;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
buflen = sprintf(buf, "%s", *argv) + 1;
|
|
|
|
tfs_term = (wl_tfs_term_t *) (buf + buflen);
|
|
tfs_term->tfs_id = 0;
|
|
buflen += sizeof(wl_tfs_term_t);
|
|
|
|
if (*++(argv) == NULL) {
|
|
printf("Missing <flags> argument\n");
|
|
return BCME_ERROR;
|
|
}
|
|
tfs_term->flags = (uint8) strtoul(*argv, NULL, 0);
|
|
|
|
if (*++(argv) == NULL)
|
|
goto set;
|
|
tfs_term->tfs_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_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)
|
|
{
|
|
char *p = buf;
|
|
UNUSED_PARAMETER(cmd);
|
|
|
|
p += 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;
|
|
|
|
printf("BSS Max Idle Period: %d(in unit of 1000TU])\n", *(uint32 *)buf);
|
|
return BCME_OK;
|
|
|
|
} else {
|
|
htol32_ua_store(strtoul(*argv++, NULL, 0), p);
|
|
p += sizeof(uint32);
|
|
htol32_ua_store(*argv? strtoul(*argv, NULL, 0) : 0, p);
|
|
p += sizeof(uint32);
|
|
|
|
return wlu_set(wl, WLC_SET_VAR, buf, p - buf);
|
|
}
|
|
}
|
|
|
|
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 = (uint8) 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 = (uint16) 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 = (uint16) tmp;
|
|
|
|
/* unicast/broadcast parsing */
|
|
if (*++argv != NULL)
|
|
bsstrans_req.unicast = (uint8) 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;
|
|
}
|
|
|
|
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 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 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 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_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 -1;
|
|
}
|
|
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);
|
|
if (err)
|
|
return err;
|
|
|
|
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);
|
|
if (err)
|
|
return err;
|
|
|
|
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);
|
|
if (err)
|
|
return err;
|
|
|
|
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);
|
|
if (err)
|
|
return err;
|
|
|
|
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);
|
|
if (err)
|
|
return err;
|
|
|
|
return err;
|
|
}
|
|
|
|
#ifdef BCMINTERNAL
|
|
static int
|
|
wl_mfp_bip_test(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
const char *cmdname = "mfp_bip_test";
|
|
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;
|
|
}
|
|
|
|
err = wlu_iovar_set(wl, cmdname, varbuf, 256);
|
|
if (err)
|
|
return err;
|
|
|
|
return err;
|
|
}
|
|
#endif /* BCMINTERNAL */
|
|
#ifdef SERDOWNLOAD
|
|
/* 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);
|
|
|
|
/* XXX this shouldn't be a global... */
|
|
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");
|
|
}
|
|
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);
|
|
}
|
|
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, 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");
|
|
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");
|
|
goto exit;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
/* 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 = -1;
|
|
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 = -1;
|
|
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
|
|
hsic_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_hsic_download(dhd, fname, vname);
|
|
exit:
|
|
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");
|
|
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");
|
|
goto exit;
|
|
}
|
|
|
|
argv++;
|
|
|
|
if (debug) {
|
|
printf("argv=%s\n", *argv);
|
|
}
|
|
|
|
fname = *argv;
|
|
|
|
/* validate arguments */
|
|
if (!fname) {
|
|
fprintf(stderr, "filename required\n");
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if (!(fp = fopen(fname, "wb"))) {
|
|
perror(fname);
|
|
ret = -1;
|
|
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");
|
|
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));
|
|
#if 0
|
|
for (j = 0; j < len; j++) {
|
|
if ((j % 16) == 0)
|
|
printf("\n");
|
|
printf("%02x ", (unsigned char)buf[j]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
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 = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if (stat(fname, &finfo)) {
|
|
printf("ReadFiles: %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 = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if (stat(vname, &finfo)) {
|
|
printf("ReadFiles: %s: %s\n", vname, strerror(errno));
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
nvlen = finfo.st_size;
|
|
len += nvlen;
|
|
|
|
/* XXX: add 4 bytes in caseewe need to add padding */
|
|
if ((buf = malloc(len +4)) == NULL) {
|
|
printf("ReadFiles: Unable to allowcate %d bytes!\n", len);
|
|
ret = -1;
|
|
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("ReadFiles: 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("ReadFiles: Failed input file check %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("ReadFiles: 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_TRX(hdr) - OFFSETOF(struct trx_header, flag_version),
|
|
CRC32_INIT_VALUE);
|
|
|
|
/* Calculate CRC over data */
|
|
for (i = SIZEOF_TRX(hdr); 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;
|
|
}
|
|
|
|
headers += SIZEOF_TRX(trx);
|
|
if (ltoh32(trx->flag_version) & TRX_UNCOMP_IMAGE) {
|
|
actual_len = ltoh32(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]) +
|
|
SIZEOF_TRX(trx);
|
|
return actual_len;
|
|
}
|
|
return actual_len;
|
|
}
|
|
#endif /* SERDOWNLOAD */
|
|
|
|
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 -1;
|
|
}
|
|
}
|
|
}
|
|
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
|
|
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_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 -1;
|
|
}
|
|
/* 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 -1;
|
|
}
|
|
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 -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
else {
|
|
if ((int)strlen (argv[1]) != datalen) {
|
|
fprintf(stderr, "length is matching to string\n");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 -1;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/* Restore the ignored warnings status */
|
|
|
|
#ifdef BCMINTERNAL
|
|
static int
|
|
wl_nwoe_ifconfig(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int ret;
|
|
struct ipv4_addr ipa_set;
|
|
nwoe_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 -1;
|
|
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;
|
|
nwoe_ifconfig_t *if_get;
|
|
if ((ret = wlu_var_getbuf(wl, cmd->name, &ifconfig, sizeof(ifconfig), &ptr)) < 0)
|
|
return ret;
|
|
|
|
if_get = (nwoe_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;
|
|
}
|
|
#endif /* BCMINTERNAL */
|
|
|
|
#if defined(WL_PROXDETECT)
|
|
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 */
|
|
|
|
/* 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 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_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];
|
|
chanspec_t chanspec;
|
|
uint16 interval, duration, tx_rate;
|
|
|
|
/* skip the command name and check if mandatory exists */
|
|
if (!*++argv) {
|
|
fprintf(stderr, "missing mandatory parameter \'method\'\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
/* parse method */
|
|
method = (uint16)atoi(argv[0]);
|
|
if (method == 0) {
|
|
fprintf(stderr, "invalid parameter \'method\'\n");
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
memset(&proxd_params, 0, 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;
|
|
|
|
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("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));
|
|
printf("maxconvergetime=%d ms\n\n", dtoh16(reply->u.rssi_params.maxconvergtmo));
|
|
}
|
|
else
|
|
{
|
|
memcpy((void *)&proxd_params, (void *)ptr, sizeof(proxd_params));
|
|
|
|
/* set */
|
|
miniopt_init(&to, cmd->name, NULL, FALSE);
|
|
while ((opt_err = miniopt(&to, argv)) != -1) {
|
|
if (opt_err == 1) {
|
|
return USAGE_ERROR;
|
|
}
|
|
argv += to.consumed;
|
|
|
|
if (to.opt == 'c') {
|
|
if (!to.good_int) {
|
|
fprintf(stderr,
|
|
"%s: could not parse \"%s\" as a a channel\n",
|
|
cmd->name, to.valstr);
|
|
return USAGE_ERROR;
|
|
}
|
|
|
|
if ((chanspec = wf_chspec_aton(to.valstr)) == 0) {
|
|
fprintf(stderr,
|
|
"%s: could not parse \"%s\" as a channel\n",
|
|
cmd->name, to.valstr);
|
|
return BCME_BADARG;
|
|
}
|
|
|
|
proxd_params.u.rssi_params.chanspec
|
|
= wl_chspec_to_driver(chanspec);
|
|
if (proxd_params.u.rssi_params.chanspec == INVCHANSPEC) {
|
|
return BCME_BADARG;
|
|
}
|
|
} else if (to.opt == 'i') {
|
|
if (!to.good_int) {
|
|
fprintf(stderr,
|
|
"%s: could not parse \"%s\" as an interval\n",
|
|
cmd->name, to.valstr);
|
|
return USAGE_ERROR;
|
|
}
|
|
proxd_params.u.rssi_params.interval = htod16(to.val);
|
|
}
|
|
else if (to.opt == 'd') {
|
|
if (!to.good_int) {
|
|
fprintf(stderr,
|
|
"%s: could not parse \"%s\" as a duration\n",
|
|
cmd->name, to.valstr);
|
|
return USAGE_ERROR;
|
|
}
|
|
proxd_params.u.rssi_params.duration = htod16(to.val);
|
|
}
|
|
else if (to.opt == 's') {
|
|
if (!to.good_int) {
|
|
fprintf(stderr,
|
|
"%s: could not parse \"%s\" as a RSSI\n",
|
|
cmd->name, to.valstr);
|
|
return USAGE_ERROR;
|
|
}
|
|
proxd_params.u.rssi_params.rssi_thresh = htod16(to.val);
|
|
}
|
|
else if (to.opt == 'p') {
|
|
if (!to.good_int) {
|
|
fprintf(stderr,
|
|
"%s: could not parse \"%s\" as a power\n",
|
|
cmd->name, to.valstr);
|
|
return USAGE_ERROR;
|
|
}
|
|
proxd_params.u.rssi_params.tx_power = htod16(to.val);
|
|
} else 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\n",
|
|
cmd->name, to.valstr);
|
|
return USAGE_ERROR;
|
|
}
|
|
} else
|
|
to.val = to.val*2;
|
|
|
|
proxd_params.u.rssi_params.tx_rate = htod16(to.val);
|
|
} else if (to.opt == 't') {
|
|
if (!to.good_int) {
|
|
fprintf(stderr,
|
|
"%s: could not parse \"%s\" as a timeout\n",
|
|
cmd->name, to.valstr);
|
|
return USAGE_ERROR;
|
|
}
|
|
proxd_params.u.rssi_params.timeout = htod16(to.val);
|
|
} else if (to.opt == 'm') {
|
|
if (!to.good_int) {
|
|
fprintf(stderr,
|
|
"%s: could not parse \"%s\" as a maxconvergetime\n",
|
|
cmd->name, to.valstr);
|
|
return USAGE_ERROR;
|
|
}
|
|
proxd_params.u.rssi_params.maxconvergtmo = htod16(to.val);
|
|
}
|
|
else
|
|
return 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;
|
|
}
|
|
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_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 */
|
|
memset(&status, 0, 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;
|
|
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));
|
|
}
|
|
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;
|
|
}
|
|
memset(buf, 0, 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)
|
|
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");
|
|
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);
|
|
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);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* WL_PROXDETECT */
|
|
|
|
#if defined(DWDS)
|
|
static int
|
|
wl_dwds_config(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
struct ether_addr ea;
|
|
wlc_dwds_config_t dwds;
|
|
char *param;
|
|
int buflen, 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 */
|
|
|
|
#ifdef WIN32
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
|
|
typedef struct {
|
|
uint16 val;
|
|
const char *str;
|
|
} patrim_t;
|
|
|
|
static const patrim_t patrims[] = {
|
|
{0x0, "NULL"},
|
|
{0x1, "bw40"},
|
|
{0x2, "bw80"},
|
|
{0x3, "bw4080"},
|
|
{0x4, "cck"},
|
|
{0x11, "NULL, bw40"},
|
|
{0x12, "NULL, bw80"},
|
|
{0x13, "NULL, bw4080"},
|
|
{0x14, "NULL, cck"},
|
|
{0x15, "bw40, bw80"},
|
|
{0x21, "NULL, bw40, bw80"},
|
|
{0x22, "NULL, bw40, cck"},
|
|
};
|
|
|
|
static int
|
|
wl_patrim(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
int patrim;
|
|
uint32 i;
|
|
|
|
UNUSED_PARAMETER(cmd);
|
|
UNUSED_PARAMETER(argv);
|
|
|
|
if (wlu_iovar_getint(wl, "patrim", &patrim) < 0)
|
|
return -1;
|
|
|
|
for (i = 0; i < sizeof(patrims) / sizeof(patrims[0]); i ++) {
|
|
if (patrim == patrims[i].val) {
|
|
printf("%s\n", patrims[i].str);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -2;
|
|
}
|
|
|
|
/* Set TCP Keep-Alive to an integer value. */
|
|
static int
|
|
wl_tcp_keep_conn_set(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
wl_mtcpkeep_alive_conn_pkt_t tcpkeepconn;
|
|
wl_mtcpkeep_alive_conn_pkt_t *tcpkeepconnp;
|
|
int rc = 0;
|
|
uint32 value;
|
|
|
|
tcpkeepconnp = &tcpkeepconn;
|
|
|
|
memset(&tcpkeepconn, 0, sizeof(wl_mtcpkeep_alive_conn_pkt_t));
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_conn_set: a GET: not supported right now\n");
|
|
return rc;
|
|
}
|
|
|
|
/* Process a SET request */
|
|
if (!wl_ether_atoe(*argv, &tcpkeepconn.saddr)) {
|
|
printf("wl_tcp_keep_conn_set: saddr did not parse\n");
|
|
return -1;
|
|
}
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_conn_set: daddr not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!wl_ether_atoe(*argv, &tcpkeepconn.daddr)) {
|
|
printf("wl_tcp_keep_conn_set: daddr did not parse\n");
|
|
return -1;
|
|
}
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_conn_set: sip not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!wl_atoip(*argv, &tcpkeepconn.sipaddr)) {
|
|
printf("wl_tcp_keep_conn_set: sipaddr did not parse\n");
|
|
return -1;
|
|
}
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_conn_set: dipaddr not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!wl_atoip(*argv, &tcpkeepconn.dipaddr)) {
|
|
printf("wl_tcp_keep_conn_set: dipaddr did not parse\n");
|
|
return -1;
|
|
}
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_conn_set: sport not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
value = htod32(strtoul(*argv, NULL, 0));
|
|
tcpkeepconn.sport = (uint16)value;
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_conn_set: dport not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
value = htod32(strtoul(*argv, NULL, 0));
|
|
tcpkeepconn.dport = (uint16)value;
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_conn_set: seq not provided\n");
|
|
return -1;
|
|
}
|
|
tcpkeepconn.seq = htod32(strtoul(*argv, NULL, 0));
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_conn_set: ack not provided\n");
|
|
return -1;
|
|
}
|
|
tcpkeepconn.ack = htod32(strtoul(*argv, NULL, 0));
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_conn_set: tcpwin not provided\n");
|
|
return -1;
|
|
}
|
|
value = htod32(strtoul(*argv, NULL, 0));
|
|
tcpkeepconn.tcpwin = (uint16)value;
|
|
rc = wlu_var_setbuf(wl, cmd->name, tcpkeepconnp, sizeof(wl_mtcpkeep_alive_conn_pkt_t));
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* Set TCP Keep-Alive interval timers and retry cnt. */
|
|
static int
|
|
wl_tcp_keep_timers_set(void *wl, cmd_t *cmd, char **argv)
|
|
{
|
|
wl_mtcpkeep_alive_timers_pkt_t tcpkeeptimers;
|
|
wl_mtcpkeep_alive_timers_pkt_t *tcpkeeptimersp;
|
|
int rc = 0;
|
|
uint32 value;
|
|
|
|
tcpkeeptimersp = &tcpkeeptimers;
|
|
|
|
memset(&tcpkeeptimers, 0, sizeof(wl_mtcpkeep_alive_timers_pkt_t));
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_timers_set: a GET: not supported right now\n");
|
|
return rc;
|
|
}
|
|
|
|
/* Process a SET request */
|
|
value = htod32(strtoul(*argv, NULL, 0));
|
|
tcpkeeptimers.interval = (uint16)value;
|
|
if ((value < 1) || (value > 14400)) {
|
|
printf("wl_tcp_keep_timers_set: bad interval provided\n");
|
|
return -1;
|
|
}
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_timers_set: retry interval not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
value = htod32(strtoul(*argv, NULL, 0));
|
|
tcpkeeptimers.retry_interval = (uint16)value;
|
|
if ((value < 1) || (value > 14400)) {
|
|
printf("wl_tcp_keep_timers_set: bad retry interval provided\n");
|
|
return -1;
|
|
}
|
|
|
|
if (*++argv == NULL) {
|
|
printf("wl_tcp_keep_timers_set: retry count not provided\n");
|
|
return -1;
|
|
}
|
|
|
|
value = htod32(strtoul(*argv, NULL, 0));
|
|
tcpkeeptimers.retry_count = (uint16)value;
|
|
if ((value < 2) || (value > 20)) {
|
|
printf("wl_tcp_keep_timers_set: bad retry count provided\n");
|
|
return -1;
|
|
}
|
|
|
|
rc = wlu_var_setbuf(wl, cmd->name, tcpkeeptimersp, sizeof(wl_mtcpkeep_alive_timers_pkt_t));
|
|
|
|
return rc;
|
|
}
|
|
#endif /* !ATE_BUILD */
|
|
|
|
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;
|
|
}
|