/* Router.c, atalk-ii/router, Garth Conboy, 01/15/90 */ /* Copyright (c) 1989 by Pacer Software Inc., La Jolla, CA */ /* GC - Initial coding. GC - (08/18/90): New error logging mechanism. GC - (10/09/91): When handling "nnnn00" destinations, note that the router may not have started on the first network network number of the cable's range! GC - (03/31/92): Updated for BufferDescriptors. GC - (09/15/92): Handle the case of a packet coming in on the wrong port (not the default port) destined for one of our proxy nodes (AppleTalk Remote Access). *** Make the PVCS source control system happy: $Header$ $Log$ *** The AppleTalk phase II router. This routine, of course, depends on the routing tables which are maintained by "fullrmtp.c". Pretty interesting that a routine with a name like "Router()" is less than 200 lines long... Because we call "TransmitDdp" the datagram that we recieve must have at least "MaximumHeaderLength + LongDdpHeaderLength" bytes ahead of it for prepending hardware/802.2/DDP headers! */ #define IncludeRouterErrors 1 #include "atalk.h" #if IamNot an AppleTalkRouter /* Empty file */ #else void _near _fastcall Router(int port, AppleTalkAddress source, AppleTalkAddress destination, int protocolType, char far *datagram, int datagramLength, int numberOfHops, Boolean prependHeadersInPlace) { RoutingTableEntry routingTableEntry; OpenSocket openSocket; Boolean delivered = False, broadcastNode; ActiveNode activeNode; int targetPort; short unsigned originalDestinationNetwork; BufferDescriptor packet; Boolean error = False; /* This algorithm was taken from the "AppleTalk Phase 2 Protocol Specification" as might be expected. */ broadcastNode = (destination.nodeNumber is AppleTalkBroadcastNodeNumber); /* If the destination network number is within the range of the reception port's network range and the destination node number is broadcast, then we can drop the packet on the floor -- it is a network specific broadcast not for this router. Note that we've already delivered the packet, and thus not gotten here, if it was really addressed to the network of any node owned by the reception port (in DdpPacketIn). */ if (IsWithinNetworkRange(destination.networkNumber, &portDescriptors[port].thisCableRange) and broadcastNode) return; /* Keep private... playing with the routing tables... */ DeferTimerChecking(); DeferIncomingPackets(); /* Try to find an entry in the routing table that contains the target network. If not found, discard the woeful packet. */ if ((routingTableEntry = FindInRoutingTable(destination.networkNumber)) is empty) { HandleIncomingPackets(); HandleDeferredTimerChecks(); return; } /* If the target network's hop count is non-zero, we really need to send the beast, so, just do it! */ if (routingTableEntry->numberOfHops isnt 0) { if (numberOfHops < 15) { /* Build a buffer descriptor; copy the packet if we can't depend on the data being around for the transmit to complete. Under WindowsNT we don't own the incoming data, so we can't hold onto it until an outgoing transmit completes.*/ if (TransmitsCompleteSynchronously and prependHeadersInPlace and (IamNot a WindowsNT)) { if ((packet = DescribeBuffer(datagramLength, datagram, False)) is Empty) error = True; else packet->prependInPlace = True; } else { if ((packet = NewBufferDescriptor(datagramLength)) is Empty) error = True; else MoveMem(packet->data, datagram, datagramLength); } if (error) { ErrorLog("Router", ISevError, __LINE__, port, IErrRouterOutOfMemory, IMsgRouterOutOfMemory, Insert0()); HandleIncomingPackets(); HandleDeferredTimerChecks(); return; } if (not TransmitDdp(routingTableEntry->port, source, destination, protocolType, packet, datagramLength, numberOfHops + 1, Empty, &routingTableEntry->nextRouter, Empty, 0)) ErrorLog("Router", ISevWarning, __LINE__, routingTableEntry->port, IErrRouterBadTransmit, IMsgRouterBadTransmit, Insert0()); } HandleIncomingPackets(); HandleDeferredTimerChecks(); return; } /* If the destination node is zero, the packet is really destined for the router's node on this port. */ targetPort = routingTableEntry->port; if (destination.nodeNumber is AnyRouterNodeNumber) { originalDestinationNetwork = destination.networkNumber; destination.networkNumber = portDescriptors[targetPort].aRouter.networkNumber; destination.nodeNumber = portDescriptors[targetPort].aRouter.nodeNumber; if ((openSocket = MapAddressToOpenSocket(targetPort, destination)) isnt empty) { destination.networkNumber = originalDestinationNetwork; destination.nodeNumber = AnyRouterNodeNumber; InvokeSocketHandler(openSocket, targetPort, source, protocolType, datagram, datagramLength, destination); /* The above call does undefer... */ } else { HandleIncomingPackets(); HandleDeferredTimerChecks(); } return; } /* We're finished with the routing tables... */ HandleIncomingPackets(); HandleDeferredTimerChecks(); /* Okay, now walk through the nodes on the target port, looking for a home for this packet. */ for (activeNode = portDescriptors[targetPort].activeNodes; activeNode isnt empty; activeNode = activeNode->next) { /* Is the packet for us? */ if (destination.networkNumber is activeNode->extendedNode.networkNumber and (broadcastNode or destination.nodeNumber is activeNode->extendedNode.nodeNumber)) { /* If for one of our proxy nodes, just blast it out. */ if (activeNode->proxyNode) { if ((packet = NewBufferDescriptor(datagramLength)) is Empty) { ErrorLog("Router", ISevError, __LINE__, port, IErrRouterOutOfMemory, IMsgRouterOutOfMemory, Insert0()); continue; } MoveMem(packet->data, datagram, datagramLength); if (not TransmitDdp(activeNode->proxyPort, source, destination, protocolType, packet, datagramLength, numberOfHops + 1, Empty, Empty, Empty, 0)) ErrorLog("Router", ISevWarning, __LINE__, activeNode->proxyPort, IErrRouterBadTransmit, IMsgRouterBadTransmit, Insert0()); delivered = True; continue; } /* Broadcast trys all nodes. */ if (broadcastNode) destination.nodeNumber = activeNode->extendedNode.nodeNumber; DeferTimerChecking(); DeferIncomingPackets(); if ((openSocket = MapAddressToOpenSocket(targetPort, destination)) isnt empty) { if (broadcastNode) destination.nodeNumber = AppleTalkBroadcastNodeNumber; InvokeSocketHandler(openSocket, targetPort, source, protocolType, datagram, datagramLength, destination); delivered = True; } else { HandleIncomingPackets(); HandleDeferredTimerChecks(); } } } /* Do we need to deliver the packet to a local port's network? */ if (not delivered or broadcastNode) { if (broadcastNode) destination.nodeNumber = AppleTalkBroadcastNodeNumber; if (numberOfHops < 15) { /* Build a buffer descriptor; copy the packet if we can't depend on the data being around for the transmit to complete. Under WindowsNT we don't own the incoming data, so we can't hold onto it until an outgoing transmit completes. */ if (TransmitsCompleteSynchronously and prependHeadersInPlace and (IamNot a WindowsNT)) { if ((packet = DescribeBuffer(datagramLength, datagram, False)) is Empty) error = True; else packet->prependInPlace = True; } else { if ((packet = NewBufferDescriptor(datagramLength)) is Empty) error = True; else MoveMem(packet->data, datagram, datagramLength); } if (error) { ErrorLog("Router", ISevError, __LINE__, port, IErrRouterOutOfMemory, IMsgRouterOutOfMemory, Insert0()); return; } if (not TransmitDdp(targetPort, source, destination, protocolType, packet, datagramLength, numberOfHops + 1, Empty, Empty, Empty, 0)) ErrorLog("Router", ISevError, __LINE__, targetPort, IErrRouterBadTransmit, IMsgRouterBadTransmit, Insert0()); } } /* The deed is done. */ return; } /* Router */ #endif