📄 bpfdrv.c
字号:
* available through a single file descriptor at a time.** RETURNS: N/A** NOMANUAL*/void _bpfDevLock ( UINT32 devId /* Unique identifier for BPF I/O device. */ ) { BPF_DEV_HDR * pBpfDevHdr; /* BPF device header */ pBpfDevHdr = (BPF_DEV_HDR *)devId; if (semTake (pBpfDevHdr->lockSem, WAIT_FOREVER) != OK) { panic ("bpfDevLock error"); } return; }/********************************************************************************* _bpfDevUnlock - release the mutual exclusion for a BPF device** This routine permits parallel BPF operations by any BPF units within* a particular BPF I/O device. It releases the lock previously acquired* by the _bpfDevLock routine.** RETURNS: N/A** NOMANUAL*/ void _bpfDevUnlock ( UINT32 devId /* Unique identifier for BPF I/O device. */ ) { BPF_DEV_HDR * pBpfDevHdr; /* BPF device header */ pBpfDevHdr = (BPF_DEV_HDR *)devId; semGive (pBpfDevHdr->lockSem); return; }/********************************************************************************* _bpfUnitLock - provides mutual exclusion for a BPF file descriptor** This routine protects shared data structures in the BPF code by obtaining* a lock which prevents BPF operations by a specific BPF unit through its* associated file descriptor. This lock primarily prevents alterations to* settings (such as the buffer size) which are currently in use by a task.* It also guarantees that a particular BPF unit will only be available * through a single file descriptor at a time.** RETURNS: N/A** NOMANUAL*/void _bpfUnitLock ( BPF_DEV_CTRL * pBpfDev /* Control structure for open BPF unit */ ) { if (semTake (pBpfDev->lockSem, WAIT_FOREVER) != OK) { panic ("bpfUnitLock error"); } return; }/********************************************************************************* _bpfUnitUnlock - release the mutual exclusion for a BPF file descriptor** This routine permits parallel BPF operations for a BPF unit associated* with a single file descriptor. It releases the lock previously acquired* by the _bpfUnitLock routine.** RETURNS: N/A** NOMANUAL*/ void _bpfUnitUnlock ( BPF_DEV_CTRL * pBpfDev /* Control structure for open BPF unit */ ) { semGive (pBpfDev->lockSem); return; }/********************************************************************************* _bpfDevDetach - detach a BPF device from the network interface** This routine detaches the device from the attached network interface. If the* BPF device requested promiscous mode it will disable promiscuous mode for the* interface. If no units of the BPF device remain attached to the network * interface, then this routine will remove the BPF MUX protocol as well.** RETURNS:* OK or ERROR** CAVEATS:* Must be called by a task which holds the device-specific _bpfDevLock* and the unit-specific _bpfUnitLock.** NOMANUAL*/STATUS _bpfDevDetach ( BPF_DEV_CTRL * pBpfDev /* Device control structure for a BPF unit */ ) { int lockKey; /* BPF global lock */ LIST * pBpfUnitList; /* list of BPF units attached to the interface */ pBpfUnitList = & (pBpfDev->pNetDev->bpfUnitList); /* Disable promiscuous mode if established for this unit. */ if (pBpfDev->promiscMode) { pBpfDev->promiscMode = FALSE; lockKey = _bpfLock (); _bpfProtoPromisc (pBpfDev->pNetDev, FALSE); _bpfUnlock (lockKey); } /* Remove the unit from the attachment list for the BPF device. */ lstDelete (pBpfUnitList, (NODE *) pBpfDev); /* * Detach this instance of the BPF MUX protocol if no more * units from this device are using the network interface. * Remove the Ethernet input hook if no more units from any * BPF device are using any BSD network interface. */ if (lstCount (pBpfUnitList) == 0) { lockKey = _bpfLock (); _bpfProtoDetach (pBpfDev); _bpfUnlock (lockKey); } pBpfDev->pNetDev = NULL; return (OK); }/********************************************************************************* _bpfPacketTap - process packets** This routine processes packets for BPF devices. For each BPF device on the* list <pListBpfDev>, the device specific packet filter is applied. If the* filter accepts the packet then it is copied to the device's buffer. That* list has at least one entry or the BPF MUX protocol would never execute * this routine.** RETURNS:* Not Applicable** NOMANUAL*/void _bpfPacketTap ( LIST * pListBpfDev, /* BPF units attached to network interface */ long type, /* MUX encoding of frame type */ M_BLK_ID pMBlk, /* M_BLK chain containing the packet */ int netDataOffset /* offset to the start of frame data */ ) { struct timeval timeStamp; /* Timestamp of packet arrival */ int snapLen; /* length of packet data to store */ int bpfHdrLen; /* size of the BPF hdr + padding */ BPF_DEV_CTRL * pBpfDev = NULL; /* BPF device */ BPF_DEV_CTRL * pStart = NULL; bpfTimeStamp (&timeStamp); /* * Determine the size of the BPF header plus padding so that the * network header is long word aligned */ bpfHdrLen = BPF_WORDALIGN (netDataOffset + sizeof (struct bpf_hdr)) - netDataOffset; pBpfDev = pStart = (BPF_DEV_CTRL *)lstFirst (pListBpfDev); if (pBpfDev == NULL) { /* * Last attached unit for this BPF device was just removed * from the network interface. */ return; } _bpfDevLock (pBpfDev->bpfDevId); /* * Protect list of attached BPF units * while applying filters. */ for ( ; pBpfDev != NULL; pBpfDev = (BPF_DEV_CTRL *) lstNext ((NODE *) pBpfDev)) { _bpfUnitLock (pBpfDev); /* Prevent changing filter or buffer size. */ pBpfDev->pktRecvCount++; snapLen = bpf_filter (pBpfDev->pBpfInsnFilter, (u_char *) pMBlk, pMBlk->mBlkPktHdr.len, 0, type, netDataOffset); if (snapLen != 0) { /* Filter accepted the frame. Copy it to the BPF unit's buffer. */ bpfPacketCatch (pBpfDev, pMBlk, snapLen, bpfHdrLen, &timeStamp, netDataOffset); } _bpfUnitUnlock (pBpfDev); } _bpfDevUnlock (pStart->bpfDevId); return; }/********************************************************************************* bpfOpen - BPF specific open routine ** This routine opens a unit for a BPF device. It initializes a BPF_DEV_CTRL* structure. All subsequent I/O operations will supply a pointer to that* control structure through the file descriptor.** RETURNS:* BPF_DEV_CTRL * - if open is successful* ERROR - if open fails** ERRNO:* S_errno_ENXIO - if minor device number is invalid* S_errno_EBUSY - if minor device is already in use* S_errno_ENOMEM - insufficient memory for device** NOMANUAL*/ LOCAL int bpfOpen ( BPF_DEV_HDR * pBpfDevHdr, /* BPF device hdr (unused) */ char * minorDevStr, /* string containing device unit number */ int flags /* user open flags */ ) { FAST BPF_DEV_CTRL * pBpfDev = NULL; /* BPF device to open */ SEM_ID readSem; /* Trigger for incoming data. */ int minorDevNum; /* unit number for device */ /* Convert string to int and verify it contains a valid unit number */ if ( (minorDevStr == NULL) || ( (minorDevNum = atoi (minorDevStr)) < 0) || (minorDevNum >= pBpfDevHdr->numDevs) ) { netErrnoSet (ENXIO); return (ERROR); } readSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY); if (readSem == NULL) { netErrnoSet (ENOMEM); return (ERROR); } pBpfDev = pBpfDevHdr->pBpfDevTbl + minorDevNum; if (pBpfDev == NULL) /* Device control header vanished!! */ { semDelete (readSem); netErrnoSet (ENOMEM); return (ERROR); } /* * Check if this BPF unit is already in use. A device lock is required * for this test since the semaphore which provides unit locks will not * exist if it is currently unused. */ _bpfDevLock ( (UINT32)pBpfDevHdr); if (pBpfDev->inUse) { _bpfDevUnlock ( (UINT32)pBpfDevHdr); semDelete (readSem); netErrnoSet (EBUSY); return (ERROR); } /* Initialize device structure. */ bzero ( (char *)pBpfDev, sizeof (BPF_DEV_CTRL)); pBpfDev->lockSem = semBCreate (SEM_Q_FIFO, SEM_FULL); if (pBpfDev->lockSem == NULL) { _bpfDevUnlock ( (UINT32)pBpfDevHdr); semDelete (readSem); netErrnoSet (ENOMEM); return (ERROR); } pBpfDev->inUse = TRUE; _bpfDevUnlock ( (UINT32)pBpfDevHdr); pBpfDev->usrFlags = flags; pBpfDev->bufSize = pBpfDevHdr->bufSize; pBpfDev->readWkupSem = readSem; pBpfDev->readTimeout = WAIT_FOREVER; /* XXX - this uses semMInit() routine internally! PD Violation??? */ selWakeupListInit (& (pBpfDev->selWkupList)); /* * Set the element for attaching to a network interface. It is only * used if this BPF unit is the first attachment to the network * interface from the parent BPF device. */ pBpfDev->pNetIfCtrl = pBpfDevHdr->pBpfNetIfTbl + minorDevNum; /* * Attaching a BPF unit to a network interface requires a value which * uniquely identifies the parent device. This field also provides * mutual exclusion on a device-specific basis when necessary. */ pBpfDev->bpfDevId = (UINT32)pBpfDevHdr; return ((int) pBpfDev); }/********************************************************************************* bpfClose - BPF specific close routine ** This routine closes a BPF device. The steps are the following:* 1) Detach from the attached network interface if any. * 2) Free any allocated memory for store buffers and the filter.* 3) Mark the device as being unused.** RETURNS:* OK or ERROR** ERRNO:** NOMANUAL*/ LOCAL STATUS bpfClose ( BPF_DEV_CTRL * pBpfDev /* BPF device control structure */ ) { _bpfUnitLock (pBpfDev); if (pBpfDev->pNetDev != NULL) { /* Detach from the network interface */ _bpfDevLock (pBpfDev->bpfDevId); (void) _bpfDevDetach (pBpfDev); _bpfDevUnlock (pBpfDev->bpfDevId); } /* Release the buffers and mark the unit available. */ bpfDevFree (pBpfDev); /* Remove the mutex semaphore for the BPF unit instead of unlocking. */ semDelete (pBpfDev->lockSem); return (OK); }/********************************************************************************* bpfRead - read next block of packets from device buffers ** This routine reads the next block of packets from the BPF device store * buffers. The call will return immeadiately if using non-Blocking mode. If* in immediate mode bpfRead will return when the timeout expires or when a* packet arrives. In normal mode, the routine returns when the timeout* expires or when the storage buffer is filled.** RETURNS: * ERROR or the number of bytes read** ERRNOS:* S_errno_EINVAL - <nBytes> is not equal to the size of the BPF buffer* S_errno_EWOULDBLOCK - no packets are available and non-Blocking mode is on** NOMANUAL*/ LOCAL int bpfRead ( BPF_DEV_CTRL * pBpfDev, /* BPF device control structure */ char * pBuf, /* user data buffer */ int nBytes /* number of bytes to read */ ) { int error = OK; /* return value errorno code */ _bpfUnitLock (pBpfDev); /* * Restrict application to use a buffer the same size as * the internal BPF buffers. */ if (nBytes != pBpfDev->bufSize) { _bpfUnitUnlock (pBpfDev); netErrnoSet (EINVAL); return (ERROR); } /* * If the hold buffer is empty, then do a timed sleep, which * ends when the timeout expires or when enough packets * have arrived to fill the store buffer. */ while (pBpfDev->readHoldBuf == NULL) { if (pBpfDev->nonBlockMode) { if (pBpfDev->recvStoreLen == 0) { _bpfUnitUnlock (pBpfDev); netErrnoSet (EWOULDBLOCK); return (ERROR); } ROTATE_BUFFERS(pBpfDev); break; } if (pBpfDev->immediateMode && pBpfDev->recvStoreLen != 0) { /* * A packet(s) either arrived since the previous * read or arrived while we were asleep. * Rotate the buffers and return what's here. */ ROTATE_BUFFERS(pBpfDev); break; } _bpfUnitUnlock (pBpfDev); error = bpfSleep (pBpfDev, pBpfDev->readTimeout); _bpfUnitLock (pBpfDev); if (error != OK) { if (error == EWOULDBLOCK) { /* * On a timeout, return what's in the buffer, * which may be empty. If new data is available, * swap the buffers to retrieve it. */ if (pBpfDev->readHoldBuf != NULL) { /* * The read buffer is now available. The receive buffer * must have filled while sleeping and the buffers were * rotated then. */ break; } if (pBpfDev->recvStoreLen == 0) { /* No data arrived while sleeping. */ _bpfUnitUnlock (pBpfDev); return (0); } ROTATE_BUFFERS(pBpfDev); break; } /* Fatal error occurred while sleeping. */ _bpfUnitUnlock (pBpfDev); netErrnoSet (error); return (ERROR); } } /* * Move data from the read buffer into user space. The entire buffer * is transferred since the target buffer is <pBpfDev>->bufSize bytes, * so rotate the buffers appropriately. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -