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.
1295 lines
39 KiB
1295 lines
39 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fullzip.c
|
|
|
|
Abstract:
|
|
|
|
ZIP handling for a router.
|
|
|
|
Author:
|
|
|
|
Garth Conboy initial coding
|
|
Nikhil Kamkolkar recoding/mpsafe
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "atalk.h"
|
|
|
|
#if (Iam an AppleTalkRouter) and (IamNot an AppleTalkStack)
|
|
#include "atpconst.h"
|
|
#endif
|
|
|
|
#if IamNot an AppleTalkRouter
|
|
// Empty file
|
|
#else
|
|
|
|
LOCAL
|
|
TimerHandler ZipQueryTimerExpired;
|
|
|
|
LOCAL
|
|
BOOLEAN GetZoneListFor(int port);
|
|
|
|
|
|
static BOOLEAN firstCall = TRUE;
|
|
|
|
|
|
BOOLEAN
|
|
StartZipProcessingOnPort(
|
|
int port
|
|
)
|
|
{
|
|
// Switch the incoming ZIP packet handler to be the router version.
|
|
CloseSocketOnNodeIfOpen(port, portDescriptors[port].aRouter,
|
|
ZONESINFORMATION_SOCKET);
|
|
if (OpenSocketOnNode(empty, port, &portDescriptors[port].aRouter,
|
|
ZONESINFORMATION_SOCKET,
|
|
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 (portDescriptors[port].portType is NONAPPLETALK_HALFPORT) {
|
|
portDescriptors[port].thisZoneValid = FALSE;
|
|
portDescriptors[port].thisZoneList = empty;
|
|
}
|
|
else if (not GetZoneListFor(port))
|
|
return(FALSE);
|
|
|
|
// Start the zip query timer.
|
|
|
|
if (firstCall) {
|
|
StartTimer(ZipQueryTimerExpired, ZIP_QUERYTIMERSECONDS, 0, empty);
|
|
firstCall = FALSE;
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
} // StartZipProcessingOnPort
|
|
|
|
|
|
|
|
|
|
void
|
|
ShutdownFullZip(
|
|
void
|
|
)
|
|
{
|
|
|
|
firstCall = TRUE;
|
|
|
|
} // ShutdownFullZip
|
|
|
|
|
|
|
|
|
|
long
|
|
ZipPacketInRouter(
|
|
APPLETALK_ERROR errorCode,
|
|
long unsigned userData,
|
|
int port,
|
|
APPLETALK_ADDRESS source,
|
|
long destinationSocket,
|
|
int protocolType,
|
|
char far *datagram,
|
|
int datagramLength,
|
|
APPLETALK_ADDRESS actualDestination
|
|
)
|
|
{
|
|
char zoneName[MAXIMUM_ZONELENGTH + 1];
|
|
BufferDescriptor packet;
|
|
RoutingTableEntry routingTableEntry, currentEntry;
|
|
int commandType, currentHash;
|
|
int networkCount, currentNetworkCount, zoneCount, currentZoneIndex;
|
|
unsigned short networkNumber;
|
|
int zoneNameLength, numberOfZonesOnTheNetwork;
|
|
BOOLEAN newPacket, packetFull, zoneNameOverlap, localZonesOnly;
|
|
BOOLEAN extendedZipReply = FALSE, useDefaultZone = FALSE;
|
|
int unsentNetworkCount;
|
|
int index, outIndex, currentReplyType, nextReplyType;
|
|
int totalNetworkCount;
|
|
int transactionId;
|
|
int zipCommand;
|
|
int startIndex;
|
|
int hashBucket;
|
|
ZoneList zoneList, zone, currentZone;
|
|
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 (protocolType isnt DDPPROTOCOL_ZIP and
|
|
protocolType isnt DDPPROTOCOL_ATP)
|
|
return((long)TRUE);
|
|
|
|
// Okay, process the request.
|
|
|
|
DeferTimerChecking();
|
|
DeferIncomingPackets();
|
|
|
|
if (protocolType is DDPPROTOCOL_ZIP) {
|
|
commandType = (unsigned char)datagram[ZIP_COMMANDOFFSET];
|
|
if (datagramLength < ZIP_FIRSTNETWORKOFFSET) {
|
|
HandleIncomingPackets();
|
|
HandleDeferredTimerChecks();
|
|
return((long)TRUE); // All ZIP commands have a command and network count!
|
|
}
|
|
networkCount = (unsigned char)datagram[ZIP_NETWORKCOUNTOFFSET];
|
|
|
|
//
|
|
// 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 ZIP_NETINFOREPLYCOMMAND:
|
|
case ZIP_NOTIFYCOMMAND:
|
|
|
|
// Don't be tellin us... we're a router!
|
|
|
|
break;
|
|
|
|
case ZIP_GETNETINFOCOMMAND:
|
|
|
|
if (not portDescriptors[port].extendedNetwork) {
|
|
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
|
|
IErrFullZipNonExtended, IMsgFullZipNonExtended,
|
|
Insert0());
|
|
break;
|
|
}
|
|
if (not portDescriptors[port].thisZoneList isnt Empty)
|
|
break; // Not fully up yet...
|
|
|
|
// Get the zone name out of the request.
|
|
|
|
if (datagramLength < ZIP_REQUESTEDZONENAMEOFFSET) {
|
|
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
|
|
IErrFullZipMissingZoneLen, IMsgFullZipMissingZoneLen,
|
|
Insert0());
|
|
break;
|
|
}
|
|
zoneNameLength =
|
|
(unsigned char)datagram[ZIP_REQUESTEDZONELENGTHOFFSET];
|
|
if (zoneNameLength > MAXIMUM_ZONELENGTH or
|
|
datagramLength < ZIP_REQUESTEDZONENAMEOFFSET + zoneNameLength) {
|
|
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
|
|
IErrFullZipBadZone, IMsgFullZipBadZone,
|
|
Insert0());
|
|
break;
|
|
}
|
|
MoveMem(zoneName, datagram + ZIP_REQUESTEDZONENAMEOFFSET,
|
|
zoneNameLength);
|
|
zoneName[zoneNameLength] = 0;
|
|
|
|
// Get a buffer descriptor for our reply.
|
|
|
|
if ((packet = NewBufferDescriptor(MAXIMUM_DDPDATAGRAMSIZE)) is Empty) {
|
|
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
|
|
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
|
|
Insert0());
|
|
break;
|
|
}
|
|
|
|
// Format a GetNetInfo reply command.
|
|
|
|
packet->data[ZIP_COMMANDOFFSET] = ZIP_NETINFOREPLYCOMMAND;
|
|
packet->data[ZIP_FLAGSOFFSET] = 0;
|
|
if (zoneNameLength is 0 or
|
|
not ZoneOnList(zoneName, portDescriptors[port].thisZoneList)) {
|
|
packet->data[ZIP_FLAGSOFFSET] |= (unsigned char)ZIP_ZONEINVALIDFLAG;
|
|
useDefaultZone = TRUE;
|
|
}
|
|
if (ElementsOnList(portDescriptors[port].thisZoneList) is 1)
|
|
packet->data[ZIP_FLAGSOFFSET] |= (unsigned char)ZIP_ONLYONEZONEFLAG;
|
|
|
|
// Add our cable range.
|
|
|
|
packet->data[ZIP_FIRSTNETWORKOFFSET] =
|
|
(char)(portDescriptors[port].thisCableRange.firstNetworkNumber
|
|
>> 8);
|
|
packet->data[ZIP_FIRSTNETWORKOFFSET + 1] =
|
|
(char)(portDescriptors[port].thisCableRange.firstNetworkNumber
|
|
& 0xFF);
|
|
packet->data[ZIP_LASTNETWORKOFFSET] =
|
|
(char)(portDescriptors[port].thisCableRange.lastNetworkNumber
|
|
>> 8);
|
|
packet->data[ZIP_LASTNETWORKOFFSET + 1] =
|
|
(char)(portDescriptors[port].thisCableRange.lastNetworkNumber
|
|
& 0xFF);
|
|
|
|
// Echo back the requested zone name.
|
|
|
|
packet->data[ZIP_REQUESTEDZONELENGTHOFFSET] = (char)zoneNameLength;
|
|
MoveMem(packet->data + ZIP_REQUESTEDZONENAMEOFFSET, zoneName,
|
|
zoneNameLength);
|
|
index = ZIP_REQUESTEDZONENAMEOFFSET + zoneNameLength;
|
|
|
|
// Place in the correct zone multicast address.
|
|
|
|
portHandlers = &portSpecificInfo[portDescriptors[port].portType];
|
|
packet->data[index++] = (char)portHandlers->hardwareAddressLength;
|
|
if (useDefaultZone)
|
|
MoveMem(packet->data + index,
|
|
MulticastAddressForZoneOnPort(port,
|
|
portDescriptors[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(portDescriptors[port].thisDefaultZone);
|
|
packet->data[index++] = (char)zoneNameLength;
|
|
MoveMem(packet->data + index,
|
|
portDescriptors[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
|
|
CABLEWIDE_BROADCASTNETWORKNUMBER and
|
|
actualDestination.nodeNumber is APPLETALK_BROADCASTNODENUMBER and
|
|
not IsWithinNetworkRange(source.networkNumber,
|
|
&portDescriptors[port].thisCableRange)
|
|
and
|
|
not IsWithinNetworkRange(source.networkNumber,
|
|
&startupNetworkRange)) {
|
|
source.networkNumber = CABLEWIDE_BROADCASTNETWORKNUMBER;
|
|
source.nodeNumber = APPLETALK_BROADCASTNODENUMBER;
|
|
}
|
|
|
|
// Okay, finally deliver our reply.
|
|
|
|
if (DeliverDdp(destinationSocket, source, DDPPROTOCOL_ZIP, packet,
|
|
index, Empty, Empty, 0) isnt ATnoError)
|
|
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
|
|
IErrFullZipBadInfoReplySend, IMsgFullZipBadInfoReplySend,
|
|
Insert0());
|
|
|
|
break;
|
|
|
|
case ZIP_QUERYCOMMAND:
|
|
|
|
//
|
|
// 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(MAXIMUM_DDPDATAGRAMSIZE)) is Empty) {
|
|
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
|
|
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
|
|
Insert0());
|
|
break;
|
|
}
|
|
|
|
for (index = ZIP_FIRSTNETWORKOFFSET,
|
|
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!
|
|
//
|
|
|
|
if (portDescriptors[port].thisCableRange.firstNetworkNumber is
|
|
networkNumber and
|
|
portDescriptors[port].thisZoneList isnt empty)
|
|
zoneList = portDescriptors[port].thisZoneList;
|
|
else if ((routingTableEntry =
|
|
FindInRoutingTable(networkNumber)) is empty or
|
|
routingTableEntry->networkRange.firstNetworkNumber isnt
|
|
networkNumber or
|
|
not routingTableEntry->zoneListValid)
|
|
continue;
|
|
else
|
|
zoneList = routingTableEntry->zoneList;
|
|
|
|
// What type of reponse does this network want?
|
|
|
|
if ((numberOfZonesOnTheNetwork = ElementsOnList(zoneList)) is 0) {
|
|
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
|
|
IErrFullZipBadZoneList, IMsgFullZipBadZoneList,
|
|
Insert0());
|
|
continue;
|
|
}
|
|
else if (numberOfZonesOnTheNetwork is 1)
|
|
nextReplyType = ZIP_REPLYCOMMAND;
|
|
else {
|
|
//
|
|
// We start a new packet for each extended network, if we
|
|
// have a previous one, send it!
|
|
//
|
|
|
|
if (unsentNetworkCount > 0) {
|
|
packet->data[ZIP_COMMANDOFFSET] = (char)currentReplyType;
|
|
if (currentReplyType is ZIP_REPLYCOMMAND)
|
|
packet->data[ZIP_NETWORKCOUNTOFFSET] =
|
|
(char)unsentNetworkCount;
|
|
|
|
// Send the packet!
|
|
|
|
if (DeliverDdp(destinationSocket, source,
|
|
DDPPROTOCOL_ZIP, packet,
|
|
outIndex, Empty, Empty, 0) isnt ATnoError)
|
|
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
|
|
IErrFullZipBadReplySend, IMsgFullZipBadReplySend,
|
|
Insert0());
|
|
|
|
if ((packet = NewBufferDescriptor(MAXIMUM_DDPDATAGRAMSIZE))
|
|
is Empty) {
|
|
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
|
|
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
|
|
Insert0());
|
|
HandleIncomingPackets();
|
|
HandleDeferredTimerChecks();
|
|
return((long)TRUE);
|
|
}
|
|
|
|
unsentNetworkCount = 0;
|
|
}
|
|
nextReplyType = ZIP_EXTENDEDREPLYCOMMAND;
|
|
newPacket = TRUE;
|
|
packet->data[ZIP_NETWORKCOUNTOFFSET] =
|
|
(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[ZIP_COMMANDOFFSET] = (char)currentReplyType;
|
|
if (currentReplyType is ZIP_REPLYCOMMAND)
|
|
packet->data[ZIP_NETWORKCOUNTOFFSET] =
|
|
(char)unsentNetworkCount;
|
|
|
|
// Send the packet!
|
|
|
|
if (DeliverDdp(destinationSocket, source,
|
|
DDPPROTOCOL_ZIP, packet,
|
|
outIndex, Empty, Empty, 0) isnt ATnoError)
|
|
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
|
|
IErrFullZipBadReplySend, IMsgFullZipBadReplySend,
|
|
Insert0());
|
|
|
|
if ((packet = NewBufferDescriptor(MAXIMUM_DDPDATAGRAMSIZE))
|
|
is Empty) {
|
|
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
|
|
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
|
|
Insert0());
|
|
HandleIncomingPackets();
|
|
HandleDeferredTimerChecks();
|
|
return((long)TRUE);
|
|
}
|
|
|
|
unsentNetworkCount = 0;
|
|
}
|
|
|
|
outIndex = ZIP_FIRSTNETWORKOFFSET;
|
|
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));
|
|
MoveMem(packet->data + outIndex, 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) +
|
|
MAXIMUM_ZONELENGTH >= MAXIMUM_DDPDATAGRAMSIZE)
|
|
newPacket = TRUE;
|
|
|
|
} // Walk zone list.
|
|
|
|
} // Walk through each network in the query packet.
|
|
|
|
// If we have unsent networks left over, send them out!
|
|
|
|
if (unsentNetworkCount > 0) {
|
|
packet->data[ZIP_COMMANDOFFSET] = (char)currentReplyType;
|
|
if (currentReplyType is ZIP_REPLYCOMMAND)
|
|
packet->data[ZIP_NETWORKCOUNTOFFSET] =
|
|
(char)unsentNetworkCount;
|
|
|
|
// Send the packet!
|
|
|
|
if (DeliverDdp(destinationSocket, source,
|
|
DDPPROTOCOL_ZIP, 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 ZIP_EXTENDEDREPLYCOMMAND:
|
|
|
|
extendedZipReply = TRUE;
|
|
// And fall through...
|
|
|
|
case ZIP_REPLYCOMMAND:
|
|
|
|
//
|
|
// 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 = ZIP_FIRSTNETWORKOFFSET,
|
|
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) {
|
|
index += zoneNameLength;
|
|
continue;
|
|
}
|
|
|
|
// Okay validate the zone name.
|
|
|
|
if (zoneNameLength is 0 or
|
|
zoneNameLength > MAXIMUM_ZONELENGTH) {
|
|
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
|
|
IErrFullZipBadReplyPacket, IMsgFullZipBadReplyPacket,
|
|
Insert0());
|
|
break; // Oops, corrupted packet!
|
|
}
|
|
if (index + zoneNameLength > datagramLength) {
|
|
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;
|
|
if (ZoneOnList(zoneName, routingTableEntry->zoneList))
|
|
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 portDescriptors[routingTableEntry->port].
|
|
extendedNetwork and
|
|
ElementsOnList(routingTableEntry->zoneList) is 1) {
|
|
ErrorLog("ZipPacketInRouter", ISevWarning, __LINE__, port,
|
|
IErrFullZipTooManyZones, IMsgFullZipTooManyZones,
|
|
Insert0());
|
|
continue;
|
|
}
|
|
|
|
// Okay, add to list.
|
|
|
|
if ((routingTableEntry->zoneList =
|
|
AddZoneToList(routingTableEntry->zoneList, zoneName))
|
|
is empty) {
|
|
ErrorLog("ZipPacketInRouter", ISevError, __LINE__, port,
|
|
IErrFullZipCantAddZone, IMsgFullZipCantAddZone,
|
|
Insert0());
|
|
routingTableEntry->zoneListValid = FALSE;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// 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->zoneListValid = 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->zoneList) >=
|
|
numberOfZonesOnTheNetwork)
|
|
routingTableEntry->zoneListValid = TRUE;
|
|
|
|
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[ATP_COMMANDCONTROLOFFSET] & ATP_FUNCTIONCODEMASK) isnt
|
|
ATP_REQUESTFUNCTIONCODE) {
|
|
HandleIncomingPackets();
|
|
HandleDeferredTimerChecks();
|
|
return((long)TRUE); // Why are they talking to us???
|
|
}
|
|
if (datagram[ATP_BITMAPOFFSET] 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[ATP_TRANSACTIONIDOFFSET]) << 8;
|
|
transactionId += (unsigned char)datagram[ATP_TRANSACTIONIDOFFSET + 1];
|
|
|
|
//
|
|
// Make sure it's one of the three requests that we know how to deal
|
|
// with.
|
|
//
|
|
|
|
zipCommand = (unsigned char)datagram[AtpZIP_COMMANDOFFSET] & 0xFF;
|
|
if (zipCommand isnt ZIP_GETZONELISTCOMMAND and
|
|
zipCommand isnt ZIP_GETLOCALZONESCOMMAND and
|
|
zipCommand isnt ZIP_GETMYZONECOMMAND) {
|
|
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[ATPZIP_STARTINDEXOFFSET] << 8);
|
|
startIndex += (unsigned char)datagram[ATPZIP_STARTINDEXOFFSET + 1];
|
|
|
|
// Allocate a buffer descriptor for the reply.
|
|
|
|
if ((packet = NewBufferDescriptor(MAXIMUM_DDPDATAGRAMSIZE)) 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[ATP_COMMANDCONTROLOFFSET] =
|
|
(unsigned char)(ATP_RESPONSEFUNCTIONCODE + ATP_ENDOFMESSAGEMASK);
|
|
packet->data[ATP_SEQUENCENUMBEROFFSET] = 0;
|
|
packet->data[ATP_TRANSACTIONIDOFFSET] = (char)((transactionId >> 8) & 0xFF);
|
|
packet->data[ATP_TRANSACTIONIDOFFSET + 1] = (char)(transactionId & 0xFF);
|
|
|
|
// Handle GetMyZone:
|
|
|
|
if (zipCommand is ZIP_GETMYZONECOMMAND) {
|
|
//
|
|
// 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
|
|
// couse, 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[ATPZIP_LASTFLAGOFFSET] = 0;
|
|
packet->data[ATPZIP_LASTFLAGOFFSET + 1] = 0;
|
|
packet->data[ATPZIP_STARTINDEXOFFSET] = 0;
|
|
packet->data[ATPZIP_STARTINDEXOFFSET + 1] = 1;
|
|
|
|
if (portDescriptors[port].extendedNetwork) {
|
|
zoneNameLength = strlen(portDescriptors[port].thisDefaultZone);
|
|
packet->data[ATP_DATAOFFSET] = (char)zoneNameLength;
|
|
MoveMem(packet->data + ATP_DATAOFFSET + 1,
|
|
portDescriptors[port].thisDefaultZone, zoneNameLength);
|
|
}
|
|
else {
|
|
zoneNameLength = strlen(portDescriptors[port].thisZone);
|
|
packet->data[ATP_DATAOFFSET] = (char)zoneNameLength;
|
|
MoveMem(packet->data + ATP_DATAOFFSET + 1,
|
|
portDescriptors[port].thisZone, zoneNameLength);
|
|
}
|
|
|
|
// Blast the reply out!
|
|
|
|
if (DeliverDdp(destinationSocket, source, DDPPROTOCOL_ATP,
|
|
packet, ATP_DATAOFFSET + 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 ZIP_GETLOCALZONESCOMMAND);
|
|
|
|
index = ATP_DATAOFFSET;
|
|
packetFull = FALSE;
|
|
for (hashBucket = 0, zoneCount = 0, networkCount = 0,
|
|
currentZoneIndex = 0;
|
|
hashBucket < NUMBEROF_RTMPHASHBUCKETS and not packetFull;
|
|
hashBucket += 1)
|
|
for (routingTableEntry = routingTable[hashBucket];
|
|
routingTableEntry isnt empty;
|
|
routingTableEntry = routingTableEntry->next)
|
|
for (zone = routingTableEntry->zoneList;
|
|
zone isnt empty;
|
|
zone = zone->next) {
|
|
//
|
|
// If we're a GetLocalZones command, we only want to count
|
|
// zones that are on the network that is directly connected to
|
|
// the port on which the request originated.
|
|
//
|
|
|
|
if (localZonesOnly)
|
|
if (routingTableEntry->numberOfHops isnt 0 or
|
|
routingTableEntry->port isnt port)
|
|
continue;
|
|
|
|
//
|
|
// We don't want to count zones with the same names, so look at
|
|
// all previous networks to see if we've already handled a zone
|
|
// of the same name. Not too easy given that we don't maintain
|
|
// a separate zone table.
|
|
//
|
|
|
|
networkCount += 1;
|
|
zoneNameOverlap = FALSE;
|
|
for (currentHash = 0, currentNetworkCount = 0;
|
|
not zoneNameOverlap and not localZonesOnly and
|
|
currentNetworkCount < networkCount and
|
|
currentHash < NUMBEROF_RTMPHASHBUCKETS;
|
|
currentHash += 1)
|
|
for (currentEntry = routingTable[currentHash];
|
|
not zoneNameOverlap and currentEntry isnt empty and
|
|
currentNetworkCount < networkCount;
|
|
currentEntry = currentEntry->next)
|
|
for (currentZone = currentEntry->zoneList;
|
|
currentZone isnt empty;
|
|
currentZone = currentZone->next) {
|
|
if ((currentNetworkCount += 1) is networkCount)
|
|
break;
|
|
if (CompareCaseInsensitive(zone->zone,
|
|
currentZone->zone))
|
|
zoneNameOverlap = TRUE;
|
|
}
|
|
if (zoneNameOverlap)
|
|
continue;
|
|
|
|
//
|
|
// Are we at the point that the requester want's us to start from
|
|
// yet?
|
|
//
|
|
|
|
currentZoneIndex += 1;
|
|
if (currentZoneIndex < startIndex)
|
|
continue;
|
|
|
|
// Place a zone name in the packet.
|
|
|
|
zoneNameLength = strlen(zone->zone);
|
|
packet->data[index++] = (char)zoneNameLength;
|
|
MoveMem(packet->data + index, zone->zone, zoneNameLength);
|
|
index += zoneNameLength;
|
|
zoneCount += 1;
|
|
|
|
// Can this packet hold another of the longest zone?
|
|
|
|
if (index + sizeof(char) + MAXIMUM_ZONELENGTH >=
|
|
MAXIMUM_DDPDATAGRAMSIZE) {
|
|
packetFull = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Okay, we've built a packet, fill in the number of zones field,
|
|
// and the Last flag.
|
|
//
|
|
|
|
packet->data[ATPZIP_LASTFLAGOFFSET] =
|
|
(char)(hashBucket >= NUMBEROF_RTMPHASHBUCKETS and
|
|
routingTableEntry is empty);
|
|
packet->data[ATPZIP_LASTFLAGOFFSET + 1] = 0;
|
|
packet->data[ATPZIP_ZONECOUNTOFFSET] =
|
|
(char)((zoneCount >> 8) & 0xFF);
|
|
packet->data[ATPZIP_ZONECOUNTOFFSET + 1] =
|
|
(char)(zoneCount & 0xFF);
|
|
|
|
// Send out the packet.
|
|
|
|
if (DeliverDdp(destinationSocket, source, DDPPROTOCOL_ATP,
|
|
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
|
|
|
|
|
|
|
|
|
|
void
|
|
ZipQueryTimerExpired(
|
|
long unsigned timerId,
|
|
int additionalDataSize,
|
|
char far *additionalData
|
|
)
|
|
{
|
|
RoutingTableEntry routingTableEntry;
|
|
BufferDescriptor datagram;
|
|
int hashBucket;
|
|
APPLETALK_ADDRESS source, destination;
|
|
long sourceSocket;
|
|
|
|
// "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 < NUMBEROF_RTMPHASHBUCKETS;
|
|
hashBucket += 1)
|
|
for (routingTableEntry = routingTable[hashBucket];
|
|
routingTableEntry isnt empty;
|
|
routingTableEntry = routingTableEntry->next) {
|
|
|
|
// If we already know the zone for this network, skip it.
|
|
|
|
if (routingTableEntry->zoneListValid)
|
|
continue;
|
|
|
|
// Get a buffer descriptor for our query.
|
|
|
|
if ((datagram = NewBufferDescriptor(ZIP_ONEZONEQUERYDDPSIZE)) is Empty) {
|
|
ErrorLog("ZipQueryTimerExpired", ISevError, __LINE__, UNKNOWN_PORT,
|
|
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
|
|
Insert0());
|
|
continue;
|
|
}
|
|
|
|
// Build the static part of the query packet.
|
|
|
|
datagram->data[ZIP_COMMANDOFFSET] = ZIP_QUERYCOMMAND;
|
|
datagram->data[ZIP_NETWORKCOUNTOFFSET] = 1;
|
|
|
|
// Place the network number in question into the query packet.
|
|
|
|
datagram->data[ZIP_FIRSTNETWORKOFFSET] =
|
|
(char)((routingTableEntry->networkRange.firstNetworkNumber
|
|
>> 8) & 0xFF);
|
|
datagram->data[ZIP_FIRSTNETWORKOFFSET + 1] =
|
|
(char)(routingTableEntry->networkRange.firstNetworkNumber & 0xFF);
|
|
|
|
// Compute the source and destination for this request.
|
|
|
|
source.networkNumber =
|
|
portDescriptors[routingTableEntry->port].aRouter.networkNumber;
|
|
source.nodeNumber =
|
|
portDescriptors[routingTableEntry->port].aRouter.nodeNumber;
|
|
source.socketNumber = ZONESINFORMATION_SOCKET;
|
|
if (routingTableEntry->numberOfHops is 0) {
|
|
destination.networkNumber =
|
|
portDescriptors[routingTableEntry->port].aRouter.networkNumber;
|
|
destination.nodeNumber =
|
|
portDescriptors[routingTableEntry->port].aRouter.nodeNumber;
|
|
}
|
|
else {
|
|
destination.networkNumber =
|
|
routingTableEntry->nextRouter.networkNumber;
|
|
destination.nodeNumber =
|
|
routingTableEntry->nextRouter.nodeNumber;
|
|
}
|
|
destination.socketNumber = ZONESINFORMATION_SOCKET;
|
|
|
|
if ((sourceSocket = MapAddressToSocket(routingTableEntry->port,
|
|
source)) < ATnoError) {
|
|
ErrorLog("ZipQueryTimerExpired", ISevError, __LINE__,
|
|
routingTableEntry->port,
|
|
IErrFullZipSocketNotOpen, IMsgFullZipSocketNotOpen,
|
|
Insert0());
|
|
FreeBufferChain(datagram);
|
|
continue;
|
|
}
|
|
|
|
// Send the packet!
|
|
|
|
if (DeliverDdp(sourceSocket, destination, DDPPROTOCOL_ZIP,
|
|
datagram, ZIP_ONEZONEQUERYDDPSIZE, Empty,
|
|
Empty, 0) isnt ATnoError)
|
|
ErrorLog("ZipQueryTimerExpired", ISevError, __LINE__,
|
|
routingTableEntry->port,
|
|
IErrFullZipBadQuerySend, IMsgFullZipBadQuerySend,
|
|
Insert0());
|
|
|
|
} // Loop through the routing table...
|
|
|
|
// Re-arm ZIP query timer...
|
|
|
|
StartTimer(ZipQueryTimerExpired, ZIP_QUERYTIMERSECONDS, 0, empty);
|
|
|
|
// We've done the deed...
|
|
|
|
HandleIncomingPackets();
|
|
HandleDeferredTimerChecks();
|
|
return;
|
|
|
|
} // ZipQueryTimerExpired
|
|
|
|
|
|
|
|
|
|
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;
|
|
APPLETALK_ADDRESS source, destination;
|
|
PortHandlers portHandlers;
|
|
char far *multicastAddress;
|
|
|
|
// Set source and destination.
|
|
|
|
source.networkNumber = portDescriptors[port].aRouter.networkNumber;
|
|
source.nodeNumber = portDescriptors[port].aRouter.nodeNumber;
|
|
source.socketNumber = ZONESINFORMATION_SOCKET;
|
|
destination.networkNumber = CABLEWIDE_BROADCASTNETWORKNUMBER;
|
|
destination.nodeNumber = APPLETALK_BROADCASTNODENUMBER;
|
|
destination.socketNumber = ZONESINFORMATION_SOCKET;
|
|
|
|
if ((routingTableEntry =
|
|
FindInRoutingTable(portDescriptors[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->zoneListValid and
|
|
numberOfRequests < NUMBEROF_ZIPQUERIES) {
|
|
// Get a buffer descriptor for the query.
|
|
|
|
if ((datagram = NewBufferDescriptor(ZIP_ONEZONEQUERYDDPSIZE)) is Empty) {
|
|
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
|
|
IErrFullZipOutOfMemory, IMsgFullZipOutOfMemory,
|
|
Insert0());
|
|
return(FALSE);
|
|
}
|
|
|
|
// Build a ZipQuery packet...
|
|
|
|
datagram->data[ZIP_COMMANDOFFSET] = ZIP_QUERYCOMMAND;
|
|
datagram->data[ZIP_NETWORKCOUNTOFFSET] = 1;
|
|
datagram->data[ZIP_FIRSTNETWORKOFFSET] =
|
|
(char)((portDescriptors[port].thisCableRange.firstNetworkNumber
|
|
>> 8) & 0xFF);
|
|
datagram->data[ZIP_FIRSTNETWORKOFFSET + 1] =
|
|
(char)(portDescriptors[port].thisCableRange.firstNetworkNumber &
|
|
0xFF);
|
|
|
|
if (not TransmitDdp(port, source, destination, DDPPROTOCOL_ZIP,
|
|
datagram, ZIP_ONEZONEQUERYDDPSIZE,
|
|
0, Empty, Empty, Empty, 0)) {
|
|
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
|
|
IErrFullZipBadQuerySend, IMsgFullZipBadQuerySend,
|
|
Insert0());
|
|
return(FALSE);
|
|
}
|
|
numberOfRequests += 1;
|
|
WaitFor(ZIP_QUERYTIMERINHUNDRETHS, &routingTableEntry->zoneListValid);
|
|
}
|
|
|
|
//
|
|
// If we got an answer, we're set... but, we're going to need to play
|
|
// with the routing tables...
|
|
//
|
|
|
|
DeferTimerChecking();
|
|
DeferIncomingPackets();
|
|
|
|
if (routingTableEntry->zoneListValid) {
|
|
//
|
|
// The valid zone list is now in the routing table... move it to the
|
|
// port descriptor.
|
|
//
|
|
|
|
if ((portDescriptors[port].thisZoneList =
|
|
CopyZoneList(routingTableEntry->zoneList)) is empty) {
|
|
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
|
|
IErrFullZipCouldNotCopy, IMsgFullZipCouldNotCopy,
|
|
Insert0());
|
|
HandleIncomingPackets();
|
|
HandleDeferredTimerChecks();
|
|
return(FALSE);
|
|
}
|
|
|
|
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 (portDescriptors[port].extendedNetwork) {
|
|
if (not portDescriptors[port].thisZoneValid and
|
|
not GetNetworkInfoForNode(port, portDescriptors[port].aRouter,
|
|
FALSE, TRUE)) {
|
|
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
|
|
IErrFullZipNoThisZone, IMsgFullZipNoThisZone,
|
|
Insert0());
|
|
return(FALSE);
|
|
}
|
|
if (not GetNetworkInfoForNode(port, portDescriptors[port].aRouter,
|
|
TRUE)) {
|
|
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
|
|
IErrFullZipNoThisZone, IMsgFullZipNoThisZone,
|
|
Insert0());
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// The defualt zone had better be on the zone list we've just
|
|
// received.
|
|
//
|
|
|
|
if (not ZoneOnList(portDescriptors[port].thisDefaultZone,
|
|
portDescriptors[port].thisZoneList) or
|
|
not ZoneOnList(portDescriptors[port].thisZone,
|
|
portDescriptors[port].thisZoneList)) {
|
|
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
|
|
IErrFullZipBadThisZone, IMsgFullZipBadThisZone,
|
|
Insert0());
|
|
return(FALSE);
|
|
}
|
|
|
|
// Okay, we're all set.
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// On a non-extended network, the one entry on the zone list should
|
|
// also be "this zone".
|
|
//
|
|
|
|
strcpy(portDescriptors[port].thisZone,
|
|
portDescriptors[port].thisZoneList->zone);
|
|
portDescriptors[port].thisZoneValid = TRUE;
|
|
return(TRUE);
|
|
}
|
|
|
|
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[portDescriptors[port].portType];
|
|
if (portDescriptors[port].extendedNetwork and
|
|
portDescriptors[port].thisZoneValid)
|
|
if (not FixedCompareCaseSensitive(portDescriptors[port].
|
|
zoneMulticastAddress,
|
|
portHandlers->hardwareAddressLength,
|
|
portHandlers->broadcastAddress,
|
|
portHandlers->hardwareAddressLength))
|
|
(*portHandlers->removeMulticastAddress)(port, 1,
|
|
portDescriptors[port].
|
|
zoneMulticastAddress);
|
|
|
|
// Okay, now we had better know enough to seed!
|
|
|
|
if (portDescriptors[port].initialZoneList is empty) {
|
|
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
|
|
IErrFullZipNeedSeedInfo, IMsgFullZipNeedSeedInfo,
|
|
Insert0());
|
|
return(FALSE);
|
|
}
|
|
|
|
if ((portDescriptors[port].thisZoneList =
|
|
CopyZoneList(portDescriptors[port].initialZoneList)) is empty) {
|
|
ErrorLog("GetZoneListFor", ISevError, __LINE__, port,
|
|
IErrFullZipCouldNotCopy, IMsgFullZipCouldNotCopy,
|
|
Insert0());
|
|
return(FALSE);
|
|
}
|
|
if (portDescriptors[port].extendedNetwork) {
|
|
// Here we need to seed the default zone too.
|
|
|
|
strcpy(portDescriptors[port].thisDefaultZone,
|
|
portDescriptors[port].initialDefaultZone);
|
|
portDescriptors[port].thisDefaultZoneValid = TRUE;
|
|
if (portDescriptors[port].initialDesiredZone[0] isnt 0)
|
|
strcpy(portDescriptors[port].thisZone,
|
|
portDescriptors[port].initialDesiredZone);
|
|
else
|
|
strcpy(portDescriptors[port].thisZone,
|
|
portDescriptors[port].initialDefaultZone);
|
|
portDescriptors[port].thisZoneValid = TRUE;
|
|
|
|
// We should now set up the zone multicast address too...
|
|
|
|
if ((multicastAddress =
|
|
MulticastAddressForZoneOnPort(port, portDescriptors[port].thisZone))
|
|
is empty)
|
|
return(FALSE);
|
|
|
|
if (not FixedCompareCaseSensitive(multicastAddress,
|
|
portHandlers->hardwareAddressLength,
|
|
portHandlers->broadcastAddress,
|
|
portHandlers->hardwareAddressLength))
|
|
(*portHandlers->addMulticastAddress)(port, 1, multicastAddress);
|
|
MoveMem(portDescriptors[port].zoneMulticastAddress, multicastAddress,
|
|
portHandlers->hardwareAddressLength);
|
|
}
|
|
else {
|
|
//
|
|
// On non-extended networks, this zone should be the only one on the
|
|
// zone list.
|
|
//
|
|
|
|
strcpy(portDescriptors[port].thisZone,
|
|
portDescriptors[port].thisZoneList->zone);
|
|
portDescriptors[port].thisZoneValid = TRUE;
|
|
}
|
|
|
|
// All set!
|
|
|
|
return(TRUE);
|
|
|
|
} // GetZoneList
|
|
|
|
|
|
|
|
|
|
PCHAR
|
|
MulticastAddressForZoneOnPort(
|
|
int port,
|
|
PCHAR zone
|
|
)
|
|
{
|
|
short unsigned checksum;
|
|
char upcasedZone[MAXIMUM_ZONELENGTH + 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 (portDescriptors[port].portType) {
|
|
case ETHERNET_NETWORK:
|
|
case FDDI_NETWORK:
|
|
return(EthernetZoneMulticastAddrs[checksum %
|
|
NUMBEROF_ENETZONEMULTICASTADDRS]);
|
|
|
|
case TOKENRING_NETWORK:
|
|
return(TokenRingZoneMulticastAddrs[checksum %
|
|
NUMBEROF_TRINGZONEMULTICASTADDRS]);
|
|
|
|
default:
|
|
ErrorLog("MulticastAddressForZoneOnPort", ISevError, __LINE__, port,
|
|
IErrFullZipBadPortType, IMsgFullZipBadPortType,
|
|
Insert0());
|
|
return(empty);
|
|
}
|
|
|
|
} // MulticastAddressForZoneOnPort
|
|
|
|
#endif
|