wi.c revision 1.84 1 /* $NetBSD: wi.c,v 1.84 2002/09/23 14:31:27 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1997, 1998, 1999
5 * Bill Paul <wpaul (at) 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
35 /*
36 * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for NetBSD.
37 *
38 * Original FreeBSD driver written by Bill Paul <wpaul (at) ctr.columbia.edu>
39 * Electrical Engineering Department
40 * Columbia University, New York City
41 */
42
43 /*
44 * The WaveLAN/IEEE adapter is the second generation of the WaveLAN
45 * from Lucent. Unlike the older cards, the new ones are programmed
46 * entirely via a firmware-driven controller called the Hermes.
47 * Unfortunately, Lucent will not release the Hermes programming manual
48 * without an NDA (if at all). What they do release is an API library
49 * called the HCF (Hardware Control Functions) which is supposed to
50 * do the device-specific operations of a device driver for you. The
51 * publically available version of the HCF library (the 'HCF Light') is
52 * a) extremely gross, b) lacks certain features, particularly support
53 * for 802.11 frames, and c) is contaminated by the GNU Public License.
54 *
55 * This driver does not use the HCF or HCF Light at all. Instead, it
56 * programs the Hermes controller directly, using information gleaned
57 * from the HCF Light code and corresponding documentation.
58 *
59 * This driver supports both the PCMCIA and ISA versions of the
60 * WaveLAN/IEEE cards. Note however that the ISA card isn't really
61 * anything of the sort: it's actually a PCMCIA bridge adapter
62 * that fits into an ISA slot, into which a PCMCIA WaveLAN card is
63 * inserted. Consequently, you need to use the pccard support for
64 * both the ISA and PCMCIA adapters.
65 */
66
67 /*
68 * FreeBSD driver ported to NetBSD by Bill Sommerfeld in the back of the
69 * Oslo IETF plenary meeting.
70 */
71
72 #include <sys/cdefs.h>
73 __KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.84 2002/09/23 14:31:27 thorpej Exp $");
74
75 #define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */
76 #define WI_HERMES_STATS_WAR /* Work around stats counter bug. */
77
78 #include "bpfilter.h"
79
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/callout.h>
83 #include <sys/device.h>
84 #include <sys/socket.h>
85 #include <sys/mbuf.h>
86 #include <sys/ioctl.h>
87 #include <sys/kernel.h> /* for hz */
88 #include <sys/proc.h>
89
90 #include <net/if.h>
91 #include <net/if_dl.h>
92 #include <net/if_llc.h>
93 #include <net/if_media.h>
94 #include <net/if_ether.h>
95 #include <net/if_ieee80211.h>
96
97 #if NBPFILTER > 0
98 #include <net/bpf.h>
99 #include <net/bpfdesc.h>
100 #endif
101
102 #include <machine/bus.h>
103
104 #include <dev/ic/wi_ieee.h>
105 #include <dev/ic/wireg.h>
106 #include <dev/ic/wivar.h>
107
108 static void wi_tap_802_11_plus __P((struct wi_softc *, struct mbuf *));
109 static void wi_tap_802_3 __P((struct wi_softc *, struct mbuf *,
110 struct wi_frame *));
111 static void wi_reset __P((struct wi_softc *));
112 static int wi_ioctl __P((struct ifnet *, u_long, caddr_t));
113 static void wi_start __P((struct ifnet *));
114 static void wi_watchdog __P((struct ifnet *));
115 static int wi_init __P((struct ifnet *));
116 static void wi_stop __P((struct ifnet *, int));
117 static void wi_rxeof __P((struct wi_softc *));
118 static void wi_txeof __P((struct wi_softc *, int));
119 static void wi_update_stats __P((struct wi_softc *));
120 static void wi_setmulti __P((struct wi_softc *));
121
122 static int wi_cmd __P((struct wi_softc *, int, int, int, int));
123 static int wi_read_record __P((struct wi_softc *, struct wi_ltv_gen *));
124 static int wi_write_record __P((struct wi_softc *, struct wi_ltv_gen *));
125 static int wi_read_data __P((struct wi_softc *, int,
126 int, caddr_t, int));
127 #if defined(OPTIMIZE_RW_DATA)
128 static void wi_rewind __P((struct wi_softc *));
129 #endif
130 static int wi_write_data __P((struct wi_softc *, int,
131 int, caddr_t, int));
132 static int wi_seek __P((struct wi_softc *, int, int, int));
133 static int wi_alloc_nicmem __P((struct wi_softc *, int, int *));
134 static void wi_inquire __P((void *));
135 static void wi_wait_scan __P((void *));
136 static int wi_setdef __P((struct wi_softc *, struct wi_req *));
137 static int wi_getdef __P((struct wi_softc *, struct wi_req *));
138
139 static int wi_media_change __P((struct ifnet *));
140 static void wi_media_status __P((struct ifnet *, struct ifmediareq *));
141
142 static void wi_get_id __P((struct wi_softc *));
143
144 static int wi_set_ssid __P((struct ieee80211_nwid *, u_int8_t *, int));
145 static void wi_request_fill_ssid __P((struct wi_req *,
146 struct ieee80211_nwid *));
147 static int wi_write_ssid __P((struct wi_softc *, int, struct wi_req *,
148 struct ieee80211_nwid *));
149 static int wi_set_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *));
150 static int wi_get_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *));
151 static int wi_sync_media __P((struct wi_softc *, int, int));
152 static int wi_set_pm __P((struct wi_softc *, struct ieee80211_power *));
153 static int wi_get_pm __P((struct wi_softc *, struct ieee80211_power *));
154 static int wi_get_channel __P((struct wi_softc *, struct ieee80211_channel *));
155 static int wi_set_channel __P((struct wi_softc *, struct ieee80211_channel *));
156 static int wi_join_bss __P((struct wi_softc *));
157
158 struct wi_card_ident wi_card_ident[] = {
159 /* CARD_ID CARD_NAME FIRM_TYPE */
160 { WI_NIC_LUCENT_ID, WI_NIC_LUCENT_STR, WI_LUCENT },
161 { WI_NIC_SONY_ID, WI_NIC_SONY_STR, WI_LUCENT },
162 { WI_NIC_LUCENT_EMB_ID, WI_NIC_LUCENT_EMB_STR, WI_LUCENT },
163 { WI_NIC_EVB2_ID, WI_NIC_EVB2_STR, WI_INTERSIL },
164 { WI_NIC_HWB3763_ID, WI_NIC_HWB3763_STR, WI_INTERSIL },
165 { WI_NIC_HWB3163_ID, WI_NIC_HWB3163_STR, WI_INTERSIL },
166 { WI_NIC_HWB3163B_ID, WI_NIC_HWB3163B_STR, WI_INTERSIL },
167 { WI_NIC_EVB3_ID, WI_NIC_EVB3_STR, WI_INTERSIL },
168 { WI_NIC_HWB1153_ID, WI_NIC_HWB1153_STR, WI_INTERSIL },
169 { WI_NIC_P2_SST_ID, WI_NIC_P2_SST_STR, WI_INTERSIL },
170 { WI_NIC_EVB2_SST_ID, WI_NIC_EVB2_SST_STR, WI_INTERSIL },
171 { WI_NIC_3842_EVA_ID, WI_NIC_3842_EVA_STR, WI_INTERSIL },
172 { WI_NIC_3842_PCMCIA_AMD_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
173 { WI_NIC_3842_PCMCIA_SST_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
174 { WI_NIC_3842_PCMCIA_ATM_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
175 { WI_NIC_3842_MINI_AMD_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL },
176 { WI_NIC_3842_MINI_SST_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL },
177 { WI_NIC_3842_MINI_ATM_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL },
178 { WI_NIC_3842_PCI_AMD_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL },
179 { WI_NIC_3842_PCI_SST_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL },
180 { WI_NIC_3842_PCI_ATM_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL },
181 { WI_NIC_P3_PCMCIA_AMD_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL },
182 { WI_NIC_P3_PCMCIA_SST_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL },
183 { WI_NIC_P3_MINI_AMD_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL },
184 { WI_NIC_P3_MINI_SST_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL },
185 { 0, NULL, 0 },
186 };
187
188 static const u_int8_t zero_bssid[6] = {0, 0, 0, 0, 0, 0};
189
190 int
191 wi_attach(sc)
192 struct wi_softc *sc;
193 {
194 struct ifnet *ifp = sc->sc_ifp;
195 const char *sep = "";
196 int i, nrate;
197 u_int8_t *r;
198 struct wi_ltv_macaddr mac;
199 struct wi_ltv_gen gen;
200 struct wi_ltv_str rate;
201 static const u_int8_t empty_macaddr[ETHER_ADDR_LEN] = {
202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
203 };
204 int s;
205
206 s = splnet();
207
208 callout_init(&sc->wi_inquire_ch);
209 callout_init(&sc->wi_scan_sh);
210
211 /* Make sure interrupts are disabled. */
212 CSR_WRITE_2(sc, WI_INT_EN, 0);
213 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
214
215 /* Reset the NIC. */
216 wi_reset(sc);
217
218 memset(&mac, 0, sizeof(mac));
219 /* Read the station address. */
220 mac.wi_type = WI_RID_MAC_NODE;
221 mac.wi_len = 4;
222 wi_read_record(sc, (struct wi_ltv_gen *)&mac);
223 memcpy(sc->sc_macaddr, mac.wi_mac_addr, ETHER_ADDR_LEN);
224
225 /*
226 * Check if we got anything meaningful.
227 *
228 * Is it really enough just checking against null ethernet address?
229 * Or, check against possible vendor? XXX.
230 */
231 if (memcmp(sc->sc_macaddr, empty_macaddr, ETHER_ADDR_LEN) == 0) {
232 printf("could not get mac address, attach failed\n");
233 splx(s);
234 return 1;
235 }
236
237 printf(" 802.11 address %s\n", ether_sprintf(sc->sc_macaddr));
238
239 /* Read NIC identification */
240 wi_get_id(sc);
241
242 memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
243 ifp->if_softc = sc;
244 ifp->if_start = wi_start;
245 ifp->if_ioctl = wi_ioctl;
246 ifp->if_watchdog = wi_watchdog;
247 ifp->if_init = wi_init;
248 ifp->if_stop = wi_stop;
249 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
250 #ifdef IFF_NOTRAILERS
251 ifp->if_flags |= IFF_NOTRAILERS;
252 #endif
253 IFQ_SET_READY(&ifp->if_snd);
254
255 (void)wi_set_ssid(&sc->wi_nodeid, WI_DEFAULT_NODENAME,
256 sizeof(WI_DEFAULT_NODENAME) - 1);
257 (void)wi_set_ssid(&sc->wi_netid, WI_DEFAULT_NETNAME,
258 sizeof(WI_DEFAULT_NETNAME) - 1);
259 (void)wi_set_ssid(&sc->wi_ibssid, WI_DEFAULT_IBSS,
260 sizeof(WI_DEFAULT_IBSS) - 1);
261
262 sc->wi_portnum = WI_DEFAULT_PORT;
263 sc->wi_ptype = WI_PORTTYPE_BSS;
264 sc->wi_ap_density = WI_DEFAULT_AP_DENSITY;
265 sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH;
266 sc->wi_tx_rate = WI_DEFAULT_TX_RATE;
267 sc->wi_max_data_len = WI_DEFAULT_DATALEN;
268 sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
269 sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
270 sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
271 sc->wi_roaming = WI_DEFAULT_ROAMING;
272 sc->wi_authtype = WI_DEFAULT_AUTHTYPE;
273
274 /*
275 * Read the default channel from the NIC. This may vary
276 * depending on the country where the NIC was purchased, so
277 * we can't hard-code a default and expect it to work for
278 * everyone.
279 */
280 gen.wi_type = WI_RID_OWN_CHNL;
281 gen.wi_len = 2;
282 wi_read_record(sc, &gen);
283 sc->wi_create_channel = sc->wi_join_channel = le16toh(gen.wi_val);
284
285 memset((char *)&sc->wi_stats, 0, sizeof(sc->wi_stats));
286
287 /* AP info was filled with 0 */
288 memset((char *)&sc->wi_aps, 0, sizeof(sc->wi_aps));
289 sc->wi_scanning = 0;
290 sc->wi_naps = 0;
291
292 /*
293 * Set flags based on firmware version.
294 */
295 switch (sc->sc_firmware_type) {
296 case WI_LUCENT:
297 sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
298 if (sc->sc_sta_firmware_ver >= 60000)
299 sc->wi_flags |= WI_FLAGS_HAS_MOR;
300 if (sc->sc_sta_firmware_ver >= 60006) {
301 sc->wi_flags |= WI_FLAGS_HAS_IBSS;
302 sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
303 }
304 sc->wi_ibss_port = htole16(1);
305 break;
306
307 case WI_INTERSIL:
308 sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
309 if (sc->sc_sta_firmware_ver >= 800) {
310 sc->wi_flags |= WI_FLAGS_HAS_HOSTAP;
311 sc->wi_flags |= WI_FLAGS_HAS_IBSS;
312 #if 0 /* Prism firmware interprets Create IBSS differently than we thought. */
313 sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
314 #endif
315 }
316 sc->wi_ibss_port = htole16(0);
317 break;
318
319 case WI_SYMBOL:
320 sc->wi_flags |= WI_FLAGS_HAS_DIVERSITY;
321 if (sc->sc_sta_firmware_ver >= 20000)
322 sc->wi_flags |= WI_FLAGS_HAS_IBSS;
323 #if 0 /* Prism firmware interprets Create IBSS differently than we thought. */
324 if (sc->sc_sta_firmware_ver >= 25000)
325 sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
326 #endif
327 sc->wi_ibss_port = htole16(4);
328 break;
329 }
330
331 /*
332 * Find out if we support WEP on this card.
333 */
334 gen.wi_type = WI_RID_WEP_AVAIL;
335 gen.wi_len = 2;
336 if (wi_read_record(sc, &gen) == 0 &&
337 gen.wi_val != le16toh(0))
338 sc->wi_flags |= WI_FLAGS_HAS_WEP;
339
340 gen.wi_type = WI_RID_CHANNEL_LIST;
341 gen.wi_len = 2;
342 if (wi_read_record(sc, &gen) == 0)
343 sc->wi_channels = le16toh(gen.wi_val);
344 else
345 sc->wi_channels = (1 << 14) - 1; /* assume all 14 channels */
346
347 /* Find supported rates. */
348 rate.wi_type = WI_RID_DATA_RATES;
349 rate.wi_len = 6;
350 if (wi_read_record(sc, (struct wi_ltv_gen *)&rate) == 0) {
351 nrate = le16toh(rate.wi_str[0]);
352 r = (u_int8_t *)&rate.wi_str[1];
353 for (i = 0; i < nrate; i++) {
354 switch (r[i] & IEEE80211_RATE_VAL) {
355 case 2:
356 sc->wi_supprates |= WI_SUPPRATES_1M;
357 break;
358 case 4:
359 sc->wi_supprates |= WI_SUPPRATES_2M;
360 break;
361 case 11:
362 sc->wi_supprates |= WI_SUPPRATES_5M;
363 break;
364 case 22:
365 sc->wi_supprates |= WI_SUPPRATES_11M;
366 break;
367 }
368 }
369 }
370
371 ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status);
372 if (sc->wi_supprates != 0)
373 printf("%s: supported rates: ", sc->sc_dev.dv_xname);
374 #define ADD(s, o) ifmedia_add(&sc->sc_media, \
375 IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL)
376 #define PRINT(n) printf("%s%s", sep, (n)); sep = ", "
377 ADD(IFM_AUTO, 0);
378 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
379 ADD(IFM_AUTO, IFM_IEEE80211_HOSTAP);
380 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
381 ADD(IFM_AUTO, IFM_IEEE80211_ADHOC);
382 ADD(IFM_AUTO, IFM_IEEE80211_ADHOC | IFM_FLAG0);
383 if (sc->wi_supprates & WI_SUPPRATES_1M) {
384 PRINT("1Mbps");
385 ADD(IFM_IEEE80211_DS1, 0);
386 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
387 ADD(IFM_IEEE80211_DS1, IFM_IEEE80211_HOSTAP);
388 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
389 ADD(IFM_IEEE80211_DS1, IFM_IEEE80211_ADHOC);
390 ADD(IFM_IEEE80211_DS1, IFM_IEEE80211_ADHOC | IFM_FLAG0);
391 }
392 if (sc->wi_supprates & WI_SUPPRATES_2M) {
393 PRINT("2Mbps");
394 ADD(IFM_IEEE80211_DS2, 0);
395 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
396 ADD(IFM_IEEE80211_DS2, IFM_IEEE80211_HOSTAP);
397 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
398 ADD(IFM_IEEE80211_DS2, IFM_IEEE80211_ADHOC);
399 ADD(IFM_IEEE80211_DS2, IFM_IEEE80211_ADHOC | IFM_FLAG0);
400 }
401 if (sc->wi_supprates & WI_SUPPRATES_5M) {
402 PRINT("5.5Mbps");
403 ADD(IFM_IEEE80211_DS5, 0);
404 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
405 ADD(IFM_IEEE80211_DS5, IFM_IEEE80211_HOSTAP);
406 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
407 ADD(IFM_IEEE80211_DS5, IFM_IEEE80211_ADHOC);
408 ADD(IFM_IEEE80211_DS5, IFM_IEEE80211_ADHOC | IFM_FLAG0);
409 }
410 if (sc->wi_supprates & WI_SUPPRATES_11M) {
411 PRINT("11Mbps");
412 ADD(IFM_IEEE80211_DS11, 0);
413 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
414 ADD(IFM_IEEE80211_DS11, IFM_IEEE80211_HOSTAP);
415 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
416 ADD(IFM_IEEE80211_DS11, IFM_IEEE80211_ADHOC);
417 ADD(IFM_IEEE80211_DS11, IFM_IEEE80211_ADHOC | IFM_FLAG0);
418 }
419 if (sc->wi_supprates != 0)
420 printf("\n");
421 ifmedia_set(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0));
422 #undef ADD
423 #undef PRINT
424
425 /*
426 * Call MI attach routines.
427 */
428 if_attach(ifp);
429 ether_ifattach(ifp, sc->sc_macaddr);
430
431 ifp->if_baudrate = IF_Mbps(2);
432
433 #if NBPFILTER > 0
434 bpfattach2(ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame),
435 (caddr_t*) &sc->sc_bpf80211);
436 if (sc->sc_firmware_type == WI_INTERSIL ||
437 sc->sc_firmware_type == WI_SYMBOL) {
438 bpfattach2(ifp, DLT_PRISM_HEADER,
439 WI_HWSPEC_END + sizeof(struct ieee80211_frame),
440 (caddr_t*) &sc->sc_bpf80211plus);
441 }
442 #endif
443
444 /* Attach is successful. */
445 sc->sc_attached = 1;
446
447 splx(s);
448 return 0;
449 }
450
451 static void
452 wi_tap_802_11_plus(struct wi_softc *sc, struct mbuf *m)
453 {
454 if (sc->sc_bpf80211plus) {
455 bpf_mtap((caddr_t) sc->sc_bpf80211plus, m);
456 }
457 if (sc->sc_bpf80211) {
458
459 /* trim off hardware-specific frame header */
460 m->m_pkthdr.len -= WI_HWSPEC_END;
461 m->m_len -= WI_HWSPEC_END;
462 m->m_data += WI_HWSPEC_END;
463
464 bpf_mtap((caddr_t) sc->sc_bpf80211, m);
465
466 /* restore hardware-specific frame header */
467 m->m_data -= WI_HWSPEC_END;
468 m->m_len += WI_HWSPEC_END;
469 m->m_pkthdr.len += WI_HWSPEC_END;
470 }
471 }
472
473 static void
474 wi_tap_802_3(struct wi_softc *sc, struct mbuf *m, struct wi_frame *hwframe)
475 {
476 int encrypted;
477 struct llc llc;
478 struct mbuf m0, m1;
479 struct ether_header *eh;
480
481 /* hand up 802.3 frame */
482 if (sc->sc_ifp->if_bpf) {
483 bpf_mtap(sc->sc_ifp->if_bpf, m);
484 }
485
486 if (m->m_len < sizeof(struct ether_header)) {
487 printf("%s: inconsistent 802.3 mbuf, only %d bytes",
488 sc->sc_dev.dv_xname, m->m_len);
489 return;
490 }
491
492 eh = mtod(m, struct ether_header *);
493
494 llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
495 llc.llc_control = LLC_UI;
496 llc.llc_snap.org_code[0] = 0;
497 llc.llc_snap.org_code[1] = 0;
498 llc.llc_snap.org_code[2] = 0;
499 llc.llc_snap.ether_type = eh->ether_type;
500
501 /* add to chain one mbuf for hardware-specific and 802.11 header,
502 * one for SNAP.
503 */
504 m0.m_pkthdr = m->m_pkthdr;
505 m0.m_flags = m->m_flags & M_COPYFLAGS;
506 m0.m_next = &m1;
507
508 m1.m_next = m;
509 m1.m_data = (caddr_t) &llc;
510 m1.m_len = sizeof(struct llc);
511
512 /* omit 802.3 header */
513 m->m_len -= sizeof(struct ether_header);
514 m->m_data += sizeof(struct ether_header);
515
516 /* do not indicate WEP-encryption to bpf. */
517 encrypted = hwframe->wi_frame_ctl & htole16(WI_FCTL_WEP);
518 hwframe->wi_frame_ctl &= ~htole16(WI_FCTL_WEP);
519
520 /* hand up hardware-specific frame */
521 if (sc->sc_bpf80211plus) {
522
523 m0.m_data = (caddr_t) hwframe;
524 m0.m_len = WI_SHORT_802_11_END;
525
526 m0.m_pkthdr.len = m->m_pkthdr.len + WI_SHORT_802_11_END +
527 sizeof(struct llc) - sizeof(struct ether_header);
528
529 if ((hwframe->wi_frame_ctl & htole16(WI_FCTL_FROMDS)) &&
530 (hwframe->wi_frame_ctl & htole16(WI_FCTL_TODS))) {
531 m0.m_pkthdr.len +=
532 WI_LONG_802_11_END - WI_SHORT_802_11_END;
533 m0.m_len += WI_LONG_802_11_END - WI_SHORT_802_11_END;
534 }
535 bpf_mtap((caddr_t) sc->sc_bpf80211plus, &m0);
536 }
537
538 /* hand up 802.11 frame */
539 if (sc->sc_bpf80211) {
540
541 m0.m_data = (caddr_t) hwframe + WI_802_11_BEGIN;
542 m0.m_len = (WI_SHORT_802_11_END - WI_802_11_BEGIN);
543
544 m0.m_pkthdr.len = m->m_pkthdr.len +
545 (WI_SHORT_802_11_END - WI_802_11_BEGIN) +
546 sizeof(struct llc) - sizeof(struct ether_header);
547
548 if ((hwframe->wi_frame_ctl & htole16(WI_FCTL_FROMDS)) &&
549 (hwframe->wi_frame_ctl & htole16(WI_FCTL_TODS))) {
550 m0.m_pkthdr.len +=
551 WI_LONG_802_11_END - WI_SHORT_802_11_END;
552 m0.m_len += WI_LONG_802_11_END - WI_SHORT_802_11_END;
553 }
554 bpf_mtap((caddr_t) sc->sc_bpf80211, &m0);
555 }
556
557 if (encrypted) {
558 /* restore WEP indication. */
559 hwframe->wi_frame_ctl |= htole16(WI_FCTL_WEP);
560 }
561
562 /* restore 802.3 header */
563 m->m_data -= sizeof(struct ether_header);
564 m->m_len += sizeof(struct ether_header);
565
566 return;
567 }
568
569 static int
570 wi_rx_rfc1042(struct wi_softc *sc, int id, struct wi_frame *frame,
571 struct llc *llc, struct mbuf *m, int maxlen)
572 {
573 struct ether_header *eh;
574 struct ifnet *ifp;
575 int read_ofs, read_len;
576 caddr_t read_ptr;
577
578 ifp = sc->sc_ifp;
579 eh = mtod(m, struct ether_header *);
580
581 read_len = le16toh(frame->wi_dat_len) - sizeof(struct llc);
582
583 if (read_len + sizeof(struct ether_header) > maxlen) {
584 printf("%s: wi_rx_rfc1042: oversized packet received "
585 "(wi_dat_len=%d, wi_status=0x%x)\n", sc->sc_dev.dv_xname,
586 le16toh(frame->wi_dat_len), le16toh(frame->wi_status));
587 m_freem(m);
588 ifp->if_ierrors++;
589 return -1;
590 }
591 m->m_pkthdr.len = m->m_len = read_len + sizeof(struct ether_header);
592
593 /* XXX use 802.11 dst, src, etc.? */
594 (void)memcpy(&eh->ether_dhost, &frame->wi_dst_addr, ETHER_ADDR_LEN);
595 (void)memcpy(&eh->ether_shost, &frame->wi_src_addr, ETHER_ADDR_LEN);
596 eh->ether_type = llc->llc_snap.ether_type;
597
598 read_ptr = (caddr_t) (eh + 1);
599 read_ofs = sizeof(struct wi_frame) + sizeof(struct llc);
600
601 if (wi_read_data(sc, id, read_ofs, read_ptr, read_len)) {
602 m_freem(m);
603 ifp->if_ierrors++;
604 return -1;
605 }
606
607 return 0;
608 }
609
610 /* for wi_rx_ethii, llc points to 8 arbitrary bytes. */
611 static int
612 wi_rx_ethii(struct wi_softc *sc, int id, struct wi_frame *frame,
613 struct llc *llc, struct mbuf *m, int maxlen)
614 {
615 struct ifnet *ifp;
616 #if 0
617 int read_ofs, read_len;
618 caddr_t read_ptr;
619 #endif
620 struct ether_header *eh;
621
622 ifp = sc->sc_ifp;
623 eh = mtod(m, struct ether_header *);
624
625 if (le16toh(frame->wi_dat_len) + sizeof(struct ether_header) > maxlen) {
626 printf("%s: wi_rx_ethii: oversized packet received "
627 "(wi_dat_len=%d, wi_status=0x%x)\n", sc->sc_dev.dv_xname,
628 le16toh(frame->wi_dat_len), le16toh(frame->wi_status));
629 m_freem(m);
630 ifp->if_ierrors++;
631 return -1;
632 }
633 m->m_pkthdr.len = m->m_len = sizeof(struct ether_header) +
634 le16toh(frame->wi_dat_len);
635
636 #if 0
637 (void)memcpy(&eh->ether_dhost, &frame->wi_dst_addr, ETHER_ADDR_LEN);
638 (void)memcpy(&eh->ether_shost, &frame->wi_src_addr, ETHER_ADDR_LEN);
639 eh->ether_type = frame->wi_len;
640
641 read_ptr = mtod(m, caddr_t) + sizeof(struct ether_header) +
642 sizeof(struct llc);
643 read_ofs = sizeof(struct wi_frame) + sizeof(struct llc);
644 read_len = le16toh(frame->wi_dat_len) - sizeof(struct llc);
645
646 if (ifp->if_flags & IFF_DEBUG)
647 printf("%s: frame->wi_dat_len = %d, frame->wi_len = %d\n",
648 sc->sc_dev.dv_xname, le16toh(frame->wi_dat_len),
649 frame->wi_len);
650
651 (void)memcpy(mtod(m, caddr_t), (u_int8_t*)frame + WI_802_3_BEGIN,
652 sizeof(struct ether_header));
653
654 if (ifp->if_flags & IFF_DEBUG)
655 printf("%s: eh->ether_type = %d\n", sc->sc_dev.dv_xname,
656 eh->ether_type);
657
658 (void)memcpy(mtod(m, caddr_t) + sizeof(struct ether_header), llc,
659 sizeof(struct llc));
660
661 if (wi_read_data(sc, id, read_ofs, read_ptr, read_len)) {
662 #else
663 if (wi_read_data(sc, id, WI_802_3_BEGIN, mtod(m, caddr_t), m->m_len)) {
664 #endif
665 m_freem(m);
666 ifp->if_ierrors++;
667 return -1;
668 }
669 if (ifp->if_flags & IFF_DEBUG)
670 printf("%s: 2nd eh->ether_type = %d\n", sc->sc_dev.dv_xname,
671 eh->ether_type);
672
673 return 0;
674 }
675
676 static int
677 wi_rx_mgmt(struct wi_softc *sc, int id, struct wi_frame *frame, struct llc *llc,
678 struct mbuf *m, int maxlen)
679 {
680 int read_ofs, read_len;
681 caddr_t read_ptr;
682 struct ifnet *ifp;
683
684 ifp = sc->sc_ifp;
685
686 if (le16toh(frame->wi_dat_len) + WI_SHORT_802_11_END > maxlen) {
687 printf("%s: oversized packet received in "
688 "Host-AP mode (wi_dat_len=%d, wi_status=0x%x)\n",
689 sc->sc_dev.dv_xname,
690 le16toh(frame->wi_dat_len),
691 le16toh(frame->wi_status));
692 m_freem(m);
693 ifp->if_ierrors++;
694 return -1;
695 }
696
697 /* Put the whole header in there. */
698 (void)memcpy(mtod(m, void *), frame, sizeof(struct wi_frame));
699 (void)memcpy(mtod(m, caddr_t) + WI_SHORT_802_11_END, llc,
700 sizeof(struct llc));
701
702 read_ptr = mtod(m, caddr_t) + WI_SHORT_802_11_END + sizeof(struct llc);
703 read_ofs = sizeof(struct wi_frame) + sizeof(struct llc);
704 read_len = le16toh(frame->wi_dat_len) - sizeof(struct llc);
705
706 if (wi_read_data(sc, id, read_ofs, read_ptr, read_len)) {
707 m_freem(m);
708 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
709 printf("%s: Host-AP: failed to copy header\n",
710 sc->sc_dev.dv_xname);
711 ifp->if_ierrors++;
712 return -1;
713 }
714
715 m->m_pkthdr.len = m->m_len =
716 WI_SHORT_802_11_END + le16toh(frame->wi_dat_len);
717
718 #if NBPFILTER > 0
719 wi_tap_802_11_plus(sc, m);
720 #endif
721
722 wihap_mgmt_input(sc, frame, m);
723
724 return 0;
725 }
726
727 #if defined(OPTIMIZE_RW_DATA)
728 static void wi_rewind(sc)
729 struct wi_softc *sc;
730 {
731 sc->wi_last_chan = -1;
732 sc->wi_last_id = -1;
733 sc->wi_last_offset = -1;
734 }
735 #endif
736
737 static void wi_rxeof(sc)
738 struct wi_softc *sc;
739 {
740 struct ifnet *ifp;
741 struct mbuf *m;
742 int id;
743 caddr_t olddata;
744 int maxlen;
745 struct wi_frame rx_frame;
746 struct llc llc;
747
748 ifp = sc->sc_ifp;
749
750 #if defined(OPTIMIZE_RW_DATA)
751 wi_rewind(sc);
752 #endif
753 id = CSR_READ_2(sc, WI_RX_FID);
754
755 /* First read in the frame header */
756 if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame,
757 sizeof(struct wi_frame))) {
758 ifp->if_ierrors++;
759 return;
760 }
761 if (ifp->if_flags & IFF_DEBUG)
762 printf("%s: rx_frame.wi_dat_len = %d\n", sc->sc_dev.dv_xname,
763 le16toh(rx_frame.wi_dat_len));
764 /* Read optional LLC. */
765 if (wi_read_data(sc, id, sizeof(struct wi_frame), (caddr_t)&llc,
766 min(sizeof(struct llc), le16toh(rx_frame.wi_dat_len)))) {
767 ifp->if_ierrors++;
768 return;
769 }
770
771 /* Drop undecryptable or packets with receive errors. */
772 if (le16toh(rx_frame.wi_status) & WI_STAT_ERRSTAT) {
773 ifp->if_ierrors++;
774 return;
775 }
776
777 MGETHDR(m, M_DONTWAIT, MT_DATA);
778 if (m == NULL) {
779 ifp->if_ierrors++;
780 return;
781 }
782 MCLGET(m, M_DONTWAIT);
783 if (!(m->m_flags & M_EXT)) {
784 m_freem(m);
785 ifp->if_ierrors++;
786 return;
787 }
788
789 olddata = m->m_data;
790 /* Align the data after the ethernet header */
791 m->m_data = (caddr_t) ALIGN(m->m_data + sizeof(struct ether_header))
792 - sizeof(struct ether_header);
793 maxlen = MCLBYTES - (m->m_data - olddata);
794 m->m_pkthdr.rcvif = ifp;
795
796 switch (le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) {
797 case WI_STAT_TUNNEL:
798 case WI_STAT_1042:
799
800 if (ifp->if_flags & IFF_DEBUG)
801 printf("%s: rx RFC1042\n", sc->sc_dev.dv_xname);
802
803 /* Convert from RFC1042 encapsulation to Ethernet II
804 * encapsulation.
805 */
806 if (wi_rx_rfc1042(sc, id, &rx_frame, &llc, m, maxlen))
807 return;
808 break;
809 case WI_STAT_MGMT:
810 if (ifp->if_flags & IFF_DEBUG)
811 printf("%s: rx Mgmt\n", sc->sc_dev.dv_xname);
812
813 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
814 (void)wi_rx_mgmt(sc, id, &rx_frame, &llc, m, maxlen);
815 return;
816 }
817 /* fall through */
818 case WI_STAT_NORMAL:
819
820 if (ifp->if_flags & IFF_DEBUG)
821 printf("%s: rx Normal\n", sc->sc_dev.dv_xname);
822
823 /* linux-wlan-ng reports that some RFC1042 frames
824 * are misidentified as Ethernet II frames. Check.
825 */
826 if (le16toh(rx_frame.wi_dat_len) >= sizeof(struct llc) &&
827 llc.llc_dsap == LLC_SNAP_LSAP &&
828 llc.llc_ssap == LLC_SNAP_LSAP &&
829 llc.llc_control == LLC_UI) {
830 if (ifp->if_flags & IFF_DEBUG)
831 printf("%s: actually rx RFC1042\n",
832 sc->sc_dev.dv_xname);
833
834 if (wi_rx_rfc1042(sc, id, &rx_frame, &llc, m, maxlen))
835 return;
836 } else if (wi_rx_ethii(sc, id, &rx_frame, &llc, m, maxlen))
837 return;
838 break;
839 case WI_STAT_WMP_MSG:
840 /* XXX hand these up with DLT_PRISM_HEADER? */
841 printf("%s: dropping WMP frame\n", sc->sc_dev.dv_xname);
842 break;
843 default:
844 /* XXX hand these up with DLT_PRISM_HEADER? */
845 printf("%s: dropping unknown-encoded frame\n",
846 sc->sc_dev.dv_xname);
847 break;
848 }
849
850 ifp->if_ipackets++;
851
852 #if NBPFILTER > 0
853 /* Handle BPF listeners. */
854 wi_tap_802_3(sc, m, &rx_frame);
855 #endif
856
857 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
858 /*
859 * Give Host-AP first crack at data packets. If it
860 * decides to handle it (or drop it), it will return
861 * non-zero. Otherwise, it is destined for this host.
862 */
863 if (wihap_data_input(sc, &rx_frame, m))
864 return;
865 }
866
867 /* Receive packet. */
868 (*ifp->if_input)(ifp, m);
869 }
870
871 static void wi_txeof(sc, status)
872 struct wi_softc *sc;
873 int status;
874 {
875 struct ifnet *ifp = sc->sc_ifp;
876
877 ifp->if_timer = 0;
878 ifp->if_flags &= ~IFF_OACTIVE;
879
880 if (status & WI_EV_TX_EXC)
881 ifp->if_oerrors++;
882 else
883 ifp->if_opackets++;
884
885 return;
886 }
887
888 void wi_inquire(xsc)
889 void *xsc;
890 {
891 struct wi_softc *sc;
892 struct ifnet *ifp;
893 int s;
894
895 sc = xsc;
896 ifp = &sc->sc_ethercom.ec_if;
897
898 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
899 return;
900
901 KASSERT(sc->sc_enabled);
902
903 callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
904
905 /* Don't do this while we're transmitting */
906 if (ifp->if_flags & IFF_OACTIVE)
907 return;
908
909 s = splnet();
910 wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0);
911 splx(s);
912 }
913
914 void wi_wait_scan(xsc)
915 void *xsc;
916 {
917 struct wi_softc *sc;
918 struct ifnet *ifp;
919 int s, result;
920
921 sc = xsc;
922 ifp = &sc->sc_ethercom.ec_if;
923
924 /* If not scanning, ignore */
925 if (!sc->wi_scanning)
926 return;
927
928 s = splnet();
929
930 /* Wait for sending complete to make INQUIRE */
931 if (ifp->if_flags & IFF_OACTIVE) {
932 callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc);
933 splx(s);
934 return;
935 }
936
937 /* try INQUIRE */
938 result = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0);
939 if (result == ETIMEDOUT)
940 callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc);
941
942 splx(s);
943 }
944
945 void wi_update_stats(sc)
946 struct wi_softc *sc;
947 {
948 struct wi_req wreq;
949 struct wi_ltv_gen gen;
950 struct wi_scan_header ap2_header; /* Prism2 header */
951 struct wi_scan_data_p2 ap2; /* Prism2 scantable*/
952 struct wi_scan_data ap; /* Lucent scantable */
953 struct wi_assoc assoc; /* Association Status */
954 u_int16_t id;
955 struct ifnet *ifp;
956 u_int32_t *ptr;
957 int len, naps, i, j;
958 u_int16_t t;
959
960 ifp = &sc->sc_ethercom.ec_if;
961
962 #if defined(OPTIMIZE_RW_DATA)
963 wi_rewind(sc);
964 #endif
965
966 id = CSR_READ_2(sc, WI_INFO_FID);
967
968 if (wi_seek(sc, id, 0, WI_BAP1)) {
969 return;
970 }
971
972 gen.wi_len = CSR_READ_2(sc, WI_DATA1);
973 gen.wi_type = CSR_READ_2(sc, WI_DATA1);
974
975 switch (gen.wi_type) {
976 case WI_INFO_SCAN_RESULTS:
977 case WI_INFO_HOST_SCAN_RESULTS:
978 if (gen.wi_len <= 3) {
979 sc->wi_naps = 0;
980 sc->wi_scanning = 0;
981 break;
982 }
983 switch (sc->sc_firmware_type) {
984 case WI_INTERSIL:
985 case WI_SYMBOL:
986 if (sc->sc_firmware_type == WI_INTERSIL) {
987 naps = 2 * (gen.wi_len - 3) / sizeof(ap2);
988 /* Read Header */
989 for(j=0; j < sizeof(ap2_header) / 2; j++)
990 ((u_int16_t *)&ap2_header)[j] =
991 CSR_READ_2(sc, WI_DATA1);
992 } else { /* WI_SYMBOL */
993 naps = 2 * (gen.wi_len - 1) / (sizeof(ap2) + 6);
994 ap2_header.wi_reason = 0;
995 }
996 naps = naps > MAXAPINFO ? MAXAPINFO : naps;
997 sc->wi_naps = naps;
998 /* Read Data */
999 for (i=0; i < naps; i++) {
1000 for(j=0; j < sizeof(ap2) / 2; j++)
1001 ((u_int16_t *)&ap2)[j] =
1002 CSR_READ_2(sc, WI_DATA1);
1003 if (sc->sc_firmware_type == WI_SYMBOL) {
1004 /* 3 more words */
1005 for (j = 0; j < 3; j++)
1006 CSR_READ_2(sc, WI_DATA1);
1007 }
1008 /* unswap 8 bit data fields: */
1009 for(j=0;j<sizeof(ap.wi_bssid)/2;j++)
1010 LE16TOH(((u_int16_t *)&ap.wi_bssid[0])[j]);
1011 for(j=0;j<sizeof(ap.wi_name)/2;j++)
1012 LE16TOH(((u_int16_t *)&ap.wi_name[0])[j]);
1013 sc->wi_aps[i].scanreason = ap2_header.wi_reason;
1014 memcpy(sc->wi_aps[i].bssid, ap2.wi_bssid, 6);
1015 sc->wi_aps[i].channel = ap2.wi_chid;
1016 sc->wi_aps[i].signal = ap2.wi_signal;
1017 sc->wi_aps[i].noise = ap2.wi_noise;
1018 sc->wi_aps[i].quality = ap2.wi_signal - ap2.wi_noise;
1019 sc->wi_aps[i].capinfo = ap2.wi_capinfo;
1020 sc->wi_aps[i].interval = ap2.wi_interval;
1021 sc->wi_aps[i].rate = ap2.wi_rate;
1022 if (ap2.wi_namelen > 32)
1023 ap2.wi_namelen = 32;
1024 sc->wi_aps[i].namelen = ap2.wi_namelen;
1025 memcpy(sc->wi_aps[i].name, ap2.wi_name,
1026 ap2.wi_namelen);
1027 }
1028 break;
1029
1030 case WI_LUCENT:
1031 naps = 2 * gen.wi_len / sizeof(ap);
1032 naps = naps > MAXAPINFO ? MAXAPINFO : naps;
1033 sc->wi_naps = naps;
1034 /* Read Data*/
1035 for (i=0; i < naps; i++) {
1036 for(j=0; j < sizeof(ap) / 2; j++)
1037 ((u_int16_t *)&ap)[j] =
1038 CSR_READ_2(sc, WI_DATA1);
1039 /* unswap 8 bit data fields: */
1040 for(j=0;j<sizeof(ap.wi_bssid)/2;j++)
1041 HTOLE16(((u_int16_t *)&ap.wi_bssid[0])[j]);
1042 for(j=0;j<sizeof(ap.wi_name)/2;j++)
1043 HTOLE16(((u_int16_t *)&ap.wi_name[0])[j]);
1044 memcpy(sc->wi_aps[i].bssid, ap.wi_bssid, 6);
1045 sc->wi_aps[i].channel = ap.wi_chid;
1046 sc->wi_aps[i].signal = ap.wi_signal;
1047 sc->wi_aps[i].noise = ap.wi_noise;
1048 sc->wi_aps[i].quality = ap.wi_signal - ap.wi_noise;
1049 sc->wi_aps[i].capinfo = ap.wi_capinfo;
1050 sc->wi_aps[i].interval = ap.wi_interval;
1051 if (ap.wi_namelen > 32)
1052 ap.wi_namelen = 32;
1053 sc->wi_aps[i].namelen = ap.wi_namelen;
1054 memcpy(sc->wi_aps[i].name, ap.wi_name,
1055 ap.wi_namelen);
1056 }
1057 break;
1058 }
1059 /* Done scanning */
1060 sc->wi_scanning = 0;
1061 break;
1062
1063 case WI_INFO_COUNTERS:
1064 /* some card versions have a larger stats structure */
1065 len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ?
1066 gen.wi_len - 1 : sizeof(sc->wi_stats) / 4;
1067 ptr = (u_int32_t *)&sc->wi_stats;
1068
1069 for (i = 0; i < len; i++) {
1070 t = CSR_READ_2(sc, WI_DATA1);
1071 #ifdef WI_HERMES_STATS_WAR
1072 if (t > 0xF000)
1073 t = ~t & 0xFFFF;
1074 #endif
1075 ptr[i] += t;
1076 }
1077
1078 ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
1079 sc->wi_stats.wi_tx_multi_retries +
1080 sc->wi_stats.wi_tx_retry_limit;
1081 break;
1082
1083 case WI_INFO_LINK_STAT: {
1084 static char *msg[] = {
1085 "connected",
1086 "disconnected",
1087 "AP change",
1088 "AP out of range",
1089 "AP in range",
1090 "association failed",
1091 "unknown link status indication"
1092 };
1093
1094 if (gen.wi_len != 2) {
1095 if (ifp->if_flags & IFF_DEBUG)
1096 printf("%s: WI_INFO_LINK_STAT: len %d\n",
1097 sc->sc_dev.dv_xname, gen.wi_len);
1098 break;
1099 }
1100 t = CSR_READ_2(sc, WI_DATA1);
1101
1102 switch (t) {
1103 case 6: /* association failed */
1104 if (!(sc->wi_flags & WI_FLAGS_JOINING))
1105 break;
1106
1107 if (ifp->if_flags & IFF_DEBUG)
1108 printf("%s: failed JOIN %s\n",
1109 sc->sc_dev.dv_xname,
1110 ether_sprintf(sc->wi_join_bssid));
1111
1112 bzero(&sc->wi_join_bssid,
1113 sizeof(sc->wi_join_bssid));
1114 sc->wi_join_channel = 0;
1115 sc->wi_flags &= ~WI_FLAGS_JOINING;
1116 break;
1117 case 2: /* disconnected */
1118 if (!(sc->wi_flags & WI_FLAGS_CONNECTED))
1119 break;
1120 sc->wi_flags &=
1121 ~(WI_FLAGS_CONNECTED | WI_FLAGS_AP_IN_RANGE);
1122 bzero(&sc->wi_current_bssid,
1123 sizeof(sc->wi_current_bssid));
1124 sc->wi_current_channel = 0;
1125 break;
1126 case 1: /* connected */
1127 case 3: /* AP change */
1128
1129 sc->wi_flags &=
1130 ~(WI_FLAGS_CONNECTED | WI_FLAGS_AP_IN_RANGE);
1131
1132 wreq.wi_type = WI_RID_CURRENT_BSSID;
1133 wreq.wi_len = WI_MAX_DATALEN;
1134
1135 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) ||
1136 wreq.wi_len != 4)
1137 break;
1138
1139 (void)memcpy(&sc->wi_current_bssid, &wreq.wi_val[0],
1140 sizeof(sc->wi_current_bssid));
1141
1142 wreq.wi_type = WI_RID_CURRENT_CHAN;
1143 wreq.wi_len = WI_MAX_DATALEN;
1144
1145 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) ||
1146 wreq.wi_len != 2)
1147 break;
1148
1149 sc->wi_current_channel = le16toh(wreq.wi_val[0]);
1150
1151 /* The only Connected/AP Change indication that
1152 * ends a JOIN-pending condition comes with the
1153 * same channel/BSSID as we asked to JOIN.
1154 */
1155 if ((sc->wi_flags & WI_FLAGS_JOINING) &&
1156 (memcmp(&sc->wi_current_bssid, &sc->wi_join_bssid,
1157 sizeof(sc->wi_join_bssid)) != 0 ||
1158 sc->wi_current_channel != sc->wi_join_channel))
1159 break;
1160
1161 sc->wi_flags |=
1162 WI_FLAGS_CONNECTED | WI_FLAGS_AP_IN_RANGE;
1163
1164 sc->wi_flags &= ~WI_FLAGS_JOINING;
1165
1166 #if 0
1167 wreq.wi_type = WI_RID_COMMQUAL;
1168 wreq.wi_len = WI_MAX_DATALEN;
1169 if (wi_read_record(sc, (struct wi_ltv_gen*)&wreq) == 0
1170 && wreq.wi_val[0] == 0)
1171 sc->wi_flags &= ~WI_FLAGS_AP_IN_RANGE;
1172 #endif
1173 break;
1174
1175 case 4: /* AP out of range */
1176 sc->wi_flags &= ~WI_FLAGS_AP_IN_RANGE;
1177 if (sc->sc_firmware_type == WI_SYMBOL) {
1178 wi_cmd(sc, WI_CMD_INQUIRE,
1179 WI_INFO_HOST_SCAN_RESULTS, 0, 0);
1180 break;
1181 }
1182 break;
1183
1184 case 5: /* AP in range */
1185 sc->wi_flags |= WI_FLAGS_AP_IN_RANGE;
1186 break;
1187 default:
1188 t = sizeof(msg) / sizeof(msg[0]) - 1;
1189 break;
1190 }
1191 if (ifp->if_flags & IFF_DEBUG)
1192 printf("%s: %s, BSSID %s %d\n", sc->sc_dev.dv_xname,
1193 msg[t - 1], ether_sprintf(sc->wi_current_bssid),
1194 sc->wi_current_channel);
1195 }
1196 break;
1197
1198 case WI_INFO_ASSOC_STAT: {
1199 static char *msg[] = {
1200 "STA Associated",
1201 "STA Reassociated",
1202 "STA Disassociated",
1203 "Association Failure",
1204 "Authentication Failed"
1205 };
1206 if (gen.wi_len != 10)
1207 break;
1208 for (i=0; i < gen.wi_len - 1; i++)
1209 ((u_int16_t *)&assoc)[i] = CSR_READ_2(sc, WI_DATA1);
1210 /* unswap 8 bit data fields: */
1211 for(j=0;j<sizeof(assoc.wi_assoc_sta)/2;j++)
1212 HTOLE16(((u_int16_t *)&assoc.wi_assoc_sta[0])[j]);
1213 for(j=0;j<sizeof(assoc.wi_assoc_osta)/2;j++)
1214 HTOLE16(((u_int16_t *)&assoc.wi_assoc_osta[0])[j]);
1215 switch (assoc.wi_assoc_stat) {
1216 case ASSOC:
1217 case DISASSOC:
1218 case ASSOCFAIL:
1219 case AUTHFAIL:
1220 printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x\n",
1221 sc->sc_dev.dv_xname,
1222 msg[assoc.wi_assoc_stat - 1],
1223 assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff,
1224 assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff,
1225 assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff);
1226 break;
1227 case REASSOC:
1228 printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x, "
1229 "OldAP = %02x:%02x:%02x:%02x:%02x:%02x\n",
1230 sc->sc_dev.dv_xname, msg[assoc.wi_assoc_stat - 1],
1231 assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff,
1232 assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff,
1233 assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff,
1234 assoc.wi_assoc_osta[0]&0xff, assoc.wi_assoc_osta[1]&0xff,
1235 assoc.wi_assoc_osta[2]&0xff, assoc.wi_assoc_osta[3]&0xff,
1236 assoc.wi_assoc_osta[4]&0xff, assoc.wi_assoc_osta[5]&0xff);
1237 break;
1238 }
1239 }
1240
1241 default:
1242 #ifdef WI_DEBUG
1243 printf("%s: got info type: 0x%04x len=0x%04x\n",
1244 sc->sc_dev.dv_xname, gen.wi_type,gen.wi_len);
1245 #endif
1246 #if 0
1247 for (i = 0; i < gen.wi_len; i++) {
1248 t = CSR_READ_2(sc, WI_DATA1);
1249 printf("[0x%02x] = 0x%04x\n", i, t);
1250 }
1251 #endif
1252 break;
1253 }
1254 }
1255
1256 static int
1257 wi_join_bss(sc)
1258 struct wi_softc *sc;
1259 {
1260 struct wi_req wreq;
1261
1262 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
1263 return 0;
1264 }
1265
1266 if (memcmp(&sc->wi_join_bssid, &zero_bssid, sizeof(zero_bssid)) == 0 &&
1267 sc->wi_join_channel == 0 && (sc->wi_flags & WI_FLAGS_CONNECTED)) {
1268
1269 return 0;
1270 } else if (memcmp(&sc->wi_join_bssid, &sc->wi_current_bssid,
1271 sizeof(sc->wi_join_bssid)) == 0 &&
1272 sc->wi_join_channel == sc->wi_current_channel) {
1273
1274 bzero(&sc->wi_join_bssid, sizeof(sc->wi_join_bssid));
1275 sc->wi_join_channel = 0;
1276 return 0;
1277 }
1278
1279 sc->wi_flags &= ~(WI_FLAGS_CONNECTED | WI_FLAGS_AP_IN_RANGE);
1280
1281 /* Indications are unavailable/unreliable in IBSS mode, so
1282 * we do not tie things up by setting WI_FLAGS_JOINING.
1283 */
1284 switch (sc->wi_ptype) {
1285 case WI_PORTTYPE_ADHOC:
1286 case WI_PORTTYPE_IBSS:
1287 sc->wi_flags &= ~WI_FLAGS_JOINING;
1288 break;
1289 default:
1290 sc->wi_flags |= WI_FLAGS_JOINING;
1291 }
1292
1293 wreq.wi_type = WI_RID_JOIN_REQ;
1294 wreq.wi_len = 5;
1295 (void)memcpy(&wreq.wi_val[0], &sc->wi_join_bssid,
1296 sizeof(sc->wi_join_bssid));
1297 wreq.wi_val[3] = htole16(sc->wi_join_channel);
1298
1299 return wi_write_record(sc, (struct wi_ltv_gen *) &wreq);
1300 }
1301
1302 int wi_intr(arg)
1303 void *arg;
1304 {
1305 struct wi_softc *sc = arg;
1306 struct ifnet *ifp;
1307 u_int16_t status;
1308 u_int16_t last_status, raw_status;
1309 int s;
1310 struct timeval start_time, present_time;
1311
1312 if (sc->sc_enabled == 0 ||
1313 (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
1314 (sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0)
1315 return (0);
1316
1317 ifp = &sc->sc_ethercom.ec_if;
1318
1319 if (!(ifp->if_flags & IFF_UP)) {
1320 CSR_WRITE_2(sc, WI_INT_EN, 0);
1321 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
1322 return 1;
1323 }
1324
1325 last_status = 0;
1326
1327 s = splclock();
1328 start_time = mono_time;
1329 splx(s);
1330
1331 for (;;) {
1332
1333 /* Only believe a status bit when we enter wi_intr, or when
1334 * the bit was "off" the last time through the loop. This is
1335 * my strategy to avoid racing the hardware/firmware if I
1336 * can re-read the event status register more quickly than
1337 * it is updated.
1338 */
1339 raw_status = CSR_READ_2(sc, WI_EVENT_STAT);
1340 status = raw_status & ~last_status;
1341 last_status = raw_status & WI_INTRS;
1342
1343 if (!(raw_status & WI_INTRS)) {
1344 break;
1345 }
1346
1347 if (status & WI_EV_RX) {
1348 wi_rxeof(sc);
1349 }
1350
1351 if (status & WI_EV_TX) {
1352 wi_txeof(sc, status);
1353 }
1354
1355 if (status & WI_EV_ALLOC) {
1356 int id;
1357 id = CSR_READ_2(sc, WI_ALLOC_FID);
1358 if (id == sc->wi_tx_data_id)
1359 wi_txeof(sc, status);
1360 }
1361
1362 if (status & WI_EV_INFO) {
1363 wi_update_stats(sc);
1364 }
1365
1366 if (status & WI_EV_TX_EXC) {
1367 wi_txeof(sc, status);
1368 }
1369
1370 /* Remember that we no longer disable interrupts. We ack
1371 * LAST so that we're not racing against new events to
1372 * process the present events. It is bad to lose the
1373 * race because an RX/TX buffer is eligible for re-use once
1374 * we ack. Possibly I have seen RX frames too long because
1375 * the NIC clobbered the frame-length before I read it all?
1376 */
1377 CSR_WRITE_2(sc, WI_EVENT_ACK, status);
1378
1379 s = splclock();
1380 present_time = mono_time;
1381 splx(s);
1382
1383 while (present_time.tv_sec > start_time.tv_sec) {
1384 present_time.tv_usec += 1000000;
1385 present_time.tv_sec--;
1386 }
1387 if (present_time.tv_usec - start_time.tv_usec >= 4000 /*4ms*/) {
1388 break;
1389 }
1390 }
1391
1392 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1393 wi_start(ifp);
1394
1395 return 1;
1396 }
1397
1398 /* Must be called at proper protection level! */
1399 static int
1400 wi_cmd(sc, cmd, val0, val1, val2)
1401 struct wi_softc *sc;
1402 int cmd;
1403 int val0;
1404 int val1;
1405 int val2;
1406 {
1407 int i, s = 0;
1408
1409 /* Wait 100us for the busy bit to clear. */
1410 for (i = 10; i--; DELAY(10)) {
1411 if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
1412 break;
1413 }
1414
1415 if (i < 0) {
1416 printf("%s: wi_cmd: BUSY did not clear, cmd=0x%x\n",
1417 sc->sc_dev.dv_xname, cmd);
1418 return EIO;
1419 }
1420
1421 CSR_WRITE_2(sc, WI_PARAM0, val0);
1422 CSR_WRITE_2(sc, WI_PARAM1, val1);
1423 CSR_WRITE_2(sc, WI_PARAM2, val2);
1424 CSR_WRITE_2(sc, WI_COMMAND, cmd);
1425
1426 /* wait .4 second for the command to complete. study the
1427 * distribution of times.
1428 */
1429 for (i = 2000; i--; DELAY(200)) {
1430 /*
1431 * Wait for 'command complete' bit to be
1432 * set in the event status register.
1433 */
1434 s = CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD;
1435 if (s) {
1436 /* Ack the event and read result code. */
1437 s = CSR_READ_2(sc, WI_STATUS);
1438 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
1439 #ifdef foo
1440 if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK))
1441 return(EIO);
1442 #endif
1443 if (s & WI_STAT_CMD_RESULT)
1444 return(EIO);
1445 break;
1446 }
1447 }
1448
1449 if (i < 0) {
1450 if (!sc->wi_scanning)
1451 printf("%s: command timed out, cmd=0x%x\n",
1452 sc->sc_dev.dv_xname, cmd);
1453 return(ETIMEDOUT);
1454 }
1455
1456 return(0);
1457 }
1458
1459 static void
1460 wi_reset(sc)
1461 struct wi_softc *sc;
1462 {
1463 int i;
1464
1465 sc->wi_flags &=
1466 ~(WI_FLAGS_INITIALIZED | WI_FLAGS_CONNECTED | WI_FLAGS_AP_IN_RANGE);
1467
1468 bzero(&sc->wi_current_bssid, sizeof(sc->wi_current_bssid));
1469 bzero(&sc->wi_stats, sizeof(sc->wi_stats));
1470
1471 for (i = 5; i--; DELAY(5 * 1000)) {
1472 if (wi_cmd(sc, WI_CMD_INI, 0, 0, 0) == 0)
1473 break;
1474 }
1475
1476 if (i < 0)
1477 printf("%s" ": init failed\n", sc->sc_dev.dv_xname);
1478 else
1479 sc->wi_flags |= WI_FLAGS_INITIALIZED;
1480
1481 CSR_WRITE_2(sc, WI_INT_EN, 0);
1482 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
1483
1484 /* Calibrate timer. */
1485 WI_SETVAL(WI_RID_TICK_TIME, 8);
1486
1487 return;
1488 }
1489
1490 /*
1491 * Read an LTV record from the NIC.
1492 */
1493 static int wi_read_record(sc, ltv)
1494 struct wi_softc *sc;
1495 struct wi_ltv_gen *ltv;
1496 {
1497 u_int16_t *ptr;
1498 int len, code;
1499 struct wi_ltv_gen *oltv, p2ltv;
1500
1501 if (sc->sc_firmware_type != WI_LUCENT) {
1502 oltv = ltv;
1503 switch (ltv->wi_type) {
1504 case WI_RID_ENCRYPTION:
1505 p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
1506 p2ltv.wi_len = 2;
1507 ltv = &p2ltv;
1508 break;
1509 case WI_RID_TX_CRYPT_KEY:
1510 p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
1511 p2ltv.wi_len = 2;
1512 ltv = &p2ltv;
1513 break;
1514 }
1515 }
1516
1517 /* Tell the NIC to enter record read mode. */
1518 if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0))
1519 return(EIO);
1520
1521 /* Seek to the record. */
1522 if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
1523 return(EIO);
1524
1525 /*
1526 * Read the length and record type and make sure they
1527 * match what we expect (this verifies that we have enough
1528 * room to hold all of the returned data).
1529 */
1530 len = CSR_READ_2(sc, WI_DATA1);
1531 if (len > ltv->wi_len)
1532 return(ENOSPC);
1533 code = CSR_READ_2(sc, WI_DATA1);
1534 if (code != ltv->wi_type)
1535 return(EIO);
1536
1537 ltv->wi_len = len;
1538 ltv->wi_type = code;
1539
1540 /* A 2us delay here prevents a MCHK exception on G4 Powerbook.
1541 * Go figure.
1542 */
1543
1544 /* Now read the data. */
1545 ptr = <v->wi_val;
1546 if (ltv->wi_len > 1)
1547 CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1);
1548
1549 if (ltv->wi_type == WI_RID_PORTTYPE &&
1550 sc->wi_ptype == WI_PORTTYPE_IBSS &&
1551 ltv->wi_val == sc->wi_ibss_port) {
1552 /*
1553 * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
1554 * Since Lucent uses port type 1 for BSS *and* IBSS we
1555 * have to rely on wi_ptype to distinguish this for us.
1556 */
1557 ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
1558 } else if (sc->sc_firmware_type != WI_LUCENT) {
1559 int v;
1560
1561 switch (oltv->wi_type) {
1562 case WI_RID_TX_RATE:
1563 case WI_RID_CUR_TX_RATE:
1564 switch (le16toh(ltv->wi_val)) {
1565 case 1: v = 1; break;
1566 case 2: v = 2; break;
1567 case 3: v = 6; break;
1568 case 4: v = 5; break;
1569 case 7: v = 7; break;
1570 case 8: v = 11; break;
1571 case 15: v = 3; break;
1572 default: v = 0x100 + le16toh(ltv->wi_val); break;
1573 }
1574 oltv->wi_val = htole16(v);
1575 break;
1576 case WI_RID_ENCRYPTION:
1577 oltv->wi_len = 2;
1578 if (le16toh(ltv->wi_val) & 0x01)
1579 oltv->wi_val = htole16(1);
1580 else
1581 oltv->wi_val = htole16(0);
1582 break;
1583 case WI_RID_TX_CRYPT_KEY:
1584 oltv->wi_len = 2;
1585 oltv->wi_val = ltv->wi_val;
1586 break;
1587 case WI_RID_CNFAUTHMODE:
1588 oltv->wi_len = 2;
1589 if (le16toh(ltv->wi_val) & 0x01)
1590 oltv->wi_val = htole16(1);
1591 else if (le16toh(ltv->wi_val) & 0x02)
1592 oltv->wi_val = htole16(2);
1593 break;
1594 }
1595 }
1596
1597 return(0);
1598 }
1599
1600 /*
1601 * Same as read, except we inject data instead of reading it.
1602 */
1603 static int wi_write_record(sc, ltv)
1604 struct wi_softc *sc;
1605 struct wi_ltv_gen *ltv;
1606 {
1607 u_int16_t *ptr;
1608 int i;
1609 struct wi_ltv_gen p2ltv;
1610
1611 if (ltv->wi_type == WI_RID_PORTTYPE &&
1612 ltv->wi_val == le16toh(WI_PORTTYPE_IBSS)) {
1613 /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
1614 p2ltv.wi_type = WI_RID_PORTTYPE;
1615 p2ltv.wi_len = 2;
1616 p2ltv.wi_val = sc->wi_ibss_port;
1617 ltv = &p2ltv;
1618 } else if (sc->sc_firmware_type != WI_LUCENT) {
1619 int v;
1620
1621 switch (ltv->wi_type) {
1622 case WI_RID_TX_RATE:
1623 p2ltv.wi_type = WI_RID_TX_RATE;
1624 p2ltv.wi_len = 2;
1625 switch (le16toh(ltv->wi_val)) {
1626 case 1: v = 1; break;
1627 case 2: v = 2; break;
1628 case 3: v = 15; break;
1629 case 5: v = 4; break;
1630 case 6: v = 3; break;
1631 case 7: v = 7; break;
1632 case 11: v = 8; break;
1633 default: return EINVAL;
1634 }
1635 p2ltv.wi_val = htole16(v);
1636 ltv = &p2ltv;
1637 break;
1638 case WI_RID_ENCRYPTION:
1639 p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
1640 p2ltv.wi_len = 2;
1641 if (le16toh(ltv->wi_val)) {
1642 uint16_t val = PRIVACY_INVOKED;
1643 /*
1644 * If using shared key WEP we must set the
1645 * EXCLUDE_UNENCRYPTED bit. Symbol cards
1646 * need this bit even when not using shared
1647 * key. We can't just test for
1648 * IEEE80211_AUTH_SHARED since Symbol cards
1649 * have 2 shared key modes.
1650 */
1651 if (sc->wi_authtype != IEEE80211_AUTH_OPEN ||
1652 sc->sc_firmware_type == WI_SYMBOL)
1653 val |= EXCLUDE_UNENCRYPTED;
1654 /* Tx encryption is broken in Host-AP mode. */
1655 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
1656 val |= HOST_ENCRYPT;
1657 p2ltv.wi_val = htole16(val);
1658 } else
1659 p2ltv.wi_val =
1660 htole16(HOST_ENCRYPT | HOST_DECRYPT);
1661 ltv = &p2ltv;
1662 break;
1663 case WI_RID_TX_CRYPT_KEY:
1664 p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
1665 p2ltv.wi_len = 2;
1666 p2ltv.wi_val = ltv->wi_val;
1667 ltv = &p2ltv;
1668 break;
1669 case WI_RID_DEFLT_CRYPT_KEYS:
1670 {
1671 int error;
1672 int keylen;
1673 struct wi_ltv_str ws;
1674 struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv;
1675
1676 keylen = le16toh(wk->wi_keys[sc->wi_tx_key].wi_keylen);
1677
1678 for (i = 0; i < 4; i++) {
1679 memset(&ws, 0, sizeof(ws));
1680 ws.wi_len = (keylen > 5) ? 8 : 4;
1681 ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
1682 memcpy(ws.wi_str,
1683 &wk->wi_keys[i].wi_keydat, keylen);
1684 error = wi_write_record(sc,
1685 (struct wi_ltv_gen *)&ws);
1686 if (error)
1687 return error;
1688 }
1689 return 0;
1690 }
1691 case WI_RID_CNFAUTHMODE:
1692 p2ltv.wi_type = WI_RID_CNFAUTHMODE;
1693 p2ltv.wi_len = 2;
1694 if (le16toh(ltv->wi_val) == 1)
1695 p2ltv.wi_val = htole16(0x01);
1696 else if (le16toh(ltv->wi_val) == 2)
1697 p2ltv.wi_val = htole16(0x02);
1698 ltv = &p2ltv;
1699 break;
1700 }
1701 }
1702
1703 if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
1704 return(EIO);
1705
1706 CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len);
1707 CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type);
1708
1709 /* Write data */
1710 ptr = <v->wi_val;
1711 if (ltv->wi_len > 1)
1712 CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1);
1713
1714 if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0))
1715 return(EIO);
1716
1717 return(0);
1718 }
1719
1720 static int wi_seek(sc, id, off, chan)
1721 struct wi_softc *sc;
1722 int id, off, chan;
1723 {
1724 int i;
1725 int selreg, offreg;
1726 int status;
1727
1728 #if defined(OPTIMIZE_RW_DATA)
1729 if (sc->wi_last_chan == chan && sc->wi_last_id == id &&
1730 sc->wi_last_offset <= off) {
1731 while (off - sc->wi_last_offset >= len) {
1732 CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, len);
1733 sc->wi_last_offset += len;
1734 }
1735 if (sc->wi_last_offset < off) {
1736 CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr,
1737 off - sc->wi_last_offset);
1738 sc->wi_last_offset = off;
1739 }
1740 return 0;
1741 }
1742 #endif
1743 switch (chan) {
1744 case WI_BAP0:
1745 selreg = WI_SEL0;
1746 offreg = WI_OFF0;
1747 break;
1748 case WI_BAP1:
1749 selreg = WI_SEL1;
1750 offreg = WI_OFF1;
1751 break;
1752 default:
1753 printf("%s: invalid data path: %x\n",
1754 sc->sc_dev.dv_xname, chan);
1755 return(EIO);
1756 }
1757
1758 CSR_WRITE_2(sc, selreg, id);
1759 CSR_WRITE_2(sc, offreg, off);
1760
1761 for (i = WI_TIMEOUT; i--; DELAY(10))
1762 if (!(CSR_READ_2(sc, offreg) & (WI_OFF_BUSY|WI_OFF_ERR)))
1763 break;
1764
1765 if (i < 0) {
1766 printf("%s: timeout in wi_seek to %x/%x; last status %x\n",
1767 sc->sc_dev.dv_xname, id, off, status);
1768 return(ETIMEDOUT);
1769 }
1770 #if defined(OPTIMIZE_RW_DATA)
1771 sc->wi_last_chan = chan;
1772 sc->wi_last_id = id;
1773 sc->wi_last_offset = off;
1774 #endif
1775 return(0);
1776 }
1777
1778 /* buf must be aligned on a u_int16_t boundary. */
1779 static int wi_read_data(sc, id, off, buf, len)
1780 struct wi_softc *sc;
1781 int id, off;
1782 caddr_t buf;
1783 int len;
1784 {
1785 u_int16_t *ptr;
1786
1787 if (len <= 0)
1788 return 0;
1789
1790 if (len & 1)
1791 len++;
1792
1793 if (wi_seek(sc, id, off, WI_BAP1))
1794 return(EIO);
1795
1796 ptr = (u_int16_t *)buf;
1797 CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, len / 2);
1798
1799 #if defined(OPTIMIZE_RW_DATA)
1800 sc->wi_last_chan = WI_BAP1;
1801 sc->wi_last_id = id;
1802 sc->wi_last_offset = off + len;
1803 #endif
1804 return(0);
1805 }
1806
1807 /*
1808 * According to the comments in the HCF Light code, there is a bug in
1809 * the Hermes (or possibly in certain Hermes firmware revisions) where
1810 * the chip's internal autoincrement counter gets thrown off during
1811 * data writes: the autoincrement is missed, causing one data word to
1812 * be overwritten and subsequent words to be written to the wrong memory
1813 * locations. The end result is that we could end up transmitting bogus
1814 * frames without realizing it. The workaround for this is to write a
1815 * couple of extra guard words after the end of the transfer, then
1816 * attempt to read then back. If we fail to locate the guard words where
1817 * we expect them, we preform the transfer over again.
1818 *
1819 * buf must be aligned on a u_int16_t boundary.
1820 */
1821 static int wi_write_data(sc, id, off, buf, len)
1822 struct wi_softc *sc;
1823 int id, off;
1824 caddr_t buf;
1825 int len;
1826 {
1827 u_int16_t *ptr;
1828
1829 if (len <= 0)
1830 return 0;
1831
1832 if (len & 1)
1833 len++;
1834
1835 #if !defined(OPTIMIZE_RW_DATA) && defined(WI_HERMES_AUTOINC_WAR)
1836 again:
1837 #endif
1838
1839 if (wi_seek(sc, id, off, WI_BAP0))
1840 return(EIO);
1841
1842 ptr = (u_int16_t *)buf;
1843 CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, ptr, len / 2);
1844
1845 #if !defined(OPTIMIZE_RW_DATA) && defined(WI_HERMES_AUTOINC_WAR)
1846 CSR_WRITE_2(sc, WI_DATA0, 0x1234);
1847 CSR_WRITE_2(sc, WI_DATA0, 0x5678);
1848
1849 if (wi_seek(sc, id, off + len, WI_BAP0))
1850 return(EIO);
1851
1852 if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
1853 CSR_READ_2(sc, WI_DATA0) != 0x5678) {
1854 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
1855 printf("%s: auto-inc error\n", sc->sc_dev.dv_xname);
1856 goto again;
1857 }
1858 #endif
1859
1860 #if defined(OPTIMIZE_RW_DATA)
1861 sc->wi_last_chan = WI_BAP0;
1862 sc->wi_last_id = id;
1863 sc->wi_last_offset = off + len;
1864 #endif
1865 return(0);
1866 }
1867
1868 /*
1869 * Allocate a region of memory inside the NIC and zero
1870 * it out.
1871 */
1872 static int wi_alloc_nicmem(sc, len, id)
1873 struct wi_softc *sc;
1874 int len;
1875 int *id;
1876 {
1877 int i;
1878
1879 #if defined(OPTIMIZE_RW_DATA)
1880 wi_rewind(sc);
1881 #endif
1882
1883 if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) {
1884 printf("%s: failed to allocate %d bytes on NIC\n",
1885 sc->sc_dev.dv_xname, len);
1886 return(ENOMEM);
1887 }
1888
1889 for (i = WI_TIMEOUT; i--; DELAY(10)) {
1890 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
1891 break;
1892 }
1893
1894 if (i < 0) {
1895 printf("%s: TIMED OUT in alloc\n", sc->sc_dev.dv_xname);
1896 return(ETIMEDOUT);
1897 }
1898
1899 *id = CSR_READ_2(sc, WI_ALLOC_FID);
1900 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
1901
1902 if (wi_seek(sc, *id, 0, WI_BAP0)) {
1903 printf("%s: seek failed in alloc\n", sc->sc_dev.dv_xname);
1904 return(EIO);
1905 }
1906
1907 for (i = 0; i < len / 2; i++)
1908 CSR_WRITE_2(sc, WI_DATA0, 0);
1909
1910 return(0);
1911 }
1912
1913 static void wi_setmulti(sc)
1914 struct wi_softc *sc;
1915 {
1916 struct ifnet *ifp;
1917 int i = 0;
1918 struct wi_ltv_mcast mcast;
1919 struct ether_multi *enm;
1920 struct ether_multistep estep;
1921 struct ethercom *ec = &sc->sc_ethercom;
1922
1923 ifp = &sc->sc_ethercom.ec_if;
1924
1925 if ((ifp->if_flags & IFF_PROMISC) != 0) {
1926 allmulti:
1927 ifp->if_flags |= IFF_ALLMULTI;
1928 memset((char *)&mcast, 0, sizeof(mcast));
1929 mcast.wi_type = WI_RID_MCAST_LIST;
1930 mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1;
1931
1932 wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
1933 return;
1934 }
1935
1936 i = 0;
1937 ETHER_FIRST_MULTI(estep, ec, enm);
1938 while (enm != NULL) {
1939 /* Punt on ranges or too many multicast addresses. */
1940 if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
1941 ETHER_ADDR_LEN) != 0 ||
1942 i >= 16)
1943 goto allmulti;
1944
1945 memcpy((char *)&mcast.wi_mcast[i], enm->enm_addrlo,
1946 ETHER_ADDR_LEN);
1947 i++;
1948 ETHER_NEXT_MULTI(estep, enm);
1949 }
1950
1951 ifp->if_flags &= ~IFF_ALLMULTI;
1952 mcast.wi_type = WI_RID_MCAST_LIST;
1953 mcast.wi_len = ((ETHER_ADDR_LEN / 2) * i) + 1;
1954 wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
1955 }
1956
1957 static int
1958 wi_setdef(sc, wreq)
1959 struct wi_softc *sc;
1960 struct wi_req *wreq;
1961 {
1962 struct sockaddr_dl *sdl;
1963 struct ifnet *ifp;
1964 int error = 0;
1965
1966 ifp = &sc->sc_ethercom.ec_if;
1967
1968 switch(wreq->wi_type) {
1969 case WI_RID_MAC_NODE:
1970 sdl = (struct sockaddr_dl *)ifp->if_sadl;
1971 memcpy((char *)&sc->sc_macaddr, (char *)&wreq->wi_val,
1972 ETHER_ADDR_LEN);
1973 memcpy(LLADDR(sdl), (char *)&wreq->wi_val, ETHER_ADDR_LEN);
1974 break;
1975 case WI_RID_PORTTYPE:
1976 error = wi_sync_media(sc, le16toh(wreq->wi_val[0]),
1977 sc->wi_tx_rate);
1978 break;
1979 case WI_RID_TX_RATE:
1980 error = wi_sync_media(sc, sc->wi_ptype,
1981 le16toh(wreq->wi_val[0]));
1982 break;
1983 case WI_RID_MAX_DATALEN:
1984 sc->wi_max_data_len = le16toh(wreq->wi_val[0]);
1985 break;
1986 case WI_RID_RTS_THRESH:
1987 sc->wi_rts_thresh = le16toh(wreq->wi_val[0]);
1988 break;
1989 case WI_RID_SYSTEM_SCALE:
1990 sc->wi_ap_density = le16toh(wreq->wi_val[0]);
1991 break;
1992 case WI_RID_CREATE_IBSS:
1993 sc->wi_create_ibss = le16toh(wreq->wi_val[0]);
1994 error = wi_sync_media(sc, sc->wi_ptype, sc->wi_tx_rate);
1995 break;
1996 case WI_RID_OWN_CHNL:
1997 sc->wi_create_channel = le16toh(wreq->wi_val[0]);
1998 break;
1999 case WI_RID_NODENAME:
2000 error = wi_set_ssid(&sc->wi_nodeid,
2001 (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
2002 break;
2003 case WI_RID_DESIRED_SSID:
2004 error = wi_set_ssid(&sc->wi_netid,
2005 (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
2006 break;
2007 case WI_RID_OWN_SSID:
2008 error = wi_set_ssid(&sc->wi_ibssid,
2009 (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
2010 break;
2011 case WI_RID_PM_ENABLED:
2012 sc->wi_pm_enabled = le16toh(wreq->wi_val[0]);
2013 break;
2014 case WI_RID_MICROWAVE_OVEN:
2015 sc->wi_mor_enabled = le16toh(wreq->wi_val[0]);
2016 break;
2017 case WI_RID_MAX_SLEEP:
2018 sc->wi_max_sleep = le16toh(wreq->wi_val[0]);
2019 break;
2020 case WI_RID_CNFAUTHMODE:
2021 sc->wi_authtype = le16toh(wreq->wi_val[0]);
2022 break;
2023 case WI_RID_ROAMING_MODE:
2024 sc->wi_roaming = le16toh(wreq->wi_val[0]);
2025 break;
2026 case WI_RID_ENCRYPTION:
2027 sc->wi_use_wep = le16toh(wreq->wi_val[0]);
2028 break;
2029 case WI_RID_TX_CRYPT_KEY:
2030 sc->wi_tx_key = le16toh(wreq->wi_val[0]);
2031 break;
2032 case WI_RID_DEFLT_CRYPT_KEYS:
2033 memcpy((char *)&sc->wi_keys, (char *)wreq,
2034 sizeof(struct wi_ltv_keys));
2035 break;
2036 default:
2037 error = EINVAL;
2038 break;
2039 }
2040
2041 return (error);
2042 }
2043
2044 static int
2045 wi_getdef(sc, wreq)
2046 struct wi_softc *sc;
2047 struct wi_req *wreq;
2048 {
2049 struct sockaddr_dl *sdl;
2050 struct ifnet *ifp;
2051 int error = 0;
2052
2053 ifp = &sc->sc_ethercom.ec_if;
2054
2055 wreq->wi_len = 2; /* XXX */
2056 switch (wreq->wi_type) {
2057 case WI_RID_MAC_NODE:
2058 wreq->wi_len += ETHER_ADDR_LEN / 2 - 1;
2059 sdl = (struct sockaddr_dl *)ifp->if_sadl;
2060 memcpy(&wreq->wi_val, &sc->sc_macaddr, ETHER_ADDR_LEN);
2061 memcpy(&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN);
2062 break;
2063 case WI_RID_PORTTYPE:
2064 wreq->wi_val[0] = htole16(sc->wi_ptype);
2065 break;
2066 case WI_RID_TX_RATE:
2067 wreq->wi_val[0] = htole16(sc->wi_tx_rate);
2068 break;
2069 case WI_RID_MAX_DATALEN:
2070 wreq->wi_val[0] = htole16(sc->wi_max_data_len);
2071 break;
2072 case WI_RID_RTS_THRESH:
2073 wreq->wi_val[0] = htole16(sc->wi_rts_thresh);
2074 break;
2075 case WI_RID_SYSTEM_SCALE:
2076 wreq->wi_val[0] = htole16(sc->wi_ap_density);
2077 break;
2078 case WI_RID_CREATE_IBSS:
2079 wreq->wi_val[0] = htole16(sc->wi_create_ibss);
2080 break;
2081 case WI_RID_OWN_CHNL:
2082 wreq->wi_val[0] = htole16(sc->wi_create_channel);
2083 break;
2084 case WI_RID_NODENAME:
2085 wi_request_fill_ssid(wreq, &sc->wi_nodeid);
2086 break;
2087 case WI_RID_DESIRED_SSID:
2088 wi_request_fill_ssid(wreq, &sc->wi_netid);
2089 break;
2090 case WI_RID_OWN_SSID:
2091 wi_request_fill_ssid(wreq, &sc->wi_ibssid);
2092 break;
2093 case WI_RID_PM_ENABLED:
2094 wreq->wi_val[0] = htole16(sc->wi_pm_enabled);
2095 break;
2096 case WI_RID_MICROWAVE_OVEN:
2097 wreq->wi_val[0] = htole16(sc->wi_mor_enabled);
2098 break;
2099 case WI_RID_MAX_SLEEP:
2100 wreq->wi_val[0] = htole16(sc->wi_max_sleep);
2101 break;
2102 case WI_RID_CNFAUTHMODE:
2103 wreq->wi_val[0] = htole16(sc->wi_authtype);
2104 break;
2105 case WI_RID_ROAMING_MODE:
2106 wreq->wi_val[0] = htole16(sc->wi_roaming);
2107 break;
2108 case WI_RID_WEP_AVAIL:
2109 wreq->wi_val[0] = (sc->wi_flags & WI_FLAGS_HAS_WEP) ?
2110 htole16(1) : htole16(0);
2111 break;
2112 case WI_RID_ENCRYPTION:
2113 wreq->wi_val[0] = htole16(sc->wi_use_wep);
2114 break;
2115 case WI_RID_TX_CRYPT_KEY:
2116 wreq->wi_val[0] = htole16(sc->wi_tx_key);
2117 break;
2118 case WI_RID_DEFLT_CRYPT_KEYS:
2119 wreq->wi_len += sizeof(struct wi_ltv_keys) / 2 - 1;
2120 memcpy(wreq, &sc->wi_keys, sizeof(struct wi_ltv_keys));
2121 break;
2122 default:
2123 #if 0
2124 error = EIO;
2125 #else
2126 #ifdef WI_DEBUG
2127 printf("%s: wi_getdef: unknown request %d\n",
2128 sc->sc_dev.dv_xname, wreq->wi_type);
2129 #endif
2130 #endif
2131 break;
2132 }
2133
2134 return (error);
2135 }
2136
2137 static int
2138 wi_ioctl(ifp, command, data)
2139 struct ifnet *ifp;
2140 u_long command;
2141 caddr_t data;
2142 {
2143 int s, error = 0;
2144 int len;
2145 struct wi_softc *sc = ifp->if_softc;
2146 struct wi_req wreq;
2147 struct ifreq *ifr;
2148 struct proc *p = curproc;
2149 struct ieee80211_nwid nwid;
2150
2151 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
2152 return (ENXIO);
2153
2154 s = splnet();
2155
2156 ifr = (struct ifreq *)data;
2157
2158 if (!sc->sc_attached) {
2159 splx(s);
2160 return(ENODEV);
2161 }
2162
2163 switch(command) {
2164 case SIOCSWAVELAN:
2165 case SIOCS80211NWID:
2166 case SIOCS80211NWKEY:
2167 case SIOCS80211POWER:
2168 case SIOCS80211BSSID:
2169 case SIOCS80211CHANNEL:
2170 error = suser(p->p_ucred, &p->p_acflag);
2171 if (error) {
2172 splx(s);
2173 return (error);
2174 }
2175 default:
2176 break;
2177 }
2178
2179 switch (command) {
2180 case SIOCSIFADDR:
2181 case SIOCGIFADDR:
2182 case SIOCSIFMTU:
2183 error = ether_ioctl(ifp, command, data);
2184 break;
2185 case SIOCSIFFLAGS:
2186 if (ifp->if_flags & IFF_UP) {
2187 if (ifp->if_flags & IFF_RUNNING &&
2188 ifp->if_flags & IFF_PROMISC &&
2189 !(sc->wi_if_flags & IFF_PROMISC)) {
2190 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
2191 WI_SETVAL(WI_RID_PROMISC, 1);
2192 } else if (ifp->if_flags & IFF_RUNNING &&
2193 !(ifp->if_flags & IFF_PROMISC) &&
2194 sc->wi_if_flags & IFF_PROMISC) {
2195 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
2196 WI_SETVAL(WI_RID_PROMISC, 0);
2197 } else
2198 wi_init(ifp);
2199 } else if (ifp->if_flags & IFF_RUNNING)
2200 wi_stop(ifp, 0);
2201 sc->wi_if_flags = ifp->if_flags;
2202
2203 if (!(ifp->if_flags & IFF_UP)) {
2204 if (sc->sc_enabled) {
2205 if (sc->sc_disable)
2206 (*sc->sc_disable)(sc);
2207 sc->sc_enabled = 0;
2208 ifp->if_flags &= ~IFF_RUNNING;
2209 }
2210 }
2211 error = 0;
2212 break;
2213 case SIOCADDMULTI:
2214 case SIOCDELMULTI:
2215 error = (command == SIOCADDMULTI) ?
2216 ether_addmulti(ifr, &sc->sc_ethercom) :
2217 ether_delmulti(ifr, &sc->sc_ethercom);
2218 if (error == ENETRESET) {
2219 if (sc->sc_enabled != 0) {
2220 /*
2221 * Multicast list has changed. Set the
2222 * hardware filter accordingly.
2223 */
2224 wi_setmulti(sc);
2225 }
2226 error = 0;
2227 }
2228 break;
2229 case SIOCSIFMEDIA:
2230 case SIOCGIFMEDIA:
2231 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
2232 break;
2233 case SIOCGWAVELAN:
2234 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
2235 if (error)
2236 break;
2237 if (wreq.wi_len > WI_MAX_DATALEN) {
2238 error = EINVAL;
2239 break;
2240 }
2241 if (wreq.wi_type == WI_RID_IFACE_STATS) {
2242 memcpy((char *)&wreq.wi_val, (char *)&sc->wi_stats,
2243 sizeof(sc->wi_stats));
2244 wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
2245 } else if (wreq.wi_type == WI_RID_READ_APS) {
2246 if (sc->wi_scanning) {
2247 error = EINPROGRESS;
2248 break;
2249 } else {
2250 len = sc->wi_naps * sizeof(struct wi_apinfo);
2251 len = len > WI_MAX_DATALEN ? WI_MAX_DATALEN : len;
2252 len = len / sizeof(struct wi_apinfo);
2253 memcpy((char *)&wreq.wi_val, (char *)&len, sizeof(len));
2254 memcpy((char *)&wreq.wi_val + sizeof(len),
2255 (char *)&sc->wi_aps,
2256 len * sizeof(struct wi_apinfo));
2257 }
2258 } else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) {
2259 /* For non-root user, return all-zeroes keys */
2260 if (suser(p->p_ucred, &p->p_acflag))
2261 memset((char *)&wreq, 0,
2262 sizeof(struct wi_ltv_keys));
2263 else
2264 memcpy((char *)&wreq, (char *)&sc->wi_keys,
2265 sizeof(struct wi_ltv_keys));
2266 } else {
2267 if (sc->sc_enabled == 0 ||
2268 (wreq.wi_type == WI_RID_ROAMING_MODE &&
2269 (sc->wi_flags & WI_FLAGS_HAS_ROAMING) == 0) ||
2270 (wreq.wi_type == WI_RID_CREATE_IBSS &&
2271 (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) == 0) ||
2272 (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
2273 (sc->wi_flags & WI_FLAGS_HAS_MOR) == 0))
2274 error = wi_getdef(sc, &wreq);
2275 else if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq))
2276 error = EINVAL;
2277 }
2278 if (error == 0)
2279 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
2280 break;
2281 case SIOCSWAVELAN:
2282 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
2283 if (error)
2284 break;
2285 error = EINVAL;
2286 if (wreq.wi_len > WI_MAX_DATALEN)
2287 break;
2288 switch (wreq.wi_type) {
2289 case WI_RID_IFACE_STATS:
2290 if (sc->sc_enabled)
2291 wi_inquire(sc);
2292 break;
2293 case WI_RID_MGMT_XMIT:
2294 error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
2295 wreq.wi_len);
2296 break;
2297 case WI_RID_SCAN_APS:
2298 if (wreq.wi_len != 4) {
2299 error = EINVAL;
2300 break;
2301 }
2302 if (!sc->wi_scanning) {
2303 switch (sc->sc_firmware_type) {
2304 case WI_LUCENT:
2305 break;
2306 case WI_INTERSIL:
2307 wreq.wi_type = WI_RID_SCAN_REQ;
2308 error = wi_write_record(sc,
2309 (struct wi_ltv_gen *)&wreq);
2310 break;
2311 case WI_SYMBOL:
2312 /*
2313 * XXX only supported on 3.x ?
2314 */
2315 wreq.wi_type = WI_RID_BCAST_SCAN_REQ;
2316 wreq.wi_val[0] =
2317 BSCAN_BCAST | BSCAN_ONETIME;
2318 wreq.wi_len = 2;
2319 error = wi_write_record(sc,
2320 (struct wi_ltv_gen *)&wreq);
2321 break;
2322 }
2323 if (!error) {
2324 sc->wi_scanning = 1;
2325 callout_reset(&sc->wi_scan_sh, hz * 1,
2326 wi_wait_scan, sc);
2327 }
2328 }
2329 break;
2330 default:
2331 /*
2332 * Filter stuff out based on what the
2333 * card can do.
2334 */
2335 if ((wreq.wi_type == WI_RID_ROAMING_MODE &&
2336 (sc->wi_flags & WI_FLAGS_HAS_ROAMING) == 0) ||
2337 (wreq.wi_type == WI_RID_CREATE_IBSS &&
2338 (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) == 0) ||
2339 (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
2340 (sc->wi_flags & WI_FLAGS_HAS_MOR) == 0))
2341 break;
2342
2343 if (wreq.wi_len > WI_MAX_DATALEN)
2344 error = EINVAL;
2345 else if (sc->sc_enabled != 0)
2346 error = wi_write_record(sc,
2347 (struct wi_ltv_gen *)&wreq);
2348 if (error == 0)
2349 error = wi_setdef(sc, &wreq);
2350 if (error == 0 && sc->sc_enabled != 0)
2351 /* Reinitialize WaveLAN. */
2352 wi_init(ifp);
2353 }
2354 break;
2355 case SIOCS80211BSSID:
2356
2357 if (sc->wi_ptype != WI_PORTTYPE_IBSS &&
2358 sc->wi_ptype != WI_PORTTYPE_BSS) {
2359 error = EINVAL;
2360 break;
2361 }
2362 /* don't join twice. */
2363 if (sc->wi_flags & WI_FLAGS_JOINING) {
2364 error = EAGAIN;
2365 break;
2366 }
2367
2368 (void)memcpy(&sc->wi_join_bssid,
2369 &((struct ieee80211_bssid *)data)->i_bssid,
2370 sizeof(sc->wi_join_bssid));
2371
2372 error = wi_join_bss(sc);
2373 break;
2374 case SIOCG80211BSSID:
2375 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2376 (void)memcpy(&((struct ieee80211_bssid *)data)->i_bssid,
2377 LLADDR(ifp->if_sadl), IEEE80211_ADDR_LEN);
2378 } else {
2379 (void)memcpy(
2380 &((struct ieee80211_bssid *)data)->i_bssid,
2381 &sc->wi_current_bssid,
2382 sizeof(sc->wi_current_bssid));
2383 }
2384 break;
2385 case SIOCS80211CHANNEL:
2386 error = wi_set_channel(sc, ((struct ieee80211_channel *)data));
2387 break;
2388 case SIOCG80211CHANNEL:
2389 error = wi_get_channel(sc, ((struct ieee80211_channel *)data));
2390 break;
2391 case SIOCG80211NWID:
2392 if (sc->sc_enabled == 0) {
2393 /* Return the desired ID */
2394 error = copyout(&sc->wi_netid, ifr->ifr_data,
2395 sizeof(sc->wi_netid));
2396 } else {
2397 wreq.wi_type = WI_RID_CURRENT_SSID;
2398 wreq.wi_len = WI_MAX_DATALEN;
2399 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) ||
2400 le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN)
2401 error = EINVAL;
2402 else {
2403 wi_set_ssid(&nwid, (u_int8_t *)&wreq.wi_val[1],
2404 le16toh(wreq.wi_val[0]));
2405 error = copyout(&nwid, ifr->ifr_data,
2406 sizeof(nwid));
2407 }
2408 }
2409 break;
2410 case SIOCS80211NWID:
2411 error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
2412 if (error != 0)
2413 break;
2414 if (nwid.i_len > IEEE80211_NWID_LEN) {
2415 error = EINVAL;
2416 break;
2417 }
2418 if (sc->wi_netid.i_len == nwid.i_len &&
2419 memcmp(sc->wi_netid.i_nwid, nwid.i_nwid, nwid.i_len) == 0)
2420 break;
2421 wi_set_ssid(&sc->wi_netid, nwid.i_nwid, nwid.i_len);
2422 if (sc->sc_enabled != 0)
2423 /* Reinitialize WaveLAN. */
2424 wi_init(ifp);
2425 break;
2426 case SIOCS80211NWKEY:
2427 error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
2428 break;
2429 case SIOCG80211NWKEY:
2430 error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
2431 break;
2432 case SIOCS80211POWER:
2433 error = wi_set_pm(sc, (struct ieee80211_power *)data);
2434 break;
2435 case SIOCG80211POWER:
2436 error = wi_get_pm(sc, (struct ieee80211_power *)data);
2437 break;
2438 case SIOCHOSTAP_ADD:
2439 case SIOCHOSTAP_DEL:
2440 case SIOCHOSTAP_GET:
2441 case SIOCHOSTAP_GETALL:
2442 case SIOCHOSTAP_GFLAGS:
2443 case SIOCHOSTAP_SFLAGS:
2444 /* Send all Host-AP specific ioctls to the Host-AP code. */
2445 error = wihap_ioctl(sc, command, data);
2446 break;
2447
2448 default:
2449 error = EINVAL;
2450 break;
2451 }
2452
2453 splx(s);
2454 return (error);
2455 }
2456
2457 static int
2458 wi_init(ifp)
2459 struct ifnet *ifp;
2460 {
2461 struct wi_softc *sc = ifp->if_softc;
2462 struct wi_req wreq;
2463 struct wi_ltv_macaddr mac;
2464 int s, error, id = 0, wasenabled;
2465
2466 if (!sc->sc_attached)
2467 return(ENODEV);
2468
2469 s = splnet();
2470 wasenabled = sc->sc_enabled;
2471 if (!sc->sc_enabled) {
2472 if ((error = (*sc->sc_enable)(sc)) != 0)
2473 goto out;
2474 sc->sc_enabled = 1;
2475 }
2476
2477 wi_stop(ifp, 0);
2478 /* Symbol firmware cannot be initialized more than once */
2479 if (!(sc->sc_firmware_type == WI_SYMBOL && wasenabled))
2480 wi_reset(sc);
2481
2482 /* Program max data length. */
2483 WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
2484
2485 /* Enable/disable IBSS creation. */
2486 WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
2487
2488 /* Set the port type. */
2489 WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
2490
2491 /* Program the RTS/CTS threshold. */
2492 WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
2493
2494 /* Program the TX rate */
2495 WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
2496
2497 /* Access point density */
2498 WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
2499
2500 /* Power Management Enabled */
2501 WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
2502
2503 /* Power Managment Max Sleep */
2504 WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
2505
2506 /* Roaming type */
2507 if (sc->wi_flags & WI_FLAGS_HAS_ROAMING)
2508 WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
2509
2510 /* Specify the network name */
2511 wi_write_ssid(sc, WI_RID_DESIRED_SSID, &wreq, &sc->wi_netid);
2512
2513 /* Specify the IBSS name */
2514 if (sc->wi_netid.i_len != 0 &&
2515 (sc->wi_ptype == WI_PORTTYPE_HOSTAP ||
2516 (sc->wi_create_ibss && sc->wi_ptype == WI_PORTTYPE_IBSS)))
2517 wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_netid);
2518 else
2519 wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_ibssid);
2520
2521 /* Specify the frequency to use */
2522 WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_create_channel);
2523
2524 /* Program the nodename. */
2525 wi_write_ssid(sc, WI_RID_NODENAME, &wreq, &sc->wi_nodeid);
2526
2527 /* Set our MAC address. */
2528 mac.wi_len = 4;
2529 mac.wi_type = WI_RID_MAC_NODE;
2530 memcpy(&mac.wi_mac_addr, sc->sc_macaddr, ETHER_ADDR_LEN);
2531 wi_write_record(sc, (struct wi_ltv_gen *)&mac);
2532
2533 /*
2534 * Initialize promiscuous mode.
2535 * Being in the Host-AP mode causes a great
2536 * deal of pain if promiscuous mode is set.
2537 * Therefore we avoid confusing the firmware
2538 * and always reset promiscuous mode in Host-AP
2539 * mode. Host-AP sees all the packets anyway.
2540 */
2541 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP &&
2542 (ifp->if_flags & IFF_PROMISC) != 0) {
2543 WI_SETVAL(WI_RID_PROMISC, 1);
2544 } else {
2545 WI_SETVAL(WI_RID_PROMISC, 0);
2546 }
2547
2548 /* Configure WEP. */
2549 if (sc->wi_flags & WI_FLAGS_HAS_WEP) {
2550 WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
2551 WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
2552 sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
2553 sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
2554 wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
2555 if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
2556 /*
2557 * ONLY HWB3163 EVAL-CARD Firmware version
2558 * less than 0.8 variant2
2559 *
2560 * If promiscuous mode disable, Prism2 chip
2561 * does not work with WEP .
2562 * It is under investigation for details.
2563 * (ichiro (at) netbsd.org)
2564 */
2565 if (sc->sc_firmware_type == WI_INTERSIL &&
2566 sc->sc_sta_firmware_ver < 802 ) {
2567 /* firm ver < 0.8 variant 2 */
2568 WI_SETVAL(WI_RID_PROMISC, 1);
2569 }
2570 WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype);
2571 }
2572 }
2573
2574 /* Set multicast filter. */
2575 wi_setmulti(sc);
2576
2577 sc->wi_flags &= ~(WI_FLAGS_JOINING | WI_FLAGS_CONNECTED |
2578 WI_FLAGS_AP_IN_RANGE);
2579
2580 /* Enable desired port */
2581 wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0);
2582
2583 /* scanning variable is modal, therefore reinit to OFF, in case it was on. */
2584 sc->wi_scanning=0;
2585 sc->wi_naps=0;
2586
2587 if ((error = wi_alloc_nicmem(sc, WI_TX_BUFSIZE, &id)) != 0) {
2588 printf("%s: tx buffer allocation failed\n",
2589 sc->sc_dev.dv_xname);
2590 goto out;
2591 }
2592 sc->wi_tx_data_id = id;
2593
2594 if ((error = wi_alloc_nicmem(sc, WI_TX_BUFSIZE, &id)) != 0) {
2595 printf("%s: mgmt. buffer allocation failed\n",
2596 sc->sc_dev.dv_xname);
2597 goto out;
2598 }
2599 sc->wi_tx_mgmt_id = id;
2600
2601 /* Enable interrupts */
2602 CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
2603
2604 wihap_init(sc);
2605
2606 out:
2607 if (error) {
2608 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
2609 ifp->if_timer = 0;
2610 printf("%s: interface not running\n", sc->sc_dev.dv_xname);
2611 splx(s);
2612 return error;
2613 }
2614
2615 ifp->if_flags |= IFF_RUNNING;
2616 ifp->if_flags &= ~IFF_OACTIVE;
2617
2618 callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
2619
2620 splx(s);
2621 return 0;
2622 }
2623
2624 static const u_int32_t crc32_tab[] = {
2625 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
2626 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
2627 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
2628 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
2629 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
2630 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
2631 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
2632 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
2633 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
2634 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
2635 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
2636 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
2637 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
2638 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
2639 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
2640 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
2641 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
2642 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
2643 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
2644 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
2645 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
2646 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
2647 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
2648 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
2649 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
2650 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
2651 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
2652 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
2653 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
2654 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
2655 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
2656 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
2657 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
2658 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
2659 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
2660 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
2661 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
2662 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
2663 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
2664 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
2665 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
2666 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
2667 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
2668 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
2669 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
2670 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
2671 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
2672 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
2673 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
2674 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
2675 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
2676 0x2d02ef8dL
2677 };
2678
2679 #define RC4STATE 256
2680 #define RC4KEYLEN 16
2681 #define RC4SWAP(x,y) \
2682 do { u_int8_t t = state[x]; state[x] = state[y]; state[y] = t; } while(0)
2683
2684 static void
2685 wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len)
2686 {
2687 u_int32_t i, crc, klen;
2688 u_int8_t state[RC4STATE], key[RC4KEYLEN];
2689 u_int8_t x, y, *dat;
2690
2691 if (!sc->wi_icv_flag) {
2692 sc->wi_icv = arc4random();
2693 sc->wi_icv_flag++;
2694 } else
2695 sc->wi_icv++;
2696 /*
2697 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
2698 * (B, 255, N) with 3 <= B < 8
2699 */
2700 if (sc->wi_icv >= 0x03ff00 &&
2701 (sc->wi_icv & 0xf8ff00) == 0x00ff00)
2702 sc->wi_icv += 0x000100;
2703
2704 /* prepend 24bit IV to tx key, byte order does not matter */
2705 key[0] = sc->wi_icv >> 16;
2706 key[1] = sc->wi_icv >> 8;
2707 key[2] = sc->wi_icv;
2708
2709 klen = le16toh(sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen) +
2710 IEEE80211_WEP_IVLEN;
2711 klen = (klen >= RC4KEYLEN) ? RC4KEYLEN : RC4KEYLEN/2;
2712 bcopy((char *)&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat,
2713 (char *)key + IEEE80211_WEP_IVLEN, klen - IEEE80211_WEP_IVLEN);
2714
2715 /* rc4 keysetup */
2716 x = y = 0;
2717 for (i = 0; i < RC4STATE; i++)
2718 state[i] = i;
2719 for (i = 0; i < RC4STATE; i++) {
2720 y = (key[x] + state[i] + y) % RC4STATE;
2721 RC4SWAP(i, y);
2722 x = (x + 1) % klen;
2723 }
2724
2725 /* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */
2726 dat = buf;
2727 dat[0] = key[0];
2728 dat[1] = key[1];
2729 dat[2] = key[2];
2730 dat[3] = sc->wi_tx_key << 6; /* pad and keyid */
2731 dat += 4;
2732
2733 /* compute rc4 over data, crc32 over data */
2734 crc = ~0;
2735 x = y = 0;
2736 for (i = 0; i < len; i++) {
2737 x = (x + 1) % RC4STATE;
2738 y = (state[x] + y) % RC4STATE;
2739 RC4SWAP(x, y);
2740 crc = crc32_tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8);
2741 dat[i] ^= state[(state[x] + state[y]) % RC4STATE];
2742 }
2743 crc = ~crc;
2744 dat += len;
2745
2746 /* append little-endian crc32 and encrypt */
2747 dat[0] = crc;
2748 dat[1] = crc >> 8;
2749 dat[2] = crc >> 16;
2750 dat[3] = crc >> 24;
2751 for (i = 0; i < IEEE80211_WEP_CRCLEN; i++) {
2752 x = (x + 1) % RC4STATE;
2753 y = (state[x] + y) % RC4STATE;
2754 RC4SWAP(x, y);
2755 dat[i] ^= state[(state[x] + state[y]) % RC4STATE];
2756 }
2757 }
2758
2759 static void
2760 wi_start(ifp)
2761 struct ifnet *ifp;
2762 {
2763 struct wi_softc *sc;
2764 struct mbuf *m0;
2765 struct ether_header *eh;
2766 int id;
2767 int len;
2768 struct wi_frame *hdr;
2769 struct llc *llc;
2770 u_int8_t *body, *payload;
2771 #if defined(WI_HOSTAP_POWERSAVE)
2772 int more_data = 0;
2773 #endif
2774
2775 sc = ifp->if_softc;
2776
2777 if (!sc->sc_attached)
2778 return;
2779
2780 if (ifp->if_flags & IFF_OACTIVE)
2781 return;
2782
2783 /* discard packets when disconnected. postpone sending packets when
2784 * connected but out of range.
2785 */
2786 if (!(sc->wi_flags & WI_FLAGS_AP_IN_RANGE) &&
2787 (sc->wi_flags & WI_FLAGS_CONNECTED)) {
2788 return;
2789 }
2790 hdr = (struct wi_frame *)&sc->wi_txbuf;
2791
2792 body = (u_int8_t *)(hdr + 1);
2793
2794 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
2795 llc = (struct llc *)(body + IEEE80211_WEP_IVLEN +
2796 IEEE80211_WEP_KIDLEN);
2797 } else {
2798 llc = (struct llc *)body;
2799 }
2800
2801 payload = (u_int8_t *)(llc + 1);
2802
2803 nextpkt:
2804 #if defined(WI_HOSTAP_POWERSAVE)
2805 /* power-save queue, first. */
2806 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
2807 m0 = wihap_dequeue(&sc->wi_hostap_info, &more_data);
2808
2809 if (m0 == NULL)
2810 #endif /* WI_HOSTAP_POWERSAVE */
2811 IFQ_DEQUEUE(&ifp->if_snd, m0);
2812
2813 if (m0 == NULL)
2814 return;
2815
2816 bzero(hdr, sizeof(*hdr));
2817 hdr->wi_frame_ctl = htole16(WI_FTYPE_DATA);
2818 id = sc->wi_tx_data_id;
2819 eh = mtod(m0, struct ether_header *);
2820
2821 #if defined(OPTIMIZE_RW_DATA)
2822 wi_rewind(sc);
2823 #endif
2824
2825 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2826 if (wihap_check_tx(sc, m0, &hdr->wi_tx_rate) == 0)
2827 goto nextpkt;
2828 #if defined(WI_HOSTAP_POWERSAVE)
2829 if (more_data)
2830 hdr->wi_frame_ctl |= htole16(WI_FCTL_PM);
2831 #endif /* WI_HOSTAP_POWERSAVE */
2832 }
2833
2834 /*
2835 * Use RFC1042 encoding for everything.
2836 */
2837
2838 hdr->wi_tx_ctl |= htole16(WI_ENC_TX_802_11);
2839
2840 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2841 hdr->wi_frame_ctl |= htole16(WI_FCTL_FROMDS);
2842 memcpy(&hdr->wi_addr1, &eh->ether_dhost,
2843 IEEE80211_ADDR_LEN);
2844 memcpy(&hdr->wi_addr2, LLADDR(ifp->if_sadl),
2845 IEEE80211_ADDR_LEN);
2846 memcpy((char *)&hdr->wi_addr3,
2847 (char *)&eh->ether_shost, IEEE80211_ADDR_LEN);
2848 } else {
2849 if (sc->wi_ptype == WI_PORTTYPE_BSS) {
2850 hdr->wi_frame_ctl |= htole16(WI_FCTL_TODS);
2851 memcpy(&hdr->wi_addr1, &sc->wi_current_bssid,
2852 IEEE80211_ADDR_LEN);
2853 memcpy(&hdr->wi_addr3, &eh->ether_dhost,
2854 IEEE80211_ADDR_LEN);
2855 } else {
2856 memcpy(&hdr->wi_addr1, &eh->ether_dhost,
2857 IEEE80211_ADDR_LEN);
2858 memcpy(&hdr->wi_addr3, &sc->wi_current_bssid,
2859 IEEE80211_ADDR_LEN);
2860 }
2861 memcpy(&hdr->wi_addr2, &eh->ether_shost,
2862 IEEE80211_ADDR_LEN);
2863 }
2864
2865 len = sizeof(struct llc) - sizeof(struct ether_header) +
2866 m0->m_pkthdr.len;
2867
2868 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
2869 llc->llc_control = LLC_UI;
2870 llc->llc_snap.org_code[0] = 0;
2871 llc->llc_snap.org_code[1] = 0;
2872 llc->llc_snap.org_code[2] = 0;
2873 llc->llc_snap.ether_type = eh->ether_type;
2874
2875 m_copydata(m0, sizeof(struct ether_header),
2876 m0->m_pkthdr.len - sizeof(struct ether_header),
2877 payload);
2878
2879 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
2880
2881 hdr->wi_frame_ctl |= htole16(WI_FCTL_WEP);
2882
2883 wi_do_hostencrypt(sc, body, len);
2884
2885 len += IEEE80211_WEP_IVLEN +
2886 IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
2887 }
2888
2889 hdr->wi_dat_len = htole16(len);
2890
2891 wi_write_data(sc, id, 0, (caddr_t)&sc->wi_txbuf,
2892 sizeof(struct wi_frame) + len);
2893
2894 #if NBPFILTER > 0
2895 /*
2896 * If there's a BPF listener, bounce a copy of
2897 * this frame to him.
2898 */
2899 wi_tap_802_3(sc, m0, hdr);
2900 #endif
2901
2902 m_freem(m0);
2903
2904 if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
2905 printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
2906
2907 ifp->if_flags |= IFF_OACTIVE;
2908
2909 /*
2910 * Set a timeout in case the chip goes out to lunch.
2911 */
2912 ifp->if_timer = 5;
2913
2914 return;
2915 }
2916
2917 int
2918 wi_mgmt_xmit(sc, data, len)
2919 struct wi_softc *sc;
2920 caddr_t data;
2921 int len;
2922 {
2923 struct wi_frame *tx_frame;
2924 int id;
2925 struct wi_80211_hdr *hdr;
2926 caddr_t dptr;
2927 struct mbuf *m0, *m1;
2928
2929 #if defined(OPTIMIZE_RW_DATA)
2930 wi_rewind(sc);
2931 #endif
2932
2933 if (!sc->sc_attached)
2934 return(ENODEV);
2935
2936 KASSERT(MHLEN >= sizeof(*tx_frame));
2937
2938 MGETHDR(m0, M_DONTWAIT, MT_DATA);
2939 if (m0 == NULL)
2940 return (ENOMEM);
2941 MGET(m1, M_DONTWAIT, MT_DATA);
2942 if (m1 == NULL) {
2943 m_free(m0);
2944 return (ENOMEM);
2945 }
2946
2947 tx_frame = mtod(m0, struct wi_frame *);
2948 memset(tx_frame, 0, sizeof(*tx_frame));
2949
2950 hdr = (struct wi_80211_hdr *)data;
2951 dptr = data + sizeof(struct wi_80211_hdr);
2952
2953 id = sc->wi_tx_mgmt_id;
2954
2955 memcpy(&tx_frame->wi_frame_ctl, hdr, sizeof(struct wi_80211_hdr));
2956
2957 tx_frame->wi_tx_ctl |= htole16(WI_ENC_TX_802_11);
2958 tx_frame->wi_dat_len = len - sizeof(struct wi_80211_hdr);
2959 tx_frame->wi_len = htole16(tx_frame->wi_dat_len);
2960
2961 tx_frame->wi_dat_len = htole16(tx_frame->wi_dat_len);
2962
2963 wi_write_data(sc, id, 0, (caddr_t)tx_frame, sizeof(*tx_frame));
2964 wi_write_data(sc, id, sizeof(*tx_frame), dptr,
2965 (len - sizeof(struct wi_80211_hdr)));
2966
2967 m0->m_len = WI_SHORT_802_11_END; /* XXX */
2968 m0->m_next = m1;
2969 m1->m_data = dptr; /* XXX */
2970 m1->m_len = len - sizeof(struct wi_80211_hdr);
2971 m1->m_next = 0;
2972
2973 m0->m_pkthdr.len = m0->m_len + m1->m_len;
2974
2975 wi_tap_802_11_plus(sc, m0);
2976
2977 m_freem(m0);
2978
2979 if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) {
2980 printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
2981 return(EIO);
2982 }
2983
2984 return(0);
2985 }
2986
2987 static void
2988 wi_stop(ifp, disable)
2989 struct ifnet *ifp;
2990 {
2991 struct wi_softc *sc = ifp->if_softc;
2992
2993 wihap_shutdown(sc);
2994
2995 if (!sc->sc_attached)
2996 return;
2997
2998 CSR_WRITE_2(sc, WI_INT_EN, 0);
2999 wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0);
3000
3001 callout_stop(&sc->wi_inquire_ch);
3002 callout_stop(&sc->wi_scan_sh);
3003
3004 if (disable) {
3005 if (sc->sc_enabled) {
3006 if (sc->sc_disable)
3007 (*sc->sc_disable)(sc);
3008 sc->sc_enabled = 0;
3009 }
3010 }
3011
3012 ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
3013 ifp->if_timer = 0;
3014 }
3015
3016 static void
3017 wi_watchdog(ifp)
3018 struct ifnet *ifp;
3019 {
3020 struct wi_softc *sc;
3021
3022 sc = ifp->if_softc;
3023
3024 printf("%s: device timeout\n", sc->sc_dev.dv_xname);
3025
3026 wi_init(ifp);
3027
3028 ifp->if_oerrors++;
3029
3030 return;
3031 }
3032
3033 void
3034 wi_shutdown(sc)
3035 struct wi_softc *sc;
3036 {
3037 int s;
3038
3039 s = splnet();
3040 if (sc->sc_enabled) {
3041 if (sc->sc_disable)
3042 (*sc->sc_disable)(sc);
3043 sc->sc_enabled = 0;
3044 }
3045 wi_stop(&sc->sc_ethercom.ec_if, 0);
3046
3047 splx(s);
3048 }
3049
3050 int
3051 wi_activate(self, act)
3052 struct device *self;
3053 enum devact act;
3054 {
3055 struct wi_softc *sc = (struct wi_softc *)self;
3056 int rv = 0, s;
3057
3058 s = splnet();
3059 switch (act) {
3060 case DVACT_ACTIVATE:
3061 rv = EOPNOTSUPP;
3062 break;
3063
3064 case DVACT_DEACTIVATE:
3065 if_deactivate(&sc->sc_ethercom.ec_if);
3066 break;
3067 }
3068 splx(s);
3069 return (rv);
3070 }
3071
3072 static void
3073 wi_get_id(sc)
3074 struct wi_softc *sc;
3075 {
3076 struct wi_ltv_ver ver;
3077 struct wi_card_ident *id;
3078
3079 /* getting chip identity */
3080 memset(&ver, 0, sizeof(ver));
3081 ver.wi_type = WI_RID_CARD_ID;
3082 ver.wi_len = 5;
3083 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
3084 printf("%s: using ", sc->sc_dev.dv_xname);
3085
3086 sc->sc_firmware_type = WI_NOTYPE;
3087 for (id = wi_card_ident; id->card_name != NULL; id++) {
3088 if (le16toh(ver.wi_ver[0]) == id->card_id) {
3089 printf("%s", id->card_name);
3090 sc->sc_firmware_type = id->firm_type;
3091 break;
3092 }
3093 }
3094 if (sc->sc_firmware_type == WI_NOTYPE) {
3095 if (le16toh(ver.wi_ver[0]) & 0x8000) {
3096 printf("Unknown PRISM2 chip");
3097 sc->sc_firmware_type = WI_INTERSIL;
3098 } else {
3099 printf("Unknown Lucent chip");
3100 sc->sc_firmware_type = WI_LUCENT;
3101 }
3102 }
3103
3104 /* get primary firmware version (Only Prism chips) */
3105 if (sc->sc_firmware_type != WI_LUCENT) {
3106 memset(&ver, 0, sizeof(ver));
3107 ver.wi_type = WI_RID_PRI_IDENTITY;
3108 ver.wi_len = 5;
3109 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
3110 LE16TOH(ver.wi_ver[1]);
3111 LE16TOH(ver.wi_ver[2]);
3112 LE16TOH(ver.wi_ver[3]);
3113 sc->sc_pri_firmware_ver = ver.wi_ver[2] * 10000 +
3114 ver.wi_ver[3] * 100 + ver.wi_ver[1];
3115 }
3116
3117 /* get station firmware version */
3118 memset(&ver, 0, sizeof(ver));
3119 ver.wi_type = WI_RID_STA_IDENTITY;
3120 ver.wi_len = 5;
3121 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
3122 LE16TOH(ver.wi_ver[1]);
3123 LE16TOH(ver.wi_ver[2]);
3124 LE16TOH(ver.wi_ver[3]);
3125 sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
3126 ver.wi_ver[3] * 100 + ver.wi_ver[1];
3127 if (sc->sc_firmware_type == WI_INTERSIL &&
3128 (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
3129 struct wi_ltv_str sver;
3130 char *p;
3131
3132 memset(&sver, 0, sizeof(sver));
3133 sver.wi_type = WI_RID_SYMBOL_IDENTITY;
3134 sver.wi_len = 7;
3135 /* value should be the format like "V2.00-11" */
3136 if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
3137 *(p = (char *)sver.wi_str) >= 'A' &&
3138 p[2] == '.' && p[5] == '-' && p[8] == '\0') {
3139 sc->sc_firmware_type = WI_SYMBOL;
3140 sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
3141 (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
3142 (p[6] - '0') * 10 + (p[7] - '0');
3143 }
3144 }
3145
3146 printf("\n%s: %s Firmware: ", sc->sc_dev.dv_xname,
3147 sc->sc_firmware_type == WI_LUCENT ? "Lucent" :
3148 (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil"));
3149 if (sc->sc_firmware_type != WI_LUCENT) /* XXX */
3150 printf("Primary (%u.%u.%u), ", sc->sc_pri_firmware_ver / 10000,
3151 (sc->sc_pri_firmware_ver % 10000) / 100,
3152 sc->sc_pri_firmware_ver % 100);
3153 printf("Station (%u.%u.%u)\n",
3154 sc->sc_sta_firmware_ver / 10000, (sc->sc_sta_firmware_ver % 10000) / 100,
3155 sc->sc_sta_firmware_ver % 100);
3156
3157 return;
3158 }
3159
3160 int
3161 wi_detach(sc)
3162 struct wi_softc *sc;
3163 {
3164 struct ifnet *ifp = sc->sc_ifp;
3165 int s;
3166
3167 if (!sc->sc_attached)
3168 return (0);
3169
3170 s = splnet();
3171 callout_stop(&sc->wi_inquire_ch);
3172
3173 /* Delete all remaining media. */
3174 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
3175
3176 /* TBD detach all BPF listeners. */
3177 ether_ifdetach(ifp);
3178 if_detach(ifp);
3179 if (sc->sc_enabled) {
3180 if (sc->sc_disable)
3181 (*sc->sc_disable)(sc);
3182 sc->sc_enabled = 0;
3183 }
3184 splx(s);
3185 return (0);
3186 }
3187
3188 void
3189 wi_power(sc, why)
3190 struct wi_softc *sc;
3191 int why;
3192 {
3193 int s;
3194
3195 if (!sc->sc_enabled)
3196 return;
3197
3198 s = splnet();
3199 switch (why) {
3200 case PWR_SUSPEND:
3201 case PWR_STANDBY:
3202 wi_stop(sc->sc_ifp, 0);
3203 if (sc->sc_enabled) {
3204 if (sc->sc_disable)
3205 (*sc->sc_disable)(sc);
3206 }
3207 break;
3208 case PWR_RESUME:
3209 sc->sc_enabled = 0;
3210 wi_init(sc->sc_ifp);
3211 (void)wi_intr(sc);
3212 break;
3213 case PWR_SOFTSUSPEND:
3214 case PWR_SOFTSTANDBY:
3215 case PWR_SOFTRESUME:
3216 break;
3217 }
3218 splx(s);
3219 }
3220
3221 static int
3222 wi_set_ssid(ws, id, len)
3223 struct ieee80211_nwid *ws;
3224 u_int8_t *id;
3225 int len;
3226 {
3227
3228 if (len > IEEE80211_NWID_LEN)
3229 return (EINVAL);
3230 ws->i_len = len;
3231 memcpy(ws->i_nwid, id, len);
3232 return (0);
3233 }
3234
3235 static void
3236 wi_request_fill_ssid(wreq, ws)
3237 struct wi_req *wreq;
3238 struct ieee80211_nwid *ws;
3239 {
3240 int len = ws->i_len;
3241
3242 memset(&wreq->wi_val[0], 0, sizeof(wreq->wi_val));
3243 wreq->wi_val[0] = htole16(len);
3244 wreq->wi_len = roundup(len, 2) / 2 + 2;
3245 memcpy(&wreq->wi_val[1], ws->i_nwid, len);
3246 }
3247
3248 static int
3249 wi_write_ssid(sc, type, wreq, ws)
3250 struct wi_softc *sc;
3251 int type;
3252 struct wi_req *wreq;
3253 struct ieee80211_nwid *ws;
3254 {
3255
3256 wreq->wi_type = type;
3257 wi_request_fill_ssid(wreq, ws);
3258 return (wi_write_record(sc, (struct wi_ltv_gen *)wreq));
3259 }
3260
3261 static int
3262 wi_sync_media(sc, ptype, txrate)
3263 struct wi_softc *sc;
3264 int ptype;
3265 int txrate;
3266 {
3267 int media = sc->sc_media.ifm_cur->ifm_media;
3268 int options = IFM_OPTIONS(media);
3269 int subtype;
3270
3271 switch (txrate) {
3272 case 1:
3273 subtype = IFM_IEEE80211_DS1;
3274 break;
3275 case 2:
3276 subtype = IFM_IEEE80211_DS2;
3277 break;
3278 case 3:
3279 subtype = IFM_AUTO;
3280 break;
3281 case 5:
3282 subtype = IFM_IEEE80211_DS5;
3283 break;
3284 case 11:
3285 subtype = IFM_IEEE80211_DS11;
3286 break;
3287 default:
3288 subtype = IFM_MANUAL; /* Unable to represent */
3289 break;
3290 }
3291
3292 options &= ~IFM_OMASK;
3293 switch (ptype) {
3294 case WI_PORTTYPE_BSS:
3295 /* default port type */
3296 break;
3297 case WI_PORTTYPE_ADHOC:
3298 options |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
3299 break;
3300 case WI_PORTTYPE_HOSTAP:
3301 options |= IFM_IEEE80211_HOSTAP;
3302 break;
3303 case WI_PORTTYPE_IBSS:
3304 options |= IFM_IEEE80211_ADHOC;
3305 break;
3306 default:
3307 subtype = IFM_MANUAL; /* Unable to represent */
3308 break;
3309 }
3310 media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
3311 IFM_INST(media));
3312 if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
3313 return (EINVAL);
3314 ifmedia_set(&sc->sc_media, media);
3315 sc->wi_ptype = ptype;
3316 sc->wi_tx_rate = txrate;
3317 return (0);
3318 }
3319
3320 static int
3321 wi_media_change(ifp)
3322 struct ifnet *ifp;
3323 {
3324 struct wi_softc *sc = ifp->if_softc;
3325 int otype = sc->wi_ptype;
3326 int orate = sc->wi_tx_rate;
3327 int ocreate_ibss = sc->wi_create_ibss;
3328
3329 sc->wi_create_ibss = 0;
3330
3331 switch (sc->sc_media.ifm_cur->ifm_media & IFM_OMASK) {
3332 case 0:
3333 sc->wi_ptype = WI_PORTTYPE_BSS;
3334 break;
3335 case IFM_IEEE80211_HOSTAP:
3336 sc->wi_ptype = WI_PORTTYPE_HOSTAP;
3337 break;
3338 case IFM_IEEE80211_ADHOC:
3339 sc->wi_ptype = WI_PORTTYPE_IBSS;
3340 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
3341 sc->wi_create_ibss = 1;
3342 break;
3343 case IFM_IEEE80211_ADHOC | IFM_FLAG0:
3344 sc->wi_ptype = WI_PORTTYPE_ADHOC;
3345 break;
3346 default:
3347 /* Invalid combination. */
3348 sc->wi_create_ibss = ocreate_ibss;
3349 return (EINVAL);
3350 }
3351
3352 switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
3353 case IFM_IEEE80211_DS1:
3354 sc->wi_tx_rate = 1;
3355 break;
3356 case IFM_IEEE80211_DS2:
3357 sc->wi_tx_rate = 2;
3358 break;
3359 case IFM_AUTO:
3360 sc->wi_tx_rate = 3;
3361 break;
3362 case IFM_IEEE80211_DS5:
3363 sc->wi_tx_rate = 5;
3364 break;
3365 case IFM_IEEE80211_DS11:
3366 sc->wi_tx_rate = 11;
3367 break;
3368 }
3369
3370 if (sc->sc_enabled != 0) {
3371 if (otype != sc->wi_ptype ||
3372 orate != sc->wi_tx_rate ||
3373 ocreate_ibss != sc->wi_create_ibss)
3374 wi_init(ifp);
3375 }
3376
3377 ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
3378
3379 return (0);
3380 }
3381
3382 static void
3383 wi_media_status(ifp, imr)
3384 struct ifnet *ifp;
3385 struct ifmediareq *imr;
3386 {
3387 struct wi_req wreq;
3388 struct wi_softc *sc = ifp->if_softc;
3389
3390 if (sc->sc_enabled == 0) {
3391 imr->ifm_active = IFM_IEEE80211|IFM_NONE;
3392 imr->ifm_status = 0;
3393 return;
3394 }
3395
3396 if (sc->wi_tx_rate == 3) {
3397 imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
3398 switch (sc->wi_ptype) {
3399 case WI_PORTTYPE_ADHOC:
3400 imr->ifm_active |= IFM_FLAG0;
3401 /* fall through */
3402 case WI_PORTTYPE_IBSS:
3403 imr->ifm_active |= IFM_IEEE80211_ADHOC;
3404 break;
3405 case WI_PORTTYPE_HOSTAP:
3406 imr->ifm_active |= IFM_IEEE80211_HOSTAP;
3407 break;
3408 default:
3409 /* do nothing for BSS, WDS, or unknown. */
3410 break;
3411 }
3412 wreq.wi_type = WI_RID_CUR_TX_RATE;
3413 wreq.wi_len = WI_MAX_DATALEN;
3414 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) {
3415 switch(wreq.wi_val[0]) {
3416 case 1:
3417 imr->ifm_active |= IFM_IEEE80211_DS1;
3418 break;
3419 case 2:
3420 imr->ifm_active |= IFM_IEEE80211_DS2;
3421 break;
3422 case 6:
3423 imr->ifm_active |= IFM_IEEE80211_DS5;
3424 break;
3425 case 11:
3426 imr->ifm_active |= IFM_IEEE80211_DS11;
3427 break;
3428 }
3429 }
3430 } else {
3431 imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
3432 }
3433
3434 imr->ifm_status = IFM_AVALID;
3435 switch (sc->wi_ptype) {
3436 case WI_PORTTYPE_IBSS:
3437 /*
3438 * XXX: It would be nice if we could give some actually
3439 * useful status like whether we joined another IBSS or
3440 * created one ourselves.
3441 */
3442 /* fall through */
3443 case WI_PORTTYPE_HOSTAP:
3444 imr->ifm_status |= IFM_ACTIVE;
3445 break;
3446 case WI_PORTTYPE_BSS:
3447 default:
3448 #if 0
3449 wreq.wi_type = WI_RID_COMMQUAL;
3450 wreq.wi_len = WI_MAX_DATALEN;
3451 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
3452 wreq.wi_val[0] != 0)
3453 #else
3454 if (sc->wi_flags & WI_FLAGS_CONNECTED)
3455 #endif
3456 imr->ifm_status |= IFM_ACTIVE;
3457 }
3458 }
3459
3460 static int
3461 wi_set_nwkey(sc, nwkey)
3462 struct wi_softc *sc;
3463 struct ieee80211_nwkey *nwkey;
3464 {
3465 int i, error;
3466 size_t len;
3467 struct wi_req wreq;
3468 struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
3469
3470 if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0)
3471 return ENODEV;
3472 if (nwkey->i_defkid <= 0 ||
3473 nwkey->i_defkid > IEEE80211_WEP_NKID)
3474 return EINVAL;
3475 memcpy(wk, &sc->wi_keys, sizeof(*wk));
3476 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
3477 if (nwkey->i_key[i].i_keydat == NULL)
3478 continue;
3479 len = nwkey->i_key[i].i_keylen;
3480 if (len > sizeof(wk->wi_keys[i].wi_keydat))
3481 return EINVAL;
3482 error = copyin(nwkey->i_key[i].i_keydat,
3483 wk->wi_keys[i].wi_keydat, len);
3484 if (error)
3485 return error;
3486 wk->wi_keys[i].wi_keylen = htole16(len);
3487 }
3488
3489 wk->wi_len = (sizeof(*wk) / 2) + 1;
3490 wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
3491 if (sc->sc_enabled != 0) {
3492 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
3493 if (error)
3494 return error;
3495 }
3496 error = wi_setdef(sc, &wreq);
3497 if (error)
3498 return error;
3499
3500 wreq.wi_len = 2;
3501 wreq.wi_type = WI_RID_TX_CRYPT_KEY;
3502 wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
3503 if (sc->sc_enabled != 0) {
3504 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
3505 if (error)
3506 return error;
3507 }
3508 error = wi_setdef(sc, &wreq);
3509 if (error)
3510 return error;
3511
3512 wreq.wi_type = WI_RID_ENCRYPTION;
3513 wreq.wi_val[0] = htole16(nwkey->i_wepon);
3514 if (sc->sc_enabled != 0) {
3515 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
3516 if (error)
3517 return error;
3518 }
3519 error = wi_setdef(sc, &wreq);
3520 if (error)
3521 return error;
3522
3523 if (sc->sc_enabled != 0)
3524 wi_init(&sc->sc_ethercom.ec_if);
3525 return 0;
3526 }
3527
3528 static int
3529 wi_get_nwkey(sc, nwkey)
3530 struct wi_softc *sc;
3531 struct ieee80211_nwkey *nwkey;
3532 {
3533 int i, len, error;
3534 struct wi_ltv_keys *wk = &sc->wi_keys;
3535
3536 if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0)
3537 return ENODEV;
3538 nwkey->i_wepon = sc->wi_use_wep;
3539 nwkey->i_defkid = sc->wi_tx_key + 1;
3540
3541 /* do not show any keys to non-root user */
3542 error = suser(curproc->p_ucred, &curproc->p_acflag);
3543 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
3544 if (nwkey->i_key[i].i_keydat == NULL)
3545 continue;
3546 /* error holds results of suser() for the first time */
3547 if (error)
3548 return error;
3549 len = le16toh(wk->wi_keys[i].wi_keylen);
3550 if (nwkey->i_key[i].i_keylen < len)
3551 return ENOSPC;
3552 nwkey->i_key[i].i_keylen = len;
3553 error = copyout(wk->wi_keys[i].wi_keydat,
3554 nwkey->i_key[i].i_keydat, len);
3555 if (error)
3556 return error;
3557 }
3558 return 0;
3559 }
3560
3561 static int
3562 wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
3563 {
3564
3565 sc->wi_pm_enabled = power->i_enabled;
3566 sc->wi_max_sleep = power->i_maxsleep;
3567
3568 if (sc->sc_enabled)
3569 return (wi_init(&sc->sc_ethercom.ec_if));
3570
3571 return (0);
3572 }
3573
3574 static int
3575 wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
3576 {
3577
3578 power->i_enabled = sc->wi_pm_enabled;
3579 power->i_maxsleep = sc->wi_max_sleep;
3580
3581 return (0);
3582 }
3583
3584 static int
3585 wi_set_channel(struct wi_softc *sc, struct ieee80211_channel *channel)
3586 {
3587 int do_init = 0, error = 0;
3588 if (channel->i_channel != 0 &&
3589 !(sc->wi_channels & (1 << (channel->i_channel - 1)))) {
3590 return EINVAL;
3591 }
3592 switch (sc->wi_ptype) {
3593 default:
3594 case WI_PORTTYPE_IBSS:
3595 case WI_PORTTYPE_ADHOC: /* set channel of BSS to join/create */
3596
3597 if (channel->i_channel != 0 &&
3598 channel->i_channel != sc->wi_create_channel) {
3599 sc->wi_create_channel = channel->i_channel;
3600 if (sc->sc_enabled)
3601 do_init = 1;
3602 }
3603 /* fall through */
3604 case WI_PORTTYPE_BSS: /* set channel of BSS to join */
3605
3606 /* We are warned not to join while a join is pending.
3607 * Our next opportunity comes after a LinkStatus notification.
3608 */
3609 if (sc->wi_flags & WI_FLAGS_JOINING) {
3610 error = EAGAIN;
3611 break;
3612 }
3613 sc->wi_join_channel = channel->i_channel;
3614 error = wi_join_bss(sc);
3615 break;
3616 case WI_PORTTYPE_HOSTAP: /* set channel of BSS to create */
3617 if (channel->i_channel == 0) {
3618 error = EINVAL;
3619 break;
3620 }
3621 if (channel->i_channel == sc->wi_create_channel)
3622 break;
3623 sc->wi_create_channel = channel->i_channel;
3624 if (sc->sc_enabled)
3625 do_init = 1;
3626 break;
3627 }
3628 if (!error && do_init)
3629 error = wi_init(sc->sc_ifp);
3630 return error;
3631 }
3632
3633 static int
3634 wi_get_channel(struct wi_softc *sc, struct ieee80211_channel *channel)
3635 {
3636 switch (sc->wi_ptype) {
3637 default:
3638 case WI_PORTTYPE_IBSS:
3639 case WI_PORTTYPE_ADHOC:
3640 if (!(sc->wi_flags & WI_FLAGS_CONNECTED)) {
3641 /* return channel of BSS to create */
3642 channel->i_channel = sc->wi_create_channel;
3643 break;
3644 }
3645 /* fall through */
3646 case WI_PORTTYPE_BSS:
3647 if (sc->wi_flags & WI_FLAGS_CONNECTED) {
3648 /* return channel of connected BSS */
3649 channel->i_channel = sc->wi_current_channel;
3650 break;
3651 }
3652 /* return channel of BSS to join */
3653 channel->i_channel = sc->wi_join_channel;
3654 break;
3655 case WI_PORTTYPE_HOSTAP:
3656 /* return channel of BSS to create */
3657 channel->i_channel = sc->wi_create_channel;
3658 break;
3659 }
3660 return 0;
3661 }
3662