1 | /* $NetBSD: if_ray.c,v 1.84 2016/07/07 06:55:42 msaitoh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2000 Christian E. Hopps |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of the author nor the names of any co-contributors |
16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Driver for the Raylink (Raytheon) / WebGear IEEE 802.11 (FH) WLANs |
34 | * |
35 | * 2-way communication with the card is through command structures |
36 | * stored in shared ram. To communicate with the card a free |
37 | * command structure is filled in and then the card is interrupted. |
38 | * The card does the same with a different set of command structures. |
39 | * Only one command can be processed at a time. This is indicated |
40 | * by the interrupt having not been cleared since it was last set. |
41 | * The bit is cleared when the command has been processed (although |
42 | * it may not yet be complete). |
43 | * |
44 | * This driver was only tested with the Aviator 2.4 wireless |
45 | * The author didn't have the pro version or raylink to test |
46 | * with. |
47 | * |
48 | * N.B. Its unclear yet whether the Aviator 2.4 cards interoperate |
49 | * with other 802.11 FH 2Mbps cards, since this was also untested. |
50 | * Given the nature of the buggy build 4 firmware there may be problems. |
51 | * |
52 | * Authentication added by Steve Weiss <srw@alum.mit.edu> based on |
53 | * advice from Corey Thomas (author of the Linux RayLink driver). |
54 | * Authentication is currently limited to adhoc networks, and was |
55 | * added to support a requirement of the newest Windows drivers for |
56 | * the RayLink. Tested with Aviator Pro (firmware 5.63) on Win98. |
57 | */ |
58 | |
59 | #include <sys/cdefs.h> |
60 | __KERNEL_RCSID(0, "$NetBSD: if_ray.c,v 1.84 2016/07/07 06:55:42 msaitoh Exp $" ); |
61 | |
62 | #include "opt_inet.h" |
63 | |
64 | #include <sys/param.h> |
65 | #include <sys/systm.h> |
66 | #include <sys/callout.h> |
67 | #include <sys/mbuf.h> |
68 | #include <sys/socket.h> |
69 | #include <sys/ioctl.h> |
70 | #include <sys/errno.h> |
71 | #include <sys/device.h> |
72 | #include <sys/kernel.h> |
73 | #include <sys/proc.h> |
74 | |
75 | #include <net/if.h> |
76 | #include <net/if_dl.h> |
77 | #include <net/if_ether.h> |
78 | #include <net/if_media.h> |
79 | #include <net/if_llc.h> |
80 | #include <net80211/ieee80211.h> |
81 | #include <net80211/ieee80211_ioctl.h> |
82 | #include <net/if_media.h> |
83 | |
84 | #ifdef INET |
85 | #include <netinet/in.h> |
86 | #include <netinet/in_systm.h> |
87 | #include <netinet/in_var.h> |
88 | #include <netinet/ip.h> |
89 | #include <netinet/if_inarp.h> |
90 | #endif |
91 | |
92 | #include <net/bpf.h> |
93 | #include <net/bpfdesc.h> |
94 | |
95 | #include <sys/cpu.h> |
96 | #include <sys/bus.h> |
97 | #include <sys/intr.h> |
98 | |
99 | #include <dev/pcmcia/pcmciareg.h> |
100 | #include <dev/pcmcia/pcmciavar.h> |
101 | #include <dev/pcmcia/pcmciadevs.h> |
102 | |
103 | #include <dev/pcmcia/if_rayreg.h> |
104 | |
105 | #define RAY_DEBUG |
106 | |
107 | #ifndef RAY_PID_COUNTRY_CODE_DEFAULT |
108 | #define RAY_PID_COUNTRY_CODE_DEFAULT RAY_PID_COUNTRY_CODE_USA |
109 | #endif |
110 | |
111 | /* amount of time to poll for non-return of certain command status */ |
112 | #ifndef RAY_CHECK_CCS_TIMEOUT |
113 | #define RAY_CHECK_CCS_TIMEOUT (hz / 2) |
114 | #endif |
115 | |
116 | /* ammount of time to consider start/join failed */ |
117 | #ifndef RAY_START_TIMEOUT |
118 | #define RAY_START_TIMEOUT (30 * hz) |
119 | #endif |
120 | |
121 | /* |
122 | * if a command cannot execute because device is busy try later |
123 | * this is also done after interrupts and other command timeouts |
124 | * so we can use a large value safely. |
125 | */ |
126 | #ifndef RAY_CHECK_SCHED_TIMEOUT |
127 | #define RAY_CHECK_SCHED_TIMEOUT (hz) /* XXX 5 */ |
128 | #endif |
129 | |
130 | #ifndef RAY_MODE_DEFAULT |
131 | #define RAY_MODE_DEFAULT SC_MODE_ADHOC |
132 | #endif |
133 | |
134 | #ifndef RAY_DEF_NWID |
135 | #define RAY_DEF_NWID "NETWORK_NAME" |
136 | #endif |
137 | |
138 | /* |
139 | * The number of times the HW is reset in 30s before disabling. |
140 | * This is needed because resets take ~2s and currently pcmcia |
141 | * spins for the reset. |
142 | */ |
143 | #ifndef RAY_MAX_RESETS |
144 | #define RAY_MAX_RESETS 3 |
145 | #endif |
146 | |
147 | /* |
148 | * Types |
149 | */ |
150 | |
151 | struct ray_softc { |
152 | device_t sc_dev; |
153 | struct ethercom sc_ec; |
154 | struct ifmedia sc_media; |
155 | |
156 | struct pcmcia_function *sc_pf; |
157 | void *sc_ih; |
158 | int sc_attached; |
159 | |
160 | int sc_resetloop; |
161 | |
162 | struct callout sc_check_ccs_ch; |
163 | struct callout sc_check_scheduled_ch; |
164 | struct callout sc_reset_resetloop_ch; |
165 | struct callout sc_disable_ch; |
166 | struct callout sc_start_join_timo_ch; |
167 | |
168 | struct ray_ecf_startup sc_ecf_startup; |
169 | struct ray_startup_params_head sc_startup; |
170 | union { |
171 | struct ray_startup_params_tail_5 u_params_5; |
172 | struct ray_startup_params_tail_4 u_params_4; |
173 | } sc_u; |
174 | |
175 | u_int8_t sc_ccsinuse[64]; /* ccs in use -- not for tx */ |
176 | u_int sc_txfree; /* a free count for efficiency */ |
177 | |
178 | u_int8_t sc_bssid[ETHER_ADDR_LEN]; /* current net values */ |
179 | u_int8_t sc_authid[ETHER_ADDR_LEN]; /* ID of authenticating |
180 | station */ |
181 | struct ieee80211_nwid sc_cnwid; /* last nwid */ |
182 | struct ieee80211_nwid sc_dnwid; /* desired nwid */ |
183 | u_int8_t sc_omode; /* old operating mode SC_MODE_xx */ |
184 | u_int8_t sc_mode; /* current operating mode SC_MODE_xx */ |
185 | u_int8_t sc_countrycode; /* current country code */ |
186 | u_int8_t sc_dcountrycode; /* desired country code */ |
187 | int sc_havenet; /* true if we have acquired a network */ |
188 | bus_size_t sc_txpad; /* tib size plus "phy" size */ |
189 | u_int8_t sc_deftxrate; /* default transfer rate */ |
190 | u_int8_t sc_encrypt; |
191 | u_int8_t sc_authstate; /* authentication state */ |
192 | |
193 | int sc_promisc; /* current set value */ |
194 | int sc_running; /* things we are doing */ |
195 | int sc_scheduled; /* things we need to do */ |
196 | int sc_timoneed; /* set if timeout is sched */ |
197 | int sc_timocheck; /* set if timeout is sched */ |
198 | bus_size_t sc_startccs; /* ccs of start/join */ |
199 | u_int sc_startcmd; /* cmd (start | join) */ |
200 | |
201 | int sc_checkcounters; |
202 | u_int64_t sc_rxoverflow; |
203 | u_int64_t sc_rxcksum; |
204 | u_int64_t sc_rxhcksum; |
205 | u_int8_t sc_rxnoise; |
206 | |
207 | /* use to return values to the user */ |
208 | struct ray_param_req *sc_repreq; |
209 | struct ray_param_req *sc_updreq; |
210 | |
211 | bus_space_tag_t sc_memt; |
212 | bus_space_handle_t sc_memh; |
213 | |
214 | #ifdef RAY_DO_SIGLEV |
215 | struct ray_siglev sc_siglevs[RAY_NSIGLEVRECS]; |
216 | #endif |
217 | }; |
218 | #define sc_ccrt sc_pf->pf_ccrt |
219 | #define sc_ccrh sc_pf->pf_ccrh |
220 | #define sc_ccroff sc_pf->pf_ccr_offset |
221 | #define sc_startup_4 sc_u.u_params_4 |
222 | #define sc_startup_5 sc_u.u_params_5 |
223 | #define sc_version sc_ecf_startup.e_fw_build_string |
224 | #define sc_tibsize sc_ecf_startup.e_tib_size |
225 | #define sc_if sc_ec.ec_if |
226 | |
227 | /* modes of operation */ |
228 | #define SC_MODE_ADHOC 0 /* ad-hoc mode */ |
229 | #define SC_MODE_INFRA 1 /* infrastructure mode */ |
230 | |
231 | /* commands -- priority given to LSB */ |
232 | #define SCP_FIRST 0x0001 |
233 | #define SCP_UPDATESUBCMD 0x0001 |
234 | #define SCP_STARTASSOC 0x0002 |
235 | #define SCP_REPORTPARAMS 0x0004 |
236 | #define SCP_IFSTART 0x0008 |
237 | |
238 | /* update sub commands -- issues are serialized priority to LSB */ |
239 | #define SCP_UPD_FIRST 0x0100 |
240 | #define SCP_UPD_STARTUP 0x0100 |
241 | #define SCP_UPD_STARTJOIN 0x0200 |
242 | #define SCP_UPD_PROMISC 0x0400 |
243 | #define SCP_UPD_MCAST 0x0800 |
244 | #define SCP_UPD_UPDATEPARAMS 0x1000 |
245 | #define SCP_UPD_SHIFT 8 |
246 | #define SCP_UPD_MASK 0xff00 |
247 | |
248 | /* these command (a subset of the update set) require timeout checking */ |
249 | #define SCP_TIMOCHECK_CMD_MASK \ |
250 | (SCP_UPD_UPDATEPARAMS | SCP_UPD_STARTUP | SCP_UPD_MCAST | \ |
251 | SCP_UPD_PROMISC) |
252 | |
253 | |
254 | #define IFM_ADHOC \ |
255 | IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_FH2, IFM_IEEE80211_ADHOC, 0) |
256 | #define IFM_INFRA \ |
257 | IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_FH2, 0, 0) |
258 | |
259 | typedef void (*ray_cmd_func_t)(struct ray_softc *); |
260 | |
261 | #define SC_BUILD_5 0x5 |
262 | #define SC_BUILD_4 0x55 |
263 | |
264 | /* sc_authstate */ |
265 | #define RAY_AUTH_UNAUTH 0 |
266 | #define RAY_AUTH_WAITING 1 |
267 | #define RAY_AUTH_AUTH 2 |
268 | #define RAY_AUTH_NEEDED 3 |
269 | |
270 | #define OPEN_AUTH_REQUEST 1 |
271 | #define OPEN_AUTH_RESPONSE 2 |
272 | #define BROADCAST_DEAUTH 0xc0 |
273 | |
274 | static int ray_alloc_ccs(struct ray_softc *, bus_size_t *, u_int, u_int); |
275 | static bus_size_t ray_fill_in_tx_ccs(struct ray_softc *, size_t, |
276 | u_int, u_int); |
277 | static int ray_validate_config(struct pcmcia_config_entry *); |
278 | static void ray_attach(device_t, device_t, void *); |
279 | static ray_cmd_func_t ray_ccs_done(struct ray_softc *, bus_size_t); |
280 | static void ray_check_ccs(void *); |
281 | static void ray_check_scheduled(void *); |
282 | static void ray_cmd_cancel(struct ray_softc *, int); |
283 | static void ray_cmd_schedule(struct ray_softc *, int); |
284 | static void ray_cmd_ran(struct ray_softc *, int); |
285 | static int ray_cmd_is_running(struct ray_softc *, int); |
286 | static int ray_cmd_is_scheduled(struct ray_softc *, int); |
287 | static void ray_cmd_done(struct ray_softc *, int); |
288 | static int ray_detach(device_t, int); |
289 | static int ray_activate(device_t, enum devact); |
290 | static void ray_disable(struct ray_softc *); |
291 | static void ray_download_params(struct ray_softc *); |
292 | static int ray_enable(struct ray_softc *); |
293 | static u_int ray_find_free_tx_ccs(struct ray_softc *, u_int); |
294 | static u_int8_t ray_free_ccs(struct ray_softc *, bus_size_t); |
295 | static void ray_free_ccs_chain(struct ray_softc *, u_int); |
296 | static void ray_if_start(struct ifnet *); |
297 | static void ray_if_stop(struct ifnet *, int); |
298 | static int ray_init(struct ray_softc *); |
299 | static int ray_intr(void *); |
300 | static void ray_intr_start(struct ray_softc *); |
301 | static int ray_ioctl(struct ifnet *, u_long, void *); |
302 | static int ray_issue_cmd(struct ray_softc *, bus_size_t, u_int); |
303 | static int ray_match(device_t, cfdata_t, void *); |
304 | static int ray_media_change(struct ifnet *); |
305 | static void ray_media_status(struct ifnet *, struct ifmediareq *); |
306 | static ray_cmd_func_t ray_rccs_intr(struct ray_softc *, bus_size_t); |
307 | static void ray_read_region(struct ray_softc *, bus_size_t,void *,size_t); |
308 | static void ray_recv(struct ray_softc *, bus_size_t); |
309 | static void ray_recv_auth(struct ray_softc *, struct ieee80211_frame *); |
310 | static void ray_report_params(struct ray_softc *); |
311 | static void ray_reset(struct ray_softc *); |
312 | static void ray_reset_resetloop(void *); |
313 | static int ray_send_auth(struct ray_softc *, u_int8_t *, u_int8_t); |
314 | static void ray_set_pending(struct ray_softc *, u_int); |
315 | static int ray_simple_cmd(struct ray_softc *, u_int, u_int); |
316 | static void ray_start_assoc(struct ray_softc *); |
317 | static void ray_start_join_net(struct ray_softc *); |
318 | static ray_cmd_func_t ray_start_join_net_done(struct ray_softc *, |
319 | u_int, bus_size_t, u_int); |
320 | static void ray_start_join_timo(void *); |
321 | static void ray_stop(struct ray_softc *); |
322 | static void ray_update_error_counters(struct ray_softc *); |
323 | static void ray_update_mcast(struct ray_softc *); |
324 | static ray_cmd_func_t ray_update_params_done(struct ray_softc *, |
325 | bus_size_t, u_int); |
326 | static void ray_update_params(struct ray_softc *); |
327 | static void ray_update_promisc(struct ray_softc *); |
328 | static void ray_update_subcmd(struct ray_softc *); |
329 | static int ray_user_report_params(struct ray_softc *, |
330 | struct ray_param_req *); |
331 | static int ray_user_update_params(struct ray_softc *, |
332 | struct ray_param_req *); |
333 | static void ray_write_region(struct ray_softc *,bus_size_t,void *,size_t); |
334 | |
335 | #ifdef RAY_DO_SIGLEV |
336 | static void ray_update_siglev(struct ray_softc *, u_int8_t *, u_int8_t); |
337 | #endif |
338 | |
339 | #ifdef RAY_DEBUG |
340 | static int ray_debug = 0; |
341 | static int ray_debug_xmit_sum = 0; |
342 | static int ray_debug_dump_desc = 0; |
343 | static int ray_debug_dump_rx = 0; |
344 | static int ray_debug_dump_tx = 0; |
345 | static struct timeval rtv, tv1, tv2, *ttp, *ltp; |
346 | #define RAY_DPRINTF(x) do { if (ray_debug) { \ |
347 | struct timeval *ttmp; \ |
348 | microtime(ttp); \ |
349 | timersub(ttp, ltp, &rtv); \ |
350 | ttmp = ttp; ttp = ltp; ltp = ttmp; \ |
351 | printf("%ld:%ld %ld:%06ld: ", \ |
352 | (long int)ttp->tv_sec, \ |
353 | (long int)ttp->tv_usec, \ |
354 | (long int)rtv.tv_sec, \ |
355 | (long int)rtv.tv_usec); \ |
356 | printf x ; \ |
357 | } } while (0) |
358 | #define RAY_DPRINTF_XMIT(x) do { if (ray_debug_xmit_sum) { \ |
359 | struct timeval *ttmp; \ |
360 | microtime(ttp); \ |
361 | timersub(ttp, ltp, &rtv); \ |
362 | ttmp = ttp; ttp = ltp; ltp = ttmp; \ |
363 | printf("%ld:%ld %ld:%06ld: ", \ |
364 | (long int)ttp->tv_sec, \ |
365 | (long int)ttp->tv_usec, \ |
366 | (long int)rtv.tv_sec, \ |
367 | (long int)rtv.tv_usec); \ |
368 | printf x ; \ |
369 | } } while (0) |
370 | |
371 | #define HEXDF_NOCOMPRESS 0x1 |
372 | #define HEXDF_NOOFFSET 0x2 |
373 | #define HEXDF_NOASCII 0x4 |
374 | void hexdump(const u_int8_t *, int, int, int, int); |
375 | static void ray_dump_mbuf(struct ray_softc *, struct mbuf *); |
376 | |
377 | #else /* !RAY_DEBUG */ |
378 | |
379 | #define RAY_DPRINTF(x) |
380 | #define RAY_DPRINTF_XMIT(x) |
381 | |
382 | #endif /* !RAY_DEBUG */ |
383 | |
384 | /* |
385 | * macros for writing to various regions in the mapped memory space |
386 | */ |
387 | |
388 | /* use already mapped ccrt */ |
389 | #define REG_WRITE(sc, off, val) \ |
390 | bus_space_write_1((sc)->sc_ccrt, (sc)->sc_ccrh, ((sc)->sc_ccroff + (off)), (val)) |
391 | |
392 | #define REG_READ(sc, off) \ |
393 | bus_space_read_1((sc)->sc_ccrt, (sc)->sc_ccrh, ((sc)->sc_ccroff + (off))) |
394 | |
395 | #define SRAM_READ_1(sc, off) \ |
396 | ((u_int8_t)bus_space_read_1((sc)->sc_memt, (sc)->sc_memh, (off))) |
397 | |
398 | #define SRAM_READ_FIELD_1(sc, off, s, f) \ |
399 | SRAM_READ_1(sc, (off) + offsetof(struct s, f)) |
400 | |
401 | #define SRAM_READ_FIELD_2(sc, off, s, f) \ |
402 | ((((u_int16_t)SRAM_READ_1(sc, (off) + offsetof(struct s, f)) << 8) \ |
403 | |(SRAM_READ_1(sc, (off) + 1 + offsetof(struct s, f))))) |
404 | |
405 | #define SRAM_READ_FIELD_N(sc, off, s, f, p, n) \ |
406 | ray_read_region(sc, (off) + offsetof(struct s, f), (p), (n)) |
407 | |
408 | #define SRAM_WRITE_1(sc, off, val) \ |
409 | bus_space_write_1((sc)->sc_memt, (sc)->sc_memh, (off), (val)) |
410 | |
411 | #define SRAM_WRITE_FIELD_1(sc, off, s, f, v) \ |
412 | SRAM_WRITE_1(sc, (off) + offsetof(struct s, f), (v)) |
413 | |
414 | #define SRAM_WRITE_FIELD_2(sc, off, s, f, v) do { \ |
415 | SRAM_WRITE_1(sc, (off) + offsetof(struct s, f), (((v) >> 8 ) & 0xff)); \ |
416 | SRAM_WRITE_1(sc, (off) + 1 + offsetof(struct s, f), ((v) & 0xff)); \ |
417 | } while (0) |
418 | |
419 | #define SRAM_WRITE_FIELD_N(sc, off, s, f, p, n) \ |
420 | ray_write_region(sc, (off) + offsetof(struct s, f), (p), (n)) |
421 | |
422 | /* |
423 | * Macros of general usefulness |
424 | */ |
425 | |
426 | #define M_PULLUP(m, s) do { \ |
427 | if ((m)->m_len < (s)) \ |
428 | (m) = m_pullup((m), (s)); \ |
429 | } while (0) |
430 | |
431 | #define RAY_ECF_READY(sc) (!(REG_READ(sc, RAY_ECFIR) & RAY_ECSIR_IRQ)) |
432 | #define RAY_ECF_START_CMD(sc) REG_WRITE(sc, RAY_ECFIR, RAY_ECSIR_IRQ) |
433 | #define RAY_GET_INDEX(ccs) (((ccs) - RAY_CCS_BASE) / RAY_CCS_SIZE) |
434 | #define RAY_GET_CCS(i) (RAY_CCS_BASE + (i) * RAY_CCS_SIZE) |
435 | |
436 | /* |
437 | * Globals |
438 | */ |
439 | |
440 | static u_int8_t llc_snapid[6] = { LLC_SNAP_LSAP, LLC_SNAP_LSAP, LLC_UI, }; |
441 | |
442 | /* based on bit index in SCP_xx */ |
443 | static ray_cmd_func_t ray_cmdtab[] = { |
444 | ray_update_subcmd, /* SCP_UPDATESUBCMD */ |
445 | ray_start_assoc, /* SCP_STARTASSOC */ |
446 | ray_report_params, /* SCP_REPORTPARAMS */ |
447 | ray_intr_start /* SCP_IFSTART */ |
448 | }; |
449 | static int ray_ncmdtab = sizeof(ray_cmdtab) / sizeof(*ray_cmdtab); |
450 | |
451 | static ray_cmd_func_t ray_subcmdtab[] = { |
452 | ray_download_params, /* SCP_UPD_STARTUP */ |
453 | ray_start_join_net, /* SCP_UPD_STARTJOIN */ |
454 | ray_update_promisc, /* SCP_UPD_PROMISC */ |
455 | ray_update_mcast, /* SCP_UPD_MCAST */ |
456 | ray_update_params /* SCP_UPD_UPDATEPARAMS */ |
457 | }; |
458 | static int ray_nsubcmdtab = sizeof(ray_subcmdtab) / sizeof(*ray_subcmdtab); |
459 | |
460 | /* autoconf information */ |
461 | CFATTACH_DECL_NEW(ray, sizeof(struct ray_softc), |
462 | ray_match, ray_attach, ray_detach, ray_activate); |
463 | |
464 | /* |
465 | * Config Routines |
466 | */ |
467 | |
468 | static int |
469 | ray_match(device_t parent, cfdata_t match, |
470 | void *aux) |
471 | { |
472 | struct pcmcia_attach_args *pa = aux; |
473 | |
474 | #ifdef RAY_DEBUG |
475 | if (!ltp) { |
476 | /* initialize timestamp XXX */ |
477 | ttp = &tv1; |
478 | ltp = &tv2; |
479 | microtime(ltp); |
480 | } |
481 | #endif |
482 | return (pa->manufacturer == PCMCIA_VENDOR_RAYTHEON |
483 | && pa->product == PCMCIA_PRODUCT_RAYTHEON_WLAN); |
484 | } |
485 | |
486 | static int |
487 | ray_validate_config(struct pcmcia_config_entry *cfe) |
488 | { |
489 | if (cfe->iftype != PCMCIA_IFTYPE_IO || |
490 | cfe->num_memspace != 1 || |
491 | cfe->num_iospace != 0 || |
492 | cfe->memspace[0].length != RAY_SRAM_MEM_SIZE) |
493 | return (EINVAL); |
494 | return (0); |
495 | } |
496 | |
497 | static void |
498 | ray_attach(device_t parent, device_t self, void *aux) |
499 | { |
500 | struct ray_softc *sc = device_private(self); |
501 | struct pcmcia_attach_args *pa = aux; |
502 | struct ifnet *ifp = &sc->sc_if; |
503 | struct pcmcia_config_entry *cfe; |
504 | struct ray_ecf_startup *ep; |
505 | int error; |
506 | |
507 | sc->sc_dev = self; |
508 | sc->sc_pf = pa->pf; |
509 | |
510 | /*XXXmem8|common*/ |
511 | error = pcmcia_function_configure(pa->pf, ray_validate_config); |
512 | if (error) { |
513 | aprint_error_dev(self, "configure failed, error=%d\n" , error); |
514 | return; |
515 | } |
516 | |
517 | cfe = pa->pf->cfe; |
518 | sc->sc_memt = cfe->memspace[0].handle.memt; |
519 | sc->sc_memh = cfe->memspace[0].handle.memh; |
520 | |
521 | callout_init(&sc->sc_reset_resetloop_ch, 0); |
522 | callout_init(&sc->sc_disable_ch, 0); |
523 | callout_init(&sc->sc_start_join_timo_ch, 0); |
524 | |
525 | error = ray_enable(sc); |
526 | if (error) |
527 | goto fail; |
528 | |
529 | /* get startup results */ |
530 | ep = &sc->sc_ecf_startup; |
531 | ray_read_region(sc, RAY_ECF_TO_HOST_BASE, ep, |
532 | sizeof(sc->sc_ecf_startup)); |
533 | |
534 | /* check to see that card initialized properly */ |
535 | if (ep->e_status != RAY_ECFS_CARD_OK) { |
536 | aprint_error_dev(self, "card failed self test: status %d\n" , |
537 | sc->sc_ecf_startup.e_status); |
538 | goto fail2; |
539 | } |
540 | |
541 | /* check firmware version */ |
542 | if (sc->sc_version != SC_BUILD_4 && sc->sc_version != SC_BUILD_5) { |
543 | aprint_error_dev(self, "unsupported firmware version %d\n" , |
544 | ep->e_fw_build_string); |
545 | goto fail2; |
546 | } |
547 | |
548 | /* clear any interrupt if present */ |
549 | REG_WRITE(sc, RAY_HCSIR, 0); |
550 | |
551 | /* |
552 | * set the parameters that will survive stop/init |
553 | */ |
554 | memset(&sc->sc_dnwid, 0, sizeof(sc->sc_dnwid)); |
555 | sc->sc_dnwid.i_len = strlen(RAY_DEF_NWID); |
556 | if (sc->sc_dnwid.i_len > IEEE80211_NWID_LEN) |
557 | sc->sc_dnwid.i_len = IEEE80211_NWID_LEN; |
558 | if (sc->sc_dnwid.i_len > 0) |
559 | memcpy(sc->sc_dnwid.i_nwid, RAY_DEF_NWID, sc->sc_dnwid.i_len); |
560 | memcpy(&sc->sc_cnwid, &sc->sc_dnwid, sizeof(sc->sc_cnwid)); |
561 | sc->sc_omode = sc->sc_mode = RAY_MODE_DEFAULT; |
562 | sc->sc_countrycode = sc->sc_dcountrycode = |
563 | RAY_PID_COUNTRY_CODE_DEFAULT; |
564 | |
565 | /* |
566 | * attach the interface |
567 | */ |
568 | /* The version isn't the most accurate way, but it's easy. */ |
569 | aprint_normal_dev(self, "firmware version %d\n" , |
570 | sc->sc_version); |
571 | if (sc->sc_version != SC_BUILD_4) |
572 | aprint_normal_dev(self, |
573 | "supported rates %0x:%0x:%0x:%0x:%0x:%0x:%0x:%0x\n" , |
574 | ep->e_rates[0], ep->e_rates[1], |
575 | ep->e_rates[2], ep->e_rates[3], ep->e_rates[4], |
576 | ep->e_rates[5], ep->e_rates[6], ep->e_rates[7]); |
577 | aprint_normal_dev(self, "802.11 address %s\n" , |
578 | ether_sprintf(ep->e_station_addr)); |
579 | |
580 | memcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); |
581 | ifp->if_softc = sc; |
582 | ifp->if_start = ray_if_start; |
583 | ifp->if_stop = ray_if_stop; |
584 | ifp->if_ioctl = ray_ioctl; |
585 | ifp->if_mtu = ETHERMTU; |
586 | ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; |
587 | IFQ_SET_READY(&ifp->if_snd); |
588 | |
589 | if_attach(ifp); |
590 | ether_ifattach(ifp, ep->e_station_addr); |
591 | /* need enough space for ieee80211_header + (snap or e2) */ |
592 | ifp->if_hdrlen = |
593 | sizeof(struct ieee80211_frame) + sizeof(struct ether_header); |
594 | |
595 | ifmedia_init(&sc->sc_media, 0, ray_media_change, ray_media_status); |
596 | ifmedia_add(&sc->sc_media, IFM_ADHOC, 0, 0); |
597 | ifmedia_add(&sc->sc_media, IFM_INFRA, 0, 0); |
598 | if (sc->sc_mode == SC_MODE_ADHOC) |
599 | ifmedia_set(&sc->sc_media, IFM_ADHOC); |
600 | else |
601 | ifmedia_set(&sc->sc_media, IFM_INFRA); |
602 | |
603 | if (pmf_device_register(self, NULL, NULL)) |
604 | pmf_class_network_register(self, ifp); |
605 | else |
606 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
607 | |
608 | /* The attach is successful. */ |
609 | sc->sc_attached = 1; |
610 | ray_disable(sc); |
611 | return; |
612 | |
613 | fail2: |
614 | ray_disable(sc); |
615 | fail: |
616 | pcmcia_function_unconfigure(pa->pf); |
617 | } |
618 | |
619 | static int |
620 | ray_activate(device_t self, enum devact act) |
621 | { |
622 | struct ray_softc *sc = device_private(self); |
623 | struct ifnet *ifp = &sc->sc_if; |
624 | |
625 | RAY_DPRINTF(("%s: activate\n" , device_xname(self))); |
626 | |
627 | switch (act) { |
628 | case DVACT_DEACTIVATE: |
629 | if_deactivate(ifp); |
630 | return 0; |
631 | default: |
632 | return EOPNOTSUPP; |
633 | } |
634 | } |
635 | |
636 | static int |
637 | ray_detach(device_t self, int flags) |
638 | { |
639 | struct ray_softc *sc; |
640 | struct ifnet *ifp; |
641 | |
642 | sc = device_private(self); |
643 | ifp = &sc->sc_if; |
644 | RAY_DPRINTF(("%s: detach\n" , device_xname(sc->sc_dev))); |
645 | |
646 | if (!sc->sc_attached) |
647 | return (0); |
648 | |
649 | pmf_device_deregister(self); |
650 | |
651 | if (sc->sc_if.if_flags & IFF_UP) |
652 | ray_disable(sc); |
653 | |
654 | ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); |
655 | ether_ifdetach(ifp); |
656 | if_detach(ifp); |
657 | |
658 | pcmcia_function_unconfigure(sc->sc_pf); |
659 | |
660 | return (0); |
661 | } |
662 | |
663 | /* |
664 | * start the card running |
665 | */ |
666 | static int |
667 | ray_enable(struct ray_softc *sc) |
668 | { |
669 | int error; |
670 | |
671 | RAY_DPRINTF(("%s: enable\n" , device_xname(sc->sc_dev))); |
672 | |
673 | sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, ray_intr, sc); |
674 | if (!sc->sc_ih) |
675 | return (EIO); |
676 | |
677 | error = ray_init(sc); |
678 | if (error) { |
679 | pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); |
680 | sc->sc_ih = 0; |
681 | } |
682 | |
683 | return (error); |
684 | } |
685 | |
686 | /* |
687 | * stop the card running |
688 | */ |
689 | static void |
690 | ray_disable(struct ray_softc *sc) |
691 | { |
692 | RAY_DPRINTF(("%s: disable\n" , device_xname(sc->sc_dev))); |
693 | |
694 | ray_stop(sc); |
695 | |
696 | sc->sc_resetloop = 0; |
697 | sc->sc_rxoverflow = 0; |
698 | sc->sc_rxcksum = 0; |
699 | sc->sc_rxhcksum = 0; |
700 | sc->sc_rxnoise = 0; |
701 | |
702 | if (sc->sc_ih) { |
703 | pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); |
704 | sc->sc_ih = 0; |
705 | } |
706 | } |
707 | |
708 | /* |
709 | * start the card running |
710 | */ |
711 | static int |
712 | ray_init(struct ray_softc *sc) |
713 | { |
714 | struct ray_ecf_startup *ep; |
715 | bus_size_t ccs; |
716 | int i; |
717 | |
718 | RAY_DPRINTF(("%s: init\n" , device_xname(sc->sc_dev))); |
719 | |
720 | if ((sc->sc_if.if_flags & IFF_RUNNING)) |
721 | ray_stop(sc); |
722 | |
723 | if (pcmcia_function_enable(sc->sc_pf)) |
724 | return (EIO); |
725 | |
726 | RAY_DPRINTF(("%s: init post-enable\n" , device_xname(sc->sc_dev))); |
727 | |
728 | /* reset some values */ |
729 | memset(sc->sc_ccsinuse, 0, sizeof(sc->sc_ccsinuse)); |
730 | sc->sc_havenet = 0; |
731 | memset(sc->sc_bssid, 0, sizeof(sc->sc_bssid)); |
732 | sc->sc_deftxrate = 0; |
733 | sc->sc_encrypt = 0; |
734 | sc->sc_txpad = 0; |
735 | sc->sc_promisc = 0; |
736 | sc->sc_scheduled = 0; |
737 | sc->sc_running = 0; |
738 | sc->sc_txfree = RAY_CCS_NTX; |
739 | sc->sc_checkcounters = 0; |
740 | sc->sc_authstate = RAY_AUTH_UNAUTH; |
741 | |
742 | /* get startup results */ |
743 | ep = &sc->sc_ecf_startup; |
744 | ray_read_region(sc, RAY_ECF_TO_HOST_BASE, ep, |
745 | sizeof(sc->sc_ecf_startup)); |
746 | |
747 | /* check to see that card initialized properly */ |
748 | if (ep->e_status != RAY_ECFS_CARD_OK) { |
749 | pcmcia_function_disable(sc->sc_pf); |
750 | printf("%s: card failed self test: status %d\n" , |
751 | device_xname(sc->sc_dev), sc->sc_ecf_startup.e_status); |
752 | return (EIO); |
753 | } |
754 | |
755 | /* fixup tib size to be correct */ |
756 | if (sc->sc_version == SC_BUILD_4 && sc->sc_tibsize == 0x55) |
757 | sc->sc_tibsize = 32; |
758 | sc->sc_txpad = sc->sc_tibsize; |
759 | |
760 | /* set all ccs to be free */ |
761 | ccs = RAY_GET_CCS(0); |
762 | for (i = 0; i < RAY_CCS_LAST; ccs += RAY_CCS_SIZE, i++) |
763 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, |
764 | RAY_CCS_STATUS_FREE); |
765 | |
766 | /* clear the interrupt if present */ |
767 | REG_WRITE(sc, RAY_HCSIR, 0); |
768 | |
769 | callout_init(&sc->sc_check_ccs_ch, 0); |
770 | callout_init(&sc->sc_check_scheduled_ch, 0); |
771 | |
772 | /* we are now up and running -- and are busy until download is cplt */ |
773 | sc->sc_if.if_flags |= IFF_RUNNING | IFF_OACTIVE; |
774 | |
775 | /* set this now so it gets set in the download */ |
776 | if (sc->sc_if.if_flags & IFF_ALLMULTI) |
777 | sc->sc_if.if_flags |= IFF_PROMISC; |
778 | else if (sc->sc_if.if_pcount == 0) |
779 | sc->sc_if.if_flags &= ~IFF_PROMISC; |
780 | sc->sc_promisc = !!(sc->sc_if.if_flags & IFF_PROMISC); |
781 | |
782 | /* call after we mark ourselves running */ |
783 | ray_download_params(sc); |
784 | |
785 | return (0); |
786 | } |
787 | |
788 | /* |
789 | * stop the card running |
790 | */ |
791 | static void |
792 | ray_stop(struct ray_softc *sc) |
793 | { |
794 | RAY_DPRINTF(("%s: stop\n" , device_xname(sc->sc_dev))); |
795 | |
796 | callout_stop(&sc->sc_check_ccs_ch); |
797 | sc->sc_timocheck = 0; |
798 | |
799 | callout_stop(&sc->sc_check_scheduled_ch); |
800 | sc->sc_timoneed = 0; |
801 | |
802 | if (sc->sc_repreq) { |
803 | sc->sc_repreq->r_failcause = RAY_FAILCAUSE_EDEVSTOP; |
804 | wakeup(ray_report_params); |
805 | } |
806 | if (sc->sc_updreq) { |
807 | sc->sc_updreq->r_failcause = RAY_FAILCAUSE_EDEVSTOP; |
808 | wakeup(ray_update_params); |
809 | } |
810 | |
811 | sc->sc_if.if_flags &= ~IFF_RUNNING; |
812 | pcmcia_function_disable(sc->sc_pf); |
813 | } |
814 | |
815 | /* |
816 | * reset the card |
817 | */ |
818 | static void |
819 | ray_reset(struct ray_softc *sc) |
820 | { |
821 | if (++sc->sc_resetloop >= RAY_MAX_RESETS) { |
822 | if (sc->sc_resetloop == RAY_MAX_RESETS) { |
823 | aprint_error_dev(sc->sc_dev, |
824 | "unable to correct, disabling\n" ); |
825 | callout_stop(&sc->sc_reset_resetloop_ch); |
826 | callout_reset(&sc->sc_disable_ch, 1, |
827 | (void (*)(void *))ray_disable, sc); |
828 | } |
829 | } else { |
830 | aprint_error_dev(sc->sc_dev, |
831 | "unexpected failure resetting hw [%d more]\n" , |
832 | RAY_MAX_RESETS - sc->sc_resetloop); |
833 | callout_stop(&sc->sc_reset_resetloop_ch); |
834 | ray_init(sc); |
835 | callout_reset(&sc->sc_reset_resetloop_ch, 30 * hz, |
836 | ray_reset_resetloop, sc); |
837 | } |
838 | } |
839 | |
840 | /* |
841 | * return resetloop to zero (enough time has expired to allow user to |
842 | * disable a whacked interface) the main reason for all this nonesense |
843 | * is that resets take ~2 seconds and currently the pcmcia code spins |
844 | * on these resets |
845 | */ |
846 | static void |
847 | ray_reset_resetloop(void *arg) |
848 | { |
849 | struct ray_softc *sc; |
850 | |
851 | sc = arg; |
852 | sc->sc_resetloop = 0; |
853 | } |
854 | |
855 | static int |
856 | ray_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
857 | { |
858 | struct ieee80211_nwid nwid; |
859 | struct ray_param_req pr; |
860 | struct ray_softc *sc; |
861 | struct ifreq *ifr; |
862 | struct ifaddr *ifa; |
863 | int error, error2, s, i; |
864 | |
865 | sc = ifp->if_softc; |
866 | error = 0; |
867 | |
868 | ifr = (struct ifreq *)data; |
869 | |
870 | s = splnet(); |
871 | |
872 | RAY_DPRINTF(("%s: ioctl: cmd 0x%lx data 0x%lx\n" , ifp->if_xname, |
873 | cmd, (long)data)); |
874 | switch (cmd) { |
875 | case SIOCINITIFADDR: |
876 | RAY_DPRINTF(("%s: ioctl: cmd SIOCINITIFADDR\n" , ifp->if_xname)); |
877 | if ((ifp->if_flags & IFF_RUNNING) == 0) |
878 | if ((error = ray_enable(sc))) |
879 | break; |
880 | ifp->if_flags |= IFF_UP; |
881 | ifa = (struct ifaddr *)data; |
882 | switch (ifa->ifa_addr->sa_family) { |
883 | #ifdef INET |
884 | case AF_INET: |
885 | arp_ifinit(&sc->sc_if, ifa); |
886 | break; |
887 | #endif |
888 | default: |
889 | break; |
890 | } |
891 | break; |
892 | case SIOCSIFFLAGS: |
893 | RAY_DPRINTF(("%s: ioctl: cmd SIOCSIFFLAGS\n" , ifp->if_xname)); |
894 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) |
895 | break; |
896 | if (ifp->if_flags & IFF_UP) { |
897 | if ((ifp->if_flags & IFF_RUNNING) == 0) { |
898 | if ((error = ray_enable(sc))) |
899 | break; |
900 | } else |
901 | ray_update_promisc(sc); |
902 | } else if (ifp->if_flags & IFF_RUNNING) |
903 | ray_disable(sc); |
904 | break; |
905 | case SIOCADDMULTI: |
906 | RAY_DPRINTF(("%s: ioctl: cmd SIOCADDMULTI\n" , ifp->if_xname)); |
907 | case SIOCDELMULTI: |
908 | if (cmd == SIOCDELMULTI) |
909 | RAY_DPRINTF(("%s: ioctl: cmd SIOCDELMULTI\n" , |
910 | ifp->if_xname)); |
911 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { |
912 | if (ifp->if_flags & IFF_RUNNING) |
913 | ray_update_mcast(sc); |
914 | error = 0; |
915 | } |
916 | break; |
917 | case SIOCSIFMEDIA: |
918 | RAY_DPRINTF(("%s: ioctl: cmd SIOCSIFMEDIA\n" , ifp->if_xname)); |
919 | case SIOCGIFMEDIA: |
920 | if (cmd == SIOCGIFMEDIA) |
921 | RAY_DPRINTF(("%s: ioctl: cmd SIOCGIFMEDIA\n" , |
922 | ifp->if_xname)); |
923 | error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); |
924 | break; |
925 | case SIOCSRAYPARAM: |
926 | RAY_DPRINTF(("%s: ioctl: cmd SIOCSRAYPARAM\n" , ifp->if_xname)); |
927 | if ((error = copyin(ifr->ifr_data, &pr, sizeof(pr)))) |
928 | break; |
929 | /* disallow certain command that have another interface */ |
930 | switch (pr.r_paramid) { |
931 | case RAY_PID_NET_TYPE: /* through media opt */ |
932 | case RAY_PID_AP_STATUS: /* unsupported */ |
933 | case RAY_PID_SSID: /* use SIOC80211[GS]NWID */ |
934 | case RAY_PID_MAC_ADDR: /* XXX need interface? */ |
935 | case RAY_PID_PROMISC: /* bpf */ |
936 | error = EINVAL; |
937 | break; |
938 | } |
939 | error = ray_user_update_params(sc, &pr); |
940 | error2 = copyout(&pr, ifr->ifr_data, sizeof(pr)); |
941 | error = error2 ? error2 : error; |
942 | break; |
943 | case SIOCGRAYPARAM: |
944 | RAY_DPRINTF(("%s: ioctl: cmd SIOCGRAYPARAM\n" , ifp->if_xname)); |
945 | if ((error = copyin(ifr->ifr_data, &pr, sizeof(pr)))) |
946 | break; |
947 | error = ray_user_report_params(sc, &pr); |
948 | error2 = copyout(&pr, ifr->ifr_data, sizeof(pr)); |
949 | error = error2 ? error2 : error; |
950 | break; |
951 | case SIOCS80211NWID: |
952 | RAY_DPRINTF(("%s: ioctl: cmd SIOCS80211NWID\n" , ifp->if_xname)); |
953 | /* |
954 | * if later people overwrite thats ok -- the latest version |
955 | * will always get start/joined even if it was set by |
956 | * a previous command |
957 | */ |
958 | if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid)))) |
959 | break; |
960 | if (nwid.i_len > IEEE80211_NWID_LEN) { |
961 | error = EINVAL; |
962 | break; |
963 | } |
964 | /* clear trailing garbages */ |
965 | for (i = nwid.i_len; i < IEEE80211_NWID_LEN; i++) |
966 | nwid.i_nwid[i] = 0; |
967 | if (!memcmp(&sc->sc_dnwid, &nwid, sizeof(nwid))) |
968 | break; |
969 | memcpy(&sc->sc_dnwid, &nwid, sizeof(nwid)); |
970 | if (ifp->if_flags & IFF_RUNNING) |
971 | ray_start_join_net(sc); |
972 | break; |
973 | case SIOCG80211NWID: |
974 | RAY_DPRINTF(("%s: ioctl: cmd SIOCG80211NWID\n" , ifp->if_xname)); |
975 | error = copyout(&sc->sc_cnwid, ifr->ifr_data, |
976 | sizeof(sc->sc_cnwid)); |
977 | break; |
978 | #ifdef RAY_DO_SIGLEV |
979 | case SIOCGRAYSIGLEV: |
980 | error = copyout(sc->sc_siglevs, ifr->ifr_data, |
981 | sizeof sc->sc_siglevs); |
982 | break; |
983 | #endif |
984 | default: |
985 | RAY_DPRINTF(("%s: ioctl: unknown\n" , ifp->if_xname)); |
986 | error = ether_ioctl(ifp, cmd, data); |
987 | break; |
988 | } |
989 | |
990 | RAY_DPRINTF(("%s: ioctl: returns %d\n" , ifp->if_xname, error)); |
991 | |
992 | splx(s); |
993 | |
994 | return (error); |
995 | } |
996 | |
997 | /* |
998 | * ifnet interface to start transmission on the interface |
999 | */ |
1000 | static void |
1001 | ray_if_start(struct ifnet *ifp) |
1002 | { |
1003 | struct ray_softc *sc; |
1004 | |
1005 | sc = ifp->if_softc; |
1006 | ray_intr_start(sc); |
1007 | } |
1008 | |
1009 | static void |
1010 | ray_if_stop(struct ifnet *ifp, int disable) |
1011 | { |
1012 | struct ray_softc *sc = ifp->if_softc; |
1013 | |
1014 | ray_stop(sc); |
1015 | } |
1016 | |
1017 | static int |
1018 | ray_media_change(struct ifnet *ifp) |
1019 | { |
1020 | struct ray_softc *sc; |
1021 | |
1022 | sc = ifp->if_softc; |
1023 | RAY_DPRINTF(("%s: media change cur %d\n" , ifp->if_xname, |
1024 | sc->sc_media.ifm_cur->ifm_media)); |
1025 | if (sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) |
1026 | sc->sc_mode = SC_MODE_ADHOC; |
1027 | else |
1028 | sc->sc_mode = SC_MODE_INFRA; |
1029 | if (sc->sc_mode != sc->sc_omode) |
1030 | ray_start_join_net(sc); |
1031 | return (0); |
1032 | } |
1033 | |
1034 | static void |
1035 | ray_media_status(struct ifnet *ifp, struct ifmediareq *imr) |
1036 | { |
1037 | struct ray_softc *sc; |
1038 | |
1039 | sc = ifp->if_softc; |
1040 | |
1041 | RAY_DPRINTF(("%s: media status\n" , ifp->if_xname)); |
1042 | |
1043 | imr->ifm_status = IFM_AVALID; |
1044 | if (sc->sc_havenet) |
1045 | imr->ifm_status |= IFM_ACTIVE; |
1046 | |
1047 | if (sc->sc_mode == SC_MODE_ADHOC) |
1048 | imr->ifm_active = IFM_ADHOC; |
1049 | else |
1050 | imr->ifm_active = IFM_INFRA; |
1051 | } |
1052 | |
1053 | /* |
1054 | * called to start from ray_intr. We don't check for pending |
1055 | * interrupt as a result |
1056 | */ |
1057 | static void |
1058 | ray_intr_start(struct ray_softc *sc) |
1059 | { |
1060 | struct ieee80211_frame *iframe; |
1061 | struct ether_header *eh; |
1062 | size_t len, pktlen, tmplen; |
1063 | bus_size_t bufp, ebufp; |
1064 | struct mbuf *m0, *m; |
1065 | struct ifnet *ifp; |
1066 | u_int firsti, hinti, previ, i, pcount; |
1067 | u_int16_t et; |
1068 | u_int8_t *d; |
1069 | |
1070 | ifp = &sc->sc_if; |
1071 | |
1072 | RAY_DPRINTF(("%s: start free %d\n" , |
1073 | ifp->if_xname, sc->sc_txfree)); |
1074 | |
1075 | ray_cmd_cancel(sc, SCP_IFSTART); |
1076 | |
1077 | if ((ifp->if_flags & IFF_RUNNING) == 0 || !sc->sc_havenet) |
1078 | return; |
1079 | |
1080 | if (IFQ_IS_EMPTY(&ifp->if_snd)) |
1081 | return; |
1082 | |
1083 | firsti = i = previ = RAY_CCS_LINK_NULL; |
1084 | hinti = RAY_CCS_TX_FIRST; |
1085 | |
1086 | if (!RAY_ECF_READY(sc)) { |
1087 | ray_cmd_schedule(sc, SCP_IFSTART); |
1088 | return; |
1089 | } |
1090 | |
1091 | /* Check to see if we need to authenticate before sending packets. */ |
1092 | if (sc->sc_authstate == RAY_AUTH_NEEDED) { |
1093 | RAY_DPRINTF(("%s: Sending auth request.\n" , ifp->if_xname)); |
1094 | sc->sc_authstate = RAY_AUTH_WAITING; |
1095 | ray_send_auth(sc, sc->sc_authid, OPEN_AUTH_REQUEST); |
1096 | return; |
1097 | } |
1098 | |
1099 | pcount = 0; |
1100 | for (;;) { |
1101 | /* if we have no descriptors be done */ |
1102 | if (i == RAY_CCS_LINK_NULL) { |
1103 | i = ray_find_free_tx_ccs(sc, hinti); |
1104 | if (i == RAY_CCS_LINK_NULL) { |
1105 | RAY_DPRINTF(("%s: no descriptors.\n" , |
1106 | ifp->if_xname)); |
1107 | ifp->if_flags |= IFF_OACTIVE; |
1108 | break; |
1109 | } |
1110 | } |
1111 | |
1112 | IFQ_DEQUEUE(&ifp->if_snd, m0); |
1113 | if (!m0) { |
1114 | RAY_DPRINTF(("%s: dry queue.\n" , ifp->if_xname)); |
1115 | break; |
1116 | } |
1117 | RAY_DPRINTF(("%s: gotmbuf 0x%lx\n" , ifp->if_xname, (long)m0)); |
1118 | pktlen = m0->m_pkthdr.len; |
1119 | if (pktlen > ETHER_MAX_LEN - ETHER_CRC_LEN) { |
1120 | RAY_DPRINTF(( |
1121 | "%s: mbuf too long %ld\n" , ifp->if_xname, |
1122 | (u_long)pktlen)); |
1123 | ifp->if_oerrors++; |
1124 | m_freem(m0); |
1125 | continue; |
1126 | } |
1127 | RAY_DPRINTF(("%s: mbuf.m_pkthdr.len %d\n" , ifp->if_xname, |
1128 | (int)pktlen)); |
1129 | |
1130 | /* we need the ether_header now for pktlen adjustments */ |
1131 | M_PULLUP(m0, sizeof(struct ether_header)); |
1132 | if (!m0) { |
1133 | RAY_DPRINTF(( "%s: couldn\'t pullup ether header\n" , |
1134 | ifp->if_xname)); |
1135 | ifp->if_oerrors++; |
1136 | continue; |
1137 | } |
1138 | RAY_DPRINTF(("%s: got pulled up mbuf 0x%lx\n" , ifp->if_xname, |
1139 | (long)m0)); |
1140 | |
1141 | /* first peek at the type of packet and figure out what to do */ |
1142 | eh = mtod(m0, struct ether_header *); |
1143 | et = ntohs(eh->ether_type); |
1144 | if (ifp->if_flags & IFF_LINK0) { |
1145 | /* don't support llc for windows compat operation */ |
1146 | if (et <= ETHERMTU) { |
1147 | m_freem(m0); |
1148 | ifp->if_oerrors++; |
1149 | continue; |
1150 | } |
1151 | tmplen = sizeof(struct ieee80211_frame); |
1152 | } else if (et > ETHERMTU) { |
1153 | /* adjust for LLC/SNAP header */ |
1154 | tmplen = sizeof(struct ieee80211_frame) |
1155 | - ETHER_ADDR_LEN; |
1156 | } else { |
1157 | tmplen = 0; |
1158 | } |
1159 | /* now get our space for the 802.11 frame */ |
1160 | M_PREPEND(m0, tmplen, M_DONTWAIT); |
1161 | if (m0) |
1162 | M_PULLUP(m0, sizeof(struct ether_header) + tmplen); |
1163 | if (!m0) { |
1164 | RAY_DPRINTF(("%s: couldn\'t prepend header\n" , |
1165 | ifp->if_xname)); |
1166 | ifp->if_oerrors++; |
1167 | continue; |
1168 | } |
1169 | /* copy the frame into the mbuf for tapping */ |
1170 | iframe = mtod(m0, struct ieee80211_frame *); |
1171 | eh = (struct ether_header *)((u_int8_t *)iframe + tmplen); |
1172 | iframe->i_fc[0] = |
1173 | (IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA); |
1174 | if (sc->sc_mode == SC_MODE_ADHOC) { |
1175 | iframe->i_fc[1] = IEEE80211_FC1_DIR_NODS; |
1176 | memcpy(iframe->i_addr1, eh->ether_dhost,ETHER_ADDR_LEN); |
1177 | memcpy(iframe->i_addr2, eh->ether_shost,ETHER_ADDR_LEN); |
1178 | memcpy(iframe->i_addr3, sc->sc_bssid, ETHER_ADDR_LEN); |
1179 | } else { |
1180 | iframe->i_fc[1] = IEEE80211_FC1_DIR_TODS; |
1181 | memcpy(iframe->i_addr1, sc->sc_bssid,ETHER_ADDR_LEN); |
1182 | memcpy(iframe->i_addr2, eh->ether_shost,ETHER_ADDR_LEN); |
1183 | memmove(iframe->i_addr3,eh->ether_dhost,ETHER_ADDR_LEN); |
1184 | } |
1185 | iframe->i_dur[0] = iframe->i_dur[1] = 0; |
1186 | iframe->i_seq[0] = iframe->i_seq[1] = 0; |
1187 | |
1188 | /* if not using crummy E2 in 802.11 make it LLC/SNAP */ |
1189 | if ((ifp->if_flags & IFF_LINK0) == 0 && et > ETHERMTU) |
1190 | memcpy(iframe + 1, llc_snapid, sizeof(llc_snapid)); |
1191 | |
1192 | RAY_DPRINTF(("%s: i %d previ %d\n" , ifp->if_xname, i, previ)); |
1193 | |
1194 | if (firsti == RAY_CCS_LINK_NULL) |
1195 | firsti = i; |
1196 | |
1197 | pktlen = m0->m_pkthdr.len; |
1198 | bufp = ray_fill_in_tx_ccs(sc, pktlen, i, previ); |
1199 | previ = hinti = i; |
1200 | i = RAY_CCS_LINK_NULL; |
1201 | |
1202 | RAY_DPRINTF(("%s: bufp 0x%lx new pktlen %d\n" , |
1203 | ifp->if_xname, (long)bufp, (int)pktlen)); |
1204 | |
1205 | /* copy out mbuf */ |
1206 | for (m = m0; m; m = m->m_next) { |
1207 | if ((len = m->m_len) == 0) |
1208 | continue; |
1209 | RAY_DPRINTF(( |
1210 | "%s: copying mbuf 0x%lx bufp 0x%lx len %d\n" , |
1211 | ifp->if_xname, (long)m, (long)bufp, (int)len)); |
1212 | d = mtod(m, u_int8_t *); |
1213 | ebufp = bufp + len; |
1214 | if (ebufp <= RAY_TX_END) |
1215 | ray_write_region(sc, bufp, d, len); |
1216 | else { |
1217 | panic("ray_intr_start" ); /* XXX */ |
1218 | /* wrapping */ |
1219 | tmplen = ebufp - bufp; |
1220 | len -= tmplen; |
1221 | ray_write_region(sc, bufp, d, tmplen); |
1222 | d += tmplen; |
1223 | bufp = RAY_TX_BASE; |
1224 | ray_write_region(sc, bufp, d, len); |
1225 | } |
1226 | bufp += len; |
1227 | } |
1228 | if (ifp->if_bpf) { |
1229 | if (ifp->if_flags & IFF_LINK0) { |
1230 | m0->m_data += sizeof(struct ieee80211_frame); |
1231 | m0->m_len -= sizeof(struct ieee80211_frame); |
1232 | m0->m_pkthdr.len -= sizeof(struct ieee80211_frame); |
1233 | } |
1234 | bpf_mtap(ifp, m0); |
1235 | if (ifp->if_flags & IFF_LINK0) { |
1236 | m0->m_data -= sizeof(struct ieee80211_frame); |
1237 | m0->m_len += sizeof(struct ieee80211_frame); |
1238 | m0->m_pkthdr.len += sizeof(struct ieee80211_frame); |
1239 | } |
1240 | } |
1241 | |
1242 | #ifdef RAY_DEBUG |
1243 | if (ray_debug && ray_debug_dump_tx) |
1244 | ray_dump_mbuf(sc, m0); |
1245 | #endif |
1246 | pcount++; |
1247 | m_freem(m0); |
1248 | |
1249 | RAY_DPRINTF_XMIT(("%s: sent packet: len %ld\n" , |
1250 | device_xname(sc->sc_dev), (u_long)pktlen)); |
1251 | } |
1252 | |
1253 | if (firsti == RAY_CCS_LINK_NULL) |
1254 | return; |
1255 | i = 0; |
1256 | if (!RAY_ECF_READY(sc)) { |
1257 | /* |
1258 | * if this can really happen perhaps we need to save |
1259 | * the chain and use it later. I think this might |
1260 | * be a confused state though because we check above |
1261 | * and don't issue any commands between. |
1262 | */ |
1263 | printf("%s: dropping tx packets device busy\n" , |
1264 | device_xname(sc->sc_dev)); |
1265 | ray_free_ccs_chain(sc, firsti); |
1266 | ifp->if_oerrors += pcount; |
1267 | return; |
1268 | } |
1269 | |
1270 | /* send it off */ |
1271 | RAY_DPRINTF(("%s: ray_start issuing %d \n" , device_xname(sc->sc_dev), |
1272 | firsti)); |
1273 | SRAM_WRITE_1(sc, RAY_SCB_CCSI, firsti); |
1274 | RAY_ECF_START_CMD(sc); |
1275 | |
1276 | ifp->if_opackets += pcount; |
1277 | } |
1278 | |
1279 | /* |
1280 | * recevice a packet from the card |
1281 | */ |
1282 | static void |
1283 | ray_recv(struct ray_softc *sc, bus_size_t ccs) |
1284 | { |
1285 | struct ieee80211_frame *frame; |
1286 | struct ether_header *eh; |
1287 | struct mbuf *m; |
1288 | size_t pktlen, fudge, len, lenread = 0; |
1289 | bus_size_t bufp, ebufp, tmp; |
1290 | struct ifnet *ifp; |
1291 | u_int8_t *src, *d; |
1292 | u_int frag = 0, ni, i, issnap, first; |
1293 | u_int8_t fc0; |
1294 | #ifdef RAY_DO_SIGLEV |
1295 | u_int8_t siglev; |
1296 | #endif |
1297 | |
1298 | #ifdef RAY_DEBUG |
1299 | /* have a look if you want to see how the card rx works :) */ |
1300 | if (ray_debug && ray_debug_dump_desc) |
1301 | hexdump((char *)sc->sc_memh + RAY_RCS_BASE, 0x400, 16, 4, 0); |
1302 | #endif |
1303 | |
1304 | m = 0; |
1305 | ifp = &sc->sc_if; |
1306 | |
1307 | /* |
1308 | * If we're expecting the E2-in-802.11 encapsulation that the |
1309 | * WebGear Windows driver produces, fudge the packet forward |
1310 | * in the mbuf by 2 bytes so that the payload after the |
1311 | * Ethernet header will be aligned. If we end up getting a |
1312 | * packet that's not of this type, we'll just drop it anyway. |
1313 | */ |
1314 | if (ifp->if_flags & IFF_LINK0) |
1315 | fudge = 2; |
1316 | else |
1317 | fudge = 0; |
1318 | |
1319 | /* it looks like at least with build 4 there is no CRC in length */ |
1320 | first = RAY_GET_INDEX(ccs); |
1321 | pktlen = SRAM_READ_FIELD_2(sc, ccs, ray_cmd_rx, c_pktlen); |
1322 | #ifdef RAY_DO_SIGLEV |
1323 | siglev = SRAM_READ_FIELD_1(sc, ccs, ray_cmd_rx, c_siglev); |
1324 | #endif |
1325 | |
1326 | RAY_DPRINTF(("%s: recv pktlen %ld frag %d\n" , device_xname(sc->sc_dev), |
1327 | (u_long)pktlen, frag)); |
1328 | RAY_DPRINTF_XMIT(("%s: received packet: len %ld\n" , |
1329 | device_xname(sc->sc_dev), (u_long)pktlen)); |
1330 | if (pktlen > MCLBYTES || pktlen < sizeof(*frame)) { |
1331 | RAY_DPRINTF(("%s: PKTLEN TOO BIG OR TOO SMALL\n" , |
1332 | device_xname(sc->sc_dev))); |
1333 | ifp->if_ierrors++; |
1334 | goto done; |
1335 | } |
1336 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
1337 | if (!m) { |
1338 | RAY_DPRINTF(("%s: MGETHDR FAILED\n" , device_xname(sc->sc_dev))); |
1339 | ifp->if_ierrors++; |
1340 | goto done; |
1341 | } |
1342 | if ((pktlen + fudge) > MHLEN) { |
1343 | /* XXX should allow chaining? */ |
1344 | MCLGET(m, M_DONTWAIT); |
1345 | if ((m->m_flags & M_EXT) == 0) { |
1346 | RAY_DPRINTF(("%s: MCLGET FAILED\n" , |
1347 | device_xname(sc->sc_dev))); |
1348 | ifp->if_ierrors++; |
1349 | m_freem(m); |
1350 | m = 0; |
1351 | goto done; |
1352 | } |
1353 | } |
1354 | m_set_rcvif(m, ifp); |
1355 | m->m_pkthdr.len = pktlen; |
1356 | m->m_len = pktlen; |
1357 | m->m_data += fudge; |
1358 | d = mtod(m, u_int8_t *); |
1359 | |
1360 | RAY_DPRINTF(("%s: recv ccs index %d\n" , device_xname(sc->sc_dev), |
1361 | first)); |
1362 | i = ni = first; |
1363 | while ((i = ni) && i != RAY_CCS_LINK_NULL) { |
1364 | ccs = RAY_GET_CCS(i); |
1365 | bufp = SRAM_READ_FIELD_2(sc, ccs, ray_cmd_rx, c_bufp); |
1366 | len = SRAM_READ_FIELD_2(sc, ccs, ray_cmd_rx, c_len); |
1367 | /* remove the CRC */ |
1368 | #if 0 |
1369 | /* at least with build 4 no crc seems to be here */ |
1370 | if (frag++ == 0) |
1371 | len -= 4; |
1372 | #endif |
1373 | ni = SRAM_READ_FIELD_1(sc, ccs, ray_cmd_rx, c_nextfrag); |
1374 | RAY_DPRINTF(( |
1375 | "%s: recv frag index %d len %ld bufp 0x%llx ni %d\n" , |
1376 | device_xname(sc->sc_dev), i, (u_long)len, |
1377 | (unsigned long long)bufp, ni)); |
1378 | if (len + lenread > pktlen) { |
1379 | RAY_DPRINTF(("%s: BAD LEN current 0x%lx pktlen 0x%lx\n" , |
1380 | device_xname(sc->sc_dev), (u_long)(len + lenread), |
1381 | (u_long)pktlen)); |
1382 | ifp->if_ierrors++; |
1383 | m_freem(m); |
1384 | m = 0; |
1385 | goto done; |
1386 | } |
1387 | if (i < RAY_RCCS_FIRST) { |
1388 | printf("ray_recv: bad ccs index 0x%x\n" , i); |
1389 | m_freem(m); |
1390 | m = 0; |
1391 | goto done; |
1392 | } |
1393 | |
1394 | ebufp = bufp + len; |
1395 | if (ebufp <= RAY_RX_END) |
1396 | ray_read_region(sc, bufp, d, len); |
1397 | else { |
1398 | /* wrapping */ |
1399 | ray_read_region(sc, bufp, d, (tmp = RAY_RX_END - bufp)); |
1400 | ray_read_region(sc, RAY_RX_BASE, d + tmp, |
1401 | ebufp - RAY_RX_END); |
1402 | } |
1403 | d += len; |
1404 | lenread += len; |
1405 | } |
1406 | done: |
1407 | |
1408 | RAY_DPRINTF(("%s: recv frag count %d\n" , device_xname(sc->sc_dev), |
1409 | frag)); |
1410 | |
1411 | /* free the rcss */ |
1412 | ni = first; |
1413 | while ((i = ni) && (i != RAY_CCS_LINK_NULL)) { |
1414 | ccs = RAY_GET_CCS(i); |
1415 | ni = SRAM_READ_FIELD_1(sc, ccs, ray_cmd_rx, c_nextfrag); |
1416 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, |
1417 | RAY_CCS_STATUS_FREE); |
1418 | } |
1419 | |
1420 | if (!m) |
1421 | return; |
1422 | |
1423 | RAY_DPRINTF(("%s: recv got packet pktlen %ld actual %ld\n" , |
1424 | device_xname(sc->sc_dev), (u_long)pktlen, (u_long)lenread)); |
1425 | #ifdef RAY_DEBUG |
1426 | if (ray_debug && ray_debug_dump_rx) |
1427 | ray_dump_mbuf(sc, m); |
1428 | #endif |
1429 | /* receivce the packet */ |
1430 | frame = mtod(m, struct ieee80211_frame *); |
1431 | fc0 = frame->i_fc[0] |
1432 | & (IEEE80211_FC0_VERSION_MASK|IEEE80211_FC0_TYPE_MASK); |
1433 | if ((fc0 & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0) { |
1434 | RAY_DPRINTF(("%s: pkt not version 0 fc 0x%x\n" , |
1435 | device_xname(sc->sc_dev), fc0)); |
1436 | m_freem(m); |
1437 | return; |
1438 | } |
1439 | if ((fc0 & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) { |
1440 | switch (frame->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { |
1441 | case IEEE80211_FC0_SUBTYPE_BEACON: |
1442 | /* Ignore beacon silently. */ |
1443 | break; |
1444 | case IEEE80211_FC0_SUBTYPE_AUTH: |
1445 | ray_recv_auth(sc, frame); |
1446 | break; |
1447 | case IEEE80211_FC0_SUBTYPE_DEAUTH: |
1448 | sc->sc_authstate = RAY_AUTH_UNAUTH; |
1449 | break; |
1450 | default: |
1451 | RAY_DPRINTF(("%s: mgt packet not supported\n" , |
1452 | device_xname(sc->sc_dev))); |
1453 | #ifdef RAY_DEBUG |
1454 | hexdump((const u_int8_t*)frame, pktlen, 16, 4, 0); |
1455 | #endif |
1456 | RAY_DPRINTF(("\n" )); |
1457 | break; |
1458 | } |
1459 | m_freem(m); |
1460 | return; |
1461 | } else if ((fc0 & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { |
1462 | RAY_DPRINTF(("%s: pkt not type data fc0 0x%x\n" , |
1463 | device_xname(sc->sc_dev), fc0)); |
1464 | m_freem(m); |
1465 | return; |
1466 | } |
1467 | |
1468 | if (pktlen < sizeof(*frame) + sizeof(struct llc)) { |
1469 | RAY_DPRINTF(("%s: pkt too small for llc (%ld)\n" , |
1470 | device_xname(sc->sc_dev), (u_long)pktlen)); |
1471 | m_freem(m); |
1472 | return; |
1473 | } |
1474 | |
1475 | if (!memcmp(frame + 1, llc_snapid, sizeof(llc_snapid))) |
1476 | issnap = 1; |
1477 | else { |
1478 | /* |
1479 | * if user has link0 flag set we allow the weird |
1480 | * Ethernet2 in 802.11 encapsulation produced by |
1481 | * the windows driver for the WebGear card |
1482 | */ |
1483 | RAY_DPRINTF(("%s: pkt not snap 0\n" , device_xname(sc->sc_dev))); |
1484 | if ((ifp->if_flags & IFF_LINK0) == 0) { |
1485 | m_freem(m); |
1486 | return; |
1487 | } |
1488 | issnap = 0; |
1489 | } |
1490 | switch (frame->i_fc[1] & IEEE80211_FC1_DIR_MASK) { |
1491 | case IEEE80211_FC1_DIR_NODS: |
1492 | src = frame->i_addr2; |
1493 | break; |
1494 | case IEEE80211_FC1_DIR_FROMDS: |
1495 | src = frame->i_addr3; |
1496 | break; |
1497 | case IEEE80211_FC1_DIR_TODS: |
1498 | RAY_DPRINTF(("%s: pkt ap2ap\n" , device_xname(sc->sc_dev))); |
1499 | m_freem(m); |
1500 | return; |
1501 | default: |
1502 | RAY_DPRINTF(("%s: pkt type unknown\n" , |
1503 | device_xname(sc->sc_dev))); |
1504 | m_freem(m); |
1505 | return; |
1506 | } |
1507 | |
1508 | #ifdef RAY_DO_SIGLEV |
1509 | ray_update_siglev(sc, src, siglev); |
1510 | #endif |
1511 | |
1512 | /* |
1513 | * This is a mess.. we should support other LLC frame types |
1514 | */ |
1515 | if (issnap) { |
1516 | /* create an ether_header over top of the 802.11+SNAP header */ |
1517 | eh = (struct ether_header *)((char *)(frame + 1) - 6); |
1518 | memcpy(eh->ether_shost, src, ETHER_ADDR_LEN); |
1519 | memcpy(eh->ether_dhost, frame->i_addr1, ETHER_ADDR_LEN); |
1520 | } else { |
1521 | /* this is the weird e2 in 802.11 encapsulation */ |
1522 | eh = (struct ether_header *)(frame + 1); |
1523 | } |
1524 | m_adj(m, (char *)eh - (char *)frame); |
1525 | bpf_mtap(ifp, m); |
1526 | /* XXX doesn't appear to be included m->m_flags |= M_HASFCS; */ |
1527 | ifp->if_ipackets++; |
1528 | if_percpuq_enqueue(ifp->if_percpuq, m); |
1529 | } |
1530 | |
1531 | /* |
1532 | * receive an auth packet |
1533 | */ |
1534 | static void |
1535 | ray_recv_auth(struct ray_softc *sc, struct ieee80211_frame *frame) |
1536 | { |
1537 | u_int8_t *var = (u_int8_t *)(frame + 1); |
1538 | |
1539 | if (sc->sc_mode == SC_MODE_ADHOC) { |
1540 | RAY_DPRINTF(("%s: recv auth packet:\n" , |
1541 | device_xname(sc->sc_dev))); |
1542 | #ifdef RAY_DEBUG |
1543 | hexdump((const u_int8_t *)frame, sizeof(*frame) + 6, 16, 4, 0); |
1544 | #endif |
1545 | RAY_DPRINTF(("\n" )); |
1546 | |
1547 | if (var[2] == OPEN_AUTH_REQUEST) { |
1548 | RAY_DPRINTF(("%s: Sending authentication response.\n" , |
1549 | device_xname(sc->sc_dev))); |
1550 | if (ray_send_auth(sc, frame->i_addr2, |
1551 | OPEN_AUTH_RESPONSE) == 0) { |
1552 | sc->sc_authstate = RAY_AUTH_NEEDED; |
1553 | memcpy(sc->sc_authid, frame->i_addr2, |
1554 | ETHER_ADDR_LEN); |
1555 | } |
1556 | } else if (var[2] == OPEN_AUTH_RESPONSE) { |
1557 | RAY_DPRINTF(("%s: Authenticated!\n" , |
1558 | device_xname(sc->sc_dev))); |
1559 | sc->sc_authstate = RAY_AUTH_AUTH; |
1560 | } |
1561 | } |
1562 | } |
1563 | |
1564 | /* |
1565 | * send an auth packet |
1566 | */ |
1567 | static int |
1568 | ray_send_auth(struct ray_softc *sc, u_int8_t *dest, u_int8_t auth_type) |
1569 | { |
1570 | u_int8_t packet[sizeof(struct ieee80211_frame) + ETHER_ADDR_LEN], *var; |
1571 | struct ieee80211_frame *frame; |
1572 | bus_size_t bufp; |
1573 | int ccsindex; |
1574 | |
1575 | ccsindex = ray_find_free_tx_ccs(sc, RAY_CCS_TX_FIRST); |
1576 | if (ccsindex == RAY_CCS_LINK_NULL) { |
1577 | RAY_DPRINTF(("%s: send auth failed -- no free tx slots\n" , |
1578 | device_xname(sc->sc_dev))); |
1579 | return (ENOMEM); |
1580 | } |
1581 | |
1582 | bufp = ray_fill_in_tx_ccs(sc, sizeof(packet), ccsindex, |
1583 | RAY_CCS_LINK_NULL); |
1584 | frame = (struct ieee80211_frame *) packet; |
1585 | frame->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_SUBTYPE_AUTH; |
1586 | frame->i_fc[1] = 0; |
1587 | memcpy(frame->i_addr1, dest, ETHER_ADDR_LEN); |
1588 | memcpy(frame->i_addr2, sc->sc_ecf_startup.e_station_addr, |
1589 | ETHER_ADDR_LEN); |
1590 | memcpy(frame->i_addr3, sc->sc_bssid, ETHER_ADDR_LEN); |
1591 | |
1592 | var = (u_int8_t *)(frame + 1); |
1593 | memset(var, 0, ETHER_ADDR_LEN); |
1594 | var[2] = auth_type; |
1595 | |
1596 | ray_write_region(sc, bufp, packet, sizeof(packet)); |
1597 | |
1598 | SRAM_WRITE_1(sc, RAY_SCB_CCSI, ccsindex); |
1599 | RAY_ECF_START_CMD(sc); |
1600 | |
1601 | RAY_DPRINTF_XMIT(("%s: sent auth packet: len %lu\n" , |
1602 | device_xname(sc->sc_dev), (u_long) sizeof(packet))); |
1603 | |
1604 | return (0); |
1605 | } |
1606 | |
1607 | /* |
1608 | * scan for free buffers |
1609 | * |
1610 | * Note: do _not_ try to optimize this away, there is some kind of |
1611 | * horrible interaction with receiving tx interrupts and they |
1612 | * have to be done as fast as possible, which means zero processing. |
1613 | * this took ~ever to figure out, don't make someone do it again! |
1614 | */ |
1615 | static u_int |
1616 | ray_find_free_tx_ccs(struct ray_softc *sc, u_int hint) |
1617 | { |
1618 | u_int i, stat; |
1619 | |
1620 | for (i = hint; i <= RAY_CCS_TX_LAST; i++) { |
1621 | stat = SRAM_READ_FIELD_1(sc, RAY_GET_CCS(i), ray_cmd, c_status); |
1622 | if (stat == RAY_CCS_STATUS_FREE) |
1623 | return (i); |
1624 | } |
1625 | |
1626 | if (hint == RAY_CCS_TX_FIRST) |
1627 | return (RAY_CCS_LINK_NULL); |
1628 | |
1629 | for (i = RAY_CCS_TX_FIRST; i < hint; i++) { |
1630 | stat = SRAM_READ_FIELD_1(sc, RAY_GET_CCS(i), ray_cmd, c_status); |
1631 | if (stat == RAY_CCS_STATUS_FREE) |
1632 | return (i); |
1633 | } |
1634 | return (RAY_CCS_LINK_NULL); |
1635 | } |
1636 | |
1637 | /* |
1638 | * allocate, initialize and link in a tx ccs for the given |
1639 | * page and the current chain values |
1640 | */ |
1641 | static bus_size_t |
1642 | ray_fill_in_tx_ccs(struct ray_softc *sc, size_t pktlen, u_int i, u_int pi) |
1643 | { |
1644 | bus_size_t ccs, bufp; |
1645 | |
1646 | /* pktlen += RAY_TX_PHY_SIZE; */ |
1647 | bufp = RAY_TX_BASE + i * RAY_TX_BUF_SIZE; |
1648 | bufp += sc->sc_txpad; |
1649 | ccs = RAY_GET_CCS(i); |
1650 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_status, RAY_CCS_STATUS_BUSY); |
1651 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_cmd, RAY_CMD_TX_REQ); |
1652 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_link, RAY_CCS_LINK_NULL); |
1653 | SRAM_WRITE_FIELD_2(sc, ccs, ray_cmd_tx, c_bufp, bufp); |
1654 | SRAM_WRITE_FIELD_2(sc, ccs, ray_cmd_tx, c_len, pktlen); |
1655 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_tx_rate, sc->sc_deftxrate); |
1656 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_apm_mode, 0); |
1657 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_antenna, 0); |
1658 | |
1659 | /* link us in */ |
1660 | if (pi != RAY_CCS_LINK_NULL) |
1661 | SRAM_WRITE_FIELD_1(sc, RAY_GET_CCS(pi), ray_cmd_tx, c_link, i); |
1662 | |
1663 | RAY_DPRINTF(("%s: ray_alloc_tx_ccs bufp 0x%llx idx %u pidx %u\n" , |
1664 | device_xname(sc->sc_dev), (unsigned long long)bufp, i, pi)); |
1665 | |
1666 | return (bufp + RAY_TX_PHY_SIZE); |
1667 | } |
1668 | |
1669 | /* |
1670 | * an update params command has completed lookup which command and |
1671 | * the status |
1672 | */ |
1673 | static ray_cmd_func_t |
1674 | ray_update_params_done(struct ray_softc *sc, bus_size_t ccs, u_int stat) |
1675 | { |
1676 | ray_cmd_func_t rcmd; |
1677 | |
1678 | rcmd = 0; |
1679 | |
1680 | RAY_DPRINTF(("%s: ray_update_params_done stat %d\n" , |
1681 | device_xname(sc->sc_dev), stat)); |
1682 | |
1683 | /* this will get more complex as we add commands */ |
1684 | if (stat == RAY_CCS_STATUS_FAIL) { |
1685 | printf("%s: failed to update a promisc\n" , |
1686 | device_xname(sc->sc_dev)); |
1687 | /* XXX should probably reset */ |
1688 | /* rcmd = ray_reset; */ |
1689 | } |
1690 | |
1691 | if (sc->sc_running & SCP_UPD_PROMISC) { |
1692 | ray_cmd_done(sc, SCP_UPD_PROMISC); |
1693 | sc->sc_promisc = SRAM_READ_1(sc, RAY_HOST_TO_ECF_BASE); |
1694 | RAY_DPRINTF(("%s: new promisc value %d\n" , |
1695 | device_xname(sc->sc_dev), sc->sc_promisc)); |
1696 | } else if (sc->sc_updreq) { |
1697 | ray_cmd_done(sc, SCP_UPD_UPDATEPARAMS); |
1698 | /* get the update parameter */ |
1699 | sc->sc_updreq->r_failcause = |
1700 | SRAM_READ_FIELD_1(sc, ccs, ray_cmd_update, c_failcause); |
1701 | sc->sc_updreq = 0; |
1702 | wakeup(ray_update_params); |
1703 | |
1704 | rcmd = ray_start_join_net; |
1705 | } |
1706 | return (rcmd); |
1707 | } |
1708 | |
1709 | /* |
1710 | * check too see if we have any pending commands. |
1711 | */ |
1712 | static void |
1713 | ray_check_scheduled(void *arg) |
1714 | { |
1715 | struct ray_softc *sc; |
1716 | int s, i, mask; |
1717 | |
1718 | s = splnet(); |
1719 | |
1720 | sc = arg; |
1721 | RAY_DPRINTF(( |
1722 | "%s: ray_check_scheduled enter schd 0x%x running 0x%x ready %d\n" , |
1723 | device_xname(sc->sc_dev), sc->sc_scheduled, sc->sc_running, |
1724 | RAY_ECF_READY(sc))); |
1725 | |
1726 | if (sc->sc_timoneed) { |
1727 | callout_stop(&sc->sc_check_scheduled_ch); |
1728 | sc->sc_timoneed = 0; |
1729 | } |
1730 | |
1731 | /* if update subcmd is running -- clear it in scheduled */ |
1732 | if (sc->sc_running & SCP_UPDATESUBCMD) |
1733 | sc->sc_scheduled &= ~SCP_UPDATESUBCMD; |
1734 | |
1735 | mask = SCP_FIRST; |
1736 | for (i = 0; i < ray_ncmdtab; mask <<= 1, i++) { |
1737 | if ((sc->sc_scheduled & ~SCP_UPD_MASK) == 0) |
1738 | break; |
1739 | if (!RAY_ECF_READY(sc)) |
1740 | break; |
1741 | if (sc->sc_scheduled & mask) |
1742 | (*ray_cmdtab[i])(sc); |
1743 | } |
1744 | |
1745 | RAY_DPRINTF(( |
1746 | "%s: ray_check_scheduled exit sched 0x%x running 0x%x ready %d\n" , |
1747 | device_xname(sc->sc_dev), sc->sc_scheduled, sc->sc_running, |
1748 | RAY_ECF_READY(sc))); |
1749 | |
1750 | if (sc->sc_scheduled & ~SCP_UPD_MASK) |
1751 | ray_set_pending(sc, sc->sc_scheduled); |
1752 | |
1753 | splx(s); |
1754 | } |
1755 | |
1756 | /* |
1757 | * check for unreported returns |
1758 | * |
1759 | * this routine is coded to only expect one outstanding request for the |
1760 | * timed out requests at a time, but thats all that can be outstanding |
1761 | * per hardware limitations |
1762 | */ |
1763 | static void |
1764 | ray_check_ccs(void *arg) |
1765 | { |
1766 | ray_cmd_func_t fp; |
1767 | struct ray_softc *sc; |
1768 | u_int i, cmd, stat = 0; |
1769 | bus_size_t ccs = 0; |
1770 | int s; |
1771 | |
1772 | s = splnet(); |
1773 | sc = arg; |
1774 | |
1775 | RAY_DPRINTF(("%s: ray_check_ccs\n" , device_xname(sc->sc_dev))); |
1776 | |
1777 | sc->sc_timocheck = 0; |
1778 | for (i = RAY_CCS_CMD_FIRST; i <= RAY_CCS_CMD_LAST; i++) { |
1779 | if (!sc->sc_ccsinuse[i]) |
1780 | continue; |
1781 | ccs = RAY_GET_CCS(i); |
1782 | cmd = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_cmd); |
1783 | switch (cmd) { |
1784 | case RAY_CMD_START_PARAMS: |
1785 | case RAY_CMD_UPDATE_MCAST: |
1786 | case RAY_CMD_UPDATE_PARAMS: |
1787 | stat = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status); |
1788 | RAY_DPRINTF(("%s: check ccs idx %u ccs 0x%llx " |
1789 | "cmd 0x%x stat %u\n" , device_xname(sc->sc_dev), i, |
1790 | (unsigned long long)ccs, cmd, stat)); |
1791 | goto breakout; |
1792 | } |
1793 | } |
1794 | breakout: |
1795 | /* see if we got one of the commands we are looking for */ |
1796 | if (i > RAY_CCS_CMD_LAST) |
1797 | ; /* nothing */ |
1798 | else if (stat == RAY_CCS_STATUS_FREE) { |
1799 | stat = RAY_CCS_STATUS_COMPLETE; |
1800 | if ((fp = ray_ccs_done(sc, ccs))) |
1801 | (*fp)(sc); |
1802 | } else if (stat != RAY_CCS_STATUS_BUSY) { |
1803 | if (sc->sc_ccsinuse[i] == 1) { |
1804 | /* give a chance for the interrupt to occur */ |
1805 | sc->sc_ccsinuse[i] = 2; |
1806 | if (!sc->sc_timocheck) { |
1807 | callout_reset(&sc->sc_check_ccs_ch, 1, |
1808 | ray_check_ccs, sc); |
1809 | sc->sc_timocheck = 1; |
1810 | } |
1811 | } else if ((fp = ray_ccs_done(sc, ccs))) |
1812 | (*fp)(sc); |
1813 | } else { |
1814 | callout_reset(&sc->sc_check_ccs_ch, RAY_CHECK_CCS_TIMEOUT, |
1815 | ray_check_ccs, sc); |
1816 | sc->sc_timocheck = 1; |
1817 | } |
1818 | splx(s); |
1819 | } |
1820 | |
1821 | /* |
1822 | * read the counters, the card implements the following protocol |
1823 | * to keep the values from being changed while read: It checks |
1824 | * the `own' bit and if zero writes the current internal counter |
1825 | * value, it then sets the `own' bit to 1. If the `own' bit was 1 it |
1826 | * increments its internal counter. The user thus reads the counter |
1827 | * if the `own' bit is one and then sets the own bit to 0. |
1828 | */ |
1829 | static void |
1830 | ray_update_error_counters(struct ray_softc *sc) |
1831 | { |
1832 | bus_size_t csc; |
1833 | |
1834 | /* try and update the error counters */ |
1835 | csc = RAY_STATUS_BASE; |
1836 | if (SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_mrxo_own)) { |
1837 | sc->sc_rxoverflow += |
1838 | SRAM_READ_FIELD_2(sc, csc, ray_csc, csc_mrx_overflow); |
1839 | SRAM_WRITE_FIELD_1(sc, csc, ray_csc, csc_mrxo_own, 0); |
1840 | } |
1841 | if (SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_mrxc_own)) { |
1842 | sc->sc_rxcksum += |
1843 | SRAM_READ_FIELD_2(sc, csc, ray_csc, csc_mrx_overflow); |
1844 | SRAM_WRITE_FIELD_1(sc, csc, ray_csc, csc_mrxc_own, 0); |
1845 | } |
1846 | if (SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_rxhc_own)) { |
1847 | sc->sc_rxhcksum += |
1848 | SRAM_READ_FIELD_2(sc, csc, ray_csc, csc_rx_hcksum); |
1849 | SRAM_WRITE_FIELD_1(sc, csc, ray_csc, csc_rxhc_own, 0); |
1850 | } |
1851 | sc->sc_rxnoise = SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_rx_noise); |
1852 | } |
1853 | |
1854 | /* |
1855 | * one of the commands we issued has completed, process. |
1856 | */ |
1857 | static ray_cmd_func_t |
1858 | ray_ccs_done(struct ray_softc *sc, bus_size_t ccs) |
1859 | { |
1860 | ray_cmd_func_t rcmd; |
1861 | u_int cmd, stat; |
1862 | |
1863 | cmd = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_cmd); |
1864 | stat = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status); |
1865 | |
1866 | RAY_DPRINTF(("%s: ray_ccs_done idx %llu cmd 0x%x stat %u\n" , |
1867 | device_xname(sc->sc_dev), (unsigned long long)RAY_GET_INDEX(ccs), |
1868 | cmd, stat)); |
1869 | |
1870 | rcmd = 0; |
1871 | switch (cmd) { |
1872 | /* |
1873 | * solicited commands |
1874 | */ |
1875 | case RAY_CMD_START_PARAMS: |
1876 | /* start network */ |
1877 | ray_cmd_done(sc, SCP_UPD_STARTUP); |
1878 | |
1879 | /* ok to start queueing packets */ |
1880 | sc->sc_if.if_flags &= ~IFF_OACTIVE; |
1881 | |
1882 | sc->sc_omode = sc->sc_mode; |
1883 | memcpy(&sc->sc_cnwid, &sc->sc_dnwid, sizeof(sc->sc_cnwid)); |
1884 | |
1885 | rcmd = ray_start_join_net; |
1886 | break; |
1887 | case RAY_CMD_UPDATE_PARAMS: |
1888 | rcmd = ray_update_params_done(sc, ccs, stat); |
1889 | break; |
1890 | case RAY_CMD_REPORT_PARAMS: |
1891 | /* get the reported parameters */ |
1892 | ray_cmd_done(sc, SCP_REPORTPARAMS); |
1893 | if (!sc->sc_repreq) |
1894 | break; |
1895 | sc->sc_repreq->r_failcause = |
1896 | SRAM_READ_FIELD_1(sc, ccs, ray_cmd_report, c_failcause); |
1897 | sc->sc_repreq->r_len = |
1898 | SRAM_READ_FIELD_1(sc, ccs, ray_cmd_report, c_len); |
1899 | ray_read_region(sc, RAY_ECF_TO_HOST_BASE, sc->sc_repreq->r_data, |
1900 | sc->sc_repreq->r_len); |
1901 | sc->sc_repreq = 0; |
1902 | wakeup(ray_report_params); |
1903 | break; |
1904 | case RAY_CMD_UPDATE_MCAST: |
1905 | ray_cmd_done(sc, SCP_UPD_MCAST); |
1906 | if (stat == RAY_CCS_STATUS_FAIL) |
1907 | rcmd = ray_reset; |
1908 | break; |
1909 | case RAY_CMD_START_NET: |
1910 | case RAY_CMD_JOIN_NET: |
1911 | rcmd = ray_start_join_net_done(sc, cmd, ccs, stat); |
1912 | break; |
1913 | case RAY_CMD_TX_REQ: |
1914 | if (sc->sc_if.if_flags & IFF_OACTIVE) { |
1915 | sc->sc_if.if_flags &= ~IFF_OACTIVE; |
1916 | /* this may also be a problem */ |
1917 | rcmd = ray_intr_start; |
1918 | } |
1919 | /* free it -- no tracking */ |
1920 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, |
1921 | RAY_CCS_STATUS_FREE); |
1922 | goto done; |
1923 | case RAY_CMD_START_ASSOC: |
1924 | ray_cmd_done(sc, SCP_STARTASSOC); |
1925 | if (stat == RAY_CCS_STATUS_FAIL) |
1926 | rcmd = ray_start_join_net; /* XXX check */ |
1927 | else { |
1928 | sc->sc_havenet = 1; |
1929 | rcmd = ray_intr_start; |
1930 | } |
1931 | break; |
1932 | case RAY_CMD_UPDATE_APM: |
1933 | case RAY_CMD_TEST_MEM: |
1934 | case RAY_CMD_SHUTDOWN: |
1935 | case RAY_CMD_DUMP_MEM: |
1936 | case RAY_CMD_START_TIMER: |
1937 | break; |
1938 | default: |
1939 | printf("%s: intr: unknown command 0x%x\n" , |
1940 | sc->sc_if.if_xname, cmd); |
1941 | break; |
1942 | } |
1943 | ray_free_ccs(sc, ccs); |
1944 | done: |
1945 | /* |
1946 | * see if needed things can be done now that a command |
1947 | * has completed |
1948 | */ |
1949 | ray_check_scheduled(sc); |
1950 | |
1951 | return (rcmd); |
1952 | } |
1953 | |
1954 | /* |
1955 | * an unsolicited interrupt, i.e., the ECF is sending us a command |
1956 | */ |
1957 | static ray_cmd_func_t |
1958 | ray_rccs_intr(struct ray_softc *sc, bus_size_t ccs) |
1959 | { |
1960 | ray_cmd_func_t rcmd; |
1961 | u_int cmd, stat; |
1962 | |
1963 | cmd = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_cmd); |
1964 | stat = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status); |
1965 | |
1966 | RAY_DPRINTF(("%s: ray_rccs_intr idx %llu cmd 0x%x stat %u\n" , |
1967 | device_xname(sc->sc_dev), (unsigned long long)RAY_GET_INDEX(ccs), |
1968 | cmd, stat)); |
1969 | |
1970 | rcmd = 0; |
1971 | switch (cmd) { |
1972 | /* |
1973 | * unsolicited commands |
1974 | */ |
1975 | case RAY_ECMD_RX_DONE: |
1976 | ray_recv(sc, ccs); |
1977 | goto done; |
1978 | case RAY_ECMD_REJOIN_DONE: |
1979 | if (sc->sc_mode == SC_MODE_ADHOC) |
1980 | break; |
1981 | /* get the current ssid */ |
1982 | SRAM_READ_FIELD_N(sc, ccs, ray_cmd_net, c_bss_id, |
1983 | sc->sc_bssid, sizeof(sc->sc_bssid)); |
1984 | rcmd = ray_start_assoc; |
1985 | break; |
1986 | case RAY_ECMD_ROAM_START: |
1987 | /* no longer have network */ |
1988 | sc->sc_havenet = 0; |
1989 | break; |
1990 | case RAY_ECMD_JAPAN_CALL_SIGNAL: |
1991 | break; |
1992 | default: |
1993 | ray_update_error_counters(sc); |
1994 | |
1995 | /* this is a bogus return from build 4 don't free 0x55 */ |
1996 | if (sc->sc_version == SC_BUILD_4 && cmd == 0x55 |
1997 | && RAY_GET_INDEX(ccs) == 0x55) { |
1998 | goto done; |
1999 | } |
2000 | printf("%s: intr: unknown command 0x%x\n" , |
2001 | sc->sc_if.if_xname, cmd); |
2002 | break; |
2003 | } |
2004 | /* free the ccs */ |
2005 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, RAY_CCS_STATUS_FREE); |
2006 | done: |
2007 | return (rcmd); |
2008 | } |
2009 | |
2010 | /* |
2011 | * process an interrupt |
2012 | */ |
2013 | static int |
2014 | ray_intr(void *arg) |
2015 | { |
2016 | struct ray_softc *sc; |
2017 | ray_cmd_func_t rcmd; |
2018 | u_int i, count; |
2019 | |
2020 | sc = arg; |
2021 | |
2022 | RAY_DPRINTF(("%s: ray_intr\n" , device_xname(sc->sc_dev))); |
2023 | |
2024 | if ((++sc->sc_checkcounters % 32) == 0) |
2025 | ray_update_error_counters(sc); |
2026 | |
2027 | count = 0; |
2028 | rcmd = 0; |
2029 | if (!REG_READ(sc, RAY_HCSIR)) |
2030 | count = 0; |
2031 | else { |
2032 | count = 1; |
2033 | i = SRAM_READ_1(sc, RAY_SCB_RCCSI); |
2034 | if (i <= RAY_CCS_LAST) |
2035 | rcmd = ray_ccs_done(sc, RAY_GET_CCS(i)); |
2036 | else if (i <= RAY_RCCS_LAST) |
2037 | rcmd = ray_rccs_intr(sc, RAY_GET_CCS(i)); |
2038 | else |
2039 | printf("%s: intr: bad cmd index %d\n" , |
2040 | device_xname(sc->sc_dev), i); |
2041 | } |
2042 | |
2043 | if (rcmd) |
2044 | (*rcmd)(sc); |
2045 | |
2046 | if (count) |
2047 | REG_WRITE(sc, RAY_HCSIR, 0); |
2048 | |
2049 | RAY_DPRINTF(("%s: interrupt handled %d\n" , device_xname(sc->sc_dev), |
2050 | count)); |
2051 | |
2052 | return (count ? 1 : 0); |
2053 | } |
2054 | |
2055 | |
2056 | /* |
2057 | * Generic CCS handling |
2058 | */ |
2059 | |
2060 | /* |
2061 | * free the chain of descriptors -- used for freeing allocated tx chains |
2062 | */ |
2063 | static void |
2064 | ray_free_ccs_chain(struct ray_softc *sc, u_int ni) |
2065 | { |
2066 | u_int i; |
2067 | |
2068 | while ((i = ni) != RAY_CCS_LINK_NULL) { |
2069 | ni = SRAM_READ_FIELD_1(sc, RAY_GET_CCS(i), ray_cmd, c_link); |
2070 | SRAM_WRITE_FIELD_1(sc, RAY_GET_CCS(i), ray_cmd, c_status, |
2071 | RAY_CCS_STATUS_FREE); |
2072 | } |
2073 | } |
2074 | |
2075 | /* |
2076 | * free up a cmd and return the old status |
2077 | * this routine is only used for commands |
2078 | */ |
2079 | static u_int8_t |
2080 | ray_free_ccs(struct ray_softc *sc, bus_size_t ccs) |
2081 | { |
2082 | u_int8_t stat; |
2083 | |
2084 | RAY_DPRINTF(("%s: free_ccs idx %llu\n" , device_xname(sc->sc_dev), |
2085 | (unsigned long long)RAY_GET_INDEX(ccs))); |
2086 | |
2087 | stat = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status); |
2088 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, RAY_CCS_STATUS_FREE); |
2089 | if (ccs <= RAY_GET_CCS(RAY_CCS_LAST)) |
2090 | sc->sc_ccsinuse[RAY_GET_INDEX(ccs)] = 0; |
2091 | |
2092 | return (stat); |
2093 | } |
2094 | |
2095 | /* |
2096 | * returns 1 and in `ccb' the bus offset of the free ccb |
2097 | * or 0 if none are free |
2098 | * |
2099 | * If `track' is not zero, handles tracking this command |
2100 | * possibly indicating a callback is needed and setting a timeout |
2101 | * also if ECF isn't ready we terminate earlier to avoid overhead. |
2102 | * |
2103 | * this routine is only used for commands |
2104 | */ |
2105 | static int |
2106 | ray_alloc_ccs(struct ray_softc *sc, bus_size_t *ccsp, u_int cmd, u_int track) |
2107 | { |
2108 | bus_size_t ccs; |
2109 | u_int i; |
2110 | |
2111 | RAY_DPRINTF(("%s: alloc_ccs cmd %d\n" , device_xname(sc->sc_dev), cmd)); |
2112 | |
2113 | /* for tracked commands, if not ready just set pending */ |
2114 | if (track && !RAY_ECF_READY(sc)) { |
2115 | ray_cmd_schedule(sc, track); |
2116 | return (0); |
2117 | } |
2118 | |
2119 | /* first scan our inuse array */ |
2120 | for (i = RAY_CCS_CMD_FIRST; i <= RAY_CCS_CMD_LAST; i++) { |
2121 | /* XXX wonder if we have to probe here to make the card go */ |
2122 | (void)SRAM_READ_FIELD_1(sc, RAY_GET_CCS(i), ray_cmd, c_status); |
2123 | if (!sc->sc_ccsinuse[i]) |
2124 | break; |
2125 | } |
2126 | if (i > RAY_CCS_CMD_LAST) { |
2127 | if (track) |
2128 | ray_cmd_schedule(sc, track); |
2129 | return (0); |
2130 | } |
2131 | sc->sc_ccsinuse[i] = 1; |
2132 | ccs = RAY_GET_CCS(i); |
2133 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, RAY_CCS_STATUS_BUSY); |
2134 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_cmd, cmd); |
2135 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_link, RAY_CCS_LINK_NULL); |
2136 | |
2137 | *ccsp = ccs; |
2138 | return (1); |
2139 | } |
2140 | |
2141 | |
2142 | /* |
2143 | * this function sets the pending bit for the command given in 'need' |
2144 | * and schedules a timeout if none is scheduled already. Any command |
2145 | * that uses the `host to ecf' region must be serialized. |
2146 | */ |
2147 | static void |
2148 | ray_set_pending(struct ray_softc *sc, u_int cmdf) |
2149 | { |
2150 | RAY_DPRINTF(("%s: ray_set_pending 0x%x\n" , device_xname(sc->sc_dev), |
2151 | cmdf)); |
2152 | |
2153 | sc->sc_scheduled |= cmdf; |
2154 | if (!sc->sc_timoneed) { |
2155 | RAY_DPRINTF(("%s: ray_set_pending new timo\n" , |
2156 | device_xname(sc->sc_dev))); |
2157 | callout_reset(&sc->sc_check_scheduled_ch, |
2158 | RAY_CHECK_SCHED_TIMEOUT, ray_check_scheduled, sc); |
2159 | sc->sc_timoneed = 1; |
2160 | } |
2161 | } |
2162 | |
2163 | /* |
2164 | * schedule the `cmdf' for completion later |
2165 | */ |
2166 | static void |
2167 | ray_cmd_schedule(struct ray_softc *sc, int cmdf) |
2168 | { |
2169 | int track; |
2170 | |
2171 | RAY_DPRINTF(("%s: ray_cmd_schedule 0x%x\n" , device_xname(sc->sc_dev), |
2172 | cmdf)); |
2173 | |
2174 | track = cmdf; |
2175 | if ((cmdf & SCP_UPD_MASK) == 0) |
2176 | ray_set_pending(sc, track); |
2177 | else if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) { |
2178 | /* don't do timeout mechanism if subcmd already going */ |
2179 | sc->sc_scheduled |= cmdf; |
2180 | } else |
2181 | ray_set_pending(sc, cmdf | SCP_UPDATESUBCMD); |
2182 | } |
2183 | |
2184 | /* |
2185 | * check to see if `cmdf' has been scheduled |
2186 | */ |
2187 | static int |
2188 | ray_cmd_is_scheduled(struct ray_softc *sc, int cmdf) |
2189 | { |
2190 | RAY_DPRINTF(("%s: ray_cmd_is_scheduled 0x%x\n" , |
2191 | device_xname(sc->sc_dev), cmdf)); |
2192 | |
2193 | return ((sc->sc_scheduled & cmdf) ? 1 : 0); |
2194 | } |
2195 | |
2196 | /* |
2197 | * cancel a scheduled command (not a running one though!) |
2198 | */ |
2199 | static void |
2200 | ray_cmd_cancel(struct ray_softc *sc, int cmdf) |
2201 | { |
2202 | RAY_DPRINTF(("%s: ray_cmd_cancel 0x%x\n" , device_xname(sc->sc_dev), |
2203 | cmdf)); |
2204 | |
2205 | sc->sc_scheduled &= ~cmdf; |
2206 | if ((cmdf & SCP_UPD_MASK) && (sc->sc_scheduled & SCP_UPD_MASK) == 0) |
2207 | sc->sc_scheduled &= ~SCP_UPDATESUBCMD; |
2208 | |
2209 | /* if nothing else needed cancel the timer */ |
2210 | if (sc->sc_scheduled == 0 && sc->sc_timoneed) { |
2211 | callout_stop(&sc->sc_check_scheduled_ch); |
2212 | sc->sc_timoneed = 0; |
2213 | } |
2214 | } |
2215 | |
2216 | /* |
2217 | * called to indicate the 'cmdf' has been issued |
2218 | */ |
2219 | static void |
2220 | ray_cmd_ran(struct ray_softc *sc, int cmdf) |
2221 | { |
2222 | RAY_DPRINTF(("%s: ray_cmd_ran 0x%x\n" , device_xname(sc->sc_dev), |
2223 | cmdf)); |
2224 | |
2225 | if (cmdf & SCP_UPD_MASK) |
2226 | sc->sc_running |= cmdf | SCP_UPDATESUBCMD; |
2227 | else |
2228 | sc->sc_running |= cmdf; |
2229 | |
2230 | if ((cmdf & SCP_TIMOCHECK_CMD_MASK) && !sc->sc_timocheck) { |
2231 | callout_reset(&sc->sc_check_ccs_ch, RAY_CHECK_CCS_TIMEOUT, |
2232 | ray_check_ccs, sc); |
2233 | sc->sc_timocheck = 1; |
2234 | } |
2235 | } |
2236 | |
2237 | /* |
2238 | * check to see if `cmdf' has been issued |
2239 | */ |
2240 | static int |
2241 | ray_cmd_is_running(struct ray_softc *sc, int cmdf) |
2242 | { |
2243 | RAY_DPRINTF(("%s: ray_cmd_is_running 0x%x\n" , device_xname(sc->sc_dev), |
2244 | cmdf)); |
2245 | |
2246 | return ((sc->sc_running & cmdf) ? 1 : 0); |
2247 | } |
2248 | |
2249 | /* |
2250 | * the given `cmdf' that was issued has completed |
2251 | */ |
2252 | static void |
2253 | ray_cmd_done(struct ray_softc *sc, int cmdf) |
2254 | { |
2255 | RAY_DPRINTF(("%s: ray_cmd_done 0x%x\n" , device_xname(sc->sc_dev), |
2256 | cmdf)); |
2257 | |
2258 | sc->sc_running &= ~cmdf; |
2259 | if (cmdf & SCP_UPD_MASK) { |
2260 | sc->sc_running &= ~SCP_UPDATESUBCMD; |
2261 | if (sc->sc_scheduled & SCP_UPD_MASK) |
2262 | ray_cmd_schedule(sc, sc->sc_scheduled & SCP_UPD_MASK); |
2263 | } |
2264 | if ((sc->sc_running & SCP_TIMOCHECK_CMD_MASK) == 0 && sc->sc_timocheck){ |
2265 | callout_stop(&sc->sc_check_ccs_ch); |
2266 | sc->sc_timocheck = 0; |
2267 | } |
2268 | } |
2269 | |
2270 | /* |
2271 | * issue the command |
2272 | * only used for commands not tx |
2273 | */ |
2274 | static int |
2275 | ray_issue_cmd(struct ray_softc *sc, bus_size_t ccs, u_int track) |
2276 | { |
2277 | u_int i; |
2278 | |
2279 | RAY_DPRINTF(("%s: ray_cmd_issue 0x%x\n" , device_xname(sc->sc_dev), |
2280 | track)); |
2281 | |
2282 | /* |
2283 | * XXX other drivers did this, but I think |
2284 | * what we really want to do is just make sure we don't |
2285 | * get here or that spinning is ok |
2286 | */ |
2287 | i = 0; |
2288 | while (!RAY_ECF_READY(sc)) |
2289 | if (++i > 50) { |
2290 | ray_free_ccs(sc, ccs); |
2291 | if (track) |
2292 | ray_cmd_schedule(sc, track); |
2293 | return (0); |
2294 | } |
2295 | |
2296 | SRAM_WRITE_1(sc, RAY_SCB_CCSI, RAY_GET_INDEX(ccs)); |
2297 | RAY_ECF_START_CMD(sc); |
2298 | ray_cmd_ran(sc, track); |
2299 | |
2300 | return (1); |
2301 | } |
2302 | |
2303 | /* |
2304 | * send a simple command if we can |
2305 | */ |
2306 | static int |
2307 | ray_simple_cmd(struct ray_softc *sc, u_int cmd, u_int track) |
2308 | { |
2309 | bus_size_t ccs; |
2310 | |
2311 | return (ray_alloc_ccs(sc, &ccs, cmd, track) && |
2312 | ray_issue_cmd(sc, ccs, track)); |
2313 | } |
2314 | |
2315 | /* |
2316 | * Functions based on CCS commands |
2317 | */ |
2318 | |
2319 | /* |
2320 | * run a update subcommand |
2321 | */ |
2322 | static void |
2323 | ray_update_subcmd(struct ray_softc *sc) |
2324 | { |
2325 | int submask, i; |
2326 | |
2327 | RAY_DPRINTF(("%s: ray_update_subcmd\n" , device_xname(sc->sc_dev))); |
2328 | |
2329 | ray_cmd_cancel(sc, SCP_UPDATESUBCMD); |
2330 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) |
2331 | return; |
2332 | submask = SCP_UPD_FIRST; |
2333 | for (i = 0; i < ray_nsubcmdtab; submask <<= 1, i++) { |
2334 | if ((sc->sc_scheduled & SCP_UPD_MASK) == 0) |
2335 | break; |
2336 | /* when done the next command will be scheduled */ |
2337 | if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) |
2338 | break; |
2339 | if (!RAY_ECF_READY(sc)) |
2340 | break; |
2341 | /* |
2342 | * give priority to LSB -- e.g., if previous loop rescheduled |
2343 | * doing this command after calling the function won't catch |
2344 | * if a later command sets an earlier bit |
2345 | */ |
2346 | if (sc->sc_scheduled & ((submask - 1) & SCP_UPD_MASK)) |
2347 | break; |
2348 | if (sc->sc_scheduled & submask) |
2349 | (*ray_subcmdtab[i])(sc); |
2350 | } |
2351 | } |
2352 | |
2353 | /* |
2354 | * report a parameter |
2355 | */ |
2356 | static void |
2357 | ray_report_params(struct ray_softc *sc) |
2358 | { |
2359 | bus_size_t ccs; |
2360 | |
2361 | ray_cmd_cancel(sc, SCP_REPORTPARAMS); |
2362 | |
2363 | if (!sc->sc_repreq) |
2364 | return; |
2365 | |
2366 | /* do the issue check before equality check */ |
2367 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) |
2368 | return; |
2369 | else if (ray_cmd_is_running(sc, SCP_REPORTPARAMS)) { |
2370 | ray_cmd_schedule(sc, SCP_REPORTPARAMS); |
2371 | return; |
2372 | } else if (!ray_alloc_ccs(sc, &ccs, RAY_CMD_REPORT_PARAMS, |
2373 | SCP_REPORTPARAMS)) |
2374 | return; |
2375 | |
2376 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_report, c_paramid, |
2377 | sc->sc_repreq->r_paramid); |
2378 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_report, c_nparam, 1); |
2379 | (void)ray_issue_cmd(sc, ccs, SCP_REPORTPARAMS); |
2380 | } |
2381 | |
2382 | /* |
2383 | * start an association |
2384 | */ |
2385 | static void |
2386 | ray_start_assoc(struct ray_softc *sc) |
2387 | { |
2388 | ray_cmd_cancel(sc, SCP_STARTASSOC); |
2389 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) |
2390 | return; |
2391 | else if (ray_cmd_is_running(sc, SCP_STARTASSOC)) |
2392 | return; |
2393 | (void)ray_simple_cmd(sc, RAY_CMD_START_ASSOC, SCP_STARTASSOC); |
2394 | } |
2395 | |
2396 | /* |
2397 | * Subcommand functions that use the SCP_UPDATESUBCMD command |
2398 | * (and are serialized with respect to other update sub commands |
2399 | */ |
2400 | |
2401 | /* |
2402 | * download the startup parameters to the card |
2403 | * -- no outstanding commands expected |
2404 | */ |
2405 | static void |
2406 | ray_download_params(struct ray_softc *sc) |
2407 | { |
2408 | struct ray_startup_params_head *sp; |
2409 | struct ray_startup_params_tail_5 *sp5; |
2410 | struct ray_startup_params_tail_4 *sp4; |
2411 | bus_size_t off; |
2412 | |
2413 | RAY_DPRINTF(("%s: init_startup_params\n" , device_xname(sc->sc_dev))); |
2414 | |
2415 | ray_cmd_cancel(sc, SCP_UPD_STARTUP); |
2416 | |
2417 | #define PUT2(p, v) \ |
2418 | do { (p)[0] = ((v >> 8) & 0xff); (p)[1] = (v & 0xff); } while(0) |
2419 | |
2420 | sp = &sc->sc_startup; |
2421 | sp4 = &sc->sc_startup_4; |
2422 | sp5 = &sc->sc_startup_5; |
2423 | memset(sp, 0, sizeof(*sp)); |
2424 | if (sc->sc_version == SC_BUILD_4) |
2425 | memset(sp4, 0, sizeof(*sp4)); |
2426 | else |
2427 | memset(sp5, 0, sizeof(*sp5)); |
2428 | /* XXX: Raylink firmware doesn't have length field for ssid */ |
2429 | memcpy(sp->sp_ssid, sc->sc_dnwid.i_nwid, sizeof(sp->sp_ssid)); |
2430 | sp->sp_scan_mode = 0x1; |
2431 | memcpy(sp->sp_mac_addr, sc->sc_ecf_startup.e_station_addr, |
2432 | ETHER_ADDR_LEN); |
2433 | PUT2(sp->sp_frag_thresh, 0x7fff); /* disabled */ |
2434 | if (sc->sc_version == SC_BUILD_4) { |
2435 | #if 1 |
2436 | /* linux/fbsd */ |
2437 | PUT2(sp->sp_dwell_time, 0x200); |
2438 | PUT2(sp->sp_beacon_period, 1); |
2439 | #else |
2440 | /* divined */ |
2441 | PUT2(sp->sp_dwell_time, 0x400); |
2442 | PUT2(sp->sp_beacon_period, 0); |
2443 | #endif |
2444 | } else { |
2445 | PUT2(sp->sp_dwell_time, 128); |
2446 | PUT2(sp->sp_beacon_period, 256); |
2447 | } |
2448 | sp->sp_dtim_interval = 1; |
2449 | #if 0 |
2450 | /* these are the documented defaults for build 5/6 */ |
2451 | sp->sp_max_retry = 0x1f; |
2452 | sp->sp_ack_timo = 0x86; |
2453 | sp->sp_sifs = 0x1c; |
2454 | #elif 1 |
2455 | /* these were scrounged from the linux driver */ |
2456 | sp->sp_max_retry = 0x07; |
2457 | |
2458 | sp->sp_ack_timo = 0xa3; |
2459 | sp->sp_sifs = 0x1d; |
2460 | #else |
2461 | /* these were divined */ |
2462 | sp->sp_max_retry = 0x03; |
2463 | |
2464 | sp->sp_ack_timo = 0xa3; |
2465 | sp->sp_sifs = 0x1d; |
2466 | #endif |
2467 | #if 0 |
2468 | /* these are the documented defaults for build 5/6 */ |
2469 | sp->sp_difs = 0x82; |
2470 | sp->sp_pifs = 0; |
2471 | #else |
2472 | /* linux/fbsd */ |
2473 | sp->sp_difs = 0x82; |
2474 | |
2475 | if (sc->sc_version == SC_BUILD_4) |
2476 | sp->sp_pifs = 0xce; |
2477 | else |
2478 | sp->sp_pifs = 0x4e; |
2479 | #endif |
2480 | |
2481 | PUT2(sp->sp_rts_thresh, 0x7fff); /* disabled */ |
2482 | if (sc->sc_version == SC_BUILD_4) { |
2483 | PUT2(sp->sp_scan_dwell, 0xfb1e); |
2484 | PUT2(sp->sp_scan_max_dwell, 0xc75c); |
2485 | } else { |
2486 | PUT2(sp->sp_scan_dwell, 0x4e2); |
2487 | PUT2(sp->sp_scan_max_dwell, 0x38a4); |
2488 | } |
2489 | sp->sp_assoc_timo = 0x5; |
2490 | if (sc->sc_version == SC_BUILD_4) { |
2491 | #if 0 |
2492 | /* linux/fbsd */ |
2493 | sp->sp_adhoc_scan_cycle = 0x4; |
2494 | sp->sp_infra_scan_cycle = 0x2; |
2495 | sp->sp_infra_super_scan_cycle = 0x4; |
2496 | #else |
2497 | /* divined */ |
2498 | sp->sp_adhoc_scan_cycle = 0x8; |
2499 | sp->sp_infra_scan_cycle = 0x1; |
2500 | sp->sp_infra_super_scan_cycle = 0x18; |
2501 | #endif |
2502 | } else { |
2503 | sp->sp_adhoc_scan_cycle = 0x8; |
2504 | sp->sp_infra_scan_cycle = 0x2; |
2505 | sp->sp_infra_super_scan_cycle = 0x8; |
2506 | } |
2507 | sp->sp_promisc = sc->sc_promisc; |
2508 | PUT2(sp->sp_uniq_word, 0x0cbd); |
2509 | if (sc->sc_version == SC_BUILD_4) { |
2510 | /* XXX what is this value anyway..? the std says 50us */ |
2511 | /* XXX sp->sp_slot_time = 0x4e; */ |
2512 | sp->sp_slot_time = 0x4e; |
2513 | #if 1 |
2514 | /*linux/fbsd*/ |
2515 | sp->sp_roam_low_snr_thresh = 0xff; |
2516 | #else |
2517 | /*divined*/ |
2518 | sp->sp_roam_low_snr_thresh = 0x30; |
2519 | #endif |
2520 | } else { |
2521 | sp->sp_slot_time = 0x32; |
2522 | sp->sp_roam_low_snr_thresh = 0xff; /* disabled */ |
2523 | } |
2524 | #if 1 |
2525 | sp->sp_low_snr_count = 0xff; /* disabled */ |
2526 | #else |
2527 | /* divined -- check */ |
2528 | sp->sp_low_snr_count = 0x07; /* disabled */ |
2529 | #endif |
2530 | #if 0 |
2531 | sp->sp_infra_missed_beacon_count = 0x2; |
2532 | #elif 1 |
2533 | /* linux/fbsd */ |
2534 | sp->sp_infra_missed_beacon_count = 0x5; |
2535 | #else |
2536 | /* divined -- check, looks fishy */ |
2537 | sp->sp_infra_missed_beacon_count = 0x7; |
2538 | #endif |
2539 | sp->sp_adhoc_missed_beacon_count = 0xff; |
2540 | sp->sp_country_code = sc->sc_dcountrycode; |
2541 | sp->sp_hop_seq = 0x0b; |
2542 | if (sc->sc_version == SC_BUILD_4) { |
2543 | sp->sp_hop_seq_len = 0x4e; |
2544 | sp4->sp_cw_max = 0x3f; /* single byte on build 4 */ |
2545 | sp4->sp_cw_min = 0x0f; /* single byte on build 4 */ |
2546 | sp4->sp_noise_filter_gain = 0x4; |
2547 | sp4->sp_noise_limit_offset = 0x8; |
2548 | sp4->sp_rssi_thresh_offset = 0x28; |
2549 | sp4->sp_busy_thresh_offset = 0x28; |
2550 | sp4->sp_sync_thresh = 0x07; |
2551 | sp4->sp_test_mode = 0x0; |
2552 | sp4->sp_test_min_chan = 0x2; |
2553 | sp4->sp_test_max_chan = 0x2; |
2554 | } else { |
2555 | sp->sp_hop_seq_len = 0x4f; |
2556 | PUT2(sp5->sp_cw_max, 0x3f); |
2557 | PUT2(sp5->sp_cw_min, 0x0f); |
2558 | sp5->sp_noise_filter_gain = 0x4; |
2559 | sp5->sp_noise_limit_offset = 0x8; |
2560 | sp5->sp_rssi_thresh_offset = 0x28; |
2561 | sp5->sp_busy_thresh_offset = 0x28; |
2562 | sp5->sp_sync_thresh = 0x07; |
2563 | sp5->sp_test_mode = 0x0; |
2564 | sp5->sp_test_min_chan = 0x2; |
2565 | sp5->sp_test_max_chan = 0x2; |
2566 | #if 0 |
2567 | sp5->sp_allow_probe_resp = 0x1; |
2568 | #else |
2569 | sp5->sp_allow_probe_resp = 0x0; |
2570 | #endif |
2571 | sp5->sp_privacy_must_start = 0x0; |
2572 | sp5->sp_privacy_can_join = 0x0; |
2573 | sp5->sp_basic_rate_set[0] = 0x2; |
2574 | /* 2 = 1Mbps, 3 = old 2Mbps 4 = 2Mbps */ |
2575 | } |
2576 | |
2577 | /* we shouldn't be called with some command pending */ |
2578 | if (!RAY_ECF_READY(sc)) |
2579 | panic("ray_download_params busy" ); |
2580 | |
2581 | /* write the compatible part */ |
2582 | off = RAY_HOST_TO_ECF_BASE; |
2583 | ray_write_region(sc, off, sp, sizeof(sc->sc_startup)); |
2584 | off += sizeof(sc->sc_startup); |
2585 | if (sc->sc_version == SC_BUILD_4) |
2586 | ray_write_region(sc, off, sp4, sizeof(*sp4)); |
2587 | else |
2588 | ray_write_region(sc, off, sp5, sizeof(*sp5)); |
2589 | if (!ray_simple_cmd(sc, RAY_CMD_START_PARAMS, SCP_UPD_STARTUP)) |
2590 | panic("ray_download_params issue" ); |
2591 | } |
2592 | |
2593 | /* |
2594 | * start or join a network |
2595 | */ |
2596 | static void |
2597 | ray_start_join_net(struct ray_softc *sc) |
2598 | { |
2599 | struct ray_net_params np; |
2600 | bus_size_t ccs; |
2601 | int cmd; |
2602 | |
2603 | ray_cmd_cancel(sc, SCP_UPD_STARTJOIN); |
2604 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) |
2605 | return; |
2606 | |
2607 | /* XXX check we may not want to re-issue */ |
2608 | if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) { |
2609 | ray_cmd_schedule(sc, SCP_UPD_STARTJOIN); |
2610 | return; |
2611 | } |
2612 | |
2613 | if (sc->sc_mode == SC_MODE_ADHOC) |
2614 | cmd = RAY_CMD_START_NET; |
2615 | else |
2616 | cmd = RAY_CMD_JOIN_NET; |
2617 | |
2618 | if (!ray_alloc_ccs(sc, &ccs, cmd, SCP_UPD_STARTJOIN)) |
2619 | return; |
2620 | sc->sc_startccs = ccs; |
2621 | sc->sc_startcmd = cmd; |
2622 | if (!memcmp(&sc->sc_cnwid, &sc->sc_dnwid, sizeof(sc->sc_cnwid)) |
2623 | && sc->sc_omode == sc->sc_mode) |
2624 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_net, c_upd_param, 0); |
2625 | else { |
2626 | sc->sc_havenet = 0; |
2627 | memset(&np, 0, sizeof(np)); |
2628 | np.p_net_type = sc->sc_mode; |
2629 | memcpy(np.p_ssid, sc->sc_dnwid.i_nwid, sizeof(np.p_ssid)); |
2630 | ray_write_region(sc, RAY_HOST_TO_ECF_BASE, &np, sizeof(np)); |
2631 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_net, c_upd_param, 1); |
2632 | } |
2633 | if (ray_issue_cmd(sc, ccs, SCP_UPD_STARTJOIN)) |
2634 | callout_reset(&sc->sc_start_join_timo_ch, RAY_START_TIMEOUT, |
2635 | ray_start_join_timo, sc); |
2636 | } |
2637 | |
2638 | static void |
2639 | ray_start_join_timo(void *arg) |
2640 | { |
2641 | struct ray_softc *sc; |
2642 | u_int stat; |
2643 | |
2644 | sc = arg; |
2645 | stat = SRAM_READ_FIELD_1(sc, sc->sc_startccs, ray_cmd, c_status); |
2646 | ray_start_join_net_done(sc, sc->sc_startcmd, sc->sc_startccs, stat); |
2647 | } |
2648 | |
2649 | /* |
2650 | * The start/join has completed. Note: we timeout the start |
2651 | * command because it seems to fail to work at least on the |
2652 | * build 4 firmware without reporting an error. This actually |
2653 | * may be a result of not putting the correct params in the |
2654 | * initial download. If this is a timeout `stat' will be |
2655 | * marked busy. |
2656 | */ |
2657 | static ray_cmd_func_t |
2658 | ray_start_join_net_done(struct ray_softc *sc, u_int cmd, bus_size_t ccs, |
2659 | u_int stat) |
2660 | { |
2661 | int i; |
2662 | struct ray_net_params np; |
2663 | |
2664 | callout_stop(&sc->sc_start_join_timo_ch); |
2665 | ray_cmd_done(sc, SCP_UPD_STARTJOIN); |
2666 | |
2667 | if (stat == RAY_CCS_STATUS_FAIL) { |
2668 | /* XXX poke ifmedia when it supports this */ |
2669 | sc->sc_havenet = 0; |
2670 | return (ray_start_join_net); |
2671 | } |
2672 | if (stat == RAY_CCS_STATUS_BUSY || stat == RAY_CCS_STATUS_FREE) { |
2673 | /* handle the timeout condition */ |
2674 | callout_reset(&sc->sc_start_join_timo_ch, RAY_START_TIMEOUT, |
2675 | ray_start_join_timo, sc); |
2676 | |
2677 | /* be safe -- not a lot occurs with no net though */ |
2678 | if (!RAY_ECF_READY(sc)) |
2679 | return (0); |
2680 | |
2681 | /* see if our nwid is up to date */ |
2682 | if (!memcmp(&sc->sc_cnwid, &sc->sc_dnwid, sizeof(sc->sc_cnwid)) |
2683 | && sc->sc_omode == sc->sc_mode) |
2684 | SRAM_WRITE_FIELD_1(sc,ccs, ray_cmd_net, c_upd_param, 0); |
2685 | else { |
2686 | memset(&np, 0, sizeof(np)); |
2687 | np.p_net_type = sc->sc_mode; |
2688 | memcpy(np.p_ssid, sc->sc_dnwid.i_nwid, |
2689 | sizeof(np.p_ssid)); |
2690 | ray_write_region(sc, RAY_HOST_TO_ECF_BASE, &np, |
2691 | sizeof(np)); |
2692 | SRAM_WRITE_FIELD_1(sc,ccs, ray_cmd_net, c_upd_param, 1); |
2693 | } |
2694 | |
2695 | if (sc->sc_mode == SC_MODE_ADHOC) |
2696 | cmd = RAY_CMD_START_NET; |
2697 | else |
2698 | cmd = RAY_CMD_JOIN_NET; |
2699 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_net, c_cmd, |
2700 | RAY_CCS_STATUS_BUSY); |
2701 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_net, c_status, |
2702 | RAY_CCS_STATUS_BUSY); |
2703 | |
2704 | /* we simply poke the card again issuing the same ccs */ |
2705 | SRAM_WRITE_1(sc, RAY_SCB_CCSI, RAY_GET_INDEX(ccs)); |
2706 | RAY_ECF_START_CMD(sc); |
2707 | ray_cmd_ran(sc, SCP_UPD_STARTJOIN); |
2708 | return (0); |
2709 | } |
2710 | /* get the current ssid */ |
2711 | SRAM_READ_FIELD_N(sc, ccs, ray_cmd_net, c_bss_id, sc->sc_bssid, |
2712 | sizeof(sc->sc_bssid)); |
2713 | |
2714 | sc->sc_deftxrate = SRAM_READ_FIELD_1(sc, ccs, ray_cmd_net,c_def_txrate); |
2715 | sc->sc_encrypt = SRAM_READ_FIELD_1(sc, ccs, ray_cmd_net, c_encrypt); |
2716 | |
2717 | /* adjust values for buggy build 4 */ |
2718 | if (sc->sc_deftxrate == 0x55) |
2719 | sc->sc_deftxrate = RAY_PID_BASIC_RATE_1500K; |
2720 | if (sc->sc_encrypt == 0x55) |
2721 | sc->sc_encrypt = 0; |
2722 | |
2723 | if (SRAM_READ_FIELD_1(sc, ccs, ray_cmd_net, c_upd_param)) { |
2724 | ray_read_region(sc, RAY_HOST_TO_ECF_BASE, &np, sizeof(np)); |
2725 | /* XXX: Raylink firmware doesn't have length field for ssid */ |
2726 | for (i = 0; i < sizeof(np.p_ssid); i++) { |
2727 | if (np.p_ssid[i] == '\0') |
2728 | break; |
2729 | } |
2730 | sc->sc_cnwid.i_len = i; |
2731 | memcpy(sc->sc_cnwid.i_nwid, np.p_ssid, i); |
2732 | sc->sc_omode = sc->sc_mode; |
2733 | if (np.p_net_type != sc->sc_mode) |
2734 | return (ray_start_join_net); |
2735 | } |
2736 | RAY_DPRINTF(("%s: net start/join nwid %.32s bssid %s inited %d\n" , |
2737 | device_xname(sc->sc_dev), sc->sc_cnwid.i_nwid, |
2738 | ether_sprintf(sc->sc_bssid), |
2739 | SRAM_READ_FIELD_1(sc, ccs, ray_cmd_net, c_inited))); |
2740 | |
2741 | /* network is now active */ |
2742 | ray_cmd_schedule(sc, SCP_UPD_MCAST|SCP_UPD_PROMISC); |
2743 | if (cmd == RAY_CMD_JOIN_NET) |
2744 | return (ray_start_assoc); |
2745 | else { |
2746 | sc->sc_havenet = 1; |
2747 | return (ray_intr_start); |
2748 | } |
2749 | } |
2750 | |
2751 | /* |
2752 | * set the card in/out of promiscuous mode |
2753 | */ |
2754 | static void |
2755 | ray_update_promisc(struct ray_softc *sc) |
2756 | { |
2757 | bus_size_t ccs; |
2758 | int promisc; |
2759 | |
2760 | ray_cmd_cancel(sc, SCP_UPD_PROMISC); |
2761 | |
2762 | /* do the issue check before equality check */ |
2763 | if (sc->sc_if.if_flags & IFF_ALLMULTI) |
2764 | sc->sc_if.if_flags |= IFF_PROMISC; |
2765 | else if (sc->sc_if.if_pcount == 0) |
2766 | sc->sc_if.if_flags &= ~IFF_PROMISC; |
2767 | promisc = !!(sc->sc_if.if_flags & IFF_PROMISC); |
2768 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) |
2769 | return; |
2770 | else if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) { |
2771 | ray_cmd_schedule(sc, SCP_UPD_PROMISC); |
2772 | return; |
2773 | } else if (promisc == sc->sc_promisc) |
2774 | return; |
2775 | else if (!ray_alloc_ccs(sc,&ccs,RAY_CMD_UPDATE_PARAMS, SCP_UPD_PROMISC)) |
2776 | return; |
2777 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_update, c_paramid, RAY_PID_PROMISC); |
2778 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_update, c_nparam, 1); |
2779 | SRAM_WRITE_1(sc, RAY_HOST_TO_ECF_BASE, promisc); |
2780 | (void)ray_issue_cmd(sc, ccs, SCP_UPD_PROMISC); |
2781 | } |
2782 | |
2783 | /* |
2784 | * update the parameter based on what the user passed in |
2785 | */ |
2786 | static void |
2787 | ray_update_params(struct ray_softc *sc) |
2788 | { |
2789 | bus_size_t ccs; |
2790 | |
2791 | ray_cmd_cancel(sc, SCP_UPD_UPDATEPARAMS); |
2792 | if (!sc->sc_updreq) { |
2793 | /* XXX do we need to wakeup here? */ |
2794 | return; |
2795 | } |
2796 | |
2797 | /* do the issue check before equality check */ |
2798 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) |
2799 | return; |
2800 | else if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) { |
2801 | ray_cmd_schedule(sc, SCP_UPD_UPDATEPARAMS); |
2802 | return; |
2803 | } else if (!ray_alloc_ccs(sc, &ccs, RAY_CMD_UPDATE_PARAMS, |
2804 | SCP_UPD_UPDATEPARAMS)) |
2805 | return; |
2806 | |
2807 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_update, c_paramid, |
2808 | sc->sc_updreq->r_paramid); |
2809 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_update, c_nparam, 1); |
2810 | ray_write_region(sc, RAY_HOST_TO_ECF_BASE, sc->sc_updreq->r_data, |
2811 | sc->sc_updreq->r_len); |
2812 | |
2813 | (void)ray_issue_cmd(sc, ccs, SCP_UPD_UPDATEPARAMS); |
2814 | } |
2815 | |
2816 | /* |
2817 | * set the multicast filter list |
2818 | */ |
2819 | static void |
2820 | ray_update_mcast(struct ray_softc *sc) |
2821 | { |
2822 | bus_size_t ccs; |
2823 | struct ether_multistep step; |
2824 | struct ether_multi *enm; |
2825 | struct ethercom *ec; |
2826 | bus_size_t bufp; |
2827 | int count; |
2828 | |
2829 | ec = &sc->sc_ec; |
2830 | ray_cmd_cancel(sc, SCP_UPD_MCAST); |
2831 | |
2832 | /* see if we have any ranges */ |
2833 | if ((count = sc->sc_ec.ec_multicnt) < 17) { |
2834 | ETHER_FIRST_MULTI(step, ec, enm); |
2835 | while (enm) { |
2836 | /* see if this is a range */ |
2837 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, |
2838 | ETHER_ADDR_LEN)) { |
2839 | count = 17; |
2840 | break; |
2841 | } |
2842 | ETHER_NEXT_MULTI(step, enm); |
2843 | } |
2844 | } |
2845 | |
2846 | /* track this stuff even when not running */ |
2847 | if (count > 16) { |
2848 | sc->sc_if.if_flags |= IFF_ALLMULTI; |
2849 | ray_update_promisc(sc); |
2850 | return; |
2851 | } else if (sc->sc_if.if_flags & IFF_ALLMULTI) { |
2852 | sc->sc_if.if_flags &= ~IFF_ALLMULTI; |
2853 | ray_update_promisc(sc); |
2854 | } |
2855 | |
2856 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) |
2857 | return; |
2858 | else if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) { |
2859 | ray_cmd_schedule(sc, SCP_UPD_MCAST); |
2860 | return; |
2861 | } else if (!ray_alloc_ccs(sc,&ccs, RAY_CMD_UPDATE_MCAST, SCP_UPD_MCAST)) |
2862 | return; |
2863 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_update_mcast, c_nmcast, count); |
2864 | bufp = RAY_HOST_TO_ECF_BASE; |
2865 | ETHER_FIRST_MULTI(step, ec, enm); |
2866 | while (enm) { |
2867 | ray_write_region(sc, bufp, enm->enm_addrlo, ETHER_ADDR_LEN); |
2868 | bufp += ETHER_ADDR_LEN; |
2869 | ETHER_NEXT_MULTI(step, enm); |
2870 | } |
2871 | (void)ray_issue_cmd(sc, ccs, SCP_UPD_MCAST); |
2872 | } |
2873 | |
2874 | /* |
2875 | * User issued commands |
2876 | */ |
2877 | |
2878 | /* |
2879 | * issue an "update params" |
2880 | * |
2881 | * expected to be called in sleepable context -- intended for user stuff |
2882 | */ |
2883 | static int |
2884 | ray_user_update_params(struct ray_softc *sc, struct ray_param_req *pr) |
2885 | { |
2886 | int rv; |
2887 | |
2888 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) { |
2889 | pr->r_failcause = RAY_FAILCAUSE_EDEVSTOP; |
2890 | return (EIO); |
2891 | } |
2892 | |
2893 | /* wait to be able to issue the command */ |
2894 | rv = 0; |
2895 | while (ray_cmd_is_running(sc, SCP_UPD_UPDATEPARAMS) || |
2896 | ray_cmd_is_scheduled(sc, SCP_UPD_UPDATEPARAMS)) { |
2897 | rv = tsleep(ray_update_params, 0|PCATCH, "cmd in use" , 0); |
2898 | if (rv) |
2899 | return (rv); |
2900 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) { |
2901 | pr->r_failcause = RAY_FAILCAUSE_EDEVSTOP; |
2902 | return (EIO); |
2903 | } |
2904 | } |
2905 | |
2906 | pr->r_failcause = RAY_FAILCAUSE_WAITING; |
2907 | sc->sc_updreq = pr; |
2908 | ray_cmd_schedule(sc, SCP_UPD_UPDATEPARAMS); |
2909 | ray_check_scheduled(sc); |
2910 | |
2911 | while (pr->r_failcause == RAY_FAILCAUSE_WAITING) |
2912 | (void)tsleep(ray_update_params, 0, "waiting cmd" , 0); |
2913 | wakeup(ray_update_params); |
2914 | |
2915 | return (0); |
2916 | } |
2917 | |
2918 | /* |
2919 | * issue a report params |
2920 | * |
2921 | * expected to be called in sleepable context -- intended for user stuff |
2922 | */ |
2923 | static int |
2924 | ray_user_report_params(struct ray_softc *sc, struct ray_param_req *pr) |
2925 | { |
2926 | int rv; |
2927 | |
2928 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) { |
2929 | pr->r_failcause = RAY_FAILCAUSE_EDEVSTOP; |
2930 | return (EIO); |
2931 | } |
2932 | |
2933 | /* wait to be able to issue the command */ |
2934 | rv = 0; |
2935 | while (ray_cmd_is_running(sc, SCP_REPORTPARAMS) |
2936 | || ray_cmd_is_scheduled(sc, SCP_REPORTPARAMS)) { |
2937 | rv = tsleep(ray_report_params, 0|PCATCH, "cmd in use" , 0); |
2938 | if (rv) |
2939 | return (rv); |
2940 | if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) { |
2941 | pr->r_failcause = RAY_FAILCAUSE_EDEVSTOP; |
2942 | return (EIO); |
2943 | } |
2944 | } |
2945 | |
2946 | pr->r_failcause = RAY_FAILCAUSE_WAITING; |
2947 | sc->sc_repreq = pr; |
2948 | ray_cmd_schedule(sc, SCP_REPORTPARAMS); |
2949 | ray_check_scheduled(sc); |
2950 | |
2951 | while (pr->r_failcause == RAY_FAILCAUSE_WAITING) |
2952 | (void)tsleep(ray_report_params, 0, "waiting cmd" , 0); |
2953 | wakeup(ray_report_params); |
2954 | |
2955 | return (0); |
2956 | } |
2957 | |
2958 | |
2959 | /* |
2960 | * this is a temporary wrapper around bus_space_read_region_1 |
2961 | * as it seems to mess with gcc. the line numbers get offset |
2962 | * presumably this is related to the inline asm on i386. |
2963 | */ |
2964 | |
2965 | static void |
2966 | ray_read_region(struct ray_softc *sc, bus_size_t off, void *vp, size_t c) |
2967 | { |
2968 | #ifdef RAY_USE_OPTIMIZED_COPY |
2969 | u_int n2, n4, tmp; |
2970 | u_int8_t *p; |
2971 | |
2972 | p = vp; |
2973 | |
2974 | /* XXX we may be making poor assumptions here but lets hope */ |
2975 | switch ((off|(bus_addr_t)p) & 0x03) { |
2976 | case 0: |
2977 | if ((n4 = c / 4)) { |
2978 | bus_space_read_region_4(sc->sc_memt, sc->sc_memh, off, |
2979 | p, n4); |
2980 | tmp = c & ~0x3; |
2981 | c &= 0x3; |
2982 | p += tmp; |
2983 | off += tmp; |
2984 | } |
2985 | switch (c) { |
2986 | case 3: |
2987 | *p = bus_space_read_1(sc->sc_memt,sc->sc_memh, off); |
2988 | p++, off++; |
2989 | case 2: |
2990 | *p = bus_space_read_1(sc->sc_memt,sc->sc_memh, off); |
2991 | p++, off++; |
2992 | case 1: |
2993 | *p = bus_space_read_1(sc->sc_memt,sc->sc_memh, off); |
2994 | } |
2995 | break; |
2996 | case 2: |
2997 | if ((n2 = (c >> 1))) |
2998 | bus_space_read_region_2(sc->sc_memt, sc->sc_memh, off, |
2999 | p, n2); |
3000 | if (c & 1) { |
3001 | c &= ~0x1; |
3002 | *(p + c) = bus_space_read_1(sc->sc_memt, sc->sc_memh, |
3003 | off + c); |
3004 | } |
3005 | break; |
3006 | case 1: |
3007 | case 3: |
3008 | bus_space_read_region_1(sc->sc_memt, sc->sc_memh, off, p, c); |
3009 | break; |
3010 | } |
3011 | #else |
3012 | bus_space_read_region_1(sc->sc_memt, sc->sc_memh, off, vp, c); |
3013 | #endif |
3014 | } |
3015 | |
3016 | /* |
3017 | * this is a temporary wrapper around bus_space_write_region_1 |
3018 | * as it seems to mess with gcc. the line numbers get offset |
3019 | * presumably this is related to the inline asm on i386. |
3020 | */ |
3021 | static void |
3022 | ray_write_region(struct ray_softc *sc, bus_size_t off, void *vp, size_t c) |
3023 | { |
3024 | #ifdef RAY_USE_OPTIMIZED_COPY |
3025 | size_t n2, n4, tmp; |
3026 | u_int8_t *p; |
3027 | |
3028 | p = vp; |
3029 | /* XXX we may be making poor assumptions here but lets hope */ |
3030 | switch ((off|(bus_addr_t)p) & 0x03) { |
3031 | case 0: |
3032 | if ((n4 = (c >> 2))) { |
3033 | bus_space_write_region_4(sc->sc_memt, sc->sc_memh, off, |
3034 | p, n4); |
3035 | tmp = c & ~0x3; |
3036 | c &= 0x3; |
3037 | p += tmp; |
3038 | off += tmp; |
3039 | } |
3040 | switch (c) { |
3041 | case 3: |
3042 | bus_space_write_1(sc->sc_memt,sc->sc_memh, off, *p); |
3043 | p++, off++; |
3044 | case 2: |
3045 | bus_space_write_1(sc->sc_memt,sc->sc_memh, off, *p); |
3046 | p++, off++; |
3047 | case 1: |
3048 | bus_space_write_1(sc->sc_memt,sc->sc_memh, off, *p); |
3049 | } |
3050 | break; |
3051 | case 2: |
3052 | if ((n2 = (c >> 1))) |
3053 | bus_space_write_region_2(sc->sc_memt, sc->sc_memh, off, |
3054 | p, n2); |
3055 | if (c & 0x1) { |
3056 | c &= ~0x1; |
3057 | bus_space_write_1(sc->sc_memt, sc->sc_memh, |
3058 | off + c, *(p + c)); |
3059 | } |
3060 | break; |
3061 | case 1: |
3062 | case 3: |
3063 | bus_space_write_region_1(sc->sc_memt, sc->sc_memh, off, p, c); |
3064 | break; |
3065 | } |
3066 | #else |
3067 | bus_space_write_region_1(sc->sc_memt, sc->sc_memh, off, vp, c); |
3068 | #endif |
3069 | } |
3070 | |
3071 | #ifdef RAY_DEBUG |
3072 | |
3073 | #define PRINTABLE(c) ((c) >= 0x20 && (c) <= 0x7f) |
3074 | |
3075 | void |
3076 | hexdump(const u_int8_t *d, int len, int br, int div, int fl) |
3077 | { |
3078 | int i, j, offw, first, tlen, ni, nj, sp; |
3079 | |
3080 | sp = br / div; |
3081 | offw = 0; |
3082 | if (len && (fl & HEXDF_NOOFFSET) == 0) { |
3083 | tlen = len; |
3084 | do { |
3085 | offw++; |
3086 | } while (tlen /= br); |
3087 | } |
3088 | if (offw) |
3089 | printf("%0*x: " , offw, 0); |
3090 | for (i = 0; i < len; i++, d++) { |
3091 | if (i && (i % br) == 0) { |
3092 | if ((fl & HEXDF_NOASCII) == 0) { |
3093 | printf(" " ); |
3094 | d -= br; |
3095 | for (j = 0; j < br; d++, j++) { |
3096 | if (j && (j % sp) == 0) |
3097 | printf(" " ); |
3098 | if (PRINTABLE(*d)) |
3099 | printf("%c" , (int)*d); |
3100 | else |
3101 | printf("." ); |
3102 | } |
3103 | } |
3104 | if (offw) |
3105 | printf("\n%0*x: " , offw, i); |
3106 | else |
3107 | printf("\n" ); |
3108 | if ((fl & HEXDF_NOCOMPRESS) == 0) { |
3109 | first = 1; |
3110 | while (len - i >= br) { |
3111 | if (memcmp(d, d - br, br)) |
3112 | break; |
3113 | d += br; |
3114 | i += br; |
3115 | if (first) { |
3116 | printf("*" ); |
3117 | first = 0; |
3118 | } |
3119 | } |
3120 | if (len == i) { |
3121 | printf("\n%0*x" , offw, i); |
3122 | return; |
3123 | } |
3124 | } |
3125 | } else if (i && (i % sp) == 0) |
3126 | printf(" " ); |
3127 | printf("%02x " , *d); |
3128 | } |
3129 | if (len && (((i - 1) % br) || i == 1)) { |
3130 | if ((fl & HEXDF_NOASCII) == 0) { |
3131 | i = i % br ? i % br : br; |
3132 | ni = (br - i) % br; |
3133 | j = (i - 1) / sp; |
3134 | nj = (div - j - 1) % div; |
3135 | j = 3 * ni + nj + 3; |
3136 | printf("%*s" , j, "" ); |
3137 | d -= i; |
3138 | for (j = 0; j < i; d++, j++) { |
3139 | if (j && (j % sp) == 0) |
3140 | printf(" " ); |
3141 | if (PRINTABLE(*d)) |
3142 | printf("%c" , (int)*d); |
3143 | else |
3144 | printf("." ); |
3145 | } |
3146 | } |
3147 | printf("\n" ); |
3148 | } |
3149 | } |
3150 | |
3151 | |
3152 | |
3153 | static void |
3154 | ray_dump_mbuf(struct ray_softc *sc, struct mbuf *m) |
3155 | { |
3156 | u_int8_t *d, *ed; |
3157 | u_int i; |
3158 | |
3159 | printf("%s: pkt dump:" , device_xname(sc->sc_dev)); |
3160 | i = 0; |
3161 | for (; m; m = m->m_next) { |
3162 | d = mtod(m, u_int8_t *); |
3163 | ed = d + m->m_len; |
3164 | |
3165 | for (; d < ed; i++, d++) { |
3166 | if ((i % 16) == 0) |
3167 | printf("\n\t" ); |
3168 | else if ((i % 8) == 0) |
3169 | printf(" " ); |
3170 | printf(" %02x" , *d); |
3171 | } |
3172 | } |
3173 | if ((i - 1) % 16) |
3174 | printf("\n" ); |
3175 | } |
3176 | #endif /* RAY_DEBUG */ |
3177 | |
3178 | #ifdef RAY_DO_SIGLEV |
3179 | static void |
3180 | ray_update_siglev(struct ray_softc *sc, u_int8_t *src, u_int8_t siglev) |
3181 | { |
3182 | int i, mini; |
3183 | struct timeval mint; |
3184 | struct ray_siglev *sl; |
3185 | |
3186 | /* try to find host */ |
3187 | for (i = 0; i < RAY_NSIGLEVRECS; i++) { |
3188 | sl = &sc->sc_siglevs[i]; |
3189 | if (memcmp(sl->rsl_host, src, ETHER_ADDR_LEN) == 0) |
3190 | goto found; |
3191 | } |
3192 | /* not found, find oldest slot */ |
3193 | mini = 0; |
3194 | mint.tv_sec = LONG_MAX; |
3195 | mint.tv_usec = 0; |
3196 | for (i = 0; i < RAY_NSIGLEVRECS; i++) { |
3197 | sl = &sc->sc_siglevs[i]; |
3198 | if (timercmp(&sl->rsl_time, &mint, <)) { |
3199 | mini = i; |
3200 | mint = sl->rsl_time; |
3201 | } |
3202 | } |
3203 | sl = &sc->sc_siglevs[mini]; |
3204 | memset(sl->rsl_siglevs, 0, RAY_NSIGLEV); |
3205 | memcpy(sl->rsl_host, src, ETHER_ADDR_LEN); |
3206 | |
3207 | found: |
3208 | microtime(&sl->rsl_time); |
3209 | memmove(&sl->rsl_siglevs[1], sl->rsl_siglevs, RAY_NSIGLEV-1); |
3210 | sl->rsl_siglevs[0] = siglev; |
3211 | } |
3212 | #endif |
3213 | |