📄 bpfdrv.c
字号:
nBytes = pBpfDev->readHoldLen; bcopy (pBpfDev->readHoldBuf, pBuf, nBytes); pBpfDev->freeBuf = pBpfDev->readHoldBuf; pBpfDev->readHoldBuf = NULL; pBpfDev->readHoldLen = 0; _bpfUnitUnlock (pBpfDev); return (nBytes); }/********************************************************************************* bpfWrite - outputs a packet directly to a network interface** This routine takes a fully formed packet, including any data link layer* header required by the device, and outputs it on the attached network* interface.** RETURNS:* ERROR or the number of bytes written to the interface ** ERRNOS:* S_errno_ENXIO - if the BPF device is not attached to a network interface** NOMANUAL*/LOCAL int bpfWrite ( BPF_DEV_CTRL * pBpfDev, /* BPF device control structure */ char * pBuf, /* user data buffer */ int nBytes /* number of bytes to read */ ) { /* Must be attached to a network interface */ if (pBpfDev->pNetIfCtrl == NULL) { netErrnoSet (ENXIO); return (ERROR); } if (_bpfProtoSend (pBpfDev->pNetIfCtrl, pBuf, nBytes, pBpfDev->nonBlockMode) != OK) { return (ERROR); } return (nBytes); }/********************************************************************************* bpfIoctl - implements BPF specific I/O control commands ** This routine implements the following I/O control commands for BPF devices:** FIONREAD Check for read packet available.* BIOCGBLEN Get buffer len [for read()].* BIOCSETF Set ethernet read filter.* BIOCFLUSH Flush read packet buffer.* BIOCPROMISC Put interface into promiscuous mode.* BIOCGDLT Get link layer type.* BIOCGETIF Get interface name.* BIOCSETIF Set interface.* BIOCSRTIMEOUT Set read timeout.* BIOCGRTIMEOUT Get read timeout.* BIOCGSTATS Get packet stats.* BIOCIMMEDIATE Set immediate mode.* BIOCVERSION Get filter language version.** RETURNS:* OK or ERROR** ERRNO:* S_errno_EINVAL - invalid command for BPF device* S_errno_ENOMEM - insufficient system memory* S_errno_ENOBUFS - expected buffer not found [from bpfProtoAttach() routine]* * NOMANUAL*/LOCAL STATUS bpfIoctl ( BPF_DEV_CTRL * pBpfDev, /* BPF device control structure */ int request, /* ioctl () command */ void * addr /* ioctl () command argument */ ) { int error = OK; /* errno value to set */ int lockKey; /* BPF lock key */ FAST int nBytes; /* byte count */ struct timeval * pTimeVal; /* timeout value */ UINT mSec; /* timeout in milliseconds */ struct bpf_stat * pBpfStat; /* BPF device statistics */ struct bpf_version * pBpfVersion; /* BPF filter version info */ switch (request) { default: error = EINVAL; break; case FIONBIO: _bpfUnitLock (pBpfDev); pBpfDev->nonBlockMode = * ((BOOL *) addr); _bpfUnitUnlock (pBpfDev); break; case FIONREAD: _bpfUnitLock (pBpfDev); /* Retrieve amount of data in the read and immediate buffers. */ nBytes = pBpfDev->recvStoreLen; if (pBpfDev->readHoldBuf != NULL) nBytes += pBpfDev->readHoldLen; _bpfUnitUnlock (pBpfDev); *(int *)addr = nBytes; break; case FIOSELECT: /* Add BPF unit to wakeup list. */ _bpfUnitLock (pBpfDev); bpfSelectAdd (pBpfDev, (SEL_WAKEUP_NODE *)addr); _bpfUnitUnlock (pBpfDev); break; case FIOUNSELECT: /* Remove BPF unit from wakeup list. */ _bpfUnitLock (pBpfDev); bpfSelectDelete (pBpfDev, (SEL_WAKEUP_NODE *)addr); _bpfUnitUnlock (pBpfDev); break; case BIOCGBLEN: _bpfUnitLock (pBpfDev); *(u_int *)addr = pBpfDev->bufSize; _bpfUnitUnlock (pBpfDev); break; case BIOCSBLEN: _bpfUnitLock (pBpfDev); /* Cannot set buffer len after attaching to network interface. */ if (pBpfDev->pNetDev != NULL) { _bpfUnitUnlock (pBpfDev); error = EINVAL; break; } nBytes = *(u_int *)addr; /* New buffer size must be between maximum and minimum limits. */ if (nBytes > BPF_MAXBUFSIZE) nBytes = BPF_MAXBUFSIZE; if (nBytes < BPF_MINBUFSIZE) { nBytes = BPF_MINBUFSIZE; } /* Determine if enough memory remains to allocate buffer. */ if ( (nBytes = min (nBytes, memFindMax ())) < BPF_MINBUFSIZE) { _bpfUnitUnlock (pBpfDev); error = ENOMEM; break; } *(u_int *)addr = nBytes; pBpfDev->bufSize = nBytes; (void) _bpfUnitUnlock (pBpfDev); break; case BIOCSETF: _bpfUnitLock (pBpfDev); error = bpfSetFilter (pBpfDev, (struct bpf_program *)addr); _bpfUnitUnlock (pBpfDev); break; case BIOCFLUSH: _bpfUnitLock (pBpfDev); bpfDevReset (pBpfDev); _bpfUnitUnlock (pBpfDev); break; case BIOCPROMISC: _bpfUnitLock (pBpfDev); if (pBpfDev->pNetDev == NULL) { /* No interface attached yet. */ error = EINVAL; } else if (!pBpfDev->promiscMode) { lockKey = _bpfLock (); error = _bpfProtoPromisc (pBpfDev->pNetDev, TRUE); (void) _bpfUnlock (lockKey); pBpfDev->promiscMode = (error == OK); } _bpfUnitUnlock (pBpfDev); break; case BIOCGDLT: _bpfUnitLock (pBpfDev); if (pBpfDev->pNetDev == NULL) error = EINVAL; else { *(u_int *)addr = pBpfDev->pNetDev->dataLinkType; } _bpfUnitUnlock (pBpfDev); break; case BIOCGETIF: _bpfUnitLock (pBpfDev); if (pBpfDev->pNetDev == NULL) error = EINVAL; else { sprintf ( ( (struct ifreq *)addr)->ifr_name, "%s%d", pBpfDev->pNetDev->devName, pBpfDev->pNetDev->devUnit); } _bpfUnitUnlock (pBpfDev); break; case BIOCSETIF: _bpfUnitLock (pBpfDev); error = bpfIfSet (pBpfDev, (struct ifreq *)addr, FALSE); _bpfUnitUnlock (pBpfDev); break; case BIOCSTOP: /* Detach device from input stream. */ _bpfUnitLock (pBpfDev); /* Do nothing if device is not attached. */ if (pBpfDev->pNetDev == NULL) { _bpfUnitUnlock (pBpfDev); break; } _bpfDevLock (pBpfDev->bpfDevId); _bpfDevDetach (pBpfDev); _bpfDevUnlock (pBpfDev->bpfDevId); _bpfUnitUnlock (pBpfDev); break; case BIOCSTART: /* Reattach device to input stream. */ _bpfUnitLock (pBpfDev); /* Do nothing if device is already attached. */ if (pBpfDev->pNetDev != NULL) { _bpfUnitUnlock (pBpfDev); break; } error = bpfIfSet (pBpfDev, (struct ifreq *)addr, TRUE); _bpfUnitUnlock (pBpfDev); break; case BIOCSRTIMEOUT: pTimeVal = (struct timeval *)addr; mSec = pTimeVal->tv_sec * 1000; mSec += pTimeVal->tv_usec / 1000; _bpfUnitLock (pBpfDev); /* scale milliseconds to ticks */ pBpfDev->readTimeout = (mSec * sysClkRateGet ()) / 1000; if (pBpfDev->readTimeout == 0) { if (pTimeVal->tv_usec == 0) { pBpfDev->readTimeout = WAIT_FOREVER; } else { pBpfDev->readTimeout = 1; } } _bpfUnitUnlock (pBpfDev); break; case BIOCGRTIMEOUT: pTimeVal = (struct timeval *)addr; _bpfUnitLock (pBpfDev); if (pBpfDev->readTimeout == WAIT_FOREVER) { pTimeVal->tv_sec = 0; pTimeVal->tv_usec = 0; _bpfUnitUnlock (pBpfDev); } else { mSec = (pBpfDev->readTimeout * sysClkRateGet ()) / 1000; pTimeVal->tv_sec = mSec / 1000; pTimeVal->tv_usec = mSec % 1000; } _bpfUnitUnlock (pBpfDev); break; case BIOCGSTATS: pBpfStat = (struct bpf_stat *)addr; _bpfUnitLock (pBpfDev); pBpfStat->bs_recv = pBpfDev->pktRecvCount; pBpfStat->bs_drop = pBpfDev->pktDropCount; _bpfUnitUnlock (pBpfDev); break; case BIOCIMMEDIATE: _bpfUnitLock (pBpfDev); pBpfDev->immediateMode = *(u_int *)addr; _bpfUnitUnlock (pBpfDev); break; case BIOCVERSION: pBpfVersion = (struct bpf_version *)addr; pBpfVersion->bv_major = BPF_MAJOR_VERSION; pBpfVersion->bv_minor = BPF_MINOR_VERSION; break; } if (error != OK) { netErrnoSet (error); return (ERROR); } return (OK); }/********************************************************************************* bpfDevReset - reset BPF device** This routine resets a BPF device by flushing its packet buffer and clearing * the receive and drop counts. ** RETURNS:* Not Applicable** CAVEATS:* Must be called by a task which holds the unit-specific _bpfUnitLock.** NOMANUAL*/LOCAL void bpfDevReset ( BPF_DEV_CTRL * pBpfDev /* BPF device control structure */ ) { if (pBpfDev->readHoldBuf != 0) { pBpfDev->freeBuf = pBpfDev->readHoldBuf; pBpfDev->readHoldBuf = 0; pBpfDev->readHoldLen = 0; } pBpfDev->recvStoreLen = 0; pBpfDev->pktRecvCount = 0; pBpfDev->pktDropCount = 0; }/********************************************************************************* bpfSelectAdd - joins the wakeup list for select operation** This routine implements the FIOSELECT operation. It adds a BPF device* to the list of I/O devices waiting for activity through the select()* routine. The add operation allows the bpfWakeup() routine to complete* the selection process once sufficient data arrives.** RETURNS: N/A** CAVEATS:* Must be called by a task which holds the unit-specific _bpfUnitLock.** NOMANUAL*/LOCAL void bpfSelectAdd ( BPF_DEV_CTRL * pBpfDev, /* BPF device control structure */ SEL_WAKEUP_NODE * pWakeupNode /* Control information from select */ ) { /* Only pend when selecting for read requests. */ if (selWakeupType (pWakeupNode) == SELREAD) { if (selNodeAdd (& (pBpfDev->selWkupList), pWakeupNode) == ERROR) return; pBpfDev->selectFlag = TRUE; /* Wake the calling task immediately if data is already available. */ if ( (pBpfDev->readHoldBuf != NULL) || (pBpfDev->immediateMode && pBpfDev->recvStoreLen != 0)) { selWakeup (pWakeupNode); } } return; }/********************************************************************************* bpfSelectDelete - leaves the wakeup list for select operation** This routine implements the FIOUNSELECT control operation. It removes a* BPF device from the list of I/O devices waiting for activity through the* select() routine. The remove operation completes the selection process* started with the FIOSELECT operation.** RETURNS: N/A** CAVEATS:* Must be called by a task which holds the unit-specific _bpfUnitLock.** NOMANUAL*/LOCAL void bpfSelectDelete ( BPF_DEV_CTRL * pBpfDev, /* BPF device control structure */ SEL_WAKEUP_NODE * pWakeupNode /* Control information from select */ ) { /* Only handle cancellations for read requests. */ if (selWakeupType (pWakeupNode) == SELREAD) { selNodeDelete (& (pBpfDev->selWkupList), pWakeupNode); /* * A BPF unit is only accessible through a single file descriptor, * so the list length will usually be zero at this point. However, * a task may have shared that file descriptor with others. No * race condition occurs because this routine executes while the * BPF unit is locked. */ if (selWakeupListLen (& (pBpfDev->selWkupList)) == 0) { pBpfDev->selectFlag = FALSE; } } return; }/********************************************************************************* bpfSetFilter - sets the filter program used by a BPF device** This routine sets the filter program to be used with a BPF device. Before* the filter progam is set it will be validated using the bpf_validate () * routine.** RETURNS:* OK* EINVAL if the filter program is invalid* ENOMEM if there is insufficient system memory to store the filter program** CAVEATS:* Must be called by a task which holds the unit-specific _bpfUnitLock.** INTERNAL* This routine returns errno values if a failure occurs so that the ioctl* mechanism can set the error number appropriately.** NOMANUAL*/LOCAL int bpfSetFilter ( BPF_DEV_CTRL * pBpfDev, /* BPF device control structure */ struct bpf_program * pBpfProg /* BPF filter program */ ) { struct bpf_insn * pBpfInsnNew; /* New BPF filter instructions */ struct bpf_insn * pBpfInsnOld; /* Previous BPF filter instructions */ UINT filterLen; /* size in instructions of new filter */ UINT filterSize; /* size in bytes of new filter */ BOOL newFlag = FALSE; /* allocate new storage for filter? */ pBpfInsnOld = pBpfDev->pBpfInsnFilter; /* If filter program contains no instructions set filter to NULL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -