📄 if_le.c
字号:
} if ((csr0 & LE_C0_TXON) == 0) { sc->sc_txoff++; lereset(&sc->sc_dev); return (1); } if (csr0 & LE_C0_RINT) { /* interrupt is cleared in lerint */ lerint(sc); } if (csr0 & LE_C0_TINT) { ler1->ler1_rdp = LE_C0_TINT|LE_C0_INEA; lexint(sc); } return (1);}/* * Ethernet interface transmitter interrupt. * Start another output if more data to send. */voidlexint(sc) register struct le_softc *sc;{ register volatile struct letmd *tmd = sc->sc_r2->ler2_tmd; sc->sc_lestats.lexints++; if ((sc->sc_if.if_flags & IFF_OACTIVE) == 0) { sc->sc_xint++; return; } if (tmd->tmd1_bits & LE_T1_OWN) { sc->sc_xown++; return; } if (tmd->tmd1_bits & LE_T1_ERR) {err: lexerror(sc); sc->sc_if.if_oerrors++; if (tmd->tmd3 & (LE_T3_BUFF|LE_T3_UFLO)) { sc->sc_uflo++; lereset(&sc->sc_dev); } else if (tmd->tmd3 & LE_T3_LCOL) sc->sc_if.if_collisions++; else if (tmd->tmd3 & LE_T3_RTRY) sc->sc_if.if_collisions += 16; } else if (tmd->tmd3 & LE_T3_BUFF) /* XXX documentation says BUFF not included in ERR */ goto err; else if (tmd->tmd1_bits & LE_T1_ONE) sc->sc_if.if_collisions++; else if (tmd->tmd1_bits & LE_T1_MORE) /* what is the real number? */ sc->sc_if.if_collisions += 2; else sc->sc_if.if_opackets++; sc->sc_if.if_flags &= ~IFF_OACTIVE; lestart(&sc->sc_if);}#define LENEXTRMP \ if (++bix == LERBUF) bix = 0, rmd = sc->sc_r2->ler2_rmd; 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. */voidlerint(sc) register struct le_softc *sc;{ register int bix = sc->sc_rmd; register volatile struct lermd *rmd = &sc->sc_r2->ler2_rmd[bix]; sc->sc_lestats.lerints++; /* * Out of sync with hardware, should never happen? */ if (rmd->rmd1_bits & LE_R1_OWN) { do { sc->sc_lestats.lerscans++; LENEXTRMP; } while ((rmd->rmd1_bits & LE_R1_OWN) && bix != sc->sc_rmd); if (bix == sc->sc_rmd) printf("%s: RINT with no buffer\n", sc->sc_dev.dv_xname); } else sc->sc_lestats.lerhits++; /* * Process all buffers with valid data */ while ((rmd->rmd1_bits & LE_R1_OWN) == 0) { int len = rmd->rmd3; /* Clear interrupt to avoid race condition */ sc->sc_r1->ler1_rdp = LE_C0_RINT|LE_C0_INEA; if (rmd->rmd1_bits & LE_R1_ERR) { sc->sc_rmd = bix; lererror(sc, "bad packet"); sc->sc_if.if_ierrors++; } else if ((rmd->rmd1_bits & (LE_R1_STP|LE_R1_ENP)) != (LE_R1_STP|LE_R1_ENP)) { /* XXX make a define for LE_R1_STP|LE_R1_ENP? */ /* * Find the end of the packet so we can see how long * it was. We still throw it away. */ do { sc->sc_r1->ler1_rdp = LE_C0_RINT|LE_C0_INEA; rmd->rmd3 = 0; rmd->rmd1_bits = LE_R1_OWN; LENEXTRMP; } while (!(rmd->rmd1_bits & (LE_R1_OWN|LE_R1_ERR|LE_R1_STP|LE_R1_ENP))); sc->sc_rmd = bix; lererror(sc, "chained buffer"); sc->sc_rxlen++; /* * If search terminated without successful completion * we reset the hardware (conservative). */ if ((rmd->rmd1_bits & (LE_R1_OWN|LE_R1_ERR|LE_R1_STP|LE_R1_ENP)) != LE_R1_ENP) { lereset(&sc->sc_dev); return; } } else { leread(sc, sc->sc_r2->ler2_rbuf[bix], len);#ifdef PACKETSTATS lerpacketsizes[len]++;#endif sc->sc_lestats.lerbufs++; } rmd->rmd3 = 0; rmd->rmd1_bits = LE_R1_OWN; LENEXTRMP; } sc->sc_rmd = bix;}voidleread(sc, pkt, len) register struct le_softc *sc; char *pkt; int len;{ register struct ether_header *et; register struct ifnet *ifp = &sc->sc_if; struct mbuf *m; struct ifqueue *inq; int flags; ifp->if_ipackets++; et = (struct ether_header *)pkt; et->ether_type = ntohs((u_short)et->ether_type); /* adjust input length to account for header and CRC */ len -= sizeof(struct ether_header) + 4; if (len <= 0) { if (ledebug) log(LOG_WARNING, "%s: ierror(runt packet): from %s: len=%d\n", sc->sc_dev.dv_xname, ether_sprintf(et->ether_shost), len); sc->sc_runt++; ifp->if_ierrors++; return; } /* Setup mbuf flags we'll need later */ flags = 0; if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)et->ether_dhost, sizeof(etherbroadcastaddr)) == 0) flags |= M_BCAST; if (et->ether_dhost[0] & 1) flags |= M_MCAST;#if NBPFILTER > 0 /* * Check if there's a bpf filter listening on this interface. * If so, hand off the raw packet to enet, then discard things * not destined for us (but be sure to keep broadcast/multicast). */ if (sc->sc_bpf) { bpf_tap(sc->sc_bpf, pkt, len + sizeof(struct ether_header)); if ((flags & (M_BCAST | M_MCAST)) == 0 && bcmp(et->ether_dhost, sc->sc_addr, sizeof(et->ether_dhost)) != 0) return; }#endif m = leget(pkt, len, 0, ifp); if (m == 0) return; /* XXX this code comes from ether_input() */ ifp->if_lastchange = time; ifp->if_ibytes += m->m_pkthdr.len + sizeof (*et); if (flags) { m->m_flags |= flags; ifp->if_imcasts++; } /* XXX end of code from ether_input() */ switch (et->ether_type) {#ifdef INET case ETHERTYPE_IP: schednetisr(NETISR_IP); inq = &ipintrq; break; case ETHERTYPE_ARP: schednetisr(NETISR_ARP); inq = &arpintrq; break;#endif#ifdef NS case ETHERTYPE_NS: schednetisr(NETISR_NS); inq = &nsintrq; break;#endif#ifdef UTAHONLY#ifdef APPLETALK case ETHERTYPE_APPLETALK: schednetisr(NETISR_DDP); inq = &ddpintq; break; case ETHERTYPE_AARP: aarpinput(&sc->sc_ac, m); return;#endif#endif default: m_freem(m); return; } if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); return; } IF_ENQUEUE(inq, m);}/* * Routine to copy from mbuf chain to transmit * buffer in board local memory. * * ### this can be done by remapping in some cases */intleput(lebuf, m) register char *lebuf; 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 *), lebuf, len); lebuf += len; } m_freem(m); if (tlen < LEMINSIZE) { bzero(lebuf, LEMINSIZE - tlen); tlen = LEMINSIZE; } return (tlen);}/* * Routine to copy from board local memory into mbufs. */struct mbuf *leget(lebuf, totlen, off0, ifp) char *lebuf; int totlen, off0; struct ifnet *ifp;{ register struct mbuf *m; struct mbuf *top = 0, **mp = ⊤ register int off = off0, len; register char *cp; char *epkt; lebuf += sizeof(struct ether_header); cp = lebuf; epkt = cp + totlen; if (off) { cp += off + 2 * sizeof(u_short); totlen -= 2 * sizeof(u_short); } MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == 0) return (0); m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = totlen; m->m_len = MHLEN; while (totlen > 0) { if (top) { MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) { m_freem(top); return (0); } m->m_len = MLEN; } len = min(totlen, epkt - cp); if (len >= MINCLSIZE) { MCLGET(m, M_DONTWAIT); if (m->m_flags & M_EXT) m->m_len = len = min(len, MCLBYTES); else len = m->m_len; } else { /* * Place initial small packet/header at end of mbuf. */ if (len < m->m_len) { if (top == 0 && len + max_linkhdr <= m->m_len) m->m_data += max_linkhdr; m->m_len = len; } else len = m->m_len; } bcopy(cp, mtod(m, caddr_t), (unsigned)len); cp += len; *mp = m; mp = &m->m_next; totlen -= len; if (cp == epkt) cp = lebuf; } return (top);}/* * Process an ioctl request. */intleioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa; register struct le_softc *sc = lecd.cd_devs[ifp->if_unit]; register volatile struct lereg1 *ler1; int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifa = (struct ifaddr *)data; ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: (void)leinit(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 *)(sc->sc_addr); else { /* * The manual says we can't change the address * while the receiver is armed, * so reset everything */ ifp->if_flags &= ~IFF_RUNNING; bcopy((caddr_t)ina->x_host.c_host, (caddr_t)sc->sc_addr, sizeof(sc->sc_addr)); } (void)leinit(ifp->if_unit); /* does le_setaddr() */ break; }#endif default: (void)leinit(ifp->if_unit); break; } break; case SIOCSIFFLAGS: ler1 = sc->sc_r1; if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { ler1->ler1_rdp = LE_C0_STOP; ifp->if_flags &= ~IFF_RUNNING; } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) (void)leinit(ifp->if_unit); /* * If the state of the promiscuous bit changes, the interface * must be reset to effect the change. */ if (((ifp->if_flags ^ sc->sc_iflags) & IFF_PROMISC) && (ifp->if_flags & IFF_RUNNING)) { sc->sc_iflags = ifp->if_flags; lereset(&sc->sc_dev); lestart(ifp); } break; case SIOCADDMULTI: error = ether_addmulti((struct ifreq *)data, &sc->sc_ac); goto update_multicast; case SIOCDELMULTI: error = ether_delmulti((struct ifreq *)data, &sc->sc_ac); update_multicast: if (error == ENETRESET) { /* * Multicast list has changed; set the hardware * filter accordingly. */ lereset(&sc->sc_dev); error = 0; } break; default: error = EINVAL; } splx(s); return (error);}voidleerror(sc, stat) register struct le_softc *sc; int stat;{ if (!ledebug) return; /* * Not all transceivers implement heartbeat * so we only log CERR once. */ if ((stat & LE_C0_CERR) && sc->sc_cerr) return; log(LOG_WARNING, "%s: error: stat=%b\n", sc->sc_dev.dv_xname, stat, LE_C0_BITS);}voidlererror(sc, msg) register struct le_softc *sc; char *msg;{ register volatile struct lermd *rmd; int len; if (!ledebug) return; rmd = &sc->sc_r2->ler2_rmd[sc->sc_rmd]; len = rmd->rmd3; log(LOG_WARNING, "%s: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", sc->sc_dev.dv_xname, msg, len > 11 ? ether_sprintf((u_char *)&sc->sc_r2->ler2_rbuf[sc->sc_rmd][6]) : "unknown", sc->sc_rmd, len, rmd->rmd1_bits, LE_R1_BITS);}voidlexerror(sc) register struct le_softc *sc;{ register volatile struct letmd *tmd; register int len, tmd3, tdr; if (!ledebug) return; tmd = sc->sc_r2->ler2_tmd; tmd3 = tmd->tmd3; tdr = tmd3 & LE_T3_TDR_MASK; len = -tmd->tmd2; log(LOG_WARNING, "%s: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b, tdr=%d (%d nsecs)\n", sc->sc_dev.dv_xname, len > 5 ? ether_sprintf((u_char *)&sc->sc_r2->ler2_tbuf[0][0]) : "unknown", 0, len, tmd->tmd1_bits, LE_T1_BITS, tmd3, LE_T3_BITS, tdr, tdr * 100);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -