1003 lines
31 KiB
C
1003 lines
31 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Tdihndlr.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file contains code relating to manipulation of address objects
|
|||
|
that is specific to the NT operating system. It creates address endpoints
|
|||
|
with the transport provider.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jim Stewart (Jimst) 10-2-92
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma CTEMakePageable(PAGE, NbtTdiOpenAddress)
|
|||
|
#pragma CTEMakePageable(PAGE, NbtTdiOpenControl)
|
|||
|
#pragma CTEMakePageable(PAGE, SetEventHandler)
|
|||
|
#pragma CTEMakePageable(PAGE, SubmitTdiRequest)
|
|||
|
#endif
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
NbtTdiOpenAddress (
|
|||
|
OUT PHANDLE pHandle,
|
|||
|
OUT PDEVICE_OBJECT *ppDeviceObject,
|
|||
|
OUT PFILE_OBJECT *ppFileObject,
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN USHORT PortNumber,
|
|||
|
IN ULONG IpAddress,
|
|||
|
IN ULONG Flags
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Note: This synchronous call may take a number of seconds. It runs in
|
|||
|
the context of the caller. The code Opens an Address object with the
|
|||
|
transport provider and then sets up event handlers for Receive,
|
|||
|
Disconnect, Datagrams and Errors.
|
|||
|
|
|||
|
THIS ROUTINE MUST BE CALLED IN THE CONTEXT OF THE FSP (I.E.
|
|||
|
PROBABLY AN EXECUTIVE WORKER THREAD).
|
|||
|
|
|||
|
The address data structures are found in tdi.h , but they are rather
|
|||
|
confusing since the definitions have been spread across several data types.
|
|||
|
This section shows the complete data type for Ip address:
|
|||
|
|
|||
|
typedef struct
|
|||
|
{
|
|||
|
int TA_AddressCount;
|
|||
|
struct _TA_ADDRESS
|
|||
|
{
|
|||
|
USHORT AddressType;
|
|||
|
USHORT AddressLength;
|
|||
|
struct _TDI_ADDRESS_IP
|
|||
|
{
|
|||
|
USHORT sin_port;
|
|||
|
USHORT in_addr;
|
|||
|
UCHAR sin_zero[8];
|
|||
|
} TDI_ADDRESS_IP
|
|||
|
|
|||
|
} TA_ADDRESS[AddressCount];
|
|||
|
|
|||
|
} TRANSPORT_ADDRESS
|
|||
|
|
|||
|
An EA buffer is allocated (for the IRP), with an EA name of "TransportAddress"
|
|||
|
and value is a structure of type TRANSPORT_ADDRESS.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
OBJECT_ATTRIBUTES AddressAttributes;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
PFILE_FULL_EA_INFORMATION EaBuffer;
|
|||
|
NTSTATUS status, locstatus;
|
|||
|
PWSTR pNameTcp=L"Tcp";
|
|||
|
PWSTR pNameUdp=L"Udp";
|
|||
|
UNICODE_STRING ucDeviceName;
|
|||
|
PTRANSPORT_ADDRESS pTransAddressEa;
|
|||
|
PTRANSPORT_ADDRESS pTransAddr;
|
|||
|
TDI_ADDRESS_IP IpAddr;
|
|||
|
BOOLEAN Attached = FALSE;
|
|||
|
PFILE_OBJECT pFileObject;
|
|||
|
HANDLE FileHandle;
|
|||
|
ULONG i, NumAddresses, EaBufferSize;
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
*ppFileObject = NULL;
|
|||
|
*ppDeviceObject = NULL;
|
|||
|
// copy device name into the unicode string - either Udp or Tcp
|
|||
|
//
|
|||
|
if (Flags & TCP_FLAG)
|
|||
|
{
|
|||
|
status = CreateDeviceString(pNameTcp,&ucDeviceName);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
status = CreateDeviceString(pNameUdp,&ucDeviceName);
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
NumAddresses = 1 + pDeviceContext->NumAdditionalIpAddresses;
|
|||
|
EaBufferSize = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
|||
|
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
|||
|
sizeof(TRANSPORT_ADDRESS) +
|
|||
|
NumAddresses*sizeof(TDI_ADDRESS_IP);
|
|||
|
|
|||
|
EaBuffer = NbtAllocMem (EaBufferSize, NBT_TAG('j'));
|
|||
|
if (EaBuffer == NULL)
|
|||
|
{
|
|||
|
DbgPrint ("Nbt.NbtTdiOpenAddress: FAILed to allocate memory for Eabuffer");
|
|||
|
CTEMemFree(ucDeviceName.Buffer);
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
// allocate Memory for the transport address
|
|||
|
//
|
|||
|
pTransAddr = NbtAllocMem (sizeof(TRANSPORT_ADDRESS)+NumAddresses*sizeof(TDI_ADDRESS_IP),NBT_TAG('k'));
|
|||
|
if (pTransAddr == NULL)
|
|||
|
{
|
|||
|
CTEMemFree(ucDeviceName.Buffer);
|
|||
|
CTEMemFree(EaBuffer);
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
EaBuffer->NextEntryOffset = 0;
|
|||
|
EaBuffer->Flags = 0;
|
|||
|
EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
|||
|
EaBuffer->EaValueLength = (USHORT)(sizeof(TRANSPORT_ADDRESS) -1 + NumAddresses*sizeof(TDI_ADDRESS_IP));
|
|||
|
RtlMoveMemory (EaBuffer->EaName, TdiTransportAddress, EaBuffer->EaNameLength+1); // "TransportAddress"
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("EaValueLength = %d\n",EaBuffer->EaValueLength));
|
|||
|
|
|||
|
// fill in the IP address and Port number
|
|||
|
//
|
|||
|
pTransAddressEa = (TRANSPORT_ADDRESS *)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
|
|||
|
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
//
|
|||
|
// For message-mode, open the ANY address regardless of what is passed in
|
|||
|
// This gives us an adapter independent handle
|
|||
|
//
|
|||
|
if (IsDeviceNetbiosless(pDeviceContext))
|
|||
|
{
|
|||
|
IpAddress = IP_ANY_ADDRESS;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
IpAddr.sin_port = htons(PortNumber); // put in network order
|
|||
|
IpAddr.in_addr = htonl(IpAddress);
|
|||
|
|
|||
|
// zero fill the last component of the IP address
|
|||
|
//
|
|||
|
RtlFillMemory((PVOID)&IpAddr.sin_zero, sizeof(IpAddr.sin_zero), 0);
|
|||
|
|
|||
|
// copy the ip address to the end of the structure
|
|||
|
//
|
|||
|
RtlMoveMemory(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;
|
|||
|
|
|||
|
for (i=0; i<pDeviceContext->NumAdditionalIpAddresses; i++)
|
|||
|
{
|
|||
|
IpAddr.sin_port = htons(PortNumber); // put in network order
|
|||
|
IpAddr.in_addr = htonl(pDeviceContext->AdditionalIpAddresses[i]);
|
|||
|
|
|||
|
// copy the ip address to the structure
|
|||
|
RtlMoveMemory(pTransAddr->Address[i+1].Address, (CONST PVOID)&IpAddr, sizeof(IpAddr));
|
|||
|
pTransAddr->Address[i+1].AddressLength = sizeof(TDI_ADDRESS_IP);
|
|||
|
pTransAddr->Address[i+1].AddressType = TDI_ADDRESS_TYPE_IP;
|
|||
|
}
|
|||
|
|
|||
|
pTransAddr->TAAddressCount = NumAddresses;
|
|||
|
|
|||
|
// copy the ip address to the end of the name in the EA structure
|
|||
|
//
|
|||
|
RtlMoveMemory((PVOID)pTransAddressEa,
|
|||
|
(CONST PVOID)pTransAddr,
|
|||
|
NumAddresses*sizeof(TDI_ADDRESS_IP) + sizeof(TRANSPORT_ADDRESS)-1);
|
|||
|
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("creating Address named %ws\n",ucDeviceName.Buffer));
|
|||
|
|
|||
|
#ifdef HDL_FIX
|
|||
|
InitializeObjectAttributes (&AddressAttributes,
|
|||
|
&ucDeviceName,
|
|||
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
#else
|
|||
|
InitializeObjectAttributes (&AddressAttributes,
|
|||
|
&ucDeviceName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
#endif // HDL_FIX
|
|||
|
|
|||
|
status = ZwCreateFile (&FileHandle,
|
|||
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
|||
|
&AddressAttributes,
|
|||
|
&IoStatusBlock,
|
|||
|
NULL,
|
|||
|
FILE_ATTRIBUTE_NORMAL,
|
|||
|
(PortNumber)? 0: FILE_SHARE_READ | FILE_SHARE_WRITE, // bug 296639: allow sharing for port 0
|
|||
|
FILE_OPEN_IF,
|
|||
|
0,
|
|||
|
(PVOID)EaBuffer,
|
|||
|
sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
|||
|
EaBuffer->EaNameLength + 1 +
|
|||
|
EaBuffer->EaValueLength);
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t===><%x>\tNbtTdiOpenAddress->ZwCreateFile, Status = <%x>\n", FileHandle, status));
|
|||
|
|
|||
|
CTEMemFree((PVOID)pTransAddr);
|
|||
|
CTEMemFree((PVOID)EaBuffer);
|
|||
|
CTEMemFree(ucDeviceName.Buffer);
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
// if the ZwCreate passed set the status to the IoStatus
|
|||
|
status = IoStatusBlock.Status;
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Nbt.NbtTdiOpenAddress: Failed to Open the Address to the transport, status = %X\n",
|
|||
|
status));
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
// dereference the file object to keep the device ptr around to avoid
|
|||
|
// this dereference at run time
|
|||
|
//
|
|||
|
status = ObReferenceObjectByHandle (FileHandle,
|
|||
|
(ULONG)0,
|
|||
|
0,
|
|||
|
KernelMode,
|
|||
|
(PVOID *)&pFileObject,
|
|||
|
NULL);
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t ++<%x>====><%x>\tNbtTdiOpenAddress->ObReferenceObjectByHandle, Status = <%x>\n", FileHandle, pFileObject, status));
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
// return the handle to the caller
|
|||
|
//
|
|||
|
*pHandle = FileHandle;
|
|||
|
//
|
|||
|
// return the parameter to the caller
|
|||
|
//
|
|||
|
*ppFileObject = pFileObject;
|
|||
|
*ppDeviceObject = IoGetRelatedDeviceObject(*ppFileObject);
|
|||
|
|
|||
|
status = SetEventHandler (*ppDeviceObject,
|
|||
|
*ppFileObject,
|
|||
|
TDI_EVENT_ERROR,
|
|||
|
(PVOID)TdiErrorHandler,
|
|||
|
(PVOID)pDeviceContext);
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
// if this is a TCP address being opened, then create different
|
|||
|
// event handlers for connections
|
|||
|
//
|
|||
|
if (Flags & TCP_FLAG)
|
|||
|
{
|
|||
|
status = SetEventHandler (*ppDeviceObject,
|
|||
|
*ppFileObject,
|
|||
|
TDI_EVENT_RECEIVE,
|
|||
|
(PVOID)TdiReceiveHandler,
|
|||
|
(PVOID)pDeviceContext);
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
status = SetEventHandler (*ppDeviceObject,
|
|||
|
*ppFileObject,
|
|||
|
TDI_EVENT_DISCONNECT,
|
|||
|
(PVOID)TdiDisconnectHandler,
|
|||
|
(PVOID)pDeviceContext);
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
// only set a connect handler if the session flag is set.
|
|||
|
// In this case the address being opened is the Netbios session
|
|||
|
// port 139
|
|||
|
//
|
|||
|
if (Flags & SESSION_FLAG)
|
|||
|
{
|
|||
|
status = SetEventHandler (*ppDeviceObject,
|
|||
|
*ppFileObject,
|
|||
|
TDI_EVENT_CONNECT,
|
|||
|
(PVOID)TdiConnectHandler,
|
|||
|
(PVOID)pDeviceContext);
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
return(status);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
return(status);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Datagram ports only need this event handler
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
if (PortNumber == pDeviceContext->DatagramPort)
|
|||
|
#else
|
|||
|
if (PortNumber == NBT_DATAGRAM_UDP_PORT)
|
|||
|
#endif
|
|||
|
{
|
|||
|
// Datagram Udp Handler
|
|||
|
status = SetEventHandler (*ppDeviceObject,
|
|||
|
*ppFileObject,
|
|||
|
TDI_EVENT_RECEIVE_DATAGRAM,
|
|||
|
(PVOID)TdiRcvDatagramHandler,
|
|||
|
(PVOID)pDeviceContext);
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
return(status);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Name Service Udp handler
|
|||
|
status = SetEventHandler (*ppDeviceObject,
|
|||
|
*ppFileObject,
|
|||
|
TDI_EVENT_RECEIVE_DATAGRAM,
|
|||
|
(PVOID)TdiRcvNameSrvHandler,
|
|||
|
(PVOID)pDeviceContext);
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
return(status);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// ERROR Case
|
|||
|
//
|
|||
|
ObDereferenceObject(pFileObject);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t --< ><====<%x>\tNbtTdiOpenAddress->ObDereferenceObject\n", pFileObject));
|
|||
|
|
|||
|
locstatus = ZwClose(FileHandle);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t<===<%x>\tNbtTdiOpenAddress1->ZwClose, status = <%x>\n", FileHandle, locstatus));
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Failed Open Address (Dereference Object) status = %X\n", status));
|
|||
|
|
|||
|
locstatus = ZwClose(FileHandle);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t<===<%x>\tNbtTdiOpenAddress2->ZwClose, status = <%x>\n", FileHandle, locstatus));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Nbt.NbtTdiOpenAddress: ZwCreateFile Failed, status = %X\n", status));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
NbtTdiOpenControl (
|
|||
|
IN tDEVICECONTEXT *pDeviceContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine opens a control object with the transport. It is very similar
|
|||
|
to opening an address object, above.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
NTSTATUS Status, locstatus;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
PWSTR pName=L"Tcp";
|
|||
|
PFILE_FULL_EA_INFORMATION EaBuffer;
|
|||
|
UNICODE_STRING DeviceName;
|
|||
|
BOOLEAN Attached = FALSE;
|
|||
|
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
// copy device name into the unicode string
|
|||
|
Status = CreateDeviceString(pName,&DeviceName);
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
#ifdef HDL_FIX
|
|||
|
InitializeObjectAttributes (&ObjectAttributes,
|
|||
|
&DeviceName,
|
|||
|
OBJ_KERNEL_HANDLE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
#else
|
|||
|
InitializeObjectAttributes (&ObjectAttributes,
|
|||
|
&DeviceName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
#endif // HDL_FIX
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Nbt.NbtTdiOpenControl: Tcp device to open = %ws\n", DeviceName.Buffer));
|
|||
|
|
|||
|
EaBuffer = NULL;
|
|||
|
|
|||
|
Status = ZwCreateFile ((PHANDLE)&pDeviceContext->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
|
|||
|
|
|||
|
|
|||
|
CTEMemFree(DeviceName.Buffer);
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t===><%x>\tNbtTdiOpenControl->ZwCreateFile, Status = <%x>\n", pDeviceContext->hControl, Status));
|
|||
|
|
|||
|
if ( NT_SUCCESS( Status ))
|
|||
|
{
|
|||
|
// if the ZwCreate passed set the status to the IoStatus
|
|||
|
Status = IoStatusBlock.Status;
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Nbt:Failed to Open the control connection to the transport, status = %X\n",Status));
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// 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 (pDeviceContext->hControl,
|
|||
|
0L,
|
|||
|
NULL,
|
|||
|
KernelMode,
|
|||
|
(PVOID *)&pDeviceContext->pControlFileObject,
|
|||
|
NULL);
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t ++<%x>====><%x>\tNbtTdiOpenControl->ObReferenceObjectByHandle, Status = <%x>\n", pDeviceContext->hControl, pDeviceContext->pControlFileObject, Status));
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
locstatus = ZwClose(pDeviceContext->hControl);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t<===<%x>\tNbtTdiOpenControl->ZwClose, status = <%x>\n", pDeviceContext->hControl, locstatus));
|
|||
|
pDeviceContext->hControl = NULL;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pDeviceContext->pControlDeviceObject =
|
|||
|
IoGetRelatedDeviceObject(pDeviceContext->pControlFileObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Nbt:Failed to Open the control connection to the transport, status1 = %X\n", Status));
|
|||
|
|
|||
|
// set control file object ptr to null so we know that we didnot open
|
|||
|
// the control point.
|
|||
|
//
|
|||
|
pDeviceContext->pControlFileObject = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
} /* NbtTdiOpenControl */
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
NbtTdiCompletionRoutine(
|
|||
|
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:
|
|||
|
|
|||
|
DeviceObject - unused.
|
|||
|
|
|||
|
Irp - Supplies Irp that the transport has finished processing.
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint( ("Nbt.NbtTdiCompletionRoutine: CompletionEvent: %X, Irp: %X, DeviceObject: %X\n",
|
|||
|
Context, Irp, DeviceObject));
|
|||
|
|
|||
|
KeSetEvent((PKEVENT )Context, 0, FALSE);
|
|||
|
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( DeviceObject );
|
|||
|
UNREFERENCED_PARAMETER( Irp );
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
SetEventHandler (
|
|||
|
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;
|
|||
|
PIRP Irp;
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
Irp = IoAllocateIrp(IoGetRelatedDeviceObject(FileObject)->StackSize, FALSE);
|
|||
|
|
|||
|
if (Irp == NULL)
|
|||
|
{
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
TdiBuildSetEventHandler(Irp, DeviceObject, FileObject,
|
|||
|
NULL, NULL,
|
|||
|
EventType, EventHandler, Context);
|
|||
|
|
|||
|
Status = SubmitTdiRequest(FileObject, Irp);
|
|||
|
|
|||
|
IoFreeIrp(Irp);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
NbtProcessIPRequest(
|
|||
|
IN ULONG IOControlCode,
|
|||
|
IN PVOID pInBuffer,
|
|||
|
IN ULONG InBufferLen,
|
|||
|
OUT PVOID *pOutBuffer,
|
|||
|
IN OUT ULONG *pOutBufferLen
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine performs iIOCTL 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;
|
|||
|
PWSTR pNameIP = L"IP";
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
UCHAR *pIPInfo = NULL;
|
|||
|
ULONG OutBufferLen = 0;
|
|||
|
BOOLEAN fAttached = FALSE;
|
|||
|
HANDLE Event = NULL;
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
|
|||
|
ucDeviceName.Buffer = NULL;
|
|||
|
Status = CreateDeviceString (pNameIP, &ucDeviceName);
|
|||
|
if (!NT_SUCCESS (Status))
|
|||
|
{
|
|||
|
KdPrint (("Nbt.NbtProcessIPRequest: ERROR <%x> -- CreateDeviceString\n", Status));
|
|||
|
return (STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
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 = NbtAllocMem (OutBufferLen, NBT_TAG2('a9'))))
|
|||
|
{
|
|||
|
if (ucDeviceName.Buffer)
|
|||
|
{
|
|||
|
CTEMemFree (ucDeviceName.Buffer);
|
|||
|
}
|
|||
|
KdPrint (("Nbt.NbtProcessIPRequest: ERROR <STATUS_INSUFFICIENT_RESOURCES>\n"));
|
|||
|
return (STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#ifdef HDL_FIX
|
|||
|
InitializeObjectAttributes (&ObjectAttributes,
|
|||
|
&ucDeviceName,
|
|||
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
#else
|
|||
|
InitializeObjectAttributes (&ObjectAttributes,
|
|||
|
&ucDeviceName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
#endif // HDL_FIX
|
|||
|
|
|||
|
CTEAttachFsp(&fAttached, REF_FSP_PROCESS_IP_REQUEST);
|
|||
|
|
|||
|
Status = ZwCreateFile (&hIP,
|
|||
|
SYNCHRONIZE | GENERIC_READ,
|
|||
|
&ObjectAttributes,
|
|||
|
&IoStatusBlock,
|
|||
|
NULL,
|
|||
|
FILE_ATTRIBUTE_NORMAL,
|
|||
|
0,
|
|||
|
FILE_OPEN,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0);
|
|||
|
|
|||
|
CTEMemFree(ucDeviceName.Buffer);
|
|||
|
|
|||
|
//
|
|||
|
// 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))
|
|||
|
{
|
|||
|
CTEDetachFsp(fAttached, REF_FSP_PROCESS_IP_REQUEST);
|
|||
|
KdPrint (("Nbt.NbtProcessIPRequest: ERROR <%x> -- ZwCreate\n", Status));
|
|||
|
if (pIPInfo)
|
|||
|
{
|
|||
|
CTEMemFree (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)
|
|||
|
{
|
|||
|
KdPrint (("Nbt.NbtProcessIPRequest: <%x> => overflow when no data expected\n",IOControlCode));
|
|||
|
Status = STATUS_UNSUCCESSFUL;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
CTEMemFree (pIPInfo);
|
|||
|
OutBufferLen *=2;
|
|||
|
if (NULL == (pIPInfo = NbtAllocMem (OutBufferLen, NBT_TAG2('b0'))))
|
|||
|
{
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
}
|
|||
|
} while (Status == STATUS_BUFFER_OVERFLOW);
|
|||
|
|
|||
|
ZwClose (Event);
|
|||
|
ZwClose (hIP);
|
|||
|
CTEDetachFsp(fAttached, REF_FSP_PROCESS_IP_REQUEST);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_PNP_POWER)
|
|||
|
KdPrint(("Nbt.NbtProcessIPRequest: Success, Ioctl=<%x>\n", IOControlCode));
|
|||
|
|
|||
|
if ((pOutBuffer) && (pOutBufferLen))
|
|||
|
{
|
|||
|
*pOutBuffer = pIPInfo;
|
|||
|
*pOutBufferLen = OutBufferLen;
|
|||
|
}
|
|||
|
else if (pIPInfo)
|
|||
|
{
|
|||
|
CTEMemFree (pIPInfo);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
KdPrint(("Nbt.NbtProcessIPRequest: IOCTL <%x> FAILed <%x>\n", IOControlCode, Status));
|
|||
|
|
|||
|
if (pIPInfo)
|
|||
|
{
|
|||
|
CTEMemFree (pIPInfo);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if FAST_DISP
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
NbtQueryIpHandler(
|
|||
|
IN PFILE_OBJECT FileObject,
|
|||
|
IN ULONG IOControlCode,
|
|||
|
OUT PVOID *EntryPoint
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine iIOCTL queries for fast send entry
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN PFILE_OBJECT FileObject - Supplies the address object's file object.
|
|||
|
IN PLONG EntryPoint - Holder of fast send address
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - Final status of the set event operation
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PIRP Irp;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
IO_STATUS_BLOCK iosb;
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
|
|||
|
if (!(Irp = IoAllocateIrp(IoGetRelatedDeviceObject(FileObject)->StackSize, FALSE)))
|
|||
|
{
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//Build IRP for sync io.
|
|||
|
|
|||
|
Irp->MdlAddress = NULL;
|
|||
|
|
|||
|
Irp->Flags = (LONG)IRP_SYNCHRONOUS_API;
|
|||
|
Irp->RequestorMode = KernelMode;
|
|||
|
Irp->PendingReturned = FALSE;
|
|||
|
|
|||
|
Irp->UserIosb = &iosb;
|
|||
|
|
|||
|
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
|
|||
|
|
|||
|
Irp->AssociatedIrp.SystemBuffer = NULL;
|
|||
|
Irp->UserBuffer = NULL;
|
|||
|
|
|||
|
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
|||
|
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
|||
|
Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
|
|||
|
|
|||
|
Irp->IoStatus.Status = 0;
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
|
|||
|
|
|||
|
irpSp = IoGetNextIrpStackLocation( Irp );
|
|||
|
irpSp->FileObject = FileObject;
|
|||
|
irpSp->DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
|||
|
|
|||
|
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
|||
|
irpSp->MinorFunction = 0;
|
|||
|
irpSp->Parameters.DeviceIoControl.IoControlCode = IOControlCode;
|
|||
|
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = EntryPoint;
|
|||
|
|
|||
|
// Now submit the Irp to know if tcp supports fast path
|
|||
|
|
|||
|
Status = SubmitTdiRequest(FileObject, Irp);
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
*EntryPoint = NULL;
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Nbt.NbtQueryDirectSendEntry: Query failed status %x \n", Status));
|
|||
|
}
|
|||
|
|
|||
|
Irp->UserIosb = NULL;
|
|||
|
IoFreeIrp(Irp);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
SubmitTdiRequest (
|
|||
|
IN PFILE_OBJECT FileObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine submits a request to TDI and waits for it to complete.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN PFILE_OBJECT FileObject - Connection or Address handle for TDI request
|
|||
|
IN PIRP Irp - TDI request to submit.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - Final status of request.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KEVENT Event;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
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(Irp,
|
|||
|
(PIO_COMPLETION_ROUTINE)NbtTdiCompletionRoutine,
|
|||
|
(PVOID)&Event,
|
|||
|
TRUE, TRUE, TRUE);
|
|||
|
|
|||
|
CHECK_COMPLETION(Irp);
|
|||
|
Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
|
|||
|
|
|||
|
//
|
|||
|
// If it failed immediately, return now, otherwise wait.
|
|||
|
//
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Nbt.SubmitTdiRequest: Failed to Submit Tdi Request, status = %X\n",Status));
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if (Status == STATUS_PENDING)
|
|||
|
{
|
|||
|
|
|||
|
Status = KeWaitForSingleObject ((PVOID)&Event, // Object to wait on.
|
|||
|
Executive, // Reason for waiting
|
|||
|
KernelMode, // Processor mode
|
|||
|
FALSE, // Alertable
|
|||
|
NULL); // Timeout
|
|||
|
ASSERT(Status == STATUS_SUCCESS);
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Nbt.SubmitTdiRequest: Failed on return from KeWaitForSingleObj, status = %X\n",
|
|||
|
Status));
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
Status = Irp->IoStatus.Status;
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Nbt.SubmitTdiRequest: Io Status from setting event = %X\n",Status));
|
|||
|
}
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|