1/*
2 * Copyright 1997, 1998, 1999
3 *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#if 0
34#ifndef lint
35static const char copyright[] = "@(#) Copyright (c) 1997, 1998, 1999\
36	Bill Paul. All rights reserved.";
37#endif
38#endif
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD$");
41
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <sys/ioctl.h>
45
46#include <arpa/inet.h>
47
48#include <net/if.h>
49#include <net/if_var.h>
50#include <net/ethernet.h>
51
52#include <dev/an/if_aironet_ieee.h>
53
54#include <stdio.h>
55#include <string.h>
56#include <stdlib.h>
57#include <unistd.h>
58#include <errno.h>
59#include <err.h>
60#include <md4.h>
61#include <ctype.h>
62
63static int an_getval(const char *, struct an_req *);
64static void an_setval(const char *, struct an_req *);
65static void an_printwords(const u_int16_t *, int);
66static void an_printspeeds(const u_int8_t *, int);
67static void an_printbool(int);
68static void an_printhex(const char *, int);
69static void an_printstr(char *, int);
70static void an_dumpstatus(const char *);
71static void an_dumpstats(const char *);
72static void an_dumpconfig(const char *);
73static void an_dumpcaps(const char *);
74static void an_dumpssid(const char *);
75static void an_dumpap(const char *);
76static void an_setconfig(const char *, int, void *);
77static void an_setssid(const char *, int, void *);
78static void an_setap(const char *, int, void *);
79static void an_setspeed(const char *, int, void *);
80static void an_readkeyinfo(const char *);
81#ifdef ANCACHE
82static void an_zerocache(const char *);
83static void an_readcache(const char *);
84#endif
85static int an_hex2int(char);
86static void an_str2key(const char *, struct an_ltv_key *);
87static void an_setkeys(const char *, const char *, int);
88static void an_enable_tx_key(const char *, const char *);
89static void an_enable_leap_mode(const char *, const char *);
90static void an_dumprssimap(const char *);
91static void usage(const char *);
92
93#define ACT_DUMPSTATS 1
94#define ACT_DUMPCONFIG 2
95#define ACT_DUMPSTATUS 3
96#define ACT_DUMPCAPS 4
97#define ACT_DUMPSSID 5
98#define ACT_DUMPAP 6
99
100#define ACT_SET_OPMODE 7
101#define ACT_SET_SSID 8
102#define ACT_SET_FREQ 11
103#define ACT_SET_AP1 12
104#define ACT_SET_AP2 13
105#define ACT_SET_AP3 14
106#define ACT_SET_AP4 15
107#define ACT_SET_DRIVERNAME 16
108#define ACT_SET_SCANMODE 17
109#define ACT_SET_TXRATE 18
110#define ACT_SET_RTS_THRESH 19
111#define ACT_SET_PWRSAVE 20
112#define ACT_SET_DIVERSITY_RX 21
113#define ACT_SET_DIVERSITY_TX 22
114#define ACT_SET_RTS_RETRYLIM 23
115#define ACT_SET_WAKE_DURATION 24
116#define ACT_SET_BEACON_PERIOD 25
117#define ACT_SET_TXPWR 26
118#define ACT_SET_FRAG_THRESH 27
119#define ACT_SET_NETJOIN 28
120#define ACT_SET_MYNAME 29
121#define ACT_SET_MAC 30
122
123#define ACT_DUMPCACHE 31
124#define ACT_ZEROCACHE 32
125
126#define ACT_ENABLE_WEP 33
127#define ACT_SET_KEY_TYPE 34
128#define ACT_SET_KEYS 35
129#define ACT_ENABLE_TX_KEY 36
130#define ACT_SET_MONITOR_MODE 37
131#define ACT_SET_LEAP_MODE 38
132
133#define ACT_DUMPRSSIMAP 39
134
135static int
136an_getval(const char *iface, struct an_req *areq)
137{
138	struct ifreq		ifr;
139	int			s, okay = 1;
140
141	bzero(&ifr, sizeof(ifr));
142
143	strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
144	ifr.ifr_data = (caddr_t)areq;
145
146	s = socket(AF_INET, SOCK_DGRAM, 0);
147
148	if (s == -1)
149		err(1, "socket");
150
151	if (ioctl(s, SIOCGAIRONET, &ifr) == -1) {
152		okay = 0;
153		err(1, "SIOCGAIRONET");
154	}
155
156	close(s);
157
158	return (okay);
159}
160
161static void
162an_setval(const char *iface, struct an_req *areq)
163{
164	struct ifreq		ifr;
165	int			s;
166
167	bzero(&ifr, sizeof(ifr));
168
169	strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
170	ifr.ifr_data = (caddr_t)areq;
171
172	s = socket(AF_INET, SOCK_DGRAM, 0);
173
174	if (s == -1)
175		err(1, "socket");
176
177	if (ioctl(s, SIOCSAIRONET, &ifr) == -1)
178		err(1, "SIOCSAIRONET");
179
180	close(s);
181
182	return;
183}
184
185static void
186an_printstr(char *str, int len)
187{
188	int			i;
189
190	for (i = 0; i < len - 1; i++) {
191		if (str[i] == '\0')
192			str[i] = ' ';
193	}
194
195	printf("[ %.*s ]", len, str);
196}
197
198static void
199an_printwords(const u_int16_t *w, int len)
200{
201	int			i;
202
203	printf("[ ");
204	for (i = 0; i < len; i++)
205		printf("%u ", w[i]);
206	printf("]");
207}
208
209static void
210an_printspeeds(const u_int8_t *w, int len)
211{
212	int			i;
213
214	printf("[ ");
215	for (i = 0; i < len && w[i]; i++)
216		printf("%2.1fMbps ", w[i] * 0.500);
217	printf("]");
218}
219
220static void
221an_printbool(int val)
222{
223	if (val)
224		printf("[ On ]");
225	else
226		printf("[ Off ]");
227}
228
229static void
230an_printhex(const char *ptr, int len)
231{
232	int			i;
233
234	printf("[ ");
235	for (i = 0; i < len; i++) {
236		printf("%02x", ptr[i] & 0xFF);
237		if (i < (len - 1))
238			printf(":");
239	}
240
241	printf(" ]");
242}
243
244
245
246static void
247an_dumpstatus(const char *iface)
248{
249	struct an_ltv_status	*sts;
250	struct an_req		areq;
251	struct an_ltv_rssi_map	an_rssimap;
252	int rssimap_valid = 0;
253
254	/*
255	 * Try to get RSSI to percent and dBM table
256	 */
257
258	an_rssimap.an_len = sizeof(an_rssimap);
259	an_rssimap.an_type = AN_RID_RSSI_MAP;
260	rssimap_valid = an_getval(iface, (struct an_req*)&an_rssimap);
261
262	if (rssimap_valid)
263		printf("RSSI table:\t\t[ present ]\n");
264	else
265		printf("RSSI table:\t\t[ not available ]\n");
266
267	areq.an_len = sizeof(areq);
268	areq.an_type = AN_RID_STATUS;
269
270	an_getval(iface, &areq);
271
272	sts = (struct an_ltv_status *)&areq;
273
274	printf("MAC address:\t\t");
275	an_printhex((char *)&sts->an_macaddr, ETHER_ADDR_LEN);
276	printf("\nOperating mode:\t\t[ ");
277	if (sts->an_opmode & AN_STATUS_OPMODE_CONFIGURED)
278		printf("configured ");
279	if (sts->an_opmode & AN_STATUS_OPMODE_MAC_ENABLED)
280		printf("MAC ON ");
281	if (sts->an_opmode & AN_STATUS_OPMODE_RX_ENABLED)
282		printf("RX ON ");
283	if (sts->an_opmode & AN_STATUS_OPMODE_IN_SYNC)
284		printf("synced ");
285	if (sts->an_opmode & AN_STATUS_OPMODE_ASSOCIATED)
286		printf("associated ");
287	if (sts->an_opmode & AN_STATUS_OPMODE_LEAP)
288		printf("LEAP ");
289	if (sts->an_opmode & AN_STATUS_OPMODE_ERROR)
290		printf("error ");
291	printf("]\n");
292	printf("Error code:\t\t");
293	an_printhex((char *)&sts->an_errcode, 1);
294	if (rssimap_valid)
295		printf("\nSignal strength:\t[ %u%% ]",
296		    an_rssimap.an_entries[
297			sts->an_normalized_strength].an_rss_pct);
298	else
299		printf("\nSignal strength:\t[ %u%% ]",
300		    sts->an_normalized_strength);
301	printf("\nAverage Noise:\t\t[ %u%% ]", sts->an_avg_noise_prev_min_pc);
302	if (rssimap_valid)
303		printf("\nSignal quality:\t\t[ %u%% ]",
304		    an_rssimap.an_entries[
305			sts->an_cur_signal_quality].an_rss_pct);
306	else
307		printf("\nSignal quality:\t\t[ %u ]",
308		    sts->an_cur_signal_quality);
309	printf("\nMax Noise:\t\t[ %u%% ]", sts->an_max_noise_prev_min_pc);
310	/*
311	 * XXX: This uses the old definition of the rate field (units of
312	 * 500kbps).  Technically the new definition is that this field
313	 * contains arbitrary values, but no devices which need this
314	 * support exist and the IEEE seems to intend to use the old
315	 * definition until they get something big so we'll keep using
316	 * it as well because this will work with new cards with
317	 * rate <= 63.5Mbps.
318	 */
319	printf("\nCurrent TX rate:\t[ %u%s ]", sts->an_current_tx_rate / 2,
320	    (sts->an_current_tx_rate % 2) ? ".5" : "");
321	printf("\nCurrent SSID:\t\t");
322	an_printstr((char *)&sts->an_ssid, sts->an_ssidlen);
323	printf("\nCurrent AP name:\t");
324	an_printstr((char *)&sts->an_ap_name, 16);
325	printf("\nCurrent BSSID:\t\t");
326	an_printhex((char *)&sts->an_cur_bssid, ETHER_ADDR_LEN);
327	printf("\nBeacon period:\t\t");
328	an_printwords(&sts->an_beacon_period, 1);
329	printf("\nDTIM period:\t\t");
330	an_printwords(&sts->an_dtim_period, 1);
331	printf("\nATIM duration:\t\t");
332	an_printwords(&sts->an_atim_duration, 1);
333	printf("\nHOP period:\t\t");
334	an_printwords(&sts->an_hop_period, 1);
335	printf("\nChannel set:\t\t");
336	an_printwords(&sts->an_channel_set, 1);
337	printf("\nCurrent channel:\t");
338	an_printwords(&sts->an_cur_channel, 1);
339	printf("\nHops to backbone:\t");
340	an_printwords(&sts->an_hops_to_backbone, 1);
341	printf("\nTotal AP load:\t\t");
342	an_printwords(&sts->an_ap_total_load, 1);
343	printf("\nOur generated load:\t");
344	an_printwords(&sts->an_our_generated_load, 1);
345	printf("\nAccumulated ARL:\t");
346	an_printwords(&sts->an_accumulated_arl, 1);
347	printf("\n");
348	return;
349}
350
351static void
352an_dumpcaps(const char *iface)
353{
354	struct an_ltv_caps	*caps;
355	struct an_req		areq;
356	u_int16_t		tmp;
357
358	areq.an_len = sizeof(areq);
359	areq.an_type = AN_RID_CAPABILITIES;
360
361	an_getval(iface, &areq);
362
363	caps = (struct an_ltv_caps *)&areq;
364
365	printf("OUI:\t\t\t");
366	an_printhex((char *)&caps->an_oui, 3);
367	printf("\nProduct number:\t\t");
368	an_printwords(&caps->an_prodnum, 1);
369	printf("\nManufacturer name:\t");
370	an_printstr((char *)&caps->an_manufname, 32);
371	printf("\nProduce name:\t\t");
372	an_printstr((char *)&caps->an_prodname, 16);
373	printf("\nFirmware version:\t");
374	an_printstr((char *)&caps->an_prodvers, 1);
375	printf("\nOEM MAC address:\t");
376	an_printhex((char *)&caps->an_oemaddr, ETHER_ADDR_LEN);
377	printf("\nAironet MAC address:\t");
378	an_printhex((char *)&caps->an_aironetaddr, ETHER_ADDR_LEN);
379	printf("\nRadio type:\t\t[ ");
380	if (caps->an_radiotype & AN_RADIOTYPE_80211_FH)
381		printf("802.11 FH");
382	else if (caps->an_radiotype & AN_RADIOTYPE_80211_DS)
383		printf("802.11 DS");
384	else if (caps->an_radiotype & AN_RADIOTYPE_LM2000_DS)
385		printf("LM2000 DS");
386	else
387		printf("unknown (%x)", caps->an_radiotype);
388	printf(" ]");
389	printf("\nRegulatory domain:\t");
390	an_printwords(&caps->an_regdomain, 1);
391	printf("\nAssigned CallID:\t");
392	an_printhex((char *)&caps->an_callid, 6);
393	printf("\nSupported speeds:\t");
394	an_printspeeds(caps->an_rates, 8);
395	printf("\nRX Diversity:\t\t[ ");
396	if (caps->an_rx_diversity == AN_DIVERSITY_FACTORY_DEFAULT)
397		printf("factory default");
398	else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
399		printf("antenna 1 only");
400	else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
401		printf("antenna 2 only");
402	else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_1_AND_2)
403		printf("antenna 1 and 2");
404	printf(" ]");
405	printf("\nTX Diversity:\t\t[ ");
406	if (caps->an_tx_diversity == AN_DIVERSITY_FACTORY_DEFAULT)
407		printf("factory default");
408	else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
409		printf("antenna 1 only");
410	else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
411		printf("antenna 2 only");
412	else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_1_AND_2)
413		printf("antenna 1 and 2");
414	printf(" ]");
415	printf("\nSupported power levels:\t");
416	an_printwords(caps->an_tx_powerlevels, 8);
417	printf("\nHardware revision:\t");
418	tmp = ntohs(caps->an_hwrev);
419	an_printhex((char *)&tmp, 2);
420	printf("\nSoftware revision:\t");
421	tmp = ntohs(caps->an_fwrev);
422	an_printhex((char *)&tmp, 2);
423	printf("\nSoftware subrevision:\t");
424	tmp = ntohs(caps->an_fwsubrev);
425	an_printhex((char *)&tmp, 2);
426	printf("\nInterface revision:\t");
427	tmp = ntohs(caps->an_ifacerev);
428	an_printhex((char *)&tmp, 2);
429	printf("\nBootblock revision:\t");
430	tmp = ntohs(caps->an_bootblockrev);
431	an_printhex((char *)&tmp, 2);
432	printf("\n");
433	return;
434}
435
436static void
437an_dumpstats(const char *iface)
438{
439	struct an_ltv_stats	*stats;
440	struct an_req		areq;
441
442	areq.an_len = sizeof(areq);
443	areq.an_type = AN_RID_32BITS_CUM;
444
445	an_getval(iface, &areq);
446
447	stats = (struct an_ltv_stats *)((uint16_t *)&areq - 1);
448
449	printf("RX overruns:\t\t\t\t\t[ %u ]\n", stats->an_rx_overruns);
450	printf("RX PLCP CSUM errors:\t\t\t\t[ %u ]\n",
451	    stats->an_rx_plcp_csum_errs);
452	printf("RX PLCP format errors:\t\t\t\t[ %u ]\n",
453	    stats->an_rx_plcp_format_errs);
454	printf("RX PLCP length errors:\t\t\t\t[ %u ]\n",
455	    stats->an_rx_plcp_len_errs);
456	printf("RX MAC CRC errors:\t\t\t\t[ %u ]\n",
457	    stats->an_rx_mac_crc_errs);
458	printf("RX MAC CRC OK:\t\t\t\t\t[ %u ]\n",
459	    stats->an_rx_mac_crc_ok);
460	printf("RX WEP errors:\t\t\t\t\t[ %u ]\n",
461	    stats->an_rx_wep_errs);
462	printf("RX WEP OK:\t\t\t\t\t[ %u ]\n",
463	    stats->an_rx_wep_ok);
464	printf("Long retries:\t\t\t\t\t[ %u ]\n",
465	    stats->an_retry_long);
466	printf("Short retries:\t\t\t\t\t[ %u ]\n",
467	    stats->an_retry_short);
468	printf("Retries exhausted:\t\t\t\t[ %u ]\n",
469	    stats->an_retry_max);
470	printf("Bad ACK:\t\t\t\t\t[ %u ]\n",
471	    stats->an_no_ack);
472	printf("Bad CTS:\t\t\t\t\t[ %u ]\n",
473	    stats->an_no_cts);
474	printf("RX good ACKs:\t\t\t\t\t[ %u ]\n",
475	    stats->an_rx_ack_ok);
476	printf("RX good CTSs:\t\t\t\t\t[ %u ]\n",
477	    stats->an_rx_cts_ok);
478	printf("TX good ACKs:\t\t\t\t\t[ %u ]\n",
479	    stats->an_tx_ack_ok);
480	printf("TX good RTSs:\t\t\t\t\t[ %u ]\n",
481	    stats->an_tx_rts_ok);
482	printf("TX good CTSs:\t\t\t\t\t[ %u ]\n",
483	    stats->an_tx_cts_ok);
484	printf("LMAC multicasts transmitted:\t\t\t[ %u ]\n",
485	    stats->an_tx_lmac_mcasts);
486	printf("LMAC broadcasts transmitted:\t\t\t[ %u ]\n",
487	    stats->an_tx_lmac_bcasts);
488	printf("LMAC unicast frags transmitted:\t\t\t[ %u ]\n",
489	    stats->an_tx_lmac_ucast_frags);
490	printf("LMAC unicasts transmitted:\t\t\t[ %u ]\n",
491	    stats->an_tx_lmac_ucasts);
492	printf("Beacons transmitted:\t\t\t\t[ %u ]\n",
493	    stats->an_tx_beacons);
494	printf("Beacons received:\t\t\t\t[ %u ]\n",
495	    stats->an_rx_beacons);
496	printf("Single transmit collisions:\t\t\t[ %u ]\n",
497	    stats->an_tx_single_cols);
498	printf("Multiple transmit collisions:\t\t\t[ %u ]\n",
499	    stats->an_tx_multi_cols);
500	printf("Transmits without deferrals:\t\t\t[ %u ]\n",
501	    stats->an_tx_defers_no);
502	printf("Transmits deferred due to protocol:\t\t[ %u ]\n",
503	    stats->an_tx_defers_prot);
504	printf("Transmits deferred due to energy detect:\t\t[ %u ]\n",
505	    stats->an_tx_defers_energy);
506	printf("RX duplicate frames/frags:\t\t\t[ %u ]\n",
507	    stats->an_rx_dups);
508	printf("RX partial frames:\t\t\t\t[ %u ]\n",
509	    stats->an_rx_partial);
510	printf("TX max lifetime exceeded:\t\t\t[ %u ]\n",
511	    stats->an_tx_too_old);
512	printf("RX max lifetime exceeded:\t\t\t[ %u ]\n",
513	    stats->an_tx_too_old);
514	printf("Sync lost due to too many missed beacons:\t[ %u ]\n",
515	    stats->an_lostsync_missed_beacons);
516	printf("Sync lost due to ARL exceeded:\t\t\t[ %u ]\n",
517	    stats->an_lostsync_arl_exceeded);
518	printf("Sync lost due to deauthentication:\t\t[ %u ]\n",
519	    stats->an_lostsync_deauthed);
520	printf("Sync lost due to disassociation:\t\t[ %u ]\n",
521	    stats->an_lostsync_disassociated);
522	printf("Sync lost due to excess change in TSF timing:\t[ %u ]\n",
523	    stats->an_lostsync_tsf_timing);
524	printf("Host transmitted multicasts:\t\t\t[ %u ]\n",
525	    stats->an_tx_host_mcasts);
526	printf("Host transmitted broadcasts:\t\t\t[ %u ]\n",
527	    stats->an_tx_host_bcasts);
528	printf("Host transmitted unicasts:\t\t\t[ %u ]\n",
529	    stats->an_tx_host_ucasts);
530	printf("Host transmission failures:\t\t\t[ %u ]\n",
531	    stats->an_tx_host_failed);
532	printf("Host received multicasts:\t\t\t[ %u ]\n",
533	    stats->an_rx_host_mcasts);
534	printf("Host received broadcasts:\t\t\t[ %u ]\n",
535	    stats->an_rx_host_bcasts);
536	printf("Host received unicasts:\t\t\t\t[ %u ]\n",
537	    stats->an_rx_host_ucasts);
538	printf("Host receive discards:\t\t\t\t[ %u ]\n",
539	    stats->an_rx_host_discarded);
540	printf("HMAC transmitted multicasts:\t\t\t[ %u ]\n",
541	    stats->an_tx_hmac_mcasts);
542	printf("HMAC transmitted broadcasts:\t\t\t[ %u ]\n",
543	    stats->an_tx_hmac_bcasts);
544	printf("HMAC transmitted unicasts:\t\t\t[ %u ]\n",
545	    stats->an_tx_hmac_ucasts);
546	printf("HMAC transmissions failed:\t\t\t[ %u ]\n",
547	    stats->an_tx_hmac_failed);
548	printf("HMAC received multicasts:\t\t\t[ %u ]\n",
549	    stats->an_rx_hmac_mcasts);
550	printf("HMAC received broadcasts:\t\t\t[ %u ]\n",
551	    stats->an_rx_hmac_bcasts);
552	printf("HMAC received unicasts:\t\t\t\t[ %u ]\n",
553	    stats->an_rx_hmac_ucasts);
554	printf("HMAC receive discards:\t\t\t\t[ %u ]\n",
555	    stats->an_rx_hmac_discarded);
556	printf("HMAC transmits accepted:\t\t\t[ %u ]\n",
557	    stats->an_tx_hmac_accepted);
558	printf("SSID mismatches:\t\t\t\t[ %u ]\n",
559	    stats->an_ssid_mismatches);
560	printf("Access point mismatches:\t\t\t[ %u ]\n",
561	    stats->an_ap_mismatches);
562	printf("Speed mismatches:\t\t\t\t[ %u ]\n",
563	    stats->an_rates_mismatches);
564	printf("Authentication rejects:\t\t\t\t[ %u ]\n",
565	    stats->an_auth_rejects);
566	printf("Authentication timeouts:\t\t\t[ %u ]\n",
567	    stats->an_auth_timeouts);
568	printf("Association rejects:\t\t\t\t[ %u ]\n",
569	    stats->an_assoc_rejects);
570	printf("Association timeouts:\t\t\t\t[ %u ]\n",
571	    stats->an_assoc_timeouts);
572	printf("Management frames received:\t\t\t[ %u ]\n",
573	    stats->an_rx_mgmt_pkts);
574	printf("Management frames transmitted:\t\t\t[ %u ]\n",
575	    stats->an_tx_mgmt_pkts);
576	printf("Refresh frames received:\t\t\t[ %u ]\n",
577	    stats->an_rx_refresh_pkts),
578	printf("Refresh frames transmitted:\t\t\t[ %u ]\n",
579	    stats->an_tx_refresh_pkts),
580	printf("Poll frames received:\t\t\t\t[ %u ]\n",
581	    stats->an_rx_poll_pkts);
582	printf("Poll frames transmitted:\t\t\t[ %u ]\n",
583	    stats->an_tx_poll_pkts);
584	printf("Host requested sync losses:\t\t\t[ %u ]\n",
585	    stats->an_lostsync_hostreq);
586	printf("Host transmitted bytes:\t\t\t\t[ %u ]\n",
587	    stats->an_host_tx_bytes);
588	printf("Host received bytes:\t\t\t\t[ %u ]\n",
589	    stats->an_host_rx_bytes);
590	printf("Uptime in microseconds:\t\t\t\t[ %u ]\n",
591	    stats->an_uptime_usecs);
592	printf("Uptime in seconds:\t\t\t\t[ %u ]\n",
593	    stats->an_uptime_secs);
594	printf("Sync lost due to better AP:\t\t\t[ %u ]\n",
595	    stats->an_lostsync_better_ap);
596}
597
598static void
599an_dumpap(const char *iface)
600{
601	struct an_ltv_aplist	*ap;
602	struct an_req		areq;
603
604	areq.an_len = sizeof(areq);
605	areq.an_type = AN_RID_APLIST;
606
607	an_getval(iface, &areq);
608
609	ap = (struct an_ltv_aplist *)&areq;
610	printf("Access point 1:\t\t\t");
611	an_printhex((char *)&ap->an_ap1, ETHER_ADDR_LEN);
612	printf("\nAccess point 2:\t\t\t");
613	an_printhex((char *)&ap->an_ap2, ETHER_ADDR_LEN);
614	printf("\nAccess point 3:\t\t\t");
615	an_printhex((char *)&ap->an_ap3, ETHER_ADDR_LEN);
616	printf("\nAccess point 4:\t\t\t");
617	an_printhex((char *)&ap->an_ap4, ETHER_ADDR_LEN);
618	printf("\n");
619
620	return;
621}
622
623static void
624an_dumpssid(const char *iface)
625{
626	struct an_ltv_ssidlist_new	*ssid;
627	struct an_req		areq;
628	int			i, max;
629
630	areq.an_len = sizeof(areq);
631	areq.an_type = AN_RID_SSIDLIST;
632
633	an_getval(iface, &areq);
634
635	max = (areq.an_len - 4) / sizeof(struct an_ltv_ssid_entry);
636	if ( max > MAX_SSIDS ) {
637		printf("Too many SSIDs only printing %d of %d\n",
638		    MAX_SSIDS, max);
639		max = MAX_SSIDS;
640	}
641	ssid = (struct an_ltv_ssidlist_new *)&areq;
642	for (i = 0; i < max; i++)
643		printf("SSID %2d:\t\t\t[ %.*s ]\n", i + 1,
644		    ssid->an_entry[i].an_len,
645		    ssid->an_entry[i].an_ssid);
646
647	return;
648}
649
650static void
651an_dumpconfig(const char *iface)
652{
653	struct an_ltv_genconfig	*cfg;
654	struct an_req		areq;
655	unsigned char		diversity;
656
657	areq.an_len = sizeof(areq);
658	areq.an_type = AN_RID_ACTUALCFG;
659
660	an_getval(iface, &areq);
661
662	cfg = (struct an_ltv_genconfig *)&areq;
663
664	printf("Operating mode:\t\t\t\t[ ");
665	if ((cfg->an_opmode & 0x7) == AN_OPMODE_IBSS_ADHOC)
666		printf("ad-hoc");
667	if ((cfg->an_opmode & 0x7) == AN_OPMODE_INFRASTRUCTURE_STATION)
668		printf("infrastructure");
669	if ((cfg->an_opmode & 0x7) == AN_OPMODE_AP)
670		printf("access point");
671	if ((cfg->an_opmode & 0x7) == AN_OPMODE_AP_REPEATER)
672		printf("access point repeater");
673	printf(" ]");
674	printf("\nReceive mode:\t\t\t\t[ ");
675	if ((cfg->an_rxmode & 0x7) == AN_RXMODE_BC_MC_ADDR)
676		printf("broadcast/multicast/unicast");
677	if ((cfg->an_rxmode & 0x7) == AN_RXMODE_BC_ADDR)
678		printf("broadcast/unicast");
679	if ((cfg->an_rxmode & 0x7) == AN_RXMODE_ADDR)
680		printf("unicast");
681	if ((cfg->an_rxmode & 0x7) == AN_RXMODE_80211_MONITOR_CURBSS)
682		printf("802.11 monitor, current BSSID");
683	if ((cfg->an_rxmode & 0x7) == AN_RXMODE_80211_MONITOR_ANYBSS)
684		printf("802.11 monitor, any BSSID");
685	if ((cfg->an_rxmode & 0x7) == AN_RXMODE_LAN_MONITOR_CURBSS)
686		printf("LAN monitor, current BSSID");
687	printf(" ]");
688	printf("\nFragment threshold:\t\t\t");
689	an_printwords(&cfg->an_fragthresh, 1);
690	printf("\nRTS threshold:\t\t\t\t");
691	an_printwords(&cfg->an_rtsthresh, 1);
692	printf("\nMAC address:\t\t\t\t");
693	an_printhex((char *)&cfg->an_macaddr, ETHER_ADDR_LEN);
694	printf("\nSupported rates:\t\t\t");
695	an_printspeeds(cfg->an_rates, 8);
696	printf("\nShort retry limit:\t\t\t");
697	an_printwords(&cfg->an_shortretry_limit, 1);
698	printf("\nLong retry limit:\t\t\t");
699	an_printwords(&cfg->an_longretry_limit, 1);
700	printf("\nTX MSDU lifetime:\t\t\t");
701	an_printwords(&cfg->an_tx_msdu_lifetime, 1);
702	printf("\nRX MSDU lifetime:\t\t\t");
703	an_printwords(&cfg->an_rx_msdu_lifetime, 1);
704	printf("\nStationary:\t\t\t\t");
705	an_printbool(cfg->an_stationary);
706	printf("\nOrdering:\t\t\t\t");
707	an_printbool(cfg->an_ordering);
708	printf("\nDevice type:\t\t\t\t[ ");
709	if (cfg->an_devtype == AN_DEVTYPE_PC4500)
710		printf("PC4500");
711	else if (cfg->an_devtype == AN_DEVTYPE_PC4800)
712		printf("PC4800");
713	else
714		printf("unknown (%x)", cfg->an_devtype);
715	printf(" ]");
716	printf("\nScanning mode:\t\t\t\t[ ");
717	if (cfg->an_scanmode == AN_SCANMODE_ACTIVE)
718		printf("active");
719	if (cfg->an_scanmode == AN_SCANMODE_PASSIVE)
720		printf("passive");
721	if (cfg->an_scanmode == AN_SCANMODE_AIRONET_ACTIVE)
722		printf("Aironet active");
723	printf(" ]");
724	printf("\nProbe delay:\t\t\t\t");
725	an_printwords(&cfg->an_probedelay, 1);
726	printf("\nProbe energy timeout:\t\t\t");
727	an_printwords(&cfg->an_probe_energy_timeout, 1);
728	printf("\nProbe response timeout:\t\t\t");
729	an_printwords(&cfg->an_probe_response_timeout, 1);
730	printf("\nBeacon listen timeout:\t\t\t");
731	an_printwords(&cfg->an_beacon_listen_timeout, 1);
732	printf("\nIBSS join network timeout:\t\t");
733	an_printwords(&cfg->an_ibss_join_net_timeout, 1);
734	printf("\nAuthentication timeout:\t\t\t");
735	an_printwords(&cfg->an_auth_timeout, 1);
736	printf("\nWEP enabled:\t\t\t\t[ ");
737	if (cfg->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE)
738	{
739		if (cfg->an_authtype & AN_AUTHTYPE_LEAP)
740			 printf("LEAP");
741		else if (cfg->an_authtype & AN_AUTHTYPE_ALLOW_UNENCRYPTED)
742			 printf("mixed cell");
743		else
744			 printf("full");
745	}
746	else
747		printf("no");
748	printf(" ]");
749	printf("\nAuthentication type:\t\t\t[ ");
750	if ((cfg->an_authtype & AN_AUTHTYPE_MASK) == AN_AUTHTYPE_NONE)
751		printf("none");
752	if ((cfg->an_authtype & AN_AUTHTYPE_MASK) == AN_AUTHTYPE_OPEN)
753		printf("open");
754	if ((cfg->an_authtype & AN_AUTHTYPE_MASK) == AN_AUTHTYPE_SHAREDKEY)
755		printf("shared key");
756	printf(" ]");
757	printf("\nAssociation timeout:\t\t\t");
758	an_printwords(&cfg->an_assoc_timeout, 1);
759	printf("\nSpecified AP association timeout:\t");
760	an_printwords(&cfg->an_specified_ap_timeout, 1);
761	printf("\nOffline scan interval:\t\t\t");
762	an_printwords(&cfg->an_offline_scan_interval, 1);
763	printf("\nOffline scan duration:\t\t\t");
764	an_printwords(&cfg->an_offline_scan_duration, 1);
765	printf("\nLink loss delay:\t\t\t");
766	an_printwords(&cfg->an_link_loss_delay, 1);
767	printf("\nMax beacon loss time:\t\t\t");
768	an_printwords(&cfg->an_max_beacon_lost_time, 1);
769	printf("\nRefresh interval:\t\t\t");
770	an_printwords(&cfg->an_refresh_interval, 1);
771	printf("\nPower save mode:\t\t\t[ ");
772	if (cfg->an_psave_mode == AN_PSAVE_NONE)
773		printf("none");
774	if (cfg->an_psave_mode == AN_PSAVE_CAM)
775		printf("constantly awake mode");
776	if (cfg->an_psave_mode == AN_PSAVE_PSP)
777		printf("PSP");
778	if (cfg->an_psave_mode == AN_PSAVE_PSP_CAM)
779		printf("PSP-CAM (fast PSP)");
780	printf(" ]");
781	printf("\nSleep through DTIMs:\t\t\t");
782	an_printbool(cfg->an_sleep_for_dtims);
783	printf("\nPower save listen interval:\t\t");
784	an_printwords(&cfg->an_listen_interval, 1);
785	printf("\nPower save fast listen interval:\t");
786	an_printwords(&cfg->an_fast_listen_interval, 1);
787	printf("\nPower save listen decay:\t\t");
788	an_printwords(&cfg->an_listen_decay, 1);
789	printf("\nPower save fast listen decay:\t\t");
790	an_printwords(&cfg->an_fast_listen_decay, 1);
791	printf("\nAP/ad-hoc Beacon period:\t\t");
792	an_printwords(&cfg->an_beacon_period, 1);
793	printf("\nAP/ad-hoc ATIM duration:\t\t");
794	an_printwords(&cfg->an_atim_duration, 1);
795	printf("\nAP/ad-hoc current channel:\t\t");
796	an_printwords(&cfg->an_ds_channel, 1);
797	printf("\nAP/ad-hoc DTIM period:\t\t\t");
798	an_printwords(&cfg->an_dtim_period, 1);
799	printf("\nRadio type:\t\t\t\t[ ");
800	if (cfg->an_radiotype & AN_RADIOTYPE_80211_FH)
801		printf("802.11 FH");
802	else if (cfg->an_radiotype & AN_RADIOTYPE_80211_DS)
803		printf("802.11 DS");
804	else if (cfg->an_radiotype & AN_RADIOTYPE_LM2000_DS)
805		printf("LM2000 DS");
806	else
807		printf("unknown (%x)", cfg->an_radiotype);
808	printf(" ]");
809	printf("\nRX Diversity:\t\t\t\t[ ");
810	diversity = cfg->an_diversity & 0xFF;
811	if (diversity == AN_DIVERSITY_FACTORY_DEFAULT)
812		printf("factory default");
813	else if (diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
814		printf("antenna 1 only");
815	else if (diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
816		printf("antenna 2 only");
817	else if (diversity == AN_DIVERSITY_ANTENNA_1_AND_2)
818		printf("antenna 1 and 2");
819	printf(" ]");
820	printf("\nTX Diversity:\t\t\t\t[ ");
821	diversity = (cfg->an_diversity >> 8) & 0xFF;
822	if (diversity == AN_DIVERSITY_FACTORY_DEFAULT)
823		printf("factory default");
824	else if (diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
825		printf("antenna 1 only");
826	else if (diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
827		printf("antenna 2 only");
828	else if (diversity == AN_DIVERSITY_ANTENNA_1_AND_2)
829		printf("antenna 1 and 2");
830	printf(" ]");
831	printf("\nTransmit power level:\t\t\t");
832	an_printwords(&cfg->an_tx_power, 1);
833	printf("\nRSS threshold:\t\t\t\t");
834	an_printwords(&cfg->an_rss_thresh, 1);
835	printf("\nNode name:\t\t\t\t");
836	an_printstr((char *)&cfg->an_nodename, 16);
837	printf("\nARL threshold:\t\t\t\t");
838	an_printwords(&cfg->an_arl_thresh, 1);
839	printf("\nARL decay:\t\t\t\t");
840	an_printwords(&cfg->an_arl_decay, 1);
841	printf("\nARL delay:\t\t\t\t");
842	an_printwords(&cfg->an_arl_delay, 1);
843	printf("\nConfiguration:\t\t\t\t[ ");
844	if (cfg->an_home_product & AN_HOME_NETWORK)
845		printf("Home Configuration");
846	else
847		printf("Enterprise Configuration");
848	printf(" ]");
849
850	printf("\n");
851	printf("\n");
852	an_readkeyinfo(iface);
853}
854
855static void
856an_dumprssimap(const char *iface)
857{
858	struct an_ltv_rssi_map	*rssi;
859	struct an_req		areq;
860	int                     i;
861
862	areq.an_len = sizeof(areq);
863	areq.an_type = AN_RID_RSSI_MAP;
864
865	an_getval(iface, &areq);
866
867	rssi = (struct an_ltv_rssi_map *)&areq;
868
869	printf("idx\tpct\t dBm\n");
870
871	for (i = 0; i < 0xFF; i++) {
872		/*
873		 * negate the dBm value: it's the only way the power
874		 * level makes sense
875		 */
876		printf("%3d\t%3d\t%4d\n", i,
877			rssi->an_entries[i].an_rss_pct,
878			- rssi->an_entries[i].an_rss_dbm);
879	}
880}
881
882static void
883usage(const char *p)
884{
885	fprintf(stderr, "usage:  %s -i iface -A (show specified APs)\n", p);
886	fprintf(stderr, "\t%s -i iface -N (show specified SSIDss)\n", p);
887	fprintf(stderr, "\t%s -i iface -S (show NIC status)\n", p);
888	fprintf(stderr, "\t%s -i iface -I (show NIC capabilities)\n", p);
889	fprintf(stderr, "\t%s -i iface -T (show stats counters)\n", p);
890	fprintf(stderr, "\t%s -i iface -C (show current config)\n", p);
891	fprintf(stderr, "\t%s -i iface -R (show RSSI map)\n", p);
892	fprintf(stderr, "\t%s -i iface -t 0-4 (set TX speed)\n", p);
893	fprintf(stderr, "\t%s -i iface -s 0-3 (set power save mode)\n", p);
894	fprintf(stderr, "\t%s -i iface [-v 1-4] -a AP (specify AP)\n", p);
895	fprintf(stderr, "\t%s -i iface -b val (set beacon period)\n", p);
896	fprintf(stderr, "\t%s -i iface [-v 0|1] -d val (set diversity)\n", p);
897	fprintf(stderr, "\t%s -i iface -j val (set netjoin timeout)\n", p);
898	fprintf(stderr, "\t%s -i iface -e 0-4 (enable transmit key)\n", p);
899	fprintf(stderr, "\t%s -i iface [-v 0-8] -k key (set key)\n", p);
900	fprintf(stderr, "\t%s -i iface -K 0-2 (no auth/open/shared secret)\n", p);
901	fprintf(stderr, "\t%s -i iface -W 0-2 (no WEP/full WEP/mixed cell)\n", p);
902	fprintf(stderr, "\t%s -i iface -l val (set station name)\n", p);
903	fprintf(stderr, "\t%s -i iface -m val (set MAC address)\n", p);
904	fprintf(stderr, "\t%s -i iface [-v 1-3] -n SSID "
905	    "(specify SSID)\n", p);
906	fprintf(stderr, "\t%s -i iface -o 0|1 (set operating mode)\n", p);
907	fprintf(stderr, "\t%s -i iface -c val (set ad-hoc channel)\n", p);
908	fprintf(stderr, "\t%s -i iface -f val (set frag threshold)\n", p);
909	fprintf(stderr, "\t%s -i iface -r val (set RTS threshold)\n", p);
910	fprintf(stderr, "\t%s -i iface -M 0-15 (set monitor mode)\n", p);
911	fprintf(stderr, "\t%s -i iface -L user (enter LEAP authentication mode)\n", p);
912#ifdef ANCACHE
913	fprintf(stderr, "\t%s -i iface -Q print signal quality cache\n", p);
914	fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p);
915#endif
916
917	fprintf(stderr, "\t%s -h (display this message)\n", p);
918
919	exit(1);
920}
921
922static void
923an_setconfig(const char *iface, int act, void *arg)
924{
925	struct an_ltv_genconfig	*cfg;
926	struct an_ltv_caps	*caps;
927	struct an_req		areq;
928	struct an_req		areq_caps;
929	u_int16_t		diversity = 0;
930	struct ether_addr	*addr;
931	int			i;
932
933	areq.an_len = sizeof(areq);
934	areq.an_type = AN_RID_GENCONFIG;
935	an_getval(iface, &areq);
936	cfg = (struct an_ltv_genconfig *)&areq;
937
938	areq_caps.an_len = sizeof(areq);
939	areq_caps.an_type = AN_RID_CAPABILITIES;
940	an_getval(iface, &areq_caps);
941	caps = (struct an_ltv_caps *)&areq_caps;
942
943	switch(act) {
944	case ACT_SET_OPMODE:
945		cfg->an_opmode = atoi(arg);
946		break;
947	case ACT_SET_FREQ:
948		cfg->an_ds_channel = atoi(arg);
949		break;
950	case ACT_SET_PWRSAVE:
951		cfg->an_psave_mode = atoi(arg);
952		break;
953	case ACT_SET_SCANMODE:
954		cfg->an_scanmode = atoi(arg);
955		break;
956	case ACT_SET_DIVERSITY_RX:
957	case ACT_SET_DIVERSITY_TX:
958		switch(atoi(arg)) {
959		case 0:
960			diversity = AN_DIVERSITY_FACTORY_DEFAULT;
961			break;
962		case 1:
963			diversity = AN_DIVERSITY_ANTENNA_1_ONLY;
964			break;
965		case 2:
966			diversity = AN_DIVERSITY_ANTENNA_2_ONLY;
967			break;
968		case 3:
969			diversity = AN_DIVERSITY_ANTENNA_1_AND_2;
970			break;
971		default:
972			errx(1, "bad diversity setting: %u", diversity);
973			break;
974		}
975		if (act == ACT_SET_DIVERSITY_RX) {
976			cfg->an_diversity &= 0xFF00;
977			cfg->an_diversity |= diversity;
978		} else {
979			cfg->an_diversity &= 0x00FF;
980			cfg->an_diversity |= (diversity << 8);
981		}
982		break;
983	case ACT_SET_TXPWR:
984		for (i = 0; i < 8; i++) {
985			if (caps->an_tx_powerlevels[i] == atoi(arg))
986				break;
987		}
988		if (i == 8)
989			errx(1, "unsupported power level: %dmW", atoi(arg));
990
991		cfg->an_tx_power = atoi(arg);
992		break;
993	case ACT_SET_RTS_THRESH:
994		cfg->an_rtsthresh = atoi(arg);
995		break;
996	case ACT_SET_RTS_RETRYLIM:
997		cfg->an_shortretry_limit =
998		   cfg->an_longretry_limit = atoi(arg);
999		break;
1000	case ACT_SET_BEACON_PERIOD:
1001		cfg->an_beacon_period = atoi(arg);
1002		break;
1003	case ACT_SET_WAKE_DURATION:
1004		cfg->an_atim_duration = atoi(arg);
1005		break;
1006	case ACT_SET_FRAG_THRESH:
1007		cfg->an_fragthresh = atoi(arg);
1008		break;
1009	case ACT_SET_NETJOIN:
1010		cfg->an_ibss_join_net_timeout = atoi(arg);
1011		break;
1012	case ACT_SET_MYNAME:
1013		bzero(cfg->an_nodename, 16);
1014		strncpy((char *)&cfg->an_nodename, optarg, 16);
1015		break;
1016	case ACT_SET_MAC:
1017		addr = ether_aton((char *)arg);
1018
1019		if (addr == NULL)
1020			errx(1, "badly formatted address");
1021		bzero(cfg->an_macaddr, ETHER_ADDR_LEN);
1022		bcopy(addr, &cfg->an_macaddr, ETHER_ADDR_LEN);
1023		break;
1024	case ACT_ENABLE_WEP:
1025		switch (atoi (arg)) {
1026		case 0:
1027			/* no WEP */
1028			cfg->an_authtype &= ~(AN_AUTHTYPE_PRIVACY_IN_USE
1029					| AN_AUTHTYPE_ALLOW_UNENCRYPTED
1030					| AN_AUTHTYPE_LEAP);
1031			break;
1032		case 1:
1033			/* full WEP */
1034			cfg->an_authtype |= AN_AUTHTYPE_PRIVACY_IN_USE;
1035			cfg->an_authtype &= ~AN_AUTHTYPE_ALLOW_UNENCRYPTED;
1036			cfg->an_authtype &= ~AN_AUTHTYPE_LEAP;
1037			break;
1038		case 2:
1039			/* mixed cell */
1040			cfg->an_authtype = AN_AUTHTYPE_PRIVACY_IN_USE
1041					| AN_AUTHTYPE_ALLOW_UNENCRYPTED;
1042			break;
1043		}
1044		break;
1045	case ACT_SET_KEY_TYPE:
1046		cfg->an_authtype = (cfg->an_authtype & ~AN_AUTHTYPE_MASK)
1047		        | atoi(arg);
1048		break;
1049	case ACT_SET_MONITOR_MODE:
1050		areq.an_type = AN_RID_MONITOR_MODE;
1051		cfg->an_len = atoi(arg);      /* mode is put in length */
1052		break;
1053	default:
1054		errx(1, "unknown action");
1055		break;
1056	}
1057
1058	an_setval(iface, &areq);
1059	exit(0);
1060}
1061
1062static void
1063an_setspeed(const char *iface, int act __unused, void *arg)
1064{
1065	struct an_req		areq;
1066	struct an_ltv_caps	*caps;
1067	u_int16_t		speed;
1068
1069	areq.an_len = sizeof(areq);
1070	areq.an_type = AN_RID_CAPABILITIES;
1071
1072	an_getval(iface, &areq);
1073	caps = (struct an_ltv_caps *)&areq;
1074
1075	switch(atoi(arg)) {
1076	case 0:
1077		speed = 0;
1078		break;
1079	case 1:
1080		speed = AN_RATE_1MBPS;
1081		break;
1082	case 2:
1083		speed = AN_RATE_2MBPS;
1084		break;
1085	case 3:
1086		if (caps->an_rates[2] != AN_RATE_5_5MBPS)
1087			errx(1, "5.5Mbps not supported on this card");
1088		speed = AN_RATE_5_5MBPS;
1089		break;
1090	case 4:
1091		if (caps->an_rates[3] != AN_RATE_11MBPS)
1092			errx(1, "11Mbps not supported on this card");
1093		speed = AN_RATE_11MBPS;
1094		break;
1095	default:
1096		errx(1, "unsupported speed");
1097		break;
1098	}
1099
1100	areq.an_len = 6;
1101	areq.an_type = AN_RID_TX_SPEED;
1102	areq.an_val[0] = speed;
1103
1104	an_setval(iface, &areq);
1105	exit(0);
1106}
1107
1108static void
1109an_setap(const char *iface, int act, void *arg)
1110{
1111	struct an_ltv_aplist	*ap;
1112	struct an_req		areq;
1113	struct ether_addr	*addr;
1114
1115	areq.an_len = sizeof(areq);
1116	areq.an_type = AN_RID_APLIST;
1117
1118	an_getval(iface, &areq);
1119	ap = (struct an_ltv_aplist *)&areq;
1120
1121	addr = ether_aton((char *)arg);
1122
1123	if (addr == NULL)
1124		errx(1, "badly formatted address");
1125
1126	switch(act) {
1127	case ACT_SET_AP1:
1128		bzero(ap->an_ap1, ETHER_ADDR_LEN);
1129		bcopy(addr, &ap->an_ap1, ETHER_ADDR_LEN);
1130		break;
1131	case ACT_SET_AP2:
1132		bzero(ap->an_ap2, ETHER_ADDR_LEN);
1133		bcopy(addr, &ap->an_ap2, ETHER_ADDR_LEN);
1134		break;
1135	case ACT_SET_AP3:
1136		bzero(ap->an_ap3, ETHER_ADDR_LEN);
1137		bcopy(addr, &ap->an_ap3, ETHER_ADDR_LEN);
1138		break;
1139	case ACT_SET_AP4:
1140		bzero(ap->an_ap4, ETHER_ADDR_LEN);
1141		bcopy(addr, &ap->an_ap4, ETHER_ADDR_LEN);
1142		break;
1143	default:
1144		errx(1, "unknown action");
1145		break;
1146	}
1147
1148	an_setval(iface, &areq);
1149	exit(0);
1150}
1151
1152static void
1153an_setssid(const char *iface, int act, void *arg)
1154{
1155	struct an_ltv_ssidlist_new	*ssid;
1156	struct an_req		areq;
1157	int			max;
1158
1159	areq.an_len = sizeof(areq);
1160	areq.an_type = AN_RID_SSIDLIST;
1161
1162	an_getval(iface, &areq);
1163	ssid = (struct an_ltv_ssidlist_new *)&areq;
1164
1165	max = (areq.an_len - 4) / sizeof(struct an_ltv_ssid_entry);
1166	if ( max > MAX_SSIDS ) {
1167		printf("Too many SSIDs only printing %d of %d\n",
1168		    MAX_SSIDS, max);
1169		max = MAX_SSIDS;
1170	}
1171
1172	if ( act > max ) {
1173		errx(1, "bad modifier %d: there "
1174		    "are only %d SSID settings", act, max);
1175		exit(1);
1176	}
1177
1178	bzero(ssid->an_entry[act-1].an_ssid,
1179	    sizeof(ssid->an_entry[act-1].an_ssid));
1180	strlcpy(ssid->an_entry[act-1].an_ssid, (char *)arg,
1181	    sizeof(ssid->an_entry[act-1].an_ssid));
1182	ssid->an_entry[act-1].an_len
1183	    = strlen(ssid->an_entry[act-1].an_ssid);
1184
1185	an_setval(iface, &areq);
1186
1187	exit(0);
1188}
1189
1190#ifdef ANCACHE
1191static void
1192an_zerocache(const char *iface)
1193{
1194	struct an_req		areq;
1195
1196	bzero(&areq, sizeof(areq));
1197	areq.an_len = 0;
1198	areq.an_type = AN_RID_ZERO_CACHE;
1199
1200	an_getval(iface, &areq);
1201}
1202
1203static void
1204an_readcache(const char *iface)
1205{
1206	struct an_req		areq;
1207	uint16_t 		*an_sigitems;
1208	struct an_sigcache 	*sc;
1209	int 			i;
1210
1211	if (iface == NULL)
1212		errx(1, "must specify interface name");
1213
1214	bzero(&areq, sizeof(areq));
1215	areq.an_len = AN_MAX_DATALEN;
1216	areq.an_type = AN_RID_READ_CACHE;
1217
1218	an_getval(iface, &areq);
1219
1220	an_sigitems = areq.an_val;
1221	sc = (struct an_sigcache *)((int32_t *)areq.an_val + 1);
1222
1223	for (i = 0; i < *an_sigitems; i++) {
1224		printf("[%d/%d]:", i+1, *an_sigitems);
1225		printf(" %02x:%02x:%02x:%02x:%02x:%02x,",
1226		  		    	sc->macsrc[0]&0xff,
1227		  		    	sc->macsrc[1]&0xff,
1228		   		    	sc->macsrc[2]&0xff,
1229		   			sc->macsrc[3]&0xff,
1230		   			sc->macsrc[4]&0xff,
1231		   			sc->macsrc[5]&0xff);
1232        	printf(" %d.%d.%d.%d,",((sc->ipsrc >> 0) & 0xff),
1233				        ((sc->ipsrc >> 8) & 0xff),
1234				        ((sc->ipsrc >> 16) & 0xff),
1235				        ((sc->ipsrc >> 24) & 0xff));
1236		printf(" sig: %d, noise: %d, qual: %d\n",
1237		   			sc->signal,
1238		   			sc->noise,
1239		   			sc->quality);
1240		sc++;
1241	}
1242}
1243#endif
1244
1245static int
1246an_hex2int(char c)
1247{
1248	if (c >= '0' && c <= '9')
1249		return (c - '0');
1250	if (c >= 'A' && c <= 'F')
1251		return (c - 'A' + 10);
1252	if (c >= 'a' && c <= 'f')
1253		return (c - 'a' + 10);
1254
1255	return (0);
1256}
1257
1258static void
1259an_str2key(const char *s, struct an_ltv_key *k)
1260{
1261	int			n, i;
1262	char			*p;
1263
1264	/* Is this a hex string? */
1265	if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
1266		/* Yes, convert to int. */
1267		n = 0;
1268		p = (char *)&k->key[0];
1269		for (i = 2; s[i] != '\0' && s[i + 1] != '\0'; i+= 2) {
1270			*p++ = (an_hex2int(s[i]) << 4) + an_hex2int(s[i + 1]);
1271			n++;
1272		}
1273		if (s[i] != '\0')
1274			errx(1, "hex strings must be of even length");
1275		k->klen = n;
1276	} else {
1277		/* No, just copy it in. */
1278		bcopy(s, k->key, strlen(s));
1279		k->klen = strlen(s);
1280	}
1281
1282	return;
1283}
1284
1285static void
1286an_setkeys(const char *iface, const char *key, int keytype)
1287{
1288	struct an_req		areq;
1289	struct an_ltv_key	*k;
1290
1291	bzero(&areq, sizeof(areq));
1292	k = (struct an_ltv_key *)&areq;
1293
1294	if (strlen(key) > 28) {
1295		err(1, "encryption key must be no "
1296		    "more than 18 characters long");
1297	}
1298
1299	an_str2key(key, k);
1300
1301	k->kindex=keytype/2;
1302
1303	if (!(k->klen==0 || k->klen==5 || k->klen==13)) {
1304		err(1, "encryption key must be 0, 5 or 13 bytes long");
1305	}
1306
1307	/* default mac and only valid one (from manual) 1.0.0.0.0.0 */
1308	k->mac[0]=1;
1309	k->mac[1]=0;
1310	k->mac[2]=0;
1311	k->mac[3]=0;
1312	k->mac[4]=0;
1313	k->mac[5]=0;
1314
1315	switch(keytype & 1) {
1316	case 0:
1317	  areq.an_len = sizeof(struct an_ltv_key);
1318	  areq.an_type = AN_RID_WEP_PERM;
1319	  an_setval(iface, &areq);
1320	  break;
1321	case 1:
1322	  areq.an_len = sizeof(struct an_ltv_key);
1323	  areq.an_type = AN_RID_WEP_TEMP;
1324	  an_setval(iface, &areq);
1325	  break;
1326	}
1327}
1328
1329static void
1330an_readkeyinfo(const char *iface)
1331{
1332	struct an_req		areq;
1333	struct an_ltv_genconfig	*cfg;
1334	struct an_ltv_key	*k;
1335	int i;
1336	int home;
1337
1338	areq.an_len = sizeof(areq);
1339	areq.an_type = AN_RID_ACTUALCFG;
1340	an_getval(iface, &areq);
1341	cfg = (struct an_ltv_genconfig *)&areq;
1342	if (cfg->an_home_product & AN_HOME_NETWORK)
1343		home = 1;
1344	else
1345		home = 0;
1346
1347	bzero(&areq, sizeof(areq));
1348	k = (struct an_ltv_key *)&areq;
1349
1350	printf("WEP Key status:\n");
1351	areq.an_type = AN_RID_WEP_TEMP;  	/* read first key */
1352	for(i=0; i<5; i++) {
1353		areq.an_len = sizeof(struct an_ltv_key);
1354		an_getval(iface, &areq);
1355       		if (k->kindex == 0xffff)
1356			break;
1357		switch (k->klen) {
1358		case 0:
1359			printf("\tKey %u is unset\n", k->kindex);
1360			break;
1361		case 5:
1362			printf("\tKey %u is set  40 bits\n", k->kindex);
1363			break;
1364		case 13:
1365			printf("\tKey %u is set 128 bits\n", k->kindex);
1366			break;
1367		default:
1368			printf("\tWEP Key %d has an unknown size %u\n",
1369			    i, k->klen);
1370		}
1371
1372		areq.an_type = AN_RID_WEP_PERM;	/* read next key */
1373	}
1374	k->kindex = 0xffff;
1375	areq.an_len = sizeof(struct an_ltv_key);
1376      	an_getval(iface, &areq);
1377	printf("\tThe active transmit key is %d\n", 4 * home + k->mac[0]);
1378
1379	return;
1380}
1381
1382static void
1383an_enable_tx_key(const char *iface, const char *arg)
1384{
1385	struct an_req		areq;
1386	struct an_ltv_key	*k;
1387	struct an_ltv_genconfig *config;
1388
1389	bzero(&areq, sizeof(areq));
1390
1391	/* set home or not home mode */
1392	areq.an_len  = sizeof(struct an_ltv_genconfig);
1393	areq.an_type = AN_RID_GENCONFIG;
1394	an_getval(iface, &areq);
1395	config = (struct an_ltv_genconfig *)&areq;
1396	if (atoi(arg) == 4) {
1397		config->an_home_product |= AN_HOME_NETWORK;
1398	}else{
1399		config->an_home_product &= ~AN_HOME_NETWORK;
1400	}
1401	an_setval(iface, &areq);
1402
1403	bzero(&areq, sizeof(areq));
1404
1405	k = (struct an_ltv_key *)&areq;
1406
1407	/* From a Cisco engineer write the transmit key to use in the
1408	   first MAC, index is FFFF*/
1409	k->kindex=0xffff;
1410	k->klen=0;
1411
1412	k->mac[0]=atoi(arg);
1413	k->mac[1]=0;
1414	k->mac[2]=0;
1415	k->mac[3]=0;
1416	k->mac[4]=0;
1417	k->mac[5]=0;
1418
1419	areq.an_len = sizeof(struct an_ltv_key);
1420	areq.an_type = AN_RID_WEP_PERM;
1421	an_setval(iface, &areq);
1422}
1423
1424static void
1425an_enable_leap_mode(const char *iface, const char *username)
1426{
1427	struct an_req		areq;
1428	struct an_ltv_status	*sts;
1429	struct an_ltv_genconfig	*cfg;
1430	struct an_ltv_caps	*caps;
1431	struct an_ltv_leap_username an_username;
1432	struct an_ltv_leap_password an_password;
1433	char *password;
1434	MD4_CTX context;
1435	int len;
1436	int i;
1437	char unicode_password[LEAP_PASSWORD_MAX * 2];
1438
1439	areq.an_len = sizeof(areq);
1440	areq.an_type = AN_RID_CAPABILITIES;
1441
1442	an_getval(iface, &areq);
1443
1444	caps = (struct an_ltv_caps *)&areq;
1445
1446	if (!(caps->an_softcaps & AN_AUTHTYPE_LEAP)) {
1447		fprintf(stderr, "Firmware does not support LEAP\n");
1448		exit(1);
1449	}
1450
1451	bzero(&an_username, sizeof(an_username));
1452	bzero(&an_password, sizeof(an_password));
1453
1454	len = strlen(username);
1455	if (len > LEAP_USERNAME_MAX) {
1456		printf("Username too long (max %d)\n", LEAP_USERNAME_MAX);
1457		exit(1);
1458	}
1459	strncpy(an_username.an_username, username, len);
1460	an_username.an_username_len = len;
1461	an_username.an_len  = sizeof(an_username);
1462	an_username.an_type = AN_RID_LEAPUSERNAME;
1463
1464	password = getpass("Enter LEAP password:");
1465
1466	len = strlen(password);
1467	if (len > LEAP_PASSWORD_MAX) {
1468		printf("Password too long (max %d)\n", LEAP_PASSWORD_MAX);
1469		exit(1);
1470	}
1471
1472	bzero(&unicode_password, sizeof(unicode_password));
1473	for(i = 0; i < len; i++) {
1474		unicode_password[i * 2] = *password++;
1475	}
1476
1477	/* First half */
1478	MD4Init(&context);
1479	MD4Update(&context, unicode_password, len * 2);
1480	MD4Final(&an_password.an_password[0], &context);
1481
1482	/* Second half */
1483	MD4Init (&context);
1484	MD4Update (&context, &an_password.an_password[0], 16);
1485	MD4Final (&an_password.an_password[16], &context);
1486
1487	an_password.an_password_len = 32;
1488	an_password.an_len  = sizeof(an_password);
1489	an_password.an_type = AN_RID_LEAPPASSWORD;
1490
1491	an_setval(iface, (struct an_req *)&an_username);
1492	an_setval(iface, (struct an_req *)&an_password);
1493
1494	areq.an_len = sizeof(areq);
1495	areq.an_type = AN_RID_GENCONFIG;
1496	an_getval(iface, &areq);
1497	cfg = (struct an_ltv_genconfig *)&areq;
1498	cfg->an_authtype = (AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_LEAP);
1499	an_setval(iface, &areq);
1500
1501	sts = (struct an_ltv_status *)&areq;
1502	areq.an_type = AN_RID_STATUS;
1503
1504	for (i = 60; i > 0; i--) {
1505		an_getval(iface, &areq);
1506		if (sts->an_opmode & AN_STATUS_OPMODE_LEAP) {
1507			printf("Authenticated\n");
1508			break;
1509		}
1510		sleep(1);
1511	}
1512
1513	if (i == 0) {
1514		fprintf(stderr, "Failed LEAP authentication\n");
1515		exit(1);
1516	}
1517}
1518
1519int
1520main(int argc, char *argv[])
1521{
1522	int			ch;
1523	int			act = 0;
1524	const char		*iface = NULL;
1525	int			modifier = 0;
1526	char			*key = NULL;
1527	void			*arg = NULL;
1528	char			*p = argv[0];
1529
1530	/* Get the interface name */
1531	opterr = 0;
1532	ch = getopt(argc, argv, "i:");
1533	if (ch == 'i') {
1534		iface = optarg;
1535	} else {
1536		if (argc > 1 && *argv[1] != '-') {
1537			iface = argv[1];
1538			optind = 2;
1539		} else {
1540			iface = "an0";
1541			optind = 1;
1542		}
1543		optreset = 1;
1544	}
1545	opterr = 1;
1546
1547	while ((ch = getopt(argc, argv,
1548	    "ANISCTRht:a:e:o:s:n:v:d:j:b:c:f:r:p:w:m:l:k:K:W:QZM:L:")) != -1) {
1549		switch(ch) {
1550		case 'Z':
1551#ifdef ANCACHE
1552			act = ACT_ZEROCACHE;
1553#else
1554			errx(1, "ANCACHE not available");
1555#endif
1556			break;
1557		case 'Q':
1558#ifdef ANCACHE
1559			act = ACT_DUMPCACHE;
1560#else
1561			errx(1, "ANCACHE not available");
1562#endif
1563			break;
1564		case 'A':
1565			act = ACT_DUMPAP;
1566			break;
1567		case 'N':
1568			act = ACT_DUMPSSID;
1569			break;
1570		case 'S':
1571			act = ACT_DUMPSTATUS;
1572			break;
1573		case 'I':
1574			act = ACT_DUMPCAPS;
1575			break;
1576		case 'T':
1577			act = ACT_DUMPSTATS;
1578			break;
1579		case 'C':
1580			act = ACT_DUMPCONFIG;
1581			break;
1582		case 'R':
1583			act = ACT_DUMPRSSIMAP;
1584			break;
1585		case 't':
1586			act = ACT_SET_TXRATE;
1587			arg = optarg;
1588			break;
1589		case 's':
1590			act = ACT_SET_PWRSAVE;
1591			arg = optarg;
1592			break;
1593		case 'p':
1594			act = ACT_SET_TXPWR;
1595			arg = optarg;
1596			break;
1597		case 'v':
1598			modifier = atoi(optarg);
1599			break;
1600		case 'a':
1601			switch(modifier) {
1602			case 0:
1603			case 1:
1604				act = ACT_SET_AP1;
1605				break;
1606			case 2:
1607				act = ACT_SET_AP2;
1608				break;
1609			case 3:
1610				act = ACT_SET_AP3;
1611				break;
1612			case 4:
1613				act = ACT_SET_AP4;
1614				break;
1615			default:
1616				errx(1, "bad modifier %d: there "
1617				    "are only 4 access point settings",
1618				    modifier);
1619				usage(p);
1620				break;
1621			}
1622			arg = optarg;
1623			break;
1624		case 'b':
1625			act = ACT_SET_BEACON_PERIOD;
1626			arg = optarg;
1627			break;
1628		case 'd':
1629			switch(modifier) {
1630			case 0:
1631				act = ACT_SET_DIVERSITY_RX;
1632				break;
1633			case 1:
1634				act = ACT_SET_DIVERSITY_TX;
1635				break;
1636			default:
1637				errx(1, "must specify RX or TX diversity");
1638				break;
1639			}
1640			if (!isdigit(*optarg)) {
1641				errx(1, "%s is not numeric", optarg);
1642				exit(1);
1643			}
1644			arg = optarg;
1645			break;
1646		case 'j':
1647			act = ACT_SET_NETJOIN;
1648			arg = optarg;
1649			break;
1650		case 'l':
1651			act = ACT_SET_MYNAME;
1652			arg = optarg;
1653			break;
1654		case 'm':
1655			act = ACT_SET_MAC;
1656			arg = optarg;
1657			break;
1658		case 'n':
1659			if (modifier == 0)
1660				modifier = 1;
1661			act = ACT_SET_SSID;
1662			arg = optarg;
1663			break;
1664		case 'o':
1665			act = ACT_SET_OPMODE;
1666			arg = optarg;
1667			break;
1668		case 'c':
1669			act = ACT_SET_FREQ;
1670			arg = optarg;
1671			break;
1672		case 'f':
1673			act = ACT_SET_FRAG_THRESH;
1674			arg = optarg;
1675			break;
1676		case 'W':
1677			act = ACT_ENABLE_WEP;
1678			arg = optarg;
1679			break;
1680		case 'K':
1681			act = ACT_SET_KEY_TYPE;
1682			arg = optarg;
1683			break;
1684		case 'k':
1685			act = ACT_SET_KEYS;
1686			key = optarg;
1687			break;
1688		case 'e':
1689			act = ACT_ENABLE_TX_KEY;
1690			arg = optarg;
1691			break;
1692		case 'q':
1693			act = ACT_SET_RTS_RETRYLIM;
1694			arg = optarg;
1695			break;
1696		case 'r':
1697			act = ACT_SET_RTS_THRESH;
1698			arg = optarg;
1699			break;
1700		case 'w':
1701			act = ACT_SET_WAKE_DURATION;
1702			arg = optarg;
1703			break;
1704		case 'M':
1705			act = ACT_SET_MONITOR_MODE;
1706			arg = optarg;
1707			break;
1708		case 'L':
1709			act = ACT_SET_LEAP_MODE;
1710			arg = optarg;
1711			break;
1712		case 'h':
1713		default:
1714			usage(p);
1715		}
1716	}
1717
1718	if (iface == NULL || (!act && !key))
1719		usage(p);
1720
1721	switch(act) {
1722	case ACT_DUMPSTATUS:
1723		an_dumpstatus(iface);
1724		break;
1725	case ACT_DUMPCAPS:
1726		an_dumpcaps(iface);
1727		break;
1728	case ACT_DUMPSTATS:
1729		an_dumpstats(iface);
1730		break;
1731	case ACT_DUMPCONFIG:
1732		an_dumpconfig(iface);
1733		break;
1734	case ACT_DUMPSSID:
1735		an_dumpssid(iface);
1736		break;
1737	case ACT_DUMPAP:
1738		an_dumpap(iface);
1739		break;
1740	case ACT_DUMPRSSIMAP:
1741		an_dumprssimap(iface);
1742		break;
1743	case ACT_SET_SSID:
1744		an_setssid(iface, modifier, arg);
1745		break;
1746	case ACT_SET_AP1:
1747	case ACT_SET_AP2:
1748	case ACT_SET_AP3:
1749	case ACT_SET_AP4:
1750		an_setap(iface, act, arg);
1751		break;
1752	case ACT_SET_TXRATE:
1753		an_setspeed(iface, act, arg);
1754		break;
1755#ifdef ANCACHE
1756	case ACT_ZEROCACHE:
1757		an_zerocache(iface);
1758		break;
1759	case ACT_DUMPCACHE:
1760		an_readcache(iface);
1761		break;
1762
1763#endif
1764	case ACT_SET_KEYS:
1765		an_setkeys(iface, key, modifier);
1766		break;
1767	case ACT_ENABLE_TX_KEY:
1768		an_enable_tx_key(iface, arg);
1769		break;
1770	case ACT_SET_LEAP_MODE:
1771		an_enable_leap_mode(iface, arg);
1772		break;
1773	default:
1774		an_setconfig(iface, act, arg);
1775		break;
1776	}
1777
1778	exit(0);
1779}
1780
1781