📄 if_ec.c
字号:
hmem->scb.command = CU_START; hmem->scb.status = 0; SET_CA;}/* * Start output on interface. Get another datagram to send * off of the interface queue, and copy it to the interface * before starting the output. */ecstart(ifp) struct ifnet *ifp;{ register struct ec_softc *ec = &ec_softc[ifp->if_unit]; register struct ec_transmit *tmd; register struct mbuf *m; int len;again: if ((ec->sc_if.if_flags & IFF_RUNNING) == 0 || ec->sc_txcnt >= NTXBUF) return (0); tmd = ec->sc_hmem->tcom + ec->sc_txnum; if (tmd->com0 & (COM0_B | COM0_C)) return (ec->sc_txbusy++, 0); IF_DEQUEUE(&ec->sc_if.if_snd, m); if (m == 0) return (0); len = ecput(ec->sc_hmem->txbuf[ec->sc_txnum], m);#if NBPFILTER > 0 /* * If bpf is listening on this interface, let it * see the packet before we commit it to the wire. */ if (ec->sc_bpf) bpf_tap(ec->sc_bpf, ec->sc_hmem->txbuf[ec->sc_txnum], len);#endif tmd->com0 = 0; tmd->count = len | COM1_EL; if (ec->sc_txcnt == 0) ec_txstart(ec); if (++ec->sc_txnum >= NTXBUF) ec->sc_txnum = 0; if (++ec->sc_txcnt >= NTXBUF) { ec->sc_txcnt = NTXBUF; ec->sc_if.if_flags |= IFF_OACTIVE; } goto again;}int ECC_intr, ECC_rint, ECC_xint, ECC_unready;ecintr(unit) register int unit;{ struct ec_softc *ec = &ec_softc[unit]; struct ec_mem *hmem = ec->sc_hmem; register int stat = hmem->scb.status; hmem->scb.command = stat & 0xf000; /* Ack interrupt cause */ SET_CA; if (stat & FR) ecrint(unit); if (stat & CX) ecxint(unit); ECC_intr++; if ((stat & RU_STATE) != RUS_READY) ECC_unready++; UNLATCH_INT;}/* * Ethernet interface transmitter interrupt. * Start another output if more data to send. */ecxint(unit) register int unit;{ register struct ec_softc *ec = &ec_softc[unit]; register struct ec_transmit *tmd; int i; ECC_rint++; if (ec->sc_txcnt == 0) { ec->sc_xint++; /* unexpected transmit interrupt */ return; } ec->sc_iflags &= ~IFF_OACTIVE; /* clear deadman indication */ if ((i = ec->sc_txnum - ec->sc_txcnt) < 0) i += NTXBUF; tmd = ec->sc_hmem->tcom + i; if (tmd->com0 & COM0_B) return; ec->sc_if.if_collisions += tmd->com0 & 0xf; if ((tmd->com0 & EXCOL) && (tmd->com0 & 0xf) == 0) ec->sc_if.if_collisions += 16; if ((tmd->com0 & COM0_OK) == 0) { ecxerror(unit); ec->sc_if.if_oerrors++; if (tmd->com0 & DMALATE) { ec->sc_uflo++; (void) ecreset(unit); return; } } else ec->sc_if.if_opackets++; tmd->com0 = 0; if (--ec->sc_txcnt > 0) ec_txstart(ec); if (ec->sc_txcnt < 0) { ec->sc_txbad++; ec->sc_txcnt = 0; } ec->sc_if.if_flags &= ~IFF_OACTIVE; (void) ecstart(&ec->sc_if);}#define ECNEXTRCOM \ if (++bix == NRXBUF) bix = 0, rmd = ec->sc_hmem->rcom; else ++rmd/* * Ethernet interface receiver interrupt. * If input error just drop packet. * Decapsulate packet based on type and pass to type specific * higher-level input routine. */ecrint(unit) int unit;{ register struct ec_softc *ec = &ec_softc[unit]; register int bix = ec->sc_rxnum; register struct ec_rfd *rmd = ec->sc_hmem->rcom + bix; /* * Out of sync with hardware, should never happen? */ ECC_xint++; if ((rmd->rfd0 & COM0_C) == 0 || (rmd->count & RBD_F) == 0) { ecrerror(unit, "out of sync, resetting"); return ecreset(unit); } /* * Process all buffers with valid data */ while ((rmd->rfd0 & COM0_C) && (rmd->count & RBD_F)) { if (rmd->rfd0 & (COM0_C|COM0_B|COM0_OK) != (COM0_C|COM0_OK)) { ec->sc_rxnum = bix; ecrerror(unit, "bad packet"); ec->sc_if.if_ierrors++; } if ((rmd->count & (RBD_F|RBD_EOF)) != (RBD_F|RBD_EOF)) { ecrerror(unit, "chained buffer"); ec->sc_rxlen++; ec->sc_if.if_ierrors++; } else ecread(ec, ec->sc_hmem->txbuf[bix], rmd->count & 0x2f); rmd->count = 0; rmd->rfd0 = 0; ECNEXTRCOM; ec->sc_rxnum = bix; }}voidecread(ec, buf, len) register struct ec_softc *ec; char *buf; int len;{ struct ether_header *et, eh; struct mbuf *m; int off, resid, unit = ec->sc_if.if_unit; ec->sc_if.if_ipackets++; et = (struct ether_header *)buf; et->ether_type = ntohs((u_short)et->ether_type); bcopy((caddr_t)et, &eh, sizeof(eh)); /* adjust input length to account for header */ len = len - sizeof(struct ether_header);#define ecdataaddr(et, off, type) ((type)(((caddr_t)((et)+1)+(off)))) if (et->ether_type >= ETHERTYPE_TRAIL && et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (et->ether_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) return; /* sanity */ et->ether_type = ntohs(*ecdataaddr(et, off, u_short *)); resid = ntohs(*(ecdataaddr(et, off+2, u_short *))); if (off + resid > len) return; /* sanity */ len = off + resid; } else off = 0; if (len <= 0) { if (ecdebug) log(LOG_WARNING, "ec%d: ierror(runt packet): from %s: len=%d\n", unit, ether_sprintf(et->ether_shost), len); ec->sc_runt++; ec->sc_if.if_ierrors++; return; }#if NBPFILTER > 0 /* * Check if there's a bpf filter listening on this interface. * If so, hand off the raw packet to bpf, which must deal with * trailers in its own way. */ if (ec->sc_bpf) bpf_tap(ec->sc_bpf, buf, len + sizeof(struct ether_header));#endif#if defined(ISO) || NBPFILTER > 0 /* * Note that the interface cannot be in promiscuous mode if * there are no bpf listeners. If we are in promiscuous * mode, we have to check if this packet is really ours. * However, there may be appropriate multicate addresses involved */#define NOT_TO(p) (bcmp(et->ether_dhost, p, sizeof(et->ether_dhost)) != 0) if (et->ether_dhost[0] & 1) { if (NOT_TO(etherbroadcastaddr)#ifdef ISO && NOT_TO(all_es_snpa) && NOT_TO(all_is_snpa) && NOT_TO(all_l1is_snpa) && NOT_TO(all_l2is_snpa)#endif ) return; } else if ((ec->sc_if.if_flags & IFF_PROMISC) && NOT_TO(ec->sc_addr)) return;#endif /* * Pull packet off interface. Off is nonzero if packet * has trailing header; m_devget will then force this header * information to be at the front, but we still have to drop * the type and length which are at the front of any trailer data. */ m = m_devget((char *)(et + 1), len, off, &ec->sc_if, 0); if (m == 0) return; ether_input(&ec->sc_if, &eh, m);}/* * Routine to copy from mbuf chain to transmit * buffer in board local memory. */ecput(ecbuf, m) register char *ecbuf; register struct mbuf *m;{ register struct mbuf *mp; register int len, tlen = 0; for (mp = m; mp; mp = mp->m_next) { len = mp->m_len; if (len == 0) continue; tlen += len; bcopy(mtod(mp, char *), ecbuf, len); ecbuf += len; } m_freem(m); if (tlen < ECMINSIZE) { bzero(ecbuf, ECMINSIZE - tlen); tlen = ECMINSIZE; } return(tlen);}/* * Process an ioctl request. */ecioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa = (struct ifaddr *)data; struct ec_softc *ec = &ec_softc[ifp->if_unit]; int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: ecinit(ifp->if_unit); /* before arpwhohas */ ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); break;#endif#ifdef NS case AF_NS: { register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *)(ec->sc_addr); else { ifp->if_flags &= ~IFF_RUNNING; bcopy((caddr_t)ina->x_host.c_host, (caddr_t)ec->sc_addr, sizeof(ec->sc_addr)); } ecinit(ifp->if_unit); break; }#endif default: ecinit(ifp->if_unit); break; } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { ifp->if_flags &= ~IFF_RUNNING; ecreset(ifp->if_unit); } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) ecinit(ifp->if_unit); /* * If the state of the promiscuous bit changes, the interface * must be reset to effect the change. */ if (((ifp->if_flags ^ ec->sc_iflags) & IFF_PROMISC) && (ifp->if_flags & IFF_RUNNING)) { ec->sc_iflags = ifp->if_flags & ~IFF_OACTIVE; ecreset(ifp->if_unit); ecstart(ifp); } break; default: error = EINVAL; } splx(s); return (error);}ecrerror(unit, msg) int unit; char *msg;{ register struct ec_softc *ec = &ec_softc[unit]; register struct ec_rfd *rmd; int len; if (!ecdebug) return; rmd = &ec->sc_hmem->rcom[ec->sc_rxnum]; len = rmd->count; log(LOG_WARNING, "ec%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", unit, msg, len > 11 ? ether_sprintf(&ec->sc_hmem->rxbuf[ec->sc_rxnum][6]) : "unknown", ec->sc_rxnum, len, rmd->rfd0, "\14\14LEN\13CRC\12ALGN\11NBUF\10DMAL\07SHRT");}ecxerror(unit) int unit;{ register struct ec_softc *ec = &ec_softc[unit]; register struct ec_transmit *tmd; int len; if (!ecdebug) return; tmd = &ec->sc_hmem->tcom[ec->sc_txnum]; len = tmd->count; log(LOG_WARNING, "ec%d: oerror: to %s: buf=%d, len=%d, com0=%b\n", unit, len > 5 ? ether_sprintf(ec->sc_hmem->txbuf[ec->sc_txnum]) : "unknown", ec->sc_txnum, len, tmd->com0, "\14\14ABRT\13LCOLL\12NCAR\11NCTS\10DMAL\07TDEF\06HRBT\05XCOL");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -