/* initial.c, /appletalk/source, Garth Conboy, 10/04/88 */ /* Copyright (c) 1988 by Pacer Software Inc., La Jolla, CA */ /* GC - Initial coding. GC - (11/25/89): Pretty much rewrote for AppleTalk phase II support; no internal network; operation without a router. GC - (08/18/90): New error logging mechanism. GC - (10/04/90): Added HalfPort support. GC - (11/12/90): We now allow non-seed routing ports; see comments below for restrictions. GC - (01/20/92): Added dynamic port assignment support; new field, desiredPort, in the PortInfo structure. GC - (01/20/92): Added ShutdownPort(). GC - (02/07/92): Added PRAM address support. GC - (04/02/92): Added AppleTalkRemoteAccess support. GC - (04/21/92): Note for someday, we should add a DeInitialize() to do: o Cancel all timers & stop timer handling o Force shutdown all ports & nodes o Free all routing info o De-register all protocol handlers o Un-initialize the Des package o Stop allocation of nodes/sockets GC - (06/29/92): Broke "defaultOrDesiredZone" into two fields. GC - (07/07/92): Opaque data descriptors to NbpAction(). GC - (07/24/92): Undid above change. GC - (08/21/92): Added first cut at UnloadAppleTalk(). GC - (12/07/92): Tuned the above for an MP environment and added locks and reference counts as needed. *** Make the PVCS source control system happy: $Header$ $Log$ *** Initialization for the Pacer AppleTalk stack and/or router. This routine takes an array of structures as its main argument. These describe the network configuration of each physical port that the stack or router should be able to communicate on. This may now be done piece-meal, not starting all ports at once. If Iam an AppleTalkStack, that is, not just an AppleTalkRouter, the first call to Initialize() must specify a defaultPort and this port cannot subsequently be shutdown. A maxmimum of MaximumNumberOrPorts (from "ports.h") ports are currently supported. 11/12/90: We now allow non-seed router ports. This can pose an interesting problem in the case where "Iam an AppleTalkStack" AND "Iam an AppleTalkRouter" for the "default port". The default port is where all "user node/sockets" are allocated. Also, remember that no user sockets are ever allocated on the router's node; a routing port, that is the default port, that has user services running on it, will always have at least two nodes, one for the router and at least one for user stuff. Imagine, if you will, a case where the default port is a non-seed routing port and "user services" (e.g. a file server) start before the router can be started, due to lack of a seed router. Further imagine that the user services start in the wrong network range (maybe the startup range). Now, imagine that a seed router finally comes up, and somebody starts the router. The router's node on the port will want ot be in the correct network range so it can start routing. We, however, don't want to "move" any user nodes because that would break any active connections. What we do is: tag any user nodes that are now in the wrong range as "orphaned". These nodes will be released when the last user socket closes on them. All further user socket open requests will be handled on new nodes that are allocated in the correct range. Got that? The only price we pay for this way cool scheme is that on LocalTalk (where only a single node is allowed) we cannot allow the port to BOTH route and be the default port. LocalTalk ports can, however, be routing ports OR be stack-only default ports. Anyhow, why would anybody want a LocalTalk port to be a default port? N.B. There is currently no lock-out between Initialize() and UnloadAppleTalk() or ShutdownPort() -- the caller must ensure that calls to either of the latter two routines do not "interrupt" an active call to Initialize(). */ #define IncludeInitialErrors 1 #include "atalk.h" ExternForVisibleFunction NbpCompletionHandler OurRegisterComplete; ExternForVisibleFunction Boolean CopyInitializationInfo(int sourcePort, PortInfo portInfo[], int targetPort); static Boolean ourRegisterCompleteFlag; static AppleTalkErrorCode ourRegisterErrorCode; Boolean far Initialize(int numberOfPorts, PortInfo portInfo[]) { int index, indexToo, targetPort, defaultPort; Boolean foundDefaultPort = False, foundDefaultZone, foundDesiredZone; ZoneList zoneList; PortHandlers portHandlers; Boolean extendedNetworkPort; Boolean halfPort, remoteAccess; Boolean anyRemoteAccessPorts = False; /* Loop through all currently active ports to see if one is already the default port. */ for (index = 0; index < MaximumNumberOfPorts; index += 1) if (PortDescriptor(index)->portActive) if (PortDescriptor(index)->defaultPort) foundDefaultPort = True; else if (PortDescriptor(index)->portType is AppleTalkRemoteAccess) anyRemoteAccessPorts = True; /* Do a little error checking... conditional compilation based on whether we're being built as a router or not. */ for (index = 0; index < numberOfPorts; index += 1) { /* Valid port types? */ switch(portInfo[index].portType) { case LocalTalkNetwork: case EthernetNetwork: case TokenRingNetwork: case FddiNetwork: case NonAppleTalkHalfPort: #if ArapIncluded case AppleTalkRemoteAccess: #endif break; default: ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadPortType, IMsgInitialBadPortType, Insert0()); return(False); } extendedNetworkPort = (portInfo[index].portType isnt LocalTalkNetwork); /* Desired port must either be valid or -1 (meaning we should choose one). */ if (portInfo[index].desiredPort isnt DynamicPort and (portInfo[index].desiredPort < 0 or portInfo[index].desiredPort >= MaximumNumberOfPorts)) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadDesiredPort, IMsgInitialBadDesiredPort, Insert0()); return(False); } /* Check HalfPort specific stuff. */ halfPort = (portInfo[index].portType is NonAppleTalkHalfPort); if (halfPort) { /* Do we like the HalfPort type? */ if (portInfo[index].protocolInfo < FirstValidHalfPortType or portInfo[index].protocolInfo > LastValidHalfPortType) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadHalfPortType, IMsgInitialBadHalfPortType, Insert0()); return(False); } /* HalfPorts gotta route. */ if (not portInfo[index].routingPort) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialNonRoutingHalfPort, IMsgInitialNonRoutingHalfPort, Insert0()); return(False); } } /* Check remote access stuff. */ remoteAccess = (portInfo[index].portType is AppleTalkRemoteAccess); if (remoteAccess) { anyRemoteAccessPorts = True; /* Do we like the RemoteAccess type? */ if (portInfo[index].protocolInfo < FirstValidRemoteAccessType or portInfo[index].protocolInfo > LastValidRemoteAccessType) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadRemoteAccessType, IMsgInitialBadRemoteAccessType, Insert0()); return(False); } /* Remote access ports can't route. */ if (portInfo[index].routingPort or portInfo[index].startRouter) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialRoutingRemoteAccess, IMsgInitialRoutingRemoteAccess, Insert0()); return(False); } } /* Other odd link checking. */ if (halfPort or remoteAccess) { /* We don't really have networks, so we can't seed. */ if (portInfo[index].seedRouter or portInfo[index].networkRange.firstNetworkNumber isnt UnknownNetworkNumber or portInfo[index].zoneList isnt empty or portInfo[index].defaultZone isnt empty or portInfo[index].desiredZone isnt empty) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialCantSeed, IMsgInitialCantSeed, Insert0()); return(False); } /* No network, so can't be the default port! */ if (portInfo[index].defaultPort) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialCantBeDefault, IMsgInitialCantBeDefault, Insert0()); return(False); } /* No network, no PRAM! */ if (portInfo[index].routersPRamStartupNode.networkNumber isnt UnknownNetworkNumber or portInfo[index].usersPRamStartupNode.networkNumber isnt UnknownNetworkNumber) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialCantHavePram, IMsgInitialCantHavePram, Insert0()); return(False); } } /* Check remote access configuration info. */ if (remoteAccess and portInfo[index].remoteAccessConfigurationInfo is Empty) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialNoRemoteConfig, IMsgInitialNoRemoteConfig, Insert0()); return(False); } else if (not remoteAccess and portInfo[index].remoteAccessConfigurationInfo isnt Empty) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialCantConfigRemote, IMsgInitialCantConfigRemote, Insert0()); return(False); } if (remoteAccess and portInfo[index].remoteAccessConfigurationInfo->serverName isnt Empty) if (strlen(portInfo[index].remoteAccessConfigurationInfo-> serverName) > ArapSvrStartSvrNameSize) { portInfo[index].remoteAccessConfigurationInfo->serverName = Empty; ErrorLog("Initialize", ISevWarning, __LINE__, index, IErrInitialBadServerName, IMsgInitialBadServerName, Insert0()); } /* Check port name. */ if (portInfo[index].portName isnt empty) if (strlen(portInfo[index].portName) > MaximumPortNameLength) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadPortName, IMsgInitialBadPortName, Insert0()); return(False); } /* Check for valid routing flags. */ #if Iam an AppleTalkRouter if (not portInfo[index].routingPort and portInfo[index].startRouter) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadRouterFlags, IMsgInitialBadRouterFlags, Insert0()); return(False); } #else if (portInfo[index].routingPort or portInfo[index].startRouter) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialNoRouter, IMsgInitialNoRouter, Insert0()); return(False); } #endif /* Valid network range or none? */ if (portInfo[index].networkRange.firstNetworkNumber isnt UnknownNetworkNumber) { if (extendedNetworkPort) if (not CheckNetworkRange(portInfo[index].networkRange)) return(False); else /* Okay */ ; else if (portInfo[index].networkRange.lastNetworkNumber isnt UnknownNetworkNumber and portInfo[index].networkRange.lastNetworkNumber isnt portInfo[index].networkRange.firstNetworkNumber) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialLocalTalkNetRange, IMsgInitialLocalTalkNetRange, Insert0()); return(False); } /* Check for range overlap with any other new seeds. */ for (indexToo = 0; indexToo < numberOfPorts; indexToo += 1) if (indexToo isnt index) if (portInfo[indexToo].networkRange.firstNetworkNumber isnt UnknownNetworkNumber) if (RangesOverlap(&portInfo[indexToo].networkRange, &portInfo[index].networkRange)) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialRangeOverlap, IMsgInitialRangeOverlap, Insert0()); return(False); } /* We also need to check for range overlap with any other currently active ports. */ for (indexToo = 0; indexToo < MaximumNumberOfPorts; indexToo += 1) if (PortDescriptor(indexToo)->portActive and PortDescriptor(indexToo)->seenRouterRecently) if (RangesOverlap(&PortDescriptor(indexToo)->thisCableRange, &portInfo[index].networkRange)) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialRangeOverlap, IMsgInitialRangeOverlap, Insert0()); return(False); } /* If we have PRAM values, they must be in this range. */ if (portInfo[index].routersPRamStartupNode.networkNumber isnt UnknownNetworkNumber and not IsWithinNetworkRange(portInfo[index].routersPRamStartupNode.networkNumber, &portInfo[index].networkRange)) { ErrorLog("Initialize", ISevWarning, __LINE__, index, IErrInitialPRamNotInRange, IMsgInitialPRamNotInRange, Insert0()); portInfo[index].routersPRamStartupNode.networkNumber = UnknownNetworkNumber; portInfo[index].routersPRamStartupNode.nodeNumber = UnknownNodeNumber; } if (portInfo[index].usersPRamStartupNode.networkNumber isnt UnknownNetworkNumber and not IsWithinNetworkRange(portInfo[index].usersPRamStartupNode.networkNumber, &portInfo[index].networkRange)) { ErrorLog("Initialize", ISevWarning, __LINE__, index, IErrInitialPRamNotInRange, IMsgInitialPRamNotInRange, Insert0()); portInfo[index].usersPRamStartupNode.networkNumber = UnknownNetworkNumber; portInfo[index].usersPRamStartupNode.nodeNumber = UnknownNodeNumber; } } /* Check default/desired zone field. */ if (not extendedNetworkPort and (portInfo[index].desiredZone isnt empty or portInfo[index].defaultZone isnt empty)) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialZoneNotAllowed, IMsgInitialZoneNotAllowed, Insert0()); return(False); } if ((portInfo[index].desiredZone isnt empty and (portInfo[index].desiredZone[0] is 0 or strlen(portInfo[index].desiredZone) > MaximumZoneLength)) or (portInfo[index].defaultZone isnt empty and (portInfo[index].defaultZone[0] is 0 or strlen(portInfo[index].defaultZone) > MaximumZoneLength))) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadZone, IMsgInitialBadZone, Insert0()); return(False); } /* Check zone stuff based on our router/stack-ness. If we're a seed router ALL seeding information must be present. */ if (not portInfo[index].seedRouter) { if (portInfo[index].zoneList isnt empty) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialZonesForNonSeed, IMsgInitialZonesForNonSeed, Insert0()); return(False); } } else { if (portInfo[index].networkRange.firstNetworkNumber is UnknownNetworkNumber) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialNetRangeNeeded, IMsgInitialNetRangeNeeded, Insert0()); return(False); } if (extendedNetworkPort) { if (portInfo[index].zoneList is empty or portInfo[index].defaultZone is empty) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialZoneInfoNeeded, IMsgInitialZoneInfoNeeded, Insert0()); return(False); } if (ElementsOnList(portInfo[index].zoneList) > MaximumZonesPerNetwork) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialTooManyZones, IMsgInitialTooManyZones, Insert0()); return(False); } } else { if (portInfo[index].zoneList is empty or portInfo[index].defaultZone isnt empty) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadZoneInfo, IMsgInitialBadZoneInfo, Insert0()); return(False); } if (ElementsOnList(portInfo[index].zoneList) isnt 1) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialOneZoneOnly, IMsgInitialOneZoneOnly, Insert0()); return(False); } } } /* Validate zone list and make sure the default zone is on the list (if present). */ for (zoneList = portInfo[index].zoneList, foundDefaultZone = False, foundDesiredZone = False; zoneList isnt empty; zoneList = zoneList->next) { if (zoneList->zone[0] is 0 or strlen(zoneList->zone) > MaximumZoneLength) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadZoneList, IMsgInitialBadZoneList, Insert0()); return(False); } if (portInfo[index].defaultZone isnt empty) if (CompareCaseInsensitive(portInfo[index].defaultZone, zoneList->zone)) foundDefaultZone = True; if (portInfo[index].desiredZone isnt empty) if (CompareCaseInsensitive(portInfo[index].desiredZone, zoneList->zone)) foundDesiredZone = True; } if (portInfo[index].zoneList isnt empty and ((portInfo[index].defaultZone isnt empty and not foundDefaultZone) or (portInfo[index].desiredZone isnt empty and not foundDesiredZone))) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialZoneNotOnList, IMsgInitialZoneNotOnList, Insert0()); return(False); } /* Only one default port allowed. */ if (foundDefaultPort and portInfo[index].defaultPort) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadDefault, IMsgInitialBadDefault, Insert0()); return(False); } if (portInfo[index].defaultPort) { foundDefaultPort = True; /* Default port had better be on a real network! */ if (portInfo[index].portType is NonAppleTalkHalfPort or portInfo[index].portType is AppleTalkRemoteAccess) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadDefaultToo, IMsgInitialBadDefaultToo, Insert0()); return(False); } } /* Okay, things look pretty good for this new port. Find an actual port to use: the explicitly requested port must be available, if such a request was made; else we'll settle for any port. */ targetPort = DynamicPort; if (portInfo[index].desiredPort isnt DynamicPort) { if (not PortDescriptor(portInfo[index].desiredPort)->portActive) targetPort = portInfo[index].desiredPort; } else for (indexToo = 0; indexToo < MaximumNumberOfPorts; indexToo += 1) if (not PortDescriptor(indexToo)->portActive) { targetPort = indexToo; portInfo[index].desiredPort = indexToo; /* Tell our caller */ break; } /* Run away if we haven't found a port. */ if (targetPort is DynamicPort) { ErrorLog("Initialize", ISevFatal, __LINE__, index, IErrInitialBadDesiredPort, IMsgInitialBadDesiredPort, Insert0()); return(False); } /* Okay, tag our new port. */ PortDescriptor(targetPort)->portActive = True; /* If remote access, allocate the remoteAccessInfo node. */ #if ArapIncluded if (remoteAccess and PortDescriptor(targetPort)->remoteAccessInfo is Empty) { RemoteAccessInfo remoteAccessInfo; if ((remoteAccessInfo = Calloc(sizeof(*PortDescriptor(targetPort)->remoteAccessInfo), 1)) is Empty) { ErrorLog("Initialize", ISevFatal, __LINE__, targetPort, IErrInitialMallocFailed, IMsgInitialMallocFailed, Insert0()); PortDescriptor(targetPort)->portActive = False; return(False); } TakeLock(ArapLock); PortDescriptor(targetPort)->remoteAccessInfo = Link(remoteAccessInfo); PortDescriptor(targetPort)->remoteAccessInfo->port = targetPort; ReleaseLock(ArapLock); } #endif /* Copy initialization info into the port descriptor. */ if (not CopyInitializationInfo(index, portInfo, targetPort)) { PortDescriptor(targetPort)->portActive = False; return(False); } #if Iam an AppleTalkRouter PortDescriptor(targetPort)->uniqueId = UniqueNumber(); #endif /* Do any controller initialization that may be needed. */ portHandlers = &portSpecificInfo[portInfo[index].portType]; if (not (*portHandlers->initializeController)(targetPort, portInfo[index].controllerInfo)) { ErrorLog("Initialize", ISevFatal, __LINE__, targetPort, IErrInitialCouldNotInit, IMsgInitialCouldNotInit, Insert0()); PortDescriptor(targetPort)->portActive = False; return(False); } /* Okay, try to find the hardware address of this port. */ if (portHandlers->findMyAddress isnt empty) if (not (*portHandlers->findMyAddress)(targetPort, portInfo[index].controllerInfo, PortDescriptor(targetPort)->myAddress)) { /* This is sort-of equivalent to not being able to find your ass with your own two hands... */ ErrorLog("Initialize", ISevFatal, __LINE__, targetPort, IErrInitialOhMy, IMsgInitialOhMy, Insert0()); PortDescriptor(targetPort)->portActive = False; return(False); } /* Direct AARP and AppleTalk protocols to their respective handlers. No AARPing on LocalTalk or half ports or Arap ports. */ if (portInfo[index].portType isnt LocalTalkNetwork and not halfPort and not remoteAccess) if (not (*portHandlers->sendPacketsTo)(targetPort, AddressResolution, portHandlers->packetInAARP)) { ErrorLog("Initialize", ISevFatal, __LINE__, targetPort, IErrInitialCouldNotCatchAarp, IMsgInitialCouldNotCatchAarp, Insert0()); PortDescriptor(targetPort)->portActive = False; return(False); } if (not (*portHandlers->sendPacketsTo)(targetPort, AppleTalk, portHandlers->packetInAT)) { ErrorLog("Initialize", ISevFatal, __LINE__, targetPort, IErrInitialCouldNotCatchAt, IMsgInitialCouldNotCatchAt, Insert0()); PortDescriptor(targetPort)->portActive = False; return(False); } /* Set up initial values for this-cable-range. */ if (PortDescriptor(targetPort)->extendedNetwork and not halfPort and not remoteAccess) { PortDescriptor(targetPort)->thisCableRange.firstNetworkNumber = FirstValidNetworkNumber; PortDescriptor(targetPort)->thisCableRange.lastNetworkNumber = LastStartupNetworkNumber; } else PortDescriptor(targetPort)->thisCableRange.firstNetworkNumber = PortDescriptor(targetPort)->thisCableRange.lastNetworkNumber = UnknownNetworkNumber; /* For a remote access port, set the initial state. */ #if ArapIncluded if (remoteAccess) PortDescriptor(targetPort)->remoteAccessInfo->state = ArapNotInitialized; #endif } /* Okay, now we'll want to be able to open sockets, get nodes, and find our default port, start timers, etc. */ if (not appleTalkRunning) { InitializeTimers(); /* We now have Arap support... initialize the Des package. */ if (desinit(0) isnt 0) { ErrorLog("Initialize", ISevFatal, __LINE__, UnknownPort, IErrInitialMallocFailed, IMsgInitialMallocFailed, Insert0()); UnloadAppleTalk(); return(False); } } appleTalkRunning = True; /* If we're a stack, not just a router, we need a default port. Remote access needs a default port too! */ if ((Iam an AppleTalkStack) or anyRemoteAccessPorts) { if (not foundDefaultPort or (defaultPort = FindDefaultPort()) < 0) { ErrorLog("Initialize", ISevFatal, __LINE__, UnknownPort, IErrInitialNoDefaultPort, IMsgInitialNoDefaultPort, Insert0()); UnloadAppleTalk(); return(False); } } /* If we're built as a router, start up the router on any requested ports. Otherwise, put our RTMP ears on (get a node on each port). */ #if Iam an AppleTalkRouter for (index = 0; index < numberOfPorts; index += 1) { if (portInfo[index].startRouter) StartRouterOnPort(portInfo[index].desiredPort); } #endif for (index = 0; index < numberOfPorts; index += 1) if (not PortDescriptor(portInfo[index].desiredPort)->routerRunning and portInfo[index].portType isnt AppleTalkRemoteAccess) if (GetNodeOnPort(portInfo[index].desiredPort, True, True, False, empty) isnt ATnoError) ErrorLog("Initialize", ISevError, __LINE__, index, IErrInitialCouldNotGetNode, IMsgInitialCouldNotGetNode, Insert0()); /* Register our name on all of our new ports... */ for (index = 0; index < numberOfPorts; index += 1) if (portInfo[index].portType isnt NonAppleTalkHalfPort and portInfo[index].portType isnt AppleTalkRemoteAccess and PortDescriptor(portInfo[index].desiredPort)->activeNodes isnt Empty) RegisterOurName(portInfo[index].desiredPort); /* For each new remote access port we need to allocate a proxy node on the default port. */ #if ArapIncluded for (index = 0; index < numberOfPorts; index += 1) if (portInfo[index].portType is AppleTalkRemoteAccess) { if (GetNodeOnPort(defaultPort, True, True, False, empty) isnt ATnoError) { ErrorLog("Initialize", ISevError, __LINE__, index, IErrInitialCouldNotGetNode, IMsgInitialCouldNotGetNode, Insert0()); continue; } /* New node is now first on list... set it up as a proxy node. */ TakeLock(DdpLock); PortDescriptor(defaultPort)->activeNodes->proxyNode = True; PortDescriptor(defaultPort)->activeNodes->proxyPort = portInfo[index].desiredPort; PortDescriptor(portInfo[index].desiredPort)->remoteAccessInfo-> proxyNode = Link(PortDescriptor(defaultPort)->activeNodes); PortDescriptor(portInfo[index].desiredPort)->remoteAccessInfo-> proxyPort = defaultPort; ReleaseLock(DdpLock); /* Close the static sockets on the proxy node, they're not needed. */ CloseSocketOnNodeIfOpen(defaultPort, PortDescriptor(defaultPort)->activeNodes-> extendedNode, NamesInformationSocket); CloseSocketOnNodeIfOpen(defaultPort, PortDescriptor(defaultPort)->activeNodes-> extendedNode, EchoerSocket); CloseSocketOnNodeIfOpen(defaultPort, PortDescriptor(defaultPort)->activeNodes-> extendedNode, RtmpSocket); CloseSocketOnNodeIfOpen(defaultPort, PortDescriptor(defaultPort)->activeNodes-> extendedNode, ZonesInformationSocket); /* Okay, we can now accept an incoming connection on this remote access port. */ PortDescriptor(portInfo[index].desiredPort)-> remoteAccessInfo->state = ArapWaiting; ErrorLog("Initialize", ISevVerbose, __LINE__, defaultPort, IErrInitialHaveProxyNode, IMsgInitialHaveProxyNode, Insert0()); } #endif /* All set! */ return(True); } /* Initialize */ void far UnloadAppleTalk(void) { int index; /* Stop timer handling. */ StopTimerHandling(); /* Stop all new AppleTalk activity (geting nodes, opening sockets, etc.) */ appleTalkRunning = False; /* Force the shutdown of all ports. */ for (index = 0; index < MaximumNumberOfPorts; index += 1) if (PortDescriptor(index)->portActive) ShutdownPort(index, True); /* Let the various protocol levels know that they need to restart timers when we get started again. */ ShutdownErrorLogging(); #if ArapIncluded ShutdownArap(); #endif ShutdownAarp(); ShutdownRtmpStub(); #if Iam an AppleTalkRouter ShutdownFullRtmp(); ShutdownFullZip(); #endif #if Iam an AppleTalkStack ShutdownPap(); ShutdownAsp(); #endif /* Free the routing tables and the best-routes cache. */ #if Iam an AppleTalkRouter ReleaseRoutingTable(); #endif /* Unload the DES package. */ desdone(); /* All set... the next call to Initialize() will bring everything back up again. */ ErrorLog("UnloadAppleTalk", ISevVerbose, __LINE__, UnknownPort, IErrInitialAppleTalkUnloaded, IMsgInitialAppleTalkUnloaded, Insert0()); return; } /* UnloadAppleTalk */ void far RegisterOurName(int port) { Boolean tryAgain = True, firstFail = True; char far *p; StaticForSmallStack char currentName[MaximumEntityFieldLength + 1]; AppleTalkAddress address; long socket; /* Build the Appletalk address of the NamesInformationSocket on our first node -- that's the one we'll name. */ if (PortDescriptor(port)->activeNodes is empty) return; address.networkNumber = PortDescriptor(port)->activeNodes->extendedNode.networkNumber; address.nodeNumber = PortDescriptor(port)->activeNodes->extendedNode.nodeNumber; address.socketNumber = NamesInformationSocket; if ((socket = MapAddressToSocket(port, address)) < 0) { ErrorLog("RegisterOurName", ISevError, __LINE__, port, IErrInitialNamesSocketNotOpen, IMsgInitialNamesSocketNotOpen, Insert0()); return; } /* Pick our port name. */ if (PortDescriptor(port)->portName[0] isnt 0) strcpy(currentName, PortDescriptor(port)->portName); else if (PortDescriptor(port)->routingPort) strcpy(currentName, OurPortNameDefaultRouter); else strcpy(currentName, OurPortNameDefaultNonRouter); /* Try to do a register on our port's node untill we find a name that is not in use. */ while(tryAgain) { /* Do the seed. */ ourRegisterCompleteFlag = False; if (NbpAction(ForRegister, socket, currentName, OurPortNameType, Empty, GetNextNbpIdForNode(socket), 0, 0, OurRegisterComplete, (long unsigned)True) isnt ATnoError) { ErrorLog("RegisterOurName", ISevError, __LINE__, port, IErrInitialBadRegisterStart, IMsgInitialBadRegisterStart, Insert0()); return; } WaitFor(30 * 100, &ourRegisterCompleteFlag); if (not ourRegisterCompleteFlag) { ErrorLog("RegisterOurName", ISevError, __LINE__, port, IErrInitialBadRegisterComplete, IMsgInitialBadRegisterComplete, Insert0()); return; } if (ourRegisterErrorCode is ATnoError) { ErrorLog("RegisterOurName", ISevVerbose, __LINE__, port, IErrInitialRegisterOkay, IMsgInitialRegisterOkay, Insert1(currentName)); return; /* All set! */ } if (ourRegisterErrorCode isnt ATnbpNameInUse) { ErrorLog("RegisterOurName", ISevError, __LINE__, port, IErrInitialErrorOnRegister, IMsgInitialErrorOnRegister, Insert0()); return; } /* Hmmm... we have a name overlap; modify the name a little. The first time put a tail on the name, ending in a few zeros, that we can then tune later. */ if (firstFail) { if (strlen(currentName) + sizeof(OurPortNameTail) - 1 > MaximumEntityFieldLength) currentName[MaximumEntityFieldLength - sizeof(OurPortNameTail) - 1] = 0; strcat(currentName, OurPortNameTail); firstFail = False; continue; } p = currentName + strlen(currentName) - 1; while(True) { if (*p is ' ') break; if (*p is '9') p -= 1; else { *p += 1; break; } } if (*p is ' ') { ErrorLog("RegisterOurName", ISevError, __LINE__, port, IErrInitialRanOutOfNames, IMsgInitialRanOutOfNames, Insert0()); return; } } } /* RegisterOurName */ Boolean far ShutdownPort(int port, Boolean force) { AddressMappingNode addressMappingNode, nextAddressMappingNode; ActiveNode activeNode, nextActiveNode; int index, waitCount; Boolean false = False; /* If we're a stack, not just a router, we can't allow the default port to be stopped. Also, we can't shutdown if we're the default port and there are any currently active remote access ports... we're where the proxy nodes live. */ #if Iam an AppleTalkStack if (not force and PortDescriptor(port)->defaultPort) { ErrorLog("ShutdownPort", ISevError, __LINE__, port, IErrInitialShutdownDefault, IMsgInitialShutdownDefault, Insert0()); return(False); } #endif if (not force and PortDescriptor(port)->defaultPort) for (index = 0; index < MaximumNumberOfPorts; index += 1) if (PortDescriptor(index)->portType is AppleTalkRemoteAccess and PortDescriptor(index)->portActive) { ErrorLog("ShutdownPort", ISevError, __LINE__, port, IErrInitialShutdownDefault, IMsgInitialShutdownDefault, Insert0()); return(False); } /* Do all that we need to stop the operation of a specified port (a slot in the portDescriptors table). Free all memory that we can, and mark the slot as inactive. */ EnterCriticalSection(); if (not PortDescriptor(port)->portActive) return(False); /* Already not operating. */ PortDescriptor(port)->portActive = False; LeaveCriticalSection(); /* Stop routing, if needed. */ #if Iam an AppleTalkRouter if (PortDescriptor(port)->routingPort and PortDescriptor(port)->seenRouterRecently) RemoveFromRoutingTable(PortDescriptor(port)->thisCableRange); if (PortDescriptor(port)->routingPort and PortDescriptor(port)->routerRunning) if (not StopRouterOnPort(port)) return(False); #endif /* Free all of our remaining nodes. This will inturn close of the open sockets and signal this action up the stack, as needed. If we're a remote access port, just free the single proxy node! If we're the default port and shutting down proxy nodes for remote access ports, shutdown the remote access port (that will inturn cause the proxy node to be freed). We can get away with walking the ActiveNode list without locking here because the port is already logically stopped, so nobody else should be mucking with the list. */ #if ArapIncluded if (PortDescriptor(port)->portType is AppleTalkRemoteAccess) { TeardownConnection(port); UnlinkActiveNode(PortDescriptor(port)->remoteAccessInfo->proxyNode); ReleaseNodeOnPort(PortDescriptor(port)->remoteAccessInfo->proxyPort, PortDescriptor(port)->remoteAccessInfo->proxyNode-> extendedNode); UnlinkRemoteAccessInfo(PortDescriptor(port)->remoteAccessInfo); } else #endif for (activeNode = PortDescriptor(port)->activeNodes; activeNode isnt Empty; activeNode = nextActiveNode) { nextActiveNode = activeNode->next; if (PortDescriptor(port)->activeNodes->proxyNode) ShutdownPort(PortDescriptor(port)->activeNodes->proxyPort, force); else ReleaseNodeOnPort(port, PortDescriptor(port)->activeNodes->extendedNode); } /* The above freeing of nodes set the closing of sockets into motion... this may take a little while (if async writes are going on). The ActiveNodes won't really be removed from the port descriptors until all reference counts drop to zero (all sockets on the node are really closed for one thing). So, hang around here until that happens. Max 10 second wait. */ waitCount = 0; while (PortDescriptor(port)->activeNodes isnt Empty and waitCount < 100) { WaitFor(10, &false); waitCount += 1; } if (PortDescriptor(port)->activeNodes isnt Empty) ErrorLog("ShutdownPort", ISevError, __LINE__, port, IErrInitialNodesStillActive, IMsgInitialNodesStillActive, Insert0()); /* The same basic thing for Arap ports... make sure we're all done with the RemoteAccessInfo. */ #if ArapIncluded if (PortDescriptor(port)->portType is AppleTalkRemoteAccess) { waitCount = 0; while (PortDescriptor(port)->remoteAccessInfo isnt Empty and waitCount < 100) { WaitFor(10, &false); waitCount += 1; } if (PortDescriptor(port)->remoteAccessInfo isnt Empty) ErrorLog("ShutdownPort", ISevError, __LINE__, port, IErrInitialArapStillActive, IMsgInitialArapStillActive, Insert0()); } #endif /* Don't be bothered while we're playing with in-memory structures. */ DeferTimerChecking(); DeferIncomingPackets(); /* Okay, free all the memory used by this port's structures. */ FreeZoneList(PortDescriptor(port)->initialZoneList); #if Iam an AppleTalkRouter FreeZones(PortDescriptor(port)->theseZones); #endif #if (IamNot a DOS) and (IamNot an OS2) if (PortDescriptor(port)->controllerInfo isnt Empty) Free(PortDescriptor(port)->controllerInfo); #endif /* Okay, now free all address mapping table chains. */ for (index = 0; index < NumberOfAddressMapHashBuckets; index += 1) for (addressMappingNode = PortDescriptor(port)->addressMappingTable[index]; addressMappingNode isnt Empty; addressMappingNode = nextAddressMappingNode) { nextAddressMappingNode = addressMappingNode->next; Free(addressMappingNode); } /* All set, re-initialize (to zero) the port descriptor, and run away. */ FillMem(PortDescriptor(port), 0, sizeof(*PortDescriptor(port))); HandleIncomingPackets(); HandleDeferredTimerChecks(); return(True); } /* ShutdownPort */ ExternForVisibleFunction Boolean CopyInitializationInfo(int sourcePort, PortInfo portInfo[], int targetPort) { /* Copy all of the information from the initialization record (portInfo) to the actual portDescriptor. */ PortDescriptor(targetPort)->portType = portInfo[sourcePort].portType; PortDescriptor(targetPort)->protocolInfo = portInfo[sourcePort].protocolInfo; if (portInfo[sourcePort].aarpProbes <= 0) PortDescriptor(targetPort)->aarpProbes = NumberOfAarpProbes; else PortDescriptor(targetPort)->aarpProbes = portInfo[sourcePort].aarpProbes; PortDescriptor(targetPort)->extendedNetwork = (PortDescriptor(targetPort)->portType isnt LocalTalkNetwork); PortDescriptor(targetPort)->initialNetworkRange = portInfo[sourcePort].networkRange; PortDescriptor(targetPort)->routersPRamStartupNode = portInfo[sourcePort].routersPRamStartupNode; PortDescriptor(targetPort)->usersPRamStartupNode = portInfo[sourcePort].usersPRamStartupNode; if (portInfo[sourcePort].zoneList isnt empty) if ((PortDescriptor(targetPort)->initialZoneList = CopyZoneList(portInfo[sourcePort].zoneList)) is empty) return(False); if (portInfo[sourcePort].portName isnt empty) strcpy(PortDescriptor(targetPort)->portName, portInfo[sourcePort].portName); else PortDescriptor(targetPort)->portName[0] = 0; if (portInfo[sourcePort].defaultZone isnt empty) strcpy(PortDescriptor(targetPort)->initialDefaultZone, portInfo[sourcePort].defaultZone); if (portInfo[sourcePort].desiredZone isnt empty) strcpy(PortDescriptor(targetPort)->initialDesiredZone, portInfo[sourcePort].desiredZone); PortDescriptor(targetPort)->defaultPort = portInfo[sourcePort].defaultPort; PortDescriptor(targetPort)->routingPort = portInfo[sourcePort].routingPort; #if Iam an AppleTalkRouter PortDescriptor(targetPort)->seedRouter = portInfo[sourcePort].seedRouter; #endif PortDescriptor(targetPort)->routerRunning = False; PortDescriptor(targetPort)->sendDdpChecksums = portInfo[sourcePort].sendDdpChecksums; #if ArapIncluded if (portInfo[sourcePort].portType is AppleTalkRemoteAccess) PortDescriptor(targetPort)->remoteAccessInfo->configuration = portInfo[sourcePort].remoteAccessConfigurationInfo; #endif if (portInfo[sourcePort].controllerInfoSize isnt 0) { #if (Iam an OS2) or (Iam a DOS) /* DCH wants the real thing (not a copy) for Ring0 to Ring0 interface work. */ PortDescriptor(targetPort)->controllerInfo = portInfo[sourcePort].controllerInfo; #else /* Make a copy of the cotroller info. */ if ((PortDescriptor(targetPort)->controllerInfo = (char far *)Malloc(portInfo[sourcePort].controllerInfoSize)) is empty) { ErrorLog("CopyInitializationInfo", ISevError, __LINE__, targetPort, IErrInitialMallocFailed, IMsgInitialMallocFailed, Insert0()); return(False); } MoveMem(PortDescriptor(targetPort)->controllerInfo, portInfo[sourcePort].controllerInfo, portInfo[sourcePort].controllerInfoSize); #endif } else PortDescriptor(targetPort)->controllerInfo = empty; /* All set. */ return(True); } /* CopyInitializationInfo */ ExternForVisibleFunction void far OurRegisterComplete (AppleTalkErrorCode errorCode, long unsigned userData, int reason, long onWhosBehalf, int nbpId, ...) { /* "Use" the parameters that we really don't care about. */ errorCode; userData; reason; onWhosBehalf; nbpId; /* Mark the register as complete... RegisterOurName will notice the change in the value of "ourRegisterCompleteFlag". */ ourRegisterErrorCode = errorCode; ourRegisterCompleteFlag = True; return; } /* OurRegisterComplete */