2 * Copyright (c) 2003-2009 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 * $FreeBSD: head/sys/net80211/ieee80211_freebsd.c 202612 2010-01-19 05:00:57Z thompsa $
29 * IEEE 802.11 support (DragonFlyBSD-specific code)
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/systm.h>
36 #include <sys/linker.h>
37 #include <sys/malloc.h>
39 #include <sys/module.h>
41 #include <sys/sysctl.h>
43 #include <sys/socket.h>
47 #include <net/if_dl.h>
48 #include <net/if_clone.h>
49 #include <net/if_media.h>
50 #include <net/if_types.h>
51 #include <net/ethernet.h>
52 #include <net/route.h>
53 #include <net/ifq_var.h>
55 #include <netproto/802_11/ieee80211_var.h>
56 #include <netproto/802_11/ieee80211_input.h>
58 SYSCTL_NODE(_net
, OID_AUTO
, wlan
, CTLFLAG_RD
, 0, "IEEE 80211 parameters");
60 #ifdef IEEE80211_DEBUG
61 int ieee80211_debug
= 0;
62 SYSCTL_INT(_net_wlan
, OID_AUTO
, debug
, CTLFLAG_RW
, &ieee80211_debug
,
63 0, "debugging printfs");
66 int ieee80211_force_swcrypto
= 0;
67 SYSCTL_INT(_net_wlan
, OID_AUTO
, force_swcrypto
, CTLFLAG_RW
,
68 &ieee80211_force_swcrypto
, 0, "force software crypto");
70 static int wlan_clone_destroy(struct ifnet
*);
71 static int wlan_clone_create(struct if_clone
*, int, caddr_t
, caddr_t
);
73 static struct if_clone wlan_cloner
=
74 IF_CLONE_INITIALIZER("wlan", wlan_clone_create
, wlan_clone_destroy
,
77 struct lwkt_serialize wlan_global_serializer
= LWKT_SERIALIZE_INITIALIZER
;
80 wlan_clone_create(struct if_clone
*ifc
, int unit
, caddr_t params
,
81 caddr_t data __unused
)
83 struct ieee80211_clone_params cp
;
84 struct ieee80211vap
*vap
;
85 struct ieee80211com
*ic
;
88 error
= copyin(params
, &cp
, sizeof(cp
));
92 ic
= ieee80211_find_com(cp
.icp_parent
);
95 if (cp
.icp_opmode
>= IEEE80211_OPMODE_MAX
) {
96 ic_printf(ic
, "%s: invalid opmode %d\n", __func__
,
100 if ((ic
->ic_caps
& ieee80211_opcap
[cp
.icp_opmode
]) == 0) {
101 ic_printf(ic
, "%s mode not supported\n",
102 ieee80211_opmode_name
[cp
.icp_opmode
]);
105 if ((cp
.icp_flags
& IEEE80211_CLONE_TDMA
) &&
106 #ifdef IEEE80211_SUPPORT_TDMA
107 (ic
->ic_caps
& IEEE80211_C_TDMA
) == 0
112 ic_printf(ic
, "TDMA not supported\n");
115 vap
= ic
->ic_vap_create(ic
, ifc
->ifc_name
, unit
,
116 cp
.icp_opmode
, cp
.icp_flags
, cp
.icp_bssid
,
117 cp
.icp_flags
& IEEE80211_CLONE_MACADDR
?
118 cp
.icp_macaddr
: ic
->ic_macaddr
);
121 return (vap
== NULL
? EIO
: 0);
125 wlan_clone_destroy(struct ifnet
*ifp
)
127 struct ieee80211vap
*vap
= ifp
->if_softc
;
128 struct ieee80211com
*ic
= vap
->iv_ic
;
130 ic
->ic_vap_delete(vap
);
135 const char *wlan_last_enter_func
;
136 const char *wlan_last_exit_func
;
139 * These serializer functions are used by wlan and all drivers.
140 * They are not recursive. The serializer must be held on
141 * any OACTIVE interactions. Dragonfly automatically holds
142 * the serializer on most ifp->if_*() calls but calls made
143 * from wlan into ath might not.
146 _wlan_serialize_enter(const char *funcname
)
148 lwkt_serialize_enter(&wlan_global_serializer
);
149 wlan_last_enter_func
= funcname
;
153 _wlan_serialize_exit(const char *funcname
)
155 lwkt_serialize_exit(&wlan_global_serializer
);
156 wlan_last_exit_func
= funcname
;
160 _wlan_is_serialized(void)
162 return (IS_SERIALIZED(&wlan_global_serializer
));
166 * Push/pop allows the wlan serializer to be entered recursively.
169 _wlan_serialize_push(const char *funcname
)
171 if (IS_SERIALIZED(&wlan_global_serializer
)) {
174 _wlan_serialize_enter(funcname
);
180 _wlan_serialize_pop(const char *funcname
, int wst
)
183 _wlan_serialize_exit(funcname
);
190 wlan_serialize_sleep(void *ident
, int flags
, const char *wmesg
, int timo
)
192 return(zsleep(ident
, &wlan_global_serializer
, flags
, wmesg
, timo
));
196 * condition-var functions which interlock the ic lock (which is now
197 * just wlan_global_serializer)
200 wlan_cv_init(struct cv
*cv
, const char *desc
)
207 wlan_cv_timedwait(struct cv
*cv
, int ticks
)
212 error
= wlan_serialize_sleep(cv
, 0, cv
->cv_desc
, ticks
);
217 wlan_cv_wait(struct cv
*cv
)
220 wlan_serialize_sleep(cv
, 0, cv
->cv_desc
, 0);
224 wlan_cv_signal(struct cv
*cv
, int broadcast
)
226 if (cv
->cv_waiters
) {
240 * Add RX parameters to the given mbuf.
242 * Returns 1 if OK, 0 on error.
245 ieee80211_add_rx_params(struct mbuf
*m
, const struct ieee80211_rx_stats
*rxs
)
248 struct ieee80211_rx_params
*rx
;
250 mtag
= m_tag_alloc(MTAG_ABI_NET80211
, NET80211_TAG_RECV_PARAMS
,
251 sizeof(struct ieee80211_rx_stats
), M_NOWAIT
);
255 rx
= (struct ieee80211_rx_params
*)(mtag
+ 1);
256 memcpy(&rx
->params
, rxs
, sizeof(*rxs
));
257 m_tag_prepend(m
, mtag
);
262 ieee80211_get_rx_params(struct mbuf
*m
, struct ieee80211_rx_stats
*rxs
)
265 struct ieee80211_rx_params
*rx
;
267 mtag
= m_tag_locate(m
, MTAG_ABI_NET80211
, NET80211_TAG_RECV_PARAMS
,
271 rx
= (struct ieee80211_rx_params
*)(mtag
+ 1);
272 memcpy(rxs
, &rx
->params
, sizeof(*rxs
));
280 ieee80211_vap_xmitpkt(struct ieee80211vap
*vap
, struct mbuf
*m
)
282 struct ifnet
*ifp
= vap
->iv_ifp
;
283 struct ifaltq_subque
*ifsq
= ifq_get_subq_default(&ifp
->if_snd
);
288 * When transmitting via the VAP, we shouldn't hold
289 * any IC TX lock as the VAP TX path will acquire it.
291 IEEE80211_TX_UNLOCK_ASSERT(vap
->iv_ic
);
293 error
= ifsq_enqueue(ifsq
, m
, NULL
);
295 IFNET_STAT_INC(ifp
, oqdrops
, 1);
296 wst
= wlan_serialize_push();
297 ifp
->if_start(ifp
, ifsq
);
298 wlan_serialize_pop(wst
);
304 ieee80211_parent_xmitpkt(struct ieee80211com
*ic
, struct mbuf
*m
)
309 * Assert the IC TX lock is held - this enforces the
310 * processing -> queuing order is maintained
312 IEEE80211_TX_LOCK_ASSERT(ic
);
313 error
= ic
->ic_transmit(ic
, m
);
315 struct ieee80211_node
*ni
;
317 ni
= (struct ieee80211_node
*)m
->m_pkthdr
.rcvif
;
319 /* XXX number of fragments */
320 IFNET_STAT_INC(ni
->ni_vap
->iv_ifp
, oerrors
, 1);
321 ieee80211_free_node(ni
);
322 ieee80211_free_mbuf(m
);
328 ieee80211_vap_destroy(struct ieee80211vap
*vap
)
331 * WLAN serializer must _not_ be held for if_clone_destroy(),
332 * since it could dead-lock the domsg to netisrs.
334 wlan_serialize_exit();
336 * Make sure we con't end up in an infinite loop in ieee80211_ifdetach
337 * when if_clone_destroy fails.
339 KKASSERT(if_clone_destroy(vap
->iv_ifp
->if_xname
) == 0);
340 wlan_serialize_enter();
344 * NOTE: This handler is used generally to convert milliseconds
345 * to ticks for various simple sysctl variables and does not
346 * need to be serialized.
349 ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS
)
351 int msecs
= ticks_to_msecs(*(int *)arg1
);
354 error
= sysctl_handle_int(oidp
, &msecs
, 0, req
);
355 if (error
== 0 && req
->newptr
) {
356 t
= msecs_to_ticks(msecs
);
357 *(int *)arg1
= (t
< 1) ? 1 : t
;
364 ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS
)
366 int inact
= (*(int *)arg1
) * IEEE80211_INACT_WAIT
;
369 error
= sysctl_handle_int(oidp
, &inact
, 0, req
);
370 if (error
== 0 && req
->newptr
)
371 *(int *)arg1
= inact
/ IEEE80211_INACT_WAIT
;
377 ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS
)
379 struct ieee80211com
*ic
= arg1
;
380 const char *name
= ic
->ic_name
;
382 return SYSCTL_OUT(req
, name
, strlen(name
));
386 ieee80211_sysctl_radar(SYSCTL_HANDLER_ARGS
)
388 struct ieee80211com
*ic
= arg1
;
391 error
= sysctl_handle_int(oidp
, &t
, 0, req
);
392 if (error
== 0 && req
->newptr
)
393 ieee80211_dfs_notify_radar(ic
, ic
->ic_curchan
);
399 ieee80211_sysctl_attach(struct ieee80211com
*ic
)
404 ieee80211_sysctl_detach(struct ieee80211com
*ic
)
409 ieee80211_sysctl_vattach(struct ieee80211vap
*vap
)
411 struct ifnet
*ifp
= vap
->iv_ifp
;
412 struct sysctl_ctx_list
*ctx
;
413 struct sysctl_oid
*oid
;
414 char num
[14]; /* sufficient for 32 bits */
416 ctx
= (struct sysctl_ctx_list
*) kmalloc(sizeof(struct sysctl_ctx_list
),
417 M_DEVBUF
, M_INTWAIT
| M_ZERO
);
419 if_printf(ifp
, "%s: cannot allocate sysctl context!\n",
423 sysctl_ctx_init(ctx
);
424 ksnprintf(num
, sizeof(num
), "%u", ifp
->if_dunit
);
425 oid
= SYSCTL_ADD_NODE(ctx
, &SYSCTL_NODE_CHILDREN(_net
, wlan
),
426 OID_AUTO
, num
, CTLFLAG_RD
, NULL
, "");
427 SYSCTL_ADD_PROC(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
428 "%parent", CTLFLAG_RD
, vap
->iv_ic
, 0,
429 ieee80211_sysctl_parent
, "A", "parent device");
430 SYSCTL_ADD_INT(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
431 "driver_caps", CTLFLAG_RW
, &vap
->iv_caps
, 0,
432 "driver capabilities");
433 #ifdef IEEE80211_DEBUG
434 vap
->iv_debug
= ieee80211_debug
;
435 SYSCTL_ADD_INT(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
436 "debug", CTLFLAG_RW
, &vap
->iv_debug
, 0,
437 "control debugging printfs");
439 SYSCTL_ADD_INT(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
440 "bmiss_max", CTLFLAG_RW
, &vap
->iv_bmiss_max
, 0,
441 "consecutive beacon misses before scanning");
442 /* XXX inherit from tunables */
443 SYSCTL_ADD_PROC(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
444 "inact_run", CTLTYPE_INT
| CTLFLAG_RW
, &vap
->iv_inact_run
, 0,
445 ieee80211_sysctl_inact
, "I",
446 "station inactivity timeout (sec)");
447 SYSCTL_ADD_PROC(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
448 "inact_probe", CTLTYPE_INT
| CTLFLAG_RW
, &vap
->iv_inact_probe
, 0,
449 ieee80211_sysctl_inact
, "I",
450 "station inactivity probe timeout (sec)");
451 SYSCTL_ADD_PROC(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
452 "inact_auth", CTLTYPE_INT
| CTLFLAG_RW
, &vap
->iv_inact_auth
, 0,
453 ieee80211_sysctl_inact
, "I",
454 "station authentication timeout (sec)");
455 SYSCTL_ADD_PROC(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
456 "inact_init", CTLTYPE_INT
| CTLFLAG_RW
, &vap
->iv_inact_init
, 0,
457 ieee80211_sysctl_inact
, "I",
458 "station initial state timeout (sec)");
459 if (vap
->iv_htcaps
& IEEE80211_HTC_HT
) {
460 SYSCTL_ADD_INT(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
461 "ampdu_mintraffic_bk", CTLFLAG_RW
,
462 &vap
->iv_ampdu_mintraffic
[WME_AC_BK
], 0,
463 "BK traffic tx aggr threshold (pps)");
464 SYSCTL_ADD_INT(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
465 "ampdu_mintraffic_be", CTLFLAG_RW
,
466 &vap
->iv_ampdu_mintraffic
[WME_AC_BE
], 0,
467 "BE traffic tx aggr threshold (pps)");
468 SYSCTL_ADD_INT(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
469 "ampdu_mintraffic_vo", CTLFLAG_RW
,
470 &vap
->iv_ampdu_mintraffic
[WME_AC_VO
], 0,
471 "VO traffic tx aggr threshold (pps)");
472 SYSCTL_ADD_INT(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
473 "ampdu_mintraffic_vi", CTLFLAG_RW
,
474 &vap
->iv_ampdu_mintraffic
[WME_AC_VI
], 0,
475 "VI traffic tx aggr threshold (pps)");
477 if (vap
->iv_caps
& IEEE80211_C_DFS
) {
478 SYSCTL_ADD_PROC(ctx
, SYSCTL_CHILDREN(oid
), OID_AUTO
,
479 "radar", CTLTYPE_INT
| CTLFLAG_RW
, vap
->iv_ic
, 0,
480 ieee80211_sysctl_radar
, "I", "simulate radar event");
482 vap
->iv_sysctl
= ctx
;
487 ieee80211_sysctl_vdetach(struct ieee80211vap
*vap
)
490 if (vap
->iv_sysctl
!= NULL
) {
491 sysctl_ctx_free(vap
->iv_sysctl
);
492 kfree(vap
->iv_sysctl
, M_DEVBUF
);
493 vap
->iv_sysctl
= NULL
;
498 ieee80211_node_dectestref(struct ieee80211_node
*ni
)
500 /* XXX need equivalent of atomic_dec_and_test */
501 atomic_subtract_int(&ni
->ni_refcnt
, 1);
502 return atomic_cmpset_int(&ni
->ni_refcnt
, 0, 1);
506 /* XXX this breaks ALTQ's packet scheduler */
508 ieee80211_flush_ifq(struct ifaltq
*ifq
, struct ieee80211vap
*vap
)
510 struct ieee80211_node
*ni
;
511 struct mbuf
*m
, **mprev
;
512 struct ifaltq_subque
*ifsq
= ifq_get_subq_default(ifq
);
514 wlan_assert_serialized();
521 mprev
= &ifsq
->ifsq_norm_head
;
522 while ((m
= *mprev
) != NULL
) {
523 ni
= (struct ieee80211_node
*)m
->m_pkthdr
.rcvif
;
524 if (ni
!= NULL
&& ni
->ni_vap
== vap
) {
525 *mprev
= m
->m_nextpkt
; /* remove from list */
526 ALTQ_SQ_CNTR_DEC(ifsq
, m
->m_pkthdr
.len
);
529 ieee80211_free_node(ni
); /* reclaim ref */
531 mprev
= &m
->m_nextpkt
;
533 /* recalculate tail ptr */
534 m
= ifsq
->ifsq_norm_head
;
535 for (; m
!= NULL
&& m
->m_nextpkt
!= NULL
; m
= m
->m_nextpkt
)
537 ifsq
->ifsq_norm_tail
= m
;
542 mprev
= &ifsq
->ifsq_prio_head
;
543 while ((m
= *mprev
) != NULL
) {
544 ni
= (struct ieee80211_node
*)m
->m_pkthdr
.rcvif
;
545 if (ni
!= NULL
&& ni
->ni_vap
== vap
) {
546 *mprev
= m
->m_nextpkt
; /* remove from list */
547 ALTQ_SQ_CNTR_DEC(ifsq
, m
->m_pkthdr
.len
);
548 ALTQ_SQ_PRIO_CNTR_DEC(ifsq
, m
->m_pkthdr
.len
);
551 ieee80211_free_node(ni
); /* reclaim ref */
553 mprev
= &m
->m_nextpkt
;
555 /* recalculate tail ptr */
556 m
= ifsq
->ifsq_prio_head
;
557 for (; m
!= NULL
&& m
->m_nextpkt
!= NULL
; m
= m
->m_nextpkt
)
559 ifsq
->ifsq_prio_tail
= m
;
561 ALTQ_SQ_UNLOCK(ifsq
);
566 * As above, for mbufs allocated with m_gethdr/MGETHDR
567 * or initialized by M_COPY_PKTHDR.
569 #define MC_ALIGN(m, len) \
571 (m)->m_data += rounddown2(MCLBYTES - (len), sizeof(long)); \
572 } while (/* CONSTCOND */ 0)
575 * Allocate and setup a management frame of the specified
576 * size. We return the mbuf and a pointer to the start
577 * of the contiguous data area that's been reserved based
578 * on the packet length. The data area is forced to 32-bit
579 * alignment and the buffer length to a multiple of 4 bytes.
580 * This is done mainly so beacon frames (that require this)
581 * can use this interface too.
584 ieee80211_getmgtframe(uint8_t **frm
, int headroom
, int pktlen
)
590 * NB: we know the mbuf routines will align the data area
591 * so we don't need to do anything special.
593 len
= roundup2(headroom
+ pktlen
, 4);
594 KASSERT(len
<= MCLBYTES
, ("802.11 mgt frame too large: %u", len
));
595 if (len
< MINCLSIZE
) {
596 m
= m_gethdr(M_NOWAIT
, MT_DATA
);
598 * Align the data in case additional headers are added.
599 * This should only happen when a WEP header is added
600 * which only happens for shared key authentication mgt
601 * frames which all fit in MHLEN.
606 m
= m_getcl(M_NOWAIT
, MT_DATA
, M_PKTHDR
);
611 m
->m_data
+= headroom
;
618 * Re-align the payload in the mbuf. This is mainly used (right now)
619 * to handle IP header alignment requirements on certain architectures.
622 ieee80211_realign(struct ieee80211vap
*vap
, struct mbuf
*m
, size_t align
)
625 struct mbuf
*n
= NULL
;
627 pktlen
= m
->m_pkthdr
.len
;
628 space
= pktlen
+ align
;
629 if (space
< MINCLSIZE
) {
630 n
= m_gethdr(M_NOWAIT
, MT_DATA
);
632 if (space
<= MCLBYTES
)
634 else if (space
<= MJUMPAGESIZE
)
635 space
= MJUMPAGESIZE
;
636 else if (space
<= MJUM9BYTES
)
640 n
= m_getjcl(M_NOWAIT
, MT_DATA
, M_PKTHDR
, space
);
642 if (__predict_true(n
!= NULL
)) {
644 n
->m_data
= (caddr_t
)(ALIGN(n
->m_data
+ align
) - align
);
645 m_copydata(m
, 0, pktlen
, mtod(n
, void *));
648 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ANY
,
649 mtod(m
, const struct ieee80211_frame
*), NULL
,
650 "%s", "no mbuf to realign");
651 vap
->iv_stats
.is_rx_badalign
++;
658 ieee80211_add_callback(struct mbuf
*m
,
659 void (*func
)(struct ieee80211_node
*, void *, int), void *arg
)
662 struct ieee80211_cb
*cb
;
664 mtag
= m_tag_alloc(MTAG_ABI_NET80211
, NET80211_TAG_CALLBACK
,
665 sizeof(struct ieee80211_cb
), M_INTWAIT
);
669 cb
= (struct ieee80211_cb
*)(mtag
+1);
672 m_tag_prepend(m
, mtag
);
673 m
->m_flags
|= M_TXCB
;
678 ieee80211_add_xmit_params(struct mbuf
*m
,
679 const struct ieee80211_bpf_params
*params
)
682 struct ieee80211_tx_params
*tx
;
684 mtag
= m_tag_alloc(MTAG_ABI_NET80211
, NET80211_TAG_XMIT_PARAMS
,
685 sizeof(struct ieee80211_tx_params
), M_NOWAIT
);
689 tx
= (struct ieee80211_tx_params
*)(mtag
+1);
690 memcpy(&tx
->params
, params
, sizeof(struct ieee80211_bpf_params
));
691 m_tag_prepend(m
, mtag
);
696 ieee80211_get_xmit_params(struct mbuf
*m
,
697 struct ieee80211_bpf_params
*params
)
700 struct ieee80211_tx_params
*tx
;
702 mtag
= m_tag_locate(m
, MTAG_ABI_NET80211
, NET80211_TAG_XMIT_PARAMS
,
706 tx
= (struct ieee80211_tx_params
*)(mtag
+ 1);
707 memcpy(params
, &tx
->params
, sizeof(struct ieee80211_bpf_params
));
712 ieee80211_process_callback(struct ieee80211_node
*ni
,
713 struct mbuf
*m
, int status
)
717 mtag
= m_tag_locate(m
, MTAG_ABI_NET80211
, NET80211_TAG_CALLBACK
, NULL
);
719 struct ieee80211_cb
*cb
= (struct ieee80211_cb
*)(mtag
+1);
720 cb
->func(ni
, cb
->arg
, status
);
724 #include <sys/libkern.h>
727 get_random_bytes(void *p
, size_t n
)
732 uint32_t v
= karc4random();
733 size_t nb
= n
> sizeof(uint32_t) ? sizeof(uint32_t) : n
;
734 bcopy(&v
, dp
, n
> sizeof(uint32_t) ? sizeof(uint32_t) : n
);
735 dp
+= sizeof(uint32_t), n
-= nb
;
740 * Helper function for events that pass just a single mac address.
743 notify_macaddr(struct ifnet
*ifp
, int op
, const uint8_t mac
[IEEE80211_ADDR_LEN
])
745 struct ieee80211_join_event iev
;
747 memset(&iev
, 0, sizeof(iev
));
748 IEEE80211_ADDR_COPY(iev
.iev_addr
, mac
);
749 rt_ieee80211msg(ifp
, op
, &iev
, sizeof(iev
));
753 ieee80211_notify_node_join(struct ieee80211_node
*ni
, int newassoc
)
755 struct ieee80211vap
*vap
= ni
->ni_vap
;
756 struct ifnet
*ifp
= vap
->iv_ifp
;
758 IEEE80211_NOTE(vap
, IEEE80211_MSG_NODE
, ni
, "%snode join",
759 (ni
== vap
->iv_bss
) ? "bss " : "");
761 if (ni
== vap
->iv_bss
) {
762 ifp
->if_link_state
= LINK_STATE_UP
;
763 notify_macaddr(ifp
, newassoc
?
764 RTM_IEEE80211_ASSOC
: RTM_IEEE80211_REASSOC
, ni
->ni_bssid
);
765 if_link_state_change(ifp
);
767 notify_macaddr(ifp
, newassoc
?
768 RTM_IEEE80211_JOIN
: RTM_IEEE80211_REJOIN
, ni
->ni_macaddr
);
773 ieee80211_notify_node_leave(struct ieee80211_node
*ni
)
775 struct ieee80211vap
*vap
= ni
->ni_vap
;
776 struct ifnet
*ifp
= vap
->iv_ifp
;
778 IEEE80211_NOTE(vap
, IEEE80211_MSG_NODE
, ni
, "%snode leave",
779 (ni
== vap
->iv_bss
) ? "bss " : "");
781 if (ni
== vap
->iv_bss
) {
782 ifp
->if_link_state
= LINK_STATE_DOWN
;
783 rt_ieee80211msg(ifp
, RTM_IEEE80211_DISASSOC
, NULL
, 0);
784 if_link_state_change(ifp
);
786 /* fire off wireless event station leaving */
787 notify_macaddr(ifp
, RTM_IEEE80211_LEAVE
, ni
->ni_macaddr
);
792 ieee80211_notify_scan_done(struct ieee80211vap
*vap
)
794 struct ifnet
*ifp
= vap
->iv_ifp
;
796 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_SCAN
, "%s\n", "notify scan done");
798 /* dispatch wireless event indicating scan completed */
799 rt_ieee80211msg(ifp
, RTM_IEEE80211_SCAN
, NULL
, 0);
803 ieee80211_notify_replay_failure(struct ieee80211vap
*vap
,
804 const struct ieee80211_frame
*wh
, const struct ieee80211_key
*k
,
805 u_int64_t rsc
, int tid
)
807 struct ifnet
*ifp
= vap
->iv_ifp
;
809 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_CRYPTO
, wh
->i_addr2
,
810 "%s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>",
811 k
->wk_cipher
->ic_name
, (intmax_t) rsc
,
812 (intmax_t) k
->wk_keyrsc
[tid
],
813 k
->wk_keyix
, k
->wk_rxkeyix
);
815 if (ifp
!= NULL
) { /* NB: for cipher test modules */
816 struct ieee80211_replay_event iev
;
818 IEEE80211_ADDR_COPY(iev
.iev_dst
, wh
->i_addr1
);
819 IEEE80211_ADDR_COPY(iev
.iev_src
, wh
->i_addr2
);
820 iev
.iev_cipher
= k
->wk_cipher
->ic_cipher
;
821 if (k
->wk_rxkeyix
!= IEEE80211_KEYIX_NONE
)
822 iev
.iev_keyix
= k
->wk_rxkeyix
;
824 iev
.iev_keyix
= k
->wk_keyix
;
825 iev
.iev_keyrsc
= k
->wk_keyrsc
[tid
];
827 rt_ieee80211msg(ifp
, RTM_IEEE80211_REPLAY
, &iev
, sizeof(iev
));
832 ieee80211_notify_michael_failure(struct ieee80211vap
*vap
,
833 const struct ieee80211_frame
*wh
, u_int keyix
)
835 struct ifnet
*ifp
= vap
->iv_ifp
;
837 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_CRYPTO
, wh
->i_addr2
,
838 "michael MIC verification failed <keyix %u>", keyix
);
839 vap
->iv_stats
.is_rx_tkipmic
++;
841 if (ifp
!= NULL
) { /* NB: for cipher test modules */
842 struct ieee80211_michael_event iev
;
844 IEEE80211_ADDR_COPY(iev
.iev_dst
, wh
->i_addr1
);
845 IEEE80211_ADDR_COPY(iev
.iev_src
, wh
->i_addr2
);
846 iev
.iev_cipher
= IEEE80211_CIPHER_TKIP
;
847 iev
.iev_keyix
= keyix
;
848 rt_ieee80211msg(ifp
, RTM_IEEE80211_MICHAEL
, &iev
, sizeof(iev
));
853 ieee80211_notify_wds_discover(struct ieee80211_node
*ni
)
855 struct ieee80211vap
*vap
= ni
->ni_vap
;
856 struct ifnet
*ifp
= vap
->iv_ifp
;
858 notify_macaddr(ifp
, RTM_IEEE80211_WDS
, ni
->ni_macaddr
);
862 ieee80211_notify_csa(struct ieee80211com
*ic
,
863 const struct ieee80211_channel
*c
, int mode
, int count
)
865 struct ieee80211vap
*vap
;
867 struct ieee80211_csa_event iev
;
869 memset(&iev
, 0, sizeof(iev
));
870 iev
.iev_flags
= c
->ic_flags
;
871 iev
.iev_freq
= c
->ic_freq
;
872 iev
.iev_ieee
= c
->ic_ieee
;
874 iev
.iev_count
= count
;
875 TAILQ_FOREACH(vap
, &ic
->ic_vaps
, iv_next
) {
877 rt_ieee80211msg(ifp
, RTM_IEEE80211_CSA
, &iev
, sizeof(iev
));
882 ieee80211_notify_radar(struct ieee80211com
*ic
,
883 const struct ieee80211_channel
*c
)
885 struct ieee80211_radar_event iev
;
886 struct ieee80211vap
*vap
;
889 memset(&iev
, 0, sizeof(iev
));
890 iev
.iev_flags
= c
->ic_flags
;
891 iev
.iev_freq
= c
->ic_freq
;
892 iev
.iev_ieee
= c
->ic_ieee
;
893 TAILQ_FOREACH(vap
, &ic
->ic_vaps
, iv_next
) {
895 rt_ieee80211msg(ifp
, RTM_IEEE80211_RADAR
, &iev
, sizeof(iev
));
900 ieee80211_notify_cac(struct ieee80211com
*ic
,
901 const struct ieee80211_channel
*c
, enum ieee80211_notify_cac_event type
)
903 struct ieee80211_cac_event iev
;
904 struct ieee80211vap
*vap
;
907 memset(&iev
, 0, sizeof(iev
));
908 iev
.iev_flags
= c
->ic_flags
;
909 iev
.iev_freq
= c
->ic_freq
;
910 iev
.iev_ieee
= c
->ic_ieee
;
912 TAILQ_FOREACH(vap
, &ic
->ic_vaps
, iv_next
) {
914 rt_ieee80211msg(ifp
, RTM_IEEE80211_CAC
, &iev
, sizeof(iev
));
919 ieee80211_notify_node_deauth(struct ieee80211_node
*ni
)
921 struct ieee80211vap
*vap
= ni
->ni_vap
;
922 struct ifnet
*ifp
= vap
->iv_ifp
;
924 IEEE80211_NOTE(vap
, IEEE80211_MSG_NODE
, ni
, "%s", "node deauth");
926 notify_macaddr(ifp
, RTM_IEEE80211_DEAUTH
, ni
->ni_macaddr
);
930 ieee80211_notify_node_auth(struct ieee80211_node
*ni
)
932 struct ieee80211vap
*vap
= ni
->ni_vap
;
933 struct ifnet
*ifp
= vap
->iv_ifp
;
935 IEEE80211_NOTE(vap
, IEEE80211_MSG_NODE
, ni
, "%s", "node auth");
937 notify_macaddr(ifp
, RTM_IEEE80211_AUTH
, ni
->ni_macaddr
);
941 ieee80211_notify_country(struct ieee80211vap
*vap
,
942 const uint8_t bssid
[IEEE80211_ADDR_LEN
], const uint8_t cc
[2])
944 struct ifnet
*ifp
= vap
->iv_ifp
;
945 struct ieee80211_country_event iev
;
947 memset(&iev
, 0, sizeof(iev
));
948 IEEE80211_ADDR_COPY(iev
.iev_addr
, bssid
);
949 iev
.iev_cc
[0] = cc
[0];
950 iev
.iev_cc
[1] = cc
[1];
951 rt_ieee80211msg(ifp
, RTM_IEEE80211_COUNTRY
, &iev
, sizeof(iev
));
955 ieee80211_notify_radio(struct ieee80211com
*ic
, int state
)
957 struct ieee80211_radio_event iev
;
958 struct ieee80211vap
*vap
;
961 memset(&iev
, 0, sizeof(iev
));
962 iev
.iev_state
= state
;
963 TAILQ_FOREACH(vap
, &ic
->ic_vaps
, iv_next
) {
965 rt_ieee80211msg(ifp
, RTM_IEEE80211_RADIO
, &iev
, sizeof(iev
));
969 /* IEEE Std 802.11a-1999, page 9, table 79 */
970 #define IEEE80211_OFDM_SYM_TIME 4
971 #define IEEE80211_OFDM_PREAMBLE_TIME 16
972 #define IEEE80211_OFDM_SIGNAL_TIME 4
973 /* IEEE Std 802.11g-2003, page 44 */
974 #define IEEE80211_OFDM_SIGNAL_EXT_TIME 6
976 /* IEEE Std 802.11a-1999, page 7, figure 107 */
977 #define IEEE80211_OFDM_PLCP_SERVICE_NBITS 16
978 #define IEEE80211_OFDM_TAIL_NBITS 6
980 #define IEEE80211_OFDM_NBITS(frmlen) \
981 (IEEE80211_OFDM_PLCP_SERVICE_NBITS + \
982 ((frmlen) * NBBY) + \
983 IEEE80211_OFDM_TAIL_NBITS)
985 #define IEEE80211_OFDM_NBITS_PER_SYM(kbps) \
986 (((kbps) * IEEE80211_OFDM_SYM_TIME) / 1000)
988 #define IEEE80211_OFDM_NSYMS(kbps, frmlen) \
989 howmany(IEEE80211_OFDM_NBITS((frmlen)), \
990 IEEE80211_OFDM_NBITS_PER_SYM((kbps)))
992 #define IEEE80211_OFDM_TXTIME(kbps, frmlen) \
993 (IEEE80211_OFDM_PREAMBLE_TIME + \
994 IEEE80211_OFDM_SIGNAL_TIME + \
995 (IEEE80211_OFDM_NSYMS((kbps), (frmlen)) * IEEE80211_OFDM_SYM_TIME))
997 /* IEEE Std 802.11b-1999, page 28, subclause 18.3.4 */
998 #define IEEE80211_CCK_PREAMBLE_LEN 144
999 #define IEEE80211_CCK_PLCP_HDR_TIME 48
1000 #define IEEE80211_CCK_SHPREAMBLE_LEN 72
1001 #define IEEE80211_CCK_SHPLCP_HDR_TIME 24
1003 #define IEEE80211_CCK_NBITS(frmlen) ((frmlen) * NBBY)
1004 #define IEEE80211_CCK_TXTIME(kbps, frmlen) \
1005 (((IEEE80211_CCK_NBITS((frmlen)) * 1000) + (kbps) - 1) / (kbps))
1008 ieee80211_txtime(struct ieee80211_node
*ni
, u_int len
, uint8_t rs_rate
,
1011 struct ieee80211vap
*vap
= ni
->ni_vap
;
1015 rs_rate
&= IEEE80211_RATE_VAL
;
1016 rate
= rs_rate
* 500; /* ieee80211 rate -> kbps */
1018 if (vap
->iv_ic
->ic_phytype
== IEEE80211_T_OFDM
) {
1020 * IEEE Std 802.11a-1999, page 37, equation (29)
1021 * IEEE Std 802.11g-2003, page 44, equation (42)
1023 txtime
= IEEE80211_OFDM_TXTIME(rate
, len
);
1024 if (vap
->iv_ic
->ic_curmode
== IEEE80211_MODE_11G
)
1025 txtime
+= IEEE80211_OFDM_SIGNAL_EXT_TIME
;
1028 * IEEE Std 802.11b-1999, page 28, subclause 18.3.4
1029 * IEEE Std 802.11g-2003, page 45, equation (43)
1031 if (vap
->iv_ic
->ic_phytype
== IEEE80211_T_OFDM_QUARTER
+1)
1033 txtime
= IEEE80211_CCK_TXTIME(rate
, len
);
1036 * Short preamble is not applicable for DS 1Mbits/s
1038 if (rs_rate
!= 2 && (flags
& IEEE80211_F_SHPREAMBLE
)) {
1039 txtime
+= IEEE80211_CCK_SHPREAMBLE_LEN
+
1040 IEEE80211_CCK_SHPLCP_HDR_TIME
;
1042 txtime
+= IEEE80211_CCK_PREAMBLE_LEN
+
1043 IEEE80211_CCK_PLCP_HDR_TIME
;
1050 ieee80211_load_module(const char *modname
)
1054 (void)kern_kldload(curthread
, modname
, NULL
);
1056 kprintf("%s: load the %s module by hand for now.\n", __func__
, modname
);
1060 static eventhandler_tag wlan_bpfevent
;
1061 static eventhandler_tag wlan_ifllevent
;
1064 bpf_track_event(void *arg
, struct ifnet
*ifp
, int dlt
, int attach
)
1066 /* NB: identify vap's by if_start */
1068 if (dlt
== DLT_IEEE802_11_RADIO
&&
1069 ifp
->if_start
== ieee80211_vap_start
) {
1070 struct ieee80211vap
*vap
= ifp
->if_softc
;
1072 * Track bpf radiotap listener state. We mark the vap
1073 * to indicate if any listener is present and the com
1074 * to indicate if any listener exists on any associated
1075 * vap. This flag is used by drivers to prepare radiotap
1076 * state only when needed.
1079 ieee80211_syncflag_ext(vap
, IEEE80211_FEXT_BPF
);
1080 if (vap
->iv_opmode
== IEEE80211_M_MONITOR
)
1081 atomic_add_int(&vap
->iv_ic
->ic_montaps
, 1);
1082 } else if (!vap
->iv_rawbpf
) {
1083 ieee80211_syncflag_ext(vap
, -IEEE80211_FEXT_BPF
);
1084 if (vap
->iv_opmode
== IEEE80211_M_MONITOR
)
1085 atomic_subtract_int(&vap
->iv_ic
->ic_montaps
, 1);
1091 ether_sprintf(const u_char
*buf
)
1093 static char ethstr
[MAXCPU
][ETHER_ADDRSTRLEN
+ 1];
1094 char *ptr
= ethstr
[mycpu
->gd_cpuid
];
1096 kether_ntoa(buf
, ptr
);
1101 * Change MAC address on the vap (if was not started).
1104 wlan_iflladdr_event(void *arg __unused
, struct ifnet
*ifp
)
1106 /* NB: identify vap's by if_init */
1107 if (ifp
->if_init
== ieee80211_init
&&
1108 (ifp
->if_flags
& IFF_UP
) == 0) {
1109 struct ieee80211vap
*vap
= ifp
->if_softc
;
1110 IEEE80211_ADDR_COPY(vap
->iv_myaddr
, IF_LLADDR(ifp
));
1117 * NB: the module name is "wlan" for compatibility with NetBSD.
1120 wlan_modevent(module_t mod
, int type
, void *unused
)
1127 kprintf("wlan: <802.11 Link Layer>\n");
1128 wlan_bpfevent
= EVENTHANDLER_REGISTER(bpf_track
,
1130 EVENTHANDLER_PRI_ANY
);
1131 wlan_ifllevent
= EVENTHANDLER_REGISTER(iflladdr_event
,
1132 wlan_iflladdr_event
, NULL
,
1133 EVENTHANDLER_PRI_ANY
);
1134 if_clone_attach(&wlan_cloner
);
1138 if_clone_detach(&wlan_cloner
);
1139 EVENTHANDLER_DEREGISTER(bpf_track
, wlan_bpfevent
);
1140 EVENTHANDLER_DEREGISTER(iflladdr_event
, wlan_ifllevent
);
1150 static moduledata_t wlan_mod
= {
1155 DECLARE_MODULE(wlan
, wlan_mod
, SI_SUB_DRIVERS
, SI_ORDER_FIRST
);
1156 MODULE_VERSION(wlan
, 1);
1157 MODULE_DEPEND(wlan
, ether
, 1, 1, 1);