wi.c revision 1.83 1 /* $NetBSD: wi.c,v 1.83 2002/08/21 03:26:29 onoe 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.83 2002/08/21 03:26:29 onoe 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_media.h>
93 #include <net/if_ether.h>
94 #include <net/if_ieee80211.h>
95
96 #if NBPFILTER > 0
97 #include <net/bpf.h>
98 #include <net/bpfdesc.h>
99 #endif
100
101 #include <machine/bus.h>
102
103 #include <dev/ic/wi_ieee.h>
104 #include <dev/ic/wireg.h>
105 #include <dev/ic/wivar.h>
106
107 static void wi_reset __P((struct wi_softc *));
108 static int wi_ioctl __P((struct ifnet *, u_long, caddr_t));
109 static void wi_start __P((struct ifnet *));
110 static void wi_watchdog __P((struct ifnet *));
111 static int wi_init __P((struct ifnet *));
112 static void wi_stop __P((struct ifnet *, int));
113 static void wi_rxeof __P((struct wi_softc *));
114 static void wi_txeof __P((struct wi_softc *, int));
115 static void wi_update_stats __P((struct wi_softc *));
116 static void wi_setmulti __P((struct wi_softc *));
117
118 static int wi_cmd __P((struct wi_softc *, int, int, int, int));
119 static int wi_read_record __P((struct wi_softc *, struct wi_ltv_gen *));
120 static int wi_write_record __P((struct wi_softc *, struct wi_ltv_gen *));
121 static int wi_read_data __P((struct wi_softc *, int,
122 int, caddr_t, int));
123 static int wi_write_data __P((struct wi_softc *, int,
124 int, caddr_t, int));
125 static int wi_seek __P((struct wi_softc *, int, int, int));
126 static int wi_alloc_nicmem __P((struct wi_softc *, int, int *));
127 static void wi_inquire __P((void *));
128 static void wi_wait_scan __P((void *));
129 static int wi_setdef __P((struct wi_softc *, struct wi_req *));
130 static int wi_getdef __P((struct wi_softc *, struct wi_req *));
131
132 static int wi_media_change __P((struct ifnet *));
133 static void wi_media_status __P((struct ifnet *, struct ifmediareq *));
134
135 static void wi_get_id __P((struct wi_softc *));
136
137 static int wi_set_ssid __P((struct ieee80211_nwid *, u_int8_t *, int));
138 static void wi_request_fill_ssid __P((struct wi_req *,
139 struct ieee80211_nwid *));
140 static int wi_write_ssid __P((struct wi_softc *, int, struct wi_req *,
141 struct ieee80211_nwid *));
142 static int wi_set_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *));
143 static int wi_get_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *));
144 static int wi_sync_media __P((struct wi_softc *, int, int));
145 static int wi_set_pm(struct wi_softc *, struct ieee80211_power *);
146 static int wi_get_pm(struct wi_softc *, struct ieee80211_power *);
147
148 struct wi_card_ident wi_card_ident[] = {
149 /* CARD_ID CARD_NAME FIRM_TYPE */
150 { WI_NIC_LUCENT_ID, WI_NIC_LUCENT_STR, WI_LUCENT },
151 { WI_NIC_SONY_ID, WI_NIC_SONY_STR, WI_LUCENT },
152 { WI_NIC_LUCENT_EMB_ID, WI_NIC_LUCENT_EMB_STR, WI_LUCENT },
153 { WI_NIC_EVB2_ID, WI_NIC_EVB2_STR, WI_INTERSIL },
154 { WI_NIC_HWB3763_ID, WI_NIC_HWB3763_STR, WI_INTERSIL },
155 { WI_NIC_HWB3163_ID, WI_NIC_HWB3163_STR, WI_INTERSIL },
156 { WI_NIC_HWB3163B_ID, WI_NIC_HWB3163B_STR, WI_INTERSIL },
157 { WI_NIC_EVB3_ID, WI_NIC_EVB3_STR, WI_INTERSIL },
158 { WI_NIC_HWB1153_ID, WI_NIC_HWB1153_STR, WI_INTERSIL },
159 { WI_NIC_P2_SST_ID, WI_NIC_P2_SST_STR, WI_INTERSIL },
160 { WI_NIC_EVB2_SST_ID, WI_NIC_EVB2_SST_STR, WI_INTERSIL },
161 { WI_NIC_3842_EVA_ID, WI_NIC_3842_EVA_STR, WI_INTERSIL },
162 { WI_NIC_3842_PCMCIA_AMD_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
163 { WI_NIC_3842_PCMCIA_SST_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
164 { WI_NIC_3842_PCMCIA_ATM_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
165 { WI_NIC_3842_MINI_AMD_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL },
166 { WI_NIC_3842_MINI_SST_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL },
167 { WI_NIC_3842_MINI_ATM_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL },
168 { WI_NIC_3842_PCI_AMD_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL },
169 { WI_NIC_3842_PCI_SST_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL },
170 { WI_NIC_3842_PCI_ATM_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL },
171 { WI_NIC_P3_PCMCIA_AMD_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL },
172 { WI_NIC_P3_PCMCIA_SST_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL },
173 { WI_NIC_P3_MINI_AMD_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL },
174 { WI_NIC_P3_MINI_SST_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL },
175 { 0, NULL, 0 },
176 };
177
178 int
179 wi_attach(sc)
180 struct wi_softc *sc;
181 {
182 struct ifnet *ifp = sc->sc_ifp;
183 const char *sep = "";
184 int i, nrate;
185 u_int8_t *r;
186 struct wi_ltv_macaddr mac;
187 struct wi_ltv_gen gen;
188 struct wi_ltv_str rate;
189 static const u_int8_t empty_macaddr[ETHER_ADDR_LEN] = {
190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
191 };
192 int s;
193
194 s = splnet();
195
196 callout_init(&sc->wi_inquire_ch);
197 callout_init(&sc->wi_scan_sh);
198
199 /* Make sure interrupts are disabled. */
200 CSR_WRITE_2(sc, WI_INT_EN, 0);
201 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
202
203 /* Reset the NIC. */
204 wi_reset(sc);
205
206 memset(&mac, 0, sizeof(mac));
207 /* Read the station address. */
208 mac.wi_type = WI_RID_MAC_NODE;
209 mac.wi_len = 4;
210 wi_read_record(sc, (struct wi_ltv_gen *)&mac);
211 memcpy(sc->sc_macaddr, mac.wi_mac_addr, ETHER_ADDR_LEN);
212
213 /*
214 * Check if we got anything meaningful.
215 *
216 * Is it really enough just checking against null ethernet address?
217 * Or, check against possible vendor? XXX.
218 */
219 if (memcmp(sc->sc_macaddr, empty_macaddr, ETHER_ADDR_LEN) == 0) {
220 printf("could not get mac address, attach failed\n");
221 splx(s);
222 return 1;
223 }
224
225 printf(" 802.11 address %s\n", ether_sprintf(sc->sc_macaddr));
226
227 /* Read NIC identification */
228 wi_get_id(sc);
229
230 memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
231 ifp->if_softc = sc;
232 ifp->if_start = wi_start;
233 ifp->if_ioctl = wi_ioctl;
234 ifp->if_watchdog = wi_watchdog;
235 ifp->if_init = wi_init;
236 ifp->if_stop = wi_stop;
237 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
238 #ifdef IFF_NOTRAILERS
239 ifp->if_flags |= IFF_NOTRAILERS;
240 #endif
241 IFQ_SET_READY(&ifp->if_snd);
242
243 (void)wi_set_ssid(&sc->wi_nodeid, WI_DEFAULT_NODENAME,
244 sizeof(WI_DEFAULT_NODENAME) - 1);
245 (void)wi_set_ssid(&sc->wi_netid, WI_DEFAULT_NETNAME,
246 sizeof(WI_DEFAULT_NETNAME) - 1);
247 (void)wi_set_ssid(&sc->wi_ibssid, WI_DEFAULT_IBSS,
248 sizeof(WI_DEFAULT_IBSS) - 1);
249
250 sc->wi_portnum = WI_DEFAULT_PORT;
251 sc->wi_ptype = WI_PORTTYPE_BSS;
252 sc->wi_ap_density = WI_DEFAULT_AP_DENSITY;
253 sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH;
254 sc->wi_tx_rate = WI_DEFAULT_TX_RATE;
255 sc->wi_max_data_len = WI_DEFAULT_DATALEN;
256 sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
257 sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
258 sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
259 sc->wi_roaming = WI_DEFAULT_ROAMING;
260 sc->wi_authtype = WI_DEFAULT_AUTHTYPE;
261
262 /*
263 * Read the default channel from the NIC. This may vary
264 * depending on the country where the NIC was purchased, so
265 * we can't hard-code a default and expect it to work for
266 * everyone.
267 */
268 gen.wi_type = WI_RID_OWN_CHNL;
269 gen.wi_len = 2;
270 wi_read_record(sc, &gen);
271 sc->wi_channel = le16toh(gen.wi_val);
272
273 memset((char *)&sc->wi_stats, 0, sizeof(sc->wi_stats));
274
275 /* AP info was filled with 0 */
276 memset((char *)&sc->wi_aps, 0, sizeof(sc->wi_aps));
277 sc->wi_scanning = 0;
278 sc->wi_naps = 0;
279
280 /*
281 * Set flags based on firmware version.
282 */
283 switch (sc->sc_firmware_type) {
284 case WI_LUCENT:
285 sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
286 if (sc->sc_sta_firmware_ver >= 60000)
287 sc->wi_flags |= WI_FLAGS_HAS_MOR;
288 if (sc->sc_sta_firmware_ver >= 60006) {
289 sc->wi_flags |= WI_FLAGS_HAS_IBSS;
290 sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
291 }
292 sc->wi_ibss_port = htole16(1);
293 break;
294
295 case WI_INTERSIL:
296 sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
297 if (sc->sc_sta_firmware_ver >= 800) {
298 sc->wi_flags |= WI_FLAGS_HAS_HOSTAP;
299 sc->wi_flags |= WI_FLAGS_HAS_IBSS;
300 sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
301 }
302 sc->wi_ibss_port = htole16(0);
303 break;
304
305 case WI_SYMBOL:
306 sc->wi_flags |= WI_FLAGS_HAS_DIVERSITY;
307 if (sc->sc_sta_firmware_ver >= 20000)
308 sc->wi_flags |= WI_FLAGS_HAS_IBSS;
309 if (sc->sc_sta_firmware_ver >= 25000)
310 sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
311 sc->wi_ibss_port = htole16(4);
312 break;
313 }
314
315 /*
316 * Find out if we support WEP on this card.
317 */
318 gen.wi_type = WI_RID_WEP_AVAIL;
319 gen.wi_len = 2;
320 if (wi_read_record(sc, &gen) == 0 &&
321 gen.wi_val != le16toh(0))
322 sc->wi_flags |= WI_FLAGS_HAS_WEP;
323
324 /* Find supported rates. */
325 rate.wi_type = WI_RID_DATA_RATES;
326 rate.wi_len = 6;
327 if (wi_read_record(sc, (struct wi_ltv_gen *)&rate) == 0) {
328 nrate = le16toh(rate.wi_str[0]);
329 r = (u_int8_t *)&rate.wi_str[1];
330 for (i = 0; i < nrate; i++) {
331 switch (r[i] & IEEE80211_RATE_VAL) {
332 case 2:
333 sc->wi_supprates |= WI_SUPPRATES_1M;
334 break;
335 case 4:
336 sc->wi_supprates |= WI_SUPPRATES_2M;
337 break;
338 case 11:
339 sc->wi_supprates |= WI_SUPPRATES_5M;
340 break;
341 case 22:
342 sc->wi_supprates |= WI_SUPPRATES_11M;
343 break;
344 }
345 }
346 }
347
348 ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status);
349 if (sc->wi_supprates != 0)
350 printf("%s: supported rates: ", sc->sc_dev.dv_xname);
351 #define ADD(s, o) ifmedia_add(&sc->sc_media, \
352 IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL)
353 #define PRINT(n) printf("%s%s", sep, (n)); sep = ", "
354 ADD(IFM_AUTO, 0);
355 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
356 ADD(IFM_AUTO, IFM_IEEE80211_HOSTAP);
357 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
358 ADD(IFM_AUTO, IFM_IEEE80211_ADHOC);
359 ADD(IFM_AUTO, IFM_IEEE80211_ADHOC | IFM_FLAG0);
360 if (sc->wi_supprates & WI_SUPPRATES_1M) {
361 PRINT("1Mbps");
362 ADD(IFM_IEEE80211_DS1, 0);
363 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
364 ADD(IFM_IEEE80211_DS1, IFM_IEEE80211_HOSTAP);
365 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
366 ADD(IFM_IEEE80211_DS1, IFM_IEEE80211_ADHOC);
367 ADD(IFM_IEEE80211_DS1, IFM_IEEE80211_ADHOC | IFM_FLAG0);
368 }
369 if (sc->wi_supprates & WI_SUPPRATES_2M) {
370 PRINT("2Mbps");
371 ADD(IFM_IEEE80211_DS2, 0);
372 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
373 ADD(IFM_IEEE80211_DS2, IFM_IEEE80211_HOSTAP);
374 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
375 ADD(IFM_IEEE80211_DS2, IFM_IEEE80211_ADHOC);
376 ADD(IFM_IEEE80211_DS2, IFM_IEEE80211_ADHOC | IFM_FLAG0);
377 }
378 if (sc->wi_supprates & WI_SUPPRATES_5M) {
379 PRINT("5.5Mbps");
380 ADD(IFM_IEEE80211_DS5, 0);
381 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
382 ADD(IFM_IEEE80211_DS5, IFM_IEEE80211_HOSTAP);
383 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
384 ADD(IFM_IEEE80211_DS5, IFM_IEEE80211_ADHOC);
385 ADD(IFM_IEEE80211_DS5, IFM_IEEE80211_ADHOC | IFM_FLAG0);
386 }
387 if (sc->wi_supprates & WI_SUPPRATES_11M) {
388 PRINT("11Mbps");
389 ADD(IFM_IEEE80211_DS11, 0);
390 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
391 ADD(IFM_IEEE80211_DS11, IFM_IEEE80211_HOSTAP);
392 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
393 ADD(IFM_IEEE80211_DS11, IFM_IEEE80211_ADHOC);
394 ADD(IFM_IEEE80211_DS11, IFM_IEEE80211_ADHOC | IFM_FLAG0);
395 }
396 if (sc->wi_supprates != 0)
397 printf("\n");
398 ifmedia_set(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0));
399 #undef ADD
400 #undef PRINT
401
402 /*
403 * Call MI attach routines.
404 */
405 if_attach(ifp);
406 ether_ifattach(ifp, sc->sc_macaddr);
407
408 ifp->if_baudrate = IF_Mbps(2);
409
410 /* Attach is successful. */
411 sc->sc_attached = 1;
412
413 splx(s);
414 return 0;
415 }
416
417 static void wi_rxeof(sc)
418 struct wi_softc *sc;
419 {
420 struct ifnet *ifp;
421 struct ether_header *eh;
422 struct wi_frame rx_frame;
423 struct mbuf *m;
424 int id;
425
426 ifp = sc->sc_ifp;
427
428 id = CSR_READ_2(sc, WI_RX_FID);
429
430 /* First read in the frame header */
431 if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) {
432 ifp->if_ierrors++;
433 return;
434 }
435
436 /*
437 * Drop undecryptable or packets with receive errors here
438 */
439 if (le16toh(rx_frame.wi_status) & WI_STAT_ERRSTAT) {
440 ifp->if_ierrors++;
441 return;
442 }
443
444 MGETHDR(m, M_DONTWAIT, MT_DATA);
445 if (m == NULL) {
446 ifp->if_ierrors++;
447 return;
448 }
449 MCLGET(m, M_DONTWAIT);
450 if (!(m->m_flags & M_EXT)) {
451 m_freem(m);
452 ifp->if_ierrors++;
453 return;
454 }
455
456 /* Align the data after the ethernet header */
457 m->m_data = (caddr_t) ALIGN(m->m_data + sizeof(struct ether_header))
458 - sizeof(struct ether_header);
459
460 eh = mtod(m, struct ether_header *);
461 m->m_pkthdr.rcvif = ifp;
462
463 if ((le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_MGMT &&
464 sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
465 if ((le16toh(rx_frame.wi_dat_len) + WI_802_11_OFFSET_RAW + 2) >
466 MCLBYTES) {
467 printf("%s: oversized packet received in "
468 "Host-AP mode (wi_dat_len=%d, wi_status=0x%x)\n",
469 sc->sc_dev.dv_xname,
470 le16toh(rx_frame.wi_dat_len),
471 le16toh(rx_frame.wi_status));
472 m_freem(m);
473 ifp->if_ierrors++;
474 return;
475 }
476
477 /* Put the whole header in there. */
478 memcpy(mtod(m, void *), &rx_frame, sizeof(rx_frame));
479 if (wi_read_data(sc, id, WI_802_11_OFFSET_RAW,
480 mtod(m, caddr_t) + WI_802_11_OFFSET_RAW,
481 le16toh(rx_frame.wi_dat_len) + 2)) {
482 m_freem(m);
483 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
484 printf("%s: Host-AP: failed to copy header\n",
485 sc->sc_dev.dv_xname);
486 ifp->if_ierrors++;
487 return;
488 }
489
490 m->m_pkthdr.len = m->m_len =
491 WI_802_11_OFFSET_RAW + le16toh(rx_frame.wi_dat_len);
492
493 /* XXX Consider giving packet to bhp? */
494
495 wihap_mgmt_input(sc, &rx_frame, m);
496 return;
497 }
498
499 if ((le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_1042 ||
500 (le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_TUNNEL ||
501 (le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_WMP_MSG) {
502 if ((le16toh(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN) > MCLBYTES) {
503 printf("%s: oversized packet received "
504 "(wi_dat_len=%d, wi_status=0x%x)\n",
505 sc->sc_dev.dv_xname,
506 le16toh(rx_frame.wi_dat_len), le16toh(rx_frame.wi_status));
507 m_freem(m);
508 ifp->if_ierrors++;
509 return;
510 }
511 m->m_pkthdr.len = m->m_len =
512 le16toh(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN;
513
514 memcpy((char *)&eh->ether_dhost, (char *)&rx_frame.wi_dst_addr,
515 ETHER_ADDR_LEN);
516 memcpy((char *)&eh->ether_shost, (char *)&rx_frame.wi_src_addr,
517 ETHER_ADDR_LEN);
518 memcpy((char *)&eh->ether_type, (char *)&rx_frame.wi_type,
519 sizeof(u_int16_t));
520
521 if (wi_read_data(sc, id, WI_802_11_OFFSET,
522 mtod(m, caddr_t) + sizeof(struct ether_header),
523 m->m_len + 2)) {
524 m_freem(m);
525 ifp->if_ierrors++;
526 return;
527 }
528 } else {
529 if ((le16toh(rx_frame.wi_dat_len) +
530 sizeof(struct ether_header)) > MCLBYTES) {
531 printf("%s: oversized packet received "
532 "(wi_dat_len=%d, wi_status=0x%x)\n",
533 sc->sc_dev.dv_xname,
534 le16toh(rx_frame.wi_dat_len), le16toh(rx_frame.wi_status));
535 m_freem(m);
536 ifp->if_ierrors++;
537 return;
538 }
539 m->m_pkthdr.len = m->m_len =
540 le16toh(rx_frame.wi_dat_len) + sizeof(struct ether_header);
541
542 if (wi_read_data(sc, id, WI_802_3_OFFSET,
543 mtod(m, caddr_t), m->m_len + 2)) {
544 m_freem(m);
545 ifp->if_ierrors++;
546 return;
547 }
548 }
549
550 ifp->if_ipackets++;
551
552 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
553 /*
554 * Give Host-AP first crack at data packets. If it
555 * decides to handle it (or drop it), it will return
556 * non-zero. Otherwise, it is destined for this host.
557 */
558 if (wihap_data_input(sc, &rx_frame, m))
559 return;
560 }
561
562 #if NBPFILTER > 0
563 /* Handle BPF listeners. */
564 if (ifp->if_bpf)
565 bpf_mtap(ifp->if_bpf, m);
566 #endif
567
568 /* Receive packet. */
569 (*ifp->if_input)(ifp, m);
570 }
571
572 static void wi_txeof(sc, status)
573 struct wi_softc *sc;
574 int status;
575 {
576 struct ifnet *ifp = sc->sc_ifp;
577
578 ifp->if_timer = 0;
579 ifp->if_flags &= ~IFF_OACTIVE;
580
581 if (status & WI_EV_TX_EXC)
582 ifp->if_oerrors++;
583 else
584 ifp->if_opackets++;
585
586 return;
587 }
588
589 void wi_inquire(xsc)
590 void *xsc;
591 {
592 struct wi_softc *sc;
593 struct ifnet *ifp;
594 int s;
595
596 sc = xsc;
597 ifp = &sc->sc_ethercom.ec_if;
598
599 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
600 return;
601
602 KASSERT(sc->sc_enabled);
603
604 callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
605
606 /* Don't do this while we're transmitting */
607 if (ifp->if_flags & IFF_OACTIVE)
608 return;
609
610 s = splnet();
611 wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0);
612 splx(s);
613 }
614
615 void wi_wait_scan(xsc)
616 void *xsc;
617 {
618 struct wi_softc *sc;
619 struct ifnet *ifp;
620 int s, result;
621
622 sc = xsc;
623 ifp = &sc->sc_ethercom.ec_if;
624
625 /* If not scanning, ignore */
626 if (!sc->wi_scanning)
627 return;
628
629 s = splnet();
630
631 /* Wait for sending complete to make INQUIRE */
632 if (ifp->if_flags & IFF_OACTIVE) {
633 callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc);
634 splx(s);
635 return;
636 }
637
638 /* try INQUIRE */
639 result = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0);
640 if (result == ETIMEDOUT)
641 callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc);
642
643 splx(s);
644 }
645
646 void wi_update_stats(sc)
647 struct wi_softc *sc;
648 {
649 struct wi_ltv_gen gen;
650 struct wi_scan_header ap2_header; /* Prism2 header */
651 struct wi_scan_data_p2 ap2; /* Prism2 scantable*/
652 struct wi_scan_data ap; /* Lucent scantable */
653 struct wi_assoc assoc; /* Association Status */
654 u_int16_t id;
655 struct ifnet *ifp;
656 u_int32_t *ptr;
657 int len, naps, i, j;
658 u_int16_t t;
659
660 ifp = &sc->sc_ethercom.ec_if;
661
662 id = CSR_READ_2(sc, WI_INFO_FID);
663
664 if (wi_seek(sc, id, 0, WI_BAP1)) {
665 return;
666 }
667
668 gen.wi_len = CSR_READ_2(sc, WI_DATA1);
669 gen.wi_type = CSR_READ_2(sc, WI_DATA1);
670
671 switch (gen.wi_type) {
672 case WI_INFO_SCAN_RESULTS:
673 case WI_INFO_HOST_SCAN_RESULTS:
674 if (gen.wi_len <= 3) {
675 sc->wi_naps = 0;
676 sc->wi_scanning = 0;
677 break;
678 }
679 switch (sc->sc_firmware_type) {
680 case WI_INTERSIL:
681 case WI_SYMBOL:
682 if (sc->sc_firmware_type == WI_INTERSIL) {
683 naps = 2 * (gen.wi_len - 3) / sizeof(ap2);
684 /* Read Header */
685 for(j=0; j < sizeof(ap2_header) / 2; j++)
686 ((u_int16_t *)&ap2_header)[j] =
687 CSR_READ_2(sc, WI_DATA1);
688 } else { /* WI_SYMBOL */
689 naps = 2 * (gen.wi_len - 1) / (sizeof(ap2) + 6);
690 ap2_header.wi_reason = 0;
691 }
692 naps = naps > MAXAPINFO ? MAXAPINFO : naps;
693 sc->wi_naps = naps;
694 /* Read Data */
695 for (i=0; i < naps; i++) {
696 for(j=0; j < sizeof(ap2) / 2; j++)
697 ((u_int16_t *)&ap2)[j] =
698 CSR_READ_2(sc, WI_DATA1);
699 if (sc->sc_firmware_type == WI_SYMBOL) {
700 /* 3 more words */
701 for (j = 0; j < 3; j++)
702 CSR_READ_2(sc, WI_DATA1);
703 }
704 /* unswap 8 bit data fields: */
705 for(j=0;j<sizeof(ap.wi_bssid)/2;j++)
706 LE16TOH(((u_int16_t *)&ap.wi_bssid[0])[j]);
707 for(j=0;j<sizeof(ap.wi_name)/2;j++)
708 LE16TOH(((u_int16_t *)&ap.wi_name[0])[j]);
709 sc->wi_aps[i].scanreason = ap2_header.wi_reason;
710 memcpy(sc->wi_aps[i].bssid, ap2.wi_bssid, 6);
711 sc->wi_aps[i].channel = ap2.wi_chid;
712 sc->wi_aps[i].signal = ap2.wi_signal;
713 sc->wi_aps[i].noise = ap2.wi_noise;
714 sc->wi_aps[i].quality = ap2.wi_signal - ap2.wi_noise;
715 sc->wi_aps[i].capinfo = ap2.wi_capinfo;
716 sc->wi_aps[i].interval = ap2.wi_interval;
717 sc->wi_aps[i].rate = ap2.wi_rate;
718 if (ap2.wi_namelen > 32)
719 ap2.wi_namelen = 32;
720 sc->wi_aps[i].namelen = ap2.wi_namelen;
721 memcpy(sc->wi_aps[i].name, ap2.wi_name,
722 ap2.wi_namelen);
723 }
724 break;
725
726 case WI_LUCENT:
727 naps = 2 * gen.wi_len / sizeof(ap);
728 naps = naps > MAXAPINFO ? MAXAPINFO : naps;
729 sc->wi_naps = naps;
730 /* Read Data*/
731 for (i=0; i < naps; i++) {
732 for(j=0; j < sizeof(ap) / 2; j++)
733 ((u_int16_t *)&ap)[j] =
734 CSR_READ_2(sc, WI_DATA1);
735 /* unswap 8 bit data fields: */
736 for(j=0;j<sizeof(ap.wi_bssid)/2;j++)
737 HTOLE16(((u_int16_t *)&ap.wi_bssid[0])[j]);
738 for(j=0;j<sizeof(ap.wi_name)/2;j++)
739 HTOLE16(((u_int16_t *)&ap.wi_name[0])[j]);
740 memcpy(sc->wi_aps[i].bssid, ap.wi_bssid, 6);
741 sc->wi_aps[i].channel = ap.wi_chid;
742 sc->wi_aps[i].signal = ap.wi_signal;
743 sc->wi_aps[i].noise = ap.wi_noise;
744 sc->wi_aps[i].quality = ap.wi_signal - ap.wi_noise;
745 sc->wi_aps[i].capinfo = ap.wi_capinfo;
746 sc->wi_aps[i].interval = ap.wi_interval;
747 if (ap.wi_namelen > 32)
748 ap.wi_namelen = 32;
749 sc->wi_aps[i].namelen = ap.wi_namelen;
750 memcpy(sc->wi_aps[i].name, ap.wi_name,
751 ap.wi_namelen);
752 }
753 break;
754 }
755 /* Done scanning */
756 sc->wi_scanning = 0;
757 break;
758
759 case WI_INFO_COUNTERS:
760 /* some card versions have a larger stats structure */
761 len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ?
762 gen.wi_len - 1 : sizeof(sc->wi_stats) / 4;
763 ptr = (u_int32_t *)&sc->wi_stats;
764
765 for (i = 0; i < len; i++) {
766 t = CSR_READ_2(sc, WI_DATA1);
767 #ifdef WI_HERMES_STATS_WAR
768 if (t > 0xF000)
769 t = ~t & 0xFFFF;
770 #endif
771 ptr[i] += t;
772 }
773
774 ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
775 sc->wi_stats.wi_tx_multi_retries +
776 sc->wi_stats.wi_tx_retry_limit;
777 break;
778
779 case WI_INFO_LINK_STAT: {
780 static char *msg[] = {
781 "connected",
782 "disconnected",
783 "AP change",
784 "AP out of range",
785 "AP in range",
786 "Association Failed"
787 };
788
789 if (gen.wi_len != 2) {
790 #ifdef WI_DEBUG
791 printf("WI_INFO_LINK_STAT: len=%d\n", gen.wi_len);
792 #endif
793 break;
794 }
795 t = CSR_READ_2(sc, WI_DATA1);
796 if ((t < 1) || (t > 6)) {
797 #ifdef WI_DEBUG
798 printf("WI_INFO_LINK_STAT: status %d\n", t);
799 #endif
800 break;
801 }
802 if (sc->sc_firmware_type == WI_SYMBOL && t == 4) {
803 wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_HOST_SCAN_RESULTS,
804 0, 0);
805 break;
806 }
807 /*
808 * Some cards issue streams of "connected" messages while
809 * trying to find a peer. Don't bother the user with this
810 * unless he is debugging.
811 */
812 if (ifp->if_flags & IFF_DEBUG)
813 printf("%s: %s\n", sc->sc_dev.dv_xname, msg[t - 1]);
814 break;
815 }
816
817 case WI_INFO_ASSOC_STAT: {
818 static char *msg[] = {
819 "STA Associated",
820 "STA Reassociated",
821 "STA Disassociated",
822 "Association Failure",
823 "Authentication Failed"
824 };
825 if (gen.wi_len != 10)
826 break;
827 for (i=0; i < gen.wi_len - 1; i++)
828 ((u_int16_t *)&assoc)[i] = CSR_READ_2(sc, WI_DATA1);
829 /* unswap 8 bit data fields: */
830 for(j=0;j<sizeof(assoc.wi_assoc_sta)/2;j++)
831 HTOLE16(((u_int16_t *)&assoc.wi_assoc_sta[0])[j]);
832 for(j=0;j<sizeof(assoc.wi_assoc_osta)/2;j++)
833 HTOLE16(((u_int16_t *)&assoc.wi_assoc_osta[0])[j]);
834 switch (assoc.wi_assoc_stat) {
835 case ASSOC:
836 case DISASSOC:
837 case ASSOCFAIL:
838 case AUTHFAIL:
839 printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x\n",
840 sc->sc_dev.dv_xname,
841 msg[assoc.wi_assoc_stat - 1],
842 assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff,
843 assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff,
844 assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff);
845 break;
846 case REASSOC:
847 printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x, "
848 "OldAP = %02x:%02x:%02x:%02x:%02x:%02x\n",
849 sc->sc_dev.dv_xname, msg[assoc.wi_assoc_stat - 1],
850 assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff,
851 assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff,
852 assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff,
853 assoc.wi_assoc_osta[0]&0xff, assoc.wi_assoc_osta[1]&0xff,
854 assoc.wi_assoc_osta[2]&0xff, assoc.wi_assoc_osta[3]&0xff,
855 assoc.wi_assoc_osta[4]&0xff, assoc.wi_assoc_osta[5]&0xff);
856 break;
857 }
858 }
859
860 default:
861 #ifdef WI_DEBUG
862 printf("%s: got info type: 0x%04x len=0x%04x\n",
863 sc->sc_dev.dv_xname, gen.wi_type,gen.wi_len);
864 #endif
865 #if 0
866 for (i = 0; i < gen.wi_len; i++) {
867 t = CSR_READ_2(sc, WI_DATA1);
868 printf("[0x%02x] = 0x%04x\n", i, t);
869 }
870 #endif
871 break;
872 }
873 }
874
875 int wi_intr(arg)
876 void *arg;
877 {
878 struct wi_softc *sc = arg;
879 struct ifnet *ifp;
880 u_int16_t status;
881
882 if (sc->sc_enabled == 0 ||
883 (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
884 (sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0)
885 return (0);
886
887 ifp = &sc->sc_ethercom.ec_if;
888
889 if (!(ifp->if_flags & IFF_UP)) {
890 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
891 CSR_WRITE_2(sc, WI_INT_EN, 0);
892 return 1;
893 }
894
895 /* Disable interrupts. */
896 CSR_WRITE_2(sc, WI_INT_EN, 0);
897
898 status = CSR_READ_2(sc, WI_EVENT_STAT);
899 CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS);
900
901 if (status & WI_EV_RX) {
902 wi_rxeof(sc);
903 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
904 }
905
906 if (status & WI_EV_TX) {
907 wi_txeof(sc, status);
908 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
909 }
910
911 if (status & WI_EV_ALLOC) {
912 int id;
913 id = CSR_READ_2(sc, WI_ALLOC_FID);
914 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
915 if (id == sc->wi_tx_data_id)
916 wi_txeof(sc, status);
917 }
918
919 if (status & WI_EV_INFO) {
920 wi_update_stats(sc);
921 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
922 }
923
924 if (status & WI_EV_TX_EXC) {
925 wi_txeof(sc, status);
926 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
927 }
928
929 if (status & WI_EV_INFO_DROP) {
930 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP);
931 }
932
933 /* Re-enable interrupts. */
934 CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
935
936 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
937 wi_start(ifp);
938
939 return 1;
940 }
941
942 /* Must be called at proper protection level! */
943 static int
944 wi_cmd(sc, cmd, val0, val1, val2)
945 struct wi_softc *sc;
946 int cmd;
947 int val0;
948 int val1;
949 int val2;
950 {
951 int i, s = 0;
952
953 /* wait for the busy bit to clear */
954 for (i = 0; i < WI_TIMEOUT; i++) {
955 if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
956 break;
957 }
958
959 if (i == WI_TIMEOUT) {
960 printf("%s: wi_cmd: BUSY did not clear, cmd=0x%x\n",
961 sc->sc_dev.dv_xname, cmd);
962 return EIO;
963 }
964
965 CSR_WRITE_2(sc, WI_PARAM0, val0);
966 CSR_WRITE_2(sc, WI_PARAM1, val1);
967 CSR_WRITE_2(sc, WI_PARAM2, val2);
968 CSR_WRITE_2(sc, WI_COMMAND, cmd);
969
970 /* wait for the cmd completed bit */
971 for (i = 0; i < WI_TIMEOUT; i++) {
972 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
973 break;
974 DELAY(1);
975 }
976
977 /* Ack the command */
978 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
979
980 s = CSR_READ_2(sc, WI_STATUS);
981 if (s & WI_STAT_CMD_RESULT)
982 return(EIO);
983
984 if (i == WI_TIMEOUT) {
985 if (!sc->wi_scanning)
986 printf("%s: command timed out, cmd=0x%x\n",
987 sc->sc_dev.dv_xname, cmd);
988 return(ETIMEDOUT);
989 }
990
991 return(0);
992 }
993
994 static void
995 wi_reset(sc)
996 struct wi_softc *sc;
997 {
998
999 DELAY(100*1000); /* 100 m sec */
1000 if (wi_cmd(sc, WI_CMD_INI, 0, 0, 0))
1001 printf("%s: init failed\n", sc->sc_dev.dv_xname);
1002 CSR_WRITE_2(sc, WI_INT_EN, 0);
1003 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
1004
1005 /* Calibrate timer. */
1006 WI_SETVAL(WI_RID_TICK_TIME, 8);
1007
1008 return;
1009 }
1010
1011 /*
1012 * Read an LTV record from the NIC.
1013 */
1014 static int wi_read_record(sc, ltv)
1015 struct wi_softc *sc;
1016 struct wi_ltv_gen *ltv;
1017 {
1018 u_int16_t *ptr;
1019 int len, code;
1020 struct wi_ltv_gen *oltv, p2ltv;
1021
1022 if (sc->sc_firmware_type != WI_LUCENT) {
1023 oltv = ltv;
1024 switch (ltv->wi_type) {
1025 case WI_RID_ENCRYPTION:
1026 p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
1027 p2ltv.wi_len = 2;
1028 ltv = &p2ltv;
1029 break;
1030 case WI_RID_TX_CRYPT_KEY:
1031 p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
1032 p2ltv.wi_len = 2;
1033 ltv = &p2ltv;
1034 break;
1035 }
1036 }
1037
1038 /* Tell the NIC to enter record read mode. */
1039 if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0))
1040 return(EIO);
1041
1042 /* Seek to the record. */
1043 if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
1044 return(EIO);
1045
1046 /*
1047 * Read the length and record type and make sure they
1048 * match what we expect (this verifies that we have enough
1049 * room to hold all of the returned data).
1050 */
1051 len = CSR_READ_2(sc, WI_DATA1);
1052 if (len > ltv->wi_len)
1053 return(ENOSPC);
1054 code = CSR_READ_2(sc, WI_DATA1);
1055 if (code != ltv->wi_type)
1056 return(EIO);
1057
1058 ltv->wi_len = len;
1059 ltv->wi_type = code;
1060
1061 /* Now read the data. */
1062 ptr = <v->wi_val;
1063 if (ltv->wi_len > 1)
1064 CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1);
1065
1066 if (ltv->wi_type == WI_RID_PORTTYPE &&
1067 sc->wi_ptype == WI_PORTTYPE_IBSS &&
1068 ltv->wi_val == sc->wi_ibss_port) {
1069 /*
1070 * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
1071 * Since Lucent uses port type 1 for BSS *and* IBSS we
1072 * have to rely on wi_ptype to distinguish this for us.
1073 */
1074 ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
1075 } else if (sc->sc_firmware_type != WI_LUCENT) {
1076 int v;
1077
1078 switch (oltv->wi_type) {
1079 case WI_RID_TX_RATE:
1080 case WI_RID_CUR_TX_RATE:
1081 switch (le16toh(ltv->wi_val)) {
1082 case 1: v = 1; break;
1083 case 2: v = 2; break;
1084 case 3: v = 6; break;
1085 case 4: v = 5; break;
1086 case 7: v = 7; break;
1087 case 8: v = 11; break;
1088 case 15: v = 3; break;
1089 default: v = 0x100 + le16toh(ltv->wi_val); break;
1090 }
1091 oltv->wi_val = htole16(v);
1092 break;
1093 case WI_RID_ENCRYPTION:
1094 oltv->wi_len = 2;
1095 if (le16toh(ltv->wi_val) & 0x01)
1096 oltv->wi_val = htole16(1);
1097 else
1098 oltv->wi_val = htole16(0);
1099 break;
1100 case WI_RID_TX_CRYPT_KEY:
1101 oltv->wi_len = 2;
1102 oltv->wi_val = ltv->wi_val;
1103 break;
1104 case WI_RID_CNFAUTHMODE:
1105 oltv->wi_len = 2;
1106 if (le16toh(ltv->wi_val) & 0x01)
1107 oltv->wi_val = htole16(1);
1108 else if (le16toh(ltv->wi_val) & 0x02)
1109 oltv->wi_val = htole16(2);
1110 break;
1111 }
1112 }
1113
1114 return(0);
1115 }
1116
1117 /*
1118 * Same as read, except we inject data instead of reading it.
1119 */
1120 static int wi_write_record(sc, ltv)
1121 struct wi_softc *sc;
1122 struct wi_ltv_gen *ltv;
1123 {
1124 u_int16_t *ptr;
1125 int i;
1126 struct wi_ltv_gen p2ltv;
1127
1128 if (ltv->wi_type == WI_RID_PORTTYPE &&
1129 ltv->wi_val == le16toh(WI_PORTTYPE_IBSS)) {
1130 /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
1131 p2ltv.wi_type = WI_RID_PORTTYPE;
1132 p2ltv.wi_len = 2;
1133 p2ltv.wi_val = sc->wi_ibss_port;
1134 ltv = &p2ltv;
1135 } else if (sc->sc_firmware_type != WI_LUCENT) {
1136 int v;
1137
1138 switch (ltv->wi_type) {
1139 case WI_RID_TX_RATE:
1140 p2ltv.wi_type = WI_RID_TX_RATE;
1141 p2ltv.wi_len = 2;
1142 switch (le16toh(ltv->wi_val)) {
1143 case 1: v = 1; break;
1144 case 2: v = 2; break;
1145 case 3: v = 15; break;
1146 case 5: v = 4; break;
1147 case 6: v = 3; break;
1148 case 7: v = 7; break;
1149 case 11: v = 8; break;
1150 default: return EINVAL;
1151 }
1152 p2ltv.wi_val = htole16(v);
1153 ltv = &p2ltv;
1154 break;
1155 case WI_RID_ENCRYPTION:
1156 p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
1157 p2ltv.wi_len = 2;
1158 if (le16toh(ltv->wi_val)) {
1159 uint16_t val = PRIVACY_INVOKED;
1160 /*
1161 * If using shared key WEP we must set the
1162 * EXCLUDE_UNENCRYPTED bit. Symbol cards
1163 * need this bit even when not using shared
1164 * key. We can't just test for
1165 * IEEE80211_AUTH_SHARED since Symbol cards
1166 * have 2 shared key modes.
1167 */
1168 if (sc->wi_authtype != IEEE80211_AUTH_OPEN ||
1169 sc->sc_firmware_type == WI_SYMBOL)
1170 val |= EXCLUDE_UNENCRYPTED;
1171 /* Tx encryption is broken in Host-AP mode. */
1172 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
1173 val |= HOST_ENCRYPT;
1174 p2ltv.wi_val = htole16(val);
1175 } else
1176 p2ltv.wi_val =
1177 htole16(HOST_ENCRYPT | HOST_DECRYPT);
1178 ltv = &p2ltv;
1179 break;
1180 case WI_RID_TX_CRYPT_KEY:
1181 p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
1182 p2ltv.wi_len = 2;
1183 p2ltv.wi_val = ltv->wi_val;
1184 ltv = &p2ltv;
1185 break;
1186 case WI_RID_DEFLT_CRYPT_KEYS:
1187 {
1188 int error;
1189 int keylen;
1190 struct wi_ltv_str ws;
1191 struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv;
1192
1193 keylen = le16toh(wk->wi_keys[sc->wi_tx_key].wi_keylen);
1194
1195 for (i = 0; i < 4; i++) {
1196 memset(&ws, 0, sizeof(ws));
1197 ws.wi_len = (keylen > 5) ? 8 : 4;
1198 ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
1199 memcpy(ws.wi_str,
1200 &wk->wi_keys[i].wi_keydat, keylen);
1201 error = wi_write_record(sc,
1202 (struct wi_ltv_gen *)&ws);
1203 if (error)
1204 return error;
1205 }
1206 return 0;
1207 }
1208 case WI_RID_CNFAUTHMODE:
1209 p2ltv.wi_type = WI_RID_CNFAUTHMODE;
1210 p2ltv.wi_len = 2;
1211 if (le16toh(ltv->wi_val) == 1)
1212 p2ltv.wi_val = htole16(0x01);
1213 else if (le16toh(ltv->wi_val) == 2)
1214 p2ltv.wi_val = htole16(0x02);
1215 ltv = &p2ltv;
1216 break;
1217 }
1218 }
1219
1220 if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
1221 return(EIO);
1222
1223 CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len);
1224 CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type);
1225
1226 /* Write data */
1227 ptr = <v->wi_val;
1228 if (ltv->wi_len > 1)
1229 CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1);
1230
1231 if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0))
1232 return(EIO);
1233
1234 return(0);
1235 }
1236
1237 static int wi_seek(sc, id, off, chan)
1238 struct wi_softc *sc;
1239 int id, off, chan;
1240 {
1241 int i;
1242 int selreg, offreg;
1243 int status;
1244
1245 switch (chan) {
1246 case WI_BAP0:
1247 selreg = WI_SEL0;
1248 offreg = WI_OFF0;
1249 break;
1250 case WI_BAP1:
1251 selreg = WI_SEL1;
1252 offreg = WI_OFF1;
1253 break;
1254 default:
1255 printf("%s: invalid data path: %x\n",
1256 sc->sc_dev.dv_xname, chan);
1257 return(EIO);
1258 }
1259
1260 CSR_WRITE_2(sc, selreg, id);
1261 CSR_WRITE_2(sc, offreg, off);
1262
1263 for (i = 0; i < WI_TIMEOUT; i++) {
1264 status = CSR_READ_2(sc, offreg);
1265 if (!(status & (WI_OFF_BUSY|WI_OFF_ERR)))
1266 break;
1267 }
1268
1269 if (i == WI_TIMEOUT) {
1270 printf("%s: timeout in wi_seek to %x/%x; last status %x\n",
1271 sc->sc_dev.dv_xname, id, off, status);
1272 return(ETIMEDOUT);
1273 }
1274 return(0);
1275 }
1276
1277 static int wi_read_data(sc, id, off, buf, len)
1278 struct wi_softc *sc;
1279 int id, off;
1280 caddr_t buf;
1281 int len;
1282 {
1283 u_int16_t *ptr;
1284
1285 if (wi_seek(sc, id, off, WI_BAP1))
1286 return(EIO);
1287
1288 ptr = (u_int16_t *)buf;
1289 CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, len / 2);
1290
1291 return(0);
1292 }
1293
1294 /*
1295 * According to the comments in the HCF Light code, there is a bug in
1296 * the Hermes (or possibly in certain Hermes firmware revisions) where
1297 * the chip's internal autoincrement counter gets thrown off during
1298 * data writes: the autoincrement is missed, causing one data word to
1299 * be overwritten and subsequent words to be written to the wrong memory
1300 * locations. The end result is that we could end up transmitting bogus
1301 * frames without realizing it. The workaround for this is to write a
1302 * couple of extra guard words after the end of the transfer, then
1303 * attempt to read then back. If we fail to locate the guard words where
1304 * we expect them, we preform the transfer over again.
1305 */
1306 static int wi_write_data(sc, id, off, buf, len)
1307 struct wi_softc *sc;
1308 int id, off;
1309 caddr_t buf;
1310 int len;
1311 {
1312 u_int16_t *ptr;
1313
1314 #ifdef WI_HERMES_AUTOINC_WAR
1315 again:
1316 #endif
1317
1318 if (wi_seek(sc, id, off, WI_BAP0))
1319 return(EIO);
1320
1321 ptr = (u_int16_t *)buf;
1322 CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, ptr, len / 2);
1323
1324 #ifdef WI_HERMES_AUTOINC_WAR
1325 CSR_WRITE_2(sc, WI_DATA0, 0x1234);
1326 CSR_WRITE_2(sc, WI_DATA0, 0x5678);
1327
1328 if (wi_seek(sc, id, off + len, WI_BAP0))
1329 return(EIO);
1330
1331 if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
1332 CSR_READ_2(sc, WI_DATA0) != 0x5678)
1333 goto again;
1334 #endif
1335
1336 return(0);
1337 }
1338
1339 /*
1340 * Allocate a region of memory inside the NIC and zero
1341 * it out.
1342 */
1343 static int wi_alloc_nicmem(sc, len, id)
1344 struct wi_softc *sc;
1345 int len;
1346 int *id;
1347 {
1348 int i;
1349
1350 if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) {
1351 printf("%s: failed to allocate %d bytes on NIC\n",
1352 sc->sc_dev.dv_xname, len);
1353 return(ENOMEM);
1354 }
1355
1356 for (i = 0; i < WI_TIMEOUT; i++) {
1357 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
1358 break;
1359 }
1360
1361 if (i == WI_TIMEOUT) {
1362 printf("%s: TIMED OUT in alloc\n", sc->sc_dev.dv_xname);
1363 return(ETIMEDOUT);
1364 }
1365
1366 *id = CSR_READ_2(sc, WI_ALLOC_FID);
1367 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
1368
1369 if (wi_seek(sc, *id, 0, WI_BAP0)) {
1370 printf("%s: seek failed in alloc\n", sc->sc_dev.dv_xname);
1371 return(EIO);
1372 }
1373
1374 for (i = 0; i < len / 2; i++)
1375 CSR_WRITE_2(sc, WI_DATA0, 0);
1376
1377 return(0);
1378 }
1379
1380 static void wi_setmulti(sc)
1381 struct wi_softc *sc;
1382 {
1383 struct ifnet *ifp;
1384 int i = 0;
1385 struct wi_ltv_mcast mcast;
1386 struct ether_multi *enm;
1387 struct ether_multistep estep;
1388 struct ethercom *ec = &sc->sc_ethercom;
1389
1390 ifp = &sc->sc_ethercom.ec_if;
1391
1392 if ((ifp->if_flags & IFF_PROMISC) != 0) {
1393 allmulti:
1394 ifp->if_flags |= IFF_ALLMULTI;
1395 memset((char *)&mcast, 0, sizeof(mcast));
1396 mcast.wi_type = WI_RID_MCAST_LIST;
1397 mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1;
1398
1399 wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
1400 return;
1401 }
1402
1403 i = 0;
1404 ETHER_FIRST_MULTI(estep, ec, enm);
1405 while (enm != NULL) {
1406 /* Punt on ranges or too many multicast addresses. */
1407 if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
1408 ETHER_ADDR_LEN) != 0 ||
1409 i >= 16)
1410 goto allmulti;
1411
1412 memcpy((char *)&mcast.wi_mcast[i], enm->enm_addrlo,
1413 ETHER_ADDR_LEN);
1414 i++;
1415 ETHER_NEXT_MULTI(estep, enm);
1416 }
1417
1418 ifp->if_flags &= ~IFF_ALLMULTI;
1419 mcast.wi_type = WI_RID_MCAST_LIST;
1420 mcast.wi_len = ((ETHER_ADDR_LEN / 2) * i) + 1;
1421 wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
1422 }
1423
1424 static int
1425 wi_setdef(sc, wreq)
1426 struct wi_softc *sc;
1427 struct wi_req *wreq;
1428 {
1429 struct sockaddr_dl *sdl;
1430 struct ifnet *ifp;
1431 int error = 0;
1432
1433 ifp = &sc->sc_ethercom.ec_if;
1434
1435 switch(wreq->wi_type) {
1436 case WI_RID_MAC_NODE:
1437 sdl = (struct sockaddr_dl *)ifp->if_sadl;
1438 memcpy((char *)&sc->sc_macaddr, (char *)&wreq->wi_val,
1439 ETHER_ADDR_LEN);
1440 memcpy(LLADDR(sdl), (char *)&wreq->wi_val, ETHER_ADDR_LEN);
1441 break;
1442 case WI_RID_PORTTYPE:
1443 error = wi_sync_media(sc, le16toh(wreq->wi_val[0]),
1444 sc->wi_tx_rate);
1445 break;
1446 case WI_RID_TX_RATE:
1447 error = wi_sync_media(sc, sc->wi_ptype,
1448 le16toh(wreq->wi_val[0]));
1449 break;
1450 case WI_RID_MAX_DATALEN:
1451 sc->wi_max_data_len = le16toh(wreq->wi_val[0]);
1452 break;
1453 case WI_RID_RTS_THRESH:
1454 sc->wi_rts_thresh = le16toh(wreq->wi_val[0]);
1455 break;
1456 case WI_RID_SYSTEM_SCALE:
1457 sc->wi_ap_density = le16toh(wreq->wi_val[0]);
1458 break;
1459 case WI_RID_CREATE_IBSS:
1460 sc->wi_create_ibss = le16toh(wreq->wi_val[0]);
1461 error = wi_sync_media(sc, sc->wi_ptype, sc->wi_tx_rate);
1462 break;
1463 case WI_RID_OWN_CHNL:
1464 sc->wi_channel = le16toh(wreq->wi_val[0]);
1465 break;
1466 case WI_RID_NODENAME:
1467 error = wi_set_ssid(&sc->wi_nodeid,
1468 (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
1469 break;
1470 case WI_RID_DESIRED_SSID:
1471 error = wi_set_ssid(&sc->wi_netid,
1472 (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
1473 break;
1474 case WI_RID_OWN_SSID:
1475 error = wi_set_ssid(&sc->wi_ibssid,
1476 (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
1477 break;
1478 case WI_RID_PM_ENABLED:
1479 sc->wi_pm_enabled = le16toh(wreq->wi_val[0]);
1480 break;
1481 case WI_RID_MICROWAVE_OVEN:
1482 sc->wi_mor_enabled = le16toh(wreq->wi_val[0]);
1483 break;
1484 case WI_RID_MAX_SLEEP:
1485 sc->wi_max_sleep = le16toh(wreq->wi_val[0]);
1486 break;
1487 case WI_RID_CNFAUTHMODE:
1488 sc->wi_authtype = le16toh(wreq->wi_val[0]);
1489 break;
1490 case WI_RID_ROAMING_MODE:
1491 sc->wi_roaming = le16toh(wreq->wi_val[0]);
1492 break;
1493 case WI_RID_ENCRYPTION:
1494 sc->wi_use_wep = le16toh(wreq->wi_val[0]);
1495 break;
1496 case WI_RID_TX_CRYPT_KEY:
1497 sc->wi_tx_key = le16toh(wreq->wi_val[0]);
1498 break;
1499 case WI_RID_DEFLT_CRYPT_KEYS:
1500 memcpy((char *)&sc->wi_keys, (char *)wreq,
1501 sizeof(struct wi_ltv_keys));
1502 break;
1503 default:
1504 error = EINVAL;
1505 break;
1506 }
1507
1508 return (error);
1509 }
1510
1511 static int
1512 wi_getdef(sc, wreq)
1513 struct wi_softc *sc;
1514 struct wi_req *wreq;
1515 {
1516 struct sockaddr_dl *sdl;
1517 struct ifnet *ifp;
1518 int error = 0;
1519
1520 ifp = &sc->sc_ethercom.ec_if;
1521
1522 wreq->wi_len = 2; /* XXX */
1523 switch (wreq->wi_type) {
1524 case WI_RID_MAC_NODE:
1525 wreq->wi_len += ETHER_ADDR_LEN / 2 - 1;
1526 sdl = (struct sockaddr_dl *)ifp->if_sadl;
1527 memcpy(&wreq->wi_val, &sc->sc_macaddr, ETHER_ADDR_LEN);
1528 memcpy(&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN);
1529 break;
1530 case WI_RID_PORTTYPE:
1531 wreq->wi_val[0] = htole16(sc->wi_ptype);
1532 break;
1533 case WI_RID_TX_RATE:
1534 wreq->wi_val[0] = htole16(sc->wi_tx_rate);
1535 break;
1536 case WI_RID_MAX_DATALEN:
1537 wreq->wi_val[0] = htole16(sc->wi_max_data_len);
1538 break;
1539 case WI_RID_RTS_THRESH:
1540 wreq->wi_val[0] = htole16(sc->wi_rts_thresh);
1541 break;
1542 case WI_RID_SYSTEM_SCALE:
1543 wreq->wi_val[0] = htole16(sc->wi_ap_density);
1544 break;
1545 case WI_RID_CREATE_IBSS:
1546 wreq->wi_val[0] = htole16(sc->wi_create_ibss);
1547 break;
1548 case WI_RID_OWN_CHNL:
1549 wreq->wi_val[0] = htole16(sc->wi_channel);
1550 break;
1551 case WI_RID_NODENAME:
1552 wi_request_fill_ssid(wreq, &sc->wi_nodeid);
1553 break;
1554 case WI_RID_DESIRED_SSID:
1555 wi_request_fill_ssid(wreq, &sc->wi_netid);
1556 break;
1557 case WI_RID_OWN_SSID:
1558 wi_request_fill_ssid(wreq, &sc->wi_ibssid);
1559 break;
1560 case WI_RID_PM_ENABLED:
1561 wreq->wi_val[0] = htole16(sc->wi_pm_enabled);
1562 break;
1563 case WI_RID_MICROWAVE_OVEN:
1564 wreq->wi_val[0] = htole16(sc->wi_mor_enabled);
1565 break;
1566 case WI_RID_MAX_SLEEP:
1567 wreq->wi_val[0] = htole16(sc->wi_max_sleep);
1568 break;
1569 case WI_RID_CNFAUTHMODE:
1570 wreq->wi_val[0] = htole16(sc->wi_authtype);
1571 break;
1572 case WI_RID_ROAMING_MODE:
1573 wreq->wi_val[0] = htole16(sc->wi_roaming);
1574 break;
1575 case WI_RID_WEP_AVAIL:
1576 wreq->wi_val[0] = (sc->wi_flags & WI_FLAGS_HAS_WEP) ?
1577 htole16(1) : htole16(0);
1578 break;
1579 case WI_RID_ENCRYPTION:
1580 wreq->wi_val[0] = htole16(sc->wi_use_wep);
1581 break;
1582 case WI_RID_TX_CRYPT_KEY:
1583 wreq->wi_val[0] = htole16(sc->wi_tx_key);
1584 break;
1585 case WI_RID_DEFLT_CRYPT_KEYS:
1586 wreq->wi_len += sizeof(struct wi_ltv_keys) / 2 - 1;
1587 memcpy(wreq, &sc->wi_keys, sizeof(struct wi_ltv_keys));
1588 break;
1589 default:
1590 #if 0
1591 error = EIO;
1592 #else
1593 #ifdef WI_DEBUG
1594 printf("%s: wi_getdef: unknown request %d\n",
1595 sc->sc_dev.dv_xname, wreq->wi_type);
1596 #endif
1597 #endif
1598 break;
1599 }
1600
1601 return (error);
1602 }
1603
1604 static int
1605 wi_ioctl(ifp, command, data)
1606 struct ifnet *ifp;
1607 u_long command;
1608 caddr_t data;
1609 {
1610 int s, error = 0;
1611 int len;
1612 struct wi_softc *sc = ifp->if_softc;
1613 struct wi_req wreq;
1614 struct ifreq *ifr;
1615 struct proc *p = curproc;
1616 struct ieee80211_nwid nwid;
1617
1618 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
1619 return (ENXIO);
1620
1621 s = splnet();
1622
1623 ifr = (struct ifreq *)data;
1624 switch (command) {
1625 case SIOCSIFADDR:
1626 case SIOCGIFADDR:
1627 case SIOCSIFMTU:
1628 error = ether_ioctl(ifp, command, data);
1629 break;
1630 case SIOCSIFFLAGS:
1631 if (ifp->if_flags & IFF_UP) {
1632 if (ifp->if_flags & IFF_RUNNING &&
1633 ifp->if_flags & IFF_PROMISC &&
1634 !(sc->wi_if_flags & IFF_PROMISC)) {
1635 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
1636 WI_SETVAL(WI_RID_PROMISC, 1);
1637 } else if (ifp->if_flags & IFF_RUNNING &&
1638 !(ifp->if_flags & IFF_PROMISC) &&
1639 sc->wi_if_flags & IFF_PROMISC) {
1640 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
1641 WI_SETVAL(WI_RID_PROMISC, 0);
1642 } else
1643 wi_init(ifp);
1644 } else if (ifp->if_flags & IFF_RUNNING)
1645 wi_stop(ifp, 0);
1646 sc->wi_if_flags = ifp->if_flags;
1647
1648 if (!(ifp->if_flags & IFF_UP)) {
1649 if (sc->sc_enabled) {
1650 if (sc->sc_disable)
1651 (*sc->sc_disable)(sc);
1652 sc->sc_enabled = 0;
1653 ifp->if_flags &= ~IFF_RUNNING;
1654 }
1655 }
1656 error = 0;
1657 break;
1658 case SIOCADDMULTI:
1659 case SIOCDELMULTI:
1660 error = (command == SIOCADDMULTI) ?
1661 ether_addmulti(ifr, &sc->sc_ethercom) :
1662 ether_delmulti(ifr, &sc->sc_ethercom);
1663 if (error == ENETRESET) {
1664 if (sc->sc_enabled != 0) {
1665 /*
1666 * Multicast list has changed. Set the
1667 * hardware filter accordingly.
1668 */
1669 wi_setmulti(sc);
1670 }
1671 error = 0;
1672 }
1673 break;
1674 case SIOCSIFMEDIA:
1675 case SIOCGIFMEDIA:
1676 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
1677 break;
1678 case SIOCGWAVELAN:
1679 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1680 if (error)
1681 break;
1682 if (wreq.wi_type == WI_RID_IFACE_STATS) {
1683 memcpy((char *)&wreq.wi_val, (char *)&sc->wi_stats,
1684 sizeof(sc->wi_stats));
1685 wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
1686 } else if (wreq.wi_type == WI_RID_READ_APS) {
1687 if (sc->wi_scanning) {
1688 error = EINPROGRESS;
1689 break;
1690 } else {
1691 len = sc->wi_naps * sizeof(struct wi_apinfo);
1692 len = len > WI_MAX_DATALEN ? WI_MAX_DATALEN : len;
1693 len = len / sizeof(struct wi_apinfo);
1694 memcpy((char *)&wreq.wi_val, (char *)&len, sizeof(len));
1695 memcpy((char *)&wreq.wi_val + sizeof(len),
1696 (char *)&sc->wi_aps,
1697 len * sizeof(struct wi_apinfo));
1698 }
1699 } else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) {
1700 /* For non-root user, return all-zeroes keys */
1701 if (suser(p->p_ucred, &p->p_acflag))
1702 memset((char *)&wreq, 0,
1703 sizeof(struct wi_ltv_keys));
1704 else
1705 memcpy((char *)&wreq, (char *)&sc->wi_keys,
1706 sizeof(struct wi_ltv_keys));
1707 } else {
1708 if (sc->sc_enabled == 0 ||
1709 (wreq.wi_type == WI_RID_ROAMING_MODE &&
1710 (sc->wi_flags & WI_FLAGS_HAS_ROAMING) == 0) ||
1711 (wreq.wi_type == WI_RID_CREATE_IBSS &&
1712 (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) == 0) ||
1713 (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
1714 (sc->wi_flags & WI_FLAGS_HAS_MOR) == 0))
1715 error = wi_getdef(sc, &wreq);
1716 else if (wreq.wi_len > WI_MAX_DATALEN)
1717 error = EINVAL;
1718 else if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq))
1719 error = EINVAL;
1720 }
1721 if (error == 0)
1722 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
1723 break;
1724 case SIOCSWAVELAN:
1725 error = suser(p->p_ucred, &p->p_acflag);
1726 if (error)
1727 break;
1728 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1729 if (error)
1730 break;
1731 if (wreq.wi_type == WI_RID_IFACE_STATS) {
1732 if (sc->sc_enabled)
1733 wi_inquire(sc);
1734 break;
1735 } else if (wreq.wi_type == WI_RID_MGMT_XMIT) {
1736 error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
1737 wreq.wi_len);
1738 } else if (wreq.wi_type == WI_RID_SCAN_APS) {
1739 if (wreq.wi_len != 4) {
1740 error = EINVAL;
1741 break;
1742 }
1743 if (!sc->wi_scanning) {
1744 switch (sc->sc_firmware_type) {
1745 case WI_LUCENT:
1746 break;
1747 case WI_INTERSIL:
1748 wreq.wi_type = WI_RID_SCAN_REQ;
1749 error = wi_write_record(sc,
1750 (struct wi_ltv_gen *)&wreq);
1751 break;
1752 case WI_SYMBOL:
1753 /*
1754 * XXX only supported on 3.x ?
1755 */
1756 wreq.wi_type = WI_RID_BCAST_SCAN_REQ;
1757 wreq.wi_val[0] =
1758 BSCAN_BCAST | BSCAN_ONETIME;
1759 wreq.wi_len = 2;
1760 error = wi_write_record(sc,
1761 (struct wi_ltv_gen *)&wreq);
1762 break;
1763 }
1764 if (!error) {
1765 sc->wi_scanning = 1;
1766 callout_reset(&sc->wi_scan_sh, hz * 1,
1767 wi_wait_scan, sc);
1768 }
1769 }
1770 } else {
1771 /*
1772 * Filter stuff out based on what the
1773 * card can do.
1774 */
1775 if ((wreq.wi_type == WI_RID_ROAMING_MODE &&
1776 (sc->wi_flags & WI_FLAGS_HAS_ROAMING) == 0) ||
1777 (wreq.wi_type == WI_RID_CREATE_IBSS &&
1778 (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) == 0) ||
1779 (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
1780 (sc->wi_flags & WI_FLAGS_HAS_MOR) == 0))
1781 break;
1782
1783 if (wreq.wi_len > WI_MAX_DATALEN)
1784 error = EINVAL;
1785 else if (sc->sc_enabled != 0)
1786 error = wi_write_record(sc,
1787 (struct wi_ltv_gen *)&wreq);
1788 if (error == 0)
1789 error = wi_setdef(sc, &wreq);
1790 if (error == 0 && sc->sc_enabled != 0)
1791 /* Reinitialize WaveLAN. */
1792 wi_init(ifp);
1793 }
1794 break;
1795 case SIOCG80211NWID:
1796 if (sc->sc_enabled == 0) {
1797 /* Return the desired ID */
1798 error = copyout(&sc->wi_netid, ifr->ifr_data,
1799 sizeof(sc->wi_netid));
1800 } else {
1801 wreq.wi_type = WI_RID_CURRENT_SSID;
1802 wreq.wi_len = WI_MAX_DATALEN;
1803 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) ||
1804 le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN)
1805 error = EINVAL;
1806 else {
1807 wi_set_ssid(&nwid, (u_int8_t *)&wreq.wi_val[1],
1808 le16toh(wreq.wi_val[0]));
1809 error = copyout(&nwid, ifr->ifr_data,
1810 sizeof(nwid));
1811 }
1812 }
1813 break;
1814 case SIOCS80211NWID:
1815 error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
1816 if (error != 0)
1817 break;
1818 if (nwid.i_len > IEEE80211_NWID_LEN) {
1819 error = EINVAL;
1820 break;
1821 }
1822 if (sc->wi_netid.i_len == nwid.i_len &&
1823 memcmp(sc->wi_netid.i_nwid, nwid.i_nwid, nwid.i_len) == 0)
1824 break;
1825 wi_set_ssid(&sc->wi_netid, nwid.i_nwid, nwid.i_len);
1826 if (sc->sc_enabled != 0)
1827 /* Reinitialize WaveLAN. */
1828 wi_init(ifp);
1829 break;
1830 case SIOCS80211NWKEY:
1831 error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
1832 break;
1833 case SIOCG80211NWKEY:
1834 error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
1835 break;
1836 case SIOCS80211POWER:
1837 error = wi_set_pm(sc, (struct ieee80211_power *)data);
1838 break;
1839 case SIOCG80211POWER:
1840 error = wi_get_pm(sc, (struct ieee80211_power *)data);
1841 break;
1842 case SIOCHOSTAP_ADD:
1843 case SIOCHOSTAP_DEL:
1844 case SIOCHOSTAP_GET:
1845 case SIOCHOSTAP_GETALL:
1846 case SIOCHOSTAP_GFLAGS:
1847 case SIOCHOSTAP_SFLAGS:
1848 /* Send all Host-AP specific ioctls to the Host-AP code. */
1849 error = wihap_ioctl(sc, command, data);
1850 break;
1851
1852 default:
1853 error = EINVAL;
1854 break;
1855 }
1856
1857 splx(s);
1858 return (error);
1859 }
1860
1861 static int
1862 wi_init(ifp)
1863 struct ifnet *ifp;
1864 {
1865 struct wi_softc *sc = ifp->if_softc;
1866 struct wi_req wreq;
1867 struct wi_ltv_macaddr mac;
1868 int error, id = 0, wasenabled;
1869
1870 wasenabled = sc->sc_enabled;
1871 if (!sc->sc_enabled) {
1872 if ((error = (*sc->sc_enable)(sc)) != 0)
1873 goto out;
1874 sc->sc_enabled = 1;
1875 }
1876
1877 wi_stop(ifp, 0);
1878 /* Symbol firmware cannot be initialized more than once */
1879 if (!(sc->sc_firmware_type == WI_SYMBOL && wasenabled))
1880 wi_reset(sc);
1881
1882 /* Program max data length. */
1883 WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
1884
1885 /* Enable/disable IBSS creation. */
1886 WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
1887
1888 /* Set the port type. */
1889 WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
1890
1891 /* Program the RTS/CTS threshold. */
1892 WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
1893
1894 /* Program the TX rate */
1895 WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
1896
1897 /* Access point density */
1898 WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
1899
1900 /* Power Management Enabled */
1901 WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
1902
1903 /* Power Managment Max Sleep */
1904 WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
1905
1906 /* Roaming type */
1907 if (sc->wi_flags & WI_FLAGS_HAS_ROAMING)
1908 WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
1909
1910 /* Specify the network name */
1911 wi_write_ssid(sc, WI_RID_DESIRED_SSID, &wreq, &sc->wi_netid);
1912
1913 /* Specify the IBSS name */
1914 if (sc->wi_netid.i_len != 0 &&
1915 (sc->wi_ptype == WI_PORTTYPE_HOSTAP ||
1916 (sc->wi_create_ibss && sc->wi_ptype == WI_PORTTYPE_IBSS)))
1917 wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_netid);
1918 else
1919 wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_ibssid);
1920
1921 /* Specify the frequency to use */
1922 WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel);
1923
1924 /* Program the nodename. */
1925 wi_write_ssid(sc, WI_RID_NODENAME, &wreq, &sc->wi_nodeid);
1926
1927 /* Set our MAC address. */
1928 mac.wi_len = 4;
1929 mac.wi_type = WI_RID_MAC_NODE;
1930 memcpy(&mac.wi_mac_addr, sc->sc_macaddr, ETHER_ADDR_LEN);
1931 wi_write_record(sc, (struct wi_ltv_gen *)&mac);
1932
1933 /*
1934 * Initialize promisc mode.
1935 * Being in the Host-AP mode causes a great
1936 * deal of pain if primisc mode is set.
1937 * Therefore we avoid confusing the firmware
1938 * and always reset promisc mode in Host-AP
1939 * mode. Host-AP sees all the packets anyway.
1940 */
1941 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP &&
1942 (ifp->if_flags & IFF_PROMISC) != 0) {
1943 WI_SETVAL(WI_RID_PROMISC, 1);
1944 } else {
1945 WI_SETVAL(WI_RID_PROMISC, 0);
1946 }
1947
1948 /* Configure WEP. */
1949 if (sc->wi_flags & WI_FLAGS_HAS_WEP) {
1950 WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
1951 WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
1952 sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
1953 sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
1954 wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
1955 if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
1956 /*
1957 * ONLY HWB3163 EVAL-CARD Firmware version
1958 * less than 0.8 variant2
1959 *
1960 * If promiscuous mode disable, Prism2 chip
1961 * does not work with WEP .
1962 * It is under investigation for details.
1963 * (ichiro (at) netbsd.org)
1964 */
1965 if (sc->sc_firmware_type == WI_INTERSIL &&
1966 sc->sc_sta_firmware_ver < 802 ) {
1967 /* firm ver < 0.8 variant 2 */
1968 WI_SETVAL(WI_RID_PROMISC, 1);
1969 }
1970 WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype);
1971 }
1972 }
1973
1974 /* Set multicast filter. */
1975 wi_setmulti(sc);
1976
1977 /* Enable desired port */
1978 wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0);
1979
1980 /* scanning variable is modal, therefore reinit to OFF, in case it was on. */
1981 sc->wi_scanning=0;
1982 sc->wi_naps=0;
1983
1984 if ((error = wi_alloc_nicmem(sc,
1985 1518 + sizeof(struct wi_frame) + 8, &id)) != 0) {
1986 printf("%s: tx buffer allocation failed\n",
1987 sc->sc_dev.dv_xname);
1988 goto out;
1989 }
1990 sc->wi_tx_data_id = id;
1991
1992 if ((error = wi_alloc_nicmem(sc,
1993 1518 + sizeof(struct wi_frame) + 8, &id)) != 0) {
1994 printf("%s: mgmt. buffer allocation failed\n",
1995 sc->sc_dev.dv_xname);
1996 goto out;
1997 }
1998 sc->wi_tx_mgmt_id = id;
1999
2000 /* Enable interrupts */
2001 CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
2002
2003 wihap_init(sc);
2004
2005 ifp->if_flags |= IFF_RUNNING;
2006 ifp->if_flags &= ~IFF_OACTIVE;
2007
2008 callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
2009
2010 out:
2011 if (error) {
2012 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
2013 ifp->if_timer = 0;
2014 printf("%s: interface not running\n", sc->sc_dev.dv_xname);
2015 }
2016 return (error);
2017 }
2018
2019 static const u_int32_t crc32_tab[] = {
2020 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
2021 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
2022 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
2023 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
2024 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
2025 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
2026 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
2027 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
2028 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
2029 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
2030 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
2031 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
2032 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
2033 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
2034 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
2035 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
2036 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
2037 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
2038 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
2039 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
2040 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
2041 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
2042 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
2043 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
2044 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
2045 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
2046 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
2047 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
2048 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
2049 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
2050 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
2051 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
2052 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
2053 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
2054 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
2055 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
2056 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
2057 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
2058 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
2059 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
2060 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
2061 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
2062 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
2063 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
2064 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
2065 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
2066 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
2067 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
2068 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
2069 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
2070 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
2071 0x2d02ef8dL
2072 };
2073
2074 #define RC4STATE 256
2075 #define RC4KEYLEN 16
2076 #define RC4SWAP(x,y) \
2077 do { u_int8_t t = state[x]; state[x] = state[y]; state[y] = t; } while(0)
2078
2079 static void
2080 wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len)
2081 {
2082 u_int32_t i, crc, klen;
2083 u_int8_t state[RC4STATE], key[RC4KEYLEN];
2084 u_int8_t x, y, *dat;
2085
2086 if (!sc->wi_icv_flag) {
2087 sc->wi_icv = arc4random();
2088 sc->wi_icv_flag++;
2089 } else
2090 sc->wi_icv++;
2091 /*
2092 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
2093 * (B, 255, N) with 3 <= B < 8
2094 */
2095 if (sc->wi_icv >= 0x03ff00 &&
2096 (sc->wi_icv & 0xf8ff00) == 0x00ff00)
2097 sc->wi_icv += 0x000100;
2098
2099 /* prepend 24bit IV to tx key, byte order does not matter */
2100 key[0] = sc->wi_icv >> 16;
2101 key[1] = sc->wi_icv >> 8;
2102 key[2] = sc->wi_icv;
2103
2104 klen = le16toh(sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen) +
2105 IEEE80211_WEP_IVLEN;
2106 klen = (klen >= RC4KEYLEN) ? RC4KEYLEN : RC4KEYLEN/2;
2107 bcopy((char *)&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat,
2108 (char *)key + IEEE80211_WEP_IVLEN, klen - IEEE80211_WEP_IVLEN);
2109
2110 /* rc4 keysetup */
2111 x = y = 0;
2112 for (i = 0; i < RC4STATE; i++)
2113 state[i] = i;
2114 for (i = 0; i < RC4STATE; i++) {
2115 y = (key[x] + state[i] + y) % RC4STATE;
2116 RC4SWAP(i, y);
2117 x = (x + 1) % klen;
2118 }
2119
2120 /* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */
2121 dat = buf;
2122 dat[0] = key[0];
2123 dat[1] = key[1];
2124 dat[2] = key[2];
2125 dat[3] = sc->wi_tx_key << 6; /* pad and keyid */
2126 dat += 4;
2127
2128 /* compute rc4 over data, crc32 over data */
2129 crc = ~0;
2130 x = y = 0;
2131 for (i = 0; i < len; i++) {
2132 x = (x + 1) % RC4STATE;
2133 y = (state[x] + y) % RC4STATE;
2134 RC4SWAP(x, y);
2135 crc = crc32_tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8);
2136 dat[i] ^= state[(state[x] + state[y]) % RC4STATE];
2137 }
2138 crc = ~crc;
2139 dat += len;
2140
2141 /* append little-endian crc32 and encrypt */
2142 dat[0] = crc;
2143 dat[1] = crc >> 8;
2144 dat[2] = crc >> 16;
2145 dat[3] = crc >> 24;
2146 for (i = 0; i < IEEE80211_WEP_CRCLEN; i++) {
2147 x = (x + 1) % RC4STATE;
2148 y = (state[x] + y) % RC4STATE;
2149 RC4SWAP(x, y);
2150 dat[i] ^= state[(state[x] + state[y]) % RC4STATE];
2151 }
2152 }
2153
2154 static void
2155 wi_start(ifp)
2156 struct ifnet *ifp;
2157 {
2158 struct wi_softc *sc;
2159 struct mbuf *m0;
2160 struct wi_frame tx_frame;
2161 struct ether_header *eh;
2162 int id;
2163
2164 sc = ifp->if_softc;
2165
2166 if (ifp->if_flags & IFF_OACTIVE)
2167 return;
2168
2169 nextpkt:
2170 IFQ_DEQUEUE(&ifp->if_snd, m0);
2171 if (m0 == NULL)
2172 return;
2173
2174 memset((char *)&tx_frame, 0, sizeof(tx_frame));
2175 tx_frame.wi_frame_ctl = htole16(WI_FTYPE_DATA);
2176 id = sc->wi_tx_data_id;
2177 eh = mtod(m0, struct ether_header *);
2178
2179 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2180 if (wihap_check_tx(&sc->wi_hostap_info, eh->ether_dhost,
2181 &tx_frame.wi_tx_rate) == 0 &&
2182 (ifp->if_flags & IFF_PROMISC) == 0) {
2183 if (ifp->if_flags & IFF_DEBUG)
2184 printf("%s: Host-AP: dropping unassoc "
2185 "dst %s\n", sc->sc_dev.dv_xname,
2186 ether_sprintf(eh->ether_dhost));
2187 m_freem(m0);
2188 goto nextpkt;
2189 }
2190 }
2191
2192 /*
2193 * Use RFC1042 encoding for IP and ARP datagrams,
2194 * 802.3 for anything else.
2195 */
2196 if (eh->ether_type == htons(ETHERTYPE_IP) ||
2197 eh->ether_type == htons(ETHERTYPE_ARP) ||
2198 eh->ether_type == htons(ETHERTYPE_REVARP) ||
2199 eh->ether_type == htons(ETHERTYPE_IPV6)) {
2200 memcpy((char *)&tx_frame.wi_addr1, (char *)&eh->ether_dhost,
2201 ETHER_ADDR_LEN);
2202 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2203 tx_frame.wi_tx_ctl |= htole16(WI_ENC_TX_MGMT);/* XXX */
2204 tx_frame.wi_frame_ctl |= htole16(WI_FCTL_FROMDS);
2205 if (sc->wi_use_wep)
2206 tx_frame.wi_frame_ctl |= htole16(WI_FCTL_WEP);
2207 memcpy((char *)&tx_frame.wi_addr2,
2208 (char *)LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
2209 memcpy((char *)&tx_frame.wi_addr3,
2210 (char *)&eh->ether_shost, ETHER_ADDR_LEN);
2211 } else
2212 memcpy((char *)&tx_frame.wi_addr2,
2213 (char *)&eh->ether_shost, ETHER_ADDR_LEN);
2214 memcpy((char *)&tx_frame.wi_dst_addr, (char *)&eh->ether_dhost,
2215 ETHER_ADDR_LEN);
2216 memcpy((char *)&tx_frame.wi_src_addr, (char *)&eh->ether_shost,
2217 ETHER_ADDR_LEN);
2218
2219 tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN;
2220 tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0);
2221 tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1);
2222 tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
2223 tx_frame.wi_type = eh->ether_type;
2224
2225 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
2226 /* Do host encryption. */
2227 memcpy(&sc->wi_txbuf[4], &tx_frame.wi_dat[0], 8);
2228
2229 m_copydata(m0, sizeof(struct ether_header),
2230 m0->m_pkthdr.len - sizeof(struct ether_header),
2231 (caddr_t)&sc->wi_txbuf[12]);
2232
2233 wi_do_hostencrypt(sc, (caddr_t)&sc->wi_txbuf,
2234 tx_frame.wi_dat_len);
2235
2236 tx_frame.wi_dat_len += IEEE80211_WEP_IVLEN +
2237 IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
2238
2239 tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
2240
2241 wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
2242 sizeof(struct wi_frame));
2243 wi_write_data(sc, id, WI_802_11_OFFSET_RAW,
2244 (caddr_t)&sc->wi_txbuf,
2245 (m0->m_pkthdr.len -
2246 sizeof(struct ether_header)) + 18);
2247 } else {
2248 m_copydata(m0, sizeof(struct ether_header),
2249 m0->m_pkthdr.len - sizeof(struct ether_header),
2250 (caddr_t)&sc->wi_txbuf);
2251
2252 tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
2253
2254 wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
2255 sizeof(struct wi_frame));
2256 wi_write_data(sc, id, WI_802_11_OFFSET,
2257 (caddr_t)&sc->wi_txbuf,
2258 (m0->m_pkthdr.len -
2259 sizeof(struct ether_header)) + 2);
2260 }
2261 } else {
2262 tx_frame.wi_dat_len = htole16(m0->m_pkthdr.len);
2263
2264 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
2265 /* Do host encryption. (XXX - not implemented) */
2266 printf("%s: host encryption not implemented "
2267 "for 802.3\n", sc->sc_dev.dv_xname);
2268 } else {
2269 m_copydata(m0, 0, m0->m_pkthdr.len,
2270 (caddr_t)&sc->wi_txbuf);
2271
2272 wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
2273 sizeof(struct wi_frame));
2274 wi_write_data(sc, id, WI_802_3_OFFSET,
2275 (caddr_t)&sc->wi_txbuf, m0->m_pkthdr.len + 2);
2276 }
2277 }
2278
2279 #if NBPFILTER > 0
2280 /*
2281 * If there's a BPF listener, bounce a copy of
2282 * this frame to him.
2283 */
2284 if (ifp->if_bpf)
2285 bpf_mtap(ifp->if_bpf, m0);
2286 #endif
2287
2288 m_freem(m0);
2289
2290 if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
2291 printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
2292
2293 ifp->if_flags |= IFF_OACTIVE;
2294
2295 /*
2296 * Set a timeout in case the chip goes out to lunch.
2297 */
2298 ifp->if_timer = 5;
2299
2300 return;
2301 }
2302
2303 int
2304 wi_mgmt_xmit(sc, data, len)
2305 struct wi_softc *sc;
2306 caddr_t data;
2307 int len;
2308 {
2309 struct wi_frame tx_frame;
2310 int id;
2311 struct wi_80211_hdr *hdr;
2312 caddr_t dptr;
2313
2314 hdr = (struct wi_80211_hdr *)data;
2315 dptr = data + sizeof(struct wi_80211_hdr);
2316
2317 memset((char *)&tx_frame, 0, sizeof(tx_frame));
2318 id = sc->wi_tx_mgmt_id;
2319
2320 memcpy((char *)&tx_frame.wi_frame_ctl, (char *)hdr,
2321 sizeof(struct wi_80211_hdr));
2322
2323 tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT);
2324 tx_frame.wi_dat_len = len - sizeof(struct wi_80211_hdr);
2325 tx_frame.wi_len = htole16(tx_frame.wi_dat_len);
2326
2327 tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
2328
2329 wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame));
2330 wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr,
2331 (len - sizeof(struct wi_80211_hdr)) + 2);
2332
2333 if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) {
2334 printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
2335 return(EIO);
2336 }
2337
2338 return(0);
2339 }
2340
2341 static void
2342 wi_stop(ifp, disable)
2343 struct ifnet *ifp;
2344 {
2345 struct wi_softc *sc = ifp->if_softc;
2346
2347 wihap_shutdown(sc);
2348
2349 CSR_WRITE_2(sc, WI_INT_EN, 0);
2350 wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0);
2351
2352 callout_stop(&sc->wi_inquire_ch);
2353 callout_stop(&sc->wi_scan_sh);
2354
2355 if (disable) {
2356 if (sc->sc_enabled) {
2357 if (sc->sc_disable)
2358 (*sc->sc_disable)(sc);
2359 sc->sc_enabled = 0;
2360 }
2361 }
2362
2363 ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
2364 ifp->if_timer = 0;
2365 }
2366
2367 static void
2368 wi_watchdog(ifp)
2369 struct ifnet *ifp;
2370 {
2371 struct wi_softc *sc;
2372
2373 sc = ifp->if_softc;
2374
2375 printf("%s: device timeout\n", sc->sc_dev.dv_xname);
2376
2377 wi_init(ifp);
2378
2379 ifp->if_oerrors++;
2380
2381 return;
2382 }
2383
2384 void
2385 wi_shutdown(sc)
2386 struct wi_softc *sc;
2387 {
2388 int s;
2389
2390 s = splnet();
2391 if (sc->sc_enabled) {
2392 if (sc->sc_disable)
2393 (*sc->sc_disable)(sc);
2394 sc->sc_enabled = 0;
2395 }
2396 splx(s);
2397 }
2398
2399 int
2400 wi_activate(self, act)
2401 struct device *self;
2402 enum devact act;
2403 {
2404 struct wi_softc *sc = (struct wi_softc *)self;
2405 int rv = 0, s;
2406
2407 s = splnet();
2408 switch (act) {
2409 case DVACT_ACTIVATE:
2410 rv = EOPNOTSUPP;
2411 break;
2412
2413 case DVACT_DEACTIVATE:
2414 if_deactivate(&sc->sc_ethercom.ec_if);
2415 break;
2416 }
2417 splx(s);
2418 return (rv);
2419 }
2420
2421 static void
2422 wi_get_id(sc)
2423 struct wi_softc *sc;
2424 {
2425 struct wi_ltv_ver ver;
2426 struct wi_card_ident *id;
2427
2428 /* getting chip identity */
2429 memset(&ver, 0, sizeof(ver));
2430 ver.wi_type = WI_RID_CARD_ID;
2431 ver.wi_len = 5;
2432 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2433 printf("%s: using ", sc->sc_dev.dv_xname);
2434
2435 sc->sc_firmware_type = WI_NOTYPE;
2436 for (id = wi_card_ident; id->card_name != NULL; id++) {
2437 if (le16toh(ver.wi_ver[0]) == id->card_id) {
2438 printf("%s", id->card_name);
2439 sc->sc_firmware_type = id->firm_type;
2440 break;
2441 }
2442 }
2443 if (sc->sc_firmware_type == WI_NOTYPE) {
2444 if (le16toh(ver.wi_ver[0]) & 0x8000) {
2445 printf("Unknown PRISM2 chip");
2446 sc->sc_firmware_type = WI_INTERSIL;
2447 } else {
2448 printf("Unknown Lucent chip");
2449 sc->sc_firmware_type = WI_LUCENT;
2450 }
2451 }
2452
2453 /* get primary firmware version (Only Prism chips) */
2454 if (sc->sc_firmware_type != WI_LUCENT) {
2455 memset(&ver, 0, sizeof(ver));
2456 ver.wi_type = WI_RID_PRI_IDENTITY;
2457 ver.wi_len = 5;
2458 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2459 LE16TOH(ver.wi_ver[1]);
2460 LE16TOH(ver.wi_ver[2]);
2461 LE16TOH(ver.wi_ver[3]);
2462 sc->sc_pri_firmware_ver = ver.wi_ver[2] * 10000 +
2463 ver.wi_ver[3] * 100 + ver.wi_ver[1];
2464 }
2465
2466 /* get station firmware version */
2467 memset(&ver, 0, sizeof(ver));
2468 ver.wi_type = WI_RID_STA_IDENTITY;
2469 ver.wi_len = 5;
2470 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2471 LE16TOH(ver.wi_ver[1]);
2472 LE16TOH(ver.wi_ver[2]);
2473 LE16TOH(ver.wi_ver[3]);
2474 sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
2475 ver.wi_ver[3] * 100 + ver.wi_ver[1];
2476 if (sc->sc_firmware_type == WI_INTERSIL &&
2477 (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
2478 struct wi_ltv_str sver;
2479 char *p;
2480
2481 memset(&sver, 0, sizeof(sver));
2482 sver.wi_type = WI_RID_SYMBOL_IDENTITY;
2483 sver.wi_len = 7;
2484 /* value should be the format like "V2.00-11" */
2485 if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
2486 *(p = (char *)sver.wi_str) >= 'A' &&
2487 p[2] == '.' && p[5] == '-' && p[8] == '\0') {
2488 sc->sc_firmware_type = WI_SYMBOL;
2489 sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
2490 (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
2491 (p[6] - '0') * 10 + (p[7] - '0');
2492 }
2493 }
2494
2495 printf("\n%s: %s Firmware: ", sc->sc_dev.dv_xname,
2496 sc->sc_firmware_type == WI_LUCENT ? "Lucent" :
2497 (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil"));
2498 if (sc->sc_firmware_type != WI_LUCENT) /* XXX */
2499 printf("Primary (%u.%u.%u), ", sc->sc_pri_firmware_ver / 10000,
2500 (sc->sc_pri_firmware_ver % 10000) / 100,
2501 sc->sc_pri_firmware_ver % 100);
2502 printf("Station (%u.%u.%u)\n",
2503 sc->sc_sta_firmware_ver / 10000, (sc->sc_sta_firmware_ver % 10000) / 100,
2504 sc->sc_sta_firmware_ver % 100);
2505
2506 return;
2507 }
2508
2509 int
2510 wi_detach(sc)
2511 struct wi_softc *sc;
2512 {
2513 struct ifnet *ifp = sc->sc_ifp;
2514 int s;
2515
2516 if (!sc->sc_attached)
2517 return (0);
2518
2519 s = splnet();
2520 callout_stop(&sc->wi_inquire_ch);
2521
2522 /* Delete all remaining media. */
2523 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
2524
2525 ether_ifdetach(ifp);
2526 if_detach(ifp);
2527 if (sc->sc_enabled) {
2528 if (sc->sc_disable)
2529 (*sc->sc_disable)(sc);
2530 sc->sc_enabled = 0;
2531 }
2532 splx(s);
2533 return (0);
2534 }
2535
2536 void
2537 wi_power(sc, why)
2538 struct wi_softc *sc;
2539 int why;
2540 {
2541 int s;
2542
2543 if (!sc->sc_enabled)
2544 return;
2545
2546 s = splnet();
2547 switch (why) {
2548 case PWR_SUSPEND:
2549 case PWR_STANDBY:
2550 wi_stop(sc->sc_ifp, 0);
2551 if (sc->sc_enabled) {
2552 if (sc->sc_disable)
2553 (*sc->sc_disable)(sc);
2554 }
2555 break;
2556 case PWR_RESUME:
2557 sc->sc_enabled = 0;
2558 wi_init(sc->sc_ifp);
2559 (void)wi_intr(sc);
2560 break;
2561 case PWR_SOFTSUSPEND:
2562 case PWR_SOFTSTANDBY:
2563 case PWR_SOFTRESUME:
2564 break;
2565 }
2566 splx(s);
2567 }
2568
2569 static int
2570 wi_set_ssid(ws, id, len)
2571 struct ieee80211_nwid *ws;
2572 u_int8_t *id;
2573 int len;
2574 {
2575
2576 if (len > IEEE80211_NWID_LEN)
2577 return (EINVAL);
2578 ws->i_len = len;
2579 memcpy(ws->i_nwid, id, len);
2580 return (0);
2581 }
2582
2583 static void
2584 wi_request_fill_ssid(wreq, ws)
2585 struct wi_req *wreq;
2586 struct ieee80211_nwid *ws;
2587 {
2588 int len = ws->i_len;
2589
2590 memset(&wreq->wi_val[0], 0, sizeof(wreq->wi_val));
2591 wreq->wi_val[0] = htole16(len);
2592 wreq->wi_len = roundup(len, 2) / 2 + 2;
2593 memcpy(&wreq->wi_val[1], ws->i_nwid, len);
2594 }
2595
2596 static int
2597 wi_write_ssid(sc, type, wreq, ws)
2598 struct wi_softc *sc;
2599 int type;
2600 struct wi_req *wreq;
2601 struct ieee80211_nwid *ws;
2602 {
2603
2604 wreq->wi_type = type;
2605 wi_request_fill_ssid(wreq, ws);
2606 return (wi_write_record(sc, (struct wi_ltv_gen *)wreq));
2607 }
2608
2609 static int
2610 wi_sync_media(sc, ptype, txrate)
2611 struct wi_softc *sc;
2612 int ptype;
2613 int txrate;
2614 {
2615 int media = sc->sc_media.ifm_cur->ifm_media;
2616 int options = IFM_OPTIONS(media);
2617 int subtype;
2618
2619 switch (txrate) {
2620 case 1:
2621 subtype = IFM_IEEE80211_DS1;
2622 break;
2623 case 2:
2624 subtype = IFM_IEEE80211_DS2;
2625 break;
2626 case 3:
2627 subtype = IFM_AUTO;
2628 break;
2629 case 5:
2630 subtype = IFM_IEEE80211_DS5;
2631 break;
2632 case 11:
2633 subtype = IFM_IEEE80211_DS11;
2634 break;
2635 default:
2636 subtype = IFM_MANUAL; /* Unable to represent */
2637 break;
2638 }
2639
2640 options &= ~IFM_OMASK;
2641 switch (ptype) {
2642 case WI_PORTTYPE_BSS:
2643 /* default port type */
2644 break;
2645 case WI_PORTTYPE_ADHOC:
2646 options |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
2647 break;
2648 case WI_PORTTYPE_IBSS:
2649 options |= IFM_IEEE80211_ADHOC;
2650 break;
2651 default:
2652 subtype = IFM_MANUAL; /* Unable to represent */
2653 break;
2654 }
2655 media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
2656 IFM_INST(media));
2657 if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
2658 return (EINVAL);
2659 ifmedia_set(&sc->sc_media, media);
2660 sc->wi_ptype = ptype;
2661 sc->wi_tx_rate = txrate;
2662 return (0);
2663 }
2664
2665 static int
2666 wi_media_change(ifp)
2667 struct ifnet *ifp;
2668 {
2669 struct wi_softc *sc = ifp->if_softc;
2670 int otype = sc->wi_ptype;
2671 int orate = sc->wi_tx_rate;
2672 int ocreate_ibss = sc->wi_create_ibss;
2673
2674 sc->wi_create_ibss = 0;
2675
2676 switch (sc->sc_media.ifm_cur->ifm_media & IFM_OMASK) {
2677 case 0:
2678 sc->wi_ptype = WI_PORTTYPE_BSS;
2679 break;
2680 case IFM_IEEE80211_HOSTAP:
2681 sc->wi_ptype = WI_PORTTYPE_HOSTAP;
2682 break;
2683 case IFM_IEEE80211_ADHOC:
2684 sc->wi_ptype = WI_PORTTYPE_IBSS;
2685 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
2686 sc->wi_create_ibss = 1;
2687 break;
2688 case IFM_IEEE80211_ADHOC | IFM_FLAG0:
2689 sc->wi_ptype = WI_PORTTYPE_ADHOC;
2690 break;
2691 default:
2692 /* Invalid combination. */
2693 sc->wi_create_ibss = ocreate_ibss;
2694 return (EINVAL);
2695 }
2696
2697 switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
2698 case IFM_IEEE80211_DS1:
2699 sc->wi_tx_rate = 1;
2700 break;
2701 case IFM_IEEE80211_DS2:
2702 sc->wi_tx_rate = 2;
2703 break;
2704 case IFM_AUTO:
2705 sc->wi_tx_rate = 3;
2706 break;
2707 case IFM_IEEE80211_DS5:
2708 sc->wi_tx_rate = 5;
2709 break;
2710 case IFM_IEEE80211_DS11:
2711 sc->wi_tx_rate = 11;
2712 break;
2713 }
2714
2715 if (sc->sc_enabled != 0) {
2716 if (otype != sc->wi_ptype ||
2717 orate != sc->wi_tx_rate ||
2718 ocreate_ibss != sc->wi_create_ibss)
2719 wi_init(ifp);
2720 }
2721
2722 ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
2723
2724 return (0);
2725 }
2726
2727 static void
2728 wi_media_status(ifp, imr)
2729 struct ifnet *ifp;
2730 struct ifmediareq *imr;
2731 {
2732 struct wi_softc *sc = ifp->if_softc;
2733
2734 if (sc->sc_enabled == 0) {
2735 imr->ifm_active = IFM_IEEE80211|IFM_NONE;
2736 imr->ifm_status = 0;
2737 return;
2738 }
2739
2740 imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
2741 imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
2742 }
2743
2744 static int
2745 wi_set_nwkey(sc, nwkey)
2746 struct wi_softc *sc;
2747 struct ieee80211_nwkey *nwkey;
2748 {
2749 int i, error;
2750 size_t len;
2751 struct wi_req wreq;
2752 struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
2753
2754 if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0)
2755 return ENODEV;
2756 if (nwkey->i_defkid <= 0 ||
2757 nwkey->i_defkid > IEEE80211_WEP_NKID)
2758 return EINVAL;
2759 memcpy(wk, &sc->wi_keys, sizeof(*wk));
2760 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2761 if (nwkey->i_key[i].i_keydat == NULL)
2762 continue;
2763 len = nwkey->i_key[i].i_keylen;
2764 if (len > sizeof(wk->wi_keys[i].wi_keydat))
2765 return EINVAL;
2766 error = copyin(nwkey->i_key[i].i_keydat,
2767 wk->wi_keys[i].wi_keydat, len);
2768 if (error)
2769 return error;
2770 wk->wi_keys[i].wi_keylen = htole16(len);
2771 }
2772
2773 wk->wi_len = (sizeof(*wk) / 2) + 1;
2774 wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
2775 if (sc->sc_enabled != 0) {
2776 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2777 if (error)
2778 return error;
2779 }
2780 error = wi_setdef(sc, &wreq);
2781 if (error)
2782 return error;
2783
2784 wreq.wi_len = 2;
2785 wreq.wi_type = WI_RID_TX_CRYPT_KEY;
2786 wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
2787 if (sc->sc_enabled != 0) {
2788 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2789 if (error)
2790 return error;
2791 }
2792 error = wi_setdef(sc, &wreq);
2793 if (error)
2794 return error;
2795
2796 wreq.wi_type = WI_RID_ENCRYPTION;
2797 wreq.wi_val[0] = htole16(nwkey->i_wepon);
2798 if (sc->sc_enabled != 0) {
2799 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2800 if (error)
2801 return error;
2802 }
2803 error = wi_setdef(sc, &wreq);
2804 if (error)
2805 return error;
2806
2807 if (sc->sc_enabled != 0)
2808 wi_init(&sc->sc_ethercom.ec_if);
2809 return 0;
2810 }
2811
2812 static int
2813 wi_get_nwkey(sc, nwkey)
2814 struct wi_softc *sc;
2815 struct ieee80211_nwkey *nwkey;
2816 {
2817 int i, len, error;
2818 struct wi_ltv_keys *wk = &sc->wi_keys;
2819
2820 if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0)
2821 return ENODEV;
2822 nwkey->i_wepon = sc->wi_use_wep;
2823 nwkey->i_defkid = sc->wi_tx_key + 1;
2824
2825 /* do not show any keys to non-root user */
2826 error = suser(curproc->p_ucred, &curproc->p_acflag);
2827 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2828 if (nwkey->i_key[i].i_keydat == NULL)
2829 continue;
2830 /* error holds results of suser() for the first time */
2831 if (error)
2832 return error;
2833 len = le16toh(wk->wi_keys[i].wi_keylen);
2834 if (nwkey->i_key[i].i_keylen < len)
2835 return ENOSPC;
2836 nwkey->i_key[i].i_keylen = len;
2837 error = copyout(wk->wi_keys[i].wi_keydat,
2838 nwkey->i_key[i].i_keydat, len);
2839 if (error)
2840 return error;
2841 }
2842 return 0;
2843 }
2844
2845 static int
2846 wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
2847 {
2848
2849 sc->wi_pm_enabled = power->i_enabled;
2850 sc->wi_max_sleep = power->i_maxsleep;
2851
2852 if (sc->sc_enabled)
2853 return (wi_init(&sc->sc_ethercom.ec_if));
2854
2855 return (0);
2856 }
2857
2858 static int
2859 wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
2860 {
2861
2862 power->i_enabled = sc->wi_pm_enabled;
2863 power->i_maxsleep = sc->wi_max_sleep;
2864
2865 return (0);
2866 }
2867