09017ca2017876eab33c9c386d2d45f183e28c78
[dragonfly.git] / sys / netproto / 802_11 / wlan / ieee80211_dragonfly.c
1 /*-
2  * Copyright (c) 2003-2009 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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.
24  *
25  * $FreeBSD: head/sys/net80211/ieee80211_freebsd.c 202612 2010-01-19 05:00:57Z thompsa $
26  * $DragonFly$
27  */
28
29 /*
30  * IEEE 802.11 support (DragonFlyBSD-specific code)
31  */
32 #include "opt_wlan.h"
33
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h> 
37 #include <sys/linker.h>
38 #include <sys/mbuf.h>   
39 #include <sys/module.h>
40 #include <sys/proc.h>
41 #include <sys/sysctl.h>
42
43 #include <sys/socket.h>
44
45 #include <net/bpf.h>
46 #include <net/if.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
54 #include <netproto/802_11/ieee80211_var.h>
55 #include <netproto/802_11/ieee80211_input.h>
56
57 SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters");
58
59 #ifdef IEEE80211_DEBUG
60 int     ieee80211_debug = 0;
61 SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug,
62             0, "debugging printfs");
63 #endif
64
65 MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state");
66
67
68 static void     wlan_clone_destroy(struct ifnet *);
69 static int      wlan_clone_create(struct if_clone *, int, caddr_t);
70
71 static struct if_clone wlan_cloner = 
72         IF_CLONE_INITIALIZER("wlan", wlan_clone_create, wlan_clone_destroy,
73             0, IF_MAXUNIT);
74
75
76 /*
77  * Allocate/free com structure in conjunction with ifnet;
78  * these routines are registered with if_register_com_alloc
79  * below and are called automatically by the ifnet code
80  * when the ifnet of the parent device is created.
81  */
82 static void *
83 wlan_alloc(u_char type, struct ifnet *ifp)
84 {
85         struct ieee80211com *ic;
86
87         ic = kmalloc(sizeof(struct ieee80211com), M_80211_COM, M_WAITOK|M_ZERO);
88         ic->ic_ifp = ifp;
89
90         return (ic);
91 }
92
93 static void
94 wlan_free(void *ic, u_char type)
95 {
96         kfree(ic, M_80211_COM);
97 }
98
99 static int
100 wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params)
101 {
102         struct ieee80211_clone_params cp;
103         struct ieee80211vap *vap;
104         struct ieee80211com *ic;
105         struct ifnet *ifp;
106         int error;
107
108         error = copyin(params, &cp, sizeof(cp));
109         if (error)
110                 return error;
111         ifp = ifunit(cp.icp_parent);
112         if (ifp == NULL)
113                 return ENXIO;
114         /* XXX move printfs to DIAGNOSTIC before release */
115         if (ifp->if_type != IFT_IEEE80211) {
116                 if_printf(ifp, "%s: reject, not an 802.11 device\n", __func__);
117                 return ENXIO;
118         }
119         if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) {
120                 if_printf(ifp, "%s: invalid opmode %d\n",
121                     __func__, cp.icp_opmode);
122                 return EINVAL;
123         }
124         ic = ifp->if_l2com;
125         if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) {
126                 if_printf(ifp, "%s mode not supported\n",
127                     ieee80211_opmode_name[cp.icp_opmode]);
128                 return EOPNOTSUPP;
129         }
130         if ((cp.icp_flags & IEEE80211_CLONE_TDMA) &&
131 #ifdef IEEE80211_SUPPORT_TDMA
132             (ic->ic_caps & IEEE80211_C_TDMA) == 0
133 #else
134             (1)
135 #endif
136         ) {
137                 if_printf(ifp, "TDMA not supported\n");
138                 return EOPNOTSUPP;
139         }
140         vap = ic->ic_vap_create(ic, ifc->ifc_name, unit,
141                         cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
142                         cp.icp_flags & IEEE80211_CLONE_MACADDR ?
143                             cp.icp_macaddr : (const uint8_t *)IF_LLADDR(ifp));
144         return (vap == NULL ? EIO : 0);
145 }
146
147 static void
148 wlan_clone_destroy(struct ifnet *ifp)
149 {
150         struct ieee80211vap *vap = ifp->if_softc;
151         struct ieee80211com *ic = vap->iv_ic;
152
153         ic->ic_vap_delete(vap);
154 }
155
156 void
157 ieee80211_vap_destroy(struct ieee80211vap *vap)
158 {
159 #ifdef __FreeBSD__
160         if_clone_destroyif(&wlan_cloner, vap->iv_ifp);
161 #endif
162 }
163
164 int
165 ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS)
166 {
167         int msecs = ticks_to_msecs(*(int *)arg1);
168         int error, t;
169
170         error = sysctl_handle_int(oidp, &msecs, 0, req);
171         if (error || !req->newptr)
172                 return error;
173         t = msecs_to_ticks(msecs);
174         *(int *)arg1 = (t < 1) ? 1 : t;
175         return 0;
176 }
177
178 static int
179 ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS)
180 {
181         int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT;
182         int error;
183
184         error = sysctl_handle_int(oidp, &inact, 0, req);
185         if (error || !req->newptr)
186                 return error;
187         *(int *)arg1 = inact / IEEE80211_INACT_WAIT;
188         return 0;
189 }
190
191 static int
192 ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS)
193 {
194         struct ieee80211com *ic = arg1;
195         const char *name = ic->ic_ifp->if_xname;
196
197         return SYSCTL_OUT(req, name, strlen(name));
198 }
199
200 static int
201 ieee80211_sysctl_radar(SYSCTL_HANDLER_ARGS)
202 {
203         struct ieee80211com *ic = arg1;
204         int t = 0, error;
205
206         error = sysctl_handle_int(oidp, &t, 0, req);
207         if (error || !req->newptr)
208                 return error;
209         IEEE80211_LOCK(ic);
210         ieee80211_dfs_notify_radar(ic, ic->ic_curchan);
211         IEEE80211_UNLOCK(ic);
212         return 0;
213 }
214
215 void
216 ieee80211_sysctl_attach(struct ieee80211com *ic)
217 {
218 }
219
220 void
221 ieee80211_sysctl_detach(struct ieee80211com *ic)
222 {
223 }
224
225 void
226 ieee80211_sysctl_vattach(struct ieee80211vap *vap)
227 {
228         struct ifnet *ifp = vap->iv_ifp;
229         struct sysctl_ctx_list *ctx;
230         struct sysctl_oid *oid;
231         char num[14];                   /* sufficient for 32 bits */
232
233         ctx = (struct sysctl_ctx_list *) kmalloc(sizeof(struct sysctl_ctx_list),
234                 M_DEVBUF, M_NOWAIT | M_ZERO);
235         if (ctx == NULL) {
236                 if_printf(ifp, "%s: cannot allocate sysctl context!\n",
237                         __func__);
238                 return;
239         }
240         sysctl_ctx_init(ctx);
241         ksnprintf(num, sizeof(num), "%u", ifp->if_dunit);
242         oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan),
243                 OID_AUTO, num, CTLFLAG_RD, NULL, "");
244         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
245                 "%parent", CTLFLAG_RD, vap->iv_ic, 0,
246                 ieee80211_sysctl_parent, "A", "parent device");
247         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
248                 "driver_caps", CTLFLAG_RW, &vap->iv_caps, 0,
249                 "driver capabilities");
250 #ifdef IEEE80211_DEBUG
251         vap->iv_debug = ieee80211_debug;
252         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
253                 "debug", CTLFLAG_RW, &vap->iv_debug, 0,
254                 "control debugging printfs");
255 #endif
256         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
257                 "bmiss_max", CTLFLAG_RW, &vap->iv_bmiss_max, 0,
258                 "consecutive beacon misses before scanning");
259         /* XXX inherit from tunables */
260         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
261                 "inact_run", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_run, 0,
262                 ieee80211_sysctl_inact, "I",
263                 "station inactivity timeout (sec)");
264         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
265                 "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_probe, 0,
266                 ieee80211_sysctl_inact, "I",
267                 "station inactivity probe timeout (sec)");
268         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
269                 "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_auth, 0,
270                 ieee80211_sysctl_inact, "I",
271                 "station authentication timeout (sec)");
272         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
273                 "inact_init", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_init, 0,
274                 ieee80211_sysctl_inact, "I",
275                 "station initial state timeout (sec)");
276         if (vap->iv_htcaps & IEEE80211_HTC_HT) {
277                 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
278                         "ampdu_mintraffic_bk", CTLFLAG_RW,
279                         &vap->iv_ampdu_mintraffic[WME_AC_BK], 0,
280                         "BK traffic tx aggr threshold (pps)");
281                 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
282                         "ampdu_mintraffic_be", CTLFLAG_RW,
283                         &vap->iv_ampdu_mintraffic[WME_AC_BE], 0,
284                         "BE traffic tx aggr threshold (pps)");
285                 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
286                         "ampdu_mintraffic_vo", CTLFLAG_RW,
287                         &vap->iv_ampdu_mintraffic[WME_AC_VO], 0,
288                         "VO traffic tx aggr threshold (pps)");
289                 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
290                         "ampdu_mintraffic_vi", CTLFLAG_RW,
291                         &vap->iv_ampdu_mintraffic[WME_AC_VI], 0,
292                         "VI traffic tx aggr threshold (pps)");
293         }
294         if (vap->iv_caps & IEEE80211_C_DFS) {
295                 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
296                         "radar", CTLTYPE_INT | CTLFLAG_RW, vap->iv_ic, 0,
297                         ieee80211_sysctl_radar, "I", "simulate radar event");
298         }
299         vap->iv_sysctl = ctx;
300         vap->iv_oid = oid;
301 }
302
303 void
304 ieee80211_sysctl_vdetach(struct ieee80211vap *vap)
305 {
306
307         if (vap->iv_sysctl != NULL) {
308                 sysctl_ctx_free(vap->iv_sysctl);
309                 kfree(vap->iv_sysctl, M_DEVBUF);
310                 vap->iv_sysctl = NULL;
311         }
312 }
313
314 int
315 ieee80211_node_dectestref(struct ieee80211_node *ni)
316 {
317         /* XXX need equivalent of atomic_dec_and_test */
318         atomic_subtract_int(&ni->ni_refcnt, 1);
319         return atomic_cmpset_int(&ni->ni_refcnt, 0, 1);
320 }
321
322 void
323 ieee80211_drain_ifq(struct ifqueue *ifq)
324 {
325         struct ieee80211_node *ni;
326         struct mbuf *m;
327
328         for (;;) {
329                 IF_DEQUEUE(ifq, m);
330                 if (m == NULL)
331                         break;
332
333                 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
334                 KASSERT(ni != NULL, ("frame w/o node"));
335                 ieee80211_free_node(ni);
336                 m->m_pkthdr.rcvif = NULL;
337
338                 m_freem(m);
339         }
340 }
341
342 void
343 ieee80211_flush_ifq(struct ifqueue *ifq, struct ieee80211vap *vap)
344 {
345         struct ieee80211_node *ni;
346         struct mbuf *m, **mprev;
347
348         IF_LOCK(ifq);
349         mprev = &ifq->ifq_head;
350         while ((m = *mprev) != NULL) {
351                 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
352                 if (ni != NULL && ni->ni_vap == vap) {
353                         *mprev = m->m_nextpkt;          /* remove from list */
354                         ifq->ifq_len--;
355
356                         m_freem(m);
357                         ieee80211_free_node(ni);        /* reclaim ref */
358                 } else
359                         mprev = &m->m_nextpkt;
360         }
361         /* recalculate tail ptr */
362         m = ifq->ifq_head;
363         for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt)
364                 ;
365         ifq->ifq_tail = m;
366         IF_UNLOCK(ifq);
367 }
368
369 /*
370  * As above, for mbufs allocated with m_gethdr/MGETHDR
371  * or initialized by M_COPY_PKTHDR.
372  */
373 #define MC_ALIGN(m, len)                                                \
374 do {                                                                    \
375         (m)->m_data += (MCLBYTES - (len)) &~ (sizeof(long) - 1);        \
376 } while (/* CONSTCOND */ 0)
377
378 /*
379  * Allocate and setup a management frame of the specified
380  * size.  We return the mbuf and a pointer to the start
381  * of the contiguous data area that's been reserved based
382  * on the packet length.  The data area is forced to 32-bit
383  * alignment and the buffer length to a multiple of 4 bytes.
384  * This is done mainly so beacon frames (that require this)
385  * can use this interface too.
386  */
387 struct mbuf *
388 ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen)
389 {
390         struct mbuf *m;
391         u_int len;
392
393         /*
394          * NB: we know the mbuf routines will align the data area
395          *     so we don't need to do anything special.
396          */
397         len = roundup2(headroom + pktlen, 4);
398         KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
399         if (len < MINCLSIZE) {
400                 m = m_gethdr(M_NOWAIT, MT_DATA);
401                 /*
402                  * Align the data in case additional headers are added.
403                  * This should only happen when a WEP header is added
404                  * which only happens for shared key authentication mgt
405                  * frames which all fit in MHLEN.
406                  */
407                 if (m != NULL)
408                         MH_ALIGN(m, len);
409         } else {
410                 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
411                 if (m != NULL)
412                         MC_ALIGN(m, len);
413         }
414         if (m != NULL) {
415                 m->m_data += headroom;
416                 *frm = m->m_data;
417         }
418         return m;
419 }
420
421 /*
422  * Re-align the payload in the mbuf.  This is mainly used (right now)
423  * to handle IP header alignment requirements on certain architectures.
424  */
425 struct mbuf *
426 ieee80211_realign(struct ieee80211vap *vap, struct mbuf *m, size_t align)
427 {
428         int pktlen, space;
429         struct mbuf *n = NULL;
430
431         pktlen = m->m_pkthdr.len;
432         space = pktlen + align;
433         if (space < MINCLSIZE)
434                 n = m_gethdr(MB_DONTWAIT, MT_DATA);
435 #ifdef notyet
436         else {
437                 n = m_getjcl(MB_DONTWAIT, MT_DATA, M_PKTHDR,
438                     space <= MCLBYTES ?     MCLBYTES :
439 #if MJUMPAGESIZE != MCLBYTES
440                     space <= MJUMPAGESIZE ? MJUMPAGESIZE :
441 #endif
442                     space <= MJUM9BYTES ?   MJUM9BYTES : MJUM16BYTES);
443         }
444 #endif
445         if (__predict_true(n != NULL)) {
446                 m_move_pkthdr(n, m);
447                 n->m_data = (caddr_t)(ALIGN(n->m_data + align) - align);
448                 m_copydata(m, 0, pktlen, mtod(n, caddr_t));
449                 n->m_len = pktlen;
450         } else {
451                 IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
452                     mtod(m, const struct ieee80211_frame *), NULL,
453                     "%s", "no mbuf to realign");
454                 vap->iv_stats.is_rx_badalign++;
455         }
456         m_freem(m);
457         return n;
458 }
459
460 int
461 ieee80211_add_callback(struct mbuf *m,
462         void (*func)(struct ieee80211_node *, void *, int), void *arg)
463 {
464         struct m_tag *mtag;
465         struct ieee80211_cb *cb;
466
467         mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK,
468                         sizeof(struct ieee80211_cb), M_NOWAIT);
469         if (mtag == NULL)
470                 return 0;
471
472         cb = (struct ieee80211_cb *)(mtag+1);
473         cb->func = func;
474         cb->arg = arg;
475         m_tag_prepend(m, mtag);
476         m->m_flags |= M_TXCB;
477         return 1;
478 }
479
480 void
481 ieee80211_process_callback(struct ieee80211_node *ni,
482         struct mbuf *m, int status)
483 {
484         struct m_tag *mtag;
485
486         mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL);
487         if (mtag != NULL) {
488                 struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1);
489                 cb->func(ni, cb->arg, status);
490         }
491 }
492
493 #include <sys/libkern.h>
494
495 void
496 get_random_bytes(void *p, size_t n)
497 {
498         uint8_t *dp = p;
499
500         while (n > 0) {
501                 uint32_t v = karc4random();
502                 size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n;
503                 bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n);
504                 dp += sizeof(uint32_t), n -= nb;
505         }
506 }
507
508 /*
509  * Helper function for events that pass just a single mac address.
510  */
511 static void
512 notify_macaddr(struct ifnet *ifp, int op, const uint8_t mac[IEEE80211_ADDR_LEN])
513 {
514         struct ieee80211_join_event iev;
515
516         memset(&iev, 0, sizeof(iev));
517         IEEE80211_ADDR_COPY(iev.iev_addr, mac);
518         rt_ieee80211msg(ifp, op, &iev, sizeof(iev));
519 }
520
521 void
522 ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc)
523 {
524         struct ieee80211vap *vap = ni->ni_vap;
525         struct ifnet *ifp = vap->iv_ifp;
526
527         IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode join",
528             (ni == vap->iv_bss) ? "bss " : "");
529
530         if (ni == vap->iv_bss) {
531                 notify_macaddr(ifp, newassoc ?
532                     RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, ni->ni_bssid);
533                 if_link_state_change(ifp);
534         } else {
535                 notify_macaddr(ifp, newassoc ?
536                     RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, ni->ni_macaddr);
537         }
538 }
539
540 void
541 ieee80211_notify_node_leave(struct ieee80211_node *ni)
542 {
543         struct ieee80211vap *vap = ni->ni_vap;
544         struct ifnet *ifp = vap->iv_ifp;
545
546         IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode leave",
547             (ni == vap->iv_bss) ? "bss " : "");
548
549         if (ni == vap->iv_bss) {
550                 rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0);
551                 if_link_state_change(ifp);
552         } else {
553                 /* fire off wireless event station leaving */
554                 notify_macaddr(ifp, RTM_IEEE80211_LEAVE, ni->ni_macaddr);
555         }
556 }
557
558 void
559 ieee80211_notify_scan_done(struct ieee80211vap *vap)
560 {
561         struct ifnet *ifp = vap->iv_ifp;
562
563         IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n", "notify scan done");
564
565         /* dispatch wireless event indicating scan completed */
566         rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0);
567 }
568
569 void
570 ieee80211_notify_replay_failure(struct ieee80211vap *vap,
571         const struct ieee80211_frame *wh, const struct ieee80211_key *k,
572         u_int64_t rsc, int tid)
573 {
574         struct ifnet *ifp = vap->iv_ifp;
575
576         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
577             "%s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>",
578             k->wk_cipher->ic_name, (intmax_t) rsc,
579             (intmax_t) k->wk_keyrsc[tid],
580             k->wk_keyix, k->wk_rxkeyix);
581
582         if (ifp != NULL) {              /* NB: for cipher test modules */
583                 struct ieee80211_replay_event iev;
584
585                 IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
586                 IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
587                 iev.iev_cipher = k->wk_cipher->ic_cipher;
588                 if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE)
589                         iev.iev_keyix = k->wk_rxkeyix;
590                 else
591                         iev.iev_keyix = k->wk_keyix;
592                 iev.iev_keyrsc = k->wk_keyrsc[tid];
593                 iev.iev_rsc = rsc;
594                 rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev));
595         }
596 }
597
598 void
599 ieee80211_notify_michael_failure(struct ieee80211vap *vap,
600         const struct ieee80211_frame *wh, u_int keyix)
601 {
602         struct ifnet *ifp = vap->iv_ifp;
603
604         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
605             "michael MIC verification failed <keyix %u>", keyix);
606         vap->iv_stats.is_rx_tkipmic++;
607
608         if (ifp != NULL) {              /* NB: for cipher test modules */
609                 struct ieee80211_michael_event iev;
610
611                 IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
612                 IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
613                 iev.iev_cipher = IEEE80211_CIPHER_TKIP;
614                 iev.iev_keyix = keyix;
615                 rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev));
616         }
617 }
618
619 void
620 ieee80211_notify_wds_discover(struct ieee80211_node *ni)
621 {
622         struct ieee80211vap *vap = ni->ni_vap;
623         struct ifnet *ifp = vap->iv_ifp;
624
625         notify_macaddr(ifp, RTM_IEEE80211_WDS, ni->ni_macaddr);
626 }
627
628 void
629 ieee80211_notify_csa(struct ieee80211com *ic,
630         const struct ieee80211_channel *c, int mode, int count)
631 {
632         struct ifnet *ifp = ic->ic_ifp;
633         struct ieee80211_csa_event iev;
634
635         memset(&iev, 0, sizeof(iev));
636         iev.iev_flags = c->ic_flags;
637         iev.iev_freq = c->ic_freq;
638         iev.iev_ieee = c->ic_ieee;
639         iev.iev_mode = mode;
640         iev.iev_count = count;
641         rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev));
642 }
643
644 void
645 ieee80211_notify_radar(struct ieee80211com *ic,
646         const struct ieee80211_channel *c)
647 {
648         struct ifnet *ifp = ic->ic_ifp;
649         struct ieee80211_radar_event iev;
650
651         memset(&iev, 0, sizeof(iev));
652         iev.iev_flags = c->ic_flags;
653         iev.iev_freq = c->ic_freq;
654         iev.iev_ieee = c->ic_ieee;
655         rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev));
656 }
657
658 void
659 ieee80211_notify_cac(struct ieee80211com *ic,
660         const struct ieee80211_channel *c, enum ieee80211_notify_cac_event type)
661 {
662         struct ifnet *ifp = ic->ic_ifp;
663         struct ieee80211_cac_event iev;
664
665         memset(&iev, 0, sizeof(iev));
666         iev.iev_flags = c->ic_flags;
667         iev.iev_freq = c->ic_freq;
668         iev.iev_ieee = c->ic_ieee;
669         iev.iev_type = type;
670         rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev));
671 }
672
673 void
674 ieee80211_notify_node_deauth(struct ieee80211_node *ni)
675 {
676         struct ieee80211vap *vap = ni->ni_vap;
677         struct ifnet *ifp = vap->iv_ifp;
678
679         IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node deauth");
680
681         notify_macaddr(ifp, RTM_IEEE80211_DEAUTH, ni->ni_macaddr);
682 }
683
684 void
685 ieee80211_notify_node_auth(struct ieee80211_node *ni)
686 {
687         struct ieee80211vap *vap = ni->ni_vap;
688         struct ifnet *ifp = vap->iv_ifp;
689
690         IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node auth");
691
692         notify_macaddr(ifp, RTM_IEEE80211_AUTH, ni->ni_macaddr);
693 }
694
695 void
696 ieee80211_notify_country(struct ieee80211vap *vap,
697         const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2])
698 {
699         struct ifnet *ifp = vap->iv_ifp;
700         struct ieee80211_country_event iev;
701
702         memset(&iev, 0, sizeof(iev));
703         IEEE80211_ADDR_COPY(iev.iev_addr, bssid);
704         iev.iev_cc[0] = cc[0];
705         iev.iev_cc[1] = cc[1];
706         rt_ieee80211msg(ifp, RTM_IEEE80211_COUNTRY, &iev, sizeof(iev));
707 }
708
709 void
710 ieee80211_notify_radio(struct ieee80211com *ic, int state)
711 {
712         struct ifnet *ifp = ic->ic_ifp;
713         struct ieee80211_radio_event iev;
714
715         memset(&iev, 0, sizeof(iev));
716         iev.iev_state = state;
717         rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev));
718 }
719
720 void
721 ieee80211_load_module(const char *modname)
722 {
723
724 #ifdef notyet
725         (void)kern_kldload(curthread, modname, NULL);
726 #else
727         kprintf("%s: load the %s module by hand for now.\n", __func__, modname);
728 #endif
729 }
730
731 static eventhandler_tag wlan_bpfevent;
732 static eventhandler_tag wlan_ifllevent;
733
734 static void
735 bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach)
736 {
737         /* NB: identify vap's by if_start */
738         if (dlt == DLT_IEEE802_11_RADIO && ifp->if_start == ieee80211_start) {
739 #ifdef notyet
740                 struct ieee80211vap *vap = ifp->if_softc;
741 #endif
742                 /*
743                  * Track bpf radiotap listener state.  We mark the vap
744                  * to indicate if any listener is present and the com
745                  * to indicate if any listener exists on any associated
746                  * vap.  This flag is used by drivers to prepare radiotap
747                  * state only when needed.
748                  */
749 #ifdef notyet
750                 if (attach) {
751                         ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF);
752                         if (vap->iv_opmode == IEEE80211_M_MONITOR)
753                                 atomic_add_int(&vap->iv_ic->ic_montaps, 1);
754                 } else if (!bpf_peers_present(vap->iv_rawbpf)) {
755                         ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF);
756                         if (vap->iv_opmode == IEEE80211_M_MONITOR)
757                                 atomic_subtract_int(&vap->iv_ic->ic_montaps, 1);
758                 }
759 #endif
760         }
761 }
762
763 static void
764 wlan_iflladdr(void *arg __unused, struct ifnet *ifp)
765 {
766         struct ieee80211com *ic = ifp->if_l2com;
767         struct ieee80211vap *vap, *next;
768
769         if (ifp->if_type != IFT_IEEE80211 || ic == NULL)
770                 return;
771
772         IEEE80211_LOCK(ic);
773         TAILQ_FOREACH_MUTABLE(vap, &ic->ic_vaps, iv_next, next) {
774                 /*
775                  * If the MAC address has changed on the parent and it was
776                  * copied to the vap on creation then re-sync.
777                  */
778                 if (vap->iv_ic == ic &&
779                     (vap->iv_flags_ext & IEEE80211_FEXT_UNIQMAC) == 0) {
780                         IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp));
781                         IEEE80211_UNLOCK(ic);
782                         if_setlladdr(vap->iv_ifp, IF_LLADDR(ifp),
783                             IEEE80211_ADDR_LEN);
784                         IEEE80211_LOCK(ic);
785                 }
786         }
787         IEEE80211_UNLOCK(ic);
788 }
789
790 /*
791  * Module glue.
792  *
793  * NB: the module name is "wlan" for compatibility with NetBSD.
794  */
795 static int
796 wlan_modevent(module_t mod, int type, void *unused)
797 {
798         switch (type) {
799         case MOD_LOAD:
800                 if (bootverbose)
801                         kprintf("wlan: <802.11 Link Layer>\n");
802                 wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track,
803                     bpf_track, 0, EVENTHANDLER_PRI_ANY);
804                 if (wlan_bpfevent == NULL)
805                         return ENOMEM;
806                 wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,
807                     wlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
808                 if (wlan_ifllevent == NULL) {
809                         EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
810                         return ENOMEM;
811                 }
812                 if_clone_attach(&wlan_cloner);
813                 if_register_com_alloc(IFT_IEEE80211, wlan_alloc, wlan_free);
814                 return 0;
815         case MOD_UNLOAD:
816                 if_deregister_com_alloc(IFT_IEEE80211);
817                 if_clone_detach(&wlan_cloner);
818                 EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
819                 EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent);
820                 return 0;
821         }
822         return EINVAL;
823 }
824
825 static moduledata_t wlan_mod = {
826         "wlan",
827         wlan_modevent,
828         0
829 };
830 DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
831 MODULE_VERSION(wlan, 1);
832 MODULE_DEPEND(wlan, ether, 1, 1, 1);