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.
 
 
 
 
 
 

1197 lines
37 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
fullrtmp.c
Abstract:
Handle the RTMP protocol for a routing node.
Author:
Garth Conboy (Pacer Software)
Nikhil Kamkolkar (NikhilK)
Revision History:
GC - (03/13/91): Added the "recentRoutes" cache to improve large network
routing performance.
GC - (01/20/92): Removed usage of numberOfConfiguredPorts; portDescriptors
may now be sparse, we use the portActive flag instead.
GC - (01/21/92): Made RemoveFromRoutingTable externally visible.
GC - (03/31/92): Updated for BufferDescriptors.
GC - (06/15/92): Correct "notify neighbor" handling: don't allow route
upgrading.
--*/
#define IncludeFullRtmpErrors 1
#include "atalk.h"
#if IamNot an AppleTalkRouter
// Empty file
#else
ExternForVisibleFunction TimerHandler RtmpSendTimerExpired;
ExternForVisibleFunction TimerHandler RtmpValidityTimerExpired;
ExternForVisibleFunction Boolean
GetOrSetNetworkNumber(int port,
unsigned int suggestedNetworkNumber);
ExternForVisibleFunction void SendRoutingData(int port,
AppleTalkAddress destination,
Boolean doSplitHorizon);
ExternForVisibleFunction void
EnterIntoRoutingTable(AppleTalkNetworkRange networkRange,
int port,
ExtendedAppleTalkNodeNumber nextRouter,
int numberOfHops);
static Boolean firstCall = True;
Boolean far StartRtmpProcessingOnPort(int port,
ExtendedAppleTalkNodeNumber routerNode)
{
//
// For extended ports there is very little to do now; the process of getting
// the node has done most of our work for us.
//
if (GET_PORTDESCRIPTOR(port)->ExtendedNetwork) {
//
// If we've seen another router; does the real network agree with what
// we were going to try to seed? No seeding for half ports.
//
if (GET_PORTDESCRIPTOR(port)->PortType isnt NonAppleTalkHalfPort and
GET_PORTDESCRIPTOR(port)->SeenRouterRecently and
GET_PORTDESCRIPTOR(port)->InitialNetworkRange.FirstNetworkNumber isnt
UnknownNetworkNumber)
if (GET_PORTDESCRIPTOR(port)->InitialNetworkRange.FirstNetworkNumber isnt
GET_PORTDESCRIPTOR(port)->ThisCableRange.FirstNetworkNumber or
GET_PORTDESCRIPTOR(port)->InitialNetworkRange.LastNetworkNumber isnt
GET_PORTDESCRIPTOR(port)->ThisCableRange.LastNetworkNumber)
ErrorLog("StartRtmpProcessingOnPort", ISevWarning, __LINE__, port,
IErrFullRtmpIgnoredNetRange, IMsgFullRtmpIgnoredNetRange,
Insert0());
// Otherwise, we're the first rotuer, so we'll seed (if we can).
if (GET_PORTDESCRIPTOR(port)->PortType is NonAppleTalkHalfPort) {
GET_PORTDESCRIPTOR(port)->ThisCableRange.FirstNetworkNumber =
UnknownNetworkNumber;
GET_PORTDESCRIPTOR(port)->ThisCableRange.LastNetworkNumber =
UnknownNetworkNumber;
}
else if (not GET_PORTDESCRIPTOR(port)->SeedRouter) {
ErrorLog("StartRtmpProcessingOnPort", ISevError, __LINE__, port,
IErrFullRtmpNoSeedCantStart, IMsgFullRtmpNoSeedCantStart,
Insert0());
return(False);
}
else if (not GET_PORTDESCRIPTOR(port)->SeenRouterRecently)
GET_PORTDESCRIPTOR(port)->ThisCableRange =
GET_PORTDESCRIPTOR(port)->InitialNetworkRange;
}
else {
//
// For non-extended networks, we need to either find or seed our network
// number.
//
if (not GetOrSetNetworkNumber(port, (unsigned int)(
GET_PORTDESCRIPTOR(port)->SeedRouter ?
GET_PORTDESCRIPTOR(port)->InitialNetworkRange.
FirstNetworkNumber :
UnknownNetworkNumber)))
return(False);
if (not GET_PORTDESCRIPTOR(port)->SeenRouterRecently)
GET_PORTDESCRIPTOR(port)->ThisCableRange.FirstNetworkNumber =
GET_PORTDESCRIPTOR(port)->InitialNetworkRange.FirstNetworkNumber;
//
// On non-extended networks, we would have "allocated" a node with network
// zero, fix this up here!
//
GET_PORTDESCRIPTOR(port)->ActiveNodes->ExtendedNode.NetworkNumber =
GET_PORTDESCRIPTOR(port)->ARouter.NetworkNumber =
routerNode.NetworkNumber =
GET_PORTDESCRIPTOR(port)->ThisCableRange.FirstNetworkNumber;
}
// Well, we're a router now, so mark us as A-ROUTER.
GET_PORTDESCRIPTOR(port)->SeenRouterRecently = True;
GET_PORTDESCRIPTOR(port)->ARouter = routerNode;
GET_PORTDESCRIPTOR(port)->RouterRunning = True;
// Okay, make it so...
if (GET_PORTDESCRIPTOR(port)->PortType isnt NonAppleTalkHalfPort)
EnterIntoRoutingTable(GET_PORTDESCRIPTOR(port)->ThisCableRange, port,
routerNode, 0);
// Switch the incoming RTMP packet handler to be the router version.
CloseSocketOnNodeIfOpen(port, routerNode, RtmpSocket);
if (OpenSocketOnNode(empty, port, &routerNode, RtmpSocket, RtmpPacketInRouter,
(long)0, False, empty, 0, empty) isnt ATnoError) {
ErrorLog("StartRtmpProcessingOnPort", ISevError, __LINE__, port,
IErrFullRtmpBadSocketOpen, IMsgFullRtmpBadSocketOpen,
Insert0());
return(False);
}
// Start the two RTMP timers.
if (firstCall) {
StartTimer(RtmpSendTimerExpired, RtmpSendTimerSeconds, 0, empty);
StartTimer(RtmpValidityTimerExpired, RtmpValidityTimerSeconds, 0, empty);
firstCall = False;
}
return(True);
} // StartRtmpProcessingOnPort
void far ShutdownFullRtmp(void)
{
firstCall = True;
} // ShutdownFullRtmp
long far RtmpPacketInRouter(AppleTalkErrorCode errorCode,
long unsigned userData,
int port,
AppleTalkAddress source,
long destinationSocket,
int protocolType,
char far *datagram,
int datagramLength,
AppleTalkAddress actualDestination)
{
AppleTalkNetworkRange cableRange;
int rtmpCommand, responseSize, numberOfHops, index, indexToo;
RoutingTableEntry routingTableEntry;
ExtendedAppleTalkNodeNumber nextRouter;
Boolean foundOverlap;
BufferDescriptor buffer;
// "Use" unneeded formals.
actualDestination, userData;
// Do we care?
if (errorCode is ATsocketClosed)
return((long)True);
else if (errorCode isnt ATnoError) {
ErrorLog("RtmpPacketInRouter", ISevError, __LINE__, port,
IErrFullRtmpBadIncomingError, IMsgFullRtmpBadIncomingError,
Insert0());
return((long)True);
}
// Is the packet long enough to have any interestng data?
if (protocolType is DdpProtocolRtmpRequest) {
if (datagramLength < RtmpRequestDatagramSize)
{
ErrorLog("RtmpPacketInRouter", ISevWarning, __LINE__, port,
IErrFullRtmpReqTooShort, IMsgFullRtmpReqTooShort,
Insert0());
return((long)True);
}
}
else if (protocolType is DdpProtocolRtmpResponseOrData) {
if ((GET_PORTDESCRIPTOR(port)->ExtendedNetwork and
datagramLength < RtmpDataMinimumSizeExtended) or
(not GET_PORTDESCRIPTOR(port)->ExtendedNetwork and
datagramLength < RtmpDataMinimumSizeNonExtended)) {
ErrorLog("RtmpPacketInRouter", ISevWarning, __LINE__, port,
IErrFullRtmpDataTooShort, IMsgFullRtmpDataTooShort,
Insert0());
return((long)True);
}
}
else
return((long)True); // Funny protocol type...
// We're going to be playing with the routing tables...
DeferTimerChecking();
DeferIncomingPackets();
if (protocolType is DdpProtocolRtmpRequest) {
rtmpCommand = (unsigned char)datagram[RtmpRequestCommandOffset];
switch (rtmpCommand) {
case RtmpRequestCommand:
break;
case RtmpDataRequestCommand:
case RtmpEntireDataRequestCommand:
//
// Send all or part of our routing tables back to the requesting
// address...
//
SendRoutingData(port, source,
(Boolean)(rtmpCommand is RtmpDataRequestCommand));
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
default:
ErrorLog("RtmpPacketInRouter", ISevWarning, __LINE__, port,
IErrFullRtmpBadReqCommand, IMsgFullRtmpBadReqCommand,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
//
// Okay, we're a standard RtmpRequest; do the right thing. Find our
// port's entry in the routing table.
//
if ((routingTableEntry =
FindInRoutingTable(GET_PORTDESCRIPTOR(port)->ARouter.
networkNumber)) is empty) {
ErrorLog("RtmpPacketInRouter", ISevError, __LINE__, port,
IErrFullRtmpBadRoutingTables, IMsgFullRtmpBadRoutingTables,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
// This guy would like an RTMP response...
if ((buffer = NewBufferDescriptor(RtmpResponseMaxSize)) is Empty) {
ErrorLog("RtmpPacketInRouter", ISevError, __LINE__, port,
IErrFullRtmpOutOfMemory, IMsgFullRtmpOutOfMemory,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
buffer->data[RtmpSendersNetworkOffset] =
(char)((GET_PORTDESCRIPTOR(port)->ARouter.NetworkNumber >> 8) & 0xFF);
buffer->data[RtmpSendersNetworkOffset + 1] =
(char)(GET_PORTDESCRIPTOR(port)->ARouter.NetworkNumber & 0xFF);
buffer->data[RtmpSendersIdLengthOffset] = 8; // Bits
buffer->data[RtmpSendersIdOffset] = GET_PORTDESCRIPTOR(port)->ARouter.NodeNumber;
//
// On an extended port, we also want to add the initial network range
// tuple.
//
if (not GET_PORTDESCRIPTOR(port)->ExtendedNetwork)
responseSize = RtmpSendersIdOffset + sizeof(char);
else {
buffer->data[RtmpRangeStartOffset] =
(char)((GET_PORTDESCRIPTOR(port)->ThisCableRange.
FirstNetworkNumber >> 8) & 0xFF);
buffer->data[RtmpRangeStartOffset + 1] =
(char)(GET_PORTDESCRIPTOR(port)->ThisCableRange.
FirstNetworkNumber & 0xFF);
buffer->data[RtmpRangeStartOffset + 2] = RtmpTupleWithRange;
buffer->data[RtmpRangeEndOffset] =
(char)((GET_PORTDESCRIPTOR(port)->ThisCableRange.
LastNetworkNumber >> 8) & 0xFF);
buffer->data[RtmpRangeEndOffset + 1] =
(char)(GET_PORTDESCRIPTOR(port)->ThisCableRange.
LastNetworkNumber & 0xFF);
responseSize = RtmpRangeEndOffset + sizeof(short unsigned);
}
// Send the response.
if (DeliverDdp(destinationSocket, source, DdpProtocolRtmpResponseOrData,
buffer, responseSize, Empty, Empty, 0) isnt ATnoError)
ErrorLog("RtmpPacketInRouter", ISevError, __LINE__, port,
IErrFullRtmpBadRespSend, IMsgFullRtmpBadRespSend,
Insert0());
}
else if (protocolType is DdpProtocolRtmpResponseOrData) {
if ((unsigned char)datagram[RtmpSendersIdLengthOffset] isnt 8)
{
ErrorLog("RtmpPacketInRouter", ISevWarning, __LINE__, port,
IErrFullRtmpBadNodeIdLen, IMsgFullRtmpBadNodeIdLen,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
// For non extended networks, we should have a leading version stamp.
if (GET_PORTDESCRIPTOR(port)->ExtendedNetwork)
index = RtmpSendersIdOffset + 1;
else
if ((unsigned char)datagram[RtmpSendersIdOffset + 1] isnt 0 or
(unsigned char)datagram[RtmpSendersIdOffset + 2] isnt 0 or
(unsigned char)datagram[RtmpSendersIdOffset + 3] isnt
RtmpVersionNumber) {
ErrorLog("RtmpPacketInRouter", ISevError, __LINE__, port,
IErrFullRtmpBadVersion, IMsgFullRtmpBadVersion,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
else
index = RtmpSendersIdOffset + 4;
//
// Walk through the routing tuples... The "+ 3" ensure we as least have
// a non-extended tuple.
//
while (index + 3 <= datagramLength) {
// Decode either a short or long tuple...
cableRange.firstNetworkNumber = (unsigned short)
(((unsigned char)datagram[index++]) << 8);
cableRange.firstNetworkNumber += (unsigned char)datagram[index++];
numberOfHops = (unsigned char)datagram[index++];
if (numberOfHops & RtmpExtendedTupleMask) {
if (index + 2 > datagramLength)
{
ErrorLog("RtmpPacketInRouter", ISevError, __LINE__, port,
IErrFullRtmpBadTuple, IMsgFullRtmpBadTuple,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
cableRange.lastNetworkNumber = (unsigned short)
(((unsigned char)datagram[index++]) << 8);
cableRange.lastNetworkNumber += (unsigned char)datagram[index++];
if ((unsigned char)datagram[index++] isnt RtmpVersionNumber) {
ErrorLog("RtmpPacketInRouter", ISevWarning, __LINE__, port,
IErrFullRtmpBadVersionExt, IMsgFullRtmpBadVersionExt,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
}
else
cableRange.lastNetworkNumber = cableRange.firstNetworkNumber;
numberOfHops &= RtmpNumberOfHopsMask;
//
// Skip dummy "this net" on half ports; the first tuple coming in
// from a half port will fall into this catagory (having no network
// range).
//
if (GET_PORTDESCRIPTOR(port)->PortType is NonAppleTalkHalfPort and
cableRange.firstNetworkNumber is UnknownNetworkNumber)
continue;
// Validate what we have...
if (not CheckNetworkRange(cableRange))
continue;
//
// Okay, first check to see if this tuple concerns a network range
// that we already know about.
//
if ((routingTableEntry =
FindInRoutingTable(cableRange.firstNetworkNumber)) isnt empty and
routingTableEntry->networkRange.firstNetworkNumber is
cableRange.firstNetworkNumber and
routingTableEntry->networkRange.lastNetworkNumber is
cableRange.lastNetworkNumber) {
// Check for "notify neighbor" telling us that an entry is bad.
if (numberOfHops is 31 and
routingTableEntry->nextRouter.networkNumber is
source.networkNumber and
routingTableEntry->nextRouter.nodeNumber is source.nodeNumber) {
// Don't "upgrade" route to PrettyBad from Bad...
if (routingTableEntry->entryState isnt Bad)
routingTableEntry->entryState = PrettyBad;
continue;
}
//
// If we're hearing about one of our directly connected nets, we
// know best... ignore the info.
//
if (routingTableEntry->numberOfHops is 0)
continue;
//
// Check for previously bad entry, and a short enough path
// with this tuple... if so, replace the entry.
//
if ((routingTableEntry->entryState is PrettyBad or
routingTableEntry->entryState is Bad) and
numberOfHops < 15) {
routingTableEntry->numberOfHops = (short)(numberOfHops + 1);
routingTableEntry->nextRouter.networkNumber =
source.networkNumber;
routingTableEntry->nextRouter.nodeNumber =
source.nodeNumber;
routingTableEntry->port = (short)port;
routingTableEntry->entryState = Good;
continue;
}
//
// Check fora shorter or equidistant path to the target network...
// if so, replace the entry.
//
if (routingTableEntry->numberOfHops >= numberOfHops + 1 and
numberOfHops < 15) {
routingTableEntry->numberOfHops = (short)(numberOfHops + 1);
routingTableEntry->nextRouter.networkNumber =
source.networkNumber;
routingTableEntry->nextRouter.nodeNumber =
source.nodeNumber;
routingTableEntry->port = (short)port;
routingTableEntry->entryState = Good;
continue;
}
//
// Check for the same router still thinking it has a path to the
// network, but it's further away now... if so, update the entry.
//
if (routingTableEntry->nextRouter.networkNumber is
source.networkNumber and
routingTableEntry->nextRouter.nodeNumber is
source.nodeNumber and
routingTableEntry->port is (short)port) {
routingTableEntry->numberOfHops = (short)(numberOfHops + 1);
if (routingTableEntry->numberOfHops < 16)
routingTableEntry->entryState = Good;
else
RemoveFromRoutingTable(cableRange);
continue;
}
continue;
}
//
// Otherwise, we need to walk through the entire routing table
// making sure the current tuple doesn't overlap with anything
// we already have (since it didn't exactly match) -- if we find
// an overlap, ignore the tuple (a network configuration error,
// no doubt), else add it as a new network range!
//
for (foundOverlap = False, indexToo = 0;
not foundOverlap and indexToo < NumberOfRtmpHashBuckets;
indexToo += 1)
for (routingTableEntry = routingTable[indexToo];
not foundOverlap and routingTableEntry isnt empty;
routingTableEntry = routingTableEntry->next)
if (RangesOverlap(&cableRange, &routingTableEntry->networkRange))
foundOverlap = True;
if (foundOverlap) {
ErrorLog("RtmpPacketInRouter", ISevWarning, __LINE__, port,
IErrFullRtmpOverlappingNets, IMsgFullRtmpOverlappingNets,
Insert0());
continue;
}
// Okay, enter this new network range!
nextRouter.networkNumber = source.networkNumber;
nextRouter.nodeNumber = source.nodeNumber;
if (numberOfHops < 15)
EnterIntoRoutingTable(cableRange, port, nextRouter,
numberOfHops + 1);
} // Walk through all of the tuples loop.
} // Protocol type is DdpProtocolRtmpResponseOrData
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
} // RtmpPacketInRouter
RoutingTableEntry far FindInRoutingTable(short unsigned networkNumber)
{
int index, recentRouteIndex;
RoutingTableEntry routingTableEntry;
// First, try the "recent route cache".
CheckMod(recentRouteIndex, networkNumber, NumberOfRecentRouteBuckets,
"FindInRoutingTable");
if (recentRoutes[recentRouteIndex] isnt empty and
IsWithinNetworkRange(networkNumber,
&recentRoutes[recentRouteIndex]->networkRange))
return(recentRoutes[recentRouteIndex]);
//
// Find a given network number in the RTMP routing table. We maintain the
// routing table as a hashed lookup structure based upon the first network
// of the given network range. First, check to see if we're lucky and the
// target network number is the start of a range...
//
CheckMod(index, networkNumber, NumberOfRtmpHashBuckets,
"FindInRoutingTable");
for (routingTableEntry = routingTable[index];
routingTableEntry isnt empty;
routingTableEntry = routingTableEntry->next)
if (routingTableEntry->networkRange.firstNetworkNumber is networkNumber)
break;
// Cache and return our find!
if (routingTableEntry isnt empty) {
recentRoutes[recentRouteIndex] = routingTableEntry;
return(routingTableEntry);
}
//
// Otherwise, we need to walk the entire routing table to see if this guy
// is within any range! Sigh. If found, cache the find.
//
for (index = 0; index < NumberOfRtmpHashBuckets; index += 1)
for (routingTableEntry = routingTable[index];
routingTableEntry isnt empty;
routingTableEntry = routingTableEntry->next)
if (IsWithinNetworkRange(networkNumber,
&routingTableEntry->networkRange)) {
recentRoutes[recentRouteIndex] = routingTableEntry;
return(routingTableEntry);
}
// Oops, nobody home!
return(empty);
} // FindInRoutingTable
Boolean far RemoveFromRoutingTable(AppleTalkNetworkRange networkRange)
{
int index;
RoutingTableEntry routingTableEntry, previousRoutingTableEntry = empty;
//
// Remove a given network number from the RTMP routing table. Return True
// if we can find/remove the network; False otherwise.
//
CheckMod(index, networkRange.firstNetworkNumber, NumberOfRtmpHashBuckets,
"RemoveFromRoutingTable");
for (routingTableEntry = routingTable[index];
routingTableEntry isnt empty;
routingTableEntry = routingTableEntry->next)
if (routingTableEntry->networkRange.firstNetworkNumber is
networkRange.firstNetworkNumber and
routingTableEntry->networkRange.lastNetworkNumber is
networkRange.lastNetworkNumber) {
// Unthread the guy who's leaving...
if (previousRoutingTableEntry is empty)
routingTable[index] = routingTableEntry->next;
else
previousRoutingTableEntry->next = routingTableEntry->next;
//
// Do a pass through the "recent router cache", remove this guy if
// he's there.
//
for (index = 0; index < NumberOfRecentRouteBuckets; index += 1)
if (recentRoutes[index] is routingTableEntry) {
recentRoutes[index] = empty;
break;
}
// Free the zone list and the actual routing table node.
FreeZoneList(routingTableEntry->zoneList);
Free(routingTableEntry);
// The deed is done.
return(True);
}
else
previousRoutingTableEntry = routingTableEntry;
return(False);
} // RemoveFromRoutingTable
ExternForVisibleFunction Boolean
GetOrSetNetworkNumber(int port,
unsigned int suggestedNetworkNumber)
{
// We use this beast for non-extended networks only!
//
// The plan here is not to mess up a working Internet. So,
// we'll send out a few RTMP request packets, if we can find the network
// number of the network, we'll use that one and ignore the one that was
// passed in. Otherwise, we'll use the one that was passed in, unless
// that is zero, in which case we'll blow the user away. A zero value for
// our argument indicates that the caller does not want to set the network
// network-number and we should expect to find at least one bridge already
// operating out there on the specified port.
//
BufferDescriptor buffer;
AppleTalkAddress source, destination;
int numberOfRequests = 0;
if (GET_PORTDESCRIPTOR(port)->ExtendedNetwork) {
ErrorLog("GetOrSetNetworkNumber", ISevError, __LINE__, port,
IErrFullRtmpSigh, IMsgFullRtmpSigh,
Insert0());
return(False);
}
// Set up the source, destination, and our very simple request packet.
source.networkNumber = destination.networkNumber = UnknownNetworkNumber;
source.nodeNumber =
GET_PORTDESCRIPTOR(port)->ActiveNodes->ExtendedNode.NodeNumber;
destination.nodeNumber = AppleTalkBroadcastNodeNumber;
source.socketNumber = destination.socketNumber = RtmpSocket;
//
// Blast a number of requests out on the wire, see if anybody will let us in
// on the network network-number.
//
while (not GET_PORTDESCRIPTOR(port)->SeenRouterRecently and
numberOfRequests < NumberOfRtmpRequests) {
// Build the request packet.
if ((buffer = NewBufferDescriptor(RtmpRequestDatagramSize)) is Empty) {
ErrorLog("GetOrSetNetworkNumber", ISevError, __LINE__, port,
IErrFullRtmpOutOfMemory, IMsgFullRtmpOutOfMemory,
Insert0());
return(False);
}
buffer->data[RtmpRequestCommandOffset] = RtmpRequestCommand;
if (not TransmitDdp(port, source, destination, DdpProtocolRtmpRequest,
buffer, RtmpRequestDatagramSize, 0, empty, empty,
Empty, 0)) {
ErrorLog("GetOrSetNetworkNumber", ISevError, __LINE__, port,
IErrFullRtmpBadReqSend, IMsgFullRtmpBadReqSend,
Insert0());
return(False);
}
numberOfRequests += 1;
WaitFor(RtmpRequestTimerInHundreths,
&GET_PORTDESCRIPTOR(port)->SeenRouterRecently);
}
// If we got an answer, we're set...
if (GET_PORTDESCRIPTOR(port)->SeenRouterRecently) {
if (suggestedNetworkNumber isnt UnknownNetworkNumber and
GET_PORTDESCRIPTOR(port)->ThisCableRange.FirstNetworkNumber isnt
(short unsigned)suggestedNetworkNumber)
ErrorLog("GetOrSetNetworkNumber", ISevWarning, __LINE__, port,
IErrFullRtmpIgnoredNet, IMsgFullRtmpIgnoredNet,
Insert0());
return(True);
}
//
// If we didn't get an answer, we had better have a suggested network number
// passed in.
//
if (suggestedNetworkNumber is UnknownNetworkNumber) {
ErrorLog("GetOrSetNetworkNumber", ISevError, __LINE__, port,
IErrFullRtmpNoSeedCantStart, IMsgFullRtmpNoSeedCantStart,
Insert0());
return(False);
}
GET_PORTDESCRIPTOR(port)->ThisCableRange.FirstNetworkNumber =
(short unsigned)suggestedNetworkNumber;
return(True);
} // GetOrSetNetworkNumber
ExternForVisibleFunction void
EnterIntoRoutingTable(AppleTalkNetworkRange networkRange,
int port,
ExtendedAppleTalkNodeNumber nextRouter,
int numberOfHops)
{
RoutingTableEntry routingTableEntry;
int index;
//
// Make a new entry in our RTMP routing table. We assume that we are passed
// a legitimate new entry (i.e. all range overlaps have already been checked
// for).
//
CheckMod(index, networkRange.firstNetworkNumber, NumberOfRtmpHashBuckets,
"EnterIntoRoutingTable");
if (networkRange.lastNetworkNumber is UnknownNetworkNumber)
networkRange.lastNetworkNumber = networkRange.firstNetworkNumber;
routingTableEntry = (RoutingTableEntry)Calloc(sizeof(*routingTableEntry), 1);
routingTableEntry->networkRange = networkRange;
routingTableEntry->port = (short)port;
routingTableEntry->nextRouter = nextRouter;
routingTableEntry->numberOfHops = (short)numberOfHops;
routingTableEntry->entryState = Good;
// Thread the new entry into the head of the hash list.
routingTableEntry->next = routingTable[index];
routingTable[index] = routingTableEntry;
} // EnterIntoRoutingTable
ExternForVisibleFunction void far RtmpSendTimerExpired(long unsigned timerId,
int additionalDataSize,
char far *additionalData)
{
AppleTalkAddress destination;
int port;
// "Use" unneeded actual parameters.
timerId, additionalDataSize, additionalData;
// Broadcast out each port a split horizon view of our routing tables.
destination.networkNumber = CableWideBroadcastNetworkNumber;
destination.nodeNumber = AppleTalkBroadcastNodeNumber;
destination.socketNumber = RtmpSocket;
for (port = 0; port < MaximumNumberOfPorts; port += 1)
if (GET_PORTDESCRIPTOR(port)->Flags & PD_ACTIVE and
GET_PORTDESCRIPTOR(port)->RouterRunning) {
DeferIncomingPackets();
SendRoutingData(port, destination, True);
HandleIncomingPackets();
}
// Re-arm the send RTMP timer...
StartTimer(RtmpSendTimerExpired, RtmpSendTimerSeconds, 0, empty);
// We've done the deed...
HandleDeferredTimerChecks();
return;
} // RtmpSendTimerExpired
ExternForVisibleFunction void far
RtmpValidityTimerExpired(long unsigned timerId,
int additionalDataSize,
char far *additionalData)
{
RoutingTableEntry routingTableEntry, nextRoutingTableEntry;
int index;
// "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();
// Walk the routing table aging the entries...
for (index = 0; index < NumberOfRtmpHashBuckets; index += 1)
for (routingTableEntry = routingTable[index];
routingTableEntry isnt empty;
routingTableEntry = nextRoutingTableEntry) {
// Get the next entry first, we may delete the current entry...
nextRoutingTableEntry = routingTableEntry->next;
switch (routingTableEntry->entryState) {
case Good:
if (routingTableEntry->numberOfHops isnt 0)
routingTableEntry->entryState = Suspect;
break;
case Suspect:
routingTableEntry->entryState = PrettyBad;
break;
case PrettyBad:
routingTableEntry->entryState = Bad;
break;
case Bad:
RemoveFromRoutingTable(routingTableEntry->networkRange);
break;
default:
ErrorLog("RtmpValidityTimerExpired", ISevError, __LINE__,
routingTableEntry->port,
IErrFullRtmpBadEntryState, IMsgFullRtmpBadEntryState,
Insert0());
RemoveFromRoutingTable(routingTableEntry->networkRange);
break;
}
}
// Re-arm the Validity timer...
StartTimer(RtmpValidityTimerExpired, RtmpValidityTimerSeconds, 0, empty);
// We've done the deed...
HandleIncomingPackets();
HandleDeferredTimerChecks();
return;
} // RtmpValidityTimerExpired
ExternForVisibleFunction void SendRoutingData(int port,
AppleTalkAddress destination,
Boolean doSplitHorizon)
{
RoutingTableEntry routingTableEntry;
BufferDescriptor datagram;
int index, hash, staticHeaderSize;
Boolean newPacket = True, unsentTuples = False;
AppleTalkAddress source;
long sourceSocket;
ExtendedAppleTalkNodeNumber sourceNode;
// First, compute the source socket: Rtmp socket on our routers node.
source.networkNumber = GET_PORTDESCRIPTOR(port)->ARouter.NetworkNumber;
source.nodeNumber = GET_PORTDESCRIPTOR(port)->ARouter.NodeNumber;
source.socketNumber = RtmpSocket;
if ((sourceSocket = MapAddressToSocket(port, source)) < ATnoError) {
//
// This may be okay during initialization... we're not started on all
// ports yet.
//
return;
}
//
// Set up the static header to an RTMP data datagram (routers net/node
// number). For half ports, since we really don't have such info fill in
// the address of the first non-half-port routing port.
//
if (GET_PORTDESCRIPTOR(port)->PortType isnt NonAppleTalkHalfPort)
sourceNode = GET_PORTDESCRIPTOR(port)->ARouter;
else {
for (index = 0; index < MaximumNumberOfPorts; index += 1)
if (GET_PORTDESCRIPTOR(index)->Flags & PD_ACTIVE and
GET_PORTDESCRIPTOR(index)->PortType isnt NonAppleTalkHalfPort and
GET_PORTDESCRIPTOR(index)->RouterRunning) {
sourceNode = GET_PORTDESCRIPTOR(index)->ARouter;
break;
}
//
// If we didn't find an address we like, just use the dummy one in
// our current port (no doubt net/node = 0).
//
if (index >= MaximumNumberOfPorts)
sourceNode = GET_PORTDESCRIPTOR(port)->ARouter;
}
// Get the first buffer descriptor.
if ((datagram = NewBufferDescriptor(MaximumDdpDatagramSize)) is Empty) {
ErrorLog("SendRoutingData", ISevError, __LINE__, port,
IErrFullRtmpOutOfMemory, IMsgFullRtmpOutOfMemory,
Insert0());
return;
}
//
// Walk through the routing table building a tuple for each network;
// we may have to send multiple packets...
//
for (hash = 0; hash < NumberOfRtmpHashBuckets; hash += 1)
for (routingTableEntry = routingTable[hash];
routingTableEntry isnt empty;
routingTableEntry = routingTableEntry->next) {
if (newPacket)
{
// Build the static part of an RtmpData packet.
MoveShortMachineToWire(datagram->data + RtmpSendersNetworkOffset,
sourceNode.networkNumber);
datagram->data[RtmpSendersIdLengthOffset] = 8; // Bits
datagram->data[RtmpSendersIdOffset] = sourceNode.nodeNumber;
//
// For non-extended networks we need the version stamp, for exteneded
// networks, we need to include a initial network range tuple as
// part of the header.
//
if (not GET_PORTDESCRIPTOR(port)->ExtendedNetwork) {
datagram->data[RtmpSendersIdOffset + 1] = 0;
datagram->data[RtmpSendersIdOffset + 2] = 0;
datagram->data[RtmpSendersIdOffset + 3] = RtmpVersionNumber;
//
staticHeaderSize = RtmpSendersIdOffset + 1 + 2 + 1; // + nodeID +
// filler +
// version
//
}
else {
datagram->data[RtmpRangeStartOffset] =
(char)((GET_PORTDESCRIPTOR(port)->ThisCableRange.
FirstNetworkNumber >> 8) & 0xFF);
datagram->data[RtmpRangeStartOffset + 1] =
(char)(GET_PORTDESCRIPTOR(port)->ThisCableRange.
FirstNetworkNumber & 0xFF);
datagram->data[RtmpRangeStartOffset + 2] = RtmpTupleWithRange;
datagram->data[RtmpRangeEndOffset] =
(char)((GET_PORTDESCRIPTOR(port)->ThisCableRange.
LastNetworkNumber >> 8) & 0xFF);
datagram->data[RtmpRangeEndOffset + 1] =
(char)(GET_PORTDESCRIPTOR(port)->ThisCableRange.
LastNetworkNumber & 0xFF);
datagram->data[RtmpRangeEndOffset + 2] = RtmpVersionNumber;
//
staticHeaderSize = RtmpRangeEndOffset + 2 + 1; // + last net number +
// version
//
#if Verbose and (IamNot a WindowsNT)
printf(" RTMP Tuple: port %d; net \"%d:%d\"; distance %d.\n", port,
GET_PORTDESCRIPTOR(port)->ThisCableRange.FirstNetworkNumber,
GET_PORTDESCRIPTOR(port)->ThisCableRange.LastNetworkNumber,
0);
#endif
}
//
// Start of a new packet full of tuples; set the packet index to
// the start up the tuples.
//
index = staticHeaderSize;
newPacket = False;
}
//
// Should the current tuple be omitted due to split horizon
// processing?
//
if (doSplitHorizon)
if (routingTableEntry->numberOfHops isnt 0)
if (routingTableEntry->port is port)
continue;
// Okay, place the tuple in the packet...
datagram->data[index++] =
(char)(routingTableEntry->networkRange.firstNetworkNumber >> 8);
datagram->data[index++] =
(char)(routingTableEntry->networkRange.firstNetworkNumber & 0xFF);
// Do "notify nieghbor" if our current state is bad.
if (routingTableEntry->entryState is PrettyBad or
routingTableEntry->entryState is Bad)
datagram->data[index++] = RtmpNumberOfHopsMask;
else
datagram->data[index++] = (char)(routingTableEntry->numberOfHops &
RtmpNumberOfHopsMask);
//
// Send an extended tuple if the network range isn't one or the target
// port is an extended network.
//
if (GET_PORTDESCRIPTOR(port)->ExtendedNetwork or
routingTableEntry->networkRange.firstNetworkNumber isnt
routingTableEntry->networkRange.lastNetworkNumber) {
datagram->data[index - 1] |= RtmpExtendedTupleMask;
datagram->data[index++] =
(char)(routingTableEntry->networkRange.lastNetworkNumber >> 8);
datagram->data[index++] =
(char)(routingTableEntry->networkRange.lastNetworkNumber & 0xFF);
datagram->data[index++] = RtmpVersionNumber;
}
#if Verbose and (IamNot a WindowsNT)
printf(" RTMP Tuple: port %d; net \"%d:%d\"; distance %d.\n", port,
routingTableEntry->networkRange.firstNetworkNumber,
routingTableEntry->networkRange.lastNetworkNumber,
routingTableEntry->numberOfHops);
#endif
unsentTuples = True;
// Send a data packet if we're full...
if (index + RtmpExtendedTupleSize >= MaximumDdpDatagramSize) {
// Send the DDP packet...
if (DeliverDdp(sourceSocket, destination,
DdpProtocolRtmpResponseOrData,
datagram, index, Empty, Empty, 0) isnt ATnoError)
ErrorLog("SendRoutingData", ISevError, __LINE__, port,
IErrFullRtmpBadDataSend, IMsgFullRtmpBadDataSend,
Insert0());
// Get the next buffer descriptor.
if ((datagram = NewBufferDescriptor(MaximumDdpDatagramSize)) is
Empty) {
ErrorLog("SendRoutingData", ISevError, __LINE__, port,
IErrFullRtmpOutOfMemory, IMsgFullRtmpOutOfMemory,
Insert0());
return;
}
newPacket = True;
unsentTuples = False;
}
}
//
// If "unsentTuples" is set then we have a partial packet that we need
// to send.
//
if (unsentTuples) {
if (DeliverDdp(sourceSocket, destination,
DdpProtocolRtmpResponseOrData,
datagram, index, Empty, Empty, 0) isnt ATnoError)
ErrorLog("SendRoutingData", ISevError, __LINE__, port,
IErrFullRtmpBadDataSend, IMsgFullRtmpBadDataSend,
Insert0());
}
else
FreeBufferChain(datagram); // Free unused buffer chain.
// The deed is done.
return;
} // SendRoutingData
#if (Verbose and (IamNot a WindowsNT)) or (Iam a Primos)
void DumpRtmpRoutingTable(void)
{
RoutingTableEntry routingTableEntry;
int index;
ZoneList zone;
char *p;
DeferTimerChecking();
DeferIncomingPackets();
// Dump the RTMP routing tables for debugging.
printf("********** RTMP routing table start:\n");
for (index = 0; index < NumberOfRtmpHashBuckets; index += 1)
for (routingTableEntry = routingTable[index];
routingTableEntry isnt empty;
routingTableEntry = routingTableEntry->next) {
printf("Range %05u:%05u; port %d; state %d; hops %02d; "
"next bridge %u.%u.\n",
routingTableEntry->networkRange.firstNetworkNumber,
routingTableEntry->networkRange.lastNetworkNumber,
routingTableEntry->port,
routingTableEntry->entryState,
routingTableEntry->numberOfHops,
routingTableEntry->nextRouter.networkNumber,
routingTableEntry->nextRouter.nodeNumber);
p = " ZoneList = ";
for (zone = routingTableEntry->zoneList;
zone isnt empty;
zone = zone->next) {
printf("%s%s\n", p, zone->zone);
p = " ";
}
}
printf("********** RTMP routing table end.\n");
HandleIncomingPackets();
HandleDeferredTimerChecks();
return;
} // DumpRtmpRoutingTable
#endif
#endif