I have a Bus Driver that creates a PDO for each physical port of a custom Ethernet card. I also have an NDIS Miniport Driver that installs onto each PDO.
The Bus Driver is based on the static Toaster example.
The NDIS Miniport is based on the Netvmini modified to match the hardware.
ToasterInterface.InterfaceHeader.InterfaceReference =
WdfDeviceInterfaceReferenceNoOp;
ToasterInterface.InterfaceHeader.InterfaceDereference =
WdfDeviceInterfaceDereferenceNoOp;
ToasterInterface.GetCrispinessLevel = Bus_GetCrispinessLevel;
ToasterInterface.SetCrispinessLevel = Bus_SetCrispinessLevel;
ToasterInterface.IsSafetyLockEnabled = Bus_IsSafetyLockEnabled;
WDF_QUERY_INTERFACE_CONFIG_INIT(&qiConfig,
(PINTERFACE) &ToasterInterface,
&GUID_TOASTER_INTERFACE_STANDARD,
NULL);
status = WdfDeviceAddQueryInterface(hChild, &qiConfig);
How do I call a KMDF WDF defined interface from an NDIS Driver?
Thanks
From the NDIS side of your driver, you can call NdisMGetDeviceProperty to obtain the FDO of the individual miniport. From there, call IoCallDriver (or IoSynchronousCallDriver to save a couple lines of code) in the usual fashion to issue IRP_MN_QUERY_INTERFACE.
You need to ensure that you dereference the bus interface before your MiniportHalt completes.
Here is the code that worked for me.
// ***********************************
// Inside Header (Both Drivers, Shared)
// ***********************************
typedef
NTSTATUS
(*PMY_BUS_INTERFACE_TEST) (
_In_ PINTERFACE InterfaceHeader,
_In_ PVOID pDataIn,
_In_ size_t szDataInSize
);
typedef struct _MY_BUS_INTERFACE {
INTERFACE InterfaceHeader;
PMY_BUS_INTERFACE_TEST InterfaceTest;
} MY_BUS_INTERFACE, *PMY_BUS_INTERFACE;
#define MY_BUS_INTERFACE_VERSION 1
DEFINE_GUID(GUID_MY_BUS_INTERFACE, 0x12345678, 0x1234, 0x1234, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
// ***********************************
// pdo.c: inside Bus_CreatePdo
// ***********************************
//
// Test Interface
//
MY_BUS_INTERFACE arincInterface;
RtlZeroMemory(&arincInterface, sizeof(MY_BUS_INTERFACE));
arincInterface.InterfaceHeader.Size = sizeof(MY_BUS_INTERFACE);
arincInterface.InterfaceHeader.Version = MY_BUS_INTERFACE_VERSION;
arincInterface.InterfaceHeader.Context = (PVOID)hChild;
arincInterface.InterfaceHeader.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
arincInterface.InterfaceHeader.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
arincInterface.InterfaceTest = Bus_InterfaceTest;
WDF_QUERY_INTERFACE_CONFIG qic;
WDF_QUERY_INTERFACE_CONFIG_INIT(&qic,
(PINTERFACE)&arincInterface,
&GUID_MY_BUS_INTERFACE,
NULL);
// ***********************************
// Inside pdo.c
// ***********************************
NTSTATUS
Bus_InterfaceTest(
_In_ PINTERFACE InterfaceHeader,
_In_ PVOID pDataIn,
_In_ size_t szDataInSize
)
{
NTSTATUS status = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(InterfaceHeader);
UNREFERENCED_PARAMETER(pDataIn);
UNREFERENCED_PARAMETER(szDataInSize);
KdPrint(("Bus_InterfaceTest: pDataIn [%p] [%llu] \n", pDataIn, szDataInSize));
status = -678;
return status;
}
// ***********************************
// Inside Miniport Driver
// ***********************************
//
// Query Interface Setup
//
MY_BUS_INTERFACE myBusInterface;
PMY_BUS_INTERFACE pMyBusInterface = &myBusInterface;
//
// Initialize an event to block on
//
KEVENT event;
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
//
// Build an irp
//
IO_STATUS_BLOCK ioStatus;
PIRP irp = IoBuildSynchronousFsdRequest(
IRP_MJ_PNP,
Adapter->NextDeviceObject,
NULL,
0,
NULL,
&event,
&ioStatus
);
if (!irp) {
pMyBusInterface = NULL;
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
irp->IoStatus.Information = 0;
//
// Get the irp stack location
//
PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation(irp);
//
// Use QUERY_INTERFACE to get the address of the direct-call
// ACPI interfaces.
//
irpSp->MajorFunction = IRP_MJ_PNP;
irpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
irpSp->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_MY_BUS_INTERFACE;
irpSp->Parameters.QueryInterface.Version = MY_BUS_INTERFACE_VERSION;
irpSp->Parameters.QueryInterface.Size = sizeof(MY_BUS_INTERFACE);
irpSp->Parameters.QueryInterface.Interface = (PINTERFACE)pMyBusInterface;
irpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;
//
// send the request down
//
NTSTATUS status = IoCallDriver(Adapter->NextDeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
else if (!NT_SUCCESS(status))
{
KdPrint(("IoCallDriver was not pending or success \n"));
break;
}
//
// test interface
//
char testData[260] = "TEST";
NTSTATUS interfaceTestStatus = (*myBusInterface.InterfaceTest)(
(PINTERFACE)pMyBusInterface,
(PVOID)testData,
strlen(testData)
);
if (interfaceTestStatus == -678)
{
KdPrint(("************************************** \n"));
KdPrint(("*** InterfaceTest SUCCESS *** \n"));
KdPrint(("************************************** \n"));
status = STATUS_SUCCESS;
}
else {
KdPrint(("************************************** \n"));
KdPrint(("*** InterfaceTest FAILURE *** \n"));
KdPrint(("************************************** \n"));
status = STATUS_UNSUCCESSFUL;
(*myBusInterface.InterfaceHeader.InterfaceDereference)(myBusInterface.InterfaceHeader.Context);
break;
}
//
// Dereference Interface
//
(*myBusInterface.InterfaceHeader.InterfaceDereference)(myBusInterface.InterfaceHeader.Context);
Related
so I will detail so that we can easily understand
I have to make a driver for a pcie card, I already have the driver that I wrote in kmdf, now I am using this driver, unfortunately I find myself stuck, I have to write an application (which for example would call the METHOD_IN_DIRECT function that I defined in a switch case in my IoDeviceControl)
I therefore tried to start from an example on github and modified it so that it works ... but obviously as this example is for a NONpnp driver it is not usable for my driver which is pnp.
So I looked for examples of applications that worked with a pnp driver to see the model / shape, but I can't find a tutorial / sites / example on the realization of this famous application, one of the only sites that spoke about it was saying:
"Set an interface guide so the application can find the device and talk to it."
now my question is:
"how to write an aplication to control a PNP driver"
the main in "test.c":
int __cdecl
main(
_In_ ULONG argc,
_In_reads_(argc) PCHAR argv[]
)
{
HANDLE hDevice;
DWORD errNum = 0;
CHAR driverLocation[MAX_PATH];
BOOL ok;
LONG error;
// ULONG bytesReturned;
printf("main start. \n");
//
//open the device
printf("createFile. \n");
hDevice = CreateFileA(DRIVER_NAME,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hDevice == INVALID_HANDLE_VALUE){...}
printf("press enter \n");
int c = getchar();
printf("reception d'un charactere . \n");
if (c) {
printf("ioctl go \n");
DoIoctls(hDevice);
printf("ioctl end \n");
//
// Close the handle to the device before unloading the driver.
//
CloseHandle(hDevice);
//
// Unload the driver. Ignore any errors.
//
ManageDriver(DRIVER_NAME, driverLocation, DRIVER_FUNC_REMOVE);
}
c = getchar();
return;
}
here is the main of "test.c" which is at the base for nonpnp but that I modified that said I do not know how to embed the use of the GUID in my application (I imagine that it is because of that that it does not work).
the function DoIoctl :
VOID
DoIoctls(
HANDLE hDevice
)
{
char OutputBuffer[100];
char InputBuffer[200];
BOOL bRc;
ULONG bytesReturned;
//
// Printing Input & Output buffer pointers and size
//
printf("\nInputBuffer Pointer = %p, BufLength = %Id\n", InputBuffer,sizeof(InputBuffer));
printf("OutputBuffer Pointer = %p BufLength = %Id\n", OutputBuffer,sizeof(OutputBuffer));
//
// Performing METHOD_IN_DIRECT
//
printf("\nCalling DeviceIoControl METHOD_IN_DIRECT\n");
if (FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer),"this String is from User Application; using METHOD_IN_DIRECT")))
{
return;
}
if (FAILED(StringCchCopy(OutputBuffer, sizeof(OutputBuffer),"This String is from User Application in OutBuffer; using METHOD_IN_DIRECT")))
{
return;
}
bRc = DeviceIoControl(hDevice,
(DWORD)Spw_PCIe_IOCTL_IN_BUFFERED,
InputBuffer,
(DWORD)strlen(InputBuffer) + 1,
OutputBuffer,
sizeof(OutputBuffer),
&bytesReturned,
NULL
);
if (!bRc)
{
printf("Error in DeviceIoControl : %d \n", GetLastError());
return;
}
printf(" Number of bytes transfered from OutBuffer: %d\n",bytesReturned);
//
// Performing METHOD_OUT_DIRECT
//
printf("\nCalling DeviceIoControl METHOD_OUT_DIRECT\n");
if (FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer), "this String is from User Application; using METHOD_OUT_DIRECT"))) {
return;
}
memset(OutputBuffer, 0, sizeof(OutputBuffer));
bRc = DeviceIoControl(hDevice,
(DWORD)Spw_PCIe_IOCTL_OUT_BUFFERED,
InputBuffer,
(DWORD)strlen(InputBuffer) + 1,
OutputBuffer,
sizeof(OutputBuffer),
&bytesReturned,
NULL
);
if (!bRc)
{
printf("Error in DeviceIoControl : : %d", GetLastError());
return;
}
printf(" OutBuffer (%d): %s\n", bytesReturned, OutputBuffer);
return;
}
function ManageDriver :
BOOLEAN
ManageDriver( // <- ManageDriver
IN LPCTSTR DriverName,
IN LPCTSTR ServiceName,
IN USHORT Function
)
{
SC_HANDLE schSCManager;
BOOLEAN rCode = TRUE;
schSCManager = OpenSCManager(NULL, // local machine
NULL, // local database
SC_MANAGER_ALL_ACCESS // access required
)
// Do the requested function.
switch (Function) {;
case DRIVER_FUNC_REMOVE: // REMOVE
printf("remove case. \n");
// Stop the driver.
StopDriver(schSCManager,DriverName);
// Remove the driver service.
RemoveDriver(schSCManager,DriverName);
// Ignore all errors.
rCode = TRUE;
break;
default:
printf("Unknown ManageDriver() function. \n");
rCode = FALSE;
break;
}
// Close handle to service control manager.
if (schSCManager) {
CloseServiceHandle(schSCManager);
}
return rCode;
} // ManageDriver fin
function remove :
BOOLEAN
RemoveDriver( // <- RemoveDriver
_In_ SC_HANDLE SchSCManager,
_In_ LPCTSTR DriverName
)
{
SC_HANDLE schService;
BOOLEAN rCode;
// Open the handle to the existing service.
schService = OpenService(SchSCManager,DriverName,SERVICE_ALL_ACCESS);
// Mark the service for deletion from the service control manager database.
DeleteService(schService)
if (schService) {
CloseServiceHandle(schService);
}
return rCode;
} // RemoveDriver fin
function StartDriver :
BOOLEAN
StartDriver(
_In_ SC_HANDLE SchSCManager,
_In_ LPCTSTR DriverName
)
{
SC_HANDLE schService;
DWORD err;
// Open the handle to the existing service.
schService = OpenService(SchSCManager, DriverName,SERVICE_ALL_ACCESS );
// Start the execution of the service (i.e. start the driver).
StartService(schService, // service identifier
0, // number of arguments
NULL // pointer to arguments
)
// Close the service object.
if (schService) {
CloseServiceHandle(schService);
}
return TRUE;
} // StartDriver fin
function StopDriver :
BOOLEAN
StopDriver(
_In_ SC_HANDLE SchSCManager,
_In_ LPCTSTR DriverName
)
{
BOOLEAN rCode = TRUE;
SC_HANDLE schService;
SERVICE_STATUS serviceStatus;
//
// Open the handle to the existing service.
//
schService = OpenService(SchSCManager,
DriverName,
SERVICE_ALL_ACCESS
);
//
// Request that the service stop.
//
ControlService(schService,
SERVICE_CONTROL_STOP,
&serviceStatus
)
//
// Close the service object.
//
if (schService) {
CloseServiceHandle(schService);
}
return rCode;
} // StopDriver fin
I deleted everything that is debugger otherwise there is sure that it would not be clear
if you had any indication maybe I'm wrong about the nature of applications maybe the solution is very dumb but if you know anything about writing application for pnp driver I'm a taker
to shorten it :
i would need an application skeleton, but not just any, i need one that works for a pnp driver.
(it doesn't matter which driver as long as it's a pnp)
this is to be able to compare with my application and see what is missing from my aplication to support plug and play
cordially thank you all
You need to obtain the device path using the SetupDi functions as shown in this answer.
First, the documentation for IcmpSendEcho2() contradicts itself:
It says:
The IcmpSendEcho2 function is called synchronously if the ApcRoutine or Event parameters are NULL
Then it says:
The IcmpSendEcho2 function is called asynchronously when either the ApcRoutine or Event parameters are specified
I presume the first one should be "if the ApcRoutine AND Event paramters are NULL"?
Also, it says under the return value:
When called asynchronously, the IcmpSendEcho2 function returns ERROR_IO_PENDING to indicate the operation is in progress
But I don't see that, I see it return 0 and GetLastError() returns ERROR_IO_PENDING. So, can both cases exist, or is the documentation completely wrong?
Now on to the next issue. I wanted to use IcmpSendEcho2() asynchronously using the ACP callback without events. This way, I didn't have to worry about resources should the number of hosts to process be extremely large. However, it doesn't work because no callback occurs. I found this in the documentation under the AcpRoutine parameter:
The routine that is called when the calling thread is in an alertable thread and an ICMPv4 reply arrives.
So I believe my problem is the main thread is not in an alterable state. Since I don't have an event to wait on, and I don't want to wait beyond the time it takes to complete everything, how do I put the main thread in an alterable state without having to guess using something like SleepEx()? Also, if I did use something like SleepEx(10,TRUE), would all the callbacks occur, or do you have to sit in a loop?
My callback context structure includes a shared global OutstandingCount type variable so I'd know when all requests were completed.
Also the ReplyBuffer is in the context structure. Another little nugget hidden in the documentation regarding the ReplyBuffer when using it asynchronously is:
The application must parse the data pointed to by ReplyBuffer parameter using the IcmpParseReplies function
So, the main question here: How are you supposed to properly use the IcmpSendEcho2() function with a AcpRoutine and no Event in a main thread?
-- Update --
Not sure if I should ask an entirely new question but now a problem where it doesn't call the ApcRoutine for every IcmpSendEcho2Ex() sent. The following code works for my normal network adapters (which are 255.255.255.0) but hangs for a 255.255.0.0 network because the outstandingcount never gets to zero.
The adapter it hangs on is:
VirtualBox Host-Only Ethernet Adapter
DHCP Enable: Yes
Autoconfiguration Enabled: Yes
Autoconfiguration IPv4Address: 169.254.21.120
Subnet Mask: 255.255.0.0
Also wonder how long it would take on networks like 10. with a subnet of 255.0.0.0.
Here's the code that starts with the IPV4Scan() built as x64 on Win10 x64:
#define PIO_APC_ROUTINE_DEFINED
#include <winternl.h>
#include <iphlpapi.h>
#include <IcmpAPI.h>
//--------------
// types
//--------------
typedef DWORD (WINAPI *LPFN_IcmpSendEcho2)(HANDLE, HANDLE , PIO_APC_ROUTINE, PVOID, IPAddr, LPVOID, WORD, PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD);
typedef DWORD (WINAPI *LPFN_IcmpSendEcho2Ex)(HANDLE, HANDLE , PIO_APC_ROUTINE, PVOID, IPAddr, IPAddr, LPVOID, WORD, PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD);
typedef HANDLE (WINAPI *LPFN_IcmpCreateFile)();
typedef BOOL (WINAPI *LPFN_IcmpCloseHandle)(HANDLE);
typedef DWORD (WINAPI *LPFN_IcmpParseReplies)(LPVOID, DWORD);
BYTE PingSignature[]={ 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8' };
typedef struct _sPingContext
{
ULONG *OutstandingCount; // shared number of pings outstanding
CMutex *Mutex; // mutex for ipsfound
CNumericBuffer<uint32_t> *IPsFound; // list of ips found (MSBF format)
LPFN_IcmpParseReplies fnIcmpParseReplies; // function pointer
BYTE ReplyBuffer[sizeof(ICMP_ECHO_REPLY) + sizeof(PingSignature) + sizeof(IO_STATUS_BLOCK) + 8]; // reply buffer (see API docs)
_sPingContext(ULONG *outstandingcount, CMutex *mutex, CNumericBuffer<uint32_t> *ipsfound, LPFN_IcmpParseReplies fnicmpparsereplies)
{
OutstandingCount=outstandingcount;
Mutex=mutex;
IPsFound=ipsfound;
fnIcmpParseReplies=fnicmpparsereplies;
memset(ReplyBuffer, 0, sizeof(ReplyBuffer));
};
} sPingContext, *psPingContext;
//-------------------------------------------------------------------------
// Purpose: Callback for async ping
//
// Input: ioresult - [i] io result of async operation
// pingccontext - [i] context passed on ping
// replysize - [i] reply size of ReplyBuffer
//
// Output: na
//
// Notes:
//
VOID PingCallbackCommon(DWORD ioresult, sPingContext* pingcontext, DWORD replysize)
{
// parse response buffer
if (pingcontext) {
if (ioresult==IP_SUCCESS) {
if (pingcontext->fnIcmpParseReplies(pingcontext->ReplyBuffer, replysize)) {
// point to reply buffer
PICMP_ECHO_REPLY pechoreply=reinterpret_cast<PICMP_ECHO_REPLY>(pingcontext->ReplyBuffer);
if (pechoreply->Status==IP_SUCCESS) {
// check response
if (pechoreply->DataSize==sizeof(PingSignature)) {
if (memcmp(pechoreply->Data, PingSignature, pechoreply->DataSize)==0) {
// successful ping
pingcontext->Mutex->Lock();
pingcontext->IPsFound->AddItem(pechoreply->Address);
pingcontext->Mutex->Unlock();
}
}
}
}
}
// reduce count
InterlockedDecrement(pingcontext->OutstandingCount);
// clean up
delete pingcontext;
}
}
//-------------------------------------------------------------------------
// Purpose: Callback for async ping
//
// Input: apccontext - [i] context passed on ping
//
// Output: na
//
// Notes:
//
VOID PingCallbackOld(PVOID apcontext)
{
sPingContext *pingcontext=reinterpret_cast<sPingContext*>(apcontext);
PingCallbackCommon(IP_SUCCESS, pingcontext, sizeof(pingcontext->ReplyBuffer));
}
//-------------------------------------------------------------------------
// Purpose: Callback for async ping
//
// Input: apccontext - [i] context passed on ping
// iostatusblock - [i] status of request
//
// Output: na
//
// Notes:
//
VOID PingCallback(PVOID apcontext, PIO_STATUS_BLOCK iostatusblock, ULONG reserved)
{
PingCallbackCommon(iostatusblock->Status, reinterpret_cast<sPingContext*>(apcontext), iostatusblock->Information);
}
//-------------------------------------------------------------------------
// Purpose: build list of network hosts using IPv4 Ping
//
// Input: subnet - [i] subnet being scanned (LSB format)
// hoststart - [i] host starting number for scan
// hostend - [i] host ending number for scan
// ips - [io] numeric buffer to update with found addresses
//
// Output: na
//
// Notes:
//
void IPV4Ping(IPAddr sourceip, uint32_t subnet, uint32_t hoststart, uint32_t hostend, CNumericBuffer<uint32_t> &ips)
{
// skip 127. network
if ((sourceip & 0xFF)==127)
return;
bool oldlib=false;
LPFN_IcmpSendEcho2Ex fnIcmpSendEcho2Ex=NULL;
LPFN_IcmpCreateFile fnIcmpCreateFile=NULL;
LPFN_IcmpCloseHandle fnIcmpCloseHandle=NULL;
LPFN_IcmpParseReplies fnIcmpParseReplies=NULL;
// first thing is first - check which set of functions to use
HMODULE hlib=LoadLibrary(_T("iphlpapi.dll"));
if (hlib) {
// load functions
fnIcmpCreateFile=(LPFN_IcmpCreateFile) GetProcAddress(hlib, "IcmpCreateFile");
fnIcmpSendEcho2Ex=(LPFN_IcmpSendEcho2Ex) GetProcAddress(hlib, "IcmpSendEcho2Ex");
fnIcmpCloseHandle=(LPFN_IcmpCloseHandle) GetProcAddress(hlib, "IcmpCloseHandle");
fnIcmpParseReplies=(LPFN_IcmpParseReplies) GetProcAddress(hlib, "IcmpParseReplies");
}
// check if have everything
if (!hlib || fnIcmpCreateFile==NULL || fnIcmpSendEcho2Ex==NULL || fnIcmpCloseHandle==NULL || fnIcmpParseReplies==NULL) {
// no, try old version
oldlib=true;
// clean up
if (hlib) {
FreeLibrary(hlib);
}
// load old lib
hlib=LoadLibrary(_T("icmp.dll"));
// check if loaded
if (hlib) {
// load functions
fnIcmpCreateFile=(LPFN_IcmpCreateFile) GetProcAddress(hlib, "IcmpCreateFile");
fnIcmpSendEcho2Ex=(LPFN_IcmpSendEcho2Ex) GetProcAddress(hlib, "IcmpSendEcho2Ex");
fnIcmpCloseHandle=(LPFN_IcmpCloseHandle) GetProcAddress(hlib, "IcmpCloseHandle");
fnIcmpParseReplies=(LPFN_IcmpParseReplies) GetProcAddress(hlib, "IcmpParseReplies");
}
}
// check if have everything
if (hlib) {
if (fnIcmpCreateFile!=NULL && fnIcmpSendEcho2Ex!=NULL && fnIcmpCloseHandle!=NULL && fnIcmpParseReplies!=NULL) {
// open icmp
HANDLE hicmp=fnIcmpCreateFile();
if (hicmp!=INVALID_HANDLE_VALUE) {
// variables for callback handling
ULONG outstandingcount=0;
CMutex mutex;
// process pings
for (uint32_t host=hoststart; host<=hostend; host++) {
// build full ip
IPAddr ip=subnet | host;
ip=GETMSBFDWORD(&ip);
// create context
sPingContext *pcontext;
if ((pcontext=new sPingContext(&outstandingcount, &mutex, &ips, fnIcmpParseReplies))!=NULL) {
// count request
InterlockedIncrement(&outstandingcount);
// now issue ping
DWORD result=fnIcmpSendEcho2Ex(hicmp,
NULL,
oldlib ? (PIO_APC_ROUTINE) PingCallbackOld : PingCallback,
pcontext,
sourceip,
ip,
PingSignature,
sizeof(PingSignature),
NULL,
pcontext->ReplyBuffer,
sizeof(pcontext->ReplyBuffer),
50);
// check if failed
if (result==0) {
// check if because pending
if (GetLastError()!=ERROR_IO_PENDING) {
// no - use callback to clean up
CDebugPrint::DebugPrint(_T("IcmpSendEcho Error %u\n"), GetLastError());
PingCallbackOld(pcontext);
}
else {
// fire off pending APC callbacks ready
SleepEx(0, TRUE);
}
}
else {
// completed sync - use callback to clean up
PingCallbackOld(pcontext);
}
}
}
// wait for completion
while (outstandingcount) {
// handle callbacks
SleepEx(10, TRUE);
}
// clean up
fnIcmpCloseHandle(hicmp);
}
}
// clean up
FreeLibrary(hlib);
}
}
//-------------------------------------------------------------------------
// Purpose: build list of network hosts by way of IP scan for V4
//
// Input: ipadapteraddress - [i] adapter ip address to build for
//
// Output: na
//
// Notes: ip addresses are MSBF
//
void IPV4Scan(IP_ADAPTER_UNICAST_ADDRESS *ipadapteraddress)
{
// build the subnet mask to use
if (ipadapteraddress->OnLinkPrefixLength<=32 && ipadapteraddress->OnLinkPrefixLength!=0) {
in_addr ia=reinterpret_cast<sockaddr_in*>(ipadapteraddress->Address.lpSockaddr)->sin_addr;
// valid mask length - build mask
uint32_t rangemask=((1U<<(32-ipadapteraddress->OnLinkPrefixLength))-1);
uint32_t mask=~rangemask;
uint32_t subnet=GETMSBFDWORD(&ia.s_addr) & mask;
CDebugPrint::DebugPrint(_T("Subnet %u.%u.%u.%u/%u\n"), (subnet>>24) & 0xFF, (subnet>>16) & 0xFF, (subnet>>8) & 0xFF, (subnet>>0) & 0xFF, ipadapteraddress->OnLinkPrefixLength);
CDebugPrint::DebugPrint(_T("Scanning %u hosts\n"), (UINT32_MAX & rangemask)-1);
CNumericBuffer<uint32_t> ipsfound;
IPV4Ping(ia.s_addr, subnet, 1, (UINT32_MAX & rangemask)-1, ipsfound);
for (UINT i=0; i<(UINT)ipsfound.GetCount(); i++) {
uint32_t ip=ipsfound[i];
CDebugPrint::DebugPrint(_T("Ping found %u.%u.%u.%u\n"), ip & 0xFF, (ip>>8) & 0xFF, (ip>>16) & 0xFF, (ip>>24) & 0xFF);
}
}
else CDebugPrint::DebugPrint(_T("Invalid subnet length %u\n"), ipadapteraddress->OnLinkPrefixLength);
}
I presume the first one should be "if the ApcRoutine AND Event
paramters are NULL"?
yes, you correct.
But I don't see that, I see it return 0 and GetLastError() returns
ERROR_IO_PENDING. So, can both cases exist, or is the documentation
completely wrong?
documentation completely wrong. by fact IcmpSendEcho2[Ex] return BOOL and error code via SetLastError ( more exactly by RtlNtStatusToDosError)
so on asynchronous call it return FALSE (0) and GetLastError() will be ERROR_IO_PENDING if all ok - this mean apc callback will be called, or another error if fail - apc callback will be not called (better call it by self in this case, for common error handling)
how do I put the main thread in an alterable state
this already depend from what your thread doing. in some case possible write event loop with MsgWaitForMultipleObjectsEx function - at once wait on windows events and be alertable. also possible wait on some objects too. if you can not rewrite self message loop with MsgWaitForMultipleObjectsEx - you can do call from worked thread, or periodically call SleepEx(0, TRUE) or undocumented NtTestAlert. without know what your main thread doing - hard say exactly what is better.
demo code can look like:
#include <iphlpapi.h>
#include <IPExport.h>
#include <icmpapi.h>
class EchoRequestContext
{
HANDLE _hFile = 0;
PVOID _ReplyBuffer = 0;
LONG _dwRefCount = 1;
ULONG _dwThreadId = GetCurrentThreadId();
static void WINAPI sOnApc(PVOID This, PIO_STATUS_BLOCK piosb, ULONG )
{
reinterpret_cast<EchoRequestContext*>(This)->OnApc(
RtlNtStatusToDosError(piosb->Status),
(ULONG)piosb->Information);
}
void OnApc(ULONG dwError, ULONG ReplySize)
{
OnReply(dwError, (PICMP_ECHO_REPLY)_ReplyBuffer, ReplySize);
if (_ReplyBuffer) delete [] _ReplyBuffer;
Release();
}
void OnReply(ULONG dwError, PICMP_ECHO_REPLY ReplyBuffer, ULONG ReplySize)
{
if (dwError)
{
DbgPrint("dwError=%u\n", dwError);
return ;
}
if (IcmpParseReplies(ReplyBuffer, ReplySize))
{
__nop();
}
}
~EchoRequestContext()
{
if (_hFile) IcmpCloseHandle(_hFile);
PostThreadMessageW(_dwThreadId, WM_QUIT, 0, 0);
}
public:
void AddRef()
{
InterlockedIncrementNoFence(&_dwRefCount);
}
void Release()
{
if (!InterlockedDecrement(&_dwRefCount))
{
delete this;
}
}
ULONG Create()
{
HANDLE hFile = IcmpCreateFile();
if (hFile == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
_hFile = hFile;
return NOERROR;
}
void SendEcho(
IPAddr DestinationAddress,
const void* RequestData,
WORD RequestSize,
ULONG ReplySize,
ULONG Timeout,
UCHAR Flags,
UCHAR Ttl)
{
if (PVOID ReplyBuffer = new UCHAR[ReplySize])
{
_ReplyBuffer = ReplyBuffer;
IP_OPTION_INFORMATION opt = { Ttl, 0, Flags };
AddRef();
ULONG dwError = IcmpSendEcho2Ex(_hFile, 0, sOnApc, this,
0, DestinationAddress,
const_cast<void*>(RequestData), RequestSize,
&opt, ReplyBuffer, ReplySize, Timeout) ? NOERROR : GetLastError();
switch (dwError)
{
case NOERROR:
case ERROR_IO_PENDING:
break;
default:
OnApc(dwError, 0 );
}
return ;
}
OnApc(ERROR_OUTOFMEMORY, 0);
}
};
#define IP(a, b, c, d) ((ULONG)(a + (b << 8) + (c << 16) + (d << 24)))
void EchoTest()
{
WSADATA wd;
if (NOERROR == WSAStartup(WINSOCK_VERSION, &wd))
{
if (EchoRequestContext* p = new EchoRequestContext)
{
if (p->Create() == NOERROR)
{
p->SendEcho(IP(8,8,8,8), "1234567890ABCDEF", 16, 0x100, 4000, IP_FLAG_DF, 255);
}
p->Release();
}
MSG msg;
__loop:
switch (MsgWaitForMultipleObjectsEx(0, 0, INFINITE,
QS_ALLINPUT, MWMO_ALERTABLE|MWMO_WAITALL))
{
default:
__debugbreak();
break;
case WAIT_FAILED:
break;
case WAIT_OBJECT_0:
while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
goto __exit;
}
}
case STATUS_USER_APC: // == WAIT_IO_COMPLETION
goto __loop;
}
__exit:
WSACleanup();
}
}
What I'm trying to do:
User-mode app sends Process ID to driver
Driver gets handle to specified Process ID
Drivers passes opened handle to user-mode app
I'm not sure if this code is even completely working. I'm quite new to drivers, so I haven't set up debugging yet and virtual machine hasn't finished downloading (slow connection problems).
Getting Process ID from user-mode app should be working fine and it should be getting stored in PROCESS_INFO struct as ProcessId. The opened handle is stored in the same struct as ProcessHandle to be sent back to the user-mode application. I'm not sure how to return data from kernel to user-mode tho, maybe someone could explain briefly.
Here's my code:
#include <ntifs.h>
#include <wdf.h>
DRIVER_INITIALIZE DriverEntry;
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\GetSysHandle"), SymbolicLink = RTL_CONSTANT_STRING(L"\\DosDevices\\GetSysHandle");
typedef struct _PROCESS_INFO
{
HANDLE ProcessId;
HANDLE ProcessHandle;
}PROCESS_INFO, *PPROCESS_INFO;
BOOLEAN GetSysHandle(PPROCESS_INFO ProcessInfo)
{
NTSTATUS status = STATUS_ACCESS_DENIED;
PEPROCESS eProcess = NULL;
status = PsLookupProcessByProcessId(ProcessInfo->ProcessId, &eProcess);
if ((!NT_SUCCESS(status)) || (!eProcess))
{
return FALSE;
}
status = ObOpenObjectByPointer(eProcess, 0, NULL, 0, 0, KernelMode, &ProcessInfo->ProcessHandle);
if ((!NT_SUCCESS(status)) || (!ProcessInfo->ProcessHandle))
{
ObDereferenceObject(eProcess);
return FALSE;
}
return TRUE;
}
void Unload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("# GetSysHandle driver unloaded.");
IoDeleteSymbolicLink(&SymbolicLink);
IoDeleteDevice(pDriverObject->DeviceObject);
}
NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP irp)
{
PIO_STACK_LOCATION io;
PPROCESS_INFO ProcessInfo;
NTSTATUS status;
io = IoGetCurrentIrpStackLocation(irp);
irp->IoStatus.Information = 0;
switch (io->MajorFunction)
{
case IRP_MJ_CREATE:
status = STATUS_SUCCESS;
break;
case IRP_MJ_CLOSE:
status = STATUS_SUCCESS;
break;
case IRP_MJ_READ:
status = STATUS_SUCCESS;
break;
case IRP_MJ_WRITE:
ProcessInfo = (PPROCESS_INFO)MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
if (!ProcessInfo)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
if (!GetSysHandle(ProcessInfo))
{
DbgPrint("# Failed to get process handle");
status = STATUS_UNSUCCESSFUL;
break;
}
status = STATUS_SUCCESS;
irp->IoStatus.Information = sizeof(PROCESS_INFO);
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
irp->IoStatus.Status = status;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
PDEVICE_OBJECT DeviceObject;
ULONG i;
DbgPrint("# GetSysHandle driver loaded");
IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject);
IoCreateSymbolicLink(&SymbolicLink, &DeviceName);
for (i = 0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)
{
DriverObject->MajorFunction[i] = DriverDispatch;
}
return STATUS_SUCCESS;
}
First and foremost (to avoid confusion): this code is for Windows and Windows Drivers.
The biggest issue I see with your driver code is that you aren't registering the IRP major functions inside of DriverEntry. You will need to set the MajorFunction parameters of the PDRIVER_OBJECT DriverObject to the dispatch functions. Without assigning these MajorFunctions, the driver will have no way of knowing what function to call when receiving a command.
To do this, break up the cases for the switch (io->MajorFunction) into different dispatch functions. For example, IRP_MJ_WRITE will be its own function, and you can declare it like so:
DRIVER_DISPATCH DispatchReadFunction;
In this case, we will want all read commands issued to the driver to run whatever code is inside the DispatchReadFunction function. So the definition will look a little like this:
NTSTATUS DispatchReadFunction(_In_ PDEVICE_OBJECT DriverObject, _In_ PIRP Irp)
{
NTSTATUS status = STATUS_SUCCESS;
//Do read code here
return status;
}
Once we have the DispatchReadFunction function written, you will need to assign it to the DriverObject->MajorFunction in the DriverEntry function like so:
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadFunction;
Finally, stub out and write the rest of the IRP_MJ_ functions that you need, making sure that you assign them to the MajorFunction memeber of DriverObject.
My DriverEntry function looks like this (I removed extra functionality):
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
status = STATUS_SUCCESS;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadFunc;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreateFunc;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchCloseFunc;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWriteFunc;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDevCtrlFunc;
return status;
}
A good starting point would be here. This link also includes a simple example (driver code and application code) that does what you are attempting to do.
Good Luck!
I am porting the famous packet capture software -- WinPcap from NDIS 5.0 to NDIS 6.x. I tried to translate every NDIS 5.0 function to its 6.0 version. In WinPcap sourcecode function NdisOpenAdapter is called by NPF_OpenAdapter in Openclos.c. I translated it to NdisOpenAdapterEx for NDIS 6.0. But I cannot find a way to set the 4th parameter BindContext.
The delcaration of NdisOpenAdapterEx can be found here:
http://msdn.microsoft.com/en-us/library/windows/hardware/ff563715(v=vs.85).aspx
Also MS said "A protocol driver must call NdisOpenAdapterEx from its ProtocolBindAdapterEx function. NDIS fails any attempt to call NdisOpenAdapterEx outside the context of ProtocolBindAdapterEx.". So it seems that NdisOpenAdapterEx cannot be called in NPF_OpenAdapter. it must be called in the NPF_BindAdapterEx function. I substituted the driver npf.sys with my own version, started Wireshark (a packet capture frontend), set breakpoints in NPF_BindAdapterEx and found NPF_BindAdapterEx was never called before NPF_OpenAdapter. So it is impposible for me to get the BindContext paramters before calling NdisOpenAdapterEx.
I just want to imgrate WinPcap to NDIS 6.0 with modifications as small as possible. And how to solve this problem?
Here is the code of Openclos.c
/*
* Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
* Copyright (c) 2005 - 2010 CACE Technologies, Davis (California)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Politecnico di Torino, CACE Technologies
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "stdafx.h"
#include <ntddk.h>
#include <ndis.h>
#include "debug.h"
#include "packet.h"
#include "..\..\Common\WpcapNames.h"
static
VOID NPF_ReleaseOpenInstanceResources(POPEN_INSTANCE pOpen);
static NDIS_MEDIUM MediumArray[] =
{
NdisMedium802_3,
// NdisMediumWan,
NdisMediumFddi, NdisMediumArcnet878_2, NdisMediumAtm, NdisMedium802_5
};
#define NUM_NDIS_MEDIA (sizeof MediumArray / sizeof MediumArray[0])
//Itoa. Replaces the buggy RtlIntegerToUnicodeString
// void PacketItoa(UINT n, PUCHAR buf)
// {
// int i;
// for(i=0;i<20;i+=2){
// buf[18-i]=(n%10)+48;
// buf[19-i]=0;
// n/=10;
// }
// }
/// Global start time. Used as an absolute reference for timestamp conversion.
struct time_conv G_Start_Time =
{
0, {0, 0},
};
ULONG g_NumOpenedInstances = 0;
BOOLEAN NPF_StartUsingBinding(IN POPEN_INSTANCE pOpen)
{
ASSERT(pOpen != NULL);
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
NdisAcquireSpinLock(&pOpen->AdapterHandleLock);
if (pOpen->AdapterBindingStatus != ADAPTER_BOUND)
{
NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
return FALSE;
}
pOpen->AdapterHandleUsageCounter++;
NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
return TRUE;
}
VOID NPF_StopUsingBinding(IN POPEN_INSTANCE pOpen)
{
ASSERT(pOpen != NULL);
//
// There is no risk in calling this function from abobe passive level
// (i.e. DISPATCH, in this driver) as we acquire a spinlock and decrement a
// counter.
//
// ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
NdisAcquireSpinLock(&pOpen->AdapterHandleLock);
ASSERT(pOpen->AdapterHandleUsageCounter > 0);
ASSERT(pOpen->AdapterBindingStatus == ADAPTER_BOUND);
pOpen->AdapterHandleUsageCounter--;
NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
}
VOID NPF_CloseBinding(IN POPEN_INSTANCE pOpen)
{
NDIS_EVENT Event;
NDIS_STATUS Status;
ASSERT(pOpen != NULL);
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
NdisInitializeEvent(&Event);
NdisResetEvent(&Event);
NdisAcquireSpinLock(&pOpen->AdapterHandleLock);
while (pOpen->AdapterHandleUsageCounter > 0)
{
NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
NdisWaitEvent(&Event, 1);
NdisAcquireSpinLock(&pOpen->AdapterHandleLock);
}
//
// now the UsageCounter is 0
//
while (pOpen->AdapterBindingStatus == ADAPTER_UNBINDING)
{
NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
NdisWaitEvent(&Event, 1);
NdisAcquireSpinLock(&pOpen->AdapterHandleLock);
}
//
// now the binding status is either bound or unbound
//
if (pOpen->AdapterBindingStatus == ADAPTER_UNBOUND)
{
NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
return;
}
ASSERT(pOpen->AdapterBindingStatus == ADAPTER_BOUND);
pOpen->AdapterBindingStatus = ADAPTER_UNBINDING;
NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
//
// do the release procedure
//
NdisResetEvent(&pOpen->NdisOpenCloseCompleteEvent);
// Close the adapter
Status = NdisCloseAdapterEx(pOpen->AdapterHandle);
if (Status == NDIS_STATUS_PENDING)
{
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Pending NdisCloseAdapter");
NdisWaitEvent(&pOpen->NdisOpenCloseCompleteEvent, 0);
}
else
{
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Not Pending NdisCloseAdapter");
}
NdisAcquireSpinLock(&pOpen->AdapterHandleLock);
pOpen->AdapterBindingStatus = ADAPTER_UNBOUND;
NdisReleaseSpinLock(&pOpen->AdapterHandleLock);
}
//-------------------------------------------------------------------
NTSTATUS NPF_OpenAdapter(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
NDIS_STATUS Status;
NDIS_STATUS ErrorStatus;
UINT i;
PUCHAR tpointer;
PLIST_ENTRY PacketListEntry;
NTSTATUS returnStatus;
NET_BUFFER_LIST_POOL_PARAMETERS PoolParameters;
NDIS_OPEN_PARAMETERS OpenParameters;
NET_FRAME_TYPE FrameTypeArray[2] =
{
NDIS_ETH_TYPE_802_1X, NDIS_ETH_TYPE_802_1Q
};
//
// Old registry based WinPcap names
//
// WCHAR EventPrefix[MAX_WINPCAP_KEY_CHARS];
// UINT RegStrLen;
TRACE_ENTER();
DeviceExtension = DeviceObject->DeviceExtension;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
// allocate some memory for the open structure
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;
}
RtlZeroMemory(Open, sizeof(OPEN_INSTANCE));
//
// Old registry based WinPcap names
//
// //
// // Get the Event names base from the registry
// //
// RegStrLen = sizeof(EventPrefix)/sizeof(EventPrefix[0]);
//
// NPF_QueryWinpcapRegistryString(NPF_EVENTS_NAMES_REG_KEY_WC,
// EventPrefix,
// RegStrLen,
// NPF_EVENTS_NAMES_WIDECHAR);
//
Open->DeviceExtension = DeviceExtension;
NdisZeroMemory(&PoolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS));
PoolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
PoolParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
PoolParameters.Header.Size = sizeof(PoolParameters);
PoolParameters.ProtocolId = NDIS_PROTOCOL_ID_TCP_IP;
PoolParameters.ContextSize = 0;
PoolParameters.fAllocateNetBuffer = TRUE;
PoolParameters.PoolTag = NPCAP_ALLOC_TAG;
Open->PacketPool = NdisAllocateNetBufferListPool(NULL, &PoolParameters);
if (Open->PacketPool == NULL)
{
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Failed to allocate packet pool");
ExFreePool(Open);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
// // Allocate a packet pool for our xmit and receive packets
// NdisAllocatePacketPool(
// &Status,
// &Open->PacketPool,
// TRANSMIT_PACKETS,
// sizeof(PACKET_RESERVED));
//
// if (Status != NDIS_STATUS_SUCCESS) {
//
// TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Failed to allocate packet pool");
//
// ExFreePool(Open);
// Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
// IoCompleteRequest(Irp, IO_NO_INCREMENT);
// return STATUS_INSUFFICIENT_RESOURCES;
// }
NdisInitializeEvent(&Open->WriteEvent);
NdisInitializeEvent(&Open->NdisRequestEvent);
NdisInitializeEvent(&Open->NdisWriteCompleteEvent);
NdisInitializeEvent(&Open->DumpEvent);
NdisAllocateSpinLock(&Open->MachineLock);
NdisAllocateSpinLock(&Open->WriteLock);
Open->WriteInProgress = FALSE;
for (i = 0; i < g_NCpu; i++)
{
NdisAllocateSpinLock(&Open->CpuData[i].BufferLock);
}
NdisInitializeEvent(&Open->NdisOpenCloseCompleteEvent);
// list to hold irp's want to reset the adapter
InitializeListHead(&Open->ResetIrpList);
// Initialize the request list
KeInitializeSpinLock(&Open->RequestSpinLock);
InitializeListHead(&Open->RequestList);
//
// Initialize the open instance
//
//Open->BindContext = NULL;
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->DumpFileName.Buffer = NULL;
Open->DumpFileHandle = NULL;
#ifdef HAVE_BUGGY_TME_SUPPORT
Open->tme.active = TME_NONE_ACTIVE;
#endif // HAVE_BUGGY_TME_SUPPORT
Open->DumpLimitReached = FALSE;
Open->MaxFrameSize = 0;
Open->WriterSN = 0;
Open->ReaderSN = 0;
Open->Size = 0;
Open->SkipSentPackets = FALSE;
Open->ReadEvent = NULL;
//
// we need to keep a counter of the pending IRPs
// so that when the IRP_MJ_CLEANUP dispatcher gets called,
// we can wait for those IRPs to be completed
//
Open->NumPendingIrps = 0;
Open->ClosePending = FALSE;
NdisAllocateSpinLock(&Open->OpenInUseLock);
//
//allocate the spinlock for the statistic counters
//
NdisAllocateSpinLock(&Open->CountersLock);
//
// link up the request stored in our open block
//
for (i = 0 ; i < MAX_REQUESTS ; i++)
{
NdisInitializeEvent(&Open->Requests[i].InternalRequestCompletedEvent);
ExInterlockedInsertTailList(&Open->RequestList, &Open->Requests[i].ListElement, &Open->RequestSpinLock);
}
NdisResetEvent(&Open->NdisOpenCloseCompleteEvent);
//
// set the proper binding flags before trying to open the MAC
//
Open->AdapterBindingStatus = ADAPTER_BOUND;
Open->AdapterHandleUsageCounter = 0;
NdisAllocateSpinLock(&Open->AdapterHandleLock);
//
// Try to open the MAC
//
TRACE_MESSAGE2(PACKET_DEBUG_LOUD, "Opening the device %ws, BindingContext=%p", DeviceExtension->AdapterName.Buffer, Open);
returnStatus = STATUS_SUCCESS;
NdisZeroMemory(&OpenParameters, sizeof(NDIS_OPEN_PARAMETERS));
OpenParameters.Header.Type = NDIS_OBJECT_TYPE_OPEN_PARAMETERS;
OpenParameters.Header.Revision = NDIS_OPEN_PARAMETERS_REVISION_1;
OpenParameters.Header.Size = sizeof(NDIS_OPEN_PARAMETERS);
OpenParameters.AdapterName = &DeviceExtension->AdapterName;
OpenParameters.MediumArray = MediumArray;
OpenParameters.MediumArraySize = sizeof(MediumArray) / sizeof(NDIS_MEDIUM);
OpenParameters.SelectedMediumIndex = &Open->Medium;
OpenParameters.FrameTypeArray = NULL;
OpenParameters.FrameTypeArraySize = 0;
//OpenParameters.FrameTypeArray = &FrameTypeArray[0];
//OpenParameters.FrameTypeArraySize = sizeof(FrameTypeArray) / sizeof(NET_FRAME_TYPE);
NDIS_DECLARE_PROTOCOL_OPEN_CONTEXT(OPEN_INSTANCE);
Status = NdisOpenAdapterEx(g_NdisProtocolHandle, (NDIS_HANDLE)Open, &OpenParameters, NULL, &Open->AdapterHandle);
// NdisOpenAdapter(
// &Status,
// &ErrorStatus,
// &Open->AdapterHandle,
// &Open->Medium,
// MediumArray,
// NUM_NDIS_MEDIA,
// g_NdisProtocolHandle,
// Open,
// &DeviceExtension->AdapterName,
// 0,
// NULL);
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened the device, Status=%x", Status);
if (Status == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&Open->NdisOpenCloseCompleteEvent, 0);
if (!NT_SUCCESS(Open->OpenCloseStatus))
{
returnStatus = Open->OpenCloseStatus;
}
else
{
returnStatus = STATUS_SUCCESS;
}
}
else
{
//
// request not pending, we know the result, and OpenComplete has not been called.
//
if (Status == NDIS_STATUS_SUCCESS)
{
returnStatus = STATUS_SUCCESS;
}
else
{
//
// this is not completely correct, as we are converting an NDIS_STATUS to a NTSTATUS
//
returnStatus = Status;
}
}
if (returnStatus == STATUS_SUCCESS)
{
ULONG localNumOpenedInstances;
//
// complete the open
//
localNumOpenedInstances = InterlockedIncrement(&g_NumOpenedInstances);
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenedInstances);
// Get the absolute value of the system boot time.
// This is used for timestamp conversion.
TIME_SYNCHRONIZE(&G_Start_Time);
returnStatus = NPF_GetDeviceMTU(Open, Irp, &Open->MaxFrameSize);
if (!NT_SUCCESS(returnStatus))
{
//
// Close the binding
//
NPF_CloseBinding(Open);
}
}
if (!NT_SUCCESS(returnStatus))
{
NPF_ReleaseOpenInstanceResources(Open);
//
// Free the open instance itself
//
ExFreePool(Open);
}
else
{
// Save or open here
IrpSp->FileObject->FsContext = Open;
}
Irp->IoStatus.Status = returnStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return returnStatus;
}
BOOLEAN NPF_StartUsingOpenInstance(IN POPEN_INSTANCE pOpen)
{
BOOLEAN returnStatus;
NdisAcquireSpinLock(&pOpen->OpenInUseLock);
if (pOpen->ClosePending)
{
returnStatus = FALSE;
}
else
{
returnStatus = TRUE;
pOpen->NumPendingIrps ++;
}
NdisReleaseSpinLock(&pOpen->OpenInUseLock);
return returnStatus;
}
VOID NPF_StopUsingOpenInstance(IN POPEN_INSTANCE pOpen)
{
NdisAcquireSpinLock(&pOpen->OpenInUseLock);
ASSERT(pOpen->NumPendingIrps > 0);
pOpen->NumPendingIrps --;
NdisReleaseSpinLock(&pOpen->OpenInUseLock);
}
VOID NPF_CloseOpenInstance(IN POPEN_INSTANCE pOpen)
{
ULONG i = 0;
NDIS_EVENT Event;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
NdisInitializeEvent(&Event);
NdisResetEvent(&Event);
NdisAcquireSpinLock(&pOpen->OpenInUseLock);
pOpen->ClosePending = TRUE;
while (pOpen->NumPendingIrps > 0)
{
NdisReleaseSpinLock(&pOpen->OpenInUseLock);
NdisWaitEvent(&Event, 1);
NdisAcquireSpinLock(&pOpen->OpenInUseLock);
}
NdisReleaseSpinLock(&pOpen->OpenInUseLock);
}
VOID NPF_ReleaseOpenInstanceResources(POPEN_INSTANCE pOpen)
{
PKEVENT pEvent;
UINT i;
TRACE_ENTER();
ASSERT(pOpen != NULL);
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open= %p", pOpen);
//NdisFreePacketPool(pOpen->PacketPool);
NdisFreeNetBufferListPool(pOpen->PacketPool);
//
// Free the filter if it's present
//
if (pOpen->bpfprogram != NULL)
ExFreePool(pOpen->bpfprogram);
//
// Jitted filters are supported on x86 (32bit) only
//
#ifdef _X86_
// Free the jitted filter if it's present
if (pOpen->Filter != NULL)
BPF_Destroy_JIT_Filter(pOpen->Filter);
#endif //_X86_
//
// Dereference the read event.
//
if (pOpen->ReadEvent != NULL)
ObDereferenceObject(pOpen->ReadEvent);
//
// free the buffer
// NOTE: the buffer is fragmented among the various CPUs, but the base pointer of the
// allocated chunk of memory is stored in the first slot (pOpen->CpuData[0])
//
if (pOpen->Size > 0)
ExFreePool(pOpen->CpuData[0].Buffer);
//
// free the per CPU spinlocks
//
for (i = 0; i < g_NCpu; i++)
{
NdisFreeSpinLock(&pOpen->CpuData[i].BufferLock);
}
//
// Free the string with the name of the dump file
//
if (pOpen->DumpFileName.Buffer != NULL)
ExFreePool(pOpen->DumpFileName.Buffer);
TRACE_EXIT();
}
//-------------------------------------------------------------------
VOID NPF_OpenAdapterCompleteEx(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status)
{
POPEN_INSTANCE Open;
PLIST_ENTRY RequestListEntry;
PINTERNAL_REQUEST MaxSizeReq;
NDIS_STATUS ReqStatus;
TRACE_ENTER();
Open = (POPEN_INSTANCE)ProtocolBindingContext;
ASSERT(Open != NULL);
if (Status != NDIS_STATUS_SUCCESS)
{
//
// this is not completely correct, as we are converting an NDIS_STATUS to a NTSTATUS
//
Open->OpenCloseStatus = Status;
}
else
{
Open->OpenCloseStatus = STATUS_SUCCESS;
}
//
// wake up the caller of NdisOpen, that is NPF_Open
//
NdisSetEvent(&Open->NdisOpenCloseCompleteEvent);
TRACE_EXIT();
}
NTSTATUS NPF_GetDeviceMTU(IN POPEN_INSTANCE pOpen, IN PIRP pIrp, OUT PUINT pMtu)
{
PLIST_ENTRY RequestListEntry;
PINTERNAL_REQUEST MaxSizeReq;
NDIS_STATUS ReqStatus;
TRACE_ENTER();
ASSERT(pOpen != NULL);
ASSERT(pIrp != NULL);
ASSERT(pMtu != NULL);
// Extract a request from the list of free ones
RequestListEntry = ExInterlockedRemoveHeadList(&pOpen->RequestList, &pOpen->RequestSpinLock);
if (RequestListEntry == NULL)
{
//
// THIS IS WRONG
//
//
// Assume Ethernet
//
*pMtu = 1514;
TRACE_EXIT();
return STATUS_SUCCESS;
}
MaxSizeReq = CONTAINING_RECORD(RequestListEntry, INTERNAL_REQUEST, ListElement);
MaxSizeReq->Request.RequestType = NdisRequestQueryInformation;
MaxSizeReq->Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBuffer = pMtu;
MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(*pMtu);
NdisResetEvent(&MaxSizeReq->InternalRequestCompletedEvent);
// submit the request
ReqStatus = NdisOidRequest(pOpen->AdapterHandle, &MaxSizeReq->Request);
if (ReqStatus == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&MaxSizeReq->InternalRequestCompletedEvent, 0);
ReqStatus = MaxSizeReq->RequestStatus;
}
//
// Put the request in the list of the free ones
//
ExInterlockedInsertTailList(&pOpen->RequestList, &MaxSizeReq->ListElement, &pOpen->RequestSpinLock);
if (ReqStatus == NDIS_STATUS_SUCCESS)
{
TRACE_EXIT();
return STATUS_SUCCESS;
}
else
{
//
// THIS IS WRONG
//
//
// Assume Ethernet
//
*pMtu = 1514;
TRACE_EXIT();
return STATUS_SUCCESS;
// return ReqStatus;
}
}
//-------------------------------------------------------------------
NTSTATUS NPF_CloseAdapter(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
POPEN_INSTANCE pOpen;
PIO_STACK_LOCATION IrpSp;
TRACE_ENTER();
IrpSp = IoGetCurrentIrpStackLocation(Irp);
pOpen = IrpSp->FileObject->FsContext;
ASSERT(pOpen != NULL);
//
// Free the open instance itself
//
ExFreePool(pOpen);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return STATUS_SUCCESS;
}
//-------------------------------------------------------------------
NTSTATUS NPF_Cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
POPEN_INSTANCE Open;
NDIS_STATUS Status;
PIO_STACK_LOCATION IrpSp;
LARGE_INTEGER ThreadDelay;
ULONG localNumOpenInstances;
TRACE_ENTER();
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Open = IrpSp->FileObject->FsContext;
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open = %p\n", Open);
ASSERT(Open != NULL);
NPF_CloseOpenInstance(Open);
if (Open->ReadEvent != NULL)
KeSetEvent(Open->ReadEvent, 0, FALSE);
NPF_CloseBinding(Open);
// NOTE:
// code commented out because the kernel dump feature is disabled
//
//if (AdapterAlreadyClosing == FALSE)
//{
//
// Unfreeze the consumer
//
// 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)
// {
// 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);
// }
//}
//
// release all the resources
//
NPF_ReleaseOpenInstanceResources(Open);
// IrpSp->FileObject->FsContext = NULL;
//
// Decrease the counter of open instances
//
localNumOpenInstances = InterlockedDecrement(&g_NumOpenedInstances);
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenInstances);
if (localNumOpenInstances == 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);
}
//
// and complete the IRP with status success
//
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return(STATUS_SUCCESS);
}
//-------------------------------------------------------------------
VOID NPF_CloseAdapterCompleteEx(IN NDIS_HANDLE ProtocolBindingContext)
{
POPEN_INSTANCE Open;
PIRP Irp;
TRACE_ENTER();
Open = (POPEN_INSTANCE)ProtocolBindingContext;
ASSERT(Open != NULL);
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open= %p", Open);
NdisSetEvent(&Open->NdisOpenCloseCompleteEvent);
TRACE_EXIT();
return;
}
//-------------------------------------------------------------------
NDIS_STATUS NPF_NetPowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT_NOTIFICATION pNetPnPEvent)
{
TRACE_ENTER();
TIME_DESYNCHRONIZE(&G_Start_Time);
TIME_SYNCHRONIZE(&G_Start_Time);
TRACE_EXIT();
return STATUS_SUCCESS;
}
//------------------------------------------------------------------
NDIS_STATUS NPF_BindAdapterEx(IN NDIS_HANDLE ProtocolDriverContext, IN NDIS_HANDLE BindContext, IN PNDIS_BIND_PARAMETERS BindParameters)
{
NTSTATUS ntStatus = NDIS_STATUS_SUCCESS;
int a = 1;
a ++;
TRACE_ENTER();
TRACE_EXIT();
return ntStatus;
}
//-------------------------------------------------------------------
NDIS_STATUS NPF_UnbindAdapterEx(IN NDIS_HANDLE UnbindContext, IN NDIS_HANDLE ProtocolBindingContext)
{
NTSTATUS Status;
POPEN_INSTANCE Open = (POPEN_INSTANCE)ProtocolBindingContext;
TRACE_ENTER();
ASSERT(Open != NULL);
//
// The following code has been disabled bcause the kernel dump feature has been disabled.
//
////
//// Awake a possible pending read on this instance
//// TODO should be ok.
////
// if(Open->mode & MODE_DUMP)
// NdisSetEvent(&Open->DumpEvent);
// else
if (Open->ReadEvent != NULL)
KeSetEvent(Open->ReadEvent, 0, FALSE);
//
// The following code has been disabled bcause the kernel dump feature has been disabled.
//
////
//// If this instance is in dump mode, complete the dump and close the file
//// TODO needs to be checked again.
////
// if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL)
// NPF_CloseDumpFile(Open);
Status = NDIS_STATUS_SUCCESS;
NPF_CloseBinding(Open);
TRACE_EXIT();
return Status;
}
//-------------------------------------------------------------------
VOID NPF_ResetComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status)
{
POPEN_INSTANCE Open;
PIRP Irp;
PLIST_ENTRY ResetListEntry;
TRACE_ENTER();
Open = (POPEN_INSTANCE)ProtocolBindingContext;
//
// remove the reset IRP from the list
//
ResetListEntry = ExInterlockedRemoveHeadList(&Open->ResetIrpList, &Open->RequestSpinLock);
Irp = CONTAINING_RECORD(ResetListEntry, IRP, Tail.Overlay.ListEntry);
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return;
}
You've definitely hit across an interesting problem with WinPcap. Its protocol driver (NPF) expects to be able to open an adapter whenever it wants. When paired with Wireshark, it will do this frequently — it's typical to see NPF open and close the same adapter dozens of times just while the Wireshark GUI is loading. It's even possible to see NPF have multiple bindings to the same adapter simultaneously.
The rough equivalent of this in NDIS 6.x is the NdisReEnumerateProtocolBindings function. What this does is queue up a workitem to call into your protocol' ProtocolBindAdapterEx handler for each adapter that is marked as bound in the registry, but isn't currently bound in NDIS. (I.e., for each adapter that INetCfg finds a bindpath to that does not already have an open handle.)
However, due to the large impedance between NPF's API and how NDIS regards binding, you'll need to tackle a few issues:
Multiple simultaneous bindings to the same adapter. (This is a rarely-used feature; NPF is one of two protocols that I know use this, so it's not really discussed much in the MSDN documentation.) The only way to get multiple simultaneous bindings in NDIS 6.x is to call NdisOpenAdapterEx twice within the same ProtocolBindAdapterEx call. That's going to be challenging, because NPF's model is to open a new binding whenever an API call comes in from usermode; it doesn't know in advance how many handles will need to be opened.
If another bind request comes in, you can attempt to close all previous handles to that adapter (transparently to the NPF API[!]), call NdisReEnumerateProtocolBindings, then open N+1 handles in your upcoming ProtocolBindAdpaterEx handler. But this is brittle.
You can also try and merge all API calls to the same adapter. If a second bind request comes in, just route it to the pre-existing binding to that adapter. This might be difficult, depending on how NPF's internals work. (I'm not allowed to read NPF source code; I can't say.)
Finally, the cheesy solution is to just allocate two (or three) binding handles always, and keep the extras cached in case Wireshark needs them. This is cheap to implement, but still a bit fragile, since you can't really know if Wireshark will want more handles than you pre-allocated.
Missing INetCfg bindings. NDIS 5.x protocols are allowed to bind to an adapter even if the protocol isn't actually supposed to be bound (according to INetCfg). Wireshark uses this to get itself bound to all sorts of random adapters, without worrying too much about whether INetCfg agrees that NPF should be bound. Once you convert to NDIS 6.x, the rules are enforced strictly, and you'll need to make sure that your protocol's INF has a LowerRange keyword for each type of adapter you want to bind over. (I.e., the NPF protocol should show up in the Adapter Properties dialog box.)
Asynchronous bindings. The NdisReEnumerateProtocolBindings model is that you call it, and NDIS will make an attempt to bind your protocol to all bindable adapters. If the adapter isn't bindable for some reason (perhaps it's in a low-power state, or it's being surprise-removed), then NDIS will simply not call your protocol back. It's going to be tough to know exactly when to give up and return failure to the usermode NPF API, since you don't get a callback saying "you won't bind to this adapter". You may be able to use NetEventBindsComplete, but frankly that's kind of a dodgy, ill-defined event and I'm not convinced it's bulletproof. I'd put in a timeout, then use the NetEvent as a hint to cut the timeout short.
Finally, I just wanted to note that, although you said that you wanted to minimize the amount of churn in WinPcap, you might want to consider repackaging its driver as an NDIS LWF. LWFs were designed for exactly this purpose, so they tend to fit better with NPF's needs. (In particular, LWFs can see native 802.11 traffic, can get more accurate data without going through the loopback hack, and are quite a bit simpler than protocols.)
I'm trying to write legacy filter-hook driver, firewall-like: look for dst port and block it.
But when packets are sent, dispatcher routine isn't called.
Register dispatch:
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
Start ipfilter driver:
C:\Users\unnamed>net start ipfilterdriver
After that, launch debug driver via Visual DDK. Driver load successfully, but breakpoint in dispatcher isn't reached. What am I doing wrong?
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
UNICODE_STRING DeviceName,Win32Device;
PDEVICE_OBJECT DeviceObject = NULL;
NTSTATUS status;
unsigned i;
RtlInitUnicodeString(&DeviceName,L"\\Device\\driver10");
RtlInitUnicodeString(&Win32Device,L"\\DosDevices\\driver10");
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = driver1DefaultHandler;
/*
DriverObject->MajorFunction[IRP_MJ_CREATE] = driver1CreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = driver1CreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
*/
status = IoCreateDevice(DriverObject, 0, &DeviceName,
FILE_DEVICE_DRVFLTIP, 0, FALSE,
&DeviceObject);
if (NT_SUCCESS(status)) {
status = IoCreateSymbolicLink(&Win32Device, &DeviceName);
if (!NT_SUCCESS(status))
dprintf("DrvFltIp.SYS: IoCreateSymbolicLink failed\n");
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
DriverObject->DriverUnload = driver1Unload;
}
if (!NT_SUCCESS(status)) {
dprintf("Error in initialization. Unloading...");
driver1Unload(DriverObject);
}
if (!DeviceObject)
return STATUS_UNEXPECTED_IO_ERROR;
/*
DeviceObject->Flags |= DO_DIRECT_IO;
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
*/
DbgPrint("Driver started\n");
return status;
}
NTSTATUS DrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
dprintf("DrvDispatch called\n");
PIO_STACK_LOCATION irpStack;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG ioControlCode;
NTSTATUS ntStatus;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
irpStack = IoGetCurrentIrpStackLocation(Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
dprintf("DrvFltIp.SYS: IRP_MJ_CREATE\n");
break;
case IRP_MJ_CLOSE:
dprintf("DrvFltIp.SYS: IRP_MJ_CLOSE\n");
break;
case IRP_MJ_DEVICE_CONTROL:
dprintf("DrvFltIp.SYS: IRP_MJ_DEVICE_CONTROL\n");
break;
}
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ntStatus;
}
Just forgot register filter-hook callback function in the DriverEntry:
Registering and Clearing a Filter Hook