xref: /netbsd-src/sys/net80211/ieee80211_netbsd.c (revision 5b040abec8060d5e6b092a276e20c68b6257712a)
1*5b040abeSmaxv /* $NetBSD: ieee80211_netbsd.c,v 1.34 2018/12/22 14:28:56 maxv Exp $ */
2f43b1441Smaxv 
3f43b1441Smaxv /*
43cdc4fcdSdyoung  * Copyright (c) 2003-2005 Sam Leffler, Errno Consulting
53cdc4fcdSdyoung  * All rights reserved.
63cdc4fcdSdyoung  *
73cdc4fcdSdyoung  * Redistribution and use in source and binary forms, with or without
83cdc4fcdSdyoung  * modification, are permitted provided that the following conditions
93cdc4fcdSdyoung  * are met:
103cdc4fcdSdyoung  * 1. Redistributions of source code must retain the above copyright
113cdc4fcdSdyoung  *    notice, this list of conditions and the following disclaimer.
123cdc4fcdSdyoung  * 2. Redistributions in binary form must reproduce the above copyright
133cdc4fcdSdyoung  *    notice, this list of conditions and the following disclaimer in the
143cdc4fcdSdyoung  *    documentation and/or other materials provided with the distribution.
153cdc4fcdSdyoung  * 3. The name of the author may not be used to endorse or promote products
163cdc4fcdSdyoung  *    derived from this software without specific prior written permission.
173cdc4fcdSdyoung  *
183cdc4fcdSdyoung  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
193cdc4fcdSdyoung  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
203cdc4fcdSdyoung  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
213cdc4fcdSdyoung  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
223cdc4fcdSdyoung  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
233cdc4fcdSdyoung  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
243cdc4fcdSdyoung  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
253cdc4fcdSdyoung  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
263cdc4fcdSdyoung  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
273cdc4fcdSdyoung  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
283cdc4fcdSdyoung  */
293cdc4fcdSdyoung 
303cdc4fcdSdyoung #include <sys/cdefs.h>
3190634029Sdyoung #ifdef __FreeBSD__
3287515e34Sskrll __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_freebsd.c,v 1.8 2005/08/08 18:46:35 sam Exp $");
3390634029Sdyoung #else
34*5b040abeSmaxv __KERNEL_RCSID(0, "$NetBSD: ieee80211_netbsd.c,v 1.34 2018/12/22 14:28:56 maxv Exp $");
3590634029Sdyoung #endif
363cdc4fcdSdyoung 
373cdc4fcdSdyoung /*
389c99eab1Sthorpej  * IEEE 802.11 support (NetBSD-specific code)
393cdc4fcdSdyoung  */
403cdc4fcdSdyoung #include <sys/param.h>
413cdc4fcdSdyoung #include <sys/kernel.h>
423cdc4fcdSdyoung #include <sys/systm.h>
433cdc4fcdSdyoung #include <sys/mbuf.h>
443cdc4fcdSdyoung #include <sys/proc.h>
453cdc4fcdSdyoung #include <sys/sysctl.h>
469c99eab1Sthorpej #include <sys/once.h>
473cdc4fcdSdyoung 
483cdc4fcdSdyoung #include <sys/socket.h>
493cdc4fcdSdyoung 
503afd44cfStls #include <sys/cprng.h>
513afd44cfStls 
523cdc4fcdSdyoung #include <net/if.h>
533cdc4fcdSdyoung #include <net/if_media.h>
5490634029Sdyoung #include <net/if_ether.h>
553cdc4fcdSdyoung #include <net/route.h>
563cdc4fcdSdyoung 
5790634029Sdyoung #include <net80211/ieee80211_netbsd.h>
583cdc4fcdSdyoung #include <net80211/ieee80211_var.h>
5990634029Sdyoung #include <net80211/ieee80211_sysctl.h>
603cdc4fcdSdyoung 
6190634029Sdyoung #define	LOGICALLY_EQUAL(x, y)	(!(x) == !(y))
6290634029Sdyoung 
6390634029Sdyoung static void ieee80211_sysctl_fill_node(struct ieee80211_node *,
642bfe9aceSdyoung     struct ieee80211_node_sysctl *, int, const struct ieee80211_channel *,
652bfe9aceSdyoung     uint32_t);
6690634029Sdyoung static struct ieee80211_node *ieee80211_node_walknext(
6790634029Sdyoung     struct ieee80211_node_walk *);
6890634029Sdyoung static struct ieee80211_node *ieee80211_node_walkfirst(
6990634029Sdyoung     struct ieee80211_node_walk *, u_short);
7090634029Sdyoung static int ieee80211_sysctl_node(SYSCTLFN_ARGS);
713cdc4fcdSdyoung 
723eab37f7Spooka static void ieee80211_sysctl_setup(void);
733eab37f7Spooka 
743cdc4fcdSdyoung #ifdef IEEE80211_DEBUG
753cdc4fcdSdyoung int	ieee80211_debug = 0;
763cdc4fcdSdyoung #endif
773cdc4fcdSdyoung 
7887515e34Sskrll typedef void (*ieee80211_setup_func)(void);
7987515e34Sskrll 
8087515e34Sskrll __link_set_decl(ieee80211_funcs, ieee80211_setup_func);
8187515e34Sskrll 
82dae53410Syamt static int
ieee80211_init0(void)839c99eab1Sthorpej ieee80211_init0(void)
8487515e34Sskrll {
8587515e34Sskrll 	ieee80211_setup_func * const *ieee80211_setup, f;
8687515e34Sskrll 
873eab37f7Spooka 	ieee80211_sysctl_setup();
883eab37f7Spooka 
895523aadfSmatt 	if (max_linkhdr < ALIGN(sizeof(struct ieee80211_qosframe_addr4))) {
905523aadfSmatt 		max_linkhdr = ALIGN(sizeof(struct ieee80211_qosframe_addr4));
915523aadfSmatt 	}
925523aadfSmatt 
9387515e34Sskrll 	__link_set_foreach(ieee80211_setup, ieee80211_funcs) {
9487515e34Sskrll 		f = (void*)*ieee80211_setup;
9587515e34Sskrll 		(*f)();
9687515e34Sskrll 	}
97dae53410Syamt 
98dae53410Syamt 	return 0;
9987515e34Sskrll }
10087515e34Sskrll 
1019c99eab1Sthorpej void
ieee80211_init(void)1029c99eab1Sthorpej ieee80211_init(void)
1039c99eab1Sthorpej {
1049c99eab1Sthorpej 	static ONCE_DECL(ieee80211_init_once);
1059c99eab1Sthorpej 
1069c99eab1Sthorpej 	RUN_ONCE(&ieee80211_init_once, ieee80211_init0);
1079c99eab1Sthorpej }
1089c99eab1Sthorpej 
1093cdc4fcdSdyoung static int
ieee80211_sysctl_inact(SYSCTLFN_ARGS)11090634029Sdyoung ieee80211_sysctl_inact(SYSCTLFN_ARGS)
1113cdc4fcdSdyoung {
11290634029Sdyoung 	int error, t;
11390634029Sdyoung 	struct sysctlnode node;
1143cdc4fcdSdyoung 
11590634029Sdyoung 	node = *rnode;
116f43b1441Smaxv 
117f43b1441Smaxv 	/*
118f43b1441Smaxv 	 * sysctl_lookup copies the product from t.  Then, it
11990634029Sdyoung 	 * copies the new value onto t.
12090634029Sdyoung 	 */
12190634029Sdyoung 	t = *(int*)rnode->sysctl_data * IEEE80211_INACT_WAIT;
12290634029Sdyoung 	node.sysctl_data = &t;
12390634029Sdyoung 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
12490634029Sdyoung 	if (error || newp == NULL)
125f43b1441Smaxv 		return error;
12690634029Sdyoung 
127f43b1441Smaxv 	/*
128f43b1441Smaxv 	 * The new value was in seconds.  Convert to inactivity-wait
12990634029Sdyoung 	 * intervals.  There are IEEE80211_INACT_WAIT seconds per
13090634029Sdyoung 	 * interval.
13190634029Sdyoung 	 */
13290634029Sdyoung 	*(int*)rnode->sysctl_data = t / IEEE80211_INACT_WAIT;
13390634029Sdyoung 
134f43b1441Smaxv 	return 0;
1353cdc4fcdSdyoung }
1363cdc4fcdSdyoung 
1373cdc4fcdSdyoung static int
ieee80211_sysctl_parent(SYSCTLFN_ARGS)13890634029Sdyoung ieee80211_sysctl_parent(SYSCTLFN_ARGS)
1393cdc4fcdSdyoung {
14090634029Sdyoung 	struct ieee80211com *ic;
14190634029Sdyoung 	char pname[IFNAMSIZ];
14290634029Sdyoung 	struct sysctlnode node;
1433cdc4fcdSdyoung 
14490634029Sdyoung 	node = *rnode;
14590634029Sdyoung 	ic = node.sysctl_data;
146fe2925feSmaya 	strlcpy(pname, ic->ic_ifp->if_xname, IFNAMSIZ);
14790634029Sdyoung 	node.sysctl_data = pname;
14890634029Sdyoung 	return sysctl_lookup(SYSCTLFN_CALL(&node));
14990634029Sdyoung }
15090634029Sdyoung 
15190634029Sdyoung /*
15290634029Sdyoung  * Create or get top of sysctl tree net.link.ieee80211.
15390634029Sdyoung  */
15490634029Sdyoung static const struct sysctlnode *
ieee80211_sysctl_treetop(struct sysctllog ** log)15590634029Sdyoung ieee80211_sysctl_treetop(struct sysctllog **log)
15690634029Sdyoung {
15790634029Sdyoung 	int rc;
15890634029Sdyoung 	const struct sysctlnode *rnode;
15990634029Sdyoung 
16090634029Sdyoung 	if ((rc = sysctl_createv(log, 0, NULL, &rnode,
16190634029Sdyoung 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "link",
16290634029Sdyoung 	    "link-layer statistics and controls",
1634f6fb3bfSpooka 	    NULL, 0, NULL, 0, CTL_NET, PF_LINK, CTL_EOL)) != 0)
16490634029Sdyoung 		goto err;
16590634029Sdyoung 
16690634029Sdyoung 	if ((rc = sysctl_createv(log, 0, &rnode, &rnode,
16790634029Sdyoung 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "ieee80211",
16890634029Sdyoung 	    "IEEE 802.11 WLAN statistics and controls",
16990634029Sdyoung 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
17090634029Sdyoung 		goto err;
17190634029Sdyoung 
17290634029Sdyoung 	return rnode;
17390634029Sdyoung err:
17490634029Sdyoung 	printf("%s: sysctl_createv failed, rc = %d\n", __func__, rc);
17590634029Sdyoung 	return NULL;
1763cdc4fcdSdyoung }
1773cdc4fcdSdyoung 
1783cdc4fcdSdyoung void
ieee80211_sysctl_attach(struct ieee80211com * ic)1793cdc4fcdSdyoung ieee80211_sysctl_attach(struct ieee80211com *ic)
1803cdc4fcdSdyoung {
18190634029Sdyoung 	int rc;
18290634029Sdyoung 	const struct sysctlnode *cnode, *rnode;
18390634029Sdyoung 	char num[sizeof("vap") + 14];		/* sufficient for 32 bits */
1843cdc4fcdSdyoung 
18590634029Sdyoung 	if ((rnode = ieee80211_sysctl_treetop(NULL)) == NULL)
1863cdc4fcdSdyoung 		return;
18790634029Sdyoung 
18890634029Sdyoung 	snprintf(num, sizeof(num), "vap%u", ic->ic_vap);
18990634029Sdyoung 
19090634029Sdyoung 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &rnode,
19190634029Sdyoung 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, num, SYSCTL_DESCR("virtual AP"),
19290634029Sdyoung 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
19390634029Sdyoung 		goto err;
19490634029Sdyoung 
19590634029Sdyoung 	/* control debugging printfs */
19690634029Sdyoung 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
19790634029Sdyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READONLY, CTLTYPE_STRING,
19890634029Sdyoung 	    "parent", SYSCTL_DESCR("parent device"),
199e21a34c2Sdsl 	    ieee80211_sysctl_parent, 0, (void *)ic, IFNAMSIZ, CTL_CREATE,
20090634029Sdyoung 	    CTL_EOL)) != 0)
20190634029Sdyoung 		goto err;
20290634029Sdyoung 
2033cdc4fcdSdyoung #ifdef IEEE80211_DEBUG
20490634029Sdyoung 	/* control debugging printfs */
20590634029Sdyoung 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
20690634029Sdyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
20790634029Sdyoung 	    "debug", SYSCTL_DESCR("control debugging printfs"),
20890634029Sdyoung 	    NULL, ieee80211_debug, &ic->ic_debug, 0,
20990634029Sdyoung 	    CTL_CREATE, CTL_EOL)) != 0)
21090634029Sdyoung 		goto err;
2113cdc4fcdSdyoung #endif
2123cdc4fcdSdyoung 	/* XXX inherit from tunables */
21390634029Sdyoung 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
21490634029Sdyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
21590634029Sdyoung 	    "inact_run", SYSCTL_DESCR("station inactivity timeout (sec)"),
21690634029Sdyoung 	    ieee80211_sysctl_inact, 0, &ic->ic_inact_run, 0,
21790634029Sdyoung 	    CTL_CREATE, CTL_EOL)) != 0)
21890634029Sdyoung 		goto err;
21990634029Sdyoung 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
22090634029Sdyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
22190634029Sdyoung 	    "inact_probe",
22290634029Sdyoung 	    SYSCTL_DESCR("station inactivity probe timeout (sec)"),
22390634029Sdyoung 	    ieee80211_sysctl_inact, 0, &ic->ic_inact_probe, 0,
22490634029Sdyoung 	    CTL_CREATE, CTL_EOL)) != 0)
22590634029Sdyoung 		goto err;
22690634029Sdyoung 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
22790634029Sdyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
22890634029Sdyoung 	    "inact_auth",
22990634029Sdyoung 	    SYSCTL_DESCR("station authentication timeout (sec)"),
23090634029Sdyoung 	    ieee80211_sysctl_inact, 0, &ic->ic_inact_auth, 0,
23190634029Sdyoung 	    CTL_CREATE, CTL_EOL)) != 0)
23290634029Sdyoung 		goto err;
23390634029Sdyoung 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
23490634029Sdyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
23590634029Sdyoung 	    "inact_init",
23690634029Sdyoung 	    SYSCTL_DESCR("station initial state timeout (sec)"),
23790634029Sdyoung 	    ieee80211_sysctl_inact, 0, &ic->ic_inact_init, 0,
23890634029Sdyoung 	    CTL_CREATE, CTL_EOL)) != 0)
23990634029Sdyoung 		goto err;
24090634029Sdyoung 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
24190634029Sdyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
24290634029Sdyoung 	    "driver_caps", SYSCTL_DESCR("driver capabilities"),
24390634029Sdyoung 	    NULL, 0, &ic->ic_caps, 0, CTL_CREATE, CTL_EOL)) != 0)
24490634029Sdyoung 		goto err;
24525e9e914Sdyoung 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
24625e9e914Sdyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
24725e9e914Sdyoung 	    "bmiss_max", SYSCTL_DESCR("consecutive beacon misses before scanning"),
24825e9e914Sdyoung 	    NULL, 0, &ic->ic_bmiss_max, 0, CTL_CREATE, CTL_EOL)) != 0)
24925e9e914Sdyoung 		goto err;
25090634029Sdyoung 
25190634029Sdyoung 	return;
25290634029Sdyoung err:
25390634029Sdyoung 	printf("%s: sysctl_createv failed, rc = %d\n", __func__, rc);
2543cdc4fcdSdyoung }
2553cdc4fcdSdyoung 
2563cdc4fcdSdyoung void
ieee80211_sysctl_detach(struct ieee80211com * ic)2573cdc4fcdSdyoung ieee80211_sysctl_detach(struct ieee80211com *ic)
2583cdc4fcdSdyoung {
25990634029Sdyoung 	sysctl_teardown(&ic->ic_sysctllog);
2603cdc4fcdSdyoung }
26190634029Sdyoung 
26290634029Sdyoung /*
26390634029Sdyoung  * Pointers for testing:
26490634029Sdyoung  *
26590634029Sdyoung  *	If there are no interfaces, or else no 802.11 interfaces,
26690634029Sdyoung  *	ieee80211_node_walkfirst must return NULL.
26790634029Sdyoung  *
26890634029Sdyoung  *	If there is any single 802.11 interface, ieee80211_node_walkfirst
26990634029Sdyoung  *	must not return NULL.
27090634029Sdyoung  */
27190634029Sdyoung static struct ieee80211_node *
ieee80211_node_walkfirst(struct ieee80211_node_walk * nw,u_short if_index)2729a7ebfddSdyoung ieee80211_node_walkfirst(struct ieee80211_node_walk *nw, u_short if_index)
27390634029Sdyoung {
274f43b1441Smaxv 	memset(nw, 0, sizeof(*nw));
27590634029Sdyoung 
27690634029Sdyoung 	nw->nw_ifindex = if_index;
27790634029Sdyoung 
2789a7ebfddSdyoung 	LIST_FOREACH(nw->nw_ic, &ieee80211com_head, ic_list) {
2799a7ebfddSdyoung 		if (if_index != 0 && nw->nw_ic->ic_ifp->if_index != if_index)
28090634029Sdyoung 			continue;
2819a7ebfddSdyoung 		if (!TAILQ_EMPTY(&nw->nw_ic->ic_sta.nt_node))
2829a7ebfddSdyoung 			nw->nw_nt = &nw->nw_ic->ic_sta;
2839a7ebfddSdyoung 		else if (!TAILQ_EMPTY(&nw->nw_ic->ic_scan.nt_node))
2849a7ebfddSdyoung 			nw->nw_nt = &nw->nw_ic->ic_scan;
2859a7ebfddSdyoung 		else if (nw->nw_ic->ic_bss == NULL)
2869a7ebfddSdyoung 			continue;
28790634029Sdyoung 		break;
28890634029Sdyoung 	}
28990634029Sdyoung 
2909a7ebfddSdyoung 	if (nw->nw_ic == NULL)
2919a7ebfddSdyoung 		return NULL;
2929a7ebfddSdyoung 
2939a7ebfddSdyoung 	if (nw->nw_nt == NULL)
2949a7ebfddSdyoung 		nw->nw_ni = nw->nw_ic->ic_bss;
2959a7ebfddSdyoung 	else
2969a7ebfddSdyoung 		nw->nw_ni = TAILQ_FIRST(&nw->nw_nt->nt_node);
29790634029Sdyoung 
29890634029Sdyoung 	return nw->nw_ni;
29990634029Sdyoung }
30090634029Sdyoung 
30190634029Sdyoung static struct ieee80211_node *
ieee80211_node_walknext(struct ieee80211_node_walk * nw)30290634029Sdyoung ieee80211_node_walknext(struct ieee80211_node_walk *nw)
30390634029Sdyoung {
3049a7ebfddSdyoung 	if (nw->nw_nt != NULL)
30590634029Sdyoung 		nw->nw_ni = TAILQ_NEXT(nw->nw_ni, ni_list);
3069a7ebfddSdyoung 	else
3079a7ebfddSdyoung 		nw->nw_ni = NULL;
30890634029Sdyoung 
3099a7ebfddSdyoung 	while (nw->nw_ni == NULL) {
3109a7ebfddSdyoung 		if (nw->nw_nt == &nw->nw_ic->ic_sta) {
3119a7ebfddSdyoung 			nw->nw_nt = &nw->nw_ic->ic_scan;
3129a7ebfddSdyoung 			nw->nw_ni = TAILQ_FIRST(&nw->nw_nt->nt_node);
3139a7ebfddSdyoung 			continue;
3149a7ebfddSdyoung 		} else if (nw->nw_nt == &nw->nw_ic->ic_scan) {
3159a7ebfddSdyoung 			nw->nw_nt = NULL;
3169a7ebfddSdyoung 			nw->nw_ni = nw->nw_ic->ic_bss;
3179a7ebfddSdyoung 			continue;
3189a7ebfddSdyoung 		}
3199a7ebfddSdyoung 		KASSERT(nw->nw_nt == NULL);
32090634029Sdyoung 		if (nw->nw_ifindex != 0)
32190634029Sdyoung 			return NULL;
32290634029Sdyoung 
32390634029Sdyoung 		nw->nw_ic = LIST_NEXT(nw->nw_ic, ic_list);
32490634029Sdyoung 		if (nw->nw_ic == NULL)
32590634029Sdyoung 			return NULL;
32690634029Sdyoung 
3279a7ebfddSdyoung 		nw->nw_nt = &nw->nw_ic->ic_sta;
3289a7ebfddSdyoung 		nw->nw_ni = TAILQ_FIRST(&nw->nw_nt->nt_node);
32990634029Sdyoung 	}
33090634029Sdyoung 
33190634029Sdyoung 	return nw->nw_ni;
33290634029Sdyoung }
33390634029Sdyoung 
33490634029Sdyoung static void
ieee80211_sysctl_fill_node(struct ieee80211_node * ni,struct ieee80211_node_sysctl * ns,int ifindex,const struct ieee80211_channel * chan0,uint32_t flags)33590634029Sdyoung ieee80211_sysctl_fill_node(struct ieee80211_node *ni,
33690634029Sdyoung     struct ieee80211_node_sysctl *ns, int ifindex,
3372bfe9aceSdyoung     const struct ieee80211_channel *chan0, uint32_t flags)
33890634029Sdyoung {
339f43b1441Smaxv 	memset(ns, 0, sizeof(*ns));
340f43b1441Smaxv 
34190634029Sdyoung 	ns->ns_ifindex = ifindex;
34290634029Sdyoung 	ns->ns_capinfo = ni->ni_capinfo;
3432bfe9aceSdyoung 	ns->ns_flags = flags;
344f43b1441Smaxv 	memcpy(ns->ns_macaddr, ni->ni_macaddr, sizeof(ns->ns_macaddr));
345f43b1441Smaxv 	memcpy(ns->ns_bssid, ni->ni_bssid, sizeof(ns->ns_bssid));
34690634029Sdyoung 	if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
34790634029Sdyoung 		ns->ns_freq = ni->ni_chan->ic_freq;
34890634029Sdyoung 		ns->ns_chanflags = ni->ni_chan->ic_flags;
34990634029Sdyoung 		ns->ns_chanidx = ni->ni_chan - chan0;
35090634029Sdyoung 	} else {
35190634029Sdyoung 		ns->ns_freq = ns->ns_chanflags = 0;
35290634029Sdyoung 		ns->ns_chanidx = 0;
35390634029Sdyoung 	}
35490634029Sdyoung 	ns->ns_rssi = ni->ni_rssi;
35590634029Sdyoung 	ns->ns_esslen = ni->ni_esslen;
356f43b1441Smaxv 	memcpy(ns->ns_essid, ni->ni_essid, sizeof(ns->ns_essid));
35790634029Sdyoung 	ns->ns_erp = ni->ni_erp;
35890634029Sdyoung 	ns->ns_associd = ni->ni_associd;
35990634029Sdyoung 	ns->ns_inact = ni->ni_inact * IEEE80211_INACT_WAIT;
36090634029Sdyoung 	ns->ns_rstamp = ni->ni_rstamp;
36190634029Sdyoung 	ns->ns_rates = ni->ni_rates;
36290634029Sdyoung 	ns->ns_txrate = ni->ni_txrate;
36390634029Sdyoung 	ns->ns_intval = ni->ni_intval;
364f43b1441Smaxv 	memcpy(ns->ns_tstamp, &ni->ni_tstamp, sizeof(ns->ns_tstamp));
36590634029Sdyoung 	ns->ns_txseq = ni->ni_txseqs[0];
36690634029Sdyoung 	ns->ns_rxseq = ni->ni_rxseqs[0];
36790634029Sdyoung 	ns->ns_fhdwell = ni->ni_fhdwell;
36890634029Sdyoung 	ns->ns_fhindex = ni->ni_fhindex;
36990634029Sdyoung 	ns->ns_fails = ni->ni_fails;
37090634029Sdyoung }
37190634029Sdyoung 
37290634029Sdyoung /* Between two examinations of the sysctl tree, I expect each
37390634029Sdyoung  * interface to add no more than 5 nodes.
37490634029Sdyoung  */
37590634029Sdyoung #define IEEE80211_SYSCTL_NODE_GROWTH	5
37690634029Sdyoung 
37790634029Sdyoung static int
ieee80211_sysctl_node(SYSCTLFN_ARGS)37890634029Sdyoung ieee80211_sysctl_node(SYSCTLFN_ARGS)
37990634029Sdyoung {
38090634029Sdyoung 	struct ieee80211_node_walk nw;
38190634029Sdyoung 	struct ieee80211_node *ni;
38290634029Sdyoung 	struct ieee80211_node_sysctl ns;
38390634029Sdyoung 	char *dp;
38490634029Sdyoung 	u_int cur_ifindex, ifcount, ifindex, last_ifindex, op, arg, hdr_type;
3852bfe9aceSdyoung 	uint32_t flags;
38690634029Sdyoung 	size_t len, needed, eltsize, out_size;
387c511c459Sdyoung 	int error, s, saw_bss = 0, nelt;
38890634029Sdyoung 
38990634029Sdyoung 	if (namelen == 1 && name[0] == CTL_QUERY)
39090634029Sdyoung 		return (sysctl_query(SYSCTLFN_CALL(rnode)));
39190634029Sdyoung 
39290634029Sdyoung 	if (namelen != IEEE80211_SYSCTL_NODENAMELEN)
39390634029Sdyoung 		return (EINVAL);
39490634029Sdyoung 
39590634029Sdyoung 	/* ifindex.op.arg.header-type.eltsize.nelt */
39690634029Sdyoung 	dp = oldp;
39790634029Sdyoung 	len = (oldp != NULL) ? *oldlenp : 0;
39890634029Sdyoung 	ifindex = name[IEEE80211_SYSCTL_NODENAME_IF];
39990634029Sdyoung 	op = name[IEEE80211_SYSCTL_NODENAME_OP];
40090634029Sdyoung 	arg = name[IEEE80211_SYSCTL_NODENAME_ARG];
40190634029Sdyoung 	hdr_type = name[IEEE80211_SYSCTL_NODENAME_TYPE];
40290634029Sdyoung 	eltsize = name[IEEE80211_SYSCTL_NODENAME_ELTSIZE];
40390634029Sdyoung 	nelt = name[IEEE80211_SYSCTL_NODENAME_ELTCOUNT];
40490634029Sdyoung 	out_size = MIN(sizeof(ns), eltsize);
40590634029Sdyoung 
40690634029Sdyoung 	if (op != IEEE80211_SYSCTL_OP_ALL || arg != 0 ||
40790634029Sdyoung 	    hdr_type != IEEE80211_SYSCTL_T_NODE || eltsize < 1 || nelt < 0)
40890634029Sdyoung 		return (EINVAL);
40990634029Sdyoung 
41090634029Sdyoung 	error = 0;
41190634029Sdyoung 	needed = 0;
41290634029Sdyoung 	ifcount = 0;
41390634029Sdyoung 	last_ifindex = 0;
41490634029Sdyoung 
41590634029Sdyoung 	s = splnet();
41690634029Sdyoung 
41790634029Sdyoung 	for (ni = ieee80211_node_walkfirst(&nw, ifindex); ni != NULL;
41890634029Sdyoung 	     ni = ieee80211_node_walknext(&nw)) {
41990634029Sdyoung 		struct ieee80211com *ic;
42090634029Sdyoung 
42190634029Sdyoung 		ic = nw.nw_ic;
42290634029Sdyoung 		cur_ifindex = ic->ic_ifp->if_index;
42390634029Sdyoung 
42490634029Sdyoung 		if (cur_ifindex != last_ifindex) {
4250e4587aeSdyoung 			saw_bss = 0;
42690634029Sdyoung 			ifcount++;
42790634029Sdyoung 			last_ifindex = cur_ifindex;
42890634029Sdyoung 		}
42990634029Sdyoung 
43090634029Sdyoung 		if (nelt <= 0)
43190634029Sdyoung 			continue;
43290634029Sdyoung 
433c511c459Sdyoung 		if (saw_bss && ni == ic->ic_bss)
434c511c459Sdyoung 			continue;
4352bfe9aceSdyoung 		else if (ni == ic->ic_bss) {
436c511c459Sdyoung 			saw_bss = 1;
4372bfe9aceSdyoung 			flags = IEEE80211_NODE_SYSCTL_F_BSS;
4382bfe9aceSdyoung 		} else
4392bfe9aceSdyoung 			flags = 0;
4402bfe9aceSdyoung 		if (ni->ni_table == &ic->ic_scan)
4412bfe9aceSdyoung 			flags |= IEEE80211_NODE_SYSCTL_F_SCAN;
4422bfe9aceSdyoung 		else if (ni->ni_table == &ic->ic_sta)
4432bfe9aceSdyoung 			flags |= IEEE80211_NODE_SYSCTL_F_STA;
44490634029Sdyoung 		if (len >= eltsize) {
44590634029Sdyoung 			ieee80211_sysctl_fill_node(ni, &ns, cur_ifindex,
4462bfe9aceSdyoung 			    &ic->ic_channels[0], flags);
44790634029Sdyoung 			error = copyout(&ns, dp, out_size);
44890634029Sdyoung 			if (error)
44990634029Sdyoung 				goto cleanup;
45090634029Sdyoung 			dp += eltsize;
45190634029Sdyoung 			len -= eltsize;
45290634029Sdyoung 		}
45390634029Sdyoung 		needed += eltsize;
45490634029Sdyoung 		if (nelt != INT_MAX)
45590634029Sdyoung 			nelt--;
45690634029Sdyoung 	}
45790634029Sdyoung cleanup:
45890634029Sdyoung 	splx(s);
45990634029Sdyoung 
46090634029Sdyoung 	*oldlenp = needed;
46190634029Sdyoung 	if (oldp == NULL)
46290634029Sdyoung 		*oldlenp += ifcount * IEEE80211_SYSCTL_NODE_GROWTH * eltsize;
46390634029Sdyoung 
46490634029Sdyoung 	return (error);
46590634029Sdyoung }
46690634029Sdyoung 
46790634029Sdyoung /*
46890634029Sdyoung  * Setup sysctl(3) MIB, net.ieee80211.*
46990634029Sdyoung  *
4700efea177Sad  * TBD condition CTLFLAG_PERMANENT on being a module or not
47190634029Sdyoung  */
4723eab37f7Spooka static struct sysctllog *ieee80211_sysctllog;
4733eab37f7Spooka static void
ieee80211_sysctl_setup(void)4743eab37f7Spooka ieee80211_sysctl_setup(void)
47590634029Sdyoung {
47690634029Sdyoung 	int rc;
477c2ec5838Schristos 	const struct sysctlnode *rnode;
47890634029Sdyoung 
4793eab37f7Spooka 	if ((rnode = ieee80211_sysctl_treetop(&ieee80211_sysctllog)) == NULL)
48090634029Sdyoung 		return;
48190634029Sdyoung 
4823eab37f7Spooka 	if ((rc = sysctl_createv(&ieee80211_sysctllog, 0, &rnode, NULL,
48390634029Sdyoung 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "nodes", "client/peer stations",
48490634029Sdyoung 	    ieee80211_sysctl_node, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
48590634029Sdyoung 		goto err;
48690634029Sdyoung 
48790634029Sdyoung #ifdef IEEE80211_DEBUG
48890634029Sdyoung 	/* control debugging printfs */
489c2ec5838Schristos 	if ((rc = sysctl_createv(&ieee80211_sysctllog, 0, &rnode, NULL,
49090634029Sdyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
49190634029Sdyoung 	    "debug", SYSCTL_DESCR("control debugging printfs"),
49290634029Sdyoung 	    NULL, 0, &ieee80211_debug, 0, CTL_CREATE, CTL_EOL)) != 0)
49390634029Sdyoung 		goto err;
494f43b1441Smaxv #endif
49590634029Sdyoung 
4963eab37f7Spooka 	ieee80211_rssadapt_sysctl_setup(&ieee80211_sysctllog);
4973eab37f7Spooka 
49890634029Sdyoung 	return;
49990634029Sdyoung err:
50090634029Sdyoung 	printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
5013cdc4fcdSdyoung }
5023cdc4fcdSdyoung 
5033cdc4fcdSdyoung int
ieee80211_node_dectestref(struct ieee80211_node * ni)5043cdc4fcdSdyoung ieee80211_node_dectestref(struct ieee80211_node *ni)
5053cdc4fcdSdyoung {
5062ed4138bSdyoung 	if (atomic_dec_uint_nv(&ni->ni_refcnt) == 0) {
5072ed4138bSdyoung 		atomic_inc_uint(&ni->ni_refcnt);
5082ed4138bSdyoung 		return 1;
50990634029Sdyoung 	} else
5102ed4138bSdyoung 		return 0;
51190634029Sdyoung }
51290634029Sdyoung 
51390634029Sdyoung void
ieee80211_drain_ifq(struct ifqueue * ifq)514f8d4f721Sdegroote ieee80211_drain_ifq(struct ifqueue *ifq)
515f8d4f721Sdegroote {
516f8d4f721Sdegroote 	struct ieee80211_node *ni;
517f8d4f721Sdegroote 	struct mbuf *m;
518f8d4f721Sdegroote 
519f8d4f721Sdegroote 	for (;;) {
520f8d4f721Sdegroote 		IF_DEQUEUE(ifq, m);
521f8d4f721Sdegroote 		if (m == NULL)
522f8d4f721Sdegroote 			break;
523f8d4f721Sdegroote 
524cef59834Sozaki-r 		ni = M_GETCTX(m, struct ieee80211_node *);
525f8d4f721Sdegroote 		KASSERT(ni != NULL);
526f8d4f721Sdegroote 		ieee80211_free_node(ni);
527cef59834Sozaki-r 		M_SETCTX(m, NULL);
528f8d4f721Sdegroote 
529f8d4f721Sdegroote 		m_freem(m);
530f8d4f721Sdegroote 	}
531f8d4f721Sdegroote }
532f8d4f721Sdegroote 
533f8d4f721Sdegroote void
if_printf(struct ifnet * ifp,const char * fmt,...)53490634029Sdyoung if_printf(struct ifnet *ifp, const char *fmt, ...)
53590634029Sdyoung {
53690634029Sdyoung 	va_list ap;
53790634029Sdyoung 	va_start(ap, fmt);
53890634029Sdyoung 
53990634029Sdyoung 	printf("%s: ", ifp->if_xname);
54090634029Sdyoung 	vprintf(fmt, ap);
54190634029Sdyoung 
54290634029Sdyoung 	va_end(ap);
54390634029Sdyoung 	return;
54490634029Sdyoung }
54590634029Sdyoung 
5463cdc4fcdSdyoung /*
5473cdc4fcdSdyoung  * Allocate and setup a management frame of the specified
5483cdc4fcdSdyoung  * size.  We return the mbuf and a pointer to the start
5493cdc4fcdSdyoung  * of the contiguous data area that's been reserved based
5503cdc4fcdSdyoung  * on the packet length.  The data area is forced to 32-bit
5513cdc4fcdSdyoung  * alignment and the buffer length to a multiple of 4 bytes.
5523cdc4fcdSdyoung  * This is done mainly so beacon frames (that require this)
5533cdc4fcdSdyoung  * can use this interface too.
5543cdc4fcdSdyoung  */
5553cdc4fcdSdyoung struct mbuf *
ieee80211_getmgtframe(u_int8_t ** frm,u_int pktlen)5563cdc4fcdSdyoung ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen)
5573cdc4fcdSdyoung {
5583cdc4fcdSdyoung 	struct mbuf *m;
5593cdc4fcdSdyoung 	u_int len;
5603cdc4fcdSdyoung 
5613cdc4fcdSdyoung 	/*
5623cdc4fcdSdyoung 	 * NB: we know the mbuf routines will align the data area
5633cdc4fcdSdyoung 	 *     so we don't need to do anything special.
5643cdc4fcdSdyoung 	 */
5653cdc4fcdSdyoung 	/* XXX 4-address frame? */
5663cdc4fcdSdyoung 	len = roundup(sizeof(struct ieee80211_frame) + pktlen, 4);
56790634029Sdyoung 	IASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
568f43b1441Smaxv 
56990634029Sdyoung 	if (len <= MHLEN) {
5703cdc4fcdSdyoung 		m = m_gethdr(M_NOWAIT, MT_HEADER);
5713cdc4fcdSdyoung 		/*
5723cdc4fcdSdyoung 		 * Align the data in case additional headers are added.
5733cdc4fcdSdyoung 		 * This should only happen when a WEP header is added
5743cdc4fcdSdyoung 		 * which only happens for shared key authentication mgt
5753cdc4fcdSdyoung 		 * frames which all fit in MHLEN.
5763cdc4fcdSdyoung 		 */
5773cdc4fcdSdyoung 		if (m != NULL)
578*5b040abeSmaxv 			m_align(m, len);
579f43b1441Smaxv 	} else {
5803cdc4fcdSdyoung 		m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR);
581f43b1441Smaxv 	}
582f43b1441Smaxv 
5833cdc4fcdSdyoung 	if (m != NULL) {
5843cdc4fcdSdyoung 		m->m_data += sizeof(struct ieee80211_frame);
5853cdc4fcdSdyoung 		*frm = m->m_data;
5862bfe9aceSdyoung 		IASSERT((uintptr_t)*frm % 4 == 0, ("bad beacon boundary"));
5873cdc4fcdSdyoung 	}
588f43b1441Smaxv 
5893cdc4fcdSdyoung 	return m;
5903cdc4fcdSdyoung }
5913cdc4fcdSdyoung 
5923cdc4fcdSdyoung void
get_random_bytes(void * p,size_t n)5933cdc4fcdSdyoung get_random_bytes(void *p, size_t n)
5943cdc4fcdSdyoung {
5953afd44cfStls 	cprng_fast(p, n);
5963cdc4fcdSdyoung }
5973cdc4fcdSdyoung 
5983cdc4fcdSdyoung void
ieee80211_notify_node_join(struct ieee80211com * ic,struct ieee80211_node * ni,int newassoc)599f43b1441Smaxv ieee80211_notify_node_join(struct ieee80211com *ic, struct ieee80211_node *ni,
600f43b1441Smaxv     int newassoc)
6013cdc4fcdSdyoung {
6023cdc4fcdSdyoung 	struct ifnet *ifp = ic->ic_ifp;
6033cdc4fcdSdyoung 	struct ieee80211_join_event iev;
6043cdc4fcdSdyoung 
605ef999039Schristos 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "%snode %s join\n",
606ef999039Schristos 	    (ni == ic->ic_bss) ? "bss " : "",
6079a7ebfddSdyoung 	    ether_sprintf(ni->ni_macaddr));
6089a7ebfddSdyoung 
60990634029Sdyoung 	memset(&iev, 0, sizeof(iev));
61092b58820Sdyoung 	if (ni == ic->ic_bss) {
6113cdc4fcdSdyoung 		IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_bssid);
6123cdc4fcdSdyoung 		rt_ieee80211msg(ifp, newassoc ?
6133cdc4fcdSdyoung 		    RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC,
6143cdc4fcdSdyoung 		    &iev, sizeof(iev));
6153cdc4fcdSdyoung 		if_link_state_change(ifp, LINK_STATE_UP);
6163f5a745eSchristos 	} else {
6173cdc4fcdSdyoung 		IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr);
6183f5a745eSchristos 		rt_ieee80211msg(ifp, newassoc ?
6193f5a745eSchristos 		    RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN,
6203f5a745eSchristos 		    &iev, sizeof(iev));
6213cdc4fcdSdyoung 	}
6223cdc4fcdSdyoung }
6233cdc4fcdSdyoung 
6243cdc4fcdSdyoung void
ieee80211_notify_node_leave(struct ieee80211com * ic,struct ieee80211_node * ni)6253cdc4fcdSdyoung ieee80211_notify_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
6263cdc4fcdSdyoung {
6273cdc4fcdSdyoung 	struct ifnet *ifp = ic->ic_ifp;
6283cdc4fcdSdyoung 	struct ieee80211_leave_event iev;
6293cdc4fcdSdyoung 
630ef999039Schristos 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "%snode %s leave\n",
631ef999039Schristos 	    (ni == ic->ic_bss) ? "bss " : "",
6329a7ebfddSdyoung 	    ether_sprintf(ni->ni_macaddr));
6339a7ebfddSdyoung 
6343cdc4fcdSdyoung 	if (ni == ic->ic_bss) {
6353cdc4fcdSdyoung 		rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0);
6363cdc4fcdSdyoung 		if_link_state_change(ifp, LINK_STATE_DOWN);
6373cdc4fcdSdyoung 	} else {
6383cdc4fcdSdyoung 		/* fire off wireless event station leaving */
6393cdc4fcdSdyoung 		memset(&iev, 0, sizeof(iev));
6403cdc4fcdSdyoung 		IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr);
6413cdc4fcdSdyoung 		rt_ieee80211msg(ifp, RTM_IEEE80211_LEAVE, &iev, sizeof(iev));
6423cdc4fcdSdyoung 	}
6433cdc4fcdSdyoung }
6443cdc4fcdSdyoung 
6453cdc4fcdSdyoung void
ieee80211_notify_scan_done(struct ieee80211com * ic)6463cdc4fcdSdyoung ieee80211_notify_scan_done(struct ieee80211com *ic)
6473cdc4fcdSdyoung {
6483cdc4fcdSdyoung 	struct ifnet *ifp = ic->ic_ifp;
6493cdc4fcdSdyoung 
6503cdc4fcdSdyoung 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
651ef999039Schristos 		"%s", "notify scan done\n");
6523cdc4fcdSdyoung 
6533cdc4fcdSdyoung 	/* dispatch wireless event indicating scan completed */
6543cdc4fcdSdyoung 	rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0);
6553cdc4fcdSdyoung }
6563cdc4fcdSdyoung 
6573cdc4fcdSdyoung void
ieee80211_notify_replay_failure(struct ieee80211com * ic,const struct ieee80211_frame * wh,const struct ieee80211_key * k,u_int64_t rsc)6583cdc4fcdSdyoung ieee80211_notify_replay_failure(struct ieee80211com *ic,
6593cdc4fcdSdyoung 	const struct ieee80211_frame *wh, const struct ieee80211_key *k,
6603cdc4fcdSdyoung 	u_int64_t rsc)
6613cdc4fcdSdyoung {
6623cdc4fcdSdyoung 	struct ifnet *ifp = ic->ic_ifp;
6633cdc4fcdSdyoung 
6643cdc4fcdSdyoung 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
66587515e34Sskrll 	    "[%s] %s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>\n",
6663cdc4fcdSdyoung 	    ether_sprintf(wh->i_addr2), k->wk_cipher->ic_name,
66787515e34Sskrll 	    (intmax_t) rsc, (intmax_t) k->wk_keyrsc,
66887515e34Sskrll 	    k->wk_keyix, k->wk_rxkeyix);
6693cdc4fcdSdyoung 
6703cdc4fcdSdyoung 	if (ifp != NULL) {		/* NB: for cipher test modules */
6713cdc4fcdSdyoung 		struct ieee80211_replay_event iev;
6723cdc4fcdSdyoung 
6733cdc4fcdSdyoung 		IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
6743cdc4fcdSdyoung 		IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
6753cdc4fcdSdyoung 		iev.iev_cipher = k->wk_cipher->ic_cipher;
67687515e34Sskrll 		if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE)
67787515e34Sskrll 			iev.iev_keyix = k->wk_rxkeyix;
67887515e34Sskrll 		else
6793cdc4fcdSdyoung 			iev.iev_keyix = k->wk_keyix;
6803cdc4fcdSdyoung 		iev.iev_keyrsc = k->wk_keyrsc;
6813cdc4fcdSdyoung 		iev.iev_rsc = rsc;
6823cdc4fcdSdyoung 		rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev));
6833cdc4fcdSdyoung 	}
6843cdc4fcdSdyoung }
6853cdc4fcdSdyoung 
6863cdc4fcdSdyoung void
ieee80211_notify_michael_failure(struct ieee80211com * ic,const struct ieee80211_frame * wh,u_int keyix)6873cdc4fcdSdyoung ieee80211_notify_michael_failure(struct ieee80211com *ic,
6883cdc4fcdSdyoung 	const struct ieee80211_frame *wh, u_int keyix)
6893cdc4fcdSdyoung {
6903cdc4fcdSdyoung 	struct ifnet *ifp = ic->ic_ifp;
6913cdc4fcdSdyoung 
6923cdc4fcdSdyoung 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
6933cdc4fcdSdyoung 	    "[%s] michael MIC verification failed <keyix %u>\n",
6943cdc4fcdSdyoung 	    ether_sprintf(wh->i_addr2), keyix);
6953cdc4fcdSdyoung 	ic->ic_stats.is_rx_tkipmic++;
6963cdc4fcdSdyoung 
6973cdc4fcdSdyoung 	if (ifp != NULL) {		/* NB: for cipher test modules */
6983cdc4fcdSdyoung 		struct ieee80211_michael_event iev;
6993cdc4fcdSdyoung 
7003cdc4fcdSdyoung 		IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
7013cdc4fcdSdyoung 		IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
7023cdc4fcdSdyoung 		iev.iev_cipher = IEEE80211_CIPHER_TKIP;
7033cdc4fcdSdyoung 		iev.iev_keyix = keyix;
7043cdc4fcdSdyoung 		rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev));
7053cdc4fcdSdyoung 	}
7063cdc4fcdSdyoung }
7073cdc4fcdSdyoung 
7083cdc4fcdSdyoung void
ieee80211_load_module(const char * modname)7093cdc4fcdSdyoung ieee80211_load_module(const char *modname)
7103cdc4fcdSdyoung {
7113cdc4fcdSdyoung #ifdef notyet
7123cdc4fcdSdyoung 	struct thread *td = curthread;
7133cdc4fcdSdyoung 
7143cdc4fcdSdyoung 	if (suser(td) == 0 && securelevel_gt(td->td_ucred, 0) == 0) {
7153cdc4fcdSdyoung 		mtx_lock(&Giant);
7163cdc4fcdSdyoung 		(void) linker_load_module(modname, NULL, NULL, NULL, NULL);
7173cdc4fcdSdyoung 		mtx_unlock(&Giant);
7183cdc4fcdSdyoung 	}
7193cdc4fcdSdyoung #else
7203cdc4fcdSdyoung 	printf("%s: load the %s module by hand for now.\n", __func__, modname);
7213cdc4fcdSdyoung #endif
7223cdc4fcdSdyoung }
7233f23c9efSmaxv 
7243f23c9efSmaxv /* -------------------------------------------------------------------------- */
7253f23c9efSmaxv 
7263f23c9efSmaxv /*
7273f23c9efSmaxv  * Append the specified data to the indicated mbuf chain,
7283f23c9efSmaxv  * Extend the mbuf chain if the new data does not fit in
7293f23c9efSmaxv  * existing space.
7303f23c9efSmaxv  *
7313f23c9efSmaxv  * Return 1 if able to complete the job; otherwise 0.
7323f23c9efSmaxv  */
7333f23c9efSmaxv int
m_append(struct mbuf * m0,int len,const void * cpv)7343f23c9efSmaxv m_append(struct mbuf *m0, int len, const void *cpv)
7353f23c9efSmaxv {
7363f23c9efSmaxv 	struct mbuf *m, *n;
7373f23c9efSmaxv 	int remainder, space;
7383f23c9efSmaxv 	const char *cp = cpv;
7393f23c9efSmaxv 
7403f23c9efSmaxv 	KASSERT(len != M_COPYALL);
7413f23c9efSmaxv 	for (m = m0; m->m_next != NULL; m = m->m_next)
7423f23c9efSmaxv 		continue;
7433f23c9efSmaxv 	remainder = len;
7443f23c9efSmaxv 	space = M_TRAILINGSPACE(m);
7453f23c9efSmaxv 	if (space > 0) {
7463f23c9efSmaxv 		/*
7473f23c9efSmaxv 		 * Copy into available space.
7483f23c9efSmaxv 		 */
7493f23c9efSmaxv 		if (space > remainder)
7503f23c9efSmaxv 			space = remainder;
7513f23c9efSmaxv 		memmove(mtod(m, char *) + m->m_len, cp, space);
7523f23c9efSmaxv 		m->m_len += space;
7533f23c9efSmaxv 		cp = cp + space, remainder -= space;
7543f23c9efSmaxv 	}
7553f23c9efSmaxv 	while (remainder > 0) {
7563f23c9efSmaxv 		/*
7573f23c9efSmaxv 		 * Allocate a new mbuf; could check space
7583f23c9efSmaxv 		 * and allocate a cluster instead.
7593f23c9efSmaxv 		 */
7603f23c9efSmaxv 		n = m_get(M_DONTWAIT, m->m_type);
7613f23c9efSmaxv 		if (n == NULL)
7623f23c9efSmaxv 			break;
763d1579b2dSriastradh 		n->m_len = uimin(MLEN, remainder);
7643f23c9efSmaxv 		memmove(mtod(n, void *), cp, n->m_len);
7653f23c9efSmaxv 		cp += n->m_len, remainder -= n->m_len;
7663f23c9efSmaxv 		m->m_next = n;
7673f23c9efSmaxv 		m = n;
7683f23c9efSmaxv 	}
7693f23c9efSmaxv 	if (m0->m_flags & M_PKTHDR)
7703f23c9efSmaxv 		m0->m_pkthdr.len += len - remainder;
7713f23c9efSmaxv 	return (remainder == 0);
7723f23c9efSmaxv }
773