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