/**********************************************************************/ /** 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 #include // // 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 - 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 ; }