File: | dev/ic/an.c |
Warning: | line 725, column 8 Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: an.c,v 1.78 2021/02/25 02:48:20 dlg 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 NBPFILTER1 > 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((void *)0), "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_ORDER1234 == BIG_ENDIAN4321 |
160 | static __inline void |
161 | an_swap16(u_int16_t *p, int cnt) |
162 | { |
163 | for (; cnt--; p++) |
164 | *p = swap16(*p)(__uint16_t)(__builtin_constant_p(*p) ? (__uint16_t)(((__uint16_t )(*p) & 0xffU) << 8 | ((__uint16_t)(*p) & 0xff00U ) >> 8) : __swap16md(*p)); |
165 | } |
166 | #define an_switch32(val)val (val >> 16 | (val & 0xFFFF) << 16) |
167 | #else |
168 | #define an_swap16(p, cnt) |
169 | #define an_switch32(val)val val |
170 | #endif |
171 | |
172 | int |
173 | an_attach(struct an_softc *sc) |
174 | { |
175 | struct ieee80211com *ic = &sc->sc_ic; |
176 | struct ifnet *ifp = &ic->ic_ific_ac.ac_if; |
177 | int i; |
178 | struct an_rid_wepkey *akey; |
179 | int buflen, kid, rid; |
180 | int chan, chan_min, chan_max; |
181 | |
182 | sc->sc_invalid = 0; |
183 | |
184 | /* disable interrupts */ |
185 | CSR_WRITE_2(sc, AN_INT_EN, 0)((sc->sc_iot)->write_2((sc->sc_ioh), (0x32), (0))); |
186 | CSR_WRITE_2(sc, AN_EVENT_ACK, 0xffff)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0xffff ))); |
187 | |
188 | // an_wait(sc); |
189 | if (an_reset(sc) != 0) { |
190 | sc->sc_invalid = 1; |
191 | return 1; |
192 | } |
193 | |
194 | /* Load factory config */ |
195 | if (an_cmd(sc, AN_CMD_READCFG0x0008, 0) != 0) { |
196 | printf("%s: failed to load config data\n", |
197 | sc->sc_dev.dv_xname); |
198 | return (EIO5); |
199 | } |
200 | |
201 | /* Read the current configuration */ |
202 | buflen = sizeof(sc->sc_config); |
203 | if (an_read_rid(sc, AN_RID_GENCONFIG0xFF10, &sc->sc_config, &buflen) != 0) { |
204 | printf("%s: read config failed\n", sc->sc_dev.dv_xname); |
205 | return(EIO5); |
206 | } |
207 | |
208 | an_swap16((u_int16_t *)&sc->sc_config.an_macaddr, 3); |
209 | |
210 | /* Read the card capabilities */ |
211 | buflen = sizeof(sc->sc_caps); |
212 | if (an_read_rid(sc, AN_RID_CAPABILITIES0xFF00, &sc->sc_caps, &buflen) != 0) { |
213 | printf("%s: read caps failed\n", sc->sc_dev.dv_xname); |
214 | return(EIO5); |
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 | akey = &sc->sc_buf.sc_wepkey; |
222 | buflen = sizeof(struct an_rid_wepkey); |
223 | rid = AN_RID_WEP_VOLATILE0xFF15; /* first persistent key */ |
224 | 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 | 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 | if (kid == 0xffff) { |
233 | sc->sc_tx_perskey = akey->an_mac_addr[0]; |
234 | sc->sc_tx_key = -1; |
235 | break; |
236 | } |
237 | if (kid >= IEEE80211_WEP_NKID4) |
238 | break; |
239 | sc->sc_perskeylen[kid] = akey->an_key_len; |
240 | sc->sc_wepkeys[kid].an_wep_keylen = -1; |
241 | rid = AN_RID_WEP_PERSISTENT0xFF16; /* for next key */ |
242 | buflen = sizeof(struct an_rid_wepkey); |
243 | } |
244 | |
245 | IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr)__builtin_memcpy((ic->ic_myaddr), (sc->sc_caps.an_oemaddr ), (6)); |
246 | bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ16); |
247 | |
248 | printf("%s: Firmware %x.%02x.%02x, Radio: ", ifp->if_xname, |
249 | sc->sc_caps.an_fwrev >> 8, |
250 | sc->sc_caps.an_fwrev & 0xff, |
251 | sc->sc_caps.an_fwsubrev); |
252 | |
253 | if (sc->sc_config.an_radiotype & AN_RADIOTYPE_80211_FH0x0001) |
254 | printf("802.11 FH"); |
255 | else if (sc->sc_config.an_radiotype & AN_RADIOTYPE_80211_DS0x0002) |
256 | printf("802.11 DS"); |
257 | else if (sc->sc_config.an_radiotype & AN_RADIOTYPE_LM2000_DS0x0004) |
258 | printf("LM2000 DS"); |
259 | else |
260 | printf("unknown (%x)", sc->sc_config.an_radiotype); |
261 | |
262 | printf(", address %s\n", ether_sprintf(ic->ic_myaddr)); |
263 | |
264 | ifp->if_softc = sc; |
265 | ifp->if_flags = IFF_BROADCAST0x2 | IFF_SIMPLEX0x800 | IFF_MULTICAST0x8000; |
266 | ifp->if_ioctl = an_ioctl; |
267 | ifp->if_start = an_start; |
268 | ifp->if_watchdog = an_watchdog; |
269 | |
270 | ic->ic_phytype = IEEE80211_T_DS; |
271 | ic->ic_opmode = IEEE80211_M_STA; |
272 | ic->ic_caps = IEEE80211_C_WEP0x00000001 | IEEE80211_C_PMGT0x00000004 | IEEE80211_C_MONITOR0x00000200; |
273 | #ifndef IEEE80211_STA_ONLY |
274 | ic->ic_caps |= IEEE80211_C_IBSS0x00000002; |
275 | #endif |
276 | ic->ic_state = IEEE80211_S_INIT; |
277 | IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr)__builtin_memcpy((ic->ic_myaddr), (sc->sc_caps.an_oemaddr ), (6)); |
278 | |
279 | switch (sc->sc_caps.an_regdomain) { |
280 | default: |
281 | case AN_REGDOMAIN_USA0: |
282 | case AN_REGDOMAIN_CANADA7: |
283 | chan_min = 1; chan_max = 11; break; |
284 | case AN_REGDOMAIN_EUROPE1: |
285 | case AN_REGDOMAIN_AUSTRALIA8: |
286 | chan_min = 1; chan_max = 13; break; |
287 | case AN_REGDOMAIN_JAPAN2: |
288 | chan_min = 14; chan_max = 14; break; |
289 | case AN_REGDOMAIN_SPAIN3: |
290 | chan_min = 10; chan_max = 11; break; |
291 | case AN_REGDOMAIN_FRANCE4: |
292 | chan_min = 10; chan_max = 13; break; |
293 | case AN_REGDOMAIN_JAPANWIDE9: |
294 | chan_min = 1; chan_max = 14; break; |
295 | } |
296 | |
297 | for (chan = chan_min; chan <= chan_max; chan++) { |
298 | ic->ic_channels[chan].ic_freq = |
299 | ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ0x0080); |
300 | ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_B(0x0080 | 0x0020); |
301 | } |
302 | ic->ic_ibss_chan = &ic->ic_channels[chan_min]; |
303 | |
304 | /* Find supported rate */ |
305 | for (i = 0; i < sizeof(sc->sc_caps.an_rates); i++) { |
306 | if (sc->sc_caps.an_rates[i] == 0) |
307 | continue; |
308 | ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[ |
309 | ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates++] = |
310 | sc->sc_caps.an_rates[i]; |
311 | } |
312 | |
313 | /* |
314 | * Call MI attach routine. |
315 | */ |
316 | if_attach(ifp); |
317 | ieee80211_ifattach(ifp); |
318 | |
319 | sc->sc_newstate = ic->ic_newstate; |
320 | ic->ic_newstate = an_newstate; |
321 | |
322 | ieee80211_media_init(ifp, an_media_change, an_media_status); |
323 | |
324 | #if NBPFILTER1 > 0 |
325 | bzero(&sc->sc_rxtapu, sizeof(sc->sc_rxtapu))__builtin_bzero((&sc->sc_rxtapu), (sizeof(sc->sc_rxtapu ))); |
326 | sc->sc_rxtapsc_rxtapu.tap.ar_ihdr.it_len = sizeof(sc->sc_rxtapu); |
327 | sc->sc_rxtapsc_rxtapu.tap.ar_ihdr.it_present = AN_RX_RADIOTAP_PRESENT((1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_RATE ) | (1 << IEEE80211_RADIOTAP_CHANNEL) | (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL )); |
328 | |
329 | bzero(&sc->sc_txtapu, sizeof(sc->sc_txtapu))__builtin_bzero((&sc->sc_txtapu), (sizeof(sc->sc_txtapu ))); |
330 | sc->sc_txtapsc_txtapu.tap.at_ihdr.it_len = sizeof(sc->sc_txtapu); |
331 | sc->sc_txtapsc_txtapu.tap.at_ihdr.it_present = AN_TX_RADIOTAP_PRESENT((1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_RATE ) | (1 << IEEE80211_RADIOTAP_CHANNEL)); |
332 | |
333 | bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO127, |
334 | sizeof(struct ieee80211_frame) + 64); |
335 | #endif |
336 | |
337 | sc->sc_attached = 1; |
338 | |
339 | return(0); |
340 | } |
341 | |
342 | void |
343 | an_rxeof(struct an_softc *sc) |
344 | { |
345 | struct ieee80211com *ic = &sc->sc_ic; |
346 | struct ifnet *ifp = &ic->ic_ific_ac.ac_if; |
347 | struct ieee80211_frame *wh; |
348 | struct ieee80211_rxinfo rxi; |
349 | struct ieee80211_node *ni; |
350 | 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 | fid = CSR_READ_2(sc, AN_RX_FID)((sc->sc_iot)->read_2((sc->sc_ioh), (0x20))); |
357 | |
358 | /* First read in the frame header */ |
359 | if (an_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr), sizeof(frmhdr)) != 0) { |
360 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0001 ))); |
361 | ifp->if_ierrorsif_data.ifi_ierrors++; |
362 | DPRINTF(("an_rxeof: read fid %x failed\n", fid)); |
363 | return; |
364 | } |
365 | an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2); |
366 | |
367 | status = frmhdr.an_rx_status; |
368 | if ((status & AN_STAT_ERRSTAT0x0003) != 0 && |
369 | ic->ic_opmode != IEEE80211_M_MONITOR) { |
370 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0001 ))); |
371 | ifp->if_ierrorsif_data.ifi_ierrors++; |
372 | DPRINTF(("an_rxeof: fid %x status %x\n", fid, status)); |
373 | return; |
374 | } |
375 | |
376 | /* the payload length field includes a 16-bit "mystery field" */ |
377 | len = frmhdr.an_rx_payload_len - sizeof(uint16_t); |
378 | off = ALIGN(sizeof(struct ieee80211_frame))(((unsigned long)(sizeof(struct ieee80211_frame)) + (sizeof(long ) - 1)) &~(sizeof(long) - 1)); |
379 | |
380 | if (off + len > MCLBYTES(1 << 11)) { |
381 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { |
382 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0001 ))); |
383 | ifp->if_ierrorsif_data.ifi_ierrors++; |
384 | DPRINTF(("an_rxeof: oversized packet %d\n", len)); |
385 | return; |
386 | } |
387 | len = 0; |
388 | } |
389 | |
390 | MGETHDR(m, M_DONTWAIT, MT_DATA)m = m_gethdr((0x0002), (1)); |
391 | if (m == NULL((void *)0)) { |
392 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0001 ))); |
393 | ifp->if_ierrorsif_data.ifi_ierrors++; |
394 | DPRINTF(("an_rxeof: MGET failed\n")); |
395 | return; |
396 | } |
397 | if (off + len + AN_GAPLEN_MAX8 > MHLEN((256 - sizeof(struct m_hdr)) - sizeof(struct pkthdr))) { |
398 | MCLGET(m, M_DONTWAIT)(void) m_clget((m), (0x0002), (1 << 11)); |
399 | if ((m->m_flagsm_hdr.mh_flags & M_EXT0x0001) == 0) { |
400 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0001 ))); |
401 | m_freem(m); |
402 | ifp->if_ierrorsif_data.ifi_ierrors++; |
403 | DPRINTF(("an_rxeof: MCLGET failed\n")); |
404 | return; |
405 | } |
406 | } |
407 | m->m_datam_hdr.mh_data += off - sizeof(struct ieee80211_frame); |
408 | |
409 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { |
410 | gaplen = frmhdr.an_gaplen; |
411 | if (gaplen > AN_GAPLEN_MAX8) { |
412 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0001 ))); |
413 | m_freem(m); |
414 | ifp->if_ierrorsif_data.ifi_ierrors++; |
415 | DPRINTF(("%s: gap too long\n", __func__)); |
416 | 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 | gap = m->m_datam_hdr.mh_data + sizeof(struct ieee80211_frame) - |
428 | sizeof(uint16_t); |
429 | an_read_bap(sc, fid, -1, gap, gaplen + sizeof(u_int16_t), |
430 | gaplen + sizeof(u_int16_t)); |
431 | } else |
432 | gaplen = 0; |
433 | |
434 | an_read_bap(sc, fid, -1, |
435 | m->m_datam_hdr.mh_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 | m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = sizeof(struct ieee80211_frame) + gaplen + |
438 | len; |
439 | |
440 | memcpy(m->m_data, &frmhdr.an_whdr, sizeof(struct ieee80211_frame))__builtin_memcpy((m->m_hdr.mh_data), (&frmhdr.an_whdr) , (sizeof(struct ieee80211_frame))); |
441 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0001 ))); |
442 | |
443 | #if NBPFILTER1 > 0 |
444 | if (sc->sc_drvbpf) { |
445 | struct mbuf mb; |
446 | struct an_rx_radiotap_header *tap = &sc->sc_rxtapsc_rxtapu.tap; |
447 | |
448 | tap->ar_rate = frmhdr.an_rx_rate; |
449 | tap->ar_antsignal = frmhdr.an_rx_signal_strength; |
450 | tap->ar_chan_freq = ic->ic_bss->ni_chan->ic_freq; |
451 | tap->ar_chan_flags = ic->ic_bss->ni_chan->ic_flags; |
452 | |
453 | |
454 | mb.m_datam_hdr.mh_data = (caddr_t)tap; |
455 | mb.m_lenm_hdr.mh_len = sizeof(sc->sc_rxtapu); |
456 | mb.m_nextm_hdr.mh_next = m; |
457 | mb.m_nextpktm_hdr.mh_nextpkt = NULL((void *)0); |
458 | mb.m_typem_hdr.mh_type = 0; |
459 | mb.m_flagsm_hdr.mh_flags = 0; |
460 | bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN(1 << 0)); |
461 | } |
462 | #endif /* NBPFILTER > 0 */ |
463 | |
464 | wh = mtod(m, struct ieee80211_frame *)((struct ieee80211_frame *)((m)->m_hdr.mh_data)); |
465 | rxi.rxi_flags = 0; |
466 | if (wh->i_fc[1] & IEEE80211_FC1_WEP0x40) { |
467 | /* |
468 | * WEP is decrypted by hardware. Clear WEP bit |
469 | * header for ieee80211_input(). |
470 | */ |
471 | wh->i_fc[1] &= ~IEEE80211_FC1_WEP0x40; |
472 | |
473 | rxi.rxi_flags |= IEEE80211_RXI_HWDEC0x00000001; |
474 | } |
475 | |
476 | ni = ieee80211_find_rxnode(ic, wh); |
477 | rxi.rxi_rssi = frmhdr.an_rx_signal_strength; |
478 | rxi.rxi_tstamp = an_switch32(frmhdr.an_rx_time)frmhdr.an_rx_time; |
479 | ieee80211_input(ifp, m, ni, &rxi); |
480 | ieee80211_release_node(ic, ni); |
481 | } |
482 | |
483 | void |
484 | an_txeof(struct an_softc *sc, u_int16_t status) |
485 | { |
486 | struct ifnet *ifp = &sc->sc_ic.ic_ific_ac.ac_if; |
487 | int cur, id; |
488 | |
489 | sc->sc_tx_timer = 0; |
490 | ifq_clr_oactive(&ifp->if_snd); |
491 | |
492 | id = CSR_READ_2(sc, AN_TX_CMP_FID)((sc->sc_iot)->read_2((sc->sc_ioh), (0x24))); |
493 | CSR_WRITE_2(sc, AN_EVENT_ACK, status & (AN_EV_TX | AN_EV_TX_EXC))((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (status & (0x0002 | 0x0004)))); |
494 | |
495 | if (status & AN_EV_TX_EXC0x0004) |
496 | ifp->if_oerrorsif_data.ifi_oerrors++; |
497 | |
498 | cur = sc->sc_txcur; |
499 | if (sc->sc_txd[cur].d_fid == id) { |
500 | sc->sc_txd[cur].d_inuse = 0; |
501 | DPRINTF2(("an_txeof: sent %x/%d\n", id, cur)); |
502 | AN_INC(cur, AN_TX_RING_CNT)(cur) = (cur + 1) % 4; |
503 | sc->sc_txcur = cur; |
504 | } else { |
505 | for (cur = 0; cur < AN_TX_RING_CNT4; cur++) { |
506 | if (id == sc->sc_txd[cur].d_fid) { |
507 | sc->sc_txd[cur].d_inuse = 0; |
508 | break; |
509 | } |
510 | } |
511 | if (ifp->if_flags & IFF_DEBUG0x4) |
512 | printf("%s: tx mismatch: " |
513 | "expected %x(%d), actual %x(%d)\n", |
514 | sc->sc_dev.dv_xname, |
515 | sc->sc_txd[sc->sc_txcur].d_fid, sc->sc_txcur, |
516 | id, cur); |
517 | } |
518 | } |
519 | |
520 | int |
521 | an_intr(void *arg) |
522 | { |
523 | struct an_softc *sc = arg; |
524 | struct ifnet *ifp = &sc->sc_ic.ic_ific_ac.ac_if; |
525 | int i; |
526 | u_int16_t status; |
527 | |
528 | if (!sc->sc_enabled || sc->sc_invalid || |
529 | (sc->sc_dev.dv_flags & DVF_ACTIVE0x0001) == 0 || |
530 | (ifp->if_flags & IFF_RUNNING0x40) == 0) |
531 | return 0; |
532 | |
533 | if ((ifp->if_flags & IFF_UP0x1) == 0) { |
534 | CSR_WRITE_2(sc, AN_INT_EN, 0)((sc->sc_iot)->write_2((sc->sc_ioh), (0x32), (0))); |
535 | CSR_WRITE_2(sc, AN_EVENT_ACK, ~0)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (~0))); |
536 | return 1; |
537 | } |
538 | |
539 | /* maximum 10 loops per interrupt */ |
540 | for (i = 0; i < 10; i++) { |
541 | if (!sc->sc_enabled || sc->sc_invalid) |
542 | return 1; |
543 | if (CSR_READ_2(sc, AN_SW0)((sc->sc_iot)->read_2((sc->sc_ioh), (0x28))) != AN_MAGIC0x414e) { |
544 | DPRINTF(("an_intr: magic number changed: %x\n", |
545 | CSR_READ_2(sc, AN_SW0))); |
546 | sc->sc_invalid = 1; |
547 | return 1; |
548 | } |
549 | status = CSR_READ_2(sc, AN_EVENT_STAT)((sc->sc_iot)->read_2((sc->sc_ioh), (0x30))); |
550 | CSR_WRITE_2(sc, AN_EVENT_ACK, status & ~(AN_INTRS))((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (status & ~((0x0001 | 0x0002 | 0x0004 | 0x0080))))); |
551 | if ((status & AN_INTRS(0x0001 | 0x0002 | 0x0004 | 0x0080)) == 0) |
552 | break; |
553 | |
554 | if (status & AN_EV_RX0x0001) |
555 | an_rxeof(sc); |
556 | |
557 | if (status & (AN_EV_TX0x0002 | AN_EV_TX_EXC0x0004)) |
558 | an_txeof(sc, status); |
559 | |
560 | if (status & AN_EV_LINKSTAT0x0080) |
561 | an_linkstat_intr(sc); |
562 | |
563 | if (ifq_is_oactive(&ifp->if_snd) == 0 && |
564 | sc->sc_ic.ic_state == IEEE80211_S_RUN && |
565 | !ifq_empty(&ifp->if_snd)(((&ifp->if_snd)->ifq_len) == 0)) |
566 | an_start(ifp); |
567 | } |
568 | |
569 | return 1; |
570 | } |
571 | |
572 | /* Must be called at proper protection level! */ |
573 | int |
574 | an_cmd(struct an_softc *sc, int cmd, int val) |
575 | { |
576 | int i, stat; |
577 | |
578 | /* make sure previous command completed */ |
579 | if (CSR_READ_2(sc, AN_COMMAND)((sc->sc_iot)->read_2((sc->sc_ioh), (0x00))) & AN_CMD_BUSY0x8000) { |
580 | if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4) |
581 | printf("%s: command 0x%x busy\n", sc->sc_dev.dv_xname, |
582 | CSR_READ_2(sc, AN_COMMAND)((sc->sc_iot)->read_2((sc->sc_ioh), (0x00)))); |
583 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x4000 ))); |
584 | } |
585 | |
586 | CSR_WRITE_2(sc, AN_PARAM0, val)((sc->sc_iot)->write_2((sc->sc_ioh), (0x02), (val))); |
587 | CSR_WRITE_2(sc, AN_PARAM1, 0)((sc->sc_iot)->write_2((sc->sc_ioh), (0x04), (0))); |
588 | CSR_WRITE_2(sc, AN_PARAM2, 0)((sc->sc_iot)->write_2((sc->sc_ioh), (0x06), (0))); |
589 | CSR_WRITE_2(sc, AN_COMMAND, cmd)((sc->sc_iot)->write_2((sc->sc_ioh), (0x00), (cmd))); |
590 | |
591 | if (cmd == AN_CMD_FW_RESTART0x0004) { |
592 | /* XXX: should sleep here */ |
593 | DELAY(100*1000)(*delay_func)(100*1000); |
594 | } |
595 | |
596 | for (i = 0; i < AN_TIMEOUT65536; i++) { |
597 | if (CSR_READ_2(sc, AN_EVENT_STAT)((sc->sc_iot)->read_2((sc->sc_ioh), (0x30))) & AN_EV_CMD0x0010) |
598 | break; |
599 | DELAY(10)(*delay_func)(10); |
600 | } |
601 | |
602 | stat = CSR_READ_2(sc, AN_STATUS)((sc->sc_iot)->read_2((sc->sc_ioh), (0x08))); |
603 | |
604 | /* clear stuck command busy if necessary */ |
605 | if (CSR_READ_2(sc, AN_COMMAND)((sc->sc_iot)->read_2((sc->sc_ioh), (0x00))) & AN_CMD_BUSY0x8000) |
606 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x4000 ))); |
607 | |
608 | /* Ack the command */ |
609 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0010 ))); |
610 | |
611 | if (i == AN_TIMEOUT65536) { |
612 | if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4) |
613 | printf("%s: command 0x%x param 0x%x timeout\n", |
614 | sc->sc_dev.dv_xname, cmd, val); |
615 | return ETIMEDOUT60; |
616 | } |
617 | if (stat & AN_STAT_CMD_RESULT0x7F00) { |
618 | if (sc->sc_ic.ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4) |
619 | printf("%s: command 0x%x param 0x%x status 0x%x " |
620 | "resp 0x%x 0x%x 0x%x\n", |
621 | sc->sc_dev.dv_xname, cmd, val, stat, |
622 | CSR_READ_2(sc, AN_RESP0)((sc->sc_iot)->read_2((sc->sc_ioh), (0x0A))), CSR_READ_2(sc, AN_RESP1)((sc->sc_iot)->read_2((sc->sc_ioh), (0x0C))), |
623 | CSR_READ_2(sc, AN_RESP2)((sc->sc_iot)->read_2((sc->sc_ioh), (0x0E)))); |
624 | return EIO5; |
625 | } |
626 | |
627 | return 0; |
628 | } |
629 | |
630 | int |
631 | an_reset(struct an_softc *sc) |
632 | { |
633 | |
634 | DPRINTF(("an_reset\n")); |
635 | |
636 | if (!sc->sc_enabled) |
637 | return ENXIO6; |
638 | |
639 | an_cmd(sc, AN_CMD_ENABLE0x0001, 0); |
640 | an_cmd(sc, AN_CMD_FW_RESTART0x0004, 0); |
641 | an_cmd(sc, AN_CMD_NOOP20x0010, 0); |
642 | |
643 | if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS0x0003, 0) == ETIMEDOUT60) { |
644 | printf("%s: reset failed\n", sc->sc_dev.dv_xname); |
645 | return ETIMEDOUT60; |
646 | } |
647 | |
648 | an_cmd(sc, AN_CMD_DISABLE0x0002, 0); |
649 | return 0; |
650 | } |
651 | |
652 | void |
653 | an_linkstat_intr(struct an_softc *sc) |
654 | { |
655 | struct ieee80211com *ic = &sc->sc_ic; |
656 | u_int16_t status; |
657 | |
658 | status = CSR_READ_2(sc, AN_LINKSTAT)((sc->sc_iot)->read_2((sc->sc_ioh), (0x10))); |
659 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0080 ))); |
660 | DPRINTF(("an_linkstat_intr: status 0x%x\n", status)); |
661 | |
662 | if (status == AN_LINKSTAT_ASSOCIATED0x0400) { |
663 | if (ic->ic_state != IEEE80211_S_RUN |
664 | #ifndef IEEE80211_STA_ONLY |
665 | || ic->ic_opmode == IEEE80211_M_IBSS |
666 | #endif |
667 | ) |
668 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1)(((ic)->ic_newstate)((ic), (IEEE80211_S_RUN), (-1))); |
669 | } else { |
670 | if (ic->ic_opmode == IEEE80211_M_STA) |
671 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1)(((ic)->ic_newstate)((ic), (IEEE80211_S_INIT), (-1))); |
672 | } |
673 | } |
674 | |
675 | /* |
676 | * Wait for firmware come up after power enabled. |
677 | */ |
678 | void |
679 | an_wait(struct an_softc *sc) |
680 | { |
681 | int i; |
682 | |
683 | CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_NOOP2)((sc->sc_iot)->write_2((sc->sc_ioh), (0x00), (0x0010 ))); |
684 | for (i = 0; i < 3000; i += 100) { |
685 | if (CSR_READ_2(sc, AN_EVENT_STAT)((sc->sc_iot)->read_2((sc->sc_ioh), (0x30))) & AN_EV_CMD0x0010) |
686 | break; |
687 | tsleep_nsec(sc, PWAIT32, "anatch", MSEC_TO_NSEC(100)); |
688 | } |
689 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0010 ))); |
690 | } |
691 | |
692 | int |
693 | 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 | if (len == 0 || blen == 0) |
698 | return 0; |
699 | if (off == -1) |
700 | off = sc->sc_bap_off; |
701 | if (id != sc->sc_bap_id || off != sc->sc_bap_off) { |
702 | if ((error = an_seek_bap(sc, id, off)) != 0) |
703 | return EIO5; |
704 | } |
705 | |
706 | cnt = (blen + 1) / 2; |
707 | CSR_READ_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt)((sc->sc_iot)->read_multi_2((sc->sc_ioh), (0x36), (( u_int16_t *)buf), (cnt))); |
708 | for (cnt2 = (len + 1) / 2; cnt < cnt2; cnt++) |
709 | (void) CSR_READ_2(sc, AN_DATA0)((sc->sc_iot)->read_2((sc->sc_ioh), (0x36))); |
710 | sc->sc_bap_off += cnt * 2; |
711 | |
712 | return 0; |
713 | } |
714 | |
715 | int |
716 | an_write_bap(struct an_softc *sc, int id, int off, void *buf, int buflen) |
717 | { |
718 | int error, cnt; |
719 | |
720 | if (buflen == 0) |
721 | return 0; |
722 | if (off == -1) |
723 | off = sc->sc_bap_off; |
724 | if (id != sc->sc_bap_id || off != sc->sc_bap_off) { |
725 | if ((error = an_seek_bap(sc, id, off)) != 0) |
Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' | |
726 | return EIO5; |
727 | } |
728 | |
729 | cnt = (buflen + 1) / 2; |
730 | CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt)((sc->sc_iot)->write_multi_2((sc->sc_ioh), (0x36), ( (u_int16_t *)buf), (cnt))); |
731 | sc->sc_bap_off += cnt * 2; |
732 | return 0; |
733 | } |
734 | |
735 | int |
736 | an_seek_bap(struct an_softc *sc, int id, int off) |
737 | { |
738 | int i, status; |
739 | |
740 | CSR_WRITE_2(sc, AN_SEL0, id)((sc->sc_iot)->write_2((sc->sc_ioh), (0x18), (id))); |
741 | CSR_WRITE_2(sc, AN_OFF0, off)((sc->sc_iot)->write_2((sc->sc_ioh), (0x1C), (off))); |
742 | |
743 | for (i = 0; ; i++) { |
744 | status = CSR_READ_2(sc, AN_OFF0)((sc->sc_iot)->read_2((sc->sc_ioh), (0x1C))); |
745 | if ((status & AN_OFF_BUSY0x8000) == 0) |
746 | break; |
747 | if (i == AN_TIMEOUT65536) { |
748 | printf("%s: timeout in an_seek_bap to 0x%x/0x%x\n", |
749 | sc->sc_dev.dv_xname, id, off); |
750 | sc->sc_bap_off = AN_OFF_ERR0x4000; /* invalidate */ |
751 | return ETIMEDOUT60; |
752 | } |
753 | DELAY(10)(*delay_func)(10); |
754 | } |
755 | if (status & AN_OFF_ERR0x4000) { |
756 | printf("%s: failed in an_seek_bap to 0x%x/0x%x\n", |
757 | sc->sc_dev.dv_xname, id, off); |
758 | sc->sc_bap_off = AN_OFF_ERR0x4000; /* invalidate */ |
759 | return EIO5; |
760 | } |
761 | sc->sc_bap_id = id; |
762 | sc->sc_bap_off = off; |
763 | return 0; |
764 | } |
765 | |
766 | int |
767 | an_mwrite_bap(struct an_softc *sc, int id, int off, struct mbuf *m, int totlen) |
768 | { |
769 | int error, len, cnt; |
770 | |
771 | if (off == -1) |
772 | off = sc->sc_bap_off; |
773 | if (id != sc->sc_bap_id || off != sc->sc_bap_off) { |
774 | if ((error = an_seek_bap(sc, id, off)) != 0) |
775 | return EIO5; |
776 | } |
777 | |
778 | for (len = 0; m != NULL((void *)0); m = m->m_nextm_hdr.mh_next) { |
779 | if (m->m_lenm_hdr.mh_len == 0) |
780 | continue; |
781 | len = min(m->m_lenm_hdr.mh_len, totlen); |
782 | |
783 | if ((mtod(m, u_long)((u_long)((m)->m_hdr.mh_data)) & 0x1) || (len & 0x1)) { |
784 | m_copydata(m, 0, totlen, &sc->sc_buf.sc_txbuf); |
785 | cnt = (totlen + 1) / 2; |
786 | an_swap16((u_int16_t *)&sc->sc_buf.sc_txbuf, cnt); |
787 | CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0,((sc->sc_iot)->write_multi_2((sc->sc_ioh), (0x36), ( sc->sc_buf.sc_val), (cnt))) |
788 | sc->sc_buf.sc_val, cnt)((sc->sc_iot)->write_multi_2((sc->sc_ioh), (0x36), ( sc->sc_buf.sc_val), (cnt))); |
789 | off += cnt * 2; |
790 | break; |
791 | } |
792 | cnt = len / 2; |
793 | an_swap16((u_int16_t *)mtod(m, u_int16_t *), cnt); |
794 | CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, mtod(m, u_int16_t *),((sc->sc_iot)->write_multi_2((sc->sc_ioh), (0x36), ( ((u_int16_t *)((m)->m_hdr.mh_data))), (cnt))) |
795 | cnt)((sc->sc_iot)->write_multi_2((sc->sc_ioh), (0x36), ( ((u_int16_t *)((m)->m_hdr.mh_data))), (cnt))); |
796 | off += len; |
797 | totlen -= len; |
798 | } |
799 | sc->sc_bap_off = off; |
800 | return 0; |
801 | } |
802 | |
803 | int |
804 | an_alloc_nicmem(struct an_softc *sc, int len, int *idp) |
805 | { |
806 | int i; |
807 | |
808 | if (an_cmd(sc, AN_CMD_ALLOC_MEM0x000A, len)) { |
809 | printf("%s: failed to allocate %d bytes on NIC\n", |
810 | sc->sc_dev.dv_xname, len); |
811 | return(ENOMEM12); |
812 | } |
813 | |
814 | for (i = 0; i < AN_TIMEOUT65536; i++) { |
815 | if (CSR_READ_2(sc, AN_EVENT_STAT)((sc->sc_iot)->read_2((sc->sc_ioh), (0x30))) & AN_EV_ALLOC0x0008) |
816 | break; |
817 | if (i == AN_TIMEOUT65536) { |
818 | printf("%s: timeout in alloc\n", sc->sc_dev.dv_xname); |
819 | return ETIMEDOUT60; |
820 | } |
821 | DELAY(10)(*delay_func)(10); |
822 | } |
823 | |
824 | *idp = CSR_READ_2(sc, AN_ALLOC_FID)((sc->sc_iot)->read_2((sc->sc_ioh), (0x22))); |
825 | CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC)((sc->sc_iot)->write_2((sc->sc_ioh), (0x34), (0x0008 ))); |
826 | return 0; |
827 | } |
828 | |
829 | int |
830 | an_read_rid(struct an_softc *sc, int rid, void *buf, int *buflenp) |
831 | { |
832 | int error; |
833 | u_int16_t len; |
834 | |
835 | /* Tell the NIC to enter record read mode. */ |
836 | error = an_cmd(sc, AN_CMD_ACCESS0x0021 | AN_ACCESS_READ0x0000, rid); |
837 | if (error) |
838 | return error; |
839 | |
840 | /* length in byte, including length itself */ |
841 | error = an_read_bap(sc, rid, 0, &len, sizeof(len), sizeof(len)); |
842 | if (error) |
843 | return error; |
844 | |
845 | len -= 2; |
846 | return an_read_bap(sc, rid, sizeof(len), buf, len, *buflenp); |
847 | } |
848 | |
849 | int |
850 | an_write_rid(struct an_softc *sc, int rid, void *buf, int buflen) |
851 | { |
852 | int error; |
853 | u_int16_t len; |
854 | |
855 | /* length in byte, including length itself */ |
856 | len = buflen + 2; |
857 | |
858 | error = an_write_bap(sc, rid, 0, &len, sizeof(len)); |
859 | if (error) |
860 | return error; |
861 | error = an_write_bap(sc, rid, sizeof(len), buf, buflen); |
862 | if (error) |
863 | return error; |
864 | |
865 | return an_cmd(sc, AN_CMD_ACCESS0x0021 | AN_ACCESS_WRITE0x0100, rid); |
866 | } |
867 | |
868 | int |
869 | an_ioctl(struct ifnet *ifp, u_long command, caddr_t data) |
870 | { |
871 | struct an_softc *sc = ifp->if_softc; |
872 | int s, error = 0; |
873 | |
874 | if ((sc->sc_dev.dv_flags & DVF_ACTIVE0x0001) == 0) |
875 | return ENXIO6; |
876 | |
877 | s = splnet()splraise(0x7); |
878 | |
879 | switch(command) { |
880 | case SIOCSIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((12))): |
881 | ifp->if_flags |= IFF_UP0x1; |
882 | error = an_init(ifp); |
883 | break; |
884 | case SIOCSIFFLAGS((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((16))): |
885 | if (ifp->if_flags & IFF_UP0x1) { |
886 | 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 | error = an_cmd(sc, AN_CMD_SET_MODE0x0009, |
893 | (ifp->if_flags & IFF_PROMISC0x100) ? 0xffff : 0); |
894 | } else |
895 | error = an_init(ifp); |
896 | } else if (sc->sc_enabled) |
897 | an_stop(ifp, 1); |
898 | break; |
899 | case SIOCADDMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((49))): |
900 | case SIOCDELMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((50))): |
901 | /* The Aironet has no multicast filter. */ |
902 | error = 0; |
903 | break; |
904 | case SIOCS80211NWKEY((unsigned long)0x80000000 | ((sizeof(struct ieee80211_nwkey) & 0x1fff) << 16) | ((('i')) << 8) | ((232))): |
905 | if ((error = suser(curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc)) != 0) |
906 | break; |
907 | error = an_set_nwkey(sc, (struct ieee80211_nwkey *)data); |
908 | break; |
909 | case SIOCG80211NWKEY(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ieee80211_nwkey) & 0x1fff) << 16) | ((('i') ) << 8) | ((233))): |
910 | error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data); |
911 | break; |
912 | default: |
913 | error = ieee80211_ioctl(ifp, command, data); |
914 | break; |
915 | } |
916 | if (error == ENETRESET52) { |
917 | if (sc->sc_enabled) |
918 | error = an_init(ifp); |
919 | else |
920 | error = 0; |
921 | } |
922 | splx(s)spllower(s); |
923 | return(error); |
924 | } |
925 | |
926 | int |
927 | an_init(struct ifnet *ifp) |
928 | { |
929 | struct an_softc *sc = ifp->if_softc; |
930 | struct ieee80211com *ic = &sc->sc_ic; |
931 | int i, error, fid; |
932 | |
933 | DPRINTF(("an_init: enabled %d\n", sc->sc_enabled)); |
934 | if (!sc->sc_enabled) { |
935 | if (sc->sc_enable) |
936 | (*sc->sc_enable)(sc); |
937 | an_wait(sc); |
938 | sc->sc_enabled = 1; |
939 | } else { |
940 | an_stop(ifp, 0); |
941 | if ((error = an_reset(sc)) != 0) { |
942 | printf("%s: failed to reset\n", ifp->if_xname); |
943 | an_stop(ifp, 1); |
944 | return error; |
945 | } |
946 | } |
947 | CSR_WRITE_2(sc, AN_SW0, AN_MAGIC)((sc->sc_iot)->write_2((sc->sc_ioh), (0x28), (0x414e ))); |
948 | |
949 | /* Allocate the TX buffers */ |
950 | for (i = 0; i < AN_TX_RING_CNT4; i++) { |
951 | if ((error = an_alloc_nicmem(sc, AN_TX_MAX_LEN(sizeof(struct an_txframe) + 2 + 1518), &fid)) != 0) { |
952 | printf("%s: failed to allocate nic memory\n", |
953 | ifp->if_xname); |
954 | an_stop(ifp, 1); |
955 | return error; |
956 | } |
957 | DPRINTF2(("an_init: txbuf %d allocated %x\n", i, fid)); |
958 | sc->sc_txd[i].d_fid = fid; |
959 | sc->sc_txd[i].d_inuse = 0; |
960 | } |
961 | sc->sc_txcur = sc->sc_txnext = 0; |
962 | |
963 | IEEE80211_ADDR_COPY(sc->sc_config.an_macaddr, ic->ic_myaddr)__builtin_memcpy((sc->sc_config.an_macaddr), (ic->ic_myaddr ), (6)); |
964 | an_swap16((u_int16_t *)&sc->sc_config.an_macaddr, 3); |
965 | sc->sc_config.an_scanmode = AN_SCANMODE_ACTIVE0x0000; |
966 | sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN0x0001; /*XXX*/ |
967 | if (ic->ic_flags & IEEE80211_F_WEPON0x00000100) { |
968 | sc->sc_config.an_authtype |= |
969 | AN_AUTHTYPE_PRIVACY_IN_USE0x0100; |
970 | } |
971 | sc->sc_config.an_listen_interval = ic->ic_lintval; |
972 | sc->sc_config.an_beacon_period = ic->ic_lintval; |
973 | if (ic->ic_flags & IEEE80211_F_PMGTON0x00000400) |
974 | sc->sc_config.an_psave_mode = AN_PSAVE_PSP0x0001; |
975 | else |
976 | sc->sc_config.an_psave_mode = AN_PSAVE_CAM0x0000; |
977 | sc->sc_config.an_ds_channel = |
978 | ieee80211_chan2ieee(ic, ic->ic_ibss_chan); |
979 | |
980 | switch (ic->ic_opmode) { |
981 | case IEEE80211_M_STA: |
982 | sc->sc_config.an_opmode = |
983 | AN_OPMODE_INFRASTRUCTURE_STATION0x0001; |
984 | sc->sc_config.an_rxmode = AN_RXMODE_BC_MC_ADDR0x0000; |
985 | break; |
986 | #ifndef IEEE80211_STA_ONLY |
987 | case IEEE80211_M_IBSS: |
988 | sc->sc_config.an_opmode = AN_OPMODE_IBSS_ADHOC0x0000; |
989 | sc->sc_config.an_rxmode = AN_RXMODE_BC_MC_ADDR0x0000; |
990 | break; |
991 | #endif |
992 | case IEEE80211_M_MONITOR: |
993 | sc->sc_config.an_opmode = |
994 | AN_OPMODE_INFRASTRUCTURE_STATION0x0001; |
995 | sc->sc_config.an_rxmode = |
996 | AN_RXMODE_80211_MONITOR_ANYBSS0x0004; |
997 | sc->sc_config.an_authtype = AN_AUTHTYPE_NONE0x0000; |
998 | if (ic->ic_flags & IEEE80211_F_WEPON0x00000100) |
999 | sc->sc_config.an_authtype |= |
1000 | AN_AUTHTYPE_PRIVACY_IN_USE0x0100 | |
1001 | AN_AUTHTYPE_ALLOW_UNENCRYPTED0x0200; |
1002 | break; |
1003 | default: |
1004 | printf("%s: bad opmode %d\n", ifp->if_xname, ic->ic_opmode); |
1005 | an_stop(ifp, 1); |
1006 | return EIO5; |
1007 | } |
1008 | sc->sc_config.an_rxmode |= AN_RXMODE_NO_8023_HEADER0x0100; |
1009 | |
1010 | /* Set the ssid list */ |
1011 | memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_ssidlist))__builtin_memset((&sc->sc_buf), (0), (sizeof(sc->sc_buf .sc_ssidlist))); |
1012 | sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid_len = |
1013 | ic->ic_des_esslen; |
1014 | if (ic->ic_des_esslen) |
1015 | memcpy(sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid,__builtin_memcpy((sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid ), (ic->ic_des_essid), (ic->ic_des_esslen)) |
1016 | ic->ic_des_essid, ic->ic_des_esslen)__builtin_memcpy((sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid ), (ic->ic_des_essid), (ic->ic_des_esslen)); |
1017 | an_swap16((u_int16_t *)&sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid, 16); |
1018 | if ((error = an_write_rid(sc, AN_RID_SSIDLIST0xFF11, &sc->sc_buf, |
1019 | sizeof(sc->sc_buf.sc_ssidlist)))) { |
1020 | printf("%s: failed to write ssid list\n", ifp->if_xname); |
1021 | an_stop(ifp, 1); |
1022 | return error; |
1023 | } |
1024 | |
1025 | /* Set the AP list */ |
1026 | memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_aplist))__builtin_memset((&sc->sc_buf), (0), (sizeof(sc->sc_buf .sc_aplist))); |
1027 | (void)an_write_rid(sc, AN_RID_APLIST0xFF12, &sc->sc_buf, |
1028 | sizeof(sc->sc_buf.sc_aplist)); |
1029 | |
1030 | /* Set the encapsulation */ |
1031 | for (i = 0; i < AN_ENCAP_NENTS8; i++) { |
1032 | sc->sc_buf.sc_encap.an_entry[i].an_ethertype = 0; |
1033 | sc->sc_buf.sc_encap.an_entry[i].an_action = |
1034 | AN_RXENCAP_RFC10240x0001 | AN_TXENCAP_RFC10240x0000; |
1035 | } |
1036 | (void)an_write_rid(sc, AN_RID_ENCAP0xFF14, &sc->sc_buf, |
1037 | sizeof(sc->sc_buf.sc_encap)); |
1038 | |
1039 | /* Set the WEP Keys */ |
1040 | if (ic->ic_flags & IEEE80211_F_WEPON0x00000100) |
1041 | an_write_wepkey(sc, AN_RID_WEP_VOLATILE0xFF15, sc->sc_wepkeys, |
1042 | sc->sc_tx_key); |
1043 | |
1044 | /* Set the configuration */ |
1045 | if ((error = an_write_rid(sc, AN_RID_GENCONFIG0xFF10, &sc->sc_config, |
1046 | sizeof(sc->sc_config)))) { |
1047 | printf("%s: failed to write config\n", ifp->if_xname); |
1048 | an_stop(ifp, 1); |
1049 | return error; |
1050 | } |
1051 | |
1052 | /* Enable the MAC */ |
1053 | if (an_cmd(sc, AN_CMD_ENABLE0x0001, 0)) { |
1054 | printf("%s: failed to enable MAC\n", sc->sc_dev.dv_xname); |
1055 | an_stop(ifp, 1); |
1056 | return ENXIO6; |
1057 | } |
1058 | if (ifp->if_flags & IFF_PROMISC0x100) |
1059 | an_cmd(sc, AN_CMD_SET_MODE0x0009, 0xffff); |
1060 | |
1061 | ifp->if_flags |= IFF_RUNNING0x40; |
1062 | ifq_clr_oactive(&ifp->if_snd); |
1063 | ic->ic_state = IEEE80211_S_INIT; |
1064 | if (ic->ic_opmode == IEEE80211_M_MONITOR) |
1065 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1)(((ic)->ic_newstate)((ic), (IEEE80211_S_RUN), (-1))); |
1066 | |
1067 | /* enable interrupts */ |
1068 | CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS)((sc->sc_iot)->write_2((sc->sc_ioh), (0x32), ((0x0001 | 0x0002 | 0x0004 | 0x0080)))); |
1069 | return 0; |
1070 | } |
1071 | |
1072 | void |
1073 | an_start(struct ifnet *ifp) |
1074 | { |
1075 | struct an_softc *sc = (struct an_softc *)ifp->if_softc; |
1076 | struct ieee80211com *ic = &sc->sc_ic; |
1077 | struct ieee80211_node *ni; |
1078 | struct ieee80211_frame *wh; |
1079 | struct an_txframe frmhdr; |
1080 | struct mbuf *m; |
1081 | u_int16_t len; |
1082 | int cur, fid; |
1083 | |
1084 | if (!sc->sc_enabled || sc->sc_invalid) { |
1085 | DPRINTF(("an_start: noop: enabled %d invalid %d\n", |
1086 | sc->sc_enabled, sc->sc_invalid)); |
1087 | return; |
1088 | } |
1089 | |
1090 | memset(&frmhdr, 0, sizeof(frmhdr))__builtin_memset((&frmhdr), (0), (sizeof(frmhdr))); |
1091 | cur = sc->sc_txnext; |
1092 | for (;;) { |
1093 | if (ic->ic_state != IEEE80211_S_RUN) { |
1094 | DPRINTF(("an_start: not running %d\n", ic->ic_state)); |
1095 | break; |
1096 | } |
1097 | m = ifq_deq_begin(&ifp->if_snd); |
1098 | if (m == NULL((void *)0)) { |
1099 | DPRINTF2(("an_start: no pending mbuf\n")); |
1100 | break; |
1101 | } |
1102 | if (sc->sc_txd[cur].d_inuse) { |
1103 | ifq_deq_rollback(&ifp->if_snd, m); |
1104 | DPRINTF2(("an_start: %x/%d busy\n", |
1105 | sc->sc_txd[cur].d_fid, cur)); |
1106 | ifq_set_oactive(&ifp->if_snd); |
1107 | break; |
1108 | } |
1109 | ifq_deq_commit(&ifp->if_snd, m); |
1110 | #if NBPFILTER1 > 0 |
1111 | if (ifp->if_bpf) |
1112 | bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT(1 << 1)); |
1113 | #endif |
1114 | if ((m = ieee80211_encap(ifp, m, &ni)) == NULL((void *)0)) { |
1115 | ifp->if_oerrorsif_data.ifi_oerrors++; |
1116 | continue; |
1117 | } |
1118 | if (ni != NULL((void *)0)) |
1119 | ieee80211_release_node(ic, ni); |
1120 | #if NBPFILTER1 > 0 |
1121 | if (ic->ic_rawbpf) |
1122 | bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT(1 << 1)); |
1123 | #endif |
1124 | |
1125 | wh = mtod(m, struct ieee80211_frame *)((struct ieee80211_frame *)((m)->m_hdr.mh_data)); |
1126 | if (ic->ic_flags & IEEE80211_F_WEPON0x00000100) |
1127 | wh->i_fc[1] |= IEEE80211_FC1_WEP0x40; |
1128 | m_copydata(m, 0, sizeof(struct ieee80211_frame), |
1129 | &frmhdr.an_whdr); |
1130 | an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2); |
1131 | |
1132 | /* insert payload length in front of llc/snap */ |
1133 | len = htons(m->m_pkthdr.len - sizeof(struct ieee80211_frame))(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len - sizeof(struct ieee80211_frame)) ? (__uint16_t)(((__uint16_t )(m->M_dat.MH.MH_pkthdr.len - sizeof(struct ieee80211_frame )) & 0xffU) << 8 | ((__uint16_t)(m->M_dat.MH.MH_pkthdr .len - sizeof(struct ieee80211_frame)) & 0xff00U) >> 8) : __swap16md(m->M_dat.MH.MH_pkthdr.len - sizeof(struct ieee80211_frame))); |
1134 | m_adj(m, sizeof(struct ieee80211_frame) - sizeof(len)); |
1135 | if (mtod(m, u_long)((u_long)((m)->m_hdr.mh_data)) & 0x01) |
1136 | memcpy(mtod(m, caddr_t), &len, sizeof(len))__builtin_memcpy((((caddr_t)((m)->m_hdr.mh_data))), (& len), (sizeof(len))); |
1137 | else |
1138 | *mtod(m, u_int16_t *)((u_int16_t *)((m)->m_hdr.mh_data)) = len; |
1139 | |
1140 | /* |
1141 | * XXX Aironet firmware apparently convert the packet |
1142 | * with longer than 1500 bytes in length into LLC/SNAP. |
1143 | * If we have 1500 bytes in ethernet payload, it is |
1144 | * 1508 bytes including LLC/SNAP and will be inserted |
1145 | * additional LLC/SNAP header with 1501-1508 in its |
1146 | * ethertype !! |
1147 | * So we skip LLC/SNAP header and force firmware to |
1148 | * convert it to LLC/SNAP again. |
1149 | */ |
1150 | m_adj(m, sizeof(struct llc)); |
1151 | |
1152 | frmhdr.an_tx_ctl = AN_TXCTL_80211(0x0002|0x0004|0x0008| 0x0010|0x0020); |
1153 | frmhdr.an_tx_payload_len = m->m_pkthdrM_dat.MH.MH_pkthdr.len; |
1154 | frmhdr.an_gaplen = AN_TXGAP_802_116; |
1155 | |
1156 | if (ic->ic_fixed_rate != -1) |
1157 | frmhdr.an_tx_rate = |
1158 | ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[ |
1159 | ic->ic_fixed_rate] & IEEE80211_RATE_VAL0x7f; |
1160 | else |
1161 | frmhdr.an_tx_rate = 0; |
1162 | |
1163 | if (sizeof(frmhdr) + AN_TXGAP_802_116 + sizeof(len) + |
1164 | m->m_pkthdrM_dat.MH.MH_pkthdr.len > AN_TX_MAX_LEN(sizeof(struct an_txframe) + 2 + 1518)) { |
1165 | ifp->if_oerrorsif_data.ifi_oerrors++; |
1166 | m_freem(m); |
1167 | continue; |
1168 | } |
1169 | |
1170 | #if NBPFILTER1 > 0 |
1171 | if (sc->sc_drvbpf) { |
1172 | struct mbuf mb; |
1173 | struct an_tx_radiotap_header *tap = &sc->sc_txtapsc_txtapu.tap; |
1174 | |
1175 | tap->at_rate = |
1176 | ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate]; |
1177 | tap->at_chan_freq = |
1178 | ic->ic_bss->ni_chan->ic_freq; |
1179 | tap->at_chan_flags = |
1180 | ic->ic_bss->ni_chan->ic_flags; |
1181 | |
1182 | mb.m_datam_hdr.mh_data = (caddr_t)tap; |
1183 | mb.m_lenm_hdr.mh_len = sizeof(sc->sc_txtapu); |
1184 | mb.m_nextm_hdr.mh_next = m; |
1185 | mb.m_nextpktm_hdr.mh_nextpkt = NULL((void *)0); |
1186 | mb.m_typem_hdr.mh_type = 0; |
1187 | mb.m_flagsm_hdr.mh_flags = 0; |
1188 | bpf_mtap(sc->sc_drvbpf, m, BPF_DIRECTION_OUT(1 << 1)); |
1189 | } |
1190 | #endif |
1191 | |
1192 | fid = sc->sc_txd[cur].d_fid; |
1193 | if (an_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) { |
1194 | ifp->if_oerrorsif_data.ifi_oerrors++; |
1195 | m_freem(m); |
1196 | continue; |
1197 | } |
1198 | /* dummy write to avoid seek. */ |
1199 | an_write_bap(sc, fid, -1, &frmhdr, AN_TXGAP_802_116); |
1200 | an_mwrite_bap(sc, fid, -1, m, m->m_pkthdrM_dat.MH.MH_pkthdr.len); |
1201 | m_freem(m); |
1202 | |
1203 | DPRINTF2(("an_start: send %d byte via %x/%d\n", |
1204 | ntohs(len) + sizeof(struct ieee80211_frame), |
1205 | fid, cur)); |
1206 | sc->sc_txd[cur].d_inuse = 1; |
1207 | if (an_cmd(sc, AN_CMD_TX0x000B, fid)) { |
1208 | printf("%s: xmit failed\n", ifp->if_xname); |
1209 | sc->sc_txd[cur].d_inuse = 0; |
1210 | continue; |
1211 | } |
1212 | sc->sc_tx_timer = 5; |
1213 | ifp->if_timer = 1; |
1214 | AN_INC(cur, AN_TX_RING_CNT)(cur) = (cur + 1) % 4; |
1215 | sc->sc_txnext = cur; |
1216 | } |
1217 | } |
1218 | |
1219 | void |
1220 | an_stop(struct ifnet *ifp, int disable) |
1221 | { |
1222 | struct an_softc *sc = ifp->if_softc; |
1223 | int i, s; |
1224 | |
1225 | if (!sc->sc_enabled) |
1226 | return; |
1227 | |
1228 | DPRINTF(("an_stop: disable %d\n", disable)); |
1229 | |
1230 | s = splnet()splraise(0x7); |
1231 | ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1)(((&sc->sc_ic)->ic_newstate)((&sc->sc_ic), ( IEEE80211_S_INIT), (-1))); |
1232 | if (!sc->sc_invalid) { |
1233 | an_cmd(sc, AN_CMD_FORCE_SYNCLOSS0x0003, 0); |
1234 | CSR_WRITE_2(sc, AN_INT_EN, 0)((sc->sc_iot)->write_2((sc->sc_ioh), (0x32), (0))); |
1235 | an_cmd(sc, AN_CMD_DISABLE0x0002, 0); |
1236 | |
1237 | for (i = 0; i < AN_TX_RING_CNT4; i++) |
1238 | an_cmd(sc, AN_CMD_DEALLOC_MEM0x000C, sc->sc_txd[i].d_fid); |
1239 | } |
1240 | |
1241 | sc->sc_tx_timer = 0; |
1242 | ifp->if_timer = 0; |
1243 | ifp->if_flags &= ~IFF_RUNNING0x40; |
1244 | ifq_clr_oactive(&ifp->if_snd); |
1245 | |
1246 | if (disable) { |
1247 | if (sc->sc_disable) |
1248 | (*sc->sc_disable)(sc); |
1249 | sc->sc_enabled = 0; |
1250 | } |
1251 | splx(s)spllower(s); |
1252 | } |
1253 | |
1254 | void |
1255 | an_watchdog(struct ifnet *ifp) |
1256 | { |
1257 | struct an_softc *sc = ifp->if_softc; |
1258 | |
1259 | if (!sc->sc_enabled) |
1260 | return; |
1261 | |
1262 | if (sc->sc_tx_timer) { |
1263 | if (--sc->sc_tx_timer == 0) { |
1264 | printf("%s: device timeout\n", ifp->if_xname); |
1265 | ifp->if_oerrorsif_data.ifi_oerrors++; |
1266 | an_init(ifp); |
1267 | return; |
1268 | } |
1269 | ifp->if_timer = 1; |
1270 | } |
1271 | ieee80211_watchdog(ifp); |
1272 | } |
1273 | |
1274 | /* TBD factor with ieee80211_media_change */ |
1275 | int |
1276 | an_media_change(struct ifnet *ifp) |
1277 | { |
1278 | struct an_softc *sc = ifp->if_softc; |
1279 | struct ieee80211com *ic = &sc->sc_ic; |
1280 | struct ifmedia_entry *ime; |
1281 | enum ieee80211_opmode newmode; |
1282 | int i, rate, error = 0; |
1283 | |
1284 | ime = ic->ic_media.ifm_cur; |
1285 | if (IFM_SUBTYPE(ime->ifm_media)((ime->ifm_media) & 0x00000000000000ffULL) == IFM_AUTO0ULL) { |
1286 | i = -1; |
1287 | } else { |
1288 | struct ieee80211_rateset *rs = |
1289 | &ic->ic_sup_rates[IEEE80211_MODE_11B]; |
1290 | rate = ieee80211_media2rate(ime->ifm_media); |
1291 | if (rate == 0) |
1292 | return EINVAL22; |
1293 | for (i = 0; i < rs->rs_nrates; i++) { |
1294 | if ((rs->rs_rates[i] & IEEE80211_RATE_VAL0x7f) == rate) |
1295 | break; |
1296 | } |
1297 | if (i == rs->rs_nrates) |
1298 | return EINVAL22; |
1299 | } |
1300 | if (ic->ic_fixed_rate != i) { |
1301 | ic->ic_fixed_rate = i; |
1302 | error = ENETRESET52; |
1303 | } |
1304 | |
1305 | #ifndef IEEE80211_STA_ONLY |
1306 | if (ime->ifm_media & IFM_IEEE80211_ADHOC0x0000000000010000ULL) |
1307 | newmode = IEEE80211_M_IBSS; |
1308 | else if (ime->ifm_media & IFM_IEEE80211_HOSTAP0x0000000000020000ULL) |
1309 | newmode = IEEE80211_M_HOSTAP; |
1310 | else |
1311 | #endif |
1312 | if (ime->ifm_media & IFM_IEEE80211_MONITOR0x0000000000100000ULL) |
1313 | newmode = IEEE80211_M_MONITOR; |
1314 | else |
1315 | newmode = IEEE80211_M_STA; |
1316 | if (ic->ic_opmode != newmode) { |
1317 | ic->ic_opmode = newmode; |
1318 | error = ENETRESET52; |
1319 | } |
1320 | if (error == ENETRESET52) { |
1321 | if (sc->sc_enabled) |
1322 | error = an_init(ifp); |
1323 | else |
1324 | error = 0; |
1325 | } |
1326 | ifp->if_baudrateif_data.ifi_baudrate = ifmedia_baudrate(ic->ic_media.ifm_cur->ifm_media); |
1327 | |
1328 | return error; |
1329 | } |
1330 | |
1331 | void |
1332 | an_media_status(struct ifnet *ifp, struct ifmediareq *imr) |
1333 | { |
1334 | struct an_softc *sc = ifp->if_softc; |
1335 | struct ieee80211com *ic = &sc->sc_ic; |
1336 | int rate, buflen; |
1337 | |
1338 | if (sc->sc_enabled == 0) { |
1339 | imr->ifm_active = IFM_IEEE802110x0000000000000400ULL | IFM_NONE2ULL; |
1340 | imr->ifm_status = 0; |
1341 | return; |
1342 | } |
1343 | |
1344 | imr->ifm_status = IFM_AVALID0x0000000000000001ULL; |
1345 | imr->ifm_active = IFM_IEEE802110x0000000000000400ULL; |
1346 | if (ic->ic_state == IEEE80211_S_RUN) |
1347 | imr->ifm_status |= IFM_ACTIVE0x0000000000000002ULL; |
1348 | buflen = sizeof(sc->sc_buf); |
1349 | if (ic->ic_fixed_rate != -1) |
1350 | rate = ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[ |
1351 | ic->ic_fixed_rate] & IEEE80211_RATE_VAL0x7f; |
1352 | else if (an_read_rid(sc, AN_RID_STATUS0xFF50, &sc->sc_buf, &buflen) != 0) |
1353 | rate = 0; |
1354 | else |
1355 | rate = sc->sc_buf.sc_status.an_current_tx_rate; |
1356 | imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B); |
1357 | switch (ic->ic_opmode) { |
1358 | case IEEE80211_M_STA: |
1359 | break; |
1360 | #ifndef IEEE80211_STA_ONLY |
1361 | case IEEE80211_M_IBSS: |
1362 | imr->ifm_active |= IFM_IEEE80211_ADHOC0x0000000000010000ULL; |
1363 | break; |
1364 | case IEEE80211_M_HOSTAP: |
1365 | imr->ifm_active |= IFM_IEEE80211_HOSTAP0x0000000000020000ULL; |
1366 | break; |
1367 | #endif |
1368 | case IEEE80211_M_MONITOR: |
1369 | imr->ifm_active |= IFM_IEEE80211_MONITOR0x0000000000100000ULL; |
1370 | break; |
1371 | default: |
1372 | break; |
1373 | } |
1374 | } |
1375 | |
1376 | int |
1377 | an_set_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey) |
1378 | { |
1379 | int error; |
1380 | struct ieee80211com *ic = &sc->sc_ic; |
1381 | u_int16_t prevauth; |
1382 | |
1383 | error = 0; |
1384 | prevauth = sc->sc_config.an_authtype; |
1385 | |
1386 | switch (nwkey->i_wepon) { |
1387 | case IEEE80211_NWKEY_OPEN0: |
1388 | sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN0x0001; |
1389 | ic->ic_flags &= ~IEEE80211_F_WEPON0x00000100; |
1390 | break; |
1391 | |
1392 | case IEEE80211_NWKEY_WEP1: |
1393 | case IEEE80211_NWKEY_WEP1 | IEEE80211_NWKEY_PERSIST0x100: |
1394 | error = an_set_nwkey_wep(sc, nwkey); |
1395 | if (error == 0 || error == ENETRESET52) { |
1396 | sc->sc_config.an_authtype = |
1397 | AN_AUTHTYPE_OPEN0x0001 | AN_AUTHTYPE_PRIVACY_IN_USE0x0100; |
1398 | ic->ic_flags |= IEEE80211_F_WEPON0x00000100; |
1399 | } |
1400 | break; |
1401 | |
1402 | default: |
1403 | error = EINVAL22; |
1404 | break; |
1405 | } |
1406 | if (error == 0 && prevauth != sc->sc_config.an_authtype) |
1407 | error = ENETRESET52; |
1408 | return error; |
1409 | } |
1410 | |
1411 | int |
1412 | an_set_nwkey_wep(struct an_softc *sc, struct ieee80211_nwkey *nwkey) |
1413 | { |
1414 | int i, txkey, anysetkey, needreset, error; |
1415 | struct an_wepkey keys[IEEE80211_WEP_NKID4]; |
1416 | |
1417 | error = 0; |
1418 | memset(keys, 0, sizeof(keys))__builtin_memset((keys), (0), (sizeof(keys))); |
1419 | anysetkey = needreset = 0; |
1420 | |
1421 | /* load argument and sanity check */ |
1422 | for (i = 0; i < IEEE80211_WEP_NKID4; i++) { |
1423 | keys[i].an_wep_keylen = nwkey->i_key[i].i_keylen; |
1424 | if (keys[i].an_wep_keylen < 0) |
1425 | continue; |
1426 | if (keys[i].an_wep_keylen != 0 && |
1427 | keys[i].an_wep_keylen < IEEE80211_WEP_KEYLEN5) |
1428 | return EINVAL22; |
1429 | if (keys[i].an_wep_keylen > sizeof(keys[i].an_wep_key)) |
1430 | return EINVAL22; |
1431 | if ((error = copyin(nwkey->i_key[i].i_keydat, |
1432 | keys[i].an_wep_key, keys[i].an_wep_keylen)) != 0) |
1433 | return error; |
1434 | anysetkey++; |
1435 | } |
1436 | txkey = nwkey->i_defkid - 1; |
1437 | if (txkey >= 0) { |
1438 | if (txkey >= IEEE80211_WEP_NKID4) |
1439 | return EINVAL22; |
1440 | /* default key must have a valid value */ |
1441 | if (keys[txkey].an_wep_keylen == 0 || |
1442 | (keys[txkey].an_wep_keylen < 0 && |
1443 | sc->sc_perskeylen[txkey] == 0)) |
1444 | return EINVAL22; |
1445 | anysetkey++; |
1446 | } |
1447 | DPRINTF(("an_set_nwkey_wep: %s: %sold(%d:%d,%d,%d,%d) " |
1448 | "pers(%d:%d,%d,%d,%d) new(%d:%d,%d,%d,%d)\n", |
1449 | sc->sc_dev.dv_xname, |
1450 | ((nwkey->i_wepon & IEEE80211_NWKEY_PERSIST) ? "persist: " : ""), |
1451 | sc->sc_tx_key, |
1452 | sc->sc_wepkeys[0].an_wep_keylen, sc->sc_wepkeys[1].an_wep_keylen, |
1453 | sc->sc_wepkeys[2].an_wep_keylen, sc->sc_wepkeys[3].an_wep_keylen, |
1454 | sc->sc_tx_perskey, |
1455 | sc->sc_perskeylen[0], sc->sc_perskeylen[1], |
1456 | sc->sc_perskeylen[2], sc->sc_perskeylen[3], |
1457 | txkey, |
1458 | keys[0].an_wep_keylen, keys[1].an_wep_keylen, |
1459 | keys[2].an_wep_keylen, keys[3].an_wep_keylen)); |
1460 | if (!(nwkey->i_wepon & IEEE80211_NWKEY_PERSIST0x100)) { |
1461 | /* set temporary keys */ |
1462 | sc->sc_tx_key = txkey; |
1463 | for (i = 0; i < IEEE80211_WEP_NKID4; i++) { |
1464 | if (keys[i].an_wep_keylen < 0) |
1465 | continue; |
1466 | memcpy(&sc->sc_wepkeys[i], &keys[i], sizeof(keys[i]))__builtin_memcpy((&sc->sc_wepkeys[i]), (&keys[i]), (sizeof(keys[i]))); |
1467 | } |
1468 | } else { |
1469 | /* set persist keys */ |
1470 | if (anysetkey) { |
1471 | /* prepare to write nvram */ |
1472 | if (!sc->sc_enabled) { |
1473 | if (sc->sc_enable) |
1474 | (*sc->sc_enable)(sc); |
1475 | an_wait(sc); |
1476 | sc->sc_enabled = 1; |
1477 | error = an_write_wepkey(sc, |
1478 | AN_RID_WEP_PERSISTENT0xFF16, keys, txkey); |
1479 | if (sc->sc_disable) |
1480 | (*sc->sc_disable)(sc); |
1481 | sc->sc_enabled = 0; |
1482 | } else { |
1483 | an_cmd(sc, AN_CMD_DISABLE0x0002, 0); |
1484 | error = an_write_wepkey(sc, |
1485 | AN_RID_WEP_PERSISTENT0xFF16, keys, txkey); |
1486 | an_cmd(sc, AN_CMD_ENABLE0x0001, 0); |
1487 | } |
1488 | if (error) |
1489 | return error; |
1490 | } |
1491 | if (txkey >= 0) |
1492 | sc->sc_tx_perskey = txkey; |
1493 | if (sc->sc_tx_key >= 0) { |
1494 | sc->sc_tx_key = -1; |
1495 | needreset++; |
1496 | } |
1497 | for (i = 0; i < IEEE80211_WEP_NKID4; i++) { |
1498 | if (sc->sc_wepkeys[i].an_wep_keylen >= 0) { |
1499 | memset(&sc->sc_wepkeys[i].an_wep_key, 0,__builtin_memset((&sc->sc_wepkeys[i].an_wep_key), (0), (sizeof(sc->sc_wepkeys[i].an_wep_key))) |
1500 | sizeof(sc->sc_wepkeys[i].an_wep_key))__builtin_memset((&sc->sc_wepkeys[i].an_wep_key), (0), (sizeof(sc->sc_wepkeys[i].an_wep_key))); |
1501 | sc->sc_wepkeys[i].an_wep_keylen = -1; |
1502 | needreset++; |
1503 | } |
1504 | if (keys[i].an_wep_keylen >= 0) |
1505 | sc->sc_perskeylen[i] = keys[i].an_wep_keylen; |
1506 | } |
1507 | } |
1508 | if (needreset) { |
1509 | /* firmware restart to reload persistent key */ |
1510 | an_reset(sc); |
1511 | } |
1512 | if (anysetkey || needreset) |
1513 | error = ENETRESET52; |
1514 | return error; |
1515 | } |
1516 | |
1517 | int |
1518 | an_get_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey) |
1519 | { |
1520 | int i; |
1521 | |
1522 | if (sc->sc_config.an_authtype & AN_AUTHTYPE_LEAP0x1000) |
1523 | nwkey->i_wepon = IEEE80211_NWKEY_EAP2; |
1524 | else if (sc->sc_config.an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE0x0100) |
1525 | nwkey->i_wepon = IEEE80211_NWKEY_WEP1; |
1526 | else |
1527 | nwkey->i_wepon = IEEE80211_NWKEY_OPEN0; |
1528 | if (sc->sc_tx_key == -1) |
1529 | nwkey->i_defkid = sc->sc_tx_perskey + 1; |
1530 | else |
1531 | nwkey->i_defkid = sc->sc_tx_key + 1; |
1532 | if (nwkey->i_key[0].i_keydat == NULL((void *)0)) |
1533 | return 0; |
1534 | for (i = 0; i < IEEE80211_WEP_NKID4; i++) { |
1535 | if (nwkey->i_key[i].i_keydat == NULL((void *)0)) |
1536 | continue; |
1537 | /* do not show any keys to userland */ |
1538 | return EPERM1; |
1539 | } |
1540 | return 0; |
1541 | } |
1542 | |
1543 | int |
1544 | an_write_wepkey(struct an_softc *sc, int type, struct an_wepkey *keys, int kid) |
1545 | { |
1546 | int i, error; |
1547 | struct an_rid_wepkey *akey; |
1548 | |
1549 | error = 0; |
1550 | akey = &sc->sc_buf.sc_wepkey; |
1551 | for (i = 0; i < IEEE80211_WEP_NKID4; i++) { |
1552 | memset(akey, 0, sizeof(struct an_rid_wepkey))__builtin_memset((akey), (0), (sizeof(struct an_rid_wepkey))); |
1553 | if (keys[i].an_wep_keylen < 0 || |
1554 | keys[i].an_wep_keylen > sizeof(akey->an_key)) |
1555 | continue; |
1556 | akey->an_key_len = keys[i].an_wep_keylen; |
1557 | akey->an_key_index = i; |
1558 | akey->an_mac_addr[0] = 1; /* default mac */ |
1559 | an_swap16((u_int16_t *)&akey->an_mac_addr, 3); |
1560 | memcpy(akey->an_key, keys[i].an_wep_key, keys[i].an_wep_keylen)__builtin_memcpy((akey->an_key), (keys[i].an_wep_key), (keys [i].an_wep_keylen)); |
1561 | an_swap16((u_int16_t *)&akey->an_key, 8); |
1562 | if ((error = an_write_rid(sc, type, akey, sizeof(*akey))) != 0) |
1563 | return error; |
1564 | } |
1565 | if (kid >= 0) { |
1566 | memset(akey, 0, sizeof(struct an_rid_wepkey))__builtin_memset((akey), (0), (sizeof(struct an_rid_wepkey))); |
1567 | akey->an_key_index = 0xffff; |
1568 | akey->an_mac_addr[0] = kid; |
1569 | an_swap16((u_int16_t *)&akey->an_mac_addr, 3); |
1570 | akey->an_key_len = 0; |
1571 | memset(akey->an_key, 0, sizeof(akey->an_key))__builtin_memset((akey->an_key), (0), (sizeof(akey->an_key ))); |
1572 | error = an_write_rid(sc, type, akey, sizeof(*akey)); |
1573 | } |
1574 | return error; |
1575 | } |
1576 | |
1577 | int |
1578 | an_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) |
1579 | { |
1580 | struct an_softc *sc = ic->ic_softcic_ac.ac_if.if_softc; |
1581 | struct ieee80211_node *ni = ic->ic_bss; |
1582 | enum ieee80211_state ostate; |
1583 | int buflen; |
1584 | |
1585 | ostate = ic->ic_state; |
1586 | DPRINTF(("an_newstate: %s -> %s\n", ieee80211_state_name[ostate], |
1587 | ieee80211_state_name[nstate])); |
1588 | |
1589 | switch (nstate) { |
1590 | case IEEE80211_S_INIT: |
1591 | ic->ic_flags &= ~IEEE80211_F_IBSSON0x00000200; |
1592 | return (*sc->sc_newstate)(ic, nstate, arg); |
1593 | |
1594 | case IEEE80211_S_RUN: |
1595 | buflen = sizeof(sc->sc_buf); |
1596 | an_read_rid(sc, AN_RID_STATUS0xFF50, &sc->sc_buf, &buflen); |
1597 | an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_cur_bssid, 3); |
1598 | an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_ssid, 16); |
1599 | IEEE80211_ADDR_COPY(ni->ni_bssid,__builtin_memcpy((ni->ni_bssid), (sc->sc_buf.sc_status. an_cur_bssid), (6)) |
1600 | sc->sc_buf.sc_status.an_cur_bssid)__builtin_memcpy((ni->ni_bssid), (sc->sc_buf.sc_status. an_cur_bssid), (6)); |
1601 | IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid)__builtin_memcpy((ni->ni_macaddr), (ni->ni_bssid), (6)); |
1602 | ni->ni_chan = &ic->ic_channels[ |
1603 | sc->sc_buf.sc_status.an_cur_channel]; |
1604 | ni->ni_esslen = sc->sc_buf.sc_status.an_ssidlen; |
1605 | if (ni->ni_esslen > IEEE80211_NWID_LEN32) |
1606 | ni->ni_esslen = IEEE80211_NWID_LEN32; /*XXX*/ |
1607 | memcpy(ni->ni_essid, sc->sc_buf.sc_status.an_ssid,__builtin_memcpy((ni->ni_essid), (sc->sc_buf.sc_status. an_ssid), (ni->ni_esslen)) |
1608 | ni->ni_esslen)__builtin_memcpy((ni->ni_essid), (sc->sc_buf.sc_status. an_ssid), (ni->ni_esslen)); |
1609 | ni->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B]; /*XXX*/ |
1610 | if (ic->ic_ific_ac.ac_if.if_flags & IFF_DEBUG0x4) { |
1611 | printf("%s: ", sc->sc_dev.dv_xname); |
1612 | if (ic->ic_opmode == IEEE80211_M_STA) |
1613 | printf("associated "); |
1614 | else |
1615 | printf("synchronized "); |
1616 | printf("with %s ssid ", ether_sprintf(ni->ni_bssid)); |
1617 | ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); |
1618 | printf(" channel %u start %uMb\n", |
1619 | sc->sc_buf.sc_status.an_cur_channel, |
1620 | sc->sc_buf.sc_status.an_current_tx_rate/2); |
1621 | } |
1622 | break; |
1623 | |
1624 | default: |
1625 | break; |
1626 | } |
1627 | ic->ic_state = nstate; |
1628 | /* skip standard ieee80211 handling */ |
1629 | return 0; |
1630 | } |
1631 | |
1632 | int |
1633 | an_detach(struct an_softc *sc) |
1634 | { |
1635 | struct ifnet *ifp = &sc->sc_ic.ic_ific_ac.ac_if; |
1636 | int s; |
1637 | |
1638 | if (!sc->sc_attached) |
1639 | return 0; |
1640 | |
1641 | s = splnet()splraise(0x7); |
1642 | sc->sc_invalid = 1; |
1643 | an_stop(ifp, 1); |
1644 | ifmedia_delete_instance(&sc->sc_ic.ic_media, IFM_INST_ANY((uint64_t) -1)); |
1645 | ieee80211_ifdetach(ifp); |
1646 | if_detach(ifp); |
1647 | splx(s)spllower(s); |
1648 | return 0; |
1649 | } |
1650 |