ieee80211_netbsd.c revision 1.31.2.5 1 /* $NetBSD: ieee80211_netbsd.c,v 1.31.2.5 2018/07/28 00:49:43 phil Exp $ */
2
3 /*-
4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5 *
6 * Copyright (c) 2003-2009 Sam Leffler, Errno Consulting
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
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 /* __FBSDID("$FreeBSD$"); */
32 __KERNEL_RCSID(0, "$NetBSD: ieee80211_netbsd.c,v 1.31.2.5 2018/07/28 00:49:43 phil Exp $");
33
34 /*
35 * IEEE 802.11 support (NetBSD-specific code)
36 */
37
38 #include "opt_wlan.h"
39
40 #include <sys/atomic.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/module.h>
47 #include <sys/proc.h>
48 #include <sys/sysctl.h>
49 #include <sys/syslog.h>
50
51 #include <sys/socket.h>
52
53 #include <net/bpf.h>
54 #include <net/if.h>
55 #include <net/if_dl.h>
56 #include <net/if_ether.h>
57 #include <net/if_media.h>
58 #include <net/if_types.h>
59 #include <net/route.h>
60
61 #include <net80211/ieee80211_var.h>
62 #include <net80211/ieee80211_input.h>
63
64 static const struct sysctlnode *
65 ieee80211_sysctl_treetop(struct sysctllog **log);
66 static void ieee80211_sysctl_setup(void);
67
68 /* NNN in .h file? */
69 #define SYSCTL_HANDLER_ARGS SYSCTLFN_ARGS
70
71 #ifdef IEEE80211_DEBUG
72 static int ieee80211_debug = 0;
73 #endif
74
75 #ifdef notyet
76 static struct if_clone *wlan_cloner;
77 #endif
78 /* notyet */
79
80 static const char wlanname[] = "wlan";
81
82 int
83 ieee80211_init0(void)
84 {
85 ieee80211_sysctl_setup();
86 return 0;
87 }
88
89 /*
90 * "taskqueue" support
91 */
92 void ieee80211_runwork(struct work *work2do, void *arg)
93 {
94 struct task *work_task = (struct task *) work2do;
95 printf ("runwork called! work2do is 0x%lx, t_work.wk_dummy is 0x%lx\n",
96 (long) work2do, (long)work_task->t_work.wk_dummy);
97 printf (" runwork: t_func is 0x%lx, t_arg is 0x%lx\n",
98 (long)work_task->t_func, (long)work_task->t_arg);
99
100 mutex_enter(&work_task->t_mutex);
101 work_task->t_onqueue = 0;
102 mutex_exit(&work_task->t_mutex);
103
104 work_task->t_func(work_task->t_arg, 0);
105 }
106
107 void taskqueue_enqueue(struct workqueue *wq, struct task *task_item)
108 {
109 printf ("taskqueue_enqueue called\n");
110 mutex_enter(&task_item->t_mutex);
111 if (!task_item->t_onqueue) {
112 printf (" taskqueue_enqueue adding item to workqueue\n");
113 workqueue_enqueue(wq, &task_item->t_work, NULL);
114 task_item->t_onqueue = 1;
115 }
116 mutex_exit(&task_item->t_mutex);
117 }
118
119 void taskqueue_drain(struct workqueue *wq, struct task *task_item)
120 {
121 printf ("taskqueue_drain called\n");
122 workqueue_wait(wq, &task_item->t_work);
123 }
124
125
126 static __unused int
127 wlan_clone_create(struct if_clone *ifc, int unit, void * params)
128 {
129 struct ieee80211_clone_params cp;
130 struct ieee80211vap *vap;
131 struct ieee80211com *ic;
132 int error;
133
134 error = copyin(params, &cp, sizeof(cp));
135 if (error)
136 return error;
137 ic = ieee80211_find_com(cp.icp_parent);
138 if (ic == NULL)
139 return ENXIO;
140 if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) {
141 ic_printf(ic, "%s: invalid opmode %d\n", __func__,
142 cp.icp_opmode);
143 return EINVAL;
144 }
145 if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) {
146 ic_printf(ic, "%s mode not supported\n",
147 ieee80211_opmode_name[cp.icp_opmode]);
148 return EOPNOTSUPP;
149 }
150 if ((cp.icp_flags & IEEE80211_CLONE_TDMA) &&
151 #ifdef IEEE80211_SUPPORT_TDMA
152 (ic->ic_caps & IEEE80211_C_TDMA) == 0
153 #else
154 (1)
155 #endif
156 ) {
157 ic_printf(ic, "TDMA not supported\n");
158 return EOPNOTSUPP;
159 }
160 vap = ic->ic_vap_create(ic, wlanname, unit,
161 cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
162 cp.icp_flags & IEEE80211_CLONE_MACADDR ?
163 cp.icp_macaddr : ic->ic_macaddr);
164
165 return (vap == NULL ? EIO : 0);
166 }
167
168 static __unused void
169 wlan_clone_destroy(struct ifnet *ifp)
170 {
171 struct ieee80211vap *vap = ifp->if_softc;
172 struct ieee80211com *ic = vap->iv_ic;
173
174 ic->ic_vap_delete(vap);
175 }
176
177 void
178 ieee80211_vap_destroy(struct ieee80211vap *vap)
179 {
180 #ifdef notyet
181 CURVNET_SET(vap->iv_ifp->if_vnet);
182 if_clone_destroyif(wlan_cloner, vap->iv_ifp);
183 CURVNET_RESTORE();
184 #else
185 printf ("vap_destroy called ... what next?\n");
186 #endif
187 }
188
189 #ifdef notyet
190 int
191 ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS)
192 {
193 int msecs = ticks_to_msecs(*(int *)arg1);
194 int error, t;
195
196 error = sysctl_handle_int(oidp, &msecs, 0, req);
197 if (error || !req->newptr)
198 return error;
199 t = msecs_to_ticks(msecs);
200 *(int *)arg1 = (t < 1) ? 1 : t;
201 return 0;
202 }
203
204 static int
205 ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS)
206 {
207 int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT;
208 int error;
209
210 error = sysctl_handle_int(oidp, &inact, 0, req);
211 if (error || !req->newptr)
212 return error;
213 *(int *)arg1 = inact / IEEE80211_INACT_WAIT;
214 return 0;
215 }
216 #endif
217
218 static int
219 ieee80211_sysctl_parent(SYSCTLFN_ARGS)
220 {
221 struct ieee80211vap *vap;
222 char pname[IFNAMSIZ];
223 struct sysctlnode node;
224
225 node = *rnode;
226 vap = node.sysctl_data;
227 strlcpy(pname, vap->iv_ifp->if_xname, IFNAMSIZ);
228 node.sysctl_data = pname;
229 return sysctl_lookup(SYSCTLFN_CALL(&node));
230 }
231
232 #ifdef notyet
233 static int
234 ieee80211_sysctl_radar(SYSCTL_HANDLER_ARGS)
235 {
236 struct ieee80211com *ic = arg1;
237 int t = 0, error;
238
239 error = sysctl_handle_int(oidp, &t, 0, req);
240 if (error || !req->newptr)
241 return error;
242 IEEE80211_LOCK(ic);
243 ieee80211_dfs_notify_radar(ic, ic->ic_curchan);
244 IEEE80211_UNLOCK(ic);
245 return 0;
246 }
247
248 /*
249 * For now, just restart everything.
250 *
251 * Later on, it'd be nice to have a separate VAP restart to
252 * full-device restart.
253 */
254 static int
255 ieee80211_sysctl_vap_restart(SYSCTL_HANDLER_ARGS)
256 {
257 struct ieee80211vap *vap = arg1;
258 int t = 0, error;
259
260 error = sysctl_handle_int(oidp, &t, 0, req);
261 if (error || !req->newptr)
262 return error;
263
264 ieee80211_restart_all(vap->iv_ic);
265 return 0;
266 }
267 #endif /* notyet */
268
269 void
270 ieee80211_sysctl_attach(struct ieee80211com *ic)
271 {
272 }
273
274 void
275 ieee80211_sysctl_detach(struct ieee80211com *ic)
276 {
277 }
278
279 /*
280 * Setup sysctl(3) MIB, net.ieee80211.*
281 *
282 * TBD condition CTLFLAG_PERMANENT on being a module or not
283 */
284 static struct sysctllog *ieee80211_sysctllog;
285 static void
286 ieee80211_sysctl_setup(void)
287 {
288 int rc;
289 const struct sysctlnode *rnode;
290
291 if ((rnode = ieee80211_sysctl_treetop(&ieee80211_sysctllog)) == NULL)
292 return;
293
294 #ifdef notyet
295 if ((rc = sysctl_createv(&ieee80211_sysctllog, 0, &rnode, NULL,
296 CTLFLAG_PERMANENT, CTLTYPE_NODE, "nodes", "client/peer stations",
297 ieee80211_sysctl_node, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
298 goto err;
299 #endif
300
301 #ifdef IEEE80211_DEBUG
302 /* control debugging printfs */
303 if ((rc = sysctl_createv(&ieee80211_sysctllog, 0, &rnode, NULL,
304 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
305 "debug", SYSCTL_DESCR("control debugging printfs"),
306 NULL, 0, &ieee80211_debug, 0, CTL_CREATE, CTL_EOL)) != 0)
307 goto err;
308 #endif
309
310 #ifdef notyet
311 ieee80211_rssadapt_sysctl_setup(&ieee80211_sysctllog);
312 #endif
313
314 return;
315 err:
316 printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
317 }
318
319 /*
320 * Create or get top of sysctl tree net.link.ieee80211.
321 */
322 static const struct sysctlnode *
323 ieee80211_sysctl_treetop(struct sysctllog **log)
324 {
325 int rc;
326 const struct sysctlnode *rnode;
327
328 if ((rc = sysctl_createv(log, 0, NULL, &rnode,
329 CTLFLAG_PERMANENT, CTLTYPE_NODE, "link",
330 "link-layer statistics and controls",
331 NULL, 0, NULL, 0, CTL_NET, PF_LINK, CTL_EOL)) != 0)
332 goto err;
333
334 if ((rc = sysctl_createv(log, 0, &rnode, &rnode,
335 CTLFLAG_PERMANENT, CTLTYPE_NODE, "ieee80211",
336 "IEEE 802.11 WLAN statistics and controls",
337 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
338 goto err;
339
340 return rnode;
341 err:
342 printf("%s: sysctl_createv failed, rc = %d\n", __func__, rc);
343 return NULL;
344 }
345
346 void
347 ieee80211_sysctl_vattach(struct ieee80211vap *vap)
348 {
349 int rc;
350 const struct sysctlnode *cnode, *rnode;
351 char num[sizeof("vap") + 14]; /* sufficient for 32 bits */
352
353 if ((rnode = ieee80211_sysctl_treetop(NULL)) == NULL)
354 return;
355
356 snprintf(num, sizeof(num), "vap%u", vap->iv_ifp->if_index);
357
358 if ((rc = sysctl_createv(&vap->iv_sysctllog, 0, &rnode, &rnode,
359 CTLFLAG_PERMANENT, CTLTYPE_NODE, num, SYSCTL_DESCR("virtual AP"),
360 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
361 goto err;
362
363 /* control debugging printfs */
364 if ((rc = sysctl_createv(&vap->iv_sysctllog, 0, &rnode, &cnode,
365 CTLFLAG_PERMANENT|CTLFLAG_READONLY, CTLTYPE_STRING,
366 "parent", SYSCTL_DESCR("parent device"),
367 ieee80211_sysctl_parent, 0, (void *)vap, IFNAMSIZ,
368 CTL_CREATE, CTL_EOL)) != 0)
369 goto err;
370
371
372 #ifdef notyet
373 struct ifnet *ifp = vap->iv_ifp;
374 struct sysctl_ctx_list *ctx;
375 struct sysctl_oid *oid;
376 char num[14]; /* sufficient for 32 bits */
377
378 ctx = (struct sysctl_ctx_list *) IEEE80211_MALLOC(sizeof(struct sysctl_ctx_list),
379 M_DEVBUF, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
380 if (ctx == NULL) {
381 if_printf(ifp, "%s: cannot allocate sysctl context!\n",
382 __func__);
383 return;
384 }
385 sysctl_ctx_init(ctx);
386 snprintf(num, sizeof(num), "%u", ifp->if_dunit);
387 oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan),
388 OID_AUTO, num, CTLFLAG_RD, NULL, "");
389 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
390 "%parent", CTLTYPE_STRING | CTLFLAG_RD, vap->iv_ic, 0,
391 ieee80211_sysctl_parent, "A", "parent device");
392 SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
393 "driver_caps", CTLFLAG_RW, &vap->iv_caps, 0,
394 "driver capabilities");
395 #ifdef IEEE80211_DEBUG
396 vap->iv_debug = ieee80211_debug;
397 SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
398 "debug", CTLFLAG_RW, &vap->iv_debug, 0,
399 "control debugging printfs");
400 #endif
401 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
402 "bmiss_max", CTLFLAG_RW, &vap->iv_bmiss_max, 0,
403 "consecutive beacon misses before scanning");
404 /* XXX inherit from tunables */
405 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
406 "inact_run", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_run, 0,
407 ieee80211_sysctl_inact, "I",
408 "station inactivity timeout (sec)");
409 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
410 "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_probe, 0,
411 ieee80211_sysctl_inact, "I",
412 "station inactivity probe timeout (sec)");
413 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
414 "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_auth, 0,
415 ieee80211_sysctl_inact, "I",
416 "station authentication timeout (sec)");
417 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
418 "inact_init", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_init, 0,
419 ieee80211_sysctl_inact, "I",
420 "station initial state timeout (sec)");
421 if (vap->iv_htcaps & IEEE80211_HTC_HT) {
422 SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
423 "ampdu_mintraffic_bk", CTLFLAG_RW,
424 &vap->iv_ampdu_mintraffic[WME_AC_BK], 0,
425 "BK traffic tx aggr threshold (pps)");
426 SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
427 "ampdu_mintraffic_be", CTLFLAG_RW,
428 &vap->iv_ampdu_mintraffic[WME_AC_BE], 0,
429 "BE traffic tx aggr threshold (pps)");
430 SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
431 "ampdu_mintraffic_vo", CTLFLAG_RW,
432 &vap->iv_ampdu_mintraffic[WME_AC_VO], 0,
433 "VO traffic tx aggr threshold (pps)");
434 SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
435 "ampdu_mintraffic_vi", CTLFLAG_RW,
436 &vap->iv_ampdu_mintraffic[WME_AC_VI], 0,
437 "VI traffic tx aggr threshold (pps)");
438 }
439
440 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
441 "force_restart", CTLTYPE_INT | CTLFLAG_RW, vap, 0,
442 ieee80211_sysctl_vap_restart, "I",
443 "force a VAP restart");
444
445 if (vap->iv_caps & IEEE80211_C_DFS) {
446 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
447 "radar", CTLTYPE_INT | CTLFLAG_RW, vap->iv_ic, 0,
448 ieee80211_sysctl_radar, "I", "simulate radar event");
449 }
450 vap->iv_sysctl = ctx;
451 vap->iv_oid = oid;
452 #endif
453 return;
454 err:
455 printf("%s: sysctl_createv failed, rc = %d\n", __func__, rc);
456 }
457
458 void
459 ieee80211_sysctl_vdetach(struct ieee80211vap *vap)
460 {
461 #ifdef notyet
462 if (vap->iv_sysctl != NULL) {
463 sysctl_ctx_free(vap->iv_sysctl);
464 IEEE80211_FREE(vap->iv_sysctl, M_DEVBUF);
465 vap->iv_sysctl = NULL;
466 }
467 #endif
468 }
469
470
471 int
472 ieee80211_node_dectestref(struct ieee80211_node *ni)
473 {
474 /* XXX need equivalent of atomic_dec_and_test */
475 atomic_subtract_int(&ni->ni_refcnt, 1);
476 return atomic_cas_uint(&ni->ni_refcnt, 0, 1) == 0;
477 }
478
479 void
480 ieee80211_drain_ifq(struct ifqueue *ifq)
481 {
482 struct ieee80211_node *ni;
483 struct mbuf *m;
484
485 for (;;) {
486 IF_DEQUEUE(ifq, m);
487 if (m == NULL)
488 break;
489
490 ni = (struct ieee80211_node *)m_get_rcvif_NOMPSAFE(m);
491 FBSDKASSERT(ni != NULL, ("frame w/o node"));
492 ieee80211_free_node(ni);
493 ieee80211_free_mbuf(m);
494 }
495 }
496
497 void
498 ieee80211_flush_ifq(struct ifqueue *ifq, struct ieee80211vap *vap)
499 {
500 struct ieee80211_node *ni;
501 struct mbuf *m, **mprev;
502
503 IFQ_LOCK(ifq);
504 mprev = &ifq->ifq_head;
505 while ((m = *mprev) != NULL) {
506 ni = (struct ieee80211_node *)m_get_rcvif_NOMPSAFE(m);
507 if (ni != NULL && ni->ni_vap == vap) {
508 *mprev = m->m_nextpkt; /* remove from list */
509 ifq->ifq_len--;
510
511 ieee80211_free_node(ni); /* reclaim ref */
512 ieee80211_free_mbuf(m);
513 } else
514 mprev = &m->m_nextpkt;
515 }
516 /* recalculate tail ptr */
517 m = ifq->ifq_head;
518 for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt)
519 ;
520 ifq->ifq_tail = m;
521 IFQ_UNLOCK(ifq);
522 }
523
524 /*
525 * As above, for mbufs allocated with m_gethdr/MGETHDR
526 * or initialized by M_COPY_PKTHDR.
527 */
528 #define MC_ALIGN(m, len) \
529 do { \
530 (m)->m_data += rounddown2(MCLBYTES - (len), sizeof(long)); \
531 } while (/* CONSTCOND */ 0)
532
533 /*
534 * Allocate and setup a management frame of the specified
535 * size. We return the mbuf and a pointer to the start
536 * of the contiguous data area that's been reserved based
537 * on the packet length. The data area is forced to 32-bit
538 * alignment and the buffer length to a multiple of 4 bytes.
539 * This is done mainly so beacon frames (that require this)
540 * can use this interface too.
541 */
542 struct mbuf *
543 ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen)
544 {
545 struct mbuf *m;
546 u_int len;
547
548 /*
549 * NB: we know the mbuf routines will align the data area
550 * so we don't need to do anything special.
551 */
552 len = roundup2(headroom + pktlen, 4);
553 FBSDKASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
554 if (len < MINCLSIZE) {
555 m = m_gethdr(M_NOWAIT, MT_DATA);
556 /*
557 * Align the data in case additional headers are added.
558 * This should only happen when a WEP header is added
559 * which only happens for shared key authentication mgt
560 * frames which all fit in MHLEN.
561 */
562 if (m != NULL)
563 MH_ALIGN(m, len);
564 } else {
565 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
566 if (m != NULL)
567 MC_ALIGN(m, len);
568 }
569 if (m != NULL) {
570 m->m_data += headroom;
571 *frm = m->m_data;
572 }
573 return m;
574 }
575
576 #ifndef __NO_STRICT_ALIGNMENT
577 /*
578 * Re-align the payload in the mbuf. This is mainly used (right now)
579 * to handle IP header alignment requirements on certain architectures.
580 */
581 struct mbuf *
582 ieee80211_realign(struct ieee80211vap *vap, struct mbuf *m, size_t align)
583 {
584 int pktlen, space;
585 struct mbuf *n;
586
587 pktlen = m->m_pkthdr.len;
588 space = pktlen + align;
589 if (space < MINCLSIZE)
590 n = m_gethdr(M_NOWAIT, MT_DATA);
591 else {
592 n = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
593 space <= MCLBYTES ? MCLBYTES :
594 #if MJUMPAGESIZE != MCLBYTES
595 space <= MJUMPAGESIZE ? MJUMPAGESIZE :
596 #endif
597 space <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES);
598 }
599 if (__predict_true(n != NULL)) {
600 m_move_pkthdr(n, m);
601 n->m_data = (caddr_t)(ALIGN(n->m_data + align) - align);
602 m_copydata(m, 0, pktlen, mtod(n, caddr_t));
603 n->m_len = pktlen;
604 } else {
605 IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
606 mtod(m, const struct ieee80211_frame *), NULL,
607 "%s", "no mbuf to realign");
608 vap->iv_stats.is_rx_badalign++;
609 }
610 m_freem(m);
611 return n;
612 }
613 #endif /* !__NO_STRICT_ALIGNMENT */
614
615 int
616 ieee80211_add_callback(struct mbuf *m,
617 void (*func)(struct ieee80211_node *, void *, int), void *arg)
618 {
619 struct m_tag *mtag;
620 struct ieee80211_cb *cb;
621
622 mtag = m_tag_get(/*MTAG_ABI_NET80211*/ NET80211_TAG_CALLBACK,
623 sizeof(struct ieee80211_cb), M_NOWAIT);
624 if (mtag == NULL)
625 return 0;
626
627 cb = (struct ieee80211_cb *)(mtag+1);
628 cb->func = func;
629 cb->arg = arg;
630 m_tag_prepend(m, mtag);
631 m->m_flags |= M_TXCB;
632 return 1;
633 }
634
635 int
636 ieee80211_add_xmit_params(struct mbuf *m,
637 const struct ieee80211_bpf_params *params)
638 {
639 struct m_tag *mtag;
640 struct ieee80211_tx_params *tx;
641
642 mtag = m_tag_get(/*MTAG_ABI_NET80211*/ NET80211_TAG_XMIT_PARAMS,
643 sizeof(struct ieee80211_tx_params), M_NOWAIT);
644 if (mtag == NULL)
645 return (0);
646
647 tx = (struct ieee80211_tx_params *)(mtag+1);
648 memcpy(&tx->params, params, sizeof(struct ieee80211_bpf_params));
649 m_tag_prepend(m, mtag);
650 return (1);
651 }
652
653 int
654 ieee80211_get_xmit_params(struct mbuf *m,
655 struct ieee80211_bpf_params *params)
656 {
657 struct m_tag *mtag;
658 struct ieee80211_tx_params *tx;
659
660 mtag = m_tag_find(m, /*MTAG_ABI_NET80211,*/ NET80211_TAG_XMIT_PARAMS,
661 NULL);
662 if (mtag == NULL)
663 return (-1);
664 tx = (struct ieee80211_tx_params *)(mtag + 1);
665 memcpy(params, &tx->params, sizeof(struct ieee80211_bpf_params));
666 return (0);
667 }
668
669 void
670 ieee80211_process_callback(struct ieee80211_node *ni,
671 struct mbuf *m, int status)
672 {
673 struct m_tag *mtag;
674
675 mtag = m_tag_find(m, /*MTAG_ABI_NET80211,*/ NET80211_TAG_CALLBACK, NULL);
676 if (mtag != NULL) {
677 struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1);
678 cb->func(ni, cb->arg, status);
679 }
680 }
681
682 /*
683 * Add RX parameters to the given mbuf.
684 *
685 * Returns 1 if OK, 0 on error.
686 */
687 int
688 ieee80211_add_rx_params(struct mbuf *m, const struct ieee80211_rx_stats *rxs)
689 {
690 struct m_tag *mtag;
691 struct ieee80211_rx_params *rx;
692
693 mtag = m_tag_get(/*MTAG_ABI_NET80211,*/ NET80211_TAG_RECV_PARAMS,
694 sizeof(struct ieee80211_rx_stats), M_NOWAIT);
695 if (mtag == NULL)
696 return (0);
697
698 rx = (struct ieee80211_rx_params *)(mtag + 1);
699 memcpy(&rx->params, rxs, sizeof(*rxs));
700 m_tag_prepend(m, mtag);
701 return (1);
702 }
703
704 int
705 ieee80211_get_rx_params(struct mbuf *m, struct ieee80211_rx_stats *rxs)
706 {
707 struct m_tag *mtag;
708 struct ieee80211_rx_params *rx;
709
710 mtag = m_tag_find(m, /*MTAG_ABI_NET80211,*/ NET80211_TAG_RECV_PARAMS,
711 NULL);
712 if (mtag == NULL)
713 return (-1);
714 rx = (struct ieee80211_rx_params *)(mtag + 1);
715 memcpy(rxs, &rx->params, sizeof(*rxs));
716 return (0);
717 }
718
719 const struct ieee80211_rx_stats *
720 ieee80211_get_rx_params_ptr(struct mbuf *m)
721 {
722 struct m_tag *mtag;
723 struct ieee80211_rx_params *rx;
724
725 mtag = m_tag_find(m, /*MTAG_ABI_NET80211,*/ NET80211_TAG_RECV_PARAMS,
726 NULL);
727 if (mtag == NULL)
728 return (NULL);
729 rx = (struct ieee80211_rx_params *)(mtag + 1);
730 return (&rx->params);
731 }
732
733
734 /*
735 * Add TOA parameters to the given mbuf.
736 */
737 int
738 ieee80211_add_toa_params(struct mbuf *m, const struct ieee80211_toa_params *p)
739 {
740 struct m_tag *mtag;
741 struct ieee80211_toa_params *rp;
742
743 mtag = m_tag_get(/*MTAG_ABI_NET80211,*/ NET80211_TAG_TOA_PARAMS,
744 sizeof(struct ieee80211_toa_params), M_NOWAIT);
745 if (mtag == NULL)
746 return (0);
747
748 rp = (struct ieee80211_toa_params *)(mtag + 1);
749 memcpy(rp, p, sizeof(*rp));
750 m_tag_prepend(m, mtag);
751 return (1);
752 }
753
754 int
755 ieee80211_get_toa_params(struct mbuf *m, struct ieee80211_toa_params *p)
756 {
757 struct m_tag *mtag;
758 struct ieee80211_toa_params *rp;
759
760 mtag = m_tag_find(m, /*MTAG_ABI_NET80211,*/ NET80211_TAG_TOA_PARAMS,
761 NULL);
762 if (mtag == NULL)
763 return (0);
764 rp = (struct ieee80211_toa_params *)(mtag + 1);
765 if (p != NULL)
766 memcpy(p, rp, sizeof(*p));
767 return (1);
768 }
769
770 /*
771 * Transmit a frame to the parent interface.
772 */
773 int
774 ieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m)
775 {
776 int error;
777 printf ("ieee80211_parent_xmitpkt called\n");
778 /*
779 * Assert the IC TX lock is held - this enforces the
780 * processing -> queuing order is maintained
781 */
782 IEEE80211_TX_LOCK_ASSERT(ic);
783 error = ic->ic_transmit(ic, m);
784 if (error) {
785 struct ieee80211_node *ni;
786
787 ni = (struct ieee80211_node *)m_get_rcvif_NOMPSAFE(m);
788
789 /* XXX number of fragments */
790 if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1);
791 ieee80211_free_node(ni);
792 ieee80211_free_mbuf(m);
793 }
794 return (error);
795 }
796
797 /*
798 * Transmit a frame to the VAP interface.
799 */
800 int
801 ieee80211_vap_xmitpkt(struct ieee80211vap *vap, struct mbuf *m)
802 {
803 struct ifnet *ifp = vap->iv_ifp;
804
805 /*
806 * When transmitting via the VAP, we shouldn't hold
807 * any IC TX lock as the VAP TX path will acquire it.
808 */
809 IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
810
811 return (ifp->if_transmit(ifp, m));
812
813 }
814
815 void
816 get_random_bytes(void *p, size_t n)
817 {
818 uint8_t *dp = p;
819
820 while (n > 0) {
821 uint32_t v = arc4random();
822 size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n;
823 bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n);
824 dp += sizeof(uint32_t), n -= nb;
825 }
826 }
827
828 /*
829 * Helper function for events that pass just a single mac address.
830 */
831 static void
832 notify_macaddr(struct ifnet *ifp, int op, const uint8_t mac[IEEE80211_ADDR_LEN])
833 {
834 struct ieee80211_join_event iev;
835
836 CURVNET_SET(ifp->if_vnet);
837 memset(&iev, 0, sizeof(iev));
838 IEEE80211_ADDR_COPY(iev.iev_addr, mac);
839 rt_ieee80211msg(ifp, op, &iev, sizeof(iev));
840 CURVNET_RESTORE();
841 }
842
843 void
844 ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc)
845 {
846 struct ieee80211vap *vap = ni->ni_vap;
847 struct ifnet *ifp = vap->iv_ifp;
848
849 CURVNET_SET_QUIET(ifp->if_vnet);
850 IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode join",
851 (ni == vap->iv_bss) ? "bss " : "");
852
853 if (ni == vap->iv_bss) {
854 notify_macaddr(ifp, newassoc ?
855 RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, ni->ni_bssid);
856 if_link_state_change(ifp, LINK_STATE_UP);
857 } else {
858 notify_macaddr(ifp, newassoc ?
859 RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, ni->ni_macaddr);
860 }
861 CURVNET_RESTORE();
862 }
863
864 void
865 ieee80211_notify_node_leave(struct ieee80211_node *ni)
866 {
867 struct ieee80211vap *vap = ni->ni_vap;
868 struct ifnet *ifp = vap->iv_ifp;
869
870 CURVNET_SET_QUIET(ifp->if_vnet);
871 IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode leave",
872 (ni == vap->iv_bss) ? "bss " : "");
873
874 if (ni == vap->iv_bss) {
875 rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0);
876 if_link_state_change(ifp, LINK_STATE_DOWN);
877 } else {
878 /* fire off wireless event station leaving */
879 notify_macaddr(ifp, RTM_IEEE80211_LEAVE, ni->ni_macaddr);
880 }
881 CURVNET_RESTORE();
882 }
883
884 void
885 ieee80211_notify_scan_done(struct ieee80211vap *vap)
886 {
887 struct ifnet *ifp = vap->iv_ifp;
888
889 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n", "notify scan done");
890
891 /* dispatch wireless event indicating scan completed */
892 CURVNET_SET(ifp->if_vnet);
893 rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0);
894 CURVNET_RESTORE();
895 }
896
897 void
898 ieee80211_notify_replay_failure(struct ieee80211vap *vap,
899 const struct ieee80211_frame *wh, const struct ieee80211_key *k,
900 u_int64_t rsc, int tid)
901 {
902 struct ifnet *ifp = vap->iv_ifp;
903
904 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
905 "%s replay detected tid %d <rsc %ju, csc %ju, keyix %u rxkeyix %u>",
906 k->wk_cipher->ic_name, tid, (intmax_t) rsc,
907 (intmax_t) k->wk_keyrsc[tid],
908 k->wk_keyix, k->wk_rxkeyix);
909
910 if (ifp != NULL) { /* NB: for cipher test modules */
911 struct ieee80211_replay_event iev;
912
913 IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
914 IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
915 iev.iev_cipher = k->wk_cipher->ic_cipher;
916 if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE)
917 iev.iev_keyix = k->wk_rxkeyix;
918 else
919 iev.iev_keyix = k->wk_keyix;
920 iev.iev_keyrsc = k->wk_keyrsc[tid];
921 iev.iev_rsc = rsc;
922 CURVNET_SET(ifp->if_vnet);
923 rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev));
924 CURVNET_RESTORE();
925 }
926 }
927
928 void
929 ieee80211_notify_michael_failure(struct ieee80211vap *vap,
930 const struct ieee80211_frame *wh, u_int keyix)
931 {
932 struct ifnet *ifp = vap->iv_ifp;
933
934 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
935 "michael MIC verification failed <keyix %u>", keyix);
936 vap->iv_stats.is_rx_tkipmic++;
937
938 if (ifp != NULL) { /* NB: for cipher test modules */
939 struct ieee80211_michael_event iev;
940
941 IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
942 IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
943 iev.iev_cipher = IEEE80211_CIPHER_TKIP;
944 iev.iev_keyix = keyix;
945 CURVNET_SET(ifp->if_vnet);
946 rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev));
947 CURVNET_RESTORE();
948 }
949 }
950
951 void
952 ieee80211_notify_wds_discover(struct ieee80211_node *ni)
953 {
954 struct ieee80211vap *vap = ni->ni_vap;
955 struct ifnet *ifp = vap->iv_ifp;
956
957 notify_macaddr(ifp, RTM_IEEE80211_WDS, ni->ni_macaddr);
958 }
959
960 void
961 ieee80211_notify_csa(struct ieee80211com *ic,
962 const struct ieee80211_channel *c, int mode, int count)
963 {
964 struct ieee80211_csa_event iev;
965 struct ieee80211vap *vap;
966 struct ifnet *ifp;
967
968 memset(&iev, 0, sizeof(iev));
969 iev.iev_flags = c->ic_flags;
970 iev.iev_freq = c->ic_freq;
971 iev.iev_ieee = c->ic_ieee;
972 iev.iev_mode = mode;
973 iev.iev_count = count;
974 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
975 ifp = vap->iv_ifp;
976 CURVNET_SET(ifp->if_vnet);
977 rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev));
978 CURVNET_RESTORE();
979 }
980 }
981
982 void
983 ieee80211_notify_radar(struct ieee80211com *ic,
984 const struct ieee80211_channel *c)
985 {
986 struct ieee80211_radar_event iev;
987 struct ieee80211vap *vap;
988 struct ifnet *ifp;
989
990 memset(&iev, 0, sizeof(iev));
991 iev.iev_flags = c->ic_flags;
992 iev.iev_freq = c->ic_freq;
993 iev.iev_ieee = c->ic_ieee;
994 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
995 ifp = vap->iv_ifp;
996 CURVNET_SET(ifp->if_vnet);
997 rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev));
998 CURVNET_RESTORE();
999 }
1000 }
1001
1002 void
1003 ieee80211_notify_cac(struct ieee80211com *ic,
1004 const struct ieee80211_channel *c, enum ieee80211_notify_cac_event type)
1005 {
1006 struct ieee80211_cac_event iev;
1007 struct ieee80211vap *vap;
1008 struct ifnet *ifp;
1009
1010 memset(&iev, 0, sizeof(iev));
1011 iev.iev_flags = c->ic_flags;
1012 iev.iev_freq = c->ic_freq;
1013 iev.iev_ieee = c->ic_ieee;
1014 iev.iev_type = type;
1015 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
1016 ifp = vap->iv_ifp;
1017 CURVNET_SET(ifp->if_vnet);
1018 rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev));
1019 CURVNET_RESTORE();
1020 }
1021 }
1022
1023 void
1024 ieee80211_notify_node_deauth(struct ieee80211_node *ni)
1025 {
1026 struct ieee80211vap *vap = ni->ni_vap;
1027 struct ifnet *ifp = vap->iv_ifp;
1028
1029 IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node deauth");
1030
1031 notify_macaddr(ifp, RTM_IEEE80211_DEAUTH, ni->ni_macaddr);
1032 }
1033
1034 void
1035 ieee80211_notify_node_auth(struct ieee80211_node *ni)
1036 {
1037 struct ieee80211vap *vap = ni->ni_vap;
1038 struct ifnet *ifp = vap->iv_ifp;
1039
1040 IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node auth");
1041
1042 notify_macaddr(ifp, RTM_IEEE80211_AUTH, ni->ni_macaddr);
1043 }
1044
1045 void
1046 ieee80211_notify_country(struct ieee80211vap *vap,
1047 const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2])
1048 {
1049 struct ifnet *ifp = vap->iv_ifp;
1050 struct ieee80211_country_event iev;
1051
1052 memset(&iev, 0, sizeof(iev));
1053 IEEE80211_ADDR_COPY(iev.iev_addr, bssid);
1054 iev.iev_cc[0] = cc[0];
1055 iev.iev_cc[1] = cc[1];
1056 CURVNET_SET(ifp->if_vnet);
1057 rt_ieee80211msg(ifp, RTM_IEEE80211_COUNTRY, &iev, sizeof(iev));
1058 CURVNET_RESTORE();
1059 }
1060
1061 void
1062 ieee80211_notify_radio(struct ieee80211com *ic, int state)
1063 {
1064 struct ieee80211_radio_event iev;
1065 struct ieee80211vap *vap;
1066 struct ifnet *ifp;
1067
1068 memset(&iev, 0, sizeof(iev));
1069 iev.iev_state = state;
1070 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
1071 ifp = vap->iv_ifp;
1072 CURVNET_SET(ifp->if_vnet);
1073 rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev));
1074 CURVNET_RESTORE();
1075 }
1076 }
1077
1078 #ifdef notyet
1079 void
1080 ieee80211_load_module(const char *modname)
1081 {
1082 struct thread *td = curthread;
1083
1084 if (suser(td) == 0 && securelevel_gt(td->td_ucred, 0) == 0) {
1085 mtx_lock(&Giant);
1086 (void) linker_load_module(modname, NULL, NULL, NULL, NULL);
1087 mtx_unlock(&Giant);
1088 }
1089 }
1090 #endif
1091
1092 #ifdef notyet
1093 static eventhandler_tag wlan_bpfevent;
1094 static eventhandler_tag wlan_ifllevent;
1095
1096 static void
1097 bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach)
1098 {
1099 /* NB: identify vap's by if_init */
1100 if (dlt == DLT_IEEE802_11_RADIO &&
1101 ifp->if_init == ieee80211_init) {
1102 struct ieee80211vap *vap = ifp->if_softc;
1103 /*
1104 * Track bpf radiotap listener state. We mark the vap
1105 * to indicate if any listener is present and the com
1106 * to indicate if any listener exists on any associated
1107 * vap. This flag is used by drivers to prepare radiotap
1108 * state only when needed.
1109 */
1110 if (attach) {
1111 ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF);
1112 if (vap->iv_opmode == IEEE80211_M_MONITOR)
1113 atomic_add_int(&vap->iv_ic->ic_montaps, 1);
1114 } else if (!bpf_peers_present(vap->iv_rawbpf)) {
1115 ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF);
1116 if (vap->iv_opmode == IEEE80211_M_MONITOR)
1117 atomic_subtract_int(&vap->iv_ic->ic_montaps, 1);
1118 }
1119 }
1120 }
1121
1122 /*
1123 * Change MAC address on the vap (if was not started).
1124 */
1125 static void
1126 wlan_iflladdr(void *arg __unused, struct ifnet *ifp)
1127 {
1128 /* NB: identify vap's by if_init */
1129 if (ifp->if_init == ieee80211_init &&
1130 (ifp->if_flags & IFF_UP) == 0) {
1131 struct ieee80211vap *vap = ifp->if_softc;
1132
1133 IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp));
1134 }
1135 }
1136 #endif
1137
1138 void
1139 if_inc_counter(struct ifnet *ifp, ift_counter ifc, int64_t value)
1140 {
1141 switch (ifc) {
1142 case IFCOUNTER_IPACKETS:
1143 ifp->if_data.ifi_ipackets += value;
1144 break;
1145 case IFCOUNTER_IERRORS:
1146 ifp->if_data.ifi_ierrors += value;
1147 break;
1148 case IFCOUNTER_OPACKETS:
1149 ifp->if_data.ifi_opackets += value;
1150 break;
1151 case IFCOUNTER_OERRORS:
1152 ifp->if_data.ifi_oerrors += value;
1153 break;
1154 case IFCOUNTER_COLLISIONS:
1155 ifp->if_data.ifi_collisions += value;
1156 break;
1157 case IFCOUNTER_IBYTES:
1158 ifp->if_data.ifi_ibytes += value;
1159 break;
1160 case IFCOUNTER_OBYTES:
1161 ifp->if_data.ifi_obytes += value;
1162 break;
1163 case IFCOUNTER_IMCASTS:
1164 ifp->if_data.ifi_imcasts += value;
1165 break;
1166 case IFCOUNTER_OMCASTS:
1167 ifp->if_data.ifi_omcasts += value;
1168 break;
1169 case IFCOUNTER_IQDROPS:
1170 ifp->if_data.ifi_iqdrops += value;
1171 break;
1172 case IFCOUNTER_OQDROPS:
1173 /* ifp->if_data.ifi_oqdrops += value; No such field, just ignore it q*/
1174 break;
1175 case IFCOUNTER_NOPROTO:
1176 ifp->if_data.ifi_noproto += value;
1177 break;
1178 default:
1179 panic("if_inc_counter: non-existant counter");
1180 }
1181 }
1182
1183
1184 #ifdef notyet
1185 /*
1186 * Module glue.
1187 *
1188 * NB: the module name is "wlan" for compatibility with NetBSD.
1189 */
1190 static int
1191 wlan_modevent(module_t mod, int type, void *unused)
1192 {
1193 switch (type) {
1194 case MOD_LOAD:
1195 if (bootverbose)
1196 printf("wlan: <802.11 Link Layer>\n");
1197 wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track,
1198 bpf_track, 0, EVENTHANDLER_PRI_ANY);
1199 wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,
1200 wlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
1201 wlan_cloner = if_clone_simple(wlanname, wlan_clone_create,
1202 wlan_clone_destroy, 0);
1203 return 0;
1204 case MOD_UNLOAD:
1205 if_clone_detach(wlan_cloner);
1206 EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
1207 EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent);
1208 return 0;
1209 }
1210 return EINVAL;
1211 }
1212
1213 static moduledata_t wlan_mod = {
1214 wlanname,
1215 wlan_modevent,
1216 0
1217 };
1218 DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
1219 MODULE_VERSION(wlan, 1);
1220 MODULE_DEPEND(wlan, ether, 1, 1, 1);
1221 #endif
1222
1223 #ifdef IEEE80211_ALQ
1224 MODULE_DEPEND(wlan, alq, 1, 1, 1);
1225 #endif /* IEEE80211_ALQ */
1226
1227 /* Missing support for if_printf in NetBSD ... */
1228 int
1229 if_printf(struct ifnet *ifp, const char *fmt, ...)
1230 {
1231 char if_fmt[256];
1232 va_list ap;
1233
1234 snprintf(if_fmt, sizeof(if_fmt), "%s: %s", ifp->if_xname, fmt);
1235 va_start(ap, fmt);
1236 vlog(LOG_INFO, if_fmt, ap);
1237 va_end(ap);
1238 return (0);
1239 }
1240
1241 /*
1242 * Set the m_data pointer of a newly-allocated mbuf
1243 * to place an object of the specified size at the
1244 * end of the mbuf, longword aligned.
1245 */
1246 void
1247 m_align(struct mbuf *m, int len)
1248 {
1249 int adjust;
1250
1251 KASSERT(len != M_COPYALL);
1252
1253 if (m->m_flags & M_EXT)
1254 adjust = m->m_ext.ext_size - len;
1255 else if (m->m_flags & M_PKTHDR)
1256 adjust = MHLEN - len;
1257 else
1258 adjust = MLEN - len;
1259 m->m_data += adjust &~ (sizeof(long)-1);
1260 }
1261
1262 /*
1263 * Append the specified data to the indicated mbuf chain,
1264 * Extend the mbuf chain if the new data does not fit in
1265 * existing space.
1266 *
1267 * Return 1 if able to complete the job; otherwise 0.
1268 */
1269 int
1270 m_append(struct mbuf *m0, int len, const void *cpv)
1271 {
1272 struct mbuf *m, *n;
1273 int remainder, space;
1274 const char *cp = cpv;
1275
1276 KASSERT(len != M_COPYALL);
1277 for (m = m0; m->m_next != NULL; m = m->m_next)
1278 continue;
1279 remainder = len;
1280 space = M_TRAILINGSPACE(m);
1281 if (space > 0) {
1282 /*
1283 * Copy into available space.
1284 */
1285 if (space > remainder)
1286 space = remainder;
1287 memmove(mtod(m, char *) + m->m_len, cp, space);
1288 m->m_len += space;
1289 cp = cp + space, remainder -= space;
1290 }
1291 while (remainder > 0) {
1292 /*
1293 * Allocate a new mbuf; could check space
1294 * and allocate a cluster instead.
1295 */
1296 n = m_get(M_DONTWAIT, m->m_type);
1297 if (n == NULL)
1298 break;
1299 n->m_len = min(MLEN, remainder);
1300 memmove(mtod(n, void *), cp, n->m_len);
1301 cp += n->m_len, remainder -= n->m_len;
1302 m->m_next = n;
1303 m = n;
1304 }
1305 if (m0->m_flags & M_PKTHDR)
1306 m0->m_pkthdr.len += len - remainder;
1307 return (remainder == 0);
1308 }
1309
1310 /*
1311 * Create a writable copy of the mbuf chain. While doing this
1312 * we compact the chain with a goal of producing a chain with
1313 * at most two mbufs. The second mbuf in this chain is likely
1314 * to be a cluster. The primary purpose of this work is to create
1315 * a writable packet for encryption, compression, etc. The
1316 * secondary goal is to linearize the data so the data can be
1317 * passed to crypto hardware in the most efficient manner possible.
1318 */
1319 struct mbuf *
1320 m_unshare(struct mbuf *m0, int how)
1321 {
1322 struct mbuf *m, *mprev;
1323 struct mbuf *n, *mfirst, *mlast;
1324 int len, off;
1325
1326 mprev = NULL;
1327 for (m = m0; m != NULL; m = mprev->m_next) {
1328 /*
1329 * Regular mbufs are ignored unless there's a cluster
1330 * in front of it that we can use to coalesce. We do
1331 * the latter mainly so later clusters can be coalesced
1332 * also w/o having to handle them specially (i.e. convert
1333 * mbuf+cluster -> cluster). This optimization is heavily
1334 * influenced by the assumption that we're running over
1335 * Ethernet where MCLBYTES is large enough that the max
1336 * packet size will permit lots of coalescing into a
1337 * single cluster. This in turn permits efficient
1338 * crypto operations, especially when using hardware.
1339 */
1340 if ((m->m_flags & M_EXT) == 0) {
1341 if (mprev && (mprev->m_flags & M_EXT) &&
1342 m->m_len <= M_TRAILINGSPACE(mprev)) {
1343 /* XXX: this ignores mbuf types */
1344 memcpy(mtod(mprev, __uint8_t *) + mprev->m_len,
1345 mtod(m, __uint8_t *), m->m_len);
1346 mprev->m_len += m->m_len;
1347 mprev->m_next = m->m_next; /* unlink from chain */
1348 m_free(m); /* reclaim mbuf */
1349 } else {
1350 mprev = m;
1351 }
1352 continue;
1353 }
1354 /*
1355 * Writable mbufs are left alone (for now).
1356 */
1357 if (!M_READONLY(m)) {
1358 mprev = m;
1359 continue;
1360 }
1361
1362 /*
1363 * Not writable, replace with a copy or coalesce with
1364 * the previous mbuf if possible (since we have to copy
1365 * it anyway, we try to reduce the number of mbufs and
1366 * clusters so that future work is easier).
1367 */
1368 FBSDKASSERT(m->m_flags & M_EXT, ("m_flags 0x%x", m->m_flags));
1369 /* NB: we only coalesce into a cluster or larger */
1370 if (mprev != NULL && (mprev->m_flags & M_EXT) &&
1371 m->m_len <= M_TRAILINGSPACE(mprev)) {
1372 /* XXX: this ignores mbuf types */
1373 memcpy(mtod(mprev, __uint8_t *) + mprev->m_len,
1374 mtod(m, __uint8_t *), m->m_len);
1375 mprev->m_len += m->m_len;
1376 mprev->m_next = m->m_next; /* unlink from chain */
1377 m_free(m); /* reclaim mbuf */
1378 continue;
1379 }
1380
1381 /*
1382 * Allocate new space to hold the copy and copy the data.
1383 * We deal with jumbo mbufs (i.e. m_len > MCLBYTES) by
1384 * splitting them into clusters. We could just malloc a
1385 * buffer and make it external but too many device drivers
1386 * don't know how to break up the non-contiguous memory when
1387 * doing DMA.
1388 */
1389 n = m_getcl(how, m->m_type, m->m_flags & M_COPYFLAGS);
1390 if (n == NULL) {
1391 m_freem(m0);
1392 return (NULL);
1393 }
1394 if (m->m_flags & M_PKTHDR) {
1395 FBSDKASSERT(mprev == NULL, ("%s: m0 %p, m %p has M_PKTHDR",
1396 __func__, m0, m));
1397 m_move_pkthdr(n, m);
1398 }
1399 len = m->m_len;
1400 off = 0;
1401 mfirst = n;
1402 mlast = NULL;
1403 for (;;) {
1404 int cc = min(len, MCLBYTES);
1405 memcpy(mtod(n, __uint8_t *), mtod(m, __uint8_t *) + off, cc);
1406 n->m_len = cc;
1407 if (mlast != NULL)
1408 mlast->m_next = n;
1409 mlast = n;
1410 #if 0
1411 newipsecstat.ips_clcopied++;
1412 #endif
1413
1414 len -= cc;
1415 if (len <= 0)
1416 break;
1417 off += cc;
1418
1419 n = m_getcl(how, m->m_type, m->m_flags & M_COPYFLAGS);
1420 if (n == NULL) {
1421 m_freem(mfirst);
1422 m_freem(m0);
1423 return (NULL);
1424 }
1425 }
1426 n->m_next = m->m_next;
1427 if (mprev == NULL)
1428 m0 = mfirst; /* new head of chain */
1429 else
1430 mprev->m_next = mfirst; /* replace old mbuf */
1431 m_free(m); /* release old mbuf */
1432 mprev = mfirst;
1433 }
1434 return (m0);
1435 }
1436