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