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.
1566 lines
34 KiB
1566 lines
34 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
aarp.c
|
|
|
|
Abstract:
|
|
|
|
This module handles AARP.
|
|
|
|
Author:
|
|
|
|
Garth Conboy Initial Coding
|
|
Nikhil Kamkolkar Rewritten for microsoft coding style, mp-safe
|
|
|
|
Revision History:
|
|
|
|
GC - (10/07/90): In TokenRing land, we may get our own broadcasts, so
|
|
ignore any AARPs from us.
|
|
GC - (01/19/92): Newest OS/2 integration: source routing info in the best
|
|
router cache; better random picking of nets and nodes
|
|
when AARPing in a range.
|
|
GC - (04/05/92): Checking for net/node overlap with exsiting active nodes
|
|
should be done in AarpForNode... don't allow the PRAM
|
|
node to be re-used!
|
|
|
|
Note that AarpForNodeOnPort() will leave the ZONESINFORMATION_SOCKET
|
|
open on the newly allocated node.
|
|
|
|
--*/
|
|
|
|
|
|
#include "atalk.h"
|
|
|
|
|
|
LOCAL
|
|
BOOLEAN
|
|
AarpForNode(
|
|
int Port,
|
|
USHORT NetworkNumber,
|
|
UCHAR NodeNumber);
|
|
|
|
LOCAL
|
|
BOOLEAN
|
|
IsPrime(
|
|
LONG Step);
|
|
|
|
LOCAL
|
|
VOID
|
|
TuneRoutingInfo(
|
|
int Port,
|
|
PUCHAR RoutingInfo);
|
|
|
|
LOCAL
|
|
VOID
|
|
EnterIntoADDRESS_MAPPINGTABLE(
|
|
int Port,
|
|
EXTENDED_NODENUMBER SourceNode,
|
|
PCHAR SourceAddress,
|
|
int AddressLength,
|
|
PUCHAR RoutingInfo,
|
|
int RoutingInfoLength);
|
|
|
|
LOCAL
|
|
PBUFFER_DESC
|
|
BuildAarpPacket(
|
|
int port,
|
|
int type,
|
|
int hardwareLength,
|
|
PCHAR sourceHardwareAddress,
|
|
EXTENDED_NODENUMBER sourceLogicalAddress,
|
|
PCHAR destHardwareAddress,
|
|
EXTENDED_NODENUMBER destLogicalAddress,
|
|
PCHAR trueDestination,
|
|
PUCHAR routingInfo,
|
|
int routingInfoLength,
|
|
PINT packetLength);
|
|
|
|
LOCAL
|
|
BOOLEAN
|
|
AarpForNodeInRange(
|
|
int port,
|
|
APPLETALK_NETWORKRANGE networkRange,
|
|
BOOLEAN serverNode,
|
|
PEXTENDED_NODENUMBER node);
|
|
|
|
LOCAL
|
|
TimerHandler
|
|
AddressMappingAgingTimerExpired;
|
|
|
|
LOCAL
|
|
TimerHandler
|
|
BestRouterAgingTimerExpired;
|
|
|
|
static BOOLEAN firstGleanCall = True;
|
|
static BOOLEAN firstAddressMappingCall = True;
|
|
|
|
|
|
VOID
|
|
ShutdownAarp(
|
|
VOID
|
|
)
|
|
{
|
|
firstGleanCall = True;
|
|
firstAddressMappingCall = True;
|
|
|
|
} // ShutdownAarp
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AarpPacketIn(
|
|
int Port,
|
|
PUCHAR RoutingInfo,
|
|
int RoutingInfoLength,
|
|
PUCHAR Packet,
|
|
int Length
|
|
)
|
|
{
|
|
PUCHAR sourceAddress;
|
|
PUCHAR startOfPacket;
|
|
EXTENDED_NODENUMBER sourceNode, destinationNode;
|
|
ULONG logEventPlace = 0;
|
|
|
|
int aarpCommand;
|
|
PBUFFER_DESC response;
|
|
short hardwareLength, logicalLength;
|
|
int packetLength;
|
|
PortHandlers portHandlers;
|
|
ActiveNode activeNode;
|
|
|
|
if (AtalkReferenceStackInterlock(__LINE__ | __AARP__) {
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
|
|
if (!AtalkReferencePortDescriptorInterlock(
|
|
GET_PORTDESCRIPTOR(Port),
|
|
__LINE__ | __AARP__) {
|
|
|
|
AtalkDereferenceStack(__LINE__ | __AARP__ );
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
|
|
Packet += IEEE8022_HEADERLENGTH;
|
|
Length -= IEEE8022_HEADERLENGTH;
|
|
startOfPacket = Packet;
|
|
|
|
portHandlers = &PortSpecificInfo[GET_PORTDESCRIPTOR(Port)->PortType];
|
|
|
|
//
|
|
// Pull out the information we'll be playing with. All three valid AARP
|
|
// commands use the same packet format.
|
|
//
|
|
|
|
Packet += AARP_HARDWARELENGTHOFFSET; // Skip the hardware type
|
|
|
|
do {
|
|
|
|
GETUCHAR2USHORT(Packet, &hardwareLength);
|
|
Packet += 1;
|
|
|
|
if ((hardwareLength < AARP_MINIMUMHARDWAREADDRESSLENGTH ) ||
|
|
(hardwareLength > AARP_MAXIMUMHARDWAREADDRESSLENGTH)) {
|
|
|
|
logEventPlace = (__AARP__ | __LINE__);
|
|
break;
|
|
}
|
|
|
|
GETUCHAR2USHORT(Packet, &logicalLength);
|
|
Packet += 1;
|
|
|
|
if (logicalLength != AarpLogicalAddressLength) {
|
|
|
|
logEventPlace = (__AARP__ | __LINE__);
|
|
break;
|
|
}
|
|
|
|
GETUSHORTTOUSHORT(Packet, &aarpCommand);
|
|
Packet += 2;
|
|
|
|
// Remember where the source address is in the packet for
|
|
// entering it into the mapping table
|
|
sourceAddress = Packet;
|
|
Packet += hardwareLength;
|
|
Packet += 1; // Skip over to leading null pad on logical address.
|
|
|
|
GETUSHORTTOUSHORT(Packet, &sourceNode.NetworkNumber);
|
|
Packet += 2;
|
|
|
|
GETUCHARTOUCHAR(Packet, &sourceNode.NodeNumber);
|
|
Packet += 1;
|
|
|
|
|
|
// Skip the destination hardware address
|
|
Packet += hardwareLength;
|
|
|
|
Packet += 1; // Skip over to leading null pad on logical destination address.
|
|
GETUSHORTTOUSHORT(Packet, &destinationNode.NetworkNumber);
|
|
Packet += 2;
|
|
|
|
GETUCHARTOUCHAR(Packet, &destinationNode.NodeNumber);
|
|
Packet += 1;
|
|
|
|
// We should have eaten the whole packet...
|
|
if (Packet - startOfPacket != Length) {
|
|
|
|
logEventPlace = (__AARP__ | __LINE__);
|
|
break;
|
|
}
|
|
|
|
// Ignore any AARPs from us.
|
|
if (FixedCompareCaseSensitive(
|
|
sourceAddress,
|
|
TOKENRING_ADDRESSLENGTH,
|
|
GET_PORTDESCRIPTOR(Port)->MyAddress,
|
|
TOKENRING_ADDRESSLENGTH))
|
|
|
|
break;
|
|
|
|
// Do the right thing...
|
|
switch(aarpCommand) {
|
|
case AARP_REQUEST:
|
|
|
|
// We can get valid mapping info from a request, use it!
|
|
// We are guaranteed routing info is positive and is not odd
|
|
// (atleast 2 bytes).
|
|
|
|
ASSERT((RoutingInfoLength >= 0) && (RoutingInfoLength != 1));
|
|
if (RoutingInfoLength > 0)
|
|
TuneRoutingInfo(Port, RoutingInfo);
|
|
|
|
EnterIntoADDRESS_MAPPINGTABLE(
|
|
Port,
|
|
sourceNode,
|
|
sourceAddress,
|
|
hardwareLength,
|
|
RoutingInfo,
|
|
RoutingInfoLength);
|
|
|
|
// After that, we can ignore any request not destined for us.
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
for (activeNode = GET_PORTDESCRIPTOR(Port)->ActiveNodes;
|
|
activeNode isnt empty;
|
|
activeNode = activeNode->next) {
|
|
|
|
if (ExtendedAppleTalkNodesEqual(
|
|
&destinationNode,
|
|
&activeNode->extendedNode))
|
|
break;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
if (activeNode is empty) {
|
|
break; // Not one of our nodes...
|
|
}
|
|
|
|
// The're asking about us, speak the truth.
|
|
response = BUILD_AARPRESPONSE(
|
|
Port,
|
|
hardwareLength,
|
|
sourceAddress,
|
|
RoutingInfo,
|
|
RoutingInfoLength,
|
|
destinationNode,
|
|
sourceNode,
|
|
&packetLength);
|
|
|
|
if (!(*PortHandlers->PacketOut)(
|
|
Port,
|
|
response,
|
|
packetLength,
|
|
NULL,
|
|
0)) {
|
|
|
|
// We allocated the packet.
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_AARPPACKETOUTFAIL,
|
|
__LINE__ | __AARP__,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
response->data,
|
|
packetLength,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
break;
|
|
|
|
case AARP_RESPONSE:
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
if (GET_PORTDESCRIPTOR(Port)->TryingToFindNodeOnPort) {
|
|
|
|
//
|
|
// No doubt, this is a response to our probe, check to make sure
|
|
// the address matches, if so set the "used" flag.
|
|
//
|
|
|
|
if (ExtendedAppleTalkNodesEqual(
|
|
&destinationNode,
|
|
&GET_PORTDESCRIPTOR(Port)->TentativeAppleTalkNode)) {
|
|
|
|
GET_PORTDESCRIPTOR(Port)->TentativeNodeHasBeenUsed = TRUE;
|
|
}
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
//
|
|
// This must have been a response to a probe or request... update our
|
|
// mapping table.
|
|
//
|
|
|
|
if (RoutingInfoLength isnt 0)
|
|
TuneRoutingInfo(Port, RoutingInfo);
|
|
|
|
EnterIntoADDRESS_MAPPINGTABLE(
|
|
Port,
|
|
sourceNode,
|
|
sourceAddress,
|
|
hardwareLength,
|
|
RoutingInfo,
|
|
RoutingInfoLength);
|
|
|
|
break;
|
|
|
|
case AARP_PROBE:
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
if (GET_PORTDESCRIPTOR(Port)->TryingToFindNodeOnPort) {
|
|
|
|
//
|
|
// If we get a probe for our current tentative address, set the
|
|
// "used" flag.
|
|
//
|
|
|
|
if (ExtendedAppleTalkNodesEqual(
|
|
&destinationNode,
|
|
&GET_PORTDESCRIPTOR(Port)->TentativeAppleTalkNode)) {
|
|
|
|
GET_PORTDESCRIPTOR(Port)->TentativeNodeHasBeenUsed = True;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the probe isn't asking about one of our AppleTalk addresses,
|
|
// drop it on the floor.
|
|
//
|
|
|
|
for (activeNode = GET_PORTDESCRIPTOR(Port)->ActiveNodes;
|
|
activeNode isnt empty;
|
|
activeNode = activeNode->next) {
|
|
|
|
if (ExtendedAppleTalkNodesEqual(
|
|
&destinationNode,
|
|
&activeNode->extendedNode)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
if (activeNode is empty) {
|
|
break; // Not one of our nodes...
|
|
}
|
|
|
|
// The're talking to us! Build and send the response.
|
|
if (RoutingInfoLength isnt 0)
|
|
TuneRoutingInfo(Port, RoutingInfo);
|
|
|
|
response = BUILD_AARPRESPONSE(
|
|
Port,
|
|
hardwareLength,
|
|
sourceAddress,
|
|
RoutingInfo,
|
|
RoutingInfoLength,
|
|
destinationNode,
|
|
sourceNode,
|
|
&packetLength);
|
|
|
|
if (!(*PortHandlers->PacketOut)(
|
|
Port,
|
|
response,
|
|
packetLength,
|
|
NULL,
|
|
0)) {
|
|
|
|
// We allocated the packet.
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_AARPPACKETOUTFAIL,
|
|
__LINE__ | __AARP__,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
response->data,
|
|
packetLength,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
logEventPlace = (__AARP__ | __LINE__);
|
|
break;
|
|
}
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
if (logEventPlace) {
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_INVALIDAARPPACKET,
|
|
logEventPlace,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
startOfPacket,
|
|
Length,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
AtalkDereferencePortDescriptor(GET_PORTDESCRIPTOR(Port),__LINE__ | __AARP__);
|
|
AtalkDereferenceStack(__LINE__ | __AARP__ );
|
|
return;
|
|
|
|
} // AarpPacketIn
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
GleanAarpInfo(
|
|
int Port,
|
|
PUCHAR sourceAddress,
|
|
int addressLength,
|
|
PUCHAR routingInfo,
|
|
int routingInfoLength,
|
|
PUCHAR Packet,
|
|
int Length
|
|
)
|
|
{
|
|
EXTENDED_NODENUMBER sourceNode, destinationNode;
|
|
UCHAR offCableInfo;
|
|
PUCHAR startOfPacket;
|
|
int index;
|
|
|
|
BOOLEAN result = TRUE;
|
|
ULONG logEventPlace = 0;
|
|
|
|
// Do we even want AppleTalk packets now?
|
|
if (AtalkReferenceStackInterlock(__LINE__ | __AARP__) {
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
|
|
if (!AtalkReferencePortDescriptorInterlock(
|
|
GET_PORTDESCRIPTOR(Port),
|
|
__LINE__ | __AARP__) {
|
|
|
|
AtalkDereferenceStack(__LINE__ | __AARP__ );
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
|
|
Packet += IEEE8022_HEADERLENGTH;
|
|
Length -= IEEE8022_HEADERLENGTH;
|
|
|
|
// Remember the start of the packet
|
|
startOfPacket = Packet;
|
|
|
|
// Get the off cable information
|
|
GETUCHAR2UCHAR(Packet, &offCableInfo);
|
|
Packet += 1;
|
|
|
|
// Skip the datagram length and checksum fields
|
|
Packet += 1+2;
|
|
|
|
// Get the destination network number
|
|
GETUSHORTTOUSHORT(Packet, &destinationNode.NetworkNumber;
|
|
Packet += 2;
|
|
|
|
// Get the source network number
|
|
GETUSHORTTOUSHORT(Packet, &sourceNode.NetworkNumber;
|
|
Packet += 2;
|
|
|
|
// Get the destination node id
|
|
GETUCHAR2UCHAR(Packet, &destinationNode.NodeNumber);
|
|
Packet += 1;
|
|
|
|
// Get the source node id
|
|
GETUCHAR2UCHAR(Packet, &sourceNode.NodeNumber);
|
|
Packet += 1;
|
|
|
|
do {
|
|
|
|
// Do a little verification. nnnn00 is legal for dest for NBP routing.
|
|
if ((sourceNode.NodeNumber < MINIMUM_USABLEAPPLETALKNODE) ||
|
|
(sourceNode.NodeNumber > MAXIMUM_USABLEAPPLETALKNODE) ||
|
|
(sourceNode.NetworkNumber < FIRST_VALIDNETWORKNUMBER) ||
|
|
(sourceNode.NetworkNumber > LAST_VALIDNETWORKNUMBER)) {
|
|
|
|
//
|
|
// Only bother logging this if we are in some routing capacity,
|
|
// otherwise, let A-ROUTER worry about it
|
|
//
|
|
|
|
if (GET_PORTDESCRIPTOR(Port)->RoutingPort) {
|
|
logEventPlace = __AARP__ | __LINE__;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (destinationNode.networkNumber > LAST_VALIDNETWORKNUMBER) {
|
|
|
|
logEventPlace = __AARP__ | __LINE__;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Did the packet come from off this cable? Look at the hop count. If so,
|
|
// enter it into our best-router cache.
|
|
//
|
|
|
|
if (RoutingInfoLength > 0)
|
|
TuneRoutingInfo(Port, RoutingInfo);
|
|
|
|
if ((offCableInfo >> 2) & OFFCABLE_MASK) {
|
|
|
|
index = HashExtendedAppleTalkNode(sourceNode) % BESTROUTER_HASHBUCKETS;
|
|
GET_PORTDESCRIPTOR(Port)->BestRouterCache[index].Valid = True;
|
|
GET_PORTDESCRIPTOR(Port)->BestRouterCache[index].AgingCount = 0;
|
|
GET_PORTDESCRIPTOR(Port)->BestRouterCache[index].Target = sourceNode;
|
|
|
|
MoveMem(
|
|
GET_PORTDESCRIPTOR(Port)->BestRouterCache[index].RouterAddress,
|
|
sourceAddress,
|
|
addressLength);
|
|
|
|
GET_PORTDESCRIPTOR(Port)->BestRouterCache[index].RoutingInfoLength =
|
|
(SHORT)routingInfoLength;
|
|
|
|
if (routingInfoLength > 0)
|
|
MoveMem(
|
|
GET_PORTDESCRIPTOR(Port)->BestRouterCache[index].RoutingInfo,
|
|
RoutingInfo,
|
|
RoutingInfoLength);
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
if (firstGleanCall) {
|
|
|
|
firstGleanCall = False;
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
// Start the best router table maintenance timer.
|
|
StartTimer(
|
|
BestRouterAgingTimerExpired,
|
|
BESTROUTER_AGINGSECONDS,
|
|
0,
|
|
NULL);
|
|
}
|
|
} else {
|
|
|
|
// "Glean" AARP information from on-cable packets.
|
|
EnterIntoADDRESS_MAPPINGTABLE(
|
|
Port,
|
|
sourceNode,
|
|
sourceAddress,
|
|
addressLength,
|
|
RoutingInfo,
|
|
RoutingInfoLength);
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (logEventPlace) {
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_INVALIDAARPPACKET,
|
|
logEventPlace,
|
|
0,
|
|
startOfPacket,
|
|
Length,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
return(logEventPlace == 0);
|
|
|
|
} // GleanAarpInfo
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AarpForNodeOnPort(
|
|
int Port,
|
|
BOOLEAN AllowStartupRange,
|
|
BOOLEAN ServerNode,
|
|
EXTENDED_NODENUMBER DesiredNode,
|
|
PEXTENDED_NODENUMBER Node
|
|
)
|
|
{
|
|
BOOLEAN foundNode = FALSE, inStartupRange = FALSE, result = TRUE;
|
|
BOOLEAN seenRouter;
|
|
PACTIVE_NODE activeNode;
|
|
EXTENDED_NODENUMBER newNode;
|
|
|
|
//
|
|
// Try to find a new extended Node on the given port; first try for the
|
|
// requested address (if specified), else try in this port's cable range
|
|
// (if it's known) or in the default cable range (if any), then try the
|
|
// start-up range (if allowed).
|
|
//
|
|
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
if (!GET_PORTDESCRIPTOR(Port)->TryingToFindNodeOnPort) {
|
|
GET_PORTDESCRIPTOR(Port)->TryingToFindNodeOnPort = TRUE;
|
|
else {
|
|
result = FALSE;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
// Return if we are already trying to find a node
|
|
// BUGBUG: Return failure of success??
|
|
if (!result) {
|
|
return(result);
|
|
}
|
|
|
|
|
|
if (DesiredNode.networkNumber != UNKNOWN_NETWORKNUMBER)
|
|
foundNode = AarpForNode(
|
|
Port,
|
|
DesiredNode.NetworkNumber,
|
|
DesiredNode.NodeNumber);
|
|
|
|
if (foundNode) {
|
|
newNode = DesiredNode;
|
|
} else {
|
|
if (GET_PORTDESCRIPTOR(Port)->SeenRouterRecently) {
|
|
|
|
foundNode = AarpForNodeInRange(
|
|
Port,
|
|
GET_PORTDESCRIPTOR(Port)->ThisCableRange,
|
|
ServerNode,
|
|
&newNode);
|
|
|
|
}else if (GET_PORTDESCRIPTOR(Port)->InitialNetworkRange.FirstNetworkNumber !=
|
|
UNKNOWN_NETWORKNUMBER) {
|
|
foundNode = AarpForNodeInRange(
|
|
Port,
|
|
GET_PORTDESCRIPTOR(Port)->InitialNetworkRange,
|
|
ServerNode,
|
|
&newNode);
|
|
} else {
|
|
|
|
//
|
|
// If no place else to try, try the start-up range. Do this even if
|
|
// we don't want to end up there.
|
|
//
|
|
// The idea is that this happens only when we are starting the router
|
|
// on one of our ports. (GetNodeOnPort in irouter.c). So we do not want
|
|
// the router started in the startup range. If we do start in the startup
|
|
// range, and we see later that we did not see a router in the process,
|
|
// we will release the node. Of course, if we are a seed router, we will
|
|
// never be here, as the if statement above will be true.
|
|
//
|
|
|
|
inStartupRange = TRUE;
|
|
foundNode = AarpForNodeInRange(
|
|
Port,
|
|
startupNetworkRange,
|
|
ServerNode,
|
|
&newNode);
|
|
}
|
|
}
|
|
|
|
// If we have a tentative Node, go on. we use the for loop, as the code in
|
|
// the beginning could be executed twice, when we get a node in the wrong
|
|
// range and need to try again
|
|
|
|
for (i=0; i < 2; i++) {
|
|
|
|
if (foundNode) {
|
|
|
|
// Build a new active Node structure and tack the new Node onto
|
|
// the Port.
|
|
if ((activeNode = (PACTIVE_NODE)Calloc(
|
|
sizeof(ACTIVE_NODE),
|
|
sizeof(CHAR))) == NULL) {
|
|
|
|
LOG_ERROR(
|
|
EVENT_ATALK_MEMORY_RESOURCES,
|
|
(__AARP__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
|
|
result = FALSE;
|
|
break;
|
|
}
|
|
|
|
activeNode->ExtendedNode = newNode;
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
activeNode->next = GET_PORTDESCRIPTOR(Port)->ActiveNodes;
|
|
GET_PORTDESCRIPTOR(Port)->ActiveNodes = activeNode;
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
//
|
|
// See who's out there. We need to open the ZIP socket in order to be
|
|
// able to hear replies.
|
|
//
|
|
|
|
if (OpenSocketOnNode(
|
|
NULL,
|
|
Port,
|
|
&newNode,
|
|
ZONESINFORMATION_SOCKET,
|
|
ZipPacketIn,
|
|
(long)0,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
NULL) != ATnoError) {
|
|
|
|
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_OPENZIPSOCKET,
|
|
(__AARP__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
|
|
ReleaseNodeOnPort(
|
|
Port,
|
|
activeNode->ExtendedNode);
|
|
|
|
result = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (i == 1) {
|
|
|
|
// We acquired a node after a retry in the correct range
|
|
break;
|
|
}
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
seenRouter = GET_PORTDESCRIPTOR(Port)->SeenRouterRecently;
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
if (!seenRouter) {
|
|
GetNetworkInfoForNode(
|
|
Port,
|
|
activeNode->ExtendedNode,
|
|
FALSE,
|
|
TRUE);
|
|
}
|
|
|
|
//
|
|
// If nobody was out there and our tentative Node was in the
|
|
// startup range and our caller doesn't want to be there, return
|
|
// an error now.
|
|
//
|
|
// Note: this means that we were trying to start the router on
|
|
// a non-seeding port, and since there is not router on the net,
|
|
// it means the net is not seeded and so, we exit.
|
|
//
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
seenRouter = GET_PORTDESCRIPTOR(Port)->SeenRouterRecently;
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
if (inStartupRange &&
|
|
!seenRouter &&
|
|
!AllowStartupRange) {
|
|
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_STARTUPRANGENODE,
|
|
(__AARP__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
|
|
ReleaseNodeOnPort(
|
|
Port,
|
|
activeNode->extendedNode);
|
|
|
|
result = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we have seen SeenRouterRecently is not true, that means we have
|
|
// used the InitialNetworkRange to AARP. If now SeenRouterRecently is
|
|
// true that means we have gotten the address in the InitialNetworkRange,
|
|
// but now there is a seeded range on the net that we must use. So redo
|
|
// the GetNode work.
|
|
//
|
|
|
|
if (GET_PORTDESCRIPTOR(Port)->SeenRouterRecently &&
|
|
!IsWithinNetworkRange(
|
|
newNode.NetworkNumber,
|
|
&GET_PORTDESCRIPTOR(Port)->ThisCableRange)) {
|
|
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_INITIALRANGENODE,
|
|
(__AARP__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
|
|
// Release the node we obtained.
|
|
ReleaseNodeOnPort(
|
|
Port,
|
|
activeNode->ExtendedNode);
|
|
|
|
foundNode = AarpForNodeInRange(
|
|
Port,
|
|
GET_PORTDESCRIPTOR(Port)->ThisCableRange,
|
|
ServerNode,
|
|
&newNode);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
GET_PORTDESCRIPTOR(Port)->TryingToFindNodeOnPort = FALSE;
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
if (foundNode && result) {
|
|
|
|
// All set!
|
|
if (node != NULL)
|
|
*node = newNode;
|
|
|
|
EnterIntoADDRESS_MAPPINGTABLE(
|
|
Port,
|
|
newNode,
|
|
GET_PORTDESCRIPTOR(Port)->MyAddress,
|
|
PortSpecificInfo[GET_PORTDESCRIPTOR(Port)->PortType].\
|
|
HardwareAddressLength,
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
return(foundNode && result);
|
|
|
|
} // AarpForNodeOnPort
|
|
|
|
|
|
|
|
|
|
VOID
|
|
EnterIntoADDRESS_MAPPINGTABLE(
|
|
int Port,
|
|
EXTENDED_NODENUMBER SourceNode,
|
|
PCHAR SourceAddress,
|
|
int AddressLength,
|
|
PCHAR RoutingInfo,
|
|
int RoutingInfoLength
|
|
)
|
|
{
|
|
int index;
|
|
PADDRESS_MAPPINGNODE mapNode;
|
|
|
|
if (SourceNode.nodeNumber < MINIMUM_USABLEAPPLETALKNODE ||
|
|
SourceNode.nodeNumber > MAXIMUM_USABLEAPPLETALKNODE ||
|
|
SourceNode.networkNumber < FIRST_VALIDNETWORKNUMBER ||
|
|
SourceNode.networkNumber > LAST_VALIDNETWORKNUMBER) {
|
|
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_AMT_INVALIDSOURCE,
|
|
(__AARP__ | __LINE__),
|
|
0,
|
|
(PUCHAR)&SourceNode,
|
|
sizeof(SourceNode),
|
|
0,
|
|
NULL);
|
|
|
|
return;
|
|
}
|
|
|
|
// The address mapping tables need to be protected by critical sections!
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
if (firstAddressMappingCall) {
|
|
firstAddressMappingCall = FALSE;
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
// Start the address mapping table maintenance timer.
|
|
StartTimer(
|
|
AddressMappingAgingTimerExpired,
|
|
ADDRESSMAPPING_AGINGSECONDS,
|
|
0,
|
|
NULL);
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
}
|
|
|
|
|
|
// Do we already know about this mapping?
|
|
index = HashExtendedAppleTalkNode(SourceNode) % ADDRESSMAP_HASHBUCKETS;
|
|
for (mapNode = GET_PORTDESCRIPTOR(Port)->ADDRESS_MAPPINGTABLE[index];
|
|
mapNode != NULL;
|
|
mapNode = mapNode->Next) {
|
|
|
|
if (ExtendedAppleTalkNodesEqual(
|
|
&SourceNode,
|
|
&mapNode->Target))
|
|
break;
|
|
}
|
|
|
|
// If not, allocate a new mapping Node.
|
|
if (mapNode == NULL) {
|
|
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
mapNode = (PADDRESS_MAPPINGNODE)Calloc(
|
|
sizeof(ADDRESS_MAPPINGNODE),
|
|
sizeof(CHAR));
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
|
|
mapNode->Next = GET_PORTDESCRIPTOR(Port)->ADDRESS_MAPPINGTABLE[index];
|
|
GET_PORTDESCRIPTOR(Port)->ADDRESS_MAPPINGTABLE[index] = mapNode;
|
|
mapNode->Target = SourceNode;
|
|
}
|
|
|
|
if (mapNode != NULL) {
|
|
|
|
// Update mapping table! Do this if we knew about the mapping OR
|
|
// if we allocated a new node
|
|
MoveMem(
|
|
mapNode->HardwareAddress,
|
|
SourceAddress,
|
|
AddressLength);
|
|
|
|
if (RoutingInfoLength > 0)
|
|
MoveMem(
|
|
mapNode->RoutingInfo,
|
|
RoutingInfo,
|
|
RoutingInfoLength);
|
|
|
|
mapNode->RoutingInfoLength = (short)RoutingInfoLength;
|
|
mapNode->AgingCount = 0;
|
|
|
|
#if Verbose // Assuming Ethernet/TokenRing here; only for debugging...
|
|
if (new) {
|
|
DbgPrint("New #%d %u.%u, addr %04X%04X%04X",
|
|
Port,
|
|
SourceNode.networkNumber,
|
|
SourceNode.nodeNumber,
|
|
*(USHORT *)SourceAddress,
|
|
*(USHORT *)(SourceAddress + sizeof(short)),
|
|
*(USHORT *)(SourceAddress + sizeof(short) * 2));
|
|
|
|
}
|
|
#endif
|
|
|
|
} else {
|
|
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
LOG_ERROR(
|
|
EVENT_ATALK_MEMORY_RESOURCES,
|
|
(__AARP__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
}
|
|
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
return;
|
|
|
|
} // EnterIntoADDRESS_MAPPINGTABLE
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AddressMappingAgingTimerExpired(
|
|
ULONG TimerId,
|
|
int AdditionalDataSize,
|
|
PCHAR AdditionalData
|
|
)
|
|
{
|
|
int port;
|
|
PADDRESS_MAPPINGNODE mapNode, nextMapNode, previousMapNode;
|
|
int index;
|
|
|
|
UNREFERENCED_PARAMETER(TimerId);
|
|
UNREFERENCED_PARAMETER(AdditionalDataSize);
|
|
UNREFERENCED_PARAMETER(AdditionalData);
|
|
|
|
//
|
|
// Walk though all address mapping tables aging the entries. We need to
|
|
// protect the mapping tables with critical sections, but don't stay in
|
|
// a critical section too long.
|
|
//
|
|
|
|
for (port = 0; port < NumberOfPortsAllocated; port += 1) {
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
if (((GET_PORTDESCRIPTOR(port)->Flags & PD_ACTIVE) == 0) ||
|
|
(!GET_PORTDESCRIPTOR(port)->ExtendedNetwork) ||
|
|
(!AtalkReferencePortDescriptor(
|
|
GET_PORTDESCRIPTOR(Port),
|
|
__LINE__ | __AARP__))) {
|
|
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
continue;
|
|
}
|
|
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
for (index = 0; index < ADDRESSMAP_HASHBUCKETS; index += 1) {
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
for (mapNode = GET_PORTDESCRIPTOR(port)->ADDRESS_MAPPINGTABLE[index],
|
|
previousMapNode = NULL;
|
|
mapNode != NULL;
|
|
previousMapNode = mapNode, mapNode = nextMapNode) {
|
|
|
|
nextMapNode = mapNode->Next;
|
|
if (mapNode->AgingCount < ADDRESSMAPPING_AGINGCHANCES)
|
|
mapNode->AgingCount += 1;
|
|
else {
|
|
if (previousMapNode is NULL)
|
|
GET_PORTDESCRIPTOR(port)->ADDRESS_MAPPINGTABLE[index] = nextMapNode;
|
|
else
|
|
previousMapNode->Next = nextMapNode;
|
|
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
Free(mapNode);
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
|
|
//
|
|
// Restart the scan on this index because we've been out of
|
|
// a critical section.
|
|
//
|
|
|
|
mapNode = NULL;
|
|
nextMapNode = GET_PORTDESCRIPTOR(port)->ADDRESS_MAPPINGTABLE[index];
|
|
}
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
}
|
|
|
|
AtalkDereferencePortDescriptor(
|
|
GET_PORTDESCRIPTOR(Port),
|
|
__LINE__ | __AARP__);
|
|
}
|
|
|
|
// Try again in a little while...
|
|
StartTimer(
|
|
AddressMappingAgingTimerExpired,
|
|
ADDRESSMAPPING_AGINGSECONDS,
|
|
0,
|
|
NULL);
|
|
|
|
return;
|
|
|
|
} // AddressMappingAgingTimerExpired
|
|
|
|
|
|
|
|
|
|
PBUFFER_DESC
|
|
BuildAarpPacket(
|
|
int Port,
|
|
int Type,
|
|
int HardwareLength,
|
|
PCHAR SourceHardwareAddress,
|
|
EXTENDED_NODENUMBER SourceLogicalAddress,
|
|
PCHAR DestHardwareAddress,
|
|
EXTENDED_NODENUMBER DestLogicalAddress,
|
|
PCHAR TrueDestination,
|
|
PCHAR RoutingInfo,
|
|
int RoutingInfoLength,
|
|
PINT PacketLength
|
|
)
|
|
{
|
|
PBUFFER_DESC packet;
|
|
PCHAR startOfOnTheWirePacket;
|
|
PCHAR copyPoint;
|
|
PortHandlers portHandlers;
|
|
|
|
UCHAR protocolLength = AARP_MAXPROTOCOLADDRESSLENGTH;
|
|
|
|
|
|
//
|
|
// Get a buffer descriptor, and set the data to be beyond the longest
|
|
// possible hardware and 802.2 header length.
|
|
//
|
|
|
|
if ((packet = NewBufferDescriptor(MAXIMUM_AARPPACKETSIZE)) == NULL) {
|
|
|
|
LOG_ERROR(
|
|
EVENT_ATALK_MEMORY_RESOURCES,
|
|
(__AARP__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
|
|
return(NULL);
|
|
}
|
|
AdjustBufferDescriptor(packet, -MAXIMUM_HEADERLENGTH);
|
|
|
|
portHandlers = &PortSpecificInfo[GET_PORTDESCRIPTOR(port)->PortType];
|
|
|
|
//
|
|
// Build the specified type of AARP packet with the specified information;
|
|
// also, tack on the link specific header; return a pointer to the
|
|
// true start of packet as well as the packet legnth. If this doesn't
|
|
// make sense, reread the "Ethernet/AppleTalk AARP" spec.
|
|
//
|
|
|
|
|
|
PUTUSHORT2USHORT(
|
|
&portHandlers->AarpPhysicalType,
|
|
packet->data+AARP_HARDWARETYPEOFFSET);
|
|
|
|
PUTUSHORT2USHORT(
|
|
&portHandlers->ProtocolTypeForAppleTalk,
|
|
packet->data+AARP_PROTOCOLTYPEOFFSET);
|
|
|
|
PUTUCHARTOUCHAR(
|
|
HardwareLength,
|
|
packet->data+AARP_HARDWARELENGTHOFFSET);
|
|
|
|
PUTUCHARTOUCHAR(
|
|
AARP_PROTOCOLADDRESSLENGTH,
|
|
packet->data+AARP_PROTOCOLLENGTHOFFSET);
|
|
|
|
PUTUSHORT2USHORT(
|
|
&Type,
|
|
packet->data+AARP_COMMANDOFFSET);
|
|
|
|
// Source hardware address.
|
|
copyPoint = packet->data + AARP_SOURCEADDRESSOFFSET;
|
|
MoveMem(
|
|
copyPoint,
|
|
SourceHardwareAddress,
|
|
HardwareLength);
|
|
|
|
copyPoint += HardwareLength;
|
|
|
|
// Source logical address
|
|
PUTUCHAR2UCHAR(
|
|
0,
|
|
copyPoint);
|
|
|
|
copyPoint += 1; // Put in the null pad
|
|
|
|
// Network number
|
|
PUTUSHORT2USHORT(
|
|
&SourceLogicalAddress.NetworkNumber,
|
|
copyPoint);
|
|
|
|
copyPoint += 2;
|
|
|
|
// Node number
|
|
PUTUCHARTOUCHAR(
|
|
&SourceLogicalAddress.NodeNumber,
|
|
copyPoint);
|
|
|
|
copyPoint += 1;
|
|
|
|
// Destination hardware address.
|
|
MoveMem(
|
|
copyPoint,
|
|
DestHardwareAddress,
|
|
HardwareLength);
|
|
|
|
copyPoint += HardwareLength;
|
|
|
|
// Destination logical address
|
|
PUTUCHARTOUCHAR(
|
|
0,
|
|
copyPoint);
|
|
|
|
copyPoint += 1; // Put in the null pad
|
|
|
|
// Network number
|
|
PUTUSHORT2USHORT(
|
|
&DestLogicalAddress.NetworkNumber,
|
|
copyPoint);
|
|
|
|
copyPoint += 2;
|
|
|
|
// Node number
|
|
PUTUCHARTOUCHAR(
|
|
&DestLogicalAddress.NodeNumber,
|
|
copyPoint);
|
|
|
|
copyPoint += 1;
|
|
|
|
startOfOnTheWirePacket = (*portHandlers->BuildHeader)(
|
|
packet->data,
|
|
MAXIMUM_AARPDATASIZE,
|
|
Port,
|
|
TrueDestination,
|
|
RoutingInfo,
|
|
RoutingInfoLength,
|
|
AddressResolution);
|
|
|
|
*packetLength = copyPoint - startOfOnTheWirePacket;
|
|
AdjustBufferDescriptor(packet, packet->data - startOfOnTheWirePacket);
|
|
|
|
return(packet);
|
|
|
|
} // BuildAarpPacket
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AarpForNodeInRange(
|
|
int Port,
|
|
APPLETALK_NETWORKRANGE NetworkRange,
|
|
BOOLEAN ServerNode,
|
|
PEXTENDED_NODENUMBER Node
|
|
)
|
|
{
|
|
UCHAR currentNodeNumber;
|
|
USHORT currentNetworkNumber;
|
|
int firstNodeNumber, lastNodeNumber;
|
|
long netTry;
|
|
int nodeTry;
|
|
USHORT nodeWidth, nodeChange, nodeIndex;
|
|
USHORT netWidth, netChange, netIndex;
|
|
BOOLEAN nodeInUse;
|
|
|
|
// Do as our routine name implies.
|
|
|
|
//
|
|
// Pick the node number range we'll try for (we pay attention to the foolish
|
|
// "ServerNode" concept for LocalTalk).
|
|
//
|
|
|
|
if (GET_PORTDESCRIPTOR(Port)->PortType != LOCALTALK_NETWORK) {
|
|
firstNodeNumber = MINIMUM_USABLEAPPLETALKNODE;
|
|
lastNodeNumber = MAXIMUM_EXTENDEDAPPLETALKNODE;
|
|
} else {
|
|
if (ServerNode) {
|
|
firstNodeNumber = LOWEST_SERVERNODENUMBER;
|
|
lastNodeNumber = MAXIMUM_EXTENDEDAPPLETALKNODE;
|
|
} else {
|
|
firstNodeNumber = MINIMUM_USABLEAPPLETALKNODE;
|
|
lastNodeNumber = HIGHEST_WORKSTATIONNODENUMBER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Okay, now some fun starts. Plow through our options trying to find an
|
|
// unused extended node number.
|
|
//
|
|
|
|
// Compute the width of our network range, and pick a random start point.
|
|
|
|
netWidth = (USHORT)((NetworkRange.LastNetworkNumber + 1) -
|
|
NetworkRange.FirstNetworkNumber);
|
|
netTry = GetRandom(NetworkRange.FirstNetworkNumber,
|
|
NetworkRange.LastNetworkNumber);
|
|
|
|
//
|
|
// Come up with a random decrement, making sure it's odd (to aVOID repeats)
|
|
// and large enough to appear pretty random. I think this algorithm is a
|
|
// little more trouble than its worth, but Microsoft likes it this way.
|
|
//
|
|
|
|
netChange = (USHORT)(GetRandom(1, netWidth) | 1);
|
|
while ((netWidth % netChange == 0) ||
|
|
(!IsPrime((long)netChange))) {
|
|
netChange += 2;
|
|
}
|
|
|
|
//
|
|
// Now walk trough the range decrementing the starting network by the
|
|
// choosen change (with wrap, of course) until we find an address or
|
|
// we've processed every available network in the range.
|
|
//
|
|
|
|
for (netIndex = 0; netIndex < netWidth; netIndex += 1) {
|
|
currentNetworkNumber = (USHORT) netTry;
|
|
|
|
// Compute the width of our node range, and pick a random start point.
|
|
nodeWidth = (USHORT)((lastNodeNumber + 1) - firstNodeNumber);
|
|
nodeTry = (int)GetRandom(firstNodeNumber, lastNodeNumber);
|
|
|
|
//
|
|
// Come up with a random decrement, making sure it's odd (to avoid repeats)
|
|
// and large enough to appear pretty random.
|
|
//
|
|
|
|
nodeChange = (USHORT)(GetRandom(1, nodeWidth) | 1);
|
|
while ((nodeWidth % nodeChange == 0) || !(IsPrime((long)nodeChange)))
|
|
nodeChange += 2;
|
|
|
|
//
|
|
// Now walk trough the range decrementing the starting network by the
|
|
// choosen change (with wrap, of course) until we find an address or
|
|
// we've processed every available node in the range.
|
|
//
|
|
|
|
for (nodeIndex = 0; nodeIndex < nodeWidth; nodeIndex += 1) {
|
|
currentNodeNumber = (UCHAR )nodeTry;
|
|
|
|
// Let AARP have a crack at it.
|
|
if (AarpForNode(Port, currentNetworkNumber, currentNodeNumber))
|
|
break;
|
|
|
|
// Okay, try again, bump down with wrap.
|
|
nodeTry -= nodeChange;
|
|
while (nodeTry < firstNodeNumber)
|
|
nodeTry += nodeWidth;
|
|
|
|
} // Node number loop
|
|
|
|
// BUGBUG: Just reading this value, no critical section??
|
|
if (!GET_PORTDESCRIPTOR(Port)->TentativeNodeHasBeenUsed)
|
|
break;
|
|
|
|
// Okay, try again, bump down with wrap.
|
|
netTry -= netChange;
|
|
while (netTry < (long)NetworkRange.FirstNetworkNumber)
|
|
netTry += netWidth;
|
|
|
|
} // Network number loop
|
|
|
|
// Okay if we found one return all's well, otherwise no luck.
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
nodeInUse = GET_PORTDESCRIPTOR(Port)->TentativeNodeHasBeenUsed;
|
|
if (!nodeInUse) {
|
|
if (node != NULL) {
|
|
*node = GET_PORTDESCRIPTOR(Port)->TentativeAppleTalkNode;
|
|
}
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
return(nodeInUse);
|
|
|
|
} // AarpForNodeInRange
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AarpForNode(
|
|
int Port,
|
|
USHORT NetworkNumber,
|
|
UCHAR NodeNumber
|
|
)
|
|
{
|
|
int probeAttempt;
|
|
PBUFFER_DESC packet;
|
|
PortHandlers portHandlers;
|
|
int packetLength;
|
|
PACTIVE_NODE activeNode;
|
|
|
|
// First make sure we don't own this node.
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
for (activeNode = GET_PORTDESCRIPTOR(Port)->ActiveNodes;
|
|
activeNode != NULL;
|
|
activeNode = activeNode->next) {
|
|
|
|
if (activeNode->extendedNode.NetworkNumber == NetworkNumber &&
|
|
activeNode->extendedNode.NodeNumber == NodeNumber)
|
|
|
|
break;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
if (activeNode) { // Node exists
|
|
return(FALSE);
|
|
}
|
|
|
|
// Use AARP to probe for a particular network/node address.
|
|
portHandlers = &PortSpecificInfo[GET_PORTDESCRIPTOR(Port)->PortType];
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
GET_PORTDESCRIPTOR(Port)->TentativeNodeHasBeenUsed = FALSE;
|
|
GET_PORTDESCRIPTOR(Port)->TentativeAppleTalkNode.NetworkNumber = NetworkNumber;
|
|
GET_PORTDESCRIPTOR(Port)->TentativeAppleTalkNode.NodeNumber = NodeNumber;
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
// Build the packet and blast it out the specified number of times.
|
|
for (probeAttempt = 0;
|
|
probeAttempt < GET_PORTDESCRIPTOR(Port)->AARP_PROBEs;
|
|
probeAttempt += 1) {
|
|
|
|
packet = BUILD_AARPPROBE(
|
|
Port,
|
|
portHandlers->HardwareAddressLength,
|
|
GET_PORTDESCRIPTOR(Port)->TentativeAppleTalkNode,
|
|
&packetLength);
|
|
|
|
if (!(*portHandlers->packetOut)(
|
|
Port,
|
|
packet,
|
|
packetLength,
|
|
NULL,
|
|
0)) {
|
|
|
|
// We allocated the packet.
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_AARPPACKETOUTFAIL,
|
|
__LINE__ | __AARP__,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
packet->data,
|
|
packetLength,
|
|
0,
|
|
NULL);
|
|
|
|
break;
|
|
}
|
|
|
|
WaitFor(
|
|
AARP_PROBETIMERINHUNDRETHS,
|
|
&GET_PORTDESCRIPTOR(Port)->TentativeNodeHasBeenUsed);
|
|
|
|
if (GET_PORTDESCRIPTOR(Port)->TentativeNodeHasBeenUsed)
|
|
break; // Did we get a probe or a response?
|
|
|
|
} // Probe attempts loop
|
|
|
|
// We win if the current tentenative node has not been used!
|
|
return(!GET_PORTDESCRIPTOR(Port)->TentativeNodeHasBeenUsed);
|
|
|
|
} // AarpForNode
|
|
|
|
|
|
|
|
|
|
VOID
|
|
BestRouterAgingTimerExpired(
|
|
ULONG TimerId,
|
|
int AdditionalDataSize,
|
|
PCHAR AdditionalData
|
|
)
|
|
{
|
|
int index, port;
|
|
|
|
// "Use" unused formals.
|
|
UNREFERENCED_PARAMETER(TimerId);
|
|
UNREFERENCED_PARAMETER(AdditionalDataSize);
|
|
UNREFERENCED_PARAMETER(AdditionalData);
|
|
|
|
|
|
// Loop through all of our active ports aging their best-router tables.
|
|
for (port = 0; port < NumberOfPortsAllocated; port += 1) {
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
if (((GET_PORTDESCRIPTOR(port)->Flags & PD_ACTIVE) == 0) ||
|
|
(!GET_PORTDESCRIPTOR(port)->ExtendedNetwork) ||
|
|
(!AtalkReferencePortDescriptor(
|
|
GET_PORTDESCRIPTOR(Port),
|
|
__LINE__ | __AARP__))) {
|
|
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
continue;
|
|
}
|
|
|
|
for (index = 0; index < BESTROUTER_HASHBUCKETS; index += 1) {
|
|
if (!GET_PORTDESCRIPTOR(port)->BestRouterCache[index].Valid)
|
|
continue;
|
|
if (GET_PORTDESCRIPTOR(port)->BestRouterCache[index].AgingCount <
|
|
BESTROUTER_AGINGCHANCES)
|
|
GET_PORTDESCRIPTOR(port)->BestRouterCache[index].AgingCount += 1;
|
|
else
|
|
GET_PORTDESCRIPTOR(port)->BestRouterCache[index].Valid = FALSE;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
AtalkDereferencePortDescriptor(
|
|
GET_PORTDESCRIPTOR(Port),
|
|
__LINE__ | __AARP__);
|
|
}
|
|
|
|
// Restart the timer!
|
|
StartTimer(
|
|
BestRouterAgingTimerExpired,
|
|
BESTROUTER_AGINGSECONDS,
|
|
0,
|
|
NULL);
|
|
|
|
return;
|
|
|
|
} // BestRouterAgingTimerExpired
|
|
|
|
|
|
|
|
|
|
VOID
|
|
TuneRoutingInfo(
|
|
int Port,
|
|
PCHAR RoutingInfo
|
|
)
|
|
{
|
|
//
|
|
// Given an incoming TokenRing routing info, tune it to make it valid
|
|
// for outing routing info. Do this in place! And, remember, you can
|
|
// always tune a routing info, but you can't tune a fish.
|
|
//
|
|
|
|
if (GET_PORTDESCRIPTOR(Port)->PortType != TOKENRING_NETWORK)
|
|
return;
|
|
|
|
// Set to "non-broadcast" and invert "direction".
|
|
|
|
RoutingInfo[0] &= TOKENRING_NONBROADCASTMASK;
|
|
if (RoutingInfo[1] & TOKENRING_DIRECTIONMASK)
|
|
RoutingInfo[1] &= ~TOKENRING_DIRECTIONMASK;
|
|
else
|
|
RoutingInfo[1] |= TOKENRING_DIRECTIONMASK;
|
|
|
|
} // TuneRoutingInfo
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
IsPrime(
|
|
long Step
|
|
)
|
|
{
|
|
// We assume "step" is odd.
|
|
long i, j;
|
|
|
|
// All odds, seven and below, are prime.
|
|
|
|
if (Step <= 7)
|
|
return (TRUE);
|
|
|
|
//
|
|
// Do a little divisibility checking. The "/3" is a reasonably good
|
|
// shot at sqrt() because the smallest odd to come through here will be
|
|
// 9.
|
|
//
|
|
|
|
j = Step/3;
|
|
for (i = 3; i <= j; i++)
|
|
if (Step % i == 0)
|
|
return(FALSE);
|
|
|
|
return(TRUE);
|
|
|
|
} // IsPrime
|
|
|
|
|