766 lines
15 KiB
C
766 lines
15 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
node.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the Appletalk Node management code.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jameel Hyder (jameelh@microsoft.com)
|
|||
|
Nikhil Kamkolkar (nikhilk@microsoft.com)
|
|||
|
|
|||
|
Revision History:
|
|||
|
19 Jun 1992 Initial Version
|
|||
|
|
|||
|
Notes: Tab stop: 4
|
|||
|
--*/
|
|||
|
|
|||
|
#include <atalk.h>
|
|||
|
#pragma hdrstop
|
|||
|
#define FILENUM NODE
|
|||
|
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGEINIT, AtalkInitNodeCreateOnPort)
|
|||
|
#pragma alloc_text(PAGEINIT, AtalkInitNodeAllocate)
|
|||
|
#pragma alloc_text(PAGEINIT, AtalkInitNodeGetPramAddr)
|
|||
|
#pragma alloc_text(PAGEINIT, AtalkInitNodeSavePramAddr)
|
|||
|
#endif
|
|||
|
|
|||
|
ATALK_ERROR
|
|||
|
AtalkInitNodeCreateOnPort(
|
|||
|
PPORT_DESCRIPTOR pPortDesc,
|
|||
|
BOOLEAN AllowStartupRange,
|
|||
|
BOOLEAN RouterNode,
|
|||
|
PATALK_NODEADDR NodeAddr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PATALK_NODE pNode;
|
|||
|
ATALK_ERROR error = ATALK_NO_ERROR;
|
|||
|
ATALK_NODEADDR desiredNode = { UNKNOWN_NETWORK, UNKNOWN_NODE};
|
|||
|
PWSTR NodeName;
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
if ((pPortDesc->pd_Flags & PD_FINDING_NODE) == 0)
|
|||
|
{
|
|||
|
pPortDesc->pd_Flags |= PD_FINDING_NODE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Return if we are already trying to find a node
|
|||
|
error = ATALK_NODE_FINDING;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// We should not be here if we have already allocated a router node and the user nodes
|
|||
|
ASSERT(!RouterNode || ((pPortDesc->pd_Flags & PD_ROUTER_NODE) == 0));
|
|||
|
ASSERT ((pPortDesc->pd_Flags & (PD_ROUTER_NODE | PD_USER_NODE_1 | PD_USER_NODE_2))
|
|||
|
!= (PD_ROUTER_NODE | PD_USER_NODE_1 | PD_USER_NODE_2));
|
|||
|
|
|||
|
// On non-extended ports we only allow one node! The theory being that some
|
|||
|
// LocalTalk cards are too smart for their own good and have a concept of
|
|||
|
// their "source node number" and thus only support one node, also on
|
|||
|
// non-extended ports, nodes are scarse.
|
|||
|
if (!EXT_NET(pPortDesc))
|
|||
|
{
|
|||
|
// For a localtalk node we do things differently.
|
|||
|
// During initialization time, we would have obtained
|
|||
|
// the address from the mac, that will be the node
|
|||
|
// address.
|
|||
|
|
|||
|
ASSERT(pPortDesc->pd_Flags & PD_BOUND);
|
|||
|
ASSERT(pPortDesc->pd_AlapNode != 0);
|
|||
|
|
|||
|
// This needs to be initialized to UNKNOWN_NETWORK or obtained
|
|||
|
// from the net during initialization.
|
|||
|
ASSERT(pPortDesc->pd_NetworkRange.anr_FirstNetwork == UNKNOWN_NETWORK);
|
|||
|
|
|||
|
if (!ATALK_SUCCESS((error = AtalkInitNodeAllocate(pPortDesc, &pNode))))
|
|||
|
{
|
|||
|
LOG_ERRORONPORT(pPortDesc,
|
|||
|
EVENT_ATALK_INIT_COULDNOTGETNODE,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// Use the allocated structure to set the info.
|
|||
|
// Thread this into the port structure.
|
|||
|
pPortDesc->pd_LtNetwork =
|
|||
|
pNode->an_NodeAddr.atn_Network =
|
|||
|
pPortDesc->pd_NetworkRange.anr_FirstNetwork;
|
|||
|
pNode->an_NodeAddr.atn_Node = (BYTE)pPortDesc->pd_AlapNode;
|
|||
|
|
|||
|
// Reference the port for this node.
|
|||
|
AtalkPortReferenceByPtrNonInterlock(pPortDesc, &error);
|
|||
|
if (!ATALK_SUCCESS(error))
|
|||
|
{
|
|||
|
AtalkFreeMemory(pNode);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// Now put it in the port descriptor
|
|||
|
pNode->an_Next = pPortDesc->pd_Nodes;
|
|||
|
pPortDesc->pd_Nodes = pNode;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Use PRAM values if we have them
|
|||
|
if (RouterNode)
|
|||
|
{
|
|||
|
NodeName = ROUTER_NODE_VALUE;
|
|||
|
if (pPortDesc->pd_RoutersPramNode.atn_Network != UNKNOWN_NETWORK)
|
|||
|
{
|
|||
|
desiredNode = pPortDesc->pd_RoutersPramNode;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if ((pPortDesc->pd_Flags & PD_USER_NODE_1) == 0)
|
|||
|
{
|
|||
|
NodeName = USER_NODE1_VALUE;
|
|||
|
if (pPortDesc->pd_UsersPramNode1.atn_Network != UNKNOWN_NETWORK)
|
|||
|
{
|
|||
|
// If we are not a router node, and the first user node
|
|||
|
// has not been allocated...
|
|||
|
desiredNode = pPortDesc->pd_UsersPramNode1;
|
|||
|
}
|
|||
|
}
|
|||
|
else if ((pPortDesc->pd_Flags & PD_USER_NODE_2) == 0)
|
|||
|
{
|
|||
|
NodeName = USER_NODE2_VALUE;
|
|||
|
if (pPortDesc->pd_UsersPramNode2.atn_Network != UNKNOWN_NETWORK)
|
|||
|
{
|
|||
|
// If we are not a router node, and the second user node
|
|||
|
// has not been allocated...
|
|||
|
desiredNode = pPortDesc->pd_UsersPramNode2;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Flags should be set so future get node requests return failure
|
|||
|
// until we are done with this attempt. We need to call
|
|||
|
// the aarp routines without the lock held - they will
|
|||
|
// block.
|
|||
|
|
|||
|
ASSERT(pPortDesc->pd_Flags & PD_FINDING_NODE);
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|||
|
|
|||
|
// If this routine succeeds in finding the node, it
|
|||
|
// will chain in the atalkNode into the port. It also
|
|||
|
// returns with the proper flags set/reset in the
|
|||
|
// pPortDesc structure. It will also have referenced the port
|
|||
|
// and inserted the node into the port's node list.
|
|||
|
error = AtalkInitAarpForNodeOnPort(pPortDesc,
|
|||
|
AllowStartupRange,
|
|||
|
desiredNode,
|
|||
|
&pNode);
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
|||
|
|
|||
|
if (!ATALK_SUCCESS(error))
|
|||
|
{
|
|||
|
// AARP for node failed.
|
|||
|
LOG_ERRORONPORT(pPortDesc,
|
|||
|
EVENT_ATALK_INIT_COULDNOTGETNODE,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} while (FALSE);
|
|||
|
|
|||
|
// Ok, done finding node. No need for a crit section.
|
|||
|
pPortDesc->pd_Flags &= ~PD_FINDING_NODE;
|
|||
|
|
|||
|
if (ATALK_SUCCESS(error))
|
|||
|
{
|
|||
|
// If router node, remember it in port descriptor
|
|||
|
// Do this before setting up the rtmp/nbp listeners.
|
|||
|
// In anycase, clients must check this value for null,
|
|||
|
// not guaranteed as zip socket could already be open.
|
|||
|
if (RouterNode)
|
|||
|
pPortDesc->pd_RouterNode = pNode;
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|||
|
|
|||
|
// Setup the RTMP, NBP and EP listeners on this node.
|
|||
|
// These will be the non-router versions. StartRouting
|
|||
|
// calls will then switch them to be the router versions
|
|||
|
// at the appropriate time.
|
|||
|
|
|||
|
error = AtalkInitDdpOpenStaticSockets(pPortDesc, pNode);
|
|||
|
|
|||
|
if (ATALK_SUCCESS(error))
|
|||
|
{
|
|||
|
if (EXT_NET(pPortDesc))
|
|||
|
{
|
|||
|
// We always save this address.
|
|||
|
AtalkInitNodeSavePramAddr(pPortDesc,
|
|||
|
NodeName,
|
|||
|
&pNode->an_NodeAddr);
|
|||
|
}
|
|||
|
|
|||
|
// Return the address of the node opened.
|
|||
|
if (NodeAddr != NULL)
|
|||
|
*NodeAddr = pNode->an_NodeAddr;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Error opening sockets. Release node, return failure
|
|||
|
LOG_ERRORONPORT(pPortDesc,
|
|||
|
EVENT_ATALK_NODE_OPENSOCKETS,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0);
|
|||
|
AtalkNodeReleaseOnPort(pPortDesc, pNode);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|||
|
}
|
|||
|
|
|||
|
if (!ATALK_SUCCESS(error))
|
|||
|
{
|
|||
|
DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_INFO,
|
|||
|
("Creation node on port %lx failed! %lx\n",
|
|||
|
pPortDesc, error));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_INFO,
|
|||
|
("Creation node on port %lx with addr %lx.%lx and p%lx\n",
|
|||
|
pPortDesc, pNode->an_NodeAddr.atn_Network,
|
|||
|
pNode->an_NodeAddr.atn_Node, pNode));
|
|||
|
}
|
|||
|
|
|||
|
return(error);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
ATALK_ERROR
|
|||
|
AtalkNodeReleaseOnPort(
|
|||
|
PPORT_DESCRIPTOR pPortDesc,
|
|||
|
PATALK_NODE pNode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDDP_ADDROBJ pDdpAddr, pNextAddr;
|
|||
|
ATALK_ERROR error;
|
|||
|
KIRQL OldIrql;
|
|||
|
SHORT i;
|
|||
|
|
|||
|
DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_WARN,
|
|||
|
("AtalkNodeReleaseOnPort: Releasing node %lx on port %lx!\n", pNode, pPortDesc));
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pNode->an_Lock, &OldIrql);
|
|||
|
|
|||
|
if ((pNode->an_NodeAddr.atn_Network == AtalkUserNode1.atn_Network) &&
|
|||
|
(pNode->an_NodeAddr.atn_Node == AtalkUserNode1.atn_Node))
|
|||
|
{
|
|||
|
pPortDesc->pd_Flags &= ~PD_USER_NODE_1;
|
|||
|
AtalkUserNode1.atn_Network = 0;
|
|||
|
AtalkUserNode1.atn_Node = 0;
|
|||
|
}
|
|||
|
else if ((pNode->an_NodeAddr.atn_Network == AtalkUserNode2.atn_Network) &&
|
|||
|
(pNode->an_NodeAddr.atn_Node == AtalkUserNode2.atn_Node))
|
|||
|
{
|
|||
|
pPortDesc->pd_Flags &= ~PD_USER_NODE_2;
|
|||
|
AtalkUserNode2.atn_Network = 0;
|
|||
|
AtalkUserNode2.atn_Node = 0;
|
|||
|
}
|
|||
|
|
|||
|
if ((pNode->an_Flags & AN_CLOSING) == 0)
|
|||
|
{
|
|||
|
// Set the closing flag.
|
|||
|
pNode->an_Flags |= AN_CLOSING;
|
|||
|
|
|||
|
// First close all the sockets on the node
|
|||
|
for (i = 0; i < NODE_DDPAO_HASH_SIZE; i++)
|
|||
|
{
|
|||
|
pNextAddr = NULL;
|
|||
|
AtalkDdpReferenceNextNc(pNode->an_DdpAoHash[i],
|
|||
|
&pDdpAddr,
|
|||
|
&error);
|
|||
|
|
|||
|
if (!ATALK_SUCCESS(error))
|
|||
|
{
|
|||
|
// Check the other hash table entries. No non-closing
|
|||
|
// sockets on this list.
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
while (TRUE)
|
|||
|
{
|
|||
|
// Get the next non-closing node using our referenced node before
|
|||
|
// closing it. Note we use pDdpAddr->...Flink.
|
|||
|
AtalkDdpReferenceNextNc(pDdpAddr->ddpao_Next,
|
|||
|
&pNextAddr,
|
|||
|
&error);
|
|||
|
|
|||
|
// Close the referenced ddp addr after releasing the node lock.
|
|||
|
RELEASE_SPIN_LOCK(&pNode->an_Lock, OldIrql);
|
|||
|
|
|||
|
if (pDdpAddr->ddpao_Flags & DDPAO_SOCK_INTERNAL)
|
|||
|
{
|
|||
|
AtalkDdpCloseAddress(pDdpAddr, NULL, NULL);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
AtalkDdpPnPSuspendAddress(pDdpAddr);
|
|||
|
}
|
|||
|
|
|||
|
// Dereference the address.
|
|||
|
AtalkDdpDereference(pDdpAddr);
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pNode->an_Lock, &OldIrql);
|
|||
|
|
|||
|
if (pNextAddr != NULL)
|
|||
|
pDdpAddr = pNextAddr;
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK(&pNode->an_Lock, OldIrql);
|
|||
|
|
|||
|
// Remove the creation reference for this node.
|
|||
|
AtalkNodeDereference(pNode);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// We are already closing.
|
|||
|
RELEASE_SPIN_LOCK(&pNode->an_Lock, OldIrql);
|
|||
|
}
|
|||
|
|
|||
|
return(ATALK_NO_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AtalkNodeExistsOnPort(
|
|||
|
PPORT_DESCRIPTOR pPortDesc,
|
|||
|
PATALK_NODEADDR pNodeAddr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PATALK_NODE pCheckNode;
|
|||
|
BOOLEAN exists = FALSE;
|
|||
|
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|||
|
|
|||
|
for (pCheckNode = pPortDesc->pd_Nodes;
|
|||
|
pCheckNode != NULL;
|
|||
|
pCheckNode = pCheckNode->an_Next)
|
|||
|
{
|
|||
|
if (ATALK_NODES_EQUAL(&pCheckNode->an_NodeAddr, pNodeAddr))
|
|||
|
{
|
|||
|
exists = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|||
|
|
|||
|
return(exists);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AtalkInitNodeSavePramAddr(
|
|||
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|||
|
IN PWSTR RegValue,
|
|||
|
OUT PATALK_NODEADDR pNode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UNICODE_STRING valueName;
|
|||
|
ULONG bytesWritten;
|
|||
|
ULONG ValueToSave;
|
|||
|
|
|||
|
// Save the node value as xxxx00yy where xxxx is network, yy is node
|
|||
|
ValueToSave = (pNode->atn_Network << 16) + pNode->atn_Node;
|
|||
|
|
|||
|
RtlInitUnicodeString (&valueName, RegValue);
|
|||
|
|
|||
|
ZwSetValueKey(pPortDesc->pd_AdapterInfoHandle,
|
|||
|
&valueName,
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
&ValueToSave,
|
|||
|
sizeof(ULONG));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AtalkInitNodeGetPramAddr(
|
|||
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|||
|
IN PWSTR RegValue,
|
|||
|
OUT PATALK_NODEADDR pNode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
UNICODE_STRING valueName;
|
|||
|
ULONG bytesWritten;
|
|||
|
ULONG ValueRead;
|
|||
|
BYTE buffer[sizeof(KEY_VALUE_FULL_INFORMATION) + 32];
|
|||
|
PKEY_VALUE_FULL_INFORMATION nodeValue = (PKEY_VALUE_FULL_INFORMATION)buffer;
|
|||
|
|
|||
|
RtlInitUnicodeString (&valueName, RegValue);
|
|||
|
|
|||
|
Status = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
|
|||
|
&valueName,
|
|||
|
KeyValueFullInformation,
|
|||
|
buffer,
|
|||
|
sizeof(buffer),
|
|||
|
&bytesWritten);
|
|||
|
if (NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
ValueRead = *(PULONG)(buffer + nodeValue->DataOffset);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ValueRead = 0;
|
|||
|
ASSERT (UNKNOWN_NETWORK == 0);
|
|||
|
ASSERT (UNKNOWN_NODE == 0);
|
|||
|
}
|
|||
|
pNode->atn_Node = (BYTE)(ValueRead & 0xFF);
|
|||
|
pNode->atn_Network = (USHORT)(ValueRead >> 16);
|
|||
|
if ((pNode->atn_Network == UNKNOWN_NETWORK) ||
|
|||
|
(pNode->atn_Node == UNKNOWN_NODE))
|
|||
|
{
|
|||
|
pNode->atn_Node = UNKNOWN_NODE;
|
|||
|
pNode->atn_Network = UNKNOWN_NETWORK;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AtalkZapPramValue(
|
|||
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|||
|
IN PWSTR RegValue
|
|||
|
)
|
|||
|
{
|
|||
|
UNICODE_STRING valueName;
|
|||
|
ULONG bytesWritten;
|
|||
|
ULONG ValueToSave;
|
|||
|
|
|||
|
// Write 0 to the value to zap it for now.
|
|||
|
ValueToSave = 0;
|
|||
|
|
|||
|
RtlInitUnicodeString (&valueName, RegValue);
|
|||
|
|
|||
|
ZwSetValueKey(pPortDesc->pd_AdapterInfoHandle,
|
|||
|
&valueName,
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
&ValueToSave,
|
|||
|
sizeof(ULONG));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ATALK_ERROR
|
|||
|
AtalkInitNodeAllocate(
|
|||
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|||
|
OUT PATALK_NODE *ppNode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PATALK_NODE pNode;
|
|||
|
|
|||
|
// Allocate a new active Node structure
|
|||
|
if ((pNode = (PATALK_NODE)AtalkAllocZeroedMemory(sizeof(ATALK_NODE))) == NULL)
|
|||
|
{
|
|||
|
return(ATALK_RESR_MEM);
|
|||
|
}
|
|||
|
|
|||
|
// Initialize some elements of the structure. Remaining stuff
|
|||
|
// done when the node is actually being inserted into the port
|
|||
|
// hash table.
|
|||
|
#if DBG
|
|||
|
pNode->an_Signature = AN_SIGNATURE;
|
|||
|
#endif
|
|||
|
|
|||
|
// Initialize the Nbp Id & Enumerator
|
|||
|
pNode->an_NextNbpId = 0;
|
|||
|
pNode->an_NextNbpEnum = 0;
|
|||
|
pNode->an_NextDynSkt = FIRST_DYNAMIC_SOCKET;
|
|||
|
INITIALIZE_SPIN_LOCK(&pNode->an_Lock);
|
|||
|
pNode->an_Port = pPortDesc; // Port on which node exists
|
|||
|
pNode->an_RefCount = 1; // Reference for creation.
|
|||
|
|
|||
|
// Return pointer to allocated node
|
|||
|
*ppNode = pNode;
|
|||
|
|
|||
|
return(ATALK_NO_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AtalkNodeRefByAddr(
|
|||
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|||
|
IN PATALK_NODEADDR NodeAddr,
|
|||
|
OUT PATALK_NODE * ppNode,
|
|||
|
OUT PATALK_ERROR pErr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PATALK_NODE pNode;
|
|||
|
KIRQL OldIrql;
|
|||
|
BOOLEAN foundNode = FALSE;
|
|||
|
|
|||
|
*pErr = ATALK_NODE_NONEXISTENT;
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
|||
|
for (pNode = pPortDesc->pd_Nodes; pNode != NULL; pNode = pNode->an_Next)
|
|||
|
{
|
|||
|
ASSERT(VALID_ATALK_NODE(pNode));
|
|||
|
|
|||
|
// Note: On non-extended ports, there should be only one pNode.
|
|||
|
if (((NodeAddr->atn_Network == CABLEWIDE_BROADCAST_NETWORK) ||
|
|||
|
(pNode->an_NodeAddr.atn_Network == NodeAddr->atn_Network) ||
|
|||
|
(!EXT_NET(pPortDesc) && (pNode->an_NodeAddr.atn_Network == UNKNOWN_NETWORK)))
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
((NodeAddr->atn_Node == ATALK_BROADCAST_NODE) ||
|
|||
|
(pNode->an_NodeAddr.atn_Node == NodeAddr->atn_Node)))
|
|||
|
{
|
|||
|
DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_INFO,
|
|||
|
("AtalkNodeRefByAddr: Found: %lx.%lx for Lookup: %lx.%lx\n",
|
|||
|
pNode->an_NodeAddr.atn_Network, pNode->an_NodeAddr.atn_Node,
|
|||
|
NodeAddr->atn_Network, NodeAddr->atn_Node));
|
|||
|
|
|||
|
foundNode = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (foundNode)
|
|||
|
{
|
|||
|
AtalkNodeRefByPtr(pNode, pErr);
|
|||
|
|
|||
|
// Return a pointer to the referenced node.
|
|||
|
if (ATALK_SUCCESS(*pErr))
|
|||
|
{
|
|||
|
ASSERT(ppNode != NULL);
|
|||
|
ASSERT(pNode != NULL);
|
|||
|
|
|||
|
*ppNode = pNode;
|
|||
|
}
|
|||
|
}
|
|||
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AtalkNodeRefNextNc(
|
|||
|
IN PATALK_NODE pNode,
|
|||
|
IN PATALK_NODE * ppNode,
|
|||
|
OUT PATALK_ERROR pErr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
MUST BE CALLED WITH THE PORTLOCK HELD!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
*pErr = ATALK_FAILURE;
|
|||
|
*ppNode = NULL;
|
|||
|
for (; pNode != NULL; pNode = pNode->an_Next)
|
|||
|
{
|
|||
|
ASSERT(VALID_ATALK_NODE(pNode));
|
|||
|
|
|||
|
AtalkNodeRefByPtr(pNode, pErr);
|
|||
|
if (ATALK_SUCCESS(*pErr))
|
|||
|
{
|
|||
|
// Ok, this node is referenced!
|
|||
|
*ppNode = pNode;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AtalkNodeDeref(
|
|||
|
IN OUT PATALK_NODE pNode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PPORT_DESCRIPTOR pPortDesc = pNode->an_Port;
|
|||
|
KIRQL OldIrql;
|
|||
|
BOOLEAN done = FALSE;
|
|||
|
|
|||
|
ASSERT(VALID_ATALK_NODE(pNode));
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pNode->an_Lock, &OldIrql);
|
|||
|
|
|||
|
ASSERT(pNode->an_RefCount > 0);
|
|||
|
if (--pNode->an_RefCount == 0)
|
|||
|
{
|
|||
|
done = TRUE;
|
|||
|
}
|
|||
|
RELEASE_SPIN_LOCK(&pNode->an_Lock, OldIrql);
|
|||
|
|
|||
|
if (done)
|
|||
|
{
|
|||
|
PATALK_NODE *ppNode;
|
|||
|
|
|||
|
ASSERT((pNode->an_Flags & AN_CLOSING) != 0);
|
|||
|
|
|||
|
DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_WARN,
|
|||
|
("AtalkNodeDeref: Freeing node %lx\n", pNode));
|
|||
|
|
|||
|
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
|||
|
// Remove this guy from the port linkage
|
|||
|
for (ppNode = &pNode->an_Port->pd_Nodes;
|
|||
|
*ppNode != NULL;
|
|||
|
ppNode = &((*ppNode)->an_Next))
|
|||
|
{
|
|||
|
if (*ppNode == pNode)
|
|||
|
{
|
|||
|
*ppNode = pNode->an_Next;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|||
|
|
|||
|
// Dereference the port for this node
|
|||
|
AtalkPortDereference(pPortDesc);
|
|||
|
|
|||
|
// Free the node structure
|
|||
|
AtalkFreeMemory(pNode);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|