📄 if_an.c
字号:
MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { ifp->if_ierrors++; return; } MCLGET(m, M_DONTWAIT); if (!(m->m_flags & M_EXT)) { m_freem(m); ifp->if_ierrors++; return; } m->m_pkthdr.rcvif = ifp; /* Read Ethenet encapsulated packet */#ifdef ANCACHE /* Read NIC frame header */ if (an_read_data(sc, id, 0, (caddr_t) & rx_frame, sizeof(rx_frame))) { ifp->if_ierrors++; return; }#endif /* Read in the 802_3 frame header */ if (an_read_data(sc, id, 0x34, (caddr_t) & rx_frame_802_3, sizeof(rx_frame_802_3))) { ifp->if_ierrors++; return; } if (rx_frame_802_3.an_rx_802_3_status != 0) { ifp->if_ierrors++; return; } /* Check for insane frame length */ if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) { ifp->if_ierrors++; return; } m->m_pkthdr.len = m->m_len = rx_frame_802_3.an_rx_802_3_payload_len + 12; eh = mtod(m, struct ether_header *); bcopy((char *)&rx_frame_802_3.an_rx_dst_addr, (char *)&eh->ether_dhost, ETHER_ADDR_LEN); bcopy((char *)&rx_frame_802_3.an_rx_src_addr, (char *)&eh->ether_shost, ETHER_ADDR_LEN); /* in mbuf header type is just before payload */ error = an_read_data(sc, id, 0x44, (caddr_t)&(eh->ether_type), rx_frame_802_3.an_rx_802_3_payload_len); if (error) { m_freem(m); ifp->if_ierrors++; return; } ifp->if_ipackets++; /* Receive packet. */ m_adj(m, sizeof(struct ether_header));#ifdef ANCACHE an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength);#endif ether_input(ifp, eh, m); }}static voidan_txeof(sc, status) struct an_softc *sc; int status;{ struct ifnet *ifp; int id, i; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; id = CSR_READ_2(sc, AN_TX_CMP_FID); if (status & AN_EV_TX_EXC) { ifp->if_oerrors++; } else ifp->if_opackets++; for (i = 0; i < AN_TX_RING_CNT; i++) { if (id == sc->an_rdata.an_tx_ring[i]) { sc->an_rdata.an_tx_ring[i] = 0; break; } } AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT); return;}/* * We abuse the stats updater to check the current NIC status. This * is important because we don't want to allow transmissions until * the NIC has synchronized to the current cell (either as the master * in an ad-hoc group, or as a station connected to an access point). */voidan_stats_update(xsc) void *xsc;{ struct an_softc *sc; struct ifnet *ifp; int s; s = splimp(); sc = xsc; ifp = &sc->arpcom.ac_if; sc->an_status.an_type = AN_RID_STATUS; sc->an_status.an_len = sizeof(struct an_ltv_status); an_read_record(sc, (struct an_ltv_gen *)&sc->an_status); if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC) sc->an_associated = 1; else sc->an_associated = 0; /* Don't do this while we're transmitting */ if (ifp->if_flags & IFF_OACTIVE) { sc->an_stat_ch = timeout(an_stats_update, sc, hz); splx(s); return; } sc->an_stats.an_len = sizeof(struct an_ltv_stats); sc->an_stats.an_type = AN_RID_32BITS_CUM; an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len); sc->an_stat_ch = timeout(an_stats_update, sc, hz); splx(s); return;}voidan_intr(xsc) void *xsc;{ struct an_softc *sc; struct ifnet *ifp; u_int16_t status; sc = (struct an_softc*)xsc; if (sc->an_gone) return; ifp = &sc->arpcom.ac_if; /* Disable interrupts. */ CSR_WRITE_2(sc, AN_INT_EN, 0); status = CSR_READ_2(sc, AN_EVENT_STAT); CSR_WRITE_2(sc, AN_EVENT_ACK, ~AN_INTRS); if (status & AN_EV_AWAKE) { CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_AWAKE); } if (status & AN_EV_LINKSTAT) { if (CSR_READ_2(sc, AN_LINKSTAT) == AN_LINKSTAT_ASSOCIATED) sc->an_associated = 1; else sc->an_associated = 0; CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT); } if (status & AN_EV_RX) { an_rxeof(sc); CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX); } if (status & AN_EV_TX) { an_txeof(sc, status); CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX); } if (status & AN_EV_TX_EXC) { an_txeof(sc, status); CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX_EXC); } if (status & AN_EV_ALLOC) CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC); /* Re-enable interrupts. */ CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS); if ((ifp->if_flags & IFF_UP) && (ifp->if_snd.ifq_head != NULL)) an_start(ifp); return;}static intan_cmd(sc, cmd, val) struct an_softc *sc; int cmd; int val;{ int i, s = 0; CSR_WRITE_2(sc, AN_PARAM0, val); CSR_WRITE_2(sc, AN_PARAM1, 0); CSR_WRITE_2(sc, AN_PARAM2, 0); CSR_WRITE_2(sc, AN_COMMAND, cmd); for (i = 0; i < AN_TIMEOUT; i++) { if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD) break; else { if (CSR_READ_2(sc, AN_COMMAND) == cmd) CSR_WRITE_2(sc, AN_COMMAND, cmd); } } for (i = 0; i < AN_TIMEOUT; i++) { CSR_READ_2(sc, AN_RESP0); CSR_READ_2(sc, AN_RESP1); CSR_READ_2(sc, AN_RESP2); s = CSR_READ_2(sc, AN_STATUS); if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE)) break; } /* Ack the command */ CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD); if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY); if (i == AN_TIMEOUT) return(ETIMEDOUT); 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. */static voidan_reset(sc) struct an_softc *sc;{ if (sc->an_gone) return; an_cmd(sc, AN_CMD_ENABLE, 0); an_cmd(sc, AN_CMD_FW_RESTART, 0); an_cmd(sc, AN_CMD_NOOP2, 0); if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) printf("an%d: reset failed\n", sc->an_unit); an_cmd(sc, AN_CMD_DISABLE, 0); return;}/* * Read an LTV record from the NIC. */static intan_read_record(sc, ltv) struct an_softc *sc; struct an_ltv_gen *ltv;{ u_int16_t *ptr; u_int8_t *ptr2; int i, len; 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("an%d: RID access failed\n", sc->an_unit); return(EIO); } /* Seek to the record. */ if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) { printf("an%d: seek to record failed\n", sc->an_unit); return(EIO); } /* * Read the length and record type and make sure they * match what we expect (this verifies that we have enough * room to hold all of the returned data). * Length includes type but not length. */ len = CSR_READ_2(sc, AN_DATA1); if (len > (ltv->an_len - 2)) { printf("an%d: record length mismatch -- expected %d, " "got %d for Rid %x\n", sc->an_unit, ltv->an_len - 2, len, ltv->an_type); len = ltv->an_len - 2; } else { ltv->an_len = len + 2; } /* Now read the data. */ len -= 2; /* skip the type */ ptr = <v->an_val; for (i = len; i > 1; i -= 2) *ptr++ = CSR_READ_2(sc, AN_DATA1); if (i) { ptr2 = (u_int8_t *)ptr; *ptr2 = CSR_READ_1(sc, AN_DATA1); } if (an_dump) an_dump_record(sc, ltv, "Read"); return(0);}/* * Same as read, except we inject data instead of reading it. */static intan_write_record(sc, ltv) struct an_softc *sc; struct an_ltv_gen *ltv;{ u_int16_t *ptr; u_int8_t *ptr2; int i, len; if (an_dump) an_dump_record(sc, ltv, "Write"); 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); /* * Length includes type but not length. */ len = ltv->an_len - 2; CSR_WRITE_2(sc, AN_DATA1, len); len -= 2; /* skip the type */ ptr = <v->an_val; for (i = len; i > 1; i -= 2) CSR_WRITE_2(sc, AN_DATA1, *ptr++); if (i) { ptr2 = (u_int8_t *)ptr; CSR_WRITE_1(sc, AN_DATA0, *ptr2); } if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type)) return(EIO); return(0);}static voidan_dump_record(sc, ltv, string) struct an_softc *sc; struct an_ltv_gen *ltv; char *string;{ u_int8_t *ptr2; int len; int i; int count = 0; char buf[17], temp; len = ltv->an_len - 4; printf("an%d: RID %4x, Length %4d, Mode %s\n", sc->an_unit, ltv->an_type, ltv->an_len - 4, string); if (an_dump == 1 || (an_dump == ltv->an_type)) { printf("an%d:\t", sc->an_unit); bzero(buf,sizeof(buf)); ptr2 = (u_int8_t *)<v->an_val; for (i = len; i > 0; i--) { printf("%02x ", *ptr2); temp = *ptr2++; if (temp >= ' ' && temp <= '~') buf[count] = temp; else if (temp >= 'A' && temp <= 'Z') buf[count] = temp; else buf[count] = '.'; if (++count == 16) { count = 0; printf("%s\n",buf); printf("an%d:\t", sc->an_unit); bzero(buf,sizeof(buf)); } } for (; count != 16; count++) { printf(" "); } printf(" %s\n",buf); }}static 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("an%d: invalid data path: %x\n", sc->an_unit, chan); return(EIO); } CSR_WRITE_2(sc, selreg, id); CSR_WRITE_2(sc, offreg, off); for (i = 0; i < AN_TIMEOUT; i++) { if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR))) break; } if (i == AN_TIMEOUT) return(ETIMEDOUT); return(0);}static intan_read_data(sc, id, off, buf, len) struct an_softc *sc; int id, off; caddr_t buf; int len;{ int i; u_int16_t *ptr; u_int8_t *ptr2; if (off != -1) { if (an_seek(sc, id, off, AN_BAP1)) return(EIO); } ptr = (u_int16_t *)buf; for (i = len; i > 1; i -= 2) *ptr++ = CSR_READ_2(sc, AN_DATA1); if (i) { ptr2 = (u_int8_t *)ptr; *ptr2 = CSR_READ_1(sc, AN_DATA1); } return(0);}static intan_write_data(sc, id, off, buf, len) struct an_softc *sc; int id, off; caddr_t buf; int len;{ int i; u_int16_t *ptr; u_int8_t *ptr2; if (off != -1) { if (an_seek(sc, id, off, AN_BAP0)) return(EIO); } ptr = (u_int16_t *)buf; for (i = len; i > 1; i -= 2) CSR_WRITE_2(sc, AN_DATA0, *ptr++); if (i) { ptr2 = (u_int8_t *)ptr; CSR_WRITE_1(sc, AN_DATA0, *ptr2); } return(0);}/* * Allocate a region of memory inside the NIC and zero * it out. */static 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("an%d: failed to allocate %d bytes on NIC\n", sc->an_unit, len); return(ENOMEM); } for (i = 0; i < AN_TIMEOUT; i++) { if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC) break; } if (i == AN_TIMEOUT) 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); for (i = 0; i < len / 2; i++) CSR_WRITE_2(sc, AN_DATA0, 0); return(0);}static 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; 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 - 1]; 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -