xref: /haiku/src/libs/compat/freebsd_wlan/net80211/ieee80211_haiku.cpp (revision 4a850ca730d8282b5b924e49e09b4ba4d6db7f54)
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 /*
83  * priv(9) NET80211 checks.
84  * Return 0 if operation is allowed, E* (usually EPERM) otherwise.
85  */
86 int
87 ieee80211_priv_check_vap_getkey(u_long cmd __unused,
88      struct ieee80211vap *vap __unused, struct ifnet *ifp __unused)
89 {
90 	return 0;
91 }
92 
93 int
94 ieee80211_priv_check_vap_manage(u_long cmd __unused,
95      struct ieee80211vap *vap __unused, struct ifnet *ifp __unused)
96 {
97 	return 0;
98 }
99 
100 int
101 ieee80211_priv_check_vap_setmac(u_long cmd __unused,
102      struct ieee80211vap *vap __unused, struct ifnet *ifp __unused)
103 {
104 	return 0;
105 }
106 
107 int
108 ieee80211_priv_check_create_vap(u_long cmd __unused,
109     struct ieee80211vap *vap __unused, struct ifnet *ifp __unused)
110 {
111 	return 0;
112 }
113 
114 
115 static struct ifnet*
116 get_ifnet(device_t device, int& i)
117 {
118 	int unit = device_get_unit(device);
119 
120 	for (i = 0; i < MAX_DEVICES; i++) {
121 		if (gDevices[i] != NULL && gDevices[i]->if_dunit == unit)
122 			return gDevices[i];
123 	}
124 
125 	return NULL;
126 }
127 
128 
129 status_t
130 init_wlan_stack(void)
131 {
132 	get_module(NET_NOTIFICATIONS_MODULE_NAME,
133 		(module_info**)&sNotificationModule);
134 
135 	return B_OK;
136 }
137 
138 
139 void
140 uninit_wlan_stack(void)
141 {
142 	if (sNotificationModule != NULL)
143 		put_module(NET_NOTIFICATIONS_MODULE_NAME);
144 }
145 
146 
147 status_t
148 start_wlan(device_t device)
149 {
150 	struct ieee80211com* ic = ieee80211_find_com(device->nameunit);
151 	if (ic == NULL)
152 		return B_BAD_VALUE;
153 
154 	struct ieee80211vap* vap = ic->ic_vap_create(ic, "wlan",
155 		device_get_unit(device),
156 		IEEE80211_M_STA,		// mode
157 		0,						// flags
158 		NULL,					// BSSID
159 		ic->ic_macaddr);		// MAC address
160 
161 	if (vap == NULL)
162 		return B_ERROR;
163 
164 	// ic_vap_create() established that gDevices[i] links to vap->iv_ifp now
165 	KASSERT(gDevices[gDeviceCount - 1] == vap->iv_ifp,
166 		("start_wlan: gDevices[i] != vap->iv_ifp"));
167 
168 	vap->iv_ifp->scan_done_sem = create_sem(0, "wlan scan done");
169 
170 	// We aren't connected to a WLAN, yet.
171 	if_link_state_change(vap->iv_ifp, LINK_STATE_DOWN);
172 
173 	dprintf("%s: wlan started.\n", __func__);
174 
175 	return B_OK;
176 }
177 
178 
179 status_t
180 stop_wlan(device_t device)
181 {
182 	int i;
183 	struct ifnet* ifp = get_ifnet(device, i);
184 	if (ifp == NULL)
185 		return B_BAD_VALUE;
186 
187 	delete_sem(ifp->scan_done_sem);
188 
189 	struct ieee80211vap* vap = (ieee80211vap*)ifp->if_softc;
190 	struct ieee80211com* ic = vap->iv_ic;
191 
192 	ic->ic_vap_delete(vap);
193 
194 	// ic_vap_delete freed gDevices[i]
195 	KASSERT(gDevices[i] == NULL, ("stop_wlan: gDevices[i] != NULL"));
196 
197 	return B_OK;
198 }
199 
200 
201 status_t
202 wlan_open(void* cookie)
203 {
204 	dprintf("wlan_open(%p)\n", cookie);
205 	struct ifnet* ifp = (struct ifnet*)cookie;
206 
207 	ifp->if_init(ifp->if_softc);
208 
209 	ifp->if_flags |= IFF_UP;
210 	ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
211 
212 	return B_OK;
213 }
214 
215 
216 status_t
217 wlan_close(void* cookie)
218 {
219 	dprintf("wlan_close(%p)\n", cookie);
220 	struct ifnet* ifp = (struct ifnet*)cookie;
221 
222 	ifp->if_flags &= ~IFF_UP;
223 	ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
224 
225 	return release_sem_etc(ifp->scan_done_sem, 1, B_RELEASE_ALL);
226 }
227 
228 
229 status_t
230 wlan_control(void* cookie, uint32 op, void* arg, size_t length)
231 {
232 	struct ifnet* ifp = (struct ifnet*)cookie;
233 
234 	switch (op) {
235 		case SIOCG80211:
236 		case SIOCS80211:
237 		{
238 			// FreeBSD drivers assume that the request structure has already
239 			// been copied into kernel space
240 			struct ieee80211req request;
241 			if (user_memcpy(&request, arg, sizeof(struct ieee80211req)) != B_OK)
242 				return B_BAD_ADDRESS;
243 
244 			if (request.i_type == IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP)
245 				return wlan_open(cookie);
246 			else if (request.i_type == IEEE80211_IOC_HAIKU_COMPAT_WLAN_DOWN)
247 				return wlan_close(cookie);
248 
249 			TRACE("wlan_control: %" B_PRIu32 ", %d\n", op, request.i_type);
250 			status_t status = ifp->if_ioctl(ifp, op, (caddr_t)&request);
251 			if (status != B_OK)
252 				return status;
253 
254 			if (op == SIOCG80211 && user_memcpy(arg, &request,
255 					sizeof(struct ieee80211req)) != B_OK)
256 				return B_BAD_ADDRESS;
257 			return B_OK;
258 		}
259 
260 		case SIOCSIFFLAGS:
261 		case SIOCSIFMEDIA:
262 		case SIOCGIFMEDIA:
263 		case SIOCSIFMTU:
264 			// Requests that make it here always come from the kernel
265 			return ifp->if_ioctl(ifp, op, (caddr_t)arg);
266 	}
267 
268 	return B_BAD_VALUE;
269 }
270 
271 
272 void
273 get_random_bytes(void* p, size_t n)
274 {
275 	uint8_t* dp = (uint8_t*)p;
276 
277 	while (n > 0) {
278 		uint32_t v = arc4random();
279 		size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n;
280 		bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n);
281 		dp += sizeof(uint32_t), n -= nb;
282 	}
283 }
284 
285 
286 struct mbuf *
287 ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen)
288 {
289 	struct mbuf *m;
290 	u_int len;
291 
292 	/*
293 	 * NB: we know the mbuf routines will align the data area
294 	 *     so we don't need to do anything special.
295 	 */
296 	len = roundup2(headroom + pktlen, 4);
297 	KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
298 	if (len < MINCLSIZE) {
299 		m = m_gethdr(M_NOWAIT, MT_DATA);
300 		/*
301 		 * Align the data in case additional headers are added.
302 		 * This should only happen when a WEP header is added
303 		 * which only happens for shared key authentication mgt
304 		 * frames which all fit in MHLEN.
305 		 */
306 		if (m != NULL)
307 			M_ALIGN(m, len);
308 	} else {
309 		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
310 		if (m != NULL)
311 			MC_ALIGN(m, len);
312 	}
313 	if (m != NULL) {
314 		m->m_data += headroom;
315 		*frm = (uint8_t*)m->m_data;
316 	}
317 	return m;
318 }
319 
320 
321 int
322 ieee80211_com_vincref(struct ieee80211vap *vap)
323 {
324 	uint32_t ostate;
325 
326 	ostate = atomic_fetchadd_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
327 
328 	if (ostate & IEEE80211_COM_DETACHED) {
329 		atomic_subtract_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
330 		return (ENETDOWN);
331 	}
332 
333 	if (_IEEE80211_MASKSHIFT(ostate, IEEE80211_COM_REF) ==
334 	    IEEE80211_COM_REF_MAX) {
335 		atomic_subtract_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
336 		return (EOVERFLOW);
337 	}
338 
339 	return (0);
340 }
341 
342 
343 void
344 ieee80211_com_vdecref(struct ieee80211vap *vap)
345 {
346 	uint32_t ostate;
347 
348 	ostate = atomic_fetchadd_32(&vap->iv_com_state, -IEEE80211_COM_REF_ADD);
349 
350 	KASSERT(_IEEE80211_MASKSHIFT(ostate, IEEE80211_COM_REF) != 0,
351 	    ("com reference counter underflow"));
352 
353 	(void) ostate;
354 }
355 
356 
357 void
358 ieee80211_com_vdetach(struct ieee80211vap *vap)
359 {
360 	int sleep_time;
361 
362 	sleep_time = msecs_to_ticks(250);
363 	atomic_set_32(&vap->iv_com_state, IEEE80211_COM_DETACHED);
364 	while (_IEEE80211_MASKSHIFT(atomic_load_32(&vap->iv_com_state),
365 	    IEEE80211_COM_REF) != 0)
366 		pause("comref", sleep_time);
367 }
368 
369 
370 /*
371  * Decrements the reference-counter and
372  * tests whether it became zero. If so, sets it to one.
373  *
374  * @return 1 reference-counter became zero
375  * @return 0 reference-counter didn't became zero
376  */
377 int
378 ieee80211_node_dectestref(struct ieee80211_node* ni)
379 {
380 	atomic_subtract_int(&ni->ni_refcnt, 1);
381 	return atomic_cmpset_int(&ni->ni_refcnt, 0, 1);
382 }
383 
384 
385 void
386 ieee80211_drain_ifq(struct ifqueue* ifq)
387 {
388 	struct ieee80211_node* ni;
389 	struct mbuf* m;
390 
391 	for (;;) {
392 		IF_DEQUEUE(ifq, m);
393 		if (m == NULL)
394 			break;
395 
396 		ni = (struct ieee80211_node*)m->m_pkthdr.rcvif;
397 		KASSERT(ni != NULL, ("frame w/o node"));
398 		ieee80211_free_node(ni);
399 		m->m_pkthdr.rcvif = NULL;
400 
401 		m_freem(m);
402 	}
403 }
404 
405 
406 void
407 ieee80211_flush_ifq(struct ifqueue* ifq, struct ieee80211vap* vap)
408 {
409 	struct ieee80211_node* ni;
410 	struct mbuf* m;
411 	struct mbuf** mprev;
412 
413 	IF_LOCK(ifq);
414 	mprev = &ifq->ifq_head;
415 	while ((m = *mprev) != NULL) {
416 		ni = (struct ieee80211_node*)m->m_pkthdr.rcvif;
417 		if (ni != NULL && ni->ni_vap == vap) {
418 			*mprev = m->m_nextpkt;
419 				// remove from list
420 			ifq->ifq_len--;
421 
422 			m_freem(m);
423 			ieee80211_free_node(ni);
424 				// reclaim ref
425 		} else
426 			mprev = &m->m_nextpkt;
427 	}
428 	// recalculate tail ptr
429 	m = ifq->ifq_head;
430 	for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt);
431 	ifq->ifq_tail = m;
432 	IF_UNLOCK(ifq);
433 }
434 
435 
436 #ifndef __NO_STRICT_ALIGNMENT
437 /*
438  * Re-align the payload in the mbuf.  This is mainly used (right now)
439  * to handle IP header alignment requirements on certain architectures.
440  */
441 extern "C" struct mbuf *
442 ieee80211_realign(struct ieee80211vap *vap, struct mbuf *m, size_t align)
443 {
444 	int pktlen, space;
445 	struct mbuf *n;
446 
447 	pktlen = m->m_pkthdr.len;
448 	space = pktlen + align;
449 	if (space < MINCLSIZE)
450 		n = m_gethdr(M_NOWAIT, MT_DATA);
451 	else {
452 		n = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
453 		    space <= MCLBYTES ?     MCLBYTES :
454 #if MJUMPAGESIZE != MCLBYTES
455 		    space <= MJUMPAGESIZE ? MJUMPAGESIZE :
456 #endif
457 		    space <= MJUM9BYTES ?   MJUM9BYTES : MJUM16BYTES);
458 	}
459 	if (__predict_true(n != NULL)) {
460 		m_move_pkthdr(n, m);
461 		n->m_data = (caddr_t)(ALIGN(n->m_data + align) - align);
462 		m_copydata(m, 0, pktlen, mtod(n, caddr_t));
463 		n->m_len = pktlen;
464 	} else {
465 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
466 		    mtod(m, const struct ieee80211_frame *), NULL,
467 		    "%s", "no mbuf to realign");
468 		vap->iv_stats.is_rx_badalign++;
469 	}
470 	m_freem(m);
471 	return n;
472 }
473 #endif /* !__NO_STRICT_ALIGNMENT */
474 
475 
476 int
477 ieee80211_add_callback(struct mbuf* m,
478 	void (*func)(struct ieee80211_node*, void*, int), void* arg)
479 {
480 	struct m_tag* mtag;
481 	struct ieee80211_cb* cb;
482 
483 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK,
484 		sizeof(struct ieee80211_cb), M_NOWAIT);
485 	if (mtag == NULL)
486 		return 0;
487 
488 	cb = (struct ieee80211_cb*)(mtag+1);
489 	cb->func = func;
490 	cb->arg = arg;
491 	m_tag_prepend(m, mtag);
492 	m->m_flags |= M_TXCB;
493 	return 1;
494 }
495 
496 
497 void
498 ieee80211_process_callback(struct ieee80211_node* ni, struct mbuf* m,
499 	int status)
500 {
501 	struct m_tag* mtag;
502 
503 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL);
504 	if (mtag != NULL) {
505 		struct ieee80211_cb* cb = (struct ieee80211_cb*)(mtag+1);
506 		cb->func(ni, cb->arg, status);
507 	}
508 }
509 
510 
511 int
512 ieee80211_add_xmit_params(struct mbuf *m,
513 	const struct ieee80211_bpf_params *params)
514 {
515 	struct m_tag *mtag;
516 	struct ieee80211_tx_params *tx;
517 
518 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS,
519 		sizeof(struct ieee80211_tx_params), M_NOWAIT);
520 	if (mtag == NULL)
521 		return (0);
522 
523 	tx = (struct ieee80211_tx_params *)(mtag+1);
524 	memcpy(&tx->params, params, sizeof(struct ieee80211_bpf_params));
525 	m_tag_prepend(m, mtag);
526 	return (1);
527 }
528 
529 
530 int
531 ieee80211_get_xmit_params(struct mbuf *m,
532 	struct ieee80211_bpf_params *params)
533 {
534 	struct m_tag *mtag;
535 	struct ieee80211_tx_params *tx;
536 
537 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS,
538 		NULL);
539 	if (mtag == NULL)
540 		return (-1);
541 	tx = (struct ieee80211_tx_params *)(mtag + 1);
542 	memcpy(params, &tx->params, sizeof(struct ieee80211_bpf_params));
543 	return (0);
544 }
545 
546 
547 /*
548  * Add RX parameters to the given mbuf.
549  *
550  * Returns 1 if OK, 0 on error.
551  */
552 int
553 ieee80211_add_rx_params(struct mbuf *m, const struct ieee80211_rx_stats *rxs)
554 {
555 	struct m_tag *mtag;
556 	struct ieee80211_rx_params *rx;
557 
558 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS,
559 		sizeof(struct ieee80211_rx_stats), M_NOWAIT);
560 	if (mtag == NULL)
561 		return (0);
562 
563 	rx = (struct ieee80211_rx_params *)(mtag + 1);
564 	memcpy(&rx->params, rxs, sizeof(*rxs));
565 	m_tag_prepend(m, mtag);
566 	return (1);
567 }
568 
569 
570 int
571 ieee80211_get_rx_params(struct mbuf *m, struct ieee80211_rx_stats *rxs)
572 {
573 	struct m_tag *mtag;
574 	struct ieee80211_rx_params *rx;
575 
576 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS,
577 		NULL);
578 	if (mtag == NULL)
579 		return (-1);
580 	rx = (struct ieee80211_rx_params *)(mtag + 1);
581 	memcpy(rxs, &rx->params, sizeof(*rxs));
582 	return (0);
583 }
584 
585 
586 const struct ieee80211_rx_stats *
587 ieee80211_get_rx_params_ptr(struct mbuf *m)
588 {
589 	struct m_tag *mtag;
590 	struct ieee80211_rx_params *rx;
591 
592 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS,
593 	    NULL);
594 	if (mtag == NULL)
595 		return (NULL);
596 	rx = (struct ieee80211_rx_params *)(mtag + 1);
597 	return (&rx->params);
598 }
599 
600 
601 /*
602  * Add TOA parameters to the given mbuf.
603  */
604 int
605 ieee80211_add_toa_params(struct mbuf *m, const struct ieee80211_toa_params *p)
606 {
607 	struct m_tag *mtag;
608 	struct ieee80211_toa_params *rp;
609 
610 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_TOA_PARAMS,
611 	    sizeof(struct ieee80211_toa_params), M_NOWAIT);
612 	if (mtag == NULL)
613 		return (0);
614 
615 	rp = (struct ieee80211_toa_params *)(mtag + 1);
616 	memcpy(rp, p, sizeof(*rp));
617 	m_tag_prepend(m, mtag);
618 	return (1);
619 }
620 
621 
622 int
623 ieee80211_get_toa_params(struct mbuf *m, struct ieee80211_toa_params *p)
624 {
625 	struct m_tag *mtag;
626 	struct ieee80211_toa_params *rp;
627 
628 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_TOA_PARAMS,
629 	    NULL);
630 	if (mtag == NULL)
631 		return (0);
632 	rp = (struct ieee80211_toa_params *)(mtag + 1);
633 	if (p != NULL)
634 		memcpy(p, rp, sizeof(*p));
635 	return (1);
636 }
637 
638 
639 /*
640  * Transmit a frame to the parent interface.
641  */
642 int
643 ieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m)
644 {
645 	int error;
646 
647 	/*
648 	 * Assert the IC TX lock is held - this enforces the
649 	 * processing -> queuing order is maintained
650 	 */
651 	IEEE80211_TX_LOCK_ASSERT(ic);
652 	error = ic->ic_transmit(ic, m);
653 	if (error) {
654 		struct ieee80211_node *ni;
655 
656 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
657 
658 		/* XXX number of fragments */
659 		if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1);
660 		ieee80211_free_node(ni);
661 		ieee80211_free_mbuf(m);
662 	}
663 	return (error);
664 }
665 
666 
667 /*
668  * Fetch the VAP name.
669  *
670  * This returns a const char pointer suitable for debugging,
671  * but don't expect it to stick around for much longer.
672  */
673 const char *
674 ieee80211_get_vap_ifname(struct ieee80211vap *vap)
675 {
676 	if (vap->iv_ifp == NULL)
677 		return "(none)";
678 	return vap->iv_ifp->if_xname;
679 }
680 
681 #ifdef DEBUGNET
682 static void
683 ieee80211_debugnet_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
684 {
685 	struct ieee80211vap *vap;
686 	struct ieee80211com *ic;
687 
688 	vap = if_getsoftc(ifp);
689 	ic = vap->iv_ic;
690 
691 	IEEE80211_LOCK(ic);
692 	ic->ic_debugnet_meth->dn8_init(ic, nrxr, ncl, clsize);
693 	IEEE80211_UNLOCK(ic);
694 }
695 
696 static void
697 ieee80211_debugnet_event(struct ifnet *ifp, enum debugnet_ev ev)
698 {
699 	struct ieee80211vap *vap;
700 	struct ieee80211com *ic;
701 
702 	vap = if_getsoftc(ifp);
703 	ic = vap->iv_ic;
704 
705 	IEEE80211_LOCK(ic);
706 	ic->ic_debugnet_meth->dn8_event(ic, ev);
707 	IEEE80211_UNLOCK(ic);
708 }
709 
710 static int
711 ieee80211_debugnet_transmit(struct ifnet *ifp, struct mbuf *m)
712 {
713 	return (ieee80211_vap_transmit(ifp, m));
714 }
715 
716 static int
717 ieee80211_debugnet_poll(struct ifnet *ifp, int count)
718 {
719 	struct ieee80211vap *vap;
720 	struct ieee80211com *ic;
721 
722 	vap = if_getsoftc(ifp);
723 	ic = vap->iv_ic;
724 
725 	return (ic->ic_debugnet_meth->dn8_poll(ic, count));
726 }
727 #endif
728 
729 /*
730  * Transmit a frame to the VAP interface.
731  */
732 int
733 ieee80211_vap_xmitpkt(struct ieee80211vap *vap, struct mbuf *m)
734 {
735 	struct ifnet *ifp = vap->iv_ifp;
736 
737 	/*
738 	 * When transmitting via the VAP, we shouldn't hold
739 	 * any IC TX lock as the VAP TX path will acquire it.
740 	 */
741 	IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
742 
743 	return (ifp->if_transmit(ifp, m));
744 
745 }
746 
747 
748 void
749 ieee80211_sysctl_vattach(struct ieee80211vap* vap)
750 {
751 	vap->iv_debug = IEEE80211_MSG_XRATE
752 		| IEEE80211_MSG_NODE
753 		| IEEE80211_MSG_ASSOC
754 		| IEEE80211_MSG_AUTH
755 		| IEEE80211_MSG_STATE
756 		| IEEE80211_MSG_WME
757 		| IEEE80211_MSG_DOTH
758 		| IEEE80211_MSG_INACT
759 		| IEEE80211_MSG_ROAM;
760 }
761 
762 
763 void
764 ieee80211_sysctl_vdetach(struct ieee80211vap* vap)
765 {
766 	dprintf("%s not implemented, yet.\n", __func__);
767 }
768 
769 
770 void
771 ieee80211_vap_destroy(struct ieee80211vap* vap)
772 {
773 	struct ieee80211com* ic = vap->iv_ic;
774 
775 	ic->ic_vap_delete(vap);
776 	dprintf("%s: done.\n", __func__);
777 }
778 
779 
780 void
781 ieee80211_load_module(const char* modname)
782 {
783 #if 0
784 	dprintf("%s not implemented, yet: modname %s\n", __func__, modname);
785 #endif
786 }
787 
788 
789 void
790 ieee80211_notify_node_join(struct ieee80211_node* ni, int newassoc)
791 {
792 	struct ieee80211vap* vap = ni->ni_vap;
793 	struct ifnet* ifp = vap->iv_ifp;
794 
795 	TRACE("%s\n", __FUNCTION__);
796 
797 	if (ni == vap->iv_bss)
798 		if_link_state_change(ifp, LINK_STATE_UP);
799 
800 	if (sNotificationModule != NULL) {
801 		char messageBuffer[512];
802 		KMessage message;
803 		message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
804 		message.AddInt32("opcode", B_NETWORK_WLAN_JOINED);
805 		message.AddString("interface", ifp->device_name);
806 		// TODO: add data about the node
807 
808 		sNotificationModule->send_notification(&message);
809 	}
810 }
811 
812 
813 void
814 ieee80211_notify_node_leave(struct ieee80211_node* ni)
815 {
816 	struct ieee80211vap* vap = ni->ni_vap;
817 	struct ifnet* ifp = vap->iv_ifp;
818 
819 	if (ni == vap->iv_bss)
820 		if_link_state_change(ifp, LINK_STATE_DOWN);
821 
822 	TRACE("%s\n", __FUNCTION__);
823 
824 	if (sNotificationModule != NULL) {
825 		char messageBuffer[512];
826 		KMessage message;
827 		message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
828 		message.AddInt32("opcode", B_NETWORK_WLAN_LEFT);
829 		message.AddString("interface", ifp->device_name);
830 		// TODO: add data about the node
831 
832 		sNotificationModule->send_notification(&message);
833 	}
834 }
835 
836 
837 void
838 ieee80211_notify_scan_done(struct ieee80211vap* vap)
839 {
840 	release_sem_etc(vap->iv_ifp->scan_done_sem, 1,
841 		B_DO_NOT_RESCHEDULE | B_RELEASE_ALL);
842 
843 	TRACE("%s\n", __FUNCTION__);
844 
845 	if (sNotificationModule != NULL) {
846 		char messageBuffer[512];
847 		KMessage message;
848 		message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
849 		message.AddInt32("opcode", B_NETWORK_WLAN_SCANNED);
850 		message.AddString("interface", vap->iv_ifp->device_name);
851 
852 		sNotificationModule->send_notification(&message);
853 	}
854 }
855 
856 
857 void
858 ieee80211_notify_replay_failure(struct ieee80211vap* vap,
859 	const struct ieee80211_frame* wh, const struct ieee80211_key* k,
860 	u_int64_t rsc, int tid)
861 {
862 	dprintf("%s not implemented, yet.\n", __func__);
863 }
864 
865 
866 void
867 ieee80211_notify_michael_failure(struct ieee80211vap* vap,
868 	const struct ieee80211_frame* wh, u_int keyix)
869 {
870 	dprintf("%s not implemented, yet.\n", __func__);
871 }
872 
873 
874 void
875 ieee80211_notify_wds_discover(struct ieee80211_node* ni)
876 {
877 	dprintf("%s not implemented, yet.\n", __func__);
878 }
879 
880 
881 void
882 ieee80211_notify_csa(struct ieee80211com* ic,
883 	const struct ieee80211_channel* c, int mode, int count)
884 {
885 	dprintf("%s not implemented, yet.\n", __func__);
886 }
887 
888 
889 void
890 ieee80211_notify_radar(struct ieee80211com* ic,
891 	const struct ieee80211_channel* c)
892 {
893 	dprintf("%s not implemented, yet.\n", __func__);
894 }
895 
896 
897 void
898 ieee80211_notify_cac(struct ieee80211com* ic,
899 	const struct ieee80211_channel* c, enum ieee80211_notify_cac_event type)
900 {
901 	dprintf("%s not implemented, yet.\n", __func__);
902 }
903 
904 
905 void
906 ieee80211_notify_node_deauth(struct ieee80211_node* ni)
907 {
908 	dprintf("%s not implemented, yet.\n", __func__);
909 }
910 
911 
912 void
913 ieee80211_notify_node_auth(struct ieee80211_node* ni)
914 {
915 	dprintf("%s not implemented, yet.\n", __func__);
916 }
917 
918 
919 void
920 ieee80211_notify_country(struct ieee80211vap* vap,
921 	const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2])
922 {
923 	dprintf("%s not implemented, yet.\n", __func__);
924 }
925 
926 
927 void
928 ieee80211_notify_radio(struct ieee80211com* ic, int state)
929 {
930 	dprintf("%s not implemented, yet.\n", __func__);
931 }
932 
933 
934 void
935 ieee80211_notify_ifnet_change(struct ieee80211vap *vap)
936 {
937 	dprintf("%s not implemented, yet.\n", __func__);
938 }
939 
940 
941 void
942 ieee80211_sysctl_attach(struct ieee80211com* ic)
943 {
944 	dprintf("%s not implemented, yet.\n", __func__);
945 }
946 
947 
948 void
949 ieee80211_sysctl_detach(struct ieee80211com* ic)
950 {
951 	dprintf("%s not implemented, yet.\n", __func__);
952 }
953