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