windows-nt/Source/XPSP1/NT/base/cluster/clusnet/xport/cxaddr.c
2020-09-26 16:20:57 +08:00

430 lines
11 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
cxaddr.c
Abstract:
TDI Address Object management code.
Author:
Mike Massa (mikemas) February 20, 1997
Revision History:
Who When What
-------- -------- ----------------------------------------------
mikemas 02-20-97 created
Notes:
--*/
#include "precomp.h"
#pragma hdrstop
#include "cxaddr.tmh"
#define CX_WILDCARD_PORT 0 // 0 means assign a port.
#define CX_MIN_USER_PORT 1025 // Minimum value for a wildcard port
#define CX_MAX_USER_PORT 5000 // Maximim value for a user port.
#define CX_NUM_USER_PORTS (CX_MAX_USER_PORT - CX_MIN_USER_PORT + 1)
//
// Address Object Data
//
USHORT CxNextUserPort = CX_MIN_USER_PORT;
LIST_ENTRY CxAddrObjTable[CX_ADDROBJ_TABLE_SIZE];
#if DBG
CN_LOCK CxAddrObjTableLock = {0,0};
#else // DBG
CN_LOCK CxAddrObjTableLock = 0;
#endif // DBG
NTSTATUS
CxParseTransportAddress(
IN TRANSPORT_ADDRESS UNALIGNED *AddrList,
IN ULONG AddressListLength,
OUT CL_NODE_ID * Node,
OUT PUSHORT Port
)
{
LONG i;
PTA_ADDRESS currentAddr;
TDI_ADDRESS_CLUSTER UNALIGNED * validAddr;
if (AddressListLength >= sizeof(TA_CLUSTER_ADDRESS)) {
//
// Find an address we can use.
//
currentAddr = (PTA_ADDRESS) AddrList->Address;
for (i = 0; i < AddrList->TAAddressCount; i++) {
if ( (currentAddr->AddressType == TDI_ADDRESS_TYPE_CLUSTER) &&
(currentAddr->AddressLength >= TDI_ADDRESS_LENGTH_CLUSTER)
)
{
validAddr = (TDI_ADDRESS_CLUSTER UNALIGNED *)
currentAddr->Address;
*Node = validAddr->Node;
*Port = validAddr->Port;
return(STATUS_SUCCESS);
}
else {
if ( AddressListLength >=
(currentAddr->AddressLength + sizeof(TA_CLUSTER_ADDRESS))
)
{
AddressListLength -= currentAddr->AddressLength;
currentAddr = (PTA_ADDRESS)
( currentAddr->Address +
currentAddr->AddressLength
);
}
else {
break;
}
}
}
}
return(STATUS_INVALID_ADDRESS_COMPONENT);
} // CxParseTransportAddress
PCX_ADDROBJ
CxFindAddressObject(
IN USHORT Port
)
/*++
Notes:
Called with AO Table lock held.
Returns with address object lock held.
--*/
{
PLIST_ENTRY entry;
ULONG hashBucket = CX_ADDROBJ_TABLE_HASH(Port);
PCX_ADDROBJ addrObj;
for ( entry = CxAddrObjTable[hashBucket].Flink;
entry != &(CxAddrObjTable[hashBucket]);
entry = entry->Flink
)
{
addrObj = CONTAINING_RECORD(
entry,
CX_ADDROBJ,
AOTableLinkage
);
if (addrObj->LocalPort == Port) {
CnAcquireLockAtDpc(&(addrObj->Lock));
addrObj->Irql = DISPATCH_LEVEL;
return(addrObj);
}
}
return(NULL);
} // CxFindAddressObject
NTSTATUS
CxOpenAddress(
OUT PCN_FSCONTEXT * CnFsContext,
IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
IN ULONG TransportAddressLength
)
{
PCX_ADDROBJ addrObj, oldAddrObj;
NTSTATUS status;
CL_NODE_ID nodeId;
USHORT port;
CN_IRQL tableIrql;
ULONG i;
ULONG hashBucket;
status = CxParseTransportAddress(
TransportAddress,
TransportAddressLength,
&nodeId,
&port
);
if (status != STATUS_SUCCESS) {
IF_CNDBG(CN_DEBUG_ADDROBJ) {
CNPRINT((
"[Clusnet] Open address - failed to parse address, status %lx\n",
status
));
}
return(status);
}
addrObj = CnAllocatePool(sizeof(CX_ADDROBJ));
if (addrObj == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
RtlZeroMemory(addrObj, sizeof(CX_ADDROBJ));
CN_INIT_SIGNATURE(&(addrObj->FsContext), CX_ADDROBJ_SIG);
CnInitializeLock(&(addrObj->Lock), CX_ADDROBJ_LOCK);
addrObj->Flags |= CX_AO_FLAG_CHECKSTATE;
CnAcquireLock(&CxAddrObjTableLock, &tableIrql);
// If no port is specified we have to assign one. If there is a
// port specified, we need to make sure that the port isn't
// already open. If the input address is a wildcard, we need to
// assign one ourselves.
if (port == CX_WILDCARD_PORT) {
port = CxNextUserPort;
for (i = 0; i < CX_NUM_USER_PORTS; i++, port++) {
if (port > CX_MAX_USER_PORT) {
port = CX_MIN_USER_PORT;
}
oldAddrObj = CxFindAddressObject(port);
if (oldAddrObj == NULL) {
IF_CNDBG(CN_DEBUG_ADDROBJ) {
CNPRINT(("[Clusnet] Assigning port %u\n", port));
}
break; // Found an unused port.
}
CnReleaseLockFromDpc(&(oldAddrObj->Lock));
}
if (i == CX_NUM_USER_PORTS) { // Couldn't find a free port.
IF_CNDBG(CN_DEBUG_ADDROBJ) {
CNPRINT((
"[Clusnet] No free wildcard ports.\n"
));
}
CnReleaseLock(&CxAddrObjTableLock, tableIrql);
CnFreePool(addrObj);
return (STATUS_TOO_MANY_ADDRESSES);
}
CxNextUserPort = port + 1;
} else { // Address was specificed
oldAddrObj = CxFindAddressObject(port);
if (oldAddrObj != NULL) {
IF_CNDBG(CN_DEBUG_ADDROBJ) {
CNPRINT((
"[Clusnet] Port %u is already in use.\n",
port
));
}
CnReleaseLockFromDpc(&(oldAddrObj->Lock));
CnReleaseLock(&CxAddrObjTableLock, tableIrql);
CnFreePool(addrObj);
return (STATUS_ADDRESS_ALREADY_EXISTS);
}
}
addrObj->LocalPort = port;
hashBucket = CX_ADDROBJ_TABLE_HASH(port);
InsertHeadList(
&(CxAddrObjTable[hashBucket]),
&(addrObj->AOTableLinkage)
);
*CnFsContext = (PCN_FSCONTEXT) addrObj;
IF_CNDBG(CN_DEBUG_ADDROBJ) {
CNPRINT((
"[Clusnet] Opened address object %p for port %u\n",
addrObj,
port
));
}
CnTrace(
CDP_ADDR_DETAIL, CdpTraceOpenAO,
"[Clusnet] Opened address object %p for port %u.",
addrObj,
port
);
CnReleaseLock(&CxAddrObjTableLock, tableIrql);
return(STATUS_SUCCESS);
} // CxOpenAddress
NTSTATUS
CxCloseAddress(
IN PCN_FSCONTEXT CnFsContext
)
{
PCX_ADDROBJ addrObj = (PCX_ADDROBJ) CnFsContext;
CN_IRQL tableIrql;
IF_CNDBG(CN_DEBUG_ADDROBJ) {
CNPRINT((
"[Clusnet] Closed address object %p for port %u\n",
addrObj,
addrObj->LocalPort
));
}
CnTrace(
CDP_ADDR_DETAIL, CdpTraceCloseAO,
"[Clusnet] Closed address object %p for port %u.",
addrObj,
addrObj->LocalPort
);
CnAcquireLock(&CxAddrObjTableLock, &tableIrql);
CnAcquireLockAtDpc(&(addrObj->Lock));
RemoveEntryList(&(addrObj->AOTableLinkage));
CnReleaseLockFromDpc(&(addrObj->Lock));
CnReleaseLock(&CxAddrObjTableLock, tableIrql);
//
// The address object memory will be freed by the common code.
//
return(STATUS_SUCCESS);
} // CxCloseAddress
NTSTATUS
CxSetEventHandler(
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
{
NTSTATUS status = STATUS_SUCCESS;
PTDI_REQUEST_KERNEL_SET_EVENT request;
PCX_ADDROBJ addrObj;
CN_IRQL irql;
//
// Since this ioctl registers a callback function pointer, ensure
// that it was issued by a kernel-mode component.
//
if (Irp->RequestorMode != KernelMode) {
return(STATUS_ACCESS_DENIED);
}
addrObj = (PCX_ADDROBJ) IrpSp->FileObject->FsContext;
request = (PTDI_REQUEST_KERNEL_SET_EVENT) &(IrpSp->Parameters);
IF_CNDBG(CN_DEBUG_ADDROBJ) {
CNPRINT((
"[Clusnet] TdiSetEvent type %u handler %p context %p\n",
request->EventType,
request->EventHandler,
request->EventContext
));
}
CnAcquireLock(&(addrObj->Lock), &irql);
switch (request->EventType) {
case TDI_EVENT_ERROR:
addrObj->ErrorHandler = request->EventHandler;
addrObj->ErrorContext = request->EventContext;
break;
case TDI_EVENT_RECEIVE_DATAGRAM:
addrObj->ReceiveDatagramHandler = request->EventHandler;
addrObj->ReceiveDatagramContext = request->EventContext;
break;
case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
addrObj->ChainedReceiveDatagramHandler = request->EventHandler;
addrObj->ChainedReceiveDatagramContext = request->EventContext;
break;
default:
status = STATUS_INVALID_PARAMETER;
break;
}
CnReleaseLock(&(addrObj->Lock), irql);
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
return(status);
} // CxSetEventHandler
VOID
CxBuildTdiAddress(
PVOID Buffer,
CL_NODE_ID Node,
USHORT Port,
BOOLEAN Verified
)
/*++
Routine Description:
Called when we need to build a TDI address structure. We fill in
the specifed buffer with the correct information in the correct
format.
Arguments:
Buffer - Buffer to be filled in as TDI address structure.
Node - Node ID to fill in.
Port - Port to be filled in.
Verified - During a receive, whether clusnet verified the
signature and data
Return Value:
Nothing
--*/
{
PTRANSPORT_ADDRESS xportAddr;
PTA_ADDRESS taAddr;
xportAddr = (PTRANSPORT_ADDRESS) Buffer;
xportAddr->TAAddressCount = 1;
taAddr = xportAddr->Address;
taAddr->AddressType = TDI_ADDRESS_TYPE_CLUSTER;
taAddr->AddressLength = sizeof(TDI_ADDRESS_CLUSTER);
((PTDI_ADDRESS_CLUSTER) taAddr->Address)->Port = Port;
((PTDI_ADDRESS_CLUSTER) taAddr->Address)->Node = Node;
((PTDI_ADDRESS_CLUSTER) taAddr->Address)->ReservedMBZ =
((Verified) ? 1 : 0);
}