Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1642 lines
57 KiB

/* FullZip.c, atalk-ii/router, Garth Conboy, 01/16/90 */
/* Copyright (c) 1989 by Pacer Software Inc., La Jolla, CA */
/* GC - Initial coding.
GC - (08/18/90): New error logging mechanism.
GC - (01/19/92): Fix from newest OS/2 base [DCH/Jameel]. Corrected zone
name overlap checking in GetZoneList processing.
GC - (03/31/92): Updated for BufferDescriptors.
GC - (11/28/92): Locks and reference counts come to town.
GC - (12/05/92): Fixed GetZoneListFor() to correctly acquire the
port's default zone.
GC - (12/06/92): Introduced a zone table for zone storage/management.
GC - (12/10/92): Half port fix from Eric Smith at Telebit.
*** Make the PVCS source control system happy:
$Header$
$Log$
***
ZIP handling for a router.
*/
#define IncludeFullZipErrors 1
#include "atalk.h"
#if (Iam an AppleTalkRouter) and (IamNot an AppleTalkStack)
#include "atpconst.h"
#endif
#if IamNot an AppleTalkRouter
/* Empty file */
#else
ExternForVisibleFunction TimerHandler ZipQueryTimerExpired;
ExternForVisibleFunction Boolean GetZoneListFor(int port);
static Boolean firstCall = True;
Boolean far StartZipProcessingOnPort(int port)
{
/* Switch the incoming ZIP packet handler to be the router version. */
CloseSocketOnNodeIfOpen(port, PortDescriptor(port)->aRouter,
ZonesInformationSocket);
if (OpenSocketOnNode(empty, port, &PortDescriptor(port)->aRouter,
ZonesInformationSocket,
ZipPacketInRouter, (long)0, False, empty, 0,
empty) isnt ATnoError)
{
ErrorLog("StartZipProcessingOnPort", ISevError, __LINE__, port,
IErrFullZipBadSocketOpen, IMsgFullZipBadSocketOpen,
Insert0());
return(False);
}
/* Try to get or set the zone information... */
if (PortDescriptor(port)->portType is NonAppleTalkHalfPort)
{
PortDescriptor(port)->thisZoneValid = False;
PortDescriptor(port)->theseZones = empty;
}
else if (not GetZoneListFor(port))
return(False);
/* Start the zip query timer. */
if (firstCall)
{
StartTimer(ZipQueryTimerExpired, ZipQueryTimerSeconds, 0, empty);
firstCall = False;
}
return(True);
} /* StartZipProcessingOnPort */
void far ShutdownFullZip(void)
{
firstCall = True;
} /* ShutdownFullZip */
long far ZipPacketInRouter(AppleTalkErrorCode errorCode,
long unsigned userData,
int port,
AppleTalkAddress source,
long destinationSocket,
int protocolType,
char far *datagram,
int datagramLength,
AppleTalkAddress actualDestination)
{
StaticForSmallStack char zoneName[MaximumZoneLength + 1];
BufferDescriptor packet;
RoutingTableEntry routingTableEntry;
int commandType;
int zoneCount, currentZoneIndex;
unsigned short networkNumber;
int zoneNameLength, numberOfZonesOnTheNetwork;
Boolean newPacket, packetFull, localZonesOnly;
Boolean extendedZipReply = False, useDefaultZone = False;
int unsentNetworkCount;
int index, outIndex, currentReplyType, nextReplyType;
int totalNetworkCount, networkCount;
int transactionId;
int zipCommand;
int startIndex;
int hashBucket;
Zones zoneList, zone;
UniqueZone uniqueZone, nextUniqueZone;
PortHandlers portHandlers;
/* "Use" unneeded actual parameters. */
destinationSocket, userData;
/* Only play if we've been asked nicely! */
if (errorCode is ATsocketClosed)
return((long)True);
else if (errorCode isnt ATnoError)
{
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipBadIncomingError, IMsgFullZipBadIncomingError,
Insert0());
return((long)True);
}
if (not appleTalkRunning or not PortDescriptor(port)->portActive)
return((long)True);
if (protocolType isnt DdpProtocolZip and
protocolType isnt DdpProtocolAtp)
return((long)True);
/* Okay, process the request. */
DeferTimerChecking();
DeferIncomingPackets();
if (protocolType is DdpProtocolZip)
{
commandType = (unsigned char)datagram[ZipCommandOffset];
if (datagramLength < ZipFirstNetworkOffset)
{
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True); /* All ZIP commands have a command and network count! */
}
networkCount = (unsigned char)datagram[ZipNetworkCountOffset];
/* For a ZIP extended reply the "network count" is really not the
numbers of networks contained in the packet, it's the total number
of zones on the single network that is described by the reply. */
numberOfZonesOnTheNetwork = networkCount;
switch (commandType)
{
case ZipNetInfoReplyCommand:
case ZipNotifyCommand:
/* Don't be tellin us... we're a router! */
break;
case ZipGetNetInfoCommand:
if (not PortDescriptor(port)->extendedNetwork)
{
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
IErrFullZipNonExtended, IMsgFullZipNonExtended,
Insert0());
break;
}
if (PortDescriptor(port)->theseZones is Empty)
break; /* Not fully up yet... */
/* Get the zone name out of the request. */
if (datagramLength < ZipRequestedZoneNameOffset)
{
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
IErrFullZipMissingZoneLen, IMsgFullZipMissingZoneLen,
Insert0());
break;
}
zoneNameLength =
(unsigned char)datagram[ZipRequestedZoneLengthOffset];
if (zoneNameLength > MaximumZoneLength or
datagramLength < ZipRequestedZoneNameOffset + zoneNameLength)
{
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
IErrFullZipBadZone, IMsgFullZipBadZone,
Insert0());
break;
}
MoveMem(zoneName, datagram + ZipRequestedZoneNameOffset,
zoneNameLength);
zoneName[zoneNameLength] = 0;
/* Get a buffer descriptor for our reply. */
if ((packet = NewBufferDescriptor(MaximumDdpDatagramSize)) is Empty)
{
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
Insert0());
break;
}
/* Format a GetNetInfo reply command. */
packet->data[ZipCommandOffset] = ZipNetInfoReplyCommand;
packet->data[ZipFlagsOffset] = 0;
if (ElementsOnList(PortDescriptor(port)->theseZones) is 1)
packet->data[ZipFlagsOffset] |= (unsigned char)ZipOnlyOneZoneFlag;
TakeLock(RoutingLock);
if (zoneNameLength is 0 or
not ZoneInZones(zoneName, PortDescriptor(port)->theseZones))
{
packet->data[ZipFlagsOffset] |= (unsigned char)ZipZoneInvalidFlag;
useDefaultZone = True;
}
/* Add our cable range. */
packet->data[ZipFirstNetworkOffset] =
(char)(PortDescriptor(port)->thisCableRange.firstNetworkNumber
>> 8);
packet->data[ZipFirstNetworkOffset + 1] =
(char)(PortDescriptor(port)->thisCableRange.firstNetworkNumber
& 0xFF);
packet->data[ZipLastNetworkOffset] =
(char)(PortDescriptor(port)->thisCableRange.lastNetworkNumber
>> 8);
packet->data[ZipLastNetworkOffset + 1] =
(char)(PortDescriptor(port)->thisCableRange.lastNetworkNumber
& 0xFF);
/* Echo back the requested zone name. */
packet->data[ZipRequestedZoneLengthOffset] = (char)zoneNameLength;
MoveMem(packet->data + ZipRequestedZoneNameOffset, zoneName,
zoneNameLength);
index = ZipRequestedZoneNameOffset + zoneNameLength;
/* Place in the correct zone multicast address. */
portHandlers = &portSpecificInfo[PortDescriptor(port)->portType];
packet->data[index++] = (char)portHandlers->hardwareAddressLength;
if (useDefaultZone)
MoveMem(packet->data + index,
MulticastAddressForZoneOnPort(port,
PortDescriptor(port)->thisDefaultZone),
portHandlers->hardwareAddressLength);
else
MoveMem(packet->data + index,
MulticastAddressForZoneOnPort(port, zoneName),
portHandlers->hardwareAddressLength);
index += portHandlers->hardwareAddressLength;
/* If we need it, add in the default zone. */
if (useDefaultZone)
{
zoneNameLength = strlen(PortDescriptor(port)->thisDefaultZone);
packet->data[index++] = (char)zoneNameLength;
MoveMem(packet->data + index,
PortDescriptor(port)->thisDefaultZone,
zoneNameLength);
index += zoneNameLength;
}
/* If the request came as a cable-wide broadcast and its source
network is not valid for this port, then we want to respond
to cable-wide broadcast rather than the source. */
if (actualDestination.networkNumber is
CableWideBroadcastNetworkNumber and
actualDestination.nodeNumber is AppleTalkBroadcastNodeNumber and
not IsWithinNetworkRange(source.networkNumber,
&PortDescriptor(port)->thisCableRange)
and
not IsWithinNetworkRange(source.networkNumber,
&startupNetworkRange))
{
source.networkNumber = CableWideBroadcastNetworkNumber;
source.nodeNumber = AppleTalkBroadcastNodeNumber;
}
/* Okay, finally deliver our reply. */
ReleaseLock(RoutingLock);
if (DeliverDdp(destinationSocket, source, DdpProtocolZip, packet,
index, Empty, Empty, 0) isnt ATnoError)
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipBadInfoReplySend, IMsgFullZipBadInfoReplySend,
Insert0());
break;
case ZipQueryCommand:
/* Walk thru the query packet building reply packets that have
as much information as we know. The "+ sizeof(short)" means
that we have complete network number.
When sending replies, we will always send a reply about a
network that has more than one zone as an extended reply.
As were walking the query list, and we encounter a couple of
networks that have only one zone, we'll pack as many of these
as we can into a non-extended reply. */
newPacket = True;
unsentNetworkCount = 0;
/* Allocate an initial buffer descriptor. */
if ((packet = NewBufferDescriptor(MaximumDdpDatagramSize)) is Empty)
{
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
Insert0());
break;
}
for (index = ZipFirstNetworkOffset,
totalNetworkCount = 0;
totalNetworkCount < networkCount and
index + (int)sizeof(short) <= datagramLength;
index += (int)sizeof(short),
totalNetworkCount += 1)
{
/* Grab the next network number from the query packet, if we
don't know about the network, or we don't know the zone
name, continue with the next network number. */
networkNumber = (unsigned short)
(((unsigned char)datagram[index]) << 8);
networkNumber += (unsigned char)datagram[index + 1];
/* Try port descriptors first... we'll get queries from
ourselfs to fill the initial routing table entry's zone
list! */
routingTableEntry = Empty;
if (PortDescriptor(port)->thisCableRange.firstNetworkNumber is
networkNumber and
PortDescriptor(port)->theseZones isnt empty)
zoneList = PortDescriptor(port)->theseZones;
else if ((routingTableEntry =
FindInRoutingTable(networkNumber)) is empty or
routingTableEntry->networkRange.firstNetworkNumber isnt
networkNumber or
not routingTableEntry->zonesValid)
{
UnlinkRoutingTableEntry(routingTableEntry);
continue;
}
else
zoneList = routingTableEntry->zones;
/* What type of reponse does this network want? */
if ((numberOfZonesOnTheNetwork = ElementsOnList(zoneList)) is 0)
{
UnlinkRoutingTableEntry(routingTableEntry);
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipBadZoneList, IMsgFullZipBadZoneList,
Insert0());
continue;
}
else if (numberOfZonesOnTheNetwork is 1)
nextReplyType = ZipReplyCommand;
else
{
/* We start a new packet for each extended network, if we
have a previous one, send it! */
if (unsentNetworkCount > 0)
{
packet->data[ZipCommandOffset] = (char)currentReplyType;
if (currentReplyType is ZipReplyCommand)
packet->data[ZipNetworkCountOffset] =
(char)unsentNetworkCount;
/* Send the packet! */
if (DeliverDdp(destinationSocket, source,
DdpProtocolZip, packet,
outIndex, Empty, Empty, 0) isnt ATnoError)
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipBadReplySend, IMsgFullZipBadReplySend,
Insert0());
if ((packet = NewBufferDescriptor(MaximumDdpDatagramSize))
is Empty)
{
UnlinkRoutingTableEntry(routingTableEntry);
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
unsentNetworkCount = 0;
}
nextReplyType = ZipExtendedReplyCommand;
newPacket = True;
packet->data[ZipNetworkCountOffset] =
(char)numberOfZonesOnTheNetwork;
}
/* Walk the zone list. */
for (zone = zoneList;
zone isnt empty;
zone = zone->next)
{
/* If we're starting to build a new reply packet due to
either:
1. first time through
2. packet full
3. switching reply types
set the index to the first tuple position. */
if (newPacket or
currentReplyType isnt nextReplyType)
{
/* If a previous packet has been built, send it. */
if (unsentNetworkCount > 0)
{
packet->data[ZipCommandOffset] = (char)currentReplyType;
if (currentReplyType is ZipReplyCommand)
packet->data[ZipNetworkCountOffset] =
(char)unsentNetworkCount;
/* Send the packet! */
if (DeliverDdp(destinationSocket, source,
DdpProtocolZip, packet,
outIndex, Empty, Empty, 0) isnt ATnoError)
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipBadReplySend, IMsgFullZipBadReplySend,
Insert0());
if ((packet = NewBufferDescriptor(MaximumDdpDatagramSize))
is Empty)
{
UnlinkRoutingTableEntry(routingTableEntry);
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
unsentNetworkCount = 0;
}
outIndex = ZipFirstNetworkOffset;
currentReplyType = nextReplyType;
newPacket = False;
}
/* Unfortunately, we seem to know the answer to the question.
Pack a new network/zone tuple into the reply packet. */
packet->data[outIndex++] = (char)((networkNumber >> 8) & 0xFF);
packet->data[outIndex++] = (char)(networkNumber & 0xFF);
packet->data[outIndex++] = (char)(zoneNameLength =
strlen(zone->zone->zone));
MoveMem(packet->data + outIndex, zone->zone->zone,
zoneNameLength);
outIndex += zoneNameLength;
unsentNetworkCount += 1;
/* If we can't hold another big tuple, signal that we should
send on the next pass. */
if (outIndex + sizeof(short) + sizeof(char) +
MaximumZoneLength >= MaximumDdpDatagramSize)
newPacket = True;
} /* Walk zone list. */
UnlinkRoutingTableEntry(routingTableEntry);
} /* Walk through each network in the query packet. */
/* If we have unsent networks left over, send them out! */
if (unsentNetworkCount > 0)
{
packet->data[ZipCommandOffset] = (char)currentReplyType;
if (currentReplyType is ZipReplyCommand)
packet->data[ZipNetworkCountOffset] =
(char)unsentNetworkCount;
/* Send the packet! */
if (DeliverDdp(destinationSocket, source,
DdpProtocolZip, packet,
outIndex, Empty, Empty, 0) isnt ATnoError)
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipBadReplySend, IMsgFullZipBadReplySend,
Insert0());
unsentNetworkCount = 0;
}
else
FreeBufferChain(packet); /* Free unused buffer chain. */
break;
case ZipExtendedReplyCommand:
extendedZipReply = True;
/* And fall through... */
case ZipReplyCommand:
/* Walk through the reply packet (assuming we asked for the
contained information). Yes, we're still using "networkCount"
when processing an extended reply, but that's okay because it
will certainly be at least the number of zones contained in
this packet. The "+ 3" garuntees that we really have network
number and zone length! */
for (index = ZipFirstNetworkOffset,
totalNetworkCount = 0;
totalNetworkCount < networkCount and
index + 3 <= datagramLength;
totalNetworkCount += 1)
{
/* Get the next network number, if it's not in our routing
table (or not the start of a range), then we certainly
don't care about its zone name. */
networkNumber = (unsigned short)
(((unsigned char)(datagram[index++])) << 8);
networkNumber += (unsigned char)(datagram[index++]);
zoneNameLength = (unsigned char)(datagram[index++]);
routingTableEntry = FindInRoutingTable(networkNumber);
if (routingTableEntry is empty or
routingTableEntry->networkRange.firstNetworkNumber isnt
networkNumber)
{
UnlinkRoutingTableEntry(routingTableEntry);
index += zoneNameLength;
continue;
}
/* Okay validate the zone name. */
if (zoneNameLength is 0 or
zoneNameLength > MaximumZoneLength)
{
UnlinkRoutingTableEntry(routingTableEntry);
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
IErrFullZipBadReplyPacket, IMsgFullZipBadReplyPacket,
Insert0());
break; /* Oops, corrupted packet! */
}
if (index + zoneNameLength > datagramLength)
{
UnlinkRoutingTableEntry(routingTableEntry);
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
IErrFullZipBadZone, IMsgFullZipBadZone,
Insert0());
break; /* Oops, corrupted packet! */
}
/* Conditionally, move the zone name into our routing table. */
MoveMem(zoneName, datagram + index, zoneNameLength);
index += zoneNameLength;
zoneName[zoneNameLength] = 0;
TakeLock(RoutingLock);
if (ZoneInZones(zoneName, routingTableEntry->zones))
{
UnlinkRoutingTableEntry(routingTableEntry);
continue;
}
/* Check for the obscure case of somebody out there trying to
add another zone to one of our directly connected networks
that is non-extended and we already know its zone. */
if (routingTableEntry->numberOfHops is 0 and
not PortDescriptor(routingTableEntry->port)->
extendedNetwork and
ElementsOnList(routingTableEntry->zones) is 1)
{
ReleaseLock(RoutingLock);
UnlinkRoutingTableEntry(routingTableEntry);
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
IErrFullZipTooManyZones, IMsgFullZipTooManyZones,
Insert0());
continue;
}
/* Okay, add to list. */
if ((routingTableEntry->zones =
AddZoneToZones(routingTableEntry->zones, zoneName))
is Empty)
{
ReleaseLock(RoutingLock);
UnlinkRoutingTableEntry(routingTableEntry);
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipCantAddZone, IMsgFullZipCantAddZone,
Insert0());
routingTableEntry->zonesValid = False;
continue;
}
ReleaseLock(RoutingLock);
/* If we're not an extended reply, we know that we have all of
the information about a given network contained in this
packet, so we can go ahead and mark the zone list valid
now. */
if (not extendedZipReply)
routingTableEntry->zonesValid = True;
/* Okay, if we just handled an extended reply, do we now know all
that we should know about the specfied network? */
if (extendedZipReply and
ElementsOnList(routingTableEntry->zones) >=
numberOfZonesOnTheNetwork)
routingTableEntry->zonesValid = True;
UnlinkRoutingTableEntry(routingTableEntry);
}
break;
default:
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
IErrFullZipFunnyCommand, IMsgFullZipFunnyCommand,
Insert0());
break;
}
}
else
{
/* An ATP/ZIP request! */
/* This had better be a GetZoneList, a GetLocalZones, or a GetMyZone
ATP request! */
if ((datagram[AtpCommandControlOffset] & AtpFunctionCodeMask) isnt
AtpRequestFunctionCode)
{
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True); /* Why are they talking to us??? */
}
if (datagram[AtpBitmapOffset] isnt 1)
{
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
IErrFullZipLongReplyExpected, IMsgFullZipLongReplyExpected,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True); /* More that one reply packet isnt an option! */
}
transactionId = ((unsigned char)datagram[AtpTransactionIdOffset]) << 8;
transactionId += (unsigned char)datagram[AtpTransactionIdOffset + 1];
/* Make sure it's one of the three requests that we know how to deal
with. */
zipCommand = (unsigned char)datagram[AtpZipCommandOffset] & 0xFF;
if (zipCommand isnt ZipGetZoneListCommand and
zipCommand isnt ZipGetLocalZonesCommand and
zipCommand isnt ZipGetMyZoneCommand)
{
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
IErrFullZipFunnyRequest, IMsgFullZipFunnyRequest,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
/* Get start index... only meaningfull for GetZoneList and
GetLocalZones requests. */
startIndex = ((unsigned char)datagram[AtpZipStartIndexOffset] << 8);
startIndex += (unsigned char)datagram[AtpZipStartIndexOffset + 1];
/* Allocate a buffer descriptor for the reply. */
if ((packet = NewBufferDescriptor(MaximumDdpDatagramSize)) is Empty)
{
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
/* Okay, build the static part of an ATP reply packet. */
packet->data[AtpCommandControlOffset] =
(unsigned char)(AtpResponseFunctionCode + AtpEndOfMessageMask);
packet->data[AtpSequenceNumberOffset] = 0;
packet->data[AtpTransactionIdOffset] = (char)((transactionId >> 8) & 0xFF);
packet->data[AtpTransactionIdOffset + 1] = (char)(transactionId & 0xFF);
/* Handle GetMyZone: */
if (zipCommand is ZipGetMyZoneCommand)
{
/* We really shouldn't be getting this request on an extended network,
but go ahead and reply with the "default zone" in this case, of
course, reply with "this zone" for non-extended nets. We are a
router, so "thisZone" will always be valid -- as will the default
zone for extended nets and as will "this zone" for non-extended. */
packet->data[AtpZipLastFlagOffset] = 0;
packet->data[AtpZipLastFlagOffset + 1] = 0;
packet->data[AtpZipStartIndexOffset] = 0;
packet->data[AtpZipStartIndexOffset + 1] = 1;
TakeLock(RoutingLock);
if (PortDescriptor(port)->extendedNetwork)
{
zoneNameLength = strlen(PortDescriptor(port)->thisDefaultZone);
packet->data[AtpDataOffset] = (char)zoneNameLength;
MoveMem(packet->data + AtpDataOffset + 1,
PortDescriptor(port)->thisDefaultZone, zoneNameLength);
}
else
{
zoneNameLength = strlen(PortDescriptor(port)->thisZone);
packet->data[AtpDataOffset] = (char)zoneNameLength;
MoveMem(packet->data + AtpDataOffset + 1,
PortDescriptor(port)->thisZone, zoneNameLength);
}
ReleaseLock(RoutingLock);
/* Blast the reply out! */
if (DeliverDdp(destinationSocket, source, DdpProtocolAtp,
packet, AtpDataOffset + 1 + zoneNameLength,
Empty, Empty, 0)
isnt ATnoError)
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipBadMyZoneSend, IMsgFullZipBadMyZoneSend,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
/* Okay, A little harder here, fill the GetZoneList or GetLocalZones
reply packet full of as many zomes as it'll hold; starting at the
requested start index. */
localZonesOnly = (zipCommand is ZipGetLocalZonesCommand);
/* Walk the zones table. */
index = AtpDataOffset;
packetFull = False;
for (hashBucket = 0, zoneCount = 0, currentZoneIndex = 0;
hashBucket < ZoneTableHashBuckets and not packetFull;
hashBucket += 1)
{
TakeLock(RoutingLock);
uniqueZone = Link(zoneTable[hashBucket]);
ReleaseLock(RoutingLock);
while(uniqueZone isnt Empty and not packetFull)
{
while (True) /* Something to break out of. */
{
TakeLock(RoutingLock);
if (localZonesOnly and
not ZoneInZones(uniqueZone->zone,
PortDescriptor(port)->theseZones))
{
ReleaseLock(RoutingLock);
break;
}
ReleaseLock(RoutingLock);
/* Are we at the point that the requester wants us to start from
yet? */
currentZoneIndex += 1;
if (currentZoneIndex < startIndex)
break;
/* Place a zone name in the packet. */
zoneNameLength = strlen(uniqueZone->zone);
packet->data[index++] = (char)zoneNameLength;
MoveMem(packet->data + index, uniqueZone->zone, zoneNameLength);
index += zoneNameLength;
zoneCount += 1;
/* Can this packet hold another of the longest zone? */
if (index + sizeof(char) + MaximumZoneLength >=
MaximumDdpDatagramSize)
packetFull = True;
break;
}
/* Move to next unique zone. */
TakeLock(RoutingLock);
nextUniqueZone = Link(uniqueZone->next);
ReleaseLock(RoutingLock);
UnlinkZone(uniqueZone);
uniqueZone = nextUniqueZone;
}
}
UnlinkZone(uniqueZone); /* Maybe Empty, maybe not. */
/* Okay, we've built a packet, fill in the number of zones field,
and the Last flag. */
packet->data[AtpZipLastFlagOffset] =
(char)(hashBucket >= ZoneTableHashBuckets and
uniqueZone is Empty);
packet->data[AtpZipLastFlagOffset + 1] = 0;
packet->data[AtpZipZoneCountOffset] =
(char)((zoneCount >> 8) & 0xFF);
packet->data[AtpZipZoneCountOffset + 1] =
(char)(zoneCount & 0xFF);
/* Send out the packet. */
if (DeliverDdp(destinationSocket, source, DdpProtocolAtp,
packet, index, Empty, Empty, 0) isnt ATnoError)
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
IErrFullZipBadZoneListSend, IMsgFullZipBadZoneListSend,
Insert0());
} /* ZIP/ATP request */
/* All set. */
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
} /* ZipPacketInRouter */
/* *************************************************************************
LinkZone
Given a zone name string, enter it into the zones table, if it's not already
there. Return the UniqueZone after incrementing the reference count.
This rotuine should be called with the RoutingLock already held by the
caller.
Returns: UniqueZone
************************************************************************* */
UniqueZone far LinkZone(char far *zone)
{
short hash = HashString(zone);
int index;
UniqueZone uniqueZone;
static long uniqueId = 1;
/* Is our zone already home? */
CheckMod(index, hash, ZoneTableHashBuckets, "LinkZone");
for (uniqueZone = zoneTable[index];
uniqueZone isnt Empty;
uniqueZone = uniqueZone->next)
if (uniqueZone->zoneHash is hash and
CompareCaseInsensitive(uniqueZone->zone, zone))
break;
if (uniqueZone isnt Empty)
{
/* We're all set, the zone is already in the table. */
return(Link(uniqueZone));
}
/* Okay, we need to build a new unique zone. */
if ((uniqueZone = Calloc(sizeof(*uniqueZone) + strlen(zone) + 1, 1)) is Empty)
{
ErrorLog("LinkZone", ISevError, __LINE__, UnknownPort,
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
Insert0());
return(Empty);
}
/* Okay, build and link the new kid on the block. */
uniqueZone->uniqueId = uniqueId++;
uniqueZone->zoneHash = hash;
strcpy(uniqueZone->zone, zone);
uniqueZone->next = zoneTable[index];
zoneTable[index] = uniqueZone;
return(Link(uniqueZone));
} /* LinkZone */
/* *************************************************************************
UnlinkZone
Given a UniqueZone, decrease it's reference count. If we're the last
referant, remove him from the zones table.
Returns: void
************************************************************************* */
void far UnlinkZone(UniqueZone zone)
{
short hash;
int index;
/* Undo one link, if we're not the last, return. */
if (zone is Empty)
return;
hash = HashString(zone->zone);
CheckMod(index, hash, ZoneTableHashBuckets, "LinkZone");
TakeLock(RoutingLock);
if (not UnlinkNoFree(zone))
{
ReleaseLock(RoutingLock);
return;
}
/* Okay, we're the last, free him. */
if (not RemoveFromListNoUnlink(zoneTable[index], zone, next))
{
ReleaseLock(RoutingLock);
ErrorLog("UnlinkZone", ISevError, __LINE__, UnknownPort,
IErrFullZipZoneMissing, IMsgFullZipZoneMissing,
Insert0());
return;
}
ReleaseLock(RoutingLock);
Free(zone);
return;
} /* UnlinkZone */
/* *************************************************************************
ZoneInZones
Search a Zones list for a given zone. The routine should be called with
the caller holding the RoutingLock.
Returns: Boolean; True if zone on list.
************************************************************************* */
Boolean far ZoneInZones(char far *zone, Zones zones)
{
short hash = HashString(zone);
/* Anybody home? */
while (zones isnt Empty)
{
if (zones->zone->zoneHash is hash and
CompareCaseInsensitive(zones->zone->zone, zone))
return(True);
zones = zones->next;
}
return(False);
} /* ZoneInZones */
/* *************************************************************************
AddZoneToZones
Add a new zone to a Zones list. This routine should be called with the
caller holding the RoutingLock.
Returns: Zones; the new zones list.
************************************************************************* */
Zones far AddZoneToZones(Zones zones, char far *zone)
{
Zones newZones;
if ((newZones = Calloc(sizeof(*newZones), 1)) is Empty)
{
ErrorLog("AddZoneToZones", ISevError, __LINE__, UnknownPort,
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
Insert0());
return(Empty);
}
if ((newZones->zone = LinkZone(zone)) is Empty)
{
Free(newZones);
return(Empty);
}
newZones->next = zones;
return(newZones);
} /* AddZoneToZones */
/* *************************************************************************
FreeZones
Free a Zones list.
Returns: void
************************************************************************* */
void far FreeZones(Zones zones)
{
Zones nextZones;
while (zones isnt Empty)
{
nextZones = zones->next;
UnlinkZone(zones->zone);
Free(zones);
zones = nextZones;
}
} /* FreeZones */
/* *************************************************************************
ZoneListToZones
Take a ZoneList and convert it to a Zones list.
Returns: Zones; the new zones list.
************************************************************************* */
Zones far ZoneListToZones(ZoneList zoneList)
{
Zones zones = Empty, newZones;
while (zoneList isnt Empty)
{
TakeLock(RoutingLock);
if ((newZones = AddZoneToZones(zones, zoneList->zone)) is Empty)
{
ReleaseLock(RoutingLock);
FreeZones(zones);
return(Empty);
}
ReleaseLock(RoutingLock);
zones = newZones;
zoneList = zoneList->next;
}
return(zones);
} /* ZoneListToZones */
/* *************************************************************************
CopyZones
Produce a copy of a Zones list. We assume the thing were copying from
won't be freed out from under us (the list is hanging off a Linked
RoutingTableEntry).
Returns: Zones; the new zones list.
************************************************************************* */
Zones far CopyZones(Zones zones)
{
Zones newZones, newZone, newZonesHead = Empty;
while (zones isnt Empty)
{
if ((newZone = Calloc(sizeof(*newZones), 1)) is Empty)
{
ErrorLog("CopyZones", ISevError, __LINE__, UnknownPort,
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
Insert0());
FreeZones(newZonesHead);
return(Empty);
}
TakeLock(RoutingLock);
if (newZonesHead is Empty)
{
newZonesHead = newZones;
newZones = newZone;
}
else
{
newZones->next = newZone;
newZones = newZone;
}
newZones->zone = Link(zones->zone);
zones = zones->next;
ReleaseLock(RoutingLock);
}
return(newZonesHead);
} /* CopyZones */
ExternForVisibleFunction void far ZipQueryTimerExpired(long unsigned timerId,
int additionalDataSize,
char far *additionalData)
{
RoutingTableEntry routingTableEntry, nextRoutingTableEntry;
BufferDescriptor datagram;
int hashBucket;
AppleTalkAddress source, destination;
long sourceSocket;
int port;
/* "Use" unneeded actual parameters. */
timerId, additionalDataSize, additionalData;
/* We're going to muck with the routing databases, so defer incoming
packets while we do the deed. */
DeferIncomingPackets();
/* We want to iterate through the routing table and send out a query to any
network that we don't know the zone name of. */
/* Walk through the routing table looking for networks that we don't know
the zone of... */
for (hashBucket = 0;
hashBucket < NumberOfRtmpHashBuckets;
hashBucket += 1)
{
TakeLock(RoutingLock);
routingTableEntry = Link(routingTable[hashBucket]);
ReleaseLock(RoutingLock);
while (routingTableEntry isnt empty)
{
while(True) /* Just something to "break" out of. */
{
/* If we already know the zone for this network, skip it. */
if (routingTableEntry->zonesValid)
break;
/* Get a buffer descriptor for our query. */
if ((datagram = NewBufferDescriptor(ZipOneZoneQueryDdpSize)) is Empty)
{
ErrorLog("ZipQueryTimerExpired", ISevError, __LINE__, UnknownPort,
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
Insert0());
break;
}
/* Build the static part of the query packet. */
datagram->data[ZipCommandOffset] = ZipQueryCommand;
datagram->data[ZipNetworkCountOffset] = 1;
/* Place the network number in question into the query packet. */
datagram->data[ZipFirstNetworkOffset] =
(char)((routingTableEntry->networkRange.firstNetworkNumber
>> 8) & 0xFF);
datagram->data[ZipFirstNetworkOffset + 1] =
(char)(routingTableEntry->networkRange.firstNetworkNumber & 0xFF);
/* Compute the source and destination for this request. */
source.networkNumber =
PortDescriptor(routingTableEntry->port)->aRouter.networkNumber;
source.nodeNumber =
PortDescriptor(routingTableEntry->port)->aRouter.nodeNumber;
port = routingTableEntry->port;
if (PortDescriptor(port)->portType is NonAppleTalkHalfPort and
source.networkNumber is UnknownNetworkNumber)
{
/* If we're sending out a half port, pick a more reasonable
source, so that the reply will get delivered to the router
and correctly entered into the routing tables. */
for (port = 0; port < MaximumNumberOfPorts; port += 1)
if (PortDescriptor(port)->portActive and
PortDescriptor(port)->routerRunning)
{
source.networkNumber =
PortDescriptor(port)->aRouter.networkNumber;
source.nodeNumber =
PortDescriptor(port)->aRouter.nodeNumber;
break;
}
if (port > MaximumNumberOfPorts)
port = routingTableEntry->port;
}
source.socketNumber = ZonesInformationSocket;
if (routingTableEntry->numberOfHops is 0)
{
/* Yes, this is talking to ourselves, but that's an option for
filling up initial routing tables entries. */
destination.networkNumber =
PortDescriptor(routingTableEntry->port)->aRouter.networkNumber;
destination.nodeNumber =
PortDescriptor(routingTableEntry->port)->aRouter.nodeNumber;
}
else
{
destination.networkNumber =
routingTableEntry->nextRouter.networkNumber;
destination.nodeNumber =
routingTableEntry->nextRouter.nodeNumber;
}
destination.socketNumber = ZonesInformationSocket;
if ((sourceSocket = MapAddressToSocket(port, source)) < ATnoError)
{
ErrorLog("ZipQueryTimerExpired", ISevError, __LINE__,
routingTableEntry->port,
IErrFullZipSocketNotOpen, IMsgFullZipSocketNotOpen,
Insert0());
FreeBufferChain(datagram);
break;
}
/* Send the packet! */
if (DeliverDdp(sourceSocket, destination, DdpProtocolZip,
datagram, ZipOneZoneQueryDdpSize, Empty,
Empty, 0) isnt ATnoError)
ErrorLog("ZipQueryTimerExpired", ISevError, __LINE__,
routingTableEntry->port,
IErrFullZipBadQuerySend, IMsgFullZipBadQuerySend,
Insert0());
break;
}
/* On to next routing table entry. */
TakeLock(RoutingLock);
nextRoutingTableEntry = Link(routingTableEntry->next);
ReleaseLock(RoutingLock);
UnlinkRoutingTableEntry(routingTableEntry);
routingTableEntry = nextRoutingTableEntry;
} /* Loop through the routing table... */
} /* Loop through all hash buckets. */
/* Re-arm ZIP query timer... */
StartTimer(ZipQueryTimerExpired, ZipQueryTimerSeconds, 0, empty);
/* We've done the deed... */
HandleIncomingPackets();
HandleDeferredTimerChecks();
return;
} /* ZipQueryTimerExpired */
ExternForVisibleFunction Boolean GetZoneListFor(int port)
{
/* Similar to RTMP finding out the network number attached to port, our
task is to find out the zone list of the network attached to a
particular port. We too don't want to mess up a working AppleTalk
internet. So, spend a little while doing zone queries to see if the
network already has a zone list -- if we find one, use it; else, we
had better be a seed router. */
BufferDescriptor datagram;
int numberOfRequests = 0;
RoutingTableEntry routingTableEntry;
AppleTalkAddress source, destination;
PortHandlers portHandlers;
char far *multicastAddress;
/* Set source and destination. */
source.networkNumber = PortDescriptor(port)->aRouter.networkNumber;
source.nodeNumber = PortDescriptor(port)->aRouter.nodeNumber;
source.socketNumber = ZonesInformationSocket;
destination.networkNumber = CableWideBroadcastNetworkNumber;
destination.nodeNumber = AppleTalkBroadcastNodeNumber;
destination.socketNumber = ZonesInformationSocket;
if ((routingTableEntry =
FindInRoutingTable(PortDescriptor(port)->thisCableRange.
firstNetworkNumber)) is empty)
{
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipRoutingTablesBad, IMsgFullZipRoutingTablesBad,
Insert0());
return(False);
}
/* Okay, blast a few of these guys out to see if any other bridge on the
network knows our zone name. */
while (not routingTableEntry->zonesValid and
numberOfRequests < NumberOfZipQueries)
{
/* Get a buffer descriptor for the query. */
if ((datagram = NewBufferDescriptor(ZipOneZoneQueryDdpSize)) is Empty)
{
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
Insert0());
UnlinkRoutingTableEntry(routingTableEntry);
return(False);
}
/* Build a ZipQuery packet... */
datagram->data[ZipCommandOffset] = ZipQueryCommand;
datagram->data[ZipNetworkCountOffset] = 1;
TakeLock(RoutingLock);
datagram->data[ZipFirstNetworkOffset] =
(char)((PortDescriptor(port)->thisCableRange.firstNetworkNumber
>> 8) & 0xFF);
datagram->data[ZipFirstNetworkOffset + 1] =
(char)(PortDescriptor(port)->thisCableRange.firstNetworkNumber &
0xFF);
ReleaseLock(RoutingLock);
if (not TransmitDdp(port, source, destination, DdpProtocolZip,
datagram, ZipOneZoneQueryDdpSize,
0, Empty, Empty, Empty, 0))
{
UnlinkRoutingTableEntry(routingTableEntry);
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipBadQuerySend, IMsgFullZipBadQuerySend,
Insert0());
return(False);
}
numberOfRequests += 1;
WaitFor(ZipQueryTimerInHundreths, &routingTableEntry->zonesValid);
}
/* If we got an answer, we're set... but, we're going to need to play
with the routing tables... */
DeferTimerChecking();
DeferIncomingPackets();
if (routingTableEntry->zonesValid)
{
/* The valid zone list is now in the routing table... move it to the
port descriptor. */
if ((PortDescriptor(port)->theseZones =
CopyZones(routingTableEntry->zones)) is empty)
{
UnlinkRoutingTableEntry(routingTableEntry);
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipCouldNotCopy, IMsgFullZipCouldNotCopy,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(False);
}
UnlinkRoutingTableEntry(routingTableEntry);
HandleIncomingPackets();
HandleDeferredTimerChecks();
/* If we are an extended network, we should already have "thisZone" set
(due to GetNetInfo's when we allocated this node), if not, try it
again. Also, find out the true default zone. */
if (PortDescriptor(port)->extendedNetwork)
{
AppleTalkAddress address;
long socket;
/* The router's Zip packet handler doesn't want to be told about
zones (it thinks it knows), so it ignores NetInfoReplies, so
for these GetNetworkInfoForNodes, swich back to the non-router
Zip handler. */
address.networkNumber = PortDescriptor(port)->aRouter.networkNumber;
address.nodeNumber = PortDescriptor(port)->aRouter.nodeNumber;
address.socketNumber = ZonesInformationSocket;
if ((socket = MapAddressToSocket(port, address)) < 0 or
NewHandlerForSocket(socket, ZipPacketIn, (long)0,
False) isnt ATnoError)
{
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipBadSocketOpen, IMsgFullZipBadSocketOpen,
Insert0());
return(False);
}
/* Now fetch the "thisZone" (if needed) and "defaultZone." */
if (not PortDescriptor(port)->thisZoneValid and
not GetNetworkInfoForNode(port, PortDescriptor(port)->aRouter,
False))
{
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipNoThisZone, IMsgFullZipNoThisZone,
Insert0());
return(False);
}
if (not GetNetworkInfoForNode(port, PortDescriptor(port)->aRouter,
True))
{
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipNoThisZone, IMsgFullZipNoThisZone,
Insert0());
return(False);
}
/* Okay, now switch back to the router's Zip handler. */
if (NewHandlerForSocket(socket, ZipPacketInRouter, (long)0,
False) isnt ATnoError)
{
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipBadSocketOpen, IMsgFullZipBadSocketOpen,
Insert0());
return(False);
}
/* The default zone had better be on the zone list we've just
received. */
TakeLock(RoutingLock);
if (not ZoneInZones(PortDescriptor(port)->thisDefaultZone,
PortDescriptor(port)->theseZones) or
not ZoneInZones(PortDescriptor(port)->thisZone,
PortDescriptor(port)->theseZones))
{
ReleaseLock(RoutingLock);
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipBadThisZone, IMsgFullZipBadThisZone,
Insert0());
return(False);
}
ReleaseLock(RoutingLock);
/* Okay, we're all set. */
return(True);
}
/* On a non-extended network, the one entry on the zone list should
also be "this zone". */
TakeLock(RoutingLock);
if (PortDescriptor(port)->theseZones isnt Empty)
{
strcpy(PortDescriptor(port)->thisZone,
PortDescriptor(port)->theseZones->zone->zone);
PortDescriptor(port)->thisZoneValid = True;
}
ReleaseLock(RoutingLock);
return(True);
}
UnlinkRoutingTableEntry(routingTableEntry);
HandleIncomingPackets();
HandleDeferredTimerChecks();
/* Okay, we didn't get an answer, we had better be able to seed. There is
a vauge chance that we got "this zone" set when allocating our node
and whatever router told us that went down before we could ask for the
zone list -- so, deallocate the multicast address, if any first. */
portHandlers = &portSpecificInfo[PortDescriptor(port)->portType];
if (PortDescriptor(port)->extendedNetwork and
PortDescriptor(port)->thisZoneValid)
if (not FixedCompareCaseSensitive(PortDescriptor(port)->
zoneMulticastAddress,
portHandlers->hardwareAddressLength,
portHandlers->broadcastAddress,
portHandlers->hardwareAddressLength))
(*portHandlers->removeMulticastAddress)(port, 1,
PortDescriptor(port)->
zoneMulticastAddress);
/* Okay, now we had better know enough to seed! */
if (PortDescriptor(port)->initialZoneList is empty)
{
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipNeedSeedInfo, IMsgFullZipNeedSeedInfo,
Insert0());
return(False);
}
if ((PortDescriptor(port)->theseZones =
ZoneListToZones(PortDescriptor(port)->initialZoneList)) is empty)
{
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
IErrFullZipCouldNotCopy, IMsgFullZipCouldNotCopy,
Insert0());
return(False);
}
if (PortDescriptor(port)->extendedNetwork)
{
/* Here we need to seed the default zone too. */
strcpy(PortDescriptor(port)->thisDefaultZone,
PortDescriptor(port)->initialDefaultZone);
PortDescriptor(port)->thisDefaultZoneValid = True;
if (PortDescriptor(port)->initialDesiredZone[0] isnt 0)
strcpy(PortDescriptor(port)->thisZone,
PortDescriptor(port)->initialDesiredZone);
else
strcpy(PortDescriptor(port)->thisZone,
PortDescriptor(port)->initialDefaultZone);
PortDescriptor(port)->thisZoneValid = True;
/* We should now set up the zone multicast address too... */
if ((multicastAddress =
MulticastAddressForZoneOnPort(port, PortDescriptor(port)->thisZone))
is empty)
return(False);
if (not FixedCompareCaseSensitive(multicastAddress,
portHandlers->hardwareAddressLength,
portHandlers->broadcastAddress,
portHandlers->hardwareAddressLength))
(*portHandlers->addMulticastAddress)(port, 1, multicastAddress);
MoveMem(PortDescriptor(port)->zoneMulticastAddress, multicastAddress,
portHandlers->hardwareAddressLength);
}
else
{
/* On non-extended networks, this zone should be the only one on the
zone list. */
TakeLock(RoutingLock);
if (PortDescriptor(port)->theseZones isnt Empty)
{
strcpy(PortDescriptor(port)->thisZone,
PortDescriptor(port)->theseZones->zone->zone);
PortDescriptor(port)->thisZoneValid = True;
}
ReleaseLock(RoutingLock);
}
/* All set! */
return(True);
} /* GetZoneListFor */
char far * far MulticastAddressForZoneOnPort(int port,
char far *zone)
{
short unsigned checksum;
StaticForSmallStack char upcasedZone[MaximumZoneLength + 1];
int index;
static struct buffDesc descriptor;
/* Upcase and checksum the passed zone name. */
for (index = 0; zone[index] isnt 0; index += 1)
if (islower(zone[index]))
upcasedZone[index] = (char)(toupper(zone[index]));
else
upcasedZone[index] = zone[index];
descriptor.outBoardDataValid = True;
descriptor.outBoardBuffer = upcasedZone;
descriptor.outBoardData = upcasedZone;
descriptor.outBoardAllocatedSize = index;
descriptor.outBoardSize = index;
checksum = DdpChecksumBufferChain(&descriptor, index, (long)0);
/* Caclulate the the zone multicast address based on the port type. */
switch (PortDescriptor(port)->portType)
{
case EthernetNetwork:
case FddiNetwork:
return(ethernetZoneMutlicastAddrs[checksum %
NumberOfEnetZoneMulticastAddrs]);
case TokenRingNetwork:
return(tokenRingZoneMutlicastAddrs[checksum %
NumberOfTRingZoneMulticastAddrs]);
default:
ErrorLog("MulticastAddressForZoneOnPort", ISevError, __LINE__, port,
IErrFullZipBadPortType, IMsgFullZipBadPortType,
Insert0());
return(empty);
}
} /* MulticastAddressForZoneOnPort */
#if Iam a Primos
void DumpZoneTable(void)
{
int index;
UniqueZone uniqueZone;
printf("\n*** Start ZoneTable dump ***\n");
for (index = 0; index < ZoneTableHashBuckets; index += 1)
{
if (zoneTable[index] is Empty)
continue;
printf("zoneTable[%d] =\n", index);
for (uniqueZone = zoneTable[index];
uniqueZone isnt Empty;
uniqueZone = uniqueZone->next)
printf(" Zone = \"%s\"; ref = %d; hash = %d; Uid = %d.\n",
uniqueZone->zone, uniqueZone->refCount, uniqueZone->zoneHash,
uniqueZone->uniqueId);
}
printf("*** End ZoneTable dump ***\n");
} /* DumpZoneTable */
#endif
#endif