X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/53a5409ebc57f165caf4d645703d954ada29be2c..5e35ed2481cff3093e5df1d23606e3f8ce318fba:/usr/src/sys/vax/if/if_en.c diff --git a/usr/src/sys/vax/if/if_en.c b/usr/src/sys/vax/if/if_en.c index 773668a06a..6299fcb687 100644 --- a/usr/src/sys/vax/if/if_en.c +++ b/usr/src/sys/vax/if/if_en.c @@ -1,477 +1,549 @@ -/* if_en.c 4.7 81/11/14 */ +/* 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_systm.h" -#include "../net/imp.h" -#include "../net/ip.h" -#include "../net/tcp.h" /* XXX */ -#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 + +#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)->t_off * 4; - 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>((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