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