|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
tdihdlr.c
Abstract:
This module implements the NT TDI event handler routines.
Revision History:
Balan Sethu Raman [SethuR] 15-Feb-1995
Notes:
--*/
#include "precomp.h"
#pragma hdrstop
#include "tdikrnl.h"
#include "rxtdip.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_RXCETDI)
extern NTSTATUS ReceiveEventHandler( IN BOOLEAN fExpedited, IN PRXCE_ADDRESS pAddress, IN PRXCE_VC pVc, IN ULONG ReceiveFlags, IN ULONG BytesIndicated, IN ULONG BytesAvailable, OUT ULONG *BytesTaken, IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
OUT PIRP *pIrp // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
);
extern NTSTATUS ReceiveEventPostProcessing( PRXCE_VC pVc, PRXCE_CONNECTION pConnection, PMDL pDataBuffer, ULONG DataBufferSize, PIRP *pIrpPointer);
extern VOID ReceiveDatagramEventPostProcessing( PRXCE_ADDRESS pAddress, PMDL pDataBuffer, ULONG DataBufferSize, PIRP *pIrpPointer);
NTSTATUS RxTdiConnectEventHandler( IN PVOID TdiEventContext, IN LONG RemoteAddressLength, IN PVOID RemoteAddress, IN LONG UserDataLength, IN PVOID UserData, IN LONG OptionsLength, IN PVOID Options, OUT CONNECTION_CONTEXT *ConnectionContext, OUT PIRP *AcceptIrp ) /*++
Routine Description:
This routine is called when a connect request has completed. The connection is fully functional when the indication occurs.
Arguments:
TdiEventContext - the context value passed in by the user in the Set Event Handler call
RemoteAddressLength,
RemoteAddress,
UserDataLength,
UserData,
OptionsLength,
Options,
ConnectionId
Return Value:
The function value is the final status from the initialization operation.
--*/ { UNREFERENCED_PARAMETER (TdiEventContext); UNREFERENCED_PARAMETER (RemoteAddressLength); UNREFERENCED_PARAMETER (RemoteAddress); UNREFERENCED_PARAMETER (UserDataLength); UNREFERENCED_PARAMETER (UserData); UNREFERENCED_PARAMETER (OptionsLength); UNREFERENCED_PARAMETER (Options); UNREFERENCED_PARAMETER (ConnectionContext);
return STATUS_INSUFFICIENT_RESOURCES; // do nothing
}
NTSTATUS RxTdiDisconnectEventHandler( IN PVOID EventContext, IN CONNECTION_CONTEXT ConnectionContext, IN LONG DisconnectDataLength, IN PVOID DisconnectData, IN LONG DisconnectInformationLength, IN PVOID DisconnectInformation, IN ULONG DisconnectFlags ) /*++
Routine Description:
This routine is used as the demultiplexing point for handling any connection disconnects for any address registered with the RxCe.
Arguments:
EventContext - the hAddress of the associated endpoint.
ConnectionContext - the hVc associated with the connection.
DisconnectIndicators - Value indicating reason for disconnection indication.
Return Value:
NTSTATUS - status of operation.
--*/ { NTSTATUS Status = STATUS_SUCCESS;
PRXCE_VC pVc = (PRXCE_VC)ConnectionContext; PRXCE_ADDRESS pAddress = (PRXCE_ADDRESS)EventContext;
PRXCE_TRANSPORT pTransport; PRXCE_CONNECTION pConnection;
RxProfile(RxTdi,RxTdiDisconnectEventHandler);
try { if (RxCeIsVcValid(pVc) && (pVc->pConnection->pAddress == pAddress)) { pConnection = pVc->pConnection;
ASSERT(RxCeIsConnectionValid(pConnection));
if ( // There is a event handler associated with this connection
(pConnection->pHandler != NULL) && // and the disconnect event handler has been specified
(pConnection->pHandler->RxCeDisconnectEventHandler != NULL)) {
Status = pConnection->pHandler->RxCeDisconnectEventHandler( pConnection->pContext, pVc, DisconnectDataLength, DisconnectData, DisconnectInformationLength, DisconnectInformation, DisconnectFlags);
if (!NT_SUCCESS(Status)) { RxDbgTrace(0, Dbg, ("Disconnect event handler notification returned %lx\n",Status)); } }
// The final action irrespective of the action taken by the handlers specified.
if (DisconnectFlags & TDI_DISCONNECT_RELEASE) { // The disconnect has to be confirmed.
// Status = RxTdiDisconnect(
// pTransport,
// pAddress,
// pConnection,
// pVc,
// RXCE_DISCONNECT_RELEASE);
}
// Mark the status of the local connection to prevent any subsequent sends
// on this connection.
InterlockedCompareExchange( &pVc->State, RXCE_VC_DISCONNECTED, RXCE_VC_ACTIVE); } } except(EXCEPTION_EXECUTE_HANDLER) { Status = STATUS_INVALID_PARAMETER; }
return Status; }
NTSTATUS RxTdiErrorEventHandler( IN PVOID TdiEventContext, IN NTSTATUS Status // status code indicating error type.
) /*++
Routine Description:
This routine is used as the default error event handler for the transport endpoint. It is pointed to by a field in the TP_ENDPOINT structure for an endpoint when the endpoint is created, and also whenever the TdiSetEventHandler request is submitted with a NULL EventHandler field.
Arguments:
TransportEndpoint - Pointer to open file object.
Status - Status code indicated by this event.
Return Value:
NTSTATUS - status of operation.
--*/
{ UNREFERENCED_PARAMETER (TdiEventContext); UNREFERENCED_PARAMETER (Status);
return STATUS_SUCCESS; }
NTSTATUS RxTdiReceiveEventHandler( IN PVOID EventContext, IN CONNECTION_CONTEXT ConnectionContext, IN ULONG ReceiveFlags, IN ULONG BytesIndicated, IN ULONG BytesAvailable, OUT ULONG *BytesTaken, IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
) /*++
Routine Description:
This routine is used as the receive event handler for the transport endpoint.
Arguments:
EventContext - hAddresst.
ConnectionContext - The client-supplied context associated with the connection on which this connection-oriented TSDU was received.
ReceiveIndicators - Bitflags which indicate the circumstances surrounding this TSDU's reception.
Tsdu - Pointer to an MDL chain that describes the (first) part of the (partially) received Transport Service Data Unit, less headers.
IoRequestPacket - Pointer to a location where the event handler may chose to return a pointer to an I/O Request Packet (IRP) to satisfy the incoming data. If returned, this IRP must be formatted as a valid TdiReceive request, except that the ConnectionId field of the TdiRequest is ignored and is automatically filled in by the transport provider.
Return Value:
NTSTATUS - status of operation.
--*/
{ return ReceiveEventHandler( FALSE, // regular receive
(PRXCE_ADDRESS)EventContext, (PRXCE_VC)ConnectionContext, ReceiveFlags, BytesIndicated, BytesAvailable, BytesTaken, Tsdu, IoRequestPacket); }
NTSTATUS RxTdiReceiveDatagramEventHandler( IN PVOID EventContext, // the event context
IN LONG SourceAddressLength, // length of the originator of the datagram
IN PVOID SourceAddress, // string describing the originator of the datagram
IN LONG OptionsLength, // options for the receive
IN PVOID Options, //
IN ULONG ReceiveDatagramFlags, //
IN ULONG BytesIndicated, // number of bytes this indication
IN ULONG BytesAvailable, // number of bytes in complete Tsdu
OUT ULONG *BytesTaken, // number of bytes used
IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
OUT PIRP *pIrp // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
) /*++
Routine Description:
This routine is used as the default receive datagram event handler for the transport endpoint. It is pointed to by a field in the TP_ENDPOINT structure for an endpoint when the endpoint is created, and also whenever the TdiSetEventHandler request is submitted with a NULL EventHandler field.
Arguments:
EventContext - event context ( hAddress )
SourceAddress - Pointer to the network name of the source from which the datagram originated.
Return Value:
NTSTATUS - status of operation.
--*/
{ NTSTATUS Status = STATUS_SUCCESS;
PRXCE_ADDRESS pAddress = (PRXCE_ADDRESS)EventContext; PRXCE_TRANSPORT pTransport;
PMDL pDataBuffer; ULONG DataBufferSize;
RxProfile(RxTdi,RxCeReceiveDatagramEventHandler);
ASSERT(RxCeIsAddressValid(pAddress));
// Check if we have an event handler associated with this address
if ( // There is a event handler associated with this address
(pAddress->pHandler != NULL)
&&
// and the expedited receive datagram handler has been specified
(pAddress->pHandler->RxCeReceiveDatagramEventHandler != NULL) ) {
Status = pAddress->pHandler->RxCeReceiveDatagramEventHandler( pAddress->pContext, SourceAddressLength, SourceAddress, OptionsLength, Options, ReceiveDatagramFlags, BytesIndicated, BytesAvailable, BytesTaken, Tsdu, &pDataBuffer, &DataBufferSize);
switch (Status) { case STATUS_SUCCESS: case STATUS_DATA_NOT_ACCEPTED: break;
case STATUS_MORE_PROCESSING_REQUIRED: ReceiveDatagramEventPostProcessing( pAddress, pDataBuffer, DataBufferSize, pIrp); break;
default: // log the error.
break; } } else { // No handler is associated. Take the default action.
Status = STATUS_DATA_NOT_ACCEPTED; }
return Status; }
NTSTATUS RxTdiReceiveExpeditedEventHandler( IN PVOID EventContext, IN CONNECTION_CONTEXT ConnectionContext, IN ULONG ReceiveFlags, //
IN ULONG BytesIndicated, // number of bytes in this indication
IN ULONG BytesAvailable, // number of bytes in complete Tsdu
OUT ULONG *BytesTaken, // number of bytes used by indication routine
IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
) /*++
Routine Description:
Arguments:
EventContext - the context value passed in by the user in the Set Event Handler call
Return Value:
The function value is the final status from the initialization operation.
--*/ { return ReceiveEventHandler( TRUE, // expedited receive
(PRXCE_ADDRESS)EventContext, (PRXCE_VC)ConnectionContext, ReceiveFlags, BytesIndicated, BytesAvailable, BytesTaken, Tsdu, IoRequestPacket); }
NTSTATUS RxTdiSendPossibleEventHandler ( IN PVOID EventContext, IN PVOID ConnectionContext, IN ULONG BytesAvailable) /*++
Routine Description:
Arguments:
EventContext - the context value passed in by the user in the Set Event Handler call
ConnectionContext - connection context of connection which can be sent on
BytesAvailable - number of bytes which can now be sent
Return Value:
ignored by the transport
--*/
{ NTSTATUS Status = STATUS_SUCCESS;
PRXCE_TRANSPORT pTransport; PRXCE_ADDRESS pAddress; PRXCE_VC pVc; PRXCE_CONNECTION pConnection;
RxProfile(RxTdi,RxCeSendPossibleEventHandler);
pVc = (PRXCE_VC)ConnectionContext; pConnection = pVc->pConnection; pAddress = pConnection->pAddress; pTransport = pAddress->pTransport;
if (NT_SUCCESS(Status)) { // Check if we have an event handler associated with this connection.
if ( // There is a event handler associated with this connection
(pConnection->pHandler != NULL)
&&
// and the expedited send possible event handler has been specified
(pConnection->pHandler->RxCeSendPossibleEventHandler != NULL) ) {
Status = pConnection->pHandler->RxCeSendPossibleEventHandler( pConnection->pContext, pVc, BytesAvailable); } else { // No handler is associated. Take the default action.
Status = STATUS_SUCCESS; } }
return Status; }
NTSTATUS ReceiveEventHandler( IN BOOLEAN fExpedited, IN PRXCE_ADDRESS pAddress, IN PRXCE_VC pVc, IN ULONG ReceiveFlags, IN ULONG BytesIndicated, IN ULONG BytesAvailable, OUT ULONG *BytesTaken, IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
OUT PIRP *pIrp // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
) /*++
Routine Description:
This routine is used as the receive event handler for the transport endpoint.
Arguments:
fExpedited - TRUE if it was a TDI_EXPEDITED_RECEIVE event
EventContext - hAddress.
ConnectionContext - The client-supplied context associated with the connection on which this connection-oriented TSDU was received.
ReceiveIndicators - Bitflags which indicate the circumstances surrounding this TSDU's reception.
Tsdu - Pointer to an MDL chain that describes the (first) part of the (partially) received Transport Service Data Unit, less headers.
IoRequestPacket - Pointer to a location where the event handler may chose to return a pointer to an I/O Request Packet (IRP) to satisfy the incoming data. If returned, this IRP must be formatted as a valid TdiReceive request, except that the ConnectionId field of the TdiRequest is ignored and is automatically filled in by the transport provider.
Return Value:
NTSTATUS - status of operation.
--*/
{ NTSTATUS Status = STATUS_UNSUCCESSFUL;
PMDL pDataBuffer = NULL; ULONG DataBufferSize;
PRXCE_CONNECTION pConnection;
RxProfile(RxTdi,ReceiveEventHandler);
ASSERT(RxCeIsVcValid(pVc));
if (ReceiveFlags & TDI_RECEIVE_PARTIAL) { // Stream mode transports always set this flag. They need to be handled in a
// different way. The clients of RxCe need only be notified when we have
// receieved a complete TSDU.
Status = STATUS_DATA_NOT_ACCEPTED; } else { pConnection = pVc->pConnection; ASSERT(RxCeIsConnectionValid(pConnection));
// Check if we have an event handler associated with this connection.
if ( // There is a event handler associated with this connection
(pConnection->pHandler != NULL) ) { if (fExpedited) { // Expedited receive
// and the expedited receive event handler has been specified
if (pConnection->pHandler->RxCeReceiveExpeditedEventHandler != NULL) {
Status = pConnection->pHandler->RxCeReceiveExpeditedEventHandler( pConnection->pContext, pVc, ReceiveFlags, BytesIndicated, BytesAvailable, BytesTaken, Tsdu, &pDataBuffer, &DataBufferSize); } } else if (pConnection->pHandler->RxCeReceiveEventHandler != NULL) { Status = pConnection->pHandler->RxCeReceiveEventHandler( pConnection->pContext, pVc, ReceiveFlags, BytesIndicated, BytesAvailable, BytesTaken, Tsdu, &pDataBuffer, &DataBufferSize); }
switch (Status) { case STATUS_SUCCESS: case STATUS_DATA_NOT_ACCEPTED: break;
case STATUS_MORE_PROCESSING_REQUIRED: { Status = ReceiveEventPostProcessing( pVc, pConnection, pDataBuffer, DataBufferSize, pIrp); } break;
default: RxDbgTrace(0, Dbg, ("Receive Event Notification returned %lx\n",Status)); break; } } }
return Status; }
NTSTATUS RxTdiReceiveCompletion( PDEVICE_OBJECT pDeviceObject, PIRP pIrp, PVOID pContext) /*++
Routine Description:
This routine is invoked upon completion of the reception of the desired amount of data.
Arguments:
pDeviceObject - the device object
pIrp - the IRP
pContext - the connection handle
--*/ { PRXCE_VC pVc = (PRXCE_VC)pContext;
if (pVc != NULL) { NTSTATUS Status; ULONG BytesCopied = (ULONG)pIrp->IoStatus.Information; PRXCE_CONNECTION pConnection = pVc->pConnection;
ASSERT( RxCeIsVcValid(pVc) && RxCeIsConnectionValid(pConnection));
if (pConnection->pHandler->RxCeDataReadyEventHandler != NULL) { Status = pConnection->pHandler->RxCeDataReadyEventHandler( pConnection->pContext, pVc->pReceiveMdl, BytesCopied, pIrp->IoStatus.Status); }
pVc->pReceiveMdl = NULL; } else { ASSERT(!"Valid connection handle for receive completion"); }
RxCeFreeIrp(pIrp);
//
// Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
// will stop working on the IRP.
//
return STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS ReceiveEventPostProcessing( PRXCE_VC pVc, PRXCE_CONNECTION pConnection, PMDL pDataMdl, ULONG DataBufferSize, PIRP *pIrpPointer) /*++
Routine Description:
This routine is invoked when a recieve event notification to a connection engine client results in further requests for copying the data out of the transport drivers buffers
Arguments:
pDataBuffer - the buffer into which the data should be copied
DataBufferSize - the size of the data
pIrpPointer - the IRP to the transport driver for processing the copy request.
Return Value:
STATUS_MORE_PROCESSING_REQUIRED -- if successful otherwise appropriate error code
--*/ { NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
PRXCE_ADDRESS pAddress = pConnection->pAddress; PRXCE_TRANSPORT pTransport = pAddress->pTransport; PIRP pIrp;
ASSERT(RxCeIsAddressValid(pAddress)); ASSERT(RxCeIsTransportValid(pTransport));
ASSERT(pConnection->pHandler->RxCeDataReadyEventHandler != NULL);
pIrp = RxCeAllocateIrpWithMDL(pTransport->pDeviceObject->StackSize,FALSE,pDataMdl); *pIrpPointer = pIrp; if (pIrp != NULL) { pVc->pReceiveMdl = pDataMdl;
TdiBuildReceive( pIrp, // the IRP
pTransport->pDeviceObject, // the device object
pVc->pEndpointFileObject, // the connection (VC) file object
RxTdiReceiveCompletion, // Completion routine
pVc, // completion context
pDataMdl, // the data buffer
0, // receive flags
DataBufferSize); // receive buffer length
//
// Make the next stack location current. Normally IoCallDriver would
// do this, but for this IRP it has been bypassed.
//
IoSetNextIrpStackLocation(pIrp); } else { // An IRP for receiving the data was not allocated. Invoke the error handler
// to communicate the status back.
ASSERT(pConnection->pHandler->RxCeDataReadyEventHandler != NULL); if (pConnection->pHandler->RxCeDataReadyEventHandler != NULL) { Status = pConnection->pHandler->RxCeDataReadyEventHandler( pConnection->pContext, pDataMdl, 0, STATUS_INSUFFICIENT_RESOURCES); }
Status = STATUS_DATA_NOT_ACCEPTED; }
return Status; }
NTSTATUS RxTdiReceiveDatagramCompletion( PDEVICE_OBJECT pDeviceObject, PIRP pIrp, PVOID pContext) /*++
Routine Description:
This routine is invoked upon completion of the reception of the desired amount of data.
Arguments:
pDeviceObject - the device object
pIrp - the IRP
pContext - the connection handle
--*/ { NTSTATUS Status; PRXCE_ADDRESS pAddress = (PRXCE_ADDRESS)pContext;
ASSERT(RxCeIsAddressValid(pAddress));
if (pAddress != NULL) { ULONG BytesCopied = (ULONG)pIrp->IoStatus.Information;
if (pAddress->pHandler->RxCeDataReadyEventHandler != NULL) { Status = pAddress->pHandler->RxCeDataReadyEventHandler( pAddress->pContext, pAddress->pReceiveMdl, BytesCopied, pIrp->IoStatus.Status); }
pAddress->pReceiveMdl = NULL; } else { ASSERT(!"Valid Address handle for receive datagram completion"); }
RxCeFreeIrp(pIrp);
//
// Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
// will stop working on the IRP.
//
return STATUS_MORE_PROCESSING_REQUIRED; }
VOID ReceiveDatagramEventPostProcessing( PRXCE_ADDRESS pAddress, PMDL pDataMdl, ULONG DataBufferSize, PIRP *pIrpPointer) /*++
Routine Description:
This routine is invoked when a recieve event notification to a connection engine client results in further requests for copying the data out of the transport drivers buffers
Arguments:
pDataBuffer - the buffer into which the data should be copied
DataBufferSize - the size of the data
pIrpPointer - the IRP to the transport driver for processing the copy request.
Return Value:
a STATUS_SUCCESS returned from this routine only implies that an IRP for processing the request was setup correctly.
--*/ { PIRP pIrp; PRXCE_TRANSPORT pTransport = pAddress->pTransport;
ASSERT(RxCeIsTransportValid(pTransport)); ASSERT(pAddress->pHandler->RxCeDataReadyEventHandler != NULL);
*pIrpPointer = pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE); if (pIrp != NULL) { pAddress->pReceiveMdl = pDataMdl;
TdiBuildReceive( pIrp, // the IRP
pTransport->pDeviceObject, // the device object
pAddress->pFileObject, // the connection (VC) file object
RxTdiReceiveDatagramCompletion, // Completion routine
pAddress, // completion context
pDataMdl, // the data buffer
0, // send flags
DataBufferSize); // send buffer length
//
// Make the next stack location current. Normally IoCallDriver would
// do this, but for this IRP it has been bypassed.
//
IoSetNextIrpStackLocation(pIrp); } else { // An IRP for receiving the data was not allocated. Invoke the error handler
// to communicate the status back.
if (pAddress->pHandler->RxCeErrorEventHandler != NULL) { pAddress->pHandler->RxCeErrorEventHandler( pAddress->pContext, STATUS_INSUFFICIENT_RESOURCES); } else { // No error handler to handle an erroneous situation.
} } }
|