No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / ic / an.c
blob7b4ea2bfc80fe670ed92b2ceda3fd88f72b35443
1 /* $NetBSD: an.c,v 1.56 2009/05/12 14:25:17 cegger Exp $ */
2 /*
3 * Copyright (c) 1997, 1998, 1999
4 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Bill Paul.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
33 * $FreeBSD: src/sys/dev/an/if_an.c,v 1.12 2000/11/13 23:04:12 wpaul Exp $
36 * Copyright (c) 2004, 2005 David Young. All rights reserved.
37 * Copyright (c) 2004, 2005 OJC Technologies. All rights reserved.
38 * Copyright (c) 2004, 2005 Dayton Data Center Services, LLC. All
39 * rights reserved.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the author nor the names of any co-contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY David Young AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL David Young AND CONTRIBUTORS
57 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
58 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
59 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
60 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
61 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
62 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
63 * THE POSSIBILITY OF SUCH DAMAGE.
67 * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD.
69 * Written by Bill Paul <wpaul@ctr.columbia.edu>
70 * Electrical Engineering Department
71 * Columbia University, New York City
75 * Ported to NetBSD from FreeBSD by Atsushi Onoe at the San Diego
76 * IETF meeting.
79 #include <sys/cdefs.h>
80 __KERNEL_RCSID(0, "$NetBSD: an.c,v 1.56 2009/05/12 14:25:17 cegger Exp $");
82 #include "bpfilter.h"
84 #include <sys/param.h>
85 #include <sys/callout.h>
86 #include <sys/sysctl.h>
87 #include <sys/systm.h>
88 #include <sys/sockio.h>
89 #include <sys/mbuf.h>
90 #include <sys/kernel.h>
91 #include <sys/ucred.h>
92 #include <sys/socket.h>
93 #include <sys/device.h>
94 #include <sys/proc.h>
95 #include <sys/md4.h>
96 #include <sys/endian.h>
97 #include <sys/kauth.h>
99 #include <sys/bus.h>
101 #include <net/if.h>
102 #include <net/if_dl.h>
103 #include <net/if_ether.h>
104 #include <net/if_llc.h>
105 #include <net/if_media.h>
106 #include <net/if_types.h>
108 #include <net80211/ieee80211_netbsd.h>
109 #include <net80211/ieee80211_var.h>
110 #include <net80211/ieee80211_radiotap.h>
112 #if NBPFILTER > 0
113 #include <net/bpf.h>
114 #include <net/bpfdesc.h>
115 #endif
117 #include <dev/ic/anreg.h>
118 #include <dev/ic/anvar.h>
120 static int an_reset(struct an_softc *);
121 static void an_wait(struct an_softc *);
122 static int an_init(struct ifnet *);
123 static void an_stop(struct ifnet *, int);
124 static void an_start(struct ifnet *);
125 static void an_watchdog(struct ifnet *);
126 static int an_ioctl(struct ifnet *, u_long, void *);
127 static int an_media_change(struct ifnet *);
128 static void an_media_status(struct ifnet *, struct ifmediareq *);
130 static int an_set_nwkey(struct an_softc *, struct ieee80211_nwkey *);
131 static int an_set_nwkey_wep(struct an_softc *, struct ieee80211_nwkey *);
132 static int an_set_nwkey_eap(struct an_softc *, struct ieee80211_nwkey *);
133 static int an_get_nwkey(struct an_softc *, struct ieee80211_nwkey *);
134 static int an_write_wepkey(struct an_softc *, int, struct an_wepkey *,
135 int);
137 static void an_rx_intr(struct an_softc *);
138 static void an_tx_intr(struct an_softc *, int);
139 static void an_linkstat_intr(struct an_softc *);
141 static int an_cmd(struct an_softc *, int, int);
142 static int an_seek_bap(struct an_softc *, int, int);
143 static int an_read_bap(struct an_softc *, int, int, void *, int);
144 static int an_write_bap(struct an_softc *, int, int, void *, int);
145 static int an_mwrite_bap(struct an_softc *, int, int, struct mbuf *, int);
146 static int an_read_rid(struct an_softc *, int, void *, int *);
147 static int an_write_rid(struct an_softc *, int, void *, int);
149 static int an_alloc_fid(struct an_softc *, int, int *);
151 static int an_newstate(struct ieee80211com *, enum ieee80211_state, int);
153 #ifdef AN_DEBUG
154 int an_debug = 0;
156 #define DPRINTF(X) if (an_debug) printf X
157 #define DPRINTF2(X) if (an_debug > 1) printf X
158 static int an_sysctl_verify(SYSCTLFN_PROTO, int lower, int upper);
159 static int an_sysctl_verify_debug(SYSCTLFN_PROTO);
160 #else
161 #define DPRINTF(X)
162 #define DPRINTF2(X)
163 #endif
166 an_attach(struct an_softc *sc)
168 struct ieee80211com *ic = &sc->sc_ic;
169 struct ifnet *ifp = &sc->sc_if;
170 int i, s;
171 struct an_rid_wepkey *akey;
172 int buflen, kid, rid;
173 int chan, chan_min, chan_max;
175 s = splnet();
177 an_wait(sc);
178 if (an_reset(sc) != 0) {
179 config_deactivate(sc->sc_dev);
180 splx(s);
181 return 1;
184 /* Load factory config */
185 if (an_cmd(sc, AN_CMD_READCFG, 0) != 0) {
186 splx(s);
187 aprint_error_dev(sc->sc_dev, "failed to load config data\n");
188 return 1;
191 /* Read the current configuration */
192 buflen = sizeof(sc->sc_config);
193 if (an_read_rid(sc, AN_RID_GENCONFIG, &sc->sc_config, &buflen) != 0) {
194 splx(s);
195 aprint_error_dev(sc->sc_dev, "read config failed\n");
196 return 1;
199 /* Read the card capabilities */
200 buflen = sizeof(sc->sc_caps);
201 if (an_read_rid(sc, AN_RID_CAPABILITIES, &sc->sc_caps, &buflen) != 0) {
202 splx(s);
203 aprint_error_dev(sc->sc_dev, "read caps failed\n");
204 return 1;
207 #ifdef AN_DEBUG
208 if (an_debug) {
209 static const int dumprid[] = {
210 AN_RID_GENCONFIG, AN_RID_CAPABILITIES, AN_RID_SSIDLIST,
211 AN_RID_APLIST, AN_RID_STATUS, AN_RID_ENCAP
214 for (rid = 0; rid < sizeof(dumprid)/sizeof(dumprid[0]); rid++) {
215 buflen = sizeof(sc->sc_buf);
216 if (an_read_rid(sc, dumprid[rid], &sc->sc_buf, &buflen)
217 != 0)
218 continue;
219 printf("%04x (%d):\n", dumprid[rid], buflen);
220 for (i = 0; i < (buflen + 1) / 2; i++)
221 printf(" %04x", sc->sc_buf.sc_val[i]);
222 printf("\n");
225 #endif
227 /* Read WEP settings from persistent memory */
228 akey = &sc->sc_buf.sc_wepkey;
229 buflen = sizeof(struct an_rid_wepkey);
230 rid = AN_RID_WEP_VOLATILE; /* first persistent key */
231 while (an_read_rid(sc, rid, akey, &buflen) == 0) {
232 kid = le16toh(akey->an_key_index);
233 DPRINTF(("an_attach: wep rid=0x%x len=%d(%zu) index=0x%04x "
234 "mac[0]=%02x keylen=%d\n",
235 rid, buflen, sizeof(*akey), kid,
236 akey->an_mac_addr[0], le16toh(akey->an_key_len)));
237 if (kid == 0xffff) {
238 sc->sc_tx_perskey = akey->an_mac_addr[0];
239 sc->sc_tx_key = -1;
240 break;
242 if (kid >= IEEE80211_WEP_NKID)
243 break;
244 sc->sc_perskeylen[kid] = le16toh(akey->an_key_len);
245 sc->sc_wepkeys[kid].an_wep_keylen = -1;
246 rid = AN_RID_WEP_PERSISTENT; /* for next key */
247 buflen = sizeof(struct an_rid_wepkey);
250 aprint_normal_dev(sc->sc_dev, "%s %s (firmware %s)\n",
251 sc->sc_caps.an_manufname, sc->sc_caps.an_prodname,
252 sc->sc_caps.an_prodvers);
254 memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
256 ifp->if_softc = sc;
257 ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS | IFF_SIMPLEX |
258 IFF_MULTICAST | IFF_ALLMULTI;
259 ifp->if_ioctl = an_ioctl;
260 ifp->if_start = an_start;
261 ifp->if_init = an_init;
262 ifp->if_stop = an_stop;
263 ifp->if_watchdog = an_watchdog;
264 IFQ_SET_READY(&ifp->if_snd);
266 ic->ic_ifp = ifp;
267 ic->ic_phytype = IEEE80211_T_DS;
268 ic->ic_opmode = IEEE80211_M_STA;
269 ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_PMGT | IEEE80211_C_IBSS |
270 IEEE80211_C_MONITOR;
271 ic->ic_state = IEEE80211_S_INIT;
272 IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr);
274 switch (le16toh(sc->sc_caps.an_regdomain)) {
275 default:
276 case AN_REGDOMAIN_USA:
277 case AN_REGDOMAIN_CANADA:
278 chan_min = 1; chan_max = 11; break;
279 case AN_REGDOMAIN_EUROPE:
280 case AN_REGDOMAIN_AUSTRALIA:
281 chan_min = 1; chan_max = 13; break;
282 case AN_REGDOMAIN_JAPAN:
283 chan_min = 14; chan_max = 14; break;
284 case AN_REGDOMAIN_SPAIN:
285 chan_min = 10; chan_max = 11; break;
286 case AN_REGDOMAIN_FRANCE:
287 chan_min = 10; chan_max = 13; break;
288 case AN_REGDOMAIN_JAPANWIDE:
289 chan_min = 1; chan_max = 14; break;
292 for (chan = chan_min; chan <= chan_max; chan++) {
293 ic->ic_channels[chan].ic_freq =
294 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
295 ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_B;
297 ic->ic_ibss_chan = &ic->ic_channels[chan_min];
299 aprint_normal("%s: 802.11 address: %s, channel: %d-%d\n",
300 ifp->if_xname, ether_sprintf(ic->ic_myaddr), chan_min, chan_max);
302 /* Find supported rate */
303 for (i = 0; i < sizeof(sc->sc_caps.an_rates); i++) {
304 if (sc->sc_caps.an_rates[i] == 0)
305 continue;
306 ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
307 ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates++] =
308 sc->sc_caps.an_rates[i];
312 * Call MI attach routine.
314 if_attach(ifp);
315 ieee80211_ifattach(ic);
317 sc->sc_newstate = ic->ic_newstate;
318 ic->ic_newstate = an_newstate;
320 ieee80211_media_init(ic, an_media_change, an_media_status);
323 * radiotap BPF device
325 #if NBPFILTER > 0
326 bpfattach2(ifp, DLT_IEEE802_11_RADIO,
327 sizeof(struct ieee80211_frame) + 64, &sc->sc_drvbpf);
328 #endif
330 memset(&sc->sc_rxtapu, 0, sizeof(sc->sc_rxtapu));
331 sc->sc_rxtap.ar_ihdr.it_len = htole16(sizeof(sc->sc_rxtapu));
332 sc->sc_rxtap.ar_ihdr.it_present = htole32(AN_RX_RADIOTAP_PRESENT);
334 memset(&sc->sc_txtapu, 0, sizeof(sc->sc_txtapu));
335 sc->sc_txtap.at_ihdr.it_len = htole16(sizeof(sc->sc_txtapu));
336 sc->sc_txtap.at_ihdr.it_present = htole32(AN_TX_RADIOTAP_PRESENT);
338 sc->sc_attached = 1;
339 splx(s);
341 ieee80211_announce(ic);
342 return 0;
345 #ifdef AN_DEBUG
347 * Setup sysctl(3) MIB, hw.an.*
349 * TBD condition CTLFLAG_PERMANENT on being a module or not
351 SYSCTL_SETUP(sysctl_an, "sysctl an(4) subtree setup")
353 int rc;
354 const struct sysctlnode *cnode, *rnode;
356 if ((rc = sysctl_createv(clog, 0, NULL, &rnode,
357 CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
358 NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0)
359 goto err;
361 if ((rc = sysctl_createv(clog, 0, &rnode, &rnode,
362 CTLFLAG_PERMANENT, CTLTYPE_NODE, "an",
363 "Cisco/Aironet 802.11 controls",
364 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
365 goto err;
367 /* control debugging printfs */
368 if ((rc = sysctl_createv(clog, 0, &rnode, &cnode,
369 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
370 "debug", SYSCTL_DESCR("Enable Cisco/Aironet debugging output"),
371 an_sysctl_verify_debug, 0, &an_debug, 0,
372 CTL_CREATE, CTL_EOL)) != 0)
373 goto err;
375 return;
376 err:
377 printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
380 static int
381 an_sysctl_verify(SYSCTLFN_ARGS, int lower, int upper)
383 int error, t;
384 struct sysctlnode node;
386 node = *rnode;
387 t = *(int*)rnode->sysctl_data;
388 node.sysctl_data = &t;
389 error = sysctl_lookup(SYSCTLFN_CALL(&node));
390 if (error || newp == NULL)
391 return (error);
393 if (t < lower || t > upper)
394 return (EINVAL);
396 *(int*)rnode->sysctl_data = t;
398 return (0);
401 static int
402 an_sysctl_verify_debug(SYSCTLFN_ARGS)
404 return an_sysctl_verify(SYSCTLFN_CALL(rnode), 0, 2);
406 #endif /* AN_DEBUG */
409 an_detach(struct an_softc *sc)
411 struct ieee80211com *ic = &sc->sc_ic;
412 struct ifnet *ifp = &sc->sc_if;
413 int s;
415 if (!sc->sc_attached)
416 return 0;
418 s = splnet();
419 an_stop(ifp, 1);
420 ieee80211_ifdetach(ic);
421 if_detach(ifp);
422 splx(s);
423 return 0;
427 an_activate(device_t self, enum devact act)
429 struct an_softc *sc = device_private(self);
431 switch (act) {
432 case DVACT_DEACTIVATE:
433 if_deactivate(&sc->sc_if);
434 return 0;
435 default:
436 return EOPNOTSUPP;
441 an_intr(void *arg)
443 struct an_softc *sc = arg;
444 struct ifnet *ifp = &sc->sc_if;
445 int i;
446 u_int16_t status;
448 if (!sc->sc_enabled || !device_is_active(sc->sc_dev) ||
449 (ifp->if_flags & IFF_RUNNING) == 0)
450 return 0;
452 if ((ifp->if_flags & IFF_UP) == 0) {
453 CSR_WRITE_2(sc, AN_INT_EN, 0);
454 CSR_WRITE_2(sc, AN_EVENT_ACK, ~0);
455 return 1;
458 /* maximum 10 loops per interrupt */
459 for (i = 0; i < 10; i++) {
460 if (!sc->sc_enabled || !device_is_active(sc->sc_dev))
461 return 1;
462 if (CSR_READ_2(sc, AN_SW0) != AN_MAGIC) {
463 DPRINTF(("an_intr: magic number changed: %x\n",
464 CSR_READ_2(sc, AN_SW0)));
465 config_deactivate(sc->sc_dev);
466 return 1;
468 status = CSR_READ_2(sc, AN_EVENT_STAT);
469 CSR_WRITE_2(sc, AN_EVENT_ACK, status & ~(AN_INTRS));
470 if ((status & AN_INTRS) == 0)
471 break;
473 if (status & AN_EV_RX)
474 an_rx_intr(sc);
476 if (status & (AN_EV_TX | AN_EV_TX_EXC))
477 an_tx_intr(sc, status);
479 if (status & AN_EV_LINKSTAT)
480 an_linkstat_intr(sc);
482 if ((ifp->if_flags & IFF_OACTIVE) == 0 &&
483 sc->sc_ic.ic_state == IEEE80211_S_RUN &&
484 !IFQ_IS_EMPTY(&ifp->if_snd))
485 an_start(ifp);
488 return 1;
491 static int
492 an_init(struct ifnet *ifp)
494 struct an_softc *sc = ifp->if_softc;
495 struct ieee80211com *ic = &sc->sc_ic;
496 int i, error, fid;
498 DPRINTF(("an_init: enabled %d\n", sc->sc_enabled));
499 if (!sc->sc_enabled) {
500 if (sc->sc_enable)
501 (*sc->sc_enable)(sc);
502 an_wait(sc);
503 sc->sc_enabled = 1;
504 } else {
505 an_stop(ifp, 0);
506 if ((error = an_reset(sc)) != 0) {
507 printf("%s: failed to reset\n", ifp->if_xname);
508 an_stop(ifp, 1);
509 return error;
512 CSR_WRITE_2(sc, AN_SW0, AN_MAGIC);
514 /* Allocate the TX buffers */
515 for (i = 0; i < AN_TX_RING_CNT; i++) {
516 if ((error = an_alloc_fid(sc, AN_TX_MAX_LEN, &fid)) != 0) {
517 printf("%s: failed to allocate nic memory\n",
518 ifp->if_xname);
519 an_stop(ifp, 1);
520 return error;
522 DPRINTF2(("an_init: txbuf %d allocated %x\n", i, fid));
523 sc->sc_txd[i].d_fid = fid;
524 sc->sc_txd[i].d_inuse = 0;
526 sc->sc_txcur = sc->sc_txnext = 0;
528 IEEE80211_ADDR_COPY(sc->sc_config.an_macaddr, ic->ic_myaddr);
529 sc->sc_config.an_scanmode = htole16(AN_SCANMODE_ACTIVE);
530 sc->sc_config.an_authtype = htole16(AN_AUTHTYPE_OPEN); /*XXX*/
531 if (ic->ic_flags & IEEE80211_F_PRIVACY) {
532 sc->sc_config.an_authtype |=
533 htole16(AN_AUTHTYPE_PRIVACY_IN_USE);
534 if (sc->sc_use_leap)
535 sc->sc_config.an_authtype |=
536 htole16(AN_AUTHTYPE_LEAP);
538 sc->sc_config.an_listen_interval = htole16(ic->ic_lintval);
539 sc->sc_config.an_beacon_period = htole16(ic->ic_lintval);
540 if (ic->ic_flags & IEEE80211_F_PMGTON)
541 sc->sc_config.an_psave_mode = htole16(AN_PSAVE_PSP);
542 else
543 sc->sc_config.an_psave_mode = htole16(AN_PSAVE_CAM);
544 sc->sc_config.an_ds_channel =
545 htole16(ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
547 switch (ic->ic_opmode) {
548 case IEEE80211_M_STA:
549 sc->sc_config.an_opmode =
550 htole16(AN_OPMODE_INFRASTRUCTURE_STATION);
551 sc->sc_config.an_rxmode = htole16(AN_RXMODE_BC_MC_ADDR);
552 break;
553 case IEEE80211_M_IBSS:
554 sc->sc_config.an_opmode = htole16(AN_OPMODE_IBSS_ADHOC);
555 sc->sc_config.an_rxmode = htole16(AN_RXMODE_BC_MC_ADDR);
556 break;
557 case IEEE80211_M_MONITOR:
558 sc->sc_config.an_opmode =
559 htole16(AN_OPMODE_INFRASTRUCTURE_STATION);
560 sc->sc_config.an_rxmode =
561 htole16(AN_RXMODE_80211_MONITOR_ANYBSS);
562 sc->sc_config.an_authtype = htole16(AN_AUTHTYPE_NONE);
563 if (ic->ic_flags & IEEE80211_F_PRIVACY)
564 sc->sc_config.an_authtype |=
565 htole16(AN_AUTHTYPE_PRIVACY_IN_USE |
566 AN_AUTHTYPE_ALLOW_UNENCRYPTED);
567 break;
568 default:
569 printf("%s: bad opmode %d\n", ifp->if_xname, ic->ic_opmode);
570 an_stop(ifp, 1);
571 return EIO;
573 sc->sc_config.an_rxmode |= htole16(AN_RXMODE_NO_8023_HEADER);
575 /* Set the ssid list */
576 memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_ssidlist));
577 sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid_len =
578 htole16(ic->ic_des_esslen);
579 if (ic->ic_des_esslen)
580 memcpy(sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid,
581 ic->ic_des_essid, ic->ic_des_esslen);
582 if (an_write_rid(sc, AN_RID_SSIDLIST, &sc->sc_buf,
583 sizeof(sc->sc_buf.sc_ssidlist)) != 0) {
584 printf("%s: failed to write ssid list\n", ifp->if_xname);
585 an_stop(ifp, 1);
586 return error;
589 /* Set the AP list */
590 memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_aplist));
591 (void)an_write_rid(sc, AN_RID_APLIST, &sc->sc_buf,
592 sizeof(sc->sc_buf.sc_aplist));
594 /* Set the encapsulation */
595 for (i = 0; i < AN_ENCAP_NENTS; i++) {
596 sc->sc_buf.sc_encap.an_entry[i].an_ethertype = htole16(0);
597 sc->sc_buf.sc_encap.an_entry[i].an_action =
598 htole16(AN_RXENCAP_RFC1024 | AN_TXENCAP_RFC1024);
600 (void)an_write_rid(sc, AN_RID_ENCAP, &sc->sc_buf,
601 sizeof(sc->sc_buf.sc_encap));
603 /* Set the WEP Keys */
604 if (ic->ic_flags & IEEE80211_F_PRIVACY)
605 an_write_wepkey(sc, AN_RID_WEP_VOLATILE, sc->sc_wepkeys,
606 sc->sc_tx_key);
608 /* Set the configuration */
609 #ifdef AN_DEBUG
610 if (an_debug) {
611 printf("write config:\n");
612 for (i = 0; i < sizeof(sc->sc_config) / 2; i++)
613 printf(" %04x", ((u_int16_t *)&sc->sc_config)[i]);
614 printf("\n");
616 #endif
617 if (an_write_rid(sc, AN_RID_GENCONFIG, &sc->sc_config,
618 sizeof(sc->sc_config)) != 0) {
619 printf("%s: failed to write config\n", ifp->if_xname);
620 an_stop(ifp, 1);
621 return error;
624 /* Enable the MAC */
625 if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
626 aprint_error_dev(sc->sc_dev, "failed to enable MAC\n");
627 an_stop(ifp, 1);
628 return ENXIO;
630 if (ifp->if_flags & IFF_PROMISC)
631 an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
633 ifp->if_flags |= IFF_RUNNING;
634 ifp->if_flags &= ~IFF_OACTIVE;
635 ic->ic_state = IEEE80211_S_INIT;
636 if (ic->ic_opmode == IEEE80211_M_MONITOR)
637 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
639 /* enable interrupts */
640 CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
641 return 0;
644 static void
645 an_stop(struct ifnet *ifp, int disable)
647 struct an_softc *sc = ifp->if_softc;
648 int i, s;
650 if (!sc->sc_enabled)
651 return;
653 DPRINTF(("an_stop: disable %d\n", disable));
655 s = splnet();
656 ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
657 if (device_is_active(sc->sc_dev)) {
658 an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
659 CSR_WRITE_2(sc, AN_INT_EN, 0);
660 an_cmd(sc, AN_CMD_DISABLE, 0);
662 for (i = 0; i < AN_TX_RING_CNT; i++)
663 an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->sc_txd[i].d_fid);
666 sc->sc_tx_timer = 0;
667 ifp->if_timer = 0;
668 ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
670 if (disable) {
671 if (sc->sc_disable)
672 (*sc->sc_disable)(sc);
673 sc->sc_enabled = 0;
675 splx(s);
678 static void
679 an_start(struct ifnet *ifp)
681 struct an_softc *sc = (struct an_softc *)ifp->if_softc;
682 struct ieee80211com *ic = &sc->sc_ic;
683 struct ieee80211_node *ni;
684 struct ieee80211_frame *wh;
685 struct an_txframe frmhdr;
686 struct ether_header *eh;
687 struct mbuf *m;
688 u_int16_t len;
689 int cur, fid;
691 if (!sc->sc_enabled || !device_is_active(sc->sc_dev)) {
692 DPRINTF(("an_start: noop: enabled %d invalid %d\n",
693 sc->sc_enabled, !device_is_active(sc->sc_dev)));
694 return;
697 memset(&frmhdr, 0, sizeof(frmhdr));
698 cur = sc->sc_txnext;
699 for (;;) {
700 if (ic->ic_state != IEEE80211_S_RUN) {
701 DPRINTF(("an_start: not running %d\n", ic->ic_state));
702 break;
704 IFQ_POLL(&ifp->if_snd, m);
705 if (m == NULL) {
706 DPRINTF2(("an_start: no pending mbuf\n"));
707 break;
709 if (sc->sc_txd[cur].d_inuse) {
710 DPRINTF2(("an_start: %x/%d busy\n",
711 sc->sc_txd[cur].d_fid, cur));
712 ifp->if_flags |= IFF_OACTIVE;
713 break;
715 IFQ_DEQUEUE(&ifp->if_snd, m);
716 ifp->if_opackets++;
717 #if NBPFILTER > 0
718 if (ifp->if_bpf)
719 bpf_mtap(ifp->if_bpf, m);
720 #endif
721 eh = mtod(m, struct ether_header *);
722 ni = ieee80211_find_txnode(ic, eh->ether_dhost);
723 if (ni == NULL) {
724 /* NB: ieee80211_find_txnode does stat+msg */
725 goto bad;
727 if ((m = ieee80211_encap(ic, m, ni)) == NULL)
728 goto bad;
729 ieee80211_free_node(ni);
730 #if NBPFILTER > 0
731 if (ic->ic_rawbpf)
732 bpf_mtap(ic->ic_rawbpf, m);
733 #endif
735 wh = mtod(m, struct ieee80211_frame *);
736 if (ic->ic_flags & IEEE80211_F_PRIVACY)
737 wh->i_fc[1] |= IEEE80211_FC1_WEP;
738 m_copydata(m, 0, sizeof(struct ieee80211_frame),
739 (void *)&frmhdr.an_whdr);
741 /* insert payload length in front of llc/snap */
742 len = htons(m->m_pkthdr.len - sizeof(struct ieee80211_frame));
743 m_adj(m, sizeof(struct ieee80211_frame) - sizeof(len));
744 if (mtod(m, u_long) & 0x01)
745 memcpy(mtod(m, void *), &len, sizeof(len));
746 else
747 *mtod(m, u_int16_t *) = len;
750 * XXX Aironet firmware apparently convert the packet
751 * with longer than 1500 bytes in length into LLC/SNAP.
752 * If we have 1500 bytes in ethernet payload, it is
753 * 1508 bytes including LLC/SNAP and will be inserted
754 * additional LLC/SNAP header with 1501-1508 in its
755 * ethertype !!
756 * So we skip LLC/SNAP header and force firmware to
757 * convert it to LLC/SNAP again.
759 m_adj(m, sizeof(struct llc));
761 frmhdr.an_tx_ctl = htole16(AN_TXCTL_80211);
762 frmhdr.an_tx_payload_len = htole16(m->m_pkthdr.len);
763 frmhdr.an_gaplen = htole16(AN_TXGAP_802_11);
765 if (ic->ic_fixed_rate != -1)
766 frmhdr.an_tx_rate =
767 ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
768 ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
769 else
770 frmhdr.an_tx_rate = 0;
772 /* XXX radiotap for tx must be completed */
773 #if NBPFILTER > 0
774 if (sc->sc_drvbpf) {
775 struct an_tx_radiotap_header *tap = &sc->sc_txtap;
776 tap->at_rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate];
777 tap->at_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
778 tap->at_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
779 /* TBD tap->wt_flags */
780 bpf_mtap2(sc->sc_drvbpf, tap, tap->at_ihdr.it_len, m);
782 #endif
784 #ifdef AN_DEBUG
785 if ((ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) ==
786 (IFF_DEBUG|IFF_LINK2)) {
787 ieee80211_dump_pkt((u_int8_t *)&frmhdr.an_whdr,
788 sizeof(struct ieee80211_frame), -1, 0);
789 printf(" txctl 0x%x plen %u\n",
790 le16toh(frmhdr.an_tx_ctl),
791 le16toh(frmhdr.an_tx_payload_len));
793 #endif
794 if (sizeof(frmhdr) + AN_TXGAP_802_11 + sizeof(len) +
795 m->m_pkthdr.len > AN_TX_MAX_LEN)
796 goto bad;
798 fid = sc->sc_txd[cur].d_fid;
799 if (an_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0)
800 goto bad;
801 /* dummy write to avoid seek. */
802 an_write_bap(sc, fid, -1, &frmhdr, AN_TXGAP_802_11);
803 an_mwrite_bap(sc, fid, -1, m, m->m_pkthdr.len);
804 m_freem(m);
806 DPRINTF2(("an_start: send %zu byte via %x/%d\n",
807 ntohs(len) + sizeof(struct ieee80211_frame),
808 fid, cur));
809 sc->sc_txd[cur].d_inuse = 1;
810 if (an_cmd(sc, AN_CMD_TX, fid)) {
811 printf("%s: xmit failed\n", ifp->if_xname);
812 sc->sc_txd[cur].d_inuse = 0;
813 continue;
815 sc->sc_tx_timer = 5;
816 ifp->if_timer = 1;
817 AN_INC(cur, AN_TX_RING_CNT);
818 sc->sc_txnext = cur;
819 continue;
820 bad:
821 ifp->if_oerrors++;
822 m_freem(m);
826 static int
827 an_reset(struct an_softc *sc)
830 DPRINTF(("an_reset\n"));
832 if (!sc->sc_enabled)
833 return ENXIO;
835 an_cmd(sc, AN_CMD_ENABLE, 0);
836 an_cmd(sc, AN_CMD_FW_RESTART, 0);
837 an_cmd(sc, AN_CMD_NOOP2, 0);
839 if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) {
840 aprint_error_dev(sc->sc_dev, "reset failed\n");
841 return ETIMEDOUT;
844 an_cmd(sc, AN_CMD_DISABLE, 0);
845 return 0;
848 static void
849 an_watchdog(struct ifnet *ifp)
851 struct an_softc *sc = ifp->if_softc;
853 if (!sc->sc_enabled)
854 return;
856 if (sc->sc_tx_timer) {
857 if (--sc->sc_tx_timer == 0) {
858 printf("%s: device timeout\n", ifp->if_xname);
859 ifp->if_oerrors++;
860 an_init(ifp);
861 return;
863 ifp->if_timer = 1;
865 ieee80211_watchdog(&sc->sc_ic);
868 static int
869 an_ioctl(struct ifnet *ifp, u_long command, void *data)
871 struct an_softc *sc = ifp->if_softc;
872 int s, error = 0;
874 if (!device_is_active(sc->sc_dev))
875 return ENXIO;
877 s = splnet();
879 switch (command) {
880 case SIOCSIFFLAGS:
881 if ((error = ifioctl_common(ifp, command, data)) != 0)
882 break;
883 if (ifp->if_flags & IFF_UP) {
884 if (sc->sc_enabled) {
886 * To avoid rescanning another access point,
887 * do not call an_init() here. Instead, only
888 * reflect promisc mode settings.
890 error = an_cmd(sc, AN_CMD_SET_MODE,
891 (ifp->if_flags & IFF_PROMISC) ? 0xffff : 0);
892 } else
893 error = an_init(ifp);
894 } else if (sc->sc_enabled)
895 an_stop(ifp, 1);
896 break;
897 case SIOCADDMULTI:
898 case SIOCDELMULTI:
899 error = ether_ioctl(ifp, command, data);
900 if (error == ENETRESET) {
901 /* we don't have multicast filter. */
902 error = 0;
904 break;
905 case SIOCS80211NWKEY:
906 error = an_set_nwkey(sc, (struct ieee80211_nwkey *)data);
907 break;
908 case SIOCG80211NWKEY:
909 error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data);
910 break;
911 default:
912 error = ieee80211_ioctl(&sc->sc_ic, command, data);
913 break;
915 if (error == ENETRESET) {
916 if (sc->sc_enabled)
917 error = an_init(ifp);
918 else
919 error = 0;
921 splx(s);
922 return error;
925 /* TBD factor with ieee80211_media_change */
926 static int
927 an_media_change(struct ifnet *ifp)
929 struct an_softc *sc = ifp->if_softc;
930 struct ieee80211com *ic = &sc->sc_ic;
931 struct ifmedia_entry *ime;
932 enum ieee80211_opmode newmode;
933 int i, rate, error = 0;
935 ime = ic->ic_media.ifm_cur;
936 if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
937 i = -1;
938 } else {
939 struct ieee80211_rateset *rs =
940 &ic->ic_sup_rates[IEEE80211_MODE_11B];
941 rate = ieee80211_media2rate(ime->ifm_media);
942 if (rate == 0)
943 return EINVAL;
944 for (i = 0; i < rs->rs_nrates; i++) {
945 if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate)
946 break;
948 if (i == rs->rs_nrates)
949 return EINVAL;
951 if (ic->ic_fixed_rate != i) {
952 ic->ic_fixed_rate = i;
953 error = ENETRESET;
956 if (ime->ifm_media & IFM_IEEE80211_ADHOC)
957 newmode = IEEE80211_M_IBSS;
958 else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
959 newmode = IEEE80211_M_HOSTAP;
960 else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
961 newmode = IEEE80211_M_MONITOR;
962 else
963 newmode = IEEE80211_M_STA;
964 if (ic->ic_opmode != newmode) {
965 ic->ic_opmode = newmode;
966 error = ENETRESET;
968 if (error == ENETRESET) {
969 if (sc->sc_enabled)
970 error = an_init(ifp);
971 else
972 error = 0;
974 ifp->if_baudrate = ifmedia_baudrate(ic->ic_media.ifm_cur->ifm_media);
976 return error;
979 static void
980 an_media_status(struct ifnet *ifp, struct ifmediareq *imr)
982 struct an_softc *sc = ifp->if_softc;
983 struct ieee80211com *ic = &sc->sc_ic;
984 int rate, buflen;
986 if (sc->sc_enabled == 0) {
987 imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
988 imr->ifm_status = 0;
989 return;
992 imr->ifm_status = IFM_AVALID;
993 imr->ifm_active = IFM_IEEE80211;
994 if (ic->ic_state == IEEE80211_S_RUN)
995 imr->ifm_status |= IFM_ACTIVE;
996 buflen = sizeof(sc->sc_buf);
997 if (ic->ic_fixed_rate != -1)
998 rate = ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
999 ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
1000 else if (an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen) != 0)
1001 rate = 0;
1002 else
1003 rate = le16toh(sc->sc_buf.sc_status.an_current_tx_rate);
1004 imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B);
1005 switch (ic->ic_opmode) {
1006 case IEEE80211_M_STA:
1007 break;
1008 case IEEE80211_M_IBSS:
1009 imr->ifm_active |= IFM_IEEE80211_ADHOC;
1010 break;
1011 case IEEE80211_M_HOSTAP:
1012 imr->ifm_active |= IFM_IEEE80211_HOSTAP;
1013 break;
1014 case IEEE80211_M_MONITOR:
1015 imr->ifm_active |= IFM_IEEE80211_MONITOR;
1016 break;
1017 default:
1018 break;
1022 static int
1023 an_set_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
1025 int error;
1026 struct ieee80211com *ic = &sc->sc_ic;
1027 u_int16_t prevauth;
1029 error = 0;
1030 prevauth = sc->sc_config.an_authtype;
1032 switch (nwkey->i_wepon) {
1033 case IEEE80211_NWKEY_OPEN:
1034 sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN;
1035 ic->ic_flags &= ~IEEE80211_F_PRIVACY;
1036 break;
1038 case IEEE80211_NWKEY_WEP:
1039 case IEEE80211_NWKEY_WEP | IEEE80211_NWKEY_PERSIST:
1040 error = an_set_nwkey_wep(sc, nwkey);
1041 if (error == 0 || error == ENETRESET) {
1042 sc->sc_config.an_authtype =
1043 AN_AUTHTYPE_OPEN | AN_AUTHTYPE_PRIVACY_IN_USE;
1044 ic->ic_flags |= IEEE80211_F_PRIVACY;
1046 break;
1048 case IEEE80211_NWKEY_EAP:
1049 error = an_set_nwkey_eap(sc, nwkey);
1050 if (error == 0 || error == ENETRESET) {
1051 sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN |
1052 AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_LEAP;
1053 ic->ic_flags |= IEEE80211_F_PRIVACY;
1055 break;
1056 default:
1057 error = EINVAL;
1058 break;
1060 if (error == 0 && prevauth != sc->sc_config.an_authtype)
1061 error = ENETRESET;
1062 return error;
1065 static int
1066 an_set_nwkey_wep(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
1068 int i, txkey, anysetkey, needreset, error;
1069 struct an_wepkey keys[IEEE80211_WEP_NKID];
1071 error = 0;
1072 memset(keys, 0, sizeof(keys));
1073 anysetkey = needreset = 0;
1075 /* load argument and sanity check */
1076 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1077 keys[i].an_wep_keylen = nwkey->i_key[i].i_keylen;
1078 if (keys[i].an_wep_keylen < 0)
1079 continue;
1080 if (keys[i].an_wep_keylen != 0 &&
1081 keys[i].an_wep_keylen < IEEE80211_WEP_KEYLEN)
1082 return EINVAL;
1083 if (keys[i].an_wep_keylen > sizeof(keys[i].an_wep_key))
1084 return EINVAL;
1085 if ((error = copyin(nwkey->i_key[i].i_keydat,
1086 keys[i].an_wep_key, keys[i].an_wep_keylen)) != 0)
1087 return error;
1088 anysetkey++;
1090 txkey = nwkey->i_defkid - 1;
1091 if (txkey >= 0) {
1092 if (txkey >= IEEE80211_WEP_NKID)
1093 return EINVAL;
1094 /* default key must have a valid value */
1095 if (keys[txkey].an_wep_keylen == 0 ||
1096 (keys[txkey].an_wep_keylen < 0 &&
1097 sc->sc_perskeylen[txkey] == 0))
1098 return EINVAL;
1099 anysetkey++;
1101 DPRINTF(("an_set_nwkey_wep: %s: %sold(%d:%d,%d,%d,%d) "
1102 "pers(%d:%d,%d,%d,%d) new(%d:%d,%d,%d,%d)\n",
1103 device_xname(sc->sc_dev),
1104 ((nwkey->i_wepon & IEEE80211_NWKEY_PERSIST) ? "persist: " : ""),
1105 sc->sc_tx_key,
1106 sc->sc_wepkeys[0].an_wep_keylen, sc->sc_wepkeys[1].an_wep_keylen,
1107 sc->sc_wepkeys[2].an_wep_keylen, sc->sc_wepkeys[3].an_wep_keylen,
1108 sc->sc_tx_perskey,
1109 sc->sc_perskeylen[0], sc->sc_perskeylen[1],
1110 sc->sc_perskeylen[2], sc->sc_perskeylen[3],
1111 txkey,
1112 keys[0].an_wep_keylen, keys[1].an_wep_keylen,
1113 keys[2].an_wep_keylen, keys[3].an_wep_keylen));
1114 if (!(nwkey->i_wepon & IEEE80211_NWKEY_PERSIST)) {
1115 /* set temporary keys */
1116 sc->sc_tx_key = txkey;
1117 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1118 if (keys[i].an_wep_keylen < 0)
1119 continue;
1120 memcpy(&sc->sc_wepkeys[i], &keys[i], sizeof(keys[i]));
1122 } else {
1123 /* set persist keys */
1124 if (anysetkey) {
1125 /* prepare to write nvram */
1126 if (!sc->sc_enabled) {
1127 if (sc->sc_enable)
1128 (*sc->sc_enable)(sc);
1129 an_wait(sc);
1130 sc->sc_enabled = 1;
1131 error = an_write_wepkey(sc,
1132 AN_RID_WEP_PERSISTENT, keys, txkey);
1133 if (sc->sc_disable)
1134 (*sc->sc_disable)(sc);
1135 sc->sc_enabled = 0;
1136 } else {
1137 an_cmd(sc, AN_CMD_DISABLE, 0);
1138 error = an_write_wepkey(sc,
1139 AN_RID_WEP_PERSISTENT, keys, txkey);
1140 an_cmd(sc, AN_CMD_ENABLE, 0);
1142 if (error)
1143 return error;
1145 if (txkey >= 0)
1146 sc->sc_tx_perskey = txkey;
1147 if (sc->sc_tx_key >= 0) {
1148 sc->sc_tx_key = -1;
1149 needreset++;
1151 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1152 if (sc->sc_wepkeys[i].an_wep_keylen >= 0) {
1153 memset(&sc->sc_wepkeys[i].an_wep_key, 0,
1154 sizeof(sc->sc_wepkeys[i].an_wep_key));
1155 sc->sc_wepkeys[i].an_wep_keylen = -1;
1156 needreset++;
1158 if (keys[i].an_wep_keylen >= 0)
1159 sc->sc_perskeylen[i] = keys[i].an_wep_keylen;
1162 if (needreset) {
1163 /* firmware restart to reload persistent key */
1164 an_reset(sc);
1166 if (anysetkey || needreset)
1167 error = ENETRESET;
1168 return error;
1171 static int
1172 an_set_nwkey_eap(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
1174 int i, error, len;
1175 struct ifnet *ifp = &sc->sc_if;
1176 struct an_rid_leapkey *key;
1177 u_int16_t unibuf[sizeof(key->an_key)];
1178 static const int leap_rid[] = { AN_RID_LEAP_PASS, AN_RID_LEAP_USER };
1179 MD4_CTX ctx;
1181 error = 0;
1183 if (nwkey->i_key[0].i_keydat == NULL &&
1184 nwkey->i_key[1].i_keydat == NULL)
1185 return 0;
1186 if (!sc->sc_enabled)
1187 return ENXIO;
1188 an_cmd(sc, AN_CMD_DISABLE, 0);
1189 key = &sc->sc_buf.sc_leapkey;
1190 for (i = 0; i < 2; i++) {
1191 if (nwkey->i_key[i].i_keydat == NULL)
1192 continue;
1193 len = nwkey->i_key[i].i_keylen;
1194 if (len > sizeof(key->an_key))
1195 return EINVAL;
1196 memset(key, 0, sizeof(*key));
1197 key->an_key_len = htole16(len);
1198 if ((error = copyin(nwkey->i_key[i].i_keydat, key->an_key,
1199 len)) != 0)
1200 return error;
1201 if (i == 1) {
1203 * Cisco seems to use PasswordHash and PasswordHashHash
1204 * in RFC-2759 (MS-CHAP-V2).
1206 memset(unibuf, 0, sizeof(unibuf));
1207 /* XXX: convert password to unicode */
1208 for (i = 0; i < len; i++)
1209 unibuf[i] = key->an_key[i];
1210 /* set PasswordHash */
1211 MD4Init(&ctx);
1212 MD4Update(&ctx, (u_int8_t *)unibuf, len * 2);
1213 MD4Final(key->an_key, &ctx);
1214 /* set PasswordHashHash */
1215 MD4Init(&ctx);
1216 MD4Update(&ctx, key->an_key, 16);
1217 MD4Final(key->an_key + 16, &ctx);
1218 key->an_key_len = htole16(32);
1220 if ((error = an_write_rid(sc, leap_rid[i], key,
1221 sizeof(*key))) != 0) {
1222 printf("%s: LEAP set failed\n", ifp->if_xname);
1223 return error;
1226 error = an_cmd(sc, AN_CMD_ENABLE, 0);
1227 if (error)
1228 printf("%s: an_set_nwkey: failed to enable MAC\n",
1229 ifp->if_xname);
1230 else
1231 error = ENETRESET;
1232 return error;
1235 static int
1236 an_get_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
1238 int i, error;
1240 error = 0;
1241 if (sc->sc_config.an_authtype & AN_AUTHTYPE_LEAP)
1242 nwkey->i_wepon = IEEE80211_NWKEY_EAP;
1243 else if (sc->sc_config.an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE)
1244 nwkey->i_wepon = IEEE80211_NWKEY_WEP;
1245 else
1246 nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
1247 if (sc->sc_tx_key == -1)
1248 nwkey->i_defkid = sc->sc_tx_perskey + 1;
1249 else
1250 nwkey->i_defkid = sc->sc_tx_key + 1;
1251 if (nwkey->i_key[0].i_keydat == NULL)
1252 return 0;
1253 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1254 if (nwkey->i_key[i].i_keydat == NULL)
1255 continue;
1256 /* do not show any keys to non-root user */
1257 /* XXX-elad: why is this inside a loop? */
1258 if ((error = kauth_authorize_network(curlwp->l_cred,
1259 KAUTH_NETWORK_INTERFACE,
1260 KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, sc->sc_ic.ic_ifp,
1261 KAUTH_ARG(SIOCG80211NWKEY), NULL)) != 0)
1262 break;
1263 nwkey->i_key[i].i_keylen = sc->sc_wepkeys[i].an_wep_keylen;
1264 if (nwkey->i_key[i].i_keylen < 0) {
1265 if (sc->sc_perskeylen[i] == 0)
1266 nwkey->i_key[i].i_keylen = 0;
1267 continue;
1269 if ((error = copyout(sc->sc_wepkeys[i].an_wep_key,
1270 nwkey->i_key[i].i_keydat,
1271 sc->sc_wepkeys[i].an_wep_keylen)) != 0)
1272 break;
1274 return error;
1277 static int
1278 an_write_wepkey(struct an_softc *sc, int type, struct an_wepkey *keys, int kid)
1280 int i, error;
1281 struct an_rid_wepkey *akey;
1283 error = 0;
1284 akey = &sc->sc_buf.sc_wepkey;
1285 memset(akey, 0, sizeof(struct an_rid_wepkey));
1286 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1287 if (keys[i].an_wep_keylen < 0 ||
1288 keys[i].an_wep_keylen > sizeof(akey->an_key))
1289 continue;
1290 akey->an_key_len = htole16(keys[i].an_wep_keylen);
1291 akey->an_key_index = htole16(i);
1292 akey->an_mac_addr[0] = 1; /* default mac */
1293 memcpy(akey->an_key, keys[i].an_wep_key, keys[i].an_wep_keylen);
1294 if ((error = an_write_rid(sc, type, akey, sizeof(*akey))) != 0)
1295 return error;
1297 if (kid >= 0) {
1298 akey->an_key_index = htole16(0xffff);
1299 akey->an_mac_addr[0] = kid;
1300 akey->an_key_len = htole16(0);
1301 memset(akey->an_key, 0, sizeof(akey->an_key));
1302 error = an_write_rid(sc, type, akey, sizeof(*akey));
1304 return error;
1307 #ifdef AN_DEBUG
1308 static void
1309 an_dump_pkt(const char *devname, struct mbuf *m)
1311 int col, col0, i;
1312 uint8_t *pkt = mtod(m, uint8_t *);
1313 const char *delim = "";
1314 int delimw = 0;
1316 printf("%s: pkt ", devname);
1317 col = col0 = strlen(devname) + strlen(": pkt ");
1318 for (i = 0; i < m->m_len; i++) {
1319 printf("%s%02x", delim, pkt[i]);
1320 delim = ":";
1321 delimw = 1;
1322 col += delimw + 2;
1323 if (col >= 72) {
1324 printf("\n%*s", col0, "");
1325 col = col0;
1326 delim = "";
1327 delimw = 0;
1330 if (col != 0)
1331 printf("\n");
1333 #endif /* AN_DEBUG */
1336 * Low level functions
1339 static void
1340 an_rx_intr(struct an_softc *sc)
1342 struct ieee80211com *ic = &sc->sc_ic;
1343 struct ifnet *ifp = &sc->sc_if;
1344 struct ieee80211_frame_min *wh;
1345 struct ieee80211_node *ni;
1346 struct an_rxframe frmhdr;
1347 struct mbuf *m;
1348 u_int16_t status;
1349 int fid, gaplen, len, off;
1350 uint8_t *gap;
1352 fid = CSR_READ_2(sc, AN_RX_FID);
1354 /* First read in the frame header */
1355 if (an_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) {
1356 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
1357 ifp->if_ierrors++;
1358 DPRINTF(("an_rx_intr: read fid %x failed\n", fid));
1359 return;
1362 #ifdef AN_DEBUG
1363 if ((ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) {
1364 ieee80211_dump_pkt((u_int8_t *)&frmhdr.an_whdr,
1365 sizeof(struct ieee80211_frame), frmhdr.an_rx_rate,
1366 frmhdr.an_rx_signal_strength);
1367 printf(" time 0x%x status 0x%x plen %u chan %u"
1368 " plcp %02x %02x %02x %02x gap %u\n",
1369 le32toh(frmhdr.an_rx_time), le16toh(frmhdr.an_rx_status),
1370 le16toh(frmhdr.an_rx_payload_len), frmhdr.an_rx_chan,
1371 frmhdr.an_plcp_hdr[0], frmhdr.an_plcp_hdr[1],
1372 frmhdr.an_plcp_hdr[2], frmhdr.an_plcp_hdr[3],
1373 le16toh(frmhdr.an_gaplen));
1375 #endif
1377 status = le16toh(frmhdr.an_rx_status);
1378 if ((status & AN_STAT_ERRSTAT) != 0 &&
1379 ic->ic_opmode != IEEE80211_M_MONITOR) {
1380 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
1381 ifp->if_ierrors++;
1382 DPRINTF(("an_rx_intr: fid %x status %x\n", fid, status));
1383 return;
1386 /* the payload length field includes a 16-bit "mystery field" */
1387 len = le16toh(frmhdr.an_rx_payload_len) - sizeof(uint16_t);
1388 off = ALIGN(sizeof(struct ieee80211_frame));
1390 if (off + len > MCLBYTES) {
1391 if (ic->ic_opmode != IEEE80211_M_MONITOR) {
1392 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
1393 ifp->if_ierrors++;
1394 DPRINTF(("an_rx_intr: oversized packet %d\n", len));
1395 return;
1397 len = 0;
1400 MGETHDR(m, M_DONTWAIT, MT_DATA);
1401 if (m == NULL) {
1402 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
1403 ifp->if_ierrors++;
1404 DPRINTF(("an_rx_intr: MGET failed\n"));
1405 return;
1407 if (off + len + AN_GAPLEN_MAX > MHLEN) {
1408 MCLGET(m, M_DONTWAIT);
1409 if ((m->m_flags & M_EXT) == 0) {
1410 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
1411 m_freem(m);
1412 ifp->if_ierrors++;
1413 DPRINTF(("an_rx_intr: MCLGET failed\n"));
1414 return;
1417 m->m_data += off - sizeof(struct ieee80211_frame);
1419 if (ic->ic_opmode != IEEE80211_M_MONITOR) {
1420 gaplen = le16toh(frmhdr.an_gaplen);
1421 if (gaplen > AN_GAPLEN_MAX) {
1422 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
1423 m_freem(m);
1424 ifp->if_ierrors++;
1425 DPRINTF(("%s: gap too long\n", __func__));
1426 return;
1429 * We don't need the 16-bit mystery field (payload length?),
1430 * so read it into the region reserved for the 802.11 header.
1432 * When Cisco Aironet 350 cards w/ firmware version 5 or
1433 * greater operate with certain Cisco 350 APs,
1434 * the "gap" is filled with the SNAP header. Read
1435 * it in after the 802.11 header.
1437 gap = m->m_data + sizeof(struct ieee80211_frame) -
1438 sizeof(uint16_t);
1439 an_read_bap(sc, fid, -1, gap, gaplen + sizeof(u_int16_t));
1440 #ifdef AN_DEBUG
1441 if ((ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) ==
1442 (IFF_DEBUG|IFF_LINK2)) {
1443 int i;
1444 printf(" gap&len");
1445 for (i = 0; i < gaplen + sizeof(u_int16_t); i++)
1446 printf(" %02x", gap[i]);
1447 printf("\n");
1449 #endif
1450 } else
1451 gaplen = 0;
1453 an_read_bap(sc, fid, -1,
1454 m->m_data + sizeof(struct ieee80211_frame) + gaplen, len);
1455 m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + gaplen +
1456 len;
1458 memcpy(m->m_data, &frmhdr.an_whdr, sizeof(struct ieee80211_frame));
1459 m->m_pkthdr.rcvif = ifp;
1460 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
1462 #if NBPFILTER > 0
1463 if (sc->sc_drvbpf) {
1464 struct an_rx_radiotap_header *tap = &sc->sc_rxtap;
1466 tap->ar_rate = frmhdr.an_rx_rate;
1467 tap->ar_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
1468 tap->ar_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
1469 tap->ar_antsignal = frmhdr.an_rx_signal_strength;
1470 if ((le16toh(frmhdr.an_rx_status) & AN_STAT_BADCRC) ||
1471 (le16toh(frmhdr.an_rx_status) & AN_STAT_ERRSTAT) ||
1472 (le16toh(frmhdr.an_rx_status) & AN_STAT_UNDECRYPTABLE))
1473 tap->ar_flags |= IEEE80211_RADIOTAP_F_BADFCS;
1475 bpf_mtap2(sc->sc_drvbpf, tap, tap->ar_ihdr.it_len, m);
1477 #endif
1478 wh = mtod(m, struct ieee80211_frame_min *);
1479 if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1481 * WEP is decrypted by hardware. Clear WEP bit
1482 * header for ieee80211_input().
1484 wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
1487 #ifdef AN_DEBUG
1488 if (an_debug > 1)
1489 an_dump_pkt(device_xname(sc->sc_dev), m);
1490 #endif /* AN_DEBUG */
1492 ni = ieee80211_find_rxnode(ic, wh);
1493 ieee80211_input(ic, m, ni, frmhdr.an_rx_signal_strength,
1494 le32toh(frmhdr.an_rx_time));
1495 ieee80211_free_node(ni);
1498 static void
1499 an_tx_intr(struct an_softc *sc, int status)
1501 struct ifnet *ifp = &sc->sc_if;
1502 int cur, fid;
1504 sc->sc_tx_timer = 0;
1505 ifp->if_flags &= ~IFF_OACTIVE;
1507 fid = CSR_READ_2(sc, AN_TX_CMP_FID);
1508 CSR_WRITE_2(sc, AN_EVENT_ACK, status & (AN_EV_TX | AN_EV_TX_EXC));
1510 if (status & AN_EV_TX_EXC)
1511 ifp->if_oerrors++;
1512 else
1513 ifp->if_opackets++;
1515 cur = sc->sc_txcur;
1516 if (sc->sc_txd[cur].d_fid == fid) {
1517 sc->sc_txd[cur].d_inuse = 0;
1518 DPRINTF2(("an_tx_intr: sent %x/%d\n", fid, cur));
1519 AN_INC(cur, AN_TX_RING_CNT);
1520 sc->sc_txcur = cur;
1521 } else {
1522 for (cur = 0; cur < AN_TX_RING_CNT; cur++) {
1523 if (fid == sc->sc_txd[cur].d_fid) {
1524 sc->sc_txd[cur].d_inuse = 0;
1525 break;
1528 if (ifp->if_flags & IFF_DEBUG)
1529 printf("%s: tx mismatch: "
1530 "expected %x(%d), actual %x(%d)\n",
1531 device_xname(sc->sc_dev),
1532 sc->sc_txd[sc->sc_txcur].d_fid, sc->sc_txcur,
1533 fid, cur);
1536 return;
1539 static void
1540 an_linkstat_intr(struct an_softc *sc)
1542 struct ieee80211com *ic = &sc->sc_ic;
1543 u_int16_t status;
1545 status = CSR_READ_2(sc, AN_LINKSTAT);
1546 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT);
1547 DPRINTF(("an_linkstat_intr: status 0x%x\n", status));
1549 if (status == AN_LINKSTAT_ASSOCIATED) {
1550 if (ic->ic_state != IEEE80211_S_RUN ||
1551 ic->ic_opmode == IEEE80211_M_IBSS)
1552 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
1553 } else {
1554 if (ic->ic_opmode == IEEE80211_M_STA)
1555 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
1559 /* Must be called at proper protection level! */
1560 static int
1561 an_cmd(struct an_softc *sc, int cmd, int val)
1563 int i, status;
1565 /* make sure that previous command completed */
1566 if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
1567 if (sc->sc_if.if_flags & IFF_DEBUG)
1568 printf("%s: command 0x%x busy\n", device_xname(sc->sc_dev),
1569 CSR_READ_2(sc, AN_COMMAND));
1570 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
1573 CSR_WRITE_2(sc, AN_PARAM0, val);
1574 CSR_WRITE_2(sc, AN_PARAM1, 0);
1575 CSR_WRITE_2(sc, AN_PARAM2, 0);
1576 CSR_WRITE_2(sc, AN_COMMAND, cmd);
1578 if (cmd == AN_CMD_FW_RESTART) {
1579 /* XXX: should sleep here */
1580 DELAY(100*1000);
1583 for (i = 0; i < AN_TIMEOUT; i++) {
1584 if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
1585 break;
1586 DELAY(10);
1589 status = CSR_READ_2(sc, AN_STATUS);
1591 /* clear stuck command busy if necessary */
1592 if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY)
1593 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
1595 /* Ack the command */
1596 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
1598 if (i == AN_TIMEOUT) {
1599 if (sc->sc_if.if_flags & IFF_DEBUG)
1600 printf("%s: command 0x%x param 0x%x timeout\n",
1601 device_xname(sc->sc_dev), cmd, val);
1602 return ETIMEDOUT;
1604 if (status & AN_STAT_CMD_RESULT) {
1605 if (sc->sc_if.if_flags & IFF_DEBUG)
1606 printf("%s: command 0x%x param 0x%x status 0x%x "
1607 "resp 0x%x 0x%x 0x%x\n",
1608 device_xname(sc->sc_dev), cmd, val, status,
1609 CSR_READ_2(sc, AN_RESP0), CSR_READ_2(sc, AN_RESP1),
1610 CSR_READ_2(sc, AN_RESP2));
1611 return EIO;
1614 return 0;
1619 * Wait for firmware come up after power enabled.
1621 static void
1622 an_wait(struct an_softc *sc)
1624 int i;
1626 CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_NOOP2);
1627 for (i = 0; i < 3*hz; i++) {
1628 if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
1629 break;
1630 (void)tsleep(sc, PWAIT, "anatch", 1);
1632 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
1635 static int
1636 an_seek_bap(struct an_softc *sc, int id, int off)
1638 int i, status;
1640 CSR_WRITE_2(sc, AN_SEL0, id);
1641 CSR_WRITE_2(sc, AN_OFF0, off);
1643 for (i = 0; ; i++) {
1644 status = CSR_READ_2(sc, AN_OFF0);
1645 if ((status & AN_OFF_BUSY) == 0)
1646 break;
1647 if (i == AN_TIMEOUT) {
1648 printf("%s: timeout in an_seek_bap to 0x%x/0x%x\n",
1649 device_xname(sc->sc_dev), id, off);
1650 sc->sc_bap_off = AN_OFF_ERR; /* invalidate */
1651 return ETIMEDOUT;
1653 DELAY(10);
1655 if (status & AN_OFF_ERR) {
1656 aprint_error_dev(sc->sc_dev, "failed in an_seek_bap to 0x%x/0x%x\n",
1657 id, off);
1658 sc->sc_bap_off = AN_OFF_ERR; /* invalidate */
1659 return EIO;
1661 sc->sc_bap_id = id;
1662 sc->sc_bap_off = off;
1663 return 0;
1666 static int
1667 an_read_bap(struct an_softc *sc, int id, int off, void *buf, int buflen)
1669 int error, cnt;
1671 if (buflen == 0)
1672 return 0;
1673 if (off == -1)
1674 off = sc->sc_bap_off;
1675 if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
1676 if ((error = an_seek_bap(sc, id, off)) != 0)
1677 return EIO;
1680 cnt = (buflen + 1) / 2;
1681 CSR_READ_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt);
1682 sc->sc_bap_off += cnt * 2;
1683 return 0;
1686 static int
1687 an_write_bap(struct an_softc *sc, int id, int off, void *buf, int buflen)
1689 int error, cnt;
1691 if (buflen == 0)
1692 return 0;
1693 if (off == -1)
1694 off = sc->sc_bap_off;
1695 if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
1696 if ((error = an_seek_bap(sc, id, off)) != 0)
1697 return EIO;
1700 cnt = (buflen + 1) / 2;
1701 CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt);
1702 sc->sc_bap_off += cnt * 2;
1703 return 0;
1706 static int
1707 an_mwrite_bap(struct an_softc *sc, int id, int off, struct mbuf *m, int totlen)
1709 int error, len, cnt;
1711 if (off == -1)
1712 off = sc->sc_bap_off;
1713 if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
1714 if ((error = an_seek_bap(sc, id, off)) != 0)
1715 return EIO;
1718 for (len = 0; m != NULL; m = m->m_next) {
1719 if (m->m_len == 0)
1720 continue;
1721 len = min(m->m_len, totlen);
1723 if ((mtod(m, u_long) & 0x1) || (len & 0x1)) {
1724 m_copydata(m, 0, totlen, (void *)&sc->sc_buf.sc_txbuf);
1725 cnt = (totlen + 1) / 2;
1726 CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0,
1727 sc->sc_buf.sc_val, cnt);
1728 off += cnt * 2;
1729 break;
1731 cnt = len / 2;
1732 CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, mtod(m, u_int16_t *),
1733 cnt);
1734 off += len;
1735 totlen -= len;
1737 sc->sc_bap_off = off;
1738 return 0;
1741 static int
1742 an_alloc_fid(struct an_softc *sc, int len, int *idp)
1744 int i;
1746 if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
1747 aprint_error_dev(sc->sc_dev, "failed to allocate %d bytes on NIC\n",
1748 len);
1749 return ENOMEM;
1752 for (i = 0; i < AN_TIMEOUT; i++) {
1753 if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
1754 break;
1755 if (i == AN_TIMEOUT) {
1756 printf("%s: timeout in alloc\n", device_xname(sc->sc_dev));
1757 return ETIMEDOUT;
1759 DELAY(10);
1762 *idp = CSR_READ_2(sc, AN_ALLOC_FID);
1763 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
1764 return 0;
1767 static int
1768 an_read_rid(struct an_softc *sc, int rid, void *buf, int *buflenp)
1770 int error;
1771 u_int16_t len;
1773 /* Tell the NIC to enter record read mode. */
1774 error = an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_READ, rid);
1775 if (error)
1776 return error;
1778 /* length in byte, including length itself */
1779 error = an_read_bap(sc, rid, 0, &len, sizeof(len));
1780 if (error)
1781 return error;
1783 len = le16toh(len) - 2;
1784 if (*buflenp < len) {
1785 aprint_error_dev(sc->sc_dev, "record buffer is too small, "
1786 "rid=%x, size=%d, len=%d\n",
1787 rid, *buflenp, len);
1788 return ENOSPC;
1790 *buflenp = len;
1791 return an_read_bap(sc, rid, sizeof(len), buf, len);
1794 static int
1795 an_write_rid(struct an_softc *sc, int rid, void *buf, int buflen)
1797 int error;
1798 u_int16_t len;
1800 /* length in byte, including length itself */
1801 len = htole16(buflen + 2);
1803 error = an_write_bap(sc, rid, 0, &len, sizeof(len));
1804 if (error)
1805 return error;
1806 error = an_write_bap(sc, rid, sizeof(len), buf, buflen);
1807 if (error)
1808 return error;
1810 return an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_WRITE, rid);
1813 static int
1814 an_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
1816 struct an_softc *sc = (struct an_softc *)ic->ic_ifp->if_softc;
1817 struct ieee80211_node *ni = ic->ic_bss;
1818 enum ieee80211_state ostate;
1819 int buflen;
1821 ostate = ic->ic_state;
1822 DPRINTF(("an_newstate: %s -> %s\n", ieee80211_state_name[ostate],
1823 ieee80211_state_name[nstate]));
1825 switch (nstate) {
1826 case IEEE80211_S_INIT:
1827 ic->ic_flags &= ~IEEE80211_F_IBSSON;
1828 return (*sc->sc_newstate)(ic, nstate, arg);
1830 case IEEE80211_S_SCAN:
1831 case IEEE80211_S_AUTH:
1832 case IEEE80211_S_ASSOC:
1833 ic->ic_state = nstate; /* NB: skip normal ieee80211 handling */
1834 return 0;
1836 case IEEE80211_S_RUN:
1837 buflen = sizeof(sc->sc_buf);
1838 an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen);
1839 IEEE80211_ADDR_COPY(ni->ni_bssid,
1840 sc->sc_buf.sc_status.an_cur_bssid);
1841 IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
1842 ni->ni_chan = &ic->ic_channels[
1843 le16toh(sc->sc_buf.sc_status.an_cur_channel)];
1844 ni->ni_esslen = le16toh(sc->sc_buf.sc_status.an_ssidlen);
1845 if (ni->ni_esslen > IEEE80211_NWID_LEN)
1846 ni->ni_esslen = IEEE80211_NWID_LEN; /*XXX*/
1847 memcpy(ni->ni_essid, sc->sc_buf.sc_status.an_ssid,
1848 ni->ni_esslen);
1849 ni->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B]; /*XXX*/
1850 if (ic->ic_ifp->if_flags & IFF_DEBUG) {
1851 printf("%s: ", device_xname(sc->sc_dev));
1852 if (ic->ic_opmode == IEEE80211_M_STA)
1853 printf("associated ");
1854 else
1855 printf("synchronized ");
1856 printf("with %s ssid ", ether_sprintf(ni->ni_bssid));
1857 ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
1858 printf(" channel %u start %uMb\n",
1859 le16toh(sc->sc_buf.sc_status.an_cur_channel),
1860 le16toh(sc->sc_buf.sc_status.an_current_tx_rate)/2);
1862 break;
1864 default:
1865 break;
1867 return (*sc->sc_newstate)(ic, nstate, arg);