wi.c revision 1.17.2.14 1 1.17.2.14 nathanw /* $NetBSD: wi.c,v 1.17.2.14 2002/06/24 22:10:04 nathanw Exp $ */
2 1.17.2.2 nathanw
3 1.17.2.2 nathanw /*
4 1.17.2.2 nathanw * Copyright (c) 1997, 1998, 1999
5 1.17.2.2 nathanw * Bill Paul <wpaul (at) ctr.columbia.edu>. All rights reserved.
6 1.17.2.2 nathanw *
7 1.17.2.2 nathanw * Redistribution and use in source and binary forms, with or without
8 1.17.2.2 nathanw * modification, are permitted provided that the following conditions
9 1.17.2.2 nathanw * are met:
10 1.17.2.2 nathanw * 1. Redistributions of source code must retain the above copyright
11 1.17.2.2 nathanw * notice, this list of conditions and the following disclaimer.
12 1.17.2.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
13 1.17.2.2 nathanw * notice, this list of conditions and the following disclaimer in the
14 1.17.2.2 nathanw * documentation and/or other materials provided with the distribution.
15 1.17.2.2 nathanw * 3. All advertising materials mentioning features or use of this software
16 1.17.2.2 nathanw * must display the following acknowledgement:
17 1.17.2.2 nathanw * This product includes software developed by Bill Paul.
18 1.17.2.2 nathanw * 4. Neither the name of the author nor the names of any co-contributors
19 1.17.2.2 nathanw * may be used to endorse or promote products derived from this software
20 1.17.2.2 nathanw * without specific prior written permission.
21 1.17.2.2 nathanw *
22 1.17.2.2 nathanw * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 1.17.2.2 nathanw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.17.2.2 nathanw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.17.2.2 nathanw * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26 1.17.2.2 nathanw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 1.17.2.2 nathanw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 1.17.2.2 nathanw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 1.17.2.2 nathanw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 1.17.2.2 nathanw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 1.17.2.2 nathanw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 1.17.2.2 nathanw * THE POSSIBILITY OF SUCH DAMAGE.
33 1.17.2.2 nathanw */
34 1.17.2.2 nathanw
35 1.17.2.2 nathanw /*
36 1.17.2.2 nathanw * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for NetBSD.
37 1.17.2.2 nathanw *
38 1.17.2.2 nathanw * Original FreeBSD driver written by Bill Paul <wpaul (at) ctr.columbia.edu>
39 1.17.2.2 nathanw * Electrical Engineering Department
40 1.17.2.2 nathanw * Columbia University, New York City
41 1.17.2.2 nathanw */
42 1.17.2.2 nathanw
43 1.17.2.2 nathanw /*
44 1.17.2.2 nathanw * The WaveLAN/IEEE adapter is the second generation of the WaveLAN
45 1.17.2.2 nathanw * from Lucent. Unlike the older cards, the new ones are programmed
46 1.17.2.2 nathanw * entirely via a firmware-driven controller called the Hermes.
47 1.17.2.2 nathanw * Unfortunately, Lucent will not release the Hermes programming manual
48 1.17.2.2 nathanw * without an NDA (if at all). What they do release is an API library
49 1.17.2.2 nathanw * called the HCF (Hardware Control Functions) which is supposed to
50 1.17.2.2 nathanw * do the device-specific operations of a device driver for you. The
51 1.17.2.2 nathanw * publically available version of the HCF library (the 'HCF Light') is
52 1.17.2.2 nathanw * a) extremely gross, b) lacks certain features, particularly support
53 1.17.2.2 nathanw * for 802.11 frames, and c) is contaminated by the GNU Public License.
54 1.17.2.2 nathanw *
55 1.17.2.2 nathanw * This driver does not use the HCF or HCF Light at all. Instead, it
56 1.17.2.2 nathanw * programs the Hermes controller directly, using information gleaned
57 1.17.2.2 nathanw * from the HCF Light code and corresponding documentation.
58 1.17.2.2 nathanw *
59 1.17.2.2 nathanw * This driver supports both the PCMCIA and ISA versions of the
60 1.17.2.2 nathanw * WaveLAN/IEEE cards. Note however that the ISA card isn't really
61 1.17.2.2 nathanw * anything of the sort: it's actually a PCMCIA bridge adapter
62 1.17.2.2 nathanw * that fits into an ISA slot, into which a PCMCIA WaveLAN card is
63 1.17.2.2 nathanw * inserted. Consequently, you need to use the pccard support for
64 1.17.2.2 nathanw * both the ISA and PCMCIA adapters.
65 1.17.2.2 nathanw */
66 1.17.2.2 nathanw
67 1.17.2.2 nathanw /*
68 1.17.2.2 nathanw * FreeBSD driver ported to NetBSD by Bill Sommerfeld in the back of the
69 1.17.2.2 nathanw * Oslo IETF plenary meeting.
70 1.17.2.2 nathanw */
71 1.17.2.2 nathanw
72 1.17.2.8 nathanw #include <sys/cdefs.h>
73 1.17.2.14 nathanw __KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.17.2.14 2002/06/24 22:10:04 nathanw Exp $");
74 1.17.2.8 nathanw
75 1.17.2.2 nathanw #define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */
76 1.17.2.2 nathanw #define WI_HERMES_STATS_WAR /* Work around stats counter bug. */
77 1.17.2.2 nathanw
78 1.17.2.2 nathanw #include "bpfilter.h"
79 1.17.2.2 nathanw
80 1.17.2.2 nathanw #include <sys/param.h>
81 1.17.2.2 nathanw #include <sys/systm.h>
82 1.17.2.2 nathanw #include <sys/callout.h>
83 1.17.2.2 nathanw #include <sys/device.h>
84 1.17.2.2 nathanw #include <sys/socket.h>
85 1.17.2.2 nathanw #include <sys/mbuf.h>
86 1.17.2.2 nathanw #include <sys/ioctl.h>
87 1.17.2.2 nathanw #include <sys/kernel.h> /* for hz */
88 1.17.2.2 nathanw #include <sys/lwp.h>
89 1.17.2.2 nathanw #include <sys/proc.h>
90 1.17.2.2 nathanw
91 1.17.2.2 nathanw #include <net/if.h>
92 1.17.2.2 nathanw #include <net/if_dl.h>
93 1.17.2.2 nathanw #include <net/if_media.h>
94 1.17.2.2 nathanw #include <net/if_ether.h>
95 1.17.2.2 nathanw #include <net/if_ieee80211.h>
96 1.17.2.2 nathanw
97 1.17.2.2 nathanw #if NBPFILTER > 0
98 1.17.2.2 nathanw #include <net/bpf.h>
99 1.17.2.2 nathanw #include <net/bpfdesc.h>
100 1.17.2.2 nathanw #endif
101 1.17.2.2 nathanw
102 1.17.2.3 nathanw #include <machine/bus.h>
103 1.17.2.2 nathanw
104 1.17.2.2 nathanw #include <dev/ic/wi_ieee.h>
105 1.17.2.2 nathanw #include <dev/ic/wireg.h>
106 1.17.2.2 nathanw #include <dev/ic/wivar.h>
107 1.17.2.2 nathanw
108 1.17.2.2 nathanw static void wi_reset __P((struct wi_softc *));
109 1.17.2.2 nathanw static int wi_ioctl __P((struct ifnet *, u_long, caddr_t));
110 1.17.2.2 nathanw static void wi_start __P((struct ifnet *));
111 1.17.2.2 nathanw static void wi_watchdog __P((struct ifnet *));
112 1.17.2.2 nathanw static int wi_init __P((struct ifnet *));
113 1.17.2.2 nathanw static void wi_stop __P((struct ifnet *, int));
114 1.17.2.2 nathanw static void wi_rxeof __P((struct wi_softc *));
115 1.17.2.2 nathanw static void wi_txeof __P((struct wi_softc *, int));
116 1.17.2.2 nathanw static void wi_update_stats __P((struct wi_softc *));
117 1.17.2.2 nathanw static void wi_setmulti __P((struct wi_softc *));
118 1.17.2.2 nathanw
119 1.17.2.2 nathanw static int wi_cmd __P((struct wi_softc *, int, int));
120 1.17.2.2 nathanw static int wi_read_record __P((struct wi_softc *, struct wi_ltv_gen *));
121 1.17.2.2 nathanw static int wi_write_record __P((struct wi_softc *, struct wi_ltv_gen *));
122 1.17.2.2 nathanw static int wi_read_data __P((struct wi_softc *, int,
123 1.17.2.2 nathanw int, caddr_t, int));
124 1.17.2.2 nathanw static int wi_write_data __P((struct wi_softc *, int,
125 1.17.2.2 nathanw int, caddr_t, int));
126 1.17.2.2 nathanw static int wi_seek __P((struct wi_softc *, int, int, int));
127 1.17.2.2 nathanw static int wi_alloc_nicmem __P((struct wi_softc *, int, int *));
128 1.17.2.7 nathanw static void wi_inquire __P((void *));
129 1.17.2.10 nathanw static void wi_wait_scan __P((void *));
130 1.17.2.2 nathanw static int wi_setdef __P((struct wi_softc *, struct wi_req *));
131 1.17.2.2 nathanw static int wi_getdef __P((struct wi_softc *, struct wi_req *));
132 1.17.2.2 nathanw static int wi_mgmt_xmit __P((struct wi_softc *, caddr_t, int));
133 1.17.2.2 nathanw
134 1.17.2.2 nathanw static int wi_media_change __P((struct ifnet *));
135 1.17.2.2 nathanw static void wi_media_status __P((struct ifnet *, struct ifmediareq *));
136 1.17.2.2 nathanw
137 1.17.2.2 nathanw static void wi_get_id __P((struct wi_softc *));
138 1.17.2.2 nathanw
139 1.17.2.2 nathanw static int wi_set_ssid __P((struct ieee80211_nwid *, u_int8_t *, int));
140 1.17.2.2 nathanw static void wi_request_fill_ssid __P((struct wi_req *,
141 1.17.2.2 nathanw struct ieee80211_nwid *));
142 1.17.2.2 nathanw static int wi_write_ssid __P((struct wi_softc *, int, struct wi_req *,
143 1.17.2.2 nathanw struct ieee80211_nwid *));
144 1.17.2.2 nathanw static int wi_set_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *));
145 1.17.2.2 nathanw static int wi_get_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *));
146 1.17.2.2 nathanw static int wi_sync_media __P((struct wi_softc *, int, int));
147 1.17.2.2 nathanw static int wi_set_pm(struct wi_softc *, struct ieee80211_power *);
148 1.17.2.2 nathanw static int wi_get_pm(struct wi_softc *, struct ieee80211_power *);
149 1.17.2.2 nathanw
150 1.17.2.12 nathanw struct wi_card_ident wi_card_ident[] = {
151 1.17.2.12 nathanw /* CARD_ID CARD_NAME FIRM_TYPE */
152 1.17.2.12 nathanw { WI_NIC_LUCENT_ID, WI_NIC_LUCENT_STR, WI_LUCENT },
153 1.17.2.12 nathanw { WI_NIC_SONY_ID, WI_NIC_SONY_STR, WI_LUCENT },
154 1.17.2.12 nathanw { WI_NIC_LUCENT_EMB_ID, WI_NIC_LUCENT_EMB_STR, WI_LUCENT },
155 1.17.2.12 nathanw { WI_NIC_EVB2_ID, WI_NIC_EVB2_STR, WI_INTERSIL },
156 1.17.2.12 nathanw { WI_NIC_HWB3763_ID, WI_NIC_HWB3763_STR, WI_INTERSIL },
157 1.17.2.12 nathanw { WI_NIC_HWB3163_ID, WI_NIC_HWB3163_STR, WI_INTERSIL },
158 1.17.2.12 nathanw { WI_NIC_HWB3163B_ID, WI_NIC_HWB3163B_STR, WI_INTERSIL },
159 1.17.2.12 nathanw { WI_NIC_EVB3_ID, WI_NIC_EVB3_STR, WI_INTERSIL },
160 1.17.2.12 nathanw { WI_NIC_HWB1153_ID, WI_NIC_HWB1153_STR, WI_INTERSIL },
161 1.17.2.12 nathanw { WI_NIC_P2_SST_ID, WI_NIC_P2_SST_STR, WI_INTERSIL },
162 1.17.2.12 nathanw { WI_NIC_EVB2_SST_ID, WI_NIC_EVB2_SST_STR, WI_INTERSIL },
163 1.17.2.12 nathanw { WI_NIC_3842_EVA_ID, WI_NIC_3842_EVA_STR, WI_INTERSIL },
164 1.17.2.12 nathanw { WI_NIC_3842_PCMCIA_AMD_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
165 1.17.2.12 nathanw { WI_NIC_3842_PCMCIA_SST_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
166 1.17.2.12 nathanw { WI_NIC_3842_PCMCIA_ATM_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
167 1.17.2.12 nathanw { WI_NIC_3842_MINI_AMD_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL },
168 1.17.2.12 nathanw { WI_NIC_3842_MINI_SST_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL },
169 1.17.2.12 nathanw { WI_NIC_3842_MINI_ATM_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL },
170 1.17.2.12 nathanw { WI_NIC_3842_PCI_AMD_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL },
171 1.17.2.12 nathanw { WI_NIC_3842_PCI_SST_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL },
172 1.17.2.12 nathanw { WI_NIC_3842_PCI_ATM_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL },
173 1.17.2.12 nathanw { WI_NIC_P3_PCMCIA_AMD_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL },
174 1.17.2.12 nathanw { WI_NIC_P3_PCMCIA_SST_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL },
175 1.17.2.12 nathanw { WI_NIC_P3_MINI_AMD_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL },
176 1.17.2.12 nathanw { WI_NIC_P3_MINI_SST_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL },
177 1.17.2.12 nathanw { 0, NULL, 0 },
178 1.17.2.12 nathanw };
179 1.17.2.12 nathanw
180 1.17.2.2 nathanw int
181 1.17.2.2 nathanw wi_attach(sc)
182 1.17.2.2 nathanw struct wi_softc *sc;
183 1.17.2.2 nathanw {
184 1.17.2.2 nathanw struct ifnet *ifp = sc->sc_ifp;
185 1.17.2.2 nathanw struct wi_ltv_macaddr mac;
186 1.17.2.2 nathanw struct wi_ltv_gen gen;
187 1.17.2.2 nathanw static const u_int8_t empty_macaddr[ETHER_ADDR_LEN] = {
188 1.17.2.2 nathanw 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
189 1.17.2.2 nathanw };
190 1.17.2.2 nathanw int s;
191 1.17.2.2 nathanw
192 1.17.2.2 nathanw s = splnet();
193 1.17.2.2 nathanw
194 1.17.2.7 nathanw callout_init(&sc->wi_inquire_ch);
195 1.17.2.10 nathanw callout_init(&sc->wi_scan_sh);
196 1.17.2.2 nathanw
197 1.17.2.2 nathanw /* Make sure interrupts are disabled. */
198 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_INT_EN, 0);
199 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
200 1.17.2.2 nathanw
201 1.17.2.2 nathanw /* Reset the NIC. */
202 1.17.2.2 nathanw wi_reset(sc);
203 1.17.2.2 nathanw
204 1.17.2.2 nathanw memset(&mac, 0, sizeof(mac));
205 1.17.2.2 nathanw /* Read the station address. */
206 1.17.2.2 nathanw mac.wi_type = WI_RID_MAC_NODE;
207 1.17.2.2 nathanw mac.wi_len = 4;
208 1.17.2.2 nathanw wi_read_record(sc, (struct wi_ltv_gen *)&mac);
209 1.17.2.2 nathanw memcpy(sc->sc_macaddr, mac.wi_mac_addr, ETHER_ADDR_LEN);
210 1.17.2.2 nathanw
211 1.17.2.2 nathanw /*
212 1.17.2.2 nathanw * Check if we got anything meaningful.
213 1.17.2.2 nathanw *
214 1.17.2.2 nathanw * Is it really enough just checking against null ethernet address?
215 1.17.2.2 nathanw * Or, check against possible vendor? XXX.
216 1.17.2.2 nathanw */
217 1.17.2.3 nathanw if (memcmp(sc->sc_macaddr, empty_macaddr, ETHER_ADDR_LEN) == 0) {
218 1.17.2.12 nathanw printf("could not get mac address, attach failed\n");
219 1.17.2.10 nathanw splx(s);
220 1.17.2.10 nathanw return 1;
221 1.17.2.2 nathanw }
222 1.17.2.2 nathanw
223 1.17.2.2 nathanw printf(" 802.11 address %s\n", ether_sprintf(sc->sc_macaddr));
224 1.17.2.2 nathanw
225 1.17.2.2 nathanw /* Read NIC identification */
226 1.17.2.2 nathanw wi_get_id(sc);
227 1.17.2.2 nathanw
228 1.17.2.2 nathanw memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
229 1.17.2.2 nathanw ifp->if_softc = sc;
230 1.17.2.2 nathanw ifp->if_start = wi_start;
231 1.17.2.2 nathanw ifp->if_ioctl = wi_ioctl;
232 1.17.2.2 nathanw ifp->if_watchdog = wi_watchdog;
233 1.17.2.2 nathanw ifp->if_init = wi_init;
234 1.17.2.2 nathanw ifp->if_stop = wi_stop;
235 1.17.2.2 nathanw ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
236 1.17.2.2 nathanw #ifdef IFF_NOTRAILERS
237 1.17.2.2 nathanw ifp->if_flags |= IFF_NOTRAILERS;
238 1.17.2.2 nathanw #endif
239 1.17.2.2 nathanw IFQ_SET_READY(&ifp->if_snd);
240 1.17.2.2 nathanw
241 1.17.2.2 nathanw (void)wi_set_ssid(&sc->wi_nodeid, WI_DEFAULT_NODENAME,
242 1.17.2.2 nathanw sizeof(WI_DEFAULT_NODENAME) - 1);
243 1.17.2.2 nathanw (void)wi_set_ssid(&sc->wi_netid, WI_DEFAULT_NETNAME,
244 1.17.2.2 nathanw sizeof(WI_DEFAULT_NETNAME) - 1);
245 1.17.2.2 nathanw (void)wi_set_ssid(&sc->wi_ibssid, WI_DEFAULT_IBSS,
246 1.17.2.2 nathanw sizeof(WI_DEFAULT_IBSS) - 1);
247 1.17.2.2 nathanw
248 1.17.2.2 nathanw sc->wi_portnum = WI_DEFAULT_PORT;
249 1.17.2.2 nathanw sc->wi_ptype = WI_PORTTYPE_BSS;
250 1.17.2.2 nathanw sc->wi_ap_density = WI_DEFAULT_AP_DENSITY;
251 1.17.2.2 nathanw sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH;
252 1.17.2.2 nathanw sc->wi_tx_rate = WI_DEFAULT_TX_RATE;
253 1.17.2.2 nathanw sc->wi_max_data_len = WI_DEFAULT_DATALEN;
254 1.17.2.2 nathanw sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
255 1.17.2.2 nathanw sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
256 1.17.2.2 nathanw sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
257 1.17.2.2 nathanw sc->wi_roaming = WI_DEFAULT_ROAMING;
258 1.17.2.2 nathanw sc->wi_authtype = WI_DEFAULT_AUTHTYPE;
259 1.17.2.2 nathanw
260 1.17.2.2 nathanw /*
261 1.17.2.2 nathanw * Read the default channel from the NIC. This may vary
262 1.17.2.2 nathanw * depending on the country where the NIC was purchased, so
263 1.17.2.2 nathanw * we can't hard-code a default and expect it to work for
264 1.17.2.2 nathanw * everyone.
265 1.17.2.2 nathanw */
266 1.17.2.2 nathanw gen.wi_type = WI_RID_OWN_CHNL;
267 1.17.2.2 nathanw gen.wi_len = 2;
268 1.17.2.2 nathanw wi_read_record(sc, &gen);
269 1.17.2.2 nathanw sc->wi_channel = le16toh(gen.wi_val);
270 1.17.2.2 nathanw
271 1.17.2.3 nathanw memset((char *)&sc->wi_stats, 0, sizeof(sc->wi_stats));
272 1.17.2.2 nathanw
273 1.17.2.10 nathanw /* AP info was filled with 0 */
274 1.17.2.10 nathanw memset((char *)&sc->wi_aps, 0, sizeof(sc->wi_aps));
275 1.17.2.10 nathanw sc->wi_scanning=0;
276 1.17.2.10 nathanw sc->wi_naps=0;
277 1.17.2.10 nathanw
278 1.17.2.2 nathanw /*
279 1.17.2.2 nathanw * Find out if we support WEP on this card.
280 1.17.2.2 nathanw */
281 1.17.2.2 nathanw gen.wi_type = WI_RID_WEP_AVAIL;
282 1.17.2.2 nathanw gen.wi_len = 2;
283 1.17.2.2 nathanw wi_read_record(sc, &gen);
284 1.17.2.2 nathanw sc->wi_has_wep = le16toh(gen.wi_val);
285 1.17.2.2 nathanw
286 1.17.2.2 nathanw ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status);
287 1.17.2.2 nathanw #define ADD(m, c) ifmedia_add(&sc->sc_media, (m), (c), NULL)
288 1.17.2.2 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
289 1.17.2.11 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0);
290 1.17.2.2 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
291 1.17.2.2 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
292 1.17.2.2 nathanw IFM_IEEE80211_ADHOC, 0), 0);
293 1.17.2.2 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
294 1.17.2.2 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
295 1.17.2.2 nathanw IFM_IEEE80211_ADHOC, 0), 0);
296 1.17.2.10 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
297 1.17.2.10 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
298 1.17.2.10 nathanw IFM_IEEE80211_ADHOC, 0), 0);
299 1.17.2.2 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
300 1.17.2.2 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
301 1.17.2.2 nathanw IFM_IEEE80211_ADHOC, 0), 0);
302 1.17.2.2 nathanw ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0);
303 1.17.2.2 nathanw #undef ADD
304 1.17.2.11 nathanw ifmedia_set(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0));
305 1.17.2.2 nathanw
306 1.17.2.2 nathanw /*
307 1.17.2.2 nathanw * Call MI attach routines.
308 1.17.2.2 nathanw */
309 1.17.2.2 nathanw if_attach(ifp);
310 1.17.2.2 nathanw ether_ifattach(ifp, mac.wi_mac_addr);
311 1.17.2.2 nathanw
312 1.17.2.2 nathanw ifp->if_baudrate = IF_Mbps(2);
313 1.17.2.2 nathanw
314 1.17.2.2 nathanw /* Attach is successful. */
315 1.17.2.2 nathanw sc->sc_attached = 1;
316 1.17.2.2 nathanw
317 1.17.2.2 nathanw splx(s);
318 1.17.2.2 nathanw return 0;
319 1.17.2.2 nathanw }
320 1.17.2.2 nathanw
321 1.17.2.2 nathanw static void wi_rxeof(sc)
322 1.17.2.2 nathanw struct wi_softc *sc;
323 1.17.2.2 nathanw {
324 1.17.2.2 nathanw struct ifnet *ifp;
325 1.17.2.2 nathanw struct ether_header *eh;
326 1.17.2.2 nathanw struct wi_frame rx_frame;
327 1.17.2.2 nathanw struct mbuf *m;
328 1.17.2.2 nathanw int id;
329 1.17.2.2 nathanw
330 1.17.2.2 nathanw ifp = sc->sc_ifp;
331 1.17.2.2 nathanw
332 1.17.2.2 nathanw id = CSR_READ_2(sc, WI_RX_FID);
333 1.17.2.2 nathanw
334 1.17.2.2 nathanw /* First read in the frame header */
335 1.17.2.2 nathanw if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) {
336 1.17.2.2 nathanw ifp->if_ierrors++;
337 1.17.2.2 nathanw return;
338 1.17.2.2 nathanw }
339 1.17.2.2 nathanw
340 1.17.2.8 nathanw /*
341 1.17.2.8 nathanw * Drop undecryptable or packets with receive errors here
342 1.17.2.8 nathanw */
343 1.17.2.7 nathanw if (le16toh(rx_frame.wi_status) & WI_STAT_ERRSTAT) {
344 1.17.2.2 nathanw ifp->if_ierrors++;
345 1.17.2.2 nathanw return;
346 1.17.2.2 nathanw }
347 1.17.2.2 nathanw
348 1.17.2.2 nathanw MGETHDR(m, M_DONTWAIT, MT_DATA);
349 1.17.2.2 nathanw if (m == NULL) {
350 1.17.2.2 nathanw ifp->if_ierrors++;
351 1.17.2.2 nathanw return;
352 1.17.2.2 nathanw }
353 1.17.2.2 nathanw MCLGET(m, M_DONTWAIT);
354 1.17.2.2 nathanw if (!(m->m_flags & M_EXT)) {
355 1.17.2.2 nathanw m_freem(m);
356 1.17.2.2 nathanw ifp->if_ierrors++;
357 1.17.2.2 nathanw return;
358 1.17.2.2 nathanw }
359 1.17.2.2 nathanw
360 1.17.2.2 nathanw /* Align the data after the ethernet header */
361 1.17.2.2 nathanw m->m_data = (caddr_t) ALIGN(m->m_data + sizeof(struct ether_header))
362 1.17.2.2 nathanw - sizeof(struct ether_header);
363 1.17.2.2 nathanw
364 1.17.2.2 nathanw eh = mtod(m, struct ether_header *);
365 1.17.2.2 nathanw m->m_pkthdr.rcvif = ifp;
366 1.17.2.2 nathanw
367 1.17.2.13 nathanw if ((le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_1042 ||
368 1.17.2.13 nathanw (le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_TUNNEL ||
369 1.17.2.13 nathanw (le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_WMP_MSG) {
370 1.17.2.2 nathanw if ((le16toh(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN) > MCLBYTES) {
371 1.17.2.2 nathanw printf("%s: oversized packet received "
372 1.17.2.2 nathanw "(wi_dat_len=%d, wi_status=0x%x)\n",
373 1.17.2.2 nathanw sc->sc_dev.dv_xname,
374 1.17.2.2 nathanw le16toh(rx_frame.wi_dat_len), le16toh(rx_frame.wi_status));
375 1.17.2.2 nathanw m_freem(m);
376 1.17.2.2 nathanw ifp->if_ierrors++;
377 1.17.2.2 nathanw return;
378 1.17.2.2 nathanw }
379 1.17.2.2 nathanw m->m_pkthdr.len = m->m_len =
380 1.17.2.2 nathanw le16toh(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN;
381 1.17.2.2 nathanw
382 1.17.2.3 nathanw memcpy((char *)&eh->ether_dhost, (char *)&rx_frame.wi_dst_addr,
383 1.17.2.3 nathanw ETHER_ADDR_LEN);
384 1.17.2.3 nathanw memcpy((char *)&eh->ether_shost, (char *)&rx_frame.wi_src_addr,
385 1.17.2.3 nathanw ETHER_ADDR_LEN);
386 1.17.2.3 nathanw memcpy((char *)&eh->ether_type, (char *)&rx_frame.wi_type,
387 1.17.2.3 nathanw sizeof(u_int16_t));
388 1.17.2.2 nathanw
389 1.17.2.2 nathanw if (wi_read_data(sc, id, WI_802_11_OFFSET,
390 1.17.2.2 nathanw mtod(m, caddr_t) + sizeof(struct ether_header),
391 1.17.2.2 nathanw m->m_len + 2)) {
392 1.17.2.2 nathanw m_freem(m);
393 1.17.2.2 nathanw ifp->if_ierrors++;
394 1.17.2.2 nathanw return;
395 1.17.2.2 nathanw }
396 1.17.2.2 nathanw } else {
397 1.17.2.2 nathanw if ((le16toh(rx_frame.wi_dat_len) +
398 1.17.2.2 nathanw sizeof(struct ether_header)) > MCLBYTES) {
399 1.17.2.2 nathanw printf("%s: oversized packet received "
400 1.17.2.2 nathanw "(wi_dat_len=%d, wi_status=0x%x)\n",
401 1.17.2.2 nathanw sc->sc_dev.dv_xname,
402 1.17.2.2 nathanw le16toh(rx_frame.wi_dat_len), le16toh(rx_frame.wi_status));
403 1.17.2.2 nathanw m_freem(m);
404 1.17.2.2 nathanw ifp->if_ierrors++;
405 1.17.2.2 nathanw return;
406 1.17.2.2 nathanw }
407 1.17.2.2 nathanw m->m_pkthdr.len = m->m_len =
408 1.17.2.2 nathanw le16toh(rx_frame.wi_dat_len) + sizeof(struct ether_header);
409 1.17.2.2 nathanw
410 1.17.2.2 nathanw if (wi_read_data(sc, id, WI_802_3_OFFSET,
411 1.17.2.2 nathanw mtod(m, caddr_t), m->m_len + 2)) {
412 1.17.2.2 nathanw m_freem(m);
413 1.17.2.2 nathanw ifp->if_ierrors++;
414 1.17.2.2 nathanw return;
415 1.17.2.2 nathanw }
416 1.17.2.2 nathanw }
417 1.17.2.2 nathanw
418 1.17.2.2 nathanw ifp->if_ipackets++;
419 1.17.2.2 nathanw
420 1.17.2.2 nathanw #if NBPFILTER > 0
421 1.17.2.2 nathanw /* Handle BPF listeners. */
422 1.17.2.2 nathanw if (ifp->if_bpf)
423 1.17.2.2 nathanw bpf_mtap(ifp->if_bpf, m);
424 1.17.2.2 nathanw #endif
425 1.17.2.2 nathanw
426 1.17.2.2 nathanw /* Receive packet. */
427 1.17.2.2 nathanw (*ifp->if_input)(ifp, m);
428 1.17.2.2 nathanw }
429 1.17.2.2 nathanw
430 1.17.2.2 nathanw static void wi_txeof(sc, status)
431 1.17.2.2 nathanw struct wi_softc *sc;
432 1.17.2.2 nathanw int status;
433 1.17.2.2 nathanw {
434 1.17.2.2 nathanw struct ifnet *ifp = sc->sc_ifp;
435 1.17.2.2 nathanw
436 1.17.2.2 nathanw ifp->if_timer = 0;
437 1.17.2.2 nathanw ifp->if_flags &= ~IFF_OACTIVE;
438 1.17.2.2 nathanw
439 1.17.2.2 nathanw if (status & WI_EV_TX_EXC)
440 1.17.2.2 nathanw ifp->if_oerrors++;
441 1.17.2.2 nathanw else
442 1.17.2.2 nathanw ifp->if_opackets++;
443 1.17.2.2 nathanw
444 1.17.2.2 nathanw return;
445 1.17.2.2 nathanw }
446 1.17.2.2 nathanw
447 1.17.2.7 nathanw void wi_inquire(xsc)
448 1.17.2.2 nathanw void *xsc;
449 1.17.2.2 nathanw {
450 1.17.2.2 nathanw struct wi_softc *sc;
451 1.17.2.2 nathanw struct ifnet *ifp;
452 1.17.2.10 nathanw int s;
453 1.17.2.2 nathanw
454 1.17.2.2 nathanw sc = xsc;
455 1.17.2.2 nathanw ifp = &sc->sc_ethercom.ec_if;
456 1.17.2.2 nathanw
457 1.17.2.2 nathanw if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
458 1.17.2.2 nathanw return;
459 1.17.2.2 nathanw
460 1.17.2.11 nathanw KASSERT(sc->sc_enabled);
461 1.17.2.11 nathanw
462 1.17.2.7 nathanw callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
463 1.17.2.2 nathanw
464 1.17.2.2 nathanw /* Don't do this while we're transmitting */
465 1.17.2.2 nathanw if (ifp->if_flags & IFF_OACTIVE)
466 1.17.2.2 nathanw return;
467 1.17.2.2 nathanw
468 1.17.2.10 nathanw s = splnet();
469 1.17.2.2 nathanw wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS);
470 1.17.2.10 nathanw splx(s);
471 1.17.2.10 nathanw }
472 1.17.2.10 nathanw
473 1.17.2.10 nathanw void wi_wait_scan(xsc)
474 1.17.2.10 nathanw void *xsc;
475 1.17.2.10 nathanw {
476 1.17.2.10 nathanw struct wi_softc *sc;
477 1.17.2.10 nathanw struct ifnet *ifp;
478 1.17.2.10 nathanw int s, result;
479 1.17.2.10 nathanw
480 1.17.2.10 nathanw sc = xsc;
481 1.17.2.10 nathanw ifp = &sc->sc_ethercom.ec_if;
482 1.17.2.10 nathanw
483 1.17.2.10 nathanw /* If not scanning, ignore */
484 1.17.2.10 nathanw if (!sc->wi_scanning)
485 1.17.2.10 nathanw return;
486 1.17.2.10 nathanw
487 1.17.2.10 nathanw s = splnet();
488 1.17.2.10 nathanw
489 1.17.2.10 nathanw /* Wait for sending complete to make INQUIRE */
490 1.17.2.10 nathanw if (ifp->if_flags & IFF_OACTIVE) {
491 1.17.2.10 nathanw callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc);
492 1.17.2.10 nathanw splx(s);
493 1.17.2.10 nathanw return;
494 1.17.2.10 nathanw }
495 1.17.2.10 nathanw
496 1.17.2.10 nathanw /* try INQUIRE */
497 1.17.2.10 nathanw result = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS);
498 1.17.2.10 nathanw if (result == ETIMEDOUT)
499 1.17.2.10 nathanw callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc);
500 1.17.2.10 nathanw
501 1.17.2.10 nathanw splx(s);
502 1.17.2.2 nathanw }
503 1.17.2.2 nathanw
504 1.17.2.2 nathanw void wi_update_stats(sc)
505 1.17.2.2 nathanw struct wi_softc *sc;
506 1.17.2.2 nathanw {
507 1.17.2.2 nathanw struct wi_ltv_gen gen;
508 1.17.2.10 nathanw struct wi_scan_header ap2_header; /* Prism2 header */
509 1.17.2.10 nathanw struct wi_scan_data_p2 ap2; /* Prism2 scantable*/
510 1.17.2.10 nathanw struct wi_scan_data ap; /* Lucent scantable */
511 1.17.2.10 nathanw struct wi_assoc assoc; /* Association Status */
512 1.17.2.2 nathanw u_int16_t id;
513 1.17.2.2 nathanw struct ifnet *ifp;
514 1.17.2.2 nathanw u_int32_t *ptr;
515 1.17.2.10 nathanw int len, naps, i, j;
516 1.17.2.2 nathanw u_int16_t t;
517 1.17.2.2 nathanw
518 1.17.2.2 nathanw ifp = &sc->sc_ethercom.ec_if;
519 1.17.2.2 nathanw
520 1.17.2.2 nathanw id = CSR_READ_2(sc, WI_INFO_FID);
521 1.17.2.2 nathanw
522 1.17.2.11 nathanw if (wi_seek(sc, id, 0, WI_BAP1)) {
523 1.17.2.11 nathanw return;
524 1.17.2.11 nathanw }
525 1.17.2.11 nathanw
526 1.17.2.11 nathanw gen.wi_len = CSR_READ_2(sc, WI_DATA1);
527 1.17.2.11 nathanw gen.wi_type = CSR_READ_2(sc, WI_DATA1);
528 1.17.2.2 nathanw
529 1.17.2.9 nathanw switch (gen.wi_type) {
530 1.17.2.10 nathanw case WI_INFO_SCAN_RESULTS:
531 1.17.2.12 nathanw case WI_INFO_HOST_SCAN_RESULTS:
532 1.17.2.11 nathanw if (gen.wi_len <= 3) {
533 1.17.2.11 nathanw sc->wi_naps = 0;
534 1.17.2.11 nathanw sc->wi_scanning = 0;
535 1.17.2.10 nathanw break;
536 1.17.2.11 nathanw }
537 1.17.2.11 nathanw switch (sc->sc_firmware_type) {
538 1.17.2.11 nathanw case WI_INTERSIL:
539 1.17.2.12 nathanw case WI_SYMBOL:
540 1.17.2.12 nathanw if (sc->sc_firmware_type == WI_INTERSIL) {
541 1.17.2.12 nathanw naps = 2 * (gen.wi_len - 3) / sizeof(ap2);
542 1.17.2.12 nathanw /* Read Header */
543 1.17.2.12 nathanw for(j=0; j < sizeof(ap2_header) / 2; j++)
544 1.17.2.12 nathanw ((u_int16_t *)&ap2_header)[j] =
545 1.17.2.12 nathanw CSR_READ_2(sc, WI_DATA1);
546 1.17.2.12 nathanw } else { /* WI_SYMBOL */
547 1.17.2.12 nathanw naps = 2 * (gen.wi_len - 1) / (sizeof(ap2) + 6);
548 1.17.2.12 nathanw ap2_header.wi_reason = 0;
549 1.17.2.12 nathanw }
550 1.17.2.10 nathanw naps = naps > MAXAPINFO ? MAXAPINFO : naps;
551 1.17.2.10 nathanw sc->wi_naps = naps;
552 1.17.2.10 nathanw /* Read Data */
553 1.17.2.10 nathanw for (i=0; i < naps; i++) {
554 1.17.2.10 nathanw for(j=0; j < sizeof(ap2) / 2; j++)
555 1.17.2.10 nathanw ((u_int16_t *)&ap2)[j] =
556 1.17.2.10 nathanw CSR_READ_2(sc, WI_DATA1);
557 1.17.2.12 nathanw if (sc->sc_firmware_type == WI_SYMBOL) {
558 1.17.2.12 nathanw /* 3 more words */
559 1.17.2.12 nathanw for (j = 0; j < 3; j++)
560 1.17.2.12 nathanw CSR_READ_2(sc, WI_DATA1);
561 1.17.2.12 nathanw }
562 1.17.2.11 nathanw /* unswap 8 bit data fields: */
563 1.17.2.11 nathanw for(j=0;j<sizeof(ap.wi_bssid)/2;j++)
564 1.17.2.11 nathanw LE16TOH(((u_int16_t *)&ap.wi_bssid[0])[j]);
565 1.17.2.11 nathanw for(j=0;j<sizeof(ap.wi_name)/2;j++)
566 1.17.2.11 nathanw LE16TOH(((u_int16_t *)&ap.wi_name[0])[j]);
567 1.17.2.10 nathanw sc->wi_aps[i].scanreason = ap2_header.wi_reason;
568 1.17.2.10 nathanw memcpy(sc->wi_aps[i].bssid, ap2.wi_bssid, 6);
569 1.17.2.10 nathanw sc->wi_aps[i].channel = ap2.wi_chid;
570 1.17.2.10 nathanw sc->wi_aps[i].signal = ap2.wi_signal;
571 1.17.2.10 nathanw sc->wi_aps[i].noise = ap2.wi_noise;
572 1.17.2.10 nathanw sc->wi_aps[i].quality = ap2.wi_signal - ap2.wi_noise;
573 1.17.2.10 nathanw sc->wi_aps[i].capinfo = ap2.wi_capinfo;
574 1.17.2.10 nathanw sc->wi_aps[i].interval = ap2.wi_interval;
575 1.17.2.10 nathanw sc->wi_aps[i].rate = ap2.wi_rate;
576 1.17.2.10 nathanw if (ap2.wi_namelen > 32)
577 1.17.2.10 nathanw ap2.wi_namelen = 32;
578 1.17.2.10 nathanw sc->wi_aps[i].namelen = ap2.wi_namelen;
579 1.17.2.10 nathanw memcpy(sc->wi_aps[i].name, ap2.wi_name,
580 1.17.2.10 nathanw ap2.wi_namelen);
581 1.17.2.10 nathanw }
582 1.17.2.11 nathanw break;
583 1.17.2.11 nathanw
584 1.17.2.11 nathanw case WI_LUCENT:
585 1.17.2.10 nathanw naps = 2 * gen.wi_len / sizeof(ap);
586 1.17.2.10 nathanw naps = naps > MAXAPINFO ? MAXAPINFO : naps;
587 1.17.2.10 nathanw sc->wi_naps = naps;
588 1.17.2.10 nathanw /* Read Data*/
589 1.17.2.10 nathanw for (i=0; i < naps; i++) {
590 1.17.2.10 nathanw for(j=0; j < sizeof(ap) / 2; j++)
591 1.17.2.10 nathanw ((u_int16_t *)&ap)[j] =
592 1.17.2.10 nathanw CSR_READ_2(sc, WI_DATA1);
593 1.17.2.11 nathanw /* unswap 8 bit data fields: */
594 1.17.2.11 nathanw for(j=0;j<sizeof(ap.wi_bssid)/2;j++)
595 1.17.2.11 nathanw HTOLE16(((u_int16_t *)&ap.wi_bssid[0])[j]);
596 1.17.2.11 nathanw for(j=0;j<sizeof(ap.wi_name)/2;j++)
597 1.17.2.11 nathanw HTOLE16(((u_int16_t *)&ap.wi_name[0])[j]);
598 1.17.2.10 nathanw memcpy(sc->wi_aps[i].bssid, ap.wi_bssid, 6);
599 1.17.2.10 nathanw sc->wi_aps[i].channel = ap.wi_chid;
600 1.17.2.10 nathanw sc->wi_aps[i].signal = ap.wi_signal;
601 1.17.2.10 nathanw sc->wi_aps[i].noise = ap.wi_noise;
602 1.17.2.10 nathanw sc->wi_aps[i].quality = ap.wi_signal - ap.wi_noise;
603 1.17.2.10 nathanw sc->wi_aps[i].capinfo = ap.wi_capinfo;
604 1.17.2.10 nathanw sc->wi_aps[i].interval = ap.wi_interval;
605 1.17.2.10 nathanw if (ap.wi_namelen > 32)
606 1.17.2.10 nathanw ap.wi_namelen = 32;
607 1.17.2.10 nathanw sc->wi_aps[i].namelen = ap.wi_namelen;
608 1.17.2.10 nathanw memcpy(sc->wi_aps[i].name, ap.wi_name,
609 1.17.2.10 nathanw ap.wi_namelen);
610 1.17.2.10 nathanw }
611 1.17.2.11 nathanw break;
612 1.17.2.10 nathanw }
613 1.17.2.10 nathanw /* Done scanning */
614 1.17.2.10 nathanw sc->wi_scanning = 0;
615 1.17.2.10 nathanw break;
616 1.17.2.10 nathanw
617 1.17.2.9 nathanw case WI_INFO_COUNTERS:
618 1.17.2.9 nathanw /* some card versions have a larger stats structure */
619 1.17.2.9 nathanw len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ?
620 1.17.2.9 nathanw gen.wi_len - 1 : sizeof(sc->wi_stats) / 4;
621 1.17.2.9 nathanw ptr = (u_int32_t *)&sc->wi_stats;
622 1.17.2.7 nathanw
623 1.17.2.9 nathanw for (i = 0; i < len; i++) {
624 1.17.2.9 nathanw t = CSR_READ_2(sc, WI_DATA1);
625 1.17.2.2 nathanw #ifdef WI_HERMES_STATS_WAR
626 1.17.2.9 nathanw if (t > 0xF000)
627 1.17.2.9 nathanw t = ~t & 0xFFFF;
628 1.17.2.2 nathanw #endif
629 1.17.2.9 nathanw ptr[i] += t;
630 1.17.2.9 nathanw }
631 1.17.2.4 nathanw
632 1.17.2.9 nathanw ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
633 1.17.2.9 nathanw sc->wi_stats.wi_tx_multi_retries +
634 1.17.2.9 nathanw sc->wi_stats.wi_tx_retry_limit;
635 1.17.2.9 nathanw break;
636 1.17.2.6 thorpej
637 1.17.2.9 nathanw case WI_INFO_LINK_STAT: {
638 1.17.2.9 nathanw static char *msg[] = {
639 1.17.2.9 nathanw "connected",
640 1.17.2.9 nathanw "disconnected",
641 1.17.2.9 nathanw "AP change",
642 1.17.2.9 nathanw "AP out of range",
643 1.17.2.10 nathanw "AP in range",
644 1.17.2.11 nathanw "Association Failed"
645 1.17.2.9 nathanw };
646 1.17.2.9 nathanw
647 1.17.2.9 nathanw if (gen.wi_len != 2) {
648 1.17.2.9 nathanw #ifdef WI_DEBUG
649 1.17.2.9 nathanw printf("WI_INFO_LINK_STAT: len=%d\n", gen.wi_len);
650 1.17.2.9 nathanw #endif
651 1.17.2.9 nathanw break;
652 1.17.2.9 nathanw }
653 1.17.2.9 nathanw t = CSR_READ_2(sc, WI_DATA1);
654 1.17.2.10 nathanw if ((t < 1) || (t > 6)) {
655 1.17.2.9 nathanw #ifdef WI_DEBUG
656 1.17.2.9 nathanw printf("WI_INFO_LINK_STAT: status %d\n", t);
657 1.17.2.9 nathanw #endif
658 1.17.2.9 nathanw break;
659 1.17.2.9 nathanw }
660 1.17.2.12 nathanw if (sc->sc_firmware_type == WI_SYMBOL && t == 4) {
661 1.17.2.12 nathanw wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_HOST_SCAN_RESULTS);
662 1.17.2.12 nathanw break;
663 1.17.2.12 nathanw }
664 1.17.2.10 nathanw /*
665 1.17.2.10 nathanw * Some cards issue streams of "connected" messages while
666 1.17.2.10 nathanw * trying to find a peer. Don't bother the user with this
667 1.17.2.10 nathanw * unless he is debugging.
668 1.17.2.10 nathanw */
669 1.17.2.10 nathanw if (ifp->if_flags & IFF_DEBUG)
670 1.17.2.10 nathanw printf("%s: %s\n", sc->sc_dev.dv_xname, msg[t - 1]);
671 1.17.2.9 nathanw break;
672 1.17.2.9 nathanw }
673 1.17.2.9 nathanw
674 1.17.2.10 nathanw case WI_INFO_ASSOC_STAT: {
675 1.17.2.10 nathanw static char *msg[] = {
676 1.17.2.10 nathanw "STA Associated",
677 1.17.2.10 nathanw "STA Reassociated",
678 1.17.2.10 nathanw "STA Disassociated",
679 1.17.2.10 nathanw "Association Failure",
680 1.17.2.11 nathanw "Authentication Failed"
681 1.17.2.10 nathanw };
682 1.17.2.10 nathanw if (gen.wi_len != 10)
683 1.17.2.10 nathanw break;
684 1.17.2.10 nathanw for (i=0; i < gen.wi_len - 1; i++)
685 1.17.2.10 nathanw ((u_int16_t *)&assoc)[i] = CSR_READ_2(sc, WI_DATA1);
686 1.17.2.11 nathanw /* unswap 8 bit data fields: */
687 1.17.2.11 nathanw for(j=0;j<sizeof(assoc.wi_assoc_sta)/2;j++)
688 1.17.2.11 nathanw HTOLE16(((u_int16_t *)&assoc.wi_assoc_sta[0])[j]);
689 1.17.2.11 nathanw for(j=0;j<sizeof(assoc.wi_assoc_osta)/2;j++)
690 1.17.2.11 nathanw HTOLE16(((u_int16_t *)&assoc.wi_assoc_osta[0])[j]);
691 1.17.2.10 nathanw switch (assoc.wi_assoc_stat) {
692 1.17.2.10 nathanw case ASSOC:
693 1.17.2.10 nathanw case DISASSOC:
694 1.17.2.10 nathanw case ASSOCFAIL:
695 1.17.2.10 nathanw case AUTHFAIL:
696 1.17.2.11 nathanw printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x\n",
697 1.17.2.10 nathanw sc->sc_dev.dv_xname,
698 1.17.2.10 nathanw msg[assoc.wi_assoc_stat - 1],
699 1.17.2.10 nathanw assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff,
700 1.17.2.10 nathanw assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff,
701 1.17.2.10 nathanw assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff);
702 1.17.2.10 nathanw break;
703 1.17.2.10 nathanw case REASSOC:
704 1.17.2.11 nathanw printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x, "
705 1.17.2.11 nathanw "OldAP = %02x:%02x:%02x:%02x:%02x:%02x\n",
706 1.17.2.10 nathanw sc->sc_dev.dv_xname, msg[assoc.wi_assoc_stat - 1],
707 1.17.2.10 nathanw assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff,
708 1.17.2.10 nathanw assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff,
709 1.17.2.10 nathanw assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff,
710 1.17.2.10 nathanw assoc.wi_assoc_osta[0]&0xff, assoc.wi_assoc_osta[1]&0xff,
711 1.17.2.10 nathanw assoc.wi_assoc_osta[2]&0xff, assoc.wi_assoc_osta[3]&0xff,
712 1.17.2.10 nathanw assoc.wi_assoc_osta[4]&0xff, assoc.wi_assoc_osta[5]&0xff);
713 1.17.2.10 nathanw break;
714 1.17.2.10 nathanw }
715 1.17.2.10 nathanw }
716 1.17.2.12 nathanw
717 1.17.2.9 nathanw default:
718 1.17.2.10 nathanw #ifdef WI_DEBUG
719 1.17.2.10 nathanw printf("%s: got info type: 0x%04x len=0x%04x\n",
720 1.17.2.10 nathanw sc->sc_dev.dv_xname, gen.wi_type,gen.wi_len);
721 1.17.2.9 nathanw #endif
722 1.17.2.10 nathanw #if 0
723 1.17.2.9 nathanw for (i = 0; i < gen.wi_len; i++) {
724 1.17.2.9 nathanw t = CSR_READ_2(sc, WI_DATA1);
725 1.17.2.9 nathanw printf("[0x%02x] = 0x%04x\n", i, t);
726 1.17.2.9 nathanw }
727 1.17.2.10 nathanw #endif
728 1.17.2.9 nathanw break;
729 1.17.2.9 nathanw }
730 1.17.2.2 nathanw }
731 1.17.2.2 nathanw
732 1.17.2.2 nathanw int wi_intr(arg)
733 1.17.2.2 nathanw void *arg;
734 1.17.2.2 nathanw {
735 1.17.2.2 nathanw struct wi_softc *sc = arg;
736 1.17.2.2 nathanw struct ifnet *ifp;
737 1.17.2.2 nathanw u_int16_t status;
738 1.17.2.2 nathanw
739 1.17.2.2 nathanw if (sc->sc_enabled == 0 ||
740 1.17.2.2 nathanw (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
741 1.17.2.2 nathanw (sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0)
742 1.17.2.2 nathanw return (0);
743 1.17.2.2 nathanw
744 1.17.2.2 nathanw ifp = &sc->sc_ethercom.ec_if;
745 1.17.2.2 nathanw
746 1.17.2.2 nathanw if (!(ifp->if_flags & IFF_UP)) {
747 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
748 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_INT_EN, 0);
749 1.17.2.2 nathanw return 1;
750 1.17.2.2 nathanw }
751 1.17.2.2 nathanw
752 1.17.2.2 nathanw /* Disable interrupts. */
753 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_INT_EN, 0);
754 1.17.2.2 nathanw
755 1.17.2.2 nathanw status = CSR_READ_2(sc, WI_EVENT_STAT);
756 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS);
757 1.17.2.2 nathanw
758 1.17.2.2 nathanw if (status & WI_EV_RX) {
759 1.17.2.2 nathanw wi_rxeof(sc);
760 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
761 1.17.2.2 nathanw }
762 1.17.2.2 nathanw
763 1.17.2.2 nathanw if (status & WI_EV_TX) {
764 1.17.2.2 nathanw wi_txeof(sc, status);
765 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
766 1.17.2.2 nathanw }
767 1.17.2.2 nathanw
768 1.17.2.2 nathanw if (status & WI_EV_ALLOC) {
769 1.17.2.2 nathanw int id;
770 1.17.2.2 nathanw id = CSR_READ_2(sc, WI_ALLOC_FID);
771 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
772 1.17.2.2 nathanw if (id == sc->wi_tx_data_id)
773 1.17.2.2 nathanw wi_txeof(sc, status);
774 1.17.2.2 nathanw }
775 1.17.2.2 nathanw
776 1.17.2.2 nathanw if (status & WI_EV_INFO) {
777 1.17.2.2 nathanw wi_update_stats(sc);
778 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
779 1.17.2.2 nathanw }
780 1.17.2.2 nathanw
781 1.17.2.2 nathanw if (status & WI_EV_TX_EXC) {
782 1.17.2.2 nathanw wi_txeof(sc, status);
783 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
784 1.17.2.2 nathanw }
785 1.17.2.2 nathanw
786 1.17.2.2 nathanw if (status & WI_EV_INFO_DROP) {
787 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP);
788 1.17.2.2 nathanw }
789 1.17.2.2 nathanw
790 1.17.2.2 nathanw /* Re-enable interrupts. */
791 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
792 1.17.2.2 nathanw
793 1.17.2.2 nathanw if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
794 1.17.2.2 nathanw wi_start(ifp);
795 1.17.2.2 nathanw
796 1.17.2.2 nathanw return 1;
797 1.17.2.2 nathanw }
798 1.17.2.2 nathanw
799 1.17.2.10 nathanw /* Must be called at proper protection level! */
800 1.17.2.2 nathanw static int
801 1.17.2.2 nathanw wi_cmd(sc, cmd, val)
802 1.17.2.2 nathanw struct wi_softc *sc;
803 1.17.2.2 nathanw int cmd;
804 1.17.2.2 nathanw int val;
805 1.17.2.2 nathanw {
806 1.17.2.2 nathanw int i, s = 0;
807 1.17.2.2 nathanw
808 1.17.2.2 nathanw /* wait for the busy bit to clear */
809 1.17.2.2 nathanw for (i = 0; i < WI_TIMEOUT; i++) {
810 1.17.2.2 nathanw if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
811 1.17.2.2 nathanw break;
812 1.17.2.2 nathanw }
813 1.17.2.2 nathanw
814 1.17.2.10 nathanw if (i == WI_TIMEOUT) {
815 1.17.2.10 nathanw printf("%s: wi_cmd: BUSY did not clear, cmd=0x%x\n",
816 1.17.2.10 nathanw sc->sc_dev.dv_xname, cmd);
817 1.17.2.10 nathanw return EIO;
818 1.17.2.10 nathanw }
819 1.17.2.10 nathanw
820 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_PARAM0, val);
821 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_PARAM1, 0);
822 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_PARAM2, 0);
823 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_COMMAND, cmd);
824 1.17.2.2 nathanw
825 1.17.2.2 nathanw /* wait for the cmd completed bit */
826 1.17.2.2 nathanw for (i = 0; i < WI_TIMEOUT; i++) {
827 1.17.2.2 nathanw if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
828 1.17.2.2 nathanw break;
829 1.17.2.2 nathanw DELAY(1);
830 1.17.2.2 nathanw }
831 1.17.2.2 nathanw
832 1.17.2.2 nathanw /* Ack the command */
833 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
834 1.17.2.2 nathanw
835 1.17.2.2 nathanw s = CSR_READ_2(sc, WI_STATUS);
836 1.17.2.2 nathanw if (s & WI_STAT_CMD_RESULT)
837 1.17.2.2 nathanw return(EIO);
838 1.17.2.2 nathanw
839 1.17.2.10 nathanw if (i == WI_TIMEOUT) {
840 1.17.2.10 nathanw if (!sc->wi_scanning)
841 1.17.2.10 nathanw printf("%s: command timed out, cmd=0x%x\n",
842 1.17.2.10 nathanw sc->sc_dev.dv_xname, cmd);
843 1.17.2.2 nathanw return(ETIMEDOUT);
844 1.17.2.10 nathanw }
845 1.17.2.2 nathanw
846 1.17.2.2 nathanw return(0);
847 1.17.2.2 nathanw }
848 1.17.2.2 nathanw
849 1.17.2.2 nathanw static void
850 1.17.2.2 nathanw wi_reset(sc)
851 1.17.2.2 nathanw struct wi_softc *sc;
852 1.17.2.2 nathanw {
853 1.17.2.11 nathanw
854 1.17.2.2 nathanw DELAY(100*1000); /* 100 m sec */
855 1.17.2.2 nathanw if (wi_cmd(sc, WI_CMD_INI, 0))
856 1.17.2.2 nathanw printf("%s: init failed\n", sc->sc_dev.dv_xname);
857 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_INT_EN, 0);
858 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
859 1.17.2.2 nathanw
860 1.17.2.2 nathanw /* Calibrate timer. */
861 1.17.2.2 nathanw WI_SETVAL(WI_RID_TICK_TIME, 8);
862 1.17.2.2 nathanw
863 1.17.2.2 nathanw return;
864 1.17.2.2 nathanw }
865 1.17.2.2 nathanw
866 1.17.2.2 nathanw /*
867 1.17.2.2 nathanw * Read an LTV record from the NIC.
868 1.17.2.2 nathanw */
869 1.17.2.2 nathanw static int wi_read_record(sc, ltv)
870 1.17.2.2 nathanw struct wi_softc *sc;
871 1.17.2.2 nathanw struct wi_ltv_gen *ltv;
872 1.17.2.2 nathanw {
873 1.17.2.2 nathanw u_int16_t *ptr;
874 1.17.2.2 nathanw int len, code;
875 1.17.2.2 nathanw struct wi_ltv_gen *oltv, p2ltv;
876 1.17.2.2 nathanw
877 1.17.2.11 nathanw if (sc->sc_firmware_type != WI_LUCENT) {
878 1.17.2.2 nathanw oltv = ltv;
879 1.17.2.2 nathanw switch (ltv->wi_type) {
880 1.17.2.2 nathanw case WI_RID_ENCRYPTION:
881 1.17.2.2 nathanw p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
882 1.17.2.2 nathanw p2ltv.wi_len = 2;
883 1.17.2.2 nathanw ltv = &p2ltv;
884 1.17.2.2 nathanw break;
885 1.17.2.2 nathanw case WI_RID_TX_CRYPT_KEY:
886 1.17.2.2 nathanw p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
887 1.17.2.2 nathanw p2ltv.wi_len = 2;
888 1.17.2.2 nathanw ltv = &p2ltv;
889 1.17.2.2 nathanw break;
890 1.17.2.12 nathanw case WI_RID_ROAMING_MODE:
891 1.17.2.12 nathanw if (sc->sc_firmware_type == WI_INTERSIL)
892 1.17.2.12 nathanw break;
893 1.17.2.12 nathanw /* not supported */
894 1.17.2.12 nathanw ltv->wi_len = 1;
895 1.17.2.12 nathanw return 0;
896 1.17.2.12 nathanw case WI_RID_MICROWAVE_OVEN:
897 1.17.2.12 nathanw /* not supported */
898 1.17.2.12 nathanw ltv->wi_len = 1;
899 1.17.2.12 nathanw return 0;
900 1.17.2.2 nathanw }
901 1.17.2.2 nathanw }
902 1.17.2.2 nathanw
903 1.17.2.2 nathanw /* Tell the NIC to enter record read mode. */
904 1.17.2.2 nathanw if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type))
905 1.17.2.2 nathanw return(EIO);
906 1.17.2.2 nathanw
907 1.17.2.2 nathanw /* Seek to the record. */
908 1.17.2.2 nathanw if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
909 1.17.2.2 nathanw return(EIO);
910 1.17.2.2 nathanw
911 1.17.2.2 nathanw /*
912 1.17.2.2 nathanw * Read the length and record type and make sure they
913 1.17.2.2 nathanw * match what we expect (this verifies that we have enough
914 1.17.2.2 nathanw * room to hold all of the returned data).
915 1.17.2.2 nathanw */
916 1.17.2.2 nathanw len = CSR_READ_2(sc, WI_DATA1);
917 1.17.2.2 nathanw if (len > ltv->wi_len)
918 1.17.2.2 nathanw return(ENOSPC);
919 1.17.2.2 nathanw code = CSR_READ_2(sc, WI_DATA1);
920 1.17.2.2 nathanw if (code != ltv->wi_type)
921 1.17.2.2 nathanw return(EIO);
922 1.17.2.2 nathanw
923 1.17.2.2 nathanw ltv->wi_len = len;
924 1.17.2.2 nathanw ltv->wi_type = code;
925 1.17.2.2 nathanw
926 1.17.2.2 nathanw /* Now read the data. */
927 1.17.2.2 nathanw ptr = <v->wi_val;
928 1.17.2.2 nathanw if (ltv->wi_len > 1)
929 1.17.2.2 nathanw CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1);
930 1.17.2.2 nathanw
931 1.17.2.11 nathanw if (sc->sc_firmware_type != WI_LUCENT) {
932 1.17.2.2 nathanw int v;
933 1.17.2.2 nathanw
934 1.17.2.2 nathanw switch (oltv->wi_type) {
935 1.17.2.2 nathanw case WI_RID_TX_RATE:
936 1.17.2.2 nathanw case WI_RID_CUR_TX_RATE:
937 1.17.2.2 nathanw switch (le16toh(ltv->wi_val)) {
938 1.17.2.2 nathanw case 1: v = 1; break;
939 1.17.2.2 nathanw case 2: v = 2; break;
940 1.17.2.2 nathanw case 3: v = 6; break;
941 1.17.2.2 nathanw case 4: v = 5; break;
942 1.17.2.2 nathanw case 7: v = 7; break;
943 1.17.2.2 nathanw case 8: v = 11; break;
944 1.17.2.2 nathanw case 15: v = 3; break;
945 1.17.2.2 nathanw default: v = 0x100 + le16toh(ltv->wi_val); break;
946 1.17.2.2 nathanw }
947 1.17.2.2 nathanw oltv->wi_val = htole16(v);
948 1.17.2.2 nathanw break;
949 1.17.2.2 nathanw case WI_RID_ENCRYPTION:
950 1.17.2.2 nathanw oltv->wi_len = 2;
951 1.17.2.2 nathanw if (le16toh(ltv->wi_val) & 0x01)
952 1.17.2.2 nathanw oltv->wi_val = htole16(1);
953 1.17.2.2 nathanw else
954 1.17.2.2 nathanw oltv->wi_val = htole16(0);
955 1.17.2.2 nathanw break;
956 1.17.2.2 nathanw case WI_RID_TX_CRYPT_KEY:
957 1.17.2.2 nathanw oltv->wi_len = 2;
958 1.17.2.2 nathanw oltv->wi_val = ltv->wi_val;
959 1.17.2.2 nathanw break;
960 1.17.2.2 nathanw case WI_RID_AUTH_CNTL:
961 1.17.2.2 nathanw oltv->wi_len = 2;
962 1.17.2.2 nathanw if (le16toh(ltv->wi_val) & 0x01)
963 1.17.2.2 nathanw oltv->wi_val = htole16(1);
964 1.17.2.2 nathanw else if (le16toh(ltv->wi_val) & 0x02)
965 1.17.2.2 nathanw oltv->wi_val = htole16(2);
966 1.17.2.2 nathanw break;
967 1.17.2.2 nathanw }
968 1.17.2.2 nathanw }
969 1.17.2.2 nathanw
970 1.17.2.2 nathanw return(0);
971 1.17.2.2 nathanw }
972 1.17.2.2 nathanw
973 1.17.2.2 nathanw /*
974 1.17.2.2 nathanw * Same as read, except we inject data instead of reading it.
975 1.17.2.2 nathanw */
976 1.17.2.2 nathanw static int wi_write_record(sc, ltv)
977 1.17.2.2 nathanw struct wi_softc *sc;
978 1.17.2.2 nathanw struct wi_ltv_gen *ltv;
979 1.17.2.2 nathanw {
980 1.17.2.2 nathanw u_int16_t *ptr;
981 1.17.2.2 nathanw int i;
982 1.17.2.2 nathanw struct wi_ltv_gen p2ltv;
983 1.17.2.2 nathanw
984 1.17.2.11 nathanw if (sc->sc_firmware_type != WI_LUCENT) {
985 1.17.2.2 nathanw int v;
986 1.17.2.2 nathanw
987 1.17.2.2 nathanw switch (ltv->wi_type) {
988 1.17.2.2 nathanw case WI_RID_TX_RATE:
989 1.17.2.2 nathanw p2ltv.wi_type = WI_RID_TX_RATE;
990 1.17.2.2 nathanw p2ltv.wi_len = 2;
991 1.17.2.2 nathanw switch (le16toh(ltv->wi_val)) {
992 1.17.2.2 nathanw case 1: v = 1; break;
993 1.17.2.2 nathanw case 2: v = 2; break;
994 1.17.2.2 nathanw case 3: v = 15; break;
995 1.17.2.2 nathanw case 5: v = 4; break;
996 1.17.2.2 nathanw case 6: v = 3; break;
997 1.17.2.2 nathanw case 7: v = 7; break;
998 1.17.2.2 nathanw case 11: v = 8; break;
999 1.17.2.2 nathanw default: return EINVAL;
1000 1.17.2.2 nathanw }
1001 1.17.2.2 nathanw p2ltv.wi_val = htole16(v);
1002 1.17.2.2 nathanw ltv = &p2ltv;
1003 1.17.2.2 nathanw break;
1004 1.17.2.2 nathanw case WI_RID_ENCRYPTION:
1005 1.17.2.2 nathanw p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
1006 1.17.2.2 nathanw p2ltv.wi_len = 2;
1007 1.17.2.2 nathanw if (le16toh(ltv->wi_val))
1008 1.17.2.12 nathanw p2ltv.wi_val = htole16(PRIVACY_INVOKED |
1009 1.17.2.12 nathanw EXCLUDE_UNENCRYPTED);
1010 1.17.2.2 nathanw else
1011 1.17.2.12 nathanw p2ltv.wi_val =
1012 1.17.2.12 nathanw htole16(HOST_ENCRYPT | HOST_DECRYPT);
1013 1.17.2.2 nathanw ltv = &p2ltv;
1014 1.17.2.2 nathanw break;
1015 1.17.2.2 nathanw case WI_RID_TX_CRYPT_KEY:
1016 1.17.2.2 nathanw p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
1017 1.17.2.2 nathanw p2ltv.wi_len = 2;
1018 1.17.2.2 nathanw p2ltv.wi_val = ltv->wi_val;
1019 1.17.2.2 nathanw ltv = &p2ltv;
1020 1.17.2.2 nathanw break;
1021 1.17.2.2 nathanw case WI_RID_DEFLT_CRYPT_KEYS:
1022 1.17.2.2 nathanw {
1023 1.17.2.2 nathanw int error;
1024 1.17.2.11 nathanw int keylen;
1025 1.17.2.2 nathanw struct wi_ltv_str ws;
1026 1.17.2.2 nathanw struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv;
1027 1.17.2.11 nathanw
1028 1.17.2.11 nathanw keylen = wk->wi_keys[sc->wi_tx_key].wi_keylen;
1029 1.17.2.11 nathanw
1030 1.17.2.2 nathanw for (i = 0; i < 4; i++) {
1031 1.17.2.10 nathanw memset(&ws, 0, sizeof(ws));
1032 1.17.2.11 nathanw ws.wi_len = (keylen > 5) ? 8 : 4;
1033 1.17.2.2 nathanw ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
1034 1.17.2.11 nathanw memcpy(ws.wi_str,
1035 1.17.2.11 nathanw &wk->wi_keys[i].wi_keydat, keylen);
1036 1.17.2.11 nathanw error = wi_write_record(sc,
1037 1.17.2.11 nathanw (struct wi_ltv_gen *)&ws);
1038 1.17.2.11 nathanw if (error)
1039 1.17.2.2 nathanw return error;
1040 1.17.2.2 nathanw }
1041 1.17.2.2 nathanw return 0;
1042 1.17.2.2 nathanw }
1043 1.17.2.2 nathanw case WI_RID_AUTH_CNTL:
1044 1.17.2.2 nathanw p2ltv.wi_type = WI_RID_AUTH_CNTL;
1045 1.17.2.2 nathanw p2ltv.wi_len = 2;
1046 1.17.2.2 nathanw if (le16toh(ltv->wi_val) == 1)
1047 1.17.2.2 nathanw p2ltv.wi_val = htole16(0x01);
1048 1.17.2.2 nathanw else if (le16toh(ltv->wi_val) == 2)
1049 1.17.2.2 nathanw p2ltv.wi_val = htole16(0x02);
1050 1.17.2.2 nathanw ltv = &p2ltv;
1051 1.17.2.2 nathanw break;
1052 1.17.2.12 nathanw
1053 1.17.2.12 nathanw case WI_RID_ROAMING_MODE:
1054 1.17.2.12 nathanw if (sc->sc_firmware_type == WI_INTERSIL)
1055 1.17.2.12 nathanw break;
1056 1.17.2.12 nathanw /* not supported */
1057 1.17.2.12 nathanw return 0;
1058 1.17.2.12 nathanw
1059 1.17.2.12 nathanw case WI_RID_MICROWAVE_OVEN:
1060 1.17.2.12 nathanw /* not supported */
1061 1.17.2.12 nathanw return 0;
1062 1.17.2.2 nathanw }
1063 1.17.2.2 nathanw }
1064 1.17.2.2 nathanw
1065 1.17.2.2 nathanw if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
1066 1.17.2.2 nathanw return(EIO);
1067 1.17.2.2 nathanw
1068 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len);
1069 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type);
1070 1.17.2.2 nathanw
1071 1.17.2.2 nathanw /* Write data */
1072 1.17.2.2 nathanw ptr = <v->wi_val;
1073 1.17.2.2 nathanw if (ltv->wi_len > 1)
1074 1.17.2.2 nathanw CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1);
1075 1.17.2.2 nathanw
1076 1.17.2.2 nathanw if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type))
1077 1.17.2.2 nathanw return(EIO);
1078 1.17.2.2 nathanw
1079 1.17.2.2 nathanw return(0);
1080 1.17.2.2 nathanw }
1081 1.17.2.2 nathanw
1082 1.17.2.2 nathanw static int wi_seek(sc, id, off, chan)
1083 1.17.2.2 nathanw struct wi_softc *sc;
1084 1.17.2.2 nathanw int id, off, chan;
1085 1.17.2.2 nathanw {
1086 1.17.2.2 nathanw int i;
1087 1.17.2.2 nathanw int selreg, offreg;
1088 1.17.2.2 nathanw int status;
1089 1.17.2.2 nathanw
1090 1.17.2.2 nathanw switch (chan) {
1091 1.17.2.2 nathanw case WI_BAP0:
1092 1.17.2.2 nathanw selreg = WI_SEL0;
1093 1.17.2.2 nathanw offreg = WI_OFF0;
1094 1.17.2.2 nathanw break;
1095 1.17.2.2 nathanw case WI_BAP1:
1096 1.17.2.2 nathanw selreg = WI_SEL1;
1097 1.17.2.2 nathanw offreg = WI_OFF1;
1098 1.17.2.2 nathanw break;
1099 1.17.2.2 nathanw default:
1100 1.17.2.2 nathanw printf("%s: invalid data path: %x\n",
1101 1.17.2.2 nathanw sc->sc_dev.dv_xname, chan);
1102 1.17.2.2 nathanw return(EIO);
1103 1.17.2.2 nathanw }
1104 1.17.2.2 nathanw
1105 1.17.2.2 nathanw CSR_WRITE_2(sc, selreg, id);
1106 1.17.2.2 nathanw CSR_WRITE_2(sc, offreg, off);
1107 1.17.2.2 nathanw
1108 1.17.2.2 nathanw for (i = 0; i < WI_TIMEOUT; i++) {
1109 1.17.2.2 nathanw status = CSR_READ_2(sc, offreg);
1110 1.17.2.2 nathanw if (!(status & (WI_OFF_BUSY|WI_OFF_ERR)))
1111 1.17.2.2 nathanw break;
1112 1.17.2.2 nathanw }
1113 1.17.2.2 nathanw
1114 1.17.2.2 nathanw if (i == WI_TIMEOUT) {
1115 1.17.2.2 nathanw printf("%s: timeout in wi_seek to %x/%x; last status %x\n",
1116 1.17.2.2 nathanw sc->sc_dev.dv_xname, id, off, status);
1117 1.17.2.2 nathanw return(ETIMEDOUT);
1118 1.17.2.2 nathanw }
1119 1.17.2.2 nathanw return(0);
1120 1.17.2.2 nathanw }
1121 1.17.2.2 nathanw
1122 1.17.2.2 nathanw static int wi_read_data(sc, id, off, buf, len)
1123 1.17.2.2 nathanw struct wi_softc *sc;
1124 1.17.2.2 nathanw int id, off;
1125 1.17.2.2 nathanw caddr_t buf;
1126 1.17.2.2 nathanw int len;
1127 1.17.2.2 nathanw {
1128 1.17.2.2 nathanw u_int16_t *ptr;
1129 1.17.2.2 nathanw
1130 1.17.2.2 nathanw if (wi_seek(sc, id, off, WI_BAP1))
1131 1.17.2.2 nathanw return(EIO);
1132 1.17.2.2 nathanw
1133 1.17.2.2 nathanw ptr = (u_int16_t *)buf;
1134 1.17.2.2 nathanw CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, len / 2);
1135 1.17.2.2 nathanw
1136 1.17.2.2 nathanw return(0);
1137 1.17.2.2 nathanw }
1138 1.17.2.2 nathanw
1139 1.17.2.2 nathanw /*
1140 1.17.2.2 nathanw * According to the comments in the HCF Light code, there is a bug in
1141 1.17.2.2 nathanw * the Hermes (or possibly in certain Hermes firmware revisions) where
1142 1.17.2.2 nathanw * the chip's internal autoincrement counter gets thrown off during
1143 1.17.2.2 nathanw * data writes: the autoincrement is missed, causing one data word to
1144 1.17.2.2 nathanw * be overwritten and subsequent words to be written to the wrong memory
1145 1.17.2.2 nathanw * locations. The end result is that we could end up transmitting bogus
1146 1.17.2.2 nathanw * frames without realizing it. The workaround for this is to write a
1147 1.17.2.2 nathanw * couple of extra guard words after the end of the transfer, then
1148 1.17.2.2 nathanw * attempt to read then back. If we fail to locate the guard words where
1149 1.17.2.2 nathanw * we expect them, we preform the transfer over again.
1150 1.17.2.2 nathanw */
1151 1.17.2.2 nathanw static int wi_write_data(sc, id, off, buf, len)
1152 1.17.2.2 nathanw struct wi_softc *sc;
1153 1.17.2.2 nathanw int id, off;
1154 1.17.2.2 nathanw caddr_t buf;
1155 1.17.2.2 nathanw int len;
1156 1.17.2.2 nathanw {
1157 1.17.2.2 nathanw u_int16_t *ptr;
1158 1.17.2.2 nathanw
1159 1.17.2.2 nathanw #ifdef WI_HERMES_AUTOINC_WAR
1160 1.17.2.2 nathanw again:
1161 1.17.2.2 nathanw #endif
1162 1.17.2.2 nathanw
1163 1.17.2.2 nathanw if (wi_seek(sc, id, off, WI_BAP0))
1164 1.17.2.2 nathanw return(EIO);
1165 1.17.2.2 nathanw
1166 1.17.2.2 nathanw ptr = (u_int16_t *)buf;
1167 1.17.2.2 nathanw CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, ptr, len / 2);
1168 1.17.2.2 nathanw
1169 1.17.2.2 nathanw #ifdef WI_HERMES_AUTOINC_WAR
1170 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_DATA0, 0x1234);
1171 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_DATA0, 0x5678);
1172 1.17.2.2 nathanw
1173 1.17.2.2 nathanw if (wi_seek(sc, id, off + len, WI_BAP0))
1174 1.17.2.2 nathanw return(EIO);
1175 1.17.2.2 nathanw
1176 1.17.2.2 nathanw if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
1177 1.17.2.2 nathanw CSR_READ_2(sc, WI_DATA0) != 0x5678)
1178 1.17.2.2 nathanw goto again;
1179 1.17.2.2 nathanw #endif
1180 1.17.2.2 nathanw
1181 1.17.2.2 nathanw return(0);
1182 1.17.2.2 nathanw }
1183 1.17.2.2 nathanw
1184 1.17.2.2 nathanw /*
1185 1.17.2.2 nathanw * Allocate a region of memory inside the NIC and zero
1186 1.17.2.2 nathanw * it out.
1187 1.17.2.2 nathanw */
1188 1.17.2.2 nathanw static int wi_alloc_nicmem(sc, len, id)
1189 1.17.2.2 nathanw struct wi_softc *sc;
1190 1.17.2.2 nathanw int len;
1191 1.17.2.2 nathanw int *id;
1192 1.17.2.2 nathanw {
1193 1.17.2.2 nathanw int i;
1194 1.17.2.2 nathanw
1195 1.17.2.2 nathanw if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len)) {
1196 1.17.2.2 nathanw printf("%s: failed to allocate %d bytes on NIC\n",
1197 1.17.2.2 nathanw sc->sc_dev.dv_xname, len);
1198 1.17.2.2 nathanw return(ENOMEM);
1199 1.17.2.2 nathanw }
1200 1.17.2.2 nathanw
1201 1.17.2.2 nathanw for (i = 0; i < WI_TIMEOUT; i++) {
1202 1.17.2.2 nathanw if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
1203 1.17.2.2 nathanw break;
1204 1.17.2.2 nathanw }
1205 1.17.2.2 nathanw
1206 1.17.2.2 nathanw if (i == WI_TIMEOUT) {
1207 1.17.2.2 nathanw printf("%s: TIMED OUT in alloc\n", sc->sc_dev.dv_xname);
1208 1.17.2.2 nathanw return(ETIMEDOUT);
1209 1.17.2.2 nathanw }
1210 1.17.2.2 nathanw
1211 1.17.2.2 nathanw *id = CSR_READ_2(sc, WI_ALLOC_FID);
1212 1.17.2.11 nathanw CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
1213 1.17.2.2 nathanw
1214 1.17.2.2 nathanw if (wi_seek(sc, *id, 0, WI_BAP0)) {
1215 1.17.2.2 nathanw printf("%s: seek failed in alloc\n", sc->sc_dev.dv_xname);
1216 1.17.2.2 nathanw return(EIO);
1217 1.17.2.2 nathanw }
1218 1.17.2.2 nathanw
1219 1.17.2.2 nathanw for (i = 0; i < len / 2; i++)
1220 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_DATA0, 0);
1221 1.17.2.2 nathanw
1222 1.17.2.2 nathanw return(0);
1223 1.17.2.2 nathanw }
1224 1.17.2.2 nathanw
1225 1.17.2.2 nathanw static void wi_setmulti(sc)
1226 1.17.2.2 nathanw struct wi_softc *sc;
1227 1.17.2.2 nathanw {
1228 1.17.2.2 nathanw struct ifnet *ifp;
1229 1.17.2.2 nathanw int i = 0;
1230 1.17.2.2 nathanw struct wi_ltv_mcast mcast;
1231 1.17.2.2 nathanw struct ether_multi *enm;
1232 1.17.2.2 nathanw struct ether_multistep estep;
1233 1.17.2.2 nathanw struct ethercom *ec = &sc->sc_ethercom;
1234 1.17.2.2 nathanw
1235 1.17.2.2 nathanw ifp = &sc->sc_ethercom.ec_if;
1236 1.17.2.2 nathanw
1237 1.17.2.2 nathanw if ((ifp->if_flags & IFF_PROMISC) != 0) {
1238 1.17.2.2 nathanw allmulti:
1239 1.17.2.2 nathanw ifp->if_flags |= IFF_ALLMULTI;
1240 1.17.2.3 nathanw memset((char *)&mcast, 0, sizeof(mcast));
1241 1.17.2.8 nathanw mcast.wi_type = WI_RID_MCAST_LIST;
1242 1.17.2.2 nathanw mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1;
1243 1.17.2.2 nathanw
1244 1.17.2.2 nathanw wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
1245 1.17.2.2 nathanw return;
1246 1.17.2.2 nathanw }
1247 1.17.2.2 nathanw
1248 1.17.2.2 nathanw i = 0;
1249 1.17.2.2 nathanw ETHER_FIRST_MULTI(estep, ec, enm);
1250 1.17.2.2 nathanw while (enm != NULL) {
1251 1.17.2.2 nathanw /* Punt on ranges or too many multicast addresses. */
1252 1.17.2.3 nathanw if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
1253 1.17.2.2 nathanw ETHER_ADDR_LEN) != 0 ||
1254 1.17.2.2 nathanw i >= 16)
1255 1.17.2.2 nathanw goto allmulti;
1256 1.17.2.2 nathanw
1257 1.17.2.3 nathanw memcpy((char *)&mcast.wi_mcast[i], enm->enm_addrlo,
1258 1.17.2.3 nathanw ETHER_ADDR_LEN);
1259 1.17.2.2 nathanw i++;
1260 1.17.2.2 nathanw ETHER_NEXT_MULTI(estep, enm);
1261 1.17.2.2 nathanw }
1262 1.17.2.2 nathanw
1263 1.17.2.2 nathanw ifp->if_flags &= ~IFF_ALLMULTI;
1264 1.17.2.8 nathanw mcast.wi_type = WI_RID_MCAST_LIST;
1265 1.17.2.2 nathanw mcast.wi_len = ((ETHER_ADDR_LEN / 2) * i) + 1;
1266 1.17.2.2 nathanw wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
1267 1.17.2.2 nathanw }
1268 1.17.2.2 nathanw
1269 1.17.2.2 nathanw static int
1270 1.17.2.2 nathanw wi_setdef(sc, wreq)
1271 1.17.2.2 nathanw struct wi_softc *sc;
1272 1.17.2.2 nathanw struct wi_req *wreq;
1273 1.17.2.2 nathanw {
1274 1.17.2.2 nathanw struct sockaddr_dl *sdl;
1275 1.17.2.2 nathanw struct ifnet *ifp;
1276 1.17.2.2 nathanw int error = 0;
1277 1.17.2.2 nathanw
1278 1.17.2.2 nathanw ifp = &sc->sc_ethercom.ec_if;
1279 1.17.2.2 nathanw
1280 1.17.2.2 nathanw switch(wreq->wi_type) {
1281 1.17.2.2 nathanw case WI_RID_MAC_NODE:
1282 1.17.2.2 nathanw sdl = (struct sockaddr_dl *)ifp->if_sadl;
1283 1.17.2.3 nathanw memcpy((char *)&sc->sc_macaddr, (char *)&wreq->wi_val,
1284 1.17.2.2 nathanw ETHER_ADDR_LEN);
1285 1.17.2.3 nathanw memcpy(LLADDR(sdl), (char *)&wreq->wi_val, ETHER_ADDR_LEN);
1286 1.17.2.2 nathanw break;
1287 1.17.2.2 nathanw case WI_RID_PORTTYPE:
1288 1.17.2.2 nathanw error = wi_sync_media(sc, le16toh(wreq->wi_val[0]), sc->wi_tx_rate);
1289 1.17.2.2 nathanw break;
1290 1.17.2.2 nathanw case WI_RID_TX_RATE:
1291 1.17.2.2 nathanw error = wi_sync_media(sc, sc->wi_ptype, le16toh(wreq->wi_val[0]));
1292 1.17.2.2 nathanw break;
1293 1.17.2.2 nathanw case WI_RID_MAX_DATALEN:
1294 1.17.2.2 nathanw sc->wi_max_data_len = le16toh(wreq->wi_val[0]);
1295 1.17.2.2 nathanw break;
1296 1.17.2.2 nathanw case WI_RID_RTS_THRESH:
1297 1.17.2.2 nathanw sc->wi_rts_thresh = le16toh(wreq->wi_val[0]);
1298 1.17.2.2 nathanw break;
1299 1.17.2.2 nathanw case WI_RID_SYSTEM_SCALE:
1300 1.17.2.2 nathanw sc->wi_ap_density = le16toh(wreq->wi_val[0]);
1301 1.17.2.2 nathanw break;
1302 1.17.2.2 nathanw case WI_RID_CREATE_IBSS:
1303 1.17.2.12 nathanw if (sc->sc_firmware_type != WI_INTERSIL)
1304 1.17.2.12 nathanw sc->wi_create_ibss = le16toh(wreq->wi_val[0]);
1305 1.17.2.2 nathanw break;
1306 1.17.2.2 nathanw case WI_RID_OWN_CHNL:
1307 1.17.2.2 nathanw sc->wi_channel = le16toh(wreq->wi_val[0]);
1308 1.17.2.2 nathanw break;
1309 1.17.2.2 nathanw case WI_RID_NODENAME:
1310 1.17.2.2 nathanw error = wi_set_ssid(&sc->wi_nodeid,
1311 1.17.2.2 nathanw (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
1312 1.17.2.2 nathanw break;
1313 1.17.2.2 nathanw case WI_RID_DESIRED_SSID:
1314 1.17.2.2 nathanw error = wi_set_ssid(&sc->wi_netid,
1315 1.17.2.2 nathanw (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
1316 1.17.2.2 nathanw break;
1317 1.17.2.2 nathanw case WI_RID_OWN_SSID:
1318 1.17.2.2 nathanw error = wi_set_ssid(&sc->wi_ibssid,
1319 1.17.2.2 nathanw (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
1320 1.17.2.2 nathanw break;
1321 1.17.2.2 nathanw case WI_RID_PM_ENABLED:
1322 1.17.2.2 nathanw sc->wi_pm_enabled = le16toh(wreq->wi_val[0]);
1323 1.17.2.2 nathanw break;
1324 1.17.2.2 nathanw case WI_RID_MICROWAVE_OVEN:
1325 1.17.2.2 nathanw sc->wi_mor_enabled = le16toh(wreq->wi_val[0]);
1326 1.17.2.2 nathanw break;
1327 1.17.2.2 nathanw case WI_RID_MAX_SLEEP:
1328 1.17.2.2 nathanw sc->wi_max_sleep = le16toh(wreq->wi_val[0]);
1329 1.17.2.2 nathanw break;
1330 1.17.2.2 nathanw case WI_RID_AUTH_CNTL:
1331 1.17.2.2 nathanw sc->wi_authtype = le16toh(wreq->wi_val[0]);
1332 1.17.2.2 nathanw break;
1333 1.17.2.2 nathanw case WI_RID_ROAMING_MODE:
1334 1.17.2.2 nathanw sc->wi_roaming = le16toh(wreq->wi_val[0]);
1335 1.17.2.2 nathanw break;
1336 1.17.2.2 nathanw case WI_RID_ENCRYPTION:
1337 1.17.2.2 nathanw sc->wi_use_wep = le16toh(wreq->wi_val[0]);
1338 1.17.2.2 nathanw break;
1339 1.17.2.2 nathanw case WI_RID_TX_CRYPT_KEY:
1340 1.17.2.2 nathanw sc->wi_tx_key = le16toh(wreq->wi_val[0]);
1341 1.17.2.2 nathanw break;
1342 1.17.2.2 nathanw case WI_RID_DEFLT_CRYPT_KEYS:
1343 1.17.2.3 nathanw memcpy((char *)&sc->wi_keys, (char *)wreq,
1344 1.17.2.2 nathanw sizeof(struct wi_ltv_keys));
1345 1.17.2.2 nathanw break;
1346 1.17.2.2 nathanw default:
1347 1.17.2.2 nathanw error = EINVAL;
1348 1.17.2.2 nathanw break;
1349 1.17.2.2 nathanw }
1350 1.17.2.2 nathanw
1351 1.17.2.2 nathanw return (error);
1352 1.17.2.2 nathanw }
1353 1.17.2.2 nathanw
1354 1.17.2.2 nathanw static int
1355 1.17.2.2 nathanw wi_getdef(sc, wreq)
1356 1.17.2.2 nathanw struct wi_softc *sc;
1357 1.17.2.2 nathanw struct wi_req *wreq;
1358 1.17.2.2 nathanw {
1359 1.17.2.2 nathanw struct sockaddr_dl *sdl;
1360 1.17.2.2 nathanw struct ifnet *ifp;
1361 1.17.2.2 nathanw int error = 0;
1362 1.17.2.2 nathanw
1363 1.17.2.2 nathanw ifp = &sc->sc_ethercom.ec_if;
1364 1.17.2.2 nathanw
1365 1.17.2.2 nathanw wreq->wi_len = 2; /* XXX */
1366 1.17.2.2 nathanw switch (wreq->wi_type) {
1367 1.17.2.2 nathanw case WI_RID_MAC_NODE:
1368 1.17.2.2 nathanw wreq->wi_len += ETHER_ADDR_LEN / 2 - 1;
1369 1.17.2.2 nathanw sdl = (struct sockaddr_dl *)ifp->if_sadl;
1370 1.17.2.3 nathanw memcpy(&wreq->wi_val, &sc->sc_macaddr, ETHER_ADDR_LEN);
1371 1.17.2.3 nathanw memcpy(&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN);
1372 1.17.2.2 nathanw break;
1373 1.17.2.2 nathanw case WI_RID_PORTTYPE:
1374 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_ptype);
1375 1.17.2.2 nathanw break;
1376 1.17.2.2 nathanw case WI_RID_TX_RATE:
1377 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_tx_rate);
1378 1.17.2.2 nathanw break;
1379 1.17.2.2 nathanw case WI_RID_MAX_DATALEN:
1380 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_max_data_len);
1381 1.17.2.2 nathanw break;
1382 1.17.2.2 nathanw case WI_RID_RTS_THRESH:
1383 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_rts_thresh);
1384 1.17.2.2 nathanw break;
1385 1.17.2.2 nathanw case WI_RID_SYSTEM_SCALE:
1386 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_ap_density);
1387 1.17.2.2 nathanw break;
1388 1.17.2.2 nathanw case WI_RID_CREATE_IBSS:
1389 1.17.2.12 nathanw if (sc->sc_firmware_type != WI_INTERSIL)
1390 1.17.2.12 nathanw wreq->wi_val[0] = htole16(sc->wi_create_ibss);
1391 1.17.2.2 nathanw break;
1392 1.17.2.2 nathanw case WI_RID_OWN_CHNL:
1393 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_channel);
1394 1.17.2.2 nathanw break;
1395 1.17.2.2 nathanw case WI_RID_NODENAME:
1396 1.17.2.2 nathanw wi_request_fill_ssid(wreq, &sc->wi_nodeid);
1397 1.17.2.2 nathanw break;
1398 1.17.2.2 nathanw case WI_RID_DESIRED_SSID:
1399 1.17.2.2 nathanw wi_request_fill_ssid(wreq, &sc->wi_netid);
1400 1.17.2.2 nathanw break;
1401 1.17.2.2 nathanw case WI_RID_OWN_SSID:
1402 1.17.2.2 nathanw wi_request_fill_ssid(wreq, &sc->wi_ibssid);
1403 1.17.2.2 nathanw break;
1404 1.17.2.2 nathanw case WI_RID_PM_ENABLED:
1405 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_pm_enabled);
1406 1.17.2.2 nathanw break;
1407 1.17.2.2 nathanw case WI_RID_MICROWAVE_OVEN:
1408 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_mor_enabled);
1409 1.17.2.2 nathanw break;
1410 1.17.2.2 nathanw case WI_RID_MAX_SLEEP:
1411 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_max_sleep);
1412 1.17.2.2 nathanw break;
1413 1.17.2.2 nathanw case WI_RID_AUTH_CNTL:
1414 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_authtype);
1415 1.17.2.2 nathanw break;
1416 1.17.2.2 nathanw case WI_RID_ROAMING_MODE:
1417 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_roaming);
1418 1.17.2.2 nathanw break;
1419 1.17.2.2 nathanw case WI_RID_WEP_AVAIL:
1420 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_has_wep);
1421 1.17.2.2 nathanw break;
1422 1.17.2.2 nathanw case WI_RID_ENCRYPTION:
1423 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_use_wep);
1424 1.17.2.2 nathanw break;
1425 1.17.2.2 nathanw case WI_RID_TX_CRYPT_KEY:
1426 1.17.2.2 nathanw wreq->wi_val[0] = htole16(sc->wi_tx_key);
1427 1.17.2.2 nathanw break;
1428 1.17.2.2 nathanw case WI_RID_DEFLT_CRYPT_KEYS:
1429 1.17.2.2 nathanw wreq->wi_len += sizeof(struct wi_ltv_keys) / 2 - 1;
1430 1.17.2.3 nathanw memcpy(wreq, &sc->wi_keys, sizeof(struct wi_ltv_keys));
1431 1.17.2.2 nathanw break;
1432 1.17.2.2 nathanw default:
1433 1.17.2.2 nathanw #if 0
1434 1.17.2.2 nathanw error = EIO;
1435 1.17.2.2 nathanw #else
1436 1.17.2.2 nathanw #ifdef WI_DEBUG
1437 1.17.2.2 nathanw printf("%s: wi_getdef: unknown request %d\n",
1438 1.17.2.2 nathanw sc->sc_dev.dv_xname, wreq->wi_type);
1439 1.17.2.2 nathanw #endif
1440 1.17.2.2 nathanw #endif
1441 1.17.2.2 nathanw break;
1442 1.17.2.2 nathanw }
1443 1.17.2.2 nathanw
1444 1.17.2.2 nathanw return (error);
1445 1.17.2.2 nathanw }
1446 1.17.2.2 nathanw
1447 1.17.2.2 nathanw static int
1448 1.17.2.2 nathanw wi_ioctl(ifp, command, data)
1449 1.17.2.2 nathanw struct ifnet *ifp;
1450 1.17.2.2 nathanw u_long command;
1451 1.17.2.2 nathanw caddr_t data;
1452 1.17.2.2 nathanw {
1453 1.17.2.7 nathanw int s, error = 0;
1454 1.17.2.10 nathanw int len;
1455 1.17.2.2 nathanw struct wi_softc *sc = ifp->if_softc;
1456 1.17.2.2 nathanw struct wi_req wreq;
1457 1.17.2.2 nathanw struct ifreq *ifr;
1458 1.17.2.14 nathanw struct proc *p = curproc;
1459 1.17.2.2 nathanw struct ieee80211_nwid nwid;
1460 1.17.2.2 nathanw
1461 1.17.2.2 nathanw if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
1462 1.17.2.2 nathanw return (ENXIO);
1463 1.17.2.2 nathanw
1464 1.17.2.2 nathanw s = splnet();
1465 1.17.2.2 nathanw
1466 1.17.2.2 nathanw ifr = (struct ifreq *)data;
1467 1.17.2.2 nathanw switch (command) {
1468 1.17.2.2 nathanw case SIOCSIFADDR:
1469 1.17.2.2 nathanw case SIOCGIFADDR:
1470 1.17.2.2 nathanw case SIOCSIFMTU:
1471 1.17.2.2 nathanw error = ether_ioctl(ifp, command, data);
1472 1.17.2.2 nathanw break;
1473 1.17.2.2 nathanw case SIOCSIFFLAGS:
1474 1.17.2.2 nathanw if (ifp->if_flags & IFF_UP) {
1475 1.17.2.2 nathanw if (ifp->if_flags & IFF_RUNNING &&
1476 1.17.2.2 nathanw ifp->if_flags & IFF_PROMISC &&
1477 1.17.2.2 nathanw !(sc->wi_if_flags & IFF_PROMISC)) {
1478 1.17.2.2 nathanw WI_SETVAL(WI_RID_PROMISC, 1);
1479 1.17.2.2 nathanw } else if (ifp->if_flags & IFF_RUNNING &&
1480 1.17.2.2 nathanw !(ifp->if_flags & IFF_PROMISC) &&
1481 1.17.2.2 nathanw sc->wi_if_flags & IFF_PROMISC) {
1482 1.17.2.2 nathanw WI_SETVAL(WI_RID_PROMISC, 0);
1483 1.17.2.2 nathanw }
1484 1.17.2.2 nathanw wi_init(ifp);
1485 1.17.2.2 nathanw } else {
1486 1.17.2.2 nathanw if (ifp->if_flags & IFF_RUNNING) {
1487 1.17.2.2 nathanw wi_stop(ifp, 0);
1488 1.17.2.2 nathanw }
1489 1.17.2.2 nathanw }
1490 1.17.2.2 nathanw sc->wi_if_flags = ifp->if_flags;
1491 1.17.2.2 nathanw
1492 1.17.2.2 nathanw if (!(ifp->if_flags & IFF_UP)) {
1493 1.17.2.2 nathanw if (sc->sc_enabled) {
1494 1.17.2.2 nathanw if (sc->sc_disable)
1495 1.17.2.2 nathanw (*sc->sc_disable)(sc);
1496 1.17.2.2 nathanw sc->sc_enabled = 0;
1497 1.17.2.2 nathanw ifp->if_flags &= ~IFF_RUNNING;
1498 1.17.2.2 nathanw }
1499 1.17.2.2 nathanw }
1500 1.17.2.2 nathanw error = 0;
1501 1.17.2.2 nathanw break;
1502 1.17.2.2 nathanw case SIOCADDMULTI:
1503 1.17.2.2 nathanw case SIOCDELMULTI:
1504 1.17.2.2 nathanw error = (command == SIOCADDMULTI) ?
1505 1.17.2.2 nathanw ether_addmulti(ifr, &sc->sc_ethercom) :
1506 1.17.2.2 nathanw ether_delmulti(ifr, &sc->sc_ethercom);
1507 1.17.2.2 nathanw if (error == ENETRESET) {
1508 1.17.2.2 nathanw if (sc->sc_enabled != 0) {
1509 1.17.2.2 nathanw /*
1510 1.17.2.2 nathanw * Multicast list has changed. Set the
1511 1.17.2.2 nathanw * hardware filter accordingly.
1512 1.17.2.2 nathanw */
1513 1.17.2.2 nathanw wi_setmulti(sc);
1514 1.17.2.2 nathanw }
1515 1.17.2.2 nathanw error = 0;
1516 1.17.2.2 nathanw }
1517 1.17.2.2 nathanw break;
1518 1.17.2.2 nathanw case SIOCSIFMEDIA:
1519 1.17.2.2 nathanw case SIOCGIFMEDIA:
1520 1.17.2.2 nathanw error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
1521 1.17.2.2 nathanw break;
1522 1.17.2.2 nathanw case SIOCGWAVELAN:
1523 1.17.2.2 nathanw error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1524 1.17.2.2 nathanw if (error)
1525 1.17.2.2 nathanw break;
1526 1.17.2.7 nathanw if (wreq.wi_type == WI_RID_IFACE_STATS) {
1527 1.17.2.3 nathanw memcpy((char *)&wreq.wi_val, (char *)&sc->wi_stats,
1528 1.17.2.7 nathanw sizeof(sc->wi_stats));
1529 1.17.2.2 nathanw wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
1530 1.17.2.10 nathanw } else if (wreq.wi_type == WI_RID_READ_APS) {
1531 1.17.2.10 nathanw if (sc->wi_scanning) {
1532 1.17.2.11 nathanw error = EINPROGRESS;
1533 1.17.2.10 nathanw break;
1534 1.17.2.10 nathanw } else {
1535 1.17.2.10 nathanw len = sc->wi_naps * sizeof(struct wi_apinfo);
1536 1.17.2.10 nathanw len = len > WI_MAX_DATALEN ? WI_MAX_DATALEN : len;
1537 1.17.2.10 nathanw len = len / sizeof(struct wi_apinfo);
1538 1.17.2.10 nathanw memcpy((char *)&wreq.wi_val, (char *)&len, sizeof(len));
1539 1.17.2.10 nathanw memcpy((char *)&wreq.wi_val + sizeof(len),
1540 1.17.2.10 nathanw (char *)&sc->wi_aps,
1541 1.17.2.10 nathanw len * sizeof(struct wi_apinfo));
1542 1.17.2.10 nathanw }
1543 1.17.2.7 nathanw } else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) {
1544 1.17.2.2 nathanw /* For non-root user, return all-zeroes keys */
1545 1.17.2.2 nathanw if (suser(p->p_ucred, &p->p_acflag))
1546 1.17.2.3 nathanw memset((char *)&wreq, 0,
1547 1.17.2.7 nathanw sizeof(struct wi_ltv_keys));
1548 1.17.2.2 nathanw else
1549 1.17.2.3 nathanw memcpy((char *)&wreq, (char *)&sc->wi_keys,
1550 1.17.2.7 nathanw sizeof(struct wi_ltv_keys));
1551 1.17.2.7 nathanw } else {
1552 1.17.2.2 nathanw if (sc->sc_enabled == 0)
1553 1.17.2.2 nathanw error = wi_getdef(sc, &wreq);
1554 1.17.2.12 nathanw else if (wreq.wi_len > WI_MAX_DATALEN)
1555 1.17.2.12 nathanw error = EINVAL;
1556 1.17.2.7 nathanw else if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq))
1557 1.17.2.2 nathanw error = EINVAL;
1558 1.17.2.2 nathanw }
1559 1.17.2.2 nathanw if (error == 0)
1560 1.17.2.2 nathanw error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
1561 1.17.2.2 nathanw break;
1562 1.17.2.2 nathanw case SIOCSWAVELAN:
1563 1.17.2.2 nathanw error = suser(p->p_ucred, &p->p_acflag);
1564 1.17.2.2 nathanw if (error)
1565 1.17.2.2 nathanw break;
1566 1.17.2.2 nathanw error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1567 1.17.2.2 nathanw if (error)
1568 1.17.2.2 nathanw break;
1569 1.17.2.7 nathanw if (wreq.wi_type == WI_RID_IFACE_STATS) {
1570 1.17.2.11 nathanw if (sc->sc_enabled)
1571 1.17.2.11 nathanw wi_inquire(sc);
1572 1.17.2.2 nathanw break;
1573 1.17.2.7 nathanw } else if (wreq.wi_type == WI_RID_MGMT_XMIT) {
1574 1.17.2.2 nathanw error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
1575 1.17.2.7 nathanw wreq.wi_len);
1576 1.17.2.10 nathanw } else if (wreq.wi_type == WI_RID_SCAN_APS) {
1577 1.17.2.10 nathanw if (wreq.wi_len != 4) {
1578 1.17.2.10 nathanw error = EINVAL;
1579 1.17.2.10 nathanw break;
1580 1.17.2.10 nathanw }
1581 1.17.2.10 nathanw if (!sc->wi_scanning) {
1582 1.17.2.12 nathanw switch (sc->sc_firmware_type) {
1583 1.17.2.12 nathanw case WI_LUCENT:
1584 1.17.2.12 nathanw break;
1585 1.17.2.12 nathanw case WI_INTERSIL:
1586 1.17.2.10 nathanw wreq.wi_type = WI_RID_SCAN_REQ;
1587 1.17.2.10 nathanw error = wi_write_record(sc,
1588 1.17.2.10 nathanw (struct wi_ltv_gen *)&wreq);
1589 1.17.2.12 nathanw break;
1590 1.17.2.12 nathanw case WI_SYMBOL:
1591 1.17.2.12 nathanw /*
1592 1.17.2.12 nathanw * XXX only supported on 3.x ?
1593 1.17.2.12 nathanw */
1594 1.17.2.12 nathanw wreq.wi_type = WI_RID_BCAST_SCAN_REQ;
1595 1.17.2.12 nathanw wreq.wi_val[0] =
1596 1.17.2.12 nathanw BSCAN_BCAST | BSCAN_ONETIME;
1597 1.17.2.12 nathanw wreq.wi_len = 2;
1598 1.17.2.12 nathanw error = wi_write_record(sc,
1599 1.17.2.12 nathanw (struct wi_ltv_gen *)&wreq);
1600 1.17.2.12 nathanw break;
1601 1.17.2.10 nathanw }
1602 1.17.2.10 nathanw if (!error) {
1603 1.17.2.10 nathanw sc->wi_scanning = 1;
1604 1.17.2.10 nathanw callout_reset(&sc->wi_scan_sh, hz * 1,
1605 1.17.2.10 nathanw wi_wait_scan, sc);
1606 1.17.2.10 nathanw }
1607 1.17.2.10 nathanw }
1608 1.17.2.7 nathanw } else {
1609 1.17.2.12 nathanw if (wreq.wi_len > WI_MAX_DATALEN)
1610 1.17.2.12 nathanw error = EINVAL;
1611 1.17.2.12 nathanw else if (sc->sc_enabled != 0)
1612 1.17.2.2 nathanw error = wi_write_record(sc,
1613 1.17.2.2 nathanw (struct wi_ltv_gen *)&wreq);
1614 1.17.2.2 nathanw if (error == 0)
1615 1.17.2.2 nathanw error = wi_setdef(sc, &wreq);
1616 1.17.2.2 nathanw if (error == 0 && sc->sc_enabled != 0)
1617 1.17.2.2 nathanw /* Reinitialize WaveLAN. */
1618 1.17.2.2 nathanw wi_init(ifp);
1619 1.17.2.2 nathanw }
1620 1.17.2.2 nathanw break;
1621 1.17.2.2 nathanw case SIOCG80211NWID:
1622 1.17.2.2 nathanw if (sc->sc_enabled == 0) {
1623 1.17.2.2 nathanw /* Return the desired ID */
1624 1.17.2.2 nathanw error = copyout(&sc->wi_netid, ifr->ifr_data,
1625 1.17.2.2 nathanw sizeof(sc->wi_netid));
1626 1.17.2.2 nathanw } else {
1627 1.17.2.2 nathanw wreq.wi_type = WI_RID_CURRENT_SSID;
1628 1.17.2.2 nathanw wreq.wi_len = WI_MAX_DATALEN;
1629 1.17.2.2 nathanw if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) ||
1630 1.17.2.2 nathanw le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN)
1631 1.17.2.2 nathanw error = EINVAL;
1632 1.17.2.2 nathanw else {
1633 1.17.2.2 nathanw wi_set_ssid(&nwid, (u_int8_t *)&wreq.wi_val[1],
1634 1.17.2.2 nathanw le16toh(wreq.wi_val[0]));
1635 1.17.2.2 nathanw error = copyout(&nwid, ifr->ifr_data,
1636 1.17.2.2 nathanw sizeof(nwid));
1637 1.17.2.2 nathanw }
1638 1.17.2.2 nathanw }
1639 1.17.2.2 nathanw break;
1640 1.17.2.2 nathanw case SIOCS80211NWID:
1641 1.17.2.2 nathanw error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
1642 1.17.2.2 nathanw if (error != 0)
1643 1.17.2.2 nathanw break;
1644 1.17.2.2 nathanw if (nwid.i_len > IEEE80211_NWID_LEN) {
1645 1.17.2.2 nathanw error = EINVAL;
1646 1.17.2.2 nathanw break;
1647 1.17.2.2 nathanw }
1648 1.17.2.2 nathanw if (sc->wi_netid.i_len == nwid.i_len &&
1649 1.17.2.2 nathanw memcmp(sc->wi_netid.i_nwid, nwid.i_nwid, nwid.i_len) == 0)
1650 1.17.2.2 nathanw break;
1651 1.17.2.2 nathanw wi_set_ssid(&sc->wi_netid, nwid.i_nwid, nwid.i_len);
1652 1.17.2.2 nathanw if (sc->sc_enabled != 0)
1653 1.17.2.2 nathanw /* Reinitialize WaveLAN. */
1654 1.17.2.2 nathanw wi_init(ifp);
1655 1.17.2.2 nathanw break;
1656 1.17.2.2 nathanw case SIOCS80211NWKEY:
1657 1.17.2.2 nathanw error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
1658 1.17.2.2 nathanw break;
1659 1.17.2.2 nathanw case SIOCG80211NWKEY:
1660 1.17.2.2 nathanw error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
1661 1.17.2.2 nathanw break;
1662 1.17.2.2 nathanw case SIOCS80211POWER:
1663 1.17.2.2 nathanw error = wi_set_pm(sc, (struct ieee80211_power *)data);
1664 1.17.2.2 nathanw break;
1665 1.17.2.2 nathanw case SIOCG80211POWER:
1666 1.17.2.2 nathanw error = wi_get_pm(sc, (struct ieee80211_power *)data);
1667 1.17.2.2 nathanw break;
1668 1.17.2.2 nathanw
1669 1.17.2.2 nathanw default:
1670 1.17.2.2 nathanw error = EINVAL;
1671 1.17.2.2 nathanw break;
1672 1.17.2.2 nathanw }
1673 1.17.2.2 nathanw
1674 1.17.2.2 nathanw splx(s);
1675 1.17.2.2 nathanw return (error);
1676 1.17.2.2 nathanw }
1677 1.17.2.2 nathanw
1678 1.17.2.2 nathanw static int
1679 1.17.2.2 nathanw wi_init(ifp)
1680 1.17.2.2 nathanw struct ifnet *ifp;
1681 1.17.2.2 nathanw {
1682 1.17.2.2 nathanw struct wi_softc *sc = ifp->if_softc;
1683 1.17.2.2 nathanw struct wi_req wreq;
1684 1.17.2.2 nathanw struct wi_ltv_macaddr mac;
1685 1.17.2.11 nathanw int error, id = 0, wasenabled;
1686 1.17.2.2 nathanw
1687 1.17.2.11 nathanw wasenabled = sc->sc_enabled;
1688 1.17.2.2 nathanw if (!sc->sc_enabled) {
1689 1.17.2.2 nathanw if ((error = (*sc->sc_enable)(sc)) != 0)
1690 1.17.2.2 nathanw goto out;
1691 1.17.2.2 nathanw sc->sc_enabled = 1;
1692 1.17.2.2 nathanw }
1693 1.17.2.2 nathanw
1694 1.17.2.2 nathanw wi_stop(ifp, 0);
1695 1.17.2.11 nathanw /* Symbol firmware cannot be initialized more than once */
1696 1.17.2.11 nathanw if (!(sc->sc_firmware_type == WI_SYMBOL && wasenabled))
1697 1.17.2.11 nathanw wi_reset(sc);
1698 1.17.2.2 nathanw
1699 1.17.2.2 nathanw /* Program max data length. */
1700 1.17.2.2 nathanw WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
1701 1.17.2.2 nathanw
1702 1.17.2.2 nathanw /* Enable/disable IBSS creation. */
1703 1.17.2.12 nathanw if (sc->sc_firmware_type != WI_INTERSIL)
1704 1.17.2.12 nathanw WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
1705 1.17.2.2 nathanw
1706 1.17.2.2 nathanw /* Set the port type. */
1707 1.17.2.2 nathanw WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
1708 1.17.2.2 nathanw
1709 1.17.2.2 nathanw /* Program the RTS/CTS threshold. */
1710 1.17.2.2 nathanw WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
1711 1.17.2.2 nathanw
1712 1.17.2.2 nathanw /* Program the TX rate */
1713 1.17.2.2 nathanw WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
1714 1.17.2.2 nathanw
1715 1.17.2.2 nathanw /* Access point density */
1716 1.17.2.2 nathanw WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
1717 1.17.2.2 nathanw
1718 1.17.2.2 nathanw /* Power Management Enabled */
1719 1.17.2.2 nathanw WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
1720 1.17.2.2 nathanw
1721 1.17.2.2 nathanw /* Power Managment Max Sleep */
1722 1.17.2.2 nathanw WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
1723 1.17.2.2 nathanw
1724 1.17.2.2 nathanw /* Roaming type */
1725 1.17.2.2 nathanw WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
1726 1.17.2.2 nathanw
1727 1.17.2.2 nathanw /* Specify the IBSS name */
1728 1.17.2.2 nathanw wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_ibssid);
1729 1.17.2.2 nathanw
1730 1.17.2.2 nathanw /* Specify the network name */
1731 1.17.2.2 nathanw wi_write_ssid(sc, WI_RID_DESIRED_SSID, &wreq, &sc->wi_netid);
1732 1.17.2.2 nathanw
1733 1.17.2.2 nathanw /* Specify the frequency to use */
1734 1.17.2.2 nathanw WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel);
1735 1.17.2.2 nathanw
1736 1.17.2.2 nathanw /* Program the nodename. */
1737 1.17.2.2 nathanw wi_write_ssid(sc, WI_RID_NODENAME, &wreq, &sc->wi_nodeid);
1738 1.17.2.2 nathanw
1739 1.17.2.2 nathanw /* Set our MAC address. */
1740 1.17.2.2 nathanw mac.wi_len = 4;
1741 1.17.2.2 nathanw mac.wi_type = WI_RID_MAC_NODE;
1742 1.17.2.2 nathanw memcpy(&mac.wi_mac_addr, sc->sc_macaddr, ETHER_ADDR_LEN);
1743 1.17.2.2 nathanw wi_write_record(sc, (struct wi_ltv_gen *)&mac);
1744 1.17.2.2 nathanw
1745 1.17.2.2 nathanw /* Initialize promisc mode. */
1746 1.17.2.2 nathanw if (ifp->if_flags & IFF_PROMISC) {
1747 1.17.2.2 nathanw WI_SETVAL(WI_RID_PROMISC, 1);
1748 1.17.2.2 nathanw } else {
1749 1.17.2.2 nathanw WI_SETVAL(WI_RID_PROMISC, 0);
1750 1.17.2.2 nathanw }
1751 1.17.2.2 nathanw
1752 1.17.2.2 nathanw /* Configure WEP. */
1753 1.17.2.2 nathanw if (sc->wi_has_wep) {
1754 1.17.2.2 nathanw WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
1755 1.17.2.2 nathanw WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
1756 1.17.2.2 nathanw sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
1757 1.17.2.2 nathanw sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
1758 1.17.2.2 nathanw wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
1759 1.17.2.11 nathanw if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
1760 1.17.2.2 nathanw /*
1761 1.17.2.2 nathanw * ONLY HWB3163 EVAL-CARD Firmware version
1762 1.17.2.11 nathanw * less than 0.8 variant2
1763 1.17.2.2 nathanw *
1764 1.17.2.2 nathanw * If promiscuous mode disable, Prism2 chip
1765 1.17.2.2 nathanw * does not work with WEP .
1766 1.17.2.2 nathanw * It is under investigation for details.
1767 1.17.2.2 nathanw * (ichiro (at) netbsd.org)
1768 1.17.2.2 nathanw */
1769 1.17.2.11 nathanw if (sc->sc_firmware_type == WI_INTERSIL &&
1770 1.17.2.12 nathanw sc->sc_sta_firmware_ver < 802 ) {
1771 1.17.2.11 nathanw /* firm ver < 0.8 variant 2 */
1772 1.17.2.2 nathanw WI_SETVAL(WI_RID_PROMISC, 1);
1773 1.17.2.2 nathanw }
1774 1.17.2.2 nathanw WI_SETVAL(WI_RID_AUTH_CNTL, sc->wi_authtype);
1775 1.17.2.2 nathanw }
1776 1.17.2.2 nathanw }
1777 1.17.2.2 nathanw
1778 1.17.2.2 nathanw /* Set multicast filter. */
1779 1.17.2.2 nathanw wi_setmulti(sc);
1780 1.17.2.2 nathanw
1781 1.17.2.2 nathanw /* Enable desired port */
1782 1.17.2.2 nathanw wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0);
1783 1.17.2.2 nathanw
1784 1.17.2.10 nathanw /* scanning variable is modal, therefore reinit to OFF, in case it was on. */
1785 1.17.2.10 nathanw sc->wi_scanning=0;
1786 1.17.2.10 nathanw sc->wi_naps=0;
1787 1.17.2.10 nathanw
1788 1.17.2.2 nathanw if ((error = wi_alloc_nicmem(sc,
1789 1.17.2.2 nathanw 1518 + sizeof(struct wi_frame) + 8, &id)) != 0) {
1790 1.17.2.2 nathanw printf("%s: tx buffer allocation failed\n",
1791 1.17.2.2 nathanw sc->sc_dev.dv_xname);
1792 1.17.2.2 nathanw goto out;
1793 1.17.2.2 nathanw }
1794 1.17.2.2 nathanw sc->wi_tx_data_id = id;
1795 1.17.2.2 nathanw
1796 1.17.2.2 nathanw if ((error = wi_alloc_nicmem(sc,
1797 1.17.2.2 nathanw 1518 + sizeof(struct wi_frame) + 8, &id)) != 0) {
1798 1.17.2.2 nathanw printf("%s: mgmt. buffer allocation failed\n",
1799 1.17.2.2 nathanw sc->sc_dev.dv_xname);
1800 1.17.2.2 nathanw goto out;
1801 1.17.2.2 nathanw }
1802 1.17.2.2 nathanw sc->wi_tx_mgmt_id = id;
1803 1.17.2.2 nathanw
1804 1.17.2.2 nathanw /* Enable interrupts */
1805 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
1806 1.17.2.2 nathanw
1807 1.17.2.2 nathanw ifp->if_flags |= IFF_RUNNING;
1808 1.17.2.2 nathanw ifp->if_flags &= ~IFF_OACTIVE;
1809 1.17.2.2 nathanw
1810 1.17.2.7 nathanw callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
1811 1.17.2.2 nathanw
1812 1.17.2.2 nathanw out:
1813 1.17.2.2 nathanw if (error) {
1814 1.17.2.2 nathanw ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1815 1.17.2.2 nathanw ifp->if_timer = 0;
1816 1.17.2.2 nathanw printf("%s: interface not running\n", sc->sc_dev.dv_xname);
1817 1.17.2.2 nathanw }
1818 1.17.2.2 nathanw return (error);
1819 1.17.2.2 nathanw }
1820 1.17.2.2 nathanw
1821 1.17.2.2 nathanw static void
1822 1.17.2.2 nathanw wi_start(ifp)
1823 1.17.2.2 nathanw struct ifnet *ifp;
1824 1.17.2.2 nathanw {
1825 1.17.2.2 nathanw struct wi_softc *sc;
1826 1.17.2.2 nathanw struct mbuf *m0;
1827 1.17.2.2 nathanw struct wi_frame tx_frame;
1828 1.17.2.2 nathanw struct ether_header *eh;
1829 1.17.2.2 nathanw int id;
1830 1.17.2.2 nathanw
1831 1.17.2.2 nathanw sc = ifp->if_softc;
1832 1.17.2.2 nathanw
1833 1.17.2.2 nathanw if (ifp->if_flags & IFF_OACTIVE)
1834 1.17.2.2 nathanw return;
1835 1.17.2.2 nathanw
1836 1.17.2.2 nathanw IFQ_DEQUEUE(&ifp->if_snd, m0);
1837 1.17.2.2 nathanw if (m0 == NULL)
1838 1.17.2.2 nathanw return;
1839 1.17.2.2 nathanw
1840 1.17.2.3 nathanw memset((char *)&tx_frame, 0, sizeof(tx_frame));
1841 1.17.2.2 nathanw id = sc->wi_tx_data_id;
1842 1.17.2.2 nathanw eh = mtod(m0, struct ether_header *);
1843 1.17.2.2 nathanw
1844 1.17.2.2 nathanw /*
1845 1.17.2.2 nathanw * Use RFC1042 encoding for IP and ARP datagrams,
1846 1.17.2.2 nathanw * 802.3 for anything else.
1847 1.17.2.2 nathanw */
1848 1.17.2.13 nathanw if (eh->ether_type == htons(ETHERTYPE_IP) ||
1849 1.17.2.13 nathanw eh->ether_type == htons(ETHERTYPE_ARP) ||
1850 1.17.2.13 nathanw eh->ether_type == htons(ETHERTYPE_REVARP) ||
1851 1.17.2.13 nathanw eh->ether_type == htons(ETHERTYPE_IPV6)) {
1852 1.17.2.3 nathanw memcpy((char *)&tx_frame.wi_addr1, (char *)&eh->ether_dhost,
1853 1.17.2.3 nathanw ETHER_ADDR_LEN);
1854 1.17.2.3 nathanw memcpy((char *)&tx_frame.wi_addr2, (char *)&eh->ether_shost,
1855 1.17.2.3 nathanw ETHER_ADDR_LEN);
1856 1.17.2.3 nathanw memcpy((char *)&tx_frame.wi_dst_addr, (char *)&eh->ether_dhost,
1857 1.17.2.3 nathanw ETHER_ADDR_LEN);
1858 1.17.2.3 nathanw memcpy((char *)&tx_frame.wi_src_addr, (char *)&eh->ether_shost,
1859 1.17.2.3 nathanw ETHER_ADDR_LEN);
1860 1.17.2.2 nathanw
1861 1.17.2.2 nathanw tx_frame.wi_dat_len = htole16(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
1862 1.17.2.2 nathanw tx_frame.wi_frame_ctl = htole16(WI_FTYPE_DATA);
1863 1.17.2.2 nathanw tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0);
1864 1.17.2.2 nathanw tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1);
1865 1.17.2.2 nathanw tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
1866 1.17.2.2 nathanw tx_frame.wi_type = eh->ether_type;
1867 1.17.2.2 nathanw
1868 1.17.2.2 nathanw m_copydata(m0, sizeof(struct ether_header),
1869 1.17.2.2 nathanw m0->m_pkthdr.len - sizeof(struct ether_header),
1870 1.17.2.2 nathanw (caddr_t)&sc->wi_txbuf);
1871 1.17.2.2 nathanw
1872 1.17.2.2 nathanw wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
1873 1.17.2.2 nathanw sizeof(struct wi_frame));
1874 1.17.2.2 nathanw wi_write_data(sc, id, WI_802_11_OFFSET, (caddr_t)&sc->wi_txbuf,
1875 1.17.2.2 nathanw (m0->m_pkthdr.len - sizeof(struct ether_header)) + 2);
1876 1.17.2.2 nathanw } else {
1877 1.17.2.2 nathanw tx_frame.wi_dat_len = htole16(m0->m_pkthdr.len);
1878 1.17.2.2 nathanw
1879 1.17.2.2 nathanw m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&sc->wi_txbuf);
1880 1.17.2.2 nathanw
1881 1.17.2.2 nathanw wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
1882 1.17.2.2 nathanw sizeof(struct wi_frame));
1883 1.17.2.2 nathanw wi_write_data(sc, id, WI_802_3_OFFSET, (caddr_t)&sc->wi_txbuf,
1884 1.17.2.2 nathanw m0->m_pkthdr.len + 2);
1885 1.17.2.2 nathanw }
1886 1.17.2.2 nathanw
1887 1.17.2.2 nathanw #if NBPFILTER > 0
1888 1.17.2.2 nathanw /*
1889 1.17.2.2 nathanw * If there's a BPF listener, bounce a copy of
1890 1.17.2.2 nathanw * this frame to him.
1891 1.17.2.2 nathanw */
1892 1.17.2.2 nathanw if (ifp->if_bpf)
1893 1.17.2.2 nathanw bpf_mtap(ifp->if_bpf, m0);
1894 1.17.2.2 nathanw #endif
1895 1.17.2.2 nathanw
1896 1.17.2.2 nathanw m_freem(m0);
1897 1.17.2.2 nathanw
1898 1.17.2.2 nathanw if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id))
1899 1.17.2.2 nathanw printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
1900 1.17.2.2 nathanw
1901 1.17.2.2 nathanw ifp->if_flags |= IFF_OACTIVE;
1902 1.17.2.2 nathanw
1903 1.17.2.2 nathanw /*
1904 1.17.2.2 nathanw * Set a timeout in case the chip goes out to lunch.
1905 1.17.2.2 nathanw */
1906 1.17.2.2 nathanw ifp->if_timer = 5;
1907 1.17.2.2 nathanw
1908 1.17.2.2 nathanw return;
1909 1.17.2.2 nathanw }
1910 1.17.2.2 nathanw
1911 1.17.2.2 nathanw static int
1912 1.17.2.2 nathanw wi_mgmt_xmit(sc, data, len)
1913 1.17.2.2 nathanw struct wi_softc *sc;
1914 1.17.2.2 nathanw caddr_t data;
1915 1.17.2.2 nathanw int len;
1916 1.17.2.2 nathanw {
1917 1.17.2.2 nathanw struct wi_frame tx_frame;
1918 1.17.2.2 nathanw int id;
1919 1.17.2.2 nathanw struct wi_80211_hdr *hdr;
1920 1.17.2.2 nathanw caddr_t dptr;
1921 1.17.2.2 nathanw
1922 1.17.2.2 nathanw hdr = (struct wi_80211_hdr *)data;
1923 1.17.2.2 nathanw dptr = data + sizeof(struct wi_80211_hdr);
1924 1.17.2.2 nathanw
1925 1.17.2.3 nathanw memset((char *)&tx_frame, 0, sizeof(tx_frame));
1926 1.17.2.2 nathanw id = sc->wi_tx_mgmt_id;
1927 1.17.2.2 nathanw
1928 1.17.2.3 nathanw memcpy((char *)&tx_frame.wi_frame_ctl, (char *)hdr,
1929 1.17.2.2 nathanw sizeof(struct wi_80211_hdr));
1930 1.17.2.2 nathanw
1931 1.17.2.2 nathanw tx_frame.wi_dat_len = htole16(len - WI_SNAPHDR_LEN);
1932 1.17.2.2 nathanw tx_frame.wi_len = htons(len - WI_SNAPHDR_LEN);
1933 1.17.2.2 nathanw
1934 1.17.2.2 nathanw wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame));
1935 1.17.2.2 nathanw wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr,
1936 1.17.2.2 nathanw (len - sizeof(struct wi_80211_hdr)) + 2);
1937 1.17.2.2 nathanw
1938 1.17.2.2 nathanw if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) {
1939 1.17.2.2 nathanw printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
1940 1.17.2.2 nathanw return(EIO);
1941 1.17.2.2 nathanw }
1942 1.17.2.2 nathanw
1943 1.17.2.2 nathanw return(0);
1944 1.17.2.2 nathanw }
1945 1.17.2.2 nathanw
1946 1.17.2.2 nathanw static void
1947 1.17.2.2 nathanw wi_stop(ifp, disable)
1948 1.17.2.2 nathanw struct ifnet *ifp;
1949 1.17.2.2 nathanw {
1950 1.17.2.2 nathanw struct wi_softc *sc = ifp->if_softc;
1951 1.17.2.2 nathanw
1952 1.17.2.2 nathanw CSR_WRITE_2(sc, WI_INT_EN, 0);
1953 1.17.2.2 nathanw wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0);
1954 1.17.2.2 nathanw
1955 1.17.2.7 nathanw callout_stop(&sc->wi_inquire_ch);
1956 1.17.2.10 nathanw callout_stop(&sc->wi_scan_sh);
1957 1.17.2.2 nathanw
1958 1.17.2.2 nathanw if (disable) {
1959 1.17.2.2 nathanw if (sc->sc_enabled) {
1960 1.17.2.2 nathanw if (sc->sc_disable)
1961 1.17.2.2 nathanw (*sc->sc_disable)(sc);
1962 1.17.2.2 nathanw sc->sc_enabled = 0;
1963 1.17.2.2 nathanw }
1964 1.17.2.2 nathanw }
1965 1.17.2.2 nathanw
1966 1.17.2.2 nathanw ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
1967 1.17.2.2 nathanw ifp->if_timer = 0;
1968 1.17.2.2 nathanw }
1969 1.17.2.2 nathanw
1970 1.17.2.2 nathanw static void
1971 1.17.2.2 nathanw wi_watchdog(ifp)
1972 1.17.2.2 nathanw struct ifnet *ifp;
1973 1.17.2.2 nathanw {
1974 1.17.2.2 nathanw struct wi_softc *sc;
1975 1.17.2.2 nathanw
1976 1.17.2.2 nathanw sc = ifp->if_softc;
1977 1.17.2.2 nathanw
1978 1.17.2.2 nathanw printf("%s: device timeout\n", sc->sc_dev.dv_xname);
1979 1.17.2.2 nathanw
1980 1.17.2.2 nathanw wi_init(ifp);
1981 1.17.2.2 nathanw
1982 1.17.2.2 nathanw ifp->if_oerrors++;
1983 1.17.2.2 nathanw
1984 1.17.2.2 nathanw return;
1985 1.17.2.2 nathanw }
1986 1.17.2.2 nathanw
1987 1.17.2.2 nathanw void
1988 1.17.2.2 nathanw wi_shutdown(sc)
1989 1.17.2.2 nathanw struct wi_softc *sc;
1990 1.17.2.2 nathanw {
1991 1.17.2.2 nathanw int s;
1992 1.17.2.2 nathanw
1993 1.17.2.2 nathanw s = splnet();
1994 1.17.2.2 nathanw if (sc->sc_enabled) {
1995 1.17.2.2 nathanw if (sc->sc_disable)
1996 1.17.2.2 nathanw (*sc->sc_disable)(sc);
1997 1.17.2.2 nathanw sc->sc_enabled = 0;
1998 1.17.2.2 nathanw }
1999 1.17.2.2 nathanw splx(s);
2000 1.17.2.2 nathanw }
2001 1.17.2.2 nathanw
2002 1.17.2.2 nathanw int
2003 1.17.2.2 nathanw wi_activate(self, act)
2004 1.17.2.2 nathanw struct device *self;
2005 1.17.2.2 nathanw enum devact act;
2006 1.17.2.2 nathanw {
2007 1.17.2.2 nathanw struct wi_softc *sc = (struct wi_softc *)self;
2008 1.17.2.2 nathanw int rv = 0, s;
2009 1.17.2.2 nathanw
2010 1.17.2.2 nathanw s = splnet();
2011 1.17.2.2 nathanw switch (act) {
2012 1.17.2.2 nathanw case DVACT_ACTIVATE:
2013 1.17.2.2 nathanw rv = EOPNOTSUPP;
2014 1.17.2.2 nathanw break;
2015 1.17.2.2 nathanw
2016 1.17.2.2 nathanw case DVACT_DEACTIVATE:
2017 1.17.2.2 nathanw if_deactivate(&sc->sc_ethercom.ec_if);
2018 1.17.2.2 nathanw break;
2019 1.17.2.2 nathanw }
2020 1.17.2.2 nathanw splx(s);
2021 1.17.2.2 nathanw return (rv);
2022 1.17.2.2 nathanw }
2023 1.17.2.2 nathanw
2024 1.17.2.2 nathanw static void
2025 1.17.2.2 nathanw wi_get_id(sc)
2026 1.17.2.2 nathanw struct wi_softc *sc;
2027 1.17.2.2 nathanw {
2028 1.17.2.2 nathanw struct wi_ltv_ver ver;
2029 1.17.2.12 nathanw struct wi_card_ident *id;
2030 1.17.2.2 nathanw
2031 1.17.2.2 nathanw /* getting chip identity */
2032 1.17.2.2 nathanw memset(&ver, 0, sizeof(ver));
2033 1.17.2.8 nathanw ver.wi_type = WI_RID_CARD_ID;
2034 1.17.2.2 nathanw ver.wi_len = 5;
2035 1.17.2.2 nathanw wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2036 1.17.2.2 nathanw printf("%s: using ", sc->sc_dev.dv_xname);
2037 1.17.2.12 nathanw
2038 1.17.2.12 nathanw sc->sc_firmware_type = WI_NOTYPE;
2039 1.17.2.12 nathanw for (id = wi_card_ident; id->card_name != NULL; id++) {
2040 1.17.2.12 nathanw if (le16toh(ver.wi_ver[0]) == id->card_id) {
2041 1.17.2.12 nathanw printf("%s", id->card_name);
2042 1.17.2.12 nathanw sc->sc_firmware_type = id->firm_type;
2043 1.17.2.12 nathanw break;
2044 1.17.2.12 nathanw }
2045 1.17.2.12 nathanw }
2046 1.17.2.12 nathanw if (sc->sc_firmware_type == WI_NOTYPE) {
2047 1.17.2.11 nathanw if (le16toh(ver.wi_ver[0]) & 0x8000) {
2048 1.17.2.11 nathanw printf("Unknown PRISM2 chip");
2049 1.17.2.11 nathanw sc->sc_firmware_type = WI_INTERSIL;
2050 1.17.2.11 nathanw } else {
2051 1.17.2.11 nathanw printf("Unknown Lucent chip");
2052 1.17.2.11 nathanw sc->sc_firmware_type = WI_LUCENT;
2053 1.17.2.11 nathanw }
2054 1.17.2.2 nathanw }
2055 1.17.2.2 nathanw
2056 1.17.2.12 nathanw /* get primary firmware version (Only Prism chips) */
2057 1.17.2.12 nathanw if (sc->sc_firmware_type != WI_LUCENT) {
2058 1.17.2.12 nathanw memset(&ver, 0, sizeof(ver));
2059 1.17.2.12 nathanw ver.wi_type = WI_RID_PRI_IDENTITY;
2060 1.17.2.12 nathanw ver.wi_len = 5;
2061 1.17.2.12 nathanw wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2062 1.17.2.12 nathanw LE16TOH(ver.wi_ver[1]);
2063 1.17.2.12 nathanw LE16TOH(ver.wi_ver[2]);
2064 1.17.2.12 nathanw LE16TOH(ver.wi_ver[3]);
2065 1.17.2.12 nathanw sc->sc_pri_firmware_ver = ver.wi_ver[2] * 10000 +
2066 1.17.2.12 nathanw ver.wi_ver[3] * 100 + ver.wi_ver[1];
2067 1.17.2.12 nathanw }
2068 1.17.2.12 nathanw
2069 1.17.2.12 nathanw /* get station firmware version */
2070 1.17.2.11 nathanw memset(&ver, 0, sizeof(ver));
2071 1.17.2.11 nathanw ver.wi_type = WI_RID_STA_IDENTITY;
2072 1.17.2.11 nathanw ver.wi_len = 5;
2073 1.17.2.11 nathanw wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2074 1.17.2.11 nathanw LE16TOH(ver.wi_ver[1]);
2075 1.17.2.11 nathanw LE16TOH(ver.wi_ver[2]);
2076 1.17.2.11 nathanw LE16TOH(ver.wi_ver[3]);
2077 1.17.2.12 nathanw sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
2078 1.17.2.11 nathanw ver.wi_ver[3] * 100 + ver.wi_ver[1];
2079 1.17.2.11 nathanw if (sc->sc_firmware_type == WI_INTERSIL &&
2080 1.17.2.12 nathanw (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
2081 1.17.2.11 nathanw struct wi_ltv_str sver;
2082 1.17.2.11 nathanw char *p;
2083 1.17.2.11 nathanw
2084 1.17.2.11 nathanw memset(&sver, 0, sizeof(sver));
2085 1.17.2.11 nathanw sver.wi_type = WI_RID_SYMBOL_IDENTITY;
2086 1.17.2.11 nathanw sver.wi_len = 7;
2087 1.17.2.12 nathanw /* value should be the format like "V2.00-11" */
2088 1.17.2.11 nathanw if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
2089 1.17.2.12 nathanw *(p = (char *)sver.wi_str) >= 'A' &&
2090 1.17.2.11 nathanw p[2] == '.' && p[5] == '-' && p[8] == '\0') {
2091 1.17.2.11 nathanw sc->sc_firmware_type = WI_SYMBOL;
2092 1.17.2.12 nathanw sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
2093 1.17.2.11 nathanw (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
2094 1.17.2.11 nathanw (p[6] - '0') * 10 + (p[7] - '0');
2095 1.17.2.11 nathanw }
2096 1.17.2.11 nathanw }
2097 1.17.2.12 nathanw
2098 1.17.2.12 nathanw printf("\n%s: %s Firmware: ", sc->sc_dev.dv_xname,
2099 1.17.2.12 nathanw sc->sc_firmware_type == WI_LUCENT ? "Lucent" :
2100 1.17.2.12 nathanw (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil"));
2101 1.17.2.12 nathanw if (sc->sc_firmware_type != WI_LUCENT) /* XXX */
2102 1.17.2.12 nathanw printf("Primary (%u.%u.%u), ", sc->sc_pri_firmware_ver / 10000,
2103 1.17.2.12 nathanw (sc->sc_pri_firmware_ver % 10000) / 100,
2104 1.17.2.12 nathanw sc->sc_pri_firmware_ver % 100);
2105 1.17.2.12 nathanw printf("Station (%u.%u.%u)\n",
2106 1.17.2.12 nathanw sc->sc_sta_firmware_ver / 10000, (sc->sc_sta_firmware_ver % 10000) / 100,
2107 1.17.2.12 nathanw sc->sc_sta_firmware_ver % 100);
2108 1.17.2.2 nathanw
2109 1.17.2.2 nathanw return;
2110 1.17.2.2 nathanw }
2111 1.17.2.2 nathanw
2112 1.17.2.2 nathanw int
2113 1.17.2.2 nathanw wi_detach(sc)
2114 1.17.2.2 nathanw struct wi_softc *sc;
2115 1.17.2.2 nathanw {
2116 1.17.2.2 nathanw struct ifnet *ifp = sc->sc_ifp;
2117 1.17.2.2 nathanw int s;
2118 1.17.2.2 nathanw
2119 1.17.2.2 nathanw if (!sc->sc_attached)
2120 1.17.2.2 nathanw return (0);
2121 1.17.2.2 nathanw
2122 1.17.2.2 nathanw s = splnet();
2123 1.17.2.7 nathanw callout_stop(&sc->wi_inquire_ch);
2124 1.17.2.2 nathanw
2125 1.17.2.2 nathanw /* Delete all remaining media. */
2126 1.17.2.2 nathanw ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
2127 1.17.2.2 nathanw
2128 1.17.2.2 nathanw ether_ifdetach(ifp);
2129 1.17.2.2 nathanw if_detach(ifp);
2130 1.17.2.2 nathanw if (sc->sc_enabled) {
2131 1.17.2.2 nathanw if (sc->sc_disable)
2132 1.17.2.2 nathanw (*sc->sc_disable)(sc);
2133 1.17.2.2 nathanw sc->sc_enabled = 0;
2134 1.17.2.2 nathanw }
2135 1.17.2.2 nathanw splx(s);
2136 1.17.2.2 nathanw return (0);
2137 1.17.2.2 nathanw }
2138 1.17.2.2 nathanw
2139 1.17.2.2 nathanw void
2140 1.17.2.2 nathanw wi_power(sc, why)
2141 1.17.2.2 nathanw struct wi_softc *sc;
2142 1.17.2.2 nathanw int why;
2143 1.17.2.2 nathanw {
2144 1.17.2.2 nathanw int s;
2145 1.17.2.2 nathanw
2146 1.17.2.2 nathanw if (!sc->sc_enabled)
2147 1.17.2.2 nathanw return;
2148 1.17.2.2 nathanw
2149 1.17.2.2 nathanw s = splnet();
2150 1.17.2.2 nathanw switch (why) {
2151 1.17.2.2 nathanw case PWR_SUSPEND:
2152 1.17.2.2 nathanw case PWR_STANDBY:
2153 1.17.2.2 nathanw wi_stop(sc->sc_ifp, 0);
2154 1.17.2.2 nathanw if (sc->sc_enabled) {
2155 1.17.2.2 nathanw if (sc->sc_disable)
2156 1.17.2.2 nathanw (*sc->sc_disable)(sc);
2157 1.17.2.2 nathanw }
2158 1.17.2.2 nathanw break;
2159 1.17.2.2 nathanw case PWR_RESUME:
2160 1.17.2.2 nathanw sc->sc_enabled = 0;
2161 1.17.2.2 nathanw wi_init(sc->sc_ifp);
2162 1.17.2.2 nathanw (void)wi_intr(sc);
2163 1.17.2.2 nathanw break;
2164 1.17.2.2 nathanw case PWR_SOFTSUSPEND:
2165 1.17.2.2 nathanw case PWR_SOFTSTANDBY:
2166 1.17.2.2 nathanw case PWR_SOFTRESUME:
2167 1.17.2.2 nathanw break;
2168 1.17.2.2 nathanw }
2169 1.17.2.2 nathanw splx(s);
2170 1.17.2.2 nathanw }
2171 1.17.2.2 nathanw
2172 1.17.2.2 nathanw static int
2173 1.17.2.2 nathanw wi_set_ssid(ws, id, len)
2174 1.17.2.2 nathanw struct ieee80211_nwid *ws;
2175 1.17.2.2 nathanw u_int8_t *id;
2176 1.17.2.2 nathanw int len;
2177 1.17.2.2 nathanw {
2178 1.17.2.2 nathanw
2179 1.17.2.2 nathanw if (len > IEEE80211_NWID_LEN)
2180 1.17.2.2 nathanw return (EINVAL);
2181 1.17.2.2 nathanw ws->i_len = len;
2182 1.17.2.2 nathanw memcpy(ws->i_nwid, id, len);
2183 1.17.2.2 nathanw return (0);
2184 1.17.2.2 nathanw }
2185 1.17.2.2 nathanw
2186 1.17.2.2 nathanw static void
2187 1.17.2.2 nathanw wi_request_fill_ssid(wreq, ws)
2188 1.17.2.2 nathanw struct wi_req *wreq;
2189 1.17.2.2 nathanw struct ieee80211_nwid *ws;
2190 1.17.2.2 nathanw {
2191 1.17.2.2 nathanw int len = ws->i_len;
2192 1.17.2.2 nathanw
2193 1.17.2.2 nathanw memset(&wreq->wi_val[0], 0, sizeof(wreq->wi_val));
2194 1.17.2.2 nathanw wreq->wi_val[0] = htole16(len);
2195 1.17.2.2 nathanw wreq->wi_len = roundup(len, 2) / 2 + 2;
2196 1.17.2.2 nathanw memcpy(&wreq->wi_val[1], ws->i_nwid, len);
2197 1.17.2.2 nathanw }
2198 1.17.2.2 nathanw
2199 1.17.2.2 nathanw static int
2200 1.17.2.2 nathanw wi_write_ssid(sc, type, wreq, ws)
2201 1.17.2.2 nathanw struct wi_softc *sc;
2202 1.17.2.2 nathanw int type;
2203 1.17.2.2 nathanw struct wi_req *wreq;
2204 1.17.2.2 nathanw struct ieee80211_nwid *ws;
2205 1.17.2.2 nathanw {
2206 1.17.2.2 nathanw
2207 1.17.2.2 nathanw wreq->wi_type = type;
2208 1.17.2.2 nathanw wi_request_fill_ssid(wreq, ws);
2209 1.17.2.2 nathanw return (wi_write_record(sc, (struct wi_ltv_gen *)wreq));
2210 1.17.2.2 nathanw }
2211 1.17.2.2 nathanw
2212 1.17.2.2 nathanw static int
2213 1.17.2.2 nathanw wi_sync_media(sc, ptype, txrate)
2214 1.17.2.2 nathanw struct wi_softc *sc;
2215 1.17.2.2 nathanw int ptype;
2216 1.17.2.2 nathanw int txrate;
2217 1.17.2.2 nathanw {
2218 1.17.2.2 nathanw int media = sc->sc_media.ifm_cur->ifm_media;
2219 1.17.2.2 nathanw int options = IFM_OPTIONS(media);
2220 1.17.2.2 nathanw int subtype;
2221 1.17.2.2 nathanw
2222 1.17.2.2 nathanw switch (txrate) {
2223 1.17.2.2 nathanw case 1:
2224 1.17.2.2 nathanw subtype = IFM_IEEE80211_DS1;
2225 1.17.2.2 nathanw break;
2226 1.17.2.2 nathanw case 2:
2227 1.17.2.2 nathanw subtype = IFM_IEEE80211_DS2;
2228 1.17.2.2 nathanw break;
2229 1.17.2.2 nathanw case 3:
2230 1.17.2.2 nathanw subtype = IFM_AUTO;
2231 1.17.2.2 nathanw break;
2232 1.17.2.10 nathanw case 5:
2233 1.17.2.10 nathanw subtype = IFM_IEEE80211_DS5;
2234 1.17.2.10 nathanw break;
2235 1.17.2.2 nathanw case 11:
2236 1.17.2.2 nathanw subtype = IFM_IEEE80211_DS11;
2237 1.17.2.2 nathanw break;
2238 1.17.2.2 nathanw default:
2239 1.17.2.2 nathanw subtype = IFM_MANUAL; /* Unable to represent */
2240 1.17.2.2 nathanw break;
2241 1.17.2.2 nathanw }
2242 1.17.2.2 nathanw switch (ptype) {
2243 1.17.2.2 nathanw case WI_PORTTYPE_ADHOC:
2244 1.17.2.2 nathanw options |= IFM_IEEE80211_ADHOC;
2245 1.17.2.2 nathanw break;
2246 1.17.2.2 nathanw case WI_PORTTYPE_BSS:
2247 1.17.2.2 nathanw options &= ~IFM_IEEE80211_ADHOC;
2248 1.17.2.2 nathanw break;
2249 1.17.2.2 nathanw default:
2250 1.17.2.2 nathanw subtype = IFM_MANUAL; /* Unable to represent */
2251 1.17.2.2 nathanw break;
2252 1.17.2.2 nathanw }
2253 1.17.2.2 nathanw media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
2254 1.17.2.2 nathanw IFM_INST(media));
2255 1.17.2.2 nathanw if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
2256 1.17.2.2 nathanw return (EINVAL);
2257 1.17.2.2 nathanw ifmedia_set(&sc->sc_media, media);
2258 1.17.2.2 nathanw sc->wi_ptype = ptype;
2259 1.17.2.2 nathanw sc->wi_tx_rate = txrate;
2260 1.17.2.2 nathanw return (0);
2261 1.17.2.2 nathanw }
2262 1.17.2.2 nathanw
2263 1.17.2.2 nathanw static int
2264 1.17.2.2 nathanw wi_media_change(ifp)
2265 1.17.2.2 nathanw struct ifnet *ifp;
2266 1.17.2.2 nathanw {
2267 1.17.2.2 nathanw struct wi_softc *sc = ifp->if_softc;
2268 1.17.2.2 nathanw int otype = sc->wi_ptype;
2269 1.17.2.2 nathanw int orate = sc->wi_tx_rate;
2270 1.17.2.2 nathanw
2271 1.17.2.2 nathanw if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
2272 1.17.2.2 nathanw sc->wi_ptype = WI_PORTTYPE_ADHOC;
2273 1.17.2.2 nathanw else
2274 1.17.2.2 nathanw sc->wi_ptype = WI_PORTTYPE_BSS;
2275 1.17.2.2 nathanw
2276 1.17.2.2 nathanw switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
2277 1.17.2.2 nathanw case IFM_IEEE80211_DS1:
2278 1.17.2.2 nathanw sc->wi_tx_rate = 1;
2279 1.17.2.2 nathanw break;
2280 1.17.2.2 nathanw case IFM_IEEE80211_DS2:
2281 1.17.2.2 nathanw sc->wi_tx_rate = 2;
2282 1.17.2.2 nathanw break;
2283 1.17.2.2 nathanw case IFM_AUTO:
2284 1.17.2.2 nathanw sc->wi_tx_rate = 3;
2285 1.17.2.2 nathanw break;
2286 1.17.2.10 nathanw case IFM_IEEE80211_DS5:
2287 1.17.2.10 nathanw sc->wi_tx_rate = 5;
2288 1.17.2.10 nathanw break;
2289 1.17.2.2 nathanw case IFM_IEEE80211_DS11:
2290 1.17.2.2 nathanw sc->wi_tx_rate = 11;
2291 1.17.2.2 nathanw break;
2292 1.17.2.2 nathanw }
2293 1.17.2.2 nathanw
2294 1.17.2.2 nathanw if (sc->sc_enabled != 0) {
2295 1.17.2.2 nathanw if (otype != sc->wi_ptype ||
2296 1.17.2.2 nathanw orate != sc->wi_tx_rate)
2297 1.17.2.2 nathanw wi_init(ifp);
2298 1.17.2.2 nathanw }
2299 1.17.2.2 nathanw
2300 1.17.2.2 nathanw ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
2301 1.17.2.2 nathanw
2302 1.17.2.2 nathanw return (0);
2303 1.17.2.2 nathanw }
2304 1.17.2.2 nathanw
2305 1.17.2.2 nathanw static void
2306 1.17.2.2 nathanw wi_media_status(ifp, imr)
2307 1.17.2.2 nathanw struct ifnet *ifp;
2308 1.17.2.2 nathanw struct ifmediareq *imr;
2309 1.17.2.2 nathanw {
2310 1.17.2.2 nathanw struct wi_softc *sc = ifp->if_softc;
2311 1.17.2.2 nathanw
2312 1.17.2.2 nathanw if (sc->sc_enabled == 0) {
2313 1.17.2.2 nathanw imr->ifm_active = IFM_IEEE80211|IFM_NONE;
2314 1.17.2.2 nathanw imr->ifm_status = 0;
2315 1.17.2.2 nathanw return;
2316 1.17.2.2 nathanw }
2317 1.17.2.2 nathanw
2318 1.17.2.2 nathanw imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
2319 1.17.2.2 nathanw imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
2320 1.17.2.2 nathanw }
2321 1.17.2.2 nathanw
2322 1.17.2.2 nathanw static int
2323 1.17.2.2 nathanw wi_set_nwkey(sc, nwkey)
2324 1.17.2.2 nathanw struct wi_softc *sc;
2325 1.17.2.2 nathanw struct ieee80211_nwkey *nwkey;
2326 1.17.2.2 nathanw {
2327 1.17.2.3 nathanw int i, error;
2328 1.17.2.3 nathanw size_t len;
2329 1.17.2.2 nathanw struct wi_req wreq;
2330 1.17.2.2 nathanw struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
2331 1.17.2.2 nathanw
2332 1.17.2.2 nathanw if (!sc->wi_has_wep)
2333 1.17.2.2 nathanw return ENODEV;
2334 1.17.2.2 nathanw if (nwkey->i_defkid <= 0 ||
2335 1.17.2.2 nathanw nwkey->i_defkid > IEEE80211_WEP_NKID)
2336 1.17.2.2 nathanw return EINVAL;
2337 1.17.2.2 nathanw memcpy(wk, &sc->wi_keys, sizeof(*wk));
2338 1.17.2.2 nathanw for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2339 1.17.2.2 nathanw if (nwkey->i_key[i].i_keydat == NULL)
2340 1.17.2.2 nathanw continue;
2341 1.17.2.2 nathanw len = nwkey->i_key[i].i_keylen;
2342 1.17.2.2 nathanw if (len > sizeof(wk->wi_keys[i].wi_keydat))
2343 1.17.2.2 nathanw return EINVAL;
2344 1.17.2.2 nathanw error = copyin(nwkey->i_key[i].i_keydat,
2345 1.17.2.2 nathanw wk->wi_keys[i].wi_keydat, len);
2346 1.17.2.2 nathanw if (error)
2347 1.17.2.2 nathanw return error;
2348 1.17.2.2 nathanw wk->wi_keys[i].wi_keylen = htole16(len);
2349 1.17.2.2 nathanw }
2350 1.17.2.2 nathanw
2351 1.17.2.2 nathanw wk->wi_len = (sizeof(*wk) / 2) + 1;
2352 1.17.2.2 nathanw wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
2353 1.17.2.2 nathanw if (sc->sc_enabled != 0) {
2354 1.17.2.2 nathanw error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2355 1.17.2.2 nathanw if (error)
2356 1.17.2.2 nathanw return error;
2357 1.17.2.2 nathanw }
2358 1.17.2.2 nathanw error = wi_setdef(sc, &wreq);
2359 1.17.2.2 nathanw if (error)
2360 1.17.2.2 nathanw return error;
2361 1.17.2.2 nathanw
2362 1.17.2.2 nathanw wreq.wi_len = 2;
2363 1.17.2.2 nathanw wreq.wi_type = WI_RID_TX_CRYPT_KEY;
2364 1.17.2.2 nathanw wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
2365 1.17.2.2 nathanw if (sc->sc_enabled != 0) {
2366 1.17.2.2 nathanw error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2367 1.17.2.2 nathanw if (error)
2368 1.17.2.2 nathanw return error;
2369 1.17.2.2 nathanw }
2370 1.17.2.2 nathanw error = wi_setdef(sc, &wreq);
2371 1.17.2.2 nathanw if (error)
2372 1.17.2.2 nathanw return error;
2373 1.17.2.2 nathanw
2374 1.17.2.2 nathanw wreq.wi_type = WI_RID_ENCRYPTION;
2375 1.17.2.2 nathanw wreq.wi_val[0] = htole16(nwkey->i_wepon);
2376 1.17.2.2 nathanw if (sc->sc_enabled != 0) {
2377 1.17.2.2 nathanw error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2378 1.17.2.2 nathanw if (error)
2379 1.17.2.2 nathanw return error;
2380 1.17.2.2 nathanw }
2381 1.17.2.2 nathanw error = wi_setdef(sc, &wreq);
2382 1.17.2.2 nathanw if (error)
2383 1.17.2.2 nathanw return error;
2384 1.17.2.2 nathanw
2385 1.17.2.2 nathanw if (sc->sc_enabled != 0)
2386 1.17.2.2 nathanw wi_init(&sc->sc_ethercom.ec_if);
2387 1.17.2.2 nathanw return 0;
2388 1.17.2.2 nathanw }
2389 1.17.2.2 nathanw
2390 1.17.2.2 nathanw static int
2391 1.17.2.2 nathanw wi_get_nwkey(sc, nwkey)
2392 1.17.2.2 nathanw struct wi_softc *sc;
2393 1.17.2.2 nathanw struct ieee80211_nwkey *nwkey;
2394 1.17.2.2 nathanw {
2395 1.17.2.2 nathanw int i, len, error;
2396 1.17.2.2 nathanw struct wi_ltv_keys *wk = &sc->wi_keys;
2397 1.17.2.2 nathanw
2398 1.17.2.2 nathanw if (!sc->wi_has_wep)
2399 1.17.2.2 nathanw return ENODEV;
2400 1.17.2.2 nathanw nwkey->i_wepon = sc->wi_use_wep;
2401 1.17.2.2 nathanw nwkey->i_defkid = sc->wi_tx_key + 1;
2402 1.17.2.2 nathanw
2403 1.17.2.2 nathanw /* do not show any keys to non-root user */
2404 1.17.2.14 nathanw error = suser(curproc->p_ucred, &curproc->p_acflag);
2405 1.17.2.2 nathanw for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2406 1.17.2.2 nathanw if (nwkey->i_key[i].i_keydat == NULL)
2407 1.17.2.2 nathanw continue;
2408 1.17.2.2 nathanw /* error holds results of suser() for the first time */
2409 1.17.2.2 nathanw if (error)
2410 1.17.2.2 nathanw return error;
2411 1.17.2.2 nathanw len = le16toh(wk->wi_keys[i].wi_keylen);
2412 1.17.2.2 nathanw if (nwkey->i_key[i].i_keylen < len)
2413 1.17.2.2 nathanw return ENOSPC;
2414 1.17.2.2 nathanw nwkey->i_key[i].i_keylen = len;
2415 1.17.2.2 nathanw error = copyout(wk->wi_keys[i].wi_keydat,
2416 1.17.2.2 nathanw nwkey->i_key[i].i_keydat, len);
2417 1.17.2.2 nathanw if (error)
2418 1.17.2.2 nathanw return error;
2419 1.17.2.2 nathanw }
2420 1.17.2.2 nathanw return 0;
2421 1.17.2.2 nathanw }
2422 1.17.2.2 nathanw
2423 1.17.2.2 nathanw static int
2424 1.17.2.2 nathanw wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
2425 1.17.2.2 nathanw {
2426 1.17.2.2 nathanw
2427 1.17.2.2 nathanw sc->wi_pm_enabled = power->i_enabled;
2428 1.17.2.2 nathanw sc->wi_max_sleep = power->i_maxsleep;
2429 1.17.2.2 nathanw
2430 1.17.2.2 nathanw if (sc->sc_enabled)
2431 1.17.2.2 nathanw return (wi_init(&sc->sc_ethercom.ec_if));
2432 1.17.2.2 nathanw
2433 1.17.2.2 nathanw return (0);
2434 1.17.2.2 nathanw }
2435 1.17.2.2 nathanw
2436 1.17.2.2 nathanw static int
2437 1.17.2.2 nathanw wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
2438 1.17.2.2 nathanw {
2439 1.17.2.2 nathanw
2440 1.17.2.2 nathanw power->i_enabled = sc->wi_pm_enabled;
2441 1.17.2.2 nathanw power->i_maxsleep = sc->wi_max_sleep;
2442 1.17.2.2 nathanw
2443 1.17.2.2 nathanw return (0);
2444 1.17.2.2 nathanw }
2445