|
|
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.