/* * Structure of an Ethernet header. * */#include "net/misc.h"#include "sys/param.h"#include "sys/config.h"#include "sys/errno.h"#include "sys/types.h"#include "sys/systm.h"#include "net/mbuf.h"#include "sys/buf.h"#include "net/protosw.h"#include "net/socket.h"#include "sys/config.h"#include "sys/mmu.h"#include "sys/sysmacros.h"#include "net/ubavar.h"#include "errno.h"#include "net/if.h"#include "net/route.h"#include "net/in.h"#include "net/in_systm.h"#include "net/ip.h"#include "net/ip_var.h"#include "net/pup.h"#include "net/if_ether.h"/* * 3Com Ethernet controller registers. */struct medevice {	u_short	me_csr;		/* control and status */	u_short	me_back;	/* backoff value */	u_char	me_pad1[0x400-2*2];	u_char	me_arom[6];	/* address ROM */	u_char	me_pad2[0x200-6];	u_char	me_aram[6];	/* address RAM */	u_char	me_pad3[0x200-6];	u_char	me_tbuf[2048];	/* transmit buffer */	u_char	me_abuf[2048];	/* rmeeive buffer A */	u_char	me_bbuf[2048];	/* receive buffer B */};/* * Control and status bits */#define	ME_BBSW		0x8000		/* buffer B belongs to ether */#define	ME_ABSW		0x4000		/* buffer A belongs to ether */#define	ME_TBSW		0x2000		/* transmit buffer belongs to ether */#define	ME_JAM		0x1000		/* Ethernet jammed (collision) */#define	ME_AMSW		0x0800		/* address RAM belongs to ether */#define	ME_RBBA		0x0400		/* buffer B older than A */#define	ME_RESET	0x0100		/* reset controller */#define	ME_BINT		0x0080		/* buffer B interrupt enable */#define	ME_AINT		0x0040		/* buffer A interrupt enable */#define	ME_TINT		0x0020		/* transmitter interrupt enable */#define	ME_JINT		0x0010		/* jam interrupt enable */#define	ME_PAMASK	0x000f		/* PA field *//* with old VAX 4.1a, keep range errors, since vax sends too-small packets. */#define	ME_PA_OLDVAX	0x0008		/* receive mine+broadcast-(fcs+frame)*/#define	ME_PA		0x0002		/*  all- fcs and frame errors  *//* * Receive status bits */#define	ME_FCSERR	0x8000		/* FCS error */#define	ME_BROADCAST	0x4000		/* packet was broadcast packet */#define	ME_RGERR	0x2000		/* range error */#define	ME_ADDRMATCH	0x1000		/* address match */#define	ME_FRERR	0x0800		/* framing error */#define	ME_DOFF		0x07ff		/* first free byte */#define	MERDOFF		2		/* packet offset in read buffer */#ifdef notdef#define	MEMAXTDOFF	(2048-60)	/* max packet offset (min size) */#endif#define	MEMAXTDOFF	(2048-512)	/* max packet offset (min size) */#define NME 1/* * 3Com Ethernet Controller interface */#define	MEMTU	1500int nulldev(), meattach(), meintr();struct	uba_device *meinfo[NME];struct	uba_driver medriver = {	nulldev, meattach, (u_short * )0, meinfo};#define	MEUNIT(x)	minor(x)int	meinit(),meoutput(),mewatch();struct mbuf *meget();extern struct ifnet loif;#ifdef	HAS8259#define ME_EOI 2int meeoi = ME_EOI;#endif/* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * es_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... */struct	me_softc {	struct	arpcom es_ac;		/* common Ethernet structures */#define	es_if	es_ac.ac_if		/* network-visible interface */#define	es_enaddr es_ac.ac_enaddr	/* hardware Ethernet address */	short	es_mask;		/* mask for current output delay */	short	es_oactive;		/* is output active? */} me_softc[NME];/* * Interface exists: make available by filling in network interface * record.  System will initialize the interface when it is ready * to accept packets. */meattach(md)	struct uba_device *md;{	struct me_softc *es = &me_softc[md->ui_unit];	register struct ifnet *ifp = &es->es_if;	register struct medevice *addr;	struct sockaddr_in *sin;	int i;	u_char *cp, *ap;	char *memap();	/* map controller into kernel space for Unisoft. memap is in config.c */	addr = (struct medevice *) memap((int)md->ui_addr, btoc(8192));	/* replace the value of ui_addr for everyone else. */	md->ui_addr = (caddr_t)addr;	ifp->if_unit = md->ui_unit;	ifp->if_name = "me";	ifp->if_mtu = MEMTU;	ifp->if_net = md->ui_flags & 0xff000000;	if (!iocheck((caddr_t)addr)) {printf("**\nCould not find me%d; am not initializing network device...**\n",			ifp->if_unit);		return;	}	addr->me_csr |= ME_RESET;	/* reset the board */	medelay(1);			/* wait for it to reset (1 sec) */	/*	 * Read the ethernet address off the board, one byte at a time.	 */	cp = es->es_enaddr;	ap = addr->me_arom;	/* check for mem. board mistakenly mapped to same addr. as me */	if ((*ap = 'g') == 'g') {		printf ("\n**Able to write the rom on me%d; probable memory addressing confilct.**\nNot initializing interface.\n\n", ifp->if_unit);		return;	}	for (i = 0; i < 6; i++)		*cp++ = *ap++;	printf("Ethernet address = ");	{		char * p = &es->es_enaddr[0];		int i, j = 0;		char buf[14];		for (i = 0; i < 6; i ++) {			buf[j++] = "0123456789ABCDEF"[((*p >> 4)&0xf)];			buf[j++] = "0123456789ABCDEF"[((*p++)&0xf)];		}		buf[j++] = '\n';		buf[j] = 0;		printf(buf);	}	sin = (struct sockaddr_in *)&es->es_if.if_addr;	sin->sin_family = AF_INET;	/* this is a way to set addresses for now (without an ioctl()) */	sin->sin_addr.s_addr = (u_long)md->ui_flags;	mesetaddr(ifp, sin);	ifp->if_init = meinit;	ifp->if_output = meoutput;	ifp->if_watchdog = mewatch;	if_attach(ifp);}mewatch(){}/* * Initialization of interface; clear recorded pending * operations. */meinit(unit)	int unit;{	struct me_softc *es = &me_softc[unit];	register struct ifnet *ifp = &es->es_if;	register struct sockaddr_in *sin;	struct medevice *addr;	int i, s;	u_char *cp, *ap;	sin = (struct sockaddr_in *)&ifp->if_addr;	if (sin->sin_addr.s_addr == 0)		/* address still unknown */	    return;	if ((es->es_if.if_flags & IFF_RUNNING) == 0) {		addr = (struct medevice *)meinfo[unit]->ui_addr;		s = splimp();		/*		 * Initialize the address RAM		 */		cp = es->es_enaddr;		ap = addr->me_aram;		for (i = 0; i < 6; i++)			*ap++ = *cp++;		addr->me_csr |= ME_AMSW;		/*		 * Hang receive buffers and start any pending writes.		 */		addr->me_csr |= ME_ABSW|ME_AINT|ME_BBSW|ME_BINT			| ME_PA_OLDVAX;		es->es_oactive = 0;		es->es_mask = ~0;		es->es_if.if_flags |= IFF_UP|IFF_RUNNING;		if (es->es_if.if_snd.ifq_head)			mestart(unit);		splx(s);	}	if_rtinit(&es->es_if, RTF_UP);	arpattach(&es->es_ac);	arpwhohas(&es->es_ac, &sin->sin_addr);}/* * Start or restart output on interface. * If interface is already active, then this is a retransmit * after a collision, and just restuff registers. * If interface is not already active, get another datagram * to send off of the interface queue, and map it to the interface * before starting the output. */mestart(dev)	register dev_t dev;{        register int unit = MEUNIT(dev);	register struct me_softc *es = &me_softc[unit];	register struct medevice *addr;	register struct mbuf *m;	addr = (struct medevice *)meinfo[unit]->ui_addr;	if (es->es_oactive)		goto restart;	IF_DEQUEUE(&es->es_if.if_snd, m);	if (m == 0) {		es->es_oactive = 0;		return;	}	meput(addr->me_tbuf, m);	addr->me_csr |= ME_TBSW|ME_TINT|ME_JINT;restart:	es->es_oactive = 1;}/* * Ethernet interface interrupt. * If received packet examine  * packet to determine type.  If can't determine length * from type, then have to drop packet.  Othewise decapsulate * packet based on type and pass to type specific higher-level * input routine. */meintr(){	register struct me_softc *es;	register struct medevice *addr;	register int unit;	extern short netoff;	register unsigned short meenables = 0;	if (netoff)		return;	(void) splnet();	for (unit = 0; unit < NME; unit++) {	es = &me_softc[unit];	addr = (struct medevice *)meinfo[unit]->ui_addr;	switch (addr->me_csr & (ME_ABSW|ME_BBSW|ME_RBBA)) {	case ME_ABSW:	case ME_ABSW|ME_RBBA:		/* BBSW == 0, receive B packet */		addr->me_csr &= ~ME_BINT;		meread(es, addr->me_bbuf);		addr->me_csr |= ME_BBSW|ME_BINT;		break;	case ME_BBSW:	case ME_BBSW|ME_RBBA:		/* ABSW == 0, rmeeive A packet */		addr->me_csr &= ~ME_AINT;		meread(es, addr->me_abuf);		addr->me_csr |= ME_ABSW|ME_AINT;		break;	case ME_RBBA:		/* ABSW == 0, BBSW == 0, RBBA, receive B, then A */		addr->me_csr &= ~(ME_AINT|ME_BINT);		meread(es, addr->me_bbuf);		addr->me_csr |= ME_BBSW|ME_BINT;		meread(es, addr->me_abuf);		addr->me_csr |= ME_ABSW|ME_AINT;		break;	case 0:		/* ABSW == 0, BBSW == 0, RBBA == 0, receive A, then B */		addr->me_csr &= ~(ME_AINT|ME_BINT);		meread(es, addr->me_abuf);		addr->me_csr |= ME_ABSW|ME_AINT;		meread(es, addr->me_bbuf);		addr->me_csr |= ME_BBSW|ME_BINT;		break;	case ME_ABSW|ME_BBSW:	case ME_ABSW|ME_BBSW|ME_RBBA:		/* no input packets */		addr->me_csr &= ~(ME_AINT|ME_BINT);		addr->me_csr |= ME_AINT|ME_BINT;		break;	default:		panic("meintr: impossible value");		/* NOT REACHED */	}	} /* end of "for unit" */	for (unit = 0; unit < NME; unit++) {	es = &me_softc[unit];	addr = (struct medevice *)meinfo[unit]->ui_addr;	if (es->es_oactive == 0)		continue;	if (addr->me_csr & ME_JAM) {		/*		 * Collision on ethernet interface.  Do exponential		 * backoff, and retransmit.  If have backed off all		 * the way print warning diagnostic, and drop packet.		 */		es->es_if.if_collisions++;		medocoll(unit);		continue;	}	if ((addr->me_csr & ME_TBSW) == 0) {		addr->me_csr &= ~(ME_TINT|ME_JINT);		es->es_if.if_opackets++;		es->es_oactive = 0;		es->es_mask = ~0;		if (es->es_if.if_snd.ifq_head)			mestart(unit);	}	} /* end of "for unit" */#ifdef HAS8259	/* try to force level change by exciting current ints on bd */	meenables = addr->me_csr & (ME_TINT|ME_AINT|ME_BINT|ME_JINT);	addr->me_csr &= ~meenables;	sendeoi(meeoi);	addr->me_csr |= meenables;#endif	return ;}meread(es, mebuf)	register struct me_softc *es;	register caddr_t mebuf;{	register struct ether_header *me;    	register struct mbuf *m;	register int len, off, meoff;	short resid;	register struct ifqueue *inq;/*int i;printf("mer.");me = (struct ether_header *)(mebuf + MERDOFF);printf("s:");for (i = 0; i < 6; i++)    printf("%x.",me->me_shost[i]&0xff);printf("  ");printf("d:");for (i = 0; i < 6; i++)    printf("%x.",me->me_dhost[i]&0xff);*/	es->es_if.if_ipackets++;	meoff = *(short *)mebuf;	if(meoff & (ME_FRERR|ME_RGERR|ME_FCSERR))		    goto err;	meoff &= ME_DOFF;		if (meoff <= MERDOFF || meoff > 2046) {err:		es->es_if.if_ierrors++;		return;	}	/*	 * Get input data length.	 * Get pointer to ethernet header (in input buffer).	 * Deal with trailer protocol: if type is PUP trailer	 * get true type from first 16-bit word past data.	 * Remember that type was trailer by setting off.	 */	len = meoff - MERDOFF - sizeof (struct ether_header) - 4; /* 4 == FCS */	me = (struct ether_header *)(mebuf + MERDOFF);#define	medataaddr(me, off, type)	((type)(((caddr_t)((me)+1)+(off))))	if (me->ether_type >= ETHERPUP_TRAIL &&	    me->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {		off = (me->ether_type - ETHERPUP_TRAIL) * 512;		if (off >= MEMTU)			return;		/* sanity */		me->ether_type = *medataaddr(me, off, u_short *);		resid = *(medataaddr(me, off+2, u_short *));		if (off + resid > len)			return;		/* sanity */		len = off + resid;	} else		off = 0;	if (len == 0)		return;	/*	 * Pull packet off interface.  Off is nonzero if packet	 * has trailing header; meget 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 = meget(mebuf, len, off);	if (m == 0)		return;	if (off) {		m->m_off += 2 * sizeof (u_short);		m->m_len -= 2 * sizeof (u_short);	}	switch (me->ether_type) {#ifdef INET	case ETHERPUP_IPTYPE:		schednetisr(NETISR_IP);		inq = &ipintrq;		break;	case ETHERPUP_ARPTYPE:		arpinput(&es->es_ac, m);		return;#endif	default:		m_freem(m);		return;	}	if (IF_QFULL(inq)) {		IF_DROP(inq);		m_freem(m);		return;	}	IF_ENQUEUE(inq, m);}medocoll(unit)	int unit;{	register struct me_softc *es = &me_softc[unit];	register struct medevice *addr =	    (struct medevice *)meinfo[unit]->ui_addr;	int delay;	/*	 * Es_mask is a 16 bit number with n low zero bits, with	 * n the number of backoffs.  When es_mask is 0 we have	 * backed off 16 times, and give up.	 */	if (es->es_mask == 0) {		es->es_if.if_oerrors++;		printf("\nme%d: 16 collisions detected on ethernet.  Dropping current packet...\n\n",			unit);		/*		 * Reset and transmit next packet (if any).		 */		es->es_oactive = 0;		es->es_mask = ~0;		if (es->es_if.if_snd.ifq_head)			mestart(unit);		return;	}	/*	 * Do exponential backoff.  Compute delay based on low bits	 * of the time.  A slot time is 51.2 microseconds (rounded to 51).	 * This does not take into account the time already used to	 * process the interrupt.	 */	es->es_mask <<= 1;	delay = (time&0xffff) &~ es->es_mask;	addr->me_back = delay * 51;	addr->me_csr |= ME_JAM|ME_JINT;}/* * Ethernet output routine. * Encapsulate a packet of type family for the local net. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. * If destination is this address or broadcast, send packet to * loop device to kludge around the fact that 3com interfaces can't * talk to themselves. */meoutput(ifp, m0, dst)	register struct ifnet *ifp;	register struct mbuf *m0;	register struct sockaddr *dst;{	int type,  s, error;	u_char edst[6];	struct in_addr idst;	register struct me_softc *es = &me_softc[ifp->if_unit];	register struct mbuf *m = m0;	register struct ether_header *me;	register int i;	struct mbuf *mcopy = (struct mbuf *) 0;		/* Null */	s = splnet();	switch (dst->sa_family) {#ifdef INET	case AF_INET:		idst = ((struct sockaddr_in *)dst)->sin_addr;		if (!arpresolve(&es->es_ac, m, &idst, edst))			return (0);	/* if not yet resolved */		if (in_lnaof(idst) == INADDR_ANY)			mcopy = m_copy(m, 0, (int)M_COPYALL);		type = ETHERPUP_IPTYPE;		goto gottype;#endif	case AF_UNSPEC:		me = (struct ether_header *)dst->sa_data;		bcopy((caddr_t)me->ether_dhost, (caddr_t)edst, sizeof (edst));		type = me->ether_type;		goto gottype;	default:		printf("me%d: can't handle af%d\n", ifp->if_unit,			dst->sa_family);		error = EAFNOSUPPORT;		goto bad;	}gottype:	/*	 * Add local net header.  If no space in first mbuf,	 * allocate another.	 */	if (m->m_off > MMAXOFF ||	    MMINOFF + sizeof (struct ether_header) > m->m_off) {		m = m_get(M_DONTWAIT);		if (m == 0) {			error = ENOBUFS;			goto bad;		}		m->m_next = m0;		m->m_off = MMINOFF;		m->m_len = sizeof (struct ether_header);	} else {		m->m_off -= sizeof (struct ether_header);		m->m_len += sizeof (struct ether_header);	}	me = mtod(m, struct ether_header *);	bcopy((caddr_t)edst, (caddr_t)me->ether_dhost, sizeof (edst));	me->ether_type = htons((u_short)type);	bcopy((caddr_t)es->es_enaddr, (caddr_t)me->ether_shost, 6);	/*	 * Queue message on interface, and start output if interface	 * not yet active.	 */	s = splimp();	if (IF_QFULL(&ifp->if_snd)) {		IF_DROP(&ifp->if_snd);		error = ENOBUFS;		goto qfull;	}	IF_ENQUEUE(&ifp->if_snd, m);	if (es->es_oactive == 0)		mestart(ifp->if_unit);	splx(s);gotlocal:	return(mcopy ? looutput(&loif, mcopy, dst) : 0);qfull:	m0 = m;bad:	m_freem(m0);	splx(s);	return(error);}/* * Routine to copy from mbuf chain to transmitter * buffer in Multibus memory. */meput(mebuf, m)	register u_char *mebuf;	register struct mbuf *m;{	register struct mbuf *mp;	register short off;	register u_char *bp;	register flag = 0;	for (off = 2048, mp = m; mp; mp = mp->m_next)		off -= mp->m_len;	if (off > MEMAXTDOFF)		/* enforce minimum packet size */		off = MEMAXTDOFF;	if (off & 01) {		off--;		flag++;	}    	*(u_short *)mebuf = off;	bp = (u_char *)(mebuf + off);	for (mp = m; mp; mp = mp->m_next) {		register unsigned len = mp->m_len;		u_char *mcp;		if (len == 0)			continue;		mcp = mtod(mp, u_char *);		bcopy(mcp, bp, (int)len);		bp += len;	}/*if ((Off & 01) && (Off > (2048-70))){int i; int j; printf("meput(%x):\n", Off);for(j=0;j<4;j++){for(i=0;i<16;i++)printf("%x ",(((char *)(off+mebuf))[i+16*j])&0xff);printf("\n");}}*/	if (flag)		*bp = 0;	m_freem(m);}/* * Routine to copy from Multibus memory into mbufs. * * Warning: This makes the fairly safe assumption that * mbufs have even lengths. */struct mbuf *meget(mebuf, totlen, off0)	register u_char *mebuf;	register int totlen, off0;{	register struct mbuf *m;	struct mbuf *top = 0, **mp = &top;	register int off = off0, len;	register u_char *cp;	cp = mebuf + MERDOFF + sizeof (struct ether_header);	/*	{int i; int j; printf("meget:\n");for(j=0;j<6;j++){for(i=0;i<16;i++)printf("%x ",(((char *)cp)[i+16*j])&0xff);printf("\n");}}	*/	while (totlen > 0) {		u_char *mcp;		MGET(m, 0);		if (m == 0){			goto bad;		}		if (off) {			len = totlen - off;			cp = mebuf + MERDOFF + sizeof (struct ether_header) + off;		} else			len = totlen;		m->m_len = len = MIN(MLEN, len);		m->m_off = MMINOFF;		mcp = mtod(m, u_char *);		bcopy(cp, mcp, len);		cp += len;		*mp = m;		mp = &m->m_next;		if (off == 0) {			totlen -= len;			continue;		}		off += len;		if (off == totlen) {			cp = mebuf + MERDOFF + sizeof (struct ether_header);			off = 0;			totlen = off0;		}	}	return (top);bad:	m_freem(top);	return (0);}/* medelay -- wait about tim secs */medelay(tim)register tim;{	register i;	while (tim--){		i = 100000;		while (i--)			;	}}mesetaddr(ifp, sin)	register struct ifnet *ifp;	register struct sockaddr_in *sin;{	ifp->if_addr = *(struct sockaddr *)sin;	ifp->if_net = in_netof(sin->sin_addr);	ifp->if_host[0] = in_lnaof(sin->sin_addr);	sin = (struct sockaddr_in *)&ifp->if_broadaddr;	sin->sin_family = AF_INET;	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);	ifp->if_flags |= IFF_BROADCAST;}