nrelease - fix/improve livecd
[dragonfly.git] / sys / netproto / 802_11 / wlan / ieee80211.c
CommitLineData
32176cfd 1/*-
f186073c 2 * Copyright (c) 2001 Atsushi Onoe
32176cfd 3 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
f186073c
JS
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
f186073c
JS
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
f186073c
JS
25 */
26
085ff963
MD
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
f186073c
JS
30/*
31 * IEEE 802.11 generic handler
32 */
32176cfd 33#include "opt_wlan.h"
f186073c 34
f186073c 35#include <sys/param.h>
32176cfd 36#include <sys/systm.h>
f186073c 37#include <sys/kernel.h>
4f655ef5 38#include <sys/malloc.h>
841ab66c 39#include <sys/socket.h>
4f655ef5 40#include <sys/sbuf.h>
841ab66c 41
4f898719
IV
42#include <machine/stdarg.h>
43
f186073c 44#include <net/if.h>
085ff963 45#include <net/if_var.h>
32176cfd 46#include <net/if_dl.h>
841ab66c 47#include <net/if_media.h>
32176cfd 48#include <net/if_types.h>
f186073c 49#include <net/ethernet.h>
f186073c
JS
50
51#include <netproto/802_11/ieee80211_var.h>
32176cfd
RP
52#include <netproto/802_11/ieee80211_regdomain.h>
53#ifdef IEEE80211_SUPPORT_SUPERG
54#include <netproto/802_11/ieee80211_superg.h>
55#endif
4028af95 56#include <netproto/802_11/ieee80211_ratectl.h>
f186073c
JS
57
58#include <net/bpf.h>
59
32176cfd
RP
60const char *ieee80211_phymode_name[IEEE80211_MODE_MAX] = {
61 [IEEE80211_MODE_AUTO] = "auto",
62 [IEEE80211_MODE_11A] = "11a",
63 [IEEE80211_MODE_11B] = "11b",
64 [IEEE80211_MODE_11G] = "11g",
65 [IEEE80211_MODE_FH] = "FH",
66 [IEEE80211_MODE_TURBO_A] = "turboA",
67 [IEEE80211_MODE_TURBO_G] = "turboG",
68 [IEEE80211_MODE_STURBO_A] = "sturboA",
69 [IEEE80211_MODE_HALF] = "half",
70 [IEEE80211_MODE_QUARTER] = "quarter",
71 [IEEE80211_MODE_11NA] = "11na",
72 [IEEE80211_MODE_11NG] = "11ng",
797b05a5
AL
73 [IEEE80211_MODE_VHT_2GHZ] = "11acg",
74 [IEEE80211_MODE_VHT_5GHZ] = "11ac",
f186073c 75};
32176cfd
RP
76/* map ieee80211_opmode to the corresponding capability bit */
77const int ieee80211_opcap[IEEE80211_OPMODE_MAX] = {
78 [IEEE80211_M_IBSS] = IEEE80211_C_IBSS,
79 [IEEE80211_M_WDS] = IEEE80211_C_WDS,
80 [IEEE80211_M_STA] = IEEE80211_C_STA,
81 [IEEE80211_M_AHDEMO] = IEEE80211_C_AHDEMO,
82 [IEEE80211_M_HOSTAP] = IEEE80211_C_HOSTAP,
83 [IEEE80211_M_MONITOR] = IEEE80211_C_MONITOR,
84#ifdef IEEE80211_SUPPORT_MESH
85 [IEEE80211_M_MBSS] = IEEE80211_C_MBSS,
86#endif
87};
88
8daa6c6e 89const uint8_t ieee80211broadcastaddr[IEEE80211_ADDR_LEN] =
32176cfd
RP
90 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
91
92static void ieee80211_syncflag_locked(struct ieee80211com *ic, int flag);
93static void ieee80211_syncflag_ht_locked(struct ieee80211com *ic, int flag);
94static void ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag);
95static int ieee80211_media_setup(struct ieee80211com *ic,
96 struct ifmedia *media, int caps, int addsta,
97 ifm_change_cb_t media_change, ifm_stat_cb_t media_stat);
32176cfd
RP
98static int media_status(enum ieee80211_opmode,
99 const struct ieee80211_channel *);
4f655ef5
MD
100#if defined(__DragonFly__)
101#else
102static uint64_t ieee80211_get_counter(struct ifnet *, ift_counter);
103#endif
f186073c 104
32176cfd 105MALLOC_DEFINE(M_80211_VAP, "80211vap", "802.11 vap state");
841ab66c 106
32176cfd
RP
107/*
108 * Default supported rates for 802.11 operation (in IEEE .5Mb units).
109 */
110#define B(r) ((r) | IEEE80211_RATE_BASIC)
111static const struct ieee80211_rateset ieee80211_rateset_11a =
112 { 8, { B(12), 18, B(24), 36, B(48), 72, 96, 108 } };
113static const struct ieee80211_rateset ieee80211_rateset_half =
114 { 8, { B(6), 9, B(12), 18, B(24), 36, 48, 54 } };
115static const struct ieee80211_rateset ieee80211_rateset_quarter =
116 { 8, { B(3), 4, B(6), 9, B(12), 18, 24, 27 } };
117static const struct ieee80211_rateset ieee80211_rateset_11b =
118 { 4, { B(2), B(4), B(11), B(22) } };
119/* NB: OFDM rates are handled specially based on mode */
120static const struct ieee80211_rateset ieee80211_rateset_11g =
121 { 12, { B(2), B(4), B(11), B(22), 12, 18, 24, 36, 48, 72, 96, 108 } };
122#undef B
123
124/*
125 * Fill in 802.11 available channel set, mark
126 * all available channels as active, and pick
127 * a default channel if not already specified.
128 */
4f655ef5 129void
32176cfd 130ieee80211_chan_init(struct ieee80211com *ic)
841ab66c 131{
32176cfd
RP
132#define DEFAULTRATES(m, def) do { \
133 if (ic->ic_sup_rates[m].rs_nrates == 0) \
134 ic->ic_sup_rates[m] = def; \
135} while (0)
136 struct ieee80211_channel *c;
841ab66c 137 int i;
841ab66c 138
32176cfd
RP
139 KASSERT(0 < ic->ic_nchans && ic->ic_nchans <= IEEE80211_CHAN_MAX,
140 ("invalid number of channels specified: %u", ic->ic_nchans));
141 memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
142 memset(ic->ic_modecaps, 0, sizeof(ic->ic_modecaps));
143 setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO);
144 for (i = 0; i < ic->ic_nchans; i++) {
145 c = &ic->ic_channels[i];
146 KASSERT(c->ic_flags != 0, ("channel with no flags"));
147 /*
148 * Help drivers that work only with frequencies by filling
149 * in IEEE channel #'s if not already calculated. Note this
150 * mimics similar work done in ieee80211_setregdomain when
151 * changing regulatory state.
152 */
153 if (c->ic_ieee == 0)
154 c->ic_ieee = ieee80211_mhz2ieee(c->ic_freq,c->ic_flags);
155 if (IEEE80211_IS_CHAN_HT40(c) && c->ic_extieee == 0)
156 c->ic_extieee = ieee80211_mhz2ieee(c->ic_freq +
157 (IEEE80211_IS_CHAN_HT40U(c) ? 20 : -20),
158 c->ic_flags);
159 /* default max tx power to max regulatory */
160 if (c->ic_maxpower == 0)
161 c->ic_maxpower = 2*c->ic_maxregpower;
162 setbit(ic->ic_chan_avail, c->ic_ieee);
163 /*
164 * Identify mode capabilities.
165 */
166 if (IEEE80211_IS_CHAN_A(c))
167 setbit(ic->ic_modecaps, IEEE80211_MODE_11A);
168 if (IEEE80211_IS_CHAN_B(c))
169 setbit(ic->ic_modecaps, IEEE80211_MODE_11B);
170 if (IEEE80211_IS_CHAN_ANYG(c))
171 setbit(ic->ic_modecaps, IEEE80211_MODE_11G);
172 if (IEEE80211_IS_CHAN_FHSS(c))
173 setbit(ic->ic_modecaps, IEEE80211_MODE_FH);
174 if (IEEE80211_IS_CHAN_108A(c))
175 setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_A);
176 if (IEEE80211_IS_CHAN_108G(c))
177 setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_G);
178 if (IEEE80211_IS_CHAN_ST(c))
179 setbit(ic->ic_modecaps, IEEE80211_MODE_STURBO_A);
180 if (IEEE80211_IS_CHAN_HALF(c))
181 setbit(ic->ic_modecaps, IEEE80211_MODE_HALF);
182 if (IEEE80211_IS_CHAN_QUARTER(c))
183 setbit(ic->ic_modecaps, IEEE80211_MODE_QUARTER);
184 if (IEEE80211_IS_CHAN_HTA(c))
185 setbit(ic->ic_modecaps, IEEE80211_MODE_11NA);
186 if (IEEE80211_IS_CHAN_HTG(c))
187 setbit(ic->ic_modecaps, IEEE80211_MODE_11NG);
188 }
189 /* initialize candidate channels to all available */
190 memcpy(ic->ic_chan_active, ic->ic_chan_avail,
191 sizeof(ic->ic_chan_avail));
192
193 /* sort channel table to allow lookup optimizations */
194 ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans);
195
196 /* invalidate any previous state */
197 ic->ic_bsschan = IEEE80211_CHAN_ANYC;
198 ic->ic_prevchan = NULL;
199 ic->ic_csa_newchan = NULL;
200 /* arbitrarily pick the first channel */
201 ic->ic_curchan = &ic->ic_channels[0];
202 ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
203
204 /* fillin well-known rate sets if driver has not specified */
205 DEFAULTRATES(IEEE80211_MODE_11B, ieee80211_rateset_11b);
206 DEFAULTRATES(IEEE80211_MODE_11G, ieee80211_rateset_11g);
207 DEFAULTRATES(IEEE80211_MODE_11A, ieee80211_rateset_11a);
208 DEFAULTRATES(IEEE80211_MODE_TURBO_A, ieee80211_rateset_11a);
209 DEFAULTRATES(IEEE80211_MODE_TURBO_G, ieee80211_rateset_11g);
210 DEFAULTRATES(IEEE80211_MODE_STURBO_A, ieee80211_rateset_11a);
211 DEFAULTRATES(IEEE80211_MODE_HALF, ieee80211_rateset_half);
212 DEFAULTRATES(IEEE80211_MODE_QUARTER, ieee80211_rateset_quarter);
213 DEFAULTRATES(IEEE80211_MODE_11NA, ieee80211_rateset_11a);
214 DEFAULTRATES(IEEE80211_MODE_11NG, ieee80211_rateset_11g);
215
085ff963
MD
216 /*
217 * Setup required information to fill the mcsset field, if driver did
218 * not. Assume a 2T2R setup for historic reasons.
219 */
220 if (ic->ic_rxstream == 0)
221 ic->ic_rxstream = 2;
222 if (ic->ic_txstream == 0)
223 ic->ic_txstream = 2;
224
32176cfd
RP
225 /*
226 * Set auto mode to reset active channel state and any desired channel.
227 */
228 (void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO);
229#undef DEFAULTRATES
230}
841ab66c 231
32176cfd 232static void
4f898719 233null_update_mcast(struct ieee80211com *ic)
32176cfd 234{
4f655ef5 235
4f898719 236 ic_printf(ic, "need multicast update callback\n");
32176cfd 237}
841ab66c 238
32176cfd 239static void
4f898719 240null_update_promisc(struct ieee80211com *ic)
32176cfd 241{
32176cfd 242
4f655ef5 243 ic_printf(ic, "need promiscuous mode update callback\n");
32176cfd
RP
244}
245
085ff963
MD
246static void
247null_update_chw(struct ieee80211com *ic)
248{
249
4f898719
IV
250 ic_printf(ic, "%s: need callback\n", __func__);
251}
252
253int
254ic_printf(struct ieee80211com *ic, const char * fmt, ...)
255{
4f655ef5 256#if defined(__DragonFly__)
4f898719
IV
257 osdep_va_list ap;
258 int retval;
259
260 retval = kprintf("%s: ", ic->ic_name);
261 osdep_va_start(ap, fmt);
262 retval += kvprintf(fmt, ap);
263 osdep_va_end(ap);
4f655ef5
MD
264#else
265 va_list ap;
266 int retval;
267
268 retval = printf("%s: ", ic->ic_name);
269 va_start(ap, fmt);
270 retval += vprintf(fmt, ap);
271 va_end(ap);
272#endif
4f898719 273 return (retval);
085ff963
MD
274}
275
4f655ef5
MD
276static LIST_HEAD(, ieee80211com) ic_head = LIST_HEAD_INITIALIZER(ic_head);
277#if defined(__DragonFly__)
278static struct lock ic_list_lock =
279 LOCK_INITIALIZER("80211list", 0, LK_CANRECURSE);
280#else
281static struct mtx ic_list_mtx;
282MTX_SYSINIT(ic_list, &ic_list_mtx, "ieee80211com list", MTX_DEF);
283#endif
284
285static int
286sysctl_ieee80211coms(SYSCTL_HANDLER_ARGS)
287{
288 struct ieee80211com *ic;
289 struct sbuf sb;
290 char *sp;
291 int error;
292
293#if defined(__DragonFly__)
294#else
295 error = sysctl_wire_old_buffer(req, 0);
296 if (error)
297 return (error);
298#endif
299 sbuf_new_for_sysctl(&sb, NULL, 8, req);
300#if defined(__DragonFly__)
301#else
302 sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
303#endif
304 sp = "";
305#if defined(__DragonFly__)
306 lockmgr(&ic_list_lock, LK_EXCLUSIVE);
307#else
308 mtx_lock(&ic_list_mtx);
309#endif
310 LIST_FOREACH(ic, &ic_head, ic_next) {
311 sbuf_printf(&sb, "%s%s", sp, ic->ic_name);
312 sp = " ";
313 }
314#if defined(__DragonFly__)
315 lockmgr(&ic_list_lock, LK_RELEASE);
316#else
317 mtx_unlock(&ic_list_mtx);
318#endif
319 error = sbuf_finish(&sb);
320 sbuf_delete(&sb);
321 return (error);
322}
323
324#if defined(__DragonFly__)
325SYSCTL_PROC(_net_wlan, OID_AUTO, devices,
326 CTLTYPE_STRING | CTLFLAG_RD, NULL, 0,
327 sysctl_ieee80211coms, "A", "names of available 802.11 devices");
328#else
329SYSCTL_PROC(_net_wlan, OID_AUTO, devices,
330 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
331 sysctl_ieee80211coms, "A", "names of available 802.11 devices");
332#endif
333
334
32176cfd
RP
335/*
336 * Attach/setup the common net80211 state. Called by
337 * the driver on attach to prior to creating any vap's.
338 */
339void
4f655ef5 340ieee80211_ifattach(struct ieee80211com *ic)
32176cfd 341{
32176cfd 342
4f898719
IV
343 IEEE80211_LOCK_INIT(ic, ic->ic_name);
344 IEEE80211_TX_LOCK_INIT(ic, ic->ic_name);
32176cfd
RP
345 TAILQ_INIT(&ic->ic_vaps);
346
347 /* Create a taskqueue for all state changes */
348 ic->ic_tq = taskqueue_create("ic_taskq", M_WAITOK | M_ZERO,
349 taskqueue_thread_enqueue, &ic->ic_tq);
085ff963 350#if defined(__DragonFly__)
32176cfd 351 taskqueue_start_threads(&ic->ic_tq, 1, TDPRI_KERN_DAEMON, -1,
4f898719 352 "%s net80211 taskq", ic->ic_name);
085ff963
MD
353#else
354 taskqueue_start_threads(&ic->ic_tq, 1, PI_NET, "%s net80211 taskq",
4f898719 355 ic->ic_name);
4f655ef5
MD
356 ic->ic_ierrors = counter_u64_alloc(M_WAITOK);
357 ic->ic_oerrors = counter_u64_alloc(M_WAITOK);
085ff963 358#endif
32176cfd
RP
359 /*
360 * Fill in 802.11 available channel set, mark all
361 * available channels as active, and pick a default
362 * channel if not already specified.
363 */
4f655ef5 364 ieee80211_chan_init(ic);
32176cfd
RP
365
366 ic->ic_update_mcast = null_update_mcast;
367 ic->ic_update_promisc = null_update_promisc;
085ff963 368 ic->ic_update_chw = null_update_chw;
32176cfd 369
085ff963 370 ic->ic_hash_key = arc4random();
32176cfd
RP
371 ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
372 ic->ic_lintval = ic->ic_bintval;
373 ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
374
375 ieee80211_crypto_attach(ic);
376 ieee80211_node_attach(ic);
377 ieee80211_power_attach(ic);
378 ieee80211_proto_attach(ic);
379#ifdef IEEE80211_SUPPORT_SUPERG
380 ieee80211_superg_attach(ic);
381#endif
382 ieee80211_ht_attach(ic);
383 ieee80211_scan_attach(ic);
384 ieee80211_regdomain_attach(ic);
385 ieee80211_dfs_attach(ic);
386
387 ieee80211_sysctl_attach(ic);
388
085ff963 389#if defined(__DragonFly__)
4f655ef5 390 lockmgr(&ic_list_lock, LK_EXCLUSIVE);
085ff963 391#else
4f655ef5
MD
392 mtx_lock(&ic_list_mtx);
393#endif
394 LIST_INSERT_HEAD(&ic_head, ic, ic_next);
395#if defined(__DragonFly__)
396 lockmgr(&ic_list_lock, LK_RELEASE);
397#else
398 mtx_unlock(&ic_list_mtx);
085ff963 399#endif
32176cfd
RP
400}
401
402/*
403 * Detach net80211 state on device detach. Tear down
404 * all vap's and reclaim all common state prior to the
405 * device state going away. Note we may call back into
406 * driver; it must be prepared for this.
407 */
408void
409ieee80211_ifdetach(struct ieee80211com *ic)
841ab66c 410{
32176cfd
RP
411 struct ieee80211vap *vap;
412
7dfe50f5
IV
413#if defined(__DragonFly__)
414 wlan_serialize_enter();
415#endif
416
4f655ef5
MD
417#if defined(__DragonFly__)
418 lockmgr(&ic_list_lock, LK_EXCLUSIVE);
419#else
420 mtx_lock(&ic_list_mtx);
421#endif
422 LIST_REMOVE(ic, ic_next);
423#if defined(__DragonFly__)
424 lockmgr(&ic_list_lock, LK_RELEASE);
425#else
426 mtx_unlock(&ic_list_mtx);
427#endif
428
429#if defined(__DragonFly__)
dd3f3f08 430 taskqueue_drain(taskqueue_thread[0], &ic->ic_restart_task);
4f655ef5
MD
431#else
432 taskqueue_drain(taskqueue_thread, &ic->ic_restart_task);
433#endif
434
a583ece6 435 /*
cfc4faf7
SZ
436 * The VAP is responsible for setting and clearing
437 * the VIMAGE context.
438 */
439 while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL)
440 ieee80211_vap_destroy(vap);
32176cfd
RP
441 ieee80211_waitfor_parent(ic);
442
443 ieee80211_sysctl_detach(ic);
444 ieee80211_dfs_detach(ic);
445 ieee80211_regdomain_detach(ic);
446 ieee80211_scan_detach(ic);
447#ifdef IEEE80211_SUPPORT_SUPERG
448 ieee80211_superg_detach(ic);
449#endif
450 ieee80211_ht_detach(ic);
451 /* NB: must be called before ieee80211_node_detach */
452 ieee80211_proto_detach(ic);
453 ieee80211_crypto_detach(ic);
454 ieee80211_power_detach(ic);
455 ieee80211_node_detach(ic);
841ab66c 456
4f655ef5
MD
457#if defined(__DragonFly__)
458#else
459 counter_u64_free(ic->ic_ierrors);
460 counter_u64_free(ic->ic_oerrors);
461#endif
085ff963 462
32176cfd 463 taskqueue_free(ic->ic_tq);
085ff963
MD
464 IEEE80211_TX_LOCK_DESTROY(ic);
465 IEEE80211_LOCK_DESTROY(ic);
7dfe50f5
IV
466
467#if defined(__DragonFly__)
468 wlan_serialize_exit();
469#endif
841ab66c
SZ
470}
471
4f655ef5
MD
472struct ieee80211com *
473ieee80211_find_com(const char *name)
474{
475 struct ieee80211com *ic;
476
477#if defined(__DragonFly__)
478 lockmgr(&ic_list_lock, LK_EXCLUSIVE);
479#else
480 mtx_lock(&ic_list_mtx);
481#endif
482 LIST_FOREACH(ic, &ic_head, ic_next) {
483 if (strcmp(ic->ic_name, name) == 0)
484 break;
485 }
486#if defined(__DragonFly__)
487 lockmgr(&ic_list_lock, LK_RELEASE);
488#else
489 mtx_unlock(&ic_list_mtx);
490#endif
491
492 return(ic);
493}
494
841ab66c
SZ
495/*
496 * Default reset method for use with the ioctl support. This
497 * method is invoked after any state change in the 802.11
498 * layer that should be propagated to the hardware but not
499 * require re-initialization of the 802.11 state machine (e.g
500 * rescanning for an ap). We always return ENETRESET which
501 * should cause the driver to re-initialize the device. Drivers
502 * can override this method to implement more optimized support.
503 */
504static int
32176cfd 505default_reset(struct ieee80211vap *vap, u_long cmd)
841ab66c
SZ
506{
507 return ENETRESET;
508}
509
4f655ef5
MD
510#if defined(__DragonFly__)
511#else
512/*
513 * Add underlying device errors to vap errors.
514 */
515static uint64_t
516ieee80211_get_counter(struct ifnet *ifp, ift_counter cnt)
517{
518 struct ieee80211vap *vap = ifp->if_softc;
519 struct ieee80211com *ic = vap->iv_ic;
520 uint64_t rv;
521
522 rv = if_get_counter_default(ifp, cnt);
523 switch (cnt) {
524 case IFCOUNTER_OERRORS:
525 rv += counter_u64_fetch(ic->ic_oerrors);
526 break;
527 case IFCOUNTER_IERRORS:
528 rv += counter_u64_fetch(ic->ic_ierrors);
529 break;
530 default:
531 break;
532 }
533
534 return (rv);
535}
536
537#endif
538
32176cfd
RP
539/*
540 * Prepare a vap for use. Drivers use this call to
541 * setup net80211 state in new vap's prior attaching
542 * them with ieee80211_vap_attach (below).
543 */
544int
545ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
085ff963 546 const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode,
4f655ef5 547 int flags, const uint8_t bssid[IEEE80211_ADDR_LEN])
f186073c 548{
841ab66c 549 struct ifnet *ifp;
841ab66c 550
7e395935 551 ifp = if_alloc(IFT_ETHER);
32176cfd 552 if (ifp == NULL) {
4f898719 553 ic_printf(ic, "%s: unable to allocate ifnet\n",
32176cfd
RP
554 __func__);
555 return ENOMEM;
556 }
557 if_initname(ifp, name, unit);
558 ifp->if_softc = vap; /* back pointer */
559 ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
4f655ef5 560#if defined(__DragonFly__)
085ff963 561 ifp->if_start = ieee80211_vap_start;
4f655ef5 562#else
085ff963
MD
563 ifp->if_transmit = ieee80211_vap_transmit;
564 ifp->if_qflush = ieee80211_vap_qflush;
565#endif
32176cfd
RP
566 ifp->if_ioctl = ieee80211_ioctl;
567 ifp->if_init = ieee80211_init;
4f655ef5
MD
568#if defined(__DragonFly__)
569#else
570 ifp->if_get_counter = ieee80211_get_counter;
571#endif
32176cfd
RP
572
573 vap->iv_ifp = ifp;
574 vap->iv_ic = ic;
575 vap->iv_flags = ic->ic_flags; /* propagate common flags */
576 vap->iv_flags_ext = ic->ic_flags_ext;
577 vap->iv_flags_ven = ic->ic_flags_ven;
578 vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE;
579 vap->iv_htcaps = ic->ic_htcaps;
085ff963 580 vap->iv_htextcaps = ic->ic_htextcaps;
32176cfd
RP
581 vap->iv_opmode = opmode;
582 vap->iv_caps |= ieee80211_opcap[opmode];
4f655ef5 583 IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_macaddr);
32176cfd
RP
584 switch (opmode) {
585 case IEEE80211_M_WDS:
586 /*
587 * WDS links must specify the bssid of the far end.
588 * For legacy operation this is a static relationship.
589 * For non-legacy operation the station must associate
590 * and be authorized to pass traffic. Plumbing the
591 * vap to the proper node happens when the vap
592 * transitions to RUN state.
593 */
594 IEEE80211_ADDR_COPY(vap->iv_des_bssid, bssid);
595 vap->iv_flags |= IEEE80211_F_DESBSSID;
596 if (flags & IEEE80211_CLONE_WDSLEGACY)
597 vap->iv_flags_ext |= IEEE80211_FEXT_WDSLEGACY;
598 break;
599#ifdef IEEE80211_SUPPORT_TDMA
600 case IEEE80211_M_AHDEMO:
601 if (flags & IEEE80211_CLONE_TDMA) {
602 /* NB: checked before clone operation allowed */
603 KASSERT(ic->ic_caps & IEEE80211_C_TDMA,
604 ("not TDMA capable, ic_caps 0x%x", ic->ic_caps));
f186073c 605 /*
32176cfd
RP
606 * Propagate TDMA capability to mark vap; this
607 * cannot be removed and is used to distinguish
608 * regular ahdemo operation from ahdemo+tdma.
f186073c 609 */
32176cfd 610 vap->iv_caps |= IEEE80211_C_TDMA;
f186073c 611 }
32176cfd
RP
612 break;
613#endif
085ff963
MD
614 default:
615 break;
f186073c 616 }
32176cfd
RP
617 /* auto-enable s/w beacon miss support */
618 if (flags & IEEE80211_CLONE_NOBEACONS)
619 vap->iv_flags_ext |= IEEE80211_FEXT_SWBMISS;
620 /* auto-generated or user supplied MAC address */
621 if (flags & (IEEE80211_CLONE_BSSID|IEEE80211_CLONE_MACADDR))
622 vap->iv_flags_ext |= IEEE80211_FEXT_UNIQMAC;
841ab66c 623 /*
32176cfd
RP
624 * Enable various functionality by default if we're
625 * capable; the driver can override us if it knows better.
841ab66c 626 */
32176cfd
RP
627 if (vap->iv_caps & IEEE80211_C_WME)
628 vap->iv_flags |= IEEE80211_F_WME;
629 if (vap->iv_caps & IEEE80211_C_BURST)
630 vap->iv_flags |= IEEE80211_F_BURST;
085ff963 631 /* NB: bg scanning only makes sense for station mode right now */
4f655ef5 632#if defined(__DragonFly__)
4584f705 633 /*
085ff963
MD
634 * DISABLE BGSCAN BY DEFAULT, many issues can crop up including
635 * the link going dead.
4584f705 636 */
4f655ef5
MD
637 /* empty */
638#else
32176cfd
RP
639 if (vap->iv_opmode == IEEE80211_M_STA &&
640 (vap->iv_caps & IEEE80211_C_BGSCAN))
641 vap->iv_flags |= IEEE80211_F_BGSCAN;
4584f705 642#endif
32176cfd
RP
643 vap->iv_flags |= IEEE80211_F_DOTH; /* XXX no cap, just ena */
644 /* NB: DFS support only makes sense for ap mode right now */
645 if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
646 (vap->iv_caps & IEEE80211_C_DFS))
647 vap->iv_flags_ext |= IEEE80211_FEXT_DFS;
648
649 vap->iv_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */
650 vap->iv_bmissthreshold = IEEE80211_HWBMISS_DEFAULT;
651 vap->iv_dtim_period = IEEE80211_DTIM_DEFAULT;
652 /*
653 * Install a default reset method for the ioctl support;
654 * the driver can override this.
655 */
656 vap->iv_reset = default_reset;
657
32176cfd
RP
658 ieee80211_sysctl_vattach(vap);
659 ieee80211_crypto_vattach(vap);
660 ieee80211_node_vattach(vap);
661 ieee80211_power_vattach(vap);
662 ieee80211_proto_vattach(vap);
663#ifdef IEEE80211_SUPPORT_SUPERG
664 ieee80211_superg_vattach(vap);
841ab66c 665#endif
32176cfd
RP
666 ieee80211_ht_vattach(vap);
667 ieee80211_scan_vattach(vap);
668 ieee80211_regdomain_vattach(vap);
669 ieee80211_radiotap_vattach(vap);
4fbce6bd 670 ieee80211_ratectl_set(vap, IEEE80211_RATECTL_NONE);
f186073c 671
32176cfd
RP
672 return 0;
673}
841ab66c 674
32176cfd
RP
675/*
676 * Activate a vap. State should have been prepared with a
677 * call to ieee80211_vap_setup and by the driver. On return
678 * from this call the vap is ready for use.
679 */
680int
4f655ef5
MD
681ieee80211_vap_attach(struct ieee80211vap *vap, ifm_change_cb_t media_change,
682 ifm_stat_cb_t media_stat, const uint8_t macaddr[IEEE80211_ADDR_LEN])
32176cfd
RP
683{
684 struct ifnet *ifp = vap->iv_ifp;
685 struct ieee80211com *ic = vap->iv_ic;
686 struct ifmediareq imr;
687 int maxrate;
f186073c 688
4f655ef5 689#if defined(__DragonFly__)
a583ece6
SZ
690 /*
691 * This function must _not_ be serialized by the WLAN serializer,
692 * since it could dead-lock the domsg to netisrs in ether_ifattach().
693 */
694 wlan_assert_notserialized();
4f655ef5 695#endif
32176cfd
RP
696 IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
697 "%s: %s parent %s flags 0x%x flags_ext 0x%x\n",
698 __func__, ieee80211_opmode_name[vap->iv_opmode],
4f898719 699 ic->ic_name, vap->iv_flags, vap->iv_flags_ext);
841ab66c 700
32176cfd
RP
701 /*
702 * Do late attach work that cannot happen until after
703 * the driver has had a chance to override defaults.
704 */
705 ieee80211_node_latevattach(vap);
706 ieee80211_power_latevattach(vap);
841ab66c 707
32176cfd
RP
708 maxrate = ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps,
709 vap->iv_opmode == IEEE80211_M_STA, media_change, media_stat);
710 ieee80211_media_status(ifp, &imr);
711 /* NB: strip explicit mode; we're actually in autoselect */
712 ifmedia_set(&vap->iv_media,
713 imr.ifm_active &~ (IFM_MMASK | IFM_IEEE80211_TURBO));
714 if (maxrate)
715 ifp->if_baudrate = IF_Mbps(maxrate);
841ab66c 716
085ff963 717#if defined(__DragonFly__)
4f655ef5 718 ether_ifattach(ifp, macaddr, &wlan_global_serializer);
085ff963 719#else
4f655ef5 720 ether_ifattach(ifp, macaddr);
34a60cf6 721#endif
4f655ef5 722 IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp));
085ff963
MD
723 /* hook output method setup by ether_ifattach */
724 vap->iv_output = ifp->if_output;
725 ifp->if_output = ieee80211_output;
32176cfd
RP
726 /* NB: if_mtu set by ether_ifattach to ETHERMTU */
727
085ff963 728 IEEE80211_LOCK(ic);
32176cfd
RP
729 TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next);
730 ieee80211_syncflag_locked(ic, IEEE80211_F_WME);
731#ifdef IEEE80211_SUPPORT_SUPERG
732 ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP);
733#endif
734 ieee80211_syncflag_locked(ic, IEEE80211_F_PCF);
735 ieee80211_syncflag_locked(ic, IEEE80211_F_BURST);
736 ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT);
737 ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40);
085ff963 738 IEEE80211_UNLOCK(ic);
32176cfd
RP
739
740 return 1;
741}
742
743/*
744 * Tear down vap state and reclaim the ifnet.
745 * The driver is assumed to have prepared for
746 * this; e.g. by turning off interrupts for the
747 * underlying device.
748 */
749void
750ieee80211_vap_detach(struct ieee80211vap *vap)
751{
752 struct ieee80211com *ic = vap->iv_ic;
753 struct ifnet *ifp = vap->iv_ifp;
754
4f655ef5 755#if defined(__DragonFly__)
a583ece6
SZ
756 /*
757 * This function must _not_ be serialized by the WLAN serializer,
758 * since it could dead-lock the domsg to netisrs in ether_ifdettach().
759 */
760 wlan_assert_notserialized();
4f655ef5 761#endif
085ff963
MD
762 CURVNET_SET(ifp->if_vnet);
763
32176cfd 764 IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s parent %s\n",
4f898719 765 __func__, ieee80211_opmode_name[vap->iv_opmode], ic->ic_name);
32176cfd 766
085ff963 767 /* NB: bpfdetach is called by ether_ifdetach and claims all taps */
32176cfd
RP
768 ether_ifdetach(ifp);
769
770 ieee80211_stop(vap);
b9334f94 771
841ab66c 772 /*
32176cfd 773 * Flush any deferred vap tasks.
841ab66c 774 */
32176cfd
RP
775 ieee80211_draintask(ic, &vap->iv_nstate_task);
776 ieee80211_draintask(ic, &vap->iv_swbmiss_task);
777
4f655ef5
MD
778#if defined(__DragonFly__)
779 /* XXX hmm, not sure what we should do here */
780#else
32176cfd
RP
781 /* XXX band-aid until ifnet handles this for us */
782 taskqueue_drain(taskqueue_swi, &ifp->if_linktask);
34a60cf6 783#endif
32176cfd 784
085ff963 785 IEEE80211_LOCK(ic);
32176cfd
RP
786 KASSERT(vap->iv_state == IEEE80211_S_INIT , ("vap still running"));
787 TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next);
788 ieee80211_syncflag_locked(ic, IEEE80211_F_WME);
789#ifdef IEEE80211_SUPPORT_SUPERG
790 ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP);
791#endif
792 ieee80211_syncflag_locked(ic, IEEE80211_F_PCF);
793 ieee80211_syncflag_locked(ic, IEEE80211_F_BURST);
794 ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT);
795 ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40);
796 /* NB: this handles the bpfdetach done below */
797 ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_BPF);
4f655ef5
MD
798#if defined(__DragonFly__)
799 if (vap->iv_ifflags & IFF_PROMISC)
800 ieee80211_promisc(vap, 0);
801 if (vap->iv_ifflags & IFF_ALLMULTI)
802 ieee80211_allmulti(vap, 0);
803#else
804 if (vap->iv_ifflags & IFF_PROMISC)
805 ieee80211_promisc(vap, false);
806 if (vap->iv_ifflags & IFF_ALLMULTI)
807 ieee80211_allmulti(vap, false);
808#endif
085ff963 809 IEEE80211_UNLOCK(ic);
32176cfd
RP
810
811 ifmedia_removeall(&vap->iv_media);
812
813 ieee80211_radiotap_vdetach(vap);
814 ieee80211_regdomain_vdetach(vap);
815 ieee80211_scan_vdetach(vap);
816#ifdef IEEE80211_SUPPORT_SUPERG
817 ieee80211_superg_vdetach(vap);
818#endif
819 ieee80211_ht_vdetach(vap);
820 /* NB: must be before ieee80211_node_vdetach */
821 ieee80211_proto_vdetach(vap);
822 ieee80211_crypto_vdetach(vap);
823 ieee80211_power_vdetach(vap);
824 ieee80211_node_vdetach(vap);
825 ieee80211_sysctl_vdetach(vap);
826
827 if_free(ifp);
085ff963
MD
828
829 CURVNET_RESTORE();
f186073c
JS
830}
831
32176cfd 832/*
4f655ef5
MD
833 * Count number of vaps in promisc, and issue promisc on
834 * parent respectively.
32176cfd 835 */
4f655ef5 836#if defined(__DragonFly__)
f186073c 837void
4f655ef5
MD
838ieee80211_promisc(struct ieee80211vap *vap, int on)
839#else
840void
841ieee80211_promisc(struct ieee80211vap *vap, bool on)
842#endif
f186073c 843{
4f655ef5 844 struct ieee80211com *ic = vap->iv_ic;
841ab66c 845
085ff963
MD
846 IEEE80211_LOCK_ASSERT(ic);
847
4f655ef5
MD
848 if (on) {
849 if (++ic->ic_promisc == 1)
850 ieee80211_runtask(ic, &ic->ic_promisc_task);
851 } else {
852 KASSERT(ic->ic_promisc > 0, ("%s: ic %p not promisc",
853 __func__, ic));
854 if (--ic->ic_promisc == 0)
855 ieee80211_runtask(ic, &ic->ic_promisc_task);
856 }
857}
858
859/*
860 * Count number of vaps in allmulti, and issue allmulti on
861 * parent respectively.
862 */
863#if defined(__DragonFly__)
864void
865ieee80211_allmulti(struct ieee80211vap *vap, int on)
866#else
867void
868ieee80211_allmulti(struct ieee80211vap *vap, bool on)
869#endif
870{
871 struct ieee80211com *ic = vap->iv_ic;
872
873 IEEE80211_LOCK_ASSERT(ic);
874
875 if (on) {
876 if (++ic->ic_allmulti == 1)
877 ieee80211_runtask(ic, &ic->ic_mcast_task);
878 } else {
879 KASSERT(ic->ic_allmulti > 0, ("%s: ic %p not allmulti",
880 __func__, ic));
881 if (--ic->ic_allmulti == 0)
882 ieee80211_runtask(ic, &ic->ic_mcast_task);
32176cfd
RP
883 }
884}
841ab66c 885
32176cfd
RP
886/*
887 * Synchronize flag bit state in the com structure
888 * according to the state of all vap's. This is used,
889 * for example, to handle state changes via ioctls.
890 */
891static void
892ieee80211_syncflag_locked(struct ieee80211com *ic, int flag)
893{
894 struct ieee80211vap *vap;
895 int bit;
841ab66c 896
085ff963
MD
897 IEEE80211_LOCK_ASSERT(ic);
898
32176cfd
RP
899 bit = 0;
900 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
901 if (vap->iv_flags & flag) {
902 bit = 1;
903 break;
904 }
905 if (bit)
906 ic->ic_flags |= flag;
907 else
908 ic->ic_flags &= ~flag;
909}
841ab66c 910
32176cfd
RP
911void
912ieee80211_syncflag(struct ieee80211vap *vap, int flag)
913{
914 struct ieee80211com *ic = vap->iv_ic;
915
085ff963 916 IEEE80211_LOCK(ic);
32176cfd
RP
917 if (flag < 0) {
918 flag = -flag;
919 vap->iv_flags &= ~flag;
920 } else
921 vap->iv_flags |= flag;
922 ieee80211_syncflag_locked(ic, flag);
085ff963 923 IEEE80211_UNLOCK(ic);
32176cfd
RP
924}
925
926/*
927 * Synchronize flags_ht bit state in the com structure
928 * according to the state of all vap's. This is used,
929 * for example, to handle state changes via ioctls.
930 */
931static void
932ieee80211_syncflag_ht_locked(struct ieee80211com *ic, int flag)
933{
934 struct ieee80211vap *vap;
935 int bit;
936
085ff963
MD
937 IEEE80211_LOCK_ASSERT(ic);
938
32176cfd
RP
939 bit = 0;
940 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
941 if (vap->iv_flags_ht & flag) {
942 bit = 1;
943 break;
944 }
945 if (bit)
946 ic->ic_flags_ht |= flag;
947 else
948 ic->ic_flags_ht &= ~flag;
949}
950
951void
952ieee80211_syncflag_ht(struct ieee80211vap *vap, int flag)
953{
954 struct ieee80211com *ic = vap->iv_ic;
955
085ff963 956 IEEE80211_LOCK(ic);
32176cfd
RP
957 if (flag < 0) {
958 flag = -flag;
959 vap->iv_flags_ht &= ~flag;
960 } else
961 vap->iv_flags_ht |= flag;
962 ieee80211_syncflag_ht_locked(ic, flag);
085ff963 963 IEEE80211_UNLOCK(ic);
32176cfd
RP
964}
965
966/*
967 * Synchronize flags_ext bit state in the com structure
968 * according to the state of all vap's. This is used,
969 * for example, to handle state changes via ioctls.
970 */
971static void
972ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag)
973{
974 struct ieee80211vap *vap;
975 int bit;
976
085ff963
MD
977 IEEE80211_LOCK_ASSERT(ic);
978
32176cfd
RP
979 bit = 0;
980 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
981 if (vap->iv_flags_ext & flag) {
982 bit = 1;
983 break;
984 }
985 if (bit)
986 ic->ic_flags_ext |= flag;
987 else
988 ic->ic_flags_ext &= ~flag;
989}
990
991void
992ieee80211_syncflag_ext(struct ieee80211vap *vap, int flag)
993{
994 struct ieee80211com *ic = vap->iv_ic;
995
085ff963 996 IEEE80211_LOCK(ic);
32176cfd
RP
997 if (flag < 0) {
998 flag = -flag;
999 vap->iv_flags_ext &= ~flag;
1000 } else
1001 vap->iv_flags_ext |= flag;
1002 ieee80211_syncflag_ext_locked(ic, flag);
085ff963 1003 IEEE80211_UNLOCK(ic);
32176cfd
RP
1004}
1005
1006static __inline int
1007mapgsm(u_int freq, u_int flags)
1008{
1009 freq *= 10;
1010 if (flags & IEEE80211_CHAN_QUARTER)
1011 freq += 5;
1012 else if (flags & IEEE80211_CHAN_HALF)
1013 freq += 10;
1014 else
1015 freq += 20;
1016 /* NB: there is no 907/20 wide but leave room */
1017 return (freq - 906*10) / 5;
1018}
1019
1020static __inline int
1021mappsb(u_int freq, u_int flags)
1022{
1023 return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5;
f186073c
JS
1024}
1025
1026/*
1027 * Convert MHz frequency to IEEE channel number.
1028 */
32176cfd 1029int
f186073c
JS
1030ieee80211_mhz2ieee(u_int freq, u_int flags)
1031{
32176cfd
RP
1032#define IS_FREQ_IN_PSB(_freq) ((_freq) > 4940 && (_freq) < 4990)
1033 if (flags & IEEE80211_CHAN_GSM)
1034 return mapgsm(freq, flags);
f186073c
JS
1035 if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */
1036 if (freq == 2484)
1037 return 14;
1038 if (freq < 2484)
32176cfd 1039 return ((int) freq - 2407) / 5;
f186073c
JS
1040 else
1041 return 15 + ((freq - 2512) / 20);
1042 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */
32176cfd
RP
1043 if (freq <= 5000) {
1044 /* XXX check regdomain? */
1045 if (IS_FREQ_IN_PSB(freq))
1046 return mappsb(freq, flags);
1047 return (freq - 4000) / 5;
1048 } else
1049 return (freq - 5000) / 5;
f186073c
JS
1050 } else { /* either, guess */
1051 if (freq == 2484)
1052 return 14;
32176cfd
RP
1053 if (freq < 2484) {
1054 if (907 <= freq && freq <= 922)
1055 return mapgsm(freq, flags);
1056 return ((int) freq - 2407) / 5;
1057 }
1058 if (freq < 5000) {
1059 if (IS_FREQ_IN_PSB(freq))
1060 return mappsb(freq, flags);
1061 else if (freq > 4900)
1062 return (freq - 4000) / 5;
1063 else
1064 return 15 + ((freq - 2512) / 20);
1065 }
f186073c
JS
1066 return (freq - 5000) / 5;
1067 }
32176cfd 1068#undef IS_FREQ_IN_PSB
f186073c
JS
1069}
1070
1071/*
1072 * Convert channel to IEEE channel number.
1073 */
32176cfd 1074int
47f525a7 1075ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c)
f186073c 1076{
32176cfd 1077 if (c == NULL) {
4f898719 1078 ic_printf(ic, "invalid channel (NULL)\n");
f186073c
JS
1079 return 0; /* XXX */
1080 }
32176cfd 1081 return (c == IEEE80211_CHAN_ANYC ? IEEE80211_CHAN_ANY : c->ic_ieee);
f186073c
JS
1082}
1083
1084/*
1085 * Convert IEEE channel number to MHz frequency.
1086 */
1087u_int
1088ieee80211_ieee2mhz(u_int chan, u_int flags)
1089{
32176cfd
RP
1090 if (flags & IEEE80211_CHAN_GSM)
1091 return 907 + 5 * (chan / 10);
f186073c
JS
1092 if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */
1093 if (chan == 14)
1094 return 2484;
1095 if (chan < 14)
1096 return 2407 + chan*5;
1097 else
1098 return 2512 + ((chan-15)*20);
1099 } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */
32176cfd
RP
1100 if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) {
1101 chan -= 37;
1102 return 4940 + chan*5 + (chan % 5 ? 2 : 0);
1103 }
f186073c
JS
1104 return 5000 + (chan*5);
1105 } else { /* either, guess */
32176cfd 1106 /* XXX can't distinguish PSB+GSM channels */
f186073c
JS
1107 if (chan == 14)
1108 return 2484;
1109 if (chan < 14) /* 0-13 */
1110 return 2407 + chan*5;
1111 if (chan < 27) /* 15-26 */
1112 return 2512 + ((chan-15)*20);
1113 return 5000 + (chan*5);
1114 }
1115}
1116
4f655ef5
MD
1117static __inline void
1118set_extchan(struct ieee80211_channel *c)
1119{
1120
1121 /*
1122 * IEEE Std 802.11-2012, page 1738, subclause 20.3.15.4:
1123 * "the secondary channel number shall be 'N + [1,-1] * 4'
1124 */
1125 if (c->ic_flags & IEEE80211_CHAN_HT40U)
1126 c->ic_extieee = c->ic_ieee + 4;
1127 else if (c->ic_flags & IEEE80211_CHAN_HT40D)
1128 c->ic_extieee = c->ic_ieee - 4;
1129 else
1130 c->ic_extieee = 0;
1131}
1132
1133static int
1134addchan(struct ieee80211_channel chans[], int maxchans, int *nchans,
1135 uint8_t ieee, uint16_t freq, int8_t maxregpower, uint32_t flags)
1136{
1137 struct ieee80211_channel *c;
1138
1139 if (*nchans >= maxchans)
1140 return (ENOBUFS);
1141
1142 c = &chans[(*nchans)++];
1143 c->ic_ieee = ieee;
1144 c->ic_freq = freq != 0 ? freq : ieee80211_ieee2mhz(ieee, flags);
1145 c->ic_maxregpower = maxregpower;
1146 c->ic_maxpower = 2 * maxregpower;
1147 c->ic_flags = flags;
1148 set_extchan(c);
1149
1150 return (0);
1151}
1152
1153static int
1154copychan_prev(struct ieee80211_channel chans[], int maxchans, int *nchans,
1155 uint32_t flags)
1156{
1157 struct ieee80211_channel *c;
1158
1159 KASSERT(*nchans > 0, ("channel list is empty\n"));
1160
1161 if (*nchans >= maxchans)
1162 return (ENOBUFS);
1163
1164 c = &chans[(*nchans)++];
1165 c[0] = c[-1];
1166 c->ic_flags = flags;
1167 set_extchan(c);
1168
1169 return (0);
1170}
1171
1172static void
1173getflags_2ghz(const uint8_t bands[], uint32_t flags[], int ht40)
1174{
1175 int nmodes;
1176
1177 nmodes = 0;
1178 if (isset(bands, IEEE80211_MODE_11B))
1179 flags[nmodes++] = IEEE80211_CHAN_B;
1180 if (isset(bands, IEEE80211_MODE_11G))
1181 flags[nmodes++] = IEEE80211_CHAN_G;
1182 if (isset(bands, IEEE80211_MODE_11NG))
1183 flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT20;
1184 if (ht40) {
1185 flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U;
1186 flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D;
1187 }
1188 flags[nmodes] = 0;
1189}
1190
1191static void
1192getflags_5ghz(const uint8_t bands[], uint32_t flags[], int ht40)
1193{
1194 int nmodes;
1195
1196 nmodes = 0;
1197 if (isset(bands, IEEE80211_MODE_11A))
1198 flags[nmodes++] = IEEE80211_CHAN_A;
1199 if (isset(bands, IEEE80211_MODE_11NA))
1200 flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20;
1201 if (ht40) {
1202 flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U;
1203 flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D;
1204 }
1205 flags[nmodes] = 0;
1206}
1207
1208static void
1209getflags(const uint8_t bands[], uint32_t flags[], int ht40)
1210{
1211
1212 flags[0] = 0;
1213 if (isset(bands, IEEE80211_MODE_11A) ||
1214 isset(bands, IEEE80211_MODE_11NA)) {
1215 if (isset(bands, IEEE80211_MODE_11B) ||
1216 isset(bands, IEEE80211_MODE_11G) ||
1217 isset(bands, IEEE80211_MODE_11NG))
1218 return;
1219
1220 getflags_5ghz(bands, flags, ht40);
1221 } else
1222 getflags_2ghz(bands, flags, ht40);
1223}
1224
1225/*
1226 * Add one 20 MHz channel into specified channel list.
1227 */
1228int
1229ieee80211_add_channel(struct ieee80211_channel chans[], int maxchans,
1230 int *nchans, uint8_t ieee, uint16_t freq, int8_t maxregpower,
1231 uint32_t chan_flags, const uint8_t bands[])
1232{
1233 uint32_t flags[IEEE80211_MODE_MAX];
1234 int i, error;
1235
1236 getflags(bands, flags, 0);
1237 KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
1238
1239 error = addchan(chans, maxchans, nchans, ieee, freq, maxregpower,
1240 flags[0] | chan_flags);
1241 for (i = 1; flags[i] != 0 && error == 0; i++) {
1242 error = copychan_prev(chans, maxchans, nchans,
1243 flags[i] | chan_flags);
1244 }
1245
1246 return (error);
1247}
1248
1249static struct ieee80211_channel *
1250findchannel(struct ieee80211_channel chans[], int nchans, uint16_t freq,
1251 uint32_t flags)
1252{
1253 struct ieee80211_channel *c;
1254 int i;
1255
1256 flags &= IEEE80211_CHAN_ALLTURBO;
1257 /* brute force search */
1258 for (i = 0; i < nchans; i++) {
1259 c = &chans[i];
1260 if (c->ic_freq == freq &&
1261 (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
1262 return c;
1263 }
1264 return NULL;
1265}
1266
1267/*
1268 * Add 40 MHz channel pair into specified channel list.
1269 */
1270int
1271ieee80211_add_channel_ht40(struct ieee80211_channel chans[], int maxchans,
1272 int *nchans, uint8_t ieee, int8_t maxregpower, uint32_t flags)
1273{
1274 struct ieee80211_channel *cent, *extc;
1275 uint16_t freq;
1276 int error;
1277
1278 freq = ieee80211_ieee2mhz(ieee, flags);
1279
1280 /*
1281 * Each entry defines an HT40 channel pair; find the
1282 * center channel, then the extension channel above.
1283 */
1284 flags |= IEEE80211_CHAN_HT20;
1285 cent = findchannel(chans, *nchans, freq, flags);
1286 if (cent == NULL)
1287 return (EINVAL);
1288
1289 extc = findchannel(chans, *nchans, freq + 20, flags);
1290 if (extc == NULL)
1291 return (ENOENT);
1292
1293 flags &= ~IEEE80211_CHAN_HT;
1294 error = addchan(chans, maxchans, nchans, cent->ic_ieee, cent->ic_freq,
1295 maxregpower, flags | IEEE80211_CHAN_HT40U);
1296 if (error != 0)
1297 return (error);
1298
1299 error = addchan(chans, maxchans, nchans, extc->ic_ieee, extc->ic_freq,
1300 maxregpower, flags | IEEE80211_CHAN_HT40D);
1301
1302 return (error);
1303}
1304
1305/*
1306 * Adds channels into specified channel list (ieee[] array must be sorted).
1307 * Channels are already sorted.
1308 */
1309static int
1310add_chanlist(struct ieee80211_channel chans[], int maxchans, int *nchans,
1311 const uint8_t ieee[], int nieee, uint32_t flags[])
1312{
1313 uint16_t freq;
1314 int i, j, error;
1315
1316#if defined(__DragonFly__)
1317 error = 0; /* work-around GCC uninitialized variable warning */
1318#endif
1319 for (i = 0; i < nieee; i++) {
1320 freq = ieee80211_ieee2mhz(ieee[i], flags[0]);
1321 for (j = 0; flags[j] != 0; j++) {
1322 if (flags[j] & IEEE80211_CHAN_HT40D)
1323 if (i == 0 || ieee[i] < ieee[0] + 4 ||
1324 freq - 20 !=
1325 ieee80211_ieee2mhz(ieee[i] - 4, flags[j]))
1326 continue;
1327 if (flags[j] & IEEE80211_CHAN_HT40U)
1328 if (i == nieee - 1 ||
1329 ieee[i] + 4 > ieee[nieee - 1] ||
1330 freq + 20 !=
1331 ieee80211_ieee2mhz(ieee[i] + 4, flags[j]))
1332 continue;
1333
1334 if (j == 0) {
1335 error = addchan(chans, maxchans, nchans,
1336 ieee[i], freq, 0, flags[j]);
1337 } else {
1338 error = copychan_prev(chans, maxchans, nchans,
1339 flags[j]);
1340 }
1341 if (error != 0)
1342 return (error);
1343 }
1344 }
1345
1346 return (error);
1347}
1348
1349int
1350ieee80211_add_channel_list_2ghz(struct ieee80211_channel chans[], int maxchans,
1351 int *nchans, const uint8_t ieee[], int nieee, const uint8_t bands[],
1352 int ht40)
1353{
1354 uint32_t flags[IEEE80211_MODE_MAX];
1355
1356 getflags_2ghz(bands, flags, ht40);
1357 KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
1358
1359 return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags));
1360}
1361
1362int
1363ieee80211_add_channel_list_5ghz(struct ieee80211_channel chans[], int maxchans,
1364 int *nchans, const uint8_t ieee[], int nieee, const uint8_t bands[],
1365 int ht40)
1366{
1367 uint32_t flags[IEEE80211_MODE_MAX];
1368
1369 getflags_5ghz(bands, flags, ht40);
1370 KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
1371
1372 return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags));
1373}
1374
f186073c 1375/*
32176cfd
RP
1376 * Locate a channel given a frequency+flags. We cache
1377 * the previous lookup to optimize switching between two
1378 * channels--as happens with dynamic turbo.
f186073c 1379 */
32176cfd
RP
1380struct ieee80211_channel *
1381ieee80211_find_channel(struct ieee80211com *ic, int freq, int flags)
f186073c 1382{
32176cfd 1383 struct ieee80211_channel *c;
f186073c 1384
32176cfd
RP
1385 flags &= IEEE80211_CHAN_ALLTURBO;
1386 c = ic->ic_prevchan;
1387 if (c != NULL && c->ic_freq == freq &&
1388 (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
1389 return c;
1390 /* brute force search */
4f655ef5 1391 return (findchannel(ic->ic_channels, ic->ic_nchans, freq, flags));
32176cfd 1392}
841ab66c 1393
32176cfd
RP
1394/*
1395 * Locate a channel given a channel number+flags. We cache
1396 * the previous lookup to optimize switching between two
1397 * channels--as happens with dynamic turbo.
1398 */
1399struct ieee80211_channel *
1400ieee80211_find_channel_byieee(struct ieee80211com *ic, int ieee, int flags)
1401{
1402 struct ieee80211_channel *c;
1403 int i;
841ab66c 1404
32176cfd
RP
1405 flags &= IEEE80211_CHAN_ALLTURBO;
1406 c = ic->ic_prevchan;
1407 if (c != NULL && c->ic_ieee == ieee &&
1408 (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
1409 return c;
1410 /* brute force search */
1411 for (i = 0; i < ic->ic_nchans; i++) {
1412 c = &ic->ic_channels[i];
1413 if (c->ic_ieee == ieee &&
1414 (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
1415 return c;
1416 }
1417 return NULL;
1418}
1419
4f898719
IV
1420/*
1421 * Lookup a channel suitable for the given rx status.
1422 *
1423 * This is used to find a channel for a frame (eg beacon, probe
1424 * response) based purely on the received PHY information.
1425 *
1426 * For now it tries to do it based on R_FREQ / R_IEEE.
1427 * This is enough for 11bg and 11a (and thus 11ng/11na)
1428 * but it will not be enough for GSM, PSB channels and the
1429 * like. It also doesn't know about legacy-turbog and
1430 * legacy-turbo modes, which some offload NICs actually
1431 * support in weird ways.
1432 *
1433 * Takes the ic and rxstatus; returns the channel or NULL
1434 * if not found.
1435 *
1436 * XXX TODO: Add support for that when the need arises.
1437 */
1438struct ieee80211_channel *
1439ieee80211_lookup_channel_rxstatus(struct ieee80211vap *vap,
1440 const struct ieee80211_rx_stats *rxs)
1441{
1442 struct ieee80211com *ic = vap->iv_ic;
1443 uint32_t flags;
1444 struct ieee80211_channel *c;
1445
1446 if (rxs == NULL)
1447 return (NULL);
1448
1449 /*
1450 * Strictly speaking we only use freq for now,
1451 * however later on we may wish to just store
1452 * the ieee for verification.
1453 */
1454 if ((rxs->r_flags & IEEE80211_R_FREQ) == 0)
1455 return (NULL);
1456 if ((rxs->r_flags & IEEE80211_R_IEEE) == 0)
1457 return (NULL);
1458
1459 /*
1460 * If the rx status contains a valid ieee/freq, then
1461 * ensure we populate the correct channel information
1462 * in rxchan before passing it up to the scan infrastructure.
1463 * Offload NICs will pass up beacons from all channels
1464 * during background scans.
1465 */
1466
1467 /* Determine a band */
1468 /* XXX should be done by the driver? */
1469 if (rxs->c_freq < 3000) {
1470 flags = IEEE80211_CHAN_G;
1471 } else {
1472 flags = IEEE80211_CHAN_A;
1473 }
1474
1475 /* Channel lookup */
1476 c = ieee80211_find_channel(ic, rxs->c_freq, flags);
1477
1478 IEEE80211_DPRINTF(vap, IEEE80211_MSG_INPUT,
1479 "%s: freq=%d, ieee=%d, flags=0x%08x; c=%p\n",
1480 __func__,
1481 (int) rxs->c_freq,
1482 (int) rxs->c_ieee,
1483 flags,
1484 c);
1485
1486 return (c);
1487}
1488
32176cfd
RP
1489static void
1490addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword)
1491{
1492#define ADD(_ic, _s, _o) \
1493 ifmedia_add(media, \
1494 IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
1495 static const u_int mopts[IEEE80211_MODE_MAX] = {
1496 [IEEE80211_MODE_AUTO] = IFM_AUTO,
1497 [IEEE80211_MODE_11A] = IFM_IEEE80211_11A,
1498 [IEEE80211_MODE_11B] = IFM_IEEE80211_11B,
1499 [IEEE80211_MODE_11G] = IFM_IEEE80211_11G,
1500 [IEEE80211_MODE_FH] = IFM_IEEE80211_FH,
1501 [IEEE80211_MODE_TURBO_A] = IFM_IEEE80211_11A|IFM_IEEE80211_TURBO,
1502 [IEEE80211_MODE_TURBO_G] = IFM_IEEE80211_11G|IFM_IEEE80211_TURBO,
1503 [IEEE80211_MODE_STURBO_A] = IFM_IEEE80211_11A|IFM_IEEE80211_TURBO,
1504 [IEEE80211_MODE_HALF] = IFM_IEEE80211_11A, /* XXX */
1505 [IEEE80211_MODE_QUARTER] = IFM_IEEE80211_11A, /* XXX */
1506 [IEEE80211_MODE_11NA] = IFM_IEEE80211_11NA,
1507 [IEEE80211_MODE_11NG] = IFM_IEEE80211_11NG,
1508 };
1509 u_int mopt;
1510
1511 mopt = mopts[mode];
1512 if (addsta)
1513 ADD(ic, mword, mopt); /* STA mode has no cap */
1514 if (caps & IEEE80211_C_IBSS)
1515 ADD(media, mword, mopt | IFM_IEEE80211_ADHOC);
1516 if (caps & IEEE80211_C_HOSTAP)
1517 ADD(media, mword, mopt | IFM_IEEE80211_HOSTAP);
1518 if (caps & IEEE80211_C_AHDEMO)
1519 ADD(media, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
1520 if (caps & IEEE80211_C_MONITOR)
1521 ADD(media, mword, mopt | IFM_IEEE80211_MONITOR);
1522 if (caps & IEEE80211_C_WDS)
1523 ADD(media, mword, mopt | IFM_IEEE80211_WDS);
1524 if (caps & IEEE80211_C_MBSS)
1525 ADD(media, mword, mopt | IFM_IEEE80211_MBSS);
1526#undef ADD
1527}
1528
1529/*
1530 * Setup the media data structures according to the channel and
1531 * rate tables.
1532 */
1533static int
1534ieee80211_media_setup(struct ieee80211com *ic,
1535 struct ifmedia *media, int caps, int addsta,
1536 ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
1537{
085ff963
MD
1538 int i, j, rate, maxrate, mword, r;
1539 enum ieee80211_phymode mode;
32176cfd
RP
1540 const struct ieee80211_rateset *rs;
1541 struct ieee80211_rateset allrates;
f186073c
JS
1542
1543 /*
1544 * Fill in media characteristics.
1545 */
32176cfd 1546 ifmedia_init(media, 0, media_change, media_stat);
f186073c 1547 maxrate = 0;
32176cfd
RP
1548 /*
1549 * Add media for legacy operating modes.
1550 */
f186073c 1551 memset(&allrates, 0, sizeof(allrates));
32176cfd
RP
1552 for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) {
1553 if (isclr(ic->ic_modecaps, mode))
f186073c 1554 continue;
32176cfd 1555 addmedia(media, caps, addsta, mode, IFM_AUTO);
f186073c
JS
1556 if (mode == IEEE80211_MODE_AUTO)
1557 continue;
f186073c
JS
1558 rs = &ic->ic_sup_rates[mode];
1559 for (i = 0; i < rs->rs_nrates; i++) {
1560 rate = rs->rs_rates[i];
1561 mword = ieee80211_rate2media(ic, rate, mode);
1562 if (mword == 0)
1563 continue;
32176cfd 1564 addmedia(media, caps, addsta, mode, mword);
f186073c 1565 /*
32176cfd 1566 * Add legacy rate to the collection of all rates.
f186073c
JS
1567 */
1568 r = rate & IEEE80211_RATE_VAL;
1569 for (j = 0; j < allrates.rs_nrates; j++)
1570 if (allrates.rs_rates[j] == r)
1571 break;
1572 if (j == allrates.rs_nrates) {
1573 /* unique, add to the set */
1574 allrates.rs_rates[j] = r;
1575 allrates.rs_nrates++;
1576 }
1577 rate = (rate & IEEE80211_RATE_VAL) / 2;
1578 if (rate > maxrate)
1579 maxrate = rate;
1580 }
f186073c
JS
1581 }
1582 for (i = 0; i < allrates.rs_nrates; i++) {
1583 mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
1584 IEEE80211_MODE_AUTO);
1585 if (mword == 0)
1586 continue;
32176cfd
RP
1587 /* NB: remove media options from mword */
1588 addmedia(media, caps, addsta,
1589 IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword));
f186073c 1590 }
32176cfd
RP
1591 /*
1592 * Add HT/11n media. Note that we do not have enough
1593 * bits in the media subtype to express the MCS so we
1594 * use a "placeholder" media subtype and any fixed MCS
1595 * must be specified with a different mechanism.
1596 */
1597 for (; mode <= IEEE80211_MODE_11NG; mode++) {
1598 if (isclr(ic->ic_modecaps, mode))
1599 continue;
1600 addmedia(media, caps, addsta, mode, IFM_AUTO);
1601 addmedia(media, caps, addsta, mode, IFM_IEEE80211_MCS);
1602 }
1603 if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
1604 isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) {
1605 addmedia(media, caps, addsta,
1606 IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS);
085ff963
MD
1607 i = ic->ic_txstream * 8 - 1;
1608 if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
1609 (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40))
1610 rate = ieee80211_htrates[i].ht40_rate_400ns;
1611 else if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40))
1612 rate = ieee80211_htrates[i].ht40_rate_800ns;
1613 else if ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20))
1614 rate = ieee80211_htrates[i].ht20_rate_400ns;
1615 else
1616 rate = ieee80211_htrates[i].ht20_rate_800ns;
1617 if (rate > maxrate)
1618 maxrate = rate;
32176cfd
RP
1619 }
1620 return maxrate;
1621}
1622
32176cfd
RP
1623/* XXX inline or eliminate? */
1624const struct ieee80211_rateset *
1625ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c)
1626{
1627 /* XXX does this work for 11ng basic rates? */
1628 return &ic->ic_sup_rates[ieee80211_chan2mode(c)];
f186073c
JS
1629}
1630
841ab66c
SZ
1631void
1632ieee80211_announce(struct ieee80211com *ic)
1633{
085ff963
MD
1634 int i, rate, mword;
1635 enum ieee80211_phymode mode;
32176cfd 1636 const struct ieee80211_rateset *rs;
841ab66c 1637
32176cfd
RP
1638 /* NB: skip AUTO since it has no rates */
1639 for (mode = IEEE80211_MODE_AUTO+1; mode < IEEE80211_MODE_11NA; mode++) {
1640 if (isclr(ic->ic_modecaps, mode))
841ab66c 1641 continue;
4f898719 1642 ic_printf(ic, "%s rates: ", ieee80211_phymode_name[mode]);
841ab66c
SZ
1643 rs = &ic->ic_sup_rates[mode];
1644 for (i = 0; i < rs->rs_nrates; i++) {
32176cfd 1645 mword = ieee80211_rate2media(ic, rs->rs_rates[i], mode);
841ab66c
SZ
1646 if (mword == 0)
1647 continue;
32176cfd 1648 rate = ieee80211_media2rate(mword);
a6ec04bc 1649 kprintf("%s%d%sMbps", (i != 0 ? " " : ""),
32176cfd 1650 rate / 2, ((rate & 0x1) != 0 ? ".5" : ""));
841ab66c 1651 }
a6ec04bc 1652 kprintf("\n");
841ab66c 1653 }
32176cfd 1654 ieee80211_ht_announce(ic);
841ab66c
SZ
1655}
1656
32176cfd
RP
1657void
1658ieee80211_announce_channels(struct ieee80211com *ic)
841ab66c 1659{
32176cfd
RP
1660 const struct ieee80211_channel *c;
1661 char type;
1662 int i, cw;
841ab66c 1663
32176cfd
RP
1664 kprintf("Chan Freq CW RegPwr MinPwr MaxPwr\n");
1665 for (i = 0; i < ic->ic_nchans; i++) {
1666 c = &ic->ic_channels[i];
1667 if (IEEE80211_IS_CHAN_ST(c))
1668 type = 'S';
1669 else if (IEEE80211_IS_CHAN_108A(c))
1670 type = 'T';
1671 else if (IEEE80211_IS_CHAN_108G(c))
1672 type = 'G';
1673 else if (IEEE80211_IS_CHAN_HT(c))
1674 type = 'n';
1675 else if (IEEE80211_IS_CHAN_A(c))
1676 type = 'a';
1677 else if (IEEE80211_IS_CHAN_ANYG(c))
1678 type = 'g';
1679 else if (IEEE80211_IS_CHAN_B(c))
1680 type = 'b';
1681 else
1682 type = 'f';
1683 if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_TURBO(c))
1684 cw = 40;
1685 else if (IEEE80211_IS_CHAN_HALF(c))
1686 cw = 10;
1687 else if (IEEE80211_IS_CHAN_QUARTER(c))
1688 cw = 5;
1689 else
1690 cw = 20;
1691 kprintf("%4d %4d%c %2d%c %6d %4d.%d %4d.%d\n"
1692 , c->ic_ieee, c->ic_freq, type
1693 , cw
1694 , IEEE80211_IS_CHAN_HT40U(c) ? '+' :
1695 IEEE80211_IS_CHAN_HT40D(c) ? '-' : ' '
1696 , c->ic_maxregpower
1697 , c->ic_minpower / 2, c->ic_minpower & 1 ? 5 : 0
1698 , c->ic_maxpower / 2, c->ic_maxpower & 1 ? 5 : 0
1699 );
1700 }
841ab66c
SZ
1701}
1702
32176cfd
RP
1703static int
1704media2mode(const struct ifmedia_entry *ime, uint32_t flags, uint16_t *mode)
f186073c 1705{
f186073c
JS
1706 switch (IFM_MODE(ime->ifm_media)) {
1707 case IFM_IEEE80211_11A:
32176cfd 1708 *mode = IEEE80211_MODE_11A;
f186073c
JS
1709 break;
1710 case IFM_IEEE80211_11B:
32176cfd 1711 *mode = IEEE80211_MODE_11B;
f186073c
JS
1712 break;
1713 case IFM_IEEE80211_11G:
32176cfd 1714 *mode = IEEE80211_MODE_11G;
f186073c
JS
1715 break;
1716 case IFM_IEEE80211_FH:
32176cfd
RP
1717 *mode = IEEE80211_MODE_FH;
1718 break;
1719 case IFM_IEEE80211_11NA:
1720 *mode = IEEE80211_MODE_11NA;
1721 break;
1722 case IFM_IEEE80211_11NG:
1723 *mode = IEEE80211_MODE_11NG;
f186073c
JS
1724 break;
1725 case IFM_AUTO:
32176cfd 1726 *mode = IEEE80211_MODE_AUTO;
f186073c
JS
1727 break;
1728 default:
32176cfd 1729 return 0;
f186073c
JS
1730 }
1731 /*
841ab66c
SZ
1732 * Turbo mode is an ``option''.
1733 * XXX does not apply to AUTO
f186073c
JS
1734 */
1735 if (ime->ifm_media & IFM_IEEE80211_TURBO) {
32176cfd
RP
1736 if (*mode == IEEE80211_MODE_11A) {
1737 if (flags & IEEE80211_F_TURBOP)
1738 *mode = IEEE80211_MODE_TURBO_A;
1739 else
1740 *mode = IEEE80211_MODE_STURBO_A;
1741 } else if (*mode == IEEE80211_MODE_11G)
1742 *mode = IEEE80211_MODE_TURBO_G;
841ab66c 1743 else
32176cfd 1744 return 0;
f186073c 1745 }
32176cfd
RP
1746 /* XXX HT40 +/- */
1747 return 1;
1748}
f186073c 1749
32176cfd
RP
1750/*
1751 * Handle a media change request on the vap interface.
1752 */
1753int
1754ieee80211_media_change(struct ifnet *ifp)
1755{
1756 struct ieee80211vap *vap = ifp->if_softc;
1757 struct ifmedia_entry *ime = vap->iv_media.ifm_cur;
1758 uint16_t newmode;
f186073c 1759
32176cfd
RP
1760 if (!media2mode(ime, vap->iv_flags, &newmode))
1761 return EINVAL;
1762 if (vap->iv_des_mode != newmode) {
1763 vap->iv_des_mode = newmode;
1764 /* XXX kick state machine if up+running */
f186073c 1765 }
32176cfd
RP
1766 return 0;
1767}
f186073c 1768
32176cfd
RP
1769/*
1770 * Common code to calculate the media status word
1771 * from the operating mode and channel state.
1772 */
1773static int
1774media_status(enum ieee80211_opmode opmode, const struct ieee80211_channel *chan)
1775{
1776 int status;
f186073c 1777
32176cfd
RP
1778 status = IFM_IEEE80211;
1779 switch (opmode) {
1780 case IEEE80211_M_STA:
1781 break;
1782 case IEEE80211_M_IBSS:
1783 status |= IFM_IEEE80211_ADHOC;
1784 break;
1785 case IEEE80211_M_HOSTAP:
1786 status |= IFM_IEEE80211_HOSTAP;
1787 break;
1788 case IEEE80211_M_MONITOR:
1789 status |= IFM_IEEE80211_MONITOR;
1790 break;
1791 case IEEE80211_M_AHDEMO:
1792 status |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
1793 break;
1794 case IEEE80211_M_WDS:
1795 status |= IFM_IEEE80211_WDS;
1796 break;
1797 case IEEE80211_M_MBSS:
1798 status |= IFM_IEEE80211_MBSS;
1799 break;
f186073c 1800 }
32176cfd
RP
1801 if (IEEE80211_IS_CHAN_HTA(chan)) {
1802 status |= IFM_IEEE80211_11NA;
1803 } else if (IEEE80211_IS_CHAN_HTG(chan)) {
1804 status |= IFM_IEEE80211_11NG;
1805 } else if (IEEE80211_IS_CHAN_A(chan)) {
1806 status |= IFM_IEEE80211_11A;
1807 } else if (IEEE80211_IS_CHAN_B(chan)) {
1808 status |= IFM_IEEE80211_11B;
1809 } else if (IEEE80211_IS_CHAN_ANYG(chan)) {
1810 status |= IFM_IEEE80211_11G;
1811 } else if (IEEE80211_IS_CHAN_FHSS(chan)) {
1812 status |= IFM_IEEE80211_FH;
1813 }
1814 /* XXX else complain? */
f186073c 1815
32176cfd
RP
1816 if (IEEE80211_IS_CHAN_TURBO(chan))
1817 status |= IFM_IEEE80211_TURBO;
1818#if 0
1819 if (IEEE80211_IS_CHAN_HT20(chan))
1820 status |= IFM_IEEE80211_HT20;
1821 if (IEEE80211_IS_CHAN_HT40(chan))
1822 status |= IFM_IEEE80211_HT40;
1823#endif
1824 return status;
1825}
1826
f186073c
JS
1827void
1828ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
1829{
32176cfd
RP
1830 struct ieee80211vap *vap = ifp->if_softc;
1831 struct ieee80211com *ic = vap->iv_ic;
1832 enum ieee80211_phymode mode;
f186073c
JS
1833
1834 imr->ifm_status = IFM_AVALID;
32176cfd
RP
1835 /*
1836 * NB: use the current channel's mode to lock down a xmit
1837 * rate only when running; otherwise we may have a mismatch
1838 * in which case the rate will not be convertible.
1839 */
d98a0bcf
MD
1840 if (vap->iv_state == IEEE80211_S_RUN ||
1841 vap->iv_state == IEEE80211_S_SLEEP) {
f186073c 1842 imr->ifm_status |= IFM_ACTIVE;
32176cfd
RP
1843 mode = ieee80211_chan2mode(ic->ic_curchan);
1844 } else
1845 mode = IEEE80211_MODE_AUTO;
1846 imr->ifm_active = media_status(vap->iv_opmode, ic->ic_curchan);
841ab66c
SZ
1847 /*
1848 * Calculate a current rate if possible.
1849 */
32176cfd 1850 if (vap->iv_txparms[mode].ucastrate != IEEE80211_FIXED_RATE_NONE) {
841ab66c
SZ
1851 /*
1852 * A fixed rate is set, report that.
1853 */
841ab66c 1854 imr->ifm_active |= ieee80211_rate2media(ic,
32176cfd
RP
1855 vap->iv_txparms[mode].ucastrate, mode);
1856 } else if (vap->iv_opmode == IEEE80211_M_STA) {
841ab66c
SZ
1857 /*
1858 * In station mode report the current transmit rate.
1859 */
841ab66c 1860 imr->ifm_active |= ieee80211_rate2media(ic,
32176cfd 1861 vap->iv_bss->ni_txrate, mode);
f186073c 1862 } else
841ab66c 1863 imr->ifm_active |= IFM_AUTO;
32176cfd
RP
1864 if (imr->ifm_status & IFM_ACTIVE)
1865 imr->ifm_current = imr->ifm_active;
f186073c
JS
1866}
1867
1868/*
1869 * Set the current phy mode and recalculate the active channel
1870 * set based on the available channels for this mode. Also
1871 * select a new default/current channel if the current one is
1872 * inappropriate for this mode.
1873 */
1874int
1875ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
1876{
f186073c 1877 /*
32176cfd
RP
1878 * Adjust basic rates in 11b/11g supported rate set.
1879 * Note that if operating on a hal/quarter rate channel
1880 * this is a noop as those rates sets are different
1881 * and used instead.
f186073c 1882 */
32176cfd
RP
1883 if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B)
1884 ieee80211_setbasicrates(&ic->ic_sup_rates[mode], mode);
f186073c
JS
1885
1886 ic->ic_curmode = mode;
841ab66c 1887 ieee80211_reset_erp(ic); /* reset ERP state */
841ab66c 1888
f186073c 1889 return 0;
f186073c
JS
1890}
1891
1892/*
32176cfd 1893 * Return the phy mode for with the specified channel.
f186073c
JS
1894 */
1895enum ieee80211_phymode
32176cfd 1896ieee80211_chan2mode(const struct ieee80211_channel *chan)
f186073c 1897{
32176cfd
RP
1898
1899 if (IEEE80211_IS_CHAN_HTA(chan))
1900 return IEEE80211_MODE_11NA;
1901 else if (IEEE80211_IS_CHAN_HTG(chan))
1902 return IEEE80211_MODE_11NG;
1903 else if (IEEE80211_IS_CHAN_108G(chan))
1904 return IEEE80211_MODE_TURBO_G;
1905 else if (IEEE80211_IS_CHAN_ST(chan))
1906 return IEEE80211_MODE_STURBO_A;
1907 else if (IEEE80211_IS_CHAN_TURBO(chan))
841ab66c 1908 return IEEE80211_MODE_TURBO_A;
32176cfd
RP
1909 else if (IEEE80211_IS_CHAN_HALF(chan))
1910 return IEEE80211_MODE_HALF;
1911 else if (IEEE80211_IS_CHAN_QUARTER(chan))
1912 return IEEE80211_MODE_QUARTER;
1913 else if (IEEE80211_IS_CHAN_A(chan))
f186073c 1914 return IEEE80211_MODE_11A;
32176cfd 1915 else if (IEEE80211_IS_CHAN_ANYG(chan))
f186073c 1916 return IEEE80211_MODE_11G;
32176cfd 1917 else if (IEEE80211_IS_CHAN_B(chan))
f186073c 1918 return IEEE80211_MODE_11B;
32176cfd
RP
1919 else if (IEEE80211_IS_CHAN_FHSS(chan))
1920 return IEEE80211_MODE_FH;
1921
1922 /* NB: should not get here */
1923 kprintf("%s: cannot map channel to mode; freq %u flags 0x%x\n",
1924 __func__, chan->ic_freq, chan->ic_flags);
1925 return IEEE80211_MODE_11B;
1926}
1927
1928struct ratemedia {
1929 u_int match; /* rate + mode */
1930 u_int media; /* if_media rate */
1931};
1932
1933static int
1934findmedia(const struct ratemedia rates[], int n, u_int match)
1935{
1936 int i;
1937
1938 for (i = 0; i < n; i++)
1939 if (rates[i].match == match)
1940 return rates[i].media;
1941 return IFM_AUTO;
f186073c
JS
1942}
1943
1944/*
32176cfd
RP
1945 * Convert IEEE80211 rate value to ifmedia subtype.
1946 * Rate is either a legacy rate in units of 0.5Mbps
1947 * or an MCS index.
f186073c
JS
1948 */
1949int
1950ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode)
1951{
32176cfd 1952 static const struct ratemedia rates[] = {
f186073c
JS
1953 { 2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
1954 { 4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
1955 { 2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 },
1956 { 4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 },
1957 { 11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 },
1958 { 22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 },
1959 { 44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 },
1960 { 12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 },
1961 { 18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 },
1962 { 24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 },
1963 { 36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 },
1964 { 48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 },
1965 { 72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 },
1966 { 96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 },
1967 { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 },
1968 { 2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 },
1969 { 4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 },
1970 { 11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 },
1971 { 22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 },
1972 { 12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 },
1973 { 18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 },
1974 { 24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 },
1975 { 36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 },
1976 { 48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 },
1977 { 72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 },
1978 { 96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 },
1979 { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 },
32176cfd
RP
1980 { 6 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM3 },
1981 { 9 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM4 },
1982 { 54 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM27 },
4f655ef5 1983 /* NB: OFDM72 doesn't really exist so we don't handle it */
f186073c 1984 };
32176cfd
RP
1985 static const struct ratemedia htrates[] = {
1986 { 0, IFM_IEEE80211_MCS },
1987 { 1, IFM_IEEE80211_MCS },
1988 { 2, IFM_IEEE80211_MCS },
1989 { 3, IFM_IEEE80211_MCS },
1990 { 4, IFM_IEEE80211_MCS },
1991 { 5, IFM_IEEE80211_MCS },
1992 { 6, IFM_IEEE80211_MCS },
1993 { 7, IFM_IEEE80211_MCS },
1994 { 8, IFM_IEEE80211_MCS },
1995 { 9, IFM_IEEE80211_MCS },
1996 { 10, IFM_IEEE80211_MCS },
1997 { 11, IFM_IEEE80211_MCS },
1998 { 12, IFM_IEEE80211_MCS },
1999 { 13, IFM_IEEE80211_MCS },
2000 { 14, IFM_IEEE80211_MCS },
2001 { 15, IFM_IEEE80211_MCS },
085ff963
MD
2002 { 16, IFM_IEEE80211_MCS },
2003 { 17, IFM_IEEE80211_MCS },
2004 { 18, IFM_IEEE80211_MCS },
2005 { 19, IFM_IEEE80211_MCS },
2006 { 20, IFM_IEEE80211_MCS },
2007 { 21, IFM_IEEE80211_MCS },
2008 { 22, IFM_IEEE80211_MCS },
2009 { 23, IFM_IEEE80211_MCS },
2010 { 24, IFM_IEEE80211_MCS },
2011 { 25, IFM_IEEE80211_MCS },
2012 { 26, IFM_IEEE80211_MCS },
2013 { 27, IFM_IEEE80211_MCS },
2014 { 28, IFM_IEEE80211_MCS },
2015 { 29, IFM_IEEE80211_MCS },
2016 { 30, IFM_IEEE80211_MCS },
2017 { 31, IFM_IEEE80211_MCS },
2018 { 32, IFM_IEEE80211_MCS },
2019 { 33, IFM_IEEE80211_MCS },
2020 { 34, IFM_IEEE80211_MCS },
2021 { 35, IFM_IEEE80211_MCS },
2022 { 36, IFM_IEEE80211_MCS },
2023 { 37, IFM_IEEE80211_MCS },
2024 { 38, IFM_IEEE80211_MCS },
2025 { 39, IFM_IEEE80211_MCS },
2026 { 40, IFM_IEEE80211_MCS },
2027 { 41, IFM_IEEE80211_MCS },
2028 { 42, IFM_IEEE80211_MCS },
2029 { 43, IFM_IEEE80211_MCS },
2030 { 44, IFM_IEEE80211_MCS },
2031 { 45, IFM_IEEE80211_MCS },
2032 { 46, IFM_IEEE80211_MCS },
2033 { 47, IFM_IEEE80211_MCS },
2034 { 48, IFM_IEEE80211_MCS },
2035 { 49, IFM_IEEE80211_MCS },
2036 { 50, IFM_IEEE80211_MCS },
2037 { 51, IFM_IEEE80211_MCS },
2038 { 52, IFM_IEEE80211_MCS },
2039 { 53, IFM_IEEE80211_MCS },
2040 { 54, IFM_IEEE80211_MCS },
2041 { 55, IFM_IEEE80211_MCS },
2042 { 56, IFM_IEEE80211_MCS },
2043 { 57, IFM_IEEE80211_MCS },
2044 { 58, IFM_IEEE80211_MCS },
2045 { 59, IFM_IEEE80211_MCS },
2046 { 60, IFM_IEEE80211_MCS },
2047 { 61, IFM_IEEE80211_MCS },
2048 { 62, IFM_IEEE80211_MCS },
2049 { 63, IFM_IEEE80211_MCS },
2050 { 64, IFM_IEEE80211_MCS },
2051 { 65, IFM_IEEE80211_MCS },
2052 { 66, IFM_IEEE80211_MCS },
2053 { 67, IFM_IEEE80211_MCS },
2054 { 68, IFM_IEEE80211_MCS },
2055 { 69, IFM_IEEE80211_MCS },
2056 { 70, IFM_IEEE80211_MCS },
2057 { 71, IFM_IEEE80211_MCS },
2058 { 72, IFM_IEEE80211_MCS },
2059 { 73, IFM_IEEE80211_MCS },
2060 { 74, IFM_IEEE80211_MCS },
2061 { 75, IFM_IEEE80211_MCS },
2062 { 76, IFM_IEEE80211_MCS },
32176cfd
RP
2063 };
2064 int m;
f186073c 2065
32176cfd
RP
2066 /*
2067 * Check 11n rates first for match as an MCS.
2068 */
2069 if (mode == IEEE80211_MODE_11NA) {
2070 if (rate & IEEE80211_RATE_MCS) {
2071 rate &= ~IEEE80211_RATE_MCS;
085ff963 2072 m = findmedia(htrates, nitems(htrates), rate);
32176cfd
RP
2073 if (m != IFM_AUTO)
2074 return m | IFM_IEEE80211_11NA;
2075 }
2076 } else if (mode == IEEE80211_MODE_11NG) {
2077 /* NB: 12 is ambiguous, it will be treated as an MCS */
2078 if (rate & IEEE80211_RATE_MCS) {
2079 rate &= ~IEEE80211_RATE_MCS;
085ff963 2080 m = findmedia(htrates, nitems(htrates), rate);
32176cfd
RP
2081 if (m != IFM_AUTO)
2082 return m | IFM_IEEE80211_11NG;
2083 }
2084 }
2085 rate &= IEEE80211_RATE_VAL;
f186073c
JS
2086 switch (mode) {
2087 case IEEE80211_MODE_11A:
32176cfd
RP
2088 case IEEE80211_MODE_HALF: /* XXX good 'nuf */
2089 case IEEE80211_MODE_QUARTER:
2090 case IEEE80211_MODE_11NA:
841ab66c 2091 case IEEE80211_MODE_TURBO_A:
32176cfd 2092 case IEEE80211_MODE_STURBO_A:
085ff963
MD
2093 return findmedia(rates, nitems(rates),
2094 rate | IFM_IEEE80211_11A);
f186073c 2095 case IEEE80211_MODE_11B:
085ff963
MD
2096 return findmedia(rates, nitems(rates),
2097 rate | IFM_IEEE80211_11B);
f186073c 2098 case IEEE80211_MODE_FH:
085ff963
MD
2099 return findmedia(rates, nitems(rates),
2100 rate | IFM_IEEE80211_FH);
f186073c
JS
2101 case IEEE80211_MODE_AUTO:
2102 /* NB: ic may be NULL for some drivers */
32176cfd 2103 if (ic != NULL && ic->ic_phytype == IEEE80211_T_FH)
085ff963 2104 return findmedia(rates, nitems(rates),
32176cfd 2105 rate | IFM_IEEE80211_FH);
f186073c
JS
2106 /* NB: hack, 11g matches both 11b+11a rates */
2107 /* fall thru... */
2108 case IEEE80211_MODE_11G:
32176cfd 2109 case IEEE80211_MODE_11NG:
841ab66c 2110 case IEEE80211_MODE_TURBO_G:
085ff963 2111 return findmedia(rates, nitems(rates), rate | IFM_IEEE80211_11G);
797b05a5
AL
2112 case IEEE80211_MODE_VHT_2GHZ:
2113 case IEEE80211_MODE_VHT_5GHZ:
2114 /* XXX TODO: need to figure out mapping for VHT rates */
2115 return IFM_AUTO;
f186073c 2116 }
f186073c 2117 return IFM_AUTO;
f186073c
JS
2118}
2119
2120int
2121ieee80211_media2rate(int mword)
2122{
f186073c
JS
2123 static const int ieeerates[] = {
2124 -1, /* IFM_AUTO */
2125 0, /* IFM_MANUAL */
2126 0, /* IFM_NONE */
2127 2, /* IFM_IEEE80211_FH1 */
2128 4, /* IFM_IEEE80211_FH2 */
2129 2, /* IFM_IEEE80211_DS1 */
2130 4, /* IFM_IEEE80211_DS2 */
2131 11, /* IFM_IEEE80211_DS5 */
2132 22, /* IFM_IEEE80211_DS11 */
2133 44, /* IFM_IEEE80211_DS22 */
2134 12, /* IFM_IEEE80211_OFDM6 */
2135 18, /* IFM_IEEE80211_OFDM9 */
2136 24, /* IFM_IEEE80211_OFDM12 */
2137 36, /* IFM_IEEE80211_OFDM18 */
2138 48, /* IFM_IEEE80211_OFDM24 */
2139 72, /* IFM_IEEE80211_OFDM36 */
2140 96, /* IFM_IEEE80211_OFDM48 */
2141 108, /* IFM_IEEE80211_OFDM54 */
2142 144, /* IFM_IEEE80211_OFDM72 */
32176cfd
RP
2143 0, /* IFM_IEEE80211_DS354k */
2144 0, /* IFM_IEEE80211_DS512k */
2145 6, /* IFM_IEEE80211_OFDM3 */
2146 9, /* IFM_IEEE80211_OFDM4 */
2147 54, /* IFM_IEEE80211_OFDM27 */
2148 -1, /* IFM_IEEE80211_MCS */
f186073c 2149 };
085ff963 2150 return IFM_SUBTYPE(mword) < nitems(ieeerates) ?
f186073c 2151 ieeerates[IFM_SUBTYPE(mword)] : 0;
f186073c 2152}
f467e28e
SZ
2153
2154/*
32176cfd
RP
2155 * The following hash function is adapted from "Hash Functions" by Bob Jenkins
2156 * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
f467e28e 2157 */
32176cfd
RP
2158#define mix(a, b, c) \
2159do { \
2160 a -= b; a -= c; a ^= (c >> 13); \
2161 b -= c; b -= a; b ^= (a << 8); \
2162 c -= a; c -= b; c ^= (b >> 13); \
2163 a -= b; a -= c; a ^= (c >> 12); \
2164 b -= c; b -= a; b ^= (a << 16); \
2165 c -= a; c -= b; c ^= (b >> 5); \
2166 a -= b; a -= c; a ^= (c >> 3); \
2167 b -= c; b -= a; b ^= (a << 10); \
2168 c -= a; c -= b; c ^= (b >> 15); \
2169} while (/*CONSTCOND*/0)
2170
2171uint32_t
2172ieee80211_mac_hash(const struct ieee80211com *ic,
2173 const uint8_t addr[IEEE80211_ADDR_LEN])
f467e28e 2174{
32176cfd 2175 uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = ic->ic_hash_key;
0dba45fe 2176
32176cfd
RP
2177 b += addr[5] << 8;
2178 b += addr[4];
2179 a += addr[3] << 24;
2180 a += addr[2] << 16;
2181 a += addr[1] << 8;
2182 a += addr[0];
0dba45fe 2183
32176cfd
RP
2184 mix(a, b, c);
2185
2186 return c;
0dba45fe 2187}
32176cfd 2188#undef mix
4f898719
IV
2189
2190char
2191ieee80211_channel_type_char(const struct ieee80211_channel *c)
2192{
2193 if (IEEE80211_IS_CHAN_ST(c))
2194 return 'S';
2195 if (IEEE80211_IS_CHAN_108A(c))
2196 return 'T';
2197 if (IEEE80211_IS_CHAN_108G(c))
2198 return 'G';
2199 if (IEEE80211_IS_CHAN_HT(c))
2200 return 'n';
2201 if (IEEE80211_IS_CHAN_A(c))
2202 return 'a';
2203 if (IEEE80211_IS_CHAN_ANYG(c))
2204 return 'g';
2205 if (IEEE80211_IS_CHAN_B(c))
2206 return 'b';
2207 return 'f';
2208}