summaryrefslogtreecommitdiffstats
path: root/private/ntos/nbt/vxd/tdihndlr.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nbt/vxd/tdihndlr.c')
-rw-r--r--private/ntos/nbt/vxd/tdihndlr.c1719
1 files changed, 1719 insertions, 0 deletions
diff --git a/private/ntos/nbt/vxd/tdihndlr.c b/private/ntos/nbt/vxd/tdihndlr.c
new file mode 100644
index 000000000..f5a9d5425
--- /dev/null
+++ b/private/ntos/nbt/vxd/tdihndlr.c
@@ -0,0 +1,1719 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Tdihndlr.c
+
+Abstract:
+
+
+ This file contains the TDI handlers that are setup for Connects,
+ Receives, Disconnects, and Errors on an address object (in tdiaddr.c).
+
+ This file represents the TDI interface on the Bottom of NBT. Therefore
+ the code basically decodes the incoming information and passes it to
+ a non-Os specific routine to do what it can. Upon return from that
+ routine additional Os specific work may need to be done.
+
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+ John Ludeman (JohnL) 04-10-93 - Rewrote for VXD
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+#include "ctemacro.h"
+
+//
+// The event receive buffer takes a pointer to a flags variable that will
+// always be the same, so just use the same variable
+//
+static USHORT usFlags = TDI_RECEIVE_NORMAL ;
+
+VOID
+AcceptCompletionRoutine(
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint extra
+ );
+VOID
+NewSessionCompletionRoutine (
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint extra
+ );
+NTSTATUS
+Reindicate(
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu
+ );
+
+//
+// This ntohl swaps just three bytes, since the 4th byte could be a session
+// keep alive message type.
+//
+__inline long
+myntohl(long x)
+{
+ return((((x) >> 24) & 0x000000FFL) |
+ (((x) >> 8) & 0x0000FF00L) |
+ (((x) << 8) & 0x00FF0000L));
+}
+
+//----------------------------------------------------------------------------
+ TDI_STATUS
+TdiReceiveHandler (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT EventRcvBuffer * pevrcvbuf
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive event indication handler.
+
+ It is called when an session packet arrives from the network. It calls
+ a non OS specific routine to decide what to do. That routine passes back
+ either a RcvElement (buffer) or a client rcv handler to call.
+
+Arguments:
+
+ IN PVOID ReceiveEventContext - Context provided for this event when event set
+ IN PVOID ConnectionContext - Connection Context, (pLowerConnection)
+ IN USHORT ReceiveFlags - Flags describing the message
+ IN ULONG BytesIndicated - Number of bytes available at indication time
+ IN ULONG BytesAvailable - Number of bytes available to receive
+ OUT PULONG BytesTaken - Number of bytes consumed by redirector.
+ IN PVOID pTsdu - Data from remote machine.
+ OUT EvenRcvBuffer *ppBuffer - Receive buffer to fill if set
+
+
+Return Value:
+
+ TDI_STATUS - Status of receive operation
+
+--*/
+
+{
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnectEle;
+ PRCV_CONTEXT prcvCont = NULL ;
+ NTSTATUS status;
+ ULONG PduSize;
+ ULONG RemainingPdu;
+
+ DbgPrint("TRH Entered (ConnectionContext = 0x") ;
+ DbgPrintNum( (ULONG) ConnectionContext) ; DbgPrint(")\r\n") ;
+
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+
+ pLowerConn->BytesRcvd += BytesAvailable;
+
+ //
+ // check if this is another part of a session pdu
+ //
+ if (pLowerConn->State == NBT_SESSION_UP)
+ {
+ DbgPrint("\tTRH: Session status is UP, Bytes: available, indicated: 0x") ;
+ DbgPrintNum( BytesAvailable ) ; DbgPrint(" 0x") ;
+ DbgPrintNum( BytesIndicated ) ;
+ DbgPrint("\r\n") ;
+
+ pConnectEle = pLowerConn->pUpperConnection;
+ pConnectEle->BytesInXport = BytesAvailable ;
+ *BytesTaken = 0 ;
+
+ DbgPrint("\tTRH: BytesInXport: 0x") ;
+ DbgPrintNum( pConnectEle->BytesInXport ) ;
+ DbgPrint("\r\n") ;
+
+
+ //
+ // ** RECEIVING A PDU STATE **
+ //
+
+ switch (pLowerConn->StateRcv)
+ {
+ case NORMAL:
+ //
+ // check indication and if less than the session header,
+ // copy to the session header buffer and go to Indic_buffer state
+ // and wait for the next indication. This is a rare case (and a pain
+ // in the butt).
+ //
+ if (BytesIndicated < sizeof(tSESSIONHDR))
+ {
+ ASSERT( pLowerConn->BytesInHdr == 0 ) ;
+ DbgPrint("\tTRH - NORMAL case: Not enough for session header, requesting 0x") ;
+ DbgPrintNum( sizeof( pLowerConn->Hdr ) ) ;
+ DbgPrint(" bytes\r\n") ;
+
+
+ if ( !GetRcvContext( &prcvCont))
+ return STATUS_INSUFFICIENT_RESOURCES ;
+
+ InitRcvContext( prcvCont, pLowerConn, NULL ) ;
+ prcvCont->usFlags = TDI_RECEIVE_NORMAL;
+ pevrcvbuf->erb_buffer = &prcvCont->ndisBuff ;
+ pevrcvbuf->erb_rtn = (CTEReqCmpltRtn) NewSessionCompletionRoutine ;
+ pevrcvbuf->erb_size = sizeof( pLowerConn->Hdr ) ;
+ pevrcvbuf->erb_context = prcvCont ;
+ pevrcvbuf->erb_flags = &usFlags ;
+ InitNDISBuff( pevrcvbuf->erb_buffer,
+ &pLowerConn->Hdr,
+ sizeof(pLowerConn->Hdr),
+ NULL ) ;
+
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+
+ //
+ // Okay to use pIrpRcv here as it will only be completed if
+ // the state is FILL_IRP
+ //
+ pConnectEle->pIrpRcv = (PCTE_IRP) prcvCont ;
+
+ return TDI_MORE_PROCESSING ;
+ }
+
+ PduSize = myntohl(((tSESSIONHDR *)pTsdu)->UlongLength)
+ + sizeof(tSESSIONHDR);
+ DbgPrint("\tTRH: New message; Opcode, PduSize + hdr : 0x") ;
+ DbgPrintNum( ((tSESSIONHDR *)pTsdu)->Type ) ; DbgPrint(" 0x") ;
+ DbgPrintNum( PduSize ) ; DbgPrint("\r\n") ;
+
+ //
+ // Indicate to the client
+ //
+ ASSERT( PduSize >= sizeof(tSESSIONHDR)) ;
+ status = RcvHandlrNotOs(
+ ReceiveEventContext,
+ ConnectionContext,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ pTsdu,
+ &prcvCont
+ );
+
+ ASSERT( *BytesTaken <= pConnectEle->BytesInXport ) ;
+ ASSERT( *BytesTaken <= BytesIndicated);
+ pConnectEle->BytesInXport -= *BytesTaken;
+ BytesIndicated -= *BytesTaken;
+ BytesAvailable -= *BytesTaken;
+ ((BYTE*)pTsdu) += *BytesTaken ;
+
+ DbgPrint("\tTRH: RcvHandlrNotOs returned, BytesTaken: 0x") ;
+ DbgPrintNum( *BytesTaken ) ;
+ DbgPrint("\r\n") ;
+
+ DbgPrint("\tTRH: RcvHandlrNotOs status, prcvCont: 0x") ;
+ DbgPrintNum( status ) ; DbgPrint(" 0x") ;
+ DbgPrintNum( (ULONG)prcvCont ) ; DbgPrint("\r\n") ;
+
+ if ( prcvCont )
+ {
+ ULONG BytesToCopy ;
+ ASSERT( status == STATUS_MORE_PROCESSING_REQUIRED );
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ //
+ // Record which session satisfied the request
+ //
+ prcvCont->pLowerConnId = pLowerConn ;
+ REQUIRE( !VxdFindLSN( pConnectEle->pClientEle->pDeviceContext,
+ pConnectEle,
+ &prcvCont->pNCB->ncb_lsn )) ;
+ //
+ // New message so strip session header
+ //
+ PduSize -= *BytesTaken ;
+ DbgPrint("\tTRH: Remaining PduSize = 0x") ;
+ DbgPrintNum( PduSize ) ; DbgPrint("\r\n") ;
+
+ DbgPrint("\tTRH: TotalPcktLen = 0x") ;
+ DbgPrintNum( pConnectEle->TotalPcktLen ) ; DbgPrint("\r\n") ;
+
+ BytesToCopy = min( pConnectEle->TotalPcktLen,
+ prcvCont->ndisBuff.Length ) ;
+
+ DbgPrint("\tTRH: BytesToCopy = 0x") ;
+ DbgPrintNum( BytesToCopy ) ; DbgPrint("\r\n") ;
+
+ //
+ // pIrpRcv is set to NULL while the request is in the
+ // transport. This prevents two completions if an error
+ // occurs
+ //
+ pLowerConn->StateRcv = FILL_IRP ;
+ pConnectEle->pIrpRcv = NULL ;
+ pConnectEle->OffsetFromStart = 0 ;
+
+ //
+ // If the data is available, then just grab it now
+ // (also, if flag is set to TDI_RECEIVE_NO_RESPONSE_EXP, we
+ // need to give hint to the xport, so let xport do the copying)
+ //
+ if ( ( BytesIndicated >= BytesToCopy ) &&
+ ( prcvCont->usFlags == TDI_RECEIVE_NORMAL ) )
+ {
+ CTEMemCopy( prcvCont->ndisBuff.VirtualAddress,
+ pTsdu,
+ BytesToCopy ) ;
+ *BytesTaken += BytesToCopy ;
+ CompletionRcv( prcvCont, STATUS_SUCCESS, BytesToCopy ) ;
+ return STATUS_SUCCESS ;
+ }
+
+ pevrcvbuf->erb_buffer = &prcvCont->ndisBuff ;
+ pevrcvbuf->erb_rtn = CompletionRcv ;
+ pevrcvbuf->erb_size = BytesToCopy ;
+ pevrcvbuf->erb_context = prcvCont ;
+ if (prcvCont->usFlags == TDI_RECEIVE_NO_RESPONSE_EXP)
+ pevrcvbuf->erb_flags = &prcvCont->usFlags ;
+ else
+ pevrcvbuf->erb_flags = &usFlags ;
+
+ DbgPrint("\tTRH: Rcv Dest Buff: 0x") ;
+ DbgPrintNum((ULONG)pevrcvbuf->erb_buffer->VirtualAddress) ; DbgPrint("\r\n") ;
+ return TDI_MORE_PROCESSING ;
+ }
+ else
+ {
+ // the client received some, all or none of the data
+ // For Keep Alives the PduSize is zero so this check
+ // will work correctly and go to the else
+ // Also, if we were attempting to complete a zero-len message
+ // but failed because there was no receive pending then we
+ // must go in PARTIAL_RCV state
+ //
+ if ( (*BytesTaken < PduSize) ||
+ ((status == STATUS_DATA_NOT_ACCEPTED) &&
+ (pConnectEle->TotalPcktLen == 0) &&
+ (pConnectEle->state == NBT_SESSION_UP)) )
+ {
+ //
+ // took some of the data, so keep track of the
+ // rest of the data left here by going to the PARTIALRCV
+ // state.
+ //
+ pLowerConn->StateRcv = PARTIAL_RCV;
+ InsertTailList( &pLowerConn->pDeviceContext->PartialRcvHead,
+ &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = TRUE;
+
+ DbgPrint("TdiReceiveHandler:Switch to Partial Rcv Indicated\r\n") ;
+
+ return STATUS_SUCCESS ;
+ }
+ else
+ {
+ //
+ // Must have taken all of the pdu data, so check for
+ // more data available - if so then reindicate ourselves.
+ // Note that TDI will pickup the bytes taken before any posted
+ // receives are performed.
+ //
+ status = STATUS_SUCCESS ;
+
+ //
+ // The next bytes in the transport will be the
+ // beginning of a Session Header so leave the state
+ // as NORMAL
+ //
+
+ if (BytesAvailable > *BytesTaken)
+ {
+ ULONG ClientBytesTaken = 0 ;
+
+ //
+ // we already added the bytes available the first time
+ // TdiReceiveHandler got called. They will get added
+ // again, so subtract now!
+ //
+ pLowerConn->BytesRcvd -= BytesAvailable;
+
+ status = TdiReceiveHandler( ReceiveEventContext,
+ ConnectionContext,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ &ClientBytesTaken,
+ pTsdu,
+ pevrcvbuf ) ;
+
+ *BytesTaken += ClientBytesTaken ;
+ //
+ // status will be more processing if pervrcvbuf
+ // was setup, else it will be success if
+ // bytes were taken. Note that BytesInXport
+ // is adjusted automatically in the call to
+ // TdiReceiveHandler
+ //
+ }
+ }
+ }
+ return status ;
+
+ case FILL_IRP:
+ {
+ NCB * pNCB = pConnectEle->pIrpRcv ;
+ ULONG BuffAvailable = pNCB->ncb_length - pConnectEle->OffsetFromStart ;
+ ULONG BytesToCopy ;
+
+ // we are still waiting for the rest of the session pdu so
+ // do not call the RcvHandlrNotOs, since we already have the buffer
+ // to put this data in.
+ prcvCont = *((PRCV_CONTEXT*)&pNCB->ncb_reserve) ;
+ ASSERT( prcvCont->Signature = RCVCONT_SIGN ) ;
+
+ //
+ // too much data may have arrived... i.e. part of the next session pdu..
+ // so check and set the receive length accordingly
+ //
+ RemainingPdu = pConnectEle->TotalPcktLen - pConnectEle->BytesRcvd;
+ BytesToCopy = min( RemainingPdu, BuffAvailable ) ;
+ pConnectEle->pIrpRcv = NULL ; // Buffer in the transport
+
+ DbgPrint("\tTRH - FILL_IRP case: Requesting 0x") ;
+ DbgPrintNum( pevrcvbuf->erb_size ) ; DbgPrint("\r\n") ;
+
+ //
+ // Append the new data onto the existing data
+ //
+ ((BYTE*)prcvCont->ndisBuff.VirtualAddress) =
+ pNCB->ncb_buffer + pConnectEle->OffsetFromStart ;
+ prcvCont->ndisBuff.Length =
+ pNCB->ncb_length - pConnectEle->OffsetFromStart ;
+
+ //
+ // If the data is available, then just grab it now
+ //
+ if ( BytesIndicated >= BytesToCopy )
+ {
+ CTEMemCopy( prcvCont->ndisBuff.VirtualAddress,
+ pTsdu,
+ BytesToCopy ) ;
+ *BytesTaken += BytesToCopy ;
+ CompletionRcv( prcvCont, STATUS_SUCCESS, BytesToCopy ) ;
+ return STATUS_SUCCESS ;
+ }
+
+ //
+ // Have to post a buffer since the data isn't available
+ // We also have a new offset for the *next* indication
+ //
+ pevrcvbuf->erb_buffer = &prcvCont->ndisBuff ;
+ pevrcvbuf->erb_rtn = CompletionRcv ;
+ pevrcvbuf->erb_size = BytesToCopy ;
+
+ pevrcvbuf->erb_context = prcvCont ;
+ pevrcvbuf->erb_flags = &usFlags ;
+ ASSERT( pConnectEle->OffsetFromStart <= pNCB->ncb_length ) ;
+
+ DbgPrint("\tTRH: offset, address: 0x") ;
+ DbgPrintNum( pConnectEle->OffsetFromStart ) ; DbgPrint(", 0x") ;
+ DbgPrintNum( (ULONG)prcvCont->ndisBuff.VirtualAddress ) ; DbgPrint("\r\n") ;
+
+ //
+ // State remains in FILL_IRP (only goes to PARTIAL_RCV when no
+ // NCBs are actively receiving and only part of a PDU has been
+ // picked up).
+ //
+ // BytesInXport adjusted in CompletinRcv
+ //
+
+ return TDI_MORE_PROCESSING ;
+ }
+ break ;
+
+ case INDICATE_BUFFER:
+ {
+ DbgPrint("\tTRH: Hit INDICATE_BUFFER state, bytes in hdr: 0x") ;
+ DbgPrintNum( pLowerConn->BytesInHdr ) ;
+ DbgPrint("\r\n") ;
+
+ //
+ // Our context is still setup so adjust things such that
+ // the location to start copying the new data into is right
+ // after the existing data in the session header buffer
+ //
+ prcvCont = (PRCV_CONTEXT) pConnectEle->pIrpRcv ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+ ((BYTE*)prcvCont->ndisBuff.VirtualAddress) =
+ ((BYTE*)&pLowerConn->Hdr) + pLowerConn->BytesInHdr ;
+ prcvCont->ndisBuff.Length =
+ sizeof( pLowerConn->Hdr ) - pLowerConn->BytesInHdr ;
+ pevrcvbuf->erb_size = min( BytesAvailable,
+ sizeof(pLowerConn->Hdr) - pLowerConn->BytesInHdr) ;
+ pevrcvbuf->erb_buffer = &prcvCont->ndisBuff ;
+ pevrcvbuf->erb_rtn = NewSessionCompletionRoutine ;
+ pevrcvbuf->erb_context = prcvCont ;
+ pevrcvbuf->erb_flags = &usFlags ;
+ return TDI_MORE_PROCESSING ;
+ }
+
+ case PARTIAL_RCV:
+ //
+ // If we get indicated in this state, then the client doesn't have
+ // any receive buffers posted and we are in the middle of a
+ // PDU, so just track the new byte count and continue waiting
+ // for the client
+ //
+ DbgPrint("\tTRH: Indicated in Partial_Rcv state\r\n") ;
+ return STATUS_SUCCESS ;
+
+ default:
+ ASSERT( FALSE ) ;
+ break;
+ }
+ }
+ else if ( pLowerConn->State == NBT_SESSION_INBOUND )
+ {
+ status = Inbound(
+ ReceiveEventContext,
+ ConnectionContext,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ pTsdu,
+ &prcvCont
+ );
+ }
+ else if ( pLowerConn->State == NBT_SESSION_OUTBOUND )
+ {
+ status = Outbound(
+ ReceiveEventContext,
+ ConnectionContext,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ pTsdu,
+ &prcvCont
+ );
+ }
+
+ //
+ // maybe disconnect is going on: reject the data
+ //
+ else
+ {
+ *BytesTaken = BytesAvailable;
+ status = STATUS_SUCCESS;
+ }
+
+ //
+ // Client should *never* pass back a completion buffer (only used by
+ // event handler which isn't supported in a VXD
+ //
+ ASSERT( prcvCont == NULL ) ;
+
+ return status;
+}
+
+//----------------------------------------------------------------------------
+
+TDI_STATUS
+ReceiveAnyHandler ( // Handles NCBRCVANY commands, is
+ IN PVOID ReceiveEventContext, // called after all other receive
+ IN PVOID ConnectionContext, // handlers
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID Data,
+ PVOID * ppBuffer // Pointer to RCV_CONTEXT
+ )
+/*++
+
+Routine Description:
+
+ This routine handles any data not processed by TdiReceiveHandler and
+ RcvHandlrNotOs. It processes ReceiveAny NCBs.
+
+ Note that TdiReceiveHandler calls RcvHandlrNotOs which may call
+ this routine (i.e., this is only called from RcvHandlrNotOs).
+
+Arguments:
+
+--*/
+{
+ TDI_STATUS tdistatus ;
+ tCLIENTELE * pClientEle;
+ PLIST_ENTRY pEntry ;
+ PRCV_CONTEXT prcvCont ;
+
+ DbgPrint("ReceiveAnyHandler Entered \r\n") ;
+ *ppBuffer = NULL ;
+
+ pClientEle = (tCLIENTELE*) ReceiveEventContext ;
+
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ) ;
+
+ //
+ // Are there any ReceiveAny NCBs queued for this connection or for
+ // any connection?
+ //
+ if ( !IsListEmpty( &pClientEle->RcvAnyHead ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->RcvAnyHead ) ;
+ DbgPrint("ReceiveAnyHandler - Found Receive Any buffer\r\n") ;
+ }
+ else if ( !IsListEmpty( &pClientEle->pDeviceContext->RcvAnyFromAnyHead ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->pDeviceContext->RcvAnyFromAnyHead ) ;
+ DbgPrint("ReceiveAnyHandler - Found Receive Any from Any buffer\r\n") ;
+ }
+ else
+ return STATUS_SUCCESS ;
+ //
+ // Found one
+ //
+ prcvCont = *ppBuffer = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+ return TDI_MORE_PROCESSING ;
+}
+
+//----------------------------------------------------------------------------
+ VOID
+CompletionRcv(
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint BytesRcvd )
+/*++
+
+Routine Description:
+
+ This routine completes TdiVxdReceive. The NCB is completed or further
+ receives are performed.
+
+Arguments:
+
+ pContext - Pointer to a RCV_CONTEXT structure
+ tdistatus - Completion status
+ BytesRcvd - Bytes copied to the destination buffer
+
+--*/
+{
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnectEle;
+ PRCV_CONTEXT prcvcont = (PRCV_CONTEXT) pContext ;
+
+ DbgPrint("CompletionRcv Entered (BytesRcvd: 0x") ;
+ DbgPrintNum( BytesRcvd ) ; DbgPrint(")\r\n") ;
+
+ ASSERT( prcvcont->Signature == RCVCONT_SIGN ) ;
+ ASSERT( tdistatus ||
+ (!tdistatus && ((prcvcont->pLowerConnId != NULL) &&
+ (prcvcont->pLowerConnId->pUpperConnection != NULL))) ) ;
+
+ //
+ // If an error occurred, bail
+ //
+ if ( tdistatus && tdistatus != TDI_BUFFER_OVERFLOW )
+ {
+ DbgPrint("CompletionRcv: error occurred, status: 0x") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\n\r") ;
+
+ //
+ // Make sure the receive IRP doesn't get completed twice if the
+ // connection is still up
+ //
+ if ( prcvcont->pLowerConnId &&
+ prcvcont->pLowerConnId->pUpperConnection )
+ {
+ prcvcont->pLowerConnId->pUpperConnection->pIrpRcv = NULL ;
+ }
+
+ CTEIoComplete( prcvcont->pNCB, tdistatus, 0 ) ;
+ return ;
+ }
+
+ pLowerConn = prcvcont->pLowerConnId ;
+ pConnectEle = pLowerConn->pUpperConnection;
+
+ ASSERT( pConnectEle->Verify == NBT_VERIFY_CONNECTION ) ;
+ pConnectEle->BytesRcvd += BytesRcvd;
+ pConnectEle->OffsetFromStart += BytesRcvd ;
+
+ //
+ // Since we request NCB buffer sizes, we can get more bytes then what
+ // was shown as available. If that happens then we've already consumed
+ // all transport bytes so reset to 0.
+ //
+ if ( pConnectEle->BytesInXport <= BytesRcvd )
+ pConnectEle->BytesInXport = 0 ;
+ else
+ pConnectEle->BytesInXport -= BytesRcvd ;
+
+ //
+ // this case handles when all bytes in a session pdu have arrived...
+ //
+ if (pConnectEle->BytesRcvd == pConnectEle->TotalPcktLen)
+ {
+ //
+ // we have received all of the data for this message
+ // so complete back to the client
+ //
+ DbgPrint("CompletionRcv: PDU Receive done, about to complete client with 0x") ;
+ DbgPrintNum( pConnectEle->OffsetFromStart ) ; DbgPrint(" of total PDU length: 0x") ;
+ DbgPrintNum( pConnectEle->TotalPcktLen ) ; DbgPrint("\r\n") ;
+
+ pConnectEle->pIrpRcv = NULL ;
+
+ //
+ // change the state before completing the ncb because our client can
+ // turn around and post a hangup rightaway (in fact, net send does that!)
+ //
+ pLowerConn->StateRcv = NORMAL;
+ CTEIoComplete( prcvcont->pNCB, STATUS_SUCCESS, pConnectEle->OffsetFromStart ) ;
+
+ //
+ // Freed by CTEIoComplete, make sure we don't use it again
+ //
+ prcvcont = NULL ;
+
+ pConnectEle->OffsetFromStart = 0;
+ pConnectEle->BytesRcvd = 0; // reset for the next session pdu
+ pLowerConn->BytesInHdr = 0 ;
+
+ //
+ // Check if there is still more data in the transport and reindicate
+ // if there is.
+ //
+ if (pConnectEle->BytesInXport)
+ {
+ ULONG BytesTaken = 0 ;
+ DbgPrint("Nbt:ComplRcv - Bytes left in Xport after completing a receive, BytesInXport= 0x") ;
+ DbgPrintNum(pConnectEle->BytesInXport) ;
+ DbgPrint("\r\n") ;
+
+ //
+ // The next thing to do is copy the session header into
+ // pLowerConn->Hdr which this will do.
+ //
+ tdistatus = Reindicate( NULL,
+ pLowerConn,
+ 0, // Rcv flags
+ 0, // Bytes Indicated
+ pConnectEle->BytesInXport, // Bytes Avail
+ &BytesTaken,
+ NULL ) ; // tsdu
+ }
+
+ }
+ else
+ if (pConnectEle->BytesRcvd > pConnectEle->TotalPcktLen)
+ {
+ DbgPrint("CompletionRcv: Too Many Bytes Rcvd!! Rcvd 0x") ;
+ DbgPrintNum( pConnectEle->BytesRcvd ) ;
+ DbgPrint(" Total message length:0x") ;
+ DbgPrintNum( pConnectEle->TotalPcktLen ) ;
+ //DbgPrint(" NCB Buffer size: 0x") ;
+ //DbgPrintNum( prcvcont->pNCB->ncb_length ) ;
+ DbgPrint("\r\n") ;
+ ASSERT(FALSE);
+
+ pConnectEle->pIrpRcv = NULL ;
+ pLowerConn->StateRcv = NORMAL;
+ pConnectEle->BytesRcvd = 0; // reset for the next session pdu
+ pLowerConn->BytesInHdr = 0 ;
+ CTEIoComplete( prcvcont->pNCB, TDI_INVALID_STATE, 0 ) ;
+ }
+ else
+ {
+ ASSERT( prcvcont->pNCB ) ;
+
+ //
+ // Haven't received all of the data for this PDU yet, check to
+ // see how much room the NCB has left in it.
+ //
+ if ( pConnectEle->OffsetFromStart >= prcvcont->pNCB->ncb_length )
+ {
+ // If OffsetFromStart is greater then the buffer size then we
+ // have went beyond the end of the buffer.
+ ASSERT( pConnectEle->OffsetFromStart == prcvcont->pNCB->ncb_length ) ;
+
+ DbgPrint("CompletionRcv: Completed NCB but more data available, Total BytesRecieved: 0x") ;
+ DbgPrintNum( pConnectEle->BytesRcvd ) ;
+ DbgPrint("\r\n Ncb buffer size completed: 0x") ;
+ DbgPrintNum( prcvcont->pNCB->ncb_length ) ;
+ DbgPrint("\r\n") ;
+
+ pConnectEle->pIrpRcv = NULL ;
+ pConnectEle->OffsetFromStart = 0;
+ pLowerConn->StateRcv = PARTIAL_RCV ;
+ InsertTailList( &pLowerConn->pDeviceContext->PartialRcvHead,
+ &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = TRUE;
+
+ //
+ // Done with this NCB, set the status appropriately and hope
+ // the client will submit another NCB to pick up the rest of
+ // the PDU. prcvcont freed by the completion.
+ //
+ CTEIoComplete( prcvcont->pNCB,
+ TDI_BUFFER_OVERFLOW, //translates to: NRC_INCOMP
+ prcvcont->pNCB->ncb_length ) ;
+
+ }
+ else
+ {
+ //
+ // Room still left in the NCB so wait for the transport to
+ // indicate when more data is available (OffsetFromStart has
+ // already been adjusted)
+ //
+ pConnectEle->pIrpRcv = prcvcont->pNCB ;
+ pLowerConn->StateRcv = FILL_IRP ;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NewSessionCompletionRoutine (
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint BytesReceived
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of the receive to get the remaining
+ data left in the transport when a session PDU starts in the middle of
+ an indication from the transport. This routine is run as the completion
+ of a recv Irp passed to the transport by NBT, to get the remainder of the
+ data in the transport.
+
+ The routine then calls the normal receive handler, which can either
+ consume the data or pass back an Irp. If an Irp is passed back then
+ the data is copied into that irp in this routine.
+
+ Called when a partial message header is received - puts the data back
+ on the
+
+Arguments:
+
+
+Return Value:
+
+ pConnectionContext - connection context returned to the transport(connection to use)
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ PRCV_CONTEXT prcvCont = pContext ;
+ NTSTATUS status;
+ ULONG BytesTaken = 0;
+ ULONG BytesAvailable ;
+ tCONNECTELE *pConnEle;
+ tLOWERCONNECTION *pLowerConn;
+
+ DbgPrint("NewSessionCompletionRoutine Entered\r\n") ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ pLowerConn = prcvCont->pLowerConnId ;
+ pConnEle = pLowerConn->pUpperConnection ;
+
+ //
+ // If an error occurred just drop the PDU on the floor (though an
+ // error really shouldn't happen)
+ //
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ FreeRcvContext( prcvCont ) ;
+ pLowerConn->StateRcv = NORMAL ;
+ return ;
+ }
+
+ //
+ // Adjust BytesInXport if there were too few bytes for the
+ // session header
+ //
+ if ( BytesReceived > pConnEle->BytesInXport )
+ pConnEle->BytesInXport = BytesReceived ;
+
+ //
+ // there may be data still in the indication buffer,
+ // so add that amount to what we just received. The transport
+ // has already copied the data into the pLowerConn->Hdr so we
+ // just need to update the state.
+ //
+ ASSERT( BytesReceived <= sizeof( pLowerConn->Hdr ) ) ;
+ pLowerConn->BytesInHdr += BytesReceived ;
+
+ //
+ // If we have a full header, process it
+ //
+ if ( pLowerConn->BytesInHdr == sizeof(pLowerConn->Hdr) )
+ {
+ ULONG BytesTaken = 0 ;
+ pLowerConn->StateRcv = NORMAL ; // New session header
+ pLowerConn->BytesInHdr = 0 ;
+ FreeRcvContext( prcvCont ) ;
+
+ //
+ // We indicate just the session header bytes, this will force
+ // the client to post a receive if they are interested in the
+ // rest of the data
+ //
+ status = Reindicate(NULL,
+ pLowerConn,
+ 0, // rcv flags
+ sizeof( pLowerConn->Hdr ),
+ pConnEle->BytesInXport,
+ &BytesTaken,
+ &pLowerConn->Hdr ) ;
+ ASSERT( BytesTaken <= sizeof( pLowerConn->Hdr ) ) ;
+ }
+ else
+ {
+ //
+ // We *still* don't have the full session header so
+ // wait for reindication
+ //
+ return ;
+ }
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+Reindicate(
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu
+ )
+/*++
+
+Routine Description:
+
+ This routine copies data from the Indicate buffer to a 128 byte buffer and
+ then fills this with data from the current indication.
+
+Arguments:
+
+
+Return Value:
+
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS ;
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnEle;
+ EventRcvBuffer evrcvbuf ;
+
+ DbgPrint("Reindicated Entered\r\n") ;
+ DbgPrint("\tReindicate: Bytes: available, indicated: 0x") ;
+ DbgPrintNum( BytesAvailable ) ; DbgPrint(" 0x") ;
+ DbgPrintNum( BytesIndicated ) ;
+ DbgPrint("\r\n") ;
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+ pConnEle = pLowerConn->pUpperConnection;
+
+ //
+ // we already added the bytes available the first time TdiReceiveHandler
+ // got called. They will get added again, so subtract now!
+ //
+ pLowerConn->BytesRcvd -= BytesAvailable;
+
+ status = TdiReceiveHandler(NULL,
+ pLowerConn,
+ 0, // rcv flags
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ pTsdu,
+ &evrcvbuf );
+
+ //
+ // If a receive context was returned, then post the receive, if bytes
+ // were taken, the state was updated in the receive handler
+ //
+ if ( status == TDI_MORE_PROCESSING )
+ {
+ TDI_REQUEST Request ;
+ PRCV_CONTEXT prcvCont = evrcvbuf.erb_context ;
+ ULONG cbRcvLength = evrcvbuf.erb_size ;
+
+ ASSERT( (evrcvbuf.erb_rtn == CompletionRcv) ||
+ (evrcvbuf.erb_rtn == NewSessionCompletionRoutine))
+ Request.RequestNotifyObject = evrcvbuf.erb_rtn ;
+ Request.RequestContext = prcvCont ;
+ Request.Handle.ConnectionContext = pLowerConn->pFileObject ;
+
+ status = TdiVxdReceive( &Request,
+ &usFlags,
+ &cbRcvLength,
+ &prcvCont->ndisBuff ) ;
+ if ( status != TDI_PENDING )
+ {
+ DbgPrint("Reindicate: Error returned from TdiVxdReceive - 0x") ;
+ DbgPrintNum( status ) ;
+ DbgPrint("\r\n") ;
+ CTEIoComplete( prcvCont->pNCB, status, 0 ) ;
+ }
+ else
+ {
+ status = TDI_SUCCESS ;
+ }
+ }
+
+ return status ;
+}
+
+//----------------------------------------------------------------------------
+
+ TDI_STATUS
+TdiConnectHandler (
+ IN PVOID pConnectEventContext,
+ IN int RemoteAddressLength,
+ IN PVOID pRemoteAddress,
+ IN int UserDataLength,
+ IN PVOID pUserData,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN PVOID * AcceptingID,
+ ConnectEventInfo * pEventInfo //OUT CONNECTION_CONTEXT *pConnectionContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is connect event handler. It is invoked when a request for
+ a connection has been received by the provider. NBT accepts the connection
+ on one of its connections in its LowerConnFree list
+
+ Initially a TCP connection is setup with this port. Then a Session Request
+ packet is sent across the connection to indicate the name of the destination
+ process. This packet is received in the RcvHandler.
+
+Arguments:
+
+ pConnectEventContext - the context passed to the transport when this event was setup
+ RemoteAddressLength - the length of the source address (4 bytes for IP)
+ pRemoteAddress - a ptr to the source address
+ UserDataLength - the number of bytes of user data - includes the session Request hdr
+ pUserData - ptr the the user data passed in
+ OptionsLength - number of options to pass in
+ pOptions - ptr to the options
+
+Return Value:
+
+ pConnectionContext - connection context returned to the transport(connection to use)
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ tDEVICECONTEXT * pDeviceContext;
+ tLOWERCONNECTION * pLowerConn ;
+ PTDI_CONNECTION_INFO pConnInfo ;
+
+ DbgPrint("TdiConnectHandler: Entered\r\n") ;
+
+ // convert the context value into the device context record ptr
+ pDeviceContext = (tDEVICECONTEXT *)pConnectEventContext;
+
+ ASSERTMSG("Bad Device context passed to the Connection Event Handler",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+
+ // call the non-OS specific routine to find a free connection.
+
+ status = ConnectHndlrNotOs(
+ pConnectEventContext,
+ RemoteAddressLength,
+ pRemoteAddress,
+ UserDataLength,
+ pUserData,
+ &pLowerConn );
+
+ if (!NT_SUCCESS(status))
+ {
+ DbgPrint("TdiConnectHandler: NO FREE CONNECTIONS in connect handler\r\n");
+ return STATUS_DATA_NOT_ACCEPTED ;
+ }
+
+ //
+ // Fill in the completion information
+ //
+ pEventInfo->cei_rtn = AcceptCompletionRoutine ;
+ pEventInfo->cei_context = pLowerConn ;
+ pEventInfo->cei_acceptinfo = NULL ;
+ pEventInfo->cei_conninfo = NULL ;
+ *AcceptingID = pLowerConn ; // Connection Context
+
+ return TDI_MORE_PROCESSING ;
+}
+
+//----------------------------------------------------------------------------
+ VOID
+AcceptCompletionRoutine(
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint extra
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of an Accept to the transport.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ tLOWERCONNECTION *pLowerConn;
+
+ DbgPrint("AcceptCompletionRoutine: Entered\r\n") ;
+ pLowerConn = (tLOWERCONNECTION *)pContext;
+
+ if (!NT_SUCCESS(tdistatus) &&
+ (pLowerConn->State == NBT_SESSION_INBOUND))
+ {
+ tDEVICECONTEXT *pDeviceContext;
+ DbgPrint("AcceptCompletionRoutine - Error returned: 0x") ;
+ DbgPrintNum( tdistatus ) ;
+ DbgPrint("\r\n") ;
+
+ // the connection setup failed, so put the lower connection block
+ // back on the free list
+ pLowerConn->State = NBT_IDLE;
+ pDeviceContext = pLowerConn->pDeviceContext;
+
+ //
+ // First remove it from pDeviceContext->LowerConnection
+ //
+ RemoveEntryList( &pLowerConn->Linkage ) ;
+ CTEInterlockedDecrementLong(&pLowerConn->RefCount);
+ InsertHeadList(&pDeviceContext->LowerConnFreeHead,
+ &pLowerConn->Linkage);
+
+ }
+}
+
+//----------------------------------------------------------------------------
+ TDI_STATUS
+TdiDisconnectHandler (
+ PVOID EventContext,
+ PVOID ConnectionContext,
+ ULONG DisconnectDataLength,
+ PVOID pDisconnectData,
+ ULONG DisconnectInformationLength,
+ PVOID pDisconnectInformation,
+ ULONG DisconnectIndicators
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a session is disconnected from a remote
+ machine.
+
+Arguments:
+
+ IN PVOID EventContext,
+ IN PCONNECTION_CONTEXT ConnectionContext,
+ IN ULONG DisconnectDataLength,
+ IN PVOID DisconnectData,
+ IN ULONG DisconnectInformationLength,
+ IN PVOID DisconnectInformation,
+ IN ULONG DisconnectIndicators
+
+Return Value:
+
+ NTSTATUS - Status of event indicator
+
+--*/
+
+{
+
+ TDI_STATUS status ;
+ tDEVICECONTEXT *pDeviceContext;
+
+ DbgPrint("TdiDisconnectHandler: Entered\r\n") ;
+
+ pDeviceContext = (tDEVICECONTEXT *)EventContext;
+ ASSERTMSG("Bad Device context passed to the Disconnect Event Handler",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+
+ status = DisconnectHndlrNotOs(
+ EventContext,
+ ConnectionContext,
+ DisconnectDataLength,
+ pDisconnectData,
+ DisconnectInformationLength,
+ pDisconnectInformation,
+ DisconnectIndicators);
+
+ if (!NT_SUCCESS(status))
+ {
+ DbgPrint("NO FREE CONNECTIONS in connect handler\n\r");
+ status = TDI_CONN_REFUSED ; // return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ DbgPrint("TdiDisconnectHandler: returning\r\n") ;
+ return status ;
+}
+
+//----------------------------------------------------------------------------
+
+TDI_STATUS
+VxdDisconnectHandler ( // Cleans up Netbios stuff for remote
+ IN PVOID DisconnectEventContext, // disconnects
+ IN PVOID ConnectionContext,
+ IN PVOID DisconnectData,
+ IN ULONG DisconnectInformationLength,
+ IN PVOID pDisconnectInformation,
+ IN ULONG DisconnectIndicators
+ )
+/*++
+
+Routine Description:
+
+ Cleans up open Netbios stuff.
+
+ Note this routine gets called from the NCB hangup completion also.
+
+Arguments:
+
+--*/
+{
+ TDI_STATUS tdistatus ;
+ tCLIENTELE * pClientEle = (tCLIENTELE*) DisconnectEventContext ;
+ tCONNECTELE * pConnEle = (tCONNECTELE*) ConnectionContext ;
+ tDEVICECONTEXT * pDeviceContext = pClientEle->pDeviceContext ;
+ tLOWERCONNECTION * pLowerConn;
+ TDI_REQUEST Request ;
+ NCBERR errNCB ;
+ UCHAR lsn ;
+ BOOL fNotified ;
+
+ DbgPrint("VxdDisconnectHandler Entered \r\n") ;
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ) ;
+ ASSERT( (pConnEle->Verify == NBT_VERIFY_CONNECTION) ||
+ (pConnEle->Verify == NBT_VERIFY_CONNECTION_DOWN)) ;
+
+ //
+ // Session is dead, kill off everything
+ //
+
+ if ( errNCB = VxdFindLSN( pDeviceContext,
+ pConnEle,
+ &lsn ))
+ {
+ //
+ // This shouldn't happen but watch for it in case we get in a
+ // weird situation
+ //
+ DbgPrint("VxdDisconnectHandler - Warning: VxdFindLsn failed\r\n") ;
+ }
+
+ REQUIRE( !VxdCompleteSessionNcbs( pDeviceContext,
+ pConnEle )) ;
+
+ pLowerConn = pConnEle->pLowerConnId ;
+ if ( pLowerConn &&
+ (pLowerConn->fOnPartialRcvList == TRUE) &&
+ pLowerConn->StateRcv == PARTIAL_RCV )
+ {
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+ }
+
+ //
+ // The close may free the connection so check if the client has been
+ // notified now.
+ //
+ fNotified = !!(pConnEle->Flags & NB_CLIENT_NOTIFIED) ;
+ Request.Handle.ConnectionContext = pConnEle ;
+ tdistatus = NbtCloseConnection( &Request,
+ NULL,
+ pDeviceContext,
+ NULL ) ;
+ if ( tdistatus )
+ {
+ DbgPrint("VxdDisconnectHandler: NbtCloseConnection returned 0x") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\r\n") ;
+ }
+
+ tdistatus = NbtDisassociateAddress( &Request ) ;
+ if ( tdistatus )
+ {
+ DbgPrint("VxdDisconnectHandler: NbtDisassociateAddress returned 0x") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\r\n") ;
+ }
+
+ if ( !errNCB && fNotified )
+ {
+ REQUIRE( NBUnregister( pDeviceContext,
+ lsn,
+ NB_SESSION )) ;
+ }
+
+ //
+ // If this name has been deleted, check to see if this is the last session,
+ // if so, delete the name
+ //
+ if ( pClientEle->fDeregistered && !ActiveSessions(pClientEle) )
+ {
+ UCHAR NameNum ;
+ if ( VxdFindNameNum( pDeviceContext, pClientEle->pAddress, &NameNum ))
+ {
+ ASSERT( FALSE ) ;
+ return STATUS_UNSUCCESSFUL ;
+ }
+
+ (void) VxdCleanupAddress( pDeviceContext,
+ NULL,
+ pClientEle,
+ NameNum,
+ TRUE ) ;
+ }
+
+ return STATUS_SUCCESS ;
+}
+
+//----------------------------------------------------------------------------
+
+//
+// This structure is the context that is passed to the datagram completion
+// routine when we want TDI to fill in the NCB's buffer
+//
+typedef struct _RCV_DG_COMP_CONTEXT
+{
+ EventRcvBuffer evrcvbuf ;
+ NCB * pncb ;
+ tCLIENTLIST * pClientList ;
+ NDIS_BUFFER ndisRcvBuf ;
+} RCV_DG_COMP_CONTEXT, *PRCV_DG_COMP_CONTEXT ;
+
+ TDI_STATUS
+TdiRcvDatagramHandler(
+ IN PVOID pDgramEventContext,
+ IN int SourceAddressLength,
+ IN PVOID pSourceAddress,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN UINT Flags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *pBytesTaken,
+ IN PVOID pData,
+ OUT EventRcvBuffer * * ppBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive datagram event indication handler.
+
+ It is called when an Datagram arrives from the network, it will look for a
+ the address with an appropriate read datagram outstanding or a Datagrm
+ Event handler setup.
+
+Arguments:
+
+ pDgramEventContext - Context provided for this event - pab
+ SourceAddressLength, - length of the src address
+ pSourceAddress, - src address
+ OptionsLength, - options length for the receive
+ pOptions, - options
+ BytesIndicated, - number of bytes this indication
+ BytesAvailable, - number of bytes in complete Tsdu
+ pTsdu - pointer to the datagram
+
+
+Return Value:
+
+ *pBytesTaken - number of bytes used
+ *IoRequestPacket - Receive IRP if MORE_PROCESSING_REQUIRED.
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ TDI_STATUS tdistatus ;
+ tDEVICECONTEXT * pDeviceContext = (tDEVICECONTEXT *)pDgramEventContext;
+ tCLIENTLIST * pClientList = NULL ;
+ NCB * pncb = NULL ;
+
+ //
+ // Tell TDI we don't want anything unless we change our minds down below
+ //
+ *ppBuffer = NULL ;
+
+ ASSERTMSG("NBT:Invalid Device Context passed to DgramRcv Handler!!\n",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
+
+ // call a non-OS specific routine to decide what to do with the datagrams
+ tdistatus = DgramHndlrNotOs(
+ pDgramEventContext,
+ SourceAddressLength,
+ pSourceAddress,
+ OptionsLength,
+ pOptions,
+ 0, // Receive data flags
+ BytesIndicated,
+ BytesAvailable,
+ pBytesTaken,
+ pData,
+ &pncb,
+ &pClientList ) ;
+ if ( !NT_SUCCESS( tdistatus ) )
+ {
+ // fail the request back to the transport provider since we
+ // could not find a receive buffer or receive handler.
+ return(tdistatus);
+
+ }
+ else
+ {
+ PRCV_DG_COMP_CONTEXT prcvdgContext = NULL ;
+
+ prcvdgContext = CTEAllocMem( sizeof( RCV_DG_COMP_CONTEXT ) ) ;
+ if ( !prcvdgContext )
+ return STATUS_DATA_NOT_ACCEPTED ;
+
+ //
+ // ncb_callname filled in by the NotOs event handler
+ //
+
+ prcvdgContext->evrcvbuf.erb_rtn = CompletionRcvDgram ;
+ prcvdgContext->evrcvbuf.erb_size = BytesAvailable - *pBytesTaken ;
+ prcvdgContext->evrcvbuf.erb_context = prcvdgContext ;
+ prcvdgContext->evrcvbuf.erb_buffer = &prcvdgContext->ndisRcvBuf ;
+ prcvdgContext->pncb = pncb ;
+ prcvdgContext->evrcvbuf.erb_flags = NULL ;
+ prcvdgContext->pClientList = pClientList ;
+ InitNDISBuff( prcvdgContext->evrcvbuf.erb_buffer,
+ pncb->ncb_buffer,
+ pncb->ncb_length,
+ NULL ) ;
+ *ppBuffer = &prcvdgContext->evrcvbuf ;
+ return TDI_MORE_PROCESSING ;
+ }
+
+ //
+ // Transport will complete the processing of the request, we don't
+ // want the datagram.
+ //
+
+ return STATUS_DATA_NOT_ACCEPTED;
+}
+
+//----------------------------------------------------------------------------
+ TDI_STATUS
+TdiRcvNameSrvHandler(
+ IN PVOID pDgramEventContext,
+ IN int SourceAddressLength,
+ IN PVOID pSourceAddress,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN UINT Flags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *pBytesTaken,
+ IN PVOID pTsdu,
+ OUT EventRcvBuffer * * ppBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine is the Name Service datagram event indication handler.
+ It gets all datagrams destined for UDP port 137
+
+
+Arguments:
+
+ pDgramEventContext - Context provided for this event - pab
+ SourceAddressLength, - length of the src address
+ pSourceAddress, - src address
+ OptionsLength, - options length for the receive
+ pOptions, - options
+ BytesIndicated, - number of bytes this indication
+ BytesAvailable, - number of bytes in complete Tsdu
+ pTsdu - pointer to the datagram
+
+
+Return Value:
+
+ *pBytesTaken - number of bytes used
+ *IoRequestPacket - Receive IRP if MORE_PROCESSING_REQUIRED.
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ TDI_STATUS tdistatus ;
+ tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)pDgramEventContext;
+ tNAMEHDR *pNameSrv = (tNAMEHDR *)pTsdu;
+
+ //
+ // No receive buffer
+ //
+ *ppBuffer = NULL ;
+
+ ASSERTMSG("NBT:The Device Context does not have the correct Verification value!!\n",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
+
+
+ // call a non-OS specific routine to decide what to do with the datagrams
+ status = NameSrvHndlrNotOs(
+ pDeviceContext,
+ pSourceAddress,
+ pNameSrv,
+ BytesIndicated);
+
+ return status ;
+
+ // to keep the compiler from generating warnings...
+ UNREFERENCED_PARAMETER( SourceAddressLength );
+ UNREFERENCED_PARAMETER( BytesIndicated );
+ UNREFERENCED_PARAMETER( BytesAvailable );
+ UNREFERENCED_PARAMETER( pBytesTaken );
+ UNREFERENCED_PARAMETER( pTsdu );
+ UNREFERENCED_PARAMETER( OptionsLength );
+ UNREFERENCED_PARAMETER( pOptions );
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+CompletionRcvDgram(
+ IN PVOID Context,
+ IN UINT tdistatus,
+ IN UINT RcvdSize
+ )
+/*++
+
+Routine Description:
+
+ This routine completes the receive datagram NCB. If multiple clients
+ were listenning then the largest NCB is used as a template and the
+ rest are completed from it.
+
+
+Arguments:
+
+ Context - Pointer to a RCV_DG_COMP_CONTEXT structure set above
+ tdistatus - Completion status
+ Rcvdsize - Number of bytes copied
+
+--*/
+{
+ PRCV_DG_COMP_CONTEXT prcvdgContext = Context ;
+ NCB * pncb = prcvdgContext->pncb ;
+ tCLIENTLIST * pClientList = prcvdgContext->pClientList;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ NTSTATUS status;
+
+ //
+ // Check to see if our buffer was big enough to get all the data
+ //
+ if ( !tdistatus &&
+ prcvdgContext->evrcvbuf.erb_size > pncb->ncb_length )
+ {
+ tdistatus = STATUS_BUFFER_OVERFLOW ;
+ }
+
+ //
+ // there may be several clients that want to see this datagram so check
+ // the client list to see...
+ //
+ if ( pClientList )
+ {
+ pHead = &pClientList->pAddress->ClientHead;
+ pEntry = pHead->Flink;
+
+#ifdef PROXY_NODE
+ if (!pClientList->fProxy)
+ {
+#endif
+ // *** Client Has posted a receive Buffer, rather than using
+ // *** receive handler - VXD case!
+ // ***
+ while (pEntry != pHead)
+ {
+ tCLIENTELE * pClientEle;
+ NCB * pncbDest ;
+
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+
+ CTEInterlockedIncrementLong(&pClientEle->RefCount);
+
+ if (pClientEle == pClientList->pClientEle)
+ {
+ // this is the client whose buffer we are using - it is
+ // passed up to the client after all other clients
+ // have been processed.
+ //
+ }
+ else
+ if (!IsListEmpty(&pClientEle->RcvDgramHead))
+ {
+ PLIST_ENTRY pRcvEntry;
+ tRCVELE * pRcvEle;
+ TDI_STATUS tdistatusTmp ;
+ UINT BytesToCopy = 0 ;
+
+ pRcvEntry = RemoveHeadList(&pClientEle->RcvDgramHead);
+ pRcvEle = CONTAINING_RECORD(pRcvEntry,tRCVELE,Linkage);
+ pncbDest = (NCB*) pRcvEle->pIrp ;
+ ASSERT( pncbDest ) ;
+
+ //
+ // Only copy the data and call name if we successfully
+ // completed the datagram
+ //
+ if ( !tdistatus || tdistatus == STATUS_BUFFER_OVERFLOW )
+ {
+ BytesToCopy = min( pncbDest->ncb_length, RcvdSize ) ;
+
+ CTEMemCopy( pncbDest->ncb_buffer,
+ pncb->ncb_buffer,
+ BytesToCopy ) ;
+ CTEMemCopy( pncbDest->ncb_callname,
+ pncb->ncb_callname,
+ NETBIOS_NAME_SIZE ) ;
+
+ if ( pncbDest->ncb_length < RcvdSize ||
+ (pncbDest->ncb_length == RcvdSize &&
+ tdistatus == STATUS_BUFFER_OVERFLOW) )
+ {
+ tdistatusTmp = STATUS_BUFFER_OVERFLOW ;
+ }
+ else
+ tdistatusTmp = STATUS_SUCCESS ;
+ }
+ else
+ {
+ tdistatusTmp = tdistatus ;
+ }
+
+ CTEIoComplete( pncbDest, tdistatusTmp, BytesToCopy ) ;
+
+ // free the receive block
+ CTEMemFree((PVOID)pRcvEle);
+
+ }
+
+ pEntry = pEntry->Flink;
+
+ CTEInterlockedDecrementLong(&pClientEle->RefCount);
+
+
+ } // of while(pEntry != pHead)
+
+ //
+ // The address was referenced in DgramRcvNotOs to be sure
+ // it did not disappear until this dgram rcv was done, which
+ // is now.
+ //
+ NbtDereferenceAddress( pClientList->pAddress ) ;
+
+#ifdef PROXY_NODE
+ }
+ else
+ {
+ //
+ // Call the ProxyDoDgramDist
+ //
+ status = ProxyDoDgramDist(
+ (tDGRAMHDR *)pncb->ncb_buffer,
+ RcvdSize,
+ (tNAMEADDR *)pClientList->pAddress, //NameAddr
+ pClientList->pRemoteAddress //device context
+ );
+
+ }
+#endif
+
+
+ //
+ // Free the buffers allocated
+ //
+ if (!pClientList->fProxy)
+ {
+ CTEMemFree(pClientList->pRemoteAddress);
+ }
+ CTEMemFree(Context);
+ }
+
+ //
+ // Finally complete our template NCB (or only NCB if single receive)
+ //
+ CTEIoComplete( pncb, tdistatus, RcvdSize ) ;
+ CTEMemFree( prcvdgContext ) ;
+
+}
+//----------------------------------------------------------------------------
+ TDI_STATUS
+TdiErrorHandler (
+ IN PVOID Context,
+ IN ULONG Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called on any error indications passed back from the
+ transport. It implements LAN_STATUS_ALERT.
+
+Arguments:
+
+ Context - Supplies the pfcb for the address.
+
+ Status - Supplies the error.
+
+Return Value:
+
+ NTSTATUS - Status of event indication
+
+--*/
+
+{
+ DbgPrint("Nbt: Error Event HAndler hit unexpectedly\r\n");
+ return TDI_INVALID_REQUEST ;
+}