xref: /dflybsd-src/sys/netproto/802_11/wlan/ieee80211_dragonfly.c (revision 05d02a3813e2bef176c69d68035311fd2efbd031)
132176cfdSRui Paulo /*-
232176cfdSRui Paulo  * Copyright (c) 2003-2009 Sam Leffler, Errno Consulting
3841ab66cSSepherosa Ziehau  * All rights reserved.
4841ab66cSSepherosa Ziehau  *
5841ab66cSSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
6841ab66cSSepherosa Ziehau  * modification, are permitted provided that the following conditions
7841ab66cSSepherosa Ziehau  * are met:
8841ab66cSSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
9841ab66cSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
10841ab66cSSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
11841ab66cSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
12841ab66cSSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
13841ab66cSSepherosa Ziehau  *
14841ab66cSSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15841ab66cSSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16841ab66cSSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17841ab66cSSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18841ab66cSSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19841ab66cSSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20841ab66cSSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21841ab66cSSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22841ab66cSSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23841ab66cSSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24841ab66cSSepherosa Ziehau  *
2532176cfdSRui Paulo  * $FreeBSD: head/sys/net80211/ieee80211_freebsd.c 202612 2010-01-19 05:00:57Z thompsa $
26841ab66cSSepherosa Ziehau  */
27841ab66cSSepherosa Ziehau 
28841ab66cSSepherosa Ziehau /*
29841ab66cSSepherosa Ziehau  * IEEE 802.11 support (DragonFlyBSD-specific code)
30841ab66cSSepherosa Ziehau  */
3132176cfdSRui Paulo #include "opt_wlan.h"
3232176cfdSRui Paulo 
33841ab66cSSepherosa Ziehau #include <sys/param.h>
34841ab66cSSepherosa Ziehau #include <sys/kernel.h>
35841ab66cSSepherosa Ziehau #include <sys/systm.h>
36841ab66cSSepherosa Ziehau #include <sys/linker.h>
37805c8e8eSzrj #include <sys/malloc.h>
38841ab66cSSepherosa Ziehau #include <sys/mbuf.h>
39841ab66cSSepherosa Ziehau #include <sys/module.h>
40841ab66cSSepherosa Ziehau #include <sys/proc.h>
41841ab66cSSepherosa Ziehau #include <sys/sysctl.h>
42841ab66cSSepherosa Ziehau 
43841ab66cSSepherosa Ziehau #include <sys/socket.h>
44841ab66cSSepherosa Ziehau 
4532176cfdSRui Paulo #include <net/bpf.h>
46841ab66cSSepherosa Ziehau #include <net/if.h>
4732176cfdSRui Paulo #include <net/if_dl.h>
4832176cfdSRui Paulo #include <net/if_clone.h>
49841ab66cSSepherosa Ziehau #include <net/if_media.h>
5032176cfdSRui Paulo #include <net/if_types.h>
51841ab66cSSepherosa Ziehau #include <net/ethernet.h>
52841ab66cSSepherosa Ziehau #include <net/route.h>
53fcaa651dSRui Paulo #include <net/ifq_var.h>
54841ab66cSSepherosa Ziehau 
55841ab66cSSepherosa Ziehau #include <netproto/802_11/ieee80211_var.h>
5632176cfdSRui Paulo #include <netproto/802_11/ieee80211_input.h>
57841ab66cSSepherosa Ziehau 
58841ab66cSSepherosa Ziehau SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters");
59841ab66cSSepherosa Ziehau 
60841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG
61841ab66cSSepherosa Ziehau int	ieee80211_debug = 0;
62841ab66cSSepherosa Ziehau SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug,
6332176cfdSRui Paulo 	    0, "debugging printfs");
64e5b94a62SSascha Wildner #endif
65e5b94a62SSascha Wildner 
66e5b94a62SSascha Wildner int	ieee80211_force_swcrypto = 0;
671b196a0cSMatthew Dillon SYSCTL_INT(_net_wlan, OID_AUTO, force_swcrypto, CTLFLAG_RW,
681b196a0cSMatthew Dillon 	    &ieee80211_force_swcrypto, 0, "force software crypto");
69841ab66cSSepherosa Ziehau 
70a7e9152eSSepherosa Ziehau static int	wlan_clone_destroy(struct ifnet *);
71bb54c3a2SAaron LI static int	wlan_clone_create(struct if_clone *, int, caddr_t, caddr_t);
72ea86af0dSRui Paulo 
73ea86af0dSRui Paulo static struct if_clone wlan_cloner =
74ea86af0dSRui Paulo 	IF_CLONE_INITIALIZER("wlan", wlan_clone_create, wlan_clone_destroy,
75ea86af0dSRui Paulo 	    0, IF_MAXUNIT);
76ea86af0dSRui Paulo 
7726c6f223SMatthew Dillon struct lwkt_serialize wlan_global_serializer = LWKT_SERIALIZE_INITIALIZER;
78ea86af0dSRui Paulo 
7932176cfdSRui Paulo static int
wlan_clone_create(struct if_clone * ifc,int unit,caddr_t params,caddr_t data __unused)80bb54c3a2SAaron LI wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params,
81bb54c3a2SAaron LI 		  caddr_t data __unused)
8232176cfdSRui Paulo {
8332176cfdSRui Paulo 	struct ieee80211_clone_params cp;
8432176cfdSRui Paulo 	struct ieee80211vap *vap;
8532176cfdSRui Paulo 	struct ieee80211com *ic;
8632176cfdSRui Paulo 	int error;
8732176cfdSRui Paulo 
8832176cfdSRui Paulo 	error = copyin(params, &cp, sizeof(cp));
8932176cfdSRui Paulo 	if (error)
9032176cfdSRui Paulo 		return error;
91b4051e25SSepherosa Ziehau 
924f655ef5SMatthew Dillon 	ic = ieee80211_find_com(cp.icp_parent);
934f655ef5SMatthew Dillon 	if (ic == NULL)
9432176cfdSRui Paulo 		return ENXIO;
9532176cfdSRui Paulo 	if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) {
964f655ef5SMatthew Dillon 		ic_printf(ic, "%s: invalid opmode %d\n", __func__,
974f655ef5SMatthew Dillon 		    cp.icp_opmode);
9832176cfdSRui Paulo 		return EINVAL;
9932176cfdSRui Paulo 	}
10032176cfdSRui Paulo 	if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) {
1014f655ef5SMatthew Dillon 		ic_printf(ic, "%s mode not supported\n",
10232176cfdSRui Paulo 		    ieee80211_opmode_name[cp.icp_opmode]);
10332176cfdSRui Paulo 		return EOPNOTSUPP;
10432176cfdSRui Paulo 	}
10532176cfdSRui Paulo 	if ((cp.icp_flags & IEEE80211_CLONE_TDMA) &&
10632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA
10732176cfdSRui Paulo 	    (ic->ic_caps & IEEE80211_C_TDMA) == 0
10832176cfdSRui Paulo #else
10932176cfdSRui Paulo 	    (1)
11032176cfdSRui Paulo #endif
11132176cfdSRui Paulo 	) {
1124f655ef5SMatthew Dillon 		ic_printf(ic, "TDMA not supported\n");
11332176cfdSRui Paulo 		return EOPNOTSUPP;
11432176cfdSRui Paulo 	}
11532176cfdSRui Paulo 	vap = ic->ic_vap_create(ic, ifc->ifc_name, unit,
11632176cfdSRui Paulo 			cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
11732176cfdSRui Paulo 			cp.icp_flags & IEEE80211_CLONE_MACADDR ?
1184f655ef5SMatthew Dillon 			    cp.icp_macaddr : ic->ic_macaddr);
119b4051e25SSepherosa Ziehau 
120b4051e25SSepherosa Ziehau 
12132176cfdSRui Paulo 	return (vap == NULL ? EIO : 0);
12232176cfdSRui Paulo }
12332176cfdSRui Paulo 
124a7e9152eSSepherosa Ziehau static int
wlan_clone_destroy(struct ifnet * ifp)12532176cfdSRui Paulo wlan_clone_destroy(struct ifnet *ifp)
12632176cfdSRui Paulo {
12732176cfdSRui Paulo 	struct ieee80211vap *vap = ifp->if_softc;
12832176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
12932176cfdSRui Paulo 
13032176cfdSRui Paulo 	ic->ic_vap_delete(vap);
131a7e9152eSSepherosa Ziehau 
132a7e9152eSSepherosa Ziehau 	return 0;
13332176cfdSRui Paulo }
13432176cfdSRui Paulo 
13551237956SMatthew Dillon const char *wlan_last_enter_func;
13651237956SMatthew Dillon const char *wlan_last_exit_func;
137085ff963SMatthew Dillon 
13826c6f223SMatthew Dillon /*
13926c6f223SMatthew Dillon  * These serializer functions are used by wlan and all drivers.
140085ff963SMatthew Dillon  * They are not recursive.  The serializer must be held on
141085ff963SMatthew Dillon  * any OACTIVE interactions.  Dragonfly automatically holds
142085ff963SMatthew Dillon  * the serializer on most ifp->if_*() calls but calls made
143085ff963SMatthew Dillon  * from wlan into ath might not.
14426c6f223SMatthew Dillon  */
14526c6f223SMatthew Dillon void
_wlan_serialize_enter(const char * funcname)14651237956SMatthew Dillon _wlan_serialize_enter(const char *funcname)
14726c6f223SMatthew Dillon {
14826c6f223SMatthew Dillon 	lwkt_serialize_enter(&wlan_global_serializer);
14951237956SMatthew Dillon 	wlan_last_enter_func = funcname;
15026c6f223SMatthew Dillon }
15126c6f223SMatthew Dillon 
15226c6f223SMatthew Dillon void
_wlan_serialize_exit(const char * funcname)15351237956SMatthew Dillon _wlan_serialize_exit(const char *funcname)
15426c6f223SMatthew Dillon {
15526c6f223SMatthew Dillon 	lwkt_serialize_exit(&wlan_global_serializer);
15651237956SMatthew Dillon 	wlan_last_exit_func = funcname;
15726c6f223SMatthew Dillon }
15826c6f223SMatthew Dillon 
15926c6f223SMatthew Dillon int
_wlan_is_serialized(void)160085ff963SMatthew Dillon _wlan_is_serialized(void)
161085ff963SMatthew Dillon {
162085ff963SMatthew Dillon 	return (IS_SERIALIZED(&wlan_global_serializer));
163085ff963SMatthew Dillon }
164085ff963SMatthew Dillon 
165085ff963SMatthew Dillon /*
166085ff963SMatthew Dillon  * Push/pop allows the wlan serializer to be entered recursively.
167085ff963SMatthew Dillon  */
168085ff963SMatthew Dillon int
_wlan_serialize_push(const char * funcname)169085ff963SMatthew Dillon _wlan_serialize_push(const char *funcname)
170085ff963SMatthew Dillon {
171085ff963SMatthew Dillon 	if (IS_SERIALIZED(&wlan_global_serializer)) {
172085ff963SMatthew Dillon 		return 0;
173085ff963SMatthew Dillon 	} else {
174085ff963SMatthew Dillon 		_wlan_serialize_enter(funcname);
175085ff963SMatthew Dillon 		return 1;
176085ff963SMatthew Dillon 	}
177085ff963SMatthew Dillon }
178085ff963SMatthew Dillon 
179085ff963SMatthew Dillon void
_wlan_serialize_pop(const char * funcname,int wst)180085ff963SMatthew Dillon _wlan_serialize_pop(const char *funcname, int wst)
181085ff963SMatthew Dillon {
182085ff963SMatthew Dillon 	if (wst) {
183085ff963SMatthew Dillon 		_wlan_serialize_exit(funcname);
184085ff963SMatthew Dillon 	}
185085ff963SMatthew Dillon }
186085ff963SMatthew Dillon 
187085ff963SMatthew Dillon #if 0
188085ff963SMatthew Dillon 
189085ff963SMatthew Dillon int
19026c6f223SMatthew Dillon wlan_serialize_sleep(void *ident, int flags, const char *wmesg, int timo)
19126c6f223SMatthew Dillon {
19226c6f223SMatthew Dillon 	return(zsleep(ident, &wlan_global_serializer, flags, wmesg, timo));
19326c6f223SMatthew Dillon }
19426c6f223SMatthew Dillon 
19526c6f223SMatthew Dillon /*
19626c6f223SMatthew Dillon  * condition-var functions which interlock the ic lock (which is now
19726c6f223SMatthew Dillon  * just wlan_global_serializer)
19826c6f223SMatthew Dillon  */
19926c6f223SMatthew Dillon void
20026c6f223SMatthew Dillon wlan_cv_init(struct cv *cv, const char *desc)
20126c6f223SMatthew Dillon {
20226c6f223SMatthew Dillon 	cv->cv_desc = desc;
20326c6f223SMatthew Dillon 	cv->cv_waiters = 0;
20426c6f223SMatthew Dillon }
20526c6f223SMatthew Dillon 
20626c6f223SMatthew Dillon int
20726c6f223SMatthew Dillon wlan_cv_timedwait(struct cv *cv, int ticks)
20826c6f223SMatthew Dillon {
20926c6f223SMatthew Dillon 	int error;
21026c6f223SMatthew Dillon 
21126c6f223SMatthew Dillon 	++cv->cv_waiters;
21226c6f223SMatthew Dillon 	error = wlan_serialize_sleep(cv, 0, cv->cv_desc, ticks);
21326c6f223SMatthew Dillon 	return (error);
21426c6f223SMatthew Dillon }
21526c6f223SMatthew Dillon 
21626c6f223SMatthew Dillon void
21726c6f223SMatthew Dillon wlan_cv_wait(struct cv *cv)
21826c6f223SMatthew Dillon {
21926c6f223SMatthew Dillon 	++cv->cv_waiters;
22026c6f223SMatthew Dillon 	wlan_serialize_sleep(cv, 0, cv->cv_desc, 0);
22126c6f223SMatthew Dillon }
22226c6f223SMatthew Dillon 
22326c6f223SMatthew Dillon void
22426c6f223SMatthew Dillon wlan_cv_signal(struct cv *cv, int broadcast)
22526c6f223SMatthew Dillon {
22626c6f223SMatthew Dillon 	if (cv->cv_waiters) {
22726c6f223SMatthew Dillon 		if (broadcast) {
22826c6f223SMatthew Dillon 			cv->cv_waiters = 0;
22926c6f223SMatthew Dillon 			wakeup(cv);
23026c6f223SMatthew Dillon 		} else {
23126c6f223SMatthew Dillon 			--cv->cv_waiters;
23226c6f223SMatthew Dillon 			wakeup_one(cv);
23326c6f223SMatthew Dillon 		}
23426c6f223SMatthew Dillon 	}
23526c6f223SMatthew Dillon }
23626c6f223SMatthew Dillon 
237085ff963SMatthew Dillon #endif
238085ff963SMatthew Dillon 
23926c6f223SMatthew Dillon /*
2404f655ef5SMatthew Dillon  * Add RX parameters to the given mbuf.
2414f655ef5SMatthew Dillon  *
2424f655ef5SMatthew Dillon  * Returns 1 if OK, 0 on error.
2434f655ef5SMatthew Dillon  */
2444f655ef5SMatthew Dillon int
ieee80211_add_rx_params(struct mbuf * m,const struct ieee80211_rx_stats * rxs)2454f655ef5SMatthew Dillon ieee80211_add_rx_params(struct mbuf *m, const struct ieee80211_rx_stats *rxs)
2464f655ef5SMatthew Dillon {
2474f655ef5SMatthew Dillon 	struct m_tag *mtag;
2484f655ef5SMatthew Dillon 	struct ieee80211_rx_params *rx;
2494f655ef5SMatthew Dillon 
2504f655ef5SMatthew Dillon 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS,
2514f655ef5SMatthew Dillon 		sizeof(struct ieee80211_rx_stats), M_NOWAIT);
2524f655ef5SMatthew Dillon 	if (mtag == NULL)
2534f655ef5SMatthew Dillon 		return (0);
2544f655ef5SMatthew Dillon 
2554f655ef5SMatthew Dillon 	rx = (struct ieee80211_rx_params *)(mtag + 1);
2564f655ef5SMatthew Dillon 	memcpy(&rx->params, rxs, sizeof(*rxs));
2574f655ef5SMatthew Dillon 	m_tag_prepend(m, mtag);
2584f655ef5SMatthew Dillon 	return (1);
2594f655ef5SMatthew Dillon }
2604f655ef5SMatthew Dillon 
2614f655ef5SMatthew Dillon int
ieee80211_get_rx_params(struct mbuf * m,struct ieee80211_rx_stats * rxs)2624f655ef5SMatthew Dillon ieee80211_get_rx_params(struct mbuf *m, struct ieee80211_rx_stats *rxs)
2634f655ef5SMatthew Dillon {
2644f655ef5SMatthew Dillon 	struct m_tag *mtag;
2654f655ef5SMatthew Dillon 	struct ieee80211_rx_params *rx;
2664f655ef5SMatthew Dillon 
2674f655ef5SMatthew Dillon 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS,
2684f655ef5SMatthew Dillon 	    NULL);
2694f655ef5SMatthew Dillon 	if (mtag == NULL)
2704f655ef5SMatthew Dillon 		return (-1);
2714f655ef5SMatthew Dillon 	rx = (struct ieee80211_rx_params *)(mtag + 1);
2724f655ef5SMatthew Dillon 	memcpy(rxs, &rx->params, sizeof(*rxs));
2734f655ef5SMatthew Dillon 	return (0);
2744f655ef5SMatthew Dillon }
2754f655ef5SMatthew Dillon 
2764f655ef5SMatthew Dillon /*
27726c6f223SMatthew Dillon  * Misc
27826c6f223SMatthew Dillon  */
279085ff963SMatthew Dillon int
ieee80211_vap_xmitpkt(struct ieee80211vap * vap,struct mbuf * m)280085ff963SMatthew Dillon ieee80211_vap_xmitpkt(struct ieee80211vap *vap, struct mbuf *m)
281085ff963SMatthew Dillon {
282085ff963SMatthew Dillon 	struct ifnet *ifp = vap->iv_ifp;
283085ff963SMatthew Dillon 	struct ifaltq_subque *ifsq = ifq_get_subq_default(&ifp->if_snd);
284085ff963SMatthew Dillon 	int error;
285085ff963SMatthew Dillon 	int wst;
286085ff963SMatthew Dillon 
287085ff963SMatthew Dillon 	/*
288085ff963SMatthew Dillon 	 * When transmitting via the VAP, we shouldn't hold
289085ff963SMatthew Dillon 	 * any IC TX lock as the VAP TX path will acquire it.
290085ff963SMatthew Dillon 	 */
291085ff963SMatthew Dillon 	IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
292085ff963SMatthew Dillon 
293085ff963SMatthew Dillon 	error = ifsq_enqueue(ifsq, m, NULL);
2946de344baSSepherosa Ziehau 	if (error)
2956de344baSSepherosa Ziehau 		IFNET_STAT_INC(ifp, oqdrops, 1);
296085ff963SMatthew Dillon 	wst = wlan_serialize_push();
297085ff963SMatthew Dillon 	ifp->if_start(ifp, ifsq);
298085ff963SMatthew Dillon 	wlan_serialize_pop(wst);
299085ff963SMatthew Dillon 
300085ff963SMatthew Dillon 	return error;
301085ff963SMatthew Dillon }
302085ff963SMatthew Dillon 
303085ff963SMatthew Dillon int
ieee80211_parent_xmitpkt(struct ieee80211com * ic,struct mbuf * m)304085ff963SMatthew Dillon ieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m)
305085ff963SMatthew Dillon {
306085ff963SMatthew Dillon 	int error;
307085ff963SMatthew Dillon 
308085ff963SMatthew Dillon 	/*
309085ff963SMatthew Dillon 	 * Assert the IC TX lock is held - this enforces the
310085ff963SMatthew Dillon 	 * processing -> queuing order is maintained
311085ff963SMatthew Dillon 	 */
312085ff963SMatthew Dillon 	IEEE80211_TX_LOCK_ASSERT(ic);
3134f655ef5SMatthew Dillon 	error = ic->ic_transmit(ic, m);
3144f655ef5SMatthew Dillon 	if (error) {
3154f655ef5SMatthew Dillon 		struct ieee80211_node *ni;
316085ff963SMatthew Dillon 
3174f655ef5SMatthew Dillon 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
318085ff963SMatthew Dillon 
3194f655ef5SMatthew Dillon 		/* XXX number of fragments */
3204f655ef5SMatthew Dillon 		IFNET_STAT_INC(ni->ni_vap->iv_ifp, oerrors, 1);
3214f655ef5SMatthew Dillon 		ieee80211_free_node(ni);
3224f655ef5SMatthew Dillon 		ieee80211_free_mbuf(m);
3234f655ef5SMatthew Dillon 	}
3244f655ef5SMatthew Dillon 	return (error);
325085ff963SMatthew Dillon }
326085ff963SMatthew Dillon 
32732176cfdSRui Paulo void
ieee80211_vap_destroy(struct ieee80211vap * vap)32832176cfdSRui Paulo ieee80211_vap_destroy(struct ieee80211vap *vap)
32932176cfdSRui Paulo {
330cfc4faf7SSepherosa Ziehau 	/*
331cfc4faf7SSepherosa Ziehau 	 * WLAN serializer must _not_ be held for if_clone_destroy(),
332cfc4faf7SSepherosa Ziehau 	 * since it could dead-lock the domsg to netisrs.
333cfc4faf7SSepherosa Ziehau 	 */
334cfc4faf7SSepherosa Ziehau 	wlan_serialize_exit();
33563000c64SImre Vadász 	/*
33663000c64SImre Vadász 	 * Make sure we con't end up in an infinite loop in ieee80211_ifdetach
33763000c64SImre Vadász 	 * when if_clone_destroy fails.
33863000c64SImre Vadász 	 */
33963000c64SImre Vadász 	KKASSERT(if_clone_destroy(vap->iv_ifp->if_xname) == 0);
340cfc4faf7SSepherosa Ziehau 	wlan_serialize_enter();
34132176cfdSRui Paulo }
34232176cfdSRui Paulo 
34347156d48SMatthew Dillon /*
34447156d48SMatthew Dillon  * NOTE: This handler is used generally to convert milliseconds
34547156d48SMatthew Dillon  *	 to ticks for various simple sysctl variables and does not
34647156d48SMatthew Dillon  *	 need to be serialized.
34747156d48SMatthew Dillon  */
34832176cfdSRui Paulo int
ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS)34932176cfdSRui Paulo ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS)
35032176cfdSRui Paulo {
35132176cfdSRui Paulo 	int msecs = ticks_to_msecs(*(int *)arg1);
35232176cfdSRui Paulo 	int error, t;
35332176cfdSRui Paulo 
35432176cfdSRui Paulo 	error = sysctl_handle_int(oidp, &msecs, 0, req);
35547156d48SMatthew Dillon 	if (error == 0 && req->newptr) {
35632176cfdSRui Paulo 		t = msecs_to_ticks(msecs);
35732176cfdSRui Paulo 		*(int *)arg1 = (t < 1) ? 1 : t;
35847156d48SMatthew Dillon 	}
35947156d48SMatthew Dillon 
36047156d48SMatthew Dillon 	return error;
36132176cfdSRui Paulo }
36232176cfdSRui Paulo 
363841ab66cSSepherosa Ziehau static int
ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS)364841ab66cSSepherosa Ziehau ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS)
365841ab66cSSepherosa Ziehau {
366841ab66cSSepherosa Ziehau 	int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT;
367841ab66cSSepherosa Ziehau 	int error;
368841ab66cSSepherosa Ziehau 
369841ab66cSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &inact, 0, req);
37047156d48SMatthew Dillon 	if (error == 0 && req->newptr)
371841ab66cSSepherosa Ziehau 		*(int *)arg1 = inact / IEEE80211_INACT_WAIT;
37247156d48SMatthew Dillon 
37347156d48SMatthew Dillon 	return error;
374841ab66cSSepherosa Ziehau }
375841ab66cSSepherosa Ziehau 
376841ab66cSSepherosa Ziehau static int
ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS)377841ab66cSSepherosa Ziehau ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS)
378841ab66cSSepherosa Ziehau {
379841ab66cSSepherosa Ziehau 	struct ieee80211com *ic = arg1;
3804f898719SImre Vadász 	const char *name = ic->ic_name;
381841ab66cSSepherosa Ziehau 
382841ab66cSSepherosa Ziehau 	return SYSCTL_OUT(req, name, strlen(name));
383841ab66cSSepherosa Ziehau }
384841ab66cSSepherosa Ziehau 
38532176cfdSRui Paulo static int
ieee80211_sysctl_radar(SYSCTL_HANDLER_ARGS)38632176cfdSRui Paulo ieee80211_sysctl_radar(SYSCTL_HANDLER_ARGS)
38732176cfdSRui Paulo {
38832176cfdSRui Paulo 	struct ieee80211com *ic = arg1;
38932176cfdSRui Paulo 	int t = 0, error;
39032176cfdSRui Paulo 
39132176cfdSRui Paulo 	error = sysctl_handle_int(oidp, &t, 0, req);
39247156d48SMatthew Dillon 	if (error == 0 && req->newptr)
39332176cfdSRui Paulo 		ieee80211_dfs_notify_radar(ic, ic->ic_curchan);
39447156d48SMatthew Dillon 
39547156d48SMatthew Dillon 	return error;
39632176cfdSRui Paulo }
39732176cfdSRui Paulo 
398841ab66cSSepherosa Ziehau void
ieee80211_sysctl_attach(struct ieee80211com * ic)399841ab66cSSepherosa Ziehau ieee80211_sysctl_attach(struct ieee80211com *ic)
400841ab66cSSepherosa Ziehau {
401841ab66cSSepherosa Ziehau }
402841ab66cSSepherosa Ziehau 
403841ab66cSSepherosa Ziehau void
ieee80211_sysctl_detach(struct ieee80211com * ic)404841ab66cSSepherosa Ziehau ieee80211_sysctl_detach(struct ieee80211com *ic)
405841ab66cSSepherosa Ziehau {
40632176cfdSRui Paulo }
40732176cfdSRui Paulo 
40832176cfdSRui Paulo void
ieee80211_sysctl_vattach(struct ieee80211vap * vap)40932176cfdSRui Paulo ieee80211_sysctl_vattach(struct ieee80211vap *vap)
41032176cfdSRui Paulo {
41132176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
41232176cfdSRui Paulo 	struct sysctl_ctx_list *ctx;
41332176cfdSRui Paulo 	struct sysctl_oid *oid;
41432176cfdSRui Paulo 	char num[14];			/* sufficient for 32 bits */
41532176cfdSRui Paulo 
416f4385629SRui Paulo 	ctx = (struct sysctl_ctx_list *) kmalloc(sizeof(struct sysctl_ctx_list),
417fcaa651dSRui Paulo 		M_DEVBUF, M_INTWAIT | M_ZERO);
41832176cfdSRui Paulo 	if (ctx == NULL) {
41932176cfdSRui Paulo 		if_printf(ifp, "%s: cannot allocate sysctl context!\n",
42032176cfdSRui Paulo 			__func__);
42132176cfdSRui Paulo 		return;
42232176cfdSRui Paulo 	}
42332176cfdSRui Paulo 	sysctl_ctx_init(ctx);
42432176cfdSRui Paulo 	ksnprintf(num, sizeof(num), "%u", ifp->if_dunit);
42532176cfdSRui Paulo 	oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan),
42632176cfdSRui Paulo 		OID_AUTO, num, CTLFLAG_RD, NULL, "");
42732176cfdSRui Paulo 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
42832176cfdSRui Paulo 		"%parent", CTLFLAG_RD, vap->iv_ic, 0,
42932176cfdSRui Paulo 		ieee80211_sysctl_parent, "A", "parent device");
43032176cfdSRui Paulo 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
43132176cfdSRui Paulo 		"driver_caps", CTLFLAG_RW, &vap->iv_caps, 0,
43232176cfdSRui Paulo 		"driver capabilities");
43332176cfdSRui Paulo #ifdef IEEE80211_DEBUG
43432176cfdSRui Paulo 	vap->iv_debug = ieee80211_debug;
43532176cfdSRui Paulo 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
43632176cfdSRui Paulo 		"debug", CTLFLAG_RW, &vap->iv_debug, 0,
43732176cfdSRui Paulo 		"control debugging printfs");
43832176cfdSRui Paulo #endif
43932176cfdSRui Paulo 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
44032176cfdSRui Paulo 		"bmiss_max", CTLFLAG_RW, &vap->iv_bmiss_max, 0,
44132176cfdSRui Paulo 		"consecutive beacon misses before scanning");
44232176cfdSRui Paulo 	/* XXX inherit from tunables */
44332176cfdSRui Paulo 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
44432176cfdSRui Paulo 		"inact_run", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_run, 0,
44532176cfdSRui Paulo 		ieee80211_sysctl_inact, "I",
44632176cfdSRui Paulo 		"station inactivity timeout (sec)");
44732176cfdSRui Paulo 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
44832176cfdSRui Paulo 		"inact_probe", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_probe, 0,
44932176cfdSRui Paulo 		ieee80211_sysctl_inact, "I",
45032176cfdSRui Paulo 		"station inactivity probe timeout (sec)");
45132176cfdSRui Paulo 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
45232176cfdSRui Paulo 		"inact_auth", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_auth, 0,
45332176cfdSRui Paulo 		ieee80211_sysctl_inact, "I",
45432176cfdSRui Paulo 		"station authentication timeout (sec)");
45532176cfdSRui Paulo 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
45632176cfdSRui Paulo 		"inact_init", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_init, 0,
45732176cfdSRui Paulo 		ieee80211_sysctl_inact, "I",
45832176cfdSRui Paulo 		"station initial state timeout (sec)");
45932176cfdSRui Paulo 	if (vap->iv_htcaps & IEEE80211_HTC_HT) {
46032176cfdSRui Paulo 		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
46132176cfdSRui Paulo 			"ampdu_mintraffic_bk", CTLFLAG_RW,
46232176cfdSRui Paulo 			&vap->iv_ampdu_mintraffic[WME_AC_BK], 0,
46332176cfdSRui Paulo 			"BK traffic tx aggr threshold (pps)");
46432176cfdSRui Paulo 		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
46532176cfdSRui Paulo 			"ampdu_mintraffic_be", CTLFLAG_RW,
46632176cfdSRui Paulo 			&vap->iv_ampdu_mintraffic[WME_AC_BE], 0,
46732176cfdSRui Paulo 			"BE traffic tx aggr threshold (pps)");
46832176cfdSRui Paulo 		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
46932176cfdSRui Paulo 			"ampdu_mintraffic_vo", CTLFLAG_RW,
47032176cfdSRui Paulo 			&vap->iv_ampdu_mintraffic[WME_AC_VO], 0,
47132176cfdSRui Paulo 			"VO traffic tx aggr threshold (pps)");
47232176cfdSRui Paulo 		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
47332176cfdSRui Paulo 			"ampdu_mintraffic_vi", CTLFLAG_RW,
47432176cfdSRui Paulo 			&vap->iv_ampdu_mintraffic[WME_AC_VI], 0,
47532176cfdSRui Paulo 			"VI traffic tx aggr threshold (pps)");
47632176cfdSRui Paulo 	}
47732176cfdSRui Paulo 	if (vap->iv_caps & IEEE80211_C_DFS) {
47832176cfdSRui Paulo 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
47932176cfdSRui Paulo 			"radar", CTLTYPE_INT | CTLFLAG_RW, vap->iv_ic, 0,
48032176cfdSRui Paulo 			ieee80211_sysctl_radar, "I", "simulate radar event");
48132176cfdSRui Paulo 	}
48232176cfdSRui Paulo 	vap->iv_sysctl = ctx;
48332176cfdSRui Paulo 	vap->iv_oid = oid;
48432176cfdSRui Paulo }
48532176cfdSRui Paulo 
48632176cfdSRui Paulo void
ieee80211_sysctl_vdetach(struct ieee80211vap * vap)48732176cfdSRui Paulo ieee80211_sysctl_vdetach(struct ieee80211vap *vap)
48832176cfdSRui Paulo {
48932176cfdSRui Paulo 
49032176cfdSRui Paulo 	if (vap->iv_sysctl != NULL) {
49132176cfdSRui Paulo 		sysctl_ctx_free(vap->iv_sysctl);
492f4385629SRui Paulo 		kfree(vap->iv_sysctl, M_DEVBUF);
49332176cfdSRui Paulo 		vap->iv_sysctl = NULL;
494841ab66cSSepherosa Ziehau 	}
495841ab66cSSepherosa Ziehau }
496841ab66cSSepherosa Ziehau 
497841ab66cSSepherosa Ziehau int
ieee80211_node_dectestref(struct ieee80211_node * ni)498841ab66cSSepherosa Ziehau ieee80211_node_dectestref(struct ieee80211_node *ni)
499841ab66cSSepherosa Ziehau {
500841ab66cSSepherosa Ziehau 	/* XXX need equivalent of atomic_dec_and_test */
501841ab66cSSepherosa Ziehau 	atomic_subtract_int(&ni->ni_refcnt, 1);
502841ab66cSSepherosa Ziehau 	return atomic_cmpset_int(&ni->ni_refcnt, 0, 1);
503841ab66cSSepherosa Ziehau }
504841ab66cSSepherosa Ziehau 
505085ff963SMatthew Dillon #if 0
506c332e0e8SSepherosa Ziehau /* XXX this breaks ALTQ's packet scheduler */
50732176cfdSRui Paulo void
508c332e0e8SSepherosa Ziehau ieee80211_flush_ifq(struct ifaltq *ifq, struct ieee80211vap *vap)
50932176cfdSRui Paulo {
51032176cfdSRui Paulo 	struct ieee80211_node *ni;
51132176cfdSRui Paulo 	struct mbuf *m, **mprev;
512c332e0e8SSepherosa Ziehau 	struct ifaltq_subque *ifsq = ifq_get_subq_default(ifq);
51332176cfdSRui Paulo 
51426c6f223SMatthew Dillon 	wlan_assert_serialized();
515c332e0e8SSepherosa Ziehau 
516c332e0e8SSepherosa Ziehau 	ALTQ_SQ_LOCK(ifsq);
517c332e0e8SSepherosa Ziehau 
5184cc8caefSSepherosa Ziehau 	/*
5194cc8caefSSepherosa Ziehau 	 * Fix normal queue
5204cc8caefSSepherosa Ziehau 	 */
5214cc8caefSSepherosa Ziehau 	mprev = &ifsq->ifsq_norm_head;
52232176cfdSRui Paulo 	while ((m = *mprev) != NULL) {
52332176cfdSRui Paulo 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
52432176cfdSRui Paulo 		if (ni != NULL && ni->ni_vap == vap) {
52532176cfdSRui Paulo 			*mprev = m->m_nextpkt;		/* remove from list */
52668dc1916SSepherosa Ziehau 			ALTQ_SQ_CNTR_DEC(ifsq, m->m_pkthdr.len);
52732176cfdSRui Paulo 
52832176cfdSRui Paulo 			m_freem(m);
52932176cfdSRui Paulo 			ieee80211_free_node(ni);	/* reclaim ref */
53032176cfdSRui Paulo 		} else
53132176cfdSRui Paulo 			mprev = &m->m_nextpkt;
53232176cfdSRui Paulo 	}
53332176cfdSRui Paulo 	/* recalculate tail ptr */
5344cc8caefSSepherosa Ziehau 	m = ifsq->ifsq_norm_head;
53532176cfdSRui Paulo 	for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt)
53632176cfdSRui Paulo 		;
5374cc8caefSSepherosa Ziehau 	ifsq->ifsq_norm_tail = m;
5384cc8caefSSepherosa Ziehau 
5394cc8caefSSepherosa Ziehau 	/*
5404cc8caefSSepherosa Ziehau 	 * Fix priority queue
5414cc8caefSSepherosa Ziehau 	 */
5424cc8caefSSepherosa Ziehau 	mprev = &ifsq->ifsq_prio_head;
5434cc8caefSSepherosa Ziehau 	while ((m = *mprev) != NULL) {
5444cc8caefSSepherosa Ziehau 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
5454cc8caefSSepherosa Ziehau 		if (ni != NULL && ni->ni_vap == vap) {
5464cc8caefSSepherosa Ziehau 			*mprev = m->m_nextpkt;		/* remove from list */
5474cc8caefSSepherosa Ziehau 			ALTQ_SQ_CNTR_DEC(ifsq, m->m_pkthdr.len);
5484cc8caefSSepherosa Ziehau 			ALTQ_SQ_PRIO_CNTR_DEC(ifsq, m->m_pkthdr.len);
5494cc8caefSSepherosa Ziehau 
5504cc8caefSSepherosa Ziehau 			m_freem(m);
5514cc8caefSSepherosa Ziehau 			ieee80211_free_node(ni);	/* reclaim ref */
5524cc8caefSSepherosa Ziehau 		} else
5534cc8caefSSepherosa Ziehau 			mprev = &m->m_nextpkt;
5544cc8caefSSepherosa Ziehau 	}
5554cc8caefSSepherosa Ziehau 	/* recalculate tail ptr */
5564cc8caefSSepherosa Ziehau 	m = ifsq->ifsq_prio_head;
5574cc8caefSSepherosa Ziehau 	for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt)
5584cc8caefSSepherosa Ziehau 		;
5594cc8caefSSepherosa Ziehau 	ifsq->ifsq_prio_tail = m;
560c332e0e8SSepherosa Ziehau 
561c332e0e8SSepherosa Ziehau 	ALTQ_SQ_UNLOCK(ifsq);
56232176cfdSRui Paulo }
563085ff963SMatthew Dillon #endif
56432176cfdSRui Paulo 
56532176cfdSRui Paulo /*
56632176cfdSRui Paulo  * As above, for mbufs allocated with m_gethdr/MGETHDR
56732176cfdSRui Paulo  * or initialized by M_COPY_PKTHDR.
56832176cfdSRui Paulo  */
56932176cfdSRui Paulo #define	MC_ALIGN(m, len)						\
57032176cfdSRui Paulo do {									\
5714f655ef5SMatthew Dillon 	(m)->m_data += rounddown2(MCLBYTES - (len), sizeof(long));	\
57232176cfdSRui Paulo } while (/* CONSTCOND */ 0)
57332176cfdSRui Paulo 
574841ab66cSSepherosa Ziehau /*
575841ab66cSSepherosa Ziehau  * Allocate and setup a management frame of the specified
576841ab66cSSepherosa Ziehau  * size.  We return the mbuf and a pointer to the start
577841ab66cSSepherosa Ziehau  * of the contiguous data area that's been reserved based
578841ab66cSSepherosa Ziehau  * on the packet length.  The data area is forced to 32-bit
579841ab66cSSepherosa Ziehau  * alignment and the buffer length to a multiple of 4 bytes.
580841ab66cSSepherosa Ziehau  * This is done mainly so beacon frames (that require this)
581841ab66cSSepherosa Ziehau  * can use this interface too.
582841ab66cSSepherosa Ziehau  */
583841ab66cSSepherosa Ziehau struct mbuf *
ieee80211_getmgtframe(uint8_t ** frm,int headroom,int pktlen)58432176cfdSRui Paulo ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen)
585841ab66cSSepherosa Ziehau {
586841ab66cSSepherosa Ziehau 	struct mbuf *m;
587841ab66cSSepherosa Ziehau 	u_int len;
588841ab66cSSepherosa Ziehau 
589841ab66cSSepherosa Ziehau 	/*
590841ab66cSSepherosa Ziehau 	 * NB: we know the mbuf routines will align the data area
591841ab66cSSepherosa Ziehau 	 *     so we don't need to do anything special.
592841ab66cSSepherosa Ziehau 	 */
59332176cfdSRui Paulo 	len = roundup2(headroom + pktlen, 4);
594841ab66cSSepherosa Ziehau 	KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
595841ab66cSSepherosa Ziehau 	if (len < MINCLSIZE) {
596b5523eacSSascha Wildner 		m = m_gethdr(M_NOWAIT, MT_DATA);
597841ab66cSSepherosa Ziehau 		/*
598841ab66cSSepherosa Ziehau 		 * Align the data in case additional headers are added.
599841ab66cSSepherosa Ziehau 		 * This should only happen when a WEP header is added
600841ab66cSSepherosa Ziehau 		 * which only happens for shared key authentication mgt
601841ab66cSSepherosa Ziehau 		 * frames which all fit in MHLEN.
602841ab66cSSepherosa Ziehau 		 */
603841ab66cSSepherosa Ziehau 		if (m != NULL)
604841ab66cSSepherosa Ziehau 			MH_ALIGN(m, len);
60532176cfdSRui Paulo 	} else {
606b5523eacSSascha Wildner 		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
60732176cfdSRui Paulo 		if (m != NULL)
60832176cfdSRui Paulo 			MC_ALIGN(m, len);
60932176cfdSRui Paulo 	}
610841ab66cSSepherosa Ziehau 	if (m != NULL) {
6114ac84526SSepherosa Ziehau 		m->m_data += headroom;
61232176cfdSRui Paulo 		*frm = m->m_data;
613841ab66cSSepherosa Ziehau 	}
614841ab66cSSepherosa Ziehau 	return m;
615841ab66cSSepherosa Ziehau }
616841ab66cSSepherosa Ziehau 
61732176cfdSRui Paulo /*
61832176cfdSRui Paulo  * Re-align the payload in the mbuf.  This is mainly used (right now)
61932176cfdSRui Paulo  * to handle IP header alignment requirements on certain architectures.
62032176cfdSRui Paulo  */
62132176cfdSRui Paulo struct mbuf *
ieee80211_realign(struct ieee80211vap * vap,struct mbuf * m,size_t align)62232176cfdSRui Paulo ieee80211_realign(struct ieee80211vap *vap, struct mbuf *m, size_t align)
62332176cfdSRui Paulo {
62432176cfdSRui Paulo 	int pktlen, space;
625ea86af0dSRui Paulo 	struct mbuf *n = NULL;
62632176cfdSRui Paulo 
62732176cfdSRui Paulo 	pktlen = m->m_pkthdr.len;
62832176cfdSRui Paulo 	space = pktlen + align;
62909804b20SMatthew Dillon 	if (space < MINCLSIZE) {
630b5523eacSSascha Wildner 		n = m_gethdr(M_NOWAIT, MT_DATA);
63109804b20SMatthew Dillon 	} else {
63209804b20SMatthew Dillon 		if (space <= MCLBYTES)
63309804b20SMatthew Dillon 			space = MCLBYTES;
63409804b20SMatthew Dillon 		else if (space <= MJUMPAGESIZE)
63509804b20SMatthew Dillon 			space = MJUMPAGESIZE;
63609804b20SMatthew Dillon 		else if (space <= MJUM9BYTES)
63709804b20SMatthew Dillon 			space = MJUM9BYTES;
63809804b20SMatthew Dillon 		else
63909804b20SMatthew Dillon 			space = MJUM16BYTES;
640b5523eacSSascha Wildner 		n = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, space);
64132176cfdSRui Paulo 	}
64232176cfdSRui Paulo 	if (__predict_true(n != NULL)) {
64332176cfdSRui Paulo 		m_move_pkthdr(n, m);
64432176cfdSRui Paulo 		n->m_data = (caddr_t)(ALIGN(n->m_data + align) - align);
645*05d02a38SAaron LI 		m_copydata(m, 0, pktlen, mtod(n, void *));
64632176cfdSRui Paulo 		n->m_len = pktlen;
64732176cfdSRui Paulo 	} else {
64832176cfdSRui Paulo 		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
64932176cfdSRui Paulo 		    mtod(m, const struct ieee80211_frame *), NULL,
65032176cfdSRui Paulo 		    "%s", "no mbuf to realign");
65132176cfdSRui Paulo 		vap->iv_stats.is_rx_badalign++;
65232176cfdSRui Paulo 	}
65332176cfdSRui Paulo 	m_freem(m);
65432176cfdSRui Paulo 	return n;
65532176cfdSRui Paulo }
65632176cfdSRui Paulo 
65732176cfdSRui Paulo int
ieee80211_add_callback(struct mbuf * m,void (* func)(struct ieee80211_node *,void *,int),void * arg)65832176cfdSRui Paulo ieee80211_add_callback(struct mbuf *m,
65932176cfdSRui Paulo 	void (*func)(struct ieee80211_node *, void *, int), void *arg)
66032176cfdSRui Paulo {
66132176cfdSRui Paulo 	struct m_tag *mtag;
66232176cfdSRui Paulo 	struct ieee80211_cb *cb;
66332176cfdSRui Paulo 
66432176cfdSRui Paulo 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK,
665fcaa651dSRui Paulo 			sizeof(struct ieee80211_cb), M_INTWAIT);
66632176cfdSRui Paulo 	if (mtag == NULL)
66732176cfdSRui Paulo 		return 0;
66832176cfdSRui Paulo 
66932176cfdSRui Paulo 	cb = (struct ieee80211_cb *)(mtag+1);
67032176cfdSRui Paulo 	cb->func = func;
67132176cfdSRui Paulo 	cb->arg = arg;
67232176cfdSRui Paulo 	m_tag_prepend(m, mtag);
67332176cfdSRui Paulo 	m->m_flags |= M_TXCB;
67432176cfdSRui Paulo 	return 1;
67532176cfdSRui Paulo }
67632176cfdSRui Paulo 
6774f898719SImre Vadász int
ieee80211_add_xmit_params(struct mbuf * m,const struct ieee80211_bpf_params * params)6784f898719SImre Vadász ieee80211_add_xmit_params(struct mbuf *m,
6794f898719SImre Vadász     const struct ieee80211_bpf_params *params)
6804f898719SImre Vadász {
6814f898719SImre Vadász 	struct m_tag *mtag;
6824f898719SImre Vadász 	struct ieee80211_tx_params *tx;
6834f898719SImre Vadász 
6844f898719SImre Vadász 	mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS,
6854f898719SImre Vadász 	    sizeof(struct ieee80211_tx_params), M_NOWAIT);
6864f898719SImre Vadász 	if (mtag == NULL)
6874f898719SImre Vadász 		return (0);
6884f898719SImre Vadász 
6894f898719SImre Vadász 	tx = (struct ieee80211_tx_params *)(mtag+1);
6904f898719SImre Vadász 	memcpy(&tx->params, params, sizeof(struct ieee80211_bpf_params));
6914f898719SImre Vadász 	m_tag_prepend(m, mtag);
6924f898719SImre Vadász 	return (1);
6934f898719SImre Vadász }
6944f898719SImre Vadász 
6954f898719SImre Vadász int
ieee80211_get_xmit_params(struct mbuf * m,struct ieee80211_bpf_params * params)6964f898719SImre Vadász ieee80211_get_xmit_params(struct mbuf *m,
6974f898719SImre Vadász     struct ieee80211_bpf_params *params)
6984f898719SImre Vadász {
6994f898719SImre Vadász 	struct m_tag *mtag;
7004f898719SImre Vadász 	struct ieee80211_tx_params *tx;
7014f898719SImre Vadász 
7024f898719SImre Vadász 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS,
7034f898719SImre Vadász 	    NULL);
7044f898719SImre Vadász 	if (mtag == NULL)
7054f898719SImre Vadász 		return (-1);
7064f898719SImre Vadász 	tx = (struct ieee80211_tx_params *)(mtag + 1);
7074f898719SImre Vadász 	memcpy(params, &tx->params, sizeof(struct ieee80211_bpf_params));
7084f898719SImre Vadász 	return (0);
7094f898719SImre Vadász }
7104f898719SImre Vadász 
71132176cfdSRui Paulo void
ieee80211_process_callback(struct ieee80211_node * ni,struct mbuf * m,int status)71232176cfdSRui Paulo ieee80211_process_callback(struct ieee80211_node *ni,
71332176cfdSRui Paulo 	struct mbuf *m, int status)
71432176cfdSRui Paulo {
71532176cfdSRui Paulo 	struct m_tag *mtag;
71632176cfdSRui Paulo 
71732176cfdSRui Paulo 	mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL);
71832176cfdSRui Paulo 	if (mtag != NULL) {
71932176cfdSRui Paulo 		struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1);
72032176cfdSRui Paulo 		cb->func(ni, cb->arg, status);
72132176cfdSRui Paulo 	}
72232176cfdSRui Paulo }
72332176cfdSRui Paulo 
724841ab66cSSepherosa Ziehau #include <sys/libkern.h>
725841ab66cSSepherosa Ziehau 
726841ab66cSSepherosa Ziehau void
get_random_bytes(void * p,size_t n)727841ab66cSSepherosa Ziehau get_random_bytes(void *p, size_t n)
728841ab66cSSepherosa Ziehau {
729841ab66cSSepherosa Ziehau 	uint8_t *dp = p;
730841ab66cSSepherosa Ziehau 
731841ab66cSSepherosa Ziehau 	while (n > 0) {
7320ced1954SMatthew Dillon 		uint32_t v = karc4random();
733841ab66cSSepherosa Ziehau 		size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n;
734841ab66cSSepherosa Ziehau 		bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n);
735841ab66cSSepherosa Ziehau 		dp += sizeof(uint32_t), n -= nb;
736841ab66cSSepherosa Ziehau 	}
737841ab66cSSepherosa Ziehau }
738841ab66cSSepherosa Ziehau 
73932176cfdSRui Paulo /*
74032176cfdSRui Paulo  * Helper function for events that pass just a single mac address.
74132176cfdSRui Paulo  */
74232176cfdSRui Paulo static void
notify_macaddr(struct ifnet * ifp,int op,const uint8_t mac[IEEE80211_ADDR_LEN])74332176cfdSRui Paulo notify_macaddr(struct ifnet *ifp, int op, const uint8_t mac[IEEE80211_ADDR_LEN])
744841ab66cSSepherosa Ziehau {
745841ab66cSSepherosa Ziehau 	struct ieee80211_join_event iev;
746841ab66cSSepherosa Ziehau 
747841ab66cSSepherosa Ziehau 	memset(&iev, 0, sizeof(iev));
74832176cfdSRui Paulo 	IEEE80211_ADDR_COPY(iev.iev_addr, mac);
74932176cfdSRui Paulo 	rt_ieee80211msg(ifp, op, &iev, sizeof(iev));
750841ab66cSSepherosa Ziehau }
751841ab66cSSepherosa Ziehau 
752841ab66cSSepherosa Ziehau void
ieee80211_notify_node_join(struct ieee80211_node * ni,int newassoc)75332176cfdSRui Paulo ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc)
754841ab66cSSepherosa Ziehau {
75532176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
75632176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
757841ab66cSSepherosa Ziehau 
75832176cfdSRui Paulo 	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode join",
75932176cfdSRui Paulo 	    (ni == vap->iv_bss) ? "bss " : "");
76032176cfdSRui Paulo 
76132176cfdSRui Paulo 	if (ni == vap->iv_bss) {
7628bdbc095SRoy Marples 		ifp->if_link_state = LINK_STATE_UP;
76332176cfdSRui Paulo 		notify_macaddr(ifp, newassoc ?
76432176cfdSRui Paulo 		    RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, ni->ni_bssid);
765f4385629SRui Paulo 		if_link_state_change(ifp);
76632176cfdSRui Paulo 	} else {
76732176cfdSRui Paulo 		notify_macaddr(ifp, newassoc ?
76832176cfdSRui Paulo 		    RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, ni->ni_macaddr);
76932176cfdSRui Paulo 	}
77032176cfdSRui Paulo }
77132176cfdSRui Paulo 
77232176cfdSRui Paulo void
ieee80211_notify_node_leave(struct ieee80211_node * ni)77332176cfdSRui Paulo ieee80211_notify_node_leave(struct ieee80211_node *ni)
77432176cfdSRui Paulo {
77532176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
77632176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
77732176cfdSRui Paulo 
77832176cfdSRui Paulo 	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode leave",
77932176cfdSRui Paulo 	    (ni == vap->iv_bss) ? "bss " : "");
78032176cfdSRui Paulo 
78132176cfdSRui Paulo 	if (ni == vap->iv_bss) {
7828bdbc095SRoy Marples 		ifp->if_link_state = LINK_STATE_DOWN;
783841ab66cSSepherosa Ziehau 		rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0);
784f4385629SRui Paulo 		if_link_state_change(ifp);
785841ab66cSSepherosa Ziehau 	} else {
786841ab66cSSepherosa Ziehau 		/* fire off wireless event station leaving */
78732176cfdSRui Paulo 		notify_macaddr(ifp, RTM_IEEE80211_LEAVE, ni->ni_macaddr);
788841ab66cSSepherosa Ziehau 	}
789841ab66cSSepherosa Ziehau }
790841ab66cSSepherosa Ziehau 
791841ab66cSSepherosa Ziehau void
ieee80211_notify_scan_done(struct ieee80211vap * vap)79232176cfdSRui Paulo ieee80211_notify_scan_done(struct ieee80211vap *vap)
793841ab66cSSepherosa Ziehau {
79432176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
795841ab66cSSepherosa Ziehau 
79632176cfdSRui Paulo 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n", "notify scan done");
797841ab66cSSepherosa Ziehau 
798841ab66cSSepherosa Ziehau 	/* dispatch wireless event indicating scan completed */
799841ab66cSSepherosa Ziehau 	rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0);
800841ab66cSSepherosa Ziehau }
801841ab66cSSepherosa Ziehau 
802841ab66cSSepherosa Ziehau void
ieee80211_notify_replay_failure(struct ieee80211vap * vap,const struct ieee80211_frame * wh,const struct ieee80211_key * k,u_int64_t rsc,int tid)80332176cfdSRui Paulo ieee80211_notify_replay_failure(struct ieee80211vap *vap,
804841ab66cSSepherosa Ziehau 	const struct ieee80211_frame *wh, const struct ieee80211_key *k,
80532176cfdSRui Paulo 	u_int64_t rsc, int tid)
806841ab66cSSepherosa Ziehau {
80732176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
808841ab66cSSepherosa Ziehau 
80932176cfdSRui Paulo 	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
81032176cfdSRui Paulo 	    "%s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>",
81132176cfdSRui Paulo 	    k->wk_cipher->ic_name, (intmax_t) rsc,
81232176cfdSRui Paulo 	    (intmax_t) k->wk_keyrsc[tid],
813841ab66cSSepherosa Ziehau 	    k->wk_keyix, k->wk_rxkeyix);
814841ab66cSSepherosa Ziehau 
815841ab66cSSepherosa Ziehau 	if (ifp != NULL) {		/* NB: for cipher test modules */
816841ab66cSSepherosa Ziehau 		struct ieee80211_replay_event iev;
817841ab66cSSepherosa Ziehau 
818841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
819841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
820841ab66cSSepherosa Ziehau 		iev.iev_cipher = k->wk_cipher->ic_cipher;
821841ab66cSSepherosa Ziehau 		if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE)
822841ab66cSSepherosa Ziehau 			iev.iev_keyix = k->wk_rxkeyix;
823841ab66cSSepherosa Ziehau 		else
824841ab66cSSepherosa Ziehau 			iev.iev_keyix = k->wk_keyix;
82532176cfdSRui Paulo 		iev.iev_keyrsc = k->wk_keyrsc[tid];
826841ab66cSSepherosa Ziehau 		iev.iev_rsc = rsc;
827841ab66cSSepherosa Ziehau 		rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev));
828841ab66cSSepherosa Ziehau 	}
829841ab66cSSepherosa Ziehau }
830841ab66cSSepherosa Ziehau 
831841ab66cSSepherosa Ziehau void
ieee80211_notify_michael_failure(struct ieee80211vap * vap,const struct ieee80211_frame * wh,u_int keyix)83232176cfdSRui Paulo ieee80211_notify_michael_failure(struct ieee80211vap *vap,
833841ab66cSSepherosa Ziehau 	const struct ieee80211_frame *wh, u_int keyix)
834841ab66cSSepherosa Ziehau {
83532176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
836841ab66cSSepherosa Ziehau 
83732176cfdSRui Paulo 	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
83832176cfdSRui Paulo 	    "michael MIC verification failed <keyix %u>", keyix);
83932176cfdSRui Paulo 	vap->iv_stats.is_rx_tkipmic++;
840841ab66cSSepherosa Ziehau 
841841ab66cSSepherosa Ziehau 	if (ifp != NULL) {		/* NB: for cipher test modules */
842841ab66cSSepherosa Ziehau 		struct ieee80211_michael_event iev;
843841ab66cSSepherosa Ziehau 
844841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
845841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
846841ab66cSSepherosa Ziehau 		iev.iev_cipher = IEEE80211_CIPHER_TKIP;
847841ab66cSSepherosa Ziehau 		iev.iev_keyix = keyix;
848841ab66cSSepherosa Ziehau 		rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev));
849841ab66cSSepherosa Ziehau 	}
850841ab66cSSepherosa Ziehau }
851841ab66cSSepherosa Ziehau 
852841ab66cSSepherosa Ziehau void
ieee80211_notify_wds_discover(struct ieee80211_node * ni)85332176cfdSRui Paulo ieee80211_notify_wds_discover(struct ieee80211_node *ni)
85432176cfdSRui Paulo {
85532176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
85632176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
85732176cfdSRui Paulo 
85832176cfdSRui Paulo 	notify_macaddr(ifp, RTM_IEEE80211_WDS, ni->ni_macaddr);
85932176cfdSRui Paulo }
86032176cfdSRui Paulo 
86132176cfdSRui Paulo void
ieee80211_notify_csa(struct ieee80211com * ic,const struct ieee80211_channel * c,int mode,int count)86232176cfdSRui Paulo ieee80211_notify_csa(struct ieee80211com *ic,
86332176cfdSRui Paulo 	const struct ieee80211_channel *c, int mode, int count)
86432176cfdSRui Paulo {
8654f898719SImre Vadász 	struct ieee80211vap *vap;
8664f898719SImre Vadász 	struct ifnet *ifp;
86732176cfdSRui Paulo 	struct ieee80211_csa_event iev;
86832176cfdSRui Paulo 
86932176cfdSRui Paulo 	memset(&iev, 0, sizeof(iev));
87032176cfdSRui Paulo 	iev.iev_flags = c->ic_flags;
87132176cfdSRui Paulo 	iev.iev_freq = c->ic_freq;
87232176cfdSRui Paulo 	iev.iev_ieee = c->ic_ieee;
87332176cfdSRui Paulo 	iev.iev_mode = mode;
87432176cfdSRui Paulo 	iev.iev_count = count;
8754f898719SImre Vadász 	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
8764f898719SImre Vadász 		ifp = vap->iv_ifp;
87732176cfdSRui Paulo 		rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev));
87832176cfdSRui Paulo 	}
8794f898719SImre Vadász }
88032176cfdSRui Paulo 
88132176cfdSRui Paulo void
ieee80211_notify_radar(struct ieee80211com * ic,const struct ieee80211_channel * c)88232176cfdSRui Paulo ieee80211_notify_radar(struct ieee80211com *ic,
88332176cfdSRui Paulo 	const struct ieee80211_channel *c)
88432176cfdSRui Paulo {
88532176cfdSRui Paulo 	struct ieee80211_radar_event iev;
8864f898719SImre Vadász 	struct ieee80211vap *vap;
8874f898719SImre Vadász 	struct ifnet *ifp;
88832176cfdSRui Paulo 
88932176cfdSRui Paulo 	memset(&iev, 0, sizeof(iev));
89032176cfdSRui Paulo 	iev.iev_flags = c->ic_flags;
89132176cfdSRui Paulo 	iev.iev_freq = c->ic_freq;
89232176cfdSRui Paulo 	iev.iev_ieee = c->ic_ieee;
8934f898719SImre Vadász 	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
8944f898719SImre Vadász 		ifp = vap->iv_ifp;
89532176cfdSRui Paulo 		rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev));
89632176cfdSRui Paulo 	}
8974f898719SImre Vadász }
89832176cfdSRui Paulo 
89932176cfdSRui Paulo void
ieee80211_notify_cac(struct ieee80211com * ic,const struct ieee80211_channel * c,enum ieee80211_notify_cac_event type)90032176cfdSRui Paulo ieee80211_notify_cac(struct ieee80211com *ic,
90132176cfdSRui Paulo 	const struct ieee80211_channel *c, enum ieee80211_notify_cac_event type)
90232176cfdSRui Paulo {
90332176cfdSRui Paulo 	struct ieee80211_cac_event iev;
9044f898719SImre Vadász 	struct ieee80211vap *vap;
9054f898719SImre Vadász 	struct ifnet *ifp;
90632176cfdSRui Paulo 
90732176cfdSRui Paulo 	memset(&iev, 0, sizeof(iev));
90832176cfdSRui Paulo 	iev.iev_flags = c->ic_flags;
90932176cfdSRui Paulo 	iev.iev_freq = c->ic_freq;
91032176cfdSRui Paulo 	iev.iev_ieee = c->ic_ieee;
91132176cfdSRui Paulo 	iev.iev_type = type;
9124f898719SImre Vadász 	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
9134f898719SImre Vadász 		ifp = vap->iv_ifp;
91432176cfdSRui Paulo 		rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev));
91532176cfdSRui Paulo 	}
9164f898719SImre Vadász }
91732176cfdSRui Paulo 
91832176cfdSRui Paulo void
ieee80211_notify_node_deauth(struct ieee80211_node * ni)91932176cfdSRui Paulo ieee80211_notify_node_deauth(struct ieee80211_node *ni)
92032176cfdSRui Paulo {
92132176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
92232176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
92332176cfdSRui Paulo 
92432176cfdSRui Paulo 	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node deauth");
92532176cfdSRui Paulo 
92632176cfdSRui Paulo 	notify_macaddr(ifp, RTM_IEEE80211_DEAUTH, ni->ni_macaddr);
92732176cfdSRui Paulo }
92832176cfdSRui Paulo 
92932176cfdSRui Paulo void
ieee80211_notify_node_auth(struct ieee80211_node * ni)93032176cfdSRui Paulo ieee80211_notify_node_auth(struct ieee80211_node *ni)
93132176cfdSRui Paulo {
93232176cfdSRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
93332176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
93432176cfdSRui Paulo 
93532176cfdSRui Paulo 	IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node auth");
93632176cfdSRui Paulo 
93732176cfdSRui Paulo 	notify_macaddr(ifp, RTM_IEEE80211_AUTH, ni->ni_macaddr);
93832176cfdSRui Paulo }
93932176cfdSRui Paulo 
94032176cfdSRui Paulo void
ieee80211_notify_country(struct ieee80211vap * vap,const uint8_t bssid[IEEE80211_ADDR_LEN],const uint8_t cc[2])94132176cfdSRui Paulo ieee80211_notify_country(struct ieee80211vap *vap,
94232176cfdSRui Paulo 	const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2])
94332176cfdSRui Paulo {
94432176cfdSRui Paulo 	struct ifnet *ifp = vap->iv_ifp;
94532176cfdSRui Paulo 	struct ieee80211_country_event iev;
94632176cfdSRui Paulo 
94732176cfdSRui Paulo 	memset(&iev, 0, sizeof(iev));
94832176cfdSRui Paulo 	IEEE80211_ADDR_COPY(iev.iev_addr, bssid);
94932176cfdSRui Paulo 	iev.iev_cc[0] = cc[0];
95032176cfdSRui Paulo 	iev.iev_cc[1] = cc[1];
95132176cfdSRui Paulo 	rt_ieee80211msg(ifp, RTM_IEEE80211_COUNTRY, &iev, sizeof(iev));
95232176cfdSRui Paulo }
95332176cfdSRui Paulo 
95432176cfdSRui Paulo void
ieee80211_notify_radio(struct ieee80211com * ic,int state)95532176cfdSRui Paulo ieee80211_notify_radio(struct ieee80211com *ic, int state)
95632176cfdSRui Paulo {
95732176cfdSRui Paulo 	struct ieee80211_radio_event iev;
9584f898719SImre Vadász 	struct ieee80211vap *vap;
9594f898719SImre Vadász 	struct ifnet *ifp;
96032176cfdSRui Paulo 
96132176cfdSRui Paulo 	memset(&iev, 0, sizeof(iev));
96232176cfdSRui Paulo 	iev.iev_state = state;
9634f898719SImre Vadász 	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
9644f898719SImre Vadász 		ifp = vap->iv_ifp;
96532176cfdSRui Paulo 		rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev));
96632176cfdSRui Paulo 	}
9674f898719SImre Vadász }
96832176cfdSRui Paulo 
969a13825b3SRui Paulo /* IEEE Std 802.11a-1999, page 9, table 79 */
970a13825b3SRui Paulo #define IEEE80211_OFDM_SYM_TIME                 4
971a13825b3SRui Paulo #define IEEE80211_OFDM_PREAMBLE_TIME            16
972a13825b3SRui Paulo #define IEEE80211_OFDM_SIGNAL_TIME              4
973a13825b3SRui Paulo /* IEEE Std 802.11g-2003, page 44 */
974a13825b3SRui Paulo #define IEEE80211_OFDM_SIGNAL_EXT_TIME          6
975a13825b3SRui Paulo 
976a13825b3SRui Paulo /* IEEE Std 802.11a-1999, page 7, figure 107 */
977a13825b3SRui Paulo #define IEEE80211_OFDM_PLCP_SERVICE_NBITS       16
978a13825b3SRui Paulo #define IEEE80211_OFDM_TAIL_NBITS               6
979a13825b3SRui Paulo 
980a13825b3SRui Paulo #define IEEE80211_OFDM_NBITS(frmlen) \
981a13825b3SRui Paulo 	(IEEE80211_OFDM_PLCP_SERVICE_NBITS + \
982a13825b3SRui Paulo 	((frmlen) * NBBY) + \
983a13825b3SRui Paulo 	IEEE80211_OFDM_TAIL_NBITS)
984a13825b3SRui Paulo 
985a13825b3SRui Paulo #define IEEE80211_OFDM_NBITS_PER_SYM(kbps) \
986a13825b3SRui Paulo 	(((kbps) * IEEE80211_OFDM_SYM_TIME) / 1000)
987a13825b3SRui Paulo 
988a13825b3SRui Paulo #define IEEE80211_OFDM_NSYMS(kbps, frmlen) \
989a13825b3SRui Paulo 	howmany(IEEE80211_OFDM_NBITS((frmlen)), \
990a13825b3SRui Paulo 	IEEE80211_OFDM_NBITS_PER_SYM((kbps)))
991a13825b3SRui Paulo 
992a13825b3SRui Paulo #define IEEE80211_OFDM_TXTIME(kbps, frmlen) \
993a13825b3SRui Paulo 	(IEEE80211_OFDM_PREAMBLE_TIME + \
994a13825b3SRui Paulo 	IEEE80211_OFDM_SIGNAL_TIME + \
995a13825b3SRui Paulo 	(IEEE80211_OFDM_NSYMS((kbps), (frmlen)) * IEEE80211_OFDM_SYM_TIME))
996a13825b3SRui Paulo 
997a13825b3SRui Paulo /* IEEE Std 802.11b-1999, page 28, subclause 18.3.4 */
998a13825b3SRui Paulo #define IEEE80211_CCK_PREAMBLE_LEN      144
999a13825b3SRui Paulo #define IEEE80211_CCK_PLCP_HDR_TIME     48
1000a13825b3SRui Paulo #define IEEE80211_CCK_SHPREAMBLE_LEN    72
1001a13825b3SRui Paulo #define IEEE80211_CCK_SHPLCP_HDR_TIME   24
1002a13825b3SRui Paulo 
1003a13825b3SRui Paulo #define IEEE80211_CCK_NBITS(frmlen)     ((frmlen) * NBBY)
1004a13825b3SRui Paulo #define IEEE80211_CCK_TXTIME(kbps, frmlen) \
1005a13825b3SRui Paulo 	(((IEEE80211_CCK_NBITS((frmlen)) * 1000) + (kbps) - 1) / (kbps))
1006a13825b3SRui Paulo 
1007a13825b3SRui Paulo uint16_t
ieee80211_txtime(struct ieee80211_node * ni,u_int len,uint8_t rs_rate,uint32_t flags)1008a13825b3SRui Paulo ieee80211_txtime(struct ieee80211_node *ni, u_int len, uint8_t rs_rate,
1009a13825b3SRui Paulo 		uint32_t flags)
1010a13825b3SRui Paulo {
1011a13825b3SRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
1012a13825b3SRui Paulo 	uint16_t txtime;
1013a13825b3SRui Paulo 	int rate;
1014a13825b3SRui Paulo 
1015a13825b3SRui Paulo 	rs_rate &= IEEE80211_RATE_VAL;
1016a13825b3SRui Paulo 	rate = rs_rate * 500;   /* ieee80211 rate -> kbps */
1017a13825b3SRui Paulo 
1018a13825b3SRui Paulo 	if (vap->iv_ic->ic_phytype == IEEE80211_T_OFDM) {
1019a13825b3SRui Paulo 		/*
1020a13825b3SRui Paulo 		 * IEEE Std 802.11a-1999, page 37, equation (29)
1021a13825b3SRui Paulo 		 * IEEE Std 802.11g-2003, page 44, equation (42)
1022a13825b3SRui Paulo 		 */
1023a13825b3SRui Paulo 		txtime = IEEE80211_OFDM_TXTIME(rate, len);
1024a13825b3SRui Paulo 		if (vap->iv_ic->ic_curmode == IEEE80211_MODE_11G)
1025a13825b3SRui Paulo 			txtime += IEEE80211_OFDM_SIGNAL_EXT_TIME;
1026a13825b3SRui Paulo 	} else {
1027a13825b3SRui Paulo 		/*
1028a13825b3SRui Paulo 		 * IEEE Std 802.11b-1999, page 28, subclause 18.3.4
1029a13825b3SRui Paulo 		 * IEEE Std 802.11g-2003, page 45, equation (43)
1030a13825b3SRui Paulo 		 */
1031a13825b3SRui Paulo 		if (vap->iv_ic->ic_phytype == IEEE80211_T_OFDM_QUARTER+1)
1032a13825b3SRui Paulo 			++len;
1033a13825b3SRui Paulo 		txtime = IEEE80211_CCK_TXTIME(rate, len);
1034a13825b3SRui Paulo 
1035a13825b3SRui Paulo 		/*
1036a13825b3SRui Paulo 		 * Short preamble is not applicable for DS 1Mbits/s
1037a13825b3SRui Paulo 		 */
1038a13825b3SRui Paulo 		if (rs_rate != 2 && (flags & IEEE80211_F_SHPREAMBLE)) {
1039a13825b3SRui Paulo 			txtime += IEEE80211_CCK_SHPREAMBLE_LEN +
1040a13825b3SRui Paulo 				IEEE80211_CCK_SHPLCP_HDR_TIME;
1041a13825b3SRui Paulo 		} else {
1042a13825b3SRui Paulo 			txtime += IEEE80211_CCK_PREAMBLE_LEN +
1043a13825b3SRui Paulo 			IEEE80211_CCK_PLCP_HDR_TIME;
1044a13825b3SRui Paulo 		}
1045a13825b3SRui Paulo 	}
1046a13825b3SRui Paulo 	return txtime;
1047a13825b3SRui Paulo }
1048a13825b3SRui Paulo 
104932176cfdSRui Paulo void
ieee80211_load_module(const char * modname)1050841ab66cSSepherosa Ziehau ieee80211_load_module(const char *modname)
1051841ab66cSSepherosa Ziehau {
1052841ab66cSSepherosa Ziehau 
105332176cfdSRui Paulo #ifdef notyet
105432176cfdSRui Paulo 	(void)kern_kldload(curthread, modname, NULL);
1055841ab66cSSepherosa Ziehau #else
1056a6ec04bcSSascha Wildner 	kprintf("%s: load the %s module by hand for now.\n", __func__, modname);
1057841ab66cSSepherosa Ziehau #endif
1058841ab66cSSepherosa Ziehau }
1059841ab66cSSepherosa Ziehau 
106032176cfdSRui Paulo static eventhandler_tag wlan_bpfevent;
106132176cfdSRui Paulo static eventhandler_tag wlan_ifllevent;
106232176cfdSRui Paulo 
106332176cfdSRui Paulo static void
bpf_track_event(void * arg,struct ifnet * ifp,int dlt,int attach)106451237956SMatthew Dillon bpf_track_event(void *arg, struct ifnet *ifp, int dlt, int attach)
1065841ab66cSSepherosa Ziehau {
106632176cfdSRui Paulo 	/* NB: identify vap's by if_start */
106747156d48SMatthew Dillon 
1068085ff963SMatthew Dillon 	if (dlt == DLT_IEEE802_11_RADIO &&
1069085ff963SMatthew Dillon 	    ifp->if_start == ieee80211_vap_start) {
107032176cfdSRui Paulo 		struct ieee80211vap *vap = ifp->if_softc;
1071841ab66cSSepherosa Ziehau 		/*
107232176cfdSRui Paulo 		 * Track bpf radiotap listener state.  We mark the vap
107332176cfdSRui Paulo 		 * to indicate if any listener is present and the com
107432176cfdSRui Paulo 		 * to indicate if any listener exists on any associated
107532176cfdSRui Paulo 		 * vap.  This flag is used by drivers to prepare radiotap
107632176cfdSRui Paulo 		 * state only when needed.
1077841ab66cSSepherosa Ziehau 		 */
107832176cfdSRui Paulo 		if (attach) {
107932176cfdSRui Paulo 			ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF);
108032176cfdSRui Paulo 			if (vap->iv_opmode == IEEE80211_M_MONITOR)
108132176cfdSRui Paulo 				atomic_add_int(&vap->iv_ic->ic_montaps, 1);
108219f10c78SRui Paulo 		} else if (!vap->iv_rawbpf) {
108332176cfdSRui Paulo 			ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF);
108432176cfdSRui Paulo 			if (vap->iv_opmode == IEEE80211_M_MONITOR)
108532176cfdSRui Paulo 				atomic_subtract_int(&vap->iv_ic->ic_montaps, 1);
1086841ab66cSSepherosa Ziehau 		}
1087841ab66cSSepherosa Ziehau 	}
1088085ff963SMatthew Dillon }
1089085ff963SMatthew Dillon 
1090085ff963SMatthew Dillon const char *
ether_sprintf(const u_char * buf)1091085ff963SMatthew Dillon ether_sprintf(const u_char *buf)
1092085ff963SMatthew Dillon {
1093085ff963SMatthew Dillon 	static char ethstr[MAXCPU][ETHER_ADDRSTRLEN + 1];
1094085ff963SMatthew Dillon 	char *ptr = ethstr[mycpu->gd_cpuid];
1095085ff963SMatthew Dillon 
1096085ff963SMatthew Dillon 	kether_ntoa(buf, ptr);
1097085ff963SMatthew Dillon 	return (ptr);
1098841ab66cSSepherosa Ziehau }
1099841ab66cSSepherosa Ziehau 
11004f655ef5SMatthew Dillon /*
11014f655ef5SMatthew Dillon  * Change MAC address on the vap (if was not started).
11024f655ef5SMatthew Dillon  */
110332176cfdSRui Paulo static void
wlan_iflladdr_event(void * arg __unused,struct ifnet * ifp)110451237956SMatthew Dillon wlan_iflladdr_event(void *arg __unused, struct ifnet *ifp)
1105841ab66cSSepherosa Ziehau {
11064f655ef5SMatthew Dillon 	/* NB: identify vap's by if_init */
11074f655ef5SMatthew Dillon 	if (ifp->if_init == ieee80211_init &&
11084f655ef5SMatthew Dillon 	    (ifp->if_flags & IFF_UP) == 0) {
11094f655ef5SMatthew Dillon 		struct ieee80211vap *vap = ifp->if_softc;
111032176cfdSRui Paulo 		IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp));
1111841ab66cSSepherosa Ziehau 	}
111231358101SSascha Wildner }
111331358101SSascha Wildner 
1114841ab66cSSepherosa Ziehau /*
1115841ab66cSSepherosa Ziehau  * Module glue.
1116841ab66cSSepherosa Ziehau  *
1117841ab66cSSepherosa Ziehau  * NB: the module name is "wlan" for compatibility with NetBSD.
1118841ab66cSSepherosa Ziehau  */
1119841ab66cSSepherosa Ziehau static int
wlan_modevent(module_t mod,int type,void * unused)1120841ab66cSSepherosa Ziehau wlan_modevent(module_t mod, int type, void *unused)
1121841ab66cSSepherosa Ziehau {
112247156d48SMatthew Dillon 	int error;
112347156d48SMatthew Dillon 
1124841ab66cSSepherosa Ziehau 	switch (type) {
1125841ab66cSSepherosa Ziehau 	case MOD_LOAD:
1126841ab66cSSepherosa Ziehau 		if (bootverbose)
1127a6ec04bcSSascha Wildner 			kprintf("wlan: <802.11 Link Layer>\n");
112832176cfdSRui Paulo 		wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track,
112951237956SMatthew Dillon 					bpf_track_event, 0,
113047156d48SMatthew Dillon 					EVENTHANDLER_PRI_ANY);
113132176cfdSRui Paulo 		wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,
113251237956SMatthew Dillon 					wlan_iflladdr_event, NULL,
113347156d48SMatthew Dillon 					EVENTHANDLER_PRI_ANY);
113432176cfdSRui Paulo 		if_clone_attach(&wlan_cloner);
113547156d48SMatthew Dillon 		error = 0;
113647156d48SMatthew Dillon 		break;
1137841ab66cSSepherosa Ziehau 	case MOD_UNLOAD:
113832176cfdSRui Paulo 		if_clone_detach(&wlan_cloner);
113932176cfdSRui Paulo 		EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
114032176cfdSRui Paulo 		EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent);
114147156d48SMatthew Dillon 		error = 0;
114247156d48SMatthew Dillon 		break;
114347156d48SMatthew Dillon 	default:
114447156d48SMatthew Dillon 		error = EINVAL;
114547156d48SMatthew Dillon 		break;
1146841ab66cSSepherosa Ziehau 	}
114747156d48SMatthew Dillon 	return error;
1148841ab66cSSepherosa Ziehau }
1149841ab66cSSepherosa Ziehau 
1150841ab66cSSepherosa Ziehau static moduledata_t wlan_mod = {
1151841ab66cSSepherosa Ziehau 	"wlan",
1152841ab66cSSepherosa Ziehau 	wlan_modevent,
1153841ab66cSSepherosa Ziehau 	0
1154841ab66cSSepherosa Ziehau };
1155841ab66cSSepherosa Ziehau DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
1156841ab66cSSepherosa Ziehau MODULE_VERSION(wlan, 1);
115732176cfdSRui Paulo MODULE_DEPEND(wlan, ether, 1, 1, 1);
1158