📄 pfilt.c
字号:
/* * Used in filter processing to avoid having to do an m_pullup */struct enpextent { long afterEnd; /* pkt offset of first byte after extent */ long offset; /* pkt offset of first byte of extent */ /* LONG SIGNED TO MAKE IT RUN FAST */ char *data; /* memory address of first byte of extent */};#define MAX_EXTENTS 16 /* enough for an ether pkt in mbufs */#define MAX_OFFSET (2<<ENF_NBPA) /* guaranteed to be larger than any offset that can be embedded in a filter *//* #define SELF_PROF 1 */#ifdef SELF_PROFint enSelfProf = 0; /* set this non-zero for profiling */struct timeval enPerPktProf = {0, 0};int enPktCount = 0;struct timeval enPerFiltProf = {0, 0};int enFiltCount = 0;struct timeval enCalibrateProf = {0, 0};int enCalibrateCount = 0;#endif SELF_PROF/**************************************************************** * * * Various Macros & Routines * * * ****************************************************************//* * forAllOpenDescriptors(p) -- a macro for iterating * over all currently open devices. Use it in place of * "for ( ...; ... ; ... )" * and supply your own loop body. The loop variable is the * parameter p which is set to point to the descriptor for * each open device in turn. */#define forAllOpenDescriptors(p) \ for ((p) = (struct enOpenDescriptor *)enDesq.enQ_F; \ (struct Queue *)(&enDesq) != &((p)->enOD_Link); \ (p) = (struct enOpenDescriptor *)(p)->enOD_Link.F)/* * enEnqueue - add an element to a queue */#define PfiltEnqueue(q, elt) \{ \ pfiltenqueue((struct Queue *)(q), (struct Queue *)(elt)); \ (q)->enQ_NumQueued++; \}/* * PfiltFlushQueue - release all packets from queue, freeing any * whose reference counts drop to 0. Assumes caller * is at high IPL so that queue will not be modified while * it is being flushed. */PfiltFlushQueue(q)register struct enQueue *q;{ register struct enPacket *qelt; smp_lock(&lk_pfilt, LK_RETRY); pfiltdequeue((struct Queue *)q, qelt); /* "qelt" is filled in at the end of the call pfiltdequeue */ while(qelt != NULL) { if (0 == --(qelt->enP_RefCount)) { PfiltEnqueue(&enFreeq, qelt); } pfiltdequeue((struct Queue *)q, qelt); } q->enQ_NumQueued = 0; smp_unlock(&lk_pfilt);}/* * PfiltInitWaitQueue - initialize an empty packet wait queue */PfiltInitWaitQueue(wq)register struct enWaitQueue *wq;{ wq->enWQ_Head = 0; wq->enWQ_Tail = 0; wq->enWQ_NumQueued = 0; wq->enWQ_MaxWaiting = ENDEFWAITING;}/* * PfiltEnWaitQueue - add a packet to a wait queue * SMP: assumes lock held coming in */PfiltEnWaitQueue(wq, p)register struct enWaitQueue *wq;struct enPacket *p;{ if (smp_debug) { if (!(smp_owner(&lk_pfilt))) panic("PfiltEnWaitQueue: not lock owner"); } wq->enWQ_Packets[wq->enWQ_Tail] = p; wq->enWQ_NumQueued++; PfiltNextWaitQueueIndex(wq->enWQ_Tail);}/* * PfiltDeWaitQueue - remove a packet from a wait queue * SMP: assumes lock held coming in */struct enPacket *PfiltDeWaitQueue(wq)register struct enWaitQueue *wq;{ struct enPacket *p; if (smp_debug) { if (!(smp_owner(&lk_pfilt))) panic("PfiltDeWaitQueue: not lock owner"); } if (wq->enWQ_NumQueued < 1) panic("PfiltDeWaitQueue"); wq->enWQ_NumQueued--; p = wq->enWQ_Packets[wq->enWQ_Head]; PfiltNextWaitQueueIndex(wq->enWQ_Head); return(p);}/* * PfiltPutBack - undo the effect of PfiltDeWaitQueue; MUST be called * immediately after corresponding PfiltDeWaitQueue with no * intervening interrupts! * SMP: assumes lock held coming in */PfiltPutBack(wq, p)register struct enWaitQueue *wq;struct enPacket *p;{ if (smp_debug) { if (!(smp_owner(&lk_pfilt))) panic("PfiltPutBack: not lock owner"); } PfiltPrevWaitQueueIndex(wq->enWQ_Head); wq->enWQ_Packets[wq->enWQ_Head] = p; wq->enWQ_NumQueued++;}/* * PfiltTrimWaitQueue - cut a wait queue back to size * SMP: assumes lock held coming in */PfiltTrimWaitQueue(d, threshold)register struct enOpenDescriptor *d;int threshold;{ register struct enWaitQueue *wq = &(d->enOD_Waiting); register int Counter = (wq->enWQ_NumQueued - threshold); register struct enPacket *p; if (smp_debug) { if (!(smp_owner(&lk_pfilt))) panic("PfiltTrimWaitQueue: not lock owner"); }#ifdef DEBUG Pfiltprintf(ENDBG_SCAV) ("PfiltTrimWaitQueue(%x, %d): %d\n", d, threshold, Counter);#endif while (Counter-- > 0) { wq->enWQ_NumQueued--; PfiltPrevWaitQueueIndex(wq->enWQ_Tail); p = wq->enWQ_Packets[wq->enWQ_Tail]; d->enOD_Drops += (1 + p->enP_Stamp.ens_dropped); /* dropped this packet and it might have recorded other drops. */ enScavDrops++; if (0 == --(p->enP_RefCount)) { m_freem(p->enP_mbuf); PfiltEnqueue(&enFreeq, p); } }}/* * PfiltFlushWaitQueue - remove all packets from wait queue */#define PfiltFlushWaitQueue(wq) PfiltTrimWaitQueue(wq, 0)/* * scavenging thresholds: * * index by number of active files; for N open files, each queue may retain * up to 1/Nth of the packets not guaranteed to be freed on scavenge. The * total number of available packets is computed less one for sending. * (assumes high IPL) */unsigned short enScavLevel[NPACKETFILTER+1];/* * PfiltInitScavenge -- set up ScavLevel table */PfiltInitScavenge(){ register int PoolSize = (ENPACKETS-ENMINSCAVENGE); register int i = sizeof(enScavLevel)/sizeof(enScavLevel[0]); PoolSize--; /* leave one for transmitter */ while (--i>0) enScavLevel[i] = (PoolSize / i);}/* * PfiltScavenge -- scan all OpenDescriptors for all ethernets, releasing * any queued buffers beyond the prescribed limit and freeing any whose * refcounts drop to 0. * Assumes caller is at high IPL so that it is safe to modify the queues. * SMP: assumes lock held coming in */PfiltScavenge(){ register struct enOpenDescriptor *d; register int threshold = 0; register struct enState *enStatep; register int unit; if (smp_debug) { if (!(smp_owner(&lk_pfilt))) panic("PfiltScavenge: not lock owner"); } for (unit = 0; unit < enUnits; unit++) { enStatep = enStatePs[unit]; threshold += enCurOpens; } threshold = enScavLevel[threshold]; enScavenges++;#ifdef DEBUG Pfiltprintf(ENDBG_SCAV)("PfiltScavenge: %d\n", threshold);#endif for (unit = 0; unit < enUnits; unit++) { enStatep = enStatePs[unit]; if (enDesq.enQ_F == 0) continue; /* never initialized */ forAllOpenDescriptors(d) { PfiltTrimWaitQueue(d, threshold); } }}/* * PfiltAllocatePacket - allocate the next packet from the free list * Assumes IPL is at high priority so that it is safe to touch the * packet queue. If the queue is currently empty, scavenge for * more packets. * SMP: assumes lock held coming in */struct enPacket *PfiltAllocatePacket(){ register struct enPacket *p; if (smp_debug) { if (!(smp_owner(&lk_pfilt))) panic("PfiltAllocatePacket: not lock owner"); } if (0 == enFreeq.enQ_NumQueued) PfiltScavenge(); pfiltdequeue((struct Queue *)&enFreeq, p); /* "p" is filled in at the end of the call, pfiltdequeue */ if (p == NULL) panic("PfiltAllocatePacket"); if (enFreeqMin > --enFreeq.enQ_NumQueued) enFreeqMin = enFreeq.enQ_NumQueued; p->enP_RefCount = 0; /* just in case */ return(p);}/* * PfiltDeallocatePacket - place the packet back on the free packet queue * (High IPL assumed). */#define PfiltDeallocatePacket(p) \{ \ if (p->enP_RefCount) panic("PfiltDeallocatePacket: refcount != 0");\ pfiltenqueue((struct Queue *)&enFreeq, (struct Queue *)(p)); \ enFreeq.enQ_NumQueued++; \}/**************************************************************** * * * Routines to move uio data to/from mbufs * * * ****************************************************************//* * These two routines were inspired by/stolen from ../sys/uipc_socket.c * Both return error code (or 0 if success). *//* * read: return contents of mbufs to user. DO NOT free them, since * there may be multiple claims on the packet! */Pfiltrmove(p, uio, flags, padneeded, truncation)struct enPacket *p;register struct uio *uio;short flags;int *padneeded; /* by reference, so we can change it */int truncation;{ register int len; register int count; register int error = 0; register struct mbuf *m = p->enP_mbuf; int total = 0; int pn = *padneeded; /* first, transfer header stamp */ if (flags & (ENTSTAMP|ENBATCH)) { if (uio->uio_resid >= (sizeof(struct enstamp) + pn)) { error = uiomove((caddr_t)&(p->enP_Stamp) - pn, sizeof(struct enstamp) + pn, UIO_READ, uio); if (error) return(error); } else { /* no room for stamp */ uio->uio_resid = 0; /* make sure Pfiltread() exits */ return(EMSGSIZE); } } count = min(p->enP_ByteCount, uio->uio_resid); /* # bytes to return */ if (count > truncation) count = truncation; while ((count > 0) && m && (error == 0)) { len = min(count, m->m_len); /* length of this transfer */ count -= len; total += len; error = uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); m = m->m_next; }#if DEBUG if ((error == 0) && (total != p->enP_ByteCount) && (truncation > p->enP_ByteCount) && (uio->uio_resid != 0)) { Pfiltprintf(ENDBG_MISC)("Pfiltrmove: %d != %d (resid %d)\n", total, p->enP_ByteCount, uio->uio_resid); }#endif DEBUG /* * record how much padding is needed if another packet is batched * following this one in the same read() */ if ((total &= ENALIGNMASK) == 0) { *padneeded = 0; /* already aligned */ } else { *padneeded = ENALIGNMENT - total; } return(error);}Pfiltwmove(uio, mbufp)register struct uio *uio;register struct mbuf **mbufp; /* top mbuf is returned by reference */{ struct mbuf *mtop = 0; register struct mbuf *m; register struct mbuf **mp = &mtop; register struct iovec *iov; register int len; int error = 0; while ((uio->uio_resid > 0) && (error == 0)) { iov = uio->uio_iov; if (iov->iov_len == 0) { uio->uio_iov++; uio->uio_iovcnt--; if (uio->uio_iovcnt < 0) panic("Pfiltwmove: uio_iovcnt < 0 while uio_resid > 0"); } MGET(m, M_WAIT, MT_DATA); if (m == NULL) {#ifdef DEBUG Pfiltprintf(ENDBG_NOMEM)("Pfiltwmove: MGET\n");#endif error = ENOBUFS; break; } if (iov->iov_len >= CLBYTES) { /* big enough to use a page */ register struct mbuf *p; MCLGET(m, p); if (p == 0) goto nopages; len = CLBYTES; } else {nopages: len = MIN(MLEN, iov->iov_len); } error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); m->m_len = len; *mp = m; mp = &(m->m_next); } if (error) { /* probably uiomove fouled up */ if (mtop) m_freem(mtop); } else { *mbufp = mtop; /* return ptr to top mbuf */ } return(error);}/* * Pfilt_open - open ether net device * * Errors: ENXIO - illegal minor device number * EBUSY - minor device already in use * ENOBUFS - KM_ALLOC failed *//* ARGSUSED */Pfilt_open(dev, flag, newmin)dev_t dev;int flag;int *newmin;{ register int md; register int unit; register struct enState *enStatep; register int error; int s;#ifdef DEBUG Pfiltprintf(ENDBG_TRACE)("Pfilt_open(%o, %x):\n", dev, flag);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -