/* * Copyright (c) 1999 - 2003 * NetGroup, Politecnico di Torino (Italy) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include "debug.h" #include "packet.h" #include #pragma VxD_LOCKED_CODE_SEG #pragma VxD_LOCKED_DATA_SEG DWORD _stdcall MyPageLock(DWORD, DWORD); void _stdcall MyPageUnlock(DWORD, DWORD); /************************************************************ Allocates the space for a packet, extracting it from the buffer reserved for the driver ************************************************************/ VOID PacketAllocatePacketBuffer( PNDIS_STATUS pStatus, POPEN_INSTANCE pOpen, PNDIS_PACKET *lplpPacket, PDIOCPARAMETERS pDiocParms, DWORD FunctionCode ) { PNDIS_BUFFER pNdisBuffer; PPACKET_RESERVED pReserved; TRACE_ENTER( "PacketAllocatePacket" ); NdisAllocatePacket( pStatus, lplpPacket, pOpen->PacketPool ); if ( *pStatus != NDIS_STATUS_SUCCESS ) { IF_VERY_LOUD( "Read- No free packets" ); *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0; return; } InitializeListHead( &(RESERVED(*lplpPacket)->ListElement) ); pReserved = RESERVED(*lplpPacket); switch ( FunctionCode ) { case IOCTL_PROTOCOL_READ: pReserved->lpBuffer = (PVOID)PacketPageLock( (PVOID)pDiocParms->lpvOutBuffer, pDiocParms->cbOutBuffer ); pReserved->cbBuffer = pDiocParms->cbOutBuffer; break; case IOCTL_PROTOCOL_WRITE: pReserved->lpBuffer = (PVOID)PacketPageLock( pDiocParms->lpvInBuffer, pDiocParms->cbInBuffer ); pReserved->cbBuffer = pDiocParms->cbInBuffer; break; default: /*function not valid, free the resource*/ IF_TRACE_MSG( "Allocate- Invalid FunctionCode %x", FunctionCode ); NdisReinitializePacket( *lplpPacket ); NdisFreePacket( *lplpPacket ); *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0; *pStatus = NDIS_STATUS_NOT_ACCEPTED; return; } pReserved->lpcbBytesReturned = (PVOID)PacketPageLock( (PVOID)pDiocParms->lpcbBytesReturned, sizeof(DWORD) ); pReserved->lpoOverlapped = (PVOID)PacketPageLock( (PVOID)pDiocParms->lpoOverlapped, sizeof(OVERLAPPED) ); NdisAllocateBuffer( pStatus, &pNdisBuffer, pOpen->BufferPool, (PVOID)pReserved->lpBuffer, pDiocParms->cbOutBuffer ); if ( *pStatus != NDIS_STATUS_SUCCESS ) { IF_TRACE( "Read- No free buffers" ); NdisReinitializePacket(*lplpPacket); NdisFreePacket(*lplpPacket); *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0; return; } NdisChainBufferAtFront( *lplpPacket, pNdisBuffer ); IF_PACKETDEBUG( PACKET_DEBUG_VERY_LOUD ) { IF_TRACE_MSG( " lplpPacket : %lx", lplpPacket ); IF_TRACE_MSG( " lpPacket : %lx", *lplpPacket ); IF_TRACE_MSG3( "pNdisBuffer : %lx %lx %lx", pNdisBuffer, (*lplpPacket)->Private.Head, (*lplpPacket)->Private.Tail ); IF_TRACE_MSG( " Reserved : %lx", pReserved ); IF_TRACE_MSG4( " lpBuffer : %lx %lx %lx %lx", pReserved->lpBuffer, pNdisBuffer->VirtualAddress, pDiocParms->lpvOutBuffer, pDiocParms->lpvInBuffer ); IF_TRACE_MSG3( " cbBuffer : %lx %lx %lx", pReserved->cbBuffer, pDiocParms->cbOutBuffer, pDiocParms->cbInBuffer ); IF_TRACE_MSG2( " lpcbBytes : %lx %lx", pReserved->lpcbBytesReturned, pDiocParms->lpcbBytesReturned ); IF_TRACE_MSG2( " lpoOverlap : %lx %lx", pReserved->lpoOverlapped, pDiocParms->lpoOverlapped ); } PACKETASSERT( pReserved->lpBuffer ); PACKETASSERT( pReserved->cbBuffer ); PACKETASSERT( pReserved->lpcbBytesReturned ); PACKETASSERT( pReserved->lpoOverlapped ); PACKETASSERT( pNdisBuffer == (*lplpPacket)->Private.Head ); PACKETASSERT( pNdisBuffer->VirtualAddress == pReserved->lpBuffer ); TRACE_LEAVE( "PacketAllocatePacket" ); return; } /************************************************************ Move a portion of the circular buffer updating the head every 1024 bytes ************************************************************/ void PacketMoveMem(PVOID Destination, PVOID Source, ULONG Length, UINT *Bhead) { ULONG WordLength; UINT n,i,NBlocks; WordLength=Length>>2; NBlocks=WordLength>>8; for(n=0;ncbOutBuffer < ETHERNET_HEADER_LENGTH ) { /*the application's buffer if too small to contain the packet*/ *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0; IF_VERY_LOUD( "Read- Buffer too small" ); TRACE_LEAVE( "ReadPacket" ); return NDIS_STATUS_FAILURE; } /*See if there are packets in the buffer*/ Thead=Open->Bhead; Ttail=Open->Btail; TLastByte=Open->BLastByte; if (Thead == Ttail) { /*there aren't buffered packet but there is no timeout */ if(Open->TimeOut == -1){ *(DWORD *)(pDiocParms->lpcbBytesReturned)=0; return(NDIS_STATUS_SUCCESS); } /*there aren't buffered packet and there is a timeout: the application must wait*/ PacketAllocatePacketBuffer( &Status, Open, &pPacket, pDiocParms, IOCTL_PROTOCOL_READ ); if ( Status == NDIS_STATUS_SUCCESS ) { PACKETASSERT( Open != NULL ); PACKETASSERT( pPacket != NULL ); NdisAcquireSpinLock( &Open->RcvQSpinLock ); InsertTailList( &Open->RcvList, &RESERVED(pPacket)->ListElement ); NdisReleaseSpinLock( &Open->RcvQSpinLock ); /*set the timeout on the read*/ Open->ReadTimeoutTimer=SetReadTimeOut(ReadTimeout,Open->TimeOut,Open); IF_TRACE_MSG2( "RcvList Link : %lx %lx", Open->RcvList.Blink, &RESERVED(pPacket)->ListElement ); PACKETASSERT( Open->RcvList.Blink == &RESERVED(pPacket)->ListElement ); PACKETASSERT( &(Open->RcvList) == RESERVED(pPacket)->ListElement.Flink ); } TRACE_LEAVE( "PacketRead" ); return(-1); /*Communicate that the operation is asynchronous*/ } /*there is at least a buffered packet: the read call can be completed*/ Input_Buffer_Length=pDiocParms->cbOutBuffer; packp=(PUCHAR)pDiocParms->lpvOutBuffer; i=0; /*get the address of the buffer*/ CurrBuff=Open->Buffer; /*fill the application buffer*/ /*first of all see if it we can copy all the buffer in one time*/ if(Ttail>Thead){ if((Ttail-Thead)Bhead)); *(DWORD *)(pDiocParms->lpcbBytesReturned)=Ttail-Thead; // The buffer is empty: reset the read event TEvent=Open->ReadEvent; _asm mov eax,TEvent; VxDCall(_VWIN32_ResetWin32Event); return(NDIS_STATUS_SUCCESS); } } else if((TLastByte-Thead)Bhead)); Open->BLastByte=Ttail; Open->Bhead=0; *(DWORD *)(pDiocParms->lpcbBytesReturned)=TLastByte-Thead; return(NDIS_STATUS_SUCCESS); } /*scan the buffer*/ CpStart=Thead; while(TRUE){ if(Thead==Ttail)break; if(Thead==TLastByte){ PacketMoveMem(packp,CurrBuff+CpStart,Thead-CpStart,&(Open->Bhead)); packp+=(Thead-CpStart); Open->Bhead=0; Thead=0; CpStart=0; } cplen=((struct bpf_hdr*)(CurrBuff+Thead))->bh_caplen+sizeof(struct bpf_hdr); if((i+cplen > Input_Buffer_Length))break; //no more space in the application buffer cplen=Packet_WORDALIGN(cplen); i+=cplen; Thead+=cplen; } PacketMoveMem(packp,CurrBuff+CpStart,Thead-CpStart,&(Open->Bhead)); *(DWORD *)(pDiocParms->lpcbBytesReturned)=i; return(NDIS_STATUS_SUCCESS); } /************************************************************ Callback routine called by NDIS when the adapter receives a packet ************************************************************/ NDIS_STATUS NDIS_API Packet_tap ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID pvHeaderBuffer, IN UINT uiHeaderBufferSize, IN PVOID pvLookAheadBuffer, IN UINT uiLookaheadBufferSize, IN UINT uiPacketSize ) #define pOpen ((POPEN_INSTANCE)ProtocolBindingContext) { PLIST_ENTRY PacketListEntry; PNDIS_PACKET pPacket; ULONG ulSizeToTransfer; NDIS_STATUS Status; UINT uiBytesTransferred; PPACKET_RESERVED pReserved; PNDIS_BUFFER pNdisBuffer; PVOID pvActualVirtualAddress; UINT uiActualLength; PUCHAR CurrBuff; UINT Thead; UINT Ttail; UINT TLastByte; PNDIS_PACKET pPacketb; struct bpf_hdr *header; LARGE_INTEGER CapTime; __int64 lCapTime; UINT fres; //filter result UINT maxbufspace; UINT to; DWORD TEvent; TRACE_ENTER( "Packet_tap" ); PACKETASSERT( (pOpen != NULL) ); pOpen->Received++; /*number of packets received by filter ++*/ /* Check if the lookahead buffer follows the mac header. If the data follow the header (i.e. there is only a buffer) a normal bpf_filter() is executed on the packet. Otherwise if there are 2 separate buffers (this could be the case of LAN emulation or stuff like this) bpf_filter_with_2_buffers() is executed. */ if((int)pvLookAheadBuffer-(int)pvHeaderBuffer != uiHeaderBufferSize) fres=bpf_filter_with_2_buffers((struct bpf_insn*)(pOpen->bpfprogram), pvHeaderBuffer, pvLookAheadBuffer, uiHeaderBufferSize, uiPacketSize+uiHeaderBufferSize, uiLookaheadBufferSize+uiHeaderBufferSize); else fres=bpf_filter((struct bpf_insn*)(pOpen->bpfprogram), pvHeaderBuffer, uiPacketSize+uiHeaderBufferSize, uiLookaheadBufferSize+uiHeaderBufferSize); if(fres==0)return NDIS_STATUS_NOT_ACCEPTED; if( fres==-1)fres=uiPacketSize+uiHeaderBufferSize; //if the filter returns -1 the whole packet must be accepted if(pOpen->mode==1){ /*statistics mode*/ NdisAcquireSpinLock( &pOpen->CountersLock ); pOpen->Npackets++; if(uiPacketSize+uiHeaderBufferSize<60) pOpen->Nbytes+=60; else pOpen->Nbytes+=uiPacketSize+uiHeaderBufferSize; /*add preamble+SFD+FCS to the packet these values must be considered because are not part of the packet received from NDIS*/ pOpen->Nbytes+=12; NdisReleaseSpinLock( &pOpen->CountersLock ); return NDIS_STATUS_NOT_ACCEPTED; //it should be quicker } /*see if there are pending requests*/ NdisAcquireSpinLock( &pOpen->RcvQSpinLock ); PacketListEntry = PacketRemoveHeadList( &pOpen->RcvList ); NdisReleaseSpinLock( &pOpen->RcvQSpinLock ); if ( PacketListEntry == NULL ) { /*no requests. This means that the application is not performing a read in this moment: the packet must go in the buffer*/ TRACE_ENTER( "IndicateReceive" ); if(pOpen->BufSize==0)return NDIS_STATUS_NOT_ACCEPTED; Thead=pOpen->Bhead; Ttail=pOpen->Btail; TLastByte=pOpen->BLastByte; maxbufspace=fres+sizeof(struct bpf_hdr); if(Ttail+maxbufspace>=pOpen->BufSize){ if(Thead<=maxbufspace) { /*the buffer is full: the packet is lost*/ pOpen->Dropped++; return NDIS_STATUS_NOT_ACCEPTED; } else{ Ttail=0; } } if((Ttail=Thead)) { /*the buffer is full: the packet is lost*/ pOpen->Dropped++; return NDIS_STATUS_NOT_ACCEPTED; } CurrBuff=pOpen->Buffer+Ttail; /*allocate the ndis buffer*/ NdisAllocateBuffer( &Status, &pNdisBuffer, pOpen->BufferPool, CurrBuff+sizeof(struct bpf_hdr), fres); if (Status != NDIS_STATUS_SUCCESS) { pOpen->Dropped++; return NDIS_STATUS_NOT_ACCEPTED; } /*allocate the packet from NDIS*/ NdisAllocatePacket(&Status,&pPacketb,pOpen->PacketPool); if (Status != NDIS_STATUS_SUCCESS) { NdisFreeBuffer( pNdisBuffer ); pOpen->Dropped++; return NDIS_STATUS_NOT_ACCEPTED; } /*link the buffer to the packet*/ NdisChainBufferAtFront(pPacketb,pNdisBuffer); if ( uiHeaderBufferSize > 0 ) { if ( uiHeaderBufferSize > pNdisBuffer->Length ) uiHeaderBufferSize = pNdisBuffer->Length; /*copy the header*/ NdisMoveMemory(pNdisBuffer->VirtualAddress, pvHeaderBuffer, uiHeaderBufferSize ); uiBytesTransferred = uiHeaderBufferSize; (BYTE *)(pNdisBuffer->VirtualAddress) += uiHeaderBufferSize; pNdisBuffer->Length -= uiHeaderBufferSize; } ulSizeToTransfer = uiPacketSize; if ( ulSizeToTransfer > pNdisBuffer->Length ) ulSizeToTransfer = pNdisBuffer->Length; /*Copy the remaining part of the packet*/ NdisTransferData( &Status, pOpen->AdapterHandle, MacReceiveContext, 0, ulSizeToTransfer, pPacketb, &uiBytesTransferred ); uiBytesTransferred+=uiHeaderBufferSize; /*get the capture time*/ lCapTime=QuerySystemTime(); /*fill the bpf header for this packet*/ if( fres>uiBytesTransferred )fres=uiBytesTransferred; lCapTime+=pOpen->StartTime; header=(struct bpf_hdr*)CurrBuff; header->bh_tstamp.tv_usec=(long)((lCapTime%1193182)*1000000/1193182); header->bh_tstamp.tv_sec=(long)((lCapTime)/1193182); header->bh_caplen=(UINT)fres; header->bh_datalen=(UINT)uiPacketSize+uiHeaderBufferSize; header->bh_hdrlen=sizeof(struct bpf_hdr); /*update the buffer*/ Ttail+=Packet_WORDALIGN(fres+sizeof(struct bpf_hdr)); if(Ttail>Thead)TLastByte=Ttail; pOpen->Btail=Ttail; pOpen->BLastByte=TLastByte; /*free the allocated buffer*/ NdisFreeBuffer( pNdisBuffer ); /*recylcle the packet*/ NdisReinitializePacket(pPacketb); /*Put the packet on the free queue*/ NdisFreePacket(pPacketb); TEvent=pOpen->ReadEvent; _asm mov eax,TEvent; VxDCall(_VWIN32_SetWin32Event); TRACE_LEAVE( "Packet_tap" ); return NDIS_STATUS_SUCCESS; } /*cancel the timeout on this read call*/ to=pOpen->ReadTimeoutTimer; _asm push esi; _asm mov esi,to; CancelReadTimeOut(); _asm pop esi; pOpen->ReadTimeoutTimer=0; pReserved = CONTAINING_RECORD( PacketListEntry, PACKET_RESERVED, ListElement ); pPacket = CONTAINING_RECORD( pReserved, NDIS_PACKET, ProtocolReserved ); IF_PACKETDEBUG( PACKET_DEBUG_VERY_LOUD ) { IF_TRACE_MSG( " Reserved : %lx", pReserved ); IF_TRACE_MSG( " pPacket : %lx", pPacket ); IF_TRACE_MSG2( " Header : %lx %lx", pvHeaderBuffer, uiHeaderBufferSize ); IF_TRACE_MSG2( " LookAhead : %lx %lx", pvLookAheadBuffer, uiLookaheadBufferSize ); IF_TRACE_MSG( " PacketSize : %lx", uiPacketSize ); } PACKETASSERT( (pReserved != NULL) ); PACKETASSERT( (pPacket != NULL) ); pNdisBuffer = pPacket->Private.Head; /*virtual address of the buffer that will contain the packet*/ pvActualVirtualAddress = pNdisBuffer->VirtualAddress; uiActualLength = pNdisBuffer->Length; CurrBuff=pNdisBuffer->VirtualAddress; (BYTE *)(pNdisBuffer->VirtualAddress) += sizeof(struct bpf_hdr); if ( uiHeaderBufferSize > 0 ) { if ( uiHeaderBufferSize > pNdisBuffer->Length ) uiHeaderBufferSize = pNdisBuffer->Length; /*copy the header*/ NdisMoveMemory(pNdisBuffer->VirtualAddress, pvHeaderBuffer, uiHeaderBufferSize ); uiBytesTransferred = uiHeaderBufferSize; (BYTE *)(pNdisBuffer->VirtualAddress) += uiHeaderBufferSize; pNdisBuffer->Length -= uiHeaderBufferSize; } ulSizeToTransfer = uiPacketSize/*uiPacketSize - uiLookaheadBufferSize*/; if ( ulSizeToTransfer > pNdisBuffer->Length ) ulSizeToTransfer = pNdisBuffer->Length; /*Copy the remaining part of the packet*/ NdisTransferData( &Status, pOpen->AdapterHandle, MacReceiveContext, 0, ulSizeToTransfer, pPacket, &uiBytesTransferred ); uiBytesTransferred+=uiHeaderBufferSize; pNdisBuffer->VirtualAddress = pvActualVirtualAddress; pNdisBuffer->Length = uiActualLength; if ( Status != NDIS_STATUS_PENDING ) { /*store the capture time*/ lCapTime=QuerySystemTime(); /*fill the bpf header for this packet*/ if( fres>uiBytesTransferred )fres=uiBytesTransferred; lCapTime+=pOpen->StartTime; header=(struct bpf_hdr*)CurrBuff; header->bh_tstamp.tv_usec=(long)((lCapTime%1193182)*1000000/1193182); header->bh_tstamp.tv_sec=(long)((lCapTime)/1193182); header->bh_caplen=(UINT)fres; header->bh_datalen=(UINT)uiPacketSize+uiHeaderBufferSize; header->bh_hdrlen=sizeof(struct bpf_hdr); /*call the completion routine*/ PacketTransferDataComplete( pOpen, pPacket, Status, fres); } else { Status = NDIS_STATUS_SUCCESS; PacketTransferDataComplete( pOpen, pPacket, Status, 0 ); } TRACE_LEAVE( "Packet_tap" ); return NDIS_STATUS_SUCCESS; } /*Ends the transfer started with the Packet_tap function*/ VOID NDIS_API PacketTransferDataComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET pPacket, IN NDIS_STATUS Status, IN UINT uiBytesTransferred ) { PPACKET_RESERVED pReserved; OVERLAPPED* pOverlap; PNDIS_BUFFER pNdisBuffer; TRACE_ENTER( "TransferDataComplete" ); pReserved = (PPACKET_RESERVED) pPacket->ProtocolReserved; pOverlap = (OVERLAPPED *) pReserved->lpoOverlapped; PACKETASSERT( (pOpen != NULL) ); PACKETASSERT( (pReserved != NULL) ); PACKETASSERT( (pOverlap != NULL) ); IF_PACKETDEBUG( PACKET_DEBUG_VERY_LOUD ) { IF_TRACE_MSG( " Status : %lx", Status ); IF_TRACE_MSG( "BytesXfered : %lx", uiBytesTransferred ); IF_TRACE_MSG( "Byte Offset : %lx", *(pReserved->lpcbBytesReturned) ); } NdisUnchainBufferAtFront( pPacket, &pNdisBuffer ); PACKETASSERT( (pNdisBuffer != NULL) ); if ( pNdisBuffer ) NdisFreeBuffer( pNdisBuffer ); *(pReserved->lpcbBytesReturned) = uiBytesTransferred+sizeof(struct bpf_hdr); pOverlap->O_InternalHigh = *(pReserved->lpcbBytesReturned); /*wakes the application process*/ VWIN32_DIOCCompletionRoutine( pOverlap->O_Internal ); PacketPageUnlock( pReserved->lpBuffer, pReserved->cbBuffer ); PacketPageUnlock( pReserved->lpcbBytesReturned, sizeof(DWORD) ); PacketPageUnlock( pReserved->lpoOverlapped, sizeof(OVERLAPPED) ); NdisReinitializePacket( pPacket ); NdisFreePacket( pPacket ); TRACE_LEAVE( "TransferDataComplete" ); return; } VOID NDIS_API PacketReceiveComplete( IN NDIS_HANDLE ProtocolBindingContext ) { IF_PACKETDEBUG( PACKET_DEBUG_VERY_LOUD ) { TRACE_ENTER( "ReceiveComplete" ); TRACE_LEAVE( "ReceiveComplete" ); } return; } /************************************************************ Routine called by the kernel when the timeout set in the PacketRead function expires ************************************************************/ void _cdecl ReadTimeout(void) { POPEN_INSTANCE Open; PLIST_ENTRY PacketListEntry; PNDIS_PACKET pPacket; PPACKET_RESERVED Reserved; OVERLAPPED* pOverlap; PNDIS_BUFFER pNdisBuffer; PUCHAR CurrBuff; struct bpf_hdr *header; UINT to; __int64 lCapTime; //the parameter is in edx _asm{ mov Open,edx } NdisAcquireSpinLock( &Open->RcvQSpinLock ); PacketListEntry = PacketRemoveHeadList( &Open->RcvList ); NdisReleaseSpinLock( &Open->RcvQSpinLock ); Open->ReadTimeoutTimer=0; if (PacketListEntry == NULL) { return; } Reserved=CONTAINING_RECORD(PacketListEntry,PACKET_RESERVED,ListElement); pPacket=CONTAINING_RECORD(Reserved,NDIS_PACKET,ProtocolReserved); Reserved = (PPACKET_RESERVED) pPacket->ProtocolReserved; pOverlap = (OVERLAPPED *) Reserved->lpoOverlapped; if(Open->mode==1){ //count mode pNdisBuffer = pPacket->Private.Head; CurrBuff=pNdisBuffer->VirtualAddress; /*get system time*/ lCapTime=QuerySystemTime(); /*fill the bpf header for this packet*/ lCapTime+=Open->StartTime; header=(struct bpf_hdr*)CurrBuff; header->bh_tstamp.tv_usec=(long)((lCapTime%1193182)*1000000/1193182); header->bh_tstamp.tv_sec=(long)((lCapTime)/1193182); header->bh_caplen=(UINT)16; header->bh_datalen=(UINT)16; header->bh_hdrlen=sizeof(struct bpf_hdr); *(__int64*)(CurrBuff+sizeof(struct bpf_hdr))=Open->Npackets; *(__int64*)(CurrBuff+sizeof(struct bpf_hdr)+8)=Open->Nbytes; //reset the countetrs Open->Npackets=0; Open->Nbytes=0; NdisUnchainBufferAtFront( pPacket, &pNdisBuffer ); if ( pNdisBuffer ) NdisFreeBuffer( pNdisBuffer ); *(Reserved->lpcbBytesReturned) = 16 + sizeof(struct bpf_hdr); pOverlap->O_InternalHigh = 16 + sizeof(struct bpf_hdr); VWIN32_DIOCCompletionRoutine( pOverlap->O_Internal ); PacketPageUnlock( Reserved->lpBuffer, Reserved->cbBuffer ); PacketPageUnlock( Reserved->lpcbBytesReturned, sizeof(DWORD) ); PacketPageUnlock( Reserved->lpoOverlapped, sizeof(OVERLAPPED) ); NdisReinitializePacket( pPacket ); NdisFreePacket( pPacket ); return; } NdisUnchainBufferAtFront( pPacket, &pNdisBuffer ); if ( pNdisBuffer ) NdisFreeBuffer( pNdisBuffer ); //wakes the application process *(Reserved->lpcbBytesReturned) = 0; pOverlap->O_InternalHigh = *(Reserved->lpcbBytesReturned); VWIN32_DIOCCompletionRoutine( pOverlap->O_Internal ); PacketPageUnlock( Reserved->lpBuffer, Reserved->cbBuffer ); PacketPageUnlock( Reserved->lpcbBytesReturned, sizeof(DWORD) ); PacketPageUnlock( Reserved->lpoOverlapped, sizeof(OVERLAPPED) ); NdisReinitializePacket( pPacket ); NdisFreePacket( pPacket ); return; }