/*******************************************************************/ /* Copyright(c) 1993 Microsoft Corporation */ /*******************************************************************/ //*** // // Filename: lineind.c // // Description: WAN connection/disconection routines // // Author: Stefan Solomon (stefans) November 20, 1993. // // Revision History: // //*** #include "rtdefs.h" BOOLEAN WanGlobalNetworkEnabled = FALSE;// this is set to TRUE if the router has been // configured to assign the same global address // to all wan clients UCHAR WanGlobalNetwork[4]; VOID SendWanGenRequest(PNICCB niccbp); VOID StartWanGenRequestTimer(PNICCB niccbp); //*** // // Function: RtLineUp // // Descr: Called when a new WAN connection has been established // //*** VOID RtLineUp ( IN USHORT NicId, IN PIPX_LINE_INFO LineInfo, IN NDIS_MEDIUM DeviceType, IN PVOID ConfigurationData) { PNICCB niccbp; PIPX_ROUTE_ENTRY rtep, oldrtep; PIPXCP_CONFIGURATION configp; UINT segment; KIRQL oldirql; RtPrint(DBG_LINE, ("IpxRouter: RtLineUp: Entered on NicId %d\n", NicId)); configp = (PIPXCP_CONFIGURATION)ConfigurationData; niccbp = NicCbPtrTab[NicId]; //*** If the NIC is active, this is just an update. Ignore it for the // moment if(niccbp->NicState != NIC_CLOSED) { return; } // //*** set up the NIC Control Block with the configuration information *** // memcpy(niccbp->Network, configp->Network, 4); memcpy(niccbp->Node, configp->LocalNode, 6); memcpy(niccbp->RemoteNode, configp->RemoteNode, 6); // set the role of this node in this wan connection if(configp->ConnectionClient) { niccbp->WanConnectionClient = TRUE; } else { niccbp->WanConnectionClient = FALSE; } niccbp->LinkSpeed = LineInfo->LinkSpeed; niccbp->TickCount = tickcount(niccbp->LinkSpeed); niccbp->MaximumPacketSize = LineInfo->MaximumPacketSize; niccbp->MacOptions = LineInfo->MacOptions; niccbp->DeviceType = DeviceType; // reset statistics counters ZeroNicStatistics(niccbp); // try 3 times to get the other end's routes niccbp->WanGenRequestCount = 3; // now, try to open the nic if(NicOpen(niccbp) != NIC_OPEN_SUCCESS) { // !!! return; } // //*** check if we have a global wan route *** // if((WanGlobalNetworkEnabled) && (!niccbp->WanConnectionClient)) { // //*** There is a global WAN route AND this is a "server" node *** //*** Add the remote "client" node to the WAN Nodes Hash Table *** // AddWanNodeToHT(niccbp); } else { // //*** There is no global WAN route OR this is a "client" node *** //*** Add a new entry in the routing table for the local WAN net *** // if((rtep = ExAllocatePool(NonPagedPool, sizeof(IPX_ROUTE_ENTRY))) == NULL) { // can't allocate the route entry -> close the nic and return NicClose(niccbp, 0); return; } segment = IpxGetSegment(niccbp->Network); // LOCK THE ROUTING TABLE ExAcquireSpinLock(&SegmentLocksTable[segment], &oldirql); // Clean-up any old propagated route with the same net address // At this point, we do not worry about alternate routes, cause we do // not add alternate routes in the routing table yet. if((oldrtep = IpxGetRoute(segment, niccbp->Network)) != NULL) { RtPrint(DBG_LINE, ("IpxRouter: RtLineUp: Deleting old route for net %x-%x-%x-%x on NicId %d\n", niccbp->Network[0], niccbp->Network[1], niccbp->Network[2], niccbp->Network[3], oldrtep->NicId)); IpxDeleteRoute(segment, oldrtep); ExFreePool(oldrtep); } // set up the new route entry memcpy(rtep->Network, niccbp->Network, IPX_NET_LEN); rtep->NicId = niccbp->NicId; memcpy(rtep->NextRouter, niccbp->Node, IPX_NODE_LEN); rtep->Flags = IPX_ROUTER_LOCAL_NET; rtep->Timer = 0; // TTL of this route entry is 3 min rtep->Segment = segment; rtep->TickCount = niccbp->TickCount; rtep->HopCount = 1; InitializeListHead(&rtep->AlternateRoute); RtPrint(DBG_LINE, ("IpxRouter: RtLineUp: Adding new route for net %x-%x-%x-%x on NicId %d\n", niccbp->Network[0], niccbp->Network[1], niccbp->Network[2], niccbp->Network[3], niccbp->NicId)); IpxAddRoute(segment, rtep); // UNLOCK THE ROUTING TABLE ExReleaseSpinLock(&SegmentLocksTable[segment], oldirql); // Broadcast the new route entry on all the LAN segments BroadcastWanNetUpdate(rtep, niccbp, NULL); } // //*** Get the WAN peer's routing table info. *** // // Send a general request on this net and then send more general requests // with a timer. ACQUIRE_SPIN_LOCK(&niccbp->NicLock); if(niccbp->NicState != NIC_ACTIVE) { // nic has been closed while we were opening; reset the counter // to show to the closing timer that the wan request timer will not // get scheduled. niccbp->WanGenRequestCount = 0; RELEASE_SPIN_LOCK(&niccbp->NicLock); return; } --niccbp->WanGenRequestCount; if(niccbp->WanGenRequestCount) { // we have at least one more request to send beside the one we are // sending now -> start the timer StartWanGenRequestTimer(niccbp); } RELEASE_SPIN_LOCK(&niccbp->NicLock); SendWanGenRequest(niccbp); } //*** // // Function: RtLineDown // // Descr: Called when a WAN line has been disconnected // //*** VOID RtLineDown (IN USHORT NicId, IN ULONG FwdAdapterCtx) { LIST_ENTRY DownRoutesList; UINT seg; BOOLEAN FirstRoute; KIRQL oldirql; PIPX_ROUTE_ENTRY rtep; PRIP_SNDREQ sndreqp; PNICCB niccbp; USHORT DownNicId; RtPrint(DBG_LINE, ("IpxRouter: RtLineDown: Entered for NicId %d\n", NicId)); // get the nic ptr for this snd req niccbp = NicCbPtrTab[NicId]; if (niccbp->NicState!=NIC_ACTIVE) { RtPrint (DBG_LINE, ("IpxRouter: NicId %d is already inactive\n", NicId)); return; } // scan the routing table and delete all the routing table entries // visible through this nic. InitializeListHead(&DownRoutesList); for(seg=0; segFlags & IPX_ROUTER_GLOBAL_WAN_NET) { // skip it! continue; } // check if this route entry is based on the nic going down if(rtep->NicId == NicId) { IpxDeleteRoute(seg, rtep); // mark it as down rtep->HopCount = 16; // add the route to the packets we prepare for bcast AddRouteToBcastSndReq(&DownRoutesList, rtep); // finally, free the route entry ExFreePool(rtep); } } // UNLOCK THE ROUTING TABLE ExReleaseSpinLock(&SegmentLocksTable[seg], oldirql); } // for all segments // broadcast all the deleted routes if((sndreqp = GetBcastSndReq(&DownRoutesList, &DownNicId)) != NULL) { // set up the request to send a bcast response with the changes // to all the nics except this one BroadcastRipUpdate(sndreqp, niccbp, NULL); } // //*** If this is a "server" node and global WAN net if it has a global Wan net //*** for remote clients, remove the client node form the wan nodes hash table // if((WanGlobalNetworkEnabled) && (!niccbp->WanConnectionClient)) { // //*** There is a global WAN route AND this is a "server" node *** //*** Add the remote "client" node to the WAN Nodes Hash Table *** // RemoveWanNodeFromHT(niccbp); } // finally, close the nic NicClose(niccbp, 0); return; } VOID SendWanGenRequest(PNICCB niccbp) { PRIP_SNDREQ sndrqp; if((sndrqp = ExAllocatePool(NonPagedPool, sizeof(RIP_SNDREQ))) == NULL) { return; } sndrqp->SndReqId = RIP_GEN_REQUEST; sndrqp->SendOnAllNics = FALSE; // send to this nic only memcpy(sndrqp->DestNode, bcastaddress, IPX_NODE_LEN); sndrqp->DestSock = IPX_RIP_SOCKET; sndrqp->DoNotSendNicCbp = NULL; // do no except any nic sndrqp->SenderNicCbp = niccbp; sndrqp->SndCompleteEventp = NULL; RipQueueSndReqAtNic(niccbp, sndrqp); } VOID WanGenRequestTimeout(PKDPC Dpc, PVOID DefferedContext, PVOID SystemArgument1, PVOID SystemArgument2) { PNICCB niccbp; niccbp = (PNICCB)DefferedContext; ACQUIRE_SPIN_LOCK(&niccbp->NicLock); if(niccbp->NicState != NIC_ACTIVE) { // reset the request counter to show that we won't reschedule // the timer niccbp->WanGenRequestCount = 0; RtPrint(DBG_LINE, ("IpxRouter: WanGenRequestTimeout: closing done on NicId %d\n", niccbp->NicId)); RELEASE_SPIN_LOCK(&niccbp->NicLock); return; } --niccbp->WanGenRequestCount; RtPrint(DBG_LINE, ("IpxRouter: WanGenRequestTimeout: sending gen req on NicId %d remaining %d\n", niccbp->NicId, niccbp->WanGenRequestCount)); if(niccbp->WanGenRequestCount) { StartWanGenRequestTimer(niccbp); } RELEASE_SPIN_LOCK(&niccbp->NicLock); SendWanGenRequest(niccbp); } //*** // // Function: StartWanGenRequestTimer // // Descr: Starts the timer for 2 sec at this Nic Cb // // Params: pointer to Nic Cb // // Returns: none // //*** VOID StartWanGenRequestTimer(PNICCB niccbp) { LARGE_INTEGER timeout; timeout.LowPart = (ULONG)(-4000 * 10000L); // 4 sec timeout.HighPart = -1; KeSetTimer(&niccbp->WanGenRequestTimer, timeout, &niccbp->WanGenRequestDpc); } //*** // // Function: SendGenRequestOnWanClient // // Descr: Sends periodical gen requests on the WAN client to get the // remote router's updates // //*** VOID SendGenRequestOnWanClient(VOID) { PNICCB niccbp; USHORT i; // scan all nics to find the wan client nic active (if any) for(i=0; iNicState == NIC_ACTIVE) && (niccbp->DeviceType == NdisMediumWan) && (niccbp->WanConnectionClient)) { // send a RIP General Request on this NIC // There is only one client NIC (or none) per router SendWanGenRequest(niccbp); return; } } }