Annotation of 43BSDTahoe/new/enet/net/enet.c, revision 1.1.1.1

1.1       root        1: /*      enet.c Stanford        25 April 1983 */
                      2: 
                      3: /*
                      4:  *  Ethernet packet filter layer,
                      5:  *     formerly: Ethernet interface driver
                      6:  *
                      7:  **********************************************************************
                      8:  * HISTORY
                      9:  * 7 October 1985      Jeff Mogul      Stanford
                     10:  *     Removed ENMAXOPENS limitation; available minors are now
                     11:  *     dynamically allocated to interfaces, out of pool of NENETFILTER
                     12:  *     minors.
                     13:  *     Certain arrays formerly in the enState structure are now global.
                     14:  *     Depends on modified openi() function so that enetopen() need
                     15:  *     only be called once.
                     16:  *     Remove support for "kernel access", it won't ever be used again.
                     17:  *     Added EIOCMFREE ioctl.
                     18:  *
                     19:  * 17 October 1984     Jeff Mogul      Stanford
                     20:  *    More performance improvements:
                     21:  *     Added ENF_CAND, ENF_COR, ENF_CNAND, and ENF_CNOR, short-circuit
                     22:  *     operators, to make filters run faster.
                     23:  *     All evaluate "(*sp++ == *sp++)":
                     24:  *     ENF_CAND: returns false immediately if result is false, otherwise
                     25:  *             continue
                     26:  *     ENF_COR: returns true immediately if result is true, otherwise
                     27:  *             continue
                     28:  *     ENF_CNAND: returns true immediately if result is false, otherwise
                     29:  *             continue
                     30:  *     ENF_CNOR: returns false immediately if result is true, otherwise
                     31:  *             continue
                     32:  *     Also added ENF_NEQ to complement ENF_EQ
                     33:  *    - Maintain count of received packets per filter, dynamically
                     34:  *     re-organize filter queue to keep highly active filters in
                     35:  *     front of queue (but maintaining priority order), if they are
                     36:  *     "high priority" filters.
                     37:  *
                     38:  * 2 October 1984      Jeff Mogul      Stanford
                     39:  *     Made a few changes to enDoFilter() to speed it up, since profiling
                     40:  *     shows it to be rather popular:
                     41:  *     - precompute maximum word in packet and address of end of
                     42:  *     filters (thereby moving this code out of "inner loop").
                     43:  *     - minor re-arrangement to avoid re-evaluating a
                     44:  *     common subexpression.
                     45:  *     - changed #ifdef DEBUG in a few routines to #ifdef INNERDEBUG,
                     46:  *     so that code in inner loops isn't always testing the enDebug
                     47:  *     flag; this not only costs directly, but also breaks up some
                     48:  *     basic blocks that the optimizer could play with.
                     49:  *     - added enOneCopy flag; if true, then never deliver more than
                     50:  *     one copy of a packet.  This is equivalent to giving everyone
                     51:  *     a "high priority" device, and cuts down the number of superfluous
                     52:  *     calls to enDoFilter(). [Temporary hack, will remove this!]
                     53:  *
                     54:  * 24 August 1984      Jeff Mogul      Stanford
                     55:  *     YA bug with sleeping in enetwrite(); straightened out handling
                     56:  *     of counts in enKludgeSleep so that they indicate the number
                     57:  *     of sleeps in progress. Maybe I've got this right, now?
                     58:  *     Also, don't sleep forever (since the net might be down).
                     59:  *
                     60:  * 17 July 1984        Jeff Mogul      Stanford
                     61:  *     Bug fix: in enetwrite(), several problems with sleeping on
                     62:  *     IF_QFULL:
                     63:  *     - don't do it for kernel mode writes.
                     64:  *     - count # of procs sleeping, to avoid lost wakeups.  Old
                     65:  *             scheme would only wake up the first sleeper.
                     66:  *     - using sleeper-count, avoid using more than one timeout
                     67:  *             table entry per device; old scheme caused timeout table panics
                     68:  *     - trap interupted sleeps using setjmp, so that we can deallocate
                     69:  *             packet header and mbufs; otherwise we lost them and panicked.
                     70:  *
                     71:  * 5 July 1984 Jeff Mogul      Stanford
                     72:  *     Bug fix: in enetwrite() make sure enP_RefCount is zero before
                     73:  *     deallocating "packet".  Otherwise, "packets" get lost, and
                     74:  *     take mbufs (and ultimately, the system) with them.
                     75:  *
                     76:  * 8 December 1983     Jeffrey Mogul   Stanford
                     77:  *     Fixed bug in enetwrite() that eventually caused allocator
                     78:  *     to run out of packets and panic.  If enetwrite() returns
                     79:  *     an error it should first deallocate any packets it has allocated.
                     80:  *
                     81:  * 10 November 1983    Jeffrey Mogul   Stanford
                     82:  *     Slight restructuring for support of 10mb ethers;
                     83:  *     - added the EIOCDEVP ioctl
                     84:  *     - removed the EIOCMTU ioctl (subsumed by EIOCDEVP)
                     85:  *     This requires an additional parameter to the enetattach
                     86:  *     call so that the device driver can specify things.
                     87:  *
                     88:  *     Also, cleaned up the enDebug scheme by adding symbolic
                     89:  *     definitions for the bits.
                     90:  *
                     91:  * 25-Apr-83   Jeffrey Mogul   Stanford
                     92:  *     Began conversion to 4.2BSD.  This involves removing all
                     93:  *             references to the actual hardware.
                     94:  *     Changed read/write interface to use uio scheme.
                     95:  *     Changed ioctl interface to "new style"; this places a hard
                     96:  *             limit on the size of a filter (about 128 bytes).
                     97:  *     "Packets" now point to mbufs, not private buffers.
                     98:  *     Filter can only access data in first mbuf (about 50 words worst case);
                     99:  *             this is long enough for all Pup purposes.
                    100:  *     Added EIOCMTU ioctl to get MTU (max packet size).
                    101:  *     Added an enetselect() routine and other select() support.
                    102:  *     Other stuff is (more or less) left intact.
                    103:  *     Most previous history comments removed.
                    104:  *     Changed some names from enXXXX to enetXXXX to avoid confusion(?)
                    105:  *
                    106:  * 10-Aug-82  Mike Accetta (mja) at Carnegie-Mellon University
                    107:  *     Added new EIOCMBIS and EIOCMBIC ioctl calls to set and clear
                    108:  *     bits in mode word;  added mode bit ENHOLDSIG which suppresses
                    109:  *     the resetting of an enabled signal after it is sent (to be
                    110:  *     used inconjunction with the SIGHOLD mechanism);  changed
                    111:  *     EIOCGETP to zero pad word for future compatibility;  changed enwrite()
                    112:  *     to enforce correct source host address on output packets (V3.05e).
                    113:  *     (Stanford already uses long timeout value and has no pad word - JCM)
                    114:  *     [Last change before 4.2BSD conversion starts.]
                    115:  *
                    116:  * 01-Dec-81  Mike Accetta (mja) at Carnegie-Mellon University
                    117:  *     Fixed bug in timeout handling caused by missing "break" in the
                    118:  *     "switch" state check within enetread().  This caused all reads
                    119:  *     to be preceeded by a bogus timeout.  In addition, fixed another
                    120:  *     bug in signal processing by also recording process ID of
                    121:  *     process to signal when an input packet is available.  This is
                    122:  *     necessary because it is possible for a process with an enabled
                    123:  *     signal to fork and exit with no guarantee that the child will
                    124:  *     reenable the signal.  Thus under appropriately bizarre race
                    125:  *     conditions, an incoming packet to the child can cause a signal
                    126:  *     to be sent to the unsuspecting process which inherited the
                    127:  *     process slot of the parent.  Of course, if the PID's wrap around
                    128:  *     AND the inheriting process has the same PID, well ... (V3.03d).
                    129:  *
                    130:  * 22-Feb-80  Rick Rashid (rfr) at Carnegie-Mellon University
                    131:  *     Rewritten to provide multiple user access via user settable
                    132:  *     filters (V1.05).
                    133:  *
                    134:  * 18-Jan-80  Mike Accetta (mja) at Carnegie-Mellon University
                    135:  *      Created (V1.00).
                    136:  *
                    137:  **********************************************************************
                    138:  */
                    139: 
                    140: #include "en.h"
                    141: #include "ec.h"
                    142: #include "il.h"
                    143: #include "de.h"
                    144: #include "enetfilter.h"
                    145: 
                    146: /* number of potential units */
                    147: #define        NENET   (NEC + NEN + NIL + NDE)
                    148: 
                    149: #if (NENETFILTER > 0)
                    150: 
                    151: #define        SUN_OPENI
                    152: 
                    153: #include "param.h"
                    154: #include "systm.h"
                    155: #include "mbuf.h"
                    156: #include "buf.h"
                    157: #include "dir.h"
                    158: #include "user.h"
                    159: #include "ioctl.h"
                    160: #include "map.h"
                    161: #include "proc.h"
                    162: #include "inode.h"
                    163: #include "file.h"
                    164: #include "tty.h"
                    165: #include "uio.h"
                    166: 
                    167: #include "protosw.h"
                    168: #include "socket.h"
                    169: #include "../net/if.h"
                    170: 
                    171: #undef queue
                    172: #undef dequeue
                    173: #include "../net/enet.h"
                    174: #include "../net/enetdefs.h"
                    175: 
                    176: #if    (NENETFILTER < 32)
                    177: #undef NENETFILTER
                    178: #define        NENETFILTER     32
                    179: #endif
                    180: 
                    181: #if    (NENETFILTER > 256)
                    182: #undef NENETFILTER
                    183: #define        NENETFILTER     256             /* maximum number of minor devices */
                    184: #endif
                    185: 
                    186: #define DEBUG  1
                    187: /* #define INNERDEBUG 1 */     /* define only when debugging enDoFilter()
                    188:                                        or enInputDone()  */
                    189: 
                    190: #define        enprintf(flags) if (enDebug&(flags)) printf
                    191: 
                    192: /*
                    193:  * Symbolic definitions for enDebug flag bits
                    194:  *     ENDBG_TRACE should be 1 because it is the most common
                    195:  *     use in the code, and the compiler generates faster code
                    196:  *     for testing the low bit in a word.
                    197:  */
                    198: 
                    199: #define        ENDBG_TRACE     1       /* trace most operations */
                    200: #define        ENDBG_DESQ      2       /* trace descriptor queues */
                    201: #define        ENDBG_INIT      4       /* initialization info */
                    202: #define        ENDBG_SCAV      8       /* scavenger operation */
                    203: #define        ENDBG_ABNORM    16      /* abnormal events */
                    204: 
                    205: 
                    206: #define min(a,b)        ( ((a)<=(b)) ? (a) : (b) )
                    207: 
                    208: #define        splenet splimp  /* used to be spl6 but I'm paranoid */
                    209: 
                    210: #define PRINET  26                     /* interruptible */
                    211: 
                    212: /*
                    213:  *  'enQueueElts' is the pool of packet headers used by the driver.
                    214:  *  'enPackets'   is the pool of packets used by the driver (these should
                    215:  *               be allocated dynamically when this becomes possible).
                    216:  *  'enFreeq'     is the queue of available packets
                    217:  *  'enState'     is the driver state table per logical unit number
                    218:  *  'enUnit'     is the physical unit number table per logical unit number;
                    219:  *               the first "attach"ed ethernet is logical unit 0, etc.
                    220:  *  'enUnitMap'          maps minor device numbers onto interface unit #s
                    221:  *  'enAllocMap'  indicates if minor device is allocated or free
                    222:  *  'enAllDescriptors' stores OpenDescriptors, indexed by minor device #
                    223:  *  'enFreeqMin'  is the minimum number of packets ever in the free queue
                    224:  *               (for statistics purposes)
                    225:  *  'enScavenges' is the number of scavenges of the active input queues
                    226:  *               (for statustics purposes)
                    227:  *  'enDebug'    is a collection of debugging bits which enable trace and/or
                    228:  *               diagnostic output as defined above (ENDBG_*)
                    229:  *  'enUnits'    is the number of attached units
                    230:  *  'enOneCopy'   if true, then no packet is delivered to more than one minor
                    231:  *               device
                    232:  */
                    233: struct enPacket        enQueueElts[ENPACKETS];
                    234: struct enQueue enFreeq;
                    235: struct enState  enState[NENET];
                    236: char           enUnitMap[NENETFILTER];
                    237: char           enAllocMap[NENETFILTER];
                    238: struct enOpenDescriptor
                    239:                enAllDescriptors[NENETFILTER];
                    240: int            enFreeqMin = ENPACKETS;
                    241: int            enScavenges = 0;
                    242: int            enDebug = ENDBG_ABNORM;
                    243: int            enUnits = 0;
                    244: int            enOneCopy = 0;
                    245: int            enMaxMinors = NENETFILTER;
                    246: 
                    247: /*
                    248:  *  Forward declarations for subroutines which return other
                    249:  *  than integer types.
                    250:  */
                    251: extern boolean enDoFilter();
                    252: 
                    253: 
                    254: /*
                    255:  * Linkages to if_en.c
                    256:  */
                    257: 
                    258: struct enet_info {
                    259:        struct  ifnet *ifp;     /* which ifp for output */
                    260: } enet_info[NENET];
                    261: 
                    262: struct sockaddr enetaf = { AF_IMPLINK };
                    263: 
                    264: 
                    265: /****************************************************************
                    266:  *                                                             *
                    267:  *             Various Macros & Routines                       *
                    268:  *                                                             *
                    269:  ****************************************************************/
                    270: 
                    271: /*
                    272:  *  forAllOpenDescriptors(p) -- a macro for iterating
                    273:  *  over all currently open devices.  Use it in place of
                    274:  *      "for ( ...; ... ; ... )"
                    275:  *  and supply your own loop body.  The loop variable is the
                    276:  *  parameter p which is set to point to the descriptor for
                    277:  *  each open device in turn.
                    278:  */
                    279: 
                    280: #define forAllOpenDescriptors(p)                                       \
                    281:        for ((p) = (struct enOpenDescriptor *)enDesq.enQ_F;             \
                    282:              (struct Queue *)(&enDesq) != &((p)->enOD_Link);           \
                    283:              (p) = (struct enOpenDescriptor *)(p)->enOD_Link.F)
                    284: 
                    285: /*
                    286:  *  enEnqueue - add an element to a queue
                    287:  */
                    288: 
                    289: #define        enEnqueue(q, elt)                                               \
                    290: {                                                                      \
                    291:        enqueue((struct Queue *)(q), (struct Queue *)(elt));            \
                    292:        (q)->enQ_NumQueued++;                                           \
                    293: }
                    294: 
                    295: /*
                    296:  *  enFlushQueue - release all packets from queue, freeing any
                    297:  *  whose reference counts drop to 0.  Assumes caller
                    298:  *  is at high IPL so that queue will not be modified while
                    299:  *  it is being flushed.
                    300:  */
                    301: 
                    302: enFlushQueue(q)
                    303: register struct enQueue *q;
                    304: {
                    305: 
                    306:     register struct enPacket *qelt;
                    307: 
                    308:     while((qelt=(struct enPacket *)dequeue((struct Queue *)q)) != NULL)
                    309:     {
                    310:        if (0 == --(qelt->enP_RefCount))
                    311:        {
                    312:            enEnqueue(&enFreeq, qelt);
                    313:        }
                    314:     }
                    315:     q->enQ_NumQueued = 0;
                    316: 
                    317: }
                    318: 
                    319: /*
                    320:  *  enInitWaitQueue - initialize an empty packet wait queue
                    321:  */
                    322: 
                    323: enInitWaitQueue(wq)
                    324: register struct enWaitQueue *wq;
                    325: {                      
                    326: 
                    327:     wq->enWQ_Head = 0;
                    328:     wq->enWQ_Tail = 0;
                    329:     wq->enWQ_NumQueued = 0;
                    330:     wq->enWQ_MaxWaiting = ENDEFWAITING;
                    331: 
                    332: }
                    333: 
                    334: /*
                    335:  *  enEnWaitQueue - add a packet to a wait queue
                    336:  */
                    337: 
                    338: enEnWaitQueue(wq, p)
                    339: register struct enWaitQueue *wq;
                    340: struct enPacket *p;
                    341: {
                    342: 
                    343:     wq->enWQ_Packets[wq->enWQ_Tail] = p;
                    344:     wq->enWQ_NumQueued++;
                    345:     enNextWaitQueueIndex(wq->enWQ_Tail);
                    346: 
                    347: }
                    348: 
                    349: /*
                    350:  *  enDeWaitQueue - remove a packet from a wait queue
                    351:  */
                    352: 
                    353: struct enPacket *
                    354: enDeWaitQueue(wq)
                    355: register struct enWaitQueue *wq;
                    356: {
                    357: 
                    358:     struct enPacket *p;
                    359: 
                    360:     wq->enWQ_NumQueued--;
                    361:     if (wq->enWQ_NumQueued < 0)
                    362:        panic("enDeWaitQueue"); 
                    363:     p = wq->enWQ_Packets[wq->enWQ_Head];
                    364:     enNextWaitQueueIndex(wq->enWQ_Head);
                    365: 
                    366:     return(p);
                    367: 
                    368: }
                    369: 
                    370: /*
                    371:  *  enTrimWaitQueue - cut a wait queue back to size
                    372:  */
                    373: enTrimWaitQueue(wq, threshold)
                    374: register struct enWaitQueue *wq;
                    375: {
                    376: 
                    377:     register int Counter = (wq->enWQ_NumQueued - threshold);
                    378:     register struct enPacket *p;
                    379: 
                    380: #ifdef DEBUG
                    381:     enprintf(ENDBG_SCAV)
                    382:                ("enTrimWaitQueue(%x, %d): %d\n", wq, threshold, Counter);
                    383: #endif
                    384:     while (Counter-- > 0)
                    385:     {
                    386:        wq->enWQ_NumQueued--;
                    387:        enPrevWaitQueueIndex(wq->enWQ_Tail);
                    388:        p = wq->enWQ_Packets[wq->enWQ_Tail];
                    389:        if (0 == --(p->enP_RefCount))
                    390:        {
                    391:            m_freem(p->enP_mbuf);
                    392:            enEnqueue(&enFreeq, p);
                    393:        }
                    394:     }
                    395: }
                    396: /*
                    397:  *  enFlushWaitQueue - remove all packets from wait queue
                    398:  */
                    399: 
                    400: #define        enFlushWaitQueue(wq)    enTrimWaitQueue(wq, 0)
                    401: 
                    402: /*
                    403:  *  scavenging thresholds:
                    404:  *
                    405:  *  index by number of active files;  for N open files, each queue may retain
                    406:  *  up to 1/Nth of the packets not guaranteed to be freed on scavenge.  The
                    407:  *  total number of available packets is computed less one for sending.
                    408:  *
                    409:  *  (assumes high IPL)
                    410:  */
                    411: char enScavLevel[NENETFILTER+1];
                    412: 
                    413: /*
                    414:  *  enInitScavenge -- set up ScavLevel table
                    415:  */
                    416: enInitScavenge()
                    417: {
                    418:     register int PoolSize = (ENPACKETS-ENMINSCAVENGE);
                    419:     register int i = sizeof(enScavLevel);
                    420: 
                    421:     PoolSize--;                /* leave one for transmitter */
                    422:     while (--i>0)
                    423:         enScavLevel[i] = (PoolSize / i);
                    424: }
                    425: 
                    426: /*
                    427:  *  enScavenge -- scan all OpenDescriptors for all ethernets, releasing
                    428:  *    any queued buffers beyond the prescribed limit and freeing any whose
                    429:  *    refcounts drop to 0.
                    430:  *    Assumes caller is at high IPL so that it is safe to modify the queues.
                    431:  */
                    432: enScavenge()
                    433: {
                    434: 
                    435:     register struct enOpenDescriptor *d;
                    436:     register int threshold = 0;
                    437:     register struct enState *enStatep;
                    438: 
                    439:     for (enStatep=enState; enStatep < &enState[NENET]; enStatep++)
                    440:        threshold += enCurOpens;
                    441:     threshold = enScavLevel[threshold];
                    442: 
                    443:     /* recalculate thresholds based on current allocations */
                    444:     enInitScavenge();
                    445: 
                    446:     enScavenges++;
                    447: #ifdef DEBUG
                    448:     enprintf(ENDBG_SCAV)("enScavenge: %d\n", threshold);
                    449: #endif
                    450:     for (enStatep=enState; enStatep < &enState[NENET]; enStatep++)
                    451:     {
                    452:        if (enDesq.enQ_F == 0)
                    453:            continue;                   /* never initialized */
                    454:        forAllOpenDescriptors(d)
                    455:        {
                    456:            enTrimWaitQueue(&(d->enOD_Waiting), threshold);
                    457:        }
                    458:     }
                    459: 
                    460: }
                    461: 
                    462: /*
                    463:  *  enAllocatePacket - allocate the next packet from the free list
                    464:  *
                    465:  *  Assumes IPL is at high priority so that it is safe to touch the
                    466:  *  packet queue.  If the queue is currently empty, scavenge for
                    467:  *  more packets.
                    468:  */
                    469: 
                    470: struct enPacket *
                    471: enAllocatePacket()
                    472: {
                    473: 
                    474:     register struct enPacket *p;
                    475: 
                    476:     if (0 == enFreeq.enQ_NumQueued)
                    477:        enScavenge();
                    478:     p = (struct enPacket *)dequeue((struct Queue *)&enFreeq);
                    479:     if (p == NULL)
                    480:        panic("enAllocatePacket");
                    481:     if (enFreeqMin > --enFreeq.enQ_NumQueued)
                    482:        enFreeqMin = enFreeq.enQ_NumQueued;
                    483: 
                    484:     p->enP_RefCount = 0;       /* just in case */
                    485: 
                    486:     return(p);
                    487: 
                    488: }
                    489: 
                    490: /*
                    491:  *  enDeallocatePacket - place the packet back on the free packet queue
                    492:  *
                    493:  *  (High IPL assumed).
                    494:  */
                    495: 
                    496: #define        enDeallocatePacket(p)                                           \
                    497: {                                                                      \
                    498:        if (p->enP_RefCount) panic("enDeallocatePacket: refcount != 0");\
                    499:        enqueue((struct Queue *)&enFreeq, (struct Queue *)(p));         \
                    500:        enFreeq.enQ_NumQueued++;                                        \
                    501: }
                    502: 
                    503: /****************************************************************
                    504:  *                                                             *
                    505:  *         Routines to move uio data to/from mbufs             *
                    506:  *                                                             *
                    507:  ****************************************************************/
                    508: 
                    509: /*
                    510:  * These two routines were inspired by/stolen from ../sys/uipc_socket.c
                    511:  *        Both return error code (or 0 if success).
                    512:  */
                    513: 
                    514: /*
                    515:  * read: return contents of mbufs to user.  DO NOT free them, since
                    516:  *     there may be multiple claims on the packet!
                    517:  */
                    518: enrmove(m, uio, count)
                    519: register struct mbuf *m;
                    520: register struct uio *uio;
                    521: register int count;
                    522: {
                    523:        register int len;
                    524:        register int error = 0;
                    525:        
                    526:        count = min(count, uio->uio_resid);     /* # of bytes to return */
                    527:        
                    528:        while ((count > 0) && m && (error == 0)) {
                    529:            len = min(count, m->m_len); /* length of this transfer */
                    530:            count -= len;
                    531:            error = uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
                    532:            
                    533:            m = m->m_next;
                    534:        }
                    535:        return(error);
                    536: }
                    537: 
                    538: enwmove(uio, mbufp)
                    539: register struct uio *uio;
                    540: register struct mbuf **mbufp;  /* top mbuf is returned by reference */
                    541: {
                    542:        struct mbuf *mtop = 0;
                    543:        register struct mbuf *m;
                    544:        register struct mbuf **mp = &mtop;
                    545:        register struct iovec *iov;
                    546:        register int len;
                    547:        int error = 0;
                    548:        
                    549:        while ((uio->uio_resid > 0) && (error == 0)) {
                    550:            iov = uio->uio_iov;
                    551:            
                    552:            if (iov->iov_len == 0) {
                    553:                uio->uio_iov++;
                    554:                uio->uio_iovcnt--;
                    555:                if (uio->uio_iovcnt < 0)
                    556:                    panic("enwmove: uio_iovcnt < 0 while uio_resid > 0");
                    557:            }
                    558:            MGET(m, M_WAIT, MT_DATA);
                    559:            if (m == NULL) {
                    560:                error = ENOBUFS;
                    561:                break;
                    562:            }
                    563:            if (iov->iov_len >= CLBYTES) {      /* big enough to use a page */
                    564:                register struct mbuf *p;
                    565:                MCLGET(p, 1);
                    566:                if (p == 0)
                    567:                    goto nopages;
                    568:                m->m_off = (int)p - (int)m;
                    569:                len = CLBYTES;
                    570:            }
                    571:            else {
                    572: nopages:
                    573:                len = MIN(MLEN, iov->iov_len);
                    574:            }
                    575:            error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
                    576:            m->m_len = len;
                    577:            *mp = m;
                    578:            mp = &(m->m_next);
                    579:        }
                    580: 
                    581:        if (error) {            /* probably uiomove fouled up */
                    582:            if (mtop)
                    583:                m_freem(mtop);
                    584:        }
                    585:        else {
                    586:            *mbufp = mtop;      /* return ptr to top mbuf */
                    587:        }
                    588:        return(error);
                    589: }
                    590: 
                    591: /*
                    592:  *  enetopen - open ether net device
                    593:  *
                    594:  *  Errors:    ENXIO   - illegal minor device number
                    595:  *             EBUSY   - minor device already in use
                    596:  */
                    597: 
                    598: /* ARGSUSED */
                    599: enetopen(dev, flag, newmin)
                    600: dev_t dev;
                    601: int flag;
                    602: int *newmin;
                    603: {
                    604:     register int md;
                    605:     register int unit = minor(dev);
                    606:     register struct enState *enStatep;
                    607: #ifndef        SUN_OPENI
                    608:     register int error;
                    609: #endif SUN_OPENI
                    610: 
                    611:     /*
                    612:      * Each open enet file has a different minor device number.
                    613:      * When a user tries to open any of them, we actually open
                    614:      * any available minor device and associate it with the
                    615:      * corresponding unit.
                    616:      *
                    617:      * This is not elegant, but UNIX will call
                    618:      * open for each new open file using the same inode but calls
                    619:      * close only when the last open file referring to the inode 
                    620:      * is released. This means that we cannot know inside the
                    621:      * driver code when the resources associated with a particular
                    622:      * open of the same inode should be deallocated.  Thus, we have
                    623:      * to make up a temporary inode to represent each simultaneous
                    624:      * open of the ethernet.  Each inode has a different minor device number.
                    625:      */
                    626: 
                    627: #ifdef DEBUG
                    628:     enprintf(ENDBG_TRACE)("enetopen(%o, %x):\n", unit, flag);
                    629: #endif
                    630: 
                    631:     /* check for illegal minor dev */
                    632:     if ( (unit >= enUnits)                             /* bad unit */
                    633:         || (enet_info[unit].ifp == 0)                  /* ifp not known */
                    634:        || ((enet_info[unit].ifp->if_flags & IFF_UP) == 0) )
                    635:                                                        /* or if down */
                    636:     {
                    637:        return(ENXIO);
                    638:     }
                    639: 
                    640:     md = enFindMinor();
                    641: #ifdef DEBUG
                    642:     enprintf(ENDBG_TRACE)("enetopen: md = %d\n", md);
                    643: #endif
                    644:     if (md < 0)
                    645:     {
                    646:        return(EBUSY);
                    647:     }
                    648: 
                    649:     enUnitMap[md] = unit;
                    650:     enAllocMap[md] = TRUE;
                    651: 
                    652: #ifdef SUN_OPENI
                    653:     *newmin = md;
                    654: #else
                    655:     error = mkpseudo(makedev(major(dev), md)));
                    656:     if (error) {
                    657:        enAllocMap[md] = FALSE;
                    658:        return(error);
                    659:     }
                    660: #endif SUN_OPENI
                    661: 
                    662:     enStatep = &enState[unit];
                    663:     enprintf(ENDBG_DESQ)
                    664:        ("enetopen: Desq: %x, %x\n", enDesq.enQ_F, enDesq.enQ_B);
                    665:     enInitDescriptor(&enAllDescriptors[md], flag);
                    666:     enInsertDescriptor(&(enDesq), &enAllDescriptors[md]);
                    667: 
                    668:     return(0);
                    669: }
                    670: 
                    671: /*
                    672:  * enFindMinor - find a free logical device on specified unit
                    673:  */
                    674: enFindMinor()
                    675: {
                    676:        register int md;
                    677:        
                    678:        for (md = 0; md < enMaxMinors; md++) {
                    679:                if (enAllocMap[md] == FALSE)
                    680:                        return(md);
                    681:        }
                    682:        return(-1);
                    683: }
                    684: 
                    685: /*
                    686:  *  enInit - intialize ethernet unit (called by enetattach)
                    687:  */
                    688: 
                    689: enInit(enStatep, unit)
                    690: register struct enState *enStatep;
                    691: register int unit;
                    692: {
                    693: 
                    694: #ifdef DEBUG
                    695:     enprintf(ENDBG_INIT)("enInit(%x %d):\n", enStatep, unit);
                    696: #endif
                    697: 
                    698:     /*  initialize free queue if not already done  */
                    699:     if (enFreeq.enQ_F == 0)
                    700:     {
                    701:        register int i;
                    702: 
                    703:        initqueue((struct Queue *)&enFreeq);
                    704:        for (i=0; i<ENPACKETS; i++)
                    705:        {
                    706:            register struct enPacket *p;
                    707: 
                    708:            p = &enQueueElts[i];
                    709:            p->enP_RefCount = 0;
                    710:            enDeallocatePacket(p);
                    711:        }
                    712:        /* also a good time to init enAllocMap */
                    713:        for (i = 0; i < enMaxMinors; i++)
                    714:                enAllocMap[i] = FALSE;
                    715:     }
                    716:     initqueue((struct Queue *)&enDesq);        /* init descriptor queue */
                    717: }        
                    718: 
                    719: /*
                    720:  *  enetclose - ether net device close routine
                    721:  */
                    722: 
                    723: /* ARGSUSED */
                    724: enetclose(dev, flag)
                    725: {
                    726:     register int md = ENINDEX(dev);
                    727:     register struct enState *enStatep = &enState[ENUNIT(dev)];
                    728:     register struct enOpenDescriptor *d = &enAllDescriptors[md];
                    729:     int ipl;
                    730: 
                    731:     enAllocMap[md] = FALSE;
                    732: 
                    733: #ifdef DEBUG
                    734:     enprintf(ENDBG_TRACE)("enetclose(%d, %x):\n", md, flag);
                    735: #endif
                    736: 
                    737:     /*
                    738:      *  insure that receiver doesn't try to queue something
                    739:      *  for the device as we are decommissioning it.
                    740:      *  (I don't think this is necessary, but I'm a coward.)
                    741:      */
                    742:     ipl = splenet();
                    743:     dequeue((struct Queue *)d->enOD_Link.B);
                    744:     enCurOpens--;
                    745:     enprintf(ENDBG_DESQ)
                    746:                ("enetclose: Desq: %x, %x\n", enDesq.enQ_F, enDesq.enQ_B);
                    747:     enFlushWaitQueue(&(d->enOD_Waiting));
                    748:     splx(ipl);
                    749: 
                    750: }
                    751: 
                    752: /*
                    753:  *  enetread - read next packet from net
                    754:  */
                    755: 
                    756: /* VARARGS */
                    757: enetread(dev, uio)
                    758: dev_t dev;
                    759: register struct uio *uio;
                    760: {
                    761:     register struct enOpenDescriptor *d = &enAllDescriptors[ENINDEX(dev)];
                    762:     register struct enPacket *p;
                    763:     int ipl;
                    764:     int error;
                    765:     extern enTimeout();
                    766: 
                    767: #if    DEBUG
                    768:     enprintf(ENDBG_TRACE)("enetread(%x):", dev);
                    769: #endif
                    770: 
                    771:     ipl = splenet();
                    772:     /*
                    773:      *  If nothing is on the queue of packets waiting for
                    774:      *  this open enet file, then set timer and sleep until
                    775:      *  either the timeout has occurred or a packet has
                    776:      *  arrived.
                    777:      */
                    778: 
                    779:     while (0 == d->enOD_Waiting.enWQ_NumQueued)
                    780:     {
                    781:        if (d->enOD_Timeout < 0)
                    782:        {
                    783:            splx(ipl);
                    784:            return(0);
                    785:        }
                    786:         if (d->enOD_Timeout)
                    787:        {
                    788:            /*
                    789:             *  If there was a previous timeout pending for this file,
                    790:             *  cancel it before setting another.  This is necessary since
                    791:             *  a cancel after the sleep might never happen if the read is
                    792:             *  interrupted by a signal.
                    793:             */
                    794:            if (d->enOD_RecvState == ENRECVTIMING)
                    795:                untimeout(enTimeout, (caddr_t)d);
                    796:             timeout(enTimeout, (caddr_t)d, (int)(d->enOD_Timeout));
                    797:             d->enOD_RecvState = ENRECVTIMING;
                    798:        }
                    799:         else
                    800:             d->enOD_RecvState = ENRECVIDLE;
                    801: 
                    802:         sleep((caddr_t)d, PRINET);
                    803: 
                    804:         switch (d->enOD_RecvState)
                    805:        {
                    806:             case ENRECVTIMING:
                    807:            {
                    808:                 untimeout(enTimeout, (caddr_t)d);
                    809:                 d->enOD_RecvState = ENRECVIDLE;
                    810:                break;
                    811:            }
                    812:             case ENRECVTIMEDOUT:
                    813:            {
                    814:                 splx(ipl);
                    815:                return(0);
                    816:            }
                    817:        }
                    818:     }
                    819: 
                    820:     p = enDeWaitQueue(&(d->enOD_Waiting));
                    821:     splx(ipl);
                    822: 
                    823:     /*  
                    824:      * Move data from packet into user space.
                    825:      */
                    826:     error = enrmove(p->enP_mbuf, uio, p->enP_ByteCount);
                    827: 
                    828:     ipl = splenet();
                    829:     if (0 == --(p->enP_RefCount))      /* if no more claims on this packet */
                    830:     {
                    831:        m_freem(p->enP_mbuf);   /* release mbuf */
                    832:        enDeallocatePacket(p);  /* and packet */
                    833:     }
                    834:     splx(ipl);
                    835: 
                    836:     return(error);
                    837: }
                    838: 
                    839: 
                    840: 
                    841: /*
                    842:  *  enTimeout - process ethernet read timeout
                    843:  */
                    844: 
                    845: enTimeout(d)
                    846: register struct enOpenDescriptor * d;
                    847: {
                    848:     register int ipl;
                    849: 
                    850: #ifdef DEBUG
                    851:     enprintf(ENDBG_TRACE)("enTimeout(%x):\n", d);
                    852: #endif
                    853:     ipl = splenet();
                    854:     d->enOD_RecvState = ENRECVTIMEDOUT;
                    855:     wakeup((caddr_t)d);
                    856:     enetwakeup(d);
                    857:     splx(ipl);
                    858: 
                    859: }
                    860: 
                    861: /*
                    862:  *  enetwrite - write next packet to net
                    863:  */
                    864: 
                    865: int enKludgeSleep[NENET];      /* Are we sleeping on IF_QFULL? */
                    866:                                /*  really, # of procs sleeping on IF_QFULL */
                    867: 
                    868: /* VARARGS */
                    869: enetwrite(dev, uio)
                    870: dev_t dev;
                    871: register struct uio *uio;
                    872: {
                    873:     register int unit = ENUNIT(dev);
                    874:     register struct enState *enStatep = &enState[unit];
                    875:     struct mbuf *mp;
                    876:     register struct ifnet *ifp = enet_info[unit].ifp;
                    877:     int ipl;
                    878:     int error;
                    879:     int sleepcount;
                    880:     int enKludgeTime();
                    881: 
                    882: #if    DEBUG
                    883:     enprintf(ENDBG_TRACE)("enetwrite(%x):\n", dev);
                    884: #endif
                    885: 
                    886:      if (uio->uio_resid == 0)
                    887:         return(0);
                    888:      if (uio->uio_resid > ifp->if_mtu) /* too large */
                    889:         return(EMSGSIZE);
                    890:  
                    891:     /*
                    892:      * Copy user data into mbufs
                    893:      */
                    894:      if (error = enwmove(uio, &mp)) {
                    895:         return(error);
                    896:      }
                    897: 
                    898:     ipl = splenet();
                    899:     /*
                    900:      * if the queue is full,
                    901:      * hang around until there's room or until process is interrupted
                    902:      */
                    903:     sleepcount = 0;
                    904:     while (IF_QFULL(&(ifp->if_snd))) {
                    905:        extern int hz;
                    906:        if (sleepcount++ > 2) { /* don't sleep too long */
                    907:            splx(ipl);
                    908:            return(ETIMEDOUT);
                    909:        }
                    910:        /* if nobody else has a timeout pending for this unit, set one */
                    911:        if (enKludgeSleep[unit] == 0)
                    912:            timeout(enKludgeTime, (caddr_t)unit, 2 * hz);
                    913:        enKludgeSleep[unit]++;  /* record that we are sleeping */
                    914:        if (setjmp(&u.u_qsave)) {
                    915:            /* sleep (following) was interrupted, clean up */
                    916: #if    DEBUG
                    917:            enprintf(ENDBG_ABNORM)
                    918:                ("enetwrite(%x): enet%d sleep %d interrupted\n", dev,
                    919:                        unit, enKludgeSleep[unit]);
                    920: #endif DEBUG
                    921:            enKludgeSleep[unit]--;      /* we're no longer sleeping */
                    922:            m_freem(mp);
                    923:            splx(ipl);
                    924:            return(EINTR);
                    925:        }
                    926:        sleep((caddr_t)&(enKludgeSleep[unit]), PRINET);
                    927:        enKludgeSleep[unit]--;  /* we are no longer sleeping */
                    928:     }
                    929:     
                    930:     /* place mbuf chain on outgoing queue & start if necessary */
                    931:     error = (*ifp->if_output)(ifp, mp, &enetaf);
                    932:                        /* this always frees the mbuf chain */
                    933:     enXcnt++;
                    934:     
                    935:     splx(ipl);
                    936:     
                    937:     return(error);
                    938: }
                    939: 
                    940: enKludgeTime(unit)
                    941: int unit;
                    942: {
                    943:        /* XXX perhaps we should always wakeup? */
                    944:        if (enKludgeSleep[unit]) {
                    945:                wakeup((caddr_t)&(enKludgeSleep[unit]));
                    946:                /* XXX should we restart transmitter? */
                    947:        }
                    948: }
                    949: 
                    950: /*
                    951:  *  enetioctl - ether net control
                    952:  *
                    953:  *  EIOCGETP    - get ethernet parameters
                    954:  *  EIOCSETP    - set ethernet read timeout
                    955:  *  EIOCSETF    - set ethernet read filter
                    956:  *  EIOCENBS    - enable signal when read packet available
                    957:  *  EIOCINHS     - inhibit signal when read packet available
                    958:  *  FIONREAD    - check for read packet available
                    959:  *  EIOCSETW    - set maximum read packet waiting queue length
                    960:  *  EIOCFLUSH   - flush read packet waiting queue
                    961:  *  EIOCMBIS    - set mode bits
                    962:  *  EIOCMBIC    - clear mode bits
                    963:  *  EICODEVP    - get device parameters
                    964:  *  EIOCMFREE   - number of free minors
                    965:  */
                    966: 
                    967: /* ARGSUSED */
                    968: enetioctl(dev, cmd, addr, flag)
                    969: caddr_t addr;
                    970: dev_t flag;
                    971: {
                    972: 
                    973:     register struct enState *enStatep = &enState[ENUNIT(dev)];
                    974:     register struct enOpenDescriptor * d = &enAllDescriptors[ENINDEX(dev)];
                    975:     int ipl;
                    976: 
                    977: #if    DEBUG
                    978:     enprintf(ENDBG_TRACE)
                    979:                ("enetioctl(%x, %x, %x, %x):\n", dev, cmd, addr, flag);
                    980: #endif
                    981: 
                    982:     switch (cmd)
                    983:     {
                    984:        case EIOCGETP:
                    985:        {
                    986:             struct eniocb t;
                    987: 
                    988:            t.en_maxwaiting = ENMAXWAITING;
                    989:            t.en_maxpriority = ENMAXPRI;
                    990:             t.en_rtout = d->enOD_Timeout;
                    991:            t.en_addr = -1;
                    992:            t.en_maxfilters = ENMAXFILTERS;
                    993: 
                    994:            bcopy((caddr_t)&t, addr, sizeof t);
                    995:        }
                    996:         endcase
                    997: 
                    998:         case EIOCSETP:
                    999:        {
                   1000:             struct eniocb t;
                   1001: 
                   1002:             bcopy(addr, (caddr_t)&t, sizeof t);
                   1003:             d->enOD_Timeout = t.en_rtout;
                   1004:        }
                   1005:         endcase
                   1006: 
                   1007:         case EIOCSETF:
                   1008:        {
                   1009:             struct enfilter f;
                   1010:            unsigned short *fp;
                   1011: 
                   1012:             bcopy(addr, (caddr_t)&f, sizeof f);
                   1013:            if (f.enf_FilterLen > ENMAXFILTERS)
                   1014:            {
                   1015:                return(EINVAL);
                   1016:            }
                   1017:             /* insure that filter is installed indivisibly */
                   1018:             ipl = splenet();
                   1019:             bcopy((caddr_t)&f, (caddr_t)&(d->enOD_OpenFilter), sizeof f);
                   1020:            /* pre-compute length of filter */
                   1021:            fp = &(d->enOD_OpenFilter.enf_Filter[0]);
                   1022:            d->enOD_FiltEnd = &(fp[d->enOD_OpenFilter.enf_FilterLen]);
                   1023:            d->enOD_RecvCount = 0;      /* reset count when filter changes */
                   1024:            dequeue((struct Queue *)d->enOD_Link.B);
                   1025:            enDesq.enQ_NumQueued--;
                   1026:            enInsertDescriptor(&(enDesq), d);
                   1027:             splx(ipl);
                   1028:        }
                   1029:         endcase
                   1030: 
                   1031:        /*
                   1032:         *  Enable signal n on input packet
                   1033:         */
                   1034:        case EIOCENBS:
                   1035:        {
                   1036:             int snum;
                   1037: 
                   1038:            bcopy(addr, (caddr_t)&snum, sizeof snum);
                   1039:            if (snum < NSIG) {
                   1040:                    d->enOD_SigProc = u.u_procp;
                   1041:                    d->enOD_SigPid  = u.u_procp->p_pid;
                   1042:                    d->enOD_SigNumb = snum;     /* This must be set last */
                   1043:            } else {
                   1044:                    goto bad;
                   1045:            }
                   1046:        }
                   1047:        endcase
                   1048: 
                   1049:        /*
                   1050:         *  Disable signal on input packet
                   1051:         */
                   1052:        case EIOCINHS:
                   1053:        {
                   1054:                d->enOD_SigNumb = 0;
                   1055:        }
                   1056:        endcase
                   1057: 
                   1058:        /*
                   1059:         *  Check for packet waiting
                   1060:         */
                   1061:        case FIONREAD:
                   1062:        {
                   1063:             int n;
                   1064:             register struct enWaitQueue *wq;
                   1065: 
                   1066:            ipl = splenet();
                   1067:            if ((wq = &(d->enOD_Waiting))->enWQ_NumQueued)
                   1068:                n = wq->enWQ_Packets[wq->enWQ_Head]->enP_ByteCount;
                   1069:            else
                   1070:                n = 0;
                   1071:            splx(ipl);
                   1072:            bcopy((caddr_t)&n, addr, sizeof n);
                   1073:        }
                   1074:        endcase
                   1075: 
                   1076:        /*
                   1077:         *  Set maximum recv queue length for a device
                   1078:         */
                   1079:        case EIOCSETW:
                   1080:        {
                   1081:             unsigned un;
                   1082: 
                   1083:            bcopy(addr, (caddr_t)&un, sizeof un);
                   1084:            /*
                   1085:              *  unsigned un         MaxQueued
                   1086:              * ----------------    ------------
                   1087:              *  0               ->  DEFWAITING
                   1088:             *  1..MAXWAITING   ->  un
                   1089:             *  MAXWAITING..-1  ->  MAXWAITING
                   1090:              */
                   1091:            d->enOD_Waiting.enWQ_MaxWaiting = (un) ? min(un, ENMAXWAITING)
                   1092:                                         : ENDEFWAITING;
                   1093:        }
                   1094:        endcase
                   1095: 
                   1096:        /*
                   1097:         *  Flush all packets queued for a device
                   1098:         */
                   1099:        case EIOCFLUSH:
                   1100:        {
                   1101:            ipl = splenet();
                   1102:            enFlushWaitQueue(&(d->enOD_Waiting));
                   1103:            splx(ipl);
                   1104:        }
                   1105:        endcase
                   1106: 
                   1107:        /*
                   1108:         *  Set mode bits
                   1109:         */
                   1110:        case EIOCMBIS:
                   1111:        {
                   1112:            u_short mode;
                   1113: 
                   1114:            bcopy(addr, (caddr_t)&mode, sizeof mode);
                   1115:            if (mode&ENPRIVMODES)
                   1116:                return(EINVAL);
                   1117:            else
                   1118:                d->enOD_Flag |= mode;
                   1119:        }
                   1120:        endcase
                   1121: 
                   1122:        /*
                   1123:         *  Clear mode bits
                   1124:         */
                   1125:        case EIOCMBIC:
                   1126:        {
                   1127:            u_short mode;
                   1128: 
                   1129:            bcopy(addr, (caddr_t)&mode, sizeof mode);
                   1130:            if (mode&ENPRIVMODES)
                   1131:                return(EINVAL);
                   1132:            else
                   1133:                d->enOD_Flag &= ~mode;
                   1134:        }
                   1135:        endcase
                   1136: 
                   1137:        /*
                   1138:         * Return hardware-specific device parameters.
                   1139:         */
                   1140:        case EIOCDEVP:
                   1141:        {
                   1142:            bcopy((caddr_t)&(enDevParams), addr, sizeof(struct endevp));
                   1143:        }
                   1144:        endcase;
                   1145: 
                   1146:        /*
                   1147:         * Return # of free minor devices.
                   1148:         */
                   1149:        case EIOCMFREE:
                   1150:        {
                   1151:            register int md;
                   1152:            register int sum = 0;
                   1153:            
                   1154:            for (md = 0; md < enMaxMinors; md++)
                   1155:                if (enAllocMap[md] == FALSE)
                   1156:                        sum++;
                   1157:            *(int *)addr = sum;
                   1158:        }
                   1159:        endcase;
                   1160: 
                   1161:         default:
                   1162:        {
                   1163:        bad:
                   1164:            return(EINVAL);
                   1165:        }
                   1166:     }
                   1167: 
                   1168:     return(0);
                   1169: 
                   1170: }
                   1171:                               
                   1172: /****************************************************************
                   1173:  *                                                             *
                   1174:  *             Support for select() system call                *
                   1175:  *                                                             *
                   1176:  *     Other hooks in:                                         *
                   1177:  *             enInitDescriptor()                              *
                   1178:  *             enInputDone()                                   *
                   1179:  *             enTimeout()                                     *
                   1180:  ****************************************************************/
                   1181: /*
                   1182:  * inspired by the code in tty.c for the same purpose.
                   1183:  */
                   1184: 
                   1185: /*
                   1186:  * enetselect - returns true iff the specific operation
                   1187:  *     will not block indefinitely.  Otherwise, return
                   1188:  *     false but make a note that a selwakeup() must be done.
                   1189:  */
                   1190: enetselect(dev, rw)
                   1191: register dev_t dev;
                   1192: int rw;
                   1193: {
                   1194:        register struct enOpenDescriptor *d;
                   1195:        register struct enWaitQueue *wq;
                   1196:        register int ipl;
                   1197:        register int avail;
                   1198:        
                   1199:        switch (rw) {
                   1200:        
                   1201:        case FREAD:
                   1202:                /*
                   1203:                 * an imitation of the FIONREAD ioctl code
                   1204:                 */
                   1205:                d = &(enAllDescriptors[ENINDEX(dev)]);
                   1206:                
                   1207:                ipl = splenet();
                   1208:                wq = &(d->enOD_Waiting);
                   1209:                if (wq->enWQ_NumQueued)
                   1210:                        avail = 1;      /* at least one packet queued */
                   1211:                else {
                   1212:                        avail = 0;      /* sorry, nothing queued now */
                   1213:                        /*
                   1214:                         * If there's already a select() waiting on this
                   1215:                         * minor device then this is a collision.
                   1216:                         * [This shouldn't happen because enet minors
                   1217:                         * really should not be shared, but if a process
                   1218:                         * forks while one of these is open, it is possible
                   1219:                         * that both processes could select() us.]
                   1220:                         */
                   1221:                        if (d->enOD_SelProc
                   1222:                             && d->enOD_SelProc->p_wchan == (caddr_t)&selwait)
                   1223:                                d->enOD_SelColl = 1;
                   1224:                        else
                   1225:                                d->enOD_SelProc = u.u_procp;            
                   1226:                }
                   1227:                splx(ipl);      
                   1228:                return(avail);
                   1229: 
                   1230:        case FWRITE:
                   1231:                /*
                   1232:                 * since the queueing for output is shared not just with
                   1233:                 * the other enet devices but also with the IP system,
                   1234:                 * we can't predict what would happen on a subsequent
                   1235:                 * write.  However, since we presume that all writes
                   1236:                 * complete eventually, and probably fairly fast, we
                   1237:                 * pretend that select() is true.
                   1238:                 */
                   1239:                return(1);
                   1240: 
                   1241:        default:                /* hmmm. */
                   1242:                return(1);              /* don't block in select() */
                   1243:        }
                   1244: }
                   1245: 
                   1246: enetwakeup(d)
                   1247: register struct enOpenDescriptor *d;
                   1248: {
                   1249:        if (d->enOD_SelProc) {
                   1250:                selwakeup(d->enOD_SelProc, d->enOD_SelColl);
                   1251:                d->enOD_SelColl = 0;
                   1252:                d->enOD_SelProc = 0;
                   1253:        }
                   1254: }
                   1255: 
                   1256: /*
                   1257:  * enetFilter - incoming linkage from ../vaxif/if_en.c
                   1258:  */
                   1259: 
                   1260: enetFilter(en, m, count)
                   1261: register int en;
                   1262: register struct mbuf *m;
                   1263: register int count;
                   1264: {
                   1265:     register struct enState *enStatep = &enState[en];
                   1266:     register struct enPacket *p;
                   1267:     register int pullcount;    /* bytes, not words */
                   1268:     int s = splenet();
                   1269: 
                   1270: #if    DEBUG
                   1271:     enprintf(ENDBG_TRACE)("enetFilter(%d):\n", en);
                   1272: #endif
                   1273: 
                   1274:     p = enAllocatePacket();    /* panics if not possible */
                   1275: 
                   1276:     p->enP_ByteCount = count;
                   1277:     
                   1278:     pullcount = min(MLEN, count);      /* largest possible first mbuf */
                   1279:     if (m->m_len < pullcount) {
                   1280:        /* first mbuf not as full as it could be - fix this */
                   1281:        if ((m = m_pullup(m, pullcount)) == 0) {
                   1282:            /* evidently no resources; bloody m_pullup discarded mbuf */
                   1283:            enDeallocatePacket(p);
                   1284:            enRdrops++;
                   1285:            goto out;
                   1286:        }
                   1287:     }
                   1288:     
                   1289:     p->enP_mbuf = m;
                   1290:     p->enP_Data = mtod(m, u_short *);
                   1291: 
                   1292:     enInputDone(enStatep, p);
                   1293: out:
                   1294:     splx(s);
                   1295: }
                   1296: 
                   1297: /*
                   1298:  * enInputDone - process correctly received packet
                   1299:  */
                   1300: 
                   1301: enInputDone(enStatep, p)
                   1302: register struct enState *enStatep;
                   1303: register struct enPacket *p;
                   1304: {
                   1305:     register struct enOpenDescriptor *d;
                   1306:     int queued = 0;
                   1307:     register int maxword;
                   1308:     register unsigned long rcount;
                   1309:     register struct enOpenDescriptor *prevd;
                   1310: 
                   1311: #if    INNERDEBUG
                   1312:     enprintf(ENDBG_TRACE)("enInputDone(%x): %x\n", enStatep, p);
                   1313: #endif
                   1314:     /* precompute highest possible word offset */
                   1315:     /* can't address beyond end of packet or end of first mbuf */
                   1316:     maxword = (min(p->enP_ByteCount, p->enP_mbuf->m_len)>>1);
                   1317: 
                   1318:     forAllOpenDescriptors(d)
                   1319:     {
                   1320:        if (enDoFilter(p, d, maxword))
                   1321:        {
                   1322:             if (d->enOD_Waiting.enWQ_NumQueued < d->enOD_Waiting.enWQ_MaxWaiting)
                   1323:            {
                   1324:                 enEnWaitQueue(&(d->enOD_Waiting), p);
                   1325:                 p->enP_RefCount++;
                   1326:                queued++;
                   1327:                 wakeup((caddr_t)d);
                   1328:                enetwakeup(d);
                   1329: #if    INNERDEBUG
                   1330:                 enprintf(ENDBG_TRACE)("enInputDone: queued\n");
                   1331: #endif
                   1332:            }
                   1333:            /*  send notification when input packet received  */
                   1334:            if (d->enOD_SigNumb) {
                   1335:                if (d->enOD_SigProc->p_pid == d->enOD_SigPid)
                   1336:                        psignal(d->enOD_SigProc, d->enOD_SigNumb);
                   1337:                if ((d->enOD_Flag & ENHOLDSIG) == 0)
                   1338:                        d->enOD_SigNumb = 0;            /* disable signal */
                   1339:            }
                   1340:            rcount = ++(d->enOD_RecvCount);
                   1341:            
                   1342:            /* see if ordering of filters is wrong */
                   1343:            if (d->enOD_OpenFilter.enf_Priority >= ENHIPRI) {
                   1344:                prevd = (struct enOpenDescriptor *)d->enOD_Link.B;
                   1345:                /*
                   1346:                 * If d is not the first element on the queue, and
                   1347:                 * the previous element is at equal priority but has
                   1348:                 * a lower count, then promote d to be in front of prevd.
                   1349:                 */
                   1350:                if (((struct Queue *)prevd != &(enDesq.enQ_Head)) &&
                   1351:                    (d->enOD_OpenFilter.enf_Priority ==
                   1352:                                prevd->enOD_OpenFilter.enf_Priority)) {
                   1353:                    /* threshold difference to avoid thrashing */
                   1354:                    if ((100 + prevd->enOD_RecvCount) < rcount) {
                   1355:                        enReorderQueue(&(prevd->enOD_Link), &(d->enOD_Link));
                   1356:                    }
                   1357:                }
                   1358:                break;  /* high-priority filter => no more deliveries */
                   1359:            }
                   1360:            else if (enOneCopy)
                   1361:                break;
                   1362:        }
                   1363:     }
                   1364:     if (queued == 0)                   /* this buffer no longer in use */
                   1365:     {
                   1366:        m_freem(p->enP_mbuf);                   /* free mbuf */
                   1367:        enDeallocatePacket(p);                  /*  and packet */
                   1368:        enRdrops++;
                   1369:     }
                   1370:     else
                   1371:        enRcnt++;
                   1372: 
                   1373: }
                   1374: 
                   1375: #define        opx(i)  (i>>ENF_NBPA)
                   1376: 
                   1377: boolean
                   1378: enDoFilter(p, d, maxword)
                   1379: struct enPacket *p;
                   1380: struct enOpenDescriptor *d;
                   1381: register int maxword;
                   1382: {
                   1383: 
                   1384:     register unsigned short *sp;
                   1385:     register unsigned short *fp;
                   1386:     register unsigned short *fpe;
                   1387:     register unsigned op;
                   1388:     register unsigned arg;
                   1389:     unsigned short stack[ENMAXFILTERS+1];
                   1390:     struct fw {unsigned arg:ENF_NBPA, op:ENF_NBPO;};
                   1391: 
                   1392: #ifdef INNERDEBUG
                   1393:     enprintf(ENDBG_TRACE)("enDoFilter(%x,%x):\n", p, d);
                   1394: #endif
                   1395:     sp = &stack[ENMAXFILTERS];
                   1396:     fp = &d->enOD_OpenFilter.enf_Filter[0];
                   1397:     fpe = d->enOD_FiltEnd;
                   1398:        /* ^ is really: fpe = &fp[d->enOD_OpenFilter.enf_FilterLen]; */
                   1399:     *sp = TRUE;
                   1400: 
                   1401:     for (; fp < fpe; )
                   1402:     {
                   1403:        op = ((struct fw *)fp)->op;
                   1404:        arg = ((struct fw *)fp)->arg;
                   1405:        fp++;
                   1406:        switch (arg)
                   1407:        {
                   1408:            default:
                   1409:                arg -= ENF_PUSHWORD;
                   1410: #ifndef        lint
                   1411:                /*
                   1412:                 * This next test is a little bogus; since arg
                   1413:                 * is unsigned, it is always >= 0 (the compiler
                   1414:                 * knows this and emits no code).  If arg were
                   1415:                 * less than ENF_PUSHWORD before the subtract,
                   1416:                 * it is certaintly going to be more than maxword
                   1417:                 * afterward, so the code does work "right"
                   1418:                 */
                   1419:                if ((arg >= 0) && (arg < maxword))
                   1420: #else
                   1421:                if (arg < maxword)
                   1422: #endif lint
                   1423:                    *--sp = p->enP_Data[arg];
                   1424:                else
                   1425:                {
                   1426: #ifdef INNERDEBUG
                   1427:                    enprintf(ENDBG_TRACE)("=>0(len)\n");
                   1428: #endif
                   1429:                    return(false);
                   1430:                }
                   1431:                break;
                   1432:            case ENF_PUSHLIT:
                   1433:                *--sp = *fp++;
                   1434:                break;
                   1435:            case ENF_PUSHZERO:
                   1436:                *--sp = 0;
                   1437:            case ENF_NOPUSH:
                   1438:                break;
                   1439:        }
                   1440:        if (sp < &stack[2])     /* check stack overflow: small yellow zone */
                   1441:        {
                   1442:            enprintf(ENDBG_TRACE)("=>0(--sp)\n");
                   1443:            return(false);
                   1444:        }
                   1445:        if (op == ENF_NOP)
                   1446:            continue;
                   1447:        /*
                   1448:         * all non-NOP operators binary, must have at least two operands
                   1449:         * on stack to evaluate.
                   1450:         */
                   1451:        if (sp > &stack[ENMAXFILTERS-2])
                   1452:        {
                   1453:            enprintf(ENDBG_TRACE)("=>0(sp++)\n");
                   1454:            return(false);
                   1455:        }
                   1456:        arg = *sp++;
                   1457:        switch (op)
                   1458:        {
                   1459:            default:
                   1460: #ifdef INNERDEBUG
                   1461:                enprintf(ENDBG_TRACE)("=>0(def)\n");
                   1462: #endif
                   1463:                return(false);
                   1464:            case opx(ENF_AND):
                   1465:                *sp &= arg;
                   1466:                break;
                   1467:            case opx(ENF_OR):
                   1468:                *sp |= arg;
                   1469:                break;
                   1470:            case opx(ENF_XOR):
                   1471:                *sp ^= arg;
                   1472:                break;
                   1473:            case opx(ENF_EQ):
                   1474:                *sp = (*sp == arg);
                   1475:                break;
                   1476:            case opx(ENF_NEQ):
                   1477:                *sp = (*sp != arg);
                   1478:                break;
                   1479:            case opx(ENF_LT):
                   1480:                *sp = (*sp < arg);
                   1481:                break;
                   1482:            case opx(ENF_LE):
                   1483:                *sp = (*sp <= arg);
                   1484:                break;
                   1485:            case opx(ENF_GT):
                   1486:                *sp = (*sp > arg);
                   1487:                break;
                   1488:            case opx(ENF_GE):
                   1489:                *sp = (*sp >= arg);
                   1490:                break;
                   1491: 
                   1492:            /* short-circuit operators */
                   1493: 
                   1494:            case opx(ENF_COR):
                   1495:                if (*sp++ == arg) {
                   1496: #ifdef INNERDEBUG
                   1497:                    enprintf(ENDBG_TRACE)("=>COR %x\n", *sp);
                   1498: #endif
                   1499:                    return(true);
                   1500:                }
                   1501:                break;
                   1502:            case opx(ENF_CAND):
                   1503:                if (*sp++ != arg) {
                   1504: #ifdef INNERDEBUG
                   1505:                    enprintf(ENDBG_TRACE)("=>CAND %x\n", *sp);
                   1506: #endif
                   1507:                    return(false);
                   1508:                }
                   1509:                break;
                   1510:            case opx(ENF_CNOR):
                   1511:                if (*sp++ == arg) {
                   1512: #ifdef INNERDEBUG
                   1513:                    enprintf(ENDBG_TRACE)("=>COR %x\n", *sp);
                   1514: #endif
                   1515:                    return(false);
                   1516:                }
                   1517:                break;
                   1518:            case opx(ENF_CNAND):
                   1519:                if (*sp++ != arg) {
                   1520: #ifdef INNERDEBUG
                   1521:                    enprintf(ENDBG_TRACE)("=>CAND %x\n", *sp);
                   1522: #endif
                   1523:                    return(true);
                   1524:                }
                   1525:                break;
                   1526:        }
                   1527:     }
                   1528: #ifdef INNERDEBUG
                   1529:     enprintf(ENDBG_TRACE)("=>%x\n", *sp);
                   1530: #endif
                   1531:     return((boolean)*sp);
                   1532: 
                   1533: }
                   1534: 
                   1535: enInitDescriptor(d, flag)
                   1536: register struct enOpenDescriptor *d;
                   1537: {
                   1538: 
                   1539: #if    DEBUG
                   1540:     enprintf(ENDBG_TRACE)("enInitDescriptor(%x):\n", d);
                   1541: #endif
                   1542:     d->enOD_RecvState = ENRECVIDLE;
                   1543:     d->enOD_OpenFilter.enf_FilterLen = 0;
                   1544:     d->enOD_OpenFilter.enf_Priority = 0;
                   1545:     d->enOD_FiltEnd = &(d->enOD_OpenFilter.enf_Filter[0]);
                   1546:     d->enOD_RecvCount = 0;
                   1547:     d->enOD_Timeout = 0;
                   1548:     d->enOD_SigNumb = 0;
                   1549:     d->enOD_Flag = flag;
                   1550:     d->enOD_SelColl = 0;
                   1551:     d->enOD_SelProc = 0;               /* probably unnecessary */
                   1552:     /*
                   1553:      * Remember the PID that opened us, at least until some process
                   1554:      * sets a signal for this minor device
                   1555:      */
                   1556:     d->enOD_SigPid = u.u_procp->p_pid;
                   1557: 
                   1558:     enInitWaitQueue(&(d->enOD_Waiting));
                   1559: #if    DEBUG
                   1560:     enprintf(ENDBG_TRACE)("=>eninitdescriptor\n");
                   1561: #endif
                   1562: 
                   1563: }
                   1564: 
                   1565: /*
                   1566:  *  enInsertDescriptor - insert open descriptor in queue ordered by priority
                   1567:  */
                   1568: 
                   1569: enInsertDescriptor(q, d)
                   1570: register struct enQueue *q;
                   1571: register struct enOpenDescriptor *d;
                   1572: {
                   1573:     struct enOpenDescriptor * nxt;
                   1574:     register int ipl;
                   1575: 
                   1576:     ipl = splenet();
                   1577:     nxt = (struct enOpenDescriptor *)q->enQ_F;
                   1578:     while ((struct Queue *)q != &(nxt->enOD_Link))
                   1579:     {
                   1580:         if (d->enOD_OpenFilter.enf_Priority > nxt->enOD_OpenFilter.enf_Priority)
                   1581:            break;
                   1582:         nxt = (struct enOpenDescriptor *)nxt->enOD_Link.F;
                   1583:     }
                   1584:     enqueue((struct Queue *)&(nxt->enOD_Link),(struct Queue *)&(d->enOD_Link));
                   1585:     enprintf(ENDBG_DESQ)("enID: Desq: %x, %x\n", q->enQ_F, q->enQ_B);
                   1586:     q->enQ_NumQueued++;
                   1587:     splx(ipl);
                   1588: 
                   1589: }
                   1590: 
                   1591: int enReorderCount = 0;                /* for external monitoring */
                   1592: 
                   1593: /*
                   1594:  * enReorderQueue - swap order of two elements in queue
                   1595:  *     assumed to be called at splenet
                   1596:  */
                   1597: enReorderQueue(first, last)
                   1598: register struct Queue *first;
                   1599: register struct Queue *last;
                   1600: {
                   1601:        register struct Queue *prev;
                   1602:        register struct Queue *next;
                   1603: 
                   1604:        enprintf(ENDBG_DESQ)("enReorderQ: %x, %x\n", first, last);
                   1605:        
                   1606:        enReorderCount++;
                   1607: 
                   1608:        /* get pointers to other queue elements */
                   1609:        prev = first->B;
                   1610:        next = last->F;
                   1611:        
                   1612:        /*
                   1613:         * no more reading from queue elements; this ensures that
                   1614:         * the code works even if there are fewer than 4 elements
                   1615:         * in the queue.
                   1616:         */
                   1617: 
                   1618:        prev->F = last;
                   1619:        next->B = first;
                   1620:        
                   1621:        last->B = prev;
                   1622:        last->F = first;
                   1623:        
                   1624:        first->F = next;
                   1625:        first->B = last;
                   1626: }
                   1627: 
                   1628: enetattach(ifp, devp)
                   1629: struct ifnet *ifp;
                   1630: struct endevp *devp;
                   1631: {
                   1632:     register struct enState *enStatep = &enState[enUnits];
                   1633: 
                   1634: #ifdef DEBUG
                   1635:     enprintf(ENDBG_INIT) ("enetattach: type %d, addr ", devp->end_dev_type);
                   1636:     if (enDebug&ENDBG_INIT) {
                   1637:        register int i;
                   1638:        for (i = 0; i < devp->end_addr_len; i++)
                   1639:            printf("%o ", devp->end_addr[i]);
                   1640:        printf("\n");
                   1641:     }
                   1642: #endif DEBUG
                   1643: 
                   1644:     enet_info[enUnits].ifp = ifp;
                   1645: 
                   1646:     bcopy((caddr_t)devp, (caddr_t)&(enDevParams), sizeof(struct endevp));
                   1647: 
                   1648:     enInit(enStatep, enUnits);
                   1649:     
                   1650:     return(enUnits++);
                   1651: }
                   1652: 
                   1653: #endif (NENETFILTER > 0)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.