2033 lines
53 KiB
C
2033 lines
53 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
connect.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code which defines the NetBIOS driver's
|
||
connection block.
|
||
|
||
Author:
|
||
|
||
Colin Watson (ColinW) 13-Mar-1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "nb.h"
|
||
//#include <zwapi.h>
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, NbCall)
|
||
#pragma alloc_text(PAGE, NbListen)
|
||
#pragma alloc_text(PAGE, NbCallCommon)
|
||
#pragma alloc_text(PAGE, NbOpenConnection)
|
||
#pragma alloc_text(PAGE, NewCb)
|
||
#pragma alloc_text(PAGE, CloseConnection)
|
||
#endif
|
||
|
||
LARGE_INTEGER Timeout = { 0xffffffff, 0xffffffff};
|
||
|
||
NTSTATUS
|
||
NbCall(
|
||
IN PDNCB pdncb,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to make a VC.
|
||
|
||
Arguments:
|
||
|
||
pdncb - Pointer to the NCB.
|
||
|
||
Irp - Pointer to the request packet representing the I/O request.
|
||
|
||
IrpSp - Pointer to current IRP stack frame.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFCB pfcb = IrpSp->FileObject->FsContext2;
|
||
PCB pcb;
|
||
PPCB ppcb;
|
||
|
||
PAGED_CODE();
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint(( "\n****** Start of NbCall ****** pdncb %lx\n", pdncb ));
|
||
}
|
||
|
||
LOCK_RESOURCE( pfcb );
|
||
|
||
ppcb = NbCallCommon( pdncb, IrpSp );
|
||
|
||
if ( ppcb == NULL ) {
|
||
//
|
||
// The error has been stored in the copy of the NCB. Return
|
||
// success so the NCB gets copied back.
|
||
//
|
||
UNLOCK_RESOURCE( pfcb );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
pcb = *ppcb;
|
||
|
||
pcb->Status = CALL_PENDING;
|
||
if (( pdncb->ncb_command & ~ASYNCH ) == NCBCALL ) {
|
||
PTA_NETBIOS_ADDRESS pConnectBlock =
|
||
ExAllocatePoolWithTag ( NonPagedPool, sizeof(TA_NETBIOS_ADDRESS), 'ySBN');
|
||
PTDI_ADDRESS_NETBIOS temp;
|
||
|
||
if ( pConnectBlock == NULL ) {
|
||
NCB_COMPLETE( pdncb, NRC_SYSTEM );
|
||
(*ppcb)->DisconnectReported = TRUE;
|
||
CleanupCb( ppcb, NULL );
|
||
UNLOCK_RESOURCE( pfcb );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
pConnectBlock->TAAddressCount = 1;
|
||
pConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
||
pConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
|
||
temp = pConnectBlock->Address[0].Address;
|
||
|
||
temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
RtlMoveMemory( temp->NetbiosName, pdncb->ncb_callname, NCBNAMSZ );
|
||
|
||
//
|
||
// Post a TdiConnect to the server. This may take a long time so return
|
||
// STATUS_PENDING so that the application thread gets free again if
|
||
// it specified ASYNC.
|
||
//
|
||
|
||
pdncb->Information.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
|
||
sizeof (TDI_ADDRESS_NETBIOS);
|
||
pdncb->Information.RemoteAddress = pConnectBlock;
|
||
} else {
|
||
// XNS NETONE name call
|
||
PTA_NETONE_ADDRESS pConnectBlock =
|
||
ExAllocatePoolWithTag ( NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
|
||
sizeof (TDI_ADDRESS_NETONE), 'xSBN' );
|
||
|
||
PTDI_ADDRESS_NETONE temp;
|
||
|
||
if ( pConnectBlock == NULL ) {
|
||
NCB_COMPLETE( pdncb, NRC_SYSTEM );
|
||
(*ppcb)->DisconnectReported = TRUE;
|
||
CleanupCb( ppcb, NULL );
|
||
UNLOCK_RESOURCE( pfcb );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
pConnectBlock->TAAddressCount = 1;
|
||
pConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETONE;
|
||
pConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETONE);
|
||
temp = pConnectBlock->Address[0].Address;
|
||
|
||
temp->NetoneNameType = TDI_ADDRESS_NETONE_TYPE_UNIQUE;
|
||
RtlMoveMemory( &temp->NetoneName[0], pdncb->ncb_callname, NCBNAMSZ );
|
||
|
||
//
|
||
// Post a TdiConnect to the server. This may take a long time so return
|
||
// STATUS_PENDING so that the application thread gets free again if
|
||
// it specified ASYNC.
|
||
//
|
||
|
||
pdncb->Information.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
|
||
sizeof (TDI_ADDRESS_NETONE);
|
||
pdncb->Information.RemoteAddress = pConnectBlock;
|
||
}
|
||
|
||
pdncb->ReturnInformation.RemoteAddress = NULL;
|
||
pdncb->ReturnInformation.RemoteAddressLength = 0;
|
||
|
||
pdncb->Information.UserDataLength = 0;
|
||
pdncb->Information.OptionsLength = 0;
|
||
|
||
TdiBuildConnect (Irp,
|
||
pcb->DeviceObject,
|
||
pcb->ConnectionObject,
|
||
NbCallCompletion,
|
||
pdncb,
|
||
&Timeout, // default timeout
|
||
&pdncb->Information,
|
||
NULL);
|
||
|
||
IoMarkIrpPending( Irp );
|
||
IoCallDriver (pcb->DeviceObject, Irp);
|
||
|
||
//
|
||
// The transport has extracted all information from RequestInformation so we can safely
|
||
// exit the current scope.
|
||
//
|
||
|
||
UNLOCK_RESOURCE( pfcb );
|
||
|
||
return STATUS_PENDING;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
NbCallCompletion(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine completes the Irp after an attempt to perform a TdiConnect
|
||
or TdiListen/TdiAccept has been returned by the transport.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - unused.
|
||
|
||
Irp - Supplies Irp that the transport has finished processing.
|
||
|
||
Context - Supplies the NCB associated with the Irp.
|
||
|
||
Return Value:
|
||
|
||
The final status from the operation (success or an exception).
|
||
|
||
--*/
|
||
{
|
||
PDNCB pdncb = (PDNCB) Context;
|
||
PFCB pfcb = IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext2;
|
||
PPCB ppcb;
|
||
NTSTATUS Status;
|
||
KIRQL OldIrql; // Used when SpinLock held.
|
||
|
||
IF_NBDBG (NB_DEBUG_COMPLETE | NB_DEBUG_CALL) {
|
||
NbPrint( ("NbCallCompletion pdncb: %lx\n" , Context));
|
||
}
|
||
|
||
if ( pdncb->Information.RemoteAddress != NULL ) {
|
||
ExFreePool( pdncb->Information.RemoteAddress );
|
||
pdncb->Information.RemoteAddress = NULL;
|
||
}
|
||
|
||
if ( pdncb->ReturnInformation.RemoteAddress != NULL ) {
|
||
ExFreePool( pdncb->ReturnInformation.RemoteAddress );
|
||
pdncb->ReturnInformation.RemoteAddress = NULL;
|
||
}
|
||
|
||
// Tell application how many bytes were transferred
|
||
pdncb->ncb_length = (unsigned short)Irp->IoStatus.Information;
|
||
|
||
//
|
||
// Tell IopCompleteRequest how much to copy back when the request
|
||
// completes.
|
||
//
|
||
|
||
Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
Status = Irp->IoStatus.Status;
|
||
|
||
LOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
ppcb = FindCb( pfcb, pdncb, FALSE);
|
||
|
||
if (( ppcb == NULL ) ||
|
||
( (*ppcb)->Status == HANGUP_PENDING )) {
|
||
|
||
//
|
||
// The connection has been closed.
|
||
// Repair the Irp so that the NCB gets copied back.
|
||
//
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
Status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
(*ppcb)->Status = SESSION_ESTABLISHED;
|
||
NCB_COMPLETE( pdncb, NRC_GOODRET );
|
||
|
||
} else {
|
||
|
||
//
|
||
// We need to close down the connection but we are at DPC level
|
||
// so tell the dll to insert a hangup.
|
||
//
|
||
|
||
NCB_COMPLETE( pdncb, NbMakeNbError( Irp->IoStatus.Status ) );
|
||
(*ppcb)->Status = SESSION_ABORTED;
|
||
|
||
// repair the Irp so that the NCB gets copied back.
|
||
Irp->IoStatus.Status = STATUS_HANGUP_REQUIRED;
|
||
Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
Status = STATUS_HANGUP_REQUIRED;
|
||
}
|
||
}
|
||
if ( ppcb != NULL ) {
|
||
(*ppcb)->UsersNcb = NULL;
|
||
}
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
IF_NBDBG (NB_DEBUG_COMPLETE | NB_DEBUG_CALL) {
|
||
NbPrint( ("NbCallCompletion exit pdncb: %lx, Status %X\n", pdncb, Status ));
|
||
}
|
||
|
||
|
||
NbCheckAndCompleteIrp32(Irp);
|
||
|
||
//
|
||
// Must return a non-error status otherwise the IO system will not copy
|
||
// back the NCB into the users buffer.
|
||
//
|
||
|
||
return Status;
|
||
|
||
UNREFERENCED_PARAMETER( DeviceObject );
|
||
}
|
||
|
||
NTSTATUS
|
||
NbListen(
|
||
IN PDNCB pdncb,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to make a VC by waiting for a call.
|
||
|
||
Arguments:
|
||
|
||
pdncb - Pointer to the NCB.
|
||
|
||
Irp - Pointer to the request packet representing the I/O request.
|
||
|
||
IrpSp - Pointer to current IRP stack frame.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFCB pfcb = IrpSp->FileObject->FsContext2;
|
||
PCB pcb;
|
||
PPCB ppcb;
|
||
PTA_NETBIOS_ADDRESS pConnectBlock;
|
||
PTDI_ADDRESS_NETBIOS temp;
|
||
|
||
PAGED_CODE();
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint(( "\n****** Start of NbListen ****** pdncb %lx\n", pdncb ));
|
||
}
|
||
|
||
LOCK_RESOURCE( pfcb );
|
||
|
||
ppcb = NbCallCommon( pdncb, IrpSp );
|
||
|
||
if ( ppcb == NULL ) {
|
||
//
|
||
// The error has been stored in the copy of the NCB. Return
|
||
// success so the NCB gets copied back.
|
||
//
|
||
UNLOCK_RESOURCE( pfcb );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
pcb = *ppcb;
|
||
|
||
pcb->Status = LISTEN_OUTSTANDING;
|
||
|
||
//
|
||
// Build the listen. We either need to tell the transport which
|
||
// address we are prepared to accept a call from or we need to
|
||
// supply a buffer for the transport to tell us where the
|
||
// call came from.
|
||
//
|
||
|
||
pConnectBlock = ExAllocatePoolWithTag ( NonPagedPool, sizeof(TA_NETBIOS_ADDRESS), 'zSBN');
|
||
|
||
if ( pConnectBlock == NULL ) {
|
||
NCB_COMPLETE( pdncb, NRC_SYSTEM );
|
||
(*ppcb)->DisconnectReported = TRUE;
|
||
CleanupCb( ppcb, NULL );
|
||
UNLOCK_RESOURCE( pfcb );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
pConnectBlock->TAAddressCount = 1;
|
||
pConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
||
temp = pConnectBlock->Address[0].Address;
|
||
temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
pConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
|
||
|
||
if ( pdncb->ncb_callname[0] == '*' ) {
|
||
// If the name starts with an asterisk then we accept anyone.
|
||
pdncb->ReturnInformation.RemoteAddress = pConnectBlock;
|
||
pdncb->ReturnInformation.RemoteAddressLength =
|
||
sizeof (TRANSPORT_ADDRESS) + sizeof (TDI_ADDRESS_NETBIOS);
|
||
|
||
pdncb->Information.RemoteAddress = NULL;
|
||
pdncb->Information.RemoteAddressLength = 0;
|
||
|
||
} else {
|
||
|
||
RtlMoveMemory( temp->NetbiosName, pdncb->ncb_callname, NCBNAMSZ );
|
||
|
||
pdncb->Information.RemoteAddress = pConnectBlock;
|
||
pdncb->Information.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
|
||
sizeof (TDI_ADDRESS_NETBIOS);
|
||
|
||
pdncb->ReturnInformation.RemoteAddress = NULL;
|
||
pdncb->ReturnInformation.RemoteAddressLength = 0;
|
||
}
|
||
|
||
|
||
//
|
||
// Post a TdiListen to the server. This may take a long time so return
|
||
// STATUS_PENDING so that the application thread gets free again if
|
||
// it specified ASYNC.
|
||
//
|
||
|
||
TdiBuildListen (Irp,
|
||
pcb->DeviceObject,
|
||
pcb->ConnectionObject,
|
||
NbListenCompletion,
|
||
pdncb,
|
||
TDI_QUERY_ACCEPT,
|
||
&pdncb->Information,
|
||
( pdncb->ncb_callname[0] == '*' )? &pdncb->ReturnInformation
|
||
: NULL
|
||
);
|
||
|
||
IoMarkIrpPending( Irp );
|
||
IoCallDriver (pcb->DeviceObject, Irp);
|
||
|
||
UNLOCK_RESOURCE( pfcb );
|
||
|
||
return STATUS_PENDING;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
NbListenCompletion(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when a TdiListen has been returned by the transport.
|
||
We can either reject or accept the call depending on the remote address.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - unused.
|
||
|
||
Irp - Supplies Irp that the transport has finished processing.
|
||
|
||
Context - Supplies the NCB associated with the Irp.
|
||
|
||
Return Value:
|
||
|
||
The final status from the operation (success or an exception).
|
||
|
||
--*/
|
||
{
|
||
PDNCB pdncb = (PDNCB) Context;
|
||
PFCB pfcb = IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext2;
|
||
PCB pcb;
|
||
PPCB ppcb;
|
||
NTSTATUS Status;
|
||
KIRQL OldIrql; // Used when SpinLock held.
|
||
|
||
IF_NBDBG (NB_DEBUG_COMPLETE | NB_DEBUG_CALL) {
|
||
NbPrint( ("NbListenCompletion pdncb: %lx status: %X\n" , Context, Irp->IoStatus.Status));
|
||
}
|
||
|
||
|
||
//
|
||
// bug # : 73260
|
||
//
|
||
// Added check to see if Status is valid
|
||
//
|
||
|
||
if ( NT_SUCCESS( Irp-> IoStatus.Status ) )
|
||
{
|
||
if ( pdncb->Information.RemoteAddress != NULL ) {
|
||
|
||
ExFreePool( pdncb->Information.RemoteAddress );
|
||
pdncb->Information.RemoteAddress = NULL;
|
||
|
||
} else {
|
||
|
||
//
|
||
// This was a listen accepting a call from any address. Return
|
||
// the remote address.
|
||
//
|
||
PTA_NETBIOS_ADDRESS pConnectBlock;
|
||
|
||
ASSERT( pdncb->ReturnInformation.RemoteAddress != NULL );
|
||
|
||
pConnectBlock = pdncb->ReturnInformation.RemoteAddress;
|
||
|
||
RtlMoveMemory(
|
||
pdncb->ncb_callname,
|
||
pConnectBlock->Address[0].Address->NetbiosName,
|
||
NCBNAMSZ );
|
||
|
||
ExFreePool( pdncb->ReturnInformation.RemoteAddress );
|
||
pdncb->ReturnInformation.RemoteAddress = NULL;
|
||
}
|
||
} else {
|
||
if ( pdncb->Information.RemoteAddress != NULL ) {
|
||
ExFreePool( pdncb->Information.RemoteAddress );
|
||
pdncb->Information.RemoteAddress = NULL;
|
||
} else {
|
||
ExFreePool( pdncb->ReturnInformation.RemoteAddress );
|
||
pdncb->ReturnInformation.RemoteAddress = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
LOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
ppcb = FindCb( pfcb, pdncb, FALSE );
|
||
|
||
if (( ppcb == NULL ) ||
|
||
( (*ppcb)->Status == HANGUP_PENDING )) {
|
||
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
//
|
||
// The connection has been closed.
|
||
// Repair the Irp so that the NCB gets copied back.
|
||
//
|
||
|
||
NCB_COMPLETE( pdncb, NRC_NAMERR );
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
Status = STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
//
|
||
// bug # : 70837
|
||
//
|
||
// Added check for cancelled listens
|
||
//
|
||
|
||
else if ( ( (*ppcb)-> Status == SESSION_ABORTED ) ||
|
||
( !NT_SUCCESS( Irp-> IoStatus.Status ) ) )
|
||
{
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
if ( (*ppcb)-> Status == SESSION_ABORTED )
|
||
{
|
||
NCB_COMPLETE( pdncb, NRC_CMDCAN );
|
||
}
|
||
else
|
||
{
|
||
(*ppcb)-> Status = SESSION_ABORTED;
|
||
NCB_COMPLETE( pdncb, NbMakeNbError( Irp->IoStatus.Status ) );
|
||
}
|
||
|
||
//
|
||
// repair the Irp so that the NCB gets copied back.
|
||
// Tell the dll to hangup the connection.
|
||
//
|
||
|
||
Irp->IoStatus.Status = STATUS_HANGUP_REQUIRED;
|
||
Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
Status = STATUS_HANGUP_REQUIRED;
|
||
}
|
||
|
||
else
|
||
{
|
||
PDEVICE_OBJECT DeviceObject;
|
||
|
||
|
||
pcb = *ppcb;
|
||
|
||
DeviceObject = pcb-> DeviceObject;
|
||
|
||
|
||
// Tell application how many bytes were transferred
|
||
pdncb->ncb_length = (unsigned short)Irp->IoStatus.Information;
|
||
|
||
RtlMoveMemory(
|
||
&pcb->RemoteName,
|
||
pdncb->ncb_callname,
|
||
NCBNAMSZ );
|
||
|
||
//
|
||
// Tell IopCompleteRequest how much to copy back when the request
|
||
// completes.
|
||
//
|
||
|
||
Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
|
||
TdiBuildAccept (Irp,
|
||
pcb->DeviceObject,
|
||
pcb->ConnectionObject,
|
||
NbCallCompletion,
|
||
pdncb,
|
||
NULL,
|
||
NULL);
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
IoCallDriver (DeviceObject, Irp);
|
||
|
||
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
|
||
|
||
IF_NBDBG (NB_DEBUG_COMPLETE | NB_DEBUG_CALL) {
|
||
NbPrint( ("NbListenCompletion exit pdncb: %lx, Status: %X\n" , pdncb, Status));
|
||
}
|
||
|
||
if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
|
||
NbCheckAndCompleteIrp32(Irp);
|
||
}
|
||
|
||
//
|
||
// Must return a non-error status otherwise the IO system will not copy
|
||
// back the NCB into the users buffer.
|
||
//
|
||
|
||
return Status;
|
||
UNREFERENCED_PARAMETER( DeviceObject );
|
||
}
|
||
|
||
PPCB
|
||
NbCallCommon(
|
||
IN PDNCB pdncb,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine contains the common components used in creating a
|
||
connection either by a TdiListen or TdiCall.
|
||
|
||
Arguments:
|
||
|
||
pdncb - Pointer to the NCB.
|
||
|
||
IrpSp - Pointer to current IRP stack frame.
|
||
|
||
Return Value:
|
||
|
||
The function value is the address of the pointer in the ConnectionBlocks to
|
||
the connection block for this call.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PPCB ppcb = NULL;
|
||
PCB pcb = NULL;
|
||
PAB pab;
|
||
PPAB ppab;
|
||
PFCB pfcb = IrpSp->FileObject->FsContext2;
|
||
PIRP IIrp;
|
||
KEVENT Event1;
|
||
NTSTATUS Status;
|
||
IO_STATUS_BLOCK Iosb1;
|
||
KAPC_STATE ApcState;
|
||
BOOLEAN ProcessAttached = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Initialize the lsn so that if we return an error and the application
|
||
// ignores it then we will not reuse a valid lsn.
|
||
//
|
||
pdncb->ncb_lsn = 0;
|
||
|
||
ppcb = NewCb( IrpSp, pdncb );
|
||
|
||
if ( ppcb == NULL ) {
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint(( "\n FAILED on create Cb of %s\n", pdncb->ncb_name));
|
||
}
|
||
|
||
return NULL; // NewCb will have filled in the error code.
|
||
}
|
||
|
||
pcb = *ppcb;
|
||
ppab = pcb->ppab;
|
||
pab = *ppab;
|
||
|
||
//
|
||
// Create an event for the synchronous I/O requests that we'll be issuing.
|
||
//
|
||
|
||
KeInitializeEvent (
|
||
&Event1,
|
||
SynchronizationEvent,
|
||
FALSE);
|
||
|
||
//
|
||
// Open the connection on the transport.
|
||
//
|
||
|
||
Status = NbOpenConnection (&pcb->ConnectionHandle, (PVOID*)&pcb->ConnectionObject, pfcb, ppcb, pdncb);
|
||
if (!NT_SUCCESS(Status)) {
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint(( "\n FAILED on open of server Connection: %X ******\n", Status ));
|
||
}
|
||
NCB_COMPLETE( pdncb, NbMakeNbError( Status ) );
|
||
(*ppcb)->DisconnectReported = TRUE;
|
||
CleanupCb( ppcb, NULL );
|
||
return NULL;
|
||
}
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint(( "NbCallCommon: Associate address\n"));
|
||
}
|
||
|
||
pcb->DeviceObject = IoGetRelatedDeviceObject( pcb->ConnectionObject );
|
||
|
||
if (PsGetCurrentProcess() != NbFspProcess) {
|
||
KeStackAttachProcess(NbFspProcess, &ApcState);
|
||
|
||
ProcessAttached = TRUE;
|
||
}
|
||
|
||
IIrp = TdiBuildInternalDeviceControlIrp (
|
||
TDI_ASSOCIATE_ADDRESS,
|
||
pcb->DeviceObject,
|
||
pcb->ConnectionObject,
|
||
&Event1,
|
||
&Iosb1);
|
||
|
||
TdiBuildAssociateAddress (
|
||
IIrp,
|
||
pcb->DeviceObject,
|
||
pcb->ConnectionObject,
|
||
NULL,
|
||
NULL,
|
||
pab->AddressHandle);
|
||
|
||
Status = IoCallDriver (pcb->DeviceObject, IIrp);
|
||
|
||
if (Status == STATUS_PENDING) {
|
||
|
||
//
|
||
// Wait for event to be signalled while ignoring alerts
|
||
//
|
||
|
||
do {
|
||
Status = KeWaitForSingleObject(
|
||
&Event1, Executive, KernelMode, TRUE, NULL
|
||
);
|
||
} while (Status == STATUS_ALERTED);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint(( "\n FAILED Event1 Wait: %X ******\n", Status ));
|
||
}
|
||
NCB_COMPLETE( pdncb, NbMakeNbError( Status ) );
|
||
if (ProcessAttached) {
|
||
KeUnstackDetachProcess(&ApcState);
|
||
}
|
||
(*ppcb)->DisconnectReported = TRUE;
|
||
CleanupCb( ppcb, NULL );
|
||
return NULL;
|
||
}
|
||
Status = Iosb1.Status;
|
||
}
|
||
|
||
if (ProcessAttached) {
|
||
KeUnstackDetachProcess(&ApcState);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint(( "\n AssociateAddress FAILED Status: %X ******\n", Status ));
|
||
}
|
||
NCB_COMPLETE( pdncb, NbMakeNbError( Status ) );
|
||
(*ppcb)->DisconnectReported = TRUE;
|
||
CleanupCb( ppcb, NULL );
|
||
return NULL;
|
||
}
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint(( "NbCallCommon: returning ppcb: %lx\n", ppcb ));
|
||
}
|
||
return ppcb;
|
||
}
|
||
|
||
NTSTATUS
|
||
NbHangup(
|
||
IN PDNCB pdncb,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to hangup a VC. This cancels all receives
|
||
and waits for all pending sends to complete before returning. This
|
||
functionality is offered directly by the underlying TDI driver so
|
||
NetBIOS just passes the Irp down to the transport.
|
||
|
||
Arguments:
|
||
|
||
pdncb - Pointer to the NCB.
|
||
|
||
Irp - Supplies Io request packet describing the Hangup NCB.
|
||
|
||
IrpSp - Pointer to current IRP stack frame.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFCB pfcb = IrpSp->FileObject->FsContext2;
|
||
PPCB ppcb;
|
||
KIRQL OldIrql; // Used when SpinLock held.
|
||
NTSTATUS Status;
|
||
|
||
LOCK( pfcb, OldIrql );
|
||
|
||
pdncb->pfcb = pfcb;
|
||
pdncb->irp = Irp;
|
||
ppcb = FindCb( pfcb, pdncb, FALSE );
|
||
|
||
if ( ppcb == NULL ) {
|
||
NCB_COMPLETE( pdncb, NRC_GOODRET );
|
||
UNLOCK( pfcb, OldIrql );
|
||
return STATUS_SUCCESS; // Connection gone already
|
||
}
|
||
|
||
if ((*ppcb)->Status == SESSION_ESTABLISHED ) {
|
||
NCB_COMPLETE( pdncb, NRC_GOODRET );
|
||
} else {
|
||
if (((*ppcb)->Status == SESSION_ABORTED ) ||
|
||
((*ppcb)->Status == HANGUP_PENDING )) {
|
||
NCB_COMPLETE( pdncb, NRC_SCLOSED );
|
||
} else {
|
||
NCB_COMPLETE( pdncb, NRC_TOOMANY ); // try later
|
||
UNLOCK( pfcb, OldIrql );;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
(*ppcb)->Status = HANGUP_PENDING;
|
||
(*ppcb)->DisconnectReported = TRUE;
|
||
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
Status = CleanupCb( ppcb, pdncb );
|
||
|
||
UNLOCK_RESOURCE( pfcb );
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
NbOpenConnection (
|
||
OUT PHANDLE FileHandle,
|
||
OUT PVOID *Object,
|
||
IN PFCB pfcb,
|
||
IN PVOID ConnectionContext,
|
||
IN PDNCB pdncb
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Makes a call to a remote address.
|
||
Arguments:
|
||
|
||
FileHandle - Pointer to where the handle to the Transport for this virtual
|
||
connection should be stored.
|
||
|
||
*Object - Pointer to where the file object pointer is to be stored
|
||
|
||
pfcb - Supplies the fcb and therefore the DriverName for this lana.
|
||
|
||
ConnectionContext - Supplies the Cb to be used with this connection on
|
||
all indications from the transport. Its actually the address of
|
||
the pcb in the ConnectionBlocks array for this lana.
|
||
|
||
pdncb - Supplies the ncb requesting the new virtual connection.
|
||
|
||
Return Value:
|
||
|
||
Status of the operation.
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
NTSTATUS Status;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
PFILE_FULL_EA_INFORMATION EaBuffer;
|
||
KAPC_STATE ApcState;
|
||
BOOLEAN ProcessAttached = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
InitializeObjectAttributes (
|
||
&ObjectAttributes,
|
||
&pfcb->pDriverName[pdncb->ncb_lana_num],
|
||
0,
|
||
NULL,
|
||
NULL);
|
||
|
||
EaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePoolWithTag (NonPagedPool,
|
||
sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
||
TDI_CONNECTION_CONTEXT_LENGTH + 1 +
|
||
sizeof(CONNECTION_CONTEXT), 'eSBN' );
|
||
if (EaBuffer == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
EaBuffer->NextEntryOffset = 0;
|
||
EaBuffer->Flags = 0;
|
||
EaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
|
||
EaBuffer->EaValueLength = sizeof (CONNECTION_CONTEXT);
|
||
|
||
RtlMoveMemory( EaBuffer->EaName, TdiConnectionContext, EaBuffer->EaNameLength + 1 );
|
||
|
||
RtlMoveMemory (
|
||
&EaBuffer->EaName[EaBuffer->EaNameLength + 1],
|
||
&ConnectionContext,
|
||
sizeof (CONNECTION_CONTEXT));
|
||
|
||
if (PsGetCurrentProcess() != NbFspProcess) {
|
||
KeStackAttachProcess(NbFspProcess, &ApcState);
|
||
|
||
ProcessAttached = TRUE;
|
||
}
|
||
|
||
|
||
IF_NBDBG( NB_DEBUG_CALL )
|
||
{
|
||
NbPrint( (
|
||
"NbOpenConnection: Create file invoked on %d for \n",
|
||
pdncb-> ncb_lana_num
|
||
) );
|
||
|
||
NbFormattedDump( pdncb-> ncb_callname, NCBNAMSZ );
|
||
}
|
||
|
||
Status = ZwCreateFile (
|
||
FileHandle,
|
||
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.
|
||
EaBuffer, // EA buffer.
|
||
sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
||
TDI_CONNECTION_CONTEXT_LENGTH + 1 +
|
||
sizeof(CONNECTION_CONTEXT) ); // EA length.
|
||
|
||
ExFreePool( EaBuffer );
|
||
|
||
if ( NT_SUCCESS( Status )) {
|
||
Status = IoStatusBlock.Status;
|
||
}
|
||
|
||
if (NT_SUCCESS( Status )) {
|
||
Status = ObReferenceObjectByHandle (
|
||
*FileHandle,
|
||
0L,
|
||
NULL,
|
||
KernelMode,
|
||
Object,
|
||
NULL);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
NTSTATUS localstatus;
|
||
|
||
IF_NBDBG( NB_DEBUG_CALL )
|
||
{
|
||
NbPrint( (
|
||
"NbOpenConnection: error : Close file invoked for %d\n",
|
||
pdncb-> ncb_lana_num
|
||
) );
|
||
}
|
||
|
||
localstatus = ZwClose( *FileHandle);
|
||
|
||
ASSERT(NT_SUCCESS(localstatus));
|
||
|
||
*FileHandle = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
if (ProcessAttached) {
|
||
KeUnstackDetachProcess(&ApcState);
|
||
}
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("NbOpenConnection Status:%X, IoStatus:%X.\n", Status, IoStatusBlock.Status));
|
||
}
|
||
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("NbOpenConnection: FAILURE, status code=%X.\n", Status));
|
||
}
|
||
return Status;
|
||
}
|
||
|
||
return Status;
|
||
} /* NbOpenConnection */
|
||
|
||
PPCB
|
||
NewCb(
|
||
IN PIO_STACK_LOCATION IrpSp,
|
||
IN OUT PDNCB pdncb
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
IrpSp - Pointer to current IRP stack frame.
|
||
|
||
pdncb - Supplies the ncb requesting the new virtual connection.
|
||
|
||
Return Value:
|
||
|
||
The address of the pointer to the new Cb in the ConnectionBlocks
|
||
Array.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||
PCB pcb;
|
||
PPCB ppcb = NULL;
|
||
PFCB pfcb = FileObject->FsContext2;
|
||
PLANA_INFO plana;
|
||
int index;
|
||
PPAB ppab;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (pdncb->ncb_lana_num > pfcb->MaxLana ) {
|
||
NCB_COMPLETE( pdncb, NRC_BRIDGE );
|
||
return NULL;
|
||
}
|
||
|
||
if (( pfcb == NULL ) ||
|
||
( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
|
||
( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
if ( pfcb == NULL ) {
|
||
NbPrint( ("NewCb pfcb==NULL\n"));
|
||
} else {
|
||
if ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) {
|
||
NbPrint( ("NewCb pfcb->ppLana[%x]==NULL\n",
|
||
pdncb->ncb_lana_num));
|
||
} else {
|
||
NbPrint( ("NewCb pfcb->ppLana[%x]->Status = %x\n",
|
||
pdncb->ncb_lana_num,
|
||
pfcb->ppLana[pdncb->ncb_lana_num]->Status));
|
||
}
|
||
}
|
||
}
|
||
|
||
NCB_COMPLETE( pdncb, NRC_BRIDGE );
|
||
return NULL;
|
||
}
|
||
plana = pfcb->ppLana[pdncb->ncb_lana_num];
|
||
|
||
if ( plana->ConnectionCount == plana->MaximumConnection ) {
|
||
NCB_COMPLETE( pdncb, NRC_LOCTFUL );
|
||
return NULL;
|
||
}
|
||
|
||
ppab = FindAb( pfcb, pdncb, TRUE );
|
||
|
||
if ( ppab == NULL ) {
|
||
//
|
||
// This application is only allowed to use names that have been
|
||
// addnamed by this application or the special address 0.
|
||
//
|
||
return NULL;
|
||
|
||
}
|
||
|
||
// FindAb has incremented the number of CurrentUsers for this address block.
|
||
|
||
//
|
||
// Find the appropriate session number to use.
|
||
//
|
||
|
||
index = plana->NextConnection;
|
||
while ( plana->ConnectionBlocks[index] != NULL ) {
|
||
index++;
|
||
if ( index > MAXIMUM_CONNECTION ) {
|
||
index = 1;
|
||
}
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("NewCb pfcb: %lx, plana: %lx, index: %lx, ppcb: %lx, pcb: %lx\n",
|
||
pfcb,
|
||
pdncb->ncb_lana_num,
|
||
index,
|
||
&plana->ConnectionBlocks[index],
|
||
plana->ConnectionBlocks[index] ));
|
||
}
|
||
}
|
||
|
||
plana->ConnectionCount++;
|
||
plana->NextConnection = index + 1;
|
||
if ( plana->NextConnection > MAXIMUM_CONNECTION ) {
|
||
plana->NextConnection = 1;
|
||
}
|
||
|
||
//
|
||
// Fill in the LSN so that the application will be able
|
||
// to reference this connection in the future.
|
||
//
|
||
|
||
pdncb->ncb_lsn = (unsigned char)index;
|
||
|
||
ppcb = &plana->ConnectionBlocks[index];
|
||
|
||
*ppcb = pcb = ExAllocatePoolWithTag (NonPagedPool, sizeof(CB), 'cSBN');
|
||
|
||
if (pcb==NULL) {
|
||
|
||
DEREFERENCE_AB(ppab);
|
||
NCB_COMPLETE( pdncb, NbMakeNbError( STATUS_INSUFFICIENT_RESOURCES ) );
|
||
return NULL;
|
||
}
|
||
|
||
pcb->ppab = ppab;
|
||
pcb->ConnectionHandle = NULL;
|
||
pcb->ConnectionObject = NULL;
|
||
pcb->DeviceObject = NULL;
|
||
pcb->pLana = plana;
|
||
pcb->ReceiveIndicated = 0;
|
||
pcb->DisconnectReported = FALSE;
|
||
InitializeListHead(&pcb->ReceiveList);
|
||
InitializeListHead(&pcb->SendList);
|
||
RtlMoveMemory( &pcb->RemoteName, pdncb->ncb_callname, NCBNAMSZ);
|
||
pcb->Adapter = plana;
|
||
pcb->SessionNumber = (UCHAR)index;
|
||
pcb->ReceiveTimeout = pdncb->ncb_rto;
|
||
pcb->SendTimeout = pdncb->ncb_sto;
|
||
|
||
//
|
||
// Fill in the Users virtual address so we can cancel the Listen/Call
|
||
// if the user desires.
|
||
//
|
||
|
||
pcb->UsersNcb = pdncb->users_ncb;
|
||
pcb->pdncbCall = pdncb;
|
||
pcb->pdncbHangup = NULL;
|
||
|
||
if (( pcb->ReceiveTimeout != 0 ) ||
|
||
( pcb->SendTimeout != 0 )) {
|
||
NbStartTimer( pfcb );
|
||
}
|
||
|
||
pcb->Signature = CB_SIGNATURE;
|
||
pcb->Status = 0; // An invalid value!
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("NewCb pfcb: %lx, ppcb: %lx, pcb= %lx, lsn %lx\n",
|
||
pfcb,
|
||
ppcb,
|
||
pcb,
|
||
index));
|
||
}
|
||
|
||
return ppcb;
|
||
} /* NewCb */
|
||
|
||
NTSTATUS
|
||
CleanupCb(
|
||
IN PPCB ppcb,
|
||
IN PDNCB pdncb OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This closes the handles in the Cb and dereferences the objects.
|
||
|
||
Note: Resource must be held before calling this routine.
|
||
|
||
Arguments:
|
||
|
||
ppcb - Address of the pointer to the Cb containing handles and objects.
|
||
|
||
pdncb - Optional Address of the Hangup DNCB.
|
||
|
||
Return Value:
|
||
|
||
STATUS_PENDING if Hangup held due to an outstanding send. Otherwise STATUS_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
PCB pcb;
|
||
PDNCB pdncbHangup;
|
||
PPAB ppab;
|
||
KIRQL OldIrql; // Used when SpinLock held.
|
||
PFCB pfcb;
|
||
PDNCB pdncbtemp;
|
||
PDNCB pdncbReceiveAny;
|
||
|
||
if ( ppcb == NULL ) {
|
||
ASSERT( FALSE );
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("CleanupCb ppcb: %lx, pdncb: %lx\n", ppcb, pdncb));
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
pcb = *ppcb;
|
||
pfcb = pcb->pLana->pFcb;
|
||
|
||
LOCK_SPINLOCK( pfcb, OldIrql );
|
||
ppab = (*ppcb)->ppab;
|
||
|
||
if ( pcb == NULL ) {
|
||
ASSERT( FALSE );
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("CleanupCb ppcb: %lx, pcb %lx, pdncb %lx\n", ppcb, pcb, pdncb));
|
||
}
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
ASSERT( pcb->Signature == CB_SIGNATURE );
|
||
|
||
//
|
||
// Set pcb->pdncbHangup to NULL. This prevents NbCompletionPDNCB from queueing a CleanupCb
|
||
// if we Close the connection and cause sends to get returned.
|
||
//
|
||
|
||
pdncbHangup = pcb->pdncbHangup;
|
||
pcb->pdncbHangup = NULL;
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("CleanupCb ppcb: %lx, pcb= %lx\n", ppcb, pcb));
|
||
}
|
||
|
||
//
|
||
// If this is a Hangup (only time pdncb != NULL
|
||
// and we do not have a hangup on this connection
|
||
// and there are outstanding sends then delay the hangup.
|
||
//
|
||
|
||
if (( pdncb != NULL ) &&
|
||
( pdncbHangup == NULL ) &&
|
||
( !IsListEmpty(&pcb->SendList) )) {
|
||
|
||
ASSERT(( pdncb->ncb_command & ~ASYNCH ) == NCBHANGUP );
|
||
|
||
//
|
||
// We must wait up to 20 seconds for the send to complete before removing the
|
||
// connection.
|
||
//
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("CleanupCb delaying Hangup, waiting for send to complete\n"));
|
||
}
|
||
|
||
pcb->pdncbHangup = pdncb;
|
||
// reset retcode so that NCB_COMPLETE will process the next NCB_COMPLETE.
|
||
pcb->pdncbHangup->ncb_retcode = NRC_PENDING;
|
||
pdncb->tick_count = 40;
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
NbStartTimer( pfcb );
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
pcb->Status = SESSION_ABORTED;
|
||
|
||
// Cancel all the receive requests for this connection.
|
||
|
||
while ( (pdncbtemp = DequeueRequest( &pcb->ReceiveList)) != NULL ) {
|
||
|
||
NCB_COMPLETE( pdncbtemp, NRC_SCLOSED );
|
||
|
||
pdncbtemp->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
NbCompleteRequest( pdncbtemp->irp, STATUS_SUCCESS );
|
||
pcb->DisconnectReported = TRUE;
|
||
|
||
}
|
||
|
||
if (pcb->DisconnectReported == FALSE) {
|
||
//
|
||
// If there is a receive any on the name associated with this connection then
|
||
// return one receive any to the application. If there are no receive any's then
|
||
// don't worry. The spec says to do this regardless of whether we have told
|
||
// the application that the connection is closed using a receive or send.
|
||
// Indeed the spec says to do this even if the application gave us a hangup!
|
||
//
|
||
|
||
if ( (pdncbReceiveAny = DequeueRequest( &(*ppab)->ReceiveAnyList)) != NULL ) {
|
||
|
||
pdncbReceiveAny->ncb_num = (*ppab)->NameNumber;
|
||
pdncbReceiveAny->ncb_lsn = pcb->SessionNumber;
|
||
NCB_COMPLETE( pdncbReceiveAny, NRC_SCLOSED );
|
||
|
||
pdncbReceiveAny->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
NbCompleteRequest( pdncbReceiveAny->irp, STATUS_SUCCESS );
|
||
pcb->DisconnectReported = TRUE;
|
||
|
||
} else {
|
||
|
||
PAB pab255 = pcb->Adapter->AddressBlocks[MAXIMUM_ADDRESS];
|
||
//
|
||
// If there is a receive any for any name then
|
||
// return one receive any to the application. If there are no receive any
|
||
// any's then don't worry.
|
||
//
|
||
|
||
if ( (pdncbReceiveAny = DequeueRequest( &pab255->ReceiveAnyList)) != NULL ) {
|
||
|
||
pdncbReceiveAny->ncb_num = (*ppab)->NameNumber;
|
||
pdncbReceiveAny->ncb_lsn = pcb->SessionNumber;
|
||
NCB_COMPLETE( pdncbReceiveAny, NRC_SCLOSED );
|
||
|
||
pdncbReceiveAny->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
NbCompleteRequest( pdncbReceiveAny->irp, STATUS_SUCCESS );
|
||
pcb->DisconnectReported = TRUE;
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
CloseConnection( ppcb, 20000 );
|
||
|
||
LOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
//
|
||
// Any sends will have been returned to the caller by now because of the NtClose on the
|
||
// ConnectionHandle. Tell the caller that the hangup is complete if we have a hangup.
|
||
//
|
||
|
||
if ( pdncbHangup != NULL ) {
|
||
NCB_COMPLETE( pdncbHangup, NRC_GOODRET );
|
||
pdncbHangup->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
NbCompleteRequest( pdncbHangup->irp, STATUS_SUCCESS );
|
||
}
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("CleanupCb pcb: %lx, ppab: %lx, AddressHandle: %lx\n",
|
||
pcb,
|
||
ppab,
|
||
(*ppab)->AddressHandle));
|
||
|
||
NbFormattedDump( (PUCHAR)&(*ppab)->Name, sizeof(NAME) );
|
||
}
|
||
|
||
//
|
||
// IBM test Mif081.c states that it is not necessary to report the disconnection
|
||
// of a session if the name has already been deleted.
|
||
//
|
||
|
||
if (( pcb->DisconnectReported == TRUE ) ||
|
||
( ((*ppab)->Status & 7 ) == DEREGISTERED )) {
|
||
pcb->Adapter->ConnectionCount--;
|
||
*ppcb = NULL;
|
||
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
DEREFERENCE_AB( ppab );
|
||
ExFreePool( pcb );
|
||
|
||
} else {
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
AbandonConnection(
|
||
IN PPCB ppcb
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine examines the connection block and attempts to find a request to
|
||
send a session abort status plus it completes the Irp with STATUS_HANGUP_REQUIRED.
|
||
It always changes the status of the connection so that further requests are correctly
|
||
rejected. Upon getting the STATUS_HANGUP_REQUIRED, the dll will submit a hangup NCB
|
||
which will call CleanupCb.
|
||
|
||
This round about method is used because of the restrictions caused by being at Dpc or Apc
|
||
level and in the wrong context when the transport indicates that the connection is to
|
||
be cleaned up.
|
||
|
||
Arguments:
|
||
|
||
ppcb - Address of the pointer to the Cb containing handles and objects.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCB pcb;
|
||
KIRQL OldIrql; // Used when SpinLock held.
|
||
PFCB pfcb;
|
||
PPAB ppab;
|
||
PDNCB pdncb;
|
||
PDNCB pdncbReceiveAny;
|
||
|
||
pcb = *ppcb;
|
||
|
||
if (pcb != NULL)
|
||
{
|
||
pfcb = pcb->pLana->pFcb;
|
||
|
||
LOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
ASSERT( pcb->Signature == CB_SIGNATURE );
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("AbandonConnection ppcb: %lx, pcb= %lx\n", ppcb, pcb));
|
||
}
|
||
pcb->Status = SESSION_ABORTED;
|
||
|
||
while ( (pdncb = DequeueRequest( &pcb->ReceiveList)) != NULL ) {
|
||
|
||
pcb->DisconnectReported = TRUE;
|
||
NCB_COMPLETE( pdncb, NRC_SCLOSED );
|
||
|
||
pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
NbCompleteRequest( pdncb->irp, STATUS_HANGUP_REQUIRED );
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
return;
|
||
}
|
||
|
||
if ( pcb->pdncbHangup != NULL ) {
|
||
pcb->DisconnectReported = TRUE;
|
||
NCB_COMPLETE( pcb->pdncbHangup, NRC_SCLOSED );
|
||
pcb->pdncbHangup->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
NbCompleteRequest( pcb->pdncbHangup->irp, STATUS_HANGUP_REQUIRED );
|
||
pcb->pdncbHangup = NULL;
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// If there is a receive any on the name associated with this connection then
|
||
// return one receive any to the application.
|
||
//
|
||
|
||
ppab = (*ppcb)->ppab;
|
||
if ( (pdncbReceiveAny = DequeueRequest( &(*ppab)->ReceiveAnyList)) != NULL ) {
|
||
|
||
pdncbReceiveAny->ncb_num = (*ppab)->NameNumber;
|
||
pdncbReceiveAny->ncb_lsn = pcb->SessionNumber;
|
||
|
||
pcb->DisconnectReported = TRUE;
|
||
NCB_COMPLETE( pdncbReceiveAny, NRC_SCLOSED );
|
||
pdncbReceiveAny->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
NbCompleteRequest( pdncbReceiveAny->irp, STATUS_HANGUP_REQUIRED );
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// If there is a receive any any with the lana associated with this connection then
|
||
// return one receive any to the application. If there are no receive any's then
|
||
// don't worry.
|
||
|
||
ppab = &pcb->Adapter->AddressBlocks[MAXIMUM_ADDRESS];
|
||
if ( (pdncbReceiveAny = DequeueRequest( &(*ppab)->ReceiveAnyList)) != NULL ) {
|
||
|
||
pdncbReceiveAny->ncb_num = (*ppab)->NameNumber;
|
||
pdncbReceiveAny->ncb_lsn = pcb->SessionNumber;
|
||
|
||
pcb->DisconnectReported = TRUE;
|
||
NCB_COMPLETE( pdncbReceiveAny, NRC_SCLOSED );
|
||
pdncbReceiveAny->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
NbCompleteRequest( pdncbReceiveAny->irp, STATUS_HANGUP_REQUIRED );
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
return;
|
||
}
|
||
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
CloseConnection(
|
||
IN PPCB ppcb,
|
||
IN DWORD dwTimeOutInMS
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine examines the connection block and attempts to close the connection
|
||
handle to the transport. This will complete all outstanding requests.
|
||
|
||
This routine assumes the spinlock is not held but the resource is.
|
||
|
||
Arguments:
|
||
|
||
ppcb - Address of the pointer to the Cb containing handles and objects.
|
||
|
||
dwTimeOutInMS - Timeout value in milliseconds for Disconnect
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCB pcb;
|
||
NTSTATUS localstatus;
|
||
|
||
PAGED_CODE();
|
||
|
||
pcb = *ppcb;
|
||
|
||
ASSERT( pcb->Signature == CB_SIGNATURE );
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("CloseConnection ppcb: %lx, pcb= %lx\n", ppcb, pcb));
|
||
}
|
||
|
||
if ( pcb->ConnectionHandle ) {
|
||
HANDLE Handle;
|
||
|
||
Handle = pcb->ConnectionHandle;
|
||
pcb->ConnectionHandle = NULL;
|
||
|
||
//
|
||
// If we have a connection, request an orderly disconnect.
|
||
//
|
||
|
||
if ( pcb->ConnectionObject != NULL ) {
|
||
PIRP Irp;
|
||
LARGE_INTEGER DisconnectTimeout;
|
||
|
||
DisconnectTimeout.QuadPart = Int32x32To64( dwTimeOutInMS, -10000 );
|
||
|
||
Irp = IoAllocateIrp( pcb->DeviceObject->StackSize, FALSE);
|
||
|
||
//
|
||
// If we cannot allocate an Irp, the ZwClose will cause a disorderly
|
||
// disconnect.
|
||
//
|
||
|
||
if (Irp != NULL) {
|
||
TdiBuildDisconnect(
|
||
Irp,
|
||
pcb->DeviceObject,
|
||
pcb->ConnectionObject,
|
||
NULL,
|
||
NULL,
|
||
&DisconnectTimeout,
|
||
TDI_DISCONNECT_RELEASE,
|
||
NULL,
|
||
NULL);
|
||
|
||
SubmitTdiRequest(pcb->ConnectionObject, Irp);
|
||
|
||
IoFreeIrp(Irp);
|
||
}
|
||
|
||
// Remove reference put on in NbOpenConnection
|
||
|
||
ObDereferenceObject( pcb->ConnectionObject );
|
||
|
||
pcb->DeviceObject = NULL;
|
||
pcb->ConnectionObject = NULL;
|
||
}
|
||
|
||
IF_NBDBG( NB_DEBUG_CALL )
|
||
{
|
||
NbPrint( (
|
||
"CloseConnection : Close file invoked for \n"
|
||
) );
|
||
|
||
NbFormattedDump( (PUCHAR) &pcb-> RemoteName, sizeof( NAME ) );
|
||
}
|
||
|
||
|
||
if (PsGetCurrentProcess() != NbFspProcess) {
|
||
KAPC_STATE ApcState;
|
||
|
||
KeStackAttachProcess(NbFspProcess, &ApcState);
|
||
localstatus = ZwClose( Handle);
|
||
ASSERT(NT_SUCCESS(localstatus));
|
||
KeUnstackDetachProcess(&ApcState);
|
||
} else {
|
||
localstatus = ZwClose( Handle);
|
||
ASSERT(NT_SUCCESS(localstatus));
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
PPCB
|
||
FindCb(
|
||
IN PFCB pfcb,
|
||
IN PDNCB pdncb,
|
||
IN BOOLEAN IgnoreState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine uses the callers lana number and LSN to find the Cb.
|
||
|
||
Arguments:
|
||
|
||
pfcb - Supplies a pointer to the Fcb that Cb is chained onto.
|
||
|
||
pdncb - Supplies the connection id from the applications point of view.
|
||
|
||
IgnoreState - Return even if connection in error.
|
||
|
||
Return Value:
|
||
|
||
The address of the pointer to the connection block or NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
PPCB ppcb;
|
||
UCHAR Status;
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("FindCb pfcb: %lx, lana: %lx, lsn: %lx\n",
|
||
pfcb,
|
||
pdncb->ncb_lana_num,
|
||
pdncb->ncb_lsn));
|
||
}
|
||
|
||
if (( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
|
||
( pfcb == NULL ) ||
|
||
( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
|
||
( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED)) {
|
||
NCB_COMPLETE( pdncb, NRC_BRIDGE );
|
||
return NULL;
|
||
}
|
||
|
||
if (( pdncb->ncb_lsn > MAXIMUM_CONNECTION ) ||
|
||
( pfcb->ppLana[pdncb->ncb_lana_num]->ConnectionBlocks[pdncb->ncb_lsn] == NULL)) {
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( (" not found\n"));
|
||
}
|
||
|
||
NCB_COMPLETE( pdncb, NRC_SNUMOUT );
|
||
return NULL;
|
||
}
|
||
|
||
ppcb = &(pfcb->ppLana[pdncb->ncb_lana_num]->ConnectionBlocks[pdncb->ncb_lsn]);
|
||
Status = (*ppcb)->Status;
|
||
|
||
//
|
||
// Hangup and session status can be requested whatever state the
|
||
// connections in. Call and Listen use FindCb only to find and modify
|
||
// the Status so they are allowed also.
|
||
//
|
||
|
||
if (( Status != SESSION_ESTABLISHED ) &&
|
||
( !IgnoreState )) {
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("FindCb Status %x\n", Status));
|
||
}
|
||
|
||
if (( pdncb->ncb_retcode == NRC_PENDING ) &&
|
||
(( pdncb->ncb_command & ~ASYNCH) != NCBHANGUP ) &&
|
||
(( pdncb->ncb_command & ~ASYNCH) != NCBSSTAT ) &&
|
||
(( pdncb->ncb_command & ~ASYNCH) != NCBCALL ) &&
|
||
(( pdncb->ncb_command & ~ASYNCH) != NCALLNIU ) &&
|
||
(( pdncb->ncb_command & ~ASYNCH) != NCBLISTEN )) {
|
||
|
||
if ( Status == SESSION_ABORTED ) {
|
||
|
||
(*ppcb)->DisconnectReported = TRUE;
|
||
NCB_COMPLETE( pdncb, NRC_SCLOSED );
|
||
|
||
} else {
|
||
|
||
NCB_COMPLETE( pdncb, NRC_TOOMANY ); // Try again later
|
||
|
||
}
|
||
|
||
//
|
||
// On hangup we want to pass the connection back to give
|
||
// cleanupcb a chance to destroy the connection. For all
|
||
// other requests return NULL.
|
||
//
|
||
|
||
if (( pdncb->ncb_command & ~ASYNCH) != NCBHANGUP ) {
|
||
return NULL;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( (", ppcb= %lx\n", ppcb ));
|
||
}
|
||
|
||
ASSERT( (*ppcb)->Signature == CB_SIGNATURE );
|
||
|
||
return ppcb;
|
||
}
|
||
|
||
BOOL
|
||
FindActiveSession(
|
||
IN PFCB pfcb,
|
||
IN PDNCB pdncb OPTIONAL,
|
||
IN PPAB ppab
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
pfcb - Supplies a pointer to the callers Fcb.
|
||
|
||
pdncb - Supplies the ncb requesting the Delete Name.
|
||
|
||
ppab - Supplies (indirectly) the TDI handle to scan for.
|
||
|
||
Return Value:
|
||
|
||
TRUE iff there is an active session found using this handle.
|
||
|
||
--*/
|
||
|
||
{
|
||
PPCB ppcb = NULL;
|
||
PLANA_INFO plana = (*ppab)->pLana;
|
||
int index;
|
||
|
||
if ( ARGUMENT_PRESENT(pdncb) ) {
|
||
if ( pdncb->ncb_lana_num > pfcb->MaxLana ) {
|
||
NCB_COMPLETE( pdncb, NRC_BRIDGE );
|
||
return FALSE;
|
||
}
|
||
|
||
if (( pfcb == NULL ) ||
|
||
( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
|
||
( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED)) {
|
||
NCB_COMPLETE( pdncb, NRC_BRIDGE );
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
ASSERT( pfcb->Signature == FCB_SIGNATURE );
|
||
|
||
for ( index=1 ; index <= MAXIMUM_CONNECTION; index++ ) {
|
||
|
||
if ( plana->ConnectionBlocks[index] == NULL ) {
|
||
continue;
|
||
}
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("FindActiveSession index:%x connections ppab: %lx = ppab: %lx state: %x\n",
|
||
index,
|
||
plana->ConnectionBlocks[index]->ppab,
|
||
ppab,
|
||
plana->ConnectionBlocks[index]->Status));
|
||
}
|
||
// Look for active sessions on this address.
|
||
if (( plana->ConnectionBlocks[index]->ppab == ppab ) &&
|
||
( plana->ConnectionBlocks[index]->Status == SESSION_ESTABLISHED )) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
VOID
|
||
CloseListens(
|
||
IN PFCB pfcb,
|
||
IN PPAB ppab
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
pfcb - Supplies a pointer to the callers Fcb.
|
||
|
||
ppab - All listens using this address are to be closed.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLANA_INFO plana;
|
||
int index;
|
||
KIRQL OldIrql; // Used when SpinLock held.
|
||
|
||
ASSERT( pfcb->Signature == FCB_SIGNATURE );
|
||
|
||
plana = (*ppab)->pLana;
|
||
LOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
for ( index=1 ; index <= MAXIMUM_CONNECTION; index++ ) {
|
||
|
||
if ( plana->ConnectionBlocks[index] == NULL ) {
|
||
continue;
|
||
}
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
NbPrint( ("CloseListen index:%x connections ppab: %lx = ppab: %lx state: %x\n",
|
||
index,
|
||
plana->ConnectionBlocks[index]->ppab,
|
||
ppab,
|
||
plana->ConnectionBlocks[index]->Status));
|
||
}
|
||
// Look for a listen on this address.
|
||
if (( plana->ConnectionBlocks[index]->ppab == ppab ) &&
|
||
( plana->ConnectionBlocks[index]->Status == LISTEN_OUTSTANDING )) {
|
||
PDNCB pdncb = plana->ConnectionBlocks[index]->pdncbCall;
|
||
NCB_COMPLETE( pdncb, NRC_NAMERR );
|
||
plana->ConnectionBlocks[index]->DisconnectReported = TRUE;
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
CleanupCb( &plana->ConnectionBlocks[index], NULL);
|
||
LOCK_SPINLOCK( pfcb, OldIrql );
|
||
}
|
||
}
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
}
|
||
|
||
PPCB
|
||
FindCallCb(
|
||
IN PFCB pfcb,
|
||
IN PNCB pncb,
|
||
IN UCHAR ucLana
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
pfcb - Supplies a pointer to the callers Fcb.
|
||
|
||
pncb - Supplies the USERS VIRTUAL address CALL or LISTEN ncb to be
|
||
cancelled.
|
||
|
||
Return Value:
|
||
|
||
The address of the pointer to the connection block or NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
PPCB ppcb = NULL;
|
||
PLANA_INFO plana;
|
||
int index;
|
||
|
||
if ( ucLana > pfcb->MaxLana ) {
|
||
return NULL;
|
||
}
|
||
|
||
if (( pfcb == NULL ) ||
|
||
( pfcb->ppLana[ucLana] == NULL ) ||
|
||
( pfcb->ppLana[ucLana]->Status != NB_INITIALIZED)) {
|
||
return NULL;
|
||
}
|
||
|
||
ASSERT( pfcb->Signature == FCB_SIGNATURE );
|
||
|
||
plana = pfcb->ppLana[ucLana];
|
||
|
||
for ( index=1 ; index <= MAXIMUM_CONNECTION; index++ ) {
|
||
|
||
if (( plana->ConnectionBlocks[index] != NULL ) &&
|
||
( plana->ConnectionBlocks[index]->UsersNcb == pncb )) {
|
||
return &plana->ConnectionBlocks[index];
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
PPCB
|
||
FindReceiveIndicated(
|
||
IN PFCB pfcb,
|
||
IN PDNCB pdncb,
|
||
IN PPAB ppab
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Find either a connection with a receive indicated or one that has been
|
||
disconnected but not reported yet.
|
||
|
||
Arguments:
|
||
|
||
pfcb - Supplies a pointer to the callers Fcb.
|
||
|
||
pdncb - Supplies the ncb with the receive any.
|
||
|
||
ppab - Supplies (indirectly) the TDI handle to scan for.
|
||
|
||
Return Value:
|
||
|
||
PPCB - returns the connection with the indicated receive.
|
||
|
||
--*/
|
||
|
||
{
|
||
PPCB ppcb = NULL;
|
||
PLANA_INFO plana;
|
||
int index;
|
||
|
||
if (( pfcb == NULL ) ||
|
||
( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
|
||
( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
|
||
NCB_COMPLETE( pdncb, NRC_BRIDGE );
|
||
return NULL;
|
||
}
|
||
|
||
ASSERT( pfcb->Signature == FCB_SIGNATURE );
|
||
|
||
plana = pfcb->ppLana[pdncb->ncb_lana_num];
|
||
|
||
for ( index=0 ; index <= MAXIMUM_CONNECTION; index++ ) {
|
||
|
||
if ( plana->ConnectionBlocks[index] == NULL ) {
|
||
continue;
|
||
}
|
||
|
||
if ( pdncb->ncb_num == MAXIMUM_ADDRESS) {
|
||
|
||
// ReceiveAny on Any address
|
||
if (( plana->ConnectionBlocks[index]->ReceiveIndicated != 0 ) ||
|
||
(( plana->ConnectionBlocks[index]->Status == SESSION_ABORTED ) &&
|
||
( plana->ConnectionBlocks[index]->DisconnectReported == FALSE ))) {
|
||
PPAB ppab;
|
||
|
||
pdncb->ncb_lsn = (UCHAR)index;
|
||
ppab = plana->ConnectionBlocks[index]->ppab;
|
||
pdncb->ncb_num = (*ppab)->NameNumber;
|
||
return &plana->ConnectionBlocks[index];
|
||
}
|
||
} else {
|
||
if ( plana->ConnectionBlocks[index]->ppab == ppab ) {
|
||
// This connection is using the correct address.
|
||
if (( plana->ConnectionBlocks[index]->ReceiveIndicated != 0 ) ||
|
||
(( plana->ConnectionBlocks[index]->Status == SESSION_ABORTED ) &&
|
||
( plana->ConnectionBlocks[index]->DisconnectReported == FALSE ))) {
|
||
pdncb->ncb_lsn = (UCHAR)index;
|
||
return &plana->ConnectionBlocks[index];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
NTSTATUS
|
||
NbTdiDisconnectHandler (
|
||
PVOID EventContext,
|
||
PVOID ConnectionContext,
|
||
ULONG DisconnectDataLength,
|
||
PVOID DisconnectData,
|
||
ULONG DisconnectInformationLength,
|
||
PVOID DisconnectInformation,
|
||
ULONG DisconnectIndicators
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when a session is disconnected from a remote
|
||
machine.
|
||
|
||
Arguments:
|
||
|
||
IN PVOID EventContext,
|
||
IN PCONNECTION_CONTEXT ConnectionContext,
|
||
IN ULONG DisconnectDataLength,
|
||
IN PVOID DisconnectData,
|
||
IN ULONG DisconnectInformationLength,
|
||
IN PVOID DisconnectInformation,
|
||
IN ULONG DisconnectIndicators
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of event indicator
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
|
||
IF_NBDBG (NB_DEBUG_CALL) {
|
||
PPCB ppcb = ConnectionContext;
|
||
NbPrint( ("NbTdiDisconnectHandler ppcb: %lx, pcb %lx\n", ppcb, (*ppcb)));
|
||
}
|
||
|
||
AbandonConnection( (PPCB)ConnectionContext );
|
||
return STATUS_SUCCESS;
|
||
|
||
UNREFERENCED_PARAMETER(EventContext);
|
||
UNREFERENCED_PARAMETER(DisconnectDataLength);
|
||
UNREFERENCED_PARAMETER(DisconnectData);
|
||
UNREFERENCED_PARAMETER(DisconnectInformationLength);
|
||
UNREFERENCED_PARAMETER(DisconnectInformation);
|
||
UNREFERENCED_PARAMETER(DisconnectIndicators);
|
||
|
||
}
|
||
|