10a0cc313b1e13905725aa24cd522fe47509da47
[dragonfly.git] / sys / dev / netif / awi / awi.c
1 /*-
2  * Copyright (c) 1999 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Bill Sommerfeld
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *        This product includes software developed by the NetBSD
19  *        Foundation, Inc. and its contributors.
20  * 4. Neither the name of The NetBSD Foundation nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $NetBSD: awi.c,v 1.26 2000/07/21 04:48:55 onoe Exp $
37  * $FreeBSD: src/sys/dev/awi/awi.c,v 1.10.2.2 2003/01/23 21:06:42 sam Exp $
38  * $DragonFly: src/sys/dev/netif/awi/Attic/awi.c,v 1.25 2005/11/28 17:13:41 dillon Exp $
39  */
40 /*
41  * Driver for AMD 802.11 firmware.
42  * Uses am79c930 chip driver to talk to firmware running on the am79c930.
43  *
44  * More-or-less a generic ethernet-like if driver, with 802.11 gorp added.
45  */
46
47 /*
48  * todo:
49  *      - flush tx queue on resynch.
50  *      - clear oactive on "down".
51  *      - rewrite copy-into-mbuf code
52  *      - mgmt state machine gets stuck retransmitting assoc requests.
53  *      - multicast filter.
54  *      - fix device reset so it's more likely to work
55  *      - show status goo through ifmedia.
56  *
57  * more todo:
58  *      - deal with more 802.11 frames.
59  *              - send reassoc request
60  *              - deal with reassoc response
61  *              - send/deal with disassociation
62  *      - deal with "full" access points (no room for me).
63  *      - power save mode
64  *
65  * later:
66  *      - SSID preferences
67  *      - need ioctls for poking at the MIBs
68  *      - implement ad-hoc mode (including bss creation).
69  *      - decide when to do "ad hoc" vs. infrastructure mode (IFF_LINK flags?)
70  *              (focus on inf. mode since that will be needed for ietf)
71  *      - deal with DH vs. FH versions of the card
72  *      - deal with faster cards (2mb/s)
73  *      - ?WEP goo (mmm, rc4) (it looks not particularly useful).
74  *      - ifmedia revision.
75  *      - common 802.11 mibish things.
76  *      - common 802.11 media layer.
77  */
78
79 /*
80  * Driver for AMD 802.11 PCnetMobile firmware.
81  * Uses am79c930 chip driver to talk to firmware running on the am79c930.
82  *
83  * The initial version of the driver was written by
84  * Bill Sommerfeld <sommerfeld@netbsd.org>.
85  * Then the driver module completely rewritten to support cards with DS phy
86  * and to support adhoc mode by Atsushi Onoe <onoe@netbsd.org>
87  */
88
89 #include "opt_inet.h"
90
91 #include <sys/param.h>
92 #include <sys/systm.h>
93 #include <sys/kernel.h>
94 #include <sys/mbuf.h>
95 #include <sys/malloc.h>
96 #include <sys/proc.h>
97 #include <sys/socket.h>
98 #include <sys/sockio.h>
99 #include <sys/errno.h>
100 #include <sys/syslog.h>
101 #include <sys/bus.h>
102 #include <sys/thread2.h>
103
104 #include <net/if.h>
105 #include <net/ifq_var.h>
106 #include <net/if_dl.h>
107 #include <net/ethernet.h>
108 #include <net/if_media.h>
109 #include <net/if_llc.h>
110 #include <netproto/802_11/ieee80211.h>
111 #include <netproto/802_11/ieee80211_ioctl.h>
112
113 #ifdef INET
114 #include <netinet/in.h>
115 #include <netinet/in_systm.h>
116 #include <netinet/in_var.h>
117 #include <netinet/ip.h>
118 #include <netinet/if_ether.h>
119 #endif
120
121 #include <net/bpf.h>
122 #include <net/bpfdesc.h>
123
124 #include <machine/cpu.h>
125 #include <machine/bus.h>
126
127 #include <dev/netif/awi/am79c930reg.h>
128 #include <dev/netif/awi/am79c930var.h>
129 #include <dev/netif/awi/awireg.h>
130 #include <dev/netif/awi/awivar.h>
131
132 static int awi_ioctl (struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *);
133 #ifdef IFM_IEEE80211
134 static int awi_media_rate2opt (struct awi_softc *sc, int rate);
135 static int awi_media_opt2rate (struct awi_softc *sc, int opt);
136 static int awi_media_change (struct ifnet *ifp);
137 static void awi_media_status (struct ifnet *ifp, struct ifmediareq *imr);
138 #endif
139 static void awi_watchdog (struct ifnet *ifp);
140 static void awi_start (struct ifnet *ifp);
141 static void awi_txint (struct awi_softc *sc);
142 static struct mbuf * awi_fix_txhdr (struct awi_softc *sc, struct mbuf *m0);
143 static struct mbuf * awi_fix_rxhdr (struct awi_softc *sc, struct mbuf *m0);
144 static void awi_input (struct awi_softc *sc, struct mbuf *m, u_int32_t rxts, u_int8_t rssi);
145 static void awi_rxint (struct awi_softc *sc);
146 static struct mbuf * awi_devget (struct awi_softc *sc, u_int32_t off, u_int16_t len);
147 static int awi_init_hw (struct awi_softc *sc);
148 static int awi_init_mibs (struct awi_softc *sc);
149 static int awi_init_txrx (struct awi_softc *sc);
150 static void awi_stop_txrx (struct awi_softc *sc);
151 static int awi_start_scan (struct awi_softc *sc);
152 static int awi_next_scan (struct awi_softc *sc);
153 static void awi_stop_scan (struct awi_softc *sc);
154 static void awi_recv_beacon (struct awi_softc *sc, struct mbuf *m0, u_int32_t rxts, u_int8_t rssi);
155 static int awi_set_ss (struct awi_softc *sc);
156 static void awi_try_sync (struct awi_softc *sc);
157 static void awi_sync_done (struct awi_softc *sc);
158 static void awi_send_deauth (struct awi_softc *sc);
159 static void awi_send_auth (struct awi_softc *sc, int seq);
160 static void awi_recv_auth (struct awi_softc *sc, struct mbuf *m0);
161 static void awi_send_asreq (struct awi_softc *sc, int reassoc);
162 static void awi_recv_asresp (struct awi_softc *sc, struct mbuf *m0);
163 static int awi_mib (struct awi_softc *sc, u_int8_t cmd, u_int8_t mib);
164 static int awi_cmd_scan (struct awi_softc *sc);
165 static int awi_cmd (struct awi_softc *sc, u_int8_t cmd);
166 static void awi_cmd_done (struct awi_softc *sc);
167 static int awi_next_txd (struct awi_softc *sc, int len, u_int32_t *framep, u_int32_t*ntxdp);
168 static int awi_intr_lock (struct awi_softc *sc);
169 static void awi_intr_unlock (struct awi_softc *sc);
170 static int awi_cmd_wait (struct awi_softc *sc);
171 static void awi_print_essid (u_int8_t *essid);
172
173 DECLARE_DUMMY_MODULE(if_awi);
174
175 #ifdef AWI_DEBUG
176 static void awi_dump_pkt (struct awi_softc *sc, struct mbuf *m, int rssi);
177 int awi_verbose = 0;
178 int awi_dump = 0;
179 #define AWI_DUMP_MASK(fc0)  (1 << (((fc0) & IEEE80211_FC0_SUBTYPE_MASK) >> 4))
180 int awi_dump_mask = AWI_DUMP_MASK(IEEE80211_FC0_SUBTYPE_BEACON);
181 int awi_dump_hdr = 0;
182 int awi_dump_len = 28;
183 #endif
184
185 #define AWI_BPF_NORM    0
186 #define AWI_BPF_RAW     1
187 #define AWI_BPF_MTAP(sc, m, raw) do {                                   \
188         if ((sc)->sc_rawbpf == (raw))                                   \
189                 BPF_MTAP((sc)->sc_ifp, (m));                            \
190 } while (0);
191
192 #ifndef llc_snap
193 #define llc_snap              llc_un.type_snap
194 #endif
195
196 devclass_t awi_devclass;
197
198 int
199 awi_attach(sc)
200         struct awi_softc *sc;
201 {
202         struct ifnet *ifp = sc->sc_ifp;
203         int error;
204 #ifdef IFM_IEEE80211
205         int i;
206         u_int8_t *phy_rates;
207         int mword;
208         struct ifmediareq imr;
209 #endif
210
211         /*
212          * Even if we can sleep in initialization state,
213          * all other processes (e.g. ifconfig) have to wait for
214          * completion of attaching interface.
215          */
216         sc->sc_status = AWI_ST_INIT;
217         TAILQ_INIT(&sc->sc_scan);
218         error = awi_init_hw(sc);
219         if (error) {
220                 sc->sc_invalid = 1;
221                 return error;
222         }
223         error = awi_init_mibs(sc);
224         if (error) {
225                 sc->sc_invalid = 1;
226                 return error;
227         }
228
229         ifp->if_softc = sc;
230         ifp->if_start = awi_start;
231         ifp->if_ioctl = awi_ioctl;
232         ifp->if_watchdog = awi_watchdog;
233         ifp->if_mtu = ETHERMTU;
234         ifp->if_hdrlen = sizeof(struct ieee80211_frame) +
235             sizeof(struct ether_header);
236         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
237 #ifdef IFF_NOTRAILERS
238         ifp->if_flags |= IFF_NOTRAILERS;
239 #endif
240         ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
241         ifq_set_ready(&ifp->if_snd);
242         memcpy(sc->sc_ec.ac_enaddr, sc->sc_mib_addr.aMAC_Address,
243             ETHER_ADDR_LEN);
244
245         if_printf(ifp, "IEEE802.11 %s %dMbps (firmware %s)\n",
246             sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH ? "FH" : "DS",
247             sc->sc_tx_rate / 10, sc->sc_banner);
248         ether_ifattach(ifp, sc->sc_mib_addr.aMAC_Address, NULL);
249
250         lwkt_serialize_enter(ifp->if_serializer);
251
252 #ifdef IFM_IEEE80211
253         ifmedia_init(&sc->sc_media, 0, awi_media_change, awi_media_status);
254         phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
255         for (i = 0; i < phy_rates[1]; i++) {
256                 mword = awi_media_rate2opt(sc, AWI_80211_RATE(phy_rates[2 + i]));
257                 if (mword == 0)
258                         continue;
259                 mword |= IFM_IEEE80211;
260                 ifmedia_add(&sc->sc_media, mword, 0, NULL);
261                 ifmedia_add(&sc->sc_media,
262                     mword | IFM_IEEE80211_ADHOC, 0, NULL);
263                 if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH)
264                         ifmedia_add(&sc->sc_media,
265                             mword | IFM_IEEE80211_ADHOC | IFM_FLAG0, 0, NULL);
266         }
267         awi_media_status(ifp, &imr);
268         ifmedia_set(&sc->sc_media, imr.ifm_active);
269 #endif
270         /* Attach is successful. */
271         sc->sc_attached = 1;
272         lwkt_serialize_exit(ifp->if_serializer);
273         return 0;
274 }
275
276 static int
277 awi_ioctl(ifp, cmd, data, cr)
278         struct ifnet *ifp;
279         u_long cmd;
280         caddr_t data;
281         struct ucred *cr;
282 {
283         struct awi_softc *sc = ifp->if_softc;
284         struct ifreq *ifr = (struct ifreq *)data;
285         struct ifaddr *ifa = (struct ifaddr *)data;
286         int error;
287         struct ieee80211_nwid nwid;
288         u_int8_t *p;
289
290         error = 0;
291
292         switch (cmd) {
293         case SIOCSIFADDR:
294                 ifp->if_flags |= IFF_UP;
295                 switch (ifa->ifa_addr->sa_family) {
296 #ifdef INET
297                 case AF_INET:
298                         arp_ifinit((void *)ifp, ifa);
299                         break;
300 #endif
301                 }
302                 /* FALLTHROUGH */
303         case SIOCSIFFLAGS:
304                 sc->sc_format_llc = !(ifp->if_flags & IFF_LINK0);
305                 if (!(ifp->if_flags & IFF_UP)) {
306                         if (sc->sc_enabled) {
307                                 awi_stop(sc);
308                                 if (sc->sc_disable)
309                                         (*sc->sc_disable)(sc);
310                                 sc->sc_enabled = 0;
311                         }
312                         break;
313                 }
314                 error = awi_init(sc);
315                 break;
316
317         case SIOCADDMULTI:
318         case SIOCDELMULTI:
319                 error = ENETRESET;      /*XXX*/
320                 /*
321                  * Do not rescan BSS.  Rather, just reset multicast filter.
322                  */
323                 if (error == ENETRESET) {
324                         if (sc->sc_enabled)
325                                 error = awi_init(sc);
326                         else
327                                 error = 0;
328                 }
329                 break;
330         case SIOCSIFMTU:
331                 if (ifr->ifr_mtu > ETHERMTU)
332                         error = EINVAL;
333                 else
334                         ifp->if_mtu = ifr->ifr_mtu;
335                 break;
336         case SIOCS80211NWID:
337                 error = suser_cred(cr, NULL_CRED_OKAY); /* EPERM if no proc */
338                 if (error)
339                         break;
340                 error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
341                 if (error)
342                         break;
343                 if (nwid.i_len > IEEE80211_NWID_LEN) {
344                         error = EINVAL;
345                         break;
346                 }
347                 if (sc->sc_mib_mac.aDesired_ESS_ID[1] == nwid.i_len &&
348                     memcmp(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid.i_nwid,
349                     nwid.i_len) == 0)
350                         break;
351                 memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
352                 sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
353                 sc->sc_mib_mac.aDesired_ESS_ID[1] = nwid.i_len;
354                 memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid.i_nwid,
355                     nwid.i_len);
356                 if (sc->sc_enabled) {
357                         awi_stop(sc);
358                         error = awi_init(sc);
359                 }
360                 break;
361         case SIOCG80211NWID:
362                 if (ifp->if_flags & IFF_RUNNING)
363                         p = sc->sc_bss.essid;
364                 else
365                         p = sc->sc_mib_mac.aDesired_ESS_ID;
366                 error = copyout(p + 1, ifr->ifr_data, 1 + IEEE80211_NWID_LEN);
367                 break;
368         case SIOCS80211NWKEY:
369                 error = suser_cred(cr, NULL_CRED_OKAY); /* EPERM if no proc */
370                 if (error)
371                         break;
372                 error = awi_wep_setnwkey(sc, (struct ieee80211_nwkey *)data);
373                 break;
374         case SIOCG80211NWKEY:
375                 error = awi_wep_getnwkey(sc, (struct ieee80211_nwkey *)data);
376                 break;
377 #ifdef IFM_IEEE80211
378         case SIOCSIFMEDIA:
379         case SIOCGIFMEDIA:
380                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
381                 break;
382 #endif
383         default:
384                 error = awi_wicfg(ifp, cmd, data);
385                 break;
386         }
387         return error;
388 }
389
390 #ifdef IFM_IEEE80211
391 static int
392 awi_media_rate2opt(sc, rate)
393         struct awi_softc *sc;
394         int rate;
395 {
396         int mword;
397
398         mword = 0;
399         switch (rate) {
400         case 10:
401                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
402                         mword = IFM_IEEE80211_FH1;
403                 else
404                         mword = IFM_IEEE80211_DS1;
405                 break;
406         case 20:
407                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
408                         mword = IFM_IEEE80211_FH2;
409                 else
410                         mword = IFM_IEEE80211_DS2;
411                 break;
412         case 55:
413                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_DS)
414                         mword = IFM_IEEE80211_DS5;
415                 break;
416         case 110:
417                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_DS)
418                         mword = IFM_IEEE80211_DS11;
419                 break;
420         }
421         return mword;
422 }
423
424 static int
425 awi_media_opt2rate(sc, opt)
426         struct awi_softc *sc;
427         int opt;
428 {
429         int rate;
430
431         rate = 0;
432         switch (IFM_SUBTYPE(opt)) {
433         case IFM_IEEE80211_FH1:
434         case IFM_IEEE80211_FH2:
435                 if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH)
436                         return 0;
437                 break;
438         case IFM_IEEE80211_DS1:
439         case IFM_IEEE80211_DS2:
440         case IFM_IEEE80211_DS5:
441         case IFM_IEEE80211_DS11:
442                 if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_DS)
443                         return 0;
444                 break;
445         }
446
447         switch (IFM_SUBTYPE(opt)) {
448         case IFM_IEEE80211_FH1:
449         case IFM_IEEE80211_DS1:
450                 rate = 10;
451                 break;
452         case IFM_IEEE80211_FH2:
453         case IFM_IEEE80211_DS2:
454                 rate = 20;
455                 break;
456         case IFM_IEEE80211_DS5:
457                 rate = 55;
458                 break;
459         case IFM_IEEE80211_DS11:
460                 rate = 110;
461                 break;
462         }
463         return rate;
464 }
465
466 /*
467  * Called from ifmedia_ioctl via awi_ioctl with lock obtained.
468  */
469 static int
470 awi_media_change(ifp)
471         struct ifnet *ifp;
472 {
473         struct awi_softc *sc = ifp->if_softc;
474         struct ifmedia_entry *ime;
475         u_int8_t *phy_rates;
476         int i, rate, error;
477
478         error = 0;
479         ime = sc->sc_media.ifm_cur;
480         rate = awi_media_opt2rate(sc, ime->ifm_media);
481         if (rate == 0)
482                 return EINVAL;
483         if (rate != sc->sc_tx_rate) {
484                 phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
485                 for (i = 0; i < phy_rates[1]; i++) {
486                         if (rate == AWI_80211_RATE(phy_rates[2 + i]))
487                                 break;
488                 }
489                 if (i == phy_rates[1])
490                         return EINVAL;
491         }
492         if (ime->ifm_media & IFM_IEEE80211_ADHOC) {
493                 sc->sc_mib_local.Network_Mode = 0;
494                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
495                         sc->sc_no_bssid = 0;
496                 else
497                         sc->sc_no_bssid = (ime->ifm_media & IFM_FLAG0) ? 1 : 0;
498         } else {
499                 sc->sc_mib_local.Network_Mode = 1;
500         }
501         if (sc->sc_enabled) {
502                 awi_stop(sc);
503                 error = awi_init(sc);
504         }
505         return error;
506 }
507
508 static void
509 awi_media_status(ifp, imr)
510         struct ifnet *ifp;
511         struct ifmediareq *imr;
512 {
513         struct awi_softc *sc = ifp->if_softc;
514
515         imr->ifm_status = IFM_AVALID;
516         if (ifp->if_flags & IFF_RUNNING)
517                 imr->ifm_status |= IFM_ACTIVE;
518         imr->ifm_active = IFM_IEEE80211;
519         imr->ifm_active |= awi_media_rate2opt(sc, sc->sc_tx_rate);
520         if (sc->sc_mib_local.Network_Mode == 0) {
521                 imr->ifm_active |= IFM_IEEE80211_ADHOC;
522                 if (sc->sc_no_bssid)
523                         imr->ifm_active |= IFM_FLAG0;
524         }
525 }
526 #endif /* IFM_IEEE80211 */
527
528 int
529 awi_intr(arg)
530         void *arg;
531 {
532         struct awi_softc *sc = arg;
533         u_int16_t status;
534         int error, handled = 0;
535
536         if (!sc->sc_enabled || !sc->sc_enab_intr || sc->sc_invalid)
537                 return 0;
538
539         am79c930_gcr_setbits(&sc->sc_chip,
540             AM79C930_GCR_DISPWDN | AM79C930_GCR_ECINT);
541         awi_write_1(sc, AWI_DIS_PWRDN, 1);
542
543         for (;;) {
544                 error = awi_intr_lock(sc);
545                 if (error)
546                         break;
547                 status = awi_read_1(sc, AWI_INTSTAT);
548                 awi_write_1(sc, AWI_INTSTAT, 0);
549                 awi_write_1(sc, AWI_INTSTAT, 0);
550                 status |= awi_read_1(sc, AWI_INTSTAT2) << 8;
551                 awi_write_1(sc, AWI_INTSTAT2, 0);
552                 DELAY(10);
553                 awi_intr_unlock(sc);
554                 if (!sc->sc_cmd_inprog)
555                         status &= ~AWI_INT_CMD; /* make sure */
556                 if (status == 0)
557                         break;
558                 handled = 1;
559                 if (status & AWI_INT_RX)
560                         awi_rxint(sc);
561                 if (status & AWI_INT_TX)
562                         awi_txint(sc);
563                 if (status & AWI_INT_CMD)
564                         awi_cmd_done(sc);
565                 if (status & AWI_INT_SCAN_CMPLT) {
566                         if (sc->sc_status == AWI_ST_SCAN &&
567                             sc->sc_mgt_timer > 0)
568                                 (void)awi_next_scan(sc);
569                 }
570         }
571         am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_DISPWDN);
572         awi_write_1(sc, AWI_DIS_PWRDN, 0);
573         return handled;
574 }
575
576 int
577 awi_init(sc)
578         struct awi_softc *sc;
579 {
580         struct ifnet *ifp = sc->sc_ifp;
581         int error, ostatus;
582         int n;
583         struct ifmultiaddr *ifma;
584
585         /* reinitialize muticast filter */
586         n = 0;
587         ifp->if_flags |= IFF_ALLMULTI;
588         sc->sc_mib_local.Accept_All_Multicast_Dis = 0;
589         if (ifp->if_flags & IFF_PROMISC) {
590                 sc->sc_mib_mac.aPromiscuous_Enable = 1;
591                 goto set_mib;
592         }
593         sc->sc_mib_mac.aPromiscuous_Enable = 0;
594         if (ifp->if_amcount != 0)
595                 goto set_mib;
596         LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
597                 if (ifma->ifma_addr->sa_family != AF_LINK)
598                         continue;
599                 if (n == AWI_GROUP_ADDR_SIZE)
600                         goto set_mib;
601                 memcpy(sc->sc_mib_addr.aGroup_Addresses[n],
602                     LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
603                     ETHER_ADDR_LEN);
604                 n++;
605         }
606         for (; n < AWI_GROUP_ADDR_SIZE; n++)
607                 memset(sc->sc_mib_addr.aGroup_Addresses[n], 0, ETHER_ADDR_LEN);
608         ifp->if_flags &= ~IFF_ALLMULTI;
609         sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
610
611   set_mib:
612 #ifdef notdef   /* allow non-encrypted frame for receiving. */
613         sc->sc_mib_mgt.Wep_Required = sc->sc_wep_algo != NULL ? 1 : 0;
614 #endif
615         if (!sc->sc_enabled) {
616                 sc->sc_enabled = 1;
617                 if (sc->sc_enable)
618                         (*sc->sc_enable)(sc);
619                 sc->sc_status = AWI_ST_INIT;
620                 error = awi_init_hw(sc);
621                 if (error)
622                         return error;
623         }
624         ostatus = sc->sc_status;
625         sc->sc_status = AWI_ST_INIT;
626         if ((error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_LOCAL)) != 0 ||
627             (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_ADDR)) != 0 ||
628             (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MAC)) != 0 ||
629             (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT)) != 0 ||
630             (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_PHY)) != 0) {
631                 awi_stop(sc);
632                 return error;
633         }
634         if (ifp->if_flags & IFF_RUNNING)
635                 sc->sc_status = AWI_ST_RUNNING;
636         else {
637                 if (ostatus == AWI_ST_INIT) {
638                         error = awi_init_txrx(sc);
639                         if (error)
640                                 return error;
641                 }
642                 error = awi_start_scan(sc);
643         }
644         return error;
645 }
646
647 void
648 awi_stop(sc)
649         struct awi_softc *sc;
650 {
651         struct ifnet *ifp = sc->sc_ifp;
652         struct awi_bss *bp;
653
654         sc->sc_status = AWI_ST_INIT;
655         if (!sc->sc_invalid) {
656                 (void)awi_cmd_wait(sc);
657                 if (sc->sc_mib_local.Network_Mode &&
658                     sc->sc_status > AWI_ST_AUTH)
659                         awi_send_deauth(sc);
660                 awi_stop_txrx(sc);
661         }
662         ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
663         ifp->if_timer = 0;
664         sc->sc_tx_timer = sc->sc_rx_timer = sc->sc_mgt_timer = 0;
665         IF_DRAIN(&sc->sc_mgtq);
666         ifq_purge(&ifp->if_snd);
667         while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) {
668                 TAILQ_REMOVE(&sc->sc_scan, bp, list);
669                 free(bp, M_DEVBUF);
670         }
671 }
672
673 static void
674 awi_watchdog(ifp)
675         struct ifnet *ifp;
676 {
677         struct awi_softc *sc = ifp->if_softc;
678
679         if (sc->sc_invalid) {
680                 ifp->if_timer = 0;
681                 return;
682         }
683
684         if (sc->sc_tx_timer && --sc->sc_tx_timer == 0) {
685                 if_printf(ifp, "transmit timeout\n");
686                 awi_txint(sc);
687         }
688         if (sc->sc_rx_timer && --sc->sc_rx_timer == 0) {
689                 if (ifp->if_flags & IFF_DEBUG) {
690                         if_printf(ifp, "no recent beacons from %6D; rescanning\n",
691                                   sc->sc_bss.bssid, ":");
692                 }
693                 ifp->if_flags &= ~IFF_RUNNING;
694                 awi_start_scan(sc);
695         }
696         if (sc->sc_mgt_timer && --sc->sc_mgt_timer == 0) {
697                 switch (sc->sc_status) {
698                 case AWI_ST_SCAN:
699                         awi_stop_scan(sc);
700                         break;
701                 case AWI_ST_AUTH:
702                 case AWI_ST_ASSOC:
703                         /* restart scan */
704                         awi_start_scan(sc);
705                         break;
706                 default:
707                         break;
708                 }
709         }
710
711         if (sc->sc_tx_timer == 0 && sc->sc_rx_timer == 0 &&
712             sc->sc_mgt_timer == 0)
713                 ifp->if_timer = 0;
714         else
715                 ifp->if_timer = 1;
716 }
717
718 static void
719 awi_start(ifp)
720         struct ifnet *ifp;
721 {
722         struct awi_softc *sc = ifp->if_softc;
723         struct mbuf *m0, *m;
724         u_int32_t txd, frame, ntxd;
725         u_int8_t rate;
726         int len, sent = 0;
727
728         for (;;) {
729                 txd = sc->sc_txnext;
730                 IF_DEQUEUE(&sc->sc_mgtq, m0);
731                 if (m0 != NULL) {
732                         if (awi_next_txd(sc, m0->m_pkthdr.len, &frame, &ntxd)) {
733                                 IF_PREPEND(&sc->sc_mgtq, m0);
734                                 ifp->if_flags |= IFF_OACTIVE;
735                                 break;
736                         }
737                 } else {
738                         if (!(ifp->if_flags & IFF_RUNNING))
739                                 break;
740                         m0 = ifq_poll(&ifp->if_snd);
741                         if (m0 == NULL)
742                                 break;
743                         len = m0->m_pkthdr.len + sizeof(struct ieee80211_frame);
744                         if (sc->sc_format_llc)
745                                 len += sizeof(struct llc) -
746                                     sizeof(struct ether_header);
747                         if (sc->sc_wep_algo != NULL)
748                                 len += IEEE80211_WEP_IVLEN +
749                                     IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
750                         if (awi_next_txd(sc, len, &frame, &ntxd)) {
751                                 ifp->if_flags |= IFF_OACTIVE;
752                                 break;
753                         }
754                         ifq_dequeue(&ifp->if_snd, m0);
755                         AWI_BPF_MTAP(sc, m0, AWI_BPF_NORM);
756                         m0 = awi_fix_txhdr(sc, m0);
757                         if (sc->sc_wep_algo != NULL && m0 != NULL)
758                                 m0 = awi_wep_encrypt(sc, m0, 1);
759                         if (m0 == NULL) {
760                                 ifp->if_oerrors++;
761                                 continue;
762                         }
763                         ifp->if_opackets++;
764                 }
765 #ifdef AWI_DEBUG
766                 if (awi_dump)
767                         awi_dump_pkt(sc, m0, -1);
768 #endif
769                 AWI_BPF_MTAP(sc, m0, AWI_BPF_RAW);
770                 len = 0;
771                 for (m = m0; m != NULL; m = m->m_next) {
772                         awi_write_bytes(sc, frame + len, mtod(m, u_int8_t *),
773                             m->m_len);
774                         len += m->m_len;
775                 }
776                 m_freem(m0);
777                 rate = sc->sc_tx_rate;  /*XXX*/
778                 awi_write_1(sc, ntxd + AWI_TXD_STATE, 0);
779                 awi_write_4(sc, txd + AWI_TXD_START, frame);
780                 awi_write_4(sc, txd + AWI_TXD_NEXT, ntxd);
781                 awi_write_4(sc, txd + AWI_TXD_LENGTH, len);
782                 awi_write_1(sc, txd + AWI_TXD_RATE, rate);
783                 awi_write_4(sc, txd + AWI_TXD_NDA, 0);
784                 awi_write_4(sc, txd + AWI_TXD_NRA, 0);
785                 awi_write_1(sc, txd + AWI_TXD_STATE, AWI_TXD_ST_OWN);
786                 sc->sc_txnext = ntxd;
787                 sent++;
788         }
789         if (sent) {
790                 if (sc->sc_tx_timer == 0)
791                         sc->sc_tx_timer = 5;
792                 ifp->if_timer = 1;
793 #ifdef AWI_DEBUG
794                 if (awi_verbose)
795                         printf("awi_start: sent %d txdone %d txnext %d txbase %d txend %d\n", sent, sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend);
796 #endif
797         }
798 }
799
800 static void
801 awi_txint(sc)
802         struct awi_softc *sc;
803 {
804         struct ifnet *ifp = sc->sc_ifp;
805         u_int8_t flags;
806
807         while (sc->sc_txdone != sc->sc_txnext) {
808                 flags = awi_read_1(sc, sc->sc_txdone + AWI_TXD_STATE);
809                 if ((flags & AWI_TXD_ST_OWN) || !(flags & AWI_TXD_ST_DONE))
810                         break;
811                 if (flags & AWI_TXD_ST_ERROR)
812                         ifp->if_oerrors++;
813                 sc->sc_txdone = awi_read_4(sc, sc->sc_txdone + AWI_TXD_NEXT) &
814                     0x7fff;
815         }
816         sc->sc_tx_timer = 0;
817         ifp->if_flags &= ~IFF_OACTIVE;
818 #ifdef AWI_DEBUG
819         if (awi_verbose)
820                 printf("awi_txint: txdone %d txnext %d txbase %d txend %d\n",
821                     sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend);
822 #endif
823         awi_start(ifp);
824 }
825
826 static struct mbuf *
827 awi_fix_txhdr(sc, m0)
828         struct awi_softc *sc;
829         struct mbuf *m0;
830 {
831         struct ether_header eh;
832         struct ieee80211_frame *wh;
833         struct llc *llc;
834
835         if (m0->m_len < sizeof(eh)) {
836                 m0 = m_pullup(m0, sizeof(eh));
837                 if (m0 == NULL)
838                         return NULL;
839         }
840         memcpy(&eh, mtod(m0, caddr_t), sizeof(eh));
841         if (sc->sc_format_llc) {
842                 m_adj(m0, sizeof(struct ether_header) - sizeof(struct llc));
843                 llc = mtod(m0, struct llc *);
844                 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
845                 llc->llc_control = LLC_UI;
846                 llc->llc_snap.org_code[0] = llc->llc_snap.org_code[1] = 
847                     llc->llc_snap.org_code[2] = 0;
848                 llc->llc_snap.ether_type = eh.ether_type;
849         }
850         M_PREPEND(m0, sizeof(struct ieee80211_frame), MB_DONTWAIT);
851         if (m0 == NULL)
852                 return NULL;
853         wh = mtod(m0, struct ieee80211_frame *);
854
855         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
856         LE_WRITE_2(wh->i_dur, 0);
857         LE_WRITE_2(wh->i_seq, 0);
858         if (sc->sc_mib_local.Network_Mode) {
859                 wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
860                 memcpy(wh->i_addr1, sc->sc_bss.bssid, ETHER_ADDR_LEN);
861                 memcpy(wh->i_addr2, eh.ether_shost, ETHER_ADDR_LEN);
862                 memcpy(wh->i_addr3, eh.ether_dhost, ETHER_ADDR_LEN);
863         } else {
864                 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
865                 memcpy(wh->i_addr1, eh.ether_dhost, ETHER_ADDR_LEN);
866                 memcpy(wh->i_addr2, eh.ether_shost, ETHER_ADDR_LEN);
867                 memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
868         }
869         return m0;
870 }
871
872 static struct mbuf *
873 awi_fix_rxhdr(sc, m0)
874         struct awi_softc *sc;
875         struct mbuf *m0;
876 {
877         struct ieee80211_frame wh;
878         struct ether_header *eh;
879         struct llc *llc;
880
881         if (m0->m_len < sizeof(wh)) {
882                 m_freem(m0);
883                 return NULL;
884         }
885         llc = (struct llc *)(mtod(m0, caddr_t) + sizeof(wh));
886         if (llc->llc_dsap == LLC_SNAP_LSAP &&
887             llc->llc_ssap == LLC_SNAP_LSAP &&
888             llc->llc_control == LLC_UI &&
889             llc->llc_snap.org_code[0] == 0 &&
890             llc->llc_snap.org_code[1] == 0 &&
891             llc->llc_snap.org_code[2] == 0) {
892                 memcpy(&wh, mtod(m0, caddr_t), sizeof(wh));
893                 m_adj(m0, sizeof(wh) + sizeof(*llc) - sizeof(*eh));
894                 eh = mtod(m0, struct ether_header *);
895                 switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
896                 case IEEE80211_FC1_DIR_NODS:
897                         memcpy(eh->ether_dhost, wh.i_addr1, ETHER_ADDR_LEN);
898                         memcpy(eh->ether_shost, wh.i_addr2, ETHER_ADDR_LEN);
899                         break;
900                 case IEEE80211_FC1_DIR_TODS:
901                         memcpy(eh->ether_dhost, wh.i_addr3, ETHER_ADDR_LEN);
902                         memcpy(eh->ether_shost, wh.i_addr2, ETHER_ADDR_LEN);
903                         break;
904                 case IEEE80211_FC1_DIR_FROMDS:
905                         memcpy(eh->ether_dhost, wh.i_addr1, ETHER_ADDR_LEN);
906                         memcpy(eh->ether_shost, wh.i_addr3, ETHER_ADDR_LEN);
907                         break;
908                 case IEEE80211_FC1_DIR_DSTODS:
909                         m_freem(m0);
910                         return NULL;
911                 }
912         } else {
913                 /* assuming ethernet encapsulation, just strip 802.11 header */
914                 m_adj(m0, sizeof(wh));
915         }
916         if (ALIGN(mtod(m0, caddr_t) + sizeof(struct ether_header)) !=
917             (u_int)(mtod(m0, caddr_t) + sizeof(struct ether_header))) {
918                 /* XXX: we loose to estimate the type of encapsulation */
919                 struct mbuf *n, *n0, **np;
920                 caddr_t newdata;
921                 int off;
922
923                 n0 = NULL;
924                 np = &n0;
925                 off = 0;
926                 while (m0->m_pkthdr.len > off) {
927                         int msize;
928
929                         n = m_getl(m0->m_pkthdr.len - off, MB_DONTWAIT,
930                                    MT_DATA, n0 == NULL ? M_PKTHDR : 0, &msize);
931                         if (n == NULL) {
932                                 m_freem(m0);
933                                 return (NULL);
934                         }
935                         n->m_len = msize;
936                         if (n0 == NULL) {
937                                 M_MOVE_PKTHDR(n, m0);
938                                 newdata = (caddr_t)
939                                     ALIGN(n->m_data
940                                     + sizeof(struct ether_header))
941                                     - sizeof(struct ether_header);
942                                 n->m_len -= newdata - n->m_data;
943                                 n->m_data = newdata;
944                         }
945                         if (n->m_len > m0->m_pkthdr.len - off)
946                                 n->m_len = m0->m_pkthdr.len - off;
947                         m_copydata(m0, off, n->m_len, mtod(n, caddr_t));
948                         off += n->m_len;
949                         *np = n;
950                         np = &n->m_next;
951                 }
952                 m_freem(m0);
953                 m0 = n0;
954         }
955         return m0;
956 }
957
958 static void
959 awi_input(sc, m, rxts, rssi)
960         struct awi_softc *sc;
961         struct mbuf *m;
962         u_int32_t rxts;
963         u_int8_t rssi;
964 {
965         struct ifnet *ifp = sc->sc_ifp;
966         struct ieee80211_frame *wh;
967
968         /* trim CRC here for WEP can find its own CRC at the end of packet. */
969         m_adj(m, -ETHER_CRC_LEN);
970         AWI_BPF_MTAP(sc, m, AWI_BPF_RAW);
971         wh = mtod(m, struct ieee80211_frame *);
972         if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
973             IEEE80211_FC0_VERSION_0) {
974                 if_printf(ifp, "receive packet with wrong version: %x\n",
975                           wh->i_fc[0]);
976                 m_freem(m);
977                 ifp->if_ierrors++;
978                 return;
979         }
980         if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
981                 m = awi_wep_encrypt(sc, m, 0);
982                 if (m == NULL) {
983                         ifp->if_ierrors++;
984                         return;
985                 }
986                 wh = mtod(m, struct ieee80211_frame *);
987         }
988 #ifdef AWI_DEBUG
989         if (awi_dump)
990                 awi_dump_pkt(sc, m, rssi);
991 #endif
992
993         if ((sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid) &&
994             sc->sc_status == AWI_ST_RUNNING) {
995                 if (memcmp(wh->i_addr2, sc->sc_bss.bssid, ETHER_ADDR_LEN) == 0) {
996                         sc->sc_rx_timer = 10;
997                         sc->sc_bss.rssi = rssi;
998                 }
999         }
1000         switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
1001         case IEEE80211_FC0_TYPE_DATA:
1002                 if (sc->sc_mib_local.Network_Mode) {
1003                         if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
1004                             IEEE80211_FC1_DIR_FROMDS) {
1005                                 m_freem(m);
1006                                 return;
1007                         }
1008                 } else {
1009                         if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
1010                             IEEE80211_FC1_DIR_NODS) {
1011                                 m_freem(m);
1012                                 return;
1013                         }
1014                 }
1015                 m = awi_fix_rxhdr(sc, m);
1016                 if (m == NULL) {
1017                         ifp->if_ierrors++;
1018                         break;
1019                 }
1020                 ifp->if_ipackets++;
1021                 ifp->if_input(ifp, m);
1022                 break;
1023         case IEEE80211_FC0_TYPE_MGT:
1024                 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
1025                    IEEE80211_FC1_DIR_NODS) {
1026                         m_freem(m);
1027                         return;
1028                 }
1029                 switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
1030                 case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
1031                 case IEEE80211_FC0_SUBTYPE_BEACON:
1032                         awi_recv_beacon(sc, m, rxts, rssi);
1033                         break;
1034                 case IEEE80211_FC0_SUBTYPE_AUTH:
1035                         awi_recv_auth(sc, m);
1036                         break;
1037                 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
1038                 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
1039                         awi_recv_asresp(sc, m);
1040                         break;
1041                 case IEEE80211_FC0_SUBTYPE_DEAUTH:
1042                         if (sc->sc_mib_local.Network_Mode)
1043                                 awi_send_auth(sc, 1);
1044                         break;
1045                 case IEEE80211_FC0_SUBTYPE_DISASSOC:
1046                         if (sc->sc_mib_local.Network_Mode)
1047                                 awi_send_asreq(sc, 1);
1048                         break;
1049                 }
1050                 m_freem(m);
1051                 break;
1052         case IEEE80211_FC0_TYPE_CTL:
1053         default:
1054                 /* should not come here */
1055                 m_freem(m);
1056                 break;
1057         }
1058 }
1059
1060 static void
1061 awi_rxint(sc)
1062         struct awi_softc *sc;
1063 {
1064         u_int8_t state, rate, rssi;
1065         u_int16_t len;
1066         u_int32_t frame, next, rxts, rxoff;
1067         struct mbuf *m;
1068
1069         rxoff = sc->sc_rxdoff;
1070         for (;;) {
1071                 state = awi_read_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE);
1072                 if (state & AWI_RXD_ST_OWN)
1073                         break;
1074                 if (!(state & AWI_RXD_ST_CONSUMED)) {
1075                         if (state & AWI_RXD_ST_RXERROR)
1076                                 sc->sc_ifp->if_ierrors++;
1077                         else {
1078                                 len   = awi_read_2(sc, rxoff + AWI_RXD_LEN);
1079                                 rate  = awi_read_1(sc, rxoff + AWI_RXD_RATE);
1080                                 rssi  = awi_read_1(sc, rxoff + AWI_RXD_RSSI);
1081                                 frame = awi_read_4(sc, rxoff + AWI_RXD_START_FRAME) & 0x7fff;
1082                                 rxts  = awi_read_4(sc, rxoff + AWI_RXD_LOCALTIME);
1083                                 m = awi_devget(sc, frame, len);
1084                                 if (state & AWI_RXD_ST_LF)
1085                                         awi_input(sc, m, rxts, rssi);
1086                                 else
1087                                         sc->sc_rxpend = m;
1088                         }
1089                         state |= AWI_RXD_ST_CONSUMED;
1090                         awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state);
1091                 }
1092                 next  = awi_read_4(sc, rxoff + AWI_RXD_NEXT);
1093                 if (next & AWI_RXD_NEXT_LAST)
1094                         break;
1095                 /* make sure the next pointer is correct */
1096                 if (next != awi_read_4(sc, rxoff + AWI_RXD_NEXT))
1097                         break;
1098                 state |= AWI_RXD_ST_OWN;
1099                 awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state);
1100                 rxoff = next & 0x7fff;
1101         }
1102         sc->sc_rxdoff = rxoff;
1103 }
1104
1105 static struct mbuf *
1106 awi_devget(sc, off, len)
1107         struct awi_softc *sc;
1108         u_int32_t off;
1109         u_int16_t len;
1110 {
1111         struct mbuf *m;
1112         struct mbuf *top, **mp;
1113         u_int tlen;
1114         int msize;
1115
1116         top = sc->sc_rxpend;
1117         mp = &top;
1118         if (top != NULL) {
1119                 sc->sc_rxpend = NULL;
1120                 top->m_pkthdr.len += len;
1121                 m = top;
1122                 while (*mp != NULL) {
1123                         m = *mp;
1124                         mp = &m->m_next;
1125                 }
1126                 if (m->m_flags & M_EXT)
1127                         tlen = m->m_ext.ext_size;
1128                 else if (m->m_flags & M_PKTHDR)
1129                         tlen = MHLEN;
1130                 else
1131                         tlen = MLEN;
1132                 tlen -= m->m_len;
1133                 if (tlen > len)
1134                         tlen = len;
1135                 awi_read_bytes(sc, off, mtod(m, u_int8_t *) + m->m_len, tlen);
1136                 off += tlen;
1137                 len -= tlen;
1138         }
1139
1140         while (len > 0) {
1141                 m = m_getl(len, MB_DONTWAIT, MT_DATA,
1142                            top == NULL ? M_PKTHDR : 0, &msize);
1143                 if (m == NULL) {
1144                         m_freem(top);
1145                         return (NULL);
1146                 }
1147                 m->m_len = msize;
1148                 if (top == NULL) {
1149                         int hdrlen = sizeof(struct ieee80211_frame) +
1150                             (sc->sc_format_llc ? sizeof(struct llc) :
1151                             sizeof(struct ether_header));
1152                         caddr_t newdata = (caddr_t)
1153                             ALIGN(m->m_data + hdrlen) - hdrlen;
1154
1155                         m->m_pkthdr.rcvif = sc->sc_ifp;
1156                         m->m_pkthdr.len = len;
1157                         m->m_len -= newdata - m->m_data;
1158                         m->m_data = newdata;
1159                 }
1160                 if (m->m_len > len)
1161                         m->m_len = len;
1162                 awi_read_bytes(sc, off, mtod(m, u_int8_t *), m->m_len);
1163                 off += m->m_len;
1164                 len -= m->m_len;
1165                 *mp = m;
1166                 mp = &m->m_next;
1167         }
1168         return top;
1169 }
1170
1171 /*
1172  * Initialize hardware and start firmware to accept commands.
1173  * Called everytime after power on firmware.
1174  */
1175
1176 static int
1177 awi_init_hw(sc)
1178         struct awi_softc *sc;
1179 {
1180         struct ifnet *ifp = sc->sc_ifp;
1181         u_int8_t status;
1182         u_int16_t intmask;
1183         int i, error;
1184
1185         sc->sc_enab_intr = 0;
1186         sc->sc_invalid = 0;     /* XXX: really? */
1187         awi_drvstate(sc, AWI_DRV_RESET);
1188
1189         /* reset firmware */
1190         am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_CORESET);
1191         DELAY(100);
1192         awi_write_1(sc, AWI_SELFTEST, 0);
1193         awi_write_1(sc, AWI_CMD, 0);
1194         awi_write_1(sc, AWI_BANNER, 0);
1195         am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_CORESET);
1196         DELAY(100);
1197
1198         /* wait for selftest completion */
1199         for (i = 0; ; i++) {
1200                 if (i >= AWI_SELFTEST_TIMEOUT*hz/1000) {
1201                         if_printf(ifp, "failed to complete selftest (timeout)\n");
1202                         return ENXIO;
1203                 }
1204                 status = awi_read_1(sc, AWI_SELFTEST);
1205                 if ((status & 0xf0) == 0xf0)
1206                         break;
1207                 sc->sc_sleep_cnt++;
1208                 (void)tsleep(sc, 0, "awitst", 1);
1209                 sc->sc_sleep_cnt--;
1210         }
1211         if (status != AWI_SELFTEST_PASSED) {
1212                 if_printf(ifp, "failed to complete selftest (code %x)\n",
1213                           status);
1214                 return ENXIO;
1215         }
1216
1217         /* check banner to confirm firmware write it */
1218         awi_read_bytes(sc, AWI_BANNER, sc->sc_banner, AWI_BANNER_LEN);
1219         if (memcmp(sc->sc_banner, "PCnetMobile:", 12) != 0) {
1220                 if_printf(ifp, "failed to complete selftest (bad banner)\n");
1221                 for (i = 0; i < AWI_BANNER_LEN; i++)
1222                         printf("%s%02x", i ? ":" : "\t", sc->sc_banner[i]);
1223                 printf("\n");
1224                 return ENXIO;
1225         }
1226
1227         /* initializing interrupt */
1228         sc->sc_enab_intr = 1;
1229         error = awi_intr_lock(sc);
1230         if (error)
1231                 return error;
1232         intmask = AWI_INT_GROGGY | AWI_INT_SCAN_CMPLT |
1233             AWI_INT_TX | AWI_INT_RX | AWI_INT_CMD;
1234         awi_write_1(sc, AWI_INTMASK, ~intmask & 0xff);
1235         awi_write_1(sc, AWI_INTMASK2, 0);
1236         awi_write_1(sc, AWI_INTSTAT, 0);
1237         awi_write_1(sc, AWI_INTSTAT2, 0);
1238         awi_intr_unlock(sc);
1239         am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_ENECINT);
1240
1241         /* issueing interface test command */
1242         error = awi_cmd(sc, AWI_CMD_NOP);
1243         if (error) {
1244                 if_printf(ifp, "failed to complete selftest");
1245                 if (error == ENXIO)
1246                         printf(" (no hardware)\n");
1247                 else if (error != EWOULDBLOCK)
1248                         printf(" (error %d)\n", error);
1249                 else
1250                         printf(" (command timeout)\n");
1251         }
1252         return error;
1253 }
1254
1255 /*
1256  * Extract the factory default MIB value from firmware and assign the driver
1257  * default value.
1258  * Called once at attaching the interface.
1259  */
1260
1261 static int
1262 awi_init_mibs(sc)
1263         struct awi_softc *sc;
1264 {
1265         int i, error;
1266         u_int8_t *rate;
1267
1268         if ((error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_LOCAL)) != 0 ||
1269             (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_ADDR)) != 0 ||
1270             (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MAC)) != 0 ||
1271             (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MGT)) != 0 ||
1272             (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_PHY)) != 0) {
1273                 if_printf(sc->sc_ifp,
1274                           "failed to get default mib value (error %d)\n",
1275                           error);
1276                 return error;
1277         }
1278
1279         rate = sc->sc_mib_phy.aSuprt_Data_Rates;
1280         sc->sc_tx_rate = AWI_RATE_1MBIT;
1281         for (i = 0; i < rate[1]; i++) {
1282                 if (AWI_80211_RATE(rate[2 + i]) > sc->sc_tx_rate)
1283                         sc->sc_tx_rate = AWI_80211_RATE(rate[2 + i]);
1284         }
1285         awi_init_region(sc);
1286         memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
1287         sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
1288         sc->sc_mib_local.Fragmentation_Dis = 1;
1289         sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
1290         sc->sc_mib_local.Power_Saving_Mode_Dis = 1;
1291
1292         /* allocate buffers */
1293         sc->sc_txbase = AWI_BUFFERS;
1294         sc->sc_txend = sc->sc_txbase +
1295             (AWI_TXD_SIZE + sizeof(struct ieee80211_frame) +
1296             sizeof(struct ether_header) + ETHERMTU) * AWI_NTXBUFS;
1297         LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Offset, sc->sc_txbase);
1298         LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Size,
1299             sc->sc_txend - sc->sc_txbase);
1300         LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Offset, sc->sc_txend);
1301         LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Size,
1302             AWI_BUFFERS_END - sc->sc_txend);
1303         sc->sc_mib_local.Network_Mode = 1;
1304         sc->sc_mib_local.Acting_as_AP = 0;
1305         return 0;
1306 }
1307
1308 /*
1309  * Start transmitter and receiver of firmware
1310  * Called after awi_init_hw() to start operation.
1311  */
1312
1313 static int
1314 awi_init_txrx(sc)
1315         struct awi_softc *sc;
1316 {
1317         int error;
1318
1319         /* start transmitter */
1320         sc->sc_txdone = sc->sc_txnext = sc->sc_txbase;
1321         awi_write_4(sc, sc->sc_txbase + AWI_TXD_START, 0);
1322         awi_write_4(sc, sc->sc_txbase + AWI_TXD_NEXT, 0);
1323         awi_write_4(sc, sc->sc_txbase + AWI_TXD_LENGTH, 0);
1324         awi_write_1(sc, sc->sc_txbase + AWI_TXD_RATE, 0);
1325         awi_write_4(sc, sc->sc_txbase + AWI_TXD_NDA, 0);
1326         awi_write_4(sc, sc->sc_txbase + AWI_TXD_NRA, 0);
1327         awi_write_1(sc, sc->sc_txbase + AWI_TXD_STATE, 0);
1328         awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_DATA, sc->sc_txbase);
1329         awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_MGT, 0);
1330         awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_BCAST, 0);
1331         awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_PS, 0);
1332         awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_CF, 0);
1333         error = awi_cmd(sc, AWI_CMD_INIT_TX);
1334         if (error)
1335                 return error;
1336
1337         /* start receiver */
1338         if (sc->sc_rxpend) {
1339                 m_freem(sc->sc_rxpend);
1340                 sc->sc_rxpend = NULL;
1341         }
1342         error = awi_cmd(sc, AWI_CMD_INIT_RX);
1343         if (error)
1344                 return error;
1345         sc->sc_rxdoff = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_DATA_DESC);
1346         sc->sc_rxmoff = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_PS_DESC);
1347         return 0;
1348 }
1349
1350 static void
1351 awi_stop_txrx(sc)
1352         struct awi_softc *sc;
1353 {
1354
1355         if (sc->sc_cmd_inprog)
1356                 (void)awi_cmd_wait(sc);
1357         (void)awi_cmd(sc, AWI_CMD_KILL_RX);
1358         (void)awi_cmd_wait(sc);
1359         sc->sc_cmd_inprog = AWI_CMD_FLUSH_TX;
1360         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_DATA, 1);
1361         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_MGT, 0);
1362         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_BCAST, 0);
1363         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_PS, 0);
1364         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_CF, 0);
1365         (void)awi_cmd(sc, AWI_CMD_FLUSH_TX);
1366         (void)awi_cmd_wait(sc);
1367 }
1368
1369 int
1370 awi_init_region(sc)
1371         struct awi_softc *sc;
1372 {
1373
1374         if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
1375                 switch (sc->sc_mib_phy.aCurrent_Reg_Domain) {
1376                 case AWI_REG_DOMAIN_US:
1377                 case AWI_REG_DOMAIN_CA:
1378                 case AWI_REG_DOMAIN_EU:
1379                         sc->sc_scan_min = 0;
1380                         sc->sc_scan_max = 77;
1381                         break;
1382                 case AWI_REG_DOMAIN_ES:
1383                         sc->sc_scan_min = 0;
1384                         sc->sc_scan_max = 26;
1385                         break;
1386                 case AWI_REG_DOMAIN_FR:
1387                         sc->sc_scan_min = 0;
1388                         sc->sc_scan_max = 32;
1389                         break;
1390                 case AWI_REG_DOMAIN_JP:
1391                         sc->sc_scan_min = 6;
1392                         sc->sc_scan_max = 17;
1393                         break;
1394                 default:
1395                         return EINVAL;
1396                 }
1397                 sc->sc_scan_set = sc->sc_scan_cur % 3 + 1;
1398         } else {
1399                 switch (sc->sc_mib_phy.aCurrent_Reg_Domain) {
1400                 case AWI_REG_DOMAIN_US:
1401                 case AWI_REG_DOMAIN_CA:
1402                         sc->sc_scan_min = 1;
1403                         sc->sc_scan_max = 11;
1404                         sc->sc_scan_cur = 3;
1405                         break;
1406                 case AWI_REG_DOMAIN_EU:
1407                         sc->sc_scan_min = 1;
1408                         sc->sc_scan_max = 13;
1409                         sc->sc_scan_cur = 3;
1410                         break;
1411                 case AWI_REG_DOMAIN_ES:
1412                         sc->sc_scan_min = 10;
1413                         sc->sc_scan_max = 11;
1414                         sc->sc_scan_cur = 10;
1415                         break;
1416                 case AWI_REG_DOMAIN_FR:
1417                         sc->sc_scan_min = 10;
1418                         sc->sc_scan_max = 13;
1419                         sc->sc_scan_cur = 10;
1420                         break;
1421                 case AWI_REG_DOMAIN_JP:
1422                         sc->sc_scan_min = 14;
1423                         sc->sc_scan_max = 14;
1424                         sc->sc_scan_cur = 14;
1425                         break;
1426                 default:
1427                         return EINVAL;
1428                 }
1429         }
1430         sc->sc_ownch = sc->sc_scan_cur;
1431         return 0;
1432 }
1433
1434 static int
1435 awi_start_scan(sc)
1436         struct awi_softc *sc;
1437 {
1438         int error = 0;
1439         struct awi_bss *bp;
1440
1441         while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) {
1442                 TAILQ_REMOVE(&sc->sc_scan, bp, list);
1443                 free(bp, M_DEVBUF);
1444         }
1445         if (!sc->sc_mib_local.Network_Mode && sc->sc_no_bssid) {
1446                 memset(&sc->sc_bss, 0, sizeof(sc->sc_bss));
1447                 sc->sc_bss.essid[0] = IEEE80211_ELEMID_SSID;
1448                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
1449                         sc->sc_bss.chanset = sc->sc_ownch % 3 + 1;
1450                         sc->sc_bss.pattern = sc->sc_ownch;
1451                         sc->sc_bss.index = 1;
1452                         sc->sc_bss.dwell_time = 200;    /*XXX*/
1453                 } else
1454                         sc->sc_bss.chanset = sc->sc_ownch;
1455                 sc->sc_status = AWI_ST_SETSS;
1456                 error = awi_set_ss(sc);
1457         } else {
1458                 if (sc->sc_mib_local.Network_Mode)
1459                         awi_drvstate(sc, AWI_DRV_INFSC);
1460                 else
1461                         awi_drvstate(sc, AWI_DRV_ADHSC);
1462                 sc->sc_start_bss = 0;
1463                 sc->sc_active_scan = 1;
1464                 sc->sc_mgt_timer = AWI_ASCAN_WAIT / 1000;
1465                 sc->sc_ifp->if_timer = 1;
1466                 sc->sc_status = AWI_ST_SCAN;
1467                 error = awi_cmd_scan(sc);
1468         }
1469         return error;
1470 }
1471
1472 static int
1473 awi_next_scan(sc)
1474         struct awi_softc *sc;
1475 {
1476         int error;
1477
1478         for (;;) {
1479                 /*
1480                  * The pattern parameter for FH phy should be incremented
1481                  * by 3.  But BayStack 650 Access Points apparently always
1482                  * assign hop pattern set parameter to 1 for any pattern.
1483                  * So we try all combinations of pattern/set parameters.
1484                  * Since this causes no error, it may be a bug of
1485                  * PCnetMobile firmware.
1486                  */
1487                 sc->sc_scan_cur++;
1488                 if (sc->sc_scan_cur > sc->sc_scan_max) {
1489                         sc->sc_scan_cur = sc->sc_scan_min;
1490                         if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
1491                                 sc->sc_scan_set = sc->sc_scan_set % 3 + 1;
1492                 }
1493                 error = awi_cmd_scan(sc);
1494                 if (error != EINVAL)
1495                         break;
1496         }
1497         return error;
1498 }
1499
1500 static void
1501 awi_stop_scan(sc)
1502         struct awi_softc *sc;
1503 {
1504         struct ifnet *ifp = sc->sc_ifp;
1505         struct awi_bss *bp, *sbp;
1506         int fail;
1507
1508         bp = TAILQ_FIRST(&sc->sc_scan);
1509         if (bp == NULL) {
1510   notfound:
1511                 if (sc->sc_active_scan) {
1512                         if (ifp->if_flags & IFF_DEBUG)
1513                                 if_printf(ifp, "entering passive scan mode\n");
1514                         sc->sc_active_scan = 0;
1515                 }
1516                 sc->sc_mgt_timer = AWI_PSCAN_WAIT / 1000;
1517                 ifp->if_timer = 1;
1518                 (void)awi_next_scan(sc);
1519                 return;
1520         }
1521         sbp = NULL;
1522         if (ifp->if_flags & IFF_DEBUG)
1523                 if_printf(ifp, "\tmacaddr     ch/pat   sig flag  wep  essid\n");
1524         for (; bp != NULL; bp = TAILQ_NEXT(bp, list)) {
1525                 if (bp->fails) {
1526                         /*
1527                          * The configuration of the access points may change
1528                          * during my scan.  So we retries to associate with
1529                          * it unless there are any suitable AP.
1530                          */
1531                         if (bp->fails++ < 3)
1532                                 continue;
1533                         bp->fails = 0;
1534                 }
1535                 fail = 0;
1536                 /*
1537                  * Since the firmware apparently scans not only the specified
1538                  * channel of SCAN command but all available channel within
1539                  * the region, we should filter out unnecessary responses here.
1540                  */
1541                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
1542                         if (bp->pattern < sc->sc_scan_min ||
1543                             bp->pattern > sc->sc_scan_max)
1544                                 fail |= 0x01;
1545                 } else {
1546                         if (bp->chanset < sc->sc_scan_min ||
1547                             bp->chanset > sc->sc_scan_max)
1548                                 fail |= 0x01;
1549                 }
1550                 if (sc->sc_mib_local.Network_Mode) {
1551                         if (!(bp->capinfo & IEEE80211_CAPINFO_ESS) ||
1552                             (bp->capinfo & IEEE80211_CAPINFO_IBSS))
1553                                 fail |= 0x02;
1554                 } else {
1555                         if ((bp->capinfo & IEEE80211_CAPINFO_ESS) ||
1556                             !(bp->capinfo & IEEE80211_CAPINFO_IBSS))
1557                                 fail |= 0x02;
1558                 }
1559                 if (sc->sc_wep_algo == NULL) {
1560                         if (bp->capinfo & IEEE80211_CAPINFO_PRIVACY)
1561                                 fail |= 0x04;
1562                 } else {
1563                         if (!(bp->capinfo & IEEE80211_CAPINFO_PRIVACY))
1564                                 fail |= 0x04;
1565                 }
1566                 if (sc->sc_mib_mac.aDesired_ESS_ID[1] != 0 &&
1567                     memcmp(&sc->sc_mib_mac.aDesired_ESS_ID, bp->essid,
1568                     sizeof(bp->essid)) != 0)
1569                         fail |= 0x08;
1570                 if (ifp->if_flags & IFF_DEBUG) {
1571                         printf(" %c %6D", fail ? '-' : '+', bp->esrc, ":");
1572                         if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
1573                                 printf("  %2d/%d%c", bp->pattern, bp->chanset,
1574                                     fail & 0x01 ? '!' : ' ');
1575                         else
1576                                 printf("  %4d%c", bp->chanset,
1577                                     fail & 0x01 ? '!' : ' ');
1578                         printf(" %+4d", bp->rssi);
1579                         printf(" %4s%c",
1580                             (bp->capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
1581                             (bp->capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
1582                             "????",
1583                             fail & 0x02 ? '!' : ' ');
1584                         printf(" %3s%c ",
1585                             (bp->capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" :
1586                             "no",
1587                             fail & 0x04 ? '!' : ' ');
1588                         awi_print_essid(bp->essid);
1589                         printf("%s\n", fail & 0x08 ? "!" : "");
1590                 }
1591                 if (!fail) {
1592                         if (sbp == NULL || bp->rssi > sbp->rssi)
1593                                 sbp = bp;
1594                 }
1595         }
1596         if (sbp == NULL)
1597                 goto notfound;
1598         sc->sc_bss = *sbp;
1599         (void)awi_set_ss(sc);
1600 }
1601
1602 static void
1603 awi_recv_beacon(sc, m0, rxts, rssi)
1604         struct awi_softc *sc;
1605         struct mbuf *m0;
1606         u_int32_t rxts;
1607         u_int8_t rssi;
1608 {
1609         struct ieee80211_frame *wh;
1610         struct awi_bss *bp;
1611         u_int8_t *frame, *eframe;
1612         u_int8_t *tstamp, *bintval, *capinfo, *ssid, *rates, *parms;
1613
1614         if (sc->sc_status != AWI_ST_SCAN)
1615                 return;
1616         wh = mtod(m0, struct ieee80211_frame *);
1617
1618         frame = (u_int8_t *)&wh[1];
1619         eframe = mtod(m0, u_int8_t *) + m0->m_len;
1620         /*
1621          * XXX:
1622          *      timestamp [8]
1623          *      beacon interval [2]
1624          *      capability information [2]
1625          *      ssid [tlv]
1626          *      supported rates [tlv]
1627          *      parameter set [tlv]
1628          *      ...
1629          */
1630         if (frame + 12 > eframe) {
1631 #ifdef AWI_DEBUG
1632                 if (awi_verbose)
1633                         printf("awi_recv_beacon: frame too short \n");
1634 #endif
1635                 return;
1636         }
1637         tstamp = frame;
1638         frame += 8;
1639         bintval = frame;
1640         frame += 2;
1641         capinfo = frame;
1642         frame += 2;
1643
1644         ssid = rates = parms = NULL;
1645         while (frame < eframe) {
1646                 switch (*frame) {
1647                 case IEEE80211_ELEMID_SSID:
1648                         ssid = frame;
1649                         break;
1650                 case IEEE80211_ELEMID_RATES:
1651                         rates = frame;
1652                         break;
1653                 case IEEE80211_ELEMID_FHPARMS:
1654                 case IEEE80211_ELEMID_DSPARMS:
1655                         parms = frame;
1656                         break;
1657                 }
1658                 frame += frame[1] + 2;
1659         }
1660         if (ssid == NULL || rates == NULL || parms == NULL) {
1661 #ifdef AWI_DEBUG
1662                 if (awi_verbose)
1663                         printf("awi_recv_beacon: ssid=%p, rates=%p, parms=%p\n",
1664                             ssid, rates, parms);
1665 #endif
1666                 return;
1667         }
1668         if (ssid[1] > IEEE80211_NWID_LEN) {
1669 #ifdef AWI_DEBUG
1670                 if (awi_verbose)
1671                         printf("awi_recv_beacon: bad ssid len: %d from %6D\n",
1672                             ssid[1], wh->i_addr2, ":");
1673 #endif
1674                 return;
1675         }
1676
1677         for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL;
1678             bp = TAILQ_NEXT(bp, list)) {
1679                 if (memcmp(bp->esrc, wh->i_addr2, ETHER_ADDR_LEN) == 0 &&
1680                     memcmp(bp->bssid, wh->i_addr3, ETHER_ADDR_LEN) == 0)
1681                         break;
1682         }
1683         if (bp == NULL) {
1684                 bp = malloc(sizeof(struct awi_bss), M_DEVBUF, M_INTWAIT);
1685                 if (bp == NULL)
1686                         return;
1687                 TAILQ_INSERT_TAIL(&sc->sc_scan, bp, list);
1688                 memcpy(bp->esrc, wh->i_addr2, ETHER_ADDR_LEN);
1689                 memcpy(bp->bssid, wh->i_addr3, ETHER_ADDR_LEN);
1690                 memset(bp->essid, 0, sizeof(bp->essid));
1691                 memcpy(bp->essid, ssid, 2 + ssid[1]);
1692         }
1693         bp->rssi = rssi;
1694         bp->rxtime = rxts;
1695         memcpy(bp->timestamp, tstamp, sizeof(bp->timestamp));
1696         bp->interval = LE_READ_2(bintval);
1697         bp->capinfo = LE_READ_2(capinfo);
1698         if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
1699                 bp->chanset = parms[4];
1700                 bp->pattern = parms[5];
1701                 bp->index = parms[6];
1702                 bp->dwell_time = LE_READ_2(parms + 2);
1703         } else {
1704                 bp->chanset = parms[2];
1705                 bp->pattern = 0;
1706                 bp->index = 0;
1707                 bp->dwell_time = 0;
1708         }
1709         if (sc->sc_mgt_timer == 0)
1710                 awi_stop_scan(sc);
1711 }
1712
1713 static int
1714 awi_set_ss(sc)
1715         struct awi_softc *sc;
1716 {
1717         struct ifnet *ifp = sc->sc_ifp;
1718         struct awi_bss *bp;
1719         int error;
1720
1721         sc->sc_status = AWI_ST_SETSS;
1722         bp = &sc->sc_bss;
1723         if (ifp->if_flags & IFF_DEBUG) {
1724                 if_printf(ifp, "ch %d pat %d id %d dw %d iv %d bss %6D ssid ",
1725                           bp->chanset, bp->pattern, bp->index, bp->dwell_time,
1726                           bp->interval, bp->bssid, ":");
1727                 awi_print_essid(bp->essid);
1728                 printf("\n");
1729         }
1730         memcpy(&sc->sc_mib_mgt.aCurrent_BSS_ID, bp->bssid, ETHER_ADDR_LEN);
1731         memcpy(&sc->sc_mib_mgt.aCurrent_ESS_ID, bp->essid,
1732             AWI_ESS_ID_SIZE);
1733         LE_WRITE_2(&sc->sc_mib_mgt.aBeacon_Period, bp->interval);
1734         error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT);
1735         return error;
1736 }
1737
1738 static void
1739 awi_try_sync(sc)
1740         struct awi_softc *sc;
1741 {
1742         struct awi_bss *bp;
1743
1744         sc->sc_status = AWI_ST_SYNC;
1745         bp = &sc->sc_bss;
1746
1747         if (sc->sc_cmd_inprog) {
1748                 if (awi_cmd_wait(sc))
1749                         return;
1750         }
1751         sc->sc_cmd_inprog = AWI_CMD_SYNC;
1752         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_SET, bp->chanset);
1753         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_PATTERN, bp->pattern);
1754         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_IDX, bp->index);
1755         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_STARTBSS,
1756             sc->sc_start_bss ? 1 : 0); 
1757         awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_DWELL, bp->dwell_time);
1758         awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_MBZ, 0);
1759         awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_TIMESTAMP,
1760             bp->timestamp, 8);
1761         awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_REFTIME, bp->rxtime);
1762         (void)awi_cmd(sc, AWI_CMD_SYNC);
1763 }
1764
1765 static void
1766 awi_sync_done(sc)
1767         struct awi_softc *sc;
1768 {
1769         struct ifnet *ifp = sc->sc_ifp;
1770
1771         if (sc->sc_mib_local.Network_Mode) {
1772                 awi_drvstate(sc, AWI_DRV_INFSY);
1773                 awi_send_auth(sc, 1);
1774         } else {
1775                 if (ifp->if_flags & IFF_DEBUG) {
1776                         if_printf(ifp, "synced with");
1777                         if (sc->sc_no_bssid)
1778                                 printf(" no-bssid");
1779                         else {
1780                                 printf(" %6D ssid ", sc->sc_bss.bssid, ":");
1781                                 awi_print_essid(sc->sc_bss.essid);
1782                         }
1783                         if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
1784                                 printf(" at chanset %d pattern %d\n",
1785                                     sc->sc_bss.chanset, sc->sc_bss.pattern);
1786                         else
1787                                 printf(" at channel %d\n", sc->sc_bss.chanset);
1788                 }
1789                 awi_drvstate(sc, AWI_DRV_ADHSY);
1790                 sc->sc_status = AWI_ST_RUNNING;
1791                 ifp->if_flags |= IFF_RUNNING;
1792                 awi_start(ifp);
1793         }
1794 }
1795
1796 static void
1797 awi_send_deauth(sc)
1798         struct awi_softc *sc;
1799 {
1800         struct ifnet *ifp = sc->sc_ifp;
1801         struct mbuf *m;
1802         struct ieee80211_frame *wh;
1803         u_int8_t *deauth;
1804
1805         MGETHDR(m, MB_DONTWAIT, MT_DATA);
1806         if (m == NULL)
1807                 return;
1808         if (ifp->if_flags & IFF_DEBUG)
1809                 if_printf(ifp, "sending deauth to %6D\n",
1810                           sc->sc_bss.bssid, ":");
1811
1812         wh = mtod(m, struct ieee80211_frame *);
1813         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
1814             IEEE80211_FC0_SUBTYPE_AUTH;
1815         wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
1816         LE_WRITE_2(wh->i_dur, 0);
1817         LE_WRITE_2(wh->i_seq, 0);
1818         memcpy(wh->i_addr1, sc->sc_bss.bssid, ETHER_ADDR_LEN);
1819         memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
1820         memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
1821
1822         deauth = (u_int8_t *)&wh[1];
1823         LE_WRITE_2(deauth, IEEE80211_REASON_AUTH_LEAVE);
1824         deauth += 2;
1825
1826         m->m_pkthdr.len = m->m_len = deauth - mtod(m, u_int8_t *);
1827         IF_ENQUEUE(&sc->sc_mgtq, m);
1828         awi_start(ifp);
1829         awi_drvstate(sc, AWI_DRV_INFTOSS);
1830 }
1831
1832 static void
1833 awi_send_auth(sc, seq)
1834         struct awi_softc *sc;
1835         int seq;
1836 {
1837         struct ifnet *ifp = sc->sc_ifp;
1838         struct mbuf *m;
1839         struct ieee80211_frame *wh;
1840         u_int8_t *auth;
1841
1842         MGETHDR(m, MB_DONTWAIT, MT_DATA);
1843         if (m == NULL)
1844                 return;
1845         sc->sc_status = AWI_ST_AUTH;
1846         if (ifp->if_flags & IFF_DEBUG)
1847                 if_printf(ifp, "sending auth to %6D\n",
1848                           sc->sc_bss.bssid, ":");
1849
1850         wh = mtod(m, struct ieee80211_frame *);
1851         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
1852             IEEE80211_FC0_SUBTYPE_AUTH;
1853         wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
1854         LE_WRITE_2(wh->i_dur, 0);
1855         LE_WRITE_2(wh->i_seq, 0);
1856         memcpy(wh->i_addr1, sc->sc_bss.esrc, ETHER_ADDR_LEN);
1857         memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
1858         memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
1859
1860         auth = (u_int8_t *)&wh[1];
1861         /* algorithm number */
1862         LE_WRITE_2(auth, IEEE80211_AUTH_ALG_OPEN);
1863         auth += 2;
1864         /* sequence number */
1865         LE_WRITE_2(auth, seq);
1866         auth += 2;
1867         /* status */
1868         LE_WRITE_2(auth, 0);
1869         auth += 2;
1870
1871         m->m_pkthdr.len = m->m_len = auth - mtod(m, u_int8_t *);
1872         IF_ENQUEUE(&sc->sc_mgtq, m);
1873         awi_start(ifp);
1874
1875         sc->sc_mgt_timer = AWI_TRANS_TIMEOUT / 1000;
1876         ifp->if_timer = 1;
1877 }
1878
1879 static void
1880 awi_recv_auth(sc, m0)
1881         struct awi_softc *sc;
1882         struct mbuf *m0;
1883 {
1884         struct ifnet *ifp = sc->sc_ifp;
1885         struct ieee80211_frame *wh;
1886         u_int8_t *auth, *eframe;
1887         struct awi_bss *bp;
1888         u_int16_t status;
1889
1890         wh = mtod(m0, struct ieee80211_frame *);
1891         auth = (u_int8_t *)&wh[1];
1892         eframe = mtod(m0, u_int8_t *) + m0->m_len;
1893         if (ifp->if_flags & IFF_DEBUG)
1894                 if_printf(ifp, "receive auth from %6D\n", wh->i_addr2, ":");
1895
1896         /* algorithm number */
1897         if (LE_READ_2(auth) != IEEE80211_AUTH_ALG_OPEN)
1898                 return;
1899         auth += 2;
1900         if (!sc->sc_mib_local.Network_Mode) {
1901                 if (sc->sc_status != AWI_ST_RUNNING)
1902                         return;
1903                 if (LE_READ_2(auth) == 1)
1904                         awi_send_auth(sc, 2);
1905                 return;
1906         }
1907         if (sc->sc_status != AWI_ST_AUTH)
1908                 return;
1909         /* sequence number */
1910         if (LE_READ_2(auth) != 2)
1911                 return;
1912         auth += 2;
1913         /* status */
1914         status = LE_READ_2(auth);
1915         if (status != 0) {
1916                 if_printf(ifp, "authentication failed (reason %d)\n", status);
1917                 for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL;
1918                     bp = TAILQ_NEXT(bp, list)) {
1919                         if (memcmp(bp->esrc, sc->sc_bss.esrc, ETHER_ADDR_LEN)
1920                             == 0) {
1921                                 bp->fails++;
1922                                 break;
1923                         }
1924                 }
1925                 return;
1926         }
1927         sc->sc_mgt_timer = 0;
1928         awi_drvstate(sc, AWI_DRV_INFAUTH);
1929         awi_send_asreq(sc, 0);
1930 }
1931
1932 static void
1933 awi_send_asreq(sc, reassoc)
1934         struct awi_softc *sc;
1935         int reassoc;
1936 {
1937         struct ifnet *ifp = sc->sc_ifp;
1938         struct mbuf *m;
1939         struct ieee80211_frame *wh;
1940         u_int16_t lintval;
1941         u_int8_t *asreq;
1942
1943         MGETHDR(m, MB_DONTWAIT, MT_DATA);
1944         if (m == NULL)
1945                 return;
1946         sc->sc_status = AWI_ST_ASSOC;
1947         if (ifp->if_flags & IFF_DEBUG)
1948                 if_printf(ifp, "sending %sassoc req to %6D\n",
1949                     reassoc ? "re" : "", sc->sc_bss.bssid, ":");
1950
1951         wh = mtod(m, struct ieee80211_frame *);
1952         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT;
1953         if (reassoc)
1954                 wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_REASSOC_REQ;
1955         else
1956                 wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
1957         wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
1958         LE_WRITE_2(wh->i_dur, 0);
1959         LE_WRITE_2(wh->i_seq, 0);
1960         memcpy(wh->i_addr1, sc->sc_bss.esrc, ETHER_ADDR_LEN);
1961         memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
1962         memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
1963
1964         asreq = (u_int8_t *)&wh[1];
1965
1966         /* capability info */
1967         if (sc->sc_wep_algo == NULL)
1968                 LE_WRITE_2(asreq, IEEE80211_CAPINFO_CF_POLLABLE);
1969         else
1970                 LE_WRITE_2(asreq,
1971                     IEEE80211_CAPINFO_CF_POLLABLE | IEEE80211_CAPINFO_PRIVACY);
1972         asreq += 2;
1973         /* listen interval */
1974         lintval = LE_READ_2(&sc->sc_mib_mgt.aListen_Interval);
1975         LE_WRITE_2(asreq, lintval);
1976         asreq += 2;
1977         if (reassoc) {
1978                 /* current AP address */
1979                 memcpy(asreq, sc->sc_bss.bssid, ETHER_ADDR_LEN);
1980                 asreq += ETHER_ADDR_LEN;
1981         }
1982         /* ssid */
1983         memcpy(asreq, sc->sc_bss.essid, 2 + sc->sc_bss.essid[1]);
1984         asreq += 2 + asreq[1];
1985         /* supported rates */
1986         memcpy(asreq, &sc->sc_mib_phy.aSuprt_Data_Rates, 4);
1987         asreq += 2 + asreq[1];
1988
1989         m->m_pkthdr.len = m->m_len = asreq - mtod(m, u_int8_t *);
1990         IF_ENQUEUE(&sc->sc_mgtq, m);
1991         awi_start(ifp);
1992
1993         sc->sc_mgt_timer = AWI_TRANS_TIMEOUT / 1000;
1994         ifp->if_timer = 1;
1995 }
1996
1997 static void
1998 awi_recv_asresp(sc, m0)
1999         struct awi_softc *sc;
2000         struct mbuf *m0;
2001 {
2002         struct ifnet *ifp = sc->sc_ifp;
2003         struct ieee80211_frame *wh;
2004         u_int8_t *asresp, *eframe;
2005         u_int16_t status;
2006         u_int8_t rate, *phy_rates;
2007         struct awi_bss *bp;
2008         int i, j;
2009
2010         wh = mtod(m0, struct ieee80211_frame *);
2011         asresp = (u_int8_t *)&wh[1];
2012         eframe = mtod(m0, u_int8_t *) + m0->m_len;
2013         if (ifp->if_flags & IFF_DEBUG)
2014                 if_printf(ifp, "receive assoc resp from %6D\n",
2015                           wh->i_addr2, ":");
2016
2017         if (!sc->sc_mib_local.Network_Mode)
2018                 return;
2019
2020         if (sc->sc_status != AWI_ST_ASSOC)
2021                 return;
2022         /* capability info */
2023         asresp += 2;
2024         /* status */
2025         status = LE_READ_2(asresp);
2026         if (status != 0) {
2027                 if_printf(ifp, "association failed (reason %d)\n", status);
2028                 for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL;
2029                     bp = TAILQ_NEXT(bp, list)) {
2030                         if (memcmp(bp->esrc, sc->sc_bss.esrc, ETHER_ADDR_LEN)
2031                             == 0) {
2032                                 bp->fails++;
2033                                 break;
2034                         }
2035                 }
2036                 return;
2037         }
2038         asresp += 2;
2039         /* association id */
2040         asresp += 2;
2041         /* supported rates */
2042         rate = AWI_RATE_1MBIT;
2043         for (i = 0; i < asresp[1]; i++) {
2044                 if (AWI_80211_RATE(asresp[2 + i]) <= rate)
2045                         continue;
2046                 phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
2047                 for (j = 0; j < phy_rates[1]; j++) {
2048                         if (AWI_80211_RATE(asresp[2 + i]) ==
2049                             AWI_80211_RATE(phy_rates[2 + j]))
2050                                 rate = AWI_80211_RATE(asresp[2 + i]);
2051                 }
2052         }
2053         if (ifp->if_flags & IFF_DEBUG) {
2054                 if_printf(ifp, "associated with %6D ssid ",
2055                           sc->sc_bss.bssid, ":");
2056                 awi_print_essid(sc->sc_bss.essid);
2057                 if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
2058                         printf(" chanset %d pattern %d\n",
2059                             sc->sc_bss.chanset, sc->sc_bss.pattern);
2060                 else
2061                         printf(" channel %d\n", sc->sc_bss.chanset);
2062         }
2063         sc->sc_tx_rate = rate;
2064         sc->sc_mgt_timer = 0;
2065         sc->sc_rx_timer = 10;
2066         ifp->if_timer = 1;
2067         sc->sc_status = AWI_ST_RUNNING;
2068         ifp->if_flags |= IFF_RUNNING;
2069         awi_drvstate(sc, AWI_DRV_INFASSOC);
2070         awi_start(ifp);
2071 }
2072
2073 static int
2074 awi_mib(sc, cmd, mib)
2075         struct awi_softc *sc;
2076         u_int8_t cmd;
2077         u_int8_t mib;
2078 {
2079         int error;
2080         u_int8_t size, *ptr;
2081
2082         switch (mib) {
2083         case AWI_MIB_LOCAL:
2084                 ptr = (u_int8_t *)&sc->sc_mib_local;
2085                 size = sizeof(sc->sc_mib_local);
2086                 break;
2087         case AWI_MIB_ADDR:
2088                 ptr = (u_int8_t *)&sc->sc_mib_addr;
2089                 size = sizeof(sc->sc_mib_addr);
2090                 break;
2091         case AWI_MIB_MAC:
2092                 ptr = (u_int8_t *)&sc->sc_mib_mac;
2093                 size = sizeof(sc->sc_mib_mac);
2094                 break;
2095         case AWI_MIB_STAT:
2096                 ptr = (u_int8_t *)&sc->sc_mib_stat;
2097                 size = sizeof(sc->sc_mib_stat);
2098                 break;
2099         case AWI_MIB_MGT:
2100                 ptr = (u_int8_t *)&sc->sc_mib_mgt;
2101                 size = sizeof(sc->sc_mib_mgt);
2102                 break;
2103         case AWI_MIB_PHY:
2104                 ptr = (u_int8_t *)&sc->sc_mib_phy;
2105                 size = sizeof(sc->sc_mib_phy);
2106                 break;
2107         default:
2108                 return EINVAL;
2109         }
2110         if (sc->sc_cmd_inprog) {
2111                 error = awi_cmd_wait(sc);
2112                 if (error) {
2113                         if (error == EWOULDBLOCK)
2114                                 printf("awi_mib: cmd %d inprog",
2115                                     sc->sc_cmd_inprog);
2116                         return error;
2117                 }
2118         }
2119         sc->sc_cmd_inprog = cmd;
2120         if (cmd == AWI_CMD_SET_MIB)
2121                 awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, ptr, size);
2122         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, mib);
2123         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, size);
2124         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, 0);
2125         error = awi_cmd(sc, cmd);
2126         if (error)
2127                 return error;
2128         if (cmd == AWI_CMD_GET_MIB) {
2129                 awi_read_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, ptr, size);
2130 #ifdef AWI_DEBUG
2131                 if (awi_verbose) {
2132                         int i;
2133
2134                         printf("awi_mib: #%d:", mib);
2135                         for (i = 0; i < size; i++)
2136                                 printf(" %02x", ptr[i]);
2137                         printf("\n");
2138                 }
2139 #endif
2140         }
2141         return 0;
2142 }
2143
2144 static int
2145 awi_cmd_scan(sc)
2146         struct awi_softc *sc;
2147 {
2148         int error;
2149         u_int8_t scan_mode;
2150
2151         if (sc->sc_active_scan)
2152                 scan_mode = AWI_SCAN_ACTIVE;
2153         else
2154                 scan_mode = AWI_SCAN_PASSIVE;
2155         if (sc->sc_mib_mgt.aScan_Mode != scan_mode) {
2156                 sc->sc_mib_mgt.aScan_Mode = scan_mode;
2157                 error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT);
2158                 return error;
2159         }
2160
2161         if (sc->sc_cmd_inprog) {
2162                 error = awi_cmd_wait(sc);
2163                 if (error)
2164                         return error;
2165         }
2166         sc->sc_cmd_inprog = AWI_CMD_SCAN;
2167         awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_DURATION,
2168             sc->sc_active_scan ? AWI_ASCAN_DURATION : AWI_PSCAN_DURATION);
2169         if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
2170                 awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET,
2171                     sc->sc_scan_set);
2172                 awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN,
2173                     sc->sc_scan_cur);
2174                 awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 1);
2175         } else {
2176                 awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET,
2177                     sc->sc_scan_cur);
2178                 awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN, 0);
2179                 awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 0);
2180         }
2181         awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SUSP, 0);
2182         return awi_cmd(sc, AWI_CMD_SCAN);
2183 }
2184
2185 static int
2186 awi_cmd(sc, cmd)
2187         struct awi_softc *sc;
2188         u_int8_t cmd;
2189 {
2190         u_int8_t status;
2191         int error = 0;
2192
2193         sc->sc_cmd_inprog = cmd;
2194         awi_write_1(sc, AWI_CMD_STATUS, AWI_STAT_IDLE);
2195         awi_write_1(sc, AWI_CMD, cmd);
2196         if (sc->sc_status != AWI_ST_INIT)
2197                 return 0;
2198         error = awi_cmd_wait(sc);
2199         if (error)
2200                 return error;
2201         status = awi_read_1(sc, AWI_CMD_STATUS);
2202         awi_write_1(sc, AWI_CMD, 0);
2203         switch (status) {
2204         case AWI_STAT_OK:
2205                 break;
2206         case AWI_STAT_BADPARM:
2207                 return EINVAL;
2208         default:
2209                 if_printf(sc->sc_ifp, "command %d failed %x\n", cmd, status);
2210                 return ENXIO;
2211         }
2212         return 0;
2213 }
2214
2215 static void
2216 awi_cmd_done(sc)
2217         struct awi_softc *sc;
2218 {
2219         u_int8_t cmd, status;
2220
2221         status = awi_read_1(sc, AWI_CMD_STATUS);
2222         if (status == AWI_STAT_IDLE)
2223                 return;         /* stray interrupt */
2224
2225         cmd = sc->sc_cmd_inprog;
2226         sc->sc_cmd_inprog = 0;
2227         if (sc->sc_status == AWI_ST_INIT) {
2228                 wakeup(sc);
2229                 return;
2230         }
2231         awi_write_1(sc, AWI_CMD, 0);
2232
2233         if (status != AWI_STAT_OK) {
2234                 if_printf(sc->sc_ifp, "command %d failed %x\n", cmd, status);
2235                 return;
2236         }
2237         switch (sc->sc_status) {
2238         case AWI_ST_SCAN:
2239                 if (cmd == AWI_CMD_SET_MIB)
2240                         awi_cmd_scan(sc);       /* retry */
2241                 break;
2242         case AWI_ST_SETSS:
2243                 awi_try_sync(sc);
2244                 break;
2245         case AWI_ST_SYNC:
2246                 awi_sync_done(sc);
2247                 break;
2248         default:
2249                 break;
2250         }
2251 }
2252
2253 static int
2254 awi_next_txd(sc, len, framep, ntxdp)
2255         struct awi_softc *sc;
2256         int len;
2257         u_int32_t *framep, *ntxdp;
2258 {
2259         u_int32_t txd, ntxd, frame;
2260
2261         txd = sc->sc_txnext;
2262         frame = txd + AWI_TXD_SIZE;
2263         if (frame + len > sc->sc_txend)
2264                 frame = sc->sc_txbase;
2265         ntxd = frame + len;
2266         if (ntxd + AWI_TXD_SIZE > sc->sc_txend)
2267                 ntxd = sc->sc_txbase;
2268         *framep = frame;
2269         *ntxdp = ntxd;
2270         /*
2271          * Determine if there are any room in ring buffer.
2272          *              --- send wait,  === new data,  +++ conflict (ENOBUFS)
2273          *   base........................end
2274          *         done----txd=====ntxd         OK
2275          *       --txd=====done++++ntxd--       full
2276          *       --txd=====ntxd    done--       OK
2277          *       ==ntxd    done----txd===       OK
2278          *       ==done++++ntxd----txd===       full
2279          *       ++ntxd    txd=====done++       full
2280          */
2281         if (txd < ntxd) {
2282                 if (txd < sc->sc_txdone && ntxd + AWI_TXD_SIZE > sc->sc_txdone)
2283                         return ENOBUFS;
2284         } else {
2285                 if (txd < sc->sc_txdone || ntxd + AWI_TXD_SIZE > sc->sc_txdone)
2286                         return ENOBUFS;
2287         }
2288         return 0;
2289 }
2290
2291 static int
2292 awi_intr_lock(sc)
2293         struct awi_softc *sc;
2294 {
2295         u_int8_t status;
2296         int i, retry;
2297
2298         status = 1;
2299         for (retry = 0; retry < 10; retry++) {
2300                 for (i = 0; i < AWI_LOCKOUT_TIMEOUT*1000/5; i++) {
2301                         status = awi_read_1(sc, AWI_LOCKOUT_HOST);
2302                         if (status == 0)
2303                                 break;
2304                         DELAY(5);
2305                 }
2306                 if (status != 0)
2307                         break;
2308                 awi_write_1(sc, AWI_LOCKOUT_MAC, 1);
2309                 status = awi_read_1(sc, AWI_LOCKOUT_HOST);
2310                 if (status == 0)
2311                         break;
2312                 awi_write_1(sc, AWI_LOCKOUT_MAC, 0);
2313         }
2314         if (status != 0) {
2315                 if_printf(sc->sc_ifp, "failed to lock interrupt\n");
2316                 return ENXIO;
2317         }
2318         return 0;
2319 }
2320
2321 static void
2322 awi_intr_unlock(sc)
2323         struct awi_softc *sc;
2324 {
2325
2326         awi_write_1(sc, AWI_LOCKOUT_MAC, 0);
2327 }
2328
2329 static int
2330 awi_cmd_wait(sc)
2331         struct awi_softc *sc;
2332 {
2333         int i, error = 0;
2334
2335         i = 0;
2336         while (sc->sc_cmd_inprog) {
2337                 if (sc->sc_invalid)
2338                         return ENXIO;
2339                 if (awi_read_1(sc, AWI_CMD) != sc->sc_cmd_inprog) {
2340                         if_printf(sc->sc_ifp, "failed to access hardware\n");
2341                         sc->sc_invalid = 1;
2342                         return ENXIO;
2343                 }
2344                 sc->sc_sleep_cnt++;
2345                 error = tsleep(sc, 0, "awicmd", AWI_CMD_TIMEOUT*hz/1000);
2346                 sc->sc_sleep_cnt--;
2347                 if (error)
2348                         break;
2349         }
2350         return error;
2351 }
2352
2353 static void
2354 awi_print_essid(essid)
2355         u_int8_t *essid;
2356 {
2357         int i, len;
2358         u_int8_t *p;
2359
2360         len = essid[1];
2361         if (len > IEEE80211_NWID_LEN)
2362                 len = IEEE80211_NWID_LEN;       /*XXX*/
2363         /* determine printable or not */
2364         for (i = 0, p = essid + 2; i < len; i++, p++) {
2365                 if (*p < ' ' || *p > 0x7e)
2366                         break;
2367         }
2368         if (i == len) {
2369                 printf("\"");
2370                 for (i = 0, p = essid + 2; i < len; i++, p++)
2371                         printf("%c", *p);
2372                 printf("\"");
2373         } else {
2374                 printf("0x");
2375                 for (i = 0, p = essid + 2; i < len; i++, p++)
2376                         printf("%02x", *p);
2377         }
2378 }
2379
2380 #ifdef AWI_DEBUG
2381 static void
2382 awi_dump_pkt(sc, m, rssi)
2383         struct awi_softc *sc;
2384         struct mbuf *m;
2385         int rssi;
2386 {
2387         struct ieee80211_frame *wh;
2388         int i, l;
2389
2390         wh = mtod(m, struct ieee80211_frame *);
2391
2392         if (awi_dump_mask != 0 &&
2393             ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK)==IEEE80211_FC1_DIR_NODS) &&
2394             ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)==IEEE80211_FC0_TYPE_MGT)) {
2395                 if ((AWI_DUMP_MASK(wh->i_fc[0]) & awi_dump_mask) != 0)
2396                         return;
2397         }
2398         if (awi_dump_mask < 0 &&
2399             (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)==IEEE80211_FC0_TYPE_DATA)
2400                 return;
2401
2402         if (rssi < 0)
2403                 printf("tx: ");
2404         else
2405                 printf("rx: ");
2406         switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
2407         case IEEE80211_FC1_DIR_NODS:
2408                 printf("NODS %6D->%6D(%6D)", wh->i_addr2, ":",
2409                        wh->i_addr1, ":", wh->i_addr3, ":");
2410                 break;
2411         case IEEE80211_FC1_DIR_TODS:
2412                 printf("TODS %6D->%6D(%6D)", wh->i_addr2, ":",
2413                        wh->i_addr3, ":", wh->i_addr1, ":");
2414                 break;
2415         case IEEE80211_FC1_DIR_FROMDS:
2416                 printf("FRDS %6D->%6D(%6D)", wh->i_addr3, ":",
2417                        wh->i_addr1, ":", wh->i_addr2, ":");
2418                 break;
2419         case IEEE80211_FC1_DIR_DSTODS:
2420                 printf("DSDS %6D->%6D(%6D->%6D)", (u_int8_t *)&wh[1], ":",
2421                        wh->i_addr3, ":", wh->i_addr2, ":", wh->i_addr1, ":");
2422                 break;
2423         }
2424         switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
2425         case IEEE80211_FC0_TYPE_DATA:
2426                 printf(" data");
2427                 break;
2428         case IEEE80211_FC0_TYPE_MGT:
2429                 switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
2430                 case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
2431                         printf(" probe_req");
2432                         break;
2433                 case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
2434                         printf(" probe_resp");
2435                         break;
2436                 case IEEE80211_FC0_SUBTYPE_BEACON:
2437                         printf(" beacon");
2438                         break;
2439                 case IEEE80211_FC0_SUBTYPE_AUTH:
2440                         printf(" auth");
2441                         break;
2442                 case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
2443                         printf(" assoc_req");
2444                         break;
2445                 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
2446                         printf(" assoc_resp");
2447                         break;
2448                 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
2449                         printf(" reassoc_req");
2450                         break;
2451                 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
2452                         printf(" reassoc_resp");
2453                         break;
2454                 case IEEE80211_FC0_SUBTYPE_DEAUTH:
2455                         printf(" deauth");
2456                         break;
2457                 case IEEE80211_FC0_SUBTYPE_DISASSOC:
2458                         printf(" disassoc");
2459                         break;
2460                 default:
2461                         printf(" mgt#%d",
2462                             wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
2463                         break;
2464                 }
2465                 break;
2466         default:
2467                 printf(" type#%d",
2468                     wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
2469                 break;
2470         }
2471         if (wh->i_fc[1] & IEEE80211_FC1_WEP)
2472                 printf(" WEP");
2473         if (rssi >= 0)
2474                 printf(" +%d", rssi);
2475         printf("\n");
2476         if (awi_dump_len > 0) {
2477                 l = m->m_len;
2478                 if (l > awi_dump_len + sizeof(*wh))
2479                         l = awi_dump_len + sizeof(*wh);
2480                 i = sizeof(*wh);
2481                 if (awi_dump_hdr)
2482                         i = 0;
2483                 for (; i < l; i++) {
2484                         if ((i & 1) == 0)
2485                                 printf(" ");
2486                         printf("%02x", mtod(m, u_int8_t *)[i]);
2487                 }
2488                 printf("\n");
2489         }
2490 }
2491 #endif