| 1 | /* |
| 2 | * Copyright (C) 2000 |
| 3 | * Dr. Duncan McLennan Barclay, dmlb@ragnet.demon.co.uk. |
| 4 | * |
| 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 DUNCAN BARCLAY 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 DUNCAN BARCLAY 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 | * $FreeBSD: src/sys/dev/ray/if_ray.c,v 1.47.2.4 2001/08/14 22:54:05 dmlb Exp $ |
| 32 | * $DragonFly: src/sys/dev/netif/ray/Attic/if_ray.c,v 1.17 2005/02/19 22:24:13 joerg Exp $ |
| 33 | * |
| 34 | */ |
| 35 | |
| 36 | /* $NetBSD: if_ray.c,v 1.12 2000/02/07 09:36:27 augustss Exp $ */ |
| 37 | /* |
| 38 | * Copyright (c) 2000 Christian E. Hopps |
| 39 | * All rights reserved. |
| 40 | * |
| 41 | * Redistribution and use in source and binary forms, with or without |
| 42 | * modification, are permitted provided that the following conditions |
| 43 | * are met: |
| 44 | * 1. Redistributions of source code must retain the above copyright |
| 45 | * notice, this list of conditions and the following disclaimer. |
| 46 | * 2. Redistributions in binary form must reproduce the above copyright |
| 47 | * notice, this list of conditions and the following disclaimer in the |
| 48 | * documentation and/or other materials provided with the distribution. |
| 49 | * 3. Neither the name of the author nor the names of any co-contributors |
| 50 | * may be used to endorse or promote products derived from this software |
| 51 | * without specific prior written permission. |
| 52 | * |
| 53 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 54 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 55 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 56 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 57 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 58 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 59 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 60 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 61 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 62 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 63 | * SUCH DAMAGE. |
| 64 | */ |
| 65 | |
| 66 | /* |
| 67 | * Card configuration |
| 68 | * ================== |
| 69 | * |
| 70 | * This card is unusual in that it uses both common and attribute |
| 71 | * memory whilst working. It should use common memory and an IO port. |
| 72 | * |
| 73 | * The bus resource allocations need to work around the brain deadness |
| 74 | * of pccardd (where it reads the CIS for common memory, sets it all |
| 75 | * up and then throws it all away assuming the card is an ed |
| 76 | * driver...). Note that this could be dangerous (because it doesn't |
| 77 | * interact with pccardd) if you use other memory mapped cards in the |
| 78 | * same pccard slot as currently old mappings are not cleaned up very well |
| 79 | * by the bus_release_resource methods or pccardd. |
| 80 | * |
| 81 | * There is no support for running this driver on 4.0. |
| 82 | * |
| 83 | * Ad-hoc and infra-structure modes |
| 84 | * ================================ |
| 85 | * |
| 86 | * The driver supports ad-hoc mode for V4 firmware and infrastructure |
| 87 | * mode for V5 firmware. V5 firmware in ad-hoc mode is untested and should |
| 88 | * work. |
| 89 | * |
| 90 | * The Linux driver also seems to have the capability to act as an AP. |
| 91 | * I wonder what facilities the "AP" can provide within a driver? We can |
| 92 | * probably use the BRIDGE code to form an ESS but I don't think |
| 93 | * power saving etc. is easy. |
| 94 | * |
| 95 | * |
| 96 | * Packet framing/encapsulation/translation |
| 97 | * ======================================== |
| 98 | * |
| 99 | * Currently we support the Webgear encapsulation: |
| 100 | * 802.11 header <net/if_ieee80211.h>struct ieee80211_frame |
| 101 | * 802.3 header <net/ethernet.h>struct ether_header |
| 102 | * IP/ARP payload |
| 103 | * |
| 104 | * and RFC1042 encapsulation of IP datagrams (translation): |
| 105 | * 802.11 header <net/if_ieee80211.h>struct ieee80211_frame |
| 106 | * 802.2 LLC header |
| 107 | * 802.2 SNAP header |
| 108 | * 802.3 Ethertype |
| 109 | * IP/ARP payload |
| 110 | * |
| 111 | * Framing should be selected via if_media stuff or link types but |
| 112 | * is currently hardcoded to: |
| 113 | * V4 encapsulation |
| 114 | * V5 translation |
| 115 | * |
| 116 | * |
| 117 | * Authentication |
| 118 | * ============== |
| 119 | * |
| 120 | * 802.11 provides two authentication mechanisms. The first is a very |
| 121 | * simple host based mechanism (like xhost) called Open System and the |
| 122 | * second is a more complex challenge/response called Shared Key built |
| 123 | * ontop of WEP. |
| 124 | * |
| 125 | * This driver only supports Open System and does not implement any |
| 126 | * host based control lists. In otherwords authentication is always |
| 127 | * granted to hosts wanting to authenticate with this station. This is |
| 128 | * the only sensible behaviour as the Open System mechanism uses MAC |
| 129 | * addresses to identify hosts. Send me patches if you need it! |
| 130 | */ |
| 131 | |
| 132 | /* |
| 133 | * ***check all XXX_INFRA code - reassoc not done well at all! |
| 134 | * ***watchdog to catch screwed up removals? |
| 135 | * ***error handling of RAY_COM_RUNQ |
| 136 | * ***error handling of ECF command completions |
| 137 | * ***can't seem to create a n/w that Win95 wants to see. |
| 138 | * ***remove panic in ray_com_ecf by re-quing or timeout |
| 139 | * ***use new ioctl stuff - probably need to change RAY_COM_FCHKRUNNING things? |
| 140 | * consider user doing: |
| 141 | * ifconfig ray0 192.168.200.38 -bssid "freed" |
| 142 | * ifconfig ray0 192.168.200.38 -bssid "fred" |
| 143 | * here the second one would be missed in this code |
| 144 | * check that v5 needs timeouts on ecf commands |
| 145 | * write up driver structure in comments above |
| 146 | * UPDATE_PARAMS seems to return via an interrupt - maybe the timeout |
| 147 | * is needed for wrong values? |
| 148 | * proper setting of mib_hop_seq_len with country code for v4 firmware |
| 149 | * best done with raycontrol? |
| 150 | * countrycode setting is broken I think |
| 151 | * userupdate should trap and do via startjoin etc. |
| 152 | * fragmentation when rx level drops? |
| 153 | * v5 might not need download |
| 154 | * defaults are as documented apart from hop_seq_length |
| 155 | * settings are sane for ad-hoc not infra |
| 156 | * |
| 157 | * driver state |
| 158 | * most state is implied by the sequence of commands in the runq |
| 159 | * but in fact any of the rx and tx path that uses variables |
| 160 | * in the sc_c are potentially going to get screwed? |
| 161 | * |
| 162 | * infra mode stuff |
| 163 | * proper handling of the basic rate set - see the manual |
| 164 | * all ray_sj, ray_assoc sequencues need a "nicer" solution as we |
| 165 | * remember association and authentication |
| 166 | * need to consider WEP |
| 167 | * acting as ap - should be able to get working from the manual |
| 168 | * need to finish RAY_ECMD_REJOIN_DONE |
| 169 | * finish authenitcation code, it doesn't handle errors/timeouts/ |
| 170 | * REJOIN etc. |
| 171 | * |
| 172 | * ray_nw_param |
| 173 | * promisc in here too? - done |
| 174 | * should be able to update the parameters before we download to the |
| 175 | * device. This means we must attach a desired struct to the |
| 176 | * runq entry and maybe have another big case statement to |
| 177 | * move these desired into current when not running. |
| 178 | * init must then use the current settings (pre-loaded |
| 179 | * in attach now!) and pass to download. But we can't access |
| 180 | * current nw params outside of the runq - ahhh |
| 181 | * differeniate between parameters set in attach and init |
| 182 | * sc_station_addr in here too (for changing mac address) |
| 183 | * move desired into the command structure? |
| 184 | * take downloaded MIB from a complete nw_param? |
| 185 | * longer term need to attach a desired nw params to the runq entry |
| 186 | * |
| 187 | * |
| 188 | * RAY_COM_RUNQ errors |
| 189 | * |
| 190 | * if sleeping in ccs_alloc with eintr/erestart/enxio/enodev |
| 191 | * erestart try again from the top |
| 192 | * XXX do not malloc more comqs |
| 193 | * XXX ccs allocation hard |
| 194 | * eintr clean up and return |
| 195 | * enxio clean up and return - done in macro |
| 196 | * |
| 197 | * if sleeping in runq_arr itself with eintr/erestart/enxio/enodev |
| 198 | * erestart try again from the top |
| 199 | * XXX do not malloc more comqs |
| 200 | * XXX ccs allocation hard |
| 201 | * XXX reinsert comqs at head of list |
| 202 | * eintr clean up and return |
| 203 | * enxio clean up and return - done in macro |
| 204 | */ |
| 205 | |
| 206 | #define XXX 0 |
| 207 | #define XXX_ACTING_AP 0 |
| 208 | #define XXX_INFRA 0 |
| 209 | #define RAY_DEBUG ( \ |
| 210 | /* RAY_DBG_AUTH | */ \ |
| 211 | /* RAY_DBG_SUBR | */ \ |
| 212 | /* RAY_DBG_BOOTPARAM | */ \ |
| 213 | /* RAY_DBG_STARTJOIN | */ \ |
| 214 | /* RAY_DBG_CCS | */ \ |
| 215 | /* RAY_DBG_IOCTL | */ \ |
| 216 | /* RAY_DBG_MBUF | */ \ |
| 217 | /* RAY_DBG_RX | */ \ |
| 218 | /* RAY_DBG_CM | */ \ |
| 219 | /* RAY_DBG_COM | */ \ |
| 220 | /* RAY_DBG_STOP | */ \ |
| 221 | /* RAY_DBG_CTL | */ \ |
| 222 | /* RAY_DBG_MGT | */ \ |
| 223 | /* RAY_DBG_TX | */ \ |
| 224 | /* RAY_DBG_DCOM | */ \ |
| 225 | 0 \ |
| 226 | ) |
| 227 | |
| 228 | /* |
| 229 | * XXX build options - move to LINT |
| 230 | */ |
| 231 | #define RAY_CM_RID 0 /* pccardd abuses windows 0 and 1 */ |
| 232 | #define RAY_AM_RID 3 /* pccardd abuses windows 0 and 1 */ |
| 233 | #define RAY_COM_TIMEOUT (hz/2) /* Timeout for CCS commands */ |
| 234 | #define RAY_TX_TIMEOUT (hz/2) /* Timeout for rescheduling TX */ |
| 235 | #define RAY_ECF_SPIN_DELAY 1000 /* Wait 1ms before checking ECF ready */ |
| 236 | #define RAY_ECF_SPIN_TRIES 10 /* Wait this many times for ECF ready */ |
| 237 | /* |
| 238 | * XXX build options - move to LINT |
| 239 | */ |
| 240 | |
| 241 | #ifndef RAY_DEBUG |
| 242 | #define RAY_DEBUG 0x0000 |
| 243 | #endif /* RAY_DEBUG */ |
| 244 | |
| 245 | #include <sys/param.h> |
| 246 | #include <sys/systm.h> |
| 247 | #include <sys/malloc.h> |
| 248 | #include <sys/kernel.h> |
| 249 | |
| 250 | #include <machine/bus.h> |
| 251 | #include <machine/resource.h> |
| 252 | #include <machine/clock.h> |
| 253 | #include <sys/bus.h> |
| 254 | #include <sys/rman.h> |
| 255 | |
| 256 | #include <sys/mbuf.h> |
| 257 | #include <sys/socket.h> |
| 258 | #include <sys/sockio.h> |
| 259 | |
| 260 | #include <net/bpf.h> |
| 261 | #include <net/ethernet.h> |
| 262 | #include <net/if.h> |
| 263 | #include <net/ifq_var.h> |
| 264 | #include <net/if_arp.h> |
| 265 | #include <net/if_dl.h> |
| 266 | #include <net/if_llc.h> |
| 267 | |
| 268 | #include <netproto/802_11/ieee80211.h> |
| 269 | #include <netproto/802_11/ieee80211_ioctl.h> |
| 270 | |
| 271 | #include <machine/limits.h> |
| 272 | |
| 273 | #include <bus/pccard/pccardvar.h> |
| 274 | #include "card_if.h" |
| 275 | |
| 276 | #include "if_rayreg.h" |
| 277 | #include "if_raymib.h" |
| 278 | #include "if_raydbg.h" |
| 279 | #include "if_rayvar.h" |
| 280 | |
| 281 | /* |
| 282 | * Prototyping |
| 283 | */ |
| 284 | static int ray_attach (device_t); |
| 285 | static int ray_ccs_alloc (struct ray_softc *sc, size_t *ccsp, char *wmesg); |
| 286 | static void ray_ccs_fill (struct ray_softc *sc, size_t ccs, u_int cmd); |
| 287 | static void ray_ccs_free (struct ray_softc *sc, size_t ccs); |
| 288 | static int ray_ccs_tx (struct ray_softc *sc, size_t *ccsp, size_t *bufpp); |
| 289 | static void ray_com_ecf (struct ray_softc *sc, struct ray_comq_entry *com); |
| 290 | static void ray_com_ecf_done (struct ray_softc *sc); |
| 291 | static void ray_com_ecf_timo (void *xsc); |
| 292 | static struct ray_comq_entry * |
| 293 | ray_com_init (struct ray_comq_entry *com, ray_comqfn_t function, int flags, char *mesg); |
| 294 | static struct ray_comq_entry * |
| 295 | ray_com_malloc (ray_comqfn_t function, int flags, char *mesg); |
| 296 | static void ray_com_runq (struct ray_softc *sc); |
| 297 | static int ray_com_runq_add (struct ray_softc *sc, struct ray_comq_entry *com[], int ncom, char *wmesg); |
| 298 | static void ray_com_runq_done (struct ray_softc *sc); |
| 299 | static int ray_detach (device_t); |
| 300 | static void ray_init (void *xsc); |
| 301 | static int ray_init_user (struct ray_softc *sc); |
| 302 | static void ray_init_assoc (struct ray_softc *sc, struct ray_comq_entry *com); |
| 303 | static void ray_init_assoc_done (struct ray_softc *sc, u_int8_t status, size_t ccs); |
| 304 | static void ray_init_auth (struct ray_softc *sc, struct ray_comq_entry *com); |
| 305 | static int ray_init_auth_send (struct ray_softc *sc, u_int8_t *dst, int sequence); |
| 306 | static void ray_init_auth_done (struct ray_softc *sc, u_int8_t status); |
| 307 | static void ray_init_download (struct ray_softc *sc, struct ray_comq_entry *com); |
| 308 | static void ray_init_download_done (struct ray_softc *sc, u_int8_t status, size_t ccs); |
| 309 | static void ray_init_download_v4 (struct ray_softc *sc, struct ray_comq_entry *com); |
| 310 | static void ray_init_download_v5 (struct ray_softc *sc, struct ray_comq_entry *com); |
| 311 | static void ray_init_mcast (struct ray_softc *sc, struct ray_comq_entry *com); |
| 312 | static void ray_init_sj (struct ray_softc *sc, struct ray_comq_entry *com); |
| 313 | static void ray_init_sj_done (struct ray_softc *sc, u_int8_t status, size_t ccs); |
| 314 | static void ray_intr (void *xsc); |
| 315 | static void ray_intr_ccs (struct ray_softc *sc, u_int8_t cmd, u_int8_t status, size_t ccs); |
| 316 | static void ray_intr_rcs (struct ray_softc *sc, u_int8_t cmd, size_t ccs); |
| 317 | static void ray_intr_updt_errcntrs (struct ray_softc *sc); |
| 318 | static int ray_ioctl (struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr); |
| 319 | static void ray_mcast (struct ray_softc *sc, struct ray_comq_entry *com); |
| 320 | static void ray_mcast_done (struct ray_softc *sc, u_int8_t status, size_t ccs); |
| 321 | static int ray_mcast_user (struct ray_softc *sc); |
| 322 | static int ray_probe (device_t); |
| 323 | static void ray_promisc (struct ray_softc *sc, struct ray_comq_entry *com); |
| 324 | static void ray_repparams (struct ray_softc *sc, struct ray_comq_entry *com); |
| 325 | static void ray_repparams_done (struct ray_softc *sc, u_int8_t status, size_t ccs); |
| 326 | static int ray_repparams_user (struct ray_softc *sc, struct ray_param_req *pr); |
| 327 | static int ray_repstats_user (struct ray_softc *sc, struct ray_stats_req *sr); |
| 328 | static int ray_res_alloc_am (struct ray_softc *sc); |
| 329 | static int ray_res_alloc_cm (struct ray_softc *sc); |
| 330 | static int ray_res_alloc_irq (struct ray_softc *sc); |
| 331 | static void ray_res_release (struct ray_softc *sc); |
| 332 | static void ray_rx (struct ray_softc *sc, size_t rcs); |
| 333 | static void ray_rx_ctl (struct ray_softc *sc, struct mbuf *m0); |
| 334 | static void ray_rx_data (struct ray_softc *sc, struct mbuf *m0, u_int8_t siglev, u_int8_t antenna); |
| 335 | static void ray_rx_mgt (struct ray_softc *sc, struct mbuf *m0); |
| 336 | static void ray_rx_mgt_auth (struct ray_softc *sc, struct mbuf *m0); |
| 337 | static void ray_rx_mgt_beacon (struct ray_softc *sc, struct mbuf *m0); |
| 338 | static void ray_rx_mgt_info (struct ray_softc *sc, struct mbuf *m0, struct ieee80211_information *elements); |
| 339 | static void ray_rx_update_cache (struct ray_softc *sc, u_int8_t *src, u_int8_t siglev, u_int8_t antenna); |
| 340 | static void ray_stop (struct ray_softc *sc, struct ray_comq_entry *com); |
| 341 | static int ray_stop_user (struct ray_softc *sc); |
| 342 | static void ray_tx (struct ifnet *ifp); |
| 343 | static void ray_tx_done (struct ray_softc *sc, u_int8_t status, size_t ccs); |
| 344 | static void ray_tx_timo (void *xsc); |
| 345 | static int ray_tx_send (struct ray_softc *sc, size_t ccs, int pktlen, u_int8_t *dst); |
| 346 | static size_t ray_tx_wrhdr (struct ray_softc *sc, size_t bufp, u_int8_t type, u_int8_t fc1, u_int8_t *addr1, u_int8_t *addr2, u_int8_t *addr3); |
| 347 | static void ray_upparams (struct ray_softc *sc, struct ray_comq_entry *com); |
| 348 | static void ray_upparams_done (struct ray_softc *sc, u_int8_t status, size_t ccs); |
| 349 | static int ray_upparams_user (struct ray_softc *sc, struct ray_param_req *pr); |
| 350 | static void ray_watchdog (struct ifnet *ifp); |
| 351 | static u_int8_t ray_tx_best_antenna (struct ray_softc *sc, u_int8_t *dst); |
| 352 | |
| 353 | #if RAY_DEBUG & RAY_DBG_COM |
| 354 | static void ray_com_ecf_check (struct ray_softc *sc, size_t ccs, char *mesg); |
| 355 | #endif /* RAY_DEBUG & RAY_DBG_COM */ |
| 356 | #if RAY_DEBUG & RAY_DBG_MBUF |
| 357 | static void ray_dump_mbuf (struct ray_softc *sc, struct mbuf *m, char *s); |
| 358 | #endif /* RAY_DEBUG & RAY_DBG_MBUF */ |
| 359 | |
| 360 | /* |
| 361 | * PC-Card (PCMCIA) driver definition |
| 362 | */ |
| 363 | static device_method_t ray_methods[] = { |
| 364 | /* Device interface */ |
| 365 | DEVMETHOD(device_probe, ray_probe), |
| 366 | DEVMETHOD(device_attach, ray_attach), |
| 367 | DEVMETHOD(device_detach, ray_detach), |
| 368 | |
| 369 | { 0, 0 } |
| 370 | }; |
| 371 | |
| 372 | static driver_t ray_driver = { |
| 373 | "ray", |
| 374 | ray_methods, |
| 375 | sizeof(struct ray_softc) |
| 376 | }; |
| 377 | |
| 378 | static devclass_t ray_devclass; |
| 379 | |
| 380 | DECLARE_DUMMY_MODULE(if_ray); |
| 381 | DRIVER_MODULE(if_ray, pccard, ray_driver, ray_devclass, 0, 0); |
| 382 | |
| 383 | /* |
| 384 | * Probe for the card by checking its startup results. |
| 385 | * |
| 386 | * Fixup any bugs/quirks for different firmware. |
| 387 | */ |
| 388 | static int |
| 389 | ray_probe(device_t dev) |
| 390 | { |
| 391 | struct ray_softc *sc = device_get_softc(dev); |
| 392 | struct ray_ecf_startup_v5 *ep = &sc->sc_ecf_startup; |
| 393 | int error; |
| 394 | |
| 395 | sc->dev = dev; |
| 396 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 397 | |
| 398 | /* |
| 399 | * Read startup results from the card. |
| 400 | */ |
| 401 | error = ray_res_alloc_cm(sc); |
| 402 | if (error) |
| 403 | return (error); |
| 404 | error = ray_res_alloc_am(sc); |
| 405 | if (error) { |
| 406 | ray_res_release(sc); |
| 407 | return (error); |
| 408 | } |
| 409 | RAY_MAP_CM(sc); |
| 410 | SRAM_READ_REGION(sc, RAY_ECF_TO_HOST_BASE, ep, |
| 411 | sizeof(sc->sc_ecf_startup)); |
| 412 | ray_res_release(sc); |
| 413 | |
| 414 | /* |
| 415 | * Check the card is okay and work out what version we are using. |
| 416 | */ |
| 417 | if (ep->e_status != RAY_ECFS_CARD_OK) { |
| 418 | RAY_PRINTF(sc, "card failed self test 0x%b", |
| 419 | ep->e_status, RAY_ECFS_PRINTFB); |
| 420 | return (ENXIO); |
| 421 | } |
| 422 | if (sc->sc_version != RAY_ECFS_BUILD_4 && |
| 423 | sc->sc_version != RAY_ECFS_BUILD_5) { |
| 424 | RAY_PRINTF(sc, "unsupported firmware version 0x%0x", |
| 425 | ep->e_fw_build_string); |
| 426 | return (ENXIO); |
| 427 | } |
| 428 | RAY_DPRINTF(sc, RAY_DBG_BOOTPARAM, "found a card"); |
| 429 | sc->sc_gone = 0; |
| 430 | |
| 431 | /* |
| 432 | * Fixup tib size to be correct - on build 4 it is garbage |
| 433 | */ |
| 434 | if (sc->sc_version == RAY_ECFS_BUILD_4 && sc->sc_tibsize == 0x55) |
| 435 | sc->sc_tibsize = sizeof(struct ray_tx_tib); |
| 436 | |
| 437 | return (0); |
| 438 | } |
| 439 | |
| 440 | /* |
| 441 | * Attach the card into the kernel |
| 442 | */ |
| 443 | static int |
| 444 | ray_attach(device_t dev) |
| 445 | { |
| 446 | struct ray_softc *sc = device_get_softc(dev); |
| 447 | struct ray_ecf_startup_v5 *ep = &sc->sc_ecf_startup; |
| 448 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 449 | size_t ccs; |
| 450 | int i, error; |
| 451 | |
| 452 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 453 | |
| 454 | if ((sc == NULL) || (sc->sc_gone)) |
| 455 | return (ENXIO); |
| 456 | |
| 457 | /* |
| 458 | * Grab the resources I need |
| 459 | */ |
| 460 | error = ray_res_alloc_cm(sc); |
| 461 | if (error) |
| 462 | return (error); |
| 463 | error = ray_res_alloc_am(sc); |
| 464 | if (error) { |
| 465 | ray_res_release(sc); |
| 466 | return (error); |
| 467 | } |
| 468 | error = ray_res_alloc_irq(sc); |
| 469 | if (error) { |
| 470 | ray_res_release(sc); |
| 471 | return (error); |
| 472 | } |
| 473 | |
| 474 | /* |
| 475 | * Reset any pending interrupts |
| 476 | */ |
| 477 | RAY_HCS_CLEAR_INTR(sc); |
| 478 | |
| 479 | /* |
| 480 | * Set the parameters that will survive stop/init and |
| 481 | * reset a few things on the card. |
| 482 | * |
| 483 | * Do not update these in ray_init_download's parameter setup |
| 484 | * |
| 485 | * XXX see the ray_init_download section for stuff to move |
| 486 | */ |
| 487 | RAY_MAP_CM(sc); |
| 488 | bzero(&sc->sc_d, sizeof(struct ray_nw_param)); |
| 489 | bzero(&sc->sc_c, sizeof(struct ray_nw_param)); |
| 490 | |
| 491 | /* Clear statistics counters */ |
| 492 | sc->sc_rxoverflow = 0; |
| 493 | sc->sc_rxcksum = 0; |
| 494 | sc->sc_rxhcksum = 0; |
| 495 | sc->sc_rxnoise = 0; |
| 496 | |
| 497 | /* Clear signal and antenna cache */ |
| 498 | bzero(sc->sc_siglevs, sizeof(sc->sc_siglevs)); |
| 499 | |
| 500 | /* Set all ccs to be free */ |
| 501 | bzero(sc->sc_ccsinuse, sizeof(sc->sc_ccsinuse)); |
| 502 | ccs = RAY_CCS_ADDRESS(0); |
| 503 | for (i = 0; i < RAY_CCS_LAST; ccs += RAY_CCS_SIZE, i++) |
| 504 | RAY_CCS_FREE(sc, ccs); |
| 505 | |
| 506 | /* |
| 507 | * Initialise the network interface structure |
| 508 | */ |
| 509 | if_initname(ifp, "ray", device_get_unit(dev)); |
| 510 | ifp->if_softc = sc; |
| 511 | ifp->if_timer = 0; |
| 512 | ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); |
| 513 | ifp->if_hdrlen = sizeof(struct ieee80211_frame) + |
| 514 | sizeof(struct ether_header); |
| 515 | ifp->if_baudrate = 1000000; /* Is this baud or bps ;-) */ |
| 516 | ifp->if_start = ray_tx; |
| 517 | ifp->if_ioctl = ray_ioctl; |
| 518 | ifp->if_watchdog = ray_watchdog; |
| 519 | ifp->if_init = ray_init; |
| 520 | ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN); |
| 521 | ifq_set_ready(&ifp->if_snd); |
| 522 | |
| 523 | /* |
| 524 | * Initialise the timers and driver |
| 525 | */ |
| 526 | callout_init(&sc->com_timer); |
| 527 | callout_init(&sc->tx_timer); |
| 528 | TAILQ_INIT(&sc->sc_comq); |
| 529 | |
| 530 | ether_ifattach(ifp, ep->e_station_addr); |
| 531 | |
| 532 | /* |
| 533 | * Print out some useful information |
| 534 | */ |
| 535 | if (bootverbose || (RAY_DEBUG & RAY_DBG_BOOTPARAM)) { |
| 536 | RAY_PRINTF(sc, "start up results"); |
| 537 | if (sc->sc_version == RAY_ECFS_BUILD_4) |
| 538 | printf(". Firmware version 4\n"); |
| 539 | else |
| 540 | printf(". Firmware version 5\n"); |
| 541 | printf(". Status 0x%b\n", ep->e_status, RAY_ECFS_PRINTFB); |
| 542 | if (sc->sc_version == RAY_ECFS_BUILD_4) { |
| 543 | printf(". Program checksum %0x\n", ep->e_resv0); |
| 544 | printf(". CIS checksum %0x\n", ep->e_rates[0]); |
| 545 | } else { |
| 546 | printf(". (reserved word) %0x\n", ep->e_resv0); |
| 547 | printf(". Supported rates %8D\n", ep->e_rates, ":"); |
| 548 | } |
| 549 | printf(". Japan call sign %12D\n", ep->e_japan_callsign, ":"); |
| 550 | if (sc->sc_version == RAY_ECFS_BUILD_5) { |
| 551 | printf(". Program checksum %0x\n", ep->e_prg_cksum); |
| 552 | printf(". CIS checksum %0x\n", ep->e_cis_cksum); |
| 553 | printf(". Firmware version %0x\n", |
| 554 | ep->e_fw_build_string); |
| 555 | printf(". Firmware revision %0x\n", ep->e_fw_build); |
| 556 | printf(". (reserved word) %0x\n", ep->e_fw_resv); |
| 557 | printf(". ASIC version %0x\n", ep->e_asic_version); |
| 558 | printf(". TIB size %0x\n", ep->e_tibsize); |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | return (0); |
| 563 | } |
| 564 | |
| 565 | /* |
| 566 | * Detach the card |
| 567 | * |
| 568 | * This is usually called when the card is ejected, but |
| 569 | * can be caused by a modunload of a controller driver. |
| 570 | * The idea is to reset the driver's view of the device |
| 571 | * and ensure that any driver entry points such as |
| 572 | * read and write do not hang. |
| 573 | */ |
| 574 | static int |
| 575 | ray_detach(device_t dev) |
| 576 | { |
| 577 | struct ray_softc *sc = device_get_softc(dev); |
| 578 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 579 | struct ray_comq_entry *com; |
| 580 | int s; |
| 581 | |
| 582 | s = splimp(); |
| 583 | |
| 584 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STOP, ""); |
| 585 | |
| 586 | if ((sc == NULL) || (sc->sc_gone)) |
| 587 | return (0); |
| 588 | |
| 589 | /* |
| 590 | * Mark as not running and detach the interface. |
| 591 | * |
| 592 | * N.B. if_detach can trigger ioctls so we do it first and |
| 593 | * then clean the runq. |
| 594 | */ |
| 595 | sc->sc_gone = 1; |
| 596 | sc->sc_c.np_havenet = 0; |
| 597 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
| 598 | ether_ifdetach(ifp); |
| 599 | |
| 600 | /* |
| 601 | * Stop the runq and wake up anyone sleeping for us. |
| 602 | */ |
| 603 | callout_stop(&sc->com_timer); |
| 604 | callout_stop(&sc->tx_timer); |
| 605 | com = TAILQ_FIRST(&sc->sc_comq); |
| 606 | for (com = TAILQ_FIRST(&sc->sc_comq); com != NULL; |
| 607 | com = TAILQ_NEXT(com, c_chain)) { |
| 608 | com->c_flags |= RAY_COM_FDETACHED; |
| 609 | com->c_retval = 0; |
| 610 | RAY_DPRINTF(sc, RAY_DBG_STOP, "looking at com %p %b", |
| 611 | com, com->c_flags, RAY_COM_FLAGS_PRINTFB); |
| 612 | if (com->c_flags & RAY_COM_FWOK) { |
| 613 | RAY_DPRINTF(sc, RAY_DBG_STOP, "waking com %p", com); |
| 614 | wakeup(com->c_wakeup); |
| 615 | } |
| 616 | } |
| 617 | |
| 618 | /* |
| 619 | * Release resources |
| 620 | */ |
| 621 | ray_res_release(sc); |
| 622 | RAY_DPRINTF(sc, RAY_DBG_STOP, "unloading complete"); |
| 623 | |
| 624 | splx(s); |
| 625 | |
| 626 | return (0); |
| 627 | } |
| 628 | |
| 629 | /* |
| 630 | * Network ioctl request. |
| 631 | */ |
| 632 | static int |
| 633 | ray_ioctl(register struct ifnet *ifp, u_long command, caddr_t data, |
| 634 | struct ucred *cr) |
| 635 | { |
| 636 | struct ray_softc *sc = ifp->if_softc; |
| 637 | struct ray_param_req pr; |
| 638 | struct ray_stats_req sr; |
| 639 | struct ifreq *ifr = (struct ifreq *)data; |
| 640 | int s, error, error2; |
| 641 | |
| 642 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_IOCTL, ""); |
| 643 | |
| 644 | if ((sc == NULL) || (sc->sc_gone)) |
| 645 | return (ENXIO); |
| 646 | |
| 647 | error = error2 = 0; |
| 648 | s = splimp(); |
| 649 | |
| 650 | switch (command) { |
| 651 | |
| 652 | case SIOCGIFADDR: |
| 653 | case SIOCSIFMTU: |
| 654 | case SIOCSIFADDR: |
| 655 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "GIFADDR/SIFMTU"); |
| 656 | error = ether_ioctl(ifp, command, data); |
| 657 | /* XXX SIFADDR used to fall through to SIOCSIFFLAGS */ |
| 658 | break; |
| 659 | |
| 660 | case SIOCSIFFLAGS: |
| 661 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "SIFFLAGS 0x%0x", ifp->if_flags); |
| 662 | /* |
| 663 | * If the interface is marked up we call ray_init_user. |
| 664 | * This will deal with mcast and promisc flags as well as |
| 665 | * initialising the hardware if it needs it. |
| 666 | */ |
| 667 | if (ifp->if_flags & IFF_UP) |
| 668 | error = ray_init_user(sc); |
| 669 | else |
| 670 | error = ray_stop_user(sc); |
| 671 | break; |
| 672 | |
| 673 | case SIOCADDMULTI: |
| 674 | case SIOCDELMULTI: |
| 675 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "ADDMULTI/DELMULTI"); |
| 676 | error = ray_mcast_user(sc); |
| 677 | break; |
| 678 | |
| 679 | case SIOCSRAYPARAM: |
| 680 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "SRAYPARAM"); |
| 681 | if ((error = copyin(ifr->ifr_data, &pr, sizeof(pr)))) |
| 682 | break; |
| 683 | error = ray_upparams_user(sc, &pr); |
| 684 | error2 = copyout(&pr, ifr->ifr_data, sizeof(pr)); |
| 685 | error = error2 ? error2 : error; |
| 686 | break; |
| 687 | |
| 688 | case SIOCGRAYPARAM: |
| 689 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "GRAYPARAM"); |
| 690 | if ((error = copyin(ifr->ifr_data, &pr, sizeof(pr)))) |
| 691 | break; |
| 692 | error = ray_repparams_user(sc, &pr); |
| 693 | error2 = copyout(&pr, ifr->ifr_data, sizeof(pr)); |
| 694 | error = error2 ? error2 : error; |
| 695 | break; |
| 696 | |
| 697 | case SIOCGRAYSTATS: |
| 698 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "GRAYSTATS"); |
| 699 | error = ray_repstats_user(sc, &sr); |
| 700 | error2 = copyout(&sr, ifr->ifr_data, sizeof(sr)); |
| 701 | error = error2 ? error2 : error; |
| 702 | break; |
| 703 | |
| 704 | case SIOCGRAYSIGLEV: |
| 705 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "GRAYSIGLEV"); |
| 706 | error = copyout(sc->sc_siglevs, ifr->ifr_data, |
| 707 | sizeof(sc->sc_siglevs)); |
| 708 | break; |
| 709 | |
| 710 | case SIOCGIFFLAGS: |
| 711 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "GIFFLAGS"); |
| 712 | error = EINVAL; |
| 713 | break; |
| 714 | |
| 715 | case SIOCGIFMETRIC: |
| 716 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "GIFMETRIC"); |
| 717 | error = EINVAL; |
| 718 | break; |
| 719 | |
| 720 | case SIOCGIFMTU: |
| 721 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "GIFMTU"); |
| 722 | error = EINVAL; |
| 723 | break; |
| 724 | |
| 725 | case SIOCGIFPHYS: |
| 726 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "GIFPYHS"); |
| 727 | error = EINVAL; |
| 728 | break; |
| 729 | |
| 730 | case SIOCSIFMEDIA: |
| 731 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "SIFMEDIA"); |
| 732 | error = EINVAL; |
| 733 | break; |
| 734 | |
| 735 | case SIOCGIFMEDIA: |
| 736 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "GIFMEDIA"); |
| 737 | error = EINVAL; |
| 738 | break; |
| 739 | |
| 740 | default: |
| 741 | error = EINVAL; |
| 742 | |
| 743 | } |
| 744 | |
| 745 | splx(s); |
| 746 | |
| 747 | return (error); |
| 748 | } |
| 749 | |
| 750 | /* |
| 751 | * Ethernet layer entry to ray_init - discard errors |
| 752 | */ |
| 753 | static void |
| 754 | ray_init(void *xsc) |
| 755 | { |
| 756 | struct ray_softc *sc = (struct ray_softc *)xsc; |
| 757 | |
| 758 | ray_init_user(sc); |
| 759 | } |
| 760 | |
| 761 | /* |
| 762 | * User land entry to network initialisation and changes in interface flags. |
| 763 | * |
| 764 | * We do a very little work here, just creating runq entries to |
| 765 | * processes the actions needed to cope with interface flags. We do it |
| 766 | * this way in case there are runq entries outstanding from earlier |
| 767 | * ioctls that modify the interface flags. |
| 768 | * |
| 769 | * Returns values are either 0 for success, a varity of resource allocation |
| 770 | * failures or errors in the command sent to the card. |
| 771 | * |
| 772 | * Note, IFF_RUNNING is eventually set by init_sj_done or init_assoc_done |
| 773 | */ |
| 774 | static int |
| 775 | ray_init_user(struct ray_softc *sc) |
| 776 | { |
| 777 | struct ray_comq_entry *com[6]; |
| 778 | int error, ncom; |
| 779 | |
| 780 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 781 | |
| 782 | /* |
| 783 | * Create the following runq entries to bring the card up. |
| 784 | * |
| 785 | * init_download - download the network to the card |
| 786 | * init_mcast - reset multicast list |
| 787 | * init_sj - find or start a BSS |
| 788 | * init_auth - authenticate with a ESSID if needed |
| 789 | * init_assoc - associate with a ESSID if needed |
| 790 | * |
| 791 | * They are only actually executed if the card is not running. |
| 792 | * We may enter this routine from a simple change of IP |
| 793 | * address and do not need to get the card to do these things. |
| 794 | * However, we cannot perform the check here as there may be |
| 795 | * commands in the runq that change the IFF_RUNNING state of |
| 796 | * the interface. |
| 797 | */ |
| 798 | ncom = 0; |
| 799 | com[ncom++] = RAY_COM_MALLOC(ray_init_download, RAY_COM_FCHKRUNNING); |
| 800 | com[ncom++] = RAY_COM_MALLOC(ray_init_mcast, RAY_COM_FCHKRUNNING); |
| 801 | com[ncom++] = RAY_COM_MALLOC(ray_init_sj, RAY_COM_FCHKRUNNING); |
| 802 | com[ncom++] = RAY_COM_MALLOC(ray_init_auth, RAY_COM_FCHKRUNNING); |
| 803 | com[ncom++] = RAY_COM_MALLOC(ray_init_assoc, RAY_COM_FCHKRUNNING); |
| 804 | |
| 805 | /* |
| 806 | * Create runq entries to process flags |
| 807 | * |
| 808 | * promisc - set/reset PROMISC and ALLMULTI flags |
| 809 | * |
| 810 | * They are only actually executed if the card is running |
| 811 | */ |
| 812 | com[ncom++] = RAY_COM_MALLOC(ray_promisc, 0); |
| 813 | |
| 814 | RAY_COM_RUNQ(sc, com, ncom, "rayinit", error); |
| 815 | |
| 816 | /* XXX no real error processing from anything yet! */ |
| 817 | |
| 818 | RAY_COM_FREE(com, ncom); |
| 819 | |
| 820 | return (error); |
| 821 | } |
| 822 | |
| 823 | /* |
| 824 | * Runq entry for resetting driver and downloading start up structures to card |
| 825 | */ |
| 826 | static void |
| 827 | ray_init_download(struct ray_softc *sc, struct ray_comq_entry *com) |
| 828 | { |
| 829 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 830 | |
| 831 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 832 | |
| 833 | /* If the card already running we might not need to download */ |
| 834 | RAY_COM_CHKRUNNING(sc, com, ifp); |
| 835 | |
| 836 | /* |
| 837 | * Reset instance variables |
| 838 | * |
| 839 | * The first set are network parameters that are read back when |
| 840 | * the card starts or joins the network. |
| 841 | * |
| 842 | * The second set are network parameters that are downloaded to |
| 843 | * the card. |
| 844 | * |
| 845 | * The third set are driver parameters. |
| 846 | * |
| 847 | * All of the variables in these sets can be updated by the |
| 848 | * card or ioctls. |
| 849 | * |
| 850 | * XXX see the ray_attach section for stuff to move |
| 851 | */ |
| 852 | sc->sc_d.np_upd_param = 0; |
| 853 | bzero(sc->sc_d.np_bss_id, ETHER_ADDR_LEN); |
| 854 | sc->sc_d.np_inited = 0; |
| 855 | sc->sc_d.np_def_txrate = RAY_MIB_BASIC_RATE_SET_DEFAULT; |
| 856 | sc->sc_d.np_encrypt = 0; |
| 857 | |
| 858 | bzero(sc->sc_d.np_ssid, IEEE80211_NWID_LEN); |
| 859 | if (sc->sc_version == RAY_ECFS_BUILD_4) { |
| 860 | sc->sc_d.np_net_type = RAY_MIB_NET_TYPE_V4; |
| 861 | strncpy(sc->sc_d.np_ssid, RAY_MIB_SSID_V4, IEEE80211_NWID_LEN); |
| 862 | sc->sc_d.np_ap_status = RAY_MIB_AP_STATUS_V4; |
| 863 | sc->sc_d.np_framing = RAY_FRAMING_ENCAPSULATION; |
| 864 | } else { |
| 865 | sc->sc_d.np_net_type = RAY_MIB_NET_TYPE_V5; |
| 866 | strncpy(sc->sc_d.np_ssid, RAY_MIB_SSID_V5, IEEE80211_NWID_LEN); |
| 867 | sc->sc_d.np_ap_status = RAY_MIB_AP_STATUS_V5; |
| 868 | sc->sc_d.np_framing = RAY_FRAMING_TRANSLATION; |
| 869 | } |
| 870 | sc->sc_d.np_priv_start = RAY_MIB_PRIVACY_MUST_START_DEFAULT; |
| 871 | sc->sc_d.np_priv_join = RAY_MIB_PRIVACY_CAN_JOIN_DEFAULT; |
| 872 | sc->sc_d.np_promisc = !!(ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)); |
| 873 | |
| 874 | /* XXX this is a hack whilst I transition the code. The instance |
| 875 | * XXX variables above should be set somewhere else. This is needed for |
| 876 | * XXX start_join */ |
| 877 | bcopy(&sc->sc_d, &com->c_desired, sizeof(struct ray_nw_param)); |
| 878 | |
| 879 | /* |
| 880 | * Download the right firmware defaults |
| 881 | */ |
| 882 | if (sc->sc_version == RAY_ECFS_BUILD_4) |
| 883 | ray_init_download_v4(sc, com); |
| 884 | else |
| 885 | ray_init_download_v5(sc, com); |
| 886 | |
| 887 | /* |
| 888 | * Kick the card |
| 889 | */ |
| 890 | ray_ccs_fill(sc, com->c_ccs, RAY_CMD_DOWNLOAD_PARAMS); |
| 891 | ray_com_ecf(sc, com); |
| 892 | } |
| 893 | |
| 894 | #define PUT2(p, v) \ |
| 895 | do { (p)[0] = ((v >> 8) & 0xff); (p)[1] = (v & 0xff); } while(0) |
| 896 | /* |
| 897 | * Firmware version 4 defaults - see if_raymib.h for details |
| 898 | */ |
| 899 | static void |
| 900 | ray_init_download_v4(struct ray_softc *sc, struct ray_comq_entry *com) |
| 901 | { |
| 902 | struct ray_mib_4 ray_mib_4_default; |
| 903 | |
| 904 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 905 | RAY_MAP_CM(sc); |
| 906 | |
| 907 | #define MIB4(m) ray_mib_4_default.m |
| 908 | |
| 909 | MIB4(mib_net_type) = com->c_desired.np_net_type; |
| 910 | MIB4(mib_ap_status) = com->c_desired.np_ap_status; |
| 911 | bcopy(com->c_desired.np_ssid, MIB4(mib_ssid), IEEE80211_NWID_LEN); |
| 912 | MIB4(mib_scan_mode) = RAY_MIB_SCAN_MODE_V4; |
| 913 | MIB4(mib_apm_mode) = RAY_MIB_APM_MODE_V4; |
| 914 | bcopy(sc->sc_station_addr, MIB4(mib_mac_addr), ETHER_ADDR_LEN); |
| 915 | PUT2(MIB4(mib_frag_thresh), RAY_MIB_FRAG_THRESH_V4); |
| 916 | PUT2(MIB4(mib_dwell_time), RAY_MIB_DWELL_TIME_V4); |
| 917 | PUT2(MIB4(mib_beacon_period), RAY_MIB_BEACON_PERIOD_V4); |
| 918 | MIB4(mib_dtim_interval) = RAY_MIB_DTIM_INTERVAL_V4; |
| 919 | MIB4(mib_max_retry) = RAY_MIB_MAX_RETRY_V4; |
| 920 | MIB4(mib_ack_timo) = RAY_MIB_ACK_TIMO_V4; |
| 921 | MIB4(mib_sifs) = RAY_MIB_SIFS_V4; |
| 922 | MIB4(mib_difs) = RAY_MIB_DIFS_V4; |
| 923 | MIB4(mib_pifs) = RAY_MIB_PIFS_V4; |
| 924 | PUT2(MIB4(mib_rts_thresh), RAY_MIB_RTS_THRESH_V4); |
| 925 | PUT2(MIB4(mib_scan_dwell), RAY_MIB_SCAN_DWELL_V4); |
| 926 | PUT2(MIB4(mib_scan_max_dwell), RAY_MIB_SCAN_MAX_DWELL_V4); |
| 927 | MIB4(mib_assoc_timo) = RAY_MIB_ASSOC_TIMO_V4; |
| 928 | MIB4(mib_adhoc_scan_cycle) = RAY_MIB_ADHOC_SCAN_CYCLE_V4; |
| 929 | MIB4(mib_infra_scan_cycle) = RAY_MIB_INFRA_SCAN_CYCLE_V4; |
| 930 | MIB4(mib_infra_super_scan_cycle) |
| 931 | = RAY_MIB_INFRA_SUPER_SCAN_CYCLE_V4; |
| 932 | MIB4(mib_promisc) = com->c_desired.np_promisc; |
| 933 | PUT2(MIB4(mib_uniq_word), RAY_MIB_UNIQ_WORD_V4); |
| 934 | MIB4(mib_slot_time) = RAY_MIB_SLOT_TIME_V4; |
| 935 | MIB4(mib_roam_low_snr_thresh) = RAY_MIB_ROAM_LOW_SNR_THRESH_V4; |
| 936 | MIB4(mib_low_snr_count) = RAY_MIB_LOW_SNR_COUNT_V4; |
| 937 | MIB4(mib_infra_missed_beacon_count) |
| 938 | = RAY_MIB_INFRA_MISSED_BEACON_COUNT_V4; |
| 939 | MIB4(mib_adhoc_missed_beacon_count) |
| 940 | = RAY_MIB_ADHOC_MISSED_BEACON_COUNT_V4; |
| 941 | MIB4(mib_country_code) = RAY_MIB_COUNTRY_CODE_V4; |
| 942 | MIB4(mib_hop_seq) = RAY_MIB_HOP_SEQ_V4; |
| 943 | MIB4(mib_hop_seq_len) = RAY_MIB_HOP_SEQ_LEN_V4; |
| 944 | MIB4(mib_cw_max) = RAY_MIB_CW_MAX_V4; |
| 945 | MIB4(mib_cw_min) = RAY_MIB_CW_MIN_V4; |
| 946 | MIB4(mib_noise_filter_gain) = RAY_MIB_NOISE_FILTER_GAIN_DEFAULT; |
| 947 | MIB4(mib_noise_limit_offset) = RAY_MIB_NOISE_LIMIT_OFFSET_DEFAULT; |
| 948 | MIB4(mib_rssi_thresh_offset) = RAY_MIB_RSSI_THRESH_OFFSET_DEFAULT; |
| 949 | MIB4(mib_busy_thresh_offset) = RAY_MIB_BUSY_THRESH_OFFSET_DEFAULT; |
| 950 | MIB4(mib_sync_thresh) = RAY_MIB_SYNC_THRESH_DEFAULT; |
| 951 | MIB4(mib_test_mode) = RAY_MIB_TEST_MODE_DEFAULT; |
| 952 | MIB4(mib_test_min_chan) = RAY_MIB_TEST_MIN_CHAN_DEFAULT; |
| 953 | MIB4(mib_test_max_chan) = RAY_MIB_TEST_MAX_CHAN_DEFAULT; |
| 954 | #undef MIB4 |
| 955 | |
| 956 | SRAM_WRITE_REGION(sc, RAY_HOST_TO_ECF_BASE, |
| 957 | &ray_mib_4_default, sizeof(ray_mib_4_default)); |
| 958 | } |
| 959 | |
| 960 | /* |
| 961 | * Firmware version 5 defaults - see if_raymib.h for details |
| 962 | */ |
| 963 | static void |
| 964 | ray_init_download_v5(struct ray_softc *sc, struct ray_comq_entry *com) |
| 965 | { |
| 966 | struct ray_mib_5 ray_mib_5_default; |
| 967 | |
| 968 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 969 | RAY_MAP_CM(sc); |
| 970 | |
| 971 | #define MIB5(m) ray_mib_5_default.m |
| 972 | MIB5(mib_net_type) = com->c_desired.np_net_type; |
| 973 | MIB5(mib_ap_status) = com->c_desired.np_ap_status; |
| 974 | bcopy(com->c_desired.np_ssid, MIB5(mib_ssid), IEEE80211_NWID_LEN); |
| 975 | MIB5(mib_scan_mode) = RAY_MIB_SCAN_MODE_V5; |
| 976 | MIB5(mib_apm_mode) = RAY_MIB_APM_MODE_V5; |
| 977 | bcopy(sc->sc_station_addr, MIB5(mib_mac_addr), ETHER_ADDR_LEN); |
| 978 | PUT2(MIB5(mib_frag_thresh), RAY_MIB_FRAG_THRESH_V5); |
| 979 | PUT2(MIB5(mib_dwell_time), RAY_MIB_DWELL_TIME_V5); |
| 980 | PUT2(MIB5(mib_beacon_period), RAY_MIB_BEACON_PERIOD_V5); |
| 981 | MIB5(mib_dtim_interval) = RAY_MIB_DTIM_INTERVAL_V5; |
| 982 | MIB5(mib_max_retry) = RAY_MIB_MAX_RETRY_V5; |
| 983 | MIB5(mib_ack_timo) = RAY_MIB_ACK_TIMO_V5; |
| 984 | MIB5(mib_sifs) = RAY_MIB_SIFS_V5; |
| 985 | MIB5(mib_difs) = RAY_MIB_DIFS_V5; |
| 986 | MIB5(mib_pifs) = RAY_MIB_PIFS_V5; |
| 987 | PUT2(MIB5(mib_rts_thresh), RAY_MIB_RTS_THRESH_V5); |
| 988 | PUT2(MIB5(mib_scan_dwell), RAY_MIB_SCAN_DWELL_V5); |
| 989 | PUT2(MIB5(mib_scan_max_dwell), RAY_MIB_SCAN_MAX_DWELL_V5); |
| 990 | MIB5(mib_assoc_timo) = RAY_MIB_ASSOC_TIMO_V5; |
| 991 | MIB5(mib_adhoc_scan_cycle) = RAY_MIB_ADHOC_SCAN_CYCLE_V5; |
| 992 | MIB5(mib_infra_scan_cycle) = RAY_MIB_INFRA_SCAN_CYCLE_V5; |
| 993 | MIB5(mib_infra_super_scan_cycle) |
| 994 | = RAY_MIB_INFRA_SUPER_SCAN_CYCLE_V5; |
| 995 | MIB5(mib_promisc) = com->c_desired.np_promisc; |
| 996 | PUT2(MIB5(mib_uniq_word), RAY_MIB_UNIQ_WORD_V5); |
| 997 | MIB5(mib_slot_time) = RAY_MIB_SLOT_TIME_V5; |
| 998 | MIB5(mib_roam_low_snr_thresh) = RAY_MIB_ROAM_LOW_SNR_THRESH_V5; |
| 999 | MIB5(mib_low_snr_count) = RAY_MIB_LOW_SNR_COUNT_V5; |
| 1000 | MIB5(mib_infra_missed_beacon_count) |
| 1001 | = RAY_MIB_INFRA_MISSED_BEACON_COUNT_V5; |
| 1002 | MIB5(mib_adhoc_missed_beacon_count) |
| 1003 | = RAY_MIB_ADHOC_MISSED_BEACON_COUNT_V5; |
| 1004 | MIB5(mib_country_code) = RAY_MIB_COUNTRY_CODE_V5; |
| 1005 | MIB5(mib_hop_seq) = RAY_MIB_HOP_SEQ_V5; |
| 1006 | MIB5(mib_hop_seq_len) = RAY_MIB_HOP_SEQ_LEN_V5; |
| 1007 | PUT2(MIB5(mib_cw_max), RAY_MIB_CW_MAX_V5); |
| 1008 | PUT2(MIB5(mib_cw_min), RAY_MIB_CW_MIN_V5); |
| 1009 | MIB5(mib_noise_filter_gain) = RAY_MIB_NOISE_FILTER_GAIN_DEFAULT; |
| 1010 | MIB5(mib_noise_limit_offset) = RAY_MIB_NOISE_LIMIT_OFFSET_DEFAULT; |
| 1011 | MIB5(mib_rssi_thresh_offset) = RAY_MIB_RSSI_THRESH_OFFSET_DEFAULT; |
| 1012 | MIB5(mib_busy_thresh_offset) = RAY_MIB_BUSY_THRESH_OFFSET_DEFAULT; |
| 1013 | MIB5(mib_sync_thresh) = RAY_MIB_SYNC_THRESH_DEFAULT; |
| 1014 | MIB5(mib_test_mode) = RAY_MIB_TEST_MODE_DEFAULT; |
| 1015 | MIB5(mib_test_min_chan) = RAY_MIB_TEST_MIN_CHAN_DEFAULT; |
| 1016 | MIB5(mib_test_max_chan) = RAY_MIB_TEST_MAX_CHAN_DEFAULT; |
| 1017 | MIB5(mib_allow_probe_resp) = RAY_MIB_ALLOW_PROBE_RESP_DEFAULT; |
| 1018 | MIB5(mib_privacy_must_start) = com->c_desired.np_priv_start; |
| 1019 | MIB5(mib_privacy_can_join) = com->c_desired.np_priv_join; |
| 1020 | MIB5(mib_basic_rate_set[0]) = com->c_desired.np_def_txrate; |
| 1021 | #undef MIB5 |
| 1022 | |
| 1023 | SRAM_WRITE_REGION(sc, RAY_HOST_TO_ECF_BASE, |
| 1024 | &ray_mib_5_default, sizeof(ray_mib_5_default)); |
| 1025 | } |
| 1026 | #undef PUT2 |
| 1027 | |
| 1028 | /* |
| 1029 | * Download completion routine |
| 1030 | */ |
| 1031 | static void |
| 1032 | ray_init_download_done(struct ray_softc *sc, u_int8_t status, size_t ccs) |
| 1033 | { |
| 1034 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 1035 | RAY_COM_CHECK(sc, ccs); |
| 1036 | |
| 1037 | RAY_CCSERR(sc, status, if_oerrors); /* XXX error counter */ |
| 1038 | |
| 1039 | ray_com_ecf_done(sc); |
| 1040 | } |
| 1041 | |
| 1042 | /* |
| 1043 | * Runq entry to empty the multicast filter list |
| 1044 | */ |
| 1045 | static void |
| 1046 | ray_init_mcast(struct ray_softc *sc, struct ray_comq_entry *com) |
| 1047 | { |
| 1048 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1049 | |
| 1050 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 1051 | RAY_MAP_CM(sc); |
| 1052 | |
| 1053 | /* If the card already running we might not need to reset the list */ |
| 1054 | RAY_COM_CHKRUNNING(sc, com, ifp); |
| 1055 | |
| 1056 | /* |
| 1057 | * Kick the card |
| 1058 | */ |
| 1059 | ray_ccs_fill(sc, com->c_ccs, RAY_CMD_UPDATE_MCAST); |
| 1060 | SRAM_WRITE_FIELD_1(sc, com->c_ccs, ray_cmd_update_mcast, c_nmcast, 0); |
| 1061 | |
| 1062 | ray_com_ecf(sc, com); |
| 1063 | } |
| 1064 | |
| 1065 | /* |
| 1066 | * Runq entry to starting or joining a network |
| 1067 | */ |
| 1068 | static void |
| 1069 | ray_init_sj(struct ray_softc *sc, struct ray_comq_entry *com) |
| 1070 | { |
| 1071 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1072 | struct ray_net_params np; |
| 1073 | int update; |
| 1074 | |
| 1075 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 1076 | RAY_MAP_CM(sc); |
| 1077 | |
| 1078 | /* If the card already running we might not need to start the n/w */ |
| 1079 | RAY_COM_CHKRUNNING(sc, com, ifp); |
| 1080 | |
| 1081 | /* |
| 1082 | * Set up the right start or join command and determine |
| 1083 | * whether we should tell the card about a change in operating |
| 1084 | * parameters. |
| 1085 | */ |
| 1086 | sc->sc_c.np_havenet = 0; |
| 1087 | if (sc->sc_d.np_net_type == RAY_MIB_NET_TYPE_ADHOC) |
| 1088 | ray_ccs_fill(sc, com->c_ccs, RAY_CMD_START_NET); |
| 1089 | else |
| 1090 | ray_ccs_fill(sc, com->c_ccs, RAY_CMD_JOIN_NET); |
| 1091 | |
| 1092 | update = 0; |
| 1093 | if (sc->sc_c.np_net_type != sc->sc_d.np_net_type) |
| 1094 | update++; |
| 1095 | if (bcmp(sc->sc_c.np_ssid, sc->sc_d.np_ssid, IEEE80211_NWID_LEN)) |
| 1096 | update++; |
| 1097 | if (sc->sc_c.np_priv_join != sc->sc_d.np_priv_join) |
| 1098 | update++; |
| 1099 | if (sc->sc_c.np_priv_start != sc->sc_d.np_priv_start) |
| 1100 | update++; |
| 1101 | RAY_DPRINTF(sc, RAY_DBG_STARTJOIN, |
| 1102 | "%s updating nw params", update?"is":"not"); |
| 1103 | if (update) { |
| 1104 | bzero(&np, sizeof(np)); |
| 1105 | np.p_net_type = sc->sc_d.np_net_type; |
| 1106 | bcopy(sc->sc_d.np_ssid, np.p_ssid, IEEE80211_NWID_LEN); |
| 1107 | np.p_privacy_must_start = sc->sc_d.np_priv_start; |
| 1108 | np.p_privacy_can_join = sc->sc_d.np_priv_join; |
| 1109 | SRAM_WRITE_REGION(sc, RAY_HOST_TO_ECF_BASE, &np, sizeof(np)); |
| 1110 | SRAM_WRITE_FIELD_1(sc, com->c_ccs, ray_cmd_net, c_upd_param, 1); |
| 1111 | } else |
| 1112 | SRAM_WRITE_FIELD_1(sc, com->c_ccs, ray_cmd_net, c_upd_param, 0); |
| 1113 | |
| 1114 | /* |
| 1115 | * Kick the card |
| 1116 | */ |
| 1117 | ray_com_ecf(sc, com); |
| 1118 | } |
| 1119 | |
| 1120 | /* |
| 1121 | * Complete start command or intermediate step in assoc command |
| 1122 | */ |
| 1123 | static void |
| 1124 | ray_init_sj_done(struct ray_softc *sc, u_int8_t status, size_t ccs) |
| 1125 | { |
| 1126 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1127 | |
| 1128 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 1129 | RAY_MAP_CM(sc); |
| 1130 | RAY_COM_CHECK(sc, ccs); |
| 1131 | |
| 1132 | RAY_CCSERR(sc, status, if_oerrors); /* XXX error counter */ |
| 1133 | |
| 1134 | /* |
| 1135 | * Read back network parameters that the ECF sets |
| 1136 | */ |
| 1137 | SRAM_READ_REGION(sc, ccs, &sc->sc_c.p_1, sizeof(struct ray_cmd_net)); |
| 1138 | |
| 1139 | /* Adjust values for buggy firmware */ |
| 1140 | if (sc->sc_c.np_inited == 0x55) |
| 1141 | sc->sc_c.np_inited = 0; |
| 1142 | if (sc->sc_c.np_def_txrate == 0x55) |
| 1143 | sc->sc_c.np_def_txrate = sc->sc_d.np_def_txrate; |
| 1144 | if (sc->sc_c.np_encrypt == 0x55) |
| 1145 | sc->sc_c.np_encrypt = sc->sc_d.np_encrypt; |
| 1146 | |
| 1147 | /* |
| 1148 | * Update our local state if we updated the network parameters |
| 1149 | * when the START_NET or JOIN_NET was issued. |
| 1150 | */ |
| 1151 | if (sc->sc_c.np_upd_param) { |
| 1152 | RAY_DPRINTF(sc, RAY_DBG_STARTJOIN, "updated parameters"); |
| 1153 | SRAM_READ_REGION(sc, RAY_HOST_TO_ECF_BASE, |
| 1154 | &sc->sc_c.p_2, sizeof(struct ray_net_params)); |
| 1155 | } |
| 1156 | |
| 1157 | /* |
| 1158 | * Hurrah! The network is now active. |
| 1159 | * |
| 1160 | * Clearing IFF_OACTIVE will ensure that the system will send us |
| 1161 | * packets. Just before we return from the interrupt context |
| 1162 | * we check to see if packets have been queued. |
| 1163 | */ |
| 1164 | if (SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_cmd) == RAY_CMD_START_NET) { |
| 1165 | sc->sc_c.np_havenet = 1; |
| 1166 | sc->sc_c.np_framing = sc->sc_d.np_framing; |
| 1167 | ifp->if_flags |= IFF_RUNNING; |
| 1168 | ifp->if_flags &= ~IFF_OACTIVE; |
| 1169 | } |
| 1170 | |
| 1171 | ray_com_ecf_done(sc); |
| 1172 | } |
| 1173 | |
| 1174 | /* |
| 1175 | * Runq entry to authenticate with an access point or another station |
| 1176 | */ |
| 1177 | static void |
| 1178 | ray_init_auth(struct ray_softc *sc, struct ray_comq_entry *com) |
| 1179 | { |
| 1180 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1181 | |
| 1182 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN | RAY_DBG_AUTH, ""); |
| 1183 | |
| 1184 | /* If card already running we might not need to authenticate */ |
| 1185 | RAY_COM_CHKRUNNING(sc, com, ifp); |
| 1186 | |
| 1187 | /* |
| 1188 | * XXX Don't do anything if we are not in a managed network |
| 1189 | * |
| 1190 | * XXX V4 adhoc does not need this, V5 adhoc unknown |
| 1191 | */ |
| 1192 | if (sc->sc_c.np_net_type != RAY_MIB_NET_TYPE_INFRA) { |
| 1193 | ray_com_runq_done(sc); |
| 1194 | return; |
| 1195 | } |
| 1196 | |
| 1197 | /* |
| 1198 | * XXX_AUTH need to think of run queue when doing auths from request i.e. would |
| 1199 | * XXX_AUTH need to have auth at top of runq? |
| 1200 | * XXX_AUTH ditto for sending any auth response packets...what about timeouts? |
| 1201 | */ |
| 1202 | |
| 1203 | /* |
| 1204 | * Kick the card |
| 1205 | */ |
| 1206 | /* XXX_AUTH check exit status and retry or fail as we can't associate without this */ |
| 1207 | ray_init_auth_send(sc, sc->sc_c.np_bss_id, IEEE80211_AUTH_OPEN_REQUEST); |
| 1208 | } |
| 1209 | |
| 1210 | /* |
| 1211 | * Build and send an authentication packet |
| 1212 | * |
| 1213 | * If an error occurs, returns 1 else returns 0. |
| 1214 | */ |
| 1215 | static int |
| 1216 | ray_init_auth_send(struct ray_softc *sc, u_int8_t *dst, int sequence) |
| 1217 | { |
| 1218 | size_t ccs, bufp; |
| 1219 | int pktlen = 0; |
| 1220 | |
| 1221 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN | RAY_DBG_AUTH, ""); |
| 1222 | |
| 1223 | /* Get a control block */ |
| 1224 | if (ray_ccs_tx(sc, &ccs, &bufp)) { |
| 1225 | RAY_RECERR(sc, "could not obtain a ccs"); |
| 1226 | return (1); |
| 1227 | } |
| 1228 | |
| 1229 | /* Fill the header in */ |
| 1230 | bufp = ray_tx_wrhdr(sc, bufp, |
| 1231 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH, |
| 1232 | IEEE80211_FC1_DIR_NODS, |
| 1233 | dst, |
| 1234 | sc->arpcom.ac_enaddr, |
| 1235 | sc->sc_c.np_bss_id); |
| 1236 | |
| 1237 | /* Add algorithm number */ |
| 1238 | SRAM_WRITE_1(sc, bufp + pktlen++, IEEE80211_AUTH_ALG_OPEN); |
| 1239 | SRAM_WRITE_1(sc, bufp + pktlen++, 0); |
| 1240 | |
| 1241 | /* Add sequence number */ |
| 1242 | SRAM_WRITE_1(sc, bufp + pktlen++, sequence); |
| 1243 | SRAM_WRITE_1(sc, bufp + pktlen++, 0); |
| 1244 | |
| 1245 | /* Add status code */ |
| 1246 | SRAM_WRITE_1(sc, bufp + pktlen++, 0); |
| 1247 | SRAM_WRITE_1(sc, bufp + pktlen++, 0); |
| 1248 | pktlen += sizeof(struct ieee80211_frame); |
| 1249 | |
| 1250 | return (ray_tx_send(sc, ccs, pktlen, dst)); |
| 1251 | } |
| 1252 | |
| 1253 | /* |
| 1254 | * Complete authentication runq |
| 1255 | */ |
| 1256 | static void |
| 1257 | ray_init_auth_done(struct ray_softc *sc, u_int8_t status) |
| 1258 | { |
| 1259 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN | RAY_DBG_AUTH, ""); |
| 1260 | |
| 1261 | if (status != IEEE80211_STATUS_SUCCESS) |
| 1262 | RAY_RECERR(sc, "authentication failed with status %d", status); |
| 1263 | /* |
| 1264 | * XXX_AUTH retry? if not just recall ray_init_auth_send and dont clear runq? |
| 1265 | * XXX_AUTH association requires that authenitcation is successful |
| 1266 | * XXX_AUTH before we associate, and the runq is the only way to halt the |
| 1267 | * XXX_AUTH progress of associate. |
| 1268 | * XXX_AUTH In this case I might not need the RAY_AUTH_NEEDED state |
| 1269 | */ |
| 1270 | ray_com_runq_done(sc); |
| 1271 | } |
| 1272 | |
| 1273 | /* |
| 1274 | * Runq entry to starting an association with an access point |
| 1275 | */ |
| 1276 | static void |
| 1277 | ray_init_assoc(struct ray_softc *sc, struct ray_comq_entry *com) |
| 1278 | { |
| 1279 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1280 | |
| 1281 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 1282 | |
| 1283 | /* If the card already running we might not need to associate */ |
| 1284 | RAY_COM_CHKRUNNING(sc, com, ifp); |
| 1285 | |
| 1286 | /* |
| 1287 | * Don't do anything if we are not in a managed network |
| 1288 | */ |
| 1289 | if (sc->sc_c.np_net_type != RAY_MIB_NET_TYPE_INFRA) { |
| 1290 | ray_com_runq_done(sc); |
| 1291 | return; |
| 1292 | } |
| 1293 | |
| 1294 | /* |
| 1295 | * Kick the card |
| 1296 | */ |
| 1297 | ray_ccs_fill(sc, com->c_ccs, RAY_CMD_START_ASSOC); |
| 1298 | ray_com_ecf(sc, com); |
| 1299 | } |
| 1300 | |
| 1301 | /* |
| 1302 | * Complete association |
| 1303 | */ |
| 1304 | static void |
| 1305 | ray_init_assoc_done(struct ray_softc *sc, u_int8_t status, size_t ccs) |
| 1306 | { |
| 1307 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1308 | |
| 1309 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 1310 | RAY_COM_CHECK(sc, ccs); |
| 1311 | |
| 1312 | RAY_CCSERR(sc, status, if_oerrors); /* XXX error counter */ |
| 1313 | |
| 1314 | /* |
| 1315 | * Hurrah! The network is now active. |
| 1316 | * |
| 1317 | * Clearing IFF_OACTIVE will ensure that the system will send us |
| 1318 | * packets. Just before we return from the interrupt context |
| 1319 | * we check to see if packets have been queued. |
| 1320 | */ |
| 1321 | sc->sc_c.np_havenet = 1; |
| 1322 | sc->sc_c.np_framing = sc->sc_d.np_framing; |
| 1323 | ifp->if_flags |= IFF_RUNNING; |
| 1324 | ifp->if_flags &= ~IFF_OACTIVE; |
| 1325 | |
| 1326 | ray_com_ecf_done(sc); |
| 1327 | } |
| 1328 | |
| 1329 | /* |
| 1330 | * Network stop. |
| 1331 | * |
| 1332 | * Inhibit card - if we can't prevent reception then do not worry; |
| 1333 | * stopping a NIC only guarantees no TX. |
| 1334 | * |
| 1335 | * The change to the interface flags is done via the runq so that any |
| 1336 | * existing commands can execute normally. |
| 1337 | */ |
| 1338 | static int |
| 1339 | ray_stop_user(struct ray_softc *sc) |
| 1340 | { |
| 1341 | struct ray_comq_entry *com[1]; |
| 1342 | int error, ncom; |
| 1343 | |
| 1344 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STOP, ""); |
| 1345 | |
| 1346 | /* |
| 1347 | * Schedule the real stop routine |
| 1348 | */ |
| 1349 | ncom = 0; |
| 1350 | com[ncom++] = RAY_COM_MALLOC(ray_stop, 0); |
| 1351 | |
| 1352 | RAY_COM_RUNQ(sc, com, ncom, "raystop", error); |
| 1353 | |
| 1354 | /* XXX no real error processing from anything yet! */ |
| 1355 | |
| 1356 | RAY_COM_FREE(com, ncom); |
| 1357 | |
| 1358 | return (error); |
| 1359 | } |
| 1360 | |
| 1361 | /* |
| 1362 | * Runq entry for stopping the interface activity |
| 1363 | */ |
| 1364 | static void |
| 1365 | ray_stop(struct ray_softc *sc, struct ray_comq_entry *com) |
| 1366 | { |
| 1367 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1368 | |
| 1369 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STOP, ""); |
| 1370 | |
| 1371 | /* |
| 1372 | * Mark as not running and drain output queue |
| 1373 | */ |
| 1374 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
| 1375 | ifp->if_timer = 0; |
| 1376 | ifq_purge(&ifp->if_snd); |
| 1377 | ray_com_runq_done(sc); |
| 1378 | } |
| 1379 | |
| 1380 | static void |
| 1381 | ray_watchdog(struct ifnet *ifp) |
| 1382 | { |
| 1383 | struct ray_softc *sc = ifp->if_softc; |
| 1384 | |
| 1385 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 1386 | RAY_MAP_CM(sc); |
| 1387 | |
| 1388 | if ((sc == NULL) || (sc->sc_gone)) |
| 1389 | return; |
| 1390 | |
| 1391 | RAY_PRINTF(sc, "watchdog timeout"); |
| 1392 | } |
| 1393 | |
| 1394 | /* |
| 1395 | * Transmit packet handling |
| 1396 | */ |
| 1397 | |
| 1398 | /* |
| 1399 | * Send a packet. |
| 1400 | * |
| 1401 | * We make two assumptions here: |
| 1402 | * 1) That the current priority is set to splimp _before_ this code |
| 1403 | * is called *and* is returned to the appropriate priority after |
| 1404 | * return |
| 1405 | * 2) That the IFF_OACTIVE flag is checked before this code is called |
| 1406 | * (i.e. that the output part of the interface is idle) |
| 1407 | * |
| 1408 | * A simple one packet at a time TX routine is used - we don't bother |
| 1409 | * chaining TX buffers. Performance is sufficient to max out the |
| 1410 | * wireless link on a P75. |
| 1411 | * |
| 1412 | * AST J30 Windows 95A (100MHz Pentium) to |
| 1413 | * Libretto 50CT FreeBSD-3.1 (75MHz Pentium) 167.37kB/s |
| 1414 | * Nonname box FreeBSD-3.4 (233MHz AMD K6) 161.82kB/s |
| 1415 | * |
| 1416 | * Libretto 50CT FreeBSD-3.1 (75MHz Pentium) to |
| 1417 | * AST J30 Windows 95A (100MHz Pentium) 167.37kB/s |
| 1418 | * Nonname box FreeBSD-3.4 (233MHz AMD K6) 161.38kB/s |
| 1419 | * |
| 1420 | * Given that 160kB/s is saturating the 2Mb/s wireless link we |
| 1421 | * are about there. |
| 1422 | * |
| 1423 | * In short I'm happy that the added complexity of chaining TX |
| 1424 | * packets together isn't worth it for my machines. |
| 1425 | */ |
| 1426 | static void |
| 1427 | ray_tx(struct ifnet *ifp) |
| 1428 | { |
| 1429 | struct ray_softc *sc = ifp->if_softc; |
| 1430 | struct mbuf *m0, *m; |
| 1431 | struct ether_header *eh; |
| 1432 | struct llc *llc; |
| 1433 | size_t ccs, bufp; |
| 1434 | int pktlen, len; |
| 1435 | |
| 1436 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_TX, ""); |
| 1437 | RAY_MAP_CM(sc); |
| 1438 | |
| 1439 | /* |
| 1440 | * Some simple checks first - some are overkill |
| 1441 | */ |
| 1442 | if ((sc == NULL) || (sc->sc_gone)) |
| 1443 | return; |
| 1444 | if (!(ifp->if_flags & IFF_RUNNING)) { |
| 1445 | RAY_RECERR(sc, "cannot transmit - not running"); |
| 1446 | return; |
| 1447 | } |
| 1448 | if (!sc->sc_c.np_havenet) { |
| 1449 | RAY_RECERR(sc, "cannot transmit - no network"); |
| 1450 | return; |
| 1451 | } |
| 1452 | if (!RAY_ECF_READY(sc)) { |
| 1453 | /* Can't assume that the ECF is busy because of this driver */ |
| 1454 | if (!callout_active(&sc->tx_timer)) { |
| 1455 | callout_reset(&sc->tx_timer, RAY_TX_TIMEOUT, |
| 1456 | ray_tx_timo, sc); |
| 1457 | return; |
| 1458 | } |
| 1459 | } else |
| 1460 | callout_stop(&sc->tx_timer); |
| 1461 | |
| 1462 | /* |
| 1463 | * We find a ccs before we process the mbuf so that we are sure it |
| 1464 | * is worthwhile processing the packet. All errors in the mbuf |
| 1465 | * processing are either errors in the mbuf or gross configuration |
| 1466 | * errors and the packet wouldn't get through anyway. |
| 1467 | */ |
| 1468 | if (ray_ccs_tx(sc, &ccs, &bufp)) { |
| 1469 | ifp->if_flags |= IFF_OACTIVE; |
| 1470 | return; |
| 1471 | } |
| 1472 | |
| 1473 | /* |
| 1474 | * Get the mbuf and process it - we have to remember to free the |
| 1475 | * ccs if there are any errors. |
| 1476 | */ |
| 1477 | m0 = ifq_dequeue(&ifp->if_snd); |
| 1478 | if (m0 == NULL) { |
| 1479 | RAY_CCS_FREE(sc, ccs); |
| 1480 | return; |
| 1481 | } |
| 1482 | |
| 1483 | pktlen = m0->m_pkthdr.len; |
| 1484 | if (pktlen > ETHER_MAX_LEN - ETHER_CRC_LEN) { |
| 1485 | RAY_RECERR(sc, "mbuf too long %d", pktlen); |
| 1486 | RAY_CCS_FREE(sc, ccs); |
| 1487 | ifp->if_oerrors++; |
| 1488 | m_freem(m0); |
| 1489 | return; |
| 1490 | } |
| 1491 | |
| 1492 | m0 = m_pullup(m0, sizeof(struct ether_header)); |
| 1493 | if (m0 == NULL) { |
| 1494 | RAY_RECERR(sc, "could not pullup ether"); |
| 1495 | RAY_CCS_FREE(sc, ccs); |
| 1496 | ifp->if_oerrors++; |
| 1497 | return; |
| 1498 | } |
| 1499 | eh = mtod(m0, struct ether_header *); |
| 1500 | |
| 1501 | /* |
| 1502 | * Write the 802.11 header according to network type etc. |
| 1503 | */ |
| 1504 | if (sc->sc_c.np_net_type == RAY_MIB_NET_TYPE_ADHOC) |
| 1505 | bufp = ray_tx_wrhdr(sc, bufp, |
| 1506 | IEEE80211_FC0_TYPE_DATA, |
| 1507 | IEEE80211_FC1_DIR_NODS, |
| 1508 | eh->ether_dhost, |
| 1509 | eh->ether_shost, |
| 1510 | sc->sc_c.np_bss_id); |
| 1511 | else |
| 1512 | if (sc->sc_c.np_ap_status == RAY_MIB_AP_STATUS_TERMINAL) |
| 1513 | bufp = ray_tx_wrhdr(sc, bufp, |
| 1514 | IEEE80211_FC0_TYPE_DATA, |
| 1515 | IEEE80211_FC1_DIR_TODS, |
| 1516 | sc->sc_c.np_bss_id, |
| 1517 | eh->ether_shost, |
| 1518 | eh->ether_dhost); |
| 1519 | else |
| 1520 | bufp = ray_tx_wrhdr(sc, bufp, |
| 1521 | IEEE80211_FC0_TYPE_DATA, |
| 1522 | IEEE80211_FC1_DIR_FROMDS, |
| 1523 | eh->ether_dhost, |
| 1524 | sc->sc_c.np_bss_id, |
| 1525 | eh->ether_shost); |
| 1526 | |
| 1527 | /* |
| 1528 | * Framing |
| 1529 | * |
| 1530 | * Add to the mbuf. |
| 1531 | */ |
| 1532 | switch (sc->sc_c.np_framing) { |
| 1533 | |
| 1534 | case RAY_FRAMING_ENCAPSULATION: |
| 1535 | /* Nice and easy - nothing! (just add an 802.11 header) */ |
| 1536 | break; |
| 1537 | |
| 1538 | case RAY_FRAMING_TRANSLATION: |
| 1539 | /* |
| 1540 | * Drop the first address in the ethernet header and |
| 1541 | * write an LLC and SNAP header over the second. |
| 1542 | */ |
| 1543 | m_adj(m0, ETHER_ADDR_LEN); |
| 1544 | if (m0 == NULL) { |
| 1545 | RAY_RECERR(sc, "could not get space for 802.2 header"); |
| 1546 | RAY_CCS_FREE(sc, ccs); |
| 1547 | ifp->if_oerrors++; |
| 1548 | return; |
| 1549 | } |
| 1550 | llc = mtod(m0, struct llc *); |
| 1551 | llc->llc_dsap = LLC_SNAP_LSAP; |
| 1552 | llc->llc_ssap = LLC_SNAP_LSAP; |
| 1553 | llc->llc_control = LLC_UI; |
| 1554 | llc->llc_un.type_snap.org_code[0] = 0; |
| 1555 | llc->llc_un.type_snap.org_code[1] = 0; |
| 1556 | llc->llc_un.type_snap.org_code[2] = 0; |
| 1557 | break; |
| 1558 | |
| 1559 | default: |
| 1560 | RAY_RECERR(sc, "unknown framing type %d", sc->sc_c.np_framing); |
| 1561 | RAY_CCS_FREE(sc, ccs); |
| 1562 | ifp->if_oerrors++; |
| 1563 | m_freem(m0); |
| 1564 | return; |
| 1565 | |
| 1566 | } |
| 1567 | if (m0 == NULL) { |
| 1568 | RAY_RECERR(sc, "could not frame packet"); |
| 1569 | RAY_CCS_FREE(sc, ccs); |
| 1570 | ifp->if_oerrors++; |
| 1571 | return; |
| 1572 | } |
| 1573 | RAY_MBUF_DUMP(sc, RAY_DBG_TX, m0, "framed packet"); |
| 1574 | |
| 1575 | /* |
| 1576 | * Copy the mbuf to the buffer in common memory |
| 1577 | * |
| 1578 | * We drop and don't bother wrapping as Ethernet packets are 1518 |
| 1579 | * bytes, we checked the mbuf earlier, and our TX buffers are 2048 |
| 1580 | * bytes. We don't have 530 bytes of headers etc. so something |
| 1581 | * must be fubar. |
| 1582 | */ |
| 1583 | pktlen = sizeof(struct ieee80211_frame); |
| 1584 | for (m = m0; m != NULL; m = m->m_next) { |
| 1585 | pktlen += m->m_len; |
| 1586 | if ((len = m->m_len) == 0) |
| 1587 | continue; |
| 1588 | if ((bufp + len) < RAY_TX_END) |
| 1589 | SRAM_WRITE_REGION(sc, bufp, mtod(m, u_int8_t *), len); |
| 1590 | else { |
| 1591 | RAY_RECERR(sc, "tx buffer overflow"); |
| 1592 | RAY_CCS_FREE(sc, ccs); |
| 1593 | ifp->if_oerrors++; |
| 1594 | m_freem(m0); |
| 1595 | return; |
| 1596 | } |
| 1597 | bufp += len; |
| 1598 | } |
| 1599 | |
| 1600 | /* |
| 1601 | * Send it off |
| 1602 | */ |
| 1603 | if (ray_tx_send(sc, ccs, pktlen, eh->ether_dhost)) |
| 1604 | ifp->if_oerrors++; |
| 1605 | else |
| 1606 | ifp->if_opackets++; |
| 1607 | m_freem(m0); |
| 1608 | } |
| 1609 | |
| 1610 | /* |
| 1611 | * Start timeout routine. |
| 1612 | * |
| 1613 | * Used when card was busy but we needed to send a packet. |
| 1614 | */ |
| 1615 | static void |
| 1616 | ray_tx_timo(void *xsc) |
| 1617 | { |
| 1618 | struct ray_softc *sc = (struct ray_softc *)xsc; |
| 1619 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1620 | int s; |
| 1621 | |
| 1622 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 1623 | |
| 1624 | if ((ifp->if_flags & IFF_OACTIVE) == 0 && !ifq_is_empty(&ifp->if_snd)) { |
| 1625 | s = splimp(); |
| 1626 | ray_tx(ifp); |
| 1627 | splx(s); |
| 1628 | } |
| 1629 | } |
| 1630 | |
| 1631 | /* |
| 1632 | * Write an 802.11 header into the Tx buffer space and return the |
| 1633 | * adjusted buffer pointer. |
| 1634 | */ |
| 1635 | static size_t |
| 1636 | ray_tx_wrhdr(struct ray_softc *sc, size_t bufp, u_int8_t type, u_int8_t fc1, u_int8_t *addr1, u_int8_t *addr2, u_int8_t *addr3) |
| 1637 | { |
| 1638 | struct ieee80211_frame header; |
| 1639 | |
| 1640 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_TX, ""); |
| 1641 | RAY_MAP_CM(sc); |
| 1642 | |
| 1643 | bzero(&header, sizeof(struct ieee80211_frame)); |
| 1644 | header.i_fc[0] = (IEEE80211_FC0_VERSION_0 | type); |
| 1645 | header.i_fc[1] = fc1; |
| 1646 | bcopy(addr1, header.i_addr1, ETHER_ADDR_LEN); |
| 1647 | bcopy(addr2, header.i_addr2, ETHER_ADDR_LEN); |
| 1648 | bcopy(addr3, header.i_addr3, ETHER_ADDR_LEN); |
| 1649 | |
| 1650 | SRAM_WRITE_REGION(sc, bufp, (u_int8_t *)&header, |
| 1651 | sizeof(struct ieee80211_frame)); |
| 1652 | |
| 1653 | return (bufp + sizeof(struct ieee80211_frame)); |
| 1654 | } |
| 1655 | |
| 1656 | /* |
| 1657 | * Fill in a few loose ends and kick the card to send the packet |
| 1658 | * |
| 1659 | * Returns 0 on success, 1 on failure |
| 1660 | */ |
| 1661 | static int |
| 1662 | ray_tx_send(struct ray_softc *sc, size_t ccs, int pktlen, u_int8_t *dst) |
| 1663 | { |
| 1664 | int i = 0; |
| 1665 | |
| 1666 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_TX, ""); |
| 1667 | RAY_MAP_CM(sc); |
| 1668 | |
| 1669 | while (!RAY_ECF_READY(sc)) { |
| 1670 | DELAY(RAY_ECF_SPIN_DELAY); |
| 1671 | if (++i > RAY_ECF_SPIN_TRIES) { |
| 1672 | RAY_RECERR(sc, "ECF busy, dropping packet"); |
| 1673 | RAY_CCS_FREE(sc, ccs); |
| 1674 | return (1); |
| 1675 | } |
| 1676 | } |
| 1677 | if (i != 0) |
| 1678 | RAY_RECERR(sc, "spun %d times", i); |
| 1679 | |
| 1680 | SRAM_WRITE_FIELD_2(sc, ccs, ray_cmd_tx, c_len, pktlen); |
| 1681 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_antenna, |
| 1682 | ray_tx_best_antenna(sc, dst)); |
| 1683 | SRAM_WRITE_1(sc, RAY_SCB_CCSI, RAY_CCS_INDEX(ccs)); |
| 1684 | RAY_ECF_START_CMD(sc); |
| 1685 | |
| 1686 | return (0); |
| 1687 | } |
| 1688 | |
| 1689 | /* |
| 1690 | * Determine best antenna to use from rx level and antenna cache |
| 1691 | */ |
| 1692 | static u_int8_t |
| 1693 | ray_tx_best_antenna(struct ray_softc *sc, u_int8_t *dst) |
| 1694 | { |
| 1695 | struct ray_siglev *sl; |
| 1696 | int i; |
| 1697 | u_int8_t antenna; |
| 1698 | |
| 1699 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_TX, ""); |
| 1700 | |
| 1701 | if (sc->sc_version == RAY_ECFS_BUILD_4) |
| 1702 | return (0); |
| 1703 | |
| 1704 | /* try to find host */ |
| 1705 | for (i = 0; i < RAY_NSIGLEVRECS; i++) { |
| 1706 | sl = &sc->sc_siglevs[i]; |
| 1707 | if (bcmp(sl->rsl_host, dst, ETHER_ADDR_LEN) == 0) |
| 1708 | goto found; |
| 1709 | } |
| 1710 | /* not found, return default setting */ |
| 1711 | return (0); |
| 1712 | |
| 1713 | found: |
| 1714 | /* This is a simple thresholding scheme that takes the mean |
| 1715 | * of the best antenna history. This is okay but as it is a |
| 1716 | * filter, it adds a bit of lag in situations where the |
| 1717 | * best antenna swaps from one side to the other slowly. Don't know |
| 1718 | * how likely this is given the horrible fading though. |
| 1719 | */ |
| 1720 | antenna = 0; |
| 1721 | for (i = 0; i < RAY_NANTENNA; i++) { |
| 1722 | antenna += sl->rsl_antennas[i]; |
| 1723 | } |
| 1724 | |
| 1725 | return (antenna > (RAY_NANTENNA >> 1)); |
| 1726 | } |
| 1727 | |
| 1728 | /* |
| 1729 | * Transmit now complete so clear ccs and network flags. |
| 1730 | */ |
| 1731 | static void |
| 1732 | ray_tx_done(struct ray_softc *sc, u_int8_t status, size_t ccs) |
| 1733 | { |
| 1734 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1735 | |
| 1736 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_TX, ""); |
| 1737 | |
| 1738 | RAY_CCSERR(sc, status, if_oerrors); |
| 1739 | |
| 1740 | RAY_CCS_FREE(sc, ccs); |
| 1741 | ifp->if_timer = 0; |
| 1742 | if (ifp->if_flags & IFF_OACTIVE) |
| 1743 | ifp->if_flags &= ~IFF_OACTIVE; |
| 1744 | } |
| 1745 | |
| 1746 | /* |
| 1747 | * Receiver packet handling |
| 1748 | */ |
| 1749 | |
| 1750 | /* |
| 1751 | * Receive a packet from the card |
| 1752 | */ |
| 1753 | static void |
| 1754 | ray_rx(struct ray_softc *sc, size_t rcs) |
| 1755 | { |
| 1756 | struct ieee80211_frame *header; |
| 1757 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1758 | struct mbuf *m0; |
| 1759 | size_t pktlen, fraglen, readlen, tmplen; |
| 1760 | size_t bufp, ebufp; |
| 1761 | u_int8_t siglev, antenna; |
| 1762 | u_int first, ni, i; |
| 1763 | u_int8_t *mp; |
| 1764 | |
| 1765 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 1766 | RAY_MAP_CM(sc); |
| 1767 | |
| 1768 | RAY_DPRINTF(sc, RAY_DBG_CCS, "using rcs 0x%x", rcs); |
| 1769 | |
| 1770 | m0 = NULL; |
| 1771 | readlen = 0; |
| 1772 | |
| 1773 | /* |
| 1774 | * Get first part of packet and the length. Do some sanity checks |
| 1775 | * and get a mbuf. |
| 1776 | */ |
| 1777 | first = RAY_CCS_INDEX(rcs); |
| 1778 | pktlen = SRAM_READ_FIELD_2(sc, rcs, ray_cmd_rx, c_pktlen); |
| 1779 | siglev = SRAM_READ_FIELD_1(sc, rcs, ray_cmd_rx, c_siglev); |
| 1780 | antenna = SRAM_READ_FIELD_1(sc, rcs, ray_cmd_rx, c_antenna); |
| 1781 | |
| 1782 | if ((pktlen > MCLBYTES) || (pktlen < sizeof(struct ieee80211_frame))) { |
| 1783 | RAY_RECERR(sc, "packet too big or too small"); |
| 1784 | ifp->if_ierrors++; |
| 1785 | goto skip_read; |
| 1786 | } |
| 1787 | |
| 1788 | MGETHDR(m0, MB_DONTWAIT, MT_DATA); |
| 1789 | if (m0 == NULL) { |
| 1790 | RAY_RECERR(sc, "MGETHDR failed"); |
| 1791 | ifp->if_ierrors++; |
| 1792 | goto skip_read; |
| 1793 | } |
| 1794 | if (pktlen > MHLEN) { |
| 1795 | MCLGET(m0, MB_DONTWAIT); |
| 1796 | if (!(m0->m_flags & M_EXT)) { |
| 1797 | RAY_RECERR(sc, "MCLGET failed"); |
| 1798 | ifp->if_ierrors++; |
| 1799 | m_freem(m0); |
| 1800 | m0 = NULL; |
| 1801 | goto skip_read; |
| 1802 | } |
| 1803 | } |
| 1804 | m0->m_pkthdr.rcvif = ifp; |
| 1805 | m0->m_pkthdr.len = pktlen; |
| 1806 | m0->m_len = pktlen; |
| 1807 | mp = mtod(m0, u_int8_t *); |
| 1808 | |
| 1809 | /* |
| 1810 | * Walk the fragment chain to build the complete packet. |
| 1811 | * |
| 1812 | * The use of two index variables removes a race with the |
| 1813 | * hardware. If one index were used the clearing of the CCS would |
| 1814 | * happen before reading the next pointer and the hardware can get in. |
| 1815 | * Not my idea but verbatim from the NetBSD driver. |
| 1816 | */ |
| 1817 | i = ni = first; |
| 1818 | while ((i = ni) && (i != RAY_CCS_LINK_NULL)) { |
| 1819 | rcs = RAY_CCS_ADDRESS(i); |
| 1820 | ni = SRAM_READ_FIELD_1(sc, rcs, ray_cmd_rx, c_nextfrag); |
| 1821 | bufp = SRAM_READ_FIELD_2(sc, rcs, ray_cmd_rx, c_bufp); |
| 1822 | fraglen = SRAM_READ_FIELD_2(sc, rcs, ray_cmd_rx, c_len); |
| 1823 | if (fraglen + readlen > pktlen) { |
| 1824 | RAY_RECERR(sc, "bad length current 0x%x pktlen 0x%x", |
| 1825 | fraglen + readlen, pktlen); |
| 1826 | ifp->if_ierrors++; |
| 1827 | m_freem(m0); |
| 1828 | m0 = NULL; |
| 1829 | goto skip_read; |
| 1830 | } |
| 1831 | if ((i < RAY_RCS_FIRST) || (i > RAY_RCS_LAST)) { |
| 1832 | RAY_RECERR(sc, "bad rcs index 0x%x", i); |
| 1833 | ifp->if_ierrors++; |
| 1834 | m_freem(m0); |
| 1835 | m0 = NULL; |
| 1836 | goto skip_read; |
| 1837 | } |
| 1838 | |
| 1839 | ebufp = bufp + fraglen; |
| 1840 | if (ebufp <= RAY_RX_END) |
| 1841 | SRAM_READ_REGION(sc, bufp, mp, fraglen); |
| 1842 | else { |
| 1843 | SRAM_READ_REGION(sc, bufp, mp, |
| 1844 | (tmplen = RAY_RX_END - bufp)); |
| 1845 | SRAM_READ_REGION(sc, RAY_RX_BASE, mp + tmplen, |
| 1846 | ebufp - RAY_RX_END); |
| 1847 | } |
| 1848 | mp += fraglen; |
| 1849 | readlen += fraglen; |
| 1850 | } |
| 1851 | |
| 1852 | skip_read: |
| 1853 | |
| 1854 | /* |
| 1855 | * Walk the chain again to free the rcss. |
| 1856 | */ |
| 1857 | i = ni = first; |
| 1858 | while ((i = ni) && (i != RAY_CCS_LINK_NULL)) { |
| 1859 | rcs = RAY_CCS_ADDRESS(i); |
| 1860 | ni = SRAM_READ_FIELD_1(sc, rcs, ray_cmd_rx, c_nextfrag); |
| 1861 | RAY_CCS_FREE(sc, rcs); |
| 1862 | } |
| 1863 | |
| 1864 | if (m0 == NULL) |
| 1865 | return; |
| 1866 | |
| 1867 | /* |
| 1868 | * Check the 802.11 packet type and hand off to |
| 1869 | * appropriate functions. |
| 1870 | */ |
| 1871 | header = mtod(m0, struct ieee80211_frame *); |
| 1872 | if ((header->i_fc[0] & IEEE80211_FC0_VERSION_MASK) |
| 1873 | != IEEE80211_FC0_VERSION_0) { |
| 1874 | RAY_RECERR(sc, "header not version 0 fc0 0x%x", |
| 1875 | header->i_fc[0]); |
| 1876 | ifp->if_ierrors++; |
| 1877 | m_freem(m0); |
| 1878 | return; |
| 1879 | } |
| 1880 | switch (header->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { |
| 1881 | |
| 1882 | case IEEE80211_FC0_TYPE_DATA: |
| 1883 | ray_rx_data(sc, m0, siglev, antenna); |
| 1884 | break; |
| 1885 | |
| 1886 | case IEEE80211_FC0_TYPE_MGT: |
| 1887 | ray_rx_mgt(sc, m0); |
| 1888 | break; |
| 1889 | |
| 1890 | case IEEE80211_FC0_TYPE_CTL: |
| 1891 | ray_rx_ctl(sc, m0); |
| 1892 | break; |
| 1893 | |
| 1894 | default: |
| 1895 | RAY_RECERR(sc, "unknown packet fc0 0x%x", header->i_fc[0]); |
| 1896 | ifp->if_ierrors++; |
| 1897 | m_freem(m0); |
| 1898 | } |
| 1899 | } |
| 1900 | |
| 1901 | /* |
| 1902 | * Deal with DATA packet types |
| 1903 | */ |
| 1904 | static void |
| 1905 | ray_rx_data(struct ray_softc *sc, struct mbuf *m0, u_int8_t siglev, u_int8_t antenna) |
| 1906 | { |
| 1907 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 1908 | struct ieee80211_frame *header = mtod(m0, struct ieee80211_frame *); |
| 1909 | struct ether_header *eh; |
| 1910 | struct llc *llc; |
| 1911 | u_int8_t *sa = NULL, *da = NULL, *ra = NULL, *ta = NULL; |
| 1912 | int trim = 0; |
| 1913 | |
| 1914 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_RX, ""); |
| 1915 | |
| 1916 | /* |
| 1917 | * Check the the data packet subtype, some packets have |
| 1918 | * nothing in them so we will drop them here. |
| 1919 | */ |
| 1920 | switch (header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { |
| 1921 | |
| 1922 | case IEEE80211_FC0_SUBTYPE_DATA: |
| 1923 | case IEEE80211_FC0_SUBTYPE_CF_ACK: |
| 1924 | case IEEE80211_FC0_SUBTYPE_CF_POLL: |
| 1925 | case IEEE80211_FC0_SUBTYPE_CF_ACPL: |
| 1926 | RAY_DPRINTF(sc, RAY_DBG_RX, "DATA packet"); |
| 1927 | break; |
| 1928 | |
| 1929 | case IEEE80211_FC0_SUBTYPE_NODATA: |
| 1930 | case IEEE80211_FC0_SUBTYPE_CFACK: |
| 1931 | case IEEE80211_FC0_SUBTYPE_CFPOLL: |
| 1932 | case IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK: |
| 1933 | RAY_DPRINTF(sc, RAY_DBG_RX, "NULL packet"); |
| 1934 | m_freem(m0); |
| 1935 | return; |
| 1936 | break; |
| 1937 | |
| 1938 | default: |
| 1939 | RAY_RECERR(sc, "reserved DATA packet subtype 0x%x", |
| 1940 | header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); |
| 1941 | ifp->if_ierrors++; |
| 1942 | m_freem(m0); |
| 1943 | return; |
| 1944 | } |
| 1945 | |
| 1946 | /* |
| 1947 | * Parse the To DS and From DS fields to determine the length |
| 1948 | * of the 802.11 header for use later on. |
| 1949 | * |
| 1950 | * Additionally, furtle out the right destination and |
| 1951 | * source MAC addresses for the packet. Packets may come via |
| 1952 | * APs so the MAC addresses of the immediate node may be |
| 1953 | * different from the node that actually sent us the packet. |
| 1954 | * |
| 1955 | * da destination address of final recipient |
| 1956 | * sa source address of orginator |
| 1957 | * ra receiver address of immediate recipient |
| 1958 | * ta transmitter address of immediate orginator |
| 1959 | * |
| 1960 | * Address matching is performed on da or sa with the AP or |
| 1961 | * BSSID in ra and ta. |
| 1962 | */ |
| 1963 | RAY_MBUF_DUMP(sc, RAY_DBG_RX, m0, "(1) packet before framing"); |
| 1964 | switch (header->i_fc[1] & IEEE80211_FC1_DIR_MASK) { |
| 1965 | |
| 1966 | case IEEE80211_FC1_DIR_NODS: |
| 1967 | da = ra = header->i_addr1; |
| 1968 | sa = ta = header->i_addr2; |
| 1969 | trim = sizeof(struct ieee80211_frame); |
| 1970 | RAY_DPRINTF(sc, RAY_DBG_RX, "from %6D to %6D", |
| 1971 | sa, ":", da, ":"); |
| 1972 | break; |
| 1973 | |
| 1974 | case IEEE80211_FC1_DIR_FROMDS: |
| 1975 | da = ra = header->i_addr1; |
| 1976 | ta = header->i_addr2; |
| 1977 | sa = header->i_addr3; |
| 1978 | trim = sizeof(struct ieee80211_frame); |
| 1979 | RAY_DPRINTF(sc, RAY_DBG_RX, "ap %6D from %6D to %6D", |
| 1980 | ta, ":", sa, ":", da, ":"); |
| 1981 | break; |
| 1982 | |
| 1983 | case IEEE80211_FC1_DIR_TODS: |
| 1984 | ra = header->i_addr1; |
| 1985 | sa = ta = header->i_addr2; |
| 1986 | da = header->i_addr3; |
| 1987 | trim = sizeof(struct ieee80211_frame); |
| 1988 | RAY_DPRINTF(sc, RAY_DBG_RX, "from %6D to %6D ap %6D", |
| 1989 | sa, ":", da, ":", ra, ":"); |
| 1990 | break; |
| 1991 | |
| 1992 | case IEEE80211_FC1_DIR_DSTODS: |
| 1993 | ra = header->i_addr1; |
| 1994 | ta = header->i_addr2; |
| 1995 | da = header->i_addr3; |
| 1996 | sa = (u_int8_t *)header+1; |
| 1997 | trim = sizeof(struct ieee80211_frame) + ETHER_ADDR_LEN; |
| 1998 | RAY_DPRINTF(sc, RAY_DBG_RX, "from %6D to %6D ap %6D to %6D", |
| 1999 | sa, ":", da, ":", ta, ":", ra, ":"); |
| 2000 | break; |
| 2001 | } |
| 2002 | |
| 2003 | /* |
| 2004 | * Framing |
| 2005 | * |
| 2006 | * Each case must leave an Ethernet header and adjust trim. |
| 2007 | */ |
| 2008 | switch (sc->sc_c.np_framing) { |
| 2009 | |
| 2010 | case RAY_FRAMING_ENCAPSULATION: |
| 2011 | /* A NOP as the Ethernet header is in the packet */ |
| 2012 | break; |
| 2013 | |
| 2014 | case RAY_FRAMING_TRANSLATION: |
| 2015 | /* Check that we have an LLC and SNAP sequence */ |
| 2016 | llc = (struct llc *)((u_int8_t *)header + trim); |
| 2017 | if (llc->llc_dsap == LLC_SNAP_LSAP && |
| 2018 | llc->llc_ssap == LLC_SNAP_LSAP && |
| 2019 | llc->llc_control == LLC_UI && |
| 2020 | llc->llc_un.type_snap.org_code[0] == 0 && |
| 2021 | llc->llc_un.type_snap.org_code[1] == 0 && |
| 2022 | llc->llc_un.type_snap.org_code[2] == 0) { |
| 2023 | /* |
| 2024 | * This is not magic. RFC1042 header is 8 |
| 2025 | * bytes, with the last two bytes being the |
| 2026 | * ether type. So all we need is another |
| 2027 | * ETHER_ADDR_LEN bytes to write the |
| 2028 | * destination into. |
| 2029 | */ |
| 2030 | trim -= ETHER_ADDR_LEN; |
| 2031 | eh = (struct ether_header *)((u_int8_t *)header + trim); |
| 2032 | |
| 2033 | /* |
| 2034 | * Copy carefully to avoid mashing the MAC |
| 2035 | * addresses. The address layout in the .11 header |
| 2036 | * does make sense, honest, but it is a pain. |
| 2037 | * |
| 2038 | * NODS da sa no risk |
| 2039 | * FROMDS da ta sa sa then da |
| 2040 | * DSTODS ra ta da sa sa then da |
| 2041 | * TODS ra sa da da then sa |
| 2042 | */ |
| 2043 | if (sa > da) { |
| 2044 | /* Copy sa first */ |
| 2045 | bcopy(sa, eh->ether_shost, ETHER_ADDR_LEN); |
| 2046 | bcopy(da, eh->ether_dhost, ETHER_ADDR_LEN); |
| 2047 | } else { |
| 2048 | /* Copy da first */ |
| 2049 | bcopy(da, eh->ether_dhost, ETHER_ADDR_LEN); |
| 2050 | bcopy(sa, eh->ether_shost, ETHER_ADDR_LEN); |
| 2051 | } |
| 2052 | |
| 2053 | } else { |
| 2054 | |
| 2055 | /* Assume RAY_FRAMING_ENCAPSULATION */ |
| 2056 | RAY_RECERR(sc, |
| 2057 | "got encapsulated packet but in translation mode"); |
| 2058 | |
| 2059 | } |
| 2060 | break; |
| 2061 | |
| 2062 | default: |
| 2063 | RAY_RECERR(sc, "unknown framing type %d", sc->sc_c.np_framing); |
| 2064 | ifp->if_ierrors++; |
| 2065 | m_freem(m0); |
| 2066 | return; |
| 2067 | } |
| 2068 | RAY_MBUF_DUMP(sc, RAY_DBG_RX, m0, "(2) packet after framing"); |
| 2069 | |
| 2070 | /* |
| 2071 | * Finally, do a bit of house keeping before sending the packet |
| 2072 | * up the stack. |
| 2073 | */ |
| 2074 | m_adj(m0, trim); |
| 2075 | RAY_MBUF_DUMP(sc, RAY_DBG_RX, m0, "(3) packet after trimming"); |
| 2076 | ifp->if_ipackets++; |
| 2077 | ray_rx_update_cache(sc, header->i_addr2, siglev, antenna); |
| 2078 | (*ifp->if_input)(ifp, m0); |
| 2079 | } |
| 2080 | |
| 2081 | /* |
| 2082 | * Deal with MGT packet types |
| 2083 | */ |
| 2084 | static void |
| 2085 | ray_rx_mgt(struct ray_softc *sc, struct mbuf *m0) |
| 2086 | { |
| 2087 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 2088 | struct ieee80211_frame *header = mtod(m0, struct ieee80211_frame *); |
| 2089 | |
| 2090 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_MGT, ""); |
| 2091 | |
| 2092 | if ((header->i_fc[1] & IEEE80211_FC1_DIR_MASK) != |
| 2093 | IEEE80211_FC1_DIR_NODS) { |
| 2094 | RAY_RECERR(sc, "MGT TODS/FROMDS wrong fc1 0x%x", |
| 2095 | header->i_fc[1] & IEEE80211_FC1_DIR_MASK); |
| 2096 | ifp->if_ierrors++; |
| 2097 | m_freem(m0); |
| 2098 | return; |
| 2099 | } |
| 2100 | |
| 2101 | /* |
| 2102 | * Check the the mgt packet subtype, some packets should be |
| 2103 | * dropped depending on the mode the station is in. See pg |
| 2104 | * 52(60) of docs |
| 2105 | * |
| 2106 | * P - proccess, J - Junk, E - ECF deals with, I - Illegal |
| 2107 | * ECF Proccesses |
| 2108 | * AHDOC procces or junk |
| 2109 | * INFRA STA process or junk |
| 2110 | * INFRA AP process or jumk |
| 2111 | * |
| 2112 | * +PPP IEEE80211_FC0_SUBTYPE_BEACON |
| 2113 | * +EEE IEEE80211_FC0_SUBTYPE_PROBE_REQ |
| 2114 | * +EEE IEEE80211_FC0_SUBTYPE_PROBE_RESP |
| 2115 | * PPP IEEE80211_FC0_SUBTYPE_AUTH |
| 2116 | * PPP IEEE80211_FC0_SUBTYPE_DEAUTH |
| 2117 | * JJP IEEE80211_FC0_SUBTYPE_ASSOC_REQ |
| 2118 | * JPJ IEEE80211_FC0_SUBTYPE_ASSOC_RESP |
| 2119 | * JPP IEEE80211_FC0_SUBTYPE_DISASSOC |
| 2120 | * JJP IEEE80211_FC0_SUBTYPE_REASSOC_REQ |
| 2121 | * JPJ IEEE80211_FC0_SUBTYPE_REASSOC_RESP |
| 2122 | * +EEE IEEE80211_FC0_SUBTYPE_ATIM |
| 2123 | */ |
| 2124 | RAY_MBUF_DUMP(sc, RAY_DBG_MGT, m0, "MGT packet"); |
| 2125 | switch (header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { |
| 2126 | |
| 2127 | case IEEE80211_FC0_SUBTYPE_BEACON: |
| 2128 | RAY_DPRINTF(sc, RAY_DBG_MGT, "BEACON MGT packet"); |
| 2129 | ray_rx_mgt_beacon(sc, m0); |
| 2130 | break; |
| 2131 | |
| 2132 | case IEEE80211_FC0_SUBTYPE_AUTH: |
| 2133 | RAY_DPRINTF(sc, RAY_DBG_MGT, "AUTH MGT packet"); |
| 2134 | ray_rx_mgt_auth(sc, m0); |
| 2135 | break; |
| 2136 | |
| 2137 | case IEEE80211_FC0_SUBTYPE_DEAUTH: |
| 2138 | RAY_DPRINTF(sc, RAY_DBG_MGT, "DEAUTH MGT packet"); |
| 2139 | /* XXX ray_rx_mgt_deauth(sc, m0); */ |
| 2140 | break; |
| 2141 | |
| 2142 | case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: |
| 2143 | case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: |
| 2144 | RAY_DPRINTF(sc, RAY_DBG_MGT, "(RE)ASSOC_REQ MGT packet"); |
| 2145 | if ((sc->sc_c.np_net_type == RAY_MIB_NET_TYPE_INFRA) && |
| 2146 | (sc->sc_c.np_ap_status == RAY_MIB_AP_STATUS_AP)) |
| 2147 | RAY_RECERR(sc, "can't be an AP yet"); /* XXX_ACTING_AP */ |
| 2148 | break; |
| 2149 | |
| 2150 | case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: |
| 2151 | case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: |
| 2152 | RAY_DPRINTF(sc, RAY_DBG_MGT, "(RE)ASSOC_RESP MGT packet"); |
| 2153 | if ((sc->sc_c.np_net_type == RAY_MIB_NET_TYPE_INFRA) && |
| 2154 | (sc->sc_c.np_ap_status == RAY_MIB_AP_STATUS_TERMINAL)) |
| 2155 | RAY_RECERR(sc, "can't be in INFRA yet"); /* XXX_INFRA */ |
| 2156 | break; |
| 2157 | |
| 2158 | case IEEE80211_FC0_SUBTYPE_DISASSOC: |
| 2159 | RAY_DPRINTF(sc, RAY_DBG_MGT, "DISASSOC MGT packet"); |
| 2160 | if (sc->sc_c.np_net_type == RAY_MIB_NET_TYPE_INFRA) |
| 2161 | RAY_RECERR(sc, "can't be in INFRA yet"); /* XXX_INFRA */ |
| 2162 | break; |
| 2163 | |
| 2164 | case IEEE80211_FC0_SUBTYPE_PROBE_REQ: |
| 2165 | case IEEE80211_FC0_SUBTYPE_PROBE_RESP: |
| 2166 | case IEEE80211_FC0_SUBTYPE_ATIM: |
| 2167 | RAY_RECERR(sc, "unexpected MGT packet subtype 0x%0x", |
| 2168 | header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); |
| 2169 | ifp->if_ierrors++; |
| 2170 | break; |
| 2171 | |
| 2172 | default: |
| 2173 | RAY_RECERR(sc, "reserved MGT packet subtype 0x%x", |
| 2174 | header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); |
| 2175 | ifp->if_ierrors++; |
| 2176 | } |
| 2177 | |
| 2178 | m_freem(m0); |
| 2179 | } |
| 2180 | |
| 2181 | /* |
| 2182 | * Deal with BEACON management packet types |
| 2183 | * XXX furtle anything interesting out |
| 2184 | * XXX Note that there are rules governing what beacons to read |
| 2185 | * XXX see 8802 S7.2.3, S11.1.2.3 |
| 2186 | * XXX is this actually useful? |
| 2187 | */ |
| 2188 | static void |
| 2189 | ray_rx_mgt_beacon(struct ray_softc *sc, struct mbuf *m0) |
| 2190 | { |
| 2191 | struct ieee80211_frame *header = mtod(m0, struct ieee80211_frame *); |
| 2192 | ieee80211_mgt_beacon_t beacon = (u_int8_t *)(header+1); |
| 2193 | struct ieee80211_information elements; |
| 2194 | |
| 2195 | u_int64_t *timestamp; |
| 2196 | |
| 2197 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_MGT, ""); |
| 2198 | |
| 2199 | timestamp = (u_int64_t *)beacon; |
| 2200 | |
| 2201 | RAY_DPRINTF(sc, RAY_DBG_MGT, "timestamp\t0x%x", *timestamp); |
| 2202 | RAY_DPRINTF(sc, RAY_DBG_MGT, "interval\t\t0x%x", IEEE80211_BEACON_INTERVAL(beacon)); |
| 2203 | RAY_DPRINTF(sc, RAY_DBG_MGT, "capability\t0x%x", IEEE80211_BEACON_CAPABILITY(beacon)); |
| 2204 | |
| 2205 | ray_rx_mgt_info(sc, m0, &elements); |
| 2206 | |
| 2207 | } |
| 2208 | |
| 2209 | static void |
| 2210 | ray_rx_mgt_info(struct ray_softc *sc, struct mbuf *m0, struct ieee80211_information *elements) |
| 2211 | { |
| 2212 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 2213 | struct ieee80211_frame *header = mtod(m0, struct ieee80211_frame *); |
| 2214 | ieee80211_mgt_beacon_t beacon = (u_int8_t *)(header+1); |
| 2215 | ieee80211_mgt_beacon_t bp, be; |
| 2216 | int len; |
| 2217 | |
| 2218 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_MGT, ""); |
| 2219 | |
| 2220 | bp = beacon + 12; |
| 2221 | be = mtod(m0, u_int8_t *) + m0->m_len; |
| 2222 | |
| 2223 | while (bp < be) { |
| 2224 | len = *(bp + 1); |
| 2225 | RAY_DPRINTF(sc, RAY_DBG_MGT, "id 0x%02x length %d", *bp, len); |
| 2226 | |
| 2227 | switch (*bp) { |
| 2228 | |
| 2229 | case IEEE80211_ELEMID_SSID: |
| 2230 | if (len > IEEE80211_NWID_LEN) { |
| 2231 | RAY_RECERR(sc, "bad SSD length: %d from %6D", |
| 2232 | len, header->i_addr2, ":"); |
| 2233 | } |
| 2234 | strncpy(elements->ssid, bp + 2, len); |
| 2235 | elements->ssid[len] = 0; |
| 2236 | RAY_DPRINTF(sc, RAY_DBG_MGT, |
| 2237 | "beacon ssid %s", elements->ssid); |
| 2238 | break; |
| 2239 | |
| 2240 | case IEEE80211_ELEMID_RATES: |
| 2241 | RAY_DPRINTF(sc, RAY_DBG_MGT, "rates"); |
| 2242 | break; |
| 2243 | |
| 2244 | case IEEE80211_ELEMID_FHPARMS: |
| 2245 | elements->fh.dwell = bp[2] + (bp[3] << 8); |
| 2246 | elements->fh.set = bp[4]; |
| 2247 | elements->fh.pattern = bp[5]; |
| 2248 | elements->fh.index = bp[6]; |
| 2249 | RAY_DPRINTF(sc, RAY_DBG_MGT, |
| 2250 | "fhparams dwell\t0x%04x", elements->fh.dwell); |
| 2251 | RAY_DPRINTF(sc, RAY_DBG_MGT, |
| 2252 | "fhparams set\t0x%02x", elements->fh.set); |
| 2253 | RAY_DPRINTF(sc, RAY_DBG_MGT, |
| 2254 | "fhparams pattern\t0x%02x", elements->fh.pattern); |
| 2255 | RAY_DPRINTF(sc, RAY_DBG_MGT, |
| 2256 | "fhparams index\t0x%02x", elements->fh.index); |
| 2257 | break; |
| 2258 | |
| 2259 | case IEEE80211_ELEMID_DSPARMS: |
| 2260 | RAY_RECERR(sc, "got direct sequence params!"); |
| 2261 | break; |
| 2262 | |
| 2263 | case IEEE80211_ELEMID_CFPARMS: |
| 2264 | RAY_DPRINTF(sc, RAY_DBG_MGT, "cfparams"); |
| 2265 | break; |
| 2266 | |
| 2267 | case IEEE80211_ELEMID_TIM: |
| 2268 | elements->tim.count = bp[2]; |
| 2269 | elements->tim.period = bp[3]; |
| 2270 | elements->tim.bitctl = bp[4]; |
| 2271 | RAY_DPRINTF(sc, RAY_DBG_MGT, |
| 2272 | "tim count\t0x%02x", elements->tim.count); |
| 2273 | RAY_DPRINTF(sc, RAY_DBG_MGT, |
| 2274 | "tim period\t0x%02x", elements->tim.period); |
| 2275 | RAY_DPRINTF(sc, RAY_DBG_MGT, |
| 2276 | "tim bitctl\t0x%02x", elements->tim.bitctl); |
| 2277 | #if RAY_DEBUG & RAY_DBG_MGT |
| 2278 | { |
| 2279 | int i; |
| 2280 | for (i = 5; i < len + 1; i++) |
| 2281 | RAY_DPRINTF(sc, RAY_DBG_MGT, |
| 2282 | "tim pvt[%03d]\t0x%02x", i-5, bp[i]); |
| 2283 | } |
| 2284 | #endif |
| 2285 | break; |
| 2286 | |
| 2287 | case IEEE80211_ELEMID_IBSSPARMS: |
| 2288 | elements->ibss.atim = bp[2] + (bp[3] << 8); |
| 2289 | RAY_DPRINTF(sc, RAY_DBG_MGT, |
| 2290 | "ibssparams atim\t0x%02x", elements->ibss.atim); |
| 2291 | break; |
| 2292 | |
| 2293 | case IEEE80211_ELEMID_CHALLENGE: |
| 2294 | RAY_DPRINTF(sc, RAY_DBG_MGT, "challenge"); |
| 2295 | break; |
| 2296 | |
| 2297 | default: |
| 2298 | RAY_RECERR(sc, "reserved MGT element id 0x%x", *bp); |
| 2299 | ifp->if_ierrors++;break; |
| 2300 | } |
| 2301 | bp += bp[1] + 2; |
| 2302 | } |
| 2303 | } |
| 2304 | |
| 2305 | /* |
| 2306 | * Deal with AUTH management packet types |
| 2307 | */ |
| 2308 | static void |
| 2309 | ray_rx_mgt_auth(struct ray_softc *sc, struct mbuf *m0) |
| 2310 | { |
| 2311 | struct ieee80211_frame *header = mtod(m0, struct ieee80211_frame *); |
| 2312 | ieee80211_mgt_auth_t auth = (u_int8_t *)(header+1); |
| 2313 | |
| 2314 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_AUTH, ""); |
| 2315 | |
| 2316 | switch (IEEE80211_AUTH_ALGORITHM(auth)) { |
| 2317 | |
| 2318 | case IEEE80211_AUTH_ALG_OPEN: |
| 2319 | RAY_DPRINTF(sc, RAY_DBG_AUTH, |
| 2320 | "open system authentication sequence number %d", |
| 2321 | IEEE80211_AUTH_TRANSACTION(auth)); |
| 2322 | if (IEEE80211_AUTH_TRANSACTION(auth) == |
| 2323 | IEEE80211_AUTH_OPEN_REQUEST) { |
| 2324 | |
| 2325 | /* XXX_AUTH use ray_init_auth_send */ |
| 2326 | |
| 2327 | } else if (IEEE80211_AUTH_TRANSACTION(auth) == |
| 2328 | IEEE80211_AUTH_OPEN_RESPONSE) |
| 2329 | ray_init_auth_done(sc, IEEE80211_AUTH_STATUS(auth)); |
| 2330 | break; |
| 2331 | |
| 2332 | case IEEE80211_AUTH_ALG_SHARED: |
| 2333 | RAY_RECERR(sc, |
| 2334 | "shared key authentication sequence number %d", |
| 2335 | IEEE80211_AUTH_TRANSACTION(auth)); |
| 2336 | break; |
| 2337 | |
| 2338 | default: |
| 2339 | RAY_RECERR(sc, |
| 2340 | "reserved authentication subtype 0x%04hx", |
| 2341 | IEEE80211_AUTH_ALGORITHM(auth)); |
| 2342 | break; |
| 2343 | } |
| 2344 | } |
| 2345 | |
| 2346 | /* |
| 2347 | * Deal with CTL packet types |
| 2348 | */ |
| 2349 | static void |
| 2350 | ray_rx_ctl(struct ray_softc *sc, struct mbuf *m0) |
| 2351 | { |
| 2352 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 2353 | struct ieee80211_frame *header = mtod(m0, struct ieee80211_frame *); |
| 2354 | |
| 2355 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CTL, ""); |
| 2356 | |
| 2357 | if ((header->i_fc[1] & IEEE80211_FC1_DIR_MASK) != |
| 2358 | IEEE80211_FC1_DIR_NODS) { |
| 2359 | RAY_RECERR(sc, "CTL TODS/FROMDS wrong fc1 0x%x", |
| 2360 | header->i_fc[1] & IEEE80211_FC1_DIR_MASK); |
| 2361 | ifp->if_ierrors++; |
| 2362 | m_freem(m0); |
| 2363 | return; |
| 2364 | } |
| 2365 | |
| 2366 | /* |
| 2367 | * Check the the ctl packet subtype, some packets should be |
| 2368 | * dropped depending on the mode the station is in. The ECF |
| 2369 | * should deal with everything but the power save poll to an |
| 2370 | * AP. See pg 52(60) of docs. |
| 2371 | */ |
| 2372 | RAY_MBUF_DUMP(sc, RAY_DBG_CTL, m0, "CTL packet"); |
| 2373 | switch (header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { |
| 2374 | |
| 2375 | case IEEE80211_FC0_SUBTYPE_PS_POLL: |
| 2376 | RAY_DPRINTF(sc, RAY_DBG_CTL, "PS_POLL CTL packet"); |
| 2377 | if ((sc->sc_d.np_net_type == RAY_MIB_NET_TYPE_INFRA) && |
| 2378 | (sc->sc_c.np_ap_status == RAY_MIB_AP_STATUS_AP)) |
| 2379 | RAY_RECERR(sc, "can't be an AP yet"); /* XXX_ACTING_AP */ |
| 2380 | break; |
| 2381 | |
| 2382 | case IEEE80211_FC0_SUBTYPE_RTS: |
| 2383 | case IEEE80211_FC0_SUBTYPE_CTS: |
| 2384 | case IEEE80211_FC0_SUBTYPE_ACK: |
| 2385 | case IEEE80211_FC0_SUBTYPE_CF_END: |
| 2386 | case IEEE80211_FC0_SUBTYPE_CF_END_ACK: |
| 2387 | RAY_RECERR(sc, "unexpected CTL packet subtype 0x%0x", |
| 2388 | header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); |
| 2389 | ifp->if_ierrors++; |
| 2390 | break; |
| 2391 | |
| 2392 | default: |
| 2393 | RAY_RECERR(sc, "reserved CTL packet subtype 0x%x", |
| 2394 | header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); |
| 2395 | ifp->if_ierrors++; |
| 2396 | } |
| 2397 | |
| 2398 | m_freem(m0); |
| 2399 | } |
| 2400 | |
| 2401 | /* |
| 2402 | * Update rx level and antenna cache |
| 2403 | */ |
| 2404 | static void |
| 2405 | ray_rx_update_cache(struct ray_softc *sc, u_int8_t *src, u_int8_t siglev, u_int8_t antenna) |
| 2406 | { |
| 2407 | struct timeval mint; |
| 2408 | struct ray_siglev *sl; |
| 2409 | int i, mini; |
| 2410 | |
| 2411 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2412 | |
| 2413 | /* Try to find host */ |
| 2414 | for (i = 0; i < RAY_NSIGLEVRECS; i++) { |
| 2415 | sl = &sc->sc_siglevs[i]; |
| 2416 | if (bcmp(sl->rsl_host, src, ETHER_ADDR_LEN) == 0) |
| 2417 | goto found; |
| 2418 | } |
| 2419 | /* Not found, find oldest slot */ |
| 2420 | mini = 0; |
| 2421 | mint.tv_sec = LONG_MAX; |
| 2422 | mint.tv_usec = 0; |
| 2423 | for (i = 0; i < RAY_NSIGLEVRECS; i++) { |
| 2424 | sl = &sc->sc_siglevs[i]; |
| 2425 | if (timevalcmp(&sl->rsl_time, &mint, <)) { |
| 2426 | mini = i; |
| 2427 | mint = sl->rsl_time; |
| 2428 | } |
| 2429 | } |
| 2430 | sl = &sc->sc_siglevs[mini]; |
| 2431 | bzero(sl->rsl_siglevs, RAY_NSIGLEV); |
| 2432 | bzero(sl->rsl_antennas, RAY_NANTENNA); |
| 2433 | bcopy(src, sl->rsl_host, ETHER_ADDR_LEN); |
| 2434 | |
| 2435 | found: |
| 2436 | microtime(&sl->rsl_time); |
| 2437 | bcopy(sl->rsl_siglevs, &sl->rsl_siglevs[1], RAY_NSIGLEV-1); |
| 2438 | sl->rsl_siglevs[0] = siglev; |
| 2439 | if (sc->sc_version != RAY_ECFS_BUILD_4) { |
| 2440 | bcopy(sl->rsl_antennas, &sl->rsl_antennas[1], RAY_NANTENNA-1); |
| 2441 | sl->rsl_antennas[0] = antenna; |
| 2442 | } |
| 2443 | } |
| 2444 | |
| 2445 | /* |
| 2446 | * Interrupt handling |
| 2447 | */ |
| 2448 | |
| 2449 | /* |
| 2450 | * Process an interrupt |
| 2451 | */ |
| 2452 | static void |
| 2453 | ray_intr(void *xsc) |
| 2454 | { |
| 2455 | struct ray_softc *sc = (struct ray_softc *)xsc; |
| 2456 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 2457 | size_t ccs; |
| 2458 | u_int8_t cmd, status; |
| 2459 | int ccsi; |
| 2460 | |
| 2461 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2462 | RAY_MAP_CM(sc); |
| 2463 | |
| 2464 | if ((sc == NULL) || (sc->sc_gone)) |
| 2465 | return; |
| 2466 | |
| 2467 | /* |
| 2468 | * Check that the interrupt was for us, if so get the rcs/ccs |
| 2469 | * and vector on the command contained within it. |
| 2470 | */ |
| 2471 | if (RAY_HCS_INTR(sc)) { |
| 2472 | ccsi = SRAM_READ_1(sc, RAY_SCB_RCSI); |
| 2473 | ccs = RAY_CCS_ADDRESS(ccsi); |
| 2474 | cmd = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_cmd); |
| 2475 | status = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status); |
| 2476 | if (ccsi <= RAY_CCS_LAST) |
| 2477 | ray_intr_ccs(sc, cmd, status, ccs); |
| 2478 | else if (ccsi <= RAY_RCS_LAST) |
| 2479 | ray_intr_rcs(sc, cmd, ccs); |
| 2480 | else |
| 2481 | RAY_RECERR(sc, "bad ccs index 0x%x", ccsi); |
| 2482 | RAY_HCS_CLEAR_INTR(sc); |
| 2483 | } |
| 2484 | |
| 2485 | /* Send any packets lying around and update error counters */ |
| 2486 | if ((ifp->if_flags & IFF_OACTIVE) == 0 && !ifq_is_empty(&ifp->if_snd)) |
| 2487 | ray_tx(ifp); |
| 2488 | if ((++sc->sc_checkcounters % 32) == 0) |
| 2489 | ray_intr_updt_errcntrs(sc); |
| 2490 | } |
| 2491 | |
| 2492 | /* |
| 2493 | * Read the error counters. |
| 2494 | */ |
| 2495 | static void |
| 2496 | ray_intr_updt_errcntrs(struct ray_softc *sc) |
| 2497 | { |
| 2498 | size_t csc; |
| 2499 | |
| 2500 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2501 | RAY_MAP_CM(sc); |
| 2502 | |
| 2503 | /* |
| 2504 | * The card implements the following protocol to keep the |
| 2505 | * values from being changed while read: It checks the `own' |
| 2506 | * bit and if zero writes the current internal counter value, |
| 2507 | * it then sets the `own' bit to 1. If the `own' bit was 1 it |
| 2508 | * incremenets its internal counter. The user thus reads the |
| 2509 | * counter if the `own' bit is one and then sets the own bit |
| 2510 | * to 0. |
| 2511 | */ |
| 2512 | csc = RAY_STATUS_BASE; |
| 2513 | if (SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_mrxo_own)) { |
| 2514 | sc->sc_rxoverflow += |
| 2515 | SRAM_READ_FIELD_2(sc, csc, ray_csc, csc_mrx_overflow); |
| 2516 | SRAM_WRITE_FIELD_1(sc, csc, ray_csc, csc_mrxo_own, 0); |
| 2517 | } |
| 2518 | if (SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_mrxc_own)) { |
| 2519 | sc->sc_rxcksum += |
| 2520 | SRAM_READ_FIELD_2(sc, csc, ray_csc, csc_mrx_overflow); |
| 2521 | SRAM_WRITE_FIELD_1(sc, csc, ray_csc, csc_mrxc_own, 0); |
| 2522 | } |
| 2523 | if (SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_rxhc_own)) { |
| 2524 | sc->sc_rxhcksum += |
| 2525 | SRAM_READ_FIELD_2(sc, csc, ray_csc, csc_rx_hcksum); |
| 2526 | SRAM_WRITE_FIELD_1(sc, csc, ray_csc, csc_rxhc_own, 0); |
| 2527 | } |
| 2528 | sc->sc_rxnoise = SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_rx_noise); |
| 2529 | } |
| 2530 | |
| 2531 | /* |
| 2532 | * Process CCS command completion |
| 2533 | */ |
| 2534 | static void |
| 2535 | ray_intr_ccs(struct ray_softc *sc, u_int8_t cmd, u_int8_t status, size_t ccs) |
| 2536 | { |
| 2537 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2538 | |
| 2539 | switch (cmd) { |
| 2540 | |
| 2541 | case RAY_CMD_DOWNLOAD_PARAMS: |
| 2542 | RAY_DPRINTF(sc, RAY_DBG_COM, "START_PARAMS"); |
| 2543 | ray_init_download_done(sc, status, ccs); |
| 2544 | break; |
| 2545 | |
| 2546 | case RAY_CMD_UPDATE_PARAMS: |
| 2547 | RAY_DPRINTF(sc, RAY_DBG_COM, "UPDATE_PARAMS"); |
| 2548 | ray_upparams_done(sc, status, ccs); |
| 2549 | break; |
| 2550 | |
| 2551 | case RAY_CMD_REPORT_PARAMS: |
| 2552 | RAY_DPRINTF(sc, RAY_DBG_COM, "REPORT_PARAMS"); |
| 2553 | ray_repparams_done(sc, status, ccs); |
| 2554 | break; |
| 2555 | |
| 2556 | case RAY_CMD_UPDATE_MCAST: |
| 2557 | RAY_DPRINTF(sc, RAY_DBG_COM, "UPDATE_MCAST"); |
| 2558 | ray_mcast_done(sc, status, ccs); |
| 2559 | break; |
| 2560 | |
| 2561 | case RAY_CMD_START_NET: |
| 2562 | case RAY_CMD_JOIN_NET: |
| 2563 | RAY_DPRINTF(sc, RAY_DBG_COM, "START|JOIN_NET"); |
| 2564 | ray_init_sj_done(sc, status, ccs); |
| 2565 | break; |
| 2566 | |
| 2567 | case RAY_CMD_TX_REQ: |
| 2568 | RAY_DPRINTF(sc, RAY_DBG_COM, "TX_REQ"); |
| 2569 | ray_tx_done(sc, status, ccs); |
| 2570 | break; |
| 2571 | |
| 2572 | case RAY_CMD_START_ASSOC: |
| 2573 | RAY_DPRINTF(sc, RAY_DBG_COM, "START_ASSOC"); |
| 2574 | ray_init_assoc_done(sc, status, ccs); |
| 2575 | break; |
| 2576 | |
| 2577 | case RAY_CMD_UPDATE_APM: |
| 2578 | RAY_RECERR(sc, "unexpected UPDATE_APM"); |
| 2579 | break; |
| 2580 | |
| 2581 | case RAY_CMD_TEST_MEM: |
| 2582 | RAY_RECERR(sc, "unexpected TEST_MEM"); |
| 2583 | break; |
| 2584 | |
| 2585 | case RAY_CMD_SHUTDOWN: |
| 2586 | RAY_RECERR(sc, "unexpected SHUTDOWN"); |
| 2587 | break; |
| 2588 | |
| 2589 | case RAY_CMD_DUMP_MEM: |
| 2590 | RAY_RECERR(sc, "unexpected DUMP_MEM"); |
| 2591 | break; |
| 2592 | |
| 2593 | case RAY_CMD_START_TIMER: |
| 2594 | RAY_RECERR(sc, "unexpected START_TIMER"); |
| 2595 | break; |
| 2596 | |
| 2597 | default: |
| 2598 | RAY_RECERR(sc, "unknown command 0x%x", cmd); |
| 2599 | break; |
| 2600 | } |
| 2601 | } |
| 2602 | |
| 2603 | /* |
| 2604 | * Process ECF command request |
| 2605 | */ |
| 2606 | static void |
| 2607 | ray_intr_rcs(struct ray_softc *sc, u_int8_t cmd, size_t rcs) |
| 2608 | { |
| 2609 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2610 | |
| 2611 | switch (cmd) { |
| 2612 | |
| 2613 | case RAY_ECMD_RX_DONE: |
| 2614 | RAY_DPRINTF(sc, RAY_DBG_RX, "RX_DONE"); |
| 2615 | ray_rx(sc, rcs); |
| 2616 | break; |
| 2617 | |
| 2618 | case RAY_ECMD_REJOIN_DONE: |
| 2619 | RAY_DPRINTF(sc, RAY_DBG_RX, "REJOIN_DONE"); |
| 2620 | sc->sc_c.np_havenet = 1; /* XXX Should not be here but in function */ |
| 2621 | break; |
| 2622 | |
| 2623 | case RAY_ECMD_ROAM_START: |
| 2624 | RAY_DPRINTF(sc, RAY_DBG_RX, "ROAM_START"); |
| 2625 | sc->sc_c.np_havenet = 0; /* XXX Should not be here but in function */ |
| 2626 | break; |
| 2627 | |
| 2628 | case RAY_ECMD_JAPAN_CALL_SIGNAL: |
| 2629 | RAY_RECERR(sc, "unexpected JAPAN_CALL_SIGNAL"); |
| 2630 | break; |
| 2631 | |
| 2632 | default: |
| 2633 | RAY_RECERR(sc, "unknown command 0x%x", cmd); |
| 2634 | break; |
| 2635 | } |
| 2636 | |
| 2637 | RAY_CCS_FREE(sc, rcs); |
| 2638 | } |
| 2639 | |
| 2640 | /* |
| 2641 | * User land entry to multicast list changes |
| 2642 | */ |
| 2643 | static int |
| 2644 | ray_mcast_user(struct ray_softc *sc) |
| 2645 | { |
| 2646 | struct ray_comq_entry *com[2]; |
| 2647 | int error, ncom; |
| 2648 | |
| 2649 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2650 | |
| 2651 | /* |
| 2652 | * Do all checking in the runq to preserve ordering. |
| 2653 | * |
| 2654 | * We run promisc to pick up changes to the ALL_MULTI |
| 2655 | * interface flag. |
| 2656 | */ |
| 2657 | ncom = 0; |
| 2658 | com[ncom++] = RAY_COM_MALLOC(ray_mcast, 0); |
| 2659 | com[ncom++] = RAY_COM_MALLOC(ray_promisc, 0); |
| 2660 | |
| 2661 | RAY_COM_RUNQ(sc, com, ncom, "raymcast", error); |
| 2662 | |
| 2663 | /* XXX no real error processing from anything yet! */ |
| 2664 | |
| 2665 | RAY_COM_FREE(com, ncom); |
| 2666 | |
| 2667 | return (error); |
| 2668 | } |
| 2669 | |
| 2670 | /* |
| 2671 | * Runq entry to setting the multicast filter list |
| 2672 | * |
| 2673 | * MUST always be followed by a call to ray_promisc to pick up changes |
| 2674 | * to promisc flag |
| 2675 | */ |
| 2676 | static void |
| 2677 | ray_mcast(struct ray_softc *sc, struct ray_comq_entry *com) |
| 2678 | { |
| 2679 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 2680 | struct ifmultiaddr *ifma; |
| 2681 | size_t bufp; |
| 2682 | int count = 0; |
| 2683 | |
| 2684 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2685 | RAY_MAP_CM(sc); |
| 2686 | |
| 2687 | /* |
| 2688 | * If card is not running we don't need to update this. |
| 2689 | */ |
| 2690 | if (!(ifp->if_flags & IFF_RUNNING)) { |
| 2691 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, "not running"); |
| 2692 | ray_com_runq_done(sc); |
| 2693 | return; |
| 2694 | } |
| 2695 | |
| 2696 | /* |
| 2697 | * The multicast list is only 16 items long so use promiscuous |
| 2698 | * mode and don't bother updating the multicast list. |
| 2699 | */ |
| 2700 | for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; |
| 2701 | ifma = ifma->ifma_link.le_next) |
| 2702 | count++; |
| 2703 | if (count == 0) { |
| 2704 | ray_com_runq_done(sc); |
| 2705 | return; |
| 2706 | } else if (count > 16) { |
| 2707 | ifp->if_flags |= IFF_ALLMULTI; |
| 2708 | ray_com_runq_done(sc); |
| 2709 | return; |
| 2710 | } else if (ifp->if_flags & IFF_ALLMULTI) |
| 2711 | ifp->if_flags &= ~IFF_ALLMULTI; |
| 2712 | |
| 2713 | /* |
| 2714 | * Kick the card |
| 2715 | */ |
| 2716 | ray_ccs_fill(sc, com->c_ccs, RAY_CMD_UPDATE_MCAST); |
| 2717 | SRAM_WRITE_FIELD_1(sc, com->c_ccs, |
| 2718 | ray_cmd_update_mcast, c_nmcast, count); |
| 2719 | bufp = RAY_HOST_TO_ECF_BASE; |
| 2720 | for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; |
| 2721 | ifma = ifma->ifma_link.le_next) { |
| 2722 | SRAM_WRITE_REGION( |
| 2723 | sc, |
| 2724 | bufp, |
| 2725 | LLADDR((struct sockaddr_dl *)ifma->ifma_addr), |
| 2726 | ETHER_ADDR_LEN |
| 2727 | ); |
| 2728 | bufp += ETHER_ADDR_LEN; |
| 2729 | } |
| 2730 | |
| 2731 | ray_com_ecf(sc, com); |
| 2732 | } |
| 2733 | |
| 2734 | /* |
| 2735 | * Complete the multicast filter list update |
| 2736 | */ |
| 2737 | static void |
| 2738 | ray_mcast_done(struct ray_softc *sc, u_int8_t status, size_t ccs) |
| 2739 | { |
| 2740 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, ""); |
| 2741 | RAY_COM_CHECK(sc, ccs); |
| 2742 | |
| 2743 | RAY_CCSERR(sc, status, if_oerrors); /* XXX error counter */ |
| 2744 | |
| 2745 | ray_com_ecf_done(sc); |
| 2746 | } |
| 2747 | |
| 2748 | /* |
| 2749 | * Runq entry to set/reset promiscuous mode |
| 2750 | */ |
| 2751 | static void |
| 2752 | ray_promisc(struct ray_softc *sc, struct ray_comq_entry *com) |
| 2753 | { |
| 2754 | struct ifnet *ifp = &sc->arpcom.ac_if; |
| 2755 | |
| 2756 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2757 | RAY_MAP_CM(sc); |
| 2758 | |
| 2759 | /* |
| 2760 | * If card not running or we already have the right flags |
| 2761 | * we don't need to update this |
| 2762 | */ |
| 2763 | sc->sc_d.np_promisc = !!(ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)); |
| 2764 | if (!(ifp->if_flags & IFF_RUNNING) || |
| 2765 | (sc->sc_c.np_promisc == sc->sc_d.np_promisc)) { |
| 2766 | ray_com_runq_done(sc); |
| 2767 | return; |
| 2768 | } |
| 2769 | |
| 2770 | /* |
| 2771 | * Kick the card |
| 2772 | */ |
| 2773 | ray_ccs_fill(sc, com->c_ccs, RAY_CMD_UPDATE_PARAMS); |
| 2774 | SRAM_WRITE_FIELD_1(sc, com->c_ccs, |
| 2775 | ray_cmd_update, c_paramid, RAY_MIB_PROMISC); |
| 2776 | SRAM_WRITE_FIELD_1(sc, com->c_ccs, ray_cmd_update, c_nparam, 1); |
| 2777 | SRAM_WRITE_1(sc, RAY_HOST_TO_ECF_BASE, sc->sc_d.np_promisc); |
| 2778 | |
| 2779 | ray_com_ecf(sc, com); |
| 2780 | } |
| 2781 | |
| 2782 | /* |
| 2783 | * User land entry to parameter reporting |
| 2784 | * |
| 2785 | * As we by pass the runq to report current parameters this function |
| 2786 | * only provides a snap shot of the driver's state. |
| 2787 | */ |
| 2788 | static int |
| 2789 | ray_repparams_user(struct ray_softc *sc, struct ray_param_req *pr) |
| 2790 | { |
| 2791 | struct ray_comq_entry *com[1]; |
| 2792 | int error, ncom; |
| 2793 | |
| 2794 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2795 | |
| 2796 | /* |
| 2797 | * Test for illegal values or immediate responses |
| 2798 | */ |
| 2799 | if (pr->r_paramid > RAY_MIB_MAX) |
| 2800 | return (EINVAL); |
| 2801 | if ((sc->sc_version == RAY_ECFS_BUILD_4) && |
| 2802 | !(mib_info[pr->r_paramid][0] & RAY_V4)) |
| 2803 | return (EINVAL); |
| 2804 | if ((sc->sc_version == RAY_ECFS_BUILD_5) && |
| 2805 | !(mib_info[pr->r_paramid][0] & RAY_V5)) |
| 2806 | return (EINVAL); |
| 2807 | if (pr->r_paramid > RAY_MIB_LASTUSER) { |
| 2808 | switch (pr->r_paramid) { |
| 2809 | |
| 2810 | case RAY_MIB_VERSION: |
| 2811 | if (sc->sc_version == RAY_ECFS_BUILD_4) |
| 2812 | *pr->r_data = RAY_V4; |
| 2813 | else |
| 2814 | *pr->r_data = RAY_V5; |
| 2815 | break; |
| 2816 | case RAY_MIB_CUR_BSSID: |
| 2817 | bcopy(sc->sc_c.np_bss_id, pr->r_data, ETHER_ADDR_LEN); |
| 2818 | break; |
| 2819 | case RAY_MIB_CUR_INITED: |
| 2820 | *pr->r_data = sc->sc_c.np_inited; |
| 2821 | break; |
| 2822 | case RAY_MIB_CUR_DEF_TXRATE: |
| 2823 | *pr->r_data = sc->sc_c.np_def_txrate; |
| 2824 | break; |
| 2825 | case RAY_MIB_CUR_ENCRYPT: |
| 2826 | *pr->r_data = sc->sc_c.np_encrypt; |
| 2827 | break; |
| 2828 | case RAY_MIB_CUR_NET_TYPE: |
| 2829 | *pr->r_data = sc->sc_c.np_net_type; |
| 2830 | break; |
| 2831 | case RAY_MIB_CUR_SSID: |
| 2832 | bcopy(sc->sc_c.np_ssid, pr->r_data, IEEE80211_NWID_LEN); |
| 2833 | break; |
| 2834 | case RAY_MIB_CUR_PRIV_START: |
| 2835 | *pr->r_data = sc->sc_c.np_priv_start; |
| 2836 | break; |
| 2837 | case RAY_MIB_CUR_PRIV_JOIN: |
| 2838 | *pr->r_data = sc->sc_c.np_priv_join; |
| 2839 | break; |
| 2840 | case RAY_MIB_DES_BSSID: |
| 2841 | bcopy(sc->sc_d.np_bss_id, pr->r_data, ETHER_ADDR_LEN); |
| 2842 | break; |
| 2843 | case RAY_MIB_DES_INITED: |
| 2844 | *pr->r_data = sc->sc_d.np_inited; |
| 2845 | break; |
| 2846 | case RAY_MIB_DES_DEF_TXRATE: |
| 2847 | *pr->r_data = sc->sc_d.np_def_txrate; |
| 2848 | break; |
| 2849 | case RAY_MIB_DES_ENCRYPT: |
| 2850 | *pr->r_data = sc->sc_d.np_encrypt; |
| 2851 | break; |
| 2852 | case RAY_MIB_DES_NET_TYPE: |
| 2853 | *pr->r_data = sc->sc_d.np_net_type; |
| 2854 | break; |
| 2855 | case RAY_MIB_DES_SSID: |
| 2856 | bcopy(sc->sc_d.np_ssid, pr->r_data, IEEE80211_NWID_LEN); |
| 2857 | break; |
| 2858 | case RAY_MIB_DES_PRIV_START: |
| 2859 | *pr->r_data = sc->sc_d.np_priv_start; |
| 2860 | break; |
| 2861 | case RAY_MIB_DES_PRIV_JOIN: |
| 2862 | *pr->r_data = sc->sc_d.np_priv_join; |
| 2863 | break; |
| 2864 | case RAY_MIB_CUR_AP_STATUS: |
| 2865 | *pr->r_data = sc->sc_c.np_ap_status; |
| 2866 | break; |
| 2867 | case RAY_MIB_CUR_PROMISC: |
| 2868 | *pr->r_data = sc->sc_c.np_promisc; |
| 2869 | break; |
| 2870 | case RAY_MIB_DES_AP_STATUS: |
| 2871 | *pr->r_data = sc->sc_d.np_ap_status; |
| 2872 | break; |
| 2873 | case RAY_MIB_DES_PROMISC: |
| 2874 | *pr->r_data = sc->sc_d.np_promisc; |
| 2875 | break; |
| 2876 | case RAY_MIB_CUR_FRAMING: |
| 2877 | *pr->r_data = sc->sc_c.np_framing; |
| 2878 | break; |
| 2879 | case RAY_MIB_DES_FRAMING: |
| 2880 | *pr->r_data = sc->sc_d.np_framing; |
| 2881 | break; |
| 2882 | |
| 2883 | default: |
| 2884 | return (EINVAL); |
| 2885 | break; |
| 2886 | } |
| 2887 | pr->r_failcause = 0; |
| 2888 | if (sc->sc_version == RAY_ECFS_BUILD_4) |
| 2889 | pr->r_len = mib_info[pr->r_paramid][RAY_MIB_INFO_SIZ4]; |
| 2890 | else if (sc->sc_version == RAY_ECFS_BUILD_5) |
| 2891 | pr->r_len = mib_info[pr->r_paramid][RAY_MIB_INFO_SIZ5]; |
| 2892 | return (0); |
| 2893 | } |
| 2894 | |
| 2895 | pr->r_failcause = 0; |
| 2896 | ncom = 0; |
| 2897 | com[ncom++] = RAY_COM_MALLOC(ray_repparams, RAY_COM_FWOK); |
| 2898 | com[ncom-1]->c_pr = pr; |
| 2899 | |
| 2900 | RAY_COM_RUNQ(sc, com, ncom, "rayrparm", error); |
| 2901 | |
| 2902 | /* XXX no real error processing from anything yet! */ |
| 2903 | if (!com[0]->c_retval && pr->r_failcause) |
| 2904 | error = EINVAL; |
| 2905 | |
| 2906 | RAY_COM_FREE(com, ncom); |
| 2907 | |
| 2908 | return (error); |
| 2909 | } |
| 2910 | |
| 2911 | /* |
| 2912 | * Runq entry to read the required parameter |
| 2913 | * |
| 2914 | * The card and driver are happy for parameters to be read |
| 2915 | * whenever the card is plugged in |
| 2916 | */ |
| 2917 | static void |
| 2918 | ray_repparams(struct ray_softc *sc, struct ray_comq_entry *com) |
| 2919 | { |
| 2920 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2921 | RAY_MAP_CM(sc); |
| 2922 | |
| 2923 | /* |
| 2924 | * Kick the card |
| 2925 | */ |
| 2926 | ray_ccs_fill(sc, com->c_ccs, RAY_CMD_REPORT_PARAMS); |
| 2927 | SRAM_WRITE_FIELD_1(sc, com->c_ccs, |
| 2928 | ray_cmd_report, c_paramid, com->c_pr->r_paramid); |
| 2929 | SRAM_WRITE_FIELD_1(sc, com->c_ccs, ray_cmd_report, c_nparam, 1); |
| 2930 | |
| 2931 | ray_com_ecf(sc, com); |
| 2932 | } |
| 2933 | |
| 2934 | /* |
| 2935 | * Complete the parameter reporting |
| 2936 | */ |
| 2937 | static void |
| 2938 | ray_repparams_done(struct ray_softc *sc, u_int8_t status, size_t ccs) |
| 2939 | { |
| 2940 | struct ray_comq_entry *com; |
| 2941 | |
| 2942 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2943 | RAY_MAP_CM(sc); |
| 2944 | RAY_COM_CHECK(sc, ccs); |
| 2945 | |
| 2946 | RAY_CCSERR(sc, status, if_oerrors); /* XXX error counter */ |
| 2947 | |
| 2948 | com = TAILQ_FIRST(&sc->sc_comq); |
| 2949 | com->c_pr->r_failcause = |
| 2950 | SRAM_READ_FIELD_1(sc, ccs, ray_cmd_report, c_failcause); |
| 2951 | com->c_pr->r_len = |
| 2952 | SRAM_READ_FIELD_1(sc, ccs, ray_cmd_report, c_len); |
| 2953 | SRAM_READ_REGION(sc, RAY_ECF_TO_HOST_BASE, |
| 2954 | com->c_pr->r_data, com->c_pr->r_len); |
| 2955 | |
| 2956 | ray_com_ecf_done(sc); |
| 2957 | } |
| 2958 | |
| 2959 | /* |
| 2960 | * User land entry (and exit) to the error counters |
| 2961 | */ |
| 2962 | static int |
| 2963 | ray_repstats_user(struct ray_softc *sc, struct ray_stats_req *sr) |
| 2964 | { |
| 2965 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2966 | |
| 2967 | sr->rxoverflow = sc->sc_rxoverflow; |
| 2968 | sr->rxcksum = sc->sc_rxcksum; |
| 2969 | sr->rxhcksum = sc->sc_rxhcksum; |
| 2970 | sr->rxnoise = sc->sc_rxnoise; |
| 2971 | |
| 2972 | return (0); |
| 2973 | } |
| 2974 | |
| 2975 | /* |
| 2976 | * User land entry to parameter update changes |
| 2977 | * |
| 2978 | * As a parameter change can cause the network parameters to be |
| 2979 | * invalid we have to re-start/join. |
| 2980 | */ |
| 2981 | static int |
| 2982 | ray_upparams_user(struct ray_softc *sc, struct ray_param_req *pr) |
| 2983 | { |
| 2984 | struct ray_comq_entry *com[4]; |
| 2985 | int error, ncom, todo; |
| 2986 | #define RAY_UPP_SJ 0x1 |
| 2987 | #define RAY_UPP_PARAMS 0x2 |
| 2988 | |
| 2989 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 2990 | |
| 2991 | /* |
| 2992 | * Check that the parameter is available based on firmware version |
| 2993 | */ |
| 2994 | pr->r_failcause = 0; |
| 2995 | if (pr->r_paramid > RAY_MIB_LASTUSER) |
| 2996 | return (EINVAL); |
| 2997 | if ((sc->sc_version == RAY_ECFS_BUILD_4) && |
| 2998 | !(mib_info[pr->r_paramid][0] & RAY_V4)) |
| 2999 | return (EINVAL); |
| 3000 | if ((sc->sc_version == RAY_ECFS_BUILD_5) && |
| 3001 | !(mib_info[pr->r_paramid][0] & RAY_V5)) |
| 3002 | return (EINVAL); |
| 3003 | |
| 3004 | /* |
| 3005 | * Handle certain parameters specially |
| 3006 | */ |
| 3007 | todo = 0; |
| 3008 | switch (pr->r_paramid) { |
| 3009 | case RAY_MIB_NET_TYPE: /* Updated via START_NET JOIN_NET */ |
| 3010 | sc->sc_d.np_net_type = *pr->r_data; |
| 3011 | todo |= RAY_UPP_SJ; |
| 3012 | break; |
| 3013 | |
| 3014 | case RAY_MIB_SSID: /* Updated via START_NET JOIN_NET */ |
| 3015 | bcopy(pr->r_data, sc->sc_d.np_ssid, IEEE80211_NWID_LEN); |
| 3016 | todo |= RAY_UPP_SJ; |
| 3017 | break; |
| 3018 | |
| 3019 | case RAY_MIB_PRIVACY_MUST_START:/* Updated via START_NET */ |
| 3020 | if (sc->sc_c.np_net_type != RAY_MIB_NET_TYPE_ADHOC) |
| 3021 | return (EINVAL); |
| 3022 | sc->sc_d.np_priv_start = *pr->r_data; |
| 3023 | todo |= RAY_UPP_SJ; |
| 3024 | break; |
| 3025 | |
| 3026 | case RAY_MIB_PRIVACY_CAN_JOIN: /* Updated via START_NET JOIN_NET */ |
| 3027 | sc->sc_d.np_priv_join = *pr->r_data; |
| 3028 | todo |= RAY_UPP_SJ; |
| 3029 | break; |
| 3030 | |
| 3031 | case RAY_MIB_BASIC_RATE_SET: |
| 3032 | sc->sc_d.np_def_txrate = *pr->r_data; |
| 3033 | todo |= RAY_UPP_PARAMS; |
| 3034 | break; |
| 3035 | |
| 3036 | case RAY_MIB_AP_STATUS: /* Unsupported */ |
| 3037 | case RAY_MIB_MAC_ADDR: /* XXX Need interface up but could be done */ |
| 3038 | case RAY_MIB_PROMISC: /* BPF */ |
| 3039 | return (EINVAL); |
| 3040 | break; |
| 3041 | |
| 3042 | default: |
| 3043 | todo |= RAY_UPP_PARAMS; |
| 3044 | todo |= RAY_UPP_SJ; |
| 3045 | break; |
| 3046 | } |
| 3047 | |
| 3048 | /* |
| 3049 | * Generate the runq entries as needed |
| 3050 | */ |
| 3051 | ncom = 0; |
| 3052 | if (todo & RAY_UPP_PARAMS) { |
| 3053 | com[ncom++] = RAY_COM_MALLOC(ray_upparams, 0); |
| 3054 | com[ncom-1]->c_pr = pr; |
| 3055 | } |
| 3056 | if (todo & RAY_UPP_SJ) { |
| 3057 | com[ncom++] = RAY_COM_MALLOC(ray_init_sj, 0); |
| 3058 | com[ncom++] = RAY_COM_MALLOC(ray_init_auth, 0); |
| 3059 | com[ncom++] = RAY_COM_MALLOC(ray_init_assoc, 0); |
| 3060 | } |
| 3061 | |
| 3062 | RAY_COM_RUNQ(sc, com, ncom, "rayuparam", error); |
| 3063 | |
| 3064 | /* XXX no real error processing from anything yet! */ |
| 3065 | if (!com[0]->c_retval && pr->r_failcause) |
| 3066 | error = EINVAL; |
| 3067 | |
| 3068 | RAY_COM_FREE(com, ncom); |
| 3069 | |
| 3070 | return (error); |
| 3071 | } |
| 3072 | |
| 3073 | /* |
| 3074 | * Runq entry to update a parameter |
| 3075 | * |
| 3076 | * The card and driver are happy for parameters to be updated |
| 3077 | * whenever the card is plugged in |
| 3078 | * |
| 3079 | * XXX the above is a little bit of a lie until _download is sorted out and we |
| 3080 | * XXX keep local copies of things |
| 3081 | */ |
| 3082 | static void |
| 3083 | ray_upparams(struct ray_softc *sc, struct ray_comq_entry *com) |
| 3084 | { |
| 3085 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 3086 | RAY_MAP_CM(sc); |
| 3087 | |
| 3088 | ray_ccs_fill(sc, com->c_ccs, RAY_CMD_UPDATE_PARAMS); |
| 3089 | |
| 3090 | SRAM_WRITE_FIELD_1(sc, com->c_ccs, |
| 3091 | ray_cmd_update, c_paramid, com->c_pr->r_paramid); |
| 3092 | SRAM_WRITE_FIELD_1(sc, com->c_ccs, ray_cmd_update, c_nparam, 1); |
| 3093 | SRAM_WRITE_REGION(sc, RAY_HOST_TO_ECF_BASE, |
| 3094 | com->c_pr->r_data, com->c_pr->r_len); |
| 3095 | |
| 3096 | ray_com_ecf(sc, com); |
| 3097 | } |
| 3098 | |
| 3099 | /* |
| 3100 | * Complete the parameter update, note that promisc finishes up here too |
| 3101 | */ |
| 3102 | static void |
| 3103 | ray_upparams_done(struct ray_softc *sc, u_int8_t status, size_t ccs) |
| 3104 | { |
| 3105 | struct ray_comq_entry *com; |
| 3106 | |
| 3107 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 3108 | RAY_MAP_CM(sc); |
| 3109 | RAY_COM_CHECK(sc, ccs); |
| 3110 | |
| 3111 | RAY_CCSERR(sc, status, if_oerrors); /* XXX error counter */ |
| 3112 | |
| 3113 | com = TAILQ_FIRST(&sc->sc_comq); |
| 3114 | |
| 3115 | switch (SRAM_READ_FIELD_1(sc, ccs, ray_cmd_update, c_paramid)) { |
| 3116 | |
| 3117 | case RAY_MIB_PROMISC: |
| 3118 | sc->sc_c.np_promisc = SRAM_READ_1(sc, RAY_HOST_TO_ECF_BASE); |
| 3119 | RAY_DPRINTF(sc, RAY_DBG_IOCTL, |
| 3120 | "promisc value %d", sc->sc_c.np_promisc); |
| 3121 | break; |
| 3122 | |
| 3123 | default: |
| 3124 | com->c_pr->r_failcause = |
| 3125 | SRAM_READ_FIELD_1(sc, ccs, ray_cmd_update, c_failcause); |
| 3126 | break; |
| 3127 | |
| 3128 | } |
| 3129 | |
| 3130 | ray_com_ecf_done(sc); |
| 3131 | } |
| 3132 | |
| 3133 | /* |
| 3134 | * Command queuing and execution |
| 3135 | */ |
| 3136 | |
| 3137 | /* |
| 3138 | * Set up a comq entry struct |
| 3139 | */ |
| 3140 | static struct ray_comq_entry * |
| 3141 | ray_com_init(struct ray_comq_entry *com, ray_comqfn_t function, int flags, char *mesg) |
| 3142 | { |
| 3143 | com->c_function = function; |
| 3144 | com->c_flags = flags; |
| 3145 | com->c_retval = 0; |
| 3146 | com->c_ccs = NULL; |
| 3147 | com->c_wakeup = NULL; |
| 3148 | com->c_pr = NULL; |
| 3149 | com->c_mesg = mesg; |
| 3150 | |
| 3151 | return (com); |
| 3152 | } |
| 3153 | |
| 3154 | /* |
| 3155 | * Malloc and set up a comq entry struct |
| 3156 | */ |
| 3157 | static struct ray_comq_entry * |
| 3158 | ray_com_malloc(ray_comqfn_t function, int flags, char *mesg) |
| 3159 | { |
| 3160 | struct ray_comq_entry *com; |
| 3161 | |
| 3162 | MALLOC(com, struct ray_comq_entry *, |
| 3163 | sizeof(struct ray_comq_entry), M_RAYCOM, M_WAITOK); |
| 3164 | |
| 3165 | return (ray_com_init(com, function, flags, mesg)); |
| 3166 | } |
| 3167 | |
| 3168 | /* |
| 3169 | * Add an array of commands to the runq, get some ccs's for them and |
| 3170 | * then run, waiting on the last command. |
| 3171 | * |
| 3172 | * We add the commands to the queue first to preserve ioctl ordering. |
| 3173 | * |
| 3174 | * On recoverable errors, this routine removes the entries from the |
| 3175 | * runq. A caller can requeue the commands (and still preserve its own |
| 3176 | * processes ioctl ordering) but doesn't have to. When the card is |
| 3177 | * detached we get out quickly to prevent panics and don't bother |
| 3178 | * about the runq. |
| 3179 | */ |
| 3180 | static int |
| 3181 | ray_com_runq_add(struct ray_softc *sc, struct ray_comq_entry *com[], int ncom, char *wmesg) |
| 3182 | { |
| 3183 | int i, error; |
| 3184 | |
| 3185 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_COM, ""); |
| 3186 | |
| 3187 | error = 0; |
| 3188 | /* |
| 3189 | * Add the commands to the runq but don't let it run until |
| 3190 | * the ccs's are allocated successfully |
| 3191 | */ |
| 3192 | com[0]->c_flags |= RAY_COM_FWAIT; |
| 3193 | for (i = 0; i < ncom; i++) { |
| 3194 | com[i]->c_wakeup = com[ncom-1]; |
| 3195 | RAY_DPRINTF(sc, RAY_DBG_COM, "adding %p", com[i]); |
| 3196 | RAY_DCOM(sc, RAY_DBG_DCOM, com[i], "adding"); |
| 3197 | TAILQ_INSERT_TAIL(&sc->sc_comq, com[i], c_chain); |
| 3198 | } |
| 3199 | com[ncom-1]->c_flags |= RAY_COM_FWOK; |
| 3200 | |
| 3201 | /* |
| 3202 | * Allocate ccs's for each command. |
| 3203 | */ |
| 3204 | for (i = 0; i < ncom; i++) { |
| 3205 | error = ray_ccs_alloc(sc, &com[i]->c_ccs, wmesg); |
| 3206 | if (error == ENXIO) |
| 3207 | return (ENXIO); |
| 3208 | else if (error) |
| 3209 | goto cleanup; |
| 3210 | } |
| 3211 | |
| 3212 | /* |
| 3213 | * Allow the queue to run and sleep if needed. |
| 3214 | * |
| 3215 | * Iff the FDETACHED flag is set in the com entry we waited on |
| 3216 | * the driver is in a zombie state! The softc structure has been |
| 3217 | * freed by the generic bus detach methods - eek. We tread very |
| 3218 | * carefully! |
| 3219 | */ |
| 3220 | com[0]->c_flags &= ~RAY_COM_FWAIT; |
| 3221 | ray_com_runq(sc); |
| 3222 | if (TAILQ_FIRST(&sc->sc_comq) != NULL) { |
| 3223 | RAY_DPRINTF(sc, RAY_DBG_COM, "sleeping"); |
| 3224 | error = tsleep(com[ncom-1], PCATCH, wmesg, 0); |
| 3225 | if (com[ncom-1]->c_flags & RAY_COM_FDETACHED) |
| 3226 | return (ENXIO); |
| 3227 | RAY_DPRINTF(sc, RAY_DBG_COM, |
| 3228 | "awakened, tsleep returned 0x%x", error); |
| 3229 | } else |
| 3230 | error = 0; |
| 3231 | |
| 3232 | cleanup: |
| 3233 | /* |
| 3234 | * Only clean the queue on real errors - we don't care about it |
| 3235 | * when we detach as the queue entries are freed by the callers. |
| 3236 | */ |
| 3237 | if (error && (error != ENXIO)) |
| 3238 | for (i = 0; i < ncom; i++) |
| 3239 | if (!(com[i]->c_flags & RAY_COM_FCOMPLETED)) { |
| 3240 | RAY_DPRINTF(sc, RAY_DBG_COM, "removing %p", |
| 3241 | com[i]); |
| 3242 | RAY_DCOM(sc, RAY_DBG_DCOM, com[i], "removing"); |
| 3243 | TAILQ_REMOVE(&sc->sc_comq, com[i], c_chain); |
| 3244 | ray_ccs_free(sc, com[i]->c_ccs); |
| 3245 | com[i]->c_ccs = NULL; |
| 3246 | } |
| 3247 | |
| 3248 | return (error); |
| 3249 | } |
| 3250 | |
| 3251 | /* |
| 3252 | * Run the command at the head of the queue (if not already running) |
| 3253 | */ |
| 3254 | static void |
| 3255 | ray_com_runq(struct ray_softc *sc) |
| 3256 | { |
| 3257 | struct ray_comq_entry *com; |
| 3258 | |
| 3259 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_COM, ""); |
| 3260 | |
| 3261 | com = TAILQ_FIRST(&sc->sc_comq); |
| 3262 | if ((com == NULL) || |
| 3263 | (com->c_flags & RAY_COM_FRUNNING) || |
| 3264 | (com->c_flags & RAY_COM_FWAIT) || |
| 3265 | (com->c_flags & RAY_COM_FDETACHED)) |
| 3266 | return; |
| 3267 | |
| 3268 | com->c_flags |= RAY_COM_FRUNNING; |
| 3269 | RAY_DPRINTF(sc, RAY_DBG_COM, "running %p", com); |
| 3270 | RAY_DCOM(sc, RAY_DBG_DCOM, com, "running"); |
| 3271 | com->c_function(sc, com); |
| 3272 | } |
| 3273 | |
| 3274 | /* |
| 3275 | * Remove run command, free ccs and wakeup caller. |
| 3276 | * |
| 3277 | * Minimal checks are done here as we ensure that the com and command |
| 3278 | * handler were matched up earlier. Must be called at splnet or higher |
| 3279 | * so that entries on the command queue are correctly removed. |
| 3280 | * |
| 3281 | * Remove the com from the comq, and wakeup the caller if it requested |
| 3282 | * to be woken. This is used for ensuring a sequence of commands |
| 3283 | * completes. Finally, re-run the queue. |
| 3284 | */ |
| 3285 | static void |
| 3286 | ray_com_runq_done(struct ray_softc *sc) |
| 3287 | { |
| 3288 | struct ray_comq_entry *com; |
| 3289 | |
| 3290 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_COM, ""); |
| 3291 | |
| 3292 | com = TAILQ_FIRST(&sc->sc_comq); /* XXX shall we check this as below */ |
| 3293 | RAY_DPRINTF(sc, RAY_DBG_COM, "removing %p", com); |
| 3294 | RAY_DCOM(sc, RAY_DBG_DCOM, com, "removing"); |
| 3295 | TAILQ_REMOVE(&sc->sc_comq, com, c_chain); |
| 3296 | |
| 3297 | com->c_flags &= ~RAY_COM_FRUNNING; |
| 3298 | com->c_flags |= RAY_COM_FCOMPLETED; |
| 3299 | com->c_retval = 0; |
| 3300 | ray_ccs_free(sc, com->c_ccs); |
| 3301 | com->c_ccs = NULL; |
| 3302 | |
| 3303 | if (com->c_flags & RAY_COM_FWOK) |
| 3304 | wakeup(com->c_wakeup); |
| 3305 | |
| 3306 | ray_com_runq(sc); |
| 3307 | |
| 3308 | /* XXX what about error on completion then? deal with when i fix |
| 3309 | * XXX the status checking |
| 3310 | * |
| 3311 | * XXX all the runq_done calls from IFF_RUNNING checks in runq |
| 3312 | * XXX routines should return EIO but shouldn't abort the runq |
| 3313 | */ |
| 3314 | } |
| 3315 | |
| 3316 | /* |
| 3317 | * Send a command to the ECF. |
| 3318 | */ |
| 3319 | static void |
| 3320 | ray_com_ecf(struct ray_softc *sc, struct ray_comq_entry *com) |
| 3321 | { |
| 3322 | int i = 0; |
| 3323 | |
| 3324 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_COM, ""); |
| 3325 | RAY_MAP_CM(sc); |
| 3326 | |
| 3327 | while (!RAY_ECF_READY(sc)) { |
| 3328 | DELAY(RAY_ECF_SPIN_DELAY); |
| 3329 | if (++i > RAY_ECF_SPIN_TRIES) |
| 3330 | RAY_PANIC(sc, "spun too long"); |
| 3331 | } |
| 3332 | if (i != 0) |
| 3333 | RAY_RECERR(sc, "spun %d times", i); |
| 3334 | |
| 3335 | RAY_DPRINTF(sc, RAY_DBG_COM, "sending %p", com); |
| 3336 | RAY_DCOM(sc, RAY_DBG_DCOM, com, "sending"); |
| 3337 | SRAM_WRITE_1(sc, RAY_SCB_CCSI, RAY_CCS_INDEX(com->c_ccs)); |
| 3338 | RAY_ECF_START_CMD(sc); |
| 3339 | |
| 3340 | if (RAY_COM_NEEDS_TIMO( |
| 3341 | SRAM_READ_FIELD_1(sc, com->c_ccs, ray_cmd, c_cmd))) { |
| 3342 | RAY_DPRINTF(sc, RAY_DBG_COM, "adding timeout"); |
| 3343 | callout_reset(&sc->com_timer, RAY_COM_TIMEOUT, |
| 3344 | ray_com_ecf_timo, sc); |
| 3345 | } |
| 3346 | } |
| 3347 | |
| 3348 | /* |
| 3349 | * Deal with commands that require a timeout to test completion. |
| 3350 | * |
| 3351 | * This routine is coded to only expect one outstanding request for the |
| 3352 | * timed out requests at a time, but thats all that can be outstanding |
| 3353 | * per hardware limitations and all that we issue anyway. |
| 3354 | * |
| 3355 | * We don't do any fancy testing of the command currently issued as we |
| 3356 | * know it must be a timeout based one...unless I've got this wrong! |
| 3357 | */ |
| 3358 | static void |
| 3359 | ray_com_ecf_timo(void *xsc) |
| 3360 | { |
| 3361 | struct ray_softc *sc = (struct ray_softc *)xsc; |
| 3362 | struct ray_comq_entry *com; |
| 3363 | u_int8_t cmd, status; |
| 3364 | int s; |
| 3365 | |
| 3366 | s = splnet(); |
| 3367 | |
| 3368 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_COM, ""); |
| 3369 | RAY_MAP_CM(sc); |
| 3370 | |
| 3371 | com = TAILQ_FIRST(&sc->sc_comq); |
| 3372 | |
| 3373 | cmd = SRAM_READ_FIELD_1(sc, com->c_ccs, ray_cmd, c_cmd); |
| 3374 | status = SRAM_READ_FIELD_1(sc, com->c_ccs, ray_cmd, c_status); |
| 3375 | switch (status) { |
| 3376 | |
| 3377 | case RAY_CCS_STATUS_COMPLETE: |
| 3378 | case RAY_CCS_STATUS_FREE: /* Buggy firmware */ |
| 3379 | ray_intr_ccs(sc, cmd, status, com->c_ccs); |
| 3380 | break; |
| 3381 | |
| 3382 | case RAY_CCS_STATUS_BUSY: |
| 3383 | callout_reset(&sc->com_timer, RAY_COM_TIMEOUT, |
| 3384 | ray_com_ecf_timo, sc); |
| 3385 | break; |
| 3386 | |
| 3387 | default: /* Replicates NetBSD */ |
| 3388 | if (sc->sc_ccsinuse[RAY_CCS_INDEX(com->c_ccs)] == 1) { |
| 3389 | /* give a chance for the interrupt to occur */ |
| 3390 | sc->sc_ccsinuse[RAY_CCS_INDEX(com->c_ccs)] = 2; |
| 3391 | callout_reset(&sc->com_timer, RAY_COM_TIMEOUT, |
| 3392 | ray_com_ecf_timo, sc); |
| 3393 | } else |
| 3394 | ray_intr_ccs(sc, cmd, status, com->c_ccs); |
| 3395 | break; |
| 3396 | |
| 3397 | } |
| 3398 | |
| 3399 | splx(s); |
| 3400 | } |
| 3401 | |
| 3402 | /* |
| 3403 | * Called when interrupt handler for the command has done all it |
| 3404 | * needs to. Will be called at splnet. |
| 3405 | */ |
| 3406 | static void |
| 3407 | ray_com_ecf_done(struct ray_softc *sc) |
| 3408 | { |
| 3409 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_COM, ""); |
| 3410 | |
| 3411 | callout_stop(&sc->com_timer); |
| 3412 | |
| 3413 | ray_com_runq_done(sc); |
| 3414 | } |
| 3415 | |
| 3416 | #if RAY_DEBUG & RAY_DBG_COM |
| 3417 | /* |
| 3418 | * Process completed ECF commands that probably came from the command queue |
| 3419 | * |
| 3420 | * This routine is called after vectoring the completed ECF command |
| 3421 | * to the appropriate _done routine. It helps check everything is okay. |
| 3422 | */ |
| 3423 | static void |
| 3424 | ray_com_ecf_check(struct ray_softc *sc, size_t ccs, char *mesg) |
| 3425 | { |
| 3426 | struct ray_comq_entry *com; |
| 3427 | |
| 3428 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_COM, "%s", mesg); |
| 3429 | |
| 3430 | com = TAILQ_FIRST(&sc->sc_comq); |
| 3431 | |
| 3432 | if (com == NULL) |
| 3433 | RAY_PANIC(sc, "no command queue"); |
| 3434 | if (com->c_ccs != ccs) |
| 3435 | RAY_PANIC(sc, "ccs's don't match"); |
| 3436 | } |
| 3437 | #endif /* RAY_DEBUG & RAY_DBG_COM */ |
| 3438 | |
| 3439 | /* |
| 3440 | * CCS allocators |
| 3441 | */ |
| 3442 | |
| 3443 | /* |
| 3444 | * Obtain a ccs for a commmand |
| 3445 | * |
| 3446 | * Returns 0 and in `ccsp' the bus offset of the free ccs. Will block |
| 3447 | * awaiting free ccs if needed - if the sleep is interrupted |
| 3448 | * EINTR/ERESTART is returned, if the card is ejected we return ENXIO. |
| 3449 | */ |
| 3450 | static int |
| 3451 | ray_ccs_alloc(struct ray_softc *sc, size_t *ccsp, char *wmesg) |
| 3452 | { |
| 3453 | size_t ccs; |
| 3454 | u_int i; |
| 3455 | int error; |
| 3456 | |
| 3457 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CCS, ""); |
| 3458 | RAY_MAP_CM(sc); |
| 3459 | |
| 3460 | for (;;) { |
| 3461 | for (i = RAY_CCS_CMD_FIRST; i <= RAY_CCS_CMD_LAST; i++) { |
| 3462 | /* we probe here to make the card go */ |
| 3463 | (void)SRAM_READ_FIELD_1(sc, RAY_CCS_ADDRESS(i), ray_cmd, |
| 3464 | c_status); |
| 3465 | if (!sc->sc_ccsinuse[i]) |
| 3466 | break; |
| 3467 | } |
| 3468 | if (i > RAY_CCS_CMD_LAST) { |
| 3469 | RAY_DPRINTF(sc, RAY_DBG_CCS, "sleeping"); |
| 3470 | error = tsleep(ray_ccs_alloc, PCATCH, wmesg, 0); |
| 3471 | if ((sc == NULL) || (sc->sc_gone)) |
| 3472 | return (ENXIO); |
| 3473 | RAY_DPRINTF(sc, RAY_DBG_CCS, |
| 3474 | "awakened, tsleep returned 0x%x", error); |
| 3475 | if (error) |
| 3476 | return (error); |
| 3477 | } else |
| 3478 | break; |
| 3479 | } |
| 3480 | RAY_DPRINTF(sc, RAY_DBG_CCS, "allocated 0x%02x", i); |
| 3481 | sc->sc_ccsinuse[i] = 1; |
| 3482 | ccs = RAY_CCS_ADDRESS(i); |
| 3483 | *ccsp = ccs; |
| 3484 | |
| 3485 | return (0); |
| 3486 | } |
| 3487 | |
| 3488 | /* |
| 3489 | * Fill the easy bits in of a pre-allocated CCS |
| 3490 | */ |
| 3491 | static void |
| 3492 | ray_ccs_fill(struct ray_softc *sc, size_t ccs, u_int cmd) |
| 3493 | { |
| 3494 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CCS, ""); |
| 3495 | RAY_MAP_CM(sc); |
| 3496 | |
| 3497 | if (ccs == NULL) |
| 3498 | RAY_PANIC(sc, "ccs not allocated"); |
| 3499 | |
| 3500 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, RAY_CCS_STATUS_BUSY); |
| 3501 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_cmd, cmd); |
| 3502 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_link, RAY_CCS_LINK_NULL); |
| 3503 | } |
| 3504 | |
| 3505 | /* |
| 3506 | * Free up a ccs allocated via ray_ccs_alloc |
| 3507 | * |
| 3508 | * Return the old status. This routine is only used for ccs allocated via |
| 3509 | * ray_ccs_alloc (not tx, rx or ECF command requests). |
| 3510 | */ |
| 3511 | static void |
| 3512 | ray_ccs_free(struct ray_softc *sc, size_t ccs) |
| 3513 | { |
| 3514 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CCS, ""); |
| 3515 | RAY_MAP_CM(sc); |
| 3516 | |
| 3517 | #if 1 | (RAY_DEBUG & RAY_DBG_CCS) |
| 3518 | if (!sc->sc_ccsinuse[RAY_CCS_INDEX(ccs)]) |
| 3519 | RAY_RECERR(sc, "freeing free ccs 0x%02x", RAY_CCS_INDEX(ccs)); |
| 3520 | #endif /* RAY_DEBUG & RAY_DBG_CCS */ |
| 3521 | if (!sc->sc_gone) |
| 3522 | RAY_CCS_FREE(sc, ccs); |
| 3523 | sc->sc_ccsinuse[RAY_CCS_INDEX(ccs)] = 0; |
| 3524 | RAY_DPRINTF(sc, RAY_DBG_CCS, "freed 0x%02x", RAY_CCS_INDEX(ccs)); |
| 3525 | wakeup(ray_ccs_alloc); |
| 3526 | } |
| 3527 | |
| 3528 | /* |
| 3529 | * Obtain a ccs and tx buffer to transmit with and fill them in. |
| 3530 | * |
| 3531 | * Returns 0 and in `ccsp' the bus offset of the free ccs. Will not block |
| 3532 | * and if none available and will returns EAGAIN. |
| 3533 | * |
| 3534 | * The caller must fill in the length later. |
| 3535 | * The caller must clear the ccs on errors. |
| 3536 | */ |
| 3537 | static int |
| 3538 | ray_ccs_tx(struct ray_softc *sc, size_t *ccsp, size_t *bufpp) |
| 3539 | { |
| 3540 | size_t ccs, bufp; |
| 3541 | int i; |
| 3542 | u_int8_t status; |
| 3543 | |
| 3544 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CCS, ""); |
| 3545 | RAY_MAP_CM(sc); |
| 3546 | |
| 3547 | i = RAY_CCS_TX_FIRST; |
| 3548 | do { |
| 3549 | status = SRAM_READ_FIELD_1(sc, RAY_CCS_ADDRESS(i), |
| 3550 | ray_cmd, c_status); |
| 3551 | if (status == RAY_CCS_STATUS_FREE) |
| 3552 | break; |
| 3553 | i++; |
| 3554 | } while (i <= RAY_CCS_TX_LAST); |
| 3555 | if (i > RAY_CCS_TX_LAST) { |
| 3556 | return (EAGAIN); |
| 3557 | } |
| 3558 | RAY_DPRINTF(sc, RAY_DBG_CCS, "allocated 0x%02x", i); |
| 3559 | |
| 3560 | /* |
| 3561 | * Reserve and fill the ccs - must do the length later. |
| 3562 | * |
| 3563 | * Even though build 4 and build 5 have different fields all these |
| 3564 | * are common apart from tx_rate. Neither the NetBSD driver or Linux |
| 3565 | * driver bother to overwrite this for build 4 cards. |
| 3566 | * |
| 3567 | * The start of the buffer must be aligned to a 256 byte boundary |
| 3568 | * (least significant byte of address = 0x00). |
| 3569 | */ |
| 3570 | ccs = RAY_CCS_ADDRESS(i); |
| 3571 | bufp = RAY_TX_BASE + i * RAY_TX_BUF_SIZE; |
| 3572 | bufp += sc->sc_tibsize; |
| 3573 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_status, RAY_CCS_STATUS_BUSY); |
| 3574 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_cmd, RAY_CMD_TX_REQ); |
| 3575 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_link, RAY_CCS_LINK_NULL); |
| 3576 | SRAM_WRITE_FIELD_2(sc, ccs, ray_cmd_tx, c_bufp, bufp); |
| 3577 | SRAM_WRITE_FIELD_1(sc, |
| 3578 | ccs, ray_cmd_tx, c_tx_rate, sc->sc_c.np_def_txrate); |
| 3579 | SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_apm_mode, 0); |
| 3580 | bufp += sizeof(struct ray_tx_phy_header); |
| 3581 | |
| 3582 | *ccsp = ccs; |
| 3583 | *bufpp = bufp; |
| 3584 | return (0); |
| 3585 | } |
| 3586 | |
| 3587 | /* |
| 3588 | * Routines to obtain resources for the card |
| 3589 | */ |
| 3590 | |
| 3591 | /* |
| 3592 | * Allocate the attribute memory on the card |
| 3593 | * |
| 3594 | * The attribute memory space is abused by these devices as IO space. As such |
| 3595 | * the OS card services don't have a chance of knowing that they need to keep |
| 3596 | * the attribute space mapped. We have to do it manually. |
| 3597 | */ |
| 3598 | static int |
| 3599 | ray_res_alloc_am(struct ray_softc *sc) |
| 3600 | { |
| 3601 | int error; |
| 3602 | |
| 3603 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CM, ""); |
| 3604 | |
| 3605 | sc->am_rid = RAY_AM_RID; |
| 3606 | sc->am_res = bus_alloc_resource(sc->dev, SYS_RES_MEMORY, |
| 3607 | &sc->am_rid, 0UL, ~0UL, 0x1000, RF_ACTIVE); |
| 3608 | if (!sc->am_res) { |
| 3609 | RAY_PRINTF(sc, "Cannot allocate attribute memory"); |
| 3610 | return (ENOMEM); |
| 3611 | } |
| 3612 | error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->dev), sc->dev, |
| 3613 | sc->am_rid, 0, NULL); |
| 3614 | if (error) { |
| 3615 | RAY_PRINTF(sc, "CARD_SET_MEMORY_OFFSET returned 0x%0x", error); |
| 3616 | return (error); |
| 3617 | } |
| 3618 | error = CARD_SET_RES_FLAGS(device_get_parent(sc->dev), sc->dev, |
| 3619 | SYS_RES_MEMORY, sc->am_rid, PCCARD_A_MEM_ATTR); |
| 3620 | if (error) { |
| 3621 | RAY_PRINTF(sc, "CARD_SET_RES_FLAGS returned 0x%0x", error); |
| 3622 | return (error); |
| 3623 | } |
| 3624 | error = CARD_SET_RES_FLAGS(device_get_parent(sc->dev), sc->dev, |
| 3625 | SYS_RES_MEMORY, sc->am_rid, PCCARD_A_MEM_8BIT); |
| 3626 | if (error) { |
| 3627 | RAY_PRINTF(sc, "CARD_SET_RES_FLAGS returned 0x%0x", error); |
| 3628 | return (error); |
| 3629 | } |
| 3630 | sc->am_bsh = rman_get_bushandle(sc->am_res); |
| 3631 | sc->am_bst = rman_get_bustag(sc->am_res); |
| 3632 | |
| 3633 | #if RAY_DEBUG & (RAY_DBG_CM | RAY_DBG_BOOTPARAM) |
| 3634 | { |
| 3635 | u_long flags; |
| 3636 | u_int32_t offset; |
| 3637 | CARD_GET_RES_FLAGS(device_get_parent(sc->dev), sc->dev, |
| 3638 | SYS_RES_MEMORY, sc->am_rid, &flags); |
| 3639 | CARD_GET_MEMORY_OFFSET(device_get_parent(sc->dev), sc->dev, |
| 3640 | sc->am_rid, &offset); |
| 3641 | RAY_PRINTF(sc, "allocated attribute memory:\n" |
| 3642 | ". start 0x%0lx count 0x%0lx flags 0x%0lx offset 0x%0x", |
| 3643 | bus_get_resource_start(sc->dev, SYS_RES_MEMORY, sc->am_rid), |
| 3644 | bus_get_resource_count(sc->dev, SYS_RES_MEMORY, sc->am_rid), |
| 3645 | flags, offset); |
| 3646 | } |
| 3647 | #endif /* RAY_DEBUG & (RAY_DBG_CM | RAY_DBG_BOOTPARAM) */ |
| 3648 | |
| 3649 | return (0); |
| 3650 | } |
| 3651 | |
| 3652 | /* |
| 3653 | * Allocate the common memory on the card |
| 3654 | * |
| 3655 | * As this memory is described in the CIS, the OS card services should |
| 3656 | * have set the map up okay, but the card uses 8 bit RAM. This is not |
| 3657 | * described in the CIS. |
| 3658 | */ |
| 3659 | static int |
| 3660 | ray_res_alloc_cm(struct ray_softc *sc) |
| 3661 | { |
| 3662 | u_long start, count, end; |
| 3663 | int error; |
| 3664 | |
| 3665 | RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CM, ""); |
| 3666 | |
| 3667 | RAY_DPRINTF(sc,RAY_DBG_CM | RAY_DBG_BOOTPARAM, |
| 3668 | "cm start 0x%0lx count 0x%0lx", |
| 3669 | bus_get_resource_start(sc->dev, SYS_RES_MEMORY, RAY_CM_RID), |
| 3670 | bus_get_resource_count(sc->dev, SYS_RES_MEMORY, RAY_CM_RID)); |
| 3671 | |
| 3672 | sc->cm_rid = RAY_CM_RID; |
| 3673 | start = bus_get_resource_start(sc->dev, SYS_RES_MEMORY, sc->cm_rid); |
| 3674 | count = bus_get_resource_count(sc->dev, SYS_RES_MEMORY, sc->cm_rid); |
| 3675 | end = start + count - 1; |
| 3676 | sc->cm_res = bus_alloc_resource(sc->dev, SYS_RES_MEMORY, |
| 3677 | &sc->cm_rid, start, end, count, RF_ACTIVE); |
| 3678 | if (!sc->cm_res) { |
| 3679 | RAY_PRINTF(sc, "Cannot allocate common memory"); |
| 3680 | return (ENOMEM); |
| 3681 | } |
| 3682 | error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->dev), sc->dev, |
| 3683 | sc->cm_rid, 0, NULL); |
| 3684 | if (error) { |
| 3685 | RAY_PRINTF(sc, "CARD_SET_MEMORY_OFFSET returned 0x%0x", error); |
| 3686 | return (error); |
| 3687 | } |
| 3688 | error = CARD_SET_RES_FLAGS(device_get_parent(sc->dev), sc->dev, |
| 3689 | SYS_RES_MEMORY, sc->cm_rid, PCCARD_A_MEM_COM); |
| 3690 | if (error) { |
| 3691 | RAY_PRINTF(sc, "CARD_SET_RES_FLAGS returned 0x%0x", error); |
| 3692 | return (error); |
| 3693 | } |
| 3694 | error = CARD_SET_RES_FLAGS(device_get_parent(sc->dev), sc->dev, |
| 3695 | SYS_RES_MEMORY, sc->cm_rid, PCCARD_A_MEM_8BIT); |
| 3696 | if (error) { |
| 3697 | RAY_PRINTF(sc, "CARD_SET_RES_FLAGS returned 0x%0x", error); |
| 3698 | return (error); |
| 3699 | } |
| 3700 | sc->cm_bsh = rman_get_bushandle(sc->cm_res); |
| 3701 | sc->cm_bst = rman_get_bustag(sc->cm_res); |
| 3702 | |
| 3703 | #if RAY_DEBUG & (RAY_DBG_CM | RAY_DBG_BOOTPARAM) |
| 3704 | { |
| 3705 | u_long flags; |
| 3706 | u_int32_t offset; |
| 3707 | CARD_GET_RES_FLAGS(device_get_parent(sc->dev), sc->dev, |
| 3708 | SYS_RES_MEMORY, sc->cm_rid, &flags); |
| 3709 | CARD_GET_MEMORY_OFFSET(device_get_parent(sc->dev), sc->dev, |
| 3710 | sc->cm_rid, &offset); |
| 3711 | RAY_PRINTF(sc, "allocated common memory:\n" |
| 3712 | ". start 0x%0lx count 0x%0lx flags 0x%0lx offset 0x%0x", |
| 3713 | bus_get_resource_start(sc->dev, SYS_RES_MEMORY, sc->cm_rid), |
| 3714 | bus_get_resource_count(sc->dev, SYS_RES_MEMORY, sc->cm_rid), |
| 3715 | flags, offset); |
| 3716 | } |
| 3717 | #endif /* RAY_DEBUG & (RAY_DBG_CM | RAY_DBG_BOOTPARAM) */ |
| 3718 | |
| 3719 | return (0); |
| 3720 | } |
| 3721 | |
| 3722 | /* |
| 3723 | * Get an irq and attach it to the bus |
| 3724 | */ |
| 3725 | static int |
| 3726 | ray_res_alloc_irq(struct ray_softc *sc) |
| 3727 | { |
| 3728 | int error; |
| 3729 | |
| 3730 | RAY_DPRINTF(sc, RAY_DBG_SUBR, ""); |
| 3731 | |
| 3732 | RAY_DPRINTF(sc,RAY_DBG_CM | RAY_DBG_BOOTPARAM, |
| 3733 | "irq start 0x%0lx count 0x%0lx", |
| 3734 | bus_get_resource_start(sc->dev, SYS_RES_IRQ, 0), |
| 3735 | bus_get_resource_count(sc->dev, SYS_RES_IRQ, 0)); |
| 3736 | |
| 3737 | sc->irq_rid = 0; |
| 3738 | sc->irq_res = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irq_rid, |
| 3739 | 0, ~0, 1, RF_ACTIVE); |
| 3740 | if (!sc->irq_res) { |
| 3741 | RAY_PRINTF(sc, "Cannot allocate irq"); |
| 3742 | return (ENOMEM); |
| 3743 | } |
| 3744 | if ((error = bus_setup_intr(sc->dev, sc->irq_res, INTR_TYPE_NET, |
| 3745 | ray_intr, sc, &sc->irq_handle)) != 0) { |
| 3746 | RAY_PRINTF(sc, "Failed to setup irq"); |
| 3747 | return (error); |
| 3748 | } |
| 3749 | RAY_DPRINTF(sc, RAY_DBG_CM | RAY_DBG_BOOTPARAM, "allocated irq:\n" |
| 3750 | ". start 0x%0lx count 0x%0lx", |
| 3751 | bus_get_resource_start(sc->dev, SYS_RES_IRQ, sc->irq_rid), |
| 3752 | bus_get_resource_count(sc->dev, SYS_RES_IRQ, sc->irq_rid)); |
| 3753 | |
| 3754 | return (0); |
| 3755 | } |
| 3756 | |
| 3757 | /* |
| 3758 | * Release all of the card's resources |
| 3759 | */ |
| 3760 | static void |
| 3761 | ray_res_release(struct ray_softc *sc) |
| 3762 | { |
| 3763 | if (sc->irq_res != 0) { |
| 3764 | bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handle); |
| 3765 | bus_release_resource(sc->dev, SYS_RES_IRQ, |
| 3766 | sc->irq_rid, sc->irq_res); |
| 3767 | sc->irq_res = 0; |
| 3768 | } |
| 3769 | if (sc->am_res != 0) { |
| 3770 | bus_release_resource(sc->dev, SYS_RES_MEMORY, |
| 3771 | sc->am_rid, sc->am_res); |
| 3772 | sc->am_res = 0; |
| 3773 | } |
| 3774 | if (sc->cm_res != 0) { |
| 3775 | bus_release_resource(sc->dev, SYS_RES_MEMORY, |
| 3776 | sc->cm_rid, sc->cm_res); |
| 3777 | sc->cm_res = 0; |
| 3778 | } |
| 3779 | } |
| 3780 | |
| 3781 | /* |
| 3782 | * mbuf dump |
| 3783 | */ |
| 3784 | #if RAY_DEBUG & RAY_DBG_MBUF |
| 3785 | static void |
| 3786 | ray_dump_mbuf(struct ray_softc *sc, struct mbuf *m, char *s) |
| 3787 | { |
| 3788 | u_int8_t *d, *ed; |
| 3789 | u_int i; |
| 3790 | char p[17]; |
| 3791 | |
| 3792 | RAY_PRINTF(sc, "%s", s); |
| 3793 | RAY_PRINTF(sc, "\nm0->data\t0x%p\nm_pkthdr.len\t%d\nm_len\t%d", |
| 3794 | mtod(m, u_int8_t *), m->m_pkthdr.len, m->m_len); |
| 3795 | i = 0; |
| 3796 | bzero(p, 17); |
| 3797 | for (; m; m = m->m_next) { |
| 3798 | d = mtod(m, u_int8_t *); |
| 3799 | ed = d + m->m_len; |
| 3800 | |
| 3801 | for (; d < ed; i++, d++) { |
| 3802 | if ((i % 16) == 0) { |
| 3803 | printf(" %s\n\t", p); |
| 3804 | } else if ((i % 8) == 0) |
| 3805 | printf(" "); |
| 3806 | printf(" %02x", *d); |
| 3807 | p[i % 16] = ((*d >= 0x20) && (*d < 0x80)) ? *d : '.'; |
| 3808 | } |
| 3809 | } |
| 3810 | if ((i - 1) % 16) |
| 3811 | printf(" %s\n", p); |
| 3812 | } |
| 3813 | #endif /* RAY_DEBUG & RAY_DBG_MBUF */ |