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.
 
 
 
 
 
 

430 lines
10 KiB

/*******************************************************************/
/* 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; seg<SegmentCount; seg++) {
FirstRoute = TRUE;
// LOCK THE ROUTING TABLE
ExAcquireSpinLock(&SegmentLocksTable[seg], &oldirql);
while((rtep = GetRoute(seg, FirstRoute)) != NULL) {
FirstRoute = FALSE;
// if this is the global wan route, skip it
if(rtep->Flags & 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; i<MaximumNicCount; i++) {
niccbp = NicCbPtrTab[i];
if((niccbp->NicState == 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;
}
}
}