Line data Source code
1 : /* $OpenBSD: if_wi.c,v 1.168 2018/02/19 08:59:52 mpi Exp $ */
2 :
3 : /*
4 : * Copyright (c) 1997, 1998, 1999
5 : * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : * 3. All advertising materials mentioning features or use of this software
16 : * must display the following acknowledgement:
17 : * This product includes software developed by Bill Paul.
18 : * 4. Neither the name of the author nor the names of any co-contributors
19 : * may be used to endorse or promote products derived from this software
20 : * without specific prior written permission.
21 : *
22 : * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 : * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 : * THE POSSIBILITY OF SUCH DAMAGE.
33 : *
34 : * From: if_wi.c,v 1.7 1999/07/04 14:40:22 wpaul Exp $
35 : */
36 :
37 : /*
38 : * Lucent WaveLAN/IEEE 802.11 driver for OpenBSD.
39 : *
40 : * Originally written by Bill Paul <wpaul@ctr.columbia.edu>
41 : * Electrical Engineering Department
42 : * Columbia University, New York City
43 : */
44 :
45 : /*
46 : * The WaveLAN/IEEE adapter is the second generation of the WaveLAN
47 : * from Lucent. Unlike the older cards, the new ones are programmed
48 : * entirely via a firmware-driven controller called the Hermes.
49 : * Unfortunately, Lucent will not release the Hermes programming manual
50 : * without an NDA (if at all). What they do release is an API library
51 : * called the HCF (Hardware Control Functions) which is supposed to
52 : * do the device-specific operations of a device driver for you. The
53 : * publicly available version of the HCF library (the 'HCF Light') is
54 : * a) extremely gross, b) lacks certain features, particularly support
55 : * for 802.11 frames, and c) is contaminated by the GNU Public License.
56 : *
57 : * This driver does not use the HCF or HCF Light at all. Instead, it
58 : * programs the Hermes controller directly, using information gleaned
59 : * from the HCF Light code and corresponding documentation.
60 : */
61 :
62 : #define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */
63 : #define WI_HERMES_STATS_WAR /* Work around stats counter bug. */
64 :
65 : #include "bpfilter.h"
66 :
67 : #include <sys/param.h>
68 : #include <sys/systm.h>
69 : #include <sys/sockio.h>
70 : #include <sys/mbuf.h>
71 : #include <sys/malloc.h>
72 : #include <sys/kernel.h>
73 : #include <sys/socket.h>
74 : #include <sys/device.h>
75 :
76 : #include <net/if.h>
77 : #include <net/if_dl.h>
78 : #include <net/if_media.h>
79 :
80 : #include <netinet/in.h>
81 : #include <netinet/if_ether.h>
82 :
83 : #include <net80211/ieee80211_var.h>
84 : #include <net80211/ieee80211_ioctl.h>
85 :
86 : #if NBPFILTER > 0
87 : #include <net/bpf.h>
88 : #endif
89 :
90 : #include <machine/bus.h>
91 :
92 : #include <dev/ic/if_wireg.h>
93 : #include <dev/ic/if_wi_ieee.h>
94 : #include <dev/ic/if_wivar.h>
95 :
96 : #include <crypto/arc4.h>
97 :
98 : #define BPFATTACH(if_bpf,if,dlt,sz)
99 : #define STATIC
100 :
101 : #ifdef WIDEBUG
102 :
103 : u_int32_t widebug = WIDEBUG;
104 :
105 : #define WID_INTR 0x01
106 : #define WID_START 0x02
107 : #define WID_IOCTL 0x04
108 : #define WID_INIT 0x08
109 : #define WID_STOP 0x10
110 : #define WID_RESET 0x20
111 :
112 : #define DPRINTF(mask,args) if (widebug & (mask)) printf args;
113 :
114 : #else /* !WIDEBUG */
115 : #define DPRINTF(mask,args)
116 : #endif /* WIDEBUG */
117 :
118 : #ifdef foo
119 : static u_int8_t wi_mcast_addr[6] = { 0x01, 0x60, 0x1D, 0x00, 0x01, 0x00 };
120 : #endif
121 :
122 : STATIC void wi_reset(struct wi_softc *);
123 : STATIC int wi_ioctl(struct ifnet *, u_long, caddr_t);
124 : STATIC void wi_init_io(struct wi_softc *);
125 : STATIC void wi_start(struct ifnet *);
126 : STATIC void wi_watchdog(struct ifnet *);
127 : STATIC void wi_rxeof(struct wi_softc *);
128 : STATIC void wi_txeof(struct wi_softc *, int);
129 : STATIC void wi_update_stats(struct wi_softc *);
130 : STATIC void wi_setmulti(struct wi_softc *);
131 :
132 : STATIC int wi_cmd_io(struct wi_softc *, int, int, int, int);
133 : STATIC int wi_read_record_io(struct wi_softc *, struct wi_ltv_gen *);
134 : STATIC int wi_write_record_io(struct wi_softc *, struct wi_ltv_gen *);
135 : STATIC int wi_read_data_io(struct wi_softc *, int,
136 : int, caddr_t, int);
137 : STATIC int wi_write_data_io(struct wi_softc *, int,
138 : int, caddr_t, int);
139 : STATIC int wi_seek(struct wi_softc *, int, int, int);
140 :
141 : STATIC void wi_inquire(void *);
142 : STATIC int wi_setdef(struct wi_softc *, struct wi_req *);
143 : STATIC void wi_get_id(struct wi_softc *);
144 :
145 : STATIC int wi_media_change(struct ifnet *);
146 : STATIC void wi_media_status(struct ifnet *, struct ifmediareq *);
147 :
148 : STATIC int wi_set_ssid(struct ieee80211_nwid *, u_int8_t *, int);
149 : STATIC int wi_set_nwkey(struct wi_softc *, struct ieee80211_nwkey *);
150 : STATIC int wi_get_nwkey(struct wi_softc *, struct ieee80211_nwkey *);
151 : STATIC int wi_sync_media(struct wi_softc *, int, int);
152 : STATIC int wi_set_pm(struct wi_softc *, struct ieee80211_power *);
153 : STATIC int wi_get_pm(struct wi_softc *, struct ieee80211_power *);
154 : STATIC int wi_set_txpower(struct wi_softc *, struct ieee80211_txpower *);
155 : STATIC int wi_get_txpower(struct wi_softc *, struct ieee80211_txpower *);
156 :
157 : STATIC int wi_get_debug(struct wi_softc *, struct wi_req *);
158 : STATIC int wi_set_debug(struct wi_softc *, struct wi_req *);
159 :
160 : STATIC void wi_do_hostencrypt(struct wi_softc *, caddr_t, int);
161 : STATIC int wi_do_hostdecrypt(struct wi_softc *, caddr_t, int);
162 :
163 : STATIC int wi_alloc_nicmem_io(struct wi_softc *, int, int *);
164 : STATIC int wi_get_fid_io(struct wi_softc *sc, int fid);
165 : STATIC void wi_intr_enable(struct wi_softc *sc, int mode);
166 : STATIC void wi_intr_ack(struct wi_softc *sc, int mode);
167 : void wi_scan_timeout(void *);
168 :
169 : /* Autoconfig definition of driver back-end */
170 : struct cfdriver wi_cd = {
171 : NULL, "wi", DV_IFNET
172 : };
173 :
174 : const struct wi_card_ident wi_card_ident[] = {
175 : WI_CARD_IDS
176 : };
177 :
178 : struct wi_funcs wi_func_io = {
179 : wi_cmd_io,
180 : wi_read_record_io,
181 : wi_write_record_io,
182 : wi_alloc_nicmem_io,
183 : wi_read_data_io,
184 : wi_write_data_io,
185 : wi_get_fid_io,
186 : wi_init_io,
187 :
188 : wi_start,
189 : wi_ioctl,
190 : wi_watchdog,
191 : wi_inquire,
192 : };
193 :
194 : int
195 0 : wi_attach(struct wi_softc *sc, struct wi_funcs *funcs)
196 : {
197 : struct ieee80211com *ic;
198 : struct ifnet *ifp;
199 0 : struct wi_ltv_macaddr mac;
200 0 : struct wi_ltv_rates rates;
201 0 : struct wi_ltv_gen gen;
202 : int error;
203 :
204 0 : ic = &sc->sc_ic;
205 0 : ifp = &ic->ic_if;
206 :
207 0 : sc->sc_funcs = funcs;
208 0 : sc->wi_cmd_count = 500;
209 :
210 0 : wi_reset(sc);
211 :
212 : /* Read the station address. */
213 0 : mac.wi_type = WI_RID_MAC_NODE;
214 0 : mac.wi_len = 4;
215 0 : error = wi_read_record(sc, (struct wi_ltv_gen *)&mac);
216 0 : if (error) {
217 0 : printf(": unable to read station address\n");
218 0 : return (error);
219 : }
220 0 : bcopy(&mac.wi_mac_addr, &ic->ic_myaddr, IEEE80211_ADDR_LEN);
221 :
222 0 : wi_get_id(sc);
223 0 : printf("address %s", ether_sprintf(ic->ic_myaddr));
224 :
225 0 : bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
226 0 : ifp->if_softc = sc;
227 0 : ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
228 0 : ifp->if_ioctl = funcs->f_ioctl;
229 0 : ifp->if_start = funcs->f_start;
230 0 : ifp->if_watchdog = funcs->f_watchdog;
231 :
232 0 : (void)wi_set_ssid(&sc->wi_node_name, WI_DEFAULT_NODENAME,
233 : sizeof(WI_DEFAULT_NODENAME) - 1);
234 0 : (void)wi_set_ssid(&sc->wi_net_name, WI_DEFAULT_NETNAME,
235 : sizeof(WI_DEFAULT_NETNAME) - 1);
236 0 : (void)wi_set_ssid(&sc->wi_ibss_name, WI_DEFAULT_IBSS,
237 : sizeof(WI_DEFAULT_IBSS) - 1);
238 :
239 0 : sc->wi_portnum = WI_DEFAULT_PORT;
240 0 : sc->wi_ptype = WI_PORTTYPE_BSS;
241 0 : sc->wi_ap_density = WI_DEFAULT_AP_DENSITY;
242 0 : sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH;
243 0 : sc->wi_tx_rate = WI_DEFAULT_TX_RATE;
244 0 : sc->wi_max_data_len = WI_DEFAULT_DATALEN;
245 0 : sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
246 0 : sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
247 0 : sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
248 0 : sc->wi_roaming = WI_DEFAULT_ROAMING;
249 0 : sc->wi_authtype = WI_DEFAULT_AUTHTYPE;
250 0 : sc->wi_diversity = WI_DEFAULT_DIVERSITY;
251 0 : sc->wi_crypto_algorithm = WI_CRYPTO_FIRMWARE_WEP;
252 :
253 : /*
254 : * Read the default channel from the NIC. This may vary
255 : * depending on the country where the NIC was purchased, so
256 : * we can't hard-code a default and expect it to work for
257 : * everyone.
258 : */
259 0 : gen.wi_type = WI_RID_OWN_CHNL;
260 0 : gen.wi_len = 2;
261 0 : if (wi_read_record(sc, &gen) == 0)
262 0 : sc->wi_channel = letoh16(gen.wi_val);
263 : else
264 0 : sc->wi_channel = 3;
265 :
266 : /*
267 : * Set flags based on firmware version.
268 : */
269 0 : switch (sc->sc_firmware_type) {
270 : case WI_LUCENT:
271 0 : sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
272 0 : if (sc->sc_sta_firmware_ver >= 60000)
273 0 : sc->wi_flags |= WI_FLAGS_HAS_MOR;
274 0 : if (sc->sc_sta_firmware_ver >= 60006) {
275 0 : sc->wi_flags |= WI_FLAGS_HAS_IBSS;
276 0 : sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
277 0 : }
278 0 : sc->wi_ibss_port = htole16(1);
279 0 : break;
280 : case WI_INTERSIL:
281 0 : sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
282 : /* older prism firmware is slow so crank the count */
283 0 : if (sc->sc_sta_firmware_ver < 10000)
284 0 : sc->wi_cmd_count = 5000;
285 : else
286 0 : sc->wi_cmd_count = 2000;
287 0 : if (sc->sc_sta_firmware_ver >= 800) {
288 : #ifndef SMALL_KERNEL
289 : /*
290 : * USB hostap is more pain than it is worth
291 : * for now, things would have to be overhauled
292 : */
293 0 : if ((sc->sc_sta_firmware_ver != 10402) &&
294 0 : (!(sc->wi_flags & WI_FLAGS_BUS_USB)))
295 0 : sc->wi_flags |= WI_FLAGS_HAS_HOSTAP;
296 : #endif
297 0 : sc->wi_flags |= WI_FLAGS_HAS_IBSS;
298 0 : sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
299 0 : }
300 0 : if (sc->sc_sta_firmware_ver >= 10603)
301 0 : sc->wi_flags |= WI_FLAGS_HAS_ENH_SECURITY;
302 0 : sc->wi_ibss_port = htole16(0);
303 0 : break;
304 : case WI_SYMBOL:
305 0 : sc->wi_flags |= WI_FLAGS_HAS_DIVERSITY;
306 0 : if (sc->sc_sta_firmware_ver >= 20000)
307 0 : sc->wi_flags |= WI_FLAGS_HAS_IBSS;
308 0 : if (sc->sc_sta_firmware_ver >= 25000)
309 0 : sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
310 0 : sc->wi_ibss_port = htole16(4);
311 0 : break;
312 : }
313 :
314 : /*
315 : * Find out if we support WEP on this card.
316 : */
317 0 : gen.wi_type = WI_RID_WEP_AVAIL;
318 0 : gen.wi_len = 2;
319 0 : if (wi_read_record(sc, &gen) == 0 && gen.wi_val != htole16(0))
320 0 : sc->wi_flags |= WI_FLAGS_HAS_WEP;
321 0 : timeout_set(&sc->sc_timo, funcs->f_inquire, sc);
322 :
323 0 : bzero(&sc->wi_stats, sizeof(sc->wi_stats));
324 :
325 : /* Find supported rates. */
326 0 : rates.wi_type = WI_RID_DATA_RATES;
327 0 : rates.wi_len = sizeof(rates.wi_rates);
328 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)&rates) == 0) {
329 : int i, nrates;
330 :
331 0 : nrates = letoh16(*(u_int16_t *)rates.wi_rates);
332 0 : if (nrates > sizeof(rates.wi_rates) - 2)
333 : nrates = sizeof(rates.wi_rates) - 2;
334 :
335 0 : sc->wi_supprates = 0;
336 0 : for (i = 0; i < nrates; i++)
337 0 : sc->wi_supprates |= rates.wi_rates[2 + i];
338 0 : } else
339 0 : sc->wi_supprates = WI_SUPPRATES_1M | WI_SUPPRATES_2M |
340 : WI_SUPPRATES_5M | WI_SUPPRATES_11M;
341 :
342 0 : ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status);
343 : #define ADD(m, c) ifmedia_add(&sc->sc_media, (m), (c), NULL)
344 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
345 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0);
346 0 : if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
347 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_IBSS,
348 : 0), 0);
349 0 : if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
350 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
351 : IFM_IEEE80211_IBSSMASTER, 0), 0);
352 0 : if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
353 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
354 : IFM_IEEE80211_HOSTAP, 0), 0);
355 0 : if (sc->wi_supprates & WI_SUPPRATES_1M) {
356 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
357 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
358 : IFM_IEEE80211_ADHOC, 0), 0);
359 0 : if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
360 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
361 : IFM_IEEE80211_IBSS, 0), 0);
362 0 : if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
363 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
364 : IFM_IEEE80211_IBSSMASTER, 0), 0);
365 0 : if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
366 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
367 : IFM_IEEE80211_HOSTAP, 0), 0);
368 : }
369 0 : if (sc->wi_supprates & WI_SUPPRATES_2M) {
370 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
371 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
372 : IFM_IEEE80211_ADHOC, 0), 0);
373 0 : if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
374 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
375 : IFM_IEEE80211_IBSS, 0), 0);
376 0 : if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
377 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
378 : IFM_IEEE80211_IBSSMASTER, 0), 0);
379 0 : if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
380 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
381 : IFM_IEEE80211_HOSTAP, 0), 0);
382 : }
383 0 : if (sc->wi_supprates & WI_SUPPRATES_5M) {
384 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
385 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
386 : IFM_IEEE80211_ADHOC, 0), 0);
387 0 : if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
388 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
389 : IFM_IEEE80211_IBSS, 0), 0);
390 0 : if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
391 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
392 : IFM_IEEE80211_IBSSMASTER, 0), 0);
393 0 : if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
394 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
395 : IFM_IEEE80211_HOSTAP, 0), 0);
396 : }
397 0 : if (sc->wi_supprates & WI_SUPPRATES_11M) {
398 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
399 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
400 : IFM_IEEE80211_ADHOC, 0), 0);
401 0 : if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
402 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
403 : IFM_IEEE80211_IBSS, 0), 0);
404 0 : if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
405 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
406 : IFM_IEEE80211_IBSSMASTER, 0), 0);
407 0 : if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
408 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
409 : IFM_IEEE80211_HOSTAP, 0), 0);
410 0 : ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0);
411 0 : }
412 : #undef ADD
413 0 : ifmedia_set(&sc->sc_media,
414 : IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0));
415 :
416 : /*
417 : * Call MI attach routines.
418 : */
419 0 : if_attach(ifp);
420 0 : memcpy(((struct arpcom *)ifp)->ac_enaddr, ic->ic_myaddr,
421 : ETHER_ADDR_LEN);
422 0 : ether_ifattach(ifp);
423 0 : printf("\n");
424 :
425 0 : sc->wi_flags |= WI_FLAGS_ATTACHED;
426 :
427 : #if NBPFILTER > 0
428 : BPFATTACH(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
429 : #endif
430 :
431 0 : if_addgroup(ifp, "wlan");
432 0 : ifp->if_priority = IF_WIRELESS_DEFAULT_PRIORITY;
433 :
434 0 : wi_init(sc);
435 0 : wi_stop(sc);
436 :
437 0 : return (0);
438 0 : }
439 :
440 : STATIC void
441 0 : wi_intr_enable(struct wi_softc *sc, int mode)
442 : {
443 0 : if (!(sc->wi_flags & WI_FLAGS_BUS_USB))
444 0 : CSR_WRITE_2(sc, WI_INT_EN, mode);
445 0 : }
446 :
447 : STATIC void
448 0 : wi_intr_ack(struct wi_softc *sc, int mode)
449 : {
450 0 : if (!(sc->wi_flags & WI_FLAGS_BUS_USB))
451 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, mode);
452 0 : }
453 :
454 : int
455 0 : wi_intr(void *vsc)
456 : {
457 0 : struct wi_softc *sc = vsc;
458 : struct ifnet *ifp;
459 : u_int16_t status;
460 :
461 : DPRINTF(WID_INTR, ("wi_intr: sc %p\n", sc));
462 :
463 0 : ifp = &sc->sc_ic.ic_if;
464 :
465 0 : if (!(sc->wi_flags & WI_FLAGS_ATTACHED) || !(ifp->if_flags & IFF_UP)) {
466 0 : CSR_WRITE_2(sc, WI_INT_EN, 0);
467 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, 0xffff);
468 0 : return (0);
469 : }
470 :
471 : /* Disable interrupts. */
472 0 : CSR_WRITE_2(sc, WI_INT_EN, 0);
473 :
474 0 : status = CSR_READ_2(sc, WI_EVENT_STAT);
475 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS);
476 :
477 0 : if (status & WI_EV_RX) {
478 0 : wi_rxeof(sc);
479 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
480 0 : }
481 :
482 0 : if (status & WI_EV_TX) {
483 0 : wi_txeof(sc, status);
484 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
485 0 : }
486 :
487 0 : if (status & WI_EV_ALLOC) {
488 : int id;
489 0 : id = CSR_READ_2(sc, WI_ALLOC_FID);
490 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
491 0 : if (id == sc->wi_tx_data_id)
492 0 : wi_txeof(sc, status);
493 0 : }
494 :
495 0 : if (status & WI_EV_INFO) {
496 0 : wi_update_stats(sc);
497 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
498 0 : }
499 :
500 0 : if (status & WI_EV_TX_EXC) {
501 0 : wi_txeof(sc, status);
502 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
503 0 : }
504 :
505 0 : if (status & WI_EV_INFO_DROP) {
506 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP);
507 0 : }
508 :
509 : /* Re-enable interrupts. */
510 0 : CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
511 :
512 0 : if (status == 0)
513 0 : return (0);
514 :
515 0 : if (!IFQ_IS_EMPTY(&ifp->if_snd))
516 0 : wi_start(ifp);
517 :
518 0 : return (1);
519 0 : }
520 :
521 : STATIC int
522 0 : wi_get_fid_io(struct wi_softc *sc, int fid)
523 : {
524 0 : return CSR_READ_2(sc, fid);
525 : }
526 :
527 :
528 : void
529 0 : wi_rxeof(struct wi_softc *sc)
530 : {
531 : struct ifnet *ifp;
532 : struct ether_header *eh;
533 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
534 : struct mbuf *m;
535 : caddr_t olddata;
536 : u_int16_t ftype;
537 : int maxlen;
538 : int id;
539 :
540 0 : ifp = &sc->sc_ic.ic_if;
541 :
542 0 : id = wi_get_fid(sc, WI_RX_FID);
543 :
544 0 : if (sc->wi_procframe || sc->wi_debug.wi_monitor) {
545 : struct wi_frame *rx_frame;
546 : int datlen, hdrlen;
547 :
548 0 : MGETHDR(m, M_DONTWAIT, MT_DATA);
549 0 : if (m == NULL) {
550 0 : ifp->if_ierrors++;
551 0 : return;
552 : }
553 0 : MCLGET(m, M_DONTWAIT);
554 0 : if (!(m->m_flags & M_EXT)) {
555 0 : m_freem(m);
556 0 : ifp->if_ierrors++;
557 0 : return;
558 : }
559 :
560 0 : if (wi_read_data(sc, id, 0, mtod(m, caddr_t),
561 : sizeof(struct wi_frame))) {
562 0 : m_freem(m);
563 0 : ifp->if_ierrors++;
564 0 : return;
565 : }
566 :
567 0 : rx_frame = mtod(m, struct wi_frame *);
568 :
569 0 : if (rx_frame->wi_status & htole16(WI_STAT_BADCRC)) {
570 0 : m_freem(m);
571 0 : ifp->if_ierrors++;
572 0 : return;
573 : }
574 :
575 0 : switch ((letoh16(rx_frame->wi_status) & WI_STAT_MAC_PORT)
576 0 : >> 8) {
577 : case 7:
578 0 : switch (letoh16(rx_frame->wi_frame_ctl) &
579 : WI_FCTL_FTYPE) {
580 : case WI_FTYPE_DATA:
581 : hdrlen = WI_DATA_HDRLEN;
582 0 : datlen = letoh16(rx_frame->wi_dat_len);
583 0 : break;
584 : case WI_FTYPE_MGMT:
585 : hdrlen = WI_MGMT_HDRLEN;
586 0 : datlen = letoh16(rx_frame->wi_dat_len);
587 0 : break;
588 : case WI_FTYPE_CTL:
589 : hdrlen = WI_CTL_HDRLEN;
590 : datlen = 0;
591 0 : break;
592 : default:
593 0 : printf(WI_PRT_FMT ": received packet of "
594 0 : "unknown type on port 7\n", WI_PRT_ARG(sc));
595 0 : m_freem(m);
596 0 : ifp->if_ierrors++;
597 0 : return;
598 : }
599 : break;
600 : case 0:
601 : hdrlen = WI_DATA_HDRLEN;
602 0 : datlen = letoh16(rx_frame->wi_dat_len);
603 0 : break;
604 : default:
605 0 : printf(WI_PRT_FMT ": received packet on invalid port "
606 0 : "(wi_status=0x%x)\n", WI_PRT_ARG(sc),
607 : letoh16(rx_frame->wi_status));
608 0 : m_freem(m);
609 0 : ifp->if_ierrors++;
610 0 : return;
611 : }
612 :
613 0 : if ((hdrlen + datlen + 2) > MCLBYTES) {
614 0 : m_freem(m);
615 0 : ifp->if_ierrors++;
616 0 : return;
617 : }
618 :
619 0 : if (wi_read_data(sc, id, hdrlen, mtod(m, caddr_t) + hdrlen,
620 0 : datlen + 2)) {
621 0 : m_freem(m);
622 0 : ifp->if_ierrors++;
623 0 : return;
624 : }
625 :
626 0 : m->m_pkthdr.len = m->m_len = hdrlen + datlen;
627 0 : } else {
628 0 : struct wi_frame rx_frame;
629 :
630 : /* First read in the frame header */
631 0 : if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame,
632 : sizeof(rx_frame))) {
633 0 : ifp->if_ierrors++;
634 0 : return;
635 : }
636 :
637 : /* Drop undecryptable or packets with receive errors here */
638 0 : if (rx_frame.wi_status & htole16(WI_STAT_ERRSTAT)) {
639 0 : ifp->if_ierrors++;
640 0 : return;
641 : }
642 :
643 : /* Stash frame type in host byte order for later use */
644 0 : ftype = letoh16(rx_frame.wi_frame_ctl) & WI_FCTL_FTYPE;
645 :
646 0 : MGETHDR(m, M_DONTWAIT, MT_DATA);
647 0 : if (m == NULL) {
648 0 : ifp->if_ierrors++;
649 0 : return;
650 : }
651 0 : MCLGET(m, M_DONTWAIT);
652 0 : if (!(m->m_flags & M_EXT)) {
653 0 : m_freem(m);
654 0 : ifp->if_ierrors++;
655 0 : return;
656 : }
657 :
658 0 : olddata = m->m_data;
659 : /* Align the data after the ethernet header */
660 0 : m->m_data = (caddr_t)ALIGN(m->m_data +
661 0 : sizeof(struct ether_header)) - sizeof(struct ether_header);
662 :
663 0 : eh = mtod(m, struct ether_header *);
664 0 : maxlen = MCLBYTES - (m->m_data - olddata);
665 :
666 0 : if (ftype == WI_FTYPE_MGMT &&
667 0 : sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
668 :
669 0 : u_int16_t rxlen = letoh16(rx_frame.wi_dat_len);
670 :
671 0 : if ((WI_802_11_OFFSET_RAW + rxlen + 2) > maxlen) {
672 0 : printf("%s: oversized mgmt packet received in "
673 : "hostap mode (wi_dat_len=%d, "
674 0 : "wi_status=0x%x)\n", sc->sc_dev.dv_xname,
675 0 : rxlen, letoh16(rx_frame.wi_status));
676 0 : m_freem(m);
677 0 : ifp->if_ierrors++;
678 0 : return;
679 : }
680 :
681 : /* Put the whole header in there. */
682 0 : bcopy(&rx_frame, mtod(m, void *),
683 : sizeof(struct wi_frame));
684 0 : if (wi_read_data(sc, id, WI_802_11_OFFSET_RAW,
685 0 : mtod(m, caddr_t) + WI_802_11_OFFSET_RAW,
686 0 : rxlen + 2)) {
687 0 : m_freem(m);
688 0 : if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
689 0 : printf("wihap: failed to copy header\n");
690 0 : ifp->if_ierrors++;
691 0 : return;
692 : }
693 :
694 0 : m->m_pkthdr.len = m->m_len =
695 : WI_802_11_OFFSET_RAW + rxlen;
696 :
697 : /* XXX: consider giving packet to bhp? */
698 :
699 0 : wihap_mgmt_input(sc, &rx_frame, m);
700 :
701 0 : return;
702 : }
703 :
704 0 : switch (letoh16(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) {
705 : case WI_STAT_1042:
706 : case WI_STAT_TUNNEL:
707 : case WI_STAT_WMP_MSG:
708 0 : if ((letoh16(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN) >
709 : maxlen) {
710 0 : printf(WI_PRT_FMT ": oversized packet received "
711 : "(wi_dat_len=%d, wi_status=0x%x)\n",
712 0 : WI_PRT_ARG(sc),
713 : letoh16(rx_frame.wi_dat_len),
714 0 : letoh16(rx_frame.wi_status));
715 0 : m_freem(m);
716 0 : ifp->if_ierrors++;
717 0 : return;
718 : }
719 0 : m->m_pkthdr.len = m->m_len =
720 : letoh16(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN;
721 :
722 0 : bcopy(&rx_frame.wi_dst_addr,
723 0 : &eh->ether_dhost, ETHER_ADDR_LEN);
724 0 : bcopy(&rx_frame.wi_src_addr,
725 0 : &eh->ether_shost, ETHER_ADDR_LEN);
726 0 : bcopy(&rx_frame.wi_type,
727 0 : &eh->ether_type, ETHER_TYPE_LEN);
728 :
729 0 : if (wi_read_data(sc, id, WI_802_11_OFFSET,
730 0 : mtod(m, caddr_t) + sizeof(struct ether_header),
731 0 : m->m_len + 2)) {
732 0 : ifp->if_ierrors++;
733 0 : m_freem(m);
734 0 : return;
735 : }
736 : break;
737 : default:
738 0 : if ((letoh16(rx_frame.wi_dat_len) +
739 0 : sizeof(struct ether_header)) > maxlen) {
740 0 : printf(WI_PRT_FMT ": oversized packet received "
741 : "(wi_dat_len=%d, wi_status=0x%x)\n",
742 0 : WI_PRT_ARG(sc),
743 0 : letoh16(rx_frame.wi_dat_len),
744 : letoh16(rx_frame.wi_status));
745 0 : m_freem(m);
746 0 : ifp->if_ierrors++;
747 0 : return;
748 : }
749 0 : m->m_pkthdr.len = m->m_len =
750 0 : letoh16(rx_frame.wi_dat_len) +
751 : sizeof(struct ether_header);
752 :
753 0 : if (wi_read_data(sc, id, WI_802_3_OFFSET,
754 0 : mtod(m, caddr_t), m->m_len + 2)) {
755 0 : m_freem(m);
756 0 : ifp->if_ierrors++;
757 0 : return;
758 : }
759 : break;
760 : }
761 :
762 0 : if (sc->wi_use_wep &&
763 0 : rx_frame.wi_frame_ctl & htole16(WI_FCTL_WEP)) {
764 : int len;
765 :
766 0 : switch (sc->wi_crypto_algorithm) {
767 : case WI_CRYPTO_FIRMWARE_WEP:
768 : break;
769 : case WI_CRYPTO_SOFTWARE_WEP:
770 0 : m_copydata(m, 0, m->m_pkthdr.len,
771 0 : (caddr_t)sc->wi_rxbuf);
772 0 : len = m->m_pkthdr.len -
773 : sizeof(struct ether_header);
774 0 : if (wi_do_hostdecrypt(sc, sc->wi_rxbuf +
775 : sizeof(struct ether_header), len)) {
776 0 : if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
777 0 : printf(WI_PRT_FMT ": Error decrypting incoming packet.\n", WI_PRT_ARG(sc));
778 0 : m_freem(m);
779 0 : ifp->if_ierrors++;
780 0 : return;
781 : }
782 0 : len -= IEEE80211_WEP_IVLEN +
783 : IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
784 : /*
785 : * copy data back to mbufs:
786 : * we need to ditch the IV & most LLC/SNAP stuff
787 : * (except SNAP type, we're going use that to
788 : * overwrite the ethertype in the ether_header)
789 : */
790 0 : m_copyback(m, sizeof(struct ether_header) -
791 0 : WI_ETHERTYPE_LEN, WI_ETHERTYPE_LEN +
792 0 : (len - WI_SNAPHDR_LEN),
793 0 : sc->wi_rxbuf + sizeof(struct ether_header) +
794 0 : IEEE80211_WEP_IVLEN +
795 0 : IEEE80211_WEP_KIDLEN + WI_SNAPHDR_LEN,
796 : M_NOWAIT);
797 0 : m_adj(m, -(WI_ETHERTYPE_LEN +
798 : IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
799 : WI_SNAPHDR_LEN));
800 0 : break;
801 : }
802 0 : }
803 :
804 0 : if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
805 : /*
806 : * Give host AP code first crack at data packets.
807 : * If it decides to handle it (or drop it), it will
808 : * return a non-zero. Otherwise, it is destined for
809 : * this host.
810 : */
811 0 : if (wihap_data_input(sc, &rx_frame, m))
812 0 : return;
813 : }
814 0 : }
815 :
816 : /* Receive packet unless in procframe or monitor mode. */
817 0 : if (sc->wi_procframe || sc->wi_debug.wi_monitor)
818 0 : m_freem(m);
819 : else {
820 0 : ml_enqueue(&ml, m);
821 0 : if_input(ifp, &ml);
822 : }
823 :
824 0 : return;
825 0 : }
826 :
827 : void
828 0 : wi_txeof(struct wi_softc *sc, int status)
829 : {
830 : struct ifnet *ifp;
831 :
832 0 : ifp = &sc->sc_ic.ic_if;
833 :
834 0 : ifp->if_timer = 0;
835 0 : ifq_clr_oactive(&ifp->if_snd);
836 :
837 0 : if (status & WI_EV_TX_EXC)
838 0 : ifp->if_oerrors++;
839 :
840 : return;
841 0 : }
842 :
843 : void
844 0 : wi_inquire(void *xsc)
845 : {
846 : struct wi_softc *sc;
847 : struct ifnet *ifp;
848 : int s, rv;
849 :
850 0 : sc = xsc;
851 0 : ifp = &sc->sc_ic.ic_if;
852 :
853 0 : timeout_add_sec(&sc->sc_timo, 60);
854 :
855 : /* Don't do this while we're transmitting */
856 0 : if (ifq_is_oactive(&ifp->if_snd))
857 0 : return;
858 :
859 0 : s = splnet();
860 0 : rv = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0);
861 0 : splx(s);
862 0 : if (rv)
863 0 : printf(WI_PRT_FMT ": wi_cmd failed with %d\n", WI_PRT_ARG(sc),
864 : rv);
865 :
866 0 : return;
867 0 : }
868 :
869 : void
870 0 : wi_update_stats(struct wi_softc *sc)
871 : {
872 0 : struct wi_ltv_gen gen;
873 : u_int16_t id;
874 : struct ifnet *ifp;
875 : u_int32_t *ptr;
876 : int len, i;
877 0 : u_int16_t t;
878 :
879 0 : ifp = &sc->sc_ic.ic_if;
880 :
881 0 : id = wi_get_fid(sc, WI_INFO_FID);
882 :
883 0 : wi_read_data(sc, id, 0, (char *)&gen, 4);
884 :
885 0 : if (gen.wi_type == htole16(WI_INFO_SCAN_RESULTS)) {
886 0 : sc->wi_scanbuf_len = letoh16(gen.wi_len);
887 0 : wi_read_data(sc, id, 4, (caddr_t)sc->wi_scanbuf,
888 0 : sc->wi_scanbuf_len * 2);
889 0 : return;
890 0 : } else if (gen.wi_type != htole16(WI_INFO_COUNTERS))
891 0 : return;
892 :
893 : /* Some card versions have a larger stats structure */
894 0 : len = (letoh16(gen.wi_len) - 1 < sizeof(sc->wi_stats) / 4) ?
895 : letoh16(gen.wi_len) - 1 : sizeof(sc->wi_stats) / 4;
896 :
897 0 : ptr = (u_int32_t *)&sc->wi_stats;
898 :
899 0 : for (i = 0; i < len; i++) {
900 0 : if (sc->wi_flags & WI_FLAGS_BUS_USB) {
901 0 : wi_read_data(sc, id, 4 + i*2, (char *)&t, 2);
902 0 : t = letoh16(t);
903 0 : } else
904 0 : t = CSR_READ_2(sc, WI_DATA1);
905 : #ifdef WI_HERMES_STATS_WAR
906 0 : if (t > 0xF000)
907 0 : t = ~t & 0xFFFF;
908 : #endif
909 0 : ptr[i] += t;
910 : }
911 :
912 0 : ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
913 0 : sc->wi_stats.wi_tx_multi_retries +
914 0 : sc->wi_stats.wi_tx_retry_limit;
915 :
916 0 : return;
917 0 : }
918 :
919 : STATIC int
920 0 : wi_cmd_io(struct wi_softc *sc, int cmd, int val0, int val1, int val2)
921 : {
922 : int i, s = 0;
923 :
924 : /* Wait for the busy bit to clear. */
925 0 : for (i = sc->wi_cmd_count; i--; DELAY(1000)) {
926 0 : if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
927 : break;
928 : }
929 0 : if (i < 0) {
930 0 : if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
931 0 : printf(WI_PRT_FMT ": wi_cmd_io: busy bit won't clear\n",
932 0 : WI_PRT_ARG(sc));
933 0 : return(ETIMEDOUT);
934 : }
935 :
936 0 : CSR_WRITE_2(sc, WI_PARAM0, val0);
937 0 : CSR_WRITE_2(sc, WI_PARAM1, val1);
938 0 : CSR_WRITE_2(sc, WI_PARAM2, val2);
939 0 : CSR_WRITE_2(sc, WI_COMMAND, cmd);
940 :
941 0 : for (i = WI_TIMEOUT; i--; DELAY(WI_DELAY)) {
942 : /*
943 : * Wait for 'command complete' bit to be
944 : * set in the event status register.
945 : */
946 0 : s = CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD;
947 0 : if (s) {
948 : /* Ack the event and read result code. */
949 0 : s = CSR_READ_2(sc, WI_STATUS);
950 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
951 0 : if (s & WI_STAT_CMD_RESULT)
952 0 : return(EIO);
953 : break;
954 : }
955 : }
956 :
957 0 : if (i < 0) {
958 0 : if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
959 0 : printf(WI_PRT_FMT
960 : ": timeout in wi_cmd 0x%04x; event status 0x%04x\n",
961 0 : WI_PRT_ARG(sc), cmd, s);
962 0 : return(ETIMEDOUT);
963 : }
964 :
965 0 : return(0);
966 0 : }
967 :
968 : STATIC void
969 0 : wi_reset(struct wi_softc *sc)
970 : {
971 : int error, tries = 3;
972 :
973 : DPRINTF(WID_RESET, ("wi_reset: sc %p\n", sc));
974 :
975 : /* Symbol firmware cannot be initialized more than once. */
976 0 : if (sc->sc_firmware_type == WI_SYMBOL) {
977 0 : if (sc->wi_flags & WI_FLAGS_INITIALIZED)
978 0 : return;
979 : tries = 1;
980 0 : }
981 :
982 0 : for (; tries--; DELAY(WI_DELAY * 1000)) {
983 0 : if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0)
984 : break;
985 : }
986 0 : if (tries < 0) {
987 0 : printf(WI_PRT_FMT ": init failed\n", WI_PRT_ARG(sc));
988 0 : return;
989 : }
990 0 : sc->wi_flags |= WI_FLAGS_INITIALIZED;
991 :
992 0 : wi_intr_enable(sc, 0);
993 0 : wi_intr_ack(sc, 0xffff);
994 :
995 : /* Calibrate timer. */
996 0 : WI_SETVAL(WI_RID_TICK_TIME, 8);
997 :
998 0 : return;
999 0 : }
1000 :
1001 : STATIC void
1002 0 : wi_cor_reset(struct wi_softc *sc)
1003 : {
1004 : u_int8_t cor_value;
1005 :
1006 : DPRINTF(WID_RESET, ("wi_cor_reset: sc %p\n", sc));
1007 :
1008 : /*
1009 : * Do a soft reset of the card; this is required for Symbol cards.
1010 : * This shouldn't hurt other cards but there have been reports
1011 : * of the COR reset messing up old Lucent firmware revisions so
1012 : * we avoid soft reset on Lucent cards for now.
1013 : */
1014 0 : if (sc->sc_firmware_type != WI_LUCENT) {
1015 0 : cor_value = bus_space_read_1(sc->wi_ltag, sc->wi_lhandle,
1016 : sc->wi_cor_offset);
1017 0 : bus_space_write_1(sc->wi_ltag, sc->wi_lhandle,
1018 : sc->wi_cor_offset, (cor_value | WI_COR_SOFT_RESET));
1019 0 : DELAY(1000);
1020 0 : bus_space_write_1(sc->wi_ltag, sc->wi_lhandle,
1021 : sc->wi_cor_offset, (cor_value & ~WI_COR_SOFT_RESET));
1022 0 : DELAY(1000);
1023 0 : }
1024 :
1025 : return;
1026 0 : }
1027 :
1028 : /*
1029 : * Read an LTV record from the NIC.
1030 : */
1031 : STATIC int
1032 0 : wi_read_record_io(struct wi_softc *sc, struct wi_ltv_gen *ltv)
1033 : {
1034 : u_int8_t *ptr;
1035 : int len, code;
1036 0 : struct wi_ltv_gen *oltv, p2ltv;
1037 :
1038 0 : if (sc->sc_firmware_type != WI_LUCENT) {
1039 : oltv = ltv;
1040 0 : switch (ltv->wi_type) {
1041 : case WI_RID_ENCRYPTION:
1042 0 : p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
1043 0 : p2ltv.wi_len = 2;
1044 : ltv = &p2ltv;
1045 0 : break;
1046 : case WI_RID_TX_CRYPT_KEY:
1047 0 : if (ltv->wi_val > WI_NLTV_KEYS)
1048 0 : return (EINVAL);
1049 0 : p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
1050 0 : p2ltv.wi_len = 2;
1051 : ltv = &p2ltv;
1052 0 : break;
1053 : }
1054 : }
1055 :
1056 : /* Tell the NIC to enter record read mode. */
1057 0 : if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0))
1058 0 : return(EIO);
1059 :
1060 : /* Seek to the record. */
1061 0 : if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
1062 0 : return(EIO);
1063 :
1064 : /*
1065 : * Read the length and record type and make sure they
1066 : * match what we expect (this verifies that we have enough
1067 : * room to hold all of the returned data).
1068 : */
1069 0 : len = CSR_READ_2(sc, WI_DATA1);
1070 0 : if (len > ltv->wi_len)
1071 0 : return(ENOSPC);
1072 0 : code = CSR_READ_2(sc, WI_DATA1);
1073 0 : if (code != ltv->wi_type)
1074 0 : return(EIO);
1075 :
1076 0 : ltv->wi_len = len;
1077 0 : ltv->wi_type = code;
1078 :
1079 : /* Now read the data. */
1080 0 : ptr = (u_int8_t *)<v->wi_val;
1081 0 : if (ltv->wi_len > 1)
1082 0 : CSR_READ_RAW_2(sc, WI_DATA1, ptr, (ltv->wi_len-1)*2);
1083 :
1084 0 : if (ltv->wi_type == WI_RID_PORTTYPE && sc->wi_ptype == WI_PORTTYPE_IBSS
1085 0 : && ltv->wi_val == sc->wi_ibss_port) {
1086 : /*
1087 : * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
1088 : * Since Lucent uses port type 1 for BSS *and* IBSS we
1089 : * have to rely on wi_ptype to distinguish this for us.
1090 : */
1091 0 : ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
1092 0 : } else if (sc->sc_firmware_type != WI_LUCENT) {
1093 : int v;
1094 :
1095 0 : switch (oltv->wi_type) {
1096 : case WI_RID_TX_RATE:
1097 : case WI_RID_CUR_TX_RATE:
1098 0 : switch (letoh16(ltv->wi_val)) {
1099 0 : case 1: v = 1; break;
1100 0 : case 2: v = 2; break;
1101 0 : case 3: v = 6; break;
1102 0 : case 4: v = 5; break;
1103 0 : case 7: v = 7; break;
1104 0 : case 8: v = 11; break;
1105 0 : case 15: v = 3; break;
1106 0 : default: v = 0x100 + letoh16(ltv->wi_val); break;
1107 : }
1108 0 : oltv->wi_val = htole16(v);
1109 0 : break;
1110 : case WI_RID_ENCRYPTION:
1111 0 : oltv->wi_len = 2;
1112 0 : if (ltv->wi_val & htole16(0x01))
1113 0 : oltv->wi_val = htole16(1);
1114 : else
1115 0 : oltv->wi_val = htole16(0);
1116 : break;
1117 : case WI_RID_TX_CRYPT_KEY:
1118 : case WI_RID_CNFAUTHMODE:
1119 0 : oltv->wi_len = 2;
1120 0 : oltv->wi_val = ltv->wi_val;
1121 0 : break;
1122 : }
1123 0 : }
1124 :
1125 0 : return(0);
1126 0 : }
1127 :
1128 : /*
1129 : * Same as read, except we inject data instead of reading it.
1130 : */
1131 : STATIC int
1132 0 : wi_write_record_io(struct wi_softc *sc, struct wi_ltv_gen *ltv)
1133 : {
1134 : u_int8_t *ptr;
1135 : u_int16_t val = 0;
1136 : int i;
1137 0 : struct wi_ltv_gen p2ltv;
1138 :
1139 0 : if (ltv->wi_type == WI_RID_PORTTYPE &&
1140 0 : letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
1141 : /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
1142 0 : p2ltv.wi_type = WI_RID_PORTTYPE;
1143 0 : p2ltv.wi_len = 2;
1144 0 : p2ltv.wi_val = sc->wi_ibss_port;
1145 : ltv = &p2ltv;
1146 0 : } else if (sc->sc_firmware_type != WI_LUCENT) {
1147 : int v;
1148 :
1149 0 : switch (ltv->wi_type) {
1150 : case WI_RID_TX_RATE:
1151 0 : p2ltv.wi_type = WI_RID_TX_RATE;
1152 0 : p2ltv.wi_len = 2;
1153 0 : switch (letoh16(ltv->wi_val)) {
1154 0 : case 1: v = 1; break;
1155 0 : case 2: v = 2; break;
1156 0 : case 3: v = 15; break;
1157 0 : case 5: v = 4; break;
1158 0 : case 6: v = 3; break;
1159 0 : case 7: v = 7; break;
1160 0 : case 11: v = 8; break;
1161 0 : default: return EINVAL;
1162 : }
1163 0 : p2ltv.wi_val = htole16(v);
1164 : ltv = &p2ltv;
1165 0 : break;
1166 : case WI_RID_ENCRYPTION:
1167 0 : p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
1168 0 : p2ltv.wi_len = 2;
1169 0 : if (ltv->wi_val & htole16(0x01)) {
1170 : val = PRIVACY_INVOKED;
1171 : /*
1172 : * If using shared key WEP we must set the
1173 : * EXCLUDE_UNENCRYPTED bit. Symbol cards
1174 : * need this bit set even when not using
1175 : * shared key. We can't just test for
1176 : * IEEE80211_AUTH_SHARED since Symbol cards
1177 : * have 2 shared key modes.
1178 : */
1179 0 : if (sc->wi_authtype != IEEE80211_AUTH_OPEN ||
1180 0 : sc->sc_firmware_type == WI_SYMBOL)
1181 0 : val |= EXCLUDE_UNENCRYPTED;
1182 :
1183 0 : switch (sc->wi_crypto_algorithm) {
1184 : case WI_CRYPTO_FIRMWARE_WEP:
1185 : /*
1186 : * TX encryption is broken in
1187 : * Host AP mode.
1188 : */
1189 0 : if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
1190 0 : val |= HOST_ENCRYPT;
1191 : break;
1192 : case WI_CRYPTO_SOFTWARE_WEP:
1193 0 : val |= HOST_ENCRYPT|HOST_DECRYPT;
1194 0 : break;
1195 : }
1196 0 : p2ltv.wi_val = htole16(val);
1197 0 : } else
1198 0 : p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
1199 : ltv = &p2ltv;
1200 0 : break;
1201 : case WI_RID_TX_CRYPT_KEY:
1202 0 : if (ltv->wi_val > WI_NLTV_KEYS)
1203 0 : return (EINVAL);
1204 0 : p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
1205 0 : p2ltv.wi_len = 2;
1206 0 : p2ltv.wi_val = ltv->wi_val;
1207 : ltv = &p2ltv;
1208 0 : break;
1209 : case WI_RID_DEFLT_CRYPT_KEYS: {
1210 : int error;
1211 : int keylen;
1212 0 : struct wi_ltv_str ws;
1213 0 : struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv;
1214 :
1215 0 : keylen = wk->wi_keys[sc->wi_tx_key].wi_keylen;
1216 : keylen = letoh16(keylen);
1217 :
1218 0 : for (i = 0; i < 4; i++) {
1219 0 : bzero(&ws, sizeof(ws));
1220 0 : ws.wi_len = (keylen > 5) ? 8 : 4;
1221 0 : ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
1222 0 : bcopy(&wk->wi_keys[i].wi_keydat,
1223 0 : ws.wi_str, keylen);
1224 0 : error = wi_write_record(sc,
1225 0 : (struct wi_ltv_gen *)&ws);
1226 0 : if (error)
1227 0 : return (error);
1228 : }
1229 0 : }
1230 0 : return (0);
1231 : }
1232 0 : }
1233 :
1234 0 : if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
1235 0 : return(EIO);
1236 :
1237 0 : CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len);
1238 0 : CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type);
1239 :
1240 0 : ptr = (u_int8_t *)<v->wi_val;
1241 0 : if (ltv->wi_len > 1)
1242 0 : CSR_WRITE_RAW_2(sc, WI_DATA1, ptr, (ltv->wi_len-1) *2);
1243 :
1244 0 : if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0))
1245 0 : return(EIO);
1246 :
1247 0 : return(0);
1248 0 : }
1249 :
1250 : STATIC int
1251 0 : wi_seek(struct wi_softc *sc, int id, int off, int chan)
1252 : {
1253 : int i;
1254 : int selreg, offreg;
1255 :
1256 0 : switch (chan) {
1257 : case WI_BAP0:
1258 : selreg = WI_SEL0;
1259 : offreg = WI_OFF0;
1260 0 : break;
1261 : case WI_BAP1:
1262 : selreg = WI_SEL1;
1263 : offreg = WI_OFF1;
1264 0 : break;
1265 : default:
1266 0 : printf(WI_PRT_FMT ": invalid data path: %x\n", WI_PRT_ARG(sc),
1267 : chan);
1268 0 : return(EIO);
1269 : }
1270 :
1271 0 : CSR_WRITE_2(sc, selreg, id);
1272 0 : CSR_WRITE_2(sc, offreg, off);
1273 :
1274 0 : for (i = WI_TIMEOUT; i--; DELAY(1))
1275 0 : if (!(CSR_READ_2(sc, offreg) & (WI_OFF_BUSY|WI_OFF_ERR)))
1276 : break;
1277 :
1278 0 : if (i < 0)
1279 0 : return(ETIMEDOUT);
1280 :
1281 0 : return(0);
1282 0 : }
1283 :
1284 : STATIC int
1285 0 : wi_read_data_io(struct wi_softc *sc, int id, int off, caddr_t buf, int len)
1286 : {
1287 : u_int8_t *ptr;
1288 :
1289 0 : if (wi_seek(sc, id, off, WI_BAP1))
1290 0 : return(EIO);
1291 :
1292 : ptr = (u_int8_t *)buf;
1293 0 : CSR_READ_RAW_2(sc, WI_DATA1, ptr, len);
1294 :
1295 0 : return(0);
1296 0 : }
1297 :
1298 : /*
1299 : * According to the comments in the HCF Light code, there is a bug in
1300 : * the Hermes (or possibly in certain Hermes firmware revisions) where
1301 : * the chip's internal autoincrement counter gets thrown off during
1302 : * data writes: the autoincrement is missed, causing one data word to
1303 : * be overwritten and subsequent words to be written to the wrong memory
1304 : * locations. The end result is that we could end up transmitting bogus
1305 : * frames without realizing it. The workaround for this is to write a
1306 : * couple of extra guard words after the end of the transfer, then
1307 : * attempt to read then back. If we fail to locate the guard words where
1308 : * we expect them, we preform the transfer over again.
1309 : */
1310 : STATIC int
1311 0 : wi_write_data_io(struct wi_softc *sc, int id, int off, caddr_t buf, int len)
1312 : {
1313 0 : u_int8_t *ptr;
1314 :
1315 : #ifdef WI_HERMES_AUTOINC_WAR
1316 : again:
1317 : #endif
1318 :
1319 0 : if (wi_seek(sc, id, off, WI_BAP0))
1320 0 : return(EIO);
1321 :
1322 : ptr = (u_int8_t *)buf;
1323 0 : CSR_WRITE_RAW_2(sc, WI_DATA0, ptr, len);
1324 :
1325 : #ifdef WI_HERMES_AUTOINC_WAR
1326 0 : CSR_WRITE_2(sc, WI_DATA0, 0x1234);
1327 0 : CSR_WRITE_2(sc, WI_DATA0, 0x5678);
1328 :
1329 0 : if (wi_seek(sc, id, off + len, WI_BAP0))
1330 0 : return(EIO);
1331 :
1332 0 : if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
1333 0 : CSR_READ_2(sc, WI_DATA0) != 0x5678)
1334 0 : goto again;
1335 : #endif
1336 :
1337 0 : return(0);
1338 0 : }
1339 :
1340 : /*
1341 : * Allocate a region of memory inside the NIC and zero
1342 : * it out.
1343 : */
1344 : STATIC int
1345 0 : wi_alloc_nicmem_io(struct wi_softc *sc, int len, int *id)
1346 : {
1347 : int i;
1348 :
1349 0 : if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) {
1350 0 : printf(WI_PRT_FMT ": failed to allocate %d bytes on NIC\n",
1351 0 : WI_PRT_ARG(sc), len);
1352 0 : return(ENOMEM);
1353 : }
1354 :
1355 0 : for (i = WI_TIMEOUT; i--; DELAY(1)) {
1356 0 : if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
1357 : break;
1358 : }
1359 :
1360 0 : if (i < 0)
1361 0 : return(ETIMEDOUT);
1362 :
1363 0 : *id = CSR_READ_2(sc, WI_ALLOC_FID);
1364 0 : CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
1365 :
1366 0 : if (wi_seek(sc, *id, 0, WI_BAP0))
1367 0 : return(EIO);
1368 :
1369 0 : for (i = 0; i < len / 2; i++)
1370 0 : CSR_WRITE_2(sc, WI_DATA0, 0);
1371 :
1372 0 : return(0);
1373 0 : }
1374 :
1375 : STATIC void
1376 0 : wi_setmulti(struct wi_softc *sc)
1377 : {
1378 0 : struct arpcom *ac = &sc->sc_ic.ic_ac;
1379 : struct ifnet *ifp;
1380 : int i = 0;
1381 0 : struct wi_ltv_mcast mcast;
1382 : struct ether_multistep step;
1383 : struct ether_multi *enm;
1384 :
1385 0 : ifp = &sc->sc_ic.ic_if;
1386 :
1387 0 : bzero(&mcast, sizeof(mcast));
1388 :
1389 0 : mcast.wi_type = WI_RID_MCAST_LIST;
1390 0 : mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1;
1391 :
1392 0 : if (ac->ac_multirangecnt > 0)
1393 0 : ifp->if_flags |= IFF_ALLMULTI;
1394 :
1395 0 : if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
1396 0 : wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
1397 0 : return;
1398 : }
1399 :
1400 0 : ETHER_FIRST_MULTI(step, &sc->sc_ic.ic_ac, enm);
1401 0 : while (enm != NULL) {
1402 0 : if (i >= 16) {
1403 0 : bzero(&mcast, sizeof(mcast));
1404 0 : break;
1405 : }
1406 :
1407 0 : bcopy(enm->enm_addrlo, &mcast.wi_mcast[i], ETHER_ADDR_LEN);
1408 0 : i++;
1409 0 : ETHER_NEXT_MULTI(step, enm);
1410 : }
1411 :
1412 0 : mcast.wi_len = (i * 3) + 1;
1413 0 : wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
1414 :
1415 0 : return;
1416 0 : }
1417 :
1418 : STATIC int
1419 0 : wi_setdef(struct wi_softc *sc, struct wi_req *wreq)
1420 : {
1421 : struct ifnet *ifp;
1422 : int error = 0;
1423 :
1424 0 : ifp = &sc->sc_ic.ic_if;
1425 :
1426 0 : switch(wreq->wi_type) {
1427 : case WI_RID_MAC_NODE:
1428 0 : bcopy(&wreq->wi_val, LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
1429 0 : bcopy(&wreq->wi_val, &sc->sc_ic.ic_myaddr, ETHER_ADDR_LEN);
1430 0 : break;
1431 : case WI_RID_PORTTYPE:
1432 0 : error = wi_sync_media(sc, letoh16(wreq->wi_val[0]),
1433 0 : sc->wi_tx_rate);
1434 0 : break;
1435 : case WI_RID_TX_RATE:
1436 0 : error = wi_sync_media(sc, sc->wi_ptype,
1437 0 : letoh16(wreq->wi_val[0]));
1438 0 : break;
1439 : case WI_RID_MAX_DATALEN:
1440 0 : sc->wi_max_data_len = letoh16(wreq->wi_val[0]);
1441 0 : break;
1442 : case WI_RID_RTS_THRESH:
1443 0 : sc->wi_rts_thresh = letoh16(wreq->wi_val[0]);
1444 0 : break;
1445 : case WI_RID_SYSTEM_SCALE:
1446 0 : sc->wi_ap_density = letoh16(wreq->wi_val[0]);
1447 0 : break;
1448 : case WI_RID_CREATE_IBSS:
1449 0 : sc->wi_create_ibss = letoh16(wreq->wi_val[0]);
1450 0 : error = wi_sync_media(sc, sc->wi_ptype, sc->wi_tx_rate);
1451 0 : break;
1452 : case WI_RID_OWN_CHNL:
1453 0 : sc->wi_channel = letoh16(wreq->wi_val[0]);
1454 0 : break;
1455 : case WI_RID_NODENAME:
1456 0 : error = wi_set_ssid(&sc->wi_node_name,
1457 0 : (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
1458 0 : break;
1459 : case WI_RID_DESIRED_SSID:
1460 0 : error = wi_set_ssid(&sc->wi_net_name,
1461 0 : (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
1462 0 : break;
1463 : case WI_RID_OWN_SSID:
1464 0 : error = wi_set_ssid(&sc->wi_ibss_name,
1465 0 : (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
1466 0 : break;
1467 : case WI_RID_PM_ENABLED:
1468 0 : sc->wi_pm_enabled = letoh16(wreq->wi_val[0]);
1469 0 : break;
1470 : case WI_RID_MICROWAVE_OVEN:
1471 0 : sc->wi_mor_enabled = letoh16(wreq->wi_val[0]);
1472 0 : break;
1473 : case WI_RID_MAX_SLEEP:
1474 0 : sc->wi_max_sleep = letoh16(wreq->wi_val[0]);
1475 0 : break;
1476 : case WI_RID_CNFAUTHMODE:
1477 0 : sc->wi_authtype = letoh16(wreq->wi_val[0]);
1478 0 : break;
1479 : case WI_RID_ROAMING_MODE:
1480 0 : sc->wi_roaming = letoh16(wreq->wi_val[0]);
1481 0 : break;
1482 : case WI_RID_SYMBOL_DIVERSITY:
1483 0 : sc->wi_diversity = letoh16(wreq->wi_val[0]);
1484 0 : break;
1485 : case WI_RID_ENH_SECURITY:
1486 0 : sc->wi_enh_security = letoh16(wreq->wi_val[0]);
1487 0 : break;
1488 : case WI_RID_ENCRYPTION:
1489 0 : sc->wi_use_wep = letoh16(wreq->wi_val[0]);
1490 0 : break;
1491 : case WI_RID_TX_CRYPT_KEY:
1492 0 : sc->wi_tx_key = letoh16(wreq->wi_val[0]);
1493 0 : break;
1494 : case WI_RID_DEFLT_CRYPT_KEYS:
1495 0 : bcopy(wreq, &sc->wi_keys, sizeof(struct wi_ltv_keys));
1496 0 : break;
1497 : case WI_FRID_CRYPTO_ALG:
1498 0 : switch (letoh16(wreq->wi_val[0])) {
1499 : case WI_CRYPTO_FIRMWARE_WEP:
1500 0 : sc->wi_crypto_algorithm = WI_CRYPTO_FIRMWARE_WEP;
1501 0 : break;
1502 : case WI_CRYPTO_SOFTWARE_WEP:
1503 0 : sc->wi_crypto_algorithm = WI_CRYPTO_SOFTWARE_WEP;
1504 0 : break;
1505 : default:
1506 0 : printf(WI_PRT_FMT ": unsupported crypto algorithm %d\n",
1507 0 : WI_PRT_ARG(sc), letoh16(wreq->wi_val[0]));
1508 : error = EINVAL;
1509 0 : }
1510 : break;
1511 : default:
1512 : error = EINVAL;
1513 0 : break;
1514 : }
1515 :
1516 0 : return (error);
1517 : }
1518 :
1519 : STATIC int
1520 0 : wi_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1521 : {
1522 : int s, error = 0, i, j, len;
1523 0 : struct wi_softc *sc = ifp->if_softc;
1524 0 : struct ifreq *ifr = (struct ifreq *)data;
1525 0 : struct proc *p = curproc;
1526 : struct wi_scan_res *res;
1527 : struct wi_scan_p2_hdr *p2;
1528 : struct wi_req *wreq = NULL;
1529 : u_int32_t flags;
1530 : struct ieee80211_nwid *nwidp = NULL;
1531 : struct ieee80211_nodereq_all *na;
1532 : struct ieee80211_bssid *bssid;
1533 :
1534 0 : s = splnet();
1535 0 : if (!(sc->wi_flags & WI_FLAGS_ATTACHED)) {
1536 : error = ENODEV;
1537 0 : goto fail;
1538 : }
1539 :
1540 : /*
1541 : * Prevent processes from entering this function while another
1542 : * process is tsleep'ing in it.
1543 : */
1544 0 : while ((sc->wi_flags & WI_FLAGS_BUSY) && error == 0)
1545 0 : error = tsleep(&sc->wi_flags, PCATCH, "wiioc", 0);
1546 0 : if (error != 0) {
1547 0 : splx(s);
1548 0 : return error;
1549 : }
1550 0 : sc->wi_flags |= WI_FLAGS_BUSY;
1551 :
1552 :
1553 : DPRINTF (WID_IOCTL, ("wi_ioctl: command %lu data %p\n",
1554 : command, data));
1555 :
1556 0 : switch(command) {
1557 : case SIOCSIFADDR:
1558 0 : ifp->if_flags |= IFF_UP;
1559 0 : wi_init(sc);
1560 0 : break;
1561 : case SIOCSIFFLAGS:
1562 0 : if (ifp->if_flags & IFF_UP) {
1563 0 : if (ifp->if_flags & IFF_RUNNING &&
1564 0 : ifp->if_flags & IFF_PROMISC &&
1565 0 : !(sc->wi_if_flags & IFF_PROMISC)) {
1566 0 : if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
1567 0 : WI_SETVAL(WI_RID_PROMISC, 1);
1568 0 : } else if (ifp->if_flags & IFF_RUNNING &&
1569 0 : !(ifp->if_flags & IFF_PROMISC) &&
1570 0 : sc->wi_if_flags & IFF_PROMISC) {
1571 0 : if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
1572 0 : WI_SETVAL(WI_RID_PROMISC, 0);
1573 : } else
1574 0 : wi_init(sc);
1575 0 : } else if (ifp->if_flags & IFF_RUNNING)
1576 0 : wi_stop(sc);
1577 0 : sc->wi_if_flags = ifp->if_flags;
1578 : error = 0;
1579 0 : break;
1580 : case SIOCSIFMEDIA:
1581 : case SIOCGIFMEDIA:
1582 0 : error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
1583 0 : break;
1584 : case SIOCGWAVELAN:
1585 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
1586 0 : error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
1587 0 : if (error)
1588 : break;
1589 0 : if (wreq->wi_len > WI_MAX_DATALEN) {
1590 : error = EINVAL;
1591 0 : break;
1592 : }
1593 0 : switch (wreq->wi_type) {
1594 : case WI_RID_IFACE_STATS:
1595 : /* XXX native byte order */
1596 0 : bcopy(&sc->wi_stats, &wreq->wi_val,
1597 : sizeof(sc->wi_stats));
1598 0 : wreq->wi_len = (sizeof(sc->wi_stats) / 2) + 1;
1599 0 : break;
1600 : case WI_RID_DEFLT_CRYPT_KEYS:
1601 : /* For non-root user, return all-zeroes keys */
1602 0 : if (suser(p))
1603 0 : bzero(wreq, sizeof(struct wi_ltv_keys));
1604 : else
1605 0 : bcopy(&sc->wi_keys, wreq,
1606 : sizeof(struct wi_ltv_keys));
1607 : break;
1608 : case WI_RID_PROCFRAME:
1609 0 : wreq->wi_len = 2;
1610 0 : wreq->wi_val[0] = htole16(sc->wi_procframe);
1611 0 : break;
1612 : case WI_RID_PRISM2:
1613 0 : wreq->wi_len = 2;
1614 0 : wreq->wi_val[0] = htole16(sc->sc_firmware_type ==
1615 : WI_LUCENT ? 0 : 1);
1616 0 : break;
1617 : case WI_FRID_CRYPTO_ALG:
1618 0 : wreq->wi_val[0] =
1619 0 : htole16((u_int16_t)sc->wi_crypto_algorithm);
1620 0 : wreq->wi_len = 1;
1621 0 : break;
1622 : case WI_RID_SCAN_RES:
1623 0 : if (sc->sc_firmware_type == WI_LUCENT) {
1624 0 : memcpy((char *)wreq->wi_val,
1625 : (char *)sc->wi_scanbuf,
1626 : sc->wi_scanbuf_len * 2);
1627 0 : wreq->wi_len = sc->wi_scanbuf_len;
1628 0 : break;
1629 : }
1630 : /* FALLTHROUGH */
1631 : default:
1632 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
1633 : error = EINVAL;
1634 0 : }
1635 : break;
1636 : }
1637 0 : error = copyout(wreq, ifr->ifr_data, sizeof(*wreq));
1638 0 : break;
1639 : case SIOCSWAVELAN:
1640 0 : if ((error = suser(curproc)) != 0)
1641 : break;
1642 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
1643 0 : error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
1644 0 : if (error)
1645 : break;
1646 : error = EINVAL;
1647 0 : if (wreq->wi_len > WI_MAX_DATALEN)
1648 : break;
1649 0 : switch (wreq->wi_type) {
1650 : case WI_RID_IFACE_STATS:
1651 : break;
1652 : case WI_RID_MGMT_XMIT:
1653 0 : error = wi_mgmt_xmit(sc, (caddr_t)&wreq->wi_val,
1654 : wreq->wi_len);
1655 0 : break;
1656 : case WI_RID_PROCFRAME:
1657 0 : sc->wi_procframe = letoh16(wreq->wi_val[0]);
1658 : error = 0;
1659 0 : break;
1660 : case WI_RID_SCAN_REQ:
1661 : error = 0;
1662 0 : if (sc->sc_firmware_type == WI_LUCENT)
1663 0 : wi_cmd(sc, WI_CMD_INQUIRE,
1664 : WI_INFO_SCAN_RESULTS, 0, 0);
1665 : else
1666 0 : error = wi_write_record(sc,
1667 0 : (struct wi_ltv_gen *)wreq);
1668 : break;
1669 : case WI_FRID_CRYPTO_ALG:
1670 0 : if (sc->sc_firmware_type != WI_LUCENT) {
1671 0 : error = wi_setdef(sc, wreq);
1672 0 : if (!error && (ifp->if_flags & IFF_UP))
1673 0 : wi_init(sc);
1674 : }
1675 : break;
1676 : case WI_RID_SYMBOL_DIVERSITY:
1677 : case WI_RID_ROAMING_MODE:
1678 : case WI_RID_CREATE_IBSS:
1679 : case WI_RID_MICROWAVE_OVEN:
1680 : case WI_RID_OWN_SSID:
1681 : case WI_RID_ENH_SECURITY:
1682 : /*
1683 : * Check for features that may not be supported
1684 : * (must be just before default case).
1685 : */
1686 0 : if ((wreq->wi_type == WI_RID_SYMBOL_DIVERSITY &&
1687 0 : !(sc->wi_flags & WI_FLAGS_HAS_DIVERSITY)) ||
1688 0 : (wreq->wi_type == WI_RID_ROAMING_MODE &&
1689 0 : !(sc->wi_flags & WI_FLAGS_HAS_ROAMING)) ||
1690 0 : (wreq->wi_type == WI_RID_CREATE_IBSS &&
1691 0 : !(sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)) ||
1692 0 : (wreq->wi_type == WI_RID_MICROWAVE_OVEN &&
1693 0 : !(sc->wi_flags & WI_FLAGS_HAS_MOR)) ||
1694 0 : (wreq->wi_type == WI_RID_ENH_SECURITY &&
1695 0 : !(sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY)) ||
1696 0 : (wreq->wi_type == WI_RID_OWN_SSID &&
1697 0 : wreq->wi_len != 0))
1698 : break;
1699 : /* FALLTHROUGH */
1700 : default:
1701 0 : error = wi_write_record(sc, (struct wi_ltv_gen *)wreq);
1702 0 : if (!error)
1703 0 : error = wi_setdef(sc, wreq);
1704 0 : if (!error && (ifp->if_flags & IFF_UP))
1705 0 : wi_init(sc);
1706 : }
1707 : break;
1708 : case SIOCGPRISM2DEBUG:
1709 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
1710 0 : error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
1711 0 : if (error)
1712 : break;
1713 0 : if (!(ifp->if_flags & IFF_RUNNING) ||
1714 0 : sc->sc_firmware_type == WI_LUCENT) {
1715 : error = EIO;
1716 0 : break;
1717 : }
1718 0 : error = wi_get_debug(sc, wreq);
1719 0 : if (error == 0)
1720 0 : error = copyout(wreq, ifr->ifr_data, sizeof(*wreq));
1721 : break;
1722 : case SIOCSPRISM2DEBUG:
1723 0 : if ((error = suser(curproc)) != 0)
1724 : break;
1725 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
1726 0 : error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
1727 0 : if (error)
1728 : break;
1729 0 : error = wi_set_debug(sc, wreq);
1730 0 : break;
1731 : case SIOCG80211NWID:
1732 0 : if ((ifp->if_flags & IFF_UP) && sc->wi_net_name.i_len > 0) {
1733 : /* Return the desired ID */
1734 0 : error = copyout(&sc->wi_net_name, ifr->ifr_data,
1735 : sizeof(sc->wi_net_name));
1736 0 : } else {
1737 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK|M_ZERO);
1738 0 : wreq->wi_type = WI_RID_CURRENT_SSID;
1739 0 : wreq->wi_len = WI_MAX_DATALEN;
1740 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)wreq) ||
1741 0 : letoh16(wreq->wi_val[0]) > IEEE80211_NWID_LEN)
1742 0 : error = EINVAL;
1743 : else {
1744 0 : nwidp = malloc(sizeof *nwidp, M_DEVBUF,
1745 : M_WAITOK | M_ZERO);
1746 0 : wi_set_ssid(nwidp, (u_int8_t *)&wreq->wi_val[1],
1747 0 : letoh16(wreq->wi_val[0]));
1748 0 : error = copyout(nwidp, ifr->ifr_data,
1749 : sizeof(*nwidp));
1750 : }
1751 : }
1752 : break;
1753 : case SIOCS80211NWID:
1754 0 : if ((error = suser(curproc)) != 0)
1755 : break;
1756 0 : nwidp = malloc(sizeof *nwidp, M_DEVBUF, M_WAITOK);
1757 0 : error = copyin(ifr->ifr_data, nwidp, sizeof(*nwidp));
1758 0 : if (error)
1759 : break;
1760 0 : if (nwidp->i_len > IEEE80211_NWID_LEN) {
1761 : error = EINVAL;
1762 0 : break;
1763 : }
1764 0 : if (sc->wi_net_name.i_len == nwidp->i_len &&
1765 0 : memcmp(sc->wi_net_name.i_nwid, nwidp->i_nwid, nwidp->i_len) == 0)
1766 : break;
1767 0 : wi_set_ssid(&sc->wi_net_name, nwidp->i_nwid, nwidp->i_len);
1768 0 : WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name);
1769 0 : if (ifp->if_flags & IFF_UP)
1770 : /* Reinitialize WaveLAN. */
1771 0 : wi_init(sc);
1772 : break;
1773 : case SIOCS80211NWKEY:
1774 0 : if ((error = suser(curproc)) != 0)
1775 : break;
1776 0 : error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
1777 0 : break;
1778 : case SIOCG80211NWKEY:
1779 0 : error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
1780 0 : break;
1781 : case SIOCS80211POWER:
1782 0 : if ((error = suser(curproc)) != 0)
1783 : break;
1784 0 : error = wi_set_pm(sc, (struct ieee80211_power *)data);
1785 0 : break;
1786 : case SIOCG80211POWER:
1787 0 : error = wi_get_pm(sc, (struct ieee80211_power *)data);
1788 0 : break;
1789 : case SIOCS80211TXPOWER:
1790 0 : if ((error = suser(curproc)) != 0)
1791 : break;
1792 0 : error = wi_set_txpower(sc, (struct ieee80211_txpower *)data);
1793 0 : break;
1794 : case SIOCG80211TXPOWER:
1795 0 : error = wi_get_txpower(sc, (struct ieee80211_txpower *)data);
1796 0 : break;
1797 : case SIOCS80211CHANNEL:
1798 0 : if ((error = suser(curproc)) != 0)
1799 : break;
1800 0 : if (((struct ieee80211chanreq *)data)->i_channel > 14) {
1801 : error = EINVAL;
1802 0 : break;
1803 : }
1804 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
1805 0 : wreq->wi_type = WI_RID_OWN_CHNL;
1806 0 : wreq->wi_val[0] =
1807 0 : htole16(((struct ieee80211chanreq *)data)->i_channel);
1808 0 : error = wi_setdef(sc, wreq);
1809 0 : if (!error && (ifp->if_flags & IFF_UP))
1810 0 : wi_init(sc);
1811 : break;
1812 : case SIOCG80211CHANNEL:
1813 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
1814 0 : wreq->wi_type = WI_RID_CURRENT_CHAN;
1815 0 : wreq->wi_len = WI_MAX_DATALEN;
1816 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
1817 : error = EINVAL;
1818 0 : break;
1819 : }
1820 0 : ((struct ieee80211chanreq *)data)->i_channel =
1821 0 : letoh16(wreq->wi_val[0]);
1822 0 : break;
1823 : case SIOCG80211BSSID:
1824 0 : bssid = (struct ieee80211_bssid *)data;
1825 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
1826 0 : wreq->wi_type = WI_RID_CURRENT_BSSID;
1827 0 : wreq->wi_len = WI_MAX_DATALEN;
1828 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
1829 : error = EINVAL;
1830 0 : break;
1831 : }
1832 0 : IEEE80211_ADDR_COPY(bssid->i_bssid, wreq->wi_val);
1833 0 : break;
1834 : case SIOCS80211SCAN:
1835 0 : if ((error = suser(curproc)) != 0)
1836 : break;
1837 0 : if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
1838 : break;
1839 0 : if ((ifp->if_flags & IFF_UP) == 0) {
1840 : error = ENETDOWN;
1841 0 : break;
1842 : }
1843 0 : if (sc->sc_firmware_type == WI_LUCENT) {
1844 0 : wi_cmd(sc, WI_CMD_INQUIRE,
1845 : WI_INFO_SCAN_RESULTS, 0, 0);
1846 0 : } else {
1847 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK|M_ZERO);
1848 0 : wreq->wi_len = 3;
1849 0 : wreq->wi_type = WI_RID_SCAN_REQ;
1850 0 : wreq->wi_val[0] = 0x3FFF;
1851 0 : wreq->wi_val[1] = 0x000F;
1852 :
1853 0 : error = wi_write_record(sc,
1854 0 : (struct wi_ltv_gen *)wreq);
1855 0 : if (error)
1856 : break;
1857 : }
1858 0 : sc->wi_scan_lock = 0;
1859 0 : timeout_set(&sc->wi_scan_timeout, wi_scan_timeout, sc);
1860 0 : len = WI_WAVELAN_RES_TIMEOUT;
1861 0 : if (sc->wi_flags & WI_FLAGS_BUS_USB) {
1862 : /* Use a longer timeout for wi@usb */
1863 0 : len = WI_WAVELAN_RES_TIMEOUT * 4;
1864 0 : }
1865 0 : timeout_add(&sc->wi_scan_timeout, len);
1866 :
1867 : /* Let the userspace process wait for completion */
1868 0 : error = tsleep(&sc->wi_scan_lock, PCATCH, "wiscan",
1869 0 : hz * IEEE80211_SCAN_TIMEOUT);
1870 0 : break;
1871 : case SIOCG80211ALLNODES:
1872 : {
1873 : struct ieee80211_nodereq *nr = NULL;
1874 :
1875 0 : if ((error = suser(curproc)) != 0)
1876 0 : break;
1877 0 : na = (struct ieee80211_nodereq_all *)data;
1878 0 : if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
1879 : /* List all associated stations */
1880 0 : error = wihap_ioctl(sc, command, data);
1881 0 : break;
1882 : }
1883 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
1884 0 : wreq->wi_len = WI_MAX_DATALEN;
1885 0 : wreq->wi_type = WI_RID_SCAN_RES;
1886 0 : if (sc->sc_firmware_type == WI_LUCENT) {
1887 0 : bcopy(sc->wi_scanbuf, wreq->wi_val,
1888 0 : sc->wi_scanbuf_len * 2);
1889 0 : wreq->wi_len = sc->wi_scanbuf_len;
1890 : i = 0;
1891 : len = WI_WAVELAN_RES_SIZE;
1892 0 : } else {
1893 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
1894 : error = EINVAL;
1895 0 : break;
1896 : }
1897 0 : p2 = (struct wi_scan_p2_hdr *)wreq->wi_val;
1898 0 : if (p2->wi_reason == 0)
1899 0 : break;
1900 : i = sizeof(*p2);
1901 : len = WI_PRISM2_RES_SIZE;
1902 : }
1903 :
1904 0 : for (na->na_nodes = j = 0; (i < (wreq->wi_len * 2) - len) &&
1905 0 : (na->na_size >= j + sizeof(struct ieee80211_nodereq));
1906 0 : i += len) {
1907 :
1908 0 : if (nr == NULL)
1909 0 : nr = malloc(sizeof *nr, M_DEVBUF, M_WAITOK);
1910 0 : res = (struct wi_scan_res *)((char *)wreq->wi_val + i);
1911 0 : if (res == NULL)
1912 : break;
1913 :
1914 0 : bzero(nr, sizeof(*nr));
1915 0 : IEEE80211_ADDR_COPY(nr->nr_macaddr, res->wi_bssid);
1916 0 : IEEE80211_ADDR_COPY(nr->nr_bssid, res->wi_bssid);
1917 0 : nr->nr_channel = letoh16(res->wi_chan);
1918 0 : nr->nr_chan_flags = IEEE80211_CHAN_B;
1919 0 : nr->nr_rssi = letoh16(res->wi_signal);
1920 0 : nr->nr_max_rssi = 0; /* XXX */
1921 0 : nr->nr_nwid_len = letoh16(res->wi_ssid_len);
1922 0 : bcopy(res->wi_ssid, nr->nr_nwid, nr->nr_nwid_len);
1923 0 : nr->nr_intval = letoh16(res->wi_interval);
1924 0 : nr->nr_capinfo = letoh16(res->wi_capinfo);
1925 0 : nr->nr_txrate = res->wi_rate == WI_WAVELAN_RES_1M ? 2 :
1926 0 : (res->wi_rate == WI_WAVELAN_RES_2M ? 4 :
1927 0 : (res->wi_rate == WI_WAVELAN_RES_5M ? 11 :
1928 0 : (res->wi_rate == WI_WAVELAN_RES_11M ? 22 : 0)));
1929 0 : nr->nr_nrates = 0;
1930 0 : while (res->wi_srates[nr->nr_nrates] != 0) {
1931 0 : nr->nr_rates[nr->nr_nrates] =
1932 0 : res->wi_srates[nr->nr_nrates] &
1933 : WI_VAR_SRATES_MASK;
1934 0 : nr->nr_nrates++;
1935 : }
1936 0 : nr->nr_flags = 0;
1937 0 : if (bcmp(nr->nr_macaddr, nr->nr_bssid,
1938 0 : IEEE80211_ADDR_LEN) == 0)
1939 0 : nr->nr_flags |= IEEE80211_NODEREQ_AP;
1940 :
1941 0 : error = copyout(nr, (caddr_t)na->na_node + j,
1942 : sizeof(struct ieee80211_nodereq));
1943 0 : if (error)
1944 : break;
1945 0 : j += sizeof(struct ieee80211_nodereq);
1946 0 : na->na_nodes++;
1947 : }
1948 0 : if (nr)
1949 0 : free(nr, M_DEVBUF, 0);
1950 0 : break;
1951 : }
1952 : case SIOCG80211FLAGS:
1953 0 : if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
1954 : break;
1955 0 : ifr->ifr_flags = 0;
1956 0 : if (sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY) {
1957 0 : wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK|M_ZERO);
1958 0 : wreq->wi_len = WI_MAX_DATALEN;
1959 0 : wreq->wi_type = WI_RID_ENH_SECURITY;
1960 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
1961 : error = EINVAL;
1962 0 : break;
1963 : }
1964 0 : sc->wi_enh_security = letoh16(wreq->wi_val[0]);
1965 0 : if (sc->wi_enh_security == WI_HIDESSID_IGNPROBES)
1966 0 : ifr->ifr_flags |= IEEE80211_F_HIDENWID >>
1967 : IEEE80211_F_USERSHIFT;
1968 : }
1969 : break;
1970 : case SIOCS80211FLAGS:
1971 0 : if ((error = suser(curproc)) != 0)
1972 : break;
1973 0 : if (sc->wi_ptype != WI_PORTTYPE_HOSTAP) {
1974 : error = EINVAL;
1975 0 : break;
1976 : }
1977 0 : flags = (u_int32_t)ifr->ifr_flags << IEEE80211_F_USERSHIFT;
1978 0 : if (sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY) {
1979 0 : sc->wi_enh_security = (flags & IEEE80211_F_HIDENWID) ?
1980 : WI_HIDESSID_IGNPROBES : 0;
1981 0 : WI_SETVAL(WI_RID_ENH_SECURITY, sc->wi_enh_security);
1982 0 : }
1983 : break;
1984 : case SIOCHOSTAP_ADD:
1985 : case SIOCHOSTAP_DEL:
1986 : case SIOCHOSTAP_GET:
1987 : case SIOCHOSTAP_GETALL:
1988 : case SIOCHOSTAP_GFLAGS:
1989 : case SIOCHOSTAP_SFLAGS:
1990 : /* Send all Host AP specific ioctl's to Host AP code. */
1991 0 : error = wihap_ioctl(sc, command, data);
1992 0 : break;
1993 : default:
1994 0 : error = ether_ioctl(ifp, &sc->sc_ic.ic_ac, command, data);
1995 0 : }
1996 :
1997 0 : if (error == ENETRESET) {
1998 0 : if (ifp->if_flags & IFF_RUNNING)
1999 0 : wi_setmulti(sc);
2000 : error = 0;
2001 0 : }
2002 :
2003 0 : if (wreq)
2004 0 : free(wreq, M_DEVBUF, 0);
2005 0 : if (nwidp)
2006 0 : free(nwidp, M_DEVBUF, 0);
2007 :
2008 : fail:
2009 0 : sc->wi_flags &= ~WI_FLAGS_BUSY;
2010 0 : wakeup(&sc->wi_flags);
2011 0 : splx(s);
2012 0 : return(error);
2013 0 : }
2014 :
2015 : void
2016 0 : wi_scan_timeout(void *arg)
2017 : {
2018 0 : struct wi_softc *sc = (struct wi_softc *)arg;
2019 0 : struct wi_req wreq;
2020 :
2021 0 : if (sc->wi_scan_lock++ < WI_WAVELAN_RES_TRIES &&
2022 0 : sc->sc_firmware_type != WI_LUCENT &&
2023 0 : (sc->wi_flags & WI_FLAGS_BUS_USB) == 0) {
2024 : /*
2025 : * The Prism2/2.5/3 chipsets will set an extra field in the
2026 : * scan result if the scan request has been completed by the
2027 : * firmware. This allows to poll for completion and to
2028 : * wait for some more time if the scan is still in progress.
2029 : *
2030 : * XXX This doesn't work with wi@usb because it isn't safe
2031 : * to call wi_read_record_usb() while beeing in the timeout
2032 : * handler.
2033 : */
2034 0 : wreq.wi_len = WI_MAX_DATALEN;
2035 0 : wreq.wi_type = WI_RID_SCAN_RES;
2036 :
2037 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
2038 0 : ((struct wi_scan_p2_hdr *)wreq.wi_val)->wi_reason == 0) {
2039 : /* Wait some more time for scan completion */
2040 0 : timeout_add(&sc->wi_scan_timeout, WI_WAVELAN_RES_TIMEOUT);
2041 0 : return;
2042 : }
2043 : }
2044 :
2045 0 : if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
2046 0 : printf(WI_PRT_FMT ": wi_scan_timeout: %d tries\n",
2047 0 : WI_PRT_ARG(sc), sc->wi_scan_lock);
2048 :
2049 : /* Wakeup the userland */
2050 0 : wakeup(&sc->wi_scan_lock);
2051 0 : sc->wi_scan_lock = 0;
2052 0 : }
2053 :
2054 : STATIC void
2055 0 : wi_init_io(struct wi_softc *sc)
2056 : {
2057 0 : struct ifnet *ifp = &sc->sc_ic.ic_ac.ac_if;
2058 : int s;
2059 0 : struct wi_ltv_macaddr mac;
2060 0 : int id = 0;
2061 :
2062 0 : if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
2063 0 : return;
2064 :
2065 : DPRINTF(WID_INIT, ("wi_init: sc %p\n", sc));
2066 :
2067 0 : s = splnet();
2068 :
2069 0 : if (ifp->if_flags & IFF_RUNNING)
2070 0 : wi_stop(sc);
2071 :
2072 0 : wi_reset(sc);
2073 :
2074 : /* Program max data length. */
2075 0 : WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
2076 :
2077 : /* Set the port type. */
2078 0 : WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
2079 :
2080 : /* Enable/disable IBSS creation. */
2081 0 : WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
2082 :
2083 : /* Program the RTS/CTS threshold. */
2084 0 : WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
2085 :
2086 : /* Program the TX rate */
2087 0 : WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
2088 :
2089 : /* Access point density */
2090 0 : WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
2091 :
2092 : /* Power Management Enabled */
2093 0 : WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
2094 :
2095 : /* Power Management Max Sleep */
2096 0 : WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
2097 :
2098 : /* Set Enhanced Security if supported. */
2099 0 : if (sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY)
2100 0 : WI_SETVAL(WI_RID_ENH_SECURITY, sc->wi_enh_security);
2101 :
2102 : /* Set Roaming Mode unless this is a Symbol card. */
2103 0 : if (sc->wi_flags & WI_FLAGS_HAS_ROAMING)
2104 0 : WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
2105 :
2106 : /* Set Antenna Diversity if this is a Symbol card. */
2107 0 : if (sc->wi_flags & WI_FLAGS_HAS_DIVERSITY)
2108 0 : WI_SETVAL(WI_RID_SYMBOL_DIVERSITY, sc->wi_diversity);
2109 :
2110 : /* Specify the network name */
2111 0 : WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name);
2112 :
2113 : /* Specify the IBSS name */
2114 0 : if (sc->wi_net_name.i_len != 0 && (sc->wi_ptype == WI_PORTTYPE_HOSTAP ||
2115 0 : (sc->wi_create_ibss && sc->wi_ptype == WI_PORTTYPE_IBSS)))
2116 0 : WI_SETSTR(WI_RID_OWN_SSID, sc->wi_net_name);
2117 : else
2118 0 : WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name);
2119 :
2120 : /* Specify the frequency to use */
2121 0 : WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel);
2122 :
2123 : /* Program the nodename. */
2124 0 : WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name);
2125 :
2126 : /* Set our MAC address. */
2127 0 : mac.wi_len = 4;
2128 0 : mac.wi_type = WI_RID_MAC_NODE;
2129 0 : bcopy(LLADDR(ifp->if_sadl), &sc->sc_ic.ic_myaddr, ETHER_ADDR_LEN);
2130 0 : bcopy(&sc->sc_ic.ic_myaddr, &mac.wi_mac_addr, ETHER_ADDR_LEN);
2131 0 : wi_write_record(sc, (struct wi_ltv_gen *)&mac);
2132 :
2133 : /*
2134 : * Initialize promisc mode.
2135 : * Being in the Host-AP mode causes
2136 : * great deal of pain if promisc mode is set.
2137 : * Therefore we avoid confusing the firmware
2138 : * and always reset promisc mode in Host-AP regime,
2139 : * it shows us all the packets anyway.
2140 : */
2141 0 : if (sc->wi_ptype != WI_PORTTYPE_HOSTAP && ifp->if_flags & IFF_PROMISC)
2142 0 : WI_SETVAL(WI_RID_PROMISC, 1);
2143 : else
2144 0 : WI_SETVAL(WI_RID_PROMISC, 0);
2145 :
2146 : /* Configure WEP. */
2147 0 : if (sc->wi_flags & WI_FLAGS_HAS_WEP) {
2148 0 : WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
2149 0 : WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
2150 0 : sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
2151 0 : sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
2152 0 : wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
2153 0 : if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
2154 : /*
2155 : * HWB3163 EVAL-CARD Firmware version less than 0.8.2.
2156 : *
2157 : * If promiscuous mode is disabled, the Prism2 chip
2158 : * does not work with WEP .
2159 : * I'm currently investigating the details of this.
2160 : * (ichiro@netbsd.org)
2161 : */
2162 0 : if (sc->sc_firmware_type == WI_INTERSIL &&
2163 0 : sc->sc_sta_firmware_ver < 802 ) {
2164 : /* firm ver < 0.8.2 */
2165 0 : WI_SETVAL(WI_RID_PROMISC, 1);
2166 0 : }
2167 0 : WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype);
2168 0 : }
2169 : }
2170 :
2171 : /* Set multicast filter. */
2172 0 : wi_setmulti(sc);
2173 :
2174 : /* Enable desired port */
2175 0 : wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0);
2176 :
2177 0 : if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id))
2178 0 : printf(WI_PRT_FMT ": tx buffer allocation failed\n",
2179 0 : WI_PRT_ARG(sc));
2180 0 : sc->wi_tx_data_id = id;
2181 :
2182 0 : if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id))
2183 0 : printf(WI_PRT_FMT ": mgmt. buffer allocation failed\n",
2184 0 : WI_PRT_ARG(sc));
2185 0 : sc->wi_tx_mgmt_id = id;
2186 :
2187 : /* Set txpower */
2188 0 : if (sc->wi_flags & WI_FLAGS_TXPOWER)
2189 0 : wi_set_txpower(sc, NULL);
2190 :
2191 : /* enable interrupts */
2192 0 : wi_intr_enable(sc, WI_INTRS);
2193 :
2194 0 : wihap_init(sc);
2195 :
2196 0 : splx(s);
2197 :
2198 0 : ifp->if_flags |= IFF_RUNNING;
2199 0 : ifq_clr_oactive(&ifp->if_snd);
2200 :
2201 0 : timeout_add_sec(&sc->sc_timo, 60);
2202 :
2203 0 : return;
2204 0 : }
2205 :
2206 : STATIC void
2207 0 : wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len)
2208 : {
2209 : u_int32_t crc, klen;
2210 0 : u_int8_t key[RC4KEYLEN];
2211 : u_int8_t *dat;
2212 0 : struct rc4_ctx ctx;
2213 :
2214 0 : if (!sc->wi_icv_flag) {
2215 0 : sc->wi_icv = arc4random();
2216 0 : sc->wi_icv_flag++;
2217 0 : } else
2218 0 : sc->wi_icv++;
2219 : /*
2220 : * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
2221 : * (B, 255, N) with 3 <= B < 8
2222 : */
2223 0 : if (sc->wi_icv >= 0x03ff00 &&
2224 0 : (sc->wi_icv & 0xf8ff00) == 0x00ff00)
2225 0 : sc->wi_icv += 0x000100;
2226 :
2227 : /* prepend 24bit IV to tx key, byte order does not matter */
2228 0 : bzero(key, sizeof(key));
2229 0 : key[0] = sc->wi_icv >> 16;
2230 0 : key[1] = sc->wi_icv >> 8;
2231 0 : key[2] = sc->wi_icv;
2232 :
2233 0 : klen = letoh16(sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen);
2234 0 : bcopy(&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat,
2235 0 : key + IEEE80211_WEP_IVLEN, klen);
2236 0 : klen = (klen > IEEE80211_WEP_KEYLEN) ? RC4KEYLEN : RC4KEYLEN / 2;
2237 :
2238 : /* rc4 keysetup */
2239 0 : rc4_keysetup(&ctx, key, klen);
2240 :
2241 : /* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */
2242 : dat = buf;
2243 0 : dat[0] = key[0];
2244 0 : dat[1] = key[1];
2245 0 : dat[2] = key[2];
2246 0 : dat[3] = sc->wi_tx_key << 6; /* pad and keyid */
2247 0 : dat += 4;
2248 :
2249 : /* compute crc32 over data and encrypt */
2250 0 : crc = ~ether_crc32_le(dat, len);
2251 0 : rc4_crypt(&ctx, dat, dat, len);
2252 0 : dat += len;
2253 :
2254 : /* append little-endian crc32 and encrypt */
2255 0 : dat[0] = crc;
2256 0 : dat[1] = crc >> 8;
2257 0 : dat[2] = crc >> 16;
2258 0 : dat[3] = crc >> 24;
2259 0 : rc4_crypt(&ctx, dat, dat, IEEE80211_WEP_CRCLEN);
2260 0 : }
2261 :
2262 : STATIC int
2263 0 : wi_do_hostdecrypt(struct wi_softc *sc, caddr_t buf, int len)
2264 : {
2265 : u_int32_t crc, klen, kid;
2266 0 : u_int8_t key[RC4KEYLEN];
2267 : u_int8_t *dat;
2268 0 : struct rc4_ctx ctx;
2269 :
2270 0 : if (len < IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
2271 : IEEE80211_WEP_CRCLEN)
2272 0 : return -1;
2273 0 : len -= (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
2274 : IEEE80211_WEP_CRCLEN);
2275 :
2276 : dat = buf;
2277 :
2278 0 : bzero(key, sizeof(key));
2279 0 : key[0] = dat[0];
2280 0 : key[1] = dat[1];
2281 0 : key[2] = dat[2];
2282 0 : kid = (dat[3] >> 6) % 4;
2283 0 : dat += 4;
2284 :
2285 0 : klen = letoh16(sc->wi_keys.wi_keys[kid].wi_keylen);
2286 0 : bcopy(&sc->wi_keys.wi_keys[kid].wi_keydat,
2287 0 : key + IEEE80211_WEP_IVLEN, klen);
2288 0 : klen = (klen > IEEE80211_WEP_KEYLEN) ? RC4KEYLEN : RC4KEYLEN / 2;
2289 :
2290 : /* rc4 keysetup */
2291 0 : rc4_keysetup(&ctx, key, klen);
2292 :
2293 : /* decrypt and compute crc32 over data */
2294 0 : rc4_crypt(&ctx, dat, dat, len);
2295 0 : crc = ~ether_crc32_le(dat, len);
2296 0 : dat += len;
2297 :
2298 : /* decrypt little-endian crc32 and verify */
2299 0 : rc4_crypt(&ctx, dat, dat, IEEE80211_WEP_CRCLEN);
2300 :
2301 0 : if ((dat[0] != crc) && (dat[1] != crc >> 8) &&
2302 0 : (dat[2] != crc >> 16) && (dat[3] != crc >> 24)) {
2303 0 : if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
2304 0 : printf(WI_PRT_FMT ": wi_do_hostdecrypt: iv mismatch: "
2305 0 : "0x%02x%02x%02x%02x vs. 0x%x\n", WI_PRT_ARG(sc),
2306 : dat[3], dat[2], dat[1], dat[0], crc);
2307 0 : return -1;
2308 : }
2309 :
2310 0 : return 0;
2311 0 : }
2312 :
2313 : void
2314 0 : wi_start(struct ifnet *ifp)
2315 : {
2316 : struct wi_softc *sc;
2317 : struct mbuf *m0;
2318 0 : struct wi_frame tx_frame;
2319 : struct ether_header *eh;
2320 : int id, hostencrypt = 0;
2321 :
2322 0 : sc = ifp->if_softc;
2323 :
2324 : DPRINTF(WID_START, ("wi_start: ifp %p sc %p\n", ifp, sc));
2325 :
2326 0 : if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
2327 0 : return;
2328 :
2329 0 : if (ifq_is_oactive(&ifp->if_snd))
2330 0 : return;
2331 :
2332 : nextpkt:
2333 0 : IFQ_DEQUEUE(&ifp->if_snd, m0);
2334 0 : if (m0 == NULL)
2335 0 : return;
2336 :
2337 0 : bzero(&tx_frame, sizeof(tx_frame));
2338 0 : tx_frame.wi_frame_ctl = htole16(WI_FTYPE_DATA | WI_STYPE_DATA);
2339 0 : id = sc->wi_tx_data_id;
2340 0 : eh = mtod(m0, struct ether_header *);
2341 :
2342 0 : if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2343 0 : if (!wihap_check_tx(&sc->wi_hostap_info, eh->ether_dhost,
2344 0 : &tx_frame.wi_tx_rate) && !(ifp->if_flags & IFF_PROMISC)) {
2345 0 : if (ifp->if_flags & IFF_DEBUG)
2346 0 : printf(WI_PRT_FMT
2347 : ": wi_start: dropping unassoc dst %s\n",
2348 0 : WI_PRT_ARG(sc),
2349 0 : ether_sprintf(eh->ether_dhost));
2350 0 : m_freem(m0);
2351 0 : goto nextpkt;
2352 : }
2353 : }
2354 :
2355 : /*
2356 : * Use RFC1042 encoding for IP and ARP datagrams,
2357 : * 802.3 for anything else.
2358 : */
2359 0 : if (eh->ether_type == htons(ETHERTYPE_IP) ||
2360 0 : eh->ether_type == htons(ETHERTYPE_ARP) ||
2361 0 : eh->ether_type == htons(ETHERTYPE_REVARP) ||
2362 0 : eh->ether_type == htons(ETHERTYPE_IPV6)) {
2363 0 : bcopy(&eh->ether_dhost,
2364 0 : &tx_frame.wi_addr1, ETHER_ADDR_LEN);
2365 0 : if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2366 0 : tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT); /* XXX */
2367 0 : tx_frame.wi_frame_ctl |= htole16(WI_FCTL_FROMDS);
2368 0 : bcopy(&sc->sc_ic.ic_myaddr,
2369 0 : &tx_frame.wi_addr2, ETHER_ADDR_LEN);
2370 0 : bcopy(&eh->ether_shost,
2371 0 : &tx_frame.wi_addr3, ETHER_ADDR_LEN);
2372 0 : if (sc->wi_use_wep)
2373 0 : hostencrypt = 1;
2374 0 : } else if (sc->wi_ptype == WI_PORTTYPE_BSS && sc->wi_use_wep &&
2375 0 : sc->wi_crypto_algorithm != WI_CRYPTO_FIRMWARE_WEP) {
2376 0 : tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT); /* XXX */
2377 0 : tx_frame.wi_frame_ctl |= htole16(WI_FCTL_TODS);
2378 0 : bcopy(&sc->sc_ic.ic_myaddr,
2379 0 : &tx_frame.wi_addr2, ETHER_ADDR_LEN);
2380 0 : bcopy(&eh->ether_dhost,
2381 0 : &tx_frame.wi_addr3, ETHER_ADDR_LEN);
2382 : hostencrypt = 1;
2383 0 : } else
2384 0 : bcopy(&eh->ether_shost,
2385 0 : &tx_frame.wi_addr2, ETHER_ADDR_LEN);
2386 0 : bcopy(&eh->ether_dhost, &tx_frame.wi_dst_addr, ETHER_ADDR_LEN);
2387 0 : bcopy(&eh->ether_shost, &tx_frame.wi_src_addr, ETHER_ADDR_LEN);
2388 :
2389 0 : tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN;
2390 0 : tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0);
2391 0 : tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1);
2392 0 : tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
2393 0 : tx_frame.wi_type = eh->ether_type;
2394 :
2395 0 : if (hostencrypt) {
2396 :
2397 : /* Do host encryption. */
2398 0 : tx_frame.wi_frame_ctl |= htole16(WI_FCTL_WEP);
2399 0 : bcopy(&tx_frame.wi_dat[0], &sc->wi_txbuf[4], 6);
2400 0 : bcopy(&tx_frame.wi_type, &sc->wi_txbuf[10], 2);
2401 :
2402 0 : m_copydata(m0, sizeof(struct ether_header),
2403 0 : m0->m_pkthdr.len - sizeof(struct ether_header),
2404 0 : (caddr_t)&sc->wi_txbuf[12]);
2405 :
2406 0 : wi_do_hostencrypt(sc, (caddr_t)&sc->wi_txbuf,
2407 0 : tx_frame.wi_dat_len);
2408 :
2409 0 : tx_frame.wi_dat_len += IEEE80211_WEP_IVLEN +
2410 : IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
2411 :
2412 0 : tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
2413 0 : wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
2414 : sizeof(struct wi_frame));
2415 0 : wi_write_data(sc, id, WI_802_11_OFFSET_RAW,
2416 : (caddr_t)&sc->wi_txbuf,
2417 0 : (m0->m_pkthdr.len -
2418 0 : sizeof(struct ether_header)) + 18);
2419 0 : } else {
2420 0 : m_copydata(m0, sizeof(struct ether_header),
2421 0 : m0->m_pkthdr.len - sizeof(struct ether_header),
2422 0 : (caddr_t)&sc->wi_txbuf);
2423 :
2424 0 : tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
2425 0 : wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
2426 : sizeof(struct wi_frame));
2427 0 : wi_write_data(sc, id, WI_802_11_OFFSET,
2428 : (caddr_t)&sc->wi_txbuf,
2429 0 : (m0->m_pkthdr.len -
2430 0 : sizeof(struct ether_header)) + 2);
2431 : }
2432 : } else {
2433 0 : tx_frame.wi_dat_len = htole16(m0->m_pkthdr.len);
2434 :
2435 0 : if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
2436 :
2437 : /* Do host encryption. (XXX - not implemented) */
2438 0 : printf(WI_PRT_FMT
2439 : ": host encrypt not implemented for 802.3\n",
2440 0 : WI_PRT_ARG(sc));
2441 0 : } else {
2442 0 : m_copydata(m0, 0, m0->m_pkthdr.len,
2443 0 : (caddr_t)&sc->wi_txbuf);
2444 :
2445 0 : wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
2446 : sizeof(struct wi_frame));
2447 0 : wi_write_data(sc, id, WI_802_3_OFFSET,
2448 0 : (caddr_t)&sc->wi_txbuf, m0->m_pkthdr.len + 2);
2449 : }
2450 : }
2451 :
2452 : #if NBPFILTER > 0
2453 : /*
2454 : * If there's a BPF listener, bounce a copy of
2455 : * this frame to him.
2456 : */
2457 0 : if (ifp->if_bpf)
2458 0 : bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
2459 : #endif
2460 :
2461 0 : m_freem(m0);
2462 :
2463 0 : ifq_set_oactive(&ifp->if_snd);
2464 :
2465 : /*
2466 : * Set a timeout in case the chip goes out to lunch.
2467 : */
2468 0 : ifp->if_timer = 5;
2469 :
2470 0 : if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
2471 0 : printf(WI_PRT_FMT ": wi_start: xmit failed\n", WI_PRT_ARG(sc));
2472 :
2473 0 : return;
2474 0 : }
2475 :
2476 : STATIC int
2477 0 : wi_mgmt_xmit(struct wi_softc *sc, caddr_t data, int len)
2478 : {
2479 0 : struct wi_frame tx_frame;
2480 : int id;
2481 : struct wi_80211_hdr *hdr;
2482 : caddr_t dptr;
2483 :
2484 0 : if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
2485 0 : return(ENODEV);
2486 :
2487 0 : hdr = (struct wi_80211_hdr *)data;
2488 0 : dptr = data + sizeof(struct wi_80211_hdr);
2489 :
2490 0 : bzero(&tx_frame, sizeof(tx_frame));
2491 0 : id = sc->wi_tx_mgmt_id;
2492 :
2493 0 : bcopy(hdr, &tx_frame.wi_frame_ctl, sizeof(struct wi_80211_hdr));
2494 :
2495 0 : tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT);
2496 0 : tx_frame.wi_dat_len = len - sizeof(struct wi_80211_hdr);
2497 0 : tx_frame.wi_len = htole16(tx_frame.wi_dat_len);
2498 :
2499 0 : tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
2500 0 : wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame));
2501 0 : wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr,
2502 0 : (len - sizeof(struct wi_80211_hdr)) + 2);
2503 :
2504 0 : if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) {
2505 0 : printf(WI_PRT_FMT ": wi_mgmt_xmit: xmit failed\n",
2506 0 : WI_PRT_ARG(sc));
2507 : /*
2508 : * Hostile stations or corrupt frames may crash the card
2509 : * and cause the kernel to get stuck printing complaints.
2510 : * Reset the card and hope the problem goes away.
2511 : */
2512 0 : wi_reset(sc);
2513 0 : return(EIO);
2514 : }
2515 :
2516 0 : return(0);
2517 0 : }
2518 :
2519 : void
2520 0 : wi_stop(struct wi_softc *sc)
2521 : {
2522 : struct ifnet *ifp;
2523 :
2524 0 : wihap_shutdown(sc);
2525 :
2526 0 : if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
2527 0 : return;
2528 :
2529 : DPRINTF(WID_STOP, ("wi_stop: sc %p\n", sc));
2530 :
2531 0 : timeout_del(&sc->sc_timo);
2532 :
2533 0 : ifp = &sc->sc_ic.ic_if;
2534 :
2535 0 : wi_intr_enable(sc, 0);
2536 0 : wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0);
2537 :
2538 0 : ifp->if_flags &= ~IFF_RUNNING;
2539 0 : ifq_clr_oactive(&ifp->if_snd);
2540 0 : ifp->if_timer = 0;
2541 :
2542 0 : return;
2543 0 : }
2544 :
2545 :
2546 : void
2547 0 : wi_watchdog(struct ifnet *ifp)
2548 : {
2549 : struct wi_softc *sc;
2550 :
2551 0 : sc = ifp->if_softc;
2552 :
2553 0 : printf(WI_PRT_FMT ": device timeout\n", WI_PRT_ARG(sc));
2554 :
2555 0 : wi_cor_reset(sc);
2556 0 : wi_init(sc);
2557 :
2558 0 : ifp->if_oerrors++;
2559 :
2560 : return;
2561 0 : }
2562 :
2563 : void
2564 0 : wi_detach(struct wi_softc *sc)
2565 : {
2566 : struct ifnet *ifp;
2567 0 : ifp = &sc->sc_ic.ic_if;
2568 :
2569 0 : if (ifp->if_flags & IFF_RUNNING)
2570 0 : wi_stop(sc);
2571 :
2572 0 : if (sc->wi_flags & WI_FLAGS_ATTACHED) {
2573 0 : sc->wi_flags &= ~WI_FLAGS_ATTACHED;
2574 0 : }
2575 0 : }
2576 :
2577 : STATIC void
2578 0 : wi_get_id(struct wi_softc *sc)
2579 : {
2580 0 : struct wi_ltv_ver ver;
2581 : const struct wi_card_ident *id;
2582 : u_int16_t pri_fw_ver[3];
2583 : const char *card_name;
2584 : u_int16_t card_id;
2585 :
2586 : /* get chip identity */
2587 0 : bzero(&ver, sizeof(ver));
2588 0 : ver.wi_type = WI_RID_CARD_ID;
2589 0 : ver.wi_len = 5;
2590 0 : wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2591 0 : card_id = letoh16(ver.wi_ver[0]);
2592 0 : for (id = wi_card_ident; id->firm_type != WI_NOTYPE; id++) {
2593 0 : if (card_id == id->card_id)
2594 : break;
2595 : }
2596 0 : if (id->firm_type != WI_NOTYPE) {
2597 0 : sc->sc_firmware_type = id->firm_type;
2598 0 : card_name = id->card_name;
2599 0 : } else if (ver.wi_ver[0] & htole16(0x8000)) {
2600 0 : sc->sc_firmware_type = WI_INTERSIL;
2601 : card_name = "Unknown PRISM2 chip";
2602 0 : } else {
2603 0 : sc->sc_firmware_type = WI_LUCENT;
2604 : }
2605 :
2606 : /* get primary firmware version (XXX - how to do Lucent?) */
2607 0 : if (sc->sc_firmware_type != WI_LUCENT) {
2608 0 : bzero(&ver, sizeof(ver));
2609 0 : ver.wi_type = WI_RID_PRI_IDENTITY;
2610 0 : ver.wi_len = 5;
2611 0 : wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2612 0 : pri_fw_ver[0] = letoh16(ver.wi_ver[2]);
2613 0 : pri_fw_ver[1] = letoh16(ver.wi_ver[3]);
2614 0 : pri_fw_ver[2] = letoh16(ver.wi_ver[1]);
2615 0 : }
2616 :
2617 : /* get station firmware version */
2618 0 : bzero(&ver, sizeof(ver));
2619 0 : ver.wi_type = WI_RID_STA_IDENTITY;
2620 0 : ver.wi_len = 5;
2621 0 : wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2622 0 : ver.wi_ver[1] = letoh16(ver.wi_ver[1]);
2623 0 : ver.wi_ver[2] = letoh16(ver.wi_ver[2]);
2624 0 : ver.wi_ver[3] = letoh16(ver.wi_ver[3]);
2625 0 : sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
2626 0 : ver.wi_ver[3] * 100 + ver.wi_ver[1];
2627 :
2628 0 : if (sc->sc_firmware_type == WI_INTERSIL &&
2629 0 : (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
2630 0 : struct wi_ltv_str sver;
2631 : char *p;
2632 :
2633 0 : bzero(&sver, sizeof(sver));
2634 0 : sver.wi_type = WI_RID_SYMBOL_IDENTITY;
2635 0 : sver.wi_len = 7;
2636 : /* value should be something like "V2.00-11" */
2637 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
2638 0 : *(p = (char *)sver.wi_str) >= 'A' &&
2639 0 : p[2] == '.' && p[5] == '-' && p[8] == '\0') {
2640 0 : sc->sc_firmware_type = WI_SYMBOL;
2641 0 : sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
2642 0 : (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
2643 0 : (p[6] - '0') * 10 + (p[7] - '0');
2644 0 : }
2645 0 : }
2646 :
2647 0 : if (sc->sc_firmware_type == WI_LUCENT) {
2648 0 : printf("%s: Firmware %d.%02d variant %d, ", WI_PRT_ARG(sc),
2649 0 : ver.wi_ver[2], ver.wi_ver[3], ver.wi_ver[1]);
2650 0 : } else {
2651 0 : printf("%s: %s%s (0x%04x), Firmware %d.%d.%d (primary), %d.%d.%d (station), ",
2652 : WI_PRT_ARG(sc),
2653 0 : sc->sc_firmware_type == WI_SYMBOL ? "Symbol " : "",
2654 0 : card_name, card_id, pri_fw_ver[0], pri_fw_ver[1],
2655 0 : pri_fw_ver[2], sc->sc_sta_firmware_ver / 10000,
2656 0 : (sc->sc_sta_firmware_ver % 10000) / 100,
2657 0 : sc->sc_sta_firmware_ver % 100);
2658 : }
2659 0 : }
2660 :
2661 : STATIC int
2662 0 : wi_sync_media(struct wi_softc *sc, int ptype, int txrate)
2663 : {
2664 0 : uint64_t media = sc->sc_media.ifm_cur->ifm_media;
2665 0 : uint64_t options = IFM_OPTIONS(media);
2666 : uint64_t subtype;
2667 :
2668 0 : switch (txrate) {
2669 : case 1:
2670 : subtype = IFM_IEEE80211_DS1;
2671 0 : break;
2672 : case 2:
2673 : subtype = IFM_IEEE80211_DS2;
2674 0 : break;
2675 : case 3:
2676 : subtype = IFM_AUTO;
2677 0 : break;
2678 : case 5:
2679 : subtype = IFM_IEEE80211_DS5;
2680 0 : break;
2681 : case 11:
2682 : subtype = IFM_IEEE80211_DS11;
2683 0 : break;
2684 : default:
2685 : subtype = IFM_MANUAL; /* Unable to represent */
2686 0 : break;
2687 : }
2688 :
2689 0 : options &= ~IFM_OMASK;
2690 0 : switch (ptype) {
2691 : case WI_PORTTYPE_BSS:
2692 : /* default port type */
2693 : break;
2694 : case WI_PORTTYPE_ADHOC:
2695 0 : options |= IFM_IEEE80211_ADHOC;
2696 0 : break;
2697 : case WI_PORTTYPE_HOSTAP:
2698 0 : options |= IFM_IEEE80211_HOSTAP;
2699 0 : break;
2700 : case WI_PORTTYPE_IBSS:
2701 0 : if (sc->wi_create_ibss)
2702 0 : options |= IFM_IEEE80211_IBSSMASTER;
2703 : else
2704 0 : options |= IFM_IEEE80211_IBSS;
2705 : break;
2706 : default:
2707 : subtype = IFM_MANUAL; /* Unable to represent */
2708 0 : break;
2709 : }
2710 0 : media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
2711 : IFM_INST(media));
2712 0 : if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
2713 0 : return (EINVAL);
2714 0 : ifmedia_set(&sc->sc_media, media);
2715 0 : sc->wi_ptype = ptype;
2716 0 : sc->wi_tx_rate = txrate;
2717 0 : return (0);
2718 0 : }
2719 :
2720 : STATIC int
2721 0 : wi_media_change(struct ifnet *ifp)
2722 : {
2723 0 : struct wi_softc *sc = ifp->if_softc;
2724 0 : int otype = sc->wi_ptype;
2725 0 : int orate = sc->wi_tx_rate;
2726 0 : int ocreate_ibss = sc->wi_create_ibss;
2727 :
2728 0 : if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_HOSTAP) &&
2729 0 : sc->sc_firmware_type != WI_INTERSIL)
2730 0 : return (EINVAL);
2731 :
2732 0 : sc->wi_create_ibss = 0;
2733 :
2734 0 : switch (sc->sc_media.ifm_cur->ifm_media & IFM_OMASK) {
2735 : case 0:
2736 0 : sc->wi_ptype = WI_PORTTYPE_BSS;
2737 0 : break;
2738 : case IFM_IEEE80211_ADHOC:
2739 0 : sc->wi_ptype = WI_PORTTYPE_ADHOC;
2740 0 : break;
2741 : case IFM_IEEE80211_HOSTAP:
2742 0 : sc->wi_ptype = WI_PORTTYPE_HOSTAP;
2743 0 : break;
2744 : case IFM_IEEE80211_IBSSMASTER:
2745 : case IFM_IEEE80211_IBSSMASTER|IFM_IEEE80211_IBSS:
2746 0 : if (!(sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS))
2747 0 : return (EINVAL);
2748 0 : sc->wi_create_ibss = 1;
2749 : /* FALLTHROUGH */
2750 : case IFM_IEEE80211_IBSS:
2751 0 : sc->wi_ptype = WI_PORTTYPE_IBSS;
2752 0 : break;
2753 : default:
2754 : /* Invalid combination. */
2755 0 : return (EINVAL);
2756 : }
2757 :
2758 0 : switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
2759 : case IFM_IEEE80211_DS1:
2760 0 : sc->wi_tx_rate = 1;
2761 0 : break;
2762 : case IFM_IEEE80211_DS2:
2763 0 : sc->wi_tx_rate = 2;
2764 0 : break;
2765 : case IFM_AUTO:
2766 0 : sc->wi_tx_rate = 3;
2767 0 : break;
2768 : case IFM_IEEE80211_DS5:
2769 0 : sc->wi_tx_rate = 5;
2770 0 : break;
2771 : case IFM_IEEE80211_DS11:
2772 0 : sc->wi_tx_rate = 11;
2773 0 : break;
2774 : }
2775 :
2776 0 : if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
2777 0 : if (otype != sc->wi_ptype || orate != sc->wi_tx_rate ||
2778 0 : ocreate_ibss != sc->wi_create_ibss)
2779 0 : wi_init(sc);
2780 : }
2781 :
2782 0 : ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
2783 :
2784 0 : return (0);
2785 0 : }
2786 :
2787 : STATIC void
2788 0 : wi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
2789 : {
2790 0 : struct wi_softc *sc = ifp->if_softc;
2791 0 : struct wi_req wreq;
2792 :
2793 0 : if (!(sc->sc_ic.ic_if.if_flags & IFF_UP)) {
2794 0 : imr->ifm_active = IFM_IEEE80211|IFM_NONE;
2795 0 : imr->ifm_status = 0;
2796 0 : return;
2797 : }
2798 :
2799 0 : if (sc->wi_tx_rate == 3) {
2800 0 : imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
2801 :
2802 0 : wreq.wi_type = WI_RID_CUR_TX_RATE;
2803 0 : wreq.wi_len = WI_MAX_DATALEN;
2804 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) {
2805 0 : switch (letoh16(wreq.wi_val[0])) {
2806 : case 1:
2807 0 : imr->ifm_active |= IFM_IEEE80211_DS1;
2808 0 : break;
2809 : case 2:
2810 0 : imr->ifm_active |= IFM_IEEE80211_DS2;
2811 0 : break;
2812 : case 6:
2813 0 : imr->ifm_active |= IFM_IEEE80211_DS5;
2814 0 : break;
2815 : case 11:
2816 0 : imr->ifm_active |= IFM_IEEE80211_DS11;
2817 0 : break;
2818 : }
2819 : }
2820 : } else {
2821 0 : imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
2822 : }
2823 :
2824 0 : imr->ifm_status = IFM_AVALID;
2825 0 : switch (sc->wi_ptype) {
2826 : case WI_PORTTYPE_ADHOC:
2827 : case WI_PORTTYPE_IBSS:
2828 : /*
2829 : * XXX: It would be nice if we could give some actually
2830 : * useful status like whether we joined another IBSS or
2831 : * created one ourselves.
2832 : */
2833 : /* FALLTHROUGH */
2834 : case WI_PORTTYPE_HOSTAP:
2835 0 : imr->ifm_status |= IFM_ACTIVE;
2836 0 : break;
2837 : default:
2838 0 : wreq.wi_type = WI_RID_COMMQUAL;
2839 0 : wreq.wi_len = WI_MAX_DATALEN;
2840 0 : if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
2841 0 : letoh16(wreq.wi_val[0]) != 0)
2842 0 : imr->ifm_status |= IFM_ACTIVE;
2843 : }
2844 0 : }
2845 :
2846 : STATIC int
2847 0 : wi_set_nwkey(struct wi_softc *sc, struct ieee80211_nwkey *nwkey)
2848 : {
2849 : int i, len, error;
2850 0 : struct wi_req wreq;
2851 0 : struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
2852 :
2853 0 : if (!(sc->wi_flags & WI_FLAGS_HAS_WEP))
2854 0 : return ENODEV;
2855 0 : if (nwkey->i_defkid <= 0 || nwkey->i_defkid > IEEE80211_WEP_NKID)
2856 0 : return EINVAL;
2857 0 : memcpy(wk, &sc->wi_keys, sizeof(*wk));
2858 0 : for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2859 0 : if (nwkey->i_key[i].i_keydat == NULL)
2860 : continue;
2861 0 : len = nwkey->i_key[i].i_keylen;
2862 0 : if (len > sizeof(wk->wi_keys[i].wi_keydat))
2863 0 : return EINVAL;
2864 0 : error = copyin(nwkey->i_key[i].i_keydat,
2865 0 : wk->wi_keys[i].wi_keydat, len);
2866 0 : if (error)
2867 0 : return error;
2868 0 : wk->wi_keys[i].wi_keylen = htole16(len);
2869 0 : }
2870 :
2871 0 : wk->wi_len = (sizeof(*wk) / 2) + 1;
2872 0 : wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
2873 0 : if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
2874 0 : error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2875 0 : if (error)
2876 0 : return error;
2877 : }
2878 0 : if ((error = wi_setdef(sc, &wreq)))
2879 0 : return (error);
2880 :
2881 0 : wreq.wi_len = 2;
2882 0 : wreq.wi_type = WI_RID_TX_CRYPT_KEY;
2883 0 : wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
2884 0 : if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
2885 0 : error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2886 0 : if (error)
2887 0 : return error;
2888 : }
2889 0 : if ((error = wi_setdef(sc, &wreq)))
2890 0 : return (error);
2891 :
2892 0 : wreq.wi_type = WI_RID_ENCRYPTION;
2893 0 : wreq.wi_val[0] = htole16(nwkey->i_wepon);
2894 0 : if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
2895 0 : error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2896 0 : if (error)
2897 0 : return error;
2898 : }
2899 0 : if ((error = wi_setdef(sc, &wreq)))
2900 0 : return (error);
2901 :
2902 0 : if (sc->sc_ic.ic_if.if_flags & IFF_UP)
2903 0 : wi_init(sc);
2904 0 : return 0;
2905 0 : }
2906 :
2907 : STATIC int
2908 0 : wi_get_nwkey(struct wi_softc *sc, struct ieee80211_nwkey *nwkey)
2909 : {
2910 : int i, len, error;
2911 0 : struct wi_ltv_keys *wk = &sc->wi_keys;
2912 :
2913 0 : if (!(sc->wi_flags & WI_FLAGS_HAS_WEP))
2914 0 : return ENODEV;
2915 0 : nwkey->i_wepon = sc->wi_use_wep;
2916 0 : nwkey->i_defkid = sc->wi_tx_key + 1;
2917 :
2918 : /* do not show any keys to non-root user */
2919 0 : error = suser(curproc);
2920 0 : for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2921 0 : if (nwkey->i_key[i].i_keydat == NULL)
2922 : continue;
2923 : /* error holds results of suser() for the first time */
2924 0 : if (error)
2925 0 : return error;
2926 0 : len = letoh16(wk->wi_keys[i].wi_keylen);
2927 0 : if (nwkey->i_key[i].i_keylen < len)
2928 0 : return ENOSPC;
2929 0 : nwkey->i_key[i].i_keylen = len;
2930 0 : error = copyout(wk->wi_keys[i].wi_keydat,
2931 0 : nwkey->i_key[i].i_keydat, len);
2932 0 : if (error)
2933 0 : return error;
2934 : }
2935 0 : return 0;
2936 0 : }
2937 :
2938 : STATIC int
2939 0 : wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
2940 : {
2941 :
2942 0 : sc->wi_pm_enabled = power->i_enabled;
2943 0 : sc->wi_max_sleep = power->i_maxsleep;
2944 :
2945 0 : if (sc->sc_ic.ic_if.if_flags & IFF_UP)
2946 0 : wi_init(sc);
2947 :
2948 0 : return (0);
2949 : }
2950 :
2951 : STATIC int
2952 0 : wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
2953 : {
2954 :
2955 0 : power->i_enabled = sc->wi_pm_enabled;
2956 0 : power->i_maxsleep = sc->wi_max_sleep;
2957 :
2958 0 : return (0);
2959 : }
2960 :
2961 : STATIC int
2962 0 : wi_set_txpower(struct wi_softc *sc, struct ieee80211_txpower *txpower)
2963 : {
2964 : u_int16_t cmd;
2965 : u_int16_t power;
2966 : int8_t tmp;
2967 : int error;
2968 : int alc;
2969 :
2970 0 : if (txpower == NULL) {
2971 0 : if (!(sc->wi_flags & WI_FLAGS_TXPOWER))
2972 0 : return (EINVAL);
2973 : alc = 0; /* disable ALC */
2974 0 : } else {
2975 0 : if (txpower->i_mode == IEEE80211_TXPOWER_MODE_AUTO) {
2976 : alc = 1; /* enable ALC */
2977 0 : sc->wi_flags &= ~WI_FLAGS_TXPOWER;
2978 0 : } else {
2979 : alc = 0; /* disable ALC */
2980 0 : sc->wi_flags |= WI_FLAGS_TXPOWER;
2981 0 : sc->wi_txpower = txpower->i_val;
2982 : }
2983 : }
2984 :
2985 : /* Set ALC */
2986 : cmd = WI_CMD_DEBUG | (WI_DEBUG_CONFBITS << 8);
2987 0 : if ((error = wi_cmd(sc, cmd, alc, 0x8, 0)) != 0)
2988 0 : return (error);
2989 :
2990 : /* No need to set the TX power value if ALC is enabled */
2991 0 : if (alc)
2992 0 : return (0);
2993 :
2994 : /* Convert dBM to internal TX power value */
2995 0 : if (sc->wi_txpower > 20)
2996 0 : power = 128;
2997 0 : else if (sc->wi_txpower < -43)
2998 0 : power = 127;
2999 : else {
3000 0 : tmp = sc->wi_txpower;
3001 0 : tmp = -12 - tmp;
3002 0 : tmp <<= 2;
3003 :
3004 0 : power = (u_int16_t)tmp;
3005 : }
3006 :
3007 : /* Set manual TX power */
3008 : cmd = WI_CMD_WRITE_MIF;
3009 0 : if ((error = wi_cmd(sc, cmd,
3010 0 : WI_HFA384X_CR_MANUAL_TX_POWER, power, 0)) != 0)
3011 0 : return (error);
3012 :
3013 0 : if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
3014 0 : printf("%s: %u (%d dBm)\n", sc->sc_dev.dv_xname, power,
3015 0 : sc->wi_txpower);
3016 :
3017 0 : return (0);
3018 0 : }
3019 :
3020 : STATIC int
3021 0 : wi_get_txpower(struct wi_softc *sc, struct ieee80211_txpower *txpower)
3022 : {
3023 : u_int16_t cmd;
3024 : u_int16_t power;
3025 : int8_t tmp;
3026 : int error;
3027 :
3028 0 : if (sc->wi_flags & WI_FLAGS_BUS_USB)
3029 0 : return (EOPNOTSUPP);
3030 :
3031 : /* Get manual TX power */
3032 : cmd = WI_CMD_READ_MIF;
3033 0 : if ((error = wi_cmd(sc, cmd,
3034 0 : WI_HFA384X_CR_MANUAL_TX_POWER, 0, 0)) != 0)
3035 0 : return (error);
3036 :
3037 0 : power = CSR_READ_2(sc, WI_RESP0);
3038 :
3039 : /* Convert internal TX power value to dBM */
3040 0 : if (power > 255)
3041 0 : txpower->i_val = 255;
3042 : else {
3043 0 : tmp = power;
3044 0 : tmp >>= 2;
3045 0 : txpower->i_val = (u_int16_t)(-12 - tmp);
3046 : }
3047 :
3048 0 : if (sc->wi_flags & WI_FLAGS_TXPOWER)
3049 0 : txpower->i_mode = IEEE80211_TXPOWER_MODE_FIXED;
3050 : else
3051 0 : txpower->i_mode = IEEE80211_TXPOWER_MODE_AUTO;
3052 :
3053 0 : return (0);
3054 0 : }
3055 :
3056 : STATIC int
3057 0 : wi_set_ssid(struct ieee80211_nwid *ws, u_int8_t *id, int len)
3058 : {
3059 :
3060 0 : if (len > IEEE80211_NWID_LEN)
3061 0 : return (EINVAL);
3062 0 : ws->i_len = len;
3063 0 : memcpy(ws->i_nwid, id, len);
3064 0 : return (0);
3065 0 : }
3066 :
3067 : STATIC int
3068 0 : wi_get_debug(struct wi_softc *sc, struct wi_req *wreq)
3069 : {
3070 : int error = 0;
3071 :
3072 0 : wreq->wi_len = 1;
3073 :
3074 0 : switch (wreq->wi_type) {
3075 : case WI_DEBUG_SLEEP:
3076 0 : wreq->wi_len++;
3077 0 : wreq->wi_val[0] = htole16(sc->wi_debug.wi_sleep);
3078 0 : break;
3079 : case WI_DEBUG_DELAYSUPP:
3080 0 : wreq->wi_len++;
3081 0 : wreq->wi_val[0] = htole16(sc->wi_debug.wi_delaysupp);
3082 0 : break;
3083 : case WI_DEBUG_TXSUPP:
3084 0 : wreq->wi_len++;
3085 0 : wreq->wi_val[0] = htole16(sc->wi_debug.wi_txsupp);
3086 0 : break;
3087 : case WI_DEBUG_MONITOR:
3088 0 : wreq->wi_len++;
3089 0 : wreq->wi_val[0] = htole16(sc->wi_debug.wi_monitor);
3090 0 : break;
3091 : case WI_DEBUG_LEDTEST:
3092 0 : wreq->wi_len += 3;
3093 0 : wreq->wi_val[0] = htole16(sc->wi_debug.wi_ledtest);
3094 0 : wreq->wi_val[1] = htole16(sc->wi_debug.wi_ledtest_param0);
3095 0 : wreq->wi_val[2] = htole16(sc->wi_debug.wi_ledtest_param1);
3096 0 : break;
3097 : case WI_DEBUG_CONTTX:
3098 0 : wreq->wi_len += 2;
3099 0 : wreq->wi_val[0] = htole16(sc->wi_debug.wi_conttx);
3100 0 : wreq->wi_val[1] = htole16(sc->wi_debug.wi_conttx_param0);
3101 0 : break;
3102 : case WI_DEBUG_CONTRX:
3103 0 : wreq->wi_len++;
3104 0 : wreq->wi_val[0] = htole16(sc->wi_debug.wi_contrx);
3105 0 : break;
3106 : case WI_DEBUG_SIGSTATE:
3107 0 : wreq->wi_len += 2;
3108 0 : wreq->wi_val[0] = htole16(sc->wi_debug.wi_sigstate);
3109 0 : wreq->wi_val[1] = htole16(sc->wi_debug.wi_sigstate_param0);
3110 0 : break;
3111 : case WI_DEBUG_CONFBITS:
3112 0 : wreq->wi_len += 2;
3113 0 : wreq->wi_val[0] = htole16(sc->wi_debug.wi_confbits);
3114 0 : wreq->wi_val[1] = htole16(sc->wi_debug.wi_confbits_param0);
3115 0 : break;
3116 : default:
3117 : error = EIO;
3118 0 : break;
3119 : }
3120 :
3121 0 : return (error);
3122 : }
3123 :
3124 : STATIC int
3125 0 : wi_set_debug(struct wi_softc *sc, struct wi_req *wreq)
3126 : {
3127 : int error = 0;
3128 : u_int16_t cmd, param0 = 0, param1 = 0;
3129 :
3130 0 : switch (wreq->wi_type) {
3131 : case WI_DEBUG_RESET:
3132 : case WI_DEBUG_INIT:
3133 : case WI_DEBUG_CALENABLE:
3134 : break;
3135 : case WI_DEBUG_SLEEP:
3136 0 : sc->wi_debug.wi_sleep = 1;
3137 0 : break;
3138 : case WI_DEBUG_WAKE:
3139 0 : sc->wi_debug.wi_sleep = 0;
3140 0 : break;
3141 : case WI_DEBUG_CHAN:
3142 0 : param0 = letoh16(wreq->wi_val[0]);
3143 0 : break;
3144 : case WI_DEBUG_DELAYSUPP:
3145 0 : sc->wi_debug.wi_delaysupp = 1;
3146 0 : break;
3147 : case WI_DEBUG_TXSUPP:
3148 0 : sc->wi_debug.wi_txsupp = 1;
3149 0 : break;
3150 : case WI_DEBUG_MONITOR:
3151 0 : sc->wi_debug.wi_monitor = 1;
3152 0 : break;
3153 : case WI_DEBUG_LEDTEST:
3154 0 : param0 = letoh16(wreq->wi_val[0]);
3155 0 : param1 = letoh16(wreq->wi_val[1]);
3156 0 : sc->wi_debug.wi_ledtest = 1;
3157 0 : sc->wi_debug.wi_ledtest_param0 = param0;
3158 0 : sc->wi_debug.wi_ledtest_param1 = param1;
3159 0 : break;
3160 : case WI_DEBUG_CONTTX:
3161 0 : param0 = letoh16(wreq->wi_val[0]);
3162 0 : sc->wi_debug.wi_conttx = 1;
3163 0 : sc->wi_debug.wi_conttx_param0 = param0;
3164 0 : break;
3165 : case WI_DEBUG_STOPTEST:
3166 0 : sc->wi_debug.wi_delaysupp = 0;
3167 0 : sc->wi_debug.wi_txsupp = 0;
3168 0 : sc->wi_debug.wi_monitor = 0;
3169 0 : sc->wi_debug.wi_ledtest = 0;
3170 0 : sc->wi_debug.wi_ledtest_param0 = 0;
3171 0 : sc->wi_debug.wi_ledtest_param1 = 0;
3172 0 : sc->wi_debug.wi_conttx = 0;
3173 0 : sc->wi_debug.wi_conttx_param0 = 0;
3174 0 : sc->wi_debug.wi_contrx = 0;
3175 0 : sc->wi_debug.wi_sigstate = 0;
3176 0 : sc->wi_debug.wi_sigstate_param0 = 0;
3177 0 : break;
3178 : case WI_DEBUG_CONTRX:
3179 0 : sc->wi_debug.wi_contrx = 1;
3180 0 : break;
3181 : case WI_DEBUG_SIGSTATE:
3182 0 : param0 = letoh16(wreq->wi_val[0]);
3183 0 : sc->wi_debug.wi_sigstate = 1;
3184 0 : sc->wi_debug.wi_sigstate_param0 = param0;
3185 0 : break;
3186 : case WI_DEBUG_CONFBITS:
3187 0 : param0 = letoh16(wreq->wi_val[0]);
3188 0 : param1 = letoh16(wreq->wi_val[1]);
3189 0 : sc->wi_debug.wi_confbits = param0;
3190 0 : sc->wi_debug.wi_confbits_param0 = param1;
3191 0 : break;
3192 : default:
3193 : error = EIO;
3194 0 : break;
3195 : }
3196 :
3197 0 : if (error)
3198 0 : return (error);
3199 :
3200 0 : cmd = WI_CMD_DEBUG | (wreq->wi_type << 8);
3201 0 : error = wi_cmd(sc, cmd, param0, param1, 0);
3202 :
3203 0 : return (error);
3204 0 : }
|