Annotation of sys/dev/ic/an.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: an.c,v 1.53 2007/01/03 18:16:43 claudio Exp $ */
2: /* $NetBSD: an.c,v 1.34 2005/06/20 02:49:18 atatat Exp $ */
3: /*
4: * Copyright (c) 1997, 1998, 1999
5: * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by Bill Paul.
18: * 4. Neither the name of the author nor the names of any co-contributors
19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32: * THE POSSIBILITY OF SUCH DAMAGE.
33: *
34: * $FreeBSD: src/sys/dev/an/if_an.c,v 1.12 2000/11/13 23:04:12 wpaul Exp $
35: */
36: /*
37: * Copyright (c) 2004, 2005 David Young. All rights reserved.
38: * Copyright (c) 2004, 2005 OJC Technologies. All rights reserved.
39: * Copyright (c) 2004, 2005 Dayton Data Center Services, LLC. All
40: * rights reserved.
41: *
42: * Redistribution and use in source and binary forms, with or without
43: * modification, are permitted provided that the following conditions
44: * are met:
45: * 1. Redistributions of source code must retain the above copyright
46: * notice, this list of conditions and the following disclaimer.
47: * 2. Redistributions in binary form must reproduce the above copyright
48: * notice, this list of conditions and the following disclaimer in the
49: * documentation and/or other materials provided with the distribution.
50: * 3. Neither the name of the author nor the names of any co-contributors
51: * may be used to endorse or promote products derived from this software
52: * without specific prior written permission.
53: *
54: * THIS SOFTWARE IS PROVIDED BY David Young AND CONTRIBUTORS ``AS IS'' AND
55: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57: * ARE DISCLAIMED. IN NO EVENT SHALL David Young AND CONTRIBUTORS
58: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
64: * THE POSSIBILITY OF SUCH DAMAGE.
65: */
66:
67: /*
68: * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD.
69: *
70: * Written by Bill Paul <wpaul@ctr.columbia.edu>
71: * Electrical Engineering Department
72: * Columbia University, New York City
73: */
74:
75: /*
76: * Ported to NetBSD from FreeBSD by Atsushi Onoe at the San Diego
77: * IETF meeting.
78: */
79:
80: #include <sys/cdefs.h>
81:
82: #include "bpfilter.h"
83:
84: #include <sys/param.h>
85: #include <sys/systm.h>
86: #include <sys/sockio.h>
87: #include <sys/mbuf.h>
88: #include <sys/kernel.h>
89: #include <sys/ucred.h>
90: #include <sys/socket.h>
91: #include <sys/timeout.h>
92: #include <sys/device.h>
93: #include <sys/proc.h>
94: #include <sys/endian.h>
95: #include <sys/tree.h>
96:
97: #include <machine/bus.h>
98:
99: #include <net/if.h>
100: #include <net/if_dl.h>
101: #include <net/if_llc.h>
102: #include <net/if_media.h>
103: #include <net/if_types.h>
104:
105: #ifdef INET
106: #include <netinet/in.h>
107: #include <netinet/in_systm.h>
108: #include <netinet/in_var.h>
109: #include <netinet/ip.h>
110: #include <netinet/if_ether.h>
111: #endif
112:
113: #include <net80211/ieee80211_radiotap.h>
114: #include <net80211/ieee80211_var.h>
115:
116: #if NBPFILTER > 0
117: #include <net/bpf.h>
118: #endif
119:
120: #include <dev/ic/anreg.h>
121: #include <dev/ic/anvar.h>
122:
123: struct cfdriver an_cd = {
124: NULL, "an", DV_IFNET
125: };
126:
127: int an_reset(struct an_softc *);
128: void an_wait(struct an_softc *);
129: int an_init(struct ifnet *);
130: void an_stop(struct ifnet *, int);
131: void an_start(struct ifnet *);
132: void an_watchdog(struct ifnet *);
133: int an_ioctl(struct ifnet *, u_long, caddr_t);
134: int an_media_change(struct ifnet *);
135: void an_media_status(struct ifnet *, struct ifmediareq *);
136:
137: int an_set_nwkey(struct an_softc *, struct ieee80211_nwkey *);
138: int an_set_nwkey_wep(struct an_softc *, struct ieee80211_nwkey *);
139: int an_get_nwkey(struct an_softc *, struct ieee80211_nwkey *);
140: int an_write_wepkey(struct an_softc *, int, struct an_wepkey *,
141: int);
142:
143: void an_rxeof(struct an_softc *);
144: void an_txeof(struct an_softc *, u_int16_t);
145: void an_linkstat_intr(struct an_softc *);
146:
147: int an_cmd(struct an_softc *, int, int);
148: int an_seek_bap(struct an_softc *, int, int);
149: int an_read_bap(struct an_softc *, int, int, void *, int, int);
150: int an_write_bap(struct an_softc *, int, int, void *, int);
151: int an_mwrite_bap(struct an_softc *, int, int, struct mbuf *, int);
152: int an_read_rid(struct an_softc *, int, void *, int *);
153: int an_write_rid(struct an_softc *, int, void *, int);
154:
155: int an_alloc_nicmem(struct an_softc *, int, int *);
156:
157: int an_newstate(struct ieee80211com *, enum ieee80211_state, int);
158:
159: #ifdef AN_DEBUG
160: int an_debug = 0;
161:
162: #define DPRINTF(X) if (an_debug) printf X
163: #define DPRINTF2(X) if (an_debug > 1) printf X
164: #else
165: #define DPRINTF(X)
166: #define DPRINTF2(X)
167: #endif
168:
169: #if BYTE_ORDER == BIG_ENDIAN
170: static __inline void
171: an_swap16(u_int16_t *p, int cnt)
172: {
173: for (; cnt--; p++)
174: *p = swap16(*p);
175: }
176: #define an_switch32(val) (val >> 16 | (val & 0xFFFF) << 16)
177: #else
178: #define an_swap16(p, cnt)
179: #define an_switch32(val) val
180: #endif
181:
182: int
183: an_attach(struct an_softc *sc)
184: {
185: struct ieee80211com *ic = &sc->sc_ic;
186: struct ifnet *ifp = &ic->ic_if;
187: int i;
188: struct an_rid_wepkey *akey;
189: int buflen, kid, rid;
190: int chan, chan_min, chan_max;
191:
192: sc->sc_invalid = 0;
193:
194: /* disable interrupts */
195: CSR_WRITE_2(sc, AN_INT_EN, 0);
196: CSR_WRITE_2(sc, AN_EVENT_ACK, 0xffff);
197:
198: // an_wait(sc);
199: if (an_reset(sc) != 0) {
200: sc->sc_invalid = 1;
201: return 1;
202: }
203:
204: /* Load factory config */
205: if (an_cmd(sc, AN_CMD_READCFG, 0) != 0) {
206: printf("%s: failed to load config data\n",
207: sc->sc_dev.dv_xname);
208: return (EIO);
209: }
210:
211: /* Read the current configuration */
212: buflen = sizeof(sc->sc_config);
213: if (an_read_rid(sc, AN_RID_GENCONFIG, &sc->sc_config, &buflen) != 0) {
214: printf("%s: read config failed\n", sc->sc_dev.dv_xname);
215: return(EIO);
216: }
217:
218: an_swap16((u_int16_t *)&sc->sc_config.an_macaddr, 3);
219:
220: /* Read the card capabilities */
221: buflen = sizeof(sc->sc_caps);
222: if (an_read_rid(sc, AN_RID_CAPABILITIES, &sc->sc_caps, &buflen) != 0) {
223: printf("%s: read caps failed\n", sc->sc_dev.dv_xname);
224: return(EIO);
225: }
226:
227: an_swap16((u_int16_t *)&sc->sc_caps.an_oemaddr, 3);
228: an_swap16((u_int16_t *)&sc->sc_caps.an_rates, 4);
229:
230: /* Read WEP settings from persistent memory */
231: akey = &sc->sc_buf.sc_wepkey;
232: buflen = sizeof(struct an_rid_wepkey);
233: rid = AN_RID_WEP_VOLATILE; /* first persistent key */
234: while (an_read_rid(sc, rid, akey, &buflen) == 0) {
235: an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
236: an_swap16((u_int16_t *)&akey->an_key, 8);
237: kid = akey->an_key_index;
238: DPRINTF(("an_attach: wep rid=0x%x len=%d(%d) index=0x%04x "
239: "mac[0]=%02x keylen=%d\n",
240: rid, buflen, sizeof(*akey), kid,
241: akey->an_mac_addr[0], akey->an_key_len));
242: if (kid == 0xffff) {
243: sc->sc_tx_perskey = akey->an_mac_addr[0];
244: sc->sc_tx_key = -1;
245: break;
246: }
247: if (kid >= IEEE80211_WEP_NKID)
248: break;
249: sc->sc_perskeylen[kid] = akey->an_key_len;
250: sc->sc_wepkeys[kid].an_wep_keylen = -1;
251: rid = AN_RID_WEP_PERSISTENT; /* for next key */
252: buflen = sizeof(struct an_rid_wepkey);
253: }
254:
255: IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr);
256: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
257:
258: printf("%s: Firmware %x.%02x.%02x, Radio: ", ifp->if_xname,
259: sc->sc_caps.an_fwrev >> 8,
260: sc->sc_caps.an_fwrev & 0xff,
261: sc->sc_caps.an_fwsubrev);
262:
263: if (sc->sc_config.an_radiotype & AN_RADIOTYPE_80211_FH)
264: printf("802.11 FH");
265: else if (sc->sc_config.an_radiotype & AN_RADIOTYPE_80211_DS)
266: printf("802.11 DS");
267: else if (sc->sc_config.an_radiotype & AN_RADIOTYPE_LM2000_DS)
268: printf("LM2000 DS");
269: else
270: printf("unknown (%x)", sc->sc_config.an_radiotype);
271:
272: printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
273:
274: ifp->if_softc = sc;
275: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
276: ifp->if_ioctl = an_ioctl;
277: ifp->if_start = an_start;
278: ifp->if_init = an_init;
279: ifp->if_watchdog = an_watchdog;
280: IFQ_SET_READY(&ifp->if_snd);
281:
282: ic->ic_phytype = IEEE80211_T_DS;
283: ic->ic_opmode = IEEE80211_M_STA;
284: ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_PMGT | IEEE80211_C_IBSS |
285: IEEE80211_C_MONITOR;
286: ic->ic_state = IEEE80211_S_INIT;
287: IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr);
288:
289: switch (sc->sc_caps.an_regdomain) {
290: default:
291: case AN_REGDOMAIN_USA:
292: case AN_REGDOMAIN_CANADA:
293: chan_min = 1; chan_max = 11; break;
294: case AN_REGDOMAIN_EUROPE:
295: case AN_REGDOMAIN_AUSTRALIA:
296: chan_min = 1; chan_max = 13; break;
297: case AN_REGDOMAIN_JAPAN:
298: chan_min = 14; chan_max = 14; break;
299: case AN_REGDOMAIN_SPAIN:
300: chan_min = 10; chan_max = 11; break;
301: case AN_REGDOMAIN_FRANCE:
302: chan_min = 10; chan_max = 13; break;
303: case AN_REGDOMAIN_JAPANWIDE:
304: chan_min = 1; chan_max = 14; break;
305: }
306:
307: for (chan = chan_min; chan <= chan_max; chan++) {
308: ic->ic_channels[chan].ic_freq =
309: ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
310: ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_B;
311: }
312: ic->ic_ibss_chan = &ic->ic_channels[chan_min];
313:
314: /* Find supported rate */
315: for (i = 0; i < sizeof(sc->sc_caps.an_rates); i++) {
316: if (sc->sc_caps.an_rates[i] == 0)
317: continue;
318: ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
319: ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates++] =
320: sc->sc_caps.an_rates[i];
321: }
322:
323: /*
324: * Call MI attach routine.
325: */
326: if_attach(ifp);
327: ieee80211_ifattach(ifp);
328:
329: sc->sc_newstate = ic->ic_newstate;
330: ic->ic_newstate = an_newstate;
331:
332: ieee80211_media_init(ifp, an_media_change, an_media_status);
333:
334: #if NBPFILTER > 0
335: bzero(&sc->sc_rxtapu, sizeof(sc->sc_rxtapu));
336: sc->sc_rxtap.ar_ihdr.it_len = sizeof(sc->sc_rxtapu);
337: sc->sc_rxtap.ar_ihdr.it_present = AN_RX_RADIOTAP_PRESENT;
338:
339: bzero(&sc->sc_txtapu, sizeof(sc->sc_txtapu));
340: sc->sc_txtap.at_ihdr.it_len = sizeof(sc->sc_txtapu);
341: sc->sc_txtap.at_ihdr.it_present = AN_TX_RADIOTAP_PRESENT;
342:
343: bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
344: sizeof(struct ieee80211_frame) + 64);
345: #endif
346:
347: sc->sc_sdhook = shutdownhook_establish(an_shutdown, sc);
348:
349: sc->sc_attached = 1;
350:
351: return(0);
352: }
353:
354: void
355: an_rxeof(struct an_softc *sc)
356: {
357: struct ieee80211com *ic = &sc->sc_ic;
358: struct ifnet *ifp = &ic->ic_if;
359: struct ieee80211_frame *wh;
360: struct ieee80211_node *ni;
361: struct an_rxframe frmhdr;
362: struct mbuf *m;
363: u_int16_t status;
364: int fid, gaplen, len, off;
365: uint8_t *gap;
366:
367: fid = CSR_READ_2(sc, AN_RX_FID);
368:
369: /* First read in the frame header */
370: if (an_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr), sizeof(frmhdr)) != 0) {
371: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
372: ifp->if_ierrors++;
373: DPRINTF(("an_rxeof: read fid %x failed\n", fid));
374: return;
375: }
376: an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2);
377:
378: status = frmhdr.an_rx_status;
379: if ((status & AN_STAT_ERRSTAT) != 0 &&
380: ic->ic_opmode != IEEE80211_M_MONITOR) {
381: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
382: ifp->if_ierrors++;
383: DPRINTF(("an_rxeof: fid %x status %x\n", fid, status));
384: return;
385: }
386:
387: /* the payload length field includes a 16-bit "mystery field" */
388: len = frmhdr.an_rx_payload_len - sizeof(uint16_t);
389: off = ALIGN(sizeof(struct ieee80211_frame));
390:
391: if (off + len > MCLBYTES) {
392: if (ic->ic_opmode != IEEE80211_M_MONITOR) {
393: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
394: ifp->if_ierrors++;
395: DPRINTF(("an_rxeof: oversized packet %d\n", len));
396: return;
397: }
398: len = 0;
399: }
400:
401: MGETHDR(m, M_DONTWAIT, MT_DATA);
402: if (m == NULL) {
403: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
404: ifp->if_ierrors++;
405: DPRINTF(("an_rxeof: MGET failed\n"));
406: return;
407: }
408: if (off + len + AN_GAPLEN_MAX > MHLEN) {
409: MCLGET(m, M_DONTWAIT);
410: if ((m->m_flags & M_EXT) == 0) {
411: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
412: m_freem(m);
413: ifp->if_ierrors++;
414: DPRINTF(("an_rxeof: MCLGET failed\n"));
415: return;
416: }
417: }
418: m->m_data += off - sizeof(struct ieee80211_frame);
419:
420: if (ic->ic_opmode != IEEE80211_M_MONITOR) {
421: gaplen = frmhdr.an_gaplen;
422: if (gaplen > AN_GAPLEN_MAX) {
423: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
424: m_freem(m);
425: ifp->if_ierrors++;
426: DPRINTF(("%s: gap too long\n", __func__));
427: return;
428: }
429: /*
430: * We don't need the 16-bit mystery field (payload length?),
431: * so read it into the region reserved for the 802.11 header.
432: *
433: * When Cisco Aironet 350 cards w/ firmware version 5 or
434: * greater operate with certain Cisco 350 APs,
435: * the "gap" is filled with the SNAP header. Read
436: * it in after the 802.11 header.
437: */
438: gap = m->m_data + sizeof(struct ieee80211_frame) -
439: sizeof(uint16_t);
440: an_read_bap(sc, fid, -1, gap, gaplen + sizeof(u_int16_t),
441: gaplen + sizeof(u_int16_t));
442: } else
443: gaplen = 0;
444:
445: an_read_bap(sc, fid, -1,
446: m->m_data + sizeof(struct ieee80211_frame) + gaplen, len, len);
447: an_swap16((u_int16_t *)(m->m_data + sizeof(struct ieee80211_frame) + gaplen), (len+1)/2);
448: m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + gaplen +
449: len;
450:
451: memcpy(m->m_data, &frmhdr.an_whdr, sizeof(struct ieee80211_frame));
452: m->m_pkthdr.rcvif = ifp;
453: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
454:
455: #if NBPFILTER > 0
456: if (sc->sc_drvbpf) {
457: struct mbuf mb;
458: struct an_rx_radiotap_header *tap = &sc->sc_rxtap;
459:
460: tap->ar_rate = frmhdr.an_rx_rate;
461: tap->ar_antsignal = frmhdr.an_rx_signal_strength;
462: tap->ar_chan_freq = ic->ic_bss->ni_chan->ic_freq;
463: tap->ar_chan_flags = ic->ic_bss->ni_chan->ic_flags;
464:
465:
466: mb.m_data = (caddr_t)tap;
467: mb.m_len = sizeof(sc->sc_rxtapu);
468: mb.m_next = m;
469: mb.m_nextpkt = NULL;
470: mb.m_type = 0;
471: mb.m_flags = 0;
472: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
473: }
474: #endif /* NPBFILTER > 0 */
475:
476: wh = mtod(m, struct ieee80211_frame *);
477: if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
478: /*
479: * WEP is decrypted by hardware. Clear WEP bit
480: * header for ieee80211_input().
481: */
482: wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
483: }
484:
485: ni = ieee80211_find_rxnode(ic, wh);
486: ieee80211_input(ifp, m, ni, frmhdr.an_rx_signal_strength,
487: an_switch32(frmhdr.an_rx_time));
488: ieee80211_release_node(ic, ni);
489: }
490:
491: void
492: an_txeof(struct an_softc *sc, u_int16_t status)
493: {
494: struct ifnet *ifp = &sc->sc_ic.ic_if;
495: int cur, id;
496:
497: sc->sc_tx_timer = 0;
498: ifp->if_flags &= ~IFF_OACTIVE;
499:
500: id = CSR_READ_2(sc, AN_TX_CMP_FID);
501: CSR_WRITE_2(sc, AN_EVENT_ACK, status & (AN_EV_TX | AN_EV_TX_EXC));
502:
503: if (status & AN_EV_TX_EXC)
504: ifp->if_oerrors++;
505: else
506: ifp->if_opackets++;
507:
508: cur = sc->sc_txcur;
509: if (sc->sc_txd[cur].d_fid == id) {
510: sc->sc_txd[cur].d_inuse = 0;
511: DPRINTF2(("an_txeof: sent %x/%d\n", id, cur));
512: AN_INC(cur, AN_TX_RING_CNT);
513: sc->sc_txcur = cur;
514: } else {
515: for (cur = 0; cur < AN_TX_RING_CNT; cur++) {
516: if (id == sc->sc_txd[cur].d_fid) {
517: sc->sc_txd[cur].d_inuse = 0;
518: break;
519: }
520: }
521: if (ifp->if_flags & IFF_DEBUG)
522: printf("%s: tx mismatch: "
523: "expected %x(%d), actual %x(%d)\n",
524: sc->sc_dev.dv_xname,
525: sc->sc_txd[sc->sc_txcur].d_fid, sc->sc_txcur,
526: id, cur);
527: }
528: }
529:
530: int
531: an_intr(void *arg)
532: {
533: struct an_softc *sc = arg;
534: struct ifnet *ifp = &sc->sc_ic.ic_if;
535: int i;
536: u_int16_t status;
537:
538: if (!sc->sc_enabled || sc->sc_invalid ||
539: (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
540: (ifp->if_flags & IFF_RUNNING) == 0)
541: return 0;
542:
543: if ((ifp->if_flags & IFF_UP) == 0) {
544: CSR_WRITE_2(sc, AN_INT_EN, 0);
545: CSR_WRITE_2(sc, AN_EVENT_ACK, ~0);
546: return 1;
547: }
548:
549: /* maximum 10 loops per interrupt */
550: for (i = 0; i < 10; i++) {
551: if (!sc->sc_enabled || sc->sc_invalid)
552: return 1;
553: if (CSR_READ_2(sc, AN_SW0) != AN_MAGIC) {
554: DPRINTF(("an_intr: magic number changed: %x\n",
555: CSR_READ_2(sc, AN_SW0)));
556: sc->sc_invalid = 1;
557: return 1;
558: }
559: status = CSR_READ_2(sc, AN_EVENT_STAT);
560: CSR_WRITE_2(sc, AN_EVENT_ACK, status & ~(AN_INTRS));
561: if ((status & AN_INTRS) == 0)
562: break;
563:
564: if (status & AN_EV_RX)
565: an_rxeof(sc);
566:
567: if (status & (AN_EV_TX | AN_EV_TX_EXC))
568: an_txeof(sc, status);
569:
570: if (status & AN_EV_LINKSTAT)
571: an_linkstat_intr(sc);
572:
573: if ((ifp->if_flags & IFF_OACTIVE) == 0 &&
574: sc->sc_ic.ic_state == IEEE80211_S_RUN &&
575: !IFQ_IS_EMPTY(&ifp->if_snd))
576: an_start(ifp);
577: }
578:
579: return 1;
580: }
581:
582: /* Must be called at proper protection level! */
583: int
584: an_cmd(struct an_softc *sc, int cmd, int val)
585: {
586: int i, stat;
587:
588: /* make sure previous command completed */
589: if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
590: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
591: printf("%s: command 0x%x busy\n", sc->sc_dev.dv_xname,
592: CSR_READ_2(sc, AN_COMMAND));
593: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
594: }
595:
596: CSR_WRITE_2(sc, AN_PARAM0, val);
597: CSR_WRITE_2(sc, AN_PARAM1, 0);
598: CSR_WRITE_2(sc, AN_PARAM2, 0);
599: CSR_WRITE_2(sc, AN_COMMAND, cmd);
600:
601: if (cmd == AN_CMD_FW_RESTART) {
602: /* XXX: should sleep here */
603: DELAY(100*1000);
604: }
605:
606: for (i = 0; i < AN_TIMEOUT; i++) {
607: if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
608: break;
609: DELAY(10);
610: }
611:
612: stat = CSR_READ_2(sc, AN_STATUS);
613:
614: /* clear stuck command busy if necessary */
615: if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY)
616: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
617:
618: /* Ack the command */
619: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
620:
621: if (i == AN_TIMEOUT) {
622: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
623: printf("%s: command 0x%x param 0x%x timeout\n",
624: sc->sc_dev.dv_xname, cmd, val);
625: return ETIMEDOUT;
626: }
627: if (stat & AN_STAT_CMD_RESULT) {
628: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
629: printf("%s: command 0x%x param 0x%x status 0x%x "
630: "resp 0x%x 0x%x 0x%x\n",
631: sc->sc_dev.dv_xname, cmd, val, stat,
632: CSR_READ_2(sc, AN_RESP0), CSR_READ_2(sc, AN_RESP1),
633: CSR_READ_2(sc, AN_RESP2));
634: return EIO;
635: }
636:
637: return 0;
638: }
639:
640: int
641: an_reset(struct an_softc *sc)
642: {
643:
644: DPRINTF(("an_reset\n"));
645:
646: if (!sc->sc_enabled)
647: return ENXIO;
648:
649: an_cmd(sc, AN_CMD_ENABLE, 0);
650: an_cmd(sc, AN_CMD_FW_RESTART, 0);
651: an_cmd(sc, AN_CMD_NOOP2, 0);
652:
653: if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) {
654: printf("%s: reset failed\n", sc->sc_dev.dv_xname);
655: return ETIMEDOUT;
656: }
657:
658: an_cmd(sc, AN_CMD_DISABLE, 0);
659: return 0;
660: }
661:
662: void
663: an_linkstat_intr(struct an_softc *sc)
664: {
665: struct ieee80211com *ic = &sc->sc_ic;
666: u_int16_t status;
667:
668: status = CSR_READ_2(sc, AN_LINKSTAT);
669: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT);
670: DPRINTF(("an_linkstat_intr: status 0x%x\n", status));
671:
672: if (status == AN_LINKSTAT_ASSOCIATED) {
673: if (ic->ic_state != IEEE80211_S_RUN ||
674: ic->ic_opmode == IEEE80211_M_IBSS)
675: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
676: } else {
677: if (ic->ic_opmode == IEEE80211_M_STA)
678: ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
679: }
680: }
681:
682: /*
683: * Wait for firmware come up after power enabled.
684: */
685: void
686: an_wait(struct an_softc *sc)
687: {
688: int i;
689:
690: CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_NOOP2);
691: for (i = 0; i < 3*hz; i++) {
692: if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
693: break;
694: (void)tsleep(sc, PWAIT, "anatch", 1);
695: }
696: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
697: }
698:
699: int
700: an_read_bap(struct an_softc *sc, int id, int off, void *buf, int len, int blen)
701: {
702: int error, cnt, cnt2;
703:
704: if (len == 0 || blen == 0)
705: return 0;
706: if (off == -1)
707: off = sc->sc_bap_off;
708: if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
709: if ((error = an_seek_bap(sc, id, off)) != 0)
710: return EIO;
711: }
712:
713: cnt = (blen + 1) / 2;
714: CSR_READ_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt);
715: for (cnt2 = (len + 1) / 2; cnt < cnt2; cnt++)
716: (void) CSR_READ_2(sc, AN_DATA0);
717: sc->sc_bap_off += cnt * 2;
718:
719: return 0;
720: }
721:
722: int
723: an_write_bap(struct an_softc *sc, int id, int off, void *buf, int buflen)
724: {
725: int error, cnt;
726:
727: if (buflen == 0)
728: return 0;
729: if (off == -1)
730: off = sc->sc_bap_off;
731: if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
732: if ((error = an_seek_bap(sc, id, off)) != 0)
733: return EIO;
734: }
735:
736: cnt = (buflen + 1) / 2;
737: CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt);
738: sc->sc_bap_off += cnt * 2;
739: return 0;
740: }
741:
742: int
743: an_seek_bap(struct an_softc *sc, int id, int off)
744: {
745: int i, status;
746:
747: CSR_WRITE_2(sc, AN_SEL0, id);
748: CSR_WRITE_2(sc, AN_OFF0, off);
749:
750: for (i = 0; ; i++) {
751: status = CSR_READ_2(sc, AN_OFF0);
752: if ((status & AN_OFF_BUSY) == 0)
753: break;
754: if (i == AN_TIMEOUT) {
755: printf("%s: timeout in an_seek_bap to 0x%x/0x%x\n",
756: sc->sc_dev.dv_xname, id, off);
757: sc->sc_bap_off = AN_OFF_ERR; /* invalidate */
758: return ETIMEDOUT;
759: }
760: DELAY(10);
761: }
762: if (status & AN_OFF_ERR) {
763: printf("%s: failed in an_seek_bap to 0x%x/0x%x\n",
764: sc->sc_dev.dv_xname, id, off);
765: sc->sc_bap_off = AN_OFF_ERR; /* invalidate */
766: return EIO;
767: }
768: sc->sc_bap_id = id;
769: sc->sc_bap_off = off;
770: return 0;
771: }
772:
773: int
774: an_mwrite_bap(struct an_softc *sc, int id, int off, struct mbuf *m, int totlen)
775: {
776: int error, len, cnt;
777:
778: if (off == -1)
779: off = sc->sc_bap_off;
780: if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
781: if ((error = an_seek_bap(sc, id, off)) != 0)
782: return EIO;
783: }
784:
785: for (len = 0; m != NULL; m = m->m_next) {
786: if (m->m_len == 0)
787: continue;
788: len = min(m->m_len, totlen);
789:
790: if ((mtod(m, u_long) & 0x1) || (len & 0x1)) {
791: m_copydata(m, 0, totlen, (caddr_t)&sc->sc_buf.sc_txbuf);
792: cnt = (totlen + 1) / 2;
793: an_swap16((u_int16_t *)&sc->sc_buf.sc_txbuf, cnt);
794: CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0,
795: sc->sc_buf.sc_val, cnt);
796: off += cnt * 2;
797: break;
798: }
799: cnt = len / 2;
800: an_swap16((u_int16_t *)mtod(m, u_int16_t *), cnt);
801: CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, mtod(m, u_int16_t *),
802: cnt);
803: off += len;
804: totlen -= len;
805: }
806: sc->sc_bap_off = off;
807: return 0;
808: }
809:
810: int
811: an_alloc_nicmem(struct an_softc *sc, int len, int *idp)
812: {
813: int i;
814:
815: if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
816: printf("%s: failed to allocate %d bytes on NIC\n",
817: sc->sc_dev.dv_xname, len);
818: return(ENOMEM);
819: }
820:
821: for (i = 0; i < AN_TIMEOUT; i++) {
822: if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
823: break;
824: if (i == AN_TIMEOUT) {
825: printf("%s: timeout in alloc\n", sc->sc_dev.dv_xname);
826: return ETIMEDOUT;
827: }
828: DELAY(10);
829: }
830:
831: *idp = CSR_READ_2(sc, AN_ALLOC_FID);
832: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
833: return 0;
834: }
835:
836: int
837: an_read_rid(struct an_softc *sc, int rid, void *buf, int *buflenp)
838: {
839: int error;
840: u_int16_t len;
841:
842: /* Tell the NIC to enter record read mode. */
843: error = an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_READ, rid);
844: if (error)
845: return error;
846:
847: /* length in byte, including length itself */
848: error = an_read_bap(sc, rid, 0, &len, sizeof(len), sizeof(len));
849: if (error)
850: return error;
851:
852: len -= 2;
853: return an_read_bap(sc, rid, sizeof(len), buf, len, *buflenp);
854: }
855:
856: int
857: an_write_rid(struct an_softc *sc, int rid, void *buf, int buflen)
858: {
859: int error;
860: u_int16_t len;
861:
862: /* length in byte, including length itself */
863: len = buflen + 2;
864:
865: error = an_write_bap(sc, rid, 0, &len, sizeof(len));
866: if (error)
867: return error;
868: error = an_write_bap(sc, rid, sizeof(len), buf, buflen);
869: if (error)
870: return error;
871:
872: return an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_WRITE, rid);
873: }
874:
875: int
876: an_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
877: {
878: struct an_softc *sc = ifp->if_softc;
879: struct ifaddr *ifa = (struct ifaddr *)data;
880: int s, error = 0;
881:
882: if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
883: return ENXIO;
884:
885: s = splnet();
886:
887: switch(command) {
888: case SIOCSIFADDR:
889: ifp->if_flags |= IFF_UP;
890: switch (ifa->ifa_addr->sa_family) {
891: #ifdef INET
892: case AF_INET:
893: error = an_init(ifp);
894: arp_ifinit(&sc->sc_ic.ic_ac, ifa);
895: break;
896: #endif
897: default:
898: error = an_init(ifp);
899: break;
900: }
901: break;
902: case SIOCSIFFLAGS:
903: if (ifp->if_flags & IFF_UP) {
904: if (sc->sc_enabled) {
905: /*
906: * To avoid rescanning another access point,
907: * do not call an_init() here. Instead, only
908: * reflect promisc mode settings.
909: */
910: error = an_cmd(sc, AN_CMD_SET_MODE,
911: (ifp->if_flags & IFF_PROMISC) ? 0xffff : 0);
912: } else
913: error = an_init(ifp);
914: } else if (sc->sc_enabled)
915: an_stop(ifp, 1);
916: break;
917: case SIOCADDMULTI:
918: case SIOCDELMULTI:
919: /* The Aironet has no multicast filter. */
920: error = 0;
921: break;
922: case SIOCS80211NWKEY:
923: error = an_set_nwkey(sc, (struct ieee80211_nwkey *)data);
924: break;
925: case SIOCG80211NWKEY:
926: error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data);
927: break;
928: default:
929: error = ieee80211_ioctl(ifp, command, data);
930: break;
931: }
932: if (error == ENETRESET) {
933: if (sc->sc_enabled)
934: error = an_init(ifp);
935: else
936: error = 0;
937: }
938: splx(s);
939: return(error);
940: }
941:
942: int
943: an_init(struct ifnet *ifp)
944: {
945: struct an_softc *sc = ifp->if_softc;
946: struct ieee80211com *ic = &sc->sc_ic;
947: int i, error, fid;
948:
949: DPRINTF(("an_init: enabled %d\n", sc->sc_enabled));
950: if (!sc->sc_enabled) {
951: if (sc->sc_enable)
952: (*sc->sc_enable)(sc);
953: an_wait(sc);
954: sc->sc_enabled = 1;
955: } else {
956: an_stop(ifp, 0);
957: if ((error = an_reset(sc)) != 0) {
958: printf("%s: failed to reset\n", ifp->if_xname);
959: an_stop(ifp, 1);
960: return error;
961: }
962: }
963: CSR_WRITE_2(sc, AN_SW0, AN_MAGIC);
964:
965: /* Allocate the TX buffers */
966: for (i = 0; i < AN_TX_RING_CNT; i++) {
967: if ((error = an_alloc_nicmem(sc, AN_TX_MAX_LEN, &fid)) != 0) {
968: printf("%s: failed to allocate nic memory\n",
969: ifp->if_xname);
970: an_stop(ifp, 1);
971: return error;
972: }
973: DPRINTF2(("an_init: txbuf %d allocated %x\n", i, fid));
974: sc->sc_txd[i].d_fid = fid;
975: sc->sc_txd[i].d_inuse = 0;
976: }
977: sc->sc_txcur = sc->sc_txnext = 0;
978:
979: IEEE80211_ADDR_COPY(sc->sc_config.an_macaddr, ic->ic_myaddr);
980: an_swap16((u_int16_t *)&sc->sc_config.an_macaddr, 3);
981: sc->sc_config.an_scanmode = AN_SCANMODE_ACTIVE;
982: sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN; /*XXX*/
983: if (ic->ic_flags & IEEE80211_F_WEPON) {
984: sc->sc_config.an_authtype |=
985: AN_AUTHTYPE_PRIVACY_IN_USE;
986: }
987: sc->sc_config.an_listen_interval = ic->ic_lintval;
988: sc->sc_config.an_beacon_period = ic->ic_lintval;
989: if (ic->ic_flags & IEEE80211_F_PMGTON)
990: sc->sc_config.an_psave_mode = AN_PSAVE_PSP;
991: else
992: sc->sc_config.an_psave_mode = AN_PSAVE_CAM;
993: sc->sc_config.an_ds_channel =
994: ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
995:
996: switch (ic->ic_opmode) {
997: case IEEE80211_M_STA:
998: sc->sc_config.an_opmode =
999: AN_OPMODE_INFRASTRUCTURE_STATION;
1000: sc->sc_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
1001: break;
1002: case IEEE80211_M_IBSS:
1003: sc->sc_config.an_opmode = AN_OPMODE_IBSS_ADHOC;
1004: sc->sc_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
1005: break;
1006: case IEEE80211_M_MONITOR:
1007: sc->sc_config.an_opmode =
1008: AN_OPMODE_INFRASTRUCTURE_STATION;
1009: sc->sc_config.an_rxmode =
1010: AN_RXMODE_80211_MONITOR_ANYBSS;
1011: sc->sc_config.an_authtype = AN_AUTHTYPE_NONE;
1012: if (ic->ic_flags & IEEE80211_F_WEPON)
1013: sc->sc_config.an_authtype |=
1014: AN_AUTHTYPE_PRIVACY_IN_USE |
1015: AN_AUTHTYPE_ALLOW_UNENCRYPTED;
1016: break;
1017: default:
1018: printf("%s: bad opmode %d\n", ifp->if_xname, ic->ic_opmode);
1019: an_stop(ifp, 1);
1020: return EIO;
1021: }
1022: sc->sc_config.an_rxmode |= AN_RXMODE_NO_8023_HEADER;
1023:
1024: /* Set the ssid list */
1025: memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_ssidlist));
1026: sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid_len =
1027: ic->ic_des_esslen;
1028: if (ic->ic_des_esslen)
1029: memcpy(sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid,
1030: ic->ic_des_essid, ic->ic_des_esslen);
1031: an_swap16((u_int16_t *)&sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid, 16);
1032: if (an_write_rid(sc, AN_RID_SSIDLIST, &sc->sc_buf,
1033: sizeof(sc->sc_buf.sc_ssidlist)) != 0) {
1034: printf("%s: failed to write ssid list\n", ifp->if_xname);
1035: an_stop(ifp, 1);
1036: return error;
1037: }
1038:
1039: /* Set the AP list */
1040: memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_aplist));
1041: (void)an_write_rid(sc, AN_RID_APLIST, &sc->sc_buf,
1042: sizeof(sc->sc_buf.sc_aplist));
1043:
1044: /* Set the encapsulation */
1045: for (i = 0; i < AN_ENCAP_NENTS; i++) {
1046: sc->sc_buf.sc_encap.an_entry[i].an_ethertype = 0;
1047: sc->sc_buf.sc_encap.an_entry[i].an_action =
1048: AN_RXENCAP_RFC1024 | AN_TXENCAP_RFC1024;
1049: }
1050: (void)an_write_rid(sc, AN_RID_ENCAP, &sc->sc_buf,
1051: sizeof(sc->sc_buf.sc_encap));
1052:
1053: /* Set the WEP Keys */
1054: if (ic->ic_flags & IEEE80211_F_WEPON)
1055: an_write_wepkey(sc, AN_RID_WEP_VOLATILE, sc->sc_wepkeys,
1056: sc->sc_tx_key);
1057:
1058: /* Set the configuration */
1059: if (an_write_rid(sc, AN_RID_GENCONFIG, &sc->sc_config,
1060: sizeof(sc->sc_config)) != 0) {
1061: printf("%s: failed to write config\n", ifp->if_xname);
1062: an_stop(ifp, 1);
1063: return error;
1064: }
1065:
1066: /* Enable the MAC */
1067: if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
1068: printf("%s: failed to enable MAC\n", sc->sc_dev.dv_xname);
1069: an_stop(ifp, 1);
1070: return ENXIO;
1071: }
1072: if (ifp->if_flags & IFF_PROMISC)
1073: an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
1074:
1075: ifp->if_flags |= IFF_RUNNING;
1076: ifp->if_flags &= ~IFF_OACTIVE;
1077: ic->ic_state = IEEE80211_S_INIT;
1078: if (ic->ic_opmode == IEEE80211_M_MONITOR)
1079: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
1080:
1081: /* enable interrupts */
1082: CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
1083: return 0;
1084: }
1085:
1086: void
1087: an_start(struct ifnet *ifp)
1088: {
1089: struct an_softc *sc = (struct an_softc *)ifp->if_softc;
1090: struct ieee80211com *ic = &sc->sc_ic;
1091: struct ieee80211_node *ni;
1092: struct ieee80211_frame *wh;
1093: struct an_txframe frmhdr;
1094: struct mbuf *m;
1095: u_int16_t len;
1096: int cur, fid;
1097:
1098: if (!sc->sc_enabled || sc->sc_invalid) {
1099: DPRINTF(("an_start: noop: enabled %d invalid %d\n",
1100: sc->sc_enabled, sc->sc_invalid));
1101: return;
1102: }
1103:
1104: memset(&frmhdr, 0, sizeof(frmhdr));
1105: cur = sc->sc_txnext;
1106: for (;;) {
1107: if (ic->ic_state != IEEE80211_S_RUN) {
1108: DPRINTF(("an_start: not running %d\n", ic->ic_state));
1109: break;
1110: }
1111: IFQ_POLL(&ifp->if_snd, m);
1112: if (m == NULL) {
1113: DPRINTF2(("an_start: no pending mbuf\n"));
1114: break;
1115: }
1116: if (sc->sc_txd[cur].d_inuse) {
1117: DPRINTF2(("an_start: %x/%d busy\n",
1118: sc->sc_txd[cur].d_fid, cur));
1119: ifp->if_flags |= IFF_OACTIVE;
1120: break;
1121: }
1122: IFQ_DEQUEUE(&ifp->if_snd, m);
1123: ifp->if_opackets++;
1124: #if NBPFILTER > 0
1125: if (ifp->if_bpf)
1126: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
1127: #endif
1128: if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) {
1129: ifp->if_oerrors++;
1130: continue;
1131: }
1132: if (ni != NULL)
1133: ieee80211_release_node(ic, ni);
1134: #if NBPFILTER > 0
1135: if (ic->ic_rawbpf)
1136: bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
1137: #endif
1138:
1139: wh = mtod(m, struct ieee80211_frame *);
1140: if (ic->ic_flags & IEEE80211_F_WEPON)
1141: wh->i_fc[1] |= IEEE80211_FC1_WEP;
1142: m_copydata(m, 0, sizeof(struct ieee80211_frame),
1143: (caddr_t)&frmhdr.an_whdr);
1144: an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2);
1145:
1146: /* insert payload length in front of llc/snap */
1147: len = htons(m->m_pkthdr.len - sizeof(struct ieee80211_frame));
1148: m_adj(m, sizeof(struct ieee80211_frame) - sizeof(len));
1149: if (mtod(m, u_long) & 0x01)
1150: memcpy(mtod(m, caddr_t), &len, sizeof(len));
1151: else
1152: *mtod(m, u_int16_t *) = len;
1153:
1154: /*
1155: * XXX Aironet firmware apparently convert the packet
1156: * with longer than 1500 bytes in length into LLC/SNAP.
1157: * If we have 1500 bytes in ethernet payload, it is
1158: * 1508 bytes including LLC/SNAP and will be inserted
1159: * additional LLC/SNAP header with 1501-1508 in its
1160: * ethertype !!
1161: * So we skip LLC/SNAP header and force firmware to
1162: * convert it to LLC/SNAP again.
1163: */
1164: m_adj(m, sizeof(struct llc));
1165:
1166: frmhdr.an_tx_ctl = AN_TXCTL_80211;
1167: frmhdr.an_tx_payload_len = m->m_pkthdr.len;
1168: frmhdr.an_gaplen = AN_TXGAP_802_11;
1169:
1170: if (ic->ic_fixed_rate != -1)
1171: frmhdr.an_tx_rate =
1172: ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
1173: ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
1174: else
1175: frmhdr.an_tx_rate = 0;
1176:
1177: if (sizeof(frmhdr) + AN_TXGAP_802_11 + sizeof(len) +
1178: m->m_pkthdr.len > AN_TX_MAX_LEN) {
1179: ifp->if_oerrors++;
1180: m_freem(m);
1181: continue;
1182: }
1183:
1184: #if NBPFILTER > 0
1185: if (sc->sc_drvbpf) {
1186: struct mbuf mb;
1187: struct an_tx_radiotap_header *tap = &sc->sc_txtap;
1188:
1189: tap->at_rate =
1190: ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate];
1191: tap->at_chan_freq =
1192: ic->ic_bss->ni_chan->ic_freq;
1193: tap->at_chan_flags =
1194: ic->ic_bss->ni_chan->ic_flags;
1195:
1196: mb.m_data = (caddr_t)tap;
1197: mb.m_len = sizeof(sc->sc_txtapu);
1198: mb.m_next = m;
1199: mb.m_nextpkt = NULL;
1200: mb.m_type = 0;
1201: mb.m_flags = 0;
1202: bpf_mtap(sc->sc_drvbpf, m, BPF_DIRECTION_OUT);
1203: }
1204: #endif
1205:
1206: fid = sc->sc_txd[cur].d_fid;
1207: if (an_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) {
1208: ifp->if_oerrors++;
1209: m_freem(m);
1210: continue;
1211: }
1212: /* dummy write to avoid seek. */
1213: an_write_bap(sc, fid, -1, &frmhdr, AN_TXGAP_802_11);
1214: an_mwrite_bap(sc, fid, -1, m, m->m_pkthdr.len);
1215: m_freem(m);
1216:
1217: DPRINTF2(("an_start: send %d byte via %x/%d\n",
1218: ntohs(len) + sizeof(struct ieee80211_frame),
1219: fid, cur));
1220: sc->sc_txd[cur].d_inuse = 1;
1221: if (an_cmd(sc, AN_CMD_TX, fid)) {
1222: printf("%s: xmit failed\n", ifp->if_xname);
1223: sc->sc_txd[cur].d_inuse = 0;
1224: continue;
1225: }
1226: sc->sc_tx_timer = 5;
1227: ifp->if_timer = 1;
1228: AN_INC(cur, AN_TX_RING_CNT);
1229: sc->sc_txnext = cur;
1230: }
1231: }
1232:
1233: void
1234: an_stop(struct ifnet *ifp, int disable)
1235: {
1236: struct an_softc *sc = ifp->if_softc;
1237: int i, s;
1238:
1239: if (!sc->sc_enabled)
1240: return;
1241:
1242: DPRINTF(("an_stop: disable %d\n", disable));
1243:
1244: s = splnet();
1245: ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
1246: if (!sc->sc_invalid) {
1247: an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
1248: CSR_WRITE_2(sc, AN_INT_EN, 0);
1249: an_cmd(sc, AN_CMD_DISABLE, 0);
1250:
1251: for (i = 0; i < AN_TX_RING_CNT; i++)
1252: an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->sc_txd[i].d_fid);
1253: }
1254:
1255: sc->sc_tx_timer = 0;
1256: ifp->if_timer = 0;
1257: ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
1258:
1259: if (disable) {
1260: if (sc->sc_disable)
1261: (*sc->sc_disable)(sc);
1262: sc->sc_enabled = 0;
1263: }
1264: splx(s);
1265: }
1266:
1267: void
1268: an_watchdog(struct ifnet *ifp)
1269: {
1270: struct an_softc *sc = ifp->if_softc;
1271:
1272: if (!sc->sc_enabled)
1273: return;
1274:
1275: if (sc->sc_tx_timer) {
1276: if (--sc->sc_tx_timer == 0) {
1277: printf("%s: device timeout\n", ifp->if_xname);
1278: ifp->if_oerrors++;
1279: an_init(ifp);
1280: return;
1281: }
1282: ifp->if_timer = 1;
1283: }
1284: ieee80211_watchdog(ifp);
1285: }
1286:
1287: void
1288: an_shutdown(void *self)
1289: {
1290: struct an_softc *sc = (struct an_softc *)self;
1291:
1292: if (sc->sc_attached)
1293: an_stop(&sc->sc_ic.ic_if, 1);
1294: }
1295:
1296: /* TBD factor with ieee80211_media_change */
1297: int
1298: an_media_change(struct ifnet *ifp)
1299: {
1300: struct an_softc *sc = ifp->if_softc;
1301: struct ieee80211com *ic = &sc->sc_ic;
1302: struct ifmedia_entry *ime;
1303: enum ieee80211_opmode newmode;
1304: int i, rate, error = 0;
1305:
1306: ime = ic->ic_media.ifm_cur;
1307: if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
1308: i = -1;
1309: } else {
1310: struct ieee80211_rateset *rs =
1311: &ic->ic_sup_rates[IEEE80211_MODE_11B];
1312: rate = ieee80211_media2rate(ime->ifm_media);
1313: if (rate == 0)
1314: return EINVAL;
1315: for (i = 0; i < rs->rs_nrates; i++) {
1316: if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate)
1317: break;
1318: }
1319: if (i == rs->rs_nrates)
1320: return EINVAL;
1321: }
1322: if (ic->ic_fixed_rate != i) {
1323: ic->ic_fixed_rate = i;
1324: error = ENETRESET;
1325: }
1326:
1327: if (ime->ifm_media & IFM_IEEE80211_ADHOC)
1328: newmode = IEEE80211_M_IBSS;
1329: else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
1330: newmode = IEEE80211_M_HOSTAP;
1331: else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
1332: newmode = IEEE80211_M_MONITOR;
1333: else
1334: newmode = IEEE80211_M_STA;
1335: if (ic->ic_opmode != newmode) {
1336: ic->ic_opmode = newmode;
1337: error = ENETRESET;
1338: }
1339: if (error == ENETRESET) {
1340: if (sc->sc_enabled)
1341: error = an_init(ifp);
1342: else
1343: error = 0;
1344: }
1345: ifp->if_baudrate = ifmedia_baudrate(ic->ic_media.ifm_cur->ifm_media);
1346:
1347: return error;
1348: }
1349:
1350: void
1351: an_media_status(struct ifnet *ifp, struct ifmediareq *imr)
1352: {
1353: struct an_softc *sc = ifp->if_softc;
1354: struct ieee80211com *ic = &sc->sc_ic;
1355: int rate, buflen;
1356:
1357: if (sc->sc_enabled == 0) {
1358: imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
1359: imr->ifm_status = 0;
1360: return;
1361: }
1362:
1363: imr->ifm_status = IFM_AVALID;
1364: imr->ifm_active = IFM_IEEE80211;
1365: if (ic->ic_state == IEEE80211_S_RUN)
1366: imr->ifm_status |= IFM_ACTIVE;
1367: buflen = sizeof(sc->sc_buf);
1368: if (ic->ic_fixed_rate != -1)
1369: rate = ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
1370: ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
1371: else if (an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen) != 0)
1372: rate = 0;
1373: else
1374: rate = sc->sc_buf.sc_status.an_current_tx_rate;
1375: imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B);
1376: switch (ic->ic_opmode) {
1377: case IEEE80211_M_STA:
1378: break;
1379: case IEEE80211_M_IBSS:
1380: imr->ifm_active |= IFM_IEEE80211_ADHOC;
1381: break;
1382: case IEEE80211_M_HOSTAP:
1383: imr->ifm_active |= IFM_IEEE80211_HOSTAP;
1384: break;
1385: case IEEE80211_M_MONITOR:
1386: imr->ifm_active |= IFM_IEEE80211_MONITOR;
1387: break;
1388: default:
1389: break;
1390: }
1391: }
1392:
1393: int
1394: an_set_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
1395: {
1396: int error;
1397: struct ieee80211com *ic = &sc->sc_ic;
1398: u_int16_t prevauth;
1399:
1400: error = 0;
1401: prevauth = sc->sc_config.an_authtype;
1402:
1403: switch (nwkey->i_wepon) {
1404: case IEEE80211_NWKEY_OPEN:
1405: sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN;
1406: ic->ic_flags &= ~IEEE80211_F_WEPON;
1407: break;
1408:
1409: case IEEE80211_NWKEY_WEP:
1410: case IEEE80211_NWKEY_WEP | IEEE80211_NWKEY_PERSIST:
1411: error = an_set_nwkey_wep(sc, nwkey);
1412: if (error == 0 || error == ENETRESET) {
1413: sc->sc_config.an_authtype =
1414: AN_AUTHTYPE_OPEN | AN_AUTHTYPE_PRIVACY_IN_USE;
1415: ic->ic_flags |= IEEE80211_F_WEPON;
1416: }
1417: break;
1418:
1419: default:
1420: error = EINVAL;
1421: break;
1422: }
1423: if (error == 0 && prevauth != sc->sc_config.an_authtype)
1424: error = ENETRESET;
1425: return error;
1426: }
1427:
1428: int
1429: an_set_nwkey_wep(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
1430: {
1431: int i, txkey, anysetkey, needreset, error;
1432: struct an_wepkey keys[IEEE80211_WEP_NKID];
1433:
1434: error = 0;
1435: memset(keys, 0, sizeof(keys));
1436: anysetkey = needreset = 0;
1437:
1438: /* load argument and sanity check */
1439: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1440: keys[i].an_wep_keylen = nwkey->i_key[i].i_keylen;
1441: if (keys[i].an_wep_keylen < 0)
1442: continue;
1443: if (keys[i].an_wep_keylen != 0 &&
1444: keys[i].an_wep_keylen < IEEE80211_WEP_KEYLEN)
1445: return EINVAL;
1446: if (keys[i].an_wep_keylen > sizeof(keys[i].an_wep_key))
1447: return EINVAL;
1448: if ((error = copyin(nwkey->i_key[i].i_keydat,
1449: keys[i].an_wep_key, keys[i].an_wep_keylen)) != 0)
1450: return error;
1451: anysetkey++;
1452: }
1453: txkey = nwkey->i_defkid - 1;
1454: if (txkey >= 0) {
1455: if (txkey >= IEEE80211_WEP_NKID)
1456: return EINVAL;
1457: /* default key must have a valid value */
1458: if (keys[txkey].an_wep_keylen == 0 ||
1459: (keys[txkey].an_wep_keylen < 0 &&
1460: sc->sc_perskeylen[txkey] == 0))
1461: return EINVAL;
1462: anysetkey++;
1463: }
1464: DPRINTF(("an_set_nwkey_wep: %s: %sold(%d:%d,%d,%d,%d) "
1465: "pers(%d:%d,%d,%d,%d) new(%d:%d,%d,%d,%d)\n",
1466: sc->sc_dev.dv_xname,
1467: ((nwkey->i_wepon & IEEE80211_NWKEY_PERSIST) ? "persist: " : ""),
1468: sc->sc_tx_key,
1469: sc->sc_wepkeys[0].an_wep_keylen, sc->sc_wepkeys[1].an_wep_keylen,
1470: sc->sc_wepkeys[2].an_wep_keylen, sc->sc_wepkeys[3].an_wep_keylen,
1471: sc->sc_tx_perskey,
1472: sc->sc_perskeylen[0], sc->sc_perskeylen[1],
1473: sc->sc_perskeylen[2], sc->sc_perskeylen[3],
1474: txkey,
1475: keys[0].an_wep_keylen, keys[1].an_wep_keylen,
1476: keys[2].an_wep_keylen, keys[3].an_wep_keylen));
1477: if (!(nwkey->i_wepon & IEEE80211_NWKEY_PERSIST)) {
1478: /* set temporary keys */
1479: sc->sc_tx_key = txkey;
1480: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1481: if (keys[i].an_wep_keylen < 0)
1482: continue;
1483: memcpy(&sc->sc_wepkeys[i], &keys[i], sizeof(keys[i]));
1484: }
1485: } else {
1486: /* set persist keys */
1487: if (anysetkey) {
1488: /* prepare to write nvram */
1489: if (!sc->sc_enabled) {
1490: if (sc->sc_enable)
1491: (*sc->sc_enable)(sc);
1492: an_wait(sc);
1493: sc->sc_enabled = 1;
1494: error = an_write_wepkey(sc,
1495: AN_RID_WEP_PERSISTENT, keys, txkey);
1496: if (sc->sc_disable)
1497: (*sc->sc_disable)(sc);
1498: sc->sc_enabled = 0;
1499: } else {
1500: an_cmd(sc, AN_CMD_DISABLE, 0);
1501: error = an_write_wepkey(sc,
1502: AN_RID_WEP_PERSISTENT, keys, txkey);
1503: an_cmd(sc, AN_CMD_ENABLE, 0);
1504: }
1505: if (error)
1506: return error;
1507: }
1508: if (txkey >= 0)
1509: sc->sc_tx_perskey = txkey;
1510: if (sc->sc_tx_key >= 0) {
1511: sc->sc_tx_key = -1;
1512: needreset++;
1513: }
1514: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1515: if (sc->sc_wepkeys[i].an_wep_keylen >= 0) {
1516: memset(&sc->sc_wepkeys[i].an_wep_key, 0,
1517: sizeof(sc->sc_wepkeys[i].an_wep_key));
1518: sc->sc_wepkeys[i].an_wep_keylen = -1;
1519: needreset++;
1520: }
1521: if (keys[i].an_wep_keylen >= 0)
1522: sc->sc_perskeylen[i] = keys[i].an_wep_keylen;
1523: }
1524: }
1525: if (needreset) {
1526: /* firmware restart to reload persistent key */
1527: an_reset(sc);
1528: }
1529: if (anysetkey || needreset)
1530: error = ENETRESET;
1531: return error;
1532: }
1533:
1534: int
1535: an_get_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
1536: {
1537: int i, error;
1538:
1539: error = 0;
1540: if (sc->sc_config.an_authtype & AN_AUTHTYPE_LEAP)
1541: nwkey->i_wepon = IEEE80211_NWKEY_EAP;
1542: else if (sc->sc_config.an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE)
1543: nwkey->i_wepon = IEEE80211_NWKEY_WEP;
1544: else
1545: nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
1546: if (sc->sc_tx_key == -1)
1547: nwkey->i_defkid = sc->sc_tx_perskey + 1;
1548: else
1549: nwkey->i_defkid = sc->sc_tx_key + 1;
1550: if (nwkey->i_key[0].i_keydat == NULL)
1551: return 0;
1552: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1553: if (nwkey->i_key[i].i_keydat == NULL)
1554: continue;
1555: /* do not show any keys to non-root user */
1556: if ((error = suser(curproc, 0)) != 0)
1557: break;
1558: nwkey->i_key[i].i_keylen = sc->sc_wepkeys[i].an_wep_keylen;
1559: if (nwkey->i_key[i].i_keylen < 0) {
1560: if (sc->sc_perskeylen[i] == 0)
1561: nwkey->i_key[i].i_keylen = 0;
1562: continue;
1563: }
1564: if ((error = copyout(sc->sc_wepkeys[i].an_wep_key,
1565: nwkey->i_key[i].i_keydat,
1566: sc->sc_wepkeys[i].an_wep_keylen)) != 0)
1567: break;
1568: }
1569: return error;
1570: }
1571:
1572: int
1573: an_write_wepkey(struct an_softc *sc, int type, struct an_wepkey *keys, int kid)
1574: {
1575: int i, error;
1576: struct an_rid_wepkey *akey;
1577:
1578: error = 0;
1579: akey = &sc->sc_buf.sc_wepkey;
1580: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1581: memset(akey, 0, sizeof(struct an_rid_wepkey));
1582: if (keys[i].an_wep_keylen < 0 ||
1583: keys[i].an_wep_keylen > sizeof(akey->an_key))
1584: continue;
1585: akey->an_key_len = keys[i].an_wep_keylen;
1586: akey->an_key_index = i;
1587: akey->an_mac_addr[0] = 1; /* default mac */
1588: an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
1589: memcpy(akey->an_key, keys[i].an_wep_key, keys[i].an_wep_keylen);
1590: an_swap16((u_int16_t *)&akey->an_key, 8);
1591: if ((error = an_write_rid(sc, type, akey, sizeof(*akey))) != 0)
1592: return error;
1593: }
1594: if (kid >= 0) {
1595: memset(akey, 0, sizeof(struct an_rid_wepkey));
1596: akey->an_key_index = 0xffff;
1597: akey->an_mac_addr[0] = kid;
1598: an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
1599: akey->an_key_len = 0;
1600: memset(akey->an_key, 0, sizeof(akey->an_key));
1601: error = an_write_rid(sc, type, akey, sizeof(*akey));
1602: }
1603: return error;
1604: }
1605:
1606: int
1607: an_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
1608: {
1609: struct an_softc *sc = ic->ic_softc;
1610: struct ieee80211_node *ni = ic->ic_bss;
1611: enum ieee80211_state ostate;
1612: int buflen;
1613:
1614: ostate = ic->ic_state;
1615: DPRINTF(("an_newstate: %s -> %s\n", ieee80211_state_name[ostate],
1616: ieee80211_state_name[nstate]));
1617:
1618: switch (nstate) {
1619: case IEEE80211_S_INIT:
1620: ic->ic_flags &= ~IEEE80211_F_IBSSON;
1621: return (*sc->sc_newstate)(ic, nstate, arg);
1622:
1623: case IEEE80211_S_RUN:
1624: buflen = sizeof(sc->sc_buf);
1625: an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen);
1626: an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_cur_bssid, 3);
1627: an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_ssid, 16);
1628: IEEE80211_ADDR_COPY(ni->ni_bssid,
1629: sc->sc_buf.sc_status.an_cur_bssid);
1630: IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
1631: ni->ni_chan = &ic->ic_channels[
1632: sc->sc_buf.sc_status.an_cur_channel];
1633: ni->ni_esslen = sc->sc_buf.sc_status.an_ssidlen;
1634: if (ni->ni_esslen > IEEE80211_NWID_LEN)
1635: ni->ni_esslen = IEEE80211_NWID_LEN; /*XXX*/
1636: memcpy(ni->ni_essid, sc->sc_buf.sc_status.an_ssid,
1637: ni->ni_esslen);
1638: ni->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B]; /*XXX*/
1639: if (ic->ic_if.if_flags & IFF_DEBUG) {
1640: printf("%s: ", sc->sc_dev.dv_xname);
1641: if (ic->ic_opmode == IEEE80211_M_STA)
1642: printf("associated ");
1643: else
1644: printf("synchronized ");
1645: printf("with %s ssid ", ether_sprintf(ni->ni_bssid));
1646: ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
1647: printf(" channel %u start %uMb\n",
1648: sc->sc_buf.sc_status.an_cur_channel,
1649: sc->sc_buf.sc_status.an_current_tx_rate/2);
1650: }
1651: break;
1652:
1653: default:
1654: break;
1655: }
1656: ic->ic_state = nstate;
1657: /* skip standard ieee80211 handling */
1658: return 0;
1659: }
1660:
1661: int
1662: an_detach(struct an_softc *sc)
1663: {
1664: struct ifnet *ifp = &sc->sc_ic.ic_if;
1665: int s;
1666:
1667: if (!sc->sc_attached)
1668: return 0;
1669:
1670: s = splnet();
1671: sc->sc_invalid = 1;
1672: an_stop(ifp, 1);
1673: ifmedia_delete_instance(&sc->sc_ic.ic_media, IFM_INST_ANY);
1674: ieee80211_ifdetach(ifp);
1675: if_detach(ifp);
1676: if (sc->sc_sdhook != NULL)
1677: shutdownhook_disestablish(sc->sc_sdhook);
1678: splx(s);
1679: return 0;
1680: }
1681:
CVSweb