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