diff --git a/reactos/drivers/net/packet/.cvsignore b/reactos/drivers/net/packet/.cvsignore new file mode 100644 index 00000000000..d7687d40e6b --- /dev/null +++ b/reactos/drivers/net/packet/.cvsignore @@ -0,0 +1,5 @@ +*.coff +*.d +*.o +*.sym +*.sys diff --git a/reactos/drivers/net/packet/Makefile b/reactos/drivers/net/packet/Makefile index e93ab64e6df..0b0ebc5dda2 100644 --- a/reactos/drivers/net/packet/Makefile +++ b/reactos/drivers/net/packet/Makefile @@ -1,4 +1,4 @@ -# $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 = ../../.. @@ -7,15 +7,26 @@ TARGET_TYPE = driver 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 diff --git a/reactos/drivers/net/packet/bucket_lookup.c b/reactos/drivers/net/packet/bucket_lookup.c new file mode 100644 index 00000000000..e2c5fde7461 --- /dev/null +++ b/reactos/drivers/net/packet/bucket_lookup.c @@ -0,0 +1,251 @@ +/* + * 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 +#include +#else +#include +#include +#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((valueSW_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 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((valueSW_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 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 diff --git a/reactos/drivers/net/packet/bucket_lookup.h b/reactos/drivers/net/packet/bucket_lookup.h new file mode 100644 index 00000000000..ffe4523ce5b --- /dev/null +++ b/reactos/drivers/net/packet/bucket_lookup.h @@ -0,0 +1,43 @@ +/* + * 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 +#else +#include +#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 diff --git a/reactos/drivers/net/packet/count_packets.c b/reactos/drivers/net/packet/count_packets.c new file mode 100644 index 00000000000..71aa61f3ffc --- /dev/null +++ b/reactos/drivers/net/packet/count_packets.c @@ -0,0 +1,51 @@ +/* + * 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 +#include +#else +#include +#include +#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; + +} diff --git a/reactos/drivers/net/packet/count_packets.h b/reactos/drivers/net/packet/count_packets.h new file mode 100644 index 00000000000..05999643d62 --- /dev/null +++ b/reactos/drivers/net/packet/count_packets.h @@ -0,0 +1,51 @@ +/* + * 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 +#else +#include +#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 + diff --git a/reactos/drivers/net/packet/debug.h b/reactos/drivers/net/packet/debug.h index da2f518ddcd..9fcd26b80ec 100644 --- a/reactos/drivers/net/packet/debug.h +++ b/reactos/drivers/net/packet/debug.h @@ -19,6 +19,8 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +#ifndef __DEBUG_INCLUDE +#define __DEBUG_INCLUDE #if DBG @@ -46,3 +48,5 @@ extern ULONG PacketDebugFlag; #define IF_INIT_LOUD(A) #endif + +#endif /*#define __DEBUG_INCLUDE*/ diff --git a/reactos/drivers/net/packet/dump.c b/reactos/drivers/net/packet/dump.c new file mode 100644 index 00000000000..e7c40fbd154 --- /dev/null +++ b/reactos/drivers/net/packet/dump.c @@ -0,0 +1,587 @@ +/* + * 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 +#include +#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; + +} diff --git a/reactos/drivers/net/packet/functions.c b/reactos/drivers/net/packet/functions.c new file mode 100644 index 00000000000..04c7e4b7586 --- /dev/null +++ b/reactos/drivers/net/packet/functions.c @@ -0,0 +1,82 @@ +/* + * 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 +#include +#include +#else +#include +#include +#include +#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; +} diff --git a/reactos/drivers/net/packet/functions.h b/reactos/drivers/net/packet/functions.h new file mode 100644 index 00000000000..91f242a8031 --- /dev/null +++ b/reactos/drivers/net/packet/functions.h @@ -0,0 +1,67 @@ +/* + * 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 +#else +#include +#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 +#include +#endif + +/* execution functions */ + +#ifdef WIN32 +#include "count_packets.h" +#include "tcp_session.h" +#endif + +#ifdef __FreeBSD__ +#include +#include +#endif + +#endif \ No newline at end of file diff --git a/reactos/drivers/net/packet/jitter.c b/reactos/drivers/net/packet/jitter.c new file mode 100644 index 00000000000..4a71a7c674f --- /dev/null +++ b/reactos/drivers/net/packet/jitter.c @@ -0,0 +1,677 @@ +/* + * 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 +#include +#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;icode) { + + 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 + +} diff --git a/reactos/drivers/net/packet/jitter.h b/reactos/drivers/net/packet/jitter.h new file mode 100644 index 00000000000..4f9c7fd225c --- /dev/null +++ b/reactos/drivers/net/packet/jitter.h @@ -0,0 +1,391 @@ +/* + * 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); + +/** + * @} + */ + +/** + * @} + */ diff --git a/reactos/drivers/net/packet/memory_t.c b/reactos/drivers/net/packet/memory_t.c new file mode 100644 index 00000000000..2a02998feeb --- /dev/null +++ b/reactos/drivers/net/packet/memory_t.c @@ -0,0 +1,65 @@ +/* + * 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) { }; diff --git a/reactos/drivers/net/packet/memory_t.h b/reactos/drivers/net/packet/memory_t.h new file mode 100644 index 00000000000..0ecd90b4b93 --- /dev/null +++ b/reactos/drivers/net/packet/memory_t.h @@ -0,0 +1,119 @@ +/* + * 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 + diff --git a/reactos/drivers/net/packet/normal_lookup.c b/reactos/drivers/net/packet/normal_lookup.c new file mode 100644 index 00000000000..ea6442f91fe --- /dev/null +++ b/reactos/drivers/net/packet/normal_lookup.c @@ -0,0 +1,191 @@ +/* + * 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 +#include +#else +#include +#include +#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; ilut_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; (ilast_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; ilut_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; (ilast_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; + +} diff --git a/reactos/drivers/net/packet/normal_lookup.h b/reactos/drivers/net/packet/normal_lookup.h new file mode 100644 index 00000000000..c88d89058ef --- /dev/null +++ b/reactos/drivers/net/packet/normal_lookup.h @@ -0,0 +1,45 @@ +/* + * 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 +#else +#include +#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 diff --git a/reactos/drivers/net/packet/openclos.c b/reactos/drivers/net/packet/openclos.c index b30c605ea26..6c857a85a3a 100644 --- a/reactos/drivers/net/packet/openclos.c +++ b/reactos/drivers/net/packet/openclos.c @@ -25,10 +25,8 @@ #include "ndis.h" #else #include -//#include #include #endif - #include "debug.h" #include "packet.h" @@ -41,10 +39,9 @@ static NDIS_MEDIUM MediumArray[] = { 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){ @@ -58,9 +55,20 @@ int i; } +/// Global start time. Used as an absolute reference for timestamp conversion. +struct time_conv G_Start_Time = { + 0, + {0, 0}, +}; -NTSTATUS STDCALL -PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) +UINT n_Opened_Instances = 0; + +NDIS_SPIN_LOCK Opened_Instances_Lock; + +//------------------------------------------------------------------- + +NTSTATUS +NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PDEVICE_EXTENSION DeviceExtension; @@ -71,33 +79,25 @@ PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 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; @@ -109,34 +109,26 @@ PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) ); - 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, @@ -146,7 +138,7 @@ PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 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); @@ -160,6 +152,7 @@ PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) //Create the string containing the name of the read event RtlInitUnicodeString(&Open->ReadEventName,(PCWSTR) EvName); + PacketItoa(NamedEventsCounter,(PUCHAR)(Open->ReadEventName.Buffer+21)); InterlockedIncrement(&NamedEventsCounter); @@ -170,6 +163,7 @@ PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 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; @@ -179,51 +173,58 @@ PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 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); @@ -242,20 +243,19 @@ PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) } - + 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, @@ -264,11 +264,11 @@ PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 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); @@ -276,7 +276,7 @@ PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) //------------------------------------------------------------------- -VOID PacketOpenAdapterComplete( +VOID NPF_OpenAdapterComplete( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus) @@ -285,7 +285,7 @@ VOID PacketOpenAdapterComplete( PIRP Irp; POPEN_INSTANCE Open; - IF_LOUD(DbgPrint("Packet: OpenAdapterComplete\n");) + IF_LOUD(DbgPrint("NPF: OpenAdapterComplete\n");) Open= (POPEN_INSTANCE)ProtocolBindingContext; @@ -296,14 +296,29 @@ VOID PacketOpenAdapterComplete( 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; @@ -315,34 +330,50 @@ VOID PacketOpenAdapterComplete( //------------------------------------------------------------------- -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); @@ -353,26 +384,50 @@ PacketClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) 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 ); @@ -386,29 +441,42 @@ PacketClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) //------------------------------------------------------------------- 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); @@ -420,15 +488,42 @@ PacketCloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS 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, @@ -436,13 +531,13 @@ PacketBindAdapter( 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 @@ -451,7 +546,10 @@ PacketUnbindAdapter( 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); @@ -459,7 +557,14 @@ PacketUnbindAdapter( 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); @@ -472,7 +577,7 @@ PacketUnbindAdapter( if (lStatus != NDIS_STATUS_PENDING) { - PacketCloseAdapterComplete( + NPF_CloseAdapterComplete( Open, lStatus ); @@ -489,7 +594,7 @@ PacketUnbindAdapter( //------------------------------------------------------------------- VOID -PacketResetComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status) +NPF_ResetComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status) { POPEN_INSTANCE Open; @@ -497,7 +602,7 @@ PacketResetComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Statu PLIST_ENTRY ResetListEntry; - IF_LOUD(DbgPrint("Packet: PacketResetComplte\n");) + IF_LOUD(DbgPrint("NPF: PacketResetComplte\n");) Open= (POPEN_INSTANCE)ProtocolBindingContext; @@ -522,7 +627,7 @@ PacketResetComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Statu 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; diff --git a/reactos/drivers/net/packet/packet.c b/reactos/drivers/net/packet/packet.c index e8592907a5c..1891a8ab7a6 100644 --- a/reactos/drivers/net/packet/packet.c +++ b/reactos/drivers/net/packet/packet.c @@ -25,27 +25,26 @@ #include "ntiologc.h" #include "ndis.h" #else -//#include #include -//#include "" #include #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; //////////////////////////////////////////////////////////////////////////////// @@ -60,10 +59,9 @@ 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" @@ -72,32 +70,30 @@ NDIS_STRING AdapterListKey = 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; @@ -110,92 +106,114 @@ DriverEntry( 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 // @@ -207,16 +225,21 @@ NdisRegisterProtocol( &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 // @@ -229,55 +252,81 @@ NdisRegisterProtocol( 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); @@ -288,9 +337,11 @@ PWCHAR getAdaptersList(void) 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}"); @@ -302,33 +353,43 @@ PWCHAR getAdaptersList(void) 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, @@ -336,36 +397,41 @@ PWCHAR getAdaptersList(void) 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) { @@ -391,17 +457,17 @@ 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) { @@ -435,17 +501,15 @@ PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(void) 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, @@ -454,73 +518,101 @@ BOOLEAN createDevice(IN OUT PDRIVER_OBJECT adriverObjectP, } 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; @@ -529,161 +621,317 @@ PacketIoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) 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; - 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; + + if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < 4*sizeof(INT)){ + 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; + + *(((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 BIOCSETF: //fuction to set a new bpf filter - //free the previous buffer if it was present + + case BIOCGEVNAME: //function to get the name of the event associated with the current instance + + if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength<26){ + EXIT_FAILURE(0); + } + + RtlCopyMemory(Irp->UserBuffer,(Open->ReadEventName.Buffer)+18,26); + + 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: + + // 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;(cntmem_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 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 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: + + // 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 { @@ -691,43 +939,63 @@ PacketIoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) 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) @@ -736,21 +1004,27 @@ PacketIoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) && (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 @@ -760,6 +1034,7 @@ PacketIoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) Open->AdapterHandle, &pRequest->Request ); + } else { // // buffer too small @@ -767,54 +1042,87 @@ PacketIoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) 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); - return Status; - } - NdisWaitEvent(&Open->IOEvent, 5000); - return(Open->IOStatus); - break; - default: - return(NDIS_STATUS_FAILURE); + if (Status != NDIS_STATUS_PENDING) { + IF_LOUD(DbgPrint("NPF: Calling RequestCompleteHandler\n");) + + NPF_RequestComplete(Open, &pRequest->Request, Status); + return Status; + + } + + NdisWaitEvent(&Open->IOEvent, 5000); + + return(Open->IOStatus); + + break; + + + default: + + 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);) @@ -823,147 +1131,136 @@ PacketRequestComplete( &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");) + + IF_LOUD(DbgPrint("NPF: 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 (Create) { - Status=IoCreateSymbolicLink(&UnicodeDosDeviceName,DeviceName); - } else { - Status=IoDeleteSymbolicLink(&UnicodeDosDeviceName); - } - ExFreePool(UnicodeDosDeviceName.Buffer); - - } - 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, @@ -971,13 +1268,29 @@ PacketReadRegistry( 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, @@ -985,22 +1298,35 @@ PacketQueryRegistryRoutine( 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; + } diff --git a/reactos/drivers/net/packet/packet.h b/reactos/drivers/net/packet/packet.h index a7dd3704be3..18dfcb12444 100644 --- a/reactos/drivers/net/packet/packet.h +++ b/reactos/drivers/net/packet/packet.h @@ -18,185 +18,516 @@ * 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 + +/*! + \brief IOCTL code: set the read timeout + + This command sets the maximum timeout after which a read is released, also if no data packets were received. +*/ #define BIOCSRTIMEOUT 7416 + +/*! + \brief IOCTL code: set working mode + + 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 + + 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 + +/*! + \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 + + This IOCTL is used to perform an OID set operation on the NIC driver. +*/ #define BIOCSETOID 2147483648 + +/*! + \brief IOCTL code: get an OID value + + This IOCTL is used to perform an OID get operation on the NIC driver. +*/ #define BIOCQUERYOID 2147483652 + +/*! + \brief IOCTL code: set the name of a the file used by kernel dump mode + + 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 + + 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 -//working modes -#define MODE_CAPT 0 -#define MODE_STAT 1 +/*! + \brief IOCTL code: Send a buffer containing multiple packets to the network, ignoring the timestamps. -//immediate timeout -#define IMMEDIATE 1 + 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 -struct bpf_insn { - USHORT code; - UCHAR jt; - UCHAR jf; - int k; +/*! + \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. }; -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) */ +/*! + \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; - PIRP Irp; - NDIS_REQUEST 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; - } 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; ///< 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 - -// -// Port device extension. -// +/*! + \brief Port device extension. + + Structure containing some data relative to every adapter on which NPF is bound. +*/ typedef struct _DEVICE_EXTENSION { - - PDEVICE_OBJECT DeviceObject; - - NDIS_HANDLE NdisProtocolHandle; - - NDIS_STRING AdapterName; - - PWSTR BindString; - PWSTR ExportString; - - + 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; -// -// Open Instance -// +/*! + \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; - 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; +{ + 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; -typedef struct _PACKET_RESERVED { - LIST_ENTRY ListElement; - PIRP Irp; - PMDL pMdl; - } PACKET_RESERVED, *PPACKET_RESERVED; +#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 +/***************************/ +/* Prototypes */ +/***************************/ -#define RESERVED(_p) ((PPACKET_RESERVED)((_p)->ProtocolReserved)) +/** @defgroup NPF_code NPF functions + * @{ + */ -#define TRANSMIT_PACKETS 128 -// -// Prototypes -// +/*! + \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. -PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings( - 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 + ); -PWCHAR getAdaptersList( - VOID - ); +/*! + \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 + ); + +/*! + \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 -PacketCancelRoutine ( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp - ); - - -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 available to NPF. 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, @@ -206,37 +537,157 @@ Packet_tap( 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 -PacketReceiveComplete( - IN NDIS_HANDLE ProtocolBindingContext +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 +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, @@ -244,117 +695,68 @@ PacketStatus( ); +/*! + \brief Callback for NDIS StatusCompleteHandler. Not used by NPF +*/ VOID -PacketStatusComplete( - IN NDIS_HANDLE ProtocolBindingContext - ); +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 -PacketTransferDataComplete( - IN NDIS_HANDLE ProtocolBindingContext, - IN PNDIS_PACKET Packet, - IN NDIS_STATUS Status, - IN UINT BytesTransferred - ); +NPF_Unload(IN PDRIVER_OBJECT DriverObject); -VOID -PacketRemoveReference( - IN PDEVICE_EXTENSION DeviceExtension - ); - +/*! + \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, @@ -363,13 +765,12 @@ PacketQueryRegistryRoutine( 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, @@ -377,29 +778,180 @@ VOID PacketBindAdapter( 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 ); +/*! + \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); -int bpf_validate(struct bpf_insn *f,int len); - +/*! + \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); diff --git a/reactos/drivers/net/packet/packet.rc b/reactos/drivers/net/packet/packet.rc index c1fa496d2ce..47f2b3d9bdc 100644 --- a/reactos/drivers/net/packet/packet.rc +++ b/reactos/drivers/net/packet/packet.rc @@ -6,8 +6,8 @@ // 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 @@ -24,16 +24,16 @@ BEGIN 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" diff --git a/reactos/drivers/net/packet/read.c b/reactos/drivers/net/packet/read.c index eb794554a4c..fc82870ca4d 100644 --- a/reactos/drivers/net/packet/read.c +++ b/reactos/drivers/net/packet/read.c @@ -26,13 +26,17 @@ #include #else #include -//#include #include #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 //------------------------------------------------------------------- @@ -80,11 +84,10 @@ UINT n,i,NBlocks; *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; @@ -101,51 +104,57 @@ PacketRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) 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; @@ -155,21 +164,78 @@ PacketRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) 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.Lengthbh_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))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;cntmachine_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); } } @@ -179,66 +245,61 @@ PacketRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) // 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)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)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; } @@ -247,11 +308,7 @@ PacketRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) 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; @@ -265,17 +322,13 @@ PacketRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) 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) { @@ -285,7 +338,6 @@ NDIS_STATUS Packet_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE Mac NDIS_STATUS Status; UINT BytesTransfered; ULONG BufferLength; - PPACKET_RESERVED Reserved; PMDL pMdl; LARGE_INTEGER CapTime; LARGE_INTEGER TimeFreq; @@ -296,13 +348,26 @@ NDIS_STATUS Packet_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE Mac 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 @@ -316,24 +381,64 @@ NDIS_STATUS Packet_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE Mac 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 @@ -343,32 +448,42 @@ NDIS_STATUS Packet_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE Mac Open->Nbytes.QuadPart+=12; NdisReleaseSpinLock( &Open->CountersLock ); + + 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; } - if(Open->BufSize==0)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; + TLastByte = Open->BLastByte; + NdisReleaseSpinLock( &Open->BufLock ); - - maxbufspace=Packet_WORDALIGN(fres+sizeof(struct bpf_hdr)); - - if((Ttail < Thead) && (Ttail+maxbufspace+1 >= Thead)) - { - //the buffer is full: the incoming packet is lost - Open->Dropped++; - return NDIS_STATUS_NOT_ACCEPTED; - } + + 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; } @@ -378,97 +493,135 @@ NDIS_STATUS Packet_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE Mac } 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) + + if(LookaheadBufferSize != PacketSize || (UINT)LookAheadBuffer-(UINT)HeaderBuffer != HeaderBufferSize) { - //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_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; @@ -477,12 +630,12 @@ NDIS_STATUS Packet_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE Mac //------------------------------------------------------------------- -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; @@ -491,18 +644,21 @@ VOID PacketTransferDataComplete (IN NDIS_HANDLE ProtocolBindingContext,IN PNDIS_ 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; } - diff --git a/reactos/drivers/net/packet/resource.h b/reactos/drivers/net/packet/resource.h new file mode 100644 index 00000000000..d704ecaaf41 --- /dev/null +++ b/reactos/drivers/net/packet/resource.h @@ -0,0 +1,15 @@ +//{{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 diff --git a/reactos/drivers/net/packet/tcp_session.c b/reactos/drivers/net/packet/tcp_session.c new file mode 100644 index 00000000000..4eb6410d7ae --- /dev/null +++ b/reactos/drivers/net/packet/tcp_session.c @@ -0,0 +1,283 @@ +/* + * 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 +#include +#else +#include +#include +#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))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_srvack_srv=new_ack; + } + else + { + uint32 new_ack=SW_ULONG_AT(mem_ex->buffer,20); + if (new_ack-session->ack_clnack_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)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_srvack_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 diff --git a/reactos/drivers/net/packet/tcp_session.h b/reactos/drivers/net/packet/tcp_session.h new file mode 100644 index 00000000000..7b0fe91f13a --- /dev/null +++ b/reactos/drivers/net/packet/tcp_session.h @@ -0,0 +1,85 @@ +/* + * 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 +#else +#include +#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 diff --git a/reactos/drivers/net/packet/time_calls.c b/reactos/drivers/net/packet/time_calls.c new file mode 100644 index 00000000000..66f18b7b913 --- /dev/null +++ b/reactos/drivers/net/packet/time_calls.c @@ -0,0 +1,236 @@ +/* + * 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*/ diff --git a/reactos/drivers/net/packet/time_calls.h b/reactos/drivers/net/packet/time_calls.h new file mode 100644 index 00000000000..2355d45f7ca --- /dev/null +++ b/reactos/drivers/net/packet/time_calls.h @@ -0,0 +1,262 @@ +/* + * 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 GET_TIME(struct timeval *dst, struct time_conv *data); + +#else /* __GNUC__ */ + +#ifdef WIN_NT_DRIVER + +__inline void TIME_DESYNCHRONIZE(struct time_conv *data) +{ + data->reference = 0; + data->start.tv_sec = 0; + data->start.tv_usec = 0; +} + +#ifdef KQPC_TS + +/* KeQueryPerformanceCounter TimeStamps */ + +__inline VOID TIME_SYNCHRONIZE(struct time_conv *data) +{ + 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; +} + +__inline void FORCE_TIME(struct timeval *src, struct time_conv *dest) +{ + dest->start=*src; +} + +__inline void GET_TIME(struct timeval *dst, struct time_conv *data) +{ + 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; + } +} + +#else + +/*RDTSC timestamps*/ + +/* callers must be at IRQL=PASSIVE_LEVEL */ +__inline VOID TIME_SYNCHRONIZE(struct time_conv *data) +{ + 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);) +} + +__inline void FORCE_TIME(struct timeval *src, struct time_conv *dest) +{ + dest->start=*src; +} + +__inline void GET_TIME(struct timeval *dst, struct time_conv *data) +{ + 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 /*KQPC_TS*/ + +#endif /*WIN_NT_DRIVER*/ + +#endif /* __GNUC__ */ + +#endif /*_time_calls*/ diff --git a/reactos/drivers/net/packet/tme.c b/reactos/drivers/net/packet/tme.c new file mode 100644 index 00000000000..87ed7dcad5a --- /dev/null +++ b/reactos/drivers/net/packet/tme.c @@ -0,0 +1,378 @@ +/* + * 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" +#endif + +#ifdef __FreeBSD__ +#include +#endif + +/* resizes extended memory */ +uint32 init_extended_memory(uint32 size, MEM_TYPE *mem_ex) +{ + uint8 *tmp; + + if ((mem_ex==NULL)||(mem_ex->buffer==NULL)||(size==0)) + return TME_ERROR; /* awfully never reached!!!! */ + + tmp=mem_ex->buffer; + mem_ex->buffer=NULL; + FREE_MEMORY(tmp); + + ALLOCATE_MEMORY(tmp,uint8,size); + if (tmp==NULL) + return TME_ERROR; /* no memory */ + + mem_ex->size=size; + mem_ex->buffer=tmp; + return TME_SUCCESS; + +} + +/* activates a block of the TME */ +uint32 set_active_tme_block(TME_CORE *tme, uint32 block) +{ + + if ((block>=MAX_TME_DATA_BLOCKS)||(!IS_VALIDATED(tme->validated_blocks,block))) + return TME_ERROR; + tme->active=block; + tme->working=block; + return TME_SUCCESS; + +} + +/* simply inserts default values in a TME block */ +/* it DOESN'T initialize the block in the core!! */ +/* FIXME default values are defined at compile time, */ +/* it will be useful to store them in the registry */ +uint32 init_tme_block(TME_CORE *tme, uint32 block) +{ + + TME_DATA *data; + if (block>=MAX_TME_DATA_BLOCKS) + return TME_ERROR; + data=&(tme->block_data[block]); + tme->working=block; + + ZERO_MEMORY(data,sizeof(TME_DATA)); + + /* entries in LUT */ + data->lut_entries=TME_LUT_ENTRIES_DEFAULT; + /* blocks */ + data->shared_memory_blocks=TME_SHARED_MEMORY_BLOCKS_DEFAULT; + /* block size */ + data->block_size=TME_BLOCK_SIZE_DEFAULT; + /* lookup function */ + data->lookup_code=lut_fcn_mapper(TME_LOOKUP_CODE_DEFAULT); + /* rehashing value */ + data->rehashing_value=TME_REHASHING_VALUE_DEFAULT; + /* out lut function */ + data->out_lut_exec=TME_OUT_LUT_EXEC_DEFAULT; + /* default function */ + data->default_exec=TME_DEFAULT_EXEC_DEFAULT; + /* extra segment size */ + data->extra_segment_size=TME_EXTRA_SEGMENT_SIZE_DEFAULT; + + + data->enable_deletion=FALSE; + data->last_read.tv_sec=0; + data->last_read.tv_usec=0; + return TME_SUCCESS; + +} +/* it validates a TME block and */ +/* (on OK) inserts the block in the core */ +uint32 validate_tme_block(MEM_TYPE *mem_ex, TME_CORE *tme, uint32 block, uint32 mem_ex_offset) +{ + uint32 required_memory; + uint8 *base=mem_ex_offset+mem_ex->buffer; + TME_DATA *data; + + /* FIXME soluzione un po' posticcia... */ + if (mem_ex_offset==0) + return TME_ERROR; + + if (block>=MAX_TME_DATA_BLOCKS) + return TME_ERROR; + data=&tme->block_data[block]; + + if (data->lut_entries==0) + return TME_ERROR; + + if (data->key_len==0) + return TME_ERROR; + + if (data->shared_memory_blocks==0) + return TME_ERROR; + + if (data->block_size==0) + return TME_ERROR; + + /* checks if the lookup function is valid */ + if (data->lookup_code==NULL) + return TME_ERROR; + + /* checks if the out lut exec function is valid */ + if (exec_fcn_mapper(data->out_lut_exec)==NULL) + return TME_ERROR; + + /* checks if the default exec function is valid */ + if (exec_fcn_mapper(data->default_exec)==NULL) + return TME_ERROR; + + /* let's calculate memory needed */ + required_memory=data->lut_entries*sizeof(RECORD); /*LUT*/ + required_memory+=data->block_size*data->shared_memory_blocks; /*shared segment*/ + required_memory+=data->extra_segment_size; /*extra segment*/ + + if (required_memory>(mem_ex->size-mem_ex_offset)) + return TME_ERROR; /*not enough memory*/ + + /* the TME block can be initialized */ + ZERO_MEMORY(base,required_memory); + + data->lut_base_address=base; + + data->shared_memory_base_address= + data->lut_base_address+ + data->lut_entries*sizeof(RECORD); + + data->extra_segment_base_address= + data->shared_memory_base_address+ + data->block_size*data->shared_memory_blocks; + data->filled_blocks=1; + VALIDATE(tme->validated_blocks,block); + tme->active=block; + tme->working=block; + return TME_SUCCESS; +} + +/* I/F between the bpf machine and the callbacks, just some checks */ +uint32 lookup_frontend(MEM_TYPE *mem_ex, TME_CORE *tme,uint32 mem_ex_offset, struct time_conv *time_ref) +{ + if (tme->active==TME_NONE_ACTIVE) + return TME_FALSE; + + return (tme->block_data[tme->active].lookup_code)(mem_ex_offset+mem_ex->buffer,&tme->block_data[tme->active],mem_ex, time_ref); +} + +/* I/F between the bpf machine and the callbacks, just some checks */ +uint32 execute_frontend(MEM_TYPE *mem_ex, TME_CORE *tme, uint32 pkt_size, uint32 offset) +{ + + exec_fcn tmp; + TME_DATA *data; + uint8 *block; + uint8 *mem_data; + + if (tme->active==TME_NONE_ACTIVE) + return TME_ERROR; + + data=&tme->block_data[tme->active]; + + if (data->last_found==NULL) + { /*out lut exec */ + tmp=exec_fcn_mapper(data->out_lut_exec); + block=data->shared_memory_base_address; + } + else + { /*checks if last_found is valid */ + if ((data->last_foundlut_base_address)||(data->last_found>=data->shared_memory_base_address)) + return TME_ERROR; + else + { + tmp=exec_fcn_mapper(SW_ULONG_AT(&((RECORD*)data->last_found)->exec_fcn,0)); + if (tmp==NULL) + return TME_ERROR; + block=SW_ULONG_AT(&((RECORD*)data->last_found)->block,0)+mem_ex->buffer; + if ((blockshared_memory_base_address)||(block>=data->extra_segment_base_address)) + return TME_ERROR; + } + } + + if (offset>=mem_ex->size) + return TME_ERROR; + + mem_data=mem_ex->buffer+offset; + + return tmp(block,pkt_size,data,mem_ex,mem_data); +} + +/*resets all the TME core*/ +uint32 reset_tme(TME_CORE *tme) +{ + if (tme==NULL) + return TME_ERROR; + ZERO_MEMORY(tme, sizeof(TME_CORE)); + return TME_SUCCESS; +} + +/* returns a register value of the active TME block */ +/* FIXME last found in maniera elegante e veloce ?!?! */ +uint32 get_tme_block_register(TME_DATA *data,MEM_TYPE *mem_ex,uint32 rgstr,uint32 *rval) +{ + switch(rgstr) + { + case TME_LUT_ENTRIES: + *rval=data->lut_entries; + return TME_SUCCESS; + case TME_MAX_FILL_STATE: + *rval=data->max_fill_state; + return TME_SUCCESS; + case TME_REHASHING_VALUE: + *rval=data->rehashing_value; + return TME_SUCCESS; + case TME_KEY_LEN: + *rval=data->key_len; + return TME_SUCCESS; + case TME_SHARED_MEMORY_BLOCKS: + *rval=data->shared_memory_blocks; + return TME_SUCCESS; + case TME_FILLED_ENTRIES: + *rval=data->filled_entries; + return TME_SUCCESS; + case TME_BLOCK_SIZE: + *rval=data->block_size; + return TME_SUCCESS; + case TME_EXTRA_SEGMENT_SIZE: + *rval=data->extra_segment_size; + return TME_SUCCESS; + case TME_FILLED_BLOCKS: + *rval=data->filled_blocks; + return TME_SUCCESS; + case TME_DEFAULT_EXEC: + *rval=data->default_exec; + return TME_SUCCESS; + case TME_OUT_LUT_EXEC: + *rval=data->out_lut_exec; + return TME_SUCCESS; + case TME_SHARED_MEMORY_BASE_ADDRESS: + *rval=data->shared_memory_base_address-mem_ex->buffer; + return TME_SUCCESS; + case TME_LUT_BASE_ADDRESS: + *rval=data->lut_base_address-mem_ex->buffer; + return TME_SUCCESS; + case TME_EXTRA_SEGMENT_BASE_ADDRESS: + *rval=data->extra_segment_base_address-mem_ex->buffer; + return TME_SUCCESS; + case TME_LAST_FOUND_BLOCK: + if (data->last_found==NULL) + *rval=0; + else + *rval=data->last_found-mem_ex->buffer; + return TME_SUCCESS; + + default: + return TME_ERROR; + } +} + +/* sets a register value in the active block */ +/* FIXME last found in maniera elegante e veloce ?!?! */ +uint32 set_tme_block_register(TME_DATA *data,MEM_TYPE *mem_ex,uint32 rgstr,uint32 value, int32 init) +{ /* very very very dangerous!!!!!!!!!!! */ + lut_fcn tmp; + switch(rgstr) + { + case TME_MAX_FILL_STATE: + data->max_fill_state=value; + return TME_SUCCESS; + case TME_REHASHING_VALUE: + data->rehashing_value=value; + return TME_SUCCESS; + case TME_FILLED_ENTRIES: + data->filled_entries=value; + return TME_SUCCESS; + case TME_FILLED_BLOCKS: + if (value<=data->shared_memory_blocks) + { + data->filled_blocks=value; + return TME_SUCCESS; + } + else + return TME_ERROR; + case TME_DEFAULT_EXEC: + data->default_exec=value; + return TME_SUCCESS; + case TME_OUT_LUT_EXEC: + data->out_lut_exec=value; + return TME_SUCCESS; + case TME_LOOKUP_CODE: + tmp=lut_fcn_mapper(value); + if (tmp==NULL) + return TME_ERROR; + else + data->lookup_code=tmp; + return TME_SUCCESS; + default: + break; + } + + if (init) + switch (rgstr) + { + + case TME_LUT_ENTRIES: + data->lut_entries=value; + return TME_SUCCESS; + case TME_KEY_LEN: + data->key_len=value; + return TME_SUCCESS; + case TME_SHARED_MEMORY_BLOCKS: + data->shared_memory_blocks=value; + return TME_SUCCESS; + case TME_BLOCK_SIZE: + data->block_size=value; + return TME_SUCCESS; + case TME_EXTRA_SEGMENT_SIZE: + data->extra_segment_size=value; + return TME_SUCCESS; + default: + return TME_ERROR; + } + else + return TME_ERROR; + +} + +/* chooses the TME block for read */ +uint32 set_active_read_tme_block(TME_CORE *tme, uint32 block) +{ + + if ((block>=MAX_TME_DATA_BLOCKS)||(!IS_VALIDATED(tme->validated_blocks,block))) + return TME_ERROR; + tme->active_read=block; + return TME_SUCCESS; + +} + +/* chooses if the autodeletion must be used */ +uint32 set_autodeletion(TME_DATA *data, uint32 value) +{ + if (value==0) /* no autodeletion */ + data->enable_deletion=FALSE; + else + data->enable_deletion=TRUE; + + return TME_SUCCESS; +} \ No newline at end of file diff --git a/reactos/drivers/net/packet/tme.h b/reactos/drivers/net/packet/tme.h new file mode 100644 index 00000000000..f6916f94aa8 --- /dev/null +++ b/reactos/drivers/net/packet/tme.h @@ -0,0 +1,182 @@ +/* + * 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 __tme_include_ +#define __tme_include_ + +#ifdef WIN_NT_DRIVER + +#include "ntddk.h" +#include "memory_t.h" +#include "time_calls.h" +#endif /*WIN_NT_DRIVER*/ + +#ifdef WIN32 +#include "memory_t.h" +#include "time_calls.h" +#endif /*WIN32*/ + + + +#ifdef __FreeBSD__ + +#ifdef _KERNEL +#include +#else +#include +#endif + +#endif + +/* error codes */ +#define TME_ERROR 0 +#define TME_SUCCESS 1 +#define TME_TRUE 2 +#define TME_FALSE 3 + +/* some constants */ +#define DEFAULT_MEM_EX_SIZE 65536 +#define MAX_TME_DATA_BLOCKS 4 +#define TME_NONE_ACTIVE 0xffffffff +#define DELTA_READ 2 /* secs */ + +#define TME_LUT_ENTRIES 0x00000000 +#define TME_MAX_FILL_STATE 0x00000001 /*potrebbe servire per un thread a passive level!?!?! */ +#define TME_REHASHING_VALUE 0x00000002 +#define TME_KEY_LEN 0x00000003 +#define TME_SHARED_MEMORY_BLOCKS 0x00000004 +#define TME_FILLED_ENTRIES 0x00000005 +#define TME_BLOCK_SIZE 0x00000006 +#define TME_EXTRA_SEGMENT_SIZE 0x00000007 +#define TME_LOOKUP_CODE 0x00000008 +#define TME_OUT_LUT_EXEC 0x00000009 +#define TME_FILLED_BLOCKS 0x0000000a +#define TME_DEFAULT_EXEC 0x0000000b +#define TME_LUT_BASE_ADDRESS 0x0000000c +#define TME_SHARED_MEMORY_BASE_ADDRESS 0x0000000d +#define TME_EXTRA_SEGMENT_BASE_ADDRESS 0x0000000e +#define TME_LAST_FOUND 0x0000000f /* contains the offset of the last found entry */ +#define TME_LAST_FOUND_BLOCK 0x00000010 +/* TME default values */ +#define TME_LUT_ENTRIES_DEFAULT 32007 +#define TME_REHASHING_VALUE_DEFAULT 1 +#define TME_SHARED_MEMORY_BLOCKS_DEFAULT 16000 +#define TME_BLOCK_SIZE_DEFAULT 64 +#define TME_EXTRA_SEGMENT_SIZE_DEFAULT 0 +#define TME_LOOKUP_CODE_DEFAULT 0 +#define TME_OUT_LUT_EXEC_DEFAULT 0 +#define TME_DEFAULT_EXEC_DEFAULT 0 +#define TME_MAX_FILL_STATE_DEFAULT 15000 + +#define IS_VALIDATED(src,index) (src&(1<tv_sec=0x7fffffff; + +/* TME callback prototypes */ +#ifndef __GNUC__ +typedef uint32 (*lut_fcn)(uint8 *key, struct __TME_DATA *data,MEM_TYPE *mem_ex, struct time_conv *time_ref ); +typedef uint32 (*exec_fcn)(uint8 *block, uint32 pkt_size, struct __TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data); +#else +typedef uint32 (*lut_fcn)(uint8 *key, void *data,MEM_TYPE *mem_ex, struct time_conv *time_ref ); +typedef uint32 (*exec_fcn)(uint8 *block, uint32 pkt_size, void *data, MEM_TYPE *mem_ex, uint8 *mem_data); +#endif + +/* DO NOT MODIFY THIS STRUCTURE!!!! GV */ +typedef struct __RECORD + +{ + uint32 block; + uint32 exec_fcn; +} + RECORD, *PRECORD; + +/* TME data registers */ +struct __TME_DATA +{ + uint32 lut_entries; + uint32 max_fill_state; + uint32 rehashing_value; + uint32 key_len; + uint32 shared_memory_blocks; + uint32 filled_entries; + uint32 block_size; + uint32 extra_segment_size; + uint32 filled_blocks; + lut_fcn lookup_code; + uint32 default_exec; + uint32 out_lut_exec; + uint8 *lut_base_address; + uint8 *shared_memory_base_address; + uint8 *extra_segment_base_address; + struct timeval last_read; + uint32 enable_deletion; + uint8 *last_found; +}; + +typedef struct __TME_DATA TME_DATA,*PTME_DATA; + + + +/* TME core */ +typedef struct __TME_CORE +{ + uint32 working; + uint32 active; + uint32 validated_blocks; + TME_DATA block_data[MAX_TME_DATA_BLOCKS]; + uint32 active_read; + +} TME_CORE, *PTME_CORE; + +static __inline int32 IS_DELETABLE(void *timestamp, TME_DATA *data) +{ + struct timeval *ts=(struct timeval*)timestamp; + + if (data->enable_deletion==FALSE) + return FALSE; + if (data->filled_entriesmax_fill_state) + return FALSE; + if ((ts->tv_sec+DELTA_READ)last_read.tv_sec) + return TRUE; + return FALSE; +} + +/* functions to manage TME */ +uint32 init_tme_block(TME_CORE *tme, uint32 block); +uint32 validate_tme_block(MEM_TYPE *mem_ex, TME_CORE *tme, uint32 block, uint32 mem_ex_offset); +uint32 lookup_frontend(MEM_TYPE *mem_ex, TME_CORE *tme,uint32 mem_ex_offset, struct time_conv *time_ref); +uint32 execute_frontend(MEM_TYPE *mem_ex, TME_CORE *tme, uint32 pkt_size,uint32 offset); +uint32 set_active_tme_block(TME_CORE *tme, uint32 block); +uint32 init_extended_memory(uint32 size, MEM_TYPE *mem_ex); +uint32 reset_tme(TME_CORE *tme); +uint32 get_tme_block_register(TME_DATA *data,MEM_TYPE *mem_ex,uint32 rgstr,uint32 *rval); +uint32 set_tme_block_register(TME_DATA *data,MEM_TYPE *mem_ex,uint32 rgstr,uint32 value, int32 init); +uint32 set_active_read_tme_block(TME_CORE *tme, uint32 block); +uint32 set_autodeletion(TME_DATA *data, uint32 value); + +/* function mappers */ +lut_fcn lut_fcn_mapper(uint32 index); +exec_fcn exec_fcn_mapper(uint32 index); + +#endif \ No newline at end of file diff --git a/reactos/drivers/net/packet/valid_insns.h b/reactos/drivers/net/packet/valid_insns.h new file mode 100644 index 00000000000..20b115d1734 --- /dev/null +++ b/reactos/drivers/net/packet/valid_insns.h @@ -0,0 +1,73 @@ +u_short valid_instructions[]= + { + BPF_RET|BPF_K, + BPF_RET|BPF_A, + BPF_LD|BPF_IMM, + BPF_LDX|BPF_IMM, + BPF_LD|BPF_MEM, + BPF_LDX|BPF_MEM, + BPF_LD|BPF_MEM_EX_IMM|BPF_B, + BPF_LD|BPF_MEM_EX_IMM|BPF_H, + BPF_LD|BPF_MEM_EX_IMM|BPF_W, + BPF_LD|BPF_MEM_EX_IND|BPF_B, + BPF_LD|BPF_MEM_EX_IND|BPF_H, + BPF_LD|BPF_MEM_EX_IND|BPF_W, + BPF_LD|BPF_W|BPF_ABS, + BPF_LD|BPF_H|BPF_ABS, + BPF_LD|BPF_B|BPF_ABS, + BPF_LDX|BPF_W|BPF_ABS, + BPF_LDX|BPF_H|BPF_ABS, + BPF_LDX|BPF_B|BPF_ABS, + BPF_LD|BPF_W|BPF_LEN, + BPF_LDX|BPF_W|BPF_LEN, + BPF_LD|BPF_W|BPF_IND, + BPF_LD|BPF_H|BPF_IND, + BPF_LD|BPF_B|BPF_IND, + BPF_LDX|BPF_MSH|BPF_B, + BPF_ST, + BPF_STX, + BPF_ST|BPF_MEM_EX_IMM|BPF_B, + BPF_STX|BPF_MEM_EX_IMM|BPF_B, + BPF_ST|BPF_MEM_EX_IMM|BPF_W, + BPF_STX|BPF_MEM_EX_IMM|BPF_W, + BPF_ST|BPF_MEM_EX_IMM|BPF_H, + BPF_STX|BPF_MEM_EX_IMM|BPF_H, + BPF_ST|BPF_MEM_EX_IND|BPF_B, + BPF_ST|BPF_MEM_EX_IND|BPF_W, + BPF_ST|BPF_MEM_EX_IND|BPF_H, + BPF_JMP|BPF_JA, + BPF_JMP|BPF_JGT|BPF_K, + BPF_JMP|BPF_JGE|BPF_K, + BPF_JMP|BPF_JEQ|BPF_K, + BPF_JMP|BPF_JSET|BPF_K, + BPF_JMP|BPF_JGT|BPF_X, + BPF_JMP|BPF_JGE|BPF_X, + BPF_JMP|BPF_JEQ|BPF_X, + BPF_JMP|BPF_JSET|BPF_X, + BPF_ALU|BPF_ADD|BPF_X, + BPF_ALU|BPF_SUB|BPF_X, + BPF_ALU|BPF_MUL|BPF_X, + BPF_ALU|BPF_DIV|BPF_X, + BPF_ALU|BPF_AND|BPF_X, + BPF_ALU|BPF_OR|BPF_X, + BPF_ALU|BPF_LSH|BPF_X, + BPF_ALU|BPF_RSH|BPF_X, + BPF_ALU|BPF_ADD|BPF_K, + BPF_ALU|BPF_SUB|BPF_K, + BPF_ALU|BPF_MUL|BPF_K, + BPF_ALU|BPF_DIV|BPF_K, + BPF_ALU|BPF_AND|BPF_K, + BPF_ALU|BPF_OR|BPF_K, + BPF_ALU|BPF_LSH|BPF_K, + BPF_ALU|BPF_RSH|BPF_K, + BPF_ALU|BPF_NEG, + BPF_MISC|BPF_TAX, + BPF_MISC|BPF_TXA, + BPF_MISC|BPF_TME|BPF_LOOKUP, + BPF_MISC|BPF_TME|BPF_EXECUTE, + BPF_MISC|BPF_TME|BPF_SET_ACTIVE, + BPF_MISC|BPF_TME|BPF_GET_REGISTER_VALUE, + BPF_MISC|BPF_TME|BPF_SET_REGISTER_VALUE + }; + +#define VALID_INSTRUCTIONS_LEN (sizeof(valid_instructions)/sizeof(u_short)) diff --git a/reactos/drivers/net/packet/win_bpf.h b/reactos/drivers/net/packet/win_bpf.h index efa809959c5..21bb9b7e580 100644 --- a/reactos/drivers/net/packet/win_bpf.h +++ b/reactos/drivers/net/packet/win_bpf.h @@ -37,7 +37,7 @@ * * @(#)bpf.h 7.1 (Berkeley) 5/7/91 * - * @(#) $Header: /cygdrive/c/RCVS/CVS/ReactOS/reactos/drivers/net/packet/win_bpf.h,v 1.1 2002/06/19 15:43:15 robd Exp $ (LBL) + * @(#) $Header: /cygdrive/c/RCVS/CVS/ReactOS/reactos/drivers/net/packet/win_bpf.h,v 1.2 2002/09/24 15:16:46 robd Exp $ (LBL) */ #ifndef BPF_MAJOR_VERSION @@ -45,37 +45,29 @@ /* BSD style release date */ #define BPF_RELEASE 199606 -#ifdef __NTDRIVER__ -#define NTKERNEL -#endif - -#ifndef NTKERNEL -#include -typedef int bpf_int32; -typedef u_int bpf_u_int32; -#else typedef UCHAR u_char; typedef USHORT u_short; -typedef UINT u_int; -typedef INT bpf_int32; -typedef UINT bpf_u_int32; -#endif - -/* - * Alignment macros. BPF_WORDALIGN rounds up to the next - * even multiple of BPF_ALIGNMENT. - */ -#ifndef __NetBSD__ -#define BPF_ALIGNMENT sizeof(bpf_int32) -#else -#define BPF_ALIGNMENT sizeof(long) -#endif -#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) +typedef ULONG u_int; +typedef LONG bpf_int32; +typedef ULONG bpf_u_int32; +typedef ULONG u_int32; #define BPF_MAXINSNS 512 #define BPF_MAXBUFSIZE 0x8000 #define BPF_MINBUFSIZE 32 +#include "time_calls.h" + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_int32 k; +}; + /* * Structure for BIOCSETF. */ @@ -122,14 +114,6 @@ struct bpf_hdr { u_short bh_hdrlen; /* length of bpf header (this struct plus alignment padding) */ }; -/* - * Because the structure above is not a multiple of 4 bytes, some compilers - * will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work. - * Only the kernel needs to know about it; applications use bh_hdrlen. - */ -#if defined(KERNEL) || defined(_KERNEL) -#define SIZEOF_BPF_HDR 18 -#endif /* * Data-link level type codes. @@ -304,15 +288,28 @@ struct bpf_hdr { #define BPF_TAX 0x00 #define BPF_TXA 0x80 -/* - * The instruction data structure. - */ -struct bpf_insn { - u_short code; - u_char jt; - u_char jf; - bpf_int32 k; -}; +/* TME instructions */ +#define BPF_TME 0x08 + +#define BPF_LOOKUP 0x90 +#define BPF_EXECUTE 0xa0 +#define BPF_INIT 0xb0 +#define BPF_VALIDATE 0xc0 +#define BPF_SET_ACTIVE 0xd0 +#define BPF_RESET 0xe0 +#define BPF_SET_MEMORY 0x80 +#define BPF_GET_REGISTER_VALUE 0x70 +#define BPF_SET_REGISTER_VALUE 0x60 +#define BPF_SET_WORKING 0x50 +#define BPF_SET_ACTIVE_READ 0x40 +#define BPF_SET_AUTODELETION 0x30 +#define BPF_SEPARATION 0xff + +#define BPF_MEM_EX_IMM 0xc0 +#define BPF_MEM_EX_IND 0xe0 +/*used for ST */ +#define BPF_MEM_EX 0xc0 + /* * Macros for insn array initializers. @@ -320,35 +317,6 @@ struct bpf_insn { #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } -/** - * @} - */ - -#if defined(BSD) && (defined(KERNEL) || defined(_KERNEL)) -/* - * Systems based on non-BSD kernels don't have ifnet's (or they don't mean - * anything if it is in ) and won't work like this. - */ -# if __STDC__ -extern void bpf_tap(struct ifnet *, u_char *, u_int); -extern void bpf_mtap(struct ifnet *, struct mbuf *); -extern void bpfattach(struct ifnet *, u_int, u_int); -extern void bpfilterattach(int); -# else -extern void bpf_tap(); -extern void bpf_mtap(); -extern void bpfattach(); -extern void bpfilterattach(); -# endif /* __STDC__ */ -#endif /* BSD && (_KERNEL || KERNEL) */ -#if __STDC__ -extern int bpf_validate(struct bpf_insn *, int); -extern u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int); -#else -extern int bpf_validate(); -extern u_int bpf_filter(); -#endif - /* * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). */ diff --git a/reactos/drivers/net/packet/win_bpf_filter.c b/reactos/drivers/net/packet/win_bpf_filter.c index 3dbbe10fc49..76dee6ee88b 100644 --- a/reactos/drivers/net/packet/win_bpf_filter.c +++ b/reactos/drivers/net/packet/win_bpf_filter.c @@ -59,35 +59,12 @@ @(#)bpf.c 7.5 (Berkeley) 7/15/91 */ -#if !(defined(lint) || defined(KERNEL)) -static const char rcsid[] = - "@(#) $Header: /cygdrive/c/RCVS/CVS/ReactOS/reactos/drivers/net/packet/win_bpf_filter.c,v 1.1 2002/06/19 15:43:15 robd Exp $ (LBL)"; -#endif - -#ifndef WIN32 -#include -#include -#else -#include -#endif -#include +#include "tme.h" #include "win_bpf.h" -#define int32 bpf_int32 -#define u_int32 bpf_u_int32 +#include "debug.h" - -#ifndef LBL_ALIGN -#if defined(sparc) || defined(mips) || defined(ibm032) || \ - defined(__alpha) || defined(__hpux) -#define LBL_ALIGN -#endif -#endif - -#ifndef LBL_ALIGN -#ifndef WIN32 -#include -#endif +#include "valid_insns.h" #define EXTRACT_SHORT(p)\ ((u_short)\ @@ -98,29 +75,23 @@ static const char rcsid[] = (u_int32)*((u_char *)p+1)<<16|\ (u_int32)*((u_char *)p+2)<<8|\ (u_int32)*((u_char *)p+3)<<0) -#endif -/** @ingroup NPF - * @{ - */ -/** @defgroup NPF_code NPF functions - * @{ - */ - -/* - * Execute the filter program starting at pc on the packet p - * wirelen is the length of the original packet - * buflen is the amount of data present - */ -u_int bpf_filter(pc, p, wirelen, buflen) +u_int bpf_filter(pc, p, wirelen, buflen,mem_ex,tme,time_ref) register struct bpf_insn *pc; register u_char *p; u_int wirelen; register u_int buflen; + PMEM_TYPE mem_ex; + PTME_CORE tme; + struct time_conv *time_ref; + { register u_int32 A, X; register int k; + u_int32 j,tmp; + u_short tmp2; + int32 mem[BPF_MEMWORDS]; if (pc == 0) @@ -225,6 +196,57 @@ u_int bpf_filter(pc, p, wirelen, buflen) X = mem[pc->k]; continue; +/* LD NO PACKET INSTRUCTIONS */ + + case BPF_LD|BPF_MEM_EX_IMM|BPF_B: + A= mem_ex->buffer[pc->k]; + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_B: + X= mem_ex->buffer[pc->k]; + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_H: + A = EXTRACT_SHORT(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_H: + X = EXTRACT_SHORT(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_W: + A = EXTRACT_LONG(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_W: + X = EXTRACT_LONG(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_B: + k = X + pc->k; + if ((int32)k>= (int32)mem_ex->size) { + return 0; + } + A= mem_ex->buffer[k]; + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_H: + k = X + pc->k; + if ((int32)(k+1)>= (int32)mem_ex->size) { + return 0; + } + A=EXTRACT_SHORT((uint32*)&mem_ex->buffer[k]); + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_W: + k = X + pc->k; + if ((int32)(k+3)>= (int32)mem_ex->size) { + return 0; + } + A=EXTRACT_LONG((uint32*)&mem_ex->buffer[k]); + continue; +/* END LD NO PACKET INSTRUCTIONS */ + case BPF_ST: mem[pc->k] = A; continue; @@ -233,6 +255,49 @@ u_int bpf_filter(pc, p, wirelen, buflen) mem[pc->k] = X; continue; +/* STORE INSTRUCTIONS */ + case BPF_ST|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)A; + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)X; + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_W: + tmp=A; + *(uint32*)&(mem_ex->buffer[pc->k])=EXTRACT_LONG(&tmp); + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_W: + tmp=X; + *(uint32*)&(mem_ex->buffer[pc->k])=EXTRACT_LONG(&tmp); + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16)A; + *(uint16*)&mem_ex->buffer[pc->k]=EXTRACT_SHORT(&tmp2); + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16)X; + *(uint16*)&mem_ex->buffer[pc->k]=EXTRACT_SHORT(&tmp2); + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_B: + mem_ex->buffer[pc->k+X]=(uint8)A; + + case BPF_ST|BPF_MEM_EX_IND|BPF_W: + tmp=A; + *(uint32*)&mem_ex->buffer[pc->k+X]=EXTRACT_LONG(&tmp); + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_H: + tmp2=(uint16)A; + *(uint16*)&mem_ex->buffer[pc->k+X]=EXTRACT_SHORT(&tmp2); + continue; +/* END STORE INSTRUCTIONS */ + case BPF_JMP|BPF_JA: pc += pc->k; continue; @@ -346,30 +411,59 @@ u_int bpf_filter(pc, p, wirelen, buflen) case BPF_MISC|BPF_TXA: A = X; continue; + +/* TME INSTRUCTIONS */ + case BPF_MISC|BPF_TME|BPF_LOOKUP: + j=lookup_frontend(mem_ex,tme,pc->k,time_ref); + if (j==TME_ERROR) + return 0; + pc += (j == TME_TRUE) ? pc->jt : pc->jf; + continue; + + case BPF_MISC|BPF_TME|BPF_EXECUTE: + if (execute_frontend(mem_ex,tme,wirelen,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_ACTIVE: + if (set_active_tme_block(tme,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_GET_REGISTER_VALUE: + if (get_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,&j)==TME_ERROR) + return 0; + A=j; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_REGISTER_VALUE: + if (set_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,A,FALSE)==TME_ERROR) + return 0; + continue; +/* END TME INSTRUCTIONS */ + } } } +//------------------------------------------------------------------- -/* - * Execute the filter program starting at pc on the packet whose header is - * pointed by p and whose data is pointed by pd. - * headersize is the size of the the header - * wirelen is the length of the original packet - * buflen is the amount of data present - */ - -u_int bpf_filter_with_2_buffers(pc, p, pd, headersize, wirelen, buflen) +u_int bpf_filter_with_2_buffers(pc, p, pd, headersize, wirelen, buflen, mem_ex,tme,time_ref) register struct bpf_insn *pc; register u_char *p; register u_char *pd; register int headersize; u_int wirelen; register u_int buflen; + PMEM_TYPE mem_ex; + PTME_CORE tme; + struct time_conv *time_ref; { register u_int32 A, X; register int k; int32 mem[BPF_MEMWORDS]; + u_int32 j,tmp; + u_short tmp2; if (pc == 0) /* @@ -538,6 +632,57 @@ u_int bpf_filter_with_2_buffers(pc, p, pd, headersize, wirelen, buflen) X = mem[pc->k]; continue; +/* LD NO PACKET INSTRUCTIONS */ + + case BPF_LD|BPF_MEM_EX_IMM|BPF_B: + A= mem_ex->buffer[pc->k]; + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_B: + X= mem_ex->buffer[pc->k]; + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_H: + A = EXTRACT_SHORT(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_H: + X = EXTRACT_SHORT(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_W: + A = EXTRACT_LONG(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_W: + X = EXTRACT_LONG(&mem_ex->buffer[pc->k]); + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_B: + k = X + pc->k; + if ((int32)k>= (int32)mem_ex->size) { + return 0; + } + A= mem_ex->buffer[k]; + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_H: + k = X + pc->k; + if ((int32)(k+1)>= (int32)mem_ex->size) { + return 0; + } + A=EXTRACT_SHORT((uint32*)&mem_ex->buffer[k]); + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_W: + k = X + pc->k; + if ((int32)(k+3)>= (int32)mem_ex->size) { + return 0; + } + A=EXTRACT_LONG((uint32*)&mem_ex->buffer[k]); + continue; +/* END LD NO PACKET INSTRUCTIONS */ + case BPF_ST: mem[pc->k] = A; continue; @@ -546,6 +691,52 @@ u_int bpf_filter_with_2_buffers(pc, p, pd, headersize, wirelen, buflen) mem[pc->k] = X; continue; + +/* STORE INSTRUCTIONS */ + case BPF_ST|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)A; + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)X; + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_W: + tmp=A; + *(uint32*)&(mem_ex->buffer[pc->k])=EXTRACT_LONG(&tmp); + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_W: + tmp=X; + *(uint32*)&(mem_ex->buffer[pc->k])=EXTRACT_LONG(&tmp); + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16)A; + *(uint16*)&mem_ex->buffer[pc->k]=EXTRACT_SHORT(&tmp2); + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16)X; + *(uint16*)&mem_ex->buffer[pc->k]=EXTRACT_SHORT(&tmp2); + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_B: + mem_ex->buffer[pc->k+X]=(uint8)A; + + case BPF_ST|BPF_MEM_EX_IND|BPF_W: + tmp=A; + *(uint32*)&mem_ex->buffer[pc->k+X]=EXTRACT_LONG(&tmp); + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_H: + tmp2=(uint16)A; + *(uint16*)&mem_ex->buffer[pc->k+X]=EXTRACT_SHORT(&tmp2); + continue; +/* END STORE INSTRUCTIONS */ + + + case BPF_JMP|BPF_JA: pc += pc->k; continue; @@ -659,37 +850,72 @@ u_int bpf_filter_with_2_buffers(pc, p, pd, headersize, wirelen, buflen) case BPF_MISC|BPF_TXA: A = X; continue; + +/* TME INSTRUCTIONS */ + case BPF_MISC|BPF_TME|BPF_LOOKUP: + j=lookup_frontend(mem_ex,tme,pc->k,time_ref); + if (j==TME_ERROR) + return 0; + pc += (j == TME_TRUE) ? pc->jt : pc->jf; + continue; + + case BPF_MISC|BPF_TME|BPF_EXECUTE: + if (execute_frontend(mem_ex,tme,wirelen,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_ACTIVE: + if (set_active_tme_block(tme,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_GET_REGISTER_VALUE: + if (get_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,&j)==TME_ERROR) + return 0; + A=j; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_REGISTER_VALUE: + if (set_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,A,FALSE)==TME_ERROR) + return 0; + continue; +/* END TME INSTRUCTIONS */ + } } } - -/* - * Return true if the 'fcode' 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. - * 'valid' is an array for use by the routine (it must be at least - * 'len' bytes long). - * - * The kernel needs to be able to verify an application's filter code. - * Otherwise, a bogus program could easily crash the system. - */ -int -bpf_validate(f, len) +int32 +bpf_validate(f, len,mem_ex_size) struct bpf_insn *f; - int len; + int32 len; + uint32 mem_ex_size; { - register int i; + register int32 i,j; register struct bpf_insn *p; - + int32 flag; + for (i = 0; i < len; ++i) { /* * Check that that jumps are forward, and within * the code block. */ + p = &f[i]; + + IF_LOUD(DbgPrint("Validating program");) + + flag=0; + for(j=0;jcode==valid_instructions[j]) + flag=1; + if (flag==0) + return 0; + + IF_LOUD(DbgPrint("Validating program: no unknown instructions");) + if (BPF_CLASS(p->code) == BPF_JMP) { - register int from = i + 1; + register int32 from = i + 1; if (BPF_OP(p->code) == BPF_JA) { if (from + p->k >= len) @@ -698,14 +924,33 @@ bpf_validate(f, len) else if (from + p->jt >= len || from + p->jf >= len) return 0; } + + IF_LOUD(DbgPrint("Validating program: no wrong JUMPS");) + /* * Check that memory operations use valid addresses. */ - if ((BPF_CLASS(p->code) == BPF_ST || + if (((BPF_CLASS(p->code) == BPF_ST && ((p->code &BPF_MEM_EX_IMM)!=BPF_MEM_EX_IMM && (p->code &BPF_MEM_EX_IND)!=BPF_MEM_EX_IND)) || (BPF_CLASS(p->code) == BPF_LD && (p->code & 0xe0) == BPF_MEM)) && - (p->k >= BPF_MEMWORDS || p->k < 0)) + (p->k >= BPF_MEMWORDS || p->k < 0)) return 0; + + IF_LOUD(DbgPrint("Validating program: no wrong ST/LD memory locations");) + + /* + * Check if key stores use valid addresses + */ + if (BPF_CLASS(p->code) == BPF_ST && (p->code &BPF_MEM_EX_IMM)==BPF_MEM_EX_IMM) + switch (BPF_SIZE(p->code)) + { + case BPF_W: if (p->k<0 || p->k+3>=(int32)mem_ex_size) return 0; + case BPF_H: if (p->k<0 || p->k+1>=(int32)mem_ex_size) return 0; + case BPF_B: if (p->k<0 || p->k>=(int32)mem_ex_size) return 0; + } + + IF_LOUD(DbgPrint("Validating program: no wrong ST/LD mem_ex locations");) + /* * Check for constant division by 0. */ @@ -713,4 +958,4 @@ bpf_validate(f, len) return 0; } return BPF_CLASS(f[len - 1].code) == BPF_RET; -} +} \ No newline at end of file diff --git a/reactos/drivers/net/packet/win_bpf_filter_init.c b/reactos/drivers/net/packet/win_bpf_filter_init.c new file mode 100644 index 00000000000..96e7e4cb44a --- /dev/null +++ b/reactos/drivers/net/packet/win_bpf_filter_init.c @@ -0,0 +1,569 @@ +/* + * 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. + * + * + * + * Portions copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "tme.h" +#include "win_bpf.h" + +/* + * Initialize the filter machine + */ +uint32 bpf_filter_init(register struct bpf_insn *pc, MEM_TYPE *mem_ex, TME_CORE *tme, struct time_conv *time_ref) +{ + register uint32 A, X; + int32 mem[BPF_MEMWORDS]; + register int32 k; + uint32 *tmp; + uint16 *tmp2; + uint32 j; + if (pc == 0) + /* + * No filter means accept all. + */ + return (uint32)-1; + A = 0; + X = 0; + --pc; + while (1) { + ++pc; + switch (pc->code) { + + default: + return 0; + +/* RET INSTRUCTIONS */ + case BPF_RET|BPF_K: + return (uint32)pc->k; + + case BPF_RET|BPF_A: + return (uint32)A; +/* END RET INSTRUCTIONS */ + +/* LD NO PACKET INSTRUCTIONS */ + case BPF_LD|BPF_IMM: + A = pc->k; + continue; + + case BPF_LDX|BPF_IMM: + X = pc->k; + continue; + + case BPF_LD|BPF_MEM: + A = mem[pc->k]; + continue; + + case BPF_LDX|BPF_MEM: + X = mem[pc->k]; + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_B: + A= mem_ex->buffer[pc->k]; + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_B: + X= mem_ex->buffer[pc->k]; + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16*)&mem_ex->buffer[pc->k]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx,tmp2 + xor eax, eax + mov ax, [ebx] + bswap eax + mov A, eax + pop ebx + pop eax + } +#else +#endif + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16*)&mem_ex->buffer[pc->k]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx,tmp2 + xor eax, eax + mov ax, [ebx] + bswap eax + mov X, eax + pop ebx + pop eax + } +#else +#endif + continue; + + case BPF_LD|BPF_MEM_EX_IMM|BPF_W: + tmp=(uint32*)&mem_ex->buffer[pc->k]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx,tmp + mov eax, [ebx] + bswap eax + mov A, eax + pop ebx + pop eax + } +#else +#endif + continue; + + case BPF_LDX|BPF_MEM_EX_IMM|BPF_W: + tmp=(uint32*)&mem_ex->buffer[pc->k]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx,tmp + mov eax, [ebx] + bswap eax + mov X, eax + pop ebx + pop eax + } +#else +#endif + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_B: + k = X + pc->k; + if ((int32)k>= (int32)mem_ex->size) { + return 0; + } + A= mem_ex->buffer[k]; + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_H: + k = X + pc->k; + if ((int32)(k+1)>= (int32)mem_ex->size) { + return 0; + } + tmp2=(uint16*)&mem_ex->buffer[k]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx,tmp2 + xor eax, eax + mov ax, [ebx] + bswap eax + mov A, eax + pop ebx + pop eax + } +#else +#endif + continue; + + case BPF_LD|BPF_MEM_EX_IND|BPF_W: + k = X + pc->k; + if ((int32)(k+3)>= (int32)mem_ex->size) { + return 0; + } + tmp=(uint32*)&mem_ex->buffer[k]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx,tmp + mov eax, [ebx] + bswap eax + mov A, eax + pop ebx + pop eax + } +#else +#endif + continue; +/* END LD NO PACKET INSTRUCTIONS */ + +/* STORE INSTRUCTIONS */ + case BPF_ST: + mem[pc->k] = A; + continue; + + case BPF_STX: + mem[pc->k] = X; + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)A; + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_B: + mem_ex->buffer[pc->k]=(uint8)X; + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_W: + tmp=(uint32*)&mem_ex->buffer[pc->k]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx, tmp + mov eax, A + bswap eax + mov [ebx], eax + pop ebx + pop eax + } +#else +#endif + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_W: + tmp=(uint32*)&mem_ex->buffer[pc->k]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx, tmp + mov eax, X + bswap eax + mov [ebx], eax + pop ebx + pop eax + } +#else +#endif + continue; + + case BPF_ST|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16*)&mem_ex->buffer[pc->k]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx, tmp2 + mov eax, A + xchg ah, al + mov [ebx], ax + pop ebx + pop eax + } +#else +#endif + continue; + + case BPF_STX|BPF_MEM_EX_IMM|BPF_H: + tmp2=(uint16*)&mem_ex->buffer[pc->k]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx, tmp2 + mov eax, X + xchg ah, al + mov [ebx], ax + pop ebx + pop eax + } +#else +#endif + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_B: + mem_ex->buffer[pc->k+X]=(uint8)A; + + case BPF_ST|BPF_MEM_EX_IND|BPF_W: + tmp=(uint32*)&mem_ex->buffer[pc->k+X]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx, tmp + mov eax, A + bswap eax + mov [ebx], eax + pop ebx + pop eax + } +#else +#endif + continue; + + case BPF_ST|BPF_MEM_EX_IND|BPF_H: + tmp2=(uint16*)&mem_ex->buffer[pc->k+X]; +#ifndef __GNUC__ + __asm + { + push eax + push ebx + mov ebx, tmp2 + mov eax, A + xchg ah, al + mov [ebx], ax + pop ebx + pop eax + } +#else +#endif + continue; +/* END STORE INSTRUCTIONS */ + +/* JUMP INSTRUCTIONS */ + case BPF_JMP|BPF_JA: + pc += pc->k; + continue; + + case BPF_JMP|BPF_JGT|BPF_K: + pc += ((int32)A > (int32)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_K: + pc += ((int32)A >= (int32)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_K: + pc += ((int32)A == (int32)pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_K: + pc += (A & pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGT|BPF_X: + pc += (A > X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_X: + pc += (A >= X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_X: + pc += (A == X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_X: + pc += (A & X) ? pc->jt : pc->jf; + continue; +/* END JUMP INSTRUCTIONS */ + +/* ARITHMETIC INSTRUCTIONS */ + case BPF_ALU|BPF_ADD|BPF_X: + A += X; + continue; + + case BPF_ALU|BPF_SUB|BPF_X: + A -= X; + continue; + + case BPF_ALU|BPF_MUL|BPF_X: + A *= X; + continue; + + case BPF_ALU|BPF_DIV|BPF_X: + if (X == 0) + return 0; + A /= X; + continue; + + case BPF_ALU|BPF_AND|BPF_X: + A &= X; + continue; + + case BPF_ALU|BPF_OR|BPF_X: + A |= X; + continue; + + case BPF_ALU|BPF_LSH|BPF_X: + A <<= X; + continue; + + case BPF_ALU|BPF_RSH|BPF_X: + A >>= X; + continue; + + case BPF_ALU|BPF_ADD|BPF_K: + A += pc->k; + continue; + + case BPF_ALU|BPF_SUB|BPF_K: + A -= pc->k; + continue; + + case BPF_ALU|BPF_MUL|BPF_K: + A *= pc->k; + continue; + + case BPF_ALU|BPF_DIV|BPF_K: + A /= pc->k; + continue; + + case BPF_ALU|BPF_AND|BPF_K: + A &= pc->k; + continue; + + case BPF_ALU|BPF_OR|BPF_K: + A |= pc->k; + continue; + + case BPF_ALU|BPF_LSH|BPF_K: + A <<= pc->k; + continue; + + case BPF_ALU|BPF_RSH|BPF_K: + A >>= pc->k; + continue; + + case BPF_ALU|BPF_NEG: + (int32)A = -((int32)A); + continue; +/* ARITHMETIC INSTRUCTIONS */ + +/* MISC INSTRUCTIONS */ + case BPF_MISC|BPF_TAX: + X = A; + continue; + + case BPF_MISC|BPF_TXA: + A = X; + continue; +/* END MISC INSTRUCTIONS */ + +/* TME INSTRUCTIONS */ + case BPF_MISC|BPF_TME|BPF_LOOKUP: + j=lookup_frontend(mem_ex,tme,pc->k,time_ref); + if (j==TME_ERROR) + return 0; + pc += (j == TME_TRUE) ? pc->jt : pc->jf; + continue; + + case BPF_MISC|BPF_TME|BPF_EXECUTE: + if (execute_frontend(mem_ex,tme,0,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_INIT: + if (init_tme_block(tme,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_VALIDATE: + if (validate_tme_block(mem_ex,tme,A,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_MEMORY: + if (init_extended_memory(pc->k,mem_ex)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_ACTIVE: + if (set_active_tme_block(tme,pc->k)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_ACTIVE_READ: + if (set_active_tme_block(tme,pc->k)==TME_ERROR) + return 0; + continue; + case BPF_MISC|BPF_TME|BPF_SET_WORKING: + if ((pc->k<0)||(pc->k>=MAX_TME_DATA_BLOCKS)) + return 0; + tme->working=pc->k; + continue; + + + + case BPF_MISC|BPF_TME|BPF_RESET: + if (reset_tme(tme)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_GET_REGISTER_VALUE: + if (get_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,&j)==TME_ERROR) + return 0; + A=j; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_REGISTER_VALUE: + if (set_tme_block_register(&tme->block_data[tme->working],mem_ex,pc->k,A,TRUE)==TME_ERROR) + return 0; + continue; + + case BPF_MISC|BPF_TME|BPF_SET_AUTODELETION: + set_autodeletion(&tme->block_data[tme->working],pc->k); + continue; + +/* END TME INSTRUCTIONS */ + + } + } +} + diff --git a/reactos/drivers/net/packet/win_bpf_filter_init.h b/reactos/drivers/net/packet/win_bpf_filter_init.h new file mode 100644 index 00000000000..23e7a9f99be --- /dev/null +++ b/reactos/drivers/net/packet/win_bpf_filter_init.h @@ -0,0 +1,31 @@ +/* + * 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 __FILTER_INIT +#define __FILTER_INIT + +#include "tme.h" + +#define INIT_OK 1 +#define INIT_ERROR 0 + +uint32 bpf_filter_init(register struct bpf_insn *pc,MEM_TYPE *mem_ex, TME_CORE *tme, struct time_conv *time_ref); + +#endif \ No newline at end of file diff --git a/reactos/drivers/net/packet/write.c b/reactos/drivers/net/packet/write.c index 470c8c01dc7..f12818f05f7 100644 --- a/reactos/drivers/net/packet/write.c +++ b/reactos/drivers/net/packet/write.c @@ -26,7 +26,6 @@ #include "ndis.h" #else #include -//#include #include #endif @@ -34,12 +33,10 @@ #include "packet.h" - -int nsent; - //------------------------------------------------------------------- -NTSTATUS STDCALL -PacketWrite( +NTSTATUS +//STDCALL +NPF_Write( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) @@ -59,9 +56,7 @@ PacketWrite( Open=IrpSp->FileObject->FsContext; - // // Check the length of the packet to avoid to use an empty packet - // if(IrpSp->Parameters.Write.Length==0) { Irp->IoStatus.Status = NDIS_STATUS_SUCCESS; @@ -79,9 +74,7 @@ PacketWrite( for(i=0;iNwrites;i++){ - // // Try to get a packet from our list of free ones - // NdisAllocatePacket( &Status, &pPacket, @@ -90,35 +83,30 @@ PacketWrite( if (Status != NDIS_STATUS_SUCCESS) { - // // No free packets - // Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest (Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } + // The packet has a buffer that needs not to be freed after every single write + RESERVED(pPacket)->FreeBufAfterWrite = FALSE; + + // Save the IRP associated with the packet RESERVED(pPacket)->Irp=Irp; - // // Attach the writes buffer to the packet - // NdisChainBufferAtFront(pPacket,Irp->MdlAddress); - // // Call the MAC - // - NdisSend( &Status, Open->AdapterHandle, pPacket); if (Status != NDIS_STATUS_PENDING) { - // // The send didn't pend so call the completion handler now - // - PacketSendComplete( + NPF_SendComplete( Open, pPacket, Status @@ -138,50 +126,207 @@ PacketWrite( //------------------------------------------------------------------- -VOID -PacketSendComplete( - IN NDIS_HANDLE ProtocolBindingContext, - IN PNDIS_PACKET pPacket, - IN NDIS_STATUS Status - ) +INT +NPF_BufferedWrite( + IN PIRP Irp, + IN PCHAR UserBuff, + IN ULONG UserBuffSize, + BOOLEAN Sync) { - PIRP Irp; - PIO_STACK_LOCATION irpSp; - POPEN_INSTANCE Open; - - IF_LOUD(DbgPrint("Packet: SendComplete, BindingContext=%d\n",ProtocolBindingContext);) - - Open= (POPEN_INSTANCE)ProtocolBindingContext; - - if((Open->Nwrites-Open->Multiple_Write_Counter)%100==99) - NdisSetEvent(&Open->WriteEvent); + POPEN_INSTANCE Open; + PIO_STACK_LOCATION IrpSp; + PNDIS_PACKET pPacket; + UINT i; + NDIS_STATUS Status; + LARGE_INTEGER StartTicks, CurTicks, TargetTicks; + LARGE_INTEGER TimeFreq; + struct timeval BufStartTime; + struct sf_pkthdr *winpcap_hdr; + PMDL TmpMdl; + PCHAR CurPos; + PCHAR EndOfUserBuff = UserBuff + UserBuffSize; - Open->Multiple_Write_Counter--; + IF_LOUD(DbgPrint("NPF: BufferedWrite, UserBuff=%x, Size=%u\n", UserBuff, UserBuffSize);) + + IrpSp = IoGetCurrentIrpStackLocation(Irp); - Irp=RESERVED(pPacket)->Irp; - irpSp = IoGetCurrentIrpStackLocation(Irp); + Open=IrpSp->FileObject->FsContext; + + // Security check on the length of the user buffer + if(UserBuff==0) + { + return 0; + } + + // Start from the first packet + winpcap_hdr = (struct sf_pkthdr*)UserBuff; + + // Retrieve the time references + StartTicks = KeQueryPerformanceCounter(&TimeFreq); + BufStartTime.tv_sec = winpcap_hdr->ts.tv_sec; + BufStartTime.tv_usec = winpcap_hdr->ts.tv_usec; + + // Chech the consistency of the user buffer + if( (PCHAR)winpcap_hdr + winpcap_hdr->caplen + sizeof(struct sf_pkthdr) > EndOfUserBuff ) + { + IF_LOUD(DbgPrint("Buffered Write: bogus packet buffer\n");) + + return -1; + } + + // Save the current time stamp counter + CurTicks = KeQueryPerformanceCounter(NULL); + + // Main loop: send the buffer to the wire + while( TRUE ){ + + if(winpcap_hdr->caplen ==0 || winpcap_hdr->caplen > 65536) + { + // Malformed header + IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed user buffer, aborting write.\n");) + + return -1; + } + + // Allocate an MDL to map the packet data + TmpMdl=IoAllocateMdl((PCHAR)winpcap_hdr + sizeof(struct sf_pkthdr), + winpcap_hdr->caplen, + FALSE, + FALSE, + NULL); + + if (TmpMdl == NULL) + { + // Unable to map the memory: packet lost + IF_LOUD(DbgPrint("NPF_BufferedWrite: unable to allocate the MDL.\n");) + + return -1; + } + + MmBuildMdlForNonPagedPool(TmpMdl); // XXX can this line be removed? + + // Allocate a packet from our free list + NdisAllocatePacket( &Status, &pPacket, Open->PacketPool); + + if (Status != NDIS_STATUS_SUCCESS) { + // No free packets + IF_LOUD(DbgPrint("NPF_BufferedWrite: no more free packets, returning.\n");) + + return (PCHAR)winpcap_hdr - UserBuff; + } + + // The packet has a buffer that needs to be freed after every single write + RESERVED(pPacket)->FreeBufAfterWrite = TRUE; + + // Attach the MDL to the packet + NdisChainBufferAtFront(pPacket,TmpMdl); + + // Call the MAC + NdisSend( &Status, Open->AdapterHandle, pPacket); + + if (Status != NDIS_STATUS_PENDING) { + // The send didn't pend so call the completion handler now + NPF_SendComplete( + Open, + pPacket, + Status + ); + } + + // Step to the next packet in the buffer + (PCHAR)winpcap_hdr += winpcap_hdr->caplen + sizeof(struct sf_pkthdr); + + // Check if the end of the user buffer has been reached + if( (PCHAR)winpcap_hdr >= EndOfUserBuff ) + { + IF_LOUD(DbgPrint("NPF_BufferedWrite: End of buffer.\n");) + + return (PCHAR)winpcap_hdr - UserBuff; + } + + if( Sync ){ + +#if 0 + // Release the application if it has been blocked for approximately more than 1 seconds + if( winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec > 1 ) + { + IF_LOUD(DbgPrint("NPF_BufferedWrite: timestamp elapsed, returning.\n");) + + return (PCHAR)winpcap_hdr - UserBuff; + } + + // Calculate the time interval to wait before sending the next packet + TargetTicks.QuadPart = StartTicks.QuadPart + + (LONGLONG)((winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec) * 1000000 + + winpcap_hdr->ts.tv_usec - BufStartTime.tv_usec) * + (TimeFreq.QuadPart) / 1000000; + + // Wait until the time interval has elapsed + while( CurTicks.QuadPart <= TargetTicks.QuadPart ) + CurTicks = KeQueryPerformanceCounter(NULL); +#endif + + } + + } + + return (PCHAR)winpcap_hdr - UserBuff; + +} + + +//------------------------------------------------------------------- + +VOID +NPF_SendComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET pPacket, + IN NDIS_STATUS Status + ) + +{ + PIRP Irp; + PIO_STACK_LOCATION irpSp; + POPEN_INSTANCE Open; + PMDL TmpMdl; + + IF_LOUD(DbgPrint("NPF: SendComplete, BindingContext=%d\n",ProtocolBindingContext);) + + Open= (POPEN_INSTANCE)ProtocolBindingContext; + + if( RESERVED(pPacket)->FreeBufAfterWrite ){ + // Free the MDL associated with the packet + NdisUnchainBufferAtFront(pPacket, &TmpMdl); + IoFreeMdl(TmpMdl); + } + else{ + if((Open->Nwrites - Open->Multiple_Write_Counter) %100 == 99) + NdisSetEvent(&Open->WriteEvent); + + Open->Multiple_Write_Counter--; + } - // // recyle the packet - // NdisReinitializePacket(pPacket); - // // Put the packet back on the free list - // NdisFreePacket(pPacket); - if(Open->Multiple_Write_Counter==0){ - // - // wake the application - // - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = irpSp->Parameters.Write.Length; - IoCompleteRequest(Irp, IO_NO_INCREMENT); + if( !(RESERVED(pPacket)->FreeBufAfterWrite) ){ + if(Open->Multiple_Write_Counter==0){ + // Release the buffer and awake the application + NdisUnchainBufferAtFront(pPacket, &TmpMdl); + + Irp=RESERVED(pPacket)->Irp; + irpSp = IoGetCurrentIrpStackLocation(Irp); + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = irpSp->Parameters.Write.Length; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + } } - return; - + return; }