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.
558 lines
14 KiB
558 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1989-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
session.c
|
|
|
|
Abstract:
|
|
|
|
Implement TDI_ASSOCIATE_ADDRESS, TDI_DISASSOCIATE_ADDRESS, Create connection/ Close Connection
|
|
|
|
Author:
|
|
|
|
Jiandong Ruan
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "session.tmh"
|
|
|
|
NTSTATUS
|
|
DisAssociateAddress(
|
|
PSMB_CONNECT ConnectObject
|
|
);
|
|
|
|
PSMB_CONNECT
|
|
SmbVerifyAndReferenceConnect(
|
|
PFILE_OBJECT FileObject,
|
|
SMB_REF_CONTEXT ctx
|
|
)
|
|
{
|
|
PSMB_CONNECT ConnectObject;
|
|
KIRQL Irql;
|
|
|
|
//
|
|
// Rdr could issue request at DISPATCH level, we'd better use spinlock instead of resource lock.
|
|
//
|
|
SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
|
|
if (FileObject->FsContext2 != UlongToPtr(SMB_TDI_CONNECT)) {
|
|
ConnectObject = NULL;
|
|
} else {
|
|
ConnectObject = (PSMB_CONNECT)FileObject->FsContext;
|
|
SmbReferenceConnect(ConnectObject, ctx);
|
|
}
|
|
SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
|
|
|
|
return ConnectObject;
|
|
}
|
|
|
|
VOID
|
|
SmbDeleteConnect(PSMB_CONNECT ob)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Kill a ConnectObject
|
|
This routine will be called when the last reference is removed from the ob.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KIRQL Irql;
|
|
|
|
SMB_ACQUIRE_SPINLOCK(ob->Device, Irql);
|
|
ASSERT(EntryIsInList(&ob->Device->PendingDeleteConnectionList, &ob->Linkage));
|
|
RemoveEntryList(&ob->Linkage);
|
|
SMB_RELEASE_SPINLOCK(ob->Device, Irql);
|
|
|
|
if (ob->PartialMdl) {
|
|
IoFreeMdl(ob->PartialMdl);
|
|
ob->PartialMdl = NULL;
|
|
}
|
|
|
|
SmbPrint(SMB_TRACE_CALL, ("SmbDeleteConnect: free connect %p\n", ob));
|
|
_delete_ConnectObject(ob);
|
|
}
|
|
|
|
void
|
|
SmbReuseConnectObject(PSMB_CONNECT ConnectObject)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SMB_PENDING_MAX; i++) {
|
|
ASSERT (ConnectObject->PendingIRPs[i] == NULL);
|
|
ConnectObject->PendingIRPs[i] = NULL;
|
|
}
|
|
|
|
ConnectObject->BytesReceived = 0;
|
|
ConnectObject->BytesSent = 0;
|
|
ConnectObject->BytesInXport = 0;
|
|
ConnectObject->CurrentPktLength = 0;
|
|
ConnectObject->BytesRemaining = 0;
|
|
ConnectObject->ClientIrp = NULL;
|
|
ConnectObject->ClientMdl = NULL;
|
|
ConnectObject->DpcRequestQueued = FALSE;
|
|
ConnectObject->BytesInIndicate = 0;
|
|
ConnectObject->HeaderBytesRcved = 0;
|
|
ConnectObject->ClientBufferSize = 0;
|
|
ConnectObject->FreeBytesInMdl = 0;
|
|
ConnectObject->StateRcvHandler = WaitingHeader;
|
|
ConnectObject->HeaderBytesRcved = 0;
|
|
|
|
ResetDisconnectOriginator(ConnectObject);
|
|
#ifdef ENABLE_RCV_TRACE
|
|
SmbInitTraceRcv(&ConnectObject->TraceRcv);
|
|
#endif
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbCreateConnection(
|
|
PSMB_DEVICE Device,
|
|
PIRP Irp,
|
|
PFILE_FULL_EA_INFORMATION ea
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a ConnectObject
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
CONNECTION_CONTEXT ClientContext;
|
|
PSMB_CONNECT ConnectObject;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
KIRQL Irql;
|
|
|
|
PAGED_CODE();
|
|
|
|
SmbPrint(SMB_TRACE_CALL, ("Enter SmbCreateConnection\n"));
|
|
if (ea->EaValueLength < sizeof(ClientContext)) {
|
|
ASSERT (0);
|
|
return STATUS_INVALID_ADDRESS_COMPONENT;
|
|
}
|
|
|
|
RtlCopyMemory(&ClientContext, ((PUCHAR)ea->EaName) + ea->EaNameLength + 1, sizeof(ClientContext));
|
|
|
|
ConnectObject = _new_ConnectObject();
|
|
if (NULL == ConnectObject) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
RtlZeroMemory(ConnectObject, sizeof(ConnectObject[0]));
|
|
|
|
SmbInitializeObject((PSMB_OBJECT)ConnectObject, TAG_CONNECT_OBJECT, (PSMB_OBJECT_CLEANUP)SmbDeleteConnect);
|
|
KeInitializeDpc(&ConnectObject->SmbHeaderDpc, (PKDEFERRED_ROUTINE)SmbGetHeaderDpc, ConnectObject);
|
|
|
|
//
|
|
// Reserved resource for getting smb header so that we don't need to worry about
|
|
// the annoying insufficient error later.
|
|
//
|
|
ASSERT(ConnectObject->PartialMdl == NULL);
|
|
ConnectObject->PartialMdl = IoAllocateMdl(
|
|
&ConnectObject->IndicateBuffer, // fake address.
|
|
SMB_MAX_SESSION_PACKET,
|
|
FALSE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if (ConnectObject->PartialMdl == NULL) {
|
|
_delete_ConnectObject(ConnectObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
ConnectObject->Device = Device;
|
|
|
|
KeInitializeSpinLock(&ConnectObject->Lock);
|
|
ConnectObject->ClientContext = ClientContext;
|
|
ConnectObject->ClientObject = NULL;
|
|
ConnectObject->TcpContext = NULL;
|
|
InitializeListHead(&ConnectObject->RcvList);
|
|
|
|
ConnectObject->State = SMB_IDLE;
|
|
|
|
ConnectObject->BytesReceived = 0;
|
|
ConnectObject->BytesSent = 0;
|
|
ConnectObject->BytesInXport = 0;
|
|
ConnectObject->CurrentPktLength = 0;
|
|
ConnectObject->BytesRemaining = 0;
|
|
|
|
SmbInitTraceRcv(&ConnectObject->TraceRcv);
|
|
|
|
SMB_ACQUIRE_SPINLOCK(Device, Irql);
|
|
InsertTailList(&Device->UnassociatedConnectionList, &ConnectObject->Linkage);
|
|
SMB_RELEASE_SPINLOCK(Device, Irql);
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
IrpSp->FileObject->FsContext = ConnectObject;
|
|
IrpSp->FileObject->FsContext2 = UlongToPtr(SMB_TDI_CONNECT);
|
|
|
|
SmbPrint(SMB_TRACE_CALL, ("Leave SmbCreateConnection: new Connect %p\n", ConnectObject));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbAssociateAddress(
|
|
PSMB_DEVICE Device,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TDI_ASSOCIATE_ADDRESS
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PSMB_CONNECT ConnectObject = NULL;
|
|
PSMB_CLIENT_ELEMENT ClientObject = NULL;
|
|
HANDLE AddressHandle;
|
|
PFILE_OBJECT AddressObject = NULL;
|
|
NTSTATUS status;
|
|
KIRQL Irql;
|
|
extern POBJECT_TYPE *IoFileObjectType;
|
|
|
|
PAGED_CODE();
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
AddressHandle = ((PTDI_REQUEST_KERNEL_ASSOCIATE)(&IrpSp->Parameters))->AddressHandle;
|
|
if (NULL == AddressHandle) {
|
|
ASSERT(0);
|
|
return STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
ConnectObject = SmbVerifyAndReferenceConnect(IrpSp->FileObject, SMB_REF_ASSOCIATE);
|
|
if (NULL == ConnectObject) {
|
|
ASSERT(0);
|
|
return STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
SmbPrint(SMB_TRACE_CALL, ("SmbAssociateAddress: connect %p\n", ConnectObject));
|
|
|
|
status = ObReferenceObjectByHandle(
|
|
AddressHandle,
|
|
FILE_READ_DATA,
|
|
*IoFileObjectType,
|
|
Irp->RequestorMode,
|
|
&AddressObject,
|
|
NULL
|
|
);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
ClientObject = SmbVerifyAndReferenceClient(AddressObject, SMB_REF_ASSOCIATE);
|
|
if (NULL == ClientObject) {
|
|
ASSERT(0);
|
|
SmbDereferenceConnect(ConnectObject, SMB_REF_ASSOCIATE);
|
|
return STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
ASSERT(ConnectObject->TcpContext == NULL);
|
|
|
|
//
|
|
// We need to hold acqure 3 locks here because we need to
|
|
// 1. remove ConnectObject from Device->UnassociatedConnectionList
|
|
// 2. insert ConnectObject into ClientObject->AssociatedConnectionList
|
|
// 3. update ConnectObject->ClientObject
|
|
//
|
|
SMB_ACQUIRE_SPINLOCK(Device, Irql);
|
|
SMB_ACQUIRE_SPINLOCK_DPC(ClientObject);
|
|
SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
|
|
|
|
if (IsAssociated(ConnectObject)) {
|
|
status = STATUS_INVALID_HANDLE;
|
|
goto cleanup1;
|
|
}
|
|
|
|
ASSERT(EntryIsInList(&Device->UnassociatedConnectionList, &ConnectObject->Linkage));
|
|
ASSERT(EntryIsInList(&Device->ClientList, &ClientObject->Linkage));
|
|
|
|
ConnectObject->ClientObject = ClientObject;
|
|
RemoveEntryList(&ConnectObject->Linkage);
|
|
InsertTailList(&ClientObject->AssociatedConnection, &ConnectObject->Linkage);
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
|
|
SMB_RELEASE_SPINLOCK_DPC(ClientObject);
|
|
SMB_RELEASE_SPINLOCK(Device, Irql);
|
|
|
|
SmbDereferenceConnect(ConnectObject, SMB_REF_ASSOCIATE);
|
|
|
|
//
|
|
// We're done, release the reference
|
|
//
|
|
ObDereferenceObject(AddressObject);
|
|
return status;
|
|
|
|
cleanup1:
|
|
SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
|
|
SMB_RELEASE_SPINLOCK_DPC(ClientObject);
|
|
SMB_RELEASE_SPINLOCK(Device, Irql);
|
|
|
|
cleanup:
|
|
if (AddressObject) {
|
|
ObDereferenceObject(AddressObject);
|
|
AddressObject = NULL;
|
|
}
|
|
if (ConnectObject) SmbDereferenceConnect(ConnectObject, SMB_REF_ASSOCIATE);
|
|
if (ClientObject) SmbDereferenceClient(ClientObject, SMB_REF_ASSOCIATE);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DisAssociateAddress(
|
|
PSMB_CONNECT ConnectObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine do the disassociation stuff. It can be called from
|
|
1. TDI_DISASSOCIATE_ADDRESS
|
|
2. SmbCloseConnection
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KIRQL Irql;
|
|
PSMB_CLIENT_ELEMENT ClientObject;
|
|
PSMB_DEVICE Device;
|
|
|
|
PAGED_CODE();
|
|
|
|
SmbDoDisconnect(ConnectObject);
|
|
|
|
if (SMB_IDLE != ConnectObject->State) {
|
|
ASSERT(0);
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
ClientObject = InterlockedExchangePointer(&ConnectObject->ClientObject, NULL);
|
|
if (NULL == ClientObject) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Remove the ConnectObject from the list in ClientObject
|
|
//
|
|
SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
|
|
SMB_ACQUIRE_SPINLOCK_DPC(ClientObject);
|
|
SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
|
|
|
|
ASSERT (EntryIsInList(&ClientObject->AssociatedConnection, &ConnectObject->Linkage));
|
|
ASSERT (ConnectObject->TcpContext == NULL);
|
|
|
|
ConnectObject->ClientObject = NULL;
|
|
|
|
//
|
|
// Disassociate the ConnectObject with the ClientObject
|
|
//
|
|
RemoveEntryList(&ConnectObject->Linkage);
|
|
InitializeListHead(&ConnectObject->Linkage);
|
|
Device = ConnectObject->Device;
|
|
|
|
SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
|
|
SMB_RELEASE_SPINLOCK_DPC(ClientObject);
|
|
SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
|
|
|
|
//
|
|
// Put the ConnectObject back into the Device->UnassociatedConnectionList
|
|
//
|
|
SMB_ACQUIRE_SPINLOCK(Device, Irql);
|
|
InsertTailList(&Device->UnassociatedConnectionList, &ConnectObject->Linkage);
|
|
SMB_RELEASE_SPINLOCK(Device, Irql);
|
|
|
|
SmbDereferenceClient(ClientObject, SMB_REF_ASSOCIATE);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbDisAssociateAddress(
|
|
PSMB_DEVICE Device,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TDI_DISASSOCIATE_ADDRESS
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_INVALID_HANDLE If the connection FileObject is corrupted.
|
|
|
|
STATUS_INVALID_DEVICE_REQUEST the connection object is not in assocated state or
|
|
it is not in disconnected state (SMB_IDLE).
|
|
|
|
STATUS_SUCCESS success
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PSMB_CONNECT ConnectObject;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ConnectObject = SmbVerifyAndReferenceConnect(IrpSp->FileObject, SMB_REF_ASSOCIATE);
|
|
if (NULL == ConnectObject) {
|
|
ASSERT(0);
|
|
return STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
SmbPrint(SMB_TRACE_CALL, ("SmbDisAssociateAddress: connect %p\n", ConnectObject));
|
|
|
|
if (IsDisAssociated(ConnectObject)) {
|
|
ASSERT(0);
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
status = DisAssociateAddress(ConnectObject);
|
|
|
|
ASSERT(status != STATUS_PENDING);
|
|
SmbDereferenceConnect(ConnectObject, SMB_REF_ASSOCIATE);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbListen(
|
|
PSMB_DEVICE Device,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TDI_LISTEN
|
|
SRV is not using this. Postpone the implementation.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
SmbPrint(SMB_TRACE_CALL, ("SmbListen\n"));
|
|
ASSERT(0);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbAccept(
|
|
PSMB_DEVICE Device,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TDI_ACCEPT
|
|
SRV is not using this. Postpone the implementation.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
SmbPrint(SMB_TRACE_CALL, ("SmbAccept\n"));
|
|
ASSERT(0);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbCloseConnection(
|
|
PSMB_DEVICE Device,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine close a connection.
|
|
|
|
A connection should be in disconnected state before it can be closed.
|
|
|
|
Note: it is unnecessary for a TDI client to disassociate the connection
|
|
endpoint from its associated transport address before making a
|
|
close-connection-endpoint request. If necessary, we should simulate
|
|
the effects of a disassociation.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_INVALID_HANDLE If the connection FileObject is corrupted.
|
|
|
|
STATUS_INVALID_DEVICE_REQUEST the connection object is not in disconnected state.
|
|
|
|
STATUS_SUCCESS Success
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
KIRQL Irql;
|
|
PSMB_CONNECT ConnectObject;
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IrpSp->FileObject->FsContext2 != UlongToPtr(SMB_TDI_CONNECT)) {
|
|
ASSERT (0);
|
|
return STATUS_INTERNAL_ERROR;
|
|
}
|
|
|
|
//
|
|
// Invalidate FsContext2 so that the object cannot be used anymore.
|
|
//
|
|
SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
|
|
IrpSp->FileObject->FsContext2 = UlongToPtr(SMB_TDI_INVALID);
|
|
SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
|
|
|
|
if (NULL == IrpSp->FileObject->FsContext) {
|
|
ASSERT(0);
|
|
return STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
ConnectObject = (PSMB_CONNECT)IrpSp->FileObject->FsContext;
|
|
|
|
SmbPrint(SMB_TRACE_CALL, ("SmbCloseConnection: Connect %p\n", ConnectObject));
|
|
|
|
DisAssociateAddress(ConnectObject);
|
|
|
|
SMB_ACQUIRE_SPINLOCK(Device, Irql);
|
|
|
|
ASSERT(EntryIsInList(&Device->UnassociatedConnectionList, &ConnectObject->Linkage));
|
|
|
|
RemoveEntryList(&ConnectObject->Linkage);
|
|
InsertTailList(&Device->PendingDeleteConnectionList, &ConnectObject->Linkage);
|
|
|
|
SMB_RELEASE_SPINLOCK(Device, Irql);
|
|
|
|
SmbDereferenceConnect(ConnectObject, SMB_REF_CREATE);
|
|
|
|
IrpSp->FileObject->FsContext = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|