|
|
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)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.