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