📄 if_le.c
字号:
unit, stat); break; } stat = ler1->ler1_rdp; } while ((stat & LE_IDON) == 0); LERDWR(ler0, LE_IDON, ler1->ler1_rdp); LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); le->sc_if.if_flags &= ~IFF_OACTIVE;}/* * Initialization of interface */leinit(unit) int unit;{ register struct ifnet *ifp = &le_softc[unit].sc_if; register struct ifaddr *ifa; int s; /* not yet, if address still unknown */ for (ifa = ifp->if_addrlist;; ifa = ifa->ifa_next) if (ifa == 0) return; else if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK) break; if ((ifp->if_flags & IFF_RUNNING) == 0) { s = splnet(); ifp->if_flags |= IFF_RUNNING; lereset(unit); (void) lestart(ifp); splx(s); }}#define LENEXTTMP \ if (++bix == LETBUF) \ bix = 0; \ tmd = LER2_TMDADDR(le->sc_r2, bix)/* * Start output on interface. Get another datagram to send * off of the interface queue, and copy it to the interface * before starting the output. */lestart(ifp) struct ifnet *ifp;{ register struct le_softc *le = &le_softc[ifp->if_unit]; register int bix = le->sc_tmdnext; register volatile void *tmd = LER2_TMDADDR(le->sc_r2, bix); register struct mbuf *m; int len = 0; if ((le->sc_if.if_flags & IFF_RUNNING) == 0) return (0); while (bix != le->sc_tmd) { if (LER2V_tmd1(tmd) & LE_OWN) panic("lestart"); IF_DEQUEUE(&le->sc_if.if_snd, m); if (m == 0) break;#if NBPFILTER > 0 /* * If bpf is listening on this interface, let it * see the packet before we commit it to the wire. */ if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m);#endif len = leput(le, LER2_TBUFADDR(le->sc_r2, bix), m); LER2_tmd3(tmd, 0); LER2_tmd2(tmd, -len); LER2_tmd1(tmd, LE_OWN | LE_STP | LE_ENP); LENEXTTMP; } if (len != 0) { le->sc_if.if_flags |= IFF_OACTIVE; LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp); } le->sc_tmdnext = bix; return (0);}/* * Process interrupts from the 7990 chip. */voidleintr(unit) int unit;{ register struct le_softc *le; register volatile struct lereg1 *ler1; register int stat; le = &le_softc[unit]; ler1 = le->sc_r1; stat = ler1->ler1_rdp; if (!(stat & LE_INTR)) { printf("le%d: spurrious interrupt\n", unit); return; } if (stat & LE_SERR) { leerror(unit, stat); if (stat & LE_MERR) { le->sc_merr++; lereset(unit); return; } if (stat & LE_BABL) le->sc_babl++; if (stat & LE_CERR) le->sc_cerr++; if (stat & LE_MISS) le->sc_miss++; LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); } if ((stat & LE_RXON) == 0) { le->sc_rxoff++; lereset(unit); return; } if ((stat & LE_TXON) == 0) { le->sc_txoff++; lereset(unit); return; } if (stat & LE_RINT) { /* interrupt is cleared in lerint */ lerint(unit); } if (stat & LE_TINT) { LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp); lexint(unit); }}/* * Ethernet interface transmitter interrupt. * Start another output if more data to send. */lexint(unit) register int unit;{ register struct le_softc *le = &le_softc[unit]; register int bix = le->sc_tmd; register volatile void *tmd; if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { le->sc_xint++; return; } LENEXTTMP; while (bix != le->sc_tmdnext && (LER2V_tmd1(tmd) & LE_OWN) == 0) { le->sc_tmd = bix; if ((LER2V_tmd1(tmd) & LE_ERR) || (LER2V_tmd3(tmd) & LE_TBUFF)) { lexerror(unit); le->sc_if.if_oerrors++; if (LER2V_tmd3(tmd) & (LE_TBUFF|LE_UFLO)) { le->sc_uflo++; lereset(unit); break; } else if (LER2V_tmd3(tmd) & LE_LCOL) le->sc_if.if_collisions++; else if (LER2V_tmd3(tmd) & LE_RTRY) le->sc_if.if_collisions += 16; } else if (LER2V_tmd1(tmd) & LE_ONE) le->sc_if.if_collisions++; else if (LER2V_tmd1(tmd) & LE_MORE) /* what is the real number? */ le->sc_if.if_collisions += 2; else le->sc_if.if_opackets++; LENEXTTMP; } if (bix == le->sc_tmdnext) le->sc_if.if_flags &= ~IFF_OACTIVE; (void) lestart(&le->sc_if);}#define LENEXTRMP \ if (++bix == LERBUF) \ bix = 0; \ rmd = LER2_RMDADDR(le->sc_r2, bix)/* * Ethernet interface receiver interrupt. * If input error just drop packet. * Decapsulate packet based on type and pass to type specific * higher-level input routine. */lerint(unit) int unit;{ register struct le_softc *le = &le_softc[unit]; register int bix = le->sc_rmd; register volatile void *rmd = LER2_RMDADDR(le->sc_r2, bix); /* * Out of sync with hardware, should never happen? */ if (LER2V_rmd1(rmd) & LE_OWN) { le->sc_rown++; LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); return; } /* * Process all buffers with valid data */ while ((LER2V_rmd1(rmd) & LE_OWN) == 0) { int len = LER2V_rmd3(rmd); /* Clear interrupt to avoid race condition */ LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); if (LER2V_rmd1(rmd) & LE_ERR) { le->sc_rmd = bix; lererror(unit, "bad packet"); le->sc_if.if_ierrors++; } else if ((LER2V_rmd1(rmd) & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { /* * Find the end of the packet so we can see how long * it was. We still throw it away. */ do { LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); LER2_rmd3(rmd, 0); LER2_rmd1(rmd, LE_OWN); LENEXTRMP; } while (!(LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); le->sc_rmd = bix; lererror(unit, "chained buffer"); le->sc_rxlen++; /* * If search terminated without successful completion * we reset the hardware (conservative). */ if ((LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != LE_ENP) { lereset(unit); return; } } else leread(unit, LER2_RBUFADDR(le->sc_r2, bix), len); LER2_rmd3(rmd, 0); LER2_rmd1(rmd, LE_OWN); LENEXTRMP; } MachEmptyWriteBuffer(); /* Paranoia */ le->sc_rmd = bix;}/* * Look at the packet in network buffer memory so we can be smart about how * we copy the data into mbufs. * This needs work since we can't just read network buffer memory like * regular memory. */leread(unit, buf, len) int unit; volatile void *buf; int len;{ register struct le_softc *le = &le_softc[unit]; struct ether_header et; struct mbuf *m; int off, resid, flags; u_short sbuf[2], eth_type; extern struct mbuf *leget(); le->sc_if.if_ipackets++; (*le->sc_copyfrombuf)(buf, 0, (char *)&et, sizeof (et)); eth_type = ntohs(et.ether_type); /* adjust input length to account for header and CRC */ len = len - sizeof(struct ether_header) - 4; if (eth_type >= ETHERTYPE_TRAIL && eth_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (eth_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) return; /* sanity */ (*le->sc_copyfrombuf)(buf, sizeof (et) + off, (char *)sbuf, sizeof (sbuf)); eth_type = ntohs(sbuf[0]); resid = ntohs(sbuf[1]); if (off + resid > len) return; /* sanity */ len = off + resid; } else off = 0; if (len <= 0) { if (ledebug) log(LOG_WARNING, "le%d: ierror(runt packet): from %s: len=%d\n", unit, ether_sprintf(et.ether_shost), len); le->sc_runt++; le->sc_if.if_ierrors++; return; } 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; /* * Pull packet off interface. Off is nonzero if packet * has trailing header; leget 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 = leget(le, buf, len, off, &le->sc_if); if (m == 0) return;#if NBPFILTER > 0 /* * Check if there's a bpf filter listening on this interface. * If so, hand off the raw packet to enet. */ if (le->sc_if.if_bpf) { bpf_mtap(le->sc_if.if_bpf, m); /* * Keep the packet if it's a broadcast or has our * physical ethernet address (or if we support * multicast and it's one). */ if (#ifdef MULTICAST (flags & (M_BCAST | M_MCAST)) == 0 &&#else (flags & M_BCAST) == 0 &&#endif bcmp(et.ether_dhost, le->sc_addr, sizeof(et.ether_dhost)) != 0) { m_freem(m); return; } }#endif m->m_flags |= flags; et.ether_type = eth_type; ether_input(&le->sc_if, &et, m);}/* * Routine to copy from mbuf chain to transmit buffer in * network buffer memory. */leput(le, lebuf, m) struct le_softc *le; register volatile void *lebuf; register struct mbuf *m;{ register struct mbuf *mp; register int len, tlen = 0; register int boff = 0; for (mp = m; mp; mp = mp->m_next) { len = mp->m_len; if (len == 0) continue; (*le->sc_copytobuf)(mtod(mp, char *), lebuf, boff, len); tlen += len; boff += len; } m_freem(m); if (tlen < LEMINSIZE) { (*le->sc_zerobuf)(lebuf, boff, LEMINSIZE - tlen); tlen = LEMINSIZE; } return(tlen);}/* * Routine to copy from network buffer memory into mbufs. */struct mbuf *leget(le, lebuf, totlen, off, ifp) struct le_softc *le; volatile void *lebuf; int totlen, off; struct ifnet *ifp;{ register struct mbuf *m; struct mbuf *top = 0, **mp = ⊤ register int len, resid, boff; /* NOTE: sizeof(struct ether_header) should be even */ boff = sizeof(struct ether_header); if (off) { /* NOTE: off should be even */ boff += off + 2 * sizeof(u_short); totlen -= 2 * sizeof(u_short); resid = totlen - off; } else resid = totlen; 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; } if (resid >= MINCLSIZE) MCLGET(m, M_DONTWAIT); if (m->m_flags & M_EXT) m->m_len = min(resid, MCLBYTES); else if (resid < m->m_len) { /* * Place initial small packet/header at end of mbuf. */ if (top == 0 && resid + max_linkhdr <= m->m_len) m->m_data += max_linkhdr; m->m_len = resid; } len = m->m_len; (*le->sc_copyfrombuf)(lebuf, boff, mtod(m, char *), len); boff += len; *mp = m; mp = &m->m_next; totlen -= len; resid -= len; if (resid == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -