1 /* $NetBSD: ieee80211_netbsd.c,v 1.16 2008/01/31 22:07:22 christos Exp $ */
3 * Copyright (c) 2003-2005 Sam Leffler, Errno Consulting
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_freebsd.c,v 1.8 2005/08/08 18:46:35 sam Exp $");
33 __KERNEL_RCSID(0, "$NetBSD: ieee80211_netbsd.c,v 1.16 2008/01/31 22:07:22 christos Exp $");
37 * IEEE 802.11 support (NetBSD-specific code)
39 #include <sys/param.h>
40 #include <sys/kernel.h>
41 #include <sys/systm.h>
44 #include <sys/sysctl.h>
47 #include <machine/stdarg.h>
49 #include <sys/socket.h>
52 #include <net/if_media.h>
53 #include <net/if_ether.h>
54 #include <net/route.h>
56 #include <net80211/ieee80211_netbsd.h>
57 #include <net80211/ieee80211_var.h>
58 #include <net80211/ieee80211_sysctl.h>
60 #define LOGICALLY_EQUAL(x, y) (!(x) == !(y))
62 static void ieee80211_sysctl_fill_node(struct ieee80211_node
*,
63 struct ieee80211_node_sysctl
*, int, const struct ieee80211_channel
*,
65 static struct ieee80211_node
*ieee80211_node_walknext(
66 struct ieee80211_node_walk
*);
67 static struct ieee80211_node
*ieee80211_node_walkfirst(
68 struct ieee80211_node_walk
*, u_short
);
69 static int ieee80211_sysctl_node(SYSCTLFN_ARGS
);
71 #ifdef IEEE80211_DEBUG
72 int ieee80211_debug
= 0;
75 typedef void (*ieee80211_setup_func
)(void);
77 __link_set_decl(ieee80211_funcs
, ieee80211_setup_func
);
82 ieee80211_setup_func
* const *ieee80211_setup
, f
;
84 __link_set_foreach(ieee80211_setup
, ieee80211_funcs
) {
85 f
= (void*)*ieee80211_setup
;
95 static ONCE_DECL(ieee80211_init_once
);
97 RUN_ONCE(&ieee80211_init_once
, ieee80211_init0
);
101 ieee80211_sysctl_inact(SYSCTLFN_ARGS
)
104 struct sysctlnode node
;
107 /* sysctl_lookup copies the product from t. Then, it
108 * copies the new value onto t.
110 t
= *(int*)rnode
->sysctl_data
* IEEE80211_INACT_WAIT
;
111 node
.sysctl_data
= &t
;
112 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
113 if (error
|| newp
== NULL
)
116 /* The new value was in seconds. Convert to inactivity-wait
117 * intervals. There are IEEE80211_INACT_WAIT seconds per
120 *(int*)rnode
->sysctl_data
= t
/ IEEE80211_INACT_WAIT
;
126 ieee80211_sysctl_parent(SYSCTLFN_ARGS
)
128 struct ieee80211com
*ic
;
129 char pname
[IFNAMSIZ
];
130 struct sysctlnode node
;
133 ic
= node
.sysctl_data
;
134 strncpy(pname
, ic
->ic_ifp
->if_xname
, IFNAMSIZ
);
135 node
.sysctl_data
= pname
;
136 return sysctl_lookup(SYSCTLFN_CALL(&node
));
140 * Create or get top of sysctl tree net.link.ieee80211.
142 static const struct sysctlnode
*
143 ieee80211_sysctl_treetop(struct sysctllog
**log
)
146 const struct sysctlnode
*rnode
;
148 if ((rc
= sysctl_createv(log
, 0, NULL
, &rnode
,
149 CTLFLAG_PERMANENT
, CTLTYPE_NODE
, "net", NULL
,
150 NULL
, 0, NULL
, 0, CTL_NET
, CTL_EOL
)) != 0)
153 if ((rc
= sysctl_createv(log
, 0, &rnode
, &rnode
,
154 CTLFLAG_PERMANENT
, CTLTYPE_NODE
, "link",
155 "link-layer statistics and controls",
156 NULL
, 0, NULL
, 0, PF_LINK
, CTL_EOL
)) != 0)
159 if ((rc
= sysctl_createv(log
, 0, &rnode
, &rnode
,
160 CTLFLAG_PERMANENT
, CTLTYPE_NODE
, "ieee80211",
161 "IEEE 802.11 WLAN statistics and controls",
162 NULL
, 0, NULL
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
167 printf("%s: sysctl_createv failed, rc = %d\n", __func__
, rc
);
172 ieee80211_sysctl_attach(struct ieee80211com
*ic
)
175 const struct sysctlnode
*cnode
, *rnode
;
176 char num
[sizeof("vap") + 14]; /* sufficient for 32 bits */
178 if ((rnode
= ieee80211_sysctl_treetop(NULL
)) == NULL
)
181 snprintf(num
, sizeof(num
), "vap%u", ic
->ic_vap
);
183 if ((rc
= sysctl_createv(&ic
->ic_sysctllog
, 0, &rnode
, &rnode
,
184 CTLFLAG_PERMANENT
, CTLTYPE_NODE
, num
, SYSCTL_DESCR("virtual AP"),
185 NULL
, 0, NULL
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
188 /* control debugging printfs */
189 if ((rc
= sysctl_createv(&ic
->ic_sysctllog
, 0, &rnode
, &cnode
,
190 CTLFLAG_PERMANENT
|CTLFLAG_READONLY
, CTLTYPE_STRING
,
191 "parent", SYSCTL_DESCR("parent device"),
192 ieee80211_sysctl_parent
, 0, ic
, IFNAMSIZ
, CTL_CREATE
,
196 #ifdef IEEE80211_DEBUG
197 /* control debugging printfs */
198 if ((rc
= sysctl_createv(&ic
->ic_sysctllog
, 0, &rnode
, &cnode
,
199 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
, CTLTYPE_INT
,
200 "debug", SYSCTL_DESCR("control debugging printfs"),
201 NULL
, ieee80211_debug
, &ic
->ic_debug
, 0,
202 CTL_CREATE
, CTL_EOL
)) != 0)
205 /* XXX inherit from tunables */
206 if ((rc
= sysctl_createv(&ic
->ic_sysctllog
, 0, &rnode
, &cnode
,
207 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
, CTLTYPE_INT
,
208 "inact_run", SYSCTL_DESCR("station inactivity timeout (sec)"),
209 ieee80211_sysctl_inact
, 0, &ic
->ic_inact_run
, 0,
210 CTL_CREATE
, CTL_EOL
)) != 0)
212 if ((rc
= sysctl_createv(&ic
->ic_sysctllog
, 0, &rnode
, &cnode
,
213 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
, CTLTYPE_INT
,
215 SYSCTL_DESCR("station inactivity probe timeout (sec)"),
216 ieee80211_sysctl_inact
, 0, &ic
->ic_inact_probe
, 0,
217 CTL_CREATE
, CTL_EOL
)) != 0)
219 if ((rc
= sysctl_createv(&ic
->ic_sysctllog
, 0, &rnode
, &cnode
,
220 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
, CTLTYPE_INT
,
222 SYSCTL_DESCR("station authentication timeout (sec)"),
223 ieee80211_sysctl_inact
, 0, &ic
->ic_inact_auth
, 0,
224 CTL_CREATE
, CTL_EOL
)) != 0)
226 if ((rc
= sysctl_createv(&ic
->ic_sysctllog
, 0, &rnode
, &cnode
,
227 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
, CTLTYPE_INT
,
229 SYSCTL_DESCR("station initial state timeout (sec)"),
230 ieee80211_sysctl_inact
, 0, &ic
->ic_inact_init
, 0,
231 CTL_CREATE
, CTL_EOL
)) != 0)
233 if ((rc
= sysctl_createv(&ic
->ic_sysctllog
, 0, &rnode
, &cnode
,
234 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
, CTLTYPE_INT
,
235 "driver_caps", SYSCTL_DESCR("driver capabilities"),
236 NULL
, 0, &ic
->ic_caps
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
238 if ((rc
= sysctl_createv(&ic
->ic_sysctllog
, 0, &rnode
, &cnode
,
239 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
, CTLTYPE_INT
,
240 "bmiss_max", SYSCTL_DESCR("consecutive beacon misses before scanning"),
241 NULL
, 0, &ic
->ic_bmiss_max
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
246 printf("%s: sysctl_createv failed, rc = %d\n", __func__
, rc
);
250 ieee80211_sysctl_detach(struct ieee80211com
*ic
)
252 sysctl_teardown(&ic
->ic_sysctllog
);
256 * Pointers for testing:
258 * If there are no interfaces, or else no 802.11 interfaces,
259 * ieee80211_node_walkfirst must return NULL.
261 * If there is any single 802.11 interface, ieee80211_node_walkfirst
262 * must not return NULL.
264 static struct ieee80211_node
*
265 ieee80211_node_walkfirst(struct ieee80211_node_walk
*nw
, u_short if_index
)
267 (void)memset(nw
, 0, sizeof(*nw
));
269 nw
->nw_ifindex
= if_index
;
271 LIST_FOREACH(nw
->nw_ic
, &ieee80211com_head
, ic_list
) {
272 if (if_index
!= 0 && nw
->nw_ic
->ic_ifp
->if_index
!= if_index
)
274 if (!TAILQ_EMPTY(&nw
->nw_ic
->ic_sta
.nt_node
))
275 nw
->nw_nt
= &nw
->nw_ic
->ic_sta
;
276 else if (!TAILQ_EMPTY(&nw
->nw_ic
->ic_scan
.nt_node
))
277 nw
->nw_nt
= &nw
->nw_ic
->ic_scan
;
278 else if (nw
->nw_ic
->ic_bss
== NULL
)
283 if (nw
->nw_ic
== NULL
)
286 if (nw
->nw_nt
== NULL
)
287 nw
->nw_ni
= nw
->nw_ic
->ic_bss
;
289 nw
->nw_ni
= TAILQ_FIRST(&nw
->nw_nt
->nt_node
);
294 static struct ieee80211_node
*
295 ieee80211_node_walknext(struct ieee80211_node_walk
*nw
)
297 if (nw
->nw_nt
!= NULL
)
298 nw
->nw_ni
= TAILQ_NEXT(nw
->nw_ni
, ni_list
);
302 while (nw
->nw_ni
== NULL
) {
303 if (nw
->nw_nt
== &nw
->nw_ic
->ic_sta
) {
304 nw
->nw_nt
= &nw
->nw_ic
->ic_scan
;
305 nw
->nw_ni
= TAILQ_FIRST(&nw
->nw_nt
->nt_node
);
307 } else if (nw
->nw_nt
== &nw
->nw_ic
->ic_scan
) {
309 nw
->nw_ni
= nw
->nw_ic
->ic_bss
;
312 KASSERT(nw
->nw_nt
== NULL
);
313 if (nw
->nw_ifindex
!= 0)
316 nw
->nw_ic
= LIST_NEXT(nw
->nw_ic
, ic_list
);
317 if (nw
->nw_ic
== NULL
)
320 nw
->nw_nt
= &nw
->nw_ic
->ic_sta
;
321 nw
->nw_ni
= TAILQ_FIRST(&nw
->nw_nt
->nt_node
);
328 ieee80211_sysctl_fill_node(struct ieee80211_node
*ni
,
329 struct ieee80211_node_sysctl
*ns
, int ifindex
,
330 const struct ieee80211_channel
*chan0
, uint32_t flags
)
332 ns
->ns_ifindex
= ifindex
;
333 ns
->ns_capinfo
= ni
->ni_capinfo
;
334 ns
->ns_flags
= flags
;
335 (void)memcpy(ns
->ns_macaddr
, ni
->ni_macaddr
, sizeof(ns
->ns_macaddr
));
336 (void)memcpy(ns
->ns_bssid
, ni
->ni_bssid
, sizeof(ns
->ns_bssid
));
337 if (ni
->ni_chan
!= IEEE80211_CHAN_ANYC
) {
338 ns
->ns_freq
= ni
->ni_chan
->ic_freq
;
339 ns
->ns_chanflags
= ni
->ni_chan
->ic_flags
;
340 ns
->ns_chanidx
= ni
->ni_chan
- chan0
;
342 ns
->ns_freq
= ns
->ns_chanflags
= 0;
345 ns
->ns_rssi
= ni
->ni_rssi
;
346 ns
->ns_esslen
= ni
->ni_esslen
;
347 (void)memcpy(ns
->ns_essid
, ni
->ni_essid
, sizeof(ns
->ns_essid
));
348 ns
->ns_erp
= ni
->ni_erp
;
349 ns
->ns_associd
= ni
->ni_associd
;
350 ns
->ns_inact
= ni
->ni_inact
* IEEE80211_INACT_WAIT
;
351 ns
->ns_rstamp
= ni
->ni_rstamp
;
352 ns
->ns_rates
= ni
->ni_rates
;
353 ns
->ns_txrate
= ni
->ni_txrate
;
354 ns
->ns_intval
= ni
->ni_intval
;
355 (void)memcpy(ns
->ns_tstamp
, &ni
->ni_tstamp
, sizeof(ns
->ns_tstamp
));
356 ns
->ns_txseq
= ni
->ni_txseqs
[0];
357 ns
->ns_rxseq
= ni
->ni_rxseqs
[0];
358 ns
->ns_fhdwell
= ni
->ni_fhdwell
;
359 ns
->ns_fhindex
= ni
->ni_fhindex
;
360 ns
->ns_fails
= ni
->ni_fails
;
363 /* Between two examinations of the sysctl tree, I expect each
364 * interface to add no more than 5 nodes.
366 #define IEEE80211_SYSCTL_NODE_GROWTH 5
369 ieee80211_sysctl_node(SYSCTLFN_ARGS
)
371 struct ieee80211_node_walk nw
;
372 struct ieee80211_node
*ni
;
373 struct ieee80211_node_sysctl ns
;
375 u_int cur_ifindex
, ifcount
, ifindex
, last_ifindex
, op
, arg
, hdr_type
;
377 size_t len
, needed
, eltsize
, out_size
;
378 int error
, s
, saw_bss
= 0, nelt
;
380 if (namelen
== 1 && name
[0] == CTL_QUERY
)
381 return (sysctl_query(SYSCTLFN_CALL(rnode
)));
383 if (namelen
!= IEEE80211_SYSCTL_NODENAMELEN
)
386 /* ifindex.op.arg.header-type.eltsize.nelt */
388 len
= (oldp
!= NULL
) ? *oldlenp
: 0;
389 ifindex
= name
[IEEE80211_SYSCTL_NODENAME_IF
];
390 op
= name
[IEEE80211_SYSCTL_NODENAME_OP
];
391 arg
= name
[IEEE80211_SYSCTL_NODENAME_ARG
];
392 hdr_type
= name
[IEEE80211_SYSCTL_NODENAME_TYPE
];
393 eltsize
= name
[IEEE80211_SYSCTL_NODENAME_ELTSIZE
];
394 nelt
= name
[IEEE80211_SYSCTL_NODENAME_ELTCOUNT
];
395 out_size
= MIN(sizeof(ns
), eltsize
);
397 if (op
!= IEEE80211_SYSCTL_OP_ALL
|| arg
!= 0 ||
398 hdr_type
!= IEEE80211_SYSCTL_T_NODE
|| eltsize
< 1 || nelt
< 0)
408 for (ni
= ieee80211_node_walkfirst(&nw
, ifindex
); ni
!= NULL
;
409 ni
= ieee80211_node_walknext(&nw
)) {
410 struct ieee80211com
*ic
;
413 cur_ifindex
= ic
->ic_ifp
->if_index
;
415 if (cur_ifindex
!= last_ifindex
) {
418 last_ifindex
= cur_ifindex
;
424 if (saw_bss
&& ni
== ic
->ic_bss
)
426 else if (ni
== ic
->ic_bss
) {
428 flags
= IEEE80211_NODE_SYSCTL_F_BSS
;
431 if (ni
->ni_table
== &ic
->ic_scan
)
432 flags
|= IEEE80211_NODE_SYSCTL_F_SCAN
;
433 else if (ni
->ni_table
== &ic
->ic_sta
)
434 flags
|= IEEE80211_NODE_SYSCTL_F_STA
;
435 if (len
>= eltsize
) {
436 ieee80211_sysctl_fill_node(ni
, &ns
, cur_ifindex
,
437 &ic
->ic_channels
[0], flags
);
438 error
= copyout(&ns
, dp
, out_size
);
453 *oldlenp
+= ifcount
* IEEE80211_SYSCTL_NODE_GROWTH
* eltsize
;
459 * Setup sysctl(3) MIB, net.ieee80211.*
461 * TBD condition CTLFLAG_PERMANENT on being a module or not
463 SYSCTL_SETUP(sysctl_ieee80211
, "sysctl ieee80211 subtree setup")
466 const struct sysctlnode
*cnode
, *rnode
;
468 if ((rnode
= ieee80211_sysctl_treetop(clog
)) == NULL
)
471 if ((rc
= sysctl_createv(clog
, 0, &rnode
, NULL
,
472 CTLFLAG_PERMANENT
, CTLTYPE_NODE
, "nodes", "client/peer stations",
473 ieee80211_sysctl_node
, 0, NULL
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
476 #ifdef IEEE80211_DEBUG
477 /* control debugging printfs */
478 if ((rc
= sysctl_createv(clog
, 0, &rnode
, &cnode
,
479 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
, CTLTYPE_INT
,
480 "debug", SYSCTL_DESCR("control debugging printfs"),
481 NULL
, 0, &ieee80211_debug
, 0, CTL_CREATE
, CTL_EOL
)) != 0)
483 #endif /* IEEE80211_DEBUG */
487 printf("%s: sysctl_createv failed (rc = %d)\n", __func__
, rc
);
491 ieee80211_node_dectestref(struct ieee80211_node
*ni
)
495 if (--ni
->ni_refcnt
== 0) {
505 ieee80211_drain_ifq(struct ifqueue
*ifq
)
507 struct ieee80211_node
*ni
;
515 ni
= (struct ieee80211_node
*)m
->m_pkthdr
.rcvif
;
517 ieee80211_free_node(ni
);
518 m
->m_pkthdr
.rcvif
= NULL
;
526 if_printf(struct ifnet
*ifp
, const char *fmt
, ...)
531 printf("%s: ", ifp
->if_xname
);
539 * Set the m_data pointer of a newly-allocated mbuf
540 * to place an object of the specified size at the
541 * end of the mbuf, longword aligned.
544 m_align(struct mbuf
*m
, int len
)
548 if (m
->m_flags
& M_EXT
)
549 adjust
= m
->m_ext
.ext_size
- len
;
550 else if (m
->m_flags
& M_PKTHDR
)
551 adjust
= MHLEN
- len
;
554 m
->m_data
+= adjust
&~ (sizeof(long)-1);
558 * Append the specified data to the indicated mbuf chain,
559 * Extend the mbuf chain if the new data does not fit in
562 * Return 1 if able to complete the job; otherwise 0.
565 m_append(struct mbuf
*m0
, int len
, const void *cpv
)
568 int remainder
, space
;
569 const char *cp
= cpv
;
571 for (m
= m0
; m
->m_next
!= NULL
; m
= m
->m_next
)
574 space
= M_TRAILINGSPACE(m
);
577 * Copy into available space.
579 if (space
> remainder
)
581 memmove(mtod(m
, char *) + m
->m_len
, cp
, space
);
583 cp
= cp
+ space
, remainder
-= space
;
585 while (remainder
> 0) {
587 * Allocate a new mbuf; could check space
588 * and allocate a cluster instead.
590 n
= m_get(M_DONTWAIT
, m
->m_type
);
593 n
->m_len
= min(MLEN
, remainder
);
594 memmove(mtod(n
, void *), cp
, n
->m_len
);
595 cp
+= n
->m_len
, remainder
-= n
->m_len
;
599 if (m0
->m_flags
& M_PKTHDR
)
600 m0
->m_pkthdr
.len
+= len
- remainder
;
601 return (remainder
== 0);
605 * Allocate and setup a management frame of the specified
606 * size. We return the mbuf and a pointer to the start
607 * of the contiguous data area that's been reserved based
608 * on the packet length. The data area is forced to 32-bit
609 * alignment and the buffer length to a multiple of 4 bytes.
610 * This is done mainly so beacon frames (that require this)
611 * can use this interface too.
614 ieee80211_getmgtframe(u_int8_t
**frm
, u_int pktlen
)
620 * NB: we know the mbuf routines will align the data area
621 * so we don't need to do anything special.
623 /* XXX 4-address frame? */
624 len
= roundup(sizeof(struct ieee80211_frame
) + pktlen
, 4);
625 IASSERT(len
<= MCLBYTES
, ("802.11 mgt frame too large: %u", len
));
627 m
= m_gethdr(M_NOWAIT
, MT_HEADER
);
629 * Align the data in case additional headers are added.
630 * This should only happen when a WEP header is added
631 * which only happens for shared key authentication mgt
632 * frames which all fit in MHLEN.
637 m
= m_getcl(M_NOWAIT
, MT_HEADER
, M_PKTHDR
);
639 m
->m_data
+= sizeof(struct ieee80211_frame
);
641 IASSERT((uintptr_t)*frm
% 4 == 0, ("bad beacon boundary"));
647 get_random_bytes(void *p
, size_t n
)
652 u_int32_t v
= arc4random();
653 size_t nb
= n
> sizeof(u_int32_t
) ? sizeof(u_int32_t
) : n
;
654 (void)memcpy(dp
, &v
, nb
);
655 dp
+= sizeof(u_int32_t
), n
-= nb
;
660 ieee80211_notify_node_join(struct ieee80211com
*ic
, struct ieee80211_node
*ni
, int newassoc
)
662 struct ifnet
*ifp
= ic
->ic_ifp
;
663 struct ieee80211_join_event iev
;
665 IEEE80211_DPRINTF(ic
, IEEE80211_MSG_NODE
, "%s: %snode %s join\n",
666 ifp
->if_xname
, (ni
== ic
->ic_bss
) ? "bss " : "",
667 ether_sprintf(ni
->ni_macaddr
));
669 memset(&iev
, 0, sizeof(iev
));
670 if (ni
== ic
->ic_bss
) {
671 IEEE80211_ADDR_COPY(iev
.iev_addr
, ni
->ni_bssid
);
672 rt_ieee80211msg(ifp
, newassoc
?
673 RTM_IEEE80211_ASSOC
: RTM_IEEE80211_REASSOC
,
675 if_link_state_change(ifp
, LINK_STATE_UP
);
677 IEEE80211_ADDR_COPY(iev
.iev_addr
, ni
->ni_macaddr
);
678 rt_ieee80211msg(ifp
, newassoc
?
679 RTM_IEEE80211_JOIN
: RTM_IEEE80211_REJOIN
,
685 ieee80211_notify_node_leave(struct ieee80211com
*ic
, struct ieee80211_node
*ni
)
687 struct ifnet
*ifp
= ic
->ic_ifp
;
688 struct ieee80211_leave_event iev
;
690 IEEE80211_DPRINTF(ic
, IEEE80211_MSG_NODE
, "%s: %snode %s leave\n",
691 ifp
->if_xname
, (ni
== ic
->ic_bss
) ? "bss " : "",
692 ether_sprintf(ni
->ni_macaddr
));
694 if (ni
== ic
->ic_bss
) {
695 rt_ieee80211msg(ifp
, RTM_IEEE80211_DISASSOC
, NULL
, 0);
696 if_link_state_change(ifp
, LINK_STATE_DOWN
);
698 /* fire off wireless event station leaving */
699 memset(&iev
, 0, sizeof(iev
));
700 IEEE80211_ADDR_COPY(iev
.iev_addr
, ni
->ni_macaddr
);
701 rt_ieee80211msg(ifp
, RTM_IEEE80211_LEAVE
, &iev
, sizeof(iev
));
706 ieee80211_notify_scan_done(struct ieee80211com
*ic
)
708 struct ifnet
*ifp
= ic
->ic_ifp
;
710 IEEE80211_DPRINTF(ic
, IEEE80211_MSG_SCAN
,
711 "%s: notify scan done\n", ic
->ic_ifp
->if_xname
);
713 /* dispatch wireless event indicating scan completed */
714 rt_ieee80211msg(ifp
, RTM_IEEE80211_SCAN
, NULL
, 0);
718 ieee80211_notify_replay_failure(struct ieee80211com
*ic
,
719 const struct ieee80211_frame
*wh
, const struct ieee80211_key
*k
,
722 struct ifnet
*ifp
= ic
->ic_ifp
;
724 IEEE80211_DPRINTF(ic
, IEEE80211_MSG_CRYPTO
,
725 "[%s] %s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>\n",
726 ether_sprintf(wh
->i_addr2
), k
->wk_cipher
->ic_name
,
727 (intmax_t) rsc
, (intmax_t) k
->wk_keyrsc
,
728 k
->wk_keyix
, k
->wk_rxkeyix
);
730 if (ifp
!= NULL
) { /* NB: for cipher test modules */
731 struct ieee80211_replay_event iev
;
733 IEEE80211_ADDR_COPY(iev
.iev_dst
, wh
->i_addr1
);
734 IEEE80211_ADDR_COPY(iev
.iev_src
, wh
->i_addr2
);
735 iev
.iev_cipher
= k
->wk_cipher
->ic_cipher
;
736 if (k
->wk_rxkeyix
!= IEEE80211_KEYIX_NONE
)
737 iev
.iev_keyix
= k
->wk_rxkeyix
;
739 iev
.iev_keyix
= k
->wk_keyix
;
740 iev
.iev_keyrsc
= k
->wk_keyrsc
;
742 rt_ieee80211msg(ifp
, RTM_IEEE80211_REPLAY
, &iev
, sizeof(iev
));
747 ieee80211_notify_michael_failure(struct ieee80211com
*ic
,
748 const struct ieee80211_frame
*wh
, u_int keyix
)
750 struct ifnet
*ifp
= ic
->ic_ifp
;
752 IEEE80211_DPRINTF(ic
, IEEE80211_MSG_CRYPTO
,
753 "[%s] michael MIC verification failed <keyix %u>\n",
754 ether_sprintf(wh
->i_addr2
), keyix
);
755 ic
->ic_stats
.is_rx_tkipmic
++;
757 if (ifp
!= NULL
) { /* NB: for cipher test modules */
758 struct ieee80211_michael_event iev
;
760 IEEE80211_ADDR_COPY(iev
.iev_dst
, wh
->i_addr1
);
761 IEEE80211_ADDR_COPY(iev
.iev_src
, wh
->i_addr2
);
762 iev
.iev_cipher
= IEEE80211_CIPHER_TKIP
;
763 iev
.iev_keyix
= keyix
;
764 rt_ieee80211msg(ifp
, RTM_IEEE80211_MICHAEL
, &iev
, sizeof(iev
));
769 ieee80211_load_module(const char *modname
)
772 struct thread
*td
= curthread
;
774 if (suser(td
) == 0 && securelevel_gt(td
->td_ucred
, 0) == 0) {
776 (void) linker_load_module(modname
, NULL
, NULL
, NULL
, NULL
);
780 printf("%s: load the %s module by hand for now.\n", __func__
, modname
);