xref: /haiku/src/libs/compat/freebsd_wlan/net80211/ieee80211_haiku.cpp (revision e705c841d784f0035a0ef3e9e96f6e017df16681)
1 /*
2  * Copyright 2009, Colin Günther, coling@gmx.de. All rights reserved.
3  * Copyright 2018, Haiku, Inc. All rights reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 /*-
9  * Copyright (c) 2003-2009 Sam Leffler, Errno Consulting
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 
34 /*
35  * IEEE 802.11 support (Haiku-specific code)
36  */
37 
38 
39 #include "ieee80211_haiku.h"
40 
41 extern "C" {
42 #	include <sys/kernel.h>
43 #	include <sys/mbuf.h>
44 #	include <sys/bus.h>
45 #	include <sys/sockio.h>
46 
47 #	include <net/if.h>
48 #	include <net/if_media.h>
49 #	include <net/if_types.h>
50 #	include <net/if_var.h>
51 
52 #	include "ieee80211_var.h"
53 };
54 
55 #include <SupportDefs.h>
56 
57 #include <util/KMessage.h>
58 
59 #include <ether_driver.h>
60 #include <net_notifications.h>
61 
62 #include <shared.h>
63 
64 
65 #define TRACE_WLAN
66 #ifdef TRACE_WLAN
67 #	define TRACE(x...) dprintf(x);
68 #else
69 #	define TRACE(x...) ;
70 #endif
71 
72 
73 #define	MC_ALIGN(m, len)									\
74 do {														\
75 	(m)->m_data += (MCLBYTES - (len)) &~ (sizeof(long) - 1);\
76 } while (/* CONSTCOND */ 0)
77 
78 
79 static net_notifications_module_info* sNotificationModule;
80 
81 
82 static struct ifnet*
83 get_ifnet(device_t device, int& i)
84 {
85 	int unit = device_get_unit(device);
86 
87 	for (i = 0; i < MAX_DEVICES; i++) {
88 		if (gDevices[i] != NULL && gDevices[i]->if_dunit == unit)
89 			return gDevices[i];
90 	}
91 
92 	return NULL;
93 }
94 
95 
96 status_t
97 init_wlan_stack(void)
98 {
99 	get_module(NET_NOTIFICATIONS_MODULE_NAME,
100 		(module_info**)&sNotificationModule);
101 
102 	return B_OK;
103 }
104 
105 
106 void
107 uninit_wlan_stack(void)
108 {
109 	if (sNotificationModule != NULL)
110 		put_module(NET_NOTIFICATIONS_MODULE_NAME);
111 }
112 
113 
114 status_t
115 start_wlan(device_t device)
116 {
117 	struct ieee80211com* ic = ieee80211_find_com(device->nameunit);
118 	if (ic == NULL)
119 		return B_BAD_VALUE;
120 
121 	struct ieee80211vap* vap = ic->ic_vap_create(ic, "wlan",
122 		device_get_unit(device),
123 		IEEE80211_M_STA,		// mode
124 		0,						// flags
125 		NULL,					// BSSID
126 		ic->ic_macaddr);		// MAC address
127 
128 	if (vap == NULL)
129 		return B_ERROR;
130 
131 	// ic_vap_create() established that gDevices[i] links to vap->iv_ifp now
132 	KASSERT(gDevices[gDeviceCount - 1] == vap->iv_ifp,
133 		("start_wlan: gDevices[i] != vap->iv_ifp"));
134 
135 	vap->iv_ifp->scan_done_sem = create_sem(0, "wlan scan done");
136 
137 	// We aren't connected to a WLAN, yet.
138 	if_link_state_change(vap->iv_ifp, LINK_STATE_DOWN);
139 
140 	dprintf("%s: wlan started.\n", __func__);
141 
142 	return B_OK;
143 }
144 
145 
146 status_t
147 stop_wlan(device_t device)
148 {
149 	int i;
150 	struct ifnet* ifp = get_ifnet(device, i);
151 	if (ifp == NULL)
152 		return B_BAD_VALUE;
153 
154 	delete_sem(ifp->scan_done_sem);
155 
156 	struct ieee80211vap* vap = (ieee80211vap*)ifp->if_softc;
157 	struct ieee80211com* ic = vap->iv_ic;
158 
159 	ic->ic_vap_delete(vap);
160 
161 	// ic_vap_delete freed gDevices[i]
162 	KASSERT(gDevices[i] == NULL, ("stop_wlan: gDevices[i] != NULL"));
163 
164 	return B_OK;
165 }
166 
167 
168 status_t
169 wlan_open(void* cookie)
170 {
171 	dprintf("wlan_open(%p)\n", cookie);
172 	struct ifnet* ifp = (struct ifnet*)cookie;
173 
174 	ifp->if_init(ifp->if_softc);
175 
176 	ifp->if_flags |= IFF_UP;
177 	ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
178 
179 	return B_OK;
180 }
181 
182 
183 status_t
184 wlan_close(void* cookie)
185 {
186 	dprintf("wlan_close(%p)\n", cookie);
187 	struct ifnet* ifp = (struct ifnet*)cookie;
188 
189 	ifp->if_flags &= ~IFF_UP;
190 	ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
191 
192 	return release_sem_etc(ifp->scan_done_sem, 1, B_RELEASE_ALL);
193 }
194 
195 
196 status_t
197 wlan_control(void* cookie, uint32 op, void* arg, size_t length)
198 {
199 	struct ifnet* ifp = (struct ifnet*)cookie;
200 
201 	switch (op) {
202 		case SIOCG80211:
203 		case SIOCS80211:
204 		{
205 			// FreeBSD drivers assume that the request structure has already
206 			// been copied into kernel space
207 			struct ieee80211req request;
208 			if (user_memcpy(&request, arg, sizeof(struct ieee80211req)) != B_OK)
209 				return B_BAD_ADDRESS;
210 
211 			if (request.i_type == IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP)
212 				return wlan_open(cookie);
213 			else if (request.i_type == IEEE80211_IOC_HAIKU_COMPAT_WLAN_DOWN)
214 				return wlan_close(cookie);
215 
216 			TRACE("wlan_control: %" B_PRIu32 ", %d\n", op, request.i_type);
217 			status_t status = ifp->if_ioctl(ifp, op, (caddr_t)&request);
218 			if (status != B_OK)
219 				return status;
220 
221 			if (op == SIOCG80211 && user_memcpy(arg, &request,
222 					sizeof(struct ieee80211req)) != B_OK)
223 				return B_BAD_ADDRESS;
224 			return B_OK;
225 		}
226 
227 		case SIOCSIFFLAGS:
228 		case SIOCSIFMEDIA:
229 		case SIOCGIFMEDIA:
230 		case SIOCSIFMTU:
231 			// Requests that make it here always come from the kernel
232 			return ifp->if_ioctl(ifp, op, (caddr_t)arg);
233 	}
234 
235 	return B_BAD_VALUE;
236 }
237 
238 
239 void
240 get_random_bytes(void* p, size_t n)
241 {
242 	uint8_t* dp = (uint8_t*)p;
243 
244 	while (n > 0) {
245 		uint32_t v = arc4random();
246 		size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n;
247 		bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n);
248 		dp += sizeof(uint32_t), n -= nb;
249 	}
250 }
251 
252 
253 struct mbuf *
254 ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen)
255 {
256 	struct mbuf *m;
257 	u_int len;
258 
259 	/*
260 	 * NB: we know the mbuf routines will align the data area
261 	 *     so we don't need to do anything special.
262 	 */
263 	len = roundup2(headroom + pktlen, 4);
264 	KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
265 	if (len < MINCLSIZE) {
266 		m = m_gethdr(M_NOWAIT, MT_DATA);
267 		/*
268 		 * Align the data in case additional headers are added.
269 		 * This should only happen when a WEP header is added
270 		 * which only happens for shared key authentication mgt
271 		 * frames which all fit in MHLEN.
272 		 */
273 		if (m != NULL)
274 			M_ALIGN(m, len);
275 	} else {
276 		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
277 		if (m != NULL)
278 			MC_ALIGN(m, len);
279 	}
280 	if (m != NULL) {
281 		m->m_data += headroom;
282 		*frm = (uint8_t*)m->m_data;
283 	}
284 	return m;
285 }
286 
287 
288 /*
289  * Decrements the reference-counter and
290  * tests whether it became zero. If so, sets it to one.
291  *
292  * @return 1 reference-counter became zero
293  * @return 0 reference-counter didn't became zero
294  */
295 int
296 ieee80211_node_dectestref(struct ieee80211_node* ni)
297 {
298 	atomic_subtract_int(&ni->ni_refcnt, 1);
299 	return atomic_cmpset_int(&ni->ni_refcnt, 0, 1);
300 }
301 
302 
303 void
304 ieee80211_drain_ifq(struct ifqueue* ifq)
305 {
306 	struct ieee80211_node* ni;
307 	struct mbuf* m;
308 
309 	for (;;) {
310 		IF_DEQUEUE(ifq, m);
311 		if (m == NULL)
312 			break;
313 
314 		ni = (struct ieee80211_node*)m->m_pkthdr.rcvif;
315 		KASSERT(ni != NULL, ("frame w/o node"));
316 		ieee80211_free_node(ni);
317 		m->m_pkthdr.rcvif = NULL;
318 
319 		m_freem(m);
320 	}
321 }
322 
323 
324 void
325 ieee80211_flush_ifq(struct ifqueue* ifq, struct ieee80211vap* vap)
326 {
327 	struct ieee80211_node* ni;
328 	struct mbuf* m;
329 	struct mbuf** mprev;
330 
331 	IF_LOCK(ifq);
332 	mprev = &ifq->ifq_head;
333 	while ((m = *mprev) != NULL) {
334 		ni = (struct ieee80211_node*)m->m_pkthdr.rcvif;
335 		if (ni != NULL && ni->ni_vap == vap) {
336 			*mprev = m->m_nextpkt;
337 				// remove from list
338 			ifq->ifq_len--;
339 
340 			m_freem(m);
341 			ieee80211_free_node(ni);
342 				// reclaim ref
343 		} else
344 			mprev = &m->m_nextpkt;
345 	}
346 	// recalculate tail ptr
347 	m = ifq->ifq_head;
348 	for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt);
349 	ifq->ifq_tail = m;
350 	IF_UNLOCK(ifq);
351 }
352 
353 
354 #ifndef __NO_STRICT_ALIGNMENT
355 /*
356  * Re-align the payload in the mbuf.  This is mainly used (right now)
357  * to handle IP header alignment requirements on certain architectures.
358  */
359 extern "C" struct mbuf *
360 ieee80211_realign(struct ieee80211vap *vap, struct mbuf *m, size_t align)
361 {
362 	int pktlen, space;
363 	struct mbuf *n;
364 
365 	pktlen = m->m_pkthdr.len;
366 	space = pktlen + align;
367 	if (space < MINCLSIZE)
368 		n = m_gethdr(M_NOWAIT, MT_DATA);
369 	else {
370 		n = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
371 		    space <= MCLBYTES ?     MCLBYTES :
372 #if MJUMPAGESIZE != MCLBYTES
373 		    space <= MJUMPAGESIZE ? MJUMPAGESIZE :
374 #endif
375 		    space <= MJUM9BYTES ?   MJUM9BYTES : MJUM16BYTES);
376 	}
377 	if (__predict_true(n != NULL)) {
378 		m_move_pkthdr(n, m);
379 		n->m_data = (caddr_t)(ALIGN(n->m_data + align) - align);
380 		m_copydata(m, 0, pktlen, mtod(n, caddr_t));
381 		n->m_len = pktlen;
382 	} else {
383 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
384 		    mtod(m, const struct ieee80211_frame *), NULL,
385 		    "%s", "no mbuf to realign");
386 		vap->iv_stats.is_rx_badalign++;
387 	}
388 	m_freem(m);
389 	return n;
390 }
391 #endif /* !__NO_STRICT_ALIGNMENT */
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 
415 void
416 ieee80211_process_callback(struct ieee80211_node* ni, struct mbuf* m,
417 	int status)
418 {
419 	struct m_tag* mtag;
420 
421 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL);
422 	if (mtag != NULL) {
423 		struct ieee80211_cb* cb = (struct ieee80211_cb*)(mtag+1);
424 		cb->func(ni, cb->arg, status);
425 	}
426 }
427 
428 
429 int
430 ieee80211_add_xmit_params(struct mbuf *m,
431 	const struct ieee80211_bpf_params *params)
432 {
433 	struct m_tag *mtag;
434 	struct ieee80211_tx_params *tx;
435 
436 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS,
437 		sizeof(struct ieee80211_tx_params), M_NOWAIT);
438 	if (mtag == NULL)
439 		return (0);
440 
441 	tx = (struct ieee80211_tx_params *)(mtag+1);
442 	memcpy(&tx->params, params, sizeof(struct ieee80211_bpf_params));
443 	m_tag_prepend(m, mtag);
444 	return (1);
445 }
446 
447 
448 int
449 ieee80211_get_xmit_params(struct mbuf *m,
450 	struct ieee80211_bpf_params *params)
451 {
452 	struct m_tag *mtag;
453 	struct ieee80211_tx_params *tx;
454 
455 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS,
456 		NULL);
457 	if (mtag == NULL)
458 		return (-1);
459 	tx = (struct ieee80211_tx_params *)(mtag + 1);
460 	memcpy(params, &tx->params, sizeof(struct ieee80211_bpf_params));
461 	return (0);
462 }
463 
464 
465 /*
466  * Add RX parameters to the given mbuf.
467  *
468  * Returns 1 if OK, 0 on error.
469  */
470 int
471 ieee80211_add_rx_params(struct mbuf *m, const struct ieee80211_rx_stats *rxs)
472 {
473 	struct m_tag *mtag;
474 	struct ieee80211_rx_params *rx;
475 
476 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS,
477 		sizeof(struct ieee80211_rx_stats), M_NOWAIT);
478 	if (mtag == NULL)
479 		return (0);
480 
481 	rx = (struct ieee80211_rx_params *)(mtag + 1);
482 	memcpy(&rx->params, rxs, sizeof(*rxs));
483 	m_tag_prepend(m, mtag);
484 	return (1);
485 }
486 
487 
488 int
489 ieee80211_get_rx_params(struct mbuf *m, struct ieee80211_rx_stats *rxs)
490 {
491 	struct m_tag *mtag;
492 	struct ieee80211_rx_params *rx;
493 
494 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS,
495 		NULL);
496 	if (mtag == NULL)
497 		return (-1);
498 	rx = (struct ieee80211_rx_params *)(mtag + 1);
499 	memcpy(rxs, &rx->params, sizeof(*rxs));
500 	return (0);
501 }
502 
503 
504 const struct ieee80211_rx_stats *
505 ieee80211_get_rx_params_ptr(struct mbuf *m)
506 {
507 	struct m_tag *mtag;
508 	struct ieee80211_rx_params *rx;
509 
510 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS,
511 	    NULL);
512 	if (mtag == NULL)
513 		return (NULL);
514 	rx = (struct ieee80211_rx_params *)(mtag + 1);
515 	return (&rx->params);
516 }
517 
518 
519 /*
520  * Add TOA parameters to the given mbuf.
521  */
522 int
523 ieee80211_add_toa_params(struct mbuf *m, const struct ieee80211_toa_params *p)
524 {
525 	struct m_tag *mtag;
526 	struct ieee80211_toa_params *rp;
527 
528 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_TOA_PARAMS,
529 	    sizeof(struct ieee80211_toa_params), M_NOWAIT);
530 	if (mtag == NULL)
531 		return (0);
532 
533 	rp = (struct ieee80211_toa_params *)(mtag + 1);
534 	memcpy(rp, p, sizeof(*rp));
535 	m_tag_prepend(m, mtag);
536 	return (1);
537 }
538 
539 
540 int
541 ieee80211_get_toa_params(struct mbuf *m, struct ieee80211_toa_params *p)
542 {
543 	struct m_tag *mtag;
544 	struct ieee80211_toa_params *rp;
545 
546 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_TOA_PARAMS,
547 	    NULL);
548 	if (mtag == NULL)
549 		return (0);
550 	rp = (struct ieee80211_toa_params *)(mtag + 1);
551 	if (p != NULL)
552 		memcpy(p, rp, sizeof(*p));
553 	return (1);
554 }
555 
556 
557 /*
558  * Transmit a frame to the parent interface.
559  */
560 int
561 ieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m)
562 {
563 	int error;
564 
565 	/*
566 	 * Assert the IC TX lock is held - this enforces the
567 	 * processing -> queuing order is maintained
568 	 */
569 	IEEE80211_TX_LOCK_ASSERT(ic);
570 	error = ic->ic_transmit(ic, m);
571 	if (error) {
572 		struct ieee80211_node *ni;
573 
574 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
575 
576 		/* XXX number of fragments */
577 		if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1);
578 		ieee80211_free_node(ni);
579 		ieee80211_free_mbuf(m);
580 	}
581 	return (error);
582 }
583 
584 
585 /*
586  * Transmit a frame to the VAP interface.
587  */
588 int
589 ieee80211_vap_xmitpkt(struct ieee80211vap *vap, struct mbuf *m)
590 {
591 	struct ifnet *ifp = vap->iv_ifp;
592 
593 	/*
594 	 * When transmitting via the VAP, we shouldn't hold
595 	 * any IC TX lock as the VAP TX path will acquire it.
596 	 */
597 	IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
598 
599 	return (ifp->if_transmit(ifp, m));
600 
601 }
602 
603 
604 void
605 ieee80211_sysctl_vattach(struct ieee80211vap* vap)
606 {
607 	vap->iv_debug = IEEE80211_MSG_XRATE
608 		| IEEE80211_MSG_NODE
609 		| IEEE80211_MSG_ASSOC
610 		| IEEE80211_MSG_AUTH
611 		| IEEE80211_MSG_STATE
612 		| IEEE80211_MSG_WME
613 		| IEEE80211_MSG_DOTH
614 		| IEEE80211_MSG_INACT
615 		| IEEE80211_MSG_ROAM;
616 }
617 
618 
619 void
620 ieee80211_sysctl_vdetach(struct ieee80211vap* vap)
621 {
622 	dprintf("%s not implemented, yet.\n", __func__);
623 }
624 
625 
626 void
627 ieee80211_vap_destroy(struct ieee80211vap* vap)
628 {
629 	struct ieee80211com* ic = vap->iv_ic;
630 
631 	ic->ic_vap_delete(vap);
632 	dprintf("%s: done.\n", __func__);
633 }
634 
635 
636 void
637 ieee80211_load_module(const char* modname)
638 {
639 #if 0
640 	dprintf("%s not implemented, yet: modname %s\n", __func__, modname);
641 #endif
642 }
643 
644 
645 void
646 ieee80211_notify_node_join(struct ieee80211_node* ni, int newassoc)
647 {
648 	struct ieee80211vap* vap = ni->ni_vap;
649 	struct ifnet* ifp = vap->iv_ifp;
650 
651 	TRACE("%s\n", __FUNCTION__);
652 
653 	if (ni == vap->iv_bss)
654 		if_link_state_change(ifp, LINK_STATE_UP);
655 
656 	if (sNotificationModule != NULL) {
657 		char messageBuffer[512];
658 		KMessage message;
659 		message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
660 		message.AddInt32("opcode", B_NETWORK_WLAN_JOINED);
661 		message.AddString("interface", ifp->device_name);
662 		// TODO: add data about the node
663 
664 		sNotificationModule->send_notification(&message);
665 	}
666 }
667 
668 
669 void
670 ieee80211_notify_node_leave(struct ieee80211_node* ni)
671 {
672 	struct ieee80211vap* vap = ni->ni_vap;
673 	struct ifnet* ifp = vap->iv_ifp;
674 
675 	if (ni == vap->iv_bss)
676 		if_link_state_change(ifp, LINK_STATE_DOWN);
677 
678 	TRACE("%s\n", __FUNCTION__);
679 
680 	if (sNotificationModule != NULL) {
681 		char messageBuffer[512];
682 		KMessage message;
683 		message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
684 		message.AddInt32("opcode", B_NETWORK_WLAN_LEFT);
685 		message.AddString("interface", ifp->device_name);
686 		// TODO: add data about the node
687 
688 		sNotificationModule->send_notification(&message);
689 	}
690 }
691 
692 
693 void
694 ieee80211_notify_scan_done(struct ieee80211vap* vap)
695 {
696 	release_sem_etc(vap->iv_ifp->scan_done_sem, 1,
697 		B_DO_NOT_RESCHEDULE | B_RELEASE_ALL);
698 
699 	TRACE("%s\n", __FUNCTION__);
700 
701 	if (sNotificationModule != NULL) {
702 		char messageBuffer[512];
703 		KMessage message;
704 		message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
705 		message.AddInt32("opcode", B_NETWORK_WLAN_SCANNED);
706 		message.AddString("interface", vap->iv_ifp->device_name);
707 
708 		sNotificationModule->send_notification(&message);
709 	}
710 }
711 
712 
713 void
714 ieee80211_notify_replay_failure(struct ieee80211vap* vap,
715 	const struct ieee80211_frame* wh, const struct ieee80211_key* k,
716 	u_int64_t rsc, int tid)
717 {
718 	dprintf("%s not implemented, yet.\n", __func__);
719 }
720 
721 
722 void
723 ieee80211_notify_michael_failure(struct ieee80211vap* vap,
724 	const struct ieee80211_frame* wh, u_int keyix)
725 {
726 	dprintf("%s not implemented, yet.\n", __func__);
727 }
728 
729 
730 void
731 ieee80211_notify_wds_discover(struct ieee80211_node* ni)
732 {
733 	dprintf("%s not implemented, yet.\n", __func__);
734 }
735 
736 
737 void
738 ieee80211_notify_csa(struct ieee80211com* ic,
739 	const struct ieee80211_channel* c, int mode, int count)
740 {
741 	dprintf("%s not implemented, yet.\n", __func__);
742 }
743 
744 
745 void
746 ieee80211_notify_radar(struct ieee80211com* ic,
747 	const struct ieee80211_channel* c)
748 {
749 	dprintf("%s not implemented, yet.\n", __func__);
750 }
751 
752 
753 void
754 ieee80211_notify_cac(struct ieee80211com* ic,
755 	const struct ieee80211_channel* c, enum ieee80211_notify_cac_event type)
756 {
757 	dprintf("%s not implemented, yet.\n", __func__);
758 }
759 
760 
761 void
762 ieee80211_notify_node_deauth(struct ieee80211_node* ni)
763 {
764 	dprintf("%s not implemented, yet.\n", __func__);
765 }
766 
767 
768 void
769 ieee80211_notify_node_auth(struct ieee80211_node* ni)
770 {
771 	dprintf("%s not implemented, yet.\n", __func__);
772 }
773 
774 
775 void
776 ieee80211_notify_country(struct ieee80211vap* vap,
777 	const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2])
778 {
779 	dprintf("%s not implemented, yet.\n", __func__);
780 }
781 
782 
783 void
784 ieee80211_notify_radio(struct ieee80211com* ic, int state)
785 {
786 	dprintf("%s not implemented, yet.\n", __func__);
787 }
788 
789 
790 void
791 ieee80211_sysctl_attach(struct ieee80211com* ic)
792 {
793 	dprintf("%s not implemented, yet.\n", __func__);
794 }
795 
796 
797 void
798 ieee80211_sysctl_detach(struct ieee80211com* ic)
799 {
800 	dprintf("%s not implemented, yet.\n", __func__);
801 }
802