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