From 2c0ded8a66266e1638c96cbba5106ffc7cb7bb52 Mon Sep 17 00:00:00 2001 From: Mike Accetta Date: Sun, 10 Nov 1985 21:58:55 -0800 Subject: [PATCH] BSD 4_3 development Work on file usr/contrib/enet/net/enet.h Work on file usr/contrib/enet/net/enet.c Work on file usr/contrib/enet/net/enetdefs.h Synthesized-from: CSRG/cd1/4.3 --- usr/contrib/enet/net/enet.c | 1653 +++++++++++++++++++++++++++++++ usr/contrib/enet/net/enet.h | 173 ++++ usr/contrib/enet/net/enetdefs.h | 239 +++++ 3 files changed, 2065 insertions(+) create mode 100644 usr/contrib/enet/net/enet.c create mode 100644 usr/contrib/enet/net/enet.h create mode 100644 usr/contrib/enet/net/enetdefs.h diff --git a/usr/contrib/enet/net/enet.c b/usr/contrib/enet/net/enet.c new file mode 100644 index 0000000000..98f62adfb9 --- /dev/null +++ b/usr/contrib/enet/net/enet.c @@ -0,0 +1,1653 @@ +/* enet.c Stanford 25 April 1983 */ + +/* + * Ethernet packet filter layer, + * formerly: Ethernet interface driver + * + ********************************************************************** + * HISTORY + * 7 October 1985 Jeff Mogul Stanford + * Removed ENMAXOPENS limitation; available minors are now + * dynamically allocated to interfaces, out of pool of NENETFILTER + * minors. + * Certain arrays formerly in the enState structure are now global. + * Depends on modified openi() function so that enetopen() need + * only be called once. + * Remove support for "kernel access", it won't ever be used again. + * Added EIOCMFREE ioctl. + * + * 17 October 1984 Jeff Mogul Stanford + * More performance improvements: + * Added ENF_CAND, ENF_COR, ENF_CNAND, and ENF_CNOR, short-circuit + * operators, to make filters run faster. + * All evaluate "(*sp++ == *sp++)": + * ENF_CAND: returns false immediately if result is false, otherwise + * continue + * ENF_COR: returns true immediately if result is true, otherwise + * continue + * ENF_CNAND: returns true immediately if result is false, otherwise + * continue + * ENF_CNOR: returns false immediately if result is true, otherwise + * continue + * Also added ENF_NEQ to complement ENF_EQ + * - Maintain count of received packets per filter, dynamically + * re-organize filter queue to keep highly active filters in + * front of queue (but maintaining priority order), if they are + * "high priority" filters. + * + * 2 October 1984 Jeff Mogul Stanford + * Made a few changes to enDoFilter() to speed it up, since profiling + * shows it to be rather popular: + * - precompute maximum word in packet and address of end of + * filters (thereby moving this code out of "inner loop"). + * - minor re-arrangement to avoid re-evaluating a + * common subexpression. + * - changed #ifdef DEBUG in a few routines to #ifdef INNERDEBUG, + * so that code in inner loops isn't always testing the enDebug + * flag; this not only costs directly, but also breaks up some + * basic blocks that the optimizer could play with. + * - added enOneCopy flag; if true, then never deliver more than + * one copy of a packet. This is equivalent to giving everyone + * a "high priority" device, and cuts down the number of superfluous + * calls to enDoFilter(). [Temporary hack, will remove this!] + * + * 24 August 1984 Jeff Mogul Stanford + * YA bug with sleeping in enetwrite(); straightened out handling + * of counts in enKludgeSleep so that they indicate the number + * of sleeps in progress. Maybe I've got this right, now? + * Also, don't sleep forever (since the net might be down). + * + * 17 July 1984 Jeff Mogul Stanford + * Bug fix: in enetwrite(), several problems with sleeping on + * IF_QFULL: + * - don't do it for kernel mode writes. + * - count # of procs sleeping, to avoid lost wakeups. Old + * scheme would only wake up the first sleeper. + * - using sleeper-count, avoid using more than one timeout + * table entry per device; old scheme caused timeout table panics + * - trap interupted sleeps using setjmp, so that we can deallocate + * packet header and mbufs; otherwise we lost them and panicked. + * + * 5 July 1984 Jeff Mogul Stanford + * Bug fix: in enetwrite() make sure enP_RefCount is zero before + * deallocating "packet". Otherwise, "packets" get lost, and + * take mbufs (and ultimately, the system) with them. + * + * 8 December 1983 Jeffrey Mogul Stanford + * Fixed bug in enetwrite() that eventually caused allocator + * to run out of packets and panic. If enetwrite() returns + * an error it should first deallocate any packets it has allocated. + * + * 10 November 1983 Jeffrey Mogul Stanford + * Slight restructuring for support of 10mb ethers; + * - added the EIOCDEVP ioctl + * - removed the EIOCMTU ioctl (subsumed by EIOCDEVP) + * This requires an additional parameter to the enetattach + * call so that the device driver can specify things. + * + * Also, cleaned up the enDebug scheme by adding symbolic + * definitions for the bits. + * + * 25-Apr-83 Jeffrey Mogul Stanford + * Began conversion to 4.2BSD. This involves removing all + * references to the actual hardware. + * Changed read/write interface to use uio scheme. + * Changed ioctl interface to "new style"; this places a hard + * limit on the size of a filter (about 128 bytes). + * "Packets" now point to mbufs, not private buffers. + * Filter can only access data in first mbuf (about 50 words worst case); + * this is long enough for all Pup purposes. + * Added EIOCMTU ioctl to get MTU (max packet size). + * Added an enetselect() routine and other select() support. + * Other stuff is (more or less) left intact. + * Most previous history comments removed. + * Changed some names from enXXXX to enetXXXX to avoid confusion(?) + * + * 10-Aug-82 Mike Accetta (mja) at Carnegie-Mellon University + * Added new EIOCMBIS and EIOCMBIC ioctl calls to set and clear + * bits in mode word; added mode bit ENHOLDSIG which suppresses + * the resetting of an enabled signal after it is sent (to be + * used inconjunction with the SIGHOLD mechanism); changed + * EIOCGETP to zero pad word for future compatibility; changed enwrite() + * to enforce correct source host address on output packets (V3.05e). + * (Stanford already uses long timeout value and has no pad word - JCM) + * [Last change before 4.2BSD conversion starts.] + * + * 01-Dec-81 Mike Accetta (mja) at Carnegie-Mellon University + * Fixed bug in timeout handling caused by missing "break" in the + * "switch" state check within enetread(). This caused all reads + * to be preceeded by a bogus timeout. In addition, fixed another + * bug in signal processing by also recording process ID of + * process to signal when an input packet is available. This is + * necessary because it is possible for a process with an enabled + * signal to fork and exit with no guarantee that the child will + * reenable the signal. Thus under appropriately bizarre race + * conditions, an incoming packet to the child can cause a signal + * to be sent to the unsuspecting process which inherited the + * process slot of the parent. Of course, if the PID's wrap around + * AND the inheriting process has the same PID, well ... (V3.03d). + * + * 22-Feb-80 Rick Rashid (rfr) at Carnegie-Mellon University + * Rewritten to provide multiple user access via user settable + * filters (V1.05). + * + * 18-Jan-80 Mike Accetta (mja) at Carnegie-Mellon University + * Created (V1.00). + * + ********************************************************************** + */ + +#include "en.h" +#include "ec.h" +#include "il.h" +#include "de.h" +#include "enetfilter.h" + +/* number of potential units */ +#define NENET (NEC + NEN + NIL + NDE) + +#if (NENETFILTER > 0) + +#define SUN_OPENI + +#include "param.h" +#include "systm.h" +#include "mbuf.h" +#include "buf.h" +#include "dir.h" +#include "user.h" +#include "ioctl.h" +#include "map.h" +#include "proc.h" +#include "inode.h" +#include "file.h" +#include "tty.h" +#include "uio.h" + +#include "protosw.h" +#include "socket.h" +#include "../net/if.h" + +#undef queue +#undef dequeue +#include "../net/enet.h" +#include "../net/enetdefs.h" + +#if (NENETFILTER < 32) +#undef NENETFILTER +#define NENETFILTER 32 +#endif + +#if (NENETFILTER > 256) +#undef NENETFILTER +#define NENETFILTER 256 /* maximum number of minor devices */ +#endif + +#define DEBUG 1 +/* #define INNERDEBUG 1 */ /* define only when debugging enDoFilter() + or enInputDone() */ + +#define enprintf(flags) if (enDebug&(flags)) printf + +/* + * Symbolic definitions for enDebug flag bits + * ENDBG_TRACE should be 1 because it is the most common + * use in the code, and the compiler generates faster code + * for testing the low bit in a word. + */ + +#define ENDBG_TRACE 1 /* trace most operations */ +#define ENDBG_DESQ 2 /* trace descriptor queues */ +#define ENDBG_INIT 4 /* initialization info */ +#define ENDBG_SCAV 8 /* scavenger operation */ +#define ENDBG_ABNORM 16 /* abnormal events */ + + +#define min(a,b) ( ((a)<=(b)) ? (a) : (b) ) + +#define splenet splimp /* used to be spl6 but I'm paranoid */ + +#define PRINET 26 /* interruptible */ + +/* + * 'enQueueElts' is the pool of packet headers used by the driver. + * 'enPackets' is the pool of packets used by the driver (these should + * be allocated dynamically when this becomes possible). + * 'enFreeq' is the queue of available packets + * 'enState' is the driver state table per logical unit number + * 'enUnit' is the physical unit number table per logical unit number; + * the first "attach"ed ethernet is logical unit 0, etc. + * 'enUnitMap' maps minor device numbers onto interface unit #s + * 'enAllocMap' indicates if minor device is allocated or free + * 'enAllDescriptors' stores OpenDescriptors, indexed by minor device # + * 'enFreeqMin' is the minimum number of packets ever in the free queue + * (for statistics purposes) + * 'enScavenges' is the number of scavenges of the active input queues + * (for statustics purposes) + * 'enDebug' is a collection of debugging bits which enable trace and/or + * diagnostic output as defined above (ENDBG_*) + * 'enUnits' is the number of attached units + * 'enOneCopy' if true, then no packet is delivered to more than one minor + * device + */ +struct enPacket enQueueElts[ENPACKETS]; +struct enQueue enFreeq; +struct enState enState[NENET]; +char enUnitMap[NENETFILTER]; +char enAllocMap[NENETFILTER]; +struct enOpenDescriptor + enAllDescriptors[NENETFILTER]; +int enFreeqMin = ENPACKETS; +int enScavenges = 0; +int enDebug = ENDBG_ABNORM; +int enUnits = 0; +int enOneCopy = 0; +int enMaxMinors = NENETFILTER; + +/* + * Forward declarations for subroutines which return other + * than integer types. + */ +extern boolean enDoFilter(); + + +/* + * Linkages to if_en.c + */ + +struct enet_info { + struct ifnet *ifp; /* which ifp for output */ +} enet_info[NENET]; + +struct sockaddr enetaf = { AF_IMPLINK }; + + +/**************************************************************** + * * + * Various Macros & Routines * + * * + ****************************************************************/ + +/* + * forAllOpenDescriptors(p) -- a macro for iterating + * over all currently open devices. Use it in place of + * "for ( ...; ... ; ... )" + * and supply your own loop body. The loop variable is the + * parameter p which is set to point to the descriptor for + * each open device in turn. + */ + +#define forAllOpenDescriptors(p) \ + for ((p) = (struct enOpenDescriptor *)enDesq.enQ_F; \ + (struct Queue *)(&enDesq) != &((p)->enOD_Link); \ + (p) = (struct enOpenDescriptor *)(p)->enOD_Link.F) + +/* + * enEnqueue - add an element to a queue + */ + +#define enEnqueue(q, elt) \ +{ \ + enqueue((struct Queue *)(q), (struct Queue *)(elt)); \ + (q)->enQ_NumQueued++; \ +} + +/* + * enFlushQueue - release all packets from queue, freeing any + * whose reference counts drop to 0. Assumes caller + * is at high IPL so that queue will not be modified while + * it is being flushed. + */ + +enFlushQueue(q) +register struct enQueue *q; +{ + + register struct enPacket *qelt; + + while((qelt=(struct enPacket *)dequeue((struct Queue *)q)) != NULL) + { + if (0 == --(qelt->enP_RefCount)) + { + enEnqueue(&enFreeq, qelt); + } + } + q->enQ_NumQueued = 0; + +} + +/* + * enInitWaitQueue - initialize an empty packet wait queue + */ + +enInitWaitQueue(wq) +register struct enWaitQueue *wq; +{ + + wq->enWQ_Head = 0; + wq->enWQ_Tail = 0; + wq->enWQ_NumQueued = 0; + wq->enWQ_MaxWaiting = ENDEFWAITING; + +} + +/* + * enEnWaitQueue - add a packet to a wait queue + */ + +enEnWaitQueue(wq, p) +register struct enWaitQueue *wq; +struct enPacket *p; +{ + + wq->enWQ_Packets[wq->enWQ_Tail] = p; + wq->enWQ_NumQueued++; + enNextWaitQueueIndex(wq->enWQ_Tail); + +} + +/* + * enDeWaitQueue - remove a packet from a wait queue + */ + +struct enPacket * +enDeWaitQueue(wq) +register struct enWaitQueue *wq; +{ + + struct enPacket *p; + + wq->enWQ_NumQueued--; + if (wq->enWQ_NumQueued < 0) + panic("enDeWaitQueue"); + p = wq->enWQ_Packets[wq->enWQ_Head]; + enNextWaitQueueIndex(wq->enWQ_Head); + + return(p); + +} + +/* + * enTrimWaitQueue - cut a wait queue back to size + */ +enTrimWaitQueue(wq, threshold) +register struct enWaitQueue *wq; +{ + + register int Counter = (wq->enWQ_NumQueued - threshold); + register struct enPacket *p; + +#ifdef DEBUG + enprintf(ENDBG_SCAV) + ("enTrimWaitQueue(%x, %d): %d\n", wq, threshold, Counter); +#endif + while (Counter-- > 0) + { + wq->enWQ_NumQueued--; + enPrevWaitQueueIndex(wq->enWQ_Tail); + p = wq->enWQ_Packets[wq->enWQ_Tail]; + if (0 == --(p->enP_RefCount)) + { + m_freem(p->enP_mbuf); + enEnqueue(&enFreeq, p); + } + } +} +/* + * enFlushWaitQueue - remove all packets from wait queue + */ + +#define enFlushWaitQueue(wq) enTrimWaitQueue(wq, 0) + +/* + * scavenging thresholds: + * + * index by number of active files; for N open files, each queue may retain + * up to 1/Nth of the packets not guaranteed to be freed on scavenge. The + * total number of available packets is computed less one for sending. + * + * (assumes high IPL) + */ +char enScavLevel[NENETFILTER+1]; + +/* + * enInitScavenge -- set up ScavLevel table + */ +enInitScavenge() +{ + register int PoolSize = (ENPACKETS-ENMINSCAVENGE); + register int i = sizeof(enScavLevel); + + PoolSize--; /* leave one for transmitter */ + while (--i>0) + enScavLevel[i] = (PoolSize / i); +} + +/* + * enScavenge -- scan all OpenDescriptors for all ethernets, releasing + * any queued buffers beyond the prescribed limit and freeing any whose + * refcounts drop to 0. + * Assumes caller is at high IPL so that it is safe to modify the queues. + */ +enScavenge() +{ + + register struct enOpenDescriptor *d; + register int threshold = 0; + register struct enState *enStatep; + + for (enStatep=enState; enStatep < &enState[NENET]; enStatep++) + threshold += enCurOpens; + threshold = enScavLevel[threshold]; + + /* recalculate thresholds based on current allocations */ + enInitScavenge(); + + enScavenges++; +#ifdef DEBUG + enprintf(ENDBG_SCAV)("enScavenge: %d\n", threshold); +#endif + for (enStatep=enState; enStatep < &enState[NENET]; enStatep++) + { + if (enDesq.enQ_F == 0) + continue; /* never initialized */ + forAllOpenDescriptors(d) + { + enTrimWaitQueue(&(d->enOD_Waiting), threshold); + } + } + +} + +/* + * enAllocatePacket - allocate the next packet from the free list + * + * Assumes IPL is at high priority so that it is safe to touch the + * packet queue. If the queue is currently empty, scavenge for + * more packets. + */ + +struct enPacket * +enAllocatePacket() +{ + + register struct enPacket *p; + + if (0 == enFreeq.enQ_NumQueued) + enScavenge(); + p = (struct enPacket *)dequeue((struct Queue *)&enFreeq); + if (p == NULL) + panic("enAllocatePacket"); + if (enFreeqMin > --enFreeq.enQ_NumQueued) + enFreeqMin = enFreeq.enQ_NumQueued; + + p->enP_RefCount = 0; /* just in case */ + + return(p); + +} + +/* + * enDeallocatePacket - place the packet back on the free packet queue + * + * (High IPL assumed). + */ + +#define enDeallocatePacket(p) \ +{ \ + if (p->enP_RefCount) panic("enDeallocatePacket: refcount != 0");\ + enqueue((struct Queue *)&enFreeq, (struct Queue *)(p)); \ + enFreeq.enQ_NumQueued++; \ +} + +/**************************************************************** + * * + * Routines to move uio data to/from mbufs * + * * + ****************************************************************/ + +/* + * These two routines were inspired by/stolen from ../sys/uipc_socket.c + * Both return error code (or 0 if success). + */ + +/* + * read: return contents of mbufs to user. DO NOT free them, since + * there may be multiple claims on the packet! + */ +enrmove(m, uio, count) +register struct mbuf *m; +register struct uio *uio; +register int count; +{ + register int len; + register int error = 0; + + count = min(count, uio->uio_resid); /* # of bytes to return */ + + while ((count > 0) && m && (error == 0)) { + len = min(count, m->m_len); /* length of this transfer */ + count -= len; + error = uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); + + m = m->m_next; + } + return(error); +} + +enwmove(uio, mbufp) +register struct uio *uio; +register struct mbuf **mbufp; /* top mbuf is returned by reference */ +{ + struct mbuf *mtop = 0; + register struct mbuf *m; + register struct mbuf **mp = &mtop; + register struct iovec *iov; + register int len; + int error = 0; + + while ((uio->uio_resid > 0) && (error == 0)) { + iov = uio->uio_iov; + + if (iov->iov_len == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + if (uio->uio_iovcnt < 0) + panic("enwmove: uio_iovcnt < 0 while uio_resid > 0"); + } + MGET(m, M_WAIT, MT_DATA); + if (m == NULL) { + error = ENOBUFS; + break; + } + if (iov->iov_len >= CLBYTES) { /* big enough to use a page */ + register struct mbuf *p; + MCLGET(p, 1); + if (p == 0) + goto nopages; + m->m_off = (int)p - (int)m; + len = CLBYTES; + } + else { +nopages: + len = MIN(MLEN, iov->iov_len); + } + error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); + m->m_len = len; + *mp = m; + mp = &(m->m_next); + } + + if (error) { /* probably uiomove fouled up */ + if (mtop) + m_freem(mtop); + } + else { + *mbufp = mtop; /* return ptr to top mbuf */ + } + return(error); +} + +/* + * enetopen - open ether net device + * + * Errors: ENXIO - illegal minor device number + * EBUSY - minor device already in use + */ + +/* ARGSUSED */ +enetopen(dev, flag, newmin) +dev_t dev; +int flag; +int *newmin; +{ + register int md; + register int unit = minor(dev); + register struct enState *enStatep; +#ifndef SUN_OPENI + register int error; +#endif SUN_OPENI + + /* + * Each open enet file has a different minor device number. + * When a user tries to open any of them, we actually open + * any available minor device and associate it with the + * corresponding unit. + * + * This is not elegant, but UNIX will call + * open for each new open file using the same inode but calls + * close only when the last open file referring to the inode + * is released. This means that we cannot know inside the + * driver code when the resources associated with a particular + * open of the same inode should be deallocated. Thus, we have + * to make up a temporary inode to represent each simultaneous + * open of the ethernet. Each inode has a different minor device number. + */ + +#ifdef DEBUG + enprintf(ENDBG_TRACE)("enetopen(%o, %x):\n", unit, flag); +#endif + + /* check for illegal minor dev */ + if ( (unit >= enUnits) /* bad unit */ + || (enet_info[unit].ifp == 0) /* ifp not known */ + || ((enet_info[unit].ifp->if_flags & IFF_UP) == 0) ) + /* or if down */ + { + return(ENXIO); + } + + md = enFindMinor(); +#ifdef DEBUG + enprintf(ENDBG_TRACE)("enetopen: md = %d\n", md); +#endif + if (md < 0) + { + return(EBUSY); + } + + enUnitMap[md] = unit; + enAllocMap[md] = TRUE; + +#ifdef SUN_OPENI + *newmin = md; +#else + error = mkpseudo(makedev(major(dev), md))); + if (error) { + enAllocMap[md] = FALSE; + return(error); + } +#endif SUN_OPENI + + enStatep = &enState[unit]; + enprintf(ENDBG_DESQ) + ("enetopen: Desq: %x, %x\n", enDesq.enQ_F, enDesq.enQ_B); + enInitDescriptor(&enAllDescriptors[md], flag); + enInsertDescriptor(&(enDesq), &enAllDescriptors[md]); + + return(0); +} + +/* + * enFindMinor - find a free logical device on specified unit + */ +enFindMinor() +{ + register int md; + + for (md = 0; md < enMaxMinors; md++) { + if (enAllocMap[md] == FALSE) + return(md); + } + return(-1); +} + +/* + * enInit - intialize ethernet unit (called by enetattach) + */ + +enInit(enStatep, unit) +register struct enState *enStatep; +register int unit; +{ + +#ifdef DEBUG + enprintf(ENDBG_INIT)("enInit(%x %d):\n", enStatep, unit); +#endif + + /* initialize free queue if not already done */ + if (enFreeq.enQ_F == 0) + { + register int i; + + initqueue((struct Queue *)&enFreeq); + for (i=0; ienP_RefCount = 0; + enDeallocatePacket(p); + } + /* also a good time to init enAllocMap */ + for (i = 0; i < enMaxMinors; i++) + enAllocMap[i] = FALSE; + } + initqueue((struct Queue *)&enDesq); /* init descriptor queue */ +} + +/* + * enetclose - ether net device close routine + */ + +/* ARGSUSED */ +enetclose(dev, flag) +{ + register int md = ENINDEX(dev); + register struct enState *enStatep = &enState[ENUNIT(dev)]; + register struct enOpenDescriptor *d = &enAllDescriptors[md]; + int ipl; + + enAllocMap[md] = FALSE; + +#ifdef DEBUG + enprintf(ENDBG_TRACE)("enetclose(%d, %x):\n", md, flag); +#endif + + /* + * insure that receiver doesn't try to queue something + * for the device as we are decommissioning it. + * (I don't think this is necessary, but I'm a coward.) + */ + ipl = splenet(); + dequeue((struct Queue *)d->enOD_Link.B); + enCurOpens--; + enprintf(ENDBG_DESQ) + ("enetclose: Desq: %x, %x\n", enDesq.enQ_F, enDesq.enQ_B); + enFlushWaitQueue(&(d->enOD_Waiting)); + splx(ipl); + +} + +/* + * enetread - read next packet from net + */ + +/* VARARGS */ +enetread(dev, uio) +dev_t dev; +register struct uio *uio; +{ + register struct enOpenDescriptor *d = &enAllDescriptors[ENINDEX(dev)]; + register struct enPacket *p; + int ipl; + int error; + extern enTimeout(); + +#if DEBUG + enprintf(ENDBG_TRACE)("enetread(%x):", dev); +#endif + + ipl = splenet(); + /* + * If nothing is on the queue of packets waiting for + * this open enet file, then set timer and sleep until + * either the timeout has occurred or a packet has + * arrived. + */ + + while (0 == d->enOD_Waiting.enWQ_NumQueued) + { + if (d->enOD_Timeout < 0) + { + splx(ipl); + return(0); + } + if (d->enOD_Timeout) + { + /* + * If there was a previous timeout pending for this file, + * cancel it before setting another. This is necessary since + * a cancel after the sleep might never happen if the read is + * interrupted by a signal. + */ + if (d->enOD_RecvState == ENRECVTIMING) + untimeout(enTimeout, (caddr_t)d); + timeout(enTimeout, (caddr_t)d, (int)(d->enOD_Timeout)); + d->enOD_RecvState = ENRECVTIMING; + } + else + d->enOD_RecvState = ENRECVIDLE; + + sleep((caddr_t)d, PRINET); + + switch (d->enOD_RecvState) + { + case ENRECVTIMING: + { + untimeout(enTimeout, (caddr_t)d); + d->enOD_RecvState = ENRECVIDLE; + break; + } + case ENRECVTIMEDOUT: + { + splx(ipl); + return(0); + } + } + } + + p = enDeWaitQueue(&(d->enOD_Waiting)); + splx(ipl); + + /* + * Move data from packet into user space. + */ + error = enrmove(p->enP_mbuf, uio, p->enP_ByteCount); + + ipl = splenet(); + if (0 == --(p->enP_RefCount)) /* if no more claims on this packet */ + { + m_freem(p->enP_mbuf); /* release mbuf */ + enDeallocatePacket(p); /* and packet */ + } + splx(ipl); + + return(error); +} + + + +/* + * enTimeout - process ethernet read timeout + */ + +enTimeout(d) +register struct enOpenDescriptor * d; +{ + register int ipl; + +#ifdef DEBUG + enprintf(ENDBG_TRACE)("enTimeout(%x):\n", d); +#endif + ipl = splenet(); + d->enOD_RecvState = ENRECVTIMEDOUT; + wakeup((caddr_t)d); + enetwakeup(d); + splx(ipl); + +} + +/* + * enetwrite - write next packet to net + */ + +int enKludgeSleep[NENET]; /* Are we sleeping on IF_QFULL? */ + /* really, # of procs sleeping on IF_QFULL */ + +/* VARARGS */ +enetwrite(dev, uio) +dev_t dev; +register struct uio *uio; +{ + register int unit = ENUNIT(dev); + register struct enState *enStatep = &enState[unit]; + struct mbuf *mp; + register struct ifnet *ifp = enet_info[unit].ifp; + int ipl; + int error; + int sleepcount; + int enKludgeTime(); + +#if DEBUG + enprintf(ENDBG_TRACE)("enetwrite(%x):\n", dev); +#endif + + if (uio->uio_resid == 0) + return(0); + if (uio->uio_resid > ifp->if_mtu) /* too large */ + return(EMSGSIZE); + + /* + * Copy user data into mbufs + */ + if (error = enwmove(uio, &mp)) { + return(error); + } + + ipl = splenet(); + /* + * if the queue is full, + * hang around until there's room or until process is interrupted + */ + sleepcount = 0; + while (IF_QFULL(&(ifp->if_snd))) { + extern int hz; + if (sleepcount++ > 2) { /* don't sleep too long */ + splx(ipl); + return(ETIMEDOUT); + } + /* if nobody else has a timeout pending for this unit, set one */ + if (enKludgeSleep[unit] == 0) + timeout(enKludgeTime, (caddr_t)unit, 2 * hz); + enKludgeSleep[unit]++; /* record that we are sleeping */ + if (setjmp(&u.u_qsave)) { + /* sleep (following) was interrupted, clean up */ +#if DEBUG + enprintf(ENDBG_ABNORM) + ("enetwrite(%x): enet%d sleep %d interrupted\n", dev, + unit, enKludgeSleep[unit]); +#endif DEBUG + enKludgeSleep[unit]--; /* we're no longer sleeping */ + m_freem(mp); + splx(ipl); + return(EINTR); + } + sleep((caddr_t)&(enKludgeSleep[unit]), PRINET); + enKludgeSleep[unit]--; /* we are no longer sleeping */ + } + + /* place mbuf chain on outgoing queue & start if necessary */ + error = (*ifp->if_output)(ifp, mp, &enetaf); + /* this always frees the mbuf chain */ + enXcnt++; + + splx(ipl); + + return(error); +} + +enKludgeTime(unit) +int unit; +{ + /* XXX perhaps we should always wakeup? */ + if (enKludgeSleep[unit]) { + wakeup((caddr_t)&(enKludgeSleep[unit])); + /* XXX should we restart transmitter? */ + } +} + +/* + * enetioctl - ether net control + * + * EIOCGETP - get ethernet parameters + * EIOCSETP - set ethernet read timeout + * EIOCSETF - set ethernet read filter + * EIOCENBS - enable signal when read packet available + * EIOCINHS - inhibit signal when read packet available + * FIONREAD - check for read packet available + * EIOCSETW - set maximum read packet waiting queue length + * EIOCFLUSH - flush read packet waiting queue + * EIOCMBIS - set mode bits + * EIOCMBIC - clear mode bits + * EICODEVP - get device parameters + * EIOCMFREE - number of free minors + */ + +/* ARGSUSED */ +enetioctl(dev, cmd, addr, flag) +caddr_t addr; +dev_t flag; +{ + + register struct enState *enStatep = &enState[ENUNIT(dev)]; + register struct enOpenDescriptor * d = &enAllDescriptors[ENINDEX(dev)]; + int ipl; + +#if DEBUG + enprintf(ENDBG_TRACE) + ("enetioctl(%x, %x, %x, %x):\n", dev, cmd, addr, flag); +#endif + + switch (cmd) + { + case EIOCGETP: + { + struct eniocb t; + + t.en_maxwaiting = ENMAXWAITING; + t.en_maxpriority = ENMAXPRI; + t.en_rtout = d->enOD_Timeout; + t.en_addr = -1; + t.en_maxfilters = ENMAXFILTERS; + + bcopy((caddr_t)&t, addr, sizeof t); + } + endcase + + case EIOCSETP: + { + struct eniocb t; + + bcopy(addr, (caddr_t)&t, sizeof t); + d->enOD_Timeout = t.en_rtout; + } + endcase + + case EIOCSETF: + { + struct enfilter f; + unsigned short *fp; + + bcopy(addr, (caddr_t)&f, sizeof f); + if (f.enf_FilterLen > ENMAXFILTERS) + { + return(EINVAL); + } + /* insure that filter is installed indivisibly */ + ipl = splenet(); + bcopy((caddr_t)&f, (caddr_t)&(d->enOD_OpenFilter), sizeof f); + /* pre-compute length of filter */ + fp = &(d->enOD_OpenFilter.enf_Filter[0]); + d->enOD_FiltEnd = &(fp[d->enOD_OpenFilter.enf_FilterLen]); + d->enOD_RecvCount = 0; /* reset count when filter changes */ + dequeue((struct Queue *)d->enOD_Link.B); + enDesq.enQ_NumQueued--; + enInsertDescriptor(&(enDesq), d); + splx(ipl); + } + endcase + + /* + * Enable signal n on input packet + */ + case EIOCENBS: + { + int snum; + + bcopy(addr, (caddr_t)&snum, sizeof snum); + if (snum < NSIG) { + d->enOD_SigProc = u.u_procp; + d->enOD_SigPid = u.u_procp->p_pid; + d->enOD_SigNumb = snum; /* This must be set last */ + } else { + goto bad; + } + } + endcase + + /* + * Disable signal on input packet + */ + case EIOCINHS: + { + d->enOD_SigNumb = 0; + } + endcase + + /* + * Check for packet waiting + */ + case FIONREAD: + { + int n; + register struct enWaitQueue *wq; + + ipl = splenet(); + if ((wq = &(d->enOD_Waiting))->enWQ_NumQueued) + n = wq->enWQ_Packets[wq->enWQ_Head]->enP_ByteCount; + else + n = 0; + splx(ipl); + bcopy((caddr_t)&n, addr, sizeof n); + } + endcase + + /* + * Set maximum recv queue length for a device + */ + case EIOCSETW: + { + unsigned un; + + bcopy(addr, (caddr_t)&un, sizeof un); + /* + * unsigned un MaxQueued + * ---------------- ------------ + * 0 -> DEFWAITING + * 1..MAXWAITING -> un + * MAXWAITING..-1 -> MAXWAITING + */ + d->enOD_Waiting.enWQ_MaxWaiting = (un) ? min(un, ENMAXWAITING) + : ENDEFWAITING; + } + endcase + + /* + * Flush all packets queued for a device + */ + case EIOCFLUSH: + { + ipl = splenet(); + enFlushWaitQueue(&(d->enOD_Waiting)); + splx(ipl); + } + endcase + + /* + * Set mode bits + */ + case EIOCMBIS: + { + u_short mode; + + bcopy(addr, (caddr_t)&mode, sizeof mode); + if (mode&ENPRIVMODES) + return(EINVAL); + else + d->enOD_Flag |= mode; + } + endcase + + /* + * Clear mode bits + */ + case EIOCMBIC: + { + u_short mode; + + bcopy(addr, (caddr_t)&mode, sizeof mode); + if (mode&ENPRIVMODES) + return(EINVAL); + else + d->enOD_Flag &= ~mode; + } + endcase + + /* + * Return hardware-specific device parameters. + */ + case EIOCDEVP: + { + bcopy((caddr_t)&(enDevParams), addr, sizeof(struct endevp)); + } + endcase; + + /* + * Return # of free minor devices. + */ + case EIOCMFREE: + { + register int md; + register int sum = 0; + + for (md = 0; md < enMaxMinors; md++) + if (enAllocMap[md] == FALSE) + sum++; + *(int *)addr = sum; + } + endcase; + + default: + { + bad: + return(EINVAL); + } + } + + return(0); + +} + +/**************************************************************** + * * + * Support for select() system call * + * * + * Other hooks in: * + * enInitDescriptor() * + * enInputDone() * + * enTimeout() * + ****************************************************************/ +/* + * inspired by the code in tty.c for the same purpose. + */ + +/* + * enetselect - returns true iff the specific operation + * will not block indefinitely. Otherwise, return + * false but make a note that a selwakeup() must be done. + */ +enetselect(dev, rw) +register dev_t dev; +int rw; +{ + register struct enOpenDescriptor *d; + register struct enWaitQueue *wq; + register int ipl; + register int avail; + + switch (rw) { + + case FREAD: + /* + * an imitation of the FIONREAD ioctl code + */ + d = &(enAllDescriptors[ENINDEX(dev)]); + + ipl = splenet(); + wq = &(d->enOD_Waiting); + if (wq->enWQ_NumQueued) + avail = 1; /* at least one packet queued */ + else { + avail = 0; /* sorry, nothing queued now */ + /* + * If there's already a select() waiting on this + * minor device then this is a collision. + * [This shouldn't happen because enet minors + * really should not be shared, but if a process + * forks while one of these is open, it is possible + * that both processes could select() us.] + */ + if (d->enOD_SelProc + && d->enOD_SelProc->p_wchan == (caddr_t)&selwait) + d->enOD_SelColl = 1; + else + d->enOD_SelProc = u.u_procp; + } + splx(ipl); + return(avail); + + case FWRITE: + /* + * since the queueing for output is shared not just with + * the other enet devices but also with the IP system, + * we can't predict what would happen on a subsequent + * write. However, since we presume that all writes + * complete eventually, and probably fairly fast, we + * pretend that select() is true. + */ + return(1); + + default: /* hmmm. */ + return(1); /* don't block in select() */ + } +} + +enetwakeup(d) +register struct enOpenDescriptor *d; +{ + if (d->enOD_SelProc) { + selwakeup(d->enOD_SelProc, d->enOD_SelColl); + d->enOD_SelColl = 0; + d->enOD_SelProc = 0; + } +} + +/* + * enetFilter - incoming linkage from ../vaxif/if_en.c + */ + +enetFilter(en, m, count) +register int en; +register struct mbuf *m; +register int count; +{ + register struct enState *enStatep = &enState[en]; + register struct enPacket *p; + register int pullcount; /* bytes, not words */ + int s = splenet(); + +#if DEBUG + enprintf(ENDBG_TRACE)("enetFilter(%d):\n", en); +#endif + + p = enAllocatePacket(); /* panics if not possible */ + + p->enP_ByteCount = count; + + pullcount = min(MLEN, count); /* largest possible first mbuf */ + if (m->m_len < pullcount) { + /* first mbuf not as full as it could be - fix this */ + if ((m = m_pullup(m, pullcount)) == 0) { + /* evidently no resources; bloody m_pullup discarded mbuf */ + enDeallocatePacket(p); + enRdrops++; + goto out; + } + } + + p->enP_mbuf = m; + p->enP_Data = mtod(m, u_short *); + + enInputDone(enStatep, p); +out: + splx(s); +} + +/* + * enInputDone - process correctly received packet + */ + +enInputDone(enStatep, p) +register struct enState *enStatep; +register struct enPacket *p; +{ + register struct enOpenDescriptor *d; + int queued = 0; + register int maxword; + register unsigned long rcount; + register struct enOpenDescriptor *prevd; + +#if INNERDEBUG + enprintf(ENDBG_TRACE)("enInputDone(%x): %x\n", enStatep, p); +#endif + /* precompute highest possible word offset */ + /* can't address beyond end of packet or end of first mbuf */ + maxword = (min(p->enP_ByteCount, p->enP_mbuf->m_len)>>1); + + forAllOpenDescriptors(d) + { + if (enDoFilter(p, d, maxword)) + { + if (d->enOD_Waiting.enWQ_NumQueued < d->enOD_Waiting.enWQ_MaxWaiting) + { + enEnWaitQueue(&(d->enOD_Waiting), p); + p->enP_RefCount++; + queued++; + wakeup((caddr_t)d); + enetwakeup(d); +#if INNERDEBUG + enprintf(ENDBG_TRACE)("enInputDone: queued\n"); +#endif + } + /* send notification when input packet received */ + if (d->enOD_SigNumb) { + if (d->enOD_SigProc->p_pid == d->enOD_SigPid) + psignal(d->enOD_SigProc, d->enOD_SigNumb); + if ((d->enOD_Flag & ENHOLDSIG) == 0) + d->enOD_SigNumb = 0; /* disable signal */ + } + rcount = ++(d->enOD_RecvCount); + + /* see if ordering of filters is wrong */ + if (d->enOD_OpenFilter.enf_Priority >= ENHIPRI) { + prevd = (struct enOpenDescriptor *)d->enOD_Link.B; + /* + * If d is not the first element on the queue, and + * the previous element is at equal priority but has + * a lower count, then promote d to be in front of prevd. + */ + if (((struct Queue *)prevd != &(enDesq.enQ_Head)) && + (d->enOD_OpenFilter.enf_Priority == + prevd->enOD_OpenFilter.enf_Priority)) { + /* threshold difference to avoid thrashing */ + if ((100 + prevd->enOD_RecvCount) < rcount) { + enReorderQueue(&(prevd->enOD_Link), &(d->enOD_Link)); + } + } + break; /* high-priority filter => no more deliveries */ + } + else if (enOneCopy) + break; + } + } + if (queued == 0) /* this buffer no longer in use */ + { + m_freem(p->enP_mbuf); /* free mbuf */ + enDeallocatePacket(p); /* and packet */ + enRdrops++; + } + else + enRcnt++; + +} + +#define opx(i) (i>>ENF_NBPA) + +boolean +enDoFilter(p, d, maxword) +struct enPacket *p; +struct enOpenDescriptor *d; +register int maxword; +{ + + register unsigned short *sp; + register unsigned short *fp; + register unsigned short *fpe; + register unsigned op; + register unsigned arg; + unsigned short stack[ENMAXFILTERS+1]; + struct fw {unsigned arg:ENF_NBPA, op:ENF_NBPO;}; + +#ifdef INNERDEBUG + enprintf(ENDBG_TRACE)("enDoFilter(%x,%x):\n", p, d); +#endif + sp = &stack[ENMAXFILTERS]; + fp = &d->enOD_OpenFilter.enf_Filter[0]; + fpe = d->enOD_FiltEnd; + /* ^ is really: fpe = &fp[d->enOD_OpenFilter.enf_FilterLen]; */ + *sp = TRUE; + + for (; fp < fpe; ) + { + op = ((struct fw *)fp)->op; + arg = ((struct fw *)fp)->arg; + fp++; + switch (arg) + { + default: + arg -= ENF_PUSHWORD; +#ifndef lint + /* + * This next test is a little bogus; since arg + * is unsigned, it is always >= 0 (the compiler + * knows this and emits no code). If arg were + * less than ENF_PUSHWORD before the subtract, + * it is certaintly going to be more than maxword + * afterward, so the code does work "right" + */ + if ((arg >= 0) && (arg < maxword)) +#else + if (arg < maxword) +#endif lint + *--sp = p->enP_Data[arg]; + else + { +#ifdef INNERDEBUG + enprintf(ENDBG_TRACE)("=>0(len)\n"); +#endif + return(false); + } + break; + case ENF_PUSHLIT: + *--sp = *fp++; + break; + case ENF_PUSHZERO: + *--sp = 0; + case ENF_NOPUSH: + break; + } + if (sp < &stack[2]) /* check stack overflow: small yellow zone */ + { + enprintf(ENDBG_TRACE)("=>0(--sp)\n"); + return(false); + } + if (op == ENF_NOP) + continue; + /* + * all non-NOP operators binary, must have at least two operands + * on stack to evaluate. + */ + if (sp > &stack[ENMAXFILTERS-2]) + { + enprintf(ENDBG_TRACE)("=>0(sp++)\n"); + return(false); + } + arg = *sp++; + switch (op) + { + default: +#ifdef INNERDEBUG + enprintf(ENDBG_TRACE)("=>0(def)\n"); +#endif + return(false); + case opx(ENF_AND): + *sp &= arg; + break; + case opx(ENF_OR): + *sp |= arg; + break; + case opx(ENF_XOR): + *sp ^= arg; + break; + case opx(ENF_EQ): + *sp = (*sp == arg); + break; + case opx(ENF_NEQ): + *sp = (*sp != arg); + break; + case opx(ENF_LT): + *sp = (*sp < arg); + break; + case opx(ENF_LE): + *sp = (*sp <= arg); + break; + case opx(ENF_GT): + *sp = (*sp > arg); + break; + case opx(ENF_GE): + *sp = (*sp >= arg); + break; + + /* short-circuit operators */ + + case opx(ENF_COR): + if (*sp++ == arg) { +#ifdef INNERDEBUG + enprintf(ENDBG_TRACE)("=>COR %x\n", *sp); +#endif + return(true); + } + break; + case opx(ENF_CAND): + if (*sp++ != arg) { +#ifdef INNERDEBUG + enprintf(ENDBG_TRACE)("=>CAND %x\n", *sp); +#endif + return(false); + } + break; + case opx(ENF_CNOR): + if (*sp++ == arg) { +#ifdef INNERDEBUG + enprintf(ENDBG_TRACE)("=>COR %x\n", *sp); +#endif + return(false); + } + break; + case opx(ENF_CNAND): + if (*sp++ != arg) { +#ifdef INNERDEBUG + enprintf(ENDBG_TRACE)("=>CAND %x\n", *sp); +#endif + return(true); + } + break; + } + } +#ifdef INNERDEBUG + enprintf(ENDBG_TRACE)("=>%x\n", *sp); +#endif + return((boolean)*sp); + +} + +enInitDescriptor(d, flag) +register struct enOpenDescriptor *d; +{ + +#if DEBUG + enprintf(ENDBG_TRACE)("enInitDescriptor(%x):\n", d); +#endif + d->enOD_RecvState = ENRECVIDLE; + d->enOD_OpenFilter.enf_FilterLen = 0; + d->enOD_OpenFilter.enf_Priority = 0; + d->enOD_FiltEnd = &(d->enOD_OpenFilter.enf_Filter[0]); + d->enOD_RecvCount = 0; + d->enOD_Timeout = 0; + d->enOD_SigNumb = 0; + d->enOD_Flag = flag; + d->enOD_SelColl = 0; + d->enOD_SelProc = 0; /* probably unnecessary */ + /* + * Remember the PID that opened us, at least until some process + * sets a signal for this minor device + */ + d->enOD_SigPid = u.u_procp->p_pid; + + enInitWaitQueue(&(d->enOD_Waiting)); +#if DEBUG + enprintf(ENDBG_TRACE)("=>eninitdescriptor\n"); +#endif + +} + +/* + * enInsertDescriptor - insert open descriptor in queue ordered by priority + */ + +enInsertDescriptor(q, d) +register struct enQueue *q; +register struct enOpenDescriptor *d; +{ + struct enOpenDescriptor * nxt; + register int ipl; + + ipl = splenet(); + nxt = (struct enOpenDescriptor *)q->enQ_F; + while ((struct Queue *)q != &(nxt->enOD_Link)) + { + if (d->enOD_OpenFilter.enf_Priority > nxt->enOD_OpenFilter.enf_Priority) + break; + nxt = (struct enOpenDescriptor *)nxt->enOD_Link.F; + } + enqueue((struct Queue *)&(nxt->enOD_Link),(struct Queue *)&(d->enOD_Link)); + enprintf(ENDBG_DESQ)("enID: Desq: %x, %x\n", q->enQ_F, q->enQ_B); + q->enQ_NumQueued++; + splx(ipl); + +} + +int enReorderCount = 0; /* for external monitoring */ + +/* + * enReorderQueue - swap order of two elements in queue + * assumed to be called at splenet + */ +enReorderQueue(first, last) +register struct Queue *first; +register struct Queue *last; +{ + register struct Queue *prev; + register struct Queue *next; + + enprintf(ENDBG_DESQ)("enReorderQ: %x, %x\n", first, last); + + enReorderCount++; + + /* get pointers to other queue elements */ + prev = first->B; + next = last->F; + + /* + * no more reading from queue elements; this ensures that + * the code works even if there are fewer than 4 elements + * in the queue. + */ + + prev->F = last; + next->B = first; + + last->B = prev; + last->F = first; + + first->F = next; + first->B = last; +} + +enetattach(ifp, devp) +struct ifnet *ifp; +struct endevp *devp; +{ + register struct enState *enStatep = &enState[enUnits]; + +#ifdef DEBUG + enprintf(ENDBG_INIT) ("enetattach: type %d, addr ", devp->end_dev_type); + if (enDebug&ENDBG_INIT) { + register int i; + for (i = 0; i < devp->end_addr_len; i++) + printf("%o ", devp->end_addr[i]); + printf("\n"); + } +#endif DEBUG + + enet_info[enUnits].ifp = ifp; + + bcopy((caddr_t)devp, (caddr_t)&(enDevParams), sizeof(struct endevp)); + + enInit(enStatep, enUnits); + + return(enUnits++); +} + +#endif (NENETFILTER > 0) diff --git a/usr/contrib/enet/net/enet.h b/usr/contrib/enet/net/enet.h new file mode 100644 index 0000000000..f76cfd228a --- /dev/null +++ b/usr/contrib/enet/net/enet.h @@ -0,0 +1,173 @@ +/* enet.h Stanford 25 April 1983 */ + +/* + * Ethernet definitions needed for user processes + * + ********************************************************************** + * HISTORY + * 7 October 1985 Jeff Mogul Stanford + * Added EIOCMFREE ioctl to indicate # of free minor devices; + * may or may not be useful. + * 17 October 1984 Jeff Mogul Stanford + * Added ENF_CAND, ENF_COR, ENF_CNAND, and ENF_CNOR, short-circuit + * operators, to make filters run faster. + * All evaluate "(*sp++ == *sp++)": + * ENF_CAND: returns false immediately if result is false, otherwise + * continue + * ENF_COR: returns true immediately if result is true, otherwise + * continue + * ENF_CNAND: returns true immediately if result is false, otherwise + * continue + * ENF_CNOR: returns false immediately if result is true, otherwise + * continue + * Also added ENF_NEQ to complement ENF_EQ + * + * 10 November 1983 Jeffrey Mogul Stanford + * Slight restructuring for support of 10mb ethers; + * added the EIOCDEVP ioctl and associated definitions + * and removed the EIOCMTU ioctl (subsumed by EIOCDEVP) + * + * 25-Apr-83 Jeffrey Mogul Stanford + * Began conversion to 4.2BSD. This involves removing all + * references to the actual hardware. + * Incompatible change: ioctl encodings! + * Added EIOCMTU ioctl to get MTU (max packet size). + * Most previous history comments removed. + * Definitions of interest only to kernel now are in enetdefs.h + * + * 10-Aug-82 Mike Accetta (mja) at Carnegie-Mellon University + * Added EIOCMBIS and EIOCMBIC definitions, and new ENHOLDSIG mode + * bit and ENPRIVMODES defintions (V3.05e). [Last change before + * 4.2BSD conversion starts.] + * + * 22-Feb-80 Rick Rashid (rfr) at Carnegie-Mellon University + * Rewritten for multiple simultaneous opens with filters (V1.05). + * + * 18-Jan-80 Mike Accetta (mja) at Carnegie-Mellon University + * Created (V1.00). + * + ********************************************************************** + */ +#ifdef KERNEL +#include "ioctl.h" +#else +#include +#endif KERNEL + +#define ENMAXFILTERS 40 /* maximum filter short words */ + +/* + * filter structure for SETF + */ +struct enfilter +{ + u_char enf_Priority; /* priority of filter */ + u_char enf_FilterLen; /* length of filter command list */ + u_short enf_Filter[ENMAXFILTERS]; /* the filter command list */ +}; + +/* set/get parameters, set filter ioctl commands */ +#define EIOCSETP _IOW(E,100, struct eniocb) +#define EIOCGETP _IOR(E,101, struct eniocb) +#define EIOCSETF _IOW(E,102, struct enfilter) +#define EIOCENBS _IOW(E,103, int) +#define EIOCINHS _IO(E,104) +#define EIOCSETW _IOW(E,105, u_int) +#define EIOCFLUSH _IO(E,106) +#define EIOCALLOCP _IO(E,107) +#define EIOCDEALLOCP _IO(E,108) +#define EIOCMBIS _IOW(E,109, u_short) +#define EIOCMBIC _IOW(E,110, u_short) +#define EIOCDEVP _IOR(E,111, struct endevp) +#define EIOCMFREE _IOR(E,112, int) + +/* + * Bits in mode word modified by EIOCMBIS and EIOCMBIC. + */ +#define ENHOLDSIG (0x0001) /* don't disable signal after sending */ +#define ENPRIVMODES (~(ENHOLDSIG)) + +/* + * We now allow specification of up to MAXFILTERS (short) words of a filter + * command list to be applied to incoming packets to determine if + * those packets should be given to a particular open ethernet file. + * + * Each open enet file specifies the filter command list via iocontrl. + * Each filter command list specifies a sequences of actions which leave a + * boolean value on the top of an internal stack. Each word of the + * command list specifies an action from the set {PUSHLIT, PUSHZERO, + * PUSHWORD+N} which respectively push the next word of the stack, zero, + * or word N of the incoming packet on the stack, and a binary operator + * from the set {EQ, LT, LE, GT, GE, AND, OR, XOR} which operates on the + * top two elements of the stack and replaces them with its result. The + * special action NOPUSH and the special operator NOP can be used to only + * perform the binary operation or to only push a value on the stack. + * + * If the final value of the filter operation is true, then the packet is + * accepted for the open file which specified the filter. + * + */ + +/* these must sum to 16! */ +#define ENF_NBPA 10 /* # bits / action */ +#define ENF_NBPO 6 /* # bits / operator */ + +/* binary operators */ +#define ENF_NOP (0<F = (head);(elt)->B = (head)->B;(head)->B = (elt);((elt)->B)->F = (elt); }; + +#define remqueue(head,elt) \ + { ((elt)->B)->F = (elt)->F; ((elt)->F)->B = (elt)->B; }; + +#define dequeue(head) \ + (((q_tmp = (head)->F) == (head)) ? NULL : \ + (((q_tmp->B)->F = q_tmp->F), \ + ((q_tmp->F)->B = q_tmp->B), \ + (q_tmp))) + +#define queueempty(head) \ + ((head)->F == (head)) + +#define initqueue(head) \ + { (head)->F = (head); (head)->B = (head); }; +#endif notdef + +/* + * The ethernet packet structure. + * + */ + +struct enPacket +{ + struct Queue enP_Link; /* queue pointers */ + u_short *enP_Data; /* pointer to start of packet */ + short enP_ByteCount; /* # of bytes in Data */ + u_short enP_RefCount; /* # of outstanding references to */ + /* this packet */ + struct mbuf *enP_mbuf; /* first mbuf of packet */ +}; +#define enP_F enP_Link.F +#define enP_B enP_Link.B + +/* + * Ethernet queue header + */ +struct enQueue +{ + struct Queue enQ_Head; /* queue header and trailer pointers */ + short enQ_NumQueued; /* number of elements in queue */ +}; +#define enQ_F enQ_Head.F +#define enQ_B enQ_Head.B + +/* + * Wait queue header + */ +struct enWaitQueue +{ + struct enPacket *enWQ_Packets[ENMAXWAITING];/* pointers to queued packets */ + char enWQ_Head; /* index into Packets (for dequeue) */ + char enWQ_Tail; /* index into Packets (for enqueue) */ + u_char enWQ_NumQueued; /* current queue size */ + u_char enWQ_MaxWaiting; /* threshold for additions */ +}; +#define enNextWaitQueueIndex(idx) \ + if (++(idx) >= ENMAXWAITING) (idx) = 0 +#define enPrevWaitQueueIndex(idx) \ + if (--(idx) < 0) (idx) = (ENMAXWAITING-1) + +/* + * States of receive side of open enet file. + */ +enum enStates {ENRECVIDLE, ENRECVTIMING, ENRECVTIMEDOUT}; + +struct enOpenDescriptor +{ + struct Queue enOD_Link; /* Linked list of OpenDescriptors */ + struct enWaitQueue enOD_Waiting; /* fixed Queue of waiting packets */ + struct proc *enOD_SigProc; /* Process to signal (user mode) */ + short enOD_SigPid; /* Process ID of process to signal */ + short enOD_SigNumb; /* Signal number for input packet */ + /* notification */ + long enOD_Timeout; /* Length of time to wait for packet */ + struct enfilter enOD_OpenFilter; /* Packet filter */ + enum enStates enOD_RecvState; /* see enStates enumeration (above) */ + short enOD_Flag; /* option bits */ + + /* following are for enetselect() */ + short enOD_SelColl; /* true if selects collide */ + struct proc *enOD_SelProc; /* process that last selected us */ + + unsigned long enOD_RecvCount; /* number of packets received */ + + /* store precomputed address of end of filter */ + unsigned short *enOD_FiltEnd; /* addr of short AFTER end of filt */ +}; + +/* + * State descriptor for each enet device + */ +struct enState +{ + long ens_Rcnt; /* input packets queued since */ + /* system startup */ + long ens_Xcnt; /* output packets sent since */ + /* system startup */ + long ens_Rdrops; /* input packets dropped since */ + /* system startup */ + long ens_Xdrops; /* output packets dropped since */ + /* system startup */ + struct enQueue /* queue of active open */ + ens_Desq; /* file descriptors */ + struct endevp ens_DevParams; /* device parameters, see enet.h */ +}; +#define enRcnt (enStatep->ens_Rcnt) +#define enXcnt (enStatep->ens_Xcnt) +#define enRdrops (enStatep->ens_Rdrops) +#define enXdrops (enStatep->ens_Xdrops) +#define enDesq (enStatep->ens_Desq) +#define enCurOpens (enStatep->ens_Desq.enQ_NumQueued) +#define enDevParams (enStatep->ens_DevParams) -- 2.20.1