/*
 * Copyright (c) 1999, 2000
 *	Politecnico di Torino.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that: (1) source code distributions
 * retain the above copyright notice and this paragraph in its entirety, (2)
 * distributions including binary code include the above copyright notice and
 * this paragraph in its entirety in the documentation or other materials
 * provided with the distribution, and (3) all advertising materials mentioning
 * features or use of this software display the following acknowledgement:
 * ``This product includes software developed by the Politecnico
 * di Torino, and its contributors.'' Neither the name of
 * the University nor the names of its contributors may be used to endorse
 * or promote products derived from this software without specific prior
 * written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _MSC_VER
#include "stdarg.h"
#include "ntddk.h"
#include "ntiologc.h"
#include "ndis.h"
#else
#include <ddk/ntddk.h>
#include <net/ndis.h>
#endif

#include "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 + PACKET_DEBUG_VERY_LOUD + PACKET_DEBUG_INIT;

#endif

PDEVICE_EXTENSION GlobalDeviceExtension;

////////////////////////////////////////////////////////////////////////////////
#define ROBERTS_PATCH
#ifdef ROBERTS_PATCH

#define NDIS_STRING_CONST(x)	{sizeof(L##x)-2, sizeof(L##x), L##x}

//void __moddi3(void) {}
//void __divdi3(void) {}

#endif // ROBERTS_PATCH
////////////////////////////////////////////////////////////////////////////////
//
// Global strings
//
NDIS_STRING NPF_Prefix = NDIS_STRING_CONST("NPF_");
NDIS_STRING devicePrefix = NDIS_STRING_CONST("\\Device\\");
NDIS_STRING symbolicLinkPrefix = NDIS_STRING_CONST("\\DosDevices\\");
NDIS_STRING tcpLinkageKeyName = NDIS_STRING_CONST("\\Registry\\Machine\\System"
								L"\\CurrentControlSet\\Services\\Tcpip\\Linkage");
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
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
#ifdef __GNUC__
STDCALL
#endif
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
{

    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;
    PWSTR          BindString;
    PWSTR          ExportString;
    PWSTR          BindStringSave;
    PWSTR          ExportStringSave;
    NDIS_HANDLE    NdisProtocolHandle;
	WCHAR* bindT;
	PKEY_VALUE_PARTIAL_INFORMATION tcpBindingsP;
	UNICODE_STRING macName;
	
	// This driver at the moment works only on single processor machines
	if(NdisSystemProcessorCount() != 1){
		return STATUS_IMAGE_MP_UP_MISMATCH;
	}

    IF_LOUD(DbgPrint("Packet: DriverEntry\n");)

	RtlZeroMemory(&ProtocolChar,sizeof(NDIS_PROTOCOL_CHARACTERISTICS));

#ifdef NDIS50
    ProtocolChar.MajorNdisVersion            = 5;
#else
    ProtocolChar.MajorNdisVersion            = 3;
#endif
    ProtocolChar.MinorNdisVersion            = 0;
#ifndef __GNUC__
    ProtocolChar.Reserved                    = 0;
#else
    ProtocolChar.u1.Reserved                 = 0;
#endif
    ProtocolChar.OpenAdapterCompleteHandler  = NPF_OpenAdapterComplete;
    ProtocolChar.CloseAdapterCompleteHandler = NPF_CloseAdapterComplete;
#ifndef __GNUC__
    ProtocolChar.SendCompleteHandler         = NPF_SendComplete;
    ProtocolChar.TransferDataCompleteHandler = NPF_TransferDataComplete;
#else
    ProtocolChar.u2.SendCompleteHandler         = NPF_SendComplete;
    ProtocolChar.u3.TransferDataCompleteHandler = NPF_TransferDataComplete;
#endif
    ProtocolChar.ResetCompleteHandler        = NPF_ResetComplete;
    ProtocolChar.RequestCompleteHandler      = NPF_RequestComplete;
#ifndef __GNUC__
    ProtocolChar.ReceiveHandler              = NPF_tap;
#else
    ProtocolChar.u4.ReceiveHandler           = NPF_tap;
#endif
    ProtocolChar.ReceiveCompleteHandler      = NPF_ReceiveComplete;
    ProtocolChar.StatusHandler               = NPF_Status;
    ProtocolChar.StatusCompleteHandler       = NPF_StatusComplete;
#ifdef NDIS50
    ProtocolChar.BindAdapterHandler          = NPF_BindAdapter;
    ProtocolChar.UnbindAdapterHandler        = NPF_UnbindAdapter;
    ProtocolChar.PnPEventHandler             = NPF_PowerChange;
    ProtocolChar.ReceivePacketHandler        = NULL;
#endif
    ProtocolChar.Name                        = ProtoName;

    NdisRegisterProtocol(
        &Status,
        &NdisProtocolHandle,
        &ProtocolChar,
        sizeof(NDIS_PROTOCOL_CHARACTERISTICS));

    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] = 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=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
    //
    while (*BindString!= UNICODE_NULL && *ExportString!= UNICODE_NULL) {
        //
        //  Create a counted unicode string for both null terminated strings
        //
        RtlInitUnicodeString(
            &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("NPF: DeviceName=%ws  MacName=%ws\n",UnicodeDeviceName.Buffer,MacDriverName.Buffer);)
        //
        //  Create the device object
        //
        Status = IoCreateDevice(
                    DriverObject,
                    sizeof(DEVICE_EXTENSION),
                    &UnicodeDeviceName,
                    FILE_DEVICE_PROTOCOL,
                    0,
                    FALSE,
                    &DeviceObject);
        if (Status != STATUS_SUCCESS) {
            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 one device.
        //
        IF_LOUD(DbgPrint("NPF: Managed to create at least one device.\n");)
        return STATUS_SUCCESS;
    }
    ExFreePool(BindStringSave);
    ExFreePool(ExportStringSave);
 */

RegistryError:
    IF_LOUD(DbgPrint("NPF: RegistryError: calling NdisDeregisterProtocol()\n");)
    NdisDeregisterProtocol(
        &Status,
        NdisProtocolHandle
        );

    Status=STATUS_UNSUCCESSFUL;

    return(Status);

}

//-------------------------------------------------------------------

PWCHAR getAdaptersList(void)
{
	PKEY_VALUE_PARTIAL_INFORMATION result = NULL;
	OBJECT_ATTRIBUTES objAttrs;
	NTSTATUS status;
	HANDLE keyHandle;
	UINT BufPos=0;
	
#define NPF_TAG_DEVICENAME  TAG('0', 'P', 'W', 'A')
	PWCHAR DeviceNames = (PWCHAR) ExAllocatePoolWithTag(PagedPool, 4096, NPF_TAG_DEVICENAME);
	
	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);
	if (!NT_SUCCESS(status)) {

        //IF_LOUD(DbgPrint("Status of %x opening %ws\n", status, tcpLinkageKeyName.Buffer);)
        IF_LOUD(DbgPrint("Status of %x opening %ws\n", status, AdapterListKey.Buffer);)

    } else { //OK
		ULONG resultLength;
		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)	{
				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}");
				PWCHAR LinkageKeyPrefix = L"\\Linkage";
				UINT LinkageKeyPrefixSize = sizeof(L"\\Linkage");
				NDIS_STRING FinalExportKey = NDIS_STRING_CONST("Export");
				PKEY_BASIC_INFORMATION tInfo= (PKEY_BASIC_INFORMATION)AdapInfo;
				UNICODE_STRING AdapterKeyName;
				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]);
#define NPF_TAG_KEYVALUE  TAG('1', 'P', 'W', 'A')
					PKEY_VALUE_PARTIAL_INFORMATION valueInfoP =	(PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag(PagedPool, valueInfoLength, NPF_TAG_KEYVALUE);
					if (valueInfoP != NULL) {
						status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey,
							KeyValuePartialInformation,
							valueInfoP,
							valueInfoLength, &resultLength);
						if (!NT_SUCCESS(status)) {
							IF_LOUD(DbgPrint("Status of %x querying key value\n", status);)
                        } 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;
}

//-------------------------------------------------------------------

PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(void)
{
  PKEY_VALUE_PARTIAL_INFORMATION result = NULL;
  OBJECT_ATTRIBUTES objAttrs;
  NTSTATUS status;
  HANDLE keyHandle;

  InitializeObjectAttributes(&objAttrs, &tcpLinkageKeyName,
                             OBJ_CASE_INSENSITIVE, NULL, NULL);
  status = ZwOpenKey(&keyHandle, KEY_READ, &objAttrs);
  if (!NT_SUCCESS(status)) {
    IF_LOUD(DbgPrint("\n\nStatus of %x opening %ws\n", status, tcpLinkageKeyName.Buffer);)
  } else {
    ULONG resultLength;
    KEY_VALUE_PARTIAL_INFORMATION valueInfo;

    IF_LOUD(DbgPrint("\n\nOpened %ws\n", tcpLinkageKeyName.Buffer);)

    status = ZwQueryValueKey(keyHandle, &bindValueName,
                             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]);
#define NPF_TAG_KEYVALUE2  TAG('2', 'P', 'W', 'A')
      PKEY_VALUE_PARTIAL_INFORMATION valueInfoP =
        (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(PagedPool, valueInfoLength, NPF_TAG_KEYVALUE2);
      
	  if (valueInfoP != NULL) {
        status = ZwQueryValueKey(keyHandle, &bindValueName,
                                 KeyValuePartialInformation,
                                 valueInfoP,
                                 valueInfoLength, &resultLength);
      
		if (!NT_SUCCESS(status)) {
          IF_LOUD(DbgPrint("\n\nStatus of %x querying key value\n", status);)
        }
        else if (valueInfoLength != resultLength) {
          IF_LOUD(DbgPrint("\n\nQuerying key value result len = %u "
                     "but previous len = %u\n",
                     resultLength, valueInfoLength);)
        }
        else if (valueInfoP->Type != REG_MULTI_SZ) {
          IF_LOUD(DbgPrint("\n\nTcpip bind value not REG_MULTI_SZ but %u\n",
                     valueInfoP->Type);)
        }
        else {                  // It's OK
#if DBG
          ULONG i;
          WCHAR* dataP = (WCHAR*)(&valueInfoP->Data[0]);
          IF_LOUD(DbgPrint("\n\nBind value:\n");)
          for (i = 0; *dataP != UNICODE_NULL; i++) {
            UNICODE_STRING macName;
            RtlInitUnicodeString(&macName, dataP);
            IF_LOUD(DbgPrint("\n\nMac %u = %ws\n", i, macName.Buffer);)
            dataP +=
              (macName.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR);
          }
#endif // DBG
          result = valueInfoP;
        }
      }
    }
    ZwClose(keyHandle);
  }
  return result;
}

//-------------------------------------------------------------------

BOOLEAN createDevice(IN OUT PDRIVER_OBJECT adriverObjectP,
                     IN PUNICODE_STRING amacNameP, NDIS_HANDLE aProtoHandle)
{
    NTSTATUS status;
    PDEVICE_OBJECT devObjP;
    UNICODE_STRING deviceName;
	UNICODE_STRING deviceSymLink;

	IF_LOUD(DbgPrint("\n\ncreateDevice for MAC %ws\n", amacNameP->Buffer););
    if (RtlCompareMemory(amacNameP->Buffer, devicePrefix.Buffer,
                       devicePrefix.Length) < devicePrefix.Length) {
		return FALSE;
    }

    deviceName.Length = 0;
    deviceName.MaximumLength = (USHORT)(amacNameP->Length + NPF_Prefix.Length + sizeof(UNICODE_NULL));
#define NPF_TAG_DEVICENAMEBUF  TAG('3', 'P', 'W', 'A')
    deviceName.Buffer = ExAllocatePoolWithTag(PagedPool, deviceName.MaximumLength, NPF_TAG_DEVICENAMEBUF);
 
	if (deviceName.Buffer == NULL)
		return FALSE;

	deviceSymLink.Length = 0;
	deviceSymLink.MaximumLength =(USHORT)(amacNameP->Length-devicePrefix.Length 
		+ symbolicLinkPrefix.Length 
		+ NPF_Prefix.Length 
		+ sizeof(UNICODE_NULL));

#define NPF_TAG_SYMLINKBUF  TAG('3', 'P', 'W', 'A')
	deviceSymLink.Buffer = ExAllocatePoolWithTag(NonPagedPool, deviceSymLink.MaximumLength, NPF_TAG_SYMLINKBUF);

	if (deviceSymLink.Buffer  == NULL)
	{
		ExFreePool(deviceName.Buffer);
		return FALSE;
	}

    RtlAppendUnicodeStringToString(&deviceName, &devicePrefix);
    RtlAppendUnicodeStringToString(&deviceName, &NPF_Prefix);
    RtlAppendUnicodeToString(&deviceName, amacNameP->Buffer +
                             devicePrefix.Length / sizeof(WCHAR));
    
	RtlAppendUnicodeStringToString(&deviceSymLink, &symbolicLinkPrefix);
	RtlAppendUnicodeStringToString(&deviceSymLink, &NPF_Prefix);
	RtlAppendUnicodeToString(&deviceSymLink, amacNameP->Buffer +
		devicePrefix.Length / sizeof(WCHAR));

	IF_LOUD(DbgPrint("Creating device 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("Device created successfully\n"););

        devObjP->Flags |= DO_DIRECT_IO;
        RtlInitUnicodeString(&devExtP->AdapterName,amacNameP->Buffer);
		devExtP->NdisProtocolHandle=aProtoHandle;

		IF_LOUD(DbgPrint("Trying to create SymLink %ws\n",deviceSymLink.Buffer););

		if (IoCreateSymbolicLink(&deviceSymLink,&deviceName) != STATUS_SUCCESS)	{
			IF_LOUD(DbgPrint("\n\nError creating SymLink %ws\nn", deviceSymLink.Buffer););

			ExFreePool(deviceName.Buffer);
			ExFreePool(deviceSymLink.Buffer);

			devExtP->ExportString = NULL;

			return FALSE;
    }

		IF_LOUD(DbgPrint("SymLink %ws successfully created.\n\n", deviceSymLink.Buffer););

		devExtP->ExportString = deviceSymLink.Buffer;

        ExFreePool(deviceName.Buffer);

		return TRUE;
    }
  
	else 
	{
		IF_LOUD(DbgPrint("\n\nIoCreateDevice status = %x\n", status););

		ExFreePool(deviceName.Buffer);
		ExFreePool(deviceSymLink.Buffer);
		
		return FALSE;
	}
}

//-------------------------------------------------------------------

VOID
NPF_Unload(IN PDRIVER_OBJECT DriverObject)
{
    PDEVICE_OBJECT     DeviceObject;
    PDEVICE_OBJECT     OldDeviceObject;
    PDEVICE_EXTENSION  DeviceExtension;
	
    NDIS_HANDLE        NdisProtocolHandle;
    NDIS_STATUS        Status;
	
	NDIS_STRING		   SymLink;

    IF_LOUD(DbgPrint("NPF: Unload\n"););

	DeviceObject    = DriverObject->DeviceObject;

    while (DeviceObject != NULL) {
        OldDeviceObject=DeviceObject;
		
        DeviceObject=DeviceObject->NextDevice;

		DeviceExtension = OldDeviceObject->DeviceExtension;

        NdisProtocolHandle=DeviceExtension->NdisProtocolHandle;

		IF_LOUD(DbgPrint("Deleting Adapter %ws, Protocol Handle=%x, Device Obj=%x (%x)\n",
			DeviceExtension->AdapterName.Buffer,
			NdisProtocolHandle,
			DeviceObject,
			OldDeviceObject););

		if (DeviceExtension->ExportString)
		{
			RtlInitUnicodeString(&SymLink , DeviceExtension->ExportString);
		
			IF_LOUD(DbgPrint("Deleting SymLink at %p\n", SymLink.Buffer););

			IoDeleteSymbolicLink(&SymLink);
			ExFreePool(DeviceExtension->ExportString);
		}

        IoDeleteDevice(OldDeviceObject);
    }

	NdisDeregisterProtocol(
        &Status,
        NdisProtocolHandle
        );

	// Free the adapters names
	ExFreePool( bindP );
}

//-------------------------------------------------------------------

NTSTATUS
NPF_IoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
    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;
	ULONG				dim,timeout;
	PUCHAR				prog;
	PPACKET_OID_DATA    OidData;
	int					*StatsBuf;
    PNDIS_PACKET        pPacket;
	ULONG				mode;
	PWSTR				DumpNameBuff;
	PUCHAR				TmpBPFProgram;
	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;

    Irp->IoStatus.Status = STATUS_SUCCESS;

    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
		
		if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < 4*sizeof(INT)){			
			EXIT_FAILURE(0);
		}

		*(((PUINT)Irp->UserBuffer)+3) = Open->Accepted;
		*(((PUINT)Irp->UserBuffer)) = Open->Received;
		*(((PUINT)Irp->UserBuffer)+1) = Open->Dropped;
		*(((PUINT)Irp->UserBuffer)+2) = 0;		// Not yet supported
		
		EXIT_SUCCESS(4*sizeof(INT));
		
		break;
		
	case BIOCGEVNAME: //function to get the name of the event associated with the current instance

		if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength<26){			
			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;
			ExFreePool(TmpBPFProgram);
		}
		
		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){
			IF_LOUD(DbgPrint("0001");)
			
			EXIT_FAILURE(0);
		}
		
		insns=(IrpSp->Parameters.DeviceIoControl.InputBufferLength)/sizeof(struct bpf_insn);
		
		//count the number of operative instructions
		for (cnt=0;(cnt<insns) &&(((struct bpf_insn*)prog)[cnt].code!=BPF_SEPARATION); cnt++);
		
		IF_LOUD(DbgPrint("Operative instructions=%u\n",cnt);)

		if (((struct bpf_insn*)prog)[cnt].code==BPF_SEPARATION && (insns-cnt-1)!=0) 
		{
			IF_LOUD(DbgPrint("Initialization instructions=%u\n",insns-cnt-1);)
	
			IsExtendedFilter=TRUE;

			initprogram=&((struct bpf_insn*)prog)[cnt+1];
			
			if(bpf_filter_init(initprogram,&(Open->mem_ex),&(Open->tme), &G_Start_Time)!=INIT_OK)
			{
			
				IF_LOUD(DbgPrint("Error initializing NPF machine (bpf_filter_init)\n");)
				
				EXIT_FAILURE(0);
			}
		}

		//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()
#define NPF_TAG_BPFPROG  TAG('4', 'P', 'W', 'A')
		TmpBPFProgram=(PUCHAR)ExAllocatePoolWithTag(NonPagedPool, cnt*sizeof(struct bpf_insn), NPF_TAG_BPFPROG);
		if (TmpBPFProgram==NULL){
			IF_LOUD(DbgPrint("Error - No memory for filter");)
			// no memory
			EXIT_FAILURE(0);
		}
		
		//copy the program in the new buffer
		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
		Open->Bhead = 0;
		Open->Btail = 0;
		(INT)Open->BLastByte = -1;
		Open->Received = 0;		
		Open->Dropped = 0;
		Open->Accepted = 0;

		EXIT_SUCCESS(IrpSp->Parameters.DeviceIoControl.InputBufferLength);
		
		break;		
		
	case BIOCSMODE:  //set the capture mode
		
		mode=*((PULONG)Irp->AssociatedIrp.SystemBuffer);
		
		if(mode == MODE_CAPT){
			Open->mode=MODE_CAPT;
			
			EXIT_SUCCESS(0);
		}
 		else if (mode==MODE_MON){
 			Open->mode=MODE_MON;

			EXIT_SUCCESS(0);
 		}	
		else{
			if(mode & MODE_STAT){
				Open->mode = MODE_STAT;
				Open->Nbytes.QuadPart=0;
				Open->Npackets.QuadPart=0;
				
				if(Open->TimeOut.QuadPart==0)Open->TimeOut.QuadPart=-10000000;
				
			}
			
			if(mode & MODE_DUMP){
				
				Open->mode |= MODE_DUMP;
				Open->MinToCopy=(Open->BufSize<2000000)?Open->BufSize/2:1000000;
				
			}	
			EXIT_SUCCESS(0);
		}
		
		EXIT_FAILURE(0);
		
		break;

	case BIOCSETDUMPFILENAME:

		if(Open->mode & MODE_DUMP)
		{
			
			// Close current dump file
			if(Open->DumpFileHandle != NULL){
				NPF_CloseDumpFile(Open);
				Open->DumpFileHandle = NULL;
			}
			
			if(IrpSp->Parameters.DeviceIoControl.InputBufferLength == 0){
				EXIT_FAILURE(0);
			}
			
			// Allocate the buffer that will contain the string
#define NPF_TAG_DUMPNAMEBUF  TAG('5', 'P', 'W', 'A')
			DumpNameBuff=ExAllocatePoolWithTag(NonPagedPool, IrpSp->Parameters.DeviceIoControl.InputBufferLength, NPF_TAG_DUMPNAMEBUF);
			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){
#define NPF_TAG_TPOINTER  TAG('6', 'P', 'W', 'A')
			tpointer = ExAllocatePoolWithTag(NonPagedPool, dim, NPF_TAG_TPOINTER);
			if (tpointer==NULL)	{
				// no memory
				Open->BufSize = 0;
				Open->Buffer = NULL;
				EXIT_FAILURE(0);
			}
		}
		else
			tpointer = NULL;

		Open->Buffer = tpointer;
		Open->Bhead = 0;
		Open->Btail = 0;
		(INT)Open->BLastByte = -1;
		
		Open->BufSize = (UINT)dim;
		EXIT_SUCCESS(dim);
		
		break;
		
	case BIOCSRTIMEOUT: //set the timeout on the read calls
		
		timeout = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
		if((int)timeout==-1)
			Open->TimeOut.QuadPart=(LONGLONG)IMMEDIATE;
		else {
			Open->TimeOut.QuadPart=(LONGLONG)timeout;
			Open->TimeOut.QuadPart*=10000;
			Open->TimeOut.QuadPart=-Open->TimeOut.QuadPart;
		}

		//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);
		
		EXIT_SUCCESS(Open->Nwrites);
		
		break;

	case BIOCSMINTOCOPY: //set the minimum buffer's size to copy to the application

		Open->MinToCopy = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
		
		EXIT_SUCCESS(Open->MinToCopy);
		
		break;
		
	case IOCTL_PROTOCOL_RESET:
		
        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("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;
		pRequest->Internal = FALSE;

        
		//
        //  See if it is an Ndis request
        //
        OidData=Irp->AssociatedIrp.SystemBuffer;
		
        if (((FunctionCode == BIOCSETOID) || (FunctionCode == BIOCQUERYOID))
            &&
            (IrpSp->Parameters.DeviceIoControl.InputBufferLength == IrpSp->Parameters.DeviceIoControl.OutputBufferLength)
            &&
            (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(PACKET_OID_DATA))
            &&
            (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(PACKET_OID_DATA)-1+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
				//
				NdisRequest(
					&Status,
					Open->AdapterHandle,
					&pRequest->Request
					);
				
        } else {
            //
            //  buffer too small
            //
            Status=NDIS_STATUS_FAILURE;
            pRequest->Request.DATA.SET_INFORMATION.BytesRead=0;
            pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten=0;
			
        }
		
        if (Status != NDIS_STATUS_PENDING) {
            IF_LOUD(DbgPrint("NPF: Calling RequestCompleteHandler\n");)
				
			NPF_RequestComplete(Open, &pRequest->Request, Status);
            return Status;
			
        }

		NdisWaitEvent(&Open->IOEvent, 5000);

		return(Open->IOStatus);
		
		break;
		
		
	default:
		
		EXIT_FAILURE(0);
	}
	
	return Status;
}

//-------------------------------------------------------------------

VOID
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;
    UINT                FunctionCode;
	KIRQL				OldIrq;

    PPACKET_OID_DATA    OidData;

    IF_LOUD(DbgPrint("NPF: RequestComplete\n");)

    Open= (POPEN_INSTANCE)ProtocolBindingContext;

    pRequest=CONTAINING_RECORD(NdisRequest,INTERNAL_REQUEST,Request);
    Irp=pRequest->Irp;

	if(pRequest->Internal == TRUE){

		// Put the request in the list of the free ones
		ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock);
		
	    if(Status != NDIS_STATUS_SUCCESS)
			Open->MaxFrameSize = 1514;	// Assume Ethernet

		// We always return success, because the adapter has been already opened
		Irp->IoStatus.Status = NDIS_STATUS_SUCCESS;
		Irp->IoStatus.Information = 0;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
		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);)

    ExInterlockedInsertTailList(
        &Open->RequestList,
        &pRequest->ListElement,
        &Open->RequestSpinLock);

    Irp->IoStatus.Status = Status;

	Open->IOStatus = Status;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	// Unlock the caller
	NdisSetEvent(&Open->IOEvent);

    return;


}

//-------------------------------------------------------------------

VOID
NPF_Status(
    IN NDIS_HANDLE   ProtocolBindingContext,
    IN NDIS_STATUS   Status,
    IN PVOID         StatusBuffer,
    IN UINT          StatusBufferSize
    )

{

    IF_LOUD(DbgPrint("NPF: Status Indication\n");)

    return;

}

//-------------------------------------------------------------------

VOID
NPF_StatusComplete(
    IN NDIS_HANDLE  ProtocolBindingContext
    )

{

    IF_LOUD(DbgPrint("NPF: StatusIndicationComplete\n");)

    return;

}

//-------------------------------------------------------------------

NTSTATUS
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;

#define NPF_TAG_PATH  TAG('7', 'P', 'W', 'A')
    Path=ExAllocatePoolWithTag(PagedPool, RegistryPath->Length+sizeof(WCHAR), NPF_TAG_PATH);

    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("NPF: Reg path is %ws\n",RegistryPath->Buffer);)

    RtlZeroMemory(
        ParamTable,
        sizeof(ParamTable)
        );



    //
    //  change to the linkage key
    //
    //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 = 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 = 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,
               ParamTable,
               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
NPF_QueryRegistryRoutine(
    IN PWSTR     ValueName,
    IN ULONG     ValueType,
    IN PVOID     ValueData,
    IN ULONG     ValueLength,
    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;

    }

#define NPF_TAG_REGBUF  TAG('8', 'P', 'W', 'A')
    Buffer=ExAllocatePoolWithTag(NonPagedPool, ValueLength, NPF_TAG_REGBUF);

    if (Buffer==NULL) {

        return STATUS_INSUFFICIENT_RESOURCES;

    }

    RtlCopyMemory(
        Buffer,
        ValueData,
        ValueLength
        );

    *((PUCHAR *)EntryContext)=Buffer;

    return STATUS_SUCCESS;

}
