1247 lines
38 KiB
C
1247 lines
38 KiB
C
/*++
|
||
|
||
Copyright (c) 2000-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Tdi.c
|
||
|
||
Abstract:
|
||
|
||
This module implements Initialization routines
|
||
the PGM Transport and other routines that are specific to the
|
||
NT implementation of a driver.
|
||
|
||
Author:
|
||
|
||
Mohammad Shabbir Alam (MAlam) 3-30-2000
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "precomp.h"
|
||
#include <ntddtcp.h> // for IOCTL_TCP_SET_INFORMATION_EX
|
||
#include <tcpinfo.h> // for TCPSocketOption
|
||
#include <tdiinfo.h> // for TCP_REQUEST_SET_INFORMATION_EX
|
||
|
||
|
||
//******************* Pageable Routine Declarations ****************
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, TdiOpenAddressHandle)
|
||
#pragma alloc_text(PAGE, CloseAddressHandles)
|
||
#pragma alloc_text(PAGE, PgmTdiOpenControl)
|
||
#endif
|
||
//******************* Pageable Routine Declarations ****************
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
PgmTdiCompletionRoutine(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine does not complete the Irp. It is used to signal to a
|
||
synchronous part of the NBT driver that it can proceed (i.e.
|
||
to allow some code that is waiting on a "KeWaitForSingleObject" to
|
||
proceeed.
|
||
|
||
Arguments:
|
||
|
||
IN DeviceObject -- unused.
|
||
IN Irp -- Supplies Irp that the transport has finished processing.
|
||
IN Context -- Supplies the event associated with the Irp.
|
||
|
||
Return Value:
|
||
|
||
The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
|
||
processing Irp stack locations at this point.
|
||
|
||
--*/
|
||
{
|
||
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "PgmTdiCompletionRoutine",
|
||
"CompletionEvent: pEvent=<%p>, pIrp=<%p>, DeviceObject=<%p>\n", Context, Irp, DeviceObject);
|
||
|
||
KeSetEvent ((PKEVENT )Context, 0, FALSE);
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
|
||
//----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
TdiSetEventHandler (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PFILE_OBJECT FileObject,
|
||
IN ULONG EventType,
|
||
IN PVOID EventHandler,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine registers an event handler with a TDI transport provider.
|
||
|
||
Arguments:
|
||
|
||
IN PDEVICE_OBJECT DeviceObject -- Supplies the device object of the transport provider.
|
||
IN PFILE_OBJECT FileObject -- Supplies the address object's file object.
|
||
IN ULONG EventType, -- Supplies the type of event.
|
||
IN PVOID EventHandler -- Supplies the event handler.
|
||
IN PVOID Context -- Supplies the context passed into the event handler when it runs
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the set event operation
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
KEVENT Event;
|
||
PIRP pIrp;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!(pIrp = IoAllocateIrp (IoGetRelatedDeviceObject (FileObject)->StackSize, FALSE)))
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiSetEventHandler",
|
||
"INSUFFICIENT_RESOURCES allocating Irp, StackSize=<%d>\n",
|
||
IoGetRelatedDeviceObject (FileObject)->StackSize);
|
||
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
TdiBuildSetEventHandler (pIrp, DeviceObject, FileObject,
|
||
NULL, NULL,
|
||
EventType, EventHandler, Context);
|
||
|
||
KeInitializeEvent (&Event, NotificationEvent, FALSE);
|
||
|
||
// set the address of the routine to be executed when the IRP
|
||
// finishes. This routine signals the event and allows the code
|
||
// below to continue (i.e. KeWaitForSingleObject)
|
||
//
|
||
IoSetCompletionRoutine (pIrp,
|
||
(PIO_COMPLETION_ROUTINE) PgmTdiCompletionRoutine,
|
||
(PVOID)&Event,
|
||
TRUE, TRUE, TRUE);
|
||
|
||
Status = IoCallDriver (IoGetRelatedDeviceObject (FileObject), pIrp);
|
||
if (Status == STATUS_PENDING)
|
||
{
|
||
Status = KeWaitForSingleObject ((PVOID)&Event, // Object to wait on.
|
||
Executive, // Reason for waiting
|
||
KernelMode, // Processor mode
|
||
FALSE, // Alertable
|
||
NULL); // Timeout
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
Status = pIrp->IoStatus.Status;
|
||
}
|
||
}
|
||
|
||
IoFreeIrp (pIrp);
|
||
|
||
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "TdiSetEventHandler",
|
||
"Status=<%d>, EventType=<%d>, Hanlder=<%x>\n", Status, EventType, EventHandler);
|
||
|
||
return (Status);
|
||
}
|
||
|
||
//----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
TdiErrorHandler(
|
||
IN PVOID Context,
|
||
IN NTSTATUS Status
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the handler for TDI errors
|
||
|
||
Arguments:
|
||
|
||
IN Context -- unused
|
||
IN Status -- error status
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the set event operation
|
||
|
||
--*/
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiErrorHandler",
|
||
"Status=<%x>\n", Status);
|
||
|
||
return (STATUS_DATA_NOT_ACCEPTED);
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
TdiOpenAddressHandle(
|
||
IN tPGM_DEVICE *pPgmDevice,
|
||
IN PVOID HandlerContext,
|
||
IN tIPADDRESS IpAddress,
|
||
IN USHORT PortNumber,
|
||
OUT HANDLE *pFileHandle,
|
||
OUT PFILE_OBJECT *ppFileObject,
|
||
OUT PDEVICE_OBJECT *ppDeviceObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to open an address handle on IP
|
||
|
||
Arguments:
|
||
|
||
IN pPgmDevice -- Pgm's Device object context
|
||
IN HandlerContext -- pAddress object ptr to be used as context ptr (NULL if don't want to be notified)
|
||
IN IpAddress -- local IpAddress on which to open address
|
||
IN PortNumber -- IP protocol port
|
||
OUT pFileHandle -- FileHandle if we succeeded
|
||
OUT ppFileObject -- FileObject if we succeeded
|
||
OUT ppDeviceObject -- IP's DeviceObject ptr if we succeeded
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the Open Address operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
ULONG EaBufferSize;
|
||
PFILE_FULL_EA_INFORMATION EaBuffer;
|
||
PTRANSPORT_ADDRESS pTransAddressEa;
|
||
PTRANSPORT_ADDRESS pTransAddr;
|
||
TDI_ADDRESS_IP IpAddr;
|
||
OBJECT_ATTRIBUTES AddressAttributes;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
PFILE_OBJECT pFileObject;
|
||
HANDLE FileHandle;
|
||
PDEVICE_OBJECT pDeviceObject;
|
||
KAPC_STATE ApcState;
|
||
BOOLEAN fAttached;
|
||
ULONG True = TRUE;
|
||
|
||
PAGED_CODE();
|
||
|
||
EaBufferSize = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
||
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
||
sizeof(TRANSPORT_ADDRESS) +
|
||
sizeof(TDI_ADDRESS_IP);
|
||
|
||
if (!(EaBuffer = PgmAllocMem (EaBufferSize, PGM_TAG('1'))))
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
|
||
"[1]: INSUFFICIENT_RESOURCES allocating <%d> bytes\n", EaBufferSize);
|
||
|
||
return (STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
// allocate Memory for the transport address
|
||
//
|
||
if (!(pTransAddr = PgmAllocMem (sizeof(TRANSPORT_ADDRESS)+sizeof(TDI_ADDRESS_IP), PGM_TAG('2'))))
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
|
||
"[2]: INSUFFICIENT_RESOURCES allocating <%d> bytes\n",
|
||
(sizeof(TRANSPORT_ADDRESS)+sizeof(TDI_ADDRESS_IP)));
|
||
|
||
PgmFreeMem (EaBuffer);
|
||
return (STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
EaBuffer->NextEntryOffset = 0;
|
||
EaBuffer->Flags = 0;
|
||
EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
||
EaBuffer->EaValueLength = (USHORT)(sizeof(TRANSPORT_ADDRESS) -1 + sizeof(TDI_ADDRESS_IP));
|
||
PgmMoveMemory (EaBuffer->EaName, TdiTransportAddress, EaBuffer->EaNameLength+1); // "TransportAddress"
|
||
|
||
// fill in the IP address and Port number
|
||
//
|
||
IpAddr.sin_port = htons (PortNumber); // put in network order
|
||
IpAddr.in_addr = htonl (IpAddress);
|
||
RtlFillMemory ((PVOID)&IpAddr.sin_zero, sizeof(IpAddr.sin_zero), 0); // zero fill the last component
|
||
|
||
// copy the ip address to the end of the structure
|
||
//
|
||
PgmMoveMemory (pTransAddr->Address[0].Address, (CONST PVOID)&IpAddr, sizeof(IpAddr));
|
||
pTransAddr->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
|
||
pTransAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
||
pTransAddr->TAAddressCount = 1;
|
||
|
||
// copy the ip address to the end of the name in the EA structure
|
||
pTransAddressEa = (TRANSPORT_ADDRESS *)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
|
||
PgmMoveMemory ((PVOID)pTransAddressEa,
|
||
(CONST PVOID)pTransAddr,
|
||
sizeof(TDI_ADDRESS_IP) + sizeof(TRANSPORT_ADDRESS)-1);
|
||
|
||
PgmAttachFsp (&ApcState, &fAttached, REF_FSP_OPEN_ADDR_HANDLE);
|
||
|
||
InitializeObjectAttributes (&AddressAttributes,
|
||
&pPgmDevice->ucBindName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL);
|
||
|
||
status = ZwCreateFile (&FileHandle,
|
||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
||
&AddressAttributes,
|
||
&IoStatusBlock,
|
||
NULL,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
0,
|
||
FILE_OPEN_IF,
|
||
0,
|
||
(PVOID)EaBuffer,
|
||
sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
||
EaBuffer->EaNameLength + 1 +
|
||
EaBuffer->EaValueLength);
|
||
|
||
PgmFreeMem ((PVOID)pTransAddr);
|
||
PgmFreeMem ((PVOID)EaBuffer);
|
||
|
||
if (NT_SUCCESS (status))
|
||
{
|
||
status = IoStatusBlock.Status;
|
||
}
|
||
|
||
if (NT_SUCCESS (status))
|
||
{
|
||
//
|
||
// Reference the FileObject to keep device ptr around!
|
||
//
|
||
status = ObReferenceObjectByHandle (FileHandle, (ULONG)0, 0, KernelMode, (PVOID *)&pFileObject, NULL);
|
||
if (!NT_SUCCESS (status))
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
|
||
"FAILed to Reference FileObject: status=<%x>\n", status);
|
||
|
||
ZwClose (FileHandle);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
|
||
"FAILed to create handle: status=<%x>, Device:\n\t%wZ\n", status, &pPgmDevice->ucBindName);
|
||
}
|
||
|
||
if (!NT_SUCCESS (status))
|
||
{
|
||
PgmDetachFsp (&ApcState, &fAttached, REF_FSP_OPEN_ADDR_HANDLE);
|
||
return (status);
|
||
}
|
||
|
||
pDeviceObject = IoGetRelatedDeviceObject (pFileObject);
|
||
|
||
//
|
||
// Now set the Event handlers (only if we have the HandlerContext set)!
|
||
//
|
||
if (HandlerContext)
|
||
{
|
||
status = TdiSetEventHandler (pDeviceObject,
|
||
pFileObject,
|
||
TDI_EVENT_ERROR,
|
||
(PVOID) TdiErrorHandler,
|
||
HandlerContext);
|
||
if (NT_SUCCESS (status))
|
||
{
|
||
// Datagram Udp Handler
|
||
status = TdiSetEventHandler (pDeviceObject,
|
||
pFileObject,
|
||
TDI_EVENT_RECEIVE_DATAGRAM,
|
||
(PVOID) TdiRcvDatagramHandler,
|
||
HandlerContext);
|
||
if (NT_SUCCESS (status))
|
||
{
|
||
status = PgmSetTcpInfo (FileHandle,
|
||
AO_OPTION_IP_PKTINFO,
|
||
&True,
|
||
sizeof (True));
|
||
|
||
if (!NT_SUCCESS (status))
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
|
||
"Setting AO_OPTION_IP_PKTINFO, status=<%x>\n", status);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
|
||
"FAILed to set TDI_EVENT_RECEIVE_DATAGRAM handler, status=<%x>\n", status);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
|
||
"FAILed to set TDI_EVENT_ERROR handler, status=<%x>\n", status);
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(status))
|
||
{
|
||
*pFileHandle = FileHandle;
|
||
*ppFileObject = pFileObject;
|
||
*ppDeviceObject = pDeviceObject;
|
||
|
||
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "TdiOpenAddressHandle",
|
||
"SUCCEEDed, FileHandle=<%x>, pFileObject=<%x>, pDeviceObject=<%x>\n",
|
||
FileHandle, pFileObject, pDeviceObject);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// FAILed to set Tdi handlers
|
||
//
|
||
ObDereferenceObject (pFileObject);
|
||
ZwClose (FileHandle);
|
||
}
|
||
|
||
PgmDetachFsp (&ApcState, &fAttached, REF_FSP_OPEN_ADDR_HANDLE);
|
||
|
||
return (status);
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
CloseAddressHandles(
|
||
IN HANDLE FileHandle,
|
||
IN PFILE_OBJECT pFileObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dereferences any FileObjects as necessary and closes the
|
||
FileHandle that was opened earlier
|
||
|
||
Arguments:
|
||
|
||
IN FileHandle -- FileHandle to be closed
|
||
IN pFileObject -- FileObject to be dereferenced
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the CloseAddress operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status1 = STATUS_SUCCESS, status2 = STATUS_SUCCESS;
|
||
KAPC_STATE ApcState;
|
||
BOOLEAN fAttached;
|
||
|
||
PAGED_CODE();
|
||
|
||
PgmAttachFsp (&ApcState, &fAttached, REF_FSP_CLOSE_ADDRESS_HANDLES);
|
||
|
||
if (pFileObject)
|
||
{
|
||
status2 = ObDereferenceObject ((PVOID *) pFileObject);
|
||
}
|
||
|
||
if (FileHandle)
|
||
{
|
||
status1 = ZwClose (FileHandle);
|
||
}
|
||
|
||
PgmDetachFsp (&ApcState, &fAttached, REF_FSP_CLOSE_ADDRESS_HANDLES);
|
||
|
||
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "CloseAddressHandles",
|
||
"FileHandle=<%x> ==> status=<%x>, pFileObject=<%x> ==> status=<%x>\n",
|
||
FileHandle, status2, pFileObject, status1);
|
||
|
||
return (STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
PgmTdiOpenControl(
|
||
IN tPGM_DEVICE *pPgmDevice
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens a Control channel over Raw IP
|
||
|
||
Arguments:
|
||
|
||
IN pPgmDevice -- Pgm's Device object context
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
KAPC_STATE ApcState;
|
||
BOOLEAN fAttached;
|
||
|
||
PAGED_CODE();
|
||
|
||
PgmAttachFsp (&ApcState, &fAttached, REF_FSP_OPEN_CONTROL_HANDLE);
|
||
|
||
InitializeObjectAttributes (&ObjectAttributes,
|
||
&pPgmDevice->ucBindName,
|
||
0,
|
||
NULL,
|
||
NULL);
|
||
|
||
Status = ZwCreateFile ((PHANDLE) &pPgmDevice->hControl,
|
||
GENERIC_READ | GENERIC_WRITE,
|
||
&ObjectAttributes, // object attributes.
|
||
&IoStatusBlock, // returned status information.
|
||
NULL, // block size (unused).
|
||
FILE_ATTRIBUTE_NORMAL, // file attributes.
|
||
0,
|
||
FILE_CREATE,
|
||
0, // create options.
|
||
(PVOID)EaBuffer, // EA buffer.
|
||
0); // Ea length
|
||
|
||
if (NT_SUCCESS (Status))
|
||
{
|
||
Status = IoStatusBlock.Status;
|
||
}
|
||
|
||
if (NT_SUCCESS (Status))
|
||
{
|
||
//
|
||
// get a reference to the file object and save it since we can't
|
||
// dereference a file handle at DPC level so we do it now and keep
|
||
// the ptr around for later.
|
||
//
|
||
Status = ObReferenceObjectByHandle (pPgmDevice->hControl,
|
||
0L,
|
||
NULL,
|
||
KernelMode,
|
||
(PVOID *) &pPgmDevice->pControlFileObject,
|
||
NULL);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmTdiOpenControl",
|
||
"ObReferenceObjectByHandle FAILed status=<%x>\n", Status);
|
||
|
||
ZwClose (pPgmDevice->hControl);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmTdiOpenControl",
|
||
"Failed to Open the Control file, Status=<%x>\n", Status);
|
||
}
|
||
|
||
PgmDetachFsp (&ApcState, &fAttached, REF_FSP_OPEN_CONTROL_HANDLE);
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
//
|
||
// We Succeeded!
|
||
//
|
||
pPgmDevice->pControlDeviceObject = IoGetRelatedDeviceObject (pPgmDevice->pControlFileObject);
|
||
|
||
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "PgmTdiOpenControl",
|
||
"Opened Control channel on: %wZ\n", &pPgmDevice->ucBindName);
|
||
}
|
||
else
|
||
{
|
||
// set control file object ptr to null so we know that we did not open the control point.
|
||
pPgmDevice->hControl = NULL;
|
||
pPgmDevice->pControlFileObject = NULL;
|
||
}
|
||
|
||
return (Status);
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
VOID
|
||
PgmDereferenceControl(
|
||
IN tCONTROL_CONTEXT *pControlContext,
|
||
IN ULONG RefContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dereferences the control channel oblect over RawIP and
|
||
frees the memory if the RefCount drops to 0
|
||
|
||
Arguments:
|
||
|
||
IN pControlContext -- Control object context
|
||
IN RefContext -- Context for which this control object was referenced earlier
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
{
|
||
ASSERT (PGM_VERIFY_HANDLE (pControlContext, PGM_VERIFY_CONTROL));
|
||
ASSERT (pControlContext->RefCount); // Check for too many derefs
|
||
ASSERT (pControlContext->ReferenceContexts[RefContext]--);
|
||
|
||
if (--pControlContext->RefCount)
|
||
{
|
||
return;
|
||
}
|
||
|
||
PgmLog (PGM_LOG_INFORM_STATUS, DBG_TDI, "PgmDereferenceControl",
|
||
"pControl=<%x> closed\n", pControlContext);
|
||
//
|
||
// Just Free the memory
|
||
//
|
||
PgmFreeMem (pControlContext);
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
NTSTATUS
|
||
TdiSendDatagramCompletion(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP pIrp,
|
||
IN PVOID pContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called on completion of a DatagramSend
|
||
|
||
Arguments:
|
||
|
||
IN PDEVICE_OBJECT DeviceObject -- Supplies the device object of the transport provider.
|
||
IN pIrp -- Request
|
||
IN PVOID Context -- Supplies the context passed
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the completion which will determine
|
||
how the IO subsystem processes it subsequently
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
tTDI_SEND_CONTEXT *pTdiSendContext = (tTDI_SEND_CONTEXT *) pContext;
|
||
|
||
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "PgmSendDatagramCompletion",
|
||
"status=<%x>, Info=<%d>, pIrp=<%x>\n", pIrp->IoStatus.Status, pIrp->IoStatus.Information, pIrp);
|
||
|
||
pTdiSendContext->pClientCompletionRoutine (pTdiSendContext->ClientCompletionContext1,
|
||
pTdiSendContext->ClientCompletionContext2,
|
||
pIrp->IoStatus.Status);
|
||
|
||
//
|
||
// Free the Memory that was allocated for this send
|
||
//
|
||
ExFreeToNPagedLookasideList (&PgmStaticConfig.TdiLookasideList, pTdiSendContext);
|
||
IoFreeMdl (pIrp->MdlAddress);
|
||
IoFreeIrp (pIrp);
|
||
|
||
// return this status to stop the IO subsystem from further processing the
|
||
// IRP - i.e. trying to complete it back to the initiating thread! -since
|
||
// there is no initiating thread - we are the initiator
|
||
return (STATUS_MORE_PROCESSING_REQUIRED);
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
NTSTATUS
|
||
TdiSendDatagram(
|
||
IN PFILE_OBJECT pTdiFileObject,
|
||
IN PDEVICE_OBJECT pTdiDeviceObject,
|
||
IN PVOID pBuffer,
|
||
IN ULONG BufferLength,
|
||
IN pCLIENT_COMPLETION_ROUTINE pClientCompletionRoutine,
|
||
IN PVOID ClientCompletionContext1,
|
||
IN PVOID ClientCompletionContext2,
|
||
IN tIPADDRESS DestIpAddress,
|
||
IN USHORT DestPort
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sends a datagram over RawIp
|
||
|
||
Arguments:
|
||
|
||
IN pTdiFileObject -- IP's FileObject for this address
|
||
IN pTdiDeviceObject -- DeviceObject for this address
|
||
IN pBuffer -- Data buffer (Pgm packet)
|
||
IN BufferLength -- length of pBuffer
|
||
IN pClientCompletionRoutine -- SendCompletion to be called
|
||
IN ClientCompletionContext1 -- Context1 for SendCompletion
|
||
IN ClientCompletionContext2 -- Context2 for SendCompletion
|
||
IN DestIpAddress -- IP address to send datagram to
|
||
IN DestPort -- Port to send to
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - STATUS_PENDING on success, and also if SendCompletion was specified
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
tTDI_SEND_CONTEXT *pTdiSendContext = NULL;
|
||
PIRP pIrp = NULL;
|
||
PMDL pMdl = NULL;
|
||
|
||
//
|
||
// Allocate the SendContext, pIrp and pMdl
|
||
//
|
||
if ((!(pTdiSendContext = ExAllocateFromNPagedLookasideList (&PgmStaticConfig.TdiLookasideList))) ||
|
||
(!(pIrp = IoAllocateIrp (pgPgmDevice->pPgmDeviceObject->StackSize, FALSE))) ||
|
||
(!(pMdl = IoAllocateMdl (pBuffer, BufferLength, FALSE, FALSE, NULL))))
|
||
{
|
||
if (pTdiSendContext)
|
||
{
|
||
ExFreeToNPagedLookasideList (&PgmStaticConfig.TdiLookasideList, pTdiSendContext);
|
||
}
|
||
|
||
if (pIrp)
|
||
{
|
||
IoFreeIrp (pIrp);
|
||
}
|
||
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiSendDatagram",
|
||
"INSUFFICIENT_RESOURCES for TdiSendContext=<%d> bytes\n", sizeof(tTDI_SEND_CONTEXT));
|
||
|
||
if (pClientCompletionRoutine)
|
||
{
|
||
pClientCompletionRoutine (ClientCompletionContext1,
|
||
ClientCompletionContext2,
|
||
STATUS_INSUFFICIENT_RESOURCES);
|
||
status = STATUS_PENDING;
|
||
}
|
||
else
|
||
{
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
return (status);
|
||
}
|
||
|
||
MmBuildMdlForNonPagedPool (pMdl);
|
||
pIrp->MdlAddress = pMdl;
|
||
|
||
// fill in the remote address
|
||
pTdiSendContext->TransportAddress.TAAddressCount = 1;
|
||
pTdiSendContext->TransportAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
|
||
pTdiSendContext->TransportAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
||
pTdiSendContext->TransportAddress.Address[0].Address->in_addr = htonl(DestIpAddress);
|
||
pTdiSendContext->TransportAddress.Address[0].Address->sin_port = htons(DestPort);
|
||
|
||
// fill in the connection information
|
||
pTdiSendContext->TdiConnectionInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
|
||
pTdiSendContext->TdiConnectionInfo.RemoteAddress = &pTdiSendContext->TransportAddress;
|
||
|
||
// Fill in our completion Context information
|
||
pTdiSendContext->pClientCompletionRoutine = pClientCompletionRoutine;
|
||
pTdiSendContext->ClientCompletionContext1 = ClientCompletionContext1;
|
||
pTdiSendContext->ClientCompletionContext2 = ClientCompletionContext2;
|
||
|
||
// Complete the "send datagram" IRP initialization.
|
||
//
|
||
TdiBuildSendDatagram (pIrp,
|
||
pTdiDeviceObject,
|
||
pTdiFileObject,
|
||
(PVOID) TdiSendDatagramCompletion,
|
||
pTdiSendContext,
|
||
pIrp->MdlAddress,
|
||
BufferLength,
|
||
&pTdiSendContext->TdiConnectionInfo);
|
||
|
||
//
|
||
// Tell the I/O manager to pass our IRP to the transport for
|
||
// processing.
|
||
//
|
||
status = IoCallDriver (pTdiDeviceObject, pIrp);
|
||
ASSERT (status == STATUS_PENDING);
|
||
|
||
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "TdiSendDatagram",
|
||
"%s Send to <%x:%x>, status=<%x>\n",
|
||
(CLASSD_ADDR(DestIpAddress) ? "MCast" : "Unicast"), DestIpAddress, DestPort, status);
|
||
|
||
//
|
||
// IoCallDriver will always result in completion routien being called
|
||
//
|
||
return (STATUS_PENDING);
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
PgmSetTcpInfo(
|
||
IN HANDLE FileHandle,
|
||
IN ULONG ToiId,
|
||
IN PVOID pData,
|
||
IN ULONG DataLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to set IP-specific options
|
||
|
||
Arguments:
|
||
|
||
IN FileHandle -- FileHandle over IP for which to set option
|
||
IN ToId -- Option Id
|
||
IN pData -- Option data
|
||
IN DataLength -- pData length
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the set option operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status, LocStatus;
|
||
ULONG BufferLength;
|
||
TCP_REQUEST_SET_INFORMATION_EX *pTcpInfo;
|
||
IO_STATUS_BLOCK IoStatus;
|
||
HANDLE event;
|
||
KAPC_STATE ApcState;
|
||
BOOLEAN fAttached;
|
||
|
||
IoStatus.Status = STATUS_SUCCESS;
|
||
|
||
BufferLength = sizeof (TCP_REQUEST_SET_INFORMATION_EX) + DataLength;
|
||
if (!(pTcpInfo = (TCP_REQUEST_SET_INFORMATION_EX *) PgmAllocMem (BufferLength, PGM_TAG('2'))))
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmSetTcpInfo",
|
||
"INSUFFICIENT_RESOURCES for pTcpInfo=<%d+%d> bytes\n",
|
||
sizeof(TCP_REQUEST_SET_INFORMATION_EX), DataLength);
|
||
|
||
return (STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
PgmZeroMemory (pTcpInfo, BufferLength);
|
||
|
||
pTcpInfo->ID.toi_entity.tei_entity = CL_TL_ENTITY;
|
||
pTcpInfo->ID.toi_entity.tei_instance= TL_INSTANCE;
|
||
pTcpInfo->ID.toi_class = INFO_CLASS_PROTOCOL;
|
||
pTcpInfo->ID.toi_type = INFO_TYPE_ADDRESS_OBJECT;
|
||
|
||
//
|
||
// Set the Configured values
|
||
//
|
||
pTcpInfo->ID.toi_id = ToiId;
|
||
pTcpInfo->BufferSize = DataLength;
|
||
PgmCopyMemory (&pTcpInfo->Buffer[0], pData, DataLength);
|
||
|
||
PgmAttachFsp (&ApcState, &fAttached, REF_FSP_SET_TCP_INFO);
|
||
|
||
Status = ZwCreateEvent (&event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
//
|
||
// Make the actual TDI call
|
||
//
|
||
Status = ZwDeviceIoControlFile (FileHandle,
|
||
event,
|
||
NULL,
|
||
NULL,
|
||
&IoStatus,
|
||
IOCTL_TCP_SET_INFORMATION_EX,
|
||
pTcpInfo,
|
||
BufferLength,
|
||
NULL,
|
||
0);
|
||
|
||
//
|
||
// If the call pended and we were supposed to wait for completion,
|
||
// then wait.
|
||
//
|
||
if (Status == STATUS_PENDING)
|
||
{
|
||
Status = NtWaitForSingleObject (event, FALSE, NULL);
|
||
ASSERT (NT_SUCCESS(Status));
|
||
}
|
||
|
||
if (NT_SUCCESS (Status))
|
||
{
|
||
Status = IoStatus.Status;
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmSetTcpInfo",
|
||
"TcpSetInfoEx request returned Status = <%x>, Id=<0x%x>\n", Status, ToiId);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmSetTcpInfo",
|
||
"ZwDeviceIoControlFile returned Status = <%x>, Id=<0x%x>\n", Status, ToiId);
|
||
}
|
||
|
||
LocStatus = ZwClose (event);
|
||
ASSERT (NT_SUCCESS(LocStatus));
|
||
}
|
||
else
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmSetTcpInfo",
|
||
"ZwCreateEvent returned Status = <%x>, Id=<0x%x>\n", Status, ToiId);
|
||
}
|
||
|
||
PgmDetachFsp (&ApcState, &fAttached, REF_FSP_SET_TCP_INFO);
|
||
|
||
if (STATUS_SUCCESS == Status)
|
||
{
|
||
PgmLog (PGM_LOG_INFORM_STATUS, DBG_TDI, "PgmSetTcpInfo",
|
||
"ToiId=<%x>, DataLength=<%d>\n", ToiId, DataLength);
|
||
}
|
||
else
|
||
{
|
||
Status = STATUS_UNSUCCESSFUL; // Once, we received a wierd status!
|
||
}
|
||
|
||
PgmFreeMem (pTcpInfo);
|
||
|
||
return (Status);
|
||
}
|
||
|
||
//----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
PgmQueryTcpInfo(
|
||
IN HANDLE FileHandle,
|
||
IN ULONG ToiId,
|
||
IN PVOID pDataIn,
|
||
IN ULONG DataInLength,
|
||
IN PVOID pDataOut,
|
||
IN ULONG DataOutLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine queries IP for transport-specific information
|
||
|
||
Arguments:
|
||
|
||
IN FileHandle -- FileHandle over IP for which to set option
|
||
IN ToId -- Option Id
|
||
IN pDataIn -- Option data
|
||
IN DataInLength -- pDataIn length
|
||
IN pDataOut -- Buffer for output data
|
||
IN DataOutLength -- pDataOut length
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the Query operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status, LocStatus;
|
||
TCP_REQUEST_QUERY_INFORMATION_EX QueryRequest;
|
||
IO_STATUS_BLOCK IoStatus;
|
||
HANDLE event;
|
||
KAPC_STATE ApcState;
|
||
BOOLEAN fAttached;
|
||
|
||
IoStatus.Status = STATUS_SUCCESS;
|
||
|
||
PgmZeroMemory (&QueryRequest, sizeof (TCP_REQUEST_QUERY_INFORMATION_EX));
|
||
QueryRequest.ID.toi_entity.tei_entity = CL_NL_ENTITY;
|
||
QueryRequest.ID.toi_entity.tei_instance = 0;
|
||
QueryRequest.ID.toi_class = INFO_CLASS_PROTOCOL;
|
||
QueryRequest.ID.toi_type = INFO_TYPE_PROVIDER;
|
||
|
||
//
|
||
// Set the Configured values
|
||
//
|
||
QueryRequest.ID.toi_id = ToiId;
|
||
PgmCopyMemory (&QueryRequest.Context, pDataIn, DataInLength);
|
||
|
||
PgmAttachFsp (&ApcState, &fAttached, REF_FSP_SET_TCP_INFO);
|
||
|
||
Status = ZwCreateEvent (&event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
//
|
||
// Make the actual TDI call
|
||
//
|
||
Status = ZwDeviceIoControlFile (FileHandle,
|
||
event,
|
||
NULL,
|
||
NULL,
|
||
&IoStatus,
|
||
IOCTL_TCP_QUERY_INFORMATION_EX,
|
||
&QueryRequest,
|
||
sizeof (TCP_REQUEST_QUERY_INFORMATION_EX),
|
||
pDataOut,
|
||
DataOutLength);
|
||
|
||
//
|
||
// If the call pended and we were supposed to wait for completion,
|
||
// then wait.
|
||
//
|
||
if (Status == STATUS_PENDING)
|
||
{
|
||
Status = NtWaitForSingleObject (event, FALSE, NULL);
|
||
ASSERT (NT_SUCCESS(Status));
|
||
}
|
||
|
||
if (NT_SUCCESS (Status))
|
||
{
|
||
Status = IoStatus.Status;
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmQueryTcpInfo",
|
||
"TcpQueryInfoEx request returned Status = <%x>, Id=<0x%x>, DataOutLength=<%d>\n",
|
||
Status, ToiId, DataOutLength);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmQueryTcpInfo",
|
||
"ZwDeviceIoControlFile returned Status = <%x>, Id=<0x%x>, DataOutLength=<%d>\n",
|
||
Status, ToiId, DataOutLength);
|
||
}
|
||
|
||
LocStatus = ZwClose (event);
|
||
ASSERT (NT_SUCCESS(LocStatus));
|
||
}
|
||
else
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmQueryTcpInfo",
|
||
"ZwCreateEvent returned Status = <%x>, Id=<0x%x>\n", Status, ToiId);
|
||
}
|
||
|
||
PgmDetachFsp (&ApcState, &fAttached, REF_FSP_SET_TCP_INFO);
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
PgmLog (PGM_LOG_INFORM_STATUS, DBG_TDI, "PgmQueryTcpInfo",
|
||
"ToiId=<%x>, DataInLength=<%d>, DataOutLength=<%d>\n",
|
||
ToiId, DataInLength, DataOutLength);
|
||
}
|
||
else
|
||
{
|
||
Status = STATUS_UNSUCCESSFUL; // Once, we received a wierd status!
|
||
}
|
||
|
||
return (Status);
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
PgmProcessIPRequest(
|
||
IN ULONG IOControlCode,
|
||
IN PVOID pInBuffer,
|
||
IN ULONG InBufferLen,
|
||
OUT PVOID *pOutBuffer,
|
||
IN OUT ULONG *pOutBufferLen
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs IOCTL queries into IP
|
||
|
||
Arguments:
|
||
|
||
IOControlCode - Ioctl to be made into IP
|
||
pInBuffer - Buffer containing data to be passed into IP
|
||
InBufferLen - Length of Input Buffer data
|
||
pOutBuffer - Returned information
|
||
pOutBufferLen - Initial expected length of Output Buffer + final length
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the operation
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
HANDLE hIP;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
UNICODE_STRING ucDeviceName;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
ULONG OutBufferLen = 0;
|
||
KAPC_STATE ApcState;
|
||
BOOLEAN fAttached;
|
||
HANDLE Event = NULL;
|
||
UCHAR *pIPInfo = NULL;
|
||
PWSTR pNameIP = L"\\Device\\IP";
|
||
|
||
PAGED_CODE();
|
||
|
||
ucDeviceName.Buffer = pNameIP;
|
||
ucDeviceName.Length = (USHORT) (sizeof (WCHAR) * wcslen (pNameIP));
|
||
ucDeviceName.MaximumLength = ucDeviceName.Length + sizeof (WCHAR);
|
||
|
||
if (pOutBuffer)
|
||
{
|
||
ASSERT (pOutBufferLen);
|
||
OutBufferLen = *pOutBufferLen; // Save the initial buffer length
|
||
*pOutBuffer = NULL;
|
||
*pOutBufferLen = 0; // Initialize the return parameter in case we fail below
|
||
|
||
if (!OutBufferLen ||
|
||
!(pIPInfo = PgmAllocMem (OutBufferLen, PGM_TAG('I'))))
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmProcessIPRequest",
|
||
"STATUS_INSUFFICIENT_RESOURCES\n");
|
||
|
||
return (STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
}
|
||
|
||
InitializeObjectAttributes (&ObjectAttributes,
|
||
&ucDeviceName,
|
||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||
NULL,
|
||
NULL);
|
||
|
||
PgmAttachFsp (&ApcState, &fAttached, REF_FSP_PROCESS_IP_REQUEST);
|
||
|
||
Status = ZwCreateFile (&hIP,
|
||
SYNCHRONIZE | GENERIC_READ,
|
||
&ObjectAttributes,
|
||
&IoStatusBlock,
|
||
NULL,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
0,
|
||
FILE_OPEN,
|
||
0,
|
||
NULL,
|
||
0);
|
||
|
||
//
|
||
// If we succeeded above, let us also try to create the Event handle
|
||
//
|
||
if ((NT_SUCCESS (Status)) &&
|
||
(!NT_SUCCESS (Status = ZwCreateEvent(&Event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))))
|
||
{
|
||
ZwClose (hIP);
|
||
}
|
||
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
PgmDetachFsp (&ApcState, &fAttached, REF_FSP_PROCESS_IP_REQUEST);
|
||
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmProcessIPRequest",
|
||
"status=<%x> -- ZwCreate\n", Status);
|
||
|
||
if (pIPInfo)
|
||
{
|
||
PgmFreeMem (pIPInfo);
|
||
}
|
||
return (Status);
|
||
}
|
||
|
||
//
|
||
// At this point, we have succeeded in creating the hIP and Event handles,
|
||
// and possibly also the output buffer memory (pIPInfo)
|
||
//
|
||
do
|
||
{
|
||
Status = ZwDeviceIoControlFile(hIP, // g_hIPDriverHandle
|
||
Event,
|
||
NULL,
|
||
NULL,
|
||
&IoStatusBlock,
|
||
IOControlCode, // Ioctl
|
||
pInBuffer,
|
||
InBufferLen,
|
||
pIPInfo,
|
||
OutBufferLen);
|
||
|
||
if (Status == STATUS_PENDING)
|
||
{
|
||
Status = NtWaitForSingleObject (Event, FALSE, NULL);
|
||
ASSERT(Status == STATUS_SUCCESS);
|
||
}
|
||
|
||
Status = IoStatusBlock.Status;
|
||
if (Status == STATUS_BUFFER_OVERFLOW)
|
||
{
|
||
if (!OutBufferLen)
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmProcessIPRequest",
|
||
"IOControlCode=<%x> => overflow when no data expected\n", IOControlCode);
|
||
|
||
Status = STATUS_UNSUCCESSFUL;
|
||
break;
|
||
}
|
||
|
||
PgmFreeMem (pIPInfo);
|
||
OutBufferLen *=2;
|
||
if (NULL == (pIPInfo = PgmAllocMem (OutBufferLen, PGM_TAG('I'))))
|
||
{
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
}
|
||
else if (NT_SUCCESS(Status))
|
||
{
|
||
PgmLog (PGM_LOG_INFORM_PATH, DBG_TDI, "PgmProcessIPRequest",
|
||
"Success, Ioctl=<%x>\n", IOControlCode);
|
||
}
|
||
else
|
||
{
|
||
PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmProcessIPRequest",
|
||
"IOCTL=<%x> returned Status=<%x>\n", IOControlCode, Status);
|
||
}
|
||
} while (Status == STATUS_BUFFER_OVERFLOW);
|
||
|
||
ZwClose (Event);
|
||
ZwClose (hIP);
|
||
PgmDetachFsp (&ApcState, &fAttached, REF_FSP_PROCESS_IP_REQUEST);
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
if ((pOutBuffer) && (pOutBufferLen))
|
||
{
|
||
*pOutBuffer = pIPInfo;
|
||
*pOutBufferLen = OutBufferLen;
|
||
}
|
||
else if (pIPInfo)
|
||
{
|
||
PgmFreeMem (pIPInfo);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (pIPInfo)
|
||
{
|
||
PgmFreeMem (pIPInfo);
|
||
}
|
||
}
|
||
|
||
return (Status);
|
||
}
|
||
|
||
|