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