⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_le.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
			       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 = &top;	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 + -