none
WDF Request and IRP - how to complete? RRS feed

  • Question

  • 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

    Monday, March 18, 2019 5:32 PM

Answers

  • 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.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    • Marked as answer by nb3m Tuesday, March 19, 2019 2:53 PM
    Tuesday, March 19, 2019 1:20 PM
  • 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.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    • Marked as answer by nb3m Tuesday, March 19, 2019 2:53 PM
    Tuesday, March 19, 2019 2:27 PM

All replies

  • 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.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Monday, March 18, 2019 8:02 PM
  • 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?


    • Edited by nb3m Tuesday, March 19, 2019 8:55 AM
    Tuesday, March 19, 2019 8:21 AM
  • 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.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    • Marked as answer by nb3m Tuesday, March 19, 2019 2:53 PM
    Tuesday, March 19, 2019 1:20 PM
  • 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?


    • Edited by nb3m Tuesday, March 19, 2019 2:07 PM
    Tuesday, March 19, 2019 2:06 PM
  • 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.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    • Marked as answer by nb3m Tuesday, March 19, 2019 2:53 PM
    Tuesday, March 19, 2019 2:27 PM
  • 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!


    • Edited by nb3m Tuesday, March 19, 2019 2:55 PM
    Tuesday, March 19, 2019 2:47 PM