1 /* $NetBSD: an.c,v 1.20 2001/07/18 02:06:44 onoe Exp $ */ 2 /* 3 * Copyright (c) 1997, 1998, 1999 4 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Bill Paul. 17 * 4. Neither the name of the author nor the names of any co-contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $FreeBSD: src/sys/dev/an/if_an.c,v 1.12 2000/11/13 23:04:12 wpaul Exp $ 34 */ 35 36 /* 37 * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD. 38 * 39 * Written by Bill Paul <wpaul@ctr.columbia.edu> 40 * Electrical Engineering Department 41 * Columbia University, New York City 42 */ 43 44 /* 45 * The Aironet 4500/4800 series cards some in PCMCIA, ISA and PCI form. 46 * This driver supports all three device types (PCI devices are supported 47 * through an extra PCI shim: /sys/pci/if_an_p.c). ISA devices can be 48 * supported either using hard-coded IO port/IRQ settings or via Plug 49 * and Play. The 4500 series devices support 1Mbps and 2Mbps data rates. 50 * The 4800 devices support 1, 2, 5.5 and 11Mbps rates. 51 * 52 * Like the WaveLAN/IEEE cards, the Aironet NICs are all essentially 53 * PCMCIA devices. The ISA and PCI cards are a combination of a PCMCIA 54 * device and a PCMCIA to ISA or PCMCIA to PCI adapter card. There are 55 * a couple of important differences though: 56 * 57 * - Lucent doesn't currently offer a PCI card, however Aironet does 58 * - Lucent ISA card looks to the host like a PCMCIA controller with 59 * a PCMCIA WaveLAN card inserted. This means that even desktop 60 * machines need to be configured with PCMCIA support in order to 61 * use WaveLAN/IEEE ISA cards. The Aironet cards on the other hand 62 * actually look like normal ISA and PCI devices to the host, so 63 * no PCMCIA controller support is needed 64 * 65 * The latter point results in a small gotcha. The Aironet PCMCIA 66 * cards can be configured for one of two operating modes depending 67 * on how the Vpp1 and Vpp2 programming voltages are set when the 68 * card is activated. In order to put the card in proper PCMCIA 69 * operation (where the CIS table is visible and the interface is 70 * programmed for PCMCIA operation), both Vpp1 and Vpp2 have to be 71 * set to 5 volts. FreeBSD by default doesn't set the Vpp voltages, 72 * which leaves the card in ISA/PCI mode, which prevents it from 73 * being activated as an PCMCIA device. Consequently, /sys/pccard/pccard.c 74 * has to be patched slightly in order to enable the Vpp voltages in 75 * order to make the Aironet PCMCIA cards work. 76 * 77 * Note that some PCMCIA controller software packages for Windows NT 78 * fail to set the voltages as well. 79 * 80 * The Aironet devices can operate in both station mode and access point 81 * mode. Typically, when programmed for station mode, the card can be set 82 * to automatically perform encapsulation/decapsulation of Ethernet II 83 * and 802.3 frames within 802.11 frames so that the host doesn't have 84 * to do it itself. This driver doesn't program the card that way: the 85 * driver handles all of the encapsulation/decapsulation itself. 86 */ 87 88 /* 89 * Ported to NetBSD from FreeBSD by Atsushi Onoe at the San Diego 90 * IETF meeting. 91 */ 92 93 #include "opt_inet.h" 94 #include "bpfilter.h" 95 96 #ifdef INET 97 /* 98 * It is designed for IPv4 only. 99 * no one use it and disabled for now. -- onoe 100 */ 101 #undef ANCACHE /* enable signal strength cache */ 102 #endif 103 104 #include <sys/param.h> 105 #include <sys/callout.h> 106 #include <sys/systm.h> 107 #include <sys/sockio.h> 108 #include <sys/mbuf.h> 109 #include <sys/kernel.h> 110 #include <sys/ucred.h> 111 #include <sys/socket.h> 112 #include <sys/device.h> 113 #include <sys/proc.h> 114 #include <sys/md4.h> 115 #ifdef ANCACHE 116 #include <sys/syslog.h> 117 #include <sys/sysctl.h> 118 #endif 119 120 #include <machine/bus.h> 121 122 #include <net/if.h> 123 #include <net/if_arp.h> 124 #include <net/if_dl.h> 125 #include <net/if_ether.h> 126 #include <net/if_ieee80211.h> 127 #include <net/if_types.h> 128 #include <net/if_media.h> 129 130 #ifdef INET 131 #include <netinet/in.h> 132 #include <netinet/in_systm.h> 133 #include <netinet/in_var.h> 134 #include <netinet/ip.h> 135 #endif 136 137 #if NBPFILTER > 0 138 #include <net/bpf.h> 139 #endif 140 141 #include <dev/ic/anreg.h> 142 #include <dev/ic/anvar.h> 143 144 #if !defined(lint) 145 static const char rcsid[] = 146 "$FreeBSD: src/sys/dev/an/if_an.c,v 1.12 2000/11/13 23:04:12 wpaul Exp $"; 147 #endif 148 149 /* These are global because we need them in sys/pci/if_an_p.c. */ 150 static void an_reset __P((struct an_softc *)); 151 static void an_wait __P((struct an_softc *)); 152 static int an_ioctl __P((struct ifnet *, u_long, caddr_t)); 153 static int an_set_nwkey __P((struct an_softc *, 154 struct ieee80211_nwkey *)); 155 static int an_set_nwkey_wep __P((struct an_softc *, 156 struct ieee80211_nwkey *)); 157 static int an_set_nwkey_eap __P((struct an_softc *, 158 struct ieee80211_nwkey *)); 159 static int an_get_nwkey __P((struct an_softc *, 160 struct ieee80211_nwkey *)); 161 static int an_write_wepkey __P((struct an_softc *sc, int type, 162 struct an_wepkey *keys, int kid)); 163 static int an_init __P((struct ifnet *)); 164 static void an_stop __P((struct ifnet *, int)); 165 static int an_init_tx_ring __P((struct an_softc *)); 166 static void an_start __P((struct ifnet *)); 167 static void an_watchdog __P((struct ifnet *)); 168 static void an_rxeof __P((struct an_softc *)); 169 static void an_txeof __P((struct an_softc *, int)); 170 171 static int an_cmd __P((struct an_softc *, int, int)); 172 static int an_read_record __P((struct an_softc *, struct an_ltv_gen *)); 173 static int an_write_record __P((struct an_softc *, struct an_ltv_gen *)); 174 static int an_read_data __P((struct an_softc *, int, 175 int, caddr_t, int)); 176 static int an_write_data __P((struct an_softc *, int, 177 int, caddr_t, int)); 178 static int an_seek __P((struct an_softc *, int, int, int)); 179 static int an_alloc_nicmem __P((struct an_softc *, int, int *)); 180 static void an_stats_update __P((void *)); 181 static int an_setdef __P((struct an_softc *, struct an_req *)); 182 #ifdef ANCACHE 183 static void an_cache_store __P((struct an_softc *, struct ether_header *, 184 struct mbuf *, unsigned short)); 185 #endif 186 #ifdef IFM_IEEE80211 187 static int an_media_change __P((struct ifnet *ifp)); 188 static void an_media_status __P((struct ifnet *ifp, struct ifmediareq *imr)); 189 #endif 190 191 int 192 an_attach(struct an_softc *sc) 193 { 194 struct ifnet *ifp = &sc->arpcom.ec_if; 195 int i, s; 196 struct an_ltv_wepkey *akey; 197 #ifdef IFM_IEEE80211 198 int mtype; 199 struct ifmediareq imr; 200 #endif 201 202 s = splnet(); 203 sc->an_associated = 0; 204 an_wait(sc); 205 206 /* Load factory config */ 207 if (an_cmd(sc, AN_CMD_READCFG, 0)) { 208 splx(s); 209 printf("%s: failed to load config data\n", sc->an_dev.dv_xname); 210 return(EIO); 211 } 212 213 /* Read the current configuration */ 214 sc->an_config.an_type = AN_RID_GENCONFIG; 215 sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 216 if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 217 splx(s); 218 printf("%s: read record failed\n", sc->an_dev.dv_xname); 219 return(EIO); 220 } 221 222 /* Read the card capabilities */ 223 sc->an_caps.an_type = AN_RID_CAPABILITIES; 224 sc->an_caps.an_len = sizeof(struct an_ltv_caps); 225 if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) { 226 splx(s); 227 printf("%s: read record failed\n", sc->an_dev.dv_xname); 228 return(EIO); 229 } 230 231 /* Read ssid list */ 232 sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 233 sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist); 234 if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 235 splx(s); 236 printf("%s: read record failed\n", sc->an_dev.dv_xname); 237 return(EIO); 238 } 239 240 /* Read AP list */ 241 sc->an_aplist.an_type = AN_RID_APLIST; 242 sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 243 if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 244 splx(s); 245 printf("%s: read record failed\n", sc->an_dev.dv_xname); 246 return(EIO); 247 } 248 249 /* Read WEP settings from persistent memory */ 250 akey = (struct an_ltv_wepkey *)&sc->an_reqbuf; 251 akey->an_type = AN_RID_WEP_VOLATILE; 252 akey->an_len = sizeof(struct an_ltv_wepkey); 253 while (an_read_record(sc, (struct an_ltv_gen *)akey) == 0) { 254 if (akey->an_key_index == 0xffff) { 255 sc->an_tx_perskey = akey->an_mac_addr[0]; 256 sc->an_tx_key = -1; 257 break; 258 } 259 if (akey->an_key_index >= IEEE80211_WEP_NKID) 260 break; 261 sc->an_perskeylen[akey->an_key_index] = akey->an_key_len; 262 sc->an_wepkeys[akey->an_key_index].an_wep_keylen = -1; 263 akey->an_type = AN_RID_WEP_PERSISTENT; /* for next key */ 264 akey->an_len = sizeof(*akey); 265 } 266 /* XXX not sure if persistent key settings should be printed here */ 267 268 printf("%s: 802.11 address: %s\n", sc->an_dev.dv_xname, 269 ether_sprintf(sc->an_caps.an_oemaddr)); 270 271 ifp->if_softc = sc; 272 ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS | IFF_SIMPLEX | 273 IFF_MULTICAST | IFF_ALLMULTI; 274 ifp->if_ioctl = an_ioctl; 275 ifp->if_start = an_start; 276 ifp->if_init = an_init; 277 ifp->if_stop = an_stop; 278 ifp->if_watchdog = an_watchdog; 279 IFQ_SET_READY(&ifp->if_snd); 280 281 memcpy(ifp->if_xname, sc->an_dev.dv_xname, IFNAMSIZ); 282 283 memset(sc->an_config.an_nodename, 0, sizeof(sc->an_config.an_nodename)); 284 memcpy(sc->an_config.an_nodename, AN_DEFAULT_NODENAME, 285 sizeof(AN_DEFAULT_NODENAME) - 1); 286 287 memset(sc->an_ssidlist.an_ssid1, 0, sizeof(sc->an_ssidlist.an_ssid1)); 288 memcpy(sc->an_ssidlist.an_ssid1, AN_DEFAULT_NETNAME, 289 sizeof(AN_DEFAULT_NETNAME) - 1); 290 sc->an_ssidlist.an_ssid1_len = strlen(AN_DEFAULT_NETNAME); 291 292 sc->an_config.an_opmode = AN_OPMODE_INFRASTRUCTURE_STATION; 293 294 sc->an_tx_rate = 0; 295 #if 0 296 memset(&sc->an_stats, 0, sizeof(sc->an_stats)); 297 #endif 298 299 /* 300 * Call MI attach routine. 301 */ 302 if_attach(ifp); 303 ether_ifattach(ifp, sc->an_caps.an_oemaddr); 304 305 #ifdef IFM_IEEE80211 306 ifmedia_init(&sc->sc_media, 0, an_media_change, an_media_status); 307 ifmedia_add(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 308 0, 0), 0, NULL); 309 ifmedia_add(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 310 IFM_IEEE80211_ADHOC, 0), 0, NULL); 311 for (i = 0; i < sizeof(sc->an_caps.an_rates); i++) { 312 switch (sc->an_caps.an_rates[i]) { 313 case AN_RATE_1MBPS: 314 mtype = IFM_IEEE80211_DS1; 315 break; 316 case AN_RATE_2MBPS: 317 mtype = IFM_IEEE80211_DS2; 318 break; 319 case AN_RATE_5_5MBPS: 320 mtype = IFM_IEEE80211_DS5; 321 break; 322 case AN_RATE_11MBPS: 323 mtype = IFM_IEEE80211_DS11; 324 break; 325 default: 326 continue; 327 } 328 ifmedia_add(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, mtype, 329 0, 0), 0, NULL); 330 ifmedia_add(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, mtype, 331 IFM_IEEE80211_ADHOC, 0), 0, NULL); 332 } 333 an_media_status(ifp, &imr); 334 ifmedia_set(&sc->sc_media, imr.ifm_active); 335 #endif 336 callout_init(&sc->an_stat_ch); 337 splx(s); 338 339 return(0); 340 } 341 342 int 343 an_detach(struct an_softc *sc) 344 { 345 struct ifnet *ifp = &sc->arpcom.ec_if; 346 int s; 347 348 s = splnet(); 349 an_stop(ifp, 1); 350 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); 351 ether_ifdetach(ifp); 352 if_detach(ifp); 353 splx(s); 354 return 0; 355 } 356 357 int 358 an_activate(struct device *self, enum devact act) 359 { 360 struct an_softc *sc = (struct an_softc *)self; 361 int s, error = 0; 362 363 s = splnet(); 364 switch (act) { 365 case DVACT_ACTIVATE: 366 error = EOPNOTSUPP; 367 break; 368 369 case DVACT_DEACTIVATE: 370 if_deactivate(&sc->arpcom.ec_if); 371 break; 372 } 373 splx(s); 374 375 return error; 376 } 377 378 void 379 an_power(int why, void *arg) 380 { 381 int s; 382 struct an_softc *sc = arg; 383 struct ifnet *ifp = &sc->arpcom.ec_if; 384 385 s = splnet(); 386 switch (why) { 387 case PWR_SUSPEND: 388 case PWR_STANDBY: 389 an_stop(ifp, 1); 390 break; 391 case PWR_RESUME: 392 if (ifp->if_flags & IFF_UP) 393 an_init(ifp); 394 break; 395 case PWR_SOFTSUSPEND: 396 case PWR_SOFTSTANDBY: 397 case PWR_SOFTRESUME: 398 break; 399 } 400 splx(s); 401 } 402 403 void 404 an_shutdown(void *arg) 405 { 406 struct an_softc *sc = arg; 407 408 an_stop(&sc->arpcom.ec_if, 1); 409 return; 410 } 411 412 static int 413 an_setdef(struct an_softc *sc, struct an_req *areq) 414 { 415 int error; 416 struct ifnet *ifp = &sc->arpcom.ec_if; 417 struct an_ltv_genconfig *cfg; 418 struct an_ltv_gen *sp; 419 420 error = 0; 421 422 switch (areq->an_type) { 423 case AN_RID_GENCONFIG: 424 cfg = (struct an_ltv_genconfig *)areq; 425 memcpy(sc->an_caps.an_oemaddr, cfg->an_macaddr, ETHER_ADDR_LEN); 426 memcpy(LLADDR(ifp->if_sadl), cfg->an_macaddr, ETHER_ADDR_LEN); 427 memcpy(&sc->an_config, areq, sizeof(struct an_ltv_genconfig)); 428 error = ENETRESET; 429 break; 430 case AN_RID_SSIDLIST: 431 memcpy(&sc->an_ssidlist, areq, sizeof(struct an_ltv_ssidlist)); 432 error = ENETRESET; 433 break; 434 case AN_RID_APLIST: 435 memcpy(&sc->an_aplist, areq, sizeof(struct an_ltv_aplist)); 436 error = ENETRESET; 437 break; 438 case AN_RID_TX_SPEED: 439 sp = (struct an_ltv_gen *)areq; 440 sc->an_tx_rate = sp->an_val; 441 break; 442 case AN_RID_WEP_VOLATILE: 443 case AN_RID_WEP_PERSISTENT: 444 case AN_RID_LEAP_USER: 445 case AN_RID_LEAP_PASS: 446 if (!sc->sc_enabled) { 447 error = ENXIO; 448 break; 449 } 450 an_cmd(sc, AN_CMD_DISABLE, 0); 451 an_write_record(sc, (struct an_ltv_gen *)areq); 452 if (an_cmd(sc, AN_CMD_ENABLE, 0)) 453 error = EIO; 454 break; 455 default: 456 if (ifp->if_flags & IFF_DEBUG) 457 printf("%s: unknown RID: %x\n", sc->an_dev.dv_xname, 458 areq->an_type); 459 error = EINVAL; 460 break; 461 } 462 return error; 463 } 464 465 static int 466 an_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 467 { 468 int s; 469 int error = 0; 470 struct an_softc *sc; 471 struct an_req *areq; 472 struct ifreq *ifr; 473 struct ieee80211_nwid nwid; 474 struct ieee80211_power *power; 475 476 sc = ifp->if_softc; 477 ifr = (struct ifreq *)data; 478 s = splnet(); 479 480 switch (command) { 481 case SIOCSIFFLAGS: 482 if (ifp->if_flags & IFF_UP) { 483 if (sc->sc_enabled) { 484 /* 485 * To avoid rescanning another access point, 486 * do not call an_init() here. Instead, only 487 * reflect promisc mode settings. 488 */ 489 error = an_cmd(sc, AN_CMD_SET_MODE, 490 (ifp->if_flags & IFF_PROMISC) ? 0xffff : 0); 491 } else 492 error = an_init(ifp); 493 } else if (sc->sc_enabled) 494 an_stop(ifp, 1); 495 break; 496 case SIOCGAIRONET: 497 areq = &sc->an_reqbuf; 498 error = copyin(ifr->ifr_data, areq, sizeof(struct an_req)); 499 if (error) 500 break; 501 switch (areq->an_type) { 502 #ifdef ANCACHE 503 case AN_RID_ZERO_CACHE: 504 /* XXX suser()? -- should belong to SIOCSAIRONET */ 505 sc->an_sigitems = sc->an_nextitem = 0; 506 goto out; 507 case AN_RID_READ_CACHE: 508 caddr_t pt = (char *)&areq->an_val; 509 memcpy(pt, &sc->an_sigitems, sizeof(int)); 510 pt += sizeof(int); 511 areq->an_len = sizeof(int) / 2; 512 memcpy(pt, &sc->an_sigcache, 513 sizeof(struct an_sigcache) * sc->an_sigitems); 514 areq->an_len += ((sizeof(struct an_sigcache) * 515 sc->an_sigitems) / 2) + 1; 516 break; 517 #endif 518 default: 519 if (an_read_record(sc, (struct an_ltv_gen *)areq)) { 520 error = EINVAL; 521 break; 522 } 523 break; 524 } 525 error = copyout(areq, ifr->ifr_data, sizeof(struct an_req)); 526 break; 527 case SIOCSAIRONET: 528 if ((error = suser(curproc->p_ucred, &curproc->p_acflag))) 529 break; 530 areq = &sc->an_reqbuf; 531 error = copyin(ifr->ifr_data, areq, sizeof(struct an_req)); 532 if (error) 533 break; 534 error = an_setdef(sc, areq); 535 break; 536 case SIOCS80211NWID: 537 error = copyin(ifr->ifr_data, &nwid, sizeof(nwid)); 538 if (error) 539 break; 540 if (nwid.i_len > IEEE80211_NWID_LEN) { 541 error = EINVAL; 542 break; 543 } 544 if (sc->an_ssidlist.an_ssid1_len == nwid.i_len && 545 memcmp(sc->an_ssidlist.an_ssid1, nwid.i_nwid, nwid.i_len) 546 == 0) 547 break; 548 memset(sc->an_ssidlist.an_ssid1, 0, IEEE80211_NWID_LEN); 549 sc->an_ssidlist.an_ssid1_len = nwid.i_len; 550 memcpy(sc->an_ssidlist.an_ssid1, nwid.i_nwid, nwid.i_len); 551 error = ENETRESET; 552 break; 553 case SIOCG80211NWID: 554 memset(&nwid, 0, sizeof(nwid)); 555 if (sc->sc_enabled && sc->an_associated) { 556 nwid.i_len = sc->an_status.an_ssidlen; 557 memcpy(nwid.i_nwid, sc->an_status.an_ssid, nwid.i_len); 558 } else { 559 nwid.i_len = sc->an_ssidlist.an_ssid1_len; 560 memcpy(nwid.i_nwid, sc->an_ssidlist.an_ssid1, 561 nwid.i_len); 562 } 563 error = copyout(&nwid, ifr->ifr_data, sizeof(nwid)); 564 break; 565 case SIOCS80211NWKEY: 566 error = an_set_nwkey(sc, (struct ieee80211_nwkey *)data); 567 break; 568 case SIOCG80211NWKEY: 569 error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data); 570 break; 571 case SIOCS80211POWER: 572 power = (struct ieee80211_power *)data; 573 sc->an_config.an_psave_mode = power->i_enabled ? 574 AN_PSAVE_PSP : AN_PSAVE_NONE; 575 sc->an_config.an_listen_interval = power->i_maxsleep; 576 error = ENETRESET; 577 break; 578 case SIOCG80211POWER: 579 power = (struct ieee80211_power *)data; 580 power->i_enabled = 581 sc->an_config.an_psave_mode != AN_PSAVE_NONE ? 1 : 0; 582 power->i_maxsleep = sc->an_config.an_listen_interval; 583 break; 584 #ifdef IFM_IEEE80211 585 case SIOCSIFMEDIA: 586 case SIOCGIFMEDIA: 587 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command); 588 break; 589 #endif 590 case SIOCADDMULTI: 591 case SIOCDELMULTI: 592 error = ether_ioctl(ifp, command, data); 593 if (error == ENETRESET) { 594 /* we don't have multicast filter. */ 595 error = 0; 596 } 597 break; 598 default: 599 error = ether_ioctl(ifp, command, data); 600 break; 601 } 602 if (error == ENETRESET) { 603 if (sc->sc_enabled) 604 error = an_init(ifp); 605 else 606 error = 0; 607 } 608 #ifdef ANCACHE 609 out: 610 #endif 611 splx(s); 612 return error; 613 } 614 615 static int 616 an_set_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey) 617 { 618 int error; 619 u_int16_t prevauth; 620 621 error = 0; 622 prevauth = sc->an_config.an_authtype; 623 624 switch (nwkey->i_wepon) { 625 case IEEE80211_NWKEY_OPEN: 626 sc->an_config.an_authtype = AN_AUTHTYPE_OPEN; 627 break; 628 629 case IEEE80211_NWKEY_WEP: 630 case IEEE80211_NWKEY_WEP | IEEE80211_NWKEY_PERSIST: 631 error = an_set_nwkey_wep(sc, nwkey); 632 if (error == 0 || error == ENETRESET) 633 sc->an_config.an_authtype = 634 AN_AUTHTYPE_OPEN | AN_AUTHTYPE_PRIVACY_IN_USE; 635 break; 636 637 case IEEE80211_NWKEY_EAP: 638 error = an_set_nwkey_eap(sc, nwkey); 639 if (error == 0 || error == ENETRESET) 640 sc->an_config.an_authtype = AN_AUTHTYPE_OPEN | 641 AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_LEAP; 642 break; 643 default: 644 error = EINVAL; 645 break; 646 } 647 if (error == 0 && prevauth != sc->an_config.an_authtype) 648 error = ENETRESET; 649 return error; 650 } 651 652 static int 653 an_set_nwkey_wep(struct an_softc *sc, struct ieee80211_nwkey *nwkey) 654 { 655 int i, txkey, anysetkey, needreset, error; 656 struct an_wepkey keys[IEEE80211_WEP_NKID]; 657 658 error = 0; 659 memset(keys, 0, sizeof(keys)); 660 anysetkey = needreset = 0; 661 662 /* load argument and sanity check */ 663 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 664 keys[i].an_wep_keylen = nwkey->i_key[i].i_keylen; 665 if (keys[i].an_wep_keylen < 0) 666 continue; 667 if (keys[i].an_wep_keylen != 0 && 668 keys[i].an_wep_keylen < IEEE80211_WEP_KEYLEN) 669 return EINVAL; 670 if (keys[i].an_wep_keylen > sizeof(keys[i].an_wep_key)) 671 return EINVAL; 672 if ((error = copyin(nwkey->i_key[i].i_keydat, 673 keys[i].an_wep_key, keys[i].an_wep_keylen)) != 0) 674 return error; 675 anysetkey++; 676 } 677 txkey = nwkey->i_defkid - 1; 678 if (txkey >= 0) { 679 if (txkey >= IEEE80211_WEP_NKID) 680 return EINVAL; 681 /* default key must have a valid value */ 682 if (keys[txkey].an_wep_keylen == 0 || 683 (keys[txkey].an_wep_keylen < 0 && 684 sc->an_perskeylen[txkey] == 0)) 685 return EINVAL; 686 anysetkey++; 687 } 688 if (!(nwkey->i_wepon & IEEE80211_NWKEY_PERSIST)) { 689 /* set temporary keys */ 690 sc->an_tx_key = txkey; 691 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 692 if (keys[i].an_wep_keylen < 0) 693 continue; 694 memcpy(&sc->an_wepkeys[i], &keys[i], sizeof(keys[i])); 695 } 696 } else { 697 /* set persist keys */ 698 if (anysetkey) { 699 /* prepare to write nvram */ 700 if (!sc->sc_enabled) { 701 if (sc->sc_enable) 702 (*sc->sc_enable)(sc); 703 an_wait(sc); 704 sc->sc_enabled = 1; 705 error = an_write_wepkey(sc, 706 AN_RID_WEP_PERSISTENT, keys, txkey); 707 if (sc->sc_disable) 708 (*sc->sc_disable)(sc); 709 sc->sc_enabled = 0; 710 } else { 711 an_cmd(sc, AN_CMD_DISABLE, 0); 712 error = an_write_wepkey(sc, 713 AN_RID_WEP_PERSISTENT, keys, txkey); 714 an_cmd(sc, AN_CMD_ENABLE, 0); 715 } 716 if (error) 717 return error; 718 } 719 if (txkey >= 0) 720 sc->an_tx_perskey = txkey; 721 if (sc->an_tx_key >= 0) { 722 sc->an_tx_key = -1; 723 needreset++; 724 } 725 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 726 if (sc->an_wepkeys[i].an_wep_keylen >= 0) { 727 memset(&sc->an_wepkeys[i].an_wep_key, 0, 728 sizeof(sc->an_wepkeys[i].an_wep_key)); 729 sc->an_wepkeys[i].an_wep_keylen = -1; 730 needreset++; 731 } 732 if (keys[i].an_wep_keylen >= 0) 733 sc->an_perskeylen[i] = keys[i].an_wep_keylen; 734 } 735 } 736 if (needreset) { 737 /* firmware restart to reload persistent key */ 738 an_reset(sc); 739 } 740 if (anysetkey || needreset) 741 error = ENETRESET; 742 return error; 743 } 744 745 static int 746 an_set_nwkey_eap(struct an_softc *sc, struct ieee80211_nwkey *nwkey) 747 { 748 int i, error; 749 struct an_ltv_leapkey *key; 750 u_int16_t unibuf[sizeof(key->an_key)]; 751 MD4_CTX ctx; 752 753 error = 0; 754 755 if (nwkey->i_key[0].i_keydat == NULL && 756 nwkey->i_key[1].i_keydat == NULL) 757 return 0; 758 if (!sc->sc_enabled) 759 return ENXIO; 760 an_cmd(sc, AN_CMD_DISABLE, 0); 761 key = (struct an_ltv_leapkey *)&sc->an_reqbuf; 762 if (nwkey->i_key[0].i_keydat != NULL) { 763 memset(key, 0, sizeof(*key)); 764 key->an_type = AN_RID_LEAP_USER; 765 key->an_len = sizeof(*key); 766 key->an_key_len = nwkey->i_key[0].i_keylen; 767 if (key->an_key_len > sizeof(key->an_key)) 768 return EINVAL; 769 if ((error = copyin(nwkey->i_key[0].i_keydat, key->an_key, 770 key->an_key_len)) != 0) 771 return error; 772 an_write_record(sc, (struct an_ltv_gen *)key); 773 } 774 if (nwkey->i_key[1].i_keydat != NULL) { 775 memset(key, 0, sizeof(*key)); 776 key->an_type = AN_RID_LEAP_PASS; 777 key->an_len = sizeof(*key); 778 key->an_key_len = nwkey->i_key[1].i_keylen; 779 if (key->an_key_len > sizeof(key->an_key)) 780 return EINVAL; 781 if ((error = copyin(nwkey->i_key[1].i_keydat, key->an_key, 782 key->an_key_len)) != 0) 783 return error; 784 /* 785 * Cisco seems to use PasswordHash and PasswordHashHash 786 * in RFC-2759 (MS-CHAP-V2). 787 */ 788 memset(unibuf, 0, sizeof(unibuf)); 789 /* XXX: convert password to unicode */ 790 for (i = 0; i < key->an_key_len; i++) 791 unibuf[i] = key->an_key[i]; 792 /* set PasswordHash */ 793 MD4Init(&ctx); 794 MD4Update(&ctx, (u_int8_t *)unibuf, key->an_key_len * 2); 795 MD4Final(key->an_key, &ctx); 796 /* set PasswordHashHash */ 797 MD4Init(&ctx); 798 MD4Update(&ctx, key->an_key, 16); 799 MD4Final(key->an_key + 16, &ctx); 800 key->an_key_len = 32; 801 an_write_record(sc, (struct an_ltv_gen *)key); 802 } 803 error = an_cmd(sc, AN_CMD_ENABLE, 0); 804 if (error) 805 printf("%s: an_set_nwkey: failed to enable MAC\n", 806 sc->an_dev.dv_xname); 807 else 808 error = ENETRESET; 809 return error; 810 } 811 812 static int 813 an_get_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey) 814 { 815 int i, error; 816 817 error = 0; 818 if (sc->an_config.an_authtype & AN_AUTHTYPE_LEAP) 819 nwkey->i_wepon = IEEE80211_NWKEY_EAP; 820 else if (sc->an_config.an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) 821 nwkey->i_wepon = IEEE80211_NWKEY_WEP; 822 else 823 nwkey->i_wepon = IEEE80211_NWKEY_OPEN; 824 if (sc->an_tx_key == -1) 825 nwkey->i_defkid = sc->an_tx_perskey + 1; 826 else 827 nwkey->i_defkid = sc->an_tx_key + 1; 828 if (nwkey->i_key[0].i_keydat == NULL) 829 return 0; 830 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 831 if (nwkey->i_key[i].i_keydat == NULL) 832 continue; 833 /* do not show any keys to non-root user */ 834 if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) != 0) 835 break; 836 nwkey->i_key[i].i_keylen = sc->an_wepkeys[i].an_wep_keylen; 837 if (nwkey->i_key[i].i_keylen < 0) { 838 if (sc->an_perskeylen[i] == 0) 839 nwkey->i_key[i].i_keylen = 0; 840 continue; 841 } 842 if ((error = copyout(sc->an_wepkeys[i].an_wep_key, 843 nwkey->i_key[i].i_keydat, 844 sc->an_wepkeys[i].an_wep_keylen)) != 0) 845 break; 846 } 847 return error; 848 } 849 850 static int 851 an_write_wepkey(struct an_softc *sc, int type, struct an_wepkey *keys, int kid) 852 { 853 int i, error; 854 struct an_ltv_wepkey *akey; 855 856 error = 0; 857 akey = (struct an_ltv_wepkey *)&sc->an_reqbuf; 858 memset(akey, 0, sizeof(struct an_ltv_wepkey)); 859 akey->an_type = type; 860 akey->an_len = sizeof(struct an_ltv_wepkey); 861 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 862 if (keys[i].an_wep_keylen < 0 || 863 keys[i].an_wep_keylen > sizeof(akey->an_key)) 864 continue; 865 akey->an_key_len = keys[i].an_wep_keylen; 866 akey->an_key_index = i; 867 akey->an_mac_addr[0] = 1; /* default mac */ 868 memcpy(akey->an_key, keys[i].an_wep_key, akey->an_key_len); 869 error = an_write_record(sc, (struct an_ltv_gen *)akey); 870 if (error) 871 return error; 872 } 873 if (kid >= 0) { 874 akey->an_key_index = 0xffff; 875 akey->an_mac_addr[0] = kid; 876 akey->an_key_len = 0; 877 memset(akey->an_key, 0, sizeof(akey->an_key)); 878 error = an_write_record(sc, (struct an_ltv_gen *)akey); 879 } 880 return error; 881 } 882 883 #ifdef IFM_IEEE80211 884 static int 885 an_media_change(struct ifnet *ifp) 886 { 887 struct an_softc *sc = ifp->if_softc; 888 struct ifmedia_entry *ime; 889 int error; 890 891 error = 0; 892 ime = sc->sc_media.ifm_cur; 893 switch (IFM_SUBTYPE(ime->ifm_media)) { 894 case IFM_AUTO: 895 sc->an_tx_rate = 0; 896 break; 897 case IFM_IEEE80211_DS1: 898 sc->an_tx_rate = AN_RATE_1MBPS; 899 break; 900 case IFM_IEEE80211_DS2: 901 sc->an_tx_rate = AN_RATE_2MBPS; 902 break; 903 case IFM_IEEE80211_DS5: 904 sc->an_tx_rate = AN_RATE_5_5MBPS; 905 break; 906 case IFM_IEEE80211_DS11: 907 sc->an_tx_rate = AN_RATE_11MBPS; 908 break; 909 } 910 if (ime->ifm_media & IFM_IEEE80211_ADHOC) 911 sc->an_config.an_opmode = AN_OPMODE_IBSS_ADHOC; 912 else 913 sc->an_config.an_opmode = AN_OPMODE_INFRASTRUCTURE_STATION; 914 /* 915 * XXX: how to set txrate for the firmware? 916 * There is a struct defined as an_txframe, which is used nowhere. 917 * Perhaps we need to change the transmit mode from 802.3 to native. 918 */ 919 920 /* we cannot return ENETRESET here */ 921 if (sc->sc_enabled) 922 error = an_init(ifp); 923 return error; 924 } 925 926 static void 927 an_media_status(ifp, imr) 928 struct ifnet *ifp; 929 struct ifmediareq *imr; 930 { 931 struct an_softc *sc = ifp->if_softc; 932 933 imr->ifm_status = IFM_AVALID; 934 imr->ifm_active = IFM_IEEE80211; 935 if (sc->sc_enabled && sc->an_associated) { 936 imr->ifm_status |= IFM_ACTIVE; 937 switch (sc->an_status.an_current_tx_rate) { 938 case 0: 939 imr->ifm_active |= IFM_AUTO; 940 break; 941 case AN_RATE_1MBPS: 942 imr->ifm_active |= IFM_IEEE80211_DS1; 943 break; 944 case AN_RATE_2MBPS: 945 imr->ifm_active |= IFM_IEEE80211_DS2; 946 break; 947 case AN_RATE_5_5MBPS: 948 imr->ifm_active |= IFM_IEEE80211_DS5; 949 break; 950 case AN_RATE_11MBPS: 951 imr->ifm_active |= IFM_IEEE80211_DS11; 952 break; 953 } 954 } 955 if ((sc->an_config.an_opmode & 0x0f) == AN_OPMODE_IBSS_ADHOC) 956 imr->ifm_active |= IFM_IEEE80211_ADHOC; 957 } 958 #endif /* IFM_IEEE80211 */ 959 960 static int 961 an_init_tx_ring(struct an_softc *sc) 962 { 963 int i, id; 964 965 for (i = 0; i < AN_TX_RING_CNT; i++) { 966 if (an_alloc_nicmem(sc, 967 ETHER_MAX_LEN + ETHER_TYPE_LEN + AN_802_11_OFFSET, &id)) 968 return ENOMEM; 969 sc->an_rdata.an_tx_fids[i] = id; 970 sc->an_rdata.an_tx_ring[i] = 0; 971 } 972 973 sc->an_rdata.an_tx_prod = 0; 974 sc->an_rdata.an_tx_cons = 0; 975 return 0; 976 } 977 978 static int 979 an_init(struct ifnet *ifp) 980 { 981 struct an_softc *sc = (struct an_softc *)ifp->if_softc; 982 983 if (sc->sc_enabled) { 984 an_stop(ifp, 0); 985 } else { 986 if (sc->sc_enable) 987 (*sc->sc_enable)(sc); 988 sc->sc_enabled = 1; 989 an_wait(sc); 990 } 991 992 sc->an_associated = 0; 993 994 /* Allocate the TX buffers */ 995 if (an_init_tx_ring(sc)) { 996 an_reset(sc); 997 if (an_init_tx_ring(sc)) { 998 printf("%s: tx buffer allocation failed\n", 999 sc->an_dev.dv_xname); 1000 an_stop(ifp, 1); 1001 return ENOMEM; 1002 } 1003 } 1004 1005 /* Set our MAC address. */ 1006 memcpy(sc->an_config.an_macaddr, sc->an_caps.an_oemaddr, 1007 ETHER_ADDR_LEN); 1008 1009 if (ifp->if_flags & IFF_MULTICAST) 1010 sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR; 1011 else if (ifp->if_flags & IFF_BROADCAST) 1012 sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR; 1013 else 1014 sc->an_config.an_rxmode = AN_RXMODE_ADDR; 1015 1016 /* Set the ssid list */ 1017 sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 1018 sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist); 1019 if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 1020 printf("%s: failed to set ssid list\n", sc->an_dev.dv_xname); 1021 an_stop(ifp, 1); 1022 return ENXIO; 1023 } 1024 1025 /* Set the AP list */ 1026 sc->an_aplist.an_type = AN_RID_APLIST; 1027 sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 1028 if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 1029 printf("%s: failed to set AP list\n", sc->an_dev.dv_xname); 1030 an_stop(ifp, 1); 1031 return ENXIO; 1032 } 1033 1034 /* Set the configuration in the NIC */ 1035 sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 1036 sc->an_config.an_type = AN_RID_GENCONFIG; 1037 if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 1038 printf("%s: failed to set configuration\n", sc->an_dev.dv_xname); 1039 an_stop(ifp, 1); 1040 return ENXIO; 1041 } 1042 1043 /* Set the WEP Keys */ 1044 if ((sc->an_config.an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) != 0) 1045 an_write_wepkey(sc, AN_RID_WEP_VOLATILE, sc->an_wepkeys, 1046 sc->an_tx_key); 1047 1048 /* Enable the MAC */ 1049 if (an_cmd(sc, AN_CMD_ENABLE, 0)) { 1050 printf("%s: failed to enable MAC\n", sc->an_dev.dv_xname); 1051 an_stop(ifp, 1); 1052 return ENXIO; 1053 } 1054 1055 an_cmd(sc, AN_CMD_SET_MODE, (ifp->if_flags & IFF_PROMISC) ? 0xffff : 0); 1056 1057 /* enable interrupts */ 1058 CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS); 1059 1060 ifp->if_flags |= IFF_RUNNING; 1061 ifp->if_flags &= ~IFF_OACTIVE; 1062 1063 callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 1064 return 0; 1065 } 1066 1067 static void 1068 an_start(struct ifnet *ifp) 1069 { 1070 struct an_softc *sc = (struct an_softc *)ifp->if_softc; 1071 struct mbuf *m0 = NULL, *m; 1072 struct an_txframe_802_3 tx_frame_802_3; 1073 struct ether_header *eh; 1074 int id, idx; 1075 u_int16_t txctl; 1076 1077 if (!sc->sc_enabled) 1078 return; 1079 1080 if (ifp->if_flags & IFF_OACTIVE) 1081 return; 1082 1083 if (!sc->an_associated) 1084 return; 1085 1086 idx = sc->an_rdata.an_tx_prod; 1087 memset(&tx_frame_802_3, 0, sizeof(tx_frame_802_3)); 1088 1089 for (;;) { 1090 IFQ_POLL(&ifp->if_snd, m0); 1091 if (m0 == NULL) 1092 break; 1093 if (sc->an_rdata.an_tx_ring[idx] != 0) 1094 break; 1095 id = sc->an_rdata.an_tx_fids[idx]; 1096 IFQ_DEQUEUE(&ifp->if_snd, m0); 1097 #if NBPFILTER > 0 1098 /* 1099 * If there's a BPF listner, bounce a copy of 1100 * this frame to him. 1101 */ 1102 if (ifp->if_bpf) 1103 bpf_mtap(ifp->if_bpf, m0); 1104 #endif 1105 1106 txctl = AN_TXCTL_8023; 1107 /* write the txctl only */ 1108 an_write_data(sc, id, 0x08, (caddr_t)&txctl, sizeof(txctl)); 1109 1110 eh = mtod(m0, struct ether_header *); 1111 memcpy(tx_frame_802_3.an_tx_dst_addr, eh->ether_dhost, 1112 ETHER_ADDR_LEN); 1113 memcpy(tx_frame_802_3.an_tx_src_addr, eh->ether_shost, 1114 ETHER_ADDR_LEN); 1115 tx_frame_802_3.an_tx_802_3_payload_len = 1116 m0->m_pkthdr.len - ETHER_ADDR_LEN * 2; 1117 m_adj(m0, ETHER_ADDR_LEN * 2); 1118 1119 /* 802_3 header */ 1120 an_write_data(sc, id, AN_802_3_OFFSET, 1121 (caddr_t)&tx_frame_802_3, sizeof(struct an_txframe_802_3)); 1122 for (m = m0; m != NULL; m = m->m_next) 1123 an_write_data(sc, id, -1, mtod(m, caddr_t), m->m_len); 1124 m_freem(m0); 1125 m0 = NULL; 1126 1127 sc->an_rdata.an_tx_ring[idx] = id; 1128 if (an_cmd(sc, AN_CMD_TX, id)) 1129 printf("%s: xmit failed\n", sc->an_dev.dv_xname); 1130 1131 AN_INC(idx, AN_TX_RING_CNT); 1132 } 1133 1134 if (m0 != NULL) 1135 ifp->if_flags |= IFF_OACTIVE; 1136 1137 sc->an_rdata.an_tx_prod = idx; 1138 1139 /* 1140 * Set a timeout in case the chip goes out to lunch. 1141 */ 1142 ifp->if_timer = 5; 1143 } 1144 1145 void 1146 an_stop(struct ifnet *ifp, int disable) 1147 { 1148 struct an_softc *sc = (struct an_softc *)ifp->if_softc; 1149 int i; 1150 1151 callout_stop(&sc->an_stat_ch); 1152 1153 ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 1154 ifp->if_timer = 0; 1155 1156 if (!sc->sc_enabled) 1157 return; 1158 1159 an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0); 1160 CSR_WRITE_2(sc, AN_INT_EN, 0); 1161 an_cmd(sc, AN_CMD_DISABLE, 0); 1162 1163 for (i = 0; i < AN_TX_RING_CNT; i++) 1164 an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]); 1165 1166 if (disable) { 1167 if (sc->sc_disable) 1168 (*sc->sc_disable)(sc); 1169 sc->sc_enabled = 0; 1170 } 1171 } 1172 1173 static void 1174 an_watchdog(struct ifnet *ifp) 1175 { 1176 struct an_softc *sc; 1177 1178 sc = ifp->if_softc; 1179 if (!sc->sc_enabled) 1180 return; 1181 1182 printf("%s: device timeout\n", sc->an_dev.dv_xname); 1183 1184 an_reset(sc); 1185 an_init(ifp); 1186 1187 ifp->if_oerrors++; 1188 return; 1189 } 1190 1191 /* 1192 * Low level functions 1193 */ 1194 1195 static void 1196 an_rxeof(struct an_softc *sc) 1197 { 1198 struct ifnet *ifp = &sc->arpcom.ec_if; 1199 struct ether_header *eh; 1200 #ifdef ANCACHE 1201 struct an_rxframe rx_frame; 1202 #endif 1203 struct an_rxframe_802_3 rx_frame_802_3; 1204 struct mbuf *m; 1205 int id, error = 0; 1206 1207 1208 id = CSR_READ_2(sc, AN_RX_FID); 1209 1210 MGETHDR(m, M_DONTWAIT, MT_DATA); 1211 if (m == NULL) { 1212 ifp->if_ierrors++; 1213 return; 1214 } 1215 MCLGET(m, M_DONTWAIT); 1216 if (!(m->m_flags & M_EXT)) { 1217 m_freem(m); 1218 ifp->if_ierrors++; 1219 return; 1220 } 1221 1222 m->m_pkthdr.rcvif = ifp; 1223 1224 /* Align the data after the ethernet header */ 1225 m->m_data = (caddr_t) ALIGN(m->m_data + sizeof(struct ether_header)) - 1226 sizeof(struct ether_header); 1227 1228 eh = mtod(m, struct ether_header *); 1229 1230 #ifdef ANCACHE 1231 /* Read NIC frame header */ 1232 if (an_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) { 1233 ifp->if_ierrors++; 1234 return; 1235 } 1236 #endif 1237 /* Read in the 802_3 frame header */ 1238 if (an_read_data(sc, id, AN_802_3_OFFSET, (caddr_t)&rx_frame_802_3, 1239 sizeof(rx_frame_802_3))) { 1240 ifp->if_ierrors++; 1241 return; 1242 } 1243 1244 if (rx_frame_802_3.an_rx_802_3_status != 0) { 1245 ifp->if_ierrors++; 1246 return; 1247 } 1248 1249 /* Check for insane frame length */ 1250 if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) { 1251 ifp->if_ierrors++; 1252 return; 1253 } 1254 1255 m->m_pkthdr.len = m->m_len = 1256 rx_frame_802_3.an_rx_802_3_payload_len + ETHER_ADDR_LEN * 2; 1257 1258 memcpy(&eh->ether_dhost, &rx_frame_802_3.an_rx_dst_addr, 1259 ETHER_ADDR_LEN); 1260 memcpy(&eh->ether_shost, &rx_frame_802_3.an_rx_src_addr, 1261 ETHER_ADDR_LEN); 1262 1263 /* in mbuf header type is just before payload */ 1264 error = an_read_data(sc, id, -1, (caddr_t)&(eh->ether_type), 1265 rx_frame_802_3.an_rx_802_3_payload_len); 1266 1267 if (error) { 1268 m_freem(m); 1269 ifp->if_ierrors++; 1270 return; 1271 } 1272 1273 ifp->if_ipackets++; 1274 1275 /* Receive packet. */ 1276 #ifdef ANCACHE 1277 an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength); 1278 #endif 1279 #if NBPFILTER > 0 1280 if (ifp->if_bpf) 1281 bpf_mtap(ifp->if_bpf, m); 1282 #endif 1283 (*ifp->if_input)(ifp, m); 1284 } 1285 1286 static void 1287 an_txeof(struct an_softc *sc, int status) 1288 { 1289 struct ifnet *ifp = &sc->arpcom.ec_if; 1290 int i, id; 1291 1292 ifp->if_timer = 0; 1293 ifp->if_flags &= ~IFF_OACTIVE; 1294 1295 id = CSR_READ_2(sc, AN_TX_CMP_FID); 1296 1297 if (status & AN_EV_TX_EXC) 1298 ifp->if_oerrors++; 1299 else 1300 ifp->if_opackets++; 1301 1302 /* fix from Doug Ambrisko -wsr */ 1303 for (i = 0; i < AN_TX_RING_CNT; i++) { 1304 if (id == sc->an_rdata.an_tx_ring[i]) { 1305 sc->an_rdata.an_tx_ring[i] = 0; 1306 break; 1307 } 1308 } 1309 if (i != sc->an_rdata.an_tx_cons) { 1310 if (ifp->if_flags & IFF_DEBUG) 1311 printf("%s: id mismatch: id %x, " 1312 "expected %x(%d), actual %x(%d)\n", 1313 sc->an_dev.dv_xname, id, 1314 sc->an_rdata.an_tx_ring[sc->an_rdata.an_tx_cons], 1315 sc->an_rdata.an_tx_cons, id, i); 1316 } 1317 1318 AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT); 1319 1320 return; 1321 } 1322 1323 /* 1324 * We abuse the stats updater to check the current NIC status. This 1325 * is important because we don't want to allow transmissions until 1326 * the NIC has synchronized to the current cell (either as the master 1327 * in an ad-hoc group, or as a station connected to an access point). 1328 */ 1329 void 1330 an_stats_update(void *xsc) 1331 { 1332 struct an_softc *sc = xsc; 1333 1334 if (sc->sc_enabled) { 1335 sc->an_status.an_type = AN_RID_STATUS; 1336 sc->an_status.an_len = sizeof(struct an_ltv_status); 1337 if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_status) 1338 == 0) { 1339 if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC) 1340 sc->an_associated = 1; 1341 else 1342 sc->an_associated = 0; 1343 #if 0 1344 /* Don't do this while we're transmitting */ 1345 if (sc->arpcom.ec_if.if_flags & IFF_OACTIVE) { 1346 sc->an_stats.an_len = 1347 sizeof(struct an_ltv_stats); 1348 sc->an_stats.an_type = AN_RID_32BITS_CUM; 1349 an_read_record(sc, 1350 (struct an_ltv_gen *)&sc->an_stats.an_len); 1351 } 1352 #endif 1353 } 1354 } 1355 callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 1356 } 1357 1358 int 1359 an_intr(void *arg) 1360 { 1361 struct an_softc *sc = arg; 1362 struct ifnet *ifp = &sc->arpcom.ec_if; 1363 u_int16_t status; 1364 1365 if (!sc->sc_enabled) 1366 return 0; 1367 1368 if (!(ifp->if_flags & IFF_UP)) { 1369 CSR_WRITE_2(sc, AN_EVENT_ACK, 0xFFFF); 1370 CSR_WRITE_2(sc, AN_INT_EN, 0); 1371 return 0; 1372 } 1373 1374 /* Disable interrupts. */ 1375 CSR_WRITE_2(sc, AN_INT_EN, 0); 1376 1377 while ((status = (CSR_READ_2(sc, AN_EVENT_STAT) & AN_INTRS)) != 0) { 1378 if (status & AN_EV_RX) { 1379 an_rxeof(sc); 1380 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX); 1381 status &= ~AN_EV_RX; 1382 } 1383 if (status & (AN_EV_TX | AN_EV_TX_EXC)) { 1384 an_txeof(sc, status); 1385 CSR_WRITE_2(sc, AN_EVENT_ACK, 1386 status & (AN_EV_TX | AN_EV_TX_EXC)); 1387 status &= ~(AN_EV_TX | AN_EV_TX_EXC); 1388 } 1389 if (status & AN_EV_LINKSTAT) { 1390 if (CSR_READ_2(sc, AN_LINKSTAT) == 1391 AN_LINKSTAT_ASSOCIATED) 1392 sc->an_associated = 1; 1393 else 1394 sc->an_associated = 0; 1395 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT); 1396 status &= ~AN_EV_LINKSTAT; 1397 } 1398 #if 0 1399 if (status & AN_EV_CMD) { 1400 wakeup(sc); 1401 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD); 1402 status &= ~AN_EV_CMD; 1403 } 1404 #endif 1405 if (status) 1406 CSR_WRITE_2(sc, AN_EVENT_ACK, status); 1407 } 1408 1409 /* Re-enable interrupts. */ 1410 CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS); 1411 1412 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0) 1413 an_start(ifp); 1414 1415 return 1; 1416 } 1417 1418 static int 1419 an_cmd(struct an_softc *sc, int cmd, int val) 1420 { 1421 int i, stat; 1422 1423 /* make sure that previous command completed */ 1424 if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) { 1425 if (sc->arpcom.ec_if.if_flags & IFF_DEBUG) 1426 printf("%s: command 0x%x busy\n", sc->an_dev.dv_xname, 1427 CSR_READ_2(sc, AN_COMMAND)); 1428 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY); 1429 } 1430 1431 CSR_WRITE_2(sc, AN_PARAM0, val); 1432 CSR_WRITE_2(sc, AN_PARAM1, 0); 1433 CSR_WRITE_2(sc, AN_PARAM2, 0); 1434 CSR_WRITE_2(sc, AN_COMMAND, cmd); 1435 1436 for (i = 0; i < AN_TIMEOUT; i++) { 1437 if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD) 1438 break; 1439 /* make sure the command is accepted */ 1440 if (CSR_READ_2(sc, AN_COMMAND) == cmd) 1441 CSR_WRITE_2(sc, AN_COMMAND, cmd); 1442 DELAY(10); 1443 } 1444 1445 stat = CSR_READ_2(sc, AN_STATUS); 1446 1447 /* clear stuck command busy if necessary */ 1448 if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) 1449 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY); 1450 1451 /* Ack the command */ 1452 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD); 1453 1454 if (i == AN_TIMEOUT) { 1455 if (sc->arpcom.ec_if.if_flags & IFF_DEBUG) 1456 printf("%s: command 0x%x param 0x%x timeout\n", 1457 sc->an_dev.dv_xname, cmd, val); 1458 return ETIMEDOUT; 1459 } 1460 if (stat & AN_STAT_CMD_RESULT) { 1461 if (sc->arpcom.ec_if.if_flags & IFF_DEBUG) 1462 printf("%s: command 0x%x param 0x%x stat 0x%x\n", 1463 sc->an_dev.dv_xname, cmd, val, stat); 1464 return EIO; 1465 } 1466 1467 return 0; 1468 } 1469 1470 /* 1471 * This reset sequence may look a little strange, but this is the 1472 * most reliable method I've found to really kick the NIC in the 1473 * head and force it to reboot correctly. 1474 */ 1475 static void 1476 an_reset(struct an_softc *sc) 1477 { 1478 1479 if (!sc->sc_enabled) 1480 return; 1481 1482 an_cmd(sc, AN_CMD_ENABLE, 0); 1483 an_cmd(sc, AN_CMD_FW_RESTART, 0); 1484 an_cmd(sc, AN_CMD_NOOP2, 0); 1485 1486 if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) 1487 printf("%s: reset failed\n", sc->an_dev.dv_xname); 1488 1489 an_cmd(sc, AN_CMD_DISABLE, 0); 1490 } 1491 1492 /* 1493 * Wait for firmware come up after power enabled. 1494 */ 1495 static void 1496 an_wait(struct an_softc *sc) 1497 { 1498 int i; 1499 1500 CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_NOOP2); 1501 for (i = 0; i < 3*hz; i++) { 1502 if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD) 1503 break; 1504 (void)tsleep(sc, PWAIT, "anatch", 1); 1505 } 1506 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD); 1507 } 1508 1509 /* 1510 * Read an LTV record from the NIC. 1511 */ 1512 static int 1513 an_read_record(struct an_softc *sc, struct an_ltv_gen *ltv) 1514 { 1515 u_int16_t *ptr; 1516 int i, len; 1517 1518 if (ltv->an_len == 0 || ltv->an_type == 0) 1519 return EINVAL; 1520 1521 /* Tell the NIC to enter record read mode. */ 1522 if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) 1523 return EIO; 1524 1525 /* Seek to the record. */ 1526 if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) 1527 return EIO; 1528 1529 /* 1530 * Read the length and record type and make sure they 1531 * match what we expect (this verifies that we have enough 1532 * room to hold all of the returned data). 1533 */ 1534 len = CSR_READ_2(sc, AN_DATA1); 1535 if (len > ltv->an_len) { 1536 if (sc->arpcom.ec_if.if_flags & IFF_DEBUG) 1537 printf("%s: RID 0x%04x record length mismatch" 1538 "-- expected %d, got %d\n", sc->an_dev.dv_xname, 1539 ltv->an_type, ltv->an_len, len); 1540 return ENOSPC; 1541 } 1542 1543 ltv->an_len = len; 1544 1545 /* Now read the data. */ 1546 ptr = <v->an_val; 1547 for (i = 0; i < (ltv->an_len - 2) >> 1; i++) 1548 ptr[i] = CSR_READ_2(sc, AN_DATA1); 1549 1550 return 0; 1551 } 1552 1553 /* 1554 * Same as read, except we inject data instead of reading it. 1555 */ 1556 static int 1557 an_write_record(struct an_softc *sc, struct an_ltv_gen *ltv) 1558 { 1559 u_int16_t *ptr; 1560 int i; 1561 1562 if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) 1563 return EIO; 1564 1565 if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) 1566 return EIO; 1567 1568 CSR_WRITE_2(sc, AN_DATA1, ltv->an_len-2); 1569 1570 ptr = <v->an_val; 1571 for (i = 0; i < (ltv->an_len - 4) >> 1; i++) 1572 CSR_WRITE_2(sc, AN_DATA1, ptr[i]); 1573 1574 if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type)) 1575 return EIO; 1576 1577 return 0; 1578 } 1579 1580 static int 1581 an_seek(struct an_softc *sc, int id, int off, int chan) 1582 { 1583 int i, selreg, offreg; 1584 1585 switch (chan) { 1586 case AN_BAP0: 1587 selreg = AN_SEL0; 1588 offreg = AN_OFF0; 1589 break; 1590 case AN_BAP1: 1591 selreg = AN_SEL1; 1592 offreg = AN_OFF1; 1593 break; 1594 default: 1595 panic("%s: invalid chan: %x\n", sc->an_dev.dv_xname, chan); 1596 } 1597 1598 CSR_WRITE_2(sc, selreg, id); 1599 CSR_WRITE_2(sc, offreg, off); 1600 1601 for (i = 0; i < AN_TIMEOUT; i++) { 1602 if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR))) 1603 break; 1604 DELAY(10); 1605 } 1606 if (i == AN_TIMEOUT) { 1607 if (sc->arpcom.ec_if.if_flags & IFF_DEBUG) 1608 printf("%s: seek(0x%x, 0x%x, 0x%x) timeout\n", 1609 sc->an_dev.dv_xname, id, off, chan); 1610 return ETIMEDOUT; 1611 } 1612 1613 return 0; 1614 } 1615 1616 static int 1617 an_read_data(struct an_softc *sc, int id, int off, caddr_t buf, int len) 1618 { 1619 int i; 1620 u_int16_t *ptr; 1621 u_int8_t *ptr2; 1622 1623 if (off != -1) { 1624 if (an_seek(sc, id, off, AN_BAP1)) 1625 return EIO; 1626 } 1627 1628 ptr = (u_int16_t *)buf; 1629 for (i = 0; i < len / 2; i++) 1630 ptr[i] = CSR_READ_2(sc, AN_DATA1); 1631 i *= 2; 1632 if (i < len){ 1633 ptr2 = (u_int8_t *)buf; 1634 ptr2[i] = CSR_READ_1(sc, AN_DATA1); 1635 } 1636 1637 return 0; 1638 } 1639 1640 static int 1641 an_write_data(struct an_softc *sc, int id, int off, caddr_t buf, int len) 1642 { 1643 int i; 1644 u_int16_t *ptr; 1645 u_int8_t *ptr2; 1646 1647 if (off != -1) { 1648 if (an_seek(sc, id, off, AN_BAP0)) 1649 return EIO; 1650 } 1651 1652 ptr = (u_int16_t *)buf; 1653 for (i = 0; i < (len / 2); i++) 1654 CSR_WRITE_2(sc, AN_DATA0, ptr[i]); 1655 i *= 2; 1656 if (i < len){ 1657 ptr2 = (u_int8_t *)buf; 1658 CSR_WRITE_1(sc, AN_DATA0, ptr2[i]); 1659 } 1660 1661 return 0; 1662 } 1663 1664 /* 1665 * Allocate a region of memory inside the NIC and zero 1666 * it out. 1667 */ 1668 static int 1669 an_alloc_nicmem(struct an_softc *sc, int len, int *id) 1670 { 1671 int i; 1672 1673 if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) { 1674 printf("%s: failed to allocate %d bytes on NIC\n", 1675 sc->an_dev.dv_xname, len); 1676 return ENOMEM; 1677 } 1678 1679 for (i = 0; i < AN_TIMEOUT; i++) { 1680 if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC) 1681 break; 1682 DELAY(10); 1683 } 1684 1685 if (i == AN_TIMEOUT) 1686 return(ETIMEDOUT); 1687 1688 CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC); 1689 *id = CSR_READ_2(sc, AN_ALLOC_FID); 1690 1691 if (an_seek(sc, *id, 0, AN_BAP0)) 1692 return EIO; 1693 1694 for (i = 0; i < len / 2; i++) 1695 CSR_WRITE_2(sc, AN_DATA0, 0); 1696 1697 return 0; 1698 } 1699 1700 #ifdef ANCACHE 1701 /* Aironet signal strength cache code. 1702 * store signal/noise/quality on per MAC src basis in 1703 * a small fixed cache. The cache wraps if > MAX slots 1704 * used. The cache may be zeroed out to start over. 1705 * Two simple filters exist to reduce computation: 1706 * 1. ip only (literally 0x800) which may be used 1707 * to ignore some packets. It defaults to ip only. 1708 * it could be used to focus on broadcast, non-IP 802.11 beacons. 1709 * 2. multicast/broadcast only. This may be used to 1710 * ignore unicast packets and only cache signal strength 1711 * for multicast/broadcast packets (beacons); e.g., Mobile-IP 1712 * beacons and not unicast traffic. 1713 * 1714 * The cache stores (MAC src(index), IP src (major clue), signal, 1715 * quality, noise) 1716 * 1717 * No apologies for storing IP src here. It's easy and saves much 1718 * trouble elsewhere. The cache is assumed to be INET dependent, 1719 * although it need not be. 1720 * 1721 * Note: the Aironet only has a single byte of signal strength value 1722 * in the rx frame header, and it's not scaled to anything sensible. 1723 * This is kind of lame, but it's all we've got. 1724 */ 1725 1726 #ifdef documentation 1727 1728 int an_sigitems; /* number of cached entries */ 1729 struct an_sigcache an_sigcache[MAXANCACHE]; /* array of cache entries */ 1730 int an_nextitem; /* index/# of entries */ 1731 1732 1733 #endif 1734 1735 /* control variables for cache filtering. Basic idea is 1736 * to reduce cost (e.g., to only Mobile-IP agent beacons 1737 * which are broadcast or multicast). Still you might 1738 * want to measure signal strength anth unicast ping packets 1739 * on a pt. to pt. ant. setup. 1740 */ 1741 /* set true if you want to limit cache items to broadcast/mcast 1742 * only packets (not unicast). Useful for mobile-ip beacons which 1743 * are broadcast/multicast at network layer. Default is all packets 1744 * so ping/unicast anll work say anth pt. to pt. antennae setup. 1745 */ 1746 static int an_cache_mcastonly = 0; 1747 #if 0 1748 SYSCTL_INT(_machdep, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW, 1749 &an_cache_mcastonly, 0, ""); 1750 #endif 1751 1752 /* set true if you want to limit cache items to IP packets only 1753 */ 1754 static int an_cache_iponly = 1; 1755 #if 0 1756 SYSCTL_INT(_machdep, OID_AUTO, an_cache_iponly, CTLFLAG_RW, 1757 &an_cache_iponly, 0, ""); 1758 #endif 1759 1760 /* 1761 * an_cache_store, per rx packet store signal 1762 * strength in MAC (src) indexed cache. 1763 */ 1764 static 1765 void an_cache_store (sc, eh, m, rx_quality) 1766 struct an_softc *sc; 1767 struct ether_header *eh; 1768 struct mbuf *m; 1769 unsigned short rx_quality; 1770 { 1771 struct ip *ip = 0; 1772 int i; 1773 static int cache_slot = 0; /* use this cache entry */ 1774 static int wrapindex = 0; /* next "free" cache entry */ 1775 int saanp=0; 1776 1777 /* filters: 1778 * 1. ip only 1779 * 2. configurable filter to throw out unicast packets, 1780 * keep multicast only. 1781 */ 1782 1783 if ((ntohs(eh->ether_type) == 0x800)) { 1784 saanp = 1; 1785 } 1786 1787 /* filter for ip packets only 1788 */ 1789 if (an_cache_iponly && !saanp) { 1790 return; 1791 } 1792 1793 /* filter for broadcast/multicast only 1794 */ 1795 if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 1796 return; 1797 } 1798 1799 #ifdef SIGDEBUG 1800 printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n", 1801 rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff); 1802 #endif 1803 1804 /* find the ip header. we want to store the ip_src 1805 * address. 1806 */ 1807 if (saanp) { 1808 ip = (struct ip *)(mtod(m, caddr_t) + 14); 1809 } 1810 1811 /* do a linear search for a matching MAC address 1812 * in the cache table 1813 * . MAC address is 6 bytes, 1814 * . var w_nextitem holds total number of entries already cached 1815 */ 1816 for(i = 0; i < sc->an_nextitem; i++) { 1817 if (!memcmp(eh->ether_shost , sc->an_sigcache[i].macsrc, 6 )) { 1818 /* Match!, 1819 * so we already have this entry, 1820 * update the data 1821 */ 1822 break; 1823 } 1824 } 1825 1826 /* did we find a matching mac address? 1827 * if yes, then overwrite a previously existing cache entry 1828 */ 1829 if (i < sc->an_nextitem ) { 1830 cache_slot = i; 1831 } 1832 /* else, have a new address entry,so 1833 * add this new entry, 1834 * if table full, then we need to replace LRU entry 1835 */ 1836 else { 1837 1838 /* check for space in cache table 1839 * note: an_nextitem also holds number of entries 1840 * added in the cache table 1841 */ 1842 if (sc->an_nextitem < MAXANCACHE ) { 1843 cache_slot = sc->an_nextitem; 1844 sc->an_nextitem++; 1845 sc->an_sigitems = sc->an_nextitem; 1846 } 1847 /* no space found, so simply wrap anth wrap index 1848 * and "zap" the next entry 1849 */ 1850 else { 1851 if (wrapindex == MAXANCACHE) { 1852 wrapindex = 0; 1853 } 1854 cache_slot = wrapindex++; 1855 } 1856 } 1857 1858 /* invariant: cache_slot now points at some slot 1859 * in cache. 1860 */ 1861 if (cache_slot < 0 || cache_slot >= MAXANCACHE) { 1862 log(LOG_ERR, "an_cache_store, bad index: %d of " 1863 "[0..%d], gross cache error\n", 1864 cache_slot, MAXANCACHE); 1865 return; 1866 } 1867 1868 /* store items in cache 1869 * .ip source address 1870 * .mac src 1871 * .signal, etc. 1872 */ 1873 if (saanp) { 1874 sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 1875 } 1876 memcpy(sc->an_sigcache[cache_slot].macsrc, eh->ether_shost, 6); 1877 1878 sc->an_sigcache[cache_slot].signal = rx_quality; 1879 1880 return; 1881 } 1882 #endif 1883