-/* if_en.c 4.8 81/11/15 */
+/* if_en.c 4.71 82/10/24 */
#include "en.h"
+
/*
- * Ethernet interface driver
+ * Xerox prototype (3 Mb) Ethernet interface driver.
*/
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/mbuf.h"
-#include "../net/inet.h"
-#include "../net/inet_pcb.h"
-#include "../net/inet_systm.h"
-#include "../net/imp.h"
-#include "../net/ip.h"
-#include "../net/ip_var.h"
-#include "../net/tcp.h" /* XXX */
-#include "../net/tcp_var.h"
-#include "../h/map.h"
#include "../h/pte.h"
#include "../h/buf.h"
-#include "../h/ubareg.h"
-#include "../h/ubavar.h"
-#include "../h/conf.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/proc.h"
-#include "../h/enreg.h"
-#include "../h/mtpr.h"
-#include "../h/cpu.h"
-#include "../h/cmap.h"
-
-int enrswaps, enwswaps;
+#include "../h/protosw.h"
+#include "../h/socket.h"
+#include "../h/vmmac.h"
+#include <errno.h>
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#include "../netpup/pup.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_en.h"
+#include "../vaxif/if_enreg.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+#define ENMTU (1024+512)
+#define ENMRU (1024+512+16) /* 16 is enough to receive trailer */
+
int enprobe(), enattach(), enrint(), enxint(), encollide();
struct uba_device *eninfo[NEN];
u_short enstd[] = { 0 };
struct uba_driver endriver =
{ enprobe, 0, enattach, 0, enstd, "en", eninfo };
-
#define ENUNIT(x) minor(x)
-struct en_packet *xpkt, *rpkt;
-struct en_prefix {
- struct en_header enp_h;
- struct tcpiphdr enp_th;
-};
-struct uba_regs *enuba;
-struct pte *enrmr, *enxmr;
-int enrbdp, enwbdp;
-int enrproto, enwproto;
-struct pte enxmap[2];
-int enxswapd;
+int eninit(),enoutput(),enreset();
+
+/*
+ * 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, ...
+ * We also have, for each interface, a UBA interface structure, which
+ * contains information about the UNIBUS resources held by the interface:
+ * map registers, buffered data paths, etc. Information is cached in this
+ * structure for use by the if_uba.c routines in running the interface
+ * efficiently.
+ */
+struct en_softc {
+ struct ifnet es_if; /* network-visible interface */
+ struct ifuba es_ifuba; /* UNIBUS resources */
+ short es_delay; /* current output delay */
+ short es_mask; /* mask for current output delay */
+ short es_lastx; /* host last transmitted to */
+ short es_oactive; /* is output active? */
+ short es_olen; /* length of last output */
+} en_softc[NEN];
+/*
+ * Do output DMA to determine interface presence and
+ * interrupt vector. DMA is too short to disturb other hosts.
+ */
enprobe(reg)
caddr_t reg;
{
- register int br, cvec;
+ register int br, cvec; /* r11, r10 value-result */
register struct endevice *addr = (struct endevice *)reg;
#ifdef lint
br = 0; cvec = br; br = cvec;
+ enrint(0); enxint(0); encollide(0);
#endif
-
addr->en_istat = 0;
- addr->en_ostat = 0;
addr->en_owc = -1;
addr->en_oba = 0;
addr->en_ostat = EN_IEN|EN_GO;
DELAY(100000);
addr->en_ostat = 0;
- printf("ethernet address %d\n", ~addr->en_addr&0xff);
+#ifdef ECHACK
+ br = 0x16;
+#endif
return (1);
}
+/*
+ * Interface exists: make available by filling in network interface
+ * record. System will initialize the interface when it is ready
+ * to accept packets.
+ */
enattach(ui)
struct uba_device *ui;
{
+ register struct en_softc *es = &en_softc[ui->ui_unit];
+ register struct sockaddr_in *sin;
+ es->es_if.if_unit = ui->ui_unit;
+ es->es_if.if_name = "en";
+ es->es_if.if_mtu = ENMTU;
+ es->es_if.if_net = ui->ui_flags;
+ es->es_if.if_host[0] =
+ (~(((struct endevice *)eninfo[ui->ui_unit]->ui_addr)->en_addr)) & 0xff;
+ sin = (struct sockaddr_in *)&es->es_if.if_addr;
+ sin->sin_family = AF_INET;
+ sin->sin_addr = if_makeaddr(es->es_if.if_net, es->es_if.if_host[0]);
+ sin = (struct sockaddr_in *)&es->es_if.if_broadaddr;
+ sin->sin_family = AF_INET;
+ sin->sin_addr = if_makeaddr(es->es_if.if_net, 0);
+ es->es_if.if_flags = IFF_BROADCAST;
+ es->es_if.if_init = eninit;
+ es->es_if.if_output = enoutput;
+ es->es_if.if_ubareset = enreset;
+ es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
+ if_attach(&es->es_if);
}
-eninit(unit)
- int unit;
-{
- register struct endevice *addr;
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+enreset(unit, uban)
+ int unit, uban;
+{
register struct uba_device *ui;
- int uban, x;
- static reenter;
- if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) {
- printf("en%d: not alive\n", unit);
+ if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
+ ui->ui_ubanum != uban)
return;
- }
- x = splimp();
- if (reenter == 0) {
- int n, j, i, k; char *cp;
- reenter = 1;
- n = 10;
- k = n<<1;
- i = rmalloc(mbmap, n*2);
- if (i == 0)
- panic("eninit");
- j = i << 1;
- cp = (char *)pftom(i);
- if (memall(&Mbmap[j], k, proc, CSYS) == 0)
- return (0);
- vmaccess(&Mbmap[j], (caddr_t)cp, k);
- rpkt = (struct en_packet *)
- (cp + 1024 - sizeof (struct en_prefix));
- xpkt = (struct en_packet *)
- (cp + 5 * 1024 + 1024 - sizeof (struct en_prefix));
- for (j = 0; j < n; j++)
- mprefcnt[i+j] = 1;
- }
- uban = ui->ui_ubanum;
- addr = (struct endevice *)ui->ui_addr;
- addr->en_istat = 0;
- addr->en_ostat = 0;
- imp_stat.iaddr =
- uballoc(uban, (caddr_t)rpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP);
- imp_stat.oaddr =
- uballoc(uban, (caddr_t)xpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP);
- enuba = ui->ui_hd->uh_uba;
- enrbdp = (imp_stat.iaddr >> 28) & 0xf;
- enwbdp = (imp_stat.oaddr >> 28) & 0xf;
- enrproto = UBAMR_MRV | (enrbdp << 21);
- enwproto = UBAMR_MRV | (enwbdp << 21);
- enrmr = &enuba->uba_map[((imp_stat.iaddr>>9)&0x1ff) + 1];
- enxmr = &enuba->uba_map[((imp_stat.oaddr>>9)&0x1ff) + 1];
- enxmap[0] = enxmr[0];
- enxmap[1] = enxmr[1];
- enxswapd = 0;
- printf("enrbdp %x enrproto %x enrmr %x imp_stat.iaddr %x\n",
- enrbdp, enrproto, enrmr, imp_stat.iaddr);
- imp_stat.impopen = 1;
- imp_stat.flush = 0;
- splx(x);
-#ifdef IMPDEBUG
- printf("eninit(%d): iaddr = %x, oaddr = %x\n",
- unit, imp_stat.iaddr, imp_stat.oaddr);
-#endif
+ printf(" en%d", unit);
+ eninit(unit);
}
-enreset(uban)
- int uban;
+/*
+ * Initialization of interface; clear recorded pending
+ * operations, and reinitialize UNIBUS usage.
+ */
+eninit(unit)
+ int unit;
{
- register int unit;
- struct uba_device *ui;
+ register struct en_softc *es = &en_softc[unit];
+ register struct uba_device *ui = eninfo[unit];
+ register struct endevice *addr;
+ int s;
- for (unit = 0; unit < NEN; unit++) {
- ui = eninfo[unit];
- if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0)
- continue;
- if (imp_stat.iaddr)
- ubarelse(uban, imp_stat.iaddr);
- if (imp_stat.oaddr)
- ubarelse(uban, imp_stat.oaddr);
- eninit(unit);
- printf("en%d ", unit);
+ if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
+ sizeof (struct en_header), (int)btoc(ENMRU)) == 0) {
+ printf("en%d: can't initialize\n", unit);
+ es->es_if.if_flags &= ~IFF_UP;
+ return;
}
+ addr = (struct endevice *)ui->ui_addr;
+ addr->en_istat = addr->en_ostat = 0;
+
+ /*
+ * Hang a receive and start any
+ * pending writes by faking a transmit complete.
+ */
+ s = splimp();
+ addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
+ addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
+ addr->en_istat = EN_IEN|EN_GO;
+ es->es_oactive = 1;
+ es->es_if.if_flags |= IFF_UP;
+ enxint(unit);
+ splx(s);
+ if_rtinit(&es->es_if, RTF_UP);
}
-int enlastdel = 25;
-int enlastx = 0;
+int enalldelay = 0;
+int enlastdel = 50;
+int enlastmask = (~0) << 5;
+
+/*
+ * Start or restart output on interface.
+ * If interface is already active, then this is a retransmit
+ * after a collision, and just restuff registers and delay.
+ * 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.
+ */
enstart(dev)
dev_t dev;
{
- register struct mbuf *m, *mp;
+ int unit = ENUNIT(dev);
+ struct uba_device *ui = eninfo[unit];
+ register struct en_softc *es = &en_softc[unit];
register struct endevice *addr;
- register caddr_t cp, top;
- int unit;
- register int len;
- u_short uaddr;
- struct uba_device *ui;
- int enxswapnow = 0;
-COUNT(ENSTART);
+ struct mbuf *m;
+ int dest;
- unit = ENUNIT(dev);
- ui = eninfo[unit];
- if (ui == 0 || ui->ui_alive == 0) {
- printf("en%d (imp_output): not alive\n", unit);
- return;
- }
- addr = (struct endevice *)ui->ui_addr;
- if (!imp_stat.outactive) {
- if ((m = imp_stat.outq_head) == NULL)
- return;
- imp_stat.outactive = 1; /* set myself active */
- imp_stat.outq_head = m->m_act; /* -> next packet chain */
- /*
- * Pack mbufs into ethernet packet.
- */
- cp = (caddr_t)xpkt;
- top = (caddr_t)xpkt + sizeof(struct en_packet);
- while (m != NULL) {
- char *dp;
- if (cp + m->m_len > top) {
- printf("imp_snd: my packet runneth over\n");
- m_freem(m);
- return;
- }
- dp = mtod(m, char *);
- if (((int)cp&0x3ff)==0 && ((int)dp&0x3ff)==0) {
- struct pte *pte = &Mbmap[mtopf(dp)*2];
- *(int *)enxmr = enwproto | pte++->pg_pfnum;
- *(int *)(enxmr+1) = enwproto | pte->pg_pfnum;
- enxswapd = enxswapnow = 1;
- } else
- bcopy((int)m + m->m_off, cp, m->m_len);
- cp += m->m_len;
- /* too soon! */
- MFREE(m, mp);
- m = mp;
- }
- if (enxswapnow == 0 && enxswapd) {
- enxmr[0] = enxmap[0];
- enxmr[1] = enxmap[1];
- }
- if (enlastx && enlastx == xpkt->Header.en_dhost)
- imp_stat.endelay = enlastdel;
- else
- enlastx = xpkt->Header.en_dhost;
- }
- len = ntohs(((struct ip *)((int)xpkt + L1822))->ip_len) + L1822;
- if (len > sizeof(struct en_packet)) {
- printf("imp_output: ridiculous IP length %d\n", len);
+ if (es->es_oactive)
+ goto restart;
+
+ /*
+ * Not already active: dequeue another request
+ * and map it to the UNIBUS. If no more requests,
+ * just return.
+ */
+ IF_DEQUEUE(&es->es_if.if_snd, m);
+ if (m == 0) {
+ es->es_oactive = 0;
return;
}
-#if defined(VAX780) || defined(VAX750)
- switch (cpu) {
-#if defined(VAX780)
- case VAX_780:
- UBA_PURGE780(enuba, enwbdp);
- break;
-#endif
-#if defined(VAX750)
- case VAX_750:
- UBA_PURGE750(enuba, enwbdp);
- break;
-#endif
+ dest = mtod(m, struct en_header *)->en_dhost;
+ es->es_olen = if_wubaput(&es->es_ifuba, m);
+
+ /*
+ * Ethernet cannot take back-to-back packets (no
+ * buffering in interface. To help avoid overrunning
+ * receivers, enforce a small delay (about 1ms) in interface:
+ * * between all packets when enalldelay
+ * * whenever last packet was broadcast
+ * * whenever this packet is to same host as last packet
+ */
+ if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
+ es->es_delay = enlastdel;
+ es->es_mask = enlastmask;
}
-#endif
- addr->en_oba = imp_stat.oaddr;
- addr->en_odelay = imp_stat.endelay;
- addr->en_owc = -((len + 1) >> 1);
-#ifdef IMPDEBUG
- printf("en%d: sending packet (%d bytes)\n", unit, len);
- prt_byte(xpkt, len);
-#endif
+ es->es_lastx = dest;
+
+restart:
+ /*
+ * Have request mapped to UNIBUS for transmission.
+ * Purge any stale data from this BDP, and start the otput.
+ */
+ if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
+ UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
+ addr = (struct endevice *)ui->ui_addr;
+ addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
+ addr->en_odelay = es->es_delay;
+ addr->en_owc = -((es->es_olen + 1) >> 1);
addr->en_ostat = EN_IEN|EN_GO;
+ es->es_oactive = 1;
}
/*
- * Setup for a read
+ * Ethernet interface transmitter interrupt.
+ * Start another output if more data to send.
*/
-ensetup(dev)
- dev_t dev;
+enxint(unit)
+ int unit;
{
- register struct endevice *addr;
- register struct uba_device *ui;
- register unsigned ubaddr;
- register int sps;
-COUNT(ENSETUP);
+ register struct uba_device *ui = eninfo[unit];
+ register struct en_softc *es = &en_softc[unit];
+ register struct endevice *addr = (struct endevice *)ui->ui_addr;
- ui = eninfo[ENUNIT(dev)];
- if (ui == 0 || ui->ui_alive == 0) {
- printf("en%d (imp_read): not alive\n", ENUNIT(dev));
+ if (es->es_oactive == 0)
+ return;
+ if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
+ es->es_if.if_oerrors++;
+ endocoll(unit);
return;
}
- addr = (struct endevice *)ui->ui_addr;
- addr->en_iba = imp_stat.iaddr;
- addr->en_iwc = -600; /* a little extra to avoid hardware bugs */
- addr->en_istat = EN_IEN|EN_GO;
+ es->es_if.if_opackets++;
+ es->es_oactive = 0;
+ es->es_delay = 0;
+ es->es_mask = ~0;
+ if (es->es_ifuba.ifu_xtofree) {
+ m_freem(es->es_ifuba.ifu_xtofree);
+ es->es_ifuba.ifu_xtofree = 0;
+ }
+ if (es->es_if.if_snd.ifq_head == 0) {
+ es->es_lastx = 256; /* putatively illegal */
+ return;
+ }
+ enstart(unit);
}
/*
- * Output interrupt handler.
+ * Collision on ethernet interface. Do exponential
+ * backoff, and retransmit. If have backed off all
+ * the way print warning diagnostic, and drop packet.
*/
-enxint(unit)
+encollide(unit)
int unit;
{
- register struct endevice *addr;
- register struct uba_device *ui;
-COUNT(ENXINT);
-
- ui = eninfo[unit];
- addr = (struct endevice *)ui->ui_addr;
+ struct en_softc *es = &en_softc[unit];
-#ifdef IMPDEBUG
- printf("en%d: enxint ostat=%b\n", unit, addr->en_ostat, EN_BITS);
-#endif
- if (!imp_stat.outactive) {
- printf("en%d: phantom output intr ostat=%b\n",
- unit, addr->en_ostat, EN_BITS);
+ es->es_if.if_collisions++;
+ if (es->es_oactive == 0)
return;
- }
- imp_stat.endelay = 0;
- imp_stat.enmask = ~0;
- if (addr->en_ostat&EN_OERROR)
- printf("en%d: output error ostat=%b\n", unit,
- addr->en_ostat, EN_BITS);
- imp_stat.outactive = 0;
- if (imp_stat.outq_head)
- enstart(unit);
- else
- enlastx = 0;
+ endocoll(unit);
}
-int collisions;
-encollide(unit)
+endocoll(unit)
int unit;
{
- register struct endevice *addr;
- register struct uba_device *ui;
-COUNT(ENCOLLIDE);
-
- collisions++;
- ui = eninfo[unit];
- addr = (struct endevice *)ui->ui_addr;
+ register struct en_softc *es = &en_softc[unit];
-#ifdef IMPDEBUG
- printf("en%d: collision ostat=%b\n", unit, addr->en_ostat, EN_BITS);
-#endif
- if (!imp_stat.outactive) {
- printf("en%d: phantom collision intr ostat=%b\n",
- unit, addr->en_ostat, EN_BITS);
+ /*
+ * 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) {
+ printf("en%d: send error\n", unit);
+ enxint(unit);
return;
}
- if (imp_stat.enmask == 0) {
- printf("en%d: output error ostat=%b\n", unit,
- addr->en_ostat, EN_BITS);
- } else {
- imp_stat.enmask <<= 1;
- imp_stat.endelay = mfpr(ICR) & ~imp_stat.enmask;
- }
+ /*
+ * Another backoff. Restart with delay based on n low bits
+ * of the interval timer.
+ */
+ es->es_mask <<= 1;
+ es->es_delay = mfpr(ICR) &~ es->es_mask;
enstart(unit);
}
+struct sockaddr_pup pupsrc = { AF_PUP };
+struct sockaddr_pup pupdst = { AF_PUP };
+struct sockproto pupproto = { PF_PUP };
+/*
+ * Ethernet interface receiver interrupt.
+ * If input error just drop packet.
+ * Otherwise purge input buffered data path and 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.
+ */
enrint(unit)
int unit;
{
- register struct mbuf *m;
- struct mbuf *mp;
- register struct endevice *addr;
- register struct uba_device *ui;
- register int len;
- register caddr_t cp;
- struct mbuf *p, *top = 0;
- struct ip *ip;
- int j, hlen;
-COUNT(ENRINT);
-
- ui = eninfo[unit];
- addr = (struct endevice *)ui->ui_addr;
-#ifdef IMPDEBUG
- printf("en%d: enrint istat=%b\n", unit, addr->en_istat, EN_BITS);
-#endif
- if (imp_stat.flush)
- goto flush;
+ register struct en_softc *es = &en_softc[unit];
+ struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
+ register struct en_header *en;
+ struct mbuf *m;
+ int len; short resid;
+ register struct ifqueue *inq;
+ int off;
+
+ es->es_if.if_ipackets++;
+
+ /*
+ * Purge BDP; drop if input error indicated.
+ */
+ if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
+ UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
if (addr->en_istat&EN_IERROR) {
-#ifdef notdef
- printf("en%d: input error istat=%b\n", unit,
- addr->en_istat, EN_BITS);
-#endif
- goto flush;
+ es->es_if.if_ierrors++;
+ goto setup;
}
-#if defined(VAX780) || defined(VAX750)
- switch (cpu) {
-#if defined(VAX780)
- case VAX_780:
- UBA_PURGE780(enuba, enrbdp);
- break;
-#endif
-#if defined(VAX750)
- case VAX_750:
- UBA_PURGE750(enuba, enrbdp);
+
+ /*
+ * Calculate 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.
+ */
+ resid = addr->en_iwc;
+ if (resid)
+ resid |= 0176000;
+ len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1;
+ len -= sizeof (struct en_header);
+ if (len > ENMRU)
+ goto setup; /* sanity */
+ en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr);
+#define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off))))
+ if (en->en_type >= ENPUP_TRAIL &&
+ en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) {
+ off = (en->en_type - ENPUP_TRAIL) * 512;
+ if (off > ENMTU)
+ goto setup; /* sanity */
+ en->en_type = *endataaddr(en, off, u_short *);
+ resid = *(endataaddr(en, off+2, u_short *));
+ if (off + resid > len)
+ goto setup; /* sanity */
+ len = off + resid;
+ } else
+ off = 0;
+ if (len == 0)
+ goto setup;
+ /*
+ * Pull packet off interface. Off is nonzero if packet
+ * has trailing header; if_rubaget 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 = if_rubaget(&es->es_ifuba, len, off);
+ if (m == 0)
+ goto setup;
+ if (off) {
+ m->m_off += 2 * sizeof (u_short);
+ m->m_len -= 2 * sizeof (u_short);
+ }
+ switch (en->en_type) {
+
+#ifdef INET
+ case ENPUP_IPTYPE:
+ schednetisr(NETISR_IP);
+ inq = &ipintrq;
break;
#endif
+#ifdef PUP
+ case ENPUP_PUPTYPE: {
+ struct pup_header *pup = mtod(m, struct pup_header *);
+
+ pupproto.sp_protocol = pup->pup_type;
+ pupdst.spup_addr = pup->pup_dport;
+ pupsrc.spup_addr = pup->pup_sport;
+ raw_input(m, &pupproto, (struct sockaddr *)&pupsrc,
+ (struct sockaddr *)&pupdst);
+ goto setup;
}
#endif
- ip = (struct ip *)((int)rpkt + L1822);
- len = ntohs(ip->ip_len) + L1822;
- if (len > sizeof(struct en_packet) || len < sizeof (struct ip)) {
- printf("enrint: bad ip length %d\n", len);
- goto flush;
+ default:
+ m_freem(m);
+ goto setup;
}
- hlen = L1822 + sizeof (struct ip);
- switch (ip->ip_p) {
- case IPPROTO_TCP:
- hlen += ((struct tcpiphdr *)ip)->ti_off << 2;
- break;
- }
- MGET(m, 0);
- if (m == 0)
- goto flush;
- top = m;
- m->m_off = MMINOFF;
- m->m_len = hlen;
- bcopy(rpkt, mtod(m, caddr_t), hlen);
- len -= hlen;
- cp = (caddr_t)rpkt + hlen;
- mp = m;
- while (len > 0) {
- MGET(m, 0);
- if (m == NULL)
- goto flush;
- if (len >= PGSIZE) {
- MPGET(p, 1);
- if (p == 0)
- goto nopage;
- m->m_len = PGSIZE;
- m->m_off = (int)p - (int)m;
- if (((int)cp & 0x3ff) == 0) {
- struct pte *cpte = &Mbmap[mtopf(cp)*2];
- struct pte *ppte = &Mbmap[mtopf(p)*2];
- struct pte t;
- enrswaps++;
- t = *ppte; *ppte++ = *cpte; *cpte++ = t;
- t = *ppte; *ppte = *cpte; *cpte = t;
- mtpr(TBIS, (caddr_t)cp);
- mtpr(TBIS, (caddr_t)cp+512);
- mtpr(TBIS, (caddr_t)p);
- mtpr(TBIS, (caddr_t)p+512);
- *(int *)(enrmr+1) =
- cpte[0].pg_pfnum | enrproto;
- *(int *)(enrmr) =
- cpte[-1].pg_pfnum | enrproto;
- goto nocopy;
- }
- } else {
-nopage:
- m->m_len = MIN(MLEN, len);
- m->m_off = MMINOFF;
- }
- bcopy(cp, (int)m + m->m_off, m->m_len);
-nocopy:
- cp += m->m_len;
- len -= m->m_len;
- mp->m_next = m;
- mp = m;
- }
- m = top;
- if (imp_stat.inq_head != NULL)
- imp_stat.inq_tail->m_act = m;
- else
- imp_stat.inq_head = m;
- imp_stat.inq_tail = m;
-#ifdef IMPDEBUG
- printf("en%d: received packet (%d bytes)\n", unit, len);
- prt_byte(rpkt, len);
-#endif
- setsoftnet();
- goto setup;
-flush:
- m_freem(top);
-#ifdef IMPDEBUG
- printf("en%d: flushing packet %x\n", unit, top);
-#endif
+ if (IF_QFULL(inq)) {
+ IF_DROP(inq);
+ m_freem(m);
+ } else
+ IF_ENQUEUE(inq, m);
+
setup:
- addr->en_iba = imp_stat.iaddr;
- addr->en_iwc = -600;
+ /*
+ * Reset for next packet.
+ */
+ addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
+ addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
addr->en_istat = EN_IEN|EN_GO;
}
-#ifdef IMPDEBUG
-prt_byte(s, ct)
- register char *s;
- int ct;
+/*
+ * 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.
+ */
+enoutput(ifp, m0, dst)
+ struct ifnet *ifp;
+ struct mbuf *m0;
+ struct sockaddr *dst;
{
- register i, j, c;
+ int type, dest, s, error;
+ register struct mbuf *m = m0;
+ register struct en_header *en;
+ register int off;
+
+ switch (dst->sa_family) {
+
+#ifdef INET
+ case AF_INET:
+ dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
+ if (dest & 0x00ffff00) {
+ error = EPERM; /* ??? */
+ goto bad;
+ }
+ dest = (dest >> 24) & 0xff;
+ off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
+ if (off > 0 && (off & 0x1ff) == 0 &&
+ m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
+ type = ENPUP_TRAIL + (off>>9);
+ m->m_off -= 2 * sizeof (u_short);
+ m->m_len += 2 * sizeof (u_short);
+ *mtod(m, u_short *) = ENPUP_IPTYPE;
+ *(mtod(m, u_short *) + 1) = m->m_len;
+ goto gottrailertype;
+ }
+ type = ENPUP_IPTYPE;
+ off = 0;
+ goto gottype;
+#endif
+#ifdef PUP
+ case AF_PUP:
+ dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host;
+ type = ENPUP_PUPTYPE;
+ off = 0;
+ goto gottype;
+#endif
+
+ default:
+ printf("en%d: can't handle af%d\n", ifp->if_unit,
+ dst->sa_family);
+ error = EAFNOSUPPORT;
+ goto bad;
+ }
+
+gottrailertype:
+ /*
+ * Packet to be sent as trailer: move first packet
+ * (control information) to end of chain.
+ */
+ while (m->m_next)
+ m = m->m_next;
+ m->m_next = m0;
+ m = m0->m_next;
+ m0->m_next = 0;
+ m0 = m;
+
+gottype:
+ /*
+ * Add local net header. If no space in first mbuf,
+ * allocate another.
+ */
+ if (m->m_off > MMAXOFF ||
+ MMINOFF + sizeof (struct en_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 en_header);
+ } else {
+ m->m_off -= sizeof (struct en_header);
+ m->m_len += sizeof (struct en_header);
+ }
+ en = mtod(m, struct en_header *);
+ en->en_shost = ifp->if_host[0];
+ en->en_dhost = dest;
+ en->en_type = type;
- for (i=0; i<ct; i++) {
- c = *s++;
- for (j=0; j<2 ; j++)
- putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]);
- putchar(' ');
+ /*
+ * 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;
}
- putchar('\n');
+ IF_ENQUEUE(&ifp->if_snd, m);
+ if (en_softc[ifp->if_unit].es_oactive == 0)
+ enstart(ifp->if_unit);
+ splx(s);
+ return (0);
+qfull:
+ m0 = m;
+ splx(s);
+bad:
+ m_freem(m0);
+ return (error);
}
-#endif IMPDEBUG