📄 an.c
字号:
CSR_WRITE_2(sc, AN_PARAM0, val); CSR_WRITE_2(sc, AN_PARAM1, 0); CSR_WRITE_2(sc, AN_PARAM2, 0); DELAY(10); CSR_WRITE_2(sc, AN_COMMAND, cmd); DELAY(10); for (i = AN_TIMEOUT; i--; DELAY(10)) { if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD) break; else { if (CSR_READ_2(sc, AN_COMMAND) == cmd) { DELAY(10); CSR_WRITE_2(sc, AN_COMMAND, cmd); } } } stat = CSR_READ_2(sc, AN_STATUS); /* clear stuck command busy if needed */ if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) { CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY); } /* Ack the command */ CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD); if (i <= 0) return(ETIMEDOUT); if (stat & AN_STAT_CMD_RESULT) return(EIO); return(0);}/* * This reset sequence may look a little strange, but this is the * most reliable method I've found to really kick the NIC in the * head and force it to reboot correctly. */voidan_reset(sc) struct an_softc *sc;{ if (sc->an_gone) return;/*printf("ena ");*/ an_cmd(sc, AN_CMD_ENABLE, 0);/* printf("rst ");*/ an_cmd(sc, AN_CMD_FW_RESTART, 0);/*printf("nop ");*/ an_cmd(sc, AN_CMD_NOOP2, 0); if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) printf("%s: reset failed\n", sc->sc_dev.dv_xname); an_cmd(sc, AN_CMD_DISABLE, 0);}/* * Read an LTV record from the NIC. */intan_read_record(sc, ltv) struct an_softc *sc; struct an_ltv_gen *ltv;{ u_int16_t *ptr, len; int i; u_int16_t ltv_data_length; if (ltv->an_len < 4 || ltv->an_type == 0) return(EINVAL); /* Tell the NIC to enter record read mode. */ if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) { printf("%s: RID 0x%04x access failed\n", sc->sc_dev.dv_xname, ltv->an_type); return(EIO); } /* Seek to the record. */ if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) { printf("%s: RID 0x%04x seek to record failed\n", sc->sc_dev.dv_xname, ltv->an_type); return(EIO); } /* * Read the length to make sure it * matches what we expect (this verifies that we have enough * room to hold all of the returned data). */ len = CSR_READ_2(sc, AN_DATA1); /* * Work out record's data length, which is struct length - type word * as we have just read the length. */ ltv_data_length = ltv->an_len - sizeof(u_int16_t); if (len > ltv_data_length) { printf("%s: RID 0x%04x record length mismatch -- expected %d, " "got %d\n", sc->sc_dev.dv_xname, ltv->an_type, ltv_data_length, len); return(ENOSPC); } /* Now read the data. */ ptr = ltv->an_val; for (i = 0; i < (len - 1) >> 1; i++) ptr[i] = CSR_READ_2(sc, AN_DATA1);#if BYTE_ORDER == BIG_ENDIAN switch (ltv->an_type) { case AN_RID_GENCONFIG: an_swap16(<v->an_val[4], 7); /* an_macaddr, an_rates */ an_swap16(<v->an_val[63], 8); /* an_nodename */ break; case AN_RID_SSIDLIST: an_swap16(<v->an_val[1], 16); /* an_ssid1 */ an_swap16(<v->an_val[18], 16); /* an_ssid2 */ an_swap16(<v->an_val[35], 16); /* an_ssid3 */ break; case AN_RID_APLIST: an_swap16(ltv->an_val, 12); break; case AN_RID_DRVNAME: an_swap16(ltv->an_val, 8); break; case AN_RID_CAPABILITIES: an_swap16(ltv->an_val, 2); /* an_oui */ an_swap16(<v->an_val[3], 34); /* an_manufname .. an_aironetaddr */ an_swap16(<v->an_val[39], 8); /* an_callid .. an_tx_diversity */ break; case AN_RID_STATUS: an_swap16(<v->an_val[0], 3); /* an_macaddr */ an_swap16(<v->an_val[7], 36); /* an_ssid .. an_prev_bssid3 */ an_swap16(<v->an_val[0x74/2], 2); /* an_ap_ip_addr */ break; case AN_RID_WEP_VOLATILE: case AN_RID_WEP_PERMANENT: an_swap16(<v->an_val[1], 3); /* an_mac_addr */ an_swap16(<v->an_val[5], 6); break; case AN_RID_32BITS_CUM: for (i = 0x60; i--; ) { u_int16_t t = ltv->an_val[i * 2] ^ ltv->an_val[i * 2 + 1]; ltv->an_val[i * 2] ^= t; ltv->an_val[i * 2 + 1] ^= t; } break; }#endif return(0);}/* * Same as read, except we inject data instead of reading it. */intan_write_record(sc, ltv) struct an_softc *sc; struct an_ltv_gen *ltv;{ u_int16_t *ptr; int i; if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) return(EIO); if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) return(EIO);#if BYTE_ORDER == BIG_ENDIAN switch (ltv->an_type) { case AN_RID_GENCONFIG: an_swap16(<v->an_val[4], 7); /* an_macaddr, an_rates */ an_swap16(<v->an_val[63], 8); /* an_nodename */ break; case AN_RID_SSIDLIST: an_swap16(<v->an_val[1], 16); /* an_ssid1 */ an_swap16(<v->an_val[18], 16); /* an_ssid2 */ an_swap16(<v->an_val[35], 16); /* an_ssid3 */ break; case AN_RID_APLIST: an_swap16(ltv->an_val, 12); break; case AN_RID_DRVNAME: an_swap16(ltv->an_val, 8); break; case AN_RID_CAPABILITIES: an_swap16(ltv->an_val, 2); /* an_oui */ an_swap16(<v->an_val[3], 34); /* an_manufname .. an_aironetaddr */ an_swap16(<v->an_val[39], 8); /* an_callid .. an_tx_diversity */ break; case AN_RID_STATUS: an_swap16(<v->an_val[0], 3); /* an_macaddr */ an_swap16(<v->an_val[7], 36); /* an_ssid .. an_prev_bssid3 */ an_swap16(<v->an_val[0x74/2], 2); /* an_ap_ip_addr */ break; case AN_RID_WEP_VOLATILE: case AN_RID_WEP_PERMANENT: an_swap16(<v->an_val[1], 3); /* an_mac_addr */ an_swap16(<v->an_val[5], 6); break; }#endif CSR_WRITE_2(sc, AN_DATA1, ltv->an_len); ptr = ltv->an_val; for (i = 0; i < (ltv->an_len - 1) >> 1; i++) CSR_WRITE_2(sc, AN_DATA1, ptr[i]); if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type)) return(EIO); return(0);}intan_seek(sc, id, off, chan) struct an_softc *sc; int id, off, chan;{ int i; int selreg, offreg; switch (chan) { case AN_BAP0: selreg = AN_SEL0; offreg = AN_OFF0; break; case AN_BAP1: selreg = AN_SEL1; offreg = AN_OFF1; break; default: printf("%s: invalid data path: %x\n", sc->sc_dev.dv_xname, chan); return (EIO); } CSR_WRITE_2(sc, selreg, id); CSR_WRITE_2(sc, offreg, off); for (i = AN_TIMEOUT; i--; DELAY(10)) { if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR))) break; } if (i <= 0) return(ETIMEDOUT); return (0);}intan_read_data(sc, id, off, buf, len) struct an_softc *sc; int id, off; caddr_t buf; int len;{ if (off != -1 && an_seek(sc, id, off, AN_BAP1)) return(EIO); bus_space_read_raw_multi_2(sc->an_btag, sc->an_bhandle, AN_DATA1, buf, len & ~1); if (len & 1) ((u_int8_t *)buf)[len - 1] = CSR_READ_1(sc, AN_DATA1); return (0);}intan_write_data(sc, id, off, buf, len) struct an_softc *sc; int id, off; caddr_t buf; int len;{ if (off != -1 && an_seek(sc, id, off, AN_BAP0)) return(EIO); bus_space_write_raw_multi_2(sc->an_btag, sc->an_bhandle, AN_DATA0, buf, len & ~1); if (len & 1) CSR_WRITE_1(sc, AN_DATA0, ((u_int8_t *)buf)[len - 1]); return (0);}/* * Allocate a region of memory inside the NIC and zero * it out. */intan_alloc_nicmem(sc, len, id) struct an_softc *sc; int len; int *id;{ int i; if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) { printf("%s: failed to allocate %d bytes on NIC\n", sc->sc_dev.dv_xname, len); return(ENOMEM); } for (i = AN_TIMEOUT; i--; DELAY(10)) { if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC) break; } if (i <= 0) return(ETIMEDOUT); CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC); *id = CSR_READ_2(sc, AN_ALLOC_FID); if (an_seek(sc, *id, 0, AN_BAP0)) return(EIO); bus_space_set_multi_2(sc->an_btag, sc->an_bhandle, AN_DATA0, 0, len / 2); CSR_WRITE_1(sc, AN_DATA0, 0); return(0);}voidan_setdef(sc, areq) struct an_softc *sc; struct an_req *areq;{ struct sockaddr_dl *sdl; struct ifaddr *ifa; struct ifnet *ifp; struct an_ltv_genconfig *cfg; struct an_ltv_ssidlist *ssid; struct an_ltv_aplist *ap; struct an_ltv_gen *sp; extern struct ifaddr **ifnet_addrs; ifp = &sc->arpcom.ac_if; switch (areq->an_type) { case AN_RID_GENCONFIG: cfg = (struct an_ltv_genconfig *)areq; ifa = ifnet_addrs[ifp->if_index]; sdl = (struct sockaddr_dl *)ifa->ifa_addr; bcopy((char *)&cfg->an_macaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); bcopy((char *)&cfg->an_macaddr, LLADDR(sdl), ETHER_ADDR_LEN); bcopy((char *)cfg, (char *)&sc->an_config, sizeof(struct an_ltv_genconfig)); break; case AN_RID_SSIDLIST: ssid = (struct an_ltv_ssidlist *)areq; bcopy((char *)ssid, (char *)&sc->an_ssidlist, sizeof(struct an_ltv_ssidlist)); break; case AN_RID_APLIST: ap = (struct an_ltv_aplist *)areq; bcopy((char *)ap, (char *)&sc->an_aplist, sizeof(struct an_ltv_aplist)); break; case AN_RID_TX_SPEED: sp = (struct an_ltv_gen *)areq; sc->an_tx_rate = sp->an_val[0]; break; case AN_RID_WEP_VOLATILE: /* Disable the MAC */ an_cmd(sc, AN_CMD_DISABLE, 0); /* Just write the key, we dont' want to save it */ an_write_record(sc, (struct an_ltv_gen *)areq); /* Turn the MAC back on */ an_cmd(sc, AN_CMD_ENABLE, 0); break; case AN_RID_WEP_PERMANENT: /* Disable the MAC */ // an_cmd(sc, AN_CMD_DISABLE, 0); /* Just write the key, the card will save it in this mode */ an_write_record(sc, (struct an_ltv_gen *)areq); /* Turn the MAC back on */ // an_cmd(sc, AN_CMD_ENABLE, 0); return; break; default: printf("%s: unknown RID: %x\n", sc->sc_dev.dv_xname, areq->an_type); return; } /* Reinitialize the card. */ if (ifp->if_flags & IFF_UP) an_init(sc);}/* * We can't change the NIC configuration while the MAC is enabled, * so in order to turn on RX monitor mode, we have to turn the MAC * off first. */voidan_promisc(sc, promisc) struct an_softc *sc; int promisc;{ struct an_ltv_genconfig genconf; /* Disable the MAC. */ an_cmd(sc, AN_CMD_DISABLE, 0); /* Set RX mode. */ if (promisc && !(sc->an_config.an_rxmode & AN_RXMODE_LAN_MONITOR_CURBSS) ) { sc->an_rxmode = sc->an_config.an_rxmode; sc->an_config.an_rxmode |= AN_RXMODE_LAN_MONITOR_CURBSS; } else { sc->an_config.an_rxmode = sc->an_rxmode; } /* Transfer the configuration to the NIC */ genconf = sc->an_config; genconf.an_len = sizeof(struct an_ltv_genconfig); genconf.an_type = AN_RID_GENCONFIG; if (an_write_record(sc, (struct an_ltv_gen *)&genconf)) { printf("%s: failed to set configuration\n", sc->sc_dev.dv_xname); return; } /* Turn the MAC back on. */ an_cmd(sc, AN_CMD_ENABLE, 0);}intan_ioctl(ifp, command, data) struct ifnet *ifp; u_long command; caddr_t data;{ int s, error = 0; struct an_softc *sc; struct an_req areq; struct ifreq *ifr; struct proc *p = curproc; struct ifaddr *ifa = (struct ifaddr *)data; s = splimp(); sc = ifp->if_softc; ifr = (struct ifreq *)data; if (sc->an_gone) { splx(s); return(ENODEV); } if ((error = ether_ioctl(ifp, &sc->arpcom, command, data)) > 0) { splx(s); return error; } switch(command) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: an_init(sc); arp_ifinit(&sc->arpcom, ifa); break;#endif default: an_init(sc); break; } break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { if (ifp->if_flags & IFF_RUNNING && ifp->if_flags & IFF_PROMISC && !(sc->an_if_flags & IFF_PROMISC)) { an_promisc(sc, 1); } else if (ifp->if_flags & IFF_RUNNING && !(ifp->if_flags & IFF_PROMISC) && sc->an_if_flags & IFF_PROMISC) { an_promisc(sc, 0); an_reset(sc); } an_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) an_stop(sc); } sc->an_if_flags = ifp->if_flags; error = 0; break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command); break; case SIOCADDMULTI: case SIOCDELMULTI: /* The Aironet has no multicast filter. */ error = 0; break; case SIOCGAIRONET: error = copyin(ifr->ifr_data, &areq, sizeof(areq)); if (error) break;#ifdef ANCACHE if (areq.an_type == AN_RID_ZERO_CACHE) { error = suser(p->p_ucred, &p->p_acflag); if (error) break; sc->an_sigitems = sc->an_nextitem = 0; break; } else if (areq.an_type == AN_RID_READ_CACHE) { char *pt = (char *)&areq.an_val; bcopy((char *)&sc->an_sigitems, (char *)pt, sizeof(int)); pt += sizeof(int); areq.an_len = sizeof(int) / 2; bcopy((char *)&sc->an_sigcache, (char *)pt, sizeof(struct an_sigcache) * sc->an_sigitems);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -