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