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);
|
|||
|
}
|
|||
|
|
|||
|
|