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