xref: /freebsd/sys/net80211/ieee80211_freebsd.c (revision d876124d6ae9d56da5b4ff4c6015efd1d0c9222a)
1 /*-
2  * Copyright (c) 2003-2008 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 
29 /*
30  * IEEE 802.11 support (FreeBSD-specific code)
31  */
32 #include "opt_wlan.h"
33 
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
37 #include <sys/linker.h>
38 #include <sys/mbuf.h>
39 #include <sys/module.h>
40 #include <sys/proc.h>
41 #include <sys/sysctl.h>
42 
43 #include <sys/socket.h>
44 
45 #include <net/if.h>
46 #include <net/if_clone.h>
47 #include <net/if_media.h>
48 #include <net/if_types.h>
49 #include <net/ethernet.h>
50 #include <net/route.h>
51 
52 #include <net80211/ieee80211_var.h>
53 
54 SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters");
55 
56 #ifdef IEEE80211_DEBUG
57 int	ieee80211_debug = 0;
58 SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug,
59 	    0, "debugging printfs");
60 #endif
61 extern int ieee80211_recv_bar_ena;
62 SYSCTL_INT(_net_wlan, OID_AUTO, recv_bar, CTLFLAG_RW, &ieee80211_recv_bar_ena,
63 	    0, "BAR frame processing (ena/dis)");
64 extern int ieee80211_nol_timeout;
65 SYSCTL_INT(_net_wlan, OID_AUTO, nol_timeout, CTLFLAG_RW,
66 	&ieee80211_nol_timeout, 0, "NOL timeout (secs)");
67 extern int ieee80211_cac_timeout;
68 SYSCTL_INT(_net_wlan, OID_AUTO, cac_timeout, CTLFLAG_RW,
69 	&ieee80211_cac_timeout, 0, "CAC timeout (secs)");
70 
71 MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state");
72 
73 /*
74  * Allocate/free com structure in conjunction with ifnet;
75  * these routines are registered with if_register_com_alloc
76  * below and are called automatically by the ifnet code
77  * when the ifnet of the parent device is created.
78  */
79 static void *
80 wlan_alloc(u_char type, struct ifnet *ifp)
81 {
82 	struct ieee80211com *ic;
83 
84 	ic = malloc(sizeof(struct ieee80211com), M_80211_COM, M_WAITOK|M_ZERO);
85 	ic->ic_ifp = ifp;
86 
87 	return (ic);
88 }
89 
90 static void
91 wlan_free(void *ic, u_char type)
92 {
93 	free(ic, M_80211_COM);
94 }
95 
96 static int
97 wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params)
98 {
99 	struct ieee80211_clone_params cp;
100 	struct ieee80211vap *vap;
101 	struct ieee80211com *ic;
102 	struct ifnet *ifp;
103 	int error;
104 
105 	error = copyin(params, &cp, sizeof(cp));
106 	if (error)
107 		return error;
108 	ifp = ifunit(cp.icp_parent);
109 	if (ifp == NULL)
110 		return ENXIO;
111 	if (ifp->if_type != IFT_IEEE80211) {
112 		if_printf(ifp, "%s: reject, not an 802.11 device\n", __func__);
113 		return EINVAL;
114 	}
115 	ic = ifp->if_l2com;
116 	vap = ic->ic_vap_create(ic, ifc->ifc_name, unit,
117 			cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
118 			cp.icp_flags & IEEE80211_CLONE_MACADDR ?
119 			    cp.icp_macaddr : ic->ic_myaddr);
120 	return (vap == NULL ? EIO : 0);
121 }
122 
123 static void
124 wlan_clone_destroy(struct ifnet *ifp)
125 {
126 	struct ieee80211vap *vap = ifp->if_softc;
127 	struct ieee80211com *ic = vap->iv_ic;
128 
129 	ic->ic_vap_delete(vap);
130 }
131 IFC_SIMPLE_DECLARE(wlan, 0);
132 
133 void
134 ieee80211_vap_destroy(struct ieee80211vap *vap)
135 {
136 	ifc_simple_destroy(&wlan_cloner, vap->iv_ifp);
137 }
138 
139 static int
140 ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS)
141 {
142 	int msecs = ticks_to_msecs(*(int *)arg1);
143 	int error, t;
144 
145 	error = sysctl_handle_int(oidp, &msecs, 0, req);
146 	if (error || !req->newptr)
147 		return error;
148 	t = msecs_to_ticks(msecs);
149 	*(int *)arg1 = (t < 1) ? 1 : t;
150 	return 0;
151 }
152 
153 #ifdef IEEE80211_AMPDU_AGE
154 extern int ieee80211_ampdu_age;
155 SYSCTL_PROC(_net_wlan, OID_AUTO, ampdu_age, CTLFLAG_RW,
156 	&ieee80211_ampdu_age, 0, ieee80211_sysctl_msecs_ticks, "I",
157 	"AMPDU max reorder age (ms)");
158 #endif
159 extern int ieee80211_addba_timeout;
160 SYSCTL_PROC(_net_wlan, OID_AUTO, addba_timeout, CTLFLAG_RW,
161 	&ieee80211_addba_timeout, 0, ieee80211_sysctl_msecs_ticks, "I",
162 	"ADDBA request timeout (ms)");
163 extern int ieee80211_addba_backoff;
164 SYSCTL_PROC(_net_wlan, OID_AUTO, addba_backoff, CTLFLAG_RW,
165 	&ieee80211_addba_backoff, 0, ieee80211_sysctl_msecs_ticks, "I",
166 	"ADDBA request backoff (ms)");
167 extern int ieee80211_addba_maxtries;
168 SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLFLAG_RW,
169 	&ieee80211_addba_maxtries, 0, "max ADDBA requests sent before backoff");
170 
171 static int
172 ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS)
173 {
174 	int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT;
175 	int error;
176 
177 	error = sysctl_handle_int(oidp, &inact, 0, req);
178 	if (error || !req->newptr)
179 		return error;
180 	*(int *)arg1 = inact / IEEE80211_INACT_WAIT;
181 	return 0;
182 }
183 
184 static int
185 ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS)
186 {
187 	struct ieee80211com *ic = arg1;
188 	const char *name = ic->ic_ifp->if_xname;
189 
190 	return SYSCTL_OUT(req, name, strlen(name));
191 }
192 
193 void
194 ieee80211_sysctl_attach(struct ieee80211com *ic)
195 {
196 }
197 
198 void
199 ieee80211_sysctl_detach(struct ieee80211com *ic)
200 {
201 }
202 
203 void
204 ieee80211_sysctl_vattach(struct ieee80211vap *vap)
205 {
206 	struct ifnet *ifp = vap->iv_ifp;
207 	struct sysctl_ctx_list *ctx;
208 	struct sysctl_oid *oid;
209 	char num[14];			/* sufficient for 32 bits */
210 
211 	MALLOC(ctx, struct sysctl_ctx_list *, sizeof(struct sysctl_ctx_list),
212 		M_DEVBUF, M_NOWAIT | M_ZERO);
213 	if (ctx == NULL) {
214 		if_printf(ifp, "%s: cannot allocate sysctl context!\n",
215 			__func__);
216 		return;
217 	}
218 	sysctl_ctx_init(ctx);
219 	snprintf(num, sizeof(num), "%u", ifp->if_dunit);
220 	oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan),
221 		OID_AUTO, num, CTLFLAG_RD, NULL, "");
222 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
223 		"%parent", CTLFLAG_RD, vap->iv_ic, 0,
224 		ieee80211_sysctl_parent, "A", "parent device");
225 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
226 		"driver_caps", CTLFLAG_RW, &vap->iv_caps, 0,
227 		"driver capabilities");
228 #ifdef IEEE80211_DEBUG
229 	vap->iv_debug = ieee80211_debug;
230 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
231 		"debug", CTLFLAG_RW, &vap->iv_debug, 0,
232 		"control debugging printfs");
233 #endif
234 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
235 		"bmiss_max", CTLFLAG_RW, &vap->iv_bmiss_max, 0,
236 		"consecutive beacon misses before scanning");
237 	/* XXX inherit from tunables */
238 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
239 		"inact_run", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_run, 0,
240 		ieee80211_sysctl_inact, "I",
241 		"station inactivity timeout (sec)");
242 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
243 		"inact_probe", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_probe, 0,
244 		ieee80211_sysctl_inact, "I",
245 		"station inactivity probe timeout (sec)");
246 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
247 		"inact_auth", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_auth, 0,
248 		ieee80211_sysctl_inact, "I",
249 		"station authentication timeout (sec)");
250 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
251 		"inact_init", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_init, 0,
252 		ieee80211_sysctl_inact, "I",
253 		"station initial state timeout (sec)");
254 	if (vap->iv_htcaps & IEEE80211_HTC_HT) {
255 		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
256 			"ampdu_mintraffic_bk", CTLFLAG_RW,
257 			&vap->iv_ampdu_mintraffic[WME_AC_BK], 0,
258 			"BK traffic tx aggr threshold (pps)");
259 		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
260 			"ampdu_mintraffic_be", CTLFLAG_RW,
261 			&vap->iv_ampdu_mintraffic[WME_AC_BE], 0,
262 			"BE traffic tx aggr threshold (pps)");
263 		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
264 			"ampdu_mintraffic_vo", CTLFLAG_RW,
265 			&vap->iv_ampdu_mintraffic[WME_AC_VO], 0,
266 			"VO traffic tx aggr threshold (pps)");
267 		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
268 			"ampdu_mintraffic_vi", CTLFLAG_RW,
269 			&vap->iv_ampdu_mintraffic[WME_AC_VI], 0,
270 			"VI traffic tx aggr threshold (pps)");
271 	}
272 	vap->iv_sysctl = ctx;
273 	vap->iv_oid = oid;
274 }
275 
276 void
277 ieee80211_sysctl_vdetach(struct ieee80211vap *vap)
278 {
279 
280 	if (vap->iv_sysctl != NULL) {
281 		sysctl_ctx_free(vap->iv_sysctl);
282 		FREE(vap->iv_sysctl, M_DEVBUF);
283 		vap->iv_sysctl = NULL;
284 	}
285 }
286 
287 int
288 ieee80211_node_dectestref(struct ieee80211_node *ni)
289 {
290 	/* XXX need equivalent of atomic_dec_and_test */
291 	atomic_subtract_int(&ni->ni_refcnt, 1);
292 	return atomic_cmpset_int(&ni->ni_refcnt, 0, 1);
293 }
294 
295 void
296 ieee80211_drain_ifq(struct ifqueue *ifq)
297 {
298 	struct ieee80211_node *ni;
299 	struct mbuf *m;
300 
301 	for (;;) {
302 		IF_DEQUEUE(ifq, m);
303 		if (m == NULL)
304 			break;
305 
306 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
307 		KASSERT(ni != NULL, ("frame w/o node"));
308 		ieee80211_free_node(ni);
309 		m->m_pkthdr.rcvif = NULL;
310 
311 		m_freem(m);
312 	}
313 }
314 
315 void
316 ieee80211_flush_ifq(struct ifqueue *ifq, struct ieee80211vap *vap)
317 {
318 	struct ieee80211_node *ni;
319 	struct mbuf *m, **mprev;
320 
321 	IF_LOCK(ifq);
322 	mprev = &ifq->ifq_head;
323 	while ((m = *mprev) != NULL) {
324 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
325 		if (ni != NULL && ni->ni_vap == vap) {
326 			*mprev = m->m_nextpkt;		/* remove from list */
327 			ifq->ifq_len--;
328 
329 			m_freem(m);
330 			ieee80211_free_node(ni);	/* reclaim ref */
331 		} else
332 			mprev = &m->m_nextpkt;
333 	}
334 	/* recalculate tail ptr */
335 	m = ifq->ifq_head;
336 	for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt)
337 		;
338 	ifq->ifq_tail = m;
339 	IF_UNLOCK(ifq);
340 }
341 
342 /*
343  * As above, for mbufs allocated with m_gethdr/MGETHDR
344  * or initialized by M_COPY_PKTHDR.
345  */
346 #define	MC_ALIGN(m, len)						\
347 do {									\
348 	(m)->m_data += (MCLBYTES - (len)) &~ (sizeof(long) - 1);	\
349 } while (/* CONSTCOND */ 0)
350 
351 /*
352  * Allocate and setup a management frame of the specified
353  * size.  We return the mbuf and a pointer to the start
354  * of the contiguous data area that's been reserved based
355  * on the packet length.  The data area is forced to 32-bit
356  * alignment and the buffer length to a multiple of 4 bytes.
357  * This is done mainly so beacon frames (that require this)
358  * can use this interface too.
359  */
360 struct mbuf *
361 ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen)
362 {
363 	struct mbuf *m;
364 	u_int len;
365 
366 	/*
367 	 * NB: we know the mbuf routines will align the data area
368 	 *     so we don't need to do anything special.
369 	 */
370 	len = roundup2(headroom + pktlen, 4);
371 	KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
372 	if (len < MINCLSIZE) {
373 		m = m_gethdr(M_NOWAIT, MT_DATA);
374 		/*
375 		 * Align the data in case additional headers are added.
376 		 * This should only happen when a WEP header is added
377 		 * which only happens for shared key authentication mgt
378 		 * frames which all fit in MHLEN.
379 		 */
380 		if (m != NULL)
381 			MH_ALIGN(m, len);
382 	} else {
383 		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
384 		if (m != NULL)
385 			MC_ALIGN(m, len);
386 	}
387 	if (m != NULL) {
388 		m->m_data += headroom;
389 		*frm = m->m_data;
390 	}
391 	return m;
392 }
393 
394 int
395 ieee80211_add_callback(struct mbuf *m,
396 	void (*func)(struct ieee80211_node *, void *, int), void *arg)
397 {
398 	struct m_tag *mtag;
399 	struct ieee80211_cb *cb;
400 
401 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK,
402 			sizeof(struct ieee80211_cb), M_NOWAIT);
403 	if (mtag == NULL)
404 		return 0;
405 
406 	cb = (struct ieee80211_cb *)(mtag+1);
407 	cb->func = func;
408 	cb->arg = arg;
409 	m_tag_prepend(m, mtag);
410 	m->m_flags |= M_TXCB;
411 	return 1;
412 }
413 
414 void
415 ieee80211_process_callback(struct ieee80211_node *ni,
416 	struct mbuf *m, int status)
417 {
418 	struct m_tag *mtag;
419 
420 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL);
421 	if (mtag != NULL) {
422 		struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1);
423 		cb->func(ni, cb->arg, status);
424 	}
425 }
426 
427 #include <sys/libkern.h>
428 
429 void
430 get_random_bytes(void *p, size_t n)
431 {
432 	uint8_t *dp = p;
433 
434 	while (n > 0) {
435 		uint32_t v = arc4random();
436 		size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n;
437 		bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n);
438 		dp += sizeof(uint32_t), n -= nb;
439 	}
440 }
441 
442 /*
443  * Helper function for events that pass just a single mac address.
444  */
445 static void
446 notify_macaddr(struct ifnet *ifp, int op, const uint8_t mac[IEEE80211_ADDR_LEN])
447 {
448 	struct ieee80211_join_event iev;
449 
450 	memset(&iev, 0, sizeof(iev));
451 	IEEE80211_ADDR_COPY(iev.iev_addr, mac);
452 	rt_ieee80211msg(ifp, op, &iev, sizeof(iev));
453 }
454 
455 void
456 ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc)
457 {
458 	struct ieee80211vap *vap = ni->ni_vap;
459 	struct ifnet *ifp = vap->iv_ifp;
460 
461 	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode join",
462 	    (ni == vap->iv_bss) ? "bss " : "");
463 
464 	if (ni == vap->iv_bss) {
465 		notify_macaddr(ifp, newassoc ?
466 		    RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, ni->ni_bssid);
467 		if_link_state_change(ifp, LINK_STATE_UP);
468 	} else {
469 		notify_macaddr(ifp, newassoc ?
470 		    RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, ni->ni_macaddr);
471 	}
472 }
473 
474 void
475 ieee80211_notify_node_leave(struct ieee80211_node *ni)
476 {
477 	struct ieee80211vap *vap = ni->ni_vap;
478 	struct ifnet *ifp = vap->iv_ifp;
479 
480 	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode leave",
481 	    (ni == vap->iv_bss) ? "bss " : "");
482 
483 	if (ni == vap->iv_bss) {
484 		rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0);
485 		if_link_state_change(ifp, LINK_STATE_DOWN);
486 	} else {
487 		/* fire off wireless event station leaving */
488 		notify_macaddr(ifp, RTM_IEEE80211_LEAVE, ni->ni_macaddr);
489 	}
490 }
491 
492 void
493 ieee80211_notify_scan_done(struct ieee80211vap *vap)
494 {
495 	struct ifnet *ifp = vap->iv_ifp;
496 
497 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n", "notify scan done");
498 
499 	/* dispatch wireless event indicating scan completed */
500 	rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0);
501 }
502 
503 void
504 ieee80211_notify_replay_failure(struct ieee80211vap *vap,
505 	const struct ieee80211_frame *wh, const struct ieee80211_key *k,
506 	u_int64_t rsc)
507 {
508 	struct ifnet *ifp = vap->iv_ifp;
509 
510 	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
511 	    "%s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>",
512 	    k->wk_cipher->ic_name, (intmax_t) rsc,
513 	    (intmax_t) k->wk_keyrsc[IEEE80211_NONQOS_TID],
514 	    k->wk_keyix, k->wk_rxkeyix);
515 
516 	if (ifp != NULL) {		/* NB: for cipher test modules */
517 		struct ieee80211_replay_event iev;
518 
519 		IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
520 		IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
521 		iev.iev_cipher = k->wk_cipher->ic_cipher;
522 		if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE)
523 			iev.iev_keyix = k->wk_rxkeyix;
524 		else
525 			iev.iev_keyix = k->wk_keyix;
526 		iev.iev_keyrsc = k->wk_keyrsc[0];	/* XXX need tid */
527 		iev.iev_rsc = rsc;
528 		rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev));
529 	}
530 }
531 
532 void
533 ieee80211_notify_michael_failure(struct ieee80211vap *vap,
534 	const struct ieee80211_frame *wh, u_int keyix)
535 {
536 	struct ifnet *ifp = vap->iv_ifp;
537 
538 	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
539 	    "michael MIC verification failed <keyix %u>", keyix);
540 	vap->iv_stats.is_rx_tkipmic++;
541 
542 	if (ifp != NULL) {		/* NB: for cipher test modules */
543 		struct ieee80211_michael_event iev;
544 
545 		IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
546 		IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
547 		iev.iev_cipher = IEEE80211_CIPHER_TKIP;
548 		iev.iev_keyix = keyix;
549 		rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev));
550 	}
551 }
552 
553 void
554 ieee80211_notify_wds_discover(struct ieee80211_node *ni)
555 {
556 	struct ieee80211vap *vap = ni->ni_vap;
557 	struct ifnet *ifp = vap->iv_ifp;
558 
559 	notify_macaddr(ifp, RTM_IEEE80211_WDS, ni->ni_macaddr);
560 }
561 
562 void
563 ieee80211_notify_csa(struct ieee80211com *ic,
564 	const struct ieee80211_channel *c, int mode, int count)
565 {
566 	struct ifnet *ifp = ic->ic_ifp;
567 	struct ieee80211_csa_event iev;
568 
569 	memset(&iev, 0, sizeof(iev));
570 	iev.iev_flags = c->ic_flags;
571 	iev.iev_freq = c->ic_freq;
572 	iev.iev_ieee = c->ic_ieee;
573 	iev.iev_mode = mode;
574 	iev.iev_count = count;
575 	rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev));
576 }
577 
578 void
579 ieee80211_notify_radar(struct ieee80211com *ic,
580 	const struct ieee80211_channel *c)
581 {
582 	struct ifnet *ifp = ic->ic_ifp;
583 	struct ieee80211_radar_event iev;
584 
585 	memset(&iev, 0, sizeof(iev));
586 	iev.iev_flags = c->ic_flags;
587 	iev.iev_freq = c->ic_freq;
588 	iev.iev_ieee = c->ic_ieee;
589 	rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev));
590 }
591 
592 void
593 ieee80211_notify_cac(struct ieee80211com *ic,
594 	const struct ieee80211_channel *c, enum ieee80211_notify_cac_event type)
595 {
596 	struct ifnet *ifp = ic->ic_ifp;
597 	struct ieee80211_cac_event iev;
598 
599 	memset(&iev, 0, sizeof(iev));
600 	iev.iev_flags = c->ic_flags;
601 	iev.iev_freq = c->ic_freq;
602 	iev.iev_ieee = c->ic_ieee;
603 	iev.iev_type = type;
604 	rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev));
605 }
606 
607 void
608 ieee80211_notify_node_deauth(struct ieee80211_node *ni)
609 {
610 	struct ieee80211vap *vap = ni->ni_vap;
611 	struct ifnet *ifp = vap->iv_ifp;
612 
613 	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node deauth");
614 
615 	notify_macaddr(ifp, RTM_IEEE80211_DEAUTH, ni->ni_macaddr);
616 }
617 
618 void
619 ieee80211_notify_node_auth(struct ieee80211_node *ni)
620 {
621 	struct ieee80211vap *vap = ni->ni_vap;
622 	struct ifnet *ifp = vap->iv_ifp;
623 
624 	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node auth");
625 
626 	notify_macaddr(ifp, RTM_IEEE80211_AUTH, ni->ni_macaddr);
627 }
628 
629 void
630 ieee80211_notify_country(struct ieee80211vap *vap,
631 	const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2])
632 {
633 	struct ifnet *ifp = vap->iv_ifp;
634 	struct ieee80211_country_event iev;
635 
636 	memset(&iev, 0, sizeof(iev));
637 	IEEE80211_ADDR_COPY(iev.iev_addr, bssid);
638 	iev.iev_cc[0] = cc[0];
639 	iev.iev_cc[1] = cc[1];
640 	rt_ieee80211msg(ifp, RTM_IEEE80211_COUNTRY, &iev, sizeof(iev));
641 }
642 
643 void
644 ieee80211_notify_radio(struct ieee80211com *ic, int state)
645 {
646 	struct ifnet *ifp = ic->ic_ifp;
647 	struct ieee80211_radio_event iev;
648 
649 	memset(&iev, 0, sizeof(iev));
650 	iev.iev_state = state;
651 	rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev));
652 }
653 
654 void
655 ieee80211_load_module(const char *modname)
656 {
657 
658 #ifdef notyet
659 	(void)kern_kldload(curthread, modname, NULL);
660 #else
661 	printf("%s: load the %s module by hand for now.\n", __func__, modname);
662 #endif
663 }
664 
665 /*
666  * Module glue.
667  *
668  * NB: the module name is "wlan" for compatibility with NetBSD.
669  */
670 static int
671 wlan_modevent(module_t mod, int type, void *unused)
672 {
673 	switch (type) {
674 	case MOD_LOAD:
675 		if (bootverbose)
676 			printf("wlan: <802.11 Link Layer>\n");
677 		if_clone_attach(&wlan_cloner);
678 		if_register_com_alloc(IFT_IEEE80211, wlan_alloc, wlan_free);
679 		return 0;
680 	case MOD_UNLOAD:
681 		if_deregister_com_alloc(IFT_IEEE80211);
682 		if_clone_detach(&wlan_cloner);
683 		return 0;
684 	}
685 	return EINVAL;
686 }
687 
688 static moduledata_t wlan_mod = {
689 	"wlan",
690 	wlan_modevent,
691 	0
692 };
693 DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
694 MODULE_VERSION(wlan, 1);
695 MODULE_DEPEND(wlan, ether, 1, 1, 1);
696