wi.c revision 1.86 1 /* $NetBSD: wi.c,v 1.86 2002/09/26 23:47:57 martin 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.86 2002/09/26 23:47:57 martin 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 error = 0;
2299 if (wreq.wi_len != 4) {
2300 error = EINVAL;
2301 break;
2302 }
2303 if (!sc->wi_scanning) {
2304 switch (sc->sc_firmware_type) {
2305 case WI_LUCENT:
2306 break;
2307 case WI_INTERSIL:
2308 wreq.wi_type = WI_RID_SCAN_REQ;
2309 error = wi_write_record(sc,
2310 (struct wi_ltv_gen *)&wreq);
2311 break;
2312 case WI_SYMBOL:
2313 /*
2314 * XXX only supported on 3.x ?
2315 */
2316 wreq.wi_type = WI_RID_BCAST_SCAN_REQ;
2317 wreq.wi_val[0] =
2318 BSCAN_BCAST | BSCAN_ONETIME;
2319 wreq.wi_len = 2;
2320 error = wi_write_record(sc,
2321 (struct wi_ltv_gen *)&wreq);
2322 break;
2323 }
2324 if (!error) {
2325 sc->wi_scanning = 1;
2326 callout_reset(&sc->wi_scan_sh, hz * 1,
2327 wi_wait_scan, sc);
2328 }
2329 }
2330 break;
2331 default:
2332 error = 0;
2333 /*
2334 * Filter stuff out based on what the
2335 * card can do.
2336 */
2337 if ((wreq.wi_type == WI_RID_ROAMING_MODE &&
2338 (sc->wi_flags & WI_FLAGS_HAS_ROAMING) == 0) ||
2339 (wreq.wi_type == WI_RID_CREATE_IBSS &&
2340 (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) == 0) ||
2341 (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
2342 (sc->wi_flags & WI_FLAGS_HAS_MOR) == 0))
2343 break;
2344
2345 if (wreq.wi_len > WI_MAX_DATALEN)
2346 error = EINVAL;
2347 else if (sc->sc_enabled != 0)
2348 error = wi_write_record(sc,
2349 (struct wi_ltv_gen *)&wreq);
2350 if (error == 0)
2351 error = wi_setdef(sc, &wreq);
2352 if (error == 0 && sc->sc_enabled != 0)
2353 /* Reinitialize WaveLAN. */
2354 wi_init(ifp);
2355 }
2356 break;
2357 case SIOCS80211BSSID:
2358
2359 if (sc->wi_ptype != WI_PORTTYPE_IBSS &&
2360 sc->wi_ptype != WI_PORTTYPE_BSS) {
2361 error = EINVAL;
2362 break;
2363 }
2364 /* don't join twice. */
2365 if (sc->wi_flags & WI_FLAGS_JOINING) {
2366 error = EAGAIN;
2367 break;
2368 }
2369
2370 (void)memcpy(&sc->wi_join_bssid,
2371 &((struct ieee80211_bssid *)data)->i_bssid,
2372 sizeof(sc->wi_join_bssid));
2373
2374 error = wi_join_bss(sc);
2375 break;
2376 case SIOCG80211BSSID:
2377 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2378 (void)memcpy(&((struct ieee80211_bssid *)data)->i_bssid,
2379 LLADDR(ifp->if_sadl), IEEE80211_ADDR_LEN);
2380 } else {
2381 (void)memcpy(
2382 &((struct ieee80211_bssid *)data)->i_bssid,
2383 &sc->wi_current_bssid,
2384 sizeof(sc->wi_current_bssid));
2385 }
2386 break;
2387 case SIOCS80211CHANNEL:
2388 error = wi_set_channel(sc, ((struct ieee80211_channel *)data));
2389 break;
2390 case SIOCG80211CHANNEL:
2391 error = wi_get_channel(sc, ((struct ieee80211_channel *)data));
2392 break;
2393 case SIOCG80211NWID:
2394 if (sc->sc_enabled == 0) {
2395 /* Return the desired ID */
2396 error = copyout(&sc->wi_netid, ifr->ifr_data,
2397 sizeof(sc->wi_netid));
2398 } else {
2399 wreq.wi_type = WI_RID_CURRENT_SSID;
2400 wreq.wi_len = WI_MAX_DATALEN;
2401 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) ||
2402 le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN)
2403 error = EINVAL;
2404 else {
2405 wi_set_ssid(&nwid, (u_int8_t *)&wreq.wi_val[1],
2406 le16toh(wreq.wi_val[0]));
2407 error = copyout(&nwid, ifr->ifr_data,
2408 sizeof(nwid));
2409 }
2410 }
2411 break;
2412 case SIOCS80211NWID:
2413 error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
2414 if (error != 0)
2415 break;
2416 if (nwid.i_len > IEEE80211_NWID_LEN) {
2417 error = EINVAL;
2418 break;
2419 }
2420 if (sc->wi_netid.i_len == nwid.i_len &&
2421 memcmp(sc->wi_netid.i_nwid, nwid.i_nwid, nwid.i_len) == 0)
2422 break;
2423 wi_set_ssid(&sc->wi_netid, nwid.i_nwid, nwid.i_len);
2424 if (sc->sc_enabled != 0)
2425 /* Reinitialize WaveLAN. */
2426 wi_init(ifp);
2427 break;
2428 case SIOCS80211NWKEY:
2429 error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
2430 break;
2431 case SIOCG80211NWKEY:
2432 error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
2433 break;
2434 case SIOCS80211POWER:
2435 error = wi_set_pm(sc, (struct ieee80211_power *)data);
2436 break;
2437 case SIOCG80211POWER:
2438 error = wi_get_pm(sc, (struct ieee80211_power *)data);
2439 break;
2440 case SIOCHOSTAP_ADD:
2441 case SIOCHOSTAP_DEL:
2442 case SIOCHOSTAP_GET:
2443 case SIOCHOSTAP_GETALL:
2444 case SIOCHOSTAP_GFLAGS:
2445 case SIOCHOSTAP_SFLAGS:
2446 /* Send all Host-AP specific ioctls to the Host-AP code. */
2447 error = wihap_ioctl(sc, command, data);
2448 break;
2449
2450 default:
2451 error = EINVAL;
2452 break;
2453 }
2454
2455 splx(s);
2456 return (error);
2457 }
2458
2459 static int
2460 wi_init(ifp)
2461 struct ifnet *ifp;
2462 {
2463 struct wi_softc *sc = ifp->if_softc;
2464 struct wi_req wreq;
2465 struct wi_ltv_macaddr mac;
2466 int s, error, id = 0, wasenabled;
2467
2468 if (!sc->sc_attached)
2469 return(ENODEV);
2470
2471 s = splnet();
2472 wasenabled = sc->sc_enabled;
2473 if (!sc->sc_enabled) {
2474 if ((error = (*sc->sc_enable)(sc)) != 0)
2475 goto out;
2476 sc->sc_enabled = 1;
2477 }
2478
2479 wi_stop(ifp, 0);
2480 /* Symbol firmware cannot be initialized more than once */
2481 if (!(sc->sc_firmware_type == WI_SYMBOL && wasenabled))
2482 wi_reset(sc);
2483
2484 /* Program max data length. */
2485 WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
2486
2487 /* Enable/disable IBSS creation. */
2488 WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
2489
2490 /* Set the port type. */
2491 WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
2492
2493 /* Program the RTS/CTS threshold. */
2494 WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
2495
2496 /* Program the TX rate */
2497 WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
2498
2499 /* Access point density */
2500 WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
2501
2502 /* Power Management Enabled */
2503 WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
2504
2505 /* Power Managment Max Sleep */
2506 WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
2507
2508 /* Roaming type */
2509 if (sc->wi_flags & WI_FLAGS_HAS_ROAMING)
2510 WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
2511
2512 /* Specify the network name */
2513 wi_write_ssid(sc, WI_RID_DESIRED_SSID, &wreq, &sc->wi_netid);
2514
2515 /* Specify the IBSS name */
2516 if (sc->wi_netid.i_len != 0 &&
2517 (sc->wi_ptype == WI_PORTTYPE_HOSTAP ||
2518 (sc->wi_create_ibss && sc->wi_ptype == WI_PORTTYPE_IBSS)))
2519 wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_netid);
2520 else
2521 wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_ibssid);
2522
2523 /* Specify the frequency to use */
2524 WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_create_channel);
2525
2526 /* Program the nodename. */
2527 wi_write_ssid(sc, WI_RID_NODENAME, &wreq, &sc->wi_nodeid);
2528
2529 /* Set our MAC address. */
2530 mac.wi_len = 4;
2531 mac.wi_type = WI_RID_MAC_NODE;
2532 memcpy(&mac.wi_mac_addr, sc->sc_macaddr, ETHER_ADDR_LEN);
2533 wi_write_record(sc, (struct wi_ltv_gen *)&mac);
2534
2535 /*
2536 * Initialize promiscuous mode.
2537 * Being in the Host-AP mode causes a great
2538 * deal of pain if promiscuous mode is set.
2539 * Therefore we avoid confusing the firmware
2540 * and always reset promiscuous mode in Host-AP
2541 * mode. Host-AP sees all the packets anyway.
2542 */
2543 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP &&
2544 (ifp->if_flags & IFF_PROMISC) != 0) {
2545 WI_SETVAL(WI_RID_PROMISC, 1);
2546 } else {
2547 WI_SETVAL(WI_RID_PROMISC, 0);
2548 }
2549
2550 /* Configure WEP. */
2551 if (sc->wi_flags & WI_FLAGS_HAS_WEP) {
2552 WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
2553 WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
2554 sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
2555 sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
2556 wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
2557 if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
2558 /*
2559 * ONLY HWB3163 EVAL-CARD Firmware version
2560 * less than 0.8 variant2
2561 *
2562 * If promiscuous mode disable, Prism2 chip
2563 * does not work with WEP .
2564 * It is under investigation for details.
2565 * (ichiro (at) netbsd.org)
2566 */
2567 if (sc->sc_firmware_type == WI_INTERSIL &&
2568 sc->sc_sta_firmware_ver < 802 ) {
2569 /* firm ver < 0.8 variant 2 */
2570 WI_SETVAL(WI_RID_PROMISC, 1);
2571 }
2572 WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype);
2573 }
2574 }
2575
2576 /* Set multicast filter. */
2577 wi_setmulti(sc);
2578
2579 sc->wi_flags &= ~(WI_FLAGS_JOINING | WI_FLAGS_CONNECTED |
2580 WI_FLAGS_AP_IN_RANGE);
2581
2582 /* Enable desired port */
2583 wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0);
2584
2585 /* scanning variable is modal, therefore reinit to OFF, in case it was on. */
2586 sc->wi_scanning=0;
2587 sc->wi_naps=0;
2588
2589 if ((error = wi_alloc_nicmem(sc, WI_TX_BUFSIZE, &id)) != 0) {
2590 printf("%s: tx buffer allocation failed\n",
2591 sc->sc_dev.dv_xname);
2592 goto out;
2593 }
2594 sc->wi_tx_data_id = id;
2595
2596 if ((error = wi_alloc_nicmem(sc, WI_TX_BUFSIZE, &id)) != 0) {
2597 printf("%s: mgmt. buffer allocation failed\n",
2598 sc->sc_dev.dv_xname);
2599 goto out;
2600 }
2601 sc->wi_tx_mgmt_id = id;
2602
2603 /* Enable interrupts */
2604 CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
2605
2606 wihap_init(sc);
2607
2608 out:
2609 if (error) {
2610 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
2611 ifp->if_timer = 0;
2612 printf("%s: interface not running\n", sc->sc_dev.dv_xname);
2613 splx(s);
2614 return error;
2615 }
2616
2617 ifp->if_flags |= IFF_RUNNING;
2618 ifp->if_flags &= ~IFF_OACTIVE;
2619
2620 callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
2621
2622 splx(s);
2623 return 0;
2624 }
2625
2626 static const u_int32_t crc32_tab[] = {
2627 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
2628 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
2629 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
2630 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
2631 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
2632 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
2633 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
2634 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
2635 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
2636 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
2637 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
2638 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
2639 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
2640 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
2641 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
2642 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
2643 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
2644 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
2645 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
2646 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
2647 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
2648 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
2649 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
2650 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
2651 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
2652 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
2653 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
2654 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
2655 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
2656 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
2657 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
2658 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
2659 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
2660 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
2661 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
2662 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
2663 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
2664 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
2665 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
2666 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
2667 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
2668 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
2669 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
2670 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
2671 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
2672 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
2673 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
2674 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
2675 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
2676 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
2677 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
2678 0x2d02ef8dL
2679 };
2680
2681 #define RC4STATE 256
2682 #define RC4KEYLEN 16
2683 #define RC4SWAP(x,y) \
2684 do { u_int8_t t = state[x]; state[x] = state[y]; state[y] = t; } while(0)
2685
2686 static void
2687 wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len)
2688 {
2689 u_int32_t i, crc, klen;
2690 u_int8_t state[RC4STATE], key[RC4KEYLEN];
2691 u_int8_t x, y, *dat;
2692
2693 if (!sc->wi_icv_flag) {
2694 sc->wi_icv = arc4random();
2695 sc->wi_icv_flag++;
2696 } else
2697 sc->wi_icv++;
2698 /*
2699 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
2700 * (B, 255, N) with 3 <= B < 8
2701 */
2702 if (sc->wi_icv >= 0x03ff00 &&
2703 (sc->wi_icv & 0xf8ff00) == 0x00ff00)
2704 sc->wi_icv += 0x000100;
2705
2706 /* prepend 24bit IV to tx key, byte order does not matter */
2707 key[0] = sc->wi_icv >> 16;
2708 key[1] = sc->wi_icv >> 8;
2709 key[2] = sc->wi_icv;
2710
2711 klen = le16toh(sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen) +
2712 IEEE80211_WEP_IVLEN;
2713 klen = (klen >= RC4KEYLEN) ? RC4KEYLEN : RC4KEYLEN/2;
2714 bcopy((char *)&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat,
2715 (char *)key + IEEE80211_WEP_IVLEN, klen - IEEE80211_WEP_IVLEN);
2716
2717 /* rc4 keysetup */
2718 x = y = 0;
2719 for (i = 0; i < RC4STATE; i++)
2720 state[i] = i;
2721 for (i = 0; i < RC4STATE; i++) {
2722 y = (key[x] + state[i] + y) % RC4STATE;
2723 RC4SWAP(i, y);
2724 x = (x + 1) % klen;
2725 }
2726
2727 /* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */
2728 dat = buf;
2729 dat[0] = key[0];
2730 dat[1] = key[1];
2731 dat[2] = key[2];
2732 dat[3] = sc->wi_tx_key << 6; /* pad and keyid */
2733 dat += 4;
2734
2735 /* compute rc4 over data, crc32 over data */
2736 crc = ~0;
2737 x = y = 0;
2738 for (i = 0; i < len; i++) {
2739 x = (x + 1) % RC4STATE;
2740 y = (state[x] + y) % RC4STATE;
2741 RC4SWAP(x, y);
2742 crc = crc32_tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8);
2743 dat[i] ^= state[(state[x] + state[y]) % RC4STATE];
2744 }
2745 crc = ~crc;
2746 dat += len;
2747
2748 /* append little-endian crc32 and encrypt */
2749 dat[0] = crc;
2750 dat[1] = crc >> 8;
2751 dat[2] = crc >> 16;
2752 dat[3] = crc >> 24;
2753 for (i = 0; i < IEEE80211_WEP_CRCLEN; i++) {
2754 x = (x + 1) % RC4STATE;
2755 y = (state[x] + y) % RC4STATE;
2756 RC4SWAP(x, y);
2757 dat[i] ^= state[(state[x] + state[y]) % RC4STATE];
2758 }
2759 }
2760
2761 static void
2762 wi_start(ifp)
2763 struct ifnet *ifp;
2764 {
2765 struct wi_softc *sc;
2766 struct mbuf *m0;
2767 struct ether_header *eh;
2768 int id;
2769 int len;
2770 struct wi_frame *hdr;
2771 struct llc *llc;
2772 u_int8_t *body, *payload;
2773 #if defined(WI_HOSTAP_POWERSAVE)
2774 int more_data = 0;
2775 #endif
2776
2777 sc = ifp->if_softc;
2778
2779 if (!sc->sc_attached)
2780 return;
2781
2782 if (ifp->if_flags & IFF_OACTIVE)
2783 return;
2784
2785 /* discard packets when disconnected. postpone sending packets when
2786 * connected but out of range.
2787 */
2788 if (!(sc->wi_flags & WI_FLAGS_AP_IN_RANGE) &&
2789 (sc->wi_flags & WI_FLAGS_CONNECTED)) {
2790 return;
2791 }
2792 hdr = (struct wi_frame *)&sc->wi_txbuf;
2793
2794 body = (u_int8_t *)(hdr + 1);
2795
2796 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
2797 llc = (struct llc *)(body + IEEE80211_WEP_IVLEN +
2798 IEEE80211_WEP_KIDLEN);
2799 } else {
2800 llc = (struct llc *)body;
2801 }
2802
2803 payload = (u_int8_t *)(llc + 1);
2804
2805 nextpkt:
2806 #if defined(WI_HOSTAP_POWERSAVE)
2807 /* power-save queue, first. */
2808 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
2809 m0 = wihap_dequeue(&sc->wi_hostap_info, &more_data);
2810
2811 if (m0 == NULL)
2812 #endif /* WI_HOSTAP_POWERSAVE */
2813 IFQ_DEQUEUE(&ifp->if_snd, m0);
2814
2815 if (m0 == NULL)
2816 return;
2817
2818 bzero(hdr, sizeof(*hdr));
2819 hdr->wi_frame_ctl = htole16(WI_FTYPE_DATA);
2820 id = sc->wi_tx_data_id;
2821 eh = mtod(m0, struct ether_header *);
2822
2823 #if defined(OPTIMIZE_RW_DATA)
2824 wi_rewind(sc);
2825 #endif
2826
2827 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2828 if (wihap_check_tx(sc, m0, &hdr->wi_tx_rate) == 0)
2829 goto nextpkt;
2830 #if defined(WI_HOSTAP_POWERSAVE)
2831 if (more_data)
2832 hdr->wi_frame_ctl |= htole16(WI_FCTL_PM);
2833 #endif /* WI_HOSTAP_POWERSAVE */
2834 }
2835
2836 /*
2837 * Use RFC1042 encoding for everything.
2838 */
2839
2840 hdr->wi_tx_ctl |= htole16(WI_ENC_TX_802_11);
2841
2842 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2843 hdr->wi_frame_ctl |= htole16(WI_FCTL_FROMDS);
2844 memcpy(&hdr->wi_addr1, &eh->ether_dhost,
2845 IEEE80211_ADDR_LEN);
2846 memcpy(&hdr->wi_addr2, LLADDR(ifp->if_sadl),
2847 IEEE80211_ADDR_LEN);
2848 memcpy((char *)&hdr->wi_addr3,
2849 (char *)&eh->ether_shost, IEEE80211_ADDR_LEN);
2850 } else {
2851 if (sc->wi_ptype == WI_PORTTYPE_BSS) {
2852 hdr->wi_frame_ctl |= htole16(WI_FCTL_TODS);
2853 memcpy(&hdr->wi_addr1, &sc->wi_current_bssid,
2854 IEEE80211_ADDR_LEN);
2855 memcpy(&hdr->wi_addr3, &eh->ether_dhost,
2856 IEEE80211_ADDR_LEN);
2857 } else {
2858 memcpy(&hdr->wi_addr1, &eh->ether_dhost,
2859 IEEE80211_ADDR_LEN);
2860 memcpy(&hdr->wi_addr3, &sc->wi_current_bssid,
2861 IEEE80211_ADDR_LEN);
2862 }
2863 memcpy(&hdr->wi_addr2, &eh->ether_shost,
2864 IEEE80211_ADDR_LEN);
2865 }
2866
2867 len = sizeof(struct llc) - sizeof(struct ether_header) +
2868 m0->m_pkthdr.len;
2869
2870 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
2871 llc->llc_control = LLC_UI;
2872 llc->llc_snap.org_code[0] = 0;
2873 llc->llc_snap.org_code[1] = 0;
2874 llc->llc_snap.org_code[2] = 0;
2875 llc->llc_snap.ether_type = eh->ether_type;
2876
2877 m_copydata(m0, sizeof(struct ether_header),
2878 m0->m_pkthdr.len - sizeof(struct ether_header),
2879 payload);
2880
2881 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
2882
2883 hdr->wi_frame_ctl |= htole16(WI_FCTL_WEP);
2884
2885 wi_do_hostencrypt(sc, body, len);
2886
2887 len += IEEE80211_WEP_IVLEN +
2888 IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
2889 }
2890
2891 hdr->wi_dat_len = htole16(len);
2892
2893 wi_write_data(sc, id, 0, (caddr_t)&sc->wi_txbuf,
2894 sizeof(struct wi_frame) + len);
2895
2896 #if NBPFILTER > 0
2897 /*
2898 * If there's a BPF listener, bounce a copy of
2899 * this frame to him.
2900 */
2901 wi_tap_802_3(sc, m0, hdr);
2902 #endif
2903
2904 m_freem(m0);
2905
2906 if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
2907 printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
2908
2909 ifp->if_flags |= IFF_OACTIVE;
2910
2911 /*
2912 * Set a timeout in case the chip goes out to lunch.
2913 */
2914 ifp->if_timer = 5;
2915
2916 return;
2917 }
2918
2919 int
2920 wi_mgmt_xmit(sc, data, len)
2921 struct wi_softc *sc;
2922 caddr_t data;
2923 int len;
2924 {
2925 struct wi_frame *tx_frame;
2926 int id;
2927 struct wi_80211_hdr *hdr;
2928 caddr_t dptr;
2929 struct mbuf *m0, *m1;
2930
2931 #if defined(OPTIMIZE_RW_DATA)
2932 wi_rewind(sc);
2933 #endif
2934
2935 if (!sc->sc_attached)
2936 return(ENODEV);
2937
2938 KASSERT(MHLEN >= sizeof(*tx_frame));
2939
2940 MGETHDR(m0, M_DONTWAIT, MT_DATA);
2941 if (m0 == NULL)
2942 return (ENOMEM);
2943 MGET(m1, M_DONTWAIT, MT_DATA);
2944 if (m1 == NULL) {
2945 m_free(m0);
2946 return (ENOMEM);
2947 }
2948
2949 tx_frame = mtod(m0, struct wi_frame *);
2950 memset(tx_frame, 0, sizeof(*tx_frame));
2951
2952 hdr = (struct wi_80211_hdr *)data;
2953 dptr = data + sizeof(struct wi_80211_hdr);
2954
2955 id = sc->wi_tx_mgmt_id;
2956
2957 memcpy(&tx_frame->wi_frame_ctl, hdr, sizeof(struct wi_80211_hdr));
2958
2959 tx_frame->wi_tx_ctl |= htole16(WI_ENC_TX_802_11);
2960 tx_frame->wi_dat_len = len - sizeof(struct wi_80211_hdr);
2961 tx_frame->wi_len = htole16(tx_frame->wi_dat_len);
2962
2963 tx_frame->wi_dat_len = htole16(tx_frame->wi_dat_len);
2964
2965 wi_write_data(sc, id, 0, (caddr_t)tx_frame, sizeof(*tx_frame));
2966 wi_write_data(sc, id, sizeof(*tx_frame), dptr,
2967 (len - sizeof(struct wi_80211_hdr)));
2968
2969 m0->m_len = WI_SHORT_802_11_END; /* XXX */
2970 m0->m_next = m1;
2971 m1->m_data = dptr; /* XXX */
2972 m1->m_len = len - sizeof(struct wi_80211_hdr);
2973 m1->m_next = 0;
2974
2975 m0->m_pkthdr.len = m0->m_len + m1->m_len;
2976
2977 wi_tap_802_11_plus(sc, m0);
2978
2979 m_freem(m0);
2980
2981 if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) {
2982 printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
2983 return(EIO);
2984 }
2985
2986 return(0);
2987 }
2988
2989 static void
2990 wi_stop(ifp, disable)
2991 struct ifnet *ifp;
2992 {
2993 struct wi_softc *sc = ifp->if_softc;
2994
2995 wihap_shutdown(sc);
2996
2997 if (!sc->sc_attached)
2998 return;
2999
3000 CSR_WRITE_2(sc, WI_INT_EN, 0);
3001 wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0);
3002
3003 callout_stop(&sc->wi_inquire_ch);
3004 callout_stop(&sc->wi_scan_sh);
3005
3006 if (disable) {
3007 if (sc->sc_enabled) {
3008 if (sc->sc_disable)
3009 (*sc->sc_disable)(sc);
3010 sc->sc_enabled = 0;
3011 }
3012 }
3013
3014 ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
3015 ifp->if_timer = 0;
3016 }
3017
3018 static void
3019 wi_watchdog(ifp)
3020 struct ifnet *ifp;
3021 {
3022 struct wi_softc *sc;
3023
3024 sc = ifp->if_softc;
3025
3026 printf("%s: device timeout\n", sc->sc_dev.dv_xname);
3027
3028 wi_init(ifp);
3029
3030 ifp->if_oerrors++;
3031
3032 return;
3033 }
3034
3035 void
3036 wi_shutdown(sc)
3037 struct wi_softc *sc;
3038 {
3039 int s;
3040
3041 s = splnet();
3042 if (sc->sc_enabled) {
3043 if (sc->sc_disable)
3044 (*sc->sc_disable)(sc);
3045 sc->sc_enabled = 0;
3046 wi_stop(&sc->sc_ethercom.ec_if, 0);
3047 }
3048
3049 splx(s);
3050 }
3051
3052 int
3053 wi_activate(self, act)
3054 struct device *self;
3055 enum devact act;
3056 {
3057 struct wi_softc *sc = (struct wi_softc *)self;
3058 int rv = 0, s;
3059
3060 s = splnet();
3061 switch (act) {
3062 case DVACT_ACTIVATE:
3063 rv = EOPNOTSUPP;
3064 break;
3065
3066 case DVACT_DEACTIVATE:
3067 if_deactivate(&sc->sc_ethercom.ec_if);
3068 break;
3069 }
3070 splx(s);
3071 return (rv);
3072 }
3073
3074 static void
3075 wi_get_id(sc)
3076 struct wi_softc *sc;
3077 {
3078 struct wi_ltv_ver ver;
3079 struct wi_card_ident *id;
3080
3081 /* getting chip identity */
3082 memset(&ver, 0, sizeof(ver));
3083 ver.wi_type = WI_RID_CARD_ID;
3084 ver.wi_len = 5;
3085 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
3086 printf("%s: using ", sc->sc_dev.dv_xname);
3087
3088 sc->sc_firmware_type = WI_NOTYPE;
3089 for (id = wi_card_ident; id->card_name != NULL; id++) {
3090 if (le16toh(ver.wi_ver[0]) == id->card_id) {
3091 printf("%s", id->card_name);
3092 sc->sc_firmware_type = id->firm_type;
3093 break;
3094 }
3095 }
3096 if (sc->sc_firmware_type == WI_NOTYPE) {
3097 if (le16toh(ver.wi_ver[0]) & 0x8000) {
3098 printf("Unknown PRISM2 chip");
3099 sc->sc_firmware_type = WI_INTERSIL;
3100 } else {
3101 printf("Unknown Lucent chip");
3102 sc->sc_firmware_type = WI_LUCENT;
3103 }
3104 }
3105
3106 /* get primary firmware version (Only Prism chips) */
3107 if (sc->sc_firmware_type != WI_LUCENT) {
3108 memset(&ver, 0, sizeof(ver));
3109 ver.wi_type = WI_RID_PRI_IDENTITY;
3110 ver.wi_len = 5;
3111 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
3112 LE16TOH(ver.wi_ver[1]);
3113 LE16TOH(ver.wi_ver[2]);
3114 LE16TOH(ver.wi_ver[3]);
3115 sc->sc_pri_firmware_ver = ver.wi_ver[2] * 10000 +
3116 ver.wi_ver[3] * 100 + ver.wi_ver[1];
3117 }
3118
3119 /* get station firmware version */
3120 memset(&ver, 0, sizeof(ver));
3121 ver.wi_type = WI_RID_STA_IDENTITY;
3122 ver.wi_len = 5;
3123 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
3124 LE16TOH(ver.wi_ver[1]);
3125 LE16TOH(ver.wi_ver[2]);
3126 LE16TOH(ver.wi_ver[3]);
3127 sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
3128 ver.wi_ver[3] * 100 + ver.wi_ver[1];
3129 if (sc->sc_firmware_type == WI_INTERSIL &&
3130 (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
3131 struct wi_ltv_str sver;
3132 char *p;
3133
3134 memset(&sver, 0, sizeof(sver));
3135 sver.wi_type = WI_RID_SYMBOL_IDENTITY;
3136 sver.wi_len = 7;
3137 /* value should be the format like "V2.00-11" */
3138 if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
3139 *(p = (char *)sver.wi_str) >= 'A' &&
3140 p[2] == '.' && p[5] == '-' && p[8] == '\0') {
3141 sc->sc_firmware_type = WI_SYMBOL;
3142 sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
3143 (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
3144 (p[6] - '0') * 10 + (p[7] - '0');
3145 }
3146 }
3147
3148 printf("\n%s: %s Firmware: ", sc->sc_dev.dv_xname,
3149 sc->sc_firmware_type == WI_LUCENT ? "Lucent" :
3150 (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil"));
3151 if (sc->sc_firmware_type != WI_LUCENT) /* XXX */
3152 printf("Primary (%u.%u.%u), ", sc->sc_pri_firmware_ver / 10000,
3153 (sc->sc_pri_firmware_ver % 10000) / 100,
3154 sc->sc_pri_firmware_ver % 100);
3155 printf("Station (%u.%u.%u)\n",
3156 sc->sc_sta_firmware_ver / 10000, (sc->sc_sta_firmware_ver % 10000) / 100,
3157 sc->sc_sta_firmware_ver % 100);
3158
3159 return;
3160 }
3161
3162 int
3163 wi_detach(sc)
3164 struct wi_softc *sc;
3165 {
3166 struct ifnet *ifp = sc->sc_ifp;
3167 int s;
3168
3169 if (!sc->sc_attached)
3170 return (0);
3171
3172 s = splnet();
3173 callout_stop(&sc->wi_inquire_ch);
3174
3175 /* Delete all remaining media. */
3176 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
3177
3178 /* TBD detach all BPF listeners. */
3179 ether_ifdetach(ifp);
3180 if_detach(ifp);
3181 if (sc->sc_enabled) {
3182 if (sc->sc_disable)
3183 (*sc->sc_disable)(sc);
3184 sc->sc_enabled = 0;
3185 }
3186 splx(s);
3187 return (0);
3188 }
3189
3190 void
3191 wi_power(sc, why)
3192 struct wi_softc *sc;
3193 int why;
3194 {
3195 int s;
3196
3197 if (!sc->sc_enabled)
3198 return;
3199
3200 s = splnet();
3201 switch (why) {
3202 case PWR_SUSPEND:
3203 case PWR_STANDBY:
3204 wi_stop(sc->sc_ifp, 0);
3205 if (sc->sc_enabled) {
3206 if (sc->sc_disable)
3207 (*sc->sc_disable)(sc);
3208 }
3209 break;
3210 case PWR_RESUME:
3211 sc->sc_enabled = 0;
3212 wi_init(sc->sc_ifp);
3213 (void)wi_intr(sc);
3214 break;
3215 case PWR_SOFTSUSPEND:
3216 case PWR_SOFTSTANDBY:
3217 case PWR_SOFTRESUME:
3218 break;
3219 }
3220 splx(s);
3221 }
3222
3223 static int
3224 wi_set_ssid(ws, id, len)
3225 struct ieee80211_nwid *ws;
3226 u_int8_t *id;
3227 int len;
3228 {
3229
3230 if (len > IEEE80211_NWID_LEN)
3231 return (EINVAL);
3232 ws->i_len = len;
3233 memcpy(ws->i_nwid, id, len);
3234 return (0);
3235 }
3236
3237 static void
3238 wi_request_fill_ssid(wreq, ws)
3239 struct wi_req *wreq;
3240 struct ieee80211_nwid *ws;
3241 {
3242 int len = ws->i_len;
3243
3244 memset(&wreq->wi_val[0], 0, sizeof(wreq->wi_val));
3245 wreq->wi_val[0] = htole16(len);
3246 wreq->wi_len = roundup(len, 2) / 2 + 2;
3247 memcpy(&wreq->wi_val[1], ws->i_nwid, len);
3248 }
3249
3250 static int
3251 wi_write_ssid(sc, type, wreq, ws)
3252 struct wi_softc *sc;
3253 int type;
3254 struct wi_req *wreq;
3255 struct ieee80211_nwid *ws;
3256 {
3257
3258 wreq->wi_type = type;
3259 wi_request_fill_ssid(wreq, ws);
3260 return (wi_write_record(sc, (struct wi_ltv_gen *)wreq));
3261 }
3262
3263 static int
3264 wi_sync_media(sc, ptype, txrate)
3265 struct wi_softc *sc;
3266 int ptype;
3267 int txrate;
3268 {
3269 int media = sc->sc_media.ifm_cur->ifm_media;
3270 int options = IFM_OPTIONS(media);
3271 int subtype;
3272
3273 switch (txrate) {
3274 case 1:
3275 subtype = IFM_IEEE80211_DS1;
3276 break;
3277 case 2:
3278 subtype = IFM_IEEE80211_DS2;
3279 break;
3280 case 3:
3281 subtype = IFM_AUTO;
3282 break;
3283 case 5:
3284 subtype = IFM_IEEE80211_DS5;
3285 break;
3286 case 11:
3287 subtype = IFM_IEEE80211_DS11;
3288 break;
3289 default:
3290 subtype = IFM_MANUAL; /* Unable to represent */
3291 break;
3292 }
3293
3294 options &= ~IFM_OMASK;
3295 switch (ptype) {
3296 case WI_PORTTYPE_BSS:
3297 /* default port type */
3298 break;
3299 case WI_PORTTYPE_ADHOC:
3300 options |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
3301 break;
3302 case WI_PORTTYPE_HOSTAP:
3303 options |= IFM_IEEE80211_HOSTAP;
3304 break;
3305 case WI_PORTTYPE_IBSS:
3306 options |= IFM_IEEE80211_ADHOC;
3307 break;
3308 default:
3309 subtype = IFM_MANUAL; /* Unable to represent */
3310 break;
3311 }
3312 media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
3313 IFM_INST(media));
3314 if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
3315 return (EINVAL);
3316 ifmedia_set(&sc->sc_media, media);
3317 sc->wi_ptype = ptype;
3318 sc->wi_tx_rate = txrate;
3319 return (0);
3320 }
3321
3322 static int
3323 wi_media_change(ifp)
3324 struct ifnet *ifp;
3325 {
3326 struct wi_softc *sc = ifp->if_softc;
3327 int otype = sc->wi_ptype;
3328 int orate = sc->wi_tx_rate;
3329 int ocreate_ibss = sc->wi_create_ibss;
3330
3331 sc->wi_create_ibss = 0;
3332
3333 switch (sc->sc_media.ifm_cur->ifm_media & IFM_OMASK) {
3334 case 0:
3335 sc->wi_ptype = WI_PORTTYPE_BSS;
3336 break;
3337 case IFM_IEEE80211_HOSTAP:
3338 sc->wi_ptype = WI_PORTTYPE_HOSTAP;
3339 break;
3340 case IFM_IEEE80211_ADHOC:
3341 sc->wi_ptype = WI_PORTTYPE_IBSS;
3342 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
3343 sc->wi_create_ibss = 1;
3344 break;
3345 case IFM_IEEE80211_ADHOC | IFM_FLAG0:
3346 sc->wi_ptype = WI_PORTTYPE_ADHOC;
3347 break;
3348 default:
3349 /* Invalid combination. */
3350 sc->wi_create_ibss = ocreate_ibss;
3351 return (EINVAL);
3352 }
3353
3354 switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
3355 case IFM_IEEE80211_DS1:
3356 sc->wi_tx_rate = 1;
3357 break;
3358 case IFM_IEEE80211_DS2:
3359 sc->wi_tx_rate = 2;
3360 break;
3361 case IFM_AUTO:
3362 sc->wi_tx_rate = 3;
3363 break;
3364 case IFM_IEEE80211_DS5:
3365 sc->wi_tx_rate = 5;
3366 break;
3367 case IFM_IEEE80211_DS11:
3368 sc->wi_tx_rate = 11;
3369 break;
3370 }
3371
3372 if (sc->sc_enabled != 0) {
3373 if (otype != sc->wi_ptype ||
3374 orate != sc->wi_tx_rate ||
3375 ocreate_ibss != sc->wi_create_ibss)
3376 wi_init(ifp);
3377 }
3378
3379 ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
3380
3381 return (0);
3382 }
3383
3384 static void
3385 wi_media_status(ifp, imr)
3386 struct ifnet *ifp;
3387 struct ifmediareq *imr;
3388 {
3389 struct wi_req wreq;
3390 struct wi_softc *sc = ifp->if_softc;
3391
3392 if (sc->sc_enabled == 0) {
3393 imr->ifm_active = IFM_IEEE80211|IFM_NONE;
3394 imr->ifm_status = 0;
3395 return;
3396 }
3397
3398 if (sc->wi_tx_rate == 3) {
3399 imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
3400 switch (sc->wi_ptype) {
3401 case WI_PORTTYPE_ADHOC:
3402 imr->ifm_active |= IFM_FLAG0;
3403 /* fall through */
3404 case WI_PORTTYPE_IBSS:
3405 imr->ifm_active |= IFM_IEEE80211_ADHOC;
3406 break;
3407 case WI_PORTTYPE_HOSTAP:
3408 imr->ifm_active |= IFM_IEEE80211_HOSTAP;
3409 break;
3410 default:
3411 /* do nothing for BSS, WDS, or unknown. */
3412 break;
3413 }
3414 wreq.wi_type = WI_RID_CUR_TX_RATE;
3415 wreq.wi_len = WI_MAX_DATALEN;
3416 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) {
3417 switch(wreq.wi_val[0]) {
3418 case 1:
3419 imr->ifm_active |= IFM_IEEE80211_DS1;
3420 break;
3421 case 2:
3422 imr->ifm_active |= IFM_IEEE80211_DS2;
3423 break;
3424 case 6:
3425 imr->ifm_active |= IFM_IEEE80211_DS5;
3426 break;
3427 case 11:
3428 imr->ifm_active |= IFM_IEEE80211_DS11;
3429 break;
3430 }
3431 }
3432 } else {
3433 imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
3434 }
3435
3436 imr->ifm_status = IFM_AVALID;
3437 switch (sc->wi_ptype) {
3438 case WI_PORTTYPE_IBSS:
3439 /*
3440 * XXX: It would be nice if we could give some actually
3441 * useful status like whether we joined another IBSS or
3442 * created one ourselves.
3443 */
3444 /* fall through */
3445 case WI_PORTTYPE_HOSTAP:
3446 imr->ifm_status |= IFM_ACTIVE;
3447 break;
3448 case WI_PORTTYPE_BSS:
3449 default:
3450 #if 0
3451 wreq.wi_type = WI_RID_COMMQUAL;
3452 wreq.wi_len = WI_MAX_DATALEN;
3453 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
3454 wreq.wi_val[0] != 0)
3455 #else
3456 if (sc->wi_flags & WI_FLAGS_CONNECTED)
3457 #endif
3458 imr->ifm_status |= IFM_ACTIVE;
3459 }
3460 }
3461
3462 static int
3463 wi_set_nwkey(sc, nwkey)
3464 struct wi_softc *sc;
3465 struct ieee80211_nwkey *nwkey;
3466 {
3467 int i, error;
3468 size_t len;
3469 struct wi_req wreq;
3470 struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
3471
3472 if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0)
3473 return ENODEV;
3474 if (nwkey->i_defkid <= 0 ||
3475 nwkey->i_defkid > IEEE80211_WEP_NKID)
3476 return EINVAL;
3477 memcpy(wk, &sc->wi_keys, sizeof(*wk));
3478 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
3479 if (nwkey->i_key[i].i_keydat == NULL)
3480 continue;
3481 len = nwkey->i_key[i].i_keylen;
3482 if (len > sizeof(wk->wi_keys[i].wi_keydat))
3483 return EINVAL;
3484 error = copyin(nwkey->i_key[i].i_keydat,
3485 wk->wi_keys[i].wi_keydat, len);
3486 if (error)
3487 return error;
3488 wk->wi_keys[i].wi_keylen = htole16(len);
3489 }
3490
3491 wk->wi_len = (sizeof(*wk) / 2) + 1;
3492 wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
3493 if (sc->sc_enabled != 0) {
3494 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
3495 if (error)
3496 return error;
3497 }
3498 error = wi_setdef(sc, &wreq);
3499 if (error)
3500 return error;
3501
3502 wreq.wi_len = 2;
3503 wreq.wi_type = WI_RID_TX_CRYPT_KEY;
3504 wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
3505 if (sc->sc_enabled != 0) {
3506 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
3507 if (error)
3508 return error;
3509 }
3510 error = wi_setdef(sc, &wreq);
3511 if (error)
3512 return error;
3513
3514 wreq.wi_type = WI_RID_ENCRYPTION;
3515 wreq.wi_val[0] = htole16(nwkey->i_wepon);
3516 if (sc->sc_enabled != 0) {
3517 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
3518 if (error)
3519 return error;
3520 }
3521 error = wi_setdef(sc, &wreq);
3522 if (error)
3523 return error;
3524
3525 if (sc->sc_enabled != 0)
3526 wi_init(&sc->sc_ethercom.ec_if);
3527 return 0;
3528 }
3529
3530 static int
3531 wi_get_nwkey(sc, nwkey)
3532 struct wi_softc *sc;
3533 struct ieee80211_nwkey *nwkey;
3534 {
3535 int i, len, error;
3536 struct wi_ltv_keys *wk = &sc->wi_keys;
3537
3538 if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0)
3539 return ENODEV;
3540 nwkey->i_wepon = sc->wi_use_wep;
3541 nwkey->i_defkid = sc->wi_tx_key + 1;
3542
3543 /* do not show any keys to non-root user */
3544 error = suser(curproc->p_ucred, &curproc->p_acflag);
3545 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
3546 if (nwkey->i_key[i].i_keydat == NULL)
3547 continue;
3548 /* error holds results of suser() for the first time */
3549 if (error)
3550 return error;
3551 len = le16toh(wk->wi_keys[i].wi_keylen);
3552 if (nwkey->i_key[i].i_keylen < len)
3553 return ENOSPC;
3554 nwkey->i_key[i].i_keylen = len;
3555 error = copyout(wk->wi_keys[i].wi_keydat,
3556 nwkey->i_key[i].i_keydat, len);
3557 if (error)
3558 return error;
3559 }
3560 return 0;
3561 }
3562
3563 static int
3564 wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
3565 {
3566
3567 sc->wi_pm_enabled = power->i_enabled;
3568 sc->wi_max_sleep = power->i_maxsleep;
3569
3570 if (sc->sc_enabled)
3571 return (wi_init(&sc->sc_ethercom.ec_if));
3572
3573 return (0);
3574 }
3575
3576 static int
3577 wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
3578 {
3579
3580 power->i_enabled = sc->wi_pm_enabled;
3581 power->i_maxsleep = sc->wi_max_sleep;
3582
3583 return (0);
3584 }
3585
3586 static int
3587 wi_set_channel(struct wi_softc *sc, struct ieee80211_channel *channel)
3588 {
3589 int do_init = 0, error = 0;
3590 if (channel->i_channel != 0 &&
3591 !(sc->wi_channels & (1 << (channel->i_channel - 1)))) {
3592 return EINVAL;
3593 }
3594 switch (sc->wi_ptype) {
3595 default:
3596 case WI_PORTTYPE_IBSS:
3597 case WI_PORTTYPE_ADHOC: /* set channel of BSS to join/create */
3598
3599 if (channel->i_channel != 0 &&
3600 channel->i_channel != sc->wi_create_channel) {
3601 sc->wi_create_channel = channel->i_channel;
3602 if (sc->sc_enabled)
3603 do_init = 1;
3604 }
3605 /* fall through */
3606 case WI_PORTTYPE_BSS: /* set channel of BSS to join */
3607
3608 /* We are warned not to join while a join is pending.
3609 * Our next opportunity comes after a LinkStatus notification.
3610 */
3611 if (sc->wi_flags & WI_FLAGS_JOINING) {
3612 error = EAGAIN;
3613 break;
3614 }
3615 sc->wi_join_channel = channel->i_channel;
3616 error = wi_join_bss(sc);
3617 break;
3618 case WI_PORTTYPE_HOSTAP: /* set channel of BSS to create */
3619 if (channel->i_channel == 0) {
3620 error = EINVAL;
3621 break;
3622 }
3623 if (channel->i_channel == sc->wi_create_channel)
3624 break;
3625 sc->wi_create_channel = channel->i_channel;
3626 if (sc->sc_enabled)
3627 do_init = 1;
3628 break;
3629 }
3630 if (!error && do_init)
3631 error = wi_init(sc->sc_ifp);
3632 return error;
3633 }
3634
3635 static int
3636 wi_get_channel(struct wi_softc *sc, struct ieee80211_channel *channel)
3637 {
3638 switch (sc->wi_ptype) {
3639 default:
3640 case WI_PORTTYPE_IBSS:
3641 case WI_PORTTYPE_ADHOC:
3642 if (!(sc->wi_flags & WI_FLAGS_CONNECTED)) {
3643 /* return channel of BSS to create */
3644 channel->i_channel = sc->wi_create_channel;
3645 break;
3646 }
3647 /* fall through */
3648 case WI_PORTTYPE_BSS:
3649 if (sc->wi_flags & WI_FLAGS_CONNECTED) {
3650 /* return channel of connected BSS */
3651 channel->i_channel = sc->wi_current_channel;
3652 break;
3653 }
3654 /* return channel of BSS to join */
3655 channel->i_channel = sc->wi_join_channel;
3656 break;
3657 case WI_PORTTYPE_HOSTAP:
3658 /* return channel of BSS to create */
3659 channel->i_channel = sc->wi_create_channel;
3660 break;
3661 }
3662 return 0;
3663 }
3664