xref: /netbsd/sys/net80211/ieee80211_netbsd.c (revision ae0244df)
1 /* $NetBSD: ieee80211_netbsd.c,v 1.34 2018/12/22 14:28:56 maxv Exp $ */
2 
3 /*
4  * Copyright (c) 2003-2005 Sam Leffler, Errno Consulting
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 #ifdef __FreeBSD__
32 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_freebsd.c,v 1.8 2005/08/08 18:46:35 sam Exp $");
33 #else
34 __KERNEL_RCSID(0, "$NetBSD: ieee80211_netbsd.c,v 1.34 2018/12/22 14:28:56 maxv Exp $");
35 #endif
36 
37 /*
38  * IEEE 802.11 support (NetBSD-specific code)
39  */
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/systm.h>
43 #include <sys/mbuf.h>
44 #include <sys/proc.h>
45 #include <sys/sysctl.h>
46 #include <sys/once.h>
47 
48 #include <sys/socket.h>
49 
50 #include <sys/cprng.h>
51 
52 #include <net/if.h>
53 #include <net/if_media.h>
54 #include <net/if_ether.h>
55 #include <net/route.h>
56 
57 #include <net80211/ieee80211_netbsd.h>
58 #include <net80211/ieee80211_var.h>
59 #include <net80211/ieee80211_sysctl.h>
60 
61 #define	LOGICALLY_EQUAL(x, y)	(!(x) == !(y))
62 
63 static void ieee80211_sysctl_fill_node(struct ieee80211_node *,
64     struct ieee80211_node_sysctl *, int, const struct ieee80211_channel *,
65     uint32_t);
66 static struct ieee80211_node *ieee80211_node_walknext(
67     struct ieee80211_node_walk *);
68 static struct ieee80211_node *ieee80211_node_walkfirst(
69     struct ieee80211_node_walk *, u_short);
70 static int ieee80211_sysctl_node(SYSCTLFN_ARGS);
71 
72 static void ieee80211_sysctl_setup(void);
73 
74 #ifdef IEEE80211_DEBUG
75 int	ieee80211_debug = 0;
76 #endif
77 
78 typedef void (*ieee80211_setup_func)(void);
79 
80 __link_set_decl(ieee80211_funcs, ieee80211_setup_func);
81 
82 static int
ieee80211_init0(void)83 ieee80211_init0(void)
84 {
85 	ieee80211_setup_func * const *ieee80211_setup, f;
86 
87 	ieee80211_sysctl_setup();
88 
89 	if (max_linkhdr < ALIGN(sizeof(struct ieee80211_qosframe_addr4))) {
90 		max_linkhdr = ALIGN(sizeof(struct ieee80211_qosframe_addr4));
91 	}
92 
93 	__link_set_foreach(ieee80211_setup, ieee80211_funcs) {
94 		f = (void*)*ieee80211_setup;
95 		(*f)();
96 	}
97 
98 	return 0;
99 }
100 
101 void
ieee80211_init(void)102 ieee80211_init(void)
103 {
104 	static ONCE_DECL(ieee80211_init_once);
105 
106 	RUN_ONCE(&ieee80211_init_once, ieee80211_init0);
107 }
108 
109 static int
ieee80211_sysctl_inact(SYSCTLFN_ARGS)110 ieee80211_sysctl_inact(SYSCTLFN_ARGS)
111 {
112 	int error, t;
113 	struct sysctlnode node;
114 
115 	node = *rnode;
116 
117 	/*
118 	 * sysctl_lookup copies the product from t.  Then, it
119 	 * copies the new value onto t.
120 	 */
121 	t = *(int*)rnode->sysctl_data * IEEE80211_INACT_WAIT;
122 	node.sysctl_data = &t;
123 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
124 	if (error || newp == NULL)
125 		return error;
126 
127 	/*
128 	 * The new value was in seconds.  Convert to inactivity-wait
129 	 * intervals.  There are IEEE80211_INACT_WAIT seconds per
130 	 * interval.
131 	 */
132 	*(int*)rnode->sysctl_data = t / IEEE80211_INACT_WAIT;
133 
134 	return 0;
135 }
136 
137 static int
ieee80211_sysctl_parent(SYSCTLFN_ARGS)138 ieee80211_sysctl_parent(SYSCTLFN_ARGS)
139 {
140 	struct ieee80211com *ic;
141 	char pname[IFNAMSIZ];
142 	struct sysctlnode node;
143 
144 	node = *rnode;
145 	ic = node.sysctl_data;
146 	strlcpy(pname, ic->ic_ifp->if_xname, IFNAMSIZ);
147 	node.sysctl_data = pname;
148 	return sysctl_lookup(SYSCTLFN_CALL(&node));
149 }
150 
151 /*
152  * Create or get top of sysctl tree net.link.ieee80211.
153  */
154 static const struct sysctlnode *
ieee80211_sysctl_treetop(struct sysctllog ** log)155 ieee80211_sysctl_treetop(struct sysctllog **log)
156 {
157 	int rc;
158 	const struct sysctlnode *rnode;
159 
160 	if ((rc = sysctl_createv(log, 0, NULL, &rnode,
161 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "link",
162 	    "link-layer statistics and controls",
163 	    NULL, 0, NULL, 0, CTL_NET, PF_LINK, CTL_EOL)) != 0)
164 		goto err;
165 
166 	if ((rc = sysctl_createv(log, 0, &rnode, &rnode,
167 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "ieee80211",
168 	    "IEEE 802.11 WLAN statistics and controls",
169 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
170 		goto err;
171 
172 	return rnode;
173 err:
174 	printf("%s: sysctl_createv failed, rc = %d\n", __func__, rc);
175 	return NULL;
176 }
177 
178 void
ieee80211_sysctl_attach(struct ieee80211com * ic)179 ieee80211_sysctl_attach(struct ieee80211com *ic)
180 {
181 	int rc;
182 	const struct sysctlnode *cnode, *rnode;
183 	char num[sizeof("vap") + 14];		/* sufficient for 32 bits */
184 
185 	if ((rnode = ieee80211_sysctl_treetop(NULL)) == NULL)
186 		return;
187 
188 	snprintf(num, sizeof(num), "vap%u", ic->ic_vap);
189 
190 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &rnode,
191 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, num, SYSCTL_DESCR("virtual AP"),
192 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
193 		goto err;
194 
195 	/* control debugging printfs */
196 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
197 	    CTLFLAG_PERMANENT|CTLFLAG_READONLY, CTLTYPE_STRING,
198 	    "parent", SYSCTL_DESCR("parent device"),
199 	    ieee80211_sysctl_parent, 0, (void *)ic, IFNAMSIZ, CTL_CREATE,
200 	    CTL_EOL)) != 0)
201 		goto err;
202 
203 #ifdef IEEE80211_DEBUG
204 	/* control debugging printfs */
205 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
206 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
207 	    "debug", SYSCTL_DESCR("control debugging printfs"),
208 	    NULL, ieee80211_debug, &ic->ic_debug, 0,
209 	    CTL_CREATE, CTL_EOL)) != 0)
210 		goto err;
211 #endif
212 	/* XXX inherit from tunables */
213 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
214 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
215 	    "inact_run", SYSCTL_DESCR("station inactivity timeout (sec)"),
216 	    ieee80211_sysctl_inact, 0, &ic->ic_inact_run, 0,
217 	    CTL_CREATE, CTL_EOL)) != 0)
218 		goto err;
219 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
220 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
221 	    "inact_probe",
222 	    SYSCTL_DESCR("station inactivity probe timeout (sec)"),
223 	    ieee80211_sysctl_inact, 0, &ic->ic_inact_probe, 0,
224 	    CTL_CREATE, CTL_EOL)) != 0)
225 		goto err;
226 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
227 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
228 	    "inact_auth",
229 	    SYSCTL_DESCR("station authentication timeout (sec)"),
230 	    ieee80211_sysctl_inact, 0, &ic->ic_inact_auth, 0,
231 	    CTL_CREATE, CTL_EOL)) != 0)
232 		goto err;
233 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
234 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
235 	    "inact_init",
236 	    SYSCTL_DESCR("station initial state timeout (sec)"),
237 	    ieee80211_sysctl_inact, 0, &ic->ic_inact_init, 0,
238 	    CTL_CREATE, CTL_EOL)) != 0)
239 		goto err;
240 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
241 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
242 	    "driver_caps", SYSCTL_DESCR("driver capabilities"),
243 	    NULL, 0, &ic->ic_caps, 0, CTL_CREATE, CTL_EOL)) != 0)
244 		goto err;
245 	if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode,
246 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
247 	    "bmiss_max", SYSCTL_DESCR("consecutive beacon misses before scanning"),
248 	    NULL, 0, &ic->ic_bmiss_max, 0, CTL_CREATE, CTL_EOL)) != 0)
249 		goto err;
250 
251 	return;
252 err:
253 	printf("%s: sysctl_createv failed, rc = %d\n", __func__, rc);
254 }
255 
256 void
ieee80211_sysctl_detach(struct ieee80211com * ic)257 ieee80211_sysctl_detach(struct ieee80211com *ic)
258 {
259 	sysctl_teardown(&ic->ic_sysctllog);
260 }
261 
262 /*
263  * Pointers for testing:
264  *
265  *	If there are no interfaces, or else no 802.11 interfaces,
266  *	ieee80211_node_walkfirst must return NULL.
267  *
268  *	If there is any single 802.11 interface, ieee80211_node_walkfirst
269  *	must not return NULL.
270  */
271 static struct ieee80211_node *
ieee80211_node_walkfirst(struct ieee80211_node_walk * nw,u_short if_index)272 ieee80211_node_walkfirst(struct ieee80211_node_walk *nw, u_short if_index)
273 {
274 	memset(nw, 0, sizeof(*nw));
275 
276 	nw->nw_ifindex = if_index;
277 
278 	LIST_FOREACH(nw->nw_ic, &ieee80211com_head, ic_list) {
279 		if (if_index != 0 && nw->nw_ic->ic_ifp->if_index != if_index)
280 			continue;
281 		if (!TAILQ_EMPTY(&nw->nw_ic->ic_sta.nt_node))
282 			nw->nw_nt = &nw->nw_ic->ic_sta;
283 		else if (!TAILQ_EMPTY(&nw->nw_ic->ic_scan.nt_node))
284 			nw->nw_nt = &nw->nw_ic->ic_scan;
285 		else if (nw->nw_ic->ic_bss == NULL)
286 			continue;
287 		break;
288 	}
289 
290 	if (nw->nw_ic == NULL)
291 		return NULL;
292 
293 	if (nw->nw_nt == NULL)
294 		nw->nw_ni = nw->nw_ic->ic_bss;
295 	else
296 		nw->nw_ni = TAILQ_FIRST(&nw->nw_nt->nt_node);
297 
298 	return nw->nw_ni;
299 }
300 
301 static struct ieee80211_node *
ieee80211_node_walknext(struct ieee80211_node_walk * nw)302 ieee80211_node_walknext(struct ieee80211_node_walk *nw)
303 {
304 	if (nw->nw_nt != NULL)
305 		nw->nw_ni = TAILQ_NEXT(nw->nw_ni, ni_list);
306 	else
307 		nw->nw_ni = NULL;
308 
309 	while (nw->nw_ni == NULL) {
310 		if (nw->nw_nt == &nw->nw_ic->ic_sta) {
311 			nw->nw_nt = &nw->nw_ic->ic_scan;
312 			nw->nw_ni = TAILQ_FIRST(&nw->nw_nt->nt_node);
313 			continue;
314 		} else if (nw->nw_nt == &nw->nw_ic->ic_scan) {
315 			nw->nw_nt = NULL;
316 			nw->nw_ni = nw->nw_ic->ic_bss;
317 			continue;
318 		}
319 		KASSERT(nw->nw_nt == NULL);
320 		if (nw->nw_ifindex != 0)
321 			return NULL;
322 
323 		nw->nw_ic = LIST_NEXT(nw->nw_ic, ic_list);
324 		if (nw->nw_ic == NULL)
325 			return NULL;
326 
327 		nw->nw_nt = &nw->nw_ic->ic_sta;
328 		nw->nw_ni = TAILQ_FIRST(&nw->nw_nt->nt_node);
329 	}
330 
331 	return nw->nw_ni;
332 }
333 
334 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)335 ieee80211_sysctl_fill_node(struct ieee80211_node *ni,
336     struct ieee80211_node_sysctl *ns, int ifindex,
337     const struct ieee80211_channel *chan0, uint32_t flags)
338 {
339 	memset(ns, 0, sizeof(*ns));
340 
341 	ns->ns_ifindex = ifindex;
342 	ns->ns_capinfo = ni->ni_capinfo;
343 	ns->ns_flags = flags;
344 	memcpy(ns->ns_macaddr, ni->ni_macaddr, sizeof(ns->ns_macaddr));
345 	memcpy(ns->ns_bssid, ni->ni_bssid, sizeof(ns->ns_bssid));
346 	if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
347 		ns->ns_freq = ni->ni_chan->ic_freq;
348 		ns->ns_chanflags = ni->ni_chan->ic_flags;
349 		ns->ns_chanidx = ni->ni_chan - chan0;
350 	} else {
351 		ns->ns_freq = ns->ns_chanflags = 0;
352 		ns->ns_chanidx = 0;
353 	}
354 	ns->ns_rssi = ni->ni_rssi;
355 	ns->ns_esslen = ni->ni_esslen;
356 	memcpy(ns->ns_essid, ni->ni_essid, sizeof(ns->ns_essid));
357 	ns->ns_erp = ni->ni_erp;
358 	ns->ns_associd = ni->ni_associd;
359 	ns->ns_inact = ni->ni_inact * IEEE80211_INACT_WAIT;
360 	ns->ns_rstamp = ni->ni_rstamp;
361 	ns->ns_rates = ni->ni_rates;
362 	ns->ns_txrate = ni->ni_txrate;
363 	ns->ns_intval = ni->ni_intval;
364 	memcpy(ns->ns_tstamp, &ni->ni_tstamp, sizeof(ns->ns_tstamp));
365 	ns->ns_txseq = ni->ni_txseqs[0];
366 	ns->ns_rxseq = ni->ni_rxseqs[0];
367 	ns->ns_fhdwell = ni->ni_fhdwell;
368 	ns->ns_fhindex = ni->ni_fhindex;
369 	ns->ns_fails = ni->ni_fails;
370 }
371 
372 /* Between two examinations of the sysctl tree, I expect each
373  * interface to add no more than 5 nodes.
374  */
375 #define IEEE80211_SYSCTL_NODE_GROWTH	5
376 
377 static int
ieee80211_sysctl_node(SYSCTLFN_ARGS)378 ieee80211_sysctl_node(SYSCTLFN_ARGS)
379 {
380 	struct ieee80211_node_walk nw;
381 	struct ieee80211_node *ni;
382 	struct ieee80211_node_sysctl ns;
383 	char *dp;
384 	u_int cur_ifindex, ifcount, ifindex, last_ifindex, op, arg, hdr_type;
385 	uint32_t flags;
386 	size_t len, needed, eltsize, out_size;
387 	int error, s, saw_bss = 0, nelt;
388 
389 	if (namelen == 1 && name[0] == CTL_QUERY)
390 		return (sysctl_query(SYSCTLFN_CALL(rnode)));
391 
392 	if (namelen != IEEE80211_SYSCTL_NODENAMELEN)
393 		return (EINVAL);
394 
395 	/* ifindex.op.arg.header-type.eltsize.nelt */
396 	dp = oldp;
397 	len = (oldp != NULL) ? *oldlenp : 0;
398 	ifindex = name[IEEE80211_SYSCTL_NODENAME_IF];
399 	op = name[IEEE80211_SYSCTL_NODENAME_OP];
400 	arg = name[IEEE80211_SYSCTL_NODENAME_ARG];
401 	hdr_type = name[IEEE80211_SYSCTL_NODENAME_TYPE];
402 	eltsize = name[IEEE80211_SYSCTL_NODENAME_ELTSIZE];
403 	nelt = name[IEEE80211_SYSCTL_NODENAME_ELTCOUNT];
404 	out_size = MIN(sizeof(ns), eltsize);
405 
406 	if (op != IEEE80211_SYSCTL_OP_ALL || arg != 0 ||
407 	    hdr_type != IEEE80211_SYSCTL_T_NODE || eltsize < 1 || nelt < 0)
408 		return (EINVAL);
409 
410 	error = 0;
411 	needed = 0;
412 	ifcount = 0;
413 	last_ifindex = 0;
414 
415 	s = splnet();
416 
417 	for (ni = ieee80211_node_walkfirst(&nw, ifindex); ni != NULL;
418 	     ni = ieee80211_node_walknext(&nw)) {
419 		struct ieee80211com *ic;
420 
421 		ic = nw.nw_ic;
422 		cur_ifindex = ic->ic_ifp->if_index;
423 
424 		if (cur_ifindex != last_ifindex) {
425 			saw_bss = 0;
426 			ifcount++;
427 			last_ifindex = cur_ifindex;
428 		}
429 
430 		if (nelt <= 0)
431 			continue;
432 
433 		if (saw_bss && ni == ic->ic_bss)
434 			continue;
435 		else if (ni == ic->ic_bss) {
436 			saw_bss = 1;
437 			flags = IEEE80211_NODE_SYSCTL_F_BSS;
438 		} else
439 			flags = 0;
440 		if (ni->ni_table == &ic->ic_scan)
441 			flags |= IEEE80211_NODE_SYSCTL_F_SCAN;
442 		else if (ni->ni_table == &ic->ic_sta)
443 			flags |= IEEE80211_NODE_SYSCTL_F_STA;
444 		if (len >= eltsize) {
445 			ieee80211_sysctl_fill_node(ni, &ns, cur_ifindex,
446 			    &ic->ic_channels[0], flags);
447 			error = copyout(&ns, dp, out_size);
448 			if (error)
449 				goto cleanup;
450 			dp += eltsize;
451 			len -= eltsize;
452 		}
453 		needed += eltsize;
454 		if (nelt != INT_MAX)
455 			nelt--;
456 	}
457 cleanup:
458 	splx(s);
459 
460 	*oldlenp = needed;
461 	if (oldp == NULL)
462 		*oldlenp += ifcount * IEEE80211_SYSCTL_NODE_GROWTH * eltsize;
463 
464 	return (error);
465 }
466 
467 /*
468  * Setup sysctl(3) MIB, net.ieee80211.*
469  *
470  * TBD condition CTLFLAG_PERMANENT on being a module or not
471  */
472 static struct sysctllog *ieee80211_sysctllog;
473 static void
ieee80211_sysctl_setup(void)474 ieee80211_sysctl_setup(void)
475 {
476 	int rc;
477 	const struct sysctlnode *rnode;
478 
479 	if ((rnode = ieee80211_sysctl_treetop(&ieee80211_sysctllog)) == NULL)
480 		return;
481 
482 	if ((rc = sysctl_createv(&ieee80211_sysctllog, 0, &rnode, NULL,
483 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "nodes", "client/peer stations",
484 	    ieee80211_sysctl_node, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
485 		goto err;
486 
487 #ifdef IEEE80211_DEBUG
488 	/* control debugging printfs */
489 	if ((rc = sysctl_createv(&ieee80211_sysctllog, 0, &rnode, NULL,
490 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
491 	    "debug", SYSCTL_DESCR("control debugging printfs"),
492 	    NULL, 0, &ieee80211_debug, 0, CTL_CREATE, CTL_EOL)) != 0)
493 		goto err;
494 #endif
495 
496 	ieee80211_rssadapt_sysctl_setup(&ieee80211_sysctllog);
497 
498 	return;
499 err:
500 	printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
501 }
502 
503 int
ieee80211_node_dectestref(struct ieee80211_node * ni)504 ieee80211_node_dectestref(struct ieee80211_node *ni)
505 {
506 	if (atomic_dec_uint_nv(&ni->ni_refcnt) == 0) {
507 		atomic_inc_uint(&ni->ni_refcnt);
508 		return 1;
509 	} else
510 		return 0;
511 }
512 
513 void
ieee80211_drain_ifq(struct ifqueue * ifq)514 ieee80211_drain_ifq(struct ifqueue *ifq)
515 {
516 	struct ieee80211_node *ni;
517 	struct mbuf *m;
518 
519 	for (;;) {
520 		IF_DEQUEUE(ifq, m);
521 		if (m == NULL)
522 			break;
523 
524 		ni = M_GETCTX(m, struct ieee80211_node *);
525 		KASSERT(ni != NULL);
526 		ieee80211_free_node(ni);
527 		M_SETCTX(m, NULL);
528 
529 		m_freem(m);
530 	}
531 }
532 
533 void
if_printf(struct ifnet * ifp,const char * fmt,...)534 if_printf(struct ifnet *ifp, const char *fmt, ...)
535 {
536 	va_list ap;
537 	va_start(ap, fmt);
538 
539 	printf("%s: ", ifp->if_xname);
540 	vprintf(fmt, ap);
541 
542 	va_end(ap);
543 	return;
544 }
545 
546 /*
547  * Allocate and setup a management frame of the specified
548  * size.  We return the mbuf and a pointer to the start
549  * of the contiguous data area that's been reserved based
550  * on the packet length.  The data area is forced to 32-bit
551  * alignment and the buffer length to a multiple of 4 bytes.
552  * This is done mainly so beacon frames (that require this)
553  * can use this interface too.
554  */
555 struct mbuf *
ieee80211_getmgtframe(u_int8_t ** frm,u_int pktlen)556 ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen)
557 {
558 	struct mbuf *m;
559 	u_int len;
560 
561 	/*
562 	 * NB: we know the mbuf routines will align the data area
563 	 *     so we don't need to do anything special.
564 	 */
565 	/* XXX 4-address frame? */
566 	len = roundup(sizeof(struct ieee80211_frame) + pktlen, 4);
567 	IASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
568 
569 	if (len <= MHLEN) {
570 		m = m_gethdr(M_NOWAIT, MT_HEADER);
571 		/*
572 		 * Align the data in case additional headers are added.
573 		 * This should only happen when a WEP header is added
574 		 * which only happens for shared key authentication mgt
575 		 * frames which all fit in MHLEN.
576 		 */
577 		if (m != NULL)
578 			m_align(m, len);
579 	} else {
580 		m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR);
581 	}
582 
583 	if (m != NULL) {
584 		m->m_data += sizeof(struct ieee80211_frame);
585 		*frm = m->m_data;
586 		IASSERT((uintptr_t)*frm % 4 == 0, ("bad beacon boundary"));
587 	}
588 
589 	return m;
590 }
591 
592 void
get_random_bytes(void * p,size_t n)593 get_random_bytes(void *p, size_t n)
594 {
595 	cprng_fast(p, n);
596 }
597 
598 void
ieee80211_notify_node_join(struct ieee80211com * ic,struct ieee80211_node * ni,int newassoc)599 ieee80211_notify_node_join(struct ieee80211com *ic, struct ieee80211_node *ni,
600     int newassoc)
601 {
602 	struct ifnet *ifp = ic->ic_ifp;
603 	struct ieee80211_join_event iev;
604 
605 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "%snode %s join\n",
606 	    (ni == ic->ic_bss) ? "bss " : "",
607 	    ether_sprintf(ni->ni_macaddr));
608 
609 	memset(&iev, 0, sizeof(iev));
610 	if (ni == ic->ic_bss) {
611 		IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_bssid);
612 		rt_ieee80211msg(ifp, newassoc ?
613 		    RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC,
614 		    &iev, sizeof(iev));
615 		if_link_state_change(ifp, LINK_STATE_UP);
616 	} else {
617 		IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr);
618 		rt_ieee80211msg(ifp, newassoc ?
619 		    RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN,
620 		    &iev, sizeof(iev));
621 	}
622 }
623 
624 void
ieee80211_notify_node_leave(struct ieee80211com * ic,struct ieee80211_node * ni)625 ieee80211_notify_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
626 {
627 	struct ifnet *ifp = ic->ic_ifp;
628 	struct ieee80211_leave_event iev;
629 
630 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "%snode %s leave\n",
631 	    (ni == ic->ic_bss) ? "bss " : "",
632 	    ether_sprintf(ni->ni_macaddr));
633 
634 	if (ni == ic->ic_bss) {
635 		rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0);
636 		if_link_state_change(ifp, LINK_STATE_DOWN);
637 	} else {
638 		/* fire off wireless event station leaving */
639 		memset(&iev, 0, sizeof(iev));
640 		IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr);
641 		rt_ieee80211msg(ifp, RTM_IEEE80211_LEAVE, &iev, sizeof(iev));
642 	}
643 }
644 
645 void
ieee80211_notify_scan_done(struct ieee80211com * ic)646 ieee80211_notify_scan_done(struct ieee80211com *ic)
647 {
648 	struct ifnet *ifp = ic->ic_ifp;
649 
650 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
651 		"%s", "notify scan done\n");
652 
653 	/* dispatch wireless event indicating scan completed */
654 	rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0);
655 }
656 
657 void
ieee80211_notify_replay_failure(struct ieee80211com * ic,const struct ieee80211_frame * wh,const struct ieee80211_key * k,u_int64_t rsc)658 ieee80211_notify_replay_failure(struct ieee80211com *ic,
659 	const struct ieee80211_frame *wh, const struct ieee80211_key *k,
660 	u_int64_t rsc)
661 {
662 	struct ifnet *ifp = ic->ic_ifp;
663 
664 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
665 	    "[%s] %s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>\n",
666 	    ether_sprintf(wh->i_addr2), k->wk_cipher->ic_name,
667 	    (intmax_t) rsc, (intmax_t) k->wk_keyrsc,
668 	    k->wk_keyix, k->wk_rxkeyix);
669 
670 	if (ifp != NULL) {		/* NB: for cipher test modules */
671 		struct ieee80211_replay_event iev;
672 
673 		IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
674 		IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
675 		iev.iev_cipher = k->wk_cipher->ic_cipher;
676 		if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE)
677 			iev.iev_keyix = k->wk_rxkeyix;
678 		else
679 			iev.iev_keyix = k->wk_keyix;
680 		iev.iev_keyrsc = k->wk_keyrsc;
681 		iev.iev_rsc = rsc;
682 		rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev));
683 	}
684 }
685 
686 void
ieee80211_notify_michael_failure(struct ieee80211com * ic,const struct ieee80211_frame * wh,u_int keyix)687 ieee80211_notify_michael_failure(struct ieee80211com *ic,
688 	const struct ieee80211_frame *wh, u_int keyix)
689 {
690 	struct ifnet *ifp = ic->ic_ifp;
691 
692 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
693 	    "[%s] michael MIC verification failed <keyix %u>\n",
694 	    ether_sprintf(wh->i_addr2), keyix);
695 	ic->ic_stats.is_rx_tkipmic++;
696 
697 	if (ifp != NULL) {		/* NB: for cipher test modules */
698 		struct ieee80211_michael_event iev;
699 
700 		IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
701 		IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
702 		iev.iev_cipher = IEEE80211_CIPHER_TKIP;
703 		iev.iev_keyix = keyix;
704 		rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev));
705 	}
706 }
707 
708 void
ieee80211_load_module(const char * modname)709 ieee80211_load_module(const char *modname)
710 {
711 #ifdef notyet
712 	struct thread *td = curthread;
713 
714 	if (suser(td) == 0 && securelevel_gt(td->td_ucred, 0) == 0) {
715 		mtx_lock(&Giant);
716 		(void) linker_load_module(modname, NULL, NULL, NULL, NULL);
717 		mtx_unlock(&Giant);
718 	}
719 #else
720 	printf("%s: load the %s module by hand for now.\n", __func__, modname);
721 #endif
722 }
723 
724 /* -------------------------------------------------------------------------- */
725 
726 /*
727  * Append the specified data to the indicated mbuf chain,
728  * Extend the mbuf chain if the new data does not fit in
729  * existing space.
730  *
731  * Return 1 if able to complete the job; otherwise 0.
732  */
733 int
m_append(struct mbuf * m0,int len,const void * cpv)734 m_append(struct mbuf *m0, int len, const void *cpv)
735 {
736 	struct mbuf *m, *n;
737 	int remainder, space;
738 	const char *cp = cpv;
739 
740 	KASSERT(len != M_COPYALL);
741 	for (m = m0; m->m_next != NULL; m = m->m_next)
742 		continue;
743 	remainder = len;
744 	space = M_TRAILINGSPACE(m);
745 	if (space > 0) {
746 		/*
747 		 * Copy into available space.
748 		 */
749 		if (space > remainder)
750 			space = remainder;
751 		memmove(mtod(m, char *) + m->m_len, cp, space);
752 		m->m_len += space;
753 		cp = cp + space, remainder -= space;
754 	}
755 	while (remainder > 0) {
756 		/*
757 		 * Allocate a new mbuf; could check space
758 		 * and allocate a cluster instead.
759 		 */
760 		n = m_get(M_DONTWAIT, m->m_type);
761 		if (n == NULL)
762 			break;
763 		n->m_len = uimin(MLEN, remainder);
764 		memmove(mtod(n, void *), cp, n->m_len);
765 		cp += n->m_len, remainder -= n->m_len;
766 		m->m_next = n;
767 		m = n;
768 	}
769 	if (m0->m_flags & M_PKTHDR)
770 		m0->m_pkthdr.len += len - remainder;
771 	return (remainder == 0);
772 }
773