if_an.c revision 74698
1/* 2 * Copyright (c) 1997, 1998, 1999 3 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * $FreeBSD: head/sys/dev/an/if_an.c 74698 2001-03-23 17:46:32Z archie $ 33 */ 34 35/* 36 * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD. 37 * 38 * Written by Bill Paul <wpaul@ctr.columbia.edu> 39 * Electrical Engineering Department 40 * Columbia University, New York City 41 */ 42 43/* 44 * The Aironet 4500/4800 series cards some in PCMCIA, ISA and PCI form. 45 * This driver supports all three device types (PCI devices are supported 46 * through an extra PCI shim: /sys/pci/if_an_p.c). ISA devices can be 47 * supported either using hard-coded IO port/IRQ settings or via Plug 48 * and Play. The 4500 series devices support 1Mbps and 2Mbps data rates. 49 * The 4800 devices support 1, 2, 5.5 and 11Mbps rates. 50 * 51 * Like the WaveLAN/IEEE cards, the Aironet NICs are all essentially 52 * PCMCIA devices. The ISA and PCI cards are a combination of a PCMCIA 53 * device and a PCMCIA to ISA or PCMCIA to PCI adapter card. There are 54 * a couple of important differences though: 55 * 56 * - Lucent doesn't currently offer a PCI card, however Aironet does 57 * - Lucent ISA card looks to the host like a PCMCIA controller with 58 * a PCMCIA WaveLAN card inserted. This means that even desktop 59 * machines need to be configured with PCMCIA support in order to 60 * use WaveLAN/IEEE ISA cards. The Aironet cards on the other hand 61 * actually look like normal ISA and PCI devices to the host, so 62 * no PCMCIA controller support is needed 63 * 64 * The latter point results in a small gotcha. The Aironet PCMCIA 65 * cards can be configured for one of two operating modes depending 66 * on how the Vpp1 and Vpp2 programming voltages are set when the 67 * card is activated. In order to put the card in proper PCMCIA 68 * operation (where the CIS table is visible and the interface is 69 * programmed for PCMCIA operation), both Vpp1 and Vpp2 have to be 70 * set to 5 volts. FreeBSD by default doesn't set the Vpp voltages, 71 * which leaves the card in ISA/PCI mode, which prevents it from 72 * being activated as an PCMCIA device. Consequently, /sys/pccard/pccard.c 73 * has to be patched slightly in order to enable the Vpp voltages in 74 * order to make the Aironet PCMCIA cards work. 75 * 76 * Note that some PCMCIA controller software packages for Windows NT 77 * fail to set the voltages as well. 78 * 79 * The Aironet devices can operate in both station mode and access point 80 * mode. Typically, when programmed for station mode, the card can be set 81 * to automatically perform encapsulation/decapsulation of Ethernet II 82 * and 802.3 frames within 802.11 frames so that the host doesn't have 83 * to do it itself. This driver doesn't program the card that way: the 84 * driver handles all of the encapsulation/decapsulation itself. 85 */ 86 87#include "opt_inet.h" 88 89#ifdef INET 90#define ANCACHE /* enable signal strength cache */ 91#endif 92 93#include <sys/param.h> 94#include <sys/systm.h> 95#include <sys/sockio.h> 96#include <sys/mbuf.h> 97#include <sys/kernel.h> 98#include <sys/socket.h> 99#ifdef ANCACHE 100#include <sys/syslog.h> 101#include <sys/sysctl.h> 102#endif 103 104#include <sys/module.h> 105#include <sys/bus.h> 106#include <machine/bus.h> 107#include <sys/rman.h> 108#include <sys/mutex.h> 109#include <machine/resource.h> 110 111#include <net/if.h> 112#include <net/if_arp.h> 113#include <net/ethernet.h> 114#include <net/if_dl.h> 115#include <net/if_types.h> 116 117#ifdef INET 118#include <netinet/in.h> 119#include <netinet/in_systm.h> 120#include <netinet/in_var.h> 121#include <netinet/ip.h> 122#endif 123 124#include <net/bpf.h> 125 126#include <machine/md_var.h> 127 128#include <dev/an/if_aironet_ieee.h> 129#include <dev/an/if_anreg.h> 130 131#if !defined(lint) 132static const char rcsid[] = 133 "$FreeBSD: head/sys/dev/an/if_an.c 74698 2001-03-23 17:46:32Z archie $"; 134#endif 135 136/* These are global because we need them in sys/pci/if_an_p.c. */ 137static void an_reset __P((struct an_softc *)); 138static int an_ioctl __P((struct ifnet *, u_long, caddr_t)); 139static void an_init __P((void *)); 140static int an_init_tx_ring __P((struct an_softc *)); 141static void an_start __P((struct ifnet *)); 142static void an_watchdog __P((struct ifnet *)); 143static void an_rxeof __P((struct an_softc *)); 144static void an_txeof __P((struct an_softc *, int)); 145 146static void an_promisc __P((struct an_softc *, int)); 147static int an_cmd __P((struct an_softc *, int, int)); 148static int an_read_record __P((struct an_softc *, struct an_ltv_gen *)); 149static int an_write_record __P((struct an_softc *, struct an_ltv_gen *)); 150static int an_read_data __P((struct an_softc *, int, 151 int, caddr_t, int)); 152static int an_write_data __P((struct an_softc *, int, 153 int, caddr_t, int)); 154static int an_seek __P((struct an_softc *, int, int, int)); 155static int an_alloc_nicmem __P((struct an_softc *, int, int *)); 156static void an_stats_update __P((void *)); 157static void an_setdef __P((struct an_softc *, struct an_req *)); 158#ifdef ANCACHE 159static void an_cache_store __P((struct an_softc *, struct ether_header *, 160 struct mbuf *, unsigned short)); 161#endif 162 163/* 164 * We probe for an Aironet 4500/4800 card by attempting to 165 * read the default SSID list. On reset, the first entry in 166 * the SSID list will contain the name "tsunami." If we don't 167 * find this, then there's no card present. 168 */ 169int an_probe(dev) 170 device_t dev; 171{ 172 struct an_softc *sc = device_get_softc(dev); 173 struct an_ltv_ssidlist ssid; 174 int error; 175 176 bzero((char *)&ssid, sizeof(ssid)); 177 178 error = an_alloc_port(dev, 0, AN_IOSIZ); 179 if (error) 180 return (0); 181 182 /* can't do autoprobing */ 183 if (rman_get_start(sc->port_res) == -1) 184 return(0); 185 186 /* 187 * We need to fake up a softc structure long enough 188 * to be able to issue commands and call some of the 189 * other routines. 190 */ 191 sc->an_bhandle = rman_get_bushandle(sc->port_res); 192 sc->an_btag = rman_get_bustag(sc->port_res); 193 sc->an_unit = device_get_unit(dev); 194 195 ssid.an_len = sizeof(ssid); 196 ssid.an_type = AN_RID_SSIDLIST; 197 198 /* Make sure interrupts are disabled. */ 199 CSR_WRITE_2(sc, AN_INT_EN, 0); 200 CSR_WRITE_2(sc, AN_EVENT_ACK, 0xFFFF); 201 202 an_reset(sc); 203 204 if (an_cmd(sc, AN_CMD_READCFG, 0)) 205 return(0); 206 207 if (an_read_record(sc, (struct an_ltv_gen *)&ssid)) 208 return(0); 209 210 /* See if the ssid matches what we expect ... but doesn't have to */ 211 if (strcmp(ssid.an_ssid1, AN_DEF_SSID)) 212 return(0); 213 214 return(AN_IOSIZ); 215} 216 217/* 218 * Allocate a port resource with the given resource id. 219 */ 220int 221an_alloc_port(dev, rid, size) 222 device_t dev; 223 int rid; 224 int size; 225{ 226 struct an_softc *sc = device_get_softc(dev); 227 struct resource *res; 228 229 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 230 0ul, ~0ul, size, RF_ACTIVE); 231 if (res) { 232 sc->port_rid = rid; 233 sc->port_res = res; 234 return (0); 235 } else { 236 return (ENOENT); 237 } 238} 239 240/* 241 * Allocate an irq resource with the given resource id. 242 */ 243int 244an_alloc_irq(dev, rid, flags) 245 device_t dev; 246 int rid; 247 int flags; 248{ 249 struct an_softc *sc = device_get_softc(dev); 250 struct resource *res; 251 252 res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 253 0ul, ~0ul, 1, (RF_ACTIVE | flags)); 254 if (res) { 255 sc->irq_rid = rid; 256 sc->irq_res = res; 257 return (0); 258 } else { 259 return (ENOENT); 260 } 261} 262 263/* 264 * Release all resources 265 */ 266void 267an_release_resources(dev) 268 device_t dev; 269{ 270 struct an_softc *sc = device_get_softc(dev); 271 272 if (sc->port_res) { 273 bus_release_resource(dev, SYS_RES_IOPORT, 274 sc->port_rid, sc->port_res); 275 sc->port_res = 0; 276 } 277 if (sc->irq_res) { 278 bus_release_resource(dev, SYS_RES_IRQ, 279 sc->irq_rid, sc->irq_res); 280 sc->irq_res = 0; 281 } 282} 283 284int an_attach(sc, unit, flags) 285 struct an_softc *sc; 286 int unit; 287 int flags; 288{ 289 struct ifnet *ifp = &sc->arpcom.ac_if; 290 291 mtx_init(&sc->an_mtx, device_get_nameunit(sc->an_dev), MTX_DEF | 292 MTX_RECURSE); 293 AN_LOCK(sc); 294 295 sc->an_gone = 0; 296 sc->an_associated = 0; 297 298 /* Reset the NIC. */ 299 an_reset(sc); 300 301 /* Load factory config */ 302 if (an_cmd(sc, AN_CMD_READCFG, 0)) { 303 printf("an%d: failed to load config data\n", sc->an_unit); 304 AN_UNLOCK(sc); 305 mtx_destroy(&sc->an_mtx); 306 return(EIO); 307 } 308 309 /* Read the current configuration */ 310 sc->an_config.an_type = AN_RID_GENCONFIG; 311 sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 312 if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 313 printf("an%d: read record failed\n", sc->an_unit); 314 AN_UNLOCK(sc); 315 mtx_destroy(&sc->an_mtx); 316 return(EIO); 317 } 318 319 /* Read the card capabilities */ 320 sc->an_caps.an_type = AN_RID_CAPABILITIES; 321 sc->an_caps.an_len = sizeof(struct an_ltv_caps); 322 if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) { 323 printf("an%d: read record failed\n", sc->an_unit); 324 AN_UNLOCK(sc); 325 mtx_destroy(&sc->an_mtx); 326 return(EIO); 327 } 328 329 /* Read ssid list */ 330 sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 331 sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist); 332 if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 333 printf("an%d: read record failed\n", sc->an_unit); 334 AN_UNLOCK(sc); 335 mtx_destroy(&sc->an_mtx); 336 return(EIO); 337 } 338 339 /* Read AP list */ 340 sc->an_aplist.an_type = AN_RID_APLIST; 341 sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 342 if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 343 printf("an%d: read record failed\n", sc->an_unit); 344 AN_UNLOCK(sc); 345 mtx_destroy(&sc->an_mtx); 346 return(EIO); 347 } 348 349 bcopy((char *)&sc->an_caps.an_oemaddr, 350 (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 351 352 printf("an%d: Ethernet address: %6D\n", sc->an_unit, 353 sc->arpcom.ac_enaddr, ":"); 354 355 ifp->if_softc = sc; 356 ifp->if_unit = sc->an_unit = unit; 357 ifp->if_name = "an"; 358 ifp->if_mtu = ETHERMTU; 359 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 360 ifp->if_ioctl = an_ioctl; 361 ifp->if_output = ether_output; 362 ifp->if_start = an_start; 363 ifp->if_watchdog = an_watchdog; 364 ifp->if_init = an_init; 365 ifp->if_baudrate = 10000000; 366 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 367 368 bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename)); 369 bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename, 370 sizeof(AN_DEFAULT_NODENAME) - 1); 371 372 bzero(sc->an_ssidlist.an_ssid1, sizeof(sc->an_ssidlist.an_ssid1)); 373 bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_ssid1, 374 sizeof(AN_DEFAULT_NETNAME) - 1); 375 sc->an_ssidlist.an_ssid1_len = strlen(AN_DEFAULT_NETNAME); 376 377 sc->an_config.an_opmode = 378 AN_OPMODE_INFRASTRUCTURE_STATION; 379 380 sc->an_tx_rate = 0; 381 bzero((char *)&sc->an_stats, sizeof(sc->an_stats)); 382 383 /* 384 * Call MI attach routine. 385 */ 386 ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 387 callout_handle_init(&sc->an_stat_ch); 388 AN_UNLOCK(sc); 389 390 return(0); 391} 392 393static void an_rxeof(sc) 394 struct an_softc *sc; 395{ 396 struct ifnet *ifp; 397 struct ether_header *eh; 398#ifdef ANCACHE 399 struct an_rxframe rx_frame; 400#endif 401 struct an_rxframe_802_3 rx_frame_802_3; 402 struct mbuf *m; 403 int id, error = 0; 404 405 ifp = &sc->arpcom.ac_if; 406 407 id = CSR_READ_2(sc, AN_RX_FID); 408 409 MGETHDR(m, M_DONTWAIT, MT_DATA); 410 if (m == NULL) { 411 ifp->if_ierrors++; 412 return; 413 } 414 MCLGET(m, M_DONTWAIT); 415 if (!(m->m_flags & M_EXT)) { 416 m_freem(m); 417 ifp->if_ierrors++; 418 return; 419 } 420 421 m->m_pkthdr.rcvif = ifp; 422 423 eh = mtod(m, struct ether_header *); 424 425#ifdef ANCACHE 426 /* Read NIC frame header */ 427 if (an_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) { 428 ifp->if_ierrors++; 429 return; 430 } 431#endif 432 /* Read in the 802_3 frame header */ 433 if (an_read_data(sc, id, 0x34, (caddr_t)&rx_frame_802_3, 434 sizeof(rx_frame_802_3))) { 435 ifp->if_ierrors++; 436 return; 437 } 438 439 if (rx_frame_802_3.an_rx_802_3_status != 0) { 440 ifp->if_ierrors++; 441 return; 442 } 443 444 /* Check for insane frame length */ 445 if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) { 446 ifp->if_ierrors++; 447 return; 448 } 449 450 m->m_pkthdr.len = m->m_len = 451 rx_frame_802_3.an_rx_802_3_payload_len + 12; 452 453 454 bcopy((char *)&rx_frame_802_3.an_rx_dst_addr, 455 (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 456 bcopy((char *)&rx_frame_802_3.an_rx_src_addr, 457 (char *)&eh->ether_shost, ETHER_ADDR_LEN); 458 459 /* in mbuf header type is just before payload */ 460 error = an_read_data(sc, id, 0x44, (caddr_t)&(eh->ether_type), 461 rx_frame_802_3.an_rx_802_3_payload_len); 462 463 if (error) { 464 m_freem(m); 465 ifp->if_ierrors++; 466 return; 467 } 468 469 ifp->if_ipackets++; 470 471 /* Receive packet. */ 472 m_adj(m, sizeof(struct ether_header)); 473#ifdef ANCACHE 474 an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength); 475#endif 476 ether_input(ifp, eh, m); 477} 478 479static void an_txeof(sc, status) 480 struct an_softc *sc; 481 int status; 482{ 483 struct ifnet *ifp; 484 int id; 485 486 /* TX DONE enable lan monitor DJA 487 an_enable_sniff(); 488 */ 489 490 ifp = &sc->arpcom.ac_if; 491 492 ifp->if_timer = 0; 493 ifp->if_flags &= ~IFF_OACTIVE; 494 495 id = CSR_READ_2(sc, AN_TX_CMP_FID); 496 497 if (status & AN_EV_TX_EXC) { 498 ifp->if_oerrors++; 499 } else 500 ifp->if_opackets++; 501 502 if (id != sc->an_rdata.an_tx_ring[sc->an_rdata.an_tx_cons]) 503 printf("an%d: id mismatch: expected %x, got %x\n", 504 sc->an_unit, 505 sc->an_rdata.an_tx_ring[sc->an_rdata.an_tx_cons], id); 506 507 sc->an_rdata.an_tx_ring[sc->an_rdata.an_tx_cons] = 0; 508 AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT); 509 510 return; 511} 512 513/* 514 * We abuse the stats updater to check the current NIC status. This 515 * is important because we don't want to allow transmissions until 516 * the NIC has synchronized to the current cell (either as the master 517 * in an ad-hoc group, or as a station connected to an access point). 518 */ 519void an_stats_update(xsc) 520 void *xsc; 521{ 522 struct an_softc *sc; 523 struct ifnet *ifp; 524 525 sc = xsc; 526 AN_LOCK(sc); 527 ifp = &sc->arpcom.ac_if; 528 529 sc->an_status.an_type = AN_RID_STATUS; 530 sc->an_status.an_len = sizeof(struct an_ltv_status); 531 an_read_record(sc, (struct an_ltv_gen *)&sc->an_status); 532 533 if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC) 534 sc->an_associated = 1; 535 else 536 sc->an_associated = 0; 537 538 /* Don't do this while we're transmitting */ 539 if (ifp->if_flags & IFF_OACTIVE) { 540 sc->an_stat_ch = timeout(an_stats_update, sc, hz); 541 AN_UNLOCK(sc); 542 return; 543 } 544 545 sc->an_stats.an_len = sizeof(struct an_ltv_stats); 546 sc->an_stats.an_type = AN_RID_32BITS_CUM; 547 an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len); 548 549 sc->an_stat_ch = timeout(an_stats_update, sc, hz); 550 AN_UNLOCK(sc); 551 552 return; 553} 554 555void an_intr(xsc) 556 void *xsc; 557{ 558 struct an_softc *sc; 559 struct ifnet *ifp; 560 u_int16_t status; 561 562 sc = (struct an_softc*)xsc; 563 564 AN_LOCK(sc); 565 566 if (sc->an_gone) { 567 AN_UNLOCK(sc); 568 return; 569 } 570 571 ifp = &sc->arpcom.ac_if; 572 573 /* Disable interrupts. */ 574 CSR_WRITE_2(sc, AN_INT_EN, 0); 575 576 status = CSR_READ_2(sc, AN_EVENT_STAT); 577 CSR_WRITE_2(sc, AN_EVENT_ACK, ~AN_INTRS); 578 579 if (status & AN_EV_AWAKE) { 580 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_AWAKE); 581 } 582 583 if (status & AN_EV_LINKSTAT) { 584 if (CSR_READ_2(sc, AN_LINKSTAT) == AN_LINKSTAT_ASSOCIATED) 585 sc->an_associated = 1; 586 else 587 sc->an_associated = 0; 588 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT); 589 } 590 591 if (status & AN_EV_RX) { 592 an_rxeof(sc); 593 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX); 594 } 595 596 if (status & AN_EV_TX) { 597 an_txeof(sc, status); 598 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX); 599 } 600 601 if (status & AN_EV_TX_EXC) { 602 an_txeof(sc, status); 603 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX_EXC); 604 } 605 606 if (status & AN_EV_ALLOC) 607 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC); 608 609 /* Re-enable interrupts. */ 610 CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS); 611 612 if ((ifp->if_flags & IFF_UP) && (ifp->if_snd.ifq_head != NULL)) 613 an_start(ifp); 614 615 AN_UNLOCK(sc); 616 617 return; 618} 619 620static int an_cmd(sc, cmd, val) 621 struct an_softc *sc; 622 int cmd; 623 int val; 624{ 625 int i, s = 0; 626 627 CSR_WRITE_2(sc, AN_PARAM0, val); 628 CSR_WRITE_2(sc, AN_PARAM1, 0); 629 CSR_WRITE_2(sc, AN_PARAM2, 0); 630 CSR_WRITE_2(sc, AN_COMMAND, cmd); 631 632 for (i = 0; i < AN_TIMEOUT; i++) { 633 if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD) 634 break; 635 else { 636 if (CSR_READ_2(sc, AN_COMMAND) == cmd) 637 CSR_WRITE_2(sc, AN_COMMAND, cmd); 638 } 639 } 640 641 for (i = 0; i < AN_TIMEOUT; i++) { 642 CSR_READ_2(sc, AN_RESP0); 643 CSR_READ_2(sc, AN_RESP1); 644 CSR_READ_2(sc, AN_RESP2); 645 s = CSR_READ_2(sc, AN_STATUS); 646 if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE)) 647 break; 648 } 649 650 /* Ack the command */ 651 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD); 652 653 if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) 654 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY); 655 656 if (i == AN_TIMEOUT) 657 return(ETIMEDOUT); 658 659 return(0); 660} 661 662/* 663 * This reset sequence may look a little strange, but this is the 664 * most reliable method I've found to really kick the NIC in the 665 * head and force it to reboot correctly. 666 */ 667static void an_reset(sc) 668 struct an_softc *sc; 669{ 670 if (sc->an_gone) 671 return; 672 673 an_cmd(sc, AN_CMD_ENABLE, 0); 674 an_cmd(sc, AN_CMD_FW_RESTART, 0); 675 an_cmd(sc, AN_CMD_NOOP2, 0); 676 677 if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) 678 printf("an%d: reset failed\n", sc->an_unit); 679 680 an_cmd(sc, AN_CMD_DISABLE, 0); 681 682 return; 683} 684 685/* 686 * Read an LTV record from the NIC. 687 */ 688static int an_read_record(sc, ltv) 689 struct an_softc *sc; 690 struct an_ltv_gen *ltv; 691{ 692 u_int16_t *ptr; 693 int i, len; 694 695 if (ltv->an_len == 0 || ltv->an_type == 0) 696 return(EINVAL); 697 698 /* Tell the NIC to enter record read mode. */ 699 if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) { 700 printf("an%d: RID access failed\n", sc->an_unit); 701 return(EIO); 702 } 703 704 /* Seek to the record. */ 705 if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) { 706 printf("an%d: seek to record failed\n", sc->an_unit); 707 return(EIO); 708 } 709 710 /* 711 * Read the length and record type and make sure they 712 * match what we expect (this verifies that we have enough 713 * room to hold all of the returned data). 714 */ 715 len = CSR_READ_2(sc, AN_DATA1); 716 if (len > ltv->an_len) { 717 printf("an%d: record length mismatch -- expected %d, " 718 "got %d\n", sc->an_unit, ltv->an_len, len); 719 return(ENOSPC); 720 } 721 722 ltv->an_len = len; 723 724 /* Now read the data. */ 725 ptr = <v->an_val; 726 for (i = 0; i < (ltv->an_len - 2) >> 1; i++) 727 ptr[i] = CSR_READ_2(sc, AN_DATA1); 728 729 return(0); 730} 731 732/* 733 * Same as read, except we inject data instead of reading it. 734 */ 735static int an_write_record(sc, ltv) 736 struct an_softc *sc; 737 struct an_ltv_gen *ltv; 738{ 739 u_int16_t *ptr; 740 int i; 741 742 if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) 743 return(EIO); 744 745 if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) 746 return(EIO); 747 748 CSR_WRITE_2(sc, AN_DATA1, ltv->an_len-2); 749 750 ptr = <v->an_val; 751 for (i = 0; i < (ltv->an_len - 4) >> 1; i++) 752 CSR_WRITE_2(sc, AN_DATA1, ptr[i]); 753 754 if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type)) 755 return(EIO); 756 757 return(0); 758} 759 760static int an_seek(sc, id, off, chan) 761 struct an_softc *sc; 762 int id, off, chan; 763{ 764 int i; 765 int selreg, offreg; 766 767 switch (chan) { 768 case AN_BAP0: 769 selreg = AN_SEL0; 770 offreg = AN_OFF0; 771 break; 772 case AN_BAP1: 773 selreg = AN_SEL1; 774 offreg = AN_OFF1; 775 break; 776 default: 777 printf("an%d: invalid data path: %x\n", sc->an_unit, chan); 778 return(EIO); 779 } 780 781 CSR_WRITE_2(sc, selreg, id); 782 CSR_WRITE_2(sc, offreg, off); 783 784 for (i = 0; i < AN_TIMEOUT; i++) { 785 if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR))) 786 break; 787 } 788 789 if (i == AN_TIMEOUT) 790 return(ETIMEDOUT); 791 792 return(0); 793} 794 795static int an_read_data(sc, id, off, buf, len) 796 struct an_softc *sc; 797 int id, off; 798 caddr_t buf; 799 int len; 800{ 801 int i; 802 u_int16_t *ptr; 803 u_int8_t *ptr2; 804 805 if (off != -1) { 806 if (an_seek(sc, id, off, AN_BAP1)) 807 return(EIO); 808 } 809 810 ptr = (u_int16_t *)buf; 811 for (i = 0; i < len / 2; i++) 812 ptr[i] = CSR_READ_2(sc, AN_DATA1); 813 i*=2; 814 if (i<len){ 815 ptr2 = (u_int8_t *)buf; 816 ptr2[i] = CSR_READ_1(sc, AN_DATA1); 817 } 818 819 return(0); 820} 821 822static int an_write_data(sc, id, off, buf, len) 823 struct an_softc *sc; 824 int id, off; 825 caddr_t buf; 826 int len; 827{ 828 int i; 829 u_int16_t *ptr; 830 u_int8_t *ptr2; 831 832 if (off != -1) { 833 if (an_seek(sc, id, off, AN_BAP0)) 834 return(EIO); 835 } 836 837 ptr = (u_int16_t *)buf; 838 for (i = 0; i < (len / 2); i++) 839 CSR_WRITE_2(sc, AN_DATA0, ptr[i]); 840 i*=2; 841 if (i<len){ 842 ptr2 = (u_int8_t *)buf; 843 CSR_WRITE_1(sc, AN_DATA0, ptr2[i]); 844 } 845 846 return(0); 847} 848 849/* 850 * Allocate a region of memory inside the NIC and zero 851 * it out. 852 */ 853static int an_alloc_nicmem(sc, len, id) 854 struct an_softc *sc; 855 int len; 856 int *id; 857{ 858 int i; 859 860 if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) { 861 printf("an%d: failed to allocate %d bytes on NIC\n", 862 sc->an_unit, len); 863 return(ENOMEM); 864 } 865 866 for (i = 0; i < AN_TIMEOUT; i++) { 867 if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC) 868 break; 869 } 870 871 if (i == AN_TIMEOUT) 872 return(ETIMEDOUT); 873 874 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC); 875 *id = CSR_READ_2(sc, AN_ALLOC_FID); 876 877 if (an_seek(sc, *id, 0, AN_BAP0)) 878 return(EIO); 879 880 for (i = 0; i < len / 2; i++) 881 CSR_WRITE_2(sc, AN_DATA0, 0); 882 883 return(0); 884} 885 886static void an_setdef(sc, areq) 887 struct an_softc *sc; 888 struct an_req *areq; 889{ 890 struct sockaddr_dl *sdl; 891 struct ifaddr *ifa; 892 struct ifnet *ifp; 893 struct an_ltv_genconfig *cfg; 894 struct an_ltv_ssidlist *ssid; 895 struct an_ltv_aplist *ap; 896 struct an_ltv_gen *sp; 897 898 ifp = &sc->arpcom.ac_if; 899 900 switch (areq->an_type) { 901 case AN_RID_GENCONFIG: 902 cfg = (struct an_ltv_genconfig *)areq; 903 904 ifa = ifnet_addrs[ifp->if_index - 1]; 905 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 906 bcopy((char *)&cfg->an_macaddr, (char *)&sc->arpcom.ac_enaddr, 907 ETHER_ADDR_LEN); 908 bcopy((char *)&cfg->an_macaddr, LLADDR(sdl), ETHER_ADDR_LEN); 909 910 bcopy((char *)cfg, (char *)&sc->an_config, 911 sizeof(struct an_ltv_genconfig)); 912 break; 913 case AN_RID_SSIDLIST: 914 ssid = (struct an_ltv_ssidlist *)areq; 915 bcopy((char *)ssid, (char *)&sc->an_ssidlist, 916 sizeof(struct an_ltv_ssidlist)); 917 break; 918 case AN_RID_APLIST: 919 ap = (struct an_ltv_aplist *)areq; 920 bcopy((char *)ap, (char *)&sc->an_aplist, 921 sizeof(struct an_ltv_aplist)); 922 break; 923 case AN_RID_TX_SPEED: 924 sp = (struct an_ltv_gen *)areq; 925 sc->an_tx_rate = sp->an_val; 926 break; 927 case AN_RID_WEP_TEMP: 928 /* Disable the MAC. */ 929 an_cmd(sc, AN_CMD_DISABLE, 0); 930 931 /* Just write the Key, we don't want to save it */ 932 an_write_record(sc, (struct an_ltv_gen *)areq); 933 934 /* Turn the MAC back on. */ 935 an_cmd(sc, AN_CMD_ENABLE, 0); 936 937 break; 938 case AN_RID_WEP_PERM: 939 940 /* Disable the MAC. */ 941 an_cmd(sc, AN_CMD_DISABLE, 0); 942 943 /* Just write the Key, the card will save it in this mode */ 944 an_write_record(sc, (struct an_ltv_gen *)areq); 945 946 /* Turn the MAC back on. */ 947 an_cmd(sc, AN_CMD_ENABLE, 0); 948 949 break; 950 default: 951 printf("an%d: unknown RID: %x\n", sc->an_unit, areq->an_type); 952 return; 953 break; 954 } 955 956 957 /* Reinitialize the card. */ 958 if (ifp->if_flags) 959 an_init(sc); 960 961 return; 962} 963 964/* 965 * We can't change the NIC configuration while the MAC is enabled, 966 * so in order to turn on RX monitor mode, we have to turn the MAC 967 * off first. 968 */ 969static void an_promisc(sc, promisc) 970 struct an_softc *sc; 971 int promisc; 972{ 973 an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0); 974 975 return; 976} 977 978static int an_ioctl(ifp, command, data) 979 struct ifnet *ifp; 980 u_long command; 981 caddr_t data; 982{ 983 int error = 0; 984 struct an_softc *sc; 985 struct an_req areq; 986 struct ifreq *ifr; 987 struct proc *p = curproc; 988 989 sc = ifp->if_softc; 990 AN_LOCK(sc); 991 ifr = (struct ifreq *)data; 992 993 if (sc->an_gone) { 994 error = ENODEV; 995 goto out; 996 } 997 998 switch(command) { 999 case SIOCSIFADDR: 1000 case SIOCGIFADDR: 1001 case SIOCSIFMTU: 1002 error = ether_ioctl(ifp, command, data); 1003 break; 1004 case SIOCSIFFLAGS: 1005 if (ifp->if_flags & IFF_UP) { 1006 if (ifp->if_flags & IFF_RUNNING && 1007 ifp->if_flags & IFF_PROMISC && 1008 !(sc->an_if_flags & IFF_PROMISC)) { 1009 an_promisc(sc, 1); 1010 } else if (ifp->if_flags & IFF_RUNNING && 1011 !(ifp->if_flags & IFF_PROMISC) && 1012 sc->an_if_flags & IFF_PROMISC) { 1013 an_promisc(sc, 0); 1014 } else 1015 an_init(sc); 1016 } else { 1017 if (ifp->if_flags & IFF_RUNNING) 1018 an_stop(sc); 1019 } 1020 sc->an_if_flags = ifp->if_flags; 1021 error = 0; 1022 break; 1023 case SIOCADDMULTI: 1024 case SIOCDELMULTI: 1025 /* The Aironet has no multicast filter. */ 1026 error = 0; 1027 break; 1028 case SIOCGAIRONET: 1029 error = copyin(ifr->ifr_data, &areq, sizeof(areq)); 1030 if (error) 1031 break; 1032#ifdef ANCACHE 1033 if (areq.an_type == AN_RID_ZERO_CACHE) { 1034 sc->an_sigitems = sc->an_nextitem = 0; 1035 break; 1036 } else if (areq.an_type == AN_RID_READ_CACHE) { 1037 char *pt = (char *)&areq.an_val; 1038 bcopy((char *)&sc->an_sigitems, (char *)pt, 1039 sizeof(int)); 1040 pt += sizeof(int); 1041 areq.an_len = sizeof(int) / 2; 1042 bcopy((char *)&sc->an_sigcache, (char *)pt, 1043 sizeof(struct an_sigcache) * sc->an_sigitems); 1044 areq.an_len += ((sizeof(struct an_sigcache) * 1045 sc->an_sigitems) / 2) + 1; 1046 } else 1047#endif 1048 if (an_read_record(sc, (struct an_ltv_gen *)&areq)) { 1049 error = EINVAL; 1050 break; 1051 } 1052 error = copyout(&areq, ifr->ifr_data, sizeof(areq)); 1053 break; 1054 case SIOCSAIRONET: 1055 if ((error = suser(p))) 1056 goto out; 1057 error = copyin(ifr->ifr_data, &areq, sizeof(areq)); 1058 if (error) 1059 break; 1060 an_setdef(sc, &areq); 1061 break; 1062 default: 1063 error = EINVAL; 1064 break; 1065 } 1066out: 1067 AN_UNLOCK(sc); 1068 1069 return(error); 1070} 1071 1072static int an_init_tx_ring(sc) 1073 struct an_softc *sc; 1074{ 1075 int i; 1076 int id; 1077 1078 if (sc->an_gone) 1079 return (0); 1080 1081 for (i = 0; i < AN_TX_RING_CNT; i++) { 1082 if (an_alloc_nicmem(sc, 1518 + 1083 0x44, &id)) 1084 return(ENOMEM); 1085 sc->an_rdata.an_tx_fids[i] = id; 1086 sc->an_rdata.an_tx_ring[i] = 0; 1087 } 1088 1089 sc->an_rdata.an_tx_prod = 0; 1090 sc->an_rdata.an_tx_cons = 0; 1091 1092 return(0); 1093} 1094 1095static void an_init(xsc) 1096 void *xsc; 1097{ 1098 struct an_softc *sc = xsc; 1099 struct ifnet *ifp = &sc->arpcom.ac_if; 1100 1101 AN_LOCK(sc); 1102 1103 if (sc->an_gone) { 1104 AN_UNLOCK(sc); 1105 return; 1106 } 1107 1108 if (ifp->if_flags & IFF_RUNNING) 1109 an_stop(sc); 1110 1111 sc->an_associated = 0; 1112 1113 /* Allocate the TX buffers */ 1114 if (an_init_tx_ring(sc)) { 1115 an_reset(sc); 1116 if (an_init_tx_ring(sc)) { 1117 printf("an%d: tx buffer allocation " 1118 "failed\n", sc->an_unit); 1119 AN_UNLOCK(sc); 1120 return; 1121 } 1122 } 1123 1124 /* Set our MAC address. */ 1125 bcopy((char *)&sc->arpcom.ac_enaddr, 1126 (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN); 1127 1128 if (ifp->if_flags & IFF_BROADCAST) 1129 sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR; 1130 else 1131 sc->an_config.an_rxmode = AN_RXMODE_ADDR; 1132 1133 if (ifp->if_flags & IFF_MULTICAST) 1134 sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR; 1135 1136 /* Initialize promisc mode. */ 1137 /* Kills card DJA can't TX packet in sniff mode 1138 if (ifp->if_flags & IFF_PROMISC) 1139 sc->an_config.an_rxmode |= AN_RXMODE_LAN_MONITOR_CURBSS; 1140 */ 1141 1142 sc->an_rxmode = sc->an_config.an_rxmode; 1143 1144 /* Set the ssid list */ 1145 sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 1146 sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist); 1147 if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 1148 printf("an%d: failed to set ssid list\n", sc->an_unit); 1149 AN_UNLOCK(sc); 1150 return; 1151 } 1152 1153 /* Set the AP list */ 1154 sc->an_aplist.an_type = AN_RID_APLIST; 1155 sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 1156 if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 1157 printf("an%d: failed to set AP list\n", sc->an_unit); 1158 AN_UNLOCK(sc); 1159 return; 1160 } 1161 1162 /* Set the configuration in the NIC */ 1163 sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 1164 sc->an_config.an_type = AN_RID_GENCONFIG; 1165 if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 1166 printf("an%d: failed to set configuration\n", sc->an_unit); 1167 AN_UNLOCK(sc); 1168 return; 1169 } 1170 1171 /* Enable the MAC */ 1172 if (an_cmd(sc, AN_CMD_ENABLE, 0)) { 1173 printf("an%d: failed to enable MAC\n", sc->an_unit); 1174 AN_UNLOCK(sc); 1175 return; 1176 } 1177 1178 if (ifp->if_flags & IFF_PROMISC) 1179 an_cmd(sc, AN_CMD_SET_MODE, 0xffff); 1180 1181 /* enable interrupts */ 1182 CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS); 1183 1184 ifp->if_flags |= IFF_RUNNING; 1185 ifp->if_flags &= ~IFF_OACTIVE; 1186 1187 sc->an_stat_ch = timeout(an_stats_update, sc, hz); 1188 AN_UNLOCK(sc); 1189 1190 return; 1191} 1192 1193static void an_start(ifp) 1194 struct ifnet *ifp; 1195{ 1196 struct an_softc *sc; 1197 struct mbuf *m0 = NULL; 1198 struct an_txframe_802_3 tx_frame_802_3; 1199 struct ether_header *eh; 1200 int id; 1201 int idx; 1202 unsigned char txcontrol; 1203 1204 sc = ifp->if_softc; 1205 1206 if (sc->an_gone) 1207 return; 1208 1209 if (ifp->if_flags & IFF_OACTIVE) 1210 return; 1211 1212 if (!sc->an_associated) 1213 return; 1214 1215 idx = sc->an_rdata.an_tx_prod; 1216 bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3)); 1217 1218 while(sc->an_rdata.an_tx_ring[idx] == 0) { 1219 IF_DEQUEUE(&ifp->if_snd, m0); 1220 if (m0 == NULL) 1221 break; 1222 1223 id = sc->an_rdata.an_tx_fids[idx]; 1224 eh = mtod(m0, struct ether_header *); 1225 1226 bcopy((char *)&eh->ether_dhost, 1227 (char *)&tx_frame_802_3.an_tx_dst_addr, ETHER_ADDR_LEN); 1228 bcopy((char *)&eh->ether_shost, 1229 (char *)&tx_frame_802_3.an_tx_src_addr, ETHER_ADDR_LEN); 1230 1231 tx_frame_802_3.an_tx_802_3_payload_len = 1232 m0->m_pkthdr.len - 12; /* minus src/dest mac & type */ 1233 1234 m_copydata(m0, sizeof(struct ether_header) - 2 , 1235 tx_frame_802_3.an_tx_802_3_payload_len, 1236 (caddr_t)&sc->an_txbuf); 1237 1238 txcontrol=AN_TXCTL_8023; 1239 /* write the txcontrol only */ 1240 an_write_data(sc, id, 0x08, (caddr_t)&txcontrol, 1241 sizeof(txcontrol)); 1242 1243 /* 802_3 header */ 1244 an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3, 1245 sizeof(struct an_txframe_802_3)); 1246 1247 /* in mbuf header type is just before payload */ 1248 an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf, 1249 tx_frame_802_3.an_tx_802_3_payload_len); 1250 1251 /* 1252 * If there's a BPF listner, bounce a copy of 1253 * this frame to him. 1254 */ 1255 if (ifp->if_bpf) 1256 bpf_mtap(ifp, m0); 1257 1258 m_freem(m0); 1259 m0 = NULL; 1260 1261 sc->an_rdata.an_tx_ring[idx] = id; 1262 if (an_cmd(sc, AN_CMD_TX, id)) 1263 printf("an%d: xmit failed\n", sc->an_unit); 1264 1265 AN_INC(idx, AN_TX_RING_CNT); 1266 } 1267 1268 if (m0 != NULL) 1269 ifp->if_flags |= IFF_OACTIVE; 1270 1271 sc->an_rdata.an_tx_prod = idx; 1272 1273 /* 1274 * Set a timeout in case the chip goes out to lunch. 1275 */ 1276 ifp->if_timer = 5; 1277 1278 return; 1279} 1280 1281void an_stop(sc) 1282 struct an_softc *sc; 1283{ 1284 struct ifnet *ifp; 1285 int i; 1286 1287 AN_LOCK(sc); 1288 1289 if (sc->an_gone) { 1290 AN_UNLOCK(sc); 1291 return; 1292 } 1293 1294 ifp = &sc->arpcom.ac_if; 1295 1296 an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0); 1297 CSR_WRITE_2(sc, AN_INT_EN, 0); 1298 an_cmd(sc, AN_CMD_DISABLE, 0); 1299 1300 for (i = 0; i < AN_TX_RING_CNT; i++) 1301 an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]); 1302 1303 untimeout(an_stats_update, sc, sc->an_stat_ch); 1304 1305 ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 1306 1307 AN_UNLOCK(sc); 1308 1309 return; 1310} 1311 1312static void an_watchdog(ifp) 1313 struct ifnet *ifp; 1314{ 1315 struct an_softc *sc; 1316 1317 sc = ifp->if_softc; 1318 AN_LOCK(sc); 1319 1320 if (sc->an_gone) { 1321 AN_UNLOCK(sc); 1322 return; 1323 } 1324 1325 printf("an%d: device timeout\n", sc->an_unit); 1326 1327 an_reset(sc); 1328 an_init(sc); 1329 1330 ifp->if_oerrors++; 1331 AN_UNLOCK(sc); 1332 1333 return; 1334} 1335 1336void an_shutdown(dev) 1337 device_t dev; 1338{ 1339 struct an_softc *sc; 1340 1341 sc = device_get_softc(dev); 1342 an_stop(sc); 1343 1344 return; 1345} 1346 1347#ifdef ANCACHE 1348/* Aironet signal strength cache code. 1349 * store signal/noise/quality on per MAC src basis in 1350 * a small fixed cache. The cache wraps if > MAX slots 1351 * used. The cache may be zeroed out to start over. 1352 * Two simple filters exist to reduce computation: 1353 * 1. ip only (literally 0x800) which may be used 1354 * to ignore some packets. It defaults to ip only. 1355 * it could be used to focus on broadcast, non-IP 802.11 beacons. 1356 * 2. multicast/broadcast only. This may be used to 1357 * ignore unicast packets and only cache signal strength 1358 * for multicast/broadcast packets (beacons); e.g., Mobile-IP 1359 * beacons and not unicast traffic. 1360 * 1361 * The cache stores (MAC src(index), IP src (major clue), signal, 1362 * quality, noise) 1363 * 1364 * No apologies for storing IP src here. It's easy and saves much 1365 * trouble elsewhere. The cache is assumed to be INET dependent, 1366 * although it need not be. 1367 * 1368 * Note: the Aironet only has a single byte of signal strength value 1369 * in the rx frame header, and it's not scaled to anything sensible. 1370 * This is kind of lame, but it's all we've got. 1371 */ 1372 1373#ifdef documentation 1374 1375int an_sigitems; /* number of cached entries */ 1376struct an_sigcache an_sigcache[MAXANCACHE]; /* array of cache entries */ 1377int an_nextitem; /* index/# of entries */ 1378 1379 1380#endif 1381 1382/* control variables for cache filtering. Basic idea is 1383 * to reduce cost (e.g., to only Mobile-IP agent beacons 1384 * which are broadcast or multicast). Still you might 1385 * want to measure signal strength anth unicast ping packets 1386 * on a pt. to pt. ant. setup. 1387 */ 1388/* set true if you want to limit cache items to broadcast/mcast 1389 * only packets (not unicast). Useful for mobile-ip beacons which 1390 * are broadcast/multicast at network layer. Default is all packets 1391 * so ping/unicast anll work say anth pt. to pt. antennae setup. 1392 */ 1393static int an_cache_mcastonly = 0; 1394SYSCTL_INT(_machdep, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW, 1395 &an_cache_mcastonly, 0, ""); 1396 1397/* set true if you want to limit cache items to IP packets only 1398*/ 1399static int an_cache_iponly = 1; 1400SYSCTL_INT(_machdep, OID_AUTO, an_cache_iponly, CTLFLAG_RW, 1401 &an_cache_iponly, 0, ""); 1402 1403/* 1404 * an_cache_store, per rx packet store signal 1405 * strength in MAC (src) indexed cache. 1406 */ 1407static 1408void an_cache_store (sc, eh, m, rx_quality) 1409 struct an_softc *sc; 1410 struct ether_header *eh; 1411 struct mbuf *m; 1412 unsigned short rx_quality; 1413{ 1414 struct ip *ip = 0; 1415 int i; 1416 static int cache_slot = 0; /* use this cache entry */ 1417 static int wrapindex = 0; /* next "free" cache entry */ 1418 int saanp=0; 1419 1420 /* filters: 1421 * 1. ip only 1422 * 2. configurable filter to throw out unicast packets, 1423 * keep multicast only. 1424 */ 1425 1426 if ((ntohs(eh->ether_type) == 0x800)) { 1427 saanp = 1; 1428 } 1429 1430 /* filter for ip packets only 1431 */ 1432 if ( an_cache_iponly && !saanp) { 1433 return; 1434 } 1435 1436 /* filter for broadcast/multicast only 1437 */ 1438 if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 1439 return; 1440 } 1441 1442#ifdef SIGDEBUG 1443 printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n", 1444 rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff); 1445#endif 1446 1447 /* find the ip header. we want to store the ip_src 1448 * address. 1449 */ 1450 if (saanp) { 1451 ip = mtod(m, struct ip *); 1452 } 1453 1454 /* do a linear search for a matching MAC address 1455 * in the cache table 1456 * . MAC address is 6 bytes, 1457 * . var w_nextitem holds total number of entries already cached 1458 */ 1459 for(i = 0; i < sc->an_nextitem; i++) { 1460 if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc, 6 )) { 1461 /* Match!, 1462 * so we already have this entry, 1463 * update the data 1464 */ 1465 break; 1466 } 1467 } 1468 1469 /* did we find a matching mac address? 1470 * if yes, then overwrite a previously existing cache entry 1471 */ 1472 if (i < sc->an_nextitem ) { 1473 cache_slot = i; 1474 } 1475 /* else, have a new address entry,so 1476 * add this new entry, 1477 * if table full, then we need to replace LRU entry 1478 */ 1479 else { 1480 1481 /* check for space in cache table 1482 * note: an_nextitem also holds number of entries 1483 * added in the cache table 1484 */ 1485 if ( sc->an_nextitem < MAXANCACHE ) { 1486 cache_slot = sc->an_nextitem; 1487 sc->an_nextitem++; 1488 sc->an_sigitems = sc->an_nextitem; 1489 } 1490 /* no space found, so simply wrap anth wrap index 1491 * and "zap" the next entry 1492 */ 1493 else { 1494 if (wrapindex == MAXANCACHE) { 1495 wrapindex = 0; 1496 } 1497 cache_slot = wrapindex++; 1498 } 1499 } 1500 1501 /* invariant: cache_slot now points at some slot 1502 * in cache. 1503 */ 1504 if (cache_slot < 0 || cache_slot >= MAXANCACHE) { 1505 log(LOG_ERR, "an_cache_store, bad index: %d of " 1506 "[0..%d], gross cache error\n", 1507 cache_slot, MAXANCACHE); 1508 return; 1509 } 1510 1511 /* store items in cache 1512 * .ip source address 1513 * .mac src 1514 * .signal, etc. 1515 */ 1516 if (saanp) { 1517 sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 1518 } 1519 bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc, 6); 1520 1521 sc->an_sigcache[cache_slot].signal = rx_quality; 1522 1523 return; 1524} 1525#endif 1526