📄 if_le.c
字号:
register int stat; if ((ler0->ler0_status & LE_IR) == 0) return(0); if (ler0->ler0_status & LE_JAB) { le->sc_jab++; lereset(unit); return(1); } ler1 = le->sc_r1; LERDWR(ler0, ler1->ler1_rdp, stat); if (stat & LE_SERR) { leerror(unit, stat); if (stat & LE_MERR) { le->sc_merr++; lereset(unit); return(1); } 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(1); } if ((stat & LE_TXON) == 0) { le->sc_txoff++; lereset(unit); return(1); } if (stat & LE_RINT) lerint(unit); if (stat & LE_TINT) lexint(unit); return(1);}/* * 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 struct letmd *tmd; int i, gotone = 0;#ifdef USELEDS if (inledcontrol == 0) ledcontrol(0, 0, LED_LANXMT);#endif do { if ((i = le->sc_tmd - le->sc_txcnt) < 0) i += LETBUF; tmd = &le->sc_r2->ler2_tmd[i]; if (tmd->tmd1 & LE_OWN) { if (gotone) break; le->sc_xown++; return; } /* clear interrupt */ LERDWR(le->sc_r0, LE_TINT|LE_INEA, le->sc_r1->ler1_rdp); /* XXX documentation says BUFF not included in ERR */ if ((tmd->tmd1 & LE_ERR) || (tmd->tmd3 & LE_TBUFF)) { lexerror(unit); le->sc_if.if_oerrors++; if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) { le->sc_uflo++; lereset(unit); } else if (tmd->tmd3 & LE_LCOL) le->sc_if.if_collisions++; else if (tmd->tmd3 & LE_RTRY) le->sc_if.if_collisions += 16; } else if (tmd->tmd1 & LE_ONE) le->sc_if.if_collisions++; else if (tmd->tmd1 & LE_MORE) /* what is the real number? */ le->sc_if.if_collisions += 2; else le->sc_if.if_opackets++; gotone++; } while (--le->sc_txcnt > 0); le->sc_if.if_flags &= ~IFF_OACTIVE; (void) lestart(&le->sc_if);}#define LENEXTRMP \ if (++bix == LERBUF) bix = 0, rmd = le->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. */lerint(unit) int unit;{ register struct le_softc *le = &le_softc[unit]; register int bix = le->sc_rmd; register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix];#ifdef USELEDS if (inledcontrol == 0) ledcontrol(0, 0, LED_LANRCV);#endif /* * Out of sync with hardware, should never happen? */ if (rmd->rmd1 & 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 ((rmd->rmd1 & LE_OWN) == 0) { int len = rmd->rmd3; /* Clear interrupt to avoid race condition */ LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); if (rmd->rmd1 & LE_ERR) { le->sc_rmd = bix; lererror(unit, "bad packet"); le->sc_if.if_ierrors++; } else if ((rmd->rmd1 & (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); rmd->rmd3 = 0; rmd->rmd1 = LE_OWN; LENEXTRMP; } while (!(rmd->rmd1 & (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 ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != LE_ENP) { lereset(unit); return; } } else leread(unit, le->sc_r2->ler2_rbuf[bix], len); rmd->rmd3 = 0; rmd->rmd1 = LE_OWN; LENEXTRMP; } le->sc_rmd = bix;}leread(unit, buf, len) int unit; char *buf; int len;{ register struct le_softc *le = &le_softc[unit]; register struct ether_header *et; struct mbuf *m; int off, resid, flags; le->sc_if.if_ipackets++; et = (struct ether_header *)buf; et->ether_type = ntohs((u_short)et->ether_type); /* adjust input length to account for header and CRC */ len = len - sizeof(struct ether_header) - 4;#define ledataaddr(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(*ledataaddr(et, off, u_short *)); resid = ntohs(*(ledataaddr(et, off+2, u_short *))); 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;#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_tap(le->sc_if.if_bpf, buf, len + sizeof(struct ether_header)); /* * 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) 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, &le->sc_if, 0); if (m == 0) return; m->m_flags |= flags; ether_input(&le->sc_if, et, m);}/* * Routine to copy from mbuf chain to transmit * buffer in board local memory. */leput(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);}/* * Process an ioctl request. */leioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa = (struct ifaddr *)data; struct le_softc *le = &le_softc[ifp->if_unit]; struct lereg1 *ler1 = le->sc_r1; 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: 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 *)(le->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; LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp); bcopy((caddr_t)ina->x_host.c_host, (caddr_t)le->sc_addr, sizeof(le->sc_addr)); } leinit(ifp->if_unit); /* does le_setaddr() */ break; }#endif default: leinit(ifp->if_unit); break; } break;#if defined (CCITT) && defined (LLC) case SIOCSIFCONF_X25: ifp -> if_flags |= IFF_UP; ifa -> ifa_rtrequest = cons_rtrequest; error = x25_llcglue(PRC_IFUP, ifa -> ifa_addr); if (error == 0) leinit(ifp -> if_unit); break;#endif /* CCITT && LLC */ case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp); ifp->if_flags &= ~IFF_RUNNING; } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) 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 ^ le->sc_iflags) & IFF_PROMISC) && (ifp->if_flags & IFF_RUNNING)) { le->sc_iflags = ifp->if_flags; lereset(ifp->if_unit); lestart(ifp); } break;#ifdef MULTICAST case SIOCADDMULTI: case SIOCDELMULTI: /* Update our multicast list */ error = (cmd == SIOCADDMULTI) ? ether_addmulti((struct ifreq *)data, &le->sc_ac) : ether_delmulti((struct ifreq *)data, &le->sc_ac); if (error == ENETRESET) { /* * Multicast list has changed; set the hardware * filter accordingly. */ lereset(ifp->if_unit); error = 0; } break;#endif default: error = EINVAL; } splx(s); return (error);}leerror(unit, stat) int unit; int stat;{ if (!ledebug) return; /* * Not all transceivers implement heartbeat * so we only log CERR once. */ if ((stat & LE_CERR) && le_softc[unit].sc_cerr) return; log(LOG_WARNING, "le%d: error: stat=%b\n", unit, stat, "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");}lererror(unit, msg) int unit; char *msg;{ register struct le_softc *le = &le_softc[unit]; register struct lermd *rmd; int len; if (!ledebug) return; rmd = &le->sc_r2->ler2_rmd[le->sc_rmd]; len = rmd->rmd3; log(LOG_WARNING, "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", unit, msg, len > 11 ? ether_sprintf((u_char *)&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown", le->sc_rmd, len, rmd->rmd1, "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");}lexerror(unit) int unit;{ register struct le_softc *le = &le_softc[unit]; register struct letmd *tmd; int len; if (!ledebug) return; tmd = le->sc_r2->ler2_tmd; len = -tmd->tmd2; log(LOG_WARNING, "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", unit, len > 5 ? ether_sprintf((u_char *)&le->sc_r2->ler2_tbuf[0][0]) : "unknown", 0, len, tmd->tmd1, "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", tmd->tmd3, "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -