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