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