mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
568 lines
12 KiB
568 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
node.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the node management code.
|
|
|
|
Author:
|
|
|
|
Garth Conboy Initial Coding
|
|
Nikhil Kamkolkar Rewritten for microsoft coding style. mpized
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "atalk.h"
|
|
|
|
LOCAL
|
|
BOOLEAN
|
|
OpenStaticSockets(int port, EXTENDED_NODENUMBER node);
|
|
|
|
LOCAL
|
|
PACTIVE_NODE
|
|
AllocateActiveNode(VOID);
|
|
|
|
|
|
|
|
APPLETALK_ERROR
|
|
GetNodeOnPort(
|
|
int Port,
|
|
BOOLEAN AllowStartupRange,
|
|
BOOLEAN ServerNode,
|
|
BOOLEAN RoutersNode,
|
|
PEXTENDED_NODENUMBER Node
|
|
)
|
|
{
|
|
APPLETALK_ERROR error = ATnoError;
|
|
int nodeNumber;
|
|
PACTIVE_NODE activeNode;
|
|
EXTENDED_NODENUMBER newNode;
|
|
EXTENDED_NODENUMBER desiredNode = { UNKNOWN_NETWORKNUMBER,
|
|
UNKNOWN_NODENUMBER};
|
|
|
|
// If the "default port" is requested, demystify it.
|
|
if (Port == DEFAULT_PORT) {
|
|
if ((Port = FindDefaultPort()) < 0) {
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
}
|
|
|
|
if (!AtalkVerifyStack(__LINE__ | __NODE__)) {
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
|
|
if (!AtalkVerifyPortDescriptor(GET_PORTDESCRIPTOR(Port),__LINE__ | __NODE__)) {
|
|
AtalkDereferenceStack((__LINE__ | __NODE__));
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
|
|
|
|
do {
|
|
|
|
|
|
// If we are an extended network port (not halfport or localtalk...)
|
|
if (!(GET_PORTDESCRIPTOR(Port)->PortType == NONAPPLETALK_HALFPORT) &&
|
|
!(GET_PORTDESCRIPTOR(Port)->PortType == LOCALTALK_NETWORK)) {
|
|
|
|
// Don't allow too many nodes per port!
|
|
if (ElementsOnList(GET_PORTDESCRIPTOR(Port)->ActiveNodes) >
|
|
MAXIMUM_NODESPERPORT) {
|
|
error = ATnoMoreNodes;
|
|
break;
|
|
}
|
|
|
|
// Pick a desired node, if we have a PRAM value.
|
|
if ((RoutersNode) &&
|
|
(GET_PORTDESCRIPTOR(Port)->RoutersPRamStartupNode.NetworkNumber !=
|
|
UNKNOWN_NETWORKNUMBER)) {
|
|
desiredNode = GET_PORTDESCRIPTOR(Port)->RoutersPRamStartupNode;
|
|
} else if (!(RoutersNode) &&
|
|
!(GET_PORTDESCRIPTOR(Port)->Flags & PD_FIRSTNODEALLOC) &&
|
|
(GET_PORTDESCRIPTOR(Port)->UsersPRamStartupNode.NetworkNumber
|
|
!= UNKNOWN_NETWORKNUMBER)) {
|
|
desiredNode = GET_PORTDESCRIPTOR(Port)->UsersPRamStartupNode;
|
|
}
|
|
|
|
// Okay, let AARP have a crack at finding a node!
|
|
if (!AarpForNodeOnPort(
|
|
Port,
|
|
AllowStartupRange,
|
|
ServerNode,
|
|
desiredNode,
|
|
&newNode)) {
|
|
error = ATnoMoreNodes;
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// 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 conecpt of
|
|
// their "source node number" and thus only support one node, also on
|
|
// non-extended Ports, nodes are scarse.
|
|
//
|
|
|
|
if ((activeNode = AllocateActiveNode()) == NULL) {
|
|
error = AToutOfMemory;
|
|
break;
|
|
}
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
if ((!(GET_PORTDESCRIPTOR(Port)->ExtendedNetwork) &&
|
|
(GET_PORTDESCRIPTOR(Port)->ActiveNodes == NULL))
|
|
|
|
||
|
|
|
|
// Only one node would ever be usefull on half Ports.
|
|
((GET_PORTDESCRIPTOR(Port)->PortType == NONAPPLETALK_HALFPORT) &&
|
|
(GET_PORTDESCRIPTOR(Port)->ActiveNodes == NULL))) {
|
|
|
|
//
|
|
// Good, no nodes on these currently, thread in our allocated node
|
|
// that should prevent other request from passing above test
|
|
//
|
|
|
|
activeNode->Next = GET_PORTDESCRIPTOR(Port)->ActiveNodes;
|
|
GET_PORTDESCRIPTOR(Port)->ActiveNodes = activeNode;
|
|
|
|
// One reference for creation, the other is until we are
|
|
// done initializing the node
|
|
AtalkReferenceActiveNode(activeNode, __NODE__ | __LINE__);
|
|
AtalkReferenceActiveNode(activeNode, __NODE__ | __LINE__);
|
|
|
|
} else {
|
|
|
|
Free(activeNode);
|
|
error = ATnoMoreNodes;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
if (error != ATnoError) {
|
|
break;
|
|
}
|
|
|
|
if (GET_PORTDESCRIPTOR(Port)->PortType == NONAPPLETALK_HALFPORT) {
|
|
|
|
// Build a dummy active node; invalid network/node values.
|
|
newNode.NetworkNumber = UNKNOWN_NETWORKNUMBER;
|
|
newNode.NodeNumber = UNKNOWN_NODENUMBER;
|
|
|
|
activeNode->ExtendedNode = newNode;
|
|
|
|
} else if (GET_PORTDESCRIPTOR(Port)->PortType == LOCALTALK_NETWORK) {
|
|
|
|
// Pick a desired node, if we have a PRAM value.
|
|
if (RoutersNode &&
|
|
GET_PORTDESCRIPTOR(Port)->RoutersPRamStartupNode.NetworkNumber
|
|
!= UNKNOWN_NETWORKNUMBER) {
|
|
|
|
desiredNode = GET_PORTDESCRIPTOR(Port)->RoutersPRamStartupNode;
|
|
|
|
} else if (!RoutersNode &&
|
|
GET_PORTDESCRIPTOR(Port)->UsersPRamStartupNode.NetworkNumber
|
|
!= UNKNOWN_NETWORKNUMBER) {
|
|
|
|
desiredNode = GET_PORTDESCRIPTOR(Port)->UsersPRamStartupNode;
|
|
}
|
|
|
|
// During intitialization the localtalk node address should have
|
|
// been stored in the MyAddress field of this port descriptor. Cast
|
|
// it as a ulong before using it.
|
|
nodeNumber = *(PUSHORT)GET_PORTDESCRIPTOR(Port)->MyAddress;
|
|
ASSERT(nodeNumber >= 0);
|
|
|
|
newNode.NetworkNumber =
|
|
GET_PORTDESCRIPTOR(Port)->ThisCableRange.FirstNetworkNumber;
|
|
newNode.NodeNumber = (char)nodeNumber;
|
|
|
|
activeNode->ExtendedNode = newNode;
|
|
}
|
|
|
|
// Remove the reference we had for the active node while initializing it
|
|
AtalkDereferenceActiveNodeInterlocked(activeNode, __NODE__ | __LINE__);
|
|
}
|
|
|
|
// Set up the RTMP, NBP and EP listeners on the new node.
|
|
if (!OpenStaticSockets(Port, newNode)) {
|
|
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_NODE_OPENSOCKETS,
|
|
(__NODE__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
if (Node != NULL)
|
|
*Node = newNode;
|
|
|
|
// Try to save PRAM info...
|
|
if (RoutersNode) {
|
|
SavePRamAddress(Port, True, newNode);
|
|
GET_PORTDESCRIPTOR(Port)->RoutersPRamStartupNode = newNode;
|
|
} else {
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
if (!GET_PORTDESCRIPTOR(Port)->Flags & PD_FIRSTNODEALLOC) {
|
|
GET_PORTDESCRIPTOR(Port)->Flags |= PD_FIRSTNODEALLOC;
|
|
GET_PORTDESCRIPTOR(Port)->UsersPRamStartupNode = newNode;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
SavePRamAddress(Port, False, newNode);
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
AtalkDereferencePortDescriptor(GET_PORTDESCRIPTOR(Port),__LINE__ | __NODE__);
|
|
AtalkDereferenceStack(__LINE__ | __NODE__ );
|
|
return(error);
|
|
|
|
} // GetNodeOnPort
|
|
|
|
|
|
|
|
|
|
APPLETALK_ERROR
|
|
ReleaseNodeOnPort(
|
|
int Port,
|
|
EXTENDED_NODENUMBER Node
|
|
)
|
|
{
|
|
APPLETALK_ERROR error = ATnoError;
|
|
PACTIVE_NODE activeNode, previousActiveNode;
|
|
POPEN_SOCKET openSocket, nextOpenSocket;
|
|
|
|
// If the "default Port" == requested, demystify it.
|
|
if (Port == DEFAULT_PORT)
|
|
if ((Port = FindDefaultPort()) < 0)
|
|
return(ATappleTalkShutDown);
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
|
|
// Find the node on the Port's active node list.
|
|
for (activeNode = GET_PORTDESCRIPTOR(Port)->ActiveNodes;
|
|
activeNode != NULL;
|
|
activeNode = activeNode->Next) {
|
|
if (ExtendedAppleTalkNodesEqual(&activeNode->ExtendedNode, &Node))
|
|
break;
|
|
}
|
|
|
|
if (activeNode != NULL) {
|
|
if ((activeNode->Flags & AN_CLOSING) == 0) {
|
|
activeNode->Flags |= AN_CLOSING;
|
|
|
|
// Close any sockets that are still open.
|
|
for (openSocket = activeNode->OpenSockets;
|
|
openSocket != NULL;
|
|
openSocket = nextOpenSocket) {
|
|
nextOpenSocket = openSocket->Next;
|
|
if (CloseSocketOnNode(openSocket->Socket, NULL, NULL) != ATnoError)
|
|
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_NODE_CLOSESOCKETS,
|
|
(__NODE__ | __LINE__),
|
|
openSocket->Socket,
|
|
openSocket,
|
|
sizeof(openSocket),
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
// Dereference for creation
|
|
AtalkDereferenceActiveNode(activeNode, __NODE__ | __LINE__);
|
|
}
|
|
|
|
// Multiple calls to ReleaseNode == a single call
|
|
|
|
} else {
|
|
error = ATnodeNotInUse;
|
|
}
|
|
|
|
return(error);
|
|
|
|
} // ReleaseNodeOnPort
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SavePRamAddress(
|
|
int Port,
|
|
BOOLEAN routersNode,
|
|
EXTENDED_NODENUMBER node
|
|
)
|
|
{
|
|
//
|
|
// If the target environment supPorts the concept, this is a good place
|
|
// to save away the last used AppleTalk addresses in PRAM. This information
|
|
// should then be passed back to Initialize() (in the PRam fields of
|
|
// PortInfo[]) on subsequent stack/router startup calls.
|
|
//
|
|
|
|
Port;
|
|
routersNode;
|
|
node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
RoutersNodeOnPort(
|
|
int Port,
|
|
PEXTENDED_NODENUMBER RoutersNode
|
|
)
|
|
{
|
|
PACTIVE_NODE activeNode;
|
|
BOOLEAN found = FALSE;
|
|
|
|
// If the "default Port" == requested, demystify it.
|
|
if (Port == DEFAULT_PORT)
|
|
if ((Port = FindDefaultPort()) < 0)
|
|
return(found);
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
for (activeNode = GET_PORTDESCRIPTOR(Port)->ActiveNodes;
|
|
activeNode != NULL;
|
|
activeNode = activeNode->Next)
|
|
if (activeNode->RoutersNode) {
|
|
*RoutersNode = activeNode->ExtendedNode;
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
return(found);
|
|
|
|
} // RoutersNodeOnPort
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
OpenStaticSockets(
|
|
int Port,
|
|
EXTENDED_NODENUMBER Node
|
|
)
|
|
{
|
|
long nbpSocket, epSocket, rtmpSocket;
|
|
|
|
if (OpenSocketOnNode(
|
|
&nbpSocket,
|
|
Port,
|
|
&Node,
|
|
NAMESINFORMATION_SOCKET,
|
|
NbpPacketIn,
|
|
(long)0,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
NULL) == ATnoError) {
|
|
|
|
if (OpenSocketOnNode(
|
|
&epSocket,
|
|
Port,
|
|
&Node,
|
|
ECHOER_SOCKET,
|
|
EpPacketIn,
|
|
(long)0,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
NULL) == ATnoError) {
|
|
|
|
if (OpenSocketOnNode(
|
|
&rtmpSocket,
|
|
Port,
|
|
&Node,
|
|
RTMP_SOCKET,
|
|
RtmpPacketIn,
|
|
(long)0,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
NULL) == ATnoError) {
|
|
|
|
return(TRUE);
|
|
|
|
} else {
|
|
CloseSocketOnNode(nbpSocket, NULL, NULL);
|
|
CloseSocketOnNode(epSocket, NULL, NULL);
|
|
}
|
|
|
|
} else {
|
|
|
|
CloseSocketOnNode(nbpSocket, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
} // OpenStaticSockets
|
|
|
|
|
|
|
|
|
|
PACTIVE_NODE
|
|
AtalkRefActiveNode(
|
|
PACTIVE_NODE ActiveNode
|
|
)
|
|
{
|
|
PACTIVE_NODE node = ActiveNode;
|
|
|
|
ASSERT(ActiveNode->ReferenceCount >= 0);
|
|
ActiveNode->ReferenceCount++;
|
|
return(node);
|
|
}
|
|
|
|
|
|
|
|
|
|
PACTIVE_NODE
|
|
AtalkVerifyActiveNode(
|
|
PACTIVE_NODE ActiveNode,
|
|
ULONG Location
|
|
)
|
|
{
|
|
PACTIVE_NODE node = ActiveNode;
|
|
|
|
if (ActiveNode->Flags & AN_CLOSING) {
|
|
node = NULL;
|
|
} else {
|
|
AtalkRefActiveNode(ActiveNode);
|
|
}
|
|
|
|
return(node);
|
|
}
|
|
|
|
|
|
|
|
|
|
PACTIVE_NODE
|
|
AtalkVerifyNextNonClosingActiveNode(
|
|
PACTIVE_NODE StartActiveNode,
|
|
ULONG Location
|
|
)
|
|
{
|
|
//
|
|
// THIS WILL INCLUDE THE START NODE
|
|
//
|
|
|
|
PACTIVE_NODE node;
|
|
|
|
while (StartActiveNode != NULL) {
|
|
if ((node = AtalkVerifyActiveNode(
|
|
StartActiveNode,
|
|
Location)) == NULL) {
|
|
StartActiveNode = StartActiveNode->Next;
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(node);
|
|
}
|
|
|
|
|
|
|
|
|
|
PACTIVE_NODE
|
|
AtalkVerifyActiveNodeInterlocked(
|
|
PACTIVE_NODE ActiveNode,
|
|
ULONG Location
|
|
)
|
|
{
|
|
PACTIVE_NODE node = ActiveNode;
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
if (ActiveNode->Flags & AN_CLOSING) {
|
|
node = NULL;
|
|
} else {
|
|
AtalkRefActiveNode(ActiveNode);
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
return(node);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkDerefActiveNode(
|
|
PACTIVE_NODE ActiveNode
|
|
)
|
|
{
|
|
PACTIVE_NODE activeNode, previousActiveNode;
|
|
BOOLEAN release = FALSE;
|
|
int port = ActiveNode->Port;
|
|
|
|
ASSERT(ActiveNode->ReferenceCount > 0);
|
|
ActiveNode->ReferenceCount--;
|
|
if (ActiveNode->ReferenceCount == 0) {
|
|
ASSERT(ActiveNode->Flags & AN_CLOSING);
|
|
release = TRUE;
|
|
|
|
// No more references on this active node
|
|
// Find the node on the port's active node list.
|
|
for (activeNode = GET_PORTDESCRIPTOR(port)->ActiveNodes,
|
|
previousActiveNode = NULL;
|
|
activeNode != NULL;
|
|
previousActiveNode = activeNode,
|
|
activeNode = activeNode->Next) {
|
|
|
|
if (activeNode == ActiveNode)
|
|
break;
|
|
}
|
|
|
|
if (activeNode == NULL) {
|
|
// INTERNAL_ERROR()
|
|
}
|
|
|
|
// Remove it from the list.
|
|
if (previousActiveNode == NULL)
|
|
GET_PORTDESCRIPTOR(port)->ActiveNodes = activeNode->Next;
|
|
else
|
|
previousActiveNode->Next = activeNode->Next;
|
|
|
|
// Deref the port descriptor for this node
|
|
AtalkDereferencePortDescriptor(
|
|
GET_PORTDESCRIPTOR(port), __NODE__ | __LINE__);
|
|
|
|
// All set!
|
|
Free(activeNode);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
PACTIVE_NODE
|
|
AllocateActiveNode(
|
|
VOID
|
|
)
|
|
{
|
|
PACTIVE_NODE activeNode;
|
|
|
|
activeNode = Calloc(sizeof(ACTIVE_NODE), sizeof(CHAR));
|
|
if (activeNode != NULL) {
|
|
activeNode->Type = AN_TYPE;
|
|
activeNode->Size = AN_SIZE;
|
|
}
|
|
|
|
return(activeNode);
|
|
}
|