1*90b80121SDavid van Moolenbroek /* $NetBSD: ieee80211.c,v 1.28 2015/04/28 15:14:57 christos Exp $ */
2*90b80121SDavid van Moolenbroek
3*90b80121SDavid van Moolenbroek /*
4*90b80121SDavid van Moolenbroek * Copyright (c) 1983, 1993
5*90b80121SDavid van Moolenbroek * The Regents of the University of California. All rights reserved.
6*90b80121SDavid van Moolenbroek *
7*90b80121SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
8*90b80121SDavid van Moolenbroek * modification, are permitted provided that the following conditions
9*90b80121SDavid van Moolenbroek * are met:
10*90b80121SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
11*90b80121SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
12*90b80121SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
13*90b80121SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
14*90b80121SDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
15*90b80121SDavid van Moolenbroek * 3. Neither the name of the University nor the names of its contributors
16*90b80121SDavid van Moolenbroek * may be used to endorse or promote products derived from this software
17*90b80121SDavid van Moolenbroek * without specific prior written permission.
18*90b80121SDavid van Moolenbroek *
19*90b80121SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*90b80121SDavid van Moolenbroek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*90b80121SDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*90b80121SDavid van Moolenbroek * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*90b80121SDavid van Moolenbroek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*90b80121SDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*90b80121SDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*90b80121SDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*90b80121SDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*90b80121SDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*90b80121SDavid van Moolenbroek * SUCH DAMAGE.
30*90b80121SDavid van Moolenbroek */
31*90b80121SDavid van Moolenbroek
32*90b80121SDavid van Moolenbroek #include <sys/cdefs.h>
33*90b80121SDavid van Moolenbroek #ifndef lint
34*90b80121SDavid van Moolenbroek __RCSID("$NetBSD: ieee80211.c,v 1.28 2015/04/28 15:14:57 christos Exp $");
35*90b80121SDavid van Moolenbroek #endif /* not lint */
36*90b80121SDavid van Moolenbroek
37*90b80121SDavid van Moolenbroek #include <sys/param.h>
38*90b80121SDavid van Moolenbroek #include <sys/ioctl.h>
39*90b80121SDavid van Moolenbroek #include <sys/socket.h>
40*90b80121SDavid van Moolenbroek
41*90b80121SDavid van Moolenbroek #include <net/if.h>
42*90b80121SDavid van Moolenbroek #include <net/if_ether.h>
43*90b80121SDavid van Moolenbroek #include <net/if_media.h>
44*90b80121SDavid van Moolenbroek #include <net/route.h>
45*90b80121SDavid van Moolenbroek #include <net80211/ieee80211.h>
46*90b80121SDavid van Moolenbroek #include <net80211/ieee80211_ioctl.h>
47*90b80121SDavid van Moolenbroek #include <net80211/ieee80211_netbsd.h>
48*90b80121SDavid van Moolenbroek
49*90b80121SDavid van Moolenbroek #include <assert.h>
50*90b80121SDavid van Moolenbroek #include <ctype.h>
51*90b80121SDavid van Moolenbroek #include <err.h>
52*90b80121SDavid van Moolenbroek #include <errno.h>
53*90b80121SDavid van Moolenbroek #include <netdb.h>
54*90b80121SDavid van Moolenbroek #include <string.h>
55*90b80121SDavid van Moolenbroek #include <stddef.h>
56*90b80121SDavid van Moolenbroek #include <stdlib.h>
57*90b80121SDavid van Moolenbroek #include <stdio.h>
58*90b80121SDavid van Moolenbroek #include <unistd.h>
59*90b80121SDavid van Moolenbroek #include <util.h>
60*90b80121SDavid van Moolenbroek
61*90b80121SDavid van Moolenbroek #include "extern.h"
62*90b80121SDavid van Moolenbroek #include "parse.h"
63*90b80121SDavid van Moolenbroek #include "env.h"
64*90b80121SDavid van Moolenbroek #include "util.h"
65*90b80121SDavid van Moolenbroek #include "prog_ops.h"
66*90b80121SDavid van Moolenbroek
67*90b80121SDavid van Moolenbroek static void ieee80211_statistics(prop_dictionary_t);
68*90b80121SDavid van Moolenbroek static void ieee80211_status(prop_dictionary_t, prop_dictionary_t);
69*90b80121SDavid van Moolenbroek static void ieee80211_constructor(void) __attribute__((constructor));
70*90b80121SDavid van Moolenbroek static int set80211(prop_dictionary_t env, uint16_t, int16_t, int16_t,
71*90b80121SDavid van Moolenbroek u_int8_t *);
72*90b80121SDavid van Moolenbroek static u_int ieee80211_mhz2ieee(u_int, u_int);
73*90b80121SDavid van Moolenbroek static int getmaxrate(const uint8_t [15], u_int8_t);
74*90b80121SDavid van Moolenbroek static const char * getcaps(int);
75*90b80121SDavid van Moolenbroek static void printie(const char*, const uint8_t *, size_t, int);
76*90b80121SDavid van Moolenbroek static int copy_essid(char [], size_t, const u_int8_t *, size_t);
77*90b80121SDavid van Moolenbroek static void scan_and_wait(prop_dictionary_t);
78*90b80121SDavid van Moolenbroek static void list_scan(prop_dictionary_t);
79*90b80121SDavid van Moolenbroek static int mappsb(u_int , u_int);
80*90b80121SDavid van Moolenbroek static int mapgsm(u_int , u_int);
81*90b80121SDavid van Moolenbroek
82*90b80121SDavid van Moolenbroek static int sethidessid(prop_dictionary_t, prop_dictionary_t);
83*90b80121SDavid van Moolenbroek static int setapbridge(prop_dictionary_t, prop_dictionary_t);
84*90b80121SDavid van Moolenbroek static int setifssid(prop_dictionary_t, prop_dictionary_t);
85*90b80121SDavid van Moolenbroek static int setifnwkey(prop_dictionary_t, prop_dictionary_t);
86*90b80121SDavid van Moolenbroek static int unsetifnwkey(prop_dictionary_t, prop_dictionary_t);
87*90b80121SDavid van Moolenbroek static int unsetifbssid(prop_dictionary_t, prop_dictionary_t);
88*90b80121SDavid van Moolenbroek static int setifbssid(prop_dictionary_t, prop_dictionary_t);
89*90b80121SDavid van Moolenbroek static int setifchan(prop_dictionary_t, prop_dictionary_t);
90*90b80121SDavid van Moolenbroek static int setiffrag(prop_dictionary_t, prop_dictionary_t);
91*90b80121SDavid van Moolenbroek static int setifpowersave(prop_dictionary_t, prop_dictionary_t);
92*90b80121SDavid van Moolenbroek static int setifpowersavesleep(prop_dictionary_t, prop_dictionary_t);
93*90b80121SDavid van Moolenbroek static int setifrts(prop_dictionary_t, prop_dictionary_t);
94*90b80121SDavid van Moolenbroek static int scan_exec(prop_dictionary_t, prop_dictionary_t);
95*90b80121SDavid van Moolenbroek
96*90b80121SDavid van Moolenbroek static void printies(const u_int8_t *, int, int);
97*90b80121SDavid van Moolenbroek static void printwmeparam(const char *, const u_int8_t *, size_t , int);
98*90b80121SDavid van Moolenbroek static void printwmeinfo(const char *, const u_int8_t *, size_t , int);
99*90b80121SDavid van Moolenbroek static const char * wpa_cipher(const u_int8_t *);
100*90b80121SDavid van Moolenbroek static const char * wpa_keymgmt(const u_int8_t *);
101*90b80121SDavid van Moolenbroek static void printwpaie(const char *, const u_int8_t *, size_t , int);
102*90b80121SDavid van Moolenbroek static const char * rsn_cipher(const u_int8_t *);
103*90b80121SDavid van Moolenbroek static const char * rsn_keymgmt(const u_int8_t *);
104*90b80121SDavid van Moolenbroek static void printrsnie(const char *, const u_int8_t *, size_t , int);
105*90b80121SDavid van Moolenbroek static void printssid(const char *, const u_int8_t *, size_t , int);
106*90b80121SDavid van Moolenbroek static void printrates(const char *, const u_int8_t *, size_t , int);
107*90b80121SDavid van Moolenbroek static void printcountry(const char *, const u_int8_t *, size_t , int);
108*90b80121SDavid van Moolenbroek static int iswpaoui(const u_int8_t *);
109*90b80121SDavid van Moolenbroek static int iswmeinfo(const u_int8_t *);
110*90b80121SDavid van Moolenbroek static int iswmeparam(const u_int8_t *);
111*90b80121SDavid van Moolenbroek static const char * iename(int);
112*90b80121SDavid van Moolenbroek
113*90b80121SDavid van Moolenbroek extern struct pinteger parse_chan, parse_frag, parse_rts;
114*90b80121SDavid van Moolenbroek extern struct pstr parse_bssid, parse_ssid, parse_nwkey;
115*90b80121SDavid van Moolenbroek extern struct pinteger parse_powersavesleep;
116*90b80121SDavid van Moolenbroek
117*90b80121SDavid van Moolenbroek static const struct kwinst ieee80211boolkw[] = {
118*90b80121SDavid van Moolenbroek {.k_word = "hidessid", .k_key = "hidessid", .k_neg = true,
119*90b80121SDavid van Moolenbroek .k_type = KW_T_BOOL, .k_bool = true, .k_negbool = false,
120*90b80121SDavid van Moolenbroek .k_exec = sethidessid}
121*90b80121SDavid van Moolenbroek , {.k_word = "apbridge", .k_key = "apbridge", .k_neg = true,
122*90b80121SDavid van Moolenbroek .k_type = KW_T_BOOL, .k_bool = true, .k_negbool = false,
123*90b80121SDavid van Moolenbroek .k_exec = setapbridge}
124*90b80121SDavid van Moolenbroek , {.k_word = "powersave", .k_key = "powersave", .k_neg = true,
125*90b80121SDavid van Moolenbroek .k_type = KW_T_BOOL, .k_bool = true, .k_negbool = false,
126*90b80121SDavid van Moolenbroek .k_exec = setifpowersave}
127*90b80121SDavid van Moolenbroek };
128*90b80121SDavid van Moolenbroek
129*90b80121SDavid van Moolenbroek static const struct kwinst listskw[] = {
130*90b80121SDavid van Moolenbroek {.k_word = "scan", .k_exec = scan_exec}
131*90b80121SDavid van Moolenbroek };
132*90b80121SDavid van Moolenbroek
133*90b80121SDavid van Moolenbroek static struct pkw lists = PKW_INITIALIZER(&lists, "ieee80211 lists", NULL,
134*90b80121SDavid van Moolenbroek "list", listskw, __arraycount(listskw), &command_root.pb_parser);
135*90b80121SDavid van Moolenbroek
136*90b80121SDavid van Moolenbroek static const struct kwinst kw80211kw[] = {
137*90b80121SDavid van Moolenbroek {.k_word = "bssid", .k_nextparser = &parse_bssid.ps_parser}
138*90b80121SDavid van Moolenbroek , {.k_word = "-bssid", .k_exec = unsetifbssid,
139*90b80121SDavid van Moolenbroek .k_nextparser = &command_root.pb_parser}
140*90b80121SDavid van Moolenbroek , {.k_word = "chan", .k_nextparser = &parse_chan.pi_parser}
141*90b80121SDavid van Moolenbroek , {.k_word = "-chan", .k_key = "chan", .k_type = KW_T_UINT,
142*90b80121SDavid van Moolenbroek .k_uint = IEEE80211_CHAN_ANY, .k_exec = setifchan,
143*90b80121SDavid van Moolenbroek .k_nextparser = &command_root.pb_parser}
144*90b80121SDavid van Moolenbroek , {.k_word = "frag", .k_nextparser = &parse_frag.pi_parser}
145*90b80121SDavid van Moolenbroek , {.k_word = "-frag", .k_key = "frag", .k_type = KW_T_INT,
146*90b80121SDavid van Moolenbroek .k_int = IEEE80211_FRAG_MAX, .k_exec = setiffrag,
147*90b80121SDavid van Moolenbroek .k_nextparser = &command_root.pb_parser}
148*90b80121SDavid van Moolenbroek , {.k_word = "list", .k_nextparser = &lists.pk_parser}
149*90b80121SDavid van Moolenbroek , {.k_word = "nwid", .k_nextparser = &parse_ssid.ps_parser}
150*90b80121SDavid van Moolenbroek , {.k_word = "nwkey", .k_nextparser = &parse_nwkey.ps_parser}
151*90b80121SDavid van Moolenbroek , {.k_word = "-nwkey", .k_exec = unsetifnwkey,
152*90b80121SDavid van Moolenbroek .k_nextparser = &command_root.pb_parser}
153*90b80121SDavid van Moolenbroek , {.k_word = "rts", .k_nextparser = &parse_rts.pi_parser}
154*90b80121SDavid van Moolenbroek , {.k_word = "-rts", .k_key = "rts", .k_type = KW_T_INT,
155*90b80121SDavid van Moolenbroek .k_int = IEEE80211_RTS_MAX, .k_exec = setifrts,
156*90b80121SDavid van Moolenbroek .k_nextparser = &command_root.pb_parser}
157*90b80121SDavid van Moolenbroek , {.k_word = "ssid", .k_nextparser = &parse_ssid.ps_parser}
158*90b80121SDavid van Moolenbroek , {.k_word = "powersavesleep",
159*90b80121SDavid van Moolenbroek .k_nextparser = &parse_powersavesleep.pi_parser}
160*90b80121SDavid van Moolenbroek };
161*90b80121SDavid van Moolenbroek
162*90b80121SDavid van Moolenbroek struct pkw kw80211 = PKW_INITIALIZER(&kw80211, "802.11 keywords", NULL, NULL,
163*90b80121SDavid van Moolenbroek kw80211kw, __arraycount(kw80211kw), NULL);
164*90b80121SDavid van Moolenbroek
165*90b80121SDavid van Moolenbroek struct pkw ieee80211bool = PKW_INITIALIZER(&ieee80211bool, "ieee80211 boolean",
166*90b80121SDavid van Moolenbroek NULL, NULL, ieee80211boolkw, __arraycount(ieee80211boolkw),
167*90b80121SDavid van Moolenbroek &command_root.pb_parser);
168*90b80121SDavid van Moolenbroek
169*90b80121SDavid van Moolenbroek struct pinteger parse_chan = PINTEGER_INITIALIZER1(&parse_chan, "chan",
170*90b80121SDavid van Moolenbroek 0, UINT16_MAX, 10, setifchan, "chan", &command_root.pb_parser);
171*90b80121SDavid van Moolenbroek
172*90b80121SDavid van Moolenbroek struct pinteger parse_rts = PINTEGER_INITIALIZER1(&parse_rts, "rts",
173*90b80121SDavid van Moolenbroek IEEE80211_RTS_MIN, IEEE80211_RTS_MAX, 10,
174*90b80121SDavid van Moolenbroek setifrts, "rts", &command_root.pb_parser);
175*90b80121SDavid van Moolenbroek
176*90b80121SDavid van Moolenbroek struct pinteger parse_frag = PINTEGER_INITIALIZER1(&parse_frag, "frag",
177*90b80121SDavid van Moolenbroek IEEE80211_FRAG_MIN, IEEE80211_FRAG_MAX, 10,
178*90b80121SDavid van Moolenbroek setiffrag, "frag", &command_root.pb_parser);
179*90b80121SDavid van Moolenbroek
180*90b80121SDavid van Moolenbroek struct pstr parse_ssid = PSTR_INITIALIZER(&parse_pass, "ssid", setifssid,
181*90b80121SDavid van Moolenbroek "ssid", &command_root.pb_parser);
182*90b80121SDavid van Moolenbroek
183*90b80121SDavid van Moolenbroek struct pinteger parse_powersavesleep =
184*90b80121SDavid van Moolenbroek PINTEGER_INITIALIZER1(&parse_powersavesleep, "powersavesleep",
185*90b80121SDavid van Moolenbroek 0, INT_MAX, 10, setifpowersavesleep, "powersavesleep",
186*90b80121SDavid van Moolenbroek &command_root.pb_parser);
187*90b80121SDavid van Moolenbroek
188*90b80121SDavid van Moolenbroek struct pstr parse_nwkey = PSTR_INITIALIZER1(&parse_nwkey, "nwkey", setifnwkey,
189*90b80121SDavid van Moolenbroek "nwkey", false, &command_root.pb_parser);
190*90b80121SDavid van Moolenbroek
191*90b80121SDavid van Moolenbroek struct pstr parse_bssid = PSTR_INITIALIZER1(&parse_bssid, "bssid", setifbssid,
192*90b80121SDavid van Moolenbroek "bssid", false, &command_root.pb_parser);
193*90b80121SDavid van Moolenbroek
194*90b80121SDavid van Moolenbroek static int
set80211(prop_dictionary_t env,uint16_t type,int16_t val,int16_t len,u_int8_t * data)195*90b80121SDavid van Moolenbroek set80211(prop_dictionary_t env, uint16_t type, int16_t val, int16_t len,
196*90b80121SDavid van Moolenbroek u_int8_t *data)
197*90b80121SDavid van Moolenbroek {
198*90b80121SDavid van Moolenbroek struct ieee80211req ireq;
199*90b80121SDavid van Moolenbroek
200*90b80121SDavid van Moolenbroek memset(&ireq, 0, sizeof(ireq));
201*90b80121SDavid van Moolenbroek ireq.i_type = type;
202*90b80121SDavid van Moolenbroek ireq.i_val = val;
203*90b80121SDavid van Moolenbroek ireq.i_len = len;
204*90b80121SDavid van Moolenbroek ireq.i_data = data;
205*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCS80211, &ireq) == -1) {
206*90b80121SDavid van Moolenbroek warn("SIOCS80211");
207*90b80121SDavid van Moolenbroek return -1;
208*90b80121SDavid van Moolenbroek }
209*90b80121SDavid van Moolenbroek return 0;
210*90b80121SDavid van Moolenbroek }
211*90b80121SDavid van Moolenbroek
212*90b80121SDavid van Moolenbroek static int
sethidessid(prop_dictionary_t env,prop_dictionary_t oenv)213*90b80121SDavid van Moolenbroek sethidessid(prop_dictionary_t env, prop_dictionary_t oenv)
214*90b80121SDavid van Moolenbroek {
215*90b80121SDavid van Moolenbroek bool on, rc;
216*90b80121SDavid van Moolenbroek
217*90b80121SDavid van Moolenbroek rc = prop_dictionary_get_bool(env, "hidessid", &on);
218*90b80121SDavid van Moolenbroek assert(rc);
219*90b80121SDavid van Moolenbroek return set80211(env, IEEE80211_IOC_HIDESSID, on ? 1 : 0, 0, NULL);
220*90b80121SDavid van Moolenbroek }
221*90b80121SDavid van Moolenbroek
222*90b80121SDavid van Moolenbroek static int
setapbridge(prop_dictionary_t env,prop_dictionary_t oenv)223*90b80121SDavid van Moolenbroek setapbridge(prop_dictionary_t env, prop_dictionary_t oenv)
224*90b80121SDavid van Moolenbroek {
225*90b80121SDavid van Moolenbroek bool on, rc;
226*90b80121SDavid van Moolenbroek
227*90b80121SDavid van Moolenbroek rc = prop_dictionary_get_bool(env, "apbridge", &on);
228*90b80121SDavid van Moolenbroek assert(rc);
229*90b80121SDavid van Moolenbroek return set80211(env, IEEE80211_IOC_APBRIDGE, on ? 1 : 0, 0, NULL);
230*90b80121SDavid van Moolenbroek }
231*90b80121SDavid van Moolenbroek
232*90b80121SDavid van Moolenbroek static enum ieee80211_opmode
get80211opmode(prop_dictionary_t env)233*90b80121SDavid van Moolenbroek get80211opmode(prop_dictionary_t env)
234*90b80121SDavid van Moolenbroek {
235*90b80121SDavid van Moolenbroek struct ifmediareq ifmr;
236*90b80121SDavid van Moolenbroek
237*90b80121SDavid van Moolenbroek memset(&ifmr, 0, sizeof(ifmr));
238*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1)
239*90b80121SDavid van Moolenbroek ;
240*90b80121SDavid van Moolenbroek else if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
241*90b80121SDavid van Moolenbroek return IEEE80211_M_IBSS; /* XXX ahdemo */
242*90b80121SDavid van Moolenbroek else if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
243*90b80121SDavid van Moolenbroek return IEEE80211_M_HOSTAP;
244*90b80121SDavid van Moolenbroek else if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
245*90b80121SDavid van Moolenbroek return IEEE80211_M_MONITOR;
246*90b80121SDavid van Moolenbroek
247*90b80121SDavid van Moolenbroek return IEEE80211_M_STA;
248*90b80121SDavid van Moolenbroek }
249*90b80121SDavid van Moolenbroek
250*90b80121SDavid van Moolenbroek static int
setifssid(prop_dictionary_t env,prop_dictionary_t oenv)251*90b80121SDavid van Moolenbroek setifssid(prop_dictionary_t env, prop_dictionary_t oenv)
252*90b80121SDavid van Moolenbroek {
253*90b80121SDavid van Moolenbroek struct ieee80211_nwid nwid;
254*90b80121SDavid van Moolenbroek ssize_t len;
255*90b80121SDavid van Moolenbroek
256*90b80121SDavid van Moolenbroek memset(&nwid, 0, sizeof(nwid));
257*90b80121SDavid van Moolenbroek if ((len = getargdata(env, "ssid", nwid.i_nwid,
258*90b80121SDavid van Moolenbroek sizeof(nwid.i_nwid))) == -1)
259*90b80121SDavid van Moolenbroek errx(EXIT_FAILURE, "%s: SSID too long", __func__);
260*90b80121SDavid van Moolenbroek nwid.i_len = (uint8_t)len;
261*90b80121SDavid van Moolenbroek if (indirect_ioctl(env, SIOCS80211NWID, &nwid) == -1)
262*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "SIOCS80211NWID");
263*90b80121SDavid van Moolenbroek return 0;
264*90b80121SDavid van Moolenbroek }
265*90b80121SDavid van Moolenbroek
266*90b80121SDavid van Moolenbroek static int
unsetifbssid(prop_dictionary_t env,prop_dictionary_t oenv)267*90b80121SDavid van Moolenbroek unsetifbssid(prop_dictionary_t env, prop_dictionary_t oenv)
268*90b80121SDavid van Moolenbroek {
269*90b80121SDavid van Moolenbroek struct ieee80211_bssid bssid;
270*90b80121SDavid van Moolenbroek
271*90b80121SDavid van Moolenbroek memset(&bssid, 0, sizeof(bssid));
272*90b80121SDavid van Moolenbroek
273*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCS80211BSSID, &bssid) == -1)
274*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "SIOCS80211BSSID");
275*90b80121SDavid van Moolenbroek return 0;
276*90b80121SDavid van Moolenbroek }
277*90b80121SDavid van Moolenbroek
278*90b80121SDavid van Moolenbroek static int
setifbssid(prop_dictionary_t env,prop_dictionary_t oenv)279*90b80121SDavid van Moolenbroek setifbssid(prop_dictionary_t env, prop_dictionary_t oenv)
280*90b80121SDavid van Moolenbroek {
281*90b80121SDavid van Moolenbroek char buf[24];
282*90b80121SDavid van Moolenbroek struct ieee80211_bssid bssid;
283*90b80121SDavid van Moolenbroek struct ether_addr *ea;
284*90b80121SDavid van Moolenbroek
285*90b80121SDavid van Moolenbroek if (getargstr(env, "bssid", buf, sizeof(buf)) == -1)
286*90b80121SDavid van Moolenbroek errx(EXIT_FAILURE, "%s: BSSID too long", __func__);
287*90b80121SDavid van Moolenbroek
288*90b80121SDavid van Moolenbroek ea = ether_aton(buf);
289*90b80121SDavid van Moolenbroek if (ea == NULL) {
290*90b80121SDavid van Moolenbroek errx(EXIT_FAILURE, "malformed BSSID: %s", buf);
291*90b80121SDavid van Moolenbroek return -1;
292*90b80121SDavid van Moolenbroek }
293*90b80121SDavid van Moolenbroek memcpy(&bssid.i_bssid, ea->ether_addr_octet,
294*90b80121SDavid van Moolenbroek sizeof(bssid.i_bssid));
295*90b80121SDavid van Moolenbroek
296*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCS80211BSSID, &bssid) == -1)
297*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "SIOCS80211BSSID");
298*90b80121SDavid van Moolenbroek return 0;
299*90b80121SDavid van Moolenbroek }
300*90b80121SDavid van Moolenbroek
301*90b80121SDavid van Moolenbroek static int
setifrts(prop_dictionary_t env,prop_dictionary_t oenv)302*90b80121SDavid van Moolenbroek setifrts(prop_dictionary_t env, prop_dictionary_t oenv)
303*90b80121SDavid van Moolenbroek {
304*90b80121SDavid van Moolenbroek bool rc;
305*90b80121SDavid van Moolenbroek int16_t val;
306*90b80121SDavid van Moolenbroek
307*90b80121SDavid van Moolenbroek rc = prop_dictionary_get_int16(env, "rts", &val);
308*90b80121SDavid van Moolenbroek assert(rc);
309*90b80121SDavid van Moolenbroek if (set80211(env, IEEE80211_IOC_RTSTHRESHOLD, val, 0, NULL) == -1)
310*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "IEEE80211_IOC_RTSTHRESHOLD");
311*90b80121SDavid van Moolenbroek return 0;
312*90b80121SDavid van Moolenbroek }
313*90b80121SDavid van Moolenbroek
314*90b80121SDavid van Moolenbroek static int
setiffrag(prop_dictionary_t env,prop_dictionary_t oenv)315*90b80121SDavid van Moolenbroek setiffrag(prop_dictionary_t env, prop_dictionary_t oenv)
316*90b80121SDavid van Moolenbroek {
317*90b80121SDavid van Moolenbroek bool rc;
318*90b80121SDavid van Moolenbroek int16_t val;
319*90b80121SDavid van Moolenbroek
320*90b80121SDavid van Moolenbroek rc = prop_dictionary_get_int16(env, "frag", &val);
321*90b80121SDavid van Moolenbroek assert(rc);
322*90b80121SDavid van Moolenbroek if (set80211(env, IEEE80211_IOC_FRAGTHRESHOLD, val, 0, NULL) == -1)
323*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "IEEE80211_IOC_FRAGTHRESHOLD");
324*90b80121SDavid van Moolenbroek return 0;
325*90b80121SDavid van Moolenbroek }
326*90b80121SDavid van Moolenbroek
327*90b80121SDavid van Moolenbroek static int
setifchan(prop_dictionary_t env,prop_dictionary_t oenv)328*90b80121SDavid van Moolenbroek setifchan(prop_dictionary_t env, prop_dictionary_t oenv)
329*90b80121SDavid van Moolenbroek {
330*90b80121SDavid van Moolenbroek bool rc;
331*90b80121SDavid van Moolenbroek struct ieee80211chanreq channel;
332*90b80121SDavid van Moolenbroek
333*90b80121SDavid van Moolenbroek rc = prop_dictionary_get_uint16(env, "chan", &channel.i_channel);
334*90b80121SDavid van Moolenbroek assert(rc);
335*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCS80211CHANNEL, &channel) == -1)
336*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "SIOCS80211CHANNEL");
337*90b80121SDavid van Moolenbroek return 0;
338*90b80121SDavid van Moolenbroek }
339*90b80121SDavid van Moolenbroek
340*90b80121SDavid van Moolenbroek static int
setifnwkey(prop_dictionary_t env,prop_dictionary_t oenv)341*90b80121SDavid van Moolenbroek setifnwkey(prop_dictionary_t env, prop_dictionary_t oenv)
342*90b80121SDavid van Moolenbroek {
343*90b80121SDavid van Moolenbroek const char *val;
344*90b80121SDavid van Moolenbroek char buf[256];
345*90b80121SDavid van Moolenbroek struct ieee80211_nwkey nwkey;
346*90b80121SDavid van Moolenbroek int i;
347*90b80121SDavid van Moolenbroek u_int8_t keybuf[IEEE80211_WEP_NKID][16];
348*90b80121SDavid van Moolenbroek
349*90b80121SDavid van Moolenbroek if (getargstr(env, "nwkey", buf, sizeof(buf)) == -1)
350*90b80121SDavid van Moolenbroek errx(EXIT_FAILURE, "%s: nwkey too long", __func__);
351*90b80121SDavid van Moolenbroek
352*90b80121SDavid van Moolenbroek val = buf;
353*90b80121SDavid van Moolenbroek
354*90b80121SDavid van Moolenbroek nwkey.i_wepon = IEEE80211_NWKEY_WEP;
355*90b80121SDavid van Moolenbroek nwkey.i_defkid = 1;
356*90b80121SDavid van Moolenbroek for (i = 0; i < IEEE80211_WEP_NKID; i++) {
357*90b80121SDavid van Moolenbroek nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
358*90b80121SDavid van Moolenbroek nwkey.i_key[i].i_keydat = keybuf[i];
359*90b80121SDavid van Moolenbroek }
360*90b80121SDavid van Moolenbroek if (strcasecmp("persist", val) == 0) {
361*90b80121SDavid van Moolenbroek /* use all values from persistent memory */
362*90b80121SDavid van Moolenbroek nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
363*90b80121SDavid van Moolenbroek nwkey.i_defkid = 0;
364*90b80121SDavid van Moolenbroek for (i = 0; i < IEEE80211_WEP_NKID; i++)
365*90b80121SDavid van Moolenbroek nwkey.i_key[i].i_keylen = -1;
366*90b80121SDavid van Moolenbroek } else if (strncasecmp("persist:", val, 8) == 0) {
367*90b80121SDavid van Moolenbroek val += 8;
368*90b80121SDavid van Moolenbroek /* program keys in persistent memory */
369*90b80121SDavid van Moolenbroek nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
370*90b80121SDavid van Moolenbroek goto set_nwkey;
371*90b80121SDavid van Moolenbroek } else {
372*90b80121SDavid van Moolenbroek set_nwkey:
373*90b80121SDavid van Moolenbroek if (isdigit((unsigned char)val[0]) && val[1] == ':') {
374*90b80121SDavid van Moolenbroek /* specifying a full set of four keys */
375*90b80121SDavid van Moolenbroek nwkey.i_defkid = val[0] - '0';
376*90b80121SDavid van Moolenbroek val += 2;
377*90b80121SDavid van Moolenbroek for (i = 0; i < IEEE80211_WEP_NKID; i++) {
378*90b80121SDavid van Moolenbroek val = get_string(val, ",", keybuf[i],
379*90b80121SDavid van Moolenbroek &nwkey.i_key[i].i_keylen, true);
380*90b80121SDavid van Moolenbroek if (val == NULL) {
381*90b80121SDavid van Moolenbroek errno = EINVAL;
382*90b80121SDavid van Moolenbroek return -1;
383*90b80121SDavid van Moolenbroek }
384*90b80121SDavid van Moolenbroek }
385*90b80121SDavid van Moolenbroek if (*val != '\0') {
386*90b80121SDavid van Moolenbroek errx(EXIT_FAILURE, "SIOCS80211NWKEY: too many keys.");
387*90b80121SDavid van Moolenbroek }
388*90b80121SDavid van Moolenbroek } else {
389*90b80121SDavid van Moolenbroek val = get_string(val, NULL, keybuf[0],
390*90b80121SDavid van Moolenbroek &nwkey.i_key[0].i_keylen, true);
391*90b80121SDavid van Moolenbroek if (val == NULL) {
392*90b80121SDavid van Moolenbroek errno = EINVAL;
393*90b80121SDavid van Moolenbroek return -1;
394*90b80121SDavid van Moolenbroek }
395*90b80121SDavid van Moolenbroek i = 1;
396*90b80121SDavid van Moolenbroek }
397*90b80121SDavid van Moolenbroek }
398*90b80121SDavid van Moolenbroek for (; i < IEEE80211_WEP_NKID; i++)
399*90b80121SDavid van Moolenbroek nwkey.i_key[i].i_keylen = 0;
400*90b80121SDavid van Moolenbroek
401*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCS80211NWKEY, &nwkey) == -1)
402*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "SIOCS80211NWKEY");
403*90b80121SDavid van Moolenbroek return 0;
404*90b80121SDavid van Moolenbroek }
405*90b80121SDavid van Moolenbroek
406*90b80121SDavid van Moolenbroek static int
unsetifnwkey(prop_dictionary_t env,prop_dictionary_t oenv)407*90b80121SDavid van Moolenbroek unsetifnwkey(prop_dictionary_t env, prop_dictionary_t oenv)
408*90b80121SDavid van Moolenbroek {
409*90b80121SDavid van Moolenbroek struct ieee80211_nwkey nwkey;
410*90b80121SDavid van Moolenbroek int i;
411*90b80121SDavid van Moolenbroek
412*90b80121SDavid van Moolenbroek nwkey.i_wepon = 0;
413*90b80121SDavid van Moolenbroek nwkey.i_defkid = 1;
414*90b80121SDavid van Moolenbroek for (i = 0; i < IEEE80211_WEP_NKID; i++) {
415*90b80121SDavid van Moolenbroek nwkey.i_key[i].i_keylen = 0;
416*90b80121SDavid van Moolenbroek nwkey.i_key[i].i_keydat = NULL;
417*90b80121SDavid van Moolenbroek }
418*90b80121SDavid van Moolenbroek
419*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCS80211NWKEY, &nwkey) == -1)
420*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "SIOCS80211NWKEY");
421*90b80121SDavid van Moolenbroek return 0;
422*90b80121SDavid van Moolenbroek }
423*90b80121SDavid van Moolenbroek
424*90b80121SDavid van Moolenbroek static int
setifpowersave(prop_dictionary_t env,prop_dictionary_t oenv)425*90b80121SDavid van Moolenbroek setifpowersave(prop_dictionary_t env, prop_dictionary_t oenv)
426*90b80121SDavid van Moolenbroek {
427*90b80121SDavid van Moolenbroek struct ieee80211_power power;
428*90b80121SDavid van Moolenbroek bool on, rc;
429*90b80121SDavid van Moolenbroek
430*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211POWER, &power) == -1)
431*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "SIOCG80211POWER");
432*90b80121SDavid van Moolenbroek
433*90b80121SDavid van Moolenbroek rc = prop_dictionary_get_bool(env, "powersave", &on);
434*90b80121SDavid van Moolenbroek assert(rc);
435*90b80121SDavid van Moolenbroek
436*90b80121SDavid van Moolenbroek power.i_enabled = on ? 1 : 0;
437*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCS80211POWER, &power) == -1) {
438*90b80121SDavid van Moolenbroek warn("SIOCS80211POWER");
439*90b80121SDavid van Moolenbroek return -1;
440*90b80121SDavid van Moolenbroek }
441*90b80121SDavid van Moolenbroek return 0;
442*90b80121SDavid van Moolenbroek }
443*90b80121SDavid van Moolenbroek
444*90b80121SDavid van Moolenbroek static int
setifpowersavesleep(prop_dictionary_t env,prop_dictionary_t oenv)445*90b80121SDavid van Moolenbroek setifpowersavesleep(prop_dictionary_t env, prop_dictionary_t oenv)
446*90b80121SDavid van Moolenbroek {
447*90b80121SDavid van Moolenbroek struct ieee80211_power power;
448*90b80121SDavid van Moolenbroek int64_t maxsleep;
449*90b80121SDavid van Moolenbroek bool rc;
450*90b80121SDavid van Moolenbroek
451*90b80121SDavid van Moolenbroek rc = prop_dictionary_get_int64(env, "powersavesleep", &maxsleep);
452*90b80121SDavid van Moolenbroek assert(rc);
453*90b80121SDavid van Moolenbroek
454*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211POWER, &power) == -1)
455*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "SIOCG80211POWER");
456*90b80121SDavid van Moolenbroek
457*90b80121SDavid van Moolenbroek power.i_maxsleep = maxsleep;
458*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCS80211POWER, &power) == -1)
459*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "SIOCS80211POWER");
460*90b80121SDavid van Moolenbroek return 0;
461*90b80121SDavid van Moolenbroek }
462*90b80121SDavid van Moolenbroek
463*90b80121SDavid van Moolenbroek static int
scan_exec(prop_dictionary_t env,prop_dictionary_t oenv)464*90b80121SDavid van Moolenbroek scan_exec(prop_dictionary_t env, prop_dictionary_t oenv)
465*90b80121SDavid van Moolenbroek {
466*90b80121SDavid van Moolenbroek struct ifreq ifr;
467*90b80121SDavid van Moolenbroek
468*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1) {
469*90b80121SDavid van Moolenbroek warn("ioctl(SIOCGIFFLAGS)");
470*90b80121SDavid van Moolenbroek return -1;
471*90b80121SDavid van Moolenbroek }
472*90b80121SDavid van Moolenbroek
473*90b80121SDavid van Moolenbroek if ((ifr.ifr_flags & IFF_UP) == 0)
474*90b80121SDavid van Moolenbroek errx(EXIT_FAILURE, "The interface must be up before scanning.");
475*90b80121SDavid van Moolenbroek
476*90b80121SDavid van Moolenbroek scan_and_wait(env);
477*90b80121SDavid van Moolenbroek list_scan(env);
478*90b80121SDavid van Moolenbroek
479*90b80121SDavid van Moolenbroek return 0;
480*90b80121SDavid van Moolenbroek }
481*90b80121SDavid van Moolenbroek
482*90b80121SDavid van Moolenbroek static void
ieee80211_statistics(prop_dictionary_t env)483*90b80121SDavid van Moolenbroek ieee80211_statistics(prop_dictionary_t env)
484*90b80121SDavid van Moolenbroek {
485*90b80121SDavid van Moolenbroek #ifndef SMALL
486*90b80121SDavid van Moolenbroek struct ieee80211_stats stats;
487*90b80121SDavid van Moolenbroek struct ifreq ifr;
488*90b80121SDavid van Moolenbroek
489*90b80121SDavid van Moolenbroek memset(&ifr, 0, sizeof(ifr));
490*90b80121SDavid van Moolenbroek ifr.ifr_buflen = sizeof(stats);
491*90b80121SDavid van Moolenbroek ifr.ifr_buf = (caddr_t)&stats;
492*90b80121SDavid van Moolenbroek if (direct_ioctl(env, (zflag) ? SIOCG80211ZSTATS : SIOCG80211STATS,
493*90b80121SDavid van Moolenbroek &ifr) == -1)
494*90b80121SDavid van Moolenbroek return;
495*90b80121SDavid van Moolenbroek #define STAT_PRINT(_member, _desc) \
496*90b80121SDavid van Moolenbroek printf("\t" _desc ": %" PRIu32 "\n", stats._member)
497*90b80121SDavid van Moolenbroek
498*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_badversion, "rx frame with bad version");
499*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_tooshort, "rx frame too short");
500*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_wrongbss, "rx from wrong bssid");
501*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_dup, "rx discard 'cuz dup");
502*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_wrongdir, "rx w/ wrong direction");
503*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_mcastecho, "rx discard 'cuz mcast echo");
504*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_notassoc, "rx discard 'cuz sta !assoc");
505*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_noprivacy, "rx w/ wep but privacy off");
506*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_unencrypted, "rx w/o wep and privacy on");
507*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_wepfail, "rx wep processing failed");
508*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_decap, "rx decapsulation failed");
509*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_mgtdiscard, "rx discard mgt frames");
510*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_ctl, "rx discard ctrl frames");
511*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_beacon, "rx beacon frames");
512*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_rstoobig, "rx rate set truncated");
513*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_elem_missing, "rx required element missing");
514*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_elem_toobig, "rx element too big");
515*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_elem_toosmall, "rx element too small");
516*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_elem_unknown, "rx element unknown");
517*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_badchan, "rx frame w/ invalid chan");
518*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_chanmismatch, "rx frame chan mismatch");
519*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_nodealloc, "rx frame dropped");
520*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_ssidmismatch, "rx frame ssid mismatch ");
521*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_auth_unsupported, "rx w/ unsupported auth alg");
522*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_auth_fail, "rx sta auth failure");
523*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_auth_countermeasures, "rx auth discard 'cuz CM");
524*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_assoc_bss, "rx assoc from wrong bssid");
525*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_assoc_notauth, "rx assoc w/o auth");
526*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_assoc_capmismatch, "rx assoc w/ cap mismatch");
527*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_assoc_norate, "rx assoc w/ no rate match");
528*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_assoc_badwpaie, "rx assoc w/ bad WPA IE");
529*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_deauth, "rx deauthentication");
530*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_disassoc, "rx disassociation");
531*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_badsubtype, "rx frame w/ unknown subtyp");
532*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_nobuf, "rx failed for lack of buf");
533*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_decryptcrc, "rx decrypt failed on crc");
534*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_ahdemo_mgt, "rx discard ahdemo mgt fram");
535*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_bad_auth, "rx bad auth request");
536*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_unauth, "rx on unauthorized port");
537*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_badkeyid, "rx w/ incorrect keyid");
538*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_ccmpreplay, "rx seq# violation (CCMP)");
539*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_ccmpformat, "rx format bad (CCMP)");
540*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_ccmpmic, "rx MIC check failed (CCMP)");
541*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_tkipreplay, "rx seq# violation (TKIP)");
542*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_tkipformat, "rx format bad (TKIP)");
543*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_tkipmic, "rx MIC check failed (TKIP)");
544*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_tkipicv, "rx ICV check failed (TKIP)");
545*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_badcipher, "rx failed 'cuz key type");
546*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_nocipherctx, "rx failed 'cuz key !setup");
547*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_acl, "rx discard 'cuz acl policy");
548*90b80121SDavid van Moolenbroek
549*90b80121SDavid van Moolenbroek STAT_PRINT(is_tx_nobuf, "tx failed for lack of buf");
550*90b80121SDavid van Moolenbroek STAT_PRINT(is_tx_nonode, "tx failed for no node");
551*90b80121SDavid van Moolenbroek STAT_PRINT(is_tx_unknownmgt, "tx of unknown mgt frame");
552*90b80121SDavid van Moolenbroek STAT_PRINT(is_tx_badcipher, "tx failed 'cuz key type");
553*90b80121SDavid van Moolenbroek STAT_PRINT(is_tx_nodefkey, "tx failed 'cuz no defkey");
554*90b80121SDavid van Moolenbroek STAT_PRINT(is_tx_noheadroom, "tx failed 'cuz no space");
555*90b80121SDavid van Moolenbroek STAT_PRINT(is_tx_fragframes, "tx frames fragmented");
556*90b80121SDavid van Moolenbroek STAT_PRINT(is_tx_frags, "tx fragments created");
557*90b80121SDavid van Moolenbroek
558*90b80121SDavid van Moolenbroek STAT_PRINT(is_scan_active, "active scans started");
559*90b80121SDavid van Moolenbroek STAT_PRINT(is_scan_passive, "passive scans started");
560*90b80121SDavid van Moolenbroek STAT_PRINT(is_node_timeout, "nodes timed out inactivity");
561*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_nomem, "no memory for crypto ctx");
562*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_tkip, "tkip crypto done in s/w");
563*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_tkipenmic, "tkip en-MIC done in s/w");
564*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_tkipdemic, "tkip de-MIC done in s/w");
565*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_tkipcm, "tkip counter measures");
566*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_ccmp, "ccmp crypto done in s/w");
567*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_wep, "wep crypto done in s/w");
568*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_setkey_cipher, "cipher rejected key");
569*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_setkey_nokey, "no key index for setkey");
570*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_delkey, "driver key delete failed");
571*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_badcipher, "unknown cipher");
572*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_nocipher, "cipher not available");
573*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_attachfail, "cipher attach failed");
574*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_swfallback, "cipher fallback to s/w");
575*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_keyfail, "driver key alloc failed");
576*90b80121SDavid van Moolenbroek STAT_PRINT(is_crypto_enmicfail, "en-MIC failed");
577*90b80121SDavid van Moolenbroek STAT_PRINT(is_ibss_capmismatch, "merge failed-cap mismatch");
578*90b80121SDavid van Moolenbroek STAT_PRINT(is_ibss_norate, "merge failed-rate mismatch");
579*90b80121SDavid van Moolenbroek STAT_PRINT(is_ps_unassoc, "ps-poll for unassoc. sta");
580*90b80121SDavid van Moolenbroek STAT_PRINT(is_ps_badaid, "ps-poll w/ incorrect aid");
581*90b80121SDavid van Moolenbroek STAT_PRINT(is_ps_qempty, "ps-poll w/ nothing to send");
582*90b80121SDavid van Moolenbroek STAT_PRINT(is_ff_badhdr, "fast frame rx'd w/ bad hdr");
583*90b80121SDavid van Moolenbroek STAT_PRINT(is_ff_tooshort, "fast frame rx decap error");
584*90b80121SDavid van Moolenbroek STAT_PRINT(is_ff_split, "fast frame rx split error");
585*90b80121SDavid van Moolenbroek STAT_PRINT(is_ff_decap, "fast frames decap'd");
586*90b80121SDavid van Moolenbroek STAT_PRINT(is_ff_encap, "fast frames encap'd for tx");
587*90b80121SDavid van Moolenbroek STAT_PRINT(is_rx_badbintval, "rx frame w/ bogus bintval");
588*90b80121SDavid van Moolenbroek #endif
589*90b80121SDavid van Moolenbroek }
590*90b80121SDavid van Moolenbroek
591*90b80121SDavid van Moolenbroek static void
ieee80211_status(prop_dictionary_t env,prop_dictionary_t oenv)592*90b80121SDavid van Moolenbroek ieee80211_status(prop_dictionary_t env, prop_dictionary_t oenv)
593*90b80121SDavid van Moolenbroek {
594*90b80121SDavid van Moolenbroek int i, nwkey_verbose;
595*90b80121SDavid van Moolenbroek struct ieee80211_nwid nwid;
596*90b80121SDavid van Moolenbroek struct ieee80211_nwkey nwkey;
597*90b80121SDavid van Moolenbroek struct ieee80211_power power;
598*90b80121SDavid van Moolenbroek u_int8_t keybuf[IEEE80211_WEP_NKID][16];
599*90b80121SDavid van Moolenbroek struct ieee80211_bssid bssid;
600*90b80121SDavid van Moolenbroek struct ieee80211chanreq channel;
601*90b80121SDavid van Moolenbroek struct ieee80211req ireq;
602*90b80121SDavid van Moolenbroek struct ether_addr ea;
603*90b80121SDavid van Moolenbroek static const u_int8_t zero_macaddr[IEEE80211_ADDR_LEN];
604*90b80121SDavid van Moolenbroek enum ieee80211_opmode opmode = get80211opmode(env);
605*90b80121SDavid van Moolenbroek
606*90b80121SDavid van Moolenbroek memset(&bssid, 0, sizeof(bssid));
607*90b80121SDavid van Moolenbroek memset(&nwkey, 0, sizeof(nwkey));
608*90b80121SDavid van Moolenbroek memset(&nwid, 0, sizeof(nwid));
609*90b80121SDavid van Moolenbroek memset(&nwid, 0, sizeof(nwid));
610*90b80121SDavid van Moolenbroek
611*90b80121SDavid van Moolenbroek if (indirect_ioctl(env, SIOCG80211NWID, &nwid) == -1)
612*90b80121SDavid van Moolenbroek return;
613*90b80121SDavid van Moolenbroek if (nwid.i_len > IEEE80211_NWID_LEN) {
614*90b80121SDavid van Moolenbroek errx(EXIT_FAILURE, "SIOCG80211NWID: wrong length of nwid (%d)", nwid.i_len);
615*90b80121SDavid van Moolenbroek }
616*90b80121SDavid van Moolenbroek printf("\tssid ");
617*90b80121SDavid van Moolenbroek print_string(nwid.i_nwid, nwid.i_len);
618*90b80121SDavid van Moolenbroek
619*90b80121SDavid van Moolenbroek if (opmode == IEEE80211_M_HOSTAP) {
620*90b80121SDavid van Moolenbroek ireq.i_type = IEEE80211_IOC_HIDESSID;
621*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211, &ireq) != -1) {
622*90b80121SDavid van Moolenbroek if (ireq.i_val)
623*90b80121SDavid van Moolenbroek printf(" [hidden]");
624*90b80121SDavid van Moolenbroek else if (vflag)
625*90b80121SDavid van Moolenbroek printf(" [shown]");
626*90b80121SDavid van Moolenbroek }
627*90b80121SDavid van Moolenbroek
628*90b80121SDavid van Moolenbroek ireq.i_type = IEEE80211_IOC_APBRIDGE;
629*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211, &ireq) != -1) {
630*90b80121SDavid van Moolenbroek if (ireq.i_val)
631*90b80121SDavid van Moolenbroek printf(" apbridge");
632*90b80121SDavid van Moolenbroek else if (vflag)
633*90b80121SDavid van Moolenbroek printf(" -apbridge");
634*90b80121SDavid van Moolenbroek }
635*90b80121SDavid van Moolenbroek }
636*90b80121SDavid van Moolenbroek
637*90b80121SDavid van Moolenbroek ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
638*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211, &ireq) == -1)
639*90b80121SDavid van Moolenbroek ;
640*90b80121SDavid van Moolenbroek else if (ireq.i_val < IEEE80211_RTS_MAX)
641*90b80121SDavid van Moolenbroek printf(" rts %d", ireq.i_val);
642*90b80121SDavid van Moolenbroek else if (vflag)
643*90b80121SDavid van Moolenbroek printf(" -rts");
644*90b80121SDavid van Moolenbroek
645*90b80121SDavid van Moolenbroek ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
646*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211, &ireq) == -1)
647*90b80121SDavid van Moolenbroek ;
648*90b80121SDavid van Moolenbroek else if (ireq.i_val < IEEE80211_FRAG_MAX)
649*90b80121SDavid van Moolenbroek printf(" frag %d", ireq.i_val);
650*90b80121SDavid van Moolenbroek else if (vflag)
651*90b80121SDavid van Moolenbroek printf(" -frag");
652*90b80121SDavid van Moolenbroek
653*90b80121SDavid van Moolenbroek memset(&nwkey, 0, sizeof(nwkey));
654*90b80121SDavid van Moolenbroek /* show nwkey only when WEP is enabled */
655*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211NWKEY, &nwkey) == -1 ||
656*90b80121SDavid van Moolenbroek nwkey.i_wepon == 0) {
657*90b80121SDavid van Moolenbroek printf("\n");
658*90b80121SDavid van Moolenbroek goto skip_wep;
659*90b80121SDavid van Moolenbroek }
660*90b80121SDavid van Moolenbroek
661*90b80121SDavid van Moolenbroek printf(" nwkey ");
662*90b80121SDavid van Moolenbroek /* try to retrieve WEP keys */
663*90b80121SDavid van Moolenbroek for (i = 0; i < IEEE80211_WEP_NKID; i++) {
664*90b80121SDavid van Moolenbroek nwkey.i_key[i].i_keydat = keybuf[i];
665*90b80121SDavid van Moolenbroek nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
666*90b80121SDavid van Moolenbroek }
667*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211NWKEY, &nwkey) == -1) {
668*90b80121SDavid van Moolenbroek printf("*****");
669*90b80121SDavid van Moolenbroek } else {
670*90b80121SDavid van Moolenbroek nwkey_verbose = 0;
671*90b80121SDavid van Moolenbroek /* check to see non default key or multiple keys defined */
672*90b80121SDavid van Moolenbroek if (nwkey.i_defkid != 1) {
673*90b80121SDavid van Moolenbroek nwkey_verbose = 1;
674*90b80121SDavid van Moolenbroek } else {
675*90b80121SDavid van Moolenbroek for (i = 1; i < IEEE80211_WEP_NKID; i++) {
676*90b80121SDavid van Moolenbroek if (nwkey.i_key[i].i_keylen != 0) {
677*90b80121SDavid van Moolenbroek nwkey_verbose = 1;
678*90b80121SDavid van Moolenbroek break;
679*90b80121SDavid van Moolenbroek }
680*90b80121SDavid van Moolenbroek }
681*90b80121SDavid van Moolenbroek }
682*90b80121SDavid van Moolenbroek /* check extra ambiguity with keywords */
683*90b80121SDavid van Moolenbroek if (!nwkey_verbose) {
684*90b80121SDavid van Moolenbroek if (nwkey.i_key[0].i_keylen >= 2 &&
685*90b80121SDavid van Moolenbroek isdigit(nwkey.i_key[0].i_keydat[0]) &&
686*90b80121SDavid van Moolenbroek nwkey.i_key[0].i_keydat[1] == ':')
687*90b80121SDavid van Moolenbroek nwkey_verbose = 1;
688*90b80121SDavid van Moolenbroek else if (nwkey.i_key[0].i_keylen >= 7 &&
689*90b80121SDavid van Moolenbroek strncasecmp("persist",
690*90b80121SDavid van Moolenbroek (const char *)nwkey.i_key[0].i_keydat, 7) == 0)
691*90b80121SDavid van Moolenbroek nwkey_verbose = 1;
692*90b80121SDavid van Moolenbroek }
693*90b80121SDavid van Moolenbroek if (nwkey_verbose)
694*90b80121SDavid van Moolenbroek printf("%d:", nwkey.i_defkid);
695*90b80121SDavid van Moolenbroek for (i = 0; i < IEEE80211_WEP_NKID; i++) {
696*90b80121SDavid van Moolenbroek if (i > 0)
697*90b80121SDavid van Moolenbroek printf(",");
698*90b80121SDavid van Moolenbroek if (nwkey.i_key[i].i_keylen < 0)
699*90b80121SDavid van Moolenbroek printf("persist");
700*90b80121SDavid van Moolenbroek else
701*90b80121SDavid van Moolenbroek print_string(nwkey.i_key[i].i_keydat,
702*90b80121SDavid van Moolenbroek nwkey.i_key[i].i_keylen);
703*90b80121SDavid van Moolenbroek if (!nwkey_verbose)
704*90b80121SDavid van Moolenbroek break;
705*90b80121SDavid van Moolenbroek }
706*90b80121SDavid van Moolenbroek }
707*90b80121SDavid van Moolenbroek printf("\n");
708*90b80121SDavid van Moolenbroek
709*90b80121SDavid van Moolenbroek skip_wep:
710*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211POWER, &power) == -1)
711*90b80121SDavid van Moolenbroek goto skip_power;
712*90b80121SDavid van Moolenbroek printf("\tpowersave ");
713*90b80121SDavid van Moolenbroek if (power.i_enabled)
714*90b80121SDavid van Moolenbroek printf("on (%dms sleep)", power.i_maxsleep);
715*90b80121SDavid van Moolenbroek else
716*90b80121SDavid van Moolenbroek printf("off");
717*90b80121SDavid van Moolenbroek printf("\n");
718*90b80121SDavid van Moolenbroek
719*90b80121SDavid van Moolenbroek skip_power:
720*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211BSSID, &bssid) == -1)
721*90b80121SDavid van Moolenbroek return;
722*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211CHANNEL, &channel) == -1)
723*90b80121SDavid van Moolenbroek return;
724*90b80121SDavid van Moolenbroek if (memcmp(bssid.i_bssid, zero_macaddr, IEEE80211_ADDR_LEN) == 0) {
725*90b80121SDavid van Moolenbroek if (channel.i_channel != (u_int16_t)-1)
726*90b80121SDavid van Moolenbroek printf("\tchan %d\n", channel.i_channel);
727*90b80121SDavid van Moolenbroek } else {
728*90b80121SDavid van Moolenbroek memcpy(ea.ether_addr_octet, bssid.i_bssid,
729*90b80121SDavid van Moolenbroek sizeof(ea.ether_addr_octet));
730*90b80121SDavid van Moolenbroek printf("\tbssid %s", ether_ntoa(&ea));
731*90b80121SDavid van Moolenbroek if (channel.i_channel != IEEE80211_CHAN_ANY)
732*90b80121SDavid van Moolenbroek printf(" chan %d", channel.i_channel);
733*90b80121SDavid van Moolenbroek printf("\n");
734*90b80121SDavid van Moolenbroek }
735*90b80121SDavid van Moolenbroek }
736*90b80121SDavid van Moolenbroek
737*90b80121SDavid van Moolenbroek static void
scan_and_wait(prop_dictionary_t env)738*90b80121SDavid van Moolenbroek scan_and_wait(prop_dictionary_t env)
739*90b80121SDavid van Moolenbroek {
740*90b80121SDavid van Moolenbroek int sroute;
741*90b80121SDavid van Moolenbroek
742*90b80121SDavid van Moolenbroek sroute = prog_socket(PF_ROUTE, SOCK_RAW, 0);
743*90b80121SDavid van Moolenbroek if (sroute < 0) {
744*90b80121SDavid van Moolenbroek warn("socket(PF_ROUTE,SOCK_RAW)");
745*90b80121SDavid van Moolenbroek return;
746*90b80121SDavid van Moolenbroek }
747*90b80121SDavid van Moolenbroek /* NB: only root can trigger a scan so ignore errors */
748*90b80121SDavid van Moolenbroek if (set80211(env, IEEE80211_IOC_SCAN_REQ, 0, 0, NULL) >= 0) {
749*90b80121SDavid van Moolenbroek char buf[2048];
750*90b80121SDavid van Moolenbroek struct if_announcemsghdr *ifan;
751*90b80121SDavid van Moolenbroek struct rt_msghdr *rtm;
752*90b80121SDavid van Moolenbroek
753*90b80121SDavid van Moolenbroek do {
754*90b80121SDavid van Moolenbroek if (prog_read(sroute, buf, sizeof(buf)) < 0) {
755*90b80121SDavid van Moolenbroek warn("read(PF_ROUTE)");
756*90b80121SDavid van Moolenbroek break;
757*90b80121SDavid van Moolenbroek }
758*90b80121SDavid van Moolenbroek rtm = (struct rt_msghdr *) buf;
759*90b80121SDavid van Moolenbroek if (rtm->rtm_version != RTM_VERSION)
760*90b80121SDavid van Moolenbroek break;
761*90b80121SDavid van Moolenbroek ifan = (struct if_announcemsghdr *) rtm;
762*90b80121SDavid van Moolenbroek } while (rtm->rtm_type != RTM_IEEE80211 ||
763*90b80121SDavid van Moolenbroek ifan->ifan_what != RTM_IEEE80211_SCAN);
764*90b80121SDavid van Moolenbroek }
765*90b80121SDavid van Moolenbroek prog_close(sroute);
766*90b80121SDavid van Moolenbroek }
767*90b80121SDavid van Moolenbroek
768*90b80121SDavid van Moolenbroek static void
list_scan(prop_dictionary_t env)769*90b80121SDavid van Moolenbroek list_scan(prop_dictionary_t env)
770*90b80121SDavid van Moolenbroek {
771*90b80121SDavid van Moolenbroek u_int8_t buf[24*1024];
772*90b80121SDavid van Moolenbroek struct ieee80211req ireq;
773*90b80121SDavid van Moolenbroek char ssid[IEEE80211_NWID_LEN+1];
774*90b80121SDavid van Moolenbroek const u_int8_t *cp;
775*90b80121SDavid van Moolenbroek int len, ssidmax;
776*90b80121SDavid van Moolenbroek
777*90b80121SDavid van Moolenbroek memset(&ireq, 0, sizeof(ireq));
778*90b80121SDavid van Moolenbroek ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
779*90b80121SDavid van Moolenbroek ireq.i_data = buf;
780*90b80121SDavid van Moolenbroek ireq.i_len = sizeof(buf);
781*90b80121SDavid van Moolenbroek if (direct_ioctl(env, SIOCG80211, &ireq) < 0)
782*90b80121SDavid van Moolenbroek errx(EXIT_FAILURE, "unable to get scan results");
783*90b80121SDavid van Moolenbroek len = ireq.i_len;
784*90b80121SDavid van Moolenbroek if (len < (int)sizeof(struct ieee80211req_scan_result))
785*90b80121SDavid van Moolenbroek return;
786*90b80121SDavid van Moolenbroek
787*90b80121SDavid van Moolenbroek ssidmax = IEEE80211_NWID_LEN;
788*90b80121SDavid van Moolenbroek printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n"
789*90b80121SDavid van Moolenbroek , ssidmax, ssidmax, "SSID"
790*90b80121SDavid van Moolenbroek , "BSSID"
791*90b80121SDavid van Moolenbroek , "CHAN"
792*90b80121SDavid van Moolenbroek , "RATE"
793*90b80121SDavid van Moolenbroek , "S:N"
794*90b80121SDavid van Moolenbroek , "INT"
795*90b80121SDavid van Moolenbroek , "CAPS"
796*90b80121SDavid van Moolenbroek );
797*90b80121SDavid van Moolenbroek cp = buf;
798*90b80121SDavid van Moolenbroek do {
799*90b80121SDavid van Moolenbroek const struct ieee80211req_scan_result *sr;
800*90b80121SDavid van Moolenbroek const uint8_t *vp;
801*90b80121SDavid van Moolenbroek
802*90b80121SDavid van Moolenbroek sr = (const struct ieee80211req_scan_result *) cp;
803*90b80121SDavid van Moolenbroek vp = (const u_int8_t *)(sr+1);
804*90b80121SDavid van Moolenbroek printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s"
805*90b80121SDavid van Moolenbroek , ssidmax
806*90b80121SDavid van Moolenbroek , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
807*90b80121SDavid van Moolenbroek , ssid
808*90b80121SDavid van Moolenbroek , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
809*90b80121SDavid van Moolenbroek , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
810*90b80121SDavid van Moolenbroek , getmaxrate(sr->isr_rates, sr->isr_nrates)
811*90b80121SDavid van Moolenbroek , sr->isr_rssi, sr->isr_noise
812*90b80121SDavid van Moolenbroek , sr->isr_intval
813*90b80121SDavid van Moolenbroek , getcaps(sr->isr_capinfo)
814*90b80121SDavid van Moolenbroek );
815*90b80121SDavid van Moolenbroek printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
816*90b80121SDavid van Moolenbroek printf("\n");
817*90b80121SDavid van Moolenbroek cp += sr->isr_len, len -= sr->isr_len;
818*90b80121SDavid van Moolenbroek } while (len >= (int)sizeof(struct ieee80211req_scan_result));
819*90b80121SDavid van Moolenbroek }
820*90b80121SDavid van Moolenbroek /*
821*90b80121SDavid van Moolenbroek * Convert MHz frequency to IEEE channel number.
822*90b80121SDavid van Moolenbroek */
823*90b80121SDavid van Moolenbroek static u_int
ieee80211_mhz2ieee(u_int isrfreq,u_int isrflags)824*90b80121SDavid van Moolenbroek ieee80211_mhz2ieee(u_int isrfreq, u_int isrflags)
825*90b80121SDavid van Moolenbroek {
826*90b80121SDavid van Moolenbroek if ((isrflags & IEEE80211_CHAN_GSM) || (907 <= isrfreq && isrfreq <= 922))
827*90b80121SDavid van Moolenbroek return mapgsm(isrfreq, isrflags);
828*90b80121SDavid van Moolenbroek if (isrfreq == 2484)
829*90b80121SDavid van Moolenbroek return 14;
830*90b80121SDavid van Moolenbroek if (isrfreq < 2484)
831*90b80121SDavid van Moolenbroek return (isrfreq - 2407) / 5;
832*90b80121SDavid van Moolenbroek if (isrfreq < 5000) {
833*90b80121SDavid van Moolenbroek if (isrflags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER))
834*90b80121SDavid van Moolenbroek return mappsb(isrfreq, isrflags);
835*90b80121SDavid van Moolenbroek else if (isrfreq > 4900)
836*90b80121SDavid van Moolenbroek return (isrfreq - 4000) / 5;
837*90b80121SDavid van Moolenbroek else
838*90b80121SDavid van Moolenbroek return 15 + ((isrfreq - 2512) / 20);
839*90b80121SDavid van Moolenbroek }
840*90b80121SDavid van Moolenbroek return (isrfreq - 5000) / 5;
841*90b80121SDavid van Moolenbroek }
842*90b80121SDavid van Moolenbroek
843*90b80121SDavid van Moolenbroek static int
getmaxrate(const u_int8_t rates[15],u_int8_t nrates)844*90b80121SDavid van Moolenbroek getmaxrate(const u_int8_t rates[15], u_int8_t nrates)
845*90b80121SDavid van Moolenbroek {
846*90b80121SDavid van Moolenbroek int i, maxrate = -1;
847*90b80121SDavid van Moolenbroek
848*90b80121SDavid van Moolenbroek for (i = 0; i < nrates; i++) {
849*90b80121SDavid van Moolenbroek int rate = rates[i] & IEEE80211_RATE_VAL;
850*90b80121SDavid van Moolenbroek if (rate > maxrate)
851*90b80121SDavid van Moolenbroek maxrate = rate;
852*90b80121SDavid van Moolenbroek }
853*90b80121SDavid van Moolenbroek return maxrate / 2;
854*90b80121SDavid van Moolenbroek }
855*90b80121SDavid van Moolenbroek
856*90b80121SDavid van Moolenbroek static const char *
getcaps(int capinfo)857*90b80121SDavid van Moolenbroek getcaps(int capinfo)
858*90b80121SDavid van Moolenbroek {
859*90b80121SDavid van Moolenbroek static char capstring[32];
860*90b80121SDavid van Moolenbroek char *cp = capstring;
861*90b80121SDavid van Moolenbroek
862*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_ESS)
863*90b80121SDavid van Moolenbroek *cp++ = 'E';
864*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_IBSS)
865*90b80121SDavid van Moolenbroek *cp++ = 'I';
866*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
867*90b80121SDavid van Moolenbroek *cp++ = 'c';
868*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
869*90b80121SDavid van Moolenbroek *cp++ = 'C';
870*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_PRIVACY)
871*90b80121SDavid van Moolenbroek *cp++ = 'P';
872*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
873*90b80121SDavid van Moolenbroek *cp++ = 'S';
874*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_PBCC)
875*90b80121SDavid van Moolenbroek *cp++ = 'B';
876*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
877*90b80121SDavid van Moolenbroek *cp++ = 'A';
878*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
879*90b80121SDavid van Moolenbroek *cp++ = 's';
880*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_RSN)
881*90b80121SDavid van Moolenbroek *cp++ = 'R';
882*90b80121SDavid van Moolenbroek if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
883*90b80121SDavid van Moolenbroek *cp++ = 'D';
884*90b80121SDavid van Moolenbroek *cp = '\0';
885*90b80121SDavid van Moolenbroek return capstring;
886*90b80121SDavid van Moolenbroek }
887*90b80121SDavid van Moolenbroek
888*90b80121SDavid van Moolenbroek static void
printie(const char * tag,const uint8_t * ie,size_t ielen,int maxlen)889*90b80121SDavid van Moolenbroek printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
890*90b80121SDavid van Moolenbroek {
891*90b80121SDavid van Moolenbroek printf("%s", tag);
892*90b80121SDavid van Moolenbroek
893*90b80121SDavid van Moolenbroek maxlen -= strlen(tag)+2;
894*90b80121SDavid van Moolenbroek if ((int)(2*ielen) > maxlen)
895*90b80121SDavid van Moolenbroek maxlen--;
896*90b80121SDavid van Moolenbroek printf("<");
897*90b80121SDavid van Moolenbroek for (; ielen > 0; ie++, ielen--) {
898*90b80121SDavid van Moolenbroek if (maxlen-- <= 0)
899*90b80121SDavid van Moolenbroek break;
900*90b80121SDavid van Moolenbroek printf("%02x", *ie);
901*90b80121SDavid van Moolenbroek }
902*90b80121SDavid van Moolenbroek if (ielen != 0)
903*90b80121SDavid van Moolenbroek printf("-");
904*90b80121SDavid van Moolenbroek printf(">");
905*90b80121SDavid van Moolenbroek }
906*90b80121SDavid van Moolenbroek
907*90b80121SDavid van Moolenbroek #define LE_READ_2(p) \
908*90b80121SDavid van Moolenbroek ((u_int16_t) \
909*90b80121SDavid van Moolenbroek ((((const u_int8_t *)(p))[0] ) | \
910*90b80121SDavid van Moolenbroek (((const u_int8_t *)(p))[1] << 8)))
911*90b80121SDavid van Moolenbroek #define LE_READ_4(p) \
912*90b80121SDavid van Moolenbroek ((u_int32_t) \
913*90b80121SDavid van Moolenbroek ((((const u_int8_t *)(p))[0] ) | \
914*90b80121SDavid van Moolenbroek (((const u_int8_t *)(p))[1] << 8) | \
915*90b80121SDavid van Moolenbroek (((const u_int8_t *)(p))[2] << 16) | \
916*90b80121SDavid van Moolenbroek (((const u_int8_t *)(p))[3] << 24)))
917*90b80121SDavid van Moolenbroek
918*90b80121SDavid van Moolenbroek /*
919*90b80121SDavid van Moolenbroek * NB: The decoding routines assume a properly formatted ie
920*90b80121SDavid van Moolenbroek * which should be safe as the kernel only retains them
921*90b80121SDavid van Moolenbroek * if they parse ok.
922*90b80121SDavid van Moolenbroek */
923*90b80121SDavid van Moolenbroek
924*90b80121SDavid van Moolenbroek static void
printwmeparam(const char * tag,const u_int8_t * ie,size_t ielen,int maxlen)925*90b80121SDavid van Moolenbroek printwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
926*90b80121SDavid van Moolenbroek {
927*90b80121SDavid van Moolenbroek #define MS(_v, _f) (((_v) & _f) >> _f##_S)
928*90b80121SDavid van Moolenbroek static const char *acnames[] = { "BE", "BK", "VO", "VI" };
929*90b80121SDavid van Moolenbroek const struct ieee80211_wme_param *wme =
930*90b80121SDavid van Moolenbroek (const struct ieee80211_wme_param *) ie;
931*90b80121SDavid van Moolenbroek int i;
932*90b80121SDavid van Moolenbroek
933*90b80121SDavid van Moolenbroek printf("%s", tag);
934*90b80121SDavid van Moolenbroek if (!vflag)
935*90b80121SDavid van Moolenbroek return;
936*90b80121SDavid van Moolenbroek printf("<qosinfo 0x%x", wme->param_qosInfo);
937*90b80121SDavid van Moolenbroek ie += offsetof(struct ieee80211_wme_param, params_acParams);
938*90b80121SDavid van Moolenbroek for (i = 0; i < WME_NUM_AC; i++) {
939*90b80121SDavid van Moolenbroek const struct ieee80211_wme_acparams *ac =
940*90b80121SDavid van Moolenbroek &wme->params_acParams[i];
941*90b80121SDavid van Moolenbroek
942*90b80121SDavid van Moolenbroek printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]"
943*90b80121SDavid van Moolenbroek , acnames[i]
944*90b80121SDavid van Moolenbroek , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : ""
945*90b80121SDavid van Moolenbroek , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN)
946*90b80121SDavid van Moolenbroek , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN)
947*90b80121SDavid van Moolenbroek , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX)
948*90b80121SDavid van Moolenbroek , LE_READ_2(&ac->acp_txop)
949*90b80121SDavid van Moolenbroek );
950*90b80121SDavid van Moolenbroek }
951*90b80121SDavid van Moolenbroek printf(">");
952*90b80121SDavid van Moolenbroek #undef MS
953*90b80121SDavid van Moolenbroek }
954*90b80121SDavid van Moolenbroek
955*90b80121SDavid van Moolenbroek static void
printwmeinfo(const char * tag,const u_int8_t * ie,size_t ielen,int maxlen)956*90b80121SDavid van Moolenbroek printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
957*90b80121SDavid van Moolenbroek {
958*90b80121SDavid van Moolenbroek printf("%s", tag);
959*90b80121SDavid van Moolenbroek if (vflag) {
960*90b80121SDavid van Moolenbroek const struct ieee80211_wme_info *wme =
961*90b80121SDavid van Moolenbroek (const struct ieee80211_wme_info *) ie;
962*90b80121SDavid van Moolenbroek printf("<version 0x%x info 0x%x>",
963*90b80121SDavid van Moolenbroek wme->wme_version, wme->wme_info);
964*90b80121SDavid van Moolenbroek }
965*90b80121SDavid van Moolenbroek }
966*90b80121SDavid van Moolenbroek
967*90b80121SDavid van Moolenbroek static const char *
wpa_cipher(const u_int8_t * sel)968*90b80121SDavid van Moolenbroek wpa_cipher(const u_int8_t *sel)
969*90b80121SDavid van Moolenbroek {
970*90b80121SDavid van Moolenbroek #define WPA_SEL(x) (((x)<<24)|WPA_OUI)
971*90b80121SDavid van Moolenbroek u_int32_t w = LE_READ_4(sel);
972*90b80121SDavid van Moolenbroek
973*90b80121SDavid van Moolenbroek switch (w) {
974*90b80121SDavid van Moolenbroek case WPA_SEL(WPA_CSE_NULL):
975*90b80121SDavid van Moolenbroek return "NONE";
976*90b80121SDavid van Moolenbroek case WPA_SEL(WPA_CSE_WEP40):
977*90b80121SDavid van Moolenbroek return "WEP40";
978*90b80121SDavid van Moolenbroek case WPA_SEL(WPA_CSE_WEP104):
979*90b80121SDavid van Moolenbroek return "WEP104";
980*90b80121SDavid van Moolenbroek case WPA_SEL(WPA_CSE_TKIP):
981*90b80121SDavid van Moolenbroek return "TKIP";
982*90b80121SDavid van Moolenbroek case WPA_SEL(WPA_CSE_CCMP):
983*90b80121SDavid van Moolenbroek return "AES-CCMP";
984*90b80121SDavid van Moolenbroek }
985*90b80121SDavid van Moolenbroek return "?"; /* NB: so 1<< is discarded */
986*90b80121SDavid van Moolenbroek #undef WPA_SEL
987*90b80121SDavid van Moolenbroek }
988*90b80121SDavid van Moolenbroek
989*90b80121SDavid van Moolenbroek static const char *
wpa_keymgmt(const u_int8_t * sel)990*90b80121SDavid van Moolenbroek wpa_keymgmt(const u_int8_t *sel)
991*90b80121SDavid van Moolenbroek {
992*90b80121SDavid van Moolenbroek #define WPA_SEL(x) (((x)<<24)|WPA_OUI)
993*90b80121SDavid van Moolenbroek u_int32_t w = LE_READ_4(sel);
994*90b80121SDavid van Moolenbroek
995*90b80121SDavid van Moolenbroek switch (w) {
996*90b80121SDavid van Moolenbroek case WPA_SEL(WPA_ASE_8021X_UNSPEC):
997*90b80121SDavid van Moolenbroek return "8021X-UNSPEC";
998*90b80121SDavid van Moolenbroek case WPA_SEL(WPA_ASE_8021X_PSK):
999*90b80121SDavid van Moolenbroek return "8021X-PSK";
1000*90b80121SDavid van Moolenbroek case WPA_SEL(WPA_ASE_NONE):
1001*90b80121SDavid van Moolenbroek return "NONE";
1002*90b80121SDavid van Moolenbroek }
1003*90b80121SDavid van Moolenbroek return "?";
1004*90b80121SDavid van Moolenbroek #undef WPA_SEL
1005*90b80121SDavid van Moolenbroek }
1006*90b80121SDavid van Moolenbroek
1007*90b80121SDavid van Moolenbroek static void
printwpaie(const char * tag,const u_int8_t * ie,size_t ielen,int maxlen)1008*90b80121SDavid van Moolenbroek printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1009*90b80121SDavid van Moolenbroek {
1010*90b80121SDavid van Moolenbroek u_int8_t len = ie[1];
1011*90b80121SDavid van Moolenbroek
1012*90b80121SDavid van Moolenbroek printf("%s", tag);
1013*90b80121SDavid van Moolenbroek if (vflag) {
1014*90b80121SDavid van Moolenbroek const char *sep;
1015*90b80121SDavid van Moolenbroek int n;
1016*90b80121SDavid van Moolenbroek
1017*90b80121SDavid van Moolenbroek ie += 6, len -= 4; /* NB: len is payload only */
1018*90b80121SDavid van Moolenbroek
1019*90b80121SDavid van Moolenbroek printf("<v%u", LE_READ_2(ie));
1020*90b80121SDavid van Moolenbroek ie += 2, len -= 2;
1021*90b80121SDavid van Moolenbroek
1022*90b80121SDavid van Moolenbroek printf(" mc:%s", wpa_cipher(ie));
1023*90b80121SDavid van Moolenbroek ie += 4, len -= 4;
1024*90b80121SDavid van Moolenbroek
1025*90b80121SDavid van Moolenbroek /* unicast ciphers */
1026*90b80121SDavid van Moolenbroek n = LE_READ_2(ie);
1027*90b80121SDavid van Moolenbroek ie += 2, len -= 2;
1028*90b80121SDavid van Moolenbroek sep = " uc:";
1029*90b80121SDavid van Moolenbroek for (; n > 0; n--) {
1030*90b80121SDavid van Moolenbroek printf("%s%s", sep, wpa_cipher(ie));
1031*90b80121SDavid van Moolenbroek ie += 4, len -= 4;
1032*90b80121SDavid van Moolenbroek sep = "+";
1033*90b80121SDavid van Moolenbroek }
1034*90b80121SDavid van Moolenbroek
1035*90b80121SDavid van Moolenbroek /* key management algorithms */
1036*90b80121SDavid van Moolenbroek n = LE_READ_2(ie);
1037*90b80121SDavid van Moolenbroek ie += 2, len -= 2;
1038*90b80121SDavid van Moolenbroek sep = " km:";
1039*90b80121SDavid van Moolenbroek for (; n > 0; n--) {
1040*90b80121SDavid van Moolenbroek printf("%s%s", sep, wpa_keymgmt(ie));
1041*90b80121SDavid van Moolenbroek ie += 4, len -= 4;
1042*90b80121SDavid van Moolenbroek sep = "+";
1043*90b80121SDavid van Moolenbroek }
1044*90b80121SDavid van Moolenbroek
1045*90b80121SDavid van Moolenbroek if (len > 2) /* optional capabilities */
1046*90b80121SDavid van Moolenbroek printf(", caps 0x%x", LE_READ_2(ie));
1047*90b80121SDavid van Moolenbroek printf(">");
1048*90b80121SDavid van Moolenbroek }
1049*90b80121SDavid van Moolenbroek }
1050*90b80121SDavid van Moolenbroek
1051*90b80121SDavid van Moolenbroek static const char *
rsn_cipher(const u_int8_t * sel)1052*90b80121SDavid van Moolenbroek rsn_cipher(const u_int8_t *sel)
1053*90b80121SDavid van Moolenbroek {
1054*90b80121SDavid van Moolenbroek #define RSN_SEL(x) (((x)<<24)|RSN_OUI)
1055*90b80121SDavid van Moolenbroek u_int32_t w = LE_READ_4(sel);
1056*90b80121SDavid van Moolenbroek
1057*90b80121SDavid van Moolenbroek switch (w) {
1058*90b80121SDavid van Moolenbroek case RSN_SEL(RSN_CSE_NULL):
1059*90b80121SDavid van Moolenbroek return "NONE";
1060*90b80121SDavid van Moolenbroek case RSN_SEL(RSN_CSE_WEP40):
1061*90b80121SDavid van Moolenbroek return "WEP40";
1062*90b80121SDavid van Moolenbroek case RSN_SEL(RSN_CSE_WEP104):
1063*90b80121SDavid van Moolenbroek return "WEP104";
1064*90b80121SDavid van Moolenbroek case RSN_SEL(RSN_CSE_TKIP):
1065*90b80121SDavid van Moolenbroek return "TKIP";
1066*90b80121SDavid van Moolenbroek case RSN_SEL(RSN_CSE_CCMP):
1067*90b80121SDavid van Moolenbroek return "AES-CCMP";
1068*90b80121SDavid van Moolenbroek case RSN_SEL(RSN_CSE_WRAP):
1069*90b80121SDavid van Moolenbroek return "AES-OCB";
1070*90b80121SDavid van Moolenbroek }
1071*90b80121SDavid van Moolenbroek return "?";
1072*90b80121SDavid van Moolenbroek #undef WPA_SEL
1073*90b80121SDavid van Moolenbroek }
1074*90b80121SDavid van Moolenbroek
1075*90b80121SDavid van Moolenbroek static const char *
rsn_keymgmt(const u_int8_t * sel)1076*90b80121SDavid van Moolenbroek rsn_keymgmt(const u_int8_t *sel)
1077*90b80121SDavid van Moolenbroek {
1078*90b80121SDavid van Moolenbroek #define RSN_SEL(x) (((x)<<24)|RSN_OUI)
1079*90b80121SDavid van Moolenbroek u_int32_t w = LE_READ_4(sel);
1080*90b80121SDavid van Moolenbroek
1081*90b80121SDavid van Moolenbroek switch (w) {
1082*90b80121SDavid van Moolenbroek case RSN_SEL(RSN_ASE_8021X_UNSPEC):
1083*90b80121SDavid van Moolenbroek return "8021X-UNSPEC";
1084*90b80121SDavid van Moolenbroek case RSN_SEL(RSN_ASE_8021X_PSK):
1085*90b80121SDavid van Moolenbroek return "8021X-PSK";
1086*90b80121SDavid van Moolenbroek case RSN_SEL(RSN_ASE_NONE):
1087*90b80121SDavid van Moolenbroek return "NONE";
1088*90b80121SDavid van Moolenbroek }
1089*90b80121SDavid van Moolenbroek return "?";
1090*90b80121SDavid van Moolenbroek #undef RSN_SEL
1091*90b80121SDavid van Moolenbroek }
1092*90b80121SDavid van Moolenbroek
1093*90b80121SDavid van Moolenbroek static void
printrsnie(const char * tag,const u_int8_t * ie,size_t ielen,int maxlen)1094*90b80121SDavid van Moolenbroek printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1095*90b80121SDavid van Moolenbroek {
1096*90b80121SDavid van Moolenbroek const char *sep;
1097*90b80121SDavid van Moolenbroek int n;
1098*90b80121SDavid van Moolenbroek
1099*90b80121SDavid van Moolenbroek printf("%s", tag);
1100*90b80121SDavid van Moolenbroek if (!vflag)
1101*90b80121SDavid van Moolenbroek return;
1102*90b80121SDavid van Moolenbroek
1103*90b80121SDavid van Moolenbroek ie += 2, ielen -= 2;
1104*90b80121SDavid van Moolenbroek
1105*90b80121SDavid van Moolenbroek printf("<v%u", LE_READ_2(ie));
1106*90b80121SDavid van Moolenbroek ie += 2, ielen -= 2;
1107*90b80121SDavid van Moolenbroek
1108*90b80121SDavid van Moolenbroek printf(" mc:%s", rsn_cipher(ie));
1109*90b80121SDavid van Moolenbroek ie += 4, ielen -= 4;
1110*90b80121SDavid van Moolenbroek
1111*90b80121SDavid van Moolenbroek /* unicast ciphers */
1112*90b80121SDavid van Moolenbroek n = LE_READ_2(ie);
1113*90b80121SDavid van Moolenbroek ie += 2, ielen -= 2;
1114*90b80121SDavid van Moolenbroek sep = " uc:";
1115*90b80121SDavid van Moolenbroek for (; n > 0; n--) {
1116*90b80121SDavid van Moolenbroek printf("%s%s", sep, rsn_cipher(ie));
1117*90b80121SDavid van Moolenbroek ie += 4, ielen -= 4;
1118*90b80121SDavid van Moolenbroek sep = "+";
1119*90b80121SDavid van Moolenbroek }
1120*90b80121SDavid van Moolenbroek
1121*90b80121SDavid van Moolenbroek /* key management algorithms */
1122*90b80121SDavid van Moolenbroek n = LE_READ_2(ie);
1123*90b80121SDavid van Moolenbroek ie += 2, ielen -= 2;
1124*90b80121SDavid van Moolenbroek sep = " km:";
1125*90b80121SDavid van Moolenbroek for (; n > 0; n--) {
1126*90b80121SDavid van Moolenbroek printf("%s%s", sep, rsn_keymgmt(ie));
1127*90b80121SDavid van Moolenbroek ie += 4, ielen -= 4;
1128*90b80121SDavid van Moolenbroek sep = "+";
1129*90b80121SDavid van Moolenbroek }
1130*90b80121SDavid van Moolenbroek
1131*90b80121SDavid van Moolenbroek if (ielen > 2) /* optional capabilities */
1132*90b80121SDavid van Moolenbroek printf(", caps 0x%x", LE_READ_2(ie));
1133*90b80121SDavid van Moolenbroek /* XXXPMKID */
1134*90b80121SDavid van Moolenbroek printf(">");
1135*90b80121SDavid van Moolenbroek }
1136*90b80121SDavid van Moolenbroek
1137*90b80121SDavid van Moolenbroek /*
1138*90b80121SDavid van Moolenbroek * Copy the ssid string contents into buf, truncating to fit. If the
1139*90b80121SDavid van Moolenbroek * ssid is entirely printable then just copy intact. Otherwise convert
1140*90b80121SDavid van Moolenbroek * to hexadecimal. If the result is truncated then replace the last
1141*90b80121SDavid van Moolenbroek * three characters with "...".
1142*90b80121SDavid van Moolenbroek */
1143*90b80121SDavid van Moolenbroek static int
copy_essid(char buf[],size_t bufsize,const u_int8_t * essid,size_t essid_len)1144*90b80121SDavid van Moolenbroek copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
1145*90b80121SDavid van Moolenbroek {
1146*90b80121SDavid van Moolenbroek const u_int8_t *p;
1147*90b80121SDavid van Moolenbroek size_t maxlen, i;
1148*90b80121SDavid van Moolenbroek
1149*90b80121SDavid van Moolenbroek if (essid_len > bufsize)
1150*90b80121SDavid van Moolenbroek maxlen = bufsize;
1151*90b80121SDavid van Moolenbroek else
1152*90b80121SDavid van Moolenbroek maxlen = essid_len;
1153*90b80121SDavid van Moolenbroek /* determine printable or not */
1154*90b80121SDavid van Moolenbroek for (i = 0, p = essid; i < maxlen; i++, p++) {
1155*90b80121SDavid van Moolenbroek if (*p < ' ' || *p > 0x7e)
1156*90b80121SDavid van Moolenbroek break;
1157*90b80121SDavid van Moolenbroek }
1158*90b80121SDavid van Moolenbroek if (i != maxlen) { /* not printable, print as hex */
1159*90b80121SDavid van Moolenbroek if (bufsize < 3)
1160*90b80121SDavid van Moolenbroek return 0;
1161*90b80121SDavid van Moolenbroek strlcpy(buf, "0x", bufsize);
1162*90b80121SDavid van Moolenbroek bufsize -= 2;
1163*90b80121SDavid van Moolenbroek p = essid;
1164*90b80121SDavid van Moolenbroek for (i = 0; i < maxlen && bufsize >= 2; i++) {
1165*90b80121SDavid van Moolenbroek sprintf(&buf[2+2*i], "%02x", p[i]);
1166*90b80121SDavid van Moolenbroek bufsize -= 2;
1167*90b80121SDavid van Moolenbroek }
1168*90b80121SDavid van Moolenbroek if (i != essid_len)
1169*90b80121SDavid van Moolenbroek memcpy(&buf[2+2*i-3], "...", 3);
1170*90b80121SDavid van Moolenbroek } else { /* printable, truncate as needed */
1171*90b80121SDavid van Moolenbroek memcpy(buf, essid, maxlen);
1172*90b80121SDavid van Moolenbroek if (maxlen != essid_len)
1173*90b80121SDavid van Moolenbroek memcpy(&buf[maxlen-3], "...", 3);
1174*90b80121SDavid van Moolenbroek }
1175*90b80121SDavid van Moolenbroek return maxlen;
1176*90b80121SDavid van Moolenbroek }
1177*90b80121SDavid van Moolenbroek
1178*90b80121SDavid van Moolenbroek static void
printssid(const char * tag,const u_int8_t * ie,size_t ielen,int maxlen)1179*90b80121SDavid van Moolenbroek printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1180*90b80121SDavid van Moolenbroek {
1181*90b80121SDavid van Moolenbroek char ssid[2*IEEE80211_NWID_LEN+1];
1182*90b80121SDavid van Moolenbroek
1183*90b80121SDavid van Moolenbroek printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid);
1184*90b80121SDavid van Moolenbroek }
1185*90b80121SDavid van Moolenbroek
1186*90b80121SDavid van Moolenbroek static void
printrates(const char * tag,const u_int8_t * ie,size_t ielen,int maxlen)1187*90b80121SDavid van Moolenbroek printrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1188*90b80121SDavid van Moolenbroek {
1189*90b80121SDavid van Moolenbroek const char *sep;
1190*90b80121SDavid van Moolenbroek size_t i;
1191*90b80121SDavid van Moolenbroek
1192*90b80121SDavid van Moolenbroek printf("%s", tag);
1193*90b80121SDavid van Moolenbroek sep = "<";
1194*90b80121SDavid van Moolenbroek for (i = 2; i < ielen; i++) {
1195*90b80121SDavid van Moolenbroek printf("%s%s%d", sep,
1196*90b80121SDavid van Moolenbroek ie[i] & IEEE80211_RATE_BASIC ? "B" : "",
1197*90b80121SDavid van Moolenbroek ie[i] & IEEE80211_RATE_VAL);
1198*90b80121SDavid van Moolenbroek sep = ",";
1199*90b80121SDavid van Moolenbroek }
1200*90b80121SDavid van Moolenbroek printf(">");
1201*90b80121SDavid van Moolenbroek }
1202*90b80121SDavid van Moolenbroek
1203*90b80121SDavid van Moolenbroek static void
printcountry(const char * tag,const u_int8_t * ie,size_t ielen,int maxlen)1204*90b80121SDavid van Moolenbroek printcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1205*90b80121SDavid van Moolenbroek {
1206*90b80121SDavid van Moolenbroek const struct ieee80211_country_ie *cie =
1207*90b80121SDavid van Moolenbroek (const struct ieee80211_country_ie *) ie;
1208*90b80121SDavid van Moolenbroek int i, nbands, schan, nchan;
1209*90b80121SDavid van Moolenbroek
1210*90b80121SDavid van Moolenbroek printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]);
1211*90b80121SDavid van Moolenbroek nbands = (cie->len - 3) / sizeof(cie->band[0]);
1212*90b80121SDavid van Moolenbroek for (i = 0; i < nbands; i++) {
1213*90b80121SDavid van Moolenbroek schan = cie->band[i].schan;
1214*90b80121SDavid van Moolenbroek nchan = cie->band[i].nchan;
1215*90b80121SDavid van Moolenbroek if (nchan != 1)
1216*90b80121SDavid van Moolenbroek printf(" %u-%u,%u", schan, schan + nchan-1,
1217*90b80121SDavid van Moolenbroek cie->band[i].maxtxpwr);
1218*90b80121SDavid van Moolenbroek else
1219*90b80121SDavid van Moolenbroek printf(" %u,%u", schan, cie->band[i].maxtxpwr);
1220*90b80121SDavid van Moolenbroek }
1221*90b80121SDavid van Moolenbroek printf(">");
1222*90b80121SDavid van Moolenbroek }
1223*90b80121SDavid van Moolenbroek
1224*90b80121SDavid van Moolenbroek /* unaligned little endian access */
1225*90b80121SDavid van Moolenbroek #define LE_READ_4(p) \
1226*90b80121SDavid van Moolenbroek ((u_int32_t) \
1227*90b80121SDavid van Moolenbroek ((((const u_int8_t *)(p))[0] ) | \
1228*90b80121SDavid van Moolenbroek (((const u_int8_t *)(p))[1] << 8) | \
1229*90b80121SDavid van Moolenbroek (((const u_int8_t *)(p))[2] << 16) | \
1230*90b80121SDavid van Moolenbroek (((const u_int8_t *)(p))[3] << 24)))
1231*90b80121SDavid van Moolenbroek
1232*90b80121SDavid van Moolenbroek static int
iswpaoui(const u_int8_t * frm)1233*90b80121SDavid van Moolenbroek iswpaoui(const u_int8_t *frm)
1234*90b80121SDavid van Moolenbroek {
1235*90b80121SDavid van Moolenbroek return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
1236*90b80121SDavid van Moolenbroek }
1237*90b80121SDavid van Moolenbroek
1238*90b80121SDavid van Moolenbroek static int
iswmeinfo(const u_int8_t * frm)1239*90b80121SDavid van Moolenbroek iswmeinfo(const u_int8_t *frm)
1240*90b80121SDavid van Moolenbroek {
1241*90b80121SDavid van Moolenbroek return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
1242*90b80121SDavid van Moolenbroek frm[6] == WME_INFO_OUI_SUBTYPE;
1243*90b80121SDavid van Moolenbroek }
1244*90b80121SDavid van Moolenbroek
1245*90b80121SDavid van Moolenbroek static int
iswmeparam(const u_int8_t * frm)1246*90b80121SDavid van Moolenbroek iswmeparam(const u_int8_t *frm)
1247*90b80121SDavid van Moolenbroek {
1248*90b80121SDavid van Moolenbroek return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
1249*90b80121SDavid van Moolenbroek frm[6] == WME_PARAM_OUI_SUBTYPE;
1250*90b80121SDavid van Moolenbroek }
1251*90b80121SDavid van Moolenbroek
1252*90b80121SDavid van Moolenbroek static const char *
iename(int elemid)1253*90b80121SDavid van Moolenbroek iename(int elemid)
1254*90b80121SDavid van Moolenbroek {
1255*90b80121SDavid van Moolenbroek switch (elemid) {
1256*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_FHPARMS: return " FHPARMS";
1257*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_CFPARMS: return " CFPARMS";
1258*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_TIM: return " TIM";
1259*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS";
1260*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE";
1261*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR";
1262*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_PWRCAP: return " PWRCAP";
1263*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_TPCREQ: return " TPCREQ";
1264*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_TPCREP: return " TPCREP";
1265*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN";
1266*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_CHANSWITCHANN:return " CSA";
1267*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_MEASREQ: return " MEASREQ";
1268*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_MEASREP: return " MEASREP";
1269*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_QUIET: return " QUIET";
1270*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS";
1271*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_TPC: return " TPC";
1272*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_CCKM: return " CCKM";
1273*90b80121SDavid van Moolenbroek }
1274*90b80121SDavid van Moolenbroek return " ???";
1275*90b80121SDavid van Moolenbroek }
1276*90b80121SDavid van Moolenbroek
1277*90b80121SDavid van Moolenbroek static void
printies(const u_int8_t * vp,int ielen,int maxcols)1278*90b80121SDavid van Moolenbroek printies(const u_int8_t *vp, int ielen, int maxcols)
1279*90b80121SDavid van Moolenbroek {
1280*90b80121SDavid van Moolenbroek while (ielen > 0) {
1281*90b80121SDavid van Moolenbroek switch (vp[0]) {
1282*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_SSID:
1283*90b80121SDavid van Moolenbroek if (vflag)
1284*90b80121SDavid van Moolenbroek printssid(" SSID", vp, 2+vp[1], maxcols);
1285*90b80121SDavid van Moolenbroek break;
1286*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_RATES:
1287*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_XRATES:
1288*90b80121SDavid van Moolenbroek if (vflag)
1289*90b80121SDavid van Moolenbroek printrates(vp[0] == IEEE80211_ELEMID_RATES ?
1290*90b80121SDavid van Moolenbroek " RATES" : " XRATES", vp, 2+vp[1], maxcols);
1291*90b80121SDavid van Moolenbroek break;
1292*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_DSPARMS:
1293*90b80121SDavid van Moolenbroek if (vflag)
1294*90b80121SDavid van Moolenbroek printf(" DSPARMS<%u>", vp[2]);
1295*90b80121SDavid van Moolenbroek break;
1296*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_COUNTRY:
1297*90b80121SDavid van Moolenbroek if (vflag)
1298*90b80121SDavid van Moolenbroek printcountry(" COUNTRY", vp, 2+vp[1], maxcols);
1299*90b80121SDavid van Moolenbroek break;
1300*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_ERP:
1301*90b80121SDavid van Moolenbroek if (vflag)
1302*90b80121SDavid van Moolenbroek printf(" ERP<0x%x>", vp[2]);
1303*90b80121SDavid van Moolenbroek break;
1304*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_VENDOR:
1305*90b80121SDavid van Moolenbroek if (iswpaoui(vp))
1306*90b80121SDavid van Moolenbroek printwpaie(" WPA", vp, 2+vp[1], maxcols);
1307*90b80121SDavid van Moolenbroek else if (iswmeinfo(vp))
1308*90b80121SDavid van Moolenbroek printwmeinfo(" WME", vp, 2+vp[1], maxcols);
1309*90b80121SDavid van Moolenbroek else if (iswmeparam(vp))
1310*90b80121SDavid van Moolenbroek printwmeparam(" WME", vp, 2+vp[1], maxcols);
1311*90b80121SDavid van Moolenbroek else if (vflag)
1312*90b80121SDavid van Moolenbroek printie(" VEN", vp, 2+vp[1], maxcols);
1313*90b80121SDavid van Moolenbroek break;
1314*90b80121SDavid van Moolenbroek case IEEE80211_ELEMID_RSN:
1315*90b80121SDavid van Moolenbroek printrsnie(" RSN", vp, 2+vp[1], maxcols);
1316*90b80121SDavid van Moolenbroek break;
1317*90b80121SDavid van Moolenbroek default:
1318*90b80121SDavid van Moolenbroek if (vflag)
1319*90b80121SDavid van Moolenbroek printie(iename(vp[0]), vp, 2+vp[1], maxcols);
1320*90b80121SDavid van Moolenbroek break;
1321*90b80121SDavid van Moolenbroek }
1322*90b80121SDavid van Moolenbroek ielen -= 2+vp[1];
1323*90b80121SDavid van Moolenbroek vp += 2+vp[1];
1324*90b80121SDavid van Moolenbroek }
1325*90b80121SDavid van Moolenbroek }
1326*90b80121SDavid van Moolenbroek
1327*90b80121SDavid van Moolenbroek static int
mapgsm(u_int isrfreq,u_int isrflags)1328*90b80121SDavid van Moolenbroek mapgsm(u_int isrfreq, u_int isrflags)
1329*90b80121SDavid van Moolenbroek {
1330*90b80121SDavid van Moolenbroek isrfreq *= 10;
1331*90b80121SDavid van Moolenbroek if (isrflags & IEEE80211_CHAN_QUARTER)
1332*90b80121SDavid van Moolenbroek isrfreq += 5;
1333*90b80121SDavid van Moolenbroek else if (isrflags & IEEE80211_CHAN_HALF)
1334*90b80121SDavid van Moolenbroek isrfreq += 10;
1335*90b80121SDavid van Moolenbroek else
1336*90b80121SDavid van Moolenbroek isrfreq += 20;
1337*90b80121SDavid van Moolenbroek /* NB: there is no 907/20 wide but leave room */
1338*90b80121SDavid van Moolenbroek return (isrfreq - 906*10) / 5;
1339*90b80121SDavid van Moolenbroek }
1340*90b80121SDavid van Moolenbroek
1341*90b80121SDavid van Moolenbroek static int
mappsb(u_int isrfreq,u_int isrflags)1342*90b80121SDavid van Moolenbroek mappsb(u_int isrfreq, u_int isrflags)
1343*90b80121SDavid van Moolenbroek {
1344*90b80121SDavid van Moolenbroek return 37 + ((isrfreq * 10) + ((isrfreq % 5) == 2 ? 5 : 0) - 49400) / 5;
1345*90b80121SDavid van Moolenbroek }
1346*90b80121SDavid van Moolenbroek
1347*90b80121SDavid van Moolenbroek static status_func_t status;
1348*90b80121SDavid van Moolenbroek static usage_func_t usage;
1349*90b80121SDavid van Moolenbroek static statistics_func_t statistics;
1350*90b80121SDavid van Moolenbroek static cmdloop_branch_t branch[2];
1351*90b80121SDavid van Moolenbroek
1352*90b80121SDavid van Moolenbroek static void
ieee80211_usage(prop_dictionary_t env)1353*90b80121SDavid van Moolenbroek ieee80211_usage(prop_dictionary_t env)
1354*90b80121SDavid van Moolenbroek {
1355*90b80121SDavid van Moolenbroek fprintf(stderr,
1356*90b80121SDavid van Moolenbroek "\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n"
1357*90b80121SDavid van Moolenbroek "\t[ list scan ]\n"
1358*90b80121SDavid van Moolenbroek "\t[ powersave | -powersave ] [ powersavesleep duration ]\n"
1359*90b80121SDavid van Moolenbroek "\t[ hidessid | -hidessid ] [ apbridge | -apbridge ]\n");
1360*90b80121SDavid van Moolenbroek }
1361*90b80121SDavid van Moolenbroek
1362*90b80121SDavid van Moolenbroek static void
ieee80211_constructor(void)1363*90b80121SDavid van Moolenbroek ieee80211_constructor(void)
1364*90b80121SDavid van Moolenbroek {
1365*90b80121SDavid van Moolenbroek cmdloop_branch_init(&branch[0], &ieee80211bool.pk_parser);
1366*90b80121SDavid van Moolenbroek cmdloop_branch_init(&branch[1], &kw80211.pk_parser);
1367*90b80121SDavid van Moolenbroek register_cmdloop_branch(&branch[0]);
1368*90b80121SDavid van Moolenbroek register_cmdloop_branch(&branch[1]);
1369*90b80121SDavid van Moolenbroek status_func_init(&status, ieee80211_status);
1370*90b80121SDavid van Moolenbroek statistics_func_init(&statistics, ieee80211_statistics);
1371*90b80121SDavid van Moolenbroek usage_func_init(&usage, ieee80211_usage);
1372*90b80121SDavid van Moolenbroek register_status(&status);
1373*90b80121SDavid van Moolenbroek register_statistics(&statistics);
1374*90b80121SDavid van Moolenbroek register_usage(&usage);
1375*90b80121SDavid van Moolenbroek }
1376