xref: /haiku/src/libs/compat/freebsd_wlan/net80211/ieee80211_haiku.cpp (revision 86021fd407331bcef948c739a4870ca453f5c6cd)
1 /*
2  * Copyright 2009, Colin Günther, coling@gmx.de. All rights reserved.
3  * Copyright 2018-2024, 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
ieee80211_priv_check_vap_getkey(u_long cmd __unused,struct ieee80211vap * vap __unused,struct ifnet * ifp __unused)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
ieee80211_priv_check_vap_manage(u_long cmd __unused,struct ieee80211vap * vap __unused,struct ifnet * ifp __unused)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
ieee80211_priv_check_vap_setmac(u_long cmd __unused,struct ieee80211vap * vap __unused,struct ifnet * ifp __unused)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
ieee80211_priv_check_create_vap(u_long cmd __unused,struct ieee80211vap * vap __unused,struct ifnet * ifp __unused)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*
get_ifnet(device_t device,int & i)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
init_wlan_stack(void)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
uninit_wlan_stack(void)140 uninit_wlan_stack(void)
141 {
142 	if (sNotificationModule != NULL)
143 		put_module(NET_NOTIFICATIONS_MODULE_NAME);
144 }
145 
146 
147 status_t
start_wlan(device_t device)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
stop_wlan(device_t device)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
wlan_open(void * cookie)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
wlan_close(void * cookie)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
wlan_control(void * cookie,uint32 op,void * arg,size_t length)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 
261 	return B_BAD_VALUE;
262 }
263 
264 
265 void
net80211_get_random_bytes(void * p,size_t n)266 net80211_get_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 
279 struct mbuf *
ieee80211_getmgtframe(uint8_t ** frm,int headroom,int pktlen)280 ieee80211_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 
314 int
ieee80211_com_vincref(struct ieee80211vap * vap)315 ieee80211_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 
336 void
ieee80211_com_vdecref(struct ieee80211vap * vap)337 ieee80211_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 
350 void
ieee80211_com_vdetach(struct ieee80211vap * vap)351 ieee80211_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  */
370 int
ieee80211_node_dectestref(struct ieee80211_node * ni)371 ieee80211_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 
378 void
ieee80211_drain_ifq(struct ifqueue * ifq)379 ieee80211_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 
399 void
ieee80211_flush_ifq(struct ifqueue * ifq,struct ieee80211vap * vap)400 ieee80211_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  */
434 extern "C" struct mbuf *
ieee80211_realign(struct ieee80211vap * vap,struct mbuf * m,size_t align)435 ieee80211_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 
469 int
ieee80211_add_callback(struct mbuf * m,void (* func)(struct ieee80211_node *,void *,int),void * arg)470 ieee80211_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 
490 void
ieee80211_process_callback(struct ieee80211_node * ni,struct mbuf * m,int status)491 ieee80211_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 
504 int
ieee80211_add_xmit_params(struct mbuf * m,const struct ieee80211_bpf_params * params)505 ieee80211_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 
523 int
ieee80211_get_xmit_params(struct mbuf * m,struct ieee80211_bpf_params * params)524 ieee80211_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  */
545 int
ieee80211_add_rx_params(struct mbuf * m,const struct ieee80211_rx_stats * rxs)546 ieee80211_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 
563 int
ieee80211_get_rx_params(struct mbuf * m,struct ieee80211_rx_stats * rxs)564 ieee80211_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 
579 const struct ieee80211_rx_stats *
ieee80211_get_rx_params_ptr(struct mbuf * m)580 ieee80211_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  */
597 int
ieee80211_add_toa_params(struct mbuf * m,const struct ieee80211_toa_params * p)598 ieee80211_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 
615 int
ieee80211_get_toa_params(struct mbuf * m,struct ieee80211_toa_params * p)616 ieee80211_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  */
635 int
ieee80211_parent_xmitpkt(struct ieee80211com * ic,struct mbuf * m)636 ieee80211_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  */
666 const char *
ieee80211_get_vap_ifname(struct ieee80211vap * vap)667 ieee80211_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
675 static void
ieee80211_debugnet_init(struct ifnet * ifp,int * nrxr,int * ncl,int * clsize)676 ieee80211_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 
689 static void
ieee80211_debugnet_event(struct ifnet * ifp,enum debugnet_ev ev)690 ieee80211_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 
703 static int
ieee80211_debugnet_transmit(struct ifnet * ifp,struct mbuf * m)704 ieee80211_debugnet_transmit(struct ifnet *ifp, struct mbuf *m)
705 {
706 	return (ieee80211_vap_transmit(ifp, m));
707 }
708 
709 static int
ieee80211_debugnet_poll(struct ifnet * ifp,int count)710 ieee80211_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  */
725 int
ieee80211_vap_xmitpkt(struct ieee80211vap * vap,struct mbuf * m)726 ieee80211_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 
741 void
ieee80211_sysctl_vattach(struct ieee80211vap * vap)742 ieee80211_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 
756 void
ieee80211_sysctl_vdetach(struct ieee80211vap * vap)757 ieee80211_sysctl_vdetach(struct ieee80211vap* vap)
758 {
759 	dprintf("%s not implemented, yet.\n", __func__);
760 }
761 
762 
763 void
ieee80211_vap_destroy(struct ieee80211vap * vap)764 ieee80211_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 
773 void
ieee80211_load_module(const char * modname)774 ieee80211_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 
782 void
ieee80211_notify_node_join(struct ieee80211_node * ni,int newassoc)783 ieee80211_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 
806 void
ieee80211_notify_node_leave(struct ieee80211_node * ni)807 ieee80211_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 
830 void
ieee80211_notify_scan_done(struct ieee80211vap * vap)831 ieee80211_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 
850 void
ieee80211_notify_replay_failure(struct ieee80211vap * vap,const struct ieee80211_frame * wh,const struct ieee80211_key * k,u_int64_t rsc,int tid)851 ieee80211_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 
859 void
ieee80211_notify_michael_failure(struct ieee80211vap * vap,const struct ieee80211_frame * wh,u_int keyix)860 ieee80211_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 
867 void
ieee80211_notify_wds_discover(struct ieee80211_node * ni)868 ieee80211_notify_wds_discover(struct ieee80211_node* ni)
869 {
870 	dprintf("%s not implemented, yet.\n", __func__);
871 }
872 
873 
874 void
ieee80211_notify_csa(struct ieee80211com * ic,const struct ieee80211_channel * c,int mode,int count)875 ieee80211_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 
882 void
ieee80211_notify_radar(struct ieee80211com * ic,const struct ieee80211_channel * c)883 ieee80211_notify_radar(struct ieee80211com* ic,
884 	const struct ieee80211_channel* c)
885 {
886 	dprintf("%s not implemented, yet.\n", __func__);
887 }
888 
889 
890 void
ieee80211_notify_cac(struct ieee80211com * ic,const struct ieee80211_channel * c,enum ieee80211_notify_cac_event type)891 ieee80211_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 
898 void
ieee80211_notify_node_deauth(struct ieee80211_node * ni)899 ieee80211_notify_node_deauth(struct ieee80211_node* ni)
900 {
901 	dprintf("%s not implemented, yet.\n", __func__);
902 }
903 
904 
905 void
ieee80211_notify_node_auth(struct ieee80211_node * ni)906 ieee80211_notify_node_auth(struct ieee80211_node* ni)
907 {
908 	dprintf("%s not implemented, yet.\n", __func__);
909 }
910 
911 
912 void
ieee80211_notify_country(struct ieee80211vap * vap,const uint8_t bssid[IEEE80211_ADDR_LEN],const uint8_t cc[2])913 ieee80211_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 
920 void
ieee80211_notify_radio(struct ieee80211com * ic,int state)921 ieee80211_notify_radio(struct ieee80211com* ic, int state)
922 {
923 	dprintf("%s not implemented, yet.\n", __func__);
924 }
925 
926 
927 extern "C" void
ieee80211_notify_ifnet_change(struct ieee80211vap * vap,int if_flags_mask)928 ieee80211_notify_ifnet_change(struct ieee80211vap *vap, int if_flags_mask)
929 {
930 	dprintf("%s not implemented, yet.\n", __func__);
931 }
932 
933 
934 void
ieee80211_sysctl_attach(struct ieee80211com * ic)935 ieee80211_sysctl_attach(struct ieee80211com* ic)
936 {
937 	dprintf("%s not implemented, yet.\n", __func__);
938 }
939 
940 
941 void
ieee80211_sysctl_detach(struct ieee80211com * ic)942 ieee80211_sysctl_detach(struct ieee80211com* ic)
943 {
944 	dprintf("%s not implemented, yet.\n", __func__);
945 }
946