WDF Request and IRP - how to complete?

Category: windows hardware wdk and driver development

Question

nb3m on Mon, 18 Mar 2019 17:32:00


Hi,

My driver is using Windows Driver Framework and Winsock Kernel. When I am writing to driver I am using WDF EvtIoWrite which takes WDFREQUEST as an argument. This function is supposed to send data to winsock subsystem. I am completing request asynchronously. I have encounter problems with completing requests. Write event takes as an argument wdf request, wsksend function takes IRP. I have successfully extracted IRP from WDFREQUEST and passed it down to winsock subsystem. I am stuck with completing wdf request. How can I complete write request when WSK takes IRP, not WDFREQUEST?

Cheers,

Lukasz

Replies

Don Burn [Windrvr] on Mon, 18 Mar 2019 20:02:29


Why do you want to use the IRP that is part of the WDFREQUEST for the operation?   When I have used WSK I have always found it easier to just create an IRP as part of a CONTEXT block for the WSK request.   So:

	Context->Irp = IoAllocateIrp( 1, FALSE );

My context typically has the buffer pointers, MDL and other things that WSK needs for the operation.   When tying it to a WDFREQUEST I have a reference to the request in the context.

nb3m on Tue, 19 Mar 2019 08:21:42


Initially I tried to do it this way however I had problems to complete request asynchronously. That's why I decided to pass IRP down.

I can finish WSK async calls by I/O completion routines but still I don't know how to finish WDF request. Even if I create request context I won't have access to this structure from I/O completion routine. How do you handle WDF requests in async way?

Edit: WDF documentation states that before sending I/O call I have to format request. Part of that request is handle to I/O target - which is WSK subsystem? How do you set that argument?


Don Burn [Windrvr] on Tue, 19 Mar 2019 13:20:19


The following is a piece of code I have used on several projects:

//
//  FUNCTION:	InitNetOpContext()
//
//  PURPOSE:	Initialize the Netop context block, including allocating the IRP,
//				the Buffer and its MDL
//
//  PARAMETERS:
//				Context		- Pointer to the the Netop context block to initialize
//
//  RETURN VALUE:
//				NTSTATUS indicating success or failure
//
static NTSTATUS InitNetOpContext( PNETOP_CONTEXT Context )
{
	NTSTATUS		status;

	status = STATUS_SUCCESS;
	RtlZeroMemory( Context, sizeof( NETOP_CONTEXT ) );
	Context->Irp = IoAllocateIrp( 1, FALSE );
	if (Context->Irp == NULL)
	{
		status = STATUS_INSUFFICIENT_RESOURCES;
	}
	if (NT_SUCCESS( status ))
	{
		Context->Buffer = ExAllocatePoolWithTag( NonPagedPool, PAGE_SIZE, BUF_TAG );
		if (Context->Buffer == NULL)
		{
			status = STATUS_NO_MEMORY;
		}
	}
	if (NT_SUCCESS( status ))
	{
		Context->WskBuf.Mdl = IoAllocateMdl( Context->Buffer, PAGE_SIZE, FALSE, FALSE, NULL );
		if (Context->WskBuf.Mdl == NULL)
		{
			status = STATUS_INSUFFICIENT_RESOURCES;
		}
	}
	if (NT_SUCCESS( status ))
	{
		MmBuildMdlForNonPagedPool( Context->WskBuf.Mdl );
		KeInitializeEvent( &Context->Event, NotificationEvent, FALSE );
		IoSetCompletionRoutine( Context->Irp, NetopCompletionRoutine,
			Context, TRUE, TRUE, TRUE );
	}
	else
	{
		FreeNetOpContext( Context );
	}
	return status;
}

WSK mainly uses the IRP for notification, you don't need a lot of setup of the IRP just the completion routine.   Once your completion routine is called you then can complete the WDFREQUEST as you would any other request.

nb3m on Tue, 19 Mar 2019 14:06:02


Thanks Don for your replays,

There is something I don't understand... When WSK completion routine is called how do you want to complete WDF request? WDFREQUEST object is not available inside WSK completion routine because WskSend takes as an context PWSK_BUF structure. If I complete WDFREQUEST right after calling WskSend then it won't be asynchronous communication. Or can I complete WDFREQUEST with IRP pending status waiting to be proceed by WSK?


Don Burn [Windrvr] on Tue, 19 Mar 2019 14:27:17


The CompletionRoutine of the IRP has a context parameter, which is where you store the Context from the code above.  Put you WDFREQUEST in as a field of the Context, then complete the request in the CompletionRoutine you use for calls.    If your WskSend will take a long time, make the request cancelable.

nb3m on Tue, 19 Mar 2019 14:47:05


Now I see what I did wrong. I did not notice that I can pass whatever context I want inside completion routine. WSK documentation in every example passed wsk_buf structure. Thanks Don! I think I can handle it now!

Cheers!