-/* if_en.c 4.29 82/01/19 */
+/*
+ * Copyright (c) 1982 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ * @(#)if_en.c 6.8 (Berkeley) %G%
+ */
#include "en.h"
/*
* Xerox prototype (3 Mb) Ethernet interface driver.
*/
+#include "../machine/pte.h"
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "buf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "vmmac.h"
+#include "errno.h"
+#include "ioctl.h"
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/mbuf.h"
-#include "../h/pte.h"
-#include "../h/buf.h"
-#include "../h/protosw.h"
-#include "../h/socket.h"
-#include "../h/ubareg.h"
-#include "../h/ubavar.h"
-#include "../h/enreg.h"
-#include "../h/cpu.h"
-#include "../h/mtpr.h"
-#include "../h/vmmac.h"
-#include "../net/in.h"
-#include "../net/in_systm.h"
#include "../net/if.h"
-#include "../net/if_en.h"
-#include "../net/if_uba.h"
-#include "../net/ip.h"
-#include "../net/ip_var.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/in_var.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#ifdef PUP
+#include "../netpup/pup.h"
+#include "../netpup/ether.h"
+#endif
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "if_en.h"
+#include "if_enreg.h"
+#include "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];
{ enprobe, 0, enattach, 0, enstd, "en", eninfo };
#define ENUNIT(x) minor(x)
-int eninit(),enoutput(),enreset();
+int eninit(),enoutput(),enreset(),enioctl();
+
+#ifdef notdef
+/*
+ * If you need to byte swap IP's in the system, define
+ * this and do a SIOCSIFFLAGS at boot time.
+ */
+#define ENF_SWABIPS 0x1000
+#endif
/*
* Ethernet software status per interface.
struct en_softc {
struct ifnet es_if; /* network-visible interface */
struct ifuba es_ifuba; /* UNIBUS resources */
+ short es_host; /* hardware host number */
short es_delay; /* current output delay */
short es_mask; /* mask for current output delay */
- u_char es_lastx; /* host last transmitted to */
+ short es_lastx; /* host last transmitted to */
short es_oactive; /* is output active? */
short es_olen; /* length of last output */
} en_softc[NEN];
register int br, cvec; /* r11, r10 value-result */
register struct endevice *addr = (struct endevice *)reg;
-COUNT(ENPROBE);
#ifdef lint
br = 0; cvec = br; br = cvec;
enrint(0); enxint(0); encollide(0);
struct uba_device *ui;
{
register struct en_softc *es = &en_softc[ui->ui_unit];
-COUNT(ENATTACH);
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;
-#ifdef ENKLUDGE
- if (es->es_if.if_net == 10) {
- es->es_if.if_host[0] <<= 16;
- es->es_if.if_host[0] |= 0x4e;
- }
-#endif
- es->es_if.if_addr =
- if_makeaddr(es->es_if.if_net, es->es_if.if_host[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_if.if_ioctl = enioctl;
+ es->es_if.if_reset = enreset;
+ es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
+#if defined(VAX750)
+ /* don't chew up 750 bdp's */
+ if (cpu == VAX_750 && ui->ui_unit > 0)
+ es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP;
+#endif
if_attach(&es->es_if);
}
int unit, uban;
{
register struct uba_device *ui;
-COUNT(ENRESET);
if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
ui->ui_ubanum != uban)
register struct endevice *addr;
int s;
+ if (es->es_if.if_addrlist == (struct ifaddr *)0)
+ return;
if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
- sizeof (struct en_header), (int)btop(ENMTU)) == 0) {
+ 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;
*/
s = splimp();
addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
- addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1;
+ 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_RUNNING;
enxint(unit);
splx(s);
}
-int enlastdel = 25;
+int enalldelay = 0;
+int enlastdel = 50;
+int enlastmask = (~0) << 5;
/*
* Start or restart output on interface.
struct uba_device *ui = eninfo[unit];
register struct en_softc *es = &en_softc[unit];
register struct endevice *addr;
+ register struct en_header *en;
struct mbuf *m;
int dest;
-COUNT(ENSTART);
if (es->es_oactive)
goto restart;
es->es_oactive = 0;
return;
}
- dest = mtod(m, struct en_header *)->en_dhost;
+ en = mtod(m, struct en_header *);
+ dest = en->en_dhost;
+ en->en_shost = es->es_host;
es->es_olen = if_wubaput(&es->es_ifuba, m);
+#ifdef ENF_SWABIPS
+ /*
+ * The Xerox interface does word at a time DMA, so
+ * someone must do byte swapping of user data if high
+ * and low ender machines are to communicate. It doesn't
+ * belong here, but certain people depend on it, so...
+ *
+ * Should swab everybody, but this is a kludge anyway.
+ */
+ if (es->es_if.if_flags & ENF_SWABIPS) {
+ en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr;
+ if (en->en_type == ENTYPE_IP)
+ enswab((caddr_t)(en + 1), (caddr_t)(en + 1),
+ es->es_olen - sizeof (struct en_header) + 1);
+ }
+#endif
/*
* Ethernet cannot take back-to-back packets (no
- * buffering in interface. To avoid overrunning
- * receiver, enforce a small delay (about 1ms) in interface
- * on successive packets sent to same host.
+ * 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 (es->es_lastx && es->es_lastx == dest)
+ if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
es->es_delay = enlastdel;
- else
- es->es_lastx = dest;
+ es->es_mask = enlastmask;
+ }
+ es->es_lastx = dest;
restart:
/*
* Have request mapped to UNIBUS for transmission.
* Purge any stale data from this BDP, and start the otput.
*/
- UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
+ 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;
{
register struct uba_device *ui = eninfo[unit];
register struct en_softc *es = &en_softc[unit];
- register struct endevice *addr;
-COUNT(ENXINT);
+ register struct endevice *addr = (struct endevice *)ui->ui_addr;
if (es->es_oactive == 0)
return;
- addr = (struct endevice *)ui->ui_addr;
+ if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
+ es->es_if.if_oerrors++;
+ endocoll(unit);
+ return;
+ }
es->es_if.if_opackets++;
es->es_oactive = 0;
es->es_delay = 0;
es->es_mask = ~0;
- if (addr->en_ostat&EN_OERROR) {
- es->es_if.if_oerrors++;
- printf("en%d: output error\n", unit);
+ 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) {
- if (es->es_ifuba.ifu_xtofree) {
- m_freem(es->es_ifuba.ifu_xtofree);
- es->es_ifuba.ifu_xtofree = 0;
- }
- es->es_lastx = 0;
+ es->es_lastx = 256; /* putatively illegal */
return;
}
enstart(unit);
/*
* Collision on ethernet interface. Do exponential
* backoff, and retransmit. If have backed off all
- * the way printing warning diagnostic, and drop packet.
+ * the way print warning diagnostic, and drop packet.
*/
encollide(unit)
int unit;
{
- register struct en_softc *es = &en_softc[unit];
-COUNT(ENCOLLIDE);
+ struct en_softc *es = &en_softc[unit];
es->es_if.if_collisions++;
if (es->es_oactive == 0)
return;
+ endocoll(unit);
+}
+
+endocoll(unit)
+ int unit;
+{
+ register struct en_softc *es = &en_softc[unit];
+
/*
* 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
enstart(unit);
}
+#ifdef notdef
+struct sockproto enproto = { AF_ETHERLINK };
+struct sockaddr_en endst = { AF_ETHERLINK };
+struct sockaddr_en ensrc = { AF_ETHERLINK };
+#endif
/*
* Ethernet interface receiver interrupt.
* If input error just drop packet.
struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
register struct en_header *en;
struct mbuf *m;
- int len;
+ int len; short resid;
register struct ifqueue *inq;
- int off;
-COUNT(ENRINT);
+ int off, s;
es->es_if.if_ipackets++;
/*
* Purge BDP; drop if input error indicated.
*/
- UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
+ 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) {
es->es_if.if_ierrors++;
- printf("en%d: input error\n", unit);
goto setup;
}
/*
+ * 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);
+ en->en_type = ntohs(en->en_type);
#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)
+ if (en->en_type >= ENTYPE_TRAIL &&
+ en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) {
+ off = (en->en_type - ENTYPE_TRAIL) * 512;
+ if (off > ENMTU)
+ goto setup; /* sanity */
+ en->en_type = ntohs(*endataaddr(en, off, u_short *));
+ resid = ntohs(*(endataaddr(en, off+2, u_short *)));
+ if (off + resid > len)
goto setup; /* sanity */
- en->en_type = *endataaddr(en, off, u_short *);
+ len = off + resid;
} else
off = 0;
-
- /*
- * Attempt to infer packet length from type;
- * can't deal with packet if can't infer length.
- */
- switch (en->en_type) {
-
-#ifdef INET
- case ENPUP_IPTYPE:
- len = htons((u_short)endataaddr(en, off ? off+2 : 0, struct ip *)->ip_len);
- if (off)
- len += 2;
- setipintr();
- inq = &ipintrq;
- break;
-#endif
-
- default:
- printf("en%d: unknow pkt type 0x%x\n", en->en_type);
- goto setup;
- }
if (len == 0)
goto setup;
-
+#ifdef ENF_SWABIPS
+ if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP)
+ enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len);
+#endif
/*
* 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 two-byte type which is at the front of any trailer data.
+ * 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;
- m->m_len -= 2;
+ m->m_off += 2 * sizeof (u_short);
+ m->m_len -= 2 * sizeof (u_short);
+ }
+ switch (en->en_type) {
+
+#ifdef INET
+ case ENTYPE_IP:
+ schednetisr(NETISR_IP);
+ inq = &ipintrq;
+ break;
+#endif
+#ifdef PUP
+ case ENTYPE_PUP:
+ rpup_input(m);
+ goto setup;
+#endif
+ default:
+#ifdef notdef
+ enproto.sp_protocol = en->en_type;
+ endst.sen_host = en->en_dhost;
+ endst.sen_net = ensrc.sen_net = es->es_if.if_net;
+ ensrc.sen_host = en->en_shost;
+ raw_input(m, &enproto,
+ (struct sockaddr *)&ensrc, (struct sockaddr *)&endst);
+#else
+ m_freem(m);
+#endif
+ goto setup;
}
- IF_ENQUEUE(inq, m);
+
+ s = splimp();
+ if (IF_QFULL(inq)) {
+ IF_DROP(inq);
+ m_freem(m);
+ } else
+ IF_ENQUEUE(inq, m);
+ splx(s);
setup:
/*
* Reset for next packet.
*/
addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
- addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1;
+ addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
addr->en_istat = EN_IEN|EN_GO;
}
* Use trailer local net encapsulation if enough data in first
* packet leaves a multiple of 512 bytes of data in remainder.
*/
-enoutput(ifp, m0, pf)
+enoutput(ifp, m0, dst)
struct ifnet *ifp;
struct mbuf *m0;
- int pf;
+ struct sockaddr *dst;
{
- int type, dest;
+ int type, dest, s, error;
register struct mbuf *m = m0;
register struct en_header *en;
- int s;
+ register int off;
- switch (pf) {
+ switch (dst->sa_family) {
#ifdef INET
- case PF_INET: {
- register struct ip *ip = mtod(m0, struct ip *);
- int off;
-
-#ifndef ENKLUDGE
- dest = ip->ip_dst.s_addr >> 24;
-#else
- dest = (ip->ip_dst.s_addr >> 8) & 0xff;
-#endif
- off = ntohs((u_short)ip->ip_len) - m->m_len;
-#ifndef ENKLUDGE
- if (off > 0 && (off & 0x1ff) == 0 && m->m_off >= MMINOFF + 2) {
- type = ENPUP_TRAIL + (off>>9);
- m->m_off -= 2;
- m->m_len += 2;
- *mtod(m, u_short *) = ENPUP_IPTYPE;
+ case AF_INET:
+ {
+ struct in_addr in;
+
+ in = ((struct sockaddr_in *)dst)->sin_addr;
+ if (in_broadcast(in))
+ dest = EN_BROADCAST;
+ else
+ dest = in_lnaof(in);
+ }
+ if (dest >= 0x100) {
+ error = EPERM; /* ??? */
+ goto bad;
+ }
+ off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
+ /* need per host negotiation */
+ if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
+ if (off > 0 && (off & 0x1ff) == 0 &&
+ m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
+ type = ENTYPE_TRAIL + (off>>9);
+ m->m_off -= 2 * sizeof (u_short);
+ m->m_len += 2 * sizeof (u_short);
+ *mtod(m, u_short *) = htons((u_short)ENTYPE_IP);
+ *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
goto gottrailertype;
}
+ type = ENTYPE_IP;
+ off = 0;
+ goto gottype;
#endif
- type = ENPUP_IPTYPE;
+#ifdef PUP
+ case AF_PUP:
+ dest = ((struct sockaddr_pup *)dst)->spup_host;
+ type = ENTYPE_PUP;
off = 0;
goto gottype;
- }
+#endif
+
+#ifdef notdef
+ case AF_ETHERLINK:
+ goto gotheader;
#endif
default:
- printf("en%d: can't encapsulate pf%d\n", ifp->if_unit, pf);
- m_freem(m0);
- return (0);
+ printf("en%d: can't handle af%d\n", ifp->if_unit,
+ dst->sa_family);
+ error = EAFNOSUPPORT;
+ goto bad;
}
gottrailertype:
*/
if (m->m_off > MMAXOFF ||
MMINOFF + sizeof (struct en_header) > m->m_off) {
- m = m_get(0);
+ MGET(m, M_DONTWAIT, MT_HEADER);
if (m == 0) {
- m_freem(m0);
- return (0);
+ error = ENOBUFS;
+ goto bad;
}
m->m_next = m0;
m->m_off = MMINOFF;
m->m_len += sizeof (struct en_header);
}
en = mtod(m, struct en_header *);
- en->en_shost = ifp->if_host[0];
+ /* add en_shost later */
en->en_dhost = dest;
- en->en_type = type;
+ en->en_type = htons((u_short)type);
+gotheader:
/*
* 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 (en_softc[ifp->if_unit].es_oactive == 0)
enstart(ifp->if_unit);
splx(s);
- return (1);
+ return (0);
+qfull:
+ m0 = m;
+ splx(s);
+bad:
+ m_freem(m0);
+ return (error);
+}
+
+/*
+ * Process an ioctl request.
+ */
+enioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ register struct en_softc *es = ((struct en_softc *)ifp);
+ struct ifaddr *ifa = (struct ifaddr *) data;
+ int s = splimp(), error = 0;
+ struct endevice *enaddr;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr;
+ es->es_host = (~enaddr->en_addr) & 0xff;
+ /*
+ * Attempt to check agreement of protocol address
+ * and board address.
+ */
+ switch (ifa->ifa_addr.sa_family) {
+ case AF_INET:
+ if (in_lnaof(IA_SIN(ifa)->sin_addr) != es->es_host)
+ return (EADDRNOTAVAIL);
+ break;
+ }
+ ifp->if_flags |= IFF_UP;
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ eninit(ifp->if_unit);
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ splx(s);
+ return (error);
}
+
+#ifdef ENF_SWABIPS
+/*
+ * Swab bytes
+ * Jeffrey Mogul, Stanford
+ */
+enswab(from, to, n)
+ register unsigned char *from, *to;
+ register int n;
+{
+ register unsigned long temp;
+
+ if ((n <= 0) || (n > 0xFFFF)) {
+ printf("enswab: bad len %d\n", n);
+ return;
+ }
+
+ n >>= 1; n++;
+#define STEP {temp = *from++;*to++ = *from++;*to++ = temp;}
+ /* round to multiple of 8 */
+ while ((--n) & 07)
+ STEP;
+ n >>= 3;
+ while (--n >= 0) {
+ STEP; STEP; STEP; STEP;
+ STEP; STEP; STEP; STEP;
+ }
+}
+#endif