|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
cdpsend.c
Abstract:
TDI Receive datagram routines.
Author:
Mike Massa (mikemas) February 20, 1997
Revision History:
Who When What -------- -------- ---------------------------------------------- mikemas 02-20-97 created
Notes:
--*/
#include "precomp.h"
#pragma hdrstop
#include "cdprecv.tmh"
#include <sspi.h>
#ifdef ALLOC_PRAGMA
#endif // ALLOC_PRAGMA
//
// Local types
//
typedef struct { CL_NODE_ID SourceNodeId; USHORT SourcePort; ULONG TdiReceiveDatagramFlags; ULONG TsduSize; PCX_ADDROBJ AddrObj; PCNP_NETWORK Network; } CDP_RECEIVE_CONTEXT, *PCDP_RECEIVE_CONTEXT;
//
// Local Data
//
PCN_RESOURCE_POOL CdpReceiveRequestPool = NULL;
#define CDP_RECEIVE_REQUEST_POOL_DEPTH 2
//
// Local utility routines
//
VOID CdpIndicateReceivePacket( IN PCX_ADDROBJ AddrObj, IN CL_NODE_ID SourceNodeId, IN USHORT SourcePort, IN ULONG TdiReceiveDatagramFlags, IN ULONG TsduSize, IN PVOID Tsdu, IN BOOLEAN DataVerified ) /*++
Notes:
Called with address object lock held. Returns with address object lock released.
--*/ { NTSTATUS status; PTDI_IND_RECEIVE_DATAGRAM handler = AddrObj->ReceiveDatagramHandler; PVOID context = AddrObj->ReceiveDatagramContext; TA_CLUSTER_ADDRESS sourceTransportAddress; PIRP irp = NULL; ULONG bytesTaken = 0;
CnVerifyCpuLockMask( CX_ADDROBJ_LOCK, // Required
0, // Forbidden
CX_ADDROBJ_LOCK_MAX // Maximum
);
CnAssert(handler != NULL);
CnReleaseLock(&(AddrObj->Lock), AddrObj->Irql);
//
// Build the source address buffer
//
CxBuildTdiAddress( &sourceTransportAddress, SourceNodeId, SourcePort, DataVerified );
CnTrace(CDP_RECV_DETAIL, CdpTraceIndicateReceive, "[CDP] Indicating dgram, src: node %u port %u, dst: port %u, " "data len %u", SourceNodeId, // LOGULONG
SourcePort, // LOGUSHORT
AddrObj->LocalPort, // LOGUSHORT
TsduSize // LOGULONG
);
//
// Call the upper layer indication handler.
//
status = (*handler)( context, sizeof(TA_CLUSTER_ADDRESS), &sourceTransportAddress, 0, // no options
NULL, TdiReceiveDatagramFlags, TsduSize, TsduSize, &bytesTaken, Tsdu, &irp );
CnAssert(status != STATUS_MORE_PROCESSING_REQUIRED); CnAssert(bytesTaken == TsduSize); CnAssert(irp == NULL);
if (irp != NULL) { irp->IoStatus.Status = STATUS_UNSUCCESSFUL; irp->IoStatus.Information = 0; IoCompleteRequest(irp, IO_NETWORK_INCREMENT); }
//
// Dereference the address object
//
CnDereferenceFsContext(&(AddrObj->FsContext));
CnVerifyCpuLockMask( 0, // Required
0xFFFFFFFF, // Forbidden
0 // Maximum
);
return;
} // CdpIndicateReceivePacket
NTSTATUS CdpCompleteReceivePacket( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { NTSTATUS status; PCNP_RECEIVE_REQUEST request = Context; PCDP_RECEIVE_CONTEXT context = request->UpperProtocolContext; PCX_ADDROBJ addrObj = context->AddrObj; ULONG consumed; PVOID data; ULONG dataLength; BOOLEAN fscontextDereferenced = FALSE;
if (Irp->IoStatus.Status == STATUS_SUCCESS) { CnAssert(Irp->IoStatus.Information == context->TsduSize);
data = request->DataBuffer; dataLength = (ULONG)Irp->IoStatus.Information;
CnAcquireLock(&(addrObj->Lock), &(addrObj->Irql));
if (addrObj->ReceiveDatagramHandler != NULL) { CdpIndicateReceivePacket( addrObj, context->SourceNodeId, context->SourcePort, context->TdiReceiveDatagramFlags, dataLength, data, FALSE // not verified
); fscontextDereferenced = TRUE; } else { CnReleaseLock(&(addrObj->Lock), addrObj->Irql); } } else { CnTrace(CDP_RECV_ERROR, CdpTraceCompleteReceiveFailed, "[CDP] Failed to fetch dgram data, src: node %u port %u, " "dst: port %u, status %!status!", context->SourceNodeId, // LOGULONG
context->SourcePort, // LOGUSHORT
addrObj->LocalPort, // LOGUSHORT
Irp->IoStatus.Status // LOGSTATUS
); }
//
// Drop the active reference on the network.
//
if (context->Network != NULL) { CnAcquireLock(&(context->Network->Lock), &(context->Network->Irql)); CnpActiveDereferenceNetwork(context->Network); context->Network = NULL; }
//
// Dereference the addr object fscontext (only necessary
// after error condition).
//
if (!fscontextDereferenced) { CnDereferenceFsContext(&(addrObj->FsContext)); }
CnpFreeReceiveRequest(request);
CnVerifyCpuLockMask( 0, // Required
0xFFFFFFFF, // Forbidden
0 // Maximum
);
return(STATUS_MORE_PROCESSING_REQUIRED);
} // CdpCompleteReceivePacket
//
// Routines exported within the Cluster Transport
//
NTSTATUS CdpInitializeReceive( VOID ) { IF_CNDBG(CN_DEBUG_INIT){ CNPRINT(("[CDP] Initializing receive...\n")); }
CdpReceiveRequestPool = CnpCreateReceiveRequestPool( sizeof(CDP_RECEIVE_CONTEXT), CDP_RECEIVE_REQUEST_POOL_DEPTH );
if (CdpReceiveRequestPool == NULL) { return(STATUS_INSUFFICIENT_RESOURCES); }
IF_CNDBG(CN_DEBUG_INIT){ CNPRINT(("[CDP] Receive initialized.\n")); }
return(STATUS_SUCCESS);
} // CdpInitializeReceive
VOID CdpCleanupReceive( VOID ) { IF_CNDBG(CN_DEBUG_INIT){ CNPRINT(("[CDP] Cleaning up receive...\n")); }
if (CdpReceiveRequestPool != NULL) { CnpDeleteReceiveRequestPool(CdpReceiveRequestPool); CdpReceiveRequestPool = NULL; }
IF_CNDBG(CN_DEBUG_INIT){ CNPRINT(("[CDP] Receive cleanup complete.\n")); }
return;
} // CdpCleanupReceive
NTSTATUS CdpReceivePacketHandler( IN PVOID Network, IN CL_NODE_ID SourceNodeId, IN ULONG CnpReceiveFlags, IN ULONG TdiReceiveDatagramFlags, IN ULONG BytesIndicated, IN ULONG BytesAvailable, OUT PULONG BytesTaken, IN PVOID Tsdu, OUT PIRP * Irp ) { NTSTATUS status; CDP_HEADER UNALIGNED * header = Tsdu; PCX_ADDROBJ addrObj; ULONG bytesTaken = 0; PCNP_RECEIVE_REQUEST request; USHORT srcPort = 0; USHORT destPort = 0; ULONG consumed = 0;
CnAssert(KeGetCurrentIrql() == DISPATCH_LEVEL);
if (BytesIndicated >= sizeof(CDP_HEADER)) { destPort = header->DestinationPort; srcPort = header->SourcePort;
//
// Consume the CDP header
//
consumed = sizeof(CDP_HEADER);
//
// Verify that the remaining packet is consistent.
//
if (header->PayloadLength != (BytesAvailable - consumed)) { goto error_exit; }
BytesIndicated -= consumed; BytesAvailable -= consumed; *BytesTaken += consumed; Tsdu = (PUCHAR)Tsdu + consumed;
CnAcquireLockAtDpc(&CxAddrObjTableLock);
addrObj = CxFindAddressObject(destPort);
if (addrObj != NULL) {
CnReleaseLockFromDpc(&CxAddrObjTableLock);
if ( ( !(addrObj->Flags & CX_AO_FLAG_CHECKSTATE) || (CnpReceiveFlags & CNP_RECV_FLAG_NODE_STATE_CHECK_PASSED) ) && (addrObj->ReceiveDatagramHandler != NULL) ) { //
// Reference the address object so it can't go away during
// the indication.
//
CnReferenceFsContext(&(addrObj->FsContext));
if (BytesAvailable == BytesIndicated) {
CdpIndicateReceivePacket( addrObj, SourceNodeId, srcPort, TdiReceiveDatagramFlags, BytesAvailable, ((BytesAvailable > 0) ? Tsdu : NULL), (BOOLEAN)( CnpReceiveFlags & CNP_RECV_FLAG_SIGNATURE_VERIFIED ) );
//
// The addrObj lock was released.
//
*BytesTaken += BytesAvailable; *Irp = NULL;
CnVerifyCpuLockMask( 0, // Required
0xFFFFFFFF, // Forbidden
0 // Maximum
);
return(STATUS_SUCCESS); }
CnReleaseLockFromDpc(&(addrObj->Lock));
//
// This message cannot be a CNP multicast, and it
// cannot have been verified, because the CNP layer
// could not have verified an incomplete message.
//
CnAssert(!(CnpReceiveFlags & CNP_RECV_FLAG_MULTICAST)); CnAssert(!(CnpReceiveFlags & CNP_RECV_FLAG_SIGNATURE_VERIFIED));
//
// We need to fetch the rest of the packet before we
// can indicate it to the upper layer.
//
request = CnpAllocateReceiveRequest( CdpReceiveRequestPool, Network, BytesAvailable, CdpCompleteReceivePacket );
if (request != NULL) {
PCDP_RECEIVE_CONTEXT context; PCNP_NETWORK network = (PCNP_NETWORK)Network; ULONG refCount;
context = request->UpperProtocolContext;
context->SourceNodeId = SourceNodeId; context->SourcePort = header->SourcePort; context->TdiReceiveDatagramFlags = TdiReceiveDatagramFlags; context->TsduSize = BytesAvailable; context->AddrObj = addrObj; context->Network = Network;
//
// Take a reference on the network so that it
// doesn't disappear before the IRP completes.
//
CnAcquireLock(&(network->Lock), &(network->Irql)); refCount = CnpActiveReferenceNetwork(Network); CnReleaseLock(&(network->Lock), network->Irql);
if (refCount == 0) { // This Network is being closed down. We
// cannot retrieve or deliver the data. Drop
// the packet.
CnpFreeReceiveRequest(request); goto error_exit; }
*Irp = request->Irp;
CnTrace(CDP_RECV_DETAIL, CdpTraceCompleteReceive, "[CDP] Fetching dgram data, src: node %u port %u, " "dst: port %u, BI %u, BA %u, CNP Flags %x.", SourceNodeId, // LOGULONG
srcPort, // LOGUSHORT
destPort, // LOGUSHORT
BytesIndicated, // LOGULONG
BytesAvailable, // LOGULONG
CnpReceiveFlags // LOGXLONG
);
CnVerifyCpuLockMask( 0, // Required
0xFFFFFFFF, // Forbidden
0 // Maximum
);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
CnTrace( CDP_RECV_ERROR, CdpTraceDropReceiveNoIrp, "[CDP] Dropping dgram: failed to allocate " "receive request." );
//
// Out of resources. Drop the packet.
//
} else { //
// No receive handler or node state check failed.
//
CnReleaseLockFromDpc(&(addrObj->Lock));
CnTrace( CDP_RECV_ERROR, CdpTraceDropReceiveState, "[CDP] Dropping dgram: addr obj flags %x, " "CNP flags %x, dgram recv handler %p.", addrObj->Flags, CnpReceiveFlags, addrObj->ReceiveDatagramHandler ); } } else { CnReleaseLockFromDpc(&CxAddrObjTableLock);
CnTrace( CDP_RECV_ERROR, CdpTraceDropReceiveNoAO, "[CDP] Dropping dgram: no clusnet addr obj found " "for dest port %u.", destPort ); } }
error_exit:
//
// Something went wrong. Drop the packet by
// indicating that we consumed it.
//
*BytesTaken += BytesAvailable; *Irp = NULL;
CnTrace(CDP_RECV_ERROR, CdpTraceDropReceive, "[CDP] Dropped dgram, src: node %u port %u, dst: port %u, " "BI %u, BA %u, CNP flags %x.", SourceNodeId, // LOGULONG
srcPort, // LOGUSHORT
destPort, // LOGUSHORT
BytesIndicated, // LOGULONG
BytesAvailable, // LOGULONG
CnpReceiveFlags // LOGXLONG
);
CnVerifyCpuLockMask( 0, // Required
0xFFFFFFFF, // Forbidden
0 // Maximum
);
return(STATUS_SUCCESS);
} // CdpReceivePacketHandler
//
// Routines exported within the Cluster Network driver
//
NTSTATUS CxReceiveDatagram( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) { NTSTATUS status = STATUS_NOT_IMPLEMENTED;
CNPRINT(("[Clusnet] CxReceiveDatagram called!\n"));
Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
return(status);
} // CxReceiveDatagram
|