summaryrefslogtreecommitdiffstats
path: root/private/ntos/nbt/vxd/vxdisol.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nbt/vxd/vxdisol.c')
-rw-r--r--private/ntos/nbt/vxd/vxdisol.c4042
1 files changed, 4042 insertions, 0 deletions
diff --git a/private/ntos/nbt/vxd/vxdisol.c b/private/ntos/nbt/vxd/vxdisol.c
new file mode 100644
index 000000000..7c5e6dfe1
--- /dev/null
+++ b/private/ntos/nbt/vxd/vxdisol.c
@@ -0,0 +1,4042 @@
+/**********************************************************************/
+/** Microsoft Windows/NT **/
+/** Copyright(c) Microsoft Corp., 1993 **/
+/**********************************************************************/
+
+/*
+ VxdIsol.c
+
+ This file roughly corresponds to ntisol.c and contains VxD specific
+ portions of the NBT driver
+
+ FILE HISTORY:
+ Johnl 15-Apr-1993 Created
+
+*/
+
+
+#include <nbtprocs.h>
+#include <nbtioctl.h>
+
+//
+// Used by VxdFindClientElement
+//
+enum CLIENT_TYPE
+{
+ CLIENT_BC,
+ CLIENT_LOCAL
+} ;
+
+//
+// Counts the number of items in the list Head
+//
+// Assumes pEntry is defined in the procedure
+//
+#define COUNT_ELEMENTS( Head, Count ) \
+ for ( pEntry = (Head).Flink ; \
+ pEntry != &(Head); \
+ pEntry = pEntry->Flink ) \
+ { \
+ (Count)++ ; \
+ }
+
+extern BOOLEAN CachePrimed;
+extern BOOL fInInit;
+
+//
+// this is used for AdapterStatus and FindName calls because we need to retain
+// the info, so can't have it as a local var (both these calls are synchronous
+// so need not worry about stomping on this memory)
+//
+TA_NETBIOS_ADDRESS tanb_global ;
+
+
+NCBERR VxdNameToClient( tDEVICECONTEXT * pDeviceContext,
+ CHAR * pName,
+ UCHAR * pNameNum,
+ tCLIENTELE * * ppClientEle ) ;
+
+//-------------------------------------------------------------------------
+//
+// Allocates and frees the SESS_SETUP_CONTEXT contents (not the context
+// itself).
+//
+TDI_STATUS AllocSessSetupContext( PSESS_SETUP_CONTEXT pSessSetupContext,
+ BOOL fListenOnStar ) ;
+void FreeSessSetupContext( PSESS_SETUP_CONTEXT pSessSetupContext ) ;
+
+NCBERR VxdInitSessionSetup( tDEVICECONTEXT * pDeviceContext,
+ TDI_REQUEST * pRequest,
+ PSESS_SETUP_CONTEXT * ppSessSetupContext,
+ NCB * pNCB ) ;
+
+BOOL VxdCopySessionStatus( tDEVICECONTEXT * pDeviceContext,
+ tCLIENTELE * pClientEle,
+ PSESSION_HEADER pSessionHeader,
+ PSESSION_BUFFER * ppSessionBuff,
+ ULONG * pRemainingSize ) ;
+
+//-------------------------------------------------------------------------
+//
+// NCB Reset context structures
+//
+//
+
+typedef struct
+{
+ //
+ // Number of active sessions we are waiting on to close
+ //
+ int cActiveSessions ;
+
+ //
+ // Number of active names we have to wait to finish deregistering
+ //
+ int cActiveNames ;
+
+ //
+ // NCB Error if reset failed (failed to resize session table for example)
+ //
+ UCHAR errncb ;
+} RESET_CONTEXT, *PRESET_CONTEXT ;
+
+NCBERR VxdResetContinue( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+
+#define DISCONNECT_TIMEOUT 15000
+
+//-------------------------------------------------------------------------
+//
+// Last valid NCB name and logical session number
+//
+#define MAX_NCB_NUMS 254
+#define ANY_NAME 255
+
+NTSTATUS
+PostInit_Proc();
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, PostInit_Proc)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+/*******************************************************************
+
+ NAME: VxdDgramSend
+
+ SYNOPSIS: Vxd specific Send Datagram code
+
+ ENTRY: pDeviceContext - Device to send the datagram on
+ pNCB - NCB that contains the datagram data/dest
+
+ RETURNS: NT_SUCCESS if successful, error otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 19-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdDgramSend( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status;
+ LONG lSentLength;
+ TDI_REQUEST Request;
+ tDGRAMHDR *pDgramHdr;
+ tCLIENTELE *pClientEle;
+ char *pName ;
+ NCBERR errNCB ;
+ TDI_CONNECTION_INFORMATION SendInfo ;
+ TA_NETBIOS_ADDRESS tanb ;
+
+
+ errNCB = VxdFindClientElement( pDeviceContext,
+ pNCB->ncb_num,
+ &pClientEle,
+ CLIENT_LOCAL ) ;
+ if ( errNCB )
+ {
+ DbgPrint("VxdDgramSend: VxdFindClientElement Failed\r\n") ;
+ return errNCB ;
+ }
+
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ) ;
+
+ if ( pClientEle->fDeregistered )
+ return NRC_NOWILD ;
+
+ //
+ // If broadcast, then use "*" for destination name
+ //
+ if ( (pNCB->ncb_command & ~ASYNCH) == NCBDGSENDBC )
+ {
+ //
+ // Name must stay valid after call
+ //
+ static char BcastName[NCBNAMSZ] = "* " ;
+ pName = BcastName ;
+ }
+ else
+ {
+ pName = pNCB->ncb_callname ;
+ }
+
+ //
+ // Initialize the transport address
+ //
+ // It's Ok to pass automatic variables to NbtSendDatagram,
+ // the necessary data is copied out before returning
+ //
+ InitNBTDIConnectInfo( &SendInfo, &tanb, pName ) ;
+ Request.Handle.AddressHandle = pClientEle;
+
+ status = NbtSendDatagram(
+ &Request,
+ &SendInfo,
+ pNCB->ncb_length,
+ &lSentLength,
+ pNCB->ncb_buffer, // user data
+ pDeviceContext,
+ (PIRP) pNCB );
+
+ errNCB = MapTDIStatus2NCBErr( status ) ;
+
+ if ( errNCB != NRC_GOODRET && errNCB != NRC_PENDING)
+ {
+ DbgPrint("VxdDgramSend - returning ncb status 0x" ) ;
+ DbgPrintNum( (ULONG) errNCB ) ;
+ DbgPrint("\r\n") ;
+ }
+ else
+ {
+ //
+ // Since NbtSendDatagram always buffers datagram sends, we need to
+ // complete the NCB here since NbtSendDatagram will not complete
+ // the data gram
+ //
+ CTEIoComplete(pNCB,status,pNCB->ncb_length);
+ }
+
+ return errNCB ;
+}
+
+/*******************************************************************
+
+ NAME: VxdDgramReceive
+
+ SYNOPSIS: Vxd specific Datagram Receive code
+
+ ENTRY: pDeviceContext - Device to send the datagram on
+ pNCB - NCB that contains the datagram data/dest
+
+ RETURNS: NT_SUCCESS if successful, error otherwise
+
+ NOTES: For a receive datagram, the name number is who we want to
+ receive to, and the call name will be set to who we
+ received from. The name number may be 0xff to indicate
+ receive to any name from anyone.
+
+ HISTORY:
+ Johnl 19-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdDgramReceive( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ TDI_REQUEST Request;
+ ULONG ReceivedLength;
+ tCLIENTELE * pClientEle ;
+ NCBERR errNCB ;
+ TDI_CONNECTION_INFORMATION RcvInfo ;
+ TDI_CONNECTION_INFORMATION SendInfo ;
+ NTSTATUS status ;
+
+ if ( pNCB->ncb_num != ANY_NAME )
+ {
+ //
+ // For the RcvBC case, this just confirms the ncb_num is valid, the
+ // pClientEle is replaced with the broadcast client element (mif
+ // tests invalid ncb_nums with broadcasts).
+ //
+ if ( errNCB = VxdFindClientElement( pDeviceContext,
+ pNCB->ncb_num,
+ &pClientEle,
+ CLIENT_LOCAL ) )
+ {
+ return errNCB ;
+ }
+
+ if ( pClientEle->fDeregistered )
+ return NRC_NOWILD ;
+
+ if ( (pNCB->ncb_command & ~ASYNCH) == NCBDGRECVBC )
+ {
+ if ( errNCB = VxdFindClientElement( pDeviceContext,
+ pNCB->ncb_num,
+ &pClientEle,
+ CLIENT_BC ) )
+ if ( errNCB )
+ return NRC_NAMERR ;
+ }
+
+ Request.Handle.AddressHandle = pClientEle ;
+
+ status = NbtReceiveDatagram(
+ &Request,
+ NULL, //pTdiRequest->ReceiveDatagramInformation,
+ NULL, //pTdiRequest->ReturnDatagramInformation,
+ pNCB->ncb_length,
+ &ReceivedLength,
+ pNCB->ncb_buffer, // user data
+ pDeviceContext,
+ pNCB );
+ if ( status == STATUS_PENDING )
+ return NRC_PENDING ;
+ }
+ else
+ {
+ tRCVELE * pRcvEle = (tRCVELE *)CTEAllocMem(sizeof(tRCVELE));
+ if (!pRcvEle)
+ return NRC_NORES ;
+
+ pRcvEle->pIrp = pNCB ;
+ pRcvEle->ReceiveInfo = NULL ;
+ pRcvEle->ReturnedInfo = NULL;
+ pRcvEle->RcvLength = pNCB->ncb_length ;
+ pRcvEle->pRcvBuffer = pNCB->ncb_buffer ;
+
+ InsertTailList( &pDeviceContext->RcvDGAnyFromAnyHead,
+ &pRcvEle->Linkage );
+
+ return NRC_PENDING ;
+ }
+
+ //
+ // Status should always be pending or error
+ //
+ ASSERT( status != TDI_SUCCESS ) ;
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCall
+
+ SYNOPSIS: Attempts to setup a session with the corresponding listen
+
+ ENTRY: pDeviceContext - Adapter to call on
+ pNCB - NCB that contains the call command
+
+ RETURNS:
+
+ NOTES: Before we can do the listen we must first open the
+ connection and associate the address.
+
+ The reserve field of the NCB is used as a SESS_SETUP_CONTEXT
+ structure
+
+ HISTORY:
+ Johnl 14-May-1993 Created
+
+********************************************************************/
+
+NCBERR VxdCall( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status;
+ NCBERR errNCB ;
+ TDI_REQUEST Request;
+ PSESS_SETUP_CONTEXT pSessSetupContext = NULL ;
+
+ if ( ( pNCB->ncb_name[0] == '*' )
+ || ( pNCB->ncb_callname[0] == '*' ) )
+ {
+ return NRC_NOWILD ;
+ }
+
+ if ( errNCB = VxdInitSessionSetup( pDeviceContext,
+ &Request,
+ &pSessSetupContext,
+ pNCB ))
+ {
+ return errNCB ;
+ }
+
+ status = NbtConnect( &Request,
+ 0, // Use system timeout
+ pSessSetupContext->pRequestConnect,
+ pSessSetupContext->pReturnConnect,
+ pNCB
+ );
+
+ if ( !NT_SUCCESS(status) )
+ {
+ VxdTearDownSession( pDeviceContext,
+ (tCONNECTELE*)Request.Handle.ConnectionContext,
+ pSessSetupContext,
+ NULL ) ;
+ }
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdSend
+
+ SYNOPSIS: Sends a netbios request
+
+ ENTRY: pDeviceContext - Adapter to call on
+ pNCB - NCB that contains the send command
+
+ EXIT:
+
+ RETURNS:
+
+ NOTES: pNCB->ncb_lsn - Session number to Send on
+
+ pNCB->ncb_reserved will contain a pointer to a tSESSIONHDR
+ for this NCB (freed in VxdIoComplete).
+
+ No-ack sends are treated like normal sends.
+
+ HISTORY:
+ Johnl 8-Jun-1993 Created
+
+********************************************************************/
+
+NCBERR VxdSend( tDEVICECONTEXT *pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status ;
+ NCBERR errNCB ;
+ tCONNECTELE * pConnEle;
+ CTELockHandle OldIrq;
+ tLOWERCONNECTION * pLowerConn;
+ tSESSIONHDR * pHdr=NULL;
+ tBUFFERCHAINSEND SendBuff ;
+ TDI_REQUEST Request ;
+ ULONG SentSize ;
+ ULONG SendFlags = 0 ;
+ PSEND_CONTEXT pSendCont = (PSEND_CONTEXT) pNCB->ncb_reserve ;
+
+ ASSERT( sizeof(SEND_CONTEXT) <=
+ sizeof(pNCB->ncb_reserve)+sizeof(pNCB->ncb_event)) ;
+
+ if ( errNCB = VxdFindConnectElement( pDeviceContext,
+ pNCB,
+ &pConnEle ))
+ {
+ return errNCB ;
+ }
+
+ ASSERT( pConnEle->Verify == NBT_VERIFY_CONNECTION ) ;
+
+ pLowerConn = (tLOWERCONNECTION *)pConnEle->pLowerConnId ;
+
+ // check the state of the connection
+ if (pConnEle->state == NBT_SESSION_UP)
+ {
+ if ( GetSessionHdr( &pHdr ))
+ {
+ //
+ // If this is part of a chain send, set up the 2nd buffer
+ //
+ if ( ((pNCB->ncb_command & ~ASYNCH) == NCBCHAINSEND) ||
+ ((pNCB->ncb_command & ~ASYNCH) == NCBCHAINSENDNA) )
+ {
+ SendBuff.Length2 = *((WORD*)pNCB->ncb_callname) ;
+ SendBuff.pBuffer2 = *((PUCHAR*)(pNCB->ncb_callname+2)) ;
+ SendFlags |= CHAIN_SEND_FLAG ;
+ DbgPrint("VxdSend - Doing chain send\r\n") ;
+ }
+ else
+ {
+ SendBuff.Length2 = 0 ;
+ }
+
+ pHdr->Type = NBT_SESSION_MESSAGE ;
+ pHdr->Flags = NBT_SESSION_FLAGS ;
+ pHdr->UlongLength = htonl(pNCB->ncb_length + SendBuff.Length2) ;
+
+ pSendCont->pHdr = pHdr ;
+
+ //
+ // Only sends that can time out are put on the timeout list
+ //
+ if ( (pSendCont->STO = pConnEle->STO) != NCB_INFINITE_TIME_OUT )
+ {
+ InsertTailList( &NbtConfig.SendTimeoutHead, &pSendCont->ListEntry ) ;
+ }
+
+ SendBuff.tBuff.pDgramHdr = pHdr ;
+ SendBuff.tBuff.HdrLength = sizeof( *pHdr ) ;
+ SendBuff.tBuff.pBuffer = pNCB->ncb_buffer ;
+ SendBuff.tBuff.Length = pNCB->ncb_length ;
+
+#ifdef DEBUG
+ if ( !pNCB->ncb_length ) // Make sure 0 length buffers do
+ SendBuff.tBuff.pBuffer = NULL ; // the right thing
+#endif
+
+ Request.RequestNotifyObject = VxdIoComplete ;
+ Request.RequestContext = pNCB ;
+ Request.Handle.ConnectionContext = pConnEle->pLowerConnId->pFileObject ;
+
+ status = TdiSend( &Request,
+ 0,
+ (USHORT) SendBuff.tBuff.HdrLength +
+ SendBuff.tBuff.Length + SendBuff.Length2,
+ &SentSize,
+ (tBUFFER*) &SendBuff,
+ SendFlags ) ;
+ ASSERT( !NT_SUCCESS( status ) ||
+ (SentSize == (SendBuff.tBuff.HdrLength +
+ SendBuff.tBuff.Length + SendBuff.Length2)) ) ;
+
+ pLowerConn->BytesSent += SentSize;
+
+ return NRC_PENDING ;
+
+ //
+ // if TdiSend fails, it will call the completion routine (directly
+ // or eventually, Vxdiocomplete) which will remove this from the list
+ // so, don't remove it here also or we overwrite redir's code segment!!
+ //
+ // //
+ // // Remove from the timeout list if an error occurred
+ // //
+ // if ( !NT_SUCCESS( status ) &&
+ // pConnEle->STO != NCB_INFINITE_TIME_OUT )
+ // {
+ // RemoveEntryList( &pSendCont->ListEntry ) ;
+ // }
+ }
+ else
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES ;
+ goto ErrorExit ;
+ }
+ }
+ else
+ {
+ status = TDI_INVALID_CONNECTION ;
+ }
+
+ if ( !NT_SUCCESS( status ) )
+ goto ErrorExit ;
+
+
+ return MapTDIStatus2NCBErr( status ) ;
+
+ErrorExit:
+ if ( pHdr )
+ FreeSessionHdr( pHdr ) ;
+
+ DbgPrint("VxdSend returning NCB error: 0x") ;
+ DbgPrintNum( MapTDIStatus2NCBErr( status ) ) ; DbgPrint("\r\n") ;
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdReceiveAny
+
+ SYNOPSIS: Handles a request to accept data from any open session
+
+ ENTRY: pDeviceContext - Adapter to call on
+ pNCB - NCB that contains the receive command
+
+ EXIT:
+
+ RETURNS:
+
+ NOTES: pNCB->ncb_lsn - Session set to who to receive from if
+ an indication is found
+
+ The most common case (for WFW rdr) is to Receive on
+ a particular name number w/o any waiting connections
+
+ HISTORY:
+ Johnl 8-Jun-1993 Created
+
+********************************************************************/
+
+NCBERR VxdReceiveAny( tDEVICECONTEXT *pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status;
+ NCBERR errNCB ;
+ tLOWERCONNECTION * pLowerConn;
+ tCLIENTELE * pClientEle = NULL ;
+ PLIST_ENTRY pEntry, pHead ;
+
+#ifdef DEBUG
+ DbgPrint("VxdReceiveAny posted: Ncb length, Rcv Buff Address: 0x") ;
+ DbgPrintNum( pNCB->ncb_length ) ; DbgPrint(", 0x") ;
+ DbgPrintNum( (ULONG) pNCB->ncb_buffer ) ; DbgPrint("\r\n") ;
+#endif
+
+ //
+ // If they've given us a name number to receive on, find it
+ //
+ if ( pNCB->ncb_num != ANY_NAME )
+ {
+ if ( errNCB = VxdFindClientElement( pDeviceContext,
+ pNCB->ncb_num,
+ &pClientEle,
+ CLIENT_LOCAL ) )
+ {
+ DbgPrint("VxdReceiveAny - Couldn't find name number\r\n") ;
+ return errNCB ;
+ }
+
+ if ( !pClientEle->fDeregistered )
+ {
+ if ( IsListEmpty( &pDeviceContext->PartialRcvHead ) )
+ {
+ goto QueueRcv ;
+ }
+ }
+ else
+ {
+ return NRC_NOWILD ;
+ }
+ }
+ else
+ {
+ if ( IsListEmpty( &pDeviceContext->PartialRcvHead ) )
+ {
+ goto QueueRcv ;
+ }
+ }
+
+ //
+ // Scan for all active sessions looking for one that has indicated
+ // data that will satisfy this ReceiveAny
+ //
+ pHead = &pDeviceContext->PartialRcvHead ;
+ pEntry = pHead->Flink ;
+ ASSERT( pEntry );
+ while ( pEntry != pHead )
+ {
+ DbgPrint("VxdReceiveAny: scanning lower connections for partial receive\r\n") ;
+ pLowerConn = CONTAINING_RECORD( pEntry, tLOWERCONNECTION, PartialRcvList ) ;
+
+ ASSERT( pLowerConn->State < NBT_DISCONNECTING );
+ //
+ // If Receive any from any, then the first one we find
+ // will work, otherwise compare the names
+ //
+
+ if ( pNCB->ncb_num == ANY_NAME )
+ break ;
+
+ else
+ {
+ if ( CTEMemCmp( pClientEle->pAddress->pNameAddr->Name,
+ pLowerConn->pUpperConnection->pClientEle->
+ pAddress->pNameAddr->Name,
+ NETBIOS_NAME_SIZE ) == NETBIOS_NAME_SIZE )
+ {
+ break ;
+ }
+ }
+
+ pEntry = pEntry->Flink ;
+ }
+
+ if ( pEntry != pHead )
+ {
+ DbgPrint("VxdReceiveAny: Found partial receive, calling VxdReceive\r\n") ;
+
+ ASSERT (pLowerConn->fOnPartialRcvList == TRUE);
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+
+ //
+ // Now find the session number this receive is taking place on
+ //
+ if ( errNCB = VxdFindLSN( pDeviceContext,
+ pLowerConn->pUpperConnection,
+ &pNCB->ncb_lsn ))
+ {
+ return errNCB ;
+ }
+
+ return VxdReceive( pDeviceContext, pNCB, FALSE ) ;
+ }
+ else
+ {
+ //
+ // Nothing active so queue it
+ //
+ PRCV_CONTEXT prcvCont ;
+
+QueueRcv:
+ if ( !GetRcvContext( &prcvCont ))
+ return NRC_NORESOURCES ;
+
+ InitRcvContext( prcvCont, NULL, pNCB ) ;
+ InitNDISBuff( &prcvCont->ndisBuff,
+ pNCB->ncb_buffer,
+ pNCB->ncb_length,
+ NULL ) ;
+ prcvCont->usFlags = TDI_RECEIVE_NORMAL;
+ *((PRCV_CONTEXT*)&pNCB->ncb_reserve) = prcvCont ;
+
+ if ( pNCB->ncb_num != ANY_NAME )
+ {
+ ASSERT( pClientEle != NULL ) ;
+ InsertTailList( &pClientEle->RcvAnyHead,
+ &prcvCont->ListEntry ) ;
+
+ return NRC_PENDING ;
+ }
+ else
+ {
+ InsertTailList( &pDeviceContext->RcvAnyFromAnyHead,
+ &prcvCont->ListEntry ) ;
+ }
+ }
+
+ return NRC_PENDING ;
+}
+
+/*******************************************************************
+
+ NAME: VxdReceive
+
+ SYNOPSIS: Worker for VxdReceive and VxdReceiveAny
+
+ ENTRY: pDeviceContext - Adapter to call on
+ pNCB - NCB that contains the receive command
+ fReceive - TRUE if we got here via a Receive ncb
+ - FALSE if we got here via a ReceiveAny ncb
+ EXIT:
+
+ RETURNS:
+
+ NOTES: pNCB->ncb_reserved will contain a pointer to a RCV_CONTEXT
+ for this NCB.
+
+ VxdReceiveAny calls this on an element where state==NBT_SESSION_UP
+ and StateRcv == PARTIAL_RCV, thus the receive context should
+ never be added to pConnele->RcvHead.
+
+ HISTORY:
+ Johnl 8-Jun-1993 Created
+
+********************************************************************/
+
+NCBERR VxdReceive( tDEVICECONTEXT * pDeviceContext, NCB * pNCB, BOOL fReceive )
+{
+ NTSTATUS status;
+ NCBERR errNCB ;
+ tCONNECTELE * pConnEle;
+ CTELockHandle OldIrq;
+ tLOWERCONNECTION * pLowerConn;
+ PRCV_CONTEXT prcvCont ;
+
+ if ( errNCB = VxdFindConnectElement( pDeviceContext,
+ pNCB,
+ &pConnEle ))
+ {
+ return errNCB ;
+ }
+
+ ASSERT( pConnEle->Verify == NBT_VERIFY_CONNECTION ) ;
+
+ pLowerConn = pConnEle->pLowerConnId;
+
+ DbgPrint("VxdReceive posted: Ncb length, Rcv buff Address: 0x") ;
+ DbgPrintNum( pNCB->ncb_length ) ; DbgPrint(", 0x") ;
+ DbgPrintNum( (ULONG) pNCB->ncb_buffer ) ; DbgPrint("\r\n") ;
+
+ //
+ // Setup the receive context tracker
+ //
+ if ( GetRcvContext( &prcvCont ))
+ {
+ InitRcvContext( prcvCont, pLowerConn, pNCB ) ;
+ InitNDISBuff( &prcvCont->ndisBuff,
+ pNCB->ncb_buffer,
+ pNCB->ncb_length,
+ NULL ) ;
+ prcvCont->RTO = pConnEle->RTO ;
+ prcvCont->usFlags = TDI_RECEIVE_NORMAL;
+
+ *((PRCV_CONTEXT*)&pNCB->ncb_reserve) = prcvCont ;
+
+ //
+ // If data is not available, queue the request, otherwise get the
+ // data
+ //
+ if ( pLowerConn->StateRcv != PARTIAL_RCV )
+ {
+ //
+ // Make sure a RcvAny didn't get to here
+ //
+ ASSERT( (pNCB->ncb_command & ~ASYNCH)== NCBRECV ) ;
+
+ if ( !pConnEle->Orig && fReceive )
+ {
+ prcvCont->usFlags = TDI_RECEIVE_NO_RESPONSE_EXP ;
+ }
+
+ InsertTailList(&pConnEle->RcvHead,
+ &prcvCont->ListEntry);
+
+ return NRC_PENDING ;
+ }
+ else
+ {
+ TDI_REQUEST Request ;
+ UINT cbReceiveLength ;
+ static USHORT usFlags = TDI_RECEIVE_NORMAL ;
+
+ DbgPrint("VxdReceive:A Rcv Buffer posted when data in the transport, InXport= 0x") ;
+ DbgPrintNum( pConnEle->BytesInXport ) ;
+ DbgPrint("\r\n") ;
+
+ pConnEle->OffsetFromStart = 0 ;
+
+ Request.RequestNotifyObject = CompletionRcv ;
+ Request.RequestContext = prcvCont ;
+ Request.Handle.ConnectionContext = pLowerConn->pFileObject ;
+
+ pConnEle->pIrpRcv = NULL ; // Buffer in the transport
+ pLowerConn->StateRcv = FILL_IRP ;
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+
+ cbReceiveLength = min( pNCB->ncb_length,
+ pConnEle->TotalPcktLen-pConnEle->BytesRcvd ) ;
+
+ //
+ // Don't pass zero length buffers to the transport
+ //
+ if ( !cbReceiveLength )
+ {
+ CompletionRcv( prcvCont, STATUS_SUCCESS, 0 ) ;
+ return NRC_GOODRET ;
+ }
+
+ //
+ // if it's an incoming session and this is a receive (as opp. to
+ // receive-any) then give transport a hint that there is no response
+ // coming back (trying to solve the raw-write-to-smb-server-perf problem)
+ //
+ if ( !pConnEle->Orig && fReceive )
+ {
+ usFlags = TDI_RECEIVE_NO_RESPONSE_EXP ;
+ }
+
+ status = TdiVxdReceive( &Request,
+ &usFlags,
+ &cbReceiveLength,
+ &prcvCont->ndisBuff ) ;
+
+ if ( status == STATUS_PENDING )
+ return NRC_PENDING ;
+
+ //
+ // Should always get pending unless a real error occurs
+ //
+ if ( !NT_SUCCESS(status) )
+ {
+ DbgPrint("VxdReceive - TdiReceive failed, error 0x") ;
+ DbgPrintNum( status ) ;
+ DbgPrint("\r\n") ;
+ CTEIoComplete( pNCB, status, 0 ) ;
+ }
+ }
+ }
+ else
+ return NRC_NORESOURCES ;
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdHangup
+
+ SYNOPSIS: Sets up a session Hangup
+
+ ENTRY: pDeviceContext -
+ pNCB - NCB that contains Hangup command
+
+ RETURNS:
+
+ NOTES: The code is similar to VxdDisconnectHandler. If this
+ changes, the VxdDisconnectHandler will probably have to
+ change
+
+ HISTORY:
+ Johnl 12-Jul-1993 Created
+
+********************************************************************/
+
+NCBERR VxdHangup( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ TDI_STATUS tdistatus ;
+ tCONNECTELE * pConnEle ;
+ NCBERR errNCB ;
+ TDI_REQUEST Request ;
+ ULONG TimeOut = DISCONNECT_TIMEOUT ;
+ tCLIENTELE * pClientEle ;
+ tLOWERCONNECTION * pLowerConn;
+
+ if ( errNCB = VxdFindConnectElement( pDeviceContext,
+ pNCB,
+ &pConnEle ))
+ {
+ //
+ // If the session was already closed but the client hasn't been
+ // notified, notify them now
+ //
+ if ( errNCB == NRC_SCLOSED )
+ {
+ CTEIoComplete( pNCB, STATUS_SUCCESS, 0 ) ;
+ errNCB = NRC_GOODRET ;
+ }
+
+ return errNCB ;
+ }
+
+ ASSERT( (pConnEle->Verify == NBT_VERIFY_CONNECTION) ||
+ (pConnEle->Verify == NBT_VERIFY_CONNECTION_DOWN)) ;
+
+ if ( tdistatus = VxdCompleteSessionNcbs( pDeviceContext, pConnEle ) )
+ {
+ DbgPrint("VxdHangup: Error return from VxdCompleteSessionNcbs\r\n") ;
+ }
+
+ if ( pClientEle = pConnEle->pClientEle )
+ {
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ||
+ pClientEle->Verify == NBT_VERIFY_CLIENT_DOWN ) ;
+ }
+
+ pLowerConn = pConnEle->pLowerConnId ;
+ if ( pLowerConn &&
+ (pLowerConn->fOnPartialRcvList == TRUE) &&
+ pLowerConn->StateRcv == PARTIAL_RCV )
+ {
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+ }
+
+ Request.Handle.ConnectionContext = pConnEle ;
+ tdistatus = NbtDisconnect( &Request,
+ &TimeOut,
+ TDI_DISCONNECT_RELEASE,
+ NULL,
+ NULL,
+ NULL ) ;
+ if ( tdistatus && tdistatus != TDI_PENDING )
+ {
+ DbgPrint("VxdHangup: Warning: NbtDisconnect returned error\r\n") ;
+ }
+
+ tdistatus = NbtCloseConnection( &Request,
+ NULL,
+ pDeviceContext,
+ NULL ) ;
+ if ( tdistatus && tdistatus != TDI_PENDING )
+ {
+ DbgPrint("VxdHangup: Warning: NbtCloseConnection returned error\r\n") ;
+ }
+
+ tdistatus = NbtDisassociateAddress( &Request ) ;
+ if ( tdistatus )
+ {
+ DbgPrint("VxdHangup: NbtDisassociateAddress returned 0x") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\r\n") ;
+ }
+
+ REQUIRE( NBUnregister( pDeviceContext, pNCB->ncb_lsn, NB_SESSION )) ;
+
+ //
+ // If this name has been deleted but there were active sessions, check
+ // to see if this is the last session, if so, delete the name
+ //
+
+ if ( pClientEle &&
+ pClientEle->fDeregistered &&
+ !ActiveSessions(pClientEle) )
+ {
+ UCHAR NameNum ;
+ if ( !VxdFindNameNum( pDeviceContext, pClientEle->pAddress, &NameNum ))
+ {
+ (void) VxdCleanupAddress( pDeviceContext,
+ NULL,
+ pClientEle,
+ NameNum,
+ TRUE ) ;
+ }
+ }
+
+ CTEIoComplete( pNCB, STATUS_SUCCESS, 0 ) ;
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdListen
+
+ SYNOPSIS: Sets up a session listen
+
+ ENTRY: pDeviceContext -
+ pNCB - NCB that contains listen command
+
+ RETURNS:
+
+ NOTES: Before we can do the listen we must first open the
+ connection and associate the address.
+
+ The reserve field of the NCB is used as a SESS_SETUP_CONTEXT
+ structure
+
+ HISTORY:
+ Johnl 14-May-1993 Created
+
+********************************************************************/
+
+NCBERR VxdListen( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status;
+ NCBERR errNCB ;
+ TDI_REQUEST Request;
+ PSESS_SETUP_CONTEXT pSessSetupContext = NULL ;
+
+ if ( errNCB = VxdInitSessionSetup( pDeviceContext,
+ &Request,
+ &pSessSetupContext,
+ pNCB ))
+ {
+ return errNCB ;
+ }
+
+ status = NbtListen( &Request,
+ TDI_QUERY_ACCEPT,
+ *pNCB->ncb_callname != '*' ?
+ pSessSetupContext->pRequestConnect : NULL,
+ pSessSetupContext->pReturnConnect,
+ pNCB
+ );
+
+ if ( !NT_SUCCESS( status ) )
+ {
+ VxdTearDownSession( pDeviceContext,
+ Request.Handle.ConnectionContext,
+ pSessSetupContext,
+ NULL ) ;
+ }
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdOpenName
+
+ SYNOPSIS: Creates an Address object in response to AddName or
+ AddGroupName.
+
+ ENTRY: pDeviceContext - Device name is being added to
+ pNCB - NCB AddName submission
+
+ RETURNS: STATUS_SUCCESS if successful, error code otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 20-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdOpenName( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status ;
+ TDI_REQUEST tdiRequest ;
+ TDI_ADDRESS_NETBIOS tdiaddr ;
+
+ if ( pNCB->ncb_name[0] == '*' ||
+ pNCB->ncb_name[0] == '\0' )
+ {
+ return NRC_NOWILD ;
+ }
+
+ //
+ // Fill in the TDI structures appropriately
+ //
+ switch ( pNCB->ncb_command & ~ASYNCH )
+ {
+ case NCBADDGRNAME:
+ tdiaddr.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP ;
+ break ;
+
+ case NCBADDNAME:
+ tdiaddr.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE ;
+ break ;
+
+ default:
+ ASSERTMSG("VxdOpenName: Unexpected command type!\n", FALSE ) ;
+ return NRC_SYSTEM ;
+ }
+
+ CTEMemCopy( tdiaddr.NetbiosName,
+ pNCB->ncb_name,
+ sizeof(pNCB->ncb_name) ) ;
+
+ status = NbtOpenAddress( &tdiRequest,
+ &tdiaddr,
+ pDeviceContext->IpAddress,
+ NULL, // Security descriptor
+ pDeviceContext,
+ pNCB ) ;
+ if ( NT_SUCCESS( status ))
+ {
+ //
+ // Set our event handler to catch "Receive Any" and "Receve
+ // Any From Any" NCBs
+ //
+ REQUIRE( !NbtSetEventHandler( (tCLIENTELE*)tdiRequest.Handle.AddressHandle,
+ TDI_EVENT_RECEIVE,
+ ReceiveAnyHandler,
+ (tCLIENTELE*)tdiRequest.Handle.AddressHandle )) ;
+ //
+ // Set an event handler to cleanup up Netbios specific stuff on
+ // disconnect
+ //
+ REQUIRE( !NbtSetEventHandler( (tCLIENTELE*)tdiRequest.Handle.AddressHandle,
+ TDI_EVENT_DISCONNECT,
+ VxdDisconnectHandler,
+ (tCLIENTELE*)tdiRequest.Handle.AddressHandle)) ;
+ }
+
+ //
+ // If we open a non-unique name twice (such as a group name) then
+ // NbtOpenAddress doesn't complete the IRP it just returns success.
+ //
+ if ( status == TDI_SUCCESS )
+ {
+ CTEIoComplete( pNCB, status, (ULONG) tdiRequest.Handle.AddressHandle ) ;
+ }
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+
+/*******************************************************************
+
+ NAME: VxdCloseName
+
+ SYNOPSIS: Called in response to a Netbios Delete Name request
+
+ ENTRY: pDeviceContext - Device name should be deleted from
+ pNCB - Netbios Delete name submission
+
+ RETURNS: STATUS_SUCCESS if successful, error code otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 23-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdCloseName( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ tCLIENTELE * pClientEle ;
+ TDI_STATUS tdistatus ;
+ UCHAR NameNum ;
+ NCBERR errNCB ;
+
+
+ if ( pNCB->ncb_name[0] == '*' ||
+ pNCB->ncb_name[0] == '\0' )
+ {
+ return NRC_NOWILD ;
+ }
+
+ if ( errNCB = VxdNameToClient( pDeviceContext,
+ pNCB->ncb_name,
+ &NameNum,
+ &pClientEle ))
+ {
+ return errNCB ;
+ }
+
+ //
+ // If any sessions are open on this name, delay deletion till last name is
+ // closed
+ //
+ if ( ActiveSessions( pClientEle ) )
+ {
+ VxdCleanupAddress( pDeviceContext, pNCB, pClientEle, NameNum, FALSE ) ;
+ CTEIoComplete( pNCB, STATUS_NRC_ACTSES, 0 ) ;
+ return NRC_GOODRET ;
+ }
+
+ //
+ // No open sessions so blow away the name
+ //
+ return VxdCleanupAddress( pDeviceContext, pNCB, pClientEle, NameNum, TRUE ) ;
+}
+
+/*******************************************************************
+
+ NAME: ActiveSessions
+
+ SYNOPSIS: Returns TRUE if pClientEle has any active sessions
+
+ ENTRY: pClientEle - Client element to check
+
+********************************************************************/
+
+BOOL ActiveSessions( tCLIENTELE * pClientEle )
+{
+ PLIST_ENTRY pHead, pEntry ;
+
+ pHead = &pClientEle->ConnectActive ;
+ pEntry = pClientEle->ConnectActive.Flink ;
+ while ( pHead != pEntry )
+ {
+ tCONNECTELE * pConnEle = CONTAINING_RECORD( pEntry, tCONNECTELE, Linkage ) ;
+
+ if ( pConnEle->state > NBT_ASSOCIATED )
+ {
+ return TRUE ;
+ }
+
+ pEntry = pEntry->Flink ;
+ }
+
+ return FALSE ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCleanupAddress
+
+ SYNOPSIS: Prepares a name for deletion and optionally deletes it
+
+ ENTRY: pDeviceContext - Adapter we are dealing with
+ pNCB - Delete name NCB
+ pClientEle - Client of address element to delete
+ NameNum - Name number in table we are deleting
+ fDeleteAddress - TRUE if address should be deleted
+
+ EXIT: The address element will be marked as deregistered and all
+ non-session NCBs will be completed. The address element
+ may optionally be deleted also.
+
+ NOTES: This routine will complete pNCB as appropriate.
+
+ HISTORY:
+ Johnl 22-Sep-1993 Created
+
+********************************************************************/
+
+NCBERR VxdCleanupAddress( tDEVICECONTEXT * pDeviceContext,
+ NCB * pNCB,
+ tCLIENTELE * pClientEle,
+ UCHAR NameNum,
+ BOOL fDeleteAddress )
+{
+ TDI_REQUEST Request ;
+ NCBERR errNCB ;
+ tCLIENTELE * pClientEleBcast ;
+ TDI_STATUS tdistatus ;
+ USHORT NameType ;
+ PLIST_ENTRY pHead, pEntry ;
+ PLIST_ENTRY pNextEntry;
+ tLISTENREQUESTS * pListen ;
+ PRCV_CONTEXT prcvCont ;
+ tRCVELE * prcvEle ;
+
+ pClientEle->fDeregistered = TRUE ;
+
+ //
+ // Delete all outstanding listens on this name
+ //
+ while ( !IsListEmpty( &pClientEle->ListenHead ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->ListenHead ) ;
+ pListen = CONTAINING_RECORD( pEntry, tLISTENREQUESTS, Linkage ) ;
+ CTEIoComplete( pListen->pIrp, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ CTEMemFree( pListen ) ;
+ }
+
+ //
+ // Delete all outstanding datagram receives on this name
+ //
+ while ( !IsListEmpty( &pClientEle->RcvDgramHead ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->RcvDgramHead ) ;
+ prcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+ CTEIoComplete( prcvEle->pIrp, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ CTEMemFree( prcvEle ) ;
+ }
+
+ //
+ // Delete all outstanding datagram broadcast receives on this name number
+ //
+ errNCB = VxdFindClientElement( pDeviceContext,
+ 0,
+ &pClientEleBcast,
+ CLIENT_BC ) ;
+
+ if ( !errNCB )
+ {
+ //
+ // Scan the NCBs looking for a receive on this name number
+ //
+ pHead = &pClientEleBcast->RcvDgramHead ;
+ pEntry = pClientEleBcast->RcvDgramHead.Flink ;
+
+ while ( pEntry != pHead )
+ {
+ prcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+ pNextEntry = pEntry->Flink ;
+ if ( ((NCB*)prcvEle->pIrp)->ncb_num == NameNum )
+ {
+ RemoveEntryList( pEntry ) ;
+ CTEIoComplete( prcvEle->pIrp, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ CTEMemFree( prcvEle ) ;
+ }
+ pEntry = pNextEntry ;
+ }
+ }
+
+
+ //
+ // Delete all outstanding Receive Anys on this name
+ //
+ while ( !IsListEmpty( &pClientEle->RcvAnyHead ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->RcvAnyHead ) ;
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+ CTEIoComplete( prcvCont->pNCB, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ }
+
+ tdistatus = TDI_SUCCESS;
+ if ( fDeleteAddress )
+ {
+ Request.Handle.ConnectionContext = pClientEle ;
+ tdistatus = NbtCloseAddress( &Request,
+ NULL, //&RequestStatus,
+ pDeviceContext,
+ pNCB ) ;
+
+ if ( (tdistatus != TDI_PENDING) && pNCB )
+ CTEIoComplete( pNCB, tdistatus, 0 ) ;
+
+ REQUIRE( NBUnregister( pDeviceContext, NameNum, NB_NAME )) ;
+
+ DbgPrint("VxdCloseName: NBUnregistered:NameNum = 0x") ;
+ DbgPrintNum( NameNum ) ;
+ DbgPrint(" ClientEle = 0x") ;
+ DbgPrintNum( pClientEle ) ;
+ DbgPrint("\r\n") ;
+
+ if ( !NT_SUCCESS( tdistatus ))
+ {
+ DbgPrint("VxdCloseName: NbtCloseAddress failed with status 0x") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\r\n") ;
+ }
+ }
+
+ return MapTDIStatus2NCBErr( tdistatus ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdAccept
+
+ SYNOPSIS: Accepts an indicated listen
+
+ ENTRY: pConnectElem - Upper part of connection we're about to
+ setup
+ pNCB - Original Listen request
+
+ RETURNS: TDI_SUCCESS if successful error code otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 27-May-1993 Created
+
+********************************************************************/
+
+TDI_STATUS VxdAccept( tCONNECTELE * pConnectElem, NCB * pNCB )
+{
+ TDI_REQUEST Request ;
+ PSESS_SETUP_CONTEXT pSessSetupCont = (PSESS_SETUP_CONTEXT) pNCB->ncb_reserve ;
+ TDI_STATUS status ;
+
+ Request.Handle.ConnectionContext = pConnectElem ;
+
+ status = NbtAccept( &Request,
+ pSessSetupCont->pRequestConnect,
+ pSessSetupCont->pReturnConnect,
+ NULL ) ;
+ if ( !NT_SUCCESS(status) )
+ {
+ DbgPrint( "VxdAccept: NbtAccept returned " ) ;
+ DbgPrintNum( status ) ;
+ DbgPrint("\r\n") ;
+ }
+
+ //
+ // It's OK if the accept is pending because it's just the
+ // session setup acknowledgement
+ //
+ if ( status == TDI_PENDING )
+ status = TDI_SUCCESS ;
+
+ return status ;
+}
+
+/*******************************************************************
+
+ NAME: VxdAdapterStatus
+
+ SYNOPSIS: Gets the requested adapter status
+
+ ENTRY: pDeviceContext - Adapter status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES:
+
+ HISTORY:
+ Johnl 10-Aug-1993 Created
+
+********************************************************************/
+
+NCBERR VxdAdapterStatus( tDEVICECONTEXT * pDeviceContext,
+ NCB * pNCB,
+ ULONG Ipaddr
+ )
+{
+ TDI_STATUS status ;
+ PADAPTER_STATUS pAdapterStatus ;
+ ULONG ActualSize;
+ ULONG Size = pNCB->ncb_length ;
+
+ //
+ // Ipaddr will always be 0 except in one case: if we came here
+ // via nbtstat -A
+ //
+ if ( !Ipaddr && *pNCB->ncb_callname == '*' )
+ {
+ //
+ // Get the local adapter status
+ //
+ DbgPrint("VxdAdapterStatus: AStat for local (*)\r\n") ;
+ status = NbtQueryAdapterStatus( pDeviceContext,
+ &pAdapterStatus,
+ &Size ) ;
+ if ( !status || status == TDI_BUFFER_OVERFLOW )
+ {
+ ActualSize = min( pNCB->ncb_length, Size ) ;
+ CTEMemCopy( pNCB->ncb_buffer,
+ pAdapterStatus,
+ ActualSize) ;
+ pNCB->ncb_length = ActualSize;
+
+ CTEFreeMem( pAdapterStatus ) ;
+ CTEIoComplete( pNCB, status, 0 ) ;
+
+ //
+ // Return a successful status (buffer overflow denoted
+ // in NCB)
+ //
+ status = NRC_GOODRET ;
+ }
+ }
+ else
+ {
+
+ ULONG IpAddrsList[2];
+
+ IpAddrsList[0] = Ipaddr;
+ IpAddrsList[1] = 0;
+
+ status = NbtSendNodeStatus( pDeviceContext,
+ pNCB->ncb_callname,
+ pNCB,
+ IpAddrsList,
+ 0,
+ NodeStatusDone);
+ }
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdFindName
+
+ SYNOPSIS: Gets the requested adapter status
+
+ ENTRY: pDeviceContext - Adapter status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES:
+
+ HISTORY:
+ Johnl 04-Oct-1993 Created
+
+********************************************************************/
+
+NCBERR VxdFindName( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ TDI_STATUS status ;
+ TDI_CONNECTION_INFORMATION RequestInfo ;
+
+ DbgPrint("VxdFindName: Entered\r\n") ;
+ InitNBTDIConnectInfo( &RequestInfo, &tanb_global, pNCB->ncb_callname ) ;
+ status = NbtQueryFindName( &RequestInfo,
+ pDeviceContext,
+ pNCB,
+ FALSE ) ;
+
+ if ( status == STATUS_SUCCESS )
+ {
+ CTEIoComplete( pNCB, STATUS_SUCCESS, 0xffffffff ) ;
+ return STATUS_SUCCESS ;
+ }
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+/*******************************************************************
+
+ NAME: VxdSessionStatus
+
+ SYNOPSIS: Gets the requested Session status
+
+ ENTRY: pDeviceContext - Session status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES: VxdCopySessionStatus will automatically complete the NCB
+ if the buffer overflows. Otherwise we will.
+
+ HISTORY:
+ Johnl 23-Aug-1993 Created
+
+********************************************************************/
+
+NCBERR VxdSessionStatus( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ TDI_STATUS status = STATUS_SUCCESS ;
+ PSESSION_HEADER pSessionHeader = (PSESSION_HEADER) pNCB->ncb_buffer ;
+ PSESSION_BUFFER pSessionBuff ;
+ ULONG RemainingSize = pNCB->ncb_length ;
+ tNAMEADDR * pNameAddr = NULL ;
+ tCLIENTELE * pClientEle = NULL ;
+ tCLIENTELE * pClientEleBcast = NULL ;
+ USHORT NameType ;
+ PLIST_ENTRY pEntry ;
+ UCHAR i ;
+ NCBERR errNCB ;
+
+ if ( RemainingSize < sizeof(SESSION_HEADER) )
+ {
+ CTEIoComplete( pNCB, STATUS_INVALID_BUFFER_SIZE, 0 ) ;
+ return NRC_GOODRET ;
+ }
+
+ pSessionHeader->sess_name = 0 ;
+ pSessionHeader->num_sess = 0 ;
+ pSessionHeader->rcv_dg_outstanding = 0 ;
+ pSessionHeader->rcv_any_outstanding = 0 ;
+
+ //
+ // For broadcast datagram statistics
+ //
+ errNCB = VxdFindClientElement( pDeviceContext,
+ 0,
+ &pClientEleBcast,
+ CLIENT_BC ) ;
+ if ( errNCB )
+ return errNCB ;
+
+ //
+ // Get all sessions?
+ //
+ if ( pNCB->ncb_name[0] == '*' )
+ {
+ for ( i = 1 ; i <= pDeviceContext->cMaxSessions ; i++ )
+ {
+ if ( pDeviceContext->pSessionTable[i] != NULL )
+ {
+ pClientEle = pDeviceContext->pSessionTable[i]->pClientEle ;
+
+ //
+ // Both normal receives and broadcast receives are
+ // kept on the same list
+ //
+ COUNT_ELEMENTS( pClientEle->RcvDgramHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ COUNT_ELEMENTS( pClientEle->RcvAnyHead,
+ pSessionHeader->rcv_any_outstanding ) ;
+ }
+ }
+
+ //
+ // Only one broadcast client element per adapter
+ //
+ COUNT_ELEMENTS( pClientEleBcast->RcvDgramHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ COUNT_ELEMENTS( pDeviceContext->RcvDGAnyFromAnyHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ pSessionHeader->sess_name = 0xff ;
+
+ RemainingSize -= sizeof( SESSION_HEADER ) ;
+ pSessionBuff = (PSESSION_BUFFER) (pSessionHeader + 1) ;
+
+ //
+ // From this device context, traverse all of the Address elements
+ // and all of its Client elements and all of its Connect Elements
+ //
+ for ( pEntry = NbtConfig.AddressHead.Flink ;
+ pEntry != &NbtConfig.AddressHead && !status ;
+ pEntry = pEntry->Flink )
+ {
+ PLIST_ENTRY pEntryClient ;
+ tADDRESSELE * pAddrEle = CONTAINING_RECORD( pEntry,
+ tADDRESSELE,
+ Linkage ) ;
+ ASSERT( pAddrEle->Verify == NBT_VERIFY_ADDRESS ) ;
+
+ //
+ // Only get addresses for this adapter
+ //
+ if ( pAddrEle->pDeviceContext != pDeviceContext )
+ continue ;
+
+ for ( pEntryClient = pAddrEle->ClientHead.Flink ;
+ pEntryClient != &pAddrEle->ClientHead ;
+ pEntryClient = pEntryClient->Flink )
+ {
+ tCLIENTELE * pClientEle = CONTAINING_RECORD( pEntryClient,
+ tCLIENTELE,
+ Linkage ) ;
+ PLIST_ENTRY pEntryConn ;
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ||
+ pClientEle->Verify == NBT_VERIFY_CLIENT_DOWN ) ;
+
+ if (!VxdCopySessionStatus( pDeviceContext,
+ pClientEle,
+ pSessionHeader,
+ &pSessionBuff,
+ &RemainingSize ))
+ {
+ status = STATUS_BUFFER_OVERFLOW ;
+ break ;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( errNCB = VxdNameToClient( pDeviceContext,
+ pNCB->ncb_name,
+ &pSessionHeader->sess_name,
+ &pClientEle ))
+ {
+ return errNCB ;
+ }
+
+ COUNT_ELEMENTS( pClientEle->RcvDgramHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ COUNT_ELEMENTS( pClientEleBcast->RcvDgramHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ COUNT_ELEMENTS( pDeviceContext->RcvDGAnyFromAnyHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ COUNT_ELEMENTS( pClientEle->RcvAnyHead,
+ pSessionHeader->rcv_any_outstanding ) ;
+
+ RemainingSize -= sizeof( SESSION_HEADER ) ;
+ pSessionBuff = (PSESSION_BUFFER) (pSessionHeader + 1) ;
+ if ( !VxdCopySessionStatus( pDeviceContext,
+ pClientEle,
+ pSessionHeader,
+ &pSessionBuff,
+ &RemainingSize ))
+ {
+ status = STATUS_BUFFER_OVERFLOW ;
+ }
+ }
+
+ CTEIoComplete( pNCB,
+ status,
+ sizeof(SESSION_HEADER) +
+ pSessionHeader->num_sess * sizeof(SESSION_BUFFER) ) ;
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCopySessionStatus
+
+ SYNOPSIS: Copies all of the sessions associated with pClientEle
+
+ ENTRY: pDeviceContext - Adapter to use
+ pClientEle - Client to retrieve all sessions for
+ pSessionHeader - Session status header
+ pSessionBuff - Pointer to beginning of session buffers
+ pRemainingSize - Remaining size of buffer
+
+ RETURNS: TRUE if all session information was transferred,
+ FALSE if we ran out of buffer space
+
+ NOTES:
+
+ HISTORY:
+ Johnl 23-Aug-1993 Created
+
+********************************************************************/
+
+BOOL VxdCopySessionStatus( tDEVICECONTEXT * pDeviceContext,
+ tCLIENTELE * pClientEle,
+ PSESSION_HEADER pSessionHeader,
+ PSESSION_BUFFER * ppSessionBuff,
+ ULONG * pRemainingSize )
+{
+ PLIST_ENTRY pEntryConn ;
+ tCONNECTELE * pConnectEle ;
+
+ for ( pEntryConn = pClientEle->ConnectActive.Flink ;
+ pEntryConn != &pClientEle->ConnectActive ;
+ pEntryConn = pEntryConn->Flink )
+ {
+ PLIST_ENTRY pEntry ;
+ BOOL fFillRemote = FALSE ;
+ pConnectEle = CONTAINING_RECORD( pEntryConn,
+ tCONNECTELE,
+ Linkage ) ;
+ ASSERT( pConnectEle->Verify == NBT_VERIFY_CONNECTION ||
+ pConnectEle->Verify == NBT_VERIFY_CONNECTION_DOWN ) ;
+
+ if ( *pRemainingSize < sizeof(SESSION_BUFFER) )
+ {
+ return FALSE ;
+ }
+
+ *pRemainingSize -= sizeof(SESSION_BUFFER) ;
+ pSessionHeader->num_sess++ ;
+ (*ppSessionBuff)->rcvs_outstanding = 0 ;
+ (*ppSessionBuff)->sends_outstanding = 0 ; // Always 0
+ REQUIRE( !VxdFindLSN( pDeviceContext, pConnectEle, &(*ppSessionBuff)->lsn )) ;
+
+ COUNT_ELEMENTS( pConnectEle->RcvHead,
+ (*ppSessionBuff)->rcvs_outstanding ) ;
+
+ //
+ // Set the session state
+ //
+ switch ( pConnectEle->state )
+ {
+ case NBT_CONNECTING: // establishing Transport connection
+ if ( pConnectEle->Orig )
+ (*ppSessionBuff)->state = CALL_PENDING ;
+ else
+ (*ppSessionBuff)->state = LISTEN_OUTSTANDING ;
+ break ;
+
+ case NBT_SESSION_INBOUND: // waiting for a session request after tcp connectio
+ case NBT_SESSION_WAITACCEPT: // waiting for accept after a listen has been satis
+ (*ppSessionBuff)->state = LISTEN_OUTSTANDING ;
+ break ;
+
+ case NBT_SESSION_OUTBOUND: // waiting for a session response after tcp connecti
+ fFillRemote = TRUE ;
+ (*ppSessionBuff)->state = CALL_PENDING ;
+
+ case NBT_SESSION_UP: // got positive response
+ fFillRemote = TRUE ;
+ (*ppSessionBuff)->state = SESSION_ESTABLISHED ;
+ break ;
+
+ case NBT_DISCONNECTING: // sent a disconnect down to Tcp, but it hasn't comp
+ (*ppSessionBuff)->state = HANGUP_PENDING;
+ break ;
+
+ case NBT_DISCONNECTED: // a session has been disconnected but not closed wit
+ (*ppSessionBuff)->state = HANGUP_COMPLETE;
+ break ;
+
+ case NBT_IDLE: // Shouldn't be on ConnectActive list
+ case NBT_ASSOCIATED:
+ default:
+ ASSERT( FALSE ) ;
+ (*ppSessionBuff)->state = SESSION_ABORTED ;
+ break ;
+ }
+
+ //
+ // Copy local and/or remote name
+ //
+ CTEMemCopy( (*ppSessionBuff)->local_name,
+ pClientEle->pAddress->pNameAddr->Name,
+ NCBNAMSZ ) ;
+
+ if ( fFillRemote )
+ {
+ CTEMemCopy( (*ppSessionBuff)->remote_name,
+ pConnectEle->RemoteName,
+ NCBNAMSZ ) ;
+ }
+
+ (*ppSessionBuff)++ ;
+ }
+
+ return TRUE ;
+}
+
+/*******************************************************************
+
+ NAME: VxdReset
+
+ SYNOPSIS: Clears out the name tables and completes all outstanding NCBs
+
+ ENTRY: pDeviceContext - Adapter status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES: If a session is active then we have to wait till we disconnect
+ the connection before deleting the name. We keep count of the
+ active sessions and call the VxdResetContinue function after
+ all session disconnects have been completed.
+
+ It is assumed this is made as a "wait" call.
+
+ HISTORY:
+ Johnl 16-Aug-1993 Created
+
+********************************************************************/
+
+NCBERR VxdReset( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ UCHAR i ;
+ TDI_STATUS tdistatus ;
+ PLIST_ENTRY pHead, pEntry ;
+ PRESET_CONTEXT pRstCont = (PRESET_CONTEXT) pNCB->ncb_reserve ;
+
+ pRstCont->cActiveSessions = 0 ;
+ pRstCont->cActiveNames = 0 ;
+ pRstCont->errncb = NRC_GOODRET ;
+
+ //
+ // Kill off all of the Receive any from any NCBs
+ //
+ while ( !IsListEmpty(&pDeviceContext->RcvAnyFromAnyHead))
+ {
+ PRCV_CONTEXT prcvCont ;
+ pEntry = RemoveHeadList( &pDeviceContext->RcvAnyFromAnyHead ) ;
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ CTEIoComplete( prcvCont->pNCB,
+ STATUS_CONNECTION_DISCONNECTED,
+ 0 ) ;
+ }
+
+ //
+ // Kill off all of the Receive any datagrams from any
+ //
+ while ( !IsListEmpty(&pDeviceContext->RcvDGAnyFromAnyHead))
+ {
+ tRCVELE * pRcvEle ;
+ pEntry = RemoveHeadList( &pDeviceContext->RcvDGAnyFromAnyHead ) ;
+ pRcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+ CTEIoComplete( pRcvEle->pIrp,
+ STATUS_NETWORK_NAME_DELETED, // NRC_NAMERR
+ 0 ) ;
+ CTEMemFree( pRcvEle ) ;
+ }
+
+ //
+ // Disconnect all sessions
+ //
+ for ( i = 1 ; i <= pDeviceContext->cMaxSessions ; i++ )
+ {
+ //
+ // This will also prevent any listens from being accepted on the
+ // connection
+ //
+ if ( pDeviceContext->pSessionTable[i] != NULL )
+ {
+ TDI_REQUEST Request ;
+ ULONG TimeOut = DISCONNECT_TIMEOUT ;
+ tCONNECTELE * pConnEle= pDeviceContext->pSessionTable[i] ;
+
+ Request.Handle.ConnectionContext = pConnEle ;
+ pRstCont->cActiveSessions++ ;
+ tdistatus = NbtDisconnect( &Request,
+ &TimeOut,
+ TDI_DISCONNECT_RELEASE,
+ NULL,
+ NULL,
+ pNCB ) ;
+
+ if ( tdistatus != TDI_PENDING )
+ {
+ pRstCont->cActiveSessions-- ;
+ tdistatus = NbtCloseConnection( &Request,
+ NULL,
+ pDeviceContext,
+ NULL ) ;
+ REQUIRE( NBUnregister( pDeviceContext, i, NB_SESSION )) ;
+ }
+ }
+ }
+
+ //
+ // If no active sessions, then go ahead and delete all the names
+ //
+ if ( !pRstCont->cActiveSessions )
+ {
+ pRstCont->cActiveSessions = -1 ;
+ return VxdResetContinue( pDeviceContext, pNCB ) ;
+ }
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdResetContinue
+
+ SYNOPSIS: Finishes the reset after all sessions have been successfully
+ shutdown
+
+ ENTRY: pDeviceContext - Adapter status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES:
+
+ HISTORY:
+ Johnl 16-Aug-1993 Created
+
+********************************************************************/
+
+NCBERR VxdResetContinue( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ UCHAR i ;
+ TDI_STATUS tdistatus ;
+ PLIST_ENTRY pHead, pEntry ;
+ PRESET_CONTEXT pRstCont = (PRESET_CONTEXT) pNCB->ncb_reserve ;
+ PNCB pNCBPerm ;
+
+ DbgPrint("VxdResetContinue entered\r\n") ;
+
+ //
+ // Now that all of the sessions have been disconnected, close each
+ // connection
+ //
+ for ( i = 1 ; i <= pDeviceContext->cMaxSessions ; i++ )
+ {
+ if ( pDeviceContext->pSessionTable[i] != NULL )
+ {
+ TDI_REQUEST Request ;
+ tCONNECTELE * pConnEle = pDeviceContext->pSessionTable[i] ;
+ Request.Handle.ConnectionContext = pConnEle ;
+
+ tdistatus = NbtCloseConnection( &Request,
+ NULL,
+ pDeviceContext,
+ NULL ) ;
+ REQUIRE( NBUnregister( pDeviceContext, i, NB_SESSION )) ;
+ }
+ }
+
+ //
+ // Delete all the names (including the permanent name)
+ //
+ for ( i = 0 ; i <= pDeviceContext->cMaxNames ; i++ )
+ {
+ if ( pDeviceContext->pNameTable[i] != NULL )
+ {
+ TDI_REQUEST Request ;
+
+ Request.Handle.ConnectionContext = pDeviceContext->pNameTable[i] ;
+ pRstCont->cActiveNames++ ;
+
+ tdistatus = NbtCloseAddress( &Request,
+ NULL, //&RequestStatus,
+ pDeviceContext,
+ pNCB ) ;
+ if ( tdistatus != TDI_PENDING )
+ pRstCont->cActiveNames-- ;
+
+ //
+ // Go ahead and remove the name from the table since nobody
+ // will be able to re-register with it since this is a "wait" cmd
+ //
+ REQUIRE( NBUnregister( pDeviceContext, i, NB_NAME )) ;
+
+ }
+ }
+
+ //
+ // Resize the session table If an error occurs, keep the old
+ // session table.
+ //
+ if ( pNCB->ncb_lsn != pDeviceContext->cMaxSessions )
+ {
+ UCHAR MaxSess = (UCHAR) pNCB->ncb_lsn ? pNCB->ncb_lsn : 6 ;
+ PVOID pSess = CTEAllocMem((USHORT)((MaxSess+1)*sizeof(tCONNECTELE*))) ;
+
+ if ( !pSess )
+ {
+ pRstCont->errncb = NRC_NORESOURCES ;
+ }
+ else
+ {
+ CTEFreeMem( pDeviceContext->pSessionTable ) ;
+ pDeviceContext->cMaxSessions = MaxSess ;
+ pDeviceContext->pSessionTable = pSess ;
+ CTEZeroMemory( &pDeviceContext->pSessionTable[0],
+ (pDeviceContext->cMaxSessions+1)*sizeof(tCONNECTELE*) ) ;
+ }
+ }
+
+ //
+ // Set current session/name numbers back to 1
+ //
+ pDeviceContext->iNcbNum = 1 ;
+ pDeviceContext->iLSNum = 1 ;
+
+ //
+ // re-add the permanent name for this adapter, non-fatal if it fails
+ //
+
+
+ if ( !NT_SUCCESS( NbtAddPermanentName( pDeviceContext )))
+ {
+ CDbgPrint( DBGFLAG_ERROR,
+ ("VxdResetContinue: Warning - Failed to add permanent name")) ;
+ }
+
+ if ( !pRstCont->cActiveNames )
+ CTEIoComplete( pNCB, NRC_GOODRET, 0 ) ;
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCancel
+
+ SYNOPSIS: Attempts to cancel the NCB pointed at by ncb_buffer
+
+ ENTRY: pDeviceContext - Adapter status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES:
+
+ HISTORY:
+ Johnl 18-Aug-1993 Created
+
+********************************************************************/
+
+NCBERR VxdCancel( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ NCB * pNCBCancelled = (NCB*) pNCB->ncb_buffer ;
+ tCONNECTELE * pConnEle ;
+ tCLIENTELE * pClientEle ;
+ NCBERR errNCB = NRC_GOODRET ;
+ TDI_STATUS tdistatus ;
+ PLIST_ENTRY pHead, pEntry ;
+ USHORT NameType ;
+ tNAMEADDR * pNameAddr ;
+ tLISTENREQUESTS * pListen ;
+ PRCV_CONTEXT prcvCont ; // Used for session receives
+ tRCVELE * prcvEle ; // Used for Datagram receives
+
+ if ( pNCB->ncb_lana_num != pNCBCancelled->ncb_lana_num )
+ {
+ DbgPrint("VxdCancel: Attempt to cancel NCB w/ different lana\r\n") ;
+ return NRC_BRIDGE ;
+ }
+
+ if ( pNCB->ncb_retcode != NRC_PENDING )
+ return NRC_CANOCCR ;
+
+ switch ( pNCBCancelled->ncb_command & ~ASYNCH )
+ {
+ case NCBSEND:
+ case NCBSENDNA:
+ case NCBCHAINSEND:
+ case NCBCHAINSENDNA:
+ case NCBRECV:
+ //
+ // Cancelling a session NCB automatically closes the session
+ //
+ if ( VxdFindConnectElement( pDeviceContext,
+ pNCBCancelled,
+ &pConnEle ))
+ {
+ DbgPrint("VxdCancel: Attempted to cancel send NCB on non-existent session\r\n") ;
+ break ;
+ }
+
+ if ( (pNCBCancelled->ncb_command & ~ASYNCH) == NCBRECV )
+ {
+ errNCB = NRC_CANOCCR ;
+ for ( pEntry = pConnEle->RcvHead.Flink ;
+ pEntry != &pConnEle->RcvHead ;
+ pEntry = pEntry->Flink )
+ {
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ if ( prcvCont->pNCB == pNCBCancelled )
+ {
+ RemoveEntryList( pEntry ) ;
+ CTEIoComplete( prcvCont->pNCB, STATUS_CANCELLED, 0 ) ;
+ errNCB = NRC_GOODRET ;
+ break ;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Sends are immediately submitted to the transport, tell
+ // caller it's too late to cancel. The transport will complete
+ // the NCB when we close the connection below.
+ //
+ errNCB = NRC_CANOCCR ;
+ }
+
+ REQUIRE( !VxdCompleteSessionNcbs( pDeviceContext, pConnEle )) ;
+ VxdTearDownSession( pDeviceContext,
+ pConnEle,
+ NULL,
+ NULL ) ;
+ //
+ // Only remove from table if we've told the client
+ //
+ if ( pConnEle->Flags & NB_CLIENT_NOTIFIED )
+ {
+ REQUIRE( NBUnregister( pDeviceContext,
+ pNCBCancelled->ncb_lsn,
+ NB_SESSION )) ;
+ }
+ break ;
+
+ case NCBCANCEL:
+ errNCB = NRC_CANCEL ; // Can't cancel a cancel
+ break ;
+
+ case NCBLISTEN:
+ //
+ // Lookup the Client Element associated with this name, then scan
+ // the listen NCBs for one that matches the one being cancelled
+ //
+ if ( errNCB = VxdNameToClient( pDeviceContext,
+ pNCBCancelled->ncb_name,
+ NULL,
+ &pClientEle ))
+ {
+ DbgPrint("VxdCancel: Tried to cancel listen on non-existent name\r\n") ;
+ errNCB = NRC_CANOCCR ;
+ break ;
+ }
+
+ errNCB = NRC_CANOCCR ;
+ for ( pEntry = pClientEle->ListenHead.Flink ;
+ pEntry != &pClientEle->ListenHead ;
+ pEntry = pEntry->Flink )
+ {
+ pListen = CONTAINING_RECORD( pEntry, tLISTENREQUESTS, Linkage ) ;
+ if ( pListen->pIrp == pNCBCancelled )
+ {
+ DbgPrint("VxdCancel: Cancelling NCB 0x") ;
+ DbgPrintNum( (ULONG) pNCBCancelled ) ; DbgPrint("\r\n") ;
+ RemoveEntryList( &pListen->Linkage ) ;
+ CTEIoComplete( pNCBCancelled, STATUS_CANCELLED, 0 ) ;
+ CTEMemFree( pListen ) ;
+ errNCB = NRC_GOODRET ;
+ break ;
+ }
+ }
+ break ;
+
+ case NCBCALL:
+ //
+ // Search the ConnectActive list for our NCB and cleanup that
+ // connection
+ //
+ if ( errNCB = VxdNameToClient( pDeviceContext,
+ pNCBCancelled->ncb_name,
+ NULL,
+ &pClientEle ))
+ {
+ DbgPrint("VxdCancel: Tried to cancel call on non-existent name\r\n") ;
+ errNCB = NRC_CANOCCR ;
+ break ;
+ }
+
+ errNCB = NRC_CANOCCR ;
+ for ( pEntry = pClientEle->ConnectActive.Flink ;
+ pEntry != &pClientEle->ConnectActive ;
+ pEntry = pEntry->Flink )
+ {
+ pConnEle = CONTAINING_RECORD( pEntry, tCONNECTELE, Linkage ) ;
+ if ( pConnEle->pIrp == pNCBCancelled )
+ {
+ tDGRAM_SEND_TRACKING * pTracker = (tDGRAM_SEND_TRACKING*)
+ pConnEle->pIrpRcv ;
+
+ //
+ // if it's too late, just say we can't cancel it
+ //
+ if (pConnEle->state >= NBT_SESSION_OUTBOUND)
+ {
+ errNCB = NRC_CANOCCR ;
+ break;
+ }
+
+ //
+ // yes, we can cancel it. we just mark the tracker to say
+ // this call is cancelled: both the original ncb and this
+ // cancel ncb will get completed at some stage.
+ //
+ DbgPrint("VxdCancel: Cancelling NCB 0x") ;
+ DbgPrintNum( (ULONG) pNCBCancelled ) ; DbgPrint("\r\n") ;
+
+ pTracker->Flags |= TRACKER_CANCELLED;
+ pConnEle->pIrpDisc = pNCB;
+
+ return NRC_GOODRET ;
+ }
+ }
+ break ;
+
+ case NCBDGRECV:
+ if ( pNCBCancelled->ncb_num == ANY_NAME )
+ {
+ pHead = &pDeviceContext->RcvDGAnyFromAnyHead ;
+ }
+ else
+ {
+ if ( errNCB = VxdFindClientElement( pDeviceContext,
+ pNCBCancelled->ncb_num,
+ &pClientEle,
+ CLIENT_LOCAL ) )
+ {
+ ASSERT( FALSE ) ;
+ break ;
+ }
+ pHead = &pClientEle->RcvDgramHead ;
+ }
+
+ errNCB = NRC_CANOCCR ;
+ for ( pEntry = pHead->Flink ;
+ pEntry != pHead ;
+ pEntry = pEntry->Flink )
+ {
+ prcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+
+ if ( prcvEle->pIrp == pNCBCancelled )
+ {
+ RemoveEntryList( pEntry ) ;
+ CTEIoComplete( pNCBCancelled, STATUS_CANCELLED, 0 ) ;
+ CTEMemFree( prcvEle ) ;
+ errNCB = NRC_GOODRET ;
+ break ;
+ }
+ }
+ break ;
+
+ case NCBDGRECVBC:
+ //
+ // For receive broadcast datagrams, we have to look through the list
+ // of clients on the Broadcast Address.
+ //
+ errNCB = VxdFindClientElement( pDeviceContext,
+ 0,
+ &pClientEle,
+ CLIENT_BC ) ;
+ if ( !errNCB )
+ {
+ errNCB = NRC_CANOCCR ;
+ for ( pEntry = pClientEle->RcvDgramHead.Flink ;
+ pEntry != &pClientEle->RcvDgramHead ;
+ pEntry = pEntry->Flink )
+ {
+ prcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+ if ( prcvEle->pIrp == pNCBCancelled )
+ {
+ RemoveEntryList( pEntry ) ;
+ CTEMemFree( prcvEle ) ;
+ CTEIoComplete( pNCBCancelled, STATUS_CANCELLED, 0 ) ;
+ errNCB = NRC_GOODRET ;
+ break ;
+ }
+ }
+ }
+ break ;
+
+ case NCBRECVANY:
+ if ( pNCBCancelled->ncb_num == ANY_NAME )
+ pHead = &pDeviceContext->RcvAnyFromAnyHead ;
+ else
+ {
+ if ( errNCB = VxdFindClientElement( pDeviceContext,
+ pNCBCancelled->ncb_num,
+ &pClientEle,
+ CLIENT_LOCAL ) )
+ {
+ ASSERT( FALSE ) ;
+ break ;
+ }
+ pHead = &pClientEle->RcvAnyHead ;
+ }
+
+ errNCB = NRC_CANOCCR ;
+ pEntry = pHead->Flink ;
+ while ( pEntry != pHead )
+ {
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ if ( prcvCont->pNCB == pNCBCancelled )
+ {
+ RemoveEntryList( pEntry ) ;
+ CTEIoComplete( prcvCont->pNCB, STATUS_CANCELLED, 0 ) ;
+ errNCB = NRC_GOODRET ;
+ break ;
+ }
+ pEntry = pEntry->Flink ;
+ }
+ break ;
+
+ default:
+ errNCB = NRC_CANCEL ;
+ }
+
+
+ CTEIoComplete( pNCB, errNCB, 0 ) ;
+
+ //
+ // No, no! Don't touch that ncb after completing it!
+ //
+ //pNCB->ncb_retcode = errNCB ;
+ //pNCB->ncb_cmd_cplt = errNCB ;
+
+ return errNCB ;
+}
+
+/*******************************************************************
+
+ NAME: VxdIoComplete
+
+ SYNOPSIS: Let's the NCB know that all processing is done by setting
+ the command completion fields and calling the post routine
+ if available.
+
+ ENTRY: pirp - Pointer to the NCB to notify that we are done
+ (or NULL if this didn't come from the Netbios I/F
+ status - Status of the completion
+ ulExtra - Extra parameter
+
+ NOTES: This is the procedure that CTEIoComplete maps to and is
+ roughly equivilent to "completing" an IRP.
+
+ HISTORY:
+ Johnl 27-Apr-1993 Created
+
+********************************************************************/
+
+VOID VxdIoComplete( PCTE_IRP pirp,
+ NTSTATUS status,
+ ULONG ulExtra )
+{
+ NCB * pNCB = pirp ;
+ NCBERR errNCB = NRC_GOODRET ;
+ PSESS_SETUP_CONTEXT pSessSetupCont ;
+ BOOL fAsync ;
+ tDEVICECONTEXT * pDeviceContext ;
+ PRESET_CONTEXT pRstCont ;
+ PSEND_CONTEXT pSendCont ;
+ tCONNECTELE * pConnEle ;
+
+ DbgPrint("VxdIoComplete: Completing NCB; Cmd, Addr, TDI status: 0x") ;
+ if ( pNCB )
+ {
+ DbgPrintNum( pNCB->ncb_command ) ;
+ DbgPrint(" 0x") ; DbgPrintNum( (ULONG) pNCB ) ;
+ DbgPrint(" 0x") ; DbgPrintNum( status ) ;
+ DbgPrint("\r\n") ;
+ }
+ else
+ DbgPrint("NULL\r\n") ;
+
+ //
+ // If no NCB to complete then we're done
+ //
+ if ( !pNCB )
+ return ;
+
+ fAsync = !!(pNCB->ncb_command & ASYNCH) ;
+
+ pDeviceContext = GetDeviceContext( pNCB ) ;
+
+ ASSERT(pDeviceContext);
+
+ //
+ // Note that we drop through the below case statement even if an error
+ // occurred because some commands need to free stuff before completing
+ // the NCB.
+ //
+ if ( status != STATUS_SUCCESS &&
+ ( pNCB->ncb_command & ~ASYNCH) != NCBCANCEL )
+ {
+ errNCB = MapTDIStatus2NCBErr( status ) ;
+ }
+
+ //
+ // Fill in any items in the NCB struct if necessary
+ //
+ switch( pNCB->ncb_command & ~ASYNCH )
+ {
+ case NCBRECVANY: // lsn was set when the receive was posted
+ case NCBRECV:
+ FreeRcvContext( *((PRCV_CONTEXT*)&pNCB->ncb_reserve) ) ;
+ if ( errNCB && errNCB != NRC_INCOMP )
+ {
+ break ;
+ }
+
+ ASSERT( ulExtra <= 0xffff ) ;
+ ASSERT( pNCB->ncb_length >= ulExtra ) ;
+ pNCB->ncb_length = (WORD) ulExtra ;
+
+ DbgPrint("\tSetting length to 0x") ;
+ DbgPrintNum( ulExtra ) ;
+ DbgPrint("\r\n") ;
+ break ;
+
+ case NCBSSTAT:
+ case NCBDGRECV:
+ case NCBDGRECVBC:
+ if ( errNCB && errNCB != NRC_INCOMP )
+ break ;
+
+ ASSERT( ulExtra <= 0xffff ) ;
+ ASSERT( pNCB->ncb_length >= ulExtra ) ;
+ pNCB->ncb_length = (WORD) ulExtra ;
+
+ DbgPrint("\tSetting length to 0x") ;
+ DbgPrintNum( ulExtra ) ;
+ DbgPrint("\r\n") ;
+ break ;
+
+ case NCBASTAT:
+ case NCBFINDNAME:
+ if ( errNCB && errNCB != NRC_INCOMP )
+ break ;
+
+ if ( ulExtra != 0xffffffff ) // Means buffer length already set
+ pNCB->ncb_length = (WORD) ulExtra ;
+
+ DbgPrint("\tAStat/Findname length is 0x") ;
+ DbgPrintNum( (ULONG) pNCB->ncb_length ) ;
+ DbgPrint("\r\n") ;
+ break ;
+
+ case NCBSEND:
+ case NCBSENDNA:
+ case NCBCHAINSEND:
+ case NCBCHAINSENDNA:
+ pSendCont = (PSEND_CONTEXT) pNCB->ncb_reserve ;
+ if ( errNCB )
+ {
+ //
+ // Sends are immediately given to the transport, so if a
+ // timeout occurs, we'll first be completed by the timeout
+ // code, then we'll be completed by the transport closing
+ // the connection.
+ //
+
+ if ( errNCB != NRC_CMDTMO &&
+ pSendCont->STO == NCB_TIMED_OUT )
+ {
+ //
+ // The transport has completed this NCB in response to the
+ // Close connection because of a send timeout. Map the
+ // error to timeout and complete back to the client. The
+ // session is dead so don't disconnect it again. The send
+ // has already been removed from the timeout list.
+ //
+ errNCB = NRC_CMDTMO ;
+ }
+ else
+ {
+ BOOL fTimedOutNCB = pSendCont->STO == NCB_TIMED_OUT ;
+
+ //
+ // Remove from timeout list
+ //
+ if ( pSendCont->STO != NCB_INFINITE_TIME_OUT )
+ RemoveEntryList( &pSendCont->ListEntry ) ;
+
+ //
+ // Kill the session
+ //
+ if ( VxdFindConnectElement( pDeviceContext,
+ pNCB,
+ &pConnEle ))
+
+ {
+ //
+ // There maybe multiple sends on this session, only the
+ // first should disconnect
+ //
+ CTEFreeMem( pSendCont->pHdr ) ;
+ DbgPrint("VxdIoComplete: Error occurred on non-existent session\r\n") ;
+ break ;
+ }
+
+ REQUIRE( !VxdCompleteSessionNcbs( pDeviceContext, pConnEle )) ;
+
+ //
+ // Only remove from table if we've told the client
+ //
+ if ( pConnEle->Flags & NB_CLIENT_NOTIFIED )
+ {
+ REQUIRE( NBUnregister( pDeviceContext,
+ pNCB->ncb_lsn,
+ NB_SESSION )) ;
+ }
+
+ VxdTearDownSession( pDeviceContext,
+ pConnEle,
+ NULL,
+ NULL ) ;
+
+ if ( fTimedOutNCB ) // pSendCont may already have been freed
+ {
+ //
+ // The Close Connection above will cause the transport to
+ // complete this send with a session closed error, wait
+ // for that before completing back to the client.
+ //
+ return ;
+ }
+ }
+ }
+ else
+ {
+ if ( pSendCont->STO != NCB_INFINITE_TIME_OUT )
+ RemoveEntryList( &pSendCont->ListEntry ) ;
+ }
+ FreeSessionHdr( pSendCont->pHdr ) ;
+ break ;
+
+ case NCBDGSEND:
+ case NCBDGSENDBC:
+ //
+ // Nothing to do
+ //
+ break ;
+
+ //
+ // Need to set the ncb_num field for the following commands. Note
+ // that the ulExtra parameter will contain a pointer to the address
+ // element that was just added for this name.
+ //
+ case NCBADDNAME:
+ case NCBADDGRNAME:
+ if ( errNCB )
+ break ;
+
+ if ( !NBRegister( pDeviceContext,
+ &pNCB->ncb_num,
+ (tCLIENTELE *) ulExtra,
+ NB_NAME ))
+ {
+ TDI_REQUEST Request ;
+ TDI_STATUS tdistatus ;
+
+ errNCB = NRC_NAMTFUL ;
+ Request.Handle.ConnectionContext = (tCLIENTELE *) ulExtra ;
+ tdistatus = NbtCloseAddress( &Request,
+ NULL, //&RequestStatus,
+ pDeviceContext,
+ NULL ) ;
+ ASSERT( NT_SUCCESS( tdistatus )) ;
+ }
+ else
+ {
+ DbgPrint("\tRegistered Name number ") ;
+ DbgPrintNum( pNCB->ncb_num ) ;
+ DbgPrint(" for Address Element ") ;
+ DbgPrintNum( ulExtra ) ;
+ DbgPrint("\r\n") ;
+ }
+ break ;
+
+#if 0
+ //
+ // Private NBT NCB type for processing the permanent name
+ //
+ case NCBADD_PERMANENT_NAME:
+ CTEFreeMem( pNCB ) ;
+
+ if ( errNCB )
+ {
+ DbgPrint("VxdIoComplete: Failed to add permanent name!\r\n") ;
+ }
+ else
+ {
+ ASSERT( pDeviceContext->pNameTable[0] == NULL ) ;
+ pDeviceContext->pNameTable[0] = (tCLIENTELE *) ulExtra ;
+ }
+ //
+ // Don't do any further processing of this NCB. Not only did
+ // we just free it, nobody is looking for it.
+ //
+ return ;
+#endif
+
+ case NCBCALL:
+ case NCBLISTEN:
+ pSessSetupCont = (PSESS_SETUP_CONTEXT) pNCB->ncb_reserve ;
+
+ if ( errNCB )
+ {
+ VxdTearDownSession( pDeviceContext,
+ pSessSetupCont->pConnEle,
+ pSessSetupCont,
+ NULL ) ;
+ break ;
+ }
+
+ //
+ // Put the connection in our LSN table and copy out the connecting
+ // name if necessary
+ //
+ if ( !NBRegister( pDeviceContext,
+ &pNCB->ncb_lsn,
+ (tCONNECTELE *) ulExtra,
+ NB_SESSION ))
+ {
+ VxdTearDownSession( pDeviceContext,
+ (tCONNECTELE *) ulExtra,
+ NULL,
+ NULL ) ;
+ errNCB = NRC_LOCTFUL ;
+ }
+ else
+ {
+ tCONNECTELE * pConnEle = (tCONNECTELE*) ulExtra ;
+
+ //
+ // Were we listenning for '*'? If so, copy out the connecting
+ // name.
+ //
+ if ( pSessSetupCont->fIsWorldListen )
+ {
+ DbgPrint( "VxdIoComplete: World listen accepted \"" ) ;
+ DbgPrint( pConnEle->RemoteName ) ;
+ DbgPrint("\" for connection endpoint\r\n") ;
+
+ CTEMemCopy( pNCB->ncb_callname,
+ pConnEle->RemoteName,
+ NCBNAMSZ ) ;
+ }
+
+ ((tCONNECTELE *)ulExtra)->RTO = pNCB->ncb_rto ;
+ ((tCONNECTELE *)ulExtra)->STO = pNCB->ncb_sto ;
+ ((tCONNECTELE *)ulExtra)->Flags = 0 ;
+
+ //
+ // Don't delete the connection element until the client has been
+ // notified that the connection is down
+ //
+ ((tCONNECTELE *)ulExtra)->RefCount++ ;
+
+ DbgPrint("\tRegistered Session number ") ;
+ DbgPrintNum( pNCB->ncb_lsn ) ;
+ DbgPrint(" for Connection Element ") ;
+ DbgPrintNum( (ULONG) pConnEle ) ;
+ DbgPrint("\r\n") ;
+ }
+
+ FreeSessSetupContext( pSessSetupCont ) ;
+
+ //
+ // If we're in WAITACCEPT, then this is a Listen that needs to
+ // be accepted
+ //
+ if ( ((tCONNECTELE *)ulExtra)->state == NBT_SESSION_WAITACCEPT )
+ {
+ //
+ // Accept the connection
+ //
+ VxdAccept( (tCONNECTELE *) ulExtra, NULL ) ;
+ }
+ break ;
+
+ case NCBRESET:
+ pRstCont = (PRESET_CONTEXT) pNCB->ncb_reserve ;
+ if ( pRstCont->cActiveSessions != -1 ||
+ pRstCont->cActiveNames )
+ {
+ DbgPrint("VxdIoComplete: Disconnect/Name de-reg completed from Reset, remaining disconnects, names: ") ;
+ DbgPrintNum( pRstCont->cActiveSessions ) ;
+ DbgPrintNum( pRstCont->cActiveNames ) ; DbgPrint("\r\n") ;
+
+ //
+ // Only complete the Reset NCB after all session have been
+ // disconnected and the names have been released on the network
+ //
+ if ( pRstCont->cActiveSessions != -1 )
+ {
+ if ( --pRstCont->cActiveSessions == 0 )
+ {
+ //
+ // Starts the name deletion process
+ //
+ pRstCont->cActiveSessions = -1 ;
+ VxdResetContinue( pDeviceContext, pNCB ) ;
+ }
+
+ return ;
+ }
+
+ if ( --pRstCont->cActiveNames != 0 )
+ {
+ return ;
+ }
+ }
+
+ if ( !errNCB )
+ errNCB = pRstCont->errncb ;
+
+ // Fall through
+
+ case NCBUNLINK:
+ pNCB->ncb_retcode = errNCB ;
+ pNCB->ncb_cmd_cplt = errNCB ;
+ goto SkipPost ;
+
+ case NCBCANCEL:
+ pNCB->ncb_retcode = errNCB ;
+ pNCB->ncb_cmd_cplt = errNCB ;
+ break;
+
+ case NCBHANGUP:
+ case NCBDELNAME:
+ case NCBTRACE:
+ break ;
+
+ default:
+ DbgPrint("VxdIoComplete: Unexpected NCB command: 0x") ;
+ DbgPrintNum( pNCB->ncb_command ) ; DbgPrint("\r\n") ;
+ break ;
+ }
+
+ if ( pNCB->ncb_retcode == NRC_PENDING )
+ {
+ pNCB->ncb_retcode = errNCB ;
+ pNCB->ncb_cmd_cplt = errNCB ;
+ }
+ else
+ {
+ if ( (pNCB->ncb_command & ~ASYNCH) != NCBCANCEL )
+ {
+ CTEPrint("VxdIoComplete: ncb_retcode already set!\r\n") ;
+ CTEPrint("\tCommand: 0x") ; DbgPrintNum(pNCB->ncb_command) ;
+ CTEPrint(" NCB Address: 0x") ; DbgPrintNum( (ULONG) pNCB ) ;
+ }
+ goto SkipPost ;
+ }
+
+ //
+ // call the post-routine only if this was a no-wait call and if
+ // the post-routine has been specified!
+ //
+ if ( fAsync && pNCB->ncb_post )
+ {
+ typedef void (CALLBACK * VXDNCBPost )( void ) ;
+ VXDNCBPost ncbpost = (VXDNCBPost) pNCB->ncb_post ;
+
+ //
+ // Clients are expecting EBX to point to the NCB (instead of
+ // pushing it on the stack...). The post routine may trash
+ // ebp also, so save it.
+ //
+ _asm push ebp ;
+ _asm mov ebx, pNCB ;
+ ncbpost() ;
+ _asm pop ebp ;
+ }
+
+SkipPost:
+ //
+ // Now that we've completed the NCB, unblock if it was a Wait NCB
+ //
+ if ( !fAsync )
+ {
+ PBLOCKING_NCB_CONTEXT pBlkNcbContext;
+ PLIST_ENTRY pHead, pEntry ;
+
+ //
+ // find the blocking ncb context from the list corresponding to this ncb
+ //
+ pHead = &NbtConfig.BlockingNcbs;
+ pEntry = pHead->Flink;
+ while( pEntry != pHead )
+ {
+ pBlkNcbContext = CONTAINING_RECORD( pEntry, BLOCKING_NCB_CONTEXT, Linkage ) ;
+ if (pBlkNcbContext->pNCB == pNCB)
+ break;
+ else
+ pBlkNcbContext = NULL;
+ pEntry = pEntry->Flink;
+ }
+
+ if (pBlkNcbContext)
+ {
+ ASSERT(pBlkNcbContext->Verify == NBT_VERIFY_BLOCKING_NCB);
+
+ //
+ // if the ncb is blocked for completion, remove the context from
+ // the list first (important!) and then signal the thread that we
+ // are done. Then free the memory.
+ //
+ if ( pBlkNcbContext->fBlocked )
+ {
+ RemoveEntryList(&pBlkNcbContext->Linkage);
+ CTESignal( pBlkNcbContext->pWaitNCBBlock, 0 ) ;
+ CTEFreeMem(pBlkNcbContext->pWaitNCBBlock);
+ CTEFreeMem(pBlkNcbContext);
+ }
+ else
+ {
+ pBlkNcbContext->fNCBCompleted = TRUE;
+ }
+ }
+ else
+ {
+ DbgPrint("VxdIoComplete: didn't find blocking ncb context\r\n") ;
+ DbgPrint("for NCB Address: 0x") ; DbgPrintNum( (ULONG) pNCB ) ;
+ }
+ }
+}
+
+/*******************************************************************
+
+ NAME: VxdInitSessionSetup
+
+ SYNOPSIS: Common initialization required for Call and Listen
+
+ ENTRY: pDeviceContext - Adapter to setup on
+ pRequest - Request to fill in if successful
+ ppSessSetupContext - Context to be filled
+ pNCB - NCB doing the call/listen
+
+ EXIT:
+
+ RETURNS: NRC_GOODRET if successful, error code otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 26-May-1993 Created
+
+********************************************************************/
+
+NCBERR VxdInitSessionSetup( tDEVICECONTEXT * pDeviceContext,
+ TDI_REQUEST * pRequest,
+ PSESS_SETUP_CONTEXT * ppSessSetupContext,
+ NCB * pNCB )
+{
+ NTSTATUS status;
+ NCBERR errNCB ;
+ TDI_REQUEST_STATUS RequestStatus ;
+ tCLIENTELE * pClientEle ;
+ tCONNECTELE * pConnEle ;
+ tNAMEADDR * pNameAddr ;
+ USHORT NameType ;
+ BOOL fIsListen = ((pNCB->ncb_command & ~ASYNCH)
+ == NCBLISTEN) ;
+
+ *ppSessSetupContext = NULL ;
+
+ //
+ // Lookup the Client Element associated with this name and verify
+ // it's valid
+ //
+ if ( errNCB = VxdNameToClient( pDeviceContext,
+ pNCB->ncb_name,
+ NULL,
+ &pClientEle ))
+ {
+ return errNCB ;
+ }
+
+ if ( pClientEle->fDeregistered )
+ return NRC_NOWILD ;
+
+ //
+ // Request.Handle.ConnectionContext will contain Connection
+ // element after we open the connection
+ //
+ if ( status = NbtOpenConnection( pRequest,
+ NULL, //ConnectionContext, // Passed to connect and disconnect handlers
+ pDeviceContext ) )
+ {
+ return MapTDIStatus2NCBErr( status ) ;
+ }
+
+ //
+ // Initialize the connection context (used by Vxd disconnect handler)
+ //
+ pConnEle = (tCONNECTELE *) pRequest->Handle.ConnectionContext ;
+ pConnEle->ConnectContext = pConnEle ;
+
+ if ( status = NbtAssociateAddress( pRequest,
+ pClientEle,
+ NULL ))
+ {
+ goto ErrorExit1 ;
+ }
+
+ ASSERT( sizeof( SESS_SETUP_CONTEXT ) <= (sizeof( pNCB->ncb_reserve ) +
+ sizeof( pNCB->ncb_event )) ) ;
+ *ppSessSetupContext = (PSESS_SETUP_CONTEXT) pNCB->ncb_reserve ;
+ if ( status = AllocSessSetupContext( *ppSessSetupContext,
+ *pNCB->ncb_callname == '*' ) )
+ goto ErrorExit0 ;
+
+ //
+ // Listen for '*' uses a NULL Request remote address
+ //
+ if ( *pNCB->ncb_callname != '*' )
+ {
+ InitNBTDIConnectInfo( (*ppSessSetupContext)->pRequestConnect,
+ (*ppSessSetupContext)->pRequestConnect->RemoteAddress,
+ pNCB->ncb_callname ) ;
+ }
+
+ InitNBTDIConnectInfo( (*ppSessSetupContext)->pReturnConnect,
+ (*ppSessSetupContext)->pReturnConnect->RemoteAddress,
+ pNCB->ncb_name ) ;
+ (*ppSessSetupContext)->fIsWorldListen = (pNCB->ncb_callname[0] == '*') ;
+ (*ppSessSetupContext)->pConnEle = pConnEle ;
+
+ return NRC_GOODRET ;
+
+ErrorExit0:
+ if ( !(NbtDisassociateAddress( pRequest ) == TDI_SUCCESS))
+ CTEPrint("VxdInitSessionSetup: AllocSesssetupContext failed and DisassociateAddress failed\r\n") ;
+
+ErrorExit1:
+ REQUIRE( NbtCloseConnection( pRequest,
+ &RequestStatus,
+ pDeviceContext,
+ NULL ) == TDI_SUCCESS ) ;
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdFindClientElement
+
+ SYNOPSIS: Finds the appropriate client element
+
+ ENTRY: pDeviceContext - Device to search on
+ ncbnum - NCB Name Number
+ ppClientEle - Receives result of search
+ Type - If CLIENT_BC (broadcast), then the Broadcast client
+ element for the pDeviceContext adapter is returned
+
+ RETURNS: STATUS_SUCCESS if the name is found, error code otherwise
+
+ NOTES: The device context points to a list of Address elements (one
+ address element for each Netbios name in the system). Each
+ address element has a Client Element list hanging off of it.
+ We return the first client element off of the Address Element
+ as there shouldn't be more then one client (is this true?).
+
+ HISTORY:
+ Johnl 23-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdFindClientElement( tDEVICECONTEXT * pDeviceContext,
+ UCHAR ncbnum,
+ tCLIENTELE * * ppClientEle,
+ enum CLIENT_TYPE Type )
+{
+ ASSERT( pDeviceContext != NULL ) ;
+ if ( !pDeviceContext )
+ return NRC_SYSTEM ;
+
+ if ( Type != CLIENT_BC )
+ {
+ if ( ncbnum > pDeviceContext->cMaxNames || !pDeviceContext->pNameTable[ncbnum] )
+ return NRC_ILLNN ;
+
+ *ppClientEle = (tCLIENTELE *) pDeviceContext->pNameTable[ncbnum] ;
+ return NRC_GOODRET ;
+ }
+ else
+ {
+ NTSTATUS status;
+ tCLIENTELE * pClientEleBcast ;
+ UCHAR pName[NETBIOS_NAME_SIZE];
+ tNAMEADDR * pNameAddr;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ //
+ // find the * name in the local hash table
+ //
+ CTEZeroMemory(pName,NETBIOS_NAME_SIZE);
+
+ pName[0] = '*';
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pName,
+ NbtConfig.pScope,
+ &pNameAddr);
+
+ if (NT_SUCCESS(status))
+ {
+ pHead = &pNameAddr->pAddressEle->ClientHead;
+ pEntry = pHead->Flink;
+
+ while ( pEntry != pHead )
+ {
+ pClientEleBcast = CONTAINING_RECORD( pEntry, tCLIENTELE, Linkage ) ;
+ if ( pClientEleBcast->pDeviceContext == pDeviceContext )
+ {
+ *ppClientEle = pClientEleBcast ;
+ break ;
+ }
+ pEntry = pEntry->Flink ;
+ }
+ }
+ else
+ {
+ return(NRC_ILLNN);
+ }
+
+ if ( pEntry == pHead )
+ return NRC_ILLNN ;
+ }
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdFindConnectElement
+
+ SYNOPSIS: Finds the appropriate connect element from the
+ session number
+
+ ENTRY: pDeviceContext - Device to search on
+ lsn - NCB LS Number
+ ppConnectEle - Receives result of search
+
+ RETURNS: NRC_GOODRET if successful, error otherwise
+
+ NOTES: LSN 0 will be disallowed because pSessionTable[0] is always
+ NULL
+
+ HISTORY:
+ Johnl 23-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdFindConnectElement( tDEVICECONTEXT * pDeviceContext,
+ NCB * pNCB,
+ tCONNECTELE * * ppConnectEle )
+{
+ UCHAR lsn ;
+ ASSERT( pNCB != NULL ) ;
+ ASSERT( pDeviceContext != NULL ) ;
+
+ if ( !pDeviceContext || !pNCB )
+ return NRC_SYSTEM ;
+
+ lsn = pNCB->ncb_lsn ;
+ if ( lsn > pDeviceContext->cMaxSessions || !pDeviceContext->pSessionTable[lsn] )
+ return NRC_SNUMOUT ;
+
+ *ppConnectEle = pDeviceContext->pSessionTable[lsn] ;
+
+ //
+ // Check to see if the connection is down but the NB client hasn't been
+ // notified, if so notify them and remove the session from the table
+ //
+ if ( ( (*ppConnectEle)->state == NBT_ASSOCIATED ||
+ (*ppConnectEle)->state == NBT_IDLE ) &&
+ (*ppConnectEle)->RefCount == 1 )
+ {
+ DbgPrint("VxdFindConnectElement: Deleting connection element\r\n") ;
+ NbtDereferenceConnection( *ppConnectEle ) ;
+ REQUIRE( NBUnregister( pDeviceContext, lsn, NB_SESSION )) ;
+ return NRC_SCLOSED ;
+ }
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdFindLSN
+
+ SYNOPSIS: Finds a session number from its tCONNECTELE *.
+
+ ENTRY: pDeviceContext - Device to search on
+ pConnectEle - Connect element to find
+ plsn - Index pConnectEle was found at
+
+ NOTES:
+
+ HISTORY:
+ Johnl 07-Jul-1993 Created
+
+********************************************************************/
+
+NCBERR VxdFindLSN( tDEVICECONTEXT * pDeviceContext,
+ tCONNECTELE * pConnectEle,
+ UCHAR * plsn )
+{
+ ASSERT( (pDeviceContext != NULL) && (pConnectEle != NULL) && (plsn != NULL)) ;
+ ASSERT( pConnectEle->Verify == NBT_VERIFY_CONNECTION ||
+ pConnectEle->Verify == NBT_VERIFY_CONNECTION_DOWN ) ;
+
+ for ( *plsn = 0 ; *plsn <= pDeviceContext->cMaxSessions ; (*plsn)++ )
+ {
+ if ( pDeviceContext->pSessionTable[*plsn] == pConnectEle )
+ return NRC_GOODRET ;
+ }
+
+ ASSERT( FALSE ) ;
+ return NRC_SNUMOUT ;
+}
+
+/*******************************************************************
+
+ NAME: VxdFindNameNum
+
+ SYNOPSIS: Finds a name number from its tADDRESSELE *.
+
+ ENTRY: pDeviceContext - Device to search on
+ pAddressEle - Address element to find
+ pNum - Index pAddressEle was found at
+
+ NOTES:
+
+ HISTORY:
+ Johnl 07-Jul-1993 Created
+
+********************************************************************/
+
+NCBERR VxdFindNameNum( tDEVICECONTEXT * pDeviceContext,
+ tADDRESSELE * pAddressEle,
+ UCHAR * pNum )
+{
+ tCLIENTELE *pClientEle;
+
+ ASSERT( (pDeviceContext != NULL) && (pAddressEle != NULL) && (pNum != NULL)) ;
+ ASSERT( pAddressEle->Verify == NBT_VERIFY_ADDRESS ) ;
+
+ for ( *pNum = 0 ; *pNum <= pDeviceContext->cMaxNames ; (*pNum)++ )
+ {
+ pClientEle = pDeviceContext->pNameTable[*pNum];
+
+ if ( (pClientEle) && (pClientEle->pAddress == pAddressEle ) )
+ return NRC_GOODRET ;
+ }
+
+ return NRC_ILLNN ;
+}
+
+/*******************************************************************
+
+ NAME: VxdNameToClient
+
+ SYNOPSIS: Converts a ncb_callname to the corresponding client element
+ in the name table
+
+ ENTRY: pDeviceContext - Device to search on
+ pchName - Name to find
+ pNameNum - Index into table name number is at (Optional)
+ ppClientEle - Client element in the name table
+
+ NOTES:
+
+ HISTORY:
+ Johnl 15-Oct-1993 Created
+
+********************************************************************/
+
+NCBERR VxdNameToClient( tDEVICECONTEXT * pDeviceContext,
+ CHAR * pName,
+ UCHAR * pNameNum,
+ tCLIENTELE * * ppClientEle )
+{
+ USHORT NameType ;
+ tNAMEADDR * pNameAddr ;
+ UCHAR NameNum ;
+ NTSTATUS status;
+
+ //
+ // Lookup the Client Element associated with this name
+ //
+ if ( pName[0] == '*' )
+ {
+ return NRC_NOWILD ; // Also means name not found
+ }
+
+ status = FindInHashTable(
+ NbtConfig.pLocalHashTbl,
+ pName,
+ NbtConfig.pScope,
+ &pNameAddr);
+
+ if (!NT_SUCCESS(status))
+ {
+ return NRC_NOWILD ; // Also means name not found
+ }
+
+ //
+ // if the name is not registered on the adapter (provided by the client)
+ // tell the client so!
+ //
+ if ( pNameAddr->AdapterMask &&
+ !(pNameAddr->AdapterMask & pDeviceContext->AdapterNumber) )
+ {
+ DbgPrint("VxdNameToClient: wrong DeviceContext element\r\n") ;
+ return NRC_NOWILD ;
+ }
+
+ if ( VxdFindNameNum( pDeviceContext, pNameAddr->pAddressEle, &NameNum ))
+ {
+ ASSERT( FALSE ) ;
+ return NRC_NOWILD ;
+ }
+
+ REQUIRE( !VxdFindClientElement( pDeviceContext,
+ NameNum,
+ ppClientEle,
+ CLIENT_LOCAL )) ;
+ ASSERT( (*ppClientEle)->Verify == NBT_VERIFY_CLIENT ) ;
+
+ if ( pNameNum != NULL )
+ *pNameNum = NameNum ;
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: NBRegister
+
+ SYNOPSIS: Finds the next available slot in apElem and assigns
+ pElem to that slot according to Netbios rules
+
+
+ ENTRY: pDeviceContext - Adapter we are adding name to
+ pNCBNum - Receives the found free slot
+ pElem - Element we are registering
+ NbTable - Indicates the Name table or session table
+
+ EXIT: *pNCBNum will point to the found slot and
+ apElem[*pNCBNum] will point to pElem
+
+ RETURNS: TRUE if we found a free slot, FALSE if the table was
+ full.
+
+ NOTES: The Netbios spec states that returned NCB nums and Logical
+ Session numbers increase to 254 until they wrap to 1 (0
+ is reserved for the adapter name).
+
+ HISTORY:
+ Johnl 28-Apr-1993 Created
+
+********************************************************************/
+
+BOOL NBRegister( tDEVICECONTEXT * pDeviceContext,
+ UCHAR * pNCBNum,
+ PVOID pElem,
+ NB_TABLE_TYPE NbTable )
+{
+ UCHAR i ;
+ BOOL fFound = FALSE ;
+ BOOL fPassTwo = FALSE ;
+ UCHAR MaxNCBNum ;
+ UCHAR * piCurrent ;
+ PVOID * apElem ;
+
+ ASSERT( pElem != NULL ) ;
+
+ if ( NbTable == NB_NAME )
+ {
+ MaxNCBNum = pDeviceContext->cMaxNames ;
+ apElem = pDeviceContext->pNameTable ;
+ piCurrent = &pDeviceContext->iNcbNum ;
+ }
+ else
+ {
+ MaxNCBNum = pDeviceContext->cMaxSessions ;
+ apElem = pDeviceContext->pSessionTable ;
+ piCurrent = &pDeviceContext->iLSNum ;
+ }
+
+ //
+ // Find the next free name number and store it in pNCBNum
+ //
+ for ( i = *piCurrent ; ; i++ )
+ {
+ if ( i > MaxNCBNum )
+ i = 1 ;
+
+ if ( !apElem[i] )
+ {
+ fFound = TRUE ;
+ break ;
+ }
+
+ //
+ // Second time we hit *piCurrent means there are no free slots
+ //
+ if ( i == *piCurrent)
+ {
+ if ( fPassTwo )
+ break ;
+ else
+ fPassTwo = TRUE ;
+ }
+ }
+
+ if ( fFound )
+ {
+ apElem[i] = pElem ;
+ *pNCBNum = *piCurrent = i ;
+
+ (*piCurrent)++ ;
+ if ( *piCurrent > MaxNCBNum )
+ *piCurrent = 1 ;
+ }
+
+ return fFound ;
+}
+
+/*******************************************************************
+
+ NAME: NBUnregister
+
+ SYNOPSIS: Invalidates the passed netbios number
+
+ ENTRY: NCBNum - Name number to unregister
+
+ EXIT: The name number entry will be set to NULL
+
+
+ RETURNS: TRUE if we freed the slot, FALSE if the name wasn't
+ registered in the first place or it's out of range
+
+ NOTES:
+
+ HISTORY:
+ Johnl 05-May-1993 Created
+
+********************************************************************/
+
+BOOL NBUnregister( tDEVICECONTEXT * pDeviceContext,
+ UCHAR NCBNum,
+ NB_TABLE_TYPE NbTable )
+{
+ UCHAR MaxNCBNum ;
+ PVOID * apElem ;
+
+ if ( NbTable == NB_NAME )
+ {
+ MaxNCBNum = pDeviceContext->cMaxNames ;
+ apElem = pDeviceContext->pNameTable ;
+ }
+ else
+ {
+ MaxNCBNum = pDeviceContext->cMaxSessions ;
+ apElem = pDeviceContext->pSessionTable ;
+ }
+
+ if ( NCBNum > MaxNCBNum || apElem[NCBNum] == NULL )
+ {
+ return FALSE ;
+ }
+
+ apElem[NCBNum] = NULL ;
+
+ return TRUE ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCompleteSessionNcbs
+
+ SYNOPSIS: Finds all NCBs attached to a session and completes them
+
+ ENTRY: pDeviceContext - Device we are on
+ pConnEle - Session connection element to complete NCBs on
+
+ NOTES:
+
+ HISTORY:
+ Johnl 16-Aug-1993 Broke out as common code
+
+********************************************************************/
+
+TDI_STATUS VxdCompleteSessionNcbs( tDEVICECONTEXT * pDeviceContext,
+ tCONNECTELE * pConnEle )
+{
+ PLIST_ENTRY pHead, pEntry ;
+ PRCV_CONTEXT prcvCont ;
+ BOOL fCompleteToClient = TRUE ;
+ UCHAR lsn ;
+ NCBERR errNCB ;
+ BOOL fAnyFound = FALSE ;
+
+ ASSERT( pConnEle != NULL ) ;
+ ASSERT( pConnEle->Verify == NBT_VERIFY_CONNECTION ||
+ pConnEle->Verify == NBT_VERIFY_CONNECTION_DOWN ) ;
+
+ if ( errNCB = VxdFindLSN( pDeviceContext,
+ pConnEle,
+ &lsn ))
+ {
+ //
+ // This shouldn't happen but watch for it in case we get in a
+ // weird situation
+ //
+ DbgPrint("VxdCompleteSessionNCBs - Warning: VxdFindLsn failed\r\n") ;
+ return STATUS_UNSUCCESSFUL ;
+ }
+
+ //
+ // Complete the first RcvAny
+ //
+ if ( pConnEle->pClientEle &&
+ !IsListEmpty( &pConnEle->pClientEle->RcvAnyHead ))
+ {
+ pEntry = RemoveHeadList( &pConnEle->pClientEle->RcvAnyHead ) ;
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ //
+ // Set the session number so the client knows which session is going
+ // away.
+ //
+ prcvCont->pNCB->ncb_lsn = lsn ;
+ CTEIoComplete( prcvCont->pNCB,
+ STATUS_CONNECTION_DISCONNECTED,
+ 0 ) ;
+ fAnyFound = TRUE ;
+ }
+
+ //
+ // Now kill all of the outstanding receives. Sends are completed as
+ // they are submitted so nothing to kill.
+ //
+ while ( !IsListEmpty( &pConnEle->RcvHead ))
+ {
+ pEntry = RemoveHeadList( &pConnEle->RcvHead ) ;
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ CTEIoComplete( prcvCont->pNCB,
+ STATUS_CONNECTION_DISCONNECTED,
+ 0 ) ;
+ fAnyFound = TRUE ;
+ }
+
+ //
+ // Once the client has been notified, deref the connection
+ // element so the memory will be deleted when the connection is
+ // closed. If the client wasn't notified, then the connection remains
+ // in our table until the next NCB on this session.
+ //
+ if ( fAnyFound &&
+ !(pConnEle->Flags & NB_CLIENT_NOTIFIED) )
+ {
+ DbgPrint("CompleteSessionNcbs - Marking connection as notified\r\n") ;
+ pConnEle->Flags |= NB_CLIENT_NOTIFIED ;
+ NbtDereferenceConnection( pConnEle ) ;
+ }
+
+
+ return TDI_SUCCESS ;
+}
+
+/*******************************************************************
+
+ NAME: VxdTearDownSession
+
+ SYNOPSIS: Closes a session and deletes its session context
+
+ ENTRY: pConnEle - Pointer to connection session element to close
+ pCont - Session context to delete (or NULL to ignore)
+ pSessSetupContext - Session context to delete if non-NULL
+ pNCB - NCB to complete after disconnect finishes
+
+ NOTES:
+
+ HISTORY:
+ Johnl 16-Aug-1993 Commonized
+
+********************************************************************/
+
+void VxdTearDownSession( tDEVICECONTEXT * pDeviceContext,
+ tCONNECTELE * pConnEle,
+ PSESS_SETUP_CONTEXT pSessSetupContext,
+ NCB * pNCB )
+{
+ TDI_STATUS tdistatus ;
+ TDI_REQUEST Request ;
+
+ if ( pConnEle != NULL )
+ {
+ ASSERT((pConnEle->Verify == NBT_VERIFY_CONNECTION) ||
+ (pConnEle->Verify == NBT_VERIFY_CONNECTION_DOWN)) ;
+
+ Request.Handle.ConnectionContext = pConnEle ;
+
+ tdistatus = NbtDisconnect( &Request, 0, TDI_DISCONNECT_ABORT, NULL, NULL, NULL ) ;
+ if ( tdistatus && tdistatus != TDI_PENDING )
+ {
+ DbgPrint("VxdTearDownSession - NbtDisconnect returned error " ) ;
+ DbgPrintNum( tdistatus ) ;
+ DbgPrint("\r\n") ;
+ }
+
+ tdistatus = NbtCloseConnection( &Request,
+ NULL,
+ pDeviceContext,
+ NULL ) ;
+ if ( tdistatus && tdistatus != TDI_PENDING )
+ {
+ DbgPrint("VxdTearDownSession - NbtCloseConnection returned error " ) ;
+ DbgPrintNum( tdistatus ) ;
+ DbgPrint("\r\n") ;
+ }
+ }
+
+ if ( pSessSetupContext )
+ FreeSessSetupContext( pSessSetupContext ) ;
+}
+/*******************************************************************
+
+ NAME: AllocSessSetupContext
+
+ SYNOPSIS: Allocates and initializes a listen context structure
+
+ ENTRY: pSessSetupContext - Pointer to structure
+ fListenOnStar - TRUE if the request remote address should
+ be left as NULL
+
+ NOTES:
+
+ HISTORY:
+ Johnl 19-May-1993 Created
+
+********************************************************************/
+
+TDI_STATUS AllocSessSetupContext( PSESS_SETUP_CONTEXT pSessSetupContext,
+ BOOL fListenOnStar )
+{
+ CTEZeroMemory( pSessSetupContext, sizeof( SESS_SETUP_CONTEXT ) ) ;
+
+ if ( !(pSessSetupContext->pRequestConnect =
+ CTEAllocMem( sizeof( TDI_CONNECTION_INFORMATION ))) ||
+ !(pSessSetupContext->pReturnConnect =
+ CTEAllocMem( sizeof( TDI_CONNECTION_INFORMATION))) )
+ {
+ goto ErrorExit1 ;
+ }
+
+ pSessSetupContext->pRequestConnect->RemoteAddress = NULL ;
+ pSessSetupContext->pReturnConnect->RemoteAddress = NULL ;
+
+ if ( !(pSessSetupContext->pReturnConnect->RemoteAddress =
+ CTEAllocMem( sizeof( TA_NETBIOS_ADDRESS ))) ||
+ (!fListenOnStar &&
+ !(pSessSetupContext->pRequestConnect->RemoteAddress =
+ CTEAllocMem( sizeof( TA_NETBIOS_ADDRESS )))) )
+ {
+ goto ErrorExit0 ;
+ }
+
+ return TDI_SUCCESS ;
+
+ErrorExit0:
+ if ( pSessSetupContext->pRequestConnect->RemoteAddress)
+ CTEFreeMem( pSessSetupContext->pRequestConnect->RemoteAddress ) ;
+
+ if ( pSessSetupContext->pReturnConnect->RemoteAddress)
+ CTEFreeMem( pSessSetupContext->pReturnConnect->RemoteAddress ) ;
+
+ErrorExit1:
+ if ( pSessSetupContext->pRequestConnect)
+ CTEFreeMem( pSessSetupContext->pRequestConnect ) ;
+
+ if ( pSessSetupContext->pReturnConnect)
+ CTEFreeMem( pSessSetupContext->pReturnConnect ) ;
+
+ return TDI_NO_RESOURCES ;
+}
+
+/*******************************************************************
+
+ NAME: FreeSessSetupContext
+
+ SYNOPSIS: Frees a successfully initialized listen context
+
+ ENTRY: pSessSetupContext - Context to be freed
+
+ HISTORY:
+ Johnl 19-May-1993 Created
+
+********************************************************************/
+
+void FreeSessSetupContext( PSESS_SETUP_CONTEXT pSessSetupContext )
+{
+ if ( pSessSetupContext->pRequestConnect->RemoteAddress )
+ CTEFreeMem( pSessSetupContext->pRequestConnect->RemoteAddress ) ;
+
+ CTEFreeMem( pSessSetupContext->pReturnConnect->RemoteAddress ) ;
+ CTEFreeMem( pSessSetupContext->pRequestConnect ) ;
+ CTEFreeMem( pSessSetupContext->pReturnConnect ) ;
+}
+
+
+/*******************************************************************
+
+ NAME: DelayedSessEstablish
+
+ SYNOPSIS: This routine is called by VxdScheduleDelayedEvent.
+ After name query is successful, we typically make a tcp
+ connection. We delay that step until later so that stack
+ usage is reduced. (yes, there is only 4k of stack on chicago!)
+
+ ENTRY: pContext - context that contains the actual parms
+
+ RETURNS: Nothing
+
+ HISTORY:
+ Koti Dec. 19, 94
+
+********************************************************************/
+VOID DelayedSessEstablish( PVOID pContext )
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ NTSTATUS status;
+ COMPLETIONCLIENT pClientCompletion;
+
+ //
+ // get our parameters out
+ //
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)pContext)->pTracker;
+ status = (NTSTATUS)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+ pClientCompletion = ((NBT_WORK_ITEM_CONTEXT *)pContext)->ClientCompletion;
+
+ CTEMemFree(pContext);
+
+ CompleteClientReq(pClientCompletion,
+ pTracker,
+ status);
+}
+
+
+
+/*******************************************************************
+
+ NAME: VxdApiWorker
+
+ SYNOPSIS: When clients such as another vxd or a V86 app (such as
+ nbtstat.exe) make requests for information or some service,
+ this is the routine that gets called.
+
+ ENTRY: OpCode - what info or service is being requested
+ ClientBuffer - buffer in which to pass info
+ ClientBufLen - how big is the buffer
+
+ RETURNS: ErrorCode from the operation (0 if success)
+
+ HISTORY:
+ Koti 16-Jun-1994 Created
+
+********************************************************************/
+
+NTSTATUS
+VxdApiWorker(
+ DWORD Ioctl,
+ PVOID ClientOutBuffer,
+ DWORD ClientOutBufLen,
+ PVOID ClientInBuffer,
+ DWORD ClientInBufLen,
+ DWORD fOkToTrashInputBuffer
+ )
+{
+
+ NTSTATUS status;
+ USHORT OpCode;
+ int i;
+ USHORT NumLanas;
+ PCHAR pchBuffer;
+ DWORD dwSize;
+ DWORD dwBytesToCopy;
+ PULONG pIpAddr;
+ PLIST_ENTRY pEntry,pHead;
+ tDEVICECONTEXT *pDeviceContext;
+ NCB ncb;
+ UCHAR retcode;
+ tIPANDNAMEINFO *pIpAndNameInfo;
+ tIPCONFIG_INFO *pIpCfg;
+
+
+ status = STATUS_SUCCESS;
+
+ dwSize = ClientOutBufLen;
+
+ // always use the first adapter on the list
+ pDeviceContext = CONTAINING_RECORD(NbtConfig.DeviceContexts.Flink,tDEVICECONTEXT,Linkage);
+
+ OpCode = (USHORT)Ioctl;
+
+ switch (OpCode)
+ {
+ // nbtstat -<any option>
+ case IOCTL_NETBT_GET_IP_ADDRS :
+
+ if (ClientOutBufLen < sizeof(ULONG)*(NbtConfig.AdapterCount + 1))
+ {
+ return( STATUS_BUFFER_OVERFLOW );
+ }
+
+ if (!ClientOutBuffer)
+ {
+ return( STATUS_INVALID_PARAMETER );
+ }
+ pIpAddr = (PULONG )ClientOutBuffer;
+
+ pEntry = pHead = &NbtConfig.DeviceContexts;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+ if (pDeviceContext->IpAddress)
+ {
+ *pIpAddr = pDeviceContext->IpAddress;
+ pIpAddr++;
+ }
+ }
+ //
+ // put a 0 address on the end
+ //
+ *pIpAddr = 0;
+
+ status = STATUS_SUCCESS;
+
+ break;
+
+ // nbtstat -n (or -N)
+ case IOCTL_NETBT_GET_LOCAL_NAMES :
+
+ // nbtstat -c
+ case IOCTL_NETBT_GET_REMOTE_NAMES :
+
+ if (!ClientOutBuffer || ClientOutBufLen == 0)
+ return (STATUS_INSUFFICIENT_RESOURCES);
+
+ if (OpCode == IOCTL_NETBT_GET_REMOTE_NAMES )
+ {
+ // make this null, so NbtQueryAda..() knows this is for remote
+ pDeviceContext = NULL;
+ }
+
+ // return an array of netbios names that are registered
+ status = NbtQueryAdapterStatus(pDeviceContext,
+ &pchBuffer,
+ &dwSize);
+ break;
+
+ // nbtstat -r
+ case IOCTL_NETBT_GET_BCAST_NAMES :
+
+ // return an array of netbios names that are registered
+ status = NbtQueryBcastVsWins(pDeviceContext,&pchBuffer,&dwSize);
+
+ break;
+
+ // nbtstat -R
+ case IOCTL_NETBT_PURGE_CACHE :
+
+ status = NbtResyncRemoteCache();
+ break;
+
+ // nbtstat -s, nbtstat -S
+ case IOCTL_NETBT_GET_CONNECTIONS :
+
+ // return an array of netbios names that are registered
+ status = NbtQueryConnectionList(NULL,
+ &pchBuffer,
+ &dwSize);
+ break;
+
+ // nbtstat -a, nbtstat -A
+ case IOCTL_NETBT_ADAPTER_STATUS:
+
+ if (!ClientOutBuffer)
+ {
+ return( STATUS_INVALID_PARAMETER );
+ }
+
+ CTEZeroMemory( &ncb, sizeof(NCB) );
+
+ ncb.ncb_command = NCBASTAT;
+ ncb.ncb_buffer = ClientOutBuffer;
+ ncb.ncb_length = ClientOutBufLen;
+ ncb.ncb_lana_num = pDeviceContext->iLana;
+
+ if (!ClientInBuffer)
+ {
+ return( STATUS_INVALID_PARAMETER );
+ }
+ pIpAndNameInfo = (tIPANDNAMEINFO *)ClientInBuffer;
+
+ //
+ // see if Ipaddress is specified: if yes, use it
+ //
+ if ( pIpAndNameInfo->IpAddress )
+ {
+ ncb.ncb_callname[0] = '*';
+ retcode = VNBT_NCB_X( &ncb, 0, &pIpAndNameInfo->IpAddress, 0, 0 );
+ }
+ //
+ // no ipaddress: use the name that's given to us
+ //
+ else
+ {
+ CTEMemCopy(
+ &ncb.ncb_callname[0],
+ &(pIpAndNameInfo->NetbiosAddress.Address[0].Address[0].NetbiosName[0]),
+ NCBNAMSZ );
+ retcode = VNBT_NCB_X( &ncb, 0, 0, 0, 0 );
+ }
+
+ status = STATUS_UNSUCCESSFUL;
+ if (!retcode)
+ {
+ if (ncb.ncb_retcode == NRC_GOODRET)
+ status = STATUS_SUCCESS;
+ else if (ncb.ncb_retcode == NRC_INCOMP)
+ status = TDI_BUFFER_OVERFLOW;
+ }
+
+ break;
+
+ // ipconfig queries us for nodetype and scope
+ case IOCTL_NETBT_IPCONFIG_INFO:
+
+ dwBytesToCopy = sizeof(tIPCONFIG_INFO) +
+ NbtConfig.ScopeLength;
+
+ if ( !ClientOutBuffer || ClientOutBufLen < dwBytesToCopy )
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ pIpCfg = (tIPCONFIG_INFO *)ClientOutBuffer;
+
+ NumLanas = 0;
+ for ( i = 0; i < NBT_MAX_LANAS; i++)
+ {
+ if (LanaTable[i].pDeviceContext != NULL)
+ {
+ pDeviceContext = LanaTable[i].pDeviceContext;
+ pIpCfg->LanaInfo[NumLanas].LanaNumber = pDeviceContext->iLana;
+ pIpCfg->LanaInfo[NumLanas].IpAddress = pDeviceContext->IpAddress;
+ pIpCfg->LanaInfo[NumLanas].NameServerAddress = pDeviceContext->lNameServerAddress;
+ pIpCfg->LanaInfo[NumLanas].BackupServer = pDeviceContext->lBackupServer;
+ pIpCfg->LanaInfo[NumLanas].lDnsServerAddress = pDeviceContext->lDnsServerAddress;
+ pIpCfg->LanaInfo[NumLanas].lDnsBackupServer = pDeviceContext->lDnsBackupServer;
+ NumLanas++;
+ }
+ }
+
+ pIpCfg->NumLanas = NumLanas;
+
+ pIpCfg->NodeType = NodeType;
+
+ pIpCfg->ScopeLength = NbtConfig.ScopeLength;
+
+ CTEMemCopy( &pIpCfg->szScope[0],
+ NbtConfig.pScope,
+ NbtConfig.ScopeLength );
+
+ status = STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ //
+ // Copy the output into user's buffer
+ //
+ if ( (OpCode == IOCTL_NETBT_GET_LOCAL_NAMES) ||
+ (OpCode == IOCTL_NETBT_GET_REMOTE_NAMES) ||
+ (OpCode == IOCTL_NETBT_GET_CONNECTIONS) ||
+ (OpCode == IOCTL_NETBT_GET_BCAST_NAMES) )
+ {
+ if ( NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
+ {
+ if ( status == STATUS_BUFFER_OVERFLOW )
+ {
+ dwBytesToCopy = ClientOutBufLen;
+ }
+ else
+ {
+ dwBytesToCopy = dwSize;
+ status = STATUS_SUCCESS;
+ }
+ CTEMemCopy( ClientOutBuffer, pchBuffer, dwBytesToCopy ) ;
+
+ CTEMemFree((PVOID)pchBuffer);
+ }
+ }
+
+ //
+ // we may be called either through the vxd entry point which 16 bit apps
+ // will do (for now, only nbtstat.exe), or through the file system api's
+ // which 32 bit apps will do via CreateFile and ioctl.
+ // If we came here through file system (i.e.VNBT_DeviceIoControl called us)
+ // then don't trash the input buffer since the status gets passed back as
+ // it is. For 16 bit apps (i.e.VNBT_Api_Handler called us), the only way
+ // we can pass status back (without major changes all over) is through the
+ // input buffer.
+ //
+ if ( ClientInBuffer && fOkToTrashInputBuffer )
+ {
+ *(NTSTATUS *)ClientInBuffer = status;
+ }
+
+ return( status );
+}
+
+/*******************************************************************
+
+ NAME: PostInit_Proc
+
+ SYNOPSIS: After the whole system is initialized, we get the
+ Sys_Vm_Init message and that's when this routine gets called.
+ This can be used for any post-processing, but for now we
+ only use it to load lmhosts (this way, we can load all the
+ #INCLUDE files which have UNC's in them, since now we know
+ the net is up).
+
+ RETURNS: ErrorCode from the operation (0 if success)
+
+ HISTORY:
+ Koti 12-Jul-1994 Created
+
+********************************************************************/
+
+NTSTATUS
+PostInit_Proc()
+{
+
+ LONG lRetcode;
+
+ CachePrimed = FALSE;
+
+ CTEPagedCode();
+
+
+ lRetcode = PrimeCache( NbtConfig.pLmHosts,
+ NULL,
+ TRUE,
+ NULL) ;
+ if (lRetcode != -1)
+ {
+ CachePrimed = TRUE ;
+ }
+
+}
+
+
+/*******************************************************************
+
+ NAME: CTEAllocInitMem
+
+ SYNOPSIS: Allocates memory during driver initialization
+
+ NOTES: If first allocation fails, we refill the heap spare and
+ try again. We can only do this during driver initialization
+ because the act of refilling may yield the current
+ thread.
+
+ HISTORY:
+ Johnl 27-Aug-1993 Created
+********************************************************************/
+
+PVOID CTEAllocInitMem( ULONG cbBuff )
+{
+ PVOID pv = CTEAllocMem( cbBuff ) ;
+
+ if ( pv )
+ {
+ return pv ;
+ }
+ else if ( fInInit )
+ {
+ DbgPrint("CTEAllocInitMem: Failed allocation, trying again\r\n") ;
+ CTERefillMem() ;
+ pv = CTEAllocMem( cbBuff ) ;
+ }
+
+ return pv ;
+}