Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

929 lines
25 KiB

/*++
Copyright (c) 1989-2001 Microsoft Corporation
Module Name:
conncache.c
Abstract:
This module implement the cache for TCP connection object
Author:
Jiandong Ruan
Revision History:
--*/
#include "precomp.h"
#include "conncache.tmh"
NTSTATUS
SmbInitTCP(
PSMB_TCP_INFO TcpInfo
);
PVOID
SmbQueryTcpHandler(
IN PFILE_OBJECT FileObject
);
VOID
SmbDestroyTcpContext(
PSMB_TCP_CONTEXT TcpCtx
);
#pragma alloc_text(PAGE, SmbShutdownTCP)
#pragma alloc_text(PAGE, SmbQueryTcpHandler)
#pragma alloc_text(PAGE, SmbSendIoctl)
#pragma alloc_text(PAGE, SmbInitTCP)
#pragma alloc_text(PAGE, SmbInitTCP4)
#pragma alloc_text(PAGE, SmbInitTCP6)
#pragma alloc_text(PAGE, SmbAllocateOutbound)
PVOID
SmbQueryTcpHandler(
IN PFILE_OBJECT FileObject
)
/*++
Routine Description:
(Lifted from NBT4)
This routine iIOCTL queries for fast send entry
With fast routine, we can directly call TCP and avoid the overhead with IO manager
Arguments:
IN PFILE_OBJECT FileObject - Supplies the address object's file object.
Return Value:
NULL if fail
otherwise the fast routine of the underlying transport.
--*/
{
NTSTATUS status;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
IO_STATUS_BLOCK iosb;
PDEVICE_OBJECT DeviceObject;
PVOID EntryPoint = NULL;
IN ULONG IOControlCode;
PAGED_CODE();
IOControlCode = IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER;
DeviceObject = IoGetRelatedDeviceObject(FileObject);
Irp = SmbAllocIrp(DeviceObject->StackSize);
if (NULL == Irp) {
return NULL;
}
//
// 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 = DeviceObject;
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 = SubmitSynchTdiRequest(FileObject, Irp);
Irp->UserIosb = NULL;
SmbFreeIrp(Irp);
if (!NT_SUCCESS(status)) {
EntryPoint = NULL;
SmbTrace (SMB_TRACE_TCP, ("return %!status!", status));
SmbPrint (SMB_TRACE_TCP, ("SmbQueryTcpHandler return 0x%08lx\n", status));
}
return EntryPoint;
}
NTSTATUS
SmbSendIoctl(
PFILE_OBJECT FileObject,
ULONG Ioctl,
PVOID InBuf,
ULONG InBufSize,
PVOID OutBuf,
ULONG *OutBufSize
)
{
PDEVICE_OBJECT DeviceObject;
ULONG OutBufSize2;
PIRP Irp;
IO_STATUS_BLOCK iosb;
NTSTATUS status;
KEVENT Event;
PAGED_CODE();
if (NULL == FileObject) {
SmbPrint(SMB_TRACE_TCP, ("SmbSendIoctl returns STATUS_INVALID_PARAMETER on NULL device object\n"));
SmbTrace(SMB_TRACE_TCP, ("returns STATUS_INVALID_PARAMETER on NULL device object"));
return STATUS_INVALID_PARAMETER;
}
DeviceObject = IoGetRelatedDeviceObject(FileObject);
if (NULL == OutBuf) {
ASSERT(OutBufSize == NULL);
OutBufSize2 = 0;
} else {
if (NULL == OutBufSize || 0 == *OutBufSize) {
ASSERT(0);
SmbPrint(SMB_TRACE_TCP, ("SmbSendIoctl returns STATUS_INVALID_PARAMETER\n"));
SmbTrace(SMB_TRACE_TCP, ("returns STATUS_INVALID_PARAMETER"));
return STATUS_INVALID_PARAMETER;
}
OutBufSize2 = *OutBufSize;
}
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest(
Ioctl,
DeviceObject,
InBuf,
InBufSize,
OutBuf,
OutBufSize2,
FALSE,
&Event,
&iosb
);
if (NULL == Irp) {
SmbPrint(SMB_TRACE_TCP, ("SmbSendIoctl returns STATUS_INSUFFICIENT_RESOURCES\n"));
SmbTrace(SMB_TRACE_TCP, ("returns STATUS_INSUFFICIENT_RESOURCES"));
return STATUS_INSUFFICIENT_RESOURCES;
}
IoGetNextIrpStackLocation(Irp)->FileObject = FileObject;
status = IoCallDriver(DeviceObject, Irp);
//
// If it failed immediately, return now, otherwise wait.
//
if (!NT_SUCCESS(status)) {
SmbPrint(SMB_TRACE_TCP, ("SmbSendIoctl: Failed to Submit Tdi Request, status = 0x%08lx\n", status));
SmbTrace(SMB_TRACE_TCP, ("Failed to Submit Tdi Request, %!status!", status));
return status;
}
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject (
&Event,
Executive,
KernelMode,
FALSE,
NULL
);
if (status != STATUS_WAIT_0) {
ASSERT(0);
SmbTrace(SMB_TRACE_TCP, ("KeWaitForSingleObject return %!status!", status));
return status;
}
status = iosb.Status;
if (NT_SUCCESS(status) && OutBufSize) {
*OutBufSize = (LONG)(iosb.Information);
}
}
SmbPrint(SMB_TRACE_TCP, ("SmbSendIoctl returns status = 0x%08lx\n", status));
SmbTrace(SMB_TRACE_TCP, ("returns %!status!", status));
return (status);
}
NTSTATUS
SmbFakeFastQuery(
IN PSMB_IP6_ADDRESS Address,
OUT PULONG pIndex,
OUT PULONG pMetric
)
{
return STATUS_NOT_SUPPORTED;
}
VOID
SmbReadTCPConf(
IN HANDLE hKey,
PSMB_TCP_INFO TcpInfo
)
{
TcpInfo->InboundLow = SmbReadULong (
hKey,
SMB_REG_INBOUND_LOW,
SMB_REG_INBOUND_LOW_DEFAULT,
SMB_REG_INBOUND_LOW_MIN
);
TcpInfo->InboundMid = SmbReadULong (
hKey,
SMB_REG_INBOUND_MID,
TcpInfo->InboundLow * 2,
TcpInfo->InboundLow * 2
);
TcpInfo->InboundHigh = SmbReadULong (
hKey,
SMB_REG_INBOUND_HIGH,
TcpInfo->InboundMid * 2,
TcpInfo->InboundMid * 2
);
}
NTSTATUS
SmbInitTCP(
PSMB_TCP_INFO TcpInfo
)
{
PVOID FastQuery;
ULONG Size;
NTSTATUS status;
PAGED_CODE();
//
// Read registry
//
SmbReadTCPConf(SmbCfg.ParametersKey, TcpInfo);
TcpInfo->InboundNumber = 0;
InitializeListHead(&TcpInfo->InboundPool);
InitializeListHead(&TcpInfo->DelayedDestroyList);
KeInitializeSpinLock(&TcpInfo->Lock);
TcpInfo->FastSend = SmbQueryTcpHandler(TcpInfo->TCPControlFileObject);
Size = sizeof(FastQuery);
status = SmbSendIoctl(
TcpInfo->IPControlFileObject,
IOCTL_IP_GET_BESTINTFC_FUNC_ADDR,
NULL,
0,
&FastQuery,
&Size
);
if (STATUS_SUCCESS == status) {
ULONG IfIndex, Metric;
TcpInfo->FastQuery = (PVOID)FastQuery;
status = ((PIP4FASTQUERY)(FastQuery))(ntohl(INADDR_LOOPBACK), &IfIndex, &Metric);
if (status == STATUS_SUCCESS) {
TcpInfo->LoopbackInterfaceIndex = IfIndex;
SmbPrint(SMB_TRACE_TCP, ("Loopback Interface Index = %d\n", IfIndex));
SmbTrace(SMB_TRACE_TCP, ("Loopback Interface Index = %d", IfIndex));
} else {
SmbPrint(SMB_TRACE_TCP, ("Query loopback Interface Index returns 0x%08lx\n", status));
SmbTrace(SMB_TRACE_TCP, ("Query loopback Interface Index returns %!status!", status));
TcpInfo->LoopbackInterfaceIndex = INVALID_INTERFACE_INDEX;
}
} else {
//
// TCP6 doesn't support fast query
//
ASSERT(TcpInfo->IpAddress.sin_family == SMB_AF_INET6);
TcpInfo->FastQuery = (PVOID)SmbFakeFastQuery;
TcpInfo->LoopbackInterfaceIndex = INVALID_INTERFACE_INDEX;
}
//
// Initialize inbound
//
SmbInitTcpAddress(&TcpInfo->InboundAddressObject);
status = SmbOpenTcpAddress(
&TcpInfo->IpAddress,
TcpInfo->Port,
&TcpInfo->InboundAddressObject
);
BAIL_OUT_ON_ERROR(status);
status = SmbSetTcpEventHandlers(
TcpInfo->InboundAddressObject.AddressObject,
TcpInfo->TdiEventContext
);
BAIL_OUT_ON_ERROR(status);
return status;
cleanup:
if (TcpInfo->InboundAddressObject.AddressHandle) {
SmbCloseAddress(&TcpInfo->InboundAddressObject);
}
return status;
}
NTSTATUS
SmbInitTCP4(
PSMB_TCP_INFO TcpInfo,
USHORT Port,
PVOID TdiEventContext
)
{
NTSTATUS status;
UNICODE_STRING ucName;
PAGED_CODE();
if (SmbCfg.Tcp4Available) {
return STATUS_SUCCESS;
}
RtlZeroMemory(TcpInfo, sizeof(TcpInfo[0]));
RtlInitUnicodeString(&ucName, DD_TCP_DEVICE_NAME);
status = IoGetDeviceObjectPointer(
&ucName,
FILE_READ_DATA| FILE_WRITE_DATA,
&TcpInfo->TCPControlFileObject,
&TcpInfo->TCPControlDeviceObject
);
BAIL_OUT_ON_ERROR(status);
RtlInitUnicodeString(&ucName, DD_IP_DEVICE_NAME);
status = IoGetDeviceObjectPointer(
&ucName,
FILE_READ_DATA| FILE_WRITE_DATA,
&TcpInfo->IPControlFileObject,
&TcpInfo->IPControlDeviceObject
);
BAIL_OUT_ON_ERROR(status);
TcpInfo->TcpStackSize = TcpInfo->TCPControlDeviceObject->StackSize;
//
// Bind to any address
//
TcpInfo->IpAddress.sin_family = SMB_AF_INET;
TcpInfo->IpAddress.ip4.sin4_addr = htonl(INADDR_ANY);
TcpInfo->Port = htons(Port);
TcpInfo->TdiEventContext = TdiEventContext;
status = SmbInitTCP(TcpInfo);
BAIL_OUT_ON_ERROR(status);
ASSERT (TcpInfo->LoopbackInterfaceIndex != INVALID_INTERFACE_INDEX);
status = SmbSetTcpInfo (
TcpInfo->InboundAddressObject.AddressObject,
CO_TL_ENTITY,
INFO_CLASS_PROTOCOL,
AO_OPTION_IFLIST,
INFO_TYPE_ADDRESS_OBJECT,
(ULONG) TRUE
);
status = SmbSetTcpInfo (
TcpInfo->InboundAddressObject.AddressObject,
CO_TL_ENTITY,
INFO_CLASS_PROTOCOL,
AO_OPTION_ADD_IFLIST,
INFO_TYPE_ADDRESS_OBJECT,
TcpInfo->LoopbackInterfaceIndex
);
if (SmbCfg.SmbDeviceObject->DeviceObject.StackSize < SmbCfg.SmbDeviceObject->Tcp4.TcpStackSize + 1) {
SmbCfg.SmbDeviceObject->DeviceObject.StackSize = SmbCfg.SmbDeviceObject->Tcp4.TcpStackSize + 1;
}
SmbCfg.Tcp4Available = TRUE;
return STATUS_SUCCESS;
cleanup:
if (TcpInfo->TCPControlFileObject) {
ObDereferenceObject(TcpInfo->TCPControlFileObject);
TcpInfo->TCPControlDeviceObject = NULL;
TcpInfo->TCPControlFileObject = NULL;
}
if (TcpInfo->IPControlFileObject) {
ObDereferenceObject(TcpInfo->IPControlFileObject);
TcpInfo->IPControlDeviceObject = NULL;
TcpInfo->IPControlFileObject = NULL;
}
SmbPrint(SMB_TRACE_TCP, ("SmbInitTCP4 returns 0x%08lx\n", status));
SmbTrace(SMB_TRACE_TCP, ("returns %!status!", status));
return status;
}
NTSTATUS
SmbInitTCP6(
PSMB_TCP_INFO TcpInfo,
USHORT Port,
PVOID TdiEventContext
)
{
NTSTATUS status;
UNICODE_STRING ucName;
PAGED_CODE();
if (SmbCfg.Tcp6Available) {
return STATUS_SUCCESS;
}
RtlZeroMemory(TcpInfo, sizeof(TcpInfo[0]));
RtlInitUnicodeString(&ucName, DD_TCPV6_DEVICE_NAME);
status = IoGetDeviceObjectPointer(
&ucName,
FILE_READ_DATA| FILE_WRITE_DATA,
&TcpInfo->TCPControlFileObject,
&TcpInfo->TCPControlDeviceObject
);
BAIL_OUT_ON_ERROR(status);
RtlInitUnicodeString(&ucName, DD_IPV6_DEVICE_NAME);
status = IoGetDeviceObjectPointer(
&ucName,
FILE_READ_DATA| FILE_WRITE_DATA,
&TcpInfo->IPControlFileObject,
&TcpInfo->IPControlDeviceObject
);
BAIL_OUT_ON_ERROR(status);
TcpInfo->TcpStackSize = TcpInfo->TCPControlDeviceObject->StackSize;
//
// Bind to any address
//
TcpInfo->IpAddress.sin_family = SMB_AF_INET6;
ip6addr_getany(&TcpInfo->IpAddress.ip6);
hton_ip6addr(&TcpInfo->IpAddress.ip6);
TcpInfo->Port = htons(Port);
TcpInfo->TdiEventContext = TdiEventContext;
status = SmbInitTCP(TcpInfo);
BAIL_OUT_ON_ERROR(status);
if (SmbCfg.SmbDeviceObject->DeviceObject.StackSize < SmbCfg.SmbDeviceObject->Tcp6.TcpStackSize + 1) {
SmbCfg.SmbDeviceObject->DeviceObject.StackSize = SmbCfg.SmbDeviceObject->Tcp6.TcpStackSize + 1;
}
SmbCfg.Tcp6Available = TRUE;
return status;
cleanup:
if (TcpInfo->TCPControlFileObject) {
ObDereferenceObject(TcpInfo->TCPControlFileObject);
TcpInfo->TCPControlDeviceObject = NULL;
TcpInfo->TCPControlFileObject = NULL;
}
if (TcpInfo->IPControlFileObject) {
ObDereferenceObject(TcpInfo->IPControlFileObject);
TcpInfo->IPControlDeviceObject = NULL;
TcpInfo->IPControlFileObject = NULL;
}
SmbPrint(SMB_TRACE_TCP, ("SmbInitTCP6 returns 0x%08lx\n", status));
SmbTrace(SMB_TRACE_TCP, ("returns %!status!", status));
return status;
}
VOID
SmbDestroyTcpContext(
PSMB_TCP_CONTEXT TcpCtx
)
{
NTSTATUS localstatus;
BOOL Attached;
PAGED_CODE();
ATTACH_FSP(Attached);
if (TcpCtx->Connect.ConnectHandle) {
localstatus = SmbCloseTcpConnection(&TcpCtx->Connect);
ASSERT(localstatus == STATUS_SUCCESS);
}
if (TcpCtx->Address.AddressHandle) {
localstatus = SmbCloseAddress(&TcpCtx->Address);
ASSERT(localstatus == STATUS_SUCCESS);
}
DETACH_FSP(Attached);
SmbInitTcpContext(TcpCtx);
_delete_TcpContext(TcpCtx);
}
VOID
SmbDelayedDestroyTcpContext(
PSMB_TCP_CONTEXT TcpCtx
)
{
KIRQL Irql;
PSMB_TCP_INFO TcpInfo = NULL;
if (NULL == TcpCtx) {
return;
}
TcpInfo = TcpCtx->CacheOwner;
SMB_ACQUIRE_SPINLOCK(TcpInfo, Irql);
ASSERT(!EntryIsInList(&TcpInfo->InboundPool, &TcpCtx->Linkage));
InsertTailList(&TcpInfo->DelayedDestroyList, &TcpCtx->Linkage);
SMB_RELEASE_SPINLOCK(TcpInfo, Irql);
SmbWakeupWorkerThread(SmbCfg.SmbDeviceObject);
}
NTSTATUS
SmbShutdownTCP(
PSMB_TCP_INFO TcpInfo
)
{
BOOL Attached;
NTSTATUS localstatus;
PLIST_ENTRY entry;
PSMB_TCP_CONTEXT TcpCtx;
PAGED_CODE();
ASSERT(SmbCfg.Unloading);
ATTACH_FSP(Attached);
//
// No lock is needed for shutdown
//
//
// Clean up inbound
//
while (!IsListEmpty(&TcpInfo->InboundPool)) {
entry = RemoveHeadList(&TcpInfo->InboundPool);
TcpInfo->InboundNumber--;
ASSERT ((TcpInfo->InboundNumber == 0 && IsListEmpty(&TcpInfo->InboundPool)) ||
(TcpInfo->InboundNumber != 0 && !IsListEmpty(&TcpInfo->InboundPool)));
TcpCtx = CONTAINING_RECORD(entry, SMB_TCP_CONTEXT, Linkage);
ASSERT(TcpCtx->Address.AddressHandle == NULL);
ASSERT(TcpCtx->Connect.ConnectHandle);
SmbDestroyTcpContext(TcpCtx);
}
localstatus = SmbCloseAddress(&TcpInfo->InboundAddressObject);
ASSERT(localstatus == STATUS_SUCCESS);
DETACH_FSP(Attached);
if (TcpInfo->TCPControlFileObject) {
ObDereferenceObject(TcpInfo->TCPControlFileObject);
TcpInfo->TCPControlDeviceObject = NULL;
TcpInfo->TCPControlFileObject = NULL;
}
if (TcpInfo->IPControlFileObject) {
ObDereferenceObject(TcpInfo->IPControlFileObject);
TcpInfo->IPControlDeviceObject = NULL;
TcpInfo->IPControlFileObject = NULL;
}
return STATUS_SUCCESS;
}
NTSTATUS
SmbSynchConnCache(
PSMB_TCP_INFO TcpInfo,
BOOL Cleanup
)
/*++
Routine Description:
This routine bring the number of TCP connection object back to normal
Arguments:
Return Value:
--*/
{
KIRQL Irql;
PLIST_ENTRY entry;
PSMB_TCP_CONTEXT TcpCtx;
NTSTATUS status, localstatus;
BOOL Attached;
LONG Target;
PAGED_CODE();
ASSERT(TcpInfo->InboundNumber >= 0);
ATTACH_FSP(Attached);
Target = (Cleanup)?0: TcpInfo->InboundMid;
if (Cleanup || TcpInfo->InboundNumber >= TcpInfo->InboundHigh) {
//
// Bring it back to Middle
//
while (!SmbCfg.Unloading) {
SMB_ACQUIRE_SPINLOCK(TcpInfo, Irql);
if (TcpInfo->InboundNumber <= Target) {
SMB_RELEASE_SPINLOCK(TcpInfo, Irql);
break;
}
ASSERT (!IsListEmpty(&TcpInfo->InboundPool));
entry = RemoveHeadList(&TcpInfo->InboundPool);
TcpInfo->InboundNumber--;
ASSERT ((TcpInfo->InboundNumber == 0 && IsListEmpty(&TcpInfo->InboundPool)) ||
(TcpInfo->InboundNumber != 0 && !IsListEmpty(&TcpInfo->InboundPool)));
SMB_RELEASE_SPINLOCK(TcpInfo, Irql);
TcpCtx = CONTAINING_RECORD(entry, SMB_TCP_CONTEXT, Linkage);
ASSERT(TcpCtx->Address.AddressHandle == NULL);
ASSERT(TcpCtx->Connect.ConnectHandle);
SmbDestroyTcpContext(TcpCtx);
}
}
if (!Cleanup && TcpInfo->InboundNumber <= TcpInfo->InboundLow) {
//
// Bring it back to Middle
//
while(!SmbCfg.Unloading && TcpInfo->InboundNumber < TcpInfo->InboundMid) {
TcpCtx = _new_TcpContext();
if (NULL == TcpCtx) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
SmbInitTcpContext(TcpCtx);
status = SmbOpenTcpConnection(
&TcpInfo->InboundAddressObject,
&TcpCtx->Connect,
&TcpCtx->Connect
);
if (status != STATUS_SUCCESS) {
_delete_TcpContext(TcpCtx);
goto cleanup;
}
SMB_ACQUIRE_SPINLOCK(TcpInfo, Irql);
InsertTailList(&TcpInfo->InboundPool, &TcpCtx->Linkage);
TcpInfo->InboundNumber++;
SMB_RELEASE_SPINLOCK(TcpInfo, Irql);
}
}
status = STATUS_SUCCESS;
cleanup:
while(1) {
SMB_ACQUIRE_SPINLOCK(TcpInfo, Irql);
if (IsListEmpty(&TcpInfo->DelayedDestroyList)) {
SMB_RELEASE_SPINLOCK(TcpInfo, Irql);
break;
}
entry = RemoveHeadList(&TcpInfo->DelayedDestroyList);
SMB_RELEASE_SPINLOCK(TcpInfo, Irql);
TcpCtx = CONTAINING_RECORD(entry, SMB_TCP_CONTEXT, Linkage);
SmbDestroyTcpContext(TcpCtx);
}
DETACH_FSP(Attached);
return status;
}
PSMB_TCP_CONTEXT
SmbAllocateOutbound(
PSMB_TCP_INFO TcpInfo
)
{
PSMB_TCP_CONTEXT TcpCtx = NULL;
NTSTATUS status = STATUS_SUCCESS;
NTSTATUS localstatus = STATUS_SUCCESS;
PAGED_CODE();
TcpCtx = _new_TcpContext();
if (NULL == TcpCtx) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
SmbInitTcpContext(TcpCtx);
status = SmbOpenTcpAddress(
&TcpInfo->IpAddress,
0,
&TcpCtx->Address
);
if (STATUS_SUCCESS != status) {
goto cleanup;
}
status = SmbSetTcpEventHandlers(
TcpCtx->Address.AddressObject,
TcpInfo->TdiEventContext
);
if (STATUS_SUCCESS != status) {
localstatus = SmbCloseAddress(&TcpCtx->Address);
ASSERT(localstatus == STATUS_SUCCESS);
goto cleanup;
}
status = SmbOpenTcpConnection(
&TcpCtx->Address,
&TcpCtx->Connect,
&TcpCtx->Connect
);
if (STATUS_SUCCESS != status) {
localstatus = SmbCloseAddress(&TcpCtx->Address);
ASSERT(localstatus == STATUS_SUCCESS);
goto cleanup;
}
TcpCtx->CacheOwner = TcpInfo;
cleanup:
if (STATUS_SUCCESS != status) {
if (TcpCtx) {
_delete_TcpContext(TcpCtx);
TcpCtx = NULL;
}
}
return TcpCtx;
}
VOID
SmbFreeOutbound(
PSMB_TCP_CONTEXT TcpCtx
)
{
SmbDelayedDestroyTcpContext(TcpCtx);
}
PSMB_TCP_CONTEXT
SmbAllocateInbound(
PSMB_TCP_INFO TcpInfo
)
{
KIRQL Irql;
BOOL WakeupWorker = TRUE;
PLIST_ENTRY entry = NULL;
PSMB_TCP_CONTEXT TcpCtx = NULL;
ASSERT(TcpInfo->InboundNumber >= 0);
SMB_ACQUIRE_SPINLOCK(TcpInfo, Irql);
if (TcpInfo->InboundNumber > 0) {
entry = RemoveHeadList(&TcpInfo->InboundPool);
TcpInfo->InboundNumber--;
ASSERT ((TcpInfo->InboundNumber == 0 && IsListEmpty(&TcpInfo->InboundPool)) ||
(TcpInfo->InboundNumber != 0 && !IsListEmpty(&TcpInfo->InboundPool)));
}
WakeupWorker = (TcpInfo->InboundNumber <= TcpInfo->InboundLow);
SMB_RELEASE_SPINLOCK(TcpInfo, Irql);
if (WakeupWorker) {
SmbWakeupWorkerThread(SmbCfg.SmbDeviceObject);
}
if (entry == NULL) {
return NULL;
}
TcpCtx = CONTAINING_RECORD(entry, SMB_TCP_CONTEXT, Linkage);
TcpCtx->CacheOwner = TcpInfo;
ASSERT(!ValidTcpAddress(&TcpCtx->Address));
ASSERT(ValidTcpConnect(&TcpCtx->Connect));
return TcpCtx;
}
VOID
SmbFreeInbound(
PSMB_TCP_CONTEXT TcpCtx
)
{
KIRQL Irql;
PSMB_TCP_INFO TcpInfo;
BOOL WakeupWorker;
if (NULL == TcpCtx) {
return;
}
ASSERT(!ValidTcpAddress(&TcpCtx->Address));
ASSERT(ValidTcpConnect(&TcpCtx->Connect));
TcpInfo = TcpCtx->CacheOwner;
ASSERT(TcpInfo->InboundNumber >= 0);
SMB_ACQUIRE_SPINLOCK(TcpInfo, Irql);
ASSERT(!EntryIsInList(&TcpInfo->InboundPool, &TcpCtx->Linkage));
InsertTailList(&TcpInfo->InboundPool, &TcpCtx->Linkage);
TcpInfo->InboundNumber++;
WakeupWorker = (TcpInfo->InboundNumber >= TcpInfo->InboundHigh);
SMB_RELEASE_SPINLOCK(TcpInfo, Irql);
if (WakeupWorker) {
SmbWakeupWorkerThread(SmbCfg.SmbDeviceObject);
}
}
VOID
SmbFreeTcpContext(
PSMB_TCP_CONTEXT TcpCtx
)
{
if (NULL == TcpCtx) {
return;
}
if (TcpCtx->Address.AddressHandle) {
SmbFreeOutbound(TcpCtx);
} else {
SmbFreeInbound(TcpCtx);
}
}
VOID
PoolWorker(
IN PSMB_DEVICE DeviceObject,
IN PIO_WORKITEM WorkItem
)
{
NTSTATUS status;
PAGED_CODE();
IoFreeWorkItem(WorkItem);
//
// Allow to fire anoter thread
//
InterlockedExchange(&DeviceObject->ConnectionPoolWorkerQueued, FALSE);
if (SmbCfg.Unloading) {
return;
}
if (SmbCfg.Tcp6Available) {
status = SmbSynchConnCache(&DeviceObject->Tcp6,
DeviceObject->DeviceRegistrationHandle == NULL);
}
if (SmbCfg.Tcp4Available) {
status = SmbSynchConnCache(&DeviceObject->Tcp4,
DeviceObject->DeviceRegistrationHandle == NULL);
}
}
NTSTATUS
SmbWakeupWorkerThread(
IN PSMB_DEVICE DeviceObject
)
{
PIO_WORKITEM WorkItem;
LONG Queued;
Queued = InterlockedExchange(&DeviceObject->ConnectionPoolWorkerQueued, TRUE);
if (Queued == FALSE) {
WorkItem = IoAllocateWorkItem(&DeviceObject->DeviceObject);
if (NULL == WorkItem) {
InterlockedExchange(&DeviceObject->ConnectionPoolWorkerQueued, FALSE);
//
// This is not a critical error.
//
return STATUS_INSUFFICIENT_RESOURCES;
}
IoQueueWorkItem(
WorkItem,
(PIO_WORKITEM_ROUTINE)PoolWorker,
DelayedWorkQueue,
WorkItem
);
}
return STATUS_SUCCESS;
}