--- /dev/null
+*.coff
+*.d
+*.o
+*.sym
+*.sys
-# $Id: Makefile,v 1.1 2002/06/19 15:43:15 robd Exp $
+# $Id: Makefile,v 1.2 2002/09/24 15:16:46 robd Exp $
PATH_TO_TOP = ../../..
TARGET_NAME = packet
-TARGET_CFLAGS = -DNDIS50
-# -disable-stdcall-fixup
+TARGET_CFLAGS = -DDBG -DWIN_NT_DRIVER -DKQPC_TS
TARGET_OBJECTS = \
- packet.o \
- read.o \
- openclos.o \
- write.o \
- win_bpf_filter.o
+ packet.o \
+ openclos.o \
+ read.o \
+ write.o \
+ dump.o \
+ jitter.o \
+ win_bpf_filter.o \
+ tme.o \
+ count_packets.o \
+ win_bpf_filter_init.o \
+ tcp_session.o \
+ memory_t.o \
+ time_calls.o \
+ functions.o \
+ bucket_lookup.o \
+ normal_lookup.o
+
TARGET_DDKLIBS = ndis.a
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef WIN32
+#include "tme.h"
+#include "bucket_lookup.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#include <net/tme/bucket_lookup.h>
+#else
+#include <tme/tme.h>
+#include <tme/bucket_lookup.h>
+#endif
+
+#endif
+
+
+
+/* the key is represented by the initial and final value */
+/* of the bucket. At the moment bucket_lookup is able to */
+/* manage values of 16, 32 bits. */
+uint32 bucket_lookup(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref)
+{
+ uint32 value;
+ uint32 i,j;
+ int found=-1;
+ uint32 blocks;
+ uint32 block_size;
+ uint8 *temp;
+ if ((data->key_len!=1)&& /*16 bit value*/
+ (data->key_len!=2)) /*32 bit value*/
+ return TME_ERROR;
+
+ /*32 bit values*/
+ blocks=data->filled_blocks-1;
+ block_size=data->block_size;
+ i=blocks/2; /*relative shift*/
+ j=i;
+ temp=data->shared_memory_base_address+block_size;
+
+ if (data->key_len==2)
+ {
+ value=SW_ULONG_AT(key,0);
+
+ if((value<SW_ULONG_AT(temp,0))||(value>SW_ULONG_AT(temp+block_size*(blocks-1),4)))
+ {
+ uint32 *key32=(uint32*) key;
+ key32[0]=key32[1]=0;
+
+ GET_TIME((struct timeval *)(data->shared_memory_base_address+8),time_ref);
+
+ data->last_found=NULL;
+ return TME_FALSE;
+ }
+
+ while(found==-1) /* search routine */
+ {
+ i=(i==1)? 1:i>>1;
+ if (SW_ULONG_AT(temp+block_size*j,0)>value)
+ if (SW_ULONG_AT(temp+block_size*(j-1),4)<value)
+ found=-2;
+ else
+ j-=i;
+ else
+ if (SW_ULONG_AT(temp+block_size*j,4)<value)
+ if (SW_ULONG_AT(temp+block_size*j,0)>value)
+ found=-2;
+ else
+ j+=i;
+ else found=j;
+ }
+ if (found<0)
+ {
+ uint32 *key32=(uint32*) key;
+ key32[0]=key32[1]=0;
+
+ GET_TIME((struct timeval *)(data->shared_memory_base_address+8),time_ref);
+
+ data->last_found=NULL;
+ return TME_FALSE;
+ }
+
+ data->last_found=data->lut_base_address+found*sizeof(RECORD);
+
+ COPY_MEMORY(key,temp+block_size*found,8);
+
+ GET_TIME((struct timeval *)(temp+block_size*found+8),time_ref);
+
+ return TME_TRUE;
+ }
+ else
+ {
+ value=SW_USHORT_AT(key,0);
+
+ if((value<SW_USHORT_AT(temp,0))||(value>SW_USHORT_AT(temp+block_size*(blocks-1),2)))
+ {
+ uint16 *key16=(uint16*) key;
+ key16[0]=key16[1]=0;
+
+ GET_TIME((struct timeval *)(data->shared_memory_base_address+4),time_ref);
+
+ data->last_found=NULL;
+ return TME_FALSE;
+ }
+
+ while(found==-1) /* search routine */
+ {
+ i=(i==1)? 1:i>>1;
+ if (SW_USHORT_AT(temp+block_size*j,0)>value)
+ if (SW_USHORT_AT(temp+block_size*(j-1),2)<value)
+ found=-2;
+ else
+ j-=i;
+ else
+ if (SW_USHORT_AT(temp+block_size*j,2)<value)
+ if (SW_USHORT_AT(temp+block_size*j,0)>value)
+ found=-2;
+ else
+ j+=i;
+ else found=j;
+ }
+
+ if (found<0)
+ {
+ uint16 *key16=(uint16*) key;
+ key16[0]=key16[1]=0;
+
+ GET_TIME((struct timeval *)(data->shared_memory_base_address+4),time_ref);
+
+ data->last_found=NULL;
+ return TME_FALSE;
+ }
+
+ data->last_found=data->lut_base_address+found*sizeof(RECORD);
+
+ GET_TIME((struct timeval *)(temp+block_size*found+4),time_ref);
+
+ COPY_MEMORY(key,temp+block_size*found,4);
+
+ return TME_TRUE;
+ }
+
+}
+
+uint32 bucket_lookup_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref)
+{
+ RECORD *records=(RECORD*)data->lut_base_address;
+
+ if ((data->key_len!=1)&& /*16 bit value*/
+ (data->key_len!=2)) /*32 bit value*/
+ return TME_ERROR;
+
+ if(data->key_len==2)
+ {
+ uint32 start,stop;
+ uint8 *tmp;
+
+ start=SW_ULONG_AT(key,0);
+ stop=SW_ULONG_AT(key,4);
+
+ if (start>stop)
+ return TME_ERROR;
+ if (data->filled_entries>0)
+ {
+ tmp=mem_ex->buffer+SW_ULONG_AT(&records[data->filled_entries-1].block,0);
+ /*check if it is coherent with the previous block*/
+ if (SW_ULONG_AT(tmp,4)>=start)
+ return TME_ERROR;
+ }
+
+ if (data->filled_blocks==data->shared_memory_blocks)
+ return TME_ERROR;
+
+ if (data->filled_entries==data->lut_entries)
+ return TME_ERROR;
+
+ tmp=data->shared_memory_base_address+data->block_size*data->filled_blocks;
+
+ COPY_MEMORY(tmp,key,8);
+
+ SW_ULONG_ASSIGN(&records[data->filled_entries].block,tmp-mem_ex->buffer);
+ SW_ULONG_ASSIGN(&records[data->filled_entries].exec_fcn,data->default_exec);
+
+ GET_TIME((struct timeval *)(tmp+8),time_ref);
+
+ data->filled_blocks++;
+ data->filled_entries++;
+
+ return TME_TRUE;
+ }
+ else
+ {
+ uint16 start,stop;
+ uint8 *tmp;
+
+ start=SW_USHORT_AT(key,0);
+ stop=SW_USHORT_AT(key,2);
+
+ if (start>stop)
+ return TME_ERROR;
+ if (data->filled_entries>0)
+ {
+ tmp=mem_ex->buffer+SW_ULONG_AT(&records[data->filled_entries-1].block,0);
+ /*check if it is coherent with the previous block*/
+ if (SW_USHORT_AT(tmp,2)>=start)
+ return TME_ERROR;
+ }
+
+ if (data->filled_blocks==data->shared_memory_blocks)
+ return TME_ERROR;
+
+ if (data->filled_entries==data->lut_entries)
+ return TME_ERROR;
+
+ tmp=mem_ex->buffer+SW_ULONG_AT(&records[data->filled_entries].block,0);
+
+ COPY_MEMORY(tmp,key,4);
+
+ SW_ULONG_ASSIGN(&records[data->filled_entries].block,tmp-mem_ex->buffer);
+ SW_ULONG_ASSIGN(&records[data->filled_entries].exec_fcn,data->default_exec);
+
+ GET_TIME((struct timeval *)(tmp+4),time_ref);
+
+ data->filled_blocks++;
+ data->filled_entries++;
+
+ return TME_TRUE;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __bucket_lookup
+#define __bucket_lookup
+#ifdef WIN32
+#include "tme.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#else
+#include <tme/tme.h>
+#endif
+
+#endif
+
+#define BUCKET_LOOKUP_INSERT 0x00000011
+uint32 bucket_lookup_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref);
+#define BUCKET_LOOKUP 0x00000010
+uint32 bucket_lookup(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref);
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef WIN32
+#include "tme.h"
+#include "count_packets.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#include <net/tme/count_packets.h>
+#else
+#include <tme/tme.h>
+#include <tme/count_packets.h>
+#endif
+
+#endif
+
+
+
+uint32 count_packets(uint8 *block, uint32 pkt_size, TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data)
+{
+
+ c_p_data *counters=(c_p_data*)(block+data->key_len*4);
+
+ counters->bytes+=pkt_size;
+ counters->packets++;
+
+ return TME_SUCCESS;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __count_packets
+#define __count_packets
+
+#ifdef WIN32
+#include "tme.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#else
+#include <tme/tme.h>
+#endif
+
+#endif
+
+typedef struct __c_p_data
+{
+ struct timeval timestamp;
+ uint64 packets;
+ uint64 bytes;
+}
+ c_p_data;
+
+#define COUNT_PACKETS 0x00000000
+uint32 count_packets(uint8 *block, uint32 pkt_size, TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data);
+
+#endif
+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef __DEBUG_INCLUDE
+#define __DEBUG_INCLUDE
#if DBG
#define IF_INIT_LOUD(A)
#endif
+
+#endif /*#define __DEBUG_INCLUDE*/
--- /dev/null
+/*
+ * Copyright (c) 1999, 2000
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef _MSC_VER
+#include "stdarg.h"
+#include "ntddk.h"
+#include "ntiologc.h"
+#include "ndis.h"
+#else
+#include <ddk/ntddk.h>
+#include <net/ndis.h>
+#endif
+
+#include "debug.h"
+#include "packet.h"
+#include "win_bpf.h"
+
+//-------------------------------------------------------------------
+
+NTSTATUS
+NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append)
+{
+ NTSTATUS ntStatus;
+ IO_STATUS_BLOCK IoStatus;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PWCHAR PathPrefix;
+ USHORT PathLen;
+ UNICODE_STRING FullFileName;
+ ULONG FullFileNameLength;
+ PDEVICE_OBJECT fsdDevice;
+
+ FILE_STANDARD_INFORMATION StandardInfo;
+
+ IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");)
+
+ if(fileName->Buffer[0] == L'\\' &&
+ fileName->Buffer[1] == L'?' &&
+ fileName->Buffer[2] == L'?' &&
+ fileName->Buffer[3] == L'\\'
+ ){
+ PathLen = 0;
+ }
+ else{
+ PathPrefix = L"\\??\\";
+ PathLen = 8;
+ }
+
+ // Insert the correct path prefix.
+ FullFileNameLength = PathLen + fileName->MaximumLength;
+
+ FullFileName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
+ FullFileNameLength,
+ '0DWA');
+
+ if (FullFileName.Buffer == NULL) {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ return ntStatus;
+ }
+
+ FullFileName.Length = PathLen;
+ FullFileName.MaximumLength = (USHORT)FullFileNameLength;
+
+ if(PathLen)
+ RtlMoveMemory (FullFileName.Buffer, PathPrefix, PathLen);
+
+ RtlAppendUnicodeStringToString (&FullFileName, fileName);
+
+ IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName);)
+
+ InitializeObjectAttributes ( &ObjectAttributes,
+ &FullFileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ // Create the dump file
+ ntStatus = ZwCreateFile( &Open->DumpFileHandle,
+ SYNCHRONIZE | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ (Append)?FILE_OPEN_IF:FILE_SUPERSEDE,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0 );
+
+ if ( !NT_SUCCESS( ntStatus ) )
+ {
+ IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus);)
+
+ ExFreePool(FullFileName.Buffer);
+ Open->DumpFileHandle=NULL;
+ ntStatus = STATUS_NO_SUCH_FILE;
+ return ntStatus;
+ }
+
+ ExFreePool(FullFileName.Buffer);
+
+ ntStatus = ObReferenceObjectByHandle(Open->DumpFileHandle,
+ FILE_WRITE_ACCESS,
+#ifndef __GNUC__
+ *IoFileObjectType,
+#else
+ IoFileObjectType,
+#endif
+ KernelMode,
+ &Open->DumpFileObject,
+ 0);
+
+ if ( !NT_SUCCESS( ntStatus ) )
+ {
+ IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus);)
+
+ ZwClose( Open->DumpFileHandle );
+ Open->DumpFileHandle=NULL;
+
+ ntStatus = STATUS_NO_SUCH_FILE;
+ return ntStatus;
+ }
+
+ fsdDevice = IoGetRelatedDeviceObject(Open->DumpFileObject);
+
+ IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus);)
+
+ return ntStatus;
+}
+
+//-------------------------------------------------------------------
+
+NTSTATUS
+NPF_StartDump(POPEN_INSTANCE Open)
+{
+ NTSTATUS ntStatus;
+ struct packet_file_header hdr;
+ IO_STATUS_BLOCK IoStatus;
+ NDIS_REQUEST pRequest;
+ ULONG MediaType;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ IF_LOUD(DbgPrint("NPF: StartDump.\n");)
+
+ // Init the file header
+ hdr.magic = TCPDUMP_MAGIC;
+ hdr.version_major = PCAP_VERSION_MAJOR;
+ hdr.version_minor = PCAP_VERSION_MINOR;
+ hdr.thiszone = 0; /*Currently not set*/
+ hdr.snaplen = 1514;
+ hdr.sigfigs = 0;
+
+ // Detect the medium type
+ switch (Open->Medium){
+
+ case NdisMediumWan:
+ hdr.linktype = DLT_EN10MB;
+ break;
+
+ case NdisMedium802_3:
+ hdr.linktype = DLT_EN10MB;
+ break;
+
+ case NdisMediumFddi:
+ hdr.linktype = DLT_FDDI;
+ break;
+
+ case NdisMedium802_5:
+ hdr.linktype = DLT_IEEE802;
+ break;
+
+ case NdisMediumArcnet878_2:
+ hdr.linktype = DLT_ARCNET;
+ break;
+
+ case NdisMediumAtm:
+ hdr.linktype = DLT_ATM_RFC1483;
+ break;
+
+ default:
+ hdr.linktype = DLT_EN10MB;
+ }
+
+ // Write the header.
+ // We can use ZwWriteFile because we are in the context of the application
+ ntStatus = ZwWriteFile(Open->DumpFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ &hdr,
+ sizeof(hdr),
+ NULL,
+ NULL );
+
+
+ if ( !NT_SUCCESS( ntStatus ) )
+ {
+ IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus);)
+
+ ZwClose( Open->DumpFileHandle );
+ Open->DumpFileHandle=NULL;
+
+ ntStatus = STATUS_NO_SUCH_FILE;
+ return ntStatus;
+ }
+
+ Open->DumpOffset.QuadPart=24;
+
+ ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle,
+ THREAD_ALL_ACCESS,
+ (ACCESS_MASK)0L,
+ 0,
+ 0,
+ NPF_DumpThread,
+ Open);
+
+ if ( !NT_SUCCESS( ntStatus ) )
+ {
+ IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
+
+ ZwClose( Open->DumpFileHandle );
+ Open->DumpFileHandle=NULL;
+
+ return ntStatus;
+ }
+#ifndef __GNUC__
+ ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle,
+ THREAD_ALL_ACCESS,
+ NULL,
+ KernelMode,
+ &Open->DumpThreadObject,
+ 0);
+#else
+#endif
+ if ( !NT_SUCCESS( ntStatus ) )
+ {
+ IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
+
+ ObDereferenceObject(Open->DumpFileObject);
+ ZwClose( Open->DumpFileHandle );
+ Open->DumpFileHandle=NULL;
+
+ return ntStatus;
+ }
+
+
+ return ntStatus;
+
+}
+
+//-------------------------------------------------------------------
+// Dump Thread
+//-------------------------------------------------------------------
+
+VOID NPF_DumpThread(POPEN_INSTANCE Open)
+{
+ ULONG FrozenNic;
+
+ IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%0x\n",Open);)
+
+ while(TRUE){
+
+ // Wait until some packets arrive or the timeout expires
+ NdisWaitEvent(&Open->DumpEvent, 5000);
+
+ IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");)
+
+ if(Open->DumpLimitReached ||
+ Open->BufSize==0){ // BufSize=0 means that this instance was closed, or that the buffer is too
+ // small for any capture. In both cases it is better to end the dump
+
+ IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");)
+ IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open->DumpOffset.QuadPart);)
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+ return;
+ }
+
+ NdisResetEvent(&Open->DumpEvent);
+
+ // Write the content of the buffer to the file
+ if(NPF_SaveCurrentBuffer(Open) != STATUS_SUCCESS){
+ PsTerminateSystemThread(STATUS_SUCCESS);
+ return;
+ }
+
+ }
+
+}
+
+//-------------------------------------------------------------------
+
+NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open)
+{
+ UINT Thead;
+ UINT Ttail;
+ UINT TLastByte;
+ PUCHAR CurrBuff;
+ NTSTATUS ntStatus;
+ IO_STATUS_BLOCK IoStatus;
+ PMDL lMdl;
+ UINT SizeToDump;
+
+
+ Thead=Open->Bhead;
+ Ttail=Open->Btail;
+ TLastByte=Open->BLastByte;
+
+ IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");)
+
+ // Get the address of the buffer
+ CurrBuff=Open->Buffer;
+ //
+ // Fill the application buffer
+ //
+ if( Ttail < Thead )
+ {
+ if(Open->MaxDumpBytes &&
+ (UINT)Open->DumpOffset.QuadPart + GetBuffOccupation(Open) > Open->MaxDumpBytes)
+ {
+ // Size limit reached
+ UINT PktLen;
+
+ SizeToDump = 0;
+
+ // Scan the buffer to detect the exact amount of data to save
+ while(TRUE){
+ PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
+
+ if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
+ break;
+
+ SizeToDump += PktLen;
+ }
+
+ }
+ else
+ SizeToDump = TLastByte-Thead;
+
+ lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
+ if (lMdl == NULL)
+ {
+ // No memory: stop dump
+ IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ MmBuildMdlForNonPagedPool(lMdl);
+
+ // Write to disk
+ NPF_WriteDumpFile(Open->DumpFileObject,
+ &Open->DumpOffset,
+ SizeToDump,
+ lMdl,
+ &IoStatus);
+
+ IoFreeMdl(lMdl);
+
+ if(!NT_SUCCESS(IoStatus.Status)){
+ // Error
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if(SizeToDump != TLastByte-Thead){
+ // Size limit reached.
+ Open->DumpLimitReached = TRUE;
+
+ // Awake the application
+ KeSetEvent(Open->ReadEvent,0,FALSE);
+
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // Update the packet buffer
+ Open->DumpOffset.QuadPart+=(TLastByte-Thead);
+ Open->BLastByte=Ttail;
+ Open->Bhead=0;
+ }
+
+ if( Ttail > Thead ){
+
+ if(Open->MaxDumpBytes &&
+ (UINT)Open->DumpOffset.QuadPart + GetBuffOccupation(Open) > Open->MaxDumpBytes)
+ {
+ // Size limit reached
+ UINT PktLen;
+
+ SizeToDump = 0;
+
+ // Scan the buffer to detect the exact amount of data to save
+ while(Thead + SizeToDump < Ttail){
+
+ PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
+
+ if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
+ break;
+
+ SizeToDump += PktLen;
+ }
+
+ }
+ else
+ SizeToDump = Ttail-Thead;
+
+ lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
+ if (lMdl == NULL)
+ {
+ // No memory: stop dump
+ IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ MmBuildMdlForNonPagedPool(lMdl);
+
+ // Write to disk
+ NPF_WriteDumpFile(Open->DumpFileObject,
+ &Open->DumpOffset,
+ SizeToDump,
+ lMdl,
+ &IoStatus);
+
+ IoFreeMdl(lMdl);
+
+ if(!NT_SUCCESS(IoStatus.Status)){
+ // Error
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if(SizeToDump != Ttail-Thead){
+ // Size limit reached.
+ Open->DumpLimitReached = TRUE;
+
+ // Awake the application
+ KeSetEvent(Open->ReadEvent,0,FALSE);
+
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // Update the packet buffer
+ Open->DumpOffset.QuadPart+=(Ttail-Thead);
+ Open->Bhead=Ttail;
+
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//-------------------------------------------------------------------
+
+NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){
+ NTSTATUS ntStatus;
+ IO_STATUS_BLOCK IoStatus;
+ PMDL WriteMdl;
+ PUCHAR VMBuff;
+ UINT VMBufLen;
+
+
+ IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
+ IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);)
+
+DbgPrint("1\n");
+ // Consistency check
+ if(Open->DumpFileHandle == NULL)
+ return STATUS_UNSUCCESSFUL;
+
+DbgPrint("2\n");
+ ZwClose( Open->DumpFileHandle );
+
+ ObDereferenceObject(Open->DumpFileObject);
+/*
+ if(Open->DumpLimitReached == TRUE)
+ // Limit already reached: don't save the rest of the buffer.
+ return STATUS_SUCCESS;
+*/
+DbgPrint("3\n");
+
+ NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE);
+
+ // Flush the buffer to file
+ NPF_SaveCurrentBuffer(Open);
+
+ // Close The file
+ ObDereferenceObject(Open->DumpFileObject);
+ ZwClose( Open->DumpFileHandle );
+
+ Open->DumpFileHandle = NULL;
+
+ ObDereferenceObject(Open->DumpFileObject);
+
+ return STATUS_SUCCESS;
+}
+
+//-------------------------------------------------------------------
+
+static NTSTATUS PacketDumpCompletion(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context)
+{
+
+ // Copy the status information back into the "user" IOSB
+ *Irp->UserIosb = Irp->IoStatus;
+
+ // Wake up the mainline code
+ KeSetEvent(Irp->UserEvent, 0, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+//-------------------------------------------------------------------
+
+VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER Offset,
+ ULONG Length,
+ PMDL Mdl,
+ PIO_STATUS_BLOCK IoStatusBlock)
+{
+ PIRP irp;
+ KEVENT event;
+ PIO_STACK_LOCATION ioStackLocation;
+ PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject);
+ NTSTATUS Status;
+
+ // Set up the event we'll use
+ KeInitializeEvent(&event, SynchronizationEvent, FALSE);
+
+ // Allocate and build the IRP we'll be sending to the FSD
+ irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
+
+ if (!irp) {
+ // Allocation failed, presumably due to memory allocation failure
+ IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoStatusBlock->Information = 0;
+
+ return;
+ }
+
+ irp->MdlAddress = Mdl;
+ irp->UserEvent = &event;
+ irp->UserIosb = IoStatusBlock;
+ irp->Tail.Overlay.Thread = PsGetCurrentThread();
+ irp->Tail.Overlay.OriginalFileObject= FileObject;
+ irp->RequestorMode = KernelMode;
+
+ // Indicate that this is a WRITE operation
+ irp->Flags = IRP_WRITE_OPERATION;
+
+ // Set up the next I/O stack location
+ ioStackLocation = IoGetNextIrpStackLocation(irp);
+ ioStackLocation->MajorFunction = IRP_MJ_WRITE;
+ ioStackLocation->MinorFunction = 0;
+ ioStackLocation->DeviceObject = fsdDevice;
+ ioStackLocation->FileObject = FileObject;
+ IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE);
+ ioStackLocation->Parameters.Write.Length = Length;
+ ioStackLocation->Parameters.Write.ByteOffset = *Offset;
+
+
+ // Send it on. Ignore the return code
+ (void) IoCallDriver(fsdDevice, irp);
+
+ // Wait for the I/O to complete.
+ KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
+
+ // Free the IRP now that we are done with it
+ IoFreeIrp(irp);
+
+ return;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef WIN32
+#include "tme.h"
+#include "functions.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#include <net/bpf.h>
+#include <net/tme/functions.h>
+#else
+#include <tme/tme.h>
+#include <bpf.h>
+#include <tme/functions.h>
+#endif
+
+#endif
+
+
+
+lut_fcn lut_fcn_mapper(uint32 index)
+{
+
+ switch (index)
+ {
+ case NORMAL_LUT_W_INSERT:
+ return (lut_fcn) normal_lut_w_insert;
+
+ case NORMAL_LUT_WO_INSERT:
+ return (lut_fcn) normal_lut_wo_insert;
+
+ case BUCKET_LOOKUP:
+ return (lut_fcn) bucket_lookup;
+
+ case BUCKET_LOOKUP_INSERT:
+ return (lut_fcn) bucket_lookup_insert;
+
+ default:
+ return NULL;
+ }
+
+ return NULL;
+
+}
+
+exec_fcn exec_fcn_mapper(uint32 index)
+{
+ switch (index)
+ {
+ case COUNT_PACKETS:
+ return (exec_fcn) count_packets;
+
+ case TCP_SESSION:
+ return (exec_fcn) tcp_session;
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __FUNCTIONS
+#define __FUNCTIONS
+
+#ifdef WIN32
+#include "tme.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#else
+#include <tme/tme.h>
+#endif
+
+#endif
+/*function mappers */
+
+lut_fcn lut_fcn_mapper(uint32 index);
+exec_fcn exec_fcn_mapper(uint32 index);
+
+/* lookup functions */
+
+#ifdef WIN32
+#include "bucket_lookup.h"
+#include "normal_lookup.h"
+#endif
+
+#ifdef __FreeBSD__
+#include <net/tme/bucket_lookup.h>
+#include <net/tme/normal_lookup.h>
+#endif
+
+/* execution functions */
+
+#ifdef WIN32
+#include "count_packets.h"
+#include "tcp_session.h"
+#endif
+
+#ifdef __FreeBSD__
+#include <net/tme/count_packets.h>
+#include <ne/tme/tcp_session.h>
+#endif
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2002
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef _MSC_VER
+#include "stdarg.h"
+#include "ntddk.h"
+#include "ntiologc.h"
+#include "ndis.h"
+#else
+#include <ddk/ntddk.h>
+#include <net/ndis.h>
+#endif
+
+#include "packet.h"
+#include "win_bpf.h"
+
+emit_func emitm;
+
+//
+// emit routine to update the jump table
+//
+void emit_lenght(binary_stream *stream, ULONG value, UINT len)
+{
+ (stream->refs)[stream->bpf_pc]+=len;
+ stream->cur_ip+=len;
+}
+
+//
+// emit routine to output the actual binary code
+//
+void emit_code(binary_stream *stream, ULONG value, UINT len)
+{
+
+ switch (len){
+
+ case 1:
+ stream->ibuf[stream->cur_ip]=(UCHAR)value;
+ stream->cur_ip++;
+ break;
+
+ case 2:
+ *((USHORT*)(stream->ibuf+stream->cur_ip))=(USHORT)value;
+ stream->cur_ip+=2;
+ break;
+
+ case 4:
+ *((ULONG*)(stream->ibuf+stream->cur_ip))=value;
+ stream->cur_ip+=4;
+ break;
+
+ default:;
+
+ }
+
+ return;
+
+}
+
+//
+// Function that does the real stuff
+//
+BPF_filter_function BPFtoX86(struct bpf_insn *prog, UINT nins, INT *mem)
+{
+ struct bpf_insn *ins;
+ UINT i, pass;
+ binary_stream stream;
+
+
+ // Allocate the reference table for the jumps
+#ifdef NTKERNEL
+ stream.refs=(UINT *)ExAllocatePoolWithTag(NonPagedPool, (nins + 1)*sizeof(UINT), '0JWA');
+#else
+ stream.refs=(UINT *)malloc((nins + 1)*sizeof(UINT));
+#endif
+ if(stream.refs==NULL)
+ {
+ return NULL;
+ }
+
+ // Reset the reference table
+ for(i=0; i< nins + 1; i++)
+ stream.refs[i]=0;
+
+ stream.cur_ip=0;
+ stream.bpf_pc=0;
+
+ // the first pass will emit the lengths of the instructions
+ // to create the reference table
+ emitm=emit_lenght;
+
+ for(pass=0;;){
+
+ ins = prog;
+
+ /* create the procedure header */
+ PUSH(EBP)
+ MOVrd(EBP,ESP)
+ PUSH(EBX)
+ PUSH(ECX)
+ PUSH(EDX)
+ PUSH(ESI)
+ PUSH(EDI)
+ MOVodd(EBX, EBP, 8)
+
+ for(i=0;i<nins;i++){
+
+ stream.bpf_pc++;
+
+ switch (ins->code) {
+
+ default:
+
+ return NULL;
+
+ case BPF_RET|BPF_K:
+
+ MOVid(EAX,ins->k)
+ POP(EDI)
+ POP(ESI)
+ POP(EDX)
+ POP(ECX)
+ POP(EBX)
+ POP(EBP)
+ RET()
+
+ break;
+
+
+ case BPF_RET|BPF_A:
+
+ POP(EDI)
+ POP(ESI)
+ POP(EDX)
+ POP(ECX)
+ POP(EBX)
+ POP(EBP)
+ RET()
+
+ break;
+
+
+ case BPF_LD|BPF_W|BPF_ABS:
+
+ MOVid(ECX,ins->k)
+ MOVrd(ESI,ECX)
+ ADDib(ECX,sizeof(INT))
+ CMPodd(ECX, EBP, 0x10)
+ JLEb(12)
+ POP(EDI)
+ POP(ESI)
+ POP(EDX)
+ POP(ECX)
+ POP(EBX)
+ POP(EBP)
+ MOVid(EAX,0) //this can be optimized with xor eax,eax
+ RET()
+ MOVobd(EAX, EBX, ESI)
+ BSWAP(EAX)
+
+ break;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+
+ MOVid(ECX,ins->k)
+ MOVrd(ESI,ECX)
+ ADDib(ECX,sizeof(SHORT))
+ CMPodd(ECX, EBP, 0x10)
+ JLEb(12)
+ POP(EDI)
+ POP(ESI)
+ POP(EDX)
+ POP(ECX)
+ POP(EBX)
+ POP(EBP)
+ MOVid(EAX,0)
+ RET()
+ MOVid(EAX,0)
+ MOVobw(AX, EBX, ESI)
+ SWAP_AX()
+
+ break;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+
+ MOVid(ECX,ins->k)
+ CMPodd(ECX, EBP, 0x10)
+ JLEb(12)
+ POP(EDI)
+ POP(ESI)
+ POP(EDX)
+ POP(ECX)
+ POP(EBX)
+ POP(EBP)
+ MOVid(EAX,0)
+ RET()
+ MOVid(EAX,0)
+ MOVobb(AL,EBX,ECX)
+
+ break;
+
+ case BPF_LD|BPF_W|BPF_LEN:
+
+ MOVodd(EAX, EBP, 0xc)
+
+ break;
+
+ case BPF_LDX|BPF_W|BPF_LEN:
+
+ MOVodd(EDX, EBP, 0xc)
+
+ break;
+
+ case BPF_LD|BPF_W|BPF_IND:
+
+ MOVid(ECX,ins->k)
+ ADDrd(ECX,EDX)
+ MOVrd(ESI,ECX)
+ ADDib(ECX,sizeof(INT))
+ CMPodd(ECX, EBP, 0x10)
+ JLEb(12)
+ POP(EDI)
+ POP(ESI)
+ POP(EDX)
+ POP(ECX)
+ POP(EBX)
+ POP(EBP)
+ MOVid(EAX,0)
+ RET()
+ MOVobd(EAX, EBX, ESI)
+ BSWAP(EAX)
+
+ break;
+
+ case BPF_LD|BPF_H|BPF_IND:
+
+ MOVid(ECX,ins->k)
+ ADDrd(ECX,EDX)
+ MOVrd(ESI,ECX)
+ ADDib(ECX,sizeof(SHORT))
+ CMPodd(ECX, EBP, 0x10)
+ JLEb(12)
+ POP(EDI)
+ POP(ESI)
+ POP(EDX)
+ POP(ECX)
+ POP(EBX)
+ POP(EBP)
+ MOVid(EAX,0)
+ RET()
+ MOVid(EAX,0)
+ MOVobw(AX, EBX, ESI)
+ SWAP_AX()
+
+ break;
+
+ case BPF_LD|BPF_B|BPF_IND:
+
+ MOVid(ECX,ins->k)
+ ADDrd(ECX,EDX)
+ CMPodd(ECX, EBP, 0x10)
+ JLEb(12)
+ POP(EDI)
+ POP(ESI)
+ POP(EDX)
+ POP(ECX)
+ POP(EBX)
+ POP(EBP)
+ MOVid(EAX,0)
+ RET()
+ MOVid(EAX,0)
+ MOVobb(AL,EBX,ECX)
+
+ break;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+
+ MOVid(ECX,ins->k)
+ CMPodd(ECX, EBP, 0x10)
+ JLEb(12)
+ POP(EDI)
+ POP(ESI)
+ POP(EDX)
+ POP(ECX)
+ POP(EBX)
+ POP(EBP)
+ MOVid(EAX,0)
+ RET()
+ MOVid(EDX,0)
+ MOVobb(DL,EBX,ECX)
+ ANDib(DL, 0xf)
+ SHLib(EDX, 2)
+
+ break;
+
+ case BPF_LD|BPF_IMM:
+
+ MOVid(EAX,ins->k)
+
+ break;
+
+ case BPF_LDX|BPF_IMM:
+
+ MOVid(EDX,ins->k)
+
+ break;
+
+ case BPF_LD|BPF_MEM:
+
+ MOVid(ECX,(INT)mem)
+ MOVid(ESI,ins->k*4)
+ MOVobd(EAX, ECX, ESI)
+
+ break;
+
+ case BPF_LDX|BPF_MEM:
+
+ MOVid(ECX,(INT)mem)
+ MOVid(ESI,ins->k*4)
+ MOVobd(EDX, ECX, ESI)
+
+ break;
+
+ case BPF_ST:
+
+ // XXX: this command and the following could be optimized if the previous
+ // instruction was already of this type
+ MOVid(ECX,(INT)mem)
+ MOVid(ESI,ins->k*4)
+ MOVomd(ECX, ESI, EAX)
+
+ break;
+
+ case BPF_STX:
+
+ MOVid(ECX,(INT)mem)
+ MOVid(ESI,ins->k*4)
+ MOVomd(ECX, ESI, EDX)
+ break;
+
+ case BPF_JMP|BPF_JA:
+
+ JMP(stream.refs[stream.bpf_pc+ins->k]-stream.refs[stream.bpf_pc])
+
+ break;
+
+ case BPF_JMP|BPF_JGT|BPF_K:
+
+ CMPid(EAX, ins->k)
+ JG(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5) // 5 is the size of the following JMP
+ JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
+ break;
+
+ case BPF_JMP|BPF_JGE|BPF_K:
+
+ CMPid(EAX, ins->k)
+ JGE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5)
+ JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
+
+ break;
+
+ case BPF_JMP|BPF_JEQ|BPF_K:
+
+ CMPid(EAX, ins->k)
+ JE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5)
+ JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
+
+ break;
+
+ case BPF_JMP|BPF_JSET|BPF_K:
+
+ MOVrd(ECX,EAX)
+ ANDid(ECX,ins->k)
+ JE(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]+5)
+ JMP(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc])
+
+ break;
+
+ case BPF_JMP|BPF_JGT|BPF_X:
+
+ CMPrd(EAX, EDX)
+ JA(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5)
+ JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
+ break;
+
+ case BPF_JMP|BPF_JGE|BPF_X:
+
+ CMPrd(EAX, EDX)
+ JAE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5)
+ JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
+
+ break;
+
+ case BPF_JMP|BPF_JEQ|BPF_X:
+
+ CMPrd(EAX, EDX)
+ JE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5)
+ JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
+
+ break;
+
+ case BPF_JMP|BPF_JSET|BPF_X:
+
+ MOVrd(ECX,EAX)
+ ANDrd(ECX,EDX)
+ JE(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]+5)
+ JMP(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc])
+
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+
+ ADDrd(EAX,EDX)
+
+ break;
+
+ case BPF_ALU|BPF_SUB|BPF_X:
+
+ SUBrd(EAX,EDX)
+
+ break;
+
+ case BPF_ALU|BPF_MUL|BPF_X:
+
+ MOVrd(ECX,EDX)
+ MULrd(EDX)
+ MOVrd(EDX,ECX)
+ break;
+
+ case BPF_ALU|BPF_DIV|BPF_X:
+
+ CMPid(EDX, 0)
+ JNEb(12)
+ POP(EDI)
+ POP(ESI)
+ POP(EDX)
+ POP(ECX)
+ POP(EBX)
+ POP(EBP)
+ MOVid(EAX,0)
+ RET()
+ MOVrd(ECX,EDX)
+ MOVid(EDX,0)
+ DIVrd(ECX)
+ MOVrd(EDX,ECX)
+
+ break;
+
+ case BPF_ALU|BPF_AND|BPF_X:
+
+ ANDrd(EAX,EDX)
+
+ break;
+
+ case BPF_ALU|BPF_OR|BPF_X:
+
+ ORrd(EAX,EDX)
+
+ break;
+
+ case BPF_ALU|BPF_LSH|BPF_X:
+
+ MOVrd(ECX,EDX)
+ SHL_CLrb(EAX)
+
+ break;
+
+ case BPF_ALU|BPF_RSH|BPF_X:
+
+ MOVrd(ECX,EDX)
+ SHR_CLrb(EAX)
+
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+
+ ADD_EAXi(ins->k)
+
+ break;
+
+ case BPF_ALU|BPF_SUB|BPF_K:
+
+ SUB_EAXi(ins->k)
+
+ break;
+
+ case BPF_ALU|BPF_MUL|BPF_K:
+
+ MOVrd(ECX,EDX)
+ MOVid(EDX,ins->k)
+ MULrd(EDX)
+ MOVrd(EDX,ECX)
+
+ break;
+
+ case BPF_ALU|BPF_DIV|BPF_K:
+
+ MOVrd(ECX,EDX)
+ MOVid(EDX,0)
+ MOVid(ESI,ins->k)
+ DIVrd(ESI)
+ MOVrd(EDX,ECX)
+
+ break;
+
+ case BPF_ALU|BPF_AND|BPF_K:
+
+ ANDid(EAX, ins->k)
+
+ break;
+
+ case BPF_ALU|BPF_OR|BPF_K:
+
+ ORid(EAX, ins->k)
+
+ break;
+
+ case BPF_ALU|BPF_LSH|BPF_K:
+
+ SHLib(EAX, (ins->k) & 255)
+
+ break;
+
+ case BPF_ALU|BPF_RSH|BPF_K:
+
+ SHRib(EAX, (ins->k) & 255)
+
+ break;
+
+ case BPF_ALU|BPF_NEG:
+
+ NEGd(EAX)
+
+ break;
+
+ case BPF_MISC|BPF_TAX:
+
+ MOVrd(EDX,EAX)
+
+ break;
+
+ case BPF_MISC|BPF_TXA:
+
+ MOVrd(EAX,EDX)
+
+ break;
+
+
+
+ }
+
+ ins++;
+ }
+
+ pass++;
+ if(pass == 2) break;
+
+#ifdef NTKERNEL
+ stream.ibuf=(CHAR*)ExAllocatePoolWithTag(NonPagedPool, stream.cur_ip, '1JWA');
+#else
+ stream.ibuf=(CHAR*)malloc(stream.cur_ip);
+#endif
+ if(stream.ibuf==NULL)
+ {
+#ifdef NTKERNEL
+ ExFreePool(stream.refs);
+#else
+ free(stream.refs);
+#endif
+ return NULL;
+ }
+
+ // modify the reference table to contain the offsets and not the lengths of the instructions
+ for(i=1; i< nins + 1; i++)
+ stream.refs[i]+=stream.refs[i-1];
+
+ // Reset the counters
+ stream.cur_ip=0;
+ stream.bpf_pc=0;
+ // the second pass creates the actual code
+ emitm=emit_code;
+
+ }
+
+ // the reference table is needed only during compilation, now we can free it
+#ifdef NTKERNEL
+ ExFreePool(stream.refs);
+#else
+ free(stream.refs);
+#endif
+ return (BPF_filter_function)stream.ibuf;
+
+}
+
+
+JIT_BPF_Filter* BPF_jitter(struct bpf_insn *fp, INT nins)
+{
+ JIT_BPF_Filter *Filter;
+
+
+ // Allocate the filter structure
+#ifdef NTKERNEL
+ Filter=(struct JIT_BPF_Filter*)ExAllocatePoolWithTag(NonPagedPool, sizeof(struct JIT_BPF_Filter), '2JWA');
+#else
+ Filter=(struct JIT_BPF_Filter*)malloc(sizeof(struct JIT_BPF_Filter));
+#endif
+ if(Filter==NULL)
+ {
+ return NULL;
+ }
+
+ // Allocate the filter's memory
+#ifdef NTKERNEL
+ Filter->mem=(INT*)ExAllocatePoolWithTag(NonPagedPool, BPF_MEMWORDS*sizeof(INT), '3JWA');
+#else
+ Filter->mem=(INT*)malloc(BPF_MEMWORDS*sizeof(INT));
+#endif
+ if(Filter->mem==NULL)
+ {
+#ifdef NTKERNEL
+ ExFreePool(Filter);
+#else
+ free(Filter);
+#endif
+ return NULL;
+ }
+
+ // Create the binary
+ if((Filter->Function = BPFtoX86(fp, nins, Filter->mem))==NULL)
+ {
+#ifdef NTKERNEL
+ ExFreePool(Filter->mem);
+ ExFreePool(Filter);
+#else
+ free(Filter->mem);
+ free(Filter);
+
+ return NULL;
+#endif
+ }
+
+ return Filter;
+
+}
+
+//////////////////////////////////////////////////////////////
+
+void BPF_Destroy_JIT_Filter(JIT_BPF_Filter *Filter){
+
+#ifdef NTKERNEL
+ ExFreePool(Filter->mem);
+ ExFreePool(Filter->Function);
+ ExFreePool(Filter);
+#else
+ free(Filter->mem);
+ free(Filter->Function);
+ free(Filter);
+#endif
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2002
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/** @ingroup NPF
+ * @{
+ */
+
+/** @defgroup NPF_include NPF structures and definitions
+ * @{
+ */
+
+//
+// Registers
+//
+#define EAX 0
+#define ECX 1
+#define EDX 2
+#define EBX 3
+#define ESP 4
+#define EBP 5
+#define ESI 6
+#define EDI 7
+
+#define AX 0
+#define CX 1
+#define DX 2
+#define BX 3
+#define SP 4
+#define BP 5
+#define SI 6
+#define DI 7
+
+#define AL 0
+#define CL 1
+#define DL 2
+#define BL 3
+
+/*! \brief A stream of X86 binary code.*/
+typedef struct binary_stream{
+ INT cur_ip; ///< Current X86 instruction pointer.
+ INT bpf_pc; ///< Current BPF instruction pointer, i.e. position in the BPF program reached by the jitter.
+ PCHAR ibuf; ///< Instruction buffer, contains the X86 generated code.
+ PUINT refs; ///< Jumps reference table.
+}binary_stream;
+
+
+/*! \brief Prototype of a filtering function created by the jitter.
+
+ The syntax and the meaning of the parameters is analogous to the one of bpf_filter(). Notice that the filter
+ is not among the parameters, because it is hardwired in the function.
+*/
+typedef UINT (*BPF_filter_function)( binary_stream *, ULONG, UINT);
+
+/*! \brief Prototype of the emit functions.
+
+ Different emit functions are used to create the reference table and to generate the actual filtering code.
+ This allows to have simpler instruction macros.
+ The first parameter is the stream that will receive the data. The secon one is a variable containing
+ the data, the third one is the length, that can be 1,2 or 4 since it is possible to emit a byte, a short
+ or a work at a time.
+*/
+typedef void (*emit_func)(binary_stream *stream, ULONG value, UINT n);
+
+/*! \brief Structure describing a x86 filtering program created by the jitter.*/
+typedef struct JIT_BPF_Filter{
+ BPF_filter_function Function; ///< The x86 filtering binary, in the form of a BPF_filter_function.
+ PINT mem;
+}
+JIT_BPF_Filter;
+
+
+
+
+/**************************/
+/* X86 INSTRUCTION MACROS */
+/**************************/
+
+/// mov r32,i32
+#define MOVid(r32, i32) \
+ emitm(&stream, 11 << 4 | 1 << 3 | r32 & 0x7, 1); emitm(&stream, i32, 4);
+
+/// mov dr32,sr32
+#define MOVrd(dr32, sr32) \
+ emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);
+
+/// mov dr32,sr32[off]
+#define MOVodd(dr32, sr32, off) \
+ emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); \
+ emitm(&stream, 1 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);\
+ emitm(&stream, off, 1);
+
+/// mov dr32,sr32[or32]
+#define MOVobd(dr32, sr32, or32) \
+ emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); \
+ emitm(&stream, (dr32 & 0x7) << 3 | 4 , 1);\
+ emitm(&stream, (or32 & 0x7) << 3 | (sr32 & 0x7) , 1);
+
+/// mov dr16,sr32[or32]
+#define MOVobw(dr32, sr32, or32) \
+ emitm(&stream, 0x66, 1); \
+ emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); \
+ emitm(&stream, (dr32 & 0x7) << 3 | 4 , 1);\
+ emitm(&stream, (or32 & 0x7) << 3 | (sr32 & 0x7) , 1);
+
+/// mov dr8,sr32[or32]
+#define MOVobb(dr8, sr32, or32) \
+ emitm(&stream, 0x8a, 1); \
+ emitm(&stream, (dr8 & 0x7) << 3 | 4 , 1);\
+ emitm(&stream, (or32 & 0x7) << 3 | (sr32 & 0x7) , 1);
+
+/// mov [dr32][or32],sr32
+#define MOVomd(dr32, or32, sr32) \
+ emitm(&stream, 0x89, 1); \
+ emitm(&stream, (sr32 & 0x7) << 3 | 4 , 1);\
+ emitm(&stream, (or32 & 0x7) << 3 | (dr32 & 0x7) , 1);
+
+/// bswap dr32
+#define BSWAP(dr32) \
+ emitm(&stream, 0xf, 1); \
+ emitm(&stream, 0x19 << 3 | dr32 , 1);
+
+/// xchg al,ah
+#define SWAP_AX() \
+ emitm(&stream, 0x86, 1); \
+ emitm(&stream, 0xc4 , 1);
+
+/// push r32
+#define PUSH(r32) \
+ emitm(&stream, 5 << 4 | 0 << 3 | r32 & 0x7, 1);
+
+/// pop r32
+#define POP(r32) \
+ emitm(&stream, 5 << 4 | 1 << 3 | r32 & 0x7, 1);
+
+/// ret
+#define RET() \
+ emitm(&stream, 12 << 4 | 0 << 3 | 3, 1);
+
+/// add dr32,sr32
+#define ADDrd(dr32, sr32) \
+ emitm(&stream, 0x03, 1);\
+ emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | (sr32 & 0x7), 1);
+
+/// add eax,i32
+#define ADD_EAXi(i32) \
+ emitm(&stream, 0x05, 1);\
+ emitm(&stream, i32, 4);
+
+/// add r32,i32
+#define ADDid(r32, i32) \
+ emitm(&stream, 0x81, 1);\
+ emitm(&stream, 24 << 3 | r32, 1);\
+ emitm(&stream, i32, 4);
+
+/// add r32,i8
+#define ADDib(r32, i8) \
+ emitm(&stream, 0x83, 1);\
+ emitm(&stream, 24 << 3 | r32, 1);\
+ emitm(&stream, i8, 1);
+
+/// sub dr32,sr32
+#define SUBrd(dr32, sr32) \
+ emitm(&stream, 0x2b, 1);\
+ emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | (sr32 & 0x7), 1);
+
+/// sub eax,i32
+#define SUB_EAXi(i32) \
+ emitm(&stream, 0x2d, 1);\
+ emitm(&stream, i32, 4);
+
+/// mul r32
+#define MULrd(r32) \
+ emitm(&stream, 0xf7, 1);\
+ emitm(&stream, 7 << 5 | (r32 & 0x7), 1);
+
+/// div r32
+#define DIVrd(r32) \
+ emitm(&stream, 0xf7, 1);\
+ emitm(&stream, 15 << 4 | (r32 & 0x7), 1);
+
+/// and r8,i8
+#define ANDib(r8, i8) \
+ emitm(&stream, 0x80, 1);\
+ emitm(&stream, 7 << 5 | r8, 1);\
+ emitm(&stream, i8, 1);
+
+/// and r32,i32
+#define ANDid(r32, i32) \
+ if (r32 == EAX){ \
+ emitm(&stream, 0x25, 1);\
+ emitm(&stream, i32, 4);}\
+ else{ \
+ emitm(&stream, 0x81, 1);\
+ emitm(&stream, 7 << 5 | r32, 1);\
+ emitm(&stream, i32, 4);}
+
+/// and dr32,sr32
+#define ANDrd(dr32, sr32) \
+ emitm(&stream, 0x23, 1);\
+ emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);
+
+/// or dr32,sr32
+#define ORrd(dr32, sr32) \
+ emitm(&stream, 0x0b, 1);\
+ emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);
+
+/// or r32,i32
+#define ORid(r32, i32) \
+ if (r32 == EAX){ \
+ emitm(&stream, 0x0d, 1);\
+ emitm(&stream, i32, 4);}\
+ else{ \
+ emitm(&stream, 0x81, 1);\
+ emitm(&stream, 25 << 3 | r32, 1);\
+ emitm(&stream, i32, 4);}
+
+/// shl r32,i8
+#define SHLib(r32, i8) \
+ emitm(&stream, 0xc1, 1);\
+ emitm(&stream, 7 << 5 | r32 & 0x7, 1);\
+ emitm(&stream, i8, 1);
+
+/// shl dr32,cl
+#define SHL_CLrb(dr32) \
+ emitm(&stream, 0xd3, 1);\
+ emitm(&stream, 7 << 5 | dr32 & 0x7, 1);
+
+/// shr r32,i8
+#define SHRib(r32, i8) \
+ emitm(&stream, 0xc1, 1);\
+ emitm(&stream, 29 << 3 | r32 & 0x7, 1);\
+ emitm(&stream, i8, 1);
+
+/// shr dr32,cl
+#define SHR_CLrb(dr32) \
+ emitm(&stream, 0xd3, 1);\
+ emitm(&stream, 29 << 3 | dr32 & 0x7, 1);
+
+/// neg r32
+#define NEGd(r32) \
+ emitm(&stream, 0xf7, 1);\
+ emitm(&stream, 27 << 3 | r32 & 0x7, 1);
+
+/// cmp dr32,sr32[off]
+#define CMPodd(dr32, sr32, off) \
+ emitm(&stream, 3 << 4 | 3 | 1 << 3, 1); \
+ emitm(&stream, 1 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);\
+ emitm(&stream, off, 1);
+
+/// cmp dr32,sr32
+#define CMPrd(dr32, sr32) \
+ emitm(&stream, 0x3b, 1); \
+ emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);
+
+/// cmp dr32,i32
+#define CMPid(dr32, i32) \
+ if (dr32 == EAX){ \
+ emitm(&stream, 0x3d, 1); \
+ emitm(&stream, i32, 4);} \
+ else{ \
+ emitm(&stream, 0x81, 1); \
+ emitm(&stream, 0x1f << 3 | (dr32 & 0x7), 1);\
+ emitm(&stream, i32, 4);}
+
+/// jne off32
+#define JNEb(off8) \
+ emitm(&stream, 0x75, 1);\
+ emitm(&stream, off8, 1);
+
+/// je off32
+#define JE(off32) \
+ emitm(&stream, 0x0f, 1);\
+ emitm(&stream, 0x84, 1);\
+ emitm(&stream, off32, 4);
+
+/// jle off32
+#define JLE(off32) \
+ emitm(&stream, 0x0f, 1);\
+ emitm(&stream, 0x8e, 1);\
+ emitm(&stream, off32, 4);
+
+/// jle off8
+#define JLEb(off8) \
+ emitm(&stream, 0x7e, 1);\
+ emitm(&stream, off8, 1);
+
+/// ja off32
+#define JA(off32) \
+ emitm(&stream, 0x0f, 1);\
+ emitm(&stream, 0x87, 1);\
+ emitm(&stream, off32, 4);
+
+/// jae off32
+#define JAE(off32) \
+ emitm(&stream, 0x0f, 1);\
+ emitm(&stream, 0x83, 1);\
+ emitm(&stream, off32, 4);
+
+/// jg off32
+#define JG(off32) \
+ emitm(&stream, 0x0f, 1);\
+ emitm(&stream, 0x8f, 1);\
+ emitm(&stream, off32, 4);
+
+/// jge off32
+#define JGE(off32) \
+ emitm(&stream, 0x0f, 1);\
+ emitm(&stream, 0x8d, 1);\
+ emitm(&stream, off32, 4);
+
+/// jmp off32
+#define JMP(off32) \
+ emitm(&stream, 0xe9, 1);\
+ emitm(&stream, off32, 4);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**************************/
+/* Prototypes */
+/**************************/
+
+/** @ingroup NPF
+ * @{
+ */
+
+/** @defgroup NPF_code NPF functions
+ * @{
+ */
+
+/*!
+ \brief BPF jitter, builds an x86 function from a BPF program.
+ \param fp The BPF pseudo-assembly filter that will be translated into x86 code.
+ \param nins Number of instructions of the input filter.
+ \return The JIT_BPF_Filter structure containing the x86 filtering binary.
+
+ BPF_jitter allocates the buffers for the new native filter and then translates the program pointed by fp
+ calling BPFtoX86().
+*/
+JIT_BPF_Filter* BPF_jitter(struct bpf_insn *fp, INT nins);
+
+/*!
+ \brief Translates a set of BPF instructions in a set of x86 ones.
+ \param ins Pointer to the BPF instructions that will be translated into x86 code.
+ \param nins Number of instructions to translate.
+ \param mem Memory used by the x86 function to emulate the RAM of the BPF pseudo processor.
+ \return The x86 filtering function.
+
+ This function does the hard work for the JIT compilation. It takes a group of BPF pseudo instructions and
+ through the instruction macros defined in jitter.h it is able to create an function directly executable
+ by NPF.
+*/
+BPF_filter_function BPFtoX86(struct bpf_insn *prog, UINT nins, INT *mem);
+/*!
+ \brief Deletes a filtering function that was previously created by BPF_jitter().
+ \param Filter The filter to destroy.
+
+ This function frees the variuos buffers (code, memory, etc.) associated with a filtering function.
+*/
+void BPF_Destroy_JIT_Filter(JIT_BPF_Filter *Filter);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "tme.h"
+#include "memory_t.h"
+
+
+int32 SW_LONG_AT(void *b, uint32 c)
+{
+ return ((int32)*((uint8 *)b+c)<<24|
+ (int32)*((uint8 *)b+c+1)<<16|
+ (int32)*((uint8 *)b+c+2)<<8|
+ (int32)*((uint8 *)b+c+3)<<0);
+}
+
+uint32 SW_ULONG_AT(void *b, uint32 c)
+{
+ return ((uint32)*((uint8 *)b+c)<<24|
+ (uint32)*((uint8 *)b+c+1)<<16|
+ (uint32)*((uint8 *)b+c+2)<<8|
+ (uint32)*((uint8 *)b+c+3)<<0);
+}
+
+int16 SW_SHORT_AT(void *b, uint32 os)
+{
+ return ((int16)
+ ((int16)*((uint8 *)b+os+0)<<8|
+ (int16)*((uint8 *)b+os+1)<<0));
+}
+
+uint16 SW_USHORT_AT(void *b, uint32 os)
+{
+ return ((uint16)
+ ((uint16)*((uint8 *)b+os+0)<<8|
+ (uint16)*((uint8 *)b+os+1)<<0));
+}
+
+VOID SW_ULONG_ASSIGN(void *dst, uint32 src)
+{
+ *((uint8*)dst+0)=*((uint8*)&src+3);
+ *((uint8*)dst+1)=*((uint8*)&src+2);
+ *((uint8*)dst+2)=*((uint8*)&src+1);
+ *((uint8*)dst+3)=*((uint8*)&src+0);
+
+}
+
+void assert(void* assert, const char* file, int line, void* msg) { };
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __memory_t
+#define __memory_t
+
+#define uint8 UCHAR
+#define int8 CHAR
+#define uint16 USHORT
+#define int16 SHORT
+#define uint32 ULONG
+#define int32 LONG
+#define uint64 ULONGLONG
+#define int64 LONGLONG
+
+/*memory type*/
+typedef struct __MEM_TYPE
+{
+ uint8 *buffer;
+ uint32 size;
+} MEM_TYPE, *PMEM_TYPE;
+
+#define LONG_AT(base,offset) (*(int32*)((uint8*)base+(uint32)offset))
+
+#define ULONG_AT(base,offset) (*(uint32*)((uint8*)base+(uint32)offset))
+
+#define SHORT_AT(base,offset) (*(int16*)((uint8*)base+(uint32)offset))
+
+#define USHORT_AT(base,offset) (*(uint16*)((uint8*)base+(uint32)offset))
+
+#ifdef __GNUC__
+
+int32 SW_LONG_AT(void *b, uint32 c);
+uint32 SW_ULONG_AT(void *b, uint32 c);
+int16 SW_SHORT_AT(void *b, uint32 os);
+uint16 SW_USHORT_AT(void *b, uint32 os);
+VOID SW_ULONG_ASSIGN(void *dst, uint32 src);
+
+#else /* __GNUC__ */
+
+__inline int32 SW_LONG_AT(void *b, uint32 c)
+{
+ return ((int32)*((uint8 *)b+c)<<24|
+ (int32)*((uint8 *)b+c+1)<<16|
+ (int32)*((uint8 *)b+c+2)<<8|
+ (int32)*((uint8 *)b+c+3)<<0);
+}
+
+__inline uint32 SW_ULONG_AT(void *b, uint32 c)
+{
+ return ((uint32)*((uint8 *)b+c)<<24|
+ (uint32)*((uint8 *)b+c+1)<<16|
+ (uint32)*((uint8 *)b+c+2)<<8|
+ (uint32)*((uint8 *)b+c+3)<<0);
+}
+
+__inline int16 SW_SHORT_AT(void *b, uint32 os)
+{
+ return ((int16)
+ ((int16)*((uint8 *)b+os+0)<<8|
+ (int16)*((uint8 *)b+os+1)<<0));
+}
+
+__inline uint16 SW_USHORT_AT(void *b, uint32 os)
+{
+ return ((uint16)
+ ((uint16)*((uint8 *)b+os+0)<<8|
+ (uint16)*((uint8 *)b+os+1)<<0));
+}
+
+__inline VOID SW_ULONG_ASSIGN(void *dst, uint32 src)
+{
+ *((uint8*)dst+0)=*((uint8*)&src+3);
+ *((uint8*)dst+1)=*((uint8*)&src+2);
+ *((uint8*)dst+2)=*((uint8*)&src+1);
+ *((uint8*)dst+3)=*((uint8*)&src+0);
+
+}
+
+#endif /* __GNUC__ */
+
+#ifdef WIN_NT_DRIVER
+
+#define ALLOCATE_MEMORY(dest,type,amount) \
+ (dest)=ExAllocatePool(NonPagedPool,sizeof(type)*(amount));
+#define ALLOCATE_ZERO_MEMORY(dest,type,amount) \
+ { \
+ (dest)=ExAllocatePool(NonPagedPool,sizeof(type)*(amount)); \
+ if ((dest)!=NULL) \
+ RtlZeroMemory((dest),sizeof(type)*(amount)); \
+ }
+
+#define FREE_MEMORY(dest) ExFreePool(dest);
+#define ZERO_MEMORY(dest,amount) RtlZeroMemory(dest,amount);
+#define COPY_MEMORY(dest,src,amount) RtlCopyMemory(dest,src,amount);
+
+#endif /*WIN_NT_DRIVER*/
+
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef WIN32
+#include "tme.h"
+#include "normal_lookup.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#include <net/tme/normal_lookup.h>
+#else
+#include <tme/tme.h>
+#include <tme/normal_lookup.h>
+#endif
+
+#endif
+
+
+/* lookup in the table, seen as an hash */
+/* if not found, inserts an element */
+/* returns TME_TRUE if the entry is found or created, */
+/* returns TME_FALSE if no more blocks are available */
+uint32 normal_lut_w_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref)
+{
+ uint32 i;
+ uint32 tocs=0;
+ uint32 *key32=(uint32*) key;
+ uint32 shrinked_key=0;
+ uint32 index;
+ RECORD *records=(RECORD*)data->lut_base_address;
+ uint8 *offset;
+ uint32 key_len=data->key_len;
+ /*the key is shrinked into a 32-bit value */
+ for (i=0; i<key_len;i++)
+ shrinked_key^=key32[i];
+ /*the first index in the table is calculated*/
+ index=shrinked_key % data->lut_entries;
+
+ while (tocs<=data->filled_entries)
+ {
+
+ if (records[index].block==0)
+ { /*creation of a new entry*/
+
+ if (data->filled_blocks==data->shared_memory_blocks)
+ {
+ /*no more free blocks*/
+ GET_TIME((struct timeval *)(data->shared_memory_base_address+4*key_len),time_ref);
+ data->last_found=NULL;
+ return TME_FALSE;
+ }
+
+ /*offset=absolute pointer to the block associated*/
+ /*with the newly created entry*/
+ offset=data->shared_memory_base_address+
+ data->block_size*data->filled_blocks;
+
+ /*copy the key in the block*/
+ COPY_MEMORY(offset,key32,key_len*4);
+ GET_TIME((struct timeval *)(offset+4*key_len),time_ref);
+ /*assign the block relative offset to the entry, in NBO*/
+ SW_ULONG_ASSIGN(&records[index].block,offset-mem_ex->buffer);
+
+ data->filled_blocks++;
+
+ /*assign the exec function ID to the entry, in NBO*/
+ SW_ULONG_ASSIGN(&records[index].exec_fcn,data->default_exec);
+ data->filled_entries++;
+
+ data->last_found=(uint8*)&records[index];
+
+ return TME_TRUE;
+ }
+ /*offset contains the absolute pointer to the block*/
+ /*associated with the current entry */
+ offset=mem_ex->buffer+SW_ULONG_AT(&records[index].block,0);
+
+ for (i=0; (i<key_len) && (key32[i]==ULONG_AT(offset,i*4)); i++);
+
+ if (i==key_len)
+ {
+ /*key in the block matches the one provided, right entry*/
+ GET_TIME((struct timeval *)(offset+4*key_len),time_ref);
+ data->last_found=(uint8*)&records[index];
+ return TME_TRUE;
+ }
+ else
+ {
+ /* wrong entry, rehashing */
+ if (IS_DELETABLE(offset+key_len*4,data))
+ {
+ ZERO_MEMORY(offset,data->block_size);
+ COPY_MEMORY(offset,key32,key_len*4);
+ SW_ULONG_ASSIGN(&records[index].exec_fcn,data->default_exec);
+ GET_TIME((struct timeval*)(offset+key_len*4),time_ref);
+ data->last_found=(uint8*)&records[index];
+ return TME_TRUE;
+ }
+ else
+ {
+ index=(index+data->rehashing_value) % data->lut_entries;
+ tocs++;
+ }
+ }
+ }
+
+ /* nothing found, last found= out of lut */
+ GET_TIME((struct timeval *)(data->shared_memory_base_address+4*key_len),time_ref);
+ data->last_found=NULL;
+ return TME_FALSE;
+
+}
+
+/* lookup in the table, seen as an hash */
+/* if not found, returns out of count entry index */
+/* returns TME_TRUE if the entry is found */
+/* returns TME_FALSE if the entry is not found */
+uint32 normal_lut_wo_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref)
+{
+ uint32 i;
+ uint32 tocs=0;
+ uint32 *key32=(uint32*) key;
+ uint32 shrinked_key=0;
+ uint32 index;
+ RECORD *records=(RECORD*)data->lut_base_address;
+ uint8 *offset;
+ uint32 key_len=data->key_len;
+ /*the key is shrinked into a 32-bit value */
+ for (i=0; i<key_len;i++)
+ shrinked_key^=key32[i];
+ /*the first index in the table is calculated*/
+ index=shrinked_key % data->lut_entries;
+
+ while (tocs<=data->filled_entries)
+ {
+
+ if (records[index].block==0)
+ { /*out of table, insertion is not allowed*/
+ GET_TIME((struct timeval *)(data->shared_memory_base_address+4*key_len),time_ref);
+ data->last_found=NULL;
+ return TME_FALSE;
+ }
+ /*offset contains the absolute pointer to the block*/
+ /*associated with the current entry */
+
+ offset=mem_ex->buffer+SW_ULONG_AT(&records[index].block,0);
+
+ for (i=0; (i<key_len) && (key32[i]==ULONG_AT(offset,i*4)); i++);
+
+ if (i==key_len)
+ {
+ /*key in the block matches the one provided, right entry*/
+ GET_TIME((struct timeval *)(offset+4*key_len),time_ref);
+ data->last_found=(uint8*)&records[index];
+ return TME_TRUE;
+ }
+ else
+ {
+ /*wrong entry, rehashing*/
+ index=(index+data->rehashing_value) % data->lut_entries;
+ tocs++;
+ }
+ }
+
+ /*nothing found, last found= out of lut*/
+ GET_TIME((struct timeval *)(data->shared_memory_base_address+4*key_len),time_ref);
+ data->last_found=NULL;
+ return TME_FALSE;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __normal_lookup
+#define __normal_lookup
+
+#ifdef WIN32
+#include "tme.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#else
+#include <tme/tme.h>
+#endif
+
+#endif
+
+#define NORMAL_LUT_W_INSERT 0x00000000
+uint32 normal_lut_w_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref);
+#define NORMAL_LUT_WO_INSERT 0x00000001
+uint32 normal_lut_wo_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref);
+#define DUMMY_INSERT 1234
+
+#endif
\ No newline at end of file
#include "ndis.h"
#else
#include <ddk/ntddk.h>
-//#include <net/miniport.h>
#include <net/ndis.h>
#endif
-
#include "debug.h"
#include "packet.h"
NdisMedium802_5
};
-ULONG NamedEventsCounter=0;
-
#define NUM_NDIS_MEDIA (sizeof MediumArray / sizeof MediumArray[0])
+ULONG NamedEventsCounter=0;
//Itoa. Replaces the buggy RtlIntegerToUnicodeString
void PacketItoa(UINT n,PUCHAR buf){
}
+/// Global start time. Used as an absolute reference for timestamp conversion.
+struct time_conv G_Start_Time = {
+ 0,
+ {0, 0},
+};
+
+UINT n_Opened_Instances = 0;
-NTSTATUS STDCALL
-PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+NDIS_SPIN_LOCK Opened_Instances_Lock;
+
+//-------------------------------------------------------------------
+
+NTSTATUS
+NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
NDIS_STATUS Status;
NDIS_STATUS ErrorStatus;
- UINT Medium;
UINT i;
PUCHAR tpointer;
PLIST_ENTRY PacketListEntry;
- LARGE_INTEGER TimeFreq;
- LARGE_INTEGER SystemTime;
- LARGE_INTEGER PTime;
PCHAR EvName;
- IF_LOUD(DbgPrint("Packet: OpenAdapter\n");)
+
+ IF_LOUD(DbgPrint("NPF: OpenAdapter\n");)
DeviceExtension = DeviceObject->DeviceExtension;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
- //
// allocate some memory for the open structure
- //
- Open=ExAllocatePool(NonPagedPool,sizeof(OPEN_INSTANCE));
+ Open=ExAllocatePoolWithTag(NonPagedPool, sizeof(OPEN_INSTANCE), '0OWA');
if (Open==NULL) {
- //
// no memory
- //
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
);
- EvName=ExAllocatePool(NonPagedPool, sizeof(L"\\BaseNamedObjects\\NPF0000000000") );
+ EvName=ExAllocatePoolWithTag(NonPagedPool, sizeof(L"\\BaseNamedObjects\\NPF0000000000"), '1OWA');
if (EvName==NULL) {
- //
// no memory
- //
ExFreePool(Open);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
- //
// Save or open here
- //
IrpSp->FileObject->FsContext=Open;
Open->DeviceExtension=DeviceExtension;
- //
// Save the Irp here for the completeion routine to retrieve
- //
Open->OpenCloseIrp=Irp;
- //
// Allocate a packet pool for our xmit and receive packets
- //
NdisAllocatePacketPool(
&Status,
&Open->PacketPool,
if (Status != NDIS_STATUS_SUCCESS) {
- IF_LOUD(DbgPrint("Packet: Failed to allocate packet pool\n");)
+ IF_LOUD(DbgPrint("NPF: Failed to allocate packet pool\n");)
ExFreePool(Open);
ExFreePool(EvName);
//Create the string containing the name of the read event
RtlInitUnicodeString(&Open->ReadEventName,(PCWSTR) EvName);
+
PacketItoa(NamedEventsCounter,(PUCHAR)(Open->ReadEventName.Buffer+21));
InterlockedIncrement(&NamedEventsCounter);
Open->ReadEvent=IoCreateNotificationEvent(&Open->ReadEventName,&Open->ReadEventHandle);
if(Open->ReadEvent==NULL){
ExFreePool(Open);
+ ExFreePool(EvName);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
KeClearEvent(Open->ReadEvent);
NdisInitializeEvent(&Open->WriteEvent);
NdisInitializeEvent(&Open->IOEvent);
+ NdisInitializeEvent(&Open->DumpEvent);
+ NdisInitializeEvent(&Open->IOEvent);
+ NdisAllocateSpinLock(&Open->machine_lock);
+
- //
// list to hold irp's want to reset the adapter
- //
InitializeListHead(&Open->ResetIrpList);
- //
- // Initialize list for holding pending read requests
- //
- KeInitializeSpinLock(&Open->RcvQSpinLock);
- InitializeListHead(&Open->RcvList);
-
- //
// Initialize the request list
- //
KeInitializeSpinLock(&Open->RequestSpinLock);
InitializeListHead(&Open->RequestList);
+
+ // Initializes the extended memory of the NPF machine
+ Open->mem_ex.buffer = ExAllocatePoolWithTag(NonPagedPool, DEFAULT_MEM_EX_SIZE, '2OWA');
+ if((Open->mem_ex.buffer) == NULL)
+ {
+ // no memory
+ ExFreePool(Open);
+ ExFreePool(EvName);
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ Open->mem_ex.size = DEFAULT_MEM_EX_SIZE;
+ RtlZeroMemory(Open->mem_ex.buffer, DEFAULT_MEM_EX_SIZE);
- // get the absolute value of the system boot time.
- PTime=KeQueryPerformanceCounter(&TimeFreq);
- KeQuerySystemTime(&SystemTime);
-#ifndef __NTDRIVER__ // robert
- Open->StartTime.QuadPart=(((SystemTime.QuadPart)%10000000)*TimeFreq.QuadPart)/10000000;
- SystemTime.QuadPart=SystemTime.QuadPart/10000000-11644473600;
-#endif
- Open->StartTime.QuadPart+=(SystemTime.QuadPart)*TimeFreq.QuadPart-PTime.QuadPart;
- //initalize the open instance
- Open->BufSize=0;
- Open->Buffer=NULL;
- Open->Bhead=0;
- Open->Btail=0;
- Open->BLastByte=0;
- Open->Dropped=0; //reset the dropped packets counter
- Open->Received=0; //reset the received packets counter
- Open->bpfprogram=NULL; //reset the filter
- Open->mode=MODE_CAPT;
- Open->Nbytes.QuadPart=0;
- Open->Npackets.QuadPart=0;
- Open->Nwrites=1;
- Open->Multiple_Write_Counter=0;
- Open->MinToCopy=0;
- Open->TimeOut.QuadPart=(LONGLONG)1;
- Open->Bound=TRUE;
+ //
+ // Initialize the open instance
+ //
+ Open->BufSize = 0;
+ Open->Buffer = NULL;
+ Open->Bhead = 0;
+ Open->Btail = 0;
+ Open->BLastByte = 0;
+ Open->Dropped = 0; //reset the dropped packets counter
+ Open->Received = 0; //reset the received packets counter
+ Open->Accepted = 0; //reset the accepted packets counter
+ Open->bpfprogram = NULL; //reset the filter
+ Open->mode = MODE_CAPT;
+ Open->Nbytes.QuadPart = 0;
+ Open->Npackets.QuadPart = 0;
+ Open->Nwrites = 1;
+ Open->Multiple_Write_Counter = 0;
+ Open->MinToCopy = 0;
+ Open->TimeOut.QuadPart = (LONGLONG)1;
+ Open->Bound = TRUE;
+ Open->DumpFileName.Buffer = NULL;
+ Open->DumpFileHandle = NULL;
+ Open->tme.active = TME_NONE_ACTIVE;
+ Open->DumpLimitReached = FALSE;
//allocate the spinlock for the statistic counters
NdisAllocateSpinLock(&Open->CountersLock);
}
-
+
IoMarkIrpPending(Irp);
-
//
// Try to open the MAC
//
- IF_LOUD(DbgPrint("Packet: Openinig the device %ws, BindingContext=%d\n",DeviceExtension->AdapterName.Buffer, Open);)
+ IF_LOUD(DbgPrint("NPF: Openinig the device %ws, BindingContext=%d\n",DeviceExtension->AdapterName.Buffer, Open);)
NdisOpenAdapter(
&Status,
&ErrorStatus,
&Open->AdapterHandle,
- &Medium,
+ &Open->Medium,
MediumArray,
NUM_NDIS_MEDIA,
DeviceExtension->NdisProtocolHandle,
0,
NULL);
- IF_LOUD(DbgPrint("Packet: Opened the device, Status=%x\n",Status);)
+ IF_LOUD(DbgPrint("NPF: Opened the device, Status=%x\n",Status);)
if (Status != NDIS_STATUS_PENDING)
{
- PacketOpenAdapterComplete(Open,Status,NDIS_STATUS_SUCCESS);
+ NPF_OpenAdapterComplete(Open,Status,NDIS_STATUS_SUCCESS);
}
return(STATUS_PENDING);
//-------------------------------------------------------------------
-VOID PacketOpenAdapterComplete(
+VOID NPF_OpenAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus)
PIRP Irp;
POPEN_INSTANCE Open;
- IF_LOUD(DbgPrint("Packet: OpenAdapterComplete\n");)
+ IF_LOUD(DbgPrint("NPF: OpenAdapterComplete\n");)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
if (Status != NDIS_STATUS_SUCCESS) {
- IF_LOUD(DbgPrint("Packet: OpenAdapterComplete-FAILURE\n");)
+ IF_LOUD(DbgPrint("NPF: OpenAdapterComplete-FAILURE\n");)
NdisFreePacketPool(Open->PacketPool);
+ //free mem_ex
+ Open->mem_ex.size = 0;
+ if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
+
ExFreePool(Open->ReadEventName.Buffer);
ExFreePool(Open);
}
+ else {
+ NdisAcquireSpinLock(&Opened_Instances_Lock);
+ n_Opened_Instances++;
+ NdisReleaseSpinLock(&Opened_Instances_Lock);
+
+ IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances);)
+
+ // Get the absolute value of the system boot time.
+ // This is used for timestamp conversion.
+ TIME_SYNCHRONIZE(&G_Start_Time);
+ }
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
//-------------------------------------------------------------------
-NTSTATUS STDCALL
-PacketClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
+NTSTATUS
+NPF_Close(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
POPEN_INSTANCE Open;
NDIS_STATUS Status;
PIO_STACK_LOCATION IrpSp;
+ LARGE_INTEGER ThreadDelay;
-
- IF_LOUD(DbgPrint("Packet: CloseAdapter\n");)
+ IF_LOUD(DbgPrint("NPF: CloseAdapter\n");)
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Open=IrpSp->FileObject->FsContext;
+ // Reset the buffer size. This tells the dump thread to stop.
+ Open->BufSize = 0;
+
if( Open->Bound == FALSE){
NdisWaitEvent(&Open->IOEvent,10000);
- //free the bpf program
- if(Open->bpfprogram!=NULL)ExFreePool(Open->bpfprogram);
-
+ // Free the filter if it's present
+ if(Open->bpfprogram != NULL)
+ ExFreePool(Open->bpfprogram);
+
+ // Free the jitted filter if it's present
+ if(Open->Filter != NULL)
+ BPF_Destroy_JIT_Filter(Open->Filter);
+
//free the buffer
Open->BufSize=0;
- if(Open->Buffer!=NULL)ExFreePool(Open->Buffer);
+ if(Open->Buffer != NULL)ExFreePool(Open->Buffer);
- NdisFreePacketPool(Open->PacketPool);
+ //free mem_ex
+ Open->mem_ex.size = 0;
+ if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
+ NdisFreePacketPool(Open->PacketPool);
+
+ // Free the string with the name of the dump file
+ if(Open->DumpFileName.Buffer!=NULL)
+ ExFreePool(Open->DumpFileName.Buffer);
+
ExFreePool(Open->ReadEventName.Buffer);
ExFreePool(Open);
return(STATUS_SUCCESS);
}
- // Eventually unfreeze PacketRead
- KeSetEvent(Open->ReadEvent,0,FALSE);
+ // Unfreeze the consumer
+ if(Open->mode & MODE_DUMP)
+ NdisSetEvent(&Open->DumpEvent);
+ else
+ KeSetEvent(Open->ReadEvent,0,FALSE);
+
+ // Save the IRP
+ Open->OpenCloseIrp = Irp;
+
+ IoMarkIrpPending(Irp);
+
+ // If this instance is in dump mode, complete the dump and close the file
+ if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL){
+#ifndef __GNUC__
+ NTSTATUS wres;
+
+ ThreadDelay.QuadPart = -50000000;
+ // Wait the completion of the thread
+ wres = KeWaitForSingleObject(Open->DumpThreadObject,
+ UserRequest,
+ KernelMode,
+ TRUE,
+ &ThreadDelay);
+
+ ObDereferenceObject(Open->DumpThreadObject);
+
+
+ // Flush and close the dump file
+ NPF_CloseDumpFile(Open);
+#endif
+ }
// Destroy the read Event
ZwClose(Open->ReadEventHandle);
- // save the IRP
- Open->OpenCloseIrp=Irp;
-
- IoMarkIrpPending(Irp);
-
- // close the adapter
+ // Close the adapter
NdisCloseAdapter(
&Status,
Open->AdapterHandle
);
-
+
if (Status != NDIS_STATUS_PENDING) {
- PacketCloseAdapterComplete(
+ NPF_CloseAdapterComplete(
Open,
Status
);
//-------------------------------------------------------------------
VOID
-PacketCloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status)
+NPF_CloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status)
{
POPEN_INSTANCE Open;
PIRP Irp;
- IF_LOUD(DbgPrint("Packet: CloseAdapterComplete\n");)
+ IF_LOUD(DbgPrint("NPF: CloseAdapterComplete\n");)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
// free the allocated structures only if the instance is still bound to the adapter
if(Open->Bound == TRUE){
- //free the bpf program
- if(Open->bpfprogram!=NULL)ExFreePool(Open->bpfprogram);
+ // Free the filter if it's present
+ if(Open->bpfprogram != NULL)
+ ExFreePool(Open->bpfprogram);
+
+ // Free the jitted filter if it's present
+ if(Open->Filter != NULL)
+ BPF_Destroy_JIT_Filter(Open->Filter);
//free the buffer
- Open->BufSize=0;
+ Open->BufSize = 0;
if(Open->Buffer!=NULL)ExFreePool(Open->Buffer);
+ //free mem_ex
+ Open->mem_ex.size = 0;
+ if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
+
NdisFreePacketPool(Open->PacketPool);
Irp=Open->OpenCloseIrp;
+ // Free the string with the name of the dump file
+ if(Open->DumpFileName.Buffer!=NULL)
+ ExFreePool(Open->DumpFileName.Buffer);
+
ExFreePool(Open->ReadEventName.Buffer);
ExFreePool(Open);
else
NdisSetEvent(&Open->IOEvent);
+ // Decrease the counter of open instances
+ NdisAcquireSpinLock(&Opened_Instances_Lock);
+ n_Opened_Instances--;
+ NdisReleaseSpinLock(&Opened_Instances_Lock);
+
+ IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances);)
+
+ if(n_Opened_Instances == 0){
+ // Force a synchronization at the next NPF_Open().
+ // This hopefully avoids the synchronization issues caused by hibernation or standby.
+ TIME_DESYNCHRONIZE(&G_Start_Time);
+ }
return;
}
+//-------------------------------------------------------------------
+
+#ifdef NDIS50
+NDIS_STATUS
+NPF_PowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent)
+{
+ IF_LOUD(DbgPrint("NPF: PowerChange\n");)
+
+ TIME_DESYNCHRONIZE(&G_Start_Time);
+
+ TIME_SYNCHRONIZE(&G_Start_Time);
+
+ return STATUS_SUCCESS;
+}
+#endif
//-------------------------------------------------------------------
VOID
-PacketBindAdapter(
+NPF_BindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING DeviceName,
IN PVOID SystemSpecific2
)
{
- IF_LOUD(DbgPrint("Packet: PacketBindAdapter\n");)
+ IF_LOUD(DbgPrint("NPF: NPF_BindAdapter\n");)
}
//-------------------------------------------------------------------
VOID
-PacketUnbindAdapter(
+NPF_UnbindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE UnbindContext
POPEN_INSTANCE Open =(POPEN_INSTANCE)ProtocolBindingContext;
NDIS_STATUS lStatus;
- IF_LOUD(DbgPrint("Packet: PacketUNBindAdapter\n");)
+ IF_LOUD(DbgPrint("NPF: NPF_UnbindAdapter\n");)
+
+ // Reset the buffer size. This tells the dump thread to stop.
+ Open->BufSize=0;
NdisResetEvent(&Open->IOEvent);
InterlockedExchange( (PLONG) &Open->Bound, FALSE );
// Awake a possible pending read on this instance
- KeSetEvent(Open->ReadEvent,0,FALSE);
+ if(Open->mode & MODE_DUMP)
+ NdisSetEvent(&Open->DumpEvent);
+ else
+ KeSetEvent(Open->ReadEvent,0,FALSE);
+
+ // If this instance is in dump mode, complete the dump and close the file
+ if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL)
+ NPF_CloseDumpFile(Open);
// Destroy the read Event
ZwClose(Open->ReadEventHandle);
if (lStatus != NDIS_STATUS_PENDING) {
- PacketCloseAdapterComplete(
+ NPF_CloseAdapterComplete(
Open,
lStatus
);
//-------------------------------------------------------------------
VOID
-PacketResetComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status)
+NPF_ResetComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status)
{
POPEN_INSTANCE Open;
PLIST_ENTRY ResetListEntry;
- IF_LOUD(DbgPrint("Packet: PacketResetComplte\n");)
+ IF_LOUD(DbgPrint("NPF: PacketResetComplte\n");)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
- IF_LOUD(DbgPrint("Packet: PacketResetComplte exit\n");)
+ IF_LOUD(DbgPrint("NPF: PacketResetComplte exit\n");)
return;
#include "ntiologc.h"
#include "ndis.h"
#else
-//#include <net/miniport.h>
#include <ddk/ntddk.h>
-//#include "<ntiologc.h>"
#include <net/ndis.h>
#endif
#include "ntddpack.h"
+
#include "debug.h"
#include "packet.h"
+#include "win_bpf.h"
+#include "win_bpf_filter_init.h"
+#include "tme.h"
#if DBG
-//
// Declare the global debug flag for this driver.
-//
-
-ULONG PacketDebugFlag = PACKET_DEBUG_LOUD;
+//ULONG PacketDebugFlag = PACKET_DEBUG_LOUD;
+ULONG PacketDebugFlag = PACKET_DEBUG_LOUD + PACKET_DEBUG_VERY_LOUD + PACKET_DEBUG_INIT;
#endif
-
PDEVICE_EXTENSION GlobalDeviceExtension;
////////////////////////////////////////////////////////////////////////////////
#endif // ROBERTS_PATCH
////////////////////////////////////////////////////////////////////////////////
//
-// Strings
+// Global strings
//
-
-NDIS_STRING PacketName = NDIS_STRING_CONST("Packet_");
+NDIS_STRING NPF_Prefix = NDIS_STRING_CONST("NPF_");
NDIS_STRING devicePrefix = NDIS_STRING_CONST("\\Device\\");
NDIS_STRING symbolicLinkPrefix = NDIS_STRING_CONST("\\DosDevices\\");
NDIS_STRING tcpLinkageKeyName = NDIS_STRING_CONST("\\Registry\\Machine\\System"
L"\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}");
NDIS_STRING bindValueName = NDIS_STRING_CONST("Bind");
-//
-// Global variable that points to the names of the bound adapters
-//
+
+/// Global variable that points to the names of the bound adapters
WCHAR* bindP = NULL;
+extern struct time_conv G_Start_Time; // from openclos.c
+
+extern NDIS_SPIN_LOCK Opened_Instances_Lock;
+
//
// Packet Driver's entry routine.
//
-
-//NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
-// PUNICODE_STRING RegistryPath)
-
NTSTATUS
-STDCALL
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
- NTSTATUS Status = STATUS_SUCCESS;
- NDIS_STATUS NdisStatus = STATUS_SUCCESS;
+
NDIS_PROTOCOL_CHARACTERISTICS ProtocolChar;
UNICODE_STRING MacDriverName;
UNICODE_STRING UnicodeDeviceName;
PDEVICE_OBJECT DeviceObject = NULL;
PDEVICE_EXTENSION DeviceExtension = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
NTSTATUS ErrorCode = STATUS_SUCCESS;
NDIS_STRING ProtoName = NDIS_STRING_CONST("PacketDriver");
ULONG DevicesCreated=0;
PKEY_VALUE_PARTIAL_INFORMATION tcpBindingsP;
UNICODE_STRING macName;
- //This driver at the moment works only on single processor machines
+ // This driver at the moment works only on single processor machines
if(NdisSystemProcessorCount() != 1){
return STATUS_IMAGE_MP_UP_MISMATCH;
}
+
IF_LOUD(DbgPrint("\n\nPacket: DriverEntry\n");)
+
RtlZeroMemory(&ProtocolChar,sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+
#ifdef NDIS50
ProtocolChar.MajorNdisVersion = 5;
#else
ProtocolChar.MajorNdisVersion = 3;
#endif
ProtocolChar.MinorNdisVersion = 0;
-// ProtocolChar.Reserved = 0;
- ProtocolChar.OpenAdapterCompleteHandler = PacketOpenAdapterComplete;
- ProtocolChar.CloseAdapterCompleteHandler = PacketCloseAdapterComplete;
- ProtocolChar.u2.SendCompleteHandler = PacketSendComplete;
- ProtocolChar.u3.TransferDataCompleteHandler = PacketTransferDataComplete;
- ProtocolChar.ResetCompleteHandler = PacketResetComplete;
- ProtocolChar.RequestCompleteHandler = PacketRequestComplete;
- ProtocolChar.u4.ReceiveHandler = Packet_tap;
- ProtocolChar.ReceiveCompleteHandler = PacketReceiveComplete;
- ProtocolChar.StatusHandler = PacketStatus;
- ProtocolChar.StatusCompleteHandler = PacketStatusComplete;
+#ifndef __GNUC__
+ ProtocolChar.Reserved = 0;
+#endif
+ ProtocolChar.OpenAdapterCompleteHandler = NPF_OpenAdapterComplete;
+ ProtocolChar.CloseAdapterCompleteHandler = NPF_CloseAdapterComplete;
+#ifndef __GNUC__
+ ProtocolChar.SendCompleteHandler = NPF_SendComplete;
+ ProtocolChar.TransferDataCompleteHandler = NPF_TransferDataComplete;
+#endif
+ ProtocolChar.ResetCompleteHandler = NPF_ResetComplete;
+ ProtocolChar.RequestCompleteHandler = NPF_RequestComplete;
+#ifndef __GNUC__
+ ProtocolChar.ReceiveHandler = NPF_tap;
+#endif
+ ProtocolChar.ReceiveCompleteHandler = NPF_ReceiveComplete;
+ ProtocolChar.StatusHandler = NPF_Status;
+ ProtocolChar.StatusCompleteHandler = NPF_StatusComplete;
#ifdef NDIS50
- ProtocolChar.BindAdapterHandler = PacketBindAdapter;
- ProtocolChar.UnbindAdapterHandler = PacketUnbindAdapter;
+ ProtocolChar.BindAdapterHandler = NPF_BindAdapter;
+ ProtocolChar.UnbindAdapterHandler = NPF_UnbindAdapter;
+ ProtocolChar.PnPEventHandler = NPF_PowerChange;
ProtocolChar.ReceivePacketHandler = NULL;
#endif
ProtocolChar.Name = ProtoName;
-/*
-NdisRegisterProtocol(
- OUT PNDIS_STATUS Status,
- OUT PNDIS_HANDLE NdisProtocolHandle,
- IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
- IN UINT CharacteristicsLength);
- */
+
NdisRegisterProtocol(
- &NdisStatus,
+ &Status,
&NdisProtocolHandle,
&ProtocolChar,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
- if (NdisStatus != NDIS_STATUS_SUCCESS) {
- IF_LOUD(DbgPrint("Packet: Failed to register protocol with NDIS\n");)
- return NdisStatus;
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ IF_LOUD(DbgPrint("NPF: Failed to register protocol with NDIS\n");)
+
+ return Status;
+
}
- //
+
+ NdisAllocateSpinLock(&Opened_Instances_Lock);
+
// Set up the device driver entry points.
- //
- DriverObject->MajorFunction[IRP_MJ_CREATE] = PacketOpen;
- DriverObject->MajorFunction[IRP_MJ_CLOSE] = PacketClose;
- DriverObject->MajorFunction[IRP_MJ_READ] = PacketRead;
- DriverObject->MajorFunction[IRP_MJ_WRITE] = PacketWrite;
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PacketIoControl;
- DriverObject->DriverUnload = PacketUnload;
- //
- // Get the name of the Packet driver and the name of the MAC driver
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = NPF_Open;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = NPF_Close;
+ DriverObject->MajorFunction[IRP_MJ_READ] = NPF_Read;
+ DriverObject->MajorFunction[IRP_MJ_WRITE] = NPF_Write;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NPF_IoControl;
+ DriverObject->DriverUnload = NPF_Unload;
+
+ // Get the name of the Packet driver and the name of the NIC driver
// to bind to from the registry
- //
- Status=PacketReadRegistry(
+ Status=NPF_ReadRegistry(
&BindString,
&ExportString,
RegistryPath
);
+
if (Status != STATUS_SUCCESS) {
+
IF_LOUD(DbgPrint("Trying dynamic binding\n");)
+
bindP = getAdaptersList();
+
if (bindP == NULL) {
IF_LOUD(DbgPrint("Adapters not found in the registry, try to copy the bindings of TCP-IP.\n");)
+
tcpBindingsP = getTcpBindings();
+
if (tcpBindingsP == NULL){
IF_LOUD(DbgPrint("TCP-IP not found, quitting.\n");)
goto RegistryError;
}
+
bindP = (WCHAR*)tcpBindingsP;
bindT = (WCHAR*)(tcpBindingsP->Data);
} else {
bindT = bindP;
+
}
+
for (; *bindT != UNICODE_NULL; bindT += (macName.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR)) {
RtlInitUnicodeString(&macName, bindT);
createDevice(DriverObject, &macName, NdisProtocolHandle);
}
+
return STATUS_SUCCESS;
+
}
+
BindStringSave = BindString;
ExportStringSave = ExportString;
+
+
//
// create a device object for each entry
//
&MacDriverName,
BindString
);
+
RtlInitUnicodeString(
&UnicodeDeviceName,
ExportString
);
+
//
// Advance to the next string of the MULTI_SZ string
//
BindString += (MacDriverName.Length+sizeof(UNICODE_NULL))/sizeof(WCHAR);
+
ExportString += (UnicodeDeviceName.Length+sizeof(UNICODE_NULL))/sizeof(WCHAR);
- IF_LOUD(DbgPrint("Packet: DeviceName=%ws MacName=%ws\n",UnicodeDeviceName.Buffer,MacDriverName.Buffer);)
+
+ IF_LOUD(DbgPrint("NPF: DeviceName=%ws MacName=%ws\n",UnicodeDeviceName.Buffer,MacDriverName.Buffer);)
+
//
// Create the device object
//
FALSE,
&DeviceObject
);
+
if (Status != STATUS_SUCCESS) {
- IF_LOUD(DbgPrint("Packet: IoCreateDevice() failed:\n");)
+ IF_LOUD(DbgPrint("NPF: IoCreateDevice() failed:\n");)
+
break;
}
+
DevicesCreated++;
+
+
DeviceObject->Flags |= DO_DIRECT_IO;
DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
DeviceExtension->DeviceObject = DeviceObject;
+
//
// Save the the name of the MAC driver to open in the Device Extension
//
+
DeviceExtension->AdapterName=MacDriverName;
+
if (DevicesCreated == 1) {
+
DeviceExtension->BindString = NULL;
DeviceExtension->ExportString = NULL;
}
+
+
DeviceExtension->NdisProtocolHandle=NdisProtocolHandle;
+
+
}
+
if (DevicesCreated > 0) {
//
- // Managed to create at least on device.
+ // Managed to create at least one device.
//
+ IF_LOUD(DbgPrint("NPF: Managed to create at least one device.\n");)
return STATUS_SUCCESS;
}
+
+
+
ExFreePool(BindStringSave);
ExFreePool(ExportStringSave);
+
RegistryError:
- NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
+ IF_LOUD(DbgPrint("NPF: RegistryError: calling NdisDeregisterProtocol()\n");)
+ NdisDeregisterProtocol(
+ &Status,
+ NdisProtocolHandle
+ );
+
Status=STATUS_UNSUCCESSFUL;
+
return(Status);
+
}
-//
-// Return the list of the MACs from SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}
-//
+//-------------------------------------------------------------------
PWCHAR getAdaptersList(void)
{
- PWCHAR DeviceNames = (PWCHAR) ExAllocatePool(PagedPool, 4096);
PKEY_VALUE_PARTIAL_INFORMATION result = NULL;
OBJECT_ATTRIBUTES objAttrs;
NTSTATUS status;
HANDLE keyHandle;
UINT BufPos=0;
+ PWCHAR DeviceNames = (PWCHAR) ExAllocatePoolWithTag(PagedPool, 4096, '0PWA');
+
if (DeviceNames == NULL) {
IF_LOUD(DbgPrint("Unable the allocate the buffer for the list of the network adapters\n");)
return NULL;
}
+
InitializeObjectAttributes(&objAttrs, &AdapterListKey,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwOpenKey(&keyHandle, KEY_READ, &objAttrs);
KEY_VALUE_PARTIAL_INFORMATION valueInfo;
CHAR AdapInfo[1024];
UINT i=0;
+
IF_LOUD(DbgPrint("getAdaptersList: scanning the list of the adapters in the registry, DeviceNames=%x\n",DeviceNames);)
+
// Scan the list of the devices
- while((status=ZwEnumerateKey(keyHandle,i,KeyBasicInformation,AdapInfo,sizeof(AdapInfo),&resultLength))==STATUS_SUCCESS) {
+ while((status=ZwEnumerateKey(keyHandle,i,KeyBasicInformation,AdapInfo,sizeof(AdapInfo),&resultLength))==STATUS_SUCCESS) {
WCHAR ExportKeyName [512];
PWCHAR ExportKeyPrefix = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
UINT ExportKeyPrefixSize = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}");
HANDLE ExportKeyHandle;
KEY_VALUE_PARTIAL_INFORMATION valueInfo;
ULONG resultLength;
+
RtlCopyMemory(ExportKeyName,
ExportKeyPrefix,
ExportKeyPrefixSize);
+
RtlCopyMemory((PCHAR)ExportKeyName+ExportKeyPrefixSize,
tInfo->Name,
tInfo->NameLength+2);
+
RtlCopyMemory((PCHAR)ExportKeyName+ExportKeyPrefixSize+tInfo->NameLength,
LinkageKeyPrefix,
LinkageKeyPrefixSize);
+
IF_LOUD(DbgPrint("Key name=%ws\n", ExportKeyName);)
+
RtlInitUnicodeString(&AdapterKeyName, ExportKeyName);
+
InitializeObjectAttributes(&objAttrs, &AdapterKeyName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
+
status=ZwOpenKey(&ExportKeyHandle,KEY_READ,&objAttrs);
+
if (!NT_SUCCESS(status)) {
DbgPrint("OpenKey Failed, %d!\n",status);
i++;
continue;
}
+
status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey,
KeyValuePartialInformation, &valueInfo,
sizeof(valueInfo), &resultLength);
+
if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW)) {
IF_LOUD(DbgPrint("\n\nStatus of %x querying key value for size\n", status);)
} else { // We know how big it needs to be.
ULONG valueInfoLength = valueInfo.DataLength + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
- PKEY_VALUE_PARTIAL_INFORMATION valueInfoP = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool(PagedPool, valueInfoLength);
+ PKEY_VALUE_PARTIAL_INFORMATION valueInfoP = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag(PagedPool, valueInfoLength, '1PWA');
if (valueInfoP != NULL) {
status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey,
KeyValuePartialInformation,
valueInfoLength, &resultLength);
if (!NT_SUCCESS(status)) {
IF_LOUD(DbgPrint("Status of %x querying key value\n", status);)
- } else{
+ } else {
IF_LOUD(DbgPrint("Device %d = %ws\n", i, valueInfoP->Data);)
RtlCopyMemory((PCHAR)DeviceNames+BufPos,
valueInfoP->Data,
valueInfoP->DataLength);
BufPos+=valueInfoP->DataLength-2;
}
+
ExFreePool(valueInfoP);
} else {
IF_LOUD(DbgPrint("Error Allocating the buffer for the device name\n");)
}
+
}
+
// terminate the buffer
DeviceNames[BufPos/2]=0;
DeviceNames[BufPos/2+1]=0;
+
ZwClose (ExportKeyHandle);
i++;
+
}
+
ZwClose (keyHandle);
+
}
if(BufPos==0){
ExFreePool(DeviceNames);
return NULL;
}
- return DeviceNames;
+ return DeviceNames;
}
-//
-// Return the MACs that bind to TCP/IP.
-//
+//-------------------------------------------------------------------
PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(void)
{
if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW)) {
IF_LOUD(DbgPrint("\n\nStatus of %x querying key value for size\n", status);)
} else { // We know how big it needs to be.
- ULONG valueInfoLength = valueInfo.DataLength +
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
+ ULONG valueInfoLength = valueInfo.DataLength + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
PKEY_VALUE_PARTIAL_INFORMATION valueInfoP =
- (PKEY_VALUE_PARTIAL_INFORMATION)
- ExAllocatePool(PagedPool, valueInfoLength);
- if (valueInfoP != NULL) {
+ (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(PagedPool, valueInfoLength, '2PWA');
+
+ if (valueInfoP != NULL) {
status = ZwQueryValueKey(keyHandle, &bindValueName,
KeyValuePartialInformation,
valueInfoP,
valueInfoLength, &resultLength);
- if (!NT_SUCCESS(status)) {
+
+ if (!NT_SUCCESS(status)) {
IF_LOUD(DbgPrint("\n\nStatus of %x querying key value\n", status);)
}
else if (valueInfoLength != resultLength) {
return result;
}
-//
-// create a device associated with a given MAC.
-//
+//-------------------------------------------------------------------
BOOLEAN createDevice(IN OUT PDRIVER_OBJECT adriverObjectP,
IN PUNICODE_STRING amacNameP, NDIS_HANDLE aProtoHandle)
{
- BOOLEAN result = FALSE;
NTSTATUS status;
PDEVICE_OBJECT devObjP;
UNICODE_STRING deviceName;
+ BOOLEAN result = FALSE;
IF_LOUD(DbgPrint("\n\ncreateDevice for MAC %ws\n", amacNameP->Buffer);)
if (RtlCompareMemory(amacNameP->Buffer, devicePrefix.Buffer,
}
deviceName.Length = 0;
- deviceName.MaximumLength = (USHORT)(amacNameP->Length + PacketName.Length + sizeof(UNICODE_NULL));
- deviceName.Buffer = ExAllocatePool(PagedPool, deviceName.MaximumLength);
+ deviceName.MaximumLength = (USHORT)(amacNameP->Length + NPF_Prefix.Length + sizeof(UNICODE_NULL));
+ deviceName.Buffer = ExAllocatePoolWithTag(PagedPool, deviceName.MaximumLength, '3PWA');
+
if (deviceName.Buffer != NULL) {
RtlAppendUnicodeStringToString(&deviceName, &devicePrefix);
- RtlAppendUnicodeStringToString(&deviceName, &PacketName);
+ RtlAppendUnicodeStringToString(&deviceName, &NPF_Prefix);
RtlAppendUnicodeToString(&deviceName, amacNameP->Buffer +
devicePrefix.Length / sizeof(WCHAR));
+
IF_LOUD(DbgPrint("\n\nDevice name: %ws\n", deviceName.Buffer);)
+
status = IoCreateDevice(adriverObjectP, sizeof(PDEVICE_EXTENSION),
&deviceName, FILE_DEVICE_TRANSPORT, 0, FALSE,
&devObjP);
+
if (NT_SUCCESS(status)) {
PDEVICE_EXTENSION devExtP = (PDEVICE_EXTENSION)devObjP->DeviceExtension;
+
IF_LOUD(DbgPrint("\n\nDevice created succesfully\n");)
+
devObjP->Flags |= DO_DIRECT_IO;
+
devExtP->DeviceObject = devObjP;
RtlInitUnicodeString(&devExtP->AdapterName,amacNameP->Buffer);
devExtP->BindString = NULL;
devExtP->ExportString = NULL;
devExtP->NdisProtocolHandle=aProtoHandle;
+
}
+
else IF_LOUD(DbgPrint("\n\nIoCreateDevice status = %x\n", status););
+
+ ExFreePool(deviceName.Buffer);
}
- if (deviceName.Length > 0)
- ExFreePool(deviceName.Buffer);
+
return result;
}
+//-------------------------------------------------------------------
-
-VOID STDCALL
-PacketUnload(IN PDRIVER_OBJECT DriverObject)
+VOID
+NPF_Unload(IN PDRIVER_OBJECT DriverObject)
{
+
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT OldDeviceObject;
PDEVICE_EXTENSION DeviceExtension;
+
NDIS_HANDLE NdisProtocolHandle;
NDIS_STATUS Status;
- IF_LOUD(DbgPrint("Packet: Unload\n");)
-
+ IF_LOUD(DbgPrint("NPF: Unload\n");)
+
+
DeviceObject = DriverObject->DeviceObject;
+
while (DeviceObject != NULL) {
DeviceExtension = DeviceObject->DeviceExtension;
+
NdisProtocolHandle=DeviceExtension->NdisProtocolHandle;
OldDeviceObject=DeviceObject;
+
DeviceObject=DeviceObject->NextDevice;
+
+ IF_LOUD(DbgPrint("Deleting Adapter %ws, Protocol Handle=%x, Device Obj=%x (%x)\n",
+ DeviceExtension->AdapterName.Buffer,
+ NdisProtocolHandle,
+ DeviceObject,
+ OldDeviceObject);)
+
IoDeleteDevice(OldDeviceObject);
+
}
- NdisDeregisterProtocol(
+
+ NdisDeregisterProtocol(
&Status,
NdisProtocolHandle
);
+
// Free the adapters names
- ExFreePool( bindP );
+ ExFreePool( bindP );
+
}
+//-------------------------------------------------------------------
-NTSTATUS STDCALL
-PacketIoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
+NTSTATUS
+NPF_IoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
- NDIS_STATUS Status;
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
PLIST_ENTRY RequestListEntry;
PINTERNAL_REQUEST pRequest;
ULONG FunctionCode;
+ NDIS_STATUS Status;
PLIST_ENTRY PacketListEntry;
UINT i;
PUCHAR tpointer;
PPACKET_OID_DATA OidData;
int *StatsBuf;
PNDIS_PACKET pPacket;
- PPACKET_RESERVED Reserved;
ULONG mode;
+ PWSTR DumpNameBuff;
PUCHAR TmpBPFProgram;
-
- IF_LOUD(DbgPrint("Packet: IoControl\n");)
+ INT WriteRes;
+ BOOLEAN SyncWrite = FALSE;
+ struct bpf_insn *initprogram;
+ ULONG insns;
+ ULONG cnt;
+ BOOLEAN IsExtendedFilter=FALSE;
+
+ IF_LOUD(DbgPrint("NPF: IoControl\n");)
IrpSp = IoGetCurrentIrpStackLocation(Irp);
FunctionCode=IrpSp->Parameters.DeviceIoControl.IoControlCode;
Open=IrpSp->FileObject->FsContext;
- RequestListEntry=ExInterlockedRemoveHeadList(&Open->RequestList,&Open->RequestSpinLock);
- if (RequestListEntry == NULL) {
- Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_UNSUCCESSFUL;
- }
- pRequest=CONTAINING_RECORD(RequestListEntry,INTERNAL_REQUEST,ListElement);
- pRequest->Irp=Irp;
+
Irp->IoStatus.Status = STATUS_SUCCESS;
- IF_LOUD(DbgPrint("Packet: Function code is %08lx buff size=%08lx %08lx\n",FunctionCode,IrpSp->Parameters.DeviceIoControl.InputBufferLength,IrpSp->Parameters.DeviceIoControl.OutputBufferLength);)
+
+ IF_LOUD(DbgPrint("NPF: Function code is %08lx buff size=%08lx %08lx\n",FunctionCode,IrpSp->Parameters.DeviceIoControl.InputBufferLength,IrpSp->Parameters.DeviceIoControl.OutputBufferLength);)
+
+
switch (FunctionCode){
+
case BIOCGSTATS: //function to get the capture stats
- StatsBuf=Irp->UserBuffer;
- StatsBuf[0]=Open->Received;
- StatsBuf[1]=Open->Dropped;
- Irp->IoStatus.Information=8;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- Status=STATUS_SUCCESS;
+
+ if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < 4*sizeof(INT)){
+ EXIT_FAILURE(0);
+ }
+
+ *(((PUINT)Irp->UserBuffer)+3) = Open->Accepted;
+ *(((PUINT)Irp->UserBuffer)) = Open->Received;
+ *(((PUINT)Irp->UserBuffer)+1) = Open->Dropped;
+ *(((PUINT)Irp->UserBuffer)+2) = 0; // Not yet supported
+
+ EXIT_SUCCESS(4*sizeof(INT));
+
break;
+
case BIOCGEVNAME: //function to get the name of the event associated with the current instance
+
if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength<26){
- Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
- Irp->IoStatus.Information=0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
- return STATUS_UNSUCCESSFUL;
+ EXIT_FAILURE(0);
}
+
RtlCopyMemory(Irp->UserBuffer,(Open->ReadEventName.Buffer)+18,26);
- Irp->IoStatus.Information=26;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- Status=STATUS_SUCCESS;
+
+ EXIT_SUCCESS(26);
+
+ break;
+
+ case BIOCSENDPACKETSSYNC:
+
+ SyncWrite = TRUE;
+
+ case BIOCSENDPACKETSNOSYNC:
+
+ WriteRes = NPF_BufferedWrite(Irp,
+ (PUCHAR)Irp->AssociatedIrp.SystemBuffer,
+ IrpSp->Parameters.DeviceIoControl.InputBufferLength,
+ SyncWrite);
+
+ if( WriteRes != -1)
+ {
+ EXIT_SUCCESS(WriteRes);
+ }
+
+ EXIT_FAILURE(WriteRes);
+
break;
- case BIOCSETF: //fuction to set a new bpf filter
- //free the previous buffer if it was present
+
+ case BIOCSETF:
+
+ // Free the previous buffer if it was present
if(Open->bpfprogram!=NULL){
TmpBPFProgram=Open->bpfprogram;
- Open->bpfprogram=NULL;
+ Open->bpfprogram = NULL;
ExFreePool(TmpBPFProgram);
}
- //get the pointer to the new program
+
+ if (Open->Filter!=NULL)
+ {
+ JIT_BPF_Filter *OldFilter=Open->Filter;
+ Open->Filter=NULL;
+ BPF_Destroy_JIT_Filter(OldFilter);
+ }
+
+ // Get the pointer to the new program
prog=(PUCHAR)Irp->AssociatedIrp.SystemBuffer;
+
if(prog==NULL){
- Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
- Irp->IoStatus.Information=0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
- return STATUS_UNSUCCESSFUL;
+ IF_LOUD(DbgPrint("0001");)
+
+ EXIT_FAILURE(0);
}
- //before accepting the program we must check that it's valid
- //Otherwise, a bogus program could easily crash the system
- if(bpf_validate((struct bpf_insn*)prog,(IrpSp->Parameters.DeviceIoControl.InputBufferLength)/sizeof(struct bpf_insn))==0) {
- Irp->IoStatus.Information=0;
- Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
- return STATUS_UNSUCCESSFUL;
+
+ insns=(IrpSp->Parameters.DeviceIoControl.InputBufferLength)/sizeof(struct bpf_insn);
+
+ //count the number of operative instructions
+ for (cnt=0;(cnt<insns) &&(((struct bpf_insn*)prog)[cnt].code!=BPF_SEPARATION); cnt++);
+
+ IF_LOUD(DbgPrint("Operative instructions=%u\n",cnt);)
+
+ if (((struct bpf_insn*)prog)[cnt].code==BPF_SEPARATION && (insns-cnt-1)!=0)
+ {
+ IF_LOUD(DbgPrint("Initialization instructions=%u\n",insns-cnt-1);)
+
+ IsExtendedFilter=TRUE;
+
+ initprogram=&((struct bpf_insn*)prog)[cnt+1];
+
+ if(bpf_filter_init(initprogram,&(Open->mem_ex),&(Open->tme), &G_Start_Time)!=INIT_OK)
+ {
+
+ IF_LOUD(DbgPrint("Error initializing NPF machine (bpf_filter_init)\n");)
+
+ EXIT_FAILURE(0);
+ }
}
- //allocate the memory to contain the new filter program
- TmpBPFProgram=(PUCHAR)ExAllocatePool(NonPagedPool, IrpSp->Parameters.DeviceIoControl.InputBufferLength);
+
+ //the NPF processor has been initialized, we have to validate the operative instructions
+ insns=cnt;
+
+ if(bpf_validate((struct bpf_insn*)prog,cnt,Open->mem_ex.size)==0)
+ {
+ IF_LOUD(DbgPrint("Error validating program");)
+ //FIXME: the machine has been initialized(?), but the operative code is wrong.
+ //we have to reset the machine!
+ //something like: reallocate the mem_ex, and reset the tme_core
+ EXIT_FAILURE(0);
+ }
+
+ // Allocate the memory to contain the new filter program
+ // We could need the original BPF binary if we are forced to use bpf_filter_with_2_buffers()
+ TmpBPFProgram=(PUCHAR)ExAllocatePoolWithTag(NonPagedPool, cnt*sizeof(struct bpf_insn), '4PWA');
if (TmpBPFProgram==NULL){
+ IF_LOUD(DbgPrint("Error - No memory for filter");)
// no memory
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- Irp->IoStatus.Information=0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
- return STATUS_INSUFFICIENT_RESOURCES;
+ EXIT_FAILURE(0);
}
+
//copy the program in the new buffer
- RtlCopyMemory(TmpBPFProgram,prog,IrpSp->Parameters.DeviceIoControl.InputBufferLength);
+ RtlCopyMemory(TmpBPFProgram,prog,cnt*sizeof(struct bpf_insn));
Open->bpfprogram=TmpBPFProgram;
+
+ // Create the new JIT filter function
+
+ if(!IsExtendedFilter)
+ if((Open->Filter=BPF_jitter((struct bpf_insn*)Open->bpfprogram,cnt))
+ == NULL)
+ {
+ IF_LOUD(DbgPrint("Error jittering filter");)
+ EXIT_FAILURE(0);
+ }
+
//return
- Irp->IoStatus.Information=IrpSp->Parameters.DeviceIoControl.InputBufferLength;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Open->Bhead=0;
- Open->Btail=0;
- Open->BLastByte=0;
- Open->Received=0;
- Open->Dropped=0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- Status=STATUS_SUCCESS;
- break;
+ Open->Bhead = 0;
+ Open->Btail = 0;
+ Open->BLastByte = 0;
+ Open->Received = 0;
+ Open->Dropped = 0;
+
+ EXIT_SUCCESS(IrpSp->Parameters.DeviceIoControl.InputBufferLength);
+
+ break;
+
case BIOCSMODE: //set the capture mode
- mode=((PULONG)Irp->AssociatedIrp.SystemBuffer)[0];
- if(mode==MODE_STAT){
- Open->mode=MODE_STAT;
- Open->Nbytes.QuadPart=0;
- Open->Npackets.QuadPart=0;
- if(Open->TimeOut.QuadPart==0)Open->TimeOut.QuadPart=-10000000;
- Irp->IoStatus.Information=1;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
- return NDIS_STATUS_SUCCESS;
- }
- else if(mode==MODE_CAPT){
+
+ mode=*((PULONG)Irp->AssociatedIrp.SystemBuffer);
+
+ if(mode == MODE_CAPT){
Open->mode=MODE_CAPT;
- Irp->IoStatus.Information=0;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
- return NDIS_STATUS_SUCCESS;
+
+ EXIT_SUCCESS(0);
}
+ else if (mode==MODE_MON){
+ Open->mode=MODE_MON;
+
+ EXIT_SUCCESS(0);
+ }
else{
- Irp->IoStatus.Information=0;
- Irp->IoStatus.Status = NDIS_STATUS_FAILURE;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
- return NDIS_STATUS_FAILURE;
+ if(mode & MODE_STAT){
+ Open->mode = MODE_STAT;
+ Open->Nbytes.QuadPart=0;
+ Open->Npackets.QuadPart=0;
+
+ if(Open->TimeOut.QuadPart==0)Open->TimeOut.QuadPart=-10000000;
+
+ }
+
+ if(mode & MODE_DUMP){
+
+ Open->mode |= MODE_DUMP;
+ Open->MinToCopy=(Open->BufSize<2000000)?Open->BufSize/2:1000000;
+
+ }
+ EXIT_SUCCESS(0);
+ }
+
+ EXIT_FAILURE(0);
+
+ break;
+
+ case BIOCSETDUMPFILENAME:
+
+ if(Open->mode & MODE_DUMP)
+ {
+
+ // Close current dump file
+ if(Open->DumpFileHandle != NULL){
+ NPF_CloseDumpFile(Open);
+ Open->DumpFileHandle = NULL;
+ }
+
+ if(IrpSp->Parameters.DeviceIoControl.InputBufferLength == 0){
+ EXIT_FAILURE(0);
+ }
+
+ // Allocate the buffer that will contain the string
+ DumpNameBuff=ExAllocatePoolWithTag(NonPagedPool, IrpSp->Parameters.DeviceIoControl.InputBufferLength, '5PWA');
+ if(DumpNameBuff==NULL || Open->DumpFileName.Buffer!=NULL){
+ IF_LOUD(DbgPrint("NPF: unable to allocate the dump filename: not enough memory or name already set\n");)
+ EXIT_FAILURE(0);
+ }
+
+ // Copy the buffer
+ RtlCopyBytes((PVOID)DumpNameBuff,
+ Irp->AssociatedIrp.SystemBuffer,
+ IrpSp->Parameters.DeviceIoControl.InputBufferLength);
+
+ // Force a \0 at the end of the filename to avoid that malformed strings cause RtlInitUnicodeString to crash the system
+ ((SHORT*)DumpNameBuff)[IrpSp->Parameters.DeviceIoControl.InputBufferLength/2-1]=0;
+
+ // Create the unicode string
+ RtlInitUnicodeString(&Open->DumpFileName, DumpNameBuff);
+
+ IF_LOUD(DbgPrint("NPF: dump file name set to %ws, len=%d\n",
+ Open->DumpFileName.Buffer,
+ IrpSp->Parameters.DeviceIoControl.InputBufferLength);)
+
+ // Try to create the file
+ if ( NT_SUCCESS( NPF_OpenDumpFile(Open,&Open->DumpFileName,FALSE)) &&
+ NT_SUCCESS( NPF_StartDump(Open))){
+
+ EXIT_SUCCESS(0);
+ }
+ }
+
+ EXIT_FAILURE(0);
+
+ break;
+
+ case BIOCSETDUMPLIMITS:
+
+ Open->MaxDumpBytes = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
+ Open->MaxDumpPacks = *((PULONG)Irp->AssociatedIrp.SystemBuffer + 1);
+
+ IF_LOUD(DbgPrint("NPF: Set dump limits to %u bytes, %u packs\n", Open->MaxDumpBytes, Open->MaxDumpPacks);)
+
+ EXIT_SUCCESS(0);
+
+ break;
+
+ case BIOCISDUMPENDED:
+ if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < 4){
+ EXIT_FAILURE(0);
}
+
+ *((UINT*)Irp->UserBuffer) = (Open->DumpLimitReached)?1:0;
+
+ EXIT_SUCCESS(4);
+
break;
- case BIOCSETBUFFERSIZE: //function to set the dimension of the buffer for the packets
- //get the number of buffers to allocate
- dim=((PULONG)Irp->AssociatedIrp.SystemBuffer)[0];
- //free the old buffer
- if(Open->Buffer!=NULL) ExFreePool(Open->Buffer);
- //allocate the new buffer
+
+ case BIOCSETBUFFERSIZE:
+
+ // Get the number of bytes to allocate
+ dim = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
+
+ // Free the old buffer
+ tpointer = Open->Buffer;
+ if(tpointer != NULL){
+ Open->BufSize = 0;
+ Open->Buffer = NULL;
+ ExFreePool(tpointer);
+ }
+ // Allocate the new buffer
if(dim!=0){
- tpointer=ExAllocatePool(NonPagedPool,dim);
- if (tpointer==NULL) {
+ tpointer = ExAllocatePoolWithTag(NonPagedPool, dim, '6PWA');
+ if (tpointer==NULL) {
// no memory
- Open->BufSize=0;
- Open->Buffer=NULL;
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
- return STATUS_INSUFFICIENT_RESOURCES;
+ Open->BufSize = 0;
+ Open->Buffer = NULL;
+ EXIT_FAILURE(0);
}
}
else
- tpointer=NULL;
- Open->Buffer=tpointer;
- Open->Bhead=0;
- Open->Btail=0;
- Open->BLastByte=0;
- Irp->IoStatus.Information=dim;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- Open->BufSize=(UINT)dim;
- Status=STATUS_SUCCESS;
+ tpointer = NULL;
+
+ Open->Buffer = tpointer;
+ Open->Bhead = 0;
+ Open->Btail = 0;
+ Open->BLastByte = 0;
+
+ Open->BufSize = (UINT)dim;
+ EXIT_SUCCESS(dim);
+
break;
+
case BIOCSRTIMEOUT: //set the timeout on the read calls
- timeout=((PULONG)Irp->AssociatedIrp.SystemBuffer)[0];
+
+ timeout = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
if((int)timeout==-1)
Open->TimeOut.QuadPart=(LONGLONG)IMMEDIATE;
else {
Open->TimeOut.QuadPart*=10000;
Open->TimeOut.QuadPart=-Open->TimeOut.QuadPart;
}
- IF_LOUD(DbgPrint("Packet: read timeout set to %d:%d\n",Open->TimeOut.HighPart,Open->TimeOut.LowPart);)
- Irp->IoStatus.Information=timeout;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- Status=STATUS_SUCCESS;
+
+ //IF_LOUD(DbgPrint("NPF: read timeout set to %d:%d\n",Open->TimeOut.HighPart,Open->TimeOut.LowPart);)
+ EXIT_SUCCESS(timeout);
+
break;
+
case BIOCSWRITEREP: //set the writes repetition number
- Open->Nwrites=((PULONG)Irp->AssociatedIrp.SystemBuffer)[0];
- Irp->IoStatus.Information=Open->Nwrites;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- Status=STATUS_SUCCESS;
+
+ Open->Nwrites = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
+
+ EXIT_SUCCESS(Open->Nwrites);
+
break;
+
case BIOCSMINTOCOPY: //set the minimum buffer's size to copy to the application
- Open->MinToCopy=((PULONG)Irp->AssociatedIrp.SystemBuffer)[0];
- Irp->IoStatus.Information=Open->MinToCopy;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- Status=STATUS_SUCCESS;
+
+ Open->MinToCopy = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
+
+ EXIT_SUCCESS(Open->MinToCopy);
+
break;
+
case IOCTL_PROTOCOL_RESET:
- IF_LOUD(DbgPrint("Packet: IoControl - Reset request\n");)
+
+ IF_LOUD(DbgPrint("NPF: IoControl - Reset request\n");)
+
IoMarkIrpPending(Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
+
ExInterlockedInsertTailList(&Open->ResetIrpList,&Irp->Tail.Overlay.ListEntry,&Open->RequestSpinLock);
NdisReset(&Status,Open->AdapterHandle);
if (Status != NDIS_STATUS_PENDING) {
- IF_LOUD(DbgPrint("Packet: IoControl - ResetComplete being called\n");)
- PacketResetComplete(Open,Status);
+ IF_LOUD(DbgPrint("NPF: IoControl - ResetComplete being called\n");)
+ NPF_ResetComplete(Open,Status);
}
+
break;
+
+
case BIOCSETOID:
case BIOCQUERYOID:
- //
+
+ // Extract a request from the list of free ones
+ RequestListEntry=ExInterlockedRemoveHeadList(&Open->RequestList,&Open->RequestSpinLock);
+ if (RequestListEntry == NULL)
+ {
+ EXIT_FAILURE(0);
+ }
+
+ pRequest=CONTAINING_RECORD(RequestListEntry,INTERNAL_REQUEST,ListElement);
+ pRequest->Irp=Irp;
+
+ //
// See if it is an Ndis request
//
OidData=Irp->AssociatedIrp.SystemBuffer;
+
if (((FunctionCode == BIOCSETOID) || (FunctionCode == BIOCQUERYOID))
&&
(IrpSp->Parameters.DeviceIoControl.InputBufferLength == IrpSp->Parameters.DeviceIoControl.OutputBufferLength)
&&
(IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(PACKET_OID_DATA)-1+OidData->Length)) {
- IF_LOUD(DbgPrint("Packet: IoControl: Request: Oid=%08lx, Length=%08lx\n",OidData->Oid,OidData->Length);)
+ IF_LOUD(DbgPrint("NPF: IoControl: Request: Oid=%08lx, Length=%08lx\n",OidData->Oid,OidData->Length);)
+
//
// The buffer is valid
//
if (FunctionCode == BIOCSETOID){
+
pRequest->Request.RequestType=NdisRequestSetInformation;
pRequest->Request.DATA.SET_INFORMATION.Oid=OidData->Oid;
+
pRequest->Request.DATA.SET_INFORMATION.InformationBuffer=OidData->Data;
pRequest->Request.DATA.SET_INFORMATION.InformationBufferLength=OidData->Length;
} else{
pRequest->Request.RequestType=NdisRequestQueryInformation;
pRequest->Request.DATA.QUERY_INFORMATION.Oid=OidData->Oid;
+
pRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer=OidData->Data;
pRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength=OidData->Length;
+
}
+
NdisResetEvent(&Open->IOEvent);
//
// submit the request
Open->AdapterHandle,
&pRequest->Request
);
+
} else {
//
// buffer too small
Status=NDIS_STATUS_FAILURE;
pRequest->Request.DATA.SET_INFORMATION.BytesRead=0;
pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten=0;
+
}
+
if (Status != NDIS_STATUS_PENDING) {
- IF_LOUD(DbgPrint("Packet: Calling RequestCompleteHandler\n");)
- PacketRequestComplete(Open, &pRequest->Request, Status);
+ IF_LOUD(DbgPrint("NPF: Calling RequestCompleteHandler\n");)
+
+ NPF_RequestComplete(Open, &pRequest->Request, Status);
return Status;
+
}
+
NdisWaitEvent(&Open->IOEvent, 5000);
+
return(Open->IOStatus);
+
break;
+
+
default:
- return(NDIS_STATUS_FAILURE);
+ EXIT_FAILURE(0);
}
- ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
+
return Status;
}
+//-------------------------------------------------------------------
+
VOID
-PacketRequestComplete(
+NPF_RequestComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_REQUEST NdisRequest,
IN NDIS_STATUS Status
)
+
{
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
PIRP Irp;
PINTERNAL_REQUEST pRequest;
- ULONG FunctionCode;
+ UINT FunctionCode;
+ KIRQL OldIrq;
PPACKET_OID_DATA OidData;
- IF_LOUD(DbgPrint("Packet: RequestComplete\n");)
+ IF_LOUD(DbgPrint("NPF: RequestComplete\n");)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
+
pRequest=CONTAINING_RECORD(NdisRequest,INTERNAL_REQUEST,Request);
Irp=pRequest->Irp;
+
+ if(Irp == NULL){
+
+ // Put the request in the list of the free ones
+ ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
+
+ return;
+ }
+
IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
FunctionCode=IrpSp->Parameters.DeviceIoControl.IoControlCode;
+
OidData=Irp->AssociatedIrp.SystemBuffer;
+
if (FunctionCode == BIOCSETOID) {
+
OidData->Length=pRequest->Request.DATA.SET_INFORMATION.BytesRead;
+
} else {
+
if (FunctionCode == BIOCQUERYOID) {
+
OidData->Length=pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten;
+
IF_LOUD(DbgPrint("RequestComplete: BytesWritten=%d\n",pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten);)
}
+
}
+
Irp->IoStatus.Information=IrpSp->Parameters.DeviceIoControl.InputBufferLength;
IF_LOUD(DbgPrint("RequestComplete: BytesReturned=%d\n",IrpSp->Parameters.DeviceIoControl.InputBufferLength);)
&Open->RequestList,
&pRequest->ListElement,
&Open->RequestSpinLock);
+
Irp->IoStatus.Status = Status;
+
Open->IOStatus = Status;
+
IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
// Unlock the IOCTL call
NdisSetEvent(&Open->IOEvent);
+
return;
+
+
}
+//-------------------------------------------------------------------
+
VOID
-PacketStatus(
+NPF_Status(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize
)
+
{
- IF_LOUD(DbgPrint("Packet: Status Indication\n");)
+
+ IF_LOUD(DbgPrint("NPF: Status Indication\n");)
+
return;
+
}
+//-------------------------------------------------------------------
+
VOID
-PacketStatusComplete(
+NPF_StatusComplete(
IN NDIS_HANDLE ProtocolBindingContext
)
-{
- IF_LOUD(DbgPrint("Packet: StatusIndicationComplete\n");)
- return;
-}
-
-#if 0
-NTSTATUS
-PacketCreateSymbolicLink(
- IN PUNICODE_STRING DeviceName,
- IN BOOLEAN Create
- )
{
- UNICODE_STRING UnicodeDosDeviceName;
- NTSTATUS Status;
- if (DeviceName->Length < sizeof(L"\\Device\\")) {
- return STATUS_UNSUCCESSFUL;
- }
- RtlInitUnicodeString(&UnicodeDosDeviceName,NULL);
- UnicodeDosDeviceName.MaximumLength=DeviceName->Length+sizeof(L"\\DosDevices")+sizeof(UNICODE_NULL);
- UnicodeDosDeviceName.Buffer=ExAllocatePool(
- NonPagedPool,
- UnicodeDosDeviceName.MaximumLength
- );
- if (UnicodeDosDeviceName.Buffer != NULL) {
- RtlZeroMemory(
- UnicodeDosDeviceName.Buffer,
- UnicodeDosDeviceName.MaximumLength
- );
- RtlAppendUnicodeToString(
- &UnicodeDosDeviceName,
- L"\\DosDevices\\"
- );
- RtlAppendUnicodeToString(
- &UnicodeDosDeviceName,
- (DeviceName->Buffer+(sizeof("\\Device")))
- );
-
- IF_LOUD(DbgPrint("Packet: DosDeviceName is %ws\n",UnicodeDosDeviceName.Buffer);)
+ IF_LOUD(DbgPrint("NPF: StatusIndicationComplete\n");)
- if (Create) {
- Status=IoCreateSymbolicLink(&UnicodeDosDeviceName,DeviceName);
- } else {
- Status=IoDeleteSymbolicLink(&UnicodeDosDeviceName);
- }
- ExFreePool(UnicodeDosDeviceName.Buffer);
+ return;
- }
- return Status;
}
-#endif
+//-------------------------------------------------------------------
NTSTATUS
-PacketReadRegistry(
+NPF_ReadRegistry(
IN PWSTR *MacDriverName,
IN PWSTR *PacketDriverName,
IN PUNICODE_STRING RegistryPath
)
+
{
NTSTATUS Status;
+
RTL_QUERY_REGISTRY_TABLE ParamTable[4];
+
PWSTR Bind = L"Bind";
PWSTR Export = L"Export";
PWSTR Parameters = L"Parameters";
PWSTR Linkage = L"Linkage";
+
PWCHAR Path;
- Path=ExAllocatePool(
- PagedPool,
- RegistryPath->Length+sizeof(WCHAR)
- );
+ Path=ExAllocatePoolWithTag(PagedPool, RegistryPath->Length+sizeof(WCHAR), '7PWA');
+
if (Path == NULL) {
+ IF_LOUD(DbgPrint("\nPacketReadRegistry: returing STATUS_INSUFFICIENT_RESOURCES\n");)
return STATUS_INSUFFICIENT_RESOURCES;
}
+
RtlZeroMemory(
Path,
RegistryPath->Length+sizeof(WCHAR)
);
+
RtlCopyMemory(
Path,
RegistryPath->Buffer,
RegistryPath->Length
);
- IF_LOUD(DbgPrint("Packet: Reg path is %ws\n",RegistryPath->Buffer);)
+ IF_LOUD(DbgPrint("NPF: Reg path is %ws\n",RegistryPath->Buffer);)
RtlZeroMemory(
ParamTable,
sizeof(ParamTable)
);
+
+
+
//
// change to the linkage key
//
- ParamTable[0].QueryRoutine = NULL;
+ //ParamTable[0].QueryRoutine = NULL;
+ ParamTable[0].QueryRoutine = NPF_QueryRegistryRoutine;
ParamTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
ParamTable[0].Name = Linkage;
+
+
//
// Get the name of the mac driver we should bind to
//
- ParamTable[1].QueryRoutine = PacketQueryRegistryRoutine;
+
+ ParamTable[1].QueryRoutine = NPF_QueryRegistryRoutine;
ParamTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED |
RTL_QUERY_REGISTRY_NOEXPAND;
+
ParamTable[1].Name = Bind;
ParamTable[1].EntryContext = (PVOID)MacDriverName;
ParamTable[1].DefaultType = REG_MULTI_SZ;
+
//
// Get the name that we should use for the driver object
//
- ParamTable[2].QueryRoutine = PacketQueryRegistryRoutine;
+
+ ParamTable[2].QueryRoutine = NPF_QueryRegistryRoutine;
ParamTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED |
RTL_QUERY_REGISTRY_NOEXPAND;
+
ParamTable[2].Name = Export;
ParamTable[2].EntryContext = (PVOID)PacketDriverName;
ParamTable[2].DefaultType = REG_MULTI_SZ;
+
Status=RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
Path,
NULL,
NULL
);
+
+ if (Status != STATUS_SUCCESS) {
+ // insert hard coded parameters here while registry on ROS is not working...
+ IF_LOUD(DbgPrint("PacketReadRegistry() RtlQueryRegistryValues failed - returing fixed parameters\n");)
+
+ *MacDriverName = ExAllocatePool(PagedPool, 50 * sizeof(WCHAR));
+ //memcpy(*MacDriverName, L"\\Device\\ne2000", 15 * sizeof(WCHAR));
+ memcpy(*MacDriverName, L"\\Device\\ne2000", 15 * sizeof(WCHAR));
+
+ *PacketDriverName = ExAllocatePool(PagedPool, 50 * sizeof(WCHAR));
+ memcpy(*PacketDriverName, L"\\Device\\NPF_ne2000", 19 * sizeof(WCHAR));
+ Status = STATUS_SUCCESS;
+
+ }
+
ExFreePool(Path);
return Status;
}
+//-------------------------------------------------------------------
+
NTSTATUS
-STDCALL
-PacketQueryRegistryRoutine(
+NPF_QueryRegistryRoutine(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN PVOID Context,
IN PVOID EntryContext
)
+
{
+
PUCHAR Buffer;
IF_LOUD(DbgPrint("Perf: QueryRegistryRoutine\n");)
+
if (ValueType != REG_MULTI_SZ) {
+
return STATUS_OBJECT_NAME_NOT_FOUND;
+
}
- Buffer=ExAllocatePool(NonPagedPool,ValueLength);
+
+ Buffer=ExAllocatePoolWithTag(NonPagedPool, ValueLength, '8PWA');
+
if (Buffer==NULL) {
+
return STATUS_INSUFFICIENT_RESOURCES;
+
}
+
RtlCopyMemory(
Buffer,
ValueData,
ValueLength
);
+
*((PUCHAR *)EntryContext)=Buffer;
+
return STATUS_SUCCESS;
+
}
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+
+/** @ingroup NPF
+ * @{
+ */
+
+/** @defgroup NPF_include NPF structures and definitions
+ * @{
+ */
+
+#ifndef __PACKET_INCLUDE______
+#define __PACKET_INCLUDE______
+
+#define NTKERNEL ///< Forces the compilation of the jitter with kernel calls
+
#define UNICODE_NULL ((WCHAR)0) // winnt
-#define MAX_REQUESTS 32
+#include "win_bpf.h"
-#define MAX_PACKET_LENGTH 1514
+#include "jitter.h"
+#include "tme.h"
-struct timeval {
- long tv_sec; /* seconds */
- long tv_usec; /* and microseconds */
-};
+#define MAX_REQUESTS 32 ///< Maximum number of simultaneous IOCTL requests.
-/*
- * Alignment macros. Packet_WORDALIGN rounds up to the next
- * even multiple of Packet_ALIGNMENT.
- */
-#define Packet_ALIGNMENT sizeof(int)
-#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1))
+#define Packet_ALIGNMENT sizeof(int) ///< Alignment macro. Defines the alignment size.
+#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) ///< Alignment macro. Rounds up to the next
+ ///< even multiple of Packet_ALIGNMENT.
+/***************************/
+/* IOCTLs */
+/***************************/
+/*!
+ \brief IOCTL code: set kernel buffer size.
-//IOCTLs
+ This IOCTL is used to set a new size of the circular buffer associated with an instance of NPF.
+ When a BIOCSETBUFFERSIZE command is received, the driver frees the old buffer, allocates the new one
+ and resets all the parameters associated with the buffer in the OPEN_INSTANCE structure. The currently
+ buffered packets are lost.
+*/
#define BIOCSETBUFFERSIZE 9592
+
+/*!
+ \brief IOCTL code: set packet filtering program.
+
+ This IOCTL sets a new packet filter in the driver. Before allocating any memory for the new filter, the
+ bpf_validate() function is called to check the correctness of the filter. If this function returns TRUE,
+ the filter is copied to the driver's memory, its address is stored in the bpfprogram field of the
+ OPEN_INSTANCE structure associated with current instance of the driver, and the filter will be applied to
+ every incoming packet. This command also empties the circular buffer used by current instance
+ to store packets. This is done to avoid the presence in the buffer of packets that do not match the filter.
+*/
#define BIOCSETF 9030
+
+/*!
+ \brief IOCTL code: get the capture stats
+
+ This command returns to the application the number of packets received and the number of packets dropped by
+ an instance of the driver.
+*/
#define BIOCGSTATS 9031
-#define BIOCSRTIMEOUT 7416
-#define BIOCSMODE 7412
-#define BIOCSWRITEREP 7413
-#define BIOCSMINTOCOPY 7414
-#define BIOCSETOID 2147483648
-#define BIOCQUERYOID 2147483652
-#define BIOCGEVNAME 7415
-//working modes
-#define MODE_CAPT 0
-#define MODE_STAT 1
+/*!
+ \brief IOCTL code: set the read timeout
-//immediate timeout
-#define IMMEDIATE 1
+ This command sets the maximum timeout after which a read is released, also if no data packets were received.
+*/
+#define BIOCSRTIMEOUT 7416
-struct bpf_insn {
- USHORT code;
- UCHAR jt;
- UCHAR jf;
- int k;
-};
+/*!
+ \brief IOCTL code: set working mode
-struct bpf_hdr {
- struct timeval bh_tstamp; /* time stamp */
- UINT bh_caplen; /* length of captured portion */
- UINT bh_datalen; /* original length of packet */
- USHORT bh_hdrlen; /* length of bpf header (this struct plus alignment padding) */
-};
+ This IOCTL can be used to set the working mode of a NPF instance. The new mode, received by the driver in the
+ buffer associated with the IOCTL command, can be #MODE_CAPT for capture mode (the default), #MODE_STAT for
+ statistical mode or #MODE_DUMP for dump mode.
+*/
+#define BIOCSMODE 7412
+/*!
+ \brief IOCTL code: set number of physical repetions of every packet written by the app
-typedef struct _INTERNAL_REQUEST {
- LIST_ENTRY ListElement;
- PIRP Irp;
- NDIS_REQUEST Request;
+ Sets the number of times a single write call must be repeated. This command sets the OPEN_INSTANCE::Nwrites
+ member, and is used to implement the 'multiple write' feature of the driver.
+*/
+#define BIOCSWRITEREP 7413
- } INTERNAL_REQUEST, *PINTERNAL_REQUEST;
+/*!
+ \brief IOCTL code: set minimum amount of data in the kernel buffer that unlocks a read call
+ This command sets the OPEN_INSTANCE::MinToCopy member.
+*/
+#define BIOCSMINTOCOPY 7414
+/*!
+ \brief IOCTL code: set an OID value
-//
-// Port device extension.
-//
-typedef struct _DEVICE_EXTENSION {
+ This IOCTL is used to perform an OID set operation on the NIC driver.
+*/
+#define BIOCSETOID 2147483648
- PDEVICE_OBJECT DeviceObject;
+/*!
+ \brief IOCTL code: get an OID value
- NDIS_HANDLE NdisProtocolHandle;
+ This IOCTL is used to perform an OID get operation on the NIC driver.
+*/
+#define BIOCQUERYOID 2147483652
- NDIS_STRING AdapterName;
+/*!
+ \brief IOCTL code: set the name of a the file used by kernel dump mode
- PWSTR BindString;
- PWSTR ExportString;
+ This command opens a file whose name is contained in the IOCTL buffer and associates it with current NPf instance.
+ The dump thread uses it to copy the content of the circular buffer to file.
+ If a file was already opened, the driver closes it before opening the new one.
+*/
+#define BIOCSETDUMPFILENAME 9029
+/*!
+ \brief IOCTL code: get the name of the event that the driver signals when some data is present in the buffer
-} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+ Command used by the application to retrieve the name of the global event associated with a NPF instance.
+ The event is signaled by the driver when the kernel buffer contains enough data for a transfer.
+*/
+#define BIOCGEVNAME 7415
-//
-// Open Instance
-//
-typedef struct _OPEN_INSTANCE
- {
- PDEVICE_EXTENSION DeviceExtension;
- NDIS_HANDLE AdapterHandle;
- NDIS_HANDLE PacketPool;
- KSPIN_LOCK RcvQSpinLock;
- LIST_ENTRY RcvList;
- PIRP OpenCloseIrp;
- KSPIN_LOCK RequestSpinLock;
- LIST_ENTRY RequestList;
- LIST_ENTRY ResetIrpList;
- INTERNAL_REQUEST Requests[MAX_REQUESTS];
- PUCHAR Buffer;
- PMDL BufferMdl;
- PKEVENT ReadEvent;
- HANDLE ReadEventHandle;
- UNICODE_STRING ReadEventName;
- int Dropped;
- int Received;
- PUCHAR bpfprogram;
- LARGE_INTEGER StartTime;
- UINT Bhead;
- UINT Btail;
- UINT BufSize;
- UINT BLastByte;
- PMDL TransferMdl;
- NDIS_SPIN_LOCK BufLock;
- UINT MinToCopy;
- LARGE_INTEGER TimeOut;
- int mode;
- LARGE_INTEGER Nbytes;
- LARGE_INTEGER Npackets;
- NDIS_SPIN_LOCK CountersLock;
- UINT Nwrites;
- UINT Multiple_Write_Counter;
- NDIS_EVENT WriteEvent;
- NDIS_EVENT IOEvent;
- NDIS_STATUS IOStatus;
- BOOLEAN Bound;
- }
-OPEN_INSTANCE, *POPEN_INSTANCE;
+/*!
+ \brief IOCTL code: Send a buffer containing multiple packets to the network, ignoring the timestamps.
+
+ Command used to send a buffer of packets in a single system call. Every packet in the buffer is preceded by
+ a sf_pkthdr structure. The timestamps of the packets are ignored, i.e. the packets are sent as fast as
+ possible. The NPF_BufferedWrite() function is invoked to send the packets.
+*/
+#define BIOCSENDPACKETSNOSYNC 9032
+
+/*!
+ \brief IOCTL code: Send a buffer containing multiple packets to the network, considering the timestamps.
+
+ Command used to send a buffer of packets in a single system call. Every packet in the buffer is preceded by
+ a sf_pkthdr structure. The timestamps of the packets are used to synchronize the write, i.e. the packets
+ are sent to the network respecting the intervals specified in the sf_pkthdr structure assiciated with each
+ packet. NPF_BufferedWrite() function is invoked to send the packets.
+*/
+#define BIOCSENDPACKETSSYNC 9033
+
+/*!
+ \brief IOCTL code: Set the dump file limits.
+
+ This IOCTL sets the limits (maximum size and maximum number of packets) of the dump file created when the
+ driver works in dump mode.
+*/
+#define BIOCSETDUMPLIMITS 9034
+
+/*!
+ \brief IOCTL code: Get the status of the kernel dump process.
+
+ This command returns TRUE if the kernel dump is ended, i.e if one of the limits set with BIOCSETDUMPLIMITS
+ (amount of bytes or number of packets) has been reached.
+*/
+#define BIOCISDUMPENDED 7411
+
+// Working modes
+#define MODE_CAPT 0x0 ///< Capture working mode
+#define MODE_STAT 0x1 ///< Statistical working mode
+#define MODE_MON 0x2 ///< Kernel monitoring mode
+#define MODE_DUMP 0x10 ///< Kernel dump working mode
+
+
+#define IMMEDIATE 1 ///< Immediate timeout. Forces a read call to return immediately.
+
+
+// The following definitions are used to provide compatibility
+// of the dump files with the ones of libpcap
+#define TCPDUMP_MAGIC 0xa1b2c3d4 ///< Libpcap magic number. Used by programs like tcpdump to recognize a driver's generated dump file.
+#define PCAP_VERSION_MAJOR 2 ///< Major libpcap version of the dump file. Used by programs like tcpdump to recognize a driver's generated dump file.
+#define PCAP_VERSION_MINOR 4 ///< Minor libpcap version of the dump file. Used by programs like tcpdump to recognize a driver's generated dump file.
+
+/*!
+ \brief Header of a libpcap dump file.
+
+ Used when a driver instance is set in dump mode to create a libpcap-compatible file.
+*/
+struct packet_file_header
+{
+ UINT magic; ///< Libpcap magic number
+ USHORT version_major; ///< Libpcap major version
+ USHORT version_minor; ///< Libpcap minor version
+ UINT thiszone; ///< Gmt to local correction
+ UINT sigfigs; ///< Accuracy of timestamps
+ UINT snaplen; ///< Length of the max saved portion of each packet
+ UINT linktype; ///< Data link type (DLT_*). See win_bpf.h for details.
+};
+/*!
+ \brief Header associated to a packet in the driver's buffer when the driver is in dump mode.
+ Similar to the bpf_hdr structure, but simpler.
+*/
+struct sf_pkthdr {
+ struct timeval ts; ///< time stamp
+ UINT caplen; ///< Length of captured portion. The captured portion can be different from
+ ///< the original packet, because it is possible (with a proper filter) to
+ ///< instruct the driver to capture only a portion of the packets.
+ UINT len; ///< Length of the original packet (off wire).
+};
+/*!
+ \brief Stores an OID request.
+
+ This structure is used by the driver to perform OID query or set operations on the underlying NIC driver.
+ The OID operations be performed usually only by network drivers, but NPF exports this mechanism to user-level
+ applications through an IOCTL interface. The driver uses this structure to wrap a NDIS_REQUEST structure.
+ This allows to handle correctly the callback structure of NdisRequest(), handling multiple requests and
+ maintaining information about the IRPs to complete.
+*/
+typedef struct _INTERNAL_REQUEST {
+ LIST_ENTRY ListElement; ///< Used to handle lists of requests.
+ PIRP Irp; ///< Irp that performed the request
+ NDIS_REQUEST Request; ///< The structure with the actual request, that will be passed to NdisRequest().
+} INTERNAL_REQUEST, *PINTERNAL_REQUEST;
+
+/*!
+ \brief Contains a NDIS packet.
+
+ The driver uses this structure to wrap a NDIS_PACKET structure.
+ This allows to handle correctly the callback structure of NdisTransferData(), handling multiple requests and
+ maintaining information about the IRPs to complete.
+*/
typedef struct _PACKET_RESERVED {
- LIST_ENTRY ListElement;
- PIRP Irp;
- PMDL pMdl;
- } PACKET_RESERVED, *PPACKET_RESERVED;
+ LIST_ENTRY ListElement; ///< Used to handle lists of packets.
+ PIRP Irp; ///< Irp that performed the request
+ PMDL pMdl; ///< MDL mapping the buffer of the packet.
+ BOOLEAN FreeBufAfterWrite; ///< True if the memory buffer associated with the packet must be freed
+ ///< after a call to NdisSend().
+} PACKET_RESERVED, *PPACKET_RESERVED;
+
+#define RESERVED(_p) ((PPACKET_RESERVED)((_p)->ProtocolReserved)) ///< Macro to obtain a NDIS_PACKET from a PACKET_RESERVED
+
+/*!
+ \brief Port device extension.
+
+ Structure containing some data relative to every adapter on which NPF is bound.
+*/
+typedef struct _DEVICE_EXTENSION {
+ PDEVICE_OBJECT DeviceObject; ///< Adapter's device.
+ NDIS_HANDLE NdisProtocolHandle; ///< NDIS handle of NPF.
+ NDIS_STRING AdapterName; ///< Name of the adapter.
+ PWSTR BindString; ///< Original device name of the adapter.
+ PWSTR ExportString; ///< Name of the exported device, i.e. name that the applications will use
+ ///< to open this adapter through WinPcap.
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+/*!
+ \brief Contains the state of a running instance of the NPF driver.
+
+ This is the most important structure of NPF: it is used by almost all the functions of the driver. An
+ _OPEN_INSTANCE structure is associated with every user-level session, allowing concurrent access
+ to the driver.
+*/
+typedef struct _OPEN_INSTANCE
+{
+ PDEVICE_EXTENSION DeviceExtension; ///< Pointer to the _DEVICE_EXTENSION structure of the device on which
+ ///< the instance is bound.
+ NDIS_HANDLE AdapterHandle; ///< NDIS idetifier of the adapter used by this instance.
+ UINT Medium; ///< Type of physical medium the underlying NDIS driver uses. See the
+ ///< documentation of NdisOpenAdapter in the MS DDK for details.
+ NDIS_HANDLE PacketPool; ///< Pool of NDIS_PACKET structures used to transfer the packets from and to the NIC driver.
+ PIRP OpenCloseIrp; ///< Pointer used to store the open/close IRP requests and provide them to the
+ ///< callbacks of NDIS.
+ KSPIN_LOCK RequestSpinLock; ///< SpinLock used to synchronize the OID requests.
+ LIST_ENTRY RequestList; ///< List of pending OID requests.
+ LIST_ENTRY ResetIrpList; ///< List of pending adapter reset requests.
+ INTERNAL_REQUEST Requests[MAX_REQUESTS]; ///< Array of structures that wrap every single OID request.
+ PMDL BufferMdl; ///< Pointer to a Memory descriptor list (MDL) that maps the circular buffer's memory.
+ PKEVENT ReadEvent; ///< Pointer to the event on which the read calls on this instance must wait.
+ HANDLE ReadEventHandle; ///< Handle of the event on which the read calls on this instance must wait.
+ UNICODE_STRING ReadEventName; ///< Name of the event on which the read calls on this instance must wait.
+ ///< The event is created with a name, so it can be used at user level to know when it
+ ///< is possible to access the driver without being blocked. This fiels stores the name
+ ///< that and is used by the BIOCGEVNAME IOCTL call.
+ INT Received; ///< Number of packets received by current instance from its opening, i.e. number of
+ ///< packet received by the network adapter since the beginning of the
+ ///< capture/monitoring/dump session.
+ INT Dropped; ///< Number of packet that current instance had to drop, from its opening. A packet
+ ///< is dropped if there is no more space to store it in the circular buffer that the
+ ///< driver associates to current instance.
+ INT Accepted; ///< Number of packet that current capture instance acepted, from its opening. A packet
+ ///< is accepted if it passes the filter and fits in the buffer. Accepted packets are the
+ ///< ones that reach the application.
+ PUCHAR bpfprogram; ///< Pointer to the filtering pseudo-code associated with current instance of the driver.
+ ///< This code is used only in particular situations (for example when the packet received
+ ///< from the NIC driver is stored in two non-consecutive buffers. In normal situations
+ ///< the filtering routine created by the JIT compiler and pointed by the next field
+ ///< is used. See \ref NPF for details on the filtering process.
+ JIT_BPF_Filter *Filter; ///< Pointer to the native filtering function created by the jitter.
+ ///< See BPF_jitter() for details.
+ PUCHAR Buffer; ///< Pointer to the circular buffer associated with every driver instance. It contains the
+ ///< data that will be passed to the application. See \ref NPF for details.
+ UINT Bhead; ///< Head of the circular buffer.
+ UINT Btail; ///< Tail of the circular buffer.
+ UINT BufSize; ///< Size of the circular buffer.
+ UINT BLastByte; ///< Position of the last valid byte in the circular buffer.
+ PMDL TransferMdl; ///< MDL used to map the portion of the buffer that will contain an incoming packet.
+ ///< Used by NdisTransferData().
+ NDIS_SPIN_LOCK BufLock; ///< SpinLock that protects the access tho the circular buffer variables.
+ UINT MinToCopy; ///< Minimum amount of data in the circular buffer that unlocks a read. Set with the
+ ///< BIOCSMINTOCOPY IOCTL.
+ LARGE_INTEGER TimeOut; ///< Timeout after which a read is released, also if the amount of data in the buffer is
+ ///< less than MinToCopy. Set with the BIOCSRTIMEOUT IOCTL.
+
+ int mode; ///< Working mode of the driver. See PacketSetMode() for details.
+ LARGE_INTEGER Nbytes; ///< Amount of bytes accepted by the filter when this instance is in statistical mode.
+ LARGE_INTEGER Npackets; ///< Number of packets accepted by the filter when this instance is in statistical mode.
+ NDIS_SPIN_LOCK CountersLock; ///< SpinLock that protects the statistical mode counters.
+ UINT Nwrites; ///< Number of times a single write must be physically repeated. See \ref NPF for an
+ ///< explanation
+ UINT Multiple_Write_Counter; ///< Counts the number of times a single write has already physically repeated.
+ NDIS_EVENT WriteEvent; ///< Event used to synchronize the multiple write process.
+ NDIS_EVENT IOEvent; ///< Event used to synchronize I/O requests with the callback structure of NDIS.
+ NDIS_STATUS IOStatus; ///< Maintains the status of and OID request call, that will be passed to the application.
+ BOOLEAN Bound; ///< Specifies if NPF is still bound to the adapter used by this instance. Bound can be
+ ///< FALSE if a Plug and Play adapter has been removed or disabled by the user.
+ HANDLE DumpFileHandle; ///< Handle of the file used in dump mode.
+ PFILE_OBJECT DumpFileObject; ///< Pointer to the object of the file used in dump mode.
+// PKTHREAD DumpThreadObject; ///< Pointer to the object of the thread used in dump mode.
+ HANDLE DumpThreadHandle; ///< Handle of the thread created by dump mode to asynchronously move the buffer to disk.
+ NDIS_EVENT DumpEvent; ///< Event used to synchronize the dump thread with the tap when the instance is in dump mode.
+ LARGE_INTEGER DumpOffset; ///< Current offset in the dump file.
+ UNICODE_STRING DumpFileName; ///< String containing the name of the dump file.
+ UINT MaxDumpBytes; ///< Maximum dimension in bytes of the dump file. If the dump file reaches this size it
+ ///< will be closed. A value of 0 means unlimited size.
+ UINT MaxDumpPacks; ///< Maximum number of packets that will be saved in the dump file. If this number of
+ ///< packets is reached the dump will be closed. A value of 0 means unlimited number of
+ ///< packets.
+ BOOLEAN DumpLimitReached; ///< TRUE if the maximum dimension of the dump file (MaxDumpBytes or MaxDumpPacks) is
+ ///< reached.
+ MEM_TYPE mem_ex; ///< Memory used by the TME virtual co-processor
+ TME_CORE tme; ///< Data structure containing the virtualization of the TME co-processor
+ NDIS_SPIN_LOCK machine_lock; ///< SpinLock that protects the mem_ex buffer
+} OPEN_INSTANCE, *POPEN_INSTANCE;
+
+
+#define TRANSMIT_PACKETS 256 ///< Maximum number of packets in the transmit packet pool. This value is an upper bound to the number
+ ///< of packets that can be transmitted at the same time or with a single call to NdisSendPackets.
+
+#ifdef __GNUC__
+#undef EXIT_SUCCESS
+#undef EXIT_FAILURE
+#endif
+
+/// Macro used in the I/O routines to return the control to user-mode with a success status.
+#define EXIT_SUCCESS(quantity) Irp->IoStatus.Information=quantity;\
+Irp->IoStatus.Status = STATUS_SUCCESS;\
+IoCompleteRequest(Irp, IO_NO_INCREMENT);\
+return STATUS_SUCCESS;\
+
+/// Macro used in the I/O routines to return the control to user-mode with a failure status.
+#define EXIT_FAILURE(quantity) Irp->IoStatus.Information=quantity;\
+Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;\
+IoCompleteRequest(Irp, IO_NO_INCREMENT);\
+return STATUS_UNSUCCESSFUL;\
+
+/**
+ * @}
+ */
-#define ETHERNET_HEADER_LENGTH 14
-#define RESERVED(_p) ((PPACKET_RESERVED)((_p)->ProtocolReserved))
+/***************************/
+/* Prototypes */
+/***************************/
-#define TRANSMIT_PACKETS 128
+/** @defgroup NPF_code NPF functions
+ * @{
+ */
-//
-// Prototypes
-//
-PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(
- VOID
- );
+/*!
+ \brief The initialization routine of the driver.
+ \param DriverObject The driver object of NPF created by the system.
+ \param RegistryPath The registry path containing the keys related to the driver.
+ \return A string containing a list of network adapters.
-PWCHAR getAdaptersList(
- VOID
- );
+ DriverEntry is a mandatory function in a device driver. Like the main() of a user level program, it is called
+ by the system when the driver is loaded in memory and started. Its purpose is to initialize the driver,
+ performing all the allocations and the setup. In particular, DriverEntry registers all the driver's I/O
+ callbacks, creates the devices, defines NPF as a protocol inside NDIS.
+*/
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+/*!
+ \brief Returns the list of the MACs available on the system.
+ \return A string containing a list of network adapters.
+
+ The list of adapters is retrieved from the
+ SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318} registry key.
+ NPF tries to create its bindings from this list. In this way it is possible to be loaded
+ and unloaded dynamically without passing from the control panel.
+*/
+PWCHAR getAdaptersList(VOID);
+
+/*!
+ \brief Returns the MACs that bind to TCP/IP.
+ \return Pointer to the registry key containing the list of adapters on which TCP/IP is bound.
+
+ If getAdaptersList() fails, NPF tries to obtain the TCP/IP bindings through this function.
+*/
+PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(VOID);
+
+/*!
+ \brief Creates a device for a given MAC.
+ \param adriverObjectP The driver object that will be associated with the device, i.e. the one of NPF.
+ \param amacNameP The name of the network interface that the device will point.
+ \param aProtoHandle NDIS protocol handle of NPF.
+ \return If the function succeeds, the return value is nonzero.
+
+ NPF creates a device for every valid network adapter. The new device points to the NPF driver, but contains
+ information about the original device. In this way, when the user opens the new device, NPF will be able to
+ determine the correct adapter to use.
+*/
BOOLEAN createDevice(
IN OUT PDRIVER_OBJECT adriverObjectP,
IN PUNICODE_STRING amacNameP,
NDIS_HANDLE aProtoHandle);
+/*!
+ \brief Opens a new instance of the driver.
+ \param DeviceObject Pointer to the device object utilized by the user.
+ \param Irp Pointer to the IRP containing the user request.
+ \return The status of the operation. See ntstatus.h in the DDK.
+
+ This function is called by the OS when a new instance of the driver is opened, i.e. when a user application
+ performs a CreateFile on a device created by NPF. NPF_Open allocates and initializes variables, objects
+ and buffers needed by the new instance, fills the OPEN_INSTANCE structure associated with it and opens the
+ adapter with a call to NdisOpenAdapter.
+*/
+NTSTATUS
+NPF_Open(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
-VOID
-PacketCancelRoutine (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- );
-
+/*!
+ \brief Ends the opening of an adapter.
+ \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
+ \param Status Status of the opening operation performed by NDIS.
+ \param OpenErrorStatus not used by NPF.
+ Callback function associated with the NdisOpenAdapter() NDIS function. It is invoked by NDIS when the NIC
+ driver has finished an open operation that was previously started by NPF_Open().
+*/
VOID
-PacketOpenAdapterComplete(
+NPF_OpenAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus
);
+/*!
+ \brief Closes an instance of the driver.
+ \param DeviceObject Pointer to the device object utilized by the user.
+ \param Irp Pointer to the IRP containing the user request.
+ \return The status of the operation. See ntstatus.h in the DDK.
+
+ This function is called when a running instance of the driver is closed by the user with a CloseHandle().
+ It stops the capture/monitoring/dump process, deallocates the memory and the objects associated with the
+ instance and closing the files. The network adapter is then closed with a call to NdisCloseAdapter.
+*/
+NTSTATUS
+NPF_Close(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+/*!
+ \brief Ends the closing of an adapter.
+ \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
+ \param Status Status of the close operation performed by NDIS.
+
+ Callback function associated with the NdisCloseAdapter() NDIS function. It is invoked by NDIS when the NIC
+ driver has finished a close operation that was previously started by NPF_Close().
+*/
VOID
-PacketCloseAdapterComplete(
+NPF_CloseAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
);
-
+/*!
+ \brief Callback invoked by NDIS when a packet arrives from the network.
+ \param ProtocolBindingContext Context of the function. Points to a OPEN_INSTANCE structure that identifies
+ the NPF instance to which the packets are destined.
+ \param MacReceiveContext Handle that identifies the underlying NIC driver that generated the request.
+ This value must be used when the packet is transferred from the NIC driver with NdisTransferData().
+ \param HeaderBuffer Pointer to the buffer in the NIC driver memory that contains the header of the packet.
+ \param HeaderBufferSize Size in bytes of the header.
+ \param LookAheadBuffer Pointer to the buffer in the NIC driver's memory that contains the incoming packet's
+ data <b>available to NPF</b>. This value does not necessarily coincide with the actual size of the packet,
+ since only a portion can be available at this time. The remaining portion can be obtained with the
+ NdisTransferData() NDIS function.
+ \param LookaheadBufferSize Size in bytes of the lookahead buffer.
+ \param PacketSize Total size of the incoming packet, excluded the header.
+ \return The status of the operation. See ntstatus.h in the DDK.
+
+ NPF_tap() is called by the underlying NIC for every incoming packet. It is the most important and one of
+ the most complex functions of NPF: it executes the filter, runs the statistical engine (if the instance is in
+ statistical mode), gathers the timestamp, moves the packet in the buffer. NPF_tap() is the only function,
+ along with the filtering ones, that is executed for every incoming packet, therefore it is carefully
+ optimized.
+*/
NDIS_STATUS
-Packet_tap(
+NPF_tap(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT PacketSize
);
+/*!
+ \brief Ends the transfer of a packet.
+ \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
+ \param Packet Pointer to the NDIS_PACKET structure that received the packet data.
+ \param Status Status of the transfer operation.
+ \param BytesTransferred Amount of bytes transferred.
+
+ Callback function associated with the NdisTransferData() NDIS function. It is invoked by NDIS when the NIC
+ driver has finished the transfer of a packet from the NIC driver memory to the NPF circular buffer.
+*/
+VOID
+NPF_TransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+/*!
+ \brief Callback function that signals the end of a packet reception.
+ \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
+ does nothing in NPF
+*/
VOID
-PacketReceiveComplete(
- IN NDIS_HANDLE ProtocolBindingContext
+NPF_ReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext);
+
+/*!
+ \brief Handles the IOCTL calls.
+ \param DeviceObject Pointer to the device object utilized by the user.
+ \param Irp Pointer to the IRP containing the user request.
+ \return The status of the operation. See ntstatus.h in the DDK.
+
+ Once the packet capture driver is opened it can be configured from user-level applications with IOCTL commands
+ using the DeviceIoControl() system call. NPF_IoControl receives and serves all the IOCTL calls directed to NPF.
+ The following commands are recognized:
+ - #BIOCSETBUFFERSIZE
+ - #BIOCSETF
+ - #BIOCGSTATS
+ - #BIOCSRTIMEOUT
+ - #BIOCSMODE
+ - #BIOCSWRITEREP
+ - #BIOCSMINTOCOPY
+ - #BIOCSETOID
+ - #BIOCQUERYOID
+ - #BIOCSETDUMPFILENAME
+ - #BIOCGEVNAME
+ - #BIOCSENDPACKETSSYNC
+ - #BIOCSENDPACKETSNOSYNC
+*/
+NTSTATUS
+NPF_IoControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
);
+/*!
+ \brief Ends an OID request.
+ \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
+ \param pRequest Pointer to the completed OID request.
+ \param Status Status of the operation.
+
+ Callback function associated with the NdisRequest() NDIS function. It is invoked by NDIS when the NIC
+ driver has finished an OID request operation that was previously started by NPF_IoControl().
+*/
VOID
-PacketRequestComplete(
+NPF_RequestComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_REQUEST pRequest,
IN NDIS_STATUS Status
);
+/*!
+ \brief Writes a raw packet to the network.
+ \param DeviceObject Pointer to the device object on which the user wrote the packet.
+ \param Irp Pointer to the IRP containing the user request.
+ \return The status of the operation. See ntstatus.h in the DDK.
+
+ This function is called by the OS in consequence of user WriteFile() call, with the data of the packet that must
+ be sent on the net. The data is contained in the buffer associated with Irp, NPF_Write takes it and
+ delivers it to the NIC driver via the NdisSend() function. The Nwrites field of the OPEN_INSTANCE structure
+ associated with Irp indicates the number of copies of the packet that will be sent: more than one copy of the
+ packet can be sent for performance reasons.
+*/
+NTSTATUS
+NPF_Write(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+/*!
+ \brief Writes a buffer of raw packets to the network.
+ \param Irp Pointer to the IRP containing the user request.
+ \param UserBuff Pointer to the buffer containing the packets to send.
+ \param UserBuffSize Size of the buffer with the packets.
+ \return The amount of bytes actually sent. If the return value is smaller than the Size parameter, an
+ error occurred during the send. The error can be caused by an adapter problem or by an
+ inconsistent/bogus user buffer.
+
+ This function is called by the OS in consequence of a BIOCSENDPACKETSNOSYNC or a BIOCSENDPACKETSSYNC IOCTL.
+ The buffer received as input parameter contains an arbitrary number of packets, each of which preceded by a
+ sf_pkthdr structure. NPF_BufferedWrite() scans the buffer and sends every packet via the NdisSend() function.
+ When Sync is set to TRUE, the packets are synchronized with the KeQueryPerformanceCounter() function.
+ This requires a remarkable amount of CPU, but allows to respect the timestamps associated with packets with a precision
+ of some microseconds (depending on the precision of the performance counter of the machine).
+ If Sync is false, the timestamps are ignored and the packets are sent as fat as possible.
+*/
+
+INT NPF_BufferedWrite(IN PIRP Irp,
+ IN PCHAR UserBuff,
+ IN ULONG UserBuffSize,
+ BOOLEAN sync);
+
+/*!
+ \brief Ends a send operation.
+ \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
+ \param pRequest Pointer to the NDIS PACKET structure used by NPF_Write() to send the packet.
+ \param Status Status of the operation.
+
+ Callback function associated with the NdisSend() NDIS function. It is invoked by NDIS when the NIC
+ driver has finished an OID request operation that was previously started by NPF_Write().
+*/
VOID
-PacketSendComplete(
+NPF_SendComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pPacket,
IN NDIS_STATUS Status
);
+/*!
+ \brief Ends a reset of the adapter.
+ \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with the current instance.
+ \param Status Status of the operation.
+ Callback function associated with the NdisReset() NDIS function. It is invoked by NDIS when the NIC
+ driver has finished an OID request operation that was previously started by NPF_IoControl(), in an IOCTL_PROTOCOL_RESET
+ command.
+*/
VOID
-PacketResetComplete(
+NPF_ResetComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
);
-
+/*!
+ \brief Callback for NDIS StatusHandler. Not used by NPF
+*/
VOID
-PacketStatus(
+NPF_Status(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN PVOID StatusBuffer,
);
+/*!
+ \brief Callback for NDIS StatusCompleteHandler. Not used by NPF
+*/
VOID
-PacketStatusComplete(
- IN NDIS_HANDLE ProtocolBindingContext
- );
-
-VOID
-PacketTransferDataComplete(
- IN NDIS_HANDLE ProtocolBindingContext,
- IN PNDIS_PACKET Packet,
- IN NDIS_STATUS Status,
- IN UINT BytesTransferred
- );
+NPF_StatusComplete(IN NDIS_HANDLE ProtocolBindingContext);
+/*!
+ \brief Function called by the OS when NPF is unloaded.
+ \param DriverObject The driver object of NPF created by the system.
+ This is the last function executed when the driver is unloaded from the system. It frees global resources,
+ delete the devices and deregisters the protocol. The driver can be unloaded by the user stopping the NPF
+ service (from control panel or with a console 'net stop npf').
+*/
VOID
-PacketRemoveReference(
- IN PDEVICE_EXTENSION DeviceExtension
- );
-
-
+NPF_Unload(IN PDRIVER_OBJECT DriverObject);
+
+
+/*!
+ \brief Function that serves the user's reads.
+ \param DeviceObject Pointer to the device used by the user.
+ \param Irp Pointer to the IRP containing the user request.
+ \return The status of the operation. See ntstatus.h in the DDK.
+
+ This function is called by the OS in consequence of user ReadFile() call. It moves the data present in the
+ kernel buffer to the user buffer associated with Irp.
+ First of all, NPF_Read checks the amount of data in kernel buffer associated with current NPF instance.
+ - If the instance is in capture mode and the buffer contains more than OPEN_INSTANCE::MinToCopy bytes,
+ NPF_Read moves the data in the user buffer and returns immediatly. In this way, the read performed by the
+ user is not blocking.
+ - If the buffer contains less than MinToCopy bytes, the application's request isn't
+ satisfied immediately, but it's blocked until at least MinToCopy bytes arrive from the net
+ or the timeout on this read expires. The timeout is kept in the OPEN_INSTANCE::TimeOut field.
+ - If the instance is in statistical mode or in dump mode, the application's request is blocked until the
+ timeout kept in OPEN_INSTANCE::TimeOut expires.
+*/
NTSTATUS
-PacketCleanup(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP FlushIrp
- );
-
-
-NTSTATUS
-PacketShutdown(
+NPF_Read(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
-VOID
-STDCALL
-PacketUnload(
- IN PDRIVER_OBJECT DriverObject
- );
+/*!
+ \brief Reads the registry keys associated woth NPF if the driver is manually installed via the control panel.
+ Normally not used in recent versions of NPF.
+*/
NTSTATUS
-STDCALL
-PacketOpen(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-PacketClose(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-PacketWrite(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-PacketRead(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-PacketIoControl(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-DriverEntry(
- IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath
- );
-
-NTSTATUS
-PacketReadRegistry(
+NPF_ReadRegistry(
IN PWSTR *MacDriverName,
IN PWSTR *PacketDriverName,
IN PUNICODE_STRING RegistryPath
);
+/*!
+ \brief Function used by NPF_ReadRegistry() to quesry the registry keys associated woth NPF if the driver
+ is manually installed via the control panel.
+
+ Normally not used in recent versions of NPF.
+*/
NTSTATUS
-PacketCreateSymbolicLink(
- IN PUNICODE_STRING DeviceName,
- IN BOOLEAN Create
- );
-/*
-typedef NTSTATUS STDCALL
-(*PRTL_QUERY_REGISTRY_ROUTINE)(PWSTR ValueName,
- ULONG ValueType,
- PVOID ValueData,
- ULONG ValueLength,
- PVOID Context,
- PVOID EntryContext);
- DriverObject->MajorFunction[IRP_MJ_CREATE] = PacketOpen;
- DriverObject->MajorFunction[IRP_MJ_CLOSE] = PacketClose;
- DriverObject->MajorFunction[IRP_MJ_READ] = PacketRead;
- DriverObject->MajorFunction[IRP_MJ_WRITE] = PacketWrite;
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PacketIoControl;
- DriverObject->DriverUnload = PacketUnload;
- */
-NTSTATUS
-STDCALL
-PacketQueryRegistryRoutine(
+NPF_QueryRegistryRoutine(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN PVOID EntryContext
);
-INT
-Packet_multiple_tap(
- IN NDIS_HANDLE ProtocolBindingContext,
- IN PNDIS_PACKET Packet
- );
-
-VOID PacketBindAdapter(
+/*!
+ \brief Callback for NDIS BindAdapterHandler. Not used by NPF.
+
+ Function called by NDIS when a new adapter is installed on the machine With Plug and Play.
+*/
+VOID NPF_BindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING DeviceName,
IN PVOID SystemSpecific2
);
+/*!
+ \brief Callback for NDIS UnbindAdapterHandler.
+ \param Status out variable filled by NPF_UnbindAdapter with the status of the unbind operation.
+ \param ProtocolBindingContext Context of the function. Contains a pointer to the OPEN_INSTANCE structure associated with current instance.
+ \param UnbindContext Specifies a handle, supplied by NDIS, that NPF can use to complete the opration.
+
+ Function called by NDIS when a new adapter is removed from the machine without shutting it down.
+ NPF_UnbindAdapter closes the adapter calling NdisCloseAdapter() and frees the memory and the structures
+ associated with it. It also releases the waiting user-level app and closes the dump thread if the instance
+ is in dump mode.
+*/
VOID
-PacketUnbindAdapter(
+NPF_UnbindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE UnbindContext
);
-
-int bpf_validate(struct bpf_insn *f,int len);
-
+/*!
+ \brief Validates a filtering program arriving from the user-level app.
+ \param f The filter.
+ \param len Its length, in pseudo instructions.
+ \param mem_ex_size The length of the extended memory, used to validate LD/ST to that memory
+ \return true if f is a valid filter program..
+
+ The kernel needs to be able to verify an application's filter code. Otherwise, a bogus program could easily
+ crash the system.
+ This function returns true if f is a valid filter program. The constraints are that each jump be forward and
+ to a valid code. The code must terminate with either an accept or reject.
+*/
+int bpf_validate(struct bpf_insn *f,int len, uint32 mem_ex_size);
+
+/*!
+ \brief The filtering pseudo-machine interpreter.
+ \param pc The filter.
+ \param p Pointer to a memory buffer containing the packet on which the filter will be executed.
+ \param wirelen Original length of the packet.
+ \param buflen Current length of the packet. In some cases (for example when the transfer of the packet to the RAM
+ has not yet finished), bpf_filter can be executed on a portion of the packet.
+ \param mem_ex The extended memory.
+ \param tme The virtualization of the TME co-processor
+ \param time_ref Data structure needed by the TME co-processor to timestamp data
+ \return The portion of the packet to keep, in bytes. 0 means that the packet must be rejected, -1 means that
+ the whole packet must be kept.
+
+ \note this function is not used in normal situations, because the jitter creates a native filtering function
+ that is faster than the interpreter.
+*/
UINT bpf_filter(register struct bpf_insn *pc,
register UCHAR *p,
UINT wirelen,
- register UINT buflen);
-
+ register UINT buflen,
+ PMEM_TYPE mem_ex,
+ PTME_CORE tme,
+ struct time_conv *time_ref);
+
+/*!
+ \brief The filtering pseudo-machine interpreter with two buffers. This function is slower than bpf_filter(),
+ but works correctly also if the MAC header and the data of the packet are in two different buffers.
+ \param pc The filter.
+ \param p Pointer to a memory buffer containing the MAC header of the packet.
+ \param pd Pointer to a memory buffer containing the data of the packet.
+ \param wirelen Original length of the packet.
+ \param buflen Current length of the packet. In some cases (for example when the transfer of the packet to the RAM
+ has not yet finished), bpf_filter can be executed on a portion of the packet.
+ \param mem_ex The extended memory.
+ \param tme The virtualization of the TME co-processor
+ \param time_ref Data structure needed by the TME co-processor to timestamp data
+ \return The portion of the packet to keep, in bytes. 0 means that the packet must be rejected, -1 means that
+ the whole packet must be kept.
+
+ This function is used when NDIS passes the packet to NPF_tap() in two buffers instaed than in a single one.
+*/
UINT bpf_filter_with_2_buffers(register struct bpf_insn *pc,
register UCHAR *p,
register UCHAR *pd,
register int headersize,
UINT wirelen,
- register UINT buflen);
+ register UINT buflen,
+ PMEM_TYPE mem_ex,
+ PTME_CORE tme,
+ struct time_conv *time_ref);
+
+/*!
+ \brief Creates the file that will receive the packets when the driver is in dump mode.
+ \param Open The NPF instance that opens the file.
+ \param fileName Pointer to a UNICODE string containing the name of the file.
+ \param append Boolean value that specifies if the data must be appended to the file.
+ \return The status of the operation. See ntstatus.h in the DDK.
+*/
+NTSTATUS NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN append);
+
+/*!
+ \brief Starts dump to file.
+ \param Open The NPF instance that opens the file.
+ \return The status of the operation. See ntstatus.h in the DDK.
+
+ This function performs two operations. First, it writes the libpcap header at the beginning of the file.
+ Second, it starts the thread that asynchronously dumps the network data to the file.
+*/
+NTSTATUS NPF_StartDump(POPEN_INSTANCE Open);
+
+/*!
+ \brief The dump thread.
+ \param Open The NPF instance that creates the thread.
+
+ This function moves the content of the NPF kernel buffer to file. It runs in the user context, so at lower
+ priority than the TAP.
+*/
+VOID NPF_DumpThread(POPEN_INSTANCE Open);
+
+/*!
+ \brief Saves the content of the packet buffer to the file associated with current instance.
+ \param Open The NPF instance that creates the thread.
+
+ Used by NPF_DumpThread() and NPF_CloseDumpFile().
+*/
+NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open);
+
+/*!
+ \brief Writes a block of packets on the dump file.
+ \param FileObject The file object that will receive the packets.
+ \param Offset The offset in the file where the packets will be put.
+ \param Length The amount of bytes to write.
+ \param Mdl MDL mapping the memory buffer that will be written to disk.
+ \param IoStatusBlock Used by the function to return the status of the operation.
+ \return The status of the operation. See ntstatus.h in the DDK.
+
+ NPF_WriteDumpFile addresses directly the file system, creating a custom IRP and using it to send a portion
+ of the NPF circular buffer to disk. This function is used by NPF_DumpThread().
+*/
+VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER Offset,
+ ULONG Length,
+ PMDL Mdl,
+ PIO_STATUS_BLOCK IoStatusBlock);
+
+
+
+/*!
+ \brief Closes the dump file associated with an instance of the driver.
+ \param Open The NPF instance that closes the file.
+ \return The status of the operation. See ntstatus.h in the DDK.
+*/
+NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open);
+
+/*!
+ \brief Returns the amount of bytes present in the packet buffer.
+ \param Open The NPF instance that closes the file.
+*/
+UINT GetBuffOccupation(POPEN_INSTANCE Open);
+
+/*!
+ \brief Called by NDIS to notify us of a PNP event. The most significant one for us is power state change.
+
+ \param ProtocolBindingContext Pointer to open context structure. This is NULL for global reconfig
+ events.
+ \param pNetPnPEvent Pointer to the PnP event
+
+ If there is a power state change, the driver is forced to resynchronize the global timer.
+ This hopefully avoids the synchronization issues caused by hibernation or standby.
+ This function is excluded from the NT4 driver, where PnP is not supported
+*/
+#ifdef NDIS50
+NDIS_STATUS NPF_PowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent);
+#endif
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /*main ifndef/define*/
-VOID ReadTimeout(IN PKDPC Dpc,
- IN PVOID DeferredContext,
- IN PVOID SystemContext1,
- IN PVOID SystemContext2);
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,3,0,33
- PRODUCTVERSION 2,3,0,33
+ FILEVERSION 3,0,0,13
+ PRODUCTVERSION 3,0,0,13
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
BEGIN
VALUE "Comments", "Netgroup Packet Filter Driver\0"
VALUE "CompanyName", "Politecnico di Torino\0"
- VALUE "FileDescription", "NPF Driver\0"
- VALUE "FileVersion", "2, 3, 0, 33\0"
- VALUE "InternalName", "NPF\0"
+ VALUE "FileDescription", "NPF Driver - TME extensions\0"
+ VALUE "FileVersion", "3, 0, 0, 13\0"
+ VALUE "InternalName", "NPF + TME \0"
VALUE "LegalCopyright", "Copyright © 2002\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "NPF.RC\0"
- VALUE "PrivateBuild", "\0"
+ VALUE "PrivateBuild", "REACTOS PRIVATE BUILD\0"
VALUE "ProductName", "NPF Driver\0"
- VALUE "ProductVersion", "2, 3, 0, 33\0"
- VALUE "SpecialBuild", "\0"
+ VALUE "ProductVersion", "3, 0, 0, 13\0"
+ VALUE "SpecialBuild", "Beta testing use only\0"
END
END
BLOCK "VarFileInfo"
#include <ndis.h>
#else
#include <ddk/ntddk.h>
-//#include <net/miniport.h>
#include <net/ndis.h>
#endif
#include "debug.h"
#include "packet.h"
+#include "win_bpf.h"
+#include "tme.h"
+#include "time_calls.h"
+
+extern struct time_conv G_Start_Time; // from openclos.c
//-------------------------------------------------------------------
*Bhead+=n;
}
-
//-------------------------------------------------------------------
-NTSTATUS STDCALL
-PacketRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
+NTSTATUS
+NPF_Read(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
LARGE_INTEGER TimeFreq;
struct bpf_hdr *header;
KIRQL Irql;
+ PUCHAR UserPointer;
+ ULONG bytecopy;
- IF_LOUD(DbgPrint("Packet: Read\n");)
-
+ IF_LOUD(DbgPrint("NPF: Read\n");)
+
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Open=IrpSp->FileObject->FsContext;
-
- if( Open->Bound == FALSE){
- // The Network adapter was removed. Return immediately with a failure status
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return(STATUS_UNSUCCESSFUL);
+
+ if( Open->Bound == FALSE ){
+ // The Network adapter was removed.
+ EXIT_FAILURE(0);
}
+ if( Open->mode & MODE_DUMP && Open->DumpFileHandle == NULL ){
+ // this instance is in dump mode, but the dump file has still not been opened
+ EXIT_FAILURE(0);
+ }
+
//See if the buffer is full enough to be copied
- if (GetBuffOccupation(Open)<=Open->MinToCopy)
+ if( GetBuffOccupation(Open) <= Open->MinToCopy || Open->mode & MODE_DUMP )
{
- //there are not enough buffered packets: the application must wait
-
//wait until some packets arrive or the timeout expires
if(Open->TimeOut.QuadPart != (LONGLONG)IMMEDIATE)
KeWaitForSingleObject(Open->ReadEvent,
UserRequest,
KernelMode,
- TRUE ,
+ TRUE,
(Open->TimeOut.QuadPart == (LONGLONG)0)? NULL: &(Open->TimeOut));
KeClearEvent(Open->ReadEvent);
- if(Open->mode==MODE_STAT){ //this capture instance is in statistics mode
+ if(Open->mode & MODE_STAT){ //this capture instance is in statistics mode
CurrBuff=(PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress);
- //get the timestamp
- CapTime=KeQueryPerformanceCounter(&TimeFreq);
//fill the bpf header for this packet
- CapTime.QuadPart+=Open->StartTime.QuadPart;
header=(struct bpf_hdr*)CurrBuff;
-#ifndef __NTDRIVER__ // robert
- header->bh_tstamp.tv_usec=(long)((CapTime.QuadPart%TimeFreq.QuadPart*1000000)/TimeFreq.QuadPart);
- header->bh_tstamp.tv_sec=(long)(CapTime.QuadPart/TimeFreq.QuadPart);
-#endif
- header->bh_caplen=16;
- header->bh_datalen=16;
- header->bh_hdrlen=sizeof(struct bpf_hdr);
-
+ GET_TIME(&header->bh_tstamp,&G_Start_Time);
+
+ if(Open->mode & MODE_DUMP){
+ *(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr)+16)=Open->DumpOffset.QuadPart;
+ header->bh_caplen=24;
+ header->bh_datalen=24;
+ Irp->IoStatus.Information = 24 + sizeof(struct bpf_hdr);
+ }
+ else{
+ header->bh_caplen=16;
+ header->bh_datalen=16;
+ header->bh_hdrlen=sizeof(struct bpf_hdr);
+ Irp->IoStatus.Information = 16 + sizeof(struct bpf_hdr);
+ }
+
*(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr))=Open->Npackets.QuadPart;
*(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr)+8)=Open->Nbytes.QuadPart;
Open->Nbytes.QuadPart=0;
NdisReleaseSpinLock( &Open->CountersLock );
- Irp->IoStatus.Information = 16 + sizeof(struct bpf_hdr);
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
- if (Open->Bhead == Open->Btail)
- //the timeout has expired, but the buffer is still empty.
- //we must awake the application returning an empty buffer.
+ if(Open->mode==MODE_MON) //this capture instance is in monitor mode
+ {
+ PTME_DATA data;
+ ULONG cnt;
+ ULONG block_size;
+ PUCHAR tmp;
+
+ UserPointer=MmGetSystemAddressForMdl(Irp->MdlAddress);
+
+ if ((!IS_VALIDATED(Open->tme.validated_blocks,Open->tme.active_read))||(IrpSp->Parameters.Read.Length<sizeof(struct bpf_hdr)))
+ {
+ EXIT_FAILURE(0);
+ }
+
+ header=(struct bpf_hdr*)UserPointer;
+
+ GET_TIME(&header->bh_tstamp,&G_Start_Time);
+
+
+ header->bh_hdrlen=sizeof(struct bpf_hdr);
+
+
+ //moves user memory pointer
+ UserPointer+=sizeof(struct bpf_hdr);
+
+ //calculus of data to be copied
+ //if the user buffer is smaller than data to be copied,
+ //only some data will be copied
+ data=&Open->tme.block_data[Open->tme.active_read];
+
+ if (data->last_read.tv_sec!=0)
+ data->last_read=header->bh_tstamp;
+
+
+ bytecopy=data->block_size*data->filled_blocks;
+
+ if ((IrpSp->Parameters.Read.Length-sizeof(struct bpf_hdr))<bytecopy)
+ bytecopy=(IrpSp->Parameters.Read.Length-sizeof(struct bpf_hdr))/ data->block_size;
+ else
+ bytecopy=data->filled_blocks;
+
+ tmp=data->shared_memory_base_address;
+ block_size=data->block_size;
+
+ for (cnt=0;cnt<bytecopy;cnt++)
+ {
+ NdisAcquireSpinLock(&Open->machine_lock);
+ RtlCopyMemory(UserPointer,tmp,block_size);
+ NdisReleaseSpinLock(&Open->machine_lock);
+ tmp+=block_size;
+ UserPointer+=block_size;
+ }
+
+ bytecopy*=block_size;
+
+ header->bh_caplen=bytecopy;
+ header->bh_datalen=header->bh_caplen;
+
+ EXIT_SUCCESS(bytecopy+sizeof(struct bpf_hdr));
+ }
+
+ if (Open->Bhead == Open->Btail || Open->mode & MODE_DUMP)
+ // The timeout has expired, but the buffer is still empty (or the packets must be written to file).
+ // We must awake the application, returning an empty buffer.
{
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return(STATUS_SUCCESS);
+ EXIT_SUCCESS(0);
}
}
//
NdisAcquireSpinLock( &Open->BufLock );
- Thead=Open->Bhead;
- Ttail=Open->Btail;
- TLastByte=Open->BLastByte;
-
+ Thead = Open->Bhead;
+ Ttail = Open->Btail;
+ TLastByte = Open->BLastByte;
+
//get the address of the buffer
CurrBuff=Open->Buffer;
-
+
NdisReleaseSpinLock( &Open->BufLock );
Input_Buffer_Length=IrpSp->Parameters.Read.Length;
packp=(PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress);
-
+
//
//fill the application buffer
//
- if(Ttail>Thead){ //first of all see if it we can copy all the buffer in one time
+ if(Ttail > Thead){ //first of all see if it we can copy all the buffer in one time
if((Ttail-Thead)<Input_Buffer_Length){
KeResetEvent(Open->ReadEvent);
+
PacketMoveMem(packp,CurrBuff+Thead,Ttail-Thead,&(Open->Bhead));
- Irp->IoStatus.Information = Ttail-Thead;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return(STATUS_SUCCESS);
+ EXIT_SUCCESS(Ttail-Thead);
}
}
- else if((TLastByte-Thead)<Input_Buffer_Length){
- PacketMoveMem(packp,CurrBuff+Thead,TLastByte-Thead,&(Open->Bhead));
+ else if((TLastByte - Thead) < Input_Buffer_Length){
+ PacketMoveMem(packp, CurrBuff+Thead, TLastByte - Thead, &(Open->Bhead));
NdisAcquireSpinLock( &Open->BufLock );
- Open->BLastByte=Open->Btail;
- Open->Bhead=0;
+ Open->BLastByte = Open->Btail;
+ Open->Bhead = 0;
NdisReleaseSpinLock( &Open->BufLock );
- Irp->IoStatus.Information = TLastByte-Thead;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return(STATUS_SUCCESS);
+ EXIT_SUCCESS(TLastByte-Thead);
}
//the buffer must be scannned to determine the number of bytes to copy
- i=0;
CpStart=Thead;
+ i=0;
while(TRUE){
- if(Thead==Ttail)break;
+ if(Thead == Ttail)break;
- if(Thead==TLastByte){
+ if(Thead == TLastByte){
// Copy the portion between thead and TLastByte
PacketMoveMem(packp,CurrBuff+CpStart,Thead-CpStart,&(Open->Bhead));
packp+=(Thead-CpStart);
NdisAcquireSpinLock( &Open->BufLock );
- Open->BLastByte=Open->Btail;
- Open->Bhead=0;
+ Open->BLastByte = Open->Btail;
+ Open->Bhead = 0;
NdisReleaseSpinLock( &Open->BufLock );
-
+
Thead=0;
CpStart=0;
}
if((i+cplen > Input_Buffer_Length)){//no more space in the application's buffer
PacketMoveMem(packp,CurrBuff+CpStart,Thead-CpStart,&(Open->Bhead));
- Irp->IoStatus.Information = i;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return(STATUS_SUCCESS);
+ EXIT_SUCCESS(i);
}
cplen=Packet_WORDALIGN(cplen);
i+=cplen;
Open->Bhead=Thead;
- Irp->IoStatus.Information = i;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return(STATUS_SUCCESS);
+ EXIT_SUCCESS(i);
}
//-------------------------------------------------------------------
-NDIS_STATUS Packet_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE MacReceiveContext,
+NDIS_STATUS NPF_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,IN UINT HeaderBufferSize,IN PVOID LookAheadBuffer,
IN UINT LookaheadBufferSize,IN UINT PacketSize)
{
NDIS_STATUS Status;
UINT BytesTransfered;
ULONG BufferLength;
- PPACKET_RESERVED Reserved;
PMDL pMdl;
LARGE_INTEGER CapTime;
LARGE_INTEGER TimeFreq;
UINT TLastByte;
UINT fres;
UINT maxbufspace;
+ USHORT NPFHdrSize;
+ UINT BufOccupation;
- IF_LOUD(DbgPrint("Packet: tap\n");)
+ IF_VERY_LOUD(DbgPrint("NPF: tap\n");)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
- Open->Received++; //number of packets received by filter ++
+ Open->Received++; // Number of packets received by filter ++
+ BufOccupation = GetBuffOccupation(Open); // Get the full buffer space
+
+ if(((Open->mode&MODE_CAPT)||(Open->mode&MODE_DUMP)) && Open->BufSize - BufOccupation < PacketSize+HeaderBufferSize+sizeof(struct bpf_hdr)){
+ // Heuristic that drops the packet also if it possibly fits in the buffer.
+ // It allows to avoid filtering in critical situations when CPU is very important.
+ Open->Dropped++;
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ NdisAcquireSpinLock(&Open->machine_lock);
+
//
//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
LookAheadBuffer,
HeaderBufferSize,
PacketSize+HeaderBufferSize,
- LookaheadBufferSize+HeaderBufferSize);
- else
- fres=bpf_filter((struct bpf_insn*)(Open->bpfprogram),
- HeaderBuffer,
- PacketSize+HeaderBufferSize,
- LookaheadBufferSize+HeaderBufferSize);
+ LookaheadBufferSize+HeaderBufferSize,
+ &Open->mem_ex,
+ &Open->tme,
+ &G_Start_Time);
+
+
+ else
+ if(Open->Filter != NULL)
+ {
+ if (Open->bpfprogram != NULL)
+ {
+ fres=Open->Filter->Function(HeaderBuffer,
+ PacketSize+HeaderBufferSize,
+ LookaheadBufferSize+HeaderBufferSize);
+
+ // Restore the stack.
+ // I ignore the reason, but this instruction is needed only at kernel level
+#ifndef __GNUC__
+ _asm add esp,12
+#else
+#endif
+ }
+ else
+ fres = -1;
+ }
+ else
+ fres=bpf_filter((struct bpf_insn*)(Open->bpfprogram),
+ HeaderBuffer,
+ PacketSize+HeaderBufferSize,
+ LookaheadBufferSize+HeaderBufferSize,
+ &Open->mem_ex,
+ &Open->tme,
+ &G_Start_Time);
+
+ NdisReleaseSpinLock(&Open->machine_lock);
+
+ if(Open->mode==MODE_MON)
+ // we are in monitor mode
+ {
+ if (fres==1)
+ KeSetEvent(Open->ReadEvent,0,FALSE);
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ }
+
+ if(fres==0)
+ // Packet not accepted by the filter, ignore it.
+ return NDIS_STATUS_NOT_ACCEPTED;
- if(fres==0)return NDIS_STATUS_NOT_ACCEPTED; //packet not accepted by the filter
//if the filter returns -1 the whole packet must be accepted
if(fres==-1 || fres > PacketSize+HeaderBufferSize)fres=PacketSize+HeaderBufferSize;
-
- if(Open->mode==MODE_STAT){
+ if(Open->mode & MODE_STAT){
// we are in statistics mode
NdisAcquireSpinLock( &Open->CountersLock );
Open->Npackets.QuadPart++;
-
+
if(PacketSize+HeaderBufferSize<60)
Open->Nbytes.QuadPart+=60;
else
Open->Nbytes.QuadPart+=12;
NdisReleaseSpinLock( &Open->CountersLock );
-
- return NDIS_STATUS_NOT_ACCEPTED;
+
+ if(!(Open->mode & MODE_DUMP)){
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
}
if(Open->BufSize==0)return NDIS_STATUS_NOT_ACCEPTED;
+
+ if(Open->mode & MODE_DUMP && Open->MaxDumpPacks && (UINT)Open->Accepted > Open->MaxDumpPacks){
+ // Reached the max number of packets to save in the dump file. Discard the packet and stop the dump thread.
+ Open->DumpLimitReached = TRUE; // This stops the thread
+ // Awake the dump thread
+ NdisSetEvent(&Open->DumpEvent);
+
+ // Awake the application
+ KeSetEvent(Open->ReadEvent,0,FALSE);
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ // Calculate the correct size for the header associated with the packet
+ NPFHdrSize=(Open->mode==MODE_CAPT)? sizeof(struct bpf_hdr): sizeof(struct sf_pkthdr);
+
NdisAcquireSpinLock( &Open->BufLock );
Thead=Open->Bhead;
Ttail=Open->Btail;
- TLastByte=Open->BLastByte;
- NdisReleaseSpinLock( &Open->BufLock );
-
- maxbufspace=Packet_WORDALIGN(fres+sizeof(struct bpf_hdr));
+ TLastByte = Open->BLastByte;
- if((Ttail < Thead) && (Ttail+maxbufspace+1 >= Thead))
- {
- //the buffer is full: the incoming packet is lost
- Open->Dropped++;
- return NDIS_STATUS_NOT_ACCEPTED;
- }
+ NdisReleaseSpinLock( &Open->BufLock );
+
+ maxbufspace=Packet_WORDALIGN(fres+NPFHdrSize);
if(Ttail+maxbufspace >= Open->BufSize){
- if(Thead<=maxbufspace)
+ if(Thead <= maxbufspace)
{
- //the buffer is full: the packet is lost
Open->Dropped++;
return NDIS_STATUS_NOT_ACCEPTED;
}
}
CurrBuff=Open->Buffer+Ttail;
-
- // Allocate an MDL to map the portion of the buffer following the
- // header
- pMdl=IoAllocateMdl(CurrBuff+HeaderBufferSize+LookaheadBufferSize+sizeof(struct bpf_hdr),maxbufspace,FALSE,FALSE,NULL);
- if (pMdl == NULL)
- {
- //no memory: packet lost
- IF_LOUD(DbgPrint("Packet: Read-Failed to allocate Mdl\n");)
- Open->Dropped++;
- return NDIS_STATUS_NOT_ACCEPTED;
- }
- MmBuildMdlForNonPagedPool(pMdl);
-
- //allocate the packet from NDIS
- NdisAllocatePacket(&Status,&pPacketb,Open->PacketPool);
- if (Status != NDIS_STATUS_SUCCESS)
+
+ if(LookaheadBufferSize != PacketSize || (UINT)LookAheadBuffer-(UINT)HeaderBuffer != HeaderBufferSize)
{
- IF_LOUD(DbgPrint("Packet: Read- No free packets\n");)
+ // Allocate an MDL to map the portion of the buffer following the header
+ pMdl=IoAllocateMdl(CurrBuff+HeaderBufferSize+LookaheadBufferSize+NPFHdrSize,
+ maxbufspace,
+ FALSE,
+ FALSE,
+ NULL);
+
+ if (pMdl == NULL)
+ {
+ // Unable to map the memory: packet lost
+ IF_LOUD(DbgPrint("NPF: Read-Failed to allocate Mdl\n");)
+ Open->Dropped++;
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+ MmBuildMdlForNonPagedPool(pMdl);
+
+ //allocate the packet from NDIS
+ NdisAllocatePacket(&Status, &pPacketb, Open->PacketPool);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ IF_LOUD(DbgPrint("NPF: Tap - No free packets\n");)
IoFreeMdl(pMdl);
- Open->Dropped++;
- return NDIS_STATUS_NOT_ACCEPTED;
- }
- //link the buffer to the packet
- NdisChainBufferAtFront(pPacketb,pMdl);
+ Open->Dropped++;
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+ //link the buffer to the packet
+ NdisChainBufferAtFront(pPacketb,pMdl);
- //Find out how much to transfer
- SizeToTransfer = fres-HeaderBufferSize;
-
- //copy the ethernet header into buffer
- NdisMoveMappedMemory((CurrBuff)+sizeof(struct bpf_hdr),HeaderBuffer,HeaderBufferSize);
-
- //Copy the look ahead buffer
- if(LookaheadBufferSize)
- {
- NdisMoveMappedMemory((CurrBuff)+sizeof(struct bpf_hdr) + HeaderBufferSize,
- LookAheadBuffer,
- (SizeToTransfer < LookaheadBufferSize)? SizeToTransfer : LookaheadBufferSize );
+ BufferLength=fres-HeaderBufferSize;
+ //Find out how much to transfer
+ SizeToTransfer = (PacketSize < BufferLength) ? PacketSize : BufferLength;
+
+ //copy the ethernet header into buffer
+ NdisMoveMappedMemory((CurrBuff)+NPFHdrSize,HeaderBuffer,HeaderBufferSize);
+
+ //Copy the look ahead buffer
+ if(LookaheadBufferSize)
+ {
+ NdisMoveMappedMemory((CurrBuff) + NPFHdrSize + HeaderBufferSize,
+ LookAheadBuffer,
+ (SizeToTransfer < LookaheadBufferSize)? SizeToTransfer : LookaheadBufferSize );
+
+ SizeToTransfer = (SizeToTransfer > LookaheadBufferSize)?
+ SizeToTransfer - LookaheadBufferSize : 0;
+ }
+
+ Open->TransferMdl=pMdl;
+
+ if(SizeToTransfer)
+ {
+ //Call the Mac to transfer the packet
+ NdisTransferData(&Status,
+ Open->AdapterHandle,
+ MacReceiveContext,
+ LookaheadBufferSize,
+ SizeToTransfer,
+ pPacketb,
+ &BytesTransfered);
+ }
+ else{
+ BytesTransfered = 0;
+ }
- SizeToTransfer = (SizeToTransfer > LookaheadBufferSize)?
- SizeToTransfer - LookaheadBufferSize : 0;
}
-
- Open->TransferMdl=pMdl;
-
- if(SizeToTransfer)
+ else
{
- //Call the Mac to transfer the packet
- NdisTransferData(&Status,
- Open->AdapterHandle,
- MacReceiveContext,
- LookaheadBufferSize,
- SizeToTransfer,
- pPacketb,
- &BytesTransfered);
- }
- else{
- BytesTransfered = 0;
+ // The whole packet is in the lookahead buffer, we can avoid the call to NdisTransferData.
+ // This allows us to avoid the allocation of the MDL and the NDIS packet as well
+ RtlCopyMemory((CurrBuff) + NPFHdrSize,
+ HeaderBuffer,
+ HeaderBufferSize + LookaheadBufferSize);
+
+ Open->TransferMdl = NULL;
+ Status = NDIS_STATUS_SUCCESS;
}
+ Open->Accepted++; // Increase the accepted packets counter
+
if (Status != NDIS_STATUS_FAILURE)
{
- //store the capture time
- CapTime=KeQueryPerformanceCounter(&TimeFreq);
if( fres > (BytesTransfered+HeaderBufferSize+LookaheadBufferSize) )
fres = BytesTransfered+HeaderBufferSize+LookaheadBufferSize;
-
- //fill the bpf header for this packet
- CapTime.QuadPart+=Open->StartTime.QuadPart;
+
+ //
+ // Build the header
+ //
header=(struct bpf_hdr*)CurrBuff;
-#ifndef __NTDRIVER__ // robert
- header->bh_tstamp.tv_usec=(long)((CapTime.QuadPart%TimeFreq.QuadPart*1000000)/TimeFreq.QuadPart);
- header->bh_tstamp.tv_sec=(long)(CapTime.QuadPart/TimeFreq.QuadPart);
-#endif
- header->bh_caplen=fres;
+ GET_TIME(&header->bh_tstamp,&G_Start_Time);
+ header->bh_caplen=fres;
header->bh_datalen=PacketSize+HeaderBufferSize;
- header->bh_hdrlen=sizeof(struct bpf_hdr);
+ if(Open->mode==MODE_CAPT){
+ header->bh_hdrlen=NPFHdrSize;
+ // Don't align if the packet goes to disk
+ Ttail+=Packet_WORDALIGN(fres + NPFHdrSize);
+ }
+ else
+ Ttail+=fres+NPFHdrSize;
//update the buffer
- Ttail+=Packet_WORDALIGN(fres+sizeof(struct bpf_hdr));
-
- if(Ttail>Thead)TLastByte=Ttail;
+ if(Ttail > Thead)TLastByte = Ttail;
NdisAcquireSpinLock( &Open->BufLock );
+
Open->Btail=Ttail;
Open->BLastByte=TLastByte;
+
NdisReleaseSpinLock( &Open->BufLock );
-
}
+
if (Status != NDIS_STATUS_PENDING){
- PacketTransferDataComplete(Open,pPacketb,Status,fres);
+
+ if( Open->TransferMdl != NULL)
+ // Complete the request and free the buffers
+ NPF_TransferDataComplete(Open,pPacketb,Status,fres);
+ else{
+ // Unfreeze the consumer
+ if(GetBuffOccupation(Open)>Open->MinToCopy){
+ if(Open->mode & MODE_DUMP){
+ NdisSetEvent(&Open->DumpEvent);
+ }
+ else
+ KeSetEvent(Open->ReadEvent,0,FALSE);
+ }
+
+ }
}
return NDIS_STATUS_SUCCESS;
//-------------------------------------------------------------------
-VOID PacketTransferDataComplete (IN NDIS_HANDLE ProtocolBindingContext,IN PNDIS_PACKET pPacket,
+VOID NPF_TransferDataComplete (IN NDIS_HANDLE ProtocolBindingContext,IN PNDIS_PACKET pPacket,
IN NDIS_STATUS Status,IN UINT BytesTransfered)
{
POPEN_INSTANCE Open;
- IF_LOUD(DbgPrint("Packet: TransferDataComplete\n");)
+ IF_LOUD(DbgPrint("NPF: TransferDataComplete\n");)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
NdisReinitializePacket(pPacket);
//Put the packet on the free queue
NdisFreePacket(pPacket);
- //Unfreeze PacketRead
- if(GetBuffOccupation(Open)>Open->MinToCopy)
- KeSetEvent(Open->ReadEvent,0,FALSE);
-
+ // Unfreeze the consumer
+ if(GetBuffOccupation(Open)>Open->MinToCopy){
+ if(Open->mode & MODE_DUMP){
+ NdisSetEvent(&Open->DumpEvent);
+ }
+ else
+ KeSetEvent(Open->ReadEvent,0,FALSE);
+ }
return;
}
//-------------------------------------------------------------------
-VOID PacketReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext)
+VOID NPF_ReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext)
{
- IF_LOUD(DbgPrint("Packet: PacketReceiveComplete\n");)
+ IF_VERY_LOUD(DbgPrint("NPF: NPF_ReceiveComplete\n");)
return;
}
-
--- /dev/null
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by NPF.RC
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef WIN32
+#include "tme.h"
+#include "tcp_session.h"
+#endif
+
+#ifdef __FreeBSD
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#include <net/tme/tcp_session.h>
+#else
+#include <tme/tme.h>
+#include <tme/tcp_session.h>
+#endif
+
+#endif
+
+uint32 tcp_session(uint8 *block, uint32 pkt_size, TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data)
+
+{
+
+ uint32 next_status;
+ uint32 direction=ULONG_AT(mem_data,12);
+ uint8 flags=mem_ex->buffer[25];
+ tcp_data *session=(tcp_data*)(block+data->key_len*4);
+
+ session->last_timestamp=session->timestamp_block;
+ session->timestamp_block.tv_sec=0x7fffffff;
+
+ if (direction==session->direction)
+ {
+ session->pkts_cln_to_srv++;
+ session->bytes_cln_to_srv+=pkt_size;
+ }
+ else
+ {
+ session->pkts_srv_to_cln++;
+ session->bytes_srv_to_cln+=pkt_size;
+ }
+ /* we use only thes four flags, we don't need PSH or URG */
+ flags&=(ACK|FIN|SYN|RST);
+
+ switch (session->status)
+ {
+ case ERROR_TCP:
+ next_status=ERROR_TCP;
+ break;
+
+ case UNKNOWN:
+ if (flags==SYN)
+ {
+ if (SW_ULONG_AT(mem_ex->buffer,20)!=0)
+ {
+
+ next_status=ERROR_TCP;
+ break;
+ }
+ next_status=SYN_RCV;
+ session->syn_timestamp=session->last_timestamp;
+
+ session->direction=direction;
+ session->seq_n_0_cln=SW_ULONG_AT(mem_ex->buffer,16);
+ }
+ else
+ next_status=UNKNOWN;
+ break;
+
+ case SYN_RCV:
+ if ((flags&RST)&&(direction!=session->direction))
+ {
+ next_status=CLOSED_RST;
+ break;
+ }
+ if ((flags==SYN)&&(direction==session->direction))
+ { /* two syns... */
+ next_status=SYN_RCV;
+ session->seq_n_0_cln=SW_ULONG_AT(mem_ex->buffer,16);
+ break;
+ }
+
+ if ((flags==(SYN|ACK))&&(direction!=session->direction))
+ {
+ if (SW_ULONG_AT(mem_ex->buffer,20)!=session->seq_n_0_cln+1)
+ {
+ next_status=ERROR_TCP;
+ break;
+ }
+ next_status=SYN_ACK_RCV;
+
+ session->syn_ack_timestamp=session->last_timestamp;
+
+ session->seq_n_0_srv=SW_ULONG_AT(mem_ex->buffer,16);
+ session->ack_cln=session->seq_n_0_cln+1;
+ }
+ else
+ {
+ next_status=ERROR_TCP;
+ }
+ break;
+
+ case SYN_ACK_RCV:
+ if ((flags&ACK)&&(flags&RST)&&(direction==session->direction))
+ {
+ next_status=CLOSED_RST;
+ session->ack_srv=SW_ULONG_AT(mem_ex->buffer,20);
+ break;
+ }
+
+ if ((flags==ACK)&&(!(flags&(SYN|FIN|RST)))&&(direction==session->direction))
+ {
+ if (SW_ULONG_AT(mem_ex->buffer,20)!=session->seq_n_0_srv+1)
+ {
+ next_status=ERROR_TCP;
+ break;
+ }
+ next_status=ESTABLISHED;
+ session->ack_srv=session->seq_n_0_srv+1;
+ break;
+ }
+ if ((flags&ACK)&&(flags&SYN)&&(direction!=session->direction))
+ {
+ next_status=SYN_ACK_RCV;
+ break;
+ }
+
+ next_status=ERROR_TCP;
+ break;
+
+ case ESTABLISHED:
+ if (flags&SYN)
+ {
+ if ((flags&ACK)&&
+ (direction!=session->direction)&&
+ ((session->ack_cln-SW_ULONG_AT(mem_ex->buffer,20))<MAX_WINDOW)
+ )
+ { /* SYN_ACK duplicato */
+ next_status=ESTABLISHED;
+ break;
+ }
+
+ if ((!(flags&ACK))&&
+ (direction==session->direction)&&
+ (SW_ULONG_AT(mem_ex->buffer,16)==session->seq_n_0_cln)&&
+ (ULONG_AT(mem_ex->buffer,20)==0)
+ )
+ { /* syn duplicato */
+ next_status=ESTABLISHED;
+ break;
+ }
+
+ next_status=ERROR_TCP;
+ break;
+ }
+ if (flags&ACK)
+ if (direction==session->direction)
+ {
+ uint32 new_ack=SW_ULONG_AT(mem_ex->buffer,20);
+ if (new_ack-session->ack_srv<MAX_WINDOW)
+ session->ack_srv=new_ack;
+ }
+ else
+ {
+ uint32 new_ack=SW_ULONG_AT(mem_ex->buffer,20);
+ if (new_ack-session->ack_cln<MAX_WINDOW)
+ session->ack_cln=new_ack;
+ }
+ if (flags&RST)
+ {
+ next_status=CLOSED_RST;
+ break;
+ }
+ if (flags&FIN)
+ if (direction==session->direction)
+ { /* an hack to make all things work */
+ session->ack_cln=SW_ULONG_AT(mem_ex->buffer,16);
+ next_status=FIN_CLN_RCV;
+ break;
+ }
+ else
+ {
+ session->ack_srv=SW_ULONG_AT(mem_ex->buffer,16);
+ next_status=FIN_SRV_RCV;
+ break;
+ }
+ next_status=ESTABLISHED;
+ break;
+
+ case CLOSED_RST:
+ next_status=CLOSED_RST;
+ break;
+
+ case FIN_SRV_RCV:
+ if (flags&SYN)
+ {
+ next_status=ERROR_TCP;
+ break;
+ }
+
+ next_status=FIN_SRV_RCV;
+
+ if (flags&ACK)
+ {
+ uint32 new_ack=SW_ULONG_AT(mem_ex->buffer,20);
+ if (direction!=session->direction)
+ if ((new_ack-session->ack_cln)<MAX_WINDOW)
+ session->ack_cln=new_ack;
+ }
+
+ if (flags&RST)
+ next_status=CLOSED_RST;
+ else
+ if ((flags&FIN)&&(direction==session->direction))
+ {
+ session->ack_cln=SW_ULONG_AT(mem_ex->buffer,16);
+ next_status=CLOSED_FIN;
+ }
+
+ break;
+
+ case FIN_CLN_RCV:
+ if (flags&SYN)
+ {
+ next_status=ERROR_TCP;
+ break;
+ }
+
+ next_status=FIN_CLN_RCV;
+
+ if (flags&ACK)
+ {
+ uint32 new_ack=SW_ULONG_AT(mem_ex->buffer,20);
+ if (direction==session->direction)
+ if (new_ack-session->ack_srv<MAX_WINDOW)
+ session->ack_srv=new_ack;
+ }
+
+ if (flags&RST)
+ next_status=CLOSED_RST;
+ else
+ if ((flags&FIN)&&(direction!=session->direction))
+ {
+ session->ack_srv=SW_ULONG_AT(mem_ex->buffer,16);
+ next_status=CLOSED_FIN;
+ }
+
+ break;
+
+ case CLOSED_FIN:
+ next_status=CLOSED_FIN;
+ break;
+ default:
+ next_status=ERROR_TCP;
+
+ }
+
+ session->status=next_status;
+
+ if ((next_status==CLOSED_FIN)||(next_status==UNKNOWN)||(next_status==CLOSED_RST)||(next_status==ERROR_TCP))
+ session->timestamp_block=session->last_timestamp;
+
+ return TME_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __tcp_session
+#define __tcp_session
+
+#ifdef WIN32
+#include "tme.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#else
+#include <tme/tme.h>
+#endif
+
+#endif
+
+#define UNKNOWN 0
+#define SYN_RCV 1
+#define SYN_ACK_RCV 2
+#define ESTABLISHED 3
+#define CLOSED_RST 4
+#define FIN_CLN_RCV 5
+#define FIN_SRV_RCV 6
+#define CLOSED_FIN 7
+#define ERROR_TCP 8
+#define FIRST_IS_CLN 0
+#define FIRST_IS_SRV 0xffffffff
+#define FIN_CLN 1
+#define FIN_SRV 2
+
+#define MAX_WINDOW 65536
+
+typedef struct __tcp_data
+{
+ struct timeval timestamp_block; /*DO NOT MOVE THIS VALUE*/
+ struct timeval syn_timestamp;
+ struct timeval last_timestamp;
+ struct timeval syn_ack_timestamp;
+ uint32 direction;
+ uint32 seq_n_0_srv;
+ uint32 seq_n_0_cln;
+ uint32 ack_srv; /* acknowledge of (data sent by server) */
+ uint32 ack_cln; /* acknowledge of (data sent by client) */
+ uint32 status;
+ uint32 pkts_cln_to_srv;
+ uint32 pkts_srv_to_cln;
+ uint32 bytes_srv_to_cln;
+ uint32 bytes_cln_to_srv;
+ uint32 close_state;
+}
+ tcp_data;
+
+#define FIN 1
+#define SYN 2
+#define RST 4
+#define PSH 8
+#define ACK 16
+#define URG 32
+
+#define TCP_SESSION 0x00000800
+uint32 tcp_session(uint8 *block, uint32 pkt_size, TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data);
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "tme.h"
+#include "win_bpf.h"
+#include "time_calls.h"
+
+
+void TIME_DESYNCHRONIZE(struct time_conv *data)
+{
+#ifndef __GNUC__
+ data->reference = 0;
+ data->start.tv_sec = 0;
+ data->start.tv_usec = 0;
+#endif
+}
+
+#ifdef KQPC_TS
+
+/* KeQueryPerformanceCounter TimeStamps */
+
+VOID TIME_SYNCHRONIZE(struct time_conv *data)
+{
+#ifndef __GNUC__
+ struct timeval tmp;
+ LARGE_INTEGER SystemTime;
+ LARGE_INTEGER i;
+ ULONG tmp2;
+ LARGE_INTEGER TimeFreq,PTime;
+
+ if (data->reference!=0)
+ return;
+
+ // get the absolute value of the system boot time.
+ PTime=KeQueryPerformanceCounter(&TimeFreq);
+ KeQuerySystemTime(&SystemTime);
+ tmp.tv_sec=(LONG)(SystemTime.QuadPart/10000000-11644473600);
+ tmp.tv_usec=(LONG)((SystemTime.QuadPart%10000000)/10);
+ tmp.tv_sec-=(ULONG)(PTime.QuadPart/TimeFreq.QuadPart);
+ tmp.tv_usec-=(LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
+ if (tmp.tv_usec<0) {
+ tmp.tv_sec--;
+ tmp.tv_usec+=1000000;
+ }
+ data->start=tmp;
+ data->reference=1;
+#endif
+}
+
+void FORCE_TIME(struct timeval *src, struct time_conv *dest)
+{
+ dest->start=*src;
+}
+
+void GET_TIME(struct timeval *dst, struct time_conv *data)
+{
+#ifndef __GNUC__
+ LARGE_INTEGER PTime, TimeFreq;
+ LONG tmp;
+
+ PTime=KeQueryPerformanceCounter(&TimeFreq);
+ tmp=(LONG)(PTime.QuadPart/TimeFreq.QuadPart);
+ dst->tv_sec=data->start.tv_sec+tmp;
+ dst->tv_usec=data->start.tv_usec+(LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
+ if (dst->tv_usec>=1000000) {
+ dst->tv_sec++;
+ dst->tv_usec-=1000000;
+ }
+#endif
+}
+
+#else
+
+/*RDTSC timestamps*/
+
+/* callers must be at IRQL=PASSIVE_LEVEL */
+VOID TIME_SYNCHRONIZE(struct time_conv *data)
+{
+#ifndef __GNUC__
+ struct timeval tmp;
+ LARGE_INTEGER system_time;
+ ULONGLONG curr_ticks;
+ KIRQL old;
+ LARGE_INTEGER start_kqpc,stop_kqpc,start_freq,stop_freq;
+ ULONGLONG start_ticks,stop_ticks;
+ ULONGLONG delta,delta2;
+ KEVENT event;
+ LARGE_INTEGER i;
+ ULONGLONG reference;
+
+ if (data->reference!=0)
+ return;
+
+ KeInitializeEvent(&event,NotificationEvent,FALSE);
+ i.QuadPart=-3500000;
+ KeRaiseIrql(HIGH_LEVEL,&old);
+ start_kqpc=KeQueryPerformanceCounter(&start_freq);
+#ifndef __GNUC__
+ __asm
+ {
+ push eax
+ push edx
+ push ecx
+ rdtsc
+ lea ecx, start_ticks
+ mov [ecx+4], edx
+ mov [ecx], eax
+ pop ecx
+ pop edx
+ pop eax
+ }
+#else
+#endif
+ KeLowerIrql(old);
+ KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i);
+ KeRaiseIrql(HIGH_LEVEL,&old);
+ stop_kqpc=KeQueryPerformanceCounter(&stop_freq);
+#ifndef __GNUC__
+ __asm
+ {
+ push eax
+ push edx
+ push ecx
+ rdtsc
+ lea ecx, stop_ticks
+ mov [ecx+4], edx
+ mov [ecx], eax
+ pop ecx
+ pop edx
+ pop eax
+ }
+#else
+#endif
+ KeLowerIrql(old);
+ delta=stop_ticks-start_ticks;
+ delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart;
+ if (delta>10000000000) {
+ delta/=16;
+ delta2/=16;
+ }
+ reference=delta*(start_freq.QuadPart)/delta2;
+ data->reference=reference/1000;
+ if (reference%1000>500)
+ data->reference++;
+ data->reference*=1000;
+ reference=data->reference;
+ KeQuerySystemTime(&system_time);
+#ifndef __GNUC__
+ __asm
+ {
+ push eax
+ push edx
+ push ecx
+ rdtsc
+ lea ecx, curr_ticks
+ mov [ecx+4], edx
+ mov [ecx], eax
+ pop ecx
+ pop edx
+ pop eax
+ }
+#else
+#endif
+ tmp.tv_sec=-(LONG)(curr_ticks/reference);
+ tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference);
+ system_time.QuadPart-=116444736000000000;
+ tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000);
+ tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10);
+ if (tmp.tv_usec<0) {
+ tmp.tv_sec--;
+ tmp.tv_usec+=1000000;
+ }
+ data->start=tmp;
+ IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);)
+#else
+#endif
+}
+
+void FORCE_TIME(struct timeval *src, struct time_conv *dest)
+{
+ dest->start=*src;
+}
+
+void GET_TIME(struct timeval *dst, struct time_conv *data)
+{
+#ifndef __GNUC__
+ ULONGLONG tmp;
+#ifndef __GNUC__
+ __asm
+ {
+ push eax
+ push edx
+ push ecx
+ rdtsc
+ lea ecx, tmp
+ mov [ecx+4], edx
+ mov [ecx], eax
+ pop ecx
+ pop edx
+ pop eax
+ }
+#else
+#endif
+ if (data->reference==0) {
+ return;
+ }
+ dst->tv_sec=(LONG)(tmp/data->reference);
+ dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference);
+ dst->tv_sec+=data->start.tv_sec;
+ dst->tv_usec+=data->start.tv_usec;
+ if (dst->tv_usec>=1000000) {
+ dst->tv_sec++;
+ dst->tv_usec-=1000000;
+ }
+#endif
+}
+
+#endif /*KQPC_TS*/
--- /dev/null
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _time_calls
+#define _time_calls
+
+#ifdef WIN_NT_DRIVER
+
+#include "debug.h"
+
+/*!
+ \brief A microsecond precise timestamp.
+
+ included in the sf_pkthdr or the bpf_hdr that NPF associates with every packet.
+*/
+
+struct timeval {
+ long tv_sec; ///< seconds
+ long tv_usec; ///< microseconds
+};
+
+#endif /*WIN_NT_DRIVER*/
+
+struct time_conv {
+ ULONGLONG reference;
+ struct timeval start;
+};
+
+#ifdef __GNUC__
+
+void TIME_DESYNCHRONIZE(struct time_conv *data);
+VOID TIME_SYNCHRONIZE(struct time_conv *data);
+void FORCE_TIME(struct timeval *src, struct time_conv *dest);
+void&n