|
|
/*++
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); }
|