K2.6 patches and update.
[tomato.git] / release / src-rt / wl / exe / wlu.c
blobb345d531d9879ae7c1643103f9bbbc4d0dbaed85
1 /*
2 * Common code for wl command-line swiss-army-knife utility
4 * Copyright (C) 2010, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
12 * $Id: wlu.c,v 1.1104.2.99 2011-01-28 23:22:50 Exp $
17 #if defined(__NetBSD__)
18 #include <typedefs.h>
19 #endif
21 /* Because IL_BIGENDIAN was removed there are few warnings that need
22 * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
23 * Hence these warnings were not seen earlier.
24 * For now ignore the following warnings
26 #ifdef WIN32
27 #pragma warning(push)
28 #pragma warning(disable : 4244)
29 #pragma warning(disable : 4761)
30 #endif
32 #if defined(_CFE_)
33 #include <lib_types.h>
34 #include <lib_string.h>
35 #include <lib_printf.h>
36 #include <lib_malloc.h>
37 #include <cfe_error.h>
38 #else
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <assert.h>
44 #endif /* defined(_CFE_) */
45 #include <typedefs.h>
46 #include <epivers.h>
47 #include <proto/ethernet.h>
48 #include <proto/802.11.h>
49 #include <proto/802.1d.h>
50 #include <proto/802.11e.h>
51 #include <proto/wpa.h>
52 #include <proto/bcmip.h>
53 #ifdef WLBTAMP
54 #include <proto/bt_amp_hci.h>
55 #endif
56 #include <wlioctl.h>
57 #include <bcmutils.h>
58 #include <bcmendian.h>
59 #include <bcmwifi.h>
60 #include <bcmsrom_fmt.h>
61 #include <bcmsrom_tbl.h>
62 #include "wlu.h"
63 #include <bcmcdc.h>
64 #if defined(WLPFN) && defined(linux)
65 #ifndef TARGETENV_android
66 #include <unistd.h>
67 #endif
68 #include <signal.h>
69 #include <sys/types.h>
70 #include <sys/socket.h>
71 #include <sys/time.h>
72 #include <sys/ioctl.h>
73 #include <netinet/in.h>
74 #include <net/if.h>
75 #include <linux/if_packet.h>
76 #endif /* WLPFN */
78 #ifdef WLEXTLOG
79 #include <wlc_extlog_idstr.h>
80 #endif
82 #include <inttypes.h>
83 #include <miniopt.h>
85 #if defined(__NetBSD__) || defined(linux) || defined(MACOSX) || defined(EFI)
86 #define stricmp strcasecmp
87 #define strnicmp strncasecmp
88 #elif defined(__ECOS)
89 extern int stricmp(const char *s1, const char *s2);
90 extern int strnicmp(const char *s1, const char *s2, size_t len);
91 #elif defined(UNDER_CE) || defined(_CRT_SECURE_NO_DEPRECATE)
92 #define stricmp _stricmp
93 #define strnicmp _strnicmp
94 #elif defined(_CFE_)
95 #include <bcmutils.h>
96 #include <osl.h>
97 #define isalnum(c) bcm_isalnum(c)
98 #define isalpha(c) bcm_isalpha(c)
99 #define iscntrl(c) bcm_iscntrl(c)
100 #define isdigit(c) bcm_isdigit(c)
101 #define isgraph(c) bcm_isgraph(c)
102 #define islower(c) bcm_islower(c)
103 #define isprint(c) bcm_isprint(c)
104 #define ispunct(c) bcm_ispunct(c)
105 #define isspace(c) bcm_isspace(c)
106 #define isupper(c) bcm_isupper(c)
107 #define isxdigit(c) bcm_isxdigit(c)
108 #define stricmp(s1, s2) lib_strcmpi((s1), (s2))
109 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
110 #define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
111 #define fprintf(stream, fmt, args...) xprintf(fmt, ##args)
112 #define fputs(s, stream) puts(s)
113 #define malloc(size) KMALLOC((size), 0)
114 #define free(ptr) KFREE(ptr)
115 #define strnicmp(s1, s2, len) strncmp((s1), (s2), (len))
116 #define strspn(s, accept) (0)
117 #define strtol(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
118 #elif defined(BWL_STRICMP)
119 #define stricmp bcmstricmp
120 #define strnicmp bcmstrnicmp
121 #endif /* __NetBSD__ */
124 /* For backwards compatibility, the absense of the define 'NO_FILESYSTEM_SUPPORT'
125 * implies that a filesystem is supported.
127 #if !defined(BWL_NO_FILESYSTEM_SUPPORT)
128 #define BWL_FILESYSTEM_SUPPORT
129 #endif
132 cmd_func_t wl_int;
133 static cmd_func_t wl_print_deprecate;
134 static cmd_func_t wl_void, wl_rssi, wl_rssi_event, wl_phy_rssi_ant, wl_gmode;
135 static cmd_func_t wlu_dump, wlu_srdump, wlu_srwrite, wlu_srvar, wl_nvsource;
136 static cmd_func_t wlu_ciswrite, wlu_cisupdate, wlu_cisdump;
137 static cmd_func_t wl_rate_mrate, wl_phy_rate, wl_bss_max;
138 static cmd_func_t wl_channel, wl_chanspec, wl_chanim_state, wl_chanim_mode;
139 static cmd_func_t wl_radio, wl_version, wl_list, wl_band, wl_bandlist, wl_phylist;
140 static cmd_func_t wl_join, wl_tssi, wl_txpwr, wl_atten, wl_evm, wl_country;
141 static cmd_func_t wl_out, wl_txpwr1, wl_country_ie_override;
142 static cmd_func_t wl_maclist, wl_get_pktcnt, wl_upgrade;
143 static cmd_func_t wl_maclist_1;
144 static cmd_func_t wl_rateset, wl_interfere, wl_interfere_override;
145 static cmd_func_t wl_radar_args, wl_radar_thrs, wl_dfs_status;
146 static cmd_func_t wl_get_txpwr_limit, wl_get_current_power, wl_get_instant_power;
147 static cmd_func_t wl_get_current_txppr;
148 static cmd_func_t wl_var_get, wl_var_getint, wl_var_getinthex, wl_var_getandprintstr;
149 static cmd_func_t wl_var_setint, wl_addwep, wl_rmwep;
150 static cmd_func_t wl_nvdump, wl_nvget, wl_nvset, wl_sta_info, wl_chan_info;
151 static cmd_func_t wl_wme_ac_req, wl_add_ie, wl_del_ie, wl_list_ie;
152 static cmd_func_t wl_wme_apsd_sta, wl_wme_dp, wl_lifetime;
153 static cmd_func_t wl_rand, wl_otpw, wl_counters, wl_delta_stats;
154 static cmd_func_t wl_assoc_info, wl_wme_counters, wl_devpath;
155 static cmd_func_t wl_bitvec128, wl_diag, wl_var_void;
156 static cmd_func_t wl_auto_channel_sel;
157 static cmd_func_t wl_bsscfg_int, wl_bsscfg_enable;
158 static cmd_func_t wl_msglevel, wl_plcphdr, wl_reg, wl_macreg, wl_band_elm;
159 static cmd_func_t wl_phymsglevel;
160 static cmd_func_t wl_rateparam, wl_wepstatus, wl_status, wl_spect;
161 static cmd_func_t wl_sup_rateset, wl_scan, wl_send_csa, wl_iscan, wl_escan;
162 #ifdef EXTENDED_SCAN
163 static cmd_func_t wl_extdscan;
164 #endif
165 static cmd_func_t wl_dump_chanlist, wl_primary_key, wl_measure_req, wl_send_quiet;
166 static cmd_func_t wl_dump_chanspecs, wl_cur_mcsset;
167 static cmd_func_t wl_wsec, wl_keys, wl_wsec_test;
168 static cmd_func_t wl_channels_in_country;
169 static cmd_func_t wl_wpa_auth, wl_tsc, wl_deauth_rc, wl_ssid, wl_bssid, wl_smfstats;
170 static cmd_func_t wl_wds_wpa_role_old, wl_wds_wpa_role, wl_set_pmk;
171 static cmd_func_t wl_rm_request, wl_rm_report;
172 static cmd_func_t wl_join_pref, wl_assoc_pref;
173 static cmd_func_t wl_dump_networks, wl_mac, wl_revinfo, wl_iov_mac;
174 static cmd_func_t wl_cac, wl_tslist, wl_tspec, wl_tslist_ea, wl_tspec_ea, wl_cac_delts_ea;
175 static cmd_func_t wl_varstr, wl_var_setintandprintstr;
176 static cmd_func_t wl_rifs;
177 static cmd_func_t wl_rifs_advert;
178 static cmd_func_t wl_test_tssi, wl_test_tssi_offs, wl_phy_rssiant, wl_rxiq;
179 static cmd_func_t wl_obss_scan, wl_obss_coex_action;
180 static cmd_func_t wl_dump_lq;
181 static cmd_func_t wl_monitor_lq;
184 #ifdef WLPFN
185 static cmd_func_t wl_pfn_set;
186 static cmd_func_t wl_pfn_add;
187 static cmd_func_t wl_pfn;
188 #if defined(linux)
189 static cmd_func_t wl_pfn_event_check;
190 static cmd_func_t wl_escan_event_check;
191 static cmd_func_t wl_escanresults;
192 #endif /* linux */
193 static cmd_func_t wl_event_filter;
194 #endif /* WLPFN */
195 static cmd_func_t wl_wowl_pattern, wl_wowl_wakeind, wl_wowl_pkt, wl_wowl_status;
196 static cmd_func_t wl_reassoc;
199 static cmd_func_t wl_pmkid_info;
202 static cmd_func_t wl_rate_histo;
203 static cmd_func_t wl_sample_collect;
204 static cmd_func_t wlu_reg3args;
206 static cmd_func_t wl_coma;
207 static cmd_func_t wl_tpc_lm;
208 static cmd_func_t wlu_reg2args;
209 static cmd_func_t wme_tx_params;
210 static cmd_func_t wme_maxbw_params;
211 static cmd_func_t wl_ampdu_tid, wl_ampdu_activate_test;
212 static cmd_func_t wl_ampdu_retry_limit_tid;
213 static cmd_func_t wl_ampdu_rr_retry_limit_tid;
214 static cmd_func_t wl_ampdu_send_addba;
215 static cmd_func_t wl_ampdu_send_delba;
217 static cmd_func_t wl_dpt_deny;
218 static cmd_func_t wl_dpt_endpoint;
219 static cmd_func_t wl_dpt_pmk;
220 static cmd_func_t wl_dpt_fname;
221 static cmd_func_t wl_dpt_list;
222 #ifdef WLBTAMP
223 static cmd_func_t wl_HCI_cmd;
224 static cmd_func_t wl_HCI_ACL_data;
225 static cmd_func_t wl_get_btamp_log;
226 #endif
227 static cmd_func_t wl_actframe;
229 static cmd_func_t wl_gpioout;
231 static cmd_func_t wl_nrate, wl_antsel, wl_txcore;
232 static cmd_func_t wl_txcore_pwr_offset;
233 static cmd_func_t wl_txfifo_sz;
234 static cmd_func_t wl_pkteng, wl_pkteng_stats;
236 static cmd_func_t wl_offload_cmpnt;
237 static cmd_func_t wl_hostip, wl_arp_stats, wl_toe_stats;
239 static cmd_func_t wl_lpphy_papdepstbl;
241 int wl_seq_batch_in_client(bool enable);
242 cmd_func_t wl_seq_start;
243 cmd_func_t wl_seq_stop;
245 static cmd_func_t wl_phy_txiqcc, wl_phy_txlocc;
246 static cmd_func_t wl_phytable, wl_phy_pavars, wl_phy_pavars2, wl_phy_povars;
247 static cmd_func_t wl_phy_fem, wl_phy_maxpower, wl_antgain, wl_phy_txpwrindex;
248 static cmd_func_t wl_keep_alive;
249 static cmd_func_t wl_srchmem;
251 static cmd_func_t wl_pkt_filter_add;
252 static cmd_func_t wl_pkt_filter_enable;
253 static cmd_func_t wl_pkt_filter_list;
254 static cmd_func_t wl_pkt_filter_stats;
256 static cmd_func_t wl_ledbh;
258 #ifdef RWL_WIFI
259 /* Function added to support RWL_WIFI Transport */
260 static cmd_func_t wl_wifiserver;
261 #endif
263 static cmd_func_t wl_led_blink_sync;
264 static cmd_func_t wl_cca_get_stats;
265 static cmd_func_t wl_itfr_get_stats;
266 static cmd_func_t wl_rrm_nbr_req;
267 static cmd_func_t wl_wnm_bsstq;
268 static cmd_func_t wl_chanim_acs_record;
270 #ifdef WLP2P
271 static cmd_func_t wl_p2p_state;
272 static cmd_func_t wl_p2p_scan;
273 static cmd_func_t wl_p2p_ifadd;
274 static cmd_func_t wl_p2p_ifdel;
275 static cmd_func_t wl_p2p_ifupd;
276 static cmd_func_t wl_p2p_if;
277 static cmd_func_t wl_p2p_ops;
278 static cmd_func_t wl_p2p_noa;
279 #endif
281 static cmd_func_t wl_rpmt;
282 static cmd_func_t wl_spatial_policy, wl_ratetbl_ppr;
284 static cmd_func_t wl_ie;
286 static void wl_txppr_print(txppr_t *ppr, int cck, int mimo);
287 static void wl_txpwr_array_print(uint8 *pwr, int cck, int mimo);
288 static void wl_txpwr_range_print(uint8 *pwr, int start, int count, const char* label, int *newline);
289 static void wl_txpwr_row_print(uint8 *pwr, int start, int count);
290 static int wl_array_uniform(uint8 *pwr, int start, int count);
291 static int wl_curpower_legacy(void *wl);
292 static void wl_txpwr_array_print_legacy2(uint8 *pwr, int cck, int mimo);
293 static void wl_txpwr_range_print_legacy2(uint8 *pwr, int start, int count, const char* label,
294 int *newline);
295 static int wl_curpower_legacy2(void *wl, cmd_t *cmd);
297 static int wl_parse_rateset(void *wl, wl_rateset_args_t* rs, char **argv);
298 static void wl_print_mcsset(char *mcsset);
300 static void dump_networks(char *buf);
301 static void dump_bss_info(wl_bss_info_t *bi);
302 static void wl_dump_wpa_rsn_ies(uint8* cp, uint len);
303 static void wl_rsn_ie_dump(bcm_tlv_t *ie);
305 int wlu_get(void *wl, int cmd, void *buf, int len);
306 int wlu_set(void *wl, int cmd, void *buf, int len);
308 static void clean_up_cmd_list(void);
309 static int add_one_batched_cmd(int cmd, void *buf, int len);
310 static int _wl_dump_lq(void *wl);
312 /* 802.11i/WPA RSN IE parsing utilities */
313 typedef struct {
314 uint16 version;
315 wpa_suite_mcast_t *mcast;
316 wpa_suite_ucast_t *ucast;
317 wpa_suite_auth_key_mgmt_t *akm;
318 uint8 *capabilities;
319 } rsn_parse_info_t;
321 static int wl_rsn_ie_parse_info(uint8* buf, uint len, rsn_parse_info_t *rsn);
322 static uint wl_rsn_ie_decode_cntrs(uint cntr_field);
324 static int wl_parse_assoc_params(char **argv, wl_assoc_params_t *params);
325 #define wl_parse_reassoc_params(argv, params) wl_parse_assoc_params(argv, \
326 (wl_assoc_params_t *)(params))
328 static int wl_parse_channel_list(char* list_str, uint16* channel_list, int channel_num);
329 static int wl_parse_chanspec_list(char* list_str, chanspec_t *chanspec_list, int chanspec_num);
331 #ifdef EXTENDED_SCAN
332 static int wl_parse_extdchannel_list(char* list_str,
333 chan_scandata_t* channel_list, int channel_num);
334 #endif
336 static uint16 wl_qdbm_to_mw(uint8 qdbm);
337 static uint8 wl_mw_to_qdbm(uint16 mw);
339 static int wl_cfg_option(char **argv, const char *fn_name, int *bsscfg_idx, int *consumed);
340 static int get_oui_bytes(uchar *oui_str, uchar *oui);
341 static int get_ie_data(uchar *data_str, uchar *ie_data, int len);
342 static void wl_printrate(int val);
343 static int rate_string2int(char *s);
344 static char *rate_int2string(char *buf, int val);
346 static int wl_get_scan(void *wl, int opc, char *buf, uint buf_len);
347 static int wl_get_iscan(void *wl, char *buf, uint buf_len);
348 int wlu_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr);
349 int wlu_var_getbuf_sm(void *wl, const char *iovar, void *param, int param_len, void **bufptr);
350 int wlu_var_getbuf_med(void *wl, const char *iovar, void *param, int param_len, void **bufptr);
351 int wlu_var_setbuf(void *wl, const char *iovar, void *param, int param_len);
353 static uint wl_iovar_mkbuf(const char *name, char *data, uint datalen, char *buf, uint buflen,
354 int *perr);
355 static int wlu_iovar_getbuf(void* wl, const char *iovar,
356 void *param, int paramlen, void *bufptr, int buflen);
357 static int wlu_iovar_setbuf(void* wl, const char *iovar,
358 void *param, int paramlen, void *bufptr, int buflen);
359 int wlu_iovar_get(void *wl, const char *iovar, void *outbuf, int len);
360 int wlu_iovar_set(void *wl, const char *iovar, void *param, int paramlen);
361 int wlu_iovar_getint(void *wl, const char *iovar, int *pval);
362 int wlu_iovar_setint(void *wl, const char *iovar, int val);
364 static int wl_bssiovar_mkbuf(const char *iovar, int bssidx, void *param,
365 int paramlen, void *bufptr, int buflen, int *perr);
366 static int wl_bssiovar_setbuf(void* wl, const char *iovar, int bssidx,
367 void *param, int paramlen, void *bufptr, int buflen);
368 static int wl_bssiovar_getbuf(void* wl, const char *iovar, int bssidx,
369 void *param, int paramlen, void *bufptr, int buflen);
370 static int wl_bssiovar_set(void *wl, const char *iovar, int bssidx, void *param, int paramlen);
371 static int wl_bssiovar_get(void *wl, const char *iovar, int bssidx, void *outbuf, int len);
372 static int wl_bssiovar_setint(void *wl, const char *iovar, int bssidx, int val);
373 static int wl_bssiovar_getint(void *wl, const char *iovar, int bssidx, int *pval);
375 static int wl_vndr_ie(void *wl, const char *command, char **argv);
376 static int hexstrtobitvec(const char *cp, uchar *bitvec, int veclen);
377 static void wl_join_pref_print_ie(bcm_tlv_t *ie);
378 static void wl_join_pref_print_akm(uint8* suite);
379 static void wl_join_pref_print_cipher_suite(uint8* suite);
380 static void wl_print_tspec(tspec_arg_t *ts);
381 static void wl_cac_addts_usage(void);
382 static void wl_cac_delts_usage(void);
384 static cmd_func_t wl_txmcsset;
385 static cmd_func_t wl_rxmcsset;
387 static int wl_mimo_stf(void *wl, cmd_t *cmd, char **argv);
389 #ifdef WLEXTLOG
390 static int wl_extlog(void *wl, cmd_t *cmd, char **argv);
391 static int wl_extlog_cfg(void *wl, cmd_t *cmd, char **argv);
392 #endif
394 static int wl_assertlog(void *wl, cmd_t *cmd, char **argv);
395 static char *ver2str(unsigned int vms, unsigned int vls);
396 static int wl_tsf(void *wl, cmd_t *cmd, char **argv);
397 static int wl_dngl_wd(void *wl, cmd_t *cmd, char **argv);
398 static int wl_mfp_config(void *wl, cmd_t *cmd, char **argv);
399 static int wl_mfp_sha256(void *wl, cmd_t *cmd, char **argv);
400 static int wl_mfp_sa_query(void *wl, cmd_t *cmd, char **argv);
401 static int wl_mfp_disassoc(void *wl, cmd_t *cmd, char **argv);
402 static int wl_mfp_deauth(void *wl, cmd_t *cmd, char **argv);
403 static int wl_mfp_assoc(void *wl, cmd_t *cmd, char **argv);
404 static int wl_mfp_auth(void *wl, cmd_t *cmd, char **argv);
405 static int wl_mfp_reassoc(void *wl, cmd_t *cmd, char **argv);
406 static int wl_scb_probe(void *wl, cmd_t *cmd, char **argv);
408 /* some OSes (FC4) have trouble allocating (kmalloc) 128KB worth of memory,
409 * hence keeping WL_DUMP_BUF_LEN below that
411 #if defined(BWL_SMALL_WLU_DUMP_BUF)
412 #define WL_DUMP_BUF_LEN (8 * 1024)
413 #else
414 #define WL_DUMP_BUF_LEN (127 * 1024)
415 #endif
417 #define OUI_STR_SIZE 8 /* OUI string size */
418 #define MAX_OUI_SIZE 3 /* MAX OUI size */
419 #define MAX_BYTE_CHARS 2 /* MAX num chars */
420 #define MAX_DATA_COLS 16 /* MAX data cols */
421 #define DIV_QUO(num, div) ((num)/div) /* Return the quotient of division to avoid floats */
422 #define DIV_REM(num, div) (((num%div) * 100)/div) /* Return the remainder of division */
424 #define RADIO_CORE_SYN (0x0 << 12)
425 #define RADIO_CORE_TX0 (0x2 << 12)
426 #define RADIO_CORE_TX1 (0x3 << 12)
427 #define RADIO_CORE_RX0 (0x6 << 12)
428 #define RADIO_CORE_RX1 (0x7 << 12)
430 #define RADIO_CORE_CR0 (0x0 << 10)
431 #define RADIO_CORE_CR1 (0x1 << 10)
432 #define RADIO_CORE_CR2 (0x2 << 10)
433 #define RADIO_CORE_ALL (0x3 << 10)
435 #define WLC_MAXMCS 32
437 /* dword align allocation */
438 static union {
439 char bufdata[WLC_IOCTL_MAXLEN];
440 uint32 alignme;
441 } bufstruct_wlu;
442 static char *buf = (char*) &bufstruct_wlu.bufdata;
444 /* integer output format, default to signed integer */
445 static uint8 int_fmt;
447 /* The below macros handle endian mis-matches between wl utility and wl driver. */
448 static bool g_swap = FALSE;
449 #define htod32(i) (g_swap?bcmswap32(i):(uint32)(i))
450 #define htod16(i) (g_swap?bcmswap16(i):(uint16)(i))
451 #define dtoh32(i) (g_swap?bcmswap32(i):(uint32)(i))
452 #define dtoh16(i) (g_swap?bcmswap16(i):(uint16)(i))
453 #define htodchanspec(i) (g_swap?htod16(i):i)
454 #define dtohchanspec(i) (g_swap?dtoh16(i):i)
455 #define htodenum(i) (g_swap?((sizeof(i) == 4) ? htod32(i) : ((sizeof(i) == 2) ? htod16(i) : i)):i)
456 #define dtohenum(i) (g_swap?((sizeof(i) == 4) ? dtoh32(i) : ((sizeof(i) == 2) ? htod16(i) : i)):i)
459 * Country names and abbreviations from ISO 3166
461 typedef struct {
462 const char *name; /* Long name */
463 const char *abbrev; /* Abbreviation */
464 } cntry_name_t;
465 cntry_name_t cntry_names[]; /* At end of this file */
467 typedef struct {
468 uint value;
469 const char *string;
470 } dbg_msg_t;
472 typedef struct {
473 uint value;
474 const char *string;
475 } phy_msg_t;
477 #define WL_SCAN_PARAMS_SSID_MAX 10
478 #define SCAN_USAGE "" \
479 "\tDefault to an active scan across all channels for any SSID.\n" \
480 "\tOptional arg: SSIDs, list of [up to 10] SSIDs to scan (comma or space separated).\n" \
481 "\tOptions:\n" \
482 "\t-s S, --ssid=S\t\tSSIDs to scan\n" \
483 "\t-t ST, --scan_type=ST\t[active|passive|prohibit] scan type\n" \
484 "\t--bss_type=BT\t\t[bss/infra|ibss/adhoc] bss type to scan\n" \
485 "\t-b MAC, --bssid=MAC\tparticular BSSID MAC address to scan, xx:xx:xx:xx:xx:xx\n" \
486 "\t-n N, --nprobes=N\tnumber of probes per scanned channel\n" \
487 "\t-a N, --active=N\tdwell time per channel for active scanning\n" \
488 "\t-p N, --passive=N\tdwell time per channel for passive scanning\n" \
489 "\t-h N, --home=N\t\tdwell time for the home channel between channel scans\n" \
490 "\t-c L, --channels=L\tcomma or space separated list of channels to scan" \
492 /* command batching data structure */
493 typedef struct wl_seq_cmd_pkt {
494 struct wl_seq_cmd_pkt *next;
495 wl_seq_cmd_ioctl_t cmd_header;
496 char * data; /* user buffer */
497 } wl_seq_cmd_pkt_t;
499 typedef struct wl_cmd_list {
500 wl_seq_cmd_pkt_t *head;
501 wl_seq_cmd_pkt_t *tail;
502 } wl_cmd_list_t;
504 static wl_cmd_list_t cmd_list;
505 static int cmd_pkt_list_num;
506 static bool cmd_batching_mode;
507 /* the default behavior is batching in driver,
508 * to indicate client batching, users should specify --interactive and --clientbatch
510 static bool batch_in_client;
512 /* If the new command needs to be part of 'wc.exe' tool used for WMM,
513 * be sure to modify wc_cmds[] array as well
515 * If you add a command, please update wlu_cmd.c cmd2cat to categorize the command.
517 cmd_t wl_cmds[] = {
518 { "ver", wl_version, -1, -1,
519 "get version information" },
520 { "cmds", wl_list, -1, -1,
521 "generate a short list of available commands"},
522 { "up", wl_void, -1, WLC_UP,
523 "reinitialize and mark adapter up (operational)" },
524 { "down", wl_void, -1, WLC_DOWN,
525 "reset and mark adapter down (disabled)" },
526 { "out", wl_out, -1, WLC_OUT,
527 "mark adapter down but do not reset hardware(disabled)\n"
528 "\tOn dualband cards, cards must be bandlocked before use."},
529 { "clk", wl_int, WLC_GET_CLK, WLC_SET_CLK,
530 "set board clock state. return error for set_clk attempt if the driver is not down\n"
531 "\t0: clock off\n"
532 "\t1: clock on" },
533 { "restart", wl_void, -1, WLC_RESTART,
534 "Restart driver. Driver must already be down."},
535 { "reboot", wl_void, -1, WLC_REBOOT,
536 "Reboot platform"},
537 { "radio", wl_radio, WLC_GET_RADIO, WLC_SET_RADIO,
538 "Set the radio on or off.\n"
539 "\t\"on\" or \"off\"" },
540 { "dump", wlu_dump, WLC_GET_VAR, -1,
541 "Give suboption \"list\" to list various suboptions" },
542 { "srclear", wlu_srwrite, -1, WLC_SET_SROM,
543 "Clears first 'len' bytes of the srom, len in decimal or hex\n"
544 "\tUsage: srclear <len>" },
545 { "srdump", wlu_srdump, WLC_GET_SROM, -1,
546 "print contents of SPROM to stdout" },
547 { "srwrite", wlu_srwrite, -1, WLC_SET_SROM,
548 "Write the srom: srwrite byteoffset value" },
549 { "srcrc", wlu_srwrite, WLC_GET_SROM, -1,
550 "Get the CRC for input binary file" },
551 { "ciswrite", wlu_ciswrite, -1, WLC_SET_VAR,
552 "Write specified <file> to the SDIO CIS source (either SROM or OTP)"},
553 { "cisupdate", wlu_cisupdate, -1, WLC_SET_VAR,
554 "Write a hex byte stream to specified byte offset to the CIS source (either SROM or OTP)\n"
555 "--preview option allows you to review the update without committing it\n"
556 "\t<byte offset> <hex byte stream> [--preview]" },
557 { "cisdump", wlu_cisdump, WLC_GET_VAR, -1,
558 "Display the content of the SDIO CIS source\n"
559 "\t-b <file> -- also write raw bytes to <file>\n"
560 "\t<len> -- optional count of bytes to display (must be even)"},
561 { "cis_source", wl_varint, WLC_GET_VAR, -1,
562 "Display which source is used for the SDIO CIS"},
563 { "cisconvert", wlu_srvar, -1, -1,
564 "Print CIS tuple for given name=value pair" },
565 { "rdvar", wlu_srvar, WLC_GET_SROM, -1,
566 "Read a named variable to the srom" },
567 { "wrvar", wlu_srvar, WLC_GET_SROM, WLC_SET_SROM,
568 "Write a named variable to the srom" },
569 { "nvram_source", wl_nvsource, WLC_GET_VAR, -1,
570 "Display which source is used for nvram"},
571 { "nvram_dump", wl_nvdump, WLC_NVRAM_DUMP, -1,
572 "print nvram variables to stdout" },
573 { "nvset", wl_nvset, -1, WLC_NVRAM_SET,
574 "set an nvram variable\n"
575 "\tname=value (no spaces around \'=\')" },
576 { "nvget", wl_nvget, WLC_NVRAM_GET, -1,
577 "get the value of an nvram variable" },
578 { "nvram_get", wl_nvget, WLC_NVRAM_GET, -1,
579 "get the value of an nvram variable" },
580 { "revinfo", wl_revinfo, WLC_GET_REVINFO, -1,
581 "get hardware revision information" },
582 { "customvar1", wl_var_getinthex, -1, -1,
583 "print the value of customvar1 in hex format" },
584 { "msglevel", wl_msglevel, WLC_GET_VAR, WLC_SET_VAR,
585 "set driver console debugging message bitvector\n"
586 "\ttype \'wl msglevel ?\' for values" },
587 { "phymsglevel", wl_phymsglevel, WLC_GET_VAR, WLC_SET_VAR,
588 "set phy debugging message bitvector\n"
589 "\ttype \'wl phymsglevel ?\' for values" },
590 { "PM", wl_int, WLC_GET_PM, WLC_SET_PM,
591 "set driver power management mode:\n"
592 "\t0: CAM (constantly awake)\n"
593 "\t1: PS (power-save)\n"
594 "\t2: FAST PS mode" },
595 { "wake", wl_int, WLC_GET_WAKE, WLC_SET_WAKE,
596 "set driver power-save mode sleep state:\n"
597 "\t0: core-managed\n"
598 "\t1: awake" },
599 { "promisc", wl_int, WLC_GET_PROMISC, WLC_SET_PROMISC,
600 "set promiscuous mode ethernet address reception\n"
601 "\t0 - disable\n"
602 "\t1 - enable" },
603 { "monitor", wl_int, WLC_GET_MONITOR, WLC_SET_MONITOR,
604 "set monitor mode\n"
605 "\t0 - disable\n"
606 "\t1 - enable active monitor mode (interface still operates)" },
607 { "frag", wl_print_deprecate, -1, -1, "Deprecated. Use fragthresh." },
608 { "rts", wl_print_deprecate, -1, -1, "Deprecated. Use rtsthresh." },
609 { "cwmin", wl_int, WLC_GET_CWMIN, WLC_SET_CWMIN,
610 "Set the cwmin. (integer [1, 255])" },
611 { "cwmax", wl_int, WLC_GET_CWMAX, WLC_SET_CWMAX,
612 "Set the cwmax. (integer [256, 2047])" },
613 { "srl", wl_int, WLC_GET_SRL, WLC_SET_SRL,
614 "Set the short retry limit. (integer [1, 255])" },
615 { "lrl", wl_int, WLC_GET_LRL, WLC_SET_LRL,
616 "Set the long retry limit. (integer [1, 255])" },
617 { "rate", wl_rate_mrate, WLC_GET_RATE, -1,
618 "force a fixed rate:\n"
619 "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n"
620 "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n"
621 "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n"
622 "\t-1 (default) means automatically determine the best rate" },
623 { "mrate", wl_rate_mrate, -1, -1, /* Deprecated. Use "bg_mrate" or "a_mrate" */
624 "force a fixed multicast rate:\n"
625 "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n"
626 "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n"
627 "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n"
628 "\t-1 (default) means automatically determine the best rate" },
629 { "a_rate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR,
630 "force a fixed rate for the A PHY:\n"
631 "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n"
632 "\t-1 (default) means automatically determine the best rate" },
633 { "a_mrate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR,
634 "force a fixed multicast rate for the A PHY:\n"
635 "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n"
636 "\t-1 (default) means automatically determine the best rate" },
637 { "bg_rate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR,
638 "force a fixed rate for the B/G PHY:\n"
639 "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n"
640 "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n"
641 "\t-1 (default) means automatically determine the best rate" },
642 { "bg_mrate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR,
643 "force a fixed multicast rate for the B/G PHY:\n"
644 "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n"
645 "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n"
646 "\t-1 (default) means automatically determine the best rate" },
647 { "infra", wl_int, WLC_GET_INFRA, WLC_SET_INFRA,
648 "Set Infrastructure mode: 0 (IBSS) or 1 (Infra BSS)" },
649 { "ap", wl_int, WLC_GET_AP, WLC_SET_AP,
650 "Set AP mode: 0 (STA) or 1 (AP)" },
651 { "bssid", wl_bssid, WLC_GET_BSSID, -1,
652 "Get the BSSID value, error if STA and not associated"},
653 { "bssmax", wl_bss_max, WLC_GET_VAR, -1,
654 "get number of BSSes " },
655 { "channel", wl_channel, WLC_GET_CHANNEL, WLC_SET_CHANNEL,
656 "Set the channel:\n"
657 "\tvalid channels for 802.11b/g (2.4GHz band) are 1 through 14\n"
658 "\tvalid channels for 802.11a (5 GHz band) are:\n"
659 "\t\t36, 40, 44, 48, 52, 56, 60, 64,\n"
660 "\t\t100, 104, 108, 112, 116,120, 124, 128, 132, 136, 140,\n"
661 "\t\t149, 153, 157, 161,\n"
662 "\t\t184, 188, 192, 196, 200, 204, 208, 212, 216"},
663 { "cur_mcsset", wl_cur_mcsset, WLC_GET_VAR, -1,
664 "Get the current mcs set"
666 { "chanspecs", wl_dump_chanspecs, WLC_GET_VAR, -1,
667 "Get all the valid chanspecs (default: all within current locale):\n"
668 "\t-b band (5(a) or 2(b/g))\n"
669 "\t-w bandwidth, 10,20 or 40\n"
670 "\t[-c country_abbrev]"
672 { "chanspec", wl_chanspec, WLC_GET_VAR, WLC_SET_VAR,
673 "Set <channel>[a,b][n][u,l]\n"
674 "\tchannel number (0-224)\n"
675 "\tband a=5G, b=2G, default to 2G if channel <= 14\n"
676 "\tbandwidth, n=10, none for 20 & 40\n"
677 "\tctl sideband, l=lower, u=upper\n"
678 "OR Set channel with legacy format:\n"
679 "\t-c channel number (0-224)\n"
680 "\t-b band (5(a) or 2(b/g))\n"
681 "\t-w bandwidth, 10,20 or 40\n"
682 "\t-s ctl sideband, -1=lower, 0=none, 1=upper"},
683 { "dfs_channel_forced", wl_chanspec, WLC_GET_VAR, WLC_SET_VAR,
684 "Set <channel>[a,b][n][u,l]\n"
685 "\tchannel number (0-224)\n"
686 "\tband a=5G, b=2G, default to 2G if channel <= 14\n"
687 "\tbandwidth, n=10, non for 20 & 40\n"
688 "\tctl sideband, l=lower, u=upper"},
689 { "tssi", wl_tssi, WLC_GET_TSSI, -1,
690 "Get the tssi value from radio" },
691 { "txpwr", wl_txpwr, -1, -1, /* Deprecated. Use "txpwr1" */
692 "Set tx power in milliwatts. Range [1, 84]." },
693 { "txpwr1", wl_txpwr1, WLC_GET_VAR, WLC_SET_VAR,
694 "Set tx power in in various units. Choose one of (default: dbm): \n"
695 "\t-d dbm units\n"
696 "\t-q quarter dbm units\n"
697 "\t-m milliwatt units\n"
698 "Can be combined with:\n"
699 "\t-o turn on override to disable regulatory and other limitations\n"
700 "Use wl txpwr -1 to restore defaults"},
701 { "txpathpwr", wl_int, WLC_GET_TX_PATH_PWR, WLC_SET_TX_PATH_PWR,
702 "Turn the tx path power on or off on 2050 radios" },
703 { "txpwrlimit", wl_get_txpwr_limit, WLC_CURRENT_PWR, -1,
704 "Return current tx power limit" },
705 { "powerindex", wl_int, WLC_GET_PWRIDX, WLC_SET_PWRIDX,
706 "Set the transmit power for A band(0-63).\n"
707 "\t-1 - default value" },
708 { "atten", wl_atten, WLC_GET_ATTEN, WLC_SET_ATTEN,
709 "Set the transmit attenuation for B band. Args: bb radio txctl1.\n"
710 "\tauto to revert to automatic control\n"
711 "\tmanual to supspend automatic control" },
712 { "phyreg", wl_reg, WLC_GET_PHYREG, WLC_SET_PHYREG,
713 "Get/Set a phy register:\n"
714 "\toffset [ value ] [ band ]" },
715 { "radioreg", wl_reg, WLC_GET_RADIOREG, WLC_SET_RADIOREG,
716 "Get/Set a radio register:\n"
717 "\toffset [ value ] [ band/core ]\n"
718 "HTPHY:\n"
719 "\tGet a radio register: wl radioreg [ offset ] [ cr0/cr1/cr2 ]\n"
720 "\tSet a radio register: wl radioreg [ offset ] [ value ] [ cr0/cr1/cr2/all ]\n"},
721 { "ucflags", wl_reg, WLC_GET_UCFLAGS, WLC_SET_UCFLAGS,
722 "Get/Set ucode flags 1, 2, 3(16 bits each)\n"
723 "\toffset [ value ] [ band ]" },
724 { "shmem", wl_reg, WLC_GET_SHMEM, WLC_SET_SHMEM,
725 "Get/Set a shared memory location:\n"
726 "\toffset [ value ] [band ]" },
727 { "macreg", wl_macreg, WLC_R_REG, WLC_W_REG,
728 "Get/Set any mac registers(include IHR and SB):\n"
729 "\tmacreg offset size[2,4] [ value ] [ band ]" },
730 { "ucantdiv", wl_int, WLC_GET_UCANTDIV, WLC_SET_UCANTDIV,
731 "Enable/disable ucode antenna diversity (1/0 or on/off)" },
732 { "gpioout", wl_gpioout, -1, -1,
733 "Set any GPIO pins to any value. Use with caution as GPIOs would be "
734 "assigned to chipcommon\n"
735 "\tUsage: gpiomask gpioval"},
736 { "devpath", wl_devpath, WLC_GET_VAR, -1,
737 "print device path" },
739 { "jtagureg", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR, "g/set JTAG user registers"},
740 { "coma", wl_coma, -1, WLC_SET_VAR, "Put the router in a catatonic state"},
741 { "pllreset", wl_var_void, -1, WLC_SET_VAR, "set the pll to reset value\n"
742 "\tUsage: wl pllreset"},
743 { "pcieserdesreg", wlu_reg3args, WLC_GET_VAR, WLC_SET_VAR,
744 "g/set SERDES registers: dev offset [val]"},
745 { "ampdu_activate_test", wl_ampdu_activate_test, -1, WLC_SET_VAR,
746 "actiate" },
747 /* nphy parameter setting is internal only for now */
748 { "ampdu_tid", wl_ampdu_tid, WLC_GET_VAR, WLC_SET_VAR,
749 "enable/disable per-tid ampdu; usage: wl ampdu_tid <tid> [0/1]" },
750 { "ampdu_retry_limit_tid", wl_ampdu_retry_limit_tid, WLC_GET_VAR, WLC_SET_VAR,
751 "Set per-tid ampdu retry limit; usage: wl ampdu_retry_limit_tid <tid> [0~31]" },
752 { "ampdu_rr_retry_limit_tid", wl_ampdu_rr_retry_limit_tid, WLC_GET_VAR, WLC_SET_VAR,
753 "Set per-tid ampdu regular rate retry limit; usage: "
754 "wl ampdu_rr_retry_limit_tid <tid> [0~31]" },
755 { "ampdu_send_addba", wl_ampdu_send_addba, WLC_GET_VAR, WLC_SET_VAR,
756 "send addba to specified ea-tid; usage: wl ampdu_send_addba <tid> <ea>" },
757 { "ampdu_send_delba", wl_ampdu_send_delba, WLC_GET_VAR, WLC_SET_VAR,
758 "send delba to specified ea-tid; usage: wl ampdu_send_delba <tid> <ea>" },
759 { "ampdu_clear_dump", wl_var_void, -1, WLC_SET_VAR,
760 "clear ampdu counters"},
761 { "dpt_deny", wl_dpt_deny, WLC_GET_VAR, WLC_SET_VAR,
762 "adds/removes ea to dpt deny list\n"
763 "\tusage: wl dpt_deny <add,remove> <ea>" },
764 { "dpt_endpoint", wl_dpt_endpoint, WLC_GET_VAR, WLC_SET_VAR,
765 "creates/updates/deletes dpt endpoint for ea\n"
766 "\tusage: wl dpt_endpoint <create, update, delete> <ea>" },
767 { "dpt_pmk", wl_dpt_pmk, -1, WLC_SET_VAR,
768 "sets DPT pre-shared key" },
769 { "dpt_fname", wl_dpt_fname, WLC_GET_VAR, WLC_SET_VAR,
770 "sets/gets DPT friendly name" },
771 { "dpt_list", wl_dpt_list, WLC_GET_VAR, -1,
772 "gets status of all dpt peers" },
773 #ifdef WLBTAMP
774 { "HCI_cmd", wl_HCI_cmd, WLC_GET_VAR, WLC_SET_VAR,
775 "carries HCI commands to the driver\n"
776 "\tusage: wl HCI_cmd <command> <args>" },
777 { "HCI_ACL_data", wl_HCI_ACL_data, WLC_GET_VAR, WLC_SET_VAR,
778 "carries HCI ACL data packet to the driver\n"
779 "\tusage: wl HCI_ACL_data <logical link handle> <data>" },
780 { "btamp_statelog", wl_get_btamp_log, WLC_GET_VAR, WLC_SET_VAR,
781 "Return state transistion log of BTAMP\n" },
782 #endif /* WLBTAMP */
783 { "actframe", wl_actframe, -1, WLC_SET_VAR,
784 "Send a Vendor specific Action frame to a channel\n"
785 "\tusage: wl actframe <Dest Mac Addr> <data> channel dwell-time <BSSID>" },
786 { "antdiv", wl_int, WLC_GET_ANTDIV, WLC_SET_ANTDIV,
787 "Set antenna diversity for rx\n"
788 "\t0 - force use of antenna 0\n"
789 "\t1 - force use of antenna 1\n"
790 "\t3 - automatic selection of antenna diversity" },
791 { "txant", wl_int, WLC_GET_TXANT, WLC_SET_TXANT,
792 "Set the transmit antenna\n"
793 "\t0 - force use of antenna 0\n"
794 "\t1 - force use of antenna 1\n"
795 "\t3 - use the RX antenna selection that was in force during\n"
796 "\t the most recently received good PLCP header" },
797 { "plcphdr", wl_plcphdr, WLC_GET_PLCPHDR, WLC_SET_PLCPHDR,
798 "Set the plcp header.\n"
799 "\t\"long\" or \"auto\" or \"debug\"" },
800 { "phytype", wl_int, WLC_GET_PHYTYPE, -1,
801 "Get phy type" },
802 { "rateparam", wl_rateparam, -1, WLC_SET_RATE_PARAMS,
803 "set driver rate selection tunables\n"
804 "\targ 1: tunable id\n"
805 "\targ 2: tunable value" },
806 { "wepstatus", wl_wepstatus, -1, -1, /* Deprecated. Use "wsec" */
807 "Set or Get WEP status\n"
808 "\twepstatus [on|off]" },
809 { "primary_key", wl_primary_key, WLC_GET_KEY_PRIMARY, WLC_SET_KEY_PRIMARY,
810 "Set or get index of primary key" },
811 { "addwep", wl_addwep, -1, WLC_SET_KEY,
812 "Set an encryption key. The key must be 5, 13 or 16 bytes long, or\n"
813 "\t10, 26, 32, or 64 hex digits long. The encryption algorithm is\n"
814 "\tautomatically selected based on the key size. keytype is accepted\n"
815 "\tonly when key length is 16 bytes/32 hex digits and specifies\n"
816 "\twhether AES-OCB or AES-CCM encryption is used. Default is ccm.\n"
817 "\tWAPI is selected if key len is 32 and arguments contain wapi.\n"
818 "\taddwep <keyindex> <keydata> [ocb | ccm | wapi] [notx] [xx:xx:xx:xx:xx:xx]" },
819 { "rmwep", wl_rmwep, -1, WLC_SET_KEY,
820 "Remove the encryption key at the specified key index." },
821 { "keys", wl_keys, WLC_GET_KEY, -1,
822 "Prints a list of the current WEP keys" },
823 { "tsc", wl_tsc, WLC_GET_KEY_SEQ, -1,
824 "Print Tx Sequence Couter for key at specified key index." },
825 { "wsec_test", wl_wsec_test, -1, WLC_SET_WSEC_TEST,
826 "Generate wsec errors\n"
827 "\twsec_test <test_type> <keyindex|xx:xx:xx:xx:xx:xx>\n"
828 "\ttype \'wl wsec_test ?\' for test_types" },
829 { "tkip_countermeasures", wl_int, -1, WLC_TKIP_COUNTERMEASURES,
830 "Enable or disable TKIP countermeasures (TKIP-enabled AP only)\n"
831 "\t0 - disable\n"
832 "\t1 - enable" },
833 { "wsec_restrict", wl_bsscfg_int, WLC_GET_WEP_RESTRICT, WLC_SET_WEP_RESTRICT,
834 "Drop unencrypted packets if WSEC is enabled\n"
835 "\t0 - disable\n"
836 "\t1 - enable" },
837 { "eap", wl_int, WLC_GET_EAP_RESTRICT, WLC_SET_EAP_RESTRICT,
838 "restrict traffic to 802.1X packets until 802.1X authorization succeeds\n"
839 "\t0 - disable\n"
840 "\t1 - enable" },
841 { "cur_etheraddr", wl_iov_mac, -1, -1,
842 "Get/set the current hw address" },
843 { "perm_etheraddr", wl_iov_mac, -1, -1,
844 "Get the permanent address from NVRAM" },
845 { "authorize", wl_mac, -1, WLC_SCB_AUTHORIZE,
846 "restrict traffic to 802.1X packets until 802.1X authorization succeeds" },
847 { "deauthorize", wl_mac, -1, WLC_SCB_DEAUTHORIZE,
848 "do not restrict traffic to 802.1X packets until 802.1X authorization succeeds" },
849 { "deauthenticate", wl_deauth_rc, -1, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
850 "deauthenticate a STA from the AP with optional reason code (AP ONLY)" },
851 { "wsec", wl_wsec, WLC_GET_WSEC, WLC_SET_WSEC,
852 "wireless security bit vector\n"
853 "\t1 - WEP enabled\n"
854 "\t2 - TKIP enabled\n"
855 "\t4 - AES enabled\n"
856 "\t8 - WSEC in software\n"
857 "\t0x80 - FIPS enabled\n"
858 "\t0x100 - WAPI enabled" },
859 { "auth", wl_bsscfg_int, WLC_GET_AUTH, WLC_SET_AUTH,
860 "set/get 802.11 authentication type. 0 = OpenSystem, 1= SharedKey, 2=Open/Shared" },
861 { "wpa_auth", wl_wpa_auth, WLC_GET_WPA_AUTH, WLC_SET_WPA_AUTH,
862 "Bitvector of WPA authorization modes:\n"
863 "\t1 WPA-NONE\n"
864 "\t2 WPA-802.1X/WPA-Professional\n"
865 "\t4 WPA-PSK/WPA-Personal\n"
866 "\t64 WPA2-802.1X/WPA2-Professional\n"
867 "\t128 WPA2-PSK/WPA2-Personal\n"
868 "\t0 disable WPA"
870 { "wpa_cap", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
871 "set/get 802.11i RSN capabilities" },
872 { "set_pmk", wl_set_pmk, -1, WLC_SET_WSEC_PMK,
873 "Set passphrase for PMK in driver-resident supplicant." },
874 { "scan", wl_scan, -1, WLC_SCAN,
875 "Initiate a scan.\n" SCAN_USAGE
877 { "iscan_s", wl_iscan, -1, WLC_SET_VAR,
878 "Initiate an incremental scan.\n" SCAN_USAGE
880 { "iscan_c", wl_iscan, -1, WLC_SET_VAR,
881 "Continue an incremental scan.\n" SCAN_USAGE
883 { "scancache_clear", wl_var_void, -1, WLC_SET_VAR,
884 "clear the scan cache"},
885 { "escan", wl_escan, -1, WLC_SET_VAR,
886 "Start an escan.\n" SCAN_USAGE
888 { "escanabort", wl_escan, -1, WLC_SET_VAR,
889 "Abort an escan.\n" SCAN_USAGE
891 #ifdef EXTENDED_SCAN
892 { "extdscan", wl_extdscan, -1, WLC_SET_VAR,
893 "Initiate an extended scan.\n"
894 "\tDefault to an active scan across all channels for any SSID.\n"
895 "\tOptional args: list of SSIDs to scan.\n"
896 "\tOptions:\n"
897 "\t-s S1 S2 S3, --ssid=S1 S2 S3\t\tSSIDs to scan, comma or space separated\n"
898 "\t-x x, --split_scan=ST\t[split_scan] scan type\n"
899 "\t-t ST, --scan_type=ST\t[background:0/forcedbackground:1/foreground:2] scan type\n"
900 "\t-n N, --nprobes=N\tnumber of probes per scanned channel, per SSID\n"
901 "\t-c L, --channels=L\tcomma or space separated list of channels to scan"},
902 #endif
903 { "passive", wl_int, WLC_GET_PASSIVE_SCAN, WLC_SET_PASSIVE_SCAN,
904 "Puts scan engine into passive mode" },
905 { "regulatory", wl_int, WLC_GET_REGULATORY, WLC_SET_REGULATORY,
906 "Get/Set regulatory domain mode (802.11d). Driver must be down." },
907 { "spect", wl_spect, WLC_GET_SPECT_MANAGMENT, WLC_SET_SPECT_MANAGMENT,
908 "Get/Set 802.11h Spectrum Management mode.\n"
909 "\t0 - Off\n"
910 "\t1 - Loose interpretation of 11h spec - may join non-11h APs\n"
911 "\t2 - Strict interpretation of 11h spec - may not join non-11h APs\n"
912 "\t3 - Disable 11h and enable 11d\n"
913 "\t4 - Loose interpretation of 11h+d spec - may join non-11h APs"
915 {"scanabort", wl_var_void, -1, WLC_SET_VAR,
916 "Abort a scan."},
917 { "scanresults", wl_dump_networks, WLC_SCAN_RESULTS, -1,
918 "Return results from last scan." },
919 { "iscanresults", wl_dump_networks, WLC_GET_VAR, -1,
920 "Return results from last iscan. Specify a buflen (max 8188)\n"
921 "\tto artificially limit the size of the results buffer.\n"
922 "\tiscanresults [buflen]"},
923 { "assoc", wl_status, -1, -1,
924 "Print information about current network association.\n"
925 "\t(also known as \"status\")" },
926 { "status", wl_status, -1, -1,
927 "Print information about current network association.\n"
928 "\t(also known as \"assoc\")" },
929 { "disassoc", wl_void, -1, WLC_DISASSOC,
930 "Disassociate from the current BSS/IBSS." },
931 { "chanlist", wl_print_deprecate, WLC_GET_VALID_CHANNELS, -1,
932 "Deprecated. Use channels." },
933 { "channels", wl_dump_chanlist, WLC_GET_VALID_CHANNELS, -1,
934 "Return valid channels for the current settings." },
935 { "channels_in_country", wl_channels_in_country, WLC_GET_CHANNELS_IN_COUNTRY, -1,
936 "Return valid channels for the country specified.\n"
937 "\tArg 1 is the country abbreviation\n"
938 "\tArg 2 is the band(a or b)"},
939 { "curpower", wl_get_current_power, WLC_CURRENT_PWR, -1,
940 "Return current tx power settings.\n"
941 "\t-q (quiet): estimated power only." },
942 { "curppr", wl_get_current_txppr, WLC_GET_VAR, -1,
943 "Return current tx power per rate offset.\n"},
944 { "txinstpwr", wl_get_instant_power, WLC_GET_VAR, -1,
945 "Return tx power based on instant TSSI "},
946 { "scansuppress", wl_int, WLC_GET_SCANSUPPRESS, WLC_SET_SCANSUPPRESS,
947 "Suppress all scans for testing.\n"
948 "\t0 - allow scans\n"
949 "\t1 - suppress scans" },
950 { "evm", wl_evm, -1, WLC_EVM,
951 "Start an EVM test on the given channel, or stop EVM test.\n"
952 "\tArg 1 is channel number 1-14, or \"off\" or 0 to stop the test.\n"
953 "\tArg 2 is optional rate (1, 2, 5.5 or 11)"},
954 { "rateset", wl_rateset, WLC_GET_RATESET, WLC_SET_RATESET,
955 "Returns or sets the supported and basic rateset, (b) indicates basic\n"
956 "\tWith no args, returns the rateset. Args are\n"
957 "\trateset \"default\" | \"all\" | <arbitrary rateset> -m <arbitrary mcsset>\n"
958 "\t\tdefault - driver defaults\n"
959 "\t\tall - all rates are basic rates\n"
960 "\t\tarbitrary rateset - list of rates\n"
961 "\t\tarbitrary mcsset - list of mcs rates octets, each bit representing\n"
962 "\t\t\t\tcorresponding mcs\n"
963 "\tList of rates are in Mbps and each rate is optionally followed\n"
964 "\tby \"(b)\" or \"b\" for a Basic rate. Example: 1(b) 2b 5.5 11\n"
965 "\tAt least one rate must be Basic for a legal rateset."},
966 { "roam_trigger", wl_band_elm, WLC_GET_ROAM_TRIGGER, WLC_SET_ROAM_TRIGGER,
967 "Get or Set the roam trigger RSSI threshold:\n"
968 "\tGet: roam_trigger [a|b]\n"
969 "\tSet: roam_trigger <integer> [a|b|all]\n"
970 "\tinteger - 0: default\n"
971 "\t 1: optimize bandwidth\n"
972 "\t 2: optimize distance\n"
973 "\t [-1, -99]: dBm trigger value"},
974 { "roam_delta", wl_band_elm, WLC_GET_ROAM_DELTA, WLC_SET_ROAM_DELTA,
975 "Set the roam candidate qualification delta. roam_delta [integer [, a/b]]" },
976 { "roam_scan_period", wl_int, WLC_GET_ROAM_SCAN_PERIOD, WLC_SET_ROAM_SCAN_PERIOD,
977 "Set the roam candidate qualification delta. (integer)" },
978 { "suprates", wl_sup_rateset, WLC_GET_SUP_RATESET_OVERRIDE, WLC_SET_SUP_RATESET_OVERRIDE,
979 "Returns or sets the 11g override for the supported rateset\n"
980 "\tWith no args, returns the rateset. Args are a list of rates,\n"
981 "\tor 0 or -1 to specify an empty rateset to clear the override.\n"
982 "\tList of rates are in Mbps, example: 1 2 5.5 11"},
983 { "scan_channel_time", wl_int, WLC_GET_SCAN_CHANNEL_TIME, WLC_SET_SCAN_CHANNEL_TIME,
984 "Get/Set scan channel time"},
985 { "scan_unassoc_time", wl_int, WLC_GET_SCAN_UNASSOC_TIME, WLC_SET_SCAN_UNASSOC_TIME,
986 "Get/Set unassociated scan channel dwell time"},
987 { "scan_home_time", wl_int, WLC_GET_SCAN_HOME_TIME, WLC_SET_SCAN_HOME_TIME,
988 "Get/Set scan home channel dwell time"},
989 { "scan_passive_time", wl_int, WLC_GET_SCAN_PASSIVE_TIME, WLC_SET_SCAN_PASSIVE_TIME,
990 "Get/Set passive scan channel dwell time"},
991 { "scan_nprobes", wl_int, WLC_GET_SCAN_NPROBES, WLC_SET_SCAN_NPROBES,
992 "Get/Set scan parameter for number of probes to use per channel scanned"},
993 { "prb_resp_timeout", wl_int, WLC_GET_PRB_RESP_TIMEOUT, WLC_SET_PRB_RESP_TIMEOUT,
994 "Get/Set probe response timeout"},
995 { "channel_qa", wl_int, WLC_GET_CHANNEL_QA, -1,
996 "Get last channel quality measurment"},
997 { "channel_qa_start", wl_void, -1, WLC_START_CHANNEL_QA,
998 "Start a channel quality measurment"},
999 { "country", wl_country, WLC_GET_COUNTRY, WLC_SET_COUNTRY,
1000 "Select Country Code for driver operational region\n"
1001 "\tFor simple country setting: wl country <country>\n"
1002 "\tWhere <country> is either a long name or country code from ISO 3166; "
1003 "for example \"Germany\" or \"DE\"\n"
1004 "\n\tFor a specific built-in country definition: "
1005 "wl country <built-in> [<advertised-country>]\n"
1006 "\tWhere <built-in> is a country country code followed by '/' and "
1007 "regulatory revision number.\n"
1008 "\tFor example, \"US/3\".\n"
1009 "\tAnd where <advertised-country> is either a long name or country code from ISO 3166.\n"
1010 "\tIf <advertised-country> is omitted, it will be the same as the built-in country code.\n"
1011 "\n\tUse 'wl country list [band(a or b)]' for the list of supported countries"},
1012 { "country_ie_override", wl_country_ie_override, WLC_GET_VAR, WLC_SET_VAR,
1013 "To set/get country ie"},
1014 { "autocountry_default", wl_varstr, WLC_GET_VAR, WLC_SET_VAR,
1015 "Select Country Code for use with Auto Contry Discovery"},
1016 { "join", wl_join, -1, -1,
1017 "Join a specified network SSID.\n"
1018 "\tUsage: join <ssid> [key <0-3>:xxxxx] [imode bss|ibss] "
1019 "[amode open|shared|openshared|wpa|wpapsk|wpa2|wpa2psk|wpanone] [options]\n"
1020 "\tOptions:\n"
1021 "\t-b MAC, --bssid=MAC \tBSSID (xx:xx:xx:xx:xx:xx) to scan and join\n"
1022 "\t-c CL, --chanspecs=CL \tchanspecs (comma or space separated list)"},
1023 { "ssid", wl_ssid, WLC_GET_SSID, WLC_SET_SSID,
1024 "Set or get a configuration's SSID.\n"
1025 "\twl ssid [-C num]|[--cfg=num] [<ssid>]\n"
1026 "\tIf the configuration index 'num' is not given, configuraion #0 is assumed and\n"
1027 "\tsetting will initiate an assoication attempt if in infrastructure mode,\n"
1028 "\tor join/creation of an IBSS if in IBSS mode,\n"
1029 "\tor creation of a BSS if in AP mode."},
1030 { "mac", wl_maclist, WLC_GET_MACLIST, WLC_SET_MACLIST,
1031 "Set or get the list of source MAC address matches.\n"
1032 "\twl mac xx:xx:xx:xx:xx:xx [xx:xx:xx:xx:xx:xx ...]\n"
1033 "\tTo Clear the list: wl mac none" },
1034 { "macmode", wl_int, WLC_GET_MACMODE, WLC_SET_MACMODE,
1035 "Set the mode of the MAC list.\n"
1036 "\t0 - Disable MAC address matching.\n"
1037 "\t1 - Deny association to stations on the MAC list.\n"
1038 "\t2 - Allow association to stations on the MAC list."},
1039 { "wds", wl_maclist, WLC_GET_WDSLIST, WLC_SET_WDSLIST,
1040 "Set or get the list of WDS member MAC addresses.\n"
1041 "\tSet using a space separated list of MAC addresses.\n"
1042 "\twl wds xx:xx:xx:xx:xx:xx [xx:xx:xx:xx:xx:xx ...]" },
1043 { "lazywds", wl_int, WLC_GET_LAZYWDS, WLC_SET_LAZYWDS,
1044 "Set or get \"lazy\" WDS mode (dynamically grant WDS membership to anyone)."},
1045 { "noise", wl_int, WLC_GET_PHY_NOISE, -1,
1046 "Get noise (moving average) right after tx in dBm" },
1047 { "fqacurcy", wl_int, -1, WLC_FREQ_ACCURACY,
1048 "Manufacturing test: set frequency accuracy mode.\n"
1049 "\tfreqacuracy syntax is: fqacurcy <channel>\n"
1050 "\tArg is channel number 1-14, or 0 to stop the test." },
1051 { "crsuprs", wl_int, -1, WLC_CARRIER_SUPPRESS,
1052 "Manufacturing test: set carrier suppression mode.\n"
1053 "\tcarriersuprs syntax is: crsuprs <channel>\n"
1054 "\tArg is channel number 1-14, or 0 to stop the test." },
1055 { "longtrain", wl_int, -1, WLC_LONGTRAIN,
1056 "Manufacturing test: set longtraining mode.\n"
1057 "\tlongtrain syntax is: longtrain <channel>\n"
1058 "\tArg is A band channel number or 0 to stop the test." },
1059 { "band", wl_band, WLC_GET_BAND, WLC_SET_BAND,
1060 "Returns or sets the current band\n"
1061 "\tauto - auto switch between available bands (default)\n"
1062 "\ta - force use of 802.11a band\n"
1063 "\tb - force use of 802.11b band" },
1064 { "bands", wl_bandlist, WLC_GET_BANDLIST, -1,
1065 "Return the list of available 802.11 bands" },
1066 { "phylist", wl_phylist, WLC_GET_PHYLIST, -1,
1067 "Return the list of available phytypes" },
1068 { "shortslot", wl_int, WLC_GET_SHORTSLOT, -1,
1069 "Get current 11g Short Slot Timing mode. (0=long, 1=short)" },
1070 { "shortslot_override", wl_int, WLC_GET_SHORTSLOT_OVERRIDE, WLC_SET_SHORTSLOT_OVERRIDE,
1071 "Get/Set 11g Short Slot Timing mode override. (-1=auto, 0=long, 1=short)" },
1072 { "shortslot_restrict", wl_int, WLC_GET_SHORTSLOT_RESTRICT, WLC_SET_SHORTSLOT_RESTRICT,
1073 "Get/Set AP Restriction on associations for 11g Short Slot Timing capable STAs.\n"
1074 "\t0 - Do not restrict association based on ShortSlot capability\n"
1075 "\t1 - Restrict association to STAs with ShortSlot capability" },
1076 { "ignore_bcns", wl_int, WLC_GET_IGNORE_BCNS, WLC_SET_IGNORE_BCNS,
1077 "AP only (G mode): Check for beacons without NONERP element"
1078 "(0=Examine beacons, 1=Ignore beacons)" },
1079 { "pktcnt", wl_get_pktcnt, WLC_GET_PKTCNTS, -1,
1080 "Get the summary of good and bad packets." },
1081 { "upgrade", wl_upgrade, -1, WLC_UPGRADE,
1082 "Upgrade the firmware on an embedded device" },
1083 { "gmode", wl_gmode, WLC_GET_GMODE, WLC_SET_GMODE,
1084 "Set the 54g Mode (LegacyB|Auto||GOnly|BDeferred|Performance|LRS)" },
1085 { "gmode_protection", wl_int, WLC_GET_GMODE_PROTECTION, -1,
1086 "Get G protection mode. (0=disabled, 1=enabled)" },
1087 { "gmode_protection_control", wl_int, WLC_GET_PROTECTION_CONTROL,
1088 WLC_SET_PROTECTION_CONTROL,
1089 "Get/Set 11g protection mode control alg."
1090 "(0=always off, 1=monitor local association, 2=monitor overlapping BSS)" },
1091 { "gmode_protection_override", wl_int, WLC_GET_GMODE_PROTECTION_OVERRIDE,
1092 WLC_SET_GMODE_PROTECTION_OVERRIDE,
1093 "Get/Set 11g protection mode override. (-1=auto, 0=disable, 1=enable)" },
1094 { "protection_control", wl_int, WLC_GET_PROTECTION_CONTROL,
1095 WLC_SET_PROTECTION_CONTROL,
1096 "Get/Set protection mode control alg."
1097 "(0=always off, 1=monitor local association, 2=monitor overlapping BSS)" },
1098 { "legacy_erp", wl_int, WLC_GET_LEGACY_ERP, WLC_SET_LEGACY_ERP,
1099 "Get/Set 11g legacy ERP inclusion (0=disable, 1=enable)" },
1100 { "scb_timeout", wl_int, WLC_GET_SCB_TIMEOUT, WLC_SET_SCB_TIMEOUT,
1101 "AP only: inactivity timeout value for authenticated stas" },
1102 { "assoclist", wl_maclist, WLC_GET_ASSOCLIST, -1,
1103 "AP only: Get the list of associated MAC addresses."},
1104 { "isup", wl_int, WLC_GET_UP, -1,
1105 "Get driver operational state (0=down, 1=up)"},
1106 { "rssi", wl_rssi, WLC_GET_RSSI, -1,
1107 "Get the current RSSI val, for an AP you must specify the mac addr of the STA" },
1108 { "rssi_event", wl_rssi_event, WLC_GET_VAR, WLC_SET_VAR,
1109 "Set parameters associated with RSSI event notification\n"
1110 "\tusage: wl rssi_event <rate_limit> <rssi_levels>\n"
1111 "\trate_limit: Number of events posted to application will be limited"
1112 " to 1 per this rate limit. Set to 0 to disable rate limit.\n"
1113 "\trssi_levels: Variable number of RSSI levels (maximum 8) "
1114 " in increasing order (e.g. -85 -70 -60). An event will be posted"
1115 " each time the RSSI of received beacons/packets crosses a level."},
1116 { "fasttimer", wl_print_deprecate, -1, -1,
1117 "Deprecated. Use fast_timer."},
1118 { "slowtimer", wl_print_deprecate, -1, -1,
1119 "Deprecated. Use slow_timer."},
1120 { "glacialtimer", wl_print_deprecate, -1, -1,
1121 "Deprecated. Use glacial_timer."},
1122 { "radar", wl_int, WLC_GET_RADAR, WLC_SET_RADAR,
1123 "Enable/Disable radar"},
1124 { "radarargs", wl_radar_args, WLC_GET_VAR, WLC_SET_VAR,
1125 "Get/Set Radar parameters in \n"
1126 "\torder as version, npulses, ncontig, min_pw, max_pw, thresh0,\n"
1127 "\tthresh1, blank, fmdemodcfg, npulses_lp, min_pw_lp, max_pw_lp,\n"
1128 "\tmin_fm_lp, max_span_lp, min_deltat, max_deltat,\n"
1129 "\tautocorr, st_level_time, t2_min, fra_pulse_err, npulses_fra,\n"
1130 "\tnpulses_stg2, npulses_stg3, percal_mask, quant, \n"
1131 "\tmin_burst_intv_lp, max_burst_intv_lp, nskip_rst_lp, max_pw_tol, feature_mask"},
1132 { "radarargs40", wl_radar_args, WLC_GET_VAR, WLC_SET_VAR,
1133 "Get/Set Radar parameters for 40Mhz channel in \n"
1134 "\torder as version, npulses, ncontig, min_pw, max_pw, thresh0,\n"
1135 "\tthresh1, blank, fmdemodcfg, npulses_lp, min_pw_lp, max_pw_lp,\n"
1136 "\tmin_fm_lp, max_span_lp, min_deltat, max_deltat,\n"
1137 "\tautocorr, st_level_time, t2_min, fra_pulse_err, npulses_fra,\n"
1138 "\tnpulses_stg2, npulses_stg3, percal_mask, quant, \n"
1139 "\tmin_burst_intv_lp, max_burst_intv_lp, nskip_rst_lp, max_pw_tol, feature_mask"},
1140 { "radarthrs", wl_radar_thrs, -1, WLC_SET_VAR,
1141 "Set Radar threshold for both 20 & 40MHz BW:\n"
1142 "\torder as thresh0_20_lo, thresh1_20_lo, thresh0_40_lo, thresh1_40_lo\n"
1143 "\tthresh0_20_hi, thresh1_20_hi, thresh0_40_hi, thresh1_40_hi"},
1144 { "dfs_status", wl_dfs_status, WLC_GET_VAR, -1,
1145 "Get dfs status"},
1146 { "interference", wl_interfere, WLC_GET_INTERFERENCE_MODE, WLC_SET_INTERFERENCE_MODE,
1147 "Get/Set interference mitigation mode. Choices are:\n"
1148 "\t0 = none\n"
1149 "\t1 = non wlan\n"
1150 "\t2 = wlan manual\n"
1151 "\t3 = wlan automatic\n"
1152 "\t4 = wlan automatic with noise reduction"},
1153 { "interference_override", wl_interfere_override,
1154 WLC_GET_INTERFERENCE_OVERRIDE_MODE,
1155 WLC_SET_INTERFERENCE_OVERRIDE_MODE,
1156 "Get/Set interference mitigation override. Choices are:\n"
1157 "\t0 = no interference mitigation\n"
1158 "\t1 = non wlan\n"
1159 "\t2 = wlan manual\n"
1160 "\t3 = wlan automatic\n"
1161 "\t4 = wlan automatic with noise reduction\n"
1162 "\t-1 = remove override, override disabled"},
1163 { "frameburst", wl_int, WLC_GET_FAKEFRAG, WLC_SET_FAKEFRAG,
1164 "Disable/Enable frameburst mode" },
1165 { "pwr_percent", wl_int, WLC_GET_PWROUT_PERCENTAGE, WLC_SET_PWROUT_PERCENTAGE,
1166 "Get/Set power output percentage"},
1167 { "toe", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1168 "Enable/Disable tcpip offload feature"},
1169 { "toe_ol", wl_offload_cmpnt, WLC_GET_VAR, WLC_SET_VAR,
1170 "Get/Set tcpip offload components"},
1171 { "toe_stats", wl_toe_stats, WLC_GET_VAR, -1,
1172 "Display checksum offload statistics"},
1173 { "toe_stats_clear", wl_var_void, -1, WLC_SET_VAR,
1174 "Clear checksum offload statistics"},
1175 { "arpoe", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1176 "Enable/Disable arp agent offload feature"},
1177 { "arp_ol", wl_offload_cmpnt, WLC_GET_VAR, WLC_SET_VAR,
1178 "Get/Set arp offload components"},
1179 { "arp_peerage", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1180 "Get/Set age of the arp entry in minutes"},
1181 { "arp_table_clear", wl_var_void, -1, WLC_SET_VAR,
1182 "Clear arp cache"},
1183 { "arp_hostip", wl_hostip, WLC_GET_VAR, WLC_SET_VAR,
1184 "Add a host-ip address or display them"},
1185 { "arp_hostip_clear", wl_var_void, -1, WLC_SET_VAR,
1186 "Clear all host-ip addresses"},
1187 { "arp_stats", wl_arp_stats, WLC_GET_VAR, -1,
1188 "Display ARP offload statistics"},
1189 { "arp_stats_clear", wl_var_void, -1, WLC_SET_VAR,
1190 "Clear ARP offload statistics"},
1191 { "wet", wl_int, WLC_GET_WET, WLC_SET_WET,
1192 "Get/Set wireless ethernet bridging mode"},
1193 { "bi", wl_int, WLC_GET_BCNPRD, WLC_SET_BCNPRD,
1194 "Get/Set the beacon period (bi=beacon interval)"},
1195 { "dtim", wl_int, WLC_GET_DTIMPRD, WLC_SET_DTIMPRD,
1196 "Get/Set DTIM"},
1197 { "wds_remote_mac", wl_mac, WLC_WDS_GET_REMOTE_HWADDR, -1,
1198 "Get WDS link remote endpoint's MAC address"},
1199 { "wds_wpa_role_old", wl_wds_wpa_role_old, WLC_WDS_GET_WPA_SUP, -1,
1200 "Get WDS link local endpoint's WPA role (old)"},
1201 { "wds_wpa_role", wl_wds_wpa_role, WLC_GET_VAR, WLC_SET_VAR,
1202 "Get/Set WDS link local endpoint's WPA role"},
1203 { "authe_sta_list", wl_maclist_1, WLC_GET_VAR, -1,
1204 "Get authenticated sta mac address list"},
1205 { "autho_sta_list", wl_maclist_1, WLC_GET_VAR, -1,
1206 "Get authorized sta mac address list"},
1207 { "measure_req", wl_measure_req, -1, WLC_MEASURE_REQUEST,
1208 "Send an 802.11h measurement request.\n"
1209 "\tUsage: wl measure_req <type> <target MAC addr>\n"
1210 "\tMeasurement types are: TPC, Basic, CCA, RPI\n"
1211 "\tTarget MAC addr format is xx:xx:xx:xx:xx:xx"},
1212 { "quiet", wl_send_quiet, -1, WLC_SEND_QUIET,
1213 "Send an 802.11h quiet command.\n"
1214 "\tUsage: wl quiet <TBTTs until start>, <duration (in TUs)>, <offset (in TUs)>"},
1215 { "csa", wl_send_csa, -1, WLC_SET_VAR,
1216 "Send an 802.11h channel switch anouncement with chanspec:\n"
1217 "\t<mode> <count> <channel>[a,b][n][u,l]\n"
1218 "\tmode (0 or 1)\n"
1219 "\tcount (0-254)\n"
1220 "\tchannel number (0-224)\n"
1221 "\tband a=5G, b=2G\n"
1222 "\tbandwidth n=10, non for 20 & 40\n"
1223 "\tctl sideband, l=lower, u=upper, default no ctl sideband"},
1224 { "constraint", wl_int, -1, WLC_SEND_PWR_CONSTRAINT,
1225 "Send an 802.11h Power Constraint IE\n"
1226 "\tUsage: wl constraint 1-255 db"},
1227 { "rm_req", wl_rm_request, -1, WLC_SET_VAR,
1228 "Request a radio measurement of type basic, cca, or rpi\n"
1229 "\tspecify a series of measurement types each followed by options.\n"
1230 "\texample: wl rm_req cca -c 1 -d 50 cca -c 6 cca -c 11\n"
1231 "\tOptions:\n"
1232 "\t-t n numeric token id for measurement set or measurement\n"
1233 "\t-c n channel\n"
1234 "\t-d n duration in TUs (1024 us)\n"
1235 "\t-p parallel flag, measurement starts at the same time as previous\n"
1236 "\n"
1237 "\tEach measurement specified uses the same channel and duration as the\n"
1238 "\tprevious unless a new channel or duration is specified."},
1239 { "rm_rep", wl_rm_report, WLC_GET_VAR, -1,
1240 "Get current radio measurement report"},
1241 { "join_pref", wl_join_pref, WLC_GET_VAR, WLC_SET_VAR,
1242 "Set/Get join target preferences."},
1243 { "assoc_pref", wl_assoc_pref, WLC_GET_ASSOC_PREFER, WLC_SET_ASSOC_PREFER,
1244 "Set/Get association preference.\n"
1245 "Usage: wl assoc_pref [auto|a|b|g]"},
1246 { "wme", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1247 "Set WME (Wireless Multimedia Extensions) mode (0=off, 1=on, -1=auto)"},
1248 { "wme_ac", wl_wme_ac_req, WLC_GET_VAR, WLC_SET_VAR,
1249 "wl wme_ac ap|sta [be|bk|vi|vo [ecwmax|ecwmin|txop|aifsn|acm <value>] ...]"},
1250 { "wme_apsd", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1251 "Set APSD (Automatic Power Save Delivery) mode on AP (0=off, 1=on)" },
1252 { "wme_apsd_sta", wl_wme_apsd_sta, WLC_GET_VAR, WLC_SET_VAR,
1253 "Set APSD parameters on STA. Driver must be down.\n"
1254 "Usage: wl wme_apsd_sta <max_sp_len> <be> <bk> <vi> <vo>\n"
1255 " <max_sp_len>: number of frames per USP: 0 (all), 2, 4, or 6\n"
1256 " <xx>: value 0 to disable, 1 to enable U-APSD per AC" },
1257 { "wme_dp", wl_wme_dp, WLC_GET_VAR, WLC_SET_VAR,
1258 "Set AC queue discard policy.\n"
1259 "Usage: wl wme_dp <be> <bk> <vi> <vo>\n"
1260 " <xx>: value 0 for newest-first, 1 for oldest-first" },
1261 { "wme_counters", wl_wme_counters, WLC_GET_VAR, -1,
1262 "print WMM stats" },
1263 { "wme_clear_counters", wl_var_void, -1, WLC_SET_VAR,
1264 "clear WMM counters"},
1265 { "wme_tx_params", wme_tx_params, -1, -1,
1266 "wl wme_tx_params [be|bk|vi|vo [short|sfb|long|lfb|max_rate <value>] ...]"},
1267 { "wme_maxbw_params", wme_maxbw_params, WLC_GET_VAR, WLC_SET_VAR,
1268 "wl wme_maxbw_params [be|bk|vi|vo <value> ....]"},
1269 { "lifetime", wl_lifetime, WLC_GET_VAR, WLC_SET_VAR,
1270 "Set Lifetime parameter (milliseconds) for each ac.\n"
1271 "wl lifetime be|bk|vi|vo [<value>]"},
1272 { "reinit", wl_void, -1, WLC_INIT,
1273 "Reinitialize device"},
1274 { "sta_info", wl_sta_info, WLC_GET_VAR, -1,
1275 "wl sta_info <xx:xx:xx:xx:xx:xx>"},
1276 { "cap", wl_var_getandprintstr, WLC_GET_VAR, -1, "driver capabilities"},
1277 { "malloc_dump", wl_print_deprecate, -1, -1, "Deprecated. Folded under 'wl dump malloc"},
1278 { "chan_info", wl_chan_info, WLC_GET_VAR, -1, "channel info"},
1279 { "add_ie", wl_add_ie, -1, WLC_SET_VAR,
1280 "Add a vendor proprietary IE to 802.11 management packets\n"
1281 "Usage: wl add_ie <pktflag> length OUI hexdata\n"
1282 "<pktflag>: Bit 0 - Beacons\n"
1283 " Bit 1 - Probe Rsp\n"
1284 " Bit 2 - Assoc/Reassoc Rsp\n"
1285 " Bit 3 - Auth Rsp\n"
1286 " Bit 4 - Probe Req\n"
1287 " Bit 5 - Assoc/Reassoc Req\n"
1288 "Example: wl add_ie 3 10 00:90:4C 0101050c121a03\n"
1289 " to add this IE to beacons and probe responses" },
1290 { "del_ie", wl_del_ie, -1, WLC_SET_VAR,
1291 "Delete a vendor proprietary IE from 802.11 management packets\n"
1292 "Usage: wl del_ie <pktflag> length OUI hexdata\n"
1293 "<pktflag>: Bit 0 - Beacons\n"
1294 " Bit 1 - Probe Rsp\n"
1295 " Bit 2 - Assoc/Reassoc Rsp\n"
1296 " Bit 3 - Auth Rsp\n"
1297 " Bit 4 - Probe Req\n"
1298 " Bit 5 - Assoc/Reassoc Req\n"
1299 "Example: wl del_ie 3 10 00:90:4C 0101050c121a03" },
1300 { "list_ie", wl_list_ie, WLC_GET_VAR, -1,
1301 "Dump the list of vendor proprietary IEs" },
1302 { "rand", wl_rand, WLC_GET_VAR, -1,
1303 "Get a 2-byte Random Number from the MAC's PRNG\n"
1304 "Usage: wl rand"},
1305 { "otpw", wl_otpw, -1, WLC_OTPW,
1306 "Write an srom image to on-chip otp\n"
1307 "Usage: wl otpw file"},
1308 { "nvotpw", wl_otpw, -1, WLC_NVOTPW,
1309 "Write nvram to on-chip otp\n"
1310 "Usage: wl nvotpw file"},
1311 { "bcmerrorstr", wl_var_getandprintstr, WLC_GET_VAR, -1, "errorstring"},
1312 { "freqtrack", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1313 "Set Frequency Tracking Mode (0=Auto, 1=On, 2=OFF)"},
1314 { "eventing", wl_bitvec128, WLC_GET_VAR, WLC_SET_VAR,
1315 "set/get 128-bit hex filter bitmask for MAC event reporting up to application layer"},
1316 { "event_msgs", wl_bitvec128, WLC_GET_VAR, WLC_SET_VAR,
1317 "set/get 128-bit hex filter bitmask for MAC event reporting via packet indications"},
1318 { "counters", wl_counters, WLC_GET_VAR, -1,
1319 "Return driver counter values" },
1320 { "delta_stats_interval", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1321 "set/get the delta statistics interval in seconds (0 to disable)"},
1322 { "delta_stats", wl_delta_stats, WLC_GET_VAR, -1,
1323 "get the delta statistics for the last interval" },
1324 { "assoc_info", wl_assoc_info, WLC_GET_VAR, -1,
1325 "Returns the assoc req and resp information [STA only]" },
1326 { "autochannel", wl_auto_channel_sel, WLC_GET_CHANNEL_SEL, WLC_START_CHANNEL_SEL,
1327 "auto channel selection: \n"
1328 "\t1 to issue a channel scanning;\n"
1329 "\t2 to set chanspec based on the channel scan result;\n"
1330 "\twithout argument to only show the chanspec selected; \n"
1331 "\tssid must set to null before this process, RF must be up"},
1332 { "csscantimer", wl_int, WLC_GET_CS_SCAN_TIMER, WLC_SET_CS_SCAN_TIMER,
1333 "auto channel scan timer in minutes (0 to disable)" },
1334 { "closed", wl_int, WLC_GET_CLOSED, WLC_SET_CLOSED,
1335 "hides the network from active scans, 0 or 1.\n"
1336 "\t0 is open, 1 is hide" },
1337 { "pmkid_info", wl_pmkid_info, WLC_GET_VAR, WLC_SET_VAR,
1338 "Returns the pmkid table" },
1339 { "abminrate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR,
1340 "get/set afterburner minimum rate threshold" },
1341 { "bss", wl_bsscfg_enable, WLC_GET_VAR, WLC_SET_VAR,
1342 "set/get BSS enabled status: up/down"},
1343 { "closednet", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
1344 "set/get BSS closed network attribute"},
1345 { "ap_isolate", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
1346 "set/get AP isolation"},
1347 { "eap_restrict", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR,
1348 "set/get EAP restriction"},
1349 { "diag", wl_diag, WLC_GET_VAR, -1,
1350 "diag testindex(1-interrupt, 2-loopback, 3-memory, 4-led);"
1351 " precede by 'wl down' and follow by 'wl up'" },
1352 { "reset_d11cnts", wl_var_void, -1, WLC_SET_VAR,
1353 "reset 802.11 MIB counters"},
1354 { "staname", wl_varstr, WLC_GET_VAR, WLC_SET_VAR,
1355 "get/set station name: \n"
1356 "\tMaximum name length is 15 bytes"},
1357 { "apname", wl_varstr, WLC_GET_VAR, -1,
1358 "get AP name"},
1359 { "otpdump", wl_var_setintandprintstr, WLC_GET_VAR, -1,
1360 "Dump raw otp"},
1361 { "otpstat", wl_var_setintandprintstr, WLC_GET_VAR, -1,
1362 "Dump OTP status"},
1363 { "nrate", wl_nrate, WLC_GET_VAR, WLC_SET_VAR,
1364 "-r legacy rate (CCK, OFDM)"
1365 "-m mcs index"
1366 "-s stf mode (0=SISO,1=CDD,2=STBC(not supported),3=SDM)"
1367 "-w Override mcs only to support STA's with/without STBC capability"},
1368 { "mimo_txbw", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1369 "get/set mimo txbw (2=20Mhz(lower), 3=20Mhz upper, 4=40Mhz, 5=40Mhz dup<mcs32 only)"},
1370 { "cac_addts", wl_cac, -1, WLC_SET_VAR,
1371 "add TSPEC, error if STA is not associated or WME is not enabled\n"
1372 "\targ: TSPEC parameter input list"},
1373 { "cac_delts", wl_cac, -1, WLC_SET_VAR,
1374 "delete TSPEC, error if STA is not associated or WME is not enabled\n"
1375 "\targ: TSINFO for the target tspec"},
1376 { "cac_delts_ea", wl_cac_delts_ea, -1, WLC_SET_VAR,
1377 "delete TSPEC, error if STA is not associated or WME is not enabled\n"
1378 "\targ1: Desired TSINFO for the target tspec\n"
1379 "\targ2: Desired MAC address"},
1380 { "cac_tslist", wl_tslist, WLC_GET_VAR, -1,
1381 "Get the list of TSINFO in driver\n"
1382 "\teg. 'wl cac_tslist' get a list of TSINFO"},
1383 { "cac_tslist_ea", wl_tslist_ea, WLC_GET_VAR, -1,
1384 "Get the list of TSINFO for given STA in driver\n"
1385 "\teg. 'wl cac_tslist_ea ea' get a list of TSINFO"},
1386 { "cac_tspec", wl_tspec, WLC_GET_VAR, -1,
1387 "Get specific TSPEC with matching TSINFO\n"
1388 "\teg. 'wl cac_tspec 0xaa 0xbb 0xcc' where 0xaa 0xbb & 0xcc are TSINFO octets"},
1389 { "cac_tspec_ea", wl_tspec_ea, WLC_GET_VAR, -1,
1390 "Get specific TSPEC for given STA with matching TSINFO\n"
1391 "\teg. 'wl cac_tspec 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx'\n"
1392 "\t where 0xaa 0xbb & 0xcc are TSINFO octets and xx is mac address"},
1395 { "phy_txpwrindex", wl_phy_txpwrindex, WLC_GET_VAR, WLC_SET_VAR,
1396 "usage: (set) phy_txpwrindex core0_idx core1_idx core2_idx core3_idx"
1397 " (get) phy_txpwrindex, return format: core0_idx core1_idx core2_idx core3_idx"
1398 "Set/Get txpwrindex"
1400 { "phy_test_tssi", wl_test_tssi, WLC_GET_VAR, -1,
1401 "wl phy_test_tssi val"},
1402 { "phy_test_tssi_offs", wl_test_tssi_offs, WLC_GET_VAR, -1,
1403 "wl phy_test_tssi_offs val"},
1404 { "phy_rssiant", wl_phy_rssiant, WLC_GET_VAR, -1,
1405 "wl phy_rssiant antindex(0-3)"},
1406 { "phy_rssi_ant", wl_phy_rssi_ant, WLC_GET_VAR, WLC_SET_VAR,
1407 "Get RSSI per antenna (only gives RSSI of current antenna for SISO PHY)"},
1408 { "lpphy_papdepstbl", wl_lpphy_papdepstbl, -1, WLC_GET_VAR,
1409 "print papd eps table; Usage: wl lpphy_papdepstbl"
1411 { "rifs", wl_rifs, WLC_GET_VAR, WLC_SET_VAR,
1412 "set/get the rifs status; usage: wl rifs <1/0> (On/Off)"
1414 { "rifs_advert", wl_rifs_advert, WLC_GET_VAR, WLC_SET_VAR,
1415 "set/get the rifs mode advertisement status; usage: wl rifs_advert <-1/0> (Auto/Off)"
1417 { "phy_rxiqest", wl_rxiq, WLC_GET_VAR, -1,
1418 "Get phy RX IQ noise in dBm:\n"
1419 "\t-s # of samples (2^n)\n"
1420 "\t-a antenna select, 0,1 or 3\n"
1421 "\t-r resolution select, 0 (coarse) or 1 (fine)\n"
1422 "\t-f lpf hpc override select, 0 (hpc unchanged) or 1 (overridden to lowest value)\n"
1423 "\t-g gain-correction select, 0 (disable) or 1 (enable)"
1425 { "phy_txiqcc", wl_phy_txiqcc, WLC_GET_VAR, WLC_SET_VAR,
1426 "usage: phy_txiqcc [a b]\n"
1427 "Set/get the iqcc a, b values"
1429 { "phy_txlocc", wl_phy_txlocc, WLC_GET_VAR, WLC_SET_VAR,
1430 "usage: phy_txlocc [di dq ei eq fi fq]\n"
1431 "Set/get locc di dq ei eq fi fq values"
1433 { "phytable", wl_phytable, WLC_GET_VAR, WLC_SET_VAR,
1434 "usage: wl phytable table_id offset width_of_table_element [table_element]\n"
1435 "Set/get table element of a table with the given ID at the given offset\n"
1436 "Note that table width supplied should be 8 or 16 or 32\n"
1437 "table ID, table offset can not be negative"
1439 { "pavars", wl_phy_pavars, WLC_GET_VAR, WLC_SET_VAR,
1440 "Set/get temp PA parameters\n"
1441 "usage: wl down\n"
1442 " wl pavars pa2gw0a0=0x1 pa2gw1a0=0x2 pa2gw2a0=0x3 ... \n"
1443 " wl pavars\n"
1444 " wl up\n"
1445 " override the PA parameters after driver attach(srom read), before diver up\n"
1446 " These override values will be propogated to HW when driver goes up\n"
1447 " PA parameters in one band range (2g, 5gl, 5g, 5gh) must all present if\n"
1448 " one of them is specified in the command, otherwise it will be filled with 0"
1450 { "pavars2", wl_phy_pavars2, WLC_GET_VAR, WLC_SET_VAR,
1451 "Set/get temp PA parameters. Extended cmd of pavars\n"
1452 "usage: wl down\n"
1453 " wl pavars2 pa2gw0a0=0x1 pa2gw1a0=0x2 pa2gw2a0=0x3 ... \n"
1454 " wl pavars2\n"
1455 " wl up\n"
1456 " override the PA parameters after driver attach(srom read), before diver up\n"
1457 " These override values will be propogated to HW when driver goes up\n"
1458 " PA parameters in one band range (2g, 5gl, 5g, 5gh) must all present if\n"
1459 " one of them is specified in the command, otherwise it will be filled with 0"
1461 { "povars", wl_phy_povars, WLC_GET_VAR, WLC_SET_VAR,
1462 "Set/get temp power offset\n"
1463 "usage: wl down\n"
1464 " wl povars cck2gpo=0x1 ofdm2gpo=0x2 mcs2gpo=0x3 ... \n"
1465 " wl povars\n"
1466 " wl up\n"
1467 " override the power offset after driver attach(srom read), before diver up\n"
1468 " These override values will be propogated to HW when driver goes up\n"
1469 " power offsets in one band range (2g, 5gl, 5g, 5gh) must all present if\n"
1470 " one of them is specified in the command, otherwise it will be filled with 0"
1471 " cck(2g only), ofdm, and mcs(0-7) for NPHY are supported "
1473 { "fem", wl_phy_fem, WLC_GET_VAR, WLC_SET_VAR,
1474 "Set temp fem2g/5g value\n"
1475 "usage: wl fem (tssipos2g=0x1 extpagain2g=0x2 pdetrange2g=0x1 triso2g=0x1 antswctl2g=0)\n"
1476 " (tssipos5g=0x1 extpagain5g=0x2 pdetrange5g=0x1 triso5g=0x1 antswctl5g=0)"
1478 { "antgain", wl_antgain, WLC_GET_VAR, WLC_SET_VAR,
1479 "Set temp ag0/1 value\n"
1480 "usage: wl antgain ag0=0x1 ag1=0x2"
1482 { "maxpower", wl_phy_maxpower, WLC_GET_VAR, WLC_SET_VAR,
1483 "Set temp maxp2g(5g)a0(a1) value\n"
1484 "usage: wl maxpower maxp2ga0=0x1 maxp2ga1=0x2 maxp5ga0=0xff maxp5ga1=0xff\n"
1485 " maxp5gla0=0x3 maxp5gla1=0x4 maxp5gha0=0x5 maxp5gha1=0x6"
1488 { "phy_antsel", wl_antsel, WLC_GET_VAR, -1,
1489 "get/set antenna configuration \n"
1490 "\tset: -1(AUTO), 0xAB(fixed antenna selection)\n"
1491 "\t\twhere A and B is the antenna numbers used for RF chain 1 and 0 respectively\n"
1492 "\tquery: <utx>[AUTO] <urx>[AUTO] <dtx>[AUTO] <drx>[AUTO]\n"
1493 "\t\twhere utx = TX unicast antenna configuration\n"
1494 "\t\t\turx = RX unicast antenna configuration\n"
1495 "\t\t\tdtx = TX default (non-unicast) antenna configuration\n"
1496 "\t\t\tdrx = RX default (non-unicast) antenna configuration\n"
1498 { "txcore", wl_txcore, WLC_GET_VAR, WLC_SET_VAR,
1499 "Usage: wl txcore -k <CCK core mask> -o <OFDM core mask> -s <1..4> -c <core bitmap>\n"
1500 "\t-k CCK core mask\n"
1501 "\t-o OFDM core mask\n"
1502 "\t-s # of space-time-streams\n"
1503 "\t-c active core (bitmask) to be used when transmitting frames\n"
1505 { "txcore_override", wl_txcore, WLC_GET_VAR, -1,
1506 "Usage: wl txcore_override\n"
1507 "\tget the user override of txcore\n"
1509 { "txchain_pwr_offset", wl_txcore_pwr_offset, WLC_GET_VAR, WLC_SET_VAR,
1510 "Usage: wl txchain_pwr_offset [qdBm offsets]\n"
1511 "\tGet/Set the current offsets for each core in qdBm (quarter dBm)\n"
1513 { "sample_collect", wl_sample_collect, WLC_PHY_SAMPLE_COLLECT, -1,
1514 "Optional parameters HTPHY/(NPHY with NREV >= 7) are:\n"
1515 "\t-f File name to dump the sample buffer (default \"sample_collect.dat\")\n"
1516 "\t-t Trigger condition (default now)\n"
1517 "\t\t now, good_fcs, bad_fcs, bad_plcp, crs, crs_glitch, crs_deassert\n"
1518 "\t-b PreTrigger duration in us (default 10)\n"
1519 "\t-a PostTrigger duration in us (default 10) \n"
1520 "\t-m Sample collect mode (default 1) \n"
1521 "\t\t HTPHY: 0=adc, 1..3=adc+rssi, 4=gpio\n"
1522 "\t\t NPHY: 1=Dual-Core adc[9:2], 2=Core0 adc[9:0], 3=Core1 adc[9:0], gpio=gpio\n"
1523 "\t-g GPIO mux select (default 0)\n"
1524 "\t\t use only for gpio mode\n"
1525 "\t-d Downsample enable (default 0)\n"
1526 "\t\t use only for HTPHY\n"
1527 "\t-e BeDeaf enable (default 0)\n"
1528 "\t-i Timeout in units of 10us (default 1000)\n"
1529 "Optional parameters (NPHY with NREV < 7) are:\n"
1530 "\t-f File name to dump the sample buffer (binary format, default \"sample_collect.dat\")\n"
1531 "\t-u Sample collect duration in us (default 60)\n"
1532 "\t-c Cores to do sample collect, only if BW=40MHz (default both)\n"
1533 "For (NREV < 7), the NPHY buffer returned has the format:\n"
1534 "\tIn 20MHz [(uint16)num_bytes, <I(core0), Q(core0), I(core1), Q(core1)>]\n"
1535 "\tIn 40MHz [(uint16)num_bytes(core0), <I(core0), Q(core0)>,\n"
1536 "\t\t(uint16)num_bytes(core1), <I(core1), Q(core1)>]"},
1537 { "txfifo_sz", wl_txfifo_sz, WLC_GET_VAR, WLC_SET_VAR,
1538 "set/get the txfifo size; usage: wl txfifo_sz <fifonum> <size_in_bytes>" },
1539 #ifdef WLPFN
1540 { "pfnset", wl_pfn_set, -1, -1,
1541 "Configures preferred network off load parameter\n"
1542 "\tpfnset syntax is: pfnset [scanfrq xxxxx(30 sec)] [netimeout xxxx(60 sec)]"
1543 "[rssi_delta xxxx(30 dBm)] [sort (listorder)|rssi] [bkgscan (0)|1] [autoswitch (0)|1]"
1544 "[immediate 0|(1)] [autoconnect (0)|1]"},
1545 { "pfnadd", wl_pfn_add, -1, -1,
1546 "Adding preferred network to monitor and connect\n"
1547 "\tpfnadd syntax is: pfnadd <SSID> [key xxxxx] [imode (bss)|ibss]"
1548 "[amode (open)|shared] [wpa_auth (wpadisabled)|wpapsk|wpa2psk|wpanone]"
1549 "[wsec WEP|TKIP|AES|TKIPAES]"},
1550 { "pfn", wl_pfn, -1, -1,
1551 "Enable/disable preferred network off load monitoring\n"
1552 "\tpfn syntax is: pfn 0|1"},
1553 { "pfnclear", wl_var_void, -1, WLC_SET_VAR,
1554 "Clear the preferred network list\n"
1555 "\tpfn syntax is: pfnclear"},
1556 #if defined(linux)
1557 { "pfneventchk", wl_pfn_event_check, -1, -1,
1558 "Listen and prints the preferred network off load event from dongle\n"
1559 "\tpfneventchk syntax is: pfneventchk [(eth1)ifname]"},
1560 { "escan_event_check", wl_escan_event_check, -1, -1,
1561 "Listen and prints the escan events from the dongle\n"
1562 "\tescan_event_check syntax is: escan_event_check ifname flag\n"
1563 "\tflag 1 = sync_id info, 2 = bss info, 4 = state + bss info [default], "
1564 "8 = TLV check for IEs"},
1565 { "escanresults", wl_escanresults, -1, WLC_SET_VAR,
1566 "Start escan and display results.\n" SCAN_USAGE
1568 #endif /* linux */
1569 { "event_filter", wl_event_filter, -1, -1,
1570 "Set/get event filter\n"
1571 "\tevent_filter syntax is: event_filter [value]"},
1572 #endif /* WLPFN */
1573 {"rate_histo", wl_rate_histo, -1, WLC_GET_VAR,
1574 "Get rate hostrogram"
1576 { "pkteng_start", wl_pkteng, -1, WLC_SET_VAR,
1577 "start packet engine tx usage: wl pkteng_start <xx:xx:xx:xx:xx:xx>"
1578 " <tx|txwithack> [(async)|sync] [ipg] [len] [nframes] [src]\n"
1579 "\tstart packet engine rx usage: wl pkteng_start <xx:xx:xx:xx:xx:xx>"
1580 " <rx|rxwithack> [(async)|sync] [rxframes] [rxtimeout]\n"
1581 "\tsync: synchronous mode\n"
1582 "\tipg: inter packet gap in us\n"
1583 "\tlen: packet length\n"
1584 "\tnframes: number of frames; 0 indicates continuous tx test\n"
1585 "\tsrc: source mac address\n"
1586 "\trxframes: number of receive frames (sync mode only)\n"
1587 "\trxtimeout: maximum timout in msec (sync mode only)"},
1588 { "pkteng_stop", wl_pkteng, -1, WLC_SET_VAR,
1589 "stop packet engine; usage: wl pkteng_stop <tx|rx>"},
1590 { "pkteng_stats", wl_pkteng_stats, -1, WLC_GET_VAR,
1591 "packet engine stats; usage: wl pkteng_stats"},
1592 { "wowl", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1593 "Enable/disable WOWL events\n"
1594 " 0 - Clear all events\n"
1595 "Bit 0 - Wakeup on Magic Packet\n"
1596 "Bit 1 - Wakeup on NetPattern (use 'wl wowl_pattern' to configure pattern)\n"
1597 "Bit 2 - Wakeup on loss-of-link due to Disassociation/Deauth\n"
1598 "Bit 3 - Wakeup on retrograde tsf\n"
1599 "Bit 4 - Wakeup on loss of beacon (use 'wl wowl_bcn_loss' to configure time)"},
1600 { "wowl_bcn_loss", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1601 "Set #of seconds of beacon loss for wakeup event"},
1602 { "wowl_pattern", wl_wowl_pattern, -1, -1,
1603 "usage: wowl_pattern [ [clr | [[ add | del ] offset mask value ]]]\n"
1604 "No options -- lists existing pattern list\n"
1605 "add -- Adds the pattern to the list\n"
1606 "del -- Removes a pattern from the list\n"
1607 "clr -- Clear current list\n"
1608 "offset -- Starting offset for the pattern\n"
1609 "mask -- Mask to be used for pattern. Bit i of mask => byte i of the pattern\n"
1610 "value -- Value of the pattern"
1612 { "wowl_wakeind", wl_wowl_wakeind, WLC_GET_VAR, WLC_SET_VAR,
1613 "usage: wowl_wakeind [clear]\n"
1614 "Shows last system wakeup event indications from PCI and D11 cores\n"
1615 "clear - Clear the indications"
1617 { "wowl_status", wl_wowl_status, WLC_GET_VAR, -1,
1618 "usage: wowl_status [clear]\n"
1619 "Shows last system wakeup setting"
1621 {"wowl_pkt", wl_wowl_pkt, -1, -1,
1622 "Send a wakeup frame to wakup a sleeping STA in WAKE mode\n"
1623 "Usage: wl wowl_pkt <len> <dst ea | bcast | ucast <STA ea>>"
1624 "[ magic [<STA ea>] | net <offset> <pattern>]\n"
1625 "e.g. To send bcast magic frame -- "
1626 "wl wowl_pkt 102 bcast magic 00:90:4c:AA:BB:CC\n"
1627 " To send ucast magic frame -- "
1628 "wl wowl_pkt 102 ucast 00:90:4c:aa:bb:cc magic\n"
1629 " To send a frame with L2 unicast - "
1630 "wl wowl_pkt 102 00:90:4c:aa:bb:cc net 0 0x00904caabbcc\n"
1631 " NOTE: offset for netpattern frame starts from \"Dest EA\" of ethernet frame."
1632 "So dest ea will be used only when offset is >= 6"},
1633 { "wme_apsd_trigger", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1634 "Set Periodic APSD Trigger Frame Timer timeout in ms (0=off)"},
1635 { "wme_autotrigger", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1636 "Enable/Disable sending of APSD Trigger frame when all ac are delivery enabled"},
1637 { "reassoc", wl_reassoc, -1, WLC_REASSOC,
1638 "Initiate a (re)association request.\n"
1639 "\tUsage: wl reassoc <bssid> [options]\n"
1640 "\tOptions:\n"
1641 "\t-c CL, --chanspecs=CL \tchanspecs (comma or space separated list)"},
1642 { "send_nulldata", wl_iov_mac, -1, -1,
1643 "Sed a null frame to the specified hw address" },
1644 { "btc_params", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR, "g/set BT Coex parameters"},
1645 { "btc_flags", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR, "g/set BT Coex flags"},
1646 { "obss_scan_params", wl_obss_scan, WLC_GET_VAR, WLC_SET_VAR,
1647 "set/get Overlapping BSS scan parameters\n"
1648 "Usage: wl obss_scan a b c d e ...; where\n"
1649 "\ta-Passive Dwell, {5-1000TU}, default = 100\n"
1650 "\tb-Active Dwell, {10-1000TU}, default = 20\n"
1651 "\tc-Width Trigger Scan Interval, {10-900sec}, default = 300\n"
1652 "\td-Passive Total per Channel, {200-10000TU}, default = 200\n"
1653 "\te-Active Total per Channel, {20-1000TU}, default = 20\n"
1654 "\tf-Channel Transition Delay Factor, {5-100}, default = 5\n"
1655 "\tg-Activity Threshold, {0-100%}, default = 25"},
1656 {"keep_alive", wl_keep_alive, -1, -1,
1657 "Send specified \"keep-alive\" packet periodically.\n"
1658 "\tUsage: wl keep_alive <period> <packet>\n"
1659 "\t\tperiod: Re-transmission period in milli-seconds. 0 to disable packet transmits.\n"
1660 "\t\tpacket: Hex packet contents to transmit. The packet contents should include "
1661 "the entire ethernet packet (ethernet header, IP header, UDP header, and UDP "
1662 "payload) specified in network byte order.\n"
1663 "\n\te.g. Send keep alive packet every 30 seconds:\n"
1664 "\twl keep_alive 30000 0x0014a54b164f000f66f45b7e08004500001e000040004011c"
1665 "52a0a8830700a88302513c413c4000a00000a0d" },
1666 { "srchmem", wl_srchmem, WLC_GET_VAR, WLC_SET_VAR,
1667 "g/set ucode srch engine memory"},
1668 { "pkt_filter_add", wl_pkt_filter_add, -1, -1,
1669 "Install a packet filter.\n"
1670 "\tUsage: wl pkt_filter_add <id> <polarity> <type> <offset> <bitmask> <pattern>\n"
1671 "\tid: Integer. User specified id.\n"
1672 "\ttype: 0 (Pattern matching filter).\n"
1673 "\toffset: Integer. Offset within received packets to start matching.\n"
1674 "\tpolarity: Set to 1 to negate match result. 0 is default.\n"
1675 "\tbitmask: Hex bitmask that indicates which bits of 'pattern' to match. Must be same\n"
1676 "\t\tsize as 'pattern'. Bit 0 of bitmask corresponds to bit 0 of pattern, etc.\n"
1677 "\t\tIf bit N of bitmask is 0, then do *not* match bit N of the pattern with\n"
1678 "\t\tthe received payload. If bit N of bitmask is 1, then perform match.\n"
1679 "\tpattern: Hex pattern to match." },
1680 { "pkt_filter_clear_stats", wl_varint, -1, WLC_SET_VAR,
1681 "Clear packet filter statistic counter values.\n"
1682 "\tUsage: wl pkt_filter_clear_stats <id>" },
1683 { "pkt_filter_enable", wl_pkt_filter_enable, -1, -1,
1684 "Enable/disable a packet filter.\n"
1685 "\tUsage: wl pkt_filter_enable <id> <0|1>"},
1686 { "pkt_filter_list", wl_pkt_filter_list, -1, -1,
1687 "List installed packet filters.\n"
1688 "\tUsage: wl pkt_filter_list [val]\n"
1689 "\tval: 0 (disabled filters) 1 (enabled filters)"},
1690 { "pkt_filter_mode", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1691 "Set packet filter match action.\n"
1692 "\tUsage: wl pkt_filter_mode <value>\n"
1693 "\tvalue: 1 - Forward packet on match, discard on non-match (default).\n"
1694 "\t 0 - Discard packet on match, forward on non-match." },
1695 { "pkt_filter_delete", wl_varint, -1, WLC_SET_VAR,
1696 "Uninstall a packet filter.\n"
1697 "\tUsage: wl pkt_filter_delete <id>"},
1698 { "pkt_filter_stats", wl_pkt_filter_stats, -1, -1,
1699 "Retrieve packet filter statistic counter values.\n"
1700 "\tUsage: wl pkt_filter_stats <id>"},
1701 { "seq_start", wl_seq_start, -1, WLC_SET_VAR,
1702 "Initiates command batching sequence. Subsequent IOCTLs will be queued until\n"
1703 "seq_stop is received."},
1704 { "seq_stop", wl_seq_stop, -1, WLC_SET_VAR,
1705 "Defines the end of command batching sequence. Queued IOCTLs will be executed."},
1706 { "seq_delay", wl_varint, -1, WLC_SET_VAR,
1707 "Driver should spin for the indicated amount of time.\n"
1708 "It is only valid within the context of batched commands."},
1709 { "seq_error_index", wl_varint, WLC_GET_VAR, -1,
1710 "Used to retrieve the index (starting at 1) of the command that failed within a batch"},
1711 { "bmac_reboot", wl_var_void, -1, WLC_SET_VAR,
1712 "Reboot BMAC"},
1713 #ifdef RWL_WIFI
1714 { "findserver", wl_wifiserver, -1, -1,
1715 "Used to find the remote server with proper mac address given by the user,this "
1716 "cmd is specific to wifi protocol."},
1717 #endif
1718 { "txmcsset", wl_txmcsset, WLC_GET_VAR, -1, "get Transmit MCS rateset for 11N device"},
1719 { "rxmcsset", wl_rxmcsset, WLC_GET_VAR, -1, "get Receive MCS rateset for 11N device"},
1720 { "mimo_ss_stf", wl_mimo_stf, WLC_GET_VAR, WLC_SET_VAR,
1721 "get/set SS STF mode.\n"
1722 "\tUsage: wl mimo_ss_stf <value> <-b a | b>\n"
1723 "\tvalue: 0 - SISO; 1 - CDD\n"
1724 "\t-b(band): a - 5G; b - 2.4G"},
1725 #ifdef WLEXTLOG
1726 { "extlog", wl_extlog, WLC_GET_VAR, -1,
1727 "get external logs\n"
1728 "\tUsage: wl extlog <from_last> <number>\n"
1729 "\from_last: 1 - from the last log record; 0 - whole log recrods"
1730 "\tnumber: number of log records to get, MAX is 32."},
1731 { "extlog_clr", wl_var_void, -1, WLC_SET_VAR, "clear external log records"},
1732 { "extlog_cfg", wl_extlog_cfg, WLC_GET_VAR, WLC_SET_VAR,
1733 "get/set external log configuration"},
1734 #endif
1735 { "assertlog", wl_assertlog, WLC_GET_VAR, -1,
1736 "get external assert logs\n"
1737 "\tUsage: wl assertlog"},
1738 { "assert_type", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1739 "set/get the asset_bypass flag; usage: wl assert_type <1/0> (On/Off)"
1741 { "ledbh", wl_ledbh, WLC_GET_VAR, WLC_SET_VAR,
1742 "set/get led behavior\n"
1743 "\tUsage: wl ledbh [0-3] [0-15]"},
1744 { "obss_coex_action", wl_obss_coex_action, -1, WLC_SET_VAR,
1745 "send OBSS 20/40 Coexistence Mangement Action Frame\n"
1746 "\tUsage: wl obss_coex_action -i <1/0> -w <1/0> -c <channel list>\n"
1747 "\t -i: 40MHz intolerate bit; -w: 20MHz width Req bit;\n"
1748 "\t -c: channel list, 1 - 14\n"
1749 "\t At least one option must be provided"
1751 {"chanim_state", wl_chanim_state, WLC_GET_VAR, -1,
1752 "get channel interference state\n"
1753 "\tUsage: wl chanim_state channel\n"
1754 "\tValid channels: 1 - 14\n"
1755 "\treturns: 0 - Acceptable; 1 - Severe"
1757 {"chanim_mode", wl_chanim_mode, WLC_GET_VAR, WLC_SET_VAR,
1758 "get/set channel interference measure (chanim) mode\n"
1759 "\tUsage: wl chanim_mode <value>\n"
1760 "\tvalue: 0 - disabled; 1 - detection only; 2 - detection and avoidance"
1762 { "ledbh", wl_ledbh, WLC_GET_VAR, WLC_SET_VAR, "set/get led behavior\n"
1763 "\tUsage: wl ledbh [0-3] [0-15]"},
1764 { "led_blink_sync", wl_led_blink_sync, WLC_GET_VAR, WLC_SET_VAR, "set/get led_blink_sync\n"
1765 "\tUsage: wl led_blink_sync [0-3] [0/1]"},
1767 {"cca_get_stats", wl_cca_get_stats, WLC_GET_VAR, -1,
1768 "Usage: wl cca_stats [-c channel] [-s num seconds][-a]\n"
1769 "\t -c channel: Optional. specify channel. 0 = All channels. Default = current channel \n"
1770 "\t -s num_seconds: Optional. Default = 10, Max = 60\n"
1771 "\t -i: list individual measurements in addition to the averages\n"
1772 "\t -curband: Only recommend channels on current band"
1774 { "itfr_get_stats", wl_itfr_get_stats, WLC_GET_VAR, -1,
1775 "get interference source information"
1777 { "itfr_enab", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1778 "get/set STA interference detection mode(STA only)\n"
1779 "\t 0 - disable\n"
1780 "\t 1 - enable maual detection\n"
1781 "\t 2 - enable auto detection"
1783 { "itfr_detect", wl_var_void, -1, WLC_SET_VAR,
1784 "issue an interference detection request"
1786 { "smfstats", wl_smfstats, WLC_GET_VAR, WLC_SET_VAR,
1787 "get/clear selected management frame (smf) stats"
1788 "\twl smfstats [-C num]|[--cfg=num] [auth]|[assoc]|[reassoc]|[clear]\n"
1789 "\tclear - to clear the stats" },
1790 #ifdef RWL_DONGLE
1791 { "dongleset", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1792 "Enable uart driver"
1794 #endif
1795 { "manfinfo", wl_var_getandprintstr, WLC_GET_VAR, -1,
1796 "show chip package info in OTP"},
1797 { "rrm_nbr_req", wl_rrm_nbr_req, -1, WLC_SET_VAR,
1798 "send 11k neighbor report measurement request\n"
1799 "\tUsage: wl rrm_nbr_req [ssid]"},
1800 { "wnm_bsstq", wl_wnm_bsstq, -1, WLC_SET_VAR,
1801 "send 11v BSS transition management query\n"
1802 "\tUsage: wl wnm_bsstq [ssid]"},
1803 #ifdef WLP2P
1804 { "p2p_ssid", wl_ssid, -1, WLC_SET_VAR,
1805 "set WiFi P2P wildcard ssid.\n"
1806 "\tUsage: wl p2p_ssid <ssid>"
1808 { "p2p_state", wl_p2p_state, -1, WLC_SET_VAR,
1809 "set WiFi P2P discovery state.\n"
1810 "\tUsage: wl p2p_state <state> [<chanspec> <dwell time>]"
1812 { "p2p_scan", wl_p2p_scan, -1, WLC_SET_VAR,
1813 "initiate WiFi P2P scan.\n"
1814 "\tUsage: wl p2p_scan S|E <scan parms>\n"
1815 SCAN_USAGE
1817 { "p2p_ifadd", wl_p2p_ifadd, -1, WLC_SET_VAR,
1818 "add WiFi P2P interface\n"
1819 "\tUsage: wl p2p_ifadd <MAC-address> go|client|dyngo [chanspec]\n"
1820 "MAC-address: xx:xx:xx:xx:xx:xx"
1822 { "p2p_ifdel", wl_p2p_ifdel, -1, WLC_SET_VAR,
1823 "delete WiFi P2P interface\n"
1824 "\tUsage: wl p2p_ifdel <MAC-address>\n"
1825 "MAC-address: xx:xx:xx:xx:xx:xx"
1827 { "p2p_ifupd", wl_p2p_ifupd, -1, WLC_SET_VAR,
1828 "update an interface to WiFi P2P interface\n"
1829 "\tUsage: wl p2p_ifupd <MAC-address> go|client\n"
1830 "MAC-address: xx:xx:xx:xx:xx:xx"
1832 { "p2p_if", wl_p2p_if, WLC_GET_VAR, -1,
1833 "query WiFi P2P interface bsscfg index\n"
1834 "\tUsage: wl p2p_if <MAC-address>\n"
1835 "MAC-address: xx:xx:xx:xx:xx:xx"
1837 { "p2p_noa", wl_p2p_noa, WLC_GET_VAR, WLC_SET_VAR,
1838 "set/get WiFi P2P NoA schedule\n"
1839 "\tUsage: wl p2p_noa <type> <type-specific-params>\n"
1840 "\t\ttype 0: Scheduled Absence (on GO): <type> <action> <action-specific-params>\n"
1841 "\t\t\taction -1: Cancel the schedule: <type> <action>\n"
1842 "\t\t\taction 0,1,2: <type> <action> <option> <option-specific-params>\n"
1843 "\t\t\t\taction 0: Do nothing during absence periods\n"
1844 "\t\t\t\taction 1: Sleep during absence periods\n"
1845 "\t\t\t\toption 0: <start:tsf> <interval> <duration> <count> ...\n"
1846 "\t\t\t\toption 1 [<start-percentage>] <duration-percentage>\n"
1847 "\t\t\t\toption 2 <start:tsf-offset> <interval> <duration> <count>\n"
1848 "\t\ttype 1: Requested Absence (on GO): "
1849 "\t\t\taction -1: Cancel the schedule: <type> <action>\n"
1850 "\t\t\taction 2: <type> <action> <option> <option-specific-params>\n"
1851 "\t\t\t\taction 2: Turn off GO beacons and probe responses during absence period\n"
1852 "\t\t\t\toption 2 <start:tsf-offset> <interval> <duration> <count>\n"
1854 { "p2p_ops", wl_p2p_ops, WLC_GET_VAR, WLC_SET_VAR,
1855 "set/get WiFi P2P OppPS and CTWindow\n"
1856 "\tUsage: wl p2p_ops <ops> [<ctw>]\n"
1857 "\t\t<ops>:\n"
1858 "\t\t\t0: Disable OppPS\n"
1859 "\t\t\t1: Enable OppPS\n"
1860 "\t\t<ctw>:\n"
1861 "\t\t\t10 and up to beacon interval\n"
1863 { "p2p_da_override", wl_iov_mac, WLC_GET_VAR, WLC_SET_VAR,
1864 "Get/Set WiFi P2P device interface addr\n"
1865 "\tUsage: wl p2p_da_override <MAC-address>\n"
1866 "MAC-address: xx:xx:xx:xx:xx:xx\n"
1867 "(When MAC-address is set to 00:00:00:00:00:00, default da restored)"
1869 #endif /* WLP2P */
1870 { "pm_dur", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1871 "Retrieve accumulated PM duration information (GET) or clear accumulator (SET)\n"
1872 "\tUsage: wl pm_dur <any-number-to-clear>"
1874 { "mpc_dur", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1875 "Retrieve accumulated MPC duration information in ms (GET) or clear accumulator (SET)\n"
1876 "\tUsage: wl mpc_dur <any-number-to-clear>"},
1877 {"chanim_acs_record", wl_chanim_acs_record, WLC_GET_VAR, -1,
1878 "get the auto channel scan record. \n"
1879 "\t Usage: wl acs_record"
1881 { "dngl_wd", wl_dngl_wd, WLC_GET_VAR, WLC_SET_VAR,
1882 "enable or disable dongle watchdog timer\n"
1883 "\tUsage: wl dngl_wd <on/off>(to turn on\\off) <exptime in sec>"},
1884 { "tsf", wl_tsf, WLC_GET_VAR, WLC_SET_VAR,
1885 "set/get tsf register\n"
1886 "\tUsage: wl tsf [<high> <low>]"},
1887 { "tpc_mode", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1888 "Enable/disable AP TPC.\n"
1889 "Usage: wl tpc_mode <mode> \n"
1890 "\t0 - disable, 1 - BSS power control, 2 - AP power control, 3 - Both (1) and (2)\n"},
1891 { "tpc_period", wl_varint, WLC_GET_VAR, WLC_SET_VAR,
1892 "Set AP TPC periodicity in secs.\n"
1893 "Usage: wl tpc_period <secs> \n"},
1894 { "tpc_lm", wl_tpc_lm, WLC_GET_VAR, -1,
1895 "Get current link margins.\n"},
1896 { "mfp_config", wl_mfp_config, -1, WLC_SET_VAR,
1897 "Config PMF capability\n"
1898 "\tusage: wl mfp 0/disable, 1/capable, 2/requred" },
1899 { "mfp_sha256", wl_mfp_sha256, -1, WLC_SET_VAR,
1900 "Config SHA256 capability\n"
1901 "\tusage: wl sha256 0/disable, 1/enable" },
1902 { "mfp_sa_query", wl_mfp_sa_query, -1, WLC_SET_VAR,
1903 "Send a sa query req/resp to a peer\n"
1904 "\tusage: wl mfp_sa_query flag action id" },
1905 { "mfp_disassoc", wl_mfp_disassoc, WLC_GET_VAR, WLC_SET_VAR,
1906 "send bogus disassoc\n"
1907 "Usage: wl mfp_disassoc\n"},
1908 { "mfp_deauth", wl_mfp_deauth, WLC_GET_VAR, WLC_SET_VAR,
1909 "send bogus deauth\n"
1910 "\tUsage: wl mfp_dedauth\n"},
1911 { "mfp_assoc", wl_mfp_assoc, WLC_GET_VAR, WLC_SET_VAR,
1912 "send assoc\n"
1913 "Usage: wl mfp_assoc\n"},
1914 { "mfp_auth", wl_mfp_auth, WLC_GET_VAR, WLC_SET_VAR,
1915 "send auth\n"
1916 "\tUsage: wl mfp_auth\n"},
1917 { "mfp_reassoc", wl_mfp_reassoc, WLC_GET_VAR, WLC_SET_VAR,
1918 "send reassoc\n"
1919 "Usage: wl mfp_reassoc\n"},
1920 { "monitor_lq", wl_monitor_lq, WLC_GET_VAR, WLC_SET_VAR,
1921 "Start/Stop monitoring link quality metrics - RSSI and SNR\n"
1922 "\tUsage: wl monitor_lq <0: turn off / 1: turn on\n"},
1923 { "monitor_lq_status", wl_dump_lq, WLC_GET_VAR, -1 /* Set not reqd */,
1924 "Returns averaged link quality metrics - RSSI and SNR values"},
1925 {"scb_probe", wl_scb_probe, WLC_GET_VAR, WLC_SET_VAR,
1926 "Set probing parameters for inactive clients.\n"
1927 "\t<timout in seconds> <activity_time in seconds> <max number of probes>"},
1928 { "rpmt", wl_rpmt, -1, WLC_SET_VAR, "rpmt <pm1-to> <pm0-to>\n"},
1929 { "spatial_policy", wl_spatial_policy, WLC_GET_VAR, WLC_SET_VAR,
1930 "set/get spatial_policy\n"
1931 "\tUsage: wl spatial_policy <-1: auto / 0: turn off / 1: turn on>\n"
1932 "\t to control individual band/sub-band use\n"
1933 "\t wl spatial_policy a b c d e\n"
1934 "\t where a is 2.4G band setting\n"
1935 "\t where b is 5G lower band setting\n"
1936 "\t where c is 5G middle band setting\n"
1937 "\t where d is 5G high band setting\n"
1938 "\t where e is 5G upper band setting\n"},
1939 { "ratetbl_ppr", wl_ratetbl_ppr, WLC_GET_VAR, WLC_SET_VAR,
1940 "Usage: For get: wl ratetbl_ppr\n"
1941 "\t For set: wl ratetbl_ppr <rate> <ppr>\n" },
1942 { "ie", wl_ie, WLC_GET_VAR, WLC_SET_VAR,
1943 "set/get IE\n"
1944 "Usage for set: wl ie type length hexdata\n"
1945 "Example: wl ie 107 9 02020800904c09215c\n"
1946 " to set IW IE with length 9\n"
1947 "Usage for get: wl ie type\n"
1948 "Example: wl ie 107\n"
1949 " to get current IW IE" },
1950 { NULL, NULL, 0, 0, NULL }
1953 cmd_t wl_varcmd = {"var", wl_varint, -1, -1, "unrecognized name, type -h for help"};
1954 const char *wlu_av0;
1956 #ifdef WC_TOOL
1957 /* Include any commands for wc tool used for WMM
1958 * These need to be only the command names from port_cmds and wl_cmds array
1960 static const char *wc_cmds[] = {
1961 "ver", "cmds", "up", "down",
1962 "gmode", "listen", "wme", "wme_ac", "wme_apsd",
1963 "wme_apsd_sta", "wme_dp"
1965 #else
1966 static const char **wc_cmds = NULL;
1967 #endif /* WC_TOOL */
1969 /* initialize stuff needed before processing the command */
1970 void
1971 wl_cmd_init(void)
1973 int_fmt = INT_FMT_DEC;
1977 void
1978 wlu_init(void)
1980 /* Init global variables at run-time, not as part of the declaration.
1981 * This is required to support init/de-init of the driver. Initialization
1982 * of globals as part of the declaration results in non-deterministic
1983 * behaviour since the value of the globals may be different on the
1984 * first time that the driver is initialized vs subsequent initializations.
1986 int_fmt = INT_FMT_DEC;
1987 batch_in_client = FALSE;
1988 cmd_pkt_list_num = 0;
1989 cmd_batching_mode = FALSE;
1992 /* parse/validate the command line arguments */
1994 * pargv is updated upon return if the first argument is an option.
1995 * It remains intact otherwise.
1998 wl_option(char ***pargv, char **pifname, int *phelp)
2000 char *ifname = NULL;
2001 int help = FALSE;
2002 int status = CMD_OPT;
2003 char **argv = *pargv;
2005 while (*argv) {
2006 /* select different adapter */
2007 if (!strcmp(*argv, "-a") || !strcmp(*argv, "-i")) {
2008 char *opt = *argv++;
2009 ifname = *argv;
2010 if (!ifname) {
2011 fprintf(stderr,
2012 "error: expected interface name after option %s\n", opt);
2013 status = CMD_ERR;
2014 break;
2018 /* integer output format */
2019 else if (!strcmp(*argv, "-d"))
2020 int_fmt = INT_FMT_DEC;
2021 else if (!strcmp(*argv, "-u"))
2022 int_fmt = INT_FMT_UINT;
2023 else if (!strcmp(*argv, "-x"))
2024 int_fmt = INT_FMT_HEX;
2026 /* command usage */
2027 else if (!strcmp(*argv, "-h") || !strcmp(*argv, "--help"))
2028 help = TRUE;
2030 else if (!strcmp(*argv, "--clientbatch")) {
2031 wl_seq_batch_in_client(TRUE);
2033 /* To handle endian mis-matches between wl utility and wl driver */
2034 else if (!strcmp(*argv, "--es")) {
2035 g_swap = TRUE;
2037 /* start of non wl options */
2038 else {
2039 status = CMD_WL;
2040 break;
2043 /* consume the argument */
2044 argv ++;
2045 break;
2048 *phelp = help;
2049 *pifname = ifname;
2050 *pargv = argv;
2052 return status;
2055 void
2056 wl_cmd_usage(FILE *fid, cmd_t *cmd)
2058 if (strlen(cmd->name) >= 8)
2059 fprintf(fid, "%s\n\t%s\n\n", cmd->name, cmd->help);
2060 else
2061 fprintf(fid, "%s\t%s\n\n", cmd->name, cmd->help);
2064 static int
2065 wl_print_deprecate(void *wl, cmd_t *cmd, char **argv)
2067 UNUSED_PARAMETER(wl);
2068 UNUSED_PARAMETER(argv);
2070 wl_cmd_usage(stderr, cmd); /* warning string is in command table */
2071 return 0;
2074 /* Dump out short list of commands */
2075 static int
2076 wl_list(void *wl, cmd_t *garb, char **argv)
2078 cmd_t *cmd;
2079 int nrows, i, len;
2080 char *list_buf;
2081 int letter, col, row, pad;
2083 UNUSED_PARAMETER(wl);
2084 UNUSED_PARAMETER(garb);
2085 UNUSED_PARAMETER(argv);
2087 for (cmd = wl_cmds, nrows = 0; cmd->name; cmd++)
2088 /* Check for wc_cmd */
2089 if (wc_cmd_check(cmd->name))
2090 nrows++;
2092 nrows /= 4;
2093 nrows++;
2095 len = nrows * 80 + 2;
2096 list_buf = malloc(len);
2097 if (list_buf == NULL) {
2098 fprintf(stderr, "Failed to allocate buffer of %d bytes\n", len);
2099 return -1;
2101 for (i = 0; i < len; i++)
2102 *(list_buf+i) = 0;
2104 row = col = 0;
2105 for (letter = 'a'; letter < 'z'; letter++) {
2106 for (cmd = wl_cmds; cmd->name; cmd++) {
2107 /* Check for wc_cmd */
2108 if (!wc_cmd_check(cmd->name))
2109 continue;
2110 if (cmd->name[0] == letter || cmd->name[0] == letter - 0x20) {
2111 strcat(list_buf+row*80, cmd->name);
2112 pad = 18 * (col + 1) - strlen(list_buf+row*80);
2113 if (pad < 1)
2114 pad = 1;
2115 for (; pad; pad--)
2116 strcat(list_buf+row*80, " ");
2117 row++;
2118 if (row == nrows) {
2119 col++; row = 0;
2124 for (row = 0; row < nrows; row++)
2125 printf("%s\n", list_buf+row*80);
2127 printf("\n");
2129 free(list_buf);
2130 return (0);
2133 void
2134 wl_cmds_usage(FILE *fid, cmd_t *port_cmds)
2136 cmd_t *port_cmd;
2137 cmd_t *cmd;
2139 /* print usage of port commands */
2140 for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++)
2141 /* Check for wc_cmd */
2142 if (wc_cmd_check(port_cmd->name))
2143 wl_cmd_usage(fid, port_cmd);
2145 /* print usage of common commands without port counterparts */
2146 for (cmd = wl_cmds; cmd->name; cmd++) {
2147 /* search if port counterpart exists */
2148 for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++)
2149 if (!strcmp(port_cmd->name, cmd->name))
2150 break;
2151 /* Also, check for this being a wc_cmd */
2152 if ((!port_cmd || !port_cmd->name) && (wc_cmd_check(cmd->name)))
2153 wl_cmd_usage(fid, cmd);
2157 void
2158 wl_usage(FILE *fid, cmd_t *port_cmds)
2160 fprintf(fid, "Usage: %s [-a|i <adapter>] [-h] [-d|u|x] <command> [arguments]\n", wlu_av0);
2162 fprintf(fid, "\n");
2163 fprintf(fid, " -h this message and command descriptions\n");
2164 fprintf(fid, " -h [cmd] command description for cmd\n");
2165 fprintf(fid, " -a, -i adapter name or number\n");
2166 fprintf(fid, " -d output format signed integer\n");
2167 fprintf(fid, " -u output format unsigned integer\n");
2168 fprintf(fid, " -x output format hexdecimal\n");
2169 fprintf(fid, "\n");
2171 wl_cmds_usage(fid, port_cmds);
2175 wl_check(void *wl)
2177 int ret;
2178 int val;
2180 if ((ret = wlu_get(wl, WLC_GET_MAGIC, &val, sizeof(int)) < 0))
2181 return ret;
2183 /* Detect if IOCTL swapping is necessary */
2184 if (val == (int)bcmswap32(WLC_IOCTL_MAGIC))
2186 val = bcmswap32(val);
2187 g_swap = TRUE;
2189 if (val != WLC_IOCTL_MAGIC)
2190 return -1;
2191 if ((ret = wlu_get(wl, WLC_GET_VERSION, &val, sizeof(int)) < 0))
2192 return ret;
2193 val = dtoh32(val);
2194 if (val > WLC_IOCTL_VERSION) {
2195 fprintf(stderr, "Version mismatch, please upgrade\n");
2196 return -1;
2198 return 0;
2201 void
2202 wl_printint(int val)
2204 switch (int_fmt) {
2205 case INT_FMT_UINT:
2206 printf("%u\n", val);
2207 break;
2208 case INT_FMT_HEX:
2209 printf("0x%x\n", val);
2210 break;
2211 case INT_FMT_DEC:
2212 default:
2213 printf("%d\n", val);
2214 break;
2219 /* Common routine to check for an option arg specifying the configuration index.
2220 * Takes the syntax -C num, --cfg=num, --config=num, or --configuration=num
2221 * Returns -1 if there is a command line parsing error.
2222 * Returns 0 if no error, and sets *consumed to the number of argv strings
2223 * used. Sets *bsscfg_idx to the index to use. Will set *bsscfg_idx to zero if there
2224 * was no config arg.
2226 static int
2227 wl_cfg_option(char **argv, const char *fn_name, int *bsscfg_idx, int *consumed)
2229 miniopt_t mo;
2230 int opt_err;
2232 *bsscfg_idx = 0;
2233 *consumed = 0;
2235 miniopt_init(&mo, fn_name, NULL, FALSE);
2237 /* process the first option */
2238 opt_err = miniopt(&mo, argv);
2240 /* check for no args or end of options */
2241 if (opt_err == -1)
2242 return 0;
2244 /* check for no options, just a positional arg encountered */
2245 if (mo.positional)
2246 return 0;
2248 /* check for error parsing options */
2249 if (opt_err == 1)
2250 return -1;
2252 /* check for -C, --cfg=X, --config=X, --configuration=X */
2253 if (mo.opt == 'C' ||
2254 !strcmp(mo.key, "cfg") ||
2255 !strcmp(mo.key, "config") ||
2256 !strcmp(mo.key, "configuration")) {
2257 if (!mo.good_int) {
2258 fprintf(stderr,
2259 "%s: could not parse \"%s\" as an integer for the configuartion index\n",
2260 fn_name, mo.valstr);
2261 return -1;
2263 *bsscfg_idx = mo.val;
2264 *consumed = mo.consumed;
2267 return 0;
2270 static int
2271 wl_void(void *wl, cmd_t *cmd, char **argv)
2273 UNUSED_PARAMETER(argv);
2275 if (cmd->set < 0)
2276 return -1;
2277 return wlu_set(wl, cmd->set, NULL, 0);
2281 wl_int(void *wl, cmd_t *cmd, char **argv)
2283 int ret;
2284 int val;
2285 char *endptr = NULL;
2287 if (!*++argv) {
2288 if (cmd->get == -1)
2289 return -1;
2290 if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0)
2291 return ret;
2293 val = dtoh32(val);
2294 wl_printint(val);
2295 } else {
2296 if (cmd->set == -1)
2297 return -1;
2298 if (!stricmp(*argv, "on"))
2299 val = 1;
2300 else if (!stricmp(*argv, "off"))
2301 val = 0;
2302 else {
2303 val = strtol(*argv, &endptr, 0);
2304 if (*endptr != '\0') {
2305 /* not all the value string was parsed by strtol */
2306 return -1;
2310 val = htod32(val);
2311 ret = wlu_set(wl, cmd->set, &val, sizeof(int));
2314 return ret;
2317 static int
2318 wl_bsscfg_int(void *wl, cmd_t *cmd, char **argv)
2320 char *endptr = NULL;
2321 char *val_name;
2322 int bsscfg_idx = 0;
2323 int val = 0;
2324 int consumed;
2325 int ret;
2327 val_name = *argv++;
2329 /* parse a bsscfg_idx option if present */
2330 if ((ret = wl_cfg_option(argv, val_name, &bsscfg_idx, &consumed)) != 0)
2331 return ret;
2333 /* handle a bsscfg int with a legacy ioctl */
2334 if (consumed == 0 && cmd->set != WLC_SET_VAR) {
2335 /* back up to the orig command and run as an ioctl int */
2336 argv--;
2337 return wl_int(wl, cmd, argv);
2340 argv += consumed;
2342 if (!*argv) {
2343 /* This is a GET */
2344 if (cmd->get == -1)
2345 return -1;
2347 if (consumed == 0)
2348 ret = wlu_iovar_getint(wl, val_name, &val);
2349 else
2350 ret = wl_bssiovar_getint(wl, val_name, bsscfg_idx, &val);
2352 if (ret < 0)
2353 return ret;
2355 wl_printint(val);
2356 } else {
2357 /* This is a SET */
2358 if (cmd->set == -1)
2359 return -1;
2361 if (!stricmp(*argv, "on"))
2362 val = 1;
2363 else if (!stricmp(*argv, "off"))
2364 val = 0;
2365 else {
2366 val = strtol(*argv, &endptr, 0);
2367 if (*endptr != '\0') {
2368 /* not all the value string was parsed by strtol */
2369 return -1;
2373 if (consumed == 0)
2374 ret = wlu_iovar_setint(wl, val_name, val);
2375 else
2376 ret = wl_bssiovar_setint(wl, val_name, bsscfg_idx, val);
2379 return ret;
2382 static int
2383 wl_bsscfg_enable(void *wl, cmd_t *cmd, char **argv)
2385 char *endptr;
2386 const char *val_name = "bss";
2387 int bsscfg_idx = 0;
2388 int val;
2389 int consumed;
2390 int ret;
2392 UNUSED_PARAMETER(cmd);
2394 /* skip the command name */
2395 argv++;
2397 /* parse a bsscfg_idx option if present */
2398 if ((ret = wl_cfg_option(argv, val_name, &bsscfg_idx, &consumed)) != 0)
2399 return ret;
2401 argv += consumed;
2402 if (consumed == 0) { /* Use the -i parameter if that was present */
2403 bsscfg_idx = -1;
2406 if (!*argv) {
2407 bsscfg_idx = htod32(bsscfg_idx);
2408 ret = wlu_iovar_getbuf(wl, val_name, &bsscfg_idx, sizeof(bsscfg_idx),
2409 buf, WLC_IOCTL_MAXLEN);
2410 if (ret < 0)
2411 return ret;
2412 val = *(int*)buf;
2413 val = dtoh32(val);
2414 if (val)
2415 printf("up\n");
2416 else
2417 printf("down\n");
2418 return 0;
2419 } else {
2420 struct {
2421 int cfg;
2422 int val;
2423 } bss_setbuf;
2424 if (!stricmp(*argv, "ap"))
2425 val = 3;
2426 else if (!stricmp(*argv, "sta"))
2427 val = 2;
2428 else if (!stricmp(*argv, "up"))
2429 val = 1;
2430 else if (!stricmp(*argv, "down"))
2431 val = 0;
2432 else if (!stricmp(*argv, "del"))
2433 val = -1;
2434 else {
2435 val = strtol(*argv, &endptr, 0);
2436 if (*endptr != '\0') {
2437 /* not all the value string was parsed by strtol */
2438 return -1;
2441 bss_setbuf.cfg = htod32(bsscfg_idx);
2442 bss_setbuf.val = htod32(val);
2444 return wlu_iovar_set(wl, val_name, &bss_setbuf, sizeof(bss_setbuf));
2448 /* Get/Set the gmode config */
2449 static int
2450 wl_gmode(void *wl, cmd_t *cmd, char **argv)
2452 char *endptr = NULL;
2453 int ret = 0, val;
2455 if (!*++argv) {
2456 const char *gconfig;
2458 /* Get the current G mode */
2459 if ((ret = wlu_get(wl, cmd->get, &val, sizeof(val))))
2460 return -1;
2462 val = dtoh32(val);
2463 switch (val) {
2464 case GMODE_LEGACY_B:
2465 gconfig = "54g Legacy B";
2466 break;
2467 case GMODE_AUTO:
2468 gconfig = "54g Auto";
2469 break;
2470 case GMODE_ONLY:
2471 gconfig = "54g Only";
2472 break;
2473 case GMODE_PERFORMANCE:
2474 gconfig = "54g Performance";
2475 break;
2476 case GMODE_LRS:
2477 gconfig = "54g LRS";
2478 break;
2479 default:
2480 gconfig = "unknown";
2481 break;
2484 printf("%s (%d)\n", gconfig, val);
2486 } else {
2487 /* Set the new G mode */
2489 if (!strnicmp(*argv, "legacy", 6))
2490 val = GMODE_LEGACY_B;
2491 else if (!strnicmp(*argv, "auto", 4))
2492 val = GMODE_AUTO;
2493 else if (!strnicmp(*argv, "gonly", 5))
2494 val = GMODE_ONLY;
2495 else if (!strnicmp(*argv, "perf", 4))
2496 val = GMODE_PERFORMANCE;
2497 else if (!strnicmp(*argv, "lrs", 3))
2498 val = GMODE_LRS;
2499 else {
2500 val = strtol(*argv, &endptr, 0);
2501 if (*endptr != '\0') {
2502 /* not all the value string was parsed by strtol */
2503 return -1;
2507 /* Set the gmode configration */
2508 val = htod32(val);
2509 if ((ret = wlu_set(wl, cmd->set, &val, sizeof(val))))
2510 goto done;
2514 done:
2515 return (ret);
2519 static int
2520 wl_reg(void *wl, cmd_t *cmd, char **argv)
2522 int reg;
2523 int ret;
2524 struct {
2525 int val;
2526 int band;
2527 } x;
2528 char *endptr = NULL;
2529 uint argc;
2530 bool core_cmd;
2532 /* eat command name */
2533 argv++;
2535 /* arg count */
2536 for (argc = 0; argv[argc]; argc++)
2539 /* required arg: reg offset */
2540 if (argc < 1)
2541 return -1;
2543 reg = strtol(argv[0], &endptr, 0);
2545 if (*endptr != '\0')
2546 return -1;
2548 x.val = 0;
2549 x.band = WLC_BAND_AUTO;
2550 core_cmd = FALSE;
2552 /* Second arg: value or band or "radio core" */
2553 if (argc >= 2) {
2554 if (!stricmp(argv[1], "a"))
2555 x.band = WLC_BAND_5G;
2556 else if (!stricmp(argv[1], "b"))
2557 x.band = WLC_BAND_2G;
2558 else {
2559 /* For NPHY Rev >= 3, the 2nd argument can be
2560 the radio core
2562 if (strcmp(cmd->name, "radioreg") == 0) {
2563 if (strcmp(argv[1], "syn") == 0) {
2564 reg |= RADIO_CORE_SYN;
2565 core_cmd = TRUE;
2566 } else if (strcmp(argv[1], "tx0") == 0) {
2567 reg |= RADIO_CORE_TX0;
2568 core_cmd = TRUE;
2569 } else if (strcmp(argv[1], "tx1") == 0) {
2570 reg |= RADIO_CORE_TX1;
2571 core_cmd = TRUE;
2572 } else if (strcmp(argv[1], "rx0") == 0) {
2573 reg |= RADIO_CORE_RX0;
2574 core_cmd = TRUE;
2575 } else if (strcmp(argv[1], "rx1") == 0) {
2576 reg |= RADIO_CORE_RX1;
2577 core_cmd = TRUE;
2580 /* For HTPHY, the 2nd argument can be
2581 the radio core
2583 if (strcmp(cmd->name, "radioreg") == 0) {
2584 if (strcmp(argv[1], "cr0") == 0) {
2585 reg |= RADIO_CORE_CR0;
2586 core_cmd = TRUE;
2587 } else if (strcmp(argv[1], "cr1") == 0) {
2588 reg |= RADIO_CORE_CR1;
2589 core_cmd = TRUE;
2590 } else if (strcmp(argv[1], "cr2") == 0) {
2591 reg |= RADIO_CORE_CR2;
2592 core_cmd = TRUE;
2595 /* If the second argument is a value */
2596 if (!core_cmd) {
2597 x.val = strtol(argv[1], &endptr, 0);
2598 if (*endptr != '\0')
2599 return (-1);
2604 /* Third arg: band OR "radio core" */
2605 if (argc >= 3) {
2606 if (!stricmp(argv[2], "a"))
2607 x.band = WLC_BAND_5G;
2608 else if (!stricmp(argv[2], "b"))
2609 x.band = WLC_BAND_2G;
2610 else {
2611 /* For NPHY Rev >= 3, the 3rd argument can be
2612 the radio core
2614 core_cmd = FALSE;
2615 if (strcmp(cmd->name, "radioreg") == 0) {
2616 if (strcmp(argv[2], "syn") == 0) {
2617 reg |= RADIO_CORE_SYN;
2618 core_cmd = TRUE;
2619 } else if (strcmp(argv[2], "tx0") == 0) {
2620 reg |= RADIO_CORE_TX0;
2621 core_cmd = TRUE;
2622 } else if (strcmp(argv[2], "tx1") == 0) {
2623 reg |= RADIO_CORE_TX1;
2624 core_cmd = TRUE;
2625 } else if (strcmp(argv[2], "rx0") == 0) {
2626 reg |= RADIO_CORE_RX0;
2627 core_cmd = TRUE;
2628 } else if (strcmp(argv[2], "rx1") == 0) {
2629 reg |= RADIO_CORE_RX1;
2630 core_cmd = TRUE;
2633 /* For HTPHY, the 3rd argument can be
2634 the radio core
2636 if (strcmp(cmd->name, "radioreg") == 0) {
2637 if (strcmp(argv[2], "cr0") == 0) {
2638 reg |= RADIO_CORE_CR0;
2639 core_cmd = TRUE;
2640 } else if (strcmp(argv[2], "cr1") == 0) {
2641 reg |= RADIO_CORE_CR1;
2642 core_cmd = TRUE;
2643 } else if (strcmp(argv[2], "cr2") == 0) {
2644 reg |= RADIO_CORE_CR2;
2645 core_cmd = TRUE;
2646 } else if (strcmp(argv[2], "all") == 0) {
2647 reg |= RADIO_CORE_ALL;
2648 core_cmd = TRUE;
2652 if (!core_cmd) {
2653 return (-1);
2658 x.val = (x.val << 16) | (reg & 0xffff);
2660 /* issue the get or set ioctl */
2661 if ((argc == 1) || ((argc == 2) && ((x.band != WLC_BAND_AUTO) || core_cmd))) {
2662 x.band = htod32(x.band);
2663 x.val = htod32(x.val);
2664 if ((ret = wlu_get(wl, cmd->get, &x, sizeof(x))) < 0)
2665 return (ret);
2666 printf("0x%04x\n", (uint16)(dtoh32(x.val)));
2667 } else {
2668 x.band = htod32(x.band);
2669 x.val = htod32(x.val);
2670 ret = wlu_set(wl, cmd->set, &x, sizeof(x));
2673 return (ret);
2676 static int
2677 wl_gpioout(void *wl, cmd_t *cmd, char **argv)
2679 uint32 mask;
2680 uint32 val;
2681 char *endptr = NULL;
2682 uint argc;
2683 uint32 *int_ptr;
2685 UNUSED_PARAMETER(cmd);
2687 val = 0;
2689 /* eat command name */
2690 argv++;
2692 /* arg count */
2693 for (argc = 0; argv[argc]; argc++)
2696 /* Get and print the values */
2697 if (argc == 0) {
2698 uint32 gpio_cntrl;
2699 uint32 gpio_out;
2700 uint32 gpio_outen;
2702 if (wlu_iovar_get(wl, "gpioout", buf, sizeof(uint32) *3))
2703 return -1;
2704 gpio_cntrl = dtoh32(((uint32 *)buf)[0]);
2705 gpio_out = dtoh32(((uint32 *)buf)[1]);
2706 gpio_outen = dtoh32(((uint32 *)buf)[2]);
2708 printf("gpiocontrol 0x%x gpioout 0x%x gpioouten 0x%x\n", gpio_cntrl,
2709 gpio_out, gpio_outen);
2711 return 0;
2714 /* required arg: mask value */
2715 if (argc < 2)
2716 return -1;
2718 mask = strtoul(argv[0], &endptr, 0);
2719 if (*endptr != '\0')
2720 return -1;
2722 val = strtoul(argv[1], &endptr, 0);
2723 if (*endptr != '\0')
2724 return -1;
2726 if ((~mask & val) != 0)
2727 return -1;
2729 int_ptr = (uint32 *)buf;
2730 mask = htod32(mask);
2731 memcpy(int_ptr, (const void *)&mask, sizeof(mask));
2732 int_ptr++;
2733 val = htod32(val);
2734 memcpy(int_ptr, (const void *)&val, sizeof(val));
2736 return wlu_iovar_set(wl, "gpioout", buf, sizeof(uint32) *2);
2739 static int
2740 wl_macreg(void *wl, cmd_t *cmd, char **argv)
2742 int reg;
2743 int size;
2744 uint32 val;
2745 int ret;
2746 char *endptr = NULL;
2747 rw_reg_t rwt;
2748 uint argc;
2750 val = 0;
2752 /* eat command name */
2753 argv++;
2755 /* arg count */
2756 for (argc = 0; argv[argc]; argc++)
2759 /* required arg: reg offset */
2760 if (argc < 1)
2761 return -1;
2763 reg = strtol(argv[0], &endptr, 0);
2764 if (*endptr != '\0')
2765 return -1;
2767 /* required arg: reg size */
2768 if (argc < 2)
2769 return (-1);
2771 size = strtol(argv[1], &endptr, 0);
2772 if (*endptr != '\0')
2773 return -1;
2775 rwt.band = WLC_BAND_AUTO;
2777 /* Third arg: new value or band */
2778 if (argc >= 3) {
2779 if (!stricmp(argv[2], "a"))
2780 rwt.band = WLC_BAND_5G;
2781 else if (!stricmp(argv[2], "b"))
2782 rwt.band = WLC_BAND_2G;
2783 else {
2784 val = strtoul(argv[2], &endptr, 0);
2785 if (*endptr != '\0')
2786 return -1;
2791 /* Fourth arg: band */
2792 if (argc >= 4) {
2793 if (!stricmp(argv[3], "a"))
2794 rwt.band = WLC_BAND_5G;
2795 else if (!stricmp(argv[3], "b"))
2796 rwt.band = WLC_BAND_2G;
2797 else
2798 return (-1);
2801 if ((argc == 2) || ((argc == 3) && (rwt.band != WLC_BAND_AUTO))) {
2802 rwt.band = htod32(rwt.band);
2803 rwt.byteoff = htod32(reg);
2804 rwt.size = htod32(size);
2805 if ((ret = wlu_get(wl, cmd->get, &rwt, sizeof(rw_reg_t))) < 0)
2806 return (ret);
2807 printf("0x%04x\n", dtoh32(rwt.val));
2809 else {
2810 rwt.band = htod32(rwt.band);
2811 rwt.byteoff = htod32(reg);
2812 rwt.size = htod32(size);
2813 rwt.val = htod32(val);
2814 ret = wlu_set(wl, cmd->set, &rwt, sizeof(rw_reg_t));
2817 return (ret);
2821 * get or get a band specific variable
2822 * the band can be a/b/all or omitted. "all"(set only)
2823 * means all supported bands. blank means current band
2825 static int
2826 wl_band_elm(void *wl, cmd_t *cmd, char **argv)
2828 int ret;
2829 struct {
2830 int val;
2831 int band;
2832 } x;
2833 char *endptr = NULL;
2834 uint argc;
2836 /* eat command name */
2837 argv++;
2839 /* arg count */
2840 for (argc = 0; argv[argc]; argc++)
2843 x.val = 0;
2844 x.band = WLC_BAND_AUTO;
2846 /* First arg: value or band */
2847 if (argc >= 1) {
2848 if (!stricmp(argv[0], "a"))
2849 x.band = WLC_BAND_5G;
2850 else if (!stricmp(argv[0], "b"))
2851 x.band = WLC_BAND_2G;
2852 else if (!stricmp(argv[0], "all"))
2853 x.band = WLC_BAND_ALL;
2854 else {
2855 x.val = strtol(argv[0], &endptr, 0);
2856 if (*endptr != '\0')
2857 return (-1);
2861 /* Second arg: band */
2862 if (argc >= 2) {
2863 if (!stricmp(argv[1], "a"))
2864 x.band = WLC_BAND_5G;
2865 else if (!stricmp(argv[1], "b"))
2866 x.band = WLC_BAND_2G;
2867 else if (!stricmp(argv[1], "all"))
2868 x.band = WLC_BAND_ALL;
2869 else
2870 return (-1);
2873 /* issue the get or set ioctl */
2874 if ((argc == 0) || ((argc == 1) && (x.band != WLC_BAND_AUTO))) {
2875 if (x.band == WLC_BAND_ALL) {
2876 printf("band option \"all\" is for set only, not get\n");
2877 return (-1);
2880 x.band = htod32(x.band);
2881 if ((ret = wlu_get(wl, cmd->get, &x, sizeof(x))) < 0)
2882 return (ret);
2884 printf("%s is 0x%04x(%d)\n", cmd->name, (uint16)(dtoh32(x.val)), dtoh32(x.val));
2885 } else {
2886 x.band = htod32(x.band);
2887 x.val = htod32(x.val);
2888 ret = wlu_set(wl, cmd->set, &x, sizeof(x));
2891 return (ret);
2894 /* Command may or may not take a MAC address */
2895 static int
2896 wl_rssi(void *wl, cmd_t *cmd, char **argv)
2898 int ret;
2899 scb_val_t scb_val;
2900 int32 rssi;
2902 if (!*++argv) {
2903 if ((ret = wlu_get(wl, cmd->get, &rssi, sizeof(rssi))) < 0)
2904 return ret;
2905 printf("%d\n", dtoh32(rssi));
2906 return 0;
2907 } else {
2908 if (!wl_ether_atoe(*argv, &scb_val.ea))
2909 return -1;
2910 if ((ret = wlu_get(wl, cmd->get, &scb_val, sizeof(scb_val))) < 0)
2911 return ret;
2912 printf("%d\n", dtoh32(scb_val.val));
2913 return 0;
2917 static int
2918 wl_rssi_event(void *wl, cmd_t *cmd, char **argv)
2920 int ret;
2922 if (!*++argv) {
2923 /* get */
2924 void *ptr = NULL;
2925 wl_rssi_event_t rssi;
2926 uint i;
2928 if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
2929 return ret;
2931 memcpy(&rssi, ptr, sizeof(rssi));
2932 rssi.rate_limit_msec = dtoh32(rssi.rate_limit_msec);
2934 printf("%d", rssi.rate_limit_msec);
2935 for (i = 0; i < rssi.num_rssi_levels; i++) {
2936 printf(" %d", rssi.rssi_levels[i]);
2938 printf("\n");
2939 } else {
2940 /* set */
2941 wl_rssi_event_t rssi;
2943 memset(&rssi, 0, sizeof(wl_rssi_event_t));
2944 rssi.rate_limit_msec = atoi(*argv);
2946 while (*++argv && rssi.num_rssi_levels < MAX_RSSI_LEVELS) {
2947 rssi.rssi_levels[rssi.num_rssi_levels++] = atoi(*argv);
2948 if (rssi.num_rssi_levels > 1) {
2949 if (rssi.rssi_levels[rssi.num_rssi_levels - 1] <=
2950 rssi.rssi_levels[rssi.num_rssi_levels - 2]) {
2951 /* rssi levels must be in increasing order */
2952 return -1;
2957 if (*argv) {
2958 /* too many parameters */
2959 return -1;
2962 rssi.rate_limit_msec = htod32(rssi.rate_limit_msec);
2963 ret = wlu_var_setbuf(wl, cmd->name, &rssi, sizeof(rssi));
2965 return ret;
2968 static int
2969 wl_phy_rssi_ant(void *wl, cmd_t *cmd, char **argv)
2971 int ret = 0;
2972 uint i;
2973 wl_rssi_ant_t *rssi_ant_p;
2975 if (!*++argv) {
2976 /* Get */
2977 void *ptr = NULL;
2979 if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
2980 return ret;
2982 rssi_ant_p = (wl_rssi_ant_t *)ptr;
2983 rssi_ant_p->version = dtoh32(rssi_ant_p->version);
2984 rssi_ant_p->count = dtoh32(rssi_ant_p->count);
2986 if (rssi_ant_p->count == 0) {
2987 printf("not supported on this chip\n");
2988 } else {
2989 for (i = 0; i < rssi_ant_p->count; i++)
2990 printf("rssi[%d] %d ", i, rssi_ant_p->rssi_ant[i]);
2991 printf("\n");
2993 } else {
2994 ret = USAGE_ERROR;
2996 return ret;
2999 /* Commands that take a MAC address */
3000 static int
3001 wl_mac(void *wl, cmd_t *cmd, char **argv)
3003 int ret;
3004 struct ether_addr ea;
3006 if (!*++argv) {
3007 if ((ret = wlu_get(wl, cmd->get, &ea, ETHER_ADDR_LEN)) < 0)
3008 return ret;
3009 printf("%s\n", wl_ether_etoa(&ea));
3010 return 0;
3011 } else {
3012 if (!wl_ether_atoe(*argv, &ea))
3013 return -1;
3014 return wlu_set(wl, cmd->set, &ea, ETHER_ADDR_LEN);
3018 /* IO variables that take a MAC address */
3019 static int
3020 wl_iov_mac(void *wl, cmd_t *cmd, char **argv)
3022 int ret;
3023 struct ether_addr ea = {{0, 0, 0, 0, 0, 0}};
3025 if (argv[1]) { /* set */
3026 if (!wl_ether_atoe(argv[1], &ea)) {
3027 printf(" ERROR: no valid ether addr provided\n");
3028 return -1;
3030 if ((ret = wlu_iovar_set(wl, cmd->name, &ea, ETHER_ADDR_LEN)) < 0) {
3031 printf("Error setting variable %s\n", argv[0]);
3032 return ret;
3034 return 0;
3035 } else { /* get */
3036 if ((ret = wlu_iovar_get(wl, cmd->name, &ea, ETHER_ADDR_LEN)) < 0) {
3037 printf("Error getting variable %s\n", argv[0]);
3038 return ret;
3040 printf("%s %s\n", argv[0], wl_ether_etoa(&ea));
3043 return 0;
3046 static int
3047 wlu_dump(void *wl, cmd_t *cmd, char **argv)
3049 int ret;
3050 char *dump_buf;
3051 int bcmerr;
3053 if (cmd->get < 0)
3054 return -1;
3056 dump_buf = malloc(WL_DUMP_BUF_LEN);
3057 if (dump_buf == NULL) {
3058 fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WL_DUMP_BUF_LEN);
3059 return -1;
3061 memset(dump_buf, 0, WL_DUMP_BUF_LEN);
3063 /* skip the command name */
3064 argv++;
3066 /* If no args given, get the subset of 'wl dump all'
3067 * Otherwise, if args are given, they are the dump section names.
3069 if (*argv == NULL) {
3070 /* query for the 'dump' without any argument */
3071 ret = wlu_iovar_getbuf(wl, "dump", NULL, 0, dump_buf, WL_DUMP_BUF_LEN);
3073 /* if the query is successful, continue on and print the result. */
3075 /* if the query fails, check for a legacy driver that does not support
3076 * the "dump" iovar, and instead issue a WLC_DUMP ioctl.
3078 if (ret) {
3079 wlu_iovar_getint(wl, "bcmerror", &bcmerr);
3080 if (bcmerr == BCME_UNSUPPORTED) {
3081 ret = wlu_get(wl, WLC_DUMP, dump_buf, WL_DUMP_BUF_LEN);
3082 if (ret) {
3083 fprintf(stderr, "dump: error on query of WLC_DUMP\n");
3084 ret = IOCTL_ERROR;
3086 } else {
3087 fprintf(stderr, "dump: error on query of dump list\n");
3088 ret = IOCTL_ERROR;
3091 } else {
3092 /* create the dump section name list */
3093 while (*argv) {
3094 /* add space delimiter if this is not the first section name */
3095 if (dump_buf[0] != '\0')
3096 strcat(dump_buf, " ");
3098 strcat(dump_buf, *argv);
3100 argv++;
3103 /* This is a "space" added at end of last argument */
3104 strcat(dump_buf, " ");
3106 ret = wlu_iovar_getbuf(wl, "dump", dump_buf, strlen(dump_buf),
3107 dump_buf, WL_DUMP_BUF_LEN);
3110 if (!ret) {
3111 fputs(dump_buf, stdout);
3114 free(dump_buf);
3116 return ret;
3120 static int
3121 wlu_srdump(void *wl, cmd_t *cmd, char **argv)
3123 int ret, i, nw, nb = 0;
3124 uint16 *words = (uint16 *)&buf[8];
3126 srom_rw_t *srt;
3128 /* srom has been expanded a few times, at the moment sromrev4/8 are the largest */
3129 nw = SROM4_WORDS;
3131 /* allow reading a larger (or any other-size one) if specified */
3132 if (*++argv != NULL) {
3133 nb = (int)strtol(*argv, NULL, 0);
3134 if (nb & 1) {
3135 printf("Byte count %d is odd\n", nb);
3136 return -1;
3138 nw = nb / 2;
3141 srt = (srom_rw_t *)buf;
3142 srt->byteoff = htod32(0);
3143 srt->nbytes = htod32(2 * nw);
3145 if (cmd->get < 0)
3146 return -1;
3147 if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
3148 return ret;
3149 if ((words[SROM4_SIGN] != SROM4_SIGNATURE) &&
3150 (words[SROM8_SIGN] != SROM4_SIGNATURE))
3151 nw = nb ? nw : SROM_WORDS;
3152 for (i = 0; i < nw; i++) {
3153 if ((i % 8) == 0)
3154 printf("\n srom[%03d]: ", i);
3155 printf("0x%04x ", words[i]);
3157 printf("\n");
3159 return 0;
3162 static int
3163 wlu_srwrite(void *wl, cmd_t *cmd, char **argv)
3165 #if !defined(BWL_FILESYSTEM_SUPPORT)
3166 UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
3167 return (-1);
3168 #elif defined(_CFE_)
3169 UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
3170 return CFE_ERR_UNSUPPORTED;
3171 #else
3172 char *arg;
3173 char *endptr;
3174 FILE *fp = NULL;
3175 int ret = 0, erase, srcrc;
3176 uint i, len;
3177 srom_rw_t *srt = (srom_rw_t *)buf;
3179 erase = !strcmp(*argv, "srclear");
3180 srcrc = !strcmp(*argv, "srcrc");
3182 /* We need at least one arg */
3183 if (!*++argv)
3184 return USAGE_ERROR;
3186 arg = *argv++;
3188 if (erase) {
3189 if (*argv)
3190 return USAGE_ERROR;
3191 len = strtoul(arg, &endptr, 0);
3192 if (*endptr != '\0') {
3193 fprintf(stderr, "error parsing value \"%s\" as an integer for byte count\n",
3194 arg);
3195 return BAD_PARAM;
3197 srt->byteoff = 0x55aa;
3198 } else if (!*argv) { /* srwrite or srcrc */
3199 /* Only one arg, it better be a file name */
3200 if (!(fp = fopen(arg, "rb"))) {
3201 fprintf(stderr, "%s: No such file or directory\n", arg);
3202 return -2;
3205 len = fread(srt->buf, 1, SROM_MAX + 1, fp);
3206 if ((ret = ferror(fp))) {
3207 printf("\nerror %d reading %s\n", ret, arg);
3208 ret = -3;
3209 goto out;
3212 if (!feof(fp)) {
3213 printf("\nFile %s is too large\n", arg);
3214 ret = -4;
3215 goto out;
3218 if (len == SROM4_WORDS * 2) {
3219 if ((srt->buf[SROM4_SIGN] != SROM4_SIGNATURE) &&
3220 (srt->buf[SROM8_SIGN] != SROM4_SIGNATURE)) {
3221 printf("\nFile %s is %d bytes but lacks a REV4/ signature\n",
3222 arg, SROM4_WORDS * 2);
3223 ret = -5;
3224 goto out;
3226 } else if ((len != SROM_WORDS * 2) && (len != SROM_MAX)) {
3227 printf("\nFile %s is %d bytes, not %d or %d or %d bytes\n", arg, len,
3228 SROM_WORDS * 2, SROM4_WORDS * 2, SROM_MAX);
3229 ret = -6;
3230 goto out;
3233 srt->byteoff = 0;
3234 } else {
3235 if (srcrc) {
3236 printf("srcrc only takes one arg\n");
3237 ret = BCME_BADARG;
3238 goto out;
3241 /* More than 1 arg, first is offset, rest are data. */
3242 srt->byteoff = strtoul(arg, &endptr, 0);
3243 if (*endptr != '\0')
3244 goto nout;
3246 i = 0;
3247 while ((arg = *argv++) != NULL) {
3248 srt->buf[i++] = (uint16)strtoul(arg, &endptr, 0);
3249 if (*endptr != '\0') {
3250 nout:
3251 printf("\n%s is not an integer\n", arg);
3252 ret = -7;
3253 goto out;
3257 if (srt->byteoff & 1) {
3258 printf("Byte offset (%d) is odd or negative\n", srt->byteoff);
3259 ret = -8;
3260 goto out;
3263 len = 2 * i;
3264 if ((srt->byteoff + len) > SROM_MAX) {
3265 printf("Data extends past %d bytes\n", SROM_MAX);
3266 ret = -9;
3267 goto out;
3270 srt->nbytes = len;
3272 if (srcrc) {
3273 srt->byteoff = 0x55ab; /* Hack for srcrc */
3274 ret = wlu_get(wl, cmd->get, buf, len + 8);
3275 printf("0x%x\n", (uint8)buf[0]);
3276 } else {
3277 printf("Writing srom. ioctl %d, iolen %d, sroff %d, len %d\n",
3278 cmd->set, len + 8, srt->byteoff, srt->nbytes);
3280 ret = wlu_set(wl, cmd->set, buf, len + 8);
3283 out:
3284 fflush(stdout);
3285 if (fp)
3286 fclose(fp);
3287 return ret;
3288 #endif /* BWL_FILESYSTEM_SUPPORT */
3291 static int
3292 wlu_ciswrite(void *wl, cmd_t *cmd, char **argv)
3294 #if !defined(BWL_FILESYSTEM_SUPPORT)
3295 UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
3296 return (-1);
3297 #elif defined(_CFE_)
3298 UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
3299 return CFE_ERR_UNSUPPORTED;
3300 #else
3301 char *arg, *bufp;
3302 FILE *fp = NULL;
3303 int ret = 0;
3304 uint32 len;
3306 cis_rw_t cish;
3307 char *cisp, *cisdata;
3309 UNUSED_PARAMETER(cmd);
3311 /* We need extacly one arg */
3312 if (!*++argv || argv[1])
3313 return -1;
3315 /* initialize buffer with iovar */
3316 bufp = buf;
3317 memset(buf, 0, WLC_IOCTL_MAXLEN);
3318 strcpy(bufp, "ciswrite");
3319 bufp += strlen("ciswrite") + 1;
3320 cisp = bufp;
3321 cisdata = cisp + sizeof(cish);
3323 cish.source = htod32(0);
3325 /* grab the filename arg */
3326 arg = *argv;
3327 if (!(fp = fopen(arg, "rb"))) {
3328 fprintf(stderr, "%s: No such file or directory\n", arg);
3329 return -2;
3332 len = fread(cisdata, 1, SROM_MAX + 1, fp);
3333 if ((ret = ferror(fp))) {
3334 printf("\nerror %d reading %s\n", ret, arg);
3335 ret = -3;
3336 goto out;
3339 if (!feof(fp)) {
3340 printf("\nFile %s is too large\n", arg);
3341 ret = -4;
3342 goto out;
3345 /* fill in offset and length */
3346 cish.byteoff = htod32(0);
3347 cish.nbytes = htod32(len);
3348 memcpy(cisp, (char*)&cish, sizeof(cish));
3350 printf("len %d sizeof(cish) %d total %d\n", len, (int)sizeof(cish),
3351 (int)(len + sizeof(cish)));
3352 ret = wl_set(wl, WLC_SET_VAR, buf, (cisp - buf) + sizeof(cish) + len);
3353 if (ret < 0) {
3354 fprintf(stderr, "ciswrite failed: %d\n", ret);
3357 out:
3358 if (fp)
3359 fclose(fp);
3361 return ret;
3362 #endif /* BWL_FILESYSTEM_SUPPORT */
3365 static int
3366 wlu_cisupdate(void *wl, cmd_t *cmd, char **argv)
3368 #if defined(_CFE_)
3369 return CFE_ERR_UNSUPPORTED;
3370 #else
3371 char *bufp, *endptr;
3372 int ret = 0;
3373 int preview = 0;
3374 uint32 off;
3375 uint32 len;
3376 uint32 updatelen;
3377 uint32 i;
3378 char hexstr[3];
3379 char bytes[SROM_MAX];
3381 cis_rw_t cish;
3382 char *cisp;
3384 UNUSED_PARAMETER(cmd);
3386 /* validate arg count */
3387 if (!*++argv || !argv[1])
3388 return -1;
3390 if (argv[2] && !strcmp(argv[2], "--preview"))
3391 preview = 1;
3393 /* grab byte offset */
3394 off = (uint32)strtol(argv[0], &endptr, 0);
3395 if (*endptr != '\0')
3396 return -1;
3399 bufp = argv[1];
3400 updatelen = strlen(bufp);
3401 if (updatelen % 2) {
3402 fprintf(stderr, "cisupdate hex string must contain an even number of digits\n");
3403 goto done;
3405 updatelen /= 2;
3407 /* convert and store hex byte values */
3408 for (i = 0; i < updatelen; i++) {
3409 hexstr[0] = *bufp;
3410 hexstr[1] = *(bufp + 1);
3411 if (!isxdigit((int)hexstr[0]) || !isxdigit((int)hexstr[1])) {
3412 fprintf(stderr, "cisupdate invalid hex digit(s) in %s\n", argv[1]);
3413 goto done;
3415 hexstr[2] = '\0';
3416 bytes[i] = (char) strtol(hexstr, NULL, 16);
3417 bufp += 2;
3420 /* Prepare the read info */
3421 cish.source = 0;
3422 cish.byteoff = 0;
3423 cish.nbytes = 0;
3425 /* set up the buffer and do the get (+9 allows space for "ciswrite" string later) */
3426 memset(buf + 9, 0, WLC_IOCTL_MAXLEN);
3427 strcpy(buf + 9, "cisdump");
3428 bufp = buf + strlen("cisdump") + 1 + 9;
3429 memcpy(bufp, (char*)&cish, sizeof(cish));
3430 bufp += sizeof(cish);
3431 ret = wl_get(wl, WLC_GET_VAR, buf + 9, (bufp - (buf + 9)) + SROM_MAX);
3432 if (ret < 0) {
3433 fprintf(stderr, "cisupdate failed to read cis: %d\n", ret);
3434 goto done;
3437 /* pull off the cis_rw_t */
3438 bufp = buf + 9;
3439 memcpy((char*)&cish, bufp, sizeof(cish));
3440 len = dtoh32(cish.nbytes);
3442 if ((off + updatelen) > len) {
3443 fprintf(stderr, "cisupdate offset %d plus update len %d exceeds CIS len %d\n",
3444 off, updatelen, len);
3445 goto done;
3448 /* move past to the data */
3449 bufp += sizeof(cish);
3451 /* update the bytes */
3452 if (cish.source == WLC_CIS_SROM) {
3453 for (i = 0; i < updatelen; ++i)
3454 bufp[off + i] = bytes[i] & 0xff;
3455 } else {
3456 for (i = 0; i < updatelen; ++i) {
3457 if (~bytes[i] & bufp[off + i]) {
3458 fprintf(stderr, "cisupdate: OTP update incompatible:"
3459 " update[%d](0x%02x)->cis[%d](0x%02x)\n",
3460 i, bytes[i], off + i, bufp[off + i]);
3461 goto done;
3463 bufp[off + i] |= bytes[i];
3467 /* initialize buffer with iovar */
3468 bufp = buf;
3469 strcpy(bufp, "ciswrite");
3470 bufp += strlen("ciswrite") + 1;
3471 cisp = bufp;
3473 /* fill in cis_rw_t fields */
3474 cish.source = 0;
3475 cish.byteoff = 0;
3476 cish.nbytes = htod32(len);
3477 memcpy(cisp, (char*)&cish, sizeof(cish));
3479 /* write the data back to the device */
3480 printf("offset %d data %s cislen %d\n", off, argv[1], len);
3481 if (preview) {
3482 bufp += sizeof(cish);
3483 for (i = 0; i < len; i++) {
3484 if ((i % 8) == 0)
3485 printf("\nByte %3d: ", i);
3486 printf("0x%02x ", (uint8)bufp[i]);
3488 printf("\n");
3489 } else {
3490 ret = wl_set(wl, WLC_SET_VAR, buf, (cisp - buf) + sizeof(cish) + len);
3491 if (ret < 0) {
3492 fprintf(stderr, "cisupdate cis write failed: %d\n", ret);
3496 done:
3497 return ret;
3498 #endif /* _CFE_ */
3501 static int
3502 wlu_cisdump(void *wl, cmd_t *cmd, char **argv)
3504 char *bufp;
3505 int i, ret = 0;
3506 cis_rw_t cish;
3507 uint nbytes = 0;
3508 char *fname = NULL;
3510 UNUSED_PARAMETER(cmd);
3512 /* Grab and move past optional output file argument */
3513 if ((argv[1] != NULL) && (strcmp(argv[1], "-b") == 0)) {
3514 fname = argv[2];
3515 argv += 2;
3518 /* check for a length argument */
3519 if (*++argv != NULL) {
3520 nbytes = (int)strtol(*argv, NULL, 0);
3521 if (nbytes & 1) {
3522 printf("Invalid byte count %d, must be even\n", nbytes);
3523 ret = -1;
3524 goto done;
3526 if (nbytes > SROM_MAX) {
3527 printf("Count %d too large\n", nbytes);
3528 ret = -1;
3529 goto done;
3533 /* Prepare the read info */
3534 cish.source = 0;
3535 cish.byteoff = 0;
3536 cish.nbytes = htod32(nbytes);
3538 /* set up the buffer and do the get */
3539 memset(buf, 0, WLC_IOCTL_MAXLEN);
3540 strcpy(buf, "cisdump");
3541 bufp = buf + strlen("cisdump") + 1;
3542 memcpy(bufp, (char*)&cish, sizeof(cish));
3543 bufp += sizeof(cish);
3544 ret = wl_get(wl, WLC_GET_VAR, buf, (bufp - buf) + (nbytes ? nbytes : SROM_MAX));
3545 if (ret < 0) {
3546 fprintf(stderr, "Failed cisdump request: %d\n", ret);
3547 goto done;
3550 /* pull off the cis_rw_t */
3551 bufp = buf;
3552 memcpy((char*)&cish, bufp, sizeof(cish));
3553 cish.source = dtoh32(cish.source);
3554 cish.byteoff = dtoh32(cish.byteoff);
3555 cish.nbytes = dtoh32(cish.nbytes);
3557 /* move past to the data */
3558 bufp += sizeof(cish);
3560 printf("Source: %d (%s)", cish.source,
3561 (cish.source == WLC_CIS_DEFAULT) ? "Built-in default" :
3562 (cish.source == WLC_CIS_SROM) ? "External SPROM" :
3563 (cish.source == WLC_CIS_OTP) ? "Internal OTP" : "Unknown?");
3564 if (!nbytes)
3565 printf("\nMaximum length: %d bytes", cish.nbytes);
3566 for (i = 0; i < (int)cish.nbytes; i++) {
3567 if ((i % 8) == 0)
3568 printf("\nByte %3d: ", i);
3569 printf("0x%02x ", (uint8)bufp[i]);
3571 printf("\n");
3573 #if defined(BWL_FILESYSTEM_SUPPORT)
3574 #if !defined(_CFE_)
3575 if (fname != NULL) {
3576 FILE *fp;
3578 if (!nbytes)
3579 nbytes = cish.nbytes;
3581 fp = fopen(fname, "wb");
3582 if (fp != NULL) {
3583 ret = fwrite(bufp, 1, nbytes, fp);
3584 if (ret != (int)nbytes) {
3585 fprintf(stderr, "Error writing %d bytes to file, rc %d!\n",
3586 (int)nbytes, ret);
3587 ret = -1;
3588 } else {
3589 printf("Wrote %d bytes to %s\n", ret, fname);
3590 ret = 0;
3592 fclose(fp);
3593 } else {
3594 fprintf(stderr, "Problem opening file %s\n", fname);
3595 ret = -1;
3598 #endif /* !(CFE|HNDRTE|IOPOS) -- has stdio filesystem */
3599 #endif /* BWL_FILESYSTEM_SUPPORT */
3601 done:
3602 return ret;
3605 #if defined(linux) || defined(MACOSX) || defined(_CFE_) || defined(__NetBSD__)
3606 /* linux, MacOS, NetBSD: ffs is in the standard C library */
3607 /* CFE, HNDRTE & IOPOS: Not needed, the code below is ifdef out */
3608 #else
3609 static int
3610 ffs(int i)
3612 int j;
3614 if (i != 0)
3615 for (j = 0; j < 32; j++)
3616 if (i & (1 << j))
3617 return j + 1;
3618 return 0;
3620 #endif /* linux, MACOSX, CFE, HNDRTE, IOPOS, NetBSD */
3622 #if !defined(_CFE_)
3624 /* VX wants prototypes even for static functions. */
3625 static char* find_pattern(char **argv, const char *pattern, uint *val);
3626 static int newtuple(char *b, int *cnt, uint8 tag, const cis_tuple_t *srv);
3627 static int parsecis(char *b, char **argv);
3628 static const sromvar_t *srvlookup(const sromvar_t *tab, char *name, int nlen, int sromrev);
3630 /* Find an entry in argv[][] in this form
3631 * name=value, could be pattern=(0x)1234 or pattern=ABC
3633 * If *val is NULL, return the pointer to value.
3634 * If *val is not NULL, fill the value into val, return the pointer to name if found,
3635 * return NULL if no match found.
3637 static char*
3638 find_pattern(char **argv, const char *pattern, uint *val)
3640 char *ret = NULL, *name = NULL, **pargv = argv;
3642 /* clear val first */
3643 if (val) *val = 0;
3645 while ((name = *pargv++)) {
3646 if ((ret = strstr(name, pattern))) {
3647 char *p = ret, *q = NULL;
3649 /* Extracting the content */
3650 p += strlen(pattern);
3652 /* var name could have same prefix */
3653 if (*p++ != '=') {
3654 ret = NULL;
3655 continue;
3657 if (!val) return (ret+strlen(pattern)+1);
3659 *val = strtoul(p, &q, strncmp(p, "0x", 2) ? 10 : 16);
3660 if (p == q) {
3661 printf("Bad value: %s\n", ret);
3662 return NULL;
3665 break;
3668 return ret;
3671 static int
3672 newtuple(char *b, int *cnt, uint8 tag, const cis_tuple_t *srv)
3674 memset(b, 0, srv->len + 2);
3676 b[0] = tag;
3677 b[1] = (char)srv->len;
3678 b[2] = (char)srv->tag;
3680 if (cnt)
3681 *cnt += 3;
3682 return 0;
3685 static int
3686 parsecis(char *b, char **argv)
3688 const cis_tuple_t *srv = cis_hnbuvars;
3689 char *cpar = NULL, *p = NULL;
3690 char par[256]; /* holds longest srv->params */
3691 char delimit[2] = " \0";
3692 int cnt = 0, i = 0;
3694 /* Walk through all the tuples, create append buffer */
3695 while (srv->tag != 0xFF) {
3696 uint val = 0;
3698 /* Special cases (Raw Data / macaddr / ccode / fem) */
3699 if (srv->tag == OTP_RAW || srv->tag == OTP_RAW1) {
3700 if ((p = find_pattern(argv, "RAW", &val))) {
3701 p += (strlen("RAW") + 1); /* RAW= */
3702 for (;;) {
3703 b[cnt++] = (unsigned char) strtoul(p, &p, 16);
3704 if (!*p++)
3705 break;
3708 } else if (srv->tag == OTP_VERS_1) {
3709 uint l1 = 1, l2 = 1;
3710 char *p2 = NULL;
3712 if ((p = find_pattern(argv, "manf", NULL)))
3713 l1 += strlen(p);
3715 if ((p2 = find_pattern(argv, "productname", NULL)))
3716 l2 += strlen(p2);
3718 if ((p != NULL) | (p2 != NULL)) {
3719 b[cnt++] = CISTPL_VERS_1;
3720 b[cnt++] = 2 + l1 + l2;
3721 b[cnt++] = 8;
3722 b[cnt++] = 0;
3723 if (p) {
3724 char *q = p;
3725 /* Replace '_' by space */
3726 while ((q = strchr(q, '_')))
3727 *q = ' ';
3728 memcpy(&b[cnt], p, l1);
3729 } else
3730 b[cnt] = '\0';
3731 cnt += l1;
3733 if (p2) {
3734 char *q = p2;
3735 /* Replace '_' by space */
3736 while ((q = strchr(q, '_')))
3737 *q = ' ';
3738 memcpy(&b[cnt], p2, l2);
3739 } else
3740 b[cnt] = '\0';
3741 cnt += l2;
3743 } else if (srv->tag == OTP_MANFID) {
3744 bool found = FALSE;
3745 uint manfid = 0, prodid = 0;
3747 if ((p = find_pattern(argv, "manfid", &manfid)))
3748 found = TRUE;
3750 if ((p = find_pattern(argv, "prodid", &prodid)))
3751 found = TRUE;
3753 if (found) {
3754 b[cnt++] = CISTPL_MANFID;
3755 b[cnt++] = srv->len;
3756 b[cnt++] = (uint8)(manfid & 0xff);
3757 b[cnt++] = (uint8)((manfid >> 8) & 0xff);
3758 b[cnt++] = (uint8)(prodid & 0xff);
3759 b[cnt++] = (uint8)((prodid >> 8) & 0xff);
3761 } else if (srv->tag == HNBU_MACADDR) {
3762 if ((p = find_pattern(argv, "macaddr", NULL))) {
3763 newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
3764 if (!wl_ether_atoe(p, (struct ether_addr*)&b[cnt]))
3765 printf("Argument does not look like a MAC "
3766 "address: %s\n", p);
3767 cnt += sizeof(struct ether_addr);
3769 } else if (srv->tag == HNBU_CCODE) {
3770 bool found = FALSE;
3771 char tmp[3] = "\0\0\0";
3773 if ((p = find_pattern(argv, "ccode", NULL))) {
3774 found = TRUE;
3775 tmp[0] = *p++;
3776 tmp[1] = *p++;
3778 if ((p = find_pattern(argv, "cctl", &val))) {
3779 found = TRUE;
3780 tmp[2] = (uint8)val;
3782 if (found) {
3783 newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
3784 memcpy(&b[cnt], tmp, 3);
3785 cnt += 3; /* contents filled already */
3787 } else if (srv->tag == HNBU_RSSISMBXA2G) {
3788 bool found = FALSE;
3789 char tmp[2] = "\0\0";
3791 if ((p = find_pattern(argv, "rssismf2g", &val))) {
3792 found = TRUE;
3793 tmp[0] |= val & 0xf;
3795 if ((p = find_pattern(argv, "rssismc2g", &val))) {
3796 found = TRUE;
3797 tmp[0] |= (val & 0xf) << 4;
3799 if ((p = find_pattern(argv, "rssisav2g", &val))) {
3800 found = TRUE;
3801 tmp[1] |= val & 0x7;
3803 if ((p = find_pattern(argv, "bxa2g", &val))) {
3804 found = TRUE;
3805 tmp[1] |= (val & 0x3) << 3;
3807 if (found) {
3808 newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
3809 memcpy(&b[cnt], tmp, 2);
3810 cnt += 2; /* contents filled already */
3812 } else if (srv->tag == HNBU_RSSISMBXA5G) {
3813 bool found = FALSE;
3814 char tmp[2] = "\0\0";
3816 if ((p = find_pattern(argv, "rssismf5g", &val))) {
3817 found = TRUE;
3818 tmp[0] |= val & 0xf;
3820 if ((p = find_pattern(argv, "rssismc5g", &val))) {
3821 found = TRUE;
3822 tmp[0] |= (val & 0xf) << 4;
3824 if ((p = find_pattern(argv, "rssisav5g", &val))) {
3825 found = TRUE;
3826 tmp[1] |= val & 0x7;
3828 if ((p = find_pattern(argv, "bxa5g", &val))) {
3829 found = TRUE;
3830 tmp[1] |= (val & 0x3) << 3;
3832 if (found) {
3833 newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
3834 memcpy(&b[cnt], tmp, 2);
3835 cnt += 2; /* contents filled already */
3837 } else if (srv->tag == HNBU_FEM) {
3838 bool found = FALSE;
3839 uint16 tmp2g = 0, tmp5g = 0;
3841 if ((p = find_pattern(argv, "antswctl2g", &val))) {
3842 found = TRUE;
3843 tmp2g |= ((val << SROM8_FEM_ANTSWLUT_SHIFT) &
3844 SROM8_FEM_ANTSWLUT_MASK);
3846 if ((p = find_pattern(argv, "triso2g", &val))) {
3847 found = TRUE;
3848 tmp2g |= ((val << SROM8_FEM_TR_ISO_SHIFT) &
3849 SROM8_FEM_TR_ISO_MASK);
3851 if ((p = find_pattern(argv, "pdetrange2g", &val))) {
3852 found = TRUE;
3853 tmp2g |= ((val << SROM8_FEM_PDET_RANGE_SHIFT) &
3854 SROM8_FEM_PDET_RANGE_MASK);
3856 if ((p = find_pattern(argv, "extpagain2g", &val))) {
3857 found = TRUE;
3858 tmp2g |= ((val << SROM8_FEM_EXTPA_GAIN_SHIFT) &
3859 SROM8_FEM_EXTPA_GAIN_MASK);
3861 if ((p = find_pattern(argv, "tssipos2g", &val))) {
3862 found = TRUE;
3863 tmp2g |= ((val << SROM8_FEM_TSSIPOS_SHIFT) &
3864 SROM8_FEM_TSSIPOS_MASK);
3866 if ((p = find_pattern(argv, "antswctl5g", &val))) {
3867 found = TRUE;
3868 tmp5g |= ((val << SROM8_FEM_ANTSWLUT_SHIFT) &
3869 SROM8_FEM_ANTSWLUT_MASK);
3871 if ((p = find_pattern(argv, "triso5g", &val))) {
3872 found = TRUE;
3873 tmp5g |= ((val << SROM8_FEM_TR_ISO_SHIFT) &
3874 SROM8_FEM_TR_ISO_MASK);
3876 if ((p = find_pattern(argv, "pdetrange5g", &val))) {
3877 found = TRUE;
3878 tmp5g |= ((val << SROM8_FEM_PDET_RANGE_SHIFT) &
3879 SROM8_FEM_PDET_RANGE_MASK);
3881 if ((p = find_pattern(argv, "extpagain5g", &val))) {
3882 found = TRUE;
3883 tmp5g |= ((val << SROM8_FEM_EXTPA_GAIN_SHIFT) &
3884 SROM8_FEM_EXTPA_GAIN_MASK);
3886 if ((p = find_pattern(argv, "tssipos5g", &val))) {
3887 found = TRUE;
3888 tmp5g |= ((val << SROM8_FEM_TSSIPOS_SHIFT) &
3889 SROM8_FEM_TSSIPOS_MASK);
3892 if (found) {
3893 newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
3894 b[cnt++] = (uint8)(tmp2g & 0xff);
3895 b[cnt++] = (uint8)((tmp2g >> 8) & 0xff);
3896 b[cnt++] = (uint8)(tmp5g & 0xff);
3897 b[cnt++] = (uint8)((tmp5g >> 8) & 0xff);
3899 } else if (srv->tag == HNBU_UUID) {
3901 char *uuidstr = NULL;
3902 char nibble[3] = {0, 0, 0};
3904 if ((uuidstr = find_pattern(argv, "uuid", NULL)) != NULL) {
3906 /* uuid format 12345678-1234-5678-1234-567812345678 */
3908 if (strlen(uuidstr) == 36) {
3909 newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv);
3910 while (*uuidstr != '\0') {
3911 if (*uuidstr == '-') {
3912 uuidstr++;
3913 continue;
3915 nibble[0] = *uuidstr++;
3916 nibble[1] = *uuidstr++;
3917 b[cnt ++] = (strtoul(nibble, NULL, 16) & 0xFF);
3922 } else { /* All other tuples */
3923 int found = FALSE, varlen = 0;
3924 char *cur = &b[cnt];
3925 uint newtp = TRUE;
3927 /* Walk through each parameters in one tuple */
3928 strcpy(par, srv->params);
3930 cpar = strtok (par, delimit); /* current param */
3931 while (cpar) {
3932 val = 0;
3934 /* Fill the CIS tuple to b but don't commit cnt yet */
3935 if (newtp) {
3936 newtuple(cur, NULL, CISTPL_BRCM_HNBU, srv);
3937 cur += 3;
3938 newtp = FALSE;
3941 /* the first byte of each parameter indicates its length */
3942 varlen = (*cpar++) - '0';
3943 /* Find the parameter in the input argument list */
3944 if ((p = find_pattern(argv, cpar, &val)))
3945 found = TRUE;
3947 *cur++ = (uint8)(val & 0xff);
3948 if (varlen >= 2)
3949 *cur++ = (uint8)((val >> 8) & 0xff);
3950 if (varlen >= 4) {
3951 *cur++ = (uint8)((val >> 16) & 0xff);
3952 *cur++ = (uint8)((val >> 24) & 0xff);
3955 /* move to the next parameter string */
3956 cpar = strtok(NULL, delimit);
3959 /* commit the tuple if its valid */
3960 if (found)
3961 cnt += (cur - &b[cnt]);
3964 srv++;
3967 printf("buffer size %d bytes:\n", cnt);
3968 for (i = 0; i < cnt; i++) {
3969 printf("0x%.02x ", b[i] & 0xff);
3970 if (i%8 == 7) printf("\n");
3972 printf("\n");
3974 return cnt;
3977 static const sromvar_t *
3978 srvlookup(const sromvar_t *tab, char *name, int nlen, int sromrev)
3980 uint32 srrmask;
3981 const sromvar_t *srv = tab;
3983 srrmask = 1 << sromrev;
3985 while (srv->name) {
3986 if ((strncmp(name, srv->name, nlen) == 0) &&
3987 ((srrmask & srv->revmask) != 0))
3988 break;
3989 while (srv->flags & SRFL_MORE)
3990 srv++;
3991 srv++;
3994 return srv;
3996 #endif
3998 static int
3999 wl_nvsource(void *wl, cmd_t *cmd, char **argv)
4001 int32 val, err;
4003 if ((err = wl_var_get(wl, cmd, argv)))
4004 return (err);
4006 val = dtoh32(*(int32*)buf);
4008 switch (val) {
4009 case 0:
4010 printf("SROM\n");
4011 break;
4012 case 1:
4013 printf("OTP\n");
4014 break;
4015 default:
4016 printf("Unrecognized source %d\n", val);
4017 break;
4020 return 0;
4023 static int
4024 wlu_srvar(void *wl, cmd_t *cmd, char **argv)
4026 #if defined(_CFE_)
4027 return CFE_ERR_UNSUPPORTED;
4028 #else
4029 int ret, nw, nlen, ro, co, wr, sromrev, shift = 0;
4030 bool otp = FALSE;
4031 uint32 val32 = 0;
4032 char *name, *p, *newval;
4033 const sromvar_t *srv;
4034 uint16 w, *words = (uint16 *)&buf[8];
4035 srom_rw_t *srt;
4036 struct ether_addr ea;
4038 ro = !strcmp(*argv, "rdvar");
4039 wr = !strcmp(*argv, "wrvar");
4040 co = !strcmp(*argv, "cisconvert");
4042 if (!*++argv)
4043 return -1;
4045 /* Check the cis source */
4046 memset(buf, 0, WLC_IOCTL_MAXLEN);
4047 strcpy(buf, "cis_source");
4048 ret = wl_get(wl, WLC_GET_VAR, buf, strlen(buf)+1);
4049 if (ret < 0) {
4050 ; /* printf("Error %x: cannot get cis_source\n", ret); */
4053 if (buf[0] == WLC_CIS_OTP)
4054 otp = TRUE;
4055 if (otp && ro) {
4056 /* Do the same thing as nvget */
4057 wl_nvget(wl, cmd, argv);
4058 return ret;
4061 if ((otp && wr) || co) {
4062 int cnt = 0;
4063 /* leave an empty srom_rw_t at the front for backward
4064 * compatibility
4066 if (!(cnt = parsecis(buf, argv))) {
4067 printf("Nothing to write!\n");
4068 return BCME_ERROR;
4071 if (!co)
4072 /* Pass the append buffer to driver */
4073 ret = wlu_iovar_set(wl, "cisvar", buf, cnt);
4074 return ret;
4077 /* First read the srom and find out the sromrev */
4078 srt = (srom_rw_t *)buf;
4079 srt->byteoff = htod32(0);
4080 srt->nbytes = htod32(2 * SROM4_WORDS);
4082 if (cmd->get < 0)
4083 return -1;
4084 if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
4085 return ret;
4086 if ((words[SROM4_SIGN] != SROM4_SIGNATURE) &&
4087 (words[SROM8_SIGN] != SROM4_SIGNATURE))
4088 nw = SROM_CRCREV;
4089 else
4090 nw = SROM4_CRCREV;
4091 sromrev = words[nw] & 0xff;
4092 if ((sromrev < 2) || (sromrev > SROM_MAXREV)) {
4093 return -2;
4096 nw = 0;
4097 while ((name = *argv++) != NULL) {
4098 int off;
4100 newval = strchr(name, '=');
4101 if (newval)
4102 *newval++ = '\0';
4103 nlen = strlen(name);
4104 if ((nlen == 0) || (nlen > 16)) {
4105 printf("Bad variable name: %s\n", name);
4106 continue;
4108 off = 0;
4109 srv = srvlookup(pci_sromvars, name, nlen + 1, sromrev);
4110 if (srv->name == NULL) {
4111 int path;
4113 srv = srvlookup(perpath_pci_sromvars, name, nlen - 1, sromrev);
4114 path = name[nlen - 1] - '0';
4115 if ((srv->name == NULL) || (path < 0) || (path >= MAX_PATH_SROM)) {
4116 printf("Variable %s does not exist in sromrev %d\n",
4117 name, sromrev);
4118 continue;
4120 if (sromrev >= 8) {
4121 if (path == 0) {
4122 off = SROM8_PATH0;
4123 } else if (path == 1) {
4124 off = SROM8_PATH1;
4125 } else if (path == 2) {
4126 off = SROM8_PATH2;
4127 } else if (path == 3) {
4128 off = SROM8_PATH3;
4130 } else
4131 off = (path == 0) ? SROM4_PATH0 : SROM4_PATH1;
4133 off += srv->off;
4135 if (ro) {
4136 /* This code is cheating a bit: it knows that SRFL_ETHADDR means three
4137 * whole words, and SRFL_MORE means 2 whole words (i.e. the masks for
4138 * them are all 0xffff).
4140 if (srv->flags & SRFL_ETHADDR) {
4141 w = words[off];
4142 ea.octet[0] = w >> 8;
4143 ea.octet[1] = w & 0xff;
4144 w = words[off + 1];
4145 ea.octet[2] = w >> 8;
4146 ea.octet[3] = w & 0xff;
4147 w = words[off + 2];
4148 ea.octet[4] = w >> 8;
4149 ea.octet[5] = w & 0xff;
4150 } else if (srv->flags & SRFL_MORE) {
4151 val32 = words[off];
4152 val32 |= words[srv[1].off] << 16;
4153 } else {
4154 shift = ffs(srv->mask) - 1;
4155 val32 = (words[off] & srv->mask) >> shift;
4158 /* OK, print it */
4159 if (srv->flags & SRFL_ETHADDR)
4160 printf("%s=%s\n", name, wl_ether_etoa(&ea));
4161 else if (srv->flags & SRFL_PRHEX)
4162 printf("%s=0x%x\n", name, val32);
4163 else if (srv->flags & SRFL_PRSIGN)
4164 printf("%s=%d\n", name, val32);
4165 else
4166 printf("%s=%u\n", name, val32);
4168 continue;
4169 } else if (wr && ((srv->flags & (SRFL_MORE |SRFL_ETHADDR)) == 0)) {
4170 shift = ffs(srv->mask) - 1;
4173 /* Make the change in the image we read */
4174 if (!newval) {
4175 printf("wrvar missing value to write for variable %s\n", name);
4176 continue;
4179 if (off > nw)
4180 nw = off;
4182 /* Cheating again as above */
4183 if (srv->flags & SRFL_ETHADDR) {
4184 if (!wl_ether_atoe(newval, &ea)) {
4185 printf("Argument does not look like a MAC address: %s\n", newval);
4186 continue;
4188 words[off] = (ea.octet[0] << 8) | ea.octet[1];
4189 words[off + 1] = (ea.octet[2] << 8) | ea.octet[3];
4190 words[off + 2] = (ea.octet[4] << 8) | ea.octet[5];
4191 nw += 2;
4192 } else {
4193 val32 = strtoul(newval, &p, 0);
4194 if (p == newval) {
4195 printf("Bad value: %s for variable %s\n", newval, name);
4196 continue;
4198 if (srv->flags & SRFL_MORE) {
4199 words[off] = val32 & 0xffff;
4200 words[off + 1] = val32 >> 16;
4201 nw++;
4202 } else {
4203 words[off] = (((val32 << shift) & srv->mask) |
4204 (words[off] & ~srv->mask));
4209 if (!ro) {
4210 /* Now write all the changes */
4211 nw++;
4212 srt->byteoff = 0;
4213 srt->nbytes = htod32(2 * nw);
4214 ret = wlu_set(wl, cmd->set, buf, (2 * nw) + 8);
4215 if (ret < 0)
4216 printf("Error %d writing the srom\n", ret);
4219 return ret;
4220 #endif /* _CFE_ */
4223 /* All 32bits are used. Please populate wl_msgs2[] with further entries */
4224 static dbg_msg_t wl_msgs[] = {
4225 {WL_ERROR_VAL, "error"},
4226 {WL_ERROR_VAL, "err"},
4227 {WL_TRACE_VAL, "trace"},
4228 {WL_PRHDRS_VAL, "prhdrs"},
4229 {WL_PRPKT_VAL, "prpkt"},
4230 {WL_INFORM_VAL, "inform"},
4231 {WL_INFORM_VAL, "info"},
4232 {WL_INFORM_VAL, "inf"},
4233 {WL_TMP_VAL, "tmp"},
4234 {WL_OID_VAL, "oid"},
4235 {WL_RATE_VAL, "rate"},
4236 {WL_ASSOC_VAL, "assoc"},
4237 {WL_ASSOC_VAL, "as"},
4238 {WL_PRUSR_VAL, "prusr"},
4239 {WL_PS_VAL, "ps"},
4240 {WL_TXPWR_VAL, "txpwr"},
4241 {WL_TXPWR_VAL, "pwr"},
4242 {WL_PORT_VAL, "port"},
4243 {WL_DUAL_VAL, "dual"},
4244 {WL_WSEC_VAL, "wsec"},
4245 {WL_WSEC_DUMP_VAL, "wsec_dump"},
4246 {WL_LOG_VAL, "log"},
4247 {WL_NRSSI_VAL, "nrssi"},
4248 {WL_LOFT_VAL, "loft"},
4249 {WL_REGULATORY_VAL, "regulatory"},
4250 {WL_RADAR_VAL, "radar"},
4251 {WL_MPC_VAL, "mpc"},
4252 {WL_APSTA_VAL, "apsta"},
4253 {WL_DFS_VAL, "dfs"},
4254 {WL_BA_VAL, "ba"},
4255 {WL_MBSS_VAL, "mbss"},
4256 {WL_CAC_VAL, "cac"},
4257 {WL_AMSDU_VAL, "amsdu"},
4258 {WL_AMPDU_VAL, "ampdu"},
4259 {WL_FFPLD_VAL, "ffpld"},
4260 {0, NULL}
4263 /* msglevels which use wl_msg_level2 should go here */
4264 static dbg_msg_t wl_msgs2[] = {
4265 {WL_DPT_VAL, "dpt"},
4266 {WL_SCAN_VAL, "scan"},
4267 {WL_WOWL_VAL, "wowl"},
4268 {WL_COEX_VAL, "coex"},
4269 {WL_RTDC_VAL, "rtdc"},
4270 {WL_PROTO_VAL, "proto"},
4271 #ifdef WLBTAMP
4272 {WL_BTA_VAL, "bta"},
4273 #endif
4274 {WL_CHANINT_VAL, "chanim"},
4275 {WL_THERMAL_VAL, "thermal"},
4276 #ifdef WLP2P
4277 {WL_P2P_VAL, "p2p"},
4278 #endif
4279 {WL_ITFR_VAL, "itfr"},
4280 #ifdef WLMCHAN
4281 {WL_MCHAN_VAL, "mchan"},
4282 #endif
4283 {0, NULL}
4286 static int
4287 wl_msglevel(void *wl, cmd_t *cmd, char **argv)
4289 int ret, i;
4290 uint hval = 0, len, val = 0, found, last_val = 0, msglevel = 0, msglevel2_add = 0;
4291 uint msglevel2_del = 0, msglevel_add = 0, msglevel_del = 0, supported = 1;
4292 char *endptr = NULL;
4293 dbg_msg_t *dbg_msg = wl_msgs, *dbg_msg2 = wl_msgs2;
4294 void *ptr = NULL;
4295 struct wl_msglevel2 msglevel64, *reply;
4296 const char *cmdname = "msglevel";
4298 UNUSED_PARAMETER(cmd);
4300 /* but preseve older IOCTL call for older drivers */
4301 if ((ret = wlu_var_getbuf_sm(wl, cmdname, &msglevel64, sizeof(msglevel64), &ptr) < 0)) {
4302 if ((ret = wlu_get(wl, WLC_GET_MSGLEVEL, &msglevel, sizeof(int))) < 0)
4303 return (ret);
4304 supported = 0;
4305 msglevel = dtoh32(msglevel);
4306 if (!*++argv) {
4307 printf("0x%x ", msglevel);
4308 for (i = 0; (val = dbg_msg[i].value); i++) {
4309 if ((msglevel & val) && (val != last_val))
4310 printf(" %s", dbg_msg[i].string);
4311 last_val = val;
4313 printf("\n");
4314 return (0);
4316 while (*argv) {
4317 char *s = *argv;
4318 if (*s == '+' || *s == '-')
4319 s++;
4320 else
4321 msglevel_del = ~0; /* make the whole list absolute */
4322 val = strtoul(s, &endptr, 0);
4323 if (val == 0xFFFFFFFF) {
4324 fprintf(stderr,
4325 "Bits >32 are not supported on this driver version\n");
4326 val = 1;
4328 /* not an integer if not all the string was parsed by strtoul */
4329 if (*endptr != '\0') {
4330 for (i = 0; (val = dbg_msg[i].value); i++)
4331 if (stricmp(dbg_msg[i].string, s) == 0)
4332 break;
4333 if (!val)
4334 goto usage;
4336 if (**argv == '-')
4337 msglevel_del |= val;
4338 else
4339 msglevel_add |= val;
4340 ++argv;
4342 msglevel &= ~msglevel_del;
4343 msglevel |= msglevel_add;
4344 msglevel = htod32(msglevel);
4345 return (wlu_set(wl, WLC_SET_MSGLEVEL, &msglevel, sizeof(int)));
4346 } else { /* 64bit message level */
4347 reply = (struct wl_msglevel2 *)ptr;
4348 reply->low = dtoh32(reply->low);
4349 reply->high = dtoh32(reply->high);
4350 if (!*++argv) {
4351 if (reply->high != 0)
4352 printf("0x%x%08x", reply->high, reply->low);
4353 else
4354 printf("0x%x ", reply->low);
4355 for (i = 0; (val = dbg_msg2[i].value); i++) {
4356 if (((reply->high & val)) && (val != last_val))
4357 printf(" %s", dbg_msg2[i].string);
4358 last_val = val;
4360 last_val = 0;
4361 for (i = 0; (val = dbg_msg[i].value); i++) {
4362 if (((reply->low & val)) && (val != last_val))
4363 printf(" %s", dbg_msg[i].string);
4364 last_val = val;
4366 printf("\n");
4367 return (0);
4369 while (*argv) {
4370 char* s = *argv;
4371 char t[32];
4372 found = 0;
4373 if (*s == '+' || *s == '-')
4374 s++;
4375 else {
4376 msglevel_del = ~0; /* make the whole list absolute */
4377 msglevel2_del = ~0;
4379 val = strtoul(s, &endptr, 0);
4380 if (val == 0xFFFFFFFF){ /* Assume >32 bit hex passed in */
4381 if (!(*s == '0' && *(s+1) == 'x')) {
4382 fprintf(stderr,
4383 "Msg bits >32 take only numerical input in hex\n");
4384 val = 0;
4385 } else {
4386 char c[32] = "0x";
4387 len = strlen(s);
4388 hval = strtoul(strncpy(t, s, len-8), &endptr, 0);
4389 *endptr = 0;
4390 s = s+strlen(t);
4391 s = strcat(c, s);
4392 val = strtoul(s, &endptr, 0);
4393 if (hval == 0xFFFFFFFF) {
4394 fprintf(stderr, "Invalid entry for msglevel\n");
4395 hval = 0;
4396 val = 0;
4400 if (*endptr != '\0') {
4401 for (i = 0; (val = dbg_msg[i].value); i++) {
4402 if (stricmp(dbg_msg[i].string, s) == 0) {
4403 found = 1;
4404 break;
4407 if (!found) {
4408 for (i = 0; (hval = dbg_msg2[i].value); i++)
4409 if (stricmp(dbg_msg2[i].string, s) == 0)
4410 break;
4412 if (!val && !hval)
4413 goto usage;
4415 if (**argv == '-') {
4416 msglevel_del |= val;
4417 if (!found)
4418 msglevel2_del |= hval;
4420 else {
4421 msglevel_add |= val;
4422 if (!found)
4423 msglevel2_add |= hval;
4425 ++argv;
4427 reply->low &= ~msglevel_del;
4428 reply->high &= ~msglevel2_del;
4429 reply->low |= msglevel_add;
4430 reply->high |= msglevel2_add;
4431 reply->low = htod32(reply->low);
4432 reply->high = htod32(reply->high);
4433 msglevel64.low = reply->low;
4434 msglevel64.high = reply->high;
4435 return (wlu_var_setbuf(wl, cmdname, &msglevel64, sizeof(msglevel64)));
4438 usage:
4439 fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");
4440 fprintf(stderr, "Use a + or - prefix to make an incremental change.");
4442 for (i = 0; (val = dbg_msg[i].value); i++) {
4443 if (val != last_val)
4444 fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string);
4445 else
4446 fprintf(stderr, ", %s", dbg_msg[i].string);
4447 last_val = val;
4449 if (supported) {
4450 for (i = 0; (val = dbg_msg2[i].value); i++) {
4451 if (val != last_val)
4452 fprintf(stderr, "\n0x%x00000000 %s", val, dbg_msg2[i].string);
4453 else
4454 fprintf(stderr, ", %s", dbg_msg2[i].string);
4455 last_val = val;
4458 fprintf(stderr, "\n");
4459 return 0;
4462 /* make sure the PHY msg level here are in sync with wlc_phy_int.h */
4463 #define WL_PHYHAL_ERROR 0x0001
4464 #define WL_PHYHAL_TRACE 0x0002
4465 #define WL_PHYHAL_INFORM 0x0004
4466 #define WL_PHYHAL_TMP 0x0008
4467 #define WL_PHYHAL_TXPWR 0x0010
4468 #define WL_PHYHAL_CAL 0x0020
4469 #define WL_PHYHAL_ACI 0x0040
4470 #define WL_PHYHAL_RADAR 0x0080
4471 #define WL_PHYHAL_THERMAL 0x0100
4473 static phy_msg_t wl_phy_msgs[] = {
4474 {WL_PHYHAL_ERROR, "error"},
4475 {WL_PHYHAL_ERROR, "err"},
4476 {WL_PHYHAL_TRACE, "trace"},
4477 {WL_PHYHAL_INFORM, "inform"},
4478 {WL_PHYHAL_TMP, "tmp"},
4479 {WL_PHYHAL_TXPWR, "txpwr"},
4480 {WL_PHYHAL_CAL, "cal"},
4481 {WL_PHYHAL_RADAR, "radar"},
4482 {WL_PHYHAL_THERMAL, "thermal"},
4483 {0, NULL}
4486 static int
4487 wl_phymsglevel(void *wl, cmd_t *cmd, char **argv)
4489 int ret, i;
4490 uint val = 0, last_val = 0;
4491 uint phymsglevel = 0, phymsglevel_add = 0, phymsglevel_del = 0;
4492 char *endptr;
4493 phy_msg_t *phy_msg = wl_phy_msgs;
4494 const char *cmdname = "phymsglevel";
4496 UNUSED_PARAMETER(cmd);
4497 if ((ret = wlu_iovar_getint(wl, cmdname, (int *)&phymsglevel) < 0)) {
4498 return ret;
4500 phymsglevel = dtoh32(phymsglevel);
4501 if (!*++argv) {
4502 printf("0x%x ", phymsglevel);
4503 for (i = 0; (val = phy_msg[i].value); i++) {
4504 if ((phymsglevel & val) && (val != last_val))
4505 printf(" %s", phy_msg[i].string);
4506 last_val = val;
4508 printf("\n");
4509 return (0);
4511 while (*argv) {
4512 char *s = *argv;
4513 if (*s == '+' || *s == '-')
4514 s++;
4515 else
4516 phymsglevel_del = ~0; /* make the whole list absolute */
4517 val = strtoul(s, &endptr, 0);
4518 if (val == 0xFFFFFFFF) {
4519 fprintf(stderr,
4520 "Bits >32 are not supported on this driver version\n");
4521 val = 1;
4523 /* not an integer if not all the string was parsed by strtoul */
4524 if (*endptr != '\0') {
4525 for (i = 0; (val = phy_msg[i].value); i++)
4526 if (stricmp(phy_msg[i].string, s) == 0)
4527 break;
4528 if (!val)
4529 goto usage;
4531 if (**argv == '-')
4532 phymsglevel_del |= val;
4533 else
4534 phymsglevel_add |= val;
4535 ++argv;
4537 phymsglevel &= ~phymsglevel_del;
4538 phymsglevel |= phymsglevel_add;
4539 phymsglevel = htod32(phymsglevel);
4540 return (wlu_iovar_setint(wl, cmdname, (int)phymsglevel));
4542 usage:
4543 fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");
4544 fprintf(stderr, "Use a + or - prefix to make an incremental change.");
4545 for (i = 0; (val = phy_msg[i].value); i++) {
4546 if (val != last_val)
4547 fprintf(stderr, "\n0x%04x %s", val, phy_msg[i].string);
4548 else
4549 fprintf(stderr, ", %s", phy_msg[i].string);
4550 last_val = val;
4552 return 0;
4555 /* take rate arg in units of 500Kbits/s and print it in units of Mbit/s */
4556 static void
4557 wl_printrate(int val)
4559 char rate_buf[32];
4561 printf("%s\n", rate_int2string(rate_buf, val));
4564 /* convert rate string in Mbit/s format, like "11", "5.5", to internal 500 Kbit/s units */
4565 static int
4566 rate_string2int(char *s)
4568 if (!stricmp(s, "-1"))
4569 return (0);
4570 if (!stricmp(s, "5.5"))
4571 return (11);
4572 return (atoi(s) * 2);
4575 /* convert rate internal 500 Kbits/s units to string in Mbits/s format, like "11", "5.5" */
4576 static char*
4577 rate_int2string(char *rate_buf, int val)
4579 if ((val == -1) || (val == 0))
4580 sprintf(rate_buf, "auto");
4581 else if (val > 1000) /* this indicates that units are kbps */
4582 sprintf(rate_buf, "%d Kbps", val);
4583 else
4584 sprintf(rate_buf, "%d%s Mbps", (val / 2), (val & 1) ? ".5" : "");
4585 return (rate_buf);
4588 /* handles both "rate" and "mrate", which makes the flow a bit complex */
4589 static int
4590 wl_rate_mrate(void *wl, cmd_t *cmd, char **argv)
4592 int error;
4593 int val;
4594 int band;
4595 int list[3];
4596 char aname[sizeof("a_mrate") + 1];
4597 char bgname[sizeof("bg_mrate") + 1];
4598 char *name;
4600 sprintf(aname, "a_%s", *argv);
4601 sprintf(bgname, "bg_%s", *argv);
4604 if ((error = wlu_get(wl, WLC_GET_BAND, &band, sizeof(uint))) < 0)
4605 return error;
4606 band = dtoh32(band);
4608 if ((error = wlu_get(wl, WLC_GET_BANDLIST, list, sizeof(list))) < 0)
4609 return error;
4610 list[0] = dtoh32(list[0]);
4611 list[1] = dtoh32(list[1]);
4612 list[2] = dtoh32(list[2]);
4614 if (!list[0])
4615 return -1;
4616 else if (list[0] > 2)
4617 list[0] = 2;
4619 if ((!strcmp(*argv, "rate"))) {
4620 /* it is "rate" */
4621 if (!*++argv) {
4622 /* it is "rate" get. handle it here */
4623 /* WLC_GET_RATE processing */
4624 if ((error = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0)
4625 return error;
4627 val = dtoh32(val);
4628 wl_printrate(val);
4629 return 0;
4631 else
4632 --argv; /* move it back for later processing */
4635 switch (band) {
4636 case WLC_BAND_AUTO :
4637 if (list[0] > 1)
4638 return -1;
4639 else if (list[1] == WLC_BAND_5G)
4640 name = (char *)aname;
4641 else if (list[1] == WLC_BAND_2G)
4642 name = (char *)bgname;
4643 else
4644 return -1;
4646 break;
4648 case WLC_BAND_5G :
4649 name = (char *)aname;
4650 break;
4652 case WLC_BAND_2G :
4653 name = (char *)bgname;
4654 break;
4656 default :
4657 return -1;
4658 break;
4661 if (!*++argv) {
4662 /* it is "mrate" get */
4663 if ((error = wlu_iovar_getint(wl, name, &val) < 0))
4664 return error;
4666 if (val == 0)
4667 printf("auto\n");
4668 else
4669 wl_printrate(val);
4671 return 0;
4672 } else {
4673 val = rate_string2int(*argv);
4674 return wlu_iovar_setint(wl, name, val);
4678 static int
4679 wl_wepstatus(void *wl, cmd_t *cmd, char **argv)
4681 int val, error;
4682 const char *name = "wsec";
4683 int wsec;
4685 UNUSED_PARAMETER(cmd);
4687 if (!*++argv) {
4688 if ((error = wlu_iovar_getint(wl, name, &val) < 0))
4689 return error;
4691 printf("%d\n", val);
4692 return 0;
4693 } else {
4694 val = atoi(*argv);
4695 if ((error = wlu_iovar_getint(wl, name, &wsec) < 0))
4696 return error;
4698 if (val)
4699 wsec |= WEP_ENABLED;
4700 else
4701 wsec &= ~WEP_ENABLED;
4703 return wlu_iovar_setint(wl, name, wsec);
4707 static int
4708 wl_bss_max(void *wl, cmd_t *cmd, char **argv)
4710 int val = 1;
4711 int error;
4713 UNUSED_PARAMETER(argv);
4715 /* Get the CAP variable; search for mbss4 or mbss16 */
4716 strcpy(buf, "cap");
4717 if ((error = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0)
4718 return (error);
4719 if (strstr(buf, "mbss16")) val = 16;
4720 else if (strstr(buf, "mbss4")) val = 4;
4722 printf("%d\n", val);
4723 return (0);
4726 static int
4727 wl_phy_rate(void *wl, cmd_t *cmd, char **argv)
4729 int val, error;
4730 int *pval;
4731 char *p;
4733 if (!*++argv) {
4734 pval = (int *) buf;
4735 strcpy(buf, cmd->name);
4736 if ((error = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0)
4737 return (error);
4738 val = dtoh32(*pval);
4739 wl_printrate(val);
4740 return (0);
4741 } else {
4742 val = htod32(rate_string2int(*argv));
4744 /* construct an iovar */
4745 strcpy(buf, cmd->name);
4746 p = &buf[strlen(buf) + 1];
4747 memcpy(p, &val, sizeof(uint));
4748 p += sizeof(uint);
4750 return (wlu_set(wl, cmd->set, &buf[0], (p - buf)));
4754 static int
4755 wl_nrate(void *wl, cmd_t *cmd, char **argv)
4757 miniopt_t to;
4758 const char* fn_name = "wl_nrate", *rspec_auto = "auto";
4759 bool mcs_set = FALSE, legacy_set = FALSE, stf_set = FALSE;
4760 bool mcs_only = FALSE;
4761 int err, opt_err;
4762 uint32 val = 0;
4763 uint32 nrate = 0;
4764 uint stf;
4766 /* toss the command name */
4767 argv++;
4769 if (!*argv) {
4770 if (cmd->get < 0)
4771 return -1;
4772 if ((err = wlu_iovar_getint(wl, "nrate", (int*)&val)) < 0)
4773 return err;
4775 if (!val) {
4776 printf("auto\n");
4777 } else {
4778 stf = (uint)((val & NRATE_STF_MASK) >> NRATE_STF_SHIFT);
4779 nrate = (val & NRATE_RATE_MASK);
4780 if (val & NRATE_OVERRIDE) {
4781 if (val & NRATE_OVERRIDE_MCS_ONLY)
4782 rspec_auto = "fixed mcs only";
4783 else
4784 rspec_auto = "fixed";
4787 if (val & NRATE_MCS_INUSE)
4788 printf("mcs index %d stf mode %d %s\n",
4789 nrate, stf, rspec_auto);
4790 else
4791 printf("legacy rate %d%s Mbps stf mode %d %s\n",
4792 nrate/2, (nrate % 2)?".5":"", stf, rspec_auto);
4794 return 0;
4797 miniopt_init(&to, fn_name, "w", FALSE);
4798 while ((opt_err = miniopt(&to, argv)) != -1) {
4799 if (opt_err == 1) {
4800 err = -1;
4801 goto exit;
4803 argv += to.consumed;
4805 if (to.opt == 'r') {
4806 if (!to.good_int) {
4807 /* special case check for "-r 5.5" */
4808 if (!strcmp(to.valstr, "5.5")) {
4809 to.val = 11;
4810 } else {
4811 fprintf(stderr,
4812 "%s: could not parse \"%s\" as a rate value\n",
4813 fn_name, to.valstr);
4814 err = -1;
4815 goto exit;
4817 } else
4818 to.val = to.val*2;
4819 if (mcs_set) {
4820 fprintf(stderr, "%s: cannot use -r and -m\n", fn_name);
4821 err = -1;
4822 goto exit;
4824 nrate |= to.val & NRATE_RATE_MASK;
4825 legacy_set = TRUE;
4827 if (to.opt == 'm') {
4828 if (!to.good_int) {
4829 fprintf(stderr,
4830 "%s: could not parse \"%s\" as an int for mcs\n",
4831 fn_name, to.valstr);
4832 err = -1;
4833 goto exit;
4835 if (legacy_set) {
4836 fprintf(stderr, "%s: cannot use -r and -m\n", fn_name);
4837 err = -1;
4838 goto exit;
4840 mcs_set = TRUE;
4841 nrate |= to.val & NRATE_RATE_MASK;
4842 nrate |= NRATE_MCS_INUSE;
4844 if (to.opt == 's') {
4845 if (!to.good_int) {
4846 fprintf(stderr,
4847 "%s: could not parse \"%s\" as an int for stf mode\n",
4848 fn_name, to.valstr);
4849 err = -1;
4850 goto exit;
4852 nrate |= (to.val << NRATE_STF_SHIFT) & NRATE_STF_MASK;
4853 stf_set = TRUE;
4855 if (to.opt == 'w') {
4856 nrate |= NRATE_OVERRIDE_MCS_ONLY;
4857 mcs_only = TRUE;
4861 if ((mcs_only && !mcs_set) || (mcs_only && (stf_set || legacy_set))) {
4862 fprintf(stderr, "%s: can use -w only with -m\n", fn_name);
4863 err = -1;
4864 goto exit;
4867 if (!stf_set) {
4868 stf = 0;
4869 if (legacy_set)
4870 stf = NRATE_STF_SISO; /* SISO */
4871 else if (mcs_set) {
4872 if ((nrate & NRATE_RATE_MASK) <= HIGHEST_SINGLE_STREAM_MCS ||
4873 (nrate & NRATE_RATE_MASK) == 32)
4874 stf = NRATE_STF_SISO; /* SISO */
4875 else
4876 stf = NRATE_STF_SDM; /* SDM */
4878 nrate |= (stf << NRATE_STF_SHIFT) & NRATE_STF_MASK;
4881 if (legacy_set || mcs_set) {
4882 err = wlu_iovar_setint(wl, "nrate", (int)nrate);
4883 } else {
4884 fprintf(stderr, "%s: you need to set a legacy or mcs rate\n", fn_name);
4885 err = -1;
4888 exit:
4889 return err;
4892 static int
4893 wl_assoc_info(void *wl, cmd_t *cmd, char **argv)
4895 uint i, req_ies_len = 0, resp_ies_len = 0;
4896 wl_assoc_info_t assoc_info;
4897 int ret;
4898 uint8 *pbuf;
4900 UNUSED_PARAMETER(argv);
4902 /* get the generic association information */
4903 strcpy(buf, cmd->name);
4904 if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0)
4905 return ret;
4907 memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t));
4908 assoc_info.req_len = htod32(assoc_info.req_len);
4909 assoc_info.resp_len = htod32(assoc_info.resp_len);
4910 assoc_info.flags = htod32(assoc_info.flags);
4912 printf("Assoc req:\n");
4913 printf("\tlen 0x%x\n", assoc_info.req_len);
4914 if (assoc_info.req_len) {
4915 printf("\tcapab 0x%x\n", ltoh16(assoc_info.req.capability));
4916 printf("\tlisten 0x%x\n", ltoh16(assoc_info.req.listen));
4917 req_ies_len = assoc_info.req_len - sizeof(struct dot11_assoc_req);
4918 if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
4919 printf("\treassoc bssid %s\n",
4920 wl_ether_etoa(&assoc_info.reassoc_bssid));
4921 req_ies_len -= ETHER_ADDR_LEN;
4925 /* get the association req IE's if there are any */
4926 if (req_ies_len) {
4927 strcpy(buf, "assoc_req_ies");
4928 if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0)
4929 return ret;
4931 printf("assoc req IEs:\n\t");
4932 for (i = 1, pbuf = (uint8*)buf; i <= req_ies_len; i++) {
4933 printf("0x%02x ", *pbuf++);
4934 if (!(i%8))
4935 printf("\n\t");
4939 printf("\nAssoc resp:\n");
4940 printf("\tlen 0x%x\n", assoc_info.resp_len);
4941 if (assoc_info.resp_len) {
4942 printf("\tcapab 0x%x\n", ltoh16(assoc_info.resp.capability));
4943 printf("\tstatus 0x%x\n", ltoh16(assoc_info.resp.status));
4944 printf("\taid 0x%x\n", ltoh16(assoc_info.resp.aid));
4945 resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp);
4948 /* get the association resp IE's if there are any */
4949 if (resp_ies_len) {
4950 strcpy(buf, "assoc_resp_ies");
4951 if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0)
4952 return ret;
4954 printf("assoc resp IEs:\n\t");
4955 for (i = 1, pbuf = (uint8*)buf; i <= resp_ies_len; i++) {
4956 printf(" 0x%02x ", *pbuf++);
4957 if (!(i%8))
4958 printf("\n\t");
4962 printf("\n");
4964 return 0;
4967 static int
4968 wl_pmkid_info(void *wl, cmd_t *cmd, char**argv)
4970 int i, j, ret;
4971 pmkid_list_t *pmkid_info;
4973 if (!*++argv) {
4974 strcpy(buf, cmd->name);
4975 if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0)
4976 return ret;
4978 pmkid_info = (pmkid_list_t *)buf;
4979 pmkid_info->npmkid = dtoh32(pmkid_info->npmkid);
4980 printf("\npmkid entries : %d\n", pmkid_info->npmkid);
4982 for (i = 0; i < (int)pmkid_info->npmkid; i++) {
4983 printf("\tPMKID[%d]: %s =",
4984 i, wl_ether_etoa(&pmkid_info->pmkid[i].BSSID));
4985 for (j = 0; j < WPA2_PMKID_LEN; j++)
4986 printf("%02x ", pmkid_info->pmkid[i].PMKID[j]);
4987 printf("\n");
4990 else {
4991 #ifdef test_pmkid_info
4992 char eaddr[6] = {0x0, 0x0, 0x1, 0x2, 0x3, 0x5};
4993 char eaddr1[6] = {0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
4994 char id[WPA2_PMKID_LEN], id1[WPA2_PMKID_LEN];
4995 int i, len = (sizeof(uint32) + 2*(sizeof(pmkid_t)));
4997 /* check that the set uses to "test" cmd */
4998 if (strcmp(*argv, "test")) {
4999 printf("\t wl pmkid_info only supports `test` a test specific set\n");
5000 return -1;
5002 if ((pmkid_info = (pmkid_list_t *)malloc(len)) == NULL) {
5003 printf("\tfailed to allocate buffer\n");
5004 return -1;
5007 printf("\toverwriting pmkid table with test pattern\n");
5008 for (i = 0; i < (int)sizeof(id); i++) {
5009 id[i] = i;
5010 id1[i] = (i*2);
5013 /* "test" - creates two PMKID entries and sets the table to that */
5014 pmkid_info->npmkid = htod32(2);
5015 memcpy(&pmkid_info->pmkid[0].BSSID.octet[0], &eaddr[0], ETHER_ADDR_LEN);
5016 memcpy(&pmkid_info->pmkid[0].PMKID[0], &id[0], WPA2_PMKID_LEN);
5017 memcpy(&pmkid_info->pmkid[1].BSSID.octet[0], &eaddr1[0], ETHER_ADDR_LEN);
5018 memcpy(&pmkid_info->pmkid[1].PMKID[0], &id1[0], WPA2_PMKID_LEN);
5020 ret = wlu_var_setbuf(wl, cmd->name, pmkid_info, len);
5022 free(pmkid_info);
5024 return ret;
5025 #else
5026 printf("\tset cmd ignored\n");
5027 #endif /* test_pmkid_info */
5030 return 0;
5033 static int
5034 wl_rateset(void *wl, cmd_t *cmd, char **argv)
5036 wl_rateset_args_t rs, defrs;
5037 int error;
5038 uint i;
5040 UNUSED_PARAMETER(cmd);
5042 error = 0;
5044 argv++;
5046 if (*argv == NULL) {
5047 /* get current rateset */
5048 if ((error = wlu_iovar_get(wl, "cur_rateset", &rs, sizeof(rs))) < 0)
5049 return (error);
5051 dump_rateset(rs.rates, dtoh32(rs.count));
5052 printf("\n");
5053 wl_print_mcsset((char *)rs.mcs);
5054 } else {
5055 /* get default rateset and mcsset */
5056 if ((error = wlu_iovar_get(wl, "rateset", &defrs,
5057 sizeof(wl_rateset_args_t))) < 0)
5058 return (error);
5059 defrs.count = dtoh32(defrs.count);
5061 if (!stricmp(*argv, "all")) {
5062 for (i = 0; i < defrs.count; i++)
5063 defrs.rates[i] |= 0x80;
5064 defrs.count = htod32(defrs.count);
5065 error = wlu_iovar_set(wl, "rateset", &defrs,
5066 sizeof(wl_rateset_args_t));
5068 else if (!stricmp(*argv, "default")) {
5069 defrs.count = htod32(defrs.count);
5070 error = wlu_iovar_set(wl, "rateset", &defrs,
5071 sizeof(wl_rateset_args_t));
5073 else { /* arbitrary list */
5074 wl_parse_rateset(wl, &defrs, argv);
5075 /* check for common error of no basic rates */
5076 for (i = 0; i < defrs.count; i++) {
5077 if (defrs.rates[i] & 0x80)
5078 break;
5080 if (i < defrs.count) {
5081 defrs.count = htod32(defrs.count);
5082 error = wlu_iovar_set(wl, "rateset", &defrs,
5083 sizeof(wl_rateset_args_t));
5084 } else {
5085 error = -1;
5086 fprintf(stderr,
5087 "Bad Args: at least one rate must be marked Basic\n");
5093 return (error);
5096 static int
5097 wl_sup_rateset(void *wl, cmd_t *cmd, char **argv)
5099 wl_rateset_args_t rs;
5100 bool got_basic;
5101 int error;
5102 uint i;
5104 error = 0;
5105 memset((char*)&rs, 0, sizeof(wl_rateset_args_t));
5107 argv++;
5109 if (*argv == NULL) {
5110 /* get rateset */
5111 if ((error = wlu_get(wl, cmd->get, &rs, sizeof(wl_rateset_t))) < 0)
5112 return (error);
5114 dump_rateset(rs.rates, dtoh32(rs.count));
5115 printf("\n");
5116 } else {
5117 if (!stricmp(*argv, "-1") || !stricmp(*argv, "0")) {
5118 /* set an empty rateset */
5119 error = wlu_set(wl, cmd->set, &rs, sizeof(wl_rateset_t));
5121 else { /* set the specified rateset */
5122 wl_parse_rateset(wl, &rs, argv);
5123 /* check for common error of including a basic rate */
5124 got_basic = FALSE;
5125 for (i = 0; i < rs.count; i++) {
5126 if (rs.rates[i] & 0x80) {
5127 rs.rates[i] &= 0x7F;
5128 got_basic = TRUE;
5131 if (got_basic) {
5132 fprintf(stderr,
5133 "Warning: Basic rate attribute ignored for \"%s\" command\n",
5134 cmd->name);
5136 rs.count = htod32(rs.count);
5137 error = wlu_set(wl, cmd->set, &rs, sizeof(wl_rateset_t));
5141 return (error);
5144 static int
5145 wl_parse_rateset(void *wl, wl_rateset_args_t* rs, char **argv)
5147 char* endp = NULL;
5148 char* arg;
5149 int r;
5150 int error = 0;
5151 int i = 0, m;
5152 bool mcs_args = FALSE;
5153 wl_rateset_args_t cur_rs;
5155 memset(rs, 0, sizeof(*rs));
5157 while ((arg = *argv++) != NULL) {
5158 /* mcs rates */
5159 if (!stricmp(arg, "-m")) {
5160 mcs_args = TRUE;
5161 break;
5164 if (rs->count >= WL_NUMRATES) {
5165 fprintf(stderr,
5166 "parsing \"%s\", too many rates specified, max is %d rates\n",
5167 arg, WL_NUMRATES);
5168 error = -1;
5169 break;
5172 /* convert the rate number to a 500kbps rate by multiplying by 2 */
5173 r = (int)(strtoul(arg, &endp, 0) * 2);
5174 if (endp == arg) {
5175 fprintf(stderr, "unable to convert the rate parameter \"%s\"\n", arg);
5176 error = -1;
5177 break;
5180 /* parse a .5 specially */
5181 if (!strncmp(endp, ".5", 2)) {
5182 r += 1;
5183 endp += 2;
5186 /* strip trailing space */
5187 while (isspace((int)endp[0]))
5188 endp++;
5190 /* check for a basic rate specifier */
5191 if (!stricmp(endp, "b") || !stricmp(endp, "(b)")) {
5192 r |= 0x80;
5193 } else if (endp[0] != '\0') {
5194 fprintf(stderr,
5195 "unable to convert trailing characters"
5196 " \"%s\" in the rate parameter \"%s\"\n",
5197 endp, arg);
5198 error = -1;
5199 break;
5202 /* no legacy rates specified */
5203 if ((rs->count == 0) && (r == 0)) {
5204 fprintf(stderr, "empty legacy rateset not supported\n");
5205 error = -1;
5206 break;
5209 rs->rates[rs->count++] = r;
5212 if (error)
5213 return error;
5215 if (!mcs_args) {
5216 /* if legacy rates are specified and not the mcs rates then
5217 * it implies that the user is trying to change only the
5218 * legacy rates. to avoid clearing the mcsset first get
5219 * the current mcsset and use it to set along with the new
5220 * legacy rateset.
5222 error = wlu_iovar_get(wl, "cur_rateset", &cur_rs, sizeof(cur_rs));
5223 if (!error)
5224 memcpy(rs->mcs, cur_rs.mcs, MCSSET_LEN);
5226 return error;
5229 /* no legacy rates are specified in the command. so get the current
5230 * legacy rateset and use it to set along with new mcsset.
5232 if (rs->count == 0) {
5233 error = wlu_iovar_get(wl, "cur_rateset", &cur_rs, sizeof(cur_rs));
5234 if (!error) {
5235 rs->count = cur_rs.count;
5236 memcpy(&rs->rates, &cur_rs.rates, rs->count);
5237 } else
5238 return error;
5241 /* Parse mcs rateset values */
5242 while ((arg = *argv++) != NULL) {
5243 if (i >= MCSSET_LEN) {
5244 fprintf(stderr, "parsing \"%s\", too many mcs rates "
5245 "specified, max is %d rates\n", arg, MCSSET_LEN);
5246 error = -1;
5247 break;
5250 m = (int)strtoul(arg, &endp, 16);
5252 if (endp == arg) {
5253 fprintf(stderr, "unable to convert the mcs parameter \"%s\"\n", arg);
5254 error = -1;
5255 break;
5258 /* strip trailing space */
5259 while (isspace((int)endp[0]))
5260 endp++;
5262 /* clear the mcs rates */
5263 if (m == 0) {
5264 memset(rs->mcs, 0, MCSSET_LEN);
5265 break;
5268 /* copy the mcs rates bitmap octets */
5269 rs->mcs[i++] = m;
5272 return error;
5275 static int
5276 wl_channel(void *wl, cmd_t *cmd, char **argv)
5278 int ret;
5279 channel_info_t ci;
5281 if (!*++argv) {
5282 memset(&ci, 0, sizeof(ci));
5283 if ((ret = wlu_get(wl, cmd->get, &ci, sizeof(channel_info_t))) < 0)
5284 return ret;
5285 ci.hw_channel = dtoh32(ci.hw_channel);
5286 ci.scan_channel = dtoh32(ci.scan_channel);
5287 ci.target_channel = dtoh32(ci.target_channel);
5288 if (ci.scan_channel) {
5289 printf("Scan in progress.\n");
5290 printf("current scan channel\t%d\n", ci.scan_channel);
5291 } else {
5292 printf("No scan in progress.\n");
5294 printf("current mac channel\t%d\n", ci.hw_channel);
5295 printf("target channel\t%d\n", ci.target_channel);
5296 return 0;
5297 } else {
5298 ci.target_channel = htod32(atoi(*argv));
5299 ret = wlu_set(wl, cmd->set, &ci.target_channel, sizeof(int));
5300 return ret;
5304 static int
5305 wl_chanspec(void *wl, cmd_t *cmd, char **argv)
5307 miniopt_t to;
5308 const char* fn_name = "wl_chanspec";
5309 bool band_set = FALSE, ch_set = FALSE, bw_set = FALSE, ctl_sb_set = FALSE;
5310 int err, opt_err;
5311 uint32 val = 0;
5312 chanspec_t chanspec = 0;
5314 /* toss the command name */
5315 argv++;
5317 if (!*argv) {
5318 if (cmd->get < 0)
5319 return -1;
5320 if ((err = wlu_iovar_getint(wl, cmd->name, (int*)&val)) < 0)
5321 return err;
5323 wf_chspec_ntoa((chanspec_t)val, buf);
5324 printf("%s (0x%x)\n", buf, val);
5325 return 0;
5329 if ((chanspec = wf_chspec_aton(*argv))) {
5330 err = wlu_iovar_setint(wl, cmd->name, (int)chanspec);
5331 } else {
5332 miniopt_init(&to, fn_name, NULL, FALSE);
5333 while ((opt_err = miniopt(&to, argv)) != -1) {
5334 if (opt_err == 1) {
5335 err = -1;
5336 goto exit;
5338 argv += to.consumed;
5340 if (to.opt == 'c') {
5341 if (!to.good_int) {
5342 fprintf(stderr,
5343 "%s: could not parse \"%s\" as an int for"
5344 " the channel\n", fn_name, to.valstr);
5345 err = -1;
5346 goto exit;
5348 if (to.val > 224) {
5349 fprintf(stderr, "%s: invalid channel %d\n",
5350 fn_name, to.val);
5351 err = -1;
5352 goto exit;
5354 chanspec |= to.val;
5355 ch_set = TRUE;
5357 if (to.opt == 'b') {
5358 if (!to.good_int) {
5359 fprintf(stderr,
5360 "%s: could not parse \"%s\" as an int for band\n",
5361 fn_name, to.valstr);
5362 err = -1;
5363 goto exit;
5365 if ((to.val != 5) && (to.val != 2)) {
5366 fprintf(stderr,
5367 "%s: invalid band %d\n",
5368 fn_name, to.val);
5369 err = -1;
5370 goto exit;
5372 if (to.val == 5)
5373 chanspec |= WL_CHANSPEC_BAND_5G;
5374 else
5375 chanspec |= WL_CHANSPEC_BAND_2G;
5376 band_set = TRUE;
5378 if (to.opt == 'w') {
5379 if (!to.good_int) {
5380 fprintf(stderr,
5381 "%s: could not parse \"%s\" as an int for"
5382 " bandwidth\n", fn_name, to.valstr);
5383 err = -1;
5384 goto exit;
5386 if ((to.val != 20) && (to.val != 40)) {
5387 fprintf(stderr,
5388 "%s: invalid bandwidth %d\n",
5389 fn_name, to.val);
5390 err = -1;
5391 goto exit;
5393 if (to.val == 20)
5394 chanspec |= WL_CHANSPEC_BW_20;
5395 else
5396 chanspec |= WL_CHANSPEC_BW_40;
5397 bw_set = TRUE;
5399 if (to.opt == 's') {
5400 if (!to.good_int) {
5401 fprintf(stderr,
5402 "%s: could not parse \"%s\" as an int for"
5403 " ctl sideband\n", fn_name, to.valstr);
5404 err = -1;
5405 goto exit;
5407 if ((to.val != 1) && (to.val != 0) && (to.val != -1)) {
5408 fprintf(stderr,
5409 "%s: invalid ctl sideband %d\n",
5410 fn_name, to.val);
5411 err = -1;
5412 goto exit;
5414 if (to.val == -1)
5415 chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
5416 else if (to.val == 1)
5417 chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
5418 else
5419 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
5420 ctl_sb_set = TRUE;
5424 /* set ctl sb to 20 if not set and 20mhz is selected */
5425 if (!ctl_sb_set && CHSPEC_IS20(chanspec)) {
5426 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
5427 ctl_sb_set = TRUE;
5430 if (ch_set && band_set && bw_set && ctl_sb_set) {
5431 err = wlu_iovar_setint(wl, cmd->name, (int)chanspec);
5432 } else {
5433 if (!ch_set)
5434 fprintf(stderr, "%s: you need to set a channel,"
5435 " '-c <ch>'\n", fn_name);
5436 if (!band_set)
5437 fprintf(stderr, "%s: you need to set a band,"
5438 " '-b <5|2>'\n", fn_name);
5439 if (!bw_set)
5440 fprintf(stderr, "%s: you need to set a bandwidth,"
5441 " '-w <20|40>'\n", fn_name);
5442 if (!ctl_sb_set)
5443 fprintf(stderr, "%s: you need to set a ctl sideband,"
5444 " '-s <-1|0|1>'\n", fn_name);
5445 err = -1;
5449 if (!err)
5450 printf("Chanspec set to 0x%x\n", chanspec);
5452 exit:
5453 return err;
5456 static int
5457 wl_chanim_state(void *wl, cmd_t *cmd, char **argv)
5459 uint32 chanspec;
5460 int argc = 0;
5461 int ret, val;
5463 argv++;
5465 /* find the arg count */
5466 while (argv[argc])
5467 argc++;
5469 if (argc != 1)
5470 return USAGE_ERROR;
5472 chanspec = wf_chspec_aton(*argv);
5474 ret = wlu_iovar_getbuf(wl, cmd->name, &chanspec, sizeof(chanspec),
5475 buf, WLC_IOCTL_SMLEN);
5476 if (ret < 0)
5477 return ret;
5478 val = *(int*)buf;
5479 val = dtoh32(val);
5481 printf("%d\n", val);
5482 return 0;
5485 static int
5486 wl_chanim_mode(void *wl, cmd_t *cmd, char **argv)
5488 int ret;
5489 int val;
5490 char *endptr;
5491 int mode;
5493 if (!*++argv) {
5494 if (cmd->get < 0)
5495 return -1;
5496 if ((ret = wlu_iovar_getint(wl, cmd->name, &mode)) < 0)
5497 return ret;
5499 switch (mode) {
5500 case CHANIM_DISABLE:
5501 printf("CHANIM mode: disabled.\n");
5502 break;
5503 case CHANIM_DETECT:
5504 printf("CHANIM mode: detect only.\n");
5505 break;
5506 case CHANIM_ACT:
5507 printf("CHANIM mode: detect + act.\n");
5508 break;
5510 return 0;
5511 } else {
5512 mode = CHANIM_DETECT;
5513 val = strtol(*argv, &endptr, 0);
5514 if (*endptr != '\0')
5515 return (-1);
5517 switch (val) {
5518 case 0:
5519 mode = CHANIM_DISABLE;
5520 break;
5521 case 1:
5522 mode = CHANIM_DETECT;
5523 break;
5524 case 2:
5525 mode = CHANIM_ACT;
5526 break;
5527 default:
5528 return (-1);
5531 mode = htod32(mode);
5532 return wlu_iovar_setint(wl, cmd->name, mode);
5537 wl_ether_atoe(const char *a, struct ether_addr *n)
5539 char *c = NULL;
5540 int i = 0;
5542 memset(n, 0, ETHER_ADDR_LEN);
5543 for (;;) {
5544 n->octet[i++] = (uint8)strtoul(a, &c, 16);
5545 if (!*c++ || i == ETHER_ADDR_LEN)
5546 break;
5547 a = c;
5549 return (i == ETHER_ADDR_LEN);
5552 char *
5553 wl_ether_etoa(const struct ether_addr *n)
5555 static char etoa_buf[ETHER_ADDR_LEN * 3];
5556 char *c = etoa_buf;
5557 int i;
5559 for (i = 0; i < ETHER_ADDR_LEN; i++) {
5560 if (i)
5561 *c++ = ':';
5562 c += sprintf(c, "%02X", n->octet[i] & 0xff);
5564 return etoa_buf;
5568 wl_atoip(const char *a, struct ipv4_addr *n)
5570 char *c = NULL;
5571 int i = 0;
5573 for (;;) {
5574 n->addr[i++] = (uint8)strtoul(a, &c, 0);
5575 if (*c++ != '.' || i == IPV4_ADDR_LEN)
5576 break;
5577 a = c;
5579 return (i == IPV4_ADDR_LEN);
5582 char *
5583 wl_iptoa(const struct ipv4_addr *n)
5585 static char iptoa_buf[IPV4_ADDR_LEN * 4];
5587 sprintf(iptoa_buf, "%u.%u.%u.%u",
5588 n->addr[0], n->addr[1], n->addr[2], n->addr[3]);
5590 return iptoa_buf;
5594 wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len)
5596 int i, c;
5597 char *p = ssid_buf;
5599 if (ssid_len > 32) ssid_len = 32;
5601 for (i = 0; i < ssid_len; i++) {
5602 c = (int)ssid[i];
5603 if (c == '\\') {
5604 *p++ = '\\';
5605 *p++ = '\\';
5606 } else if (isprint((uchar)c)) {
5607 *p++ = (char)c;
5608 } else {
5609 p += sprintf(p, "\\x%02X", c);
5612 *p = '\0';
5614 return p - ssid_buf;
5617 /* pretty hex print a contiguous buffer */
5618 void
5619 wl_hexdump(uchar *dump_buf, uint nbytes)
5621 char line[256];
5622 char* p;
5623 uint i;
5625 if (nbytes == 0) {
5626 printf("\n");
5627 return;
5630 p = line;
5631 for (i = 0; i < nbytes; i++) {
5632 if (i % 16 == 0 && nbytes > 16) {
5633 p += sprintf(p, "%04d: ", i); /* line prefix */
5635 p += sprintf(p, "%02x ", dump_buf[i]);
5636 if (i % 16 == 15) {
5637 printf("%s\n", line); /* flush line */
5638 p = line;
5642 /* flush last partial line */
5643 if (p != line)
5644 printf("%s\n", line);
5647 static int
5648 wl_plcphdr(void *wl, cmd_t *cmd, char **argv)
5650 int ret;
5651 int val;
5653 if (!*++argv) {
5654 if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0)
5655 return ret;
5656 val = dtoh32(val);
5657 if (val == WLC_PLCP_AUTO)
5658 printf("long");
5659 else if (val == WLC_PLCP_SHORT)
5660 printf("auto");
5661 else if (val == WLC_PLCP_LONG)
5662 printf("debug");
5663 else
5664 printf("unknown");
5665 printf("\n");
5666 return 0;
5667 } else {
5668 if (!stricmp(*argv, "long"))
5669 val = WLC_PLCP_AUTO;
5670 else if (!stricmp(*argv, "auto"))
5671 val = WLC_PLCP_SHORT;
5672 else if (!stricmp(*argv, "debug"))
5673 val = WLC_PLCP_LONG;
5674 else
5675 return -1;
5676 val = htod32(val);
5677 return wlu_set(wl, cmd->set, &val, sizeof(int));
5681 /* WLC_GET_RADIO and WLC_SET_RADIO in driver operate on radio_disabled which
5682 * is opposite of "wl radio [1|0]". So invert for user.
5683 * In addition, display WL_RADIO_SW_DISABLE and WL_RADIO_HW_DISABLE bits.
5685 static int
5686 wl_radio(void *wl, cmd_t *cmd, char **argv)
5688 int ret;
5689 uint val;
5690 char *endptr = NULL;
5692 if (!*++argv) {
5693 if (cmd->get < 0)
5694 return -1;
5695 if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0)
5696 return ret;
5697 val = dtoh32(val);
5698 printf("0x%04x\n", val);
5699 return 0;
5700 } else {
5701 if (cmd->set < 0)
5702 return -1;
5703 if (!stricmp(*argv, "on"))
5704 val = WL_RADIO_SW_DISABLE << 16;
5705 else if (!stricmp(*argv, "off"))
5706 val = WL_RADIO_SW_DISABLE << 16 | WL_RADIO_SW_DISABLE;
5707 else {
5708 val = strtol(*argv, &endptr, 0);
5709 if (*endptr != '\0') {
5710 /* not all the value string was parsed by strtol */
5711 return -1;
5714 /* raw bits setting, add the mask if not provided */
5715 if ((val >> 16) == 0) {
5716 val |= val << 16;
5719 val = htod32(val);
5720 return wlu_set(wl, cmd->set, &val, sizeof(int));
5724 static char *
5725 ver2str(unsigned int vms, unsigned int vls)
5727 static char verstr[100];
5728 unsigned int maj, year, month, day, build;
5730 maj = (vms >> 16) & 0xFFFF;
5731 if (maj > 1000) {
5732 /* it is probably a date... */
5733 year = (vms >> 16) & 0xFFFF;
5734 month = vms & 0xFFFF;
5735 day = (vls >> 16) & 0xFFFF;
5736 build = vls & 0xFFFF;
5737 sprintf(verstr, "%d/%d/%d build %d",
5738 month, day, year, build);
5739 } else {
5740 /* it is a tagged release. */
5741 sprintf(verstr, "%d.%d RC%d.%d",
5742 (vms>>16)&0xFFFF, vms&0xFFFF,
5743 (vls>>16)&0xFFFF, vls&0xFFFF);
5745 return verstr;
5749 static int
5750 wl_version(void *wl, cmd_t *cmd, char **argv)
5752 int ret;
5753 int bcmerr = 0;
5754 char *p = NULL;
5755 char *dump_buf;
5757 UNUSED_PARAMETER(cmd);
5758 UNUSED_PARAMETER(argv);
5760 printf("%s\n",
5761 ver2str(((EPI_MAJOR_VERSION) << 16) | EPI_MINOR_VERSION,
5762 (EPI_RC_NUMBER << 16) | EPI_INCREMENTAL_NUMBER));
5764 dump_buf = malloc(WLC_IOCTL_SMLEN);
5765 if (dump_buf == NULL) {
5766 fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WLC_IOCTL_SMLEN);
5767 return -1;
5769 memset(dump_buf, 0, WLC_IOCTL_SMLEN);
5771 /* query for 'ver' to get version info */
5772 ret = wlu_iovar_get(wl, "ver", dump_buf, WLC_IOCTL_SMLEN);
5774 /* if the query is successful, continue on and print the result. */
5776 /* if the query fails, check for a legacy driver that does not support
5777 * the "dump" iovar, and instead issue a WLC_DUMP ioctl.
5779 if (ret) {
5780 wlu_iovar_getint(wl, "bcmerror", &bcmerr);
5781 if (bcmerr == BCME_UNSUPPORTED) {
5782 ret = wlu_get(wl, WLC_DUMP, dump_buf, WLC_IOCTL_SMLEN);
5786 if (ret) {
5787 fprintf(stderr, "Error %d on query of driver dump\n", (int)ret);
5788 free(dump_buf);
5789 return IOCTL_ERROR;
5792 /* keep only the first line from the dump buf output */
5793 p = strchr(dump_buf, '\n');
5794 if (p)
5795 *p = '\0';
5796 printf("%s\n", dump_buf);
5798 free(dump_buf);
5800 return 0;
5803 static int
5804 wl_rateparam(void *wl, cmd_t *cmd, char **argv)
5806 int val[2];
5808 if (!*++argv)
5809 return -1;
5810 val[0] = htod32(atoi(*argv));
5811 if (!*++argv)
5812 return -1;
5813 val[1] = htod32(atoi(*argv));
5814 return wlu_set(wl, cmd->set, val, 2 * sizeof(val));
5817 /* wl scan
5818 * -s --ssid=ssid_list
5819 * -t T --scan_type=T : [active|passive]
5820 * --bss_type=T : [infra|bss|adhoc|ibss]
5821 * -b --bssid=
5822 * -n --nprobes=
5823 * -a --active=
5824 * -p --passive=
5825 * -h --home=
5826 * -c --channels=
5827 * ssid_list
5830 /* Parse a comma-separated list from list_str into ssid array, starting
5831 * at index idx. Max specifies size of the ssid array. Parses ssids
5832 * and returns updated idx; if idx >= max not all fit, the excess have
5833 * not been copied. Returns -1 on empty string, or on ssid too long.
5835 static int
5836 wl_parse_ssid_list(char* list_str, wlc_ssid_t* ssid, int idx, int max)
5838 char *str, *ptr;
5840 if (list_str == NULL)
5841 return -1;
5843 for (str = list_str; str != NULL; str = ptr) {
5844 if ((ptr = strchr(str, ',')) != NULL)
5845 *ptr++ = '\0';
5847 if (strlen(str) > DOT11_MAX_SSID_LEN) {
5848 fprintf(stderr, "ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN);
5849 return -1;
5851 if (strlen(str) == 0)
5852 ssid[idx].SSID_len = 0;
5854 if (idx < max) {
5855 strcpy((char*)ssid[idx].SSID, str);
5856 ssid[idx].SSID_len = strlen(str);
5858 idx++;
5861 return idx;
5864 static int
5865 wl_scan_prep(void *wl, cmd_t *cmd, char **argv, wl_scan_params_t *params, int *params_size)
5867 int val = 0;
5868 char key[64];
5869 int keylen;
5870 char *p, *eq, *valstr, *endptr = NULL;
5871 char opt;
5872 bool positional_param;
5873 bool good_int;
5874 bool opt_end;
5875 int err = 0;
5876 int i;
5878 int nchan = 0;
5879 int nssid = 0;
5880 wlc_ssid_t ssids[WL_SCAN_PARAMS_SSID_MAX];
5882 UNUSED_PARAMETER(wl);
5883 UNUSED_PARAMETER(cmd);
5885 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
5886 params->bss_type = DOT11_BSSTYPE_ANY;
5887 params->scan_type = 0;
5888 params->nprobes = -1;
5889 params->active_time = -1;
5890 params->passive_time = -1;
5891 params->home_time = -1;
5892 params->channel_num = 0;
5893 memset(ssids, 0, WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t));
5895 /* skip the command name */
5896 argv++;
5898 opt_end = FALSE;
5899 while ((p = *argv) != NULL) {
5900 argv++;
5901 positional_param = FALSE;
5902 memset(key, 0, sizeof(key));
5903 opt = '\0';
5904 valstr = NULL;
5905 good_int = FALSE;
5907 if (opt_end) {
5908 positional_param = TRUE;
5909 valstr = p;
5911 else if (!strcmp(p, "--")) {
5912 opt_end = TRUE;
5913 continue;
5915 else if (!strncmp(p, "--", 2)) {
5916 eq = strchr(p, '=');
5917 if (eq == NULL) {
5918 fprintf(stderr,
5919 "wl_scan: missing \" = \" in long param \"%s\"\n", p);
5920 err = -1;
5921 goto exit;
5923 keylen = eq - (p + 2);
5924 if (keylen > 63) keylen = 63;
5925 memcpy(key, p + 2, keylen);
5927 valstr = eq + 1;
5928 if (*valstr == '\0') {
5929 fprintf(stderr,
5930 "wl_scan: missing value after \" = \" in long param \"%s\"\n", p);
5931 err = -1;
5932 goto exit;
5935 else if (!strncmp(p, "-", 1)) {
5936 opt = p[1];
5937 if (strlen(p) > 2) {
5938 fprintf(stderr,
5939 "wl_scan: only single char options, error on param \"%s\"\n", p);
5940 err = -1;
5941 goto exit;
5943 if (*argv == NULL) {
5944 fprintf(stderr,
5945 "wl_scan: missing value parameter after \"%s\"\n", p);
5946 err = -1;
5947 goto exit;
5949 valstr = *argv;
5950 argv++;
5951 } else {
5952 positional_param = TRUE;
5953 valstr = p;
5956 /* parse valstr as int just in case */
5957 if (valstr) {
5958 val = (int)strtol(valstr, &endptr, 0);
5959 if (*endptr == '\0') {
5960 /* not all the value string was parsed by strtol */
5961 good_int = TRUE;
5965 if (opt == 's' || !strcmp(key, "ssid") || positional_param) {
5966 nssid = wl_parse_ssid_list(valstr, ssids, nssid, WL_SCAN_PARAMS_SSID_MAX);
5967 if (nssid < 0) {
5968 err = -1;
5969 goto exit;
5972 if (opt == 't' || !strcmp(key, "scan_type")) {
5973 if (!strcmp(valstr, "active")) {
5974 params->scan_type = 0;
5975 } else if (!strcmp(valstr, "passive")) {
5976 params->scan_type = WL_SCANFLAGS_PASSIVE;
5977 } else if (!strcmp(valstr, "prohibit")) {
5978 params->scan_type = WL_SCANFLAGS_PROHIBITED;
5979 } else {
5980 fprintf(stderr,
5981 "scan_type value should be \"active\" "
5982 "or \"passive\", but got \"%s\"\n", valstr);
5983 err = -1;
5984 goto exit;
5987 if (!strcmp(key, "bss_type")) {
5988 if (!strcmp(valstr, "bss") || !strcmp(valstr, "infra")) {
5989 params->bss_type = DOT11_BSSTYPE_INFRASTRUCTURE;
5990 } else if (!strcmp(valstr, "ibss") || !strcmp(valstr, "adhoc")) {
5991 params->bss_type = DOT11_BSSTYPE_INDEPENDENT;
5992 } else if (!strcmp(valstr, "any")) {
5993 params->bss_type = DOT11_BSSTYPE_ANY;
5994 } else {
5995 fprintf(stderr,
5996 "bss_type value should be "
5997 "\"bss\", \"ibss\", or \"any\", but got \"%s\"\n", valstr);
5998 err = -1;
5999 goto exit;
6002 if (opt == 'b' || !strcmp(key, "bssid")) {
6003 if (!wl_ether_atoe(valstr, &params->bssid)) {
6004 fprintf(stderr,
6005 "could not parse \"%s\" as an ethernet MAC address\n", valstr);
6006 err = -1;
6007 goto exit;
6010 if (opt == 'n' || !strcmp(key, "nprobes")) {
6011 if (!good_int) {
6012 fprintf(stderr,
6013 "could not parse \"%s\" as an int for value nprobes\n", valstr);
6014 err = -1;
6015 goto exit;
6017 params->nprobes = val;
6019 if (opt == 'a' || !strcmp(key, "active")) {
6020 if (!good_int) {
6021 fprintf(stderr,
6022 "could not parse \"%s\" as an int for active dwell time\n",
6023 valstr);
6024 err = -1;
6025 goto exit;
6027 params->active_time = val;
6029 if (opt == 'p' || !strcmp(key, "passive")) {
6030 if (!good_int) {
6031 fprintf(stderr,
6032 "could not parse \"%s\" as an int for passive dwell time\n",
6033 valstr);
6034 err = -1;
6035 goto exit;
6037 params->passive_time = val;
6039 if (opt == 'h' || !strcmp(key, "home")) {
6040 if (!good_int) {
6041 fprintf(stderr,
6042 "could not parse \"%s\" as an int for home channel dwell time\n",
6043 valstr);
6044 err = -1;
6045 goto exit;
6047 params->home_time = val;
6049 if (opt == 'c' || !strcmp(key, "channels")) {
6050 nchan = wl_parse_channel_list(valstr, params->channel_list,
6051 WL_NUMCHANNELS);
6052 if (nchan == -1) {
6053 fprintf(stderr, "error parsing channel list arg\n");
6054 err = -1;
6055 goto exit;
6060 if (nssid > WL_SCAN_PARAMS_SSID_MAX) {
6061 fprintf(stderr, "ssid count %d exceeds max of %d\n",
6062 nssid, WL_SCAN_PARAMS_SSID_MAX);
6063 err = -1;
6064 goto exit;
6067 params->nprobes = htod32(params->nprobes);
6068 params->active_time = htod32(params->active_time);
6069 params->passive_time = htod32(params->passive_time);
6070 params->home_time = htod32(params->home_time);
6072 for (i = 0; i < nchan; i++) {
6073 params->channel_list[i] = htodchanspec(params->channel_list[i]);
6076 for (i = 0; i < nssid; i++) {
6077 ssids[i].SSID_len = htod32(ssids[i].SSID_len);
6080 /* For a single ssid, use the single fixed field */
6081 if (nssid == 1) {
6082 nssid = 0;
6083 memcpy(&params->ssid, &ssids[0], sizeof(ssids[0]));
6086 /* Copy ssid array if applicable */
6087 if (nssid > 0) {
6088 i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16);
6089 i = ROUNDUP(i, sizeof(uint32));
6090 if (i + nssid * sizeof(wlc_ssid_t) > (uint)*params_size) {
6091 fprintf(stderr, "additional ssids exceed params_size\n");
6092 err = -1;
6093 goto exit;
6096 p = (char*)params + i;
6097 memcpy(p, ssids, nssid * sizeof(wlc_ssid_t));
6098 p += nssid * sizeof(wlc_ssid_t);
6099 } else {
6100 p = (char*)params->channel_list + nchan * sizeof(uint16);
6103 params->channel_num = htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) |
6104 (nchan & WL_SCAN_PARAMS_COUNT_MASK));
6105 *params_size = p - (char*)params + nssid * sizeof(wlc_ssid_t);
6106 exit:
6107 return err;
6111 static int
6112 wl_scan(void *wl, cmd_t *cmd, char **argv)
6114 int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
6115 wl_scan_params_t *params;
6116 int err = 0;
6118 params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
6119 params = (wl_scan_params_t*)malloc(params_size);
6120 if (params == NULL) {
6121 fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
6122 return -1;
6124 memset(params, 0, params_size);
6126 err = wl_scan_prep(wl, cmd, argv, params, &params_size);
6128 if (!err) {
6129 err = wlu_set(wl, cmd->set, params, params_size);
6132 free(params);
6133 return err;
6136 #if defined(linux)
6137 extern time_t time(time_t *ptr);
6138 #endif
6139 static int
6140 wl_escan(void *wl, cmd_t *cmd, char **argv)
6142 int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)) +
6143 (WL_NUMCHANNELS * sizeof(uint16));
6144 wl_escan_params_t *params;
6145 int err = 0;
6146 uint16 action = WL_SCAN_ACTION_START;
6148 if (!stricmp(*argv, "escan"))
6149 /* start an escan */
6150 action = WL_SCAN_ACTION_START;
6151 else if (!stricmp(*argv, "escanabort"))
6152 /* abort an escan */
6153 action = WL_SCAN_ACTION_ABORT;
6154 else {
6155 printf("unknown escan command: %s\n", *argv);
6156 return 0;
6159 params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
6160 params = (wl_escan_params_t*)malloc(params_size);
6161 if (params == NULL) {
6162 fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
6163 return -1;
6165 memset(params, 0, params_size);
6167 err = wl_scan_prep(wl, cmd, argv, &params->params, &params_size);
6169 if (!err) {
6170 params->version = htod32(ESCAN_REQ_VERSION);
6171 params->action = htod16(action);
6173 #if defined(linux)
6174 srand((unsigned)time(NULL));
6175 params->sync_id = htod16(rand() & 0xffff);
6176 #else
6177 params->sync_id = htod16(4321);
6178 #endif /* #if defined(linux) */
6180 params_size += OFFSETOF(wl_escan_params_t, params);
6181 err = wlu_iovar_setbuf(wl, "escan", params, params_size, buf, WLC_IOCTL_MAXLEN);
6184 free(params);
6185 return err;
6188 static int
6189 wl_iscan(void *wl, cmd_t *cmd, char **argv)
6191 int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) +
6192 (WL_NUMCHANNELS * sizeof(uint16));
6193 wl_iscan_params_t *params;
6194 int err = 0;
6195 uint16 action = WL_SCAN_ACTION_START;
6196 char **p;
6197 uint16 iscan_duration = 0;
6199 if (!stricmp(*argv, "iscan_s"))
6200 action = WL_SCAN_ACTION_START;
6201 else if (!stricmp(*argv, "iscan_c"))
6202 action = WL_SCAN_ACTION_CONTINUE;
6203 else {
6204 printf("unknown iscan command: %s\n", *argv);
6205 return 0;
6208 /* look for iscan_duration parameter */
6209 p = argv;
6210 while (*p != NULL) {
6211 if (!strcmp(*p, "-d") || !strncmp(*p, "--duration=", 11)) {
6212 char *valptr;
6213 int val;
6214 char *endptr;
6215 if (!strcmp(*p, "-d"))
6216 valptr = *(++p);
6217 else
6218 valptr = *p + 11;
6219 val = (int)strtol(valptr, &endptr, 0);
6220 if (*endptr != '\0') {
6221 fprintf(stderr,
6222 "could not parse \"%s\" as an int for duration\n",
6223 valptr);
6224 err = -1;
6225 goto exit;
6227 iscan_duration = (uint16) val;
6228 break;
6230 ++p;
6233 params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
6234 params = (wl_iscan_params_t*)malloc(params_size);
6235 if (params == NULL) {
6236 fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
6237 return -1;
6239 memset(params, 0, params_size);
6241 err = wl_scan_prep(wl, cmd, argv, &params->params, &params_size);
6243 if (!err) {
6244 params->version = htod32(ISCAN_REQ_VERSION);
6245 params->action = htod16(action);
6246 params->scan_duration = htod16(iscan_duration);
6247 params_size += OFFSETOF(wl_iscan_params_t, params);
6248 err = wlu_iovar_setbuf(wl, "iscan", params, params_size, buf, WLC_IOCTL_MAXLEN);
6251 free(params);
6252 exit:
6253 return err;
6256 static int
6257 wl_parse_assoc_params(char **argv, wl_assoc_params_t *params)
6259 int err = BCME_OK;
6260 char *p, *eq, *valstr;
6261 char opt;
6262 bool opt_end;
6263 int keylen;
6264 char key[64];
6265 int i;
6267 opt_end = FALSE;
6269 while ((p = *argv) != NULL) {
6270 argv++;
6271 memset(key, 0, sizeof(key));
6272 opt = '\0';
6273 valstr = NULL;
6275 if (opt_end) {
6276 valstr = p;
6278 else if (!strcmp(p, "--")) {
6279 opt_end = TRUE;
6280 continue;
6282 else if (!strncmp(p, "--", 2)) {
6283 eq = strchr(p, '=');
6284 if (eq == NULL) {
6285 fprintf(stderr, "wl_parse_assoc_params: missing \" = \" in "
6286 "long param \"%s\"\n", p);
6287 err = BCME_BADARG;
6288 goto exit;
6290 keylen = eq - (p + 2);
6291 if (keylen > 63) keylen = 63;
6292 memcpy(key, p + 2, keylen);
6294 valstr = eq + 1;
6295 if (*valstr == '\0') {
6296 fprintf(stderr, "wl_parse_assoc_params: missing value after "
6297 "\" = \" in long param \"%s\"\n", p);
6298 err = BCME_BADARG;
6299 goto exit;
6302 else if (!strncmp(p, "-", 1)) {
6303 opt = p[1];
6304 if (strlen(p) > 2) {
6305 fprintf(stderr, "wl_parse_assoc_params: only single char options, "
6306 "error on param \"%s\"\n", p);
6307 err = BCME_BADARG;
6308 goto exit;
6310 if (*argv == NULL) {
6311 fprintf(stderr, "wl_parse_assoc_params: missing value parameter "
6312 "after \"%s\"\n", p);
6313 err = BCME_BADARG;
6314 goto exit;
6316 valstr = *argv++;
6317 } else {
6318 valstr = p;
6321 /* handle -o v or --option=val */
6322 if (opt == 'b' || !stricmp(key, "bssid")) {
6323 if (!wl_ether_atoe(valstr, &params->bssid)) {
6324 fprintf(stderr, "could not parse as an ethernet MAC address\n");
6325 err = BCME_BADARG;
6326 goto exit;
6329 else if (opt == 'c' || !strcmp(key, "chanspecs")) {
6330 params->chanspec_num =
6331 wl_parse_chanspec_list(valstr, params->chanspec_list, WL_NUMCHANNELS);
6332 if (params->chanspec_num == -1) {
6333 fprintf(stderr, "error parsing chanspec list arg\n");
6334 err = BCME_BADARG;
6335 goto exit;
6340 /* prepare the chanspec using the channel number and the user provided options */
6341 for (i = 0; i < params->chanspec_num; i++) {
6342 params->chanspec_list[i] = htodchanspec(params->chanspec_list[i]);
6344 params->chanspec_num = htod32(params->chanspec_num);
6346 exit:
6347 return err;
6350 /* wl reassoc <bssid>
6351 * Options:
6352 * -c CL, --chanspecs=CL, where CL is a comma or space separated list of chanspecs
6354 static int
6355 wl_reassoc(void *wl, cmd_t *cmd, char **argv)
6357 int params_size = WL_REASSOC_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(chanspec_t);
6358 wl_reassoc_params_t *params;
6359 int err = 0;
6361 UNUSED_PARAMETER(cmd);
6363 if (*++argv == NULL) {
6364 fprintf(stderr, "no arguments to wl_reassoc\n");
6365 return BCME_ERROR;
6368 params = (wl_reassoc_params_t *)malloc(params_size);
6369 if (params == NULL) {
6370 fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
6371 return BCME_NOMEM;
6373 memset(params, 0, params_size);
6375 if (!wl_ether_atoe(*argv, &params->bssid)) {
6376 fprintf(stderr, "could not parse %s as an Ethernet MAC address\n", *argv);
6377 err = BCME_BADARG;
6378 goto exit;
6380 /* default to plain old ioctl */
6381 params_size = ETHER_ADDR_LEN;
6383 if (*++argv != NULL) {
6384 if ((err = wl_parse_reassoc_params(argv, params)) != BCME_OK) {
6385 fprintf(stderr, "could not parse reassociation parameters\n");
6386 goto exit;
6388 params_size = WL_REASSOC_PARAMS_FIXED_SIZE +
6389 dtoh32(params->chanspec_num) * sizeof(chanspec_t);
6392 err = wlu_set(wl, WLC_REASSOC, params, params_size);
6394 exit:
6395 free(params);
6396 return err;
6399 #ifdef EXTENDED_SCAN
6400 /* wl extdscan
6401 * -s --ssid=ssid1 ssid2 ssid3
6402 * -b --split_scan=0 : [split_scan]
6403 * -t --scan_type=0 : [background/forcedbackground/foreground]
6404 * -n --nprobes=
6405 * -c --channels=
6407 static int
6408 wl_extdscan(void *wl, cmd_t *cmd, char **argv)
6410 wl_extdscan_params_t *params;
6411 int params_size = WL_EXTDSCAN_PARAMS_FIXED_SIZE +
6412 (WL_NUMCHANNELS * sizeof(chan_scandata_t));
6413 int val = 0;
6414 char *p, *eq, *valstr, *endptr;
6415 char opt;
6416 bool positional_param;
6417 bool good_int;
6418 bool opt_end;
6419 int err = 0;
6420 int keylen;
6421 char key[64];
6422 int i;
6423 int nssid = 0;
6425 fprintf(stderr, "params alloc size is %d\n", params_size);
6426 params = (wl_extdscan_params_t *)malloc(params_size);
6427 if (params == NULL) {
6428 fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
6429 return -1;
6431 memset(params, 0, params_size);
6433 params->scan_type = EXTDSCAN_FORCEDBACKGROUND_SCAN;
6434 params->nprobes = 3;
6435 params->band = WLC_BAND_2G;
6436 params->split_scan = 0;
6438 /* skip the command name */
6439 argv++;
6441 if (*argv == NULL) {
6442 fprintf(stderr, "no arguments to wl_extdscan\n");
6443 err = -1;
6444 goto exit;
6446 opt_end = FALSE;
6447 while ((p = *argv) != NULL) {
6448 argv++;
6449 positional_param = FALSE;
6450 memset(key, 0, sizeof(key));
6451 opt = '\0';
6452 valstr = NULL;
6453 good_int = FALSE;
6455 if (opt_end) {
6456 positional_param = TRUE;
6457 valstr = p;
6459 else if (!strcmp(p, "--")) {
6460 opt_end = TRUE;
6461 continue;
6463 else if (!strncmp(p, "--", 2)) {
6464 eq = strchr(p, '=');
6465 if (eq == NULL) {
6466 fprintf(stderr,
6467 "wl_extdscan: missing \" = \" in long param \"%s\"\n", p);
6468 err = -1;
6469 goto exit;
6471 keylen = eq - (p + 2);
6472 if (keylen > 63) keylen = 63;
6473 memcpy(key, p + 2, keylen);
6475 valstr = eq + 1;
6476 if (*valstr == '\0') {
6477 fprintf(stderr,
6478 "extdscan: missing value after \" = \" in long param \"%s\"\n", p);
6479 err = -1;
6480 goto exit;
6483 else if (!strncmp(p, "-", 1)) {
6484 opt = p[1];
6485 if (strlen(p) > 2) {
6486 fprintf(stderr,
6487 "extdscan: only single char options, error on param \"%s\"\n", p);
6488 err = -1;
6489 goto exit;
6491 if (*argv == NULL) {
6492 fprintf(stderr,
6493 "extdscan: missing value parameter after \"%s\"\n", p);
6494 err = -1;
6495 goto exit;
6497 valstr = *argv;
6498 argv++;
6499 } else {
6500 positional_param = TRUE;
6501 valstr = p;
6504 /* parse valstr as int just in case */
6505 if (valstr) {
6506 val = (int)strtol(valstr, &endptr, 0);
6507 if (*endptr == '\0') {
6508 /* not all the value string was parsed by strtol */
6509 good_int = TRUE;
6513 if (opt == 's' || !strcmp(key, "ssid") || positional_param) {
6514 nssid = wl_parse_ssid_list(valstr, params->ssid,
6515 nssid, WLC_EXTDSCAN_MAX_SSID);
6516 if (nssid < 0) {
6517 err = -1;
6518 goto exit;
6521 if (opt == 'b' || !strcmp(key, "band")) {
6522 if (!strcmp(valstr, "5G")) {
6523 params->band = WLC_BAND_5G;
6525 else if (!strcmp(valstr, "2.4G")) {
6526 params->band = WLC_BAND_2G;
6528 else if (!strcmp(valstr, "all")) {
6529 params->band = WLC_BAND_ALL;
6530 } else {
6531 fprintf(stderr,
6532 "scan_type value should be \"5G\" "
6533 "or \"2.4G\" " "or \"all\" but got \"%s\"\n", valstr);
6534 err = -1;
6535 goto exit;
6538 if (opt == 't' || !strcmp(key, "scan_type")) {
6539 if (!strcmp(valstr, "background")) {
6540 params->scan_type = EXTDSCAN_BACKGROUND_SCAN;
6541 } else if (!strcmp(valstr, "fbackground")) {
6542 params->scan_type = EXTDSCAN_FORCEDBACKGROUND_SCAN;
6543 } else if (!strcmp(valstr, "foreground")) {
6544 params->scan_type = EXTDSCAN_FOREGROUND_SCAN;
6545 } else {
6546 fprintf(stderr,
6547 "scan_type value should be \"background\" "
6548 "or \"fbackground\" " "or \"foreground\" but got \"%s\"\n", valstr);
6549 err = -1;
6550 goto exit;
6553 if (opt == 'n' || !strcmp(key, "nprobes")) {
6554 if (!good_int) {
6555 fprintf(stderr,
6556 "could not parse \"%s\" as an int for value nprobes\n", valstr);
6557 err = -1;
6558 goto exit;
6560 params->nprobes = val;
6562 if (opt == 'x' || !strcmp(key, "split_scan")) {
6563 if (val != 0)
6564 params->split_scan = 1;
6566 if (opt == 'c' || !strcmp(key, "channels")) {
6567 params->channel_num = wl_parse_extdchannel_list(valstr,
6568 params->channel_list, WL_NUMCHANNELS);
6569 if (params->channel_num == -1) {
6570 fprintf(stderr, "error parsing channel list arg\n");
6571 err = -1;
6572 goto exit;
6577 if (nssid > WLC_EXTDSCAN_MAX_SSID) {
6578 fprintf(stderr, "ssid count %d exceeds max of %d\n",
6579 nssid, WLC_EXTDSCAN_MAX_SSID);
6580 err = -1;
6581 goto exit;
6584 params_size = WL_EXTDSCAN_PARAMS_FIXED_SIZE +
6585 (params->channel_num * sizeof(chan_scandata_t));
6587 fprintf(stderr, "ssid list is %s(%d) %s(%d) %s(%d) %s(%d) %s(%d)\n",
6588 (char *)&params->ssid[0].SSID, params->ssid[0].SSID_len,
6589 (char *)&params->ssid[1].SSID, params->ssid[1].SSID_len,
6590 (char *)&params->ssid[2].SSID, params->ssid[2].SSID_len,
6591 (char *)&params->ssid[3].SSID, params->ssid[3].SSID_len,
6592 (char *)&params->ssid[4].SSID, params->ssid[4].SSID_len);
6593 if (params->split_scan)
6594 fprintf(stderr, "split scan is enabled\n");
6595 else
6596 fprintf(stderr, "split scan is not enabled\n");
6598 fprintf(stderr, "scan type is %d, nprobes are %d, band is %d, channels are %d\n",
6599 params->scan_type, params->nprobes, params->band, params->channel_num);
6601 fprintf(stderr, "params size is %d\n", params_size);
6602 params->scan_type = htodenum(params->scan_type);
6603 for (i = 0; i < WLC_EXTDSCAN_MAX_SSID; i++) {
6604 params->ssid[i].SSID_len = htod32(params->ssid[i].SSID_len);
6606 for (i = 0; i < params->channel_num; i++) {
6607 params->channel_list[i].channel = htodchanspec(params->channel_list[i].channel);
6608 params->channel_list[i].channel_mintime =
6609 htod32(params->channel_list[i].channel_mintime);
6610 params->channel_list[i].channel_maxtime =
6611 htod32(params->channel_list[i].channel_maxtime);
6613 params->channel_num = htod32(params->channel_num);
6614 err = wlu_var_setbuf(wl, cmd->name, params, params_size);
6616 exit:
6617 free(params);
6618 return err;
6621 static int
6622 wl_parse_extdchannel_list(char* list_str, chan_scandata_t* channel_list, int channel_num)
6624 int num;
6625 int val;
6626 char* str;
6627 char* endptr;
6629 if (list_str == NULL)
6630 return -1;
6632 str = list_str;
6633 num = 0;
6634 while (*str != '\0') {
6635 val = (int)strtol(str, &endptr, 0);
6636 if (endptr == str) {
6637 fprintf(stderr,
6638 "could not parse channel number starting at"
6639 " substring \"%s\" in list:\n%s\n",
6640 str, list_str);
6641 return -1;
6643 str = endptr + strspn(endptr, " ,");
6645 if (num == channel_num) {
6646 fprintf(stderr, "too many channels (more than %d) in channel list:\n%s\n",
6647 channel_num, list_str);
6648 return -1;
6650 channel_list->channel = (uint16)val;
6651 channel_list++;
6652 num++;
6655 return num;
6657 #endif /* EXTENDED_SCAN */
6659 static int
6660 wl_parse_channel_list(char* list_str, uint16* channel_list, int channel_num)
6662 int num;
6663 int val;
6664 char* str;
6665 char* endptr = NULL;
6667 if (list_str == NULL)
6668 return -1;
6670 str = list_str;
6671 num = 0;
6672 while (*str != '\0') {
6673 val = (int)strtol(str, &endptr, 0);
6674 if (endptr == str) {
6675 fprintf(stderr,
6676 "could not parse channel number starting at"
6677 " substring \"%s\" in list:\n%s\n",
6678 str, list_str);
6679 return -1;
6681 str = endptr + strspn(endptr, " ,");
6683 if (num == channel_num) {
6684 fprintf(stderr, "too many channels (more than %d) in channel list:\n%s\n",
6685 channel_num, list_str);
6686 return -1;
6689 channel_list[num++] = (uint16)val;
6692 return num;
6695 static int
6696 wl_parse_chanspec_list(char *list_str, chanspec_t *chanspec_list, int chanspec_num)
6698 int num = 0;
6699 chanspec_t chanspec;
6700 char *next, str[8];
6701 size_t len;
6703 if ((next = list_str) == NULL)
6704 return BCME_ERROR;
6706 while ((len = strcspn(next, " ,")) > 0) {
6707 if (len >= sizeof(str)) {
6708 fprintf(stderr, "string \"%s\" before ',' or ' ' is too long\n", next);
6709 return BCME_ERROR;
6711 strncpy(str, next, len);
6712 str[len] = 0;
6713 chanspec = wf_chspec_aton(str);
6714 if (chanspec == 0) {
6715 fprintf(stderr, "could not parse chanspec starting at "
6716 "\"%s\" in list:\n%s\n", str, list_str);
6717 return BCME_ERROR;
6719 if (num == chanspec_num) {
6720 fprintf(stderr, "too many chanspecs (more than %d) in chanspec list:\n%s\n",
6721 chanspec_num, list_str);
6722 return BCME_ERROR;
6724 chanspec_list[num++] = chanspec;
6725 next += len;
6726 next += strspn(next, " ,");
6729 return num;
6732 /* channel info structure */
6733 typedef struct {
6734 uint chan; /* channel number */
6735 uint freq; /* in Mhz */
6736 } chan_info_t;
6738 static chan_info_t chan_info[] = {
6739 /* B channels */
6740 { 1, 2412},
6741 { 2, 2417},
6742 { 3, 2422},
6743 { 4, 2427},
6744 { 5, 2432},
6745 { 6, 2437},
6746 { 7, 2442},
6747 { 8, 2447},
6748 { 9, 2452},
6749 { 10, 2457},
6750 { 11, 2462},
6751 { 12, 2467},
6752 { 13, 2472},
6753 { 14, 2484},
6755 /* A channels */
6756 /* 11a usa low */
6757 { 36, 5180},
6758 { 40, 5200},
6759 { 44, 5220},
6760 { 48, 5240},
6761 { 52, 5260},
6762 { 56, 5280},
6763 { 60, 5300},
6764 { 64, 5320},
6766 /* 11a Europe */
6767 { 100, 5500},
6768 { 104, 5520},
6769 { 108, 5540},
6770 { 112, 5560},
6771 { 116, 5580},
6772 { 120, 5600},
6773 { 124, 5620},
6774 { 128, 5640},
6775 { 132, 5660},
6776 { 136, 5680},
6777 { 140, 5700},
6779 /* 11a usa high */
6780 { 149, 5745},
6781 { 153, 5765},
6782 { 157, 5785},
6783 { 161, 5805},
6785 /* 11a japan */
6786 { 184, 4920},
6787 { 188, 4940},
6788 { 192, 4960},
6789 { 196, 4980},
6790 { 200, 5000},
6791 { 204, 5020},
6792 { 208, 5040},
6793 { 212, 5060},
6794 { 216, 5080}
6797 uint
6798 freq2channel(uint freq)
6800 int i;
6802 for (i = 0; i < (int)ARRAYSIZE(chan_info); i++) {
6803 if (chan_info[i].freq == freq)
6804 return (chan_info[i].chan);
6806 return (0);
6809 void
6810 dump_rateset(uint8 *rates, uint count)
6812 uint i;
6813 uint r;
6814 bool b;
6816 printf("[ ");
6817 for (i = 0; i < count; i++) {
6818 r = rates[i] & 0x7f;
6819 b = rates[i] & 0x80;
6820 if (r == 0)
6821 break;
6822 printf("%d%s%s ", (r / 2), (r % 2)?".5":"", b?"(b)":"");
6824 printf("]");
6827 /* Helper routine to print the infrastructure mode while pretty printing the BSS list */
6828 static const char *
6829 capmode2str(uint16 capability)
6831 capability &= (DOT11_CAP_ESS | DOT11_CAP_IBSS);
6833 if (capability == DOT11_CAP_ESS)
6834 return "Managed";
6835 else if (capability == DOT11_CAP_IBSS)
6836 return "Ad Hoc";
6837 else
6838 return "<unknown>";
6842 * Traverse a string of 1-byte tag/1-byte length/variable-length value
6843 * triples, returning a pointer to the substring whose first element
6844 * matches tag
6846 static uint8 *
6847 wlu_parse_tlvs(uint8 *tlv_buf, int buflen, uint key)
6849 uint8 *cp;
6850 int totlen;
6852 cp = tlv_buf;
6853 totlen = buflen;
6855 /* find tagged parameter */
6856 while (totlen >= 2) {
6857 uint tag;
6858 int len;
6860 tag = *cp;
6861 len = *(cp +1);
6863 /* validate remaining totlen */
6864 if ((tag == key) && (totlen >= (len + 2)))
6865 return (cp);
6867 cp += (len + 2);
6868 totlen -= (len + 2);
6871 return NULL;
6874 static int
6875 wlu_bcmp(const void *b1, const void *b2, int len)
6877 return (memcmp(b1, b2, len));
6880 /* Is this body of this tlvs entry a WPA entry? If */
6881 /* not update the tlvs buffer pointer/length */
6882 static bool
6883 wlu_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, uint *tlvs_len)
6885 uint8 *ie = *wpaie;
6887 /* If the contents match the WPA_OUI and type=1 */
6888 if ((ie[1] >= 6) && !wlu_bcmp(&ie[2], WPA_OUI "\x01", 4)) {
6889 return TRUE;
6892 /* point to the next ie */
6893 ie += ie[1] + 2;
6894 /* calculate the length of the rest of the buffer */
6895 *tlvs_len -= (int)(ie - *tlvs);
6896 /* update the pointer to the start of the buffer */
6897 *tlvs = ie;
6899 return FALSE;
6902 static void
6903 wl_dump_wpa_rsn_ies(uint8* cp, uint len)
6905 uint8 *parse = cp;
6906 uint parse_len = len;
6907 uint8 *wpaie;
6908 uint8 *rsnie;
6910 while ((wpaie = wlu_parse_tlvs(parse, parse_len, DOT11_MNG_WPA_ID)))
6911 if (wlu_is_wpa_ie(&wpaie, &parse, &parse_len))
6912 break;
6913 if (wpaie)
6914 wl_rsn_ie_dump((bcm_tlv_t*)wpaie);
6916 rsnie = wlu_parse_tlvs(cp, len, DOT11_MNG_RSN_ID);
6917 if (rsnie)
6918 wl_rsn_ie_dump((bcm_tlv_t*)rsnie);
6920 return;
6923 static void
6924 wl_rsn_ie_dump(bcm_tlv_t *ie)
6926 int i;
6927 int rsn;
6928 wpa_ie_fixed_t *wpa = NULL;
6929 rsn_parse_info_t rsn_info;
6930 wpa_suite_t *suite;
6931 uint8 std_oui[3];
6932 int unicast_count = 0;
6933 int akm_count = 0;
6934 uint16 capabilities;
6935 uint cntrs;
6936 int err;
6938 if (ie->id == DOT11_MNG_RSN_ID) {
6939 rsn = TRUE;
6940 memcpy(std_oui, WPA2_OUI, WPA_OUI_LEN);
6941 err = wl_rsn_ie_parse_info(ie->data, ie->len, &rsn_info);
6942 } else {
6943 rsn = FALSE;
6944 memcpy(std_oui, WPA_OUI, WPA_OUI_LEN);
6945 wpa = (wpa_ie_fixed_t*)ie;
6946 err = wl_rsn_ie_parse_info((uint8*)&wpa->version, wpa->length - WPA_IE_OUITYPE_LEN,
6947 &rsn_info);
6949 if (err || rsn_info.version != WPA_VERSION)
6950 return;
6952 if (rsn)
6953 printf("RSN:\n");
6954 else
6955 printf("WPA:\n");
6957 /* Check for multicast suite */
6958 if (rsn_info.mcast) {
6959 printf("\tmulticast cipher: ");
6960 if (!wlu_bcmp(rsn_info.mcast->oui, std_oui, 3)) {
6961 switch (rsn_info.mcast->type) {
6962 case WPA_CIPHER_NONE:
6963 printf("NONE\n");
6964 break;
6965 case WPA_CIPHER_WEP_40:
6966 printf("WEP64\n");
6967 break;
6968 case WPA_CIPHER_WEP_104:
6969 printf("WEP128\n");
6970 break;
6971 case WPA_CIPHER_TKIP:
6972 printf("TKIP\n");
6973 break;
6974 case WPA_CIPHER_AES_OCB:
6975 printf("AES-OCB\n");
6976 break;
6977 case WPA_CIPHER_AES_CCM:
6978 printf("AES-CCMP\n");
6979 break;
6980 default:
6981 printf("Unknown-%s(#%d)\n", rsn ? "RSN" : "WPA",
6982 rsn_info.mcast->type);
6983 break;
6986 else {
6987 printf("Unknown-%02X:%02X:%02X(#%d) ",
6988 rsn_info.mcast->oui[0], rsn_info.mcast->oui[1],
6989 rsn_info.mcast->oui[2], rsn_info.mcast->type);
6993 /* Check for unicast suite(s) */
6994 if (rsn_info.ucast) {
6995 unicast_count = ltoh16_ua(&rsn_info.ucast->count);
6996 printf("\tunicast ciphers(%d): ", unicast_count);
6997 for (i = 0; i < unicast_count; i++) {
6998 suite = &rsn_info.ucast->list[i];
6999 if (!wlu_bcmp(suite->oui, std_oui, 3)) {
7000 switch (suite->type) {
7001 case WPA_CIPHER_NONE:
7002 printf("NONE ");
7003 break;
7004 case WPA_CIPHER_WEP_40:
7005 printf("WEP64 ");
7006 break;
7007 case WPA_CIPHER_WEP_104:
7008 printf("WEP128 ");
7009 break;
7010 case WPA_CIPHER_TKIP:
7011 printf("TKIP ");
7012 break;
7013 case WPA_CIPHER_AES_OCB:
7014 printf("AES-OCB ");
7015 break;
7016 case WPA_CIPHER_AES_CCM:
7017 printf("AES-CCMP ");
7018 break;
7019 default:
7020 printf("WPA-Unknown-%s(#%d) ", rsn ? "RSN" : "WPA",
7021 suite->type);
7022 break;
7025 else {
7026 printf("Unknown-%02X:%02X:%02X(#%d) ",
7027 suite->oui[0], suite->oui[1], suite->oui[2],
7028 suite->type);
7031 printf("\n");
7033 /* Authentication Key Management */
7034 if (rsn_info.akm) {
7035 akm_count = ltoh16_ua(&rsn_info.akm->count);
7036 printf("\tAKM Suites(%d): ", akm_count);
7037 for (i = 0; i < akm_count; i++) {
7038 suite = &rsn_info.akm->list[i];
7039 if (!wlu_bcmp(suite->oui, std_oui, 3)) {
7040 switch (suite->type) {
7041 case RSN_AKM_NONE:
7042 printf("None ");
7043 break;
7044 case RSN_AKM_UNSPECIFIED:
7045 printf("WPA ");
7046 break;
7047 case RSN_AKM_PSK:
7048 printf("WPA-PSK ");
7049 break;
7050 default:
7051 printf("Unknown-%s(#%d) ",
7052 rsn ? "RSN" : "WPA", suite->type);
7053 break;
7056 else {
7057 printf("Unknown-%02X:%02X:%02X(#%d) ",
7058 suite->oui[0], suite->oui[1], suite->oui[2],
7059 suite->type);
7062 printf("\n");
7065 /* Capabilities */
7066 if (rsn_info.capabilities) {
7067 capabilities = ltoh16_ua(rsn_info.capabilities);
7068 printf("\tCapabilities(0x%04x): ", capabilities);
7069 if (rsn)
7070 printf("%sPre-Auth, ", (capabilities & RSN_CAP_PREAUTH) ? "" : "No ");
7072 printf("%sPairwise, ", (capabilities & RSN_CAP_NOPAIRWISE) ? "No " : "");
7074 cntrs = wl_rsn_ie_decode_cntrs((capabilities & RSN_CAP_PTK_REPLAY_CNTR_MASK) >>
7075 RSN_CAP_PTK_REPLAY_CNTR_SHIFT);
7077 printf("%d PTK Replay Ctr%s", cntrs, (cntrs > 1)?"s":"");
7079 if (rsn) {
7080 cntrs = wl_rsn_ie_decode_cntrs(
7081 (capabilities & RSN_CAP_GTK_REPLAY_CNTR_MASK) >>
7082 RSN_CAP_GTK_REPLAY_CNTR_SHIFT);
7084 printf("%d GTK Replay Ctr%s\n", cntrs, (cntrs > 1)?"s":"");
7085 } else {
7086 printf("\n");
7088 } else {
7089 printf("\tNo %s Capabilities advertised\n", rsn ? "RSN" : "WPA");
7094 /* Validates and parses the RSN or WPA IE contents into a rsn_parse_info_t structure
7095 * Returns 0 on success, or 1 if the information in the buffer is not consistant with
7096 * an RSN IE or WPA IE.
7097 * The buf pointer passed in should be pointing at the version field in either an RSN IE
7098 * or WPA IE.
7100 static int
7101 wl_rsn_ie_parse_info(uint8* rsn_buf, uint len, rsn_parse_info_t *rsn)
7103 uint16 count;
7105 memset(rsn, 0, sizeof(rsn_parse_info_t));
7107 /* version */
7108 if (len < sizeof(uint16))
7109 return 1;
7111 rsn->version = ltoh16_ua(rsn_buf);
7112 len -= sizeof(uint16);
7113 rsn_buf += sizeof(uint16);
7115 /* Multicast Suite */
7116 if (len < sizeof(wpa_suite_mcast_t))
7117 return 0;
7119 rsn->mcast = (wpa_suite_mcast_t*)rsn_buf;
7120 len -= sizeof(wpa_suite_mcast_t);
7121 rsn_buf += sizeof(wpa_suite_mcast_t);
7123 /* Unicast Suite */
7124 if (len < sizeof(uint16))
7125 return 0;
7127 count = ltoh16_ua(rsn_buf);
7129 if (len < (sizeof(uint16) + count * sizeof(wpa_suite_t)))
7130 return 1;
7132 rsn->ucast = (wpa_suite_ucast_t*)rsn_buf;
7133 len -= (sizeof(uint16) + count * sizeof(wpa_suite_t));
7134 rsn_buf += (sizeof(uint16) + count * sizeof(wpa_suite_t));
7136 /* AKM Suite */
7137 if (len < sizeof(uint16))
7138 return 0;
7140 count = ltoh16_ua(rsn_buf);
7142 if (len < (sizeof(uint16) + count * sizeof(wpa_suite_t)))
7143 return 1;
7145 rsn->akm = (wpa_suite_auth_key_mgmt_t*)rsn_buf;
7146 len -= (sizeof(uint16) + count * sizeof(wpa_suite_t));
7147 rsn_buf += (sizeof(uint16) + count * sizeof(wpa_suite_t));
7149 /* Capabilites */
7150 if (len < sizeof(uint16))
7151 return 0;
7153 rsn->capabilities = rsn_buf;
7155 return 0;
7158 static uint
7159 wl_rsn_ie_decode_cntrs(uint cntr_field)
7161 uint cntrs;
7163 switch (cntr_field) {
7164 case RSN_CAP_1_REPLAY_CNTR:
7165 cntrs = 1;
7166 break;
7167 case RSN_CAP_2_REPLAY_CNTRS:
7168 cntrs = 2;
7169 break;
7170 case RSN_CAP_4_REPLAY_CNTRS:
7171 cntrs = 4;
7172 break;
7173 case RSN_CAP_16_REPLAY_CNTRS:
7174 cntrs = 16;
7175 break;
7176 default:
7177 cntrs = 0;
7178 break;
7181 return cntrs;
7185 void
7186 wl_dump_raw_ie(bcm_tlv_t *ie, uint len)
7188 uint dump_len;
7190 if (len == 0) {
7191 return;
7192 } else if (len == 1) {
7193 printf("IE header truncated: ID: 0x%02X\n", ie->id);
7194 return;
7195 } else if (len < (uint)(ie->len + TLV_HDR_LEN)) {
7196 printf("IE data truncated: ID: 0x%02X Len: %d\n", ie->id, ie->len);
7197 dump_len = len - TLV_HDR_LEN;
7198 } else {
7199 printf("ID: 0x%02X Len: %d\n", ie->id, ie->len);
7200 dump_len = ie->len;
7203 /* choose how to format the data based on data len */
7204 if (dump_len > 16)
7205 printf("Data:\n");
7206 else if (dump_len > 0)
7207 printf("Data: ");
7209 if (dump_len > 0)
7210 wl_hexdump(ie->data, dump_len);
7212 if (dump_len < ie->len)
7213 printf("<missing %d bytes>\n", ie->len - dump_len);
7215 return;
7219 /* Pretty print the BSS list */
7220 static void
7221 dump_networks(char *network_buf)
7223 wl_scan_results_t *list = (wl_scan_results_t*)network_buf;
7224 wl_bss_info_t *bi;
7225 uint i;
7227 if (list->count == 0)
7228 return;
7229 else if (list->version != WL_BSS_INFO_VERSION &&
7230 list->version != LEGACY2_WL_BSS_INFO_VERSION &&
7231 list->version != LEGACY_WL_BSS_INFO_VERSION) {
7232 fprintf(stderr, "Sorry, your driver has bss_info_version %d "
7233 "but this program supports only version %d.\n",
7234 list->version, WL_BSS_INFO_VERSION);
7235 return;
7238 bi = list->bss_info;
7239 for (i = 0; i < list->count; i++, bi = (wl_bss_info_t*)((int8*)bi + dtoh32(bi->length))) {
7240 dump_bss_info(bi);
7244 static void
7245 dump_bss_info(wl_bss_info_t *bi)
7247 char ssidbuf[SSID_FMT_BUF_LEN];
7248 char chspec_str[CHANSPEC_STR_LEN];
7249 wl_bss_info_107_t *old_bi;
7250 int mcs_idx = 0;
7252 /* Convert version 107 to 109 */
7253 if (dtoh32(bi->version) == LEGACY_WL_BSS_INFO_VERSION) {
7254 old_bi = (wl_bss_info_107_t *)bi;
7255 bi->chanspec = CH20MHZ_CHSPEC(old_bi->channel);
7256 bi->ie_length = old_bi->ie_length;
7257 bi->ie_offset = sizeof(wl_bss_info_107_t);
7260 wl_format_ssid(ssidbuf, bi->SSID, bi->SSID_len);
7262 printf("SSID: \"%s\"\n", ssidbuf);
7264 printf("Mode: %s\t", capmode2str(dtoh16(bi->capability)));
7265 printf("RSSI: %d dBm\t", (int16)(dtoh16(bi->RSSI)));
7268 * SNR has valid value in only 109 version.
7269 * So print SNR for 109 version only.
7271 if (dtoh32(bi->version) == WL_BSS_INFO_VERSION) {
7272 printf("SNR: %d dB\t", (int16)(dtoh16(bi->SNR)));
7275 printf("noise: %d dBm\t", bi->phy_noise);
7276 if (bi->flags) {
7277 bi->flags = dtoh16(bi->flags);
7278 printf("Flags: ");
7279 if (bi->flags & WL_BSS_FLAGS_FROM_BEACON) printf("FromBcn ");
7280 if (bi->flags & WL_BSS_FLAGS_FROM_CACHE) printf("Cached ");
7281 if (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) printf("RSSI on-channel ");
7282 printf("\t");
7284 printf("Channel: %s\n", wf_chspec_ntoa(dtohchanspec(bi->chanspec), chspec_str));
7286 printf("BSSID: %s\t", wl_ether_etoa(&bi->BSSID));
7288 printf("Capability: ");
7289 bi->capability = dtoh16(bi->capability);
7290 if (bi->capability & DOT11_CAP_ESS) printf("ESS ");
7291 if (bi->capability & DOT11_CAP_IBSS) printf("IBSS ");
7292 if (bi->capability & DOT11_CAP_POLLABLE) printf("Pollable ");
7293 if (bi->capability & DOT11_CAP_POLL_RQ) printf("PollReq ");
7294 if (bi->capability & DOT11_CAP_PRIVACY) printf("WEP ");
7295 if (bi->capability & DOT11_CAP_SHORT) printf("ShortPre ");
7296 if (bi->capability & DOT11_CAP_PBCC) printf("PBCC ");
7297 if (bi->capability & DOT11_CAP_AGILITY) printf("Agility ");
7298 if (bi->capability & DOT11_CAP_SHORTSLOT) printf("ShortSlot ");
7299 if (bi->capability & DOT11_CAP_CCK_OFDM) printf("CCK-OFDM ");
7300 printf("\n");
7302 printf("Supported Rates: ");
7303 dump_rateset(bi->rateset.rates, dtoh32(bi->rateset.count));
7304 printf("\n");
7305 if (dtoh32(bi->ie_length))
7306 wl_dump_wpa_rsn_ies((uint8 *)(((uint8 *)bi) + dtoh16(bi->ie_offset)),
7307 dtoh32(bi->ie_length));
7309 if (dtoh32(bi->version) != LEGACY_WL_BSS_INFO_VERSION && bi->n_cap) {
7310 printf("802.11N Capable:\n");
7311 bi->chanspec = dtohchanspec(bi->chanspec);
7312 printf("\tChanspec: %sGHz channel %d %dMHz (0x%x)\n",
7313 CHSPEC_IS2G(bi->chanspec)?"2.4":"5", CHSPEC_CHANNEL(bi->chanspec),
7314 CHSPEC_IS40(bi->chanspec) ? 40 : (CHSPEC_IS20(bi->chanspec) ? 20 : 10),
7315 bi->chanspec);
7316 printf("\tControl channel: %d\n", bi->ctl_ch);
7317 printf("\t802.11N Capabilities: ");
7318 if (dtoh32(bi->nbss_cap) & HT_CAP_40MHZ)
7319 printf("40Mhz ");
7320 if (dtoh32(bi->nbss_cap) & HT_CAP_SHORT_GI_20)
7321 printf("SGI20 ");
7322 if (dtoh32(bi->nbss_cap) & HT_CAP_SHORT_GI_40)
7323 printf("SGI40 ");
7324 printf("\n\tSupported MCS : [ ");
7325 for (mcs_idx = 0; mcs_idx < (MCSSET_LEN * 8); mcs_idx++)
7326 if (isset(bi->basic_mcs, mcs_idx))
7327 printf("%d ", mcs_idx);
7328 printf("]\n");
7331 printf("\n");
7334 static int
7335 _wl_dump_lq(void *wl)
7337 int ret = BCME_OK, noise = 0;
7338 wl_lq_t *plq = NULL;
7339 void *ptr = NULL;
7341 memset(buf, 0, sizeof(wl_lq_t));
7343 /* Display stats when disabled */
7344 if ((ret = wlu_get(wl, WLC_GET_PHY_NOISE, &noise, sizeof(int))) < 0) {
7345 printf("wlc_get noise failed with retcode:%d\n", ret);
7346 return ret;
7349 if ((ret = wlu_var_getbuf_sm (wl, "monitor_lq_status", NULL, 0, &ptr)) < 0) {
7350 printf("wlc_get lq_status failed with retcode:%d\n", ret);
7351 return ret;
7354 plq = (wl_lq_t *)ptr;
7356 if (!plq->isvalid) {
7357 printf("Stats collection currently disabled"
7358 "['wl monitor_lq 1' to enable statistics collection]\n");
7359 return ret;
7362 noise = dtoh32(noise);
7363 plq->rssi[LQ_IDX_MIN] = dtoh32(plq->rssi[LQ_IDX_MIN]);
7364 plq->rssi[LQ_IDX_MAX] = dtoh32(plq->rssi[LQ_IDX_MAX]);
7365 plq->rssi[LQ_IDX_AVG] = dtoh32(plq->rssi[LQ_IDX_AVG]);
7367 printf("rss: %d, %d, %d\nsnr: %d, %d, %d\n",
7368 plq->rssi[LQ_IDX_MIN],
7369 plq->rssi[LQ_IDX_AVG],
7370 plq->rssi[LQ_IDX_MAX],
7371 plq->rssi[LQ_IDX_MIN]-noise,
7372 plq->rssi[LQ_IDX_AVG]-noise,
7373 plq->rssi[LQ_IDX_MAX]-noise);
7375 return ret;
7376 } /* _wl_dump_lq */
7378 static int
7379 wl_dump_lq(void *wl, cmd_t *cmd, char **argv)
7381 int ret = BCME_OK;
7383 UNUSED_PARAMETER(cmd);
7385 if (!*++argv)
7386 ret = _wl_dump_lq(wl);
7388 return ret;
7389 } /* wl_dump_lq */
7391 static int
7392 wl_monitor_lq(void *wl, cmd_t *cmd, char **argv)
7394 int ret = BCME_OK;
7395 char *endptr = NULL;
7396 char **startptr = argv;
7398 if (!*++startptr) { /* Get */
7399 wl_varint(wl, cmd, argv);
7401 else {
7402 int val = *startptr[0];
7403 val = strtol(*startptr, &endptr, 0);
7405 if (*endptr != '\0') {
7406 return -1;
7409 val = htod32(val);
7411 if (val == LQ_STOP_MONITOR) {
7412 ret = _wl_dump_lq(wl);
7415 wl_varint(wl, cmd, argv); /* Standard set call after getting stats */
7418 return ret;
7419 } /* wl_monitor_lq */
7421 static int
7422 wl_dump_networks(void *wl, cmd_t *cmd, char **argv)
7424 int ret;
7425 char *dump_buf, *dump_buf_orig;
7426 uint32 status = 0;
7427 bool iscan = FALSE;
7429 dump_buf_orig = dump_buf = malloc(WL_DUMP_BUF_LEN);
7430 if (dump_buf == NULL) {
7431 fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WL_DUMP_BUF_LEN);
7432 return -1;
7435 iscan = (cmd->get != WLC_SCAN_RESULTS);
7436 if (iscan) {
7437 int buflen = 1920; /* usually fits about 10 BSS infos */
7439 if (*(++argv)) {
7440 char *endptr = NULL;
7441 buflen = strtol(*argv, &endptr, 0);
7442 if (*endptr != '\0') {
7443 ret = -1;
7444 goto exit;
7447 ret = wl_get_iscan(wl, dump_buf, buflen);
7448 } else
7449 ret = wl_get_scan(wl, WLC_SCAN_RESULTS, dump_buf, WL_DUMP_BUF_LEN);
7451 if (ret == 0) {
7452 if (iscan) {
7453 status = dtoh32(((wl_iscan_results_t *)dump_buf)->status);
7454 dump_buf += OFFSETOF(wl_iscan_results_t, results);
7456 dump_networks(dump_buf);
7457 if (iscan) {
7458 switch (status) {
7459 case WL_SCAN_RESULTS_PARTIAL:
7460 printf("iscanresults incomplete\n");
7461 break;
7462 case WL_SCAN_RESULTS_SUCCESS:
7463 printf("iscanresults complete\n");
7464 break;
7465 case WL_SCAN_RESULTS_PENDING:
7466 printf("iscanresults pending\n");
7467 break;
7468 case WL_SCAN_RESULTS_ABORTED:
7469 printf("iscanresults aborted\n");
7470 break;
7471 default:
7472 printf("iscanresults returned unknown status %d\n", status);
7473 break;
7478 exit:
7479 free(dump_buf_orig);
7480 return ret;
7483 static int
7484 wl_dump_chanlist(void *wl, cmd_t *cmd, char **argv)
7486 uint32 chan_buf[WL_NUMCHANNELS + 1];
7487 wl_uint32_list_t *list;
7488 int ret;
7489 uint i;
7491 UNUSED_PARAMETER(argv);
7493 list = (wl_uint32_list_t *)(void *)chan_buf;
7494 list->count = htod32(WL_NUMCHANNELS);
7495 ret = wlu_get(wl, cmd->get, chan_buf, sizeof(chan_buf));
7496 if (ret < 0)
7497 return ret;
7499 for (i = 0; i < dtoh32(list->count); i++)
7500 printf("%d ", dtoh32(list->element[i]));
7501 printf("\n");
7502 return ret;
7505 static int
7506 wl_cur_mcsset(void *wl, cmd_t *cmd, char **argv)
7508 int ret;
7510 UNUSED_PARAMETER(cmd);
7511 UNUSED_PARAMETER(argv);
7513 memset(buf, 0, WLC_IOCTL_SMLEN);
7514 ret = wlu_iovar_get(wl, "cur_mcsset", &buf[0], MCSSET_LEN);
7515 if (ret < 0)
7516 return ret;
7518 wl_print_mcsset(buf);
7520 return ret;
7524 static int
7525 wl_dump_chanspecs(void *wl, cmd_t *cmd, char **argv)
7527 miniopt_t to;
7528 const char* fn_name = "wl_dump_chanspecs";
7529 wl_uint32_list_t *list;
7530 chanspec_t c = 0, *chanspec;
7531 int ret, buflen;
7532 uint i;
7533 int err, opt_err;
7534 bool band_set = FALSE, bw_set = FALSE;
7535 char abbrev[WLC_CNTRY_BUF_SZ] = ""; /* default.. current locale */
7536 char chspec_str[CHANSPEC_STR_LEN];
7538 UNUSED_PARAMETER(cmd);
7539 UNUSED_PARAMETER(argv);
7541 memset(buf, 0, WLC_IOCTL_MAXLEN);
7543 strcpy(buf, "chanspecs");
7544 buflen = strlen(buf) + 1;
7546 /* toss the command name */
7547 argv++;
7549 /* Validate arguments if any */
7550 if (*argv) {
7551 miniopt_init(&to, fn_name, NULL, FALSE);
7552 while ((opt_err = miniopt(&to, argv)) != -1) {
7553 if (opt_err == 1) {
7554 err = -1;
7555 goto exit;
7557 argv += to.consumed;
7559 if (to.opt == 'b') {
7560 if (!to.good_int) {
7561 fprintf(stderr,
7562 "%s: could not parse \"%s\" as an int for band\n",
7563 fn_name, to.valstr);
7564 err = -1;
7565 goto exit;
7567 if ((to.val != 5) && (to.val != 2)) {
7568 fprintf(stderr,
7569 "%s: invalid band %d\n",
7570 fn_name, to.val);
7571 err = -1;
7572 goto exit;
7574 if (to.val == 5)
7575 c |= WL_CHANSPEC_BAND_5G;
7576 else
7577 c |= WL_CHANSPEC_BAND_2G;
7578 band_set = TRUE;
7580 if (to.opt == 'w') {
7581 if (!to.good_int) {
7582 fprintf(stderr,
7583 "%s: could not parse \"%s\" as an int for"
7584 " bandwidth\n",
7585 fn_name, to.valstr);
7586 err = -1;
7587 goto exit;
7589 if ((to.val != 20) && (to.val != 40)) {
7590 fprintf(stderr,
7591 "%s: invalid bandwidth %d\n",
7592 fn_name, to.val);
7593 err = -1;
7594 goto exit;
7596 if (to.val == 20)
7597 c |= WL_CHANSPEC_BW_20;
7598 else
7599 c |= WL_CHANSPEC_BW_40;
7600 bw_set = TRUE;
7602 if (to.opt == 'c') {
7603 if (!to.valstr) {
7604 fprintf(stderr,
7605 "%s: please provide country abbrev \n", fn_name);
7606 err = -1;
7607 goto exit;
7609 strncpy(abbrev, to.valstr, WLC_CNTRY_BUF_SZ - 1);
7610 abbrev[WLC_CNTRY_BUF_SZ - 1] = '\0';
7613 if (!bw_set || !band_set) {
7614 if (!band_set)
7615 fprintf(stderr, "%s: you need to set a band, '-b <5|2>'\n",
7616 fn_name);
7617 if (!bw_set)
7618 fprintf(stderr, "%s: you need to set a bandwidth, '-w <20|40>'\n",
7619 fn_name);
7620 err = -1;
7621 goto exit;
7625 /* Add chanspec argument */
7626 chanspec = (chanspec_t *) (buf + buflen);
7627 *chanspec = htodchanspec(c);
7628 buflen += (sizeof(chanspec_t));
7630 /* Add country abbrev */
7631 strncpy(buf + buflen, abbrev, WLC_CNTRY_BUF_SZ);
7632 buflen += WLC_CNTRY_BUF_SZ;
7634 /* Add list */
7635 list = (wl_uint32_list_t *)(buf + buflen);
7636 list->count = htod32(WL_NUMCHANSPECS);
7637 buflen += sizeof(uint32)*(WL_NUMCHANSPECS + 1);
7639 ret = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen);
7640 if (ret < 0)
7641 return ret;
7643 list = (wl_uint32_list_t *)buf;
7644 for (i = 0; i < dtoh32(list->count); i++) {
7645 c = (chanspec_t)dtoh32(list->element[i]);
7646 wf_chspec_ntoa(c, chspec_str);
7647 printf("%s (0x%04x)\n", chspec_str, c);
7649 printf("\n");
7650 return ret;
7652 exit:
7653 return err;
7656 static int
7657 wl_channels_in_country(void *wl, cmd_t *cmd, char **argv)
7659 wl_channels_in_country_t *cic;
7660 int ret;
7661 uint i, len;
7663 cic = (wl_channels_in_country_t *)buf;
7664 cic->buflen = WLC_IOCTL_MAXLEN;
7665 cic->count = 0;
7667 /* country abbrev must follow */
7668 if (!*++argv) {
7669 fprintf(stderr, "missing country abbrev\n");
7670 return -1;
7673 len = strlen(*argv);
7674 if ((len > 3) || (len < 2)) {
7675 fprintf(stderr, "invalid country abbrev: %s\n", *argv);
7676 return -1;
7679 strcpy(cic->country_abbrev, *argv);
7681 /* band must follow */
7682 if (!*++argv) {
7683 fprintf(stderr, "missing band\n");
7684 return -1;
7687 if (!stricmp(*argv, "a"))
7688 cic->band = WLC_BAND_5G;
7689 else if (!stricmp(*argv, "b"))
7690 cic->band = WLC_BAND_2G;
7691 else {
7692 fprintf(stderr, "unsupported band: %s\n", *argv);
7693 return -1;
7696 cic->buflen = htod32(cic->buflen);
7697 cic->band = htod32(cic->band);
7698 cic->count = htod32(cic->count);
7699 ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN);
7700 if (ret < 0)
7701 return ret;
7703 for (i = 0; i < dtoh32(cic->count); i++)
7704 printf("%d ", dtoh32(cic->channel[i]));
7705 printf("\n");
7707 return ret;
7710 static int
7711 wl_get_scan(void *wl, int opc, char *scan_buf, uint buf_len)
7713 wl_scan_results_t *list = (wl_scan_results_t*)scan_buf;
7714 int ret;
7716 list->buflen = htod32(buf_len);
7717 ret = wlu_get(wl, opc, scan_buf, buf_len);
7718 if (ret < 0)
7719 return ret;
7720 ret = 0;
7722 list->buflen = dtoh32(list->buflen);
7723 list->version = dtoh32(list->version);
7724 list->count = dtoh32(list->count);
7725 if (list->buflen == 0) {
7726 list->version = 0;
7727 list->count = 0;
7728 } else if (list->version != WL_BSS_INFO_VERSION &&
7729 list->version != LEGACY2_WL_BSS_INFO_VERSION &&
7730 list->version != LEGACY_WL_BSS_INFO_VERSION) {
7731 fprintf(stderr, "Sorry, your driver has bss_info_version %d "
7732 "but this program supports only version %d.\n",
7733 list->version, WL_BSS_INFO_VERSION);
7734 list->buflen = 0;
7735 list->count = 0;
7738 return ret;
7741 static int
7742 wl_get_iscan(void *wl, char *scan_buf, uint buf_len)
7744 wl_iscan_results_t list;
7745 wl_scan_results_t *results;
7746 int ret;
7748 memset(&list, '\0', sizeof(list));
7749 list.results.buflen = htod32(buf_len);
7750 ret = wlu_iovar_getbuf(wl, "iscanresults", &list, WL_ISCAN_RESULTS_FIXED_SIZE,
7751 scan_buf, WLC_IOCTL_MAXLEN);
7753 if (ret < 0)
7754 return ret;
7756 ret = 0;
7758 results = &((wl_iscan_results_t*)scan_buf)->results;
7759 results->buflen = dtoh32(results->buflen);
7760 results->version = dtoh32(results->version);
7761 results->count = dtoh32(results->count);
7762 if (results->buflen == 0) {
7763 printf("wl_get_iscan buflen 0\n");
7764 results->version = 0;
7765 results->count = 0;
7766 } else if (results->version != WL_BSS_INFO_VERSION &&
7767 results->version != LEGACY2_WL_BSS_INFO_VERSION &&
7768 results->version != LEGACY_WL_BSS_INFO_VERSION) {
7769 fprintf(stderr, "Sorry, your driver has bss_info_version %d "
7770 "but this program supports only version %d.\n",
7771 results->version, WL_BSS_INFO_VERSION);
7772 results->buflen = 0;
7773 results->count = 0;
7776 return ret;
7779 static int
7780 wl_spect(void *wl, cmd_t *cmd, char **argv)
7782 int ret, spect;
7783 char *endptr = NULL;
7785 if (!*++argv) {
7786 if ((ret = wlu_get(wl, cmd->get, &spect, sizeof(spect))) < 0) {
7787 return ret;
7790 spect = dtoh32(spect);
7791 switch (spect) {
7792 case SPECT_MNGMT_OFF:
7793 printf("Off\n");
7794 break;
7796 case SPECT_MNGMT_LOOSE_11H:
7797 printf("Loose interpretation of 11h spec - may join non 11h AP.\n");
7798 break;
7800 case SPECT_MNGMT_STRICT_11H:
7801 printf("Strict interpretation of 11h spec - may not join non 11h AP.\n");
7802 break;
7804 case SPECT_MNGMT_STRICT_11D:
7805 printf("802.11d mode\n");
7806 break;
7808 case SPECT_MNGMT_LOOSE_11H_D:
7809 printf("Loose interpretation of 11h+d spec - may join non-11h APs\n");
7810 break;
7812 default:
7813 printf("invalid value 0x%x\n", spect);
7814 return -1;
7815 break;
7817 return (0);
7818 } else {
7819 spect = strtol(*argv, &endptr, 0);
7820 if (*endptr != '\0')
7821 return (-1);
7823 if (spect < SPECT_MNGMT_OFF || spect > SPECT_MNGMT_LOOSE_11H_D)
7824 return (-1);
7826 spect = htod32(spect);
7827 return wlu_set(wl, cmd->set, &spect, sizeof(spect));
7831 static int
7832 wl_status(void *wl, cmd_t *cmd, char **argv)
7834 int ret;
7835 struct ether_addr bssid;
7836 wlc_ssid_t ssid;
7837 char ssidbuf[SSID_FMT_BUF_LEN];
7838 wl_bss_info_t *bi;
7840 UNUSED_PARAMETER(cmd);
7841 UNUSED_PARAMETER(argv);
7843 if ((ret = wlu_get(wl, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) == 0) {
7844 /* The adapter is associated. */
7845 *(uint32*)buf = htod32(WLC_IOCTL_MAXLEN);
7846 if ((ret = wlu_get(wl, WLC_GET_BSS_INFO, buf, WLC_IOCTL_MAXLEN)) < 0)
7847 return ret;
7849 bi = (wl_bss_info_t*)(buf + 4);
7850 if (dtoh32(bi->version) == WL_BSS_INFO_VERSION ||
7851 dtoh32(bi->version) == LEGACY2_WL_BSS_INFO_VERSION ||
7852 dtoh32(bi->version) == LEGACY_WL_BSS_INFO_VERSION)
7853 dump_bss_info(bi);
7854 else
7855 fprintf(stderr, "Sorry, your driver has bss_info_version %d "
7856 "but this program supports only version %d.\n",
7857 bi->version, WL_BSS_INFO_VERSION);
7858 } else {
7859 printf("Not associated. Last associated with ");
7861 if ((ret = wlu_get(wl, WLC_GET_SSID, &ssid, sizeof(wlc_ssid_t))) < 0) {
7862 printf("\n");
7863 return ret;
7866 wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len));
7867 printf("SSID: \"%s\"\n", ssidbuf);
7870 return 0;
7873 static int
7874 wl_deauth_rc(void *wl, cmd_t *cmd, char **argv)
7876 scb_val_t scb_val;
7877 int ret;
7879 if (!*++argv) {
7880 fprintf(stderr, "STA MAC must be specified\n");
7881 ret = -1;
7883 } else if (!wl_ether_atoe(*argv, &scb_val.ea)) {
7884 fprintf(stderr, "Malformed STA MAC parameter\n");
7885 ret = -1;
7887 } else if (!*++argv) {
7888 /* No reason code furnished, so driver will use its default */
7889 ret = wlu_set(wl, WLC_SCB_DEAUTHENTICATE, &scb_val.ea,
7890 ETHER_ADDR_LEN);
7892 } else {
7893 scb_val.val = htod32((uint32)strtoul(*argv, NULL, 0));
7894 ret = wlu_set(wl, cmd->set, &scb_val, sizeof(scb_val));
7896 return ret;
7899 static int
7900 wl_wpa_auth(void *wl, cmd_t *cmd, char **argv)
7902 int bsscfg_idx = 0;
7903 int consumed;
7904 int wpa_auth = 0;
7905 int ret = 0;
7906 int i;
7907 static struct {
7908 int val;
7909 const char *name;
7910 } auth_mode[] =
7911 /* Keep the numeric values in the staticly initialized
7912 * help string consistent. Unfortunately, there isn't
7913 * an automatic way for that.
7915 {{WPA_AUTH_NONE, "WPA-NONE"},
7916 {WPA_AUTH_UNSPECIFIED, "WPA-802.1x"},
7917 {WPA_AUTH_PSK, "WPA-PSK"},
7918 {WPA2_AUTH_UNSPECIFIED, "WPA2-802.1x"},
7919 {WPA2_AUTH_PSK, "WPA2-PSK"},
7920 {WPA_AUTH_DISABLED, "disabled"}};
7922 /* skip the command name */
7923 argv++;
7925 /* parse a bsscfg_idx option if present */
7926 if ((ret = wl_cfg_option(argv, cmd->name, &bsscfg_idx, &consumed)) != 0)
7927 return ret;
7929 argv += consumed;
7931 if (!*argv) {
7932 /* no arg, so this is a GET. */
7934 if (!consumed)
7935 ret = wlu_iovar_getint(wl, "wpa_auth", &wpa_auth);
7936 else
7937 ret = wl_bssiovar_getint(wl, "wpa_auth", bsscfg_idx, &wpa_auth);
7939 if (ret < 0)
7940 return ret;
7942 /* Show all AKM suites enabled */
7943 printf("0x%x", wpa_auth);
7945 if (wpa_auth == WPA_AUTH_DISABLED)
7946 printf(" Disabled");
7948 for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) {
7949 if (wpa_auth & auth_mode[i].val)
7950 printf(" %s", auth_mode[i].name);
7953 printf("\n");
7954 return ret;
7957 } else {
7958 /* there's an arg, so this is a SET. */
7959 ret = 1;
7961 /* Validate the user input range */
7962 if (isdigit((int)*argv[0])) {
7963 unsigned int range = 0;
7965 /* param is a number; look for value in the list */
7966 wpa_auth = strtoul(*argv, NULL, 0);
7968 /* Validate the user input range */
7970 for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++)
7971 range |= auth_mode[i].val;
7973 range = (~range) & 0xFFFF;
7975 if (range & wpa_auth) {
7976 ret = 1;
7977 goto usage;
7978 } else {
7979 ret = 0;
7982 } else {
7984 int arg_count = 0;
7985 char** p_argv;
7986 int j = 0;
7987 unsigned int range = 0;
7989 wpa_auth = 0;
7990 p_argv = argv;
7992 for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++)
7993 range |= auth_mode[i].val;
7995 range = (~range) & (0xFFFF);
7997 while (*p_argv) {
7998 arg_count++;
7999 p_argv++;
8002 p_argv = argv;
8004 for (j = 0; j < arg_count; j++) {
8005 bool found = FALSE;
8007 argv = p_argv + j;
8009 /* treat param as string to be matched in list */
8010 for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) {
8011 if (!stricmp(auth_mode[i].name, *argv)) {
8013 found = TRUE;
8014 wpa_auth |= auth_mode[i].val;
8015 ret = 0;
8017 /* traverse the list */
8018 argv++;
8019 if (!*argv)
8020 break;
8024 if ((found == FALSE) || (range & wpa_auth))
8025 goto usage;
8029 if (ret)
8030 fprintf(stderr, "%s is not a valid WPA auth mode\n", *argv);
8031 else {
8032 if (!consumed)
8033 ret = wlu_iovar_setint(wl, "wpa_auth", wpa_auth);
8034 else
8035 ret = wl_bssiovar_setint(wl, "wpa_auth", bsscfg_idx, wpa_auth);
8039 return ret;
8041 usage:
8042 fprintf(stderr, "Inavlid user argument.\n");
8043 fprintf(stderr, "Values may be a bitvector or list of names from the set.\n");
8045 for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) {
8046 fprintf(stderr, "\n0x%04x %s", auth_mode[i].val, auth_mode[i].name);
8049 printf("\n");
8050 return ret;
8053 static int
8054 wl_set_pmk(void *wl, cmd_t *cmd, char **argv)
8056 wsec_pmk_t psk;
8057 size_t key_len;
8059 if (!*++argv) {
8060 return -1;
8062 key_len = strlen(*argv);
8063 if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
8064 fprintf(stderr, "passphrase must be between %d and %d characters long\n",
8065 WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN);
8066 return -1;
8068 psk.key_len = htod16((ushort) key_len);
8069 psk.flags = htod16(WSEC_PASSPHRASE);
8070 memcpy(psk.key, *argv, key_len);
8071 return wlu_set(wl, cmd->set, &psk, sizeof(psk));
8074 static int
8075 wl_wsec(void *wl, cmd_t *cmd, char **argv)
8077 int wsec;
8078 int bsscfg_idx = 0;
8079 int consumed;
8080 char *endptr = NULL;
8081 int error;
8083 UNUSED_PARAMETER(cmd);
8085 argv++;
8087 /* parse a bsscfg_idx option if present */
8088 if ((error = wl_cfg_option(argv, "wsec", &bsscfg_idx, &consumed)) != 0)
8089 return error;
8091 argv += consumed;
8093 if (!*argv) {
8094 /* This is a GET */
8095 if (consumed == 0) {
8096 error = wlu_get(wl, WLC_GET_WSEC, &wsec, sizeof(uint32));
8097 wsec = dtoh32(wsec);
8099 else
8100 error = wl_bssiovar_getint(wl, "wsec", bsscfg_idx, &wsec);
8102 if (!error)
8103 wl_printint(wsec);
8104 } else {
8105 /* This is a SET */
8106 if (!stricmp(*argv, "off"))
8107 wsec = 0;
8108 else {
8109 wsec = strtol(*argv, &endptr, 0);
8110 if (*endptr != '\0') {
8111 /* not all the value string was parsed by strtol */
8112 return -1;
8116 if (consumed == 0) {
8117 wsec = htod32(wsec);
8118 error = wlu_set(wl, WLC_SET_WSEC, &wsec, sizeof(uint32));
8120 else
8121 error = wl_bssiovar_setint(wl, "wsec", bsscfg_idx, wsec);
8124 return error;
8127 static int
8128 parse_wep(char **argv, wl_wsec_key_t *key, bool options)
8130 char hex[] = "XX";
8131 unsigned char *data = key->data;
8132 char *keystr = *argv;
8134 switch (strlen(keystr)) {
8135 case 5:
8136 case 13:
8137 case 16:
8138 key->len = strlen(keystr);
8139 memcpy(data, keystr, key->len + 1);
8140 break;
8141 case 12:
8142 case 28:
8143 case 34:
8144 case 66:
8145 /* strip leading 0x */
8146 if (!strnicmp(keystr, "0x", 2))
8147 keystr += 2;
8148 else
8149 return -1;
8150 /* fall through */
8151 case 10:
8152 case 26:
8153 case 32:
8154 case 64:
8155 key->len = strlen(keystr) / 2;
8156 while (*keystr) {
8157 strncpy(hex, keystr, 2);
8158 *data++ = (char) strtoul(hex, NULL, 16);
8159 keystr += 2;
8161 break;
8162 default:
8163 return -1;
8166 switch (key->len) {
8167 case 5:
8168 key->algo = CRYPTO_ALGO_WEP1;
8169 break;
8170 case 13:
8171 key->algo = CRYPTO_ALGO_WEP128;
8172 break;
8173 case 16:
8174 /* default to AES-CCM */
8175 key->algo = CRYPTO_ALGO_AES_CCM;
8176 break;
8177 case 32:
8178 key->algo = CRYPTO_ALGO_TKIP;
8179 break;
8180 default:
8181 return -1;
8184 /* Set as primary key by default */
8185 key->flags |= WL_PRIMARY_KEY;
8187 if (options) {
8188 /* Get options */
8189 while (*++argv) {
8190 if (!strnicmp("ccm", *argv, 3) && key->len == 16)
8191 key->algo = CRYPTO_ALGO_AES_CCM;
8192 #ifdef BCMWAPI_WPI
8193 else if (!strnicmp("wapi", *argv, 4) && key->len == 32)
8194 key->algo = CRYPTO_ALGO_SMS4;
8195 #endif /* BCMWAPI_WPI */
8196 else if (!strnicmp("ocb", *argv, 3) && key->len == 16)
8197 key->algo = CRYPTO_ALGO_AES_OCB_MPDU;
8198 else if (!strnicmp("notx", *argv, 4))
8199 key->flags &= ~WL_PRIMARY_KEY;
8200 else if (!wl_ether_atoe(*argv, &key->ea))
8201 memset(&key->ea, 0, ETHER_ADDR_LEN);
8205 return 0;
8208 static int
8209 wl_primary_key(void *wl, cmd_t *cmd, char **argv)
8211 int i, val, ret = 0;
8213 if (!*++argv) {
8214 i = 0;
8215 do {
8216 val = htod32(i);
8217 if (wlu_get(wl, cmd->get, &val, sizeof(val)) < 0) {
8218 return -1;
8220 if (dtoh32(val)) {
8221 printf("Key %d is primary\n", i);
8222 return 0;
8224 } while (++i < DOT11_MAX_DEFAULT_KEYS);
8225 printf("No primary key set\n");
8227 } else {
8228 val = htod32(atoi(*argv));
8229 ret = wlu_set(wl, cmd->set, &val, sizeof(val));
8231 return ret;
8234 static int
8235 wl_addwep(void *wl, cmd_t *cmd, char **argv)
8237 wl_wsec_key_t key;
8238 int bsscfg_idx = 0;
8239 int consumed;
8240 int error;
8242 memset(&key, 0, sizeof(key));
8244 argv++;
8246 /* parse a bsscfg_idx option if present */
8247 if ((error = wl_cfg_option(argv, "addwep", &bsscfg_idx, &consumed)) != 0)
8248 return error;
8250 argv += consumed;
8252 /* GET operation not allowed */
8253 if (!*argv)
8254 return -1;
8256 key.index = atoi(*argv++);
8258 if (!*argv) {
8259 fprintf(stderr, "No key specified\n");
8260 return -1;
8262 if (parse_wep(argv, &key, TRUE))
8263 return -1;
8265 key.index = htod32(key.index);
8266 key.len = htod32(key.len);
8267 key.algo = htod32(key.algo);
8268 key.flags = htod32(key.flags);
8270 if (consumed == 0) {
8271 error = wlu_set(wl, cmd->set, &key, sizeof(key));
8272 } else {
8273 error = wl_bssiovar_setbuf(wl, "wsec_key", bsscfg_idx,
8274 &key, sizeof(key), buf, WLC_IOCTL_MAXLEN);
8277 return error;
8280 static int
8281 wl_rmwep(void *wl, cmd_t *cmd, char **argv)
8283 wl_wsec_key_t key;
8284 int bsscfg_idx = 0;
8285 int consumed;
8286 int error;
8288 memset(&key, 0, sizeof(key));
8290 argv++;
8292 /* parse a bsscfg_idx option if present */
8293 if ((error = wl_cfg_option(argv, "rmwep", &bsscfg_idx, &consumed)) != 0)
8294 return error;
8296 argv += consumed;
8298 /* GET operation not allowed */
8299 if (!*argv)
8300 return -1;
8302 key.index = htod32(atoi(*argv++));
8304 if (*argv) {
8305 if (!(wl_ether_atoe(*argv, &key.ea)))
8306 return -1;
8309 if (consumed == 0) {
8310 error = wlu_set(wl, cmd->set, &key, sizeof(key));
8311 } else {
8312 error = wlu_var_setbuf(wl, "wsec_key", &key, sizeof(key));
8315 return error;
8318 static struct {
8319 uint value;
8320 const char *string;
8321 } wsec_test[] = {
8322 {WSEC_GEN_MIC_ERROR, "mic_error"},
8323 {WSEC_GEN_REPLAY, "replay"},
8324 {WSEC_GEN_ICV_ERROR, "icv_error"},
8325 {WSEC_GEN_MFP_ACT_ERROR, "act_error"},
8326 {WSEC_GEN_MFP_DISASSOC_ERROR, "disassoc_error"},
8327 {WSEC_GEN_MFP_DEAUTH_ERROR, "deauth_error"},
8328 {0, NULL}
8332 static int
8333 wl_wsec_test(void *wl, cmd_t *cmd, char **argv)
8335 wl_wsec_key_t *key;
8336 int i, len;
8337 char *endptr = NULL, *wsec_buf = NULL;
8338 uint32 val, last_val;
8339 int err = 0;
8341 if (!*++argv)
8342 goto usage;
8344 val = strtol(*argv, &endptr, 0);
8345 if (endptr == *argv) {
8346 /* the value string was not parsed by strtol */
8347 for (i = 0; wsec_test[i].value; i++)
8348 if (stricmp(wsec_test[i].string, *argv) == 0) {
8349 val = wsec_test[i].value;
8350 break;
8352 if (wsec_test[i].value == 0)
8353 goto usage;
8355 ++argv;
8357 switch (val) {
8358 case WSEC_GEN_REPLAY:
8359 case WSEC_GEN_MIC_ERROR:
8360 case WSEC_GEN_ICV_ERROR:
8361 case WSEC_GEN_MFP_ACT_ERROR:
8362 case WSEC_GEN_MFP_DISASSOC_ERROR:
8363 case WSEC_GEN_MFP_DEAUTH_ERROR:
8364 if (!*argv) {
8365 fprintf(stderr, "insufficient arguments\n");
8366 return -1;
8368 len = sizeof(wl_wsec_key_t) + 4;
8369 wsec_buf = malloc(len);
8370 *(uint32 *)wsec_buf = htod32(val);
8371 key = (wl_wsec_key_t *)&wsec_buf[4];
8372 memset(key, 0, sizeof(wl_wsec_key_t));
8373 /* If it doesn't look like an ether addr, suppose it's a key index */
8374 if (!(wl_ether_atoe(*argv, &key->ea))) {
8375 memset(&key->ea, 0, ETHER_ADDR_LEN);
8376 key->index = htod32(atoi(*argv));
8378 break;
8379 default:
8380 goto usage;
8381 break;
8384 err = wlu_set(wl, cmd->set, wsec_buf, len);
8385 free(wsec_buf);
8386 goto exit;
8388 usage:
8389 fprintf(stderr, "wsec test_type may be a number or name from the following set:");
8390 last_val = 0xffffffff;
8391 for (i = 0; (val = wsec_test[i].value); i++) {
8392 if (val != last_val)
8393 fprintf(stderr, "\n0x%04x %s", val, wsec_test[i].string);
8394 else
8395 fprintf(stderr, ", %s", wsec_test[i].string);
8396 last_val = val;
8398 fprintf(stderr, "\n");
8400 exit:
8401 return err;
8404 static int
8405 wl_keys(void *wl, cmd_t *cmd, char **argv)
8407 int ret;
8408 uint i, j;
8409 union {
8410 int index;
8411 wl_wsec_key_t key;
8412 } u;
8413 int wep_is_on = 0;
8414 const char *addr;
8415 int empty_first, empty_last;
8416 bool empty;
8418 UNUSED_PARAMETER(argv);
8420 if ((ret = wlu_iovar_getint(wl, "wsec", &wep_is_on)) < 0)
8421 fprintf(stderr, "Could not query wsec status.\n");
8423 empty_first = empty_last = -1;
8425 for (i = 0; ; i++) { /* The upper limit is not known here. */
8426 u.index = htod32(i);
8427 ret = wlu_get(wl, cmd->get, &u, sizeof(u));
8428 empty = (ETHER_ISNULLADDR(&u.key.ea) && dtoh32(u.key.algo) == CRYPTO_ALGO_OFF);
8430 if (empty_first != -1 &&
8431 (ret < 0 || !empty)) {
8432 if (empty_first == empty_last)
8433 printf("%3d: <empty>\n", empty_first);
8434 else
8435 printf("%3d - %3d: <empty>\n", empty_first, empty_last);
8436 empty_first = empty_last = -1;
8439 if (ret < 0) {
8440 /* If at least one beyond the defaults could be read,
8441 * not knowing the limit must have been the error.
8443 return (i >= DOT11_MAX_DEFAULT_KEYS) ? 0 : ret;
8446 /* Key may not have been set yet */
8447 if (i < DOT11_MAX_DEFAULT_KEYS)
8448 addr = "(default)";
8449 else if (empty) {
8450 if (empty_first == -1) empty_first = i;
8451 empty_last = i;
8452 continue;
8453 } else
8454 addr = wl_ether_etoa(&u.key.ea);
8456 printf("%3d: %-17s Key %d: %s ", i, addr, dtoh32(u.key.index),
8457 bcm_crypto_algo_name(dtoh32(u.key.algo)));
8459 if (wep_is_on && dtoh32(u.key.flags) & WL_PRIMARY_KEY)
8460 printf("*");
8461 printf("\t");
8463 if (dtoh32(u.key.len) == 0)
8464 printf("No key present");
8465 else {
8466 if (dtoh32(u.key.flags) & WL_SOFT_KEY)
8467 printf("soft ");
8468 printf("len %d, data 0x", dtoh32(u.key.len));
8469 for (j = 0; j < dtoh32(u.key.len); j++)
8470 printf("%02X", u.key.data[j]);
8472 for (j = 0; j < dtoh32(u.key.len); j++)
8473 if (!isprint(u.key.data[j]))
8474 break;
8475 if (j == dtoh32(u.key.len))
8476 printf(" (%.*s)", (int)dtoh32(u.key.len), u.key.data);
8480 printf("\n");
8483 return 0;
8486 static int
8487 wl_tsc(void *wl, cmd_t *cmd, char **argv)
8489 union {
8490 int32 index;
8491 uint8 tsc[DOT11_WPA_KEY_RSC_LEN];
8492 } u;
8493 uint32 hi, lo;
8494 int idx, ret;
8496 if (!*++argv)
8497 return -1;
8498 idx = atoi(*argv);
8499 if (idx < 0) {
8500 fprintf(stderr, "Key index %d out of range. Should be positive.\n", idx);
8501 return -1;
8503 u.index = htod32(idx);
8504 if ((ret = wlu_get(wl, cmd->get, &u, sizeof(u))) < 0)
8505 return ret;
8506 lo = u.tsc[0] | (u.tsc[1] << 8) | (u.tsc[2] << 16) | (u.tsc[3] << 24);
8507 hi = u.tsc[4] | (u.tsc[5] << 8) | (u.tsc[6] << 16) | (u.tsc[7] << 24);
8509 printf("Key %d TSC: 0x%04x:%08x\n", idx, hi, lo);
8510 return 0;
8513 static void
8514 wl_txppr_print(txppr_t *ppr, int cck, int isht)
8516 uint i;
8517 uint n = isht ? WL_NUM_3x3_ELEMENTS : WL_NUM_2x2_ELEMENTS;
8518 uint offset = isht ? WL_NUM_3x3_ELEMENTS : 0;
8519 uint8 *ptr;
8520 const char *str = "";
8522 printf("20MHz:\n");
8523 if (cck) {
8524 printf("CCK %2d %2d %2d %2d\n", ppr->cck[0], ppr->cck[1],
8525 ppr->cck[2], ppr->cck[3]);
8526 if (isht) {
8527 printf("CCK CDD 1x2 %2d %2d %2d %2d\n",
8528 ppr->cck_cdd.s1x2[0], ppr->cck_cdd.s1x2[1],
8529 ppr->cck_cdd.s1x2[2], ppr->cck_cdd.s1x2[3]);
8530 printf("CCK CDD 1x3 %2d %2d %2d %2d\n",
8531 ppr->cck_cdd.s1x3[0], ppr->cck_cdd.s1x3[1],
8532 ppr->cck_cdd.s1x3[2], ppr->cck_cdd.s1x3[3]);
8535 printf("OFDM %2d %2d %2d %2d %2d %2d %2d %2d\n",
8536 ppr->ofdm[0], ppr->ofdm[1], ppr->ofdm[2], ppr->ofdm[3],
8537 ppr->ofdm[4], ppr->ofdm[5], ppr->ofdm[6], ppr->ofdm[7]);
8538 printf("OFDM-CDD %2d %2d %2d %2d %2d %2d %2d %2d\n",
8539 ppr->ofdm_cdd[0], ppr->ofdm_cdd[1], ppr->ofdm_cdd[2], ppr->ofdm_cdd[3],
8540 ppr->ofdm_cdd[4], ppr->ofdm_cdd[5], ppr->ofdm_cdd[6], ppr->ofdm_cdd[7]);
8541 for (i = 0; i < n; i++) {
8542 switch (i + offset) {
8543 case 0:
8544 str = "MCS-SISO ";
8545 ptr = ppr->u20.n.siso;
8546 break;
8547 case 1:
8548 str = "MCS-CDD ";
8549 ptr = ppr->u20.n.cdd;
8550 break;
8551 case 2:
8552 str = "MCS STBC ";
8553 ptr = ppr->u20.n.stbc;
8554 break;
8555 case 3:
8556 str = "MCS 8~15 ";
8557 ptr = ppr->u20.n.sdm;
8558 break;
8559 case 4:
8560 case 5:
8561 ptr = NULL;
8562 break;
8563 case 6:
8564 str = "1 Nsts 1 Tx ";
8565 ptr = ppr->u20.ht.s1x1;
8566 break;
8567 case 7:
8568 str = "1 Nsts 2 Tx ";
8569 ptr = ppr->u20.ht.s1x2;
8570 break;
8571 case 8:
8572 str = "1 Nsts 3 Tx ";
8573 ptr = ppr->ht.u20s1x3;
8574 break;
8575 case 9:
8576 str = "2 Nsts 2 Tx ";
8577 ptr = ppr->u20.ht.s2x2;
8578 break;
8579 case 10:
8580 str = "2 Nsts 3 Tx ";
8581 ptr = ppr->ht.u20s2x3;
8582 break;
8583 case 11:
8584 str = "3 Nsts 3 Tx ";
8585 ptr = ppr->u20.ht.s3x3;
8586 break;
8587 default:
8588 ptr = NULL;
8589 break;
8591 printf("%s %2d %2d %2d %2d %2d %2d %2d %2d\n",
8592 str, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
8595 printf("\n40MHz:\n");
8596 printf("OFDM %2d %2d %2d %2d %2d %2d %2d %2d\n",
8597 ppr->ofdm_40[0], ppr->ofdm_40[1], ppr->ofdm_40[2], ppr->ofdm_40[3],
8598 ppr->ofdm_40[4], ppr->ofdm_40[5], ppr->ofdm_40[6], ppr->ofdm_40[7]);
8599 printf("OFDM-CDD %2d %2d %2d %2d %2d %2d %2d %2d\n",
8600 ppr->ofdm_40_cdd[0], ppr->ofdm_40_cdd[1], ppr->ofdm_40_cdd[2], ppr->ofdm_40_cdd[3],
8601 ppr->ofdm_40_cdd[4], ppr->ofdm_40_cdd[5], ppr->ofdm_40_cdd[6], ppr->ofdm_40_cdd[7]);
8602 for (i = 0; i < n; i++) {
8603 switch (i + offset) {
8604 case 0:
8605 str = "MCS-SISO ";
8606 ptr = ppr->u40.n.siso;
8607 break;
8608 case 1:
8609 str = "MCS-CDD ";
8610 ptr = ppr->u40.n.cdd;
8611 break;
8612 case 2:
8613 str = "MCS STBC ";
8614 ptr = ppr->u40.n.stbc;
8615 break;
8616 case 3:
8617 str = "MCS 8~15 ";
8618 ptr = ppr->u40.n.sdm;
8619 break;
8620 case 4:
8621 case 5:
8622 ptr = NULL;
8623 break;
8624 case 6:
8625 str = "1 Nsts 1 Tx ";
8626 ptr = ppr->u40.ht.s1x1;
8627 break;
8628 case 7:
8629 str = "1 Nsts 2 Tx ";
8630 ptr = ppr->u40.ht.s1x2;
8631 break;
8632 case 8:
8633 str = "1 Nsts 3 Tx ";
8634 ptr = ppr->ht.u40s1x3;
8635 break;
8636 case 9:
8637 str = "2 Nsts 2 Tx ";
8638 ptr = ppr->u40.ht.s2x2;
8639 break;
8640 case 10:
8641 str = "2 Nsts 3 Tx ";
8642 ptr = ppr->ht.u40s2x3;
8643 break;
8644 case 11:
8645 str = "3 Nsts 3 Tx ";
8646 ptr = ppr->u40.ht.s3x3;
8647 break;
8648 default:
8649 ptr = NULL;
8650 break;
8652 printf("%s %2d %2d %2d %2d %2d %2d %2d %2d\n",
8653 str, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
8655 printf("MCS32 %2d\n", ppr->mcs32);
8657 printf("\n20 in 40MHz:\n");
8658 if (cck) {
8659 printf("CCK %2d %2d %2d %2d\n", ppr->cck_20ul[0], ppr->cck_20ul[1],
8660 ppr->cck_20ul[2], ppr->cck_20ul[3]);
8661 if (isht) {
8662 printf("CCK CDD 1x2 %2d %2d %2d %2d\n",
8663 ppr->cck_20ul_cdd.s1x2[0], ppr->cck_20ul_cdd.s1x2[1],
8664 ppr->cck_20ul_cdd.s1x2[2], ppr->cck_20ul_cdd.s1x2[3]);
8665 printf("CCK CDD 1x3 %2d %2d %2d %2d\n",
8666 ppr->cck_20ul_cdd.s1x3[0], ppr->cck_20ul_cdd.s1x3[1],
8667 ppr->cck_20ul_cdd.s1x3[2], ppr->cck_20ul_cdd.s1x3[3]);
8670 printf("OFDM %2d %2d %2d %2d %2d %2d %2d %2d\n",
8671 ppr->ofdm_20ul[0], ppr->ofdm_20ul[1], ppr->ofdm_20ul[2], ppr->ofdm_20ul[3],
8672 ppr->ofdm_20ul[4], ppr->ofdm_20ul[5], ppr->ofdm_20ul[6], ppr->ofdm_20ul[7]);
8673 printf("OFDM-CDD %2d %2d %2d %2d %2d %2d %2d %2d\n",
8674 ppr->ofdm_20ul_cdd[0], ppr->ofdm_20ul_cdd[1],
8675 ppr->ofdm_20ul_cdd[2], ppr->ofdm_20ul_cdd[3],
8676 ppr->ofdm_20ul_cdd[4], ppr->ofdm_20ul_cdd[5],
8677 ppr->ofdm_20ul_cdd[6], ppr->ofdm_20ul_cdd[7]);
8678 for (i = 0; i < n; i++) {
8679 switch (i) {
8680 case 0:
8681 str = "1 Nsts 1 Tx ";
8682 ptr = ppr->ht20ul.s1x1;
8683 break;
8684 case 1:
8685 str = "1 Nsts 2 Tx ";
8686 ptr = ppr->ht20ul.s1x2;
8687 break;
8688 case 2:
8689 str = "1 Nsts 3 Tx ";
8690 ptr = ppr->ht.ul20s1x3;
8691 break;
8692 case 3:
8693 str = "2 Nsts 2 Tx ";
8694 ptr = ppr->ht20ul.s2x2;
8695 break;
8696 case 4:
8697 str = "2 Nsts 3 Tx ";
8698 ptr = ppr->ht.ul20s2x3;
8699 break;
8700 case 5:
8701 str = "3 Nsts 3 Tx ";
8702 ptr = ppr->ht20ul.s3x3;
8703 break;
8704 default:
8705 ptr = NULL;
8706 break;
8708 printf("%s %2d %2d %2d %2d %2d %2d %2d %2d\n",
8709 str, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
8711 printf("\n");
8714 static int
8715 wl_get_current_txppr(void *wl, cmd_t *cmd, char **argv)
8717 int err;
8718 int mimo;
8719 chanspec_t chanspec;
8720 char chanspec_str[CHANSPEC_STR_LEN];
8721 wl_txppr_t txppr, *wl_txppr;
8723 memset(&txppr, 0, sizeof(wl_txppr_t));
8724 argv++;
8725 if (*argv)
8726 fprintf(stderr, "Ignoring arguments for %s\n", cmd->name);
8728 txppr.ver = WL_TXPPR_VERSION;
8729 txppr.len = WL_TXPPR_LENGTH;
8730 if ((err = wlu_iovar_getbuf(wl, "curppr", &txppr, sizeof(wl_txppr_t),
8731 buf, WLC_IOCTL_MAXLEN)) < 0)
8732 return err;
8734 wl_txppr = (wl_txppr_t *)buf;
8735 /* parse */
8736 wl_txppr->flags = dtoh32(wl_txppr->flags);
8737 wl_txppr->chanspec = dtohchanspec(wl_txppr->chanspec);
8738 wl_txppr->local_chanspec = dtohchanspec(wl_txppr->local_chanspec);
8740 chanspec = wl_txppr->chanspec;
8741 mimo = (wl_txppr->flags & WL_TX_POWER_F_HT) |
8742 (wl_txppr->flags & WL_TX_POWER_F_MIMO) |
8743 (wl_txppr->flags & WL_TX_POWER_F_SISO);
8745 /* dump */
8746 printf("Current channel:\t %s\n",
8747 wf_chspec_ntoa(wl_txppr->chanspec, chanspec_str));
8748 printf("BSS channel:\t\t %s\n",
8749 wf_chspec_ntoa(wl_txppr->local_chanspec, chanspec_str));
8750 printf("Power/Rate Dump (in 1/2dB): Channel %d\n", CHSPEC_CHANNEL(chanspec));
8751 wl_txppr_print((txppr_t *)wl_txppr->ppr, CHSPEC_IS2G(chanspec),
8752 (mimo & WL_TX_POWER_F_MIMO));
8753 return err;
8756 static int
8757 wl_get_current_power(void *wl, cmd_t *cmd, char **argv)
8759 int err;
8760 int mimo;
8761 int i;
8762 chanspec_t chanspec;
8763 char chanspec_str[CHANSPEC_STR_LEN];
8764 tx_power_t power;
8765 bool use_new_power;
8766 wlc_rev_info_t revinfo;
8767 uint32 phytype;
8769 memset(&power, 0, sizeof(power));
8771 argv++;
8772 if (*argv)
8773 fprintf(stderr, "Ignoring arguments for %s\n", cmd->name);
8775 /* Check for legacy driver by supplying a short buffer
8776 * Legacy drivers do not return an error.
8778 err = wlu_get(wl, cmd->get, &buf[0], 4);
8779 use_new_power = (err != 0);
8781 if (!use_new_power)
8782 return wl_curpower_legacy(wl);
8784 /* Check for legacy driver by supplying a power structure with
8785 * 45 rates instead of 101 rates. The Legacy driver will not
8786 * return an error in which case the wl curpower command will
8787 * print the output in the old format using 45 rates.
8789 err = wl_curpower_legacy2(wl, cmd);
8791 if (!err)
8792 return err;
8794 if ((err = wlu_get(wl, cmd->get, &power, sizeof(power))) < 0)
8795 return err;
8797 /* get PHYTYPE as well */
8798 memset(&revinfo, 0, sizeof(revinfo));
8799 if ((err = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) != 0)
8800 return err;
8801 phytype = dtoh32(revinfo.phytype);
8803 /* parse */
8804 power.flags = dtoh32(power.flags);
8805 power.chanspec = dtohchanspec(power.chanspec);
8806 power.local_chanspec = dtohchanspec(power.local_chanspec);
8808 chanspec = power.chanspec;
8809 mimo = (power.flags & WL_TX_POWER_F_HT) |
8810 (power.flags & WL_TX_POWER_F_MIMO) |
8811 (power.flags & WL_TX_POWER_F_SISO);
8813 /* dump */
8814 printf("Power Control:\t\t %s, %s\n",
8815 (power.flags & WL_TX_POWER_F_ENABLED) ? "On" : "Off",
8816 (power.flags & WL_TX_POWER_F_HW) ? "HW" : "SW");
8817 printf("Current channel:\t %s\n",
8818 wf_chspec_ntoa(power.chanspec, chanspec_str));
8819 printf("BSS channel:\t\t %s\n",
8820 wf_chspec_ntoa(power.local_chanspec, chanspec_str));
8821 printf("BSS Local Max:\t\t%2d.%-2d dBm\n",
8822 DIV_QUO(power.local_max, 4), DIV_REM(power.local_max, 4));
8823 printf("BSS Local Constraint:\t%2d.%-2d dB\n",
8824 DIV_QUO(power.local_constraint, 4), DIV_REM(power.local_constraint, 4));
8825 printf("User Target:\t\t%2d.%-2d dBm\n",
8826 DIV_QUO(power.user_limit[0], 4), DIV_REM(power.user_limit[0], 4));
8827 printf("SROM antgain:\t\t 2G: %d.%d dB, 5G: %d.%d dB\n\n",
8828 DIV_QUO(power.antgain[0], 4), DIV_REM(power.antgain[0], 4),
8829 DIV_QUO(power.antgain[1], 4), DIV_REM(power.antgain[1], 4));
8831 printf("Regulatory Limits:\n");
8832 wl_txpwr_array_print(power.reg_limit, CHSPEC_IS2G(chanspec), mimo);
8833 printf("\n");
8835 printf("Board Limits:\n");
8836 wl_txpwr_array_print(power.board_limit, CHSPEC_IS2G(chanspec), mimo);
8837 printf("\n");
8839 printf("Power Target:\n");
8840 wl_txpwr_array_print(power.target, CHSPEC_IS2G(chanspec), mimo);
8841 printf("\n");
8843 /* print the different power estimate combinations */
8844 if (mimo) {
8845 printf("Maximum Power Target among all rates:\t");
8846 for (i = 0; i < power.rf_cores; i++)
8847 printf("%d.%d ",
8848 DIV_QUO(power.tx_power_max[i], 4),
8849 DIV_REM(power.tx_power_max[i], 4));
8850 printf("\n");
8852 printf("Rate index with Maximum Power Target:\t");
8853 for (i = 0; i < power.rf_cores; i++)
8854 printf("%d ", power.tx_power_max_rate_ind[i]);
8855 printf("\n");
8857 printf("Last adjusted est. power :\t");
8858 for (i = 0; i < power.rf_cores; i++)
8859 printf("%d.%d ",
8860 DIV_QUO(power.est_Pout[i], 4),
8861 DIV_REM(power.est_Pout[i], 4));
8862 printf("\n");
8863 } else {
8864 printf("Last est. power:\t%d.%d dBm\n",
8865 DIV_QUO(power.est_Pout[0], 4),
8866 DIV_REM(power.est_Pout[0], 4));
8869 if (!mimo && CHSPEC_IS2G(chanspec)) {
8870 printf("Last CCK est. power:\t%d.%d dBm\n",
8871 DIV_QUO(power.est_Pout_cck, 4),
8872 DIV_REM(power.est_Pout_cck, 4));
8875 return err;
8878 static void
8879 wl_txpwr_array_print(uint8 *pwr, int cck, int mimo)
8881 int newline = TRUE;
8882 uint offset;
8883 bool isnphy = FALSE;
8885 /* CCK rates */
8886 if (cck) {
8887 wl_txpwr_range_print(pwr, WL_TX_POWER_CCK_FIRST, WL_NUM_RATES_CCK,
8888 "CCK ", &newline);
8889 if (!isnphy) {
8890 wl_txpwr_range_print(pwr, WL_TX_POWER_CCK_CDD_S1x2_FIRST, WL_NUM_RATES_CCK,
8891 "CCK CDD 1x2 ", &newline);
8892 wl_txpwr_range_print(pwr, WL_TX_POWER_CCK_CDD_S1x3_FIRST, WL_NUM_RATES_CCK,
8893 "CCK CDD 1x3 ", &newline);
8897 if (!mimo) {
8898 /* OFDM rates */
8899 wl_txpwr_range_print(pwr, WL_TX_POWER_OFDM20_FIRST, WL_NUM_RATES_OFDM,
8900 "Legacy OFDM ", &newline);
8901 } else if (mimo == WL_TX_POWER_F_SISO) {
8902 /* Legacy OFDM 20MHz SISO rates */
8903 wl_txpwr_range_print(pwr, WL_TX_POWER_OFDM20_FIRST, WL_NUM_RATES_OFDM,
8904 "Legacy OFDM 20MHz SISO ", &newline);
8906 /* MCS 20MHz SISO rates */
8907 wl_txpwr_range_print(pwr, WL_TX_POWER_MCS20_SISO_FIRST_SSN,
8908 WL_NUM_RATES_MCS_1STREAM, "MCS 0-7 20MHz SISO ", &newline);
8910 /* MCS 40MHz SISO rates */
8911 wl_txpwr_range_print(pwr, WL_TX_POWER_MCS20_SISO_FIRST_SSN,
8912 WL_NUM_RATES_MCS_1STREAM, "MCS 0-7 40MHz SISO ", &newline);
8913 } else {
8914 if ((mimo & WL_TX_POWER_F_HT) != WL_TX_POWER_F_HT)
8915 isnphy = TRUE;
8916 /* Legacy OFDM 20MHz SISO rates */
8917 wl_txpwr_range_print(pwr, WL_TX_POWER_OFDM20_FIRST, WL_NUM_RATES_OFDM,
8918 "Legacy OFDM 20MHz SISO ", &newline);
8920 /* Legacy OFDM 20MHz CDD rates */
8921 wl_txpwr_range_print(pwr, WL_TX_POWER_OFDM20_CDD_FIRST, WL_NUM_RATES_OFDM,
8922 "Legacy OFDM 20MHz CDD ", &newline);
8924 /* MCS 20MHz SISO rates */
8925 offset = isnphy ? WL_TX_POWER_MCS20_SISO_FIRST : WL_TX_POWER_20_S1x1_FIRST;
8926 wl_txpwr_range_print(pwr, offset, WL_NUM_RATES_MCS_1STREAM,
8927 isnphy ? "MCS 0-7 20MHz SISO " : "MCS 0-7 20MHz 1 Tx ", &newline);
8929 /* MCS 20MHz CDD rates */
8930 offset = isnphy ? WL_TX_POWER_MCS20_CDD_FIRST : WL_TX_POWER_20_S1x2_FIRST;
8931 wl_txpwr_range_print(pwr, offset, WL_NUM_RATES_MCS_1STREAM,
8932 isnphy ? "MCS 0-7 20MHz CDD " : "MCS 0-7 20MHz 2 Tx ", &newline);
8934 /* MCS 20MHz STBC rates */
8935 offset = isnphy ? WL_TX_POWER_MCS20_STBC_FIRST : WL_TX_POWER_20_S1x3_FIRST;
8936 wl_txpwr_range_print(pwr, offset, WL_NUM_RATES_MCS_1STREAM,
8937 isnphy ? "MCS 0-7 20MHz STBC " : "MCS 0-7 20MHz 3 Tx ", &newline);
8939 #ifdef NOT_YET
8940 if (!isnphy) {
8941 /* MCS 0-7 20MHz STBC 2x2 rates */
8942 wl_txpwr_range_print(pwr, WL_TX_POWER_HT_STBC_S2x2_FIRST,
8943 WL_NUM_RATES_MCS_1STREAM, "MCS 0-7 20MHz STBC 2 Tx ",
8944 &newline);
8945 /* MCS 0-7 20MHz STBC 2x3 rates */
8946 wl_txpwr_range_print(pwr, WL_TX_POWER_HT_STBC_S2x3_FIRST,
8947 WL_NUM_RATES_MCS_1STREAM, "MCS 0-7 20MHz STBC 3 Tx ",
8948 &newline);
8950 #endif
8951 /* MCS 20MHz SDM rates */
8952 offset = isnphy ? WL_TX_POWER_MCS20_SDM_FIRST : WL_TX_POWER_20_S2x2_FIRST;
8953 wl_txpwr_range_print(pwr, offset, WL_NUM_RATES_MCS_1STREAM,
8954 isnphy ? "MCS 8-15 20MHz SDM " : "MCS 8-15 20MHz 2 Tx ", &newline);
8956 if (!isnphy) {
8957 /* 20MHz MCS 8-15 with 3 Tx Chain */
8958 wl_txpwr_range_print(pwr, WL_TX_POWER_20_S2x3_FIRST,
8959 WL_NUM_RATES_MCS_1STREAM, "MCS 8-15 20MHz 3 Tx ", &newline);
8960 /* 20MHz MCS 16-23 with 3 Tx Chain */
8961 wl_txpwr_range_print(pwr, WL_TX_POWER_20_S3x3_FIRST,
8962 WL_NUM_RATES_MCS_1STREAM, "MCS 16-23 20MHz 3 Tx ", &newline);
8965 /* Legacy OFDM 40MHz SISO rates */
8966 wl_txpwr_range_print(pwr, WL_TX_POWER_OFDM40_FIRST, WL_NUM_RATES_OFDM,
8967 "Legacy OFDM 40MHz SISO ", &newline);
8969 /* Legacy OFDM 40MHz CDD rates */
8970 wl_txpwr_range_print(pwr, WL_TX_POWER_OFDM40_CDD_FIRST, WL_NUM_RATES_OFDM,
8971 "Legacy OFDM 40MHz CDD ", &newline);
8973 /* MCS 40MHz SISO rates */
8974 offset = isnphy ? WL_TX_POWER_MCS40_SISO_FIRST : WL_TX_POWER_40_S1x1_FIRST;
8975 wl_txpwr_range_print(pwr, offset, WL_NUM_RATES_MCS_1STREAM,
8976 isnphy ? "MCS 0-7 40MHz SISO " : "MCS 0-7 40MHz 1 Tx ", &newline);
8978 /* MCS 40MHz CDD rates */
8979 offset = isnphy ? WL_TX_POWER_MCS40_CDD_FIRST : WL_TX_POWER_40_S1x2_FIRST;
8980 wl_txpwr_range_print(pwr, offset, WL_NUM_RATES_MCS_1STREAM,
8981 isnphy ? "MCS 0-7 40MHz CDD " : "MCS 0-7 40MHz 2 Tx ", &newline);
8983 /* MCS 40MHz STBC rates */
8984 offset = isnphy ? WL_TX_POWER_MCS40_STBC_FIRST : WL_TX_POWER_40_S1x3_FIRST;
8985 wl_txpwr_range_print(pwr, offset, WL_NUM_RATES_MCS_1STREAM,
8986 isnphy ? "MCS 0-7 40MHz STBC " : "MCS 0-7 40MHz 3 Tx ", &newline);
8988 #ifdef NOT_YET
8989 if (!isnphy) {
8990 /* MCS 0-7 40MHz STBC 2x2 rates */
8991 wl_txpwr_range_print(pwr, WL_TX_POWER_HT_STBC_40_S2x2_FIRST,
8992 WL_NUM_RATES_MCS_1STREAM, "MCS 0-7 40MHz STBC 2 Tx ",
8993 &newline);
8994 /* MCS 0-7 40MHz STBC 2x3 rates */
8995 wl_txpwr_range_print(pwr, WL_TX_POWER_HT_STBC_40_S2x3_FIRST,
8996 WL_NUM_RATES_MCS_1STREAM, "MCS 0-7 40MHz STBC 3 Tx ",
8997 &newline);
8999 #endif
9000 /* MCS 40MHz SDM rates */
9001 offset = isnphy ? WL_TX_POWER_MCS40_SDM_FIRST : WL_TX_POWER_40_S2x2_FIRST;
9002 wl_txpwr_range_print(pwr, offset, WL_NUM_RATES_MCS_1STREAM,
9003 isnphy ? "MCS 8-15 40MHz SDM " : "MCS 8-15 40MHz 2 Tx ", &newline);
9005 if (!isnphy) {
9006 /* 40MHz MCS 8-15 with 3 Tx Chain */
9007 wl_txpwr_range_print(pwr, WL_TX_POWER_40_S2x3_FIRST,
9008 WL_NUM_RATES_MCS_1STREAM, "MCS 8-15 40MHz 3 Tx ", &newline);
9009 /* 40MHz MCS 16-23 with 3 Tx Chain */
9010 wl_txpwr_range_print(pwr, WL_TX_POWER_40_S3x3_FIRST,
9011 WL_NUM_RATES_MCS_1STREAM, "MCS 16-23 40MHz 3 Tx ", &newline);
9013 /* MCS 32 */
9014 wl_txpwr_range_print(pwr, WL_TX_POWER_MCS_32, WL_NUM_RATES_MCS32,
9015 "MCS 32 ", &newline);
9017 if (isnphy)
9018 goto exit;
9020 if (cck) {
9021 /* 20 in 40MHz CCK rates */
9022 wl_txpwr_range_print(pwr, WL_TX_POWER_20UL_CCK_FIRST, WL_NUM_RATES_CCK,
9023 "20UL CCK ", &newline);
9024 wl_txpwr_range_print(pwr, WL_TX_POWER_CCK_20U_CDD_S1x2_FIRST,
9025 WL_NUM_RATES_CCK, "20UL CCK CDD 1x2 ", &newline);
9026 wl_txpwr_range_print(pwr, WL_TX_POWER_CCK_20U_CDD_S1x3_FIRST,
9027 WL_NUM_RATES_CCK, "20UL CCK CDD 1x3 ", &newline);
9029 /* 20 in 40MHz OFDM rates */
9030 wl_txpwr_range_print(pwr, WL_TX_POWER_20UL_OFDM_FIRST, WL_NUM_RATES_OFDM,
9031 "20UL Legacy OFDM ", &newline);
9033 /* 20 in 40MHz OFDM CDD rates */
9034 wl_txpwr_range_print(pwr, WL_TX_POWER_20UL_OFDM_CDD_FIRST, WL_NUM_RATES_OFDM,
9035 "20UL Legacy OFDM CDD ", &newline);
9037 /* 20 in 40MHz MCS 0-7 rates 1 Tx chain */
9038 wl_txpwr_range_print(pwr, WL_TX_POWER_20UL_S1x1_FIRST, WL_NUM_RATES_MCS_1STREAM,
9039 "MCS 0-7 20UL 1 Tx ", &newline);
9041 /* 20 in 40MHz MCS 0-7 rates 2 Tx chain */
9042 wl_txpwr_range_print(pwr, WL_TX_POWER_20UL_S1x2_FIRST, WL_NUM_RATES_MCS_1STREAM,
9043 "MCS 0-7 20UL 2 Tx ", &newline);
9045 /* 20 in 40MHz MCS 0-7 rates 3 Tx chain */
9046 wl_txpwr_range_print(pwr, WL_TX_POWER_20UL_S1x3_FIRST, WL_NUM_RATES_MCS_1STREAM,
9047 "MCS 0-7 20UL 3 Tx ", &newline);
9049 /* 20 in 40MHz MCS 8-15 rates 2 Tx chain */
9050 wl_txpwr_range_print(pwr, WL_TX_POWER_20UL_S2x2_FIRST, WL_NUM_RATES_MCS_1STREAM,
9051 "MCS 8-15 20UL 2 Tx ", &newline);
9053 /* 20 in 40MHz MCS 8-15 rates 3 Tx chain */
9054 wl_txpwr_range_print(pwr, WL_TX_POWER_20UL_S2x3_FIRST, WL_NUM_RATES_MCS_1STREAM,
9055 "MCS 8-15 20UL 3 Tx ", &newline);
9057 /* 20 in 40MHz MCS 16-23 rates 3 Tx chain */
9058 wl_txpwr_range_print(pwr, WL_TX_POWER_20UL_S3x3_FIRST, WL_NUM_RATES_MCS_1STREAM,
9059 "MCS 16-23 20UL 3 Tx ", &newline);
9060 #ifdef NOT_YET
9061 if (!isnphy) {
9062 /* 20 in 40MHz MCS 0-7 STBC 2x2 rates */
9063 wl_txpwr_range_print(pwr, WL_TX_POWER_HT_STBC_UL20_S2x2_FIRST,
9064 WL_NUM_RATES_MCS_1STREAM, "MCS 0-7 20UL STBC 2 Tx ",
9065 &newline);
9066 /* 20 in 40MHz MCS 0-7 STBC 2x3 rates */
9067 wl_txpwr_range_print(pwr, WL_TX_POWER_HT_STBC_UL20_S2x3_FIRST,
9068 WL_NUM_RATES_MCS_1STREAM, "MCS 0-7 20UL STBC 3 Tx ",
9069 &newline);
9071 #endif
9073 exit:
9074 if (!newline)
9075 printf("\n");
9078 static void
9079 wl_txpwr_range_print(uint8 *pwr, int start, int count, const char* label, int *newline)
9081 if (wl_array_uniform(pwr, start, count)) {
9082 /* need a newline for abbreviated printout */
9083 if (!*newline)
9084 printf("\n");
9085 printf("%s: %2d.%-2d", label,
9086 DIV_QUO(pwr[start], 4),
9087 DIV_REM(pwr[start], 4));
9088 *newline = FALSE;
9089 } else {
9090 /* need a newline for a full row printout */
9091 if (!*newline)
9092 printf("\n");
9093 printf("%s: ", label);
9094 wl_txpwr_row_print(pwr, start, count);
9095 printf("\n");
9096 *newline = TRUE;
9100 static void
9101 wl_txpwr_row_print(uint8 *pwr, int start, int count)
9103 int i, rate;
9105 for (i = 0, rate = start; i < count; i++, rate++)
9106 printf("%2d.%-2d ",
9107 DIV_QUO(pwr[rate], 4),
9108 DIV_REM(pwr[rate], 4));
9111 /* return TRUE if all the values in the array are uniformly the same */
9112 static int
9113 wl_array_uniform(uint8 *pwr, int start, int count)
9115 int i, rate;
9117 for (i = 1, rate = start + 1; i < count; i++, rate++)
9118 if (pwr[rate] != pwr[rate - 1])
9119 return FALSE;
9121 return TRUE;
9124 static int
9125 wl_curpower_legacy2(void *wl, cmd_t *cmd)
9127 int err;
9128 int mimo;
9129 int i;
9130 chanspec_t chanspec;
9131 char chanspec_str[CHANSPEC_STR_LEN];
9132 tx_power_legacy2_t power;
9134 if ((err = wlu_get(wl, cmd->get, &power, sizeof(power))) < 0)
9135 return err;
9137 power.flags = dtoh32(power.flags);
9138 power.chanspec = dtohchanspec(power.chanspec);
9139 power.local_chanspec = dtohchanspec(power.local_chanspec);
9141 chanspec = power.chanspec;
9142 mimo = (power.flags & WL_TX_POWER_F_MIMO);
9144 printf("Power Control:\t\t %s, %s\n",
9145 (power.flags & WL_TX_POWER_F_ENABLED) ? "On" : "Off",
9146 (power.flags & WL_TX_POWER_F_HW) ? "HW" : "SW");
9147 printf("Current channel:\t %s\n",
9148 wf_chspec_ntoa(power.chanspec, chanspec_str));
9149 printf("BSS channel:\t\t %s\n",
9150 wf_chspec_ntoa(power.local_chanspec, chanspec_str));
9151 printf("BSS Local Max:\t\t%2d.%-2d dBm\n",
9152 DIV_QUO(power.local_max, 4), DIV_REM(power.local_max, 4));
9153 printf("BSS Local Constraint:\t%2d.%-2d dB\n",
9154 DIV_QUO(power.local_constraint, 4), DIV_REM(power.local_constraint, 4));
9155 printf("User Target:\t\t%2d.%-2d dBm\n",
9156 DIV_QUO(power.user_limit[0], 4), DIV_REM(power.user_limit[0], 4));
9157 printf("SROM antgain:\t\t 2G: %d.%d dB, 5G: %d.%d dB\n\n",
9158 DIV_QUO(power.antgain[0], 4), DIV_REM(power.antgain[0], 4),
9159 DIV_QUO(power.antgain[1], 4), DIV_REM(power.antgain[1], 4));
9161 printf("Regulatory Limits:\n");
9162 wl_txpwr_array_print_legacy2(power.reg_limit, CHSPEC_IS2G(chanspec), mimo);
9163 printf("\n");
9165 printf("Board Limits:\n");
9166 wl_txpwr_array_print_legacy2(power.board_limit, CHSPEC_IS2G(chanspec), mimo);
9167 printf("\n");
9169 printf("Power Target:\n");
9170 wl_txpwr_array_print_legacy2(power.target, CHSPEC_IS2G(chanspec), mimo);
9171 printf("\n");
9173 /* print the different power estimate combinations */
9174 if (mimo) {
9175 printf("Last est. power:\t");
9176 for (i = 0; i < power.rf_cores; i++)
9177 printf("%d.%d ",
9178 DIV_QUO(power.est_Pout[i], 4),
9179 DIV_REM(power.est_Pout[i], 4));
9180 printf("\n");
9181 } else {
9182 printf("Last est. power:\t%d.%d dBm\n",
9183 DIV_QUO(power.est_Pout[0], 4),
9184 DIV_REM(power.est_Pout[0], 4));
9187 if (!mimo && CHSPEC_IS2G(chanspec)) {
9188 printf("Last CCK est. power:\t%d.%d dBm\n",
9189 DIV_QUO(power.est_Pout_cck, 4),
9190 DIV_REM(power.est_Pout_cck, 4));
9193 return err;
9196 static void
9197 wl_txpwr_array_print_legacy2(uint8 *pwr, int cck, int mimo)
9199 int newline = TRUE;
9201 /* CCK rates */
9202 if (cck)
9203 wl_txpwr_range_print_legacy2(pwr, WL_TX_POWER_CCK_FIRST, WL_NUM_RATES_CCK,
9204 "CCK", &newline);
9206 /* OFDM rates */
9207 wl_txpwr_range_print_legacy2(pwr, WL_TX_POWER_OFDM20_FIRST, WL_NUM_RATES_OFDM, "OFDM",
9208 &newline);
9210 if (mimo) {
9211 /* MCS 20MHz rates */
9212 wl_txpwr_range_print_legacy2(pwr, WL_TX_POWER_MCS20_FIRST, WL_NUM_RATES_MCS_1STREAM,
9213 "MCS 20MHz", &newline);
9215 /* MCS 40MHz rates */
9216 wl_txpwr_range_print_legacy2(pwr, WL_TX_POWER_MCS40_FIRST, WL_NUM_RATES_MCS_1STREAM,
9217 "MCS 40MHz", &newline);
9220 if (!newline)
9221 printf("\n");
9224 static void
9225 wl_txpwr_range_print_legacy2(uint8 *pwr, int start, int count, const char* label, int *newline)
9227 if (wl_array_uniform(pwr, start, count)) {
9228 /* need a space for abbreviated printout */
9229 if (!*newline)
9230 printf(" ");
9231 printf("%s: %2d.%-2d", label,
9232 DIV_QUO(pwr[start], 4),
9233 DIV_REM(pwr[start], 4));
9234 *newline = FALSE;
9235 } else {
9236 /* need a newline for a full row printout */
9237 if (!*newline)
9238 printf("\n");
9239 printf("%s: ", label);
9240 wl_txpwr_row_print(pwr, start, count);
9241 printf("\n");
9242 *newline = TRUE;
9247 static int
9248 wl_curpower_legacy(void *wl)
9250 int err;
9251 int val;
9252 int i;
9253 int32 flags;
9254 chanspec_t chanspec;
9255 char chanspec_str[CHANSPEC_STR_LEN];
9256 tx_power_legacy_t power;
9257 int eirp;
9259 err = wlu_iovar_getint(wl, "eirp", &eirp);
9260 if (err)
9261 return err;
9263 if ((err = wlu_iovar_getint(wl, "chanspec", &val)) < 0)
9264 return err;
9265 chanspec = (chanspec_t)val;
9266 wf_chspec_ntoa(chanspec, chanspec_str);
9268 if ((err = wlu_get(wl, WLC_CURRENT_PWR, &power, sizeof(power))) < 0)
9269 return err;
9271 printf("Current channel:\t\t %s\n",
9272 wf_chspec_ntoa(chanspec, chanspec_str));
9273 printf("User Target:\t\t\t%2d.%-2d dBm\n",
9274 DIV_QUO(power.txpwr_band_max[0], 4),
9275 DIV_REM(power.txpwr_band_max[0], 4));
9276 printf("Regulatory Local Max:\t\t%2d.%-2d dBm\n",
9277 DIV_QUO(power.txpwr_local_max, 4),
9278 DIV_REM(power.txpwr_local_max, 4));
9279 printf("Regulatory Local Constraint:\t%2d.%-2d dB\n",
9280 DIV_QUO(power.txpwr_local_constraint, 4),
9281 DIV_REM(power.txpwr_local_constraint, 4));
9282 printf("Antgain used in Channel Max:\t %s\n",
9283 (eirp & 1) ?
9284 "Yes, channel is EIRP" : "No, channel is Conducted");
9285 printf("Hardware Power Control:\t\t ");
9286 /* ucflags 2 */
9287 flags = htod32(2);
9288 if ((err = wlu_get(wl, WLC_GET_UCFLAGS, &flags, sizeof(flags))) >= 0) {
9289 flags = dtoh32(flags);
9290 printf("%s\n", (flags & 0x80) ? "HW PWRCTL On" : "HW PWRCTL Off");
9293 printf("Regulatory Channel Max:\t\t%2d.%-2d dBm\n",
9294 DIV_QUO(power.txpwr_chan_reg_max, 4),
9295 DIV_REM(power.txpwr_chan_reg_max, 4));
9296 printf("SROM antgain:\t\t\t 2G: %d.%d dB, 5G: %d.%d dB\n\n",
9297 DIV_QUO(power.txpwr_antgain[0], 4),
9298 DIV_REM(power.txpwr_antgain[0], 4),
9299 DIV_QUO(power.txpwr_antgain[1], 4),
9300 DIV_REM(power.txpwr_antgain[1], 4));
9302 printf("Min of Reg & Local Limits:\n");
9303 printf(" CCK:\t ");
9304 for (i = 0; i < 4; i++)
9305 printf("%d.%d ",
9306 DIV_QUO(power.txpwr_limit[i], 4),
9307 DIV_REM(power.txpwr_limit[i], 4));
9308 printf("\nOFDM:\t ");
9309 for (; i < NUM_PWRCTRL_RATES; i++)
9310 printf("%d.%d ",
9311 DIV_QUO(power.txpwr_limit[i], 4),
9312 DIV_REM(power.txpwr_limit[i], 4));
9313 printf("\n\n");
9315 /* band specific info */
9316 if (CHSPEC_IS2G(chanspec)) {
9317 /* 2G band */
9318 printf("Last B phy CCK est. power:\t%2d.%-2d dBm\n",
9319 DIV_QUO(power.txpwr_est_Pout[0], 4),
9320 DIV_REM(power.txpwr_est_Pout[0], 4));
9321 printf("Last B phy OFDM est. power:\t%2d.%-2d dBm\n",
9322 DIV_QUO(power.txpwr_est_Pout_gofdm, 4),
9323 DIV_REM(power.txpwr_est_Pout_gofdm, 4));
9325 printf("\n");
9326 printf("Srom limit B/G:\n");
9327 printf(" CCK:\t ");
9328 for (i = 0; i < 4; i++)
9329 printf("%d.%d ", DIV_QUO(power.txpwr_bphy_cck_max[i], 4),
9330 DIV_REM(power.txpwr_bphy_cck_max[i], 4));
9331 printf("\nOFDM:\t ");
9332 for (; i < NUM_PWRCTRL_RATES; i++)
9333 printf("%d.%d ", DIV_QUO(power.txpwr_bphy_cck_max[i], 4),
9334 DIV_REM(power.txpwr_bphy_cck_max[i], 4));
9335 printf("\n");
9337 printf("Last B phy target power:\n");
9338 printf(" CCK:\t ");
9339 for (i = 0; i < 4; i++)
9340 printf("%d.%d ", DIV_QUO(power.txpwr_target[0][i], 4),
9341 DIV_REM(power.txpwr_target[0][i], 4));
9342 printf("\nOFDM:\t ");
9343 for (; i < NUM_PWRCTRL_RATES; i++)
9344 printf("%d.%d ", DIV_QUO(power.txpwr_target[0][i], 4),
9345 DIV_REM(power.txpwr_target[0][i], 4));
9346 printf("\n");
9347 } else {
9348 /* 5G band */
9349 printf("Last A phy est. power:\t\t%2d.%-2d dBm\n",
9350 DIV_QUO(power.txpwr_est_Pout[1], 4),
9351 DIV_REM(power.txpwr_est_Pout[1], 4));
9352 printf("Srom limit A:\n");
9353 printf("OFDM:\t ");
9354 for (i = 4; i < NUM_PWRCTRL_RATES; i++)
9355 printf("%d.%d ", DIV_QUO(power.txpwr_aphy_max[i], 4),
9356 DIV_REM(power.txpwr_aphy_max[i], 4));
9357 printf("\n");
9359 printf("Last A phy target power:\n");
9360 printf("OFDM:\t ");
9361 for (i = 4; i < NUM_PWRCTRL_RATES; i++)
9362 printf("%d.%d ", DIV_QUO(power.txpwr_target[1][i], 4),
9363 DIV_REM(power.txpwr_target[1][i], 4));
9364 printf("\n");
9367 return err;
9370 static int
9371 wl_get_instant_power(void *wl, cmd_t *cmd, char **argv)
9373 int ret;
9374 tx_inst_power_t *power;
9375 uint band_list[3];
9377 UNUSED_PARAMETER(cmd);
9378 UNUSED_PARAMETER(argv);
9380 strcpy(buf, "txinstpwr");
9381 if ((ret = wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN)) < 0) {
9382 return ret;
9385 power = (tx_inst_power_t *)buf;
9386 /* Make the most of the info returned in band_list!
9387 * b/g and a
9388 * b/g-uni
9389 * a-uni
9390 * NOTE: NO a and b/g case ...
9392 if ((ret = wlu_get(wl, WLC_GET_BANDLIST, band_list, sizeof(band_list))) < 0)
9393 return (ret);
9394 band_list[0] = dtoh32(band_list[0]);
9395 band_list[1] = dtoh32(band_list[1]);
9396 band_list[2] = dtoh32(band_list[2]);
9398 /* If B/G is present it's always the lower index */
9399 if (band_list[1] == WLC_BAND_2G) {
9400 printf("Last B phy CCK est. power:\t%2d.%d dBm\n",
9401 DIV_QUO(power->txpwr_est_Pout[0], 4),
9402 DIV_REM(power->txpwr_est_Pout[0], 4));
9403 printf("Last B phy OFDM est. power:\t%2d.%d dBm\n",
9404 DIV_QUO(power->txpwr_est_Pout_gofdm, 4),
9405 DIV_REM(power->txpwr_est_Pout_gofdm, 4));
9407 printf("\n");
9410 /* A band */
9411 if (band_list[1] == WLC_BAND_5G || (band_list[0] > 1 && band_list[2] == WLC_BAND_5G)) {
9412 printf("Last A phy est. power:\t\t%2d.%d dBm\n",
9413 DIV_QUO(power->txpwr_est_Pout[1], 4),
9414 DIV_REM(power->txpwr_est_Pout[1], 4));
9417 return ret;
9420 static int
9421 wl_evm(void *wl, cmd_t *cmd, char **argv)
9423 int val[3];
9425 /* Get channel */
9426 if (!*++argv) {
9427 fprintf(stderr, "Need to specify at least one parameter\n");
9428 return -1;
9431 if (!stricmp(*argv, "off"))
9432 val[0] = 0;
9433 else
9434 val[0] = atoi(*argv);
9436 /* set optional parameters to default */
9437 val[1] = 4; /* rate in 500Kb units */
9438 val[2] = 0; /* This is ignored */
9440 /* Get optional rate and convert to 500Kb units */
9441 if (*++argv)
9442 val[1] = rate_string2int(*argv);
9444 val[0] = htod32(val[0]);
9445 val[1] = htod32(val[1]);
9446 val[2] = htod32(val[2]);
9447 return wlu_set(wl, cmd->set, val, sizeof(val));
9450 /* wl join <ssid> [key <0-3>:xxxxx]
9451 * [imode bss|ibss]
9452 * [amode open|shared|openshared|wpa|wpapsk|wpa2|wpa2psk|wpanone]
9453 * [options]
9454 * Options:
9455 * -b MAC, --bssid=MAC, where MAC is in xx:xx:xx:xx:xx:xx format
9456 * -c CL, --chanspecs=CL, where CL is a comma or space separated list of chanspecs
9458 static int
9459 wl_join(void *wl, cmd_t *cmd, char **argv)
9461 int ret = BCME_OK, idx = 0;
9462 wl_join_params_t *join_params;
9463 int join_params_size;
9464 wl_wsec_key_t key;
9465 int wsec = 0, auth = 0, infra = 1;
9466 int wpa_auth = WPA_AUTH_DISABLED;
9467 char* cmd_name;
9469 UNUSED_PARAMETER(cmd);
9471 cmd_name = *argv++;
9473 /* allocate the max storage */
9474 join_params_size = WL_JOIN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(chanspec_t);
9475 if ((join_params = malloc(join_params_size)) == NULL) {
9476 fprintf(stderr, "Error allocating %d bytes for assoc params\n", join_params_size);
9477 return BCME_NOMEM;
9479 memset(join_params, 0, join_params_size);
9480 memcpy(&join_params->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
9482 /* verify that SSID was specified and is a valid length */
9483 if (!*argv || (strlen(*argv) > DOT11_MAX_SSID_LEN)) {
9484 ret = BCME_BADARG;
9485 goto exit;
9488 join_params->ssid.SSID_len = strlen(*argv);
9489 memcpy(join_params->ssid.SSID, *argv, join_params->ssid.SSID_len);
9490 /* default to plain old ioctl */
9491 join_params_size = sizeof(wlc_ssid_t);
9493 /* get current wsec */
9494 if (wlu_iovar_getint(wl, "wsec", &wsec) < 0)
9495 wsec = 0;
9497 while (*++argv) {
9498 if (!stricmp(*argv, "wepkey") || !stricmp(*argv, "wep") || !stricmp(*argv, "key")) {
9499 /* specified wep key */
9500 memset(&key, 0, sizeof(key));
9501 if (!*++argv) {
9502 ret = BCME_BADARG;
9503 goto exit;
9505 /* WEP index specified */
9506 if (*(argv[0]+1) == ':') {
9507 idx = *argv[0] - 0x30;
9508 if (idx < 0 || idx > 3) {
9509 fprintf(stderr, "Invalid key index %d specified\n", idx);
9510 ret = BCME_BADARG;
9511 goto exit;
9513 argv[0] += 2; /* colon + digit */
9515 key.index = idx;
9517 if (parse_wep(argv, &key, FALSE)) {
9518 ret = BCME_BADARG;
9519 goto exit;
9522 key.index = htod32(key.index);
9523 key.len = htod32(key.len);
9524 key.algo = htod32(key.algo);
9525 key.flags = htod32(key.flags);
9527 if ((ret = wlu_set(wl, WLC_SET_KEY, &key, sizeof(wl_wsec_key_t))) < 0) {
9528 ret = BCME_BADARG;
9529 goto exit;
9531 wsec |= WEP_ENABLED;
9533 /* specified infrastructure mode */
9534 else if (!stricmp(*argv, "imode") ||
9535 !stricmp(*argv, "infra") ||
9536 !stricmp(*argv, "mode")) {
9537 if (!*++argv) {
9538 fprintf(stderr, "%s %s: expected argument after \"infra\" keyword "
9539 "but command line ended.\n", wlu_av0, cmd_name);
9540 ret = BCME_BADARG;
9541 goto exit;
9542 } else if (!stricmp(*argv, "ibss") ||
9543 !stricmp(*argv, "adhoc") ||
9544 !stricmp(*argv, "ad-hoc")) {
9545 infra = 0;
9546 } else if (!stricmp(*argv, "bss") ||
9547 !stricmp(*argv, "managed") ||
9548 !strnicmp(*argv, "infra", 5)) {
9549 infra = 1;
9550 } else {
9551 fprintf(stderr, "%s %s: unrecongnized parameter \"%s\" after "
9552 "\"infra\" keyword\n", wlu_av0, cmd_name, *argv);
9553 ret = BCME_BADARG;
9554 goto exit;
9557 /* specified authentication mode */
9558 else if (!stricmp(*argv, "amode") || !strnicmp(*argv, "auth", 4)) {
9559 if (!*++argv) {
9560 ret = BCME_BADARG;
9561 goto exit;
9563 if (!stricmp(*argv, "open"))
9564 auth = WL_AUTH_OPEN_SYSTEM;
9565 else if (!stricmp(*argv, "shared"))
9566 auth = WL_AUTH_SHARED_KEY;
9567 else if (!stricmp(*argv, "openshared"))
9568 auth = WL_AUTH_OPEN_SHARED;
9569 else if (!stricmp(*argv, "wpanone"))
9570 wpa_auth = WPA_AUTH_NONE;
9571 else if (!stricmp(*argv, "wpa"))
9572 wpa_auth = WPA_AUTH_UNSPECIFIED;
9573 else if (!stricmp(*argv, "wpapsk"))
9574 wpa_auth = WPA_AUTH_PSK;
9575 else if (!stricmp(*argv, "wpa2"))
9576 wpa_auth = WPA2_AUTH_UNSPECIFIED;
9577 else if (!stricmp(*argv, "wpa2psk"))
9578 wpa_auth = WPA2_AUTH_PSK;
9579 else {
9580 ret = BCME_BADARG;
9581 goto exit;
9584 /* optional assoc params */
9585 else if ((ret = wl_parse_assoc_params(argv, &join_params->params)) == BCME_OK) {
9586 join_params_size = WL_JOIN_PARAMS_FIXED_SIZE +
9587 dtoh32(join_params->params.chanspec_num) * sizeof(chanspec_t);
9588 break;
9590 else {
9591 fprintf(stderr, "%s %s: unable to parse parameter \"%s\"\n",
9592 wlu_av0, cmd_name, *argv);
9593 goto exit;
9597 /* set infrastructure mode */
9598 infra = htod32(infra);
9599 if ((ret = wlu_set(wl, WLC_SET_INFRA, &infra, sizeof(int))) < 0)
9600 goto exit;
9602 /* set authentication mode */
9603 auth = htod32(auth);
9604 if ((ret = wlu_set(wl, WLC_SET_AUTH, &auth, sizeof(int))) < 0)
9605 goto exit;
9607 /* set wsec mode */
9608 if ((ret = wlu_iovar_setint(wl, "wsec", wsec)) < 0)
9609 goto exit;
9611 /* set WPA_auth mode */
9612 wpa_auth = htod32(wpa_auth);
9613 if ((ret = wlu_set(wl, WLC_SET_WPA_AUTH, &wpa_auth, sizeof(wpa_auth))) < 0)
9614 goto exit;
9616 /* set ssid with extend assoc params (if any) */
9617 join_params->ssid.SSID_len = htod32(join_params->ssid.SSID_len);
9618 ret = wlu_set(wl, WLC_SET_SSID, join_params, join_params_size);
9620 exit:
9621 free(join_params);
9622 return ret;
9625 /* Set or Get the "bssid" iovar, with an optional config index argument:
9626 * wl bssid [-C N]|[--cfg=N] bssid
9628 * Option:
9629 * -C N
9630 * --cfg=N
9631 * --config=N
9632 * --configuration=N
9633 * specify the config index N
9634 * If cfg index not given on a set, the WLC_SET_BSSID ioctl will be used
9636 static int
9637 wl_bssid(void *wl, cmd_t *cmd, char **argv)
9639 struct ether_addr ea;
9640 int bsscfg_idx = 0;
9641 int consumed;
9642 int error;
9644 UNUSED_PARAMETER(cmd);
9646 argv++;
9648 /* parse a bsscfg_idx option if present */
9649 if ((error = wl_cfg_option(argv, "bssid", &bsscfg_idx, &consumed)) != 0)
9650 return error;
9652 argv += consumed;
9654 if (*argv == NULL) {
9655 if (consumed == 0) {
9656 /* no config index, use WLC_GET_BSSID on the interface */
9657 error = wlu_get(wl, WLC_GET_BSSID, &ea, ETHER_ADDR_LEN);
9658 } else {
9659 /* use "bssid" iovar since a config option was given */
9660 error = wl_bssiovar_get(wl, "bssid", bsscfg_idx, &ea, ETHER_ADDR_LEN);
9662 if (error < 0)
9663 return error;
9664 printf("%s\n", wl_ether_etoa(&ea));
9666 } else {
9668 if (!wl_ether_atoe(*argv, &ea))
9669 return -1;
9671 if (consumed == 0) {
9672 /* no config index given, use WLC_SET_BSSID */
9673 error = wlu_set(wl, WLC_SET_BSSID, &ea, ETHER_ADDR_LEN);
9674 } else {
9675 /* use "bssid" iovar since a config option was given */
9676 error = wl_bssiovar_set(wl, "bssid", bsscfg_idx, &ea, ETHER_ADDR_LEN);
9679 return error;
9682 /* Set or Get the "ssid" iovar, with an optional config index argument:
9683 * wl ssid [-C N]|[--cfg=N] ssid
9685 * Option:
9686 * -C N
9687 * --cfg=N
9688 * --config=N
9689 * --configuration=N
9690 * specify the config index N
9691 * If cfg index not given on a set, the WLC_SET_SSID ioctl will be used
9693 static int
9694 wl_ssid(void *wl, cmd_t *cmd, char **argv)
9696 char ssidbuf[SSID_FMT_BUF_LEN];
9697 wlc_ssid_t ssid = { 0, {0} };
9698 int bsscfg_idx = 0;
9699 int consumed;
9700 int error;
9702 argv++;
9704 /* parse a bsscfg_idx option if present */
9705 if ((error = wl_cfg_option(argv, "ssid", &bsscfg_idx, &consumed)) != 0)
9706 return error;
9708 argv += consumed;
9710 if (*argv == NULL) {
9711 if (consumed == 0) {
9712 /* no config index, use WLC_GET_SSID on the interface */
9713 if (cmd->get == WLC_GET_SSID)
9714 error = wlu_get(wl, WLC_GET_SSID, &ssid, sizeof(ssid));
9715 else
9716 error = wlu_iovar_get(wl, cmd->name, &ssid, sizeof(ssid));
9717 } else {
9718 if (cmd->get == WLC_GET_SSID) {
9719 /* use "ssid" iovar since a config option was given */
9720 error = wl_bssiovar_get(wl, "ssid", bsscfg_idx, &ssid,
9721 sizeof(ssid));
9722 } else {
9723 error = wl_bssiovar_get(wl, cmd->name, bsscfg_idx, &ssid,
9724 sizeof(ssid));
9727 if (error < 0)
9728 return error;
9730 ssid.SSID_len = dtoh32(ssid.SSID_len);
9731 wl_format_ssid(ssidbuf, ssid.SSID, ssid.SSID_len);
9732 printf("Current %s: \"%s\"\n",
9733 (cmd->get == WLC_GET_SSID)? "SSID": cmd->name,
9734 ssidbuf);
9735 } else {
9736 if (strlen(argv[0]) > DOT11_MAX_SSID_LEN) {
9737 fprintf(stderr, "SSID arg \"%s\" must be 32 chars or less\n", argv[0]);
9738 return -1;
9740 ssid.SSID_len = strlen(argv[0]);
9741 memcpy(ssid.SSID, argv[0], ssid.SSID_len);
9743 wl_format_ssid(ssidbuf, ssid.SSID, ssid.SSID_len);
9744 printf("Setting %s: \"%s\"\n", (cmd->set == WLC_SET_SSID)? "SSID": cmd->name,
9745 ssidbuf);
9747 ssid.SSID_len = htod32(ssid.SSID_len);
9748 if (consumed == 0) {
9749 /* no config index given, use WLC_SET_SSID */
9750 if (cmd->set == WLC_SET_SSID) {
9751 error = wlu_set(wl, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
9752 } else {
9753 error = wlu_iovar_set(wl, cmd->name, &ssid, sizeof(wlc_ssid_t));
9755 } else {
9756 if (cmd->set == WLC_SET_SSID) {
9757 /* use "ssid" iovar since a config option was given */
9758 error = wl_bssiovar_set(wl, "ssid", bsscfg_idx, &ssid,
9759 sizeof(wlc_ssid_t));
9760 } else
9761 error = wl_bssiovar_set(wl, cmd->name, bsscfg_idx, &ssid,
9762 sizeof(wlc_ssid_t));
9765 return error;
9768 static const char*
9769 wl_smfs_map_type(uint8 type)
9771 static const struct {uint8 type; char name[32];} type_names[] = {
9772 {SMFS_TYPE_AUTH, "Authentication_Request"},
9773 {SMFS_TYPE_ASSOC, "Association_Request"},
9774 {SMFS_TYPE_REASSOC, "Reassociation_Request"},
9775 {SMFS_TYPE_DISASSOC_TX, "Disassociation_Request_TX"},
9776 {SMFS_TYPE_DISASSOC_RX, "Disassociation_Request_RX"},
9777 {SMFS_TYPE_DEAUTH_TX, "Deauthentication_Request_TX"},
9778 {SMFS_TYPE_DEAUTH_RX, "Deauthentication_Request_RX"}
9781 const char *tname = "UNKNOWN";
9782 uint i;
9784 for (i = 0; i < ARRAYSIZE(type_names); i++) {
9785 if (type_names[i].type == type)
9786 tname = type_names[i].name;
9788 return tname;
9791 static int
9792 wl_disp_smfs(char *inbuf)
9794 static const char *codename[] = {"Status_code", "Reason_code"};
9795 wl_smf_stats_t *smf_stats;
9796 wl_smfs_elem_t *elemt = NULL;
9797 int len;
9798 const char *namebuf;
9799 uint32 version;
9800 int count;
9802 smf_stats = (wl_smf_stats_t *) inbuf;
9803 namebuf = wl_smfs_map_type(smf_stats->type);
9805 version = dtoh32(smf_stats->version);
9806 if (version != SMFS_VERSION) {
9807 fprintf(stderr, "Sorry, your driver has smfs_version %d "
9808 "but this program supports only version %d.\n",
9809 version, SMFS_VERSION);
9810 return -1;
9813 printf("Frame type: %s\n", namebuf);
9814 printf("\tIgnored Count: %d\n", dtoh32(smf_stats->ignored_cnt));
9815 printf("\tMalformed Count: %d\n", dtoh32(smf_stats->malformed_cnt));
9817 len = dtoh16(smf_stats->length);
9818 count = dtoh32(smf_stats->count_total);
9820 if (count) {
9821 namebuf = codename[dtoh32(smf_stats->codetype)];
9822 printf("\tSuccessful/Failed Count:\n");
9823 elemt = &smf_stats->elem[0];
9826 while (count) {
9827 printf("\t\t%s %d Count: %d\n", namebuf, dtoh16(elemt->code),
9828 dtoh32(elemt->count));
9829 elemt ++;
9830 count --;
9833 return 0;
9838 * Check for the smfstats parameters. One of defined parameters can be passed in.
9840 static int
9841 wl_smfs_option(char **argv, int* idx, int *consumed, int* clear)
9843 int err = 0;
9844 char *p;
9845 char const * smfs_opt[] = {"auth", "assoc", "reassoc", "disassoc_tx",
9846 "disassoc_rx", "deauth_tx", "deauth_rx"};
9847 char const * clear_opt = "clear";
9848 int i;
9849 char const * cur_opt;
9851 if (*argv == NULL) {
9852 goto exit;
9855 p = *argv++;
9857 for (i = 0; i < SMFS_TYPE_MAX; i++) {
9858 cur_opt = smfs_opt[i];
9859 if (!strcmp(p, cur_opt)) {
9860 *idx = i;
9861 *consumed += 1;
9862 goto exit;
9866 if (!strcmp(p, clear_opt))
9867 *clear = 1;
9869 exit:
9870 return err;
9873 /* Get or Clear (set) the "smfstats" iovar, with an optional config index argument:
9874 * wl smfstats [-C N]|[--cfg=N] 0
9876 * Option:
9877 * -C N
9878 * --cfg=N
9879 * --config=N
9880 * --configuration=N
9881 * specify the config index N
9882 * If cfg index not given on a set, the WLC_SET_SMF_STATS ioctl will be used
9884 static int
9885 wl_smfstats(void *wl, cmd_t *cmd, char **argv)
9887 int bsscfg_idx = 0;
9888 int cfg_consumed = 0, smfs_consumed = 0;
9889 int err;
9890 int i, val;
9891 int smf_index = 0;
9892 int smfs_clear = 0;
9894 BCM_REFERENCE(cmd);
9896 argv++;
9898 /* parse a bsscfg_idx option if present */
9899 if ((err = wl_cfg_option(argv, "smfstats", &bsscfg_idx, &cfg_consumed)) != 0)
9900 return err;
9902 argv += cfg_consumed;
9904 if ((err = wl_smfs_option(argv, &smf_index, &smfs_consumed, &smfs_clear)) != 0)
9905 return err;
9907 if (!smfs_clear) {
9908 if (cfg_consumed == 0) {
9909 if (smfs_consumed) {
9910 err = wlu_iovar_getbuf(wl, "smfstats", &smf_index, sizeof(int),
9911 buf, WLC_IOCTL_SMLEN);
9912 if (!err)
9913 wl_disp_smfs(buf);
9915 else {
9916 for (i = 0; i < SMFS_TYPE_MAX; i++) {
9917 smf_index = i;
9918 err = wlu_iovar_getbuf(wl, "smfstats", &smf_index,
9919 sizeof(int), buf, WLC_IOCTL_SMLEN);
9920 if (!err)
9921 wl_disp_smfs(buf);
9924 } else {
9925 /* use "stats" iovar since a config option was given */
9926 if (smfs_consumed) {
9927 err = wl_bssiovar_getbuf(wl, "smfstats", bsscfg_idx, &smf_index,
9928 sizeof(int), buf, WLC_IOCTL_SMLEN);
9929 if (!err)
9930 wl_disp_smfs(buf);
9932 else {
9933 for (i = 0; i < SMFS_TYPE_MAX; i++) {
9934 smf_index = i;
9935 err = wl_bssiovar_getbuf(wl, "smfstats", bsscfg_idx,
9936 &smf_index, sizeof(int), buf, WLC_IOCTL_SMLEN);
9937 if (!err)
9938 wl_disp_smfs(buf);
9942 if (err < 0)
9943 return err;
9944 } else {
9945 val = 0;
9947 if (cfg_consumed == 0)
9948 err = wlu_iovar_setint(wl, "smfstats", val);
9949 else
9950 err = wl_bssiovar_setint(wl, "smfstats", bsscfg_idx, val);
9953 return err;
9957 static int
9958 wl_tssi(void *wl, cmd_t *cmd, char **argv)
9960 int ret;
9961 int val;
9963 UNUSED_PARAMETER(argv);
9965 if (cmd->get < 0)
9966 return -1;
9967 if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0)
9968 return ret;
9970 val = dtoh32(val);
9971 printf("CCK %d OFDM %d\n", (val & 0xff), (val >> 8) & 0xff);
9972 return 0;
9975 /* Quarter dBm units to mW
9976 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
9977 * Table is offset so the last entry is largest mW value that fits in
9978 * a uint16.
9981 #define QDBM_OFFSET 153 /* QDBM_OFFSET */
9982 #define QDBM_TABLE_LEN 40 /* QDBM_TABLE_LEN */
9984 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
9985 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
9987 #define QDBM_TABLE_LOW_BOUND 6493 /* QDBM_TABLE_LOW_BOUND */
9989 /* Largest mW value that will round down to the last table entry,
9990 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
9991 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
9993 #define QDBM_TABLE_HIGH_BOUND 64938 /* QDBM_TABLE_HIGH_BOUND */
9995 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
9996 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
9997 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
9998 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
9999 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
10000 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
10001 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
10004 static uint16
10005 wl_qdbm_to_mw(uint8 qdbm)
10007 uint factor = 1;
10008 int idx = qdbm - QDBM_OFFSET;
10010 if (idx > QDBM_TABLE_LEN) {
10011 /* clamp to max uint16 mW value */
10012 return 0xFFFF;
10015 /* scale the qdBm index up to the range of the table 0-40
10016 * where an offset of 40 qdBm equals a factor of 10 mW.
10018 while (idx < 0) {
10019 idx += 40;
10020 factor *= 10;
10023 /* return the mW value scaled down to the correct factor of 10,
10024 * adding in factor/2 to get proper rounding.
10026 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
10029 static uint8
10030 wl_mw_to_qdbm(uint16 mw)
10032 uint8 qdbm;
10033 int offset;
10034 uint mw_uint = mw;
10035 uint boundary;
10037 /* handle boundary case */
10038 if (mw_uint <= 1)
10039 return 0;
10041 offset = QDBM_OFFSET;
10043 /* move mw into the range of the table */
10044 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
10045 mw_uint *= 10;
10046 offset -= 40;
10049 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
10050 boundary = nqdBm_to_mW_map[qdbm] +
10051 (nqdBm_to_mW_map[qdbm+1] - nqdBm_to_mW_map[qdbm])/2;
10052 if (mw_uint < boundary) break;
10055 qdbm += (uint8)offset;
10057 return (qdbm);
10060 #define UNIT_MW 1 /* UNIT_MW */
10061 #define UNIT_QDBM 2 /* UNIT_QDBM */
10062 #define UNIT_DBM 3 /* UNIT_DBM */
10063 static int
10064 wl_txpwr1(void *wl, cmd_t *cmd, char **argv)
10066 int ret, val, new_val = 0, unit;
10067 const char *name = "qtxpower";
10068 bool override = FALSE;
10070 if (!*++argv) {
10071 if (cmd->get < 0)
10072 return -1;
10073 if ((ret = wlu_iovar_getint(wl, name, &val)) < 0)
10074 return ret;
10076 override = ((val & WL_TXPWR_OVERRIDE) != 0);
10077 val &= ~WL_TXPWR_OVERRIDE;
10078 printf("TxPower is %d qdbm, %d.%d dbm, %d mW Override is %s\n",
10079 val, DIV_QUO(val, 4), DIV_REM(val, 4),
10080 wl_qdbm_to_mw((uint8)(MIN(val, 0xff))),
10081 override ? "On" : "Off");
10082 return 0;
10083 } else {
10084 /* for set */
10085 unit = UNIT_DBM; /* default units */
10087 /* override can be used in combo with any unit */
10088 if (!strcmp(*argv, "-o")) {
10089 override = TRUE;
10090 if (!*++argv)
10091 return (-1);
10094 if (!strcmp(*argv, "-d")) {
10095 unit = UNIT_DBM;
10096 argv++;
10098 else if (!strcmp(*argv, "-q")) {
10099 unit = UNIT_QDBM;
10100 argv++;
10102 else if (!strcmp(*argv, "-m")) {
10103 unit = UNIT_MW;
10104 argv++;
10107 /* override can be used in combo with any unit */
10108 if (!strcmp(*argv, "-o")) {
10109 override = TRUE;
10110 argv++;
10113 if (!*argv)
10114 return (-1);
10116 val = atoi(*argv);
10118 if (val == -1) {
10119 val = 127; /* Max val of 127 qdbm */
10120 unit = UNIT_QDBM;
10123 if (val <= 0) {
10124 return -1;
10127 switch (unit) {
10128 case UNIT_MW:
10129 new_val = wl_mw_to_qdbm((uint16)MIN(val, 0xffff));
10130 break;
10131 case UNIT_DBM:
10132 new_val = val * 4;
10133 break;
10134 case UNIT_QDBM:
10135 new_val = val;
10136 break;
10139 if (override)
10140 new_val |= WL_TXPWR_OVERRIDE;
10142 return wlu_iovar_setint(wl, name, new_val);
10146 static int
10147 wl_txpwr(void *wl, cmd_t *cmd, char **argv)
10149 int error;
10150 int val;
10151 char *endptr = NULL;
10152 int override;
10153 const char *name = "qtxpower";
10155 UNUSED_PARAMETER(cmd);
10157 if (!*++argv) {
10158 if ((error = wlu_iovar_getint(wl, name, &val)) < 0)
10159 return error;
10161 /* Report power in mw with WL_TXPWR_OVERRIDE
10162 * bit indicating the status
10164 override = ((val & WL_TXPWR_OVERRIDE) != 0);
10165 val &= ~WL_TXPWR_OVERRIDE;
10166 printf("%d.%d dBm = %d mw. %s\n", DIV_QUO(val, 4), DIV_REM(val, 4),
10167 wl_qdbm_to_mw((uint8)(MIN(val, 0xff))), (override ? "(Override ON)" : ""));
10168 return 0;
10169 } else {
10170 if (!strcmp(*argv, "-u")) {
10171 override = 0;
10172 argv++;
10173 } else
10174 override = WL_TXPWR_OVERRIDE;
10176 val = strtol(*argv, &endptr, 0);
10177 if (*endptr != '\0') {
10178 /* not all the value string was parsed by strtol */
10179 return -1;
10182 val = wl_mw_to_qdbm((uint16)MIN(val, 0xffff));
10184 /* wl command input power will override current power set if told so */
10185 val |= override;
10187 return wlu_iovar_setint(wl, name, val);
10191 static int
10192 wl_get_txpwr_limit(void *wl, cmd_t *cmd, char **argv)
10194 int ret;
10195 uint8 val_qdbm;
10196 uint16 val_mw;
10197 tx_power_legacy_t power;
10199 UNUSED_PARAMETER(argv);
10201 ret = wlu_get(wl, cmd->get, &power, sizeof(power));
10202 if (ret < 0)
10203 return ret;
10205 val_qdbm = MIN(power.txpwr_band_max[0], power.txpwr_local_max);
10206 val_mw = wl_qdbm_to_mw((uint8)(MIN(val_qdbm, 0xff)));
10208 printf("%d mW (%d.%d dBm)\n", val_mw, DIV_QUO(val_qdbm, 4), DIV_REM(val_qdbm, 4));
10210 return ret;
10213 static int
10214 wl_atten(void *wl, cmd_t *cmd, char **argv)
10216 int ret;
10217 atten_t atten;
10218 char *endptr;
10220 if (!*++argv) {
10221 if (cmd->get < 0)
10222 return -1;
10224 if ((ret = wlu_get(wl, cmd->get, &atten, sizeof(atten_t))) < 0)
10225 return ret;
10227 printf("tx %s bb/radio/ctl1 %d/%d/%d\n",
10228 (dtoh16(atten.auto_ctrl) ? "auto" : ""),
10229 dtoh16(atten.bb), dtoh16(atten.radio), dtoh16(atten.txctl1));
10231 return 0;
10232 } else {
10233 if (cmd->set < 0)
10234 return -1;
10236 if (!stricmp(*argv, "auto")) {
10237 atten.auto_ctrl = WL_ATTEN_PCL_ON;
10239 else if (!stricmp(*argv, "manual")) {
10240 atten.auto_ctrl = WL_ATTEN_PCL_OFF;
10242 else {
10243 atten.auto_ctrl = WL_ATTEN_APP_INPUT_PCL_OFF;
10245 atten.bb = (uint16)strtoul(*argv, &endptr, 0);
10246 if (*endptr != '\0') {
10247 /* not all the value string was parsed by strtol */
10248 return -1;
10251 if (!*++argv)
10252 return -1;
10254 atten.radio = (uint16)strtoul(*argv, &endptr, 0);
10255 if (*endptr != '\0') {
10256 /* not all the value string was parsed by strtol */
10257 return -1;
10260 if (!*++argv)
10261 return -1;
10263 atten.txctl1 = (uint16)strtoul(*argv, &endptr, 0);
10264 if (*endptr != '\0') {
10265 /* not all the value string was parsed by strtol */
10266 return -1;
10271 atten.auto_ctrl = htod16(atten.auto_ctrl);
10272 atten.bb = htod16(atten.bb);
10273 atten.radio = htod16(atten.radio);
10274 atten.txctl1 = htod16(atten.txctl1);
10275 return wlu_set(wl, cmd->set, &atten, sizeof(atten_t));
10279 static int
10280 wl_maclist(void *wl, cmd_t *cmd, char **argv)
10282 int ret;
10283 struct maclist *maclist = (struct maclist *) buf;
10284 struct ether_addr *ea;
10285 uint i, max = (WLC_IOCTL_MAXLEN - sizeof(int)) / ETHER_ADDR_LEN;
10286 uint len;
10288 if (!*++argv) {
10289 if (cmd->get < 0)
10290 return -1;
10291 maclist->count = htod32(max);
10292 if ((ret = wlu_get(wl, cmd->get, maclist, WLC_IOCTL_MAXLEN)) < 0)
10293 return ret;
10294 maclist->count = dtoh32(maclist->count);
10295 for (i = 0, ea = maclist->ea; i < maclist->count && i < max; i++, ea++)
10296 printf("%s %s\n", cmd->name, wl_ether_etoa(ea));
10297 return 0;
10298 } else {
10299 if (cmd->set < 0)
10300 return -1;
10301 /* Clear list */
10302 maclist->count = htod32(0);
10303 if (!stricmp(*argv, "none") || !stricmp(*argv, "clear"))
10304 return wlu_set(wl, cmd->set, maclist, sizeof(int));
10305 /* Get old list */
10306 maclist->count = htod32(max);
10307 if ((ret = wlu_get(wl, cmd->get, maclist, WLC_IOCTL_MAXLEN)) < 0)
10308 return ret;
10309 /* Append to old list */
10310 maclist->count = dtoh32(maclist->count);
10311 ea = &maclist->ea[maclist->count];
10312 while (*argv && maclist->count < max) {
10313 if (!wl_ether_atoe(*argv, ea)) {
10314 printf("Problem parsing MAC address \"%s\".\n", *argv);
10315 return -1;
10317 maclist->count++;
10318 ea++;
10319 argv++;
10321 /* Set new list */
10322 len = sizeof(maclist->count) + maclist->count * sizeof(maclist->ea);
10323 maclist->count = htod32(maclist->count);
10324 return wlu_set(wl, cmd->set, maclist, len);
10328 static int
10329 wl_maclist_1(void *wl, cmd_t *cmd, char **argv)
10331 struct maclist *maclist;
10332 struct ether_addr *ea;
10333 uint i;
10334 int ret;
10336 strcpy(buf, argv[0]);
10338 if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0)
10339 return ret;
10341 maclist = (struct maclist *)buf;
10343 for (i = 0, ea = maclist->ea; i < dtoh32(maclist->count); i++, ea++)
10344 printf("%s %s\n", cmd->name, wl_ether_etoa(ea));
10345 return 0;
10348 static int
10349 wl_out(void *wl, cmd_t *cmd, char **argv)
10351 UNUSED_PARAMETER(cmd);
10352 UNUSED_PARAMETER(argv);
10354 return wlu_set(wl, WLC_OUT, NULL, 0);
10357 static int
10358 wl_band(void *wl, cmd_t *cmd, char **argv)
10360 uint band;
10361 int error;
10363 UNUSED_PARAMETER(cmd);
10365 error = 0;
10367 argv++;
10369 if (*argv == NULL) { /* get current band */
10370 if ((error = wlu_get(wl, WLC_GET_BAND, &band, sizeof(uint))) < 0)
10371 return (error);
10372 band = dtoh32(band);
10374 if (band == WLC_BAND_AUTO)
10375 printf("auto\n");
10376 else if (band == WLC_BAND_5G)
10377 printf("a\n");
10378 else if (band == WLC_BAND_2G)
10379 printf("b\n");
10380 else
10381 printf("unrecognized band value %d\n", band);
10382 } else { /* set the band */
10383 if (!stricmp(*argv, "auto"))
10384 band = WLC_BAND_AUTO;
10385 else if (!stricmp(*argv, "a"))
10386 band = WLC_BAND_5G;
10387 else if (!stricmp(*argv, "b"))
10388 band = WLC_BAND_2G;
10389 else {
10390 printf("unsupported band: %s\n", *argv);
10391 return (-1);
10394 band = htod32(band);
10395 error = wlu_set(wl, WLC_SET_BAND, &band, sizeof(uint));
10398 return (error);
10401 static int
10402 wl_bandlist(void *wl, cmd_t *cmd, char **argv)
10404 uint list[3];
10405 int error;
10406 uint i;
10408 UNUSED_PARAMETER(cmd);
10410 error = 0;
10412 argv++;
10414 if ((error = wlu_get(wl, WLC_GET_BANDLIST, list, sizeof(list))) < 0)
10415 return (error);
10416 list[0] = dtoh32(list[0]);
10417 list[1] = dtoh32(list[1]);
10418 list[2] = dtoh32(list[2]);
10420 /* list[0] is count, followed by 'count' bands */
10422 if (list[0] > 2)
10423 list[0] = 2;
10425 for (i = 1; i <= list[0]; i++)
10426 if (list[i] == WLC_BAND_5G)
10427 printf("a ");
10428 else if (list[i] == WLC_BAND_2G)
10429 printf("b ");
10430 else
10431 printf("? ");
10432 printf("\n");
10434 return (0);
10437 static int
10438 wl_phylist(void *wl, cmd_t *cmd, char **argv)
10440 char phylist_buf[128];
10441 int error;
10442 char *cp;
10444 UNUSED_PARAMETER(cmd);
10446 error = 0;
10448 argv++;
10450 if ((error = wlu_get(wl, WLC_GET_PHYLIST, phylist_buf, sizeof(phylist_buf))) < 0)
10451 return (error);
10453 cp = phylist_buf;
10455 for (; *cp; cp++)
10456 printf("%c ", *cp);
10457 printf("\n");
10459 return (0);
10462 #ifdef linux
10463 #define UPGRADE_BUFSIZE 512 /* upgrade buffer size */
10464 #else
10465 #define UPGRADE_BUFSIZE 1024 /* upgrade buffer size */
10466 #endif /* linux */
10468 static int
10469 wl_upgrade(void *wl, cmd_t *cmd, char **argv)
10471 #if !defined(BWL_FILESYSTEM_SUPPORT)
10472 UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
10473 return (-1);
10474 #elif defined(_CFE_)
10475 UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
10476 return CFE_ERR_UNSUPPORTED;
10477 #else
10478 FILE *fp;
10479 int ret = 0;
10480 struct {
10481 uint32 offset;
10482 char buf[UPGRADE_BUFSIZE];
10483 } block;
10484 uint32 offset;
10485 uint len;
10487 if (!*++argv)
10488 return -1;
10490 if (!(fp = fopen(*argv, "rb"))) {
10491 fprintf(stderr, "%s: No such file or directory\n", *argv);
10492 return -2;
10495 printf("Programming %s...", *argv);
10496 fflush(stdout);
10497 offset = 0;
10498 block.offset = htod32(offset);
10499 while ((len = fread(block.buf, 1, sizeof(block.buf), fp))) {
10500 if ((ret = wlu_set(wl, cmd->set, &block, 4 + len)) < 0)
10501 break;
10502 offset += len;
10503 block.offset = htod32(offset);
10504 printf(".");
10505 fflush(stdout);
10508 if (ferror(fp)) {
10509 ret = ferror(fp);
10510 printf("\nerror reading %s\n", *argv);
10511 } else {
10512 long status = WLC_UPGRADE_PENDING;
10513 int retries;
10515 printf("\nCommitting image to flash...\n");
10516 while (status == WLC_UPGRADE_PENDING) {
10517 retries = 10;
10518 retry:
10519 if ((ret = wlu_get(wl, WLC_UPGRADE_STATUS,
10520 &status, sizeof(status))) < 0) {
10521 /* the first attempt to get status will
10522 * likely fail due to dev reset
10524 if (retries--)
10525 goto retry;
10526 break;
10528 status = dtoh32(status);
10530 if (status == WLC_UPGRADE_SUCCESS)
10531 printf("\nDone\n\nSuccessfully downloaded %d bytes\n", block.offset);
10532 else
10533 fprintf(stderr, "\n*** UPGRADE FAILED! *** (status %ld)\n", status);
10536 fclose(fp);
10537 return ret;
10538 #endif /* BWL_FILESYSTEM_SUPPORT */
10541 #include <bcmnvram.h>
10543 static int
10544 wl_otpw(void *wl, cmd_t *cmd, char **argv)
10546 #if !defined(BWL_FILESYSTEM_SUPPORT)
10547 UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
10548 return (-1);
10549 #elif defined(_CFE_)
10550 UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
10551 return CFE_ERR_UNSUPPORTED;
10552 #else
10553 FILE *fp;
10554 int ret = 0;
10555 struct nvram_header *nvr;
10556 char *p, otpw_buf[1024 - 128];
10557 const char *msg;
10558 uint len;
10560 if (!*++argv)
10561 return -1;
10563 if (!(fp = fopen(*argv, "rb"))) {
10564 fprintf(stderr, "%s: No such file or directory\n", *argv);
10565 return -2;
10568 len = fread(otpw_buf, 1, sizeof(otpw_buf) - 1, fp);
10569 if ((ret = ferror(fp))) {
10570 printf("\nerror %d reading %s\n", ret, *argv);
10571 ret = -3;
10572 goto out;
10574 if (!feof(fp)) {
10575 printf("\nFile %s too large\n", *argv);
10576 ret = -4;
10577 goto out;
10580 /* Got the bits, do they look like the output of nvserial? */
10581 nvr = (struct nvram_header *)otpw_buf;
10582 if (nvr->magic == NVRAM_MAGIC) {
10583 if (cmd->set == WLC_OTPW) {
10584 printf("File %s looks like an nvserial file, use nvotpw\n", *argv);
10585 fflush(stdout);
10586 ret = -5;
10587 goto out;
10589 len = nvr->len - sizeof(struct nvram_header);
10590 if (len & 1) {
10591 otpw_buf[len++] = '\0';
10593 p = (char *)(nvr + 1);
10594 msg = "nvserial";
10595 } else {
10596 if (cmd->set == WLC_NVOTPW) {
10597 printf("File %s is not an nvserial file\n", *argv);
10598 ret = -6;
10599 goto out;
10601 if (len & 1) {
10602 printf("File %s has an odd length (%d)\n", *argv, len);
10603 ret = -7;
10604 goto out;
10606 p = otpw_buf;
10607 msg = "raw";
10610 printf("Writing %d bytes from %s file %s to otp ...\n", len, msg, *argv);
10611 fflush(stdout);
10613 if ((ret = wlu_set(wl, cmd->set, p, len)) < 0) {
10614 printf("\nError %d writing %s to otp\n", ret, *argv);
10617 out:
10618 fclose(fp);
10619 return ret;
10620 #endif /* BWL_FILESYSTEM_SUPPORT */
10623 static int
10624 wl_get_pktcnt(void *wl, cmd_t *cmd, char **argv)
10626 int ret;
10627 get_pktcnt_t pktcnt;
10629 UNUSED_PARAMETER(argv);
10631 memset(&pktcnt, 0, sizeof(pktcnt));
10632 if ((ret = wlu_get(wl, cmd->get, &pktcnt, sizeof(pktcnt))) < 0)
10633 return ret;
10635 printf("Receive: good packet %d, bad packet %d, othercast good packet %d\n",
10636 dtoh32(pktcnt.rx_good_pkt), dtoh32(pktcnt.rx_bad_pkt),
10637 dtoh32(pktcnt.rx_ocast_good_pkt));
10638 printf("Transmit: good packet %d, bad packet %d\n",
10639 dtoh32(pktcnt.tx_good_pkt), dtoh32(pktcnt.tx_bad_pkt));
10641 return ret;
10644 static int
10645 wl_interfere(void *wl, cmd_t *cmd, char **argv)
10647 int ret;
10648 int val;
10649 char *endptr = NULL;
10650 int mode;
10652 if (!*++argv) {
10653 if (cmd->get < 0)
10654 return -1;
10655 if ((ret = wlu_get(wl, cmd->get, &mode, sizeof(mode))) < 0)
10656 return ret;
10657 mode = dtoh32(mode);
10658 switch (mode & 0x7f) {
10659 case INTERFERE_NONE:
10660 printf("All interference mitigation is disabled. (mode 0)\n");
10661 break;
10662 case NON_WLAN:
10663 printf("Non-wireless LAN Interference mitigation is enabled. (mode 1)\n");
10664 break;
10665 case WLAN_MANUAL:
10666 printf("Wireless LAN Interference mitigation is enabled. (mode 2)\n");
10667 break;
10668 case WLAN_AUTO:
10669 printf("Auto Wireless LAN Interference mitigation is enabled and ");
10670 if (mode & AUTO_ACTIVE)
10671 printf("active. (mode 3)\n");
10672 else
10673 printf("not active. (mode 3)\n");
10675 break;
10676 case WLAN_AUTO_W_NOISE:
10677 printf("Auto Wireless LAN Interference mitigation is enabled and ");
10678 if (mode & AUTO_ACTIVE)
10679 printf("active, ");
10680 else
10681 printf("not active, ");
10683 printf("and noise reduction is enabled. (mode 4)\n");
10684 break;
10686 return 0;
10687 } else {
10688 mode = INTERFERE_NONE;
10689 val = strtol(*argv, &endptr, 0);
10690 if (*endptr != '\0')
10691 return (-1);
10693 switch (val) {
10694 case 0:
10695 mode = INTERFERE_NONE;
10696 break;
10697 case 1:
10698 mode = NON_WLAN;
10699 break;
10700 case 2:
10701 mode = WLAN_MANUAL;
10702 break;
10703 case 3:
10704 mode = WLAN_AUTO;
10705 break;
10706 case 4:
10707 mode = WLAN_AUTO_W_NOISE;
10708 break;
10709 default:
10710 return (-1);
10713 mode = htod32(mode);
10714 return wlu_set(wl, cmd->set, &mode, sizeof(mode));
10718 static int
10719 wl_interfere_override(void *wl, cmd_t *cmd, char **argv)
10721 int ret;
10722 int val;
10723 char *endptr;
10724 int mode;
10726 if (!*++argv) {
10727 if (cmd->get < 0)
10728 return -1;
10729 if ((ret = wlu_get(wl, cmd->get, &mode, sizeof(mode))) < 0) {
10730 return ret;
10732 mode = dtoh32(mode);
10733 switch (mode) {
10734 case INTERFERE_NONE:
10735 printf("Interference override NONE, "
10736 "all mitigation disabled. (mode 0)\n");
10737 break;
10738 case NON_WLAN:
10739 printf("Interference override enabled. "
10740 " Non-wireless LAN Interference mitigation is enabled. (mode 1)\n");
10741 break;
10742 case WLAN_MANUAL:
10743 printf("Interference override enabled. "
10744 " Wireless LAN Interference mitigation is enabled. (mode 2)\n");
10745 break;
10746 case WLAN_AUTO:
10747 printf("Interference override enabled. "
10748 " Interference mitigation is enabled and ");
10749 if (mode & AUTO_ACTIVE)
10750 printf("active. (mode 3)\n");
10751 else
10752 printf("not active. (mode 3)\n");
10754 break;
10755 case WLAN_AUTO_W_NOISE:
10756 printf("Interference override enabled. "
10757 " Interference mitigation is enabled and ");
10758 if (mode & AUTO_ACTIVE)
10759 printf("active, ");
10760 else
10761 printf("not active, ");
10763 printf("and noise reduction is enabled. (mode 4)\n");
10764 break;
10765 case INTERFERE_OVRRIDE_OFF:
10766 printf("Interference override disabled. \n");
10767 break;
10769 return 0;
10770 } else {
10771 mode = INTERFERE_NONE;
10772 val = strtol(*argv, &endptr, 0);
10773 if (*endptr != '\0')
10774 return (-1);
10776 switch (val) {
10777 case 0:
10778 mode = INTERFERE_NONE;
10779 break;
10780 case 1:
10781 mode = NON_WLAN;
10782 break;
10783 case 2:
10784 mode = WLAN_MANUAL;
10785 break;
10786 case 3:
10787 mode = WLAN_AUTO;
10788 break;
10789 case 4:
10790 mode = WLAN_AUTO_W_NOISE;
10791 break;
10792 case INTERFERE_OVRRIDE_OFF:
10793 mode = INTERFERE_OVRRIDE_OFF;
10794 break;
10795 default:
10796 return (-1);
10799 mode = htod32(mode);
10800 return wlu_set(wl, cmd->set, &mode, sizeof(mode));
10804 static cntry_name_t *
10805 wlc_cntry_name_to_country(char *long_name)
10807 cntry_name_t *cntry;
10808 for (cntry = cntry_names; cntry->name &&
10809 stricmp(long_name, cntry->name); cntry++);
10810 return (!cntry->name ? NULL : cntry);
10813 static cntry_name_t *
10814 wlc_cntry_abbrev_to_country(const char *abbrev)
10816 cntry_name_t *cntry;
10817 if (!*abbrev || strlen(abbrev) > 3 || strlen(abbrev) < 2)
10818 return (NULL);
10819 for (cntry = cntry_names; cntry->name &&
10820 strnicmp(abbrev, cntry->abbrev, strlen(abbrev)); cntry++);
10821 return (!cntry->name ? NULL : cntry);
10824 static int
10825 wl_parse_country_spec(const char *spec, char *ccode, int *regrev)
10827 char *revstr;
10828 char *endptr = NULL;
10829 int ccode_len;
10830 int rev = -1;
10832 revstr = strchr(spec, '/');
10834 if (revstr) {
10835 rev = strtol(revstr + 1, &endptr, 10);
10836 if (*endptr != '\0') {
10837 /* not all the value string was parsed by strtol */
10838 fprintf(stderr,
10839 "Could not parse \"%s\" as a regulatory revision "
10840 "in the country string \"%s\"\n",
10841 revstr + 1, spec);
10842 return USAGE_ERROR;
10846 if (revstr)
10847 ccode_len = (int)(uintptr)(revstr - spec);
10848 else
10849 ccode_len = (int)strlen(spec);
10851 if (ccode_len > 3) {
10852 fprintf(stderr,
10853 "Could not parse a 2-3 char country code "
10854 "in the country string \"%s\"\n",
10855 spec);
10856 return USAGE_ERROR;
10859 memcpy(ccode, spec, ccode_len);
10860 ccode[ccode_len] = '\0';
10861 *regrev = rev;
10863 return 0;
10867 wl_country(void *wl, cmd_t *cmd, char **argv)
10869 cntry_name_t *cntry;
10870 wl_country_t cspec = {{0}, 0, {0}};
10871 int argc = 0;
10872 int err;
10873 int bcmerr = 1;
10875 /* skip the command name */
10876 argv++;
10878 /* find the arg count */
10879 while (argv[argc])
10880 argc++;
10882 /* check arg list count */
10883 if (argc > 2) {
10884 fprintf(stderr, "Too many arguments (%d) for command %s\n", argc, cmd->name);
10885 return USAGE_ERROR;
10888 buf[0] = 0;
10889 if (argc == 0) {
10890 const char* name = "<unknown>";
10892 /* first try the country iovar */
10893 err = wlu_iovar_get(wl, "country", &cspec, sizeof(cspec));
10895 if (!err) {
10896 cntry = wlc_cntry_abbrev_to_country(cspec.country_abbrev);
10897 if (cntry)
10898 name = cntry->name;
10900 printf("%s (%s/%d) %s\n",
10901 cspec.country_abbrev, cspec.ccode, cspec.rev, name);
10903 return 0;
10906 /* if there was an error other than BCME_UNSUPPORTED, fail now */
10907 wlu_iovar_getint(wl, "bcmerror", &bcmerr);
10908 if (bcmerr != BCME_UNSUPPORTED)
10909 return err;
10911 /* if the "country" iovar is unsupported, try the WLC_SET_COUNTRY ioctl */
10912 if ((err = wlu_get(wl, cmd->get, &buf[0], WLC_IOCTL_SMLEN)))
10913 return err;
10914 if (strlen(buf) == 0) {
10915 printf("No country set\n");
10916 return 0;
10919 cntry = wlc_cntry_abbrev_to_country(buf);
10920 if (cntry != NULL)
10921 name = cntry->name;
10923 printf("%s () %s\n", buf, name);
10924 return 0;
10927 if (!stricmp(*argv, "list")) {
10928 uint i;
10929 const char* abbrev;
10930 wl_country_list_t *cl = (wl_country_list_t *)buf;
10932 cl->buflen = WLC_IOCTL_MAXLEN;
10933 cl->count = 0;
10935 /* band may follow */
10936 if (*++argv) {
10937 cl->band_set = TRUE;
10938 if (!stricmp(*argv, "a"))
10939 cl->band = WLC_BAND_5G;
10940 else if (!stricmp(*argv, "b") || !stricmp(*argv, "g"))
10941 cl->band = WLC_BAND_2G;
10942 else {
10943 printf("unsupported band: %s\n", *argv);
10944 return -1;
10946 } else {
10947 cl->band_set = FALSE;
10950 cl->buflen = htod32(cl->buflen);
10951 cl->band_set = htod32(cl->band_set);
10952 cl->band = htod32(cl->band);
10953 cl->count = htod32(cl->count);
10954 err = wlu_get(wl, WLC_GET_COUNTRY_LIST, buf, WLC_IOCTL_MAXLEN);
10955 if (err < 0)
10956 return err;
10958 printf("Supported countries: country code and long name\n");
10959 for (i = 0; i < dtoh32(cl->count); i++) {
10960 abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ];
10961 cntry = wlc_cntry_abbrev_to_country(abbrev);
10962 printf("%s\t%s\n", abbrev, cntry ? cntry->name : "");
10964 return 0;
10967 memset(&cspec, 0, sizeof(cspec));
10968 cspec.rev = -1;
10970 if (argc == 1) {
10971 /* check for the first arg being a country name, e.g. "United States",
10972 * or country spec, "US/1", or just a country code, "US"
10974 if ((cntry = wlc_cntry_name_to_country(argv[0])) != NULL) {
10975 /* arg matched a country name */
10976 memcpy(cspec.country_abbrev, cntry->abbrev, WLC_CNTRY_BUF_SZ);
10977 err = 0;
10978 } else {
10979 /* parse a country spec, e.g. "US/1", or a country code.
10980 * cspec.rev will be -1 if not specified.
10982 err = wl_parse_country_spec(argv[0], cspec.country_abbrev, &cspec.rev);
10985 if (err) {
10986 fprintf(stderr,
10987 "Argument \"%s\" could not be parsed as a country name, "
10988 "country code, or country code and regulatory revision.\n",
10989 argv[0]);
10990 return USAGE_ERROR;
10993 /* if the arg was a country spec, then fill out ccdoe and rev,
10994 * and leave country_abbrev defaulted to the ccode
10996 if (cspec.rev != -1)
10997 memcpy(cspec.ccode, cspec.country_abbrev, WLC_CNTRY_BUF_SZ);
10998 } else {
10999 /* for two args, the first needs to be a country code or country spec */
11000 err = wl_parse_country_spec(argv[0], cspec.ccode, &cspec.rev);
11001 if (err) {
11002 fprintf(stderr,
11003 "Argument 1 \"%s\" could not be parsed as a country code, or "
11004 "country code and regulatory revision.\n",
11005 argv[0]);
11006 return USAGE_ERROR;
11009 /* the second arg needs to be a country name or country code */
11010 if ((cntry = wlc_cntry_name_to_country(argv[1])) != NULL) {
11011 /* arg matched a country name */
11012 memcpy(cspec.country_abbrev, cntry->abbrev, WLC_CNTRY_BUF_SZ);
11013 } else {
11014 int rev;
11015 err = wl_parse_country_spec(argv[1], cspec.country_abbrev, &rev);
11016 if (rev != -1) {
11017 fprintf(stderr,
11018 "Argument \"%s\" had a revision. Arg 2 must be "
11019 "a country name or country code without a revision\n",
11020 argv[1]);
11021 return USAGE_ERROR;
11025 if (err) {
11026 fprintf(stderr,
11027 "Argument 2 \"%s\" could not be parsed as "
11028 "a country name or country code\n",
11029 argv[1]);
11030 return USAGE_ERROR;
11034 /* first try the country iovar */
11035 if (cspec.rev == -1 && cspec.ccode[0] == '\0')
11036 err = wlu_iovar_set(wl, "country", &cspec, WLC_CNTRY_BUF_SZ);
11037 else
11038 err = wlu_iovar_set(wl, "country", &cspec, sizeof(cspec));
11040 if (err == 0)
11041 return 0;
11043 /* if there was an error other than BCME_UNSUPPORTED, fail now */
11044 wlu_iovar_getint(wl, "bcmerror", &bcmerr);
11045 if (bcmerr != BCME_UNSUPPORTED)
11046 return err;
11048 /* if the "country" iovar is unsupported, try the WLC_SET_COUNTRY ioctl if possible */
11050 if (cspec.rev != -1 || cspec.ccode[0] != '\0') {
11051 fprintf(stderr,
11052 "Driver does not support full country spec interface, "
11053 "only a country name or code may be sepcified\n");
11054 return err;
11057 /* use the legacy ioctl */
11058 err = wlu_set(wl, WLC_SET_COUNTRY, cspec.country_abbrev, WLC_CNTRY_BUF_SZ);
11060 return err;
11064 wl_country_ie_override(void *wl, cmd_t *cmd, char **argv)
11066 int argc = 0;
11067 int error, i;
11069 /* skip the command name */
11070 argv++;
11072 /* find the arg count */
11073 while (argv[argc])
11074 argc++;
11076 if (argc == 0) {
11077 void *ptr;
11078 bcm_tlv_t *ie;
11080 if ((error = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
11081 return (error);
11083 ie = (bcm_tlv_t *)ptr;
11085 printf("ie tag:0x%x ie len:0x%x ie data:", ie->id, ie->len);
11087 for (i = 0; i < ie->len; i++)
11088 printf("0x%x ", ie->data[i]);
11090 printf("\n");
11092 return error;
11094 } else {
11095 /* Set */
11096 char *endptr = NULL;
11097 uchar *valsp;
11098 int8 ie_len, pad = 0;
11100 /* retrieve the ie len in advance to check for padding */
11101 ie_len = (int8)strtol(*(argv + 1), NULL, 0);
11102 if (ie_len & 1) {
11103 fprintf(stderr, "country ie len is odd(%d), padding by 1 octet\n", ie_len);
11104 pad = 1;
11107 valsp = (uchar*)malloc(argc + pad);
11108 if (valsp == NULL) {
11109 fprintf(stderr, "Error allocating %d bytes country ie\n", argc);
11110 return -1;
11112 memset(valsp, 0, argc + pad);
11114 for (i = 0; i < argc; i++, argv++) {
11116 valsp[i] = strtol(*argv, &endptr, 0);
11118 /* make sure all the value string was parsed by strtol */
11119 if (*endptr != '\0')
11120 return -1;
11123 /* update ie len if padded */
11124 if (pad) {
11125 valsp[1] += 1;
11126 valsp[ie_len + TLV_HDR_LEN] = 0;
11129 return wlu_var_setbuf(wl, cmd->name, valsp, argc + pad);
11133 #define ACI_SPIN "spin"
11134 #define ACI_ENTER "enter"
11135 #define ACI_EXIT "exit"
11136 #define ACI_GLITCH "glitch"
11138 #define NPHY_ACI_ADCPWR_ENTER "adcpwr_enter"
11139 #define NPHY_ACI_ADCPWR_EXIT "adcpwr_exit"
11140 #define NPHY_ACI_REPEAT_CTR "repeat"
11141 #define NPHY_ACI_NUM_SAMPLES "samples"
11142 #define NPHY_ACI_UNDETECT "undetect_sz"
11143 #define NPHY_ACI_LOPWR "loaci"
11144 #define NPHY_ACI_MDPWR "mdaci"
11145 #define NPHY_ACI_HIPWR "hiaci"
11146 #define NPHY_ACI_NOISE_NOASSOC_GLITCH_TH_UP "nphy_noise_noassoc_glitch_th_up"
11147 #define NPHY_ACI_NOISE_NOASSOC_GLITCH_TH_DN "nphy_noise_noassoc_glitch_th_dn"
11148 #define NPHY_ACI_NOISE_ASSOC_GLITCH_TH_UP "nphy_noise_assoc_glitch_th_up"
11149 #define NPHY_ACI_NOISE_ASSOC_GLITCH_TH_DN "nphy_noise_assoc_glitch_th_dn"
11150 #define NPHY_ACI_NOISE_ASSOC_ACI_GLITCH_TH_UP "nphy_noise_assoc_aci_glitch_th_up"
11151 #define NPHY_ACI_NOISE_ASSOC_ACI_GLITCH_TH_DN "nphy_noise_assoc_aci_glitch_th_dn"
11152 #define NPHY_ACI_NOISE_NOASSOC_ENTER_TH "nphy_noise_noassoc_enter_th"
11153 #define NPHY_ACI_NOISE_ASSOC_ENTER_TH "nphy_noise_assoc_enter_th"
11154 #define NPHY_ACI_NOISE_ASSOC_RX_GLITCH_BADPLCP_ENTER_TH \
11155 "nphy_noise_assoc_rx_glitch_badplcp_enter_th"
11156 #define NPHY_ACI_NOISE_ASSOC_CRSIDX_INCR "nphy_noise_assoc_crsidx_incr"
11157 #define NPHY_ACI_NOISE_NOASSOC_CRSIDX_INCR "nphy_noise_noassoc_crsidx_incr"
11158 #define NPHY_ACI_NOISE_CRSIDX_DECR "nphy_noise_crsidx_decr"
11161 #if defined(BWL_FILESYSTEM_SUPPORT)
11162 #if !defined(_CFE_)
11163 static int
11164 wl_do_samplecollect_n(void *wl, wl_samplecollect_args_t *collect, uint8 *buff, FILE *fp)
11166 uint16 nbytes;
11167 int ret = 0;
11169 ret = wlu_iovar_getbuf(wl, "sample_collect", collect, sizeof(wl_samplecollect_args_t),
11170 buff, WLC_SAMPLECOLLECT_MAXLEN);
11172 if (ret)
11173 return ret;
11175 /* bytes 1:0 indicate capture length */
11176 while ((nbytes = ltoh16_ua(buff))) {
11177 nbytes += 2;
11178 ret = fwrite(buff, 1, nbytes, fp);
11179 if (ret != nbytes) {
11180 fprintf(stderr, "Error writing %d bytes to file, rc %d!\n",
11181 nbytes, ret);
11182 ret = -1;
11183 break;
11184 } else {
11185 fprintf(stderr, "Wrote %d bytes\n", nbytes);
11187 buff += nbytes;
11189 return (ret);
11192 static int
11193 wl_do_samplecollect(void *wl, wl_samplecollect_args_t *collect, int sampledata_version,
11194 uint32 *buff, FILE *fp)
11196 uint16 nbytes, tag;
11197 uint32 flag, *header, sync;
11198 uint8 *ptr;
11199 int err;
11200 wl_sampledata_t *sample_collect;
11201 wl_sampledata_t sample_data, *psample;
11203 err = wlu_iovar_getbuf(wl, "sample_collect", collect, sizeof(wl_samplecollect_args_t),
11204 buff, WLC_SAMPLECOLLECT_MAXLEN);
11206 if (err)
11207 return err;
11209 sample_collect = (wl_sampledata_t *)buff;
11210 header = (uint32 *)&sample_collect[1];
11211 tag = ltoh16_ua(&sample_collect->tag);
11212 if (tag != WL_SAMPLEDATA_HEADER_TYPE) {
11213 fprintf(stderr, "Expect SampleData Header type %d, receive type %d\n",
11214 WL_SAMPLEDATA_HEADER_TYPE, tag);
11215 return -1;
11218 nbytes = ltoh16_ua(&sample_collect->length);
11219 flag = ltoh32_ua(&sample_collect->flag);
11220 sync = ltoh32_ua(&header[0]);
11221 if (sync != 0xACDC2009) {
11222 fprintf(stderr, "Header sync word mismatch (0x%08x)\n", sync);
11223 return -1;
11226 err = fwrite((uint8 *)header, 1, nbytes, fp);
11227 if (err != (int)nbytes)
11228 fprintf(stderr, "Failed write file-header to file %d\n", err);
11230 memset(&sample_data, 0, sizeof(wl_sampledata_t));
11231 sample_data.version = sampledata_version;
11232 sample_data.size = htol16(sizeof(wl_sampledata_t));
11233 flag = 0;
11234 /* new format, used in htphy */
11235 do {
11236 sample_data.tag = htol16(WL_SAMPLEDATA_TYPE);
11237 sample_data.length = htol16(WLC_SAMPLECOLLECT_MAXLEN);
11238 /* mask seq# */
11239 sample_data.flag = htol32((flag & 0xff));
11241 err = wlu_iovar_getbuf(wl, "sample_data", &sample_data, sizeof(wl_sampledata_t),
11242 buff, WLC_SAMPLECOLLECT_MAXLEN);
11243 if (err) {
11244 fprintf(stderr, "Error reading back sample collected data\n");
11245 err = -1;
11246 break;
11249 ptr = (uint8 *)buff + sizeof(wl_sampledata_t);
11250 psample = (wl_sampledata_t *)buff;
11251 tag = ltoh16_ua(&psample->tag);
11252 nbytes = ltoh16_ua(&psample->length);
11253 flag = ltoh32_ua(&psample->flag);
11254 if (tag != WL_SAMPLEDATA_TYPE) {
11255 fprintf(stderr, "Expect SampleData type %d, receive type %d\n",
11256 WL_SAMPLEDATA_TYPE, tag);
11257 err = -1;
11258 break;
11260 if (nbytes == 0) {
11261 fprintf(stderr, "Done retrieving sample data\n");
11262 err = -1;
11263 break;
11265 err = fwrite(ptr, 1, nbytes, fp);
11266 if (err != (int)nbytes) {
11267 fprintf(stderr, "Error writing %d bytes to file, rc %d!\n",
11268 (int)nbytes, err);
11269 err = -1;
11270 break;
11271 } else {
11272 printf("Wrote %d bytes\n", err);
11274 } while (flag & WL_SAMPLEDATA_MORE_DATA);
11275 return err;
11277 #endif
11278 #endif /* defined(BWL_FILESYSTEM_SUPPORT) */
11280 static int
11281 wl_sample_collect(void *wl, cmd_t *cmd, char **argv)
11283 #if !defined(BWL_FILESYSTEM_SUPPORT)
11284 UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
11285 return (-1);
11286 #elif defined(_CFE_)
11287 UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv);
11288 return CFE_ERR_UNSUPPORTED;
11289 #else
11290 int ret = -1;
11291 uint8 *buff = NULL;
11292 wl_samplecollect_args_t collect;
11293 const char *fname = "sample_collect.dat";
11294 wlc_rev_info_t revinfo;
11295 uint32 phytype, phyrev;
11296 FILE *fp = NULL;
11298 /* Default setting for sampledata_version */
11299 int sampledata_version = htol16(WL_SAMPLEDATA_T_VERSION);
11301 UNUSED_PARAMETER(cmd);
11303 memset(&revinfo, 0, sizeof(revinfo));
11304 ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
11305 if (ret) {
11306 return ret;
11308 phytype = dtoh32(revinfo.phytype);
11309 phyrev = dtoh32(revinfo.phyrev);
11311 /* Assign some default params first */
11312 /* 60us is roughly the max we can store (for NPHY with NREV < 7). */
11313 collect.coll_us = 60;
11314 collect.cores = -1;
11315 /* extended settings */
11316 collect.trigger = TRIGGER_NOW;
11317 collect.mode = 1;
11318 collect.post_dur = 10;
11319 collect.pre_dur = 10;
11320 collect.gpio_sel = 0;
11321 collect.downsamp = FALSE;
11322 collect.be_deaf = FALSE;
11323 collect.timeout = 1000;
11324 collect.agc = FALSE;
11325 collect.filter = FALSE;
11326 collect.version = WL_SAMPLECOLLECT_T_VERSION;
11327 collect.length = sizeof(wl_samplecollect_args_t);
11329 /* Skip the command name */
11330 argv++;
11331 ret = -1;
11332 while (*argv) {
11333 char *s = *argv;
11335 if (argv[1] == NULL)
11336 goto exit;
11337 if (!strcmp(s, "-f"))
11338 fname = argv[1];
11339 else if (!strcmp(s, "-u"))
11340 collect.coll_us = atoi(argv[1]);
11341 else if (!strcmp(s, "-c"))
11342 collect.cores = atoi(argv[1]);
11343 /* extended settings */
11344 else if (!strcmp(s, "-t")) {
11345 /* event trigger */
11346 if (!strcmp(argv[1], "crs"))
11347 collect.trigger = TRIGGER_CRS;
11348 else if (!strcmp(argv[1], "crs_deassert"))
11349 collect.trigger = TRIGGER_CRSDEASSERT;
11350 else if (!strcmp(argv[1], "good_fcs"))
11351 collect.trigger = TRIGGER_GOODFCS;
11352 else if (!strcmp(argv[1], "bad_fcs"))
11353 collect.trigger = TRIGGER_BADFCS;
11354 else if (!strcmp(argv[1], "bad_plcp"))
11355 collect.trigger = TRIGGER_BADPLCP;
11356 else if (!strcmp(argv[1], "crs_glitch"))
11357 collect.trigger = TRIGGER_CRSGLITCH;
11359 else if (!strcmp(s, "-m")) {
11360 if (!strcmp(argv[1], "gpio")) {
11361 if (phytype == WLC_PHY_TYPE_HT) {
11362 collect.mode = 4;
11363 } else {
11364 /* MIMOPHY */
11365 collect.mode = 0xff;
11367 } else {
11368 collect.mode = atoi(argv[1]);
11371 else if (!strcmp(s, "-b"))
11372 collect.pre_dur = atoi(argv[1]);
11373 else if (!strcmp(s, "-a"))
11374 collect.post_dur = atoi(argv[1]);
11375 else if (!strcmp(s, "-g"))
11376 collect.gpio_sel = atoi(argv[1]);
11377 else if (!strcmp(s, "-d"))
11378 collect.downsamp = atoi(argv[1]);
11379 else if (!strcmp(s, "-e"))
11380 collect.be_deaf = atoi(argv[1]);
11381 else if (!strcmp(s, "-i"))
11382 collect.timeout = atoi(argv[1]);
11383 else if (!strcmp(s, "--agc")) {
11384 /* perform software agc for sample collect */
11385 collect.agc = atoi(argv[1]);
11387 else if (!strcmp(s, "--filter")) {
11388 /* Set HPC for LPF to lowest possible value (0x1) */
11389 collect.filter = atoi(argv[1]);
11391 else if (!strcmp(s, "-v"))
11392 sampledata_version = atoi(argv[1]);
11393 else
11394 goto exit;
11396 argv += 2;
11399 buff = malloc(WLC_SAMPLECOLLECT_MAXLEN);
11400 if (buff == NULL) {
11401 fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n",
11402 WLC_SAMPLECOLLECT_MAXLEN);
11403 return -1;
11405 memset(buff, 0, WLC_SAMPLECOLLECT_MAXLEN);
11407 if ((fp = fopen(fname, "wb")) == NULL) {
11408 fprintf(stderr, "Problem opening file %s\n", fname);
11409 ret = -1;
11410 goto exit;
11413 if (phytype == WLC_PHY_TYPE_HT) {
11414 ret = wl_do_samplecollect(wl, &collect, sampledata_version, (uint32 *)buff, fp);
11415 } else if (phytype == WLC_PHY_TYPE_N) {
11416 if (phyrev < 7) {
11417 ret = wl_do_samplecollect_n(wl, &collect, buff, fp);
11418 } else {
11419 ret = wl_do_samplecollect(wl, &collect, sampledata_version,
11420 (uint32 *)buff, fp);
11424 exit:
11425 if (buff) free(buff);
11426 if (fp) fclose(fp);
11427 return ret;
11428 #endif /* !BWL_FILESYSTEM_SUPPORT */
11431 static int
11432 wl_ampdu_activate_test(void *wl, cmd_t *cmd, char **argv)
11434 char *param;
11435 const char *cmdname = "ampdu_activate_test";
11436 struct agg {
11437 bool val1;
11438 bool val2;
11439 } x;
11440 int err = 0;
11442 UNUSED_PARAMETER(cmd);
11444 if ((param = *++argv) == NULL)
11445 return USAGE_ERROR;
11447 x.val1 = atoi(param);
11448 if ((param = *++argv)) {
11449 x.val2 = atoi(param);
11450 printf("%d %d\n", x.val1, x.val2);
11451 err = wlu_var_setbuf(wl, cmdname, &x, sizeof(x));
11453 return err;
11456 static int
11457 wl_ampdu_tid(void *wl, cmd_t *cmd, char **argv)
11459 char *param;
11460 const char *cmdname = "ampdu_tid";
11461 struct ampdu_tid_control atc, *reply;
11462 uint8 tid;
11463 int err;
11464 void *ptr = NULL;
11466 UNUSED_PARAMETER(cmd);
11468 if ((param = *++argv) == NULL)
11469 return USAGE_ERROR;
11471 tid = atoi(param);
11472 if (tid > MAXPRIO)
11473 return USAGE_ERROR;
11474 atc.tid = tid;
11476 if ((param = *++argv)) {
11477 atc.enable = atoi(param);
11478 err = wlu_var_setbuf(wl, cmdname, &atc, sizeof(atc));
11479 } else {
11480 if ((err = wlu_var_getbuf_sm(wl, cmdname, &atc, sizeof(atc), &ptr) < 0))
11481 return err;
11482 reply = (struct ampdu_tid_control *)ptr;
11483 printf("AMPDU for tid %d: %d\n", tid, reply->enable);
11485 return err;
11488 static int
11489 wl_ampdu_retry_limit_tid(void *wl, cmd_t *cmd, char **argv)
11491 char *param;
11492 const char *cmdname = "ampdu_retry_limit_tid";
11493 struct ampdu_retry_tid retry_limit, *reply;
11494 uint8 tid;
11495 int err;
11496 void *ptr = NULL;
11498 UNUSED_PARAMETER(cmd);
11500 if ((param = *++argv) == NULL)
11501 return USAGE_ERROR;
11503 tid = atoi(param);
11504 if (tid > MAXPRIO)
11505 return USAGE_ERROR;
11506 retry_limit.tid = tid;
11508 if ((param = *++argv)) {
11509 retry_limit.retry = atoi(param);
11510 err = wlu_var_setbuf(wl, cmdname, &retry_limit, sizeof(retry_limit));
11511 } else {
11512 if ((err = wlu_var_getbuf(wl, cmdname, &retry_limit,
11513 sizeof(retry_limit), &ptr)) < 0)
11514 return err;
11515 reply = (struct ampdu_retry_tid *)ptr;
11516 printf("AMPDU retry limit for tid %d: %d\n", tid, reply->retry);
11518 return err;
11521 static int
11522 wl_ampdu_rr_retry_limit_tid(void *wl, cmd_t *cmd, char **argv)
11524 char *param;
11525 const char *cmdname = "ampdu_rr_retry_limit_tid";
11526 struct ampdu_retry_tid retry_limit, *reply;
11527 uint8 tid;
11528 int err;
11529 void *ptr = NULL;
11531 UNUSED_PARAMETER(cmd);
11533 if ((param = *++argv) == NULL)
11534 return USAGE_ERROR;
11536 tid = atoi(param);
11537 if (tid > MAXPRIO)
11538 return USAGE_ERROR;
11539 retry_limit.tid = tid;
11541 if ((param = *++argv)) {
11542 retry_limit.retry = atoi(param);
11543 err = wlu_var_setbuf(wl, cmdname, &retry_limit, sizeof(retry_limit));
11544 } else {
11545 if ((err = wlu_var_getbuf(wl, cmdname, &retry_limit,
11546 sizeof(retry_limit), &ptr)) < 0)
11547 return err;
11548 reply = (struct ampdu_retry_tid *)ptr;
11549 printf("AMPDU regular rate retry limit for tid %d: %d\n", tid, reply->retry);
11551 return err;
11555 static int
11556 wl_ampdu_send_addba(void *wl, cmd_t *cmd, char **argv)
11558 char *param;
11559 const char *cmdname = "ampdu_send_addba";
11560 struct ampdu_ea_tid aet;
11561 uint8 tid;
11563 UNUSED_PARAMETER(cmd);
11565 if ((param = *++argv) == NULL)
11566 return USAGE_ERROR;
11568 tid = atoi(param);
11569 if (tid > MAXPRIO)
11570 return USAGE_ERROR;
11571 aet.tid = tid;
11573 argv++;
11574 if (!*argv) {
11575 printf("error: missing address\n");
11576 return USAGE_ERROR;
11579 if (!wl_ether_atoe(*argv, &aet.ea)) {
11580 printf("error: could not parse MAC address %s\n", *argv);
11581 return -1;
11584 return wlu_var_setbuf(wl, cmdname, &aet, sizeof(aet));
11587 static int
11588 wl_ampdu_send_delba(void *wl, cmd_t *cmd, char **argv)
11590 char *param;
11591 const char *cmdname = "ampdu_send_delba";
11592 struct ampdu_ea_tid aet;
11593 uint8 tid;
11595 UNUSED_PARAMETER(cmd);
11597 if ((param = *++argv) == NULL)
11598 return USAGE_ERROR;
11600 tid = atoi(param);
11601 if (tid > MAXPRIO)
11602 return USAGE_ERROR;
11603 aet.tid = tid;
11605 argv++;
11606 if (!*argv) {
11607 printf("error: missing address\n");
11608 return USAGE_ERROR;
11611 if (!wl_ether_atoe(*argv, &aet.ea)) {
11612 printf("error: could not parse MAC address %s\n", *argv);
11613 return -1;
11616 return wlu_var_setbuf(wl, cmdname, &aet, sizeof(aet));
11619 static int
11620 wl_dpt_deny(void *wl, cmd_t *cmd, char **argv)
11622 const char *cmdname = "dpt_deny";
11623 dpt_iovar_t info;
11625 UNUSED_PARAMETER(cmd);
11627 if (!*++argv)
11628 return USAGE_ERROR;
11630 info.pad = 0;
11632 if (!strcmp("add", *argv))
11633 info.mode = DPT_DENY_LIST_ADD;
11634 else if (!strcmp("remove", *argv))
11635 info.mode = DPT_DENY_LIST_REMOVE;
11636 else {
11637 printf("error: invalid mode string\n");
11638 return USAGE_ERROR;
11641 argv++;
11642 if (!*argv) {
11643 printf("error: missing mode value\n");
11644 return USAGE_ERROR;
11647 if (!wl_ether_atoe(*argv, &info.ea)) {
11648 printf("error: could not parse MAC address %s\n", *argv);
11649 return -1;
11652 return wlu_var_setbuf(wl, cmdname, &info, sizeof(info));
11655 static int
11656 wl_dpt_endpoint(void *wl, cmd_t *cmd, char **argv)
11658 const char *cmdname = "dpt_endpoint";
11659 dpt_iovar_t info;
11661 UNUSED_PARAMETER(cmd);
11663 if (!*++argv)
11664 return USAGE_ERROR;
11666 info.pad = 0;
11668 if (!strcmp("create", *argv))
11669 info.mode = DPT_MANUAL_EP_CREATE;
11670 else if (!strcmp("modify", *argv))
11671 info.mode = DPT_MANUAL_EP_MODIFY;
11672 else if (!strcmp("delete", *argv))
11673 info.mode = DPT_MANUAL_EP_DELETE;
11674 else {
11675 printf("error: invalid mode string\n");
11676 return USAGE_ERROR;
11679 argv++;
11680 if (!*argv) {
11681 printf("error: missing ea\n");
11682 return USAGE_ERROR;
11685 if (!wl_ether_atoe(*argv, &info.ea)) {
11686 printf("error: could not parse MAC address %s\n", *argv);
11687 return -1;
11690 return wlu_var_setbuf(wl, cmdname, &info, sizeof(info));
11693 static int
11694 wl_actframe(void *wl, cmd_t *cmd, char **argv)
11696 wl_action_frame_t * action_frame;
11697 wl_af_params_t * af_params;
11698 struct ether_addr ea;
11699 int argc;
11700 int err = 0;
11702 UNUSED_PARAMETER(cmd);
11704 if (!argv[1] || !argv[2]) {
11705 fprintf(stderr, "Too few arguments\n");
11706 return -1;
11709 /* arg count */
11710 for (argc = 0; argv[argc]; argc++)
11713 if ((af_params = (wl_af_params_t *) malloc(WL_WIFI_AF_PARAMS_SIZE)) == NULL) {
11714 printf("wl_actframe: unable to allocate frame \n");
11715 return -1;
11717 af_params->channel = 0;
11718 af_params->dwell_time = -1;
11719 action_frame = &af_params->action_frame;
11721 /* Add the packet Id */
11722 action_frame->packetId = (uint32)(uintptr)action_frame;
11724 /* convert the ea string into an ea struct */
11725 if (!wl_ether_atoe(argv[1], &ea)) {
11726 free(action_frame);
11727 printf(" ERROR: no valid ether addr provided\n");
11728 return -1;
11730 memcpy(&action_frame->da, (char*)&ea, ETHER_ADDR_LEN);
11731 /* set default BSSID */
11732 memcpy(&af_params->BSSID, (char*)&ea, ETHER_ADDR_LEN);
11734 /* add the length */
11735 if (argv[2]) {
11736 action_frame->len = htod16(strlen(argv[2])) / 2;
11739 /* add the channel */
11740 if (argc > 3 && argv[3]) {
11741 af_params->channel = htod32(atoi(argv[3]));
11744 /* add the dwell_time */
11745 if (argc > 4 && argv[4]) {
11746 af_params->dwell_time = htod32(atoi(argv[4]));
11749 /* add the BSSID */
11750 if (argc > 5 && argv[5]) {
11751 if (!wl_ether_atoe(argv[5], &ea)) {
11752 free(action_frame);
11753 printf(" ERROR: no valid ether addr provided\n");
11754 return -1;
11756 memcpy(&af_params->BSSID, (char*)&ea, ETHER_ADDR_LEN);
11759 if ((err = get_ie_data ((uchar *)argv[2],
11760 &action_frame->data[0],
11761 action_frame->len))) {
11762 free(af_params);
11763 fprintf(stderr, "Error parsing data arg\n");
11764 return err;
11766 err = wlu_var_setbuf(wl, "actframe", af_params, WL_WIFI_AF_PARAMS_SIZE);
11768 free(af_params);
11770 return (err);
11774 static int
11775 wl_dpt_pmk(void *wl, cmd_t *cmd, char **argv)
11777 const char *cmdname = "dpt_pmk";
11778 wsec_pmk_t psk;
11779 size_t key_len;
11781 UNUSED_PARAMETER(cmd);
11783 if (!*++argv)
11784 return USAGE_ERROR;
11786 key_len = strlen(*argv);
11787 if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
11788 fprintf(stderr, "passphrase must be between %d and %d characters long\n",
11789 WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN);
11790 return -1;
11792 psk.key_len = htod16((ushort) key_len);
11793 psk.flags = htod16(WSEC_PASSPHRASE);
11794 memcpy(psk.key, *argv, key_len);
11796 return wlu_var_setbuf(wl, cmdname, &psk, sizeof(wsec_pmk_t));
11799 static int
11800 wl_dpt_fname(void *wl, cmd_t *cmd, char **argv)
11802 char *param;
11803 const char *cmdname = "dpt_fname";
11804 int err;
11805 dpt_fname_t fname, *reply;
11806 void *ptr = NULL;
11808 UNUSED_PARAMETER(cmd);
11810 if ((param = *++argv)) {
11811 fname.len = strlen(param);
11812 if (fname.len >= (DPT_FNAME_LEN - 1)) {
11813 fprintf(stderr, "Name must be less than 32 characters\n");
11814 return -1;
11816 memcpy(fname.name, param, fname.len);
11817 fname.name[fname.len] = '\0';
11818 err = wlu_var_setbuf(wl, cmdname, &fname, sizeof(fname));
11819 } else {
11820 if ((err = wlu_var_getbuf(wl, cmdname, &fname, sizeof(fname), &ptr) < 0))
11821 return err;
11822 reply = (dpt_fname_t *)ptr;
11823 printf("%s\n", reply->name);
11825 return err;
11828 static int
11829 wl_dpt_list(void *wl, cmd_t *cmd, char **argv)
11831 int err;
11832 uint32 i;
11833 dpt_list_t *list;
11835 if (*++argv)
11836 return USAGE_ERROR;
11838 strcpy(buf, cmd->name);
11839 if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)))
11840 return err;
11842 list = (dpt_list_t *) buf;
11844 printf("List of DPT connections:\n");
11845 for (i = 0; i < list->num; i++) {
11846 printf("%s: status 0x%x rx %d tx %d rssi %d\n",
11847 list->status[i].name,
11848 list->status[i].status,
11849 list->status[i].sta.rx_ucast_pkts,
11850 list->status[i].sta.tx_pkts,
11851 list->status[i].rssi);
11853 return err;
11856 #ifdef WLBTAMP
11857 #define MATCH_OP(op, opstr) (strlen(op) == strlen(opstr) && strncmp(op, opstr, strlen(op)) == 0)
11859 static int
11860 wl_HCI_cmd(void *wl, cmd_t *cmd, char **argv)
11862 union {
11863 char buf[HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE];
11864 uint32 alignme;
11865 } cbuf;
11866 amp_hci_cmd_t *cpkt = (amp_hci_cmd_t *)&cbuf.buf[0];
11867 char *op;
11868 uint8 plen;
11870 UNUSED_PARAMETER(cmd);
11872 if (!*++argv)
11873 return USAGE_ERROR;
11875 /* recognize and encode operations */
11876 op = *argv++;
11877 if (MATCH_OP(op, "Read_Link_Quality")) {
11878 cpkt->opcode = HCI_Read_Link_Quality;
11879 } else if (MATCH_OP(op, "Read_Local_AMP_Info")) {
11880 cpkt->opcode = HCI_Read_Local_AMP_Info;
11881 } else if (MATCH_OP(op, "Read_Local_AMP_ASSOC")) {
11882 cpkt->opcode = HCI_Read_Local_AMP_ASSOC;
11883 } else if (MATCH_OP(op, "Write_Remote_AMP_ASSOC")) {
11884 cpkt->opcode = HCI_Write_Remote_AMP_ASSOC;
11885 } else if (MATCH_OP(op, "Create_Physical_Link")) {
11886 cpkt->opcode = HCI_Create_Physical_Link;
11887 } else if (MATCH_OP(op, "Accept_Physical_Link_Request")) {
11888 cpkt->opcode = HCI_Accept_Physical_Link_Request;
11889 } else if (MATCH_OP(op, "Disconnect_Physical_Link")) {
11890 cpkt->opcode = HCI_Disconnect_Physical_Link;
11891 } else if (MATCH_OP(op, "Create_Logical_Link")) {
11892 cpkt->opcode = HCI_Create_Logical_Link;
11893 } else if (MATCH_OP(op, "Accept_Logical_Link")) {
11894 cpkt->opcode = HCI_Accept_Logical_Link;
11895 } else if (MATCH_OP(op, "Disconnect_Logical_Link")) {
11896 cpkt->opcode = HCI_Disconnect_Logical_Link;
11897 } else if (MATCH_OP(op, "Logical_Link_Cancel")) {
11898 cpkt->opcode = HCI_Logical_Link_Cancel;
11899 } else if (MATCH_OP(op, "Short_Range_Mode")) {
11900 cpkt->opcode = HCI_Short_Range_Mode;
11901 } else if (MATCH_OP(op, "Read_Connection_Accept_Timeout")) {
11902 cpkt->opcode = HCI_Read_Connection_Accept_Timeout;
11903 } else if (MATCH_OP(op, "Write_Connection_Accept_Timeout")) {
11904 cpkt->opcode = HCI_Write_Connection_Accept_Timeout;
11905 } else if (MATCH_OP(op, "Read_Link_Supervision_Timeout")) {
11906 cpkt->opcode = HCI_Read_Link_Supervision_Timeout;
11907 } else if (MATCH_OP(op, "Write_Link_Supervision_Timeout")) {
11908 cpkt->opcode = HCI_Write_Link_Supervision_Timeout;
11909 } else if (MATCH_OP(op, "Reset")) {
11910 cpkt->opcode = HCI_Reset;
11911 } else if (MATCH_OP(op, "Enhanced_Flush")) {
11912 cpkt->opcode = HCI_Enhanced_Flush;
11913 } else if (MATCH_OP(op, "Read_Best_Effort_Flush_Timeout")) {
11914 cpkt->opcode = HCI_Read_Best_Effort_Flush_Timeout;
11915 } else if (MATCH_OP(op, "Write_Best_Effort_Flush_Timeout")) {
11916 cpkt->opcode = HCI_Write_Best_Effort_Flush_Timeout;
11917 } else if (MATCH_OP(op, "Read_Logical_Link_Accept_Timeout")) {
11918 cpkt->opcode = HCI_Read_Logical_Link_Accept_Timeout;
11919 } else if (MATCH_OP(op, "Write_Logical_Link_Accept_Timeout")) {
11920 cpkt->opcode = HCI_Write_Logical_Link_Accept_Timeout;
11921 } else if (MATCH_OP(op, "Read_Buffer_Size")) {
11922 cpkt->opcode = HCI_Read_Buffer_Size;
11923 } else if (MATCH_OP(op, "Read_Data_Block_Size")) {
11924 cpkt->opcode = HCI_Read_Data_Block_Size;
11925 } else if (MATCH_OP(op, "Set_Event_Mask_Page_2")) {
11926 cpkt->opcode = HCI_Set_Event_Mask_Page_2;
11927 } else if (MATCH_OP(op, "Flow_Spec_Modify")) {
11928 cpkt->opcode = HCI_Flow_Spec_Modify;
11929 } else if (MATCH_OP(op, "Read_Local_Version_Info")) {
11930 cpkt->opcode = HCI_Read_Local_Version_Info;
11931 } else if (MATCH_OP(op, "Read_Local_Supported_Commands")) {
11932 cpkt->opcode = HCI_Read_Local_Supported_Commands;
11933 } else if (MATCH_OP(op, "Read_Failed_Contact_Counter")) {
11934 cpkt->opcode = HCI_Read_Failed_Contact_Counter;
11935 } else if (MATCH_OP(op, "Reset_Failed_Contact_Counter")) {
11936 cpkt->opcode = HCI_Reset_Failed_Contact_Counter;
11937 } else {
11938 printf("unsupported HCI command: %s\n", op);
11939 return (-1);
11942 plen = 0;
11943 while (*argv && (plen < HCI_CMD_DATA_SIZE)) {
11944 cpkt->parms[plen++] = (uint8)strtol(*argv++, NULL, 0);
11946 cpkt->plen = plen;
11948 return wlu_var_setbuf(wl, cmd->name, cpkt, HCI_CMD_PREAMBLE_SIZE + plen);
11951 static int
11952 wl_HCI_ACL_data(void *wl, cmd_t *cmd, char **argv)
11954 /* Align struct. Also declare static so that large array isn't allocated
11955 * from the stack.
11957 static union {
11958 uint8 buf[HCI_ACL_DATA_PREAMBLE_SIZE + 2048];
11959 uint32 alignme;
11960 } g_wlu_hci_dbuf;
11962 amp_hci_ACL_data_t *dpkt = (amp_hci_ACL_data_t *)&g_wlu_hci_dbuf.buf[0];
11963 uint16 dlen;
11965 if (!*++argv)
11966 return USAGE_ERROR;
11968 /* get logical link handle */
11969 dpkt->handle = (HCI_ACL_DATA_BC_FLAGS | HCI_ACL_DATA_PB_FLAGS);
11970 dpkt->handle |= (uint16)strtol(*argv++, NULL, 0);
11972 /* get data */
11973 dlen = 0;
11974 while (*argv && (dlen < 2048)) {
11975 dpkt->data[dlen++] = (uint8)strtol(*argv++, NULL, 0);
11977 dpkt->dlen = dlen;
11979 return wlu_var_setbuf(wl, cmd->name, dpkt, HCI_ACL_DATA_PREAMBLE_SIZE + dlen);
11982 static int
11983 wl_get_btamp_log(void *wl, cmd_t *cmd, char **argv)
11985 int err, i, j;
11986 char *val_name;
11987 uint8 *state;
11988 uint8 idx = 0;
11989 void *ptr = buf;
11991 UNUSED_PARAMETER(cmd);
11993 /* command name */
11994 val_name = *argv++;
11996 if (!*argv) {
11997 if ((err = wlu_var_getbuf_sm (wl, cmd->name, NULL, 0, &ptr)))
11998 return err;
11999 state = (uint8 *)ptr;
12000 idx = *state++;
12002 for (i = 0; i < BTA_STATE_LOG_SZ; i++, idx--) {
12003 j = (idx & (BTA_STATE_LOG_SZ - 1));
12004 switch (state[j]) {
12005 case HCIReset:
12006 printf("%2d: HCI Reset\n", state[j]);
12007 break;
12008 case HCIReadLocalAMPInfo:
12009 printf("%2d: HCI Read Local AMPInfo\n", state[j]);
12010 break;
12011 case HCIReadLocalAMPASSOC:
12012 printf("%2d: HCI Read Local AMPASSOC\n", state[j]);
12013 break;
12014 case HCIWriteRemoteAMPASSOC:
12015 printf("%2d: HCI Write Remote AMPASSOC\n", state[j]);
12016 break;
12017 case HCICreatePhysicalLink:
12018 printf("%2d: HCI Create Physical Link\n", state[j]);
12019 break;
12020 case HCIAcceptPhysicalLinkRequest:
12021 printf("%2d: HCI Accept Physical Link Request\n", state[j]);
12022 break;
12023 case HCIDisconnectPhysicalLink:
12024 printf("%2d: HCI Disconnect Physical Link\n", state[j]);
12025 break;
12026 case HCICreateLogicalLink:
12027 printf("%2d: HCI Create Logical Link\n", state[j]);
12028 break;
12029 case HCIAcceptLogicalLink:
12030 printf("%2d: HCI Accept Logical Link\n", state[j]);
12031 break;
12032 case HCIDisconnectLogicalLink:
12033 printf("%2d: HCI Disconnect Logical Link\n", state[j]);
12034 break;
12035 case HCILogicalLinkCancel:
12036 printf("%2d: HCI Logical Link Cancel\n", state[j]);
12037 break;
12038 case HCIAmpStateChange:
12039 printf("%2d: HCI Amp State Change\n", state[j]);
12040 break;
12041 default:
12042 break;
12045 return 0;
12046 } else
12047 err = wlu_iovar_setint(wl, val_name, (int)idx);
12049 return err;
12051 #endif /* WLBTAMP */
12054 * RADAR detection parameter control
12056 static int
12057 wl_radar_args(void *wl, cmd_t *cmd, char **argv)
12059 int ret;
12060 wl_radar_args_t ra;
12062 /* Skip the command name */
12063 argv++;
12065 if (*argv == NULL) {
12066 /* Get */
12068 if ((ret = wlu_iovar_get(wl, cmd->name, &ra, sizeof(ra))) < 0)
12069 return ret;
12071 if (ra.version != WL_RADAR_ARGS_VERSION) {
12072 printf("\tIncorrect version of RADAR_ARGS struct: expected %d; got %d\n",
12073 WL_RADAR_ARGS_VERSION, ra.version);
12074 return -1;
12076 printf("version %d npulses %d ncontig %d min_pw %d max_pw %d thresh0 0x%x "
12077 "thresh1 0x%x\n",
12078 ra.version, ra.npulses, ra.ncontig, ra.min_pw,
12079 ra.max_pw, ra.thresh0, ra.thresh1);
12080 printf("blank 0x%x fmdemodcfg 0x%x npulses_lp %d min_pw_lp %d "
12081 "max_pw_lp %d\n",
12082 ra.blank, ra.fmdemodcfg, ra.npulses_lp, ra.min_pw_lp,
12083 ra.max_pw_lp);
12084 printf("min_fm_lp %d max_span_lp %d min_deltat %d max_deltat %d\n",
12085 ra.min_fm_lp, ra.max_span_lp, ra.min_deltat, ra.max_deltat);
12087 printf("autocorr 0x%x st_level_time 0x%x t2_min %d fra_pulse_err %d\n",
12088 ra.autocorr, ra.st_level_time, ra.t2_min, ra.fra_pulse_err);
12089 printf("npulses_fra %d npulses_stg2 %d npulses_stg3 %d percal_mask 0x%x quant %d\n",
12090 ra.npulses_fra, ra.npulses_stg2, ra.npulses_stg3, ra.percal_mask,
12091 ra.quant);
12092 printf("min_burst_intv_lp %d max_burst_intv_lp %d nskip_rst_lp %d max_pw_tol %d "
12093 "feature_mask 0x%x\n",
12094 ra.min_burst_intv_lp, ra.max_burst_intv_lp, ra.nskip_rst_lp,
12095 ra.max_pw_tol, ra.feature_mask);
12096 } else {
12097 /* Set */
12098 char *endptr = NULL;
12099 int val_count = 30;
12100 long vals[30];
12101 long *pval;
12102 int i;
12104 for (i = 0; i < val_count; i++, argv++) {
12105 /* verify that there is another arg */
12106 if (*argv == NULL)
12107 return -1;
12109 vals[i] = strtol(*argv, &endptr, 0);
12111 /* make sure all the value string was parsed by strtol */
12112 if (*endptr != '\0')
12113 return -1;
12116 pval = vals;
12118 ra.version = *pval++;
12119 ra.npulses = *pval++;
12120 ra.ncontig = *pval++;
12121 ra.min_pw = *pval++;
12122 ra.max_pw = *pval++;
12123 ra.thresh0 = (uint16)*pval++;
12124 ra.thresh1 = (uint16)*pval++;
12125 ra.blank = (uint16)*pval++;
12126 ra.fmdemodcfg = (uint16)*pval++;
12127 ra.npulses_lp = *pval++;
12128 ra.min_pw_lp = *pval++;
12129 ra.max_pw_lp = *pval++;
12130 ra.min_fm_lp = *pval++;
12131 ra.max_span_lp = *pval++;
12132 ra.min_deltat = *pval++;
12133 ra.max_deltat = *pval++;
12134 ra.autocorr = (uint16)*pval++;
12135 ra.st_level_time = (uint16)*pval++;
12136 ra.t2_min = (uint16)*pval++;
12137 ra.fra_pulse_err = (uint32)*pval++;
12138 ra.npulses_fra = (int)*pval++;
12139 ra.npulses_stg2 = (int)*pval++;
12140 ra.npulses_stg3 = (int)*pval++;
12141 ra.percal_mask = (int)*pval++;
12142 ra.quant = (int)*pval++;
12143 ra.min_burst_intv_lp = (uint32)*pval++;
12144 ra.max_burst_intv_lp = (uint32)*pval++;
12145 ra.nskip_rst_lp = (int)*pval++;
12146 ra.max_pw_tol = (int)*pval++;
12147 ra.feature_mask = (uint16)*pval++;
12149 return wlu_var_setbuf(wl, cmd->name, &ra, sizeof(wl_radar_args_t));
12151 return ret;
12154 static int
12155 wl_radar_thrs(void *wl, cmd_t *cmd, char **argv)
12157 int ret = -1;
12158 wl_radar_thr_t radar_thrs;
12160 if (*++argv) {
12161 /* Set */
12162 char *endptr;
12163 int val_count = 8;
12164 uint16 vals[8];
12165 uint16 *pval;
12166 int i;
12168 for (i = 0; i < val_count; i++, argv++) {
12169 /* verify that there is another arg */
12170 if (*argv == NULL)
12171 return -1;
12173 vals[i] = (uint16)strtol(*argv, &endptr, 0);
12175 /* make sure all the value string was parsed by strtol */
12176 if (*endptr != '\0')
12177 return -1;
12180 radar_thrs.version = WL_RADAR_THR_VERSION;
12182 /* Order thresh0_20_lo, thresh1_20_lo, thresh0_40_lo, thresh1_40_lo
12183 * thresh0_20_hi, thresh1_20_hi, thresh0_40_hi, thresh1_40_hi
12185 pval = vals;
12186 radar_thrs.thresh0_20_lo = (uint16)*pval++;
12187 radar_thrs.thresh1_20_lo = (uint16)*pval++;
12188 radar_thrs.thresh0_40_lo = (uint16)*pval++;
12189 radar_thrs.thresh1_40_lo = (uint16)*pval++;
12190 radar_thrs.thresh0_20_hi = (uint16)*pval++;
12191 radar_thrs.thresh1_20_hi = (uint16)*pval++;
12192 radar_thrs.thresh0_40_hi = (uint16)*pval++;
12193 radar_thrs.thresh1_40_hi = (uint16)*pval++;
12195 return wlu_var_setbuf(wl, cmd->name, &radar_thrs, sizeof(wl_radar_thr_t));
12197 return ret;
12200 static int
12201 wl_dfs_status(void *wl, cmd_t *cmd, char **argv)
12203 int ret;
12204 wl_dfs_status_t *dfs_status_ptr;
12206 const char *dfs_cacstate_str[WL_DFS_CACSTATES] = {
12207 "IDLE",
12208 "PRE-ISM Channel Availability Check(CAC)",
12209 "In-Service Monitoring(ISM)",
12210 "Channel Switching Announcement(CSA)",
12211 "POST-ISM Channel Availability Check",
12212 "PRE-ISM Ouf Of Channels(OOC)",
12213 "POST-ISM Out Of Channels(OOC)"
12216 void *ptr;
12218 UNUSED_PARAMETER(argv);
12220 if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
12221 return ret;
12223 dfs_status_ptr = (wl_dfs_status_t *)ptr;
12225 dfs_status_ptr->state = dtoh32(dfs_status_ptr->state);
12226 dfs_status_ptr->duration = dtoh32(dfs_status_ptr->duration);
12227 dfs_status_ptr->chanspec_cleared = dtohchanspec(dfs_status_ptr->chanspec_cleared);
12229 if (dfs_status_ptr->state >= WL_DFS_CACSTATES) {
12230 printf("Unknown dfs state %d.\n", dfs_status_ptr->state);
12231 return -1;
12234 printf("state %s time elapsed %dms radar channel cleared by dfs ",
12235 dfs_cacstate_str[dfs_status_ptr->state], dfs_status_ptr->duration);
12237 if (dfs_status_ptr->chanspec_cleared) {
12238 printf("channel spec %d channel %d\n", dfs_status_ptr->chanspec_cleared,
12239 CHSPEC_CHANNEL(dfs_status_ptr->chanspec_cleared));
12241 else {
12242 printf("none\n");
12245 return ret;
12248 static int
12249 wl_wds_wpa_role_old(void *wl, cmd_t *cmd, char **argv)
12251 uint remote[2];
12252 uint *sup = remote;
12254 UNUSED_PARAMETER(argv);
12256 if (wlu_get(wl, WLC_WDS_GET_REMOTE_HWADDR, remote, sizeof(remote)) < 0) {
12257 printf("Unable to get remote endpoint's hwaddr\n");
12258 return -1;
12260 if (wlu_get(wl, cmd->get, remote, sizeof(remote)) < 0) {
12261 printf("Unable to get local endpoint's WPA role\n");
12262 return -1;
12264 printf("Local endpoing's WPA role: %s\n", dtoh32(*sup) ? "supplicant" : "authenticator");
12265 return 0;
12270 * wlu_reg2args is a generic function that is used for setting/getting
12271 * WL_IOVAR variables that require address for read, and
12272 * address + data for write.
12274 static int
12275 wlu_reg2args(void *wl, cmd_t *cmd, char **argv)
12277 char var[256];
12278 uint32 int_val;
12279 bool get = TRUE;
12280 uint32 len;
12281 void *ptr = NULL;
12282 char *endptr;
12284 if (argv[1]) {
12285 len = sizeof(int_val);
12286 int_val = htod32(strtoul(argv[1], &endptr, 0));
12287 memcpy(var, (char *)&int_val, sizeof(int_val));
12289 else
12290 return -1;
12292 if (argv[2]) {
12293 get = FALSE;
12294 int_val = htod32(strtoul(argv[2], &endptr, 0));
12295 memcpy(&var[len], (char *)&int_val, sizeof(int_val));
12296 len += sizeof(int_val);
12298 if (get) {
12299 if (wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr) < 0)
12300 return -1;
12302 printf("0x%x\n", dtoh32(*(int *)ptr));
12304 else
12305 wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
12306 return 0;
12310 * wlu_reg3args is a generic function that is used for setting/getting
12311 * WL_IOVAR variables that require address + offset for read, and
12312 * address + offset + data for write.
12314 static int
12315 wlu_reg3args(void *wl, cmd_t *cmd, char **argv)
12317 char var[256];
12318 uint32 int_val;
12319 bool get = TRUE;
12320 uint32 len, i;
12321 void *ptr = NULL;
12322 char *endptr;
12323 uint numargs;
12325 len = 0;
12327 if (!argv[1] || !argv[2]) {
12328 printf("Wrong syntax => dev offset [val]\n");
12329 return -1;
12332 if (argv[3]) {
12333 numargs = 3;
12334 get = FALSE;
12335 } else
12336 numargs = 2;
12338 for (i = 1; i <= numargs; i++) {
12339 int_val = htod32(strtoul(argv[i], &endptr, 0));
12340 memcpy(&var[len], (char *)&int_val, sizeof(int_val));
12341 len += sizeof(int_val);
12344 if (get) {
12345 if (wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr) < 0)
12346 return -1;
12348 printf("0x%x\n", dtoh32(*(int *)ptr));
12350 else
12351 wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
12352 return 0;
12355 static int
12356 wl_coma(void *wl, cmd_t *cmd, char **argv)
12358 char var[256];
12359 uint32 int_val;
12360 uint32 len, i;
12361 char *endptr;
12362 uint numargs;
12363 int err = 0;
12365 len = 0;
12367 if (!argv[1]) {
12368 printf("Wrong syntax => coma [reset-time] [delay]\n");
12369 return -1;
12372 if (!argv[2]) {
12373 numargs = 1;
12374 } else if (!argv[3]) {
12375 numargs = 2;
12376 } else {
12377 numargs = 3;
12380 for (i = 1; i <= numargs; i++) {
12381 int_val = htod32(strtoul(argv[i], &endptr, 0));
12382 memcpy(&var[len], (char *)&int_val, sizeof(int_val));
12383 len += sizeof(int_val);
12386 err = wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
12388 return err;
12391 static int
12392 wl_tpc_lm(void *wl, cmd_t *cmd, char **argv)
12394 int ret;
12395 uint16 val;
12396 int v;
12397 int8 aplm, stalm;
12399 UNUSED_PARAMETER(argv);
12401 if ((ret = wlu_iovar_getint(wl, cmd->name, (&v))) < 0)
12402 return ret;
12404 val = (uint16)v;
12405 stalm = val & 0xff;
12406 aplm = (val >> 8) & 0xff;
12408 printf("TPC: APs link margin:%d\t STAs link margin:%d\n", aplm, stalm);
12410 return 0;
12414 static int
12415 wl_wds_wpa_role(void *wl, cmd_t *cmd, char **argv)
12417 char var[256];
12418 char *mac;
12419 char *sup;
12420 int len;
12421 if (strlen("wds_wpa_role") + 1 + ETHER_ADDR_LEN + 1 > sizeof(var))
12422 return -1;
12423 /* build var required by WLC_GET|SET_VAR */
12424 len = sprintf(var, "%s", "wds_wpa_role") + 1;
12425 mac = var + len;
12426 if (wlu_get(wl, WLC_WDS_GET_REMOTE_HWADDR, mac, ETHER_ADDR_LEN) < 0) {
12427 printf("Unable to get remote endpoint's hwaddr\n");
12428 return -1;
12430 len += ETHER_ADDR_LEN + 1;
12431 if (argv[1]) {
12432 sup = mac + ETHER_ADDR_LEN;
12433 switch ((uchar)(*sup = atoi(argv[1]))) {
12434 case WL_WDS_WPA_ROLE_AUTH:
12435 case WL_WDS_WPA_ROLE_SUP:
12436 case WL_WDS_WPA_ROLE_AUTO:
12437 if (wlu_set(wl, cmd->set, var, len) < 0)
12438 printf("Unable to set local endpoint's WPA role\n");
12439 break;
12440 default:
12441 printf("Invalid WPA role %s. %u:authenticator, %u:supplicant, %u:auto\n",
12442 argv[1], WL_WDS_WPA_ROLE_AUTH,
12443 WL_WDS_WPA_ROLE_SUP, WL_WDS_WPA_ROLE_AUTO);
12444 break;
12447 else if (wlu_get(wl, cmd->get, var, len) < 0) {
12448 printf("Unable to get local endpoint's WPA role\n");
12449 return -1;
12451 else {
12452 sup = var;
12453 printf("Local endpoint's WPA role: %s\n", *sup ? "supplicant" : "authenticator");
12455 return 0;
12458 static int
12459 wl_measure_req(void *wl, cmd_t *cmd, char **argv)
12461 uint32 val;
12462 struct ether_addr ea;
12464 if (!*++argv) {
12465 printf("error: missing arguments\n");
12466 return -1;
12469 if (!stricmp(*argv, "tpc"))
12470 val = WLC_MEASURE_TPC;
12471 else if (!stricmp(*argv, "basic"))
12472 val = WLC_MEASURE_CHANNEL_BASIC;
12473 else if (!stricmp(*argv, "cca"))
12474 val = WLC_MEASURE_CHANNEL_CCA;
12475 else if (!stricmp(*argv, "rpi"))
12476 val = WLC_MEASURE_CHANNEL_RPI;
12477 else {
12478 printf("error: unknown measurement type %s\n", *argv);
12479 return -1;
12481 argv++;
12483 if (!*argv) {
12484 printf("error: missing target address\n");
12485 return -1;
12488 if (!wl_ether_atoe(*argv, &ea)) {
12489 printf("error: could not parse MAC address %s\n", *argv);
12490 return -1;
12493 val = htod32(val);
12494 memcpy(&buf[0], &val, sizeof(uint32));
12495 memcpy(&buf[4], ea.octet, ETHER_ADDR_LEN);
12497 return wlu_set(wl, cmd->set, buf, sizeof(uint32) + ETHER_ADDR_LEN);
12500 static int
12501 wl_send_quiet(void *wl, cmd_t *cmd, char **argv)
12503 dot11_quiet_t quiet;
12505 if (!*++argv) {
12506 printf("error: missing arguments\n");
12507 return -1;
12509 /* Order is count, duration, offset */
12510 quiet.count = atoi(*argv);
12511 if (!*++argv) {
12512 printf("error: missing arguments\n");
12513 return -1;
12515 quiet.duration = atoi(*argv);
12516 if (!*++argv) {
12517 printf("error: missing arguments\n");
12518 return -1;
12520 quiet.offset = atoi(*argv);
12521 quiet.period = 0;
12523 quiet.duration = htod16(quiet.duration);
12524 quiet.offset = htod16(quiet.offset);
12525 return (wlu_set(wl, cmd->set, &quiet, sizeof(quiet)));
12528 static int
12529 wl_send_csa(void *wl, cmd_t *cmd, char **argv)
12531 int err;
12532 wl_chan_switch_t csa_arg;
12534 /* Order is mode, count channel */
12535 if (!*++argv) {
12536 printf("error: missing arguments\n");
12537 return -1;
12539 csa_arg.mode = atoi(*argv) ? 1 : 0;
12540 if (!*++argv) {
12541 printf("error: missing count\n");
12542 return -1;
12544 csa_arg.count = atoi(*argv);
12545 if (!*++argv) {
12546 printf("error: missing channel\n");
12547 return -1;
12550 if ((csa_arg.chspec = wf_chspec_aton(*argv))) {
12551 csa_arg.chspec = htodchanspec(csa_arg.chspec);
12552 err = wlu_var_setbuf(wl, cmd->name, &csa_arg, sizeof(csa_arg));
12553 } else {
12554 printf("Error: bad parameters \"%s\"\n", *argv);
12555 return -1;
12558 return err;
12561 static int
12562 wl_var_setint(void *wl, cmd_t *cmd, char **argv)
12564 int32 val;
12565 char *varname;
12566 char *endptr = NULL;
12568 UNUSED_PARAMETER(cmd);
12570 if (!*argv) {
12571 printf("set: missing arguments\n");
12572 return -1;
12575 varname = *argv++;
12577 if (!*argv) {
12578 printf("set: missing value argument for set of \"%s\"\n", varname);
12579 return -1;
12582 val = strtol(*argv, &endptr, 0);
12583 if (*endptr != '\0') {
12584 /* not all the value string was parsed by strtol */
12585 printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n",
12586 *argv, varname);
12587 return -1;
12590 return wlu_iovar_setint(wl, varname, val);
12593 static int
12594 wl_var_get(void *wl, cmd_t *cmd, char **argv)
12596 char *varname;
12597 char *p;
12599 UNUSED_PARAMETER(cmd);
12601 if (!*argv) {
12602 printf("get: missing arguments\n");
12603 return -1;
12606 varname = *argv++;
12608 if (*argv) {
12609 printf("get: error, extra arg \"%s\"\n", *argv);
12610 return -1;
12613 strcpy(buf, varname);
12614 p = buf;
12615 while (*p != '\0') {
12616 *p = tolower((int)*p);
12617 p++;
12619 return (wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN));
12622 static int
12623 wl_var_getinthex(void *wl, cmd_t *cmd, char **argv)
12625 int err;
12626 int32 val;
12628 if ((err = wl_var_get(wl, cmd, argv)))
12629 return (err);
12631 val = dtoh32(*(int32*)buf);
12633 printf("0x%08x\n", val);
12635 return 0;
12638 static int
12639 wl_var_getint(void *wl, cmd_t *cmd, char **argv)
12641 int err;
12642 int32 val;
12644 if ((err = wl_var_get(wl, cmd, argv)))
12645 return (err);
12647 val = dtoh32(*(int32*)buf);
12649 if (val < 10)
12650 printf("%d\n", val);
12651 else
12652 printf("%d (0x%x)\n", val, val);
12654 return (0);
12657 static int
12658 wl_var_getandprintstr(void *wl, cmd_t *cmd, char **argv)
12660 int err;
12662 if ((err = wl_var_get(wl, cmd, argv)))
12663 return (err);
12665 printf("%s\n", buf);
12666 return (0);
12669 /* Variation: Like getandprint, but allow an int arg to be passed */
12670 static int
12671 wl_var_setintandprintstr(void *wl, cmd_t *cmd, char **argv)
12673 int err;
12674 int32 val;
12675 char *varname;
12676 char *endptr = NULL;
12678 UNUSED_PARAMETER(cmd);
12680 if (!*argv) {
12681 printf("set: missing arguments\n");
12682 return -1;
12685 varname = *argv++;
12687 if (!*argv) {
12688 val = 0;
12689 } else {
12690 val = strtol(*argv, &endptr, 0);
12691 if (*endptr != '\0') {
12692 /* not all the value string was parsed by strtol */
12693 printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n",
12694 *argv, varname);
12695 return -1;
12699 val = htod32(val);
12700 err = wlu_iovar_getbuf(wl, varname, &val, sizeof(int), buf, WLC_IOCTL_MAXLEN);
12702 if (err)
12703 return (err);
12705 printf("%s\n", buf);
12706 return (0);
12709 void
12710 wl_printlasterror(void *wl)
12712 char error_str[128];
12714 if (wlu_iovar_get(wl, "bcmerrorstr", error_str, sizeof(error_str)) != 0) {
12715 fprintf(stderr, "%s: \nError getting the last error\n", wlu_av0);
12716 } else {
12717 fprintf(stderr, "%s: %s\n", wlu_av0, error_str);
12721 /* just issue a wl_var_setint() or a wl_var_getint() if there is a 2nd arg */
12723 wl_varint(void *wl, cmd_t *cmd, char *argv[])
12725 if (argv[1])
12726 return (wl_var_setint(wl, cmd, argv));
12727 else
12728 return (wl_var_getint(wl, cmd, argv));
12732 wlu_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr)
12734 int len;
12736 memset(buf, 0, WLC_IOCTL_MAXLEN);
12737 strcpy(buf, iovar);
12739 /* include the null */
12740 len = strlen(iovar) + 1;
12742 if (param_len)
12743 memcpy(&buf[len], param, param_len);
12745 *bufptr = buf;
12747 return wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN);
12750 /* get buffer for smaller sizes upto 256 bytes */
12752 wlu_var_getbuf_sm(void *wl, const char *iovar, void *param, int param_len, void **bufptr)
12754 int len;
12756 memset(buf, 0, WLC_IOCTL_SMLEN);
12757 strcpy(buf, iovar);
12759 /* include the null */
12760 len = strlen(iovar) + 1;
12762 if (param_len)
12763 memcpy(&buf[len], param, param_len);
12765 *bufptr = buf;
12767 return wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_SMLEN);
12770 /* Get buffer for medium sizes upto 1500 bytes */
12772 wlu_var_getbuf_med(void *wl, const char *iovar, void *param, int param_len, void **bufptr)
12774 int len;
12776 memset(buf, 0, WLC_IOCTL_MEDLEN);
12777 strcpy(buf, iovar);
12779 /* include the null */
12780 len = strlen(iovar) + 1;
12782 if (param_len)
12783 memcpy(&buf[len], param, param_len);
12785 *bufptr = buf;
12787 return wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MEDLEN);
12792 wlu_var_setbuf(void *wl, const char *iovar, void *param, int param_len)
12794 int len;
12796 memset(buf, 0, WLC_IOCTL_MAXLEN);
12797 strcpy(buf, iovar);
12799 /* include the null */
12800 len = strlen(iovar) + 1;
12802 if (param_len)
12803 memcpy(&buf[len], param, param_len);
12805 len += param_len;
12807 return wlu_set(wl, WLC_SET_VAR, &buf[0], len);
12810 static int
12811 wl_var_void(void *wl, cmd_t *cmd, char **argv)
12813 UNUSED_PARAMETER(argv);
12815 if (cmd->set < 0)
12816 return -1;
12818 return wlu_var_setbuf(wl, cmd->name, NULL, 0);
12822 * format an iovar buffer
12823 * iovar name is converted to lower case
12825 static uint
12826 wl_iovar_mkbuf(const char *name, char *data, uint datalen, char *iovar_buf, uint buflen, int *perr)
12828 uint iovar_len;
12829 char *p;
12831 iovar_len = strlen(name) + 1;
12833 /* check for overflow */
12834 if ((iovar_len + datalen) > buflen) {
12835 *perr = BCME_BUFTOOSHORT;
12836 return 0;
12839 /* copy data to the buffer past the end of the iovar name string */
12840 if (datalen > 0)
12841 memmove(&iovar_buf[iovar_len], data, datalen);
12843 /* copy the name to the beginning of the buffer */
12844 strcpy(iovar_buf, name);
12846 /* wl command line automatically converts iovar names to lower case for
12847 * ease of use
12849 p = iovar_buf;
12850 while (*p != '\0') {
12851 *p = tolower((int)*p);
12852 p++;
12855 *perr = 0;
12856 return (iovar_len + datalen);
12861 * get named iovar providing both parameter and i/o buffers
12862 * iovar name is converted to lower case
12864 static int
12865 wlu_iovar_getbuf(void* wl, const char *iovar,
12866 void *param, int paramlen, void *bufptr, int buflen)
12868 int err;
12870 wl_iovar_mkbuf(iovar, param, paramlen, bufptr, buflen, &err);
12871 if (err)
12872 return err;
12874 return wlu_get(wl, WLC_GET_VAR, bufptr, buflen);
12878 * set named iovar providing both parameter and i/o buffers
12879 * iovar name is converted to lower case
12881 static int
12882 wlu_iovar_setbuf(void* wl, const char *iovar,
12883 void *param, int paramlen, void *bufptr, int buflen)
12885 int err;
12886 int iolen;
12888 iolen = wl_iovar_mkbuf(iovar, param, paramlen, bufptr, buflen, &err);
12889 if (err)
12890 return err;
12892 return wlu_set(wl, WLC_SET_VAR, bufptr, iolen);
12896 * get named iovar without parameters into a given buffer
12897 * iovar name is converted to lower case
12900 wlu_iovar_get(void *wl, const char *iovar, void *outbuf, int len)
12902 char smbuf[WLC_IOCTL_SMLEN];
12903 int err;
12905 /* use the return buffer if it is bigger than what we have on the stack */
12906 if (len > (int)sizeof(smbuf)) {
12907 err = wlu_iovar_getbuf(wl, iovar, NULL, 0, outbuf, len);
12908 } else {
12909 memset(smbuf, 0, sizeof(smbuf));
12910 err = wlu_iovar_getbuf(wl, iovar, NULL, 0, smbuf, sizeof(smbuf));
12911 if (err == 0)
12912 memcpy(outbuf, smbuf, len);
12915 return err;
12919 * set named iovar given the parameter buffer
12920 * iovar name is converted to lower case
12923 wlu_iovar_set(void *wl, const char *iovar, void *param, int paramlen)
12925 char smbuf[WLC_IOCTL_SMLEN*2];
12927 memset(smbuf, 0, sizeof(smbuf));
12929 return wlu_iovar_setbuf(wl, iovar, param, paramlen, smbuf, sizeof(smbuf));
12933 * get named iovar as an integer value
12934 * iovar name is converted to lower case
12937 wlu_iovar_getint(void *wl, const char *iovar, int *pval)
12939 int ret;
12941 ret = wlu_iovar_get(wl, iovar, pval, sizeof(int));
12942 if (ret >= 0)
12944 *pval = dtoh32(*pval);
12946 return ret;
12950 * set named iovar given an integer parameter
12951 * iovar name is converted to lower case
12954 wlu_iovar_setint(void *wl, const char *iovar, int val)
12956 val = htod32(val);
12957 return wlu_iovar_set(wl, iovar, &val, sizeof(int));
12961 * format a bsscfg indexed iovar buffer
12963 static int
12964 wl_bssiovar_mkbuf(const char *iovar, int bssidx, void *param,
12965 int paramlen, void *bufptr, int buflen, int *perr)
12967 const char *prefix = "bsscfg:";
12968 int8* p;
12969 uint prefixlen;
12970 uint namelen;
12971 uint iolen;
12973 prefixlen = strlen(prefix); /* length of bsscfg prefix */
12974 namelen = strlen(iovar) + 1; /* length of iovar name + null */
12975 iolen = prefixlen + namelen + sizeof(int) + paramlen;
12977 /* check for overflow */
12978 if (buflen < 0 || iolen > (uint)buflen) {
12979 *perr = BCME_BUFTOOSHORT;
12980 return 0;
12983 p = (int8*)bufptr;
12985 /* copy prefix, no null */
12986 memcpy(p, prefix, prefixlen);
12987 p += prefixlen;
12989 /* copy iovar name including null */
12990 memcpy(p, iovar, namelen);
12991 p += namelen;
12993 /* bss config index as first param */
12994 bssidx = htod32(bssidx);
12995 memcpy(p, &bssidx, sizeof(int32));
12996 p += sizeof(int32);
12998 /* parameter buffer follows */
12999 if (paramlen)
13000 memcpy(p, param, paramlen);
13002 *perr = 0;
13003 return iolen;
13007 * set named & bss indexed driver iovar providing both parameter and i/o buffers
13009 static int
13010 wl_bssiovar_setbuf(void* wl, const char *iovar, int bssidx,
13011 void *param, int paramlen, void *bufptr, int buflen)
13013 int err;
13014 int iolen;
13016 iolen = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &err);
13017 if (err)
13018 return err;
13020 return wlu_set(wl, WLC_SET_VAR, bufptr, iolen);
13024 * get named & bss indexed driver iovar providing both parameter and i/o buffers
13026 static int
13027 wl_bssiovar_getbuf(void* wl, const char *iovar, int bssidx,
13028 void *param, int paramlen, void *bufptr, int buflen)
13030 int err;
13032 wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &err);
13033 if (err)
13034 return err;
13036 return wlu_get(wl, WLC_GET_VAR, bufptr, buflen);
13040 * get named & bss indexed driver variable to buffer value
13042 static int
13043 wl_bssiovar_get(void *wl, const char *iovar, int bssidx, void *outbuf, int len)
13045 char smbuf[WLC_IOCTL_SMLEN];
13046 int err;
13048 /* use the return buffer if it is bigger than what we have on the stack */
13049 if (len > (int)sizeof(smbuf)) {
13050 err = wl_bssiovar_getbuf(wl, iovar, bssidx, NULL, 0, outbuf, len);
13051 } else {
13052 memset(smbuf, 0, sizeof(smbuf));
13053 err = wl_bssiovar_getbuf(wl, iovar, bssidx, NULL, 0, smbuf, sizeof(smbuf));
13054 if (err == 0)
13055 memcpy(outbuf, smbuf, len);
13058 return err;
13062 * set named & bss indexed driver variable to buffer value
13064 static int
13065 wl_bssiovar_set(void *wl, const char *iovar, int bssidx, void *param, int paramlen)
13067 char smbuf[WLC_IOCTL_SMLEN];
13069 memset(smbuf, 0, sizeof(smbuf));
13071 return wl_bssiovar_setbuf(wl, iovar, bssidx, param, paramlen, smbuf, sizeof(smbuf));
13075 * get named & bsscfg indexed driver variable as an int value
13077 static int
13078 wl_bssiovar_getint(void *wl, const char *iovar, int bssidx, int *pval)
13080 int ret;
13082 ret = wl_bssiovar_get(wl, iovar, bssidx, pval, sizeof(int));
13083 if (ret == 0)
13085 *pval = dtoh32(*pval);
13087 return ret;
13091 * set named & bsscfg indexed driver variable to int value
13093 static int
13094 wl_bssiovar_setint(void *wl, const char *iovar, int bssidx, int val)
13096 val = htod32(val);
13097 return wl_bssiovar_set(wl, iovar, bssidx, &val, sizeof(int));
13100 static int
13101 wl_nvdump(void *wl, cmd_t *cmd, char **argv)
13103 int err;
13104 const char *iovar = "nvram_dump";
13105 void *p = NULL;
13107 UNUSED_PARAMETER(cmd);
13109 /* skip the "nvdump/nvram_dump" command name */
13110 argv++;
13112 if (*argv) {
13113 printf("nvdump error: extra arg \"%s\"\n", *argv);
13114 return -1;
13117 if ((err = wlu_var_getbuf(wl, iovar, NULL, 0, &p)) < 0) {
13118 if ((err = wlu_get(wl, WLC_NVRAM_DUMP, &buf[0], WLC_IOCTL_MAXLEN)))
13119 return err;
13120 p = (void *)buf;
13122 printf("%s\n", (char *)p);
13124 return err;
13127 static int
13128 wl_nvget(void *wl, cmd_t *cmd, char **argv)
13130 int err;
13131 char *varname;
13132 const char *iovar = "nvram_get";
13133 void *p;
13135 UNUSED_PARAMETER(cmd);
13137 /* skip the "nvget/nvram_get" command name */
13138 argv++;
13140 if (!*argv) {
13141 printf("nvget: missing arguments\n");
13142 return -1;
13145 varname = *argv++;
13147 if (*argv) {
13148 printf("nvget error: extra arg \"%s\"\n", *argv);
13149 return -1;
13152 if ((err = wlu_var_getbuf(wl, iovar, varname, strlen(varname) + 1, &p)) < 0) {
13154 strcpy(buf, varname);
13155 if ((err = wlu_get(wl, WLC_NVRAM_GET, &buf[0], WLC_IOCTL_MAXLEN)))
13156 return err;
13159 printf("%s\n", buf);
13161 return err;
13164 static int
13165 wl_nvset(void *wl, cmd_t *cmd, char **argv)
13167 char *varname;
13169 UNUSED_PARAMETER(cmd);
13171 /* skip the "nvset" command name if present */
13172 if (!strcmp("nvset", *argv))
13173 argv++;
13175 if (!*argv) {
13176 printf("nvset: missing arguments\n");
13177 return -1;
13180 varname = *argv++;
13182 if (*argv) {
13183 fprintf(stderr,
13184 "nvset error: extra arg \"%s\"; format is name=value (no spaces around '=')\n",
13185 *argv);
13186 return -1;
13189 if (!strchr(varname, '=')) {
13190 fprintf(stderr,
13191 "nvset error: no '=' in \"%s\", format is name=value (no spaces around '=')\n",
13192 *argv);
13193 return -1;
13196 strcpy(buf, varname);
13198 return (wlu_set(wl, WLC_NVRAM_SET, &buf[0], strlen(buf) + 1));
13201 static int
13202 wl_chan_info(void *wl, cmd_t *cmd, char **argv)
13204 uint bitmap;
13205 uint channel;
13206 int buflen, err, first, last, minutes;
13207 char *param;
13208 bool all;
13210 if (!*++argv) {
13211 first = 0;
13212 last = 255;
13213 all = TRUE;
13214 } else {
13215 last = first = atoi(*argv);
13216 if (last <= 0) {
13217 printf(" Usage: %s [channel | All ]\n", cmd->name);
13218 return -1;
13220 all = FALSE;
13223 for (; first <= last; first++) {
13224 channel = first & WL_CHANSPEC_CHAN_MASK;
13225 if (channel < 14)
13226 channel |= WL_CHANSPEC_BAND_2G;
13227 else
13228 channel |= WL_CHANSPEC_BAND_5G;
13230 strcpy(buf, "per_chan_info");
13231 buflen = strlen(buf) + 1;
13232 param = (char *)(buf + buflen);
13233 channel = htod32(channel);
13234 memcpy(param, (char*)&channel, sizeof(channel));
13236 if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)))
13237 return err;
13239 channel = dtoh32(channel);
13240 bitmap = dtoh32(*(uint *)buf);
13241 minutes = (bitmap >> 24) & 0xff;
13243 if (!(bitmap & WL_CHAN_VALID_HW)) {
13244 if (!all)
13245 printf("Invalid Channel\n");
13246 continue;
13249 if (!(bitmap & WL_CHAN_VALID_SW)) {
13250 if (!all)
13251 printf("Not supported in current locale\n");
13252 continue;
13255 printf("Channel %d\t", channel & WL_CHANSPEC_CHAN_MASK);
13257 if (bitmap & WL_CHAN_BAND_5G)
13258 printf("A Band");
13259 else
13260 printf("B Band");
13262 if (bitmap & WL_CHAN_RADAR) {
13263 printf(", RADAR Sensitive");
13265 if (bitmap & WL_CHAN_RESTRICTED) {
13266 printf(", Restricted");
13268 if (bitmap & WL_CHAN_PASSIVE) {
13269 printf(", Passive");
13271 if (bitmap & WL_CHAN_INACTIVE) {
13272 printf(", Temporarily Out of Service for %d minutes", minutes);
13274 printf("\n");
13277 return (0);
13280 static int
13281 wl_test_tssi(void *wl, cmd_t *cmd, char **argv)
13283 int ret;
13284 int val;
13285 char* endptr = NULL;
13287 /* toss the command name */
13288 argv++;
13290 if (!*argv)
13291 return -1;
13293 val = htod32(strtol(*argv, &endptr, 0));
13294 if (*endptr != '\0') {
13295 /* not all the value string was parsed by strtol */
13296 printf("set: error parsing value \"%s\" as an integer\n", *argv);
13297 return -1;
13300 ret = wlu_iovar_getbuf(wl, cmd->name, &val, sizeof(val),
13301 buf, WLC_IOCTL_MAXLEN);
13303 if (ret)
13304 return ret;
13306 val = dtoh32(*(int*)buf);
13308 wl_printint(val);
13310 return ret;
13313 static int
13314 wl_test_tssi_offs(void *wl, cmd_t *cmd, char **argv)
13316 int ret;
13317 int val;
13318 char* endptr = NULL;
13320 /* toss the command name */
13321 argv++;
13323 if (!*argv)
13324 return -1;
13326 val = htod32(strtol(*argv, &endptr, 0));
13327 if (*endptr != '\0') {
13328 /* not all the value string was parsed by strtol */
13329 printf("set: error parsing value \"%s\" as an integer\n", *argv);
13330 return -1;
13333 ret = wlu_iovar_getbuf(wl, cmd->name, &val, sizeof(val),
13334 buf, WLC_IOCTL_MAXLEN);
13336 if (ret)
13337 return ret;
13339 val = dtoh32(*(int*)buf);
13341 wl_printint(val);
13343 return ret;
13346 static int
13347 wl_sta_info(void *wl, cmd_t *cmd, char **argv)
13349 sta_info_t *sta;
13350 struct ether_addr ea;
13351 char *param;
13352 int buflen, err;
13354 /* convert the ea string into an ea struct */
13355 if (!*++argv || !wl_ether_atoe(*argv, &ea)) {
13356 printf(" ERROR: no valid ether addr provided\n");
13357 return -1;
13360 strcpy(buf, "sta_info");
13361 buflen = strlen(buf) + 1;
13362 param = (char *)(buf + buflen);
13363 memcpy(param, (char*)&ea, ETHER_ADDR_LEN);
13365 if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MEDLEN)))
13366 return err;
13368 /* display the sta info */
13369 sta = (sta_info_t *)buf;
13370 sta->ver = dtoh16(sta->ver);
13372 /* Report unrecognized version */
13373 if (sta->ver > WL_STA_VER) {
13374 printf(" ERROR: unknown driver station info version %d\n", sta->ver);
13375 return -1;
13378 sta->len = dtoh16(sta->len);
13379 sta->cap = dtoh16(sta->cap);
13380 sta->flags = dtoh32(sta->flags);
13381 sta->idle = dtoh32(sta->idle);
13382 sta->rateset.count = dtoh32(sta->rateset.count);
13383 sta->in = dtoh32(sta->in);
13384 sta->listen_interval_inms = dtoh32(sta->listen_interval_inms);
13386 printf(" STA %s:\n", *argv);
13387 printf("\t rateset ");
13388 dump_rateset(sta->rateset.rates, sta->rateset.count);
13389 printf("\n\t idle %d seconds\n", sta->idle);
13390 printf("\t in network %d seconds\n", sta->in);
13391 printf("\t state:%s%s%s\n",
13392 (sta->flags & WL_STA_AUTHE) ? " AUTHENTICATED" : "",
13393 (sta->flags & WL_STA_ASSOC) ? " ASSOCIATED" : "",
13394 (sta->flags & WL_STA_AUTHO) ? " AUTHORIZED" : "");
13396 printf("\t flags 0x%x:%s%s%s%s%s%s%s%s%s\n",
13397 sta->flags,
13398 (sta->flags & WL_STA_BRCM) ? " BRCM" : "",
13399 (sta->flags & WL_STA_ABCAP) ? " ABCAP" : "",
13400 (sta->flags & WL_STA_WME) ? " WME" : "",
13401 (sta->flags & WL_STA_PS) ? " PS" : "",
13402 (sta->flags & WL_STA_APSD_BE) ? " APSD_BE" : "",
13403 (sta->flags & WL_STA_APSD_BK) ? " APSD_BK" : "",
13404 (sta->flags & WL_STA_APSD_VI) ? " APSD_VI" : "",
13405 (sta->flags & WL_STA_APSD_VO) ? " APSD_VO" : "",
13406 (sta->flags & WL_STA_N_CAP) ? " N_CAP" : "");
13408 /* Driver didn't return extended station info */
13409 if (sta->len < sizeof(sta_info_t))
13410 return 0;
13412 if (sta->flags & WL_STA_SCBSTATS)
13414 printf("\t tx pkts: %d\n", dtoh32(sta->tx_pkts));
13415 printf("\t tx failures: %d\n", dtoh32(sta->tx_failures));
13416 printf("\t rx ucast pkts: %d\n", dtoh32(sta->rx_ucast_pkts));
13417 printf("\t rx mcast/bcast pkts: %d\n", dtoh32(sta->rx_mcast_pkts));
13418 printf("\t rate of last tx pkt: %d kbps\n", dtoh32(sta->tx_rate));
13419 printf("\t rate of last rx pkt: %d kbps\n", dtoh32(sta->rx_rate));
13420 printf("\t rx decrypt succeeds: %d\n", dtoh32(sta->rx_decrypt_succeeds));
13421 printf("\t rx decrypt failures: %d\n", dtoh32(sta->rx_decrypt_failures));
13424 return (0);
13427 static int
13428 wl_revinfo(void *wl, cmd_t *cmd, char **argv)
13430 char b[8];
13431 int err;
13432 wlc_rev_info_t revinfo;
13434 UNUSED_PARAMETER(cmd);
13435 UNUSED_PARAMETER(argv);
13437 memset(&revinfo, 0, sizeof(revinfo));
13439 err = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
13440 if (err) {
13441 return err;
13444 printf("vendorid 0x%x\n", dtoh32(revinfo.vendorid));
13445 printf("deviceid 0x%x\n", dtoh32(revinfo.deviceid));
13446 printf("radiorev 0x%x\n", dtoh32(revinfo.radiorev));
13447 printf("chipnum 0x%x\n", dtoh32(revinfo.chipnum));
13448 printf("chiprev 0x%x\n", dtoh32(revinfo.chiprev));
13449 printf("chippackage 0x%x\n", dtoh32(revinfo.chippkg));
13450 printf("corerev 0x%x\n", dtoh32(revinfo.corerev));
13451 printf("boardid 0x%x\n", dtoh32(revinfo.boardid));
13452 printf("boardvendor 0x%x\n", dtoh32(revinfo.boardvendor));
13453 printf("boardrev %s\n", bcm_brev_str(dtoh32(revinfo.boardrev), b));
13454 printf("driverrev 0x%x\n", dtoh32(revinfo.driverrev));
13455 printf("ucoderev 0x%x\n", dtoh32(revinfo.ucoderev));
13456 printf("bus 0x%x\n", dtoh32(revinfo.bus));
13457 printf("phytype 0x%x\n", dtoh32(revinfo.phytype));
13458 printf("phyrev 0x%x\n", dtoh32(revinfo.phyrev));
13459 printf("anarev 0x%x\n", dtoh32(revinfo.anarev));
13461 return 0;
13464 static int
13465 wl_rm_request(void *wl, cmd_t *cmd, char **argv)
13467 miniopt_t to;
13468 const char* fn_name = "wl_rm_request";
13469 wl_rm_req_t *rm_ptr;
13470 wl_rm_req_t rm;
13471 wl_rm_req_elt_t req;
13472 int buflen = 0;
13473 int err, opt_err;
13474 int type;
13475 bool in_measure = FALSE;
13477 UNUSED_PARAMETER(cmd);
13479 memset(buf, 0, WLC_IOCTL_MAXLEN);
13480 memset(&rm, 0, WL_RM_REQ_FIXED_LEN);
13481 memset(&req, 0, sizeof(wl_rm_req_elt_t));
13483 strcpy(buf, "rm_req");
13484 buflen = strlen(buf) + 1;
13486 rm_ptr = (wl_rm_req_t*)(buf + buflen);
13487 buflen += WL_RM_REQ_FIXED_LEN;
13489 /* toss the command name */
13490 argv++;
13492 miniopt_init(&to, fn_name, "p", FALSE);
13493 while ((opt_err = miniopt(&to, argv)) != -1) {
13494 if (opt_err == 1) {
13495 err = -1;
13496 goto exit;
13498 argv += to.consumed;
13500 if (to.opt == 't') {
13501 if (!to.good_int) {
13502 fprintf(stderr,
13503 "%s: could not parse \"%s\" as an int for the token\n",
13504 fn_name, to.valstr);
13505 err = -1;
13506 goto exit;
13509 if (!in_measure)
13510 rm.token = to.val;
13511 else
13512 req.token = to.val;
13514 if (to.opt == 'c') {
13515 if (!to.good_int) {
13516 fprintf(stderr,
13517 "%s: could not parse \"%s\" as an int for channel\n",
13518 fn_name, to.valstr);
13519 err = -1;
13520 goto exit;
13523 req.chanspec = to.val & WL_CHANSPEC_CHAN_MASK;
13524 req.chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
13525 req.chanspec |= ((to.val <= 14) ? WL_CHANSPEC_BAND_2G :
13526 WL_CHANSPEC_BAND_5G);
13528 if (to.opt == 'd') {
13529 if (!to.good_int) {
13530 fprintf(stderr,
13531 "%s: could not parse \"%s\" as an int for duration\n",
13532 fn_name, to.valstr);
13533 err = -1;
13534 goto exit;
13536 req.dur = to.val;
13539 if (to.opt == 'p') {
13540 req.flags = WL_RM_FLAG_PARALLEL;
13543 if (to.positional) {
13544 if (!strcmp(to.valstr, "basic")) {
13545 type = WL_RM_TYPE_BASIC;
13546 } else if (!strcmp(to.valstr, "cca")) {
13547 type = WL_RM_TYPE_CCA;
13548 } else if (!strcmp(to.valstr, "rpi")) {
13549 type = WL_RM_TYPE_RPI;
13550 } else {
13551 fprintf(stderr,
13552 "%s: could not parse \"%s\" as a measurement type\n",
13553 fn_name, to.valstr);
13554 err = -1;
13555 goto exit;
13557 /* complete the previous measurement */
13558 if (in_measure) {
13559 req.chanspec = htodchanspec(req.chanspec);
13560 req.token = htod32(req.token);
13561 req.tsf_h = htod32(req.tsf_h);
13562 req.tsf_l = htod32(req.tsf_l);
13563 req.dur = htod32(req.dur);
13564 memcpy(buf + buflen, &req, sizeof(wl_rm_req_elt_t));
13565 buflen += sizeof(wl_rm_req_elt_t);
13566 rm.count++;
13567 req.chanspec = dtohchanspec(req.chanspec);
13568 req.token = dtoh32(req.token);
13569 req.tsf_h = dtoh32(req.tsf_h);
13570 req.tsf_l = dtoh32(req.tsf_l);
13571 req.dur = dtoh32(req.dur);
13572 /* measure to measure default param update */
13573 req.token++; /* each measure gets a new token */
13574 req.flags = 0; /* measure flags are cleared between measures */
13576 in_measure = TRUE;
13577 req.type = (int8)type;
13581 /* complete the last measurement */
13582 if (in_measure) {
13583 req.chanspec = htodchanspec(req.chanspec);
13584 req.token = htod32(req.token);
13585 req.tsf_h = htod32(req.tsf_h);
13586 req.tsf_l = htod32(req.tsf_l);
13587 req.dur = htod32(req.dur);
13588 memcpy(buf + buflen, &req, sizeof(wl_rm_req_elt_t));
13589 buflen += sizeof(wl_rm_req_elt_t);
13590 rm.count++;
13593 if (rm.count == 0) {
13594 fprintf(stderr, "%s: no measurement requests specified\n",
13595 fn_name);
13596 err = -1;
13597 goto exit;
13600 rm.token = htod32(rm.token);
13601 rm.count = htod32(rm.count);
13602 memcpy(rm_ptr, &rm, WL_RM_REQ_FIXED_LEN);
13604 err = wlu_set(wl, WLC_SET_VAR, &buf[0], buflen);
13606 exit:
13607 return err;
13610 static int
13611 wl_rm_report(void *wl, cmd_t *cmd, char **argv)
13613 wl_rm_rep_t *rep_set;
13614 wl_rm_rep_elt_t rep;
13615 char extra[128];
13616 char* p;
13617 const char* name;
13618 uint8* data;
13619 int err, bin;
13620 uint32 val;
13621 uint16 channel;
13622 bool aband;
13623 int len;
13625 UNUSED_PARAMETER(cmd);
13626 UNUSED_PARAMETER(argv);
13628 strcpy(buf, "rm_rep");
13630 err = wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN);
13631 if (err) {
13632 return err;
13635 rep_set = (wl_rm_rep_t *)buf;
13636 rep_set->token = dtoh32(rep_set->token);
13637 rep_set->len = dtoh32(rep_set->len);
13639 printf("Measurement Report: token %d, length %d\n", rep_set->token, rep_set->len);
13641 len = rep_set->len;
13642 data = (uint8*)rep_set->rep;
13643 for (; len > 0; (len -= rep.len), (data += rep.len)) {
13644 if (len >= WL_RM_REP_ELT_FIXED_LEN)
13645 memcpy(&rep, data, WL_RM_REP_ELT_FIXED_LEN);
13646 else
13647 break;
13649 rep.chanspec = dtohchanspec(rep.chanspec);
13650 rep.token = dtoh32(rep.token);
13651 rep.tsf_h = dtoh32(rep.tsf_h);
13652 rep.tsf_l = dtoh32(rep.tsf_l);
13653 rep.dur = dtoh32(rep.dur);
13654 rep.len = dtoh32(rep.len);
13656 data += WL_RM_REP_ELT_FIXED_LEN;
13657 len -= WL_RM_REP_ELT_FIXED_LEN;
13659 if (rep.type == WL_RM_TYPE_BASIC)
13660 name = "Basic";
13661 else if (rep.type == WL_RM_TYPE_CCA)
13662 name = "CCA";
13663 else if (rep.type == WL_RM_TYPE_RPI)
13664 name = "RPI";
13665 else
13666 name = NULL;
13668 if (name)
13669 printf("\nReport : %s\n", name);
13670 else
13671 printf("\nReport : %d <unknown>\n", rep.type);
13673 p = extra;
13674 if (rep.flags & WL_RM_FLAG_PARALLEL) {
13675 if (p != extra) p += sprintf(p, " | ");
13676 p += sprintf(p, "Parallel");
13678 if (rep.flags & WL_RM_FLAG_LATE) {
13679 if (p != extra) p += sprintf(p, " | ");
13680 p += sprintf(p, "Late");
13682 if (rep.flags & WL_RM_FLAG_INCAPABLE) {
13683 if (p != extra) p += sprintf(p, " | ");
13684 p += sprintf(p, "Incapable");
13686 if (rep.flags & WL_RM_FLAG_REFUSED) {
13687 if (p != extra) p += sprintf(p, " | ");
13688 p += sprintf(p, "Refused");
13691 if (p != extra) {
13692 printf("flags : 0x%02x (%s)\n", rep.flags, extra);
13693 } else {
13694 printf("flags : 0x%02x\n", rep.flags);
13696 printf("token : %4d\n", rep.token);
13698 if (rep.flags & (WL_RM_FLAG_LATE |
13699 WL_RM_FLAG_INCAPABLE |
13700 WL_RM_FLAG_REFUSED)) {
13701 continue;
13704 channel = CHSPEC_CHANNEL(rep.chanspec);
13705 aband = CHSPEC_IS5G(rep.chanspec);
13707 printf("channel : %4d %s\n", channel,
13708 aband ? "(a)":"(b)");
13709 printf("start tsf: 0x%x:%08x\n", rep.tsf_h, rep.tsf_l);
13710 printf("duration : %4d TU\n", rep.dur);
13712 if (len < (int)rep.len) {
13713 printf("Error: partial report element, %d report bytes "
13714 "remain, element claims %d\n",
13715 len, rep.len);
13716 break;
13719 if (rep.type == WL_RM_TYPE_BASIC) {
13720 if (rep.len >= 4) {
13721 memcpy(&val, data, sizeof(uint32));
13722 val = dtoh32(val);
13723 printf("Basic bits: 0x%08x\n", val);
13725 } else if (rep.type == WL_RM_TYPE_CCA) {
13726 if (rep.len >= 4) {
13727 memcpy(&val, data, sizeof(uint32));
13728 val = dtoh32(val);
13729 printf("Carrier Fraction: %d / 255\n", val);
13731 } else if (rep.type == WL_RM_TYPE_RPI) {
13732 if (rep.len >= sizeof(wl_rm_rpi_rep_t)) {
13733 wl_rm_rpi_rep_t rpi_rep;
13734 int8 min = -128;
13735 int8 max;
13737 memcpy(&rpi_rep, data, sizeof(wl_rm_rpi_rep_t));
13739 for (bin = 0; bin < 8; bin++) {
13740 max = rpi_rep.rpi_max[bin];
13741 if (bin == 0)
13742 printf(" Power <= %3d: ",
13743 max);
13744 else if (bin < 7)
13745 printf(" %3d < Power <= %3d: ",
13746 min, max);
13747 else
13748 printf(" %3d < Power : ",
13749 min);
13750 min = max;
13751 printf("%3d\n", rpi_rep.rpi[bin]);
13757 return err;
13760 static int
13761 wl_join_pref(void *wl, cmd_t *cmd, char **argv)
13763 char* data;
13764 int err;
13765 int len;
13766 int remaining_bytes;
13767 int i;
13768 bcm_tlv_t *ie;
13770 UNUSED_PARAMETER(cmd);
13772 strcpy(buf, "join_pref");
13774 /* set */
13775 if (argv[1]) {
13776 len = strlen(buf);
13777 data = argv[1];
13778 for (i = len + 1, len += 1 + strlen(data) / 2;
13779 (i < len) && (i < (int)WLC_IOCTL_MAXLEN); i ++) {
13780 char hex[] = "XX";
13781 hex[0] = *data++;
13782 hex[1] = *data++;
13783 buf[i] = (uint8)strtoul(hex, NULL, 16);
13785 err = wlu_set(wl, WLC_SET_VAR, buf, i);
13787 /* get */
13788 else if (!(err = wlu_get(wl, WLC_GET_VAR, buf, WLC_IOCTL_MAXLEN))) {
13789 len = dtoh32(*(int *)buf);
13790 data = buf + sizeof(int);
13791 for (i = 0; i < len; i ++)
13792 printf("%02x", data[i]);
13793 printf("\n");
13794 /* pretty print the join pref elements */
13795 remaining_bytes = len;
13796 ie = (bcm_tlv_t*)data;
13797 if (!bcm_valid_tlv(ie, remaining_bytes))
13798 ie = NULL;
13799 while (ie) {
13800 wl_join_pref_print_ie(ie);
13801 ie = bcm_next_tlv(ie, &remaining_bytes);
13804 return err;
13807 static void
13808 wl_join_pref_print_ie(bcm_tlv_t *ie)
13810 int i;
13811 uint8 band;
13812 uint8 count;
13813 int suite_len;
13814 uint8 *suite;
13815 int data_bytes;
13818 switch (ie->id) {
13819 case WL_JOIN_PREF_RSSI:
13820 printf("Pref RSSI\n");
13821 if (ie->len > 2)
13822 printf("\t<%d extra bytes in pref data>\n", ie->len);
13823 break;
13824 case WL_JOIN_PREF_BAND:
13825 printf("Pref BAND: ");
13826 if (ie->len < 2) {
13827 printf("len = %d <band pref data truncated>\n", ie->len);
13828 break;
13831 band = ie->data[1];
13832 if (band == WLC_BAND_AUTO)
13833 printf("0x%x AUTO (no preference)\n", band);
13834 else if (band == WLC_BAND_5G)
13835 printf("0x%x 5 GHz\n", band);
13836 else if (band == WLC_BAND_2G)
13837 printf("0x%x 2.4 GHz\n", band);
13838 else if (band == WLJP_BAND_ASSOC_PREF)
13839 printf("0x%x Use ASSOC_PREFER value\n", band);
13840 else
13841 printf("0x%x\n", band);
13843 if (ie->len > 2)
13844 printf("\t<%d extra bytes in pref data>\n", ie->len - 1);
13846 break;
13847 case WL_JOIN_PREF_WPA:
13848 printf("Pref WPA: ");
13849 if (ie->len < 2) {
13850 printf("len = %d <WPA pref data truncated>\n", ie->len);
13851 break;
13853 count = ie->data[1];
13854 printf("%d ACP Specs\n", count);
13856 data_bytes = ie->len - 2;
13857 suite_len = 4; /* WPA Suite Selector length, OUI + type */
13858 suite = ie->data + 2;
13860 for (i = 0; i < (int)count; i++) {
13861 if (data_bytes < 3 * suite_len)
13862 break;
13863 printf("\t");
13864 /* AKM Suite */
13865 wl_join_pref_print_akm(suite);
13866 printf(",");
13868 suite = suite + suite_len;
13869 /* Unicast Cipher Suite */
13870 printf("U:");
13871 wl_join_pref_print_cipher_suite(suite);
13872 printf(",");
13874 suite = suite + suite_len;
13875 /* Multicast Cipher Suite */
13876 printf("M:");
13877 if (!memcmp(suite, WL_WPA_ACP_MCS_ANY, suite_len))
13878 printf("Any");
13879 else
13880 wl_join_pref_print_cipher_suite(suite);
13881 printf("\n");
13883 suite = suite + suite_len;
13884 data_bytes -= 3 * suite_len;
13887 if (i != count)
13888 printf("\t<expected %d more specs, %d bytes>\n",
13889 count - i, suite_len * (count - i));
13890 if (data_bytes > 0)
13891 printf("\t<%d extra bytes>\n", data_bytes);
13892 break;
13893 case WL_JOIN_PREF_RSSI_DELTA:
13894 printf("RSSI Delta for Pref BAND: ");
13895 if (ie->len < 2) {
13896 printf("len = %d <rssi delta pref data truncated>\n", ie->len);
13897 break;
13900 band = ie->data[1];
13901 if (band == WLC_BAND_AUTO)
13902 printf("0x%x AUTO (no preference)\n", band);
13903 else if (band == WLC_BAND_5G)
13904 printf("0x%x 5 GHz\n", band);
13905 else if (band == WLC_BAND_2G)
13906 printf("0x%x 2.4 GHz\n", band);
13907 else
13908 printf("0x%x\n", band);
13910 printf("RSSI boost %ddb\n", ie->data[0]);
13912 break;
13913 default:
13914 printf("Pref 0x%x: len = %d\n", ie->id, ie->len);
13915 for (i = 0; i < ie->len; i++)
13916 printf("%02x", ie->data[i]);
13917 printf("\n");
13918 break;
13924 static void
13925 wl_join_pref_print_akm(uint8* suite)
13927 uint8 type = suite[3];
13928 const char *oui_name;
13930 if (!memcmp(suite, WPA_OUI, 3))
13931 oui_name = "WPA";
13932 else if (!memcmp(suite, WPA2_OUI, 3))
13933 oui_name = "WPA2";
13934 else
13935 oui_name = NULL;
13937 if (oui_name) {
13938 if (type == RSN_AKM_NONE)
13939 printf("%s-NONE", oui_name);
13940 else if (type == RSN_AKM_UNSPECIFIED)
13941 printf("%s", oui_name);
13942 else if (type == RSN_AKM_UNSPECIFIED)
13943 printf("%s-PSK", oui_name);
13944 else
13945 printf("%s/0x%x", oui_name, type);
13946 } else {
13947 printf("0x%02x%02x%02x/0x%02x", suite[0], suite[1], suite[2], suite[3]);
13951 static void
13952 wl_join_pref_print_cipher_suite(uint8* suite)
13954 uint8 type = suite[3];
13955 const char *oui_name;
13957 if (!memcmp(suite, WPA_OUI, 3))
13958 oui_name = "WPA";
13959 else if (!memcmp(suite, WPA2_OUI, 3))
13960 oui_name = "WPA2";
13961 else
13962 oui_name = NULL;
13964 if (oui_name) {
13965 if (type == WPA_CIPHER_NONE)
13966 printf("%s/NONE", oui_name);
13967 else if (type == WPA_CIPHER_WEP_40)
13968 printf("%s/WEP40", oui_name);
13969 else if (type == WPA_CIPHER_TKIP)
13970 printf("%s/TKIP", oui_name);
13971 else if (type == WPA_CIPHER_AES_CCM)
13972 printf("%s/AES", oui_name);
13973 else if (type == WPA_CIPHER_WEP_104)
13974 printf("%s/WEP104", oui_name);
13975 else
13976 printf("%s/0x%x", oui_name, type);
13977 } else {
13978 printf("0x%02x%02x%02x/0x%02x", suite[0], suite[1], suite[2], suite[3]);
13982 static int
13983 wl_assoc_pref(void *wl, cmd_t *cmd, char **argv)
13985 uint assoc_pref;
13986 int err;
13988 /* set */
13989 if (argv[1]) {
13990 if (!strcmp(argv[1], "auto") || !strcmp(argv[1], "0"))
13991 assoc_pref = WLC_BAND_AUTO;
13992 else if (!strcmp(argv[1], "a") || !strcmp(argv[1], "1"))
13993 assoc_pref = WLC_BAND_5G;
13994 else if (!strcmp(argv[1], "b") || !strcmp(argv[1], "g") || !strcmp(argv[1], "2"))
13995 assoc_pref = WLC_BAND_2G;
13996 else
13997 return -1;
13998 assoc_pref = htod32(assoc_pref);
13999 err = wlu_set(wl, cmd->set, &assoc_pref, sizeof(assoc_pref));
14001 /* get */
14002 else if (!(err = wlu_get(wl, cmd->get, &assoc_pref, sizeof(assoc_pref)))) {
14003 assoc_pref = dtoh32(assoc_pref);
14004 switch (assoc_pref) {
14005 case WLC_BAND_AUTO:
14006 printf("auto\n");
14007 break;
14008 case WLC_BAND_5G:
14009 printf("a\n");
14010 break;
14011 case WLC_BAND_2G:
14012 printf("b/g\n");
14013 break;
14016 return err;
14019 static const char ac_names[AC_COUNT][6] = {"AC_BE", "AC_BK", "AC_VI", "AC_VO"};
14022 * Get or set WME per-AC transmit parameters
14024 static int
14025 wme_tx_params(void *wl, cmd_t *cmd, char **argv)
14027 char *val_p, *ac_str, *param;
14028 int buflen;
14029 int aci;
14030 wme_tx_params_t cur_params[AC_COUNT], new_params[AC_COUNT];
14031 int err;
14032 int val;
14034 UNUSED_PARAMETER(cmd);
14036 argv++;
14038 buflen = WLC_IOCTL_MAXLEN;
14041 * Get current acparams, using buf as an input buffer.
14042 * Return data is array of 4 ACs of wme params.
14045 strcpy(buf, "wme_tx_params");
14046 if ((err = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen)) < 0) {
14047 return err;
14049 memcpy(&cur_params, buf, WL_WME_TX_PARAMS_IO_BYTES);
14051 if ((ac_str = *argv++) == NULL) {
14052 printf("WME TX params: \n");
14053 for (aci = 0; aci < AC_COUNT; aci++) {
14054 printf("%s: short %d. sfb %d. long %d. lfb %d. max %d\n", ac_names[aci],
14055 cur_params[aci].short_retry,
14056 cur_params[aci].short_fallback,
14057 cur_params[aci].long_retry,
14058 cur_params[aci].long_fallback,
14059 cur_params[aci].max_rate);
14061 } else {
14062 int chk_lim;
14063 if (strcmp(ac_str, "be") == 0) {
14064 aci = AC_BE;
14065 } else if (strcmp(ac_str, "bk") == 0) {
14066 aci = AC_BK;
14067 } else if (strcmp(ac_str, "vi") == 0) {
14068 aci = AC_VI;
14069 } else if (strcmp(ac_str, "vo") == 0) {
14070 aci = AC_VO;
14071 } else {
14072 printf("Unknown access class: %s\n", ac_str);
14073 return USAGE_ERROR;
14076 /* Preload new values with current values */
14077 memcpy(&new_params, &cur_params, sizeof(new_params));
14078 while ((param = *argv++) != NULL) {
14079 if ((val_p = *argv++) == NULL) {
14080 printf("Need value following %s\n", param);
14081 return USAGE_ERROR;
14083 chk_lim = 15;
14084 val = (int)strtoul(val_p, NULL, 0);
14085 /* All values must fit in uint8 */
14086 if (!strcmp(param, "short")) {
14087 new_params[aci].short_retry = (uint8)val;
14088 } else if (!strcmp(param, "sfb")) {
14089 new_params[aci].short_fallback = (uint8)val;
14090 } else if (!strcmp(param, "long")) {
14091 new_params[aci].long_retry = (uint8)val;
14092 } else if (!strcmp(param, "lfb")) {
14093 new_params[aci].long_fallback = (uint8)val;
14094 } else if ((!strcmp(param, "max_rate")) || (!strcmp(param, "max")) ||
14095 (!strcmp(param, "rate"))) {
14096 chk_lim = 255;
14097 new_params[aci].max_rate = (uint8)val;
14098 } else {
14099 printf("Unknown parameter: %s\n", param);
14100 return USAGE_ERROR;
14102 if (val > chk_lim) {
14103 printf("Value for %s must be < %d\n", param, chk_lim + 1);
14104 return USAGE_ERROR;
14107 strcpy(buf, "wme_tx_params");
14108 memcpy(buf + strlen(buf) + 1, new_params, WL_WME_TX_PARAMS_IO_BYTES);
14109 err = wlu_set(wl, WLC_SET_VAR, &buf[0], buflen);
14112 return 0;
14116 * Get or Set WME Access Class (AC) parameters
14117 * wl wme_ac ap|sta [be|bk|vi|vo [ecwmax|ecwmin|txop|aifsn|acm <value>] ...]
14118 * Without args past ap|sta, print current values
14120 static int
14121 wl_wme_ac_req(void *wl, cmd_t *cmd, char **argv)
14123 int err, buflen;
14124 edcf_acparam_t acparam_cur[AC_COUNT], acparam_new[AC_COUNT], *acp;
14125 char *ac_str, *param, *val;
14126 bool acm;
14127 int aci, aifsn, ecwmin, ecwmax, txop;
14128 int ap_mode = 0;
14129 int sta_param = 0;
14131 argv++;
14133 if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
14134 return err;
14135 ap_mode = dtoh32(ap_mode);
14137 if ((param = *argv++) == NULL)
14138 return USAGE_ERROR;
14140 if (!strcmp(param, "ap"))
14141 sta_param = 0;
14142 else if (!strcmp(param, "sta"))
14143 sta_param = 1;
14144 else
14145 return USAGE_ERROR;
14147 if (!ap_mode && !sta_param) {
14148 fprintf(stderr, "Can't work with AP parameters on STA\n");
14149 return USAGE_ERROR;
14153 * On call to wlu_get, buf contains the NUL-terminated
14154 * string "wme_ac_sta" or "wme_ac_ap".
14155 * On return, gotten data starts at beginning of buf.
14157 * On call to wlu_set, buf contains the NUL-terminated
14158 * string "wme_ac_sta" or "wme_ac_ap", followed by the data.
14159 * Only a return value is returned.
14162 if (sta_param)
14163 strcpy(buf, "wme_ac_sta");
14164 else
14165 strcpy(buf, "wme_ac_ap");
14167 buflen = WLC_IOCTL_MAXLEN;
14170 * Get current acparams, using buf as an input buffer.
14171 * Return data is array of 4 ACs of wme params.
14174 if ((err = wlu_get(wl, cmd->get, &buf[0], buflen)) < 0)
14175 return err;
14177 memcpy(&acparam_cur, buf, sizeof(acparam_cur));
14179 if ((ac_str = *argv++) == NULL) {
14180 printf("AC Parameters %s\n",
14181 ap_mode ? (sta_param ? "advertised for STA" : "for AP") : "for STA");
14183 for (aci = 0; aci < AC_COUNT; aci++) {
14184 acp = &acparam_cur[aci];
14185 acp->TXOP = dtoh16(acp->TXOP);
14186 if (((acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT) != aci)
14187 printf("Warning: AC params out of order\n");
14188 acm = (acp->ACI & EDCF_ACM_MASK) ? 1 : 0;
14189 aifsn = acp->ACI & EDCF_AIFSN_MASK;
14190 ecwmin = acp->ECW & EDCF_ECWMIN_MASK;
14191 ecwmax = (acp->ECW & EDCF_ECWMAX_MASK) >> EDCF_ECWMAX_SHIFT;
14192 txop = acp->TXOP;
14193 printf("%s: raw: ACI 0x%x ECW 0x%x TXOP 0x%x\n",
14194 ac_names[aci],
14195 acp->ACI, acp->ECW, acp->TXOP);
14196 printf(" dec: aci %d acm %d aifsn %d "
14197 "ecwmin %d ecwmax %d txop 0x%x\n",
14198 aci, acm, aifsn, ecwmin, ecwmax, txop);
14199 /* CWmin = 2^(ECWmin) - 1 */
14200 /* CWmax = 2^(ECWmax) - 1 */
14201 /* TXOP = number of 32 us units */
14202 printf(" eff: CWmin %d CWmax %d TXop %dusec\n",
14203 EDCF_ECW2CW(ecwmin), EDCF_ECW2CW(ecwmax), EDCF_TXOP2USEC(txop));
14206 err = 0;
14207 } else {
14208 if (strcmp(ac_str, "be") == 0)
14209 aci = AC_BE;
14210 else if (strcmp(ac_str, "bk") == 0)
14211 aci = AC_BK;
14212 else if (strcmp(ac_str, "vi") == 0)
14213 aci = AC_VI;
14214 else if (strcmp(ac_str, "vo") == 0)
14215 aci = AC_VO;
14216 else
14217 return USAGE_ERROR;
14219 /* Preload new values with current values */
14220 memcpy(&acparam_new, &acparam_cur, sizeof(acparam_new));
14222 acp = &acparam_new[aci];
14224 while ((param = *argv++) != NULL) {
14225 if ((val = *argv++) == NULL)
14226 return USAGE_ERROR;
14228 if (!strcmp(param, "acm")) {
14229 if (!stricmp(val, "on") || !stricmp(val, "1"))
14230 acp->ACI |= EDCF_ACM_MASK;
14231 else if (!stricmp(val, "off") || !stricmp(val, "0"))
14232 acp->ACI &= ~EDCF_ACM_MASK;
14233 else {
14234 fprintf(stderr, "acm value must be 1|0\n");
14235 return USAGE_ERROR;
14237 } else if (!strcmp(param, "aifsn")) {
14238 aifsn = (int)strtol(val, NULL, 0);
14239 if (aifsn >= EDCF_AIFSN_MIN && aifsn <= EDCF_AIFSN_MAX)
14240 acp->ACI =
14241 (acp->ACI & ~EDCF_AIFSN_MASK) |
14242 (aifsn & EDCF_AIFSN_MASK);
14243 else {
14244 fprintf(stderr, "aifsn %d out of range (%d-%d)\n",
14245 aifsn, EDCF_AIFSN_MIN, EDCF_AIFSN_MAX);
14246 return USAGE_ERROR;
14248 } else if (!strcmp(param, "ecwmax")) {
14249 ecwmax = (int)strtol(val, NULL, 0);
14250 if (ecwmax >= EDCF_ECW_MIN && ecwmax <= EDCF_ECW_MAX)
14251 acp->ECW =
14252 ((ecwmax << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK) |
14253 (acp->ECW & EDCF_ECWMIN_MASK);
14254 else {
14255 fprintf(stderr, "ecwmax %d out of range (%d-%d)\n",
14256 ecwmax, EDCF_ECW_MIN, EDCF_ECW_MAX);
14257 return USAGE_ERROR;
14259 } else if (!strcmp(param, "ecwmin")) {
14260 ecwmin = (int)strtol(val, NULL, 0);
14261 if (ecwmin >= EDCF_ECW_MIN && ecwmin <= EDCF_ECW_MAX)
14262 acp->ECW =
14263 ((acp->ECW & EDCF_ECWMAX_MASK) |
14264 (ecwmin & EDCF_ECWMIN_MASK));
14265 else {
14266 fprintf(stderr, "ecwmin %d out of range (%d-%d)\n",
14267 ecwmin, EDCF_ECW_MIN, EDCF_ECW_MAX);
14268 return USAGE_ERROR;
14270 } else if (!strcmp(param, "txop")) {
14271 txop = (int)strtol(val, NULL, 0);
14272 if (txop >= EDCF_TXOP_MIN && txop <= EDCF_TXOP_MAX)
14273 acp->TXOP = htod16(txop);
14274 else {
14275 fprintf(stderr, "txop %d out of range (%d-%d)\n",
14276 txop, EDCF_TXOP_MIN, EDCF_TXOP_MAX);
14277 return USAGE_ERROR;
14279 } else {
14280 fprintf(stderr, "unexpected param %s\n", param);
14281 return USAGE_ERROR;
14286 * Now use buf as an output buffer.
14287 * Put WME acparams after "wme_ac\0" in buf.
14288 * NOTE: only one of the four ACs can be set at a time.
14290 if (sta_param)
14291 strcpy(buf, "wme_ac_sta");
14292 else
14293 strcpy(buf, "wme_ac_ap");
14295 memcpy(buf + strlen(buf) + 1, acp, sizeof(edcf_acparam_t));
14297 err = wlu_set(wl, cmd->set, &buf[0], buflen);
14300 return err;
14304 * Get or Set WME APSD control parameters
14305 * wl wme_apsd_sta <max_sp_len> <be> <bk> <vi> <vo>
14306 * <max_sp_len> is 0 (all), 2, 4, or 6
14307 * <be>, <bk>, <vi>, <vo> are each 0 or 1 for APSD enable
14308 * with no args, print current values
14310 static int
14311 wl_wme_apsd_sta(void *wl, cmd_t *cmd, char **argv)
14313 int err;
14314 int buflen;
14315 char *param;
14316 int ap_mode;
14317 int qosinfo;
14318 int msp, max_sp_len, be, bk, vi, vo;
14320 if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
14321 return err;
14323 if (ap_mode) {
14324 printf("%s: STA only\n", cmd->name);
14325 return -1;
14328 /* Display current params if no args, else set params */
14330 memset(buf, 0, WLC_IOCTL_MAXLEN);
14331 strcpy(buf, "wme_qosinfo");
14332 buflen = WLC_IOCTL_MAXLEN;
14334 param = *++argv;
14336 if (param == NULL) {
14337 if ((err = wlu_get(wl, cmd->get, &buf[0], buflen)) < 0)
14338 return err;
14340 memcpy(&qosinfo, buf, sizeof(qosinfo));
14341 qosinfo = dtoh32(qosinfo);
14343 msp = (qosinfo & WME_QI_STA_MAXSPLEN_MASK) >> WME_QI_STA_MAXSPLEN_SHIFT;
14344 be = (qosinfo & WME_QI_STA_APSD_BE_MASK) >> WME_QI_STA_APSD_BE_SHIFT;
14345 bk = (qosinfo & WME_QI_STA_APSD_BK_MASK) >> WME_QI_STA_APSD_BK_SHIFT;
14346 vi = (qosinfo & WME_QI_STA_APSD_VI_MASK) >> WME_QI_STA_APSD_VI_SHIFT;
14347 vo = (qosinfo & WME_QI_STA_APSD_VO_MASK) >> WME_QI_STA_APSD_VO_SHIFT;
14349 max_sp_len = msp * 2;
14351 printf("Max SP Length = %d, APSD: BE=%d BK=%d VI=%d VO=%d\n",
14352 max_sp_len, be, bk, vi, vo);
14353 } else {
14354 max_sp_len = (int)strtol(param, 0, 0);
14355 if ((param = *++argv) == NULL)
14356 return -1;
14357 be = (int)strtol(param, 0, 0);
14358 if ((param = *++argv) == NULL)
14359 return -1;
14360 bk = (int)strtol(param, 0, 0);
14361 if ((param = *++argv) == NULL)
14362 return -1;
14363 vi = (int)strtol(param, 0, 0);
14364 if ((param = *++argv) == NULL)
14365 return -1;
14366 vo = (int)strtol(param, 0, 0);
14368 if (((be | bk | vi | vo) & ~1) | (max_sp_len & ~6)) {
14369 printf("%s: Invalid parameter\n", cmd->name);
14370 return -1;
14373 msp = max_sp_len / 2;
14375 qosinfo = (msp << WME_QI_STA_MAXSPLEN_SHIFT) & WME_QI_STA_MAXSPLEN_MASK;
14376 qosinfo |= (be << WME_QI_STA_APSD_BE_SHIFT) & WME_QI_STA_APSD_BE_MASK;
14377 qosinfo |= (bk << WME_QI_STA_APSD_BK_SHIFT) & WME_QI_STA_APSD_BK_MASK;
14378 qosinfo |= (vi << WME_QI_STA_APSD_VI_SHIFT) & WME_QI_STA_APSD_VI_MASK;
14379 qosinfo |= (vo << WME_QI_STA_APSD_VO_SHIFT) & WME_QI_STA_APSD_VO_MASK;
14381 qosinfo = htod32(qosinfo);
14382 memcpy(&buf[strlen(buf) + 1], &qosinfo, sizeof(qosinfo));
14384 err = wlu_set(wl, cmd->set, &buf[0], buflen);
14387 return err;
14391 * Get or Set WME discard policy
14392 * wl wme_dp <be> <bk> <vi> <vo>
14393 * <be>, <bk>, <vi>, <vo> are each 0/1 for discard newest/oldest first
14394 * with no args, print current values
14396 static int
14397 wl_wme_dp(void *wl, cmd_t *cmd, char **argv)
14399 int err;
14400 int buflen;
14401 char *param;
14402 int dp;
14403 int be, bk, vi, vo;
14405 /* Display current params if no args, else set params */
14407 memset(buf, 0, WLC_IOCTL_MAXLEN);
14408 strcpy(buf, "wme_dp");
14409 buflen = WLC_IOCTL_MAXLEN;
14411 param = *++argv;
14413 if (param == NULL) {
14414 if ((err = wlu_get(wl, cmd->get, &buf[0], buflen)) < 0)
14415 return err;
14417 memcpy(&dp, buf, sizeof(dp));
14418 dp = dtoh32(dp);
14420 be = (dp >> AC_BE) & 1;
14421 bk = (dp >> AC_BK) & 1;
14422 vi = (dp >> AC_VI) & 1;
14423 vo = (dp >> AC_VO) & 1;
14425 printf("Discard oldest first: BE=%d BK=%d VI=%d VO=%d\n", be, bk, vi, vo);
14426 } else {
14427 be = (int)strtol(param, 0, 0);
14428 if ((param = *++argv) == NULL)
14429 return -1;
14430 bk = (int)strtol(param, 0, 0);
14431 if ((param = *++argv) == NULL)
14432 return -1;
14433 vi = (int)strtol(param, 0, 0);
14434 if ((param = *++argv) == NULL)
14435 return -1;
14436 vo = (int)strtol(param, 0, 0);
14438 if ((be | bk | vi | vo) & ~1) {
14439 printf("%s: Invalid parameter\n", cmd->name);
14440 return -1;
14443 dp = (be << AC_BE) | (bk << AC_BK) | (vi << AC_VI) | (vo << AC_VO);
14445 dp = htod32(dp);
14446 memcpy(&buf[strlen(buf) + 1], &dp, sizeof(dp));
14448 err = wlu_set(wl, cmd->set, &buf[0], buflen);
14451 return err;
14455 * Get or Set WME lifetime parameter
14456 * "wl lifetime be|bk|vi|vo [<value>]"},
14457 * with no args, print current values
14459 static int
14460 wl_lifetime(void *wl, cmd_t *cmd, char **argv)
14462 int err;
14463 uint8 ac;
14464 char *param, *val;
14465 const char *cmdname = "lifetime";
14466 wl_lifetime_t lifetime, *reply;
14467 void *ptr = NULL;
14469 UNUSED_PARAMETER(cmd);
14471 if ((param = *++argv) == NULL)
14472 return USAGE_ERROR;
14474 if (strcmp(param, "be") == 0)
14475 ac = AC_BE;
14476 else if (strcmp(param, "bk") == 0)
14477 ac = AC_BK;
14478 else if (strcmp(param, "vi") == 0)
14479 ac = AC_VI;
14480 else if (strcmp(param, "vo") == 0)
14481 ac = AC_VO;
14482 else {
14483 fprintf(stderr, "unexpected param %s\n", param);
14484 return USAGE_ERROR;
14487 if ((val = *++argv) == NULL) {
14488 lifetime.ac = htod32(ac);
14489 if ((err = wlu_var_getbuf(wl, cmdname, &lifetime, sizeof(lifetime),
14490 &ptr)) < 0)
14491 return err;
14492 reply = (wl_lifetime_t *) ptr;
14493 reply->ac = dtoh32(reply->ac);
14494 reply->lifetime = dtoh32(reply->lifetime);
14495 printf("Lifetime for access class '%s' is %dms\n", param, reply->lifetime);
14497 else {
14498 lifetime.ac = htod32(ac);
14499 lifetime.lifetime = htod32((uint)strtol(val, 0, 0));
14500 err = wlu_var_setbuf(wl, cmdname, &lifetime, sizeof(lifetime));
14503 return err;
14506 static int
14507 wl_add_ie(void *wl, cmd_t *cmd, char **argv)
14509 UNUSED_PARAMETER(cmd);
14511 return (wl_vndr_ie(wl, "add", argv));
14514 static int
14515 wl_del_ie(void *wl, cmd_t *cmd, char **argv)
14517 UNUSED_PARAMETER(cmd);
14519 return (wl_vndr_ie(wl, "del", argv));
14522 static int
14523 wl_vndr_ie(void *wl, const char *command, char **argv)
14525 vndr_ie_setbuf_t *ie_setbuf;
14526 uint32 pktflag;
14527 int ielen, datalen, buflen, iecount;
14528 int err = 0;
14529 int ret;
14530 int bsscfg_idx = 0;
14531 int consumed = 0;
14533 if (!argv[1] || !argv[2] || !argv[3]) {
14534 fprintf(stderr, "Too few arguments\n");
14535 return -1;
14538 /* parse a bsscfg_idx option if present */
14539 if ((ret = wl_cfg_option(argv + 1, argv[0], &bsscfg_idx, &consumed)) != 0)
14540 return ret;
14541 if (consumed)
14542 argv = argv + consumed;
14543 if (consumed == 0)
14544 bsscfg_idx = -1;
14546 pktflag = (uint)strtol(argv[1], 0, 0);
14548 if ((pktflag &
14549 ~(VNDR_IE_BEACON_FLAG |
14550 VNDR_IE_PRBRSP_FLAG |
14551 VNDR_IE_ASSOCRSP_FLAG |
14552 VNDR_IE_AUTHRSP_FLAG |
14553 VNDR_IE_PRBREQ_FLAG |
14554 VNDR_IE_ASSOCREQ_FLAG |
14555 VNDR_IE_IWAPID_FLAG))) {
14556 fprintf(stderr, "Invalid packet flag 0x%x (%d)\n", pktflag, pktflag);
14557 return -1;
14560 ielen = atoi(argv[2]);
14561 if (ielen > VNDR_IE_MAX_LEN) {
14562 fprintf(stderr, "IE length is %d, should be <= %d\n", ielen, VNDR_IE_MAX_LEN);
14563 return -1;
14565 else if (ielen < VNDR_IE_MIN_LEN) {
14566 fprintf(stderr, "IE length is %d, should be >= %d\n", ielen, VNDR_IE_MIN_LEN);
14567 return -1;
14570 if (strlen(argv[3]) != OUI_STR_SIZE) {
14571 fprintf(stderr, "Invalid OUI length %d\n", (int)strlen(argv[3]));
14572 return -1;
14575 datalen = ielen - VNDR_IE_MIN_LEN;
14576 if (datalen > 0) {
14577 if (!argv[4]) {
14578 fprintf(stderr, "Data bytes should be specified for IE of length %d",
14579 ielen);
14580 return -1;
14582 else {
14583 /* Ensure each data byte is 2 characters long */
14584 if ((int)strlen (argv[4]) < (datalen * 2)) {
14585 fprintf(stderr, "Please specify all the data bytes for this IE\n");
14586 return -1;
14591 if (datalen == 0 && (argv[4] != NULL))
14592 fprintf(stderr, "Ignoring data bytes for IE of length %d", ielen);
14594 buflen = sizeof(vndr_ie_setbuf_t) + datalen - 1;
14596 ie_setbuf = (vndr_ie_setbuf_t *) malloc(buflen);
14598 if (ie_setbuf == NULL) {
14599 fprintf(stderr, "memory alloc failure\n");
14600 return -1;
14603 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
14604 strncpy(ie_setbuf->cmd, command, VNDR_IE_CMD_LEN - 1);
14605 ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
14608 /* Buffer contains only 1 IE */
14609 iecount = htod32(1);
14610 memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
14613 * The packet flag bit field indicates the packets that will
14614 * contain this IE
14616 pktflag = htod32(pktflag);
14617 memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
14618 &pktflag, sizeof(uint32));
14620 /* Now, add the IE to the buffer */
14621 ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
14623 if ((err = get_oui_bytes ((uchar *)argv[3],
14624 &ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0]))) {
14625 free(ie_setbuf);
14626 fprintf(stderr, "Error parsing OUI arg\n");
14627 return err;
14630 if (datalen > 0) {
14631 if ((err = get_ie_data ((uchar *)argv[4],
14632 &ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0],
14633 datalen))) {
14634 free(ie_setbuf);
14635 fprintf(stderr, "Error parsing data arg\n");
14636 return err;
14640 if (bsscfg_idx == -1)
14641 err = wlu_var_setbuf(wl, "vndr_ie", ie_setbuf, buflen);
14642 else
14643 err = wl_bssiovar_setbuf(wl, "vndr_ie", bsscfg_idx,
14644 ie_setbuf, buflen, buf, WLC_IOCTL_MAXLEN);
14646 free(ie_setbuf);
14648 return (err);
14651 static int
14652 wl_list_ie(void *wl, cmd_t *cmd, char **argv)
14654 uchar *iebuf;
14655 uchar *data;
14656 int tot_ie, pktflag, iecount, count, datalen, col;
14657 vndr_ie_buf_t *ie_getbuf;
14658 vndr_ie_info_t *ie_info;
14659 vndr_ie_t *ie;
14660 int err = 0;
14661 void *ptr;
14663 UNUSED_PARAMETER(cmd);
14664 UNUSED_PARAMETER(argv);
14666 err = wlu_var_getbuf(wl, "vndr_ie", NULL, 0, &ptr);
14667 if (err == 0) {
14668 ie_getbuf = (vndr_ie_buf_t *)ptr;
14669 memcpy(&tot_ie, (void *)&ie_getbuf->iecount, sizeof(int));
14670 tot_ie = dtoh32(tot_ie);
14671 printf("Total IEs %d\n", tot_ie);
14673 iebuf = (uchar *)&ie_getbuf->vndr_ie_list[0];
14675 for (iecount = 0; iecount < tot_ie; iecount++) {
14676 ie_info = (vndr_ie_info_t *) iebuf;
14677 memcpy(&pktflag, (void *)&ie_info->pktflag, sizeof(uint32));
14678 pktflag = dtoh32(pktflag);
14679 iebuf += sizeof(uint32);
14681 printf("\n");
14683 ie = &ie_info->vndr_ie_data;
14684 printf("IE index = %d\n", iecount);
14685 printf("-----------------\n");
14686 printf("Pkt Flg = 0x%x\n", pktflag);
14687 printf("Length = %d\n", ie->len);
14688 printf("OUI = %02x:%02x:%02x\n",
14689 ie->oui[0], ie->oui[1], ie->oui[2]);
14690 printf("Data:\n");
14692 data = &ie->data[0];
14693 datalen = ie->len - VNDR_IE_MIN_LEN;
14694 for (count = 0; (count < datalen);) {
14695 for (col = 0; (col < MAX_DATA_COLS) &&
14696 (count < datalen); col++, count++) {
14697 printf("%02x ", *data++);
14699 printf("\n");
14702 iebuf += ie->len + VNDR_IE_HDR_LEN;
14705 else {
14706 fprintf(stderr, "Error %d getting IOVar\n", err);
14709 return err;
14712 static int
14713 wl_rand(void *wl, cmd_t *cmd, char **argv)
14715 char *randbuf;
14716 uint16 randnum;
14717 int err;
14718 void *ptr;
14720 UNUSED_PARAMETER(argv);
14722 if ((err = wlu_var_getbuf (wl, cmd->name, NULL, 0, &ptr)))
14723 return (err);
14725 randbuf = (char *)ptr;
14726 memcpy(&randnum, randbuf, sizeof(uint16));
14727 printf("%d\n", randnum);
14729 return (0);
14732 #define PRVAL(name) pbuf += sprintf(pbuf, "%s %d ", #name, dtoh32(cnt.name))
14733 #define PRNL() pbuf += sprintf(pbuf, "\n")
14735 static int
14736 wl_counters(void *wl, cmd_t *cmd, char **argv)
14738 char *statsbuf;
14739 wl_cnt_t cnt;
14740 int err;
14741 uint i;
14742 char *pbuf = buf;
14743 void *ptr;
14745 UNUSED_PARAMETER(argv);
14747 if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr)))
14748 return (err);
14750 statsbuf = (char *)ptr;
14751 memcpy(&cnt, statsbuf, sizeof(cnt));
14752 cnt.version = dtoh16(cnt.version);
14753 cnt.length = dtoh16(cnt.length);
14755 if (cnt.version > WL_CNT_T_VERSION) {
14756 printf("\tIncorrect version of counters struct: expected %d; got %d\n",
14757 WL_CNT_T_VERSION, cnt.version);
14758 return -1;
14760 else if (cnt.version != WL_CNT_T_VERSION) {
14761 printf("\tIncorrect version of counters struct: expected %d; got %d\n",
14762 WL_CNT_T_VERSION, cnt.version);
14763 printf("\tDisplayed values may be incorrect\n");
14766 /* summary stat counter line */
14767 PRVAL(txframe); PRVAL(txbyte); PRVAL(txretrans); PRVAL(txerror);
14768 PRVAL(rxframe); PRVAL(rxbyte); PRVAL(rxerror); PRNL();
14770 PRVAL(txprshort); PRVAL(txdmawar); PRVAL(txnobuf); PRVAL(txnoassoc);
14771 PRVAL(txchit); PRVAL(txcmiss); PRVAL(txcongest); PRNL();
14773 PRVAL(reset); PRVAL(txserr); PRVAL(txphyerr); PRVAL(txphycrs);
14774 PRVAL(txfail); PRVAL(tbtt); PRNL();
14776 pbuf += sprintf(pbuf, "d11_txfrag %d d11_txmulti %d d11_txretry %d d11_txretrie %d\n",
14777 dtoh32(cnt.txfrag), dtoh32(cnt.txmulti), dtoh32(cnt.txretry), dtoh32(cnt.txretrie));
14779 pbuf += sprintf(pbuf, "d11_txrts %d d11_txnocts %d d11_txnoack %d d11_txfrmsnt %d\n",
14780 dtoh32(cnt.txrts), dtoh32(cnt.txnocts), dtoh32(cnt.txnoack), dtoh32(cnt.txfrmsnt));
14782 PRVAL(rxcrc); PRVAL(rxnobuf); PRVAL(rxnondata); PRVAL(rxbadds);
14783 PRVAL(rxbadcm); PRVAL(rxdup); PRVAL(rxfragerr); PRNL();
14785 PRVAL(rxrunt); PRVAL(rxgiant); PRVAL(rxnoscb); PRVAL(rxbadproto);
14786 PRVAL(rxbadsrcmac); PRNL();
14788 pbuf += sprintf(pbuf, "d11_rxfrag %d d11_rxmulti %d d11_rxundec %d\n",
14789 dtoh32(cnt.rxfrag), dtoh32(cnt.rxmulti), dtoh32(cnt.rxundec));
14791 PRVAL(rxctl); PRVAL(rxbadda); PRVAL(rxfilter); PRNL();
14793 pbuf += sprintf(pbuf, "rxuflo: ");
14794 for (i = 0; i < NFIFO; i++)
14795 pbuf += sprintf(pbuf, "%d ", dtoh32(cnt.rxuflo[i]));
14796 pbuf += sprintf(pbuf, "\n");
14797 PRVAL(txallfrm); PRVAL(txrtsfrm); PRVAL(txctsfrm); PRVAL(txackfrm); PRNL();
14798 PRVAL(txdnlfrm); PRVAL(txbcnfrm); PRVAL(txtplunfl); PRVAL(txphyerr); PRNL();
14799 pbuf += sprintf(pbuf, "txfunfl: ");
14800 for (i = 0; i < NFIFO; i++)
14801 pbuf += sprintf(pbuf, "%d ", dtoh32(cnt.txfunfl[i]));
14802 pbuf += sprintf(pbuf, "\n");
14804 /* WPA2 counters */
14805 PRNL();
14806 PRVAL(tkipmicfaill); PRVAL(tkipicverr); PRVAL(tkipcntrmsr); PRNL();
14807 PRVAL(tkipreplay); PRVAL(ccmpfmterr); PRVAL(ccmpreplay); PRNL();
14808 PRVAL(ccmpundec); PRVAL(fourwayfail); PRVAL(wepundec); PRNL();
14809 PRVAL(wepicverr); PRVAL(decsuccess); PRVAL(rxundec); PRNL();
14811 PRNL();
14812 PRVAL(rxfrmtoolong); PRVAL(rxfrmtooshrt);
14813 PRVAL(rxinvmachdr); PRVAL(rxbadfcs); PRNL();
14814 PRVAL(rxbadplcp); PRVAL(rxcrsglitch);
14815 PRVAL(rxstrt); PRVAL(rxdfrmucastmbss); PRNL();
14816 PRVAL(rxmfrmucastmbss); PRVAL(rxcfrmucast);
14817 PRVAL(rxrtsucast); PRVAL(rxctsucast); PRNL();
14818 PRVAL(rxackucast); PRVAL(rxdfrmocast);
14819 PRVAL(rxmfrmocast); PRVAL(rxcfrmocast); PRNL();
14820 PRVAL(rxrtsocast); PRVAL(rxctsocast);
14821 PRVAL(rxdfrmmcast); PRVAL(rxmfrmmcast); PRNL();
14822 PRVAL(rxcfrmmcast); PRVAL(rxbeaconmbss);
14823 PRVAL(rxdfrmucastobss); PRVAL(rxbeaconobss); PRNL();
14824 PRVAL(rxrsptmout); PRVAL(bcntxcancl);
14825 PRVAL(rxf0ovfl); PRVAL(rxf1ovfl); PRNL();
14826 PRVAL(rxf2ovfl); PRVAL(txsfovfl); PRVAL(pmqovfl); PRNL();
14827 PRVAL(rxcgprqfrm); PRVAL(rxcgprsqovfl);
14828 PRVAL(txcgprsfail); PRVAL(txcgprssuc); PRNL();
14829 PRVAL(prs_timeout); PRVAL(rxnack); PRVAL(frmscons);
14830 PRVAL(txnack); PRVAL(txglitch_nack); PRNL();
14831 PRVAL(txburst); PRVAL(txphyerror); PRNL();
14832 PRVAL(txchanrej); PRNL();
14834 if (cnt.version >= 4) {
14835 /* per-rate receive counters */
14836 PRVAL(rx1mbps); PRVAL(rx2mbps); PRVAL(rx5mbps5); PRNL();
14837 PRVAL(rx6mbps); PRVAL(rx9mbps); PRVAL(rx11mbps); PRNL();
14838 PRVAL(rx12mbps); PRVAL(rx18mbps); PRVAL(rx24mbps); PRNL();
14839 PRVAL(rx36mbps); PRVAL(rx48mbps); PRVAL(rx54mbps); PRNL();
14842 if (cnt.version >= 5) {
14843 PRVAL(pktengrxducast); PRVAL(pktengrxdmcast); PRNL();
14846 if (cnt.version >= 6) {
14847 PRVAL(txmpdu_sgi); PRVAL(rxmpdu_sgi); PRVAL(txmpdu_stbc);
14848 PRVAL(rxmpdu_stbc); PRNL();
14851 pbuf += sprintf(pbuf, "\n");
14852 fputs(buf, stdout);
14853 return (0);
14856 static int
14857 wl_delta_stats(void *wl, cmd_t *cmd, char **argv)
14859 char *statsbuf;
14860 wl_delta_stats_t cnt;
14861 int err;
14862 char *pbuf = buf;
14863 void *ptr;
14865 UNUSED_PARAMETER(cmd);
14866 UNUSED_PARAMETER(argv);
14868 if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr)))
14869 return (err);
14871 statsbuf = (char *)ptr;
14872 memcpy(&cnt, statsbuf, sizeof(cnt));
14873 cnt.version = dtoh16(cnt.version);
14874 cnt.length = dtoh16(cnt.length);
14876 if (cnt.version != WL_DELTA_STATS_T_VERSION) {
14877 printf("\tIncorrect version of delta stats struct: expected %d; got %d\n",
14878 WL_DELTA_STATS_T_VERSION, cnt.version);
14879 return -1;
14882 PRVAL(txframe); PRVAL(txbyte); PRVAL(txretrans); PRVAL(txfail); PRNL();
14884 PRVAL(rxframe); PRVAL(rxbyte); PRNL();
14886 PRVAL(rx1mbps); PRVAL(rx2mbps); PRVAL(rx5mbps5); PRVAL(rx6mbps); PRNL();
14887 PRVAL(rx9mbps); PRVAL(rx11mbps); PRVAL(rx12mbps); PRVAL(rx18mbps); PRNL();
14888 PRVAL(rx24mbps); PRVAL(rx36mbps); PRVAL(rx48mbps); PRVAL(rx54mbps); PRNL();
14890 pbuf += sprintf(pbuf, "\n");
14891 fputs(buf, stdout);
14892 return (0);
14895 static int
14896 wl_wme_counters(void *wl, cmd_t *cmd, char **argv)
14898 char *statsbuf;
14899 wl_wme_cnt_t cnt;
14900 int err;
14901 void *ptr;
14902 char *pbuf = buf;
14903 uint ac;
14904 int ap_mode = 0;
14906 UNUSED_PARAMETER(argv);
14908 if ((err = wlu_var_getbuf_sm (wl, cmd->name, NULL, 0, &ptr)))
14909 return (err);
14911 statsbuf = (char *)ptr;
14912 memcpy(&cnt, statsbuf, sizeof(cnt));
14913 cnt.version = dtoh16(cnt.version);
14914 cnt.length = dtoh16(cnt.length);
14916 if (cnt.version != WL_WME_CNT_VERSION) {
14917 printf("\tIncorrect version of counters struct: expected %d; got %d\n",
14918 WL_WME_CNT_VERSION, cnt.version);
14919 return -1;
14922 if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode)))) {
14923 return -1;
14925 ap_mode = dtoh32(ap_mode);
14927 /* summary stat counter line */
14928 for (ac = AC_BE; ac < AC_COUNT; ac++) {
14929 pbuf += sprintf(pbuf, "\n%s: tx frames: %d bytes: %d failed frames: %d "
14930 "failed bytes: %d\n",
14931 ac_names[ac], dtoh32(cnt.tx[ac].packets), dtoh32(cnt.tx[ac].bytes),
14932 dtoh32(cnt.tx_failed[ac].packets), dtoh32(cnt.tx_failed[ac].bytes));
14933 pbuf += sprintf(pbuf, " rx frames: %d bytes: %d failed frames: %d "
14934 "failed bytes: %d\n", dtoh32(cnt.rx[ac].packets),
14935 dtoh32(cnt.rx[ac].bytes), dtoh32(cnt.rx_failed[ac].packets),
14936 dtoh32(cnt.rx_failed[ac].bytes));
14938 if (ap_mode)
14939 pbuf += sprintf(pbuf, " foward frames: %d bytes: %d \n",
14940 dtoh32(cnt.forward[ac].packets),
14941 dtoh32(cnt.forward[ac].bytes));
14943 pbuf += sprintf(pbuf, " tx frames time expired: %d \n",
14944 dtoh32(cnt.tx_expired[ac].packets));
14946 pbuf += sprintf(pbuf, "\n");
14947 fputs(buf, stdout);
14948 return (0);
14951 static int
14952 wl_devpath(void *wl, cmd_t *cmd, char **argv)
14954 int err;
14955 void *ptr;
14956 char *pbuf = buf;
14958 UNUSED_PARAMETER(argv);
14960 if ((err = wlu_var_getbuf_sm (wl, cmd->name, NULL, 0, &ptr)))
14961 return (err);
14963 pbuf += strlen(buf);
14964 sprintf(pbuf, "\n");
14965 fputs(buf, stdout);
14966 return (0);
14969 static int
14970 wl_diag(void *wl, cmd_t *cmd, char **argv)
14972 uint testindex;
14973 int buflen, err;
14974 char *param;
14975 uint32 testresult;
14977 if (!*++argv) {
14978 printf(" Usage: %s testindex[1-4]\n", cmd->name);
14979 return -1;
14982 testindex = atoi(*argv);
14984 strcpy(buf, "diag");
14985 buflen = strlen(buf) + 1;
14986 param = (char *)(buf + buflen);
14987 testindex = htod32(testindex);
14988 memcpy(param, (char*)&testindex, sizeof(testindex));
14990 if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)))
14991 return err;
14993 testresult = *(uint32 *)buf;
14994 testindex = dtoh32(testindex);
14995 testresult = dtoh32(testresult);
14996 if (testresult != 0) {
14997 printf("\ndiag test %d failed(error code %d)\n", testindex, testresult);
14998 } else
14999 printf("\ndiag test %d passed\n", testindex);
15001 return (0);
15004 static int
15005 wl_phy_rssiant(void *wl, cmd_t *cmd, char **argv)
15007 uint32 antindex;
15008 int buflen, err;
15009 char *param;
15010 int16 antrssi;
15012 if (!*++argv) {
15013 printf(" Usage: %s antenna_index[0-3]\n", cmd->name);
15014 return -1;
15017 antindex = htod32(atoi(*argv));
15019 strcpy(buf, "nphy_rssiant");
15020 buflen = strlen(buf) + 1;
15021 param = (char *)(buf + buflen);
15022 memcpy(param, (char*)&antindex, sizeof(antindex));
15024 if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)))
15025 return err;
15027 antindex = dtoh32(antindex);
15028 antrssi = dtoh16(*(int16 *)buf);
15029 printf("\nnphy_rssiant ant%d = %d\n", antindex, antrssi);
15031 return (0);
15034 static int
15035 get_oui_bytes(uchar *oui_str, uchar *oui)
15037 int idx;
15038 uchar val;
15039 uchar *src, *dest;
15040 char hexstr[3];
15042 src = oui_str;
15043 dest = oui;
15045 for (idx = 0; idx < MAX_OUI_SIZE; idx++) {
15046 hexstr[0] = src[0];
15047 hexstr[1] = src[1];
15048 hexstr[2] = '\0';
15050 val = (uchar) strtoul(hexstr, NULL, 16);
15052 *dest++ = val;
15053 src += 2;
15055 if ((idx < (MAX_OUI_SIZE - 1)) && (*src++ != ':'))
15056 return -1;
15059 return 0;
15062 static int
15063 get_ie_data(uchar *data_str, uchar *ie_data, int len)
15065 uchar *src, *dest;
15066 uchar val;
15067 int idx;
15068 char hexstr[3];
15070 src = data_str;
15071 dest = ie_data;
15073 for (idx = 0; idx < len; idx++) {
15074 hexstr[0] = src[0];
15075 hexstr[1] = src[1];
15076 hexstr[2] = '\0';
15078 val = (uchar) strtoul(hexstr, NULL, 16);
15080 *dest++ = val;
15081 src += 2;
15084 return 0;
15087 static int
15088 hexstrtobitvec(const char *cp, uchar *bitvec, int veclen)
15090 uchar value = 0;
15091 int nibble; /* index of current hex-format nibble to process */
15092 int even; /* 1 if even number of nibbles, 0 if odd number */
15093 int i = 0;
15095 if (cp[0] == '0' && cp[1] == 'x')
15096 cp += 2;
15098 memset(bitvec, '\0', veclen);
15099 nibble = strlen(cp);
15100 if (!nibble)
15101 return -1;
15102 even = ((nibble % 2) == 0);
15104 /* convert from right to left (lsb is rightmost byte) */
15105 --nibble;
15106 while (nibble >= 0 && i < veclen && (isxdigit((int)cp[nibble]) &&
15107 (value = isdigit((int)cp[nibble]) ? cp[nibble]-'0' :
15108 (islower((int)cp[nibble]) ? toupper((int)cp[nibble]) : cp[nibble])-'A'+10) < 16)) {
15109 if (even == ((nibble+1) % 2)) {
15110 bitvec[i] += value*16;
15111 ++i;
15112 } else
15113 bitvec[i] = value;
15114 --nibble;
15117 return ((nibble == -1 && i <= veclen) ? 0 : -1);
15120 static int
15121 wl_bitvec128(void *wl, cmd_t *cmd, char **argv)
15123 char *vbuf;
15124 int err;
15125 uchar bitvec[16];
15126 bool skipzeros;
15127 int i;
15129 err = 0;
15130 skipzeros = TRUE;
15132 /* set */
15133 if (argv[1]) {
15134 memset(bitvec, '\0', sizeof(bitvec));
15135 if (!(err = hexstrtobitvec(argv[1], bitvec, sizeof(bitvec))))
15136 err = wlu_var_setbuf(wl, cmd->name, bitvec, sizeof(bitvec));
15138 /* get */
15139 else {
15140 void *ptr;
15142 memset(buf, '\0', WLC_IOCTL_MAXLEN);
15143 if (!(err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr))) {
15144 vbuf = (char *)ptr;
15145 printf("0x");
15146 for (i = (sizeof(bitvec) - 1); i >= 0; i--) {
15147 if (vbuf[i] || (i == 0))
15148 skipzeros = FALSE;
15149 if (skipzeros)
15150 continue;
15151 printf("%02x", vbuf[i] & 0xff);
15153 printf("\n");
15157 return (err);
15160 static int
15161 wl_auto_channel_sel(void *wl, cmd_t *cmd, char **argv)
15164 * The following condition(s) must be met when Auto Channel Selection
15165 * is enabled.
15166 * - the I/F is up (change radio channel requires it is up?)
15167 * - the AP must not be associated (setting SSID to empty should
15168 * make sure it for us)
15170 int chosen = 0;
15171 wl_uint32_list_t request;
15172 int ret = 0;
15174 if (!*++argv) {
15175 ret = wlu_get(wl, cmd->get, &chosen, sizeof(chosen));
15176 chosen = dtoh32(chosen);
15177 if (ret >= 0 && chosen != 0) {
15178 wf_chspec_ntoa((chanspec_t)chosen, buf);
15179 printf("%s (0x%x)\n", buf, chosen);
15180 return 0;
15182 else {
15183 if (chosen == 0)
15184 printf("invalid chanspec (0x%x)\n", chosen);
15186 } else {
15187 if (atoi(*argv) == 1) {
15188 request.count = htod32(0);
15189 ret = wlu_set(wl, cmd->set, &request, sizeof(request));
15190 } else if (atoi(*argv) == 2) {
15191 ret = wlu_get(wl, cmd->get, &chosen, sizeof(chosen));
15192 if (ret >= 0 && chosen != 0)
15193 ret = wlu_iovar_setint(wl, "chanspec", (int)chosen);
15194 } else {
15195 ret = -1;
15198 return ret;
15201 static int
15202 wl_varstr(void *wl, cmd_t *cmd, char **argv)
15204 int error;
15205 char *str;
15207 if (!*++argv) {
15208 void *ptr;
15210 if ((error = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
15211 return (error);
15213 str = (char *)ptr;
15214 printf("%s\n", str);
15215 return (0);
15216 } else {
15217 str = *argv;
15218 /* str length include NULL */
15219 return wlu_var_setbuf(wl, cmd->name, str, (strlen(str)+1));
15223 /* Return TRUE if it's one of the wc cmds. If WC_TOOL is not defined,
15224 * it'll return TRUE by default so all the commands are allowed.
15226 bool wc_cmd_check(const char *cmd_name)
15228 uint j;
15229 if (wc_cmds == NULL)
15230 return TRUE;
15232 for (j = 0; j < ARRAYSIZE(wc_cmds); j++)
15233 if (strcmp(wc_cmds[j], cmd_name) == 0)
15234 return TRUE;
15235 return FALSE;
15238 #define NUM_TSLIST_ARG 3 /* minimum number of arguments required for TSLIST */
15239 #define NUM_TSLIST_PER_EA_ARG 3 /* minimum number of arguments required for TSLIST */
15240 #define MIN_NUM_DELTS_ARG 4 /* minimum number of arguments required for DELTS */
15241 #define MIN_NUM_DELTS_EA_ARG 5 /* minimum number of arguments required for DELTS */
15242 #define MIN_NUM_ADDTS_ARG 19 /* minimum number of arguments required for ADDTS */
15243 #define PERIODIC_TRAFFIC 1 /* Periodic traffic type */
15244 #define VO_TID (0 << 1) /* voice TID */
15245 #define VI_TID (1 << 1) /* signal TID */
15246 #define UPLINK_DIRECTION (0 << 5) /* uplink direction traffic stream */
15247 #define DOWNLINK_DIRECTION (1 << 5) /* downlink direction traffic stream */
15248 #define BI_DIRECTION (3 << 5) /* bi direction traffic stream */
15249 #define EDCA_ACCESS (1 << 7) /* EDCA access policy */
15250 #define UAPSD_PSB (1 << 2) /* U-APSD power saving behavior */
15251 #define VO_USER_PRIO (6 << 3) /* voice user priority */
15252 #define VI_USER_PRIO (4 << 3) /* signal user priority */
15253 #define TID_SHIFT 1 /* TID Shift */
15254 #define UP_SHIFT 3 /* UP Shift */
15256 static void
15257 wl_cac_format_tspec_htod(tspec_arg_t *tspec_arg)
15259 tspec_arg->version = htod16(tspec_arg->version);
15260 tspec_arg->length = htod16(tspec_arg->length);
15261 tspec_arg->flag = htod32(tspec_arg->flag);
15262 tspec_arg->nom_msdu_size = htod16(tspec_arg->nom_msdu_size);
15263 tspec_arg->max_msdu_size = htod16(tspec_arg->max_msdu_size);
15264 tspec_arg->min_srv_interval = htod32(tspec_arg->min_srv_interval);
15265 tspec_arg->max_srv_interval = htod32(tspec_arg->max_srv_interval);
15266 tspec_arg->inactivity_interval = htod32(tspec_arg->inactivity_interval);
15267 tspec_arg->suspension_interval = htod32(tspec_arg->suspension_interval);
15268 tspec_arg->srv_start_time = htod32(tspec_arg->srv_start_time);
15269 tspec_arg->min_data_rate = htod32(tspec_arg->min_data_rate);
15270 tspec_arg->mean_data_rate = htod32(tspec_arg->mean_data_rate);
15271 tspec_arg->peak_data_rate = htod32(tspec_arg->peak_data_rate);
15272 tspec_arg->max_burst_size = htod32(tspec_arg->max_burst_size);
15273 tspec_arg->delay_bound = htod32(tspec_arg->delay_bound);
15274 tspec_arg->min_phy_rate = htod32(tspec_arg->min_phy_rate);
15275 tspec_arg->surplus_bw = htod16(tspec_arg->surplus_bw);
15276 tspec_arg->medium_time = htod16(tspec_arg->medium_time);
15279 static void
15280 wl_cac_format_tspec_dtoh(tspec_arg_t *tspec_arg)
15282 tspec_arg->version = dtoh16(tspec_arg->version);
15283 tspec_arg->length = dtoh16(tspec_arg->length);
15284 tspec_arg->flag = dtoh32(tspec_arg->flag);
15285 tspec_arg->nom_msdu_size = dtoh16(tspec_arg->nom_msdu_size);
15286 tspec_arg->max_msdu_size = dtoh16(tspec_arg->max_msdu_size);
15287 tspec_arg->min_srv_interval = dtoh32(tspec_arg->min_srv_interval);
15288 tspec_arg->max_srv_interval = dtoh32(tspec_arg->max_srv_interval);
15289 tspec_arg->inactivity_interval = dtoh32(tspec_arg->inactivity_interval);
15290 tspec_arg->suspension_interval = dtoh32(tspec_arg->suspension_interval);
15291 tspec_arg->srv_start_time = dtoh32(tspec_arg->srv_start_time);
15292 tspec_arg->min_data_rate = dtoh32(tspec_arg->min_data_rate);
15293 tspec_arg->mean_data_rate = dtoh32(tspec_arg->mean_data_rate);
15294 tspec_arg->peak_data_rate = dtoh32(tspec_arg->peak_data_rate);
15295 tspec_arg->max_burst_size = dtoh32(tspec_arg->max_burst_size);
15296 tspec_arg->delay_bound = dtoh32(tspec_arg->delay_bound);
15297 tspec_arg->min_phy_rate = dtoh32(tspec_arg->min_phy_rate);
15298 tspec_arg->surplus_bw = dtoh16(tspec_arg->surplus_bw);
15299 tspec_arg->medium_time = dtoh16(tspec_arg->medium_time);
15303 static void wl_cac_addts_usage(void)
15305 fprintf(stderr, "Too few arguments\n");
15306 fprintf(stderr, "wl cac_addts ver dtoken tid dir psb up a b c d e ...\n");
15307 fprintf(stderr, "\twhere ver is the structure version\n");
15308 fprintf(stderr, "\twhere dtoken is the dialog token [range 1-255]\n");
15309 fprintf(stderr, "\twhere tid is the tspec identifier [range 0-7]\n");
15310 fprintf(stderr, "\twhere dir is direction [uplink | downlink | bi-directional]\n");
15311 fprintf(stderr, "\twhere psb is power save mode [legacy|U-APSD]\n");
15312 fprintf(stderr, "\twhere up is user priority [range 0-7]\n");
15313 fprintf(stderr, "\twhere a is the nominal MSDU size\n");
15314 fprintf(stderr, "\twhere b is bool for fixed size msdu [ 0 and 1]\n");
15315 fprintf(stderr, "\twhere c is the maximum MSDU size\n");
15316 fprintf(stderr, "\twhere d is the minimum service interval\n");
15317 fprintf(stderr, "\twhere e is the maximum service interval\n");
15318 fprintf(stderr, "\twhere f is the inactivity interval\n");
15319 fprintf(stderr, "\twhere g is the suspension interval\n");
15320 fprintf(stderr, "\twhere h is the minimum data rate\n");
15321 fprintf(stderr, "\twhere i is the mean data rate\n");
15322 fprintf(stderr, "\twhere j is the peak data rate\n");
15323 fprintf(stderr, "\twhere k is the max burst size\n");
15324 fprintf(stderr, "\twhere l is the delay bound\n");
15325 fprintf(stderr, "\twhere m is the surplus bandwidth [fixed point notation]\n");
15328 static void wl_cac_delts_usage(void)
15330 fprintf(stderr, "Too few arguments\n");
15331 fprintf(stderr, "wl cac_delts ver a b c \n");
15332 fprintf(stderr, "\twhere ver is the tspec version\n");
15333 fprintf(stderr, "\twhere a is byte[0] of tsinfo (bits 0-7)\n");
15334 fprintf(stderr, "\twhere b is byte[1] of tsinfo (bits 8-15)\n");
15335 fprintf(stderr, "\twhere c is byte[2] of tsinfo (bits 16-23)\n");
15338 static int
15339 wl_cac(void *wl, cmd_t *cmd, char **argv)
15341 int err = -1;
15342 int ap_mode = 0;
15343 int cmd_type = 0;
15344 tspec_arg_t tspec_arg;
15345 char *endptr = NULL;
15346 uint buflen;
15347 char *arg1, *user_argv;
15348 uint8 direction = BI_DIRECTION;
15349 uint8 user_tid, user_prio, user_psb;
15350 uint fixed;
15352 if ((wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
15353 return err;
15354 ap_mode = dtoh32(ap_mode);
15356 if (ap_mode) {
15357 fprintf(stderr, "This command can only be executed on the STA\n");
15358 return err;
15361 if (!strcmp(*argv, "cac_addts"))
15362 cmd_type = 1;
15363 else if (!strcmp(*argv, "cac_delts"))
15364 cmd_type = 2;
15365 else {
15366 fprintf(stderr, "unknown command\n");
15367 return BCME_BADARG;
15370 /* eat command name */
15371 if (!*++argv) {
15372 (cmd_type == 1) ? wl_cac_addts_usage():wl_cac_delts_usage();
15373 return BCME_BADARG;
15376 buflen = sizeof(tspec_arg_t);
15377 memset((uint8 *)&tspec_arg, 0, buflen);
15379 /* get direction option */
15380 arg1 = *argv;
15382 /* Unidirectional DL/UL */
15383 if (!strcmp(arg1, "UDL") || (!strcmp(arg1, "UUL")))
15384 direction = DOWNLINK_DIRECTION;
15386 if (cmd_type == 1) {
15387 uint argc = 0;
15389 /* arg count */
15390 while (argv[argc])
15391 argc++;
15393 /* required argments */
15394 if (argc < MIN_NUM_ADDTS_ARG) {
15395 wl_cac_addts_usage();
15396 return BCME_BADARG;
15399 tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
15400 tspec_arg.version = (uint16)strtol(*argv++, &endptr, 0);
15401 if (*endptr != '\0')
15402 goto error;
15404 tspec_arg.dialog_token = (uint8)strtol(*argv++, &endptr, 0);
15405 if (*endptr != '\0')
15406 goto error;
15408 user_tid = (uint8)strtol(*argv++, &endptr, 0);
15409 user_tid <<= TID_SHIFT;
15410 if (*endptr != '\0')
15411 goto error;
15413 /* store the pointer for parsing */
15414 user_argv = *argv++;
15416 if (!strcmp(user_argv, "uplink"))
15417 direction = UPLINK_DIRECTION;
15418 else if (!strcmp(user_argv, "downlink"))
15419 direction = DOWNLINK_DIRECTION;
15420 else if (!strcmp(user_argv, "bi-directional"))
15421 direction = BI_DIRECTION;
15422 else
15423 goto error;
15425 /* store the pointer for parsing */
15426 user_argv = *argv++;
15428 if (!strcmp(user_argv, "legacy"))
15429 user_psb = 0;
15430 else if (!strcmp(user_argv, "U-APSD"))
15431 user_psb = UAPSD_PSB;
15432 else
15433 goto error;
15435 user_prio = (uint8)strtol(*argv++, &endptr, 0);
15436 user_prio <<= UP_SHIFT;
15437 if (*endptr != '\0')
15438 goto error;
15440 tspec_arg.tsinfo.octets[0] = (uint8)(user_tid |
15441 direction | EDCA_ACCESS);
15443 tspec_arg.tsinfo.octets[1] = (uint8)(user_prio | user_psb);
15444 tspec_arg.tsinfo.octets[2] = 0x00;
15446 tspec_arg.nom_msdu_size = (uint16)strtol(*argv++, &endptr, 0);
15447 if (*endptr != '\0')
15448 goto error;
15450 fixed = (uint)strtol(*argv++, &endptr, 0);
15451 if (*endptr != '\0')
15452 goto error;
15454 if (fixed == 1)
15455 tspec_arg.nom_msdu_size |= 0x8000;
15457 tspec_arg.max_msdu_size = (uint16)strtol(*argv++, &endptr, 0);
15458 if (*endptr != '\0')
15459 goto error;
15461 tspec_arg.min_srv_interval = strtol(*argv++, &endptr, 0);
15462 if (*endptr != '\0')
15463 goto error;
15465 tspec_arg.max_srv_interval = strtol(*argv++, &endptr, 0);
15466 if (*endptr != '\0')
15467 goto error;
15469 tspec_arg.inactivity_interval = strtol(*argv++, &endptr, 0);
15470 if (*endptr != '\0')
15471 goto error;
15473 tspec_arg.suspension_interval = strtol(*argv++, &endptr, 0);
15474 if (*endptr != '\0')
15475 goto error;
15477 tspec_arg.min_data_rate = strtol(*argv++, &endptr, 0);
15478 if (*endptr != '\0')
15479 goto error;
15481 tspec_arg.mean_data_rate = strtol(*argv++, &endptr, 0);
15482 if (*endptr != '\0')
15483 goto error;
15485 tspec_arg.peak_data_rate = strtol(*argv++, &endptr, 0);
15486 if (*endptr != '\0')
15487 goto error;
15489 tspec_arg.max_burst_size = strtol(*argv++, &endptr, 0);
15490 if (*endptr != '\0')
15491 goto error;
15493 tspec_arg.delay_bound = strtol(*argv++, &endptr, 0);
15494 if (*endptr != '\0')
15495 goto error;
15497 tspec_arg.surplus_bw = (uint16)strtol(*argv++, &endptr, 0);
15498 if (*endptr != '\0')
15499 goto error;
15501 tspec_arg.min_phy_rate = strtol(*argv++, &endptr, 0);
15502 if (*endptr != '\0')
15503 goto error;
15504 printf("Setting min_phy_rate to 0x%x\n", tspec_arg.min_phy_rate);
15505 } else {
15506 uint argc = 0;
15508 /* arg count */
15509 while (argv[argc])
15510 argc++;
15512 /* required argments */
15513 if (argc < MIN_NUM_DELTS_ARG) {
15514 wl_cac_delts_usage();
15515 return BCME_BADARG;
15518 tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
15519 tspec_arg.version = (uint16)strtol(*argv++, &endptr, 0);
15521 if (*endptr != '\0')
15522 goto error;
15524 tspec_arg.tsinfo.octets[0] = (uint8)strtol(*argv++, &endptr, 0);
15525 if (*endptr != '\0')
15526 goto error;
15528 tspec_arg.tsinfo.octets[1] = (uint8)strtol(*argv++, &endptr, 0);
15529 if (*endptr != '\0')
15530 goto error;
15532 tspec_arg.tsinfo.octets[2] = (uint8)strtol(*argv++, &endptr, 0);
15533 if (*endptr != '\0')
15534 goto error;
15537 wl_cac_format_tspec_htod(&tspec_arg);
15538 err = wlu_var_setbuf(wl, cmd->name, &tspec_arg, buflen);
15540 error:
15541 return err;
15544 /* get a list of traffic stream (TSINFO) in driver */
15545 static int
15546 wl_tslist(void *wl, cmd_t *cmd, char **argv)
15548 void *ptr;
15549 int i;
15550 int ap_mode, err = -1;
15551 struct tslist *tslist;
15553 UNUSED_PARAMETER(argv);
15555 if ((wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
15556 return err;
15557 ap_mode = dtoh32(ap_mode);
15559 if (ap_mode) {
15560 fprintf(stderr, "This command can only be executed on the STA\n");
15561 return err;
15564 if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
15565 return err;
15567 tslist = (struct tslist *)ptr;
15568 tslist->count = dtoh32(tslist->count);
15569 for (i = 0; i < tslist->count; i++)
15570 printf("tsinfo 0x%02X 0x%02X 0x%02X TID %d User Prio %d Direction %d\n",
15571 tslist->tsinfo[i].octets[0],
15572 tslist->tsinfo[i].octets[1],
15573 tslist->tsinfo[i].octets[2],
15574 WLC_CAC_GET_TID(tslist->tsinfo[i]),
15575 WLC_CAC_GET_USER_PRIO(tslist->tsinfo[i]),
15576 WLC_CAC_GET_DIR(tslist->tsinfo[i]));
15578 return 0;
15581 /* get specific TSPEC in driver */
15582 static int
15583 wl_tspec(void *wl, cmd_t *cmd, char **argv)
15585 void *ptr;
15586 int ap_mode, err = -1;
15587 tspec_arg_t *ts, tspec_arg;
15588 char *temp = NULL;
15589 uint argc = 0;
15591 if ((wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
15592 return err;
15593 ap_mode = dtoh32(ap_mode);
15595 if (ap_mode) {
15596 fprintf(stderr, "This command can only be executed on the STA\n");
15597 return err;
15600 /* eat command name */
15601 argv++;
15603 /* arg count */
15604 while (argv[argc])
15605 argc++;
15607 /* required argments */
15608 if (argc < NUM_TSLIST_ARG) {
15609 fprintf(stderr, "Too few arguments\n");
15610 fprintf(stderr, "wl cac_tspec 0xaa 0xbb 0xcc \n");
15611 fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n");
15612 fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n");
15613 fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n");
15614 return BCME_BADARG;
15617 memset((uint8 *)&tspec_arg, 0, sizeof(tspec_arg_t));
15619 tspec_arg.tsinfo.octets[0] = (uint8)strtol(*argv++, &temp, 0);
15620 if (*temp != '\0')
15621 goto error;
15623 tspec_arg.tsinfo.octets[1] = (uint8)strtol(*argv++, &temp, 0);
15624 if (*temp != '\0')
15625 goto error;
15627 tspec_arg.tsinfo.octets[2] = (uint8)strtol(*argv++, &temp, 0);
15628 if (*temp != '\0')
15629 goto error;
15631 if ((err = wlu_var_getbuf(wl, cmd->name, &tspec_arg, sizeof(tspec_arg_t), &ptr)) < 0)
15632 return err;
15634 ts = (tspec_arg_t *)ptr;
15635 wl_cac_format_tspec_dtoh(ts);
15636 wl_print_tspec(ts);
15637 return 0;
15638 error:
15639 return err;
15642 /* get/set max bandwidth for each access category in ap */
15643 static int
15644 wme_maxbw_params(void *wl, cmd_t *cmd, char **argv)
15646 wme_max_bandwidth_t cur_params, new_params;
15647 char *val_p, *ac_str, *param;
15648 int buflen;
15649 int aci;
15650 int err;
15651 int val;
15652 int ap_mode = 0;
15654 argv++;
15656 if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
15657 return err;
15659 if (!ap_mode) {
15660 printf("%s: AP only\n", cmd->name);
15661 return -1;
15664 buflen = WLC_IOCTL_MAXLEN;
15666 /* get the current max bandwidth, using buf as an input buffer. */
15667 strcpy(buf, "wme_maxbw_params");
15668 if ((err = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen)) < 0) {
15669 return err;
15672 /* cache the current values */
15673 memcpy(&cur_params, buf, sizeof(wme_max_bandwidth_t));
15675 if ((ac_str = *argv) == NULL) {
15676 printf("WME bandwidth limit: \n");
15677 for (aci = 0; aci < AC_COUNT; aci++) {
15678 printf("%s: bandwidth limit %d\n", ac_names[aci],
15679 cur_params.ac[aci]);
15681 } else {
15682 /* preload new values with current values */
15683 memcpy(&new_params, &cur_params, sizeof(new_params));
15684 while ((param = *argv++) != NULL) {
15685 if ((val_p = *argv++) == NULL) {
15686 printf("Need value following %s\n", param);
15687 return USAGE_ERROR;
15690 val = (int)strtoul(val_p, NULL, 0);
15692 if (!strcmp(param, "be")) {
15693 new_params.ac[AC_BE] = (uint32)val;
15694 } else if (!strcmp(param, "bk")) {
15695 new_params.ac[AC_BK] = (uint32)val;
15696 } else if (!strcmp(param, "vi")) {
15697 new_params.ac[AC_VI] = (uint32)val;
15698 } else if (!strcmp(param, "vo")) {
15699 new_params.ac[AC_VO] = (uint32)val;
15700 } else {
15701 printf("Unknown access category: %s\n", param);
15702 return USAGE_ERROR;
15706 strcpy(buf, "wme_maxbw_params");
15707 memcpy(buf + strlen(buf) + 1, &new_params, sizeof(wme_max_bandwidth_t));
15708 err = wlu_set(wl, WLC_SET_VAR, &buf[0], buflen);
15712 return 0;
15715 /* get the tspec list for the given station */
15716 static int
15717 wl_tslist_ea(void *wl, cmd_t *cmd, char **argv)
15719 void *ptr;
15720 int i;
15721 int ap_mode, err = -1;
15722 struct tslist *tslist;
15723 scb_val_t scb_val;
15724 int ret;
15727 if (!*++argv) {
15728 printf("MAC address must be specified\n");
15729 ret = -1;
15730 } else if (!wl_ether_atoe(*argv, &scb_val.ea)) {
15731 printf("Malformed MAC address parameter\n");
15732 ret = -1;
15735 if ((wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))))
15736 return err;
15738 ap_mode = dtoh32(ap_mode);
15740 if ((err = wlu_var_getbuf(wl, cmd->name, &scb_val.ea, ETHER_ADDR_LEN, &ptr)) < 0)
15741 return err;
15743 tslist = (struct tslist *)ptr;
15745 for (i = 0; i < tslist->count; i++)
15746 printf("tsinfo 0x%02X 0x%02X 0x%02X TID %d User Prio %d Direction %d\n",
15747 tslist->tsinfo[i].octets[0],
15748 tslist->tsinfo[i].octets[1],
15749 tslist->tsinfo[i].octets[2],
15750 WLC_CAC_GET_TID(tslist->tsinfo[i]),
15751 WLC_CAC_GET_USER_PRIO(tslist->tsinfo[i]),
15752 WLC_CAC_GET_DIR(tslist->tsinfo[i]));
15754 return 0;
15758 /* get specific TSPEC for a STA */
15759 static int
15760 wl_tspec_ea(void *wl, cmd_t *cmd, char **argv)
15762 void *ptr;
15763 int err = -1;
15764 tspec_per_sta_arg_t tsea;
15765 tspec_arg_t *ts;
15766 char *temp;
15767 uint argc = 0;
15769 /* eat command name */
15770 argv++;
15772 while (argv[argc])
15773 argc++;
15775 /* required argments */
15776 if (argc < (NUM_TSLIST_PER_EA_ARG + 1)) {
15777 fprintf(stderr, "Too few arguments\n");
15778 fprintf(stderr, "wl cac_tspec 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx\n");
15779 fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n");
15780 fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n");
15781 fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n");
15782 fprintf(stderr, "\twhere xx:xx:xx:xx:xx:xx is mac address )\n");
15783 return BCME_BADARG;
15786 memset((uint8 *)&tsea, 0, sizeof(tspec_per_sta_arg_t));
15788 ts = &tsea.ts;
15790 ts->tsinfo.octets[0] = (uint8)strtol(*argv++, &temp, 0);
15791 if (*temp != '\0')
15792 goto error;
15794 ts->tsinfo.octets[1] = (uint8)strtol(*argv++, &temp, 0);
15795 if (*temp != '\0')
15796 goto error;
15798 ts->tsinfo.octets[2] = (uint8)strtol(*argv++, &temp, 0);
15799 if (*temp != '\0')
15800 goto error;
15802 /* add the ether address after tsinfo */
15803 if (!*argv) {
15804 printf("MAC address must be specified\n");
15805 return -1;
15806 } else if (!wl_ether_atoe(*argv, &tsea.ea)) {
15807 printf("Malformed MAC address parameter\n");
15808 return -1;
15811 if ((err = wlu_var_getbuf(wl, cmd->name, &tsea, sizeof(tspec_per_sta_arg_t), &ptr)) < 0)
15812 return err;
15814 ts = (tspec_arg_t *)ptr;
15815 wl_cac_format_tspec_dtoh(ts);
15816 wl_print_tspec(ts);
15817 return 0;
15819 error:
15820 return err;
15823 static const uint8 wlu_wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE,
15824 AC_BE };
15825 static const uint8 wlu_prio2fifo[NUMPRIO] = {
15826 0, /* 0 BE AC_BE Best Effort */
15827 1, /* 1 BK AC_BK Background */
15828 2, /* 2 -- AC_BK Background */
15829 3, /* 3 EE AC_BE Best Effort */
15830 4, /* 4 CL AC_VI Video */
15831 5, /* 5 VI AC_VI Video */
15832 6, /* 6 VO AC_VO Voice */
15833 7 /* 7 NC AC_VO Voice */
15835 #define WME_PRIO2AC(prio) wlu_wme_fifo2ac[wlu_prio2fifo[(prio)]]
15837 static void
15838 wl_print_tspec(tspec_arg_t *ts)
15840 const char *str;
15841 if (ts->version != TSPEC_ARG_VERSION) {
15842 printf("\tIncorrect version of TSPEC struct: expected %d; got %d\n",
15843 TSPEC_ARG_VERSION, ts->version);
15844 return;
15847 if (ts->length < (sizeof(tspec_arg_t) - (2 * sizeof(uint16)))) {
15848 printf("\tTSPEC arg length too short: expected %d; got %d\n",
15849 (int)(sizeof(tspec_arg_t) - (2 * sizeof(uint16))), ts->length);
15850 return;
15853 switch (ts->flag & TSPEC_STATUS_MASK) {
15854 case TSPEC_PENDING:
15855 str = "PENDING";
15856 break;
15857 case TSPEC_ACCEPTED:
15858 str = "ACCEPTED";
15859 break;
15860 case TSPEC_REJECTED:
15861 str = "REJECTED";
15862 break;
15863 default:
15864 str = "UNKNOWN";
15865 break;
15868 printf("version %d\n", ts->version);
15869 printf("length %d\n", ts->length);
15871 printf("TID %d %s\n", WLC_CAC_GET_TID(ts->tsinfo), str);
15872 printf("tsinfo 0x%02x 0x%02x 0x%02x\n", ts->tsinfo.octets[0],
15873 ts->tsinfo.octets[1], ts->tsinfo.octets[2]);
15875 /* breakout bitfields for apsd */
15876 if (WLC_CAC_GET_PSB(ts->tsinfo)) {
15877 int ac = WME_PRIO2AC(WLC_CAC_GET_USER_PRIO(ts->tsinfo));
15878 switch (WLC_CAC_GET_DIR(ts->tsinfo)) {
15879 case (TS_INFO_UPLINK >> TS_INFO_DIRECTION_SHIFT):
15880 printf("AC[%d] : Trigger enabled\n", ac);
15881 break;
15883 case (TS_INFO_DOWNLINK >> TS_INFO_DIRECTION_SHIFT):
15884 printf("AC[%d] : Delivery enabled\n", ac);
15885 break;
15887 case (TS_INFO_BIDIRECTIONAL >>
15888 TS_INFO_DIRECTION_SHIFT):
15889 printf("AC[%d] : Trig & Delv enabled\n", ac);
15890 break;
15892 } else {
15893 int ac;
15894 ac = WME_PRIO2AC(WLC_CAC_GET_USER_PRIO(ts->tsinfo));
15895 printf("AC [%d] : Legacy Power save\n", ac);
15899 printf("nom_msdu_size %d %s\n", (ts->nom_msdu_size & 0x7fff),
15900 ((ts->nom_msdu_size & 0x8000) ? "fixed size" : ""));
15901 printf("max_msdu_size %d\n", ts->max_msdu_size);
15902 printf("min_srv_interval %d\n", ts->min_srv_interval);
15903 printf("max_srv_interval %d\n", ts->max_srv_interval);
15904 printf("inactivity_interval %d\n", ts->inactivity_interval);
15905 printf("suspension_interval %d\n", ts->suspension_interval);
15906 printf("srv_start_time %d\n", ts->srv_start_time);
15907 printf("min_data_rate %d\n", ts->min_data_rate);
15908 printf("mean_data_rate %d\n", ts->mean_data_rate);
15909 printf("peak_data_rate %d\n", ts->peak_data_rate);
15910 printf("max_burst_size %d\n", ts->max_burst_size);
15911 printf("delay_bound %d\n", ts->delay_bound);
15912 printf("min_phy_rate %d\n", ts->min_phy_rate);
15913 printf("surplus_bw %d\n", ts->surplus_bw);
15914 printf("medium_time %d\n", ts->medium_time);
15918 /* send delts for a specific ea */
15919 /* TODO : Club this with wl_tspec_ea */
15920 static int
15921 wl_cac_delts_ea(void *wl, cmd_t *cmd, char **argv)
15923 void *ptr;
15924 int err = -1;
15925 char *endptr = NULL;
15926 tspec_per_sta_arg_t tsea;
15927 tspec_arg_t *ts;
15928 uint argc = 0;
15930 /* eat command name */
15931 argv++;
15933 while (argv[argc])
15934 argc++;
15936 /* required argments */
15937 if (argc < (NUM_TSLIST_PER_EA_ARG + 1)) {
15938 fprintf(stderr, "Too few arguments\n");
15939 fprintf(stderr, "wl cac_delts_ea ver 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx\n");
15940 fprintf(stderr, "\twhere ver is the tspec version\n");
15941 fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n");
15942 fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n");
15943 fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n");
15944 fprintf(stderr, "\twhere xx:xx:xx:xx:xx:xx is mac address )\n");
15945 return BCME_BADARG;
15948 memset((uint8 *)&tsea, 0, sizeof(tspec_per_sta_arg_t));
15950 ts = &tsea.ts;
15952 ts->length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
15953 ts->version = (uint16)strtol(*argv++, &endptr, 0);
15955 if (*endptr != '\0')
15956 goto error;
15958 ts->tsinfo.octets[0] = (uint8)strtol(*argv++, &endptr, 0);
15959 if (*endptr != '\0')
15960 goto error;
15962 ts->tsinfo.octets[1] = (uint8)strtol(*argv++, &endptr, 0);
15963 if (*endptr != '\0')
15964 goto error;
15966 ts->tsinfo.octets[2] = (uint8)strtol(*argv++, &endptr, 0);
15967 if (*endptr != '\0')
15968 goto error;
15971 /* add the ether address after tsinfo */
15972 if (!*argv) {
15973 printf("MAC address must be specified\n");
15974 return -1;
15975 } else if (!wl_ether_atoe(*argv, &tsea.ea)) {
15976 printf("Malformed MAC address parameter\n");
15977 return -1;
15980 wl_cac_format_tspec_htod(ts);
15981 if ((err = wlu_var_getbuf(wl, cmd->name, &tsea, sizeof(tspec_per_sta_arg_t), &ptr)) < 0)
15982 return err;
15984 return 0;
15986 error:
15987 return err;
15991 static int
15992 wl_antsel(void *wl, cmd_t *cmd, char **argv)
15994 const char *ant_sel = "fixed";
15995 char *val_name;
15996 wlc_antselcfg_t val = {{0}, 0};
15997 int err, argc, i;
15998 char *endptr = NULL;
15999 uint32 txchain_bitmap = 0;
16000 uint16 antsel_mask = 0;
16002 /* toss the command name */
16003 val_name = *argv++;
16005 if (!*argv) {
16006 if (cmd->get < 0)
16007 return -1;
16008 if ((err = wlu_iovar_get(wl, "txchain", &txchain_bitmap, sizeof(txchain_bitmap))) < 0)
16009 return err;
16011 /* iterate over max 4 chains */
16012 for (i = 0; i < 4; i ++) {
16013 if (!(txchain_bitmap & (1<<i)))
16014 antsel_mask |= (0xF << i * 4);
16017 if ((err = wlu_iovar_get(wl, val_name, &val, sizeof(wlc_antselcfg_t))) < 0)
16018 return err;
16020 printf("C3C2C1C0: ");
16021 for (i = ANT_SELCFG_TX_UNICAST; i < ANT_SELCFG_MAX; i++) {
16022 if (val.ant_config[i] & ANT_SELCFG_AUTO)
16023 ant_sel = "auto";
16024 printf("0x%04X %s ",
16025 antsel_mask | (val.ant_config[i] & ANT_SELCFG_MASK), ant_sel);
16027 printf("\n");
16028 } else {
16029 /* arg count */
16030 for (argc = 0; argv[argc]; argc++);
16032 if ((argc >= 2 && argc <= 3) || argc > ANT_SELCFG_MAX) {
16033 printf("invalid %d args\n", argc);
16034 return -1;
16037 val.ant_config[ANT_SELCFG_TX_UNICAST] = (uint8)strtol(*argv++, &endptr, 0);
16038 printf("UTX 0x%02x\n", val.ant_config[ANT_SELCFG_TX_UNICAST]);
16039 if (*endptr != '\0') {
16040 printf("Invaild UTX parameter: %s\n", *argv);
16041 return -1;
16043 if (argc == 1) {
16044 val.ant_config[ANT_SELCFG_RX_UNICAST] =
16045 val.ant_config[ANT_SELCFG_TX_UNICAST];
16046 val.ant_config[ANT_SELCFG_TX_DEF] = val.ant_config[ANT_SELCFG_TX_UNICAST];
16047 val.ant_config[ANT_SELCFG_RX_DEF] = val.ant_config[ANT_SELCFG_TX_UNICAST];
16048 } else {
16049 val.ant_config[ANT_SELCFG_RX_UNICAST] = (uint8)strtol(*argv++, &endptr, 0);
16050 printf("URX 0x%02x\n", val.ant_config[ANT_SELCFG_RX_UNICAST]);
16051 if (*endptr != '\0') {
16052 printf("Invaild URX parameter: %s\n", *argv);
16053 return -1;
16055 val.ant_config[ANT_SELCFG_TX_DEF] = (uint8)strtol(*argv++, &endptr, 0);
16056 printf("DTX 0x%02x\n", val.ant_config[ANT_SELCFG_TX_DEF]);
16057 if (*endptr != '\0') {
16058 printf("Invaild DTX parameter: %s\n", *argv);
16059 return -1;
16061 val.ant_config[ANT_SELCFG_RX_DEF] = (uint8)strtol(*argv++, &endptr, 0);
16062 printf("DRX 0x%02x\n", val.ant_config[ANT_SELCFG_RX_DEF]);
16063 if (*endptr != '\0') {
16064 printf("Invaild DRX parameter: %s\n", *argv);
16065 return -1;
16068 err = wlu_iovar_set(wl, val_name, &val, sizeof(wlc_antselcfg_t));
16070 return err;
16073 static int
16074 wl_txcore_pwr_offset(void *wl, cmd_t *cmd, char **argv)
16076 wl_txchain_pwr_offsets_t offsets;
16077 char *endptr;
16078 int i;
16079 long val;
16080 int err;
16082 /* toss the command name */
16083 argv++;
16085 if (!*argv) {
16086 err = wlu_iovar_get(wl, cmd->name, &offsets, sizeof(wl_txchain_pwr_offsets_t));
16088 if (err < 0)
16089 return err;
16091 printf("txcore offsets qdBm: %d %d %d %d\n",
16092 offsets.offset[0], offsets.offset[1],
16093 offsets.offset[2], offsets.offset[3]);
16095 return 0;
16098 memset(&offsets, 0, sizeof(wl_txchain_pwr_offsets_t));
16100 for (i = 0; i < WL_NUM_TXCHAIN_MAX; i++, argv++) {
16101 if (!*argv)
16102 break;
16104 val = strtol(*argv, &endptr, 0);
16105 if (*endptr != '\0')
16106 return -1;
16108 if (val > 0)
16109 return -1;
16111 offsets.offset[i] = (int8)val;
16114 err = wlu_iovar_set(wl, cmd->name, &offsets, sizeof(wl_txchain_pwr_offsets_t));
16116 return err;
16119 static int
16120 wl_txcore(void *wl, cmd_t *cmd, char **argv)
16122 miniopt_t to;
16123 const char* fn_name = "wl_txcore";
16124 int err = 0, opt_err, val;
16125 uint8 streams = 0;
16126 bool streams_set = FALSE;
16127 uint8 core = 0;
16128 bool core_set = FALSE;
16129 uint8 cck_mask = 0;
16130 bool cck_set = FALSE;
16131 uint8 ofdm_mask = 0;
16132 bool ofdm_set = FALSE;
16133 uint8 mcs_mask[4] = {0, 0, 0, 0}; /* pre-initialize # of streams {core:4 | stream:4} */
16134 bool mcs_set = FALSE;
16135 uint8 idx;
16136 uint32 coremask[2] = {0, 0};
16138 /* toss the command name */
16139 argv++;
16141 if (!*argv) {
16142 if (cmd->get < 0)
16143 return -1;
16144 if ((err = wlu_iovar_get(wl, cmd->name, &coremask, sizeof(uint32)*2)) < 0)
16145 return err;
16147 printf("txcore enabled bitmap (Nsts {4..1}) 0x%02x 0x%02x 0x%02x 0x%02x\n",
16148 (coremask[0] >> 24) & 0xff, (coremask[0] >> 16) & 0xff,
16149 (coremask[0] >> 8) & 0xff, coremask[0] & 0xff);
16150 printf("txcore mask OFDM 0x%02x CCK 0x%02x\n",
16151 (coremask[1] >> 8) & 0xff, coremask[1] & 0xff);
16152 return 0;
16155 val = atoi(*argv);
16156 if (val == -1)
16157 goto next;
16159 miniopt_init(&to, fn_name, "w", FALSE);
16160 while ((opt_err = miniopt(&to, argv)) != -1) {
16161 if (opt_err == 1) {
16162 err = -1;
16163 goto exit;
16165 argv += to.consumed;
16167 if (to.opt == 's') {
16168 if (!to.good_int) {
16169 fprintf(stderr,
16170 "%s: could not parse \"%s\" as an int for streams\n",
16171 fn_name, to.valstr);
16172 err = -1;
16173 goto exit;
16175 streams_set = TRUE;
16176 streams = (to.val & 0x0f);
16177 if (streams > 4)
16178 fprintf(stderr, "%s: Nsts > %d\n", fn_name, to.val);
16180 if (to.opt == 'c') {
16181 if (!to.good_int) {
16182 fprintf(stderr,
16183 "%s: could not parse \"%s\" as an int for stf core\n",
16184 fn_name, to.valstr);
16185 err = -1;
16186 goto exit;
16188 core_set = TRUE;
16189 core = (to.val & 0x0f) << 4;
16190 if (core == 0) {
16191 fprintf(stderr, "%s: %1d-stream core cannot be zero\n",
16192 fn_name, streams);
16193 err = -1;
16194 goto exit;
16197 if (to.opt == 'o') {
16198 if (!to.good_int) {
16199 fprintf(stderr,
16200 "%s: could not parse \"%s\" as an int for streams\n",
16201 fn_name, to.valstr);
16202 err = -1;
16203 goto exit;
16205 ofdm_set = TRUE;
16206 ofdm_mask = (to.val & 0x0f);
16207 if (ofdm_mask == 0) {
16208 fprintf(stderr, "%s: OFDM core cannot be zero\n", fn_name);
16209 err = -1;
16210 goto exit;
16213 if (to.opt == 'k') {
16214 if (!to.good_int) {
16215 fprintf(stderr,
16216 "%s: could not parse \"%s\" as an int for streams\n",
16217 fn_name, to.valstr);
16218 err = -1;
16219 goto exit;
16221 cck_set = TRUE;
16222 cck_mask = (to.val & 0x0f);
16223 if (cck_mask == 0) {
16224 fprintf(stderr, "%s: CCK core cannot be zero\n", fn_name);
16225 err = -1;
16226 goto exit;
16230 if (streams_set && core_set) {
16231 streams_set = core_set = FALSE;
16232 mcs_set = TRUE;
16233 idx = streams - 1;
16234 mcs_mask[idx] = (uint8)(core|streams);
16238 if (streams_set != core_set) {
16239 fprintf(stderr, "%s: require to set both -s x -c y\n", fn_name);
16240 err = -1;
16241 goto exit;
16244 if (mcs_set) {
16245 coremask[0] |= mcs_mask[0] << 0;
16246 coremask[0] |= mcs_mask[1] << 8;
16247 coremask[0] |= mcs_mask[2] << 16;
16248 coremask[0] |= mcs_mask[3] << 24;
16250 if (cck_set)
16251 coremask[1] |= cck_mask;
16252 if (ofdm_set)
16253 coremask[1] |= ofdm_mask << 8;
16254 next:
16255 err = wlu_var_setbuf(wl, cmd->name, coremask, sizeof(uint32)*2);
16256 exit:
16257 return err;
16260 static int
16261 wl_txfifo_sz(void *wl, cmd_t *cmd, char **argv)
16263 char *param;
16264 const char *cmdname = "txfifo_sz";
16265 wl_txfifo_sz_t ts, *reply;
16266 uint fifo;
16267 int err;
16268 void *ptr = NULL;
16270 UNUSED_PARAMETER(cmd);
16272 if ((param = *++argv) == NULL)
16273 return USAGE_ERROR;
16275 fifo = atoi(param);
16276 if (fifo > NFIFO)
16277 return USAGE_ERROR;
16278 ts.fifo = fifo;
16279 ts.magic = WL_TXFIFO_SZ_MAGIC;
16281 if ((param = *++argv)) {
16282 ts.size = atoi(param);
16283 err = wlu_var_setbuf(wl, cmdname, &ts, sizeof(ts));
16284 } else {
16285 if ((err = wlu_var_getbuf_sm(wl, cmdname, &ts, sizeof(ts), &ptr) < 0))
16286 return err;
16287 reply = (wl_txfifo_sz_t *)ptr;
16288 printf("fifo %d size %d\n", fifo, reply->size);
16290 return err;
16292 #ifdef WLPFN
16293 static int
16294 wl_pfn_set(void *wl, cmd_t *cmd, char **argv)
16296 int err;
16297 wl_pfn_param_t pfn_param;
16299 UNUSED_PARAMETER(cmd);
16301 /* Setup default values */
16302 pfn_param.version = PFN_VERSION;
16303 /* Sorting based on list order, no back ground scan, no autoswitch, and immediate scan */
16304 pfn_param.flags = (PFN_LIST_ORDER << SORT_CRITERIA_BIT | ENABLE << IMMEDIATE_SCAN_BIT);
16305 /* Scan frequency of 30 sec */
16306 pfn_param.scan_freq = 30;
16307 /* RSSI margin of 30 dBm */
16308 pfn_param.rssi_margin = 30;
16309 /* Network timeout 60 sec */
16310 pfn_param.lost_network_timeout = 60;
16312 while (*++argv) {
16313 if (!stricmp(*argv, "scanfrq"))
16314 pfn_param.scan_freq = atoi(*++argv);
16316 else if (!stricmp(*argv, "netimeout"))
16317 pfn_param.lost_network_timeout = atoi(*++argv);
16319 else if (!stricmp(*argv, "rssi_delta"))
16320 pfn_param.rssi_margin = atoi(*++argv);
16322 else if (!stricmp(*argv, "sort")) {
16323 if (*++argv) {
16324 pfn_param.flags &= ~SORT_CRITERIA_MASK;
16325 if (!stricmp(*argv, "listorder"))
16326 pfn_param.flags |= (PFN_LIST_ORDER << SORT_CRITERIA_BIT);
16327 else if (!stricmp(*argv, "rssi"))
16328 pfn_param.flags |= (PFN_RSSI << SORT_CRITERIA_BIT);
16329 else {
16330 fprintf(stderr, "Invalid sort option %s\n", *argv);
16331 return -1;
16333 } else {
16334 fprintf(stderr, "Missing sort option\n");
16335 return -1;
16337 } else if (!stricmp(*argv, "bkgscan")) {
16338 if (*++argv) {
16339 pfn_param.flags &= ~ENABLE_BKGRD_SCAN_MASK;
16340 if (atoi(*argv))
16341 pfn_param.flags |= (ENABLE << ENABLE_BKGRD_SCAN_BIT);
16342 else
16343 pfn_param.flags |= (DISABLE << ENABLE_BKGRD_SCAN_BIT);
16344 } else {
16345 fprintf(stderr, "Missing bkgscan option\n");
16346 return -1;
16348 } else if (!stricmp(*argv, "autoswitch")) {
16349 pfn_param.flags &= ~AUTO_NET_SWITCH_MASK;
16350 if (*++argv) {
16351 if (atoi(*argv))
16352 pfn_param.flags |= (ENABLE << AUTO_NET_SWITCH_BIT);
16353 else
16354 pfn_param.flags |= (DISABLE << AUTO_NET_SWITCH_BIT);
16355 } else {
16356 fprintf(stderr, "Missing autoswitch option\n");
16357 return -1;
16359 } else if (!stricmp(*argv, "immediate")) {
16360 pfn_param.flags &= ~IMMEDIATE_SCAN_MASK;
16361 if (*++argv) {
16362 if (atoi(*argv))
16363 pfn_param.flags |= (ENABLE << IMMEDIATE_SCAN_BIT);
16364 else
16365 pfn_param.flags |= (DISABLE << IMMEDIATE_SCAN_BIT);
16366 } else {
16367 fprintf(stderr, "Missing immediate option\n");
16368 return -1;
16370 } else if (!stricmp(*argv, "autoconnect")) {
16371 pfn_param.flags &= ~AUTO_CONNECT_MASK;
16372 if (*++argv) {
16373 if (atoi(*argv))
16374 pfn_param.flags |= (ENABLE << AUTO_CONNECT_BIT);
16375 else
16376 pfn_param.flags |= (DISABLE << AUTO_CONNECT_BIT);
16377 } else {
16378 fprintf(stderr, "Missing autoconnect option\n");
16379 return -1;
16381 } else {
16382 fprintf(stderr, "Invalid parameter %s\n", *argv);
16383 return -1;
16387 pfn_param.version = htod32(pfn_param.version);
16388 pfn_param.scan_freq = htod32(pfn_param.scan_freq);
16389 pfn_param.lost_network_timeout = htod32(pfn_param.lost_network_timeout);
16390 pfn_param.flags = htod16(pfn_param.flags);
16391 pfn_param.rssi_margin = htod16(pfn_param.rssi_margin);
16392 if ((err = wlu_iovar_set(wl, "pfn_set", &pfn_param, sizeof(wl_pfn_param_t))))
16393 return (err);
16395 return (0);
16398 char key[100];
16399 static int
16400 wl_pfn_add(void *wl, cmd_t *cmd, char **argv)
16402 int err;
16403 wl_pfn_t pfn_element;
16405 UNUSED_PARAMETER(cmd);
16407 memset(&pfn_element, '\0', sizeof(wl_pfn_t));
16408 memset(key, '\0', sizeof(key));
16410 /* Default join setting, open, no WPA, no WEP and bss */
16411 pfn_element.bss_type = DOT11_BSSTYPE_INFRASTRUCTURE;
16412 pfn_element.auth = DOT11_OPEN_SYSTEM;
16413 pfn_element.wpa_auth = WPA_AUTH_DISABLED;
16414 pfn_element.wsec = 0;
16415 pfn_element.infra = 1;
16417 while (*++argv) {
16418 if (!stricmp(*argv, "ssid")) {
16419 if (*++argv) {
16420 pfn_element.ssid.SSID_len = strlen(*argv);
16421 if (pfn_element.ssid.SSID_len > DOT11_MAX_SSID_LEN) {
16422 fprintf(stderr, "SSID too long: %s\n", *argv);
16423 return -1;
16425 memcpy(pfn_element.ssid.SSID, *argv, pfn_element.ssid.SSID_len);
16427 } else if (!stricmp(*argv, "key")) {
16428 if (*++argv)
16429 strncpy(key, *argv, sizeof(key));
16430 if (strlen(key) == 0) {
16431 fprintf(stderr, "Missing value for key\n");
16432 return -1;
16434 } else if (!stricmp(*argv, "imode")) {
16435 if (*++argv) {
16436 if (!stricmp(*argv, "bss")) {
16437 pfn_element.bss_type = DOT11_BSSTYPE_INFRASTRUCTURE;
16438 pfn_element.infra = 1;
16439 } else if (!stricmp(*argv, "ibss")) {
16440 pfn_element.bss_type = DOT11_BSSTYPE_INDEPENDENT;
16441 pfn_element.infra = 0;
16442 } else {
16443 fprintf(stderr, "Invalid imode arg %s\n", *argv);
16444 return -1;
16447 else {
16448 fprintf(stderr, "Missing option for imode\n");
16449 return -1;
16451 } else if (!stricmp(*argv, "amode")) {
16452 if (*++argv) {
16453 if (!stricmp(*argv, "open"))
16454 pfn_element.auth = DOT11_OPEN_SYSTEM;
16455 else if (!stricmp(*argv, "shared"))
16456 pfn_element.auth = DOT11_SHARED_KEY;
16457 else {
16458 fprintf(stderr, "Invalid imode arg %s\n", *argv);
16459 return -1;
16461 } else {
16462 fprintf(stderr, "Missing option for amode\n");
16463 return -1;
16465 } else if (!stricmp(*argv, "wpa_auth")) {
16466 if (*++argv) {
16467 int kmax = sizeof(pfn_element.pfn_security.wpa_sec_key.key);
16468 if (strlen(key) == 0) {
16469 fprintf(stderr, "Key must be specified before wpa_auth\n");
16470 return -1;
16471 } else if ((int)strlen(key) > kmax) {
16472 fprintf(stderr, "Key too long for wpa_auth\n");
16473 return -1;
16475 pfn_element.pfn_security.wpa_sec_key.key_len = strlen(key);
16476 pfn_element.pfn_security.wpa_sec_key.flags = WSEC_PASSPHRASE;
16477 memcpy(pfn_element.pfn_security.wpa_sec_key.key, key,
16478 pfn_element.pfn_security.wpa_sec_key.key_len);
16480 pfn_element.pfn_security.wpa_sec_key.key_len =
16481 htod16(pfn_element.pfn_security.wpa_sec_key.key_len);
16482 pfn_element.pfn_security.wpa_sec_key.flags =
16483 htod16(pfn_element.pfn_security.wpa_sec_key.flags);
16485 if (!stricmp(*argv, "wpapsk"))
16486 pfn_element.wpa_auth = WPA_AUTH_PSK;
16487 else if (!stricmp(*argv, "wpa2psk"))
16488 pfn_element.wpa_auth = WPA2_AUTH_PSK;
16489 else if (!stricmp(*argv, "wpadisabled"))
16490 pfn_element.wpa_auth = WPA_AUTH_DISABLED;
16491 else {
16492 fprintf(stderr, "Invalid wpa_auth option %s\n", *argv);
16493 return -1;
16495 } else {
16496 fprintf(stderr, "Missing option for wpa_auth\n");
16497 return -1;
16499 } else if (!stricmp(*argv, "wsec")) {
16500 if (*++argv) {
16501 if (!stricmp(*argv, "WEP")) {
16502 char *keystr[2] = {key, '\0'};
16504 int kmax = sizeof(pfn_element.pfn_security.sec_key.data);
16506 pfn_element.pfn_security.sec_key.index = 0;
16508 if (strlen(key) == 0) {
16509 fprintf(stderr, "Key must be specified "
16510 "before wsec WEP\n");
16511 return -1;
16512 } else if ((int)strlen(key) > kmax) {
16513 fprintf(stderr, "Key too long for WEP\n");
16514 return -1;
16515 } else if (parse_wep(keystr,
16516 &pfn_element.pfn_security.sec_key, FALSE))
16517 return -1;
16518 pfn_element.wsec = WEP_ENABLED;
16520 pfn_element.pfn_security.sec_key.index =
16521 htod32(pfn_element.pfn_security.sec_key.index);
16522 pfn_element.pfn_security.sec_key.len =
16523 htod32(pfn_element.pfn_security.sec_key.len);
16524 pfn_element.pfn_security.sec_key.algo =
16525 htod32(pfn_element.pfn_security.sec_key.algo);
16526 pfn_element.pfn_security.sec_key.flags =
16527 htod32(pfn_element.pfn_security.sec_key.flags);
16528 } else if (!stricmp(*argv, "TKIP"))
16529 pfn_element.wsec = TKIP_ENABLED;
16530 else if (!stricmp(*argv, "AES"))
16531 pfn_element.wsec = AES_ENABLED;
16532 else if (!stricmp(*argv, "TKIPAES"))
16533 pfn_element.wsec = TKIP_ENABLED | AES_ENABLED;
16534 else {
16535 fprintf(stderr, "Invalid wsec option %s\n", *argv);
16536 return -1;
16538 } else {
16539 fprintf(stderr, "Missing option for wsec\n");
16540 return -1;
16542 } else {
16543 fprintf(stderr, "Invalid parameter %s\n", *argv);
16544 return -1;
16548 pfn_element.ssid.SSID_len = htod32(pfn_element.ssid.SSID_len);
16549 pfn_element.bss_type = htod32(pfn_element.bss_type);
16550 pfn_element.infra = htod32(pfn_element.infra);
16551 pfn_element.auth = htod32(pfn_element.auth);
16552 pfn_element.wpa_auth = htod32(pfn_element.wpa_auth);
16553 pfn_element.wsec = htod32(pfn_element.wsec);
16554 if ((err = wlu_iovar_set(wl, "pfn_add", &pfn_element, sizeof(wl_pfn_t))))
16555 return (err);
16557 return (0);
16560 static int
16561 wl_pfn(void *wl, cmd_t *cmd, char **argv)
16563 int err, val;
16565 UNUSED_PARAMETER(cmd);
16567 if (*++argv) {
16568 val = atoi(*argv);
16569 err = wlu_iovar_setint(wl, "pfn", (val ? 1 : 0));
16570 } else {
16571 err = wlu_iovar_getint(wl, "pfn", &val);
16572 if (!err)
16573 wl_printint(val);
16576 return err;
16579 #if defined(linux)
16580 static int
16581 wl_pfn_event_check(void *wl, cmd_t *cmd, char **argv)
16583 int fd, err;
16584 struct sockaddr_ll sll;
16585 struct ifreq ifr;
16586 char ifnames[IFNAMSIZ] = {"eth1"};
16587 bcm_event_t * event;
16588 char data[512];
16589 wlc_ssid_t * ssid;
16590 int event_type;
16591 struct ether_addr *addr;
16592 char eabuf[ETHER_ADDR_STR_LEN];
16594 UNUSED_PARAMETER(wl);
16595 UNUSED_PARAMETER(cmd);
16597 if (*++argv)
16598 strncpy(ifnames, *argv, IFNAMSIZ);
16600 memset(&ifr, 0, sizeof(ifr));
16601 strncpy(ifr.ifr_name, ifnames, IFNAMSIZ);
16603 fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
16604 if (fd < 0) {
16605 printf("Cannot create socket %d\n", fd);
16606 return -1;
16609 err = ioctl(fd, SIOCGIFINDEX, &ifr);
16610 if (err < 0) {
16611 printf("Cannot get index %d\n", err);
16612 return -1;
16615 memset(&sll, 0, sizeof(sll));
16616 sll.sll_family = AF_PACKET;
16617 sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
16618 sll.sll_ifindex = ifr.ifr_ifindex;
16619 err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
16620 if (err < 0) {
16621 printf("Cannot get index %d\n", err);
16622 return -1;
16625 while (1) {
16626 recv(fd, data, sizeof(data), 0);
16627 event = (bcm_event_t *)data;
16628 addr = (struct ether_addr *)&(event->event.addr);
16630 event_type = ntoh32(event->event.event_type);
16632 if (addr != NULL) {
16633 sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x",
16634 (uchar)addr->octet[0]&0xff,
16635 (uchar)addr->octet[1]&0xff,
16636 (uchar)addr->octet[2]&0xff,
16637 (uchar)addr->octet[3]&0xff,
16638 (uchar)addr->octet[4]&0xff,
16639 (uchar)addr->octet[5]&0xff);
16642 if (ntoh32(event->event.datalen)) {
16643 ssid = (wlc_ssid_t *)(data + sizeof(bcm_event_t));
16644 char ssidbuf[SSID_FMT_BUF_LEN];
16646 wl_format_ssid(ssidbuf, ssid->SSID, ssid->SSID_len);
16648 if (WLC_E_PFN_NET_FOUND == event_type)
16649 printf("Network found SSID = %s, SSID_len = %d\n",
16650 ssidbuf, ssid->SSID_len);
16652 if (WLC_E_PFN_NET_LOST == event_type)
16653 printf("Network lost SSID = %s, SSID_len = %d\n",
16654 ssidbuf, ssid->SSID_len);
16657 if (WLC_E_LINK == event_type || WLC_E_NDIS_LINK == event_type) {
16658 if (ntoh16(event->event.flags) & WLC_EVENT_MSG_LINK)
16659 printf("MACEVENT Link up :%s\n", eabuf);
16660 else
16661 printf("MACEVENT Link down :%s\n", eabuf);
16665 return (0);
16668 #define ESCAN_EVENTS_BUFFER_SIZE 2048
16670 static int
16671 wl_escan_event_check(void *wl, cmd_t *cmd, char **argv)
16673 int fd, err, i, octets;
16674 struct sockaddr_ll sll;
16675 struct ifreq ifr;
16676 char ifnames[IFNAMSIZ] = {"eth1"};
16677 uint8 print_flag = 4;
16678 bcm_event_t * event;
16679 uint32 reason, status;
16680 char* data;
16681 int event_type;
16682 struct ether_addr *addr;
16683 uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* 128-bit mask */
16685 wl_escan_result_t* escan_data;
16688 UNUSED_PARAMETER(wl);
16689 UNUSED_PARAMETER(cmd);
16691 if (*++argv) {
16692 strncpy(ifnames, *argv, (IFNAMSIZ - 1));
16693 if (*++argv)
16694 print_flag = atoi(*argv);
16697 memset(&ifr, 0, sizeof(ifr));
16698 strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
16700 memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN);
16701 event_inds_mask[WLC_E_ESCAN_RESULT / 8] |= 1 << (WLC_E_ESCAN_RESULT % 8);
16702 if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
16703 return (err);
16705 fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
16706 if (fd < 0) {
16707 printf("Cannot create socket %d\n", fd);
16708 return -1;
16711 err = ioctl(fd, SIOCGIFINDEX, &ifr);
16712 if (err < 0) {
16713 printf("Cannot get index %d\n", err);
16714 return -1;
16717 memset(&sll, 0, sizeof(sll));
16718 sll.sll_family = AF_PACKET;
16719 sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
16720 sll.sll_ifindex = ifr.ifr_ifindex;
16721 err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
16722 if (err < 0) {
16723 printf("Cannot bind %d\n", err);
16724 return -1;
16727 data = (char*)malloc(ESCAN_EVENTS_BUFFER_SIZE);
16729 if (data == NULL) {
16730 printf("Cannot not allocate %d bytes for events receive buffer\n",
16731 ESCAN_EVENTS_BUFFER_SIZE);
16732 return -1;
16735 while (1) {
16736 octets = recv(fd, data, ESCAN_EVENTS_BUFFER_SIZE, 0);
16737 event = (bcm_event_t *)data;
16738 addr = (struct ether_addr *)&(event->event.addr);
16740 event_type = ntoh32(event->event.event_type);
16742 if ((event_type == WLC_E_ESCAN_RESULT) && (octets > 0)) {
16743 escan_data = (wl_escan_result_t*)&data[sizeof(bcm_event_t)];
16744 reason = ntoh32(event->event.reason);
16745 status = ntoh32(event->event.status);
16747 if (print_flag & 1)
16748 printf("WLC_E_ESCAN_RESULT, (sync_id,status) = (%d,%d)\n",
16749 escan_data->sync_id, status);
16751 if (print_flag & 2)
16752 for (i = 0; i < escan_data->bss_count; i++)
16753 dump_bss_info(&escan_data->bss_info[i]);
16755 if (print_flag & 4) {
16756 if (status == WLC_E_STATUS_PARTIAL) {
16757 printf("sync_id: %d, WLC_E_STATUS_PARTIAL\n",
16758 escan_data->sync_id);
16759 for (i = 0; i < escan_data->bss_count; i++)
16760 dump_bss_info(&escan_data->bss_info[i]);
16762 if (status == WLC_E_STATUS_SUCCESS)
16763 printf("sync_id: %d, WLC_E_STATUS_SUCCESS => SCAN_DONE\n",
16764 escan_data->sync_id);
16765 if ((status != WLC_E_STATUS_SUCCESS) &&
16766 (status != WLC_E_STATUS_PARTIAL))
16767 printf("sync_id: %d, status:%d, misc. error/abort\n",
16768 escan_data->sync_id, status);
16771 if (print_flag & 8) {
16772 int remainder = escan_data->bss_info[0].ie_length;
16773 int processed = sizeof(wl_escan_result_t);
16774 uint8* iebuf = &((uint8*)escan_data)[sizeof(wl_escan_result_t)];
16776 if (status != WLC_E_STATUS_PARTIAL)
16777 continue;
16779 printf("MOREINFO: (sync_id,buflen,ielen) = (%d,%d,%d)\n",
16780 escan_data->sync_id,
16781 escan_data->buflen,
16782 escan_data->bss_info[0].ie_length);
16784 /* do a tlv sanity check */
16785 while (remainder > 0) {
16786 processed += 1 + 1 + iebuf[1];
16787 remainder -= 1 + 1 + iebuf[1];
16788 iebuf += 1 + 1 + iebuf[1];
16790 if (processed >= ESCAN_EVENTS_BUFFER_SIZE)
16791 break;
16793 if (remainder != 0) {
16794 printf("ERROR: IE tlv sanity check failed for "
16795 "(ssid,sync_id,buflen,ielen,remainder) = "
16796 "(%s,%d,%d,%d,%d)\n",
16797 escan_data->bss_info[0].SSID,
16798 escan_data->sync_id, escan_data->buflen,
16799 escan_data->bss_info[0].ie_length,
16800 remainder);
16801 iebuf = &((uint8*)escan_data)[sizeof(wl_escan_result_t)];
16802 if ((escan_data->buflen - sizeof(wl_escan_result_t)) > 0) {
16803 for (i = 0;
16804 i < (int)(escan_data->buflen -
16805 sizeof(wl_escan_result_t));
16806 i++) {
16807 printf("%02x ", iebuf[i]);
16809 printf("\n");
16816 /* if we ever reach here */
16817 free(data);
16819 return (0);
16822 struct escan_bss {
16823 struct escan_bss *next;
16824 wl_bss_info_t bss[1];
16826 #define ESCAN_BSS_FIXED_SIZE 4
16828 static int
16829 wl_escanresults(void *wl, cmd_t *cmd, char **argv)
16831 int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)) +
16832 (WL_NUMCHANNELS * sizeof(uint16));
16833 wl_escan_params_t *params;
16834 int fd, err, octets;
16835 struct sockaddr_ll sll;
16836 struct ifreq ifr;
16837 char ifnames[IFNAMSIZ] = {"eth1"};
16838 bcm_event_t *event;
16839 uint32 reason, status;
16840 char *data;
16841 int event_type;
16842 struct ether_addr *addr;
16843 uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* 128-bit mask */
16844 wl_escan_result_t *escan_data;
16845 struct escan_bss *escan_bss_head = NULL;
16846 struct escan_bss *escan_bss_tail = NULL;
16847 struct escan_bss *result;
16849 params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
16850 params = (wl_escan_params_t*)malloc(params_size);
16851 if (params == NULL) {
16852 fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size);
16853 return -1;
16855 memset(params, 0, params_size);
16857 err = wl_scan_prep(wl, cmd, argv, &params->params, &params_size);
16858 if (err)
16859 goto exit2;
16861 memset(&ifr, 0, sizeof(ifr));
16862 if (wl)
16863 strncpy(ifr.ifr_name, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1));
16864 else
16865 strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
16867 memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN);
16868 event_inds_mask[WLC_E_ESCAN_RESULT / 8] |= 1 << (WLC_E_ESCAN_RESULT % 8);
16869 if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
16870 goto exit2;
16872 fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
16873 if (fd < 0) {
16874 printf("Cannot create socket %d\n", fd);
16875 err = -1;
16876 goto exit2;
16879 err = ioctl(fd, SIOCGIFINDEX, &ifr);
16880 if (err < 0) {
16881 printf("Cannot get index %d\n", err);
16882 goto exit2;
16885 /* bind the socket first before starting escan so we won't miss any event */
16886 memset(&sll, 0, sizeof(sll));
16887 sll.sll_family = AF_PACKET;
16888 sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
16889 sll.sll_ifindex = ifr.ifr_ifindex;
16890 err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
16891 if (err < 0) {
16892 printf("Cannot bind %d\n", err);
16893 goto exit2;
16896 params->version = htod32(ESCAN_REQ_VERSION);
16897 params->action = htod16(WL_SCAN_ACTION_START);
16899 #if defined(linux)
16900 srand((unsigned)time(NULL));
16901 params->sync_id = htod16(rand() & 0xffff);
16902 #else
16903 params->sync_id = htod16(4321);
16904 #endif /* #if defined(linux) */
16906 params_size += OFFSETOF(wl_escan_params_t, params);
16907 err = wlu_iovar_setbuf(wl, "escan", params, params_size, buf, WLC_IOCTL_MAXLEN);
16909 data = (char*)malloc(ESCAN_EVENTS_BUFFER_SIZE);
16911 if (data == NULL) {
16912 printf("Cannot not allocate %d bytes for events receive buffer\n",
16913 ESCAN_EVENTS_BUFFER_SIZE);
16914 err = -1;
16915 goto exit2;
16918 /* receive scan result */
16919 while (1) {
16920 octets = recv(fd, data, ESCAN_EVENTS_BUFFER_SIZE, 0);
16921 event = (bcm_event_t *)data;
16922 addr = (struct ether_addr *)&(event->event.addr);
16923 event_type = ntoh32(event->event.event_type);
16925 if ((event_type == WLC_E_ESCAN_RESULT) && (octets > 0)) {
16926 escan_data = (wl_escan_result_t*)&data[sizeof(bcm_event_t)];
16927 reason = ntoh32(event->event.reason);
16928 status = ntoh32(event->event.status);
16930 if (status == WLC_E_STATUS_PARTIAL) {
16931 wl_bss_info_t *bi = &escan_data->bss_info[0];
16932 wl_bss_info_t *bss;
16934 /* check if we've received info of same BSSID */
16935 for (result = escan_bss_head; result; result = result->next) {
16936 bss = result->bss;
16938 #define WLC_BSS_RSSI_ON_CHANNEL 0x0002 /* Copied from wlc.h. Is there a better way to do this? */
16940 if (!wlu_bcmp(bi->SSID, bss->SSID, ETHER_ADDR_LEN) &&
16941 CHSPEC_BAND(bi->chanspec) ==
16942 CHSPEC_BAND(bss->chanspec) &&
16943 bi->SSID_len == bss->SSID_len &&
16944 !wlu_bcmp(bi->SSID, bss->SSID, bi->SSID_len))
16945 break;
16948 if (!result) {
16949 /* New BSS. Allocate memory and save it */
16950 struct escan_bss *ebss = malloc(ESCAN_BSS_FIXED_SIZE
16951 + bi->length);
16953 if (!ebss) {
16954 perror("can't allocate memory for bss");
16955 goto exit1;
16958 ebss->next = NULL;
16959 memcpy(&ebss->bss, bi, bi->length);
16960 if (escan_bss_tail) {
16961 escan_bss_tail->next = ebss;
16963 else {
16964 escan_bss_head = ebss;
16966 escan_bss_tail = ebss;
16968 else {
16969 /* We've got this BSS. Update rssi if necessary */
16970 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
16971 (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
16972 /* preserve max RSSI if the measurements are
16973 * both on-channel or both off-channel
16975 bss->RSSI = MAX(bss->RSSI, bi->RSSI);
16976 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
16977 (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
16978 /* preserve the on-channel rssi measurement
16979 * if the new measurement is off channel
16981 bss->RSSI = bi->RSSI;
16982 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
16986 else if (status == WLC_E_STATUS_SUCCESS) {
16987 /* Escan finished. Let's go dump the results. */
16988 break;
16990 else {
16991 printf("sync_id: %d, status:%d, misc. error/abort\n",
16992 escan_data->sync_id, status);
16993 goto exit1;
16998 /* print scan results */
16999 for (result = escan_bss_head; result; result = result->next) {
17000 dump_bss_info(result->bss);
17003 exit1:
17004 /* free scan results */
17005 result = escan_bss_head;
17006 while (result) {
17007 struct escan_bss *tmp = result->next;
17008 free(result);
17009 result = tmp;
17012 free(data);
17013 close(fd);
17014 exit2:
17015 free(params);
17016 return err;
17018 #endif /* linux */
17020 static int
17021 wl_event_filter(void *wl, cmd_t *cmd, char **argv)
17023 int err;
17024 uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* 128-bit mask */
17026 UNUSED_PARAMETER(cmd);
17027 UNUSED_PARAMETER(argv);
17029 memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN);
17031 /* Register for following event for pfn */
17032 event_inds_mask[WLC_E_LINK / 8] |= 1 << (WLC_E_LINK % 8);
17033 event_inds_mask[WLC_E_PFN_NET_FOUND / 8] |= 1 << (WLC_E_PFN_NET_FOUND % 8);
17034 event_inds_mask[WLC_E_PFN_NET_LOST / 8] |= 1 << (WLC_E_PFN_NET_LOST % 8);
17036 if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN)))
17037 return (err);
17039 return (0);
17041 #endif /* WLPFN */
17043 static dbg_msg_t toe_cmpnt[] = {
17044 {TOE_TX_CSUM_OL, "tx_csum_ol"},
17045 {TOE_RX_CSUM_OL, "rx_csum_ol"},
17046 {0, NULL}
17049 static dbg_msg_t arpoe_cmpnt[] = {
17050 {ARP_OL_AGENT, "agent"},
17051 {ARP_OL_SNOOP, "snoop"},
17052 {ARP_OL_HOST_AUTO_REPLY, "host_auto_reply"},
17053 {ARP_OL_PEER_AUTO_REPLY, "peer_auto_reply"},
17054 {0, NULL}
17058 * Tcpip Offload Component-wise get/set control.
17060 static int
17061 wl_offload_cmpnt(void *wl, cmd_t *cmd, char **argv)
17063 int ret, i;
17064 uint val, last_val = 0, cmpnt_add = 0, cmpnt_del = 0;
17065 char *endptr;
17066 dbg_msg_t *dbg_msg = NULL;
17067 void *ptr = NULL;
17068 int cmpnt;
17070 if (strcmp(cmd->name, "toe_ol") == 0)
17071 dbg_msg = toe_cmpnt;
17072 else if (strcmp(cmd->name, "arp_ol") == 0)
17073 dbg_msg = arpoe_cmpnt;
17075 if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
17076 return (ret);
17077 cmpnt = dtoh32(*(int *)ptr);
17079 if (!*++argv) {
17080 printf("0x%x ", cmpnt);
17081 for (i = 0; (val = dbg_msg[i].value); i++) {
17082 if ((cmpnt & val) && (val != last_val))
17083 printf(" %s", dbg_msg[i].string);
17084 last_val = val;
17086 printf("\n");
17087 return (0);
17090 while (*argv) {
17091 char *s = *argv;
17092 if (*s == '+' || *s == '-')
17093 s++;
17094 else
17095 cmpnt_del = ~0; /* make the whole list absolute */
17096 val = strtoul(s, &endptr, 0);
17097 /* not a plain integer if not all the string was parsed by strtoul */
17098 if (*endptr != '\0') {
17099 for (i = 0; (val = dbg_msg[i].value); i++)
17100 if (stricmp(dbg_msg[i].string, s) == 0)
17101 break;
17102 if (!val)
17103 goto usage;
17105 if (**argv == '-')
17106 cmpnt_del |= val;
17107 else
17108 cmpnt_add |= val;
17109 ++argv;
17112 cmpnt &= ~cmpnt_del;
17113 cmpnt |= cmpnt_add;
17115 cmpnt = htod32(cmpnt);
17116 return (wlu_var_setbuf(wl, cmd->name, &cmpnt, sizeof(int)));
17118 usage:
17119 fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");
17120 fprintf(stderr, "Use a + or - prefix to make an incremental change.");
17122 for (i = 0; (val = dbg_msg[i].value); i++) {
17123 if (val != last_val)
17124 fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string);
17125 else
17126 fprintf(stderr, ", %s", dbg_msg[i].string);
17127 last_val = val;
17129 fprintf(stderr, "\n");
17131 return 0;
17135 * If a host IP address is given, add it to the host-cache, e.g. "wl arp_hostip 192.168.1.1".
17136 * If no address is given, dump all the addresses.
17138 static int
17139 wl_hostip(void *wl, cmd_t *cmd, char **argv)
17141 int ret;
17142 struct ipv4_addr ipa_set, *ipa_get, null_ipa;
17144 if (!*++argv) {
17145 /* Get */
17146 void *ptr = NULL;
17147 if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
17148 return ret;
17150 memset(null_ipa.addr, 0, IPV4_ADDR_LEN);
17152 for (ipa_get = (struct ipv4_addr *)ptr;
17153 memcmp(null_ipa.addr, ipa_get->addr, IPV4_ADDR_LEN) != 0;
17154 ipa_get++)
17155 printf("%s\n", wl_iptoa(ipa_get));
17157 printf("Total %d host addresses\n", (int)(ipa_get - (struct ipv4_addr *)ptr));
17158 } else {
17159 /* Add */
17160 if (!wl_atoip(*argv, &ipa_set))
17161 return -1;
17162 /* we add one ip-addr at a time */
17163 return wlu_var_setbuf(wl, cmd->name, &ipa_set, sizeof(IPV4_ADDR_LEN));
17166 return ret;
17169 static int
17170 wl_arp_stats(void *wl, cmd_t *cmd, char **argv)
17172 int ret;
17173 struct arp_ol_stats_t *arpstats;
17175 if (!*++argv) {
17176 /* Get */
17177 void *ptr = NULL;
17179 if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
17180 return ret;
17181 arpstats = (struct arp_ol_stats_t *)ptr;
17182 printf("host_ip_entries = %d\n", dtoh32(arpstats->host_ip_entries));
17183 printf("host_ip_overflow = %d\n", dtoh32(arpstats->host_ip_overflow));
17184 printf("arp_table_entries = %d\n", dtoh32(arpstats->arp_table_entries));
17185 printf("arp_table_overflow = %d\n", dtoh32(arpstats->arp_table_overflow));
17186 printf("host_request = %d\n", dtoh32(arpstats->host_request));
17187 printf("host_reply = %d\n", dtoh32(arpstats->host_reply));
17188 printf("host_service = %d\n", dtoh32(arpstats->host_service));
17189 printf("peer_request = %d\n", dtoh32(arpstats->peer_request));
17190 printf("peer_request_drop = %d\n", dtoh32(arpstats->peer_request_drop));
17191 printf("peer_reply = %d\n", dtoh32(arpstats->peer_reply));
17192 printf("peer_reply_drop = %d\n", dtoh32(arpstats->peer_reply_drop));
17193 printf("peer_service = %d\n", dtoh32(arpstats->peer_service));
17194 printf("host_ip_entries = %d\n", dtoh32(arpstats->host_ip_entries));
17195 } else
17196 printf("Cannot set arp stats, use 'wl arp_stats_clear' to clear the counters\n");
17198 return 0;
17201 static int
17202 wl_toe_stats(void *wl, cmd_t *cmd, char **argv)
17204 int ret;
17205 struct toe_ol_stats_t *toestats;
17207 if (!*++argv) {
17208 /* Get */
17209 void *ptr = NULL;
17211 if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
17212 return ret;
17213 toestats = (struct toe_ol_stats_t *)ptr;
17214 printf("tx_summed = %d\n", dtoh32(toestats->tx_summed));
17215 printf("tx_iph_fill = %d\n", dtoh32(toestats->tx_iph_fill));
17216 printf("tx_tcp_fill = %d\n", dtoh32(toestats->tx_tcp_fill));
17217 printf("tx_udp_fill = %d\n", dtoh32(toestats->tx_udp_fill));
17218 printf("tx_icmp_fill = %d\n", dtoh32(toestats->tx_icmp_fill));
17219 printf("rx_iph_good = %d\n", dtoh32(toestats->rx_iph_good));
17220 printf("rx_iph_bad = %d\n", dtoh32(toestats->rx_iph_bad));
17221 printf("rx_tcp_good = %d\n", dtoh32(toestats->rx_tcp_good));
17222 printf("rx_tcp_bad = %d\n", dtoh32(toestats->rx_tcp_bad));
17223 printf("rx_udp_good = %d\n", dtoh32(toestats->rx_udp_good));
17224 printf("rx_udp_bad = %d\n", dtoh32(toestats->rx_udp_bad));
17225 printf("rx_icmp_good = %d\n", dtoh32(toestats->rx_icmp_good));
17226 printf("rx_icmp_bad = %d\n", dtoh32(toestats->rx_icmp_bad));
17227 printf("tx_tcp_errinj = %d\n", dtoh32(toestats->tx_tcp_errinj));
17228 printf("tx_udp_errinj = %d\n", dtoh32(toestats->tx_udp_errinj));
17229 printf("tx_icmp_errinj = %d\n", dtoh32(toestats->tx_icmp_errinj));
17230 printf("rx_tcp_errinj = %d\n", dtoh32(toestats->rx_tcp_errinj));
17231 printf("rx_udp_errinj = %d\n", dtoh32(toestats->rx_udp_errinj));
17232 printf("rx_icmp_errinj = %d\n", dtoh32(toestats->rx_icmp_errinj));
17233 } else
17234 printf("Cannot set toe stats, use 'wl toe_stats_clear' to clear the counters\n");
17236 return 0;
17239 static int
17240 wl_rate_histo(void *wl, cmd_t *cmd, char **argv)
17242 uint32 *hw_rates_used, *mcs_rates;
17243 void *ptr = NULL;
17244 int i, err, total = 0;
17246 UNUSED_PARAMETER(argv);
17248 if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
17249 return err;
17251 printf("Rates:\n");
17252 hw_rates_used = ptr;
17253 for (i = 0; i <= WLC_MAXRATE; i++) {
17254 if (hw_rates_used[i]) {
17255 total += hw_rates_used[i];
17256 if DIV_REM(i, 2)
17257 printf("%.2d\t%d.%d Mbit/s\n",
17258 hw_rates_used[i], DIV_QUO(i, 2), DIV_REM(i, 2)/10);
17259 else
17260 printf("%.2d\t%d Mbit/s\n",
17261 hw_rates_used[i], DIV_QUO(i, 2));
17265 printf("MCS indexes:\n");
17266 total = 0;
17267 mcs_rates = &hw_rates_used[i];
17268 for (i = 0; i <= WLC_MAXMCS; i++) {
17269 if (mcs_rates[i]) {
17270 total += mcs_rates[i];
17271 printf("%d\tMCS %d\n", mcs_rates[i], i);
17274 return 0;
17277 static int
17278 wl_pkteng_stats(void *wl, cmd_t *cmd, char **argv)
17280 wl_pkteng_stats_t *stats;
17281 void *ptr = NULL;
17282 int err;
17284 UNUSED_PARAMETER(argv);
17286 if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
17287 return err;
17289 stats = ptr;
17290 printf("Lost frame count %d\n", stats->lostfrmcnt);
17291 printf("RSSI %d\n", stats->rssi);
17292 printf("Signal to noise ratio %d\n", stats->snr);
17294 return 0;
17297 #define LPPHY_PAPD_EPS_TBL_SIZE 64
17298 static int
17299 wl_lpphy_papdepstbl(void *wl, cmd_t *cmd, char **argv)
17301 int32 eps_real, eps_imag;
17302 int i;
17303 uint32 eps_tbl[LPPHY_PAPD_EPS_TBL_SIZE];
17304 int err;
17306 UNUSED_PARAMETER(argv);
17308 if ((err = wlu_iovar_get(wl, cmd->name, &eps_tbl, sizeof(eps_tbl))) < 0)
17309 return err;
17311 printf("PAPD EPS TABLE:\n");
17312 for (i = 0; i < LPPHY_PAPD_EPS_TBL_SIZE; i++) {
17313 if ((eps_real = (int32)(eps_tbl[i] >> 12)) > 0x7ff)
17314 eps_real -= 0x1000; /* Sign extend */
17315 if ((eps_imag = (int32)(eps_tbl[i] & 0xfff)) > 0x7ff)
17316 eps_imag -= 0x1000; /* Sign extend */
17317 if (eps_imag >= 0)
17318 printf("%d+j%d\n", eps_real, eps_imag);
17319 else
17320 printf("%d-j%d\n", eps_real, -eps_imag);
17323 return 0;
17326 static int
17327 wl_phy_txiqcc(void *wl, cmd_t *cmd, char **argv)
17329 int i;
17330 int err;
17331 int32 iqccValues[2];
17332 int32 value;
17333 char *endptr;
17334 int32 a, b;
17336 if (!*++argv) {
17337 if ((err = wlu_iovar_get(wl, cmd->name, iqccValues, 2*sizeof(int32))) < 0)
17338 return err;
17339 a = (int16)iqccValues[0];
17340 b = (int16)iqccValues[1];
17341 /* sign extend a, b from 10 bit signed value to 32 bit signed value */
17342 a = ((a << 22) >> 22);
17343 b = ((b << 22) >> 22);
17344 printf("%d %d\n", a, b);
17346 else
17348 for (i = 0; i < 2; i++) {
17349 value = strtol(*argv++, &endptr, 0);
17350 if (value > 511 || value < -512) {
17351 return BCME_BADARG;
17353 iqccValues[i] = value;
17356 if ((err = wlu_var_setbuf(wl, cmd->name, iqccValues, 2*sizeof(int32))) < 0)
17357 return err;
17360 return 0;
17363 static int
17364 wl_phy_txlocc(void *wl, cmd_t *cmd, char **argv)
17366 int i;
17367 int err;
17368 int8 loccValues[6];
17369 int32 value;
17370 char *endptr;
17372 if (!*++argv) {
17373 if ((err = wlu_iovar_get(wl, cmd->name, loccValues, sizeof(loccValues))) < 0)
17374 return err;
17376 /* sign extend the loccValues */
17377 loccValues[2] = (loccValues[2] << 3) >> 3;
17378 loccValues[3] = (loccValues[3] << 3) >> 3;
17379 loccValues[4] = (loccValues[4] << 3) >> 3;
17380 loccValues[5] = (loccValues[5] << 3) >> 3;
17382 printf("%d %d %d %d %d %d\n", loccValues[0],
17383 loccValues[1], loccValues[2], loccValues[3], loccValues[4], loccValues[5]);
17385 else
17387 for (i = 0; i < 6; i++) {
17388 value = strtol(*argv++, &endptr, 0);
17389 if (((i < 2) && (value > 63 || value < -64)) ||
17390 ((i >= 2) && (value > 15 || value < -15))) {
17391 return BCME_BADARG;
17393 loccValues[i] = (int8)value;
17396 if ((err = wlu_var_setbuf(wl, "lpphy_txlocc", loccValues, 6*sizeof(int8))) < 0)
17397 return err;
17400 return 0;
17404 static int
17405 wl_phytable(void *wl, cmd_t *cmd, char **argv)
17407 int err;
17408 int32 tableInfo[4];
17409 int32 value;
17410 char *endptr;
17411 void *ptr = NULL;
17412 int32 tableId, tableOffset, tableWidth, tableElement;
17414 if (*++argv != NULL)
17415 tableId = strtol(*argv, &endptr, 0);
17416 else
17417 return USAGE_ERROR;
17419 if (*++argv != NULL)
17420 tableOffset = strtol(*argv, &endptr, 0);
17421 else
17422 return USAGE_ERROR;
17424 if (*++argv != NULL)
17425 tableWidth = strtol(*argv, &endptr, 0);
17426 else
17427 return USAGE_ERROR;
17429 if ((tableId < 0) || (tableOffset < 0))
17430 return BCME_BADARG;
17432 if ((tableWidth != 8) && (tableWidth != 16) && (tableWidth != 32))
17433 return BCME_BADARG;
17435 if (!*++argv) {
17436 tableInfo[0] = tableId;
17437 tableInfo[1] = tableOffset;
17438 tableInfo[2] = tableWidth;
17440 if ((err = wlu_var_getbuf(wl, cmd->name, tableInfo, 4*sizeof(int32), &ptr)) < 0)
17441 return err;
17443 tableElement = ((int32*)ptr)[0];
17445 printf("0x%x(%d)\n", tableElement, tableElement);
17447 else
17449 value = strtol(*argv++, &endptr, 0);
17450 tableElement = value;
17452 tableInfo[0] = tableId;
17453 tableInfo[1] = tableOffset;
17454 tableInfo[2] = tableWidth;
17455 tableInfo[3] = tableElement;
17457 if ((err = wlu_var_setbuf(wl, cmd->name, tableInfo, 4*sizeof(int32))) < 0)
17458 return err;
17461 return 0;
17464 static int
17465 wl_phy_txpwrindex(void *wl, cmd_t *cmd, char **argv)
17467 uint i;
17468 int ret;
17469 uint32 txpwridx[4] = { 0 };
17470 int8 idx[4] = { 0 };
17471 uint argc;
17472 char *endptr;
17474 /* arg count */
17475 for (argc = 0; argv[argc]; argc++);
17476 argc--;
17478 for (i = 0; i < 4; i++) {
17479 if (argc > i) {
17480 txpwridx[i] = strtol(argv[1 + i], &endptr, 0);
17481 if (*endptr != '\0') {
17482 printf("error\n");
17483 return -1;
17488 if (argc == 0) {
17489 if ((ret = wlu_iovar_getint(wl, cmd->name, (int*)&txpwridx[0])) < 0) {
17490 return (ret);
17492 txpwridx[0] = dtoh32(txpwridx[0]);
17493 idx[0] = (int8)(txpwridx[0] & 0xff);
17494 idx[1] = (int8)((txpwridx[0] >> 8) & 0xff);
17495 idx[2] = (int8)((txpwridx[0] >> 16) & 0xff);
17496 idx[3] = (int8)((txpwridx[0] >> 24) & 0xff);
17497 printf("txpwrindex for core{0...3}: %d %d %d %d\n", idx[0], idx[1],
17498 idx[2], idx[3]);
17499 } else {
17501 wlc_rev_info_t revinfo;
17502 uint32 phytype;
17504 memset(&revinfo, 0, sizeof(revinfo));
17505 ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
17506 if (ret) {
17507 return ret;
17509 phytype = dtoh32(revinfo.phytype);
17511 if (phytype == WLC_PHY_TYPE_HT) {
17512 if (argc != 3) {
17513 printf("HTPHY must specify 3 core txpwrindex\n");
17514 return BCME_BADARG;
17516 } else if (phytype == WLC_PHY_TYPE_N) {
17517 if (argc != 2) {
17518 printf("NPHY must specify 2 core txpwrindex\n");
17519 return BCME_BADARG;
17523 ret = wlu_iovar_setbuf(wl, cmd->name, txpwridx, 4*sizeof(uint32),
17524 buf, WLC_IOCTL_MAXLEN);
17527 return ret;
17530 static int
17531 wl_phy_pavars2(void *wl, cmd_t *cmd, char **argv)
17533 #if defined(_CFE_)
17534 return CFE_ERR_UNSUPPORTED;
17535 #else
17536 const pavars_t *pav = pavars;
17537 wl_pavars2_t pavars2_data, *ptr = NULL;
17538 uint16 *inpa = pavars2_data.inpa;
17539 char *cpar = NULL, *p = NULL;
17540 char par[256]; /* holds longest pavars->vars */
17541 char delimit[2] = " \0";
17542 int err = 0;
17543 unsigned int val;
17545 UNUSED_PARAMETER(cmd);
17547 if (*++argv) { /* set */
17548 while (pav->phy_type != PHY_TYPE_NULL) {
17549 bool found = FALSE;
17550 int i = 0;
17552 pavars2_data.ver = WL_PHY_PAVAR_VER;
17553 pavars2_data.len = sizeof(wl_pavars2_t);
17554 pavars2_data.phy_type = pav->phy_type;
17555 pavars2_data.bandrange = pav->bandrange;
17556 pavars2_data.chain = pav->chain;
17557 pavars2_data.inuse = 0;
17558 strcpy(par, pav->vars);
17560 cpar = strtok (par, delimit); /* current param */
17561 do {
17562 val = 0;
17564 /* Find the parameter in the input argument list */
17565 if ((p = find_pattern(argv, cpar, &val))) {
17566 found = TRUE;
17567 inpa[i] = (uint16)val;
17568 } else
17569 inpa[i] = 0;
17570 i++;
17571 } while ((cpar = strtok (NULL, delimit)));
17573 if (found) {
17574 if ((err = wlu_var_setbuf(wl, "pavars2", &pavars2_data,
17575 sizeof(wl_pavars2_t))) < 0) {
17576 printf("wl_phy_pavars2: fail to set\n");
17577 return err;
17580 pav++;
17582 } else { /* get */
17583 while (pav->phy_type != PHY_TYPE_NULL) {
17584 int i = 0;
17585 uint16 *outpa;
17587 pavars2_data.ver = WL_PHY_PAVAR_VER;
17588 pavars2_data.len = sizeof(wl_pavars2_t);
17589 pavars2_data.phy_type = pav->phy_type;
17590 pavars2_data.bandrange = pav->bandrange;
17591 pavars2_data.chain = pav->chain;
17592 pavars2_data.inuse = 0;
17593 strcpy(par, pav->vars);
17595 if ((err = wlu_var_getbuf_sm(wl, "pavars2", &pavars2_data,
17596 sizeof(wl_pavars2_t), (void **)&ptr)) < 0) {
17597 printf("phy %x band %x chain %d err %d\n", pav->phy_type,
17598 pav->chain, pav->bandrange, err);
17599 break;
17602 outpa = (uint16*)(ptr->inpa);
17603 if (ptr->phy_type == PHY_TYPE_NULL) {
17604 pav++;
17605 continue;
17608 cpar = strtok(par, delimit); /* current param */
17609 do {
17610 printf("%s=0x%x\n", cpar, outpa[i++]);
17611 } while ((cpar = strtok (NULL, delimit)));
17613 pav++;
17617 return err;
17618 #endif /* _CFE_ */
17621 static int
17622 wl_phy_pavars(void *wl, cmd_t *cmd, char **argv)
17624 #if defined(_CFE_)
17625 return CFE_ERR_UNSUPPORTED;
17626 #else
17627 const pavars_t *pav = pavars;
17628 uint16 inpa[WL_PHY_PAVARS_LEN];
17629 char *cpar = NULL, *p = NULL;
17630 char par[256]; /* holds longest pavars->vars */
17631 char delimit[2] = " \0";
17632 int err = 0;
17633 unsigned int val;
17634 void *ptr = NULL;
17636 if (*++argv) { /* set */
17637 while (pav->phy_type != PHY_TYPE_NULL) {
17638 bool found = FALSE;
17639 int i = 0;
17641 inpa[i++] = pav->phy_type;
17642 inpa[i++] = pav->bandrange;
17643 inpa[i++] = pav->chain;
17644 strcpy(par, pav->vars);
17646 cpar = strtok (par, delimit); /* current param */
17647 do {
17648 val = 0;
17650 /* Find the parameter in the input argument list */
17651 if ((p = find_pattern(argv, cpar, &val))) {
17652 found = TRUE;
17653 inpa[i] = (uint16)val;
17654 } else
17655 inpa[i] = 0;
17656 i++;
17657 } while ((cpar = strtok (NULL, delimit)));
17659 if (found) {
17660 if ((err = wlu_var_setbuf(wl, cmd->name, inpa,
17661 WL_PHY_PAVARS_LEN * sizeof(uint16))) < 0) {
17662 printf("wl_phy_pavars: fail to set\n");
17663 return err;
17666 pav++;
17668 } else { /* get */
17669 while (pav->phy_type != PHY_TYPE_NULL) {
17670 int i = 0;
17671 uint16 *outpa;
17673 inpa[i++] = pav->phy_type;
17674 inpa[i++] = pav->bandrange;
17675 inpa[i++] = pav->chain;
17676 strcpy(par, pav->vars);
17678 if ((err = wlu_var_getbuf_sm(wl, cmd->name, inpa,
17679 WL_PHY_PAVARS_LEN * sizeof(uint16), &ptr)) < 0) {
17680 printf("phy %x band %x chain %d err %d\n", pav->phy_type,
17681 pav->chain, pav->bandrange, err);
17682 break;
17685 outpa = (uint16*)ptr;
17686 if (outpa[0] == PHY_TYPE_NULL) {
17687 pav++;
17688 continue;
17691 cpar = strtok(par, delimit); /* current param */
17692 do {
17693 printf("%s=0x%x\n", cpar, outpa[i++]);
17694 } while ((cpar = strtok (NULL, delimit)));
17696 pav++;
17700 return err;
17701 #endif /* _CFE_ */
17704 static int
17705 wl_phy_povars(void *wl, cmd_t *cmd, char **argv)
17707 #if defined(_CFE_)
17708 return CFE_ERR_UNSUPPORTED;
17709 #else
17710 const povars_t *pov = povars;
17711 wl_po_t inpo;
17712 char *cpar = NULL, *p = NULL;
17713 char par[256]; /* holds longest povars->vars */
17714 char delimit[2] = " \0";
17715 int err = 0;
17716 uint val;
17717 void *ptr = NULL;
17719 if (*++argv) { /* set */
17720 while (pov->phy_type != PHY_TYPE_NULL) {
17721 bool found = FALSE;
17722 int i = 0;
17724 inpo.phy_type = pov->phy_type;
17725 inpo.band = pov->bandrange;
17726 strcpy(par, pov->vars);
17728 /* Take care of cck and ofdm before walking through povars->vars */
17729 if (pov->bandrange == WL_CHAN_FREQ_RANGE_2G) {
17730 p = find_pattern(argv, "cck2gpo", &val);
17731 if (p) found = TRUE;
17732 inpo.cckpo = p ? (uint16)val : 0;
17734 p = find_pattern(argv, "ofdm2gpo", &val);
17735 } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GL) {
17736 p = find_pattern(argv, "ofdm5glpo", &val);
17737 } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GM) {
17738 p = find_pattern(argv, "ofdm5gpo", &val);
17739 } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GH) {
17740 p = find_pattern(argv, "ofdm5ghpo", &val);
17742 inpo.ofdmpo = p ? (uint32)val : 0;
17743 if (p) found = TRUE;
17745 cpar = strtok (par, delimit); /* current param */
17746 do {
17747 val = 0;
17749 /* Find the parameter in the input argument list */
17750 p = find_pattern(argv, cpar, &val);
17751 if (p) found = TRUE;
17752 inpo.mcspo[i] = p ? (uint16)val : 0;
17753 i++;
17754 } while ((cpar = strtok (NULL, delimit)));
17756 if (found) {
17757 if ((err = wlu_var_setbuf(wl, cmd->name, &inpo,
17758 sizeof(wl_po_t))) < 0) {
17759 printf("wl_phy_povars: fail to set\n");
17760 return err;
17763 pov++;
17765 } else { /* get */
17766 while (pov->phy_type != PHY_TYPE_NULL) {
17767 int i = 0;
17768 wl_po_t *outpo;
17770 inpo.phy_type = pov->phy_type;
17771 inpo.band = pov->bandrange;
17772 strcpy(par, pov->vars);
17774 if ((err = wlu_var_getbuf(wl, cmd->name, &inpo, sizeof(povars_t),
17775 &ptr)) < 0) {
17776 printf("phy %x band %x err %d\n", pov->phy_type,
17777 pov->bandrange, err);
17778 break;
17781 outpo = (wl_po_t*)ptr;
17782 if (outpo->phy_type == PHY_TYPE_NULL) {
17783 pov++;
17784 continue;
17787 /* Take care of cck and ofdm before walking through povars->vars */
17788 if (outpo->band == WL_CHAN_FREQ_RANGE_2G) {
17789 printf("cck2gpo=0x%x\n", outpo->cckpo);
17790 printf("ofdm2gpo=0x%x\n", outpo->ofdmpo);
17791 } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GL) {
17792 printf("ofdm5glpo=0x%x\n", outpo->ofdmpo);
17793 } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GM) {
17794 printf("ofdm5gpo=0x%x\n", outpo->ofdmpo);
17795 } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GH) {
17796 printf("ofdm5ghpo=0x%x\n", outpo->ofdmpo);
17799 cpar = strtok(par, delimit); /* current param */
17800 do {
17801 printf("%s=0x%x\n", cpar, outpo->mcspo[i++]);
17802 } while ((cpar = strtok (NULL, delimit)));
17804 pov++;
17808 return err;
17809 #endif /* _CFE_ */
17812 static int
17813 wl_phy_fem(void *wl, cmd_t *cmd, char **argv)
17815 #if defined(_CFE_)
17816 return CFE_ERR_UNSUPPORTED;
17817 #else
17818 srom_fem_t fem;
17819 srom_fem_t *rfem;
17820 void *ptr;
17821 bool found = FALSE;
17822 int err = 0;
17823 uint val;
17825 UNUSED_PARAMETER(cmd);
17827 if (*++argv) { /* write fem */
17829 /* fem2g */
17830 memset(&fem, 0, sizeof(srom_fem_t));
17832 if (find_pattern(argv, "tssipos2g", &val)) {
17833 found = TRUE;
17834 fem.tssipos = val;
17837 if (find_pattern(argv, "extpagain2g", &val)) {
17838 found = TRUE;
17839 fem.extpagain = val;
17842 if (find_pattern(argv, "pdetrange2g", &val)) {
17843 found = TRUE;
17844 fem.pdetrange = val;
17847 if (find_pattern(argv, "triso2g", &val)) {
17848 found = TRUE;
17849 fem.triso = val;
17852 if (find_pattern(argv, "antswctl2g", &val)) {
17853 found = TRUE;
17854 fem.antswctrllut = val;
17857 if (found) {
17858 if ((err = wlu_var_setbuf(wl, "fem2g", &fem, sizeof(srom_fem_t)) < 0))
17859 printf("wl_phy_fem: fail to set fem2g\n");
17860 else
17861 printf("fem2g set\n");
17864 found = FALSE;
17865 /* fem5g */
17866 memset(&fem, 0, sizeof(srom_fem_t));
17868 if (find_pattern(argv, "tssipos5g", &val)) {
17869 found = TRUE;
17870 fem.tssipos = val;
17873 if (find_pattern(argv, "extpagain5g", &val)) {
17874 found = TRUE;
17875 fem.extpagain = val;
17878 if (find_pattern(argv, "pdetrange5g", &val)) {
17879 found = TRUE;
17880 fem.pdetrange = val;
17883 if (find_pattern(argv, "triso5g", &val)) {
17884 found = TRUE;
17885 fem.triso = val;
17888 if (find_pattern(argv, "antswctl5g", &val)) {
17889 found = TRUE;
17890 fem.antswctrllut = val;
17893 if (found) {
17894 if ((err = wlu_var_setbuf(wl, "fem5g", &fem, sizeof(srom_fem_t)) < 0))
17895 printf("wl_phy_fem: fail to set fem5g\n");
17896 else
17897 printf("fem5g set\n");
17899 } else {
17900 if ((err = wlu_var_getbuf(wl, "fem2g", NULL, 0, (void**)&ptr) < 0)) {
17901 printf("wl_phy_fem: fail to get fem2g\n");
17902 } else {
17903 rfem = (srom_fem_t*)ptr; /* skip the "fem2g" */
17904 printf("tssipos2g=0x%x extpagain2g=0x%x pdetrange2g=0x%x"
17905 " triso2g=0x%x antswctl2g=0x%x\n",
17906 rfem->tssipos, rfem->extpagain, rfem->pdetrange,
17907 rfem->triso, rfem->antswctrllut);
17910 if ((err = wlu_var_getbuf(wl, "fem5g", NULL, 0, (void**)&ptr) < 0)) {
17911 printf("wl_phy_fem: fail to get fem5g\n");
17912 } else {
17913 rfem = (srom_fem_t*)ptr; /* skip the "fem2g" */
17914 printf("tssipos5g=0x%x extpagain5g=0x%x pdetrange5g=0x%x"
17915 " triso5g=0x%x antswctl5g=0x%x\n",
17916 rfem->tssipos, rfem->extpagain, rfem->pdetrange,
17917 rfem->triso, rfem->antswctrllut);
17921 return err;
17922 #endif /* _CFE_ */
17925 static int
17926 wl_phy_maxpower(void *wl, cmd_t *cmd, char **argv)
17928 #if defined(_CFE_)
17929 return CFE_ERR_UNSUPPORTED;
17930 #else
17931 int err = 0;
17932 uint val;
17933 uint8 maxp[8];
17934 void *ptr;
17935 uint8 *rmaxp;
17937 UNUSED_PARAMETER(cmd);
17939 if (*++argv) { /* write maxpower */
17941 if (find_pattern(argv, "maxp2ga0", &val))
17942 maxp[0] = val;
17943 else
17944 printf("Missing maxp2ga0\n");
17946 if (find_pattern(argv, "maxp2ga1", &val))
17947 maxp[1] = val;
17948 else
17949 printf("Missing maxp2ga1\n");
17951 if (find_pattern(argv, "maxp5ga0", &val))
17952 maxp[2] = val;
17953 else
17954 printf("Missing maxp5ga0\n");
17956 if (find_pattern(argv, "maxp5ga1", &val))
17957 maxp[3] = val;
17958 else
17959 printf("Missing maxp5ga1\n");
17961 if (find_pattern(argv, "maxp5gla0", &val))
17962 maxp[4] = val;
17963 else
17964 printf("Missing maxp5gla0\n");
17966 if (find_pattern(argv, "maxp5gla1", &val))
17967 maxp[5] = val;
17968 else
17969 printf("Missing maxp5gla1\n");
17971 if (find_pattern(argv, "maxp5gha0", &val))
17972 maxp[6] = val;
17973 else
17974 printf("Missing maxp5gha0\n");
17976 if (find_pattern(argv, "maxp5gha1", &val))
17977 maxp[7] = val;
17978 else
17979 printf("Missing maxp5gha1\n");
17981 if ((err = wlu_var_setbuf(wl, "maxpower", &maxp, 8 * sizeof(uint8)) < 0)) {
17982 printf("wl_phy_maxpower: fail to set\n");
17983 err = -1;
17985 } else {
17986 if ((err = wlu_var_getbuf(wl, "maxpower", NULL, 0, &ptr) < 0)) {
17987 printf("wl_phy_maxpower: fail to get maxpower\n");
17988 err = -1;
17990 rmaxp = (uint8*)ptr;
17991 printf("maxp2ga0=%x\n", rmaxp[0]);
17992 printf("maxp2ga1=%x\n", rmaxp[1]);
17993 printf("maxp5ga0=%x\n", rmaxp[2]);
17994 printf("maxp5ga1=%x\n", rmaxp[3]);
17995 printf("maxp5gla0=%x\n", rmaxp[4]);
17996 printf("maxp5gla1=%x\n", rmaxp[5]);
17997 printf("maxp5gha0=%x\n", rmaxp[6]);
17998 printf("maxp5gha1=%x\n", rmaxp[7]);
18001 return err;
18002 #endif /* _CFE_ */
18005 static int
18006 wl_antgain(void *wl, cmd_t *cmd, char **argv)
18008 #if defined(_CFE_)
18009 return CFE_ERR_UNSUPPORTED;
18010 #else
18011 int err = 0;
18012 uint val;
18013 uint8 ag[2];
18014 uint8 *rag;
18015 void *ptr;
18017 UNUSED_PARAMETER(cmd);
18019 if (*++argv) { /* write maxpower */
18020 if (find_pattern(argv, "ag0", &val))
18021 ag[0] = val & 0xff;
18022 else {
18023 printf("Missing ag0\n");
18024 return 0;
18027 if (find_pattern(argv, "ag1", &val))
18028 ag[1] = val & 0xff;
18029 else {
18030 printf("Missing ag1\n");
18031 return 0;
18034 if ((err = wlu_var_setbuf(wl, "antgain", &ag, 2 * sizeof(uint8)) < 0)) {
18035 printf("wl_antgain: fail to set\n");
18036 err = -1;
18038 } else {
18039 if ((err = wlu_var_getbuf(wl, "antgain", NULL, 0, &ptr) < 0)) {
18040 printf("wl_antgain: fail to get antgain\n");
18041 err = -1;
18043 rag = (uint8*)ptr;
18044 printf("ag0=%x\n", rag[0]);
18045 printf("ag1=%x\n", rag[1]);
18048 return err;
18049 #endif /* _CFE_ */
18052 static int
18053 wl_pkteng(void *wl, cmd_t *cmd, char **argv)
18055 wl_pkteng_t pkteng;
18057 memset(&pkteng, 0, sizeof(pkteng));
18058 if (strcmp(cmd->name, "pkteng_stop") == 0) {
18059 if (!*++argv)
18060 return -1;
18061 if (strcmp(*argv, "tx") == 0)
18062 pkteng.flags = WL_PKTENG_PER_TX_STOP;
18063 else if (strcmp(*argv, "rx") == 0)
18064 pkteng.flags = WL_PKTENG_PER_RX_STOP;
18065 else
18066 return -1;
18067 return (wlu_var_setbuf(wl, "pkteng", &pkteng, sizeof(pkteng)));
18069 else if (strcmp(cmd->name, "pkteng_start") == 0) {
18070 if (!*++argv)
18071 return -1;
18072 if (!wl_ether_atoe(*argv, (struct ether_addr *)&pkteng.dest))
18073 return -1;
18074 if (!*++argv)
18075 return -1;
18076 if ((strcmp(*argv, "tx") == 0) || (strcmp(*argv, "txwithack") == 0)) {
18077 if (strcmp(*argv, "tx") == 0)
18078 pkteng.flags = WL_PKTENG_PER_TX_START;
18079 else
18080 pkteng.flags = WL_PKTENG_PER_TX_WITH_ACK_START;
18081 if (!*++argv)
18082 return -1;
18083 if (strcmp(*argv, "async") == 0)
18084 pkteng.flags &= ~WL_PKTENG_SYNCHRONOUS;
18085 else if (strcmp(*argv, "sync") == 0)
18086 pkteng.flags |= WL_PKTENG_SYNCHRONOUS;
18087 else
18088 /* neither optional parameter [async|sync] */
18089 --argv;
18090 if (!*++argv)
18091 return -1;
18092 pkteng.delay = strtoul(*argv, NULL, 0);
18093 if (!*++argv)
18094 return -1;
18095 pkteng.length = strtoul(*argv, NULL, 0);
18096 if (!*++argv)
18097 return -1;
18098 pkteng.nframes = strtoul(*argv, NULL, 0);
18099 if (*++argv)
18100 if (!wl_ether_atoe(*argv, (struct ether_addr *)&pkteng.src))
18101 return -1;
18103 else if ((strcmp(*argv, "rx") == 0) || (strcmp(*argv, "rxwithack") == 0)) {
18104 if ((strcmp(*argv, "rx") == 0))
18105 pkteng.flags = WL_PKTENG_PER_RX_START;
18106 else
18107 pkteng.flags = WL_PKTENG_PER_RX_WITH_ACK_START;
18109 if (*++argv) {
18110 if (strcmp(*argv, "async") == 0)
18111 pkteng.flags &= ~WL_PKTENG_SYNCHRONOUS;
18112 else if (strcmp(*argv, "sync") == 0) {
18113 pkteng.flags |= WL_PKTENG_SYNCHRONOUS;
18114 /* sync mode requires number of frames and timeout */
18115 if (!*++argv)
18116 return -1;
18117 pkteng.nframes = strtoul(*argv, NULL, 0);
18118 if (!*++argv)
18119 return -1;
18120 pkteng.delay = strtoul(*argv, NULL, 0);
18124 else
18125 return -1;
18127 return (wlu_var_setbuf(wl, "pkteng", &pkteng, sizeof(pkteng)));
18129 else {
18130 printf("Invalid command name %s\n", cmd->name);
18131 return 0;
18135 static int
18136 wl_rxiq(void *wl, cmd_t *cmd, char **argv)
18138 miniopt_t to;
18139 const char* fn_name = "wl_rxiqest";
18140 int err, argc, opt_err;
18141 uint32 rxiq;
18142 uint8 resolution = 0;
18143 uint8 lpf_hpc = 1;
18144 uint8 gain_correct = 0;
18146 /* arg count */
18147 for (argc = 0; argv[argc]; argc++);
18149 /* DEFAULT:
18150 * gain_correct = 0 (disable gain correction),
18151 * lpf_hpc = 1 (sets lpf hpc to lowest value),
18152 * resolution = 0 (coarse),
18153 * samples = 1024 (2^10) and antenna = 3
18155 rxiq = (gain_correct << 24) | (lpf_hpc << 20) | (resolution << 16) | (10 << 8) | 3;
18158 if (argc != 0) {
18159 miniopt_init(&to, fn_name, NULL, FALSE);
18160 while ((opt_err = miniopt(&to, argv)) != -1) {
18161 if (opt_err == 1) {
18162 err = -1;
18163 goto exit;
18165 argv += to.consumed;
18167 if (to.opt == 'g') {
18168 if (!to.good_int) {
18169 fprintf(stderr,
18170 "%s: could not parse \"%s\" as an int"
18171 " for gain-correction (0, 1)\n",
18172 fn_name, to.valstr);
18174 err = -1;
18175 goto exit;
18177 if ((to.val < 0) || (to.val > 1)) {
18178 fprintf(stderr, "%s: invalid gain-correction select %d"
18179 " (0,1)\n", fn_name, to.val);
18180 err = -1;
18181 goto exit;
18183 gain_correct = to.val & 0xf;
18184 rxiq = ((gain_correct << 24) | (rxiq & 0xffffff));
18186 if (to.opt == 'f') {
18187 if (!to.good_int) {
18188 fprintf(stderr,
18189 "%s: could not parse \"%s\" as an int"
18190 " for lpf-hpc override select (0, 1)\n",
18191 fn_name, to.valstr);
18192 err = -1;
18193 goto exit;
18195 if ((to.val < 0) || (to.val > 1)) {
18196 fprintf(stderr, "%s: invalid lpf-hpc override select %d"
18197 " (0,1)\n", fn_name, to.val);
18198 err = -1;
18199 goto exit;
18201 lpf_hpc = to.val & 0xf;
18202 rxiq = ((lpf_hpc << 20) | (rxiq & 0xf0fffff));
18204 if (to.opt == 'r') {
18205 if (!to.good_int) {
18206 fprintf(stderr,
18207 "%s: could not parse \"%s\" as an int"
18208 " for resolution (0, 1)\n", fn_name, to.valstr);
18209 err = -1;
18210 goto exit;
18212 if ((to.val < 0) || (to.val > 1)) {
18213 fprintf(stderr, "%s: invalid resolution select %d"
18214 " (0,1)\n", fn_name, to.val);
18215 err = -1;
18216 goto exit;
18218 resolution = to.val & 0xf;
18219 rxiq = ((resolution << 16) | (rxiq & 0xff0ffff));
18221 if (to.opt == 's') {
18222 if (!to.good_int) {
18223 fprintf(stderr,
18224 "%s: could not parse \"%s\" as an int for"
18225 " the sample count\n", fn_name, to.valstr);
18226 err = -1;
18227 goto exit;
18229 if (to.val < 0 || to.val > 16) {
18230 fprintf(stderr, "%s: sample count too large %d"
18231 "(10 <= x <= 16)\n", fn_name, to.val);
18232 err = -1;
18233 goto exit;
18235 rxiq = (((to.val & 0xff) << 8) | (rxiq & 0xfff00ff));
18237 if (to.opt == 'a') {
18238 if (!to.good_int) {
18239 fprintf(stderr,
18240 "%s: could not parse \"%s\" as an int"
18241 " for antenna (0, 1, 3)\n", fn_name, to.valstr);
18242 err = -1;
18243 goto exit;
18245 if ((to.val < 0) || (to.val > 3)) {
18246 fprintf(stderr, "%s: invalid antenna select %d\n",
18247 fn_name, to.val);
18248 err = -1;
18249 goto exit;
18251 rxiq = ((rxiq & 0xfffff00) | (to.val & 0xff));
18256 if ((err = wlu_iovar_setint(wl, cmd->name, (int)rxiq)) < 0)
18257 return err;
18258 if ((err = wlu_iovar_getint(wl, cmd->name, (int*)&rxiq)) < 0)
18259 return err;
18261 if (resolution == 1) {
18262 /* fine resolution power reporting (0.25dB resolution) */
18263 if (rxiq >> 20) {
18264 /* Three chains: */
18265 uint8 core;
18266 int16 tmp;
18267 for (core = 0; core < 3; core ++) {
18268 tmp = (rxiq >> (10*core)) & 0x3ff;
18269 tmp = ((int16)(tmp << 6)) >> 6; /* sign extension */
18270 if (tmp < 0) {
18271 tmp = -1*tmp;
18272 printf("-%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25);
18273 } else {
18274 printf("%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25);
18277 printf("\n");
18279 } else {
18280 if (rxiq >> 16)
18281 printf("%ddBm %ddBm %ddBm\n", (int8)(rxiq & 0xff),
18282 (int8)((rxiq >> 8) & 0xff), (int8)((rxiq >> 16) & 0xff));
18283 else if (rxiq >> 8)
18284 printf("%ddBm %ddBm\n", (int8)(rxiq & 0xff), (int8)((rxiq >> 8) & 0xff));
18285 else
18286 printf("%ddBm\n", (int8)(rxiq & 0xff));
18288 exit:
18289 return err;
18292 /* Convert user's input in hex pattern to byte-size mask */
18293 static int
18294 wl_pattern_atoh(char *src, char *dst)
18296 int i;
18297 if (strncmp(src, "0x", 2) != 0 &&
18298 strncmp(src, "0X", 2) != 0) {
18299 printf("Mask invalid format. Needs to start with 0x\n");
18300 return -1;
18302 src = src + 2; /* Skip past 0x */
18303 if (strlen(src) % 2 != 0) {
18304 printf("Mask invalid format. Needs to be of even length\n");
18305 return -1;
18307 for (i = 0; *src != '\0'; i++) {
18308 char num[3];
18309 strncpy(num, src, 2);
18310 num[2] = '\0';
18311 dst[i] = (uint8)strtoul(num, NULL, 16);
18312 src += 2;
18314 return i;
18317 static int
18318 wl_wowl_status(void *wl, cmd_t *cmd, char **argv)
18320 int flags_prev = 0;
18321 int err;
18323 UNUSED_PARAMETER(cmd);
18325 argv++;
18327 if ((err = wlu_iovar_getint(wl, "wowl_status", &flags_prev)))
18328 return err;
18330 printf("Status of last wakeup:\n");
18331 printf("\tflags:0x%x\n", flags_prev);
18333 if (flags_prev & WL_WOWL_BCN)
18334 printf("\t\tWake-on-Loss-of-Beacons enabled\n");
18336 if (flags_prev & WL_WOWL_MAGIC)
18337 printf("\t\tWake-on-Magic frame enabled\n");
18338 if (flags_prev & WL_WOWL_NET)
18339 printf("\t\tWake-on-Net pattern enabled\n");
18340 if (flags_prev & WL_WOWL_DIS)
18341 printf("\t\tWake-on-Deauth enabled\n");
18343 if (flags_prev & WL_WOWL_RETR)
18344 printf("\t\tRetrograde TSF enabled\n");
18345 if (flags_prev & WL_WOWL_TST)
18346 printf("\t\tTest-mode enabled\n");
18348 printf("\n");
18350 return 0;
18353 static int
18354 wl_wowl_wakeind(void *wl, cmd_t *cmd, char **argv)
18356 wl_wowl_wakeind_t wake = {0, 0};
18357 int err;
18359 UNUSED_PARAMETER(cmd);
18361 argv++;
18363 if (*argv) {
18364 if (strcmp(*argv, "clear"))
18365 return -1;
18366 err = wlu_iovar_set(wl, "wowl_wakeind", *argv, strlen(*argv));
18367 return err;
18370 if ((err = wlu_iovar_get(wl, "wowl_wakeind", &wake, sizeof(wl_wowl_wakeind_t))) < 0)
18371 return err;
18373 if (wake.pci_wakeind)
18374 printf("PCI Indication set\n");
18375 if (wake.ucode_wakeind != 0) {
18376 printf("MAC Indication set\n");
18378 if ((wake.ucode_wakeind & WL_WOWL_MAGIC) == WL_WOWL_MAGIC)
18379 printf("\tMAGIC packet received\n");
18380 if ((wake.ucode_wakeind & WL_WOWL_NET) == WL_WOWL_NET)
18381 printf("\tPacket received with Netpattern\n");
18382 if ((wake.ucode_wakeind & WL_WOWL_DIS) == WL_WOWL_DIS)
18383 printf("\tDisassociation/Deauth received\n");
18384 if ((wake.ucode_wakeind & WL_WOWL_RETR) == WL_WOWL_RETR)
18385 printf("\tRetrograde TSF detected\n");
18386 if ((wake.ucode_wakeind & WL_WOWL_BCN) == WL_WOWL_BCN)
18387 printf("\tBeacons Lost\n");
18388 if ((wake.ucode_wakeind & WL_WOWL_TST) == WL_WOWL_TST)
18389 printf("\tTest Mode\n");
18390 if ((wake.ucode_wakeind & (WL_WOWL_NET | WL_WOWL_MAGIC))) {
18391 if ((wake.ucode_wakeind & WL_WOWL_BCAST) == WL_WOWL_BCAST)
18392 printf("\t\tBroadcast/Mcast frame received\n");
18393 else
18394 printf("\t\tUnicast frame received\n");
18398 if (!wake.pci_wakeind && wake.ucode_wakeind == 0)
18399 printf("No wakeup indication set\n");
18401 return 0;
18404 /* Send a wakeup frame to sta in WAKE mode */
18405 static int
18406 wl_wowl_pkt(void *wl, cmd_t *cmd, char **argv)
18408 char *arg = buf;
18409 const char *str;
18410 char *dst;
18411 uint tot = 0;
18412 uint16 type, pkt_len;
18413 int dst_ea = 0; /* 0 == manual, 1 == bcast, 2 == ucast */
18414 char *ea[ETHER_ADDR_LEN];
18415 if (!*++argv)
18416 return -1;
18418 UNUSED_PARAMETER(cmd);
18420 str = "wowl_pkt";
18421 strncpy(arg, str, strlen(str));
18422 arg[strlen(str)] = '\0';
18423 dst = arg + strlen(str) + 1;
18424 tot += strlen(str) + 1;
18426 pkt_len = (uint16)htod32(strtoul(*argv, NULL, 0));
18428 *((uint16*)dst) = pkt_len;
18430 dst += sizeof(pkt_len);
18431 tot += sizeof(pkt_len);
18433 if (!*++argv) {
18434 printf("Dest of the packet needs to be provided\n");
18435 return -1;
18438 /* Dest of the frame */
18439 if (!strcmp(*argv, "bcast")) {
18440 dst_ea = 1;
18441 if (!wl_ether_atoe("ff:ff:ff:ff:ff:ff", (struct ether_addr *)dst))
18442 return -1;
18443 } else if (!strcmp(*argv, "ucast")) {
18444 dst_ea = 2;
18445 if (!*++argv) {
18446 printf("EA of ucast dest of the packet needs to be provided\n");
18447 return -1;
18449 if (!wl_ether_atoe(*argv, (struct ether_addr *)dst))
18450 return -1;
18451 /* Store it */
18452 memcpy(ea, dst, ETHER_ADDR_LEN);
18453 } else if (!wl_ether_atoe(*argv, (struct ether_addr *)dst))
18454 return -1;
18456 dst += ETHER_ADDR_LEN;
18457 tot += ETHER_ADDR_LEN;
18459 if (!*++argv) {
18460 printf("type - magic/net needs to be provided\n");
18461 return -1;
18464 if (strncmp(*argv, "magic", strlen("magic")) == 0)
18465 type = WL_WOWL_MAGIC;
18466 else if (strncmp(*argv, "net", strlen("net")) == 0)
18467 type = WL_WOWL_NET;
18468 else
18469 return -1;
18471 *((uint16*)dst) = type;
18472 dst += sizeof(type);
18473 tot += sizeof(type);
18475 if (type == WL_WOWL_MAGIC) {
18476 if (pkt_len < MAGIC_PKT_MINLEN)
18477 return -1;
18479 if (dst_ea == 2)
18480 memcpy(dst, ea, ETHER_ADDR_LEN);
18481 else {
18482 if (!*++argv)
18483 return -1;
18485 if (!wl_ether_atoe(*argv, (struct ether_addr *)dst))
18486 return -1;
18488 tot += ETHER_ADDR_LEN;
18489 } else {
18490 wl_wowl_pattern_t *wl_pattern;
18491 wl_pattern = (wl_wowl_pattern_t *)dst;
18493 if (!*++argv) {
18494 printf("Starting offset not provided\n");
18495 return -1;
18498 wl_pattern->offset = (uint)htod32(strtoul(*argv, NULL, 0));
18500 wl_pattern->masksize = 0;
18502 wl_pattern->patternoffset = (uint)htod32(sizeof(wl_wowl_pattern_t));
18504 dst += sizeof(wl_wowl_pattern_t);
18506 if (!*++argv) {
18507 printf("pattern not provided\n");
18508 return -1;
18511 wl_pattern->patternsize =
18512 (uint)htod32(wl_pattern_atoh((char *)(uintptr)*argv, dst));
18514 tot += sizeof(wl_wowl_pattern_t) + wl_pattern->patternsize;
18517 return (wlu_set(wl, WLC_SET_VAR, arg, tot));
18520 static int
18521 wl_wowl_pattern(void *wl, cmd_t *cmd, char **argv)
18523 int err;
18524 uint i, j;
18525 uint8 *ptr;
18526 wl_wowl_pattern_t *wl_pattern;
18528 UNUSED_PARAMETER(cmd);
18530 if (*++argv) {
18531 char *arg = buf;
18532 const char *str;
18533 char *dst;
18534 uint tot = 0;
18536 if (strcmp(*argv, "add") != 0 && strcmp(*argv, "del") != 0 &&
18537 strcmp(*argv, "clr") != 0) {
18538 return -1;
18541 str = "wowl_pattern";
18542 strncpy(arg, str, strlen(str));
18543 arg[strlen(str)] = '\0';
18544 dst = arg + strlen(str) + 1;
18545 tot += strlen(str) + 1;
18547 str = *argv;
18548 strncpy(dst, str, strlen(str));
18549 tot += strlen(str) + 1;
18551 if (strcmp(str, "clr") != 0) {
18552 wl_pattern = (wl_wowl_pattern_t *)(dst + strlen(str) + 1);
18553 dst = (char*)wl_pattern + sizeof(wl_wowl_pattern_t);
18554 if (!*++argv) {
18555 printf("Starting offset not provided\n");
18556 return -1;
18558 wl_pattern->offset = htod32(strtoul(*argv, NULL, 0));
18559 if (!*++argv) {
18560 printf("Mask not provided\n");
18561 return -1;
18564 /* Parse the mask */
18565 str = *argv;
18566 wl_pattern->masksize = htod32(wl_pattern_atoh((char *)(uintptr)str, dst));
18567 if (wl_pattern->masksize == (uint)-1)
18568 return -1;
18570 dst += wl_pattern->masksize;
18571 wl_pattern->patternoffset = htod32((sizeof(wl_wowl_pattern_t) +
18572 wl_pattern->masksize));
18574 if (!*++argv) {
18575 printf("Pattern value not provided\n");
18576 return -1;
18579 /* Parse the value */
18580 str = *argv;
18581 wl_pattern->patternsize =
18582 htod32(wl_pattern_atoh((char *)(uintptr)str, dst));
18583 if (wl_pattern->patternsize == (uint)-1)
18584 return -1;
18585 tot += sizeof(wl_wowl_pattern_t) + wl_pattern->patternsize +
18586 wl_pattern->masksize;
18589 return (wlu_set(wl, WLC_SET_VAR, arg, tot));
18590 } else {
18591 wl_wowl_pattern_list_t *list;
18592 if ((err = wlu_iovar_get(wl, "wowl_pattern", buf, WLC_IOCTL_MAXLEN)) < 0)
18593 return err;
18594 list = (wl_wowl_pattern_list_t *)buf;
18595 printf("#of patterns :%d\n", list->count);
18596 ptr = (uint8 *)list->pattern;
18597 for (i = 0; i < list->count; i++) {
18598 uint8 *pattern;
18600 wl_pattern = (wl_wowl_pattern_t *)ptr;
18601 printf("Pattern %d:\n", i+1);
18602 printf("Offset :%d\n"
18603 "Masksize :%d\n"
18604 "Mask :0x",
18605 wl_pattern->offset, wl_pattern->masksize);
18606 pattern = ((uint8 *)wl_pattern + sizeof(wl_wowl_pattern_t));
18607 for (j = 0; j < wl_pattern->masksize; j++)
18608 printf("%02x", pattern[j]);
18609 printf("\n"
18610 "PatternSize:%d\n"
18611 "Pattern :0x", wl_pattern->patternsize);
18612 /* Go to end to find pattern */
18613 pattern = ((uint8*)wl_pattern + wl_pattern->patternoffset);
18614 for (j = 0; j < wl_pattern->patternsize; j++)
18615 printf("%02x", pattern[j]);
18616 printf("\n\n");
18617 ptr += (wl_pattern->masksize + wl_pattern->patternsize +
18618 sizeof(wl_wowl_pattern_t));
18622 return err;
18625 static int
18626 wl_rifs(void *wl, cmd_t *cmd, char **argv)
18628 int err;
18629 int val, rifs;
18630 char *val_name;
18632 UNUSED_PARAMETER(cmd);
18634 /* command name */
18635 val_name = *argv++;
18637 if (!*argv) {
18638 if ((err = wlu_iovar_getint(wl, val_name, (int*)&rifs)) < 0)
18639 return err;
18641 printf("%s\n", ((rifs & 0xff) ? "On" : "Off"));
18642 return 0;
18645 val = rifs = (atoi(*argv) ? 1 : 0);
18646 if (rifs != 0 && rifs != 1)
18647 return USAGE_ERROR;
18649 if ((err = wlu_set(wl, WLC_SET_FAKEFRAG, &val, sizeof(int))) < 0) {
18650 printf("Set frameburst error %d\n", err);
18651 return err;
18653 if ((err = wlu_iovar_setint(wl, val_name, (int)rifs)) < 0)
18654 printf("Set rifs error %d\n", err);
18656 return err;
18659 static int
18660 wl_rifs_advert(void *wl, cmd_t *cmd, char **argv)
18662 int err;
18663 int rifs_advert;
18664 char *val_name;
18666 BCM_REFERENCE(cmd);
18668 /* command name */
18669 val_name = *argv++;
18671 if (!*argv) {
18672 if ((err = wlu_iovar_getint(wl, val_name, (int*)&rifs_advert)) < 0)
18673 return err;
18675 printf("%s\n", ((rifs_advert & 0xff) ? "On" : "Off"));
18676 return 0;
18679 if (strcmp(*argv, "-1") && strcmp(*argv, "0"))
18680 return USAGE_ERROR;
18682 rifs_advert = atoi(*argv);
18684 if ((err = wlu_iovar_setint(wl, val_name, (int)rifs_advert)) < 0)
18685 printf("Set rifs mode advertisement error %d\n", err);
18687 return err;
18690 static void
18691 clean_up_cmd_list(void)
18693 wl_seq_cmd_pkt_t *this_cmd, *next_cmd;
18695 this_cmd = cmd_list.head;
18696 while (this_cmd != NULL) {
18697 next_cmd = this_cmd->next;
18698 if (this_cmd->data != NULL) {
18699 free(this_cmd->data);
18701 free(this_cmd);
18702 this_cmd = next_cmd;
18704 cmd_list.head = NULL;
18705 cmd_list.tail = NULL;
18706 cmd_pkt_list_num = 0;
18709 static int
18710 add_one_batched_cmd(int cmd, void *cmdbuf, int len)
18712 wl_seq_cmd_pkt_t *new_cmd;
18714 new_cmd = malloc(sizeof(wl_seq_cmd_pkt_t));
18716 if (new_cmd == NULL) {
18717 printf("malloc(%d) failed, free %d batched commands and exit batching mode\n",
18718 (int)sizeof(wl_seq_cmd_pkt_t), cmd_pkt_list_num);
18719 goto free_and_exit;
18720 } else {
18721 printf("batching %dth command %d\n", cmd_pkt_list_num+1, cmd);
18724 new_cmd->cmd_header.cmd = cmd;
18725 new_cmd->cmd_header.len = len;
18726 new_cmd->next = NULL;
18728 new_cmd->data = malloc(len);
18730 if (new_cmd->data == NULL) {
18731 printf("malloc(%d) failed, free %d batched commands and exit batching mode\n",
18732 len, cmd_pkt_list_num);
18733 free(new_cmd);
18734 goto free_and_exit;
18737 memcpy(new_cmd->data, cmdbuf, len);
18739 if (cmd_list.tail != NULL)
18740 cmd_list.tail->next = new_cmd;
18741 else
18742 cmd_list.head = new_cmd;
18744 cmd_list.tail = new_cmd;
18746 cmd_pkt_list_num ++;
18747 return 0;
18749 free_and_exit:
18751 clean_up_cmd_list();
18753 if (cmd_batching_mode) {
18754 cmd_batching_mode = FALSE;
18756 else {
18757 printf("calling add_one_batched_cmd() at non-command-batching mode, weird\n");
18760 return -1;
18763 /* now IOCTL GET commands shall call wlu_get() instead of wl_get() so that the commands
18764 * can be batched when needed
18767 wlu_get(void *wl, int cmd, void *cmdbuf, int len)
18769 if (cmd_batching_mode) {
18770 if (!WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd)) {
18771 printf("IOCTL GET command %d is not supported in batching mode\n", cmd);
18772 return IOCTL_ERROR;
18776 return wl_get(wl, cmd, cmdbuf, len);
18779 /* now IOCTL SET commands shall call wlu_set() instead of wl_set() so that the commands
18780 * can be batched when needed
18783 wlu_set(void *wl, int cmd, void *cmdbuf, int len)
18785 if (cmd_batching_mode) {
18786 return add_one_batched_cmd(cmd, cmdbuf, len);
18788 else {
18789 return wl_set(wl, cmd, cmdbuf, len);
18793 /* this is the batched command packet size. now for remoteWL, we set it to 512 bytes */
18794 #define MEMBLOCK (512 - 32) /* allow 32 bytes for overhead (header, alignment, etc) */
18796 int wl_seq_batch_in_client(bool enable)
18798 batch_in_client = enable;
18799 return 0;
18803 wl_seq_start(void *wl, cmd_t *cmd, char **argv)
18805 UNUSED_PARAMETER(cmd);
18806 UNUSED_PARAMETER(argv);
18808 if (!batch_in_client) {
18809 return wlu_iovar_setbuf(wl, "seq_start", NULL, 0, buf, WLC_IOCTL_MAXLEN);
18811 else {
18812 if (cmd_batching_mode) {
18813 printf("calling seq_start() when it's already in batching mode\n");
18814 clean_up_cmd_list();
18815 cmd_batching_mode = FALSE;
18816 return USAGE_ERROR;
18818 else {
18819 cmd_batching_mode = TRUE;
18820 cmd_pkt_list_num = 0;
18822 cmd_list.head = NULL;
18823 cmd_list.tail = NULL;
18827 return 0;
18831 wl_seq_stop(void *wl, cmd_t *cmd, char **argv)
18833 char *bufp;
18834 int ret = 0;
18835 int seq_list_len;
18836 int len;
18837 wl_seq_cmd_pkt_t *next_cmd;
18839 UNUSED_PARAMETER(cmd);
18840 UNUSED_PARAMETER(argv);
18842 if (!batch_in_client) {
18843 return wlu_iovar_setbuf(wl, "seq_stop", NULL, 0, buf, WLC_IOCTL_MAXLEN);
18845 else {
18846 if (!cmd_batching_mode) {
18847 printf("calling seq_stop when it's already out of batching mode\n");
18848 return IOCTL_ERROR;
18850 cmd_batching_mode = FALSE;
18852 next_cmd = cmd_list.head;
18854 /* dump batched commands to the DUT */
18856 if (next_cmd == NULL) {
18857 printf("no command batched\n");
18858 return 0;
18861 ret = wlu_iovar_setbuf(wl, "seq_start", NULL, 0, buf, WLC_IOCTL_MAXLEN);
18862 if (ret) {
18863 printf("failed to send seq_start\n");
18864 goto fail;
18867 while (next_cmd != NULL) {
18868 bufp = buf;
18869 memset(bufp, 0, WLC_IOCTL_MAXLEN);
18871 strcpy(bufp, "seq_list");
18872 bufp += (strlen("seq_list") + 1);
18873 bufp = ALIGN_ADDR(bufp, WL_SEQ_CMD_ALIGN_BYTES);
18874 seq_list_len = bufp - buf;
18876 while ((seq_list_len < MEMBLOCK) && (next_cmd != NULL)) {
18877 len = ROUNDUP(next_cmd->cmd_header.len, WL_SEQ_CMD_ALIGN_BYTES);
18878 len += (seq_list_len + sizeof(wl_seq_cmd_ioctl_t));
18880 if (len < MEMBLOCK) {
18881 memcpy(bufp, &(next_cmd->cmd_header),
18882 sizeof(wl_seq_cmd_ioctl_t));
18883 bufp += sizeof(wl_seq_cmd_ioctl_t);
18884 memcpy(bufp, next_cmd->data, next_cmd->cmd_header.len);
18885 bufp += next_cmd->cmd_header.len;
18886 bufp = ALIGN_ADDR(bufp, WL_SEQ_CMD_ALIGN_BYTES);
18887 seq_list_len = len;
18889 next_cmd = next_cmd->next;
18891 else
18892 break;
18895 ret = wl_set(wl, WLC_SET_VAR, &buf[0], seq_list_len);
18897 if (ret) {
18898 printf("failed to send seq_list\n");
18899 goto fail;
18903 ret = wlu_iovar_setbuf(wl, "seq_stop", NULL, 0, buf, WLC_IOCTL_MAXLEN);
18904 if (ret) {
18905 printf("failed to send seq_stop\n");
18908 fail:
18909 clean_up_cmd_list();
18910 return ret;
18914 static int
18915 wl_obss_scan_params_range_chk(wl_obss_scan_arg_t *obss_scan_arg)
18917 if (obss_scan_arg->passive_dwell < 0)
18918 obss_scan_arg->passive_dwell = WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT;
18919 else if (obss_scan_arg->passive_dwell < WLC_OBSS_SCAN_PASSIVE_DWELL_MIN ||
18920 obss_scan_arg->passive_dwell > WLC_OBSS_SCAN_PASSIVE_DWELL_MAX) {
18921 printf("passive dwell not in range %d\n", obss_scan_arg->passive_dwell);
18922 return -1;
18925 if (obss_scan_arg->active_dwell < 0)
18926 obss_scan_arg->active_dwell = WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT;
18927 else if (obss_scan_arg->active_dwell < WLC_OBSS_SCAN_ACTIVE_DWELL_MIN ||
18928 obss_scan_arg->active_dwell > WLC_OBSS_SCAN_ACTIVE_DWELL_MAX) {
18929 printf("active dwell not in range %d\n", obss_scan_arg->active_dwell);
18930 return -1;
18933 if (obss_scan_arg->bss_widthscan_interval < 0)
18934 obss_scan_arg->bss_widthscan_interval =
18935 WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT;
18936 else if (obss_scan_arg->bss_widthscan_interval < WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN ||
18937 obss_scan_arg->bss_widthscan_interval > WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX) {
18938 printf("Width Trigger Scan Interval not in range %d\n",
18939 obss_scan_arg->bss_widthscan_interval);
18940 return -1;
18943 if (obss_scan_arg->chanwidth_transition_delay < 0)
18944 obss_scan_arg->chanwidth_transition_delay =
18945 WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT;
18946 else if ((obss_scan_arg->chanwidth_transition_delay <
18947 WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN) ||
18948 (obss_scan_arg->chanwidth_transition_delay >
18949 WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX)) {
18950 printf("Width Channel Transition Delay Factor not in range %d\n",
18951 obss_scan_arg->chanwidth_transition_delay);
18952 return -1;
18955 if (obss_scan_arg->passive_total < 0)
18956 obss_scan_arg->passive_total = WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT;
18957 else if (obss_scan_arg->passive_total < WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN ||
18958 obss_scan_arg->passive_total > WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX) {
18959 printf("Passive Total per Channel not in range %d\n", obss_scan_arg->passive_total);
18960 return -1;
18963 if (obss_scan_arg->active_total < 0)
18964 obss_scan_arg->active_total = WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT;
18965 if (obss_scan_arg->active_total < WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN ||
18966 obss_scan_arg->active_total > WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX) {
18967 printf("Active Total per Channel not in range %d\n", obss_scan_arg->active_total);
18968 return -1;
18971 if (obss_scan_arg->activity_threshold < 0)
18972 obss_scan_arg->activity_threshold = WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT;
18973 else if (obss_scan_arg->activity_threshold < WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN ||
18974 obss_scan_arg->activity_threshold > WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX) {
18975 printf("Activity Threshold not in range %d\n", obss_scan_arg->activity_threshold);
18976 return -1;
18978 return 0;
18981 /* Send a periodic keep-alive packet at the specificed interval. */
18982 static int
18983 wl_keep_alive(void *wl, cmd_t *cmd, char **argv)
18985 const char *str;
18986 wl_keep_alive_pkt_t keep_alive_pkt;
18987 wl_keep_alive_pkt_t *keep_alive_pktp;
18988 int buf_len;
18989 int str_len;
18990 int i;
18991 int rc;
18992 void *ptr = NULL;
18995 if (NULL == *++argv) {
18997 ** Get current keep-alive status.
18999 if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
19000 return rc;
19002 keep_alive_pktp = (wl_keep_alive_pkt_t *) ptr;
19004 printf("Period (msec) :%d\n"
19005 "Length :%d\n"
19006 "Packet :0x",
19007 dtoh32(keep_alive_pktp->period_msec),
19008 dtoh16(keep_alive_pktp->len_bytes));
19010 for (i = 0; i < keep_alive_pktp->len_bytes; i++)
19011 printf("%02x", keep_alive_pktp->data[i]);
19013 printf("\n");
19015 else {
19017 ** Set keep-alive attributes.
19020 str = "keep_alive";
19021 str_len = strlen(str);
19022 strncpy(buf, str, str_len);
19023 buf[ str_len ] = '\0';
19025 keep_alive_pktp = (wl_keep_alive_pkt_t *) (buf + str_len + 1);
19026 keep_alive_pkt.period_msec = htod32(strtoul(*argv, NULL, 0));
19027 buf_len = str_len + 1;
19030 if (0 == keep_alive_pkt.period_msec) {
19031 keep_alive_pkt.len_bytes = 0;
19033 buf_len += sizeof(wl_keep_alive_pkt_t);
19035 else {
19036 if (NULL == *++argv) {
19037 printf("Network packet not provided\n");
19038 return -1;
19042 keep_alive_pkt.len_bytes =
19043 htod16(wl_pattern_atoh(*argv, (char *) keep_alive_pktp->data));
19045 buf_len += (WL_KEEP_ALIVE_FIXED_LEN + keep_alive_pkt.len_bytes);
19049 /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
19050 * then memcpy'ed into buffer (keep_alive_pktp) since there is no
19051 * guarantee that the buffer is properly aligned.
19053 memcpy((char *)keep_alive_pktp, &keep_alive_pkt, WL_KEEP_ALIVE_FIXED_LEN);
19056 rc = wlu_set(wl,
19057 WLC_SET_VAR,
19058 buf,
19059 buf_len);
19063 return (rc);
19067 /* Enable/disable installed packet filter. */
19068 static int
19069 wl_pkt_filter_enable(void *wl, cmd_t *cmd, char **argv)
19071 wl_pkt_filter_enable_t enable_parm;
19072 int rc;
19074 if (NULL == *++argv) {
19075 printf("No args provided\n");
19076 return (-1);
19079 /* Parse packet filter id. */
19080 enable_parm.id = htod32(strtoul(*argv, NULL, 0));
19082 if (NULL == *++argv) {
19083 printf("Enable/disable value not provided\n");
19084 return (-1);
19087 /* Parse enable/disable value. */
19088 enable_parm.enable = htod32(strtoul(*argv, NULL, 0));
19091 /* Enable/disable the specified filter. */
19092 rc = wlu_var_setbuf(wl,
19093 cmd->name,
19094 &enable_parm,
19095 sizeof(wl_pkt_filter_enable_t));
19097 return (rc);
19101 /* Install a new packet filter. */
19102 static int
19103 wl_pkt_filter_add(void *wl, cmd_t *cmd, char **argv)
19105 const char *str;
19106 wl_pkt_filter_t pkt_filter;
19107 wl_pkt_filter_t *pkt_filterp;
19108 int buf_len;
19109 int str_len;
19110 int rc;
19111 uint32 mask_size;
19112 uint32 pattern_size;
19114 UNUSED_PARAMETER(cmd);
19116 if (NULL == *++argv) {
19117 printf("No args provided\n");
19118 return (-1);
19121 str = "pkt_filter_add";
19122 str_len = strlen(str);
19123 strncpy(buf, str, str_len);
19124 buf[ str_len ] = '\0';
19125 buf_len = str_len + 1;
19127 pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
19129 /* Parse packet filter id. */
19130 pkt_filter.id = htod32(strtoul(*argv, NULL, 0));
19132 if (NULL == *++argv) {
19133 printf("Polarity not provided\n");
19134 return -1;
19137 /* Parse filter polarity. */
19138 pkt_filter.negate_match = htod32(strtoul(*argv, NULL, 0));
19140 if (NULL == *++argv) {
19141 printf("Filter type not provided\n");
19142 return -1;
19145 /* Parse filter type. */
19146 pkt_filter.type = htod32(strtoul(*argv, NULL, 0));
19148 if (NULL == *++argv) {
19149 printf("Offset not provided\n");
19150 return -1;
19153 /* Parse pattern filter offset. */
19154 pkt_filter.u.pattern.offset = htod32(strtoul(*argv, NULL, 0));
19156 if (NULL == *++argv) {
19157 printf("Bitmask not provided\n");
19158 return -1;
19161 /* Parse pattern filter mask. */
19162 mask_size =
19163 htod32(wl_pattern_atoh(*argv, (char *) pkt_filterp->u.pattern.mask_and_pattern));
19165 if (NULL == *++argv) {
19166 printf("Pattern not provided\n");
19167 return -1;
19170 /* Parse pattern filter pattern. */
19171 pattern_size =
19172 htod32(wl_pattern_atoh(*argv,
19173 (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
19175 if (mask_size != pattern_size) {
19176 printf("Mask and pattern not the same size\n");
19177 return -1;
19181 pkt_filter.u.pattern.size_bytes = mask_size;
19182 buf_len += WL_PKT_FILTER_FIXED_LEN;
19183 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
19185 /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
19186 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
19187 ** guarantee that the buffer is properly aligned.
19189 memcpy((char *)pkt_filterp,
19190 &pkt_filter,
19191 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
19194 rc = wlu_set(wl,
19195 WLC_SET_VAR,
19196 buf,
19197 buf_len);
19200 return (rc);
19204 /* List installed packet filters. */
19205 static int
19206 wl_pkt_filter_list(void *wl, cmd_t *cmd, char **argv)
19208 wl_pkt_filter_list_t *list;
19209 wl_pkt_filter_t *filterp;
19210 void *ptr = NULL;
19211 unsigned int i;
19212 unsigned int j;
19213 int rc;
19214 unsigned int filter_len;
19215 uint32 enable;
19218 if (NULL == *++argv) {
19219 printf("No args provided\n");
19220 return (-1);
19223 /* Parse filter list to retrieve (enabled/disabled). */
19224 enable = htod32(strtoul(*argv, NULL, 0));
19226 ** Get list of installed packet filters.
19228 if ((rc = wlu_var_getbuf(wl, cmd->name, &enable, sizeof(enable), &ptr)) < 0)
19229 return rc;
19231 list = (wl_pkt_filter_list_t *) ptr;
19233 printf("Num filters: %d\n\n", list->num);
19235 filterp = list->filter;
19236 for (i = 0; i < list->num; i++)
19238 printf("Id :%d\n"
19239 "Negate :%d\n"
19240 "Type :%d\n"
19241 "Offset :%d\n"
19242 "Pattern len :%d\n"
19243 "Mask :0x",
19244 dtoh32(filterp->id),
19245 dtoh32(filterp->negate_match),
19246 dtoh32(filterp->type),
19247 dtoh32(filterp->u.pattern.offset),
19248 dtoh32(filterp->u.pattern.size_bytes));
19251 for (j = 0; j < filterp->u.pattern.size_bytes; j++)
19252 printf("%02x", filterp->u.pattern.mask_and_pattern[j]);
19254 printf("\nPattern :0x");
19256 for (; j < 2 * filterp->u.pattern.size_bytes; j++)
19257 printf("%02x", filterp->u.pattern.mask_and_pattern[j]);
19259 printf("\n\n");
19262 filter_len = WL_PKT_FILTER_FIXED_LEN;
19263 filter_len += WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * filterp->u.pattern.size_bytes;
19264 filterp = (wl_pkt_filter_t *) ((uint8 *)filterp + filter_len);
19265 filterp = ALIGN_ADDR(filterp, sizeof(uint32));
19269 return (rc);
19273 /* Get packet filter debug statistics. */
19274 static int
19275 wl_pkt_filter_stats(void *wl, cmd_t *cmd, char **argv)
19277 wl_pkt_filter_stats_t *stats;
19278 uint32 id;
19279 int rc;
19280 void *ptr = NULL;
19282 if (NULL == *++argv) {
19283 printf("No args provided\n");
19284 return (-1);
19287 /* Parse filter id to retrieve. */
19288 id = htod32(strtoul(*argv, NULL, 0));
19291 /* Get debug stats. */
19292 if ((rc = wlu_var_getbuf(wl, cmd->name, &id, sizeof(id), &ptr)) < 0)
19293 return rc;
19295 stats = (wl_pkt_filter_stats_t *) ptr;
19297 printf("Packets matched for filter '%d': %d\n"
19298 "Total packets discarded : %d\n"
19299 "Total packet forwarded : %d\n",
19301 dtoh32(stats->num_pkts_matched),
19302 dtoh32(stats->num_pkts_discarded),
19303 dtoh32(stats->num_pkts_forwarded));
19305 return (rc);
19309 static int
19310 wl_obss_scan(void *wl, cmd_t *cmd, char **argv)
19312 int err = -1;
19313 wl_obss_scan_arg_t obss_scan_arg;
19314 char *endptr = NULL;
19315 uint buflen;
19316 uint argc = 0;
19318 if (!*++argv) {
19319 void *ptr = NULL;
19320 wl_obss_scan_arg_t *obss_scan_param;
19322 err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr);
19323 if (err < 0)
19324 return err;
19326 obss_scan_param = (wl_obss_scan_arg_t *)ptr;
19327 printf("%d %d %d %d %d %d %d\n",
19328 dtoh16(obss_scan_param->passive_dwell),
19329 dtoh16(obss_scan_param->active_dwell),
19330 dtoh16(obss_scan_param->bss_widthscan_interval),
19331 dtoh16(obss_scan_param->passive_total),
19332 dtoh16(obss_scan_param->active_total),
19333 dtoh16(obss_scan_param->chanwidth_transition_delay),
19334 dtoh16(obss_scan_param->activity_threshold));
19335 return 0;
19338 /* arg count */
19339 while (argv[argc])
19340 argc++;
19342 buflen = WL_OBSS_SCAN_PARAM_LEN;
19343 memset((uint8 *)&obss_scan_arg, 0, buflen);
19345 /* required argments */
19346 if (argc < WL_MIN_NUM_OBSS_SCAN_ARG) {
19347 fprintf(stderr, "Too few/many arguments (require %d, got %d)\n",
19348 WL_MIN_NUM_OBSS_SCAN_ARG, argc);
19349 return err;
19352 obss_scan_arg.passive_dwell = htod16((int16)strtol(*argv++, &endptr, 0));
19353 if (*endptr != '\0')
19354 goto error;
19356 obss_scan_arg.active_dwell = htod16((int16)strtol(*argv++, &endptr, 0));
19357 if (*endptr != '\0')
19358 goto error;
19360 obss_scan_arg.bss_widthscan_interval = htod16((int16)strtol(*argv++, &endptr, 0));
19361 if (*endptr != '\0')
19362 goto error;
19364 obss_scan_arg.passive_total = htod16((int16)strtol(*argv++, &endptr, 0));
19365 if (*endptr != '\0')
19366 goto error;
19368 obss_scan_arg.active_total = htod16((int16)strtol(*argv++, &endptr, 0));
19369 if (*endptr != '\0')
19370 goto error;
19372 obss_scan_arg.chanwidth_transition_delay = htod16((int16)strtol(*argv++, &endptr, 0));
19373 if (*endptr != '\0')
19374 goto error;
19376 obss_scan_arg.activity_threshold = htod16((int16)strtol(*argv++, &endptr, 0));
19377 if (*endptr != '\0')
19378 goto error;
19380 if (wl_obss_scan_params_range_chk(&obss_scan_arg))
19381 return BCME_RANGE;
19383 err = wlu_var_setbuf(wl, cmd->name, &obss_scan_arg, buflen);
19385 error:
19386 return err;
19389 #ifdef RWL_WIFI
19390 /* Function added to support RWL_WIFI Transport
19391 * Used to find the remote server with proper mac address given by
19392 * the user,this cmd is specific to RWL_WIFIi protocol
19394 static int wl_wifiserver(void *wl, cmd_t *cmd, char **argv)
19396 int ret;
19398 if ((ret = wlu_iovar_set(wl, cmd->name, *argv, strlen(*argv))) < 0) {
19399 printf("Error finding the remote server %s\n", argv[0]);
19400 return ret;
19402 return ret;
19404 #endif
19405 static int
19406 wl_obss_coex_action(void *wl, cmd_t *cmd, char **argv)
19408 int err;
19409 char var[256];
19410 wl_action_obss_coex_req_t *req = (wl_action_obss_coex_req_t *)var;
19411 int val;
19412 int num = 0;
19413 uint8 options = 0;
19415 argv++;
19416 memset(&var, 0, sizeof(wl_action_obss_coex_req_t));
19417 while (*argv) {
19418 if (!strncmp(*argv, "-i", 2) && ((options & 0x1) != 0x1)) {
19419 argv++;
19420 if (!*argv)
19421 return -1;
19422 val = atoi(*argv);
19423 if ((val != 0) && (val != 1))
19424 return -1;
19425 req->info |= val ? WL_COEX_40MHZ_INTOLERANT : 0;
19426 options |= 0x1;
19428 else if (!strncmp(*argv, "-w", 2) && ((options & 0x2) != 0x2)) {
19429 argv++;
19430 if (!*argv)
19431 return -1;
19432 val = atoi(*argv);
19433 if ((val != 0) && (val != 1))
19434 return -1;
19435 req->info |= val ? WL_COEX_WIDTH20 : 0;
19436 options |= 0x2;
19438 else if (!strncmp(*argv, "-c", 2) && ((options & 0x4) != 0x4)) {
19439 argv++;
19440 while (*argv) {
19441 if (isdigit((const unsigned char)(**argv))) {
19442 val = htod32(strtoul(*argv, NULL, 0));
19443 if ((val == 0) || (val > 14)) {
19444 printf("Invalid channel %d\n", val);
19445 return -1;
19447 req->ch_list[num] = (uint8)val;
19448 num++;
19449 argv++;
19450 if (num > 14) {
19451 printf("Too many channels (max 14)\n");
19452 return -1;
19454 } else
19455 break;
19457 if (!num) {
19458 printf("With option '-c' specified, a channel list is required\n");
19459 return -1;
19461 req->num = num;
19462 options |= 0x4;
19463 continue;
19465 else
19466 return -1;
19467 argv++;
19469 if (!options)
19470 return -1;
19471 err = wlu_var_setbuf(wl, cmd->name, &var, (sizeof(wl_action_obss_coex_req_t) +
19472 (req->num ? (req->num - 1) * sizeof(uint8) : 0)));
19473 return err;
19476 static int
19477 wl_srchmem(void *wl, cmd_t *cmd, char **argv)
19479 int ret = 0;
19480 struct args {
19481 int reg;
19482 int band;
19483 uint32 ssidlen;
19484 uint8 ssid[DOT11_MAX_SSID_LEN];
19485 } x;
19486 struct args *pargs;
19487 char *endptr;
19488 uint argc;
19489 char *iovar;
19491 UNUSED_PARAMETER(cmd);
19493 memset(&x, 0, sizeof(x));
19495 /* save command name */
19496 iovar = argv[0];
19497 argv++;
19499 /* arg count */
19500 for (argc = 0; argv[argc]; argc++)
19503 /* required arg: reg offset */
19504 if (argc < 1)
19505 return -1;
19507 x.reg = strtol(argv[0], &endptr, 0);
19508 if (*endptr != '\0' || x.reg > 15)
19509 return -1;
19511 if (argc > 2)
19512 return (-1);
19514 if (argc == 2) {
19515 uint32 len;
19517 len = strlen(argv[1]);
19518 if (len > sizeof(x.ssid)) {
19519 printf("ssid too long\n");
19520 return (-1);
19522 memcpy(x.ssid, argv[1], len);
19523 x.ssidlen = len;
19526 /* issue the get or set ioctl */
19527 if ((argc == 1)) {
19528 x.band = htod32(x.band);
19529 x.reg = htod32(x.reg);
19531 ret = wlu_iovar_getbuf(wl, iovar, &x, sizeof(x), buf, WLC_IOCTL_SMLEN);
19532 if (ret < 0) {
19533 printf("get returned error 0x%x\n", ret);
19534 return (ret);
19536 pargs = (struct args *)(buf + strlen(iovar) + 1 + 2*sizeof(int));
19538 wl_hexdump((uchar *)pargs, sizeof(pargs->ssidlen) + sizeof(pargs->ssid));
19540 } else {
19541 x.band = htod32(x.band);
19542 x.reg = htod32(x.reg);
19543 x.ssidlen = htod32(x.ssidlen);
19545 ret = wlu_iovar_setbuf(wl, iovar, &x, sizeof(x), buf, WLC_IOCTL_MAXLEN);
19546 if (ret < 0) {
19547 printf("set returned error 0x%x\n", ret);
19548 return (ret);
19552 return (ret);
19555 cntry_name_t cntry_names[] = {
19557 {"AFGHANISTAN", "AF"},
19558 {"ALBANIA", "AL"},
19559 {"ALGERIA", "DZ"},
19560 {"AMERICAN SAMOA", "AS"},
19561 {"ANDORRA", "AD"},
19562 {"ANGOLA", "AO"},
19563 {"ANGUILLA", "AI"},
19564 {"ANTARCTICA", "AQ"},
19565 {"ANTIGUA AND BARBUDA", "AG"},
19566 {"ARGENTINA", "AR"},
19567 {"ARMENIA", "AM"},
19568 {"ARUBA", "AW"},
19569 {"ASCENSION ISLAND", "AC"},
19570 {"AUSTRALIA", "AU"},
19571 {"AUSTRIA", "AT"},
19572 {"AZERBAIJAN", "AZ"},
19573 {"BAHAMAS", "BS"},
19574 {"BAHRAIN", "BH"},
19575 {"BANGLADESH", "BD"},
19576 {"BARBADOS", "BB"},
19577 {"BELARUS", "BY"},
19578 {"BELGIUM", "BE"},
19579 {"BELIZE", "BZ"},
19580 {"BENIN", "BJ"},
19581 {"BERMUDA", "BM"},
19582 {"BHUTAN", "BT"},
19583 {"BOLIVIA", "BO"},
19584 {"BOSNIA AND HERZEGOVINA", "BA"},
19585 {"BOTSWANA", "BW"},
19586 {"BOUVET ISLAND", "BV"},
19587 {"BRAZIL", "BR"},
19588 {"BRITISH INDIAN OCEAN TERRITORY", "IO"},
19589 {"BRUNEI DARUSSALAM", "BN"},
19590 {"BULGARIA", "BG"},
19591 {"BURKINA FASO", "BF"},
19592 {"BURUNDI", "BI"},
19593 {"CAMBODIA", "KH"},
19594 {"CAMEROON", "CM"},
19595 {"CANADA", "CA"},
19596 {"CAPE VERDE", "CV"},
19597 {"CAYMAN ISLANDS", "KY"},
19598 {"CENTRAL AFRICAN REPUBLIC", "CF"},
19599 {"CHAD", "TD"},
19600 {"CHILE", "CL"},
19601 {"CHINA", "CN"},
19602 {"CHRISTMAS ISLAND", "CX"},
19603 {"CLIPPERTON ISLAND", "CP"},
19604 {"COCOS (KEELING) ISLANDS", "CC"},
19605 {"COLOMBIA", "CO"},
19606 {"COMOROS", "KM"},
19607 {"CONGO", "CG"},
19608 {"CONGO, THE DEMOCRATIC REPUBLIC OF THE", "CD"},
19609 {"COOK ISLANDS", "CK"},
19610 {"COSTA RICA", "CR"},
19611 {"COTE D'IVOIRE", "CI"},
19612 {"CROATIA", "HR"},
19613 {"CUBA", "CU"},
19614 {"CYPRUS", "CY"},
19615 {"CZECH REPUBLIC", "CZ"},
19616 {"DENMARK", "DK"},
19617 {"DJIBOUTI", "DJ"},
19618 {"DOMINICA", "DM"},
19619 {"DOMINICAN REPUBLIC", "DO"},
19620 {"ECUADOR", "EC"},
19621 {"EGYPT", "EG"},
19622 {"EL SALVADOR", "SV"},
19623 {"EQUATORIAL GUINEA", "GQ"},
19624 {"ERITREA", "ER"},
19625 {"ESTONIA", "EE"},
19626 {"ETHIOPIA", "ET"},
19627 {"EUROPEAN UNION", "EU"},
19628 {"FALKLAND ISLANDS (MALVINAS)", "FK"},
19629 {"FAROE ISLANDS", "FO"},
19630 {"FIJI", "FJ"},
19631 {"FINLAND", "FI"},
19632 {"FRANCE", "FR"},
19633 {"FRENCH GUIANA", "GF"},
19634 {"FRENCH POLYNESIA", "PF"},
19635 {"FRENCH SOUTHERN TERRITORIES", "TF"},
19636 {"GABON", "GA"},
19637 {"GAMBIA", "GM"},
19638 {"GEORGIA", "GE"},
19639 {"GERMANY", "DE"},
19640 {"GHANA", "GH"},
19641 {"GIBRALTAR", "GI"},
19642 {"GREECE", "GR"},
19643 {"GREENLAND", "GL"},
19644 {"GRENADA", "GD"},
19645 {"GUADELOUPE", "GP"},
19646 {"GUAM", "GU"},
19647 {"GUATEMALA", "GT"},
19648 {"GUERNSEY", "GG"},
19649 {"GUINEA", "GN"},
19650 {"GUINEA-BISSAU", "GW"},
19651 {"GUYANA", "GY"},
19652 {"HAITI", "HT"},
19653 {"HEARD ISLAND AND MCDONALD ISLANDS", "HM"},
19654 {"HOLY SEE (VATICAN CITY STATE)", "VA"},
19655 {"HONDURAS", "HN"},
19656 {"HONG KONG", "HK"},
19657 {"HUNGARY", "HU"},
19658 {"ICELAND", "IS"},
19659 {"INDIA", "IN"},
19660 {"INDONESIA", "ID"},
19661 {"IRAN, ISLAMIC REPUBLIC OF", "IR"},
19662 {"IRAQ", "IQ"},
19663 {"IRELAND", "IE"},
19664 {"ISRAEL", "IL"},
19665 {"ITALY", "IT"},
19666 {"JAMAICA", "JM"},
19667 {"JAPAN", "JP"},
19668 {"JERSEY", "JE"},
19669 {"JORDAN", "JO"},
19670 {"KAZAKHSTAN", "KZ"},
19671 {"KENYA", "KE"},
19672 {"KIRIBATI", "KI"},
19673 {"KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF", "KP"},
19674 {"KOREA, REPUBLIC OF", "KR"},
19675 {"KUWAIT", "KW"},
19676 {"KYRGYZSTAN", "KG"},
19677 {"LAO PEOPLE'S DEMOCRATIC REPUBLIC", "LA"},
19678 {"LATVIA", "LV"},
19679 {"LEBANON", "LB"},
19680 {"LESOTHO", "LS"},
19681 {"LIBERIA", "LR"},
19682 {"LIBYAN ARAB JAMAHIRIYA", "LY"},
19683 {"LIECHTENSTEIN", "LI"},
19684 {"LITHUANIA", "LT"},
19685 {"LUXEMBOURG", "LU"},
19686 {"MACAO", "MO"},
19687 {"MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF", "MK"},
19688 {"MADAGASCAR", "MG"},
19689 {"MALAWI", "MW"},
19690 {"MALAYSIA", "MY"},
19691 {"MALDIVES", "MV"},
19692 {"MALI", "ML"},
19693 {"MALTA", "MT"},
19694 {"MAN, ISLE OF", "IM"},
19695 {"MARSHALL ISLANDS", "MH"},
19696 {"MARTINIQUE", "MQ"},
19697 {"MAURITANIA", "MR"},
19698 {"MAURITIUS", "MU"},
19699 {"MAYOTTE", "YT"},
19700 {"MEXICO", "MX"},
19701 {"MICRONESIA, FEDERATED STATES OF", "FM"},
19702 {"MOLDOVA, REPUBLIC OF", "MD"},
19703 {"MONACO", "MC"},
19704 {"MONGOLIA", "MN"},
19705 {"MONTENEGRO", "ME"},
19706 {"MONTSERRAT", "MS"},
19707 {"MOROCCO", "MA"},
19708 {"MOZAMBIQUE", "MZ"},
19709 {"MYANMAR", "MM"},
19710 {"NAMIBIA", "NA"},
19711 {"NAURU", "NR"},
19712 {"NEPAL", "NP"},
19713 {"NETHERLANDS", "NL"},
19714 {"NETHERLANDS ANTILLES", "AN"},
19715 {"NEW CALEDONIA", "NC"},
19716 {"NEW ZEALAND", "NZ"},
19717 {"NICARAGUA", "NI"},
19718 {"NIGER", "NE"},
19719 {"NIGERIA", "NG"},
19720 {"NIUE", "NU"},
19721 {"NORFOLK ISLAND", "NF"},
19722 {"NORTHERN MARIANA ISLANDS", "MP"},
19723 {"NORWAY", "NO"},
19724 {"OMAN", "OM"},
19725 {"PAKISTAN", "PK"},
19726 {"PALAU", "PW"},
19727 {"PALESTINIAN TERRITORY, OCCUPIED", "PS"},
19728 {"PANAMA", "PA"},
19729 {"PAPUA NEW GUINEA", "PG"},
19730 {"PARAGUAY", "PY"},
19731 {"PERU", "PE"},
19732 {"PHILIPPINES", "PH"},
19733 {"PITCAIRN", "PN"},
19734 {"POLAND", "PL"},
19735 {"PORTUGAL", "PT"},
19736 {"PUERTO RICO", "PR"},
19737 {"QATAR", "QA"},
19738 {"REUNION", "RE"},
19739 {"ROMANIA", "RO"},
19740 {"RUSSIAN FEDERATION", "RU"},
19741 {"RWANDA", "RW"},
19742 {"SAINT HELENA", "SH"},
19743 {"SAINT KITTS AND NEVIS", "KN"},
19744 {"SAINT LUCIA", "LC"},
19745 {"SAINT PIERRE AND MIQUELON", "PM"},
19746 {"SAINT VINCENT AND THE GRENADINES", "VC"},
19747 {"SAMOA", "WS"},
19748 {"SAN MARINO", "SM"},
19749 {"SAO TOME AND PRINCIPE", "ST"},
19750 {"SAUDI ARABIA", "SA"},
19751 {"SENEGAL", "SN"},
19752 {"SERBIA", "RS"},
19753 {"SEYCHELLES", "SC"},
19754 {"SIERRA LEONE", "SL"},
19755 {"SINGAPORE", "SG"},
19756 {"SLOVAKIA", "SK"},
19757 {"SLOVENIA", "SI"},
19758 {"SOLOMON ISLANDS", "SB"},
19759 {"SOMALIA", "SO"},
19760 {"SOUTH AFRICA", "ZA"},
19761 {"SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS", "GS"},
19762 {"SPAIN", "ES"},
19763 {"SRI LANKA", "LK"},
19764 {"SUDAN", "SD"},
19765 {"SURINAME", "SR"},
19766 {"SVALBARD AND JAN MAYEN", "SJ"},
19767 {"SWAZILAND", "SZ"},
19768 {"SWEDEN", "SE"},
19769 {"SWITZERLAND", "CH"},
19770 {"SYRIAN ARAB REPUBLIC", "SY"},
19771 {"TAIWAN, PROVINCE OF CHINA", "TW"},
19772 {"TAJIKISTAN", "TJ"},
19773 {"TANZANIA, UNITED REPUBLIC OF", "TZ"},
19774 {"THAILAND", "TH"},
19775 {"TIMOR-LESTE (EAST TIMOR)", "TL"},
19776 {"TOGO", "TG"},
19777 {"TOKELAU", "TK"},
19778 {"TONGA", "TO"},
19779 {"TRINIDAD AND TOBAGO", "TT"},
19780 {"TRISTAN DA CUNHA", "TA"},
19781 {"TUNISIA", "TN"},
19782 {"TURKEY", "TR"},
19783 {"TURKMENISTAN", "TM"},
19784 {"TURKS AND CAICOS ISLANDS", "TC"},
19785 {"TUVALU", "TV"},
19786 {"UGANDA", "UG"},
19787 {"UKRAINE", "UA"},
19788 {"UNITED ARAB EMIRATES", "AE"},
19789 {"UNITED KINGDOM", "GB"},
19790 {"UNITED STATES", "US"},
19791 {"UNITED STATES MINOR OUTLYING ISLANDS", "UM"},
19792 {"URUGUAY", "UY"},
19793 {"UZBEKISTAN", "UZ"},
19794 {"VANUATU", "VU"},
19795 {"VENEZUELA", "VE"},
19796 {"VIET NAM", "VN"},
19797 {"VIRGIN ISLANDS, BRITISH", "VG"},
19798 {"VIRGIN ISLANDS, U.S.", "VI"},
19799 {"WALLIS AND FUTUNA", "WF"},
19800 {"WESTERN SAHARA", "EH"},
19801 {"YEMEN", "YE"},
19802 {"YUGOSLAVIA", "YU"},
19803 {"ZAMBIA", "ZM"},
19804 {"ZIMBABWE", "ZW"},
19805 {"RADAR CHANNELS", "RDR"},
19806 {"ALL CHANNELS", "ALL"},
19807 {NULL, NULL}
19810 static void
19811 wl_print_mcsset(char *mcsset)
19813 int i;
19815 printf("MCS SET : [ ");
19816 for (i = 0; i < (MCSSET_LEN * 8); i++)
19817 if (isset(mcsset, i))
19818 printf("%d ", i);
19819 printf("]\n");
19822 static int
19823 wl_txmcsset(void *wl, cmd_t *cmd, char **argv)
19825 int err;
19827 if ((err = wl_var_get(wl, cmd, argv)) < 0)
19828 return err;
19829 wl_print_mcsset(buf);
19831 return err;
19834 static int
19835 wl_rxmcsset(void *wl, cmd_t *cmd, char **argv)
19837 int err;
19839 if ((err = wl_var_get(wl, cmd, argv)) < 0)
19840 return err;
19842 wl_print_mcsset(buf);
19844 return err;
19847 static int
19848 wl_mimo_stf(void *wl, cmd_t *cmd, char **argv)
19850 char var[256];
19851 uint32 int_val;
19852 bool get = TRUE;
19853 uint32 len = 0;
19854 void *ptr = NULL;
19855 char *endptr;
19856 int i = 0, j = 0;
19858 while (argv[i])
19859 i++;
19861 if (i > 4)
19862 return -1;
19864 /* toss the command name */
19865 argv++;
19866 j = 1;
19868 if (i == 1) {
19869 int_val = -1;
19870 memcpy(&var[len], (char *)&int_val, sizeof(int_val));
19871 len += sizeof(int_val);
19873 else {
19874 if (isdigit((const unsigned char)(**argv))) {
19875 get = FALSE;
19876 int_val = htod32(strtoul(*argv, &endptr, 0));
19877 if ((int_val != 0) && (int_val != 1)) {
19878 fprintf(stderr, "wl mimo_ss_stf: bad stf mode.\n");
19879 return -1;
19881 memcpy(var, (char *)&int_val, sizeof(int_val));
19882 len += sizeof(int_val);
19883 argv++;
19884 j++;
19887 if (j == i) {
19888 int_val = -1;
19889 memcpy(&var[len], (char *)&int_val, sizeof(int_val));
19890 len += sizeof(int_val);
19892 else if (!strncmp(*argv, "-b", 2)) {
19893 argv++;
19894 j++;
19895 if (j == i)
19896 return -1;
19898 if (!strcmp(*argv, "a"))
19899 int_val = 1;
19900 else if (!strcmp(*argv, "b"))
19901 int_val = 0;
19902 else {
19903 fprintf(stderr,
19904 "wl mimo_ss_stf: wrong -b option, \"-b a\" or \"-b b\"\n");
19905 return -1;
19907 j++;
19908 if (j < i)
19909 return -1;
19910 memcpy(&var[len], (char *)&int_val, sizeof(int_val));
19911 len += sizeof(int_val);
19915 if (get) {
19916 if (wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr) < 0)
19917 return -1;
19919 printf("0x%x\n", dtoh32(*(int *)ptr));
19921 else
19922 wlu_var_setbuf(wl, cmd->name, &var, sizeof(var));
19923 return 0;
19926 #ifdef WLEXTLOG
19927 static int
19928 wl_extlog(void *wl, cmd_t *cmd, char **argv)
19930 int argc;
19931 char *endptr;
19932 int err;
19933 int from_last;
19934 int i, j;
19935 char *log_p = NULL;
19936 wlc_extlog_req_t r_args;
19937 wlc_extlog_results_t *results;
19938 void *ptr = NULL;
19940 /* arg count */
19941 for (argc = 0; argv[argc]; argc++)
19944 if (argc > 3)
19945 return -1;
19947 if (argc == 1)
19948 from_last = 0;
19949 else {
19950 from_last = htod32(strtoul(argv[1], &endptr, 0));
19951 if ((from_last != 0) && (from_last != 1))
19952 return -1;
19955 r_args.from_last = from_last;
19956 if (argc == 3)
19957 r_args.num = htod32(strtoul(argv[2], &endptr, 0));
19958 else
19959 r_args.num = 32;
19961 if ((err = wlu_var_getbuf(wl, cmd->name, &r_args, sizeof(wlc_extlog_req_t), &ptr)) < 0)
19962 return err;
19964 results = (wlc_extlog_results_t *)buf;
19966 printf("get external log records: %d\n", results->num);
19967 if (!results->num)
19968 return 0;
19970 if (results->version != EXTLOG_CUR_VER) {
19971 printf("version mismatch: version = 0x%x, expected 0x%0x\n",
19972 results->version, EXTLOG_CUR_VER);
19973 return 0;
19976 log_p = (char *)&results->logs[0];
19978 printf("Seq:\tTime(ms) Log\n");
19979 for (i = 0; i < (int)results->num; i++) {
19980 printf("%d:\t%d\t ", ((log_record_t*)log_p)->seq_num,
19981 ((log_record_t*)log_p)->time);
19982 for (j = 0; j < FMTSTR_MAX_ID; j++)
19983 if (((log_record_t*)log_p)->id == extlog_fmt_str[j].id)
19984 break;
19985 if (j == FMTSTR_MAX_ID) {
19986 printf("fmt string not found for id %d\n", ((log_record_t*)log_p)->id);
19987 log_p += results->record_len;
19988 continue;
19991 switch (extlog_fmt_str[j].arg_type) {
19992 case LOG_ARGTYPE_NULL:
19993 printf("%s", extlog_fmt_str[j].fmt_str);
19994 break;
19996 case LOG_ARGTYPE_STR:
19997 printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->str);
19998 break;
20000 case LOG_ARGTYPE_INT:
20001 printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->arg);
20002 break;
20004 case LOG_ARGTYPE_INT_STR:
20005 printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->arg,
20006 ((log_record_t*)log_p)->str);
20007 break;
20009 case LOG_ARGTYPE_STR_INT:
20010 printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->str,
20011 ((log_record_t*)log_p)->arg);
20012 break;
20014 log_p += results->record_len;
20017 return 0;
20021 static int
20022 wl_extlog_cfg(void *wl, cmd_t *cmd, char **argv)
20024 int argc;
20025 int err = 0;
20026 char *endptr;
20027 wlc_extlog_cfg_t *r_cfg;
20028 wlc_extlog_cfg_t w_cfg;
20030 /* arg count */
20031 for (argc = 0; argv[argc]; argc++)
20034 if (argc == 1) {
20035 err = wl_var_get(wl, cmd, argv);
20036 if (err < 0)
20037 return err;
20038 r_cfg = (wlc_extlog_cfg_t *)buf;
20039 printf("max_number=%d, module=%x, level=%d, flag=%d, version=0x%04x\n",
20040 r_cfg->max_number, r_cfg->module, r_cfg->level,
20041 r_cfg->flag, r_cfg->version);
20043 else if (argc == 4) {
20044 w_cfg.module = htod16((uint16)(strtoul(argv[1], &endptr, 0)));
20045 w_cfg.level = (uint8)strtoul(argv[2], &endptr, 0);
20046 w_cfg.flag = (uint8)strtoul(argv[3], &endptr, 0);
20047 wlu_var_setbuf(wl, cmd->name, &w_cfg, sizeof(wlc_extlog_cfg_t));
20049 else {
20050 fprintf(stderr, "illegal command!\n");
20051 return -1;
20054 return err;
20056 #endif /* WLEXTLOG */
20058 static int
20059 wl_assertlog(void *wl, cmd_t *cmd, char **argv)
20061 int argc;
20062 int err;
20063 int i;
20064 char *log_p = NULL;
20065 assertlog_results_t *results;
20066 void *ptr = NULL;
20068 /* arg count */
20069 for (argc = 0; argv[argc]; argc++)
20072 if (argc > 1)
20073 return -1;
20075 if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
20076 return err;
20078 results = (assertlog_results_t *)buf;
20080 printf("get external assert logs: %d\n", results->num);
20081 if (!results->num)
20082 return 0;
20084 if (results->version != ASSERTLOG_CUR_VER) {
20085 printf("Version mismatch: version = 0x%x, expected 0x%x\n",
20086 results->version, ASSERTLOG_CUR_VER);
20087 return 0;
20090 log_p = (char *)&results->logs[0];
20092 printf("id: \ttime(ms) \tstring\n");
20093 for (i = 0; i < (int)results->num; i++) {
20094 printf("%d: \t%d \t%s", i, ((assert_record_t *)log_p)->time,
20095 ((assert_record_t *)log_p)->str);
20096 log_p += results->record_len;
20099 return 0;
20102 extern cca_congest_channel_req_t *
20103 cca_per_chan_summary(cca_congest_channel_req_t *input,
20104 cca_congest_channel_req_t *avg, bool percent);
20106 extern int
20107 cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer);
20109 static const char *
20110 cca_level(int score, int med, int hi)
20112 if (score < med)
20113 return ("Low");
20114 if (score >= med && score < hi)
20115 return ("Medium");
20116 if (score >= hi)
20117 return ("High");
20118 return NULL;
20121 static const char *cca_errors[] = {
20122 "No error",
20123 "Preferred band",
20124 "Dwell Duration too low",
20125 "Channel prefs",
20126 "Interference too high",
20127 "Only 1 channel inoput"
20130 static int
20131 wl_cca_get_stats(void *wl, cmd_t *cmd, char **argv)
20133 cca_congest_channel_req_t *results;
20134 cca_congest_channel_req_t req;
20135 cca_congest_t *chptr;
20136 cca_congest_channel_req_t *avg[MAX_CCA_CHANNELS]; /* Max num of channels */
20137 void *ptr = NULL;
20138 char *param, *val_p;
20139 int base, limit, i, channel, err = 0;
20140 int ibss_per, obss_per, inter_per, val;
20141 const char *ibss_lvl = NULL;
20142 const char *obss_lvl = NULL;
20143 const char *inter_lvl = NULL;
20144 int tmp_channel;
20145 chanspec_t new_chanspec, cur_chanspec;
20146 bool do_average = TRUE;
20147 bool do_individ = FALSE;
20148 bool do_analyze = TRUE;
20149 bool curband = FALSE;
20150 bool do_csa = FALSE;
20151 int avg_chan_idx = 0;
20152 uint32 flags;
20155 req.num_secs = 10;
20156 tmp_channel = 0xff;
20158 argv++;
20160 /* Parse args */
20161 while ((param = *argv++) != NULL) {
20162 if (stricmp(param, "-a") == 0) {
20163 do_analyze = TRUE;
20164 continue;
20166 if (stricmp(param, "-i") == 0) {
20167 do_individ = TRUE;
20168 continue;
20170 if (stricmp(param, "-csa") == 0) {
20171 do_csa = TRUE;
20172 continue;
20174 if (stricmp(param, "-curband") == 0) {
20175 curband = TRUE;
20176 continue;
20179 if ((val_p = *argv++) == NULL) {
20180 printf("Need value following %s\n", param);
20181 return USAGE_ERROR;
20183 if (stricmp(param, "-c") == 0) {
20184 tmp_channel = (int)strtoul(val_p, NULL, 0);
20187 if (stricmp(param, "-cs") == 0) {
20188 if ((new_chanspec = wf_chspec_aton(val_p)))
20189 tmp_channel = wf_chspec_ctlchan(new_chanspec);
20192 if (stricmp(param, "-s") == 0) {
20193 req.num_secs = (int)strtoul(val_p, NULL, 0);
20194 if (req.num_secs == 0 || req.num_secs > MAX_CCA_SECS) {
20195 printf("%d: Num of seconds must be <= %d\n",
20196 req.num_secs, MAX_CCA_SECS);
20197 return USAGE_ERROR;
20201 if (!do_average && !do_individ) {
20202 printf("Must pick at least one of averages or individual secs\n");
20203 return USAGE_ERROR;
20206 if (tmp_channel == 0) {
20207 /* do all channels */
20208 base = 1; limit = 255;
20209 } else {
20210 /* Use current channel as default if none specified */
20211 if (tmp_channel == 0xff) {
20212 if ((err = wlu_iovar_getint(wl, "chanspec", (int*)&val)) < 0) {
20213 printf("CCA: Can't get currrent chanspec\n");
20214 return err;
20216 cur_chanspec = (chanspec_t)val;
20217 tmp_channel = wf_chspec_ctlchan(cur_chanspec);
20218 printf("Using channel %d\n", tmp_channel);
20220 base = limit = tmp_channel;
20224 for (channel = base; channel <= limit; channel++) {
20226 /* Get stats for each channel */
20227 req.chanspec = CH20MHZ_CHSPEC(channel);
20228 if ((err = wlu_var_getbuf(wl, cmd->name, &req, sizeof(req), &ptr)) < 0)
20229 return err;
20231 results = (cca_congest_channel_req_t *)ptr;
20232 if (results->chanspec == 0 || results->num_secs == 0)
20233 continue;
20235 if (results->num_secs > MAX_CCA_SECS) {
20236 printf("Bogus num of seconds returned %d\n", results->num_secs);
20237 return -1;
20240 /* Summarize and save summary for this channel */
20241 if (do_average) {
20242 avg[avg_chan_idx] = (cca_congest_channel_req_t *)
20243 malloc(sizeof(cca_congest_channel_req_t));
20244 cca_per_chan_summary(results, avg[avg_chan_idx], 1);
20245 if (avg[avg_chan_idx]->num_secs)
20246 avg_chan_idx++;
20249 /* printf stats for each second of each channel */
20250 if (do_individ) {
20251 if (channel == base)
20252 printf("chan dur ibss obss"
20253 " interf time\n");
20254 for (i = 0; i < results->num_secs; i++) {
20255 chptr = &results->secs[i];
20256 if (chptr->duration) {
20257 /* Percentages */
20258 ibss_per = chptr->congest_ibss * 100 /chptr->duration;
20259 obss_per = chptr->congest_obss * 100 /chptr->duration;
20260 inter_per = chptr->interference * 100 /chptr->duration;
20261 /* Levels */
20262 ibss_lvl = cca_level(ibss_per, IBSS_MED, IBSS_HI);
20263 obss_lvl = cca_level(obss_per, OBSS_MED, OBSS_HI);
20264 inter_lvl = cca_level(inter_per, INTERFER_MED, INTERFER_HI);
20266 printf("%-3u %4d %4u %2d%% %-6s %4u %2d%% %-6s %4u %2d%% %-6s %d\n",
20267 CHSPEC_CHANNEL(results->chanspec),
20268 chptr->duration,
20269 chptr->congest_ibss, ibss_per, ibss_lvl,
20270 chptr->congest_obss, obss_per, obss_lvl,
20271 chptr->interference, inter_per, inter_lvl,
20272 chptr->timestamp);
20278 /* Print summary stats of each channel */
20279 if (do_average) {
20280 int j;
20281 printf("Summaries:\n");
20282 printf("chan dur ibss obss interf num seconds\n");
20283 for (j = 0; j < avg_chan_idx; j++) {
20284 /* Percentages */
20285 ibss_per = avg[j]->secs[0].congest_ibss;
20286 obss_per = avg[j]->secs[0].congest_obss;
20287 inter_per = avg[j]->secs[0].interference;
20288 /* Levels */
20289 ibss_lvl = cca_level(ibss_per, IBSS_MED, IBSS_HI);
20290 obss_lvl = cca_level(obss_per, OBSS_MED, OBSS_HI);
20291 inter_lvl = cca_level(inter_per, INTERFER_MED, INTERFER_HI);
20293 if (avg[j]->num_secs) {
20294 printf("%-3u %4d %4s %2d%% %-6s %4s %2d%% %-6s %4s %2d%% %-6s %d\n",
20295 CHSPEC_CHANNEL(avg[j]->chanspec),
20296 avg[j]->secs[0].duration,
20297 "", avg[j]->secs[0].congest_ibss, ibss_lvl,
20298 "", avg[j]->secs[0].congest_obss, obss_lvl,
20299 "", avg[j]->secs[0].interference, inter_lvl,
20300 avg[j]->num_secs);
20305 if (!do_analyze)
20306 return err;
20308 if ((err = wlu_iovar_getint(wl, "chanspec", (int *)&val)) < 0) {
20309 printf("CCA: Can't get currrent chanspec\n");
20310 return err;
20312 cur_chanspec = (chanspec_t)val;
20313 flags = 0;
20314 if (curband) {
20315 if (CHSPEC_IS5G(cur_chanspec))
20316 flags |= CCA_FLAG_5G_ONLY;
20317 if (CHSPEC_IS2G(cur_chanspec))
20318 flags |= CCA_FLAG_2G_ONLY;
20321 if ((err = cca_analyze(avg, avg_chan_idx, flags, &new_chanspec)) != 0) {
20322 printf("Cannot find a good channel due to: %s\n", cca_errors[err]);
20323 return 0;
20325 printf("Recommended channel: %d\n", wf_chspec_ctlchan(new_chanspec));
20327 return 0;
20330 static int
20331 wl_itfr_get_stats(void *wl, cmd_t *cmd, char **argv)
20333 int err;
20334 interference_source_rep_t *iftr_stats = NULL;
20335 const char *iftr_source[] = {"none", "wireless phone", "wireless video camera",
20336 "microwave oven", "wireless baby monitor", "bluetooth device",
20337 "wireless video camera or baby monitor", "bluetooth or baby monitor",
20338 "video camera or phone", "unidentified"}; /* sync with interference_source_t */
20340 UNUSED_PARAMETER(argv);
20342 if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, (void*)&iftr_stats)) < 0)
20343 return err;
20345 if (iftr_stats->flags & ITFR_NOISY_ENVIRONMENT)
20346 printf("Feature is stopped due to noisy environment\n");
20347 else
20348 printf("Interference %s detected. last interference at timestamp %d: "
20349 "source is %s on %s channel\n",
20350 (iftr_stats->flags & ITFR_INTERFERENCED) ? "is" : "is not",
20351 iftr_stats->timestamp, iftr_source[iftr_stats->source],
20352 (iftr_stats->flags & ITFR_HOME_CHANNEL) ? "home" : "non-home");
20354 return err;
20357 static int
20358 wl_chanim_acs_record(void *wl, cmd_t *cmd, char **argv)
20360 void *ptr = NULL;
20361 int err = 0, i;
20362 wl_acs_record_t *result;
20364 /* need to add to this str if new acs trigger type is added */
20365 const char *trig_str[] = {"None", "IOCTL", "CHANIM", "TIMER", "BTA"};
20367 UNUSED_PARAMETER(argv);
20369 if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0)
20370 return err;
20372 result = (wl_acs_record_t *) ptr;
20374 if (!result->count) {
20375 printf("There is no ACS recorded\n");
20376 return err;
20379 printf("current timestamp: %u (ms)\n", result->timestamp);
20381 printf("Timestamp(ms) ACS Trigger Selected Channel Glitch Count CCA Count\n");
20382 for (i = 0; i < result->count; i++) {
20383 uint8 idx = CHANIM_ACS_RECORD - result->count + i;
20384 chanim_acs_record_t * record = &result->acs_record[idx];
20386 printf("%10u \t%s \t%10d \t%12d \t%8d\n", record->timestamp,
20387 trig_str[record->trigger], wf_chspec_ctlchan(record->selected_chspc),
20388 record->glitch_cnt, record->ccastats);
20390 return err;
20393 static int
20394 ARGCNT(char **argv)
20396 int i;
20398 for (i = 0; argv[i] != NULL; i ++)
20400 return i;
20403 #ifdef WLP2P
20404 static int
20405 wl_p2p_state(void *wl, cmd_t *cmd, char **argv)
20407 wl_p2p_disc_st_t st;
20408 int count;
20409 char *endptr;
20411 argv++;
20413 count = ARGCNT(argv);
20414 if (count < 1)
20415 return -1;
20417 st.state = (uint8) strtol(argv[0], &endptr, 0);
20418 if (st.state == WL_P2P_DISC_ST_LISTEN) {
20419 if (count != 3)
20420 return -1;
20421 if (wl_parse_chanspec_list(argv[1], &st.chspec, 1) == -1) {
20422 fprintf(stderr, "error parsing chanspec list arg\n");
20423 return BCME_BADARG;
20425 st.dwell = (uint16) strtol(argv[2], &endptr, 0);
20428 return wlu_var_setbuf(wl, cmd->name, &st, sizeof(st));
20431 static int
20432 wl_p2p_scan(void *wl, cmd_t *cmd, char **argv)
20434 wl_p2p_scan_t *params = NULL;
20435 int params_size = 0;
20436 int malloc_size = 0;
20437 int sparams_size = 0;
20438 int err = 0;
20440 if (*(argv + 1) != NULL) {
20441 malloc_size = sizeof(wl_p2p_scan_t);
20442 switch (toupper(**(argv + 1))) {
20443 case 'S':
20444 malloc_size += WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
20445 break;
20446 case 'E':
20447 malloc_size += OFFSETOF(wl_escan_params_t, params) +
20448 WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
20449 break;
20452 if (malloc_size == 0) {
20453 fprintf(stderr, "wrong syntax, need 'S' or 'E'\n");
20454 return -1;
20457 malloc_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
20458 params = (wl_p2p_scan_t *)malloc(malloc_size);
20459 if (params == NULL) {
20460 fprintf(stderr, "Error allocating %d bytes for scan params\n", malloc_size);
20461 return -1;
20463 memset(params, 0, malloc_size);
20465 switch (toupper(**(argv + 1))) {
20466 case 'S': {
20467 wl_scan_params_t *sparams = (wl_scan_params_t *)(params+1);
20468 sparams_size = malloc_size - sizeof(wl_p2p_scan_t);
20470 params->type = 'S';
20472 err = wl_scan_prep(wl, cmd, argv + 1, sparams, &sparams_size);
20473 params_size = sizeof(wl_p2p_scan_t) + sparams_size;
20474 break;
20477 case 'E': {
20478 wl_escan_params_t *eparams = (wl_escan_params_t *)(params+1);
20479 sparams_size = malloc_size - sizeof(wl_p2p_scan_t) - sizeof(wl_escan_params_t);
20481 params->type = 'E';
20483 eparams->version = htod32(ESCAN_REQ_VERSION);
20484 eparams->action = htod16(WL_SCAN_ACTION_START);
20486 #if defined(linux)
20487 srand((unsigned)time(NULL));
20488 eparams->sync_id = htod16(rand() & 0xffff);
20489 #else
20490 eparams->sync_id = htod16(4321);
20491 #endif /* #if defined(linux) */
20493 err = wl_scan_prep(wl, cmd, argv + 1, &eparams->params, &sparams_size);
20494 params_size = sizeof(wl_p2p_scan_t) + sizeof(wl_escan_params_t) + sparams_size;
20495 break;
20499 if (!err)
20500 err = wlu_iovar_setbuf(wl, cmd->name, params, params_size, buf, WLC_IOCTL_MAXLEN);
20502 free(params);
20503 return err;
20506 static int
20507 wl_p2p_ifadd(void *wl, cmd_t *cmd, char **argv)
20509 wl_p2p_if_t ifreq;
20510 int count;
20512 argv++;
20514 count = ARGCNT(argv);
20515 if (count < 2)
20516 return -1;
20518 if (!wl_ether_atoe(argv[0], &ifreq.addr))
20519 return -1;
20521 if (stricmp(argv[1], "go") == 0)
20522 ifreq.type = WL_P2P_IF_GO;
20523 else if (stricmp(argv[1], "client") == 0)
20524 ifreq.type = WL_P2P_IF_CLIENT;
20525 else if (stricmp(argv[1], "dyngo") == 0)
20526 ifreq.type = WL_P2P_IF_DYNBCN_GO;
20527 else
20528 return -1;
20530 if (ifreq.type == WL_P2P_IF_GO || ifreq.type == WL_P2P_IF_DYNBCN_GO) {
20531 if (count > 2) {
20532 if (wl_parse_chanspec_list(argv[2], &ifreq.chspec, 1) == -1) {
20533 fprintf(stderr, "error parsing chanspec list arg\n");
20534 return BCME_BADARG;
20537 else
20538 ifreq.chspec = 0;
20541 return wlu_var_setbuf(wl, cmd->name, &ifreq, sizeof(ifreq));
20544 static int
20545 wl_p2p_ifdel(void *wl, cmd_t *cmd, char **argv)
20547 struct ether_addr addr;
20548 int count;
20550 argv++;
20552 count = ARGCNT(argv);
20553 if (count != 1)
20554 return -1;
20556 if (!wl_ether_atoe(argv[0], &addr))
20557 return -1;
20559 return wlu_var_setbuf(wl, cmd->name, &addr, sizeof(addr));
20562 static int
20563 wl_p2p_ifupd(void *wl, cmd_t *cmd, char **argv)
20565 wl_p2p_if_t ifreq;
20566 int count;
20567 int ret;
20568 int bsscfg_idx = 0;
20569 int consumed = 0;
20571 argv++;
20573 /* parse a bsscfg_idx option if present */
20574 if ((ret = wl_cfg_option(argv, cmd->name, &bsscfg_idx, &consumed)) != 0)
20575 return ret;
20576 argv += consumed;
20577 if (consumed == 0)
20578 bsscfg_idx = -1;
20580 count = ARGCNT(argv);
20581 if (count < 2)
20582 return -1;
20584 if (!wl_ether_atoe(argv[0], &ifreq.addr))
20585 return -1;
20587 if (stricmp(argv[1], "go") == 0)
20588 ifreq.type = WL_P2P_IF_GO;
20589 else if (stricmp(argv[1], "client") == 0)
20590 ifreq.type = WL_P2P_IF_CLIENT;
20591 else
20592 return -1;
20594 ifreq.chspec = 0;
20596 if (bsscfg_idx == -1)
20597 return wlu_var_setbuf(wl, cmd->name, &ifreq, sizeof(ifreq));
20598 return wl_bssiovar_setbuf(wl, cmd->name, bsscfg_idx,
20599 &ifreq, sizeof(ifreq),
20600 buf, WLC_IOCTL_MAXLEN);
20603 static int
20604 wl_p2p_if(void *wl, cmd_t *cmd, char **argv)
20606 struct ether_addr addr;
20607 int count;
20608 wl_p2p_ifq_t *ptr;
20609 int err;
20611 argv++;
20613 count = ARGCNT(argv);
20614 if (count != 1)
20615 return -1;
20617 if (!wl_ether_atoe(argv[0], &addr))
20618 return -1;
20620 err = wlu_var_getbuf(wl, cmd->name, &addr, sizeof(addr), (void*)&ptr);
20621 if (err >= 0)
20622 printf("%u %s\n", dtoh32(ptr->bsscfgidx), (ptr->ifname));
20624 return err;
20627 static int
20628 wl_p2p_ops(void *wl, cmd_t *cmd, char **argv)
20630 wl_p2p_ops_t ops;
20631 int count;
20632 char *endptr;
20634 argv++;
20636 count = ARGCNT(argv);
20637 if (count < 1) {
20638 wl_p2p_ops_t *ops;
20639 int err;
20641 err = wlu_var_getbuf(wl, cmd->name, NULL, 0, (void *)&ops);
20642 if (err != BCME_OK) {
20643 fprintf(stderr, "%s: error %d\n", cmd->name, err);
20644 return BCME_ERROR;
20647 printf("ops: %u ctw: %u\n", ops->ops, ops->ctw);
20649 return BCME_OK;
20652 ops.ops = (uint8) strtol(argv[0], &endptr, 0);
20653 if (ops.ops != 0) {
20654 if (count != 2)
20655 return -1;
20656 ops.ctw = (uint8) strtol(argv[1], &endptr, 0);
20658 else
20659 ops.ctw = 0;
20661 return wlu_var_setbuf(wl, cmd->name, &ops, sizeof(ops));
20664 static int
20665 wl_p2p_noa(void *wl, cmd_t *cmd, char **argv)
20667 int count;
20668 wl_p2p_sched_t *noa;
20669 int len;
20670 int i;
20671 char *endptr;
20673 argv ++;
20675 strcpy(buf, cmd->name);
20677 count = ARGCNT(argv);
20678 if (count < 2) {
20679 int err = wlu_get(wl, WLC_GET_VAR, buf, WLC_IOCTL_MAXLEN);
20680 wl_p2p_sched_t *sched;
20681 int i;
20683 if (err != BCME_OK) {
20684 fprintf(stderr, "%s: error %d\n", cmd->name, err);
20685 return BCME_ERROR;
20688 sched = (wl_p2p_sched_t *)buf;
20689 for (i = 0; i < 16; i ++) {
20690 if (sched->desc[i].count == 0)
20691 break;
20692 printf("start: %u interval: %u duration: %u count: %u\n",
20693 sched->desc[i].start, sched->desc[i].interval,
20694 sched->desc[i].duration, sched->desc[i].count);
20697 return BCME_OK;
20700 len = strlen(buf);
20702 noa = (wl_p2p_sched_t *)&buf[len + 1];
20703 len += 1;
20705 noa->type = (uint8)strtol(argv[0], &endptr, 0);
20706 len += sizeof(noa->type);
20707 noa->action = (uint8)strtol(argv[1], &endptr, 0);
20708 len += sizeof(noa->action);
20710 argv += 2;
20711 count -= 2;
20713 /* action == -1 is to cancel the current schedule */
20714 if (noa->action == WL_P2P_SCHED_ACTION_RESET) {
20715 /* the fixed portion of wl_p2p_sched_t with action == WL_P2P_SCHED_ACTION_RESET
20716 * is required to cancel the curret schedule.
20718 len += (char *)&noa->desc[0] - ((char *)buf + len);
20720 /* Take care of any special cases only and let all other cases fall through
20721 * as normal 'start/interval/duration/count' descriptions.
20722 * All cases start with 'type' 'action' 'option'.
20723 * Any count value greater than 255 is to repeat unlimited.
20725 else {
20726 switch (noa->type) {
20727 case WL_P2P_SCHED_TYPE_ABS:
20728 case WL_P2P_SCHED_TYPE_REQ_ABS:
20729 if (count < 1)
20730 return -2;
20731 noa->option = (uint8)strtol(argv[0], &endptr, 0);
20732 len += sizeof(noa->option);
20733 argv += 1;
20734 count -= 1;
20735 break;
20738 /* add any paddings before desc field */
20739 len += (char *)&noa->desc[0] - ((char *)buf + len);
20741 switch (noa->type) {
20742 case WL_P2P_SCHED_TYPE_ABS:
20743 switch (noa->option) {
20744 case WL_P2P_SCHED_OPTION_BCNPCT:
20745 if (count == 1) {
20746 noa->desc[0].duration = htod32(strtol(argv[0], &endptr, 0));
20747 noa->desc[0].start = 100 - noa->desc[0].duration;
20749 else if (count == 2) {
20750 noa->desc[0].start = htod32(strtol(argv[0], &endptr, 0));
20751 noa->desc[0].duration = htod32(strtol(argv[1], &endptr, 0));
20753 else {
20754 fprintf(stderr, "Usage: wl p2p_noa 0 %d 1 "
20755 "<start-pct> <duration-pct>\n",
20756 noa->action);
20757 return BCME_ERROR;
20759 len += sizeof(wl_p2p_sched_desc_t);
20760 break;
20762 default:
20763 if (count < 4 || (count % 4) != 0) {
20764 fprintf(stderr, "Usage: wl p2p_noa 0 %d 0 "
20765 "<start> <interval> <duration> <count> ...\n",
20766 noa->action);
20767 return BCME_ERROR;
20769 goto normal;
20771 break;
20773 default:
20774 if (count != 4) {
20775 fprintf(stderr, "Usage: wl p2p_noa 1 %d "
20776 "<start> <interval> <duration> <count> ...\n",
20777 noa->action);
20778 return BCME_ERROR;
20780 /* fall through... */
20781 normal:
20782 for (i = 0; i < count; i += 4) {
20783 noa->desc[i / 4].start = htod32(strtoul(argv[i], &endptr, 0));
20784 noa->desc[i / 4].interval = htod32(strtol(argv[i + 1], &endptr, 0));
20785 noa->desc[i / 4].duration = htod32(strtol(argv[i + 2], &endptr, 0));
20786 noa->desc[i / 4].count = htod32(strtol(argv[i + 3], &endptr, 0));
20787 len += sizeof(wl_p2p_sched_desc_t);
20789 break;
20793 return wlu_set(wl, WLC_SET_VAR, buf, len);
20795 #endif /* WLP2P */
20797 static int
20798 wl_rpmt(void *wl, cmd_t *cmd, char **argv)
20800 int count;
20801 int len;
20802 char *endptr;
20803 uint32 val;
20805 argv ++;
20807 count = ARGCNT(argv);
20808 if (count != 2) {
20809 return BCME_ERROR;
20812 strcpy(buf, cmd->name);
20813 len = strlen(buf) + 1;
20815 val = htod32(strtoul(argv[0], &endptr, 0));
20816 memcpy(&buf[len], &val, sizeof(uint32));
20817 len += sizeof(uint32);
20818 val = htod32(strtoul(argv[1], &endptr, 0));
20819 memcpy(&buf[len], &val, sizeof(uint32));
20820 len += sizeof(uint32);
20822 return wlu_set(wl, WLC_SET_VAR, buf, len);
20825 static int
20826 wl_ledbh(void *wl, cmd_t *cmd, char **argv)
20828 int err;
20829 wl_led_info_t led;
20830 void *ptr = NULL;
20832 memset(&led, 0, sizeof(wl_led_info_t));
20833 if (*++argv == NULL) {
20834 printf("Usage: ledbh [led#] [behavior#]\n");
20835 return -1;
20837 led.index = (int)strtoul(*argv, NULL, 10);
20839 if (led.index > 3) {
20840 printf("only 4 led supported\n");
20841 return -1;
20844 if (*++argv) { /* set */
20845 /* Read the original back so we don't toggle the activehi */
20846 if ((err = wlu_var_getbuf(wl, cmd->name, (void*)&led,
20847 sizeof(wl_led_info_t), &ptr)) < 0) {
20848 printf("wl_ledbh: fail to get. code %x\n", err);
20850 led.behavior = (int)strtoul(*argv, NULL, 10);
20851 led.activehi = ((wl_led_info_t*)ptr)->activehi;
20853 if ((err = wlu_var_setbuf(wl, cmd->name, (void*)&led,
20854 sizeof(wl_led_info_t))) < 0) {
20855 printf("wl_ledbh: fail to set\n");
20857 } else { /* get */
20858 wl_led_info_t *ledo;
20860 if ((err = wlu_var_getbuf(wl, cmd->name, (void*)&led,
20861 sizeof(wl_led_info_t), &ptr)) < 0) {
20862 printf("wl_ledbh: fail to get\n");
20864 ledo = (wl_led_info_t*)ptr;
20866 printf("led %d behavior %d\n", ledo->index, ledo->behavior);
20869 return 0;
20872 static int
20873 wl_led_blink_sync(void *wl, cmd_t *cmd, char **argv)
20875 int argc;
20876 int err = 0;
20877 int in_arg[2];
20878 void *ptr = NULL;
20879 char *endptr;
20881 /* arg count */
20882 for (argc = 0; argv[argc]; argc++)
20885 if (argc > 3 || argc < 2)
20886 return -1;
20888 in_arg[0] = htod32((uint32)(strtoul(argv[1], &endptr, 0)));
20890 if (in_arg[0] > 3) {
20891 printf("only 4 led supported\n");
20892 return -1;
20895 if (argc == 2) {
20896 err = wlu_var_getbuf(wl, cmd->name, (void*)in_arg, sizeof(int), &ptr);
20897 if (err < 0)
20898 return err;
20899 printf("led%d, blink_sync is %s\n", in_arg[0],
20900 (dtoh32(*(int*)ptr) != 0) ? "TRUE" : "FALSE");
20902 else if (argc == 3) {
20903 in_arg[1] = htod32((uint32)(strtoul(argv[2], &endptr, 0)));
20904 wlu_var_setbuf(wl, cmd->name, in_arg, sizeof(in_arg));
20906 else {
20907 fprintf(stderr, "illegal command!\n");
20908 return -1;
20911 return err;
20914 static int
20915 wl_rrm_nbr_req(void *wl, cmd_t *cmd, char **argv)
20917 int err, buflen;
20918 wlc_ssid_t ssid;
20920 UNUSED_PARAMETER(cmd);
20922 strcpy(buf, "rrm_nbr_req");
20923 buflen = strlen("rrm_nbr_req") + 1;
20925 if (*++argv) {
20926 uint32 len;
20928 len = strlen(*argv);
20929 if (len > DOT11_MAX_SSID_LEN) {
20930 printf("ssid too long\n");
20931 return (-1);
20933 memset(&ssid, 0, sizeof(wlc_ssid_t));
20934 memcpy(ssid.SSID, *argv, len);
20935 ssid.SSID_len = len;
20936 memcpy(&buf[buflen], &ssid, sizeof(wlc_ssid_t));
20937 buflen += sizeof(wlc_ssid_t);
20940 err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
20942 return err;
20945 static int
20946 wl_dngl_wd(void *wl, cmd_t *cmd, char **argv)
20948 const char *cmdname = "dngl_wd";
20949 struct dngl_wd {
20950 uint32 dngl_wd;
20951 uint32 dngl_wd_exptime;
20952 } dngl_wd_buf;
20953 char *endptr;
20954 int err;
20956 UNUSED_PARAMETER(cmd);
20958 /* toss the command name */
20959 argv++;
20961 if (*argv == NULL) {
20962 /* get */
20963 err = wlu_iovar_get(wl, cmdname, &dngl_wd_buf, sizeof(dngl_wd_buf));
20964 if (err)
20965 return err;
20966 if (htod32(dngl_wd_buf.dngl_wd))
20967 printf("wd: on exptime: %dsec\n",
20968 htod32(dngl_wd_buf.dngl_wd_exptime));
20969 else
20970 printf("wd: off\n");
20971 } else {
20972 if (!stricmp(*argv, "on")) {
20973 dngl_wd_buf.dngl_wd = 1;
20974 if (argv[1] == NULL)
20975 dngl_wd_buf.dngl_wd_exptime = 0;
20976 else {
20977 argv++;
20978 dngl_wd_buf.dngl_wd_exptime = (uint32)strtoul(*argv, &endptr, 0);
20980 } else if (!stricmp(*argv, "off")) {
20981 dngl_wd_buf.dngl_wd = 0;
20982 dngl_wd_buf.dngl_wd_exptime = 0;
20983 } else
20984 return USAGE_ERROR;
20986 dngl_wd_buf.dngl_wd = dtoh32(dngl_wd_buf.dngl_wd);
20987 dngl_wd_buf.dngl_wd_exptime = dtoh32(dngl_wd_buf.dngl_wd_exptime);
20988 err = wlu_iovar_set(wl, cmdname, &dngl_wd_buf, sizeof(dngl_wd_buf));
20990 return err;
20994 static int
20995 wl_wnm_bsstq(void *wl, cmd_t *cmd, char **argv)
20997 int err, buflen;
20998 wlc_ssid_t ssid;
21000 UNUSED_PARAMETER(cmd);
21002 strcpy(buf, "wnm_bsstq");
21003 buflen = strlen("wnm_bsstq") + 1;
21005 if (*++argv) {
21006 uint32 len;
21008 len = strlen(*argv);
21009 if (len > DOT11_MAX_SSID_LEN) {
21010 printf("ssid too long\n");
21011 return (-1);
21013 memset(&ssid, 0, sizeof(wlc_ssid_t));
21014 memcpy(ssid.SSID, *argv, len);
21015 ssid.SSID_len = len;
21016 memcpy(&buf[buflen], &ssid, sizeof(wlc_ssid_t));
21017 buflen += sizeof(wlc_ssid_t);
21020 err = wlu_set(wl, WLC_SET_VAR, buf, buflen);
21022 return err;
21026 static int
21027 wl_tsf(void *wl, cmd_t *cmd, char **argv)
21029 const char *cmdname = "tsf";
21030 struct tsf {
21031 uint32 low;
21032 uint32 high;
21033 } tsf_buf;
21034 char *endptr;
21035 int err;
21037 UNUSED_PARAMETER(cmd);
21039 /* toss the command name */
21040 argv++;
21042 if (*argv == NULL) {
21043 /* get */
21044 err = wlu_iovar_get(wl, cmdname, &tsf_buf, sizeof(tsf_buf));
21045 if (err)
21046 return err;
21047 printf("0x%08X 0x%08X\n", htod32(tsf_buf.high), htod32(tsf_buf.low));
21048 } else {
21049 /* set */
21050 if (argv[1] == NULL)
21051 return USAGE_ERROR;
21053 tsf_buf.high = (uint32)strtoul(*argv, &endptr, 0);
21054 if (*endptr != '\0') {
21055 fprintf(stderr, "%s: %s: error parsing \"%s\" as an integer\n",
21056 wlu_av0, cmdname, *argv);
21057 return USAGE_ERROR;
21060 argv++;
21061 tsf_buf.low = (uint32)strtoul(*argv, &endptr, 0);
21062 if (*endptr != '\0') {
21063 fprintf(stderr, "%s: %s: error parsing \"%s\" as an integer\n",
21064 wlu_av0, cmdname, *argv);
21065 return USAGE_ERROR;
21068 tsf_buf.low = dtoh32(tsf_buf.low);
21069 tsf_buf.high = dtoh32(tsf_buf.high);
21071 err = wlu_iovar_set(wl, cmdname, &tsf_buf, sizeof(tsf_buf));
21072 if (err)
21073 return err;
21076 return err;
21079 static int
21080 wl_mfp_config(void *wl, cmd_t *cmd, char **argv)
21082 int argc;
21083 int err = 0;
21084 int flag = 0;
21085 const char *cmdname = "mfp";
21087 UNUSED_PARAMETER(cmd);
21089 /* arg count */
21090 for (argc = 0; argv[argc]; argc++)
21093 if (argc > 1 && argv[1]) {
21094 flag = htod32(atoi(argv[1]));
21095 *(int *)buf = flag;
21098 err = wlu_iovar_set(wl, cmdname, buf, 256);
21100 return (err);
21104 static int
21105 wl_mfp_sha256(void *wl, cmd_t *cmd, char **argv)
21107 int argc;
21108 int err = 0;
21109 int flag = 0;
21110 const char *cmdname = "mfp_sha256";
21112 UNUSED_PARAMETER(cmd);
21114 /* arg count */
21115 for (argc = 0; argv[argc]; argc++)
21118 if (argc > 1 && argv[1]) {
21119 flag = htod32(atoi(argv[1]));
21120 *(int *)buf = flag;
21123 err = wlu_iovar_set(wl, cmdname, buf, 256);
21125 return (err);
21130 static int
21131 wl_mfp_sa_query(void *wl, cmd_t *cmd, char **argv)
21133 wl_sa_query_t * query;
21134 int argc;
21135 int err = 0;
21137 UNUSED_PARAMETER(cmd);
21139 /* arg count */
21140 for (argc = 0; argv[argc]; argc++)
21143 if ((query = (wl_sa_query_t *) malloc(sizeof(wl_sa_query_t))) == NULL) {
21144 printf("unable to allocate frame \n");
21145 return -1;
21147 memset(query, 0, sizeof(wl_sa_query_t));
21149 /* add the flag */
21150 if (argc > 1 && argv[1]) {
21151 query->flag = htod32(atoi(argv[1]));
21154 /* add the action */
21155 if (argc > 2 && argv[2]) {
21156 query->action = htod32(atoi(argv[2]));
21159 /* add the id */
21160 if (argc > 3 && argv[3]) {
21161 query->id = htod32(atoi(argv[3]));
21164 err = wlu_var_setbuf(wl, "mfp_sa_query", query, sizeof(wl_sa_query_t));
21166 free(query);
21168 return (err);
21172 static int
21173 wl_mfp_disassoc(void *wl, cmd_t *cmd, char **argv)
21175 const char *cmdname = "mfp_disassoc";
21176 int argc;
21177 int flag;
21178 char buf[256];
21179 int err;
21181 UNUSED_PARAMETER(cmd);
21182 memset(buf, 0, 256);
21184 /* arg count */
21185 for (argc = 0; argv[argc]; argc++)
21188 /* add the action */
21189 if (argc > 1 && argv[1]) {
21190 flag = htod32(atoi(argv[1]));
21191 *(int *)buf = flag;
21193 if (argc > 2 && argv[2]) {
21194 flag = htod32(atoi(argv[2]));
21195 *(int *)(buf + sizeof(flag)) = flag;
21198 err = wlu_iovar_set(wl, cmdname, buf, 256);
21199 if (err)
21200 return err;
21202 return err;
21205 static int
21206 wl_mfp_deauth(void *wl, cmd_t *cmd, char **argv)
21208 const char *cmdname = "mfp_deauth";
21209 int argc;
21210 int flag;
21211 char buf[256];
21212 int err;
21214 UNUSED_PARAMETER(cmd);
21216 memset(buf, 0, 256);
21218 /* arg count */
21219 for (argc = 0; argv[argc]; argc++)
21222 /* add the action */
21223 if (argc > 1 && argv[1]) {
21224 flag = htod32(atoi(argv[1]));
21225 *(int *)buf = flag;
21227 if (argc > 2 && argv[2]) {
21228 flag = htod32(atoi(argv[2]));
21229 *(int *)(buf + sizeof(flag)) = flag;
21232 err = wlu_iovar_set(wl, cmdname, buf, 256);
21233 if (err)
21234 return err;
21236 return err;
21239 static int
21240 wl_mfp_assoc(void *wl, cmd_t *cmd, char **argv)
21242 const char *cmdname = "mfp_assoc";
21243 int argc;
21244 int flag;
21245 char buf[256];
21246 int err;
21248 UNUSED_PARAMETER(cmd);
21249 memset(buf, 0, 256);
21251 /* arg count */
21252 for (argc = 0; argv[argc]; argc++)
21255 /* add the action */
21256 if (argc > 1 && argv[1]) {
21257 flag = htod32(atoi(argv[1]));
21258 *(int *)buf = flag;
21260 if (argc > 2 && argv[2]) {
21261 flag = htod32(atoi(argv[2]));
21262 *(int *)(buf + sizeof(int)) = flag;
21265 err = wlu_iovar_set(wl, cmdname, buf, 256);
21266 if (err)
21267 return err;
21269 return err;
21272 static int
21273 wl_mfp_auth(void *wl, cmd_t *cmd, char **argv)
21275 const char *cmdname = "mfp_auth";
21276 int argc;
21277 int flag;
21278 char buf[256];
21279 int err;
21281 UNUSED_PARAMETER(cmd);
21282 memset(buf, 0, 256);
21284 /* arg count */
21285 for (argc = 0; argv[argc]; argc++)
21288 /* add the action */
21289 if (argc > 1 && argv[1]) {
21290 flag = htod32(atoi(argv[1]));
21291 *(int *)buf = flag;
21293 if (argc > 2 && argv[2]) {
21294 flag = htod32(atoi(argv[2]));
21295 *(int *)(buf + sizeof(int)) = flag;
21298 err = wlu_iovar_set(wl, cmdname, buf, 256);
21299 if (err)
21300 return err;
21302 return err;
21306 static int
21307 wl_mfp_reassoc(void *wl, cmd_t *cmd, char **argv)
21309 const char *cmdname = "mfp_reassoc";
21310 int argc;
21311 int flag;
21312 char buf[256];
21313 int err;
21315 UNUSED_PARAMETER(cmd);
21316 memset(buf, 0, 256);
21318 /* arg count */
21319 for (argc = 0; argv[argc]; argc++)
21322 /* add the action */
21323 if (argc > 1 && argv[1]) {
21324 flag = htod32(atoi(argv[1]));
21325 *(int *)buf = flag;
21327 if (argc > 2 && argv[2]) {
21328 flag = htod32(atoi(argv[2]));
21329 *(int *)(buf + sizeof(int)) = flag;
21332 err = wlu_iovar_set(wl, cmdname, buf, 256);
21333 if (err)
21334 return err;
21336 return err;
21340 static int
21341 wl_scb_probe(void *wl, cmd_t *cmd, char **argv)
21343 const char *cmdname = "scb_probe";
21344 wl_scb_probe_t buff;
21345 int err, argc;
21347 UNUSED_PARAMETER(cmd);
21349 /* toss the command name */
21350 argv++;
21352 if (*argv == NULL) {
21353 /* get */
21354 err = wlu_iovar_get(wl, cmdname, &buff, sizeof(wl_scb_probe_t));
21355 if (err)
21356 return err;
21358 printf("timeout:%d sec, activity_time:%d sec, nprobes:%d\n",
21359 buff.scb_timeout, buff.scb_activity_time, buff.scb_max_probe);
21360 } else {
21361 /* arg count */
21362 for (argc = 0; argv[argc]; argc++)
21365 if (argc < 3) {
21366 return -1;
21369 buff.scb_timeout = htod32(atoi(argv[0]));
21370 buff.scb_activity_time = htod32(atoi(argv[1]));
21371 buff.scb_max_probe = htod32(atoi(argv[2]));
21372 err = wlu_iovar_set(wl, cmdname, &buff, sizeof(wl_scb_probe_t));
21374 return err;
21377 static int
21378 wl_spatial_policy(void *wl, cmd_t *cmd, char **argv)
21380 void *ptr = NULL;
21381 int err, i, *reply;
21382 int mode[SPATIAL_MODE_MAX_IDX] = {-1, -1, -1, -1, -1};
21384 /* Order is 2G, 5G-LOW, 5G-MID, 5G-HIGH, 5G-UPPER
21385 * if only one argument given, than all band or sub-band take the
21386 * same value
21388 if (!*++argv) {
21389 bool all_same = TRUE;
21390 if ((err = wlu_var_getbuf(wl, cmd->name, &mode, sizeof(mode), &ptr)) < 0)
21391 return err;
21392 reply = (int *)ptr;
21393 for (i = 1; i < SPATIAL_MODE_MAX_IDX; i++) {
21394 /* check if return values for each band/sub-band is same or not */
21395 if (reply[i-1] != reply[i])
21396 all_same = FALSE;
21398 if (all_same)
21399 printf("%2d\n", reply[0]);
21400 else {
21401 printf("2.4GHz : %2d\n", reply[SPATIAL_MODE_2G_IDX]);
21402 printf("5GHz (lower) : %2d\n", reply[SPATIAL_MODE_5G_LOW_IDX]);
21403 printf("5GHz (middle): %2d\n", reply[SPATIAL_MODE_5G_MID_IDX]);
21404 printf("5GHz (high) : %2d\n", reply[SPATIAL_MODE_5G_HIGH_IDX]);
21405 printf("5GHz (upper) : %2d\n", reply[SPATIAL_MODE_5G_UPPER_IDX]);
21407 return 0;
21409 mode[0] = atoi(*argv);
21410 if (!*++argv) {
21411 for (i = 1; i < SPATIAL_MODE_MAX_IDX; i++)
21412 mode[i] = mode[0];
21413 } else {
21414 for (i = 1; i < SPATIAL_MODE_MAX_IDX; i++) {
21415 mode[i] = atoi(*argv);
21416 if (!*++argv && i < (SPATIAL_MODE_MAX_IDX - 1)) {
21417 printf("error: missing arguments\n");
21418 return -1;
21422 err = wlu_var_setbuf(wl, cmd->name, &mode, sizeof(mode));
21423 return err;
21426 static int
21427 wl_ratetbl_ppr(void *wl, cmd_t *cmd, char **argv)
21429 void *ptr = NULL;
21430 int err, i, *reply;
21431 int val[12];
21433 /* Order is 2G, 5G-LOW, 5G-MID, 5G-HIGH, 5G-UPPER
21434 * if only one argument given, than all band or sub-band take the
21435 * same value
21437 memset(&val, 0, sizeof(val));
21438 if (!*++argv) {
21439 if ((err = wlu_var_getbuf(wl, cmd->name, &val, sizeof(val), &ptr)) < 0)
21440 return err;
21441 reply = (int *)ptr;
21442 for (i = 0; i < 12; i++)
21443 printf("%s: %2d\n", (reply[i] & 0x80) ? "OFDM" : "CCK ", (reply[i] & 0x7f));
21444 return 0;
21446 val[0] = atoi(*argv++);
21447 val[1] = atoi(*argv++);
21448 err = wlu_var_setbuf(wl, cmd->name, &val, sizeof(val));
21449 return err;
21452 static int
21453 wl_ie(void *wl, cmd_t *cmd, char **argv)
21455 void *ptr;
21456 int err;
21457 uchar *data;
21458 int bsscfg_idx = 0;
21459 int consumed = 0;
21460 uint32 pktflag;
21461 int iecount;
21462 ie_setbuf_t *ie_setbuf;
21463 ie_getbuf_t param;
21464 uchar datalen, type, count, col;
21466 /* parse a bsscfg_idx option if present */
21467 if ((err = wl_cfg_option(argv + 1, argv[0], &bsscfg_idx, &consumed)) != 0)
21468 return err;
21469 if (consumed)
21470 argv = argv + consumed;
21471 if (consumed == 0)
21472 bsscfg_idx = -1;
21474 if (!*++argv) {
21475 fprintf(stderr, "missing parameter type\n");
21476 return -1;
21478 /* get IE type */
21479 type = (uchar)atoi(argv[0]);
21481 /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE */
21482 pktflag = htod32(VNDR_IE_CUSTOM_FLAG);
21484 if (!*++argv) {
21485 memcpy((void *)&param.pktflag, &pktflag, sizeof(uint32));
21486 param.id = type;
21487 ptr = buf;
21488 if (bsscfg_idx == -1)
21489 err = wlu_var_getbuf(wl, cmd->name, &param, sizeof(param), &ptr);
21490 else
21491 err = wl_bssiovar_getbuf(wl, cmd->name, bsscfg_idx, &param, sizeof(param),
21492 buf, WLC_IOCTL_MAXLEN);
21493 if (err == 0) {
21494 data = (uchar *)ptr;
21495 datalen = data[1]+2;
21496 printf("%s len %d\n", cmd->name, datalen);
21497 printf("%s Data:\n", cmd->name);
21498 for (count = 0; (count < datalen);) {
21499 for (col = 0; (col < MAX_DATA_COLS) &&
21500 (count < datalen); col++, count++) {
21501 printf("%02x", *data++);
21503 printf("\n");
21506 else {
21507 fprintf(stderr, "Error %d getting IOVar\n", err);
21509 return err;
21512 /* get IE length */
21513 datalen = (uchar)atoi(argv[0]);
21515 if (datalen > 0) {
21516 if (!argv[1]) {
21517 fprintf(stderr, "Data bytes should be specified for IE of length %d\n",
21518 datalen);
21519 return -1;
21521 else {
21522 /* Ensure each data byte is 2 characters long */
21523 if ((int)strlen (argv[1]) < (datalen * 2)) {
21524 fprintf(stderr, "Please specify all the data bytes for this IE\n");
21525 return -1;
21530 if ((datalen == 0) && (argv[1] != NULL))
21531 fprintf(stderr, "Ignoring data bytes for IE of length %d\n", datalen);
21533 count = sizeof(ie_setbuf_t) + datalen - 1;
21534 data = malloc(count);
21535 if (data == NULL) {
21536 fprintf(stderr, "memory alloc failure\n");
21537 return -1;
21540 ie_setbuf = (ie_setbuf_t *) data;
21541 /* Copy the ie SET command ("add") to the buffer */
21542 strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
21543 ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
21545 /* Buffer contains only 1 IE */
21546 iecount = htod32(1);
21547 memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int));
21549 memcpy((void *)&ie_setbuf->ie_buffer.pktflag, &pktflag, sizeof(uint32));
21551 /* Now, add the IE to the buffer */
21552 ie_setbuf->ie_buffer.ie_list[0].id = type;
21553 ie_setbuf->ie_buffer.ie_list[0].len = datalen;
21555 if (datalen > 0) {
21556 if ((err = get_ie_data ((uchar *)argv[1],
21557 &ie_setbuf->ie_buffer.ie_list[0].data[0],
21558 datalen))) {
21559 free(data);
21560 fprintf(stderr, "Error parsing data arg\n");
21561 return err;
21565 if (bsscfg_idx == -1)
21566 err = wlu_var_setbuf(wl, cmd->name, data, count);
21567 else
21568 err = wl_bssiovar_setbuf(wl, cmd->name, bsscfg_idx,
21569 data, count, buf, WLC_IOCTL_MAXLEN);
21571 free(data);
21572 return (err);
21575 /* Restore the ignored warnings status */
21576 #ifdef WIN32
21577 #pragma warning(pop)
21578 #endif