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