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